29.12.2012 Views

spectrum utility - OpenLibra

spectrum utility - OpenLibra

spectrum utility - OpenLibra

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

tions. Last time, I described the<br />

simple cases of adding or subtracting<br />

one (INC and DEC) from<br />

a register, or register pair. There<br />

are a number of machine code<br />

instructions which allow more<br />

complex addition and subtrac<br />

tion. For these, the choice of<br />

register is more limited than with<br />

INC and DEC. A single register<br />

addition or subtraction must<br />

always involve the 'A' register.<br />

Addition takes the form of adding<br />

the contents of the A<br />

register to another register or<br />

byte in memory (addressed by<br />

the HL pair), or a number<br />

(operand) in the program, and<br />

placing the result in the A<br />

register. Similarly, subtraction<br />

involves taking the value of a<br />

register, memory byte, or<br />

operand from the value in 'A'<br />

and placing the result back in the<br />

A register.<br />

Two byte arithmetic is more<br />

restricted. Addition involves<br />

taking the contents of the HL<br />

register pair, adding the contents<br />

of another register, and<br />

placing the result in HL. Subtraction<br />

involves subtracting a<br />

register pair value from the value<br />

in HL, and placing the result in<br />

HL. In single byte arithmetic,<br />

numbers are restricted to the<br />

range 0 to 255, whilst the range<br />

for two byte arithmetic is 0 to<br />

65535.<br />

A further complication is the<br />

carry flag. It is possible to add<br />

two numbers, then add the<br />

value of carry (0 or 11 to the<br />

result just before storing the<br />

final value. And it is possible to<br />

subtract the complement (1<br />

minus the value) of the carry flag<br />

from the result of subtracting<br />

two values, before storing the<br />

result. This gives two forms of<br />

add (ADD and ADC) and two<br />

forms of subtract (SUB and<br />

SBC); without and with the<br />

Table 1 Testing Flags<br />

a) Symbols and flag values<br />

Flag Flag = 1 Flag = 0<br />

C C (Carry) NC (No carry)<br />

Z Z (Zero) NZ (No zero<br />

P/V PO (parity odd) PE (parity even)<br />

S P (positive) M (negative)<br />

b) Valid operations, and their opcodes<br />

Unconditional Operation<br />

Flag: C<br />

JP (C3) JPC (DA)<br />

JP NC ID2)<br />

JR (18)<br />

CALL (CD)<br />

JRC (38)<br />

JR NC (30)<br />

CALL C (DCl<br />

CALL NC (D4)<br />

RET (C9) RET C (D8)<br />

RET NC (DO)<br />

carry flag. Confused? I'll try and<br />

explain.<br />

For simple arithmetic, it's<br />

easier to use the forms of add or<br />

subtract which do not use the<br />

carry flag value (ADD and SUB).<br />

So, if you are adding two<br />

registers or two register pairs, or<br />

subtracting two registers, use<br />

ADD or SUB. That way there is<br />

little chance of a mistake being<br />

made by an incorrect setting of<br />

the carry flag. The carry flag will,<br />

of course, be set (or reset) by the<br />

result of the addition/subtrac<br />

tion. For more complicated<br />

arithmetic, involving numbers<br />

held in several bytes, you'll want<br />

to use ADC or SBC. The purpose<br />

of involving the carry flag is that<br />

you can register whether or<br />

not there has been an addition or<br />

subtraction which has resulted<br />

in a value greater or smaller than<br />

that allowed by the restrictions<br />

on the register size. In this way<br />

you can carry a value to the next<br />

addition/subtraction, as you<br />

would carry one into the 'tens'<br />

column, having added 6 and 5 in<br />

the 'units'. Before using ADC or<br />

SBC it is usual to reset (for ADCl<br />

or set (for SBC) the carry flag<br />

before carrying out the calculation.<br />

The assembly language in<br />

struction to set the carry flag is<br />

SCF. There is no direct instruction<br />

to reset the carry flag, but<br />

this can be carried out by first<br />

setting the carry flag with SCF<br />

followed by the instruction CCF<br />

(complement carry flag), which<br />

inverts the value of the carry flag<br />

(0 to 1, or 1 to 0). The two in<br />

structions are one byte each<br />

(opcodes are 37 (SCF) and 3F<br />

(CCF), hex). The carry flag can<br />

be reset in one byte; I'll show<br />

you how next time.<br />

You'll see all the opcodes for<br />

the add and subtract in Table 2.<br />

Note that for two byte subtraction,<br />

only SBC is available, so be<br />

ZX PROGRAMMING<br />

Conditional Operations<br />

P/V<br />

JP PO (E2|<br />

JP PE (EA)<br />

CALL PO (E4)<br />

CALL PE (EC)<br />

RET PO (EO)<br />

RET PE (E8)<br />

sure to set the carry flag when<br />

using it for simple arithmetic. Fig<br />

2 in the examples section, later<br />

on, provides a BASIC program<br />

which should help to clarify any<br />

doubts about the different add<br />

and subtract instructions.<br />

Block loading<br />

The final piece of theory for this<br />

issue is the Z80's powerful<br />

block load instruction. It allows<br />

the values in a block of bytes (of<br />

any size) in memory to be moved<br />

to another location. It works like<br />

this:<br />

The starting address of the<br />

source block is loaded into the<br />

HL register pair, the starting address<br />

of the destination block is<br />

moved into DE, and the number<br />

of bytes to be moved goes into<br />

BC. Then one instruction LDIR<br />

performs the move. LDIR stands<br />

for LoaD Increment Repeat. The<br />

value in BC acts as a counter.<br />

The value in the byte addressed<br />

by HL is transferred to the byte<br />

addressed by DE: HL and DE are<br />

incremented, while BC is<br />

decremented, then the instruction<br />

repeats itself automatically<br />

until BC gets down to zero.<br />

There is a non-repeat alter<br />

native, LDI, where the byte<br />

value transfer takes place, and<br />

registers HL and DE are incremented,<br />

BC decremented,<br />

but the instruction is not<br />

repeated automatically. Begin<br />

ners to machine code would normally<br />

use LDIR, and this is<br />

shown in the examples.<br />

The Z80 offers an almost<br />

identical instruction called<br />

LDDR. To use this, the END addresses<br />

of the source and<br />

destination blocks are loaded into<br />

HL and DE, respectively,<br />

while BC still holds the number<br />

of bytes to be transferred. Each<br />

cycle of the instruction involves<br />

Z<br />

JPZ (CA)<br />

JP NZ (C2><br />

JRZ (28)<br />

HR N (20)<br />

CALL Z (CC)<br />

CALL NZ (C4)<br />

RET Z(C8)<br />

RET NZ (CO)<br />

transfer from (HL) to (DE), and<br />

all three register pairs<br />

decremented. LDD is the nonautomatic<br />

repeat version of<br />

LDDR. It doesn't really matter<br />

whether you use LDIR or LDDR<br />

unless there is some overlap between<br />

the source and destination<br />

blocks of memory. Then, the<br />

choice is critical if bytes are not<br />

going to be corrupted. I'll leave<br />

you to sort out which should be<br />

used, depending on whether the<br />

overlap is at the beginning or end<br />

of the source block! The block<br />

move opcodes are shown in<br />

Table 2.<br />

Examples<br />

The first two examples given<br />

this time are written in such a<br />

way that they will work on both<br />

theZX81 and Spectrum. Example<br />

1 is the flag demonstration<br />

program, and all details appear<br />

in f ig. 1 . Example 2<br />

demonstrates add and subtract,<br />

and should help explain any<br />

questions you might have on all<br />

the arithmetic instructions mentioned<br />

earlier. Fig. 2 contains the<br />

details of this.<br />

The final example carries out<br />

similar block move operations<br />

on both ZX81 and Spectrum;<br />

copying the display file to a safe<br />

area of RAM, then returning it<br />

'instantly'. Machine differences<br />

prevent the same code working<br />

on both machines, so ZX81<br />

users should refer to fig. 3, while<br />

Spectrum owners go to fig. 4.<br />

Next time we'll be looking at<br />

a stack which has little to do<br />

with chimneys, and some bit<br />

operations!<br />

Spectrum users should type in<br />

the following listing as shown<br />

(Figure IK A minor change<br />

should be made by ZX81 users.<br />

S<br />

JP P(F2)<br />

JP M (FA)<br />

CALL P IF4)<br />

CALL M (FC)<br />

RET P (FOl<br />

RET M (F8)<br />

ZX COMPUTING APRIL/MAY 19 85 8 9

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!