Video: Lesson P31 - Hardware Sprites on the MSX1!

MSX & MSX2 including the V9990 GPU (V9K)
John
Posts: 13
Joined: Tue Mar 24, 2020 1:18 am

Re: Video: Lesson P31 - Hardware Sprites on the MSX1!

Post by John » 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;
Attachments
Spritewithtilesfiles_.zip
(2.97 KiB) Downloaded 17 times
1.PNG
1.PNG (74.53 KiB) Viewed 360 times

Voyager_sput
Posts: 14
Joined: Tue Jan 07, 2020 11:45 am

Re: Video: Lesson P31 - Hardware Sprites on the MSX1!

Post by Voyager_sput » Sun May 03, 2020 10:22 am

Hello John,

You almost had it. Note, i'm by far not a Z80 programmer (i'm more into 6502), but I got your code working.

The problem was in line 24 of your code:

Code: Select all

ld de,128
Loading the DE register for 128 tiles. But you should load it with 128 tiles with a size of 8 bytes per tiles, so like this:

Code: Select all

ld de,128*8
That should load Chibiko properly on your screen. Note 2) Chibiko is a bit white. As far as I understand the MSX1, you still need to load in the pallet data for the bitmap to get any colors on screen for the sprite.
Attachments
chibiko-msx1.PNG
chibiko-msx1.PNG (15.48 KiB) Viewed 358 times

John
Posts: 13
Joined: Tue Mar 24, 2020 1:18 am

Re: Video: Lesson P31 - Hardware Sprites on the MSX1!

Post by John » Mon May 04, 2020 3:13 pm

Hi Voyager_Sput,

Thanks . But there is another more subtle bug when I tried to use this code for animating sprites. Adding a simple infinite loop to the code , the relevant changes to the code is shown below, shows the bug



Programstart:
call INIT32 ; SCREEN 1

Programstartwithoutclearscreen:
ld de,128*8
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


jp Programstartwithoutclearscreen


;------ code below is pasted copied and pasted from diffrent tutorials



all I have done is add a simple infinite loop using the label Programstartwithoutclearscreen
everything else is the same as before (with your bugfix regarding register de of course).

The result is garbage/corruption added to the screen (screen shot attached)-you have to wait a while for the garbage to appear-maybe up to a minute.

For animating sprites, say using 2 frames, I would repeatedly
use the Definetiles subroutine, in an indefinite or infinite loop,
reloading the tiles for each frame of the sprite animation. But
this will cause the screen to go corrupt with garbage as described above. So where is the bug?
Attachments
2.PNG
2.PNG (34.82 KiB) Viewed 354 times

Voyager_sput
Posts: 14
Joined: Tue Jan 07, 2020 11:45 am

Re: Video: Lesson P31 - Hardware Sprites on the MSX1!

Post by Voyager_sput » Mon May 04, 2020 8:07 pm

Hi John,

That's a tough one. The definetiles part is fine, if I put the Programstartwithoutclearscreen: label lower, it still corrupts. Something is happening with the FillAreaWithTiles function. But i'm not sure what....

It's like something is corrupting a register or overflowing somewhere causing this weird behavior. I'm just not sure if it's a problem in the FillAreaWithTiles function or the GetVDPScreenPos function. The drawing is very dependent on the BC,HL, DE and A register. Any one of them could become corrupted somewhere along the line, I just can't see it. The pushes and pop's seem to be in place just fine.

I'd advise setting up some monitoring function (perhaps Keiths own function) or a debugger so you can see the state of the registers at certain points. The corruption appears instant, but given how fast it's running, it could very well have done 10's or 100's of loops before some memory value or register suddenly gets unexpected values. The way it looks now, something is overflowing so part of Chibiko are (also) loaded to her right, scrolling through some tiles. Perhaps that part also overflows eventually, causing the explosion of tiles in the botton of the screen (after about 17 seconds).

User avatar
akuyou
Posts: 398
Joined: Mon Apr 22, 2019 3:19 am
Contact:

Re: Video: Lesson P31 - Hardware Sprites on the MSX1!

Post by akuyou » Tue May 05, 2020 12:04 pm

Firstly make sure you've got interrupts disabled - the interrupt handler may mess with the VDP, so could be causing this.

If that fails, The VDP can take a little time to process the OUT commands... so put a few NOPs after each OUT and see if that fixes it.
Chibi Akuma(s) Comedy-Horror 8-bit Bullet Hell shooter! // 「チビ悪魔」可笑しいゴシックSTG ! // Work in Progress: ChibiAliens

Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809

Post Reply

Return to “MSX & MSX2 Assembly Programming”