Author Topic: PUSHing data to the screen via stack  (Read 3542 times)

0 Members and 1 Guest are viewing this topic.

Offline redbox

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.788
  • Country: gb
    • redbox
  • Liked: 406
  • Likes Given: 287
PUSHing data to the screen via stack
« on: 17:00, 30 November 09 »
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:

Code: [Select]
; 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?
« Last Edit: 17:05, 30 November 09 by redbox »

Offline arnoldemu

  • Supporter
  • 6128 Plus
  • *
  • Posts: 5.336
  • Country: gb
    • Unofficial Amstrad WWW Resource
  • Liked: 2280
  • Likes Given: 3478
Re: PUSHing data to the screen via stack
« Reply #1 on: 17:39, 30 November 09 »
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

Offline redbox

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.788
  • Country: gb
    • redbox
  • Liked: 406
  • Likes Given: 287
Re: PUSHing data to the screen via stack
« Reply #2 on: 18:20, 30 November 09 »
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...!
« Last Edit: 23:46, 30 November 09 by redbox »

Offline redbox

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.788
  • Country: gb
    • redbox
  • Liked: 406
  • Likes Given: 287
Re: PUSHing data to the screen via stack
« Reply #3 on: 23:49, 30 November 09 »
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:

Code: [Select]
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:

Code: [Select]
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):

Code: [Select]

<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
« Last Edit: 00:11, 01 December 09 by redbox »

Offline fano

  • Supporter
  • 6128 Plus
  • *
  • Posts: 835
  • Country: fr
  • Easter Egg Programmer
    • Easter Egg
  • Liked: 278
  • Likes Given: 614
Re: PUSHing data to the screen via stack
« Reply #4 on: 08:43, 01 December 09 »
Code: [Select]
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 :

Code: [Select]
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 :

Code: [Select]
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....
« Last Edit: 14:18, 01 December 09 by fano »
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !

Offline redbox

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.788
  • Country: gb
    • redbox
  • Liked: 406
  • Likes Given: 287
Re: PUSHing data to the screen via stack
« Reply #5 on: 16:09, 01 December 09 »
But 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:

Code: [Select]
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.:

Code: [Select]
<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?

Offline Axelay

  • 6128 Plus
  • ******
  • Posts: 594
  • Country: au
  • Liked: 394
  • Likes Given: 89
Re: PUSHing data to the screen via stack
« Reply #6 on: 17:22, 01 December 09 »
Or perhaps if you want to use the stack, you could interleave it in pairs and pop the data like this:

Code: [Select]
; 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.

Offline fano

  • Supporter
  • 6128 Plus
  • *
  • Posts: 835
  • Country: fr
  • Easter Egg Programmer
    • Easter Egg
  • Liked: 278
  • Likes Given: 614
Re: PUSHing data to the screen via stack
« Reply #7 on: 20:02, 01 December 09 »
Great one Axelay  ;D

A cool trick if you are using Winape about stack saving/restoring is using automodified code :

Code: [Select]
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 !

Offline fano

  • Supporter
  • 6128 Plus
  • *
  • Posts: 835
  • Country: fr
  • Easter Egg Programmer
    • Easter Egg
  • Liked: 278
  • Likes Given: 614
Re: PUSHing data to the screen via stack
« Reply #8 on: 20:24, 01 December 09 »
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
This is not really a problem if you use a "table of tables" and organize your plotting code as a subroutine :

Code: [Select]
.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...
« Last Edit: 21:10, 01 December 09 by fano »
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !

Offline redbox

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.788
  • Country: gb
    • redbox
  • Liked: 406
  • Likes Given: 287
Re: PUSHing data to the screen via stack
« Reply #9 on: 12:08, 02 December 09 »
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...!