====================== LMC Indirection Tricks ====================== -Ian! D. Allen - idallen@idallen.ca - www.idallen.com The LMC has no "indirect addressing" mode, where you can tell the LMC to load or store via an address that changes according to the program logic. For example: read in numbers and store them in increasing memory locations. Most real computers have some "address register" that you can increment and use; the LMC does not. All LMC load and store operations use a fixed address as the operand. The trick you have to use in the LMC to load or store at a program-determined address is to write "self-modifying code": the program logic must modify a "LDA" or STO" instruction to contain the program-determined address and the LMC must then execute that modified instruction to do the actual load or store. The program must continually modify the load or store instruction by updating the address. Here is an example algorithm that uses this trick twice: Write the values 11 through 29 into mailboxes 81 through 99. Sum the mailboxes in reverse order; output the sum. Pseudocode for ( counter = 81; counter <= 99; counter++ ) memory[counter] = counter - 70 endfor sum = 0 for ( counter = 99; counter >= 81; counter-- ) sum += memory[counter] endfor output sum Revised Pseudocode (turn FOR into WHILE) counter = 81 while ( counter <= 99 ) memory[counter] = counter - 70 counter = counter + 1 endwhile sum = 0 counter = 99 while ( counter >= 81 ) sum += memory[counter] counter = counter - 1 endwhile output sum LMC Revised Pseudocode using "skip" and "jump" and self-modify code: counter = 81 TEST1: calculate 99 - counter if ( positive light is on ) skip next instruction jump to ENDWH1 DOIT1 = STORE+counter calculate counter - 70 DOIT1: /* self-modify STORE code gets stored here */ counter = counter + 1 jump to TEST1 ENDWH1: sum = 0 counter = 99 TEST2: calculate counter - 81 if ( positive light is on ) skip next instruction jump to ENDWH2 DOIT2 = LOAD+couunter DOIT2: /* self-modify LOAD code gets stored here */ sum = sum + contents of calculator counter = counter - 1 jump to TEST2 ENDWH2: output sum halt ;Label Mnem. Operand Comments............. ;----- ----- ------- --------------------- LDA NUM81 STO COUNTER TEST1 LDA NUM99 ; FIRST LOOP while counter <= 99 SUB COUNTER SKP JMP ENDWH1 LDA STORE ; mem[counter] = counter - 70 ADD COUNTER STO DOIT1 LDA COUNTER SUB NUM70 DOIT1 DAT ; SELF-MODIFYING "STO" CODE HERE LDA COUNTER ; counter++ ADD ONE STO COUNTER JMP TEST1 ENDWH1 LDA ZERO ; two initializations in FOR loop STO SUM LDA NUM99 STO COUNTER TEST2 LDA COUNTER ; SECOND LOOP while counter >= 81 SUB NUM81 SKP JMP ENDWH2 LDA LOAD ; sum += mem[counter] ADD COUNTER STO DOIT2 DOIT2 DAT ; SELF-MODIFYING "LDA" CODE HERE ADD SUM STO SUM LDA COUNTER ; counter-- SUB ONE STO COUNTER JMP TEST2 ENDWH2 LDA SUM ; output sum and stop OUT HLT ; CONSTANTS LOAD DAT 100 ; constant: code for a LOAD STORE DAT 200 ; constant: code for a STORE ONE DAT 001 ; constant ZERO DAT 000 ; constant NUM70 DAT 070 ; constant NUM81 DAT 081 ; constant NUM99 DAT 099 ; constant ; VARIABLES SUM DAT ; variable: sum of mailboxes COUNTER DAT ; variable: count the mailboxes ------------------------------------------------------------------------------- Assembly Language "Listing" file showing mailboxes (MB) and Machine Code: MB Code Label Mnemon. Operand Comments -- ---- ----- ------- ------- ------------------------- 00 142 : LDA NUM81 01 245 : STO COUNTER 02 143 : TEST1 LDA NUM99 ; FIRST LOOP while counter <= 99 03 445 : SUB COUNTER 04 802 : SKP 05 916 : JMP ENDWH1 06 138 : LDA STORE ; mem[counter] = counter - 70 07 345 : ADD COUNTER 08 211 : STO DOIT1 09 145 : LDA COUNTER 10 441 : SUB NUM70 11 000 : DOIT1 DAT ; SELF-MODIFYING "STO" CODE HERE 12 145 : LDA COUNTER ; counter++ 13 339 : ADD ONE 14 245 : STO COUNTER 15 902 : JMP TEST1 16 140 : ENDWH1 LDA ZERO ; two initializations in FOR loop 17 244 : STO SUM 18 143 : LDA NUM99 19 245 : STO COUNTER 20 145 : TEST2 LDA COUNTER ; SECOND LOOP while counter >= 81 21 442 : SUB NUM81 22 802 : SKP 23 934 : JMP ENDWH2 24 137 : LDA LOAD ; sum += mem[counter] 25 345 : ADD COUNTER 26 227 : STO DOIT2 27 000 : DOIT2 DAT ; SELF-MODIFYING "LDA" CODE HERE 28 344 : ADD SUM 29 244 : STO SUM 30 145 : LDA COUNTER ; counter-- 31 439 : SUB ONE 32 245 : STO COUNTER 33 920 : JMP TEST2 34 144 : ENDWH2 LDA SUM ; output sum and stop 35 600 : OUT 36 700 : HLT 37 100 : LOAD DAT 100 ; constant: code for a LOAD 38 200 : STORE DAT 200 ; constant: code for a STORE 39 001 : ONE DAT 001 ; constant 40 000 : ZERO DAT 000 ; constant 41 070 : NUM70 DAT 070 ; constant 42 081 : NUM81 DAT 081 ; constant 43 099 : NUM99 DAT 099 ; constant 44 000 : SUM DAT ; variable: sum of mailboxes 45 000 : COUNTER DAT ; variable: count the mailboxes TEST1 at 02 DOIT1 at 11 ENDWH1 at 16 TEST2 at 20 DOIT2 at 27 ENDWH2 at 34 LOAD at 37 STORE at 38 ONE at 39 ZERO at 40 NUM70 at 41 NUM81 at 42 NUM99 at 43 SUM at 44 COUNTER at 45 -- | Ian! D. Allen - idallen@idallen.ca - Ottawa, Ontario, Canada | Home Page: http://idallen.com/ Contact Improv: http://contactimprov.ca/ | College professor (Free/Libre GNU+Linux) at: http://teaching.idallen.com/ | Defend digital freedom: http://eff.org/ and have fun: http://fools.ca/