DEVICE ZXSPECTRUM128
include "../../_sdk/sys_h.asm"
;│┐│-│-TПTВTМ:
;0x0100..0x3eff - subroutines
;0x3f00..0x3fff - stack
;0x4000..0x7fff - VRAM
;0x8000..0xbfff - game/paged for screen
;0xc000..0xffff - scratchpad RAM/paged for screen
INTSTACK=0x0100;0x3f00
STACK=INTSTACK-64
org PROGSTART
begin
ld sp,STACK
OS_HIDEFROMPARENT
ld e,0 ;EGA
OS_SETGFX ;e=0:EGA, e=2:MC, e=3:6912, e=6:text ;+SET FOCUS ;e=-1: disable gfx (out: e=old gfxmode)
ld e,0
OS_SETSCREEN
ld e,0 ;color byte
OS_CLS
ld e,1
OS_SETSCREEN
ld e,0 ;color byte
OS_CLS
OS_GETMAINPAGES
;dehl=pages in 0000,4000,8000,c000
ld a,e
ld (pgcode4000),a
ld a,h
ld (pgcode8000),a
ld a,l
ld (pgcodec000),a
ld a,e
ld hl,MUZHOOK
OS_SETMUSIC
OS_NEWPAGE
ld a,e
ld (pgtiles),a
ld de,pal
OS_SETPAL
call swapimer
jp GO
pal
;DDp palette: %grbG11RB(low),%grbG11RB(high), inverted
;bg=1 ;зел ;салат ;син ;небо ;крас ;ярко-голуб
dw 0xffff,0xffff,0xcfcf,0x4f4f,0xdede,0xcccc,0xfdfd,0xcece
dw 0xbdbd,0xacac,0x2d2d,0x2c2c,0xefef,0x4e4e,0xecec,0x0c0c
;флаг ;роз ;древко ;лим ;тзел ;??? ;road
timer
dw 0
oldtimer
dw 0
quiter
halt
;ld a,(pgmuznum)
;SETPG32KHIGH
;call muz
call shutay
call swapimer
QUIT
swapimer
di
ld de,0x0038
ld hl,oldimer
ld bc,3
swapimer0
ld a,(de)
ldi ;[oldimer] -> [0x0038]
dec hl
ld (hl),a ;[0x0038] -> [oldimer]
inc hl
jp pe,swapimer0
ei
ret
oldimer
jp on_int ;заменится на код из 0x0038
jp 0x0038+3
on_int
;restore stack with de
ld (on_int_hl),hl
ld (on_int_sp),sp
pop hl
ld (on_int_sp2),sp
ld (on_int_jp),hl
ld sp,INTSTACK
push af
push bc
push de
;imer_curscreen_value=$+1
;ld a,0
;ld bc,0x7ffd
;out (c),a
ex de,hl;ld hl,0
on_int_sp=$+1
ld (0),hl ;восстановили запоротый стек
push ix
push iy
ex af,af' ;'
exx
push af
push bc
push de
push hl
;curpalette=$+1
;ld de,wolfpal
;OS_SETPAL
curscrnum_int=$+1
ld e,0
OS_SETSCREEN
;pgmuznum=$+1
; ld a,0
; SETPG32KHIGH
call oldimer
GET_KEY
ld (curkey),a
if 1==0
ld a,(curpg32klow) ;ok
push af
ld a,(curpg32khigh) ;ok
push af
call setpgcode8000c000
call MUZHOOK ;muzplay
pop af
SETPG32KHIGH
pop af
SETPG32KLOW
;pgc000=$+1
; ld a,0
; SETPG32KHIGH
endif
pop hl
pop de
pop bc
pop af
exx
ex af,af' ;'
pop iy
pop ix
ld hl,(timer)
inc hl
ld (timer),hl
pop de
pop bc
pop af
on_int_hl=$+1
ld hl,0
on_int_sp2=$+1
ld sp,0
ei
on_int_jp=$+1
jp 0
setpgtiles4000
pgtiles=$+1
ld a,0
SETPG16K
ret
setpgtiles8000
ld a,(pgtiles)
SETPG32KLOW
ret
setpgcode4000
pgcode4000=$+1
ld a,0
SETPG16K
ret
setpgcode8000c000
pgcode8000=$+1
ld a,0
SETPG32KLOW
pgcodec000=$+1
ld a,0
SETPG32KHIGH
ret
gentiles
;call setpgtiles4000
ld l,0
gentiles0
ld h,0x20
ld d,0x40/8
ld a,l
add a,a
rl d
add a,a
rl d
add a,a
rl d
ld e,a
dup 8
ld a,(de)
ld (hl),-1;0
rla
rr (hl)
rla
rr (hl)
set 3,h
ld (hl),-1;0
rla
rr (hl)
rla
rr (hl)
res 3,h
set 4,h
ld (hl),-1;0
rla
rr (hl)
rla
rr (hl)
set 3,h
ld (hl),-1;0
rla
rr (hl)
rla
rr (hl)
res 3,h
res 4,h
inc e
inc h
edup
ld h,0x20
gentiles0atr0
ld d,0x60/8
ld a,l
add a,a
rl d
add a,a
rl d
add a,a
rl d
xor h
and 0xf8
xor h
ld e,a
ld a,(de) ;IiiiPppp
rra
rra
rra
rra
call geninkbyte
ld c,a
ld a,(de)
call geninkbyte
ld b,a
;ld bc,0b0000000011111111
;c=ink (IIiiiiii)
;b=paper (PPpppppp)
ld a,(hl)
rla
sbc a,a
ld e,a ;RRRRRRRR
ld a,(hl)
rla
rla
sbc a,a ;LLLLLLLL
xor e
and 0b01000111
xor e
ld d,a
;a=%RLRRRLLL
and c ;ink (IIiiiiii)
ld e,a
ld a,d
cpl
and b ;paper (PPpppppp)
or e
ld (hl),a
inc h
bit 6,h
jr z,gentiles0atr0
inc l
jp nz,gentiles0
;call setpgcode4000
;gen sprites
;The Sprite Pattern Table occupies 2 KB of VRAM from 3800H to 3FFFH. It contains two hundred and fifty-six 8x8 pixel patterns, numbered from 0 to 255.
;AC
;BD
;8 bytes block A
;8 bytes block B
;8 bytes block C
;8 bytes block D
;pattern 0..3 = pattern 0, pattern 4..7 = pattern 1...
;(decoded to 128 bytes per pattern in pgtiles)
call setpgtiles8000
ld hl,0x4000+0x1800
ld de,0x8000
ld b,2*64 ;halfsprites
genspr0
push bc
ld ix,0b0100000010000000
ld a,b
cp 2*64-7
jr nc,$+2+4
ld ix,0b0100011110111000
ld c,4
genspr0subcolumns
push hl
ld b,16
genspr00
;colors:
;0b1110 - road (and 0b1111)
;0b0001?- shadow
;0b0110 -our car(and 0b0111)
;0b0000 - enemy (and 0b0000)
ld a,0xff
rlc (hl)
jr nc,$+4
xor hx;0b01000000 ;change left pixel
rlc (hl)
jr nc,$+4
xor lx;0b10000000 ;change right pixel
ld (de),a
inc hl
inc de
djnz genspr00
pop hl
dec c
jr nz,genspr0subcolumns
ld bc,16
add hl,bc ;next column (halfsprite)
pop bc
djnz genspr0
call setpgcode8000c000
ret
geninkbyte
;a=????Iiii
;out: a=IIiiiiii
ld b,a
rla
rla
rla
xor b
and 0b01111000
xor b ;?Iiiiiii
rla ;Iiiiiii?
rlca ;iiiiii?I
rra ;Iiiiiii? (CY=I)
rra
ret
;0 чёрный
;1 чёрный
;2 тёмно-зелёный с синевой
;3 ярко-зелёный
;4 синий
;5 фиолетовый
;6 красный
;7 тёмно-голубой
;8 ярко-красный
;9 розовый
;a ярко-жёлтый
;b лимонный
;c тёмно-зелёный
;d ярко-голубой
;e серый (дорога)
;f белый
MACRO SPRCOLUMN
dup 15
ld a,(de)
and (hl)
ld (hl),a;0xaa
inc e
add hl,bc ;40
edup
ld a,(de)
and (hl)
ld (hl),a;0xaa
inc e
endm
macro NEXTCOLUMN
bit 6,h
set 6,h
jr z,$+2+4+2+2+1
ld a,h
xor 0x60
ld h,a
and 0x20
jr nz,$+3
inc hl
endm
;The Name Table occupies 768 bytes of VRAM from 1800H to 1AFFH (!!!3800!!!), the same as in 32x24 Text Mode. The table is initialized with the character code sequence 0 to 255 repeated three times and is then left untouched, in this mode it is the Character Pattern Table which is modified during normal operation.
;The Character Pattern Table occupies 6 KB of VRAM from 0000H to 17FFH. While its structure is the same as in the text modes it does not contain a character set but is initialized to all 0 pixels. The first 2 KB of the Character Pattern Table is addressed by the character codes from the first third of the Name Table, the second 2 KB by the central third of the Name Table and the last 2 KB by the final third of the Name Table. Because of the sequential pattern in the Name Table the entire Character Pattern Table is read out linearly during a video frame.
emulVDP
push bc
push de
push hl
curkey=$+1
ld a,0
cp key_esc
jp z,quiter
;wait for screen change
EmulatePPU_waitforscreenready0
ld hl,(timer)
endoflastredrawtimer=$+1
ld de,0
or a
sbc hl,de
jr z,EmulatePPU_waitforscreenready0
;ld a,(user_scr0_low) ;ok
;SETPG32KLOW
;ld a,(user_scr0_high) ;ok
;SETPG32KHIGH
call setpgsscr8000c000
;TODO draw only changed tiles
ld de,0x4000+0x3800 ;tilemap
ld hl,0x8000+4 ;screen
;ld hx,0x40 ;tile gfx base
ld b,24
emulVDPtiles0
push bc
ld a,24
sub b
rra
rra
rra
and 3
add a,0x40/8
ld hx,a ;tile gfx base
push hl
ld b,32
emulVDPtiles1
ld a,(de) ;tile
push bc
push de
push hl
ld bc,40
ld e,a
push hl
ld d,0x20
push hl
dup 7
ld a,(de)
ld (hl),a
inc d
add hl,bc
edup
ld a,(de)
ld (hl),a
pop hl
set 6,h
ld d,0x28
dup 7
ld a,(de)
ld (hl),a
inc d
add hl,bc
edup
ld a,(de)
ld (hl),a
pop hl
set 5,h
ld d,0x30
push hl
dup 7
ld a,(de)
ld (hl),a
inc d
add hl,bc
edup
ld a,(de)
ld (hl),a
pop hl
set 6,h
ld d,0x38
dup 7
ld a,(de)
ld (hl),a
inc d
add hl,bc
edup
ld a,(de)
ld (hl),a
pop hl
pop de
pop bc
inc de
inc hl
dec b
jp nz,emulVDPtiles1
pop hl
ld bc,40*8
add hl,bc
pop bc
dec b
jp nz,emulVDPtiles0
;The Sprite Attribute Table occupies 128 bytes of VRAM from 1B00H to 1B7FH /3b00/. The table contains thirty-two four byte blocks, one for each sprite. The first block controls sprite 0 (the "top" sprite), the ;second controls sprite 1 and so on to sprite 31. The format of each block is as below:
; Vertical Position Byte 0
; Horizontal Position Byte 1
; Pattern Number Byte 2
; EC 0 0 0 Colour Code(bits 3..0) Byte 3
;In Byte 3, the Early Clock bit is normally 0 but will shift the sprite thirty-two pixels to the left when set to 1. This is so that sprites can slide in from the left of the screen, there being no spare coordinates in the horizontal direction.
;The Sprite Pattern Table occupies 2 KB of VRAM from 3800H to 3FFFH /1800/. It contains two hundred and fifty-six 8x8 pixel patterns, numbered from 0 to 255.
;AC
;BD
;8 bytes block A
;8 bytes block B
;8 bytes block C
;8 bytes block D
;for 16x16 sprites: pattern 0..3 = pattern 0, pattern 4..7 = pattern 1...
ld hl,0x4000+0x3B7F
emulVDPsprites0
ld a,(hl) ;d3..0=colour code, d7=early clock (x-=32)
dec l
ld d,(hl) ;pattern number
dec l
ld c,(hl) ;x
dec l
ld b,(hl) ;y
or a
jp z,emulVDPsprites0_skip ;colour 0
inc b
ld a,b
cp 0xd1+1 ;???
jp nc,emulVDPsprites0_skip
inc c
srl c
srl c
srl c
ld a,c
add a,4
ld c,a
;srl b
;srl b
;srl b
ld a,b
cp 24 *8
jp nc,emulVDPsprites0_skip
push hl
;bc=yx
ld a,c ;x
ld l,b ;y
ld h,0
ld b,h
ld c,l
add hl,hl
add hl,hl
add hl,bc ;*5
add hl,hl
add hl,hl
add hl,hl ;*40
;add hl,hl
;add hl,hl
;add hl,hl
add a,l
ld l,a
ld a,h
adc a,0x80
ld h,a
call setpgtiles4000
ld bc,40
;d=pattern number
ld e,0
srl d
srl d ;pattern 0..3 = pattern 0, pattern 4..7 = pattern 1...
srl d
rr e
set 6,d ;ld d,0x40;+0x38 ;sprites
dup 8-1
push hl
SPRCOLUMN
pop hl
NEXTCOLUMN
edup
SPRCOLUMN
call setpgcode4000
pop hl
emulVDPsprites0_skip
dec l
jp p,emulVDPsprites0
ld hl,(timer)
ld (endoflastredrawtimer),hl
call changescrpg
call setpgcode8000c000
pop hl
pop de
pop bc
ret
pause
push af
push bc
push de
push hl
exx
ex af,af' ;'
push af
push bc
push de
push hl
push ix
push iy
halt ;YIELD
pop iy
pop ix
pop hl
pop de
pop bc
pop af
ex af,af' ;'
exx
pop hl
pop de
pop bc
pop af
ret
muztest
ei
halt
call L_9266 ;music player
jr muztest
L0020
;DCOMPR
;Address : #0020
;Function : Compares HL with DE
;Input : HL, DE
;Output : Z-flag set if HL and DE are equal. C-flag set if HL is less than DE.
;Registers: AF
push hl
or a
sbc hl,de
pop hl
ret
L003D
;???
;INIFNK
;Address : #003E
;Function : Initialises the contents of the function keys
;Registers: All
ret
L0047
;WRTVDP
;Address : #0047
;Function : write data in the VDP-register
;Input : B - data to write
; C - number of the register
;Registers: AF, BC
;can spoil bc
;TODO
ret
L004D
;WRTVRM
;Address : #004D
;Function : Writes data in VRAM
;Input : HL - address write (0..3fff)
; A - value write
;Registers: AF
push hl
set 6,h
ld (hl),a
pop hl
ret
L0056
;FILVRM
;Address : #0056
;Function : fill VRAM with value
;Input : A - data byte
; BC - length of the area to be written
; HL - start address
;Registers: AF, BC
push bc
push hl
set 6,h
FILVRM0
ld (hl),a
cpi
jp pe,FILVRM0
pop hl
pop bc ;unneeded?
ret
L005C
;LDIRVM
;Address : #005C
;Function : Block transfer to VRAM from memory
;Input : BC - blocklength
; DE - Start address of VRAM
; HL - Start address of memory
;Registers: All
push bc
push de
push hl
set 6,d
ldir
pop hl
pop de
pop bc ;unneeded?
ret
L00D5
;GTSTCK
;Address : #00D5
;Function : Returns the joystick status
;Input : A - Joystick number to test (0 = cursors, 1 = port 1, 2 = port 2)
;Output : A - Direction (1 up, 3 right, 5 down, 7 left)
;Registers: All
or a
jp nz,GTSTCK2
push bc
ld a,0x7f
in a,(0xfe)
bit 2,a ;'M'
jr nz,nomuzoff
ld a,(muzoff)
xor 0x80
ld (muzoff),a
push de
push hl
push ix
LD A,#07
CALL L0096
AND #C0
OR #38
LD E,A
LD A,#07
CALL L0093
LD E,#0e
LD A,#08
CALL L0093
LD A,#0a
CALL L0093
halt
halt
halt
pop ix
pop hl
pop de
nomuzoff
ld a,0xfe
in a,(0xfe)
bit 0,a
jr nz,nocheat
ld a,0xfd
in a,(0xfe)
bit 3,a
jr nz,nofuelcheat
xor a
;ld (fuelcheat1),a
ld b,a
ld c,a
ld (fuelcheat2),bc
nofuelcheat
ld a,0xbf
in a,(0xfe)
bit 1,a
jr nz,nolivescheat
xor a
ld (livescheat),a
nolivescheat
ld a,0xfb
in a,(0xfe)
bit 2,a
jr nz,noenemycheat
ld a,0xc9
ld (EnemyCollision),a
noenemycheat
nocheat
ld a,0xef
in a,(0xfe)
ld bc,0xdffe
in b,(c)
bit 0,b ;'p'
jr nz,$+4
res 3,a
bit 1,b ;'o'
jr nz,$+4
res 4,a
ld bc,0xfbfe
in b,(c)
bit 0,b ;'q'
jr nz,$+4
res 1,a
ld bc,0xfdfe
in b,(c)
bit 0,b ;'a'
jr nz,$+4
res 2,a
pop bc
rra
and 0x0f
ld hl,tstick
add a,l
ld l,a
jr nc,$+3
inc h
ld a,(hl)
ret
tstick
db 0,0,0,0
db 0,6,8,7
db 0,4,2,3
db 0,5,1,0
GTSTCK2
xor a
ret
L00D8
;GTTRIG
;Address : #00D8
;Function : Returns current trigger status
;Input : A - trigger button to test
; 0 = spacebar
; 1 = port 1, button A
; 2 = port 2, button A
; 3 = port 1, button B
; 4 = port 2, button B
;Output : A - #00 trigger button not pressed
; #FF trigger button pressed
;Registers: AF
or a
jr nz,GTTRIG2
ld a,0x7f
in a,(0xfe)
cpl
rra
jr c,gttrigok
ld a,0xef
in a,(0xfe)
cpl
rra
gttrigok
sbc a,a
ret
GTTRIG2
xor a
ret
setpgsscr8000c000
call getuser_scr_low
SETPG32KLOW
call getuser_scr_high
SETPG32KHIGH
ret
getuser_scr_low
getuser_scr_low_patch=$+1
getuser_scr_low_patchN=0xff&(user_scr0_low^user_scr1_low)
ld a,(user_scr1_low) ;ok
ret
getuser_scr_high
getuser_scr_high_patch=$+1
getuser_scr_high_patchN=0xff&(user_scr0_high^user_scr1_high)
ld a,(user_scr1_high) ;ok
ret
changescrpg
ld hl,getuser_scr_low_patch
ld a,(hl)
xor getuser_scr_low_patchN
ld (hl),a
ld hl,getuser_scr_high_patch
ld a,(hl)
xor getuser_scr_high_patchN
ld (hl),a
ld a,(curscrnum_int)
xor 1
ld (curscrnum_int),a
ret
display $
ds 0x2000-$
include "HWC1.ASM"
;>=0x4000 for system INT
MUZHOOK;#FD9F ;$FD9F is one of the interrupt service routine hooks (HTIMI) and it's called every 50/60 times per second by the BIOS.
ret
ret
ret
L0090
;GICINI
;Address : #0090
;Function : Initialises PSG and sets initial value for the PLAY statement
;Registers: All
shutay
push bc
push de
ld de,0xe00
shutay0
dec d
ld bc,0xfffd
out (c),d
ld b,0xbf
out (c),e
jr nz,shutay0
pop de
pop bc
ret
L0093
;WRTPSG
;Address : #0093
;Function : Writes data to PSG-register
;Input : A - PSG register number
; E - data write
push bc
ld bc,0xfffd
out (c),a
ld b,0xbf
out (c),e
pop bc
ret
L0096
;RDPSG
;Address : #0096
;Function : Reads value from PSG-register
;Input : A - PSG-register read
;Output : A - value read
push bc
ld bc,0xfffd
out (c),a
in a,(c)
pop bc
ret
end
display "End=",end
;display "Free after end=",/d,#c000-end
display "Size ",/d,end-begin," bytes"
savebin "hws.com",begin,end-begin
LABELSLIST "../../../us/user.l"