0 Members and 1 Guest are viewing this topic.
.%001! ;Word Count utility using the burst command set's Fastload facility.%002! ;written 92/06/25 by Craig Bruce for C= Hacking Net Magazine.%003!The code is written for the Buddy assembler and here are a few setupdirectives..%004! .mem.%005! .bank 15.%006! .org $1c01.%007!.%008! ;*** BASIC startup code.%009!This is what the "10 sys 7200" in BASIC looks like. It is here so thisprogram can be executed with BASIC RUN command..%010! .word $1c1c.%011! .word 10.%012! .byte $9e.%013! .asc " 7200 : ".%014! .byte $8f.%015! .asc " 6502 power!".%016! .byte 0.%017! .word 0.%018! .word 0.%019!.%020! jmp main.%021!.%022! ;========== burst read library ==========.%023!.%024! burstStatus = $fe.%025! burstBufCount = $ff.%026! burstBuf = $b00"serialFlag" is used to determine whether a device is Fast or not, and the"ioStatus" (a.k.a. "ST") is to tell if a device is present or not..%027! serialFlag = $a1c.%028! ioStatus = $90"ciaIcr" is the interrupt control register of CIA#1. It is polled to wait fordata becoming available in the shift register ("ciaData"). "ciaSerialClk" isthe Slow serial bus clock line that is used for handshaking on the Fast bus..%029! ciaIcr = $dc0d.%030! ciaSerialClk = $dd00.%031! ciaData = $dc0c.%032!.%033! kernelListen = $ffb1.%034! kernelSecond = $ff93.%035! kernelCiout = $ffa8.%036! kernelUnlsn = $ffae.%037! kernelSpinp = $ff47.%038!This is the error code value this package returns if it detects that a deviceis not Fast..%039! errNotBurstDevice = 10.%040!.%041! burstFilenameLen = burstBufCount.%042!.%043! burstOpen = * ;(.A=Device, burstBuf=Filename, .X=NameLen):Set up for a burst open: clear the Fast flag and the device not present flag..%044! stx burstFilenameLen.%045! pha.%046! lda serialFlag.%047! and #%10111111.%048! sta serialFlag.%049! lda #0.%050! sta ioStatus.%051! plaCommand the disk device to Listen. Then check if the device is present or not(bit 7 of ioStatus). If not present, return the kernel error code..%052! jsr kernelListen.%053! bit ioStatus.%054! bpl +.%055!.%056! devNotPresent = *.%057! jsr kernelUnlsn.%058! lda #5.%059! sec.%060! rts.%061!Tell disk device to listen on the command channel (channel #15)..%062! + lda #$6f.%063! jsr kernelSecondSend the "U0"+CHR$(159) burst command header..%064! lda #"u".%065! jsr kernelCiout.%066! bit ioStatus.%067! bmi devNotPresent.%068! lda #"0".%069! jsr kernelCiout.%070! lda #$9f.%071! jsr kernelCioutSend the filename..%072! ldy #0.%073! - lda burstBuf,y.%074! jsr kernelCiout.%075! iny.%076! cpy burstFilenameLen.%077! bcc -Finish sending the burst command and make sure the device is Fast..%078! jsr kernelUnlsn.%079! lda serialFlag.%080! and #$40.%081! bne +.%082! sec.%083! lda #errNotBurstDevice.%084! rts.%085!Disable interrupts..%086! + seiPrepare to receive data and signal the disk drive to start sending (bytoggling the slow serial Clock line)..%087! clc.%088! jsr kernelSpinp.%089! bit ciaIcr.%090! lda ciaSerialClk.%091! eor #$10.%092! sta ciaSerialClkRead the first sector of the file..%093! jsr burstReadCheck for errors. Burst error code 2 (file not found) is translated to itskernel equivalent..%094! lda burstStatus.%095! cmp #2.%096! bcc +.%097! bne shortFile.%098! sec.%099! lda #4.%100! + rts.%101!Check if this is a one-block file..%102! shortFile = *.%103! cmp #$1f.%104! bne openError.%105! ldy burstBufCount.%106! ldx #2.%107!If so, we have to read the two bytes that the disk drive forgot to tell usabout. For each byte, we wait for for the Shift Register Ready signal, togglethe clock, and read the shift data register. I can get away with reading thedata register after sending the acknowledge signal to the disk drive because Iam running with interrupts disabled and it could not possibly send the nextbyte before I pick up the current one. We wouldn't want any NMIs happeningwhile doing this, though..%108! shortFileByte = *.%109! lda #$08.%110! - bit ciaIcr.%111! beq -.%112! lda ciaSerialClk.%113! eor #$10.%114! sta ciaSerialClk.%115! lda ciaData.%116! sta burstBuf,y.%117! iny.%118! dex.%119! bne shortFileByteStore the updated byte count and exit..%120! sty burstBufCount.%121! clc.%122! rts.%123!In the event of a burst error, re-enable the interrupts since the user mightnot call the burstClose routine. Return the translated error code..%124! openError = *.%125! cli.%126! sec.%127! ora #$10.%128! rts.%129!Read the next sector of the file..%130! burstRead = * ;( ) : burstBuf, burstBufCount, burstStatusWait for the status byte to arrive..%131! lda #8.%132! - bit ciaIcr.%133! beq -Toggle clock line for acknowledge..%134! lda ciaSerialClk.%135! eor #$10.%136! sta ciaSerialClkGet status byte and check. If 2 or more and not $1F, then an error hasoccurred. If 0, then prepare to read 254 data bytes..%137! lda ciaData.%138! sta burstStatus.%139! ldx #254.%140! cmp #2.%141! bcc actualRead.%142! cmp #$1f.%143! bne openErrorIf status byte is $1F, then get the next byte, which tells how many data bytesare to follow..%144! lda #8.%145! - bit ciaIcr.%146! beq -.%147! ldx ciaData.%148! lda ciaSerialClk.%149! eor #$10.%150! sta ciaSerialClk.%151!.%152! actualRead = *.%153! stx burstBufCount.%154! ldy #0.%155!Read the data bytes and put them into the burst buffer. The clock line togglevalue is computed before receiving the data for a little extra zip. I haven'texperimented with this, but you might be able to toggle the clock line beforereceiving the data (however, probably not for the first byte)..%156! readByte = *.%157! lda ciaSerialClk.%158! eor #$10.%159! tax.%160! lda #8.%161! - bit ciaIcr.%162! beq -.%163! stx ciaSerialClk.%164! lda ciaData.%165! sta burstBuf,y.%166! iny.%167! cpy burstBufCount.%168! bne readByte.%169! + clc.%170! rts.%171!Close the burst package: simply CLI..%172! burstClose = *.%173! cli.%174! clc.%175! rts.%176!.%177! ;========== main program ==========.%178!This is the word counting application code..%179! bkWC = $0e.%180! bkSelect = $ff00.%181! kernelChrin = $ffcf.%182! kernelChrout = $ffd2.%183!The "wcInWord" is a boolean variable that tells whether the file scanner iscurrently in a word or not. The Lines, Words, and Bytes are 24-bit counters..%184! wcInWord = 2 ;(1).%185! wcLines = 3 ;(3).%186! wcWords = 6 ;(3).%187! wcBytes = 9 ;(3).%188!.%189! main = *Put the kernel ROM and I/O space into context then initialize the countingvariables..%190! lda #bkWC.%191! sta bkSelect.%192! jsr wcInitFollow the burst reading procedure outline..%193! jsr wcGetFilename.%194! jsr burstOpen.%195! bcc +.%196! jsr reportError.%197! rts.%198! / jsr wcScanBuffer.%199! lda burstStatus.%200! cmp #$1f.%201! beq +.%202! jsr burstRead.%203! bcc -.%204! jsr reportError.%205! + jsr burstCloseReport the numbers of lines, words, and characters and then exit..%206! jsr wcReport.%207! rts.%208!Initialize the variables..%209! wcInit = *.%210! lda #0.%211! ldx #8.%212! - sta wcLines,x.%213! dex.%214! bpl -.%215! sta wcInWord.%216! rts.%217!Get the device and filename from the user. Returns parameters suitable forpassing to burstOpen..%218! wcGetFilename = * ;() : burstBuf=Filename, .A=Device, .X=FilenameLenDisplay the prompt..%219! ldx #0.%220! - lda promptMsg,x.%221! beq +.%222! jsr kernelChrout.%223! inx.%224! bne -Get the input line from the user..%225! + ldx #0.%226! - jsr kernelChrin.%227! sta burstBuf,x.%228! cmp #13.%229! beq +.%230! inx.%231! bne -.%232! + jsr kernelChroutExtract the device number from the start of the input line. If it is notthere, assume device number 8..%233! lda #8.%234! cpx #2.%235! bcc filenameExit.%236! ldy burstBuf+1.%237! cpy #":".%238! bne filenameExit.%239! sec.%240! lda burstBuf.%241! sbc #"a"-8.%242! tayIf a device name was present, then we have to move the rest of the filenameback over it now that we've extracted it..%243! ldx #0.%244! - lda burstBuf+2,x.%245! sta burstBuf,x.%246! cmp #13.%247! beq +.%248! inx.%249! bne -.%250! + tya.%251! filenameExit = *.%252! rts.%253!.%254! promptMsg = *.%255! .asc "enter filename in form filename, or a:filename, ".%256! .asc "or b:filename, ...".%257! .byte 13.%258! .asc "where 'a' is for device 8, 'b' is for device 9, ...".%259! .byte 13,0.%260!Scan the burst buffer after reading a sector into it..%261! wcScanBuffer = *.%262! ldy #0.%263! cpy burstBufCount.%264! bne +.%265! rts.%266! + ldx wcInWord.%267! - lda burstBuf,y.%268! ; jsr kernelChrout ;uncomment this line to echo the data read.%269! cmp #13.%270! bne +If the current character is a carriage return, then increment the line count..%271! inc wcLines.%272! bne +.%273! inc wcLines+1.%274! bne +.%275! inc wcLines+2If the character is a TAB, SPACE, or a RETURN, then it is a Delimiter;otherwise, it is considered a Letter..%276! + cmp #33.%277! bcs isLetter.%278! cmp #" ".%279! beq isDelimiter.%280! cmp #13.%281! beq isDelimiter.%282! cmp #9.%283! beq isDelimiter.%284!.%285! isLetter = *If the character is a Letter and the previous one was a Delimiter, thenincrement the word count..%286! cpx #1.%287! beq scanCont.%288! ldx #1.%289! inc wcWords.%290! bne scanCont.%291! inc wcWords+1.%292! bne scanCont.%293! inc wcWords+2.%294! jmp scanCont.%295!.%296! isDelimiter = *.%297! ldx #0.%298!.%299! scanCont = *.%300! iny.%301! cpy burstBufCount.%302! bcc -Add the number of bytes in the burst buffer to the total byte count for thefile..%303! clc.%304! lda wcBytes.%305! adc burstBufCount.%306! sta wcBytes.%307! bcc +.%308! inc wcBytes+1.%309! bne +.%310! inc wcBytes+2.%311! + stx wcInWord.%312! rts.%313!Report the number of lines, words, and bytes read. Uses a "printf" type ofscheme..%314! wcReport = *.%315! ldx #0.%316! - lda reportMsg,x.%317! beq reportExit.%318! cmp #13.%319! bcs +.%320! stx 14.%321! tax.%322! lda 2,x.%323! sta 15.%324! lda 0,x.%325! ldy 1,x.%326! ldx 15.%327! jsr putnum.%328! ldx 14.%329! jmp reportCont.%330! + jsr kernelChrout.%331! reportCont = *.%332! inx.%333! bne -.%334! reportExit = *.%335! rts.%336!.%337! reportMsg = *.%338! .byte 13.%339! .asc "lines=".%340! .byte wcLines.%341! .asc ", words=".%342! .byte wcWords.%343! .asc ", chars=".%344! .byte wcBytes,27.%345! .asc "q".%346! .byte 13,0.%347!Reports the error number given in the .A register. Called after an error isreturned from a burst routine..%348! reportError = * ;( .A=errNum ).%349! pha.%350! ldx #0.%351! - lda errorMsg,x.%352! beq +.%353! jsr kernelChrout.%354! inx.%355! bne -.%356! + pla.%357! ldy #0.%358! ldx #0.%359! jsr putnum.%360! lda #13.%361! jsr kernelChrout.%362! rts.%363!.%364! errorMsg = *.%365! .asc "*** i/o error #".%366! .byte 0.%367!.%368! ;==========library==========.%369!Routine to print out the 24-bit number given in .AYX..%370! libwork = $60.%371! itoaBin = libwork.%372! itoaBcd = libwork+3.%373! itoaFlag = libwork+7.%374!.%375! putnum = *Initialize binary and BCD (Binary Coded Decimal) representations of number..%376! sta itoaBin+0.%377! sty itoaBin+1.%378! stx itoaBin+2.%379! ldx #3.%380! lda #0.%381! - sta itoaBcd,x.%382! dex.%383! bpl -.%384! sta itoaFlag.%385! ldy #24.%386! sed.%387!Rotate each bit out of the binary number and then multiply the BCD number bytwo and add the bit in. Effectively, we are shifting the bits out of thebinary number and into the BCD representation of the number..%388! itoaNextBit = *.%389! asl itoaBin+0.%390! rol itoaBin+1.%391! rol itoaBin+2.%392! ldx #3.%393! - lda itoaBcd,x.%394! adc itoaBcd,x.%395! sta itoaBcd,x.%396! dex.%397! bpl -.%398! dey.%399! bne itoaNextBit.%400! cldTake the BCD bytes and spit out the two digits they contain..%401! ldx #0.%402! ldy #0.%403! - lda itoaBcd,x.%404! jsr itoaPutHex.%405! inx.%406! cpx #4.%407! bcc -.%408! rts.%409!.%410! itoaPutHex = *.%411! pha.%412! lsr.%413! lsr.%414! lsr.%415! lsr.%416! jsr itoaPutDigit.%417! pla.%418! and #$0f.%419!Print out the individual digits of the number. If the current digit is zeroand all digits so far have been zero, then don't output anything, unless it isthe last digit of the number..%420! itoaPutDigit = *.%421! cmp itoaFlag.%422! bne +.%423! cpy #7.%424! bcc itoaPutDigitExit.%425! + ora #$30.%426! sta itoaFlag.%427! jsr kernelChrout.%428! itoaPutDigitExit = *.%429! iny.%430! rts
begin 640 wcM`1P<'`H`GB`W,C`P(#H@CR`V-3`R(%!/5T52(0``````3!$=AO](K1P**;^-M'`JI`(60:""Q_R20$`<@KO^I!3A@J6\@D_^I52"H_R20,.NI,""H_ZF?(*C_MH`"Y``L@J/_(Q/^0]2"N_ZT<"BE`T`0XJ0I@>!@@1_\L#=RM`-U)$(T`W2"]M'*7^R0*0!=`$.*D$8,D?T"&D_Z("J0@L#=SP^ZT`W4D0C0#=K0SMYX3_&&!8.`D08*D(+`W<\/NM`-U)$(T`W:T,W(7^HO[)`I`6R1_0W:D(+`W<M\/NN#-RM`-U)$(T`W8;_H`"M`-U)$*JI""P-W/#[C@#=K0SM8%@88*D.C0#_(#T=($D=(",I?[)'_`((+TM6QY@J0"B")4#RA#[A0)@H@"]C1WP!B#2_^C0]:(`(,__G0`+R0WP`^C0\R#2MLZD(X`*0'JP!"\`ZT!M24Q%3D%-12!)3B!&3U)-($9)3$5.04U%+"!/4B!!.D9)3$5.04U%+"!/4B!"M.D9)3$5.04U%+"`N+BX-5TA%4D4@)T$G($E3($9/4B!$159)0T4@."P@)T(GM($E3($9/4B!$159)0T4@.2P@+BXN#0"@`,3_T`%@I@*Y``O)#=`*Y@/0!N8$MT`+F!H@#(Q/^0MQ1BE"67_A0F0!N8*T`+F"X8"8*(`O8(>\!_)#;`5A@ZJM0*%#[4`M`&F#R#,M'J8.3'X>(-+_Z-#<8`U,24Y%4ST#+"!73U)$4ST&+"!#2$%24ST)&U$-`$BBM`+V\'O`&(-+_Z-#U:*``H@`@S!ZI#2#2_V`J*BH@22]/($524D]2(",`A6"$M889BH@.I`)5CRA#[A6>@&/@&8"9A)F*B`[5C=6.58\H0]XC0[-BB`*``M6,@D!!_HX`20]F!(2DI*2B`/'V@I#\5GT`3`!Y`'"3"%9R#2_\A@`````end