; TI990/10 LOAD ROMs disassembly ; ;General background : ; These ROMs contain the handler for the LOAD/RESTART interrupt. This interrupt is called at ; start-up (instead of RESET, which is used for "warm reset", I think), so that the boot loader in ; ROMs can be executed. ; ; This interrupt can also be triggered by the programmer panel, and there is code to handle the ; panel functions. ; ;Description : ; We have 1kb of ROMs (4 256*8 ROMs). ; ; If you want a starting point, you can have a look at the LOAD vector located at >FFFC. ; The LOAD routine starts at >FC00. ; ; The ROMs basically do the following : ; * handle programmer panel functions if applicable ; * look for a MDU, and boot from it if present ; * if programmer panel enabled, boot from the unit designated in RO/R1/R2 (either ASR tape, ; Card Reader, or tape/disk based on a MT3200/WD900 controller or equivalent) ; ; by default, it boots from disk unit 0, using controller base address >F800. ; ;Conventions used : ; TMS9900 assembly conventions should have been respected. Particularily : ; * bit are numbered from MSB to LSB (unlike almost every other CPU) ; ; Raphael Nabet, 2000/04/30 ; ; revision history : ; 2000/04/30 : initial release ; LOAD vector entry point FC00: 020C 1FE0 LI R12,>1FE0 ; programmer panel CRU base FC04: 0221 6700 AI R1,>6700 ; look for magical value (>9900) FC08: 1602 JNE >FC0E ; continue with normal vector if not found FC0A: 1D0A SBO >000A ; switch "Run" light on FC0C: 0450 B *R0 ; branch to routine if found FC0E: 0209 00A0 LI R9,>00A0 ; R9 points to free area in RAM ? FC12: 0700 SETO R0 ; R0 < 0 : use TILINE unit (tape, FD1000, hard disk) by default FC14: 0201 F800 LI R1,>F800 ; TILINE address for default disk controller FC18: 0202 0800 LI R2,>0800 ; if programmer panel enabled, boot from drive unit 0 by default FC1C: 1F0B TB >000B FC1E: 133B JEQ >FC96 ; if programmer panel disabled, jump to boot routine FC20: C10E MOV R14,R4 ; load old PC to display it ; programmer panel scan : we have 4 rows of 8 switches ; 16 switches allow to toggle the display in R4. ; the 16 other switches allow to access programmer panel functions. ; ; register conventions here : ; R4 = data register ; R7 = memory address register ; R13 = WP ; R14 = PC ; R15 = ST ; keyscan loop start FC22: 3204 LDCR R4,8 ; display data register MSB FC24: 3220 0089 LDCR @>0089,8 ; display data register LSB FC28: 0205 FC8C LI R5,>FC8C FC2C: 0695 BL *R5 ; read current 8 switches from programmer panel to R3 MSB FC2E: 16FE JNE >FC2C ; wait for all switches to be released FC30: 0695 BL *R5 FC32: 16FC JNE >FC2C ; test again to fix switch bounce problems FC34: 0695 BL *R5 FC36: 16FA JNE >FC2C ; again FC38: 04C3 CLR R3 FC3A: 1D08 SBO >0008 ; "Increment scan" bit -> select another row of switches FC3C: 0695 BL *R5 FC3E: 13FD JEQ >FC3A ; if no switch pressed, scan next row FC40: 0695 BL *R5 FC42: 13FB JEQ >FC3A ; fixes switch bounce problems FC44: 0695 BL *R5 FC46: 13F9 JEQ >FC3A ; again FC48: 1F09 TB >0009 ; scan count bit 0 -> is current switch row number odd or even ? FC4A: 1601 JNE >FC4E FC4C: 06C3 SWPB R3 ; if odd, we read last 8 switches in 16 switches, so we rotate 8 bits FC4E: 1F08 TB >0008 ; scan count bit 1 -> is this command switches or data switches ? FC50: 1302 JEQ >FC56 ; command switches -> jump to interpret command FC52: 2903 XOR R3,R4 ; data switches -> toggle the data displayed as requested FC54: 10E6 JMP >FC22 ; update display and go back to scan routine FC56: 04C5 CLR R5 FC58: 05C5 INCT R5 FC5A: 0A13 SLA R3,1 FC5C: 17FD JNC >FC58 ; count first bit set to 1 in R3, i.e. first switch pressed FC5E: 04A5 FC62 X @>FC62(R5) ; execute command as needed FC62: 10DF JMP >FC22 ; jump to display value if the X instruction did not jump ; Programmer panel instruction table. ; All jump offsets must be relative to >FC62, since this is the value of PC when X ; executes the instruction in the table. FC64: 1013 JMP *+>FC88->FC62 ; "Halt/SIE" switch FC66: 1011 JMP *+>FC84->FC62 ; "Run" switch FC68: 0360 RSET ; "Reset" switch FC6A: 101A JMP *+>FC96->FC62 ; "Load" switch FC6C: C10D MOV R13,R4 ; "Display WP" switch FC6E: C10E MOV R14,R4 ; "Display PC" switch FC70: C10F MOV R15,R4 ; "Display ST" switch FC72: C107 MOV R7,R4 ; "Display MA" switch FC74: C344 MOV R4,R13 ; "Enter WP" switch FC76: C384 MOV R4,R14 ; "Enter PC" switch FC78: C3C4 MOV R4,R15 ; "Enter ST" switch FC7A: C1C4 MOV R4,R7 ; "Enter MA" switch FC7C: C117 MOV *R7,R4 ; "MDD" switch ("Memory Data Display") FC7E: 05C7 INCT R7 ; "MAI" switch ("Memory Address Increment") FC80: C5C4 MOV R4,*R7 ; "MDE" switch ("Memory Data Enter") FC82: 04C4 CLR R4 ; "CLR" switch ; Code for run switch FC84: 1D0A SBO >000A ; switch "Run" light on FC86: 0380 RTWP ; return to interrupt point ; code for "Halt/SIE" switch FC88: 1D0E SBO >000E ; set "Single Instruction Execute" FC8A: 0380 RTWP ; Restart trap will occur after 2 instructions ; The second instruction executed will be an instruction from the program we interrupted. ; Pressing the HALT/SIE switch repetitively, you will trace the current program. ; this routine reads a row of 8 switches from the programmer panel FC8C: 1D0D SBO >000D ; start panel timer FC8E: 1F0A TB >000A ; wait for timer active bit to be set FC90: 16FE JNE >FC8E FC92: 3603 STCR R3,8 ; retrieve value FC94: 045B B *R11 ; Real boot routine ; ; We can load from several devices : MDU (Maintenance Diagnostics Unit, with a tape reader), ; ASR (a data terminal with optionnal tape reader), card reader, a tape unit with MT3200 controller, ; a double-sided floppy disk or a hard disk with WD900 controller (intelligent controllers on TI-LINE ; memory bus). ; ; tape units (MDU, ASR and MT3200) and card reader use some object code encoded with alphanumeric and ; hexadecimal characters. ; disks (double-sided floppies and hard-disk) use binary code. ; FC96: 0360 RSET ; RESET external peripherals FC98: 0203 FDFE LI R3,>FDFE ; address of the start-up routine we jump to - defaults to error routine FC9C: 0205 F7FE LI R5,>F7FE ; last word before system memory space FCA0: 020B FDFC LI R11,>FDFC ; pointer to the read routine used by the object code interpreter FCA4: C381 MOV R1,R14 ; if programmer panel enabled, TILINE peripheral to boot from FCA6: C3C2 MOV R2,R15 ; if programmer panel enabled, unit to load from ; simple memory test >F7FE -> >0000 FCA8: C555 MOV *R5,*R5 ; try to read and write current word FCAA: 0645 DECT R5 FCAC: 18FD JOC >FCA8 ; loop until we wrap around to >FFFE ; now real boot FCAE: 1D0A SBO >000A ; switch "Run" light on FCB0: 1F0E TB >000E ; this bit must tell a MDU is present FCB2: 1302 JEQ >FCB8 ; jump if not present FCB4: 04C0 CLR R0 FCB6: 102B JMP >FD0E ; boot from the MDU ? FCB8: C000 MOV R0,R0 ; read boot device type (defaults to -1) FCBA: 1139 JLT >FD2E ; boot from TILINE tape or disk device (FD1000, hard disk...) FCBC: 020C 0040 LI R12,>0040 ; device address >020 : card reader FCC0: C000 MOV R0,R0 FCC2: 1605 JNE >FCCE ; skip if card reader FCC4: 04CC CLR R12 ; device address >000 : 733 ASR FCC6: 1D09 SBO >0009 FCC8: 1D0A SBO >000A FCCA: 3220 FDF4 LDCR @>FDF4,8 ; effectively writes >11 FCCE: C000 MOV R0,R0 FCD0: 131E JEQ >FD0E ; skip if ASR FCD2: 1109 JLT >FCE6 ; skip if TILINE tape unit FCD4: 1F07 TB >0007 ; set up card reader at CRU address >020 FCD6: 13FE JEQ >FCD4 FCD8: 1F01 TB >0001 FCDA: 13FE JEQ >FCD8 FCDC: 1E0F SBZ >000F FCDE: 1F07 TB >0007 FCE0: 16FE JNE >FCDE FCE2: 1D0F SBO >000F FCE4: 1014 JMP >FD0E ; entry point to boot from TILINE tape unit (MT3200 controller or equivalent) FCE6: C183 MOV R3,R6 ; save R3, R5 FCE8: C285 MOV R5,R10 FCEA: 04C0 CLR R0 ; meaningless FCEC: 04C1 CLR R1 ; meaningless FCEE: 04C2 CLR R2 ; read offset = 0 (read record from the beginning) FCF0: 0203 0050 LI R3,>0050 ; char count = >0050 (max record lenght = 80 chars) ; It seems that we cannot have more than 80 bytes of code ! FCF4: 04C4 CLR R4 ; load at address 0 FCF6: 0205 0400 LI R5,>0400 ; >4 : read binary forward command FCFA: E14F SOC R15,R5 ; set unit ID FCFC: 06A0 FF32 BL @>FF32 ; execute command on tape unit FD00: D920 FDD9 0050 MOVB @>FDD9,@>0050(R4) ; append carriage return after the data we read (@>FDD9 = >0D) FD06: C0C6 MOV R6,R3 ; restore R3, R5 FD08: C14A MOV R10,R5 FD0A: 020B FDFC LI R11,>FDFC ; pointer to the read routine used by the object code interpreter ; entry point to boot from MDU FD0E: 04C7 CLR R7 ; clear checksum ; object code interpreter ; ; ASR, MDU, MT3200 tapes and cards use object code, as described in the Model 990 Computer Programming ; Card. ; ; We receive characters from the boot device. These are interpreted as commands or as hexadecimal ; immediate operands. Note that we actually only use hexadecimal characters, and 'G','H',':'. ; ; Commands with 16-bit immediate (encoded in hexadecimal) : ; * '1' : Absolute Entry Address : boot routine address = IMM ; * '2' : Relocatable Entry Address : boot routine address = offset + IMM ; * '7' : Checksum : stops the machine if (sum of all data received since start of record) + IMM != 0 ; * '9' : Absolute Load Address : memory address pointer = IMM ; * 'A' : Relocatable Load Address : memory address pointer = offset + IMM ; * 'B' : Absolute Data : * (memory address pointer ++) = IMM ; * 'C' : Relocatable Data : * (memory address pointer ++) = offset + IMM ; * 'D' : Load Bias Or Offset : offset = IMM ; * 'E' : (no reference) : stop the machine ; ; Control commands (parameter-less) : ; * ':' : (no reference) : branch to boot routine address ; * 'F' : End Of Record : wait for next card to be inserted (does not really work) ; ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) : ; * '8' : Ignore Checksum Value : does nothing ; * 'J' : (no reference) ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) and 6-char symbol name : ; * '3', '4', '5', '6', 'G', 'H' (symbol-related commands) ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) and 8-char program name : ; * '0' : Program Start ; * 'I' : (no reference) ; FD10: 069B BL *R11 ; read command number in R10 from tape (range 0-19) FD12: D0AA FE18 MOVB @>FE18(R10),R2 ; read offset to routine in table FD16: 132C JEQ >FD70 ; handle 'F' command separately because it is parameter-less FD18: 0882 SRA R2,8 ; convert to signed 16-bit offset FD1A: C207 MOV R7,R8 ; save checksum FD1C: 0201 0004 LI R1,>0004 ; 4*4 = 16 bits to read FD20: 069B BL *R11 ; read hex digit (4 bits) FD22: 0A46 SLA R6,4 ; shift digits we have already read FD24: A18A A R10,R6 ; and insert new digit in R6 FD26: 0601 DEC R1 FD28: 16FB JNE >FD20 ; loop until we have read a 16-bit hex value FD2A: 0462 FD2A B @>FD2A(R2) ; jump to routine ; Boot from a tape/disk unit using MD900/MT3200 controller or equivalent on the TILINE bus ; ; The routine expects the unit mask to be in R15. FD2E: C10F MOV R15,R4 ; current unit mask : 1 (and only 1) bit must be set FD30: 0A44 SLA R4,4 FD32: 13D9 JEQ >FCE6 ; routine for tape unit FD34: 0460 FE86 B @>FE86 ; routine for disk unit ; entry point for '3', '4', '5', '6','G','H' ; read 6 additional characters and ignore them FD38: 0201 0006 LI R1,>0006 ; read 6 chars FD3C: 1015 JMP >FD68 ; entry point for 'A' ; add offset to R6, set address pointer FD3E: A189 A R9,R6 ; add offset to R6 (R9 set by 'D' command, defaults to >00A0) ; entry point for '9' ; set address pointer FD40: C146 MOV R6,R5 FD42: 10E6 JMP >FD10 ; next command ; entry point for 'C' ; add offset to R6, write two bytes FD44: A189 A R9,R6 ; entry point for 'B' ; write two bytes FD46: DD46 MOVB R6,*R5+ FD48: 06C6 SWPB R6 FD4A: DD46 MOVB R6,*R5+ FD4C: 10E1 JMP >FD10 ; entry point for '7' ; check checksum FD4E: A206 A R6,R8 FD50: 13DF JEQ >FD10 ; continue on if value matches checksum ; entry point for 'E' ; boot failure FD52: 046B 0002 B @>0002(R11) ; jump to >FDFE (IDLE) ; entry point for 'D' ; set bias/offset FD56: C246 MOV R6,R9 ; set bias/offset value FD58: 0249 FFFE ANDI R9,>FFFE ; convert to word address FD5C: 10D9 JMP >FD10 ; entry point for '2' ; add offset to R6, set boot routine address FD5E: A189 A R9,R6 ; entry point for '1' ; set boot routine address FD60: C0C6 MOV R6,R3 ; set boot routine address FD62: 10D6 JMP >FD10 ; entry point for '0','I' ; read 8 additionnal characters and ignore them FD64: 0201 0008 LI R1,>0008 ; read 8 chars FD68: 069B BL *R11 FD6A: 0601 DEC R1 FD6C: 16FD JNE >FD68 FD6E: 10D0 JMP >FD10 ; entry point for 'F' command (parameter-less) ; wait for next card to be inserted FD70: 069B BL *R11 FD72: 16FE JNE >FD70 ; wait for next card FD74: 10AC JMP >FCCE ; read routine ; Read ASCII character from 733 ASR located at >000, a MDU unit located at >FF0, a MT3200 tape unit ; on TILINE bus, or a card reader located at >020, and translate it to one hexadecimal number. ; The routine for the card reader includes Hollerith->ASCII code conversion. FD76: C000 MOV R0,R0 ; test device type flag FD78: 1327 JEQ >FDC8 ; jump if ASR FD7A: 112B JLT >FDD2 ; jump if MT3200 ; card reader located at >020 ; ; Read Hollerith code, and translate it to ASCII code, then hexadecimal number. ; Seems to set EQ flag if the card is not inserted and R10 contains 0. FD7C: 1F07 TB >0007 ; test whether card is inserted ? FD7E: 1622 JNE >FDC4 FD80: 1F0F TB >000F ; wait for next row of punch holes ? FD82: 16FC JNE >FD7C FD84: 340A STCR R10,16 ; read code ; ; Encoding : ; ; We use Hollerith code. It uses 12 lines (0-9 and 11-12), plus one synchro line. ; ; Line map : ; MSB LSB ; CRU bit : 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ; register bit : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; card line : ? 1 2 3 4 5 6 7 | 12 11 0 9 8 ? synchro ; ; line | may be a card sensor. ; ; Hollerith character codes (source : Model 990 Computer Programming Card) : ; ; Space : Blank & : 12 - : 11 0 : 0 ; 1 : 1 A/a : 12-1 J/j : 11-1 / : 0-1 ; 2 : 2 B/b : 12-2 K/k : 11-2 S/s : 0-2 ; 3 : 3 C/c : 12-3 L/l : 11-3 T/t : 0-3 ; 4 : 4 D/d : 12-4 M/m : 11-4 U/u : 0-4 ; 5 : 5 E/e : 12-5 N/n : 11-5 V/v : 0-5 ; 6 : 6 F/f : 12-6 O/o : 11-6 W/w : 0-6 ; 7 : 7 G/g : 12-7 P/p : 11-7 X/x : 0-7 ; 8 : 8 H/h : 12-8 Q/q : 11-8 Y/y : 0-8 ; 9 : 9 I/i : 12-9 R/r : 11-9 Z/z : 0-9 ; : : 2-8 [ : 12-2-8 ] : 11-2-8 \ : 0-2-8 ; # : 3-8 . : 12-3-8 $ : 11-3-8 , : 0-3-8 ; @ : 4-8 < : 12-4-8 * : 11-4-8 % : 0-4-8 ; ' : 5-8 ( : 12-5-8 ) : 11-5-8 _ : 0-5-8 ; = : 6-8 + : 12-6-8 ; : 11-6-8 > : 0-6-8 ; " : 7-8 ! : 12-7-8 ^ : 11-7-8 ? : 0-7-8 FD86: 04C0 CLR R0 FD88: 04CC CLR R12 FD8A: 092A SRL R10,2 FD8C: 04CD CLR R13 FD8E: 0204 000D LI R4,>000D ; 13 lines to test FD92: 091A SRL R10,1 ; test line FD94: 170B JNC >FDAC ; skip if line not punched FD96: D024 FE6B MOVB @>FE6B(R4),R0 ; read compatibility mask FD9A: 2700 CZC R0,R12 ; test ((R0 & ~R12) == R0) - this checks that the current line FD9C: 1304 JEQ >FDA6 ; is not incompatible with the lines we have interpreted so far FD9E: 0203 C001 LI R3,>C001 ; error code FDA2: 0460 FF9E B @>FF9E ; abort boot in error FDA6: B364 FE78 AB @>FE78(R4),R13 ; else, add offset associated with line FDAA: E300 SOC R0,R12 ; and update mask in R12 FDAC: 0604 DEC R4 FDAE: 15F1 JGT >FD92 ; test next line FDB0: 098D SRL R13,8 ; 8-bit -> 16-bit offset FDB2: D2AD FE2C MOVB @>FE2C(R13),R10 ; read ascii code in table FDB6: 098A SRL R10,8 ; convert to 16-bit value FDB8: C00A MOV R10,R0 FDBA: 020C 0040 LI R12,>0040 FDBE: 1F0F TB >000F FDC0: 13FE JEQ >FDBE ; wait for device ready ? FDC2: 1012 JMP >FDE8 ; goto character decode routine ; we jump there if no card is inserted (?) when reading from the card reader located at >020 FDC4: 828A C R10,R10 FDC6: 1019 JMP >FDFA ; read routine ; Read ASCII character from 733 ASR located at >000 or MDU unit located at >FF0, and translate it to ; one hexadecimal number. FDC8: 1F0C TB >000C ; wait for incoming character ? FDCA: 16FE JNE >FDC8 FDCC: 1E0C SBZ >000C FDCE: 35CA STCR R10,7 ; read 7-bit ASCII character FDD0: 1001 JMP >FDD4 FDD2: D2B4 MOVB *R4+,R10 ; read byte from memory (MT3200 is DMA driven) FDD4: 098A SRL R10,8 ; move MSB to LSB FDD6: 028A 000D CI R10,>000D ; carriage return ? (appended at end of MT3200 record) FDDA: 130F JEQ >FDFA ; if so return FDDC: 028A 005A CI R10,>005A ; greater than 'Z' ? FDE0: 15CA JGT >FD76 ; if so, ignore current char and read next char FDE2: 028A 0020 CI R10,>0020 ; control character (lower than ' ') ? FDE6: 11C7 JLT >FD76 ; if so, ignore current char and read next char FDE8: A1CA A R10,R7 ; update checksum FDEA: 022A FFD0 AI R10,>FFD0 ; substract >30 (numeric character -> numeric value) FDEE: 028A 000A CI R10,>000A FDF2: 1306 JEQ >FE00 ; jump to handler if it is ':' FDF4: 1102 JLT >FDFA ; if greater, it must be 'A'-'F' (or 'G', 'H'...) FDF6: 022A FFF9 AI R10,>FFF9 ; convert to hex value FDFA: 069B BL *R11 ; trick : return to the caller AND restore R11 to be >FDFC ; entry point for the routine which reads data from the boot device FDFC: 10BC JMP >FD76 FDFE: 0340 IDLE ; stop the machine ; entry point for the ':' command (parameter-less command) ; jump to external boot routine FE00: C000 MOV R0,R0 FE02: 1608 JNE >FE14 FE04: 1E0B SBZ >000B ; clean up the ASR status ? FE06: 1E0C SBZ >000C FE08: 0581 INC R1 FE0A: 16FE JNE >FE08 FE0C: 1F0C TB >000C FE0E: 13F8 JEQ >FE00 FE10: 1E09 SBZ >0009 FE12: 1E0D SBZ >000D FE14: 0360 RSET ; reset peripherals FE16: 0453 B *R3 ; jumps to boot routine specified by >1 or >2 command ; (jumps to >FDFE if no routine was specified) ; offset table for jumps in object code interpreter, used on >FD2A (offsets relative to >FD2A) FE18: 3A36 340E BYTE >FD64->FD2A,>FD60->FD2A,>FD5E->FD2A,>FD38->FD2A FE1C: 0E0E 0E22 BYTE >FD38->FD2A,>FD38->FD2A,>FD38->FD2A,>FD4E->FD2A FE20: E616 141C BYTE >FD10->FD2A,>FD40->FD2A,>FD3E->FD2A,>FD46->FD2A FE24: 1A2C 2E00 BYTE >FD44->FD2A,>FD56->FD2A,>FD52->FD2A,>00 FE28: 0E0E 3AE6 BYTE >FD38->FD2A,>FD38->FD2A,>FD64->FD2A,>FD10->FD2A ; table used for the 2nd step of the hollerith->ascii code conversion ; blank, 1, 2, 3, ..., 7 FE2C: 2031 3233 BYTE ' ','1','2','3' FE30: 3435 3637 BYTE '4','5','6','7' ; 0, 0-1, 0-2, ..., 0-7 FE34: 302F 5354 BYTE '0','/','S','T' FE38: 5556 5758 BYTE 'U','V','W','X' ; 11, 11-1, ..., 11-7 FE3C: 2D4A 4B4C BYTE '-','J','K','L' FE40: 4D4E 4F50 BYTE 'M','N','O','P' ; 12, 12-1, ..., 12-7 FE44: 2641 4243 BYTE '&','A','B','C' FE48: 4445 4647 BYTE 'D','E','F','G' ; 8, 9, 2-8, 3-8, ..., 7-8 FE4C: 3839 3A23 BYTE '8','9',':','#' FE50: 4027 3D22 BYTE '@',''','=','"' ; 0-8, 0-9, 0-2-8, 0-3-8, ..., 0-7-8 FE54: 595A 5C2C BYTE 'Y','Z','\',',' FE58: 255F 3E3F BYTE '%','_','>','?' ; 11-8, 11-9, 11-2-8, 11-3-8, ..., 11-7-8 FE5C: 5152 5D24 BYTE 'Q','R',']','$' FE60: 2A29 3B5E BYTE '*',')',';','^' ; 12-8, 12-9, 12-2-8, 12-3-8, ..., 12-7-8 FE64: 4849 5B2E BYTE 'H','I','[','.' FE68: 3C28 2B21 BYTE '<','(','+','!' ; table used for hollerith->ascii code conversion : ; it allows to detect impossible superposition. ; line order : 1 2 3 4 5 6 7 | 12 11 0 9 8 ; ; rules : ; * at most one punch in lines 1 2 3 4 5 6 7 and 9 (>01 mask) ; * lines 8 and 1 cannot be punched simulteanously (line 9 must be used instead) (>02 mask) ; * at most one punch in lines 0 11 12 (>04 mask) ; ; Note that the >08 mask is needed to prevent the program from rejecting character when the | line is ; punched. ; FE6C: 0301 0101 BYTE >03,>01,>01,>01 FE70: 0101 0108 BYTE >01,>01,>01,>08 FE74: 0404 0403 BYTE >04,>04,>04,>03 FE78: 02 BYTE >02 ; table used for the 1st step of the hollerith->ascii code conversion : ; it provides an offset associated with each line. ; line order : 1 2 3 4 5 6 7 | 12 11 0 9 8 FE79: 01 0203 BYTE >01,>02,>03 FE7C: 0405 0607 BYTE >04,>05,>06,>07 FE80: 0018 1008 BYTE >00,>18,>10,>08 FE84: 2120 BYTE >21,>20 ; boot from a disk unit attached to a WD900 disk controller (or equivalent) whose address is in R14 FE86: C14F MOV R15,R5 ; unit ID FE88: 020C FF32 LI R12,>FF32 FE8C: 0200 0700 LI R0,>0700 ; restore command FE90: 04C1 CLR R1 FE92: 069C BL *R12 ; execute command FE94: 04C0 CLR R0 ; store register command FE96: 04C1 CLR R1 FE98: 0203 0006 LI R3,>0006 ; command returns 6 bytes FE9C: 0204 0200 LI R4,>0200 ; free area in RAM FEA0: 069C BL *R12 FEA2: C2A4 0004 MOV @>0004(R4),R10 FEA6: 09BA SRL R10,11 ; keep number of track per cylinder (i.e. number of heads) FEA8: 0200 0400 LI R0,>0400 ; read unformatted FEAC: 04C1 CLR R1 ; cylinder 0 FEAE: 04C2 CLR R2 FEB0: 069C BL *R12 ; read current track/cylinder address, # of sectors per record, and sector length FEB2: C004 MOV R4,R0 ; >0200 : read data FEB4: D064 0002 MOVB @>0002(R4),R1 ; set the "sectors per records" field FEB8: C0E4 0004 MOV @>0004(R4),R3 ; count = sector lenght FEBC: 0A13 SLA R3,1 ; word count -> byte count FEBE: 069C BL *R12 ; (reads record #0) FEC0: C3E4 000E MOV @>000E(R4),R15 ; alternate boot program track address FEC4: 890F 0024 C R15,@>0024(R4) ; compare with normal program track address FEC8: 130D JEQ >FEE4 FECA: C924 0024 000E MOV @>0024(R4),@>000E(R4) ; replace alternate boot program, with normal one ; so alternate program will be loaded only once FED0: 0200 0300 LI R0,>0300 ; write data FED4: 069C BL *R12 ; write record back FED6: C824 001C 00A0 MOV @>001C(R4),@>00A0 ; use alternate load point FEDC: C824 001E 00A2 MOV @>001E(R4),@>00A2 ; and alternate length FEE2: 1006 JMP >FEF0 FEE4: C824 0018 00A0 MOV @>0018(R4),@>00A0 ; use normal load point FEEA: C824 001A 00A2 MOV @>001A(R4),@>00A2 ; use normal length FEF0: 0200 0400 LI R0,>0400 ; read unformatted FEF4: 0203 0006 LI R3,>0006 ; command returns 6 bytes FEF8: 06A0 FF26 BL @>FF26 ; compute cylinder/head address from track address in R15 FEFC: 069C BL *R12 FEFE: C064 0002 MOV @>0002(R4),R1 ; set format & sector according to value returned by controller FF02: 0200 0200 LI R0,>0200 ; >0200 : read data FF06: C0E0 00A2 MOV @>00A2,R3 ; program length FF0A: 0204 00A0 LI R4,>00A0 ; free area in RAM ? FF0E: 06A0 FF26 BL @>FF26 FF12: C3E0 00A0 MOV @>00A0,R15 ; program load point FF16: 069C BL *R12 ; read boot program FF18: 0200 ABC0 LI R0,>ABC0 ; magical value ? FF1C: C04E MOV R14,R1 ; boot device address FF1E: 04C2 CLR R2 FF20: D085 MOVB R5,R2 ; unit ID FF22: 0360 RSET ; Reset for things to be cleaner FF24: 045F B *R15 ; jump to boot program ; compute cylinder & head address from "flat" track address ; input : ; R10 = number of heads ; R15 = track address ; returns : ; R2 = cylinder address ; R0 |= head address FF26: C24F MOV R15,R9 FF28: 04C8 CLR R8 FF2A: 3E0A DIV R10,R8 ; compute R15/R10 FF2C: C088 MOV R8,R2 ; R2 = quotient : cylinder address FF2E: E009 SOC R9,R0 ; R0 LSB = remainder : head address FF30: 045B B *R11 ; execute some command on a WD900/WT3200 controller ; R0 -> W1 : command and surface register (WD900) ; R1 -> W2 : format and sector (MSByte : sectors per record ; LSByte : sector number) (WD900) ; R2 -> W3 : cylinder address (cylinder number) (WD900) / read offset (WT3200) ; R3 -> W4 : count (length to read/write) ; R4 -> W5 : address (destination/source address to read/write from, 16 LSBits) ; R5 -> W6 : WD900 : select and address (unit selection, 1 bit per unit, in LOW nibble of MSByte, and ; 4 MSBits of address in low nibble of LSByte) ; WT3200 : command and transport select (unit selection, 1 bit per unit, in HIGH nibble ; of MSByte, command in high nibble of LSByte, and 4 MSBits of address in low nibble of ; LSByte) ; ; R14 = controller address ; ; cf 990 Handbook, 5-23, page 188, and WD900/MT3200 general description, chapter 3 ; FF32: 020D 0005 LI R13,>0005 ; retry count FF36: C1CE MOV R14,R7 ; TILINE device address FF38: C227 000E MOV @>000E(R7),R8 FF3C: 1101 JLT >FF40 FF3E: 10FB JMP >FF36 ; wait for IDLE controller status bit to be cleared FF40: C9C5 000C MOV R5,@>000C(R7) FF44: C5D7 MOV *R7,*R7 FF46: 11FC JLT >FF40 FF48: 04F7 CLR *R7+ ; disc status FF4A: CDC0 MOV R0,*R7+ FF4C: CDC1 MOV R1,*R7+ FF4E: CDC2 MOV R2,*R7+ FF50: CDC3 MOV R3,*R7+ FF52: CDC4 MOV R4,*R7+ FF54: CDC5 MOV R5,*R7+ FF56: 04D7 CLR *R7 FF58: C217 MOV *R7,R8 FF5A: 1101 JLT >FF5E FF5C: 10FD JMP >FF58 ; wait for IDLE controller status bit to be cleared FF5E: C1C5 MOV R5,R7 FF60: 0247 F000 ANDI R7,>F000 ; 4 MSBits select unit on WT3200, and are unused on WD900 FF64: 1604 JNE >FF6E ; skip if we are using a tape unit FF66: C1DE MOV *R14,R7 ; disk status FF68: 0247 4000 ANDI R7,>4000 FF6C: 16FC JNE >FF66 ; wait for NR (Not Ready) status bit to be cleared FF6E: 0248 01FF ANDI R8,>01FF ; test all individual error bits in controller status FF72: 1602 JNE >FF78 ; jump on error FF74: 0700 SETO R0 FF76: 045B B *R11 ; normal return ; error handler : FF78: C1C5 MOV R5,R7 FF7A: 0247 F000 ANDI R7,>F000 FF7E: 1303 JEQ >FF86 ; jump if disk unit FF80: 0203 D001 LI R3,>D001 ; error code FF84: 100C JMP >FF9E ; stop in error FF86: 0288 0001 CI R8,>0001 ; check unit error in controller status FF8A: 1604 JNE >FF94 ; if set, means an error condition is set in disk status FF8C: C21E MOV *R14,R8 ; read disk status FF8E: 0248 E000 ANDI R8,>E000 ; test bits OL, NR, WP (Off-line, not-ready, write-protect) FF92: 16CF JNE >FF32 ; restarts everything ! (must be a bug...) FF94: 060D DEC R13 ; decrement retry count FF96: 15CF JGT >FF36 ; try again FF98: 0203 D002 LI R3,>D002 ; error code FF9C: 1000 JMP >FF9E ; stop in error ; error stop ; we jump to this routine when boot fails ; display R3 for diagnostics purpose, light the fail LED, and stop. FF9E: 020C 1FE0 LI R12,>1FE0 FFA2: 1D0B SBO >000B FFA4: 3203 LDCR R3,8 FFA6: 3220 0087 LDCR @>0087,8 FFAA: 0340 IDLE ; spare room FFAC: 0000 DATA >0000 FFAE: 0000 DATA >0000 FFB0: 0000 DATA >0000 FFB2: 0000 DATA >0000 FFB4: 0000 DATA >0000 FFB6: 0000 DATA >0000 FFB8: 0000 DATA >0000 FFBA: 0000 DATA >0000 FFBC: 0000 DATA >0000 FFBE: 0000 DATA >0000 FFC0: 0000 DATA >0000 FFC2: 0000 DATA >0000 FFC4: 0000 DATA >0000 FFC6: 0000 DATA >0000 FFC8: 0000 DATA >0000 FFCA: 0000 DATA >0000 FFCC: 0000 DATA >0000 FFCE: 0000 DATA >0000 FFD0: 0000 DATA >0000 FFD2: 0000 DATA >0000 FFD4: 0000 DATA >0000 FFD6: 0000 DATA >0000 FFD8: 0000 DATA >0000 FFDA: 0000 DATA >0000 FFDC: 0000 DATA >0000 FFDE: 0000 DATA >0000 FFE0: 0000 DATA >0000 FFE2: 0000 DATA >0000 FFE4: 0000 DATA >0000 FFE6: 0000 DATA >0000 FFE8: 0000 DATA >0000 FFEA: 0000 DATA >0000 FFEC: 0000 DATA >0000 FFEE: 0000 DATA >0000 FFF0: 0000 DATA >0000 FFF2: 0000 DATA >0000 FFF4: 0000 DATA >0000 ; pointers to routines FFF6: FC9C DATA >FC9C ; boot loader FFF8: FC96 DATA >FC96 ; ditto FFFA: FD0E DATA >FD0E ; boot loader for MDU (?) ; LOAD vector FFFC: 0080 FC00 DATA >0080,>FC00