News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_redbox

PUSHing data to the screen via stack

Started by redbox, 16:00, 30 November 09

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

redbox

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?

arnoldemu

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?
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

redbox

#2
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...!

redbox

#3
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


fano

#4
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....
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !

redbox

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?

Axelay

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.

fano

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
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !

fano

#8
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...
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !

redbox

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...!

Powered by SMFPacks Menu Editor Mod