WACCI 137 Index - Home Page www.wacci.org.uk
01 - Thanx & Stuff | 02 - Fair Comment | 03 - New Generation | 04 - Exploring the PSG |
05 - Programmers' Patch | 06 - CPC Changed My Life | 07 - Cartography |
Matthew Phillips takes a look at the most popular assemblers that the CPC machine code programmer can choose between
Last time I was trying to transfer some vital files from the Amstrad CPC to the Acorn, using some very unorthodox methods! Since then, the replacement drive belts ordered from that marvellous man Brian Watson have arrived, and once fitted the old three incher has been working fine again. So, have I got any further with the job of developing the patch for CP/M Plus that I was talking of two years ago? Funnily enough, I have not...
This month, I thought we would do something rather more useful, by looking at some assemblers which are available for Z80 coding. The assembler is a vital part of the programmer's kit, which converts assembly language mnemonics into a machine code binary file. For any other language, the equivalent tool is called a compiler, but for some reason it is called an assembler for assembly language, which is the very lowest level of coding.
The first assembler I ever used was one which was published as a BASIC listing in Computing with the Amstrad, July 1985. It's not bad for what it is, and various modifications were published in the letters pages of that magazine over the following months. I wouldn't on the whole recommend it now, as there are much better alternatives available free of charge, but the course on machine code which ran from January 1985 to December 1986 in that magazine is still one of the best introductions to machine code on the Amstrad.
I would also recommend Mastering Machine Code on your Amstrad 464/664/6128 by Clive Gifford and Scott Vincent, Interface Publications, 1986. Of course, it's no longer in print, but should you see it anywhere, it's worth a read. (Seconded - Richard)
The worst thing about RAW, as the assembler was called, was that it was very slow. Being written in BASIC, if you were assembling anything moderately big, it would take half an hour or more. The worst annoyance was when, towards the end of the second pass, it would find that a relative address was out of range, and you would then have to go back, alter the code, and assemble again. And that was before you got onto the debugging.
After four years of extremely slow assembling, I joined WACCI, and ordered a disc full of machine code tools. Almost all of the WACCI PD library was CP/M stuff in those days. There were several assemblers available, but the one I picked on was called ZMac, which announced itself as "SSD Relocating (and eventually macro) Z80 assembler ver 1.07'. I don't think it ever reached the macro stage!
Assembling was a two-stage process. First you use ZMac to convert the assembly language source files into relocatable object files, and then you use ZLink to join the object files together to produce your CP/M executable .COM file. This concept of a linker is very common when you are using "real" programming tools. It means that the source code can be divided up into manageable chunks. Also, if you have only altered one of the source files, you only need to pass that one through ZMac, rather than reassembling all of the object files.
I wrote a little CP/M application (assembled with ZMac and ZLink) called ZBin, which took the place of ZLink and produced Amsdos binary files. This is still available on WACCI PD disc 2 (I believe) or on disc 131, the Music and MIDI disc. I used this combination of ZMac and ZBin until very recently. It is pretty quick, and the only disadvantage is that ZBin will not link more than one object file together. You also have to use CP/M to assemble the code, which might put some people off.
A couple of years ago I got a second hand copy of Maxam 1.5. This is a ROM version for use with Protext. I had been using Protext for writing all my code for several years, so Maxam is the logical assembler to use. It is now available from WACCI. The last details printed on how to get hold of the ex-Arnor products were printed on page 23 of WACCI 132 (July 2000), but I think it is planned to make some of them available on the new web site. Perhaps it's time for an update article from somebody.
I have not done much CPC coding since I got Maxam, so I haven't really got into it yet, but it is certainly the best assembler available for the CPC. It does not have a linker, so when you assemble the code, you have to assemble all of it, every time. You can at least divide up the source code into several files, which makes things more manageable, and these subsidiary files can be inserted into the main code using an assembler directive. (Or, if you like, you can simulate a linker in your own code by writing two or three separate programs, which communicate with each other via a jump-block. This is how I wrote RoutePlanner PCW - using Protext and Maxam 1.5 on the CPC! - Richard)
Maxam has various features which put it in a totally different league to the assemblers I used to use. The most important of these is conditional assembly. This allows you to make several different versions of software all from the same source code. To take an example from last month, where I had three different routines to reset the different MIDI interfaces, you could instead have a code fragment like that in Listing 1.
At the start of the code you would set the labels RAM and EMR according to whether you were wanting to produce code for the RAM Music Machine, the EMR interface, or the DHCP one. The following would set things up for the EMR interface:
RAM EQU 0 EMR EQU 1
When the assembler comes across the 'if' statement, it evaluates the expression and then includes the block of code after the 'if' only if the expression is not zero. If you work through Listing 1, you will find that by setting RAM and EMR appropriately, you can get the three routines featured in the assembly listing last time under the labels .ramreset, .emrreset and .dhcpreset.
It is important to remember, though, that these choices have to be made when you are assembling the code. After that the user is stuck with them, making it a technique which is best reserved for fairly major alternatives to support different kinds of hardware.
By careful use of conditional assembly, a software house could even maintain CPC and PCW versions of the same package using one set of source files. To give another example, you could produce a specially restricted version of some software for free distribution, allowing you to assemble the full commercial version from the same code.
In general, it is a good idea to re-use code. If you have a piece of code that works, guard it carefully, and use it whenever it is appropriate. Writing a new piece of code each time to do the same job only increases the chances of bugs getting in again. Modularising code by dividing it up into manageable files and using conditional assembly techniques help you to re-use code.
The main reason I have not used Maxam much since getting it is that I now have something better! Now those of you who have been reading closely may have noticed that I said that Maxam was the best assembler... for the CPC.
The assembler I now use does not run on a CPC, but nevertheless produces Z80 machine code, and even Amsdos binary files. It is what is called a cross-assembler: an assembler running on one computer system which produces code for use on another computer system.
This particular cross-assembler is called Zmac, but has nothing to do with the CP/M program of the same name. This Zmac is written in C, and so can be compiled to run on a large number of different machines. It has been used on DOS, Windows, Unix, and RISC OS, and probably a few other types of system.
It was originally written in 1978 by Bruce Norskog (whoever he was!) and has been modified and improved by several people over the years (including a small contribution from me). It is now maintained by Mark Rison, who uses it to develop CPC/IP, the CPC internet system that I have mentioned before.
Zmac is free, and available from www.nenie.org/cpcip/ , the home page for CPC/IP. You can also download the CPC/IP source from there which is a good example of how to use conditional assembly and other advanced features.
Note that the version on this webpage is source only. You will have to compile it with a C compiler in order to use it on your chosen system. That should not be much trouble, though, if you have a C compiler. A pre-compiled version for RISC OS is available from my web site at www.sinenomine.freeserve.co.uk/software/ which includes a nice graphical front end. (And if you want one for the Mac, I've put one up at www.systemeD.net . It's not very pretty. But it works - Richard)
The good thing is that this Zmac is extremely compatible with Maxam, and most Maxam source code will compile straight off in Zmac. The main problem will be if you have used colons to put more than one assembly command on a line, as Zmac does not allow that. (But with a little clumsy hacking, it can be persuaded to - Richard)
See the list in the box for the main differences between Maxam and Zmac. As you can see, Zmac has quite a few advantages over Maxam.
Perhaps the biggest feature is that Zmac has macros. Macros are a powerful feature which are only present in the CP/M version of Maxam, Maxam II. At the simplest level, a macro allows you to define a shorthand form for commonly used pieces of code. You might define a macro called 'exbcde':
exbcde macro PUSH BC PUSH DE POP BC POP DE endm
and then you could just type 'exbcde' to exchange the contents of the BC and DE registers.
But macros are far more powerful than this, as you can use parameters and all the features of conditional assembly to produce some really clever stuff. I've given a quick example of a macro called 'copymem'. This is for copying memory from one location to another.
Usually, you would just use LDIR to do this - but if the block of memory you are copying from overlaps with the memory you are copying to, things can go wrong, as you may have already overwritten some of what you are copying before you get to the end of the block. In these cases, LDDR is required, with the copying starting from the end of each block. The copymem macro in Listing 2 will work out which is needed, and insert the appropriate code. The last few lines show how the macro is called from the main body of the source code. Listing 3 shows the code that the assembler produces as a result.
The other great advantage of Zmac over Maxam is that it is much faster, because you can use it on more powerful modern computers. It now makes a lot of sense to develop CPC software using tools like Zmac, keeping the source code on the hard disc of a PC or Acorn rather than on low capacity floppy discs on a CPC. You can assemble the code faster, and test it easily using an emulator.
Next time we will turn our attention to looking at disassemblers, unless anyone e-mails me on [email protected] to suggest a different topic!
Listing 1 Using conditional assembly to cater for hardware differences. .resetmidi if RAM LD BC,&F8EC else if EMR LD BC,&F8F2 else LD BC,&F8E0 endif endif LD A,3 OUT (C),A if RAM LD A,&15 else LD A,&16 endif OUT (C),A RET Listing 2 A macro for safe memory copying. ;This macro corrupts no registers copymem macro from,to,length PUSH AF PUSH BC PUSH DE PUSH HL LD BC,length if from<&5200 7007 11FF55 LD DE,&5200+&400-1 700A 21FF53 LD HL,&5000+&400-1 700D EDB8 LDDR else endif 700F E1 POP HL 7010 D1 POP DE 7011 C1 POP BC 7012 F1 POP AF 7013 endm ;copy memory from &5200 to &5000 7013 copymem &5200, &5000, &400 7013 F5 PUSH AF 7014 C5 PUSH BC 7015 D5 PUSH DE 7016 E5 PUSH HL 7017 010004 LD BC,&400 0000 if &5200<&5000 else 701A 110050 LD DE,&5000 701D 210052 LD HL,&5200 7020 EDB0 LDIR endif 7022 E1 POP HL 7023 D1 POP DE 7024 C1 POP BC 7025 F1 POP AF 7026 endm
01 - Thanx & Stuff | 02 - Fair Comment | 03 - New Generation | 04 - Exploring the PSG |
05 - Programmers' Patch | 06 - CPC Changed My Life | 07 - Cartography |
WACCI 137 Index - Home Page www.wacci.org.uk