;------------------------------------------------------------------------------ ; ; 1541 with 8 bits IDE interface V0.11 ; ; - IDE routines placed in freed area, original routines on original places ; ; ; Remark: the main idea is to use only 8 of the 16 bits of the interface. ; This means that only half of the capacity of the drive is used. But ; IMHO even then an old 20 GB harddisk can store all available ; programs that ever have been programmed for all the Commodores with ; an IEC bus. ; Using only 8 bits also solves the problem what to do with the 512 ; bytes sized sectors. Saving a 256 bytes sized C= sector on a 512 ; bytes one would mean we first have to load it because we HAVE to ; write 512 bytes and thus have to preserve the other C= sector first. ; Unfortunately the parameters of the HD cannot be read with an 8 bits ; interface as half of the information will be discarded. The disk ; parameters have to be provided in another way or the disk has to be ; pre-formatted by a PC. ; ; ; Main idea ; ; The idea is to use LBA mode only; all sectors can be accessed by an unique ; number. A normal 1541 disk with 35 tracks has 683 sectors that can be used. ; Some programs enable one to format and use 40 tracks with 768 sectors. And ; this is HEX $300. Reserving $300 sectors per image will simplify the ; needed calculations significantly. ; ; The very first sector is used for administration. The following 767 ones are ; used to store the directory. I reserved 32 bytes for each image entry. This ; means that this directory can represent 767 * 8 = 6136 images. And 6136 ; images total about 1.2 GB of disk space. Using bigger disks means we have to ; reserve another 300 sectors for every 1.2 GB. The number of neede sectors ; can be calculated. ; ;------------------------------------------------------------------------------ ; Changes so far in original routines: ; 00- skip ROM test ; 02- initialization of the added I/O ; 04- read header of sector ; 05- added label for return of (4) ; 06- read sector ; 07- find sector ; 08- write sector ; 09- write sector, return to original routines ; 10- verify data ; 11- step head ; 12- format track ; 14- changes to avoid multiple reads of the header ; 16- Start up text ; 19- new commands .eq JOBSZP = $00 .eq JOBS = $0000 .eq TRASECzp = $06 ; track/sector for job .eq TRASECab = $0006 .eq DISKIDzp = $12 ; ID of disk in drive 0 .eq DISKIDab = $0012 .eq IMDIIDzp = $13 ; image of most recent header read .eq IMDIIDab = $0013 .eq HDR1IDzp = $16 ; first ID character .eq HDR2ID = $17 ; second ID character .eq HDRTRK = $18 ; track number .eq HDRSEC = $19 ; sector number ; Free 1A 1B .eq WPSW0 = $1C ; write protect drive 0 .eq WPSW1 = $1D ; write protect drive 1 .eq LWPT0 = $1E ; last state wr protec switch dr 0 .eq LWPT1 = $1F ; last state wr protec switch dr 1 .eq DRVST = $20 ; disk drive status (drive 0) 1/0 ; bit 4 = shut down drive motor y/n ; bit 5 = drive motor on/off ; bit 6 = head stepping on/off ; bit 7 = drive ready no/yes .eq DRVST1 = $21 ; disk drive status (drive 1) .eq DRVTRK = $22 ; current track under head (drive 0) .eq VIC20mode = $23 ; VIC-20 / C64 mode .eq STAB0zp = $24 ; work area .eq STAB0ab = $0024 .eq STAB1 = $25 .eq SAVPNT = $2E ; temporary savepoint .eq BUFPNT = $30 ; pointer to currently active buffer .eq J_BUFPNT = $0030 .eq HDRPNT = $32 ; pointer to active values in hdr table .eq GCRPNT = $34 ; pointer to last converted character ; Free 35 .eq BYTCNT = $36 ; byte counter for GCR/binary convers. ; Free 37 .eq BID = $38 ; data block ID character ($07) .eq HBID = $39 ; header block ID character ($08) ; Free 3A .eq IDEid1 = $3B ; Disk ID1 .eq IDEid2 = $3C ; Disk ID2 .eq DRIVE = $3D ; drive .eq CURDRV = $3E ; current drive ($FF is none) .eq JOBN = $3F ; position of last job in queue (0-5) .eq TRACC = $40 ; byte counter for GCR/binary convers. .eq NXTJOB = $41 ; position of next job in queue (0-5) .eq NXTTRK = $42 ; next track to move head to .eq SECCNT = $43 ; sector counter for format routine .eq WORK = $44 ; temporary workspace .eq JOB = $45 ; temporary storage of job code ; Free 46 .eq DBID = $47 ; data block ID code, normal $07 .eq ACLTIM = $48 ; timer for acceleration of head .eq SAVSP = $49 ; temporary save of stackpointer .eq STEPS = $4A ; number of steps to move head to ; desired track .eq TMP = $4B ; temporary storage .eq CSECT = $4C ; last sector read .eq NEXTS = $4D ; next sector to service .eq NXTBF = $4E ; HB of pointer to next buffer of GCR- ; bytes to be changed to binary .eq NXTPNT = $4F ; LB of above ; Free 50 ; binary (0) or GCR (1) .eq FTNUM = $51 ; current track to be formatted .eq BTAB0 = $52 ; temp. area for the four bytes to be .eq BTAB1 = $53 ; converted from or to GCR .eq BTAB2 = $54 .eq BTAB3 = $55 .eq GTAB0 = $56 ; temp. area for the five gcr bytes .eq GTAB1 = $57 ; to be converted from or to binary .eq GTAB2 = $58 .eq GTAB3 = $59 .eq GTAB4 = $5A .eq GTAB5 = $5B .eq GTAB6 = $5C .eq GTAB7 = $5D .eq AS = $5E ; number of steps to ac/decelerate when ; stepping the head ($04) .eq AF = $5F ; ac/deceleration factor ($04) .eq ACLSTP = $60 ; number of steps left to ac/decelerate ; when stepping the head .eq RSTEPS = $61 ; number of steps left to step the head ; when in fast stepping (run) mode .eq NXTSTzp = $62 ; pointer to head stepping routine ; ($FA05) .eq NXTSTab = $0062 .eq MINSTP = $64 ; minimum of steps to go for run mode .eq VNMI = $65 ; pointer to NMI routine .eq J_VNMI = $0065 .eq NMIFLG = $67 ; indicator if NMI in progress .eq AUTOFG = $68 ; flag to en/disable (0/1) the auto ; initialization of a disk (read BAM) .eq SECINC = $69 .eq REVCNT = $6A .eq USRJMP = $6B ; LB user jump .eq BMPNT = $6D ; pointer to start of bitmap ($0400) .eq TEMP0 = $6F .eq J_TEMP0 = $006F .eq TEMP1 = $70 .eq TEMP2 = $71 .eq TEMP3 = $72 .eq TEMP4 = $73 .eq TEMP5 = $74 .eq IP = $75 ; indirect pointer variable .eq J_IP = $0075 .eq LSNADR = $77 .eq TLKADR = $78 .eq LSNACT = $79 ; active listener flag .eq TLKACT = $7A ; active talker flag .eq ATNPND = $7C ; ATN pending .eq ATNMOD = $7D ; 6502 in attention mode .eq LastTrack = $7E ; last used track .eq DRVNMB = $7F ; drive number .eq TRACK = $80 ; current track number .eq SECTOR = $81 ; current sector number .eq CURCHN = $82 ; current channel .eq SA = $83 ; secundair address .eq ORGSA = $84 ; original secundair address .eq DATA = $85 ; temporary databyte .eq R0 = $86 ; temporary result .eq R1 = $87 .eq R2 = $88 .eq J_R2 = $0088 .eq R3 = $89 .eq R4 = $8A .eq RESULT0 = $8B ; result area .eq RESULT1 = $8C .eq RESULT2 = $8D .eq RESULT3 = $8E .eq ACCUM0 = $8F ; accumulator .eq ACCUM1 = $90 .eq ACCUM2 = $91 .eq ACCUM3 = $92 .eq ACCUM4 = $93 .eq DIRBUF = $94 ; directory buffer ($0205) .eq CONT = $98 ; bit counter for serial .eq BUFTABzp = $99 ; $99..A2 pointer to buffer0..4 ; normally: $0300..$0700 .eq BUFTABab = $0099 .eq INPPTR = $A3 ; pointer to inputbuffer $0200 .eq ERRPTR = $A5 ; pointer to errorbuffer $02D5 .eq BUF0CH1zp = $A7 .eq BUF0CH1ab = $00A7 .eq BUF0CH5 = $AB .eq BUF0CH6 = $AC .eq BUF0CH7 = $AD .eq BUF1CH1zp = $AE .eq BUF1CH1ab = $00AE .eq BUF1CH7 = $B4 .eq RECL = $B5 .eq RECH = $BB .eq WRIPNTab = $00C1 ; Write pointer .eq WRIPNT = $C1 ; Write pointer .eq RecLength = $C7 ; $C7..CC Rec length for every buffer .eq SIDSECzp = $CD .eq SIDSECab = $00CD .eq CHNNUM = $D3 .eq CHNNUM1 = $D4 ; $D4..7 Channel numbers .eq CHNNUM2 = $D5 .eq CHNNUM3 = $D6 .eq CHNNUM4 = $D7 .eq DIRSECP = $D8 ; $D8..C pointer directory sectors .eq BUFPTR = $DD ; $DD..E1 bufferpointers .eq DRVNUM = $E2 ; $E2..6 drive numbers .eq COMFLG = $E7 ; $E7..A used for marking comma's .eq DIACFLab = $00EC ; Flag for direct access .eq DIACFLzp = $EC .eq REWRFLab = $00F2 ; read/write flag .eq REWRFLzp = $F2 .eq WRFLAG = $F6 ; Write-flag .eq RDFLAG = $F7 ; Read-flag .eq EOIFLG = $F8 .eq JOBNUM = $F9 ; job number .eq LRUTBLzp = $FA ; least recently used table .eq LRUTBLab = $00FA .eq A_0100 = $0100 .eq A_0101 = $0101 .eq A_0102 = $0102 .eq CMDBUF = $0200 .eq INSTRU = $022A ; instruction number .eq LINTAB = $022B .eq CH4WFL = $023A ; Write-flag channel 4 .eq CH5WFL = $023B ; Write-flag channel 5 ; actually not used .eq A_023C = $023C .eq A_023D = $023D .eq OUTREG = $023E ; output registers .eq ENDPNT = $0244 .eq TYPE = $024A ; active file type .eq STRSIZ = $024B ; length of string .eq TEMPSA = $024C ; temporary secondary address .eq CMD = $024D ; temporary job command .eq BSTSEC = $024E ; best sector to do .eq BUFUSEL = $024F .eq BUFUSEH = $0250 .eq MDIRTY = $0251 ; <> 0 means: BAM changed flag (dr 0) ; $0252 = same for drive 1 .eq ENTFND = $0253 ; directory entry found flag .eq DIRLST = $0254 ; directory listing flag .eq CMDWAT = $0255 ; command waiting flag .eq LINUSE = $0256 ; LINDX use word .eq LBUSED = $0257 ; last buffer used .eq RECSIZ = $0258 ; record size (directory routine) .eq TRKSS = $0259 ; side sector track .eq SECSS = $025A ; side sector sector .eq LSTJOB = $025B ; last job / drive number .eq DSEC = $0260 ; sector of directory entry by buffer .eq DIND = $0266 ; index of directory entry by buffer .eq ERWORD = $026C ; error word .eq ERLED = $026D ; which LED must blink during error .eq PRGDRV = $026E ; last program drive .eq PRGSEC = $026F ; last program sector .eq WLINDX = $0270 ; write LINDX .eq NBTEMP0 = $0272 .eq NBTEMP1 = $0273 .eq CMDSIZ = $0274 ; size of command string .eq CHAR = $0275 ; character under parser .eq LIMIT = $0276 ; PTR limit in comparison .eq F1CNT = $0277 ; file stream 1 count .eq F2CNT = $0278 ; file stream 2 count / number of drives .eq F2PTR = $0279 ; file stream 2 pointer .eq FILTBL = $027A ; table of filename pointers .eq FILTRK = $0280 ; first file link (track) .eq FILSEC = $0285 ; first file link (sector) .eq PATFLG = $028A ; pattern present flag .eq IMAGE = $028B ; file stream image / flag syntax check .eq DRVCNT = $028C ; number of drive searches .eq DRVFLG = $028D ; drive search flag .eq LSTDRV = $028E ; last drive w/o error .eq FOUND = $028F ; found flag in directory searches .eq DIRSEC = $0290 ; directory sector .eq DELSEC = $0291 ; sector of first available entry .eq DELIND = $0292 ; index of first available entry .eq LSTBUF = $0293 ; O if last block .eq INDEX = $0294 ; current index in buffer .eq FILCNT = $0295 ; counter of file entries .eq TYPFLG = $0296 ; match by type of flag .eq MODE = $0297 ; active file mode (R,W) .eq JOBRTN = $0298 ; job return flag .eq EPTR = $0299 ; pointer for recovery .eq TOFF = $029A ; total track offset .eq UBAM = $029B ; last BAM update pointer .eq TBAM = $029D ; track # of BAM image .eq BAMima = $02A1 ; BAM images .eq NameBuffer = $02B1 ; directory output buffer .eq A_02C3 = $02C3 .eq A_02C4 = $02C4 .eq ERRBUF = $02D5 ; error message output buffer .eq WBAM = $02F9 ; 'don't write BAM'-flag. set at start .eq NDBL = $02FA ; # of disk blocks free (lo byte 0/1) .eq A_02FB = $02FB .eq NDBH = $02FC ; # of disk blocks free (hi byte 0/1) .eq A_02FD = $02FD .eq PHASE = $02FE ; current phase of head stepper motor .eq BUF0 = $0300 .eq A_0345 = $0345 .eq BUF2 = $0500 .eq BUF3 = $0600 .eq ErrorCount = $0620 ;+------+-----+-----+---+---+---+----------------+---------------+ ;| Addr | CS0 | CS1 |A2 |A1 |A0 | Read (-IOR) | Write (-IOW) | ;+------+-----+-----+---+---+---+----------------+---------------+-----------+ ;| | 0 | 0 | X | X | X | ILLEGAL | ILLEGAL | | ;+------+-----+-----+---+---+---+----------------+---------------+-----------+ ;| 1000 | 0 | 1 | 0 | 0 | 0 | Data Port | Data Port | <--+ | ;| 1001 | 0 | 1 | 0 | 0 | 1 | Error Register | Precomp | | | ;| 1002 | 0 | 1 | 0 | 1 | 0 | Sector Count | Sector Count | Command | ;| 1003 | 0 | 1 | 0 | 1 | 1 | Sector Number | Sector Number | Block | ;| 1004 | 0 | 1 | 1 | 0 | 0 | Cylinder Low | Cylinder Low | Registers | ;| 1005 | 0 | 1 | 1 | 0 | 1 | Cylinder High | Cylinder High | | | ;| 1006 | 0 | 1 | 1 | 1 | 0 | Drive / Head | Drive / Head | | | ;| 1007 | 0 | 1 | 1 | 1 | 1 | Status | Command | <--+ | ;+------+-----+-----+---+---+---+----------------+---------------+-----------+ ;| 1008 | 1 | 0 | 0 | 0 | 0 | High Impedance | Not Used | Control | ;| ... | 1 | 0 | ... | High Impedance | Not Used | Block | ;| 100D | 1 | 0 | 1 | 0 | 1 | High Impedance | Not Used | Registers | ;| 100E | 1 | 0 | 1 | 1 | 0 | Altern Status | Device Control| | | ;| 100F | 1 | 0 | 1 | 1 | 1 | Drive Address | Not Used | <--+ | ;+------+-----+-----+---+---+---+----------------+---------------+-----------+ ;| | 1 | 1 | X | X | X | High Impedance | Not Used | | ;+------+-----+-----+---+---+---+----------------+---------------+-----------+ .eq IDEcs0 = $1000 ; CS0 .eq IDEdata = IDEcs0 + 0 .eq IDEerror = IDEcs0 + 1 .eq IDEnumSec = IDEcs0 + 2 ; number of sectors .eq IDElba0 = IDEcs0 + 3 ; starts counting from ONE !!! .eq IDElba1 = IDEcs0 + 4 .eq IDElba2 = IDEcs0 + 5 .eq IDElba3 = IDEcs0 + 6 .eq IDEstatus = IDEcs0 + 7 ; when reading .eq IDEcommand = IDEcs0 + 7 ; when writing .eq IDEcs1 = IDEcs0 + 8 ; CS1 .eq IDEcontrol = IDEcs0 + 14 ; Register Designation Function ; 0 ORA or IRB Output or input register B ; 1 ORA or IRA Output or input register A ; 2 DDRB Data direction register B ; 3 DDRA Data direction register A ; 4 T1C-L T1 low-byte latch or T1 low-byte counter ; 5 T1C-H T1 high-byte counter ; 6 T1L-L T1 low-byte latch ; 7 T1L-H T1 high-byte latch ; 8 T2C-L T2 low-byte latch or T2 low-byte counter ; 9 T2C-H T2 high-byte counter ; 10 SR Shift Register ; 11 ACR Auxiliary Control Register ; 12 PCR Peripheral Control Register ; 13 IFR Interrupt Flag Register ; 14 IER Interrupt Enable Register ; 15 ORA or IRA Identical to offset 1 but no handshake .eq PortB1 = $1800 ; bit 0 = DATA in ; bit 1 = DATA out ; bit 2 = CLOCK in ; bit 3 = CLOCK out ; bit 4 = ATN out ; bit 5 = device number bit 0 ; bit 6 = device number bit 1 ; bit 7 = ATN in .eq PortA1 = $1801 ; not used .eq DDRB1 = $1802 .eq DDRA1 = $1803 .eq T1CL1 = $1804 .eq T1CH1 = $1805 .eq T1LL1 = $1806 .eq T1LH1 = $1807 .eq T2CL1 = $1808 .eq T2CH1 = $1809 .eq SR1 = $180A .eq ACR1 = $180B .eq PCR1 = $180C .eq IFR1 = $180D .eq IER1 = $180E .eq IRA1 = $180F .eq PortB2 = $1C00 ; bit 0 = stepping motor bit 0 ; bit 1 = stepping motor bit 1 ; bit 2 = motor ON/OFF ; bit 3 = drive 0 LED ; bit 4 = write protect sense ; bit 5 = density select 0 ; bit 6 = density select 1 ; bit 7 = SYNC detect line .eq PortA2 = $1C01 ; GCR data I/O to diskette .eq DDRB2 = $1C02 .eq DDRA2 = $1C03 .eq T1CL2 = $1C04 .eq T1CH2 = $1C05 .eq T1LL2 = $1C06 .eq T1LH2 = $1C07 .eq T2CL2 = $1C08 .eq T2CH2 = $1C09 .eq SR2 = $1C0A .eq ACR2 = $1C0B .eq PCR2 = $1C0C .eq IFR2 = $1C0D .eq IER2 = $1C0E .eq IRA2 = $1C0F .eq POSTcode = PortA1 ; Constants .eq NewStack = $45 ;============================================================================== .ba $8000 .fb $FF, $4000 .fb $FF, 256 ; &&&20 ;** Turn LED on with checking drive [C100] ; in: - ; out: - ; used: A LedOn sei lda #$F7 and PortB2 ; LED out pha lda DRVNMB ; drive 0? beq L_C110 ; yes -> pla ; no, LED out ora #$00 ; used to be LED drive 1 bne L_C113 L_C110 pla ora #$08 ; LED on L_C113 sta PortB2 cli rts ;** NOT USED ----> ;** Turn LED on [C118] sei lda #$08 ora PortB2 sta PortB2 cli rts ; <---- ;** Clear error flags [C123] ; in: - ; out: - ; used: A ClrErrorFlags lda #$00 sta ERWORD sta ERLED rts ;** Prepare for LED flash after error [C12C] ; in: - ; out: - ; used: A PrepLedFlash sei txa pha lda #$50 sta ERWORD ldx #$00 ; drive number lda A_FECA,X ; in this case value 8 sta ERLED ora PortB2 sta PortB2 ; LED on pla tax cli rts ;** Interprete command from computer [C146] ; in: - ; out: - ; used: A X Y InterprCmnd lda #$00 sta WBAM lda LSTDRV ; last drive number sta DRVNMB jsr OK2Buffer ; OK message in buffer lda ORGSA ; secundair address bpl L_C160 and #$0F cmp #$0F ; 15, command-channel ? beq L_C160 ; yes, -> jmp OPEN_N15 ; OPEN command L_C160 jsr ChkLineLength lda (INPPTR),Y ; get first char ; &&&19 First check for new commands sta CHAR ; mark it L_C168 ldx #$0B L_C16A lda TblCommands,X ; compare commands cmp CHAR ; with char beq L_C17A ; found, -> dex bpl L_C16A lda #$31 ; NOT found jmp OutputErrorMsg ; 31, 'syntax error' L_C17A stx INSTRU cpx #$09 ; commandnumber < 9 ? bcc L_C184 ; yes -> jsr ChkSyntax ; test for R, S or N L_C184 ldx INSTRU ; X = commandnumber lda CmdAddrLB,X sta TEMP0 lda CmdAddrHB,X sta TEMP1 jmp (TEMP0) ; jump to command ;** Prepare error msg after executing command [C194] ; in: - ; out: - ; used: A X Y Out_Err_msg lda #$00 sta WBAM J_C199 lda ERWORD ; flag set? bne OutputErrorMsg ; yes, -> ldy #$00 tya sty TRACK J_C1A3 sty SECTOR sty INPPTR jsr Errmsg2buf ; OK-message jsr ClrErrorFlags J_C1AD lda DRVNMB sta LSTDRV ; mark as last drive tax lda #$00 sta $FF,X jsr EraseInputBuf ; clear inputbuffer jmp Close17_18 ; close internal channel ;** Erase input buffer [C1BD] ; in: - ; out: - ; used: A Y EraseInputBuf ldy #$28 lda #$00 L_C1C1 sta CMDBUF,Y ; fill $0200 - $0228 with 0 dey bpl L_C1C1 rts ;** Output error msg (track and sector 0) [C1C8] OutputErrorMsg ldy #$00 sty TRACK sty SECTOR jmp CreErrorMsg ; Accu contains errornumber ;** Check input line [C1D1] ChkInputLine ldx #$00 stx FILTBL ; pointer to drivenumber lda #":" jsr SearchInputBuf ; Check line until : or end beq B_C1E2 ; not found, -> dey dey sty FILTBL ; points to drivenumber for : B_C1E2 jmp Get_Drv_Num ;** Check for a colon in the line [C1E5] ChkForColon ldy #$00 ldx #$00 lda #":" jmp SearchInputBuf ;** Check the syntax of the line [C1EE] ; ; Settings of IMAGE ($028B) after check: ; ; bit meaning ; --- ------------------------- ; 7 found wildcard (Y=1) \ ; 6 more then one file implied (Y=1) | file #1 ; 5 Drive # specified | ; 4 filename given / ; 3 found wildcard (Y=1) \ ; 2 more then one file implied (Y=1) | file #2 ; 1 Drive # specified | ; 0 filename given / ChkSyntax jsr ChkForColon bne Chk4DrvNum B_C1F3 lda #$34 jmp OutputErrorMsg ; 34, 'Syntax error' Chk4DrvNum dey dey sty FILTBL ; points to drivenumber for : txa ; found ',' for ':' ? bne B_C1F3 ; yes, -> 'Syntax error' ChkWildcard lda #"=" jsr SearchInputBuf txa ; found ',' ? beq L_C20A ; no, -> lda #$40 ; set bit 6 ... L_C20A ora #$21 ; ... and 0 and 5 sta IMAGE inx stx F1CNT stx F2CNT lda PATFLG ; found wildcard? beq L_C228 ; no, -> lda #$80 ora IMAGE sta IMAGE ; set bit 7 lda #$00 sta PATFLG ; reset wildcardflag L_C228 tya ; found '=' ? beq L_C254 ; no, -> sta FILTBL,X lda F1CNT ; number of ',' for '=' sign sta F2PTR lda #$8D ; shift CR jsr SearchInputBuf inx ; increment ',' counter stx F2CNT ; mark number of ',' dex lda PATFLG ; found wildcard? beq L_C245 ; no, -> lda #$08 ; set bit 3 L_C245 cpx F1CNT ; ',' after '=' ? beq L_C24C ; no, -> ora #$04 ; set bit 2 L_C24C ora #$03 ; set bit 0 and 1 eor IMAGE sta IMAGE ; flag syntax test L_C254 lda IMAGE ldx INSTRU and TblSyntax-8,X ; combine with checkbyte bne L_C260 ; faulty syntax, -> rts L_C260 sta ERWORD ; set error flag lda #$30 jmp OutputErrorMsg ; 30, 'Syntax error' ;** Search character in input buffer [C268] SearchInputBuf sta CHAR ; mark char L_C26B cpy CMDSIZ ; end of line? bcs L_C29E ; yes, -> lda (INPPTR),Y ; get char from buffer iny cmp CHAR ; compare with char searched for beq L_C2A0 ; found, -> cmp #"*" beq L_C280 cmp #"?" bne L_C283 L_C280 inc PATFLG ; set wildcardflag L_C283 cmp #"," bne L_C26B ; no, -> tya sta FILTBL+1,X ; mark place of ',' lda PATFLG and #$7F ; wildcard? beq L_C299 ; no, -> lda #$80 sta COMFLG,X ; mark flag sta PATFLG ; mark as wildcard L_C299 inx ; increment ',' counter cpx #$04 ; alread 4 comma's? bcc L_C26B ; no, continue -> L_C29E ldy #$00 L_C2A0 lda CMDSIZ sta FILTBL+1,X ; set flag end-of-line lda PATFLG and #$7F ; wildcard? beq L_C2B1 ; no, -> lda #$80 sta COMFLG,X ; set flag L_C2B1 tya rts ;** Check line length ptr in command [C2B3] ChkLineLength ldy INPPTR ; 0 ? beq L_C2CB dey ; 1 ? beq L_C2CA lda CMDBUF,Y ; get char from inputbuffer cmp #$0D ; 'CR' beq L_C2CB ; yes, end-of-line -> dey lda CMDBUF,Y ; get previous char cmp #$0D ; 'CR' beq L_C2CB ; yes, -> iny L_C2CA iny ; reset to old value L_C2CB sty CMDSIZ cpy #$2A ; check length instruction ldy #$FF bcc CLR_Flg_inp ; < 42 = OK, -> sty INSTRU lda #$32 jmp OutputErrorMsg ; 32, 'syntax error' = line too long ;** Clear flag for command input [C2DC] CLR_Flg_inp ldy #$00 tya ; A := 0 sta INPPTR sta RECSIZ sta TYPE sta TYPFLG sta CHNNUM sta F2PTR sta F1CNT sta F2CNT sta PATFLG sta ERWORD ldx #$05 L_C2FD sta F2PTR,X ; flag line analyse sta DIRSECP-1,X sta BUFPTR-1,X sta DRVNUM-1,X sta COMFLG-1,X ; wildcard flags sta FILTRK-1,X sta FILSEC-1,X dex bne L_C2FD rts ;** Get drive number [C312] GetDrvNum lda F2CNT ; number of comma's sta F1CNT ; mark R_C318 lda #$01 sta F2CNT ; only ONE drive sta F2PTR GetDrvNum2 ldy LSTDRV ldx #$00 L_C325 stx CHNNUM lda FILTBL,X ; place of ':' jsr Search_DrvNum ; get drive number for : ldx CHNNUM sta FILTBL,X ; store exact place tya sta DRVNUM,X ; store drive number inx cpx F2CNT ; done for every drive? bcc L_C325 ; no, -> (in fact never: R_C318) rts ;** Search for drive number [C33C] ;- out: Y contains drivenumber Search_DrvNum tax ; mark R_C33D ldy #$00 lda #":" cmp CMDBUF+1,X beq L_C352 ; yes, -> cmp CMDBUF,X ; this place? bne L_C361 ; no, -> inx L_C34C tya ; A := 0 (R_C33D) L_C34D and #$01 ; filter drive number L_C34F tay txa rts L_C352 lda CMDBUF,X ; get drive number inx inx cmp #"0" beq L_C34D cmp #"1" beq L_C34D bne L_C34C ; use last drive, always -> L_C361 tya ora #$80 ; set bit 7, not sure of drive and #$81 ; clear bit 1..6 bne L_C34F ; always -> ;** Get drive number [C368] Get_Drv_Num lda #$00 sta IMAGE ; clear syntax flag ldy FILTBL ; place in commandline B_C370 lda (INPPTR),Y ; get char jsr ChkDriveNum ; Number is sure? bpl L_C388 ; yes, -> iny ; increment pointer cpy CMDSIZ ; end of line? bcs L_C383 ldy CMDSIZ dey bne B_C370 L_C383 dec IMAGE lda #$00 L_C388 and #$01 sta DRVNMB jmp LedOn ;** Reverse drive number [C38F] ReverseDriveNum lda DRVNMB eor #$01 and #$01 sta DRVNMB rts ;** Check filetype [C398] Chk_Filetype ldy #$00 lda F1CNT ; found '=' sign cmp F2CNT beq L_C3B8 ; no, -> dec F2CNT ; get pointer ldy F2CNT lda FILTBL,Y tay lda (INPPTR),Y ; get char behind '=' ldy #$04 L_C3B0 cmp TblFiletype,Y ; compare with 'S', 'P', 'U', 'R' beq L_C3B8 ; same, -> dey bne L_C3B0 ; if not found, filetype 'DEL' is assumed L_C3B8 tya sta TYPFLG ; note file type (1-4) rts ;** Check drive number [C3BD] ChkDriveNum cmp #"0" beq L_C3C7 cmp #"1" beq L_C3C7 ora #$80 ; set bit 7 = type not sure L_C3C7 and #$81 rts ;** Verify drive number [C3CA] Verify_Drv_Num lda #$00 sta TEMP0 sta DRVFLG pha ldx F2CNT ; number of drives (1541: 1) L_C3D5 pla ora TEMP0 pha ; 0, lda #$01 sta TEMP0 dex ; next drive bmi L_C3EF lda DRVNUM,X bpl L_C3E8 ; >= 0, -> asl TEMP0 ; TEMP0 := 2 asl TEMP0 ; TEMP0 := 4 L_C3E8 lsr bcc L_C3D5 ; bit 0 was 0, -> asl TEMP0 ; TEMP0 := 2 / 8 bne L_C3D5 ; always -> L_C3EF pla tax lda FlagDrvTest-1,X ; get syntax flag pha and #$03 sta DRVCNT pla asl bpl L_C43C lda DRVNUM L_C400 and #$01 sta DRVNMB lda DRVCNT beq L_C434 jsr InitDrive beq L_C420 ; no error, -> jsr ReverseDriveNum ; go to other drive lda #$00 sta DRVCNT jsr InitDrive beq L_C439 ; no error, -> L_C41B lda #$74 jsr OutputErrorMsg ; 74, 'drive not ready' L_C420 jsr ReverseDriveNum jsr InitDrive php jsr ReverseDriveNum plp beq L_C439 lda #$00 sta DRVCNT beq L_C439 ; always -> L_C434 jsr InitDrive bne L_C41B ; if error, -> L_C439 jmp LedOn L_C43C rol ; drivenumber from carry to bit 0 jmp L_C400 ;** Flags for drive check FlagDrvTest .by $00, $80, $41, $01, $01, $01, $01, $81 .by $81, $81, $81, $42, $42, $42, $42 ;** Search for file in directory [C44F] Srch_File_Dir jsr Verify_Drv_Num L_C452 lda #$00 sta DELIND jsr RD_1st_Dir_Blk ; read first directory block bne L_C475 ; found something, -> L_C45C dec DRVCNT ; Drive is known? bpl L_C462 ; no, -> rts L_C462 lda #$01 ; go for other drive sta DRVFLG jsr ReverseDriveNum jsr LedOn jmp L_C452 L_C470 jsr Nxt_File_Dir beq L_C485 ; not found, -> L_C475 jsr Tst_Input_Dir lda FOUND beq L_C47E ; more files, -> rts L_C47E lda ENTFND ; file found? bmi L_C470 ; no, -> bpl L_C475 ; yes, -> L_C485 lda FOUND beq L_C45C ; file found, -> rts ;** Search next file in directory [C48B] SrchNxtFileDir jsr RD_Nxt_Dir_Blk beq L_C4AA ; not found, -> bne L_C4BA ; found, -> L_C492 lda #$01 sta DRVFLG jsr ReverseDriveNum jsr LedOn SrchDirEntry lda #$00 sta DELIND jsr RD_1st_Dir_Blk bne L_C4BA ; if found, -> sta FOUND L_C4AA lda FOUND bne L_C4D7 ; found, -> RTS dec DRVCNT bpl L_C492 ; try other drive, -> rts ;** Search next directory item [C4B5] SrchNxtDirEnt jsr Nxt_File_Dir beq L_C4AA ; not found, -> L_C4BA jsr Tst_Input_Dir ldx ENTFND ; found file? bpl L_C4C9 ; yes, -> lda FOUND beq SrchNxtDirEnt ; no, -> bne L_C4D7 ; no, ready -> RTS L_C4C9 lda TYPFLG ; DEL? beq L_C4D7 ; yes, ready -> RTS lda COMFLG,X ; filetype and #$07 cmp TYPFLG ; like wanted type? bne SrchNxtDirEnt L_C4D7 rts ;** Check input in directory [C4D8] Tst_Input_Dir ldx #$FF stx ENTFND ; flag file found inx stx PATFLG ; erses joker flag jsr Set_Ptr_to_File beq L_C4EC L_C4E6 rts L_C4E7 jsr Ptr_to_Nxt_File bne L_C4E6 ; no file, ready -> L_C4EC lda DRVNMB eor DRVNUM,X lsr bcc L_C4FE ; bit 0 was 0, -> and #$40 ; standard drive? beq L_C4E7 ; yes, -> lda #$02 cmp DRVCNT ; search on both drives beq L_C4E7 ; yes, -> L_C4FE lda FILTBL,X ; check next file name tax jsr Get_Length_Name ; get length filename ldy #$03 jmp L_C51D L_C50A lda CMDBUF,X ; get char from instruction cmp (DIRBUF),Y ; same char in directory? beq L_C51B ; yes, -> cmp #"?" ; wildcard? bne L_C4E7 ; no, next file -> lda (DIRBUF),Y cmp #$A0 ; shift space beq L_C4E7 ; no, next file -> L_C51B inx ; increment pointer iny L_C51D cpx LIMIT ; end of name in instruction? bcs L_C52B ; yes, -> lda CMDBUF,X cmp #"*" ; wildcard? beq L_C535 ; yes, found file, -> bne L_C50A ; no, continue search, always -> L_C52B cpy #$13 ; end of name bcs L_C535 ; yes, -> lda (DIRBUF),Y cmp #$A0 ; shift space bne L_C4E7 ; no, name is longer -> ;** Found file [C535] L_C535 ldx F2PTR ; position of the found file stx ENTFND lda COMFLG,X ; filetype and #$80 sta PATFLG lda INDEX sta BUFPTR,X lda SECTOR ; sectornumber of directory sta DIRSECP,X ; in tabels ldy #$00 lda (DIRBUF),Y ; filetype iny pha and #$40 ; isolate lock-bit ... sta TEMP0 ; ... and save pla and #$DF ; clear bit 5 bmi L_C55C ; file open -> ora #$20 ; set bit 5 L_C55C and #$27 ; clear bit 3, 4 end 7 ora TEMP0 ; restore lock-bit sta TEMP0 lda #$80 and COMFLG,X ; isolate wildcard-flag ora TEMP0 sta COMFLG,X lda DRVNUM,X and #$80 ora DRVNMB sta DRVNUM,X lda (DIRBUF),Y ; first track of file sta FILTRK,X iny lda (DIRBUF),Y ; first sector of file sta FILSEC,X lda RECSIZ ; do we have length of record? bne Set_Ptr_to_File ; yes, -> ;* Get length of record ldy #$15 lda (DIRBUF),Y sta RECSIZ ;** Set pointer to file [C589] Set_Ptr_to_File lda #$FF sta FOUND lda F2CNT sta F2PTR Ptr_to_Nxt_File dec F2PTR ; [C594] bpl L_C59A rts L_C59A ldx F2PTR lda COMFLG,X ; wildcard-flag is set? bmi L_C5A6 ; yes, -> lda FILTRK,X ; track number is set? bne Ptr_to_Nxt_File ; yes, -> L_C5A6 lda #$00 sta FOUND rts ;** Read first directory Block [C5AC] RD_1st_Dir_Blk ldy #$00 sty DELSEC dey sty ENTFND lda DirTrack ; track with directory sta TRACK lda #$01 sta SECTOR sta LSTBUF jsr ReadSeqFile J_C5C4 lda LSTBUF ; last sector? bne L_C5CA ; no, -> rts L_C5CA lda #$07 sta FILCNT ; number of dir entries (-1) lda #$00 jsr GetAthByte ; get byte from buffer sta LSTBUF ; mark as track J_C5D7 jsr SetBufPointer dec FILCNT ; decrement entry counter ldy #$00 lda (DIRBUF),Y ; first byte of directory = filetype bne L_C5FB lda DELSEC bne Nxt_File_Dir jsr GetTrackSector lda SECTOR sta DELSEC lda DIRBUF ; bufferpointer ldx DELIND sta DELIND beq Nxt_File_Dir rts L_C5FB ldx #$01 cpx DELIND ; bufferpointer = 1 ? bne L_C62F ; no, -> beq Nxt_File_Dir ; yes, always -> ;** Read next directory Block [C604] RD_Nxt_Dir_Blk lda DirTrack sta TRACK lda DIRSEC sta SECTOR jsr ReadSeqFile lda INDEX jsr SetBufPointer3 ;** Search for next file in directory [C617] Nxt_File_Dir lda #$FF sta ENTFND ; erase flag "found file" lda FILCNT ; searched all dir-entries? bmi L_C629 ; yes, -> lda #$20 jsr IncBufPointer jmp J_C5D7 L_C629 jsr RdNxtBlock ; set pointer jmp J_C5C4 ; read next block L_C62F lda DIRBUF sta INDEX jsr GetTrackSector lda SECTOR sta DIRSEC ; mark sector rts ;** Test and initialize drive [C63D] InitDrive lda AUTOFG ; auto-initialization (= read BAM) ? bne B_C669 ; no, -> ldx DRVNMB lsr WPSW0,X ; disk changed? bcc B_C669 ; no, then done -> lda #$FF sta JOBRTN ; set errorflag jsr ReadDirTrack ; read directorytrack ldy #$FF ; $FF = error cmp #$02 ; 20 'read error' ? beq B_C65F ; yes, -> cmp #$03 ; 21 'read error' ? beq B_C65F ; yes, -> cmp #$0F ; 74 'drive not ready' ? beq B_C65F ; yes, -> ldy #$00 ; no error B_C65F ldx DRVNMB tya ; error? sta $FF,X ; save errorcode bne B_C669 ; if error, -> jsr LoadBAM ; load BAM B_C669 ldx DRVNMB lda $FF,X ; load errorcode rts ;** Name of file in directory buffer [C66E] ; in: ; A = maximum length ; X points to start of the name in CMDBUF NamFil2DirBuf pha ; Accu contains maximum length jsr Get_Length_Name jsr FilNam2Buf ; write filename in buffer pla sec sbc STRSIZ ; compare length with maximum length tax ; store difference in X beq B_C687 ; = 0, -> bcc B_C687 ; greater then maximum, -> ;** Add $A0 (shifted space) to end of name until maximum lda #$A0 B_C681 sta (DIRBUF),Y iny dex bne B_C681 B_C687 rts ;** Next subroutine is only called at $C672 [C688] FilNam2Buf tya ; buffernumber asl A ; *2 => pointer tay lda BUFTABab,Y sta DIRBUF lda BUFTABab+1,Y sta DIRBUF+1 ldy #$00 B_C697 lda CMDBUF,X ; get character from buffer sta (DIRBUF),Y iny beq B_C6A5 ; buffer full -> inx cpx LIMIT ; check with maximum bcc B_C697 B_C6A5 rts ;** Search for end of name in command [C6A6] Get_length_name lda #$00 sta STRSIZ txa ; save X pha B_C6AD lda CMDBUF,X cmp #"," beq B_C6C8 ; end search -> cmp #"=" beq B_C6C8 ; end search -> inc STRSIZ inx lda #$0F ; 15 = (maximum length of name) - 1 cmp STRSIZ bcc B_C6C8 ; found 16 characters, -> cpx CMDSIZ ; compare with length of input bcc B_C6AD ; smaller, search on -> B_C6C8 stx LIMIT pla tax ; restore X rts ;** Directory entry in buffer [C6CE] GetDirEntry lda SA pha lda CURCHN pha jsr GetDirEntry2 pla sta CURCHN pla sta SA rts ;** Create directory entry in buffer [C6DE] GetDirEntry2 lda #$11 sta SA jsr OpenChan4Read jsr SetBufPointer lda ENTFND ; found entry? bpl B_C6F7 ; yes, -> lda DRVFLG ; drive 1? bne B_C6FC ; yes, -> jsr BlocksFree clc rts B_C6F7 lda DRVFLG beq B_C71B B_C6FC dec DRVFLG bne B_C70E dec DRVFLG jsr ReverseDriveNum jsr BlocksFree sec jmp ReverseDriveNum B_C70E lda #$00 sta NBTEMP1 ; HB number of blocks sta DRVFLG jsr DirHeader sec rts ; IMHO this routine roughly calculates the length of the number of blocks ; of a file and thus where the name, file type, etc. should be placed. ; #### alles fixeren op: xxxxx "NAAM " PRG ? B_C71B ldx #$18 ; length of entry ldy #$1D ; position HB number of blocks lda (DIRBUF),Y sta NBTEMP1 beq B_C728 ldx #$16 B_C728 dey lda (DIRBUF),Y sta NBTEMP0 cpx #$16 beq B_C73C cmp #$0A ; number of blocks? bcc B_C73C ; <10 , -> dex cmp #$64 ; <100 , -> bcc B_C73C dex B_C73C jsr ClrNameBuf lda (DIRBUF),Y ; A = filetype pha asl A ; bit 7 in Carry / write protection? bpl B_C74A ; no, -> lda #"<" sta NameBuffer+1,X B_C74A pla ; filetype and #$0F ; isolate bit 0..3 tay ; and use as index lda TblFiletype+10,Y ; 3rd char of filetype sta NameBuffer,X dex lda TblFiletype+5,Y ; 2nd char of filetype sta NameBuffer,X dex lda TblFiletype,Y ; 1st char of filetype sta NameBuffer,X dex dex bcs B_C76B ; file closed, -> lda #"*" ; file open mark sta NameBuffer+1,X B_C76B lda #$A0 ; fill with shifted space sta NameBuffer,X dex ; Copy the file name ldy #$12 B_C773 lda (DIRBUF),Y sta NameBuffer,X dex dey cpy #$03 bcs B_C773 lda #'"' ; " before file name sta NameBuffer,X ; Replace shifted space with normal space by cleraing bit 7 B_C783 inx cpx #$20 ; ???? bcs B_C793 lda NameBuffer,X cmp #'"' beq B_C793 cmp #$A0 ; shifted space? bne B_C783 ; no, -> B_C793 lda #'"' ; yes, replace sta NameBuffer,X B_C798 inx cpx #$20 bcs B_C7A7 lda #$7F and NameBuffer,X ; erase bit 7 sta NameBuffer,X ; in remaining chars bpl B_C798 ; always -> B_C7A7 jsr SrchNxtDirEnt sec rts ;** Clear the reserved space for the name of the disk [C7AC] ClrNameBuf ldy #$1B ; total length lda #" " B_C7B0 sta NameBuffer-1,Y dey bne B_C7B0 rts ;** Create header with disk name [C7B7] DirHeader jsr GetBufNumBAM jsr ReadBAM jsr ClrNameBuf lda #$FF sta TEMP0 ; ??? where used ??? ; Output the drive number in front of the disk label ldx DRVNMB stx NBTEMP0 lda #$00 sta NBTEMP1 ldx JOBNUM lda BufferAddress,X sta DIRBUF+1 lda LengthBAM ; $90, position of disk name sta DIRBUF ldy #$16 lda (DIRBUF),Y ; read char of disk name cmp #$A0 ; shifted space? bne B_C7ED ; no, -> lda #"1" .by $2C ; dummy BIT opcode B_C7E5 lda (DIRBUF),Y cmp #$A0 ; shifted space? bne B_C7ED ; no, -> lda #" " B_C7ED sta NameBuffer+2,Y dey bpl B_C7E5 lda #$12 ; Reverse ON sta NameBuffer lda #'"' sta NameBuffer+1 ; write " before and ... sta NameBuffer+18 ; ... behind disk name lda #" " sta NameBuffer+19 ; add space rts ;** Create last line = ... BLOCKS FREE [C806] BlocksFree jsr ClrNameBuf ldy #$0B B_C80B lda TxtBlocksFree,Y sta NameBuffer,Y dey bpl B_C80B jmp NumBlocksFree TxtBlocksFree .tx "BLOCKS FREE." ;** S - Scratch command [C823] Scratch jsr Chk_Filetype jsr GetDrvNum2 jsr Verify_Drv_Num lda #$00 sta R0 ; counter erased files jsr SrchDirEntry bmi B_C872 ; not found, -> B_C835 jsr IsFileOpen bcc B_C86D ; yes, -> ldy #$00 lda (DIRBUF),Y ; filetype and #$40 ; LOCK-bit set? bne B_C86D ; yes, -> jsr DelDirEntry ; delete entry ldy #$13 lda (DIRBUF),Y ; tracknumber of first side-sector beq B_C855 ; does not exist, -> sta TRACK iny lda (DIRBUF),Y ; sector number sta SECTOR jsr DelSectorChain ; delete all side-sectors B_C855 ldx ENTFND ; file number lda #$20 and COMFLG,X ; file closed? bne B_C86B ; no, -> lda FILTRK,X sta TRACK lda FILSEC,X sta SECTOR jsr DelSectorChain ; delete file B_C86B inc R0 ; increase number of erased files B_C86D jsr SrchNxtFileDir ; another file? bpl B_C835 ; yes, -> B_C872 lda R0 sta TRACK lda #$01 ldy #$00 jmp J_C1A3 ; message "FILES SCRATCHED" ;** Erase file [C87D] DelSectorChain jsr FreeSector ; free block in BAM jsr ReadSeqFile jsr GetBufNumBAM ; get buffer number in BAM lda BUF0CH1zp,X cmp #$FF ; buffer not used? beq J_C894 ; yes, -> lda WBAM ora #$40 sta WBAM J_C894 lda #$00 jsr SetBufPointer3 ; buffer pointer to zero jsr RdNxtBlock2 ; get track sta TRACK jsr RdNxtBlock2 ; get sector sta SECTOR lda TRACK ; track number bne B_C8AD ; not equal to zero jsr WriteBam ; write BAM jmp CloseChannel ; close channel B_C8AD jsr FreeSector ; free block in BAM jsr RdNxtBlock ; read next block jmp J_C894 ; and continue ;** Erase dir entry [C8B6] DelDirEntry ldy #$00 tya sta (DIRBUF),Y ; set file type to zero jsr WriteSector3 ; write block jmp VerifyExec ; and check ;** D - Backup command (UNUSED) [C8C1] SyntaxError lda #$31 jmp OutputErrorMsg ; 31, 'syntax error' ;** Format disk [C8C6] FormatFloppy lda #$4C ; JMP-command sta BUF3 lda #<(E_FAC7) sta BUF3+1 lda #>(E_FAC7) sta BUF3+2 ; "JMP $FAC7" in $600 ... $602 lda #$03 jsr Par2DiskCtrl2 ; set parameters lda DRVNMB ; drive number ora #$E0 ; command code for formatting sta JOBSZP+3 ; transmit B_C8E0 lda JOBSZP+3 bmi B_C8E0 ; wait until formatting done cmp #$02 bcc B_C8EF ; smaller than two, then ok lda #$03 ldx #$00 jmp PrepErrMsg ; 21, 'read error' B_C8EF rts ;** C - Copy command [C8F0] Copy lda #$E0 sta BUFUSEL jsr ClearTBAM jsr GetBufNumBAM ; get buffer number of BAM lda #$FF sta BUF0CH1zp,X lda #$0F sta LINUSE jsr ChkForColon ; check input line bne B_C90C jmp SyntaxError ; 31, 'syntax error' B_C90C jsr Chk4DrvNum ; check input jsr GetDrvNum2 ; test drive number lda IMAGE ; flag for syntax check and #$55 ; normal copy? bne B_C928 ; yes, -> ldx FILTBL lda CMDBUF,X ; character of the command cmp #'*' ; * ? bne B_C928 ; no, -> B_C923 lda #$30 jmp OutputErrorMsg ; 30, 'syntax error' B_C928 lda IMAGE ; syntax flag and #$D9 bne B_C923 ; 30, 'syntax error' jmp J_C952 ;** Parameters for copying a whole disk. Not used in a 1541 E_C932 lda #$00 sta RECSIZ sta DRVCNT ; number of drives sta FILTRK ; track number in directory sta FILTRK+1 lda DRVNUM+1 and #$01 sta DRVNMB ; drive number ora #$01 sta DELSEC ; sector number lda FILTBL+1 sta FILTBL rts J_C952 jsr Srch_File_Dir ; search for file in directory lda F2CNT ; number of filenames in command cmp #$03 ; smaller than three? bcc B_C9A1 ; yes, -> lda DRVNUM ; first drive number cmp DRVNUM+1 ; second drive number bne B_C9A1 ; not on same drive? lda BUFPTR ; directory block of the 1st file cmp BUFPTR+1 ; same directory block as second file? bne B_C9A1 ; no, -> lda DIRSECP ; directory sector of first file cmp DIRSECP+1 ; same directory sector as second file? bne B_C9A1 ; no, -> jsr IsFilePresent ; is file present? lda #$01 sta F2PTR jsr ReadDirSec jsr CheckREL ; get data type beq B_C982 ; REL file? yes cmp #$02 ; prg-file? bne B_C987 ; no, -> B_C982 lda #$64 jsr OutputErrorMsg ; 64, 'file type mismatch' B_C987 lda #$12 ; 18 sta SA ; secondary address ; not used at all in rest of code ----> lda A_023C sta A_023D lda #$FF sta A_023C ; <---- jsr Prep4Append ; prepare append ldx #$02 jsr CopyFile2 ; copy file jmp Out_Err_Msg ; done B_C9A1 jsr CopyFile1 ; copy file jmp Out_Err_Msg ; done ;** [C9A7] CopyFile1 jsr Chk2Filenames lda DRVNUM ; drive number of first file and #$01 sta DRVNMB ; drive number jsr P_D486 jsr CreDirEntry ; enter file in directory ldx F1CNT ;** [C9B9] CopyFile2 stx F2PTR jsr ReadDirSec lda #$11 ; 17 sta SA jsr OpenChan4Read jsr CheckREL ; get data type bne B_C9CE ; no REL file? jsr P_CA53 B_C9CE lda #$08 sta EOIFLG jmp J_C9D8 B_C9D5 jsr WrData2Buffer ; write byte in buffer J_C9D8 jsr OpenChnGetByt ; and get byte lda #$80 jsr ChkChanBit ; test bit 7 beq B_C9D5 ; not set? jsr CheckREL ; check file type beq B_C9EA ; REL file? jsr WrData2Buffer ; get data byte in buffer B_C9EA ldx F2PTR inx cpx F2CNT bcc CopyFile2 lda #$12 ; 18 sta SA jmp CloseFile ; close channel ;** Open an internal channel for reading a directory block/file [C9FA] ReadDirSec ldx F2PTR lda DRVNUM,X ; drive number and #$01 sta DRVNMB ; save lda DirTrack ; 18, directory track sta TRACK ; save lda DIRSECP,X ; directory sector sta SECTOR jsr ReadSeqFile ; read block ldx F2PTR lda BUFPTR,X ; pointer in block jsr SetBufPointer3 ; set buffer pointer ldx F2PTR lda COMFLG,X ; file type and #$07 ; isolate sta TYPE ; and save lda #$00 sta RECSIZ jsr OpenFile4Read ; get parameters for REL file ldy #$01 jsr CheckREL ; get file type beq B_CA31 ; REL file? iny B_CA31 tya jmp SetBufPointer3 ; set buffer pointer OpenChnGetByt lda #$11 ; 11 sta SA ; open channel and get byte OpenChnGetByt2 jsr P_D39B sta DATA ldx CURCHN ; channel number lda REWRFLzp,X and #$08 ; isolate end marker sta EOIFLG bne B_CA52 ; not set? jsr CheckREL ; REL file? beq B_CA52 ; no, -> lda #$80 jsr SetFlags ; set bit 7 = last record B_CA52 rts P_CA53 jsr GetDrvNum3 ; set drive number jsr SetPar2LstRec lda CHNNUM3 pha lda CHNNUM2 pha lda #$12 ; 18 sta SA jsr OpenChan4Write ; open write channel jsr GetDrvNum3 ; set drive number jsr SetPar2LstRec jsr Record2Buffer lda CHNNUM3 sta R1 lda CHNNUM2 sta R0 lda #$00 sta R2 sta CHNNUM1 sta CHNNUM4 pla sta CHNNUM2 pla sta CHNNUM3 jmp J_E33B ;** R - Rename command [CA88] Rename jsr GetDrvNum2 ; get drive number from command line lda DRVNUM+1 and #$01 sta DRVNUM+1 ; 2nd drive number cmp DRVNUM ; compare with 1st drive number beq B_CA97 ; same? ora #$80 B_CA97 sta DRVNUM jsr Srch_File_Dir ; search for file in directory jsr Chk2Filenames ; does name exist? lda DRVNUM+1 and #$01 sta DRVNMB ; drive number lda DIRSECP+1 sta SECTOR ; sector number jsr ReadSector2 ; read block from directory jsr VerifyExec ; ok? lda BUFPTR+1 ; pointer to directory entry clc adc #$03 ; pointer plus 3 to file name jsr SetBufPointer3 ; set buffer pointer jsr GetBufNumber ; get buffer number tay ldx FILTBL lda #$10 ; 16 characters jsr NamFil2DirBuf ; write name in buffer jsr WriteSector3 ; write block to directory jsr VerifyExec ; ok? jmp Out_Err_Msg ; done, prepare disk status ;** Check if file present [CACC] IsFilePresent lda COMFLG+1 ; file type and #$07 sta TYPE ; save ldx F2CNT B_CAD6 dex cpx F1CNT bcc B_CAE6 lda FILTRK,X ; track number bne B_CAD6 ; not zero? lda #$62 jmp OutputErrorMsg ; 62, 'file not found' B_CAE6 rts ;** Check if two file names are the same [CAE7] Chk2Filenames jsr IsFilePresent ; does file exist with old name? B_CAEA lda FILTRK,X ; track number of new file beq B_CAF4 ; file erased? lda #$63 jmp OutputErrorMsg ; 63, 'file exists' B_CAF4 dex bpl B_CAEA rts ;** M - Memory command [CAF8] Memory lda CMDBUF+1 ; 2nd character from buffer cmp #'-' bne B_CB4B lda CMDBUF+3 sta TEMP0 ; address in $6F/$70 lda CMDBUF+4 sta TEMP1 ldy #$00 lda CMDBUF+2 ; 3rd character from buffer cmp #'R' beq B_CB20 ; to memory read jsr P_F258 ; (RTS) cmp #'W' beq B_CB50 ; to memory write cmp #'E' bne B_CB4B jmp (J_TEMP0) ; memory-execute ;** M-R memory read [CB20] B_CB20 lda (TEMP0),Y ; read byte sta DATA lda CMDSIZ ; length of command line cmp #$06 ; less than 6? bcc B_CB45 ; yes, -> ldx CMDBUF+5 ; number dex beq B_CB45 ; only one byte? txa ; number of bytes clc adc TEMP0 ; plus start address inc TEMP0 sta ENDPNT+5 ; end pointer lda TEMP0 sta ERRPTR ; buffer pointer for error message lda TEMP1 ; set to start address for 'M-R' sta ERRPTR+1 jmp J_D443 ; byte out B_CB45 jsr OpenChan4Read ; open read channel jmp J_D43A ; byte out B_CB4B lda #$31 jmp OutputErrorMsg ; 31, 'syntax error' ;** M-W momory write [CB50] B_CB50 lda CMDBUF+6,Y ; read character sta (TEMP0),Y ; and save iny cpy CMDBUF+5 ; number of characters bcc B_CB50 ; all characters? rts ;** U - User command [CB5C] User ldy CMDBUF+1 ; second char cpy #'0' bne E_CB6C ; no, -> ;** Initial setup USER JUMP vectortable [CB63] SetVectorU0 lda #<(UserVectors) sta USRJMP ; pointer to table of user-addresses lda #>(UserVectors) ; $FFEA sta USRJMP+1 rts E_CB6C jsr P_CB72 jmp Out_Err_Msg ; done, prepare error message P_CB72 dey tya and #$0F ; number asl A ; times 2 tay lda (USRJMP),Y ; as pointer in table sta IP iny ; address at $75/$76 lda (USRJMP),Y sta IP+1 jmp (J_IP) ; execute function ;** Open direct access channel, number [CB84] J_CB84 lda LSTDRV ; last drive number sta DRVNMB ; drive number lda SA ; channel number pha jsr InitDrive ; check drive and initialize pla sta SA ldx CMDSIZ ; length of filename dex bne B_CBA5 ; greater than one? lda #$01 jsr FindRdChanBuf ; layout buffer and channel jmp J_CBF1 ; set flags, done B_CBA0 lda #$70 jmp OutputErrorMsg ; 70, 'no channel' B_CBA5 ldy #$01 jsr GetCmdParms2 ; get buffer number ldx FILSEC ; buffer number cpx #$05 ; bigger than 5? bcs B_CBA0 ; 70, 'no channel' lda #$00 sta TEMP0 sta TEMP1 sec B_CBB8 rol TEMP0 rol TEMP1 dex bpl B_CBB8 lda TEMP0 and BUFUSEL bne B_CBA0 lda TEMP1 and BUFUSEH bne B_CBA0 lda TEMP0 ora BUFUSEL sta BUFUSEL lda TEMP1 ora BUFUSEH sta BUFUSEH lda #$00 jsr FindRdChanBuf ; search channel ldx CURCHN ; channel number lda FILSEC ; buffer number sta BUF0CH1zp,X tax lda DRVNMB ; drive number sta JOBSZP,X sta LSTJOB,X J_CBF1 ldx SA ; secondary address lda LINTAB,X ora #$40 ; set READ and WRITE flags sta LINTAB,X ldy CURCHN ; channel number lda #$FF sta ENDPNT,Y ; end pointer lda #$89 sta REWRFLab,Y ; set READ and WRITE flags lda BUF0CH1ab,Y ; buffer number sta OUTREG,Y asl A ; times 2 tax lda #$01 sta BUFTABzp,X ; buffer pointer to one lda #$0E sta DIACFLab,Y ; flag for direct access jmp Out_Err_Msg ; done ;** B - Block command [CC1B] Block ldy #$00 ldx #$00 lda #'-' jsr SearchInputBuf ; search for minus sign bne B_CC30 ; found? B_CC26 lda #$31 jmp OutputErrorMsg ; 31, 'syntax error' B_CC2B lda #$30 jmp OutputErrorMsg ; 30, 'syntax error' B_CC30 txa bne B_CC2B ; comma, then error ldx #$05 lda CMDBUF,Y ; char from buffer B_CC38 cmp Afrwep,X ; compare with 'AFRWEP' beq B_CC42 ; found? dex bpl B_CC38 ; compare with all characters bmi B_CC26 ; not found, error B_CC42 txa ora #$80 ; command number, set bit 7 sta INSTRU jsr GetCmdParms ; get parameters lda INSTRU asl A ; number times 2 tax ; as index lda CmdAFRWEP+1,X ; address of command hi sta TEMP1 lda CmdAFRWEP,X ; address lo sta TEMP0 jmp (J_TEMP0) ; jump to command AFRWEP .tx "AFRWEP" ;** Addresses of block commands [CC63] CmdAFRWEP .WO L_CD03 ;** B-A .WO E_CCF5 ;** B-F .WO E_CD56 ;** B-R .WO E_CD73 ;** B-W .WO E_CDA3 ;** B-E .WO E_CDBD ;** B-P ;** Get parameters from block commands [CC6F] ; parameters will look like: [:] channel#; unit; track; sector GetCmdParms ldy #$00 ldx #$00 lda #':' jsr SearchInputBuf ; test line to colon bne GetCmdParms2 ; found? ldy #$03 ; no, begin at 4th character GetCmdParms2 lda CMDBUF,Y ; search for separating char cmp #' ' beq B_CC8B cmp #$1D ; cursor right beq B_CC8B cmp #',' bne B_CC92 B_CC8B iny cpy CMDSIZ ; line end? bcc GetCmdParms2 rts B_CC92 jsr P_CCA1 ; preserve next parameter inc F1CNT ; increment parameter counter ldy F2PTR cpx #$04 ; compare with maximum number bcc B_CC8B bcs B_CC2B ; 30, 'syntax error' P_CCA1 lda #$00 sta TEMP0 sta TEMP1 ; erase storage area for decimal numbers sta TEMP3 ldx #$FF B_CCAB lda CMDBUF,Y ; get characters from input buffer cmp #$40 bcs B_CCCA ; no digits? cmp #'0' bcc B_CCCA ; no digits? and #$0F ; convert ASCII digits to hex pha ; and save lda TEMP1 sta TEMP2 ; move digits one further lda TEMP0 sta TEMP1 pla sta TEMP0 ; note read number iny ; increment pointer in input buffer cpy CMDSIZ ; line end reached bcc B_CCAB ; no, -> B_CCCA sty F2PTR ; save pointer clc lda #$00 B_CCD0 inx cpx #$03 bcs B_CCE4 ; convert hex digits to one byte ldy TEMP0,X B_CCD7 dey bmi B_CCD0 adc Decimal,X ; add decimal value bcc B_CCD7 clc inc TEMP3 bne B_CCD7 B_CCE4 pha ldx F1CNT ; counter for paramaters lda TEMP3 sta FILTRK,X ; lo byte pla sta FILSEC,X ; hi byte rts ;** Decimal values Decimal .by 1, 10, 100 ;** B-F block free E_CCF5 jsr P_CDF5 ; get track, sector and drive number jsr FreeSector ; free block jmp Out_Err_Msg ; done, prepare error message ;** B-A block allocate E_CCFE lda #$01 sta WBAM L_CD03 jsr P_CDF5 ; get track, sector and drive number lda SECTOR ; sector pha ; save jsr P_F1FA ; find block in BAM beq B_CD19 ; block allocated? pla ; desired sector cmp SECTOR ; = next free sector? bne B_CD2C ; no, -> jsr AllocSector ; allocate block in BAM jmp Out_Err_Msg ; done B_CD19 pla B_CD1A lda #$00 sta SECTOR ; sector 0 inc TRACK ; next track lda TRACK ; track number cmp A_FED7 ; 36, last track number + 1 bcs B_CD31 ; >=, then 'no block' jsr P_F1FA ; find free block in next track beq B_CD1A ; not found, check next track B_CD2C lda #$65 jsr CreErrorMsg ; 65, 'no block' next free block B_CD31 lda #$65 jsr OutputErrorMsg ; 65, 'no block' no more free blocks ;** [CD36] OpenChanRdSec jsr OpenChannel2 ; open channel, set parameters jmp ReadSector ; read block from disk ;** Get byte from buffer P_CD3C jsr GetBufChanNum ; set pointer to buffer [D12F] lda (BUFTABzp,X) ; get byte rts ;** Read block from disk [CD42] Readsector3 jsr OpenChanRdSec ; open channel, read block lda #$00 jsr SetBufPointer3 ; set buffer pointer to zero jsr P_CD3C ; get a byte from the buffer sta ENDPNT,Y lda #$89 ; set read and write flag sta REWRFLab,Y rts ;** B-R block read E_CD56 jsr Readsector3 ; read block from disk jsr PrepbyteBuf ; prepare byte from buffer jmp Out_Err_Msg ; prepare error message ;** U1 substitute for block read E_CD5F jsr GetCmdParms ; get parameters of the command jsr Readsector3 ; read block from disk lda ENDPNT,Y ; end pointer sta OUTREG,Y ; save as data byte lda #$FF sta ENDPNT,Y ; end pointer to $FF jmp Out_Err_Msg ; done, prepare error message ;** B-W block write E_CD73 jsr OpenChannel2 ; open channel jsr SetBufPointer ; set buffer pointer tay dey cmp #$02 ; buffer pointer lo less than 2? bcs B_CD81 ; no, -> ldy #$01 B_CD81 lda #$00 jsr SetBufPointer3 ; buffer pointer to zero tya jsr Write2Buf ; write byte in buffer txa pha jsr WriteSector ; write block to disk pla tax jsr GetByteBuf ; get byte from buffer jmp Out_Err_Msg ; done, error message ;** U2 substitute for block write E_CD97 jsr GetCmdParms ; get command parameters jsr OpenChannel2 ; open channel jsr WriteSector ; and write block to disk jmp Out_Err_Msg ; done ;** B-E block execute E_CDA3 jsr P_F258 ; (RTS) jsr OpenChanRdSec ; open channel and read block lda #$00 sta TEMP0 ; address low ldx JOBNUM lda BufferAddress,X ; buffer address high sta TEMP1 jsr P_CDBA ; execute routine jmp Out_Err_Msg ; done P_CDBA jmp (J_TEMP0) ; jump to routine ;** B-P block pointer E_CDBD jsr OpenChannel ; open channel, get buffer number lda JOBNUM asl A ; * 2 tax ; as index lda FILSEC+1 ; pointer value sta BUFTABzp,X ; save as buffer pointer jsr GetBufChanNum ; prepare a byte in buffer [D12F] jsr GetByteBuf ; for output jmp Out_Err_Msg ; done ;** Open channel [CDD2] OpenChannel ldx CHNNUM inc CHNNUM lda FILSEC,X ; buffer number tay dey dey cpy #$0C ; buffer number smaller than 14? bcc B_CDE5 ; yes, -> B_CDE0 lda #$70 jmp OutputErrorMsg ; 70, 'no channel' B_CDE5 sta SA ; secondary address jsr OpenChan4Read ; open channel bcs B_CDE0 ; already allocated, 'no channel' jsr GetBufNumber ; buffer number sta JOBNUM ; set rts ;** Check buffer number and open channel OpenChannel2 jsr OpenChannel ; check buffer number and open channel P_CDF5 ldx CHNNUM ; channel number lda FILSEC,X ; buffer address and #$01 sta DRVNMB ; drive number lda FILSEC+2,X sta SECTOR ; sector lda FILSEC+1,X sta TRACK ; track jsr ChkTraSec3 ; track and sector ok? jmp LedOn ; turn LED on ;** Set pointer for REL file SetPtrRelFil jsr P_CE2C ; record number * record length jsr P_CE6E ; divide by 254 lda ACCUM1 ; remainder = pointer in data block sta CHNNUM4 ; data pointer jsr P_CE71 ; divide by 120 = side-sector number inc CHNNUM4 inc CHNNUM4 ; data pointer + 2 (track/sector ; pointer!) lda RESULT0 ; result of division sta CHNNUM2 ; equals side-sector number lda ACCUM1 ; remainder asl A ; times 2 clc adc #$10 ; plus 16 sta CHNNUM3 ; =pointer in side-sector to data block rts ;** record number * record length [CE2C] P_CE2C jsr ClearResult ; erase work storage sta ACCUM3 ldx CURCHN ; channel number lda RECL,X ; record number lo sta ACCUM1 lda RECH,X ; record number hi sta ACCUM2 bne B_CE41 lda ACCUM1 beq B_CE4C ; record number not zero? B_CE41 lda ACCUM1 sec sbc #$01 ; then subtract one sta ACCUM1 bcs B_CE4C dec ACCUM2 B_CE4C lda RecLength,X ; record length sta TEMP0 B_CE50 lsr TEMP0 bcc B_CE57 jsr P_CEED ; record number * record length B_CE57 jsr LshiftAccum ; shift register left lda TEMP0 bne B_CE50 lda CHNNUM1 clc adc RESULT0 sta RESULT0 bcc B_CE6D ; result in $8B/$8C/$8D inc RESULT1 bne B_CE6D inc RESULT2 B_CE6D rts ;** Divide by 254 P_CE6E lda #$FE ; 254 .by $2C ; dummy BIT opcode ;** Divide by 120 P_CE71 lda #$78 sta TEMP0 ; divisor ldx #$03 B_CE77 lda ACCUM0,X pha lda R4,X sta ACCUM0,X pla sta R4,X dex bne B_CE77 jsr ClearResult ; erase work storage B_CE87 ldx #$00 B_CE89 lda ACCUM1,X sta ACCUM0,X inx cpx #$04 bcc B_CE89 lda #$00 sta ACCUM3 bit TEMP0 bmi B_CEA3 asl ACCUM0 php lsr ACCUM0 plp jsr LshiftAccum2 ; shift register 1 left B_CEA3 jsr P_CEED ; add register 0 to register 1 jsr LshiftAccum ; shift register 1 left bit TEMP0 bmi B_CEB0 jsr LshiftAccumX2 ; left-shift register 1 twice B_CEB0 lda ACCUM0 clc adc ACCUM1 sta ACCUM1 bcc B_CEBF inc ACCUM2 bne B_CEBF inc ACCUM3 B_CEBF lda ACCUM3 ora ACCUM2 bne B_CE87 lda ACCUM1 sec sbc TEMP0 ; quotient in $8B/$8C/$8D bcc B_CED8 inc RESULT0 bne B_CED6 inc RESULT1 bne B_CED6 inc RESULT2 B_CED6 sta ACCUM1 ; remainder in $90 B_CED8 rts ;** Erase work storage [CED9] ClearResult lda #$00 sta RESULT0 sta RESULT1 sta RESULT2 rts ;** Left shift 3-byte register twice [CEE2] LshiftAccumX2 jsr LshiftAccum ;** Left shift 3-byte register once [CEE5] LshiftAccum clc LshiftAccum2 rol ACCUM1 rol ACCUM2 rol ACCUM3 rts ;** [CEED] P_CEED clc ldx #$FD B_CEF0 lda RESULT3,X ; register $90/$91/$92 adc ACCUM4,X ; add to register $8B/$8C/$8D sta RESULT3,X inx bne B_CEF0 rts ;** Initialize least recently used table [CEFA] InitLastTable ldx #$00 B_CEFC txa ; store 0,1,2,3,6 .... sta LRUTBLzp,X ; .... $FA/B/C/D/E inx cpx #$04 bne B_CEFC lda #$06 sta LRUTBLzp,X rts ;** [CF09] UpdateTbl ldy #$04 ldx CURCHN ; channel number J_CF0D lda LRUTBLab,Y stx LRUTBLzp,Y cmp CURCHN ; channel number beq B_CF1D dey bmi InitLastTable tax jmp J_CF0D B_CF1D rts ; [CE1E] ChangeBuffer2 jsr UpdateTbl jsr ChkBufferOK bne B_CF6C ; no, -> jsr GetDrvNum3 ; set drive number jsr GetBuffer bmi B_CF76 jsr DeactivateBuf lda TRACK ; track pha lda SECTOR ; sector pha lda #$01 jsr GetAthByte ; get byte 1 from buffer sta SECTOR ; sector lda #$00 jsr GetAthByte ; get byte 0 from buffer sta TRACK ; last sector? beq B_CF66 ; yes, -> jsr CheckREL ; REL file? beq B_CF57 ; yes, -> jsr Chk4Write bne B_CF57 jsr ChangeBuffer jmp J_CF5D B_CF57 jsr ChangeBuffer jsr ReadSector2 J_CF5D pla sta SECTOR ; get sector pla sta TRACK ; and track number jmp J_CF6F B_CF66 pla sta SECTOR ; get back sector pla sta TRACK ; and track number B_CF6C jsr ChangeBuffer J_CF6F jsr GetBufNumber tax jmp VerifyExec ; and verify B_CF76 lda #$70 jmp OutputErrorMsg ; 70, 'no channel' ;** Look for a free buffer [CF7B] Look4FreeBuf jsr UpdateTbl jsr ChkBufferOK bne B_CF8B jsr GetBuffer bmi B_CF76 jsr DeactivateBuf B_CF8B rts ;** Change buffer [CF8C] ChangeBuffer ldx CURCHN ; channel number lda BUF0CH1zp,X eor #$80 ; toggle bit 7 in table sta BUF0CH1zp,X lda BUF1CH1zp,X eor #$80 ; toggle bit 7 in table sta BUF1CH1zp,X rts ;** Write data in buffer [CF9B] WrData2Buffer ldx #$12 ; channel 18 stx SA jsr OpenChan4Write ; open write channel jsr LedOn ; turn LED on jsr CheckREL ; check file type bcc B_CFAF ; no REL file lda #$20 jsr DeleteFlags ; change buffer B_CFAF lda SA ; secondary address cmp #$0F ; 15? beq B_CFD8 ; yes, -> bne B_CFBF ; no, -> P_CFB7 lda ORGSA ; secondary address and #$8F cmp #$0F ; greater than 15? bcs B_CFD8 ; then input buffer B_CFBF jsr CheckREL ; check file type bcs B_CFC9 ; REL file or direct access? lda DATA ; data byte jmp J_D19D ; write in buffer B_CFC9 bne B_CFCE ; direct access file? jmp J_E0AB ; write data byte in REL file B_CFCE lda DATA jsr Write2Buf ; write data byte in buffer ldy CURCHN ; channel number jmp GetByteBuf ; prepare next byte for output B_CFD8 lda #$04 ; channel 4 sta CURCHN ; corresponding input buffer jsr SetBufPointer ; set buffer pointer cmp #$2A ; 40 beq B_CFE8 ; buffer end? lda DATA jsr Write2Buf ; write data byte in buffer B_CFE8 lda EOIFLG ; end flag set? beq B_CFED ; yes, -> rts B_CFED inc CMDWAT ; set command flag rts ;** Write data byte in buffer [CFF1] Write2Buf pha ; save data byte jsr GetBufNumber ; get buffer number bpl J_CFFD ; associated buffer? pla lda #$61 jmp OutputErrorMsg ; 61, 'file not open' J_CFFD asl A ; buffer number times 2 tax ; as index pla ; data byte sta (BUFTABzp,X) ; write in buffer inc BUFTABzp,X ; increment buffer pointer rts ;** I - Initialize command [D005] Initialize jsr ChkInputLine ; find drive number jsr LoadBAM ; load BAM jmp Out_Err_Msg ; prepare disk status ;** Read header of BAM Sector [D00E] ReadDirTrack jsr GetBufNumBAM2 ; drive 0: A=13, 1: A=6 tay ldx BUF0CH1zp,Y cpx #$FF ; buffer available? bne B_D02C ; yes, -> pha jsr GetBuffer tax ; buffer available? bpl B_D024 ; yes, -> lda #$70 jsr CreErrorMsg2 ; 70, 'no channel' B_D024 pla tay txa ora #$80 ; inactive sta BUF0CH1ab,Y B_D02C txa and #$0F sta JOBNUM ldx #$00 stx SECTOR ; sector 0 ldx DirTrack ; 18 stx TRACK ; track 18 jsr Par2DiskCtrl2 ; transmit parameter to disk controller lda #$B0 ; command code 'read block header' jmp J_D58C ; transmit to disk controller ;** Load BAM [D042] LoadBAM jsr ClearTBAM jsr ClsChanOthDrv jsr ReadDirTrack ; read block ldx DRVNMB ; drive number lda #$00 sta MDIRTY,X ; reset flag for "BAM changed' txa asl A tax lda HDR1IDzp sta DISKIDzp,X lda HDR2ID ; save ID sta IMDIIDzp,X jsr DskReadBlock lda JOBNUM ; buffer number asl A tax lda #$02 ; buffer pointer to $200 sta BUFTABzp,X lda (BUFTABzp,X) ; get character from buffer ldx DRVNMB ; drive number sta A_0101,X lda #$00 sta WPSW0,X ; no disk change sta $FF,X ; flag for read error ;** Calculate blocks free [D075] J_D075 jsr SetBufPtrBAM ; buffer address to $6D/$6E ldy #$04 ; begin at position 4 lda #$00 tax B_D07D clc adc (BMPNT),Y ; add number of free blocks per track bcc B_D083 inx ; X as hi-byte B_D083 iny iny ; plus 4 iny iny cpy #$48 ; track 18? beq B_D083 ; then skip cpy #$90 ; last track number? bne B_D07D ; no, -> pha ; lo-byte txa ; hi-byte ldx DRVNMB ; drive number sta NDBH,X ; hi-byte to $2FC pla ; lo-byte sta NDBL,X ; to $2FA rts ;** Read a sector into the buffer [D09B] ReadBlk2Buf jsr Par2DiskCtrl ; parameters to disk controller jsr ReadBlock ; read block jsr VerifyExec ; ok? jsr GetByteFromBuf ; get byte from buffer sta TRACK ; track jsr GetByteFromBuf ; next byte from buffer sta SECTOR ; sector rts J_D0AF jsr ReadBlk2Buf lda TRACK ; track bne B_D0B7 rts B_D0B7 jsr ChangeBuffer2 ; change buffer jsr Par2DiskCtrl ; parameters to disk controller jsr ReadBlock ; read block jmp ChangeBuffer2 ; change buffer ;** Read Block [D0C3] ReadBlock lda #$80 ; code for 'read' bne B_D0C9 ;** Write Block [D0C7] WriteBlock lda #$90 ; code for 'write' B_D0C9 sta CMD ; save jsr GetBufNumber ; get buffer number tax jsr ChkTrackSector ; get track/sector, read/write block txa pha asl A ; buffer pointer times 2 tax lda #$00 sta BUFTABzp,X ; pointer in buffer to zero jsr CheckREL ; get file type cmp #$04 ; REL file or direct access? bcs B_D0E8 ; yes, -> inc RECL,X bne B_D0E8 ; increment block counter inc RECH,X B_D0E8 pla tax rts ;** Open channel for reading [D0EB] OpenChan4Read lda SA ; secondary address cmp #$13 ; 19 bcc B_D0F3 ; smaller? and #$0F B_D0F3 cmp #$0F bne B_D0F9 lda #$10 ; 16 B_D0F9 tax sec lda LINTAB,X ; already in use? bmi B_D106 ; yes, -> and #$0F sta CURCHN tax clc ; flag for ok B_D106 rts ;** Open channel for writing OpenChan4Write lda SA ; secondary address cmp #$13 ; 19 bcc B_D10F ; smaller? and #$0F B_D10F tax lda LINTAB,X ; channel number tay asl A bcc B_D121 bmi B_D123 B_D119 tya and #$0F sta CURCHN tax clc ; flag for ok rts B_D121 bmi B_D119 B_D123 sec ; flag for channel allocated rts ;** Check for file type REL [D125] CheckREL ldx CURCHN lda DIACFLzp,X lsr A and #$07 cmp #$04 ; 'REL'? rts ;** Get buffer and channel numbers [D12F] GetBufChanNum jsr GetBufNumber ; get buffer number asl A tax ldy CURCHN rts ;** Get a byte from buffer [D137] GetByteFromBuf jsr GetBufChanNum ; get buffer and channel number [D12F] lda ENDPNT,Y ; end pointer beq B_D151 lda (BUFTABzp,X) ; get byte from buffer pha lda BUFTABzp,X ; buffer pointer cmp ENDPNT,Y ; equal end pointer? bne B_D14D ; no, -> lda #$FF sta BUFTABzp,X ; buffer pointer to -1 B_D14D pla ; data byte inc BUFTABzp,X ; increment buffer pointer rts ;** Get byte and read next block B_D151 lda (BUFTABzp,X) ; get character from buffer inc BUFTABzp,X ; increment buffer pointer rts ; [D156] RdNxtBlock2 jsr GetByteFromBuf ; get byte from buffer bne B_D191 ; not last character? sta DATA ; save data byte lda ENDPNT,Y ; end pointer beq B_D16A ; yes, -> lda #$80 sta REWRFLab,Y ; READ-flag lda DATA ; data byte rts B_D16A jsr ChangeBuffer2 ; change buffer and read next block lda #$00 jsr SetBufPointer3 ; set buffer pointer to zero jsr GetByteFromBuf ; get first byte from buffer cmp #$00 ; track number zero beq B_D192 ; yes, then last block sta TRACK ; save last track number jsr GetByteFromBuf ; get next byte sta SECTOR ; save as following track jsr ChangeBuffer2 ; change buffer and read next block jsr GetDrvNum3 ; save drive number jsr Par2DiskCtrl ; parameter to disk controller jsr ReadBlock ; transmit read command jsr ChangeBuffer2 ; change buffer and read block lda DATA ; get data byte B_D191 rts ;** Write byte in buffer and block B_D192 jsr GetByteFromBuf ; get next byte from buffer ldy CURCHN sta ENDPNT,Y ; save as end pointer lda DATA ; get data byte back rts J_D19D jsr Write2Buf ; byte in buffer beq Buffer2Disk ; buffer full? rts ;** Write the contents of the buffer to disk [D1A3] Buffer2Disk jsr GetDrvNum3 ; get drive number jsr P_F11E ; find free block in BAM lda #$00 jsr SetBufPointer3 ; buffer pointer to zero lda TRACK jsr Write2Buf ; track number as first byte lda SECTOR jsr Write2Buf ; sector number as second byte jsr WriteBlock ; write block jsr ChangeBuffer2 ; change buffer jsr Par2DiskCtrl ; parameter to disk controller lda #$02 jmp SetBufPointer3 ; buffer pointer to 2 ;** Increment buffer pointer with value in A [D1C6] IncBufPointer sta TEMP0 jsr SetBufPointer ; get buffer pointer clc adc TEMP0 sta BUFTABzp,X ; and increment sta DIRBUF rts ;** Get drive number GetDrvNum3 jsr GetBufNumber ; get drive number tax lda LSTJOB,X and #$01 ; isolate drive number sta DRVNMB ; and save rts ;** Find write channel and buffer FindWrChanBuf sec ; flag for writing bcs B_D1E3 ;** Find read channel and buffer FindRdChanBuf clc ; flag for reading B_D1E3 php ; save sta TEMP0 ; buffer number, AFAIK 0 or 1 jsr CloseChannel ; close channel jsr P_D37F ; allocate free channel sta CURCHN ; channel number ldx SA ; secondary address plp ; read channel? bcc B_D1F5 ; yes, -> ora #$80 ; flag for writing B_D1F5 sta LINTAB,X ; set and #$3F tay lda #$FF ; default value sta BUF0CH1ab,Y sta BUF1CH1ab,Y ; write in associated table sta SIDSECab,Y dec TEMP0 ; decrement buffer number bmi B_D226 ; done already? jsr GetBuffer ; find buffer bpl B_D217 ; found? ;** No channel available [D20F] NoChannel jsr FreeBuffer ; erase flags in table [D25A] lda #$70 jmp OutputErrorMsg ; 70, 'no channel' B_D217 sta BUF0CH1ab,Y ; buffer number in table dec TEMP0 ; buffer number bmi B_D226 ; already done? jsr GetBuffer ; find buffer bmi NoChannel ; not found? sta BUF1CH1ab,Y ; buffer number in table B_D226 rts ;** Close channel [D227] ; in: - ; out: - ; used: A X Y CloseChannel lda SA ; secondary address cmp #$0F ; 15? bne B_D22E ; no, -> rts ; else done already B_D22E ldx SA lda LINTAB,X ; channel number cmp #$FF ; not associated? beq B_D259 ; then done and #$3F sta CURCHN ; channel number lda #$FF sta LINTAB,X ; erase association in table ldx CURCHN lda #$00 sta REWRFLzp,X ; erase READ and WRITE flag jsr FreeBuffer ; [D25A] ldx CURCHN ; channel number lda #$01 ; set bit 0 B_D24D dex bmi B_D253 ; shift to correct position asl A bne B_D24D B_D253 ora LINUSE ; free in allocation register sta LINUSE B_D259 rts ;** Free buffer [D25A] ; in: - ; out: - ; used: A X Y FreeBuffer ldx CURCHN ; channel number lda BUF0CH1zp,X ; buffer number cmp #$FF beq B_D26B ; not associated? pha lda #$FF sta BUF0CH1zp,X ; erase buffer association pla jsr ClrAllocReg ; clr buffer alloc register [D2F3] B_D26B ldx CURCHN ; channel number lda BUF1CH1zp,X cmp #$FF ; associated in second table? beq B_D27C ; no, -> pha lda #$FF sta BUF1CH1zp,X ; erase association pla jsr ClrAllocReg ; clr buffer alloc register [D2F3] B_D27C ldx CURCHN ; channel number lda SIDSECzp,X cmp #$FF ; associated in 3rd table? beq B_D28D ; no, -> pha lda #$FF sta SIDSECzp,X ; erase association pla jsr ClrAllocReg ; clr buffer alloc register [D2F3] B_D28D rts ;** Get a free buffer [D28E] GetBuffer tya pha ldy #$01 jsr FindBuffer bpl B_D2A3 ; found one, -> dey jsr FindBuffer bpl B_D2A3 ; found one, -> jsr StealBuffer tax ; success? bmi B_D2B6 ; no, -> B_D2A3 lda JOBSZP,X ; job is completed? bmi B_D2A3 ; no, wait -> ;* clear jobqueue lda DRVNMB sta JOBSZP,X sta LSTJOB,X txa asl A tay lda #$02 sta BUFTABab,Y B_D2B6 pla tay txa rts ;** Find a free buffer [D2BA] ; in: Y ; out : N flag FindBuffer ldx #$07 B_D2BC lda BUFUSEL,Y and PowersOf2,X ; buffer used? beq B_D2C8 ; no, -> dex ; all buffers checked? bpl B_D2BC ; no, -> rts B_D2C8 lda BUFUSEL,Y eor PowersOf2,X ; toggle bit sta BUFUSEL,Y txa ; buffer number dey bmi B_D2D8 clc adc #$08 B_D2D8 tax ; buffer number B_D2D9 rts ;** Check if a buffer is free [D2DA] ChkBufFree ldx CURCHN lda BUF0CH1zp,X ; buffer free? bmi B_D2E9 ; yes, -> txa clc adc #$07 ; alternative buffer tax lda BUF0CH1zp,X ; free? bpl B_D2D9 ; no, -> B_D2E9 cmp #$FF ; free? beq B_D2D9 ; yes, -> pha lda #$FF sta BUF0CH1zp,X ; mark as free pla ;** Clear allocation register of the freed buffer [D2F3] ; in: A ; out: - ; used: A X Y ClrAllocReg and #$0F tay ; buffer number iny ldx #$10 ; 16 B_D2F9 ror BUFUSEH ror BUFUSEL ; rotate 16-bit allocation register dey bne B_D303 clc ; erase bit for buffer B_D303 dex bpl B_D2F9 rts ;** Close all channels [D307] CloseAllChan lda #$0E ; 14 sta SA ; secondary address B_D30B jsr CloseChannel ; close channel dec SA ; next secondary address bne B_D30B rts ;** Close all channels of other drives [D313] ClsChanOthDrv lda #$0E ; 14 sta SA ; secondary address B_D317 ldx SA lda LINTAB,X ; association table cmp #$FF ; channel associated? beq B_D334 ; no, -> and #$3F sta CURCHN ; channel number jsr GetBufNumber ; get buffer number tax lda LSTJOB,X ; drive number and #$01 ; isolate cmp DRVNMB ; equal to actual drive number bne B_D334 ; no, -> jsr CloseChannel ; close channel B_D334 dec SA ; next channel bpl B_D317 rts ;** Steal the less recently used inactive buffer [D339] StealBuffer lda TEMP0 pha ldy #$00 B_D33E ldx LRUTBLzp,Y lda BUF0CH1zp,X ; buffer is active? bpl B_D348 ; yes, -> cmp #$FF ; buffer is used? bne B_D35E ; no, -> ;* check alternative buffer B_D348 txa clc adc #$07 tax lda BUF0CH1zp,X ; buffer active as well? bpl B_D355 ; yes, -> cmp #$FF ; buffer is used? bne B_D35E ; no, -> B_D355 iny ; next channel cpy #$05 bcc B_D33E ldx #$FF ; no buffer found bne B_D37A ; always -> B_D35E stx TEMP0 and #$3F tax B_D363 lda JOBSZP,X ; used by job now? bmi B_D363 ; wait for completion of job, -> cmp #$02 ; job ended in error? bcc B_D373 ; no, steal buffer -> ldx TEMP0 cpx #$07 ; alternative buffers left to check? bcc B_D348 ; yes, -> bcs B_D355 ; always -> B_D373 ldy TEMP0 lda #$FF sta BUF0CH1ab,Y ; make buffer "unused" B_D37A pla sta TEMP0 txa rts ;** Find channel and allocate P_D37F ldy #$00 lda #$01 ; set bit 0 B_D383 bit LINUSE ; channel free? bne B_D391 ; yes, -> iny asl A ; rotate bit to left bne B_D383 ; all channels checked? lda #$70 jmp OutputErrorMsg ; 70, 'no channel' B_D391 eor #$FF ; rotate bit model and LINUSE ; erase bit sta LINUSE ; allocate channel tya rts ;** Get byte for output P_D39B jsr OpenChan4Read ; open channel for reading jsr LedOn ; turn LED on jsr NxtByteFile ; get byte in output register ldx CURCHN ; channel number lda OUTREG,X ; get byte rts ; get byte in output register [D3AA] NxtByteFile ldx CURCHN ; channel number jsr CheckREL ; check file type bne B_D3B4 ; no REL file? jmp J_E120 ; get byte from REL file B_D3B4 lda SA ; secondary address cmp #$0F ; 15 beq B_D414 ; yes, read error channel lda REWRFLzp,X and #$08 ; end flag set? bne B_D3D3 ; no, -> jsr CheckREL ; check file type cmp #$07 ; direct access file? bne B_D3CE ; no, -> lda #$89 ; set READ and WRITE flag sta REWRFLzp,X jmp J_D3DE B_D3CE lda #$00 sta REWRFLzp,X ; erase READ and WRITE flag rts B_D3D3 lda SA ; secondary address beq B_D409 ; zero, LOAD? jsr CheckREL ; check file type cmp #$04 ; REL file or direct access? bcc B_D400 ; no, -> J_D3DE jsr GetBufChanNum ; get buffer and channel number [D12F] lda BUFTABzp,X ; buffer pointer cmp ENDPNT,Y ; equal end pointer? bne PrepByteBuf ; no, -> lda #$00 sta BUFTABzp,X ; buffer pointer to zero ;** [D3EC] PrepByteBuf inc BUFTABzp,X ; increment buffer pointer ;** [D3EE] GetByteBuf lda (BUFTABzp,X) ; get byte from buffer sta OUTREG,Y ; into output register lda BUFTABzp,X ; buffer pointer cmp ENDPNT,Y ; equal end pointer? bne B_D3FF ; no, -> lda #$81 sta REWRFLab,Y ; set flags B_D3FF rts B_D400 jsr RdNxtBlock2 ; get byte from buffer J_D403 ldx CURCHN ; channel number sta OUTREG,X ; byte in output register rts B_D409 lda DIRLST ; flag for directory? beq B_D400 ; no, -> jsr P_ED67 ; create directory line jmp J_D403 B_D414 jsr SetBufPointer ; set buffer pointer cmp #$D4 ; error buffer? bne B_D433 ; no, -> lda DIRBUF+1 cmp #$02 ; error buffer? bne B_D433 ; no, -> lda #$0D ; CR sta DATA ; in output register jsr ClrErrorFlags ; erase error flags lda #$00 jsr OK2Buffer2 ; create 'ok' message dec ERRPTR ; set buffer pointer back lda #$80 ; set READ flag bne B_D445 ; always -> B_D433 jsr GetByteFromBuf ; get byte from buffer sta DATA ; into output register bne J_D443 J_D43A lda #$D4 jsr SetBufPointer3 ; set buffer pointer in front of error ; pointer lda #$02 sta BUFTABzp+1,X ; hi-address J_D443 lda #$88 ; set READ flag B_D445 sta RDFLAG lda DATA ; data byte sta OUTREG+5 ; into output register rts ;** Read next block [D44D] RdNxtBlock jsr GetBufNumber ; get buffer number asl A ; times 2 tax lda #$00 sta BUFTABzp,X ; buffer pointer to zero lda (BUFTABzp,X) ; get first byte from buffer beq B_D45F ; no block following? dec BUFTABzp,X ; buffer pointer to -1 jmp RdNxtBlock2 ; read next block B_D45F rts ;** Read block ReadSector lda #$80 ; command code for reading bne B_D466 ;** Write block WriteSector lda #$90 ; command code for writing B_D466 ora DRVNMB ; drive number sta CMD ; save code lda JOBNUM jsr Par2DiskCtrl2 ; parameter to disk controller ldx JOBNUM jmp J_D593 ; execute command ;** Allocate buffer and read block [D475] ReadSeqFile lda #$01 ; file type to sequential ReadXxxFile sta TYPE lda #$11 ; 17 sta SA ; secondary address jsr RdBlkAllocBuf ; allocate buffer and read block lda #$02 jmp SetBufPointer3 ; buffer pointer to 2 ;** Allocate new block P_D486 lda #$12 ; 18 sta SA ; secondary address jmp AllocNewSec ; allocate new block ;** Write dir block WrDirSector jsr GetTrackSector ; get track and sector number lda #$01 sta TEMP0 ; a block lda SECINC ; save step width 10 for block pha ; allocation lda #$03 sta SECINC jsr P_F12D ; find free block in BAM pla sta SECINC ; get step width back lda #$00 jsr SetBufPointer3 ; buffer pointer to zero lda TRACK jsr Write2Buf ; track number in buffer lda SECTOR jsr Write2Buf ; sector number in buffer jsr WriteBlock ; write block to disk jsr VerifyExec ; and verify lda #$00 jsr SetBufPointer3 ; buffer pointer to zero B_D4BB jsr Write2Buf ; fill buffer with zeroes bne B_D4BB jsr Write2Buf ; zero as following track lda #$FF jmp Write2Buf ; $FF as number of bytes ;** Set buffer pointer [D4C8] SetBufPointer3 sta TEMP0 ; save pointer jsr GetBufNumber ; get buffer number asl A ; times 2 tax lda BUFTABzp+1,X ; buffer pointer hi sta DIRBUF+1 lda TEMP0 sta BUFTABzp,X ; buffer pointer lo, new value sta DIRBUF rts ;** Close internal channel [D4DA] Close17_18 lda #$11 ; 17 sta SA jsr CloseChannel ; close channel lda #$12 ; 18 sta SA jmp CloseChannel ; close channel ;** Set buffer pointer [D4E8] SetBufPointer jsr GetBufNumber ; get buffer number SetBufPointer2 asl A tax lda BUFTABzp+1,X ; buffer pointer hi sta DIRBUF+1 lda BUFTABzp,X ; buffer pointer lo sta DIRBUF rts ;** Get first byte from buffer [D4F6] GetAthByte sta TEMP2 ; pointer lo jsr GetBufNumber ; get buffer number tax lda BufferAddress,X ; hi-byte buffer address sta TEMP3 ; pointer hi ldy #$00 lda (TEMP2),Y ; get byte from buffer rts ;** Check track and sector numbers ChkTrackSector lda LSTJOB,X ; command code for disk controller and #$01 ; drive number ora CMD ; plus command code P_D50E pha ; save stx JOBNUM ; buffer number txa asl A ; times 2 tax lda TRASECzp+1,X ; sector sta CMD ; save lda TRASECzp,X ; track beq B_D54A ; track 0 not allowed, -> cmp A_FED7 ; 36, highest track number + 1 bcs B_D54A ; track number too big, -> tax pla ; command code pha and #$F0 cmp #$90 ; code for writing? bne B_D57A ; no, -> pla pha lsr A ; drive 1? bcs B_D535 ; yes, -> lda A_0101 bcc B_D538 ; always -> B_D535 lda A_0102 B_D538 beq B_D53F cmp A_FED5 ; 'A', format marker bne B_D572 ; 73, 'cbm dos v2.6 1541' B_D53F txa ; track number jsr MaxSectors ; get maximum sector number cmp CMD ; compare with sector number beq B_D54A ; equal, then error bcs B_D57A ; smaller? B_D54A jsr GetTrackSect2 B_D54D lda #$66 jmp CreErrorMsg ; 66, 'illegal track or sector' ;** Get track and sector numbers [D552] GetTrackSect2 lda JOBNUM ; buffer number asl A ; *2 tax ; as index lda TRASECzp,X sta TRACK ; track lda TRASECzp+1,X sta SECTOR ; sector rts ;** Check for valid track and sector numbers [D55F] ChkTraSec3 lda TRACK ; track beq B_D54D ; zero, then error cmp A_FED7 ; 36, maximum track number + 1 bcs B_D54D ; 66, 'illegal track and sector number' jsr MaxSectors ; get maximum sector number cmp SECTOR ; sector beq B_D54D bcc B_D54D ; error rts B_D572 jsr GetTrackSect2 lda #$73 jmp CreErrorMsg ; 73, 'cbm dos v2.6 1541' B_D57A ldx JOBNUM ; buffer number pla sta CMD ; command code for disk controller sta JOBSZP,X ; in command register sta LSTJOB,X ; and write in table rts ;** Read block DskReadBlock lda #$80 ; code for read bne J_D58C ;** Write block DskWriteBlock lda #$90 ; code for write J_D58C ora DRVNMB ; drive number ldx JOBNUM ; buffer number P_D590 sta CMD J_D593 lda CMD ; command code jsr P_D50E ; check track and sector ;** Verify execution [D598] VerifyExec jsr P_D5A6 ; verify execution bcs VerifyExec ; wait for end pha lda #$00 sta JOBRTN ; erase error flag pla rts P_D5A6 lda JOBSZP,X ; command code (bit 7) in register? bmi B_D5C4 ; yes, -> cmp #$02 bcc B_D5C2 ; error-free execution cmp #$08 ; 8 beq B_D5BA ; write protect cmp #$0B ; 11 beq B_D5BA ; ID mismatch cmp #$0F ; 15, drive not ready nop nop ; &&&20 B_D5BA bit JOBRTN bmi B_D5C2 jmp J_D63F ; create error message B_D5C2 clc ; execution ended rts B_D5C4 sec ; execution not yet ended rts .fb $FF, 111 ; &&&20 B_D635 pla ; command code cmp #$90 ; for writing? bne J_D63F ; no, -> ora DRVNMB ; drive number sta LSTJOB,X ; command code in table J_D63F lda JOBSZP,X ; return message jsr PrepErrMsg ; set error message B_D644 pla bit JOBRTN bmi J_D66D pha lda #$C0 ; command code for head positioning ora DRVNMB ; drive number sta JOBSZP,X ; in command register B_D651 lda JOBSZP,X bmi B_D651 ; wait for execution jsr RetryExec ; attempt command execution again cmp #$02 ; return message bcs B_D635 ; incorrect? B_D65C pla cmp #$90 ; command code for writing bne J_D66D ; no, -> ora DRVNMB ; drive number sta LSTJOB,X ; in table jsr RetryExec ; attempt execution again cmp #$02 ; return message bcs J_D63F ; error? J_D66D pla sta DRVNMB ; get drive number back pla tay lda JOBSZP,X ; error code clc ; end-of-execution flag rts .fb $FF, 48 ; &&&20 ;** Attempt command execution multiple times [D6A6] RetryExec lda REVCNT ; maximum number of repetitions and #$3F tay B_D6AB lda ERLED ; bit for LED eor PortB2 sta PortB2 lda LSTJOB,X ; command sta JOBSZP,X ; transmit to disk controller B_D6B9 lda JOBSZP,X ; and return message bmi B_D6B9 ; wait cmp #$02 ; ok? bcc B_D6C4 ; yes, -> dey ; decrement counter bne B_D6AB ; attempt again B_D6C4 pha lda ERLED ora PortB2 ; LED off sta PortB2 pla rts ;** Transmit param to disk controller Par2DiskCtrl jsr GetBufNumber ; get buffer number Par2DiskCtrl2 asl A tay lda TRACK ; track number sta TRASECab,Y ; transmit lda SECTOR ; sector number sta TRASECab+1,Y ; transmit lda DRVNMB ; drive number asl A ; times 2 tax rts ;** Enter file in dir [D6E4] CreDirEntry lda SA ; secondary address pha lda CURCHN ; channel number pha lda SECTOR ; sector number pha lda TRACK ; track number pha ; save lda #$11 sta SA ; secondary address 17 jsr GetTrackSector ; get track and sector number lda TYPE ; file type pha ; save lda DRVNUM ; drive number and #$01 sta DRVNMB ; set ldx JOBNUM ; buffer number eor LSTJOB,X lsr A bcc B_D715 ; equal drive number? ldx #$01 stx DELIND ; pointer in directory jsr Rd_1st_Dir_Blk ; load dir and find first entry beq B_D730 ; if not found -> new sector bne J_D73D ; always -> B_D715 lda DELSEC ; sector number in directory beq B_D726 ; equal zero cmp SECTOR ; equal sector number? beq J_D73D ; yes, -> sta SECTOR ; save sector number jsr ReadSector ; read block jmp J_D73D B_D726 lda #$01 sta DELIND ; pointer to one jsr Nxt_File_Dir ; find next entry in directory bne J_D73D ; found? ; write entry B_D730 jsr WrDirSector ; write directory block lda SECTOR ; sector number sta DELSEC lda #$02 sta DELIND ; pointer to 2 J_D73D lda DELIND jsr SetBufPointer3 ; set buffer pointer pla sta TYPE ; file type cmp #$04 ; REL file? bne B_D74D ; no, -> ora #$80 ; set bit 7 B_D74D jsr Write2Buf ; and write in buffer pla sta FILTRK ; following track jsr Write2Buf ; in buffer pla sta FILSEC ; following sector jsr Write2Buf ; in buffer jsr GetBufNumber ; get buffer number tay lda FILTBL tax lda #$10 ; 16, length of filename jsr NamFil2DirBuf ; write filename in buffer ldy #$10 lda #$00 B_D76F sta (DIRBUF),Y ; fill with zeroes at position 16 iny cpy #$1B ; position 27 already? bcc B_D76F ; no, -> lda TYPE ; file type cmp #$04 ; REL file? bne B_D790 ; no, -> ldy #$10 lda TRKSS ; track sta (DIRBUF),Y iny lda SECSS ; and sector sta (DIRBUF),Y ; the side-sectors in directory entry iny lda RECSIZ ; record length sta (DIRBUF),Y ; in directory B_D790 jsr WriteSector ; write block pla sta CURCHN ; channel number tax pla sta SA ; secondary address lda DELSEC sta DIRSECP sta DSEC,X lda DELIND sta BUFPTR sta DIND,X lda TYPE ; file type sta COMFLG lda DRVNMB ; drive number sta DRVNUM rts ;** OPEN command, secondary addres <> 15 OPEN_N15 lda SA ; secondary address sta TEMPSA jsr ChkLineLength ; get line length, erase flags stx INSTRU ldx CMDBUF ; first character from buffer lda TEMPSA ; secondary address bne B_D7F3 ; not equal 0 (LOAD)? cpx #'*' bne B_D7F3 lda LastTrack ; last track number beq B_D81C sta TRACK ; track number lda PRGDRV ; last drive number sta DRVNMB ; drive number sta DRVNUM lda #$02 sta COMFLG ; set data type to program lda PRGSEC ; last sector number sta SECTOR ; sector jsr LedOn ; turn LED on jsr RdBlkAllocBuf ; allocate buffer, read block lda #$04 ; file type PRG (*2) ora DRVNMB ; drive number J_D7EB ldx CURCHN ; channel number sta DIACFLab,Y ; set flag jmp Out_Err_Msg ; done B_D7F3 cpx #'$' ; directory bne B_D815 ; no, -> lda TEMPSA ; secondary address bne B_D7FF ; not equal to zero? jmp J_DA55 ; OPEN $ ;** Treat directory as SEQ file B_D7FF jsr ChkInputLine ; analyze line to end lda DirTrack ; 18, directory track sta TRACK ; track lda #$00 sta SECTOR ; sector 0 jsr RdBlkAllocBuf ; allocate buffer, read block lda DRVNMB ; drive number ora #$02 ; file type SEQ (*2) jmp J_D7EB ; continue as above B_D815 cpx #"#" bne B_D82B jmp J_CB84 ; open direct access file B_D81C lda #$02 sta TYPFLG ; file type program lda #$00 sta DRVNMB ; drive 0 sta LSTDRV jsr LoadBAM ; load BAM B_D82B jsr ChkForColon ; analyze line, colon found? bne B_D834 ; no, -> ldx #$00 beq B_D840 ; always -> B_D834 txa ; comma found? beq B_D83C ; no, -> lda #$30 jmp OutputErrorMsg ; 30, 'syntax error' B_D83C dey beq B_D840 dey B_D840 sty FILTBL ; pointer to drive number lda #$8D ; shift CR jsr SearchInputBuf ; analyze line to end inx stx F2CNT ; comma counter jsr GetDrvNum ; get drive number jsr Verify_Drv_Num ; check drive number jsr SrchDirEntry ; find file entry in directory ldx #$00 ; default values stx RECSIZ ; record length stx MODE stx TYPE ; file type inx cpx F1CNT ; comma before equal sign? bcs B_D876 ; no, -> jsr ChkTypeMode ; get file type and control mode inx cpx F1CNT ; additional comma? bcs B_D876 ; no, -> cpy #$04 ; REL file? beq B_D8B1 ; yes, -> jsr ChkTypeMode ; get file type and control method B_D876 ldx TEMPSA stx SA ; secondary address cpx #$02 ; greater than 2? bcs B_D891 ; yes, -> stx MODE ; 0 or 1 (LOAD or SAVE) lda #$40 sta WBAM lda TYPE ; DEL type? bne B_D8A7 ; no, -> lda #$02 ; PRG sta TYPE ; as file type B_D891 lda TYPE bne B_D8A7 lda COMFLG and #$07 ; get file type and command line sta TYPE lda FILTRK ; track number bne B_D8A7 ; not equal zero? lda #$01 sta TYPE ; file type sequential B_D8A7 lda MODE ; control method cmp #$01 ; Write? beq B_D8C6 ; yes, -> jmp J_D940 B_D8B1 ldy FILTBL,X ; pointer behind second comma lda CMDBUF,Y ; get value sta RECSIZ ; record length lda FILTRK ; track number, used? bne B_D876 ; yes, -> lda #$01 ; 'W' sta MODE ; as second method bne B_D876 ; always -> B_D8C6 lda COMFLG ; file type and #$80 ; isolate wildcard flag tax ; wildcard in name? bne B_D8E1 ; yes, -> lda #$20 bit COMFLG ; was file closed? beq B_D8D9 ; yes, -> jsr DelDirEntry ; byte 0 in buffer and write block jmp OpenFile4Write B_D8D9 lda FILTRK ; track number of the first block bne B_D8E1 ; already existing jmp OpenFile4Write B_D8E1 lda CMDBUF ; first character from input buffer cmp #'@' ; replace? beq B_D8F5 ; yes, -> txa ; file exists? bne B_D8F0 ; no, -> lda #$63 jmp OutputErrorMsg ; 63, 'file exists' B_D8F0 lda #$33 jmp OutputErrorMsg ; 33, 'syntax error' ;** Open a file with overwriting B_D8F5 lda COMFLG ; file type and #$07 ; isolate cmp TYPE bne B_D965 ; file type different? cmp #$04 ; REL file? beq B_D965 ; 64, 'file type mismatch' jsr AllocNewSec lda CURCHN sta WLINDX ; save channel number lda #$11 sta SA jsr OpenChan4Read ; open read channel lda INDEX jsr SetBufPointer3 ; set buffer pointer for directory ldy #$00 lda (DIRBUF),Y ; file type ora #$20 ; set bit 5, open file sta (DIRBUF),Y ldy #$1A lda TRACK ; track sta (DIRBUF),Y iny lda SECTOR ; and sector sta (DIRBUF),Y ; for open with at-sign ldx WLINDX ; channel number lda DIRSECP sta DSEC,X ; pointer to directory block lda BUFPTR sta DIND,X jsr GetTrackSector ; get track and sector number jsr WriteSector ; write block jmp J_D9EF ; prepare track, sector, and drive ; number J_D940 lda FILTRK ; file erased? bne B_D94A ; no, -> lda #$62 jmp OutputErrorMsg ; 62, 'file not found' B_D94A lda MODE ; control mode cmp #$03 ; Merge? beq B_D95C ; yes, then no test of unclosed file lda #$20 bit COMFLG ; file closed? beq B_D95C ; yes, ok -> lda #$60 jmp OutputErrorMsg B_D95C lda COMFLG and #$07 ; isolate file type cmp TYPE ; same file type? beq B_D96A ; yes, -> B_D965 lda #$64 jmp OutputErrorMsg ; 64, 'file type mismatch' B_D96A ldy #$00 sty F2PTR ldx MODE ; control mode cpx #$02 ; Append? bne B_D990 ; no, -> cmp #$04 ; REL file? beq B_D965 ; yes, -> lda (DIRBUF),Y and #$4F ; mark file as open sta (DIRBUF),Y lda SA pha lda #$11 ; READ sta SA ; channel 17 jsr GetTrackSector ; get track and sector number jsr WriteSector ; write block pla sta SA ; get channel number back B_D990 jsr OpenFile4Read lda MODE ; control mode cmp #$02 bne J_D9EF jsr Prep4Append jmp Out_Err_Msg ; done ;** Open file for reading [D9A0] OpenFile4Read ldy #$13 lda (DIRBUF),Y ; track sta TRKSS iny lda (DIRBUF),Y sta SECSS iny lda (DIRBUF),Y ; record length ldx RECSIZ ; last record len sta RECSIZ txa ; length 0 ? beq B_D9C3 ; yes, -> cmp RECSIZ ; same length? beq B_D9C3 ; yes, -> lda #$50 jsr OutputErrorMsg ; 50, 'record not present' B_D9C3 ldx F2PTR lda FILTRK,X ; track sta TRACK lda FILSEC,X ; sector sta SECTOR jsr RdBlkAllocBuf ldy CURCHN ldx F2PTR lda DIRSECP,X sta DSEC,Y lda BUFPTR,X sta DIND,Y rts ;** Open file for writing [D9E3] OpenFile4Write lda DRVNUM ; drive number and #$01 sta DRVNMB jsr AllocNewSec jsr CreDirEntry J_D9EF lda SA ; channel number cmp #$02 bcs B_DA06 jsr GetSector2 lda TRACK sta LastTrack lda DRVNMB sta PRGDRV lda SECTOR sta PRGSEC B_DA06 jmp J_C199 ;** Check file type and control mode [DA09] ; in: X = place behind comma ChkTypeMode ldy FILTBL,X ; pointer in command line lda CMDBUF,Y ; get characters from line ldy #$04 B_DA11 dey bmi B_DA1C cmp A_FEB2,Y ; control modes 'R', 'W', 'A', 'M' bne B_DA11 sty MODE ; save B_DA1C ldy #$05 B_DA1E dey bmi B_DA29 cmp A_FEB6,Y ; file types 'D','S','P','U','L' bne B_DA1E sty TYPE ; save B_DA29 rts ;** preparation for append [DA2A] Prep4Append jsr OpenChnGetByt2 ; open channel to read, get byte lda #$80 jsr ChkChanBit ; last byte? beq Prep4Append ; no, -> jsr GetNxtSector ; get track and sector number ldx SECTOR ; sector number inx txa bne B_DA42 ; not $FF? jsr Buffer2Disk ; close buffer, write block lda #$02 B_DA42 jsr SetBufPointer3 ; buffer pointer to 2 ldx CURCHN ; channel number lda #$01 sta REWRFLzp,X ; set flag for WRITE lda #$80 ora CURCHN ldx SA sta LINTAB,X ; channel number in table rts ;** Load directory [DA55] J_DA55 lda #$0C ; command number 12 sta INSTRU lda #$00 ; default only drive 0 ldx CMDSIZ dex ; only "$" ? beq B_DA6D ; yes, -> dex bne B_DA86 lda CMDBUF+1 ; second character jsr ChkDriveNum ; check drive number bmi B_DA86 ; not 0 or 1? B_DA6D sta DRVNUM ; save drivenumber inc F1CNT ; number of ',' for '=' sign inc F2CNT ; total number of ',' inc FILTBL lda #$80 sta COMFLG ; set wildcard flag lda #'*' sta CMDBUF ; as file name in command buffer sta CMDBUF+1 bne B_DA9E ; always -> B_DA86 jsr ChkForColon ; test input line for ":" bne B_DA90 ; not found, -> jsr CLR_Flg_inp ; erase flags ldy #$03 B_DA90 dey dey sty FILTBL ; pointer to drive number in command jsr ChkWildcard ; analyze line jsr Chk_Filetype ; ascertain file type jsr GetDrvNum2 ; get drive number B_DA9E jsr Verify_Drv_Num ; initialize drive if necessary jsr DirHeader ; prepare disk title jsr SrchDirEntry ; load directory jsr P_EC9E ; create and prepare directory jsr GetByteFromBuf ; get byte from buffer ldx CURCHN ; channel number sta OUTREG,X ; byte in output register lda DRVNMB ; drive number sta LSTDRV ; save as last drive number ora #$04 sta DIACFLzp,X ; PRG-flag lda #$00 sta INPPTR ; set pointer back in input buffer rts ;** Close routine [DAC0] Close lda #$00 sta WBAM lda SA ; secondary address bne B_DAD4 ; not zero? lda #$00 ; secondary address 0, LOAD sta DIRLST jsr CloseChannel ; close channel B_DAD1 jmp Close17_18 ; close internal channels 17 & 18 B_DAD4 cmp #$0F ; 15 beq B_DAEC ; yes, close all channels jsr CloseFile ; close file lda SA ; secondary address cmp #$02 bcc B_DAD1 ; smaller than 2? lda ERWORD bne B_DAE9 jmp Out_Err_Msg ; termination B_DAE9 jmp J_C1AD ;** Close file B_DAEC lda #$0E ; 14 sta SA ; secondary address B_DAF0 jsr CloseFile ; close file dec SA ; next secondary address bpl B_DAF0 lda ERWORD bne B_DAFF jmp Out_Err_Msg ; termination B_DAFF jmp J_C1AD ;** Close file [DB02] CloseFile ldx SA ; secondary address lda LINTAB,X ; get channel number cmp #$FF ; no channel associated? bne B_DB0C rts ; no, then none B_DB0C and #$0F ; isolate channel number sta CURCHN jsr CheckREL ; check data type cmp #$07 ; direct access? beq B_DB26 ; yes, -> cmp #$04 ; REL file? beq B_DB2C ; yes, -> jsr OpenChan4Write ; channel for writing open bcs B_DB29 ; no file for writing? jsr WriteLastSec ; write last block jsr WriteDirEntry ; write entry in directory and block B_DB26 jsr WriteBam ; write BAM B_DB29 jmp CloseChannel ; close channel B_DB2C jsr GetBufWrSec ; get buffer number, write block jsr ChangeBuffer2 ; change buffer jsr SetPar2LstRec ; get last side-sector ldx CHNNUM2 ; side-sector number stx TEMP4 inc TEMP4 lda #$00 sta TEMP1 sta TEMP2 lda CHNNUM3 sec sbc #$0E ; minus 14 for pointer sta TEMP3 jsr CalcSecPtrREL ; calculate block number of file ldx CURCHN ; channel number lda TEMP1 sta RECL,X ; record number lo lda TEMP2 sta RECH,X ; record number hi lda #$40 jsr ChkChanBit ; bit 6 set? beq B_DB5F ; no, -> jsr WriteDirEntry ; enter in directory B_DB5F jmp CloseChannel ; close channel ;** Write last block [DB62] WriteLastSec ldx CURCHN ; channel number lda RECL,X ; record number lo ora RECH,X ; record number hi bne B_DB76 ; not zero? jsr SetBufPointer ; set buffer pointer cmp #$02 bne B_DB76 ; not 2 lda #$0D ; CR jsr Write2Buf ; in buffer B_DB76 jsr SetBufPointer ; set buffer pointer cmp #$02 ; now equal to 2? bne B_DB8C ; no, -> jsr ChangeBuffer2 ; change buffer ldx CURCHN ; channel number lda RECL,X ; record number lo bne B_DB88 dec RECH,X ; decrement block number hi B_DB88 dec RECL,X ; and block number lo lda #$00 B_DB8C sec sbc #$01 ; set pointer pha lda #$00 jsr SetBufPointer3 ; buffer pointer to zero jsr Write2Buf ; write zero in buffer pla ; second byte = pointer to end jsr Write2Buf ; write in buffer jsr WriteBlock ; write block to disk jsr VerifyExec ; and verify jmp ChangeBuffer2 ; change buffer ;** Directory entry [DBA5] WriteDirEntry ldx CURCHN ; channel number stx WLINDX ; save lda SA ; secondary address pha ; save lda DSEC,X ; sector number in directory sta SECTOR ; set lda DIND,X ; pointer in directory sta INDEX lda DIACFLzp,X and #$01 sta DRVNMB ; drive number lda DirTrack ; 18, directory track sta TRACK ; set jsr GetBufNumber ; increment buffer number pha sta JOBNUM jsr ReadSector ; read directory block ldy #$00 lda BufferAddress,X ; buffer address sta R1 lda INDEX ; buffer pointer sta R0 lda (R0),Y ; file type and #$20 ; file closed? beq B_DC21 ; yes, -> jsr CheckREL ; check file type cmp #$04 ; REL file? beq J_DC29 ; yes, -> lda (R0),Y and #$8F ; erase bits 4,5, and 6 sta (R0),Y ; in file type iny lda (R0),Y ; track number sta TRACK sty TEMP2 ldy #$1B lda (R0),Y ; sector number of the file for pha ; overwriting dey lda (R0),Y ; track number for overwriting bne B_DC06 ; set? sta TRACK ; set track number pla sta SECTOR ; sector number lda #$67 jsr CreErrorMsg ; 67, 'illegal track or sector' B_DC06 pha lda #$00 sta (R0),Y ; erase track number iny sta (R0),Y ; and sector number of the ; substitute file pla ldy TEMP2 sta (R0),Y iny ; set track & sector number of the new ; file lda (R0),Y sta SECTOR pla sta (R0),Y jsr DelSectorChain ; erase all files jmp J_DC29 B_DC21 lda (R0),Y ; get file type and #$0F ; isolate bits 0-3 ora #$80 ; set bit 7 for closed file sta (R0),Y J_DC29 ldx WLINDX ; channel number ldy #$1C lda RECL,X ; block number lo sta (R0),Y ; in directory entry iny lda RECH,X ; and block number hi sta (R0),Y ; write pla ; buffer number tax lda #$90 ; code for 'writing' ora DRVNMB jsr P_D590 ; write block pla sta SA ; secondary address jmp OpenChan4Write ; open channel for writing ;** Read block, allocate buffer [DC46] RdBlkAllocBuf lda #$01 jsr FindRdChanBuf ; find channel and buffer for read jsr ResetPointer ; set pointer lda TYPE ; file type pha ; save asl A ora DRVNMB ; drive number sta DIACFLzp,X jsr ReadBlk2Buf ; read block in buffer ldx CURCHN ; channel number lda TRACK ; track bne B_DC65 ; following track? lda SECTOR ; sector sta ENDPNT,X ; as end pointer B_DC65 pla ; file type cmp #$04 ; REL file? bne B_DCA9 ; no, -> ldy SA ; secondary address lda LINTAB,Y ; channel number ora #$40 sta LINTAB,Y ; set flag for READ and WRITE lda RECSIZ ; record length sta RecLength,X jsr GetBuffer ; find buffer for side-sector bpl B_DC81 ; found? jmp NoChannel ; 70, 'no channel' B_DC81 ldx CURCHN ; channel number sta SIDSECzp,X ldy TRKSS sty TRACK ; track for side-sector ldy SECSS sty SECTOR ; sector for side-sector jsr Par2DiskCtrl2 ; transmit parameters to disk controller jsr ReadSector4 ; read side sector jsr VerifyExec ; and verify J_DC98 ldx CURCHN ; channel number lda #$02 sta WRIPNT,X ; pointer for writing lda #$00 jsr SetBufPointer3 ; buffer pointer to zero jsr NxtByte2Out ; find next record jmp GetSector2 ; get track and sector number B_DCA9 jsr RdNxtBlock2 ; get byte from buffer ldx CURCHN ; channel number sta OUTREG,X ; byte in output register lda #$88 ; set flag for READ sta REWRFLzp,X rts ;** Reset pointer ResetPointer ldx CURCHN ; channel number lda BUF0CH1zp,X ; buffer number asl A ; times 2 tay lda #$02 sta BUFTABab,Y ; buffer pointer lo lda BUF1CH1zp,X ora #$80 ; set bit 7 sta BUF1CH1zp,X asl A tay lda #$02 sta BUFTABab,Y ; buffer pointer lo lda #$00 sta RECL,X ; block number lo sta RECH,X ; block number hi lda #$00 sta ENDPNT,X ; end pointer rts ;** Construct a new block [DCDA] AllocNewSec jsr FreeSecAlloc ; find free sector in BAM lda #$01 jsr FindWrChanBuf ; open channel jsr Par2DiskCtrl ; transmit parameter to disk controller jsr ResetPointer ; reset pointer ldx CURCHN ; channel number lda TYPE ; file type pha asl A ora DRVNMB ; drive number sta DIACFLzp,X ; save as flag pla cmp #$04 ; REL file? beq B_DCFD ; yes, -> lda #$01 sta REWRFLzp,X ; set WRITE flag rts B_DCFD ldy SA ; secondary address lda LINTAB,Y ; channel number in table and #$3F ; erase the top two bits ora #$40 ; set bit 6 sta LINTAB,Y ; READ and WRITE flag lda RECSIZ ; record length sta RecLength,X ; in table jsr GetBuffer ; find buffer bpl B_DD16 ; found? jmp NoChannel ; 70, 'no channel' B_DD16 ldx CURCHN ; channel number sta SIDSECzp,X ; buffer number for side-sector jsr EraseBuffer ; erase buffer jsr P_F11E ; find free block in BAM lda TRACK ; track sta TRKSS ; for side-sector lda SECTOR ; sector sta SECSS ; for side-sector ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number jsr Par2DiskCtrl2 ; transmit parameter to disk controller lda #$00 jsr SetBufPtrSS2 ; buffer pointer to zero lda #$00 jsr WrBytSidSec lda #$11 ; 17 jsr WrBytSidSec ; as end pointer in buffer lda #$00 ; zero jsr WrBytSidSec ; as side-sector number in buffer lda RECSIZ ; record length jsr WrBytSidSec ; in buffer lda TRACK ; track number of this block jsr WrBytSidSec ; in buffer lda SECTOR ; sector number jsr WrBytSidSec ; in buffer lda #$10 ; 16 jsr SetBufPtrSS2 ; buffer pointer to 16 jsr GetSector2 ; get track and sector number lda TRACK ; track number of the first data block jsr WrBytSidSec ; in buffer lda SECTOR ; sector number of the first data block jsr WrBytSidSec ; in buffer jsr WriteSector4 ; write block to disk jsr VerifyExec ; and check lda #$02 jsr SetBufPointer3 ; buffer pointer to 2 ldx CURCHN ; channel number sec lda #$00 sbc RecLength,X ; record length sta WRIPNT,X ; pointer for writing jsr CreateRecords jsr SetLinkLstRec ; write link bytes in buffer jsr WriteSector3 ; write block to disk jsr VerifyExec ; and check jsr WriteBam ; write BAM jmp J_DC98 ; and done ;** Write byte in side-sector block [DD8D] WrBytSidSec pha ; save byte ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number of the side-sector jmp J_CFFD ; write byte in buffer ;** Manipulate flags E_DD95 bcc DeleteFlags ; [DD97] SetFlags ldx CURCHN ; channel number ora DIACFLzp,X ; set flag bne B_DDA3 ; (IMHO) always -> ; [DD9D] DeleteFlags ldx CURCHN ; channel number eor #$FF and DIACFLzp,X ; erase flag B_DDA3 sta DIACFLzp,X rts ChkChanBit ldx CURCHN ; channel number and DIACFLzp,X ; test flag rts ;** Verify command code for writing [DDAB] Chk4Write jsr GetBufNumber ; get buffer number tax lda LSTJOB,X and #$F0 ; isolate command code cmp #$90 ; code for writing? rts ;** Check if the file is open [DDB7] IsFileOpen ldx #$00 B_DDB9 stx TEMP2 ; counter for secondary address lda LINTAB,X ; get channel number from table cmp #$FF bne B_DDCA ; file open? B_DDC2 ldx TEMP2 inx ; increment counter cpx #$10 ; smaller than 16? bcc B_DDB9 rts B_DDCA stx TEMP2 and #$3F ; isolate channel number tay lda DIACFLab,Y and #$01 ; isolate drive number sta TEMP1 ldx ENTFND lda DRVNUM,X and #$01 ; isolate drive number cmp TEMP1 ; same drive? bne B_DDC2 ; no, -> lda DSEC,Y ; sector number in directory cmp DIRSECP,X ; same as file? bne B_DDC2 ; no, -> lda DIND,Y cmp BUFPTR,X ; pointer same? bne B_DDC2 ; no, -> clc rts ;** Write a block of a REL file [DDF1] GetBufWrSec jsr GetBufNumber2 ; get buffer number bvc B_DDFC ; no REL file? jsr WriteSector3 ; write block jsr VerifyExec ; and verify B_DDFC rts ;** Write bytes for following track [DDFD] WrNxtSecBuf jsr SetBufPtrZero ; set buffer pointer lda TRACK ; track number sta (DIRBUF),Y ; in buffer iny lda SECTOR ; sector number sta (DIRBUF),Y ; in buffer jmp WrBufNum2Tbl ; set rel-flag ;** Get following track and sector numbers [DE0C] GetNxtTraSec jsr SetBufPtrZero ; set buffer pointer lda (DIRBUF),Y ; following track number sta TRACK iny lda (DIRBUF),Y ; and get sector number sta SECTOR rts ;** Set linker for last block of record [DE19] SetLinkLstRec jsr SetBufPtrZero ; set buffer pointer lda #$00 ; zero sta (DIRBUF),Y ; as track number iny ldx CURCHN ; channel number lda WRIPNT,X ; pointer in block tax dex ; minus 1 txa sta (DIRBUF),Y ; as pointer in block rts ;** Buffer pointer to zero [DE2B] SetBufPtrZero jsr GetBufNumber ; get buffer number asl A ; times 2 tax lda BUFTABzp+1,X ; buffer pointer hi sta DIRBUF+1 lda #$00 sta DIRBUF ; buffer pointer lo ldy #$00 rts ;** Get track and Sector [DE3B] GetTrackSector jsr OpenChan4Read ; get channel number GetSector2 jsr GetBufNumber ; get buffer number sta JOBNUM ; save asl A ; times 2 tay lda TRASECab,Y ; get track sta TRACK lda TRASECab+1,Y ; and sector number from disk controller sta SECTOR rts ;** [DE50] P_DE50 lda #$90 ; command code for writing sta CMD bne B_DE7F ; always -> ;** [DE57] ReadSector2 lda #$80 ; command code for reading sta CMD bne B_DE7F ; always -> ;** [DE5E] WriteSector3 lda #$90 ; command code for writing sta CMD bne B_DE8B ; always -> ;??? used ??? lda #$80 ; command code for reading sta CMD bne B_DE8B ;** [DE6C] WriteSector4 lda #$90 ; command code for writing sta CMD bne B_DE75 ;** [DE73] ReadSector4 lda #$80 ; command code for reading B_DE75 sta CMD ldx CURCHN ; channel number lda SIDSECzp,X ; side-sector buffer number tax ; buffer associated? bpl B_DE92 ; yes,-> B_DE7F jsr Par2DiskCtrl ; generate header for disk controller jsr GetBufNumber ; get buffer number tax lda DRVNMB ; drive number sta LSTJOB,X B_DE8B jsr P_E115 ; buffer number jsr GetBufNumber ; get buffer number tax B_DE92 jmp ChkTrackSector ; write block ;** Get following track and sector from buffer [DE95] GetNxtSector lda #$00 jsr SetBufPointer3 ; buffer pointer to zero jsr GetByteFromBuf ; get byte sta TRACK ; save as track jsr GetByteFromBuf ; get byte sta SECTOR ; as sector rts ;** Coppy buffer contents [DEA5] CopyBuffer pha lda #$00 sta TEMP0 sta TEMP2 lda BufferAddress,Y ; buffer address Y, hi sta TEMP1 lda BufferAddress,X ; buffer address X, lo sta TEMP3 pla tay dey B_DEB9 lda (TEMP0),Y sta (TEMP2),Y dey bpl B_DEB9 rts ;** Erase the buffer [DEC1] EraseBuffer tay ; buffer number lda BufferAddress,Y ; get hi-address sta TEMP1 lda #$00 ; lo-address sta TEMP0 tay B_DECC sta (TEMP0),Y ; erase buffer iny bne B_DECC rts ;** Get side-sector number [DED2] GetNumSideSec lda #$00 jsr SetBufPtrSS ; buffer pointer to zero ldy #$02 lda (DIRBUF),Y ; byte 2 contains the side-sector number rts ;** Set buffer pointer to side-sector [DEDC] SetBufPtrSS sta DIRBUF ; printer lo ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number tax lda BufferAddress,X ; buffer address hi sta DIRBUF+1 ; set rts ;** Buffer pointer for side-sector [DEE9] SetBufPtrSS2 pha ; pointer in side-sector jsr SetBufPtrSS ; set buffer pointer pha txa ; buffer number asl A ; times 2 tax pla sta BUFTABzp+1,X ; buffer pointer hi pla sta BUFTABzp,X ; buffer pointer lo rts ;** Get side sector and buffer pointer [DEF8] GetSideSector jsr IsSidSecInBuf ; is side-sector in buffer? bmi B_DF0B ; no, -> bvc B_DF12 ; ok ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number jsr ReadSideSec ; read side-sector jsr IsSidSecInBuf ; and check if in buffer bpl B_DF12 ; yes? B_DF0B jsr SetPar2LstRec ; get last side-sector bit A_FECD+1 ; set V bit rts B_DF12 lda CHNNUM3 ; side-sector and pointer jsr SetBufPtrSS2 ; set pointer in side-sector bit A_FECD ; erase V bit rts ;** Read side-sector [DF1B] ReadSideSec sta JOBNUM ; buffer number lda #$80 ; command code for reading bne B_DF25 ; always -> ;** Write side-sector ; !!! not used IMHO ==> sta JOBNUM ; buffer number lda #$90 ; command code for writing ; <== B_DF25 pha lda DIACFLzp,X and #$01 ; isolate drive number sta DRVNMB pla ora DRVNMB ; command code plus drive number sta CMD ; save lda (DIRBUF),Y ; track number sta TRACK iny lda (DIRBUF),Y ; sector number sta SECTOR lda JOBNUM ; buffer number jsr Par2DiskCtrl2 ; transmit parameter to disk controller ldx JOBNUM ; buffer number jmp J_D593 ; transmit command to disk controller ;** Set buffer pointer in side-sector [DF45] SetPtrSidSec ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number jmp SetBufPointer2 ; set buffer pointer ;** Calculate number of blocks in a REL file B_DF4C lda #$78 ; 120 block pointers per side-sector jsr IncSidSecPtr ; add to $70/$71 ;** [DF51] CalcSecPtrREL dex ; next side-sector? bpl B_DF4C ; yes, -> lda TEMP3 ; pointer value in last block lsr A ; divided by 2 jsr IncSidSecPtr ; add to previous sum lda TEMP4 ; number of the side-sector block ;** [DF5C] IncSidSecPtr clc adc TEMP1 sta TEMP1 ; add bcc B_DF65 inc TEMP2 B_DF65 rts ;** Verify side-sector in buffer [DF66] IsSidSecInBuf jsr GetNumSideSec ; get side-sector number cmp CHNNUM2 ; = number of necessary block? bne B_DF7B ; no, -> ldy CHNNUM3 ; pointer in side-sector lda (DIRBUF),Y ; track number beq B_DF77 bit A_FECD ; erase bits rts B_DF77 bit A_FECD+2 ; set N-bit rts B_DF7B lda CHNNUM2 ; side-sector number cmp #$06 ; 6 or greater? bcs B_DF8B ; yes, -> asl A tay lda #$04 sta DIRBUF lda (DIRBUF),Y ; track number bne B_DF8F B_DF8B bit A_FECD+3 ; set N and V bits rts B_DF8F bit A_FECD+1 ; set V bit rts ;** Get buffer number [DF93] GetBufNumber ldx CURCHN ; channel number lda BUF0CH1zp,X ; buffer number bpl B_DF9B lda BUF1CH1zp,X ; buffer number from second table B_DF9B and #$BF ; erase V bit rts ;** Get buffer number [DF9E] GetBufNumber2 ldx CURCHN ; channel number stx LBUSED ; save lda BUF0CH1zp,X ; get buffer number bpl B_DFB0 ; buffer allocated txa clc adc #$07 ; increment number by 7 sta LBUSED ; and save lda BUF1CH1zp,X ; buffer number from table 2 B_DFB0 sta TEMP1 and #$1F ; erase the highest 3 bits bit TEMP1 rts ChkBufferOK ldx CURCHN ; channel number lda BUF0CH1zp,X ; buffer number bmi B_DFBF ; buffer free? lda BUF1CH1zp,X ; buffer number from table 2 B_DFBF cmp #$FF ; free? rts ;** [DFC2] DeactivateBuf ldx CURCHN ora #$80 ldy BUF0CH1zp,X bpl B_DFCD sta BUF0CH1zp,X rts B_DFCD sta BUF1CH1zp,X rts ;** Get next record in REL file [DFD0] GetNxtRelRec lda #$20 jsr DeleteFlags ; erase bit 5 lda #$80 jsr ChkChanBit ; test bit 7 bne B_E01D ; set? ldx CURCHN ; channel number inc RECL,X ; increment record number bne B_DFE4 inc RECH,X ; record number hi B_DFE4 ldx CURCHN ; channel number lda WRIPNT,X ; write pointer beq B_E018 ; zero? jsr SetBufPointer ; set buffer pointer ldx CURCHN ; channel number cmp WRIPNT,X ; buffer pointer smaller than write ; pointer bcc B_DFF6 ; yes, -> jsr WrRdSector ; write block, read next block B_DFF6 ldx CURCHN ; channel number lda WRIPNT,X ; write pointer jsr SetBufPointer3 ; set buffer pointer = write pointer lda (BUFTABzp,X) ; byte from buffer sta DATA ; put in output register lda #$20 jsr DeleteFlags ; erase bit 5 jsr SetPtr2NxtRec ; add record length to write pointer P_E009 pha ; and save bcc B_E034 ; not yet in last block? lda #$00 jsr GetAthByte ; get track number bne B_E034 ; does block exist? pla ; pointer cmp #$02 ; = 2 beq B_E02A ; yes, -> B_E018 lda #$80 jsr SetFlags ; set bit 7 B_E01D jsr GetBufChanNum ; get byte from buffer [D12F] lda BUFTABzp,X ; buffer pointer sta ENDPNT,Y ; as end pointer lda #$0D ; CR sta DATA ; in output register rts B_E02A jsr Ptr2LastChar ldx CURCHN ; channel number lda #$00 sta WRIPNT,X ; write pointer to zero rts B_E034 pla ;** Set the pointer to the last character [E035] Ptr2LastChar ldx CURCHN ; channel number sta WRIPNT,X ; set write pointer jmp J_E16E ; continue -> ;** Write block and read next block [E03C] WrRdSector jsr GetDrvNum3 ; get drive number jsr GetNxtSector ; get track and sector number jsr GetBufNumber2 ; get bufer number bvc B_E05D ; no REL file? jsr WriteSector3 ; write block jsr ChangeBuffer2 ; change buffer lda #$02 jsr SetBufPointer3 ; buffer pointer to 2 jsr Chk4Write ; command code for writing? bne B_E07B ; no, -> jsr ReadSector2 ; read block jmp VerifyExec ; and verify B_E05D jsr ChangeBuffer2 ; change buffer jsr Chk4Write ; command code for writing? bne B_E06B ; no, -> jsr ReadSector2 ; read block jsr VerifyExec ; and verify B_E06B jsr GetNxtSector ; get track and sector number lda TRACK ; track beq B_E07B ; no following track jsr ChangeBuffer2 ; change buffer jsr ReadSector2 ; read block jsr ChangeBuffer2 ; change buffer B_E07B rts ;** Write a byte in a record WrByte2Record jsr WrBufNum2Tbl jsr GetBufNumber ; get buffer number asl A ; times 2 tax lda DATA ; data byte sta (BUFTABzp,X) ; write in buffer ldy BUFTABzp,X ; buffer pointer iny ; increment bne B_E096 ; not equal zero? ldy CURCHN ; channel number lda WRIPNTab,Y ; write pointer beq B_E09E ; equal zero? ldy #$02 ; buffer pointer to 2 B_E096 tya ldy CURCHN ; channel number cmp WRIPNTab,Y ; buffer pointer = write pointer? bne B_E0A3 ; no, -> B_E09E lda #$20 jmp SetFlags ; set bit 5 B_E0A3 inc BUFTABzp,X ; increment buffer pointer bne B_E0AA ; not zero? jsr WrRdSector ; else write block, read next one B_E0AA rts ;** Write byte in REL file J_E0AB lda #$A0 jsr ChkChanBit ; test bits 6 & 7 bne B_E0D9 ; set? J_E0B2 lda DATA ; data byte jsr WrByte2Record ; write in record lda EOIFLG ; end? beq B_E0C8 ; yes, -> rts B_E0BC lda #$20 jsr ChkChanBit ; test bit 5 beq B_E0C8 ; not set lda #$51 ; 51, 'overflow in record' sta ERWORD ; set error flag B_E0C8 jsr P_E0F3 ; fill remainder with zeroes jsr NxtByte2Out lda ERWORD ; error flag set? beq B_E0D6 ; no, -> jmp OutputErrorMsg ; set error message B_E0D6 jmp OK2Buffer ; error free execution B_E0D9 and #$80 ; bit 7 set? bne B_E0E2 ; yes, -> lda EOIFLG beq B_E0BC ; end? rts B_E0E2 lda DATA ; data byte pha jsr ExpandSidSec ; expand side-sector pla sta DATA lda #$80 jsr DeleteFlags ; erase bit 7 jmp J_E0B2 ; write byte in file ;** Fill record with 0s P_E0F3 lda #$20 jsr ChkChanBit ; test bit 5 bne B_E104 ; set? lda #$00 sta DATA ; zero as data byte jsr WrByte2Record ; write in record jmp P_E0F3 ; until record full B_E104 rts ;** Write buffer number in table WrBufNum2Tbl lda #$40 jsr SetFlags ; set bit 6 jsr GetBufNumber2 ; get buffer number ora #$40 ; set bit 6 ldx LBUSED ; channel number + 7 sta BUF0CH1zp,X ; write in table rts P_E115 jsr GetBufNumber2 ; get buffer number and #$BF ; erase bit 6 ldx LBUSED ; channel number sta BUF0CH1zp,X ; write in table rts ;** Get byte from REL file [E120] J_E120 lda #$80 jsr ChkChanBit ; test bit 7 bne NoRecord ; set? jsr GetBufChanNum ; get byte from buffer [D12F] lda BUFTABzp,X ; buffer pointer cmp ENDPNT,Y ; compare to end pointer beq NxtByte2Out ; equal? inc BUFTABzp,X ; increment buffer pointer bne B_E13B ; not zero? jsr WrRdSector ; write block, read next one J_E138 jsr GetBufChanNum ; get byte from buffer [D12F] B_E13B lda (BUFTABzp,X) J_E13D sta OUTREG,Y ; in output register lda #$89 sta REWRFLab,Y ; set READ and WRITE flag lda BUFTABzp,X ; buffer pointer cmp ENDPNT,Y ; compare to end pointer beq B_E14D ; same? rts B_E14D lda #$81 sta REWRFLab,Y ; set flag for end rts ; [E153] NxtByte2Out jsr GetNxtRelRec ; find next record jsr GetBufChanNum ; get buffer and channel number [D12F] lda DATA ; data byte jmp J_E13D ; into output register ;** Message "No record present" [E15E] NoRecord ldx CURCHN ; channel number lda #$0D ; CR sta OUTREG,X ; into output register lda #$81 sta REWRFLzp,X ; set flag for end lda #$50 jsr OutputErrorMsg ; 50, 'record not present' J_E16E ldx CURCHN ; channel number lda WRIPNT,X ; write pointer sta R1 ; save dec R1 cmp #$02 ; equal 2? bne B_E17E ; no, -> lda #$FF sta R1 B_E17E lda RecLength,X ; record length sta R2 jsr SetBufPointer ; set buffer pointer ldx CURCHN ; channel number cmp R1 ; buffer pointer > write pointer? bcc B_E1A4 beq B_E1A4 ; no, -> jsr ChangeBuffer2 ; change buffer jsr LastCharNot0 bcc B_E19D ldx CURCHN ; channel number sta ENDPNT,X jmp ChangeBuffer2 ; change buffer B_E19D jsr ChangeBuffer2 ; change buffer lda #$FF sta R1 B_E1A4 jsr LastCharNot0 bcs B_E1AC jsr SetBufPointer ; set buffer pointer B_E1AC ldx CURCHN ; channel number sta ENDPNT,X ; end pointer rts ;** Find the last char of the record <> 0 [E1B2] LastCharNot0 jsr SetBufPtrZero ; buffer pointer to zero ldy R1 B_E1B7 lda (DIRBUF),Y ; byte from buffer bne B_E1C8 ; not zero? dey cpy #$02 bcc B_E1C4 dec R2 bne B_E1B7 B_E1C4 dec R2 clc rts B_E1C8 tya sec rts ;** Get last side-sector [E1CB] SetPar2LstRec jsr GetNumSideSec ; get number of the side-sector sta CHNNUM2 ; save lda #$04 sta DIRBUF ; pointer to side-sectors ldy #$0A bne B_E1DC B_E1D8 dey dey bmi Error67 B_E1DC lda (DIRBUF),Y ; track number of the previous block beq B_E1D8 tya lsr A ; divide by 2 cmp CHNNUM2 ; = number of the actual block? beq B_E1EF ; yes, -> sta CHNNUM2 ; else save all numbers ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number jsr ReadSideSec ; read block B_E1EF ldy #$00 sty DIRBUF ; buffer pointer lda (DIRBUF),Y ; track number bne Error67 ; another block? iny lda (DIRBUF),Y ; sector number = end pointer tay dey sty CHNNUM3 ; save end pointer tya jmp SetBufPtrSS2 ; set buffer pointer ;** [E202] Error67 lda #$67 jsr CreErrorMsg ; 67, 'illegal track or sector' ;** P - Position command [E207] Position jsr ChkLineLength ; verify lines lda CMDBUF+1 ; secondary address sta SA jsr OpenChan4Read ; find channel number bcc B_E219 ; found? lda #$70 jsr OutputErrorMsg ; 70, 'no block' B_E219 lda #$A0 jsr DeleteFlags ; erase bits 6 & 7 jsr CheckREL ; verify if 'REL'-file beq B_E228 ; yes, -> lda #$64 jsr OutputErrorMsg ; 64, 'file type mismatch' B_E228 lda DIACFLzp,X and #$01 sta DRVNMB ; drive number lda CMDBUF+2 ; record number lo sta RECL,X lda CMDBUF+3 ; record number hi sta RECH,X ldx CURCHN ; channel number lda #$89 sta REWRFLzp,X ; READ and WRITE flag lda CMDBUF+4 ; byte-pointer beq B_E253 ; zero? sec sbc #$01 beq B_E253 cmp RecLength,X ; compare with record length bcc B_E253 lda #$51 sta ERWORD ; 51, 'overflow in record' lda #$00 B_E253 sta CHNNUM1 jsr SetPtrRelFil ; calculate pointer in REL file jsr GetSideSector ; and read appropriate side-sector bvc B_E265 ; does block exist? lda #$80 jsr SetFlags ; set bit 7 jmp NoRecord ; and 50, 'record not present' B_E265 jsr P_E275 lda #$80 jsr ChkChanBit ; test bit 7 beq B_E272 ; not set jmp NoRecord ; 50, 'record not present' B_E272 jmp Out_Err_Msg ; done P_E275 jsr Record2Buffer lda CHNNUM4 ; pointer in REL file jsr SetBufPointer3 ; set buffer pointer ldx CURCHN ; channel number lda RecLength,X ; record length sec sbc CHNNUM1 ; minus position bcs B_E289 ; positive? jmp Error67 ; 67, 'illegal track or sector' B_E289 clc adc CHNNUM4 ; add pointer in data block bcc B_E291 ; no overflow adc #$01 ; plus 2 sec B_E291 jsr P_E009 ; set pointer jmp J_E138 ; get byte from buffer E_E297 lda #$51 jsr OutputErrorMsg ; 51, 'overflow in record' ;** Write record into the buffer [E29C] Record2Buffer lda DIRBUF ; buffer pointer lo sta R3 lda DIRBUF+1 ; buffer pointer hi sta R4 jsr CompTraSec ; compare track and sector bne B_E2AA ; not equal? rts B_E2AA jsr GetBufWrSec jsr GetNxtTraSec lda TRACK ; track beq B_E2C2 ; no block following? jsr CompTraSec2 ; compare track and sector number bne B_E2BF ; not equal? jsr ChangeBuffer2 ; change buffer jmp ChkBufFree B_E2BF jsr ChkBufFree B_E2C2 ldy #$00 lda (R3),Y ; track sta TRACK iny lda (R3),Y ; and sector of the next block sta SECTOR jmp J_D0AF ; read block ;** Comp sectors [E2D0] CompTraSec jsr GetSector2 CompTraSec2 ldy #$00 lda (R3),Y ; track number cmp TRACK ; compare beq B_E2DC rts B_E2DC iny lda (R3),Y ; sector number cmp SECTOR ; compare rts ;** Divide data blocks into records [E2E2] CreateRecords jsr SetBufPtrZero ; set buffer pointer ldy #$02 lda #$00 B_E2E9 sta (DIRBUF),Y ; erase buffer iny bne B_E2E9 jsr SetPtr2NxtRec ; set pointer to next record B_E2F1 sta WRIPNT,X tay lda #$FF sta (DIRBUF),Y ; $FF as 1st character in record jsr SetPtr2NxtRec ; set pointer to next record bcc B_E2F1 ; done in this block? L_E2FD bne B_E303 ; block full? [E2FD] lda #$00 sta WRIPNT,X ; write pointer to zero B_E303 rts ;** Set pointer to next record SetPtr2NxtRec ldx CURCHN ; channel number lda WRIPNT,X ; write pointer sec beq B_E318 ; equal zero? clc adc RecLength,X ; add record length bcc B_E31B ; smaller than 256? bne B_E318 ; equal 256? lda #$02 bit A_FECC ; set the Zero flag, needed at L_E2FD rts B_E318 adc #$01 ; add two sec B_E31B rts ;** Expand side-sector [E31C] ExpandSidSec jsr GetDrvNum3 ; get drive number jsr SetPar2LstRec ; get last side-sector jsr Record2Buffer jsr Look4FreeBuf lda CHNNUM3 sta R1 lda CHNNUM2 ; side-sector number sta R0 lda #$00 sta R2 lda #$00 sta CHNNUM1 jsr SetPtrRelFil ; calculate side-sector number and ; pointer J_E33B jsr NumBlocksFree ; number of free blocks ldy CURCHN ; channel number ldx RecLength,Y ; record length dex txa clc adc CHNNUM4 ; plus pointer in data block bcc B_E355 inc CHNNUM3 inc CHNNUM3 ; increment pointer to end by 2 bne B_E355 inc CHNNUM2 ; increment side-sector number lda #$10 sta CHNNUM3 ; set pointer to 16 B_E355 lda R1 clc adc #$02 jsr SetBufPtrSS2 ; set buffer pointer for side-sector lda CHNNUM2 ; side-sector number cmp #$06 bcc B_E368 ; smaller than 6? B_E363 lda #$52 jsr OutputErrorMsg ; 52, 'file too large' B_E368 lda CHNNUM3 ; end pointer sec sbc R1 ; minus last end pointer bcs B_E372 sbc #$0F ; minus 16 clc B_E372 sta TEMP3 lda CHNNUM2 ; side-sector number sbc R0 ; minus last side-sector number sta TEMP4 ; save ldx #$00 stx TEMP1 ; erase sum for calculation stx TEMP2 tax jsr CalcSecPtrREL ; calculate block # of REL file [DF51] lda TEMP2 bne B_E38F ldx TEMP1 dex bne B_E38F inc R2 B_E38F cmp NBTEMP1 ; block number of REL file bcc B_E39D ; greater than free blocks on disk? bne B_E363 ; 52, 'file too large' lda NBTEMP0 cmp TEMP1 bcc B_E363 ; 52, 'file too large' B_E39D lda #$01 jsr GetAthByte ; get byte from buffer clc adc #$01 ; plus 1 ldx CURCHN sta WRIPNT,X ; as write pointer jsr P_F11E ; find free block in BAM jsr WrNxtSecBuf ; track and sector in buffer lda R2 bne B_E3C8 ; only one block needed? jsr WriteSector3 ; write block B_E3B6 jsr ChangeBuffer2 ; change buffer jsr Par2DiskCtrl ; transmit parameter to disk controller jsr P_F11E ; find free block in BAM jsr WrNxtSecBuf ; track and sector in buffer jsr CreateRecords jmp J_E3D4 B_E3C8 jsr ChangeBuffer2 ; change buffer jsr Par2DiskCtrl ; transmit parameter to disk controller jsr CreateRecords jsr SetLinkLstRec ; zero byte and end pointer in buffer J_E3D4 jsr WriteSector3 ; write block jsr GetNxtTraSec ; get track and sector lda TRACK ; track pha lda SECTOR ; and sector pha ; save jsr GetSector2 ; get track and sector from disk lda SECTOR ; controller pha lda TRACK ; save track and sector pha jsr SetPtrSidSec ; set buffer pointer for side-sector tax bne B_E3F9 ; pointer not zero? jsr P_E44E ; write side-sector lda #$10 jsr SetBufPtrSS2 ; buffer pointer to 16 inc R0 ; increment side-sector number B_E3F9 pla jsr WrBytSidSec ; track in side-sector pla jsr WrBytSidSec ; sector in side-sector pla sta SECTOR ; sector pla sta TRACK ; and get track back beq B_E418 ; no more blocks? lda R0 ; side-sector number cmp CHNNUM2 ; changed? bne B_E3B6 ; yes, -> jsr SetPtrSidSec ; set buffer pointer in side-sector cmp CHNNUM3 ; end pointer bcc B_E3B6 ; smaller? beq B_E3C8 ; same B_E418 jsr SetPtrSidSec ; set buffer pointer in side-sector pha lda #$00 jsr SetBufPtrSS ; buffer pointer to zero lda #$00 tay sta (DIRBUF),Y ; zero as track number iny pla ; end pointer sec sbc #$01 ; minus one sta (DIRBUF),Y ; as sector jsr WriteSector4 ; write block jsr VerifyExec ; and verify jsr WriteBam ; update BAM jsr SetPtrRelFil ; update pointer for REL file jsr ChangeBuffer2 ; change buffer jsr GetSideSector ; right side-sector? bvs B_E444 ; no, -> jmp P_E275 B_E444 lda #$80 jsr SetFlags ; set bit 7 lda #$50 jsr OutputErrorMsg ; 50, 'record not present' ;** Write side-sector and allocate new P_E44E jsr P_F11E ; find free block in BAM jsr ChangeBuffer2 ; change buffer jsr GetBufWrSec ; write block jsr GetBufNumber ; get buffer number pha jsr EraseBuffer ; erase buffer ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number tay pla tax lda #$10 ; 16 bytes of the side-sector jsr CopyBuffer ; copy in buffer lda #$00 jsr SetBufPtrSS ; buffer pointer to 0, old side-sector ldy #$02 lda (DIRBUF),Y ; side-sector number pha lda #$00 jsr SetBufPointer3 ; buffer pointer to 0, new side-sector pla clc adc #$01 ; increment side-sector number sta (DIRBUF),Y ; and in buffer asl A ; times 2 adc #$04 ; plus 4 sta R3 tay sec sbc #$02 ; minus 2 sta R4 ; same pointer to old side-sector lda TRACK ; track sta R1 sta (DIRBUF),Y ; in buffer iny lda SECTOR ; sector sta R2 sta (DIRBUF),Y ; in buffer ldy #$00 tya sta (DIRBUF),Y ; zero in buffer iny lda #$11 ; 17 sta (DIRBUF),Y ; number of bytes in block lda #$10 ; 16 jsr SetBufPointer3 ; buffer pointer to 16 jsr P_DE50 ; write block jsr VerifyExec ; and verify ldx CURCHN ; channel number lda SIDSECzp,X ; buffer number of the side-sector pha jsr GetBufNumber2 ; get buffer number ldx CURCHN ; channel number sta SIDSECzp,X ; write in table pla ldx LBUSED ; channel number + 7 sta BUF0CH1zp,X ; in table lda #$00 jsr SetBufPointer3 ; buffer pointer to zero ldy #$00 lda TRACK ; track sta (DIRBUF),Y ; in buffer iny lda SECTOR ; sector sta (DIRBUF),Y ; in buffer jmp J_E4DE B_E4D1 jsr GetBufNumber ; get buffer number ldx CURCHN ; channel number jsr ReadSideSec ; read block lda #$00 jsr SetBufPointer3 ; buffer pointer to zero J_E4DE dec R4 dec R4 ; counter for side-sector blocks ldy R3 lda R1 ; track number sta (DIRBUF),Y ; in buffer iny lda R2 ; sector number sta (DIRBUF),Y ; in buffer jsr WriteSector3 ; write block jsr VerifyExec ; and verify ldy R4 ; counter for side-sector blocks cpy #$03 bcs B_E4D1 ; greater than or equal to 3? jmp ChangeBuffer2 ; change buffer ;** Table of error messages ;** Format: error numbers ;** description ;** (with start and end letters +$80) ;** If value AND DRVNMB less than $10 ;** Then look up text in pointer ;** Table. ErrorMessages ; [E4FC] ;** Ok .by $00 ; 00 .by $A0,$4F,$CB ; ' oK' ;** Read eroor .by $20,$21,$22,$23,$24,$27 ; error numbers of 'read error' .by $D2,$45,$41,$44 ; 'Read' .by $89 ; pointer to 'error' ;** File too large .by $52 ; 52 .by $83 ; pointer to 'file' .by $20,$54,$4F,$4F ; ' too ' .by $20,$4C,$41,$52,$47,$C5 ; 'largE' ;** Record not present .by $50 ; 50 .by $8B ; pointer to 'record' and 'not' .by $06 ; pointer to 'record' and 'not' .by $20,$50,$52,$45,$53,$45,$4E,$D4 ; ' presenT' ;** Overflow in record .by $51 ; 51 .by $CF,$56,$45,$52,$46,$4C,$4F,$57 ; 'Overflow' .by $20,$49,$4E ; ' in' .by $8B ; pointer to 'record' ;** Write error .by $25,$28 ; error numbers of 'write error' .by $8A ; pointers to 'write' and 'error' .by $89 ; pointers to 'write' and 'error' ;** Write protect on .by $26 ; 26 .by $8A ; pointer to 'write' .by $20,$50,$52,$4F,$54,$45,$43,$54 ; ' protect' .by $20,$4F,$CE ; ' oN' ;** Disk id mismatch .by $29 ; 29 .by $88 ; pointer to 'disk' .by $20,$49,$44 ; ' id' .by $85 ; pointer to 'mismatch' ;** Syntax error .by $30,$31,$32,$33,$34 ; error numbers for 'syntax error' .by $D3,$59,$4E,$54,$41,$58 ; 'Syntax' .by $89 ; pointer to 'error' ;** Write file open .by $60 ; 60 .by $8A ; pointers to 'write', 'file' and 'open' .by $03 ; pointers to 'write', 'file' and 'open' .by $84 ; pointers to 'write', 'file' and 'open' ;** File exists .by $63 ; 63 .by $83 ; pointer to 'file' .by $20,$45,$58,$49,$53,$54,$D3 ; ' existS' ;** File type mismatch .by $64 ; 64 .by $83 ; pointer to 'file' .by $20,$54,$59,$50,$45 ; ' type' .by $85 ; pointer to 'mismatch' ;** No block .by $65 ; 65 .by $CE,$4F ; 'No' .by $20,$42,$4C,$4F,$43,$CB ; ' block' ;** Illegal track or sector .by $66,$67 ; error numbers for .by $C9,$4C,$4C,$45,$47,$41,$4C ; 'Illegal' .by $20,$54,$52,$41,$43,$4B ; ' track' .by $20,$4F,$52 ; ' or' .by $20,$53,$45,$43,$54,$4F,$D2 ; ' sectoR' ;** File not open .by $61 ; 61 .by $83 ; pointer to 'file' .by $06 ; pointer to 'not' .by $84 ; pointer to 'open' ;** File not found .by $39,$62 ; error numbers for 'file not found' .by $83 ; pointers to 'file' .by $06 ; pointers to 'not' .by $87 ; pointers to 'found' ;** Files scratched .by $01 ; 01 .by $83 ; pointer to 'files' .by $53,$20,$53 ; 's s' .by $43,$52,$41,$54,$43,$48,$45,$C4 ; 'cratcheD' ;** No channel .by $70 ; 70 .by $CE,$4F ; 'No' .by $20,$43,$48,$41,$4E,$4E,$45,$CC ; 'channeL' ;** Dir error .by $71 ; 71 .by $C4,$49,$52 ; 'Dir' .by $89 ; pointer to 'error' ;** Disk full .by $72 ; 72 .by $88 ; pointer to 'disk' .by $20,$46,$55,$4C,$CC ; ' fulL' ;** Cbm dos v2.6 1541 .by $73 ; 73 .by 'C' + $80 .tx 'BM 1541IDE8 V0.' ; CBM 1541IDE8 V0.1 &&&16 .BY '7' + $80 ;** Drive not ready .by $74 ; 74 .by $C4,$52,$49,$56,$45 ; 'Drive' .by $06 ; pointer to 'not' .by $20,$52,$45,$41,$44,$D9 ; ' readY' ;** Indexed words ;** Format: index number ;** description .by $09 ; ' readY' .by $C5,$52,$52,$4F,$D2 ; 'ErroR' .by $0A .by $D7,$52,$49,$54,$C5 ; 'WritE' .by $03 .by $C6,$49,$4C,$C5 ; 'FilE' .by $04 .by $CF,$50,$45,$CE ; 'OpeN' .by $05 .by $CD,$49,$53,$4D,$41,$54,$43,$C8 ; 'MismatcH' .by $06 .by $CE,$4F,$D4 ; 'NoT' .by $07 .by $C6,$4F,$55,$4E,$C4 ; 'FounD' .by $08 .by $C4,$49,$53,$CB ; 'DisK' .by $0B .by $D2,$45,$43,$4F,$52,$C4 ; 'RecorD' ;** prepare error number and message [E60A] PrepErrMsg pha ; save error code stx JOBNUM ; drive number txa asl A ; times 2 tax ; as pointer lda TRASECzp,X sta TRACK ; get track lda TRASECzp+1,X sta SECTOR ; and sector number pla ; get error code back and #$0F ; isolate bits 0-3 beq B_E625 ; zero, then 24, 'read error' cmp #$0F ; 15? bne B_E627 lda #$74 ; 74, 'drive not ready' bne B_E62D ; 6 B_E625 lda #$06 ; add $20 B_E627 ora #$20 tax dex dex ; subtract two txa B_E62D pha ; save error number lda INSTRU ; number of the disk command ; ????? cmp #$00 ; OPEN or VALIDATE? bne B_E644 ; no, -> lda #$FF sta INSTRU pla ; get error number back jsr Errmsg2buf ; generate error message jsr LoadBAM ; load BAM jmp CreErrorMsg2 ; set error message B_E644 pla ; [E645] CreErrorMsg jsr Errmsg2buf ; set error message ; [E648] CreErrorMsg2 jsr EraseInputBuf ; erase input buffer lda #$00 sta WBAM ; erase error flag jsr PrepLedFlash ; turn LED off jsr Close17_18 ; close channels 17 and 18 lda #$00 sta INPPTR ; input buffer pointer to zero ldx #NewStack txs ; initialize stack pointer lda ORGSA ; secondary address and #$0F sta SA cmp #$0F ; 15? beq B_E698 ; yes, command channel sei lda LSNACT ; LISTEN active? bne B_E688 ; yes, -> lda TLKACT ; TALK active? bne B_E680 ; yes, -> ldx SA ; channel number lda LINTAB,X ; open channel to this secondary addr cmp #$FF beq B_E698 ; no, -> and #$0F sta CURCHN ; channel jmp J_E68E ;** TALK B_E680 jsr OpenChan4Read ; open channel for reading nop ; accept byte nop nop bne J_E68E ;** LISTEN B_E688 jsr OpenChan4Write ; open channel for writing nop ; accept byte nop nop J_E68E jsr CheckREL ; verify file type cmp #$04 ; file type REL? bcs B_E698 ; yes, -> jsr CloseChannel ; close channel B_E698 jmp WaitLoop1 ;** Convert hex to decimal (2 bytes) [E69B] ; in: A Y ; out: - ; used: A X Y Bcd2Ascii tax lda #$00 sed J_E69F cpx #$00 beq B_E6AA ; convert hex to BCD clc adc #$01 dex jmp J_E69F B_E6AA cld ;** Divide BCD number into two bytes [E6AB] Hex2Ascii tax lsr A lsr A ; shift hi-nibble down lsr A lsr A jsr P_E6B4 ; convert to ASCII txa P_E6B4 and #$0F ; erase top 4 bits ora #$30 ; add '0' sta (ERRPTR),Y ; write in buffer iny ; increment buffer pointer rts ;** Write OK in buffer [E6BC] ; in: - ; out: - ; used: A X Y OK2Buffer jsr ClrErrorFlags ; erase error flag lda #$00 ; error number 0 ; in: A ; out: - ; used: A X Y OK2Buffer2 ldy #$00 sty TRACK ; track 0 sty SECTOR ; sector 0 ;** Error message in buffer (number in A) [E6C7] ; in: A TRACK SECTOR ; out: - ; used: A X Y Errmsg2buf ldy #$00 ; buffer pointer ldx #<(ERRBUF) stx ERRPTR ldx #>(ERRBUF) stx ERRPTR+1 ; pointer $A5/$A6 to $02D5 jsr Hex2Ascii ; error number to ASCII and in buffer lda #',' sta (ERRPTR),Y ; write in buffer iny ; increment buffer pointer lda ERRBUF ; first digit of the disk status sta OUTREG+5 ; in output register txa ; error number in accumulator jsr Message2Buffer ; error message in buffer lda #',' sta (ERRPTR),Y ; write in buffer iny ; and increment buffer pointer lda TRACK ; track number jsr Bcd2Ascii ; to ASCII and in buffer lda #',' sta (ERRPTR),Y ; write in buffer iny ; increment buffer pointer lda SECTOR ; sector jsr Bcd2Ascii ; convert to ASCII and in buffer dey tya clc adc #$D5 sta ENDPNT+5 ; end pointer inc ERRPTR lda #$88 ; set READ flag sta RDFLAG rts ;** Write error message to buffer [E706] ; in: A ; out: - ; used: A X Y Message2Buffer tax ; error code to X lda R0 pha ; preserve pointer $86/$87 lda R1 pha lda #<(ErrorMessages) sta R0 lda #>(ErrorMessages) sta R1 ; $E4FC - start of the error messages txa ; error number in accumulator ldx #$00 J_E718 cmp (R0,X) ; compare with error number in table beq B_E73D pha jsr IncPointer ; bit 7 into carry and erase bcc B_E727 ; not set? B_E722 jsr IncPointer ; bit 7 into carry bcc B_E722 ; wait for character with bit 7 set B_E727 lda R1 cmp #>(PrepErrMsg) bcc B_E735 ; check for end of table bne B_E739 lda #<(PrepErrMsg) cmp R0 bcc B_E739 B_E735 pla jmp J_E718 ; no, continue B_E739 pla jmp J_E74D ; done B_E73D jsr GetChar ; get a character, bit 7 in carry bcc B_E73D ; wait for character with bit 7 set B_E742 jsr WrChar2Buf ; and write in buffer jsr GetChar ; get next character [E767] bcc B_E742 ; wait for character with bit 7 set jsr WrChar2Buf ; put character in buffer J_E74D pla sta R1 pla ; get pointer $86/$87 back sta R0 rts ;** Write character into buffer [E754] ; in: A Y ; out: Y ; used: A X Y WrChar2Buf cmp #' ' bcs B_E763 ; greater, then write in buffer tax ; save code lda #$20 ; blank sta (ERRPTR),Y ; write in buffer iny ; increment buffer pointer txa ; code in accumulator jsr Message2Buffer ; output previous text rts ;** Get a char of the error message B_E763 sta (ERRPTR),Y ; write character in buffer iny ; and increment pointer rts ;** [E767] GetChar inc R0 bne Bit7Carry ; increment pointer inc R1 ;** [E76D] ; in: X ; out: A C ; used: A Bit7Carry lda (R0,X) ; get character asl A ; bit 7 into carry lda (R0,X) ; get character again and #$7F ; erase bit 7 rts ;** Increment pointer [E775] ; in: X ; out: A C ; used: A IncPointer jsr Bit7Carry ; bit 7 into carry inc R0 bne B_E77E ; increment pointer inc R1 B_E77E rts S_E77F rts ;** Check for auto start removed P_E780 rts ; read IEEE port E_E781 nop nop nop nop ; isolate 'CLOCK IN' bit nop nop ; not set, then done nop nop nop ; isolate 'DATA IN' bit nop nop ; not set, then done nop nop nop ; load IEEE port nop nop nop ; test 'DATA IN' and 'CLOCK IN' nop nop ; wait until both set nop nop ; file name nop nop nop ; character in the input line nop nop nop ; '*' as filename nop nop ; write in buffer nop nop nop nop rts ;** & - USR file execute command [E7A3] USRexec lda #$8D jsr SearchInputBuf ; check command line to end jsr P_F258 ; RTS lda F2CNT ; number of file names pha ; save lda #$01 sta F2CNT ; file name lda #$FF sta R0 jsr Srch_File_Dir ; find file lda FILTRK bne B_E7C5 ; found? lda #$39 jsr OutputErrorMsg ; 39, 'file not found' B_E7C5 pla sta F2CNT ; get number of file names back lda FILTRK sta TRACK ; track lda FILSEC sta SECTOR ; and sector lda #$03 ; file type 'USR' jsr ReadXxxFile ; buffer allocated, read 1st block B_E7D8 lda #$00 sta R1 ; erase checksum jsr GetBytFromFil ; get byte from file sta R2 ; save as start address lo jsr GenChecksum ; from checksum jsr GetBytFromFil ; get byte from file sta R3 ; as start address hi jsr GenChecksum ; form checksum lda R0 beq B_E7FA lda R2 pha ; save program start address lda R3 pha lda #$00 sta R0 B_E7FA jsr GetBytFromFil ; get byte from file sta R4 ; save as counter jsr GenChecksum ; form checksum B_E802 jsr GetBytFromFil ; get byte from file ldy #$00 sta (R2),Y ; save as program bytes jsr GenChecksum ; form checksum lda R2 clc adc #$01 sta R2 ; increment $88/$89 bcc B_E817 inc R3 B_E817 dec R4 ; decrement pointer bne B_E802 jsr OpenChnGetByt ; get next byte lda DATA ; data byte cmp R1 ; equal to checksum? beq B_E82C ; yes, -> jsr GetSector2 ; transmit parameter to disk controller lda #$50 jsr CreErrorMsg ; 50, 'record not present' B_E82C lda EOIFLG ; end? bne B_E7D8 ; no, next data block pla sta R3 pla ; get program start address back sta R2 jmp (J_R2) ; and execute program ;** [E839] GetBytFromFil jsr OpenChnGetByt ; get byte from file lda EOIFLG ; end? bne B_E848 ; no, -> jsr GetSector2 ; transmit parameter to disk controller lda #$51 jsr CreErrorMsg ; 51, 'overflow in record' B_E848 lda DATA ; data byte rts ;** Generate checksum [E84B] GenChecksum clc adc R1 adc #$00 sta R1 rts ;** IRQ routine for serial bus P_E853 lda PortA1 ; read port A, erase IRQ flag lda #$01 sta ATNPND ; set flag for 'ATN received' rts ;** Service the serial bus [E85B] SerialBus sei lda #$00 sta ATNPND ; erase flag for 'ATN received' sta LSNACT ; erase flag for LISTEN sta TLKACT ; erase flag for TALK ldx #NewStack txs ; new stack pointer lda #$80 sta EOIFLG ; non-EOI state sta ATNMOD ; erase EOI flag jsr ClkOut_L ; CLK out (L) jsr DataOut_H ; DATA out (H) lda PortB1 ora #$10 ; switch data lines to input sta PortB1 ; DATA as input B_E87B lda PortB1 ; ATN active? bpl J_E8D7 ; no -> and #$04 ; CLOCK in? bne B_E87B ; no, wait -> B_E884 jsr GetByteFromBus ; read byte from bus1 cmp #$3F ; unlisten? bne B_E891 ; no -> lda #$00 sta LSNACT ; reset flag for LISTEN beq B_E902 ; always -> B_E891 cmp #$5F ; untalk? bne B_E89B ; no -> lda #$00 sta TLKACT ; reset flag for TALK beq B_E902 ; always -> B_E89B cmp TLKADR ; TALK-address? bne B_E8A9 ; no -> lda #$01 sta TLKACT ; set flag for TALK lda #$00 sta LSNACT ; reset flag for LISTEN beq B_E8D2 ; always -> B_E8A9 cmp LSNADR ; LISTEN-address? bne B_E8B7 ; no -> lda #$01 sta LSNACT ; set flag for LISTEN lda #$00 sta TLKACT ; reset flag for TALK beq B_E8D2 ; always -> B_E8B7 tax and #$60 cmp #$60 ; secondary address? bne B_E8FD ; no -> txa ; yes! sta ORGSA ; byte is secondary address and #$0F sta SA ; channel number lda ORGSA and #$F0 cmp #$E0 ; CLOSE? bne B_E902 ; no -> cli jsr Close ; CLOSE-routine sei B_E8D2 bit PortB1 ; ATN still active? bmi B_E884 ; yes, read next byte -> J_E8D7 lda #$00 ; no, end ATN mode sta ATNMOD ; set EOI lda PortB1 ; IEEE port and #$EF ; switch data lines to output sta PortB1 lda LSNACT ; LISTEN? beq B_E8ED ; no -> jsr ReceiveData ; receive data jmp WaitLoop1 ; to WaitLoop B_E8ED lda TLKACT ; TALK? beq B_E8FA ; no -> jsr DataOut_L ; free dataline jsr ClkOut_H ; CLOCK (L) jsr SendData ; send data B_E8FA jmp WaitLoop0 ; to WaitLoop B_E8FD lda #$10 ; nor Talk, neither LISTEN: ignore sta PortB1 ; kill all lines except ATN acknowledge B_E902 bit PortB1 ; ATN still present? bpl J_E8D7 ; no -> bmi B_E902 ; wait until gone -> ;** Send data [E909] SendData sei jsr OpenChan4Read ; open channel for read bcs B_E915 ; channel active J_E90F ldx CURCHN ; channel number lda REWRFLzp,X ; set READ flag? bmi B_E916 ; yes, -> B_E915 rts B_E916 jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit php ; and save jsr ClkOut_L ; CLOCK OUT lo plp beq B_E937 B_E925 jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit bne B_E925 ldx CURCHN ; channel number lda REWRFLzp,X ; status and #$08 ; check for EOI bne B_E94B ; no, -> B_E937 jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit bne B_E937 B_E941 jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit beq B_E941 B_E94B jsr ClkOut_H ; CLOCK OUT hi jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit bne B_E94B lda #$08 ; counter to 8 bits for serial sta CONT ; transmission B_E95C jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit bne B_E999 ldx CURCHN lda OUTREG,X ror A ; lowest data bit in carry sta OUTREG,X bcs B_E973 ; set bit jsr DataOut_H ; DATA OUT, output bit '0' bne B_E976 ; always -> B_E973 jsr DataOut_L ; DATA OUT, output bit '1' B_E976 jsr ClkOut_L ; set CLOCK OUT lda VIC20mode ; VIC-20 ? bne B_E980 ; yes, no slowdown needed, -> jsr DelayC64 ; delay for serial bus for C64 B_E980 jsr P_FEFB ; set DATA OUT and CLOCK OUT dec CONT ; all bits output? bne B_E95C ; no, -> B_E987 jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$01 ; isolate data bit beq B_E987 cli jsr NxtByteFile ; get next data byte sei jmp J_E90F ; and output B_E999 jmp WaitLoop0 ; to delay loop ;** DATA OUT lo [E99C] DataOut_L lda PortB1 and #$FD ; output bit '1' sta PortB1 rts ;** DATA OUT hi [E9A5] DataOut_H lda PortB1 ora #$02 ; output bit '0' sta PortB1 rts ;** CLOCK OUT hi [E9AE] ClkOut_H lda PortB1 ora #$08 ; set bit 3 sta PortB1 rts ;** CLOCK OUT lo ClkOut_L lda PortB1 and #$F7 ; erase bit 3 sta PortB1 rts ;** Read IEC port [E9C0] ReadIecPort lda PortB1 ; read port cmp PortB1 ; wait for constants bne ReadIecPort rts ;** Get data byte from bus [E9C9] GetByteFromBus lda #$08 sta CONT ; bit counter for serial output B_E9CD jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$04 ; CLOCK IN? bne B_E9CD ; no, wait jsr DataOut_L ; DATA OUT, bit '1' lda #$01 jmp PATCH2 ; set timer J_E9DF jsr Check4EOI ; check EOI lda IFR1 and #$40 ; timer run down? bne B_E9F2 ; yes, EOI jsr ReadIecPort ; read IEEE port and #$04 ; CLOCK IN? beq J_E9DF ; no, wait bne B_EA0B ;** Accept byte with EOI B_E9F2 jsr DataOut_H ; DATA OUT bit '0' hi ldx #$0A ; 10 B_E9F7 dex ; delay loop, approx 50 micro sec. bne B_E9F7 jsr DataOut_L ; DATA OUT, bit '1', lo B_E9FD jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE and #$04 ; CLOCK IN? beq B_E9FD ; no, wait lda #$00 sta EOIFLG ; set EOI flag B_EA0B lda PortB1 ; IEEE port eor #$01 ; invert data byte lsr A and #$02 bne B_EA0B ; CLOCK IN? nop nop nop ror DATA ; prepare next bit B_EA1A jsr Check4EOI ; check EOI jsr ReadIecPort ; read IEEE port and #$04 ; CLOCK IN? beq B_EA1A ; no, -> dec CONT ; decrement bit counter bne B_EA0B ; all bits output? jsr DataOut_H ; DATA OUT, bit '0', hi lda DATA ; load data byte again rts ;** Accept data from serial bus [EA2E] ReceiveData sei jsr OpenChan4Write ; open channel for writing bcs B_EA39 ; channel not active? lda REWRFLzp,X ; WRITE flag ror A bcs B_EA44 ; not set? B_EA39 lda ORGSA ; secondary address and #$F0 cmp #$F0 ; OPEN command? beq B_EA44 ; yes, -> jmp WaitLoop0 ; to wait loop B_EA44 jsr GetByteFromBus ; get data byte from bus cli jsr P_CFB7 ; and write in buffer jmp ReceiveData ; to loop beginning ;** [EA4E] WaitLoop0 lda #$00 sta PortB1 ; reset IEEE port jmp WaitLoop1 ; to wait loop S_EA56 jmp SerialBus ;** Test for EOI [EA59] Check4EOI lda ATNMOD ; EOI received? beq B_EA63 ; yes, -> lda PortB1 ; IEEE port bpl B_EA6B B_EA62 rts B_EA63 lda PortB1 ; IEC port bpl B_EA62 jmp SerialBus ; to serial bus main loop B_EA6B jmp J_E8D7 ; set EOI, serial bus ;** Flash LED for hardware defects, self-test [EA6E] ; if X=$FD, then continue flashing BlinkOnce ldx #$00 ; blink once for ZeroPage .by $2C ; dummy BIT opcode BlinkX ldx TEMP0 ; blink X+1 times for RAM/ROM err txs ; use Stackreg. as extra register L_EA74 tsx L_EA75 lda #$08 ; LED on ora PortB2 jmp PATCH3 ; [FEEA] J_EA7D tya ; delay L_EA7E clc L_EA7F adc #$01 bne L_EA7F dey bne L_EA7E lda PortB2 and #$F7 ; turn LED off sta PortB2 ; LED off L_EA8E tya ; delay L_EA8F clc L_EA90 adc #$01 bne L_EA90 ; delay loop dey bne L_EA8F dex ; all flashes? bpl L_EA75 ; no, -> cpx #$FC bne L_EA8E ; no, extra pause beq L_EA74 ; always, -> start again flashing ;** RESET routine [EAA0] RESET sei cld ldx #$FF jmp PATCH1 ; port A to output ;** Test ZP-RAM L_EAA7 inx ; Why ???, see R_EAAA ldy #$00 R_EAAA ldx #$00 ;** Fill ZP with ascending pattern L_EAAC txa ; Store 1, 2, 3 etc. sta JOBSZP,X ; .... on address 1, 2, 3 etc. inx bne L_EAAC L_EAB2 txa cmp JOBSZP,X ; check contents bne BlinkOnce ; no, then to error display (blink) L_EAB7 inc JOBSZP,X ; loop to add 256 iny bne L_EAB7 cmp JOBSZP,X ; result must be the same bne BlinkOnce ; error sty JOBSZP,X ; Y=0 lda JOBSZP,X ; A=0 ? bne BlinkOnce ; no, error -> inx bne L_EAB2 ;** Test both ROMs L_EAC9 inc TEMP0 ; number of LED-flashes stx IP+1 ; HB lda #$00 sta IP ; IP=0 tay ; &&&00 Skip ROM test for the moment ;-- ldx #$20 ; 8 KByte ;-- clc jmp CheckRAM ; &&& L_EAD5 dec IP+1 ; next page L_EAD7 adc (IP),Y ; add byte iny bne L_EAD7 dex ; all 8 KB bne L_EAD5 ; no -> adc #$00 ; add Carry tax cmp IP+1 ; A=$E0/C0 ? bne L_EB1F ; no, error -> cpx #$C0 ; $C000-$DFFF checked? bne L_EAC9 ; no, next 8 KB ;** Check RAM CheckRAM lda #$01 sta IP+1 ; start with page 1 inc TEMP0 ldx #$07 ; 7 pages L_EAF2 tya clc adc IP+1 sta (IP),Y iny bne L_EAF2 inc IP+1 dex ; next page bne L_EAF2 ldx #$07 ; 7 pages L_EB02 dec IP+1 L_EB04 dey tya clc adc IP+1 cmp (IP),Y bne L_EB1F ; RAM-error -> eor #$FF sta (IP),Y eor (IP),Y sta (IP),Y bne L_EB1F ; RAM-error -> tya bne L_EB04 ; next byte dex bne L_EB02 ; next page beq InitStack ; always -> L_EB1F jmp BlinkX ; to error display ;** Initialize stackpointer [EB22] InitStack jmp InitIDE ; &&&02 ;-- ldx #NewStack ; initialize stackpointer ;-- txs ; initialize stack pointer InitStack2 lda PortB2 ; de-activate LED and #$F7 ; turn LED off sta PortB2 lda #$01 ; trigger CA1 (ATN IN) sta PCR1 ; on positive edge lda #$82 ; enable interrupt via ATN IN sta IFR1 ; interrupt possible through ATN IN sta IER1 ;** Read device number out of bit 5/6 of Port B1 lda PortB1 ; read port B and #$60 ; isolate bits 5 & 6 (device number) asl rol rol ; rotate to bit positions 0 & 1 rol ora #$48 ; dev. number for talk sta TLKADR ; device number for TALK (send) eor #$60 ; dev. number for listen sta LSNADR ; device number + $20 for LISTEN ;** Initialize pointers to buffers 0..4 ldx #$00 ldy #$00 L_EB4F lda #$00 sta BUFTABzp,X ; Low Byte = 0 inx lda BufferAddress,Y ; Load HB from tabel sta BUFTABzp,X ; save inx iny cpy #$05 bne L_EB4F ;** Let $A3/$A4 point to $0200 lda #<(CMDBUF) sta BUFTABzp,X inx ; pointer $A3/$A4 to $200, input buffer lda #>(CMDBUF) sta BUFTABzp,X inx ;** Buffer errormessage ERRBUF in $A5/$A6 lda #<(ERRBUF) sta BUFTABzp,X inx ; pointer $A5/$A6 to $2D5, error lda #>(ERRBUF) ; message pointer sta BUFTABzp,X ;** Fill channel table with $FF (= not used) lda #$FF ldx #$12 L_EB76 sta LINTAB,X ; fill channel table with $FF dex bpl L_EB76 ldx #$05 L_EB7E sta BUF0CH1zp,X ; erase buffer tables sta BUF1CH1zp,X sta SIDSECzp,X ; erase side-sector table dex bpl L_EB7E lda #$05 ; buffer 5 sta BUF0CH5 ; for channel 4 lda #$06 ; buffer 6 sta BUF0CH6 ; for channel 5 lda #$FF sta BUF0CH7 sta BUF1CH7 lda #$05 sta CH5WFL ; reset WRITE-flag channel 5 lda #$84 sta CH4WFL ; set WRITE-flag channel 4 lda #$0F ; initialize channel allocation register sta LINUSE ; mark all channels as free lda #$01 sta WRFLAG ; WRITE flag lda #$88 sta RDFLAG ; READ flag lda #$E0 ; 5 buffers free sta BUFUSEL ; 5 buffers free (bit = 0) lda #$FF ; $24F/$250, 16 bit sta BUFUSEH lda #$01 ; disk has changed sta WPSW0 sta WPSW1 jsr SetVectorU0 ; set vector for U0 jsr InitLastTable ; initialize channel table jsr InitDiskCntrlr ; initialize disk-controler ;** Initialize NMI-vector lda #<(InitStack) sta VNMI lda #>(InitStack) ; pointer $65/$66 to $EB22 sta VNMI+1 lda #$0A sta SECINC ; interleave 10 lda #$05 ; for sector assignment sta REVCNT ; try 5 times to read lda #$73 ; initialize error message jsr OK2Buffer2 ; 73, 'cbm dos v2.6 1541' lda #$00 sta PortB1 lda #$1A ; bit 1, 3 & 4 to output sta DDRB1 jsr P_E780 ; check for autostart ;** [EBE7] WaitLoop1 cli lda PortB1 and #$E5 ; reset serial port sta PortB1 lda CMDWAT ; command flag? beq WaitLoop2 ; no, -> lda #$00 ; reset command flag sta CMDWAT ; reset command flag sta NMIFLG jsr InterprCmnd ; analyse and execute instruction ;** Wait loop WaitLoop2 cli lda ATNPND ; ATN pending? beq L_EC07 ; no, -> jmp SerialBus ; to IEEE routine L_EC07 cli lda #$0E ; 14 sta TEMP3 ; secundair address lda #$00 sta TEMP0 ; job counter sta TEMP1 L_EC12 ldx TEMP3 lda LINTAB,X ; secondary address cmp #$FF ; channel added ? beq L_EC2B ; no -> and #$3F sta CURCHN ; channel number jsr GetBufNumber ; get buffer # tax lda LSTJOB,X ; get drive # and #$01 tax inc TEMP0,X ; increment job counter L_EC2B dec TEMP3 ; decrement secundair address bpl L_EC12 ; >= 0, -> ldy #$04 ; buffer counter L_EC31 lda JOBS,Y ; does disk controler work? bpl L_EC3B ; no, -> and #$01 ; isolate drive # tax inc TEMP0,X ; incr. job counter L_EC3B dey ; next buffer? bpl L_EC31 ; yes, -> sei lda PortB2 and #$F7 ; LED bit off pha lda DRVNMB ; save drive # sta R0 lda #$00 sta DRVNMB ; drive 0 lda TEMP0 ; job for drive 0? beq L_EC5C ; no, -> lda WPSW0 ; disk change for drive 0? beq L_EC58 ; no, -> jsr ClsChanOthDrv ; close all channels to drive 0 L_EC58 pla ora #$08 ; LED bit on pha L_EC5C inc DRVNMB ; drive 1 lda TEMP1 ; job for drive 1? beq L_EC6D ; no -> lda WPSW1 ; disk change for drive 1? beq L_EC69 ; no -> jsr ClsChanOthDrv ; close all channels to drive 1 L_EC69 pla ora #$00 ; LED drive 1 on (does not exist) pha L_EC6D lda R0 ; restore drive # sta DRVNMB ; get drive number back pla ; bit for LED ldx ERWORD ; IRQ-counter for blinking LED beq L_EC98 ; no blinking, -> lda PortB2 cpx #$80 ; old error? bne L_EC81 ; yes, -> jmp L_EC8B ; no, new error -> L_EC81 ldx T1CH1 ; still timing? bmi L_EC98 ; yes -> ldx #$A0 ; no, new 8 msec cycle stx T1CH1 ; set timer L_EC8B dec ERWORD ; time is up? bne L_EC98 ; no -> eor ERLED ; toggle LED ldx #$10 stx ERWORD ; reset counter L_EC98 sta PortB2 ; LED on/off jmp WaitLoop2 ; start loop all over again ;** Load dir [EC9E] P_EC9E lda #$00 sta SA ; secondary address 0 lda #$01 jsr FindRdChanBuf ; find channel and buffer lda #$00 jsr SetBufPointer3 ; initialize buffer pointer ldx CURCHN ; channel number lda #$00 sta ENDPNT,X ; pointer to end = zero jsr GetBufNumber ; get buffer number tax lda DRVNMB ; drive number sta LSTJOB,X ; bring in table ; write start address $0401 in buffer lda #$01 jsr Write2Buf lda #$04 jsr Write2Buf lda #$01 ; 2 times 1 jsr Write2Buf jsr Write2Buf ; write in buffer as link address lda NBTEMP0 ; drive number jsr Write2Buf ; write in buffer as line number lda #$00 ; line number hi jsr Write2Buf ; in buffer jsr DirLine2Buf ; directory entry in buffer jsr GetBufNumber ; get buffer number asl A tax dec BUFTABzp,X ; decrement buffer pointer dec BUFTABzp,X lda #$00 jsr Write2Buf ; 0 as line end in buffer P_ECEA lda #$01 jsr Write2Buf ; 2 times 1 as link address jsr Write2Buf jsr GetDirEntry ; directory entry in buffer bcc B_ED23 ; another entry? lda NBTEMP0 ; block number lo jsr Write2Buf ; in buffer lda NBTEMP1 ; block number hi jsr Write2Buf ; in buffer jsr DirLine2Buf ; directory entry in buffer lda #$00 ; zero as end marker in buffer jsr Write2Buf ; buffer full? bne P_ECEA ; no, -> J_ED0D jsr GetBufNumber ; get buffer number asl A tax lda #$00 sta BUFTABzp,X ; buffer pointer to zero lda #$88 ; set READ flag ldy CURCHN ; channel number sta DIRLST sta REWRFLab,Y ; flag for channel lda DATA ; data byte rts B_ED23 lda NBTEMP0 ; block number lo jsr Write2Buf ; write in buffer lda NBTEMP1 ; block number hi jsr Write2Buf ; in buffer jsr DirLine2Buf ; 'blocks free.' in buffer jsr GetBufNumber ; get buffer number asl A tax dec BUFTABzp,X dec BUFTABzp,X ; buffer pointer minus 2 lda #$00 jsr Write2Buf jsr Write2Buf jsr Write2Buf ; three zeroes as program end jsr GetBufNumber ; get buffer number asl A ; times 2 tay lda BUFTABab,Y ; buffer pointer ldx CURCHN sta ENDPNT,X ; as end marker dec ENDPNT,X jmp J_ED0D ;** Write dir line into buffer DirLine2Buf ldy #$00 B_ED5B lda NameBuffer,Y ; character from buffer jsr Write2Buf ; write in output buffer iny cpy #$1B ; 27 characters? bne B_ED5B rts ;** Get byte from buffer P_ED67 jsr GetByteFromBuf ; get byte beq B_ED6D ; buffer pointer zero? rts B_ED6D sta DATA ; save data byte ldy CURCHN ; channel number lda ENDPNT,Y ; set end marker beq B_ED7E ; zero (LOAD $)? lda #$80 sta REWRFLab,Y ; set READ flag lda DATA ; data byte rts B_ED7E pha jsr P_ECEA ; create directory line in buffer pla rts ;** V - Validate command [ED84] Validate jsr ChkInputLine ; find drive number in input line jsr LoadBAM ; load BAM lda #$40 sta WBAM jsr CreateBam ; create new BAM in buffer lda #$00 sta DELIND jsr Rd_1st_Dir_Blk ; load directory, find 1st flag bne B_EDD9 ; found? B_ED9C lda #$00 sta SECTOR ; sector 0 lda DirTrack ; 18 sta TRACK ; track 18 for BAM jsr AllocateFile ; mark directory blocks as allocated lda #$00 sta WBAM jsr WriteBam2 ; write BAM back to disk [EEFF] jmp Out_Err_Msg ; done, prepare disk status B_EDB3 iny lda (DIRBUF),Y ; save track pha iny lda (DIRBUF),Y ; and sector pha ldy #$13 ; pointer to side-sector block lda (DIRBUF),Y beq B_EDCB ; no track following? sta TRACK ; track and iny lda (DIRBUF),Y sta SECTOR ; sector of 1st side-sector block jsr AllocateFile ; mark side-sector block as B_EDCB pla ; allocated sta SECTOR pla ; get track and sector back sta TRACK jsr AllocateFile ; mark blocks of file as allocated J_EDD4 jsr Rd_Nxt_Dir_Blk ; read next entry in directory beq B_ED9C ; end of directory? B_EDD9 ldy #$00 lda (DIRBUF),Y ; file type bmi B_EDB3 ; bit 7 set, file closed? jsr DelDirEntry ; file type to zero and write BAM jmp J_EDD4 ;** Allocate file blocks in BAM [EDE5] AllocateFile jsr ChkTraSec3 ; check track and sector number jsr AllocSector ; allocate block in BAM jsr ReadSeqFile ; read next block J_EDEE lda #$00 jsr SetBufPointer3 ; buffer pointer zero jsr GetByteFromBuf ; get byte from buffer sta TRACK ; track jsr GetByteFromBuf ; get byte from buffer sta SECTOR ; sector lda TRACK ; another block? bne B_EE04 ; yes, -> jmp CloseChannel ; close channel B_EE04 jsr AllocSector ; allocate block in BAM jsr RdNxtBlock ; read next block jmp J_EDEE ; continue ;** N - New (Format) command [EE0D] New jsr GetDrvNum ; get drive number lda DRVNUM ; drive number OK? bpl B_EE19 ; yes, -> lda #$33 jmp OutputErrorMsg ; 33, 'syntax error' B_EE19 and #$01 sta DRVNMB ; drive number jsr LedOn ; turn LED on lda DRVNMB ; drive number asl ; times 2 tax ldy FILTBL+1 ; comma position cpy CMDSIZ ; compare with end name beq B_EE46 ; format without ID lda CMDBUF,Y ; first character of ID sta DISKIDzp ; save lda CMDBUF+1,Y ; second character sta IMDIIDzp jsr CloseAllChan ; close all channels [D307] lda #$01 sta TRACK ; track 1 jsr FormatFloppy ; format disk ;@@10 jsr EraseBamBuf ; erase buffer [F005] jmp J_EE56 ; continue as below B_EE46 jsr LoadBAM ; load BAM ldx DRVNMB ; drive number lda A_0101,X cmp A_FED5 ; 'A', marker for 1541 format beq J_EE56 ; ok jmp B_D572 ; 73, 'cbm dos v2.6 1541' J_EE56 jsr CreateBam ; create BAM lda JOBNUM ; buffer number tay asl A tax lda LengthBAM ; $90, start of disk name sta BUFTABzp,X ; buffer pointer to name ldx FILTBL lda #$1B ; 27 jsr NamFil2DirBuf ; write filenames in buffer ldy #$12 ; position 18 ldx DRVNMB ; drive number lda A_FED5 ; 'A', 1541 format sta A_0101,X txa asl A ; times 2 tax lda #'R' ; lda DISKIDzp,X ; ID, first character sta (DIRBUF),Y ; in buffer iny lda #'B' ; lda IMDIIDzp,X ; and second character sta (DIRBUF),Y ; in buffer iny iny lda #'2' sta (DIRBUF),Y ; in buffer iny lda A_FED5 ; 'A' 1541 format sta (DIRBUF),Y ; in buffer ldy #$02 sta (BMPNT),Y ; and at position 2 lda DirTrack ; 18 sta TRACK ; track number jsr AllocSector2 ; mark block as allocated lda #$01 ; 1 sta SECTOR ; sector number jsr AllocSector2 ; mark block as allocated jsr WriteBam2 ; write BAM [EEFF] jsr EraseBamBuf ; [F005] ldy #$01 lda #$FF sta (BMPNT),Y ; all 256 bytes of this sector used jsr WriteSector ; write BAM dec SECTOR ; decrement sector number, 0 jsr ReadSector ; read block jmp Out_Err_Msg ; prepare disk status ;** Create BAM CreateBam jsr ClearTBAM ldy #$00 lda #$12 ; 18 sta (BMPNT),Y ; pointer to directory track iny tya ; 1 sta (BMPNT),Y ; pointer to directory sector iny iny iny B_EEC7 lda #$00 sta TEMP0 sta TEMP1 ; 3 bytes = 24 bits for sectors sta TEMP2 tya ; byte position lsr A lsr A ; divided by 4 = track number jsr MaxSectors ; get number of sectors sta (BMPNT),Y ; and in BAM iny tax B_EED9 sec rol TEMP0 rol TEMP1 ; create bit model rol TEMP2 dex bne B_EED9 B_EEE3 lda TEMP0,X ; 3 bytes sta (BMPNT),Y ; the BAM in buffer iny inx cpx #$03 bcc B_EEE3 cpy #$90 ; position 144? bcc B_EEC7 ; no, next track jmp J_D075 ; calculate number of free blocks ;** Write BAM if needed [EEF4] WriteBam jsr GetBufNumber ; get buffer number tax lda LSTJOB,X ; command for disk controller and #$01 sta DRVNMB ; isolate drive number ; [EEFF] WriteBam2 ldy DRVNMB lda MDIRTY,Y ; BAM-changed flag set? bne B_EF07 ; yes, -> rts B_EF07 lda #$00 sta MDIRTY,Y ; reset BAM-changed flag jsr SetBufPtrBAM ; set buffer pointer for BAM lda DRVNMB ; drive number asl A ; times 2 pha jsr VerifyBamEntry ; verify BAM entry pla clc adc #$01 ; increment drive number jsr VerifyBamEntry ; verify BAM entry lda TRACK ; track pha lda #$01 ; track 1 sta TRACK B_EF24 asl A ; times 4 asl A sta BMPNT ; bytes/track jsr P_F220 ; verify BAM inc TRACK ; increment track number lda TRACK cmp A_FED7 ; and compare with max val + 1 = 36 bcc B_EF24 ; ok, next track pla sta TRACK ; get track number back jmp DskWriteBlock ; write BAM to disk ;** Set buffer pointer for BAM [EF3A] ;@@12 SetBufPtrBAM jsr GetBufNumBAM2 ; get 13 for drive 0 tax ;@@14 jsr ReadBAM ; allocate buffer ldx JOBNUM ; buffer number lda BufferAddress,X ; buffer address, hi byte sta BMPNT+1 lda #$00 ; lo byte sta BMPNT ; pointer to $6D/$6E rts ;** Get number of free blocks for dir [EF4D] NumBlocksFree ldx DRVNMB ; drive number lda NDBL,X ; number of blocks, lo sta NBTEMP0 lda NDBH,X ; number of blocks, hi sta NBTEMP1 ; in buffer for directory rts S_EF5C jsr P_EFF1 ; set buffer pointer ;** Mark block as free [EF5F] FreeSector jsr GetBitBAM ; get state of bit for sector in BAM sec bne B_EF87 ; block already free, then done lda (BMPNT),Y ; bit model of BAM ora PowersOf2,X ; set bit X, marker for free sta (BMPNT),Y jsr P_EF88 ; set flag for BAM changed ldy TEMP0 clc lda (BMPNT),Y adc #$01 ; increment number of free blocks/track sta (BMPNT),Y lda TRACK ; track cmp DirTrack ; equal to 18? beq B_EFBA ; then skip inc NDBL,X ; increment number of free blocks in ; disk bne B_EF87 inc NDBH,X ; increment number of blocks hi B_EF87 rts ;** Set flag for BAM changed P_EF88 ldx DRVNMB ; drive number lda #$01 sta MDIRTY,X ; flag = 1 rts ;** Mark block as allocated [EF90] AllocSector jsr P_EFF1 ; set buffer pointer AllocSector2 jsr GetBitBAM ; erase bit for sector in BAM beq B_EFCE ; already allocated, then done lda (BMPNT),Y eor PowersOf2,X ; erase bit for block sta (BMPNT),Y jsr P_EF88 ; set flag for BAM changed ldy TEMP0 lda (BMPNT),Y sec sbc #$01 ; decrement number of blocks per track sta (BMPNT),Y lda TRACK ; track cmp DirTrack ; 18? beq B_EFBD lda NDBL,X ; number of free blocks lo bne B_EFBA dec NDBH,X ; decrement number of free blocks B_EFBA dec NDBL,X B_EFBD lda NDBH,X ; number of free blocks hi bne B_EFCE ; more than 255 blocks free? lda NDBL,X ; free blocks lo cmp #$03 bcs B_EFCE ; smaller than 3? lda #$72 jsr Errmsg2buf ; 72, 'disk full' B_EFCE rts ;** Get state of bit for sector in BAM entry [EFCF] GetBitBAM jsr P_F011 ; find BAM field for this track tya sta TEMP0 P_EFD5 lda SECTOR ; sector lsr A lsr A ; divide by 8 lsr A sec adc TEMP0 tay ; byte number in BAM entry lda SECTOR ; sector number and #$07 tax ; bit number in BAM entry lda (BMPNT),Y ; byte in BAM and PowersOf2,X ; get state rts ;** Powers of 2 [EFE9] PowersOf2 .by $01, $02, $04, $08, $10, $20, $40, $80 ;** Write BAM after change [EFF1] P_EFF1 lda #$FF bit WBAM beq B_F004 bpl B_F004 bvs B_F004 lda #$00 sta WBAM ; reset flag jmp DskWriteBlock ; write block B_F004 rts ;** Erase BAM buffer [F005] ;@@11 EraseBamBuf jsr SetBufPtrBAM ; pointer $6D/$6E to BAM buffer ldy #$00 tya B_F00B sta (BMPNT),Y ; erase BAM buffer iny bne B_F00B rts P_F011 lda TEMP0 pha lda TEMP1 pha ldx DRVNMB ; drive number lda $FF,X beq B_F022 ; drive zero? lda #$74 jsr CreErrorMsg2 ; 'drive not ready' B_F022 jsr GetBufNumBAM2 ; drive 0: A=13, drive 1: A=6 sta TEMP0 ; channel txa ; drive number, most probably 0 asl A sta TEMP1 tax lda TRACK ; track cmp TBAM,X beq B_F03E inx ; altenative channel stx TEMP1 cmp TBAM,X beq B_F03E jsr P_F05B B_F03E lda TEMP1 ldx DRVNMB ; drive number sta UBAM,X asl A asl A ; times 4 clc adc #<(BAMima) sta BMPNT lda #>(BAMima) adc #$00 sta BMPNT+1 ldy #$00 pla sta TEMP1 pla sta TEMP0 rts P_F05B ldx TEMP0 ; channel = 13 jsr ReadBAM lda DRVNMB ; drive number tax asl A ora UBAM,X eor #$01 and #$03 sta TEMP1 jsr VerifyBamEntry lda JOBNUM ; buffer number asl A tax lda TRACK ; track asl A asl A ; times 4 sta BUFTABzp,X ; equal pointer in BAM field lda TEMP1 asl A asl A tay B_F07F lda (BUFTABzp,X) sta BAMima,Y lda #$00 sta (BUFTABzp,X) ; zero in buffer inc BUFTABzp,X ; increment buffer pointer iny tya and #$03 bne B_F07F ldx TEMP1 lda TRACK ; track sta TBAM,X lda WBAM bne B_F09F jmp DskWriteBlock ; write block B_F09F ora #$80 sta WBAM rts ;** Verify the BAM entry [F0A5] VerifyBamEntry tay lda TBAM,Y ; BAM in memory? beq B_F0D0 ; no, -> pha ; save track lda #$00 ; ???? sta TBAM,Y lda JOBNUM ; buffer number asl A ; times 2 tax pla ; restore track asl A asl A ; * 4 sta BUFTABzp,X tya ; drive asl A asl A ; * 4 (why ???) tay B_F0BE lda BAMima,Y sta (BUFTABzp,X) ; write in buffer lda #$00 sta BAMima,Y inc BUFTABzp,X ; increment buffer pointer iny tya and #$03 bne B_F0BE B_F0D0 rts ;** Clear the variable TBAM (+1) [F0D1] ClearTBAM lda DRVNMB ; drive number asl A tax lda #$00 sta TBAM,X inx sta TBAM,X rts ;** Read BAM into page 7 if not loaded yet [F0DF] ;@@15 ReadBAM lda BUF0CH1zp,X cmp #$FF ; BAM loaded? bne B_F10A ; yes, -> txa pha ;@@16 jsr GetBuffer tax bpl B_F0F2 lda #$70 jsr OutputErrorMsg ; 70, 'no channel' B_F0F2 stx JOBNUM pla tay txa ora #$80 sta BUF0CH1ab,Y asl A tax lda DirTrack ; 18, directory track sta TRASECzp,X ; save lda #$00 ; 0 sta TRASECzp+1,X ; as sector jmp DskReadBlock ; read block B_F10A and #$0F sta JOBNUM ; buffer number rts ;** Get buffer number for BAM [F10F] ;@@13 GetBufNumBAM2 lda #$06 ; Drive 1 -> 6 ldx DRVNMB ; drive number bne B_F118 clc adc #$07 ; Drive 0 -> 13 B_F118 rts ;** Get buffer number for BAM [F119] GetBufNumBAM jsr GetBufNumBAM2 ; get buffer number tax rts ;** Find and allocate free block [F11E] P_F11E jsr GetSector2 ; get track and sector number lda #$03 sta TEMP0 ; counter lda #$01 ora WBAM sta WBAM P_F12D lda TEMP0 ; save counter pha jsr P_F011 ; find BAM field for this track pla sta TEMP0 ; get counter back lda (BMPNT),Y ; number of free blocks in track bne B_F173 ; blocks still free? lda TRACK ; track cmp DirTrack ; 18, directory track? beq B_F15A ; yes, 'disk full' bcc B_F15F ; smaller, then next lower track inc TRACK ; increment track number lda TRACK cmp A_FED7 ; 36, highest track number plus one bne P_F12D ; no, continue searching this track ldx DirTrack ; 18, directory track dex ; decrement stx TRACK ; save as track number lda #$00 sta SECTOR ; begin with sector number zero dec TEMP0 ; decrement counter bne P_F12D ; not yet zero, then continue B_F15A lda #$72 jsr OutputErrorMsg ; 72, 'disk full' B_F15F dec TRACK ; decrement track number bne P_F12D ; not yet 0, continue in this track ldx DirTrack ; 18, directory track inx ; increment stx TRACK ; save as track number lda #$00 sta SECTOR ; begin with sector zero dec TEMP0 ; decrement counter bne P_F12D ; not yet zero, then continue beq B_F15A ; else 'disk full' B_F173 lda SECTOR ; sector number clc adc SECINC ; plus step width (10) sta SECTOR ; as new number lda TRACK ; track number jsr MaxSectors ; get maximum sector number sta BSTSEC sta CMD ; and save cmp SECTOR ; greater than selected sector number? bcs B_F195 ; yes, -> sec ; else lda SECTOR ; sector number sbc BSTSEC ; minus maximum sector number sta SECTOR ; save as new sector number beq B_F195 ; zero? dec SECTOR ; else decrement sector number by one B_F195 jsr P_F1FA ; check BAM, find free sector beq B_F19D ; not found? B_F19A jmp AllocSector ; allocate block in BAM B_F19D lda #$00 sta SECTOR ; sector zero jsr P_F1FA ; find free sector bne B_F19A ; found? jmp J_F1F5 ; no, 'dir sector' ;** Find free sector and allocate [F1A9] FreeSecAlloc lda #$01 ora WBAM sta WBAM ; don't write to the BAM lda R0 pha lda #$01 ; track counter sta R0 B_F1B8 lda DirTrack ; 18, directory track sec sbc R0 ; minus counter sta TRACK ; save as track number bcc B_F1CB ; result <= zero? beq B_F1CB ; then try top half of directory jsr P_F011 ; find BAM field for this track lda (BMPNT),Y ; number of free blocks in this track bne B_F1E6 ; free blocks exist B_F1CB lda DirTrack ; 18, directory track clc adc R0 ; plus counter sta TRACK ; save as track number inc R0 ; increment counter cmp A_FED7 ; 36, max track number plus one bcc B_F1DF ; smaller, then ok lda #$67 jsr CreErrorMsg ; 67, 'illegal track or sector' B_F1DF jsr P_F011 ; find BAM field for this track lda (BMPNT),Y ; number of free blocks? beq B_F1B8 ; no more free blocks? B_F1E6 pla sta R0 lda #$00 sta SECTOR ; sector 0 jsr P_F1FA ; find free sector beq J_F1F5 ; not found? jmp AllocSector ; allocate block in BAM J_F1F5 lda #$71 jsr CreErrorMsg ; 71, 'dir error' ;** Find free sectors in current track [F1FA] P_F1FA jsr P_F011 ; find BAM field for this track tya ; point to number of free blocks pha jsr P_F220 ; verify BAM lda TRACK ; track jsr MaxSectors ; get max number of sectors of the track sta BSTSEC ; save pla sta TEMP0 ; save pointer B_F20D lda SECTOR ; compare sector cmp BSTSEC ; with maximum number bcs B_F21D ; greater than or equal to? jsr P_EFD5 ; get bit number of sector bne B_F21F ; sector free? inc SECTOR ; increment sector number bne B_F20D ; and check if free B_F21D lda #$00 ; no sectors free B_F21F rts ;** Verify number of free blocks in BAM P_F220 lda TEMP0 pha lda #$00 sta TEMP0 ; counter to zero ldy DirTrack+1 ; 4, number of bytes per track in BAM dey B_F22B ldx #$07 B_F22D lda (BMPNT),Y and PowersOf2,X ; isolate bit beq B_F236 inc TEMP0 ; increment counter of free sectors B_F236 dex bpl B_F22D dey bne B_F22B lda (BMPNT),Y ; compare with number on diskette cmp TEMP0 bne B_F246 ; not equal, then error pla sta TEMP0 rts B_F246 lda #$71 jsr CreErrorMsg ; 71, 'dir error' ; Although it is a JSR, the routine resets the stack pointer and ends up ; in WaitLoop1. ;** Establish number of sectors per track [F24B] MaxSectors ldx A_FED6 ; 4 different values B_F24E cmp A_FED6,X ; track number dex bcs B_F24E ; not greater? lda A_FED1,X ; get number of sectors rts P_F258 rts ;** Initialize disk controller [F259] InitDiskCntrlr lda #$6F ; bit 4 (write protect) and 7 (SYNC) sta DDRB2 ; as input and #$F0 sta PortB2 ; port B, control port lda PCR2 ; PCR, control register and #$FE ora #$0E ora #$E0 sta PCR2 lda #$41 ; neg. edge latch, CA2 (H), sta ACR2 ; CB1 input, CB2 = R/W control lda #$00 ; 20 msec between IRQs sta T1LL2 ; timer 1 lo latch lda #$3A sta T1LH2 ; timer 1 hi latch sta T1CH2 ; timer 1 hi lda #$7F sta IER2 ; clear IRQs lda #$C0 ; only timer 1 sta IFR2 sta IER2 ; enable IRQs lda #$FF sta CURDRV sta FTNUM ; track counter for formatting lda #$08 ; 8 sta HBID ; constants for block header lda #$07 ; 7 sta DBID ; constants for data block lda #<(StepHead) sta NXTSTzp lda #>(StepHead) ; pointer $62/$63 to $FA05 sta NXTSTzp+1 lda #$C8 ; 200 sta MINSTP lda #$04 sta AS lda #$04 sta AF ;** IRQ routine for disk controller [F2B0] IRQdiskCntrllr tsx stx SAVSP ; save stackpointer lda T1CL2 ; erase flag of timer lda PCR2 and #$FD sta PCR2 ; disable "Byte Ready" / SO J_F2BE ldy #$05 B_F2C0 lda JOBS,Y ; command for buffer Y bpl B_F2F3 ; no, -> cmp #$D0 ; execute PRG in buffer? bne B_F2CD ; no, -> tya jmp ExecBufPRG_2 ; execute program in buffer B_F2CD and #$01 ; isolate drive number beq B_F2D8 ; drive zero? yes, -> sty JOBN lda #$0F jmp P_F969 ; 74, 'drive not ready' B_F2D8 tax sta DRIVE cmp CURDRV ; motor running? beq B_F2E9 ; yes, -> jsr MotorOn ; turn drive motor on lda DRIVE sta CURDRV ; set flag jmp LoopDiskCntrl ; to job loop B_F2E9 lda DRVST ; ?? where initialised ?? bmi B_F2F0 asl A ; head transport programmed? bpl B_F2F9 ; yes, -> B_F2F0 jmp LoopDiskCntrl ; to job loop B_F2F3 dey bpl B_F2C0 ; check next buffer jmp LoopDiskCntrl ; to job loop ;** Head transport B_F2F9 lda #$20 sta DRVST ; program motor on ldy #$05 sty JOBN B_F301 jsr InitPntr2Buf ; set pointer in buffer bmi B_F320 ; command for buffer? J_F306 dec JOBN ; decrement counter bpl B_F301 ; check next buffer ldy NXTJOB ; buffer number jsr InitPntr2Buf2 ; set pointer in buffer lda NXTTRK ; track difference for last job sta STEPS ; as counter for head transport asl STEPS lda #$60 ; set flag for head transport sta DRVST lda (HDRPNT),Y ; get track number from buffer sta DRVTRK jmp LoopDiskCntrl ; to job loop B_F320 and #$01 ; isolate drive number cmp DRIVE ; equal drive number of last job? bne J_F306 ; no, -> lda DRVTRK ; last track number beq B_F33C ; equal zero? sec sbc (HDRPNT),Y ; equal track number of this job? beq B_F33C ; yes, -> eor #$FF sta NXTTRK inc NXTTRK lda JOBN sta NXTJOB jmp J_F306 B_F33C ldx #$04 lda (HDRPNT),Y ; track number of the job sta TRACC ; save B_F342 cmp A_FED6,X ; compare with maximum track number dex bcs B_F342 ; greater? lda A_FED1,X ; get number of sectors per track sta SECCNT ; and save ;** Create value for density for PB5/PB6 txa asl A asl A asl A asl A asl A sta WORK ; gives 0, 32, 64, 96 lda PortB2 and #$9F ora WORK ; generate control byte for motor sta PortB2 ldx DRIVE lda JOB ; command code cmp #$40 ; position head? beq B_F37C ; yes, -> cmp #$60 ; command code for program execution? beq ExecBufPRG ; yes, -> jmp ReadHeader ; read block header ;** Execute program in buffer [F36E] ExecBufPRG lda JOBN ExecBufPRG_2 clc adc #$03 ; plus 3 sta BUFPNT+1 lda #$00 ; equals address of buffer sta BUFPNT jmp (J_BUFPNT) ; execute program in buffer ;** Bump, find track 1 (head at stop) B_F37C lda #$60 sta DRVST ; set flag for head transport lda PortB2 ora #3 ; --turn stepper motors off for sute sta PortB2 lda #$A4 ; -45 sta STEPS ; step counter for head transport lda #$01 sta DRVTRK ; track number jmp P_F969 ; ok ;** Initialize pointer in buffer [F393] InitPntr2Buf ldy JOBN InitPntr2Buf2 lda JOBS,Y ; command code pha ; save bpl B_F3AB and #$78 ; erase bits 0,1,2, and 7 sta JOB tya ; buffer number asl A ; times two adc #$06 ; plus 6 sta HDRPNT ; equals pointer to actual buffer tya ; buffer number clc adc #$03 ; plus 3 sta BUFPNT+1 ; equals buffer address hi B_F3AB ldy #$00 sty BUFPNT ; buffer address lo pla ; get command code back rts ;** Read block header, verify ID [F3B1] ; #### not needed with harddisk ReadHeader jmp ReadHeadN ; &&&04 .fb $FF, 50 ; &&&20 ; &&&05 L_F3E6 ldx CURDRV ; drive number lda HDRTRK ; track number of header sta DRVTRK,X ; use as actual track number lda JOB cmp #$30 ; code for 'preserve header'? beq B_F410 ; yes, -> lda CURDRV asl A tay lda DISKIDab,Y cmp HDR1IDzp ; compare with ID1 bne B_F41B lda IMDIIDab,Y cmp HDR2ID ; compare with ID2 bne B_F41B ; <>, then 29, 'disk id mismatch' jmp JobOptimal .fb $FF, 9 ; &&&20 ;** preserve block header B_F410 lda HDR1IDzp ; ID1 sta DISKIDzp lda HDR2ID ; and ID2 sta IMDIIDzp ; preserv J_F418 lda #$01 ; ok .by $2C ; dummy BIT opcode B_F41B lda #$0B ; 29, 'disk id mismatch' .by $2C ; dummy BIT opcode B_F41E lda #$09 ; 27, 'write error' jmp P_F969 ; done ;** Job optimisation [F423] JobOptimal lda #$7F sta CSECT lda HDRSEC clc adc #$02 cmp SECCNT ; max. sectors/track bcc B_F432 sbc SECCNT B_F432 sta NEXTS ldx #$05 stx JOBN ldx #$FF B_F43A jsr InitPntr2Buf ; set buffer pointer for disk controller bpl B_F483 ; no job, -> sta WORK ; save job code and #$01 cmp CURDRV ; momentary drive? bne B_F483 ; no, -> ldy #$00 lda (HDRPNT),Y ; get track # cmp TRACC ; same as from momentary job? bne B_F483 ; no, -> lda JOB ; command code cmp #$60 ; execute program in buffer? beq B_F461 ; yes, -> ldy #$01 sec lda (HDRPNT),Y ; get sector # sbc NEXTS bpl B_F461 clc adc SECCNT B_F461 cmp CSECT bcs B_F483 jmp B_F473 ; &&&14 .fb $FF, 11 ; &&&20 B_F473 sta CSECT lda JOBN tax adc #$03 sta BUFPNT+1 bne B_F483 B_F47E pla cmp #$06 bcc B_F473 B_F483 dec JOBN bpl B_F43A txa bpl B_F48D jmp LoopDiskCntrl ; to job loop B_F48D stx JOBN jsr InitPntr2Buf ; get buffer number lda JOB ; command code jmp J_F4CA ; continue checking .fb $FF, 51 ; &&&20 ;** Test command code further J_F4CA cmp #$00 ; command code for 'read'? beq B_F4D1 ; yes, -> jmp J_F56E ; continue checking command ;** Read sector B_F4D1 jmp JobReadSector ; &&&06 .fb $FF, 49 ; &&&20 B_F505 lda #$01 ; ok jmp P_F969 ; prepare error message .fb $FF, 6 ; &&&20 ;** Read block header [F510] FindSector lda DRIVE ; drive number asl A tax lda DISKIDzp ; ID1 sta HDR1IDzp ; save lda IMDIIDzp ; ID2 sta HDR2ID ; save ldy #$00 lda (HDRPNT),Y ; get track and sta HDRTRK iny lda (HDRPNT),Y ; sector number from buffer sta HDRSEC ;** At this point the track and sector to be searched for are stored rts .fb $FF, 58 ; &&&20 ;** Test command code further [F56E] J_F56E cmp #$10 ; command code for 'write' beq B_F575 ; yes, -> jmp J_F691 ; continue checking command code ;** Write data block to disk B_F575 jmp JobWriteSector ; &&&08 .fb $FF, 100 ; &&&20 l_F5DC ldy JOBN ; &&&09 lda JOBS,Y eor #$30 ; convert command code 'write' to ; 'verify' sta JOBS,Y jmp ReadHeader .fb $FF, 168 ; &&&20 ;** Test command code further J_F691 cmp #$20 ; command code for 'verify'? beq B_F698 ; yes, -> jmp J_F6CA ; continue checking command code ;** Compare written data with data on disk B_F698 jmp JobVerify ; &&&10 .fb $FF, 42 ; &&&20 B_F6C5 lda #$07 jmp P_F969 ; 25, 'write error' ;** Command code for find sector J_F6CA jsr FindSector ; read block header jmp J_F418 ; done ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This table simplifies the conversion from D64 track to the lineair sector ; numbering used by the harddisk ; Sector Track Tracktable .wo 1 ; 1 .wo 22 ; 2 .wo 43 ; 3 .wo 64 ; 4 .wo 85 ; 5 .wo 106 ; 6 .wo 127 ; 7 .wo 148 ; 8 .wo 169 ; 9 .wo 190 ; 10 .wo 211 ; 11 .wo 232 ; 12 .wo 253 ; 13 .wo 274 ; 14 .wo 295 ; 15 .wo 316 ; 16 .wo 337 ; 17 .wo 358 ; 18 .wo 377 ; 19 .wo 396 ; 20 .wo 415 ; 21 .wo 434 ; 22 .wo 453 ; 23 .wo 472 ; 24 .wo 491 ; 25 .wo 509 ; 26 .wo 527 ; 27 .wo 545 ; 28 .wo 563 ; 29 .wo 581 ; 30 .wo 599 ; 31 .wo 616 ; 32 .wo 633 ; 33 .wo 650 ; 34 .wo 667 ; 35 .wo 684 ; 36 .wo 701 ; 37 .wo 718 ; 38 .wo 735 ; 39 .wo 752 ; 40 TrackSector .by 20 ; 1 .by 20 ; 2 .by 20 ; 3 .by 20 ; 4 .by 20 ; 5 .by 20 ; 6 .by 20 ; 7 .by 20 ; 8 .by 20 ; 9 .by 20 ; 10 .by 20 ; 11 .by 20 ; 12 .by 20 ; 13 .by 20 ; 14 .by 20 ; 15 .by 20 ; 16 .by 20 ; 17 .by 18 ; 18 .by 18 ; 19 .by 18 ; 20 .by 18 ; 21 .by 18 ; 22 .by 18 ; 23 .by 18 ; 24 .by 17 ; 25 .by 17 ; 26 .by 17 ; 27 .by 17 ; 28 .by 17 ; 29 .by 17 ; 30 .by 16 ; 31 .by 16 ; 32 .by 16 ; 33 .by 16 ; 34 .by 16 ; 35 .by 16 ; 36 .by 16 ; 37 .by 16 ; 38 .by 16 ; 39 .by 16 ; 40 ; &&&02 Init the IDE drive InitIDE ldx #NewStack txs ldx #$FF stx POSTcode+2 ; init data direction ldx #$C3 stx POSTcode ; output C3 ; init LED lda #8 sta DDRB2 sta PortB2 ; Check if drive is ready InitIde010 lda IDEstatus ; ready? bmi InitIde010 ; if not, -> wait ; Read the disk ID and store it ; Read BAM sector from harddisk ldx #34 ; track (18 - 1) * 2 clc lda #0 ; sector 0 jsr SetTSparms3 jsr ReadIdeSector ; Read actual ID lda BUF0+162 sta IDEid1 lda BUF0+163 sta IDEid2 jmp InitStack2 ; !&&&04 Emulate the reading of the header of a sector by copying stored ; values into the places where the original routine would store them ReadHeadN ldx #$5A ; 90 stx TMP ; counter lda JOB cmp #$30 ; code for 'preserve header' beq ReadHeadN1 ; preserve header lda IDEid1 sta DISKIDzp lda IDEid2 sta IMDIIDzp ReadHeadN1 lda DISKIDzp ; ID1 sta HDR1IDzp ; save lda IMDIIDzp ; ID2 sta HDR2ID ; save ldy #$00 lda (HDRPNT),Y ; get track and sta HDRTRK iny lda (HDRPNT),Y ; sector number from buffer sta HDRSEC clv jmp L_F3E6 ; !&&&05 ; !&&&06 IDE replacement for reading data from disk JobReadSector jsr FindSector jsr LedOnn jsr SetTSparms lda #$20 ; read sector jsr SendCommand ldy #0 JobReadSec lda IDEdata sta (BUFPNT),Y iny bne JobReadSec lda #7 sta BID jsr LedOff jmp B_F505 ; !&&&08 IDE replacement for writing data to disk JobWriteSector jsr FindSector jsr SetTSparms lda #$30 ; write sector jsr SendCommand ldy #0 sty BUFPNT JobWrSector20 lda (BUFPNT),Y sta IDEdata iny bne JobWrSector20 jmp L_F5DC ; !&&&09 ; !&&&10 IDE replacement for verifying data on the disk JobVerify jsr FindSector jsr SetTSparms jsr LedOnn lda #$20 ; read sector jsr SendCommand ldx #0 ; no errors found yet ldy #0 JobVerify20 lda IDEdata eor (BUFPNT),Y ; compare beq JobVerify40 ; OK, -> JobVerify30 inx ; error found beq JobVerify30 ; make sure it stays <> 0 JobVerify40 iny ; 256 bytes? bne JobVerify20 ; no, -> jsr LedOff ldy #$FD txa ; Error? bne JobVerify60 ; yes, -> jmp J_F418 ; OK JobVerify60 jmp B_F6C5 ; error ; !&&&11 Stepping the head. ; For regular operations nothing has to be done. But a problem occurs ; when someone steps the head and starts reading the passing sectors ; not using the normal procedure. We'll see..... StepHeadN lda #0 sta STEPS sta RSTEPS sta ACLSTP jmp L_FA52 ; !&&&12 Format one track by filling all sectors with $00 ;- in: FTNUM = track ;- out: X = 0 FormatTrack ; sei ldx FTNUM ; track # lda TrackSector-1,X tay ; Y := last sector ; Fill sector with zeros FormatTrack01 lda FTNUM ; track # ; sta POSTcode asl ; * 2 tax clc tya jsr SetTSparms3 lda #$30 ; write sector jsr SendCommand lda #0 tax FormatTrack02 sta IDEdata inx bne FormatTrack02 dey ; next sector? bpl FormatTrack01 ; yes, -> ; cli ;&&&99 jmp L_FD8B ; !&&&18 Turn motor on? MotorOnN lda #$A0 sta DRVST lda #1 jmp MotorOn2 ;** ======================================================================== ;** turn LED off LedOff lda #$F7 and PortB2 sta PortB2 rts ;** turn LED on (without SEI and CLI) LedOnn lda #8 ora PortB2 sta PortB2 rts ;** Read a sector from the HD into BUF0 ReadIdeSector lda #$20 ; read sector jsr SendCommand ldx #0 ReadIdeSec lda IDEdata sta BUF0,X inx ; read 256 bytes? bne ReadIdeSec ; no, -> rts ;** Send command to IDE ;- in: A contains command ;- out: A contains error code SendCommand sta IDEcommand SendCommand010 lda IDEstatus ; ready? bmi SendCommand010 ; if not, -> wait and #1 ; error? rts ;** Set track and sector SetTSparms lda HDRTRK ; track # SetTSparms2 asl ; * 2 tax clc lda HDRSEC SetTSparms3 adc TrackTable-2,X ; relative number sta IDElba0 lda TrackTable-1,X adc #0 sta IDElba1 lda #0 sta IDElba2 lda #$E0 sta IDElba3 lda #1 sta IDEnumsec rts ;@@20 SubTmp lda DISKIDzp sta POSTcode l1 sei .by $FF jmp L1 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .ba $F969 ;** Error entry disk controller P_F969 ldy JOBN sta JOBS,Y jmp B_f975 .fb $FF, 4 ; &&&20 B_F975 jsr MotorOff ldx SAVSP ; get stack pointer back txs jmp J_F2BE ;** Turn drive motor on [F97E] MotorOn jmp MotorOnN ; &&&18 .fb $FF, 11 ; &&&20 MotorOn2 sta ACLTIM rts ;** Turn drive motor off (logical) [F98F] MotorOff ldx CURDRV ; why? -> see $F978 lda DRVST ora #$10 ; turn drive motor off sta DRVST lda #$FF sta ACLTIM rts ;** Job loop disk controller [F99C] LoopDiskCntrl lda T1LH2 sta T1CH2 ;* has writeprotect status changed? lda PortB2 and #$10 ; write protect? cmp LWPT0 sta LWPT0 beq B_F9B1 ; Not changed, -> lda #$01 sta WPSW0 ; state has changed ;* check if head is above track: PHASE is 0 or 2 B_F9B1 lda PHASE jmp B_F9CB .fb $FF, 20 ; &&&20 B_F9CB ldx CURDRV ; drive active? bmi B_F9D6 ; no, -> lda DRVST tay cmp #$20 ; drivemotor on? bne B_F9D9 ; no, -> B_F9D6 jmp J_FABE B_F9D9 dec ACLTIM ; drive is up to speed? bne B_F9FA ; no, -> tya ; A = DRVST bpl B_F9E4 ; drive already marked ready, -> and #$7F ; mark ready sta DRVST B_F9E4 and #$10 ; shut down drive motor ? beq B_F9FA ; no, -> ;** Drive motor off (hardware) lda PortB2 and #$FB sta PortB2 lda #$FF sta CURDRV lda #$00 sta DRVST beq B_F9D6 ; always -> B_F9FA tya and #$40 ; activate steppermotor? bne B_FA02 ; yes, -> jmp J_FABE B_FA02 jmp (NXTSTab) ; StepHead [FA05] ;** Step the head [FA05] StepHead jmp StepHeadN ; &&&11 .fb $FF, 74 ; &&&20 L_FA52 lda DRVST and #$BF ; erase bit 6 sta DRVST lda #<(StepHead) sta NXTSTzp lda #>(StepHead) ; pointer $62/$63 to $FA05 sta NXTSTzp+1 jmp J_FABE .fb $FF, 91 ; &&&20 J_FABE lda PCR2 and #$FD ; erase bit 1 sta PCR2 ; disable "Byte ready" rts ;** Formatting E_FAC7 lda FTNUM ; track number bpl B_FAF5 ; formatting already in progress ldx DRIVE ; drive number lda #$60 ; flag for head transport sta DRVST,X ; set lda #$01 sta DRVTRK,X ; set destination track sta FTNUM ; running track number for format lda #$A4 ; - 46 tracks sta STEPS ; step counter for head transport lda PortB2 and #$FC ; set phase to 0 sta PortB2 lda #2 ; org. 10 sta ErrorCount ; error counter jmp LoopDiskCntrl ; back in job loop .fb $FF, 10 ; &&&20 B_FAF5 ldy #$00 cmp (HDRPNT),Y beq B_FB00 sta (HDRPNT),Y jmp LoopDiskCntrl ; to job loop B_FB00 lda PortB2 and #$10 ; write protect? jmp J_FB0C ; no, -> .fb $FF, 4 ; &&&20 ;== ; As there is no need to lowformat a track on the IDE disk, all according ; routines are skipped. ;== J_FB0C jmp FormatTrack ; &&&12 .fb $FF, 636 ; &&&20 L_FD8B inc FTNUM ; increment track number lda FTNUM cmp #$24 ; compare with 36, highest track ; number + 1 bcs B_FD96 ; greater, then formatting done jmp LoopDiskCntrl ; continue B_FD96 lda #$FF sta FTNUM ; track number to $FF lda #$01 jmp P_F969 ; ok .fb $FF, 52 ; &&&20 ;** Attempt counter for formatting J_FDD3 dec ErrorCount ; decrement number of attempts beq B_FDDB ; zero, then error jmp LoopDiskCntrl ; continue B_FDDB ldy #$FF sty FTNUM ; flag for end of formatting iny ; #### still needed ??? jmp P_F969 ; error termination .fb $FF, 132 ; &&&20 ;** Interrupt routine [FE67] IRQ pha txa pha ; save registers tya pha lda IFR1 ; interrupt from serial bus? and #$02 beq B_FE76 ; no, -> jsr P_E853 ; serve serial bus B_FE76 lda IFR2 ; interrupt from timer 1? asl A bpl B_FE7F ; no, -> jsr IRQdiskCntrllr ; IRQ routine for disk controller B_FE7F pla tay pla ; get registers back tax pla rti ;** Constands for disk format [FE85] DirTrack .by $12 ;** directory track .by $04 ;** start of bam .by $04 ;** length of bam per track LengthBAM .by $90 ;** end of bam ;** Table of command words [FE89] TblCommands .by "V" ; Validate .by "I" ; Initialize .by "D" ; D (back up, not used) .by "M" ; Memory .by "B" ; Block .by "U" ; User .by "P" ; Position .by "&" ; USR execute .by "C" ; Copy .by "R" ; Rename .by "S" ; Scratch .by "N" ; New (Format) ;** Low byte of command addresses CmdAddrLB .by <(Validate) .by <(Initialize) .by <(SyntaxError) .by <(Memory) .by <(Block) .by <(User) .by <(Position) .by <(USRexec) .by <(Copy) .by <(Rename) .by <(Scratch) .by <(New) ;** High byte of command addresses [FEA1] CmdAddrHB .by >(Validate) .by >(Initialize) .by >(SyntaxError) .by >(Memory) .by >(Block) .by >(User) .by >(Position) .by >(USRexec) .by >(Copy) .by >(Rename) .by >(Scratch) .by >(New) ;** Bytes for syntax check TblSyntax .by $51, $DD, $1C, $9E, $1C ; ; ^ ^ ; | | ; +-------------------+---- why are these here? ;** File control methods A_FEB2 .tx "RWAM" ;** File types A_FEB6 .tx "DSPUL" ;** Names of file types [FEBB] TblFiletype .tx "DSPUR" ;** 1st char .tx "EERSE" ;** 2nd char .tx "LQGRL" ;** 3rd char ;** Value of LED-byte for every drive [FECA] A_FECA .by $08,$00 ;** For setting the Zero flag, see routine at [E304] A_FECC .by $00 ;** Masks for bit command A_FECD .by $3F,$7F,$BF,$FF ;** Number of sectors per track A_FED1 .by $11,$12,$13,$15 ;** Constands for disk format A_FED5 .by $41 ;** A marker for 1541 format A_FED6 .by $04 ;** 4 track ranges A_FED7 .by $24 ;** number of tracks .by $1F,$19,$12 ;** tracks on which sector numbers ; change ;** Control bytes for head postion A_FEDB .by $01,$FF, $FF,$01,$00 ;** High byte addresses of buffers [FEE0] BufferAddress .by $03,$04,$05,$06,$07,$07 ;** ROM checksum .by $3E L_FEE7 jmp (J_VNMI) ;** Patch for diagnostic routine, from $EA7A [FEEA] PATCH3 sta PortB2 ; turn LED on sta DDRB2 ; port to output jmp J_EA7D ; back to diagnostic routine ;** Delay loop for serial bus in 1541 mode from $E97D [FEF3] DelayC64 txa ldx #$05 B_FEF6 dex ; about 40 microseconds bne B_FEF6 tax rts ;** Patch for data output to serial bus from $E980 [FEFB] P_FEFB jsr ClkOut_H ; CLOCK OUT hi jmp DataOut_L ; DATA OUT lo ;** U9 vector, switch 1540/1541 [FF01] NMI lda CMDBUF+2 cmp #'-' beq B_FF0D ; if parameter is '+', then at B_FF0D result is 0 sec sbc #'+' bne L_FEE7 ; indirect jump over ($0065) B_FF0D sta VIC20mode rts ;** Patch for reset routine, from $EAA4 [FF10] PATCH1 stx DDRA1 lda #$02 sta PortB1 lda #$1A sta DDRB1 jmp L_EAA7 ;** Patch for listen to serial bus from $E9DC [FF20] PATCH2 lda PortB1 and #$01 bne PATCH2 lda #$01 sta T1CH1 jmp J_E9DF ;** Unused .fb $AA, 183 ; [FFE6] ;??? Are these two vectors used ??? .WO FormatFloppy .WO MotorOff ;** USER vectors [FFEA] UserVectors .WO E_CD5F ;** UA, U1 .WO E_CD97 ;** UB, U2 .WO BUF2+0 ;** UC, U3 .WO BUF2+3 ;** UD, U4 .WO BUF2+6 ;** UE, U5 .WO BUF2+9 ;** UF, U6 .WO BUF2+12 ;** UG, U7 .WO BUF2+15 ;** UH, U8 ;** Hardware vectors .WO NMI ;** UI, U9 .WO RESET ;** RESET .WO IRQ ;** IRQ .en