Changes

Jump to: navigation, search

Where to learn?

119 bytes added, 00:38, 15 December 2006
I think you could divide the problem of low level coding into three distinct parts.
a. # Z80 assembly language <br>b. # Assembler syntax <br>c. # CPC specifics (memory map, firmware (i.e. OS) and hardware)
By saying "assembly", "assembler" or "asm" (for short) a1. and b2. get intermixed and sometimes confuse people. By saying "assembly" the connotations point more to the z80 assembly language (it's commands, a.k.a. "mnemonics". This is source code.); this is a mirror of the z80 architecture as every mnemonic has a direct machine code equivalent (i.e. object code). "Assembler" is a term more properly used for a full-blown program that gets the work done of converting source code into machine code and adds its own made-up commands (which are words that look like z80 mnemonics, but are actually only offered for convenience by the assembler) or directives (words that set up and take care of various things) in the syntax for ease of programming. "asm" may mean both.
Also how a CPC does something, like printing a character on the screen depends on its firmware and hardware and how its memory is organized and used by the firmware, hardware and user-programs. The MSX has totally different hardware so here's where your code starts to differentiate. Since most of the asm code is general purpose, this is why Spectrum ports were so easy to make; just use different screen, sound and keyboard drivers and voila... Of course code that is specifically written for the CPC will take more advantage of its hardware (it will be less portable/general-purpose but the programme/game has the potential to run faster and have more features).
What instruction to use depends on two things:
a. # What you need to do. e.g. You need to add two 8-bit numbers, you use 8-bit addition. You need to add 1 to an 8-bit number, then you increment it by 1. You can do these two things (addition and increment) for 16-bit numbers too.b. # What the Z80 is able to do. It just can't do some things, for example it can't multiply two numbers. You'll need to use a multiplication routine for that. You can add a 16-bit value to the HL register pair, but you can't add a 16-bit value to any other register pair (like BC or DE). In order to get around this you'll have to move data around like exchanging the values of registers or saving data into other registers or on the stack or in a memory location. All CISC processors are full of such quirks (they are not "orthogonal", which means you can't combine every command with every possible parameter type(s). Some commands only take specific parameters and you have to live with that).
Assembler is in a class of languages considered error-prone, so you need to take care that your program is stable. Also, by learning z80 assembler you make a step forward for learning x86 assembler since this is a related family of processors.
So there's the Z80 general stuff that you can learn in any Z80 tutorial. A good tutorial I know of is the [http://www.ticalc.org/pub/text/z80/z80asmg.zip Independent Z80 Assembly Guide]. Available online at [http://cobb.host.sk/z80guide/index.htm http://cobb.host.sk/z80guide/index.htm]. It "was written in a way that it can be used for ANY Z80 calculator or computer". You can use all of this code with a CPC or CPC emulator and it will work. No graphics, sound, file or input routines are included of course; all this is CPC specific, but once you've learnt some of the general z80 stuff, then you'll be able to access the CPC's specific features. I'd recommend using WinAPE's built-in assembler, assemble everything in CPC's memory and then check the results with WinAPE's debugger (or in BASIC with peeks and pokes and/or short BASIC programs). Just put a
<code>.org #4000</code>
in front of each example, and a
<code>ret</code>
if necessary at the end, assemble and then use
<code>call #4000</code>
from BASIC to run the machine code.
Only 64K is directly accessible by the Z80. On the CPC architecture the last 16K is by default used as the screen data (addresses &C000 to &FFFF). Addresses 0 to &170 and HIMEM+1 to &BFFF is used by the Firmware, BASIC and AMSDOS ROM's. Himem is a Locomotive BASIC variable that reports the highest available free memory location when the CPC boots up. By lowering this value, you assign less space for the BASIC part of your program and it's BASIC data (strings, variables, arrays). The rest (from the new HIMEM's value up to the initial HIMEM value when the computer boots up) can be used by your machine code and its data. You alter the HIMEM value by e.g.
<code>MEMORY &2000</code>
from BASIC. Obviously it shouldn't be lower than &170 or higher than HIMEM's initial value. (Sometimes I personally don't use this at all. If I compile something at &4000 and my BASIC program is small, then I just don't bother with MEMORY and HIMEM because usually nothing gets overwritten.)
You can use this for all asm source you have available, like for the tutorial source code.
When calling some asm code from BASIC, you would use something like:<br><code>10 CLS<br>20 MEMORY &3FFF<br>30 CALL &4000<br>40 END</code>
The Call command calls a machine code routine. If there's nothing at address &4000 then the computer will probably crash.
When you assemble a z80 program it's important to instruct the assembler as to where it should put the resultant machine code. You do this by using the ORG assembler directive, like:
<code>org #4000</code>
for the BASIC code above. If you have several machine code routines that you would like to call from BASIC then where to call depends on where the routine you want to call starts in memory. However calculating or copying and typing in specific addresses is cumbersome because each time you reassemble your program these memory locations may also change.
Assemble and type
<code>Call &4000</code>
from BASIC. Then you can call each of these routines from BASIC by name, like:
<code>|PRINT</code>
4
edits