;------------------------------------------------------------------------------ ; ; 1541 with 8 bits IDE interface V0.1 ; ; - WITHOUT the mechanical drive ; ; ; 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 ; 01- check extra RAM, incorperated in original check ; 02- initialization of the added I/O ; 03- Create first image after boot-up ; 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 ; 13- GCR conversion not needed ; 14- changes to avoid multiple reads of the header ; 16- Start up text ; 18- Change start-up time of motor ; 19- new commands ; 20- freed space because of removing real floppy .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 HDR1IDab = $0016 .eq HDR2ID = $17 ; second ID character .eq HDRTRK = $18 ; track number .eq HDRSEC = $19 ; sector number .eq HDRCHK = $1A ; header checksum ; Free 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 .. 3C .eq DRIVE = $3D ; drive (always 0checksum .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 .eq GCRFLG = $50 ; indicator that data in buffer is ; 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 ExtraRAM = $01C0 .eq IDEid1 = ExtraRAM+1 ; Disk ID1 .eq IDEid2 = ExtraRAM+2 ; Disk ID2 .eq IDEtrck = ExtraRAM+3 ; track .eq IDEsect = ExtraRAM+4 ; sector .eq IDEtmp0 = IDEsect+1 ; temporary .eq IDEtmp1 = IDEtmp0+1 .eq IDEtmp2 = IDEtmp0+2 .eq IDEtmp3 = IDEtmp0+3 .eq IDEtmp4 = IDEtmp0+4 .eq IDEtmp5 = IDEtmp0+5 .eq IDEimage0 = IDElba3R+1 ; number of last used image .eq IDEimage1 = IDEimage0+1 .eq IDEimage2 = IDEimage0+2 .eq IDEimage3 = IDEimage0+3 .eq IDEimlba0 = IDEimage3+1 ; LBA of this last used image .eq IDEimlba1 = IDEimlba0+1 ; (first byte is always 0) .eq IDEimlba2 = IDEimlba1+1 .eq IDEimlba3 = IDEimlba2+1 .eq IDEdir = IDEimlba3+1 ; number of directory blocks .eq IDE1st = IDEdir+1 ; creation of 1st image needed? ; - $AA = yes, $55 = no .eq ErrCount = IDE1st+1 .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 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 ;+------+-----+-----+---+---+---+----------------+---------------+ ;| 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 ;============================================================================== ; Constants: .eq NewStack = $80 ;============================================================================== .ba $C000 .fb $FF, 256 ; &&&20-17 ;** 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 jmp NewCommands ;-- 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 bne B_D5C6 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 ;** Additional attempts for read errors B_D5C6 tya pha lda DRVNMB ; drive number pha lda LSTJOB,X and #$01 ; drive number sta DRVNMB tay lda A_FECA,Y ; bit model for drive sta ERLED jsr RetryExec ; read attempt cmp #$02 bcs B_D5E3 ; not ok? jmp J_D66D ; done B_D5E3 lda LSTJOB,X ; command code and #$F0 ; isolate pha cmp #$90 ; code for write bne B_D5F4 ; no, -> lda DRVNMB ; drive number ora #$B8 sta LSTJOB,X B_D5F4 bit REVCNT bvs B_D631 lda #$00 sta EPTR ; counter for searches next to track sta TOFF B_D600 ldy EPTR ; counter lda TOFF sec sbc A_FEDB,Y ; constants for read attempts sta TOFF lda A_FEDB,Y jsr P_D676 ; position head next to track inc EPTR ; increment counter jsr RetryExec ; read attempt cmp #$02 ; return message bcc B_D625 ; smaller than 2, ok? ldy EPTR ; load counter lda A_FEDB,Y ; get constants bne B_D600 ; not yet zero (table end)? B_D625 lda TOFF jsr P_D676 ; position head lda JOBSZP,X cmp #$02 ; return message bcc B_D65C ; ok? B_D631 bit REVCNT bpl B_D644 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 ;** Move head by half a track P_D676 cmp #$00 beq B_D692 bmi B_D688 B_D67C ldy #$01 jsr P_D693 ; transmit data for head position sec sbc #$01 bne B_D67C beq B_D692 B_D688 ldy #$FF jsr P_D693 ; transmit data for head position clc adc #$01 bne B_D688 B_D692 rts ;** Move head one track in or out P_D693 pha tya ldy DRVNMB ; drive number sta PHASE,Y B_D69A cmp PHASE,Y ; wait for return message from beq B_D69A lda #$00 ; disk controller sta PHASE,Y pla rts ;** 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 ld