As you're just starting out you should get into the early habit of looking for redundancy in your code. As your projects become more and more involved you will find yourself wishing the Z80 ran a lot faster than 3.5mhz! Shaving clock cycles (the time the Z80 spends processing each instruction) from within your code should become second nature - and it's better to get into the habit now!
Very quickly looking at your code there are a few areas (marked in red) where some cycles could be saved:
;Prints numbers 1-20 to the screen
xor a
ld (5C3Ch),a ;open screen for printing
;
[COLOR="Red"][b]ld a,0 ;Redundant as A is already 0 here[/b][/COLOR]
loop inc a
ld b,0 ;[COLOR="Red"][B]This *MIGHT* be redundant - see my text below[/B] [/COLOR]
ld c,a ;load bc with a
push af ;push a out of way for a bit
call 6683 ;print bc
ld a,13 ;
rst 10h ;print Return
pop af ;get back a
cp 20 ;a-20=...
ret z ;exit if 20-20=0
jr loop ;next number!
I've never used the ROM to do any screen printing stuff - so the LD B,0 *might* be redundant too, providing the call to 6683 doesn't destroy the BC pair? If so, then you could move the LD B,0 outside of the main loop, and pre-load it with the (already) zeroed A from above. Sinclair ROM aficionados will put you right on that one! ;)
I suppose at the moment machine code seems to be just so ultra-fast? Perhaps even too fast? But, as I mentioned above, it won't be long before you wish the Z80 was *much* faster! What, you don't believe me?! Just wait and see! ;);)
Getting into the habit of looking for redundant code early on in your Z80 career makes lots of sense! :p
Yup I totally hear what you're saying; good advice there - thanks for those tips Chris. As you said, it's good to get into good habits early before they become habitual, especially when dealing with low level skuzzy assembler :confused:
Half the problem I find is adjusting one's analogue organic brain to the mindset of bitty, flippy minimalist Z80.. know what I mean? Especially when you're used to working in BASIC and all those bitty flippy bits are done for you without you having to worry about it.
Interestingly when you dis-assemble this because there's a DEF* statement in the middle of the program it comes up with gibberish after this point. Any way around this?
Not really, no... It's a fact of writing machine code that when you assemble a program, a significant portion of the information that's meaningful to the programmer is stripped out - this includes label names, and whether a particular string of bytes is meant to be treated as code or data. With enough manual work you can reconstruct that information (and certain tools like code tracers can help) but the real way around it is to make sure you don't lose your original source code :-)
Not really, no... It's a fact of writing machine code that when you assemble a program, a significant portion of the information that's meaningful to the programmer is stripped out - this includes label names, and whether a particular string of bytes is meant to be treated as code or data. With enough manual work you can reconstruct that information (and certain tools like code tracers can help) but the real way around it is to make sure you don't lose your original source code :-)
Whoah, I made it into a sig and have less than 20 posts
Yah.. I thought it summed it up nicely.. the paradigm shift in computer programming between to 80s and the noughties.. I mean tweenies or whatever...
So, the go-faster code now looks like....
; PRINT A MESSAGE THEN CHANGE BORDER COLOUR LOTS OF TIMES
;
xor a
ld (5C3Ch),a
;
call WrtMsg
defm 16,4,17,2,22,11,7,"Hi there, partner!",0
;
ld hl,60000
;
loop2 ld a,8
;
loop dec a ;[U]THIS I PRESUME CHANGES the [b]Z[/b] flag if a=0 but not the [b]C[/b] flag?[/u]
out (254),a
jr nz,loop
;
dec hl
ld a,h
or l
jr nz,loop2
ret
;
;
;
WrtMsg pop hl
ld a,(hl)
inc hl
push hl
and a
ret z
rst 10h
jr WrtMsg
Thanks for that OR L tip for HL looping.. nice one - this is what I mean.. Z80 programming is faster than greased lighting but it's so abstract. The art of it is trying to think like a computer... it don't come natural... it ain't intuitive.. at least not to me.. I usually end up scrabbling round with a pencil and paper trying to get into my head why OR L works the way it does in that example or why XOR A is the same as LD A,0 etc.
I've never used the ROM to do any screen printing stuff - so the LD B,0 *might* be redundant too, providing the call to 6683 doesn't destroy the BC pair? If so, then you could move the LD B,0 outside of the main loop, and pre-load it with the (already) zeroed A from above. Sinclair ROM aficionados will put you right on that one! ;)
Alas 6683 [$1A1B] preserves most registers apart from the main BC pair which is left holding -10 [$FFF6]. A nice one to check this as
PRINT USR 6683 outputs 668365526
The first 6683 is printed in machine code as BC holds the argument to USR and the 65526 [65536 -10] is printed by BASIC as the returned value of BC.
The fact that B always holds $FF could still be useful in speeding it up slightly as INC B is faster than LD B,0 in a loop.
The WriteMsg in the second routine is lovely using the stack to find the data following the CALL. Most of the Jupiter Ace ROM is written like this with some quite complicated structures following the CALL.
Yah.. I thought it summed it up nicely.. the paradigm shift in computer programming between to 80s and the noughties.. I mean tweenies or whatever...
It was the Noughties, now it's the Oonies.
My username originally from paradigm shift from procedural (C) to OOP (C++) but also applies to many other things. e.g. Z80 assembler which I am just teaching myself now in order to buff my low level skills, I thought C was low-level enough, lol.
Anyway expect my first game whenever, Kerfuffle is the working title it'll be like a cross between berzerk and robotron and nemesis.
Getting into the habit of looking for redundant code early on in your Z80 career makes lots of sense! :p
Agreed, but it's just as important to learn when not to optimise.
To keep us on topic.. I use Pasmo and some purpose-written tools (graphics converters, tap makers and so on) all tied together with makefiles. If you start working on large projects with code and data coming from many different source files then you'll find a solid build system pretty essential if you want to remain sane ;)
That's scary. Sounds like some California offshoot of the Moonies to me... Welcome to the age of unreason :)
My username originally from paradigm shift from procedural (C) to OOP (C++) but also applies to many other things. e.g. Z80 assembler which I am just teaching myself now in order to buff my low level skills, I thought C was low-level enough, lol...
Ha Ha! I don't think I'll be learning C++ anytime soon.. I tried once.. got to about page 28 in a Learn C++ manual (out of 1000) & then gave up :grin: my poor ol' brain is struggling enough wi' Z80!
;Prints numbers 1-20 to the screen
xor a
ld (5C3Ch),a ;open screen for printing
;
loop inc a
ld c,a ;load bc with a
push af ;push a out of way for a bit
call #2f86 ;print bc, also set B=0
ld a,13 ;
rst 10h ;print Return
pop af ;get back a
cp 20 ;a-20=...
ret z ;exit if 20-20=0
jr loop ;next number!
Not faster, but shorter in memory. Can therefore be used in MINIGAMES.
The assembler may still be updated. Although I'm no longer working on SPIN itself, I am still working - intermittently - on the assembler as a separate project. Changes made to it *should* still find their way into SPIN, barring some major incompatibility, but I'm striving to avoid those. Incidentally, the assembler in the new version of SPIN does/should (finally) have macro capability despite remarks by Dunny in earlier posts - he's presumably unaware of this.
Not that anyone cares really as I gather that about 2 people ever used SPIN to assemble anything! And I was one of those!
Count me in there... Your work for the spectrum scene is much much appreciated there Marko, and I know Im not alone in saying that... Its not just the software either, your posts have also been helpful and enlightening much of the time too... Keep up the Good Work!
1) sjasmplus has pseudo op-codes for things like ld iy, hl (does push hl, pop iy), is that a feature of most assemblers or is sjasmplus weird? This will only be an issue if I change assemblers of course.
2) What's with the memory window in the Spin debugger? You can't go to an address by typing in the number :( If I import the symbols will I be able to do this? I guess I'll have to look at how to get sjasmplus to produce a symbol file in that case ;)
3) Can you do a break on data read/write or does it only break when the PC gets to a specific value?
Spin is great but I couldn't find any help for the debugger which is the most mportant bit for programmers ;)
Count me in there... Your work for the spectrum scene is much much appreciated there Marko, and I know Im not alone in saying that... Its not just the software either, your posts have also been helpful and enlightening much of the time too... Keep up the Good Work!
Agreed - it's a luxury to be able to assemble and immediately test, whether the results are good or bad ;)
I don't use assembler In Spin although I would like to. I would just like to see one day a documentation and maybe a bug list to know what is not working.
I use however breakpoints with waddr and raddr options. Very useful and not present in any other emulator I know.
I don't use assembler In Spin although I would like to. I would just like to see one day a documentation and maybe a bug list to know what is not working.
Comments
Yup I totally hear what you're saying; good advice there - thanks for those tips Chris. As you said, it's good to get into good habits early before they become habitual, especially when dealing with low level skuzzy assembler :confused:
Half the problem I find is adjusting one's analogue organic brain to the mindset of bitty, flippy minimalist Z80.. know what I mean? Especially when you're used to working in BASIC and all those bitty flippy bits are done for you without you having to worry about it.
WWW
Not really, no... It's a fact of writing machine code that when you assemble a program, a significant portion of the information that's meaningful to the programmer is stripped out - this includes label names, and whether a particular string of bytes is meant to be treated as code or data. With enough manual work you can reconstruct that information (and certain tools like code tracers can help) but the real way around it is to make sure you don't lose your original source code :-)
Yah.. that makes sense..
Yah.. I thought it summed it up nicely.. the paradigm shift in computer programming between to 80s and the noughties.. I mean tweenies or whatever...
So, the go-faster code now looks like....
; PRINT A MESSAGE THEN CHANGE BORDER COLOUR LOTS OF TIMES ; xor a ld (5C3Ch),a ; call WrtMsg defm 16,4,17,2,22,11,7,"Hi there, partner!",0 ; ld hl,60000 ; loop2 ld a,8 ; loop dec a ;[U]THIS I PRESUME CHANGES the [b]Z[/b] flag if a=0 but not the [b]C[/b] flag?[/u] out (254),a jr nz,loop ; dec hl ld a,h or l jr nz,loop2 ret ; ; ; WrtMsg pop hl ld a,(hl) inc hl push hl and a ret z rst 10h jr WrtMsgThanks for that OR L tip for HL looping.. nice one - this is what I mean.. Z80 programming is faster than greased lighting but it's so abstract. The art of it is trying to think like a computer... it don't come natural... it ain't intuitive.. at least not to me.. I usually end up scrabbling round with a pencil and paper trying to get into my head why OR L works the way it does in that example or why XOR A is the same as LD A,0 etc.
WWW
Alas 6683 [$1A1B] preserves most registers apart from the main BC pair which is left holding -10 [$FFF6]. A nice one to check this as
PRINT USR 6683 outputs 668365526
The first 6683 is printed in machine code as BC holds the argument to USR and the 65526 [65536 -10] is printed by BASIC as the returned value of BC.
The fact that B always holds $FF could still be useful in speeding it up slightly as INC B is faster than LD B,0 in a loop.
The WriteMsg in the second routine is lovely using the stack to find the data following the CALL. Most of the Jupiter Ace ROM is written like this with some quite complicated structures following the CALL.
It was the Noughties, now it's the Oonies.
My username originally from paradigm shift from procedural (C) to OOP (C++) but also applies to many other things. e.g. Z80 assembler which I am just teaching myself now in order to buff my low level skills, I thought C was low-level enough, lol.
Anyway expect my first game whenever, Kerfuffle is the working title it'll be like a cross between berzerk and robotron and nemesis.
To keep us on topic.. I use Pasmo and some purpose-written tools (graphics converters, tap makers and so on) all tied together with makefiles. If you start working on large projects with code and data coming from many different source files then you'll find a solid build system pretty essential if you want to remain sane ;)
Ha Ha! I don't think I'll be learning C++ anytime soon.. I tried once.. got to about page 28 in a Learn C++ manual (out of 1000) & then gave up :grin: my poor ol' brain is struggling enough wi' Z80!
Yeah, it's a beauty itsn't it. Got that out of Toni Baker's Mastering Machine Code On Your ZX Spectrum. Think I chose the right book there.
WWW
The assembler may still be updated. Although I'm no longer working on SPIN itself, I am still working - intermittently - on the assembler as a separate project. Changes made to it *should* still find their way into SPIN, barring some major incompatibility, but I'm striving to avoid those. Incidentally, the assembler in the new version of SPIN does/should (finally) have macro capability despite remarks by Dunny in earlier posts - he's presumably unaware of this.
Not that anyone cares really as I gather that about 2 people ever used SPIN to assemble anything! And I was one of those!
Absolute twaddle. I know about 189 off the top of my head :evil:
Is that hex?
No, it's Bandit :evil:
Do you want some Headex for that?
Well, I use it... and I can't imagine I'm the other one you're referring to... so that's at least, erm... *counts on fingers*... three!
A few questions though:
1) sjasmplus has pseudo op-codes for things like ld iy, hl (does push hl, pop iy), is that a feature of most assemblers or is sjasmplus weird? This will only be an issue if I change assemblers of course.
2) What's with the memory window in the Spin debugger? You can't go to an address by typing in the number :( If I import the symbols will I be able to do this? I guess I'll have to look at how to get sjasmplus to produce a symbol file in that case ;)
3) Can you do a break on data read/write or does it only break when the PC gets to a specific value?
Spin is great but I couldn't find any help for the debugger which is the most mportant bit for programmers ;)
Agreed - it's a luxury to be able to assemble and immediately test, whether the results are good or bad ;)
http://www.worldofspectrum.org/forums/showthread.php?p=224831
Not sure what you mean with no.2, you're not on about "View>Goto>Address" are you?
Marko's a good lad, only one thing wrong with him in fact. He's a sock :evil:
I've tried and failed to work out what you meant there...
Excellent, now I can set breaks on read/write.
View->Goto>Address works too!
But you can't just type an address into the address drop down of the memory window, it just beeps if I try and do that.
Thanks!
Bytes:Chuntey - Spectrum tech blog.
I use however breakpoints with waddr and raddr options. Very useful and not present in any other emulator I know.
Well, there's always: http://www.worldofspectrum.org/forums/showthread.php?t=27883.
It's about the only useful thing I've done on WoS, so I have to keep mentioning it... ;)