home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.tar / ftp.whtech.com / ti-990 / TI990_4.txt < prev   
Text File  |  2006-10-19  |  32KB  |  771 lines

  1. ; TI990/4 LOAD ROMs disassembly
  2. ;
  3. ; This ROM could be the item listed as 945121-0002 in 990 Handbook, 6-11 (page 218).
  4. ;
  5. ;General background :
  6. ; These ROMs contain the handler for the LOAD/RESTART interrupt.  Provided the board configuration is
  7. ; correct, this interrupt is called at start-up (instead of RESET), and we execute the boot loader.
  8. ;
  9. ; This interrupt can also be triggered by the programmer panel, and there is code to handle the panel
  10. ; functions.
  11. ;
  12. ;Description :
  13. ; Include a CPU test ROM set at >FC00, and a LOAD/RESTART ROM with programmer panel handling and
  14. ; boot strap code at >FE00.  Note that the LOAD ROM calls the test routine in the CPU test ROM.
  15. ;
  16. ; The first ROM should be interesting for people who want to test an emulator.
  17. ; The second ROM is a source of documentation on the boot process, and the programmer panel.
  18. ;
  19. ; If you want a starting point, you can have a look at the LOAD vector located at >FFFC.
  20. ; The LOAD routine starts at >FE00.
  21. ;
  22. ;Notes :
  23. ; * The code assumes 32 (?) bytes of RAM are available at >F800.
  24. ; * The code can ignore the programmer panel provided the proper CRU bit is set, which allows the use
  25. ;  of programmer-panel-less TI990/4.
  26. ; * The boot strap loader boots from a 733 ASR terminal at CRU address >000.  Though, if you write a
  27. ;  non-zero value to @>F800 (using the programmer panel), the ROM should boot from a Card Reader
  28. ;  located at CRU address >020.  The loader seems to support booting from a MDU (Maintenance
  29. ;  Diagnostics Unit) when such a MDU is connected in the programmer panel slot.
  30. ;  (Standard CRU map reference : 990 computer family systems handbook, H-2, page 346)
  31. ; * A description of the 733 ASR terminal is given in the 990 handbook.  Among other things, there is
  32. ;  an optionnal tape unit, which could be actually used by the boot process.  Unfortunately, I have no
  33. ;  documentation on the ASR CRU interface.
  34. ;
  35. ;Conventions used :
  36. ; TMS9900 assembly conventions should have been respected.  Particularily :
  37. ; * bit are numbered from MSB to LSB (unlike almost every other CPU)
  38. ;
  39. ;
  40. ; Raphael Nabet, 2000/04/24
  41. ;
  42. ; revision history :
  43. ; 2000/04/24 : clarified a few things with MDU support
  44. ; 2000/02/20 : fixed a few comments, documented object code and Hollerith code better
  45. ; 2000/02/16 : fixed a few comments, replaced DW and DB with standard DATA and BYTE directives
  46. ; 2000/01/31 : fixed some ambiguous comments, documented programmer panel better, found out actual
  47. ;   identity of boot devices
  48. ; 2000/01/28 : initial release
  49.  
  50.  
  51.  
  52.  
  53. ; Here we have a cpu test ROM
  54. ; test routine entry point
  55. ; preserves R0.
  56. ; jumps to the boot routine on exit
  57. FC00: 1D0B           SBO  >000B         ; switch "Fault" light on
  58. FC02: 0208 7FFF      LI   R8,>7FFF
  59. FC06: 05C8           INCT R8
  60. FC08: 1933           JNO  >FC70         ; stop if no overflow
  61. FC0A: C040           MOV  R0,R1
  62. FC0C: C008           MOV  R8,R0
  63. FC0E: 0858           SRA  R8,5
  64. FC10: 0918           SRL  R8,1
  65. FC12: 0808           SRA  R8,0
  66. FC14: C001           MOV  R1,R0         ; restore R0
  67. FC16: 0288 3F00      CI   R8,>3F00
  68. FC1A: 162A           JNE  >FC70         ; stop if different from the value expected
  69. FC1C: 0704           SETO R4
  70. FC1E: 0244 5555      ANDI R4,>5555
  71. FC22: 06A0 FC36      BL   @>FC36        ; this should clear R4, or stop if it fails
  72. FC26: 0264 5555      ORI  R4,>5555
  73. FC2A: 06A0 FC36      BL   @>FC36
  74. FC2E: 0300 0001      LIMI >0001         ; effectively sets least significant bit in ST
  75. FC32: 0420 FC4E      BLWP @>FC4E        ; jump to >FC40
  76.  
  77. ; should be called with R4 == >5555
  78. FC36: 0264 AAAA      ORI  R4,>AAAA
  79. FC3A: 0584           INC  R4
  80. FC3C: 1619           JNE  >FC70         ; stop if R4 != 0
  81. FC3E: 045B           B    *R11
  82.  
  83. ; continue on...
  84. FC40: 02CB           STST R11
  85. FC42: 081B           SRA  R11,1         ; test LSBit in ST
  86. FC44: 1715           JNC  >FC70         ; stop if not set
  87. FC46: 04CF           CLR  R15           ; -> clear ST
  88. FC48: 020E FC52      LI   R14,>FC52     ; actual jump address
  89. FC4C: 0380           RTWP
  90.  
  91. FC4E: F7EC FC40      DATA >F7EC,>FC40   ; BLWP vector
  92.  
  93. ; continue on...  This gets tricky :-) .
  94. FC52: 02C7           STST R7
  95. FC54: C047           MOV  R7,R1
  96. FC56: 160C           JNE  >FC70         ; stop if ST not clear
  97.  
  98. FC58: C081           MOV  R1,R2
  99. FC5A: 0B52           SRC  R2,5          ;
  100. FC5C: 06C2           SWPB R2            ; effectively rotate R2 3 bits left
  101. FC5E: C2C2           MOV  R2,R11
  102. FC60: 074B           ABS  R11
  103.  
  104. FC62: C0C2           MOV  R2,R3
  105. FC64: 0A13           SLA  R3,1          ; test R2 sign bit
  106. FC66: 1709           JNC  >FC7A         ; start if R2 is positive
  107.  
  108. FC68: 054B           INV  R11           ; R11 = ~R11
  109. FC6A: 808B           C    R11,R2        ; so R11 = R2-1
  110. FC6C: 1B7A           JH   >FD62         ; stop the machine if R11>R2
  111. FC6E: 1101           JLT  >FC72         ; huh ??? what if R2 == 0x8000 ? This must be a bug !
  112.  
  113. FC70: 10FF           JMP  >FC70         ; stop everything
  114.  
  115. FC72: 82C2           C    R2,R11
  116. FC74: 1A76           JL   >FD62         ; we still have R11 = R2-1...
  117. FC76: 05CB           INCT R11
  118. FC78: 060B           DEC  R11           ; now R11 == R2
  119.  
  120. ; we jump here when R2 >= 0
  121. FC7A: 808B           C    R11,R2
  122. FC7C: 1672           JNE  >FD62
  123.  
  124. FC7E: C0C1           MOV  R1,R3
  125. FC80: A0C2           A    R2,R3
  126. FC82: C101           MOV  R1,R4
  127. FC84: 0504           NEG  R4
  128. FC86: 6102           S    R2,R4
  129. FC88: 0504           NEG  R4
  130. FC8A: 9103           CB   R3,R4         ; we should have R3==R4
  131. FC8C: 1B6A           JH   >FD62         ; stop if logically higher
  132. FC8E: 1201           JLE  >FC92         ; jump there if OK
  133. FC90: 1068           JMP  >FD62         ; stop if arithmetically greater
  134.  
  135. FC92: 9820 F807 F809 CB   @>F807,@>F809 ; compare R3 MSB and R4 MSB
  136. FC98: 1664           JNE  >FD62         ; stop if different
  137. FC9A: 20C4           COC  R4,R3         ; (R3 & R4) == R3 ?
  138. FC9C: 1662           JNE  >FD62
  139. FC9E: 0544           INV  R4
  140. FCA0: 24C4           CZC  R4,R3         ; (R3 & ~R4) == R3 ?
  141. FCA2: 165F           JNE  >FD62
  142. FCA4: 0544           INV  R4
  143. FCA6: 7103           SB   R3,R4         ; result 0 in R4 MSB
  144. FCA8: 115C           JLT  >FD62
  145. FCAA: 165B           JNE  >FD62
  146. FCAC: 7820 F807 F809 SB   @>F807,@>F809 ; substract LSB
  147. FCB2: 1657           JNE  >FD62
  148. FCB4: D102           MOVB R2,R4         ; move R2 MSB
  149. FCB6: D820 F805 F809 MOVB @>F805,@>F809 ; move R2 LSB
  150. FCBC: B820 F803 F809 AB   @>F803,@>F809 ; add R1 LSB
  151. FCC2: 1702           JNC  >FCC8
  152. FCC4: 0224 0100      AI   R4,>0100      ; adjust carry if needed
  153. FCC8: B101           AB   R1,R4         ; add R1 MSB
  154. FCCA: 8103           C    R3,R4         ; we should still have R3 = R1+R2, too...
  155. FCCC: 164A           JNE  >FD62
  156. FCCE: 0583           INC  R3
  157. FCD0: 0583           INC  R3
  158. FCD2: 80C4           C    R4,R3
  159. FCD4: 1346           JEQ  >FD62
  160. FCD6: 1545           JGT  >FD62
  161. FCD8: 0643           DECT R3
  162. FCDA: 8103           C    R3,R4
  163. FCDC: 1642           JNE  >FD62
  164. FCDE: C143           MOV  R3,R5
  165. FCE0: C185           MOV  R5,R6
  166. FCE2: C1C5           MOV  R5,R7
  167. FCE4: 06C7           SWPB R7            ; swap bytes (8-bit rotate)
  168. FCE6: 0985           SRL  R5,8
  169. FCE8: 0A86           SLA  R6,8
  170. FCEA: E185           SOC  R5,R6         ; swap bytes with another method
  171. FCEC: 81C6           C    R6,R7
  172. FCEE: 1639           JNE  >FD62
  173. FCF0: 0B86           SRC  R6,8          ; swap bytes again
  174. FCF2: 80C6           C    R6,R3         ; should equate the original value
  175. FCF4: 1636           JNE  >FD62
  176.  
  177. ; now, multiply R1 and R2 with custom code, then check MPY gives the same result
  178. FCF6: 020A 0010      LI   R10,>0010     ; 16 bits to test
  179. FCFA: 04CB           CLR  R11
  180. FCFC: 04C8           CLR  R8
  181. FCFE: 04C7           CLR  R7
  182. FD00: C182           MOV  R2,R6
  183. FD02: C141           MOV  R1,R5
  184.  
  185. FD04: 0815           SRA  R5,1          ; if R5 LSB is set
  186. FD06: 1704           JNC  >FD10
  187.  
  188. FD08: A2C6           A    R6,R11        ; add R7:R6 to R8:R11
  189. FD0A: 1701           JNC  >FD0E
  190. FD0C: 0588           INC  R8
  191. FD0E: A207           A    R7,R8
  192.  
  193. FD10: 0A17           SLA  R7,1          ; shift R7:R6
  194. FD12: 0A16           SLA  R6,1
  195. FD14: 1801           JOC  >FD18
  196. FD16: 1001           JMP  >FD1A
  197. FD18: 0587           INC  R7
  198.  
  199. FD1A: 060A           DEC  R10           ; loop
  200. FD1C: 16F3           JNE  >FD04
  201.  
  202. FD1E: C0C1           MOV  R1,R3
  203. FD20: 38E0 F804      MPY  @>F804,R3     ; = MPY R2,R3
  204. FD24: 8203           C    R3,R8         ; compare MSWord
  205. FD26: 161D           JNE  >FD62
  206. FD28: 82C4           C    R4,R11        ; compare LSWord
  207. FD2A: 161B           JNE  >FD62
  208.  
  209. ; now, test DIVide
  210. FD2C: 8081           C    R1,R2
  211. FD2E: 1408           JHE  >FD40
  212. FD30: A101           A    R1,R4         ; if R1 < R2, add R1 to MSW (R4)
  213. FD32: 1702           JNC  >FD38
  214. FD34: 6101           S    R1,R4         ; if carry, revert to normal method
  215. FD36: 1004           JMP  >FD40         ; (otherwise, there might be an overflow when executing DIV)
  216. FD38: 3CC2           DIV  R2,R3
  217. FD3A: 04A0 FD34      X    @>FD34        ; = S R1,R4 (remainder should be R1, and is fixed to be 0)
  218. FD3E: 1003           JMP  >FD46
  219.  
  220. FD40: 3CE0 F804      DIV  @>F804,R3     ; compute R3:R4 / R2
  221. FD44: C104           MOV  R4,R4         ; test the remainder
  222.  
  223. FD46: 160D           JNE  >FD62         ; should be 0
  224.  
  225. ; now test parity ST bit
  226. FD48: D181           MOVB R1,R6
  227. FD4A: 0207 0008      LI   R7,>0008      ; 8 bits to test
  228. FD4E: 04C8           CLR  R8
  229. FD50: 0A16           SLA  R6,1
  230. FD52: 1701           JNC  >FD56
  231. FD54: 0588           INC  R8            ; count bits
  232. FD56: 0607           DEC  R7
  233. FD58: 15FB           JGT  >FD50         ; loop if some bits left
  234.  
  235. FD5A: 0B18           SRC  R8,1          ; test parity
  236. FD5C: 1703           JNC  >FD64
  237.  
  238. FD5E: D041           MOVB R1,R1         ; should be odd parity
  239. FD60: 1C03           JOP  >FD68
  240. FD62: 10FF           JMP  >FD62
  241.  
  242. FD64: B1C1           AB   R1,R7         ; R7 == 0 from previous loop (remember ?)
  243. FD66: 1CFD           JOP  >FD62         ; should be even parity
  244.  
  245. FD68: C142           MOV  R2,R5
  246. FD6A: 4142           SZC  R2,R5         ; R5 = R5 & ~R2
  247. FD6C: 16FA           JNE  >FD62         ; result should be 0
  248. FD6E: A142           A    R2,R5         ; hence R5 = R2
  249. FD70: 5142           SZCB R2,R5         ; R2 MSB & R5 MSB
  250. FD72: 16F7           JNE  >FD62
  251. FD74: 5820 F805 F80B SZCB @>F805,@>F80B ; R2 LSB & R5 LSB
  252. FD7A: 16F3           JNE  >FD62
  253. FD7C: 070B           SETO R11           ; R11 = >FFFF
  254. FD7E: 42C2           SZC  R2,R11        ; R11 = R11 & ~R2
  255. FD80: 13F0           JEQ  >FD62         ; obviously, R2 is assumed to be non-zero
  256. FD82: F141           SOCB R1,R5         ; R5 should be 0 from previous computation.
  257. FD84: 06C5           SWPB R5
  258. FD86: F160 F803      SOCB @>F803,R5     ; bit-wise OR with R1 LSB
  259. FD8A: 0B85           SRC  R5,8          ; so R5 = R1
  260. FD8C: 6141           S    R1,R5
  261. FD8E: 16E9           JNE  >FD62
  262.  
  263. FD90: 0581           INC  R1            ; increment R1
  264. FD92: 0281 FFC0      CI   R1,>FFC0
  265. FD96: 1B0A           JH   >FDAC         ; if R1 > >FFC0, bail out
  266.  
  267. FD98: C181           MOV  R1,R6
  268. FD9A: 0204 0013      LI   R4,>0013
  269. FD9E: 3D44           DIV  R4,R5         ; effectively computes R6 / 19  (R5 is still 0, remember ?)
  270. FDA0: C186           MOV  R6,R6         ; test the remainder
  271. FDA2: 1602           JNE  >FDA8
  272. FDA4: 0221 03E8      AI   R1,>03E8      ; add 1000 to R1 if R1 is multiple of 19
  273. FDA8: 0460 FC58      B    @>FC58        ; and loop
  274. ; this effectively results into testing a sequence :
  275. ; 0,1,...,18,1019,1020,1021,1022,1023,1024,1025,2026,2027,2028,...,2032,3033,...,65467,...,65472.
  276. ; The next value is 65473, which is greater than >FFC0 (65472), so we exit the routine at this point.
  277. ; Looks like a decent way to shuffle values.
  278.  
  279. ; memory test
  280. ; we use some nasty self-compiling code
  281. FDAC: 070A           SETO R10
  282. FDAE: 0202 02E0      LI   R2,>02E0      ; LWPI
  283. FDB2: 04C3           CLR  R3            ; >0000
  284. FDB4: 0204 0460      LI   R4,>0460      ; B @
  285. FDB8: 0205 FDD0      LI   R5,>FDD0      ; >FDD0
  286.  
  287. ; loop start
  288. FDBC: 0283 F800      CI   R3,>F800
  289. FDC0: 131A           JEQ  >FDF6         ; don't test system area >F800->FFFF
  290. FDC2: 02A6           STWP R6
  291. FDC4: 8183           C    R3,R6         ; do not overwrite our workspace.
  292. FDC6: 1602           JNE  >FDCC         ; geez, the previous test already ensured this !
  293. FDC8: 0223 0020      AI   R3,>0020
  294. FDCC: C053           MOV  *R3,R1        ; save future R0 register
  295.  
  296. FDCE: 0442           B    R2            ; this emulates missing "LWP R3" instruction
  297. FDD0: 2820 F814      XOR  @>F814,R0     ; XOR old R10 with new R0
  298. FDD4: 02E0 F800      LWPI >F800         ; restore old WP
  299. FDD8: 0541           INV  R1            ; R1 = ~R1
  300. FDDA: C1C1           MOV  R1,R7
  301. FDDC: 84C1           C    R1,*R3        ; should give the same result as R0 = R0 ^ >FFFF
  302. FDDE: 1606           JNE  >FDEC
  303. FDE0: 0553           INV  *R3           ; Restore memory location
  304. FDE2: 2873           XOR  *R3+,R1       ; result should be >FFFF
  305. FDE4: 0581           INC  R1
  306. FDE6: 13EA           JEQ  >FDBC         ; try next word if OK
  307.  
  308. FDE8: 0643           DECT R3            ; else restore R3
  309. FDEA: 0547           INV  R7            ; restore value read in RAM
  310. FDEC: C183           MOV  R3,R6
  311. FDEE: 0A36           SLA  R6,3          ; if the address in on a 8kb-boundary, we must only have left
  312. FDF0: 1302           JEQ  >FDF6         ; the RAM area, so we continue on (?)
  313. FDF2: C087           MOV  R7,R2
  314. FDF4: 0340           IDLE               ; else stop the machine
  315. FDF6: C060 FFF8      MOV  @>FFF8,R1     ; read pointer to boot routine
  316. FDFA: 0451           B    *R1           ; and jump there
  317.  
  318. ; entry point for self-test routine
  319. FDFC: 0460 FC00      B    @>FC00
  320.  
  321.  
  322. ; Here, we have programmer panel handling and boot strap code.
  323. ; LOAD vector entry point :
  324. FE00: 020C 1FE0      LI   R12,>1FE0     ; load programmer panel CRU base address
  325. FE04: 0221 6700      AI   R1,>6700      ; test for magical value (>9900)
  326. FE08: 1602           JNE  >FE0E         ; jump if not found
  327. FE0A: 1D0A           SBO  >000A         ; switch "Run" light on
  328. FE0C: 0450           B    *R0           ; jump to routine pointed by R0
  329. FE0E: 0209 00A0      LI   R9,>00A0
  330. FE12: 04C0           CLR  R0
  331. FE14: 1F0B           TB   >000B         ; test if programmer panel present and active
  332. FE16: 13F2           JEQ  >FDFC         ; if panel inactive, silently jump to CPU self-test
  333.  
  334. FE18: C08E           MOV  R14,R2        ; else copy old PC to display register
  335.  
  336. ; programmer panel scan : we have 4 rows of 8 switches
  337. ; 16 switches allow to toggle the display in R2.
  338. ; the 16 other switches allow to access programmer panel functions.
  339. ;
  340. ; register conventions here :
  341. ; R2 = data register
  342. ; R7 = memory address register
  343. ; R13 = WP
  344. ; R14 = PC
  345. ; R15 = ST
  346.  
  347. ; keyscan loop start
  348. FE1A: 3202           LDCR R2,8          ; display data register MSB
  349. FE1C: 3220 F805      LDCR @>F805,8      ; display data register LSB
  350.  
  351. FE20: 0205 FE7C      LI   R5,>FE7C
  352. FE24: 0695           BL   *R5           ; read current 8 switches from programmer panel to R1 MSB
  353. FE26: 16FE           JNE  >FE24         ; wait for all switches to be released
  354. FE28: 0695           BL   *R5
  355. FE2A: 16FC           JNE  >FE24         ; test again to fix switch bounce problems
  356. FE2C: 04C1           CLR  R1
  357.  
  358. FE2E: 1D08           SBO  >0008         ; "Increment scan" bit -> select another row of switches
  359. FE30: 0695           BL   *R5
  360. FE32: 13FD           JEQ  >FE2E         ; if no switch pressed, scan next row
  361. FE34: 0695           BL   *R5
  362. FE36: 13FB           JEQ  >FE2E         ; fixes switch bounce problems
  363.  
  364. FE38: 1F09           TB   >0009         ; scan count bit 0 -> is current switch row number odd or even ?
  365. FE3A: 1601           JNE  >FE3E
  366. FE3C: 06C1           SWPB R1            ; if odd, we read last 8 switches in 16 switches, so we rotate 8 bits.
  367. FE3E: 1F08           TB   >0008         ; scan count bit 1 -> is this command switches or data switches ?
  368. FE40: 1302           JEQ  >FE46         ; command switches -> jump to interpret command
  369. FE42: 2881           XOR  R1,R2         ; data switches -> toggle the data displayed as requested
  370. FE44: 10EA           JMP  >FE1A         ; update display and go back to scan routine
  371.  
  372. ; command interpreter for programmer panel
  373. FE46: 04C5           CLR  R5
  374. FE48: 05C5           INCT R5
  375. FE4A: 0A11           SLA  R1,1
  376. FE4C: 17FD           JNC  >FE48         ; count first bit set to 1 in R1, i.e. first switch pressed
  377. FE4E: 04A5 FE52      X    @>FE52(R5)    ; execute command as needed.
  378. FE52: 10E3           JMP  >FE1A         ; update display and go back to scan routine if we have not jumped away
  379. ; The jump offsets in the following table must be >FE52-relative, since this is the value of PC when X
  380. ; executes the instruction.
  381. FE54: 1013           JMP  *+>FE78->FE52 ; "Halt/SIE" switch
  382. FE56: 1011           JMP  *+>FE74->FE52 ; "Run" switch
  383. FE58: 0360           RSET               ; "Reset" switch
  384. FE5A: 10D5           JMP  *+>FDFC->FE52 ; "Load" switch
  385. FE5C: C08D           MOV  R13,R2        ; "Display WP" switch
  386. FE5E: C08E           MOV  R14,R2        ; "Display PC" switch
  387. FE60: C08F           MOV  R15,R2        ; "Display ST" switch
  388. FE62: C087           MOV  R7,R2         ; "Display MA" switch
  389. FE64: C342           MOV  R2,R13        ; "Enter WP" switch
  390. FE66: C382           MOV  R2,R14        ; "Enter PC" switch
  391. FE68: C3C2           MOV  R2,R15        ; "Enter ST" switch
  392. FE6A: C1C2           MOV  R2,R7         ; "Enter MA" switch
  393. FE6C: C097           MOV  *R7,R2        ; "MDD" switch ("Memory Data Display")
  394. FE6E: 05C7           INCT R7            ; "MAI" switch ("Memory Address Increment")
  395. FE70: C5C2           MOV  R2,*R7        ; "MDE" switch ("Memory Data Enter")
  396. FE72: 04C2           CLR  R2            ; "CLR" switch
  397.  
  398. ; Code for run switch
  399. FE74: 1D0A           SBO  >000A         ; switch "Run" light on
  400. FE76: 0380           RTWP
  401.  
  402. ; code for "Halt/SIE" switch
  403. FE78: 1D0E           SBO  >000E         ; set "Single Instruction Execute"
  404. FE7A: 0380           RTWP               ; Restart trap will occur after 2 instructions
  405. ; The second instruction executed will be an instruction from the program we interrupted.
  406. ; Pressing the HALT/SIE switch repetitively, you will trace the current program.
  407.  
  408.  
  409. ; this routine read a row of 8 switches from the programmer panel
  410. FE7C: 1D0D           SBO  >000D         ; start panel timer
  411. FE7E: 1F0A           TB   >000A         ; wait for timer active bit to be set
  412. FE80: 16FE           JNE  >FE7E
  413. FE82: 3601           STCR R1,8          ; retrieve value
  414. FE84: 045B           B    *R11
  415.  
  416. ; Real boot routine, called after the CPU self-test
  417. ;
  418. ; We boot from a 733 ASR terminal located at CRU address >000.
  419. ;
  420. ; Note that when R0 is non-zero, we boot from a card reader located at CRU address >020 instead, but
  421. ; this possibility is never used since R0 is cleared by the LOAD vector.
  422. ; This must be a debug mode, which should be enabled with the programmer panel.
  423. ;
  424. ; The boot code is encoded as object code, as described in the Model 990 Computer Programming Card.
  425. ;
  426. ; We receive characters from the boot device.  These are interpreted as commands or as hexadecimal
  427. ; immediate operands.  Note that we actually only use hexadecimal characters, and 'G','H',':'.
  428. ;
  429. ; Commands with 16-bit immediate (encoded in hexadecimal) :
  430. ; * '1' : Absolute Entry Address : boot routine address = IMM
  431. ; * '2' : Relocatable Entry Address : boot routine address = offset + IMM
  432. ; * '7' : Checksum : stops the machine if (sum of all data received since start of record) + IMM != 0
  433. ; * '9' : Absolute Load Address : memory address pointer = IMM
  434. ; * 'A' : Relocatable Load Address : memory address pointer = offset + IMM
  435. ; * 'B' : Absolute Data : * (memory address pointer ++) = IMM
  436. ; * 'C' : Relocatable Data : * (memory address pointer ++) = offset + IMM
  437. ; * 'D' : Load Bias Or Offset : offset = IMM
  438. ; * 'E' : (no reference) : stop the machine
  439. ;
  440. ; Control commands (parameter-less) :
  441. ; * ':' : (no reference) : branch to boot routine address
  442. ; * 'F' : End Of Record : wait for next card to be inserted
  443. ;
  444. ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) :
  445. ; * '8' : Ignore Checksum Value : does nothing
  446. ; * 'J' : (no reference)
  447. ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) and 6-char symbol name :
  448. ; * '3', '4', '5', '6', 'G', 'H' (symbol-related commands)
  449. ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) and 8-char program name :
  450. ; * '0' : Program Start
  451. ; * 'I' : (no reference)
  452. ;
  453. FE86: 0360           RSET               ; RESET external peripherals
  454. FE88: 0203 FFCA      LI   R3,>FFCA      ; address of the start-up routine we jump to - defaults to error routine
  455. FE8C: 020B FFC8      LI   R11,>FFC8     ; points routine which fetches data from the boot device
  456. FE90: 0205 F7FE      LI   R5,>F7FE      ; last word before our small system memory area
  457.  
  458. FE94: C555           MOV  *R5,*R5       ; try to read and write current word
  459. FE96: 0645           DECT R5            ; previous word
  460. FE98: 18FD           JOC  >FE94         ; loop until we wrap around to >FFFE
  461. FE9A: 1D0A           SBO  >000A         ; switch "Run" light on
  462. FE9C: 1F0E           TB   >000E         ; this bit must tell a MDU is present
  463. FE9E: 1613           JNE  >FEC6         ; boot from the MDU ?
  464.  
  465. FEA0: 020C 0040      LI   R12,>0040
  466. FEA4: C000           MOV  R0,R0         ; R0 was cleared on line >FE12 (!) - can be set with the programmer pannel to use the card reader
  467. FEA6: 1605           JNE  >FEB2         ; skip if card reader
  468. FEA8: 04CC           CLR  R12           ; device address >000 : 733 ASR
  469. FEAA: 1D09           SBO  >0009         ; set-up device
  470. FEAC: 1D0A           SBO  >000A
  471. FEAE: 3220 FFC0      LDCR @>FFC0,8      ; effectively writes >11
  472. FEB2: C000           MOV  R0,R0
  473. FEB4: 1308           JEQ  >FEC6         ; skip if ASR
  474. FEB6: 1F07           TB   >0007         ; set up card reader at CRU address >020
  475. FEB8: 13FE           JEQ  >FEB6
  476. FEBA: 1F01           TB   >0001
  477. FEBC: 13FE           JEQ  >FEBA
  478. FEBE: 1E0F           SBZ  >000F
  479. FEC0: 1F07           TB   >0007
  480. FEC2: 16FE           JNE  >FEC0
  481. FEC4: 1D0F           SBO  >000F
  482.  
  483. FEC6: 04C7           CLR  R7            ; clear checksum
  484.  
  485. FEC8: 069B           BL   *R11          ; read command number in R10 from boot device (range 0-19)
  486. FECA: D0AA FFE4      MOVB @>FFE4(R10),R2    ; read routine offset in table
  487. FECE: 1327           JEQ  >FF1E         ; handle 'F' command separately because it is parameter-less
  488. FED0: 0882           SRA  R2,8          ; convert to signed 16-bit offset
  489. FED2: C107           MOV  R7,R4         ; save checksum
  490. FED4: 0201 0004      LI   R1,>0004      ; 4*4 = 16 bits to read
  491. FED8: 069B           BL   *R11          ; read hex digit (4 bits)
  492. FEDA: 0A46           SLA  R6,4          ; shift digits we have already read
  493. FEDC: A18A           A    R10,R6        ; and insert new digit in R6
  494. FEDE: 0601           DEC  R1
  495. FEE0: 16FB           JNE  >FED8         ; loop until we have read a 16-bit hex value
  496. FEE2: 0462 FEE2      B    @>FEE2(R2)    ; jump to routine
  497.  
  498. ; entry point for '3', '4', '5', '6','G','H'
  499. ; read 6 additional characters and ignore them
  500. FEE6: 0201 0006      LI   R1,>0006      ; read 6 chars
  501. FEEA: 1015           JMP  >FF16
  502.  
  503. ; entry point for 'A'
  504. ; add offset to R6, set address pointer
  505. FEEC: A189           A    R9,R6         ; add offset to R6 (R9 set by 'D' command, defaults to >00A0)
  506. ; entry point for '9'
  507. ; set address pointer
  508. FEEE: C146           MOV  R6,R5         ; set address pointer
  509. FEF0: 10EB           JMP  >FEC8         ; continue on ?
  510.  
  511. ; entry point for 'C'
  512. ; add offset to R6, write two bytes
  513. FEF2: A189           A    R9,R6
  514. ; entry point for 'B'
  515. ; write two bytes
  516. FEF4: DD46           MOVB R6,*R5+
  517. FEF6: 06C6           SWPB R6
  518. FEF8: DD46           MOVB R6,*R5+
  519. FEFA: 10E6           JMP  >FEC8
  520.  
  521. ; entry point for '7'
  522. ; check checksum
  523. FEFC: A106           A    R6,R4
  524. FEFE: 13E4           JEQ  >FEC8         ; continue on if value matches checksum
  525. ; entry point for 'E'
  526. ; boot failure
  527. FF00: 046B 0002      B    @>0002(R11)   ; jump to >FFCA (IDLE)
  528.  
  529. ; entry point for 'D'
  530. ; set bias/offset
  531. FF04: C246           MOV  R6,R9         ; set bias/offset value
  532. FF06: 0249 FFFE      ANDI R9,>FFFE      ; convert to word address
  533. FF0A: 10DE           JMP  >FEC8
  534.  
  535. ; entry point for '2'
  536. ; add offset to R6, set boot routine address
  537. FF0C: A189           A    R9,R6
  538. ; entry point for '1'
  539. ; set boot routine address
  540. FF0E: C0C6           MOV  R6,R3         ; set boot routine address
  541. FF10: 10DB           JMP  >FEC8
  542.  
  543. ; entry point for '0','I'
  544. ; read 8 additionnal characters and ignore them
  545. FF12: 0201 0008      LI   R1,>0008      ; read 8 chars
  546. FF16: 069B           BL   *R11
  547. FF18: 0601           DEC  R1
  548. FF1A: 16FD           JNE  >FF16
  549. FF1C: 10D5           JMP  >FEC8
  550.  
  551. ; entry point for 'F' command (parameter-less)
  552. ; wait for next card to be inserted
  553. FF1E: 069B           BL   *R11
  554. FF20: 16FE           JNE  >FF1E         ; wait for next card
  555. FF22: 10C7           JMP  >FEB2
  556.  
  557.  
  558. ; the following routine seems to read a hex digit from either boot device
  559. FF24: C000           MOV  R0,R0         ; test device type
  560. FF26: 1338           JEQ  >FF98
  561.  
  562. ; card reader located at >020
  563. ;
  564. ; Read Hollerith code, and translate it to ASCII code, then hexadecimal number.
  565. ; Seems to set EQ flag if the card is not inserted and R10 contains 0.
  566. ; The routine is obviously incomplete, but we do translate alphanumeric characters and ':'...
  567. FF28: 1F07           TB   >0007         ; test whether card is inserted ?
  568. FF2A: 1634           JNE  >FF94
  569. FF2C: 1F0F           TB   >000F         ; wait for next row of punch holes ?
  570. FF2E: 16FC           JNE  >FF28
  571. FF30: 340A           STCR R10,16        ; read code
  572. ;
  573. ; Encoding :
  574. ;
  575. ; We use Hollerith code.  It uses 12 lines (0-9 and 11-12), plus one synchro line.
  576. ;
  577. ; Line map :
  578. ;                          MSB                       LSB
  579. ; CRU bit :      15 14 13 12 11 10  9  8    7  6  5  4  3  2  1  0
  580. ; register bit :  0  1  2  3  4  5  6  7    8  9 10 11 12 13 14 15
  581. ; card line :     ?  1  2  3  4  5  6  7    ? 12 11  0  9  8  ? synchro
  582. ;
  583. ; Hollerith character codes (source : Model 990 Computer Programming Card) :
  584. ;
  585. ; Space : Blank
  586. ; ! : 12-7-8
  587. ; " : 7-8
  588. ; # : 3-8
  589. ; $ : 11-3-8
  590. ; % : 0-4-8
  591. ; & : 12
  592. ; ' : 5-8
  593. ; ( : 12-5-8
  594. ; ) : 11-5-8
  595. ; * : 11-4-8
  596. ; + : 12-6-8
  597. ; , : 0-3-8
  598. ; - : 11
  599. ; . : 12-3-8
  600. ; / : 0-1
  601. ; 0 : 0
  602. ; 1 : 1
  603. ; 2 : 2
  604. ; 3 : 3
  605. ; 4 : 4
  606. ; 5 : 5
  607. ; 6 : 6
  608. ; 7 : 7
  609. ; 8 : 8
  610. ; 9 : 9
  611. ; : : 2-8
  612. ; ; : 11-6-8
  613. ; < : 12-4-8
  614. ; = : 6-8
  615. ; > : 0-6-8
  616. ; ? : 0-7-8
  617. ; @ : 4-8
  618. ; A/a : 12-1
  619. ; B/b : 12-2
  620. ; C/c : 12-3
  621. ; D/d : 12-4
  622. ; E/e : 12-5
  623. ; F/f : 12-6
  624. ; G/g : 12-7
  625. ; H/h : 12-8
  626. ; I/i : 12-9
  627. ; J/j : 11-1
  628. ; K/k : 11-2
  629. ; L/l : 11-3
  630. ; M/m : 11-4
  631. ; N/n : 11-5
  632. ; O/o : 11-6
  633. ; P/p : 11-7
  634. ; Q/q : 11-8
  635. ; R/r : 11-9
  636. ; S/s : 0-2
  637. ; T/t : 0-3
  638. ; U/u : 0-4
  639. ; V/v : 0-5
  640. ; W/w : 0-6
  641. ; X/x : 0-7
  642. ; Y/y : 0-8
  643. ; Z/z : 0-9
  644. ; [ : 12-2-8
  645. ; ] : 11-2-8
  646. ; ^ : 11-7-8
  647. ; _ : 0-5-8
  648. ;
  649. ; missing :
  650. ; \ : 0-2-8
  651.  
  652. FF32: 04C8           CLR  R8
  653. FF34: D20A           MOVB R10,R8        ; copy MSB
  654. FF36: 092A           SRL  R10,2
  655. FF38: 0ABA           SLA  R10,11        ; keep 5 bits (bits 9-13) in R10
  656.  
  657. FF3A: 058A           INC  R10
  658. FF3C: 0A18           SLA  R8,1          ; find last bit set to 1 in R8 and increment R10 accordingly
  659. FF3E: 16FD           JNE  >FF3A
  660.  
  661. FF40: 060A           DEC  R10           ; fix R10
  662. FF42: C20A           MOV  R10,R8
  663. FF44: 06C8           SWPB R8
  664. FF46: E288           SOC  R8,R10
  665. FF48: C20A           MOV  R10,R8
  666. ; Current result :
  667. ; R10 MSB = R8 MSB = R10 LSB = R8 LSB
  668. ; bits 0-4 (most significant) : bits 9-13 from 16-bit code
  669. ; bits 5-7 (least significant) : number of the last bit set to 1 in the MSByte of the 16-bit code
  670. ;                                (0 if none)
  671. FF4A: 024A 000F      ANDI R10,>000F     ; so line 8 -> >8, and ':' (2-8) -> >A (!)
  672. FF4E: 022A 0030      AI   R10,>0030
  673.  
  674. FF52: 0A18           SLA  R8,1
  675. FF54: 1702           JNC  >FF5A
  676. FF56: 022A 0010      AI   R10,>0010     ; line 12 : A -> ...
  677.  
  678. FF5A: 0A18           SLA  R8,1
  679. FF5C: 1702           JNC  >FF62
  680. FF5E: 022A 0019      AI   R10,>0019     ; line 11 : J -> ...
  681.  
  682. FF62: 0A18           SLA  R8,1
  683. FF64: 1702           JNC  >FF6A
  684. FF66: 022A 0023      AI   R10,>0023     ; line 0 : 0 (number), and S -> ...
  685.  
  686. FF6A: 0A18           SLA  R8,1
  687. FF6C: 1702           JNC  >FF72
  688. FF6E: 022A 0009      AI   R10,>0009     ; line 9 : 9, etc.
  689.  
  690. FF72: 028A 0030      CI   R10,>0030     ; no hole -> space
  691. FF76: 1602           JNE  >FF7C
  692. FF78: 020A 0020      LI   R10,>0020
  693.  
  694. FF7C: 028A 0053      CI   R10,>0053     ; 0
  695. FF80: 1602           JNE  >FF86
  696. FF82: 020A 0030      LI   R10,>0030
  697.  
  698. FF86: 028A 0055      CI   R10,>0055
  699. FF8A: 1101           JLT  >FF8E
  700. FF8C: 064A           DECT R10
  701.  
  702. FF8E: 1F0F           TB   >000F
  703. FF90: 13FE           JEQ  >FF8E         ; wait for device ready ?
  704. FF92: 1010           JMP  >FFB4         ; goto character decode routine
  705.  
  706. ; we jump there if no card is inserted (?) when reading from the card reader located at >020
  707. FF94: 828A           C    R10,R10
  708. FF96: 1017           JMP  >FFC6
  709.  
  710. ; read routine
  711. ; Read ASCII character from 733 ASR located at >000 or MDU unit located at >FF0, and translate it to
  712. ; one hexadecimal number.
  713. FF98: 1F0C           TB   >000C         ; wait for incoming character ?
  714. FF9A: 16FE           JNE  >FF98
  715. FF9C: 1E0C           SBZ  >000C         ; clear
  716. FF9E: 35CA           STCR R10,7         ; read ASCII character
  717. FFA0: 098A           SRL  R10,8
  718. FFA2: 028A 000D      CI   R10,>000D
  719. FFA6: 130F           JEQ  >FFC6         ; exit if CR
  720. FFA8: 028A 005A      CI   R10,>005A     ; if higher than 'Z'
  721. FFAC: 15F5           JGT  >FF98
  722. FFAE: 028A 0020      CI   R10,>0020     ; or lower than ' '
  723. FFB2: 11F2           JLT  >FF98         ; try again
  724. FFB4: A1CA           A    R10,R7        ; add R10 to checksum in R7 (?)
  725. FFB6: 022A FFD0      AI   R10,>FFD0     ; substract '0'
  726. FFBA: 028A 000A      CI   R10,>000A     ; if character is ':'
  727. FFBE: 1306           JEQ  >FFCC         ; jump to boot routine
  728. FFC0: 1102           JLT  >FFC6
  729. FFC2: 022A FFF9      AI   R10,>FFF9     ; substract 7 for 'A'-'F' to give hexadecimal digit
  730. FFC6: 069B           BL   *R11          ; return and restore R11 to point to >FFC8 (!)
  731.  
  732. ; entry point for the routine which reads data from the boot device
  733. FFC8: 10AD           JMP  >FF24
  734.  
  735. FFCA: 0340           IDLE               ; stop the machine
  736.  
  737. ; entry point for the ':' command (parameter-less command)
  738. ; jump to external boot routine
  739. FFCC: C000           MOV  R0,R0
  740. FFCE: 1608           JNE  >FFE0
  741. FFD0: 1E0B           SBZ  >000B         ; clean up the ASR status ?
  742. FFD2: 1E0C           SBZ  >000C
  743. FFD4: 0581           INC  R1
  744. FFD6: 16FE           JNE  >FFD4
  745. FFD8: 1F0C           TB   >000C
  746. FFDA: 13F8           JEQ  >FFCC
  747. FFDC: 1E09           SBZ  >0009
  748. FFDE: 1E0D           SBZ  >000D
  749.  
  750. FFE0: 0360           RSET               ; reset peripherals
  751. FFE2: 0453           B    *R3           ; jumps to boot routine specified by >1 or >2 command
  752.                                         ; (jumps to >FFCA if no routine was specified)
  753.  
  754.  
  755. ; offset table for jumps in object code interpreter, used on >FEE2 (offsets relative to >FEE2)
  756. FFE4: 302C 2A04      BYTE >FF12->FEE2, >FF0E->FEE2, >FF0C->FEE2, >FEE6->FEE2
  757. FFE8: 0404 041A      BYTE >FEE6->FEE2, >FEE6->FEE2, >FEE6->FEE2, >FEFC->FEE2
  758. FFEC: E60C 0A12      BYTE >FEC8->FEE2, >FEEE->FEE2, >FEEC->FEE2, >FEF4->FEE2
  759. FFF0: 1022 1E00      BYTE >FEF2->FEE2, >FF04->FEE2, >FF00->FEE2, >00
  760. FFF4: 0404 30E6      BYTE >FEE6->FEE2, >FEE6->FEE2, >FF12->FEE2, >FEC8->FEE2
  761.  
  762.  
  763. ; pointers to routines
  764. FFF8: FE86           DATA >FE86         ; boot loader
  765. FFFA: FEC6           DATA >FEC6            ; boot loader for MDU (?)
  766.  
  767. ; LOAD vector
  768. FFFC: F800 FE00      DATA >F800,>FE00
  769.  
  770.  
  771.