Last time we covered a lot of ground by skimming quickly over it. If you did not understand all the rotate and shift insructions, don’t worry. You can get along fine without them for now. You should however make sure you hover over the logical instructions, And, Or and Xor, long enough, as they are very useful.
You will also need to review my article on number systems, as a thorough explanation of Binary is given there. For this reason, I did not give much explanation of Binary in the last lesson.
Now, lets discuss some instructions that are off in the corner by themselves. The first is Nop, which is read No OPeration. You guessed it, it doesn’t do anything. Almost. The purpose of Nop is to waste time (4 T states) and provide a space filler. No flags are affected.
Nop is also used by us programmers to fix our errors. You can replace unwanted instructions with a Nop, by direct pokeing, rather than re-assemble a large section of code.
Cpl means ComPLement the accumulator. We have briefly mentioned complementing a few times. The result is to invert all bits. For example, assume the accumulator contains 10111011b. After complementing, the accumulator will contain 01000100b.
Neg will NEGate (2’s complement) the accumulator. Negating the same value of 10111011b in the accumulator will yield 01000101b. Creating the two’s complement of a number is done by complementing the number and adding one. Neg performs this operation on the contents of the accumulator. Any number plus its two’s complement will equal zero.
The last instruction is Daa which means Decimal Adjust Accumulator. This instruction works in conjuction with the Rld and Rrd instructions from last lesson. As I stated then, I have not found a good use for these instructions. I will however give a brief description of their purpose, as you may encounter them.
Daa adjusts the accumulator for Binary Coded Decimal (BCD) addition and subtraction operations. In order to understand Daa and its rotates, we need to understand BCD.
BCD is a method of representing a decimal digit (0-9) in four bits, much the same as any single hex digit (0-F) can be. This means that 15BCD is 00010101b in binary digits and not the usual 00001111b that we would normally find in binary representations. Look again, this is because there can be no digit greater than 9 in any four bits, in BCD.
The problem is that our old friend, CPU, does not know whether we want to store decimal or hex digits in its words. Therefore, Daa will check the half-carry flag to determine when to adjust the binary result, back to a decimal digit. The only advantage to BCD, that I have found, is that it makes the retrieval of decimal digits easier.
As I have said, I do not subscribe to the philosophy that BCD is a necessary or useful tool. Therefore, I will dwell on it no longer. You can find texts on the subject, if you are interested.
That’s all the instructions for this lesson (Tim says I have been getting long-winded). I did however leave some of you hanging last lesson with the question, “What is source code?” This question was raised by some readers requesting information and instruction on the use of assemblers.
I must make very general comments as each assembler has its own set of commands. Unfortunately, the best way to learn the commands is to use the assembler. The basic operation of assemblers is simple. They allow us humans to type in our MC as mnemonics instead of hex digits. The assembler then uses our mnemonics to assemble the binary instructions that are understood by the CPU.
There are basically two types of assemblers. The first is an interactive or virtual assembler, a good example is Hot-Z by Ray Kingsley. This type of assembler is a little more difficult to use but much quicker. It generates the MC in place as you type in the mnemonics. The disadvantage is that it is not as easy to move and re-address large sections of code.
The second type will generate an ASCII source code file in addition to the assembled MC. Source code is much like a letter you might type on your word processor. It is an ASCII encoded file containing all the labels and mnemonics you type into it, as well as pseudo-ops. The disadvantage is a loss of speed and disc space, as there are two files to handle. Much of this is offset by the gain in flexibility to change the code as well as the ability to comment the source code file. The addition of comments are a huge benefit in helping yourself remember what it was you had intended the code to do. The best example is Zeus by Crystal Computing.
I use Hot-Z and Zeus regularly and feel they are the best available for the 2068. Hot-Z is the only assembler available for the TS1000. I have several for the TS1000 that put the mnemonics in REM statements, but none of they work very well.
A moment ago I mentioned pseudo-ops. These will vary as to availability with your assembler and will be detailed in the instruction manual. Pseudo-ops are assembler directives, not mnemonics. They tell the assembler important things at the time of assembly. They do not generate any MC instructions and are not executable by the Z80.
Typical pseudo-ops are:
Org.......assemble the following MC from this address
to End or the next Org
Equ.......set label equal to specified value
End.......end of source file
Defb......defines the contents of the current byte
Defw......defines the contents of the current word
Defs......defines an amount of bytes to be reserved
at
the current address
Defm......defines the contents of the current bytes
as
the stated ASCII string
There are many more pseudo-ops, but these are the most common. You will also encounter labels and comments in source listings. Labels are much like Basic variables. They assign a name to an address. Some assemblers require labels to be followed by a colon.
Comments are just that and are preceded by a semi-colon. They may appear at the end of a line, to explain that instruction, or on a line by themselves.
Now, our utility for this lesson. Those of you using the TS1000 will particularly appreciate this one. It will generate a line 0 Rem statement of the size specified. You need only type two commands to run the code:
Rand length
Let x=Usr address
The first will load the length of the desired Rem statement into the system variable, Seed. No formatting or conversions required by you. The second statement will run the routine from the loaded address.
Watch the source carefully, as it will run on both the the TS1000 and TS2068, but there are some lines that are unique to each computer. Also, it must be loaded and run from above ramtop or you will confuse the poor CPU.
;Generate Rem Statement
;
GenRem Ld HL,(Seed) ;get length desired
Inc HL ;adjust for Rem
Inc HL ;adjust for EOL
Push HL ;save line length
Ld BC,4 ;add overhead bytes
Add HL,BC
Push HL ;get length into BC as required
Pop BC ;by Rom routine
Ld HL,407Dh ;TS1000 only--address to put Rem
Ld HL,(Prog) ;TS2068 only--statement at
Call 099Eh ;TS1000 only--Rom routine to make
Call 12BBh ;TS2068 only--BC spaces at HL. The
;routine returns with DE=last byte
;of the new space & HL=first byte-1
;of the new space.
Ld A,76h ;TS1000 only--EOL marker
Ld A,0Dh ;TS2068 only
Ld (DE),A ;load end of line marker into the
;last byte of the new line
Xor A ;A=0
Inc HL ;correct the pointer
Ld (HL),A ;load high byte of line number
Inc HL ;adjust pointer
Ld (HL),A ;load low byte of line number
Pop BC ;retrieve line length
Inc HL ;adjust pointer
Ld (HL),C ;load low byte of line length
Inc HL ;adjust pointer
Ld (HL),B ;load high byte of line length
Inc HL ;adjust pointer
Ld (HL),EAh ;load Rem character
;the line is now complete, but it
;contains 'garbage' that should be
;cleared out
Ld BC,(Seed) ;get length of space made
Loop Xor A ;A=0, you could use Ld A,x, where
;x=any fill character
Inc HL ;adjust pointer
Ld (HL),A ;clear the byte
Dec BC ;adjust counter
Ld A,B ;and test if BC=0
Or C
Jr NZ,Loop ;loop to clear next byte if BC<>0
Done Ret ;return to Basic
Early in this series, I promised to show you an easy way to save and load your MC above ramtop on the TS1000. Since we now have a routine that must run there, this seems like a good time to keep my promise.
Make the following changes to the hex loader from lesson 1:
60 Let A$="210C40C9S"
70 Rem insert your own MC string of hex digits
between the quotes in line 60 and end the
string with an 's'
The secret to remember is that A$ contains all the MC as a string of hex digits. You must also remember to reset ramtop and type a New command, before re-loading your saved MC Basic. Next lesson we will learn the block instructions. You will be amazed at the difference in speed!
And now, a special little utility for the TS1000. The TS2068 has several nice graphics commands. This routine will emulate the Flash command on the TS1000 by flashing the entire screen. I will leave the modification of it to you, for flashing one or more characters.
;Flash Screen
;
Flash Ld HL,(D-File) ;get start of D-File
Ld C,18h ;line count
OutrLp Inc HL ;step over EOL marker
Ld B,20h ;character count
InnrLp Ld A,(HL) ;get character
Add A,80h ;invert it
Ld (HL),A ;replace character
Inc HL ;advance character pointer
Djnz, InnrLp ;check if line complete and loop
;if not
Dec C ;count line done
Jr NZ, OutrLp ;check if screen complete and
;loop if not
Done Ret ;return to Basic
This routine can be called from your Basic programs with a Rand Usr address command. The following will demonstrate:
10 Rand Usr Flash
20 Pause 50
30 Goto 10
I hope you find these routines useful. We have two more lessons to go and we will be done with the Z80 instruction set. You should now be able to write your own MC routines. I believe the only way you can learn MC is to use it, so get stumbling!
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.