home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.whtech.com
/
ftp.whtech.com.tar
/
ftp.whtech.com
/
ti-990
/
TI990_4.txt
< prev
Wrap
Text File
|
2006-10-19
|
32KB
|
771 lines
; TI990/4 LOAD ROMs disassembly
;
; This ROM could be the item listed as 945121-0002 in 990 Handbook, 6-11 (page 218).
;
;General background :
; These ROMs contain the handler for the LOAD/RESTART interrupt. Provided the board configuration is
; correct, this interrupt is called at start-up (instead of RESET), and we execute the boot loader.
;
; This interrupt can also be triggered by the programmer panel, and there is code to handle the panel
; functions.
;
;Description :
; Include a CPU test ROM set at >FC00, and a LOAD/RESTART ROM with programmer panel handling and
; boot strap code at >FE00. Note that the LOAD ROM calls the test routine in the CPU test ROM.
;
; The first ROM should be interesting for people who want to test an emulator.
; The second ROM is a source of documentation on the boot process, and the programmer panel.
;
; If you want a starting point, you can have a look at the LOAD vector located at >FFFC.
; The LOAD routine starts at >FE00.
;
;Notes :
; * The code assumes 32 (?) bytes of RAM are available at >F800.
; * The code can ignore the programmer panel provided the proper CRU bit is set, which allows the use
; of programmer-panel-less TI990/4.
; * The boot strap loader boots from a 733 ASR terminal at CRU address >000. Though, if you write a
; non-zero value to @>F800 (using the programmer panel), the ROM should boot from a Card Reader
; located at CRU address >020. The loader seems to support booting from a MDU (Maintenance
; Diagnostics Unit) when such a MDU is connected in the programmer panel slot.
; (Standard CRU map reference : 990 computer family systems handbook, H-2, page 346)
; * A description of the 733 ASR terminal is given in the 990 handbook. Among other things, there is
; an optionnal tape unit, which could be actually used by the boot process. Unfortunately, I have no
; documentation on the ASR CRU interface.
;
;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/24
;
; revision history :
; 2000/04/24 : clarified a few things with MDU support
; 2000/02/20 : fixed a few comments, documented object code and Hollerith code better
; 2000/02/16 : fixed a few comments, replaced DW and DB with standard DATA and BYTE directives
; 2000/01/31 : fixed some ambiguous comments, documented programmer panel better, found out actual
; identity of boot devices
; 2000/01/28 : initial release
; Here we have a cpu test ROM
; test routine entry point
; preserves R0.
; jumps to the boot routine on exit
FC00: 1D0B SBO >000B ; switch "Fault" light on
FC02: 0208 7FFF LI R8,>7FFF
FC06: 05C8 INCT R8
FC08: 1933 JNO >FC70 ; stop if no overflow
FC0A: C040 MOV R0,R1
FC0C: C008 MOV R8,R0
FC0E: 0858 SRA R8,5
FC10: 0918 SRL R8,1
FC12: 0808 SRA R8,0
FC14: C001 MOV R1,R0 ; restore R0
FC16: 0288 3F00 CI R8,>3F00
FC1A: 162A JNE >FC70 ; stop if different from the value expected
FC1C: 0704 SETO R4
FC1E: 0244 5555 ANDI R4,>5555
FC22: 06A0 FC36 BL @>FC36 ; this should clear R4, or stop if it fails
FC26: 0264 5555 ORI R4,>5555
FC2A: 06A0 FC36 BL @>FC36
FC2E: 0300 0001 LIMI >0001 ; effectively sets least significant bit in ST
FC32: 0420 FC4E BLWP @>FC4E ; jump to >FC40
; should be called with R4 == >5555
FC36: 0264 AAAA ORI R4,>AAAA
FC3A: 0584 INC R4
FC3C: 1619 JNE >FC70 ; stop if R4 != 0
FC3E: 045B B *R11
; continue on...
FC40: 02CB STST R11
FC42: 081B SRA R11,1 ; test LSBit in ST
FC44: 1715 JNC >FC70 ; stop if not set
FC46: 04CF CLR R15 ; -> clear ST
FC48: 020E FC52 LI R14,>FC52 ; actual jump address
FC4C: 0380 RTWP
FC4E: F7EC FC40 DATA >F7EC,>FC40 ; BLWP vector
; continue on... This gets tricky :-) .
FC52: 02C7 STST R7
FC54: C047 MOV R7,R1
FC56: 160C JNE >FC70 ; stop if ST not clear
FC58: C081 MOV R1,R2
FC5A: 0B52 SRC R2,5 ;
FC5C: 06C2 SWPB R2 ; effectively rotate R2 3 bits left
FC5E: C2C2 MOV R2,R11
FC60: 074B ABS R11
FC62: C0C2 MOV R2,R3
FC64: 0A13 SLA R3,1 ; test R2 sign bit
FC66: 1709 JNC >FC7A ; start if R2 is positive
FC68: 054B INV R11 ; R11 = ~R11
FC6A: 808B C R11,R2 ; so R11 = R2-1
FC6C: 1B7A JH >FD62 ; stop the machine if R11>R2
FC6E: 1101 JLT >FC72 ; huh ??? what if R2 == 0x8000 ? This must be a bug !
FC70: 10FF JMP >FC70 ; stop everything
FC72: 82C2 C R2,R11
FC74: 1A76 JL >FD62 ; we still have R11 = R2-1...
FC76: 05CB INCT R11
FC78: 060B DEC R11 ; now R11 == R2
; we jump here when R2 >= 0
FC7A: 808B C R11,R2
FC7C: 1672 JNE >FD62
FC7E: C0C1 MOV R1,R3
FC80: A0C2 A R2,R3
FC82: C101 MOV R1,R4
FC84: 0504 NEG R4
FC86: 6102 S R2,R4
FC88: 0504 NEG R4
FC8A: 9103 CB R3,R4 ; we should have R3==R4
FC8C: 1B6A JH >FD62 ; stop if logically higher
FC8E: 1201 JLE >FC92 ; jump there if OK
FC90: 1068 JMP >FD62 ; stop if arithmetically greater
FC92: 9820 F807 F809 CB @>F807,@>F809 ; compare R3 MSB and R4 MSB
FC98: 1664 JNE >FD62 ; stop if different
FC9A: 20C4 COC R4,R3 ; (R3 & R4) == R3 ?
FC9C: 1662 JNE >FD62
FC9E: 0544 INV R4
FCA0: 24C4 CZC R4,R3 ; (R3 & ~R4) == R3 ?
FCA2: 165F JNE >FD62
FCA4: 0544 INV R4
FCA6: 7103 SB R3,R4 ; result 0 in R4 MSB
FCA8: 115C JLT >FD62
FCAA: 165B JNE >FD62
FCAC: 7820 F807 F809 SB @>F807,@>F809 ; substract LSB
FCB2: 1657 JNE >FD62
FCB4: D102 MOVB R2,R4 ; move R2 MSB
FCB6: D820 F805 F809 MOVB @>F805,@>F809 ; move R2 LSB
FCBC: B820 F803 F809 AB @>F803,@>F809 ; add R1 LSB
FCC2: 1702 JNC >FCC8
FCC4: 0224 0100 AI R4,>0100 ; adjust carry if needed
FCC8: B101 AB R1,R4 ; add R1 MSB
FCCA: 8103 C R3,R4 ; we should still have R3 = R1+R2, too...
FCCC: 164A JNE >FD62
FCCE: 0583 INC R3
FCD0: 0583 INC R3
FCD2: 80C4 C R4,R3
FCD4: 1346 JEQ >FD62
FCD6: 1545 JGT >FD62
FCD8: 0643 DECT R3
FCDA: 8103 C R3,R4
FCDC: 1642 JNE >FD62
FCDE: C143 MOV R3,R5
FCE0: C185 MOV R5,R6
FCE2: C1C5 MOV R5,R7
FCE4: 06C7 SWPB R7 ; swap bytes (8-bit rotate)
FCE6: 0985 SRL R5,8
FCE8: 0A86 SLA R6,8
FCEA: E185 SOC R5,R6 ; swap bytes with another method
FCEC: 81C6 C R6,R7
FCEE: 1639 JNE >FD62
FCF0: 0B86 SRC R6,8 ; swap bytes again
FCF2: 80C6 C R6,R3 ; should equate the original value
FCF4: 1636 JNE >FD62
; now, multiply R1 and R2 with custom code, then check MPY gives the same result
FCF6: 020A 0010 LI R10,>0010 ; 16 bits to test
FCFA: 04CB CLR R11
FCFC: 04C8 CLR R8
FCFE: 04C7 CLR R7
FD00: C182 MOV R2,R6
FD02: C141 MOV R1,R5
FD04: 0815 SRA R5,1 ; if R5 LSB is set
FD06: 1704 JNC >FD10
FD08: A2C6 A R6,R11 ; add R7:R6 to R8:R11
FD0A: 1701 JNC >FD0E
FD0C: 0588 INC R8
FD0E: A207 A R7,R8
FD10: 0A17 SLA R7,1 ; shift R7:R6
FD12: 0A16 SLA R6,1
FD14: 1801 JOC >FD18
FD16: 1001 JMP >FD1A
FD18: 0587 INC R7
FD1A: 060A DEC R10 ; loop
FD1C: 16F3 JNE >FD04
FD1E: C0C1 MOV R1,R3
FD20: 38E0 F804 MPY @>F804,R3 ; = MPY R2,R3
FD24: 8203 C R3,R8 ; compare MSWord
FD26: 161D JNE >FD62
FD28: 82C4 C R4,R11 ; compare LSWord
FD2A: 161B JNE >FD62
; now, test DIVide
FD2C: 8081 C R1,R2
FD2E: 1408 JHE >FD40
FD30: A101 A R1,R4 ; if R1 < R2, add R1 to MSW (R4)
FD32: 1702 JNC >FD38
FD34: 6101 S R1,R4 ; if carry, revert to normal method
FD36: 1004 JMP >FD40 ; (otherwise, there might be an overflow when executing DIV)
FD38: 3CC2 DIV R2,R3
FD3A: 04A0 FD34 X @>FD34 ; = S R1,R4 (remainder should be R1, and is fixed to be 0)
FD3E: 1003 JMP >FD46
FD40: 3CE0 F804 DIV @>F804,R3 ; compute R3:R4 / R2
FD44: C104 MOV R4,R4 ; test the remainder
FD46: 160D JNE >FD62 ; should be 0
; now test parity ST bit
FD48: D181 MOVB R1,R6
FD4A: 0207 0008 LI R7,>0008 ; 8 bits to test
FD4E: 04C8 CLR R8
FD50: 0A16 SLA R6,1
FD52: 1701 JNC >FD56
FD54: 0588 INC R8 ; count bits
FD56: 0607 DEC R7
FD58: 15FB JGT >FD50 ; loop if some bits left
FD5A: 0B18 SRC R8,1 ; test parity
FD5C: 1703 JNC >FD64
FD5E: D041 MOVB R1,R1 ; should be odd parity
FD60: 1C03 JOP >FD68
FD62: 10FF JMP >FD62
FD64: B1C1 AB R1,R7 ; R7 == 0 from previous loop (remember ?)
FD66: 1CFD JOP >FD62 ; should be even parity
FD68: C142 MOV R2,R5
FD6A: 4142 SZC R2,R5 ; R5 = R5 & ~R2
FD6C: 16FA JNE >FD62 ; result should be 0
FD6E: A142 A R2,R5 ; hence R5 = R2
FD70: 5142 SZCB R2,R5 ; R2 MSB & R5 MSB
FD72: 16F7 JNE >FD62
FD74: 5820 F805 F80B SZCB @>F805,@>F80B ; R2 LSB & R5 LSB
FD7A: 16F3 JNE >FD62
FD7C: 070B SETO R11 ; R11 = >FFFF
FD7E: 42C2 SZC R2,R11 ; R11 = R11 & ~R2
FD80: 13F0 JEQ >FD62 ; obviously, R2 is assumed to be non-zero
FD82: F141 SOCB R1,R5 ; R5 should be 0 from previous computation.
FD84: 06C5 SWPB R5
FD86: F160 F803 SOCB @>F803,R5 ; bit-wise OR with R1 LSB
FD8A: 0B85 SRC R5,8 ; so R5 = R1
FD8C: 6141 S R1,R5
FD8E: 16E9 JNE >FD62
FD90: 0581 INC R1 ; increment R1
FD92: 0281 FFC0 CI R1,>FFC0
FD96: 1B0A JH >FDAC ; if R1 > >FFC0, bail out
FD98: C181 MOV R1,R6
FD9A: 0204 0013 LI R4,>0013
FD9E: 3D44 DIV R4,R5 ; effectively computes R6 / 19 (R5 is still 0, remember ?)
FDA0: C186 MOV R6,R6 ; test the remainder
FDA2: 1602 JNE >FDA8
FDA4: 0221 03E8 AI R1,>03E8 ; add 1000 to R1 if R1 is multiple of 19
FDA8: 0460 FC58 B @>FC58 ; and loop
; this effectively results into testing a sequence :
; 0,1,...,18,1019,1020,1021,1022,1023,1024,1025,2026,2027,2028,...,2032,3033,...,65467,...,65472.
; The next value is 65473, which is greater than >FFC0 (65472), so we exit the routine at this point.
; Looks like a decent way to shuffle values.
; memory test
; we use some nasty self-compiling code
FDAC: 070A SETO R10
FDAE: 0202 02E0 LI R2,>02E0 ; LWPI
FDB2: 04C3 CLR R3 ; >0000
FDB4: 0204 0460 LI R4,>0460 ; B @
FDB8: 0205 FDD0 LI R5,>FDD0 ; >FDD0
; loop start
FDBC: 0283 F800 CI R3,>F800
FDC0: 131A JEQ >FDF6 ; don't test system area >F800->FFFF
FDC2: 02A6 STWP R6
FDC4: 8183 C R3,R6 ; do not overwrite our workspace.
FDC6: 1602 JNE >FDCC ; geez, the previous test already ensured this !
FDC8: 0223 0020 AI R3,>0020
FDCC: C053 MOV *R3,R1 ; save future R0 register
FDCE: 0442 B R2 ; this emulates missing "LWP R3" instruction
FDD0: 2820 F814 XOR @>F814,R0 ; XOR old R10 with new R0
FDD4: 02E0 F800 LWPI >F800 ; restore old WP
FDD8: 0541 INV R1 ; R1 = ~R1
FDDA: C1C1 MOV R1,R7
FDDC: 84C1 C R1,*R3 ; should give the same result as R0 = R0 ^ >FFFF
FDDE: 1606 JNE >FDEC
FDE0: 0553 INV *R3 ; Restore memory location
FDE2: 2873 XOR *R3+,R1 ; result should be >FFFF
FDE4: 0581 INC R1
FDE6: 13EA JEQ >FDBC ; try next word if OK
FDE8: 0643 DECT R3 ; else restore R3
FDEA: 0547 INV R7 ; restore value read in RAM
FDEC: C183 MOV R3,R6
FDEE: 0A36 SLA R6,3 ; if the address in on a 8kb-boundary, we must only have left
FDF0: 1302 JEQ >FDF6 ; the RAM area, so we continue on (?)
FDF2: C087 MOV R7,R2
FDF4: 0340 IDLE ; else stop the machine
FDF6: C060 FFF8 MOV @>FFF8,R1 ; read pointer to boot routine
FDFA: 0451 B *R1 ; and jump there
; entry point for self-test routine
FDFC: 0460 FC00 B @>FC00
; Here, we have programmer panel handling and boot strap code.
; LOAD vector entry point :
FE00: 020C 1FE0 LI R12,>1FE0 ; load programmer panel CRU base address
FE04: 0221 6700 AI R1,>6700 ; test for magical value (>9900)
FE08: 1602 JNE >FE0E ; jump if not found
FE0A: 1D0A SBO >000A ; switch "Run" light on
FE0C: 0450 B *R0 ; jump to routine pointed by R0
FE0E: 0209 00A0 LI R9,>00A0
FE12: 04C0 CLR R0
FE14: 1F0B TB >000B ; test if programmer panel present and active
FE16: 13F2 JEQ >FDFC ; if panel inactive, silently jump to CPU self-test
FE18: C08E MOV R14,R2 ; else copy old PC to display register
; programmer panel scan : we have 4 rows of 8 switches
; 16 switches allow to toggle the display in R2.
; the 16 other switches allow to access programmer panel functions.
;
; register conventions here :
; R2 = data register
; R7 = memory address register
; R13 = WP
; R14 = PC
; R15 = ST
; keyscan loop start
FE1A: 3202 LDCR R2,8 ; display data register MSB
FE1C: 3220 F805 LDCR @>F805,8 ; display data register LSB
FE20: 0205 FE7C LI R5,>FE7C
FE24: 0695 BL *R5 ; read current 8 switches from programmer panel to R1 MSB
FE26: 16FE JNE >FE24 ; wait for all switches to be released
FE28: 0695 BL *R5
FE2A: 16FC JNE >FE24 ; test again to fix switch bounce problems
FE2C: 04C1 CLR R1
FE2E: 1D08 SBO >0008 ; "Increment scan" bit -> select another row of switches
FE30: 0695 BL *R5
FE32: 13FD JEQ >FE2E ; if no switch pressed, scan next row
FE34: 0695 BL *R5
FE36: 13FB JEQ >FE2E ; fixes switch bounce problems
FE38: 1F09 TB >0009 ; scan count bit 0 -> is current switch row number odd or even ?
FE3A: 1601 JNE >FE3E
FE3C: 06C1 SWPB R1 ; if odd, we read last 8 switches in 16 switches, so we rotate 8 bits.
FE3E: 1F08 TB >0008 ; scan count bit 1 -> is this command switches or data switches ?
FE40: 1302 JEQ >FE46 ; command switches -> jump to interpret command
FE42: 2881 XOR R1,R2 ; data switches -> toggle the data displayed as requested
FE44: 10EA JMP >FE1A ; update display and go back to scan routine
; command interpreter for programmer panel
FE46: 04C5 CLR R5
FE48: 05C5 INCT R5
FE4A: 0A11 SLA R1,1
FE4C: 17FD JNC >FE48 ; count first bit set to 1 in R1, i.e. first switch pressed
FE4E: 04A5 FE52 X @>FE52(R5) ; execute command as needed.
FE52: 10E3 JMP >FE1A ; update display and go back to scan routine if we have not jumped away
; The jump offsets in the following table must be >FE52-relative, since this is the value of PC when X
; executes the instruction.
FE54: 1013 JMP *+>FE78->FE52 ; "Halt/SIE" switch
FE56: 1011 JMP *+>FE74->FE52 ; "Run" switch
FE58: 0360 RSET ; "Reset" switch
FE5A: 10D5 JMP *+>FDFC->FE52 ; "Load" switch
FE5C: C08D MOV R13,R2 ; "Display WP" switch
FE5E: C08E MOV R14,R2 ; "Display PC" switch
FE60: C08F MOV R15,R2 ; "Display ST" switch
FE62: C087 MOV R7,R2 ; "Display MA" switch
FE64: C342 MOV R2,R13 ; "Enter WP" switch
FE66: C382 MOV R2,R14 ; "Enter PC" switch
FE68: C3C2 MOV R2,R15 ; "Enter ST" switch
FE6A: C1C2 MOV R2,R7 ; "Enter MA" switch
FE6C: C097 MOV *R7,R2 ; "MDD" switch ("Memory Data Display")
FE6E: 05C7 INCT R7 ; "MAI" switch ("Memory Address Increment")
FE70: C5C2 MOV R2,*R7 ; "MDE" switch ("Memory Data Enter")
FE72: 04C2 CLR R2 ; "CLR" switch
; Code for run switch
FE74: 1D0A SBO >000A ; switch "Run" light on
FE76: 0380 RTWP
; code for "Halt/SIE" switch
FE78: 1D0E SBO >000E ; set "Single Instruction Execute"
FE7A: 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 read a row of 8 switches from the programmer panel
FE7C: 1D0D SBO >000D ; start panel timer
FE7E: 1F0A TB >000A ; wait for timer active bit to be set
FE80: 16FE JNE >FE7E
FE82: 3601 STCR R1,8 ; retrieve value
FE84: 045B B *R11
; Real boot routine, called after the CPU self-test
;
; We boot from a 733 ASR terminal located at CRU address >000.
;
; Note that when R0 is non-zero, we boot from a card reader located at CRU address >020 instead, but
; this possibility is never used since R0 is cleared by the LOAD vector.
; This must be a debug mode, which should be enabled with the programmer panel.
;
; The boot code is encoded as 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
;
; 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)
;
FE86: 0360 RSET ; RESET external peripherals
FE88: 0203 FFCA LI R3,>FFCA ; address of the start-up routine we jump to - defaults to error routine
FE8C: 020B FFC8 LI R11,>FFC8 ; points routine which fetches data from the boot device
FE90: 0205 F7FE LI R5,>F7FE ; last word before our small system memory area
FE94: C555 MOV *R5,*R5 ; try to read and write current word
FE96: 0645 DECT R5 ; previous word
FE98: 18FD JOC >FE94 ; loop until we wrap around to >FFFE
FE9A: 1D0A SBO >000A ; switch "Run" light on
FE9C: 1F0E TB >000E ; this bit must tell a MDU is present
FE9E: 1613 JNE >FEC6 ; boot from the MDU ?
FEA0: 020C 0040 LI R12,>0040
FEA4: C000 MOV R0,R0 ; R0 was cleared on line >FE12 (!) - can be set with the programmer pannel to use the card reader
FEA6: 1605 JNE >FEB2 ; skip if card reader
FEA8: 04CC CLR R12 ; device address >000 : 733 ASR
FEAA: 1D09 SBO >0009 ; set-up device
FEAC: 1D0A SBO >000A
FEAE: 3220 FFC0 LDCR @>FFC0,8 ; effectively writes >11
FEB2: C000 MOV R0,R0
FEB4: 1308 JEQ >FEC6 ; skip if ASR
FEB6: 1F07 TB >0007 ; set up card reader at CRU address >020
FEB8: 13FE JEQ >FEB6
FEBA: 1F01 TB >0001
FEBC: 13FE JEQ >FEBA
FEBE: 1E0F SBZ >000F
FEC0: 1F07 TB >0007
FEC2: 16FE JNE >FEC0
FEC4: 1D0F SBO >000F
FEC6: 04C7 CLR R7 ; clear checksum
FEC8: 069B BL *R11 ; read command number in R10 from boot device (range 0-19)
FECA: D0AA FFE4 MOVB @>FFE4(R10),R2 ; read routine offset in table
FECE: 1327 JEQ >FF1E ; handle 'F' command separately because it is parameter-less
FED0: 0882 SRA R2,8 ; convert to signed 16-bit offset
FED2: C107 MOV R7,R4 ; save checksum
FED4: 0201 0004 LI R1,>0004 ; 4*4 = 16 bits to read
FED8: 069B BL *R11 ; read hex digit (4 bits)
FEDA: 0A46 SLA R6,4 ; shift digits we have already read
FEDC: A18A A R10,R6 ; and insert new digit in R6
FEDE: 0601 DEC R1
FEE0: 16FB JNE >FED8 ; loop until we have read a 16-bit hex value
FEE2: 0462 FEE2 B @>FEE2(R2) ; jump to routine
; entry point for '3', '4', '5', '6','G','H'
; read 6 additional characters and ignore them
FEE6: 0201 0006 LI R1,>0006 ; read 6 chars
FEEA: 1015 JMP >FF16
; entry point for 'A'
; add offset to R6, set address pointer
FEEC: A189 A R9,R6 ; add offset to R6 (R9 set by 'D' command, defaults to >00A0)
; entry point for '9'
; set address pointer
FEEE: C146 MOV R6,R5 ; set address pointer
FEF0: 10EB JMP >FEC8 ; continue on ?
; entry point for 'C'
; add offset to R6, write two bytes
FEF2: A189 A R9,R6
; entry point for 'B'
; write two bytes
FEF4: DD46 MOVB R6,*R5+
FEF6: 06C6 SWPB R6
FEF8: DD46 MOVB R6,*R5+
FEFA: 10E6 JMP >FEC8
; entry point for '7'
; check checksum
FEFC: A106 A R6,R4
FEFE: 13E4 JEQ >FEC8 ; continue on if value matches checksum
; entry point for 'E'
; boot failure
FF00: 046B 0002 B @>0002(R11) ; jump to >FFCA (IDLE)
; entry point for 'D'
; set bias/offset
FF04: C246 MOV R6,R9 ; set bias/offset value
FF06: 0249 FFFE ANDI R9,>FFFE ; convert to word address
FF0A: 10DE JMP >FEC8
; entry point for '2'
; add offset to R6, set boot routine address
FF0C: A189 A R9,R6
; entry point for '1'
; set boot routine address
FF0E: C0C6 MOV R6,R3 ; set boot routine address
FF10: 10DB JMP >FEC8
; entry point for '0','I'
; read 8 additionnal characters and ignore them
FF12: 0201 0008 LI R1,>0008 ; read 8 chars
FF16: 069B BL *R11
FF18: 0601 DEC R1
FF1A: 16FD JNE >FF16
FF1C: 10D5 JMP >FEC8
; entry point for 'F' command (parameter-less)
; wait for next card to be inserted
FF1E: 069B BL *R11
FF20: 16FE JNE >FF1E ; wait for next card
FF22: 10C7 JMP >FEB2
; the following routine seems to read a hex digit from either boot device
FF24: C000 MOV R0,R0 ; test device type
FF26: 1338 JEQ >FF98
; 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.
; The routine is obviously incomplete, but we do translate alphanumeric characters and ':'...
FF28: 1F07 TB >0007 ; test whether card is inserted ?
FF2A: 1634 JNE >FF94
FF2C: 1F0F TB >000F ; wait for next row of punch holes ?
FF2E: 16FC JNE >FF28
FF30: 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
;
; Hollerith character codes (source : Model 990 Computer Programming Card) :
;
; Space : Blank
; ! : 12-7-8
; " : 7-8
; # : 3-8
; $ : 11-3-8
; % : 0-4-8
; & : 12
; ' : 5-8
; ( : 12-5-8
; ) : 11-5-8
; * : 11-4-8
; + : 12-6-8
; , : 0-3-8
; - : 11
; . : 12-3-8
; / : 0-1
; 0 : 0
; 1 : 1
; 2 : 2
; 3 : 3
; 4 : 4
; 5 : 5
; 6 : 6
; 7 : 7
; 8 : 8
; 9 : 9
; : : 2-8
; ; : 11-6-8
; < : 12-4-8
; = : 6-8
; > : 0-6-8
; ? : 0-7-8
; @ : 4-8
; A/a : 12-1
; B/b : 12-2
; C/c : 12-3
; D/d : 12-4
; E/e : 12-5
; F/f : 12-6
; G/g : 12-7
; H/h : 12-8
; I/i : 12-9
; J/j : 11-1
; K/k : 11-2
; L/l : 11-3
; M/m : 11-4
; N/n : 11-5
; O/o : 11-6
; P/p : 11-7
; Q/q : 11-8
; R/r : 11-9
; S/s : 0-2
; T/t : 0-3
; U/u : 0-4
; V/v : 0-5
; W/w : 0-6
; X/x : 0-7
; Y/y : 0-8
; Z/z : 0-9
; [ : 12-2-8
; ] : 11-2-8
; ^ : 11-7-8
; _ : 0-5-8
;
; missing :
; \ : 0-2-8
FF32: 04C8 CLR R8
FF34: D20A MOVB R10,R8 ; copy MSB
FF36: 092A SRL R10,2
FF38: 0ABA SLA R10,11 ; keep 5 bits (bits 9-13) in R10
FF3A: 058A INC R10
FF3C: 0A18 SLA R8,1 ; find last bit set to 1 in R8 and increment R10 accordingly
FF3E: 16FD JNE >FF3A
FF40: 060A DEC R10 ; fix R10
FF42: C20A MOV R10,R8
FF44: 06C8 SWPB R8
FF46: E288 SOC R8,R10
FF48: C20A MOV R10,R8
; Current result :
; R10 MSB = R8 MSB = R10 LSB = R8 LSB
; bits 0-4 (most significant) : bits 9-13 from 16-bit code
; bits 5-7 (least significant) : number of the last bit set to 1 in the MSByte of the 16-bit code
; (0 if none)
FF4A: 024A 000F ANDI R10,>000F ; so line 8 -> >8, and ':' (2-8) -> >A (!)
FF4E: 022A 0030 AI R10,>0030
FF52: 0A18 SLA R8,1
FF54: 1702 JNC >FF5A
FF56: 022A 0010 AI R10,>0010 ; line 12 : A -> ...
FF5A: 0A18 SLA R8,1
FF5C: 1702 JNC >FF62
FF5E: 022A 0019 AI R10,>0019 ; line 11 : J -> ...
FF62: 0A18 SLA R8,1
FF64: 1702 JNC >FF6A
FF66: 022A 0023 AI R10,>0023 ; line 0 : 0 (number), and S -> ...
FF6A: 0A18 SLA R8,1
FF6C: 1702 JNC >FF72
FF6E: 022A 0009 AI R10,>0009 ; line 9 : 9, etc.
FF72: 028A 0030 CI R10,>0030 ; no hole -> space
FF76: 1602 JNE >FF7C
FF78: 020A 0020 LI R10,>0020
FF7C: 028A 0053 CI R10,>0053 ; 0
FF80: 1602 JNE >FF86
FF82: 020A 0030 LI R10,>0030
FF86: 028A 0055 CI R10,>0055
FF8A: 1101 JLT >FF8E
FF8C: 064A DECT R10
FF8E: 1F0F TB >000F
FF90: 13FE JEQ >FF8E ; wait for device ready ?
FF92: 1010 JMP >FFB4 ; goto character decode routine
; we jump there if no card is inserted (?) when reading from the card reader located at >020
FF94: 828A C R10,R10
FF96: 1017 JMP >FFC6
; read routine
; Read ASCII character from 733 ASR located at >000 or MDU unit located at >FF0, and translate it to
; one hexadecimal number.
FF98: 1F0C TB >000C ; wait for incoming character ?
FF9A: 16FE JNE >FF98
FF9C: 1E0C SBZ >000C ; clear
FF9E: 35CA STCR R10,7 ; read ASCII character
FFA0: 098A SRL R10,8
FFA2: 028A 000D CI R10,>000D
FFA6: 130F JEQ >FFC6 ; exit if CR
FFA8: 028A 005A CI R10,>005A ; if higher than 'Z'
FFAC: 15F5 JGT >FF98
FFAE: 028A 0020 CI R10,>0020 ; or lower than ' '
FFB2: 11F2 JLT >FF98 ; try again
FFB4: A1CA A R10,R7 ; add R10 to checksum in R7 (?)
FFB6: 022A FFD0 AI R10,>FFD0 ; substract '0'
FFBA: 028A 000A CI R10,>000A ; if character is ':'
FFBE: 1306 JEQ >FFCC ; jump to boot routine
FFC0: 1102 JLT >FFC6
FFC2: 022A FFF9 AI R10,>FFF9 ; substract 7 for 'A'-'F' to give hexadecimal digit
FFC6: 069B BL *R11 ; return and restore R11 to point to >FFC8 (!)
; entry point for the routine which reads data from the boot device
FFC8: 10AD JMP >FF24
FFCA: 0340 IDLE ; stop the machine
; entry point for the ':' command (parameter-less command)
; jump to external boot routine
FFCC: C000 MOV R0,R0
FFCE: 1608 JNE >FFE0
FFD0: 1E0B SBZ >000B ; clean up the ASR status ?
FFD2: 1E0C SBZ >000C
FFD4: 0581 INC R1
FFD6: 16FE JNE >FFD4
FFD8: 1F0C TB >000C
FFDA: 13F8 JEQ >FFCC
FFDC: 1E09 SBZ >0009
FFDE: 1E0D SBZ >000D
FFE0: 0360 RSET ; reset peripherals
FFE2: 0453 B *R3 ; jumps to boot routine specified by >1 or >2 command
; (jumps to >FFCA if no routine was specified)
; offset table for jumps in object code interpreter, used on >FEE2 (offsets relative to >FEE2)
FFE4: 302C 2A04 BYTE >FF12->FEE2, >FF0E->FEE2, >FF0C->FEE2, >FEE6->FEE2
FFE8: 0404 041A BYTE >FEE6->FEE2, >FEE6->FEE2, >FEE6->FEE2, >FEFC->FEE2
FFEC: E60C 0A12 BYTE >FEC8->FEE2, >FEEE->FEE2, >FEEC->FEE2, >FEF4->FEE2
FFF0: 1022 1E00 BYTE >FEF2->FEE2, >FF04->FEE2, >FF00->FEE2, >00
FFF4: 0404 30E6 BYTE >FEE6->FEE2, >FEE6->FEE2, >FF12->FEE2, >FEC8->FEE2
; pointers to routines
FFF8: FE86 DATA >FE86 ; boot loader
FFFA: FEC6 DATA >FEC6 ; boot loader for MDU (?)
; LOAD vector
FFFC: F800 FE00 DATA >F800,>FE00