forum speccy.pl
ZX Spectrum => PROGRAMOWANIE => Wątek zaczęty przez: apk w 2017.02.01, 19:13:01
-
Witam wszystkich,
mam problem z instrukcją BIT. Buduję urządzenie na Z80, do którego dostałem kod programu. Niestety nie ja jestem autorem więc nie mogę go tu zamieścić w całości :(.
Podczas kompilacji wyrzucane są błędy. Z niektórymi sobie poradziłem (w życiu nie programowałem Z80 w asemblerze, tylko 8051 i AVR, ale to w sumie wszystko jest podobne). Największy problem mam na razie z takimi instrukcjami - pojawia się komunikat offset out of range.
BIT PAUSE,(IY-W+MODE)
LD (IY-W+KEY),B
ADD A,(IY-W+SCREENO)
gdzie definicje są takie:
W EQU 0E080H
LD IY,W
PAUSE EQU 4
KEY DEFS 1
SCREENO DEFS 1
MODE DEFS 1
Czy powinienem ten kod skompilować w jakimś specyficznym asemblerze? Czy można tą komendę można napisać jakoś inaczej?
Z góry dziękuję za pomoc.
Pozdrawiam
P.
-
Komunikat błędu jak najbardziej sensowny.
Offset jest liczbą 8-bitową ze znakiem, czyli zakres -128 do 127, a Ty masz zdefiniowaną stałą W 16-bitową.
Witaj na forum.
-
Czyli nie jest tak, ze kompilator obliczy wartość wykonując działanie: 0E080H - 0E080H + 1=1?
P.
-
Niestety nie.
Skoro jednak za każdym razem powtarza się IY-W, to dlaczego nie wyliczyć adresu bazowego wcześniej ?
LD BC,-W
ADD IY,BC
Potem już tylko właściwy offset
BIT PAUSE,(IY+MODE)
LD (IY+KEY),B
ADD A,(IY+SCREENO)
-
Takie dziwolongi potrafi obsłużyć kompilator sjasmplus. Ja nie wiem jak on się w tym łapie ;)
-
Spróbuję zrobić to co proponują obaj przedmówcy :)
Do pear:
Co jest zatem efektem działania z nawiasu? Jaka wartość? Program ma 8kB bez 3 bajtów i nie wiem czy obejście się zmieści. Poza tym chciałbym jak najmniej go modyfikować bo mogę popsuć coś innego. Ale spróbuję.
P.
-
Jeżeli po raz pierwszy piszesz coś tak dużego w asm Z80, to zapewne pozostawiasz dużo możliwości do optymalizacji.
Możemy pomóc, jeżeli zdradzisz nam/mi co to jest...
Używanie rejestrów indexowych jest wygodne, ale też pamięci i czasowo żerne.
-
Nie rozumiem po co wartość W jest ładowana do IY, a potem znów ta sama wartość jest odejmowana.
Jeśli to jest stała wartość IY w całym programie, to po prostu od razu załaduj tam 0 (zero).
-
Co jest zatem efektem działania z nawiasu?
Nawias w assemblerze Z80 prawie zawsze (w zasadzie z wyjątkiem operacji I/O) oznacza zawartość pamięci o adresie z nawiasu. W wypadku rejestrów indeksowych IX i IY oznacza to "zawartość pamięci o adresie z rejestru IX przesuniętym o ośmiobitowy indeks". Przeliczenia których oczekujesz od assemblera (kompilatora) nie dadzą się wykonać z bo mieszasz definicje stałych, zmiennych i rozkazy... EQU to deklaracja stałej, DEFS to deklaracja zmiennej a LD IY,W to już konkretny rozkaz. Po wykonaniu tego ostatniego w IY jest konkretna wartość - w twoim wypadku $E080, ale kolejna próba zaadresowania (IY-W+MODE) nie ma prawa zadziałać, bo do tego samego rozkazu można skoczyć z dowolnego innego miejsca z zupełnie inną zawartością w IY - ty oczekujesz, że assembler coś ci zoptymalizuje podczas gdy on oczekuje od ciebie precyzji wypowiedzi ;)
Dobrze jest zabierając się za takie rzeczy zaopatrzyć się w szczegółową listę rozkazów - np. oficjalną specyfikację procesora - w której znajdziesz informacje na temat tego jakie rozmiary mogą mieć poszczególne parametry w różnych trybach adresowania, jakie ustawiają znaczniki itp.
-
Sjasmplus dał radę i problematyczne komendy zostały skompilowane. Pojawił się teraz problem z makrem. Wygląda ono tak:
;MAKROINSTRUKCJA ROLL
;~~~~~~~~~~~~~~~~~~~~
; USUWA PRZENIESIENIA ADRES0W BUFORA TEKSTOWEGO
; ORAZ EKRANU POZA OBSZAR 2KB. 5 NAJSTARSZYCH BIT0W
; ADRESU W HL JEST BRANE Z KOM0RKI OKRESLONEJ
; PRZEZ PARAMETR MAKROINSTR. (ADRES STRONY BUFORA
; TEKSTOWEGO TPAGE ).
MACRO %ROLL
LD A,(\0)
XOR H
AND 11111000B
XOR H
LD H,A
ENDMAC
Błąd pojawia się tu: MACRO %ROLL
W dalszej części programu sa komendy wywołujące makro, które także generują błąd:
%ROLL TPAGE ;KOREKCJA ADR. ZR0DLA
Pojawia się komunikat, że polecenie ma za mało parametrów.
Samo TPAGE jest tak zefiniowane: TPAGE DEFS 1
Na razie doszedłem do tego, że Endmac trzeba zamienić na Endm.
Co należy zmienic, żeby kompilator to przyjął?
A tak informacyjnie to ja nie piszę tego programu. Dostałem od kogoś program gotowy, którego niestety nie mogę skompilować, bo albo pisany był w jakimś dziwnym asemblerze prawie 30 lat temu, albo od początku zawierał błędy. Znam się na programowaniu 8051 i avr więc asembler nie jest mi obcy, po prostu nigdy nie programowałem Z80.
Dziękuję wszystkim za zaangażowanie i pomoc.
P.
-
Strzelam że chodziło o coś takiego :
;MAKROINSTRUKCJA ROLL
;~~~~~~~~~~~~~~~~~~~~
macro roll page
ld a,(page)
xor h
and %11111000
xor h
ld h,a
endm
start:
ld a,16
ld (tpage),a
ld hl,$4200
roll tpage
ld a,(hl)
ret
tpage:
defs 1
-
Witam,
wprowadziłem następujące zmiany:
MACRO ROLL TPAGE
LD A,(TPAGE)
XOR H
AND 11111000B
XOR H
LD H,A
ENDM
Efekt jest taki, że makro jest kompilowane prawidłowo, natomiast przy wywołaniu: ROLL TPAGE pojawia się następujący błąd: line 616: Over 20 defines nested.
Chyba coś jest nie tak z parametrem przekazywanym do makro. Zrobiłem eksperyment i LD w makro zmieniłem na:
LD A,0
czyli nie wykorzystuję parametru. Teraz ROLL TPAGE kompiluje się prawidłowo, a listing wygląda tak:
0616 02D4 P_PRT2 ROLL TPAGE ;KOREKCJA ADR. ZR0DLA
0616 02D4 3E 00 > LD A,0;(TPAGE)
0616 02D6 AC > XOR H
0616 02D7 E6 F8 > AND 11111000B
0616 02D9 AC > XOR H
0616 02DA 67 > LD H,A
0617 02DB ED A0 LDI ;PRZESLANIE ZNAKU
Czyli chyba prawidłowo, bo w miejsce wywołania makra podstawia jego kod.
Czy można jakoś inaczej napisać LD A,(TPAGE) z makra, aby wszystko działało? Jedyne informacje o definiowaniu TPAGE w programie znajdujące się w jego różnych miejscach są następujące:
DEFB 0F0H ;TPAGE
TPAGE DEFS 1
P.
-
Nie do końca rozumiem, co chcesz uzyskać, ale jeśli używasz TPAGE jako etykiety do zmiennej a potem tego samego TPAGE jako parametru dla makro to mam wrażenie, że kompilator może się gubić. Skoro wywołujesz ROLL z parametrem TPAGE to sugeruje, że chcesz do makra przekazać TPAGE jako adres zmiennej, którą deklarujesz w ostatnim kawałku kodu. Jeśli ta zmienna zawsze jest w tym samym miejscu wyrzuć po prostu parametr z definicji makro i wołaj ROLL bez parametru. Jeśli może się zmieniać, to zmień nazwę w makro z TPAGE na coś innego i wtedy wołaj ROLL TPAGE (albo z innym parametrem, którego potrzebujesz).
-
Witam,
wprowadziłem następujące zmiany:
MACRO ROLL TPAGE
LD A,(TPAGE)
XOR H
AND 11111000B
XOR H
LD H,A
ENDM
Efekt jest taki, że makro jest kompilowane prawidłowo, natomiast przy wywołaniu: ROLL TPAGE pojawia się następujący błąd: line 616: Over 20 defines nested.
Może jednak powinieneś wrócić do 'numbered parameters'...
Wpisz to makro jako :
MACRO ROLL 1
LD A,(@1)
XOR H
AND 11111000B
XOR H
LD H,A
ENDM
-
Poniższy kod nie zadziałał:
MACRO ROLL 1
LD A,(@1)
XOR H
AND 11111000B
XOR H
LD H,A
ENDM
Pomogło jednak, jak proponował matofesi, usunięcie parametru:
MACRO ROLL
LD A,(TPAGE)
XOR H
AND 11111000B
XOR H
LD H,A
ENDM
wywołanie: ROLL
Z 69 błędów ilość spadła do 7 :)
Kolejny fragment sprawiający kłopoty:
LD (HL),.LOW.K_2
INC HL
LD (HL),.HIGH.K_2
Listing:
a.asm line 495: Label not found: K_11.LOW.K_2
0495 023F 36 00 LD (HL),.LOW.K_2
0496 0241 23 INC HL
a.asm line 497: Label not found: K_11.HIGH.K_2
0497 0242 36 00 LD (HL),.HIGH.K_2
K_2 to oznaczenie miejsca w kodzie:
K_2 LD A,XX
Nie rozumiem, co te komendy mają robić (czy ładują do HL adres?). Składnia jest także błędna i nie wiem jak to obejść.
***********************
Kolejne błędy dotyczą definicji kodów ascii.
Kod:
DEFB 0, '''','"', XX, XX ;40 - ' "
Listing:
a.asm line 3624: Syntax error: ''','"', XX, XX
3624 1581 00 DEFB 0, '''','"', XX, XX ;40 - ' "
***********************
Kolejny
Kod:
DEFB 0, '\', '|', FS, XX ;43 - \ |
Listing:
a.asm line 3627: Unexpected: |', FS, XX ;43 - \ |
3627 158C 00 27 2C 20 DEFB 0, '\', '|', FS, XX ;43 - \ |
***********************
I chyba ostatni
Kod:
DEFB ESC,'P','\',ESC,'O'
Listing:
a.asm line 3766: Unexpected: O'
3766 1730 DEFB ESC,'P','\\',ESC,'O'
3766 1730 1B505C272C4553432C
P.
-
LOW i HIGH to zwykle dyrektywy/funkcje assemblera generujące odpowiednio dolną i górną połówkę szesnastobitowej liczby podanej jako parametr. I zwykle zapisuje się operacje z ich użyciem jako np.
LD (hl), LOW k_2
Bez użycia kropek, które pojawiają się u ciebie. Znowu jednak sugeruję - sprawdź w dokumentacji assemblera, którego używasz jak te funkcje albo ich odpowiedniki wyglądają.
A cały kod, który pokazujesz ładuje pod adres z HL adres kawałka kodu od etykiety K_2 - prawdopodobnie jakiś wektor skoku albo kod samomodyfikujący.
Co do drugiej części - nie wiem czym to kompilujesz (sjasm?), ale sprawdź w dokumentacji czy przypadkiem DB nie deklaruje pojedynczego bajtu a do sekwencji bajtów nie ma jakiejś innej dyrektywy. Sprawdź też czy przypadkiem backslash w tym assemblerze nie jest (albo jest) znakiem "escape-ującym" i nie psuje ci sekwencji. A najlepiej byłoby te wszystkie sekwencje zamienić po prostu na ich szesnastkowe lub dziesiętne wartości żeby nie zmuszać kompilatora do niepotrzebnej ekwilibrystyki.
-
Dziękuję za pomoc, udało się całość skompilować :). Niestety wyszedł kolejny problem :(. Wygląda na to, że ORG nie działa. Kod wygląda tak:
ASTART EQU 00000H ;ADRES STARTOWY
ORG ASTART
CSTART: LD SP,0 ;PIERWSZY PUSH FFFE-F
DI ;POTRZEBNE PO JP 0000
JP CSTART1
;
;(MIEJSCE NA RESTARTY 08H, 10H, 18H, 20H, 28H, 30H)
;
ORG ASTART+038H
EX AF,AF'
ASTART+038H nie przesuwa kodu do pozycji 038F, tylko umieszcza go bezpośrednio po JP CSTART1. Powinienem tam mieć z 50 zer, a nie ma tego.
Używam zgodnie z wcześniejszą radą sjasmplus. Patrzyłem na dokumentację do sjasm, ale nie znalazłem info o ORG.
P.
-
Sjasma nie znam - może ma jakiś parametr, żeby ORG dodawał puste segmenty. Ale jak potrzebujesz zrobić "dziurę" to zawsze możesz dać coś takiego:
ds ASTART+038h-$
$ to wbudowany w większość assemblerów symbol oznaczający "adres pamięci do którego zapisany zostanie aktualny kawałek kodu/danych". W tym wypadku wyliczy ci ile miejsca zostało od tego punktu w którym aktualnie się znajdujesz do tego, w którym ma się skończyć dziura (czyli ASTART-$38) i "zarezerwuje" stosowną liczbę bajtów.
-
Poniższy kod nie zadziałał:
MACRO ROLL 1
LD A,(@1)
XOR H
AND 11111000B
XOR H
LD H,A
ENDM
Dziwne. U mnie działa.
test.z80
Errors: 0
1 00:0000
2 00:0000 MACRO ROLL 1
3 00:0000 < LD A,(@1)
4 00:0000 < XOR H
5 00:0000 < AND 11111000B
6 00:0000 < XOR H
7 00:0000 < LD H,A
8 00:0000 < ENDM
9 00:0000
10 00:0000 start:
11 00:0000 ROLL $8000
11 00:0000 3A 00 80 > LD A,(@1)
11 00:0003 AC > XOR H
11 00:0004 E6 F8 > AND 11111000B
11 00:0006 AC > XOR H
11 00:0007 67 > LD H,A
12 00:0008 ROLL tpau
12 00:0008 3A 19 00 > LD A,(@1)
12 00:000B AC > XOR H
12 00:000C E6 F8 > AND 11111000B
12 00:000E AC > XOR H
12 00:000F 67 > LD H,A
13 00:0010 ROLL over
13 00:0010 3A 1A 00 > LD A,(@1)
13 00:0013 AC > XOR H
13 00:0014 E6 F8 > AND 11111000B
13 00:0016 AC > XOR H
13 00:0017 67 > LD H,A
14 00:0018 76 halt
15 00:0019
16 00:0019 64 tpau: db 100
17 00:001A 00 (1) over: ds 1
-
Dziękuję za pomoc, udało się całość skompilować :). Niestety wyszedł kolejny problem :(. Wygląda na to, że ORG nie działa. Kod wygląda tak:
[...]
Uroki SJASM... :(
Możesz wymusić lokalizację w ten sposób:
code !$2000
org $2000
-
Spróbowałem na szybko z tym:
ds ASTART+038h-$
i tym:
code !$2000
org $2000
i w obu przypadkach nie działało. Może coś źle wpisałem. W każdym bądź razie zrobiłem prowizorkę i wpisałem odpowiednią ilość razy nop. Kompilacja zakończyła się sukcesem. Dziękuję wszystkim za pomoc :)
A swoją drogą bardzo fajne forum. Dobrze, że tu trafiłem.
Pozdrawiam
P.
-
Jedyne co mi przychodzi do głowy, to to, że zacząłeś pisać od pierwszej linii.
SJASM tego nie lubi. Od pierwszej linii zaczynają się jedynie etykiety, wszystkie rozkazy, makra, polecenia itp. muszą się zaczynać od odstępu (spacje lub taby)
A - i żeby jeszcze bardziej zagmatwać, można zrobić też tak :
macro odstep 1
repeat @1 - $
db 0
endrepeat
endm
org 0
di
jp start
odstep $8
ret
odstep $10
ret
odstep $18
ret
odstep $20
ret
odstep $28
ret
odstep $30
ret
odstep $38
reti
odstep $66
retn
odstep $100
start:
ret
;)
-
Wiem, że od lewej to tylko etykiety. Tak jest też w asemblerach na inne procesory. Nie wiem czemu nie zadziałało :(
Mam jeszcze pytanie z innej beczki. Przedmiotowy program powstał 30 lat temu. Jakim asemblerem mógł być kompilowany? Wyboru pewnie dużego nie było, a że program powstał w Polsce to tym bardziej.
Pozdrawiam
P.
-
Może http://www.cpcwiki.eu/index.php/ZSM ?
-
Mam jeszcze pytanie z innej beczki. Przedmiotowy program powstał 30 lat temu. Jakim asemblerem mógł być kompilowany? Wyboru pewnie dużego nie było, a że program powstał w Polsce to tym bardziej.
Eeee... tak to trochę mało danych jest... Jakbyś pokazał kawałek oryginalnego kodu to pewnie łatwiej by było zgadywać. ;)
Musiałbyś powiedzieć na jaką platformę to miało być robione albo na jakiej platformie było pisane wtedy moglibyśmy zgadywać.
30 lat temu to był 1987 rok - początek pirackiego el dorado. Można było u nas dostać prawie wszystko więc i z assemblerami Z80 nie powinno być problemu. Na Spectrum to GENS, ale chyba jakieś inne też bywały. Na peceta pod DOSa na pewno sporo różności by się znalazło, to samo z CPMem.
-
Jak dla mnie główną wskazówką jest ten dziwny zapis, który stwarzał najwięcej problemów:
BIT PAUSE,(IY-W+MODE)
LD (IY-W+ROLLC),23
Sprawdziłem kilka kompilatorów i żaden, poza podpowiedzianym sjasmplus tego nie ruszył.
Poza tym zapis makro, w którym koniec makra zapisywany jest chyba tez inaczej niż zwykle:
MACRO %ROLL
LD A,(\0)
XOR H
AND 11111000B
XOR H
LD H,A
ENDMAC
No i jeszcze te zapisy z kropkami - bez kropek dało się skompilować:
LD (HL),.LOW.K_2
INC HL
LD (HL),.HIGH.K_2
Reszta kodu wg mnie wygląda najzupełniej normalnie, zresztą nie sprawiała problemu.
Ostatnia wskazówka jest poniżej. Program, który kompilowałem był w kilku plikach. Jest jeden plik chyba do linkera, który składal wszystko w calośc. Oto jego treść:
name TERM
;
pstitl 'Term1'
$TGRA11_1.S01
;
pstitl 'Term2'
$TGRA11_2.S01
;
pstitl 'Term3'
$TGRA11_3.S01
;
pstitl 'Term4'
$TGRA11_4.S01
;
endmod
;
END ;
Program przeznaczony jest dla Z80, na czym był kompilowany - nie wiem.
P.