; HDT C5 BOOT PROM ; commented by Holger Veit 2013 ; The file was produced from CPU-C5.BIN from bitsavers.org ; by a self-written IDA module. IDA is a software by Hexrays/Datarescue. ; ; This work is Creative Commons CC-BY-SA ; ; This is the ROM version of HDT. ; ; This ROM can boot from the built-in floppy drive ; as well as from a PRIAM QBUS HD controller. ; Functions to examine and modify memory locations ; are not present (were removed in favor of PRIAM boot code). ; Only commands 'R' and 'P' are present. ; ; Processor: WD9000 ; Target assembler: P-Code Pseudo Assembler ; Note: this is no valid assembler and not intended to be ; converted back into machine code. BOOTTIB:0000 ; File Name : C:\hv\ucsd\pdq3\simh\hdt\CPU_C5.bin BOOTTIB:0000 ; Format : Binary file BOOTTIB:0000 ; Base Address: 0000h Range: F400h - F800h Loaded length: 0400h^ BOOTTIB:0000 BOOTTIB:0000 ; This is C5 version of HDT code - this is apparently BOOTTIB:0000 ; a boot PROM which can boot from FDC and PRIAM HD BOOTTIB:0000 ; Processor: WD9000 BOOTTIB:0000 ; Target assembler: P-Code Pseudo Assembler BOOTTIB:0000 ; Segment type: Regular BOOTTIB:0000 ; START OF SEGMENT BOOTTIB:0000 .WORD $f401 ; fc68 points here - start of ROM, "MR" BOOTTIB:0002 .WORD $f404 ; MR=0: CTP BOOTTIB:0004 .WORD $f410 ; MR=1: SSV BOOTTIB:0006 .WORD $fc00 ; MR=2: RQ BOOTTIB:0008 .WORD $fc00 ; ---TIB--- BOOTTIB:0008 ; f404: waitq BOOTTIB:000A .WORD $00ff ; f405: flags/prior BOOTTIB:000C .WORD $0000 ; f406: SPlow BOOTTIB:000E .WORD $0200 ; f407: SPupr BOOTTIB:0010 .WORD $01e7 ; f408: SP BOOTTIB:0012 .WORD $01e7 ; f409: MP BOOTTIB:0014 .WORD $01e7 ; f40a: BP BOOTTIB:0016 .WORD $0368 ; f40b: IPC BOOTTIB:0018 .WORD $f418 ; f40c: SEGB BOOTTIB:001A .WORD $fc00 ; f40d: hangp BOOTTIB:001C .WORD $0000 ; f40e: iorslt BOOTTIB:001E .WORD $fc00 ; f40f: sibs - NIL: no segs > 127 BOOTTIB:0020 .WORD $fc00 ; ---Seg dictionary--- BOOTTIB:0020 ; f410 ptr to sib 00 BOOTTIB:0022 .WORD $f412 ; f411 ptr to sib 01 BOOTTIB:0024 .WORD $f418 ; f412 sib01->segbase BOOTTIB:0026 .WORD $01df ; f413 sib01->segleng BOOTTIB:0028 .WORD $0001 ; f414 sib01->segrefs BOOTTIB:002A .WORD $0000 ; f415 sib01->segaddr BOOTTIB:002C .WORD $0000 ; f416 sib01->segunit BOOTTIB:002E .WORD $0000 ; f417 seg01->prevsp BOOTTIB:002E ; END OF SEGMENT HDT:0000 ; segment global variables HDT:0000 ; global1 char received from console (input) HDT:0000 ; global2 integer 'current address' HDT:0000 ; global3 boolean flag: has a 'current address' HDT:0000 ; global4 address of console 0xfc10 HDT:0000 ; global5 temporary for TIB->SEGB address HDT:0000 ; global6-7 HDT semaphore (HDT halts on this) HDT:0000 ; global8 address of HDT info structure (0x22) HDT:0000 ; global9-16 string(16): "0123456789abcdef" HDT:0000 ; global17-22 Set of HEX chars ['0'..'9','A'..'F'] HDT:0000 HDT:0000 ; Segment type: Pure code HDT:0000 ; START OF SEGMENT HDT:0000 .WPTR proctbl ; ptr to proctbl HDT:0002 ; HDT:0002 ; procedure bootfd(loadbase : memp, unit: integer); HDT:0002 ; HDT:0002 ; local stack frame HDT:0002 ; local1 HDT:0002 ; local2 address 0xff20 HDT:0002 ; local3 HDT:0002 ; local4 HDT:0002 ; local5 HDT:0002 ; local6 temporary value for argument1 HDT:0002 ; local7 temporary value for unit HDT:0002 ; local8/argument1 loadbase HDT:0002 ; local9/argument2 unit HDT:0002 .CPTR exitic_bootpriam HDT:0004 bootpriam .WORD $0007 HDT:0006 LLA 6 ; copy loadbase/unit arguments into temporary HDT:0008 LLA 8 HDT:000A MOV 2 HDT:000C LDCI $FF20 ; store address 0xff20 into local2 HDT:000F STL 2 HDT:0011 SLDL 2 ; copy 0xff20 into local3 HDT:0012 STL 3 HDT:0014 SLDL 3 ; copy 0xff20 into local4 HDT:0015 STL 4 HDT:0017 SLDL 4 ; copy 0xff20 into local5 HDT:0018 STL 5 HDT:001A SLDL 4 ; copy 0xff20 into local8/loadbase HDT:001B STL 8 HDT:001D SLDL 3 ; copy 0xff25 into local9/argument2 HDT:001E INC 5 HDT:0020 STL 9 HDT:0022 loc_F452 ; HDT:0022 SLDL 9 ; store 0 into 0xff25 HDT:0023 SLDC 0 HDT:0024 STO HDT:0025 SLDL 9 ; set bit 10 of 0xff25 to 1 HDT:0026 SLDC 1 HDT:0027 SLDC $A HDT:0028 SLDC 1 HDT:0029 STP HDT:002A loop_F45A ; HDT:002A SLDL 8 ; address 0xff23 HDT:002B INC 3 HDT:002D SLDC 1 ; check bit 6 of 0xff23 HDT:002E SLDC 6 HDT:002F LDP HDT:0030 FJP loc_F46B ; exit if bit6 = 0 HDT:0032 SLDL 8 ; address 0xff23 HDT:0033 INC 3 HDT:0035 SLDC 8 ; clear low 8 bits of 0xff23 HDT:0036 SLDC 0 HDT:0037 SLDC 0 HDT:0038 STP HDT:0039 UJP loop_F45A ; wait loop until bit6 is 1 HDT:003B loc_F46B ; HDT:003B SLDL 9 ; set bit11 of 0xff25 to 1 HDT:003C SLDC 1 HDT:003D SLDC $B HDT:003E SLDC 1 HDT:003F STP HDT:0040 SLDL 9 ; set bit 11 of 0xff25 to 0 HDT:0041 SLDC 1 HDT:0042 SLDC $B HDT:0043 SLDC 0 HDT:0044 STP HDT:0045 loop_F475 ; HDT:0045 SLDL 8 ; address 0xff23 HDT:0046 INC 3 HDT:0048 SLDC 1 ; check bit6 of 0xff23 HDT:0049 SLDC 6 HDT:004A LDP HDT:004B FJP loop_F475 ; loop until bit6 = 1 HDT:004D SLDL 8 ; address 0xff23 HDT:004E INC 3 HDT:0050 SLDC 8 ; clear low word of 0xff23 HDT:0051 SLDC 0 HDT:0052 SLDC 0 HDT:0053 STP HDT:0054 SLDL 9 ; set bit10 of 0xff25 to 0 HDT:0055 SLDC 1 HDT:0056 SLDC $A HDT:0057 SLDC 0 HDT:0058 STP HDT:0059 SLDL 5 ; address 0xff21 HDT:005A INC 1 HDT:005C SLDC $16 ; set 0xff21 = 22 (0x16) HDT:005D STO HDT:005E SLDL 5 ; address 0xff22 HDT:005F INC 2 HDT:0061 SLDC 0 ; set 0xff22 = 0 HDT:0062 STO HDT:0063 SLDL 5 ; address 0xff23 HDT:0064 INC 3 HDT:0066 SLDC 0 ; set 0xff23 = 0 HDT:0067 STO HDT:0068 SLDL 9 ; set bit10 of 0xff25 = 1 HDT:0069 SLDC 1 HDT:006A SLDC $A HDT:006B SLDC 1 HDT:006C STP HDT:006D SLDL 8 ; set 0xff20 = 0 HDT:006E SLDC 0 HDT:006F STO HDT:0070 SLDL 8 ; address 0xff21 HDT:0071 INC 1 HDT:0073 SLDC 8 HDT:0074 SLDC 0 HDT:0075 SLDL 7 ; get unit number HDT:0076 SLDC $10 ; restrict to unit 0..15 HDT:0077 MODI HDT:0078 STP ; store into low byte of 0xff21 HDT:0079 SLDL 3 ; address 0xff26 HDT:007A INC 6 HDT:007C SLDL 6 ; get loadbase HDT:007D SLDC 2 ; multiply with 2 (make byte address) HDT:007E MPI HDT:007F SLDC 1 ; subtract 1 HDT:0080 SBI HDT:0081 STO ; store into 0xff26 HDT:0082 SLDL 3 ; address 0xff27 HDT:0083 INC 7 HDT:0085 LDCI $D3FF ; store 0xd3ff (-0x2301) into 0xff27 HDT:0088 STO HDT:0089 SLDL 8 ; address 0xff23 HDT:008A INC 3 HDT:008C SLDC 8 ; store 0x53 into 0xff23 HDT:008D SLDC 0 HDT:008E LDCB $53 HDT:0090 STP HDT:0091 loop_F4C1 ; HDT:0091 SLDL 9 ; address 0xff25 HDT:0092 SLDC 1 ; check bit 15 of 0xff25 HDT:0093 SLDC $F HDT:0094 LDP HDT:0095 FJP loop_F4C1 ; loop until it becomes 1 HDT:0097 SLDL 8 ; address 0xff21 HDT:0098 INC 1 HDT:009A SLDC 2 HDT:009B SLDC 4 ; get bits 2-5 of 0xff21 HDT:009C LDP HDT:009D SLDC 0 ; is code = 0? HDT:009E EQUI HDT:009F FJP loc_F452 ; no, retry HDT:00A1 exitic_bootpriam ; exit boot priam HDT:00A1 RPU 9 HDT:00A3 .ALIGN HDT:00A4 .CPTR exitic_proc4 HDT:00A6 proc4 .WORD $0000 HDT:00A8 LOD 1,1 HDT:00AB LDCI $4153 HDT:00AE LOD 1,2 HDT:00B1 ADI HDT:00B2 STO HDT:00B3 loc_F4E3 HDT:00B3 LOD 1,1 HDT:00B6 SIND 0 HDT:00B7 BNOT HDT:00B8 FJP loc_F4E3 HDT:00BA loc_F4EA HDT:00BA LOD 1,1 HDT:00BD LDCI $41D0 HDT:00C0 LOD 1,2 HDT:00C3 ADI HDT:00C4 STO HDT:00C5 LOD 1,1 HDT:00C8 INC 4 HDT:00CA SLDC 0 HDT:00CB STO HDT:00CC LOD 1,1 HDT:00CF INC 5 HDT:00D1 SLDC 0 HDT:00D2 STO HDT:00D3 LOD 1,1 HDT:00D6 SIND 0 HDT:00D7 BNOT HDT:00D8 FJP loc_F4EA HDT:00DA exitic_proc4 HDT:00DA RPU 0 HDT:00DC ; HDT:00DC ; procedure bootfd(loadbase : memp, unit : integer); HDT:00DC ; HDT:00DC ; boot from onboard floppy HDT:00DC ; HDT:00DC ; local stack frame HDT:00DC ; local1 address 0xfc34 HDT:00DC ; local2 HDT:00DC ; local3 HDT:00DC ; local4 HDT:00DC ; local5 HDT:00DC ; argument1 HDT:00DC ; argument2 HDT:00DC HDT:00DC .CPTR exitic_bootfd ; also temporary HDT:00DE bootfd .WORD $0005 HDT:00E0 LDCI $100 ; shift unit# 8 bit left HDT:00E3 SLDL 7 HDT:00E4 MPI HDT:00E5 STL 2 ; store as temporary HDT:00E7 LLA 1 ; store address 0xfc34 into local1 HDT:00E9 LDCI $3CC HDT:00EC NGI HDT:00ED STO HDT:00EE retry ; HDT:00EE CPL 4 ; init FDC and DMA HDT:00F0 CPL 4 ; init again HDT:00F2 CPL 4 ; and again - now it should be really done! HDT:00F4 SLDL 1 HDT:00F5 LDCI $410F ; issue command RESTORE HDT:00F8 SLDL 2 ; merge in unit# HDT:00F9 ADI HDT:00FA STO HDT:00FB loop_F52B ; HDT:00FB SLDC 3 ; calc 12 HDT:00FC SLDC 4 HDT:00FD MPI HDT:00FE STL 7 ; store in temporary HDT:0100 SLDL 1 ; get 0xfc34 (FD status) HDT:0101 SIND 0 HDT:0102 BNOT ; check bit0 (BUSY) HDT:0103 FJP loop_F52B ; loop until BUSY=1 HDT:0105 SLDL 1 ; programm DMA byte count = 0xf300 (0x0d00 bytes to read) HDT:0106 INC 6 HDT:0108 SLDC 0 HDT:0109 STO HDT:010A SLDL 1 HDT:010B INC 7 HDT:010D SLDC $D ; 0xf3 HDT:010E NGI HDT:010F STO HDT:0110 SLDL 1 ; program DMA base = 2* loadbase HDT:0111 INC 8 HDT:0113 SLDL 6 HDT:0114 SLDL 6 HDT:0115 ADI HDT:0116 STO HDT:0117 SLDL 1 HDT:0118 INC 9 >HDT:011A SLDL 6 HDT:011B SLDL 6 HDT:011C ADI HDT:011D LDCI $100 HDT:0120 DVI HDT:0121 STO HDT:0122 SLDL 1 ; clear DMA address extension HDT:0123 INC $A HDT:0125 SLDC 0 HDT:0126 STO HDT:0127 SLDL 1 ; clear DMA status flags (interrupts and TCZI) HDT:0128 INC 5 HDT:012A SLDC 0 HDT:012B STO HDT:012C SLDL 1 ; program DMA for RUN and IOM=fdc-to-ram HDT:012D INC 4 HDT:012F SLDC $11 HDT:0130 STO HDT:0131 SLDL 1 ; set FDC sector =1 HDT:0132 INC 2 HDT:0134 SLDC 1 HDT:0135 STO HDT:0136 SLDL 1 ; program FDC for READ MULTIPLE HDT:0137 LDCI $4194 HDT:013A SLDL 2 HDT:013B ADI HDT:013C STO HDT:013D loop_F56D ; read DMA status HDT:013D SLDL 1 HDT:013E SIND 5 HDT:013F SLDC $A ; select bits TCZI and DINT HDT:0140 LAND HDT:0141 SLDC 0 HDT:0142 NEQI HDT:0143 FJP loop_F56D ; loop as long as they are 0 HDT:0145 SLDL 1 HDT:0146 SIND 5 HDT:0147 SLDC 8 ; select bit TCZI HDT:0148 LAND HDT:0149 SLDC 0 HDT:014A EQUI HDT:014B FJP exitic_bootfd ; if set, done HDT:014D UJPL retry ; loop retry booting HDT:0150 exitic_bootfd HDT:0150 RPU 7 HDT:0152 ; HDT:0152 ; procedure emit(local4: char); HDT:0152 ; HDT:0152 ; send argument to console output HDT:0152 ; HDT:0152 ; local stack frame HDT:0152 ; local1 dummy HDT:0152 ; local2 dummy HDT:0152 ; local3 dummy HDT:0152 ; argument1 (local4) HDT:0152 .CPTR exitic_emit HDT:0154 emit .WORD $0003 HDT:0156 loc_F586 ; load 0xfc12 (console status register) HDT:0156 SLDO 4 HDT:0157 SIND 2 HDT:0158 SLDC 1 ; mask out bit 1 (transmitter ready) HDT:0159 LAND HDT:015A SLDC 0 ; is zero? HDT:015B EQUI HDT:015C FJP loc_F586 ; no, loop HDT:015E SLDO 4 ; load address 0xfc13 (console transmit) HDT:015F INC 3 HDT:0161 LDCB $FF ; load 255 HDT:0163 SLDL 4 ; load char to emit HDT:0164 SBI ; invert (negative logic) HDT:0165 STO ; transmit HDT:0166 exitic_emit ; exit HDT:0166 RPU 4 HDT:0168 ; HDT:0168 ; procedure inchar; HDT:0168 ; HDT:0168 ; waits for char from console, echoes it HDT:0168 ; and returns in global1 HDT:0168 .CPTR exitic_inchar HDT:016A inchar .WORD $0000 HDT:016C loc_F59C ; address 0xfc12 (console status) HDT:016C SLDO 4 HDT:016D SIND 2 HDT:016E SLDC 2 ; mask bit 2 (receiver full) HDT:016F LAND HDT:0170 SLDC 0 ; is 0? HDT:0171 EQUI HDT:0172 FJP loc_F59C ; no, loop - no char received HDT:0174 LDCB $7F ; load 0x7f HDT:0176 SLDO 4 ; read 0xfc13 (receive buffer) HDT:0177 SIND 3 HDT:0178 LDCB $7F ; mask out 7 bits HDT:017A LAND HDT:017B SBI ; invert (negative logic) HDT:017C SRO 1 ; save received char HDT:017E SLDO 1 ; get char HDT:017F LDCB $61 ; lower case? HDT:0181 GEQI HDT:0182 FJP loc_F5BA ; no, skip HDT:0184 SLDO 1 ; get char HDT:0185 LDCB $20 ; convert to upper case HDT:0187 SBI HDT:0188 SRO 1 ; save it again HDT:018A loc_F5BA ; get char HDT:018A SLDO 1 HDT:018B CPG 5 ; echo HDT:018D exitic_inchar ; exit HDT:018D RPU 0 HDT:018F .ALIGN HDT:0190 ; HDT:0190 ; function readnumber : integer; HDT:0190 ; HDT:0190 ; read hex characters until a non-hex is found HDT:0190 ; collect as a number, return it to caller HDT:0190 ; HDT:0190 ; local stack frame HDT:0190 ; local1 variant record(integer, packed array(1..4) of 0..15) HDT:0190 ; local2 dummy HDT:0190 ; local3 dummy HDT:0190 ; local4 dummy HDT:0190 ; return value HDT:0190 .CPTR exitic_readnumber HDT:0192 readnumber .WORD $0004 HDT:0194 SLDC 0 ; clear number collector variable HDT:0195 STL 1 HDT:0197 loc_F5C7 ; address of local1 HDT:0197 LLA 1 HDT:0199 SLDC 4 ; array[4] (4 bits) HDT:019A SLDC $C HDT:019B LLA 1 ; address of local1 HDT:019D SLDC 4 ; array(3) (4 bits) HDT:019E SLDC 8 HDT:019F LDP ; copy array(4) := array(3) HDT:01A0 STP HDT:01A1 LLA 1 ; copy array(3) := array(2) HDT:01A3 SLDC 4 HDT:01A4 SLDC 8 HDT:01A5 LLA 1 HDT:01A7 SLDC 4 HDT:01A8 SLDC 4 HDT:01A9 LDP HDT:01AA STP HDT:01AB LLA 1 ; copy array(2) := array(1) HDT:01AD SLDC 4 HDT:01AE SLDC 4 HDT:01AF LLA 1 HDT:01B1 SLDC 4 HDT:01B2 SLDC 0 HDT:01B3 LDP HDT:01B4 STP HDT:01B5 SLDO 1 ; get char read HDT:01B6 LDCB $39 ; is less equal '9'? HDT:01B8 LEQI HDT:01B9 FJP loc_F5F6 ; no, skip HDT:01BB LLA 1 ; address array(1) HDT:01BD SLDC 4 HDT:01BE SLDC 0 HDT:01BF SLDO 1 ; ord(input char) HDT:01C0 LDCB $30 ; subtract ord('0') from char HDT:01C2 SBI HDT:01C3 STP ; store into array(1) HDT:01C4 UJP loc_F601 ; skip else part HDT:01C6 loc_F5F6 ; address of array(1) HDT:01C6 LLA 1 HDT:01C8 SLDC 4 HDT:01C9 SLDC 0 HDT:01CA SLDO 1 ; ord(input char) HDT:01CB LDCB $41 ; subtract ord('A') HDT:01CD SBI HDT:01CE SLDC $A ; add 10 HDT:01CF ADI HDT:01D0 STP ; store in array(1) HDT:01D1 loc_F601 ; expect another char HDT:01D1 CPG 6 HDT:01D3 SLDO 1 ; get it HDT:01D4 LAO 17 ; if char in ['0'..'9', 'A'..'F'] then HDT:01D6 LDM 5 HDT:01D8 SLDC 5 HDT:01D9 INN HDT:01DA BNOT HDT:01DB FJP loc_F5C7 ; loop HDT:01DD SLDL 1 ; return local1 (collected number) HDT:01DE STL 5 HDT:01E0 exitic_readnumber ; exit HDT:01E0 RPU 4 HDT:01E2 ; HDT:01E2 ; procedure reboot HDT:01E2 ; HDT:01E2 ; boot from the specified unit, if any, otherwise HDT:01E2 ; boot from unit 0 HDT:01E2 ; HDT:01E2 ; local stack frame HDT:01E2 ; local1 temporary HDT:01E2 .CPTR exitic_reboot HDT:01E4 reboot .WORD $0001 HDT:01E6 SLDO 3 ; get global3 (number flag) HDT:01E7 BNOT ; if "has a number" then skip HDT:01E8 FJP loc_F61D HDT:01EA SLDC 0 ; otherwise clear number (boot device 0) HDT:01EB SRO 2 HDT:01ED loc_F61D ; load address 0x2000 HDT:01ED LDCI $2000 HDT:01F0 STL 1 ; store as temporary HDT:01F2 SLDO 8 ; get global8 HDT:01F3 SLDO 2 ; get unit number (either 0 or number entered before 'R') HDT:01F4 STO ; save it (in HDT info at 0x22) HDT:01F5 SLDO 2 ; get unit number HDT:01F6 SLDC $10 ; shift 4 bits right (i.e. bits 7..4) HDT:01F7 DVI HDT:01F8 SLDC 0 ; are there some bits set? HDT:01F9 EQUI HDT:01FA FJP loc_F632 ; no skip HDT:01FC SLDO 2 ; push unit HDT:01FD SLDL 1 ; push address HDT:01FE CPG 2 ; boot from PRIAM drive HDT:0200 UJP loc_F636 ; continue HDT:0202 loc_F632 ; push unit HDT:0202 SLDO 2 HDT:0203 SLDL 1 ; push address HDT:0204 CPG 3 ; boot from FDC HDT:0206 loc_F636 ; address 0x2008 (TIB->SEGB) HDT:0206 SLDL 1 HDT:0207 SLDC 8 HDT:0208 ADI HDT:0209 SRO 5 ; store in temporary HDT:020B SLDO 5 ; get TIB->SEGB address HDT:020C SLDO 5 ; get SEGB value HDT:020D SIND 0 HDT:020E SLDC $C ; add offset to actual segment (byte addr 0x2030) HDT:020F ADI HDT:0210 STO ; set it into SEGB HDT:0211 LDCI -3 ; address RQ for SPR HDT:0214 SLDL 1 ; get address of TIB to execute (boot TIB) HDT:0215 SPR ; set RQ HDT:0216 LAO 6 ; wait on HDT semaphore, switch context to boot code HDT:0218 WAIT HDT:0219 exitic_reboot ; exit booter HDT:0219 RPU 1 HDT:021B .ALIGN HDT:021C casetbl_F64C .WORD $0000 ; case low index HDT:021E .WORD $0007 ; case high index HDT:0220 .WORD $0002 ; case idx 0 case0_F70A HDT:0222 .WORD $0007 ; case idx 1 case1_F70F HDT:0224 .WORD $000c ; case idx 2 case2_F714 HDT:0226 .WORD $0011 ; case idx 3 case3_F719 HDT:0228 .WORD $0016 ; case idx 4 case4_F71E HDT:022A .WORD $001c ; case idx 5 case5_F724 HDT:022C .WORD $0022 ; case idx 6 case6_F72A HDT:022E .WORD $0028 ; case idx 7 case7_F730 HDT:0230 a0123456789abcd .ASC '0123456789ABCDEF' HDT:0240 set_of_hex .WORD $0000 ; Set of HEX chars: [ '0'..'9', 'A'..'F' ] HDT:0240 ; bitmap 0000 0000 0000 0000 HDT:0242 .WORD $0000 ; bitmap 0000 0000 0000 0000 HDT:0244 .WORD $0000 ; bitmap 0000 0000 0000 0000 HDT:0246 .WORD $03ff ; bitmap 0000 0011 1111 1111 HDT:0248 .WORD $007e ; bitmap 0000 0000 0111 1110 HDT:024A ; local stack frame HDT:024A ; local1 temporary value for high byte of timer0 init HDT:024A ; local2 temporary init value for CTRL1 HDT:024A ; temp3 boolean: is hdt sema initialized? HDT:024A ; temp4 memp: temporary for various addresses HDT:024A .CPTR exitic_init HDT:024C init .WORD $0004 HDT:024E LAO 6 ; address of global6: semaphore HDT:0250 DUP1 ; seminit(global6,0); HDT:0251 SLDC 0 ; | HDT:0252 STO ; | HDT:0253 INC 1 ; | HDT:0255 LDCN ; | HDT:0256 STO ; |------ HDT:0257 LDCI $3F0 ; load 0xfc10 (address of console) HDT:025A NGI HDT:025B STL 4 ; save temporary HDT:025D SLDL 4 ; copy console address to global4 HDT:025E SRO 4 HDT:0260 SLDO 4 ; load 0xfc18 (system environment switch) HDT:0261 IND 8 HDT:0263 LDCB $80 ; mask out bit 7 (boot into HDT) HDT:0265 LAND HDT:0266 SLDC 0 HDT:0267 EQUI HDT:0268 FJP enter_hdt ; branch if bit is 1 (enter monitor) HDT:026A LDCI -3 ; This code is not yet understood: HDT:026A ; if SES bit 7 is 0, this will be called. HDT:026A ; This is possibly for custom configurations or ROMs. HDT:026A ; HDT:026A ; -3 address RQ register to be set HDT:026D LDCI $4000 ; load 0x4000 HDT:0270 LDCI $401 ; load 0x401 HDT:0273 SLDO 4 ; address 0xfc18 (system environment switch) HDT:0274 IND 8 HDT:0276 LDCB $20 ; test bit 5 (undocumented - reserved for user apps!) HDT:0278 LAND ; is either 0x00 or 0x20 HDT:0279 MPI ; multiply: results in 0x0000 or 0x8020 HDT:027A ADI ; add offset 0x4000 -> 0x4000 or 0xc020 HDT:027B SPR ; put into request queue HDT:027C LAO 6 ; wait on semaphore HDT:027E WAIT HDT:027F ; area 0x22 HDT:027F ; offset 0,1 HDT semaphore? HDT:027F ; offset 2 SSV for HDT segment HDT:027F ; offset 3 RQ for HDT segment HDT:027F enter_hdt ; HDT info structure HDT:027F LDCB $22 HDT:0281 SRO 8 ; store as global8 HDT:0283 SLDO 8 ; get address of sema HDT:0284 SIND 0 ; count HDT:0285 SLDO 8 HDT:0286 SIND 1 ; link HDT:0287 ADI HDT:0288 LDCI $4005 ; load 0xbffb HDT:028B NGI HDT:028C EQUI ; compare semaphore with init value HDT:028C ; is 0 in cold start HDT:028D STL 3 ; save it temporary HDT:028F SLDL 3 HDT:0290 FJP cold_init HDT:0292 LDCI -2 ; ---reentering HDT--- HDT:0292 ; address SSV for SPR HDT:0295 SLDO 8 ; get SSV for HDT HDT:0296 SIND 2 HDT:0297 SPR ; set it in CPU register HDT:0298 LDCI -3 ; address RQ for SPR HDT:029B SLDO 8 ; get RQ for HDT HDT:029C SIND 3 HDT:029D SPR ; set it in CPU register HDT:029E cold_init ; invert init flag HDT:029E SLDL 3 HDT:029F BNOT HDT:02A0 SLDO 8 ; semaphore count HDT:02A1 SIND 0 HDT:02A2 LOR ; merge HDT:02A3 FJPL loc_F777 ; is not cold start and no waiting on semaphore, branch HDT:02A6 LDCI $3E0 ; ---reinitialize--- HDT:02A9 NGI ; load 0xfc20 (console baud rate) HDT:02AA STL 4 ; store as temporary HDT:02AC SLDL 4 ; address 0xfc24 (system status register) HDT:02AD INC 4 HDT:02AF LDCB $80 ; enforce bus init (BINIT) HDT:02B1 STO HDT:02B2 SLDL 4 ; address 0xfc24 (system status register) HDT:02B3 INC 4 HDT:02B5 SLDC 1 ; clear BERR flag by writing a 1 HDT:02B5 ; disable interrupt system HDT:02B6 STO HDT:02B7 SLDL 4 ; address 0xfc23 (timer mode register) HDT:02B8 INC 3 HDT:02BA LDCB $34 ; program counter 0 for 16 bit operation, mode 2 HDT:02BC STO HDT:02BD SLDL 4 ; address 0xfc23 (timer mode register) HDT:02BE INC 3 HDT:02C0 LDCB $70 ; program counter 1 for 16 bit operation, mode 0 HDT:02C2 STO HDT:02C3 SLDL 4 ; address 0xfc23 (timer mode register) HDT:02C4 INC 3 HDT:02C6 LDCB $B0 ; program counter 2 for 16 bit operation, mode 0 HDT:02C8 STO HDT:02C9 SLDC 0 ; default value for timer0 high byte (=0) HDT:02CA STL 1 HDT:02CC LDCB $58 ; default console CTRL1 reg value (negative logic): HDT:02CC ; bit 7: normal mode HDT:02CC ; bit 6: non break mode HDT:02CC ; bit 5: single stop bit HDT:02CC ; bit 4: non echo mode HDT:02CC ; bit 3: no parity HDT:02CC ; bit 2: receiver enabled HDT:02CC ; bit 1: RTSbar=0 HDT:02CC ; bit 0: DTRbar=0 HDT:02CE STL 2 HDT:02D0 SLDO 4 ; address 0xfc18 (sytem environment switch) HDT:02D1 IND 8 HDT:02D3 SLDC 7 ; mask out low 3 bits for baud rate HDT:02D4 LAND HDT:02D5 XJP casetbl_F64C ; case of baudrate value HDT:02D8 loc_F708 ; compiler generates this even if not used HDT:02D8 UJP otherwise_F73D HDT:02DA case0_F70A ; address 0xfc20 HDT:02DA SLDL 4 HDT:02DB SLDC 2 ; timer value for 19200Bd HDT:02DC STO HDT:02DD UJP otherwise_F73D ; exit case HDT:02DF case1_F70F ; address 0xfc20 HDT:02DF SLDL 4 HDT:02E0 SLDC 4 ; timer value for 9600Bd HDT:02E1 STO HDT:02E2 UJP otherwise_F73D ; exit case HDT:02E4 case2_F714 ; address 0xfc20 HDT:02E4 SLDL 4 HDT:02E5 SLDC 8 ; timer value for 4800 Bd HDT:02E6 STO HDT:02E7 UJP otherwise_F73D ; exit case HDT:02E9 case3_F719 ; address 0xfc20 HDT:02E9 SLDL 4 HDT:02EA SLDC $10 ; timer value for 2400Bd HDT:02EB STO HDT:02EC UJP otherwise_F73D HDT:02EE case4_F71E ; address 0xfc20 HDT:02EE SLDL 4 HDT:02EF LDCB $21 ; timer value for 1200Bd HDT:02F1 STO HDT:02F2 UJP otherwise_F73D ; exit case HDT:02F4 case5_F724 ; address 0xfc20 HDT:02F4 SLDL 4 HDT:02F5 LDCB $41 ; timer value for 600Bd HDT:02F7 STO HDT:02F8 UJP otherwise_F73D ; exit case HDT:02FA case6_F72A ; address 0xfc20 HDT:02FA SLDL 4 HDT:02FB LDCB $82 ; timer value for 300Bd HDT:02FD STO HDT:02FE UJP otherwise_F73D ; exit case HDT:0300 case7_F730 ; address 0xfc20 HDT:0300 SLDL 4 HDT:0301 LDCB $5D ; timer value low for 110Bd HDT:0303 STO HDT:0304 SLDC 1 ; fix high byte for timer 0 HDT:0305 STL 1 HDT:0307 LDCB $78 ; Modify settings for console CTRL1 register: HDT:0307 ; as above, but HDT:0307 ; bit 5: 2 stop bits HDT:0309 STL 2 HDT:030B UJP otherwise_F73D HDT:030D otherwise_F73D ; address 0xfc20 (high byte) HDT:030D SLDL 4 HDT:030E SLDL 1 ; get high byte value, is 1 for 110 Bd, 0 else HDT:030F STO ; store and activate timer HDT:0310 SLDL 4 ; address 0xfc21 (timer1) HDT:0311 INC 1 ; initialize timer1 wit 0x0001 HDT:0313 SLDC 1 ; | HDT:0314 STO ; |low byte HDT:0315 SLDL 4 ; | HDT:0316 INC 1 ; | HDT:0318 SLDC 0 ; |high byte HDT:0319 STO ; |------ HDT:031A SLDL 4 ; initialize timer2 with 0x0001 HDT:031B INC 2 ; | HDT:031D SLDC 1 ; |low byte HDT:031E STO ; | HDT:031F SLDL 4 ; | HDT:0320 INC 2 ; | HDT:0322 SLDC 0 ; | high byte HDT:0323 STO ; |------ HDT:0324 SLDO 4 ; address 0xfc10 (console) HDT:0325 INC 2 ; address 0xfc12 (console status/DLE register) HDT:0327 SLDO 4 ; read out status (should be 00 after BINIT/bus reset) HDT:0328 SIND 2 HDT:0329 STO ; store to DLE register HDT:0329 ; Note: this is a weird way of getting a 00 into DLE register HDT:0329 ; Note2: the console is used in ASYNC mode anyway HDT:032A SLDO 4 ; address 0xfc10 (console CTRL1) HDT:032B SLDL 2 ; get default value (0x58 or 0x78) HDT:032C STO ; store it HDT:032D SLDO 4 ; address 0xfc11 (console CTRL2) HDT:032E INC 1 HDT:0330 LDCB $FE ; set CTRL mode (negative logic): HDT:0330 ; bit 7,6 = 00: 8 bits HDT:0330 ; bit 5 = 0 asynchronous mode HDT:0330 ; bit 4 = 0 even parity (ignored) HDT:0330 ; bit 3 = 0 receiver clock rate1 (x32) HDT:0330 ; bit 2-0 = 001: clock rate1 (x32) HDT:0332 STO ; store HDT:0333 SLDL 3 ; get cold start flag (=0 on boot) HDT:0334 FJP loc_F769 ; skip if cold start HDT:0336 LAO 6 ; wait on HDT semaphore HDT:0338 WAIT HDT:0339 loc_F769 ; load 0xfc24 (system status register) HDT:0339 SLDL 4 HDT:033A SIND 4 HDT:033B LDCB $80 ; mask INIT bit HDT:033D LAND HDT:033E SLDC 0 ; is it 0? HDT:033F EQUI HDT:0340 FJP loc_F777 ; no, skip HDT:0342 SLDC 0 ; set hasnumber flag := false HDT:0343 SRO 3 HDT:0345 CPG 8 ; goto reboot (does not return) HDT:0347 loc_F777 ; global8 index 1 HDT:0347 SLDO 8 HDT:0348 INC 1 HDT:034A SLDC 0 ; clear HDT:034B STO HDT:034C LAO 9 ; globa lstring store (16 bytes) HDT:034E LCA a0123456789abcd ; address of HEX conversion constants HDT:0351 MOV 8 ; move into global HDT:0353 LAO 17 ; global set of hex chars HDT:0355 LDC set_of_hex,5 ; load initial values ['0'..'9','A'..'F'] HDT:0359 SLDC 5 ; length of init value HDT:035A ADJ 5 ; pack to 5 words HDT:035C STM 5 ; store in global HDT:035E exitic_init ; done with initialization HDT:035E RPU 4 HDT:0360 ; local stack frame HDT:0360 ; hmmm: this is the top level procedure, HDT:0360 ; so global == local HDT:0360 ; SLDL1 is the same as SLDO1 HDT:0360 ; so look up the various globals... HDT:0360 .CPTR exitic_proc1 HDT:0362 proc1 .WORD $0015 HDT:0364 SLDC 6 HDT:0365 LSL 0 HDT:0367 SPR HDT:0368 ENTRY_POINT ; IPC start on reset points here HDT:0368 CPG 9 ; initialize timers/console HDT:036A loc_F79A ; load CR HDT:036A SLDC $D HDT:036B CPG 5 ; emit HDT:036D SLDC $A ; load LF HDT:036E CPG 5 ; emit HDT:0370 LDCB '#' ; load '#' HDT:0372 CPG 5 ; emit HDT:0374 SLDC 0 ; global2 := 0 (current address) HDT:0375 STL 2 HDT:0377 SLDC 0 ; global3 := 0 (flag T/F, has address) HDT:0378 STL 3 HDT:037A CPG 6 ; wait for input char from console HDT:037C SLDL 1 ; get char received HDT:037D LLA 17 ; address of set of hex (global17) HDT:037F LDM 5 ; load 5 words of set HDT:0381 SLDC 5 ; set is 5 words HDT:0382 INN ; check if inchar in ['0'-'9','A'-'F'] HDT:0383 FJP loc_F7BD ; no, skip HDT:0385 SLDC 0 ; return value HDT:0386 CPG 7 ; read a number HDT:0388 STL 2 ; store global2 (current address) HDT:038A SLDC 1 ; set flag: has address HDT:038B STL 3 HDT:038D loc_F7BD ; arrives here if non-hex char found HDT:038D SLDL 1 ; load input char HDT:038E LDCB 'R' ; is it 'R' (reboot) HDT:0390 EQUI HDT:0391 FJP loc_F7C5 ; no, skip HDT:0393 CPG 8 ; go reboot HDT:0395 loc_F7C5 ; load input char HDT:0395 SLDL 1 HDT:0396 LDCB 'P' ; is it 'P'? HDT:0398 EQUI HDT:0399 FJP loc_F7CE ; no, skip HDT:039B LLA 6 ; wait on HDT sema, i.e. context switch back to HDT:039B ; interrupted process HDT:039D WAIT HDT:039E loc_F7CE ; emit '?' HDT:039E LDCB '?' HDT:03A0 CPG 5 HDT:03A2 UJPL loc_F79A ; loop HDT:03A5 exitic_proc1 HDT:03A5 CXG 3,$18 HDT:03A8 RPU $15 HDT:03AA proctbl HDT:03AA .WPTR init HDT:03AC .WPTR reboot HDT:03AE .WPTR readnumber HDT:03B0 .WPTR inchar HDT:03B2 .WPTR emit HDT:03B4 .WPTR proc4 HDT:03B6 .WPTR bootfd HDT:03B8 .WPTR bootpriam HDT:03BA .WPTR proc1 HDT:03BC byte_F7EC .BYTE $01 ; seg#: seg01 HDT:03BD .BYTE $09 ; # of procs in segment HDT:03BE .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; padding HDT:03BE .BYTE $00,$00 HDT:03BE ; END OF SEGMENT