Re: Video: Lesson P31 - Hardware Sprites on the MSX1!
Posted: Sat May 02, 2020 3:18 am
Hi,
I have gone through your tutorial (video and the writing) of
using tiles for simulating sprites on the MSX-1.
I have copied and pasted your code ,from
your files, into a simpler cartridge program that
has only MSX1 code-
(instead of leaving in all the code for all the
different platforms and using multiple files).
The only change I made to your code was to comment
out the line
ld hl, BitmapFont
in DOINIT since I do not require it
and I don't thinks fonts are used for
drawing the sprite-also I am just initialising
the screen 1 by simply calling the BIOS
address &006F.
The program, compiles without errors, but does not fully work-
it draws the tiles in the right place
but the tiles are not redefined as a sprite-see
the image,
The sprite used is yours from the Lesson.
So where is the bug?
Code is below. Also all used files are attached.
org &4000
db "AB";
dw Programstart ;
dw Programend ;
dw Programstart
INIT32 equ &006F
VdpOut_Data equ &98 ;For Data writes
VdpOut_Control equ &99 ;For Reg settings /Selecting Dest addr in VRAM
Programstart:
call INIT32 ; SCREEN 1
ld de,128
ld hl, SpriteData
ld bc, SpriteDataEnd-SpriteData
call DefineTiles
;We need to fill an area with numeric tiles, then we'll set those tiles to our chibiko character
ld bc,&0303 ;Start Position in BC
ld hl,&0606 ;Width/Height of the area to fill with tiles in HL
ld de,128
call FillAreaWithTiles ;Fill a grid area with consecutive tiles
Looppause:
jp Looppause
;------ code below is pasted copied and pasted from diffrent tutorials
GetColMemPos: ;Get a BC (XY) color memory pos, 32 chars per line, 8 bytes of color per char,
; this command uses Y as a bitmap line number (0-192), not a tile number (0-24)
push bc
ld a,c
and %11111000
and %11111000
rrca
rrca
rrca
or &20 ;Colors start at &2000
ld h,a
ld a,b
and %00011111
rlca
rlca
rlca
ld b,a
ld a,c
and %00000111
or b
ld l,a
call VDP_SetWriteAddress
pop bc
ret
CopyToVDP: ;Send data to the VDP using OUT commands
push bc
push hl
ex de,hl
call VDP_SetWriteAddress
pop hl
pop bc
inc b
inc c
CopyToVDP2:
ld a,(hl)
out (VdpOut_Data),a
inc hl
dec c
jr nz,CopyToVDP2
dec b
jr nz,CopyToVDP2
ret
ScreenINIT:
ret
DOINIT:
ld a, %00000010 ;mode 2
out (VdpOut_Control),a
ld a,128+0 ;0 - - - - - - M2 EXTVID
out (VdpOut_Control),a
ld a, %01000000 ;(show screen)
out (VdpOut_Control),a
ld a,128+1 ;1 4/16K BL GINT M1 M3 - SI MAG
out (VdpOut_Control),a
ld a, %10011111 ;Color table address ;%10011111=tile mode ; %11111111= bitmap mode
out (VdpOut_Control),a
ld a,128+3 ;3 CT13 CT12 CT11 CT10 CT9 CT8 CT7 CT6
out (VdpOut_Control),a
;in mode 2 control register #3 has a different meaning. Only bit 7 (CT13) sets the CT address.
;Somewhat like control register #4 for the PG, bits 6 - 0 are an ANDmask over the top 7 bits of the character number.
;Set Sprite attrib table to &1B00
ld a,%00110110
out (VdpOut_Control),a
ld a,128+5
out (VdpOut_Control),a
;ld a,%00000000
;out (VdpOut_Control),a
;ld a,128+11
;out (VdpOut_Control),a
;Set Sprite Pattern table to &3800
ld a,%00000111
out (VdpOut_Control),a
ld a,128+6
out (VdpOut_Control),a
ld a, %00000000 ;Pattern table address
out (VdpOut_Control),a
ld a,128+4 ;4 - - - - - PG13 PG12 PG11
out (VdpOut_Control),a
ld a, &F0 ;Text color
out (VdpOut_Control),a
ld a,128+7 ;7 TC3 TC2 TC1 TC0 BD3 BD2 BD1 BD0
out (VdpOut_Control),a
; ld hl, BitmapFont dont need for tile based software sprites
ld de, &0000 ; $8000
ld bc, 8*96 ; the ASCII char
call CopyToVDP ; load tile data
CLS:
ld hl,&1800 ;Set all the tiles to Zero
call VDP_SetWriteAddress
ld bc,&17FF
;ld d,0
FillRpt:
xor a; ;Write a Zero
out (VdpOut_Data),a
dec bc
ld a,b
or c
jr nz, FillRpt
ld hl,&2000 ;Clear all the color info, 8 lines per tile, 32x24 tiles=&1800
call VDP_SetWriteAddress
ld a,0
ld bc,&1800
FillRptnb:
ld a,&F0 ;Foreground / Background... F0=White/Black
out (VdpOut_Data),a
dec bc
ld a,b
or c
jr nz, FillRptnb
ret
VDP_SetReadAddress:
ld C,0 ;Bit 6=0 when reading, 1 when writing
jr VDP_SetAddress
prepareVram:
VDP_SetWriteAddress:
ld C,64 ;&40/64/Bit6
VDP_SetAddress:
ld a, l
out (VdpOut_Control), a
ld a, h
or C
out (VdpOut_Control), a
ret
SetHardwareSprite:
rlca ;4 bytes per sprite
rlca
push bc
push hl
ld h,&1B ;Sprite Attribs start at &1B00
ld l,a
call VDP_SetWriteAddress
pop hl
pop bc
ld a,c
out (VdpOut_Data),a ;y
ld a,B
out (VdpOut_Data),a ;x
ld a,h
out (VdpOut_Data),a ;Pattern
ld a,l
out (VdpOut_Data),a ;Color + 'EC'
;'EC' - early clock - shifts sprite 32 pixels left so sprites can be offscreen left
ld a,%00001000 ;turn on sprites
out (VdpOut_Control),a ;Set up Vram [VR=1] [SPD=SpriteDisable]
ld a,128+8
out (VdpOut_Control),a ;R#8 [MS ] [LP ] [TP ] [CB ] [VR ] [ 0 ] [SPD] [BW ]
ret
FillAreaWithTiles: ;Fill an area with consecutively numbered tiles, so we can simulate a bitmap area
;BC = X,Y
;HL = W,H
;DE = Start Tile
ld a,h
add b
ld h,a
ld a,l
add c
ld l,a
FillAreaWithTiles_Yagain:
push bc
push de
push hl
call GetVDPScreenPos
pop hl
pop de
FillAreaWithTiles_Xagain:
ld a,e
out (VdpOut_Data),a
inc e
inc b
ld a,b
cp h
jr nz,FillAreaWithTiles_Xagain
pop bc
inc c
ld a,c
cp l
jr nz,FillAreaWithTiles_Yagain
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Write Tile data to Vram
;Tile patterns start at &0000 - each tile is 8 bytes... we have 256 available.
;In theory, The tilemap supports 768 tiles, the first 1/3rd for the top part of the screen,
;The 2nd for the middle, and 3rd for the bottom... we use it to fake a bitmap mode, but it's slow, so we're not using it here.
DefineTiles: ;BC=Bytecount, HL=source, DE=Destination
push bc
ex de,hl
call prepareVram
ex de,hl
pop bc
DefineTiles2:
ld a,(hl)
out (VdpOut_Data),a
inc hl
dec bc
ld a,b
or c
jp nz,DefineTiles2
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetVDPScreenPos: ;Move the VDP write pointer to a memory location by XY location
push bc ;B=Xpos (0-31), C=Ypos (0-23)
ld h,0
ld l,c
or a
rl l ;32 bytes per line, so shift L left 5 times, and push any overflow into H
rl h
rl l
rl h
rl l
rl h
rl l
rl h
rl l
rl h
ld a,l
or b ;Or in the X co-ordinate
ld l,a
ld a,h
or &18 ;Tilemap starts at &1800
ld h,a
call VDP_SetWriteAddress
pop bc
ret
SpriteData:
incbin "C:\Spriteswithtiles\RawMSX1.RAW"
;;;;; the test sprite (from the tutorial) is in a folder named Sprites with tiles
SpriteDataEnd:
Programend:
org &C000;
I have gone through your tutorial (video and the writing) of
using tiles for simulating sprites on the MSX-1.
I have copied and pasted your code ,from
your files, into a simpler cartridge program that
has only MSX1 code-
(instead of leaving in all the code for all the
different platforms and using multiple files).
The only change I made to your code was to comment
out the line
ld hl, BitmapFont
in DOINIT since I do not require it
and I don't thinks fonts are used for
drawing the sprite-also I am just initialising
the screen 1 by simply calling the BIOS
address &006F.
The program, compiles without errors, but does not fully work-
it draws the tiles in the right place
but the tiles are not redefined as a sprite-see
the image,
The sprite used is yours from the Lesson.
So where is the bug?
Code is below. Also all used files are attached.
org &4000
db "AB";
dw Programstart ;
dw Programend ;
dw Programstart
INIT32 equ &006F
VdpOut_Data equ &98 ;For Data writes
VdpOut_Control equ &99 ;For Reg settings /Selecting Dest addr in VRAM
Programstart:
call INIT32 ; SCREEN 1
ld de,128
ld hl, SpriteData
ld bc, SpriteDataEnd-SpriteData
call DefineTiles
;We need to fill an area with numeric tiles, then we'll set those tiles to our chibiko character
ld bc,&0303 ;Start Position in BC
ld hl,&0606 ;Width/Height of the area to fill with tiles in HL
ld de,128
call FillAreaWithTiles ;Fill a grid area with consecutive tiles
Looppause:
jp Looppause
;------ code below is pasted copied and pasted from diffrent tutorials
GetColMemPos: ;Get a BC (XY) color memory pos, 32 chars per line, 8 bytes of color per char,
; this command uses Y as a bitmap line number (0-192), not a tile number (0-24)
push bc
ld a,c
and %11111000
and %11111000
rrca
rrca
rrca
or &20 ;Colors start at &2000
ld h,a
ld a,b
and %00011111
rlca
rlca
rlca
ld b,a
ld a,c
and %00000111
or b
ld l,a
call VDP_SetWriteAddress
pop bc
ret
CopyToVDP: ;Send data to the VDP using OUT commands
push bc
push hl
ex de,hl
call VDP_SetWriteAddress
pop hl
pop bc
inc b
inc c
CopyToVDP2:
ld a,(hl)
out (VdpOut_Data),a
inc hl
dec c
jr nz,CopyToVDP2
dec b
jr nz,CopyToVDP2
ret
ScreenINIT:
ret
DOINIT:
ld a, %00000010 ;mode 2
out (VdpOut_Control),a
ld a,128+0 ;0 - - - - - - M2 EXTVID
out (VdpOut_Control),a
ld a, %01000000 ;(show screen)
out (VdpOut_Control),a
ld a,128+1 ;1 4/16K BL GINT M1 M3 - SI MAG
out (VdpOut_Control),a
ld a, %10011111 ;Color table address ;%10011111=tile mode ; %11111111= bitmap mode
out (VdpOut_Control),a
ld a,128+3 ;3 CT13 CT12 CT11 CT10 CT9 CT8 CT7 CT6
out (VdpOut_Control),a
;in mode 2 control register #3 has a different meaning. Only bit 7 (CT13) sets the CT address.
;Somewhat like control register #4 for the PG, bits 6 - 0 are an ANDmask over the top 7 bits of the character number.
;Set Sprite attrib table to &1B00
ld a,%00110110
out (VdpOut_Control),a
ld a,128+5
out (VdpOut_Control),a
;ld a,%00000000
;out (VdpOut_Control),a
;ld a,128+11
;out (VdpOut_Control),a
;Set Sprite Pattern table to &3800
ld a,%00000111
out (VdpOut_Control),a
ld a,128+6
out (VdpOut_Control),a
ld a, %00000000 ;Pattern table address
out (VdpOut_Control),a
ld a,128+4 ;4 - - - - - PG13 PG12 PG11
out (VdpOut_Control),a
ld a, &F0 ;Text color
out (VdpOut_Control),a
ld a,128+7 ;7 TC3 TC2 TC1 TC0 BD3 BD2 BD1 BD0
out (VdpOut_Control),a
; ld hl, BitmapFont dont need for tile based software sprites
ld de, &0000 ; $8000
ld bc, 8*96 ; the ASCII char
call CopyToVDP ; load tile data
CLS:
ld hl,&1800 ;Set all the tiles to Zero
call VDP_SetWriteAddress
ld bc,&17FF
;ld d,0
FillRpt:
xor a; ;Write a Zero
out (VdpOut_Data),a
dec bc
ld a,b
or c
jr nz, FillRpt
ld hl,&2000 ;Clear all the color info, 8 lines per tile, 32x24 tiles=&1800
call VDP_SetWriteAddress
ld a,0
ld bc,&1800
FillRptnb:
ld a,&F0 ;Foreground / Background... F0=White/Black
out (VdpOut_Data),a
dec bc
ld a,b
or c
jr nz, FillRptnb
ret
VDP_SetReadAddress:
ld C,0 ;Bit 6=0 when reading, 1 when writing
jr VDP_SetAddress
prepareVram:
VDP_SetWriteAddress:
ld C,64 ;&40/64/Bit6
VDP_SetAddress:
ld a, l
out (VdpOut_Control), a
ld a, h
or C
out (VdpOut_Control), a
ret
SetHardwareSprite:
rlca ;4 bytes per sprite
rlca
push bc
push hl
ld h,&1B ;Sprite Attribs start at &1B00
ld l,a
call VDP_SetWriteAddress
pop hl
pop bc
ld a,c
out (VdpOut_Data),a ;y
ld a,B
out (VdpOut_Data),a ;x
ld a,h
out (VdpOut_Data),a ;Pattern
ld a,l
out (VdpOut_Data),a ;Color + 'EC'
;'EC' - early clock - shifts sprite 32 pixels left so sprites can be offscreen left
ld a,%00001000 ;turn on sprites
out (VdpOut_Control),a ;Set up Vram [VR=1] [SPD=SpriteDisable]
ld a,128+8
out (VdpOut_Control),a ;R#8 [MS ] [LP ] [TP ] [CB ] [VR ] [ 0 ] [SPD] [BW ]
ret
FillAreaWithTiles: ;Fill an area with consecutively numbered tiles, so we can simulate a bitmap area
;BC = X,Y
;HL = W,H
;DE = Start Tile
ld a,h
add b
ld h,a
ld a,l
add c
ld l,a
FillAreaWithTiles_Yagain:
push bc
push de
push hl
call GetVDPScreenPos
pop hl
pop de
FillAreaWithTiles_Xagain:
ld a,e
out (VdpOut_Data),a
inc e
inc b
ld a,b
cp h
jr nz,FillAreaWithTiles_Xagain
pop bc
inc c
ld a,c
cp l
jr nz,FillAreaWithTiles_Yagain
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Write Tile data to Vram
;Tile patterns start at &0000 - each tile is 8 bytes... we have 256 available.
;In theory, The tilemap supports 768 tiles, the first 1/3rd for the top part of the screen,
;The 2nd for the middle, and 3rd for the bottom... we use it to fake a bitmap mode, but it's slow, so we're not using it here.
DefineTiles: ;BC=Bytecount, HL=source, DE=Destination
push bc
ex de,hl
call prepareVram
ex de,hl
pop bc
DefineTiles2:
ld a,(hl)
out (VdpOut_Data),a
inc hl
dec bc
ld a,b
or c
jp nz,DefineTiles2
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetVDPScreenPos: ;Move the VDP write pointer to a memory location by XY location
push bc ;B=Xpos (0-31), C=Ypos (0-23)
ld h,0
ld l,c
or a
rl l ;32 bytes per line, so shift L left 5 times, and push any overflow into H
rl h
rl l
rl h
rl l
rl h
rl l
rl h
rl l
rl h
ld a,l
or b ;Or in the X co-ordinate
ld l,a
ld a,h
or &18 ;Tilemap starts at &1800
ld h,a
call VDP_SetWriteAddress
pop bc
ret
SpriteData:
incbin "C:\Spriteswithtiles\RawMSX1.RAW"
;;;;; the test sprite (from the tutorial) is in a folder named Sprites with tiles
SpriteDataEnd:
Programend:
org &C000;