Download PDP8 doc#1

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
1
Appendices
2
Appendix A
Instruction repertoire,
assembly language and
coding examples for Simul8
Instruction repertoire
Predefined op-codes for the simulator
Symbol
Class
adcrb
adstrt
cia
clkcf
clkt
cma
iot
iot
opr
iot
iot
opr
7020
memref
6410
iot
6411
dca
dlsk
Value
dscf
Symbol
Class
6601
6604
7041
6501
6504
7040
adsf
and
cla
clksf
cll
cml
iot
memref
opr
iot
opr
3000
dlma
iot
6400
drd
iot
iot
6402
Value
6602
0000
7200
6502
7100
opr
dssf
iot
6401
dtcf
iot
6414
dtsf
iot
iot
6415
hlt
opr
6412
dwrt
i
7402
'indirect'
7001
iof
0400
iac
opr
iot
6002
ion
iot
iot
6000
isz
memref
memref
5000
jms
memref
iot
6036
ksf
iot
6001
iot
2000
jmp
4000
krb
6031
3
nop
opr
7000
opr
opr
opr
7004
rar
opr
opr
7006
rtr
opr
opr
7410
sma
opr
7450
snl
7000
ral
7010
rtl
7012
skp
opr
7500
sna
opr
7420
spa
opr
7510
sza
opr
7440
szl
opr
7430
tad
iot
6042
tls
iot
6044
tsf
memref
1000
tcf
iot
6046
tpc
iot
6041
The classes are: 'memref' = memory reference instruction, 'iot' = input/output instruction,
and 'opr' = operate instruction.
4
Memory reference instructions
and
'and'
Logical 'and' of the contents of accumulator with contents of the referenced memory
location.
acc:= acc & memory[effective address];
dca
'deposit and clear acc'
Store the contents of the accumulator in the referenced memory location, then clear (i.e.
zero) the accumulator.
memory[effective address] := acc;
acc:=0;
isz
'increment and skip if zero'
Increment (add 1 to) the contents of the referenced memory location, storing the new
value back into the location. If the new value is zero, then increment the program counter
skipping the next instruction.
memory[effective address] := memory[effective address] +1;
if(memory[effective address] = 0) then pc:=pc+1;
(Note: this does not involve the accumulator whose contents are not changed by this
instruction.)
jmp
'jump'
Change program counter so that next instruction is taken from the referenced memory
location.
pc:= effective address;
jms
'jump to subroutine'
First, store the current value of the program counter in the referenced memory location
(establishing the link needed when returning from the subroutine). Then change the
program counter so that the next instruction is taken from the following memory location.
memory[effective address] := pc;
pc := effective address + 1;
tad
'two's complement add'
5
Form the sum of the contents of the accumulator and the contents of the referenced
memory location. If there is a carry out of the leftmost bit, then the value of the 'link' bit is
complemented. There is no hardware detection of arithmetic overflow.
acc := acc + memory[effective address];
if(addition gave carry )then link : = not link;
Operate instructions
cml
hlt
iac
nop
'complement and increment acc'
(i.e. change sign of contents of acc as interpreted in twos complement notation)
'clear acc'
'clear link'
'complement acc'
(i.e. change each 0 bit in acc to a 1, each 1 to a 0)
'complement link'
'halt' (terminate execution)
'increment acc'
'do nothing'
ral
rar
rtl
rtr
'rotate acc left'
'rotate acc right'
'rotate acc twice left'
'rotate acc twice right'
skp
sma
sna
snl
spa
sza
szl
'skip the next instruction'
'skip if acc holds minus (negative) number'
'skip if contents of acc non zero'
'skip if non-zero link'
'skip if acc holds positive number (including zero)'
'skip if contents of acc is zero'
'skip if zero link'
cia
cla
cll
cma
It is possible to combine 'operate' instructions in various restricted ways. Combining
operate instructions shortens programs and makes them faster. The restrictions on
combinations are somewhat complex, and not really important. Typical permitted
combinations are:
cla cll
sna cla
'clear both acc and link'
'skip if non-zero acc, clear acc'
All the skip instructions can be combined with 'cla'; this allows computations needed for a
comparison to be done in the acc, the result tested with skip and the unneeded temporary
result removed from the acc.
6
Input/output instructions
Analog/digital converter
adcrb
adsf
adstrt
' A/D read data buffer and clear flag'
'skip if A/D flag set'
'start A/D sampling'
The A/D represents a 9-bit accuracy, single line A/D converter that samples the voltage
on an input line and returns a numerical representation of the voltage (accurate to one part
in five hundred). This is not a simulation of a real A/D device; control of this A/D is
greatly simplified.
Example
Store five samples from the A/D in successive memory locations starting at address
'datum'.
*200
cla cll
tad
whered
dca
ptr
tad
howmny
cia
dca
countr
main,
adstrt
wait,
adsf
jmp
wait
adcrb
dca i
store in memory
isz
ptr
isz
countr
/ set up a 'pointer' to where data are to be
/ stored
/ the number of samples to be read
/ make it negative
/ save in a counter variable
/ start sampling the next value
/ wait loop, flag will set when voltage reading ready
/ read data into the acc
ptr
/ update memory ptr (can assume won't cause skip)
/ increment counter, this will cause skip when have
/
necessary samples
jmp
main
/ (if not complete, go back for next value)
hlt
/ all done
/ here there are a couple of 'assemble time' constants
whered, datum
/ the address where the first data will be stored
howmny,
5
/ it is five samples needed
/ here there are the variables used for counters and pointers
ptr,
0
countr, 0
datum, 0
/ first of locations for data
$
Clock
clkcf
'clear clock flag'
/
7
clksf
clkt
'skip if clock flag set'
'clock toggle'
The clock is a slightly simplified version of a 'fixed-frequency' clock. Once started, it will
set its flag every 'x' microseconds. Starting/stopping of the flag is non-standard. These
operations are implemented through the single I/O instruction 'clkt'; if the clock is not
running, 'clkt' starts it; if it is running, 'clkt' stops it (i.e. it's a toggle switch).
Example
A loop to cause a fixed delay of 100 clock 'ticks'.
loop1,
limit,
count1,
.
tad
cia
dca
clkt
clksf
jmp
clkcf
isz
jmp
clkt
.
.
.
0144
0
limit
/ limit on number of clock ticks to wait
count1
loop1
count1
loop1
/ start clock
/ these two instructions cause wait for
/ next 'tick'
/ clear flag, start clock counting down again
/ increment count of ticks, skip when have sufficient
/ switch off clock
/ one hundred decimal
Disk
The disk is the most complex of the devices on this simulator, and yet is really extremely
simplified in comparison to most disk units. There are two sets of instructions for the
disk. The first set is used to cause the disk unit to move its read/write heads to the
appropriate block.
dlsk
dssf
dscf
'load disk block register and start seek'
'skip if disk seek flag set'
'clear disk seek flag'
The second group sets the start address in memory for the transfer, and initiates the read
or write operations.
dlma
drd
dtsf
dtcf
'load disk memory address register (from acc)'
'start reading from disk into memory'
'skip if disk data-transfer-complete-flag is set'
'clear disk data-transfer-complete-flag'
8
dwrt
'start writing to disk from memory'
Example
A test program for the disk that will read block 1 into memory is as follows:
*200
cla cll
tad
sought
/ pick up desired block number
dlsk
/ get disk to start seek
dwt,
dssf
/ wait for seek flag to set when block found
jmp
dwt
dscf
/ clear flag
cla
tad
adrbuf
/ pointer for data
dlma
/ load disk memory address register
drd
/ start read
/ if anything is to be done, then could do some work while transfer proceeds via dma
/ but as there is nothing to do, just wait for completion of the transfer
twt,
dtsf
jmp
twt
dtcf
hlt
sought, 1
adrbuf, buf
*400
buf,
0
$
Interrupts
iof
ion
'interrupts off (disabled)'
'interrupts on (enabled)'
These instructions are used to control the 'interrupt' system. By default, interrupts are
disabled; all I/O necessarily involve wait loops. Interrupts must be enabled at the start of a
program using interrupt driven I/O. Interrupts are automatically temporarily disabled
whenever an interrupt does occur, and must be re-enabled as part of the code that effects
the return from interrupt. The interrupts off instruction can be used to temporarily disable
interrupts during a 'critical section' of code, such as code testing a shared variable.
Keyboard
krb
ksf
'read data from keyboard buffer to acc, clear keyboard flag'
'skip if keyboard flag set'
9
These instructions handle input from a keyboard. Note that there is no instruction to start
the data transfer (on keyboard input that is done by the user, not the computer). Here, two
instructions suffice: a skip that tests if data are ready in the keyboard control unit's buffer
and an instruction that reads those data into the acc and clears the keyboard flag.
Example
Read characters from keyboard, echo to 'teletype', stop when the character zero (0) has
been echoed. (The ASCII character zero has the octal value 060.)
copy,
wait,
zero,
$
*200
cla cll
ksf
jmp
copy
krb
tls
tsf
jmp
wait
cia
tad
zero
sza cla
jmp
copy
hlt
060
/ here we wait for a character to be keyed in
/ got one, read it in to acc
/ forward copy to 'tty (teletype)'
/ wait for tty to print character
/ negate value
/ add constant
/ if result zero then task complete
/ else go back for next character
/ ascii code for character zero
'Teletype' (printing terminal)
tcf
tls
tpc
tsf
'teletype clear flag'
'teletype load and send (clears flag)"
'teletype print character'
'skip if teletype flag set'
Example
Print out a standard message. The message is assumed to be held as a sequence of ASCII
characters (i.e. octal constants) stored one per word in successive words of memory. The
message is terminated by a word containing the value zero. The example is coded as a
subroutine; it is assumed that when called the acc will hold the address where the message
is stored.
msg,
0
location where the return address is saved
dca
mptr
/ save start address of message
mloop, tad i mptr
/ get next character of message
sna
jmp i msg
/ if it was zero, then at end of message
/
10
tls
valid character, then send it
mwait,
tsf
wait for it to be printed
jmp
mwait
cla
isz
mptr
jmp
mloop
mptr,
0
/ if
/
/ update address ptr, assume no 'skip'
/ go get next character
The assembly language of the simulator
Character set
Letters (lower case)
Digits
Comma
Slash (comment symbol)
Star
Dollars
'White space'
Carriage return
: abcdefghijklmnopqrstuvwxyz
: 0123456789
:,
:/
:*
:$
: tab, space
: return
These are the characters used by the assembler program. Other characters (e.g. ", +, =, - ,
!, and &) are permitted in comments. Upper case letters are converted to lower case.
Octal digits and constants
The octal digits are represented by the characters '0'...'7'. An octal constant consists of a
sequence of from one to four octal digits. A constant should be followed by a white space
character or carriage return.
octal digit
=
octal constant
=
0|1|2|3|4|5|6|7
4
{octal digit }
1
The assembler generates an error message 'too large an octal constant' if given an octal
constant of more than four octal digits. The error messages 'syntax error' or 'invalid input'
result from illegal characters, for example, '8', being found in a supposed 'octal constant'.
Valid octal constants
0123
01
11
1
1777
7776
2345
Invalid octal constants
5678
5a3
9
17777
User's symbol names
The user's symbols correspond to the labeled instructions, the labeled locations for
holding program variables, and the labeled locations holding program constants. Users'
symbol names must start with a letter, consist only of letters and digits, and should not
exceed six characters in length.
symbol_name
=
5
letter { letter | digit }
0
The assembler generates an error message 'name too long' if given a name exceeding six
characters. The error messages 'syntax error' or 'invalid input' results from illegal
characters found when a symbol name was expected. Users' symbols must be defined by
their occurring as labels at some point in the program text.
Valid names
ptr
max
addra
buffb
count1
sub2
Invalid names
1ptr
mainloop
Predefined op-code symbols
The op-codes listed in the op-code summary are predefined; these definitions cannot be
changed. Any attempt to redefine a standard op-code, for example, by labeling a location
12
with the name of one of the op-codes, results in the assembler reporting a 'doubly defined'
symbol.
Comments
A comment is introduced by a slash character, '/', and includes all characters up to the
next carriage return.
comment
=
/
{ any characters} carriage return
Labels
A label should occur at the start of a line. A label consists of a (unique) users' symbol
name with a terminating comma.
label
=
symbol_name ,
The assembler has two error messages concerning labels. 'Doubly defined' label means
that the same name has been used when labeling two different memory locations.
'Undefined symbol' errors relate to references to users' symbols for which there are no
corresponding label definitions.
Origin directive
An origin directive is used to specify the address of the memory location for the next
instruction or program datum assembled. An origin directive should occur on a line by
itself. It takes the form of a star and an octal constant specifying the address.
origin directive
=
*octal constant
Valid origin directives
*2
*200
*6000
Invalid origin directives
*800
*14000
13
The assembler may report errors 'number too large' or 'invalid input' if given bad data in
an origin directive.
End directive
A dollar symbol by itself at the begining of a line marks the end of the program text.
Forms of assembly language statements
The following types of statement are processed by the assembler:
Memory-reference instructions
Input/output instructions
Operate instructions
Specifications of constants (including address constants)
'Declarations' of variables
Any instruction can be labeled. Locations used for specifications of constants and
reserved by declarations of variables must be labeled.
There are no strict formatting requirements; it is not necessary to leave a
particular number of spaces at the beginning of a line. Usually, a statement should start
with a label or a tab character. In memory-reference instructions, the op-code/[indirect
symbol]/operand should be separated by one or more spaces.
Memory-reference instructions
[optional label] memref_op-code [indirect symbol] symbol_name
The memory-reference op-codes are 'and', 'tad', 'isz', 'dca', 'jms', and 'jmp'. Indirect
addressing, when needed, is indicated by the character 'i' between the op-code and the
'symbol_name'. The 'symbol_name' must correspond to the name used in one of the labels
in the program.
Direct memory references
Instruction
and mask
Interpretation
Form the logical 'and' of the data in the acc and the data from
the location labeled ' mask'; place the result in the acc.
14
tad sum
Form the sum of the data in the acc and the data from the
location labeled 'sum'; place the result in the acc.
isz lcount
Increment the contents of the location labeled 'lcount'; if the
incremented value is equal to zero then increment the PC to skip
the next instruction.
dca result
Store the contents of the acc in the location labeled 'result'; then
clear the acc.
jms subone
Call the subroutine that starts at the location labeled 'subone';
store current value of PC in the location labeled 'subone';
change the PC so that next instruction is taken from the location
following 'subone'.
jmp loop1
Change the PC so that the next instruction is taken from the
location labeled 'loop1'.
Indirect memory references
Instruction
and
Interpretation
i pmask
tad i
pdata
Form the logical 'and' of the data in the acc and data from the
location whose address can be found in the location labeled
'pmask' (first fetch the address from 'pmask', then fetch the data
from that address); place the result in the acc.
Form the sum of the data in the acc and data fetched from the
location whose address can be found in the location labeled
'pdata' (first fetch the address from 'pdata', then fetch the data
from that address); place the result in the acc. Usually used
when working through the elements of an array.
isz i ptcnt
Increment the contents of the location whose address
is held in the location labeled as 'ptcnt' (fetch the address from 'ptcnt', then operate on the
contents of the location with that address); if the incremented value is equal to zero then
increment the PC to skip the next
instruction.
Indirect memory references – continued
Instruction
dca i
Interpretation
bufptr
Store the contents of the acc in the location whose address is
held in the location labeled 'bufptr' (first fetch the address, then
store the contents of the acc in the location with that address);
then clear the acc. Mainly used when storing data in arrays.
15
jms i
psub1
Call the subroutine that starts at the location whose address is
held in 'psub1' (first, fetch this address from 'psub1', then store
the current value of PC in the location having this address;
change the PC so that the next instruction is taken from the
following location. Mainly used when calling a subroutine located
on another page.
jmp i
xx
Change the PC so that the next instruction is taken from the
location whose address is held in the location labeled 'xx' (first,
fetch the address from 'xx'; then use this address in the jump).
Most frequent use is in returns from subroutines, for example,
'jmp i subone'.
Valid memory reference instructions
(That is, valid if all the symbols referenced have been defined.)
ndif,
tad
dca
alpha
result
Invalid memory reference instructions
lp
tad beta i
dca isz sum
tad datum
Indirect symbol in wrong place.
Two op-codes?
No comma, label field will be misinterpreted.
Input/output instructions
[ optional label] io-opcode
An I/O instruction should occur by itself, though of course the instruction can be labeled,
and may be followed by a comment.
Valid I/O instructions
twait,
tsf
krb
/ check tty flag
Invalid I/O instructions
disc
dscf
krb datum
No comma after label, label field will be misinterpreted.
I/O instructions don't take operands.
16
Operate instructions
[optional label] operate_op-code
The majority of operate instructions involve a single instruction op-code, possibly labeled
and possibly followed by a comment. There a few permitted combinations of two (or
more) operate op-codes. For these the instruction format is of the form '[optional label]
operate1 operate2' (the order of the individual operate instructions in such a combined
instruction does not matter). Since the restrictions on combining operate instructions are
complex, use of combinations should be restricted to those combinations given as
examples in the main text.
Valid operate instructions
loop1,
cla cll
sna cla
hlt
Invalid operate instructions
cla count
Operate instructions don't take operands.
Constants
Individual constants (representing limit values, characters, bit masks, and so on) will
appear in the assembly-language source code in the form:
label octal-value
The assembler cannot interpret decimal numbers, signed numbers, or text strings for
character sequences. If a negative number is required, then the octal pattern
corresponding to the two's complement representation of that negative number must be
given.
Arrays of constant data (most commonly, these will be required for text strings)
will appear in the assembly-language source in the form:
label
octal-value
octal-value
octal-value
0
A conventional way of terminating a string is to place a zero word at the end.
Valid constants
17
limit,
mask1,
minus2,
msg1,
0012
0177
7776
123
165
155
040
075
040
0
/ limit for loop is ten (decimal)
/ mask for seven bit character
/ value -2
/S
/u
/m
/ space
/=
/ space
Address constants are a special case. They are required in constant pointers, for example,
a pointer to a subroutine located on another page, and base address values referencing
arrays.
label symbol-name
The assembler processes these constant declarations by filling in the values for the
addresses of the symbols (once these addresses have been determined).
Examples of address constants
psub1,
addrb,
subone
buffb
/ pointer to subone
/ address of start of 'buffer b'
Variables
Variables are defined in the source assembly language program by constructs of the form:
label 0
This defines the symbol used in the label field and reserves one memory word for the
variable with that symbol name. For example:
ptr1,
sum,
0
0
/ pointer used when accessing characters in array ...
/ location for sum
Such statements, in an assembly-language source program, define the variables 'ptr1' and
'sum'. (When the final object code is loaded, the locations corresponding to the variables
'ptr1' and 'sum' are set to zero. As in a FORTRAN 'DATA' statement, other initial values
can be defined for program variables. However, this 'initialization' is a load-time
operation; the zeroing-out or value-setting of the variables is not repeated at run time. If
the program is restarted, such variables have whatever values they possessed at the end of
18
the previous run of that program. Memory locations for program variables that need to
start as 0 should be explicitly cleared in the initialization phase of any program.)
Declarations of arrays are achieved as in the following example:
/ save 100 octal words for array buf1 starting at 1000
*1000
buf1,
0
*1100
/ now have 40 octal words for array ob1
ob1,
0
*1140
An origin directive is used to define where the array starts. A label is defined at that
location. Another origin directive then identifies the first location following the array.
Layout of a program
Simple programs should have the following organization:
/ This program ...
Each program should start with a few lines of
comments explaining the task it accomplishes.
*20
An origin directive should be used to place the first of
any global variables at location 0020. Comments
should identify the use of each variable and constant.
buff1,
kd100,
char,
buffb
0144
0
/ address of a buffer
/ decimal value 100
/ last character read
It is best to group separately the variables, constants,
and address pointers.
*200
The start of the main program should be located at
address 0200; so the *200 origin directive is always
needed.
/ start of main
.
/ main loop,
/ get next datum & ...
lp,
cla
jms sub
/ zero values are special
/ so ...
sna
19
Do not comment every instruction as it only clutters
the program listing; instead insert a comment every
few lines of code explaining the role of the next few
instructions in the overall task being handled by the
program.
.
.
The code of the main program should be followed by
its constants, address pointers, and then local
variables.
.
.
done,
lim,
psub2,
asum,
cla
hlt
0050
sub2
0
/ end of program
/ max iterations for ...
/ output routine on page 2
/ number of ...
If several routines are located on the same page, then
they should be clearly separated.
/-----/ sub, get data from a/d
/ and ...
sub,
0
.
A new origin directive is needed at the begining of
each page.
/---------*400
/---------/ Here we have the page 2 routines which include ....
.
Code should occupy the first few pages in memory
with any data arrays located at higher addresses.
/------*1600
/------/ On this page have two 64(dec) word arrays for data being analyzed and ..
arr1,
0
*1700
arr2,
0
The program should terminate with an end directive, that is, the
'$' symbol.
$
Program structures
20
While loops
The following code typifies the structure of a while loop:
Pascal
while (x <> 0) do begin
.
.
.
end;
Assembly language
whl1,
.
cla cll
tad
x
sna
cla
jmp
whe1
/ test if x non zero
/ if it is zero, jump to the instruction following the while
loop
.
.
/ body of while, corresponding to code
between
whe1,
.
.
jmp whl1
cla
.
/ begin and end
/ jump back to head of while loop
/ code following while
For loops
A for loop can be constructed in a style similar to that used for the while loop; a variable
can be allocated for the loop control and the termination test can check whether this
variable contains a specified limit value. However, if the value of the loop index is not
needed in the loop, then the following assembly language coding is slightly more
efficient:
/ initialization,
/ set a counter to hold, as a negative number, the
/ number of times the loop is to be cycled
tad
lim
/ pick up required cycle count
cia
/ negate it
dca
cntr
/ store in counter
/ head of loop
/ return to this point at start of each iteration
loop1,
cla cll
.
.
/ body of loop where computation performed
.
21
/ termination test and jump back to head of loop if not finished
isz
cntr
jmp
loop1
.
.
If ... then ...;
Simple if tests are coded by having a jump over the body of the if code (the parts 'then
begin ... end;').
Pascal
if (z=0) then begin
.
.
end;
Assembly language
ifnd,
cla cll
tad
z
sza cla
jmp
ifnd
.
.
.
cla
.
/ body of if statement
/ code following if
If ... then ... else ...;
The code for the simple if ... then ...; construct has to be extended with additional jumps.
Pascal
if (alpha>=3) then count1:=count1+1 else count2:=count2+1;
Assembly language
cla
tad
three
cia
tad
alpha
spa cla
jmp
elsebt
tad
count1
/ (alpha-3) in acc
/ jump over 'then' clause to get to else
22
elsebt,
endif,
three,
iac
dca
jmp
tad
iac
dca
.
.
.
.
3
count1
endif
count2
/ jump over 'else' clause to get to end of if statement
count2
/ code following if
Comparisons
The simulated machine lacks a compare instruction (and the condition bits that are
needed to record the results of a comparison). Consequently, as in the example above
where it was necessary to test if alpha>=3, a calculation must be carried out where one
value is subtracted from the other, the result left in the acc, and the result tested in a
subsequent skip operation.
Procedure's structure and declarations
The arrangement of code for a subroutine differs from the layout of a typical Pascal
procedure. Attempts to follow Pascal too closely (by having a procedure entry,
declarations of variables and constants, and then code) are likely to result in errors.
The following fragment illustrates the difference in layout. It is a procedure to
swap the values of two variables, 'alpha' and 'beta'; in the Pascal version these variables
are assumed to be globals; in the assembly code they are page zero variables.
Pascal
procedure swap;
var temp:integer;
begin
temp:=alpha;
alpha:=beta;
beta:=temp;
end;
Correct assembly language version of swap
swap,
0
location for return address
cla
tad
alpha
dca
temp
tad
beta
dca
alpha
/
23
tad
temp
dca
beta
jmp i swap
temp,
0
location for temporary results in subroutine swap
/
Incorrect assembly-language version of swap
swap,
0
location for return address
temp,
0
location for temporary results in subroutine swap
cla
tad
alpha
dca
temp
tad
beta
dca
alpha
tad
temp
dca
beta
jmp i swap
/
/
If the incorrect code is executed, the first 'instruction' of the subroutine 'swap' is
determined by the contents of 'temp'. The first time the routine is called, this would be
zero; zero interpreted as an instruction is an 'and' (which would probably not do much
harm). Then the current value of 'alpha' (e.g. 5100 octal) is stored in 'temp', from where it
is later copied into 'beta'. The next time the 'swap' routine is called, the value 5100 octal
left in 'temp' is executed as an instruction (this time it causes a jump to location 100 and
wrecks the program).
Don't let variables or constants become mixed into the code of the routines!
24
Looping and accessing successive elements of an array
A 'pointer', initialized to contain the address of the first element of the array, is used to
access array elements. The pointer is incremented on each cycle through the loop. (It is
easiest to think in terms of arrays with an index starting at zero, rather than at 1; so an
array with 'lim' elements is really var datum : array[0..(lim-1)] of integer;).
Example
Sum the values in all elements of array:
Pascal
sum:=0;
for i:=0 to (lim-1) do sum:=sum+datum[i];
Assembly language
.
.
/ set up loop
tad
lim
cia
dca
cntr
tad
addtm
dca
ptr1
/ use acc to 'accumulate' the sum
loopz,
tad i ptr1
isz
ptr1
nop
isz
cntr
jmp
loopz
dca
sum
.
.
.
/ number of elements in array
/ address of element zero of array datum
/ add next element to partial sum
/ update ptr1
/ (Don't want that isz ever to cause a skip)
/ increment count of elements processed
/ store resulting sum in appropriate variable
Access to random elements of an array
Access to random elements of an array requires the complete process of constructing the
address of the particular array element required and then accessing the memory location
having this computed address. On the simulator, the final access to memory to fetch or
store the required datum requires the use of a pointer variable which is also held in
memory.
So, to access an arbitrary memory element one needs to fetch the address of the
start of the array, and add the index value to get the address of the element required. This
address must be stored in a pointer. An indirect access using this pointer is made to access
the required data.
25
Example
Count the number of occurrences of each different ASCII character in a sequence of 512
characters read from the keyboard.
The program consists of two loops. In the first of these, the array of counts must
be cleared; here, each array element is accessed in sequence permitting the simple
incrementing pointer method to be used for array access. In the second loop, the 512
characters are read and each is used to increment an appropriate count in the array of
counts.
Pascal
program ascii;
var chars :array[0..127] of integer;
cntr,temp:integer;
ch:char;
begin
for cntr:=0 to 127 do chars[cntr]:=0;
for cntr:=1 to 512 do begin
read(ch);
temp:=ord(ch);
chars[temp]:=chars[temp]+1
end;
end.
Assembly language
*200
/ count ascii,
/----------------------------------/ first, must 'zero' out the array which will hold counters
cla cll
/ set up the loop controls, a -ve counter in cntr, and a pointer
tad
limit
/ number of different ascii characters
cia
/ negate
dca
cntr
tad
addr
/ address of where the counts are stored
dca
ptr
/ start the clearing loop
clear,
dca i ptr
isz
ptr
nop
isz
cntr
jmp
clear
/----------------------------------/ now initialize count for number of characters to process
tad
numchr
/ number of characters to be read
cia
dca
cntr
26
/----------------------------------/ ok, initialization complete, get characters
loop,
ksf
jmp
loop
krb
and
mask
/ mask down to 7 bits (just in case!)
/----------------------------------/ Here is where the random access is made to the array of character counts.
/ now have what is really an index value in acc
/ add in base address of array
tad
addr
/ and save the resulting final address in a pointer
dca
dptr
/ ok, dptr holds address of character count value that is to be incremented
tad i
dptr
/ get current value
iac
/
increment
dca i
dptr
/ store back
/ (that could have been done as isz i dptr)
/
/ ok, processing of current character complete
/ go back for more if necessary
isz
cntr
jmp l
oop
hlt
/----------------------------------/----------------------------------/ variables, pointers etc for character count program
dptr,
0
/ used as pointer holding address of array element
ptr,
0
/ used as pointer into array when clearing it
cntr,
0
/ used as counter for loops
addr,
chars
/ address of array containing character counts
mask,
0177
/ make certain only 7-bit ascii codes
numchr, 1000
/ 512 decimal
limit,
0200
*0400
chars,
0
/ start of array for character counts
$
27
ASCII character values
|000 nul
|010 bs
|020 dle
|030 can
|040 sp
|050 (
|060 0
|070 8
|100 @
|110 H
|120 P
|130 X
|140 `
|150 h
|160 p
|170 x
|001 soh |002 stx
|011 ht |012 nl
|021 dc1 |022 dc2
|031 em |032 sub
|041 !
|042 "
|051 )
|052 *
|061 1 |062 2
|071 9 |072 :
|101 A |102 B
|111 I
|112 J
|121 Q |122 R
|131 Y |132 Z
|141 a |142 b
|151 i
|152 j
|161 q |162 r
|171 y |172 z
|003 etx
|013 vt
|023 dc3
|033 esc
|043 #
|053 +
|063 3
|073 ;
|103 C
|113 K
|123 S
|133 [
|143 c
|153 k
|163 s
|173 {
|004 eot
|014 np
|024 dc4
|034 fs
|044 $
|054 ,
|064 4
|074 <
|104 D
|114 L
|124 T
|134 \
|144 d
|154 l
|164 t
|174 |
|005 enq |006 ack
|015 cr |016 so
|025 nak |026 syn
|035 gs |036 rs
|045 % |046 &
|055 |056 .
|065 5 |066 6
|075 = |076 >
|105 E |106 F
|115 M |116 N
|125 U |126 V
|135 ]
|136 ^
|145 e |146 f
|155 m |156 n
|165 u |166 v
|175 }
|176 ~
|007 bel
|017 si
|027 etb
|037 us
|047 '
|057 /
|067 7
|077 ?
|107 G
|117 O
|127 W
|137 _
|147 g
|157 o
|167 w
|177 del
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|