home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.tar / ftp.whtech.com / ti-990 / TI990_10_universal.txt < prev    next >
Text File  |  2006-10-19  |  34KB  |  725 lines

  1. ; TI990/10 LOAD ROMs disassembly
  2. ;
  3. ;General background :
  4. ; These ROMs contain the handler for the LOAD/RESTART interrupt.  This interrupt is called at
  5. ; start-up (instead of RESET, which is used for "warm reset", I think), so that the boot loader in
  6. ; ROMs can be executed.
  7. ;
  8. ; This interrupt can also be triggered by the programmer panel, and there is code to handle the
  9. ; panel functions.
  10. ;
  11. ;Description :
  12. ; We have 1kb of ROMs (4 256*8 ROMs).
  13. ;
  14. ; If you want a starting point, you can have a look at the LOAD vector located at >FFFC.
  15. ; The LOAD routine starts at >FC00.
  16. ;
  17. ; The ROMs are obviously an instance of the "universal ROM loader" as described in the
  18. ; Model 990 Universal ROM Loader User's Guide.  As such, the boot loader is identical to the TI990/12
  19. ; loader.  You should read the Universal ROM Loader User's Guide before reading the disassembly.
  20. ;
  21. ; The ROM basically do the following :
  22. ; * handle programmer panel functions if applicable
  23. ; * perform minimal self-test (compute ROM checksum)
  24. ; * look for a MDU, and boot from it if present
  25. ; * if programmer panel disabled, boot from the first tape/disk unit it finds (using a MT3200/WD900
  26. ;  controller or equivalent)
  27. ; * if programmer panel enabled, boot from the unit designated in RO/R1/R2 (either ASR tape,
  28. ;  FD800 single-sided disk, or tape/disk based on a MT3200/WD900 controller or equivalent)
  29. ;
  30. ;Conventions used :
  31. ; TMS9900 assembly conventions should have been respected.  Particularily :
  32. ; * bit are numbered from MSB to LSB (unlike almost every other CPU)
  33. ;
  34. ; Raphael Nabet, 2000/04/24
  35. ;
  36. ; revision history :
  37. ; 2000/04/24 : initial release
  38.  
  39. ; LOAD vector entry point
  40. FC00: 020C 1FE0      LI   R12,>1FE0     ; programmer panel CRU base
  41. FC04: 0221 6700      AI   R1,>6700      ; look for magical value (>9900)
  42. FC08: 1602           JNE  >FC0E         ; continue with normal vector if not found
  43. FC0A: 1D0A           SBO  >000A         ; switch "Run" light on
  44. FC0C: 0450           B    *R0           ; branch to routine if found
  45.  
  46. FC0E: 0209 00A0      LI   R9,>00A0      ; R9 points to free area in RAM ?
  47. FC12: 0700           SETO R0            ; R0 < 0 : use TILINE unit (tape, FD1000, hard disk) by default
  48. FC14: 0201 F800      LI   R1,>F800      ; TILINE address for default disk unit
  49. FC18: 0202 0800      LI   R2,>0800      ; if programmer panel enabled, boot from drive unit 0 by default
  50. FC1C: 1F0B           TB   >000B
  51. FC1E: 133B           JEQ  >FC96         ; if programmer panel disabled, jump to self-test
  52.  
  53. FC20: C10E           MOV  R14,R4        ; load old PC to display it
  54.  
  55. ; programmer panel scan : we have 4 rows of 8 switches
  56. ; 16 switches allow to toggle the display in R4.
  57. ; the 16 other switches allow to access programmer panel functions.
  58. ;
  59. ; register conventions here :
  60. ; R4 = data register
  61. ; R7 = memory address register
  62. ; R13 = WP
  63. ; R14 = PC
  64. ; R15 = ST
  65.  
  66. ; keyscan loop start
  67. FC22: 3204           LDCR R4,8          ; display data register MSB
  68. FC24: 3220 0089      LDCR @>0089,8      ; display data register LSB
  69.  
  70. FC28: 0205 FC8C      LI   R5,>FC8C      ; read current 8 switches from programmer panel to R3 MSB
  71. FC2C: 0695           BL   *R5           ; wait for all switches to be released
  72. FC2E: 16FE           JNE  >FC2C
  73. FC30: 0695           BL   *R5           ; test again to fix switch bounce problems
  74. FC32: 16FC           JNE  >FC2C
  75. FC34: 0695           BL   *R5           ; again
  76. FC36: 16FA           JNE  >FC2C
  77. FC38: 04C3           CLR  R3
  78. FC3A: 1D08           SBO  >0008         ; "Increment scan" bit -> select another row of switches
  79. FC3C: 0695           BL   *R5
  80. FC3E: 13FD           JEQ  >FC3A         ; if no switch pressed, scan next row
  81. FC40: 0695           BL   *R5
  82. FC42: 13FB           JEQ  >FC3A         ; fixes switch bounce problems
  83. FC44: 0695           BL   *R5
  84. FC46: 13F9           JEQ  >FC3A         ; again
  85.  
  86. FC48: 1F09           TB   >0009         ; scan count bit 0 -> is current switch row number odd or even ?
  87. FC4A: 1601           JNE  >FC4E
  88. FC4C: 06C3           SWPB R3            ; if odd, we read last 8 switches in 16 switches, so we rotate 8 bits
  89. FC4E: 1F08           TB   >0008         ; scan count bit 1 -> is this command switches or data switches ?
  90. FC50: 1302           JEQ  >FC56         ; command switches -> jump to interpret command
  91. FC52: 2903           XOR  R3,R4         ; data switches -> toggle the data on display as requested
  92. FC54: 10E6           JMP  >FC22         ; update display and go back to scan routine
  93.  
  94. FC56: 04C5           CLR  R5
  95. FC58: 05C5           INCT R5
  96. FC5A: 0A13           SLA  R3,1
  97. FC5C: 17FD           JNC  >FC58         ; count first bit set to 1 in R3, i.e. first switch pressed
  98. FC5E: 04A5 FC62      X    @>FC62(R5)    ; execute command as needed
  99. FC62: 10DF           JMP  >FC22         ; jump to display value if the X instruction did not jump
  100.  
  101. ; Programmer panel instruction table.
  102. ; All jump offsets must be relative to FC62 since this is the value of PC when the instruction
  103. ; is executed.
  104. FC64: 1013           JMP  *+>FC88->FC62 ; "Halt/SIE" switch
  105. FC66: 1011           JMP  *+>FC84->FC62 ; "Run" switch
  106. FC68: 0360           RSET               ; "Reset" switch
  107. FC6A: 101A           JMP  *+>FC96->FC62 ; "Load" switch
  108. FC6C: C10D           MOV  R13,R4        ; "Display WP" switch
  109. FC6E: C10E           MOV  R14,R4        ; "Display PC" switch
  110. FC70: C10F           MOV  R15,R4        ; "Display ST" switch
  111. FC72: C107           MOV  R7,R4         ; "Display MA" switch
  112. FC74: C344           MOV  R4,R13        ; "Enter WP" switch
  113. FC76: C384           MOV  R4,R14        ; "Enter PC" switch
  114. FC78: C3C4           MOV  R4,R15        ; "Enter ST" switch
  115. FC7A: C1C4           MOV  R4,R7         ; "Enter MA" switch
  116. FC7C: C117           MOV  *R7,R4        ; "MDD" switch ("Memory Data Display")
  117. FC7E: 05C7           INCT R7            ; "MAI" switch ("Memory Address Increment")
  118. FC80: C5C4           MOV  R4,*R7        ; "MDE" switch ("Memory Data Enter")
  119. FC82: 04C4           CLR  R4            ; "CLR" switch
  120.  
  121. ; Code for run switch
  122. FC84: 1D0A           SBO  >000A         ; switch "Run" light on
  123. FC86: 0380           RTWP               ; return to interrupt point
  124.  
  125. ; code for "Halt/SIE" switch
  126. FC88: 1D0E           SBO  >000E         ; set "Single Instruction Execute"
  127. FC8A: 0380           RTWP               ; Restart trap will occur after 2 instructions
  128. ; The second instruction executed will be an instruction from the program we interrupted.
  129. ; Pressing the HALT/SIE switch repetitively, you will trace the current program.
  130.  
  131.  
  132. ; this routine read a row of 8 switches from the programmer panel
  133. FC8C: 1D0D           SBO  >000D         ; start panel timer
  134. FC8E: 1F0A           TB   >000A         ; wait for timer active bit to be set
  135. FC90: 16FE           JNE  >FC8E
  136. FC92: 3603           STCR R3,8          ; retrieve value
  137. FC94: 045B           B    *R11
  138.  
  139.  
  140. ; Self-test routine
  141. ; compute ROM checksum for address range >FC00->FFF3, and compare it with value in >FFF4.
  142. FC96: 020B AAAA      LI   R11,>AAAA
  143. FC9A: 0205 FC00      LI   R5,>FC00
  144. FC9E: 2AF5           XOR  *R5+,R11
  145. FCA0: 0B1B           SRC  R11,1
  146. FCA2: 0285 FFF4      CI   R5,>FFF4
  147. FCA6: 16FB           JNE  >FC9E
  148. FCA8: 854B           C    R11,*R5       ; compare with checksum at >FFF4
  149. FCAA: 130E           JEQ  >FCC8         ; jump to boot if OK
  150. FCAC: 1D0A           SBO  >000A
  151. FCAE: 0703           SETO R3
  152. FCB0: 0460 FFA4      B    @>FFA4        ; stop in error
  153.  
  154.  
  155. ; Real boot routine, called after the CPU self-test
  156. ;
  157. ; We can load from several devices : MDU (Maintenance Diagnostics Unit, with a tape reader),
  158. ; ASR (a data terminal with optionnal tape reader), a single-sided disk (dumb controller on CRU bus),
  159. ; a tape unit with MT3200 controller, a double-sided floppy disk or a hard disk with WD900 controller
  160. ; (intelligent controllers on TI-LINE memory bus).
  161. ;
  162. ; tape units (MDU, ASR and MT3200) use some object code encoded with alphanumeric and hexadecimal
  163. ; characters.
  164. ; Single-sided floppy uses a simple boot routine to fetch a binary start-up program.
  165. ; The routine for double-sided floppies and hard-disk is somewhat more complex.
  166.  
  167.  
  168. ; offset table for jumps in object code interpreter, used on >FD42 (offsets relative to >FD42)
  169. FCB4: 302C 2A04      BYTE >FD72->FD42,>FD6E->FD42,>FD6C->FD42,>FD46->FD42
  170. FCB8: 0404 041A      BYTE >FD46->FD42,>FD46->FD42,>FD46->FD42,>FD5C->FD42
  171. FCBC: E60C 0A12      BYTE >FD28->FD42,>FD4E->FD42,>FD4C->FD42,>FD54->FD42
  172. FCC0: 1022 1E00      BYTE >FD52->FD42,>FD64->FD42,>FD60->FD42,>00
  173. FCC4: 0404 30E6      BYTE >FD46->FD42,>FD46->FD42,>FD72->FD42,>FD28->FD42
  174.  
  175.  
  176. ; actual boot routine
  177. FCC8: 0360           RSET               ; RESET external peripherals
  178. FCCA: 0203 FE94      LI   R3,>FE94      ; address of the start-up routine we jump to - defaults to error routine
  179. FCCE: 0205 F7FE      LI   R5,>F7FE      ; last word before system memory space
  180. FCD2: C381           MOV  R1,R14        ; if programmer panel enabled, TILINE peripheral to boot from
  181. FCD4: C3C2           MOV  R2,R15        ; if programmer panel enabled, unit to load from
  182.  
  183. ; simple memory test >F7FE -> >0000
  184. FCD6: C555           MOV  *R5,*R5       ; try to read and write current word
  185. FCD8: 0645           DECT R5
  186. FCDA: 18FD           JOC  >FCD6         ; loop until we wrap around to >FFFE
  187.  
  188. ; now real boot
  189. FCDC: 1D0A           SBO  >000A         ; switch "Run" light on
  190. FCDE: 1F0E           TB   >000E         ; this bit must tell a MDU is present
  191. FCE0: 1302           JEQ  >FCE6         ; jump if not present
  192. FCE2: 04C0           CLR  R0
  193. FCE4: 101D           JMP  >FD20         ; boot from the MDU ?
  194.  
  195. FCE6: C000           MOV  R0,R0         ; read boot device type (defaults to -1)
  196. FCE8: 114E           JLT  >FD86         ; boot from TILINE tape or disk device (FD1000, hard disk...)
  197. FCEA: 154C           JGT  >FD84         ; boot from FD800 single-sided floppy disk
  198. ; if (R0 == 0), boot from ASR terminal
  199. FCEC: 04CC           CLR  R12           ; device address >000 : 733 ASR
  200. FCEE: 1D09           SBO  >0009         ; set-up device
  201. FCF0: 1D0A           SBO  >000A
  202. FCF2: 3220 FE8A      LDCR @>FE8A,8      ; effectively writes >11
  203.  
  204. ; entry point to boot from TILINE tape unit (MT3200 controller or equivalent)
  205. FCF6: 04CD           CLR  R13
  206. FCF8: C000           MOV  R0,R0
  207. FCFA: 1312           JEQ  >FD20         ; skip if booting from ASR
  208. FCFC: C183           MOV  R3,R6         ; save R3, R5
  209. FCFE: C285           MOV  R5,R10
  210. FD00: 04C0           CLR  R0            ; meaningless
  211. FD02: 04C1           CLR  R1            ; meaningless
  212. FD04: 04C2           CLR  R2            ; read offset = 0 (read record from the beginning)
  213. FD06: 0203 0050      LI   R3,>0050      ; char count = >0050 (max record lenght = 80 chars)
  214.                                         ; It seems that we cannot have more than 80 bytes of code !
  215. FD0A: 04C4           CLR  R4            ; load at address 0
  216. FD0C: 0205 0400      LI   R5,>0400      ; >4 : read binary forward command
  217. FD10: E14F           SOC  R15,R5        ; set unit ID
  218. FD12: 06A0 FF54      BL   @>FF54        ; execute command on tape unit
  219. FD16: D920 FE6F 0050 MOVB @>FE6F,@>0050(R4) ; append carriage return after the data we read (@>FE6F = >0D)
  220. FD1C: C0C6           MOV  R6,R3         ; restore R3, R5
  221. FD1E: C14A           MOV  R10,R5
  222.  
  223. ; entry point to boot from MDU
  224. FD20: 020B FE92      LI   R11,>FE92     ; pointer to read routine
  225. FD24: 04C7           CLR  R7            ; clear checksum
  226. FD26: 058D           INC  R13
  227.  
  228. ; object code interpreter
  229. ;
  230. ; ASR, MDU and MT3200 tapes use object code, as described in the Model 990 Computer Programming Card.
  231. ;
  232. ; We receive characters from the boot device.  These are interpreted as commands or as hexadecimal
  233. ; immediate operands.  Note that we actually only use hexadecimal characters, and 'G','H',':'.
  234. ;
  235. ; Commands with 16-bit immediate (encoded in hexadecimal) :
  236. ; * '1' : Absolute Entry Address : boot routine address = IMM
  237. ; * '2' : Relocatable Entry Address : boot routine address = offset + IMM
  238. ; * '7' : Checksum : stops the machine if (sum of all data received since start of record) + IMM != 0
  239. ; * '9' : Absolute Load Address : memory address pointer = IMM
  240. ; * 'A' : Relocatable Load Address : memory address pointer = offset + IMM
  241. ; * 'B' : Absolute Data : * (memory address pointer ++) = IMM
  242. ; * 'C' : Relocatable Data : * (memory address pointer ++) = offset + IMM
  243. ; * 'D' : Load Bias Or Offset : offset = IMM
  244. ; * 'E' : (no reference) : stop the machine
  245. ;
  246. ; Control commands (parameter-less) :
  247. ; * ':' : (no reference) : branch to boot routine address
  248. ; * 'F' : End Of Record : wait for next card to be inserted (does not really work)
  249. ;
  250. ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) :
  251. ; * '8' : Ignore Checksum Value : does nothing
  252. ; * 'J' : (no reference)
  253. ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) and 6-char symbol name :
  254. ; * '3', '4', '5', '6', 'G', 'H' (symbol-related commands)
  255. ; Unsupported commands with 16-bit immediate (encoded in hexadecimal) and 8-char program name :
  256. ; * '0' : Program Start
  257. ; * 'I' : (no reference)
  258. ;
  259. FD28: 069B           BL   *R11          ; read command number in R10 from tape (range 0-19)
  260. FD2A: D0AA FCB4      MOVB @>FCB4(R10),R2    ; read offset to routine in table
  261. FD2E: 1327           JEQ  >FD7E         ; handle 'F' command separately because it is parameter-less
  262. FD30: 0882           SRA  R2,8          ; convert to signed 16-bit offset
  263. FD32: C207           MOV  R7,R8         ; save checksum
  264. FD34: 0201 0004      LI   R1,>0004      ; 4*4 = 16 bits to read
  265. FD38: 069B           BL   *R11          ; read hex digit (4 bits)
  266. FD3A: 0A46           SLA  R6,4          ; shift digits we have already read
  267. FD3C: A18A           A    R10,R6        ; and insert new digit in R6
  268. FD3E: 0601           DEC  R1
  269. FD40: 16FB           JNE  >FD38         ; loop until we have read a 16-bit hex value
  270. FD42: 0462 FD42      B    @>FD42(R2)    ; jump to routine
  271.  
  272. ; entry point for '3', '4', '5', '6','G','H'
  273. ; read 6 additional characters and ignore them
  274. FD46: 0201 0006      LI   R1,>0006      ; read 6 chars
  275. FD4A: 1015           JMP  >FD76
  276.  
  277. ; entry point for 'A'
  278. ; add offset to R6, set address pointer
  279. FD4C: A189           A    R9,R6         ; add offset to R6 (R9 set by 'D' command, defaults to >00A0)
  280. ; entry point for '9'
  281. ; set address pointer
  282. FD4E: C146           MOV  R6,R5
  283. FD50: 10EB           JMP  >FD28         ; next command
  284.  
  285. ; entry point for 'C'
  286. ; add offset to R6, write two bytes
  287. FD52: A189           A    R9,R6
  288. FD54: DD46           MOVB R6,*R5+
  289. ; entry point for 'B'
  290. ; write two bytes
  291. FD56: 06C6           SWPB R6
  292. FD58: DD46           MOVB R6,*R5+
  293. FD5A: 10E6           JMP  >FD28
  294.  
  295. ; entry point for '7'
  296. ; check checksum
  297. FD5C: A206           A    R6,R8
  298. FD5E: 13E4           JEQ  >FD28         ; continue on if value matches checksum
  299. ; entry point for 'E'
  300. ; boot failure
  301. FD60: 046B 0002      B    @>0002(R11)   ; jump to >FE94 (stop machine and blink fail LED)
  302.  
  303. ; entry point for 'D'
  304. ; set bias/offset
  305. FD64: C246           MOV  R6,R9         ; set bias/offset value
  306. FD66: 0249 FFFE      ANDI R9,>FFFE      ; convert to word address
  307. FD6A: 10DE           JMP  >FD28
  308.  
  309. ; entry point for '2'
  310. ; add offset to R6, set boot routine address
  311. FD6C: A189           A    R9,R6
  312. ; entry point for '1'
  313. ; set boot routine address
  314. FD6E: C0C6           MOV  R6,R3         ; set boot routine address
  315. FD70: 10DB           JMP  >FD28
  316.  
  317. ; entry point for '0','I'
  318. ; read 8 additionnal characters and ignore them
  319. FD72: 0201 0008      LI   R1,>0008      ; read 8 chars
  320. FD76: 069B           BL   *R11
  321. FD78: 0601           DEC  R1
  322. FD7A: 16FD           JNE  >FD76
  323. FD7C: 10D5           JMP  >FD28
  324.  
  325. ; entry point for 'F' command (parameter-less)
  326. ; wait for next record
  327. FD7E: 069B           BL   *R11
  328. FD80: 16FE           JNE  >FD7E         ; wait for next record
  329. FD82: 10BA           JMP  >FCF8
  330.  
  331.  
  332. ; branch point to routine at >FDEE
  333. FD84: 1034           JMP  >FDEE
  334.  
  335.  
  336. ; Boot from a tape/disk unit using MD900/MT3200 controller or equivalent on the TILINE bus
  337. ;
  338. ; When programmer panel is available, the routine expect the unit mask to be in R15.
  339. ;
  340. ; When programmer panel is unavailable, the routine scans tape units 0-3, then disk units 0-3.
  341. ; It generally boots on the first unit which is ready ; however, when possible, it does not boot from
  342. ; a writable disk.  The resulting priority order is : tape #0, ..., tape #3,
  343. ; disk #0 (write-protected), ..., disk #3 (write-protected),
  344. ; disk #0 (writable), ..., disk #3 (writable).  When no unit is ready, it keeps scanning
  345. ; all units continuously, so that the user can insert a boot disk/tape after start-up.
  346. ;
  347. ; R1 = >F800 (?)
  348. ; R2 = >0800 (?)
  349.  
  350. FD86: 04CD           CLR  R13
  351. FD88: 1F0B           TB   >000B         ; programmer panel...
  352. FD8A: 1306           JEQ  >FD98         ; if disabled, try each unit until we find a bootable one
  353.  
  354. FD8C: C10F           MOV  R15,R4        ; current unit mask : 1 (and only 1) bit must be set
  355. FD8E: 0A44           SLA  R4,4
  356. FD90: 13B2           JEQ  >FCF6         ; routine for tape unit
  357. FD92: 102C           JMP  >FDEC         ; routine for disk unit
  358.  
  359.  
  360. ; we end here when no tape or writable disk could be found.
  361. ; R13 may contain the ID of some write-protected disk.
  362. FD94: C3CD           MOV  R13,R15       ; restore unit ID from R13
  363. FD96: 162A           JNE  >FDEC         ; jump to boot routine if non-zero
  364.                                         ; else, we start over, until someone insert a disk/tape
  365.  
  366. ; Find a bootable tape/disk on the TILINE bus
  367. FD98: 020C 1FC0      LI   R12,>1FC0     ; Error interrupt register CRU base
  368. FD9C: 020F 0001      LI   R15,>0001
  369. FDA0: 020E F880      LI   R14,>F880     ; TILINE base address for MT3200 tape controller
  370.  
  371. FDA4: 1E0F           SBZ  >000F         ; clear TIMEOUT (i.e. unimplemented memory)
  372. FDA6: 0B1F           SRC  R15,1         ; try next unit (try >8000 first, then >4000, etc)
  373. FDA8: 808F           C    R15,R2        ; compare with >0800 (support for up to 4 tape units)
  374. FDAA: 1B03           JH   >FDB2         ; jump if greater than >0800
  375.  
  376. FDAC: C381           MOV  R1,R14        ; else use WD900 disk unit at base address >F800
  377. FDAE: D3CF           MOVB R15,R15       ; if R15 MSByte is NULL, we are done
  378. FDB0: 13F1           JEQ  >FD94         ; jump to boot from writable disk, or retry
  379.  
  380. FDB2: C21E           MOV  *R14,R8       ; load disc status
  381. FDB4: 1F0F           TB   >000F         ; test RAM TIMEOUT
  382. FDB6: 13F6           JEQ  >FDA4         ; try next unit if no controller found on bus
  383.  
  384. FDB8: C22E 000E      MOV  @>000E(R14),R8    ; load controller status
  385. FDBC: 1101           JLT  >FDC0         ; wait for IDLE status bit to be cleared
  386. FDBE: 10FC           JMP  >FDB8
  387.  
  388. FDC0: 04DE           CLR  *R14          ; clear disc status
  389. FDC2: CB8F 000C      MOV  R15,@>000C(R14)   ; select unit
  390. FDC6: 808F           C    R15,R2
  391. FDC8: 1204           JLE  >FDD2         ; skip 2 instructions if using disk unit
  392. FDCA: EB82 000C      SOC  R2,@>000C(R14)    ; bits 4-7 = >8 : read transport status command
  393. FDCE: 04EE 000E      CLR  @>000E(R14)   ; clear controller status
  394.  
  395. FDD2: 0206 5E00      LI   R6,>5E00
  396. FDD6: 0606           DEC  R6
  397. FDD8: 16FE           JNE  >FDD6         ; wait for about 10 or 20ms
  398.  
  399. FDDA: C21E           MOV  *R14,R8       ; read disk or tape transport status
  400. FDDC: 11E3           JLT  >FDA4         ; try next unit if off-line status bit set (no unit or no tape/disk)
  401. FDDE: 808F           C    R15,R2
  402. FDE0: 1B8A           JH   >FCF6         ; if this is a tape unit, jump to object code interpreter
  403. FDE2: C34D           MOV  R13,R13
  404. FDE4: 1601           JNE  >FDE8
  405. FDE6: C34F           MOV  R15,R13       ; save R15 in R13 if it is the first bootable unit found
  406. FDE8: 0A38           SLA  R8,3
  407. FDEA: 17DC           JNC  >FDA4         ; try next unit if the disk is not write-protected (?)
  408. FDEC: 1061           JMP  >FEB0         ; jump to disk boot routine if the disk is write-protected (?)
  409.  
  410.  
  411. ; Complete boot routine to boot from a single-sided diskette
  412. ; Boots from FD800 unit at CRU address >80->A0 (i.e. >40->50)
  413. FDEE: 020C 00A0      LI   R12,>00A0     ; CRU base address for command register ?
  414. FDF2: 0702           SETO R2            ; R2 = >FFFF
  415. FDF4: 04C3           CLR  R3
  416. FDF6: 3408           STCR R8,16         ; read 16 bits
  417. FDF8: 1502           JGT  >FDFE
  418. FDFA: 0A68           SLA  R8,6          ; if negative, test CRU bit >A5
  419. FDFC: 1814           JOC  >FE26         ; if bit set, start over
  420.  
  421. FDFE: 1F0A           TB   >000A
  422. FE00: 13FE           JEQ  >FDFE         ; wait for something
  423. FE02: 3002           LDCR R2,16         ; write all 1s
  424. FE04: 0208 E000      LI   R8,>E000
  425. FE08: E203           SOC  R3,R8
  426. FE0A: 1F0A           TB   >000A
  427. FE0C: 13FE           JEQ  >FE0A         ; wait again
  428. FE0E: 3008           LDCR R8,16         ; write track number ???
  429. FE10: 1F0F           TB   >000F
  430. FE12: 16FE           JNE  >FE10
  431. FE14: 3408           STCR R8,16         ; read 16 bits
  432. FE16: 0248 1BFC      ANDI R8,>1BFC
  433. FE1A: 1306           JEQ  >FE28         ; start boot
  434. FE1C: 0223 0400      AI   R3,>0400
  435. FE20: 0283 1000      CI   R3,>1000
  436. FE24: 1AEE           JL   >FE02
  437. FE26: 10E3           JMP  >FDEE         ; start over
  438.  
  439.  
  440. FE28: 020C 0080      LI   R12,>0080     ; CRU base address for data register ?
  441. FE2C: C289           MOV  R9,R10        ; R9 points to free area in RAM ?
  442.  
  443. FE2E: 0201 0080      LI   R1,>0080      ; 256 bytes (= 128 words) in a data cluster ?
  444.  
  445. FE32: 1F11           TB   >0011         ; data present bit (?)
  446. FE34: 1306           JEQ  >FE42
  447. FE36: 1F1A           TB   >001A         ; device error bit (?)
  448. FE38: 13FC           JEQ  >FE32
  449. FE3A: 020C 00A0      LI   R12,>00A0
  450. FE3E: 3403           STCR R3,16
  451. FE40: 102A           JMP  >FE96         ; stop the machine in error
  452.  
  453. FE42: 343A           STCR *R10+,16      ; read 16 bits
  454. FE44: 1E0F           SBZ  >000F
  455. FE46: 0641           DECT R1
  456. FE48: 15F4           JGT  >FE32         ; loop until read 256 bytes
  457.  
  458. FE4A: 064A           DECT R10           ; point to last word
  459. FE4C: 809A           C    *R10,R2       ; compare last word with >FFFF mark
  460. FE4E: 16EF           JNE  >FE2E         ; if different, keep 254 previous bytes and append another sector (?)
  461.  
  462. FE50: 0360           RSET               ; else, jump to boot routine
  463. FE52: 0200 FEC8      LI   R0,>FEC8
  464. FE56: CE43           MOV  R3,*R9+       ; write device number
  465. FE58: 0459           B    *R9           ; execute boot routine at offset 2
  466.  
  467.  
  468. ; read routine
  469. ; Read ASCII character from 733 ASR located at >000, a MDU unit located at >FF0, or a MT3200 tape unit
  470. ; on TILINE bus, and translate it to one hexadecimal number.
  471. FE5A: C000           MOV  R0,R0         ; test device type flag
  472. FE5C: 1105           JLT  >FE68         ; jump if MT3200
  473.  
  474. FE5E: 1F0C           TB   >000C
  475. FE60: 16FE           JNE  >FE5E         ; wait...
  476.  
  477. FE62: 1E0C           SBZ  >000C
  478. FE64: 35CA           STCR R10,7         ; read 7 bits
  479. FE66: 1001           JMP  >FE6A
  480.  
  481.  
  482. FE68: D2B4           MOVB *R4+,R10      ; read byte from memory (MT3200 is DMA driven)
  483.  
  484. FE6A: 098A           SRL  R10,8         ; move MSB to LSB
  485. FE6C: 028A 000D      CI   R10,>000D     ; carriage return ? (appended at end of MT3200 record)
  486. FE70: 130F           JEQ  >FE90         ; if so return
  487. FE72: 028A 005A      CI   R10,>005A     ; greater than 'Z' ?
  488. FE76: 15F1           JGT  >FE5A         ; if so, ignore current char and read next char
  489. FE78: 028A 0020      CI   R10,>0020     ; control character (lower than ' ') ?
  490. FE7C: 11EE           JLT  >FE5A         ; if so, ignore current char and read next char
  491. FE7E: A1CA           A    R10,R7        ; update checksum
  492. FE80: 022A FFD0      AI   R10,>FFD0     ; substract >30 (numeric character -> numeric value)
  493. FE84: 028A 000A      CI   R10,>000A
  494. FE88: 1307           JEQ  >FE98         ; jump to handler if it is ':'
  495. FE8A: 1102           JLT  >FE90         ; if greater, it must be 'A'-'F'
  496. FE8C: 022A FFF9      AI   R10,>FFF9     ; convert to hex value
  497. FE90: 069B           BL   *R11          ; trick : return to the caller AND restore R11 to be >FE92
  498.  
  499. ; read routine entry point
  500. FE92: 10E3           JMP  >FE5A
  501.  
  502. ; entry point for bad ':' (called when no '1' command has been executed before ':')
  503. FE94: C0CD           MOV  R13,R3
  504. FE96: 1057           JMP  >FF46
  505.  
  506. ; handler for ':' command
  507. FE98: C000           MOV  R0,R0         ; test boot device type flag
  508. FE9A: 1608           JNE  >FEAC
  509.  
  510. FE9C: 1E0B           SBZ  >000B         ; clean-up ?
  511. FE9E: 1E0C           SBZ  >000C
  512. FEA0: 0581           INC  R1
  513. FEA2: 16FE           JNE  >FEA0
  514. FEA4: 1F0C           TB   >000C
  515. FEA6: 13F8           JEQ  >FE98
  516. FEA8: 1E09           SBZ  >0009
  517. FEAA: 1E0D           SBZ  >000D
  518.  
  519. FEAC: 0360           RSET               ; reset all peripherals
  520. FEAE: 0453           B    *R3           ; jump to boot routine
  521.  
  522.  
  523. ; boot from a disk unit attached to a WD900 disk controller (or equivalent) whose address is in R14
  524. FEB0: C14F           MOV  R15,R5        ; unit ID
  525. FEB2: 020C FF54      LI   R12,>FF54
  526. FEB6: 020D 0005      LI   R13,>0005     ; retry count ?
  527.  
  528. FEBA: 0200 0700      LI   R0,>0700      ; restore command
  529. FEBE: 04C1           CLR  R1
  530. FEC0: 069C           BL   *R12
  531.  
  532. FEC2: 04C0           CLR  R0            ; store register command
  533. FEC4: 0203 0006      LI   R3,>0006      ; command returns 6 bytes
  534. FEC8: 0204 0200      LI   R4,>0200      ; free area in RAM
  535. FECC: 069C           BL   *R12
  536. FECE: C2A4 0004      MOV  @>0004(R4),R10
  537. FED2: 09BA           SRL  R10,11        ; keep number of track per cylinder (i.e. number of heads)
  538.  
  539. FED4: 0200 0400      LI   R0,>0400      ; read unformatted
  540. FED8: 04C2           CLR  R2            ; cylinder 0
  541. FEDA: 069C           BL   *R12          ; read current track/cylinder address, # of sectors per record, and sector lenght
  542.  
  543. FEDC: C004           MOV  R4,R0         ; >0200 : read data
  544. FEDE: D064 0002      MOVB @>0002(R4),R1 ; set the "sectors per records" field
  545. FEE2: C0E4 0004      MOV  @>0004(R4),R3 ; count = sector lenght
  546. FEE6: 0A13           SLA  R3,1          ; word count -> byte count
  547. FEE8: 069C           BL   *R12          ; read record #0
  548. FEEA: C3E4 000E      MOV  @>000E(R4),R15    ; alternate boot program track address
  549. FEEE: 890F 0024      C    R15,@>0024(R4)    ; compare with normal program track address
  550. FEF2: 130C           JEQ  >FF0C
  551.  
  552. FEF4: C924 0024 000E MOV  @>0024(R4),@>000E(R4) ; replace alternate boot program, with normal one
  553.                                         ; so alternate program will be loaded only once
  554. FEFA: 0200 0300      LI   R0,>0300      ; write data
  555. FEFE: 069C           BL   *R12          ; write record #0
  556. FF00: C924 001C 0018 MOV  @>001C(R4),@>0018(R4) ; use alternate load point
  557. FF06: C924 001E 001A MOV  @>001E(R4),@>001A(R4) ; and alternate length
  558.  
  559. FF0C: 0200 0400      LI   R0,>0400      ; read unformatted
  560. FF10: 0203 0006      LI   R3,>0006      ; command returns 6 bytes
  561. FF14: 06A0 FF48      BL   @>FF48        ; compute cylinder/head address from track address in R15
  562. FF18: 069C           BL   *R12
  563.  
  564. FF1A: C064 0002      MOV  @>0002(R4),R1 ; set format & sector according to value read from controller
  565. FF1E: C004           MOV  R4,R0         ; >0200 : read data
  566. FF20: 06A0 FF48      BL   @>FF48
  567. FF24: C3E4 0018      MOV  @>0018(R4),R15    ; program load point
  568. FF28: C0E4 001A      MOV  @>001A(R4),R3 ; program length
  569. FF2C: 130A           JEQ  >FF42         ; fail if null
  570. FF2E: 0204 00A0      LI   R4,>00A0      ; free area in RAM ?
  571. FF32: 069C           BL   *R12          ; read boot program
  572.  
  573. FF34: 0200 ABC0      LI   R0,>ABC0      ; magical value ?
  574. FF38: C04E           MOV  R14,R1        ; boot device address
  575. FF3A: 04C2           CLR  R2
  576. FF3C: D085           MOVB R5,R2         ; unit ID
  577. FF3E: 0360           RSET               ; Reset for things to be cleaner
  578. FF40: 045F           B    *R15          ; jump to boot program
  579.  
  580. ; exit point when boot program lenght is NULL
  581. FF42: 0203 D001      LI   R3,>D001      ; load error code
  582.  
  583. FF46: 102E           JMP  >FFA4         ; stop machine and blink the Fail LED
  584.  
  585. ; compute cylinder & head address from "flat" track address
  586. ; input :
  587. ; R10 = number of heads
  588. ; R15 = track address
  589. ; returns :
  590. ; R2 = cylinder address
  591. ; R0 |= head address
  592. FF48: C24F           MOV  R15,R9
  593. FF4A: 04C8           CLR  R8
  594. FF4C: 3E0A           DIV  R10,R8        ; compute R15/R10
  595. FF4E: C088           MOV  R8,R2         ; R2 = quotient : cylinder address
  596. FF50: E009           SOC  R9,R0         ; R0 LSB = remainder : head address
  597. FF52: 045B           B    *R11
  598.  
  599.  
  600. ; execute some command on a WD900/WT3200 controller
  601. ; R0 -> W1 : command and surface register (WD900)
  602. ; R1 -> W2 : format and sector (MSByte : sectors per record ; LSByte : sector number) (WD900)
  603. ; R2 -> W3 : cylinder address (cylinder number) (WD900) / read offset (WT3200)
  604. ; R3 -> W4 : count (length to read/write)
  605. ; R4 -> W5 : address (destination/source address to read/write from, 16 LSBits)
  606. ; R5 -> W6 : WD900 : select and address (unit selection, 1 bit per unit, in LOW nibble of MSByte, and
  607. ;           4 MSBits of address in low nibble of LSByte) 
  608. ;            WT3200 : command and transport select (unit selection, 1 bit per unit, in HIGH nibble
  609. ;           of MSByte, command in high nibble of LSByte, and 4 MSBits of address in low nibble of
  610. ;           LSByte)
  611. ;
  612. ; R14 = controller address
  613. ;
  614. ; cf 990 Handbook, 5-23, page 188, and WD900/MT3200 general description, chapter 3
  615. ;
  616. FF54: C1CE           MOV  R14,R7        ; TILINE device address
  617. FF56: C227 000E      MOV  @>000E(R7),R8
  618. FF5A: 1101           JLT  >FF5E
  619. FF5C: 10FB           JMP  >FF54         ; wait for IDLE controller status bit to be cleared
  620.  
  621. ; write device registers
  622. FF5E: 04F7           CLR  *R7+          ; disc status
  623. FF60: CDC0           MOV  R0,*R7+
  624. FF62: CDC1           MOV  R1,*R7+
  625. FF64: CDC2           MOV  R2,*R7+
  626. FF66: CDC3           MOV  R3,*R7+
  627. FF68: CDC4           MOV  R4,*R7+
  628. FF6A: CDC5           MOV  R5,*R7+
  629. FF6C: 04D7           CLR  *R7
  630.  
  631. FF6E: C217           MOV  *R7,R8
  632. FF70: 1101           JLT  >FF74
  633. FF72: 10FD           JMP  >FF6E         ; wait for IDLE controller status bit to be cleared
  634.  
  635. FF74: C1C5           MOV  R5,R7
  636. FF76: 09C7           SRL  R7,12         ; 4 MSBits select unit on WT3200, and are unused on WD900
  637. FF78: 1603           JNE  >FF80         ; skip if we are using a tape unit
  638.  
  639. FF7A: C1DE           MOV  *R14,R7       ; disk status
  640. FF7C: 0A27           SLA  R7,2
  641. FF7E: 18FD           JOC  >FF7A         ; wait for NR (Not Ready) status bit to be cleared
  642.  
  643. FF80: 0248 01FF      ANDI R8,>01FF      ; test all individual error bits in controller status
  644. FF84: 1602           JNE  >FF8A         ; jump on error
  645.  
  646. FF86: 0700           SETO R0
  647. FF88: 045B           B    *R11          ; normal return
  648.  
  649. ; error handler :
  650. FF8A: C1DE           MOV  *R14,R7       ; read disk status
  651. FF8C: 11E3           JLT  >FF54         ; wait for OL (off-line) status bit to be set
  652. FF8E: C1C5           MOV  R5,R7
  653. FF90: 09C7           SRL  R7,12
  654. FF92: 1602           JNE  >FF98         ; skip if we are using a tape unit
  655.  
  656. FF94: 060D           DEC  R13
  657. FF96: 1691           JNE  >FEBA         ; do a few retries before fail ?
  658.  
  659. FF98: 0288 0001      CI   R8,>0001      ; check unit error / tape error in controller status
  660. FF9C: 1602           JNE  >FFA2         ; means an error condition is set in disk status / tape transport status
  661. FF9E: 04C8           CLR  R8
  662. FFA0: D21E           MOVB *R14,R8       ; read error code in disk status / tape transport status register
  663.  
  664. FFA2: C0C8           MOV  R8,R3         ; display either controller status or disk status / tape transport status
  665.  
  666.  
  667. ; error stop
  668. ; we jump to this routine when boot fails
  669. ; display R3 for diagnostics purpose, and blink the fail LED.
  670. FFA4: 020C 1FE0      LI   R12,>1FE0
  671. FFA8: 3203           LDCR R3,8
  672. FFAA: 3220 0087      LDCR @>0087,8
  673. FFAE: 1D0B           SBO  >000B
  674. FFB0: 05C1           INCT R1
  675. FFB2: 15FD           JGT  >FFAE
  676. FFB4: 1E0B           SBZ  >000B
  677. FFB6: 10FC           JMP  >FFB0
  678.  
  679.  
  680. ; spare room
  681. FFB8: 0000           DATA >0000
  682. FFBA: 0000           DATA >0000
  683. FFBC: 0000           DATA >0000
  684. FFBE: 0000           DATA >0000
  685. FFC0: 0000           DATA >0000
  686. FFC2: 0000           DATA >0000
  687. FFC4: 0000           DATA >0000
  688. FFC6: 0000           DATA >0000
  689. FFC8: 0000           DATA >0000
  690. FFCA: 0000           DATA >0000
  691. FFCC: 0000           DATA >0000
  692. FFCE: 0000           DATA >0000
  693. FFD0: 0000           DATA >0000
  694. FFD2: 0000           DATA >0000
  695. FFD4: 0000           DATA >0000
  696. FFD6: 0000           DATA >0000
  697. FFD8: 0000           DATA >0000
  698. FFDA: 0000           DATA >0000
  699. FFDC: 0000           DATA >0000
  700. FFDE: 0000           DATA >0000
  701. FFE0: 0000           DATA >0000
  702. FFE2: 0000           DATA >0000
  703. FFE4: 0000           DATA >0000
  704. FFE6: 0000           DATA >0000
  705. FFE8: 0000           DATA >0000
  706. FFEA: 0000           DATA >0000
  707. FFEC: 0000           DATA >0000
  708. FFEE: 0000           DATA >0000
  709. FFF0: 0000           DATA >0000
  710. FFF2: 0000           DATA >0000
  711.  
  712.  
  713. ; checksum
  714. FFF4: DDF1           DATA >DDF1
  715.  
  716. ; pointers to routines
  717. FFF6: FCCE           DATA >FCCE         ; boot loader
  718. FFF8: FCC8           DATA >FCC8         ; ditto
  719. FFFA: FD24           DATA >FD24         ; boot loader for MDU (?)
  720.  
  721. ; LOAD vector
  722. FFFC: 0080 FC00      DATA >0080,>FC00
  723.  
  724.  
  725.