Now the blind boot state machine has loaded the contents of master boot record in its read FIFO to be executed by 6502, this is description of the MBR contents.
First part is the 6502 reset vector. Since CF's read FIFO is currently mapped to $8000-$FFFF, the reset vector need to be in high 32K memory. A good vector is the NOP instruction, $EA that places the reset vector at $EAEA. Since there are some uncertainly how many instructions will be fetched after reset, there are 5 NOP instruction followed by illegal instruction $3 that executes in one clock cycle. The single cycle illegal instruction is for synchronization purpose in case the 5th and last $EA is treated as a NOP instruction which takes two cycles to execute; in that case $3 serves as dummy read of the NOP instruction.
Dummy reads following an instruction execution is the biggest worry for blind boot. One byte instruction that takes two clocks to execute such as NOP will need a dummy data following the one byte instruction. I'm using the illegal instruction $3 as the dummy data in my software. Another complication is the dummy data is needed only if the dummy operation is in the memory range of $8000-$FFFF which causes a CF read cycle. If the dummy operation is in the memory range of $0-$7FFF, it is accessing RAM and not causing CF read so dummy data is not needed.
Really, the case-by-case analysis of dummy operation is too complicated for me to manage so I do the bare minimum and do it with a Macro. The idea is to create a small program in RAM using a series of macros then jump to RAM to execute the program normally. I have 256 bytes to create such program. This is the macro:
Code:
.macro savebyte val
LDA #val
STA $800,x
INX
.byte 3
.endmacro
LDA #val is two bytes execute in two clock cycles so no need for dummy data; STA $800,x is 3-byte instruction that executes in 5 clocks so it does two dummy operations BUT the operations are in $800-$8FF range which is RAM area, so no dummy data needed in the instruction stream. INX is one byte but executes in two clocks, so it needs a dummy data which is $3.
The program after reset vector is LDX #0 to initialize regX (2-byte instruction executed in 2 clocks, no dummy operation), then a series of macro to create a program in RAM, followed by enough $3 illegal instructions to the last 3 bytes of the 256-byte FIFO which is JMP $800 to execute the program created in RAM.
The program created in RAM is a simple serial reader. It checks for serial receive data ready and write the incoming serial data to RAM start from $900. After 256 bytes of data is received, it jumps into $900 to execute.
The 256-byte serial data is an Intel Hex loader that loads a monitor and jumps into it. So this is a 4-stage boot process:
Stage 1, executes data from CF's master boot record to create a serial reader in RAM;
Stage 2, serial reader reads in 256-byte Intel Hex loader from the serial port;
Stage 3, Intel Hex loader reads in a monitor into memory
Stage 4, monitor load application programs as needed.
The reason for all these stages is ease of test and development. Later I'll shorten the process so Stage 1 creates a CF reader that reads dedicated sectors of data from CF disk into RAM and executes it.
This is the listing of the program in MBR.
Code:
00B300 1 ;This is the opcode stream for master boot record
00B300 1 ; it will be executed as stream of opcode for 65c02
00B300 1 EA NOP ;reset vector plus extra padding
00B301 1 EA NOP
00B302 1 EA NOP
00B303 1 EA NOP
00B304 1 EA NOP
00B305 1 03 .byte 3 ;illegal instruction executed in 1 cycle
00B306 1 ;for synchronization purpose
00B306 1 A2 00 LDX #0
00B308 1 A9 A2 9D 00 savebyte $a2 ;LDX #0
00B30C 1 08 E8 03
00B30F 1 A9 00 9D 00 savebyte $0
00B313 1 08 E8 03
00B316 1 A9 E8 9D 00 savebyte $e8 ;add a delay loop
00B31A 1 08 E8 03
00B31D 1 A9 D0 9D 00 savebyte $d0
00B321 1 08 E8 03
00B324 1 A9 FD 9D 00 savebyte $fd
00B328 1 08 E8 03
00B32B 1 A9 AD 9D 00 savebyte $ad ;LDA SerStat($8000)
00B32F 1 08 E8 03
00B332 1 A9 00 9D 00 savebyte $00
00B336 1 08 E8 03
00B339 1 A9 80 9D 00 savebyte $80
00B33D 1 08 E8 03
00B340 1 A9 29 9D 00 savebyte $29
00B344 1 08 E8 03
00B347 1 A9 01 9D 00 savebyte $01
00B34B 1 08 E8 03
00B34E 1 A9 F0 9D 00 savebyte $f0 ;BEQ xxx
00B352 1 08 E8 03
00B355 1 A9 F9 9D 00 savebyte $f9
00B359 1 08 E8 03
00B35C 1 A9 AD 9D 00 savebyte $ad ;LDA SerData ($8001)
00B360 1 08 E8 03
00B363 1 A9 01 9D 00 savebyte $01
00B367 1 08 E8 03
00B36A 1 A9 80 9D 00 savebyte $80
00B36E 1 08 E8 03
00B371 1 A9 9D 9D 00 savebyte $9d ;STA $900,x
00B375 1 08 E8 03
00B378 1 A9 00 9D 00 savebyte $0
00B37C 1 08 E8 03
00B37F 1 A9 09 9D 00 savebyte $9
00B383 1 08 E8 03
00B386 1 A9 E8 9D 00 savebyte $e8 ;INX
00B38A 1 08 E8 03
00B38D 1 A9 D0 9D 00 savebyte $d0 ;BNE xxx
00B391 1 08 E8 03
00B394 1 A9 F0 9D 00 savebyte $f0
00B398 1 08 E8 03
00B39B 1 A9 4C 9D 00 savebyte $4c ;JMP $900
00B39F 1 08 E8 03
00B3A2 1 A9 00 9D 00 savebyte $0
00B3A6 1 08 E8 03
00B3A9 1 A9 09 9D 00 savebyte $9
00B3AD 1 08 E8 03
00B3B0 1 03 03 03 03 .res $4d,3 ;pad with illegal instruction that execute in 1 cycle
00B3B4 1 03 03 03 03
00B3B8 1 03 03 03 03
00B3FD 1 ; until last 3 bytes of 256-byte page
00B3FD 1 4C 00 08 JMP $800
00B400 1 ;program above is executed as it streams out of CF data port
00B400 1 ;****************************** end of FT245 bootstrap ********************
00B400 1 ; .org $800
00B400 1 ;this is the first stage loader, loading 256 bytes of following data into 0x900
00B400 1 ; then jump into 0x900
00B400 1 ;00 1 A2 00 LDX #0
00B400 1 ;02 1 delayx:
00B400 1 ;02 1 E8 INX ;delay a bit for nDASP to negate
00B400 1 ;03 1 D0 FD BNE delayx
00B400 1 ;05 1 xxx:
00B400 1 ;05 1 AD 00 80 LDA SerStat ;chk serial receive ready flag
00B400 1 ;08 1 29 01 AND #1
00B400 1 ;0A 1 F0 F9 BEQ xxx
00B400 1 ;0C 1 AD 01 80 LDA SerData
00B400 1 ;0F 1 9D 00 09 STA $900,x
00B400 1 ;12 1 E8 INX
00B400 1 ;13 1 D0 F0 BNE xxx
00B400 1 ;15 1 4C 00 09 JMP $900