; Boot code for Tube Flex - 6809 Flex running in an Acorn Tube environment ; ======================================================================== ; Searches for a BBCFLEX.SYS file on a single density disk, single or double ; sided, ten sectors per track. Double sided disks either have logical sectors ; 11+ or logical tracks 80+. ; ; Boot sector code stored in track 0 sector 0 and 1 (Flex disk addresses ; 00/01 and 00/02) ; ; The first two sectors of track 0 must be physical sectors 0 and 1. The ; rest of the disk can be numbered as per whatever base sector number you ; chose. Track 1 is scanned to find the physical sector numbering used. ; Flex uses logical sector numbers counting from 1, and most Flex systems ; number physical sectors counting from 1. ; ; v0.00 04-Feb-2015 JGH: Initial version. ; v0.01 10-Feb-2015 JGH: Added code header. ; v0.02 10-Feb-2015 JGH: Scans sector IDs to find sector numbering. ; v0.03 17-Feb-2015 JGH: D'oh! Got DFS catalog address wrong-endian. ; Optimised GETBYTE and SCANLP. OSWORD EQU $FFF1 CONOUT EQU $F80A WARM EQU $F802 DISKBUF EQU $C300 ; Memory to use to load disk data to ORG $C100 ; Boot code load address ; DFS catalogue entry for sector 0 ; -------------------------------- BOOTLOAD: FCC "BBCFLEX " ; First 8 bytes of disk title FCC "!BOOT " ; $.!BOOT FCB $A4 ; '$'+Locked FCC "FLEX " ; $.FLEX FCB $A4 ; '$'+Locked BOOTNAME: FCC "FLEX" ; "FLEX.SYS" filename FCB 0,0,0,0 ; (Customisable) FCC "SYS" FCC " not found" FCB 13,10,0 ; 6809 code header ; ---------------- BOOTEXEC: JMP >BOOT FCB 0,0,0 FCB $43 ; type=CODE+6809 FCB BOOTCOPY-BOOTEXEC ; offset to 0,"(C)" FCB $00 ; binary version FCC "BBCFLEX LOADER" ; title FCB $00 FCC "0.03 (17 Feb 2015)" BOOTCOPY: FCB $00 FCC "(C)BBC FLEX developers" FCB $00 ; Boot code ; --------- BOOT: LDS #$C080 ; Set up a stack JSR DISKCALL ; Read sector IDs from track 1 BNE BOOT ; If disk error, keep trying ; Reads {trk, head, sec, size}... LDX #DISKBUF+6 ; Point to second loaded sector ID BOOTLP: LDA ,X ; Get physical sector number CMPA SECLO ; Compare with first sector number BCC BOOTLO STA SECLO ; Smaller than SECLO, set SECLO to it BOOTLO: CMPA SECHI ; Compare with last sector number BCS BOOTHI STA SECHI ; Higher than last sector, set SECHI to it BOOTHI: LEAX 4,X ; Point to next sector ID CMPA DISKBUF+2 ; Compare with first loaded ID BNE BOOTLP ; Loop until find repeat of first ID LDA SECHI ; Calculate number of sectors SUBA SECLO ADDA #1 STA SECNUM ; SECLO =first physical sector number ; SECHI =last physical sector number ; SECNUM=number of sectors on track ; Scan through root directory for BBCFLEX.SYS file ; ------------------------------------------------ LDD #$0005 ; Root directory starts at 00/05 DIRLP: JSR DISKLOAD ; Load a sector of the root directory ; Directory sector layout ; 00-01 Link sector ; 02-0F unused ; 10+ 24-byte directory entries ; ; Directory entry layout ; 00-07 Filename, padded with zeros ; 08-0A Extension, padded with zeros ; 0B Attributes, b7=NoWR, b6=NoDel, b5=NoRd, b4=NoCat ; 0C Reserved ; 0D-0E Start disk address (track/sector) ; 0F-10 End disk address (track/sector) ; 11-12 File size ; 13 Sector map indicator ; 14 Reserved ; 15-17 Creation date LDY #DISKBUF+16 ; Point to first directory entry LDX #BOOTNAME ; Point to name to look for NAMELP1: LDB #$FF NAMELP2: ADDB #1 ; Inc. character offset CMPB #11 BEQ NAMEFOUND ; 11 characters matched - found LDA B,X ; Get character from directory ANDA #$DF ; Force to upper case CMPA B,Y ; Compare to file looking for BEQ NAMELP2 ; Loop for all characters ; Filename in directory does not match LEAY 24,Y ; Step to next name CMPY #DISKBUF+256 ; Passed end of sector? BCS NAMELP1 ; No, check next name ; Load next sector and loop again LDD DISKBUF ; Get sector link BNE DIRLP ; More catalog, loop to search it ; Boo! No file found LDB #0 FAILLP: LDA B,X BEQ FAILED JSR [CONOUT] FAILNUL: ADDB #1 CMPB #8 BNE FAILLP LDA #"." JSR [CONOUT] BRA FAILLP FAILED: CMPB #12 BCS FAILNUL ; Skip $00 within filename JMP [WARM] ; Drop back to monitor ; DFS catalogue entry for sector 1 ; -------------------------------- RMB $C200-$ ; Align to second sector start FCC "BOOT" ; Final 4 bytes of disk title FCB 0 ; Cycles FCB $10 ; Offset of end of catalog FCB $20 ; Boot option + disk size high byte FCB $02 ; Disk size low byte FCB BOOTLOAD % 256 ; Catalog info for $.!BOOT FCB BOOTLOAD / 256 ; NB: little-endian FCB BOOTEXEC % 256 FCB BOOTEXEC / 256 FDB $0002 ; Length=&200 FDB $0000 ; Start sector=&0000 FCB BOOTLOAD % 256 ; Catalog info for $.FLEX FCB BOOTLOAD / 256 ; NB: little-endian FCB BOOTEXEC % 256 FCB BOOTEXEC / 256 FDB $0002 ; Length=&200 FDB $0000 ; Start sector=&0000 ; Found system file, load it ; -------------------------- NAMEFOUND: LEAY 13,Y ; Point to disk address entry LDD ,Y ; D=disk address of the file ; Load file starting at disk address in D as a binary file ; -------------------------------------------------------- ; Binary file format, read from sector contents (ie, bytes 4-255) as byte stream ; repeat { (any extra ignored) $02 ...data... } ; (any extra ignored) $16 ; ; Boot loader ends when first transfer address found STD DISKBUF ; Preload buffer with first link LDY #DISKBUF+256 ; Preload Y with empty buffer pointer SCANLP: JSR GETBYTE ; Get a byte from byte stream CMPA #$02 ; Is it - data record header BEQ SCANREC CMPA #$16 ; Is it - transfer address BNE SCANLP ; No, keep going SCANREC: TFR A,B ; Save record marker JSR GETBYTE ; Get transfer address STA DEST+0 JSR GETBYTE STA DEST+1 CMPB #$02 BEQ LOADDATA ; Jump to read data record JMP [DEST] ; Otherwise, jump to transfer address ; Load data record from file ; -------------------------- LOADDATA: JSR GETBYTE ; Get record length TFR A,B ; B=data length BEQ SCANLP ; Length=0, scan for next record LDX DEST LOADLP: JSR GETBYTE ; Get byte STA ,X+ ; Store in memory DECB BNE LOADLP ; Loop until this record done BRA SCANLP ; Scan for next record ; Get byte from file ; ------------------ GETBYTE: CMPY #DISKBUF+256 BCS GETBYTE2 ; Buffer not yet empty, get byte PSHS B,X LDD DISKBUF ; Get link sector JSR DISKLOAD ; Load next sector into buffer PULS B,X LDY #DISKBUF+4 ; Set buffer pointer to first byte GETBYTE2: LDA ,Y+ ; Get byte from buffer and increment RTS ; DISKLOAD - load disk sector D into disk buffer ; ---------------------------------------------- ; On entry, A=track 0-nn, B=sector 1-10 or 1-20 ; DISKLOAD: LDX #0 ; X=side 0 CMPB SECNUM BLS DISKTRACK ; Sector 1-10, side 0 SUBB SECNUM ; Reduce sector to 1-10 LDX #2 ; X=side 1 DISKTRACK: CMPA #80 BCS DISKSECTOR ; Track 0-79, side 0 SUBA #80 ; Reduce track to 0-79 LDX #2 ; X=side 1 DISKSECTOR: SUBB #1 ; Convert sector to 0-9 ADDB SECLO ; Add base sector number ; A=physical track, B=physical sector, X=physical side 0/2 STD DSKTRK ; Store track and sector EXG D,X ; B=drive+side STB DSKDRV ; Store drive+side LDA #$53 STA DSKCMD ; "Read sectors" LDD #$211E ; 1x256-byte sector & default result STD DSKNUM DISKCALL: LDX #DISKCTRL LDA #127 JSR OSWORD LDA DSKRES ; Get result CMPA #$10 BEQ DISKCALL ; Ignore 'Not Ready' for 3.5" drives TSTA ; Set EQ flag from result RTS DISKCTRL: DSKDRV: FCB 0 ; Drive FCB DISKBUF % 256 ; Address low - nb, little-endian! FCB DISKBUF / 256 FDB 0 ; Address high FCB $03 ; Three parameters DSKCMD: FCB $5B ; "Read Sector IDs" DSKTRK: FCB 1 ; Track DSKSEC: FCB 0 ; Sector DSKNUM: FCB $10 ; Up to 16 sector IDs DSKRES: FCB $1E ; Preload result with 'drive not present' SECLO: FCB $FF ; First physical sector number SECHI: FCB $00 ; Last physical sector number SECNUM: FCB $00 ; Number of sectors per track DEST: FDB $0000 ; Data transfer address DSKPTR: FDB $0000 ; Byte read pointer ; Test data ; --------- ; RMB $C300-$ ; Align to third sector start ; RMB 16 ; Padding ; FCC "BBC FLEX " ; RMB $C326-$ ; FCB 9 ; $26=tracks-1 ; FCB 10 ; $27=sectors ; RMB $C400-$ ; RMB $C500-$ ; RMB $C528-$ ; FCC "BBCFLEX SYS" ; RMB $C600-$ ; RMB $C700-$ ; RMB $C800-$ ; RMB $C900-$ ; RMB $CA00-$ ; RMB $CB00-$ ; RMB $CC00-$ ;