ZX Spectrum > PROGRAMOWANIE
Asembler ZX Spectrum - Pytania na początek (Cartridge).
siudym:
Nadszedł czas aby zacząć coś porobić w ASM na ZX Spectrum wiec mam kilka szybkich pytań :)
- Jaki asembler/kompiler najlepiej używać? PASMO ?
- Jak się ma format Cartridge w ZX? Chyna nie jest popularny, ale nawet jeśli chciałbym zrobić coś używając tego formatu.
Gdzie mapuje sie ROM w Carcie na pamie pamieci? Czy przejmuje miejsce BASIC czyli $0000-3FFF ?
Czy trzeba coś dodatkowo zdefiniować w kodzie gdy chcę stworzyć kod dla Carta? Czy wystarczy ORG $0000 i wielkość max 16KB.
ZX Spectrum nie posiada Sprites, tak? Wiec wszelkie obiekty sprajto-podobne generowane sa tak samo jak piksele ekranu ale podczas przemieszczania
ich poprzednie miejsce jest kasowane z ekranu i wstawiane i iles-tam pix dalej zaleznie od ich szybkosci?
Są jakieś ograniczenia podczas zapisu do pamięci ekranu? Czy można sobie zapisywać w dowolnej chwili zmieniając coś na ekranie?
matofesi:
--- Cytat: siudym w 2023.01.09, 12:08:46 ---Nadszedł czas aby zacząć coś porobić w ASM na ZX Spectrum wiec mam kilka szybkich pytań :)
- Jaki asembler/kompiler najlepiej używać? PASMO ?
--- Koniec cytatu ---
Pasmo jest stosunkowo "bezpiecznym" wyborem - ma obsługuje wszystko, co może być potrzebne z makrami, pętlami itp. I pozwala generować w wyniku wszystkie istotne formaty.
--- Cytuj ---- Jak się ma format Cartridge w ZX? Chyna nie jest popularny, ale nawet jeśli chciałbym zrobić coś używając tego formatu.
Gdzie mapuje sie ROM w Carcie na pamie pamieci? Czy przejmuje miejsce BASIC czyli $0000-3FFF ?
--- Koniec cytatu ---
Cartridge to po prostu podmiana ROMu - 16 kilo od adresu 0 i bez dostępu do ROMu systemowego.
--- Cytuj ---Czy trzeba coś dodatkowo zdefiniować w kodzie gdy chcę stworzyć kod dla Carta? Czy wystarczy ORG $0000 i wielkość max 16KB.
--- Koniec cytatu ---
Powinien wystarczyć ORG.
--- Cytuj ---ZX Spectrum nie posiada Sprites, tak? Wiec wszelkie obiekty sprajto-podobne generowane sa tak samo jak piksele ekranu ale podczas przemieszczania
ich poprzednie miejsce jest kasowane z ekranu i wstawiane i iles-tam pix dalej zaleznie od ich szybkosci?
--- Koniec cytatu ---
W dużym uproszczeniu - tak. Wszystko co chcesz mieć na ekranie musisz wyrysować na piechotę :)
--- Cytuj ---Są jakieś ograniczenia podczas zapisu do pamięci ekranu? Czy można sobie zapisywać w dowolnej chwili zmieniając coś na ekranie?
--- Koniec cytatu ---
Są - poczytaj o memory contention. W uproszczeniu - jeśli kod usiłuje dostać się do "niskiego" RAMu ($4000-$7fff) w tym samym czasie kiedy ULA pobiera z niego dane procesor zostanie wstrzymany na 1-6 taktów. Dokładny pattern tych wstrzymań oraz liczba "bezpiecznych" taktów od początku ramki jest zależna od modelu.
A tak z czystej ciekawości... dlaczego cartridge? Bo w wypadku ZXów to takie trochę perwersyjne samoograniczanie ;)
siudym:
Dzięki. Co do Carta to takie konsolowe "zboczenie" :) Oczywiscie nigdy tego nie wymagam, ale zawsze z ciekawosci na początku chcę coś zrobić w tym formacie.
Jakie są metody synchronizacji petli CPU z predkoscia ramki? Szperam w gogle, ale na razie nic spewnego nie doczytalem, jedynie, ze HALT wystarczy, ale nie jest zalecany (chyba).
matofesi:
HALT wstrzymuje procesor (wewnętrznie wykonuje nieskończoną pętlę NOP) aż do wywołania następnego przerwania - w wypadku ZXów przerwanie wywołuje ULA raz na ramkę. Jeśli piszesz kod od $0000 wystarczy procedurę przyjęcia przerwania umieścić pod adresem $38. Albo umieścić tam EI+RET i synchronizować samym HALTem.
Jeśli robisz kod pracujący normalnie w RAMie to synchronizacja HALTem bez dodatkowych przygotowań wywołuje najpierw procedurę w ROMie, która skanuje klawiaturę i robi kilka innych drobiazgów. A to powoduje, że synchronizacja nie jest płynna - zależnie od tego co akurat robi ROM twój kod uruchomi się trochę wcześniej albo trochę później.
Żeby w takiej sytuacji mieć cały czas dla siebie należy przygotować procedurę obsługi w RAMie, ustawić tablicę wektorów, wycelować w nią rejestr I i przełączyć procesor w tryb IM 2. Tak w jednym zdaniu ;)
Można też - jeśli kod ma działać tylko na prawdziwych ZXach (nie zadziała na Timexach a na innych klonach będzie różnie) użyć "pływających atrybutów" i synchronizować się (z dokładnością do prędkości pętli) do ekranu według zawartości atrybutu. Ale to jest już zupełnie inna bajka ;)
siudym:
Mam przykładowy kod, ale nie mam pojęcia jak go uruchomić ;D
Skompilowałem go PASMO i próbowałem uruchomić Spectaculator jako .BIN bo nie wiem jakie powinno być rozszerzenie tak skompilowanego kodu. Niestety nic nie uruchamia się. Potrzebuje jakieś podstawowe info.
--- Kod: ---org 32768 ;we can ORG (or assemble) this code anywhere really
;a beginner's, unoptimised sprite routine
main: halt ;this stops the program until the Spectrum is about to refresh the TV screen
;the HALT is important to avoid sprite flicker, and it slows down the program
call deletesprite ;we need to delete the old position of the sprite
call movesprite ;move the sprite! Could be based on player key input or baddy AI
call drawsprite ;get correct preshifted graphic, and draw it on the screen
jr main ;loop!
;
deletesprite: ;we need to delete the old sprite before we draw the new one. The sprite is 3 bytes wide & 16 pixels high
ld a,(x_coordinate) ;make C=xcor and B=ycor
ld c,a
ld a,(y_coordinate)
ld b,a
call yx2pix ;point DE at the corresponding screen address
ld b,16 ;sprite is 16 lines high
deleteloop: ;NEW!
ld a,0 ;empty A to delete
ld (de),a ;repeat a total of 3 times
inc e ;next column along
ld (de),a
dec e ;NEW
call nextlinedown ;move DE down one line
djnz deleteloop ;repeat 16 times
ret
;
movesprite: ;very simple routine that just increases the x coordinate
ld a,(x_coordinate)
inc a
ld (x_coordinate),a
cp 232 ;check if the sprite has moved all the way to the right (256-24)
ret c ;return if not
ld a,0 ;if yes then back to left
ld (x_coordinate),a
ret
;
drawsprite:
ld a,(x_coordinate) ;make C=xcor and B=ycor
ld c,a
ld a,(y_coordinate)
ld b,a
call yx2pix ;point DE at corresponding screen position
ld a,(x_coordinate) ;but we still need to find which preshifted sprite to draw
and 00000111b ;we have 8 preshifted graphics to choose from, cycled 0-7 in the right hand 3 bits of the x coordinate
call getsprite ;point HL at the correct graphic
ld b,16 ;sprite is 16 lines high
drawloop: ;NEW
ld a,(hl) ;take a byte of graphic
ld (de),a ;and put it on the screen
inc hl ;next byte of graphic
inc e ;next column on screen
ld a,(hl) ;repeat for 3 bytes across
ld (de),a
inc hl
dec e
call nextlinedown
djnz drawloop ;repeat for all 16 lines
ret
;
x_coordinate: db 0
y_coordinate: db 0
;
nextlinedown: ;don't worry about how this works yet!
inc d ;just arrive with DE in the display file
ld a,d ;and it gets moved down one line
and 7
ret nz
ld a,e
add a,32
ld e,a
ret c
ld a,d
sub 8
ld d,a
ret
;
yx2pix: ;don't worry about how this works yet! just arrive with arrive with B=y 0-192, C=x 0-255
ld a,b ;return with DE at corresponding place on the screen
rra
rra
rra
and 24
or 64
ld d,a
ld a,b
and 7
or d
ld d,a
ld a,b
rla
rla
and 224
ld e,a
ld a,c
rra
rra
rra
and 31
or e
ld e,a
ret
;
getsprite: ;don't worry much about how this works! for an alternative method that
;uses a table see 'getsprite_alternativemethod'
;Arrive A holding which pixel within a byte (0-7), point HL at correct graphic
ld h,0 ;we need to multiply A by 48, do it in HL
ld l,a
add hl,hl ;x2
add hl,hl ;x4
add hl,hl ;x8
add hl,hl ;x16
add hl,hl ;x32
ld bc,spritegraphic0
add hl,bc ;HL now pointing at correct sprite frame
ret
;
spritegraphic0: ;8 preshifted graphics, each one 3 bytes wide and 16 pixels high, this one a simple square
; ASM data file from a ZX-Paintbrush picture with 16 x 128 pixels (= 2 x 16 characters)
; block based output of pixel data - each block contains 16 x 16 pixels
; block at pixel position (0,0):
db 126, 0, 255, 0, 219, 0, 255, 0
db 189, 0, 195, 0, 255, 0, 126, 0
db 24, 0, 24, 0, 24, 0, 24, 0
db 24, 0, 36, 0, 66, 0, 129, 0
; block at pixel position (0,16):
db 63, 0, 127, 128, 109, 128, 127, 128
db 94, 128, 97, 128, 127, 128, 63, 0
db 12, 0, 12, 0, 12, 0, 12, 0
db 12, 0, 18, 0, 33, 0, 64, 128
; block at pixel position (0,32):
db 31, 128, 63, 192, 54, 192, 63, 192
db 47, 64, 48, 192, 63, 192, 31, 128
db 6, 0, 6, 0, 6, 0, 6, 0
db 6, 0, 9, 0, 16, 128, 32, 64
; block at pixel position (0,48):
db 15, 192, 31, 224, 27, 96, 31, 224
db 23, 160, 24, 96, 31, 224, 15, 192
db 3, 0, 3, 0, 3, 0, 3, 0
db 3, 0, 4, 128, 8, 64, 16, 32
; block at pixel position (0,64):
db 7, 224, 15, 240, 13, 176, 15, 240
db 11, 208, 12, 48, 15, 240, 7, 224
db 1, 128, 1, 128, 1, 128, 1, 128
db 1, 128, 2, 64, 4, 32, 8, 16
; block at pixel position (0,80):
db 3, 240, 7, 248, 6, 216, 7, 248
db 5, 232, 6, 24, 7, 248, 3, 240
db 0, 192, 0, 192, 0, 192, 0, 192
db 0, 192, 1, 32, 2, 16, 4, 8
; block at pixel position (0,96):
db 1, 248, 3, 252, 3, 108, 3, 252
db 2, 244, 3, 12, 3, 252, 1, 248
db 0, 96, 0, 96, 0, 96, 0, 96
db 0, 96, 0, 144, 1, 8, 2, 4
; block at pixel position (0,112):
db 0, 252, 1, 254, 1, 182, 1, 254
db 1, 122, 1, 134, 1, 254, 0, 252
db 0, 48, 0, 48, 0, 48, 0, 48
db 0, 48, 0, 72, 0, 132, 1, 2
;
--- Koniec kodu ---
Nawigacja
[#] Następna strona
Idź do wersji pełnej