Assembly Language Help

The place for codemasters or beginners to talk about programming any language for the Spectrum.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Assembly Language Help

Post by Ast A. Moore »

RMartins wrote: Mon Apr 30, 2018 1:48 pm If you got used to recognize a set of specific addresses, than that probably works as a name or reference for you, but it will probably not work with others.

For example, a lot of the systems variables are named in the ZX manual, hence in practice we should use their names, since that is common knowledge, but that doesn't prevent individual A or B, to actually know their address values by heart. But that will not be the general case for sure.
It’s extremely easy to see at a glance whether an address is in ROM or RAM—any Spectrum developer knows that RAM starts at address $4000 (16384), so anything below that is a ROM call. Comments will help with the rest. The same applies to system variables.

I’ll reiterate: applying high-level programming language practices to assembly—particularly in the context of the Spectrum (what with it being a relatively simple machine)—will only muddy the waters and create confusion. The fewer levels of abstraction exist between the hardware and the software the better.

As for the opcode analogy, I think that’s strawmanning. Assembly already has a one-to-one correspondence between a mnemonic and its opcode, so there’s no practical need in memorizing the latter. In the rare cases of self-modifying code, when you need to inject a different opcode somewhere in your code, a quick glance at the Z80 instruction set is all that’s needed.

I agree about pattern recognition, but there’s also readability and efficiency. You can just as easily recognize the few ROM addresses that are practical to use in programming. Moreover, a fixed address will instantly tell you that you’re making a ROM call or addressing a system variable; whereas a label will signal to you that it’s a reference to a RAM address, which can move from location to location as you work on your code. When both are represented by a label—confusion will inevitably set in.

Either approach will work, of course. Any assembler will happily replace labels with constants or memory addresses. Readability is a different matter, however.

In any case, for the most part, this whole argument becomes moot at some point, as people tend to use ROM calls more and more sparingly once their programming skills have improved and they have come up with their own, more efficient routines.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Joefish
Rick Dangerous
Posts: 2058
Joined: Tue Nov 14, 2017 10:26 am

Re: Assembly Language Help

Post by Joefish »

If you're going to be showing your code to other people and asking them to help you fix it then it needs to be very clear what's going on.
Whether that's through commenting everything or using labels doesn't really matter, so long as it's clear. But using opcodes and 'magic numbers' without a comment makes the code very hard to read.

Using labels for things like system variable addresses and ROM routines is hardly a 'higher level language' concept though. It's been done for years. Having an include file with lables defined for all the system variables and the ROM functions (as listed in The Complete Spectrum ROM Disassembly) is/was a fairly common practice.
Ralf
Rick Dangerous
Posts: 2283
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Assembly Language Help

Post by Ralf »

Different strokes. I was never a big fan of this approach.
This a kind of a double edge sword.
It's a matter of your personal programming style. Eveybody may have his own.

Unfortunately in the past I have seen many really intellingent people going into not so intelligent fights about the style ;) In case of Z80 assembly it was either using decimal/hexadecimal or like here about labels, constants, comments.

Personally I use decimal notation in my programs and several times I was told that it's very wrong. But it just works for me. My answer was always the same - do it your way and let others to do it their way.

As for "magic numbers" my personal approach is something balanced. I never write code like LD (30000),A. Always use labels for such case.

But LD HL,16384 is much clearer for me than LD HL,Screen (what the hell is screen?)
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Assembly Language Help

Post by Ast A. Moore »

Joefish wrote: Mon Apr 30, 2018 2:57 pm Whether that's through commenting everything or using labels doesn't really matter, so long as it's clear. But using opcodes and 'magic numbers' without a comment makes the code very hard to read.
Well, duh. Most uncommented assembly listings are difficult to read. (If I don’t comment my own code profusely, I tend to forget what I was thinking writing it in less than a week.) Knowing some “magic numbers” helps, though.
Joefish wrote: Mon Apr 30, 2018 2:57 pmUsing labels for things like system variable addresses and ROM routines is hardly a 'higher level language' concept though. It's been done for years. Having an include file with lables defined for all the system variables and the ROM functions (as listed in The Complete Spectrum ROM Disassembly) is/was a fairly common practice.
Well, The Complete Spectrum ROM Disassembly aside (although it too suffers from readability issues, but it’s a special case), I think we need to make a clear distinction then between readability in general and readability as perceived by the author. I posit they are not the same. I personally find browsing through a gazillion include files maddening.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Assembly Language Help

Post by Ast A. Moore »

Ralf wrote: Mon Apr 30, 2018 3:09 pm I use decimal notation in my programs and several times I was told that it's very wrong. But it just works for me.
I use a mixture of all three: mostly decimals for arithmetic and known addresses (i.e. system variables), hexadecimals nice “round” numbers (when suitable) and some well-known locations (i.e. $4000, $5b00, etc.), and binary for when bits are important (i.e. attributes, port masks, etc.)

Occasionally, I even use arithmetic expressions (for fractional coordinates, for example):

Code: Select all

	ld hl,15+256*58		;L=15 (fraction), H=58 (integer)
I don’t think I’ve ever used octals, though. Hmm.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Ralf
Rick Dangerous
Posts: 2283
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: Assembly Language Help

Post by Ralf »

Occasionally, I even use arithmetic expressions (for fractional coordinates, for example):
Hehe, I do that too :) Things like LD HL,50*256+1

This way I can remain in decimal notation and still see high and low byte.
User avatar
Joefish
Rick Dangerous
Posts: 2058
Joined: Tue Nov 14, 2017 10:26 am

Re: Assembly Language Help

Post by Joefish »

The point of using named labels is so that the name itself is clear; you shouldn't have to refer to the include file that defines it to understand what it does.
User avatar
Seven.FFF
Manic Miner
Posts: 744
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Assembly Language Help

Post by Seven.FFF »

Joefish wrote: Mon Apr 30, 2018 4:31 pm The point of using named labels is so that the name itself is clear; you shouldn't have to refer to the include file that defines it to understand what it does.
Yes, indeed. If ld hl, Screen doesn't quite do it for you, call the constant ScreenPixelsStart or something! Although extensive commenting is invaluable, there's a certain amount of self-documentation available that can really help.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
PeterJ
Site Admin
Posts: 6873
Joined: Thu Nov 09, 2017 7:19 pm
Location: Surrey, UK

Re: Assembly Language Help

Post by PeterJ »

Thanks for all the comments. Coding style is indeed down to personal preference and I think where it's the equivalent of variables like plx and ply it makes sense to me, but where it's a ROM routine I think a remark is fine. I am trying to use useful names for labels though.
AndyC
Dynamite Dan
Posts: 1405
Joined: Mon Nov 13, 2017 5:12 am

Re: Assembly Language Help

Post by AndyC »

Ast A. Moore wrote: Mon Apr 30, 2018 2:31 pm It’s extremely easy to see at a glance whether an address is in ROM or RAM—any Spectrum developer knows that RAM starts at address $4000 (16384), so anything below that is a ROM call. Comments will help with the rest. The same applies to system variables.
Well, except when it isn't. Like on the +2A/+3.
Ast A. Moore wrote: Mon Apr 30, 2018 2:31 pm In any case, for the most part, this whole argument becomes moot at some point, as people tend to use ROM calls more and more sparingly once their programming skills have improved and they have come up with their own, more efficient routines.
Ironically, that's the biggest reason to use labels over comments. Because you're going to use labels when you use your own code (so gain consistency) and will also find it easier to swap out a ROM routine for a custom version when it's only a matter of removing the ROM label from your include rather than searching through the source looking for (hopefully) commented calls.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Assembly Language Help

Post by Ast A. Moore »

AndyC wrote: Mon Apr 30, 2018 6:11 pm
Ast A. Moore wrote: Mon Apr 30, 2018 2:31 pm It’s extremely easy to see at a glance whether an address is in ROM or RAM—any Spectrum developer knows that RAM starts at address $4000 (16384), so anything below that is a ROM call. Comments will help with the rest. The same applies to system variables.
Well, except when it isn't. Like on the +2A/+3.
Yeah . . . no. When someone’s at a level of proficiency he needs to use the special addressing mode on a +2A/+3, the last thing he’ll be looking for is a piece of advice on whether to use numeric addresses or name labels. ;) We’re talking beginner stuff here.
AndyC wrote: Mon Apr 30, 2018 6:11 pm
Ast A. Moore wrote: Mon Apr 30, 2018 2:31 pm In any case, for the most part, this whole argument becomes moot at some point, as people tend to use ROM calls more and more sparingly once their programming skills have improved and they have come up with their own, more efficient routines.
Ironically, that's the biggest reason to use labels over comments. Because you're going to use labels when you use your own code (so gain consistency) and will also find it easier to swap out a ROM routine for a custom version when it's only a matter of removing the ROM label from your include rather than searching through the source looking for (hopefully) commented calls.
Theoretically, maybe. In practice, though, if you’re replacing ROM routines with your own, you’re likely to use different parameters, so your whole setup prior to the call will need rewriting.

Even with ROM calls, you don’t always jump to the beginning of a routine; oftentimes, it’s more efficient to jump somewhere in the middle, and the point of entry might change depending on context. It’s easier and more straighforward to use a numeric address and a comment.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Einar Saukas
Bugaboo
Posts: 3097
Joined: Wed Nov 15, 2017 2:48 pm

Re: Assembly Language Help

Post by Einar Saukas »

Ast A. Moore wrote: Mon Apr 30, 2018 3:25 pmI don’t think I’ve ever used octals, though. Hmm.
Octals are great for attributes!
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Assembly Language Help

Post by Ast A. Moore »

Einar Saukas wrote: Tue May 01, 2018 3:07 pm
Ast A. Moore wrote: Mon Apr 30, 2018 3:25 pmI don’t think I’ve ever used octals, though. Hmm.
Octals are great for attributes!
True. I just see the entire attribute byte as binary for some reason. Probably out of habit. But, yeah, ignoring Bits 6 and 7, it lends itself to octal numbers very well.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Seven.FFF
Manic Miner
Posts: 744
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Assembly Language Help

Post by Seven.FFF »

I like to write attributes as binary with spaces, like %01 001 010.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
Morkin
Bugaboo
Posts: 3266
Joined: Mon Nov 13, 2017 8:50 am
Location: Bristol, UK

Re: Assembly Language Help

Post by Morkin »

PeterJ wrote: Sun Apr 29, 2018 6:02 pm
Image

Maybe I can get my title in WH Smiths for Christmas :-)
Cool..! Look forward to seeing the final game - looks like it could be a fun arcadey one..
My Speccy site: thirdharmoniser.com
User avatar
MatGubbins
Dynamite Dan
Posts: 1239
Joined: Mon Nov 13, 2017 11:45 am
Location: Kent, UK

Re: Assembly Language Help

Post by MatGubbins »

Yup, glad that you've taken the plunge into the deep depths of machine code and swimming to the surface. You'll have fun, you'll have late nights of decoding something, you'll have that evening of hitting a wall/shouting at the screen because of a stupid coding mistake (missing out a Z from a JP Z,nn or something similar), but you'll have the satisfaction of everything coming together and working how you want it to be, the enjoyment of re-writing the code to be faster and smaller, finding new ways to get a routine working and laughing at your own old code from a few weeks earlier that you thought was oh-so great but now you would quite happily bury it under the patio with next doors cat.

Enjoy!
User avatar
PeterJ
Site Admin
Posts: 6873
Joined: Thu Nov 09, 2017 7:19 pm
Location: Surrey, UK

Re: Assembly Language Help

Post by PeterJ »

Thanks for all the comments everyone.

Another question if I may. If I use Call label-name, then from that have another call to a different label-name, and Ret at the end of each label does the Z80 keep track and return to after the last call instruction issued?

So I suppose I'm asking is it OK to have a call to a subroutine within another subroutine?

Thanks
User avatar
R-Tape
Site Admin
Posts: 6402
Joined: Thu Nov 09, 2017 11:46 am

Re: Assembly Language Help

Post by R-Tape »

PeterJ wrote: Wed May 02, 2018 4:52 pm Thanks for all the comments everyone.

Another question if I may. If I use Call label-name, then from that have another call to a different label-name, and Ret at the end of each label does the Z80 keep track and return to after the last call instruction issued?

So I suppose I'm asking is it OK to have a call to a subroutine within another subroutine?

Thanks
That's most definitely okay, and you will struggle to make complex programs otherwise.

When you CALL a subroutine the 16 bit address to RETurn to is automatically PUSHed on the stack so the stack builds downwards by two bytes every time. CALL another one and it builds down again. You can just keep doing this as long as the stack doesn't get too big and write over your program.

So this is perfectly fine:

Code: Select all

sub1:	call sub2	;address r1 pushed onto the stack
r1:	ret
	;
sub2:	call sub3	;address r2 pushed onto the stack
r2:	ret
	;
sub3:	call sub4	;address r3 pushed onto the stack
r3:	ret
	;
sub4:	call sub5	;address r4 pushed onto the stack
r4:	ret
	;
sub5	do stuff*
	ret

*when we are here the stack looks like this:

SP>	r4
	r3
	r2
	r1

So when we RET from sub5, we POP r4 and the stack reduces by two, we return to r4, the next RET to r3 and so on.
It's the same as PUSH and POP, you need to keep an eye on what your last CALL was so you know where you return to, it has to balance (unless you're doing trickery which I don't recommend yet).

This can cause a LOT of problems early on, but keeping the stack balanced becomes second nature sooner or later. The books do a decent job of explaining, but in my case I only fully 'got' it after trial and error.
Post Reply