;------------------------------------------------------------------------------ ; ; 1541 with 8 bits IDE interface V0.1 ; ; - including 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 .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) .eq CHKSUM = $3A ; data or header checksum ; Free 3B 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 A_01BB = $01BB .eq CMDBUF = $0200 .eq INSTRU = $022A ; instruction number .eq LINTAB = $022B .eq CH4WFL = $023A ; Write-flag channel 4 .eq CH5WFL = $023B ; Write-flag channel 5 ; actually not used .eq A_023C = $023C .eq A_023D = $023D .eq OUTREG = $023E ; output registers .eq ENDPNT = $0244 .eq TYPE = $024A ; active file type .eq STRSIZ = $024B ; length of string .eq TEMPSA = $024C ; temporary secondary address .eq CMD = $024D ; temporary job command .eq BSTSEC = $024E ; best sector to do .eq BUFUSEL = $024F .eq BUFUSEH = $0250 .eq MDIRTY = $0251 ; <> 0 means: BAM changed flag (dr 0) ; $0252 = same for drive 1 .eq ENTFND = $0253 ; directory entry found flag .eq DIRLST = $0254 ; directory listing flag .eq CMDWAT = $0255 ; command waiting flag .eq LINUSE = $0256 ; LINDX use word .eq LBUSED = $0257 ; last buffer used .eq RECSIZ = $0258 ; record size (directory routine) .eq TRKSS = $0259 ; side sector track .eq SECSS = $025A ; side sector sector .eq LSTJOB = $025B ; last job / drive number .eq DSEC = $0260 ; sector of directory entry by buffer .eq DIND = $0266 ; index of directory entry by buffer .eq ERWORD = $026C ; error word .eq ERLED = $026D ; which LED must blink during error .eq PRGDRV = $026E ; last program drive .eq PRGSEC = $026F ; last program sector .eq WLINDX = $0270 ; write LINDX .eq NBTEMP0 = $0272 .eq NBTEMP1 = $0273 .eq CMDSIZ = $0274 ; size of command string .eq CHAR = $0275 ; character under parser .eq LIMIT = $0276 ; PTR limit in comparison .eq F1CNT = $0277 ; file stream 1 count .eq F2CNT = $0278 ; file stream 2 count / number of drives .eq F2PTR = $0279 ; file stream 2 pointer .eq FILTBL = $027A ; table of filename pointers .eq FILTRK = $0280 ; first file link (track) .eq FILSEC = $0285 ; first file link (sector) .eq PATFLG = $028A ; pattern present flag .eq IMAGE = $028B ; file stream image / flag syntax check .eq DRVCNT = $028C ; number of drive searches .eq DRVFLG = $028D ; drive search flag .eq LSTDRV = $028E ; last drive w/o error .eq FOUND = $028F ; found flag in directory searches .eq DIRSEC = $0290 ; directory sector .eq DELSEC = $0291 ; sector of first available entry .eq DELIND = $0292 ; index of first available entry .eq LSTBUF = $0293 ; O if last block .eq INDEX = $0294 ; current index in buffer .eq FILCNT = $0295 ; counter of file entries .eq TYPFLG = $0296 ; match by type of flag .eq MODE = $0297 ; active file mode (R,W) .eq JOBRTN = $0298 ; job return flag .eq EPTR = $0299 ; pointer for recovery .eq TOFF = $029A ; total track offset .eq UBAM = $029B ; last BAM update pointer .eq TBAM = $029D ; track # of BAM image .eq BAMima = $02A1 ; BAM images .eq NameBuffer = $02B1 ; directory output buffer .eq A_02C3 = $02C3 .eq A_02C4 = $02C4 .eq ERRBUF = $02D5 ; error message output buffer .eq WBAM = $02F9 ; 'don't write BAM'-flag. set at start .eq NDBL = $02FA ; # of disk blocks free (lo byte 0/1) .eq A_02FB = $02FB .eq NDBH = $02FC ; # of disk blocks free (hi byte 0/1) .eq A_02FD = $02FD .eq PHASE = $02FE ; current phase of head stepper motor .eq BUF0 = $0300 .eq A_0345 = $0345 .eq BUF2 = $0500 .eq BUF3 = $0600 .eq A_0620 = $0620 .eq A_0621 = $0621 .eq A_0622 = $0622 .eq A_0623 = $0623 .eq A_0624 = $0624 .eq A_0625 = $0625 .eq A_0626 = $0626 .eq A_0627 = $0627 .eq A_0628 = $0628 ; Extra 1KB/2KB of RAM from $0800 to $0C00/$1000 .eq ExtraRAM = $0800 .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 IDElba0R = IDEtmp5+1 ; copy of disk parameters in RAM .eq IDElba1R = IDElba0R+1 .eq IDElba2R = IDElba1R+1 .eq IDElba3R = IDElba2R+1 .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 ORGflop = IDE1st+1 ; read from IDE or real floppy ; - $AA = IDE, $55 = floppy ;+------+-----+-----+---+---+---+----------------+---------------+ ;| 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 .ba $8000 ;** Block containing text and other forms of data HDidentity .tx "1541-IDE8 WD " ; 8 bits interface HDversion .tx "00.00.01.WD " ; This table simplifies the conversion from D64 track to the lineair sector ; numbering used by the harddisk ; Sector Track Tracktable .wo 0 ; 1 .wo 21 ; 2 .wo 42 ; 3 .wo 63 ; 4 .wo 84 ; 5 .wo 105 ; 6 .wo 126 ; 7 .wo 147 ; 8 .wo 168 ; 9 .wo 189 ; 10 .wo 210 ; 11 .wo 231 ; 12 .wo 252 ; 13 .wo 273 ; 14 .wo 294 ; 15 .wo 315 ; 16 .wo 336 ; 17 .wo 357 ; 18 .wo 376 ; 19 .wo 395 ; 20 .wo 414 ; 21 .wo 433 ; 22 .wo 452 ; 23 .wo 471 ; 24 .wo 490 ; 25 .wo 508 ; 26 .wo 526 ; 27 .wo 544 ; 28 .wo 562 ; 29 .wo 580 ; 30 .wo 598 ; 31 .wo 615 ; 32 .wo 632 ; 33 .wo 649 ; 34 .wo 666 ; 35 .wo 683 ; 36 .wo 700 ; 37 .wo 717 ; 38 .wo 734 ; 39 .wo 751 ; 40 TrackSector .wo 21 ; 1 .wo 21 ; 2 .wo 21 ; 3 .wo 21 ; 4 .wo 21 ; 5 .wo 21 ; 6 .wo 21 ; 7 .wo 21 ; 8 .wo 21 ; 9 .wo 21 ; 10 .wo 21 ; 11 .wo 21 ; 12 .wo 21 ; 13 .wo 21 ; 14 .wo 21 ; 15 .wo 21 ; 16 .wo 21 ; 17 .wo 19 ; 18 .wo 19 ; 19 .wo 19 ; 20 .wo 19 ; 21 .wo 19 ; 22 .wo 19 ; 23 .wo 19 ; 24 .wo 18 ; 25 .wo 18 ; 26 .wo 18 ; 27 .wo 18 ; 28 .wo 18 ; 29 .wo 18 ; 30 .wo 17 ; 31 .wo 17 ; 32 .wo 17 ; 33 .wo 17 ; 34 .wo 17 ; 35 .wo 17 ; 36 .wo 17 ; 37 .wo 17 ; 38 .wo 17 ; 39 .wo 17 ; 40 ; &&&02 Init the IDE drive InitIDE ldx #$45 txs lda #$AA sta ORGflop ; all operations are meant for IDE ; init LED lda #8 sta DDRB2 sta PortB2 ; Check if drive is ready InitIde010 lda IDEstatus ; ready? bmi InitIde010 ; if not, -> wait ; Check if drive is formated for 1541IDE8 ; Read very first sector from harddisk ldx #1 stx IDEnumSec ; number of sectors stx IDElba0 ; start with sector 1 dex stx IDElba1 stx IDElba2 ldx #$E0 ; LBA mode !!! stx IDElba3 jsr ReadIdeSector ; Compare first 16 bytes with signature ldx #15 InitIde025 lda BUF0,X cmp HDidentity,X beq InitIde030 ; Not equal, so it isn't a 1541IDE8 disk ;@@10 jmp InitNewDisk InitIde030 dex ; X >= 0, checked 16 characters? bpl InitIde025 ; no, -> ; Signature OK, save disk, # directories and image parameters in memory ldx #13 InitIde040 lda BUF0+16,X sta IDElba0R,X dex bpl InitIde040 ; Read the disk ID and store it ; Read BAM sector from harddisk ldx #1 stx IDEnumSec ; number of sectors ldx #34 ; track (18 - 1) * 2 lda Tracktable,X ; LB track 18, sector 1 sta IDElba0 clc lda Tracktable+1,X ; HB track 18, sector 1 adc IDEimlba0 sta IDElba1 adc IDEimlba1 sta IDElba2 adc IDEimlba2 and #$0F ora #$E0 ; LBA mode !!! sta IDElba3 jsr ReadIdeSector ; Read actual ID lda BUF0+162 sta IDEid1 lda BUF0+163 sta IDEid2 lda #$55 ; creation of 1st image not needed sta IDE1st jmp InitStack2 ;** Find out how many sectors the disk has InitNewDisk lda #0 sta IDElba0R sta IDElba1R sta IDElba2R lda #$E0 sta IDElba3R ldy #3 ; start with IDElba3R lda #8 ; start with 64 GB real size InitIde105 sta IDEtmp0 InitIde110 ora IDElba0R,Y ; check next size jsr SeekSector beq InitIde120 ; sector exists, -> ; sector not found, disk is smaller lda IDEtmp0 eor #$FF ; ..00100.. -> ..11011.. and IDElba0R,Y ; clear this specific size bit sta IDElba0R,Y InitIde120 lsr IDEtmp0 ; next lower bit, all done? bne InitIde110 ; no, -> check next sector ; IDElbaxR checked, check next lower one InitIde200 dey ; all IDElbaxR's done? beq InitIde210 ; yes, -> lda #$80 bne InitIde105 ; always -> ; info: IDElba0R doesn't need to be checked as we need a multiple value ; of $300 sectors InitIde210 jmp CmdP ; prepare harddisk ; !&&&03 Creation of 1st image needed? FirstImage lda IDE1st cmp #$55 ; not needed? bne FirstImage010 ; maybe, -> rts ; no, return to waitloop FirstImage010 cmp #$AA ; needed? beq FirstImage020 ; yes, -> cmp #$C3 ; pre-format needed? bne FirstImage012 ; no, -> jmp L_C41B ; 74, 'drive not ready' FirstImage012 ; Unknown code, program error ??? ldx #9 stx TEMP0 jmp BlinkX ; Copy command to Command Buffer FirstImage020 ldx #(ImageNameX-ImageName) stx INPPTR ; see [C2B3] FirstImage030 lda ImageName,X sta CMDBUF,X dex bmi FirstImage030 inx stx LSTDRV ; set last drive for sure lda #15 sta ORGSA sta SA jmp L_C160 ImageName .tx "N:1541IDE8,RB" ImageNameX ; !&&&04 Emulate the reading of the header of a sector by copying stored ; values into the places where the original routine would store them ReadHeadN lda ORGflop cmp #$55 ; floppy operation? bne ReadHeadN0 ; no, -> ldx #$5A ; 90 stx TMP ; counter jmp L_F3B5 ReadHeadN0 ldx #$5A ; 90 stx TMP ; counter lda JOB cmp #$30 ; code for 'preserve header' beq ReadHeadN1 ; preserve header lda IDEid1 sta DISKIDzp lda IDEid2 sta IMDIIDzp ReadHeadN1 lda DISKIDzp ; ID1 sta HDR1IDzp ; save lda IMDIIDzp ; ID2 sta HDR2ID ; save ldy #$00 sty GCRFLG ; avoid GCR conversion lda (HDRPNT),Y ; get track and sta HDRTRK iny lda (HDRPNT),Y ; sector number from buffer sta HDRSEC dey ; Y := 0 ; calculate parity for block header lda #0 eor HDR1IDzp eor HDR2ID eor HDRTRK eor HDRSEC sta HDRCHK ; and save clv jmp L_F3D8 ; !&&&05 ; !&&&06 IDE replacement for reading data from disk JobReadSector lda ORGflop cmp #$55 ; floppy operation? bne JobReadSec0 ; no, -> jsr FindDatablock ; find beginning of data block jmp B_F4D4 JobReadSec0 jsr FindSector jsr LedOnn jsr SetTSparms lda #$20 ; read sector jsr SendCommand ldy #0 sty GCRFLG sty IDEtmp0 JobReadSec lda IDEdata sta (BUFPNT),Y eor IDEtmp0 ; calculate checksum sta IDEtmp0 iny bne JobReadSec sta CHKSUM lda #7 sta BID jsr LedOff jmp B_F505 ; !&&&07 Continue original FindSector routine or not? FindSector2 lda ORGflop cmp #$55 ; floppy operation? beq FindSector3 ; yes, -> rts FindSector3 jsr Header2gcr ; convert to GCR jmp FindSector4 ; !&&&08 IDE replacement for writing data to disk JobWriteSector lda ORGflop cmp #$55 ; floppy operation? bne JobWrSector10 ; no, -> jsr P_F78F jmp JobWrSector30 JobWrSector10 jsr FindSector jsr SetTSparms lda #$30 ; write sector jsr SendCommand ldy #0 sty BUFPNT JobWrSector20 lda (BUFPNT),Y sta IDEdata iny bne JobWrSector20 jmp L_F5DC ; !&&&09 ; !&&&10 IDE replacement for verifying data on the disk JobVerify lda ORGflop cmp #$55 ; floppy operation? bne JobVerify10 ; no, -> jsr P_F78F jmp JobVerify00 JobVerify10 jsr FindSector jsr SetTSparms jsr LedOnn lda #$20 ; read sector jsr SendCommand ldx #0 ; no errors found yet ldy #0 JobVerify20 lda IDEdata eor (BUFPNT),Y ; compare beq JobVerify40 ; OK, -> JobVerify30 inx ; error found beq JobVerify30 ; make sure it stays <> 0 JobVerify40 iny ; 256 bytes? bne JobVerify20 ; no, -> jsr LedOff ldy #$FD txa ; Error? bne JobVerify60 ; yes, -> jmp J_F418 ; OK JobVerify60 jmp B_F6C5 ; error ; !&&&11 Stepping the head. ; For regular operations nothing has to be done. But a problem occurs ; when someone steps the head and starts reading the passing sectors ; not using the normal procedure. We'll see..... StepHeadN lda ORGflop cmp #$55 ; floppy operation? bne StepHeadN3 ; no, -> lda STEPS bpl StepHeadN2 jmp StepHeadN1 StepHeadN2 jmp B_FA0E ; Now skip all stepping routines and set all relevant values to zero StepHeadN3 lda #0 sta STEPS sta RSTEPS sta ACLSTP jmp L_FA52 ; !&&&12 Format one track by filling all sectors with $00 ;- in: FTNUM = track ;- out: X = 0 FormatTrack lda ORGflop cmp #$55 ; floppy operation? bne FormatTrack1 ; no, -> jsr P_FDA3 ; write $FF to disk 10240 times jmp FormatTrack2 FormatTrack1 ldx FTNUM ; track # dex lda TrackSector,X tay ; Y := last sector ; Fill sector with zeros FormatTrack01 lda FTNUM ; track # jsr SetTSparms2 lda #0 tax FormatTrack02 sta IDEdata inx bne FormatTrack02 dey ; next sector? bpl FormatTrack01 ; yes, -> ldx #$00 jmp L_FD8B ; !&&&13 GCR conversion needed? CheckGCR lda ORGflop cmp #$55 ; floppy operation? bne CheckGCR2 ; no, -> jmp Gcr2Data ; GCR conversion CheckGCR2 rts ; !&&&14 MultiRead not needed for IDE MultiRead pha lda ORGflop cmp #$55 ; floppy operation? bne MultiRead1 ; no, -> lda JOB jmp MultiRead2 MultiRead1 pla jmp B_F473 ; !&&&18 Turn motor on? MotorOnN lda #$A0 sta DRVST lda ORGflop cmp #$55 ; floppy operation? bne MotorOnN2 ; no, -> jmp MotorOn1 MotorOnN2 lda PortB2 and #$FB ; floppy motor off (for sure) sta PortB2 lda #1 jmp MotorOn2 ; !&&&19 Insert new commands NewCommands sta CHAR ; mark it cmp #"!" beq NewCommands10 jmp L_C168 ; original routine NewCommands10 lda CMDBUF+1 ; 2nd character from buffer sta CHAR ldx #(CmdAddrLB2-TblCommands2-1) NewCommands20 lda TblCommands2,X ; compare commands cmp CHAR ; with char beq NewCommands30 ; found, -> dex bpl NewCommands20 lda #$31 ; NOT found jmp OutputErrorMsg ; 31, 'syntax error' NewCommands30 stx INSTRU lda CmdAddrLB2,X sta TEMP0 lda CmdAddrHB2,X sta TEMP1 jmp (TEMP0) ; jump to command ;** table of command words TblCommands2 .by "$" ; Directory available D64's .by "F" ; Floppy to/from image .by "I" ; Initialize D64 .by "P" ; Prepare harddisk ;** low byte of command addresses CmdAddrLB2 .by <(CmdDIR) .by <(CmdF) .by <(CmdI) .by <(CmdP) .by <(SyntaxError) ;** high byte of command addresses CmdAddrHB2 .by >(CmdDIR) .by >(CmdF) .by >(CmdI) .by >(CmdP) .by >(SyntaxError) CmdDIR CmdF ;** Initialize another image by reading the given number CmdI ldx #1 ; skip the spaces between "!I" and the number CmdI010 inx cpx CMDSIZ ; command is only "!I" ? beq CmdI020 ; yes, syntax error -> lda CMDBUF,X cmp #" " ; space? beq CmdI010 ; skip, next character -> CmdI015 lda CMDBUF,X cmp #"0" ; >= 0 ? beq CmdI030 ; yes, -> ; Syntax error CmdI020 lda #$31 ; NOT found jmp OutputErrorMsg ; 31, 'syntax error' CmdI030 cmp #":" ; > 9 ? bcs CmdI020 ; yes, error -> sta IDEtmp0-2,X ; store in IDEtmpX inx cpx CMDSIZ ; end of command? bne CmdI015 CmdP ;** Prepare a new harddisk for 1541IDE8 ; in: IDElba0R..IDElba3R contains number of sectors ; First sector ; identifier 16 bytes ; version 16 bytes ; disk parameters 4 bytes ; last used image 4 bytes ; LBA of last used image 4 bytes (first byte = 0) ; number of needed dir blocks 1 byte ; Clear first 65535 sectors (good for a 200 GB harddisk) ldy #0 ldx #$E0 stx IDElba3 ldx #1 stx IDElba0 dex ; X := 0 stx IDElba1 stx IDElba2 stx IDEnumSec ; 256 sectors CmdP050 lda #$30 ; write sector jsr SendCommand txa ; A := 0 CmdP060 sta IDEdata inx bne CmdP060 iny ; done all 256 sectors? bne CmdP050 ; no, -> inc IDElba1 ; done all 65536 sectors? bne CmdP060 ; no, -> ; Prepare sector 1 ; Clear RAM buffer ; in: A=0, X=0 CmdP070 sta BUF0,X inx bne CmdP070 ; Insert data ; Identifyer + version ldx #31 CmdP080 lda HDidentity,X sta BUF0,X dex bpl CmdP080 ; Disk parameters ldx #3 CmdP090 lda IDElba0R,X sta BUF0+32,X dex bpl CmdP090 ; How many directory sectors are needed? ; - idea: $300 directory sectors cover $480000 data sectors. So ignore ; LBA0 and LBA1 and subtract $0048 from LBA2/LBA3 until the result ; is negative. ldx #$FF ; X := number of dir blocks ;@@11 ldy IDElba2R sty IDEtmp2 lda IDElba3R and #$0F ; clear bit 4..7 sta IDEtmp3 CmdP100 sec ; set Carry for subtraction inx lda IDEtmp2 sbc #$48 sta IDEtmp2 lda IDEtmp3 sbc #0 sta IDEtmp3 bcs CmdP100 ; Carry set = no underflow -> stx IDEdir ; store number of dir blocks stx BUF0+28 stx BUF0+20 ; is also "last used" image stx IDEimage0 ldx #0 stx IDEimage1 stx IDEimage2 stx IDEimage3 jsr CalcLBA ; calculate LBA of last used image ; Copy calculated LBA to buffer ldx #3 CmdP110 lda IDElba0,X sta BUF0+40,X dex bpl CmdP110 ; Write first sector ldx #1 stx IDEnumSec ; number of sectors stx IDElba0 ; start with sector 1 dex stx IDElba1 stx IDElba2 ldx #$E0 ; LBA mode !!! stx IDElba3 lda #$30 ; write sector jsr SendCommand ldx #0 CmdP150 lda BUF0,X sta IDEdata inx ; 256 bytes written? bne CmdP150 ; no, -> ; Create first image after boot-up lda #$AA sta IDE1st jmp InitStack2 ;** ======================================================================== ;** Calculate LBA of last used image ; Idea: Each image containss $300 sectors. Just clear IDEimlbaX and add ; the image number three times to IDEimlba. CalcLBA ldx #3 ; counter lda #0 sta IDEimlba0 sta IDEimlba1 sta IDEimlba2 sta IDEimlba3 CalcLBA010 clc lda IDEimlba0 adc IDEimage0 sta IDEimlba0 lda IDEimlba1 adc IDEimage1 sta IDEimlba1 lda IDEimlba2 adc IDEimage2 sta IDEimlba2 lda IDEimlba3 adc #0 sta IDEimlba3 dex bne CalcLBA010 rts ;** turn LED off LedOff lda #$F7 and PortB2 sta PortB2 rts ;** turn LED on (without SEI and CLI) LedOnn lda #8 ora PortB2 sta PortB2 rts ;** Read a sector from the HD into BUF0 ReadIdeSector lda #$20 ; read sector jsr SendCommand ldx #0 ReadIdeSec lda IDEdata sta BUF0,X inx ; read 256 bytes? bne ReadIdeSec ; no, -> rts ;** Seek a sector ;- in: LBA data in IDElbaxR SeekSector ldx #3 SeekSector10 lda IDElba0R,x sta IDElba0,x dex bpl SeekSector10 lda #$77 ; Seek ;continue jmp SendCommand ;** Send command to IDE ;- in: A contains command ;- out: A contains error code SendCommand sta IDEcommand SendCommand010 lda IDEstatus ; ready? bmi SendCommand010 ; if not, -> wait and #1 ; error? rts ;** Set track and sector SetTSparms lda HDRTRK ; track # ldy HDRSEC SetTSparms2 asl ; * 2 tax lda TrackTable,X ; relative number sta IDEtmp0 clc lda TrackTable+1,X adc IDEimlba0 sta IDEtmp1 lda IDEimlba1 adc #0 sta IDEtmp2 lda IDEimlba2 adc #0 and #$0F ora $E0 sta IDEtmp3 ; add sector to first result clc tya ; A:= sector adc IDEtmp0 sta IDElba0 lda IDEtmp1 adc #0 sta IDElba1 lda IDEtmp2 adc #0 sta IDElba2 lda IDEtmp3 adc #0 sta IDElba3 rts ;============================================================================== .ba $C000 .fb $FF, 256 ;** 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