Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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 | | | | | | | | | | | | | | | |