3000 – Jump Table.

3000
Jump to 325EH for a SLOW tape header write.
3003
Jump to 329BH for a FAST tape header write.
3006
Jump to 3274H for a SLOW tape header read.
3009
Jump to 32DAH for a FAST tape header read.
300C
Jump to 31C0H for Cassette OFF.
300F
Jump to 31D1H for Cassette ON.
*3012
Jump to 34B6H for Warm Boot.
*3012
Jump to 34ABH for Warm Boot.
3015
Jump to 3455H for Bootstrap.
3018
Jump to 35C2H for Maskable Interrupt Handler.
301B
Jump to 35FBH for RS-232 Initialization.
301E
Jump to 365AH for RS-232 Input.
3021
Jump to 3680H for RS-232 Output.
3024
Jump to 338EH for Keyboard Input.
*3027
Jump to 3738H for I/O Re-Router.
*3027
Jump to 3739H for I/O Re-Router.
302A
Jump to 31F7H for part of cassette header routine.
*302D
Jump to 377AH for a routine which parses whether the current instruction on a the current line is in quotes.
*302D
Jump to 377BH for a routine which parses whether the current instruction on a the current line is in quotes.
*3030
Jump to 3798H for STRING=DATE$+””+TIME$.
*3030
Jump to 3799H for STRING=DATE$+””+TIME$.
3033
Jump to 35BBH to put the DATE onto the upper right hand corner of the screen.
3036
Jump to 35A0H to put the TIME 10 characters from the upper right hand corner of the screen.
3039
IN A,(E4H)
Poll Port E4H into A.

NOTE: Port E4H is the Non-Maskable Interrupt Latch.
*303B
INC A
Bump A.
*303C-303E
If Port E4H plus 1 is NOT zero, then JUMP to the NMI Vector at 4049H.
*303F
DI
Disable Interrupts.
*3040-3041
JUMP back 3015H to JUMP to 3455H for Bootstrap.
*3042-3044
JUMP to 37B4H of v1.
*303B
BIT 5,A
Check the 5th Bit of the Non-Maskable Interrupt Latch.
*303D
Jump to 351CH to go to the NMI handler.
*3040
Jump to 3015H for Bootstrap.
*3042
Jump to 37B5H to display the CASS? prompt.

3045 – Keyboard Rows 0-3, Unshifted, No Caps Lock.

3045
40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A

3060 – Load A with the Computer version number, which is always 1 for a Model III and 0 for a Model 4.

*3060
NOP
No Operation.
*3061
NOP
No Operation.
*3062
NOP
No Operation.
*3063
NOP
No Operation.
*3064
NOP
No Operation.
*3060
LD A,(37EAH)
Load the memory contents of 37EAH into A.

NOTE: 37EAH is a hard coded 01H.
*3063
OR A
Set up flags for those memory contents.
*3064
RET
RETURN.

3065 – Keyboard Rows 4-6, Unshifted, No Caps Lock.

3065
30 31 32 33 34 35 36 37 38 39 3A 3B 2C 2D 2E 2F 0D 1F 01 5B 0A 08 09 20

307D – Set the Keyboard Repeat Delay Count to 1500.

307D
LD HL,05DCH
Load HL with 05DCH.

NOTE: 05DCH is 1500.
307E
LD (41FFH),HL
Load the memory location at 41FFH with 05DCH.

NOTE: 41FFH holds the keyboard scan repeat delay count.
3083
XOR A
Clear A and all flags.
3084
RET
RETURN.

3085 – Keyboard Rows 0-3, shifted, No Caps Lock.

3085
60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A

30A0 – This is a mess. The v1 code is a mess and so the v2 code is weird. v2 has it putting A into (HL), clearing A and FLAGS and RETURN.

*30A0
LD H,L
Load H with the contents of L.
*30A1-30A2
If the ZERO flag is set, JUMP back 3070H, which makes no sense since that’s a jump into the alphabet.
*30A3-30A5
If the CARRRY FLAG is set, JUMP to 0029H, which makes no sense since that’s a jump into the middle of an instruction jumping to DOS.
*30A0
LD (HL),A
Load the memory address pointed to by HL with A.
*30A1
XOR A
Clear A and all flags.
*30A2
RET
RETURN.

*30A3
AAAA
UNUSED GARBAGE.
*30A5
NOP
No Operation.

30A6 – Keyboard Rows 4-6, shifted, No Caps Lock.

30A6
21 22 23 24 25 26 27 28 29 2A 2B 3C 3D 3E 3F 0D 1F 01 1B 1A 18 19 20

30BD – Toggle Caps Lock.

*30BD-30BE
GOSUB to 28BFH.

NOTE: 28BFH computes the amount of space remaining in the string area.
*30BF-30C1
LD HL,40D3H
Load HL with 40D3H.

NOTE: 40D3H is generally used as the pointer workspace.
*30C2
PUSH HL
Push HL onto the STACK.
*30BD
LD A,01H
Load A with 01H.
*30BE
LD HL,4019H
Load HL with 4019H.

NOTE: 4019H holds the caps lock toggle in the keyboard DCB.
*30C2
XOR (HL)
Invert the contents of the (4019H).
*30C3
JR 30A0H
JUMP back to 30A0H.

30C5 – Keyboard Rows 0-3, UNshifted, Caps Lock.

30C5
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59

30E0 – GOSUB to the PRINT SCREEN Routine, Clear A, and RETURN

*30E0
NOP
No Operation.
*30E1
NOP
No Operation.
*30E2
NOP
No Operation.
*30E3
NOP
No Operation.
*30E4
NOP
No Operation.
*30E0
GOSUB to 01D9H.

NOTE: 01D9H is the Print Screen Routine.
*30E3
XOR A
Erase A and Reset flags.
*30E4
RET
RETURN.

30E5 – Keyboard Rows 4-6, UNshifted, Caps Lock

30E5
30 31 32 33 34 35 36 37 38 39 3A 3B 2C 2D 2E 2F 0D 1F 01 5B 0A 08 09 20

30FD – Checking for a BREAK key during a cassette operation

*30FD-30FF
LD DE,40D6H
Load DE with 40D6H.

NOTE: 40D6H holds the next available string location.
*3100
RST 18H
Call the COMPARE DE:HL routine, which numerically compares DE and HL. Will not work for signed integers (except positive ones). Uses the A-register only. The result of the comparison is returned in the status register as: CARRY SET=HL<DE; NO CARRY=HL>DE; NZ=Unequal; Z=Equal).
*3101-3103
LD (40B3H),HL
Load HL with the memory contents of 40B3H.

NOTE: 40B3H is the current position in the workspace table.
*3104
POP HL
Restore HL from the STACK.
*30FD
If the ZERO FLAG is set, jump back to 30E0H which will then call the print screen routine.
*30FF
AND (HL)
Prepare to check for a BREAK by masking A against the memory contents of HL …
*3100
CP 01H
… and COMPARING it to 01H.
*3102
RET NZ
If the result of the compare is NOT zero, then RETURN.
*3103
RST 28H
If we are here, then a BREAK was hit, so call RST 28H to handle the BREAK.
*3104
RET
RETURN.

3105 – Keyboard Rows 0-3, shifted, Caps Lock

3105
60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 “VWXYZ”

3120 – Go to the next Keyboard row

*3120
INC BC
Bump BC.
*3121-3123
LD HL,1803H
Load HL with 1803H.
*3124-3126
JP P,2100H
If the PARITY BIT is set, Jump to 2100H which sends a CARRIAGE RETURN to the current output device, calls a DOS link, Clears A and FLAGS, and RETURNS.
*3120
INC D
Bump D so that D holds the NEXT row number.
*3121
INC HL
Bump HL so that HL holds the NEXT buffer location.
*3122
RLC C
We need C to point to the next row of keys, so we rotate C left one bit, copying BIT 7 to the CARRY FLAG and the CARRY FLAG to BIT 0.
*3124
RET
RETURN.
*3125
NOP
No Operation.

3125 – Keyboard Rows 4-6, Shifted, Caps Lock

*3125
!”#$%&'()*+<=>? 0D 1F 01 1B 1A 18 19 20
*3126
!”#$%&'()*+<=>? 0D 1F 01 1B 1A 18 19 20

313D – Restore Scanning Variables.
This routine is called from 33CC which is in the middle of the keyboard input routine.

*313D
EX DE,HL
Exchange DE and HL.
*313E
POP AF
Restore AF from the STACK.
*313F
RET
RETURN.
*3140
POP AF
Restore AF from the STACK.
*3141-3142
LD E,1AH
Load E with 1AH.
*3143-3145
If the ZERO FLAG is set, JUMP to 20A2H.

NOTE: 20A2H is in the middle of the PRINT routine, and is at the point where we know we have a At this point we have a PRINT@nnnn.
*313D
LD A,(41FDH)
If the ZERO FLAG is not set, then load A with the memory contents of 41FDH.

NOTE: 41FDH is the saved position in the keyboard scan.
*3140
LD L,A
Load L with the A.
*3141
LD A,(41FEH)
Load A with the memory contents of 41FEH.

NOTE: 41FEH is the saved IMAGE at the saved position in the keyboard scan data.
*3144
RET
RETURN.

3145 – Printer Character Table Codes 32-127.

*3146
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 3E
*3145
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 3E

31A5 – Output the TIMING MARK to the cassette

31A5
LD A,01H
Load A with 01H. This is to prepare to send 0.46V to tape.
31A7
OUT (FFH),A
Load Port FFH with A.

NOTE: Port FFH is the cassette port. When outputting to FFH, Bits Zero and 1 set to: 00 is .85V, 01 is .46V, and 10 is 0.0V.
31A9
LD B,0DH
Load B with 0DH in as a loop counter.
31AB
Loop this instruction until B hits ZERO.
31AD
LD A,02H
Load A with 01H. This is to prepare to send 0.0V to tape.
31AF
OUT (FFH),A
Load Port FFH with A.

NOTE: Port FFH is the cassette port. When outputting to FFH, Bits Zero and 1 set to: 00 is .85V, 01 is .46V, and 10 is 0.0V.
31B1
LD B,0DH
Load B with 0DH in as a delay.
31B3
Loop this instruction until B hits ZERO.
31B5
GOSUB to 31F3 to send 0.46V to tape.

NOTE: 31F3H resets the cassette port, and then output a 0 to the Cassette Port FFH.
31B8
LD B,78H
Load B with 78H in as a delay.
31BA
Loop this instruction until B hits ZERO.
31BC
RET
RETURN.

31BD
LD HL,2CA5H
Load HL with 2CA5H.

NOTE: 2CA5H is the “BAD” message string.

31C0 – Turn Off The Cassette

31C0
LD A,(4213H)
Load A with the memory contents of 4213H.

NOTE: 4213H is the default interrupt vector setting for the cassette.
31C3
OUT (E0H),A
Output A to Port E0H.

NOTE: Port E0H is the maskable interrupt latch, which directs jumps.
Jump Table:
  • xxxxxxx1 jumps to 3365H
  • xxxxxx1x jumps to 3369H
  • xxxxx1xx jumps to 4046H
  • xxxx1xxx jumps to 403DH
  • xxx1xxxx jumps to 4206H
  • xx1xxxxx jumps to 4209H
  • x1xxxxxx jumps to 44040H
  • 1xxxxxxx jumps to 44043H
31C5
IN A,(FFH)
INPut the contents of Port FFH and store the result in A.

NOTE: Port FFH is the cassertte port read status. If the 7th bit is 0 then it is low, and if 7th bith is 1 then it is high.
31C7
LD A,(4210H)
Load A with the memory contents of 4210H.

NOTE: 4210H is the bit mask for Port ECH. Port ECH is the Miscellaneous Controls port, which covers clock on/off (Bit 0), cassette motor on or off (Bit 1), double size video on or off (Bit 2), and special character set select of Kana or misc (Bit 3). Higher bits are used for the Model 4 only.
31CA
AND FDH
Mask A against FDH (1111 1101) to zero bit 1.
31CC
GOSUB to 31EDH to save the mask into 4210H, output it to Port ECH, and return here.
31CF
EI
Enable Interrupts.
31D0
RET
RETURN.

31D1 – Turn On The Cassette – Part 1. This will remove the return address, save DE and BC, restore the return address, and than blank the “**”

31D1
EX DE,HL
Swap DE and HL to remove the return address.
31D2
EX (SP),HL
Swap the memory contents pointed to by the STACK POINTER and HL (which is now what DE was).
31D3
PUSH BC
Save BC to the STACK.
31D4
PUSH HL
Save HL to the STACK.
31D5
EX DE,HL
Swap DE and HL back.
31D6
IN A,(ECH)
Poll Port ECH and put the results into A.

NOTE: Port ECH is the Miscellaneous Controls port, which covers clock on/off (Bit 0), cassette motor on or off (Bit 1), double size video on or off (Bit 2), and special character set select of Kana or misc (Bit 3). Higher bits are used for the Model 4 only.
31D8
LD DE," "
Load DE with SPACESPACE.
31DB
LD (3C3EH),DE
Load the screen memory location of 3C3EH with DE.
31DF
GOSUB to 31E8H to turn on the cassette.
31E2
LD BC,7D00H
Load a delay count of 7D00 (Decimal: 32,000) into BC.
31E5
Jump to 0060H, which JUMPs to the delay routine at 01FBH and RETURNS.

31E8 – Turn On The Cassette – Actually Set the Bit Mask and Output the Command

31E8
LD A,(4210H)
Load A with the memory contents of 4210H.

NOTE: 4210H is the bit mask for Port ECH. Port ECH is the Miscellaneous Controls port, which covers clock on/off (Bit 0), cassette motor on or off (Bit 1), double size video on or off (Bit 2), and special character set select of Kana or misc (Bit 3). Higher bits are used for the Model 4 only.
31EB
OR 02H
OR A with 02H (0000 0010) to set Bit 1.
31ED
LD (4210H),A
Save revised Bit Mask back to 4210H.

NOTE: 4210H is the bit mask for Port ECH. Port ECH is the Miscellaneous Controls port, which covers clock on/off (Bit 0), cassette motor on or off (Bit 1), double size video on or off (Bit 2), and special character set select of Kana or misc (Bit 3). Higher bits are used for the Model 4 only.
31F0
OUT (ECH),A
Output that Bit Mask to port 0ECH.
31F2
RET
RETURN.

31F3 – Reset the Cassette Port. This routine OUTputs a 0 to the Cassette Port FFH

31F3
XOR A
We want to reset the cassette port so we zero A.
31F4
OUT (FFH),A
Load Port FFH with A.

NOTE: Port FFH is the cassette port. When outputting to FFH, Bits Zero and 1 set to: 00 is .85V, 01 is .46V, and 10 is 0.0V.
31F6
RET
RETURN.

31F7 – Check to see if we have a PRINT # command and, if so, get the port number, validate that the next character is a , and return.

31F7
LD A,(HL)
Load Register A with the memory contents pointed to by Register Pair HL.
31F8
SUB 23H
Subtract 23H so that we can test to see if the caller was a PRINT # command.
31FA
If that subtraction didn’t result in a ZERO (a match), the JUMP to 0253H.

NOTE: 0253H is in the middle of the “Write a Byte to Cassette” Routine. It ends in a RETURN.
31FD
If it was a PRINT # command, then GOSUB to 2B01H to get the device number.
3200
RST 08H
“,”
So now we have PRINT #n and the next character needs to be a ,, so call RST 08 to check for the next character against a “,” and generate a SYNTAX ERROR if it wasn’t.
3202
RET
If we are here, then we have PRINT #n, so we RETURN.

3203 – Vector for a SLOW cassette read

3203
LD B,08H
Load B with 8, representing the need to LOOP for 8 bits.
3205
GOSUB to 3220H.

NOTE: 3220H reads the tape until it finds a timing mark or the BREAK is hit.
3208
Loop that GOSUB 8 times.
LD A,(4212H)
Put the contents of 4212H into A.

NOTE: 4212H holds the cassette blinker counter.
320D
INC A
Bump A.
320E
AND 5FH
Mask A against 5F (0101 1111) to turn Bit 7 and Bit 5 off.
3210
LD (4212H),A
Put A into 4212H.

NOTE: 4212H holds the cassette blinker counter.
3213
If the masked count is NOT ZERO, then skip the next few instructions.
3215
LD A,(3C3FH)
Load A with the screen contents at position 3C3FH.
3218
XOR 0AH
XOR A against 0AH (00001010). This turns a “*” into a ” ” and vice versa as a a “*” is 0010 1010 and when you XOR that against 0000 1010 you get 0010 0000 which is a ” ” (and vice versa).
321A
LD (3C3FH),A
Put the revised A onto the screen at position 3C3FH.
321D
LD A,D
Put D (the byte) into A.
321E
JUMP to 3298H to restore the registers and RETURN.

3220 – Cassette – Keep reading tape looking for a timing mark or BREAK.

3220
PUSH BC
Save BC to the STACK.
3221
IN A,(FFH)
Poll Port FFH with the results into Register A.

NOTE: FFH is the Cassette Port.
3223
RLA
Put the level received in A into the Carry Bit by rotating A left 1 bit (putting bit 7 into the CARRY FLAG and the old CARRY FLAG into bit 0).
3224
If the CARRY FLAG is set then the timing mark was found, so JUMP to 322EH.
3226
GOSUB to 028DH to check for a BREAK key.
3229
Loop back to 3221H until we get either a timing mark or a BREAK key.
322B
If we are here, then we got a BREAK key, so JUMP to 335CH.

322E – Cassette – Wait for the timing mark to pass and the next data to show up. Put that data into Bit 0 of D.

First, wait for 6EH Units (the length of the timing mark)

322E
LD B,6EH
Load B with 6EH, which is the length of the timing mark.
3230
Loop until B is 0.

Reset the cassette port

3232
GOSUB to 31F3H to RESET the cassette port.

Next, wait for 98H Units (the length until a data pulse is expected)

3235
LD B,98H
Load B with 98H, which is when the next data pulse should be available.
3237
Loop until B is 0.

… continue

3239
IN A,(FFH)
Poll Port FFH and put the results into A.

NOTE: Port FFH is the Cassette Port.
323B
POP BC
Restore BC from the STACK.
323C
RLA
Rotate A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into the CARRY FLAG.
323D
RL D
Rotate D left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into BIT 0 of D.
323F
JUMP to 31F3H to reset the cassette port and RETURN.

3241 – Vector for a SLOW cassette write. On entry A is the byte to output.

3241
PUSH AF
Save AF to the STACK.
3242
PUSH BC
Save BC to the STACK.
3243
PUSH DE
Save DE to the STACK.
3244
LD C,08H
Load C with an 8, representing 8 bits to be written.
3246
LD D,A
Load D with A.

NOTE: D will be the DATA BYTE.
3247
GOSUB to 31A5H.

NOTE: 31A5H outputs the timing mark.
324A
RLC D
Rotate D left one bit, with the contents of BIT 7 being put into BOTH the CARRY FLAG and BIT 0. This puts the DATA BIT into CARRY.
324C
If there is no DATA BIT (because CARRY is 0) then JUMP to 3258H to wait the appropriate amount of time for a 0 byte to be written.
324E
If we are here, then there was a PULSE, so GOSUB to 31A5H to output the timing bit.
DEC C
Reduce the counter holding the number of bits to deal with by 1.
3252
Loop back to 3247H until the counter in C hits 0.
3254
POP DE
Restore DE from the STACK.
3255
POP BC
Restore BC from the STACK.
3256
POP AF
Restore AF from the STACK.
3257
RET
RETURN.

3258 – “Write a 0 Bit” by simply waiting the appropriate amount of time and doing nothing.

3258
LD B,9AH
Set a delay of 9A.
325A
Loop until that hits zero.
325C
JUMP to 3251H.

325E – SLOW tape header write

325E
PUSH HL
Save HL to the STACK.
325F
LD HL,3241H
Load HL with 3241H.

NOTE: 3241H is the Vector for a SLOW cassette write.
3262
LD (420CH),HL
Load the memory contents of 420CH with HL.

NOTE: 420CH is the TAPE WRITE VECTOR.
3265
LD B,53H
Load B with 53H (Decimal: 83) in prepartion to output 83 ZEROes.
3267
XOR A
Clear A and all flags.
3268
GOSUB to 3241H.

NOTE: 3241H is the Vector for a SLOW cassette write.
326B
Loop back to 3268H until 63 ZEROes have been written.
326D
LD A,0A5H
Load A with A5H.

NOTE: A5H is the OUTPUT SYNC BYTE.
326F
GOSUB to 3241H.

NOTE: 3241H is the Vector for a SLOW cassette write.
3272
JUMP to 3297H to restore all the registers and RETURN.

3274 – SLOW tape header read

3274
PUSH HL
Save HL to the STACK.
3275
LD HL,3203H
Load HL with 3203H.

NOTE: 3203H is the vector for a SLOW cassette read.
3278
LD (420EH),HL
Put the vector for a slow cassette read into the memory location at 420EH.

NOTE: 420EH is the TAPE READ VECTOR.
327B
LD B,40H
Load B with 40H to set up a loop of 64 to try to find 64 zeroes.
327D
LD D,00H
Load D with 0.
327F
GOSUB to 3220H.

NOTE: 3220H will keep reading tape looking for a timing mark or BREAK.
3282
LD A,D
Load A with the D (the data byte) to begin to check the current data byte.
3283
OR A
Set up the flags.
3284
LOOP back to 327BH until A is ZERO.
3286
Loop back to 327FH 64 times.
3288
GOSUB to 3220H.

NOTE: 3220H reads the tape until it finds a timing mark or the BREAK is hit.
328B
LD A,D
Load A with the D (the data byte) to begin to check the current data byte.
328C
CP 0A5H
Compare A to A5H looking for a SYNC BYTE.
328E
JUMP back to to 3288H if a SYNC BYTE wasn’t found.
LD HL,"**"
In preparation to display a “**”, load HL with **.
3293
LD (3C3EH),HL
Put HL onto the screen at location 3C3EH.
3296
LD A,H
Load A with H (which is a *.
3297
POP HL
Restore HL from the STACK.
3298
POP BC
Restore BC from the STACK.
3299
POP DE
Restore DE from the STACK.
329A
RET
RETURN.

329B – FAST tape header write.

329B
PUSH HL
Save HL to the STACK.
329C
LD HL,32BAH
Load HL with 32BAH.

NOTE: 32BAH is the VECTOR TO FAST WRITE.
329F
LD (420CH),HL
Load the memory contents of 420CH with HL.

NOTE: 420CH is the TAPE WRITE VECTOR.
32A2
LD B,00H
Load B with 00H to set up a loop of 256 to output 256 “55H” bytes.
32A4
LD A,55H
Load A with “55H”.
32A6
GOSUB to 32B4H.

NOTE: 32B4 restore all registers from the STACK, and Fill C with A, and JUMP to cassette write
32A9
LOOP back to 32A4H 256 times.
32AB
LD A,7FH
Load A with 7FH.

NOTE: 7FH is the OUTPUT SYNC BYTE.
32AD
GOSUB to 32B4H.

NOTE: 32B4 restore all registers from the STACK, and Fill C with A, and JUMP to cassette write
32B0
LD A,A5H
Load A with A5H.

NOTE: A5H is the SLOW SYNC BYTE.
32B2
JUMP to 3297H to restore all the registers and RETURN.

32B4 – Restore all registers from the STACK, and Fill C with A, and JUMP to cassette write.

32B4
PUSH AF
Save AF to the STACK.
32B5
PUSH BC
Save BC to the STACK.
32B6
PUSH DE
Save DE to the STACK.
32B7
LD C,A
Load C with A.
32B8
JUMP to 32C1H.

NOTE: 32C1H will write to cassette without a start bit.

32BA – Save all registers to the STACK, and Fill C with A, GOSBUB to write out the START BIT …

32BA
PUSH AF
Save AF to the STACK.
32BB
PUSH BC
Save BC to the STACK.
32BC
PUSH DE
Save DE to the STACK.
32BD
LD C,A
Load C with A.
32BE
GOSUB to 333EH to write the START BIT.

32C1 – Call 3335H to Output a Bit 8 Times

32C1
LD B,08H
Load B with an 8 to set up a loop for 8 bits.
32C3
GOSUB to 3335H to output the bit.
32C6
Loop back one instruction for all 8 bits.
32C8
JUMP to 3254H to restore all the registers and RETURN.

32CA – Read the start bit, read 8 bits, check for error, and flash the star

32CA
GOSUB to 3350H to READ START BIT.
32CD
LD B,08H
Load B with an 8 to set up a loop for 8 bits.
32CF
GOSUB to 3350H to READ BIT.
32D2
GOSUB to 337CH to CHECK FOR DATA ERROR.
32D5
Loop back 2 instructions for all 8 bits.
32D7
JUMP to 320AH to flash the *.

32DA – FAST tape header read.

32DA
PUSH HL
Save HL to the STACK.
32DB
LD HL,32CAH
Load HL with 32CAH.

NOTE: 32CAH reads an verifies a byte.
32DE
LD (420EH),HL
Load the TAPE READ VECTOR (memory location of 420EH) with the 32CAH.
32E1
LD A,01H
Load A with a 1 to set the interrupt.
32E3
OUT (E0H),A
OUTPUT A to Port E0H.

NOTE: Port E0H is the maskable interrupt latch, which directs jumps.
Jump Table:
  • xxxxxxx1 jumps to 3365H
  • xxxxxx1x jumps to 3369H
  • xxxxx1xx jumps to 4046H
  • xxxx1xxx jumps to 403DH
  • xxx1xxxx jumps to 4206H
  • xx1xxxxx jumps to 4209H
  • x1xxxxxx jumps to 44040H
  • 1xxxxxxx jumps to 44043H
32E5
LD B,80H
Set up a loop of 80H (128) to try to read 128 bits.
32E7
GOSUB to 3350H to READ a BIT.
32EA
LD A,C
Load A with C (which is the pulse width).
32EB
CP 0FH
Compare A to 0FH to see if the pulse width was too short.
32ED
Loop back to 32E5H if the pulse width was too short.
32EF
CP 3EH
Compare A to 3EH to see if the pulse width was too long.
32F1
Loop back to 32E5H if the pulse width was too long.
32F3
Loop back to 32E7H 128 times.
32F5
LD HL,0000H
Load HL with 0000.
32F8
LD B,40H
Set up a loop of 40H (Decimal: 64) to try to read 64 bits.
32FA
GOSUB to 3350H to READ BIT.
32FD
GOSUB to 3350H to READ BIT.
3300
LD D,C
Load D with C (which holds the delay count).
3301
GOSUB to 3350H to READ BIT.
3304
LD A,D
Load A with D to set up to find the difference in the delays.
3305
SUB C
Subtract C (the delay count) from A (which holds D).
3306
JUMP to 330AH (to GET ABSOLUTE) if the carry flag is NOT set.
3308
NEG
A = 0 – A.
330A
CP 0DH
Compare the NEGated A against 0DH. This has the effect of checking A-0DH, so if A < 0DH then the CARRY will be set and if A >= 0DH then the NO CARRY will be set.
330C
If the CARRY FLAG is set, JUMP to 3313H which will bump L and continue the 64 bit loop.
330E
INC H
Bump HL since we have one more zero bit.
330F
Loop back to 32FAH until 64 bits read.
3311
JUMP out of the loop to 3316H.
3313
INC L
Bump L since we have one more bit.
3314
Loop back to 32FAH until 64 bits read.
3316
LD A,40H
Load A with 40H (64).
3318
CP H
Compare A with H to check for bits.
3319
If they match, then JUMP forward to 3325H.
331B
CP L
Compare with A to check for one bits.
331C
If not, JUMP forward to 32F5H.
331E
LD A,02H
Load A with 2 to set the interrupt vector.
3320
OUT (E0H),A
Output the 2 to Port E0H.

NOTE: Port E0H is the maskable interrupt latch, which directs jumps.
Jump Table:
  • xxxxxxx1 jumps to 3365H
  • xxxxxx1x jumps to 3369H
  • xxxxx1xx jumps to 4046H
  • xxxx1xxx jumps to 403DH
  • xxx1xxxx jumps to 4206H
  • xx1xxxxx jumps to 4209H
  • x1xxxxxx jumps to 44040H
  • 1xxxxxxx jumps to 44043H
3322
GOSUB to 3350H to READ BIT.
3325
LD D,00H
Zero D.
3327
GOSUB to 3350H to READ BIT.
332A
GOSUB to 337CH to check for a data error.
332D
LD A,D
Load A with D (the read byte).
332E
CP 7FH
Compare A against 7F to check for a MARKER BYTE.
3330
If no marker byte, then JUMP to 3327H.
3332
If it was a marker byte, then JP to 3290H to flash the * and continue.
3335
RLC C
We need to shift the bit into CARRY so we rotate C left one bit, copying BIT 7 to the CARRY FLAG and the CARRY FLAG to BIT 0.
3337
If the bit was 0, JUMP forward 2 instructions to 333EH.
3339
LD DE,1217H
Load DE with 1217H to set up a delay for 1 BIT.
333C
Skip the next instruction.
LD DE,2B2FH
Load DE with 2B2F to set the delay for a 0 BIT.
DEC D
Decrement D as DELAY #1.
3342
JUMP back to the prior instruction until D is 0.
3344
LD A,02H
Load A with a 2 to set up for a write of 0 VOLTS to TAPE.
3346
OUT (FFH),A
Load Port FFH with A.

NOTE: Port FFH is the cassette port. When outputting to FFH, Bits Zero and 1 set to: 00 is .85V, 01 is .46V, and 10 is 0.0V.
3348
DEC E
Decrement E as DELAY #2.
3349
JUMP back to the prior instruction until E is 0.
334B
LD A,01H
Load A with 01H to prepare to send 0.85 VOLTS to TAPE.
334D
OUT (FFH),A
Load Port FFH with A.

NOTE: Port FFH is the cassette port. When outputting to FFH, Bits Zero and 1 set to: 00 is .85V, 01 is .46V, and 10 is 0.0V.
334F
RET
RETURN.

3350H – READ a BIT

3350
EI
Enable Interrupts.
3351
LD C,00H
Load C with 0.
3353
INC C
Bump C.
3354
LD A,(3840H)
Load A with the contents of 3840H so as to check for a BREAK.
3357
AND 04H
Mask A with 4 (0000 0100).
3359
If the Masked A is 0, then LOOP back to 3353H.
335B
DI
Disable Interrupts.
335C
LD HL,4B42H
Load HL with “BK” to set up to display “BK” over the “**”.
335F
LD (3C3EH),HL
Put the “BK” in HL onto the video screen at 3C3EH.
3362
JUMP to 4203H, which then jumps to 022EH, which is the BREAK VECTOR for cassette and RS-232.

3365H – This is a Port E0H Masked Jump. If the MASKABLE INTERRUPT is xxxxxxx1, it jumps here.

3365
LD E,01H
Load E with 01H (Binary: 0000 0001) to make the bit go high.
3367
Skip the next instruction.
3369
LD E,00H
Load E with 0 to make the bit go low.
336B
LD A,06H
Load A with 6.
336D
ADD A,C
Add A (6) to C, so COUNT = COUNT + 6.
336E
LD C,A
Put the count held in A back into C.
336F
IN A,(FFH)
Poll FFH (to get the level) into A.

NOTE: FFH is the Cassette Port.
3371
AND 01H
Mask A with 1 (0000 0001) to keep only Bit 0.
3373
CP E
Compare A with E (which was the set level).
3374
If A does NOT match E then skip the next 3 instructions.
3376
POP AF
Restore AF from the STACK.
3377
POP AF
Restore AF (the REMOTE CALLER’S ADDRESS) from the STACK.
3378
RET
RETURN to the caller’s caller.
POP AF
Restore AF from the STACK.
337A
EI
Enable Interrupts.
337B
RET
RETURN back top the loop.

337CH – Check for a Data Error.

337C
LD A,C
Load A with C (the count).
337D
CP 22H
Compare A with 22H. Results:
  • If A=22H it sets the ZERO FLAG
  • If A<22H then the CARRY FLAG will be set
  • If A>=22H then the NO CARRY FLAG will be set
337F
RL D
We need to put the data bit into D so we rotate D left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into BIT 0 of D.
3381
CP 0FH
Make sure it was not too quick by checking A against 0FH. This has the effect of checking A-0FH, so if A < 0FH then the CARRY will be set and if A >= 0FH then the NO CARRY will be set.
3383
If A < 0FH then it was too quick and we have a data error so JUMP forward a few instructions 3388H.
3385
CP 3EH
Compare A against 3EH to make sure it was not too slow.
3387
RET C
If it wasn’t too slow, RETURN.
3388
LD A,44H
It was too slow, so load A with a D.
338A
LD (3C3EH),A
Put the “D” on the screen at video location 3C3EH.
338D
RET
RETURN.

338EH – Jump Point for Keyboard Input.

338E
GOSUB to 3060H (which loads the computer version number into A) to check to see if lower case is installed.

NOTE: The Model III v1 and v2 code diverges and remerges too often between here and 3529H, often differing just by memory location, so the tracking of those versions is stopping here.
3391
If 3060H is NOT ZERO then JUMP to 33A3H. 3060H is hard coded to 1 for a Model III and 0 for a Model 4.
3393
LD BC,3880H
Load BC with 3880H (which are the SHIFT KEYS).
3396
LD HL,4018H
Load HL with 4018H (which is the FLAG BYTE).
3399
LD A,(BC)
Load A with the memory contents of 3880H (which are the SHIFT KEYS).
339A
AND 02H
Mask Bit 1 (the RIGHT SHIFT).
339C
LD E,A
Put the masked A into E.
339D
XOR (HL)
Roggle against the old image.
339E
LD (HL),E
Save the new image into (HL).
339F
AND E
Mask Bit 1 against A.
33A0
If NOT ZERO then RIGHT SHIFT PRESSED and we JUMP to 30BDH.
LD A,FFH
Load A with FF to set up for a FLAG = 0FFH = NO CONTROL.
33A5
LD HL,3840H
Load HL with 3840H to start a check for a DOWN ARROW.
33A8
BIT 4,(HL)
Test BIT 4 of (HL) to check for a DOWN ARROW.
33AA
JUMP to 33B4H if the a DOWN ARROW was NOT pressed.
33AC
SLA L
Next we need to check for a a LEFT SHIFT so shift L left.
33AE
BIT 00H,(HL)
Test BIT 0 of (HL) to check for a LEFT SHIFT.
33B0
JUMP to 33B4H if the a LEFT SHIFT was NOT pressed.
33B2
LD A,1FH
Load A with 1F to set up for FLAG = CONTROL KEY.
33B4
LD (4224H),A
Save the CONTROL FLAG into (4224H).

NOTE: 4224H Holds the CONTROL KEY flag.
33B7
Load BC with 3801H (KEYBOARD ROW 0).
33BA
Load HL with 4036H (BUFFER ROW 0).
33BD
LD D,00H
Load D with 0 (so D = ROW 0).
33BF
LD A,(BC)
Load A with the contents held in (BC) to check the keyboard row.
33C0
LD E,A
Load E with the contents held in (BC) to check the keyboard row.
33C1
XOR (HL)
XOR (HL) to set changed bits.
33C2
LD (HL),E
Save the scan back into (HL).
33C3
AND E
Mask A with E (to mask the released keys).
33C4
JUMP to 33F8H if any keys are pressed.
33C6
GOSUB to 3120H to go to the next row.
33C9
Loop back to 33BFH if there are any rows left.
33CC
GOSUB to 313DH to restore scanning variables.
33CF
AND (HL)
MASK A against (HL) to see if the previous keys are still pressed.
33D0
JUMP to 33DAH if the previous keys are still pressed.
33D2
SBC HL,HL
Zero HL by subtracting HL from HL.
33D4
LD (4201H),HL
Load the memory location at 4201H with HL to clear the repeat counter.

NOTE: 4201H is the REPEAT DELAY COUNTER.
33D7
JUMP to 307DH to finish and return a null.

33DA – Keyboard Repeat – Jumps Here if the same keys are still pressed.

33DA
PUSH HL
Save HL to STACK.
33DB
LD HL,(4201H)
Load HL with the repeat delay counter.

NOTE: 4201H is the REPEAT DELAY COUNTER.
33DE
INC HL
Bump HL.
33DF
LD (4201H),HL
Load the memory location at 4201H with HL to clear the repeat counter.

NOTE: 4201H is the REPEAT DELAY COUNTER.
33E2
LD DE,(41FFH)
Load DE with the byte stored at 41FFH.

NOTE: 41FFH is the REPEAT DELAY COUNT.
33E6
SBC HL,DE
Subtract with CARRY DE from HL.
33E8
POP DE
Restore old HL (which is what is in the stack) into DE.
33E9
If we haven’t scanned enough then JUMP to 30A1H to clear flags and RETURN.
33EC
XOR A
Clear A and all flags.
33ED
LD (DE),A
Put a 0 into the memory location pointed to (DE) to let the key be re-read.
33EE
LD (4201H),HL
Load the memory location at 4201H with HL to clear the repeat counter.

NOTE: 4201H is the REPEAT DELAY COUNTER.
33F1
LD L,96H
Load L with 96H to set a fast repeat count.
33F3
LD (41FFH),HL
Save HL into the memory location at 41FFH.

NOTE: 41FFH is the REPEAT DELAY COUNT.
33F6
JUMP to 33A3H to re-scan the keybaord.
33F8
LD E,A
Load E with A.
33F9
PUSH BC
Save BC to the STACK.
33FA
LD BC,05C4H
Load BC with 05C4H to set up a 1/50 second delay for de-bounce.
33FD
GOSUB to 0060H which jumps to the delay routine at 01FBH (which uses BC as a loop counter). It RETs when done so it doesn’t come back here.
3400
POP BC
Restore BC from the STACK.
3401
LD A,(BC)
Load A with the memory contents pointed to by BC to re-check the keyboard.
3402
AND E
Compare A against E to check the pattern.
3403
RET Z
If not the same pattern then RETURN.
3404
LD (41FEH),A
If it is the same pattern then save A into (41FEH).

NOTE: 41FE is the SAVED IMAGE AT POSITION.
3407
LD A,L
Load A with L (the scan position).
3408
LD (41FDH),A
Save A into (41FDH).

NOTE: 41FDH is the SAVED POSITION IN SCAN.
340B
LD A,D
Load A with D (8 * ROW #).
340C
RLA
Rotate A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into the CARRY FLAG.
340D
RLA
Rotate A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into the CARRY FLAG.
340E
RLA
Rotate A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into the CARRY FLAG.
340F
LD D,A
D = A
3410
LD A,E
A = E
3411
RRCA
Rotate A right one bit, with the contents of BIT 0 being put into BOTH the CARRY FLAG and BIT 7. D = 8* ROW # + KEY #.
3412
If the contents of BIT 0 of A was SET, skip forward a few instructions to 3417H.
3414
INC D
D = D + 1
3415
Loop back to 3411H (to keep rotating A right one bit and bumping D).
3417
To check for DUAL SHIFTS GOSUB to 3060H (which loads the computer version number into A and sets the flags).
341A
LD A,(3880H)
Put the contents of memory location 3880H into A to GET SHIFT(S).
341D
If there are DUAL SHIFTS, JUMP to 3421H.
341F
AND 01H
MASK with 01H (Binary: 0000 0001) to keep only Bit 0 to check for shifts.
3421
AND 03H
Further MASK with 03H (Binary: 0000 0011) to keep only Bits 0 and 1 to check for shifts.
3423
If the masked A is 0, then we have no shifts, and skip the next instruction (to 3427H).
3425
SET 6,D
Set BIT 6 of D to offset D for shifts.
3427
LD A,(4019H)
Load A with the contents of memory location 4019H to check for CAPS LOCK.

NOTE: 4019H is the CAPS LOCK TOGGLE.
342A
OR A
Set the flags.
342B
If the ZERO flag is set then there is NO CAPS LOCK so skip the next intruction.
342D
SET 7,D
Set BIT 7 of D to offset D for CAPS LOCK.

NOTE: BIT 7 is the difference between UPPER CASE and LOWER CASE versions of the same letter.
LD HL,3045H
Load HL with 3045H (the KEYBOARD TABLES).
3432
LD E,D
We need DE to be the OFFSET, so load E with D and …
3433
LD D,00H
… load D with 00.
3435
ADD HL,DE
Add DE (the offset over the keyboard table) to HL (the keyboard table).
3436
LD A,(HL)
Get the character pointed to by (HL) and put it into A.
3437
CP 1AH
Check A against 1AH to see if we have a SHIFT DOWN ARROW.
3439
If we have a SHIFT DOWN ARROW then JUMP to 30A1H.
343C
LD B,A
We do NOT have a SHIFT DOWN ARROW so save the character from A into B.
343D
GOSUB to 3060H (which loads the computer version number into A and sets flags).
3440
LD A,B
A = B
3441
If the computer version number is 0 (a Model III) then JUMP to 3447H.
3443
OR A
If we are here then the computer version number is 1 (a Model 4) so set the flags and …
3444
JUMP to 30BDH to TOGGLE CAPS LOCK.

3447 – If this is a Model III then we do not have a CAPS LOCK so check A is a “*” then check to see if the CONTROL KEY FLAG is 1F.

3447
LD HL,4224H
Load HL with the CONTROL KEY flag.

NOTE: 4224H is the CONTROL KEY flag, part of the I/O Router DCB.
344A
CP 2AH
Check A against a *.
344C
If A is not a * then exit the routine and jump to 3452H to jump to 30FDH to continue with a BREAK key check.
344E
LD A,1FH
If A is a * then Put a 1FH (Decimal 26) into A.
3450
CP (HL)
Check the CONTROL KEY FLAG against 1FH and set flags.
3451
LD A,B
Put the character (held in B) back into A.
3452
Jump back to 30FDH to continue with a BREAK key check.

3455 – This is the BOOTSTRAP. Clears ports, checks for a BREAK key and a Floppy Controller.

3455
IM 1
Set the INTERRUPT MODE to 1.
3457
LD SP,407DH
Load the STACK POINTER with 407DH.
345A
OUT (E4H),A
Output A to Port E4H.

NOTE: Port E4H is the non-maskable interrupt latch. This is to clear the non-maskable interrupt status.
345C
OR 20H
OR 20H (0010 0000) against A to turn on Bit 5 (the control bit).
345E
OUT (ECH),A
Output the modified A back to Port E4H.

NOTE: Port E4H is the non-maskable interrupt latch.
3460
LD A,81H
Load A with 81H (Decimal 129, Binary 10000001).
3462
OUT (F4H),A
Output A to Port F4H to select drive 0 and double-density.

NOTE: Port F4H is the Disk Drive and Disk Density Select. Bits 0-3 are the drive select of 0-3 and Bit 7 is 0 for single density and 1 for double density.
3464
LD A,D0H
Load A with D0H (Decimal: 208, Binary: 1101 0000).
3466
OUT (F0H),A
Output “D0H” to Port F0H.

NOTE: Port F0H is the FDC Status Register. Output Commands:
  • 00H – restore
  • 80H – read sector
  • A0H – write normal sector
  • A1H – write read protect sector
  • C0H – read address
  • D0H – reset; puts FDC in mode 1
  • E0H – read track
  • F0H – write track
3468
GOSUB to 3518H to delay 3 instruction cycles, arguably the time it will take for the FDC to respond to that OUT command.
346B
LD A,04H
Load A with a 4 (Binary: 0000 0100).
346D
OUT (E0H),A
Output 4 to E0H to JUMP to 4046H to Set the Maskable Interrupt.

NOTE: Port E0H is the maskable interrupt latch, which directs jumps.
Jump Table:
  • xxxxxxx1 jumps to 3365H
  • xxxxxx1x jumps to 3369H
  • xxxxx1xx jumps to 4046H
  • xxxx1xxx jumps to 403DH
  • xxx1xxxx jumps to 4206H
  • xx1xxxxx jumps to 4209H
  • x1xxxxxx jumps to 44040H
  • 1xxxxxxx jumps to 44043H
346F
LD A,0BH
Load A with 0BH (Binary: 00001011).
3471
OUT (F0H),A
Output 0BH to Port F0H to to RESTORE TO TRACK.

NOTE: Port F0H is the FDC Status Register. A B0H (Decimal: 00001011) sent to Port F0H is the command Restore (0000), Load Head at Beginning (1), No Verify (0), 30ms step rate (11).
3473
LD HL,36AAH
Next we need to initialize some ports via a LDIR. The next 4 commands will move the 76 (4C) bytes from 36AAH to 4000H.
3476
LD DE,4000H
3479
LD BC,004CH
347C
LDIR
347E
LD HL,36F9H
Next we need to initialize more ports via a LDIR. The next 4 commands will move the 64 (40) bytes from 36F9H to 41E5H.
3481
LD DE,41E5H
3484
LD BC,0040H
3487
LDIR
3489
GOSUB to 01C9H to clear the screen.
348C
GOSUB to 028DH to check for a BREAK key.
348F
If we have a BREAK key then jump to Non-Disk BASIC at 37AF.
3492
IN A,(F0H)
If we did not get a BREAK, then we next need to verify the disk controller by polling Port F0H.

NOTE: Port F0H is the FLOPPPY STATUS REGISTER. Results:
  • 1 = Busy
  • 2 = Index/DRQ
  • 4 = Track 0/Lost Data
  • 8 = CRC Error
  • 16 = Seek Error/Record Not Found
  • 32 = Record Type/Write Fault/Head Loaded
  • 64 = Write Protected
  • 128 = Not Ready
3494
INC A
Bump the FDC Status by 1 (which would turn a FFH (128) into a 00H), making a Z flag mean “Disk Controller Not Ready”.
3495
If the FDC Stats + 1 is zero, then we have no disk controller, so jump to Non-Disk BASIC at 37AF.
3498
LD BC,0000H
If we are here, then we have a floppy controller, so set up for a loop of 65,535 times.
349B
DEC BC
Decrease BC by 1.
349C
LD A,81H
Set A to 81H (Decimal: 10000001).
349E
OUT (F4H),A
Send 1000 0001 to Port F4H to set double density.

NOTE: Port F4H is the Disk Drive and Disk Density Select. Bits 0-3 are the drive select of 0-3 and Bit 7 is 0 for single density and 1 for double density.
34A0
LD A,B
OR C
To test a BC against 0, LOAD A with B and then OR C. A will be 0 only if both B and C were zero.
34A2
If we have finished the 65,535 loop then jump to Non-Disk BASIC at 37AF.
34A5
IN A,(F0H)
We are still in the loop, so poll Port F0H into A.

NOTE: Port F0H is the FLOPPPY STATUS REGISTER. Results:
  • xxxx xxx1 = Busy
  • xxxx xx1x = Index/DRQ
  • xxxx x1xx = Track 0/Lost Data
  • xxxx 1xxx = CRC Error
  • xxx1 xxxx = Seek Error/Record Not Found
  • xx1x xxxx = Record Type/Write Fault/Head Loaded
  • x1xx xxxx = Write Protected
  • 1xxx xxxx = Not Ready
34A7
BIT 2,A
Test Bit 2 of A (the Floppy Status). If it is 0 then we haven’t made it to track 0, otherwise we have.
34A9
Still haven’t found track 0, so jump back to 349B to continue the drive polling loop of 65,535 times.

34ABH – Warm Boot Routine.

34AB
LD E,05H
Set up for a loop of 5 using Register E.
34AD
LD BC,0000H
Set up for a loop of 65,536 using Register Pair BC.
34B0
IN A,(F0H)
Poll Port F0H into A.

NOTE: Port F0H is the FLOPPPY STATUS REGISTER. Results:
  • xxxx xxx1 = Busy
  • xxxx xx1x = Index/DRQ
  • xxxx x1xx = Track 0/Lost Data
  • xxxx 1xxx = CRC Error
  • xxx1 xxxx = Seek Error/Record Not Found
  • xx1x xxxx = Record Type/Write Fault/Head Loaded
  • x1xx xxxx = Write Protected
  • 1xxx xxxx = Not Ready
34B2
BIT 01H,A
Check A to see if bit 1 (meaning “Drive Busy”) is set.
34B4
If bit 1 is set, jump to 34C7.
34B6
DEC BC
If bit 1 is not set (meaning, the drive is NOT busy), reduce the counter (BC) by 1.
34B7
LD A,81H
Load A with 81H (Decimal: 129, Binary: 1000 0001).
34B9
OUT (F4H),A
Output A to Port F4H to select drive 0, double density.

NOTE: Port F4H is the Disk Drive and Disk Density Select. Bits 0-3 are the drive select of 0-3 and Bit 7 is 0 for single density and 1 for double density.
34BB
LD A,B
OR C
To test a BC against 0, LOAD A with B and then OR C. A will be 0 only if both B and C were zero.
34BD
If BC is not 0, then loop back to 43B0H.
34BF
LD HL,0277H
If we are here, then we received no BIT 1 of FLOPPY STATUS REGISTER despite 65,536 tries, so we need to deal with that by printing “DISKETTE?” on the screen. Point HL to the “DISKETTE?” message at 0279H.
34C2
GOSUB to 021BH. Note; 021BH will display the character at (HL) until a 03H is found.
34C5
If we are here, there is no disk in drive and we displayed “DISKETTE?” so loop back to 034AB to poll for a disk all over again.
34C7
DEC E
If we are here, it found a diskette so next we need to find the index mark. First decrement E by 1.
34C8
Jump back to the top of this WARM BOOT ROUTINE to check the FDC up to 5 times.
LD A,81H
Load A with 81H (Decimal: 129, Binary: 1000 0001).
34CC
OUT (F4H),A
Output A to Port F4H to select drive 0, double density.

NOTE: Port F4H is the Disk Drive and Disk Density Select. Bits 0-3 are the drive select of 0-3 and Bit 7 is 0 for single density and 1 for double density.
34CE
LD HL,3502H
We need to set the Non-Maskable Interrupt Vector to be a JUMP to 3502H so we do the next 4 steps. Sets 3502H as the jump point for a NMI hit, which is what occurs once a sector has been completely read.
34D1
LD (404AH),HL
34D4
LD A,C3H
Load A with C3H (Decimal: 195, Binary 1100 0011).
34D6
LD (4049H),A
Put the C3H into 4049H.

NOTE: 4049H is the Non-Maskable Interrupt Vector.
34D9
LD A,80H
Load A with 80H (Decimal: 128, Binary 1000 0000).
34DB
OUT (E4H),A
Output “1000 0000” to Port E4H.

NOTE: Port E4H is the non-maskable interrupt latch.
34DD
LD BC,00F3H
Set BC to F3H.

NOTE: Port F3H is the Floppy Disk Controller Data Register.
34E0
LD HL,4300H
Set HL to 4300H, which is where the data is going to go.
34E3
LD A,01H
Prepare to read Sector 1 by loading A with a 1.
34E5
OUT (F2H),A
Output 1 to Port F2H.

NOTE: Port F2H is the Floppy Disk Controller Track Register.
34E7
LD A,80H
Prepare to read a single sector by loading A with 80H (Decimal: 128, Binary: 1000 0000).
34E9
OUT (F0H),A
Output “1000 0000” to Port F0H.

NOTE: Port F0H is the FDC Status Register. Outputting 1000 0000 is issuing the command READ SECTOR (100), SINGLE RECORD (0), SIDE 0 (0), NO 15MS DELAY (0), DISABLE SIDE COMPARE (0).
34EB
GOSUB to 3518H to delay 3 instruction cycles, arguably the time it will take for the FDC to respond to the port command.
34EE
IN A,(F0H)
Load the results of Port F0H into A.

NOTE: Port F0H is the FLOPPPY STATUS REGISTER. Results:
  • 1 = Busy
  • 2 = Index/DRQ
  • 4 = Track 0/Lost Data
  • 8 = CRC Error
  • 16 = Seek Error/Record Not Found
  • 32 = Record Type/Write Fault/Head Loaded
  • 64 = Write Protected
  • 128 = Not Ready
34F0
AND 02H
Mask A against (0000 0010) which will leave only bit 1 active. This will test for the index mark, and Z will indicate that the index mark has NOT been detected, and NZ will indicate the index mark has been detected.
34F2
Loop back 2 instructions to keep polling F0H until the index is found.
34F5
INI
Input the data byte.
LD A,81H
Load A with 81H (Decimal: 129, Binary: 1000 0001) to select disk 0.
34F9
OR 40H
OR A with 40H (Binary: 0100 0000) to set A to double-density.
34FB
OUT (F4H),A
Output A to Port F4H to select drive 0, double density.

NOTE: Port F4H is the Disk Drive and Disk Density Select. Bits 0-3 are the drive select of 0-3 and Bit 7 is 0 for single density and 1 for double density.
34FD
INI
Input the data byte.
34FF
Loop back to 34F7 to set drive and density.

NOTE: This appears to be an infinite loop in the code, but it isn’t in actuality. Once the disk controller has loaded an entire sector, it will trigger a non-maskable interrupt and will exit to 3502H. That was set up at 34CE.

3502H – Non-Maskable Interrupt Jump Point to verify the disk sector read wasn’t in error.

3502
XOR A
Clear A and all flags.
3503
OUT (E4H),A
Send a 0 to Port E4H.

NOTE: Port E4H is the non-maskable interrupt latch. This is to clear the non-maskable interrupt status.
3505
LD HL,45EDH
Now that the NMI jumped here, we need to set a new NMI jump, this time to 45EDH.
3508
LD (4049H),HL
Load “45EDH” into 4049H.

NOTE: 4049H is the Non-Maskable Interrupt Vector.
350B
GOSUB to 3518H to delay 3 instruction cycles, arguably the time it will take for the FDC to respond to the port command.
350E
IN A,(F0H)
Poll Port F0H and put the results into A.

NOTE: Port F0H is the FLOPPPY STATUS REGISTER. Results:
  • xxxxxxx1 = Busy
  • xxxxxx1x = Index/DRQ
  • xxxxx1xx = Track 0/Lost Data
  • xxxx1xxx = CRC Error
  • xxx1 xxxx = Seek Error/Record Not Found
  • xx1x xxxx = Record Type/Write Fault/Head Loaded
  • x1xx xxxx = Write Protected
  • 1xxx xxxx = Not Ready
3510
POP HL
Clean up the Stack.
3511
AND 1CH
Mask A with 1CH (Binary: 0001 1100). This keep only bit 3 (Track 0/Lost Data), bit 4 (CRC Error) and bit 5 (Seek Error/Record Not Found). If NONE of these are present, then Z will be set.
3513
If those 3 errors aren’t generated, then JUMP to 4300H.
3516
If we are here at least one of those errors were present, so JUMP back to 34CAH to try to read the sector again.

3518H – Really Short Delay keyed to FDC Controller Response Time.

3518
PUSH BC
Push BC to the Stack.
3519
POP BC
Get BC from the Stack.
351A
NOP
No Operation.
351B
RET
Return.

351CH – NMI handler. On entry, A holds Bit 5 of the Non-Maskable Interrupt Latch at port 0E4H. 303DH jumped here.

351C
If Bit 5 of the Non-Maskable Interrupt Latch was NOT zero (meaning, disk interrupt), then jump to 4049H.
351F
IN A,(E4H)
Poll Port E4H into A.

NOTE: Port E4H is the Non-Maskable Interrupt Latch.
3521
BIT 5,A
Test Bit 5 of Port E4 against A.

NOTE: Port E4H is the Non-Maskable Interrupt Latch.
3523
Loop back 2 instructions until it is set (i.e., not a zero).
3525
Jump to 0000H to restart the computer.
3528
FF
Unused Garbage. Holdover from v1 ROM.

3529H – Deal with the cursor.

3529
LD DE,3591H
Set the return address to 3591H and put that into DE.
352C
PUSH DE
Push that return address onto the Stack.
352D
IN A,(ECH)
Poll Port ECH and put the results into A.

NOTE: Port ECH is the Miscellaneous Controls port, which covers clock on/off (Bit 0), cassette motor on or off (Bit 1), double size video on or off (Bit 2), and special character set select of Kana or misc (Bit 3). Higher bits are used for the Model 4 only.
352F
LD A,(4022H)
Check to see if the Cursor is on by loading (4022H) into A.

NOTE: 4022H holds the Cursor ON/OFF Flag and will be 0 if the cursor is off, or the the underscore character otherwise.
3532
OR A
Set the flags.
3533
If A was zero, then the cursor is off and we JUMP down to 3557H.
3535
LD A,(401CH)
Check to see if the cursor is to blink by loading (401CH) into A.

NOTE: 401CH holds the Cursor Blink Switch and will be 0 for Blink, and anything else for No Blink.
3538
OR A
Test A.
3539
If the system is set for No Blink, then JUMP to 3557H.
353B
LD HL,401AH
Load HL with 401AH.

NOTE: 401AH is the memory location that stores the cursor blink count.
353E
DEC (HL)
Reduce the memory contents of (401AH) by one.

NOTE: 401AH is the memory location that stores the cursor blink count.
353F
If that reduced count is still not zero, JUMP to 3557H.
3541
LD (HL),07H
Set the cursor blink count to 7.

NOTE: 401AH is the memory location that stores the cursor blink count.
3543
INC HL
Bump HL. This will increase HL from 401AH to 401BH.

NOTE: 401BH holds the cursor blink status – 0 = Off, Anything Else = On.
3544
LD A,(HL)
Poll the cursor blink status memory location and put the results into A.
3545
AND 01H
Mask A against 0000 0001, to have only Bit 0 active.
3547
XOR 01H
XOR A with 01H.
3549
LD (HL),A
Put the toggled cursor blink status into the appropriate memory location.
354A
LD HL,(4020H)
Poll (4020H) and put the result into HL.

NOTE: 4020H holds the current cursor position.
354D
If the current cursor position is 0, then it is off, so JUMP down 2 instructions to 3554H to make the cursor a blank (space).
354F
LD A,(4023H)
Load A with the memory contents of (4023H).

NOTE: 4023H holds the cursor character.
3552
JUMP down to 3556H to skip the next instruction and continue this routine by displaying the character in A.
LD A,20H
Load A with 20H which is the ASCII equivalent of a SPACE.

3556H – Update the heartbeat and deal with the time, including rollover to the next day, month, and year.

3556
LD (HL),A
Put the character held in A into the memory location pointed to by (HL).

NOTE: (HL) will hold the current cursor position.
3557
LD HL,4216H
LET Register Pair HL = 4216H.

NOTE: 4216H is the heartbeat counter.
355A
DEC (HL)
Decrease the number held at (4216H) by 1.
355B
RET NZ
If the number held at (4216H) is not zero, then RETURN.
355C
LD (HL),1EH
Put a 1EH (Decimal: 30) into (4216H).

NOTE: 4216H is the heartbeat counter.
355E
INC HL
Bump HL by 1. HL will now point to 4217H, which is the memory location that holds the SECONDS.
355F
LD DE,0266H
Load DE with 0266H.

NOTE: 0266H points to the TIME DATA of the number of seconds in a minute, the number of mnutes in an hour, and the number of hours in a day.
3562
LD B,03H
Load B with a 03H, to set up a loop where we test seconds, minutes, and hours against their maximums.
3564
INC (HL)
Bump the number currently held in HL to increase the number stored there 1.

NOTE: If HL is 4217H then it is seconds, 4218H then it is minutes, 4217H then it is hours.
3565
LD A,(DE)
Poll the memory contents held at (DE) and put the result into A to get the maximum possible units for each time measure.

NOTE: 0266H points to the TIME DATA of the number of seconds in a minute, 0267H points to the number of mnutes in an hour, and 0268H points to the number of hours in a day.
3566
SUB (HL)
Compare the maximum to what we have by subtracting that maximum from the value pointed at in (HL).
3567
RET NZ
If there is no difference between what we have and the maximum then RETURN.
3568
LD (HL),A
If there is a difference, then put the difference into (HL) because we have to bump the next highest thing (seconds to minutes, minutes to hours, hours to days).
3569
INC HL
Bump HL.

NOTE: If HL is 4217H then it is seconds, 4218H then it is minutes, 4219H then it is hours, and 421AH then it is YEARS.
356A
INC DE
Bump DE.

NOTE: 0266H points to the TIME DATA of the number of seconds in a minute, 0267H points to the number of mnutes in an hour, and 0268H points to the number of hours in a day.
356B
Loop back to 3564H until the loop of 3 has been met, meaning that we have processed seconds, minutes, and hours.
356D
INC HL
Bump HL one more time, to 421BH.

NOTE: 421BH holds the current DAY portion of the date.
356E
INC (HL)
Bump the DAY portion of the date.
356F
INC HL
Bump HL one more time, to 421CH.

NOTE: 421BH holds the current MONTH portion of the date.
3570
LD A,(HL)
Get the month and put it into A.
3571
DEC HL
Decrease HL back to to 421BH.

NOTE: 421BH holds the DAY portion of the date.
3572
DEC A
Decrease A by one (to the previous month).

NOTE: DE currently points to the memory locations housing the of days in each month.
3573
ADD A,E
Add E to A.
3574
LD E,A
Load E with the result. E = E + A.
3575
LD A,(DE)
Poll the number of days in a month and put the result into A.
3576
CP (HL)
Compare A against (HL).

NOTE: If this is not a loop, the HL holds the day portion of the date.
3577
RET NC
If all of this shows that the current day of the month is less than the maximum number of days in a month, then RETURN because we don’t need to bump anything more.
3578
LD A,(HL)
Load A with the current day of the month, as HL was pushed back to point to the day of the month at instruction 3571H.
3579
CP 1EH
Compare A to 1E (Decimal: 30).

NOTE: A CP actually subtracts 1E from A without modifying A, but the flags are set accordingly. Here, if A is < 1E then the CARRY FLAG will be set.
357B
If the carry flag isn’t set then JUMP to 3583H to update the MONTH, but not the YEAR.
357D
DEC HL
Decrement HL to now point to 421AH.

NOTE: 421AH points to the current YEAR.
357E
LD A,(HL)
Load the YEAR into A.
357F
INC HL
Bump HL to 421BH.

NOTE: 421BH points to the current DAY.
3580
AND 03H
Mask A (which is holding the year) with 03H (Binary: 00000011) to test for a leap year.
3582
RET Z
RETURN if that mask showed that we are in the 4th year of a cycle (because 04 and higher are turned off).
LD (HL),01H
Put a 1 into the memory location pointed to by HL (which is DAY).
3585
INC HL
Bump HL to 421CH.

NOTE: 421BH points to the current MONTH.
3586
INC (HL)
Increase the current MONTH by 1.
3587
LD A,(HL)
Put the current MONTH into A.
3588
SUB 0DH
Subract 13 from A.

NOTE: This will test against a month 13. If A is < 13, then the CARRY FLAG will be set.
358A
RET C
If it is NOT month 13 then RETURN to skip the next code which increases the YEAR.
358B
LD (HL),01H
If we are here, then MONTH = 13, so set MONTH to 1.
358D
DEC HL
Decrement HL to 421BH.

NOTE: 421BH points to the current DAY.
358E
DEC HL
Decrement HL to 421AH.

NOTE: 421BH points to the current YEAR.
358F
INC (HL)
Bump the current year.
3590
RET
RETURN.

3591H – Check to see if the clock is on and exit back out if it is off OR the heartbeat shows that the clock was just updated. Pass through otherwise.

3591
LD A,(4210H)
Test to see if the clock is on by loading A with the memory contents of 4210H.

NOTE: 4210H is the bit mask for Port ECH. Port ECH is the Miscellaneous Controls port, which covers clock on/off (Bit 0), cassette motor on or off (Bit 1), double size video on or off (Bit 2), and special character set select of Kana or misc (Bit 3). Higher bits are used for the Model 4 only.
3594
BIT 0,A
Test Bit 0 of A to see if the clock is on or off.
3596
RET Z
If Bit 0 of A is ZERO, then return.
3597
LD A,(4216H)
If we are here, then the clock is on, so load A with the memory contents of (4216H) to see if the clock was just updated.

NOTE: 4216H is the heartbeat counter.
359A
CP 1EH
Compare the heartbeat counter against 1EH.

NOTE: A CP actually subtracts 1E from A without modifying A, but the flags are set accordingly.
359C
RET NZ
If the clock was not just updated, then RETURN.
359D
LD HL,3C35H
If the clock was just updated, then we need to display to screen so we set HL to the screen location of 3C35H which is the top line of the screen, 10 characters from the end of first line.

35A0H – Put the Clock 10 characters from the end of the first line. We enter this routine with HL pointing to the screen location 10 characters from the end of the first line.

35A0
LD DE,4219H
Set DE to 4219H.

NOTE: 4219H is the current HOUR.
35A3
LD C,3AH
Load C with a :.

NOTE: This routine is also used to convert the date, and C will be swapped out to a / for that routine.
35A5
LD B,03H
Load B with a 3.

NOTE: This is because we need to convert 3 numbers, so we will loop 3 times.
35A7
LD A,(DE)
Put the memory contents of DE into A.

NOTE: This will be HOUR (4219H) on the first pass, MINUTE (4218H) on the second pass, and SECOND (4219H) on the third pass.
35A8
DEC DE
Decrement DE to point to the next unit to be dealt with.
35A9
LD (HL),2FH
Load the memory location pointed to by (HL) with 2F.

NOTE: 2F is a / which is also 1 character below a 0.
35AB
INC (HL)
Increase whatever is held in (HL). On the first iteration, this change the character at the screen location to a 0.
35AC
SUB 0AH
A = A – 10. If A is < 10, then the CARRY FLAG will be set and if A is > 10, the NOT CARRY FLAG will be set.
35AE
Loop back 2 instructions if A > 10 [V!!!].
35B0
ADD A,3AH
If we are here, then A was less than 10, so we need to increase A by 3A (Binary: 0011 1010) to point to the ASCII number of the remainder.
35B2
INC HL
Bump HL to point to the next location on the video screen. On the first iteration, this will be the 2nd digit of the HOUR.
35B3
LD (HL),A
Put the ASCII value of the remainder onto the screen. On the first iteration, this will be the 2nd digit of the HOUR put into 4220H.
35B4
INC HL
Bump HL to point to the next location on the video screen. On the first iteration, this will be the 3rd character.
35B5
DEC B
Decrement B to the next unit. On the first iteration, this will move from 3 to 2.
35B6
RET Z
If we have processed all passes in the loop, RETURN.
35B7
LD (HL),C
If we are here, then the routine has not yet looped 3 times, so put a : onto the screen.
35B8
INC HL
Bump HL to point to the next location on the video screen.
35B9
JUMP back to 35A7 to continue the loop.

35BBH – Put the DATE 8 characters from the end of the first line. We enter this routine with HL pointing to the screen location and we just jump into the prior routine with a different pointer to the DATE and a change in the delimeter to a /.

35BB
LD DE,421CH
Load DE with 421CH.

NOTE: 421CH holds the current MONTH.
35BE
LD C,2FH
Load C with a /.
35C0
Jump into the above routine to convert the Month, Day, and Year.

35C2H – Maskable Interrupt Handler.

35C2
PUSH AF
Save AF to the STACK.
35C3
IN A,(E0H)
Poll Port E0H which is the MASKABLE INTERRUPT LATCH and put the results into A.
35C5
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35C6
If Bit 0 is low then JUMP to 3365H.
35C9
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35CA
If Bit 0 is low then JUMP to 3369H.
35CD
PUSH BC
Save all the registers.
35CE
PUSH DE
35CF
PUSH HL
35D0
PUSH IX
35D2
PUSH IY
35D4
LD HL,35F1H
Load HL with 35F1H to set the return address.
35D7
PUSH HL
Push HL to the STACK.
35D8
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35D9
If Bit 0 is low then JUMP to 4046H.

NOTE: 4046H is Interrupt Vector 2 and contains a JUMP to 35A9H. It is commonly used by the clock.
35DC
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35DD
If Bit 0 is low then JUMP to 403DH.

NOTE: 403DH is Interrupt Vector 3 and contains a JUMP to 35FAH.
35E0
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35E1
If Bit 0 is low then JUMP to 4206H.

NOTE: 403DH is Interrupt Vector 4 and contains a JUMP to 35FAH.
35E4
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35E5
If Bit 0 is low then JUMP to 4209H.

NOTE: 4209H is Interrupt Vector 5 and contains a JUMP to 35FAH.
35E8
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35E9
If Bit 0 is low then JUMP to 4040H.

NOTE: 4209H is Interrupt Vector 6 and contains a JUMP to 35FAH.
35EC
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
35ED
If Bit 0 (which was BIT 7) is low then JUMP to 4043H.

NOTE: 4043H is Interrupt Vector 7 and contains a JUMP to 35FAH.
35F0
POP HL
Restore all registers.
35F1
POP IY
35F3
POP IX
35F5
POP HL
35F6
POP DE
35F7
POP BC
35F8
POP AF
35F9
EI
Enable Interrupts.
35FA
RET
RETURN.

35FBH – RS-232 Initialization Routine. I’m [guessing] that IX is set to 41F5H

35FB
DI
Disable Interrupts so they don’t interrupt this routine.
35FC
IN A,(EAH)
Poll Port EAH into A.

NOTE: Port EAH is the RS-232 UART Control Register/Status Register. Input:
  • Bit 3: Parity error (1=True)
  • Bit 4: Framing Error (1=True)
  • Bit 5: Overrun (1=True)
  • Bit 6: Data Sent (1=True)
  • Bit 7: Data Ready (1=True)
35FE
CP FFH
Compare A with FFH to see if the RS-232 exists.
3600
If the RS-232 does NOT exist, JUMP down to 363AH.
3602
XOR A
Flip the RS-232 Port Results, just to get a non-zero result.
3603
OUT (E8H),A
Output A to port E8H.

NOTE: Port E8H is the RS-232 Status Register & Master Reset. Outputting ANYTHING to Port E8H resets the RS-232.
3605
LD A,(IX+03H)
Load the BAUD RATE CODE into A.

NOTE: 41F8H holds the baud rate code.
3608
OUT (E9H),A
Output A to Port E9H.

NOTE: Port E9H is the RS-232 Baud Rate Selects and Sense Switches. Outputting to Port E9H will set the Baud Rate as follows:
  • Bits 0-3 – Select the Receive Rate
  • Bits 4-7 – Select the Transmit Rate
360A
LD A,(IX+04H)
Load the CONFIURATION CODE into A.

NOTE: 41F9 holds the RS-232 Configuration Code.
360D
OR A
Set the flags.
360E
If the CONFIGURATION CODE in A is 0, then JUMP down to 363AH.
3610
OUT (EAH),A
Output the CONFIGURATION CODE to Port EAH.

NOTE: Port EAH is the RS-232 UART Control Register/Status Register. For output:
  • Bit 0: Data Terminal Ready
  • Bit 1: Request to End
  • Bit 2: Break
  • Bit 3: Parity Enable
  • Bit 4: Stop Bits
  • Bit 5: Select
  • Bit 6: Word Length
  • Bit 7: Parity (0=Odd, 1=Even)
3612
LD IY,41E5H
Load IY with 41E5H.

NOTE: 41E5H Is the RS-232 Input DCB. 1=READ ONLY.
3616
GOSUB to 3644H [to CLEAR OPTIONS].
3619
LD A,(IX+05H)
Load the WAIT SWITCH into A.

NOTE: 41FAH holds the RS-232 Wait Switch.
361C
OR A
Set the flags.
361D
If the WAIT SWITCH was ZERO, skip the next instruction and pick up at 3623H.
361F
SET 01H,(IY+04H)
If we are here, the WAIT SWITCH was NOT zero, so SET BIT 1 of (41E9H) to SET the WAIT FLAG.

NOTE: 41E9H is the RS-232 Input DCB:
  • Bit 2: Driver On/Off
  • Bit 1: Wait/No Wait
3623
SET 02H,(IY+04H)
and SET BIT 2 of (41E9H) to SET the ACTIVE FLAG.

NOTE: 41E9H is the RS-232 Input DCB:
  • Bit 2: Driver On/Off
  • Bit 1: Wait/No Wait
3627
LD IY,41EDH
Load IY with 41EDH.

NOTE: 41EDH is the RS-232 Output DCB. Type = 2 = Write Only.
362B
OR A
Set flags.
362C
If the ZERO flag is set, we have NO WAIT, so JUMP to 3632H.
362E
SET 01H,(IY+04H)
Set Bit 1 of 41F1H to set the WAIT FLAG.

NOTE: 41F1H is part of the RS-232 Output DCB:
  • Bit 2: Driver ON/OFF
  • Bit 1: Wait/No Wait
3632
SET 02H,(IY+04H)
Set Bit 2 of 41F1H to set the ACTIVE FLAG.
3636
IN A,(E8H)
Poll Port E8H and put the result into A.

NOTE: Port E8H is the RS-232 Status Register & Master Reset. Input:
  • Bit 4: Ring Indicator
  • Bit 5: Carrier Detect
  • Bit 6: Data Set Ready
  • Bit 7: Clear to Send
3638
EI
Re-Enable Interrupts.
3639
RET
RETURN.

363A – This will zero out a bunch of RS-232 Related Ports and Memory Addresses. We wind up here if there is no RS-232 or the RS-232 CONFIGURATION CODE is 0.

363A
XOR A
Clear A and all flags.
363B
LD B,04H
Load B with 4 as a counter. 4 is because there are 4 ports – E8H-EBH:
  • Port E8H: RS-232 Status Register & Master Reset
  • Port E9H: RS-232 Baud Rate Select and Sense Switches
  • Port EAH: RS-232 UART Control Register and Status Register
  • Port EBH: RS-232 Data Register
363D
LD C,0E8H
Load C with E8H.
OUT (C),A
Send a 0 to the current port. On the first iteration, this is E8H (the RS-232 Status Register & Master Reset).
3641
INC C
BUMP C to the next port.
3642
Jump back to 363FH until all 4 ports have been reset.
LD HL,41E8H
Load HL with 41E8H.

NOTE: 41E8 is the Input Buffer of the RS-232 Input DCB.
3647
LD B,03H
Load B with 3 as a counter. 3 is for 3 bytes – 41E8H, 41E9H, and 41EAH.
LD (HL),00H
Load (HL) with 00H.
364B
INC HL
Bump HL.
364C
Loop back to 3649H until 3 bytes have been zeroed.
364E
LD HL,41F0H
Load HL with 41F0H.

NOTE: 41F0H is the 1 characer output buffer for the RS-232 Output DCB.
3651
LD B,03H
Load B with 3 as a counter. 3 is for 3 bytes – 41F0H, 41F1H, and 41F2H.
LD (HL),00H
Load (HL) with 00H.
3655
INC HL
Bump HL.
3656
Loop back to 3653H until 3 bytes have been zeroed.
3658
RETURN.

365AH – RS-232 Input Routine.

365A
LD IX,41E5H
Load IX with 41E5H.

NOTE: 41E5H is the DCB for RS-232 Input. 41E8H is the 1 Character RS-232 Input.
365E
XOR A
Clear A and all Flags.
365F
LD (IX+03H),A
Load (41E8H) with a Zero.

NOTE: 41E8H is the 1 Character RS-232 Input.
3662
BIT 2,(IX+04H)
Test Bit 2 of 41E9H to see if the RS-232 is active.

NOTE: Bit 2 of 41E9 contains the DRIVER ON/OFF.
3666
RET Z
If the Driver is OFF, RETURN.
3667
IN A,(EAH)
If the Driver is ON, Poll Port EAH into A.

NOTE: Port EAH is the RS-232 UART Control Register/Status Register. Input:
  • Bit 3: Parity error (1=True)
  • Bit 4: Framing Error (1=True)
  • Bit 5: Overrun (1=True)
  • Bit 6: Data Sent (1=True)
  • Bit 7: Data Ready (1=True)
3669
BIT 7,A
Test Bit 7 of A.

NOTE: Bit 7 will be 1 if DATA READY (1=True).
366B
If NOT ZERO, then the DATA is NOT ready, and JUMP to 367AH.
366D
BIT 1,(IX+04H)
Test Bit 1 of 41E9H.

NOTE: Bit 1 of 41E9 contains the WAIT/NO WAIT of the RS-232 Input DCB.
3671
RET Z
If its NO WAIT then RETURN, otherwise continue (to keep polling).
3672
GOSUB to 028DH to check for a BREAK key.
3675
JUMP to 3667H to poll again if there was NO BREAK.
3677
JUMP to 4203H if the BREAK key was pressed.

NOTE: 4203H JUMPS to 022EH and is the break vector for tape and RS-232.
367A
IN A,(EBH)
Poll Port EBH to A.

NOTE: Port EBH is the RS-232C Data Register. It contains the data received from the RS-232C.
367C
LD (IX+03H),A
Load (41E8H) with a A (the data from Port EBH).

NOTE: 41E8H is the 1 Character RS-232 Input.
367F
RET
RETURN.

3680H – RS-232 Output Routine.

3680
LD IX,41EDH
Note. 41EDH is the RS-232 Output DCB, and 41F1H holds DRIVER ON/OFF in BIT 2, and WAIT/NO WAIT in BIT 1.
3684
BIT 2,(IX+04H)
Test Bit 2 of 41F1H to see if the RS-232 is active.
3688
RET Z
If the RS-232 is NOT active, RETURN.
IN A,(EAH)
If the RS-232 IS active, then Poll Port EAH into A.

NOTE: Port EAH is the RS-232 UART Control Register/Status Register. Input:
  • Bit 3: Parity error (1=True)
  • Bit 4: Framing Error (1=True)
  • Bit 5: Overrun (1=True)
  • Bit 6: Data Sent (1=True)
  • Bit 7: Data Ready (1=True)
368B
BIT 6,A
Test Bit 6 of Port EAH to see READY TO SEND.
368D
If READY TO SEND then skip forward to 369CH.
368F
BIT 1,(IX+04H)
Test Bit 1 of 41F1H to see if the RS-232 is active.

NOTE: 41F1H Hholds DRIVER ON/OFF in BIT 2, and WAIT/NO WAIT in BIT 1.
3693
RET Z
If RS-232 is NOT active, RETURN.
3694
GOSUB to 028DH to check for a BREAK key.
3697
JUMP to 3689H to poll again if there was NO BREAK.
3699
JUMP to 4203H if the BREAK key was pressed.

NOTE: 4203H JUMPS to 022EH and is the break vector for tape and RS-232.
369C
LD A,(IX+03H)
Load A with the memory contents of (41EEH).

NOTE: 41EEH is the Driver Address for the RS-232 Output DCB.
369F
OR A
Test A and Set Flags.
36A0
If not zero, then there is a character in the buffer, so skip the next instruction.
36A2
LD A,C
Load A with C [GET CHAR FROM DISPATCHER].
36A3
OUT (EBH),A
Send A out of Port EBH.

NOTE: Port EBH is the RS-232C Data Register. It contains the data to be sent to the RS-232C.
36A5
LD (IX+03H),00H
Load memory contents of (41EEH) with a 0.

NOTE: 41EEH is the Driver Address for the RS-232 Output DCB.
36A9
RET
RETURN.

36AAH – Initial Vectors and DCBs for RAM 4000H-404BH.

36AA
C3 96 1C C3 78 1D C3 90 1C C3 D9 25 C9 00 00 C9 00 00 C3 18 30 01 24 30 00 01 07 00 00 07 73 04 00 3C 00 B0 00 06 C2 03 43 01 00 FF 52 C3 00 50 C7 00 00 AF C9 00 AA AA AA AA AA AA AA C3 FA 35 C3 FA 35 C3 FA 35 C3 29 35 C7 00

36F5H – UNUSED.

36F5
00 00 00 00

36F9H – Initial Vectors and DCBs for RAM 41E5H-4224H.

36F9
01 1E 30 00 00 00 52 49 02 21 30 00 00 00 52 4F 02 1B 30 55 6C FF 52 4E 00 00 FF FF
36AA
00 00 C3 2E 02 C3 FA 35 C3 FA 35 41 32 03 32 28 03 3C 04 00 00 1E 33 1C 0C 00 0E 02 02 39 37 00 00 00 00 FF

3739H – I/O Re-Router.

3739
LD A,(IX+03H)
Load A with the character at (IX+3) which is the first character of the destination.
373C
CP 52H
Check to see if that characer is a “R”.
373E
If it is not an “R” then skip the next instruction and JUMP to 3743H.
3740
LD A,(IX+04H)
Load A with the character at (IX+4) which is the second character of the destination.
GOSUB to 375EH to get the applicable DCB Address from the DCB Table.
3746
RET NZ
If the DCB Address was not found, then RETURN.
3747
PUSH HL
Store HL onto the STACK.
3748
LD A,(IX+05H)
Load A with the characer at (IX+5) which is the first character of the source.
374B
CP 52H
Check to see if that characer is a “R”.
374D
If it is not an “R” then skip the next instruction and JUMP to 3752H.
374F
LD A,(IX+06H)
Load A with the character at (IX+6) which is the second character of the source.
3752
GOSUB to 375EH to get the applicable DCB Address from the DCB Table.
3755
EX DE,HL
Swap the SOURCE DCB and the DESTINATION DCB.
3756
POP HL
Restore HL from the Stack.
3757
RET NZ
If the DCB Address was not found, then RETURN.
3758
LD BC,0003H
If the DCB Address was found, we need to move 3 bytes, so set up BC with a 3.
375B
LDIR
Move the 3 bytes from (HL) to (DE).
375D
RET
Return.

375EH – Look Up DCB Address. On SUCCESSFUL exit, HL will have the DCB address.

375E
LD HL,376CH
Load HL with 376CH (which is a table of K, D, P, I, and O).
3761
LD BC,000FH
Load BC with 0FH (Decimal: 15), as the table is 15 bytes long.
3764
CPIR
Search for the character on the table.

NOTE: CPIR will check (HL) vs A. HL is then increased, and BC decreased. If BC is still not zero, and Z is not set, it repeats.
3766
RET NZ
If the Z flag is set, the DCB was not found on the table.
3767
LD A,(HL)
If the Z flag is not set, then we have a match, so load A with the memory contents of (HL).
3768
INC HL
Bump HL.
3769
LD H,(HL)
Load H with the memory contents of (HL).
376A
LD L,A
Load L with A.
376B
RET
Return.

376CH – DCB Address Table.

376C
“K” 4015H
376F
“D” 401DH
3772
“P” 4025H
3775
“I” 41E5H
3778
“O” 41EDH

377BH – This is jumped to by 2B91 in the middle of the tokenize routine.

377B
CP 22H
If the character in register A is not an end of the BASIC line character, then test the character against 22H to see if it is a ".
377D
If the character in register A is not a ", then JUMP forward a few instructions to 3789H.
377F
LD A,(409FH)
Load A with the memory contents of 409FH.

NOTE: 409FH is the DATA FLAG.
3782
XOR 01H
XOR A against 1 (Binary: 0000 0001).

NOTE: XOR is an exclusive OR, meaning that if the 2 things are the SAME the result is 0, and if the 2 things are DIFFERENT, the result is 1.
3784
LD (409FH),A
Load memory location 409FH with a the XOR’d results.

NOTE: 409FH is the DATA FLAG.
3787
LD A,22H
Load A with 22H, which is a ".
CP 3AH
Compare A against 3AH (which is a :) doing A – 3AH. If A < 3AH, for UNSIGNED items, then the C FLAG is set. If A => 3AH, for UNSIGNED items, then the C FLAG is reset. If A = 3AH then the Z flag is set.
378B
If A is 3AH then JUMP to 06AAH.

NOTE: 06AAH is in the middle of the KEYBOARD DRIVER ENTRY ROUTINE.
378E
LD A,(409FH)
Otherwise, Load A with the memory contents of 409FH.

NOTE: 409FH is the DATA FLAG.
3791
RRA
Rotate the contents of A one bit to the right, with the contents of the carry bit being moved to bit 7 and the contents of bit 0 being moved to the carry bit. If Bit 0 is low then NC will be set.
3792
If Bit 7 of the DATA FLAG was set, then JUMP to 06A8H.

NOTE: 06A8H is in the middle of the KEYBOARD DRIVER ENTRY ROUTINE.
3795
RLA
Rotate A left one bit, with the contents of BIT 7 being put into the CARRY FLAG and the CARRY FLAG are put into BIT 0. This puts the read data into the CARRY FLAG.
3796
JP 06A3H
JUMP to 06A3H.

NOTE: 06A3H is the REM processor in the middle of the KEYBOARD DRIVER ENTRY ROUTINE.

3799H – BASIC TIMES (DATE$+” “+TIME$)

3799
RST 10H
Call the EXAMINE NEXT SYMBOL routine at RST 10H.
NOTE:
  • The RST 10H routine loads the next character from the string pointed to by the HL register into the A-register and clears the CARRY FLAG if it is alphabetic, or sets it if is alphanumeric.
  • Blanks and control codes 09H and 0BH are ignored causing the following character to be loaded and tested.
  • The HL register will be incremented before loading any character therfore on the first call the HL register should contain the string address minus one.
  • The string must be terminated by a byte of zeros.
379A
PUSH HL
Save HL (the current position) to the STACK.
379B
LD A,11H
Load A with 11H (Decimal: 17).

NOTE: This is to set up for a 17 Byte String.
379D
GOSUB to 2857H to create the string.
37A0
LD HL,(40D4H)
Load HL with the memory contents of (40D4H).

NOTE: 40D4 is the string pointer.
37A3
GOSUB to 35BBH.

NOTE: 35BBH populates the DATE$ and puts it on the screen.
37A6
LD (HL),20H
Load the memory location pointed to by HL with a SPACE.
37A8
INC HL
Increment HL to move 1 character over.
37A9
GOSUB to 35A0H.

NOTE: 35A0H populates the TIME$ and puts it on the screen.
37AC
JUMP to 2884H, which is in the middle of the STRING routine.

37AFH – This is a jump to NON-Disk BASIC

37AF
GOSUB to 37B5H to set the cassette tape speed.
37B2
JUMP to 0075H to go to non-disk initialization.

37B5H – Set the TAPE BAUD RATE ($SETCAS).

37B5
EI
Enable Interrupts.
37B6
GOSUB to 37D7H which loads A with a carrage return, and jumps to 0033H to display it.
37B9
LD HL,37F6H
Load HL with the address of the “CASS?” message.
37BC
GOSUB to 021BH.

NOTE: 021BH will display a message Until 03H or 0DH Reached.
37BF
GOSUB to 0049H.

NOTE: 0049H is the $KBWAIT routine which scans the keyboard and returns with the key pressed, if any, in register A.
37C2
CP 0DH
Compare A and 0D (a CARRIAGE RETURN).
37C4
If the CARRIAGE RETURN is hit, then JUMP to 37D4H to default to HIGH SPEED.
37C6
PUSH AF
Save AF to the STACK.

NOTE: A currently holds the character pressed in response to the “CASS?” message.
37C7
GOSUB to 0033H.

NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.
37CA
POP AF
Restore AF from the STACK.

NOTE: A will then hold the character pressed in response to the “CASS?” message.
37CB
CP 48H
Compare A with 48H (ASCII: H).
37CD
If A = H then JUMP to 37D4H to select HIGH SPEED.
37CF
CP 4CH
Compare A with a 4CH (ASCII: L).
37D1
If A was NOT a “L” then JUMP back to 37B5H to try again.

37D4 – Set the Selected Cassette Baud Rate as LOW SPEED

37D3
XOR A
Set A to 0.

NOTE: Storing a 0 at 4211H will select low speed.

37D4 – Write the Byte to Select the Selected “CASS?” Cassette Baud Rate

37D4
LD (4211H),A
Save A (which is either “H” or 0 at this point) into (4211H).

NOTE: 4211H holds the CASSETTE BAUD RATE SELECT as:
  • 0: 500 Baud
  • Anything Else: 1500 baud
37D7
LD A,0DH
A = CARRIAGE RETURN
37D9
Display the CARRIAGE RETURN via a JUMP to 0033H.

NOTE: 0033H is the character print routine, to put the character held in Register A at the current cursor position.

37DCH – Enable the TIME$ Command

37DC
LD HL,3030H
Load HL with 3030H.

NOTE: 3030H is the STRING=DATE$+””+TIME$ routine.
37DF
LD (4177H),HL
Load the memory location held at 4177H with HL.

NOTE: 4176H is the TIME$ vector as is currently set to be JP ?L3 ERROR as the M1/M3 ROM considered that to be a DOS command. It is not a DOS command for a Model III so that jump needs to be changed. In this case, it is changed from JP ?L3 ERROR to JP 3030H.
37E2
JUMP to 022EH to continue.

NOTE: 022EH will enable interrupts, show the READY prompt, and RETURN.
37E5
AA
Unused.
37E6
AA
Unused.
37E7
AA
Unused.

37E8H – Hidden 2 Byte Code – Printer Output. While these bytes may show JR NC,381AH, that is not really a valid command as there is no executable code at 381AH.

37E8
N/A
The equivalent of testing port F8H for status. If you PEEK this location, you will get the PRINTER STATUS (63 = Printer ON; 143 = Printer Off) rather than what may actually be contained at this ROM location. Thanks to George Philips for this info!
37E9
N/A
The equivalent of sending a byte to port F8H. If you POKE this location, you are sending a byte to the PRINTER. Thanks to George Philips for this info!

37EA – Computer Version Number

37EA
01
Computer version.

37EBH – Display the Copyright Message

37EB
GOSUB to 021BH.

NOTE: 021BH will display the message pointed to by HL.
37EE
LD HL,0202H
Load HL with 0202H.

NOTE: 0202H points to the message ‘(C) “80 Tandy”‘.
37F1
GOSUB to 021BH.

NOTE: 021BH will display the message pointed to by HL.
37F4
Jump Back to 37DC to patch the TIME$ Function into being live and then going to READY.

37F6H – “CASS?” Message Storage Area.

37F6
0E “CASS?” 03
CURSOR ON + “CASS?” Message Storage Area + END OF TEXT.
37FE
AA AA
Unused.