Dark Bit Factory & Gravity
PROGRAMMING => Other languages => ASM => Topic started by: ninogenio on June 06, 2008
-
ive pulled a little clear screen function out of one of my books and it works just fine but i dont quite understand how ldir does it's job.
// ninos first z80 assembler mess around
// some screen constants
screen_addr: equ 16384
attr_addr: equ screen_addr+6144
// program placement in ram
org 24768
// main loop
MainLoop:
call ClearScreen
jp MainLoop
// clear screen subroutine
ClearScreen:
push af
push bc
push hl
ld hl,screen_addr
ld de,screen_addr+1
ld bc,6143
ld (hl),0
ldir
pop hl
pop bc
pop af
ret
acording to the book ldir will move hl 6143 times so does that mean that ldir is linked with bc or does it simply get its value from bc because bc was the last register loaded with a value.
-
Shit, you're taking me back a long time here Nino :D
Hehe, apologies if this is wrong, because the last time I used Z80 was when I was about 13 years old, here's what your code is doing..
By the way LDIR is short for load, increment and repeat.
push af : preserve these three registers
push bc
push hl
ld hl,screen_addr : point hl at the start of the screen
ld de,screen_addr+1 : put loacation +1 into register pair de
ld bc,6143 : bc holds the amount of times for ldir to repeat
ld (hl),0 : moves 0 into hl
ldir
pop hl : restore the three registers
pop bc
pop af
I think that a by product of ldir will make de=hl and therefore clear the screen that way.
But like I said, I have slept since I used Z80 last ;)
I dont think I'm far out though.... Need a Speccy to try it out on!
-
that makes a lot of sense shockwave cheers!
so if i am right ldir would take registers as so.
a source pointer a dest pointer and a counter.
cool but i wonder how fast it is ill try out some test's.
btw if you wish to build some of this stuff go here.
http://www.worldofspectrum.org/utilities.html
and pick an assembler from down the list i am using z80/.sna assembler and it seems to be doing what i want at this time.
-
I found only one page so far with instructions for the z80 and that page only named the instructions it didnt give away any details of what operation they did / its arguments / clock cycles etc, thats a real shame given how widely available similar info for the 6502 is. I would like to give the z80 an honest go myself but I think I will hold off until I have some more free time. But at the moment it is tempting.
-
If you do some I will too, maybe we can start a Z80 revival here :)
-
I think I will I have chosen the spectalutor + Z80 (sna) assembler Just reading through the manuals now.
-
lol I hadnt even got as far as downloading an emulator yet :)
-
Best of luck
This page is the best opcode reference I have found so far it gives a description of operation counts clock cycles tells you what flags may be affected and tells you how many bytes each requires. Everything you need to know
http://www.ftp83plus.net/Tutorials/z80inset_fullA.htm
This is more compact and has all the above except description of operation, better for looking at if you already know what each opcode do
http://www.shiar.org/product/z80.txt
-
very cool links rain! k+,
and as for the ldir instruction i found a detailed diagram on it's actions in my book it increases hl and de as well as simultaniously decreasing bc so it is tied to those registers. somehow though i suspect this is slower than some other methods.
-
There's no special ordering, the LDIR instruction works with all the current values of the registers.
It loads the data from the memory at (hl) and stores it at (de). It does this bc times.
Effectively it does
loop:
ld temp,(hl)
ld (de),temp
inc hl
inc de
dec bc
jr nz loop
It does this in a rather respectable 16 cycles per byte moved.
Now, the code you posted does a trick. The Z80 doesn't have a block clear instruction, only a block move instruction. What's happening here is it's block moving an overlapping memory area - normally you don't want this - but in this case it does something like
hl = screen address
de = screen address + 1
ld (hl),0 - clear the first byte of screen memory
ld bc,size of screen
ldir - copy the blank byte at screen address (hl) to screen address+1 (de) and repeat
As ldir executes it keeps moving that blank byte one space further on, and then copying it to the next location.
This might seem wasteful - re-reading the 0 as many times as writing it, but at only 16 cycles, it's faster than doing a loop which just stores zeroes.
Jim
-
cool cheers jim,
on the list that rain linked too it says the clock cycles for ldir are 21/16 and in my book it says that ldir takes up 21 so does that mean it can take either 21 clock cycles or 16 clock cycles?
-
When there are two speeds it usually means something like 16 clock cycles would be its normal operation speed but if it crosses a page boundary then it may take 21 clocks.
-
ah right cheers rain!
-
That's not right. If you see this it means that it takes 21 cycles if it loops and 16 cycles if it doesn't. For branches (jr cc) it's the same - 5 extra cycles if the branch is taken. (call cc is 7 extra).
Taking in to account these extra 5 cycles it might appear that this is a rubbish way to clear memory - but then consider this 'simpler' example:
ld a,0
ld hl,screensize
ld de,screen_ptr
ld bc,65535
loop:
ld (de),a 7
inc de 6
add hl,bc 11
jr nz loop 12
Wow! That's 36 cycles!
(You have to use add hl,bc because dec hl doesn't set any condition flags.)
The Z80 doesn't have any pages, it has a flat 64Kb address space. On the Spectrum 48K this is split into 3 main areas, 16Kb ROM, 16Kb screen, variables, and program data, 2x16Kb of general purpose memory.
It's the 2nd 16Kb that is interesting. The memory bandwidth for that RAM bank is shared between the CPU and the ULA (the display chip). Depending which bit of the screen is being updated by the ULA can mean you stall reading for up to 6 extra cycles. That might make the LDIR clear a bit worse because it is doing 6Kb of reads as well as 6Kb of writes, at an average of about 3 extra cycles per move, but that's still only 24.
Check out the 'Contended Memory' section here
http://www.worldofspectrum.org/faq/reference/48kreference.htm (http://www.worldofspectrum.org/faq/reference/48kreference.htm)
By the way, Spectaculator is shareware and cost £16 to register. ZX SPIN is free, and it has a built-in assembler - you might want to try that!
Jim
-
so its 21 if a branch is required and 16 if execution falls through?
on a side note, how does the cpu address 128k?
that ZX SPIN sounds a lot more useful
-
This would appear to have the answers you want Rain,
http://www.worldofspectrum.org/faq/reference/128kreference.htm (http://www.worldofspectrum.org/faq/reference/128kreference.htm)
-
Yup, Rain, that's absolutely right - 16 to copy the byte and change the register values (flags too), 5 to loop back. Effectively the CPU 'forgets' to increment the pc register after doing an ldi instruction. In 128K mode, 16Kb pages can be swapped in and out. eg. There are 2 16Kb ROMs on these machines, and the 16Kb containing the screen can be swapped, allowing real double buffering. Don't think anyone really used that though! Shockwave's link has all the details. WoS is the gold standard for this kind of information :)
Jim
-
cool stuff guys there is a load to digest here!
just wondering what methode was most common for displaying gfx on the speccy, ive looked at the example that comes with the z80/.sna asembler and the guy seems to draw directly to the screen a scan line at a time and during updates to the position of the gfx he clears and redraws the gfx a scanline at a time so in effect he never does a full screen clear this way is quick but is prone to tearing, is this the way most folks do it?
i wonder how good the 128 would be at double buffering, it would definitly be worth a go!
-
Since there's only one screen, most programs just draw to the screen and damn the tearing. As the years went on though, people got cleverer and synced the drawing just behind the ULA so no tearing. Hard to do though, and most people just stuck with it. If you look at some of the games that had rainbow fx - AgentX II, Zub, Uridium, etc, people were drawing a few bytes in front of the ULA, so they could change the 8x8 colour squares every scanline and get 8 colours per square!
I only ever saw one demo of page flipping on a 128Kb, and it was a flickery mess. I don't recall anyone using it.
Jim
-
yeah i read on the wiki that 8 colors per attribute square was possible and i really would like to have a go at that but for now ive stuck with the norm the only draw back is that you have to keep note of the sprites last position to erase it as a full screen clear per frame on the zx isnt really feasible.
i found a web site a while back and cant remeber the name of the site but it had some 128k demos ive attached my favourite, and im sure this must do double buffering.
but i cant understand how this sort of rendering is possible on the spectrum, do you guy's have any idea?
-
Awesome demo thats a whole lotta pixels pushing. I see why you like it. Couldnt imagine whats going on there behind the scenes to keep that frame rate up though.
-
No double buffering on that one nino - you can see the emulators emulating the tearing, especially during the yellow rotozoom! Nice demo though, great music!
Jim