Z80 Good Programming Practices
Using IX
If you have objects represented by adjacent chunks of data in memory, you can use IX to easily manage them.
Without | With |
---|---|
ld b,10 ld hl,SpritesData DisplaySpritesLoop ld b,(hl) ; coordx inc hl ld c,(hl) ; coordy inc hl ld d,(hl) ; first part of address inc hl ld e,(hl) ; end of address inc hl call DisplaySprite djnz DisplaySpritesLoop |
COORDX .equ 0 COORDY .equ 1 ADDR1 .equ 2 ADDR2 .equ 3 ld b,10 ld ix,SpritesData DisplaySpritesLoop ld b,(ix+COORDX) ld c,(ix+COORDY) ld d,(ix+ADDR1) ld e,(ix+ADDR2) call DisplaySprite ld hl,4 add ix,hl djnz DisplaySpritesLoop |
Defining constants for the offsets of each field of your "objects" makes the code more understandable. However this particular example is not the best, being that the original code is faster and smaller. Typically in sequential access using the HL register would perform better, however if random access of different objects and different elements in an object is required through out a particular iteration, than ix would be the better choice.
Lookup table
If you have a place in your code where a value is tested to choose between a lot of things, like subroutines or data, it can be a good idea to use lookup tables instead of a series of tests. It makes the code more readable, concise and extensible.
In terms optimisation though it should be used when the data is not sequentially ordered or when the objects being pointed to are not the same size. For example, using LUTs (Look Up Tables) to find a tile in a block of memory that is only tiles would both slower and cost more memory. Using LUTs to find a particular string would be quicker but would waste more memory than a linear search. Using LUTs as a jump table to different code blocks located through out a program would be faster and smaller compared to the alternative.
Without | With |
---|---|
ld a,(SpriteNumber) cp 1 jp z,ChooseSprite1 cp 2 jp z,ChooseSprite2 cp 3 jp z,ChooseSprite3 cp 4 jp z,ChooseSprite4 ... ChooseSprite1 ld hl,Sprite1 jp DisplaySprite ChooseSprite2 ld hl,Sprite2 jp DisplaySprite ChooseSprite3 ld hl,Sprite3 jp DisplaySprite ChooseSprite4 ld hl,Sprite4 jp DisplaySprite ... DisplaySprite ld bc,(coordinates) call SpriteRoutine |
ld a,(SpriteNumber) add a,a ; a*2 ld h,0 ld l,a ld de,SpriteAddressLUT add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a ld bc,(coordinates) call SpriteRoutine ... SpriteAddressLUT .dw Sprite1 .dw Sprite2 .dw Sprite3 .dw Sprite4 |
And this one :
Without | With |
---|---|
ld a,(MenuChoice) cp 1 jp z,Choice1 cp 2 jp z,Choice2 cp 3 jp z,Choice3 cp 4 jp z,Choice4 ... |
ld a,(MenuChoice) add a,a ; a*2 ld h,0 ld l,a ld de,CodeBranchLUT add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a jp (hl) ... CodeBranchLUT .dw Choice1 .dw Choice2 .dw Choice3 .dw Choice4 |