title '8502 drivers 4 Dec 85' maclib x6502 maclib z80 maclib cxequ $-MACRO ; ; COMMON EQUATES ; ; page 0 variables, from 0a to 8f are usable ; prtno equ 0000Ah ; 0Ah second$adr equ prtno+1 ; 0Bh DATCHN equ second$adr+1 ; 0Ch CMDCHN equ datchn+1 ; 0Dh DEVNO equ cmdchn+1 ; 0Eh adr$1 equ devno+1 ; 0Fh temp$byte equ adr$1+2 ; 11h ; equ temp$byte+1 ; 12h pal$nts equ 00a03h ; FF=PAL=50Hz 0=NTSC=60Hz serial equ 00a1ch d2pra equ 0dd00h ; serial control port (clk and data) d1sdr equ 0dc0ch ; Fast serial data reg. d1icr equ 0dc0dh ; serial channel interrupt control reg clkbit equ 10h ; d2pra clock bit mask ; ; KERNAL EQUATES ; K$spin$spout equ 0FF64h ; C=0 spin C=1 spout K$setbnk equ 0FF68h ; set the logical bank # for open ; disk commands ;I A=load and store bank # (C128 type bank) ; X=file name bank # K$readst equ 0FFB7h ; read status byte ;O A = status K$setlfs equ 0FFBAh ; setup a logical file ;I A=logical file # ; X=device # (0-31) ; Y=seconday command (FF if nane) K$setnam equ 0FFBDh ; set up file name for OPEN ;I A=name length ; X=low byte pointer to name ; Y=high byte pointer to name K$open equ 0FFC0h ; open a logical file (after setlfs ; and setnam) ;O A = error # (1,2,4,5,6,240) K$chkin equ 0FFC6h ; open a channel for input ;I X = logical file # ;O A = errors #(0,3,5,6) K$chkout equ 0FFC9h ; open a channel for output ;I X = logical file # ;O A = error #(0,3,5,7) K$clrchn equ 0FFCCh ; clears ALL I/O channel K$chrin equ 0FFCFh ; get a character from input channel ;O A=input character K$chrout equ 0FFD2h ; output a character to output channel ;I A =output char ;GETIN equ 0FFE4h K$clall equ 0FFE7h ; close ALL open logical files K$close equ 0FFC3h ; close a logical file ;I A = logical channel # to be closed ;O A = error #(0,240) RESET equ 0FFFCh PAGE ; org bios8502 ; ; **** THIS IS THE COMMAND LOOP **** ; start: @ldx -1,# ;-K @txs ;-K set the stack to the top @JSR VICIO ;-K go find and do requested operation bios$exit: @sei ;?K DISABLE INTERRUPTS @ldx 3eh,# ;?K set up Z80 memory map as required @stx force$map ;?K @ldx 82h,# ;-K @stx CIA1+int$ctrl ;-K turn on CIA timer B interrupts @jmp enable$z80+6 ;-K PAGE ; ; ; iotbl: dw sys$reset ;-1 reset system (C128) dw initilize ;0 initialize the 8502 dw READ ;1 Read a sector of data to sector buffer dw WRITE ;2 Write a " " " " " " dw readf ;3 Set-up for fast read (154X only) dw writef ;4 Set-up for fast write (154X only) dw dsktst ;5 test for 154x and diskette type dw query$dsk ;6 get disk characteristics dw PRINT ;7 print data character dw FORMAT ;8 format disk as 1541 disk dw user$fun ;9 vector to user code (L=viccount,H=vicdata) dw ram$dsk$rd ;10 RAM disk read dw ram$dsk$wr ;11 RAM disk write NUMCMD equ ($-IOTBL)/2 ; NUMBER OF COMMANDS iotbl$low equ low(iotbl) ; ; ; sys$reset: ;**CMD ENTRY** @jsr en$kernal ;-K @JMP (RESET) ;+K ; ; ; user$fun: ;**CMD ENTRY** @jmp (vic$count) ;-K page ; ; **** IO COMMAND DISPATCH ROUTINE **** ; VICIO: @lda vic$cmd ;-K get the command @cmp NUMCMD,# ;-K is this a valid command @bcs bad$command ;-K no, exit without doing anything ;-K yes, get vector to it @cld ;-K clear to binary mode @asl a ;-K A=2*CMD (carry cleared) @clc ;-K @adc iotbl$low+2,# ;-K add to vector table start address @sta VICIO2+1 ;-K modify the JMP instructions ind adr VICIO2: @jmp (IOTBL) ;-K this is the ind adr that ; is modified above ; ; ; input$byte: @sei @lda d2pra @eor clk$bit,# @sta d2pra ; @lda 8,# in$1: @bit d1icr @beq in$1 @lda d1sdr bad$command: @RTS ;-K page ; ; initialize the 8502 ; initilize: ;**CMD ENTRY** @ldx low(irqs),# ;-K @ldy high(irqs),# ;-K @stx 314h ;-K IRQ vector @sty 315h ;-K @stx 316h ;-K BRK vector @sty 317h ;-K @stx 318h ;-K NMI vector @sty 319h ;-K @jsr en$kernal ;-K @lda 0fffeh ;+K @sta 0fffeh ;+K write to RAM under ROM @lda 0ffffh ;+K @sta 0ffffh ;+K @lda 6,# ;+K @sta CIA2+data$dir$b ;+K setup user port for RS232 @lda pal$nts ;+K -1=50Hz(PAL) 0=60Hz(NTSC) @sta sys$freq ;+K @jmp K$clall ;+K close all open files PAGE ; ; **** DISK SECTOR READ **** ; READ: ;**CMD ENTRY** @JSR set$drv ;-K @jsr en$kernal ;+K @ldx datchn ;+K @jsr K$chkin ;+K @bcs disk$changed ;+K @jsr K$clrchn ;+K clear the input channel for now @LDA '1',# ;+K read command @JSR setup ;+K send it @JSR CKINDT ;+K @LDX 0,# ;+K ; READ1: @JSR K$chrin ;+K get a byte from the KERNAL @STA @BUFFER,X ;+K save it in the buffer @INX ;+K advance the buffer pointer @BNE READ1 ;+K loop back if not past buf end @jmp K$clrchn ;+K CLEAR CHANNEL ; ; disk$changed: @lda 0bh,# ;?K disk changed error code @sta vic$data ;?K @jmp en$K$open ;?K page ; ; **** DISK SECTOR WRITE **** ; WRITE: ;**CMD ENTRY** @jsr set$drv ;-K @jsr ckotcm ;-K @LDY setpnt$lng,# ;+K ; WRITE0: @LDA SETPNT,X ;+K @JSR K$chrout ;+K @INX ;+K @DEY ;+K @BNE WRITE0 ;+K @JSR K$clrchn ;+K @JSR CKINCM ;+K @BNE WRITE2 ;+K @JSR K$clrchn ;+K @JSR CKOTDT ;+K @LDX 0,# ;+K ; WRITE1: @sei ;+K disable interrupts @ldy 3fh,# ;+K enable all RAM in bank 0 @sty force$map ;+K @LDA @BUFFER,X ;-K @ldy 0,# ;-K re-enable kernal @sty force$map ;-K ; @cli ;+K interrupts back on @JSR K$chrout ;+K write buffer character @INX ;+K @BNE WRITE1 ;+K write all 256 bytes of buffer @JSR K$clrchn ;+K clear the channel @LDA '2',# ;+K write command @JMP setup ;+K ; WRITE2: @lda 0ffh,# ;+K @sta vic$data ;+K writes thru ROM to RAM @jmp opencm ;+K page ; ; Set-up for fast disk write ; writef: ;**CMD ENTRY** @lda 2,# ;-K 2=read command @skip2 ;-K ; ; Set-up for fast disk read ; readf: ;**CMD ENTRY** @lda 0,# ;-K 0=read command @sta f$cmd ;-K @lda 0,# ;-K @sta vic$data ;-K @jsr set$drv$f ;-K @ldy f$cmd$lng,# ;-K command set above rd/wr @jsr send$fast ;-K @jmp clk$hi ;+K page ; ; test the format of the disk return code to CP/M ; telling the disk type. Also test for FAST disk drive. ; dsktst: ;**CMD ENTRY** @lda vic$drv ;-K @eor 0ffh,# ;-K @and fast ;-K @sta fast ;-K clear fast indicator bit for current drive @jsr set$and$open ;-K set drv close and reopen the channel @ldx 0,# ;+K delay to allow drive to reset status tst$delay: @nop ;+K @nop ;+K @dex ;+K @bne tst$delay ;+K @ldy inq$cmd$lng,# ;+K @ldx inq$cmd,# ;+K @jsr send$fast$cmd ;+K @jsr input$byte ;+K @sta vic$data ;+K @jsr clk$hi ;+K @jsr dis$kernal ;+K @lda vic$drv ;-K @ora fast ;-K set current drive as fast @sta fast ;-K @rts ;-K page ; ; ; query$dsk: ;**CMD ENTRY** @jsr set$drv$f ;-K will query track set by user @ldy query$cmd$lng,# ;-K command length is 4 @ldx query$cmd,# ;-K @jsr send$fast$cmd ;-K @jsr input$byte ;+K @sta vic$data ;+K @bpl clk$hi ;+K exit if not MFM @and 0eh,# ;+K test for error @bne clk$hi ;+K exit if error @jsr input$byte ;+K read offset sectors status byte @sta @buffer ;+K @and 0eh,# ;+K test for error @bne clk$hi ;+K exit if error @tax ;+K get a zero in X @ldy 5,# ;+K five info bytes are sent back query$loop: @inx @jsr input$byte @sta @buffer,X @dey @bne query$loop clk$hi: @lda d2pra ;+K set clock bit HIGH @and 0ffh-clkbit,# @sta d2pra @rts PAGE ; ; **** PRINTER OUTPUT **** ; ; this routine will support two printers ; the device number is passed in vic$drv (4,5) ; secondary address in vic$trk ; the logical file number is equal to the device # ; if VIC$count=0 then output character in VIC$data ; if VIC$count<>0 then output characters pointered to by @buffer ; PRINT: ;**CMD ENTRY** @lda vic$drv ;-K @sta prtno ;-K @lda vic$trk ;-K @sta second$adr ;-K this line should be deleted and one @cmp second$adr ;-K ..below used. ;; @sta second$adr ;-K save secondary adr @bne reopen$prt ;-K @jsr en$kernal ;-K print$cont: @ldx prtno ;+K @JSR K$chkout ;+K @BCS PERR0 ;+K PRINT ERROR IF CARRY SET @jsr dis$kernal ;+K @ldx vic$count ;-K @bne print$buffer ;-K @LDA vic$data ;-K GET CHARACTER @sta io$0 ;-K @JSR K$chrout ;+K AND PRINT IT @JMP K$clrchn ;+K CLEAR CHANNEL print$buffer: @stx temp$byte ;-K @lda @buffer ;-K @sta adr$1 ;-K @lda @buffer+1 ;-K @sta adr$1+1 ;-K @ldy 0,# ;-K @ldx 0,# ;-K print$buf$loop: @sta bank$0 ;?K enable RAM bank 0 (no I/O) @lda (adr$1),y ;rK @stx force$map ;rK @jsr K$chrout ;+K @iny ;+K @dec temp$byte ;+K @bne print$buf$loop ;+K @jmp K$clrchn ;+K ; ; PERR0: @CMP 3,# ;+K FILE NOT OPEN? @BNE PERR1 ;+K BRANCH IF NO reopen$prt: @JSR OPNPRT ;?K OPEN PRINTER CHANNEL @BCC print$cont ;+K IF CARRY CLEAR, OK TO PRINT PERR1: @LDA 255,# ;+K NO DEVICE PRESENT @STA vic$data ;+K FLAG BAD ATTEMPT writes to ram under ROM PRTST: @RTS ;+K PAGE ; ; **** FORMAT DISK ROUTINE **** ; FORMAT: ;**CMD ENTRY** @jsr set$drv$num ;-K @lda fast ;-K @and vicdrv ;-K @bne format$fast ;-K @JSR CKOTCM ;-K returns X=0 @LDY fmtcmd$lng,# ;+K FMT1: @LDA FMTCMD,X ;+K @JSR K$chrout ;+K @INX ;+K @DEY ;+K @BNE FMT1 ;+K @JSR K$clrchn ;+K fmt2: @JSR CKINCM ;+K check for errors @BEQ setup3 ;+K no errors, return good status @BNE setup5 ;+K error return error status format$fast: @ldx @buffer ;-K get command length fast$F: ;-K @lda @buffer+1-1,x ;-K @sta F$cmd-1,x ;-K @dex ;-K transfer command tail from buffer+1 @bne fast$F @ldy @buffer ;-K @iny ;-K @iny ;-K count is tail length plus 2 @ldx F$cmd ;-K @jsr send$fast$cmd ;-K @jmp fmt2 ;+K PAGE ; ; ; ram$dsk$rd: ; RAM disk read @ldx 81h,# ;-K @skip$2 ;-K ; ; ; ram$dsk$wr: ; RAM disk write @ldx 80h,# ;-K @lda 3fh,# ;-K point to RAM bank 0 @stx RM$command ;-K @sta force$map ;-K @rts ;-K PAGE ; ; ; setup: @STA DSKCMD+1 ;?K @LDA 2,# ;?K RETRY COUNT @STA vic$data ;?K writes to RAM under ROM @JSR CKOTCM ;?K returns X=0 @LDY dskcmd$lng,# ;+K setup2: @LDA DSKCMD,X ;+K @JSR K$chrout ;+K @INX ;+K @DEY ;+K @BNE setup2 ;+K @JSR K$clrchn ;+K @JSR CKINCM ;+K @BEQ setup3 ;+K @jsr dis$kernal ;+K @DEC vic$data ;-K @BEQ setup5 ;-K @jmp disk$changed ;-k ; ; setup5: @LDA 0dh,# ;?K normal read/write error flag @skip2 ;?K ALWAYS ; ; ; setup3: @lda 0,# ;?K get data good flag setup4: @STA vic$data ;?K writes to RAM under ROM @jsr en$kernal ;?K @JMP K$clrchn ;+K page ; ; ; send$fast$cmd: @jsr set$cmd ;?K unit # must have been set already send$fast: @ldx 0,# ;?K @stx force$map ;?K enable the kernal @ldx cmdchn ;+K @jsr K$chkout ;+K @bcs chan$error ;+K @ldx 0,# ;+K sendf: @lda f$cmd$buf,x ;+K @jsr K$chrout ;+K @inx ;+K @dey ;+K @bne sendf ;+K @jsr K$clrchn ;+K @bit serial ;+K @bvc not$fast ;+K @bit d1icr ;+K clear interrupts from chip @rts ;+K chan$error: @lda 0dh,# ;+K get error code @skip2 ;+K not$fast: @lda 0ch,# ;+K get error code @sta vic$data ;+K @jsr clk$hi ;+K @jmp bios$exit ;+K ; ; ; set$cmd: @lda dskcmd+5 ;?K check lsb of unit # @ror a ;?K get lsb to carry bit @bcc unit$0 ;?K @inx ;?K make command for unit 1 unit$0: @stx F$cmd ;?K @rts page ; ; ........not tested........ ; ;rd$buff: ; @sei ; disable interrupts ; @lda vic$data ; @sta adr$1+1 ; save hi part of address ; @lda 0,# ; @sta adr$1 ; save low part of address ; @tax ; get a zero for both indexes ; @tay ; ;rd$buf$1: ; @lda (adr$1),y ; @sta @buffer,x ; @inx ; @iny ; @bne rd$buf$1 ; @rts PAGE ; ; ; set$drv: @lda vic$trk ;-K @jsr binasc ;-K @stx dskcmd+7 ;-K @sta dskcmd+8 ;-K @lda vic$sect ;-K @bmi no$side$1 ;-K @jsr binasc ;-K @stx dskcmd+10 ;-K @sta dskcmd+11 ;-K @jmp set$drv$num ;-K no$side$1: @lda 04h,# ;-K @sta vic$data ;-K @jmp bios$exit ;-K ; ; ; set$drv$f: @lda vic$count ;-K @sta f$rd$count ;-K @lda vic$trk ;-K @sta f$rd$trk @lda vic$sect ;-K @bpl side$0 ;-K @tax ;-K @lda f$cmd ;-K @ora 10h,# ;-K @sta f$cmd ;-K @txa ;-K @and 7fh,# ;-K side$0: @sta f$rd$sect ;-K page ; ; VIC$DRV dev,dat,cmd ; 00000001 device #8-0 8,11,15 ; 00000010 device #9-0 9,12,16 ; 00000100 device #10-0 10,13,17 ; 00001000 device #11-0 11,14,18 ; 10000001 device #8-1 8,11,15 ; 10000010 device #9-1 9,12,16 ; 10000100 device #10-1 10,13,17 ; 10001000 device #11-1 11,14,18 ; set$drv$num: ; @cli ;-K @ldy 8-1,# ;-K start as drive 8 @ldx '0',# ;-K ..unit 0 @lda vic$drv ;-K get requested drv# @bpl unit$nu$0 @inx ;-K make unit 1 unit$nu$0: @iny ;-K add one to the drive # @lsr a ;-K is drive number correct? @bcc unit$nu$0 ;-K no, loop back @stx dskcmd+5 ;-K save unit# to disk cmd string @stx fmtcmd+1 ;-K save unit# to format cmd string @txa @ror a ;-K get lsb to carry bit @lda F$cmd @and 0feh,# @adc 0,# ; set the lsb if carry set (carry cleared) @sta F$cmd @tya ;-K get device # to A @sta devno ;-K save device # @adc 3,# ;-K make the data chan# (carry cleared above) @sta datchn ;-K save data chan# @adc 4,# ;-K make the cmd chan# @sta cmdchn ;-K save cmd chan# @lda serial ;-K @and 0bfh,# ;-K @sta serial ;-K clear the fast serial indicator @rts ;-K page ; ; **** CONVERT BINARY TO ASCII **** ; BINASC: @CLD ;?K @LDX '0',# ;?K @SEC ;?K BA0: @SBC 10,# ;?K @BCC BA1 ;?K @INX ;?K @BCS BA0 ;?K BA1: @ADC 3Ah,# ;?K @RTS ;?K PAGE ; ; **** OPEN DISK COMMAND CHANNEL **** ; set$and$open: @jsr set$drv$num ;-K en$K$open: @jsr en$kernal ;-K opencm: @LDA CMDCHN ;+K @clc ;+K clear the carry to force true closing @JSR K$close ;+K @LDA CMDCHN ;+K @LDX DEVNO ;+K @LDY 15,# ;+K @JSR K$setlfs ;+K @lda 0,# ;+K bank (C128 type) for load and store @sta F$stat ;+K write status byte value = 0 @tax ;+K file name bank (C128 type bank#) @jsr K$setbnk ;+K @ldx write$stat,# ;+K @jsr set$cmd ;+K @lda 4,# ;+K write status command lenght @ldx low(f$cmd$buf),# ;+K @ldy high(f$cmd$buf),# ;+K @JSR K$setnam ;+K @JSR K$open ;+K @bcs misdsk @JSR K$readst @ROL A ;+K GET MSB TO CARRY @BCS MISDSK ;+K DEVICE MISSING IF CARRY SET @bit serial ;+K test for fast device @bvs no$dt$open ;+K do not open data channel if fast ; ; **** OPEN DISK DATA CHANNEL **** ; OPENDT: @LDA DATCHN ;+K @clc ;+K forces true closing of channel @JSR K$close ;+K @LDA DATCHN ;+K @LDX DEVNO ;+K @LDY 8,# ;+K @JSR K$setlfs ;+K @lda 0,# ;+K bank (C128 type) for load and store @tax ;+K file name bank (C128 type bank#) @jsr K$setbnk ;+K @LDA 1,# ;+K @LDX low(POUND),# ;+K @LDY high(POUND),# ;+K @JSR K$setnam ;+K @jsr K$open ;+K @bcs misdsk no$dt$open: @rts page ; ; ; * DEVICE MISSING, CLEAN UP ERROR * ; MISDSK: @LDA 0fh,# ;+K SET ERROR CODE for missing drive @STA vic$data ;+K writes to RAM under ROM @LDA CMDCHN ;+K K$close CHANNEL @clc ;+K force true closing of channel @JSR K$close ;+K @JMP bios$exit ;+K PAGE ; ; **** SELF CORRECTING CHECK IO ROUTINES **** ; CKICM: @JSR OPENCM ;+K CKINCM: @LDX CMDCHN ;+K @JSR K$chkin ;+K @BCS CKICM ;+K @JSR K$chrin ;+K @CMP '0',# ;+K @RTS ;+K ; ; ; CKIDT: @JSR OPENDT ;+K CKINDT: @LDX DATCHN ;+K @JSR K$chkin ;+K @BCS CKIDT ;+K @RTS ;+K ; ; ; CKODT: @JSR OPENDT ;+K CKOTDT: @LDX DATCHN ;+K @JSR K$chkout ;+K @BCS CKODT ;+K @RTS ;+K ; ; ; CKOCM: @jsr OPENCM ;+K CKOTCM: @jsr en$kernal ;?K @LDX CMDCHN ;+K @JSR K$chkout ;+K @BCS CKOCM ;+K @LDX 0,# ;+K @RTS ;+K PAGE ; ; **** OPEN PRINTER CHANNEL **** ; opnprt: @jsr en$kernal ;-K @lda prtno ;+K @clc ;+K @JSR K$close ;+K @lda prtno ;+K @TAX ;+K LDX #4 (or #5) @ldy second$adr ;+K secondary adr passed in vic$trk (normaly=7) @JSR K$setlfs ;+K @LDA 0,# ;+K @JSR K$setnam ;+K @lda 0,# ;+K bank (C128 type) for load and store @tax ;+K file name bank (C128 type bank#) @jsr K$setbnk ;+K @JMP K$open ;+K page ; ; handle all interrupts in BIOS 8502 (throw them away) ; irqs: @lda CIA$1+int$ctrl @lda CIA$2+int$ctrl @lda 0fh,# @sta VIC+25 @pla @sta force$map @pla @tay @pla @tax @pla @rti ; ; ; en$kernal: @ldy 0,# ;?K @sty force$map ;?K ; @cli ;+K enable interrupts @rts ;+K ; ; ; dis$kernal: @sei ;?K disable interrupts @ldy 3eh,# ;?K @sty force$map ;?K @rts ;-K page ; ; ; DSKCMD: db 'U1:8 0 tt ss',CR dskcmd$lng equ $-dskcmd POUND: db '#' FMTCMD: db 'N0:CP/M DISK,65',CR fmtcmd$lng equ $-FMTCMD SETPNT: db 'B-P 8 0',CR setpnt$lng equ $-setpnt ; ; fast command buffer ; f$cmd$buf: db 'U0' ; not set f$cmd: db 0 ; byte 3 F$stat: f$rd$trk: db 1 ; byte 4 f$rd$sect: db 0 ; byte 5 f$rd$count: db 1 ; byte 6 db 0 ; byte 7 db 0 ; byte 8 db 0 ; byte 9 db 0 ; byte 10 db 0 ; byte 11 f$cmd$lng equ 6 ; U0+cmd+track+sector+#sectors write$stat equ 01001100b write$stat$lng equ 4 ; U0+cmd+(status to write) inq$cmd: equ 00000100b inq$cmd$lng equ 3 ; U0+cmd query$cmd: equ 10001010b query$cmd$lng equ 4 ; U0+cmd+(track offset)