; PDP-8/A Console ROM disassembly ; Entry at 74000 ; Appears to assume AC has been cleared and that IF/DF are set to field 7 at entry. ; ROM from 74000-74377 (3x 82S129 1-kbit ROM chips) ; RAM from 70100-70117 (3x DM7479 64-bit RAM chips) ; Unknown hardware register at 70120 ; Usage summary: ; This board and associated ROM provides a fairly standard "ODT"-like interface: ; Memory examination: ; An octal address of up to 5 digits can be entered by the user, allowing addressing of all 8 data fields. ; this address may be followed by a "/" character, which will display the contents of that address. ; A carriage return terminates this process, a line feed will increment the address and display its contents. ; Memory deposits: ; As above; after the memory contents are displayed, entry of another four digit octal value will replace the contents of the ; current address. A carriage return terminates this process, a line feed will increment the address, display its contents, ; and allow entry of a new value to be stored. ; ; The "G" command starts execution at the specified address, or if no address is specified, will start at 200. ; (e.g. "7756G" starts at address 7756, "G" starts at 200). ; ; The "D" command sets the data field for subsequent "G" commands (the "G" command will of course set the instruction field ; appropriately.) Only the low 3 bits of the specified value are used. ; (e.g. "1234D" and "4D" both set the data field to field 4.) ; ; The "S" command deposits the specified value into onboard register at 70120. What effect this has is unknown. ; ; Two RIM loaders are provided by the ROM, they can be loaded into memory at 7756 with the "L" (low-speed) ; and "H" (high-speed) commands. An optional field can be provided, which specifies the field to load the loader into. ; the loader is not automatically executed, a subsequent "G" command is required. ; (e.g. "3L" places the low-speed loader into field 3, "H" places the high-speed loader into field 0) ; ; RAM 70100 ; temporary storage for AC 70101 ; temporary storage for current address & loader words / used for CDI/CDF instructions ; with "G" command 70102/0000 ; subroutine entry for teletype output routine / used for CDI/CDF instructions with ; "G" command" 70103/5504 JMP I 104 ; jump back into ROM at 74344 for output routine / jump to start address for "G" command 70104/4344 ; overwritten with start address for "G" command 70105/0000 ; RAM thunk. This return address is overwritten ; by the routine in ROM at 74370, allowing ROM code to ; execute subroutine calls. 70106/5507 JMP I 107 ; indirect jump back into ROM at 74370 70107/4370 ; address of ROM thunk code 70110 ; CDF instruction modified & used to change data and instruction fields in various places 70111/5505 JMP I 105 ; return from subroutine 70112 ; CDF instruction used during "G" commands 70113 ; 4 digit address input by user 70114 ; 1 digit field address input by user 70115 ; last character input by user 70116 ; indicates whether a valid digit has been entered - 0 if true, 0200 if not. 70117 ; stores the current field being addressed via memory access commands 70120 ; Appears to be some sort of hardware register; function unknown. ; ROM entry point 74000/1356 TAD 4156 ; load 5507 (JMP I 107) 74001/3106 DCA 106 ; store at 70106 74002/1357 TAD 4157 ; load 4370 (ROM address for thunk code) 74003/3107 DCA 107 ; store at 70107 74004/1332 TAD 4132 ; load 5505 (JMP I 105) 74005/3111 DCA 111 ; store at 70111 74006/1360 TAD 4160 ; load 4344 - character output subroutine address 74007/3104 DCA 104 ; store at 70104 - write subroutine address to RAM 74010/0200 AND 4000 ; AND with 74000 (this is actually a constant value, see 74053) 74011/3112 DCA 112 ; store 0 at 70112 74012/3120 DCA 120 ; store 0 at 70120 74013/1361 TAD 4161 ; load 5504 (JMP I 104) 74014/3103 DCA 103 ; store at 70103 74015/0010 AND 10 ; and with 70010 (another constant value) 74016/7000 NOP ; another constant 74017/1273 TAD 4073 ; load carriage return character (1215; low 7 bits are 15) 74020/4102 JMS 102 ; output to teletype 74021/1244 TAD 4044 ; load line feed character (4012; low 7 bits are 12) 74022/4102 JMS 102 ; output the character 74023/4105 JMS 105 ; jump to RAM thunk routine 74024/4053 JMS 53 ; ROM routine - command input routine ; arguments to routine: this is a sequence of pairs of words: ; word 0 - input character (command) ; word 1 - address of the routine used to service said command. ; these are all commands that can optionally take a numeric argument as a prefix ; (i.e. "0200G" or just "G" is allowed) 74025/0314 ; 'L' - read Low-Speed RIM loader into the field specified by the numeric argument (0-7) 74026/4134 74027/0310 ; 'H' - read High-Speed RIM loader into the field specified by the numeric argument (0-7) 74030/4133 74031/0307 ; 'G' - start execution at the specified 15-bit address. If no argument specified, start ; at 0200 in field 0. 74032/4246 74033/0000 ; end of command table 74034/1116 TAD 116 ; was at least one digit entered? 74035/7640 SZA CLA 74036/5250 JMP 4050 ; no, jump to 74050 -- this is invalid input 74037/4105 JMS 105 ; jump to RAM thunk routine 74040/4114 JMS 114 ; ROM routine - process more commands ; another table of arguments as above: ; These are all commands that require a numeric argument as a prefix. 74041/0304 ; 'D' - set Data field to the field specified by the numeric argument (0-7) 74042/4227 74043/0323 ; 'S' - Writes specified value to 70120. What purpose does this serve? 74044/4012 74045/0257 ; '/' - memory read/write command - prints the current value at the specified address, ; and allows modification. 74046/4264 74047/0000 ; end of command table ; Invalid input. Print a "?" and start over. 74050/1302 TAD 4102 ; load a '?' char into the AC 74051/4102 JMS 102 ; output it to the teletype 74052/5216 JMP 4016 ; and start the input over again. ; ROM routine: command input: ; Read a character from keyboard, parse as either an octal digit, or if not ; a valid octal digit, see if it matches one of the commands in the argument list ; (see comments at 74024). 74053/1210 TAD 4010 ; load AC with 200 74054/3116 DCA 116 ; save at 70116 74055/3114 DCA 114 ; load 0 at 70114 74056/3113 DCA 113 ; and 70113 74057/6032 KCC ; clear input, read character 74060/6031 KSF ; skip if input data is ready 74061/5260 JMP 4060 ; nope, keep waiting 74062/1210 TAD 4010 ; add 200 74063/6034 KRS ; OR in keyboard char 74064/3115 DCA 115 ; store at 70115 74065/1115 TAD 115 ; get keyboard char back 74066/4102 JMS 102 ; output it to the terminal 74067/1115 TAD 115 ; get char back again 74070/1274 TAD 4074 ; add 7510 (-270 octal, character '8') 74071/7500 SMA ; skip if AC < 0 74072/5314 JMP 4114 ; not less than '8' -- this is not an octal digit 74073/1215 TAD 4015 ; add 10 (this instruction is also used as a constant value (ref'd from 74017)) 74074/7510 SPA ; skip if AC >= 0 74075/5314 JMP 4114 ; not greater than or equal to '0' -- this is not an octal digit. 74076/3115 DCA 115 ; this is a digit: store at 115 74077/7000 NOP ; (constant value which is conveniently also a NOP) 74100/3116 DCA 116 ; store 0 at 116 - a digit was entered 74101/1113 TAD 113 ; load value at 70113 (low 4 digits) 74102/0277 AND 4077 ; and with 7000 (mask off top 3 bits) (also used as a constant for the '?' character) 74103/7106 CLL RTL ; clear link; rotate twice left 74104/7006 RTL ; rotate once more -- top 3 bits are now at low 3 bits) 74105/3114 DCA 114 ; store at 70114 - this will be the 3 bit field address if 5 digits are entered 74106/1113 TAD 113 ; load running total for low 4 digits 74107/7104 CLL RAL 74110/7104 CLL RAL 74111/7104 CLL RAL ; rotate left three times, ensuring link doesn't get involved, this leaves space for next digit in the 3 low bits 74112/1115 TAD 115 ; add the digit that was just entered into the low 3 bits 74113/5256 JMP 4056 ; go back and get the next character. ; routine continuation - a non-digit character was entered. 74114/7200 CLA ; clear AC 74115/6271 CDF 7 ; change to DF 7 74116/1505 TAD I 105 ; get command character to test for 74117/2105 ISZ 105 ; (and increment return address to point to routine jump word) 74120/7450 SNA ; if this is zero, we return -- this matched no commands 74121/5505 JMP I 105 ; return 74122/7041 CIA ; not zero, give me the 2's complement of that value 74123/7510 SPA ; check if it is >= 0 74124/1115 TAD 115 ; no: add to input character 74125/7640 SZA CLA ; check if it is == 0; clear AC 74126/5316 JMP 4116 ; not zero -- not a match for this command, let's try the next one 74127/1505 TAD I 105 ; value is zero, no more arguments; get the JMS instruction to use 74130/3105 DCA 105 ; modify return to invoke this subroutine jump 74131/1113 TAD 113 ; load AC with 4 digits of address (argument to command) 74132/5505 JMP I 105 ; "return" from subroutine (also constant 5505 (used at 74004)) ; this will actually end up invoking the command routine. ; ROM routine for "H" command: 74133/7610 SKP CLA ; clear AC, skip next. ; ROM routine for "L" command: 74134/7610 SKP CLA ; clear AC, skip next (skipped for "H" command) 74135/1362 TAD 4162 ; load AC with 7756 (skipped for "L" command) 74136/1363 TAD 4163 ; for "L" command: load AC with 4206 (ROM address of low-speed RIM loader) ; for "H" command: add 4206 to 7756; giving us 4164, the ROM address of the ; high-speed RIM loader) 74137/3114 DCA 114 ; deposit address at 70114 74140/1362 TAD 4162 ; load AC with 7756 (start of RIM loader core address) 74141/3116 DCA 116 ; deposit address at 70116 74142/6271 CDF 7 ; set data field to 7 74143/1514 TAD I 114 ; load RIM instruction from ROM 74144/2114 ISZ 114 ; increment source address 74145/7450 SNA ; loader is terminated by a 0 -- are we done? 74146/5216 JMP 4016 ; yep, return to the prompt. 74147/3101 DCA 101 ; deposit RIM instruction word at 70101 74150/4105 JMS 105 ; jump to RAM thunk 74151/4234 JMS 4034 ; ROM routine - change data field to the field specified in the command argument 74152/1101 TAD 101 ; get RIM instruction word 74153/3516 DCA I 116 ; deposit it at the current address in the correct field. 74154/2116 ISZ 116 ; increment destination address. 74155/5342 JMP 4142 ; do the next word. ; constant instruction words loaded into RAM: 74156/5507 JMP I 107 ; constant 5507 (referenced at 74000) 74157/4370 JMS 4170 ; constant 4370 (referenced at 74002) 74160/4344 JMS 4144 ; constant 4344 (referenced at 74006) 74161/5504 JMP I 104 ; constant 5504 (referenced at 74013) 74162/7756 ; constant - RIM core address 74163/4206 ; constant - RIM loader ROM address ; high-speed RIM loader 74164/6014 RFC 74165/6011 RSF 74166/5357 JMP 4157 74167/6016 RFC RRB 74170/7106 CLL RTL 74171/7006 RTL 74172/7510 SPA 74173/5374 JMP 4174 74174/7006 RTL 74175/6011 RSF 74176/5367 JMP 4167 74177/6016 RFC RRB 74200/7420 SNL 74201/3776 DCA I 4376 74202/3376 DCA 4376 74203/5357 JMP 4357 74204/0000 AND 0 74205/7563 MQA MQL SCA SCL ; unused ; low-speed RIM loader 74206/6032 KCC 74207/6031 KSF 74210/5357 JMP 4357 74211/6036 KRB 74212/7106 CLL RTL 74213/7006 RTL 74214/7510 SPA 74215/5357 JMP 4357 74216/7006 RTL 74217/6031 KSF 74220/5367 JMP 4367 74221/6034 KRS 74222/7420 SNL 74223/3776 DCA I 4376 74224/3376 DCA 4376 74225/5356 JMP 4356 74226/0000 AND 0 ; ROM routine for "D" command 74227/4105 JMS 105 ; invoke RAM thunk 74230/4235 JMS 4235 ; set Data field 74231/1110 TAD 110 ; get CDF instruction 74232/3112 DCA 112 ; store at 70112 for future use by "G" commands 74233/5662 JMP I 4262 ; return to top of main loop. ; ROM subroutine used in "L"/"H"/"G" commands. ; Sets the data field, if specified by the user. 74234/1113 TAD 113 ; read argument value 74235/7106 CLL RTL ; clear link, rotate left twice 74236/7004 RAL ; rotate again 74237/0244 AND 4244 ; AND with 70, mask off non-field bits 74240/1245 TAD 4245 ; create CDF instruction 74241/3110 DCA 110 ; and write it to RAM 74242/5110 JMP 110 ; jump to CDF instruction in RAM ; (instruction at 111 is JMP I 105 which will return) 74243/7774 SPA SNA SZL CLA OAS ; constant: -4 74244/0070 AND 70 ; constant - field mask value 74245/6201 CDF 0 ; constant - CDF instruction ; ROM routine for "G" command: 74246/1116 TAD 116 ; add 0200 if no argument was specified to "G" (defaults to 200, conventional entrypoint) 74247/3104 DCA 104 ; deposit argument at 74104 (address to start execution at) 74250/1114 TAD 114 ; read field address 74251/4105 JMS 105 ; jump to RAM thunk 74252/4235 JMS 4235 ; ROM routine - set data field 74253/7326 CLA CLL CML RTL ; AC = 2 74254/1110 TAD 110 ; add to CDF instruction, now it's a CDI instruction 74255/3101 DCA 101 ; store at 101 74256/1112 TAD 112 ; copy CDF instruction for data field switch (as specified by "D" command) 74257/3102 DCA 102 ; store at 102 74260/6007 CAF ; Clear all the stuff 74261/5101 JMP 101 ; Execute the CDI instruction; now the data and instruction fields are set. ; This will then do an indirect jump to the address at 74104, starting execution. 74262/4016 JMS 16 ; fixed return address to top of main loop. 74263/4050 JMS 50 ; fixed return address to "?" printing routine. ; Rom routine for "/" command 74264/3101 DCA 101 ; save the address at 70101 74265/1114 TAD 114 ; get the field 74266/3117 DCA 117 ; save at 70117 74267/1117 TAD 117 ; get it back 74270/4105 JMS 105 ; invoke RAM thunk 74271/4235 JMS 4235 ; ROM routine - set data field 74272/1501 TAD I 101 ; read the word at the user-specified address 74273/4105 JMS 105 ; thunk 74274/4351 JMS 4351 ; ROM routine - print octal value of the word we read in 74275/1311 TAD 4311 ; load AC with 7640 (space) 74276/4102 JMS 102 ; print it 74277/4105 JMS 105 ; RAM thunk 74300/4053 JMS 53 ; ROM routine - execute user command, arguments are as previously described 74301/0215 ; Carriage Return command. 74302/4307 74303/0212 ; Line Feed 74304/4307 74305/0000 ; That's it 74306/5663 JMP I 4263 ; return and print a "?" because we didn't understand the user's request. ; Process a CR or LF: 74307/7200 CLA 74310/1116 TAD 116 ; load "digit was entered" flag 74311/7640 SZA CLA ; well, was a digit entered? (this word also used as character value for ' ') 74312/5317 JMP 4317 ; no. 74313/4105 JMS 105 ; yes, RAM thunk 74314/0110 AND 110 ; RAM routine at 110 to change data field 74315/1113 TAD 113 ; load value provided by user 74316/3501 DCA I 101 ; deposit at address 74317/1115 TAD 115 ; get last keystroke 74320/7110 CLL RAR ; rotate right, bit 11 into link (test whether this is CR or LF) 74321/7630 SZL CLA ; if link is zero, this is a linefeed 74322/5662 JMP I 4262 ; carriage return: we are done here, return to main program loop. 74323/1301 TAD 4301 ; line feed: get the carriage return character 74324/4102 JMS 102 ; and print it 74325/4102 JMS 102 ; and print it again 74326/2101 ISZ 101 ; increment the address 74327/7410 SKP ; skip the next instruction normally 74330/2117 ISZ 117 ; increment the field if the address wraps around 74331/0257 AND 4257 ; and with 3102 (AC is zero here so this does nothing, this is a constant for the '/' character) 74332/1117 TAD 117 ; load the field 74333/0260 AND 4260 ; mask off the bottom three bits 74334/1362 TAD 4362 ; add 260 (make this an ASCII digit) 74335/4102 JMS 102 ; and print it 74336/1101 TAD 101 ; load the address 74337/4105 JMS 105 ; thunk 74340/4351 JMS 4351 ; ROM routine - print octal number 74341/1331 TAD 4331 ; load 257 ('/' character) into AC 74342/4102 JMS 102 ; and print it 74343/5267 JMP 4267 ; and start over, printing the contents of this memory location and accepting input. ; ROM subroutine: output character in AC to teletype and wait until it is sent. ; AC is cleared on exit. 74344/6046 TLS ; Output character in AC to teletype 74345/6041 TSF ; Skip if teletype is done 74346/5345 JMP 4345 ; Nope, keep waiting 74347/7200 CLA ; Teletype done. clear AC. 74350/5502 JMP I 102 ; return from subroutine ; ROM routine to print a 4 digit octal value to the teletype. 74351/3115 DCA 115 ; save the value to 70115 74352/1243 TAD 4243 ; get the digit counter (-4) 74353/3116 DCA 116 ; store at 70116 74354/1115 TAD 115 ; read current value 74355/7106 CLL RTL 74356/7004 RAL ; rotate left thrice 74357/3115 DCA 115 ; store at 70115 74360/1115 TAD 115 ; get the value back 74361/7004 RAL ; rotate it left once 74362/0260 AND 4260 ; and with 6007 (we only care about the low three bits) 74363/1362 TAD 4362 ; add 260 (convert to an ASCII digit) 74364/4102 JMS 102 ; output to the teletype 74365/2116 ISZ 116 ; increment digit counter, skip on zero 74366/5354 JMP 4354 ; not done -- go do this again 74367/5505 JMP I 105 ; done -- return. ; ROM subroutine: other half of thunk routine invoked from RAM at 70105. ; Executes the instruction at the address following the invoking JMS. ; ROM subroutine code must do a "JMP I 105" to return. 74370/6271 CDF 7 ; change to field 7 74371/3100 DCA 100 ; store AC at 70100 74372/1505 TAD I 105 ; load address of ROM routine to execute 74373/3102 DCA 102 ; store at 102 74374/2105 ISZ 105 ; increment return address 74375/1100 TAD 100 ; restore AC 74376/5502 JMP I 102 ; "return" from this routine (execute ROM routine) ; unused 74377/0000