forum speccy.pl
ZX Spectrum => PROGRAMOWANIE => Wątek zaczęty przez: Dalthon w 2018.08.21, 02:46:31
-
O ile rysowanie punktu procedurą z ROM jest banalne...
10 PLOT 80,80
ld b,80 ; y
ld c,80 ; x
call 8933
... linie też się bez problemu rysuje...
10 PLOT 8,80
20 DRAW 10,10
ld b,80 ; y
ld c,80 ; x
call 8933
ld b,10 ; Y
ld c,10 ; X
ld d,1 ; +Y
ld e,1 ; +X
call 9402
... tak nie mam pojęcia (a analizowałem sobie rom tutaj: http://skoolkid.github.io/rom/) jak zrobić rysowanie 'po łuku'...
10 PLOT 80,80
20 DRAW 10,10,.5
Ktoś, coś? ;)
-
Musiałbym pogrzebać, ale w związku z tym, że trzeci parametr jest ułamkowy więc prawie na pewno będzie trzeba go przekazywać przez stos kalkulatora. I pozostałe dwa raczej też.
Zajrzę do TCSRD i spróbuję coś "wywąchać" ;)
edit: Wywąchałem... Nie podejmuję się opisać na 100% jak się to robi ;)
A wydaje mi się, że robi się tak jak myślałem - najpierw ustawiamy współrzędne początku linii w COORDS, potem na stos kalkulatora wrzucamy X, Y i kąt (kąt leży na górze, Y, X poniżej) a następnie skaczemy w środek procedury DRAW - pod adres $2394. Tam zaczyna się program dla kalkulatora, który robi kontrolę kąta, kierunku itp. dzieli łuk na mniejsze kawałki i w pętli (cały czas napieprzając kalkulatorem ;)) wywołuje LINE-DRAW ($2477) rysując przybliżenie zadanego parametrami łuku. Z tej procedury widzę dwa wnioski - już wiem, czemu to jest takie cholernie wolne i już wiem skąd się bierze rysowanie "gwiazdek" jak się zada dziwny kąt jako parametr.
-
Ok. Zrobiłem w ASMie ;)
org $8000
ld a,100
ld (23677),a ; początkowe X
ld a,50
ld (23678),a ; początkowe Y
ld a,50
call $2d28 ; wrzuć na stos kalkulatora A - X linii
ld a,50
call $2d28 ; j.w. - Y linii
rst $28 ; FP-CALC
db $34 ; stk-data - wrzuć na stos kalkulatora liczbę FP
db $f1, $49, $0f, $da, $a2 ; PI/2
db $38 ; end-calc
call $2394 ; rysowanie łuku wg parametrów ze stosu kalkulatora
ld hl,$2758 ; wracamy do BASICa - kalkulator zmienia
; HL' trzeba więc przywrócić właściwą
; zawartość
exx
ret
end $8000
Powyższy kod jest mniej więcej odpowiednikiem PLOT 100,50 : DRAW 50,50,PI/2
Tak jak pisałem - najpierw ładujemy do COORDS początkowe współrzędne (PLOT bez PLOTa ;)), potem wrzucamy na stos parametry w tym ułamkowy kąt a następnie skaczemy do rysowania łuku. Na koniec odtwarzamy HL' - to jeden z błędów w ROMie - HL' musi być na wyjściu procedur używających kalkulatora ustawiony na $2758, jeśli tak nie jest program się po prostu zawiesi po wykonaniu ostatniego RET.
Całość działa tak samo jak z BASICa i jedyny problem, to przygotowanie startowych parametrów jeśli chcemy rysować łuki oparte na jakichś konkretnych kątach. Albo trzeba te liczby wyliczać kalkulatorem albo np. wydłubywać ze zmiennoprzecinkowej reprezentacji w programie BASICowych albo zmiennej ;)
-
Ooooooooooooooo... rozpykałeś to bez mydła! Wielkie dzięki!!! Teraz tylko rozkminić jak zapisywane są ułamki i będzie z górki :)
Szkoda że już nie robisz nic na zx'ie - taki talent się marnuje...
-
Prosz... :>
http://www.worldofspectrum.org/z88forever/dn327/fpp.htm
-
Ooooooooooooooo... rozpykałeś to bez mydła! Wielkie dzięki!!! Teraz tylko rozkminić jak zapisywane są ułamki i będzie z górki :)
Liczby zmiennoprzecinkowe co do zasady zapisywane są wykładniczo jako pięć bajtów, ale mogą też być 2 albo 4 o ile pamiętam. W kilku miejscach były opisy jak to jest przeliczane, ale jakoś nigdy nie miałem zacięcia, żeby się w to wgryzać. Najprostsza metoda przeliczenia wartości ułamkowej na odpowiedni zapis dla kalkulatora to użycie takiej liczby w programie w BASICu (ROM zamieni za ciebie cyferki na formę FP) a potem podejrzenie w pamięci co mu wyszło - liczba jest w linii BASICa zapisana najpierw tekstem potem jest $0e a potem pięć bajtów reprezentacji FP. Można też kazać ROMowi sparsować tekst i zamienić na postać FP albo "wyliczyć" sobie kalkulatorem jeśli dana wartość jest "wyliczalna".
Szkoda że już nie robisz nic na zx'ie - taki talent się marnuje...
Mój problem z robieniem na cokolwiek jest taki, że mam problemy z wymyśleniem tego, CO ewentualnie miałbym zrobić. Wolę się zajmować rozwiązywaniem zadanych przez kogoś problemów nić wymyślać sobie własne. Przynajmniej jeśli chodzi zabawę ;)
-
Prosz... :>
http://www.worldofspectrum.org/z88forever/dn327/fpp.htm
Hmmm... Czy z88 aby na pewno używa systemowego kalkulatora i zgodnego z nim formatu liczb?
Nie używałem to nie wiem :)
-
A czy przypadkiem liczba w 5 bajtach nie jest tak że w każdej połówce bajta jest jedna cyfra dziesiętna?
Tylko nie wiem gdzie przecinek trzyma.
-
@ZbyniuR Przypadkiem nie. Celowo też nie.
W pierwszym bajcie jest wykładnik, w pozostałych czterech mantysa.
-
W dodatku do Komputera "Tajniki ZX Spectrum" Andrzej Kadlof wyjaśniał zapis liczb w taki sposób:
Sposoby kodowania liczb większych i zmiennoprzecinkowych
są w różnych komputerach rozmaite. W ZX-Basic wszystkie
liczby są przechowywane w pięciu kolejnych komórkach pamięci.
Dla programisty istnieją tylko liczby zmiennoprzecinkowe,
ale w pamięci liczby całkowite z przedziału - 65536...65535 są
kodowane w innej postaci niż pozostałe. Pierwszy i ostatni bajt
w ich przedstawieniu zawsze zawiera zero. Drugi bajt jest równy
0 dla liczb dodatnich i 255 dla ujemnych. W trzecim i czwartym
umieszcza się odpowiednio młodszy i starszy bajt danej liczby,
przy czym wartości ujemne są pamiętane w kodzie uzupełnień do
dwóch. Np. liczba 38 wygląda tak: 0 0 0 38 0, natomiast
743=2*256+231 ma postać 0 0 231 2 0. Z kolei - 1231 zapamiętane
jest jako 0 255 251 49 0, bo 256*251+49=65536-1231.
Z pozostałymi liczbami sprawa jest bardziej zawiła. Wykorzystuje
się fakt, że każdą liczbę można jednoznacznie przedstawić
w postaci 2 ^ n*m, gdzie m jest liczbą z przedziału [1/2,1]. W
pierwszym bajcie Spectrum przechowuje wartość n+128. W pozostałych
czterech umieszczona jest liczba m w postaci binarnej, a
dokładnie - m*2 ^ 32, z tym, że najstarszy bit, który powinien
zawsze być równy 1 służy do przechowywania znaku liczby. Jedynka
oznacza minus a zero plus.
Przypuśćmy, że pięć kolejnych komórek pamięci zawiera liczby
130 212 16 34 178. Są one interpretowane jako liczba
2 ^ (130-128)*(212/2 ^ 8+16/2 ^ 16+34/2 ^ 24+178/2 ^ 32),
natomiast bajty 106 112 4 231 78 przedstawiają liczbę
2 ^ (106-128)*((128+112)/2 ^ 8+4/2 ^ 16+231/2 ^ 24+78/2 ^ 32)
Nie przekonuje mnie ta matematyka, ale może komuś coś z tego wyniknie ;)
-
Ciekawa lekturą. Póki co nie wykorzystywałem procedur rysujących z ROM.
Trochę więcej, wraz z przykładowym programem wylicząjacym IEEE 754, znajduje się na stronie https://eduinf.waw.pl/inf/alg/006_bin/0022.php, co jest dobrym uzupełnieniem wiedzy dotyczącej DRAW oraz parametrów dla niego.
-
To jeszcze na koniec to o czym pisałem czyli metoda na przekształcenie tekstowej reprezentacji liczby na liczbę FP na stosie kalkulatora:
org $8000
ch_add equ 23645
ld a,2
call $1601 ; chan-open
; === POCZĄTEK ===
ld hl,(ch_add)
push hl
ld hl,number
ld (ch_add),hl
rst $20
call $2c9b ; dec-to-fp
pop hl
ld (ch_add),hl
; === KONIEC ===
call $2de3 ; print-fp
ld hl,$2758
exx
ret
number
db 0
db "12.345"
db 0
Właściwy kod jest między POCZĄTEK a KONIEC - reszta to otoczka otwierająca kanał 2 i drukująca liczbę FP ze stosu kalkulatora na ekran.
A właściwy kod najpierw zachowuje na stosie (procesora) zawartość zmiennej ch_add a potem przestawia ją na adres tekstowej reprezentacji liczby, którą chcemy dostać w formacie FP. Następnie wywoływane jest RST $20 pobierające znak spod ch_add - nie analizowałem dlaczego, ale pierwszy znak przez procedurę jest pomijany stąd db 0 na początku. Po pobraniu znaku skaczemy do właściwej procedury dec-to-fp, która parsuje to, co dostała i przetwarza na formę FP - obsługuje wszystkie formy zapisu liczb, których można użyć w BASICu (.123, 1.234, 1.2E2 itp.) i kończy analizę po napotkaniu znaku, który nie jest dopuszczalną częścią liczby (tutaj ostatnie db 0). Po wyjściu mamy na stosie kalkulatora formę FP liczby, którą na zewnątrz drukujemy na ekran używając print-fp a w praktycznych zastosowaniach używamy jej np. jako parametru dla DRAW albo do innych obliczeń kalkulatorem.
-
Zawsze można liczyć na forum - nawet taki niszowy temat rozpracowany na czynniki pierwsze :)
Szkoda że ten 3 parametr jest tak zapisywany - z racji długości, raczej ciężko będzie to wykorzystać w 256b produkcjach (bo taki był pierwotny zamysł) ale do 1kB i 4kB jak znalazł!
ps. muszę częściej wrzucać tutaj swoje rozterki, zamiast odpuszczać i wymyślać co innego :D
-
Taaaa... jednak za głupi jestem :/
A jak ze znakami? Próbuję zrobić
10 PLOT 0,47
20 DRAW 255,0,-3.14
albo (bo efekt ten sam;)
10 PLOT 255,47
20 DRAW -255,0,3.14
i nic mi z tego nie wychodzi :(
-
Problem pewnie w tym, że stk-data wymaga nie po prostu liczby, ale liczby w postaci 'skondensowanej'.
Więc -pi to nie $82, $c8, $f5, $c2, $8f ale $f2, $c8, $f5, $c2, $8f.
org $8000
ld a,0
ld (23677),a ; początkowe X
ld a,47
ld (23678),a ; początkowe Y
ld a,255
call $2d28 ; wrzuć na stos kalkulatora A - X linii
ld a,0
call $2d28 ; j.w. - Y linii
rst $28 ; FP-CALC
db $34 ; stk-data - wrzuć na stos kalkulatora liczbę FP
db $f2, $c8, $f5, $c2, $8f ; -PI
db $38
call $2394 ; rysowanie łuku wg parametrów ze stosu kalkulatora
ld hl,$2758 ; wracamy do BASICa - kalkulator zmienia
; HL' trzeba więc przywrócić właściwą
; zawartość
exx
ret
-
Wow! A ja siedziałem i kombinowałem...
Pierwotnie mając PI $82, $48, $f5, $c2, $8f jasne dla mnie było że 2 bajt zmienia się przy -PI na $c8 ale co się dzieje z 1 bajtem to dla mnie zagadka (pewnie za dużo piwa dzisiaj;p)
Wielkie dzięki! Teraz wiem że dla PI (bez minusa) powinno być $f2, $48, $f5, $c2, $8f - tylko nie wiem dlaczego (te czary z 1 bajtem...).
-
Pierwsze dwa bity określają do ilu bajtów została liczba 'skompresowana' (https://skoolkid.github.io/rom/asm/33C6.html)
Czy takie czary były faktycznie potrzebne i czy dały jakiś realny zysk - nie mam pojęcia, ale zakładam że jednak tak (bo są :) )
-
Nb. można też bez kombinowania z kalkulatorem :
org $8000
ld a,0
ld (23677),a ; początkowe X
ld a,47
ld (23678),a ; początkowe Y
ld a,255
call $2d28 ; wrzuć na stos kalkulatora A - X linii
ld a,0
call $2d28 ; j.w. - Y linii
ld hl,par3
ld de,($5c65) ;Point DE to STKEND.
call $33c0 ;Stack the 5 bytes.
ex de,hl ;Point HL to the new position of STKEND, and reset the system variable.
ld ($5c65),hl
call $2394 ; rysowanie łuku wg parametrów ze stosu kalkulatora
ld hl,$2758 ; wracamy do BASICa - kalkulator zmienia
; HL' trzeba więc przywrócić właściwą
; zawartość
exx
ret
par3: db $82, $c8, $f5, $c2, $8f
-
Naprawdę wielkie dzięki! Efekt potrzebny osiągnięty - będzie w kolejnym 1kB wykorzystane ;)