Hello all,
I am trying to remember how to (in assembler) get data to the CPC screen by moving the stack pointer to the screen address (i.e. &C000 upwards for 16k screen), reading the data from a DEFB (see code example) and then PUSHing it to the screen.
The DEFBs I am using are the ones outputted by ConvImgCPC, for example in a Mode 1 screen you have:
; Mode 1
; 80x200
DB #00, #00, #00, #00, #00, #00, #00, #F8
DB #F0, #F0, #F0, #F0, #E3, #00, #00, #00
DB #00, #00, #00, #00, #00, #00, #00, #00
...etc...
If I remember correctly, this technique is fast?
the stack goes backwards. So you should point SP at &0000 to start.
You'll need to point to the end of your gfx.
then do something like this:
;; HL = last byte in data
;; note low byte, high byte and order it will be pushed onto the stack!
ld d,(hl)
dec hl
ld e,(hl)
dec hl
ld b,(hl)
dec hl
ld c,(hl)
dec hl
push de
push bc
....
remember to disable interrupts too because this will cause problems and the firmware will not be happy.
Also, remember to restore stack if your using firmware too.
If you don't really need the speed then why not just use LDIR?
Thanks for that - I forgot the stack goes backwards! When I did it before I think I was only pushing 1 byte so it didn't really matter.
I am trying to create an animation on the CPC. For example, if I have two images, I am writing a small program which will detect the difference between the two and record it in a look-up table. I'm hoping the differences will be not too much, but I still think I need a fast routine to get the data to the screen because I'm assuming there is a limit in how much you can shift in one frame.
I will try a simple routine and see how much I can do...!
Okay, my memory of z80 is much worse than I thought - I want to use a look-up table to get a screen location and plot a byte there.
This works:
ld hl,data
ld a,(hl)
ld de,&c000
ld (de),a
.data
DB #00
But having the screen address in a table at the end doesn't work:
ld hl,data
ld a,(hl)
ld de,address
ld (de),a
.data
DB #00
.address
DW #c000
What am I doing wrong?!
Eventually, I want to be able to loop this, with a data table and a screen table to plot all the changes (excuse the pseudo-code I use before I program the real z80):
<count total of data entries>
<put total into register>
.loop
ld hl,data
ld a,(hl)
ld de,address
ld (de),a
<decrease total by 1 and loop again until 0 then exit - jr nz,loop or something>
.data
DB #00, #CF, #32, #00 etc
.address
DW #c000, #D040, #FF00, #E880 etc
Quote from: redbox on 22:49, 30 November 09
ld hl,data
ld a,(hl)
ld de,address
ld (de),a
.data
DB #00
.address
DW #c000
What am I doing wrong
This is logical, i you do : ld de,address , you will get adress in DE but if you do ld de,(address) you will get content of adress in DE
When using an address table you may do this :
ld IX,table
ld HL,data
... do you stuff ...
.loop
ld E,(IX+0)
ld D,(IX+1)
ld A,(HL)
ld (DE),A
inc HL
inc IX
inc IX
...do what you want and loop on .loop
.data
DB #00, #CF, #32, #00 etc
.table
DW #c000, #D040, #FF00, #E880 etc
But you may do something better using interleaved data and address , e.g :
ld HL,table
...other init stuff...
.loop
ld A,(HL) ;get data
inc HL
ld E,(HL) ;get scr address (in reverse order)
inc HL
ld D,(HL)
inc HL
ld (DE),A ;write it
...do your loop to .loop
.table
db #00:dw #C000
db #CF:dw #D040
.....etc....
Quote from: fano on 07:43, 01 December 09But you may do something better using interleaved data and address
Thanks fano - that's great!
Now I will have to start writing the loop code. I am thinking something on the lines of:
ld hl,table
ld b,end_table-table
.loop
...plot code...
dec b
jp nz,loop
.table
db #00:dw #C000
db #CF:dw #D040
.end_table
Can't try it until I get home but hopefully something like this will work (I saw a similar technique in some source code to work out the size of a raster from a table).
The only problem I can see in the future is this is okay for one table, but because it's an animation I am going to have lots of tables and the loop will become more complex, e.g.:
<currenttable = table1>
<big loop>
ld hl,currenttable
ld b,end_currenttable-currenttable
.loop
...plot code...
dec b
jp nz,loop
<goto big loop and change currenttable to table2, table3 etc until they are all done>
.table1
db #00:dw #C000
db #CF:dw #D040
.end_table1
.table2
db #EE:dw #E800
.end_table2
.table3
db #60:dw #D000
db #00:dw #E040
dv #40:dw #F080
.end_table3
What do you think?
Or perhaps if you want to use the stack, you could interleave it in pairs and pop the data like this:
; enter with b equal to the number of pairs in the table, and hl equal to the start of the table
; disable interupts and point stack to start of selected table
di
ld (SaveSP),sp
ld sp,hl
.ProcTableLoop
; read pair of addresses & bytes
pop hl
pop de
ld (hl),e
pop hl
ld (hl),d
djnz ProcTableLoop
; restore SP & interupts
ld sp,(SaveSP)
ei
...
.SaveSP
defw 0
.Table0
defw &c000: defb 255: defb 128: defw &c800
defw &f000: defb 255: defb 128: defw &e800
If you had an odd number of bytes to write, you'd need to just repeat the last, or write a dummy.
Great one Axelay ;D
A cool trick if you are using Winape about stack saving/restoring is using automodified code :
di
ld (save_stack),SP
...do you stuff...
save_stack EQU $+1
ld SP,0
ei
Quote from: redbox on 15:09, 01 December 09The only problem I can see in the future is this is okay for one table, but because it's an animation I am going to have lots of tables and the loop will become more complex
This is not really a problem if you use a "table of tables" and organize your plotting code as a subroutine :
.main
ld IX,main_table
ld B,table_count
.main_loop
ld L,(IX)
inc IX
ld H,(IX)
inc IX
call plot
djnz main_loop
;plot code
; in : HL table adress
; out : AF,DE,HL corrupted - BC,IX,IY unchanged
.plot
push BC
...do your stuff...
pop BC
ret
.main_table
dw table1,table2,table3,etc...
.table1
...stuff...
.table2
...stuff...
.table3
...stuff...
etc...
This is just an example , there a lot of way to do...
Wow, thanks guys - all very helpful.
Think I will write the 'traditional' version (using the table of tables) and then try the stack version to see how much quicker it is...!