; CC.PROM.TEXT --------------------------------------------------------- ; ; CC.PROM -- Corvus CONCEPT Workstation PROM ; ; Copyright 1982 Corvus Systems, Inc. ; San Jose, California ; ; All Rights Reserved ; ; v 0.1 05-06-82 LEF Original program ; v 0.2 05-27-82 LEF Add keyboard driver (kb) ; Add display driver (mb) ; Add 8" Corvus floppy disk driver/boot ; Finds first local disk for booting ; OMNINET disk driver modifications ; v 0.3 06-21-82 LEF Add MACSBUG interface ; Add 5" floppy driver/boot ; Finds first floppy disk for booting ; Local disk driver modifications ; OMNINET disk driver modifications ; v 0.4 06-29-82 LEF Add time out to OMNINET short commands ; v 0.5 08-18-82 KB Modified MacsBug interface ; Modified Apple 5" floppy driver ; v 0.6 10-29-82 LEF Swap BACKSPACE and \ keys ; Modified display driver ; v 0.7 05-01-83 LEF Remove Apple floppy boot ; Add auto PROM boot ; OMNINET disk driver modifications ; KB Add DSDD floppy driver/boot (rev B) ; v 0.8 07-01-83 LEF Add Concept Plus, Uniplex, Venus support ; 09-14-83 KB Enhanced and changed Uniplex support ; ;{!CC} Concept version 0.8 ;----------------------------------------------------------------------- ;{!CC} {/SC} {CV} ;select generic Concept/Venus 0.8 ; ;{!CC} {/SC} {DS} ;select units with a display 0.8 ; ; ; File: P.PROM.TEXT ; Date: 15-Nov-83 ; By: L. Franklin changes by K. Ball ; ; +-----+----------------+ ; Stag PROM checksums: | | | ; | H | | ; | | | ; +-----+----------------+ ; | | | ; | L | | ; | | | ; +-----+----------------+ page ; File: CC.PROM.EQ.TEXT ; Date: 20-Oct-83 ; ;ROMvers equ 0 ;Current PROM version number PROMvers equ 15 ;Current PROM version number (interim) PROMlevl equ 8 ;Current PROM level number ; RAMbase equ $00000 ;Base address of low RAM RAMlen equ $1000 ;Length of low RAM (4k bytes) RAMkbbuf equ RAMbase+$300 ;Start of keyboard buffer RAMkblen equ $100 ;Length of keyboard buffer RAMmxbug equ RAMbase+$400 ;Start of MACSBUG RAM RAMwksta equ RAMbase+$700 ;Start of workstation RAM RAMend equ RAMbase+RAMLen ;End address + 1 of low RAM ; ROMbase equ $10000 ;Base address of workstation PROM ROMlen equ $2000 ;Length of workstation PROM ROMend equ ROMbase+ROMlen ;End address + 1 of workstation PROM ; MXBbase equ $20000 ;Base address of MACSBUG (if present) MXBlen equ $2000 ;Length of MACSBUG MXBend equ MXBbase+MXBlen ;End address + 1 of MACSBUG MXBinit equ MXBbase+4 ;Address of MacsBug init vector 0.5 MXBentry equ MXBbase+8 ;Address of MacsBug entry vector 0.5 ; IOPbase equ $30000 ;Base address of I/O pg IOPprom equ IOPbase+$0200 ;Base address of slot PROMs 0.7 VIAbase equ IOPbase+$0F00 ;Base address of VIA registers ; DSPbase equ $80000 ;{!CC}Base address of display buffer 0.8 DSPlen equ $0E000 ;{!CC}Length of display buffer 0.8 DSPend equ DSPbase+DSPlen ;{!CC}End address + 1 of display buffer 0.8 USRbase equ DSPend ;{!CC}Base address of user RAM 0.8 ; ; ; MEMprom equ $90000 ;memory limit if not in PROM 0.7 MEM256k equ $BFFFC ;memory limit for 256k system 0.7 MEM512k equ $FFFFC ;{!CV};memory limit for 512k system 0.7 page ; ; Corvus CONCEPT Workstation interrupt vector definition ; IVlvl1 equ $64 ;level 1 interrupt vector (SLOTS) IVlvl2 equ $68 ;level 2 interrupt vector (DC1) IVlvl3 equ $6C ;level 3 interrupt vector (OMNINET) IVlvl4 equ $70 ;level 4 interrupt vector (DC0) IVlvl5 equ $74 ;level 5 interrupt vector (TIMER) IVlvl6 equ $78 ;level 6 interrupt vector (KYDB) IVlvl7 equ $7C ;level 7 interrupt vector ; ; Corvus CONCEPT Workstation static RAM address definition ; CPbtslot equ RAMwksta+$000 ;(700-700) boot slot number CPbtsrvr equ RAMwksta+$001 ;(701-701) boot server number ;(702-705) CPosslot equ RAMwksta+$006 ;(706-706) OS volume slot number CPossrvr equ RAMwksta+$007 ;(707-707) OS volume server number CPosdrv equ RAMwksta+$008 ;(708-708) OS volume drive number CPosblk equ RAMwksta+$009 ;(709-70B) OS volume block number CPtrnvrs equ RAMwksta+$00C ;(70C-70C) OMNINET transporter version CPtprnbr equ RAMwksta+$00D ;(70D-70D) OMNINET transporter number CPdiskRC equ RAMwksta+$00E ;(70E-70E) disk controller return code CPomniRC equ RAMwksta+$00F ;(70F-70F) OMNINET return code ; CPtimout equ RAMwksta+$010 ;(710-713) boot disk timeout value 0.7 CPblkio equ RAMwksta+$014 ;(714-717) boot disk blk i/o subr pointer CPdskio equ RAMwksta+$018 ;(718-71B) boot disk i/o subr pointer ; CPuserID equ RAMwksta+$01C ;(71C-725) user name (decrypted) CPusernm equ RAMwksta+$026 ;(726-72F) user name (encrypted) ; CPfinlv equ RAMwksta+$030 ;(730-733) floppy interleave table pointer CPfdvsz equ RAMwksta+$034 ;(734-735) floppy device size (blocks) CPfbps equ RAMwksta+$036 ;(736-737) floppy bytes per sector CPfspt equ RAMwksta+$038 ;(738-738) floppy sectors per track CPftps equ RAMwksta+$039 ;(739-739) floppy tracks per side CPfspd equ RAMwksta+$03A ;(73A-73A) floppy sides per disk CPfofst equ RAMwksta+$03B ;(73B-73B) floppy first track offset CPftyp equ RAMwksta+$03C ;(73C-73C) floppy type ; CPwndrcd equ RAMwksta+$040 ;(740-763) system window record (36 bytes) CPscnofs equ RAMwksta+$064 ;(764-765) bytes per display scan line CPdspflg equ RAMwksta+$066 ;(766-766) display flags CPbblen equ RAMwksta+$067 ;(767-767) blind boot user name length 0.8 CPbbname equ RAMwksta+$068 ;(768-76F) blind boot user name 0.8 page CPsl1typ equ RAMwksta+$071 ;(771-771) slot device type for slot 1 CPsl2typ equ RAMwksta+$072 ;(772-772) slot device type for slot 2 CPsl3typ equ RAMwksta+$073 ;(773-773) slot device type for slot 3 CPsl4typ equ RAMwksta+$074 ;(774-774) slot device type for slot 4 CPsl5typ equ RAMwksta+$075 ;(775-775) slot device type for slot 5 ; CPuserpw equ RAMwksta+$080 ;(780-787) user password (encrypted) 0.7 CPomnidv equ RAMwksta+$090 ;(790-7CF) network devices (64 bytes) 0.7 ; (indexed by transporter nbr) 0.7 CPsrvnam equ RAMwksta+$0D0 ;(7D0-7DA) disk server name (10 bytes) 0.8 ; CPomnram equ RAMwksta+$180 ;(880-88F) static RAM for OMNINET CPsl1ram equ RAMwksta+$200 ;(900-9FF) static RAM for slot 1 device CPsl2ram equ RAMwksta+$300 ;(A00-AFF) static RAM for slot 2 device CPsl3ram equ RAMwksta+$400 ;(B00-BFF) static RAM for slot 3 device CPsl4ram equ RAMwksta+$500 ;(C00-CFF) static RAM for slot 4 device ; CPiobuf equ RAMwksta+$600 ;(D00-EFF) I/O buffer (512 bytes) CPstack equ RAMwksta+$800 ;(F00-FFF) initial system stack CPextcrt equ RAMwksta+$800 ;(F00-F00) external CRT flag CPsysst equ RAMwksta+$801 ;(F01-F01) system initialization status CPistack equ RAMwksta+$8FC ;(FFC-FFC) initial system stack pointer ; CPomnibf equ USRbase-$30 ;OMNINET driver buffer (48 bytes) 0.8 ; (OMNINET can't access below $80000) page ; ; Corvus CONCEPT Workstation PROM address vector definitions ; CPsysrst equ ROMbase+$004 ;(10004) system restart pointer CPuniqid equ ROMbase+$008 ;(10008) unique workstation ID CPromvrs equ ROMbase+$00C ;(1000C) PROM version number CPromlvl equ ROMbase+$00D ;(1000D) PROM level number CPcksum equ ROMbase+$00E ;(1000E) PROM checksum ; CPobootj equ ROMbase+$010 ;(10010) jump to OMNINET disk boot subr CPoboot equ ROMbase+$012 ;(10012) OMNINET disk boot subr pointer CPoblkio equ ROMbase+$016 ;(10016) OMNINET disk blk i/o subr pointer CPodskio equ ROMbase+$01A ;(1001A) OMNINET disk i/o subr pointer ; CPlbootj equ ROMbase+$020 ;(10020) jump to local disk boot subr CPlboot equ ROMbase+$022 ;(10022) local disk boot subr pointer CPlblkio equ ROMbase+$026 ;(10026) local disk blk i/o subr pointer CPldskio equ ROMbase+$02A ;(1002A) local disk i/o subr pointer ; CPfbootj equ ROMbase+$030 ;(10030) jump to floppy disk boot subr CPfboot equ ROMbase+$032 ;(10032) floppy boot subr pointer CPfblkio equ ROMbase+$036 ;(10036) SSSD floppy blk i/o subr pointer CPfsctio equ ROMbase+$03A ;(1003A) SSSD floppy sector i/o subr pointer CPfinit equ ROMbase+$03E ;(1003E) SSSD floppy initialization ;Pablkio equ ROMbase+$042 ;(10042) Apple floppy blk i/o subr pointer ;Pasctio equ ROMbase+$046 ;(10046) Apple floppy sector i/o subr pointer ;Painit equ ROMbase+$04A ;(1004A) Apple floppy initialization CPxblkio equ ROMbase+$042 ;(10042) DDDS floppy blk i/o subr ptr 0.7 CPxsctio equ ROMbase+$046 ;(10046) DDDS floppy sctr i/o subr ptr 0.7 CPxinit equ ROMbase+$04A ;(1004A) DDDS floppy initialization 0.7 ; CPkbinit equ ROMbase+$050 ;(10050) initialize (reset) keyboard driver CPkbgetc equ ROMbase+$054 ;(10054) get a keyboard character ; CPdsinit equ ROMbase+$060 ;(10060) initialize display driver CPdsputc equ ROMbase+$064 ;(10064) display a character CPdsputs equ ROMbase+$068 ;(10068) display a string CPdscvuc equ ROMbase+$06C ;(1006C) convert character to upper case ; CPivec1 equ ROMbase+$070 ;(10070) level 1 interrupt vector (SLOTS) CPivec2 equ ROMbase+$074 ;(10074) level 2 interrupt vector (DC1) CPivec3 equ ROMbase+$078 ;(10078) level 3 interrupt vector (OMNINET) CPivec4 equ ROMbase+$07C ;(1007C) level 4 interrupt vector (DC0) CPivec5 equ ROMbase+$080 ;(10080) level 5 interrupt vector (TIMER) CPivec6 equ ROMbase+$084 ;(10084) level 6 interrupt vector (KYDB) CPivec7 equ ROMbase+$088 ;(10088) level 7 interrupt vector page ; ; Corvus CONCEPT Workstation I/O pg definitions ; IOkybd equ VIAbase+$05 ;(30F05) level 6 - keyboard 0.7 IOdc0 equ VIAbase+$25 ;(30F25) level 4 - data comm 0 0.7 IOdc1 equ VIAbase+$45 ;(30F45) level 2 - data comm 1 0.7 IObootsw equ VIAbase+$61 ;(30F61) boot selection switches IObeepfq equ VIAbase+$71 ;(30F71) beep frequency IOtimr equ VIAbase+$7D ;(30F7D) level 5 - timer 0.7 IOslot equ VIAbase+$7F ;(30F7F) level 1 - slots (port A ORA) 0.7 IOomni equ VIAbase+$C1 ;(30FC1) level 3 - OMNINET 0.7 ; ; Slot device types (set in CPsl1typ..CPsl5typ) ; DTndev equ 0 ;no device DTlocl equ 1 ;local disk DTomni equ 2 ;OMNINET disk DTc8 equ 3 ;Corvus 8" SSSD floppy disk DTc5 equ 4 ;Corvus 5" SSSD floppy disk (unused) DTa5 equ 5 ;Apple 5" floppy disk ; DTbank equ 6 ;Corvus BANK ; DTf8 equ 7 ;Corvus 8" DSDD floppy disk DTf5 equ 8 ;Corvus 5" DSDD floppy disk DTf3 equ 9 ;Corvus 3" DSDD floppy disk ; Miscellaneous equates ; off equ 0 ; on equ 1 ; false equ 0 ;Pascal FALSE boolean true equ 1 ;Pascal TRUE boolean jumpto equ $4EF9 ;"jmp" op code DskRead equ $32 ;disk read command DskWrit equ $33 ;disk write command NTO1 equ $00040000 ;{!CC};network timeout - broadcast NTO2 equ $07FFFFFF ;{!CC};network timeout - normal traffic ;{!CC}; (25 minutes) page ;driver address equates ; ; CC.PROM.KB -- Keyboard driver equates ; ; ; ADDRESSES OF KEYBOARD UART'S I/O REGISTERS ; KBRdata EQU VIAbase+$01 ;DATA INPUT PORT KBRstat EQU VIAbase+$03 ;STATUS REGISTER KBRcmnd EQU VIAbase+$05 ;COMMAND REGISTER KBRcntl EQU VIAbase+$07 ;CONTROL REGISTER ; ; External CRT equates ; KBcPort equ $30f21 ;data comm 0 UART pointer KBuDa equ 0 ;UART data port offset KBuSt equ 2 ;UART status port offset KBrdBit equ 3 ;busy bit for input ; ; CC.PROM.DS -- Display driver equates ; DShomeH equ $8D55E ;{!CC}horizontal home location 0.8 DShomeV equ $8D506 ;{!CC}vertical home location 0.8 DSdefOf equ 96 ;default bytes per scan line DScellW equ 6 ;character cell width DScellY equ 10 ;character cell height DSmaxXH equ 719 ;120*DScellW-1 DSmaxYH equ 559 ;56*DScellY-1 DSmaxXV equ 557 ;93*DScellW-1 DSmaxYV equ 719 ;72*DScellY-1 ; ; External CRT equates ; DScPort equ $30f21 ;data comm 0 UART pointer DSuDa equ 0 ;UART data port offset DSuSt equ 2 ;UART status port offset DSwrBit equ 4 ;busy bit for output ; ; CC.PROM.LD -- Local disk driver equates ; ; ; CC.PROM.OD -- Omninet disk driver equates ; StrAdr EQU $30FA1 ;address of Transporter register RdyAdr EQU $30F7F ;address of VIA register A, used for Omninet ready page ;driver address equates (continued) ; ; CC.PROM.FD -- Corvus 8" SSSD floppy disk driver equates ; ; FLOPPY MAIN EQUATES USED BY THE DRIVERS AND FORMAT CODE GROUPS. ; indices to code in static ram - ram is slot dependent $900 for ; $A00 for slot 2, $B00 for slot 3, and $C00 for slot 4. ; BASERAM equ CPsl1ram ;ADDRESS OF FIRST RAM FOR SLOTS BLKSZ equ 512 ;OS BLOCK SIZE ; ; SLOT BASE ADDRESSES ; ; The floppy controller is inserted into one of the slots. ; Each slot has two address select decodes coming to it. ; One is called NDEVSEL and the other is called SLOTSEL. ; NDEV1AD equ $30001 ;ADRS OF NDEV0 (does not exist) DEVADOFST equ $20 ;OFFSET OF OTHER NDEVS ADRS ; SLOT1AD equ $30001 ;ADRS OF slot 0 (does not exist) SLTADOFST equ $200 ;ADRS OFST FOR OTHER SLOTS ; SLTSTAD equ $30A01 ;SLOT STATUS ADRS ; ; CC.PROM.FB -- Corvus 8" DDDS floppy disk driver equates ; ; I/O slot base address ; IOSbase EQU $30001 ;as if a slot 0 existed IOSoffst EQU $20 ;offset to next slot ; DBPoffst EQU $100 ;offset to next pg of static ram MAXdrive EQU 4 ;maximum number of drives page ;vectors ; Corvus CONCEPT Workstation PROM address vectors ; org ROMbase ; data.l 0 ;(10000) initial stack pointer data.l setup ;(10004) start of PROM code data.l $FFFFFFFF ;(10008) unique workstation ID data.b PROMvers ;(1000C) PROM version number data.b PROMlevl ;(1000D) PROM level number data.w $FFFF ;(1000E) PROM checksum ; data.w jumpto ;(10010) jump to OMNINET disk boot subr data.l SBomni ;(10012) OMNINET disk boot subr pointer data.l ODblkIO ;(10016) OMNINET disk blk i/o subr pointer data.l ODdskIO ;(1001A) OMNINET disk i/o subr pointer data.w 0 ; ; data.w jumpto ;(10020) jump to local disk boot subr data.l SBlocal ;(10022) local disk boot subr pointer data.l LDblkIO ;(10026) local disk blk i/o subr pointer data.l LDdskIO ;(1002A) local disk i/o subr pointer data.w 0 ; ; data.w jumpto ;(10030) jump to floppy disk boot subr data.l SBflpy ;(10032) floppy boot subr pointer data.l FDblkIO ;{!CC};(10036) SSSD floppy blk i/o subr 0.8 data.l FDsecIO ;{!CC};(1003A) SSSD floppy sector i/o subr 0.8 data.l FDinit ;{!CC};(1003E) SSSD floppy initialization 0.8 ; ---- data.l ADblkIO ;(10042) Apple floppy blk i/o subr 0.7 ; ---- data.l ADsecIO ;(10046) Apple floppy sector i/o subr 0.7 ; ---- data.l ADinit ;(1004A) Apple floppy initialization 0.7 data.l FBblkIO ;(10042) DSDD floppy blk i/o subr 0.7 data.l FBsctIO ;(10046) DSDD floppy sector i/o subr 0.7 data.l FBinit ;(1004A) DSDD floppy initialization 0.7 data.w 0 ; data.l KBinit ;(10050) initialize (reset) keyboard driver data.l KBgetch ;(10054) get a keyboard character data.l 0 ;(10058) data.l 0 ;(1005C) data.l DSinit ;(10060) initialize display driver data.l DSputch ;(10064) display a character data.l DSputst ;(10068) display a string data.l DScvtuc ;(1006C) convert character to upper case data.l INTslot ;(10070) level 1 interrupt vector (SLOTS) data.l INTdc1 ;(10074) level 2 interrupt vector (DC1) data.l INTomni ;(10078) level 3 interrupt vector (OMNINET) data.l INTdc0 ;(1007C) level 4 interrupt vector (DC0) data.l INTtimr ;(10080) level 5 interrupt vector (TIMER) data.l INTkybd ;(10084) level 6 interrupt vector (KYDB) data.l INTlvl7 ;(10088) level 7 interrupt vector data.l 0 ;(1008C) list 0 msgcpy data.b 'Copyright ' ;Corvus CONCEPT data.b '1983 Corvus ' ; PROM data.b 'Systems, Inc.' ; copyright notice data.b 0 ; list 1 page ;Setup ; Initialize Corvus CONCEPT hardware ; Setup move.w #$2700,sr ;set priority to 7, nmi interrupt only lea CPistack.w, SP ;set system stack pointer 0.8 ; ; delay for possible Apple floppy reset *kb 8/23/82* 0.5 ; 0.5 MOVEQ #-1, D0 ;Must wait at least 1 second 0.8 Setup1 DBRA D0,Setup1 ;* 0.5 Setup2 DBRA D0,Setup2 ;* 0.5 Setup3 DBRA D0,Setup3 ;* 0.5 ; move.l #VIAbase,a6 ;get pointer to VIA I/O locations clr.w CPextcrt.w ;reset system flags (CPextcrt, CPsysst) move.b #$17,$07(a6) ;kybd control, 600 baud, 8 bit word move.b #$0B,$05(a6) ;kybd command, no parity, no interrupts move.b #$3E,$27(a6) ;dcom0 control, 9600 baud, 7 bit word move.b #$AB,$25(a6) ;dcom0 cmd mark parity, xmit & rcv w/o IRQ move.b #$3E,$47(a6) ;dcom1 control, 9600 baud, 7 bit word move.b #$AB,$45(a6) ;dcom1 command clr.b $7F(a6) ;VIA port A -- ok to read port before 0.8 clr.b $61(a6) ;VIA port B -- write byte of zero 0.8 move.b #$80,$67(a6) ;VIA data direction A move.b #$37,$65(a6) ;VIA data direction B move.b #$10,$77(a6) ;free run shift register, counter move.b #$0F,$75(a6) ;symmetrical wave shape move.b #$A0,$71(a6) ;fairly low initial frequency tst.b $C1(a6) ;turn off possible OMNINET interrupt move.b $01(a6),d0 ;clear keyboard data buffer move.b $21(a6),d0 ;clear dcom0 data buffer move.b $41(a6),d0 ;clear dcom1 data buffer page ;SetMB ; ; Check Corvus CONCEPT hardware (test 1) ; ; Verify ports making no data accesses ; SetupCk cmpi.b #$3E,$27(a6) ;dcom0 control 0.8 bne.s CHerr ; cmpi.b #$AB,$25(a6) ;dcom0 command bne.s CHerr ; cmpi.b #$3E,$47(a6) ;dcom1 control bne.s CHerr ; cmpi.b #$AB,$45(a6) ;dcom1 command bne.s CHerr ; cmpi.b #$17,$07(a6) ;kybd control bne.s CHerr ; cmpi.b #$0B,$05(a6) ;kybd command bne.s CHerr ; cmpi.b #$80,$67(a6) ;VIA data direction A bne.s CHerr ; cmpi.b #$37,$65(a6) ;VIA data direction B beq.s CHend ; CHerr moveq #-1,d0 ;short delay before error tone 0.8 CHerr1 dbra d0,CHerr1 ;* bset #0,CPsysst.w ;set test 1 failed flag bsr Flash ;* CHend moveq #-1,d0 ;{!DS};short delay before clearing screen 0.8 CHend1 dbra d0,CHend1 ;{!DS} bsr SBprom2 ;{!DS};is this a boot to PROM? 0.7 beq.s CHend2 ;{!DS};yes, do not clear screen 0.7 move.l #DSPbase,a0 ;{!DS};get pointer to start of display screen move.l #DSPend,a1 ;{!DS};get pointer to end of display screen bsr ZeroRam ;{!DS};clear display screen CHend2 move.b #$FF,$75(a6) ;turn off initial tone 0.7 ; SetMB -- Initialize MACSBUG RAM ; SetMB lea RAMmxbug.w,a0 ;get pointer to start of MACSBUG RAM 0.8 lea RAMwksta-4.w,a1 ;get pointer to end of MACSBUG RAM 0.8 bsr ZeroRam ;zero MACSBUG RAM 0.7 bsr SBprom1 ;is debug PROM present? 0.7 bne.s RomTst1 ;no, go on 0.7 jsr (a1) ;initialize MACSBUG 0.8 bsr SBprom2 ;is this a boot to PROM? 0.7 beq MemClr1 ;yes, bypass PROM and RAM checks 0.7 page ;RomTst1, RamTst1, RamTst2, MemTest ; ; RomTst1 -- Check Corvus CONCEPT PROM (test 2) ; RomTst1 move.l #CPcksum,a0 ;get pointer to start of PROM move.l #ROMend,a1 ;get pointer to end of PROM bsr RomTst ;check PROM beq.s RamTst1 ;PROM ok, go on bset #1,CPsysst.w ;set test 2 failed flag bsr Flash ;* ; ; RamTst1 -- Check Corvus CONCEPT static RAM (test 3) ; RamTst1 lea RAMwksta.w,a0 ;get pointer to start of RAM 0.8 bsr WalkBit ;is RAM valid? bne.s RT1err ;no, report error lea CPstack.w,a1 ;get pointer to end of RAM 0.8 ; (leave room for stack) bsr March ;is RAM valid? beq.s RamTst2 ;yes, go on ; RT1err bset #2,CPsysst.w ;set test 3 failed flag bsr Flash ;* ; ; RamTst2 -- Check Corvus CONCEPT dynamic RAM (test 4) ; RamTst2 move.l #USRbase,a0 ;get pointer to start of RAM bsr WalkBit ;is RAM valid? bne.s RT2err ;no, report error bsr RamSize ;get dynamic RAM size (a1 = RAM size) bsr March ;is RAM valid? beq.s MemTest ;yes, go on ; RT2err bset #3,CPsysst.w ;set test 4 failed flag bsr Flash ;* ; ; MemTest -- Check Corvus CONCEPT dynamic RAM (test 5) ; MemTest bsr IncTest ;test user dynamic RAM beq.s MemClr ;no error, clear memory bset #4,CPsysst.w ;set test 5 failed flag bsr Flash ;* page ;MemClr, SetIntV, SlotID ; MemClr -- Clear memory ; MemClr move.l #DSPbase,a0 ;{!CV};get pointer to start of RAM 0.7 bsr RamSize ;get dynamic RAM size (a1 = RAM size) 0.7 bsr ZeroRam ;zero RAM 0.7 ; 0.7 MemClr1 lea RAMwksta.w,a0 ;get pointer to start of RAM 0.8 lea CPstack-2.w,a1 ;get pointer to end of RAM 0.8 ; (leave room for stack) 0.7 bsr ZeroRam ;zero static RAM 0.7 ; SetIntV -- Set up interrupt vectors ; SetIntV move.l #CPivec1,a0 ;get pointer to interrupt vector table lea IVlvl1.w,a1 ;get pointer to interrupt vectors 0.8 moveq #6,d0 ;get number of vectors to move SUI1 move.l (a0)+,(a1)+ ;move pointers to interrupt vectors dbra d0,SUI1 ;* ;{!DS} bsr KBinit ;{!DS};initialize keyboard bsr DSinit ;{!DS};initialize display ; lea msg1,a0 ;mesg - "Corvus CONCEPT Initialization" bsr DSputst ;output message lea msgcpy,a0 ;mesg - copyright notice bsr DSputst ;output message lea msg2,a0 ;mesg - carriage returns bsr DSputst ;output message ; SlotID -- Examine slots for known devices ; SlotID lea CPsl1typ.w,a5 ;get pointer to slot types table 0.8 movea.l #IOPprom,a0 ;get pointer to slot 1 interface PROM 0.7 moveq #1,d6 ;get index for slot 1 SlotID1 movep.l 01(a0),d1 ;get interface prom code (ID) movep.l 09(a0),d2 ;get interface prom code (ID) tst.b IOPbase+$9FFF.L ;disable interface RAM 0.7 page ;SlotID (continued) move.b #DTlocl,-1(a5,d6);set possible device type 0.7 cmp.l #$A920A900,d1 ;is this a local disk? bne.s SlotID3 ;no, check next device cmp.l #$A903A93C,d2 ;is this a local disk? bne.s SlotID3 ;no, check next device bsr LDsync ;sync with local disk bge.s SlotID9 ;check next slot if disk responded 0.7 bset #5,CPsysst.w ;set test 6 failed flag 0.7 bsr Flash ;* 0.7 bra.s SlotID8 ;bypass slot if disk did not respond 0.7 ; 0.7 SlotID3 move.b #DTa5,-1(a5,d6) ;set possible device type 0.7 cmp.l #$A220A000,d1 ;is this an Apple floppy? bne.s SlotID4 ;no, check next device cmp.l #$A203863C,d2 ;* beq.s SlotID9 ;check next slot (dev type set) 0.7 ; SlotID4 cmp.l #'CORV',d1 ;is this a Corvus floppy? bne.s SlotID8 ;no, check next slot 0.7 ; 0.7 move.b #DTc8,-1(a5,d6) ;set possible device type 0.7 cmp.l #'US01',d2 ;is this a Corvus SSSD floppy? 0.7 bne.s SlotID5 ;no, check for another floppy type 0.7 bsr SlotAdr ;compute FDC register base pointer 0.7 move.b #$20,1(a1) ;turn off floppy motor 0.7 bra.s SlotID9 ;check next slot (dev type set) 0.7 ; 0.7 SlotID5 move.b #DTf8,-1(a5,d6) ;set possible device type 0.7 cmp.l #'US02',d2 ;is this a Corvus DSDD floppy? 0.7 bne.s SlotID8 ;no, set no device in slot 0.7 bsr SlotAdr ;compute FDC register base pointer 0.7 move.b #$08,9(a1) ;turn off floppy motor 0.7 btst #7,9(a1) ;is this an 8" floppy? 0.7 bon.s SlotID9 ;yes, check next slot (dev type set) 0.7 move.b #DTf5,-1(a5,d6) ;set device type 0.7 bra.s SlotID9 ;check next slot (dev type set) 0.7 ; 0.7 SlotID8 clr.b -1(a5,d6) ;set no device in slot 0.7 ; SlotID9 adda.w #$200,a0 ;update interface PROM pointer addq #1,d6 ;update slot number cmp.w #4,d6 ;have we looked at all slots? ble SlotID1 ;no, check next slot page ;SlotID (continued) moveq #InitOp,d0 ;get OMNINET Transporter number bsr ODcomnd ;* move.b d7,CPtprnbr.w ;save OMNINET Transporter number 0.7 blt.s SlotIDb ;if error, go on 0.7 ; bsr ODpeek ;check if transporter is a PTom 0.8 cmpi.b #$63, D7 ;version less than 64? 0.8 bls.s RptStat ;yes, is PTom - ignore it 0.8 moveq #EchoOp,d0 ;is OMNINET Transporter number in use? move.b CPtprnbr.w,d1 ;get station's transporter host number 0.8 bsr ODcomnd ;* cmpi.b #Echoed,d7 ;* bne.s SlotIDa ;no, go on bset #6,CPsysst.w ;set test 7 failed flag bsr Flash ;* bra.s SlotIDb ;bypass disk server broadcast SlotIDa bsr ODbroad ;send broadcast message to disk srvr 0.7 ;* in order to get disk server 0.7 ;* Transporter number 0.7 SlotIDb move.b d7,CPbtsrvr.w ;save boot server number blt.s RptStat ;if error, go on move.b #DTomni,4(a5) ;set device type page ;RptStat ; ; RptStat -- Report results of system initialization tests ; RptStat moveq #0,d1 ;initialize test number tst.b CPsysst.w ;any system errors? bne.s RptSt1 ;yes, report them lea msg32,a0 ;mesg - All system tests passed bsr DSputst ;output message ; ---- bra.s RptSt8 ;output carriage returns ; RptSt1 btst d1,CPsysst.w ;did current test pass? boff.s RptSt2 ;yes, go on lea msg30,a0 ;mesg - System test bsr DSputst ;output message move.b d1,d0 ;get test number addi.b #$31,d0 ;* bsr DSputch ;output test number lea msg31,a0 ;mesg - failed bsr DSputst ;output message ; RptSt2 addq.w #1,d1 ;increment test number cmp.w #7,d1 ;finished with all tests? bls.s RptSt1 ;no, process next test 0.8 ; RptSt8 lea msg2,a0 ;output carriage returns bsr DSputst ;* move.b #$0F,$75(a6) ;symmetrical wave shape move.b #$A0,$71(a6) ;output a low pitch tone moveq #-1,d0 ;short delay 0.8 RptSt9 dbra d0,RptSt9 ;leaves d0 as $FFFFFFFF move.b d0,$75(a6) ;turn off tone 0.8 page ;SelBoot ; ; SelBoot -- Select boot type ; SelBoot move.b IObootsw.L,d0 ;get boot selection switches andi.w #$C0,d0 ;* beq SBuser ;00 - user select cmpi.b #$40,d0 ; beq.s SBlocal ;01 - local disk boot cmpi.b #$80,d0 ; beq.s SBomni ;02 - OMNINET disk boot bsr SBprom1 ;is debug PROM present? 0.7 bne.s SBflpy ;03 - no, floppy disk boot 0.8 move.b #1,CPextcrt.w ;03 - yes, debug (or other) PROM 0.7 ; SBdebug bsr SBprom1 ;is debug PROM present? 0.7 bne.s SBuser ;no, ask user for boot device lea msg4,a0 ;mesg - MACSBUG I/O on DataComm 0 0.6 bsr DSputst ;output message movea.l MXBentry.L,a0 ;*kb yes, go to debugger 0.5 jmp (a0) ;*kb 0.5 ; SBomni lea msg11,a0 ;mesg - "OMNINET disk boot" bsr SBmsg ;output message bsr Oboot ;load OS boot code bra.s SBboot ;transfer control to boot code ; SBlocal lea msg12,a0 ;mesg - "Local disk boot" bsr SBmsg ;output message bsr Lboot ;load OS boot code bra.s SBboot ;transfer control to boot code ; SBflpy lea msg13,a0 ;mesg - "Floppy disk boot" bsr.s SBmsg ;output message movea.l #CPsl1typ,a1 ;get pointer to slot 1 type moveq #1,d0 ;get initial slot number SBflpy1 move.b -1(a1,d0),d1 ;get device type cmpi.b #DTc8,d1 ;{!CC};is this a Corvus SSSD floppy disk? 0.8 beq.s SBflpy2 ;{!CC};yes, use it for booting 0.8 ; ---- cmpi.b #DTa5,d1 ;is this an Apple floppy disk? 0.7 ; ---- beq.s SBflpy3 ;yes, use it for booting 0.7 cmpi.b #DTf8,d1 ;is this a Corvus DSDD 8" floppy disk? 0.7 beq.s SBflpy4 ;yes, use it for booting 0.7 cmpi.b #DTf5,d1 ;is this a Corvus DSDD 5" floppy disk? 0.7 beq.s SBflpy4 ;yes, use it for booting 0.7 addq #1,d0 ;update slot number cmp.w #4,d0 ;have we looked at all slots? ble.s SBflpy1 ;no, check next slot bra GoToBt1 ;output error message ; SBflpy2 bsr Fboot ;{!CC};load OS boot code 0.8 bra.s SBboot ;{!CC};transfer control to boot code 0.8 ; ;Bflpy3 bsr Aboot ;load OS boot code 0.7 ; ---- bra.s SBboot ;transfer control to boot code 0.7 page ;SBuser, SBmsg, SBprom1, SBprom2 SBflpy4 bsr FBboot ;load OS boot code 0.7 SBboot bra GoToBt ;transfer control to boot code 0.7 ; SBuser bsr.s SBprom2 ;boot to debug PROM? 0.7 beq SBdebug ;yes 0.7 lea msg10,a0 ;mesg - "Select boot device" bsr DSputst ;output message bsr KBgetch ;get reply bsr DScvtUC ;convert character to upper case move.b d0,-(sp) ;save reply bsr DSputch ;echo reply moveq #DSCcr,d0 ;output carriage return bsr DSputch ;* move.b (sp)+,d0 ;restore reply cmpi.b #'F',d0 ;Corvus floppy boot? beq.s SBflpy ;yes, do it cmpi.b #'D',d0 ;debug? beq SBdebug ;yes, do it cmpi.b #'L',d0 ;local disk boot? beq SBlocal ;yes, do it cmpi.b #'O',d0 ;OMNINET disk boot? beq SBomni ;yes, do it bra Setup ;no, start over again ; ; SBmsg -- Output message ; SBmsg bsr DSputst ;output message lea msg19,a0 ;mesg - "disk boot" bsr DSputst ;output message rts ;return ; ; SBprom1 -- Is debug PROM present? (EQ - yes, NE - no) ; SBprom1 lea MXBinit.L,a0 ;is debug PROM present? 0.7 lea MXBbase+$C.L,a1 ;* 0.7 cmpa.l (a0),a1 ;* 0.7 rts ;return 0.7 ; ; SBprom2 -- Boot to debug PROM? (EQ - yes, NE - no) ; SBprom2 movem.l a0-a1/d0,-(sp) ;save registers 0.7 bsr.s SBprom1 ;is debug PROM present? 0.7 bne.s SBprom9 ;no, return 0.7 move.b IObootsw.L,d0 ;get boot selection switches 0.7 andi.w #$C0,d0 ;* 0.7 cmpi.w #$C0,d0 ;is this a boot to PROM? 0.7 SBprom9 movem.l (sp)+,a0-a1/d0 ;restore registers 0.7 rts ;return 0.7 page ;GoToBt ; ; GoToBt -- Transfer control to boot code ; ; Enter: A0.L = Boot code entry point pointer ; ; Values passed in registers to the boot are: ; ; +---------------+---------------+---------------+---------------+ ; D0 | low user RAM address | ; +---------------+---------------+---------------+---------------+ ; D1 | high user RAM address | ; +---------------+---------------+---------------+---------------+ ; D2 | low user RAM address (same as D0) | ; +---------------+---------------+---------------+---------------+ ; D3 | high user RAM address (same as D1) | ; +---------------+---------------+---------------+---------------+ ; D4 | 0 | 0 | boot slot | boot server | ; +---------------+---------------+---------------+---------------+ ; D5 | 0 | ; +---------------+---------------+---------------+---------------+ ; D6 | 0 | ; +---------------+---------------+---------------+---------------+ ; D7 | 0 | ; +---------------+---------------+---------------+---------------+ ; GoToBt bge.s GoToBt2 ;go on if no boot load error ; GoToBt1 lea msg3,a0 ;mesg - "Boot error" bsr DSputst ;output message bra SBuser ;select boot device again ; GoToBt2 bsr RamSize ;get dynamic RAM size (a1 = RAM size) 0.6 cmpa.l #MEMprom,a1 ;are we in PROM? 0.7 bne.s GoToBt3 ;yes, go on 0.6 lea CPbtslot.w,a1 ;set RAM size to protect code 0.6 ; 0.6 GoToBt3 move.l #USRbase,d0 ;D0 - low user RAM address 0.6 move.l a1,d1 ;D1 - high user RAM address move.l d0,d2 ;D2 - low user RAM address move.l d1,d3 ;D3 - high user RAM address clr.l d4 ;D4 - 0 move.b CPbtslot.w,d4 ;D4 - boot slot lsl.w #8,d4 ; move.b CPbtsrvr.w,d4 ;D4 - boot slot/boot server clr.l d5 ;D5 - 0 clr.l d6 ;D6 - 0 clr.l d7 ;D7 - 0 jmp (a0) ;enter boot code page ;RomTst ; ; RomTst -- Compute checksum for PROM ; (PROM checksum is included in address range) ; ; Enter: A0.L = PROM start pointer ; A1.L = PROM end pointer ; ; Exit: EQ = PROM checksum valid ; NE = PROM checksum error ; RomTst move.l a0,a2 ;get starting address clr.w d0 ; RT1 move.w (a2)+,d1 ; eor.w d1,d0 ; cmpa.l a1,a2 ; blt.s RT1 ; cmp.w #$FFFF,d0 ; rts ;return ; ; WalkBit -- Walking ones and zeros ; ; Enter: A0.L = RAM start pointer ; WalkBit move.l a0,a2 ;get starting address move.l a0,a1 ;get ending address adda.w #$10,a1 ;* 0.8 WB1 moveq #-2,d0 ;puts $FFFE in low word 0.8 WB2 move.w d0,(a2) ; cmp.w (a2),d0 ; bne.s WBerr ; rol #1,d0 ; bcs.s WB2 ; ; moveq #1,d0 ; 0.8 WB3 move.w d0,(a2) ; cmp.w (a2),d0 ; bne.s WBerr ; asl #1,d0 ; bcc.s WB3 ; ; addq.l #2,a2 ; 0.8 cmpa.l a1,a2 ; blt.s WB1 ; ; WBerr rts ;return page ;March ; ; March -- ; ; Enter: A0.L = RAM start pointer ; A1.L = RAM end pointer ; March move.l a0,a2 ; clr.l d0 ; ; MR1 move.w d0,(a2)+ ; cmpa.l a1,a2 ; bne.s MR1 ; ; move.w d0,d2 ; not.w d2 ; MR2 move.w -(a2),d1 ; cmp.w d0,d1 ; bne.s MRerr ; move.w d2,(a2) ; cmpa.l a0,a2 ; bne.s MR2 ; ; move.w d2,d0 ; not.w d2 ; MR3 move.w (a2),d1 ; cmp.w d0,d1 ; bne.s MRerr ; move.w d2,(a2)+ ; cmpa.l a1,a2 ; bne.s MR3 ; ; MRerr rts ;return page ;IncTest, RamSize, ZeroRam ; ; IncTest -- ; ; Enter: A0.L = RAM start pointer ; A1.L = RAM end pointer ; IncTest move.l a0,a2 ; move.w #$101,d1 ; ; IT01 move.w d1,(a2)+ ; rol.w #1,d1 ; cmpa.l a1,a2 ; blt.s IT01 ; ; move.l a0,a2 ; move.w #$101,d1 ; ; IT02 cmp.w (a2)+,d1 ; bne.s IT99 ; rol.w #1,d1 ; cmpa.l a1,a2 ; blt.s IT02 ; ; IT99 rts ;return ; ; RamSize -- Get end of user RAM pointer ; ; Exit: A1.L = RAM end pointer ; RamSize move.l #MEMprom,a1 ;are we in PROM? 0.7 cmpi.l #ROMend,(sp) ;* bgt.s RamSiz9 ;no, return move.l #MEM512k,MEM512k.L ;{!CV};get actual RAM size 0.7 move.l #MEM256k,MEM256k.L ;{!CV} 0.7 move.l MEM512k.L,a1 ;{!CV} 0.7 RamSiz9 rts ;return ; ; ZeroRam -- Move 0 to RAM subroutine ; ; Enter: A0.L = RAM start pointer ; A1.L = RAM end pointer ; ZeroRam clr.l (A0)+ ; cmpa.l a1,a0 ; ble.s ZeroRam ; rts ;return page ;Flash ; ; Flash -- Flash display screen subroutine ; Flash movem.l a0-a1/a6/d0-d1,-(sp);save registers 0.8 FL0 move.l #VIAbase,a6 ;get pointer to VIA I/O locations move.b #$0F,$75(a6) ;symmetrical wave shape move.b #$40,$71(a6) ;output a high pitch error tone bsr SBprom2 ;{!CV};is this a boot to PROM? 0.7 beq.s FL4 ;{!CV};yes, do not flash screen 0.7 move.l #DSPend-$30,a1 ;{!CV};get ptr to end of display screen 0.7 ; FL1 move.l #DSPbase,a0 ;{!CV};get pointer to start of 0.8 FL2 not.w (a0)+ ;{!CV}; display screen 0.8 cmpa.l a1,a0 ;{!CV} 0.8 blt.s FL2 ;{!CV} 0.8 move.l #DSPbase,a0 ;{!CV};get pointer to start of 0.8 FL3 not.w (a0)+ ;{!CV}; display screen 0.8 cmpa.l a1,a0 ;{!CV} 0.8 blt.s FL3 ;{!CV} 0.8 ;{!CV} 0.8 FL4 moveq #-1,d0 ;short delay 0.8 FL5 dbra d0,FL5 ;* move.b #$FF,$75(a6) ;turn off tone moveq #-1,d0 ;short delay 0.8 FL6 dbra d0,FL6 ;* movem.l (sp)+,a0-a1/a6/d0-d1;restore registers 0.8 rts ;return page ;INT... ; ; INTlvl7 -- process level 7 interrupt (ignore interrupt) ; INTlvl7 rte ;return from interrupt ; ; INTkybd -- process KEYBOARD interrupt (ignore interrupt) ; INTkybd ori.b #$02,IOkybd.l ;lvl 6 (KYBD) - turn off recv int 0.7 andi.b #$F3,IOkybd.l ;lvl 6 (KYBD) - turn off xmit int 0.7 rte ;return from interrupt ; ; INTtimr -- process TIMER interrupt (ignore interrupt) ; INTtimr move.b #$7F,IOtimr.l ;lvl 5 (TIMER) - turn off VIA int 0.7 rte ;return from interrupt ; ; INTdc0 -- process DATACOMM0 interrupt (ignore interrupt) ; INTdc0 ori.b #$02,IOdc0.l ;lvl 4 (DC0) - turn off recv int 0.7 andi.b #$F3,IOdc0.l ;lvl 4 (DC0) - turn off xmit int 0.7 rte ;return from interrupt ; ; INTomni -- process OMNINET interrupt (ignore interrupt) ; INTomni tst.b IOomni.l ;lvl 3 (OMNINET) - reset interrupt 0.7 rte ;return from interrupt ; INTdc1 -- process DATACOMM1 interrupt (ignore interrupt) ; INTdc1 ori.b #$02,IOdc1.l ;lvl 2 (DC1) - turn off recv int 0.7 andi.b #$F3,IOdc1.l ;lvl 2 (DC1) - turn off xmit int 0.7 rte ;return from interrupt ; INTslot -- process SLOT interrupt (ignore interrupt) ; INTslot movem.l D0/A0,-(SP) ;save registers lea IOslot.l,a0 ;get pointer to port A ORA 0.7 move.b (A0),D0 ;read port A w/o handshake bchg #7,D0 ;toggle IOX move.b D0,(A0) ;write new IOX movem.l (SP)+,D0/A0 ;restore registers rte ;return from interrupt page ;SlotAdr, msg... ; ; SlotAdr -- compute slot address given slot number ; ; Enter: D6.B - Slot number ; ; Exit: A1.L - I/O port address ; SlotAdr move.l d6,-(sp) ;save register ext.w d6 ;compute disk port address for slot lsl.w #5,d6 ;* move.l #IOPbase,a1 ;* 0.7 adda.w d6,a1 ;* move.l (sp)+,d6 ;restore register rts ;return list 0 msg1 data.b DSCcr,DSCcr data.b 'Corvus CONCEPT Initialization (' ;{!CC} 0.8 data.b PROMvers+$30,'.',PROMlevl+$30,')' msg2 data.b DSCcr,DSCcr,0 msg3 data.b 'Boot error ....',DSCcr,DSCcr,0 msg4 data.b DSCcr,DSCcr,'MACSBUG I/O on DataComm 0',DSCcr,0 msg10 data.b 'Select boot device (D,F,L,O): ',0 msg11 data.b 'OMNINET',0 msg12 data.b 'Local',0 msg13 data.b 'Floppy',0 msg19 data.b ' disk boot',DSCcr,0 msg30 data.b 'System test ',0 msg31 data.b ' failed',DSCcr,0 msg32 data.b 'All system tests passed',DSCcr,0 data.b 0 page ;p.prom.kb ; ; File: CC.PROM.KB ; Date: 15-Nov-83 ; By: Keith Ball ; ; KEYBOARD DRIVER FOR PROM (kb) ; ; EQUATES FOR ALL KEYBOARD SOFTWARE ; ; KEYBOARD DATA AREA DEFINITIONS ; KBBflgs EQU 0 ;FLAG JUST HI ORDER BYTE KBBfrnt EQU KBBflgs+2 ;FRONT PTR SAVE KBBrear EQU KBBfrnt+4 ;REAR PTR SAVE KBBsrsv EQU KBBrear+4 ;STATUS REG SAVE AREA KBBbufr EQU KBBsrsv+2 ;KEYBOARD BUFFER KBBlen EQU RAMkblen-KBBbufr;NMBR OF BYTES IN BUFFER ; ; FLAG BIT DEFINITIONS ; KBFfull EQU 0 ;BUFFER FULL FLAG KBFemty EQU 1 ;BUFFER EMPTY FLAG KBFclos EQU 2 ;KEY CLOSURE FLAG KBFshft EQU 3 ;SHIFT KEY KBFcntl EQU 4 ;CONTROL KEY KBFlock EQU 5 ;SHIFT LOCK KEY ; ; MISCELLANEOUS EQUATES ; KBmsk40 EQU $1F ;MASK TO CLEAR D7-D5 (CONTROL CODE) ; ; TABLE VALUES FOR PROCESSING CHARACTERS ; KBCqual EQU $7F ;QUALIFIER VALUES > THEN THIS KBCshft EQU $FE ;TABLE VALUE FOR SHIFT KBCcntl EQU $FD ;TABLE VALUE FOR CONTROL KBClock EQU $FC ;TABLE VALUE FOR SHIFT LOCK KBCnoch EQU $FF ;TABLE VALUE FOR NO CHAR CDE ; ; SPECIAL ASCII CHARACTERS ; KBClca EQU 'a' ;LOWER CASE A KBClcz EQU 'z' ;LOWER CASE Z KBCqmrk EQU '?' ;QUESTION MARK page ; ; COMMAND AND CONTROL REGISTER VALUES ; KBccOff EQU $02 ;TURN OFF UART (CMD) KBcc600 EQU $17 ;600 BAUD AND 8 BIT XMIT (CTL) KBccBrk EQU $08 ;XMIT A BREAK (CMD) KBccGo EQU $09 ;TURN ON INTS & UART (CMD) ; KBdsInt EQU $0700 ;DISABLE 68000 INTERRUPTS ; ; KBinit - Initialize (reset) keyboard ; ; REGISTER A2 IS USED AS POINTER TO COMMAND REGISTER ; REGISTER A3 IS ADDRESS OF KBRD DATA AREA ; KBinit MOVEM.L D0/A0-A3,-(SP) ;save registers LEA RAMkbbuf.W,A3 LEA KBRcmnd.L,A2 MOVE.B #KBccOff,(A2) ;TURN OFF KBRD LEA KBBflgs(A3),A0 ;CLEAR INT HANDLER FLAGS CLR.L (A0) ;INCLUDES QUALIFIERS BSET #KBFemty,(A0) ;BUFFER IS EMPTY ; ; INITIALIZE FRONT & REAR POINTERS ; LEA KBBbufr(A3),A0 LEA KBBfrnt(A3),A1 MOVE.L A0,(A1)+ MOVE.L A0,(A1) LEA KBintr,A0 ;SETUP AUTOVECTOR 6 MOVE.L A0,IVlvl6.W ;WITH ADDR OF INT HANDLER ; ; TURN ON KEYBOARD UART ; MOVE.B KBRstat-KBRcmnd(A2),D0 ;RESET UART 0.8 MOVE.B KBRdata-KBRcmnd(A2),D0 ;CLEAR RECEIVE 0.8 MOVE.B #KBcc600,KBRcntl-KBRcmnd(A2) ;8 BITS, 600 BAUD XMIT 0.8 MOVE.B #KBccBrk,(A2) ;FORCE BREAK OF KBRD MOVE.W #33333,D0 ;DELAY FOR UART TO DO BREAK KBinit1 DBF D0,KBinit1 ;NEED MINIMUM OF 33.3 MILLISECS MOVE.B #KBccGo,(A2) ;TURN ON UART & INTERRUPTS move.w #$2500,sr ;set priority to 6, KYBD intr only MOVEM.L (SP)+,D0/A0-A3 ;restore registers RTS page ; ; KBintr - Keyboard interrupt service routine ; ; BEGIN INTERRUPT SERVICE ROUTINE. THIS IS THE ENTRY POINT. IT'S ADDRESS ; MUST BE PLACED IN AUTO VECTOR INTERRUPT 6 VECTOR BEFORE KEYBOARD INTERRUPT ; IS TURNED ON. ; ; REGISTER USEAGE: D0 - KEYCODE ; D1 - CHARACTER ; A0 - ADDRESS OF FLAG BYTE ; A2 - BASE ADDRESS OF KBRD DATA AREA ; KBintr MOVEM.L D0-A6,-(SP) ;SAVE REGISTERS ON STACK LEA RAMkbbuf.W,A2 ;BASE ADDR OF KBRD DATA AREA BSR KBgetky ;GET KEYCODE FROM UART DATA PORT ; ; IF BIT 7 OF KEYCODE SET THEN CLOSURE ELSE RELEASE ; LEA KBBflgs(A2),A0 BCLR #KBFclos,(A0) ;ASSUME RELEASE BTST #7,D0 ;KEYCODE BIT D7 CLEAR? BEQ.S KBintr1 ;YES BSET #KBFclos,(A0) BCLR #7,D0 ; ; GET CHARACTER CODE FOR THIS KEYCODE ; KBintr1 LEA KBstable,A1 ;ASSUME SHIFT TABLE BTST #KBFshft,(A0) BNE.S KBintr2 ;SHIFT BIT SET LEA KBrtable,A1 ;ELSE USE REGULAR TABLE KBintr2 MOVE.B 0(A1,D0.W),D1 ;INDEX TABLE BY KEYCODE ; ; IF CHAR(D1) = $FF THEN IGNORE AND EXIT ; CMPI.B #KBCnoch,D1 BEQ.S KBintr9 BSR.S KBproky ;ELSE PROCESS KEYCODE ; ; EXIT INTERRUPT SERVICE ROUTINE ; KBintr9 MOVEM.L (SP)+,D0-A6 ;RESTORE REGISTERS RTE ;EXIT INTERRUPT page ; ; KBgetch - Get a keyboard character ; ; Register useage: A0 = Front pointer ; A1 = address of end of buffer + 1 ; A2 = updated front pointer ; A3 = address of front pointer ; A4 = address of flag byte ; A5 = address of keyboard data area ; A6 = address of Status Register save area ; ; Exit: D0.B - Next character in buffer ; KBgetch MOVEM.L A0-A6,-(SP) ;save all address registers LEA RAMkbbuf.W,A5 ;keyboard data area LEA KBBflgs(A5),A4 ;address of Flag byte tst.b CPextcrt.w ;using external CRT? 0.8 bon.s KBgchra ;yes, use data comm 0 0.8 bsr SBprom2 ;debug boot PROM? 0.7 bne.s KBgchr1 ;no, go on 0.7 KBgchra move.l #KBcPort,a1 ;get UART pointer 0.8 KBgchr0 btst #KBrdBit,KBuSt(a1) ;is char in UART? 0.7 boff.s KBgchr0 ;no, wait some more 0.7 move.b KBuDa(a1),d0 ;get character 0.7 bra.s KBgchr9 ;return 0.7 ; ; Wait for a character in the Buffer. ; KBgchr1 BTST #KBFemty,(A4) ;while (Buffer_empty) do; BNE.S KBgchr1 ;* ; ; have char, check for wrap around before get char ; LEA KBBfrnt(A5),A3 ;pointer to Front save loc MOVE.L (A3),A0 ;Front pointer LEA KBBbufr+KBBlen(A5),A1 ;end of buffer + 1 MOVE.L A0,A2 ; ADDQ.L #1,A2 ;add one to pointer to get next addr CMPA.L A1,A2 ;Front=end of buffer + 1 0.7 BNE.S KBgchr2 ;No LEA KBBbufr(A5),A2 ;yes, then wrap back to beginning ; KBgchr2 ;----- LEA KBBsrsv(A5),A6 ;don't need 0.8 MOVE.W SR,-(SP) ;put SR on stack 0.8 ORI.W #KBdsInt,SR ;*** disable interrupts MOVE.B (A0),D0 ;get char MOVE.L A2,(A3) ;save new Front value CMPA.L KBBrear(A5),A2 ;if Front=Rear then BNE.S KBgchr3 ;Buffer_empty := true; BSET #KBFemty,(A4) ; ; KBgchr3 MOVE.W (SP)+,SR ;*** enable interrupts 0.8 KBgchr9 MOVEM.L (SP)+,A0-A6 ;restore callers address regs 0.7 RTS ;return page ; ; KBgetky - GET KEYCODE (IGNORES ERRORS) ; ; EXIT : (D0) - UART DATA PORT BYTE ; KBgetky CLR.L D0 ;MAKE SURE HI 3 BYTES ARE 0 ; ; READ STATUS REGISTER TO CLEAR IRQ BIT ; ALWAYS READ DATA PORT SO IF OVERRUN THEN FOR NEXT CHAR ; IT WILL BE CLEARED. ; MOVE.B KBRstat.L,D1 ;GET STATUS OF RECEIVE MOVE.B KBRdata.L,D0 ;READ UART DATA PORT RTS page ; ; KBproky - PROCESS CHARACTER OR QUALIFIER ; ; Enter: D1 = CHARACTER CODE FROM TABLE ; D0 = KEYCODE ; A0 = ADDRESS OF FLAGS ; KBproky CMPI.B #KBCqual,D1 ;IS IT A QUALIFIER BHI.S KBpro3 ;YES ; ; IGNORE REST OF KEYS IF NOT CLOSURE ; BTST #KBFclos,(A0) BEQ.S KBpro9 ; ; TEST FOR CONTROL ; BTST #KBFcntl,(A0) BEQ.S KBpro1 ;NO,TRY SHIFT LOCK CMPI.B #KBCqmrk,D1 BLS.S KBpro1 ANDI.B #KBmsk40,D1 ;CLEAR BITS D7,D6,D5 OF CHAR BRA.S KBpro2 ;PUT CHAR ; ; TEST FOR SHIFT LOCK ; KBpro1 BTST #KBFlock,(A0) BEQ.S KBpro2 ;KEY NOT DOWN CMPI.B #KBClca,D1 BCS.S KBpro2 ;NOT WITHIN RANGE CMPI.B #KBClcz,D1 BHI.S KBpro2 ;NOT WITHIN RANGE LEA KBstable,A1 MOVE.B 0(A1,D0.W),D1 ;INDEX TABLE BY KEYCODE ; ; IF BUFFER NOT FULL PUT CHARACTER ; KBpro2 BTST #KBFfull,(A0) BNE.S KBpro9 BSR.S KBputch BRA.S KBpro9 ; ; PROCESS A QUALIFIER KEY ; KBpro3 BSR.S KBqual KBpro9 RTS page ; ; KBputch - PUT ONE CHARACTER IN BUFFER ; ; Enter: D1 = BYTE TO PUT IN BUFFER ; A0 = ADDRESS OF FLAGS ; A2 = ADDRESS OF KEYBOARD DATA AREA ; ; ; PUT CHARACTER IN CIRCULAR QUEUE AT REAR ; KBputch LEA KBBrear(A2),A5 ;get pointer to rear pointer MOVE.L (A5),A3 ;* MOVE.B D1,(A3)+ ;UPDATE POINTER ALSO ; ; IF REAR > ENDBUFFER THEN REAR := @BUFFER ; LEA KBBbufr+KBBlen(A2),A4 ; A4 = end buffer + 1 CMPA.L A4,A3 ; BNE.S KBput1 ;NOT BEYOND BUFFER LEA KBBbufr(A2),A3 ; ; ; IF FRONT = REAR THEN BUFFER FULL ; KBput1 CMPA.L KBBfrnt(A2),A3 ; BNE.S KBput2 ; BSET #KBFfull,(A0) ; KBput2 MOVE.L A3,(A5) ;UPDATE REAR IN MEMORY BCLR #KBFemty,(A0) ;SHOW BUFFER NOT EMPTY RTS ;return page ; ; KBqual - PROCESS QUALIFIER KEYS ; ; Enter: D1 = CHARACTER CODE FROM TABLE ; A0 = ADDRESS OF FLAGS ; KBqual CMPI.B #KBCshft,D1 ;IS IT SHIFT? BNE.S KBqual1 ;NO MOVEQ #KBFshft,D2 ;BIT POSITION OF SHIFT BRA.S KBqual3 ;CHANGE FLAG ; KBqual1 CMPI.B #KBCcntl,D1 ;IS IT CONTROL? BNE.S KBqual2 ;NO MOVEQ #KBFcntl,D2 ;BIT POSITION OF CONTROL BRA.S KBqual3 ;CHANGE FLAG ; KBqual2 CMPI.B #KBClock,D1 ;IS IT SHIFT LOCK? BNE.S KBqual9 ;NO,THEN IT'S GARBAGE MOVEQ #KBFlock,D2 ; ; IF CLOSURE THEN SET FLAG ELSE CLEAR FLAG ; KBqual3 BTST #KBFclos,(A0) BEQ.S KBqual8 BSET D2,(A0) BRA.S KBqual9 KBqual8 BCLR D2,(A0) KBqual9 RTS page ; ; THE SHIFT TABLE ; TABLE IS INDEXED BY KEYCODE. EACH BYTE REPRESENTS THE ENTRY FOR ; THE CORRESPONDING KEYCODE. ; ; 0 1 2 3 4 5 6 7 8 9 A B C D E F KBstable ; .. 3 9 .. 6 , - cr .. 1 7 .. 4 8 5 2 DATA.B $FF,$33,$39,$FF,$36,$2C,$2D,$0D,$FF,$31,$37,$FF,$34,$38,$35,$32 ; ; + .. { | cr } bs .. ) ? P _ : ~ " .. ; DATA.B $2B,$FF,$7B,$7C,$0D,$7D,$08,$FF,$29,$3F,$50,$5F,$3A,$7E,$22,$FE ; + .. { bs cr } | .. ) ? P _ : ~ " .. ;0.6 DATA.B $2B,$FF,$7B,$08,$0D,$7D,$7C,$FF,$29,$3F,$50,$5F,$3A,$7E,$22,$FE ;0.6 ; .. .. .. .. .. .. .. .. $ % R T F G V B DATA.B $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$24,$25,$52,$54,$46,$47,$56,$42 ; @ # W E S D X C esc ! .. Q .. A .. Z DATA.B $40,$23,$57,$45,$53,$44,$58,$43,$1B,$21,$FF,$51,$FC,$41,$FE,$5A ; ^ & Y U H J N M .. .. .. sp .. 0 .. . DATA.B $5E,$26,$59,$55,$48,$4A,$4E,$4D,$FD,$FF,$FF,$20,$FF,$30,$FF,$2E ; * ( I O K L < > .. .. .. .. .. .. .. .. DATA.B $2A,$28,$49,$4F,$4B,$4C,$3C,$3E,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF page ; ; THE REGULAR TABLE - UNSHIFTED OR LOWER CASE ; TABLE IS INDEXED BY KEYCODE. EACH BYTE REPRESENTS THE ENTRY FOR ; THE CORRESPONDING KEYCODE. ; ; 0 1 2 3 4 5 6 7 8 9 A B C D E F KBrtable ; .. 3 9 .. 6 , - cr .. 1 7 .. 4 8 5 2 DATA.B $FF,$33,$39,$FF,$36,$2C,$2D,$0D,$FF,$31,$37,$FF,$34,$38,$35,$32 ; ; = .. [ \ cr ] bs .. 0 / p - ; ` ; .. ; DATA.B $3D,$FF,$5B,$5C,$0D,$5D,$08,$FF,$30,$2F,$70,$2D,$3B,$60,$27,$FE ; = .. [ bs cr ] \ .. 0 / p - ; ` ; .. ;0.6 DATA.B $3D,$FF,$5B,$08,$0D,$5D,$5C,$FF,$30,$2F,$70,$2D,$3B,$60,$27,$FE ;0.6 ; .. .. .. .. .. .. .. .. 4 5 r t f g v b DATA.B $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$34,$35,$72,$74,$66,$67,$76,$62 ; 2 3 w e s d x c esc 1 .. q .. a .. z DATA.B $32,$33,$77,$65,$73,$64,$78,$63,$1B,$31,$FF,$71,$FC,$61,$FE,$7A ; 6 7 y u h j n m .. .. .. sp .. 0 .. . DATA.B $36,$37,$79,$75,$68,$6A,$6E,$6D,$FD,$FF,$FF,$20,$FF,$30,$FF,$2E ; 8 9 i o k l , . .. .. .. .. .. .. .. .. DATA.B $38,$39,$69,$6F,$6B,$6C,$2C,$2E,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF page ;p.prom.ds ; ; File: CC.PROM.DS ; Date: 15-Nov-83 ; ; DISPLAY DRIVER FOR PROM (mb) 05/18/82 ; ; BOTH horizontal and vertical display driver ; contains default window records, copies them into memory ; contains default character sets ; no CRTST code: no window functions DSClf equ $0A ;line feed character DSCcr equ $0D ;carriage return character DSCesc equ $1B ;escape character DSCblnk equ $20 ;blank character DSClca equ $61 ;lower case "a" DSClcz equ $7A ;lower case "z" DSCdiff equ $20 ; ; Character Set Record Equates ; ;Stblloc equ 0 ;character set data pointer (not used) CSlpch equ 4 ;scanlines per character CSbpch equ 6 ;bits per character CSfrstch equ 8 ;first character code - ascii CSlastch equ 10 ;last character code - ascii CSmask equ 12 ;mask used in positioning cells CSattr1 equ 16 ;attributes ; bit 0 = 1 - vertical orientation CSattr2 equ 17 ;currently unused CSdata equ 18 ;offset of char data from char record ; ; Window Record Equates ; WRcharpt equ 0 ;character set pointer WRhomept equ 4 ;home (upper left) pointer WRcuradr equ 8 ;current location pointer WRhomeof equ 12 ;bit offset of home location WRbasex equ 14 ;home x value, relative to root window WRbasey equ 16 ;home y value, relative to root window WRlngthx equ 18 ;maximum x value, relative to window (bits) WRlngthy equ 20 ;maximum y value, relative to window (bits) WRcursx equ 22 ;current x value (bits) WRcursy equ 24 ;current y value (bits) WRbitofs equ 26 ;bit offset of current address WRgrorgx equ 28 ;graphics - origin x (bits relative to home loc) WRgrorgy equ 30 ;graphics - origin y (bits relative to home loc) WRattr1 equ 32 ;attributes WRattr2 equ 33 ;attributes vert equ 0 ; 1 = vertical, 0 = horizontal WRstate equ 34 ;used for decoding escape sequences WRrcdlen equ 35 ;window description record length ; WRlength equ 36 ;actual window record length page ; ; DSinit - Initialize display driver ; DSinit MOVEM.L D4/A0-A2,-(SP) ;save registers MOVE.W #DSdefOf,CPscnofs.W ;set bytes per scan line LEA DSwndH,A0 ;assume horizontal orientation LEA DScsetH,A2 ;* BTST #3,IObootsw.L ;is display horizontal? BOFF.S DSinit1 ;yes, go on LEA DSwndV,A0 ;set vertical orientation LEA DScsetV,A2 ;* DSinit1 LEA CPwndrcd.W,A1 ;get pointer to RAM window record 0.8 MOVEQ #WRlength-1,D4 ;get window record length 0.6 DSinit2 MOVE.B (A0)+,(A1)+ ;copy window record to RAM 0.6 DBRA D4,DSinit2 ;* LEA CPwndrcd.W,A0 ;get RAM window record pointer 0.8 MOVE.L A2,WRcharpt(A0) ;set character set record pointer BSR DScurs ;display cursor on screen MOVEM.L (SP)+,D4/A0-A2 ;restore registers RTS ;return ; ; DScvtUC - Convert character to upper case ; ; Enter: D0.B = ASCII character ; ; Exit: D0.B = upper case ASCII character ; DScvtUC CMPI.B #DSClca,D0 ;is character lower case? BLO.S DScvtU1 ;no, return CMPI.B #DSClcz,D0 ;* BHI.S DScvtU1 ;no, return SUBI.B #DSCdiff,D0 ;convert character to upper case DScvtU1 RTS ;return ; ; DSputst - Display a string ; ; Enter: A0.L - Character string pointer ; (terminated by 0) ; DSputst movem.l D0/A0,-(SP) ;save registers ; DSpst1 move.b (a0)+,d0 ;get next character beq.s DSpst9 ;finished, return bsr.s DSputch ;output character bra.s DSpst1 ;get next character ; DSpst9 movem.l (SP)+,D0/A0 ;restore registers rts ;return page ; ; DSputch - Display a character ; ; Enter: D0.B - Character to output ; DSputch MOVEM.L D0-D7/A0-A6,-(SP) ;save registers andi.w #$7F,d0 ;make character 7 bits LEA CPwndrcd.W,A0 ;get RAM window record pointer 0.8 tst.b CPextcrt.w ;using external CRT? 0.8 bon.s DSxCrt ;yes, use data comm 0 0.8 bsr SBprom2 ;debug PROM boot? 0.7 beq.s DSxCrt ;yes, use data comm 0 0.7 MOVE.L WRcharpt(A0),A2 ;get character set record pointer CLR.L D3 ; MOVE.B WRstate(A0),D3 ; LSL.W #1,D3 ;convert to state table index LEA DSsTbl,A1 ; MOVE.W 0(A1,D3.W),D3 ;D3 = dist from DSsTbl JMP 0(A1,D3.W) ;go to current state processing ; DSnxtSt ADDQ.B #1,WRstate(A0) ;increment for next state BRA.S DSexit ;return ; DSxCrt move.l #DScPort,a1 ;get UART pointer 0.7 DSxCrt1 btst #DSwrBit,DSuSt(a1) ;is UART output busy? 0.7 boff.s DSxCrt1 ;yes, try again 0.7 move.b d0,DSuDa(a1) ;output the character 0.7 cmpi.b #DSCcr,d0 ;was it a ? 0.7 bne.s DSreset ;no, go on 0.7 btst #1,CPdspflg.w ;auto line feed? 0.7 bon.s DSreset ;yes, bypass insertion 0.7 moveq #DSClf,d0 ;add a 0.7 BRA.S DSxCrt1 ;output LF 0.8 DSreset CLR.B WRstate(A0) ;reset current state ; DSexit MOVEM.L (SP)+,D0-D7/A0-A6 ;restore registers RTS ;return page DSst0 CMP.B #DSCesc,D0 ;is char ESC? BEQ.S DSnxtSt ;yes, go to next state CMP.W CSfrstch(A2),D0 ;ascinum < first char? BLO.S DSctl ;yes, it's a control char BSR.S DSshwCh ;display character BSR DSincx ;inccurx BRA.S DSexit ;return DSctl SUBQ.W #8,D0 ;commence decoding ctrl char BMI.S DSexit ; CMPI.W #5,D0 ;ascinum in [8..13]? BHI.S DSexit ;yes, do cursor ctrl LEA DScTbl,A3 ;A3==>jump table for ctrl chars LSL.W #1,D0 ;make it word count PEA DSexit ;ensure RTS to exit ;---- MOVE.W 0(A3,D0),D0 ;D0 is offset from DScTbl 0.8 ;---- JMP 0(A3,D0) ;jump to proper routine 0.8 BRA.S DSgortn ;goto proper routine 0.8 DSesc CLR.W D1 ;initialize index reg LEA DSeTbl,A3 ;A3==> beginning of table ; DSesc1 CMP.W 0(A3,D1),D0 ;does table entry match char? BEQ.S DSesc2 ;yes, go on ADDQ.W #4,D1 ;go to next entry TST.W 0(A3,D1) ;end of table? BPL.S DSesc1 ;no, loop BRA.S DSreset ;return ; DSesc2 MOVE.W D1,D0 ;set D0 to table offset ADDQ.W #2,D0 ; PEA DSreset ;ensure RTS to reset state DSgortn MOVE.W 0(A3,D0),D0 ;D0 is offset from DSeTbl JMP 0(A3,D0) ;jump to proper routine page ; ; DSshwCh - Display character ; ; Enter: A0.L = window record pointer ; A2.L = character set record pointer ; D0.W = ASCII character ; ; Note: Character set must be in bytes, not words ; DSshwCh BSR DScvtUC ;convert character to upper case CMP.W CSfrstch(A2),D0 ;is character in character set? BLT.S DSshow1 ;no, output space CMP.W CSlastch(A2),D0 ;* BLE.S DSshow2 ;yes, output character DSshow1 MOVE.W #DSCblnk,D0 ;no, output space ; DSshow2 SUB.W CSfrstch(A2),D0 ;get relative character position LEA DScsetV+CSdata,a3 ;get pointer to character data MULU #DScellW,D0 ;* ADDA.L D0,A3 ;* MOVE.L WRcuradr(A0),A4 ;get current character address MOVE.W CSlpch(A2),D1 ;get number of scan lines for character SUBQ.W #1,D1 ;get count for DBRA MOVE.W CPscnofs.W,D3 ;get scan line length MOVE.W WRbitofs(A0),D5 ;get bit offset of character in cell MOVE.L CSmask(A2),D6 ;get character mask BTST #vert,WRattr2(A0) ;is this vertical orientation? BOFF.S DSshow6 ;no, output horizontal character ; ; output vertical orientation character ; MOVE.L D6,D0 ; NOT.L D0 ;D0 = inverted mask ROR.L D5,D6 ;D6 = positioned mask DSshow3 MOVE.B (A3)+,D2 ;D2 = char data LSL.W #8,D2 ; SWAP D2 ;get char in high word AND.L D0,D2 ;clear rest of source char LSR.L D5,D2 ;position source char AND.L D6,(A4) ;clear dest char area OR.L D2,(A4) ;move in character SUBA.W D3,A4 ; DBRA D1,DSshow3 ;repeat for D1:=CSlpch-1 to 0 BRA.S DSshow9 ;return page ; ; output horizontal orientation character ; DSshow6 TST.W -(A4) ;A4==>long word with cell ROL.L D5,D6 ;D6 = positioned mask MOVE.L D6,D4 ; NOT.L D4 ;D4 = inverted mask moveq #7,d0 ;use 8 bits of character data ; DSshow7 clr.l d2 ;clear current scan line of character tst.w d0 ;have we used 8 bits of character data? blt.s DSshw76 ;yes, pad with space btst d0,0(a3) ;construct next horizontal character boff.s DSshw71 ;* from vertical character data bset #0,d2 ;* DSshw71 btst d0,1(a3) ;* boff.s DSshw72 ;* bset #1,d2 ;* DSshw72 btst d0,2(a3) ;* boff.s DSshw73 ;* bset #2,d2 ;* DSshw73 btst d0,3(a3) ;* boff.s DSshw74 ;* bset #3,d2 ;* DSshw74 btst d0,4(a3) ;* boff.s DSshw75 ;* bset #4,d2 ;* DSshw75 btst d0,5(a3) ;* boff.s DSshw76 ;* bset #5,d2 ;* DSshw76 subq #1,d0 ;indicate another bit used LSL.L D5,D2 ;shift char into position AND.L D6,(A4) ; OR.L D2,(A4) ; SUBA.W D3,A4 ; DBRA D1,DSshow7 ; DSshow9 RTS ;return page ; ; DScrsR -- cursor right ; DScrsR BSR DScurs0 ;remove cursor DSincx MOVE.W WRcursx(A0),D1 ;get current cursor X position ADDQ.W #DScellW,D1 ;increment 1 character space 0.6 MOVE.W D1,WRcursx(A0) ;save new cursor X position 0.6 CMP.W WRlngthx(A0),D1 ;at end of line? 0.6 BGE.S DSrtrn1 ;yes, do carriage return 0.6 BRA.S DScurs ;show cursor 0.6 ; ; DScrsU -- cursor up ; DScrsU BSR.S DScurs0 ;remove cursor BRA.S DSdecy ;decrement cursor Y position ; ; DSrtrn -- return ; DSrtrn BSR.S DScurs0 ;remove cursor DSrtrn1 CLR.W WRcursx(A0) ;zero current cursor X position BTST #1,CPdspflg.w ;auto line feed? BOFF.S DSincy ;no, increment cursor Y position BRA.S DScurs ;show cursor ; ; DScrsD -- cursor down ; DScrsD BSR.S DScurs0 ;remove cursor DSincy MOVE.W WRcursy(A0),D1 ;get current cursor Y position ADDI.W #DScellY,D1 ;increment 1 character space 0.6 MOVE.W D1,WRcursy(A0) ;save new cursor Y position 0.6 CMP.W WRlngthy(A0),D1 ;at bottom of screen? 0.6 BLE.S DScurs ;on bottom line? 0.6 BRA DSclAL ;yes, wrap to home position 0.6 ; ; DScrsL -- cursor left ; DScrsL BSR.S DScurs0 ;remove cursor DSdecx TST.W WRcursx(A0) ;at beginning of line? BEQ.S DSwrapx ;yes, wrap to previous line SUBQ.W #DScellW,WRcursx(A0) ;decrement 1 character space BRA.S DScurs ;show cursor page ; ; DScrsH -- cursor home ; DScrsH BSR.S DScurs0 ;remove cursor DScrsH1 CLR.W WRcursx(A0) ;zero current cursor X position CLR.W WRcursy(A0) ;zero current cursor Y position BRA.S DScurs ;show cursor DSwrapx BSR.S DSwrap ; MOVE.W D0,WRcursx(A0) ; DSdecy TST.W WRcursy(A0) ;at top line? BEQ.S DScurs ;yes, show cursor SUBI.W #DScellY,WRcursy(A0) ;decrement 1 character space BRA.S DScurs ;show cursor DSwrap CLR.L D0 ;get current cursor X position MOVE.W WRlngthx(A0),D0 ;* MOVEQ #DScellW,D2 ;get character width DIVU D2,D0 ; MULU D2,D0 ; RTS ;return DScurs BSR.S DScrsAd ;compute cursor address DScurs0 MOVE.W CSlpch(A2),D1 ;get scan lines per character SUBQ.W #1,D1 ;set loop counter MOVE.L WRcuradr(A0),A4 ;get current cursor address MOVE.W WRbitofs(A0),D5 ;get current cursor bit offset MOVE.L CSmask(A2),D7 ;get character mask BTST #vert,WRattr2(A0) ;vertical orientation? BOFF.S DScurs1 ;no ROR.L D5,D7 ; BRA.S DScurs2 ; DScurs1 TST.W -(A4) ; ROL.L D5,D7 ; DScurs2 NOT.L D7 ;D7 = positioned inverted mask DScurs3 EOR.L D7,(A4) ;invert character SUBA.W CPscnofs.W,A4 ;* DBRA D1,DScurs3 ;* RTS ;return DScrsAd MOVEM.W WRcursx(A0),D5-D6 ;get current cursor position BSR DSaddr ;compute cursor address MOVE.W D7,WRbitofs(A0) ;save cursor bit offset MOVE.L A4,WRcuradr(A0) ;save cursor address RTS ;return page ; ; DSclAL -- clear screen ; DSclAL BSR DScrsH1 ;home cursor ; ; DSclES -- clear to end of screen ; DSclES BSR.S DSclEL ;first clear this line BTST #vert,WRattr2(A0) ;vertical orientation? BON.S DSclES2 ;yes, clear vertical screen ; --- clear to end of horizontal screen MOVE.W WRcursy(A0),D6 ;get current cursor Y position DSclES1 ADDI.W #DScellY,D6 ;increment to next line MOVE.W WRlngthy(A0),D0 ;get bottom of screen limit CMP.W D0,D6 ;at bottom of screen? BGE.S DSclES9 ;yes, return SUB.W D6,D0 ;compute number of scan lines to clear CLR.W D3 ;set starting X position to 0 BSR.S DSclrH ;clear to bottom of screen BRA.S DSclES9 ;return ; --- clear to end of vertical screen DSclES2 MOVE.W WRcursy(A0),D0 ;get current cursor Y position DSclES3 ADDI.W #DScellY,D0 ;increment to next line CMP.W WRlngthy(A0),D0 ;at bottom of screen? BGE.S DSclES9 ;yes, return MOVE.W D0,D6 ; CLR.W D5 ; BSR.S DSclrV ;clear one vertical line BRA.S DSclES3 ;repeat until all lines cleared ; DSclES9 RTS ;return ; ; DSclEL -- clear to end of line ; DSclEL BSR DScurs0 ;remove cursor MOVEM.W WRcursx(A0),D5-D6 ;get current cursor X and Y BTST #vert,WRattr2(A0) ;vertical orientation BOFF.S DSclEL1 ;no, clear horizontal line BSR.S DSclrV ;clear one vertical line BRA.S DSclEL2 ;show cursor ; DSclEL1 MOVEQ #DScellY-1,D0 ;D0 = #scanlines to clear MOVE.W D5,D3 ; BSR.S DSclrH ;clear one horizontal line DSclEL2 BRA DScurs0 ;show cursor page DSclrV MOVE.W WRlngthx(A0),D4 ;get length of line SUB.W D5,D4 ;compute number of scan lines clear BSR DSaddr ;compute cursor address MOVE.W CPscnofs.W,D1 ;get bytes per scan line MOVE.L CSmask(A2),D6 ;get character mask ROR.L D7,D6 ;align character mask DSclrV1 AND.L D6,(A4) ;clear one scan line SUBA.W D1,A4 ;compute address of next scan line DBRA D4,DSclrV1 ;repeat to end of line RTS ;return DSclrH MOVE.W WRlngthx(A0),D4 ;D5 = x, D6 = y ADDQ.W #1,D4 ; MOVE.W D4,D5 ; SUB.W D3,D4 ; BSR DSaddr ;A4 = addr(x,y), D7 = bitnum SUB.W D7,D4 ; TST.W D7 ; BNE.S DSclrH1 ; TST.W (A4)+ ; DSclrH1 MOVE.W D4,D3 ; ANDI.W #$F,D3 ; ASR.W #4,D4 ; SUBQ.W #1,D4 ; MOVEQ #-1,D1 ; MOVE.W D1,D2 ; LSL.W D7,D1 ; LSR.W D3,D2 ; DSclrH2 MOVE.L A4,A5 ; TST.W D7 ; BEQ.S DSclrH3 ; AND.W D1,(A5)+ ; DSclrH3 MOVE.W D4,D6 ; BMI.S DSclrH5 ; DSclrH4 CLR.W (A5)+ ; DBRA D6,DSclrH4 ; DSclrH5 TST.W D3 ; BEQ.S DSclrH6 ; AND.W D2,(A5) ; DSclrH6 SUBA.W CPscnofs.W,A4 ; DBRA D0,DSclrH2 ; RTS ;return page DStab MOVE.W WRcursx(A0),D0 ;get current cursor X position AND.L #$FFFF,D0 ;clear hi word MOVEQ #DScellW*8,D2 ; DIVU D2,D0 ;find next tab to right ADDQ.W #1,D0 ; MULU D2,D0 ; CMP.W WRlngthx(A0),D0 ;new x > right? BLS.S DStab1 ;no, change x RTS ;return DStab1 BSR DScurs0 ;remove cursor MOVE.W D0,WRcursx(A0) ;save new cursor X position BRA DScurs ;show cursor ; ; DSaddr -- compute cursor address ; ; Enter: D5 = x ; D6 = y ; ; Exit: DSaddr (x,y) in A4, bit offset in D7 ; DSaddr MOVEA.L WRhomept(A0),A4 ;get home pointer for orientation BTST #vert,WRattr2(A0) ;vertical orientation? BON.S DSaddrV ;yes, compute address for vertical ; DSaddrH ADD.W WRhomeof(A0),D5 ; MOVE.W D5,D7 ; ANDI.W #$F,D7 ; ASR.W #4,D5 ; ASL.W #1,D5 ; SUBA.W D5,A4 ; MULU CPscnofs.W,D6 ; SUBA.L D6,A4 ; RTS ;return ; DSaddrV ADD.W WRhomeof(A0),D6 ; MOVE.W D6,D7 ; ANDI.W #$F,D7 ; ASR.W #4,D6 ; ASL.W #1,D6 ; ADDA.W D6,A4 ; MULU CPscnofs.W,D5 ; SUBA.L D5,A4 ; RTS ;return page ; ; jump tables ; DScTbl DATA.W DScrsL-DScTbl ;ctl-H: back space DATA.W DStab-DScTbl ;ctl-I: tab DATA.W DScrsD-DScTbl ;ctl-J: line feed DATA.W DScrsU-DScTbl ;ctl-K: cursor up DATA.W DScrsR-DScTbl ;ctl-L: cursor right DATA.W DSrtrn-DScTbl ;ctl-M: carriage return DSeTbl DATA.W $48,DScrsH-DSeTbl ;esc-H: home cursor DATA.W $4A,DSclAL-DSeTbl ;esc-J: clear screen DATA.W $4B,DSclEL-DSeTbl ;esc-K: clear to end of line DATA.W $59,DSclES-DSeTbl ;esc-Y: clear to end of screen DATA.W -1 ;end of table DSsTbl DATA.W DSst0-DSsTbl ;state 0 DATA.W DSesc-DSsTbl ;state 1 DSwndH DATA.L DScsetH ;WRcharpt DATA.L DShomeH ;home DATA.L DShomeH ;address DATA.W 0,0,0 ;WRhomeof,WRbasex,WRbasey DATA.W DSmaxXH,DSmaxYH ;right,bottom DATA.W 0,0,0 ;x,y,WRbitofs DATA.W 0,DSmaxYH ;WRgrorgx,WRgrorgy DATA.B 0,$1C ;attr1,attr2 DATA.B 0,WRlength ;state, WRrcdlen DScsetH DATA.L DScsetV+CSdata ;character set record pointer DATA.W DScellY,DScellW ;CSlpch, CSbpch DATA.W 32,90 ;CSfrstch, CSlastch DATA.W $FFFF,$FFC0,0 ;mask, dummy, attribs ; ; use vertical character set data ; page DSwndV DATA.L DScsetV ;WRcharpt DATA.L DShomeV ;home DATA.L DShomeV ;address DATA.W 0,0,0 ;WRhomeof,WRbasex,WRbasey DATA.W DSmaxXV,DSmaxYV ;right,bottom DATA.W 0,0,0 ;x,y,WRbitofs DATA.W 0,DSmaxYV ;WRgrorgx,WRgrorgy DATA.B 0,$1D ;attr1,attr2 DATA.B 0,WRlength ;state, WRrcdlen DScsetV DATA.L DScsetV+CSdata ;character set record pointer DATA.W DScellW,DScellY ;CSlpch, CSbpch DATA.W 32,90 ;CSfrstch, CSlastch DATA.W $003F,$FFFF,256 ;mask, dummy, attribs ; ; vertical character set data ; DATA.B 0,0,0,0,0,0 ; blank DATA.B 0,0,$FD,0,0,0 ; ! DATA.B 0,$E0,0,$E0,0,0 ; " DATA.B $28,$FE,$28,$FE,$28,0 ; # DATA.B $24,$54,$FE,$54,$48,0 ; $ DATA.B $C4,$C8,$10,$26,$46,0 ; % DATA.B $6C,$92,$6A,$04,$0A,0 ; & DATA.B 0,0,$20,$C0,0,0 ; ' DATA.B 0,$38,$44,$82,0,0 ; ( DATA.B 0,0,$82,$44,$38,0 ; ) DATA.B $08,$2A,$1C,$2A,$08,0 ; * DATA.B $08,$08,$3E,$08,$08,0 ; + DATA.B 0,$01,$07,0,0,0 ; , DATA.B $10,$10,$10,$10,$10,0 ; - DATA.B 0,0,$02,0,0,0 ; . DATA.B $04,$08,$10,$20,$40,0 ; / DATA.B $7C,$8A,$92,$A2,$7C,0 ; 0 DATA.B 0,$42,$FE,$02,0,0 ; 1 DATA.B $46,$8A,$92,$92,$62,0 ; 2 DATA.B $84,$82,$92,$B2,$CC,0 ; 3 DATA.B $18,$28,$48,$FE,$08,0 ; 4 DATA.B $E4,$A2,$A2,$A2,$9C,0 ; 5 DATA.B $3C,$52,$92,$92,$1C,0 ; 6 DATA.B $80,$8E,$90,$A0,$C0,0 ; 7 DATA.B $6C,$92,$92,$92,$6C,0 ; 8 DATA.B $62,$92,$92,$94,$78,0 ; 9 DATA.B 0,0,$24,0,0,0 ; : DATA.B 0,$01,$26,0,0,0 ; ; DATA.B 0,$10,$28,$44,$82,0 ; < DATA.B 0,$28,$28,$28,$28,0 ; = DATA.B 0,$82,$44,$28,$10,0 ; > DATA.B $40,$80,$9A,$A0,$40,0 ; ? DATA.B $7C,$82,$9A,$9A,$7A,0 ; @ DATA.B $3E,$48,$88,$48,$3E,0 ; A DATA.B $FE,$92,$92,$92,$6C,0 ; B DATA.B $7C,$82,$82,$82,$44,0 ; C DATA.B $FE,$82,$82,$82,$7C,0 ; D DATA.B $FE,$92,$92,$82,$82,0 ; E DATA.B $FE,$90,$90,$80,$80,0 ; F DATA.B $7C,$82,$8A,$8A,$4C,0 ; G DATA.B $FE,$10,$10,$10,$FE,0 ; H DATA.B 0,$82,$FE,$82,0,0 ; I DATA.B $04,$82,$82,$FC,$80,0 ; J DATA.B $FE,$10,$28,$44,$82,0 ; K DATA.B $FE,$02,$02,$02,$02,0 ; L DATA.B $FE,$40,$30,$40,$FE,0 ; M DATA.B $FE,$20,$10,$08,$FE,0 ; N DATA.B $7C,$82,$82,$82,$7C,0 ; O DATA.B $FE,$90,$90,$90,$60,0 ; P DATA.B $7C,$82,$8A,$84,$7A,0 ; Q DATA.B $FE,$90,$98,$94,$62,0 ; R DATA.B $64,$92,$92,$92,$4C,0 ; S DATA.B $80,$80,$FE,$80,$80,0 ; T DATA.B $FC,$02,$02,$02,$FC,0 ; U DATA.B $F8,$04,$02,$04,$F8,0 ; V DATA.B $FC,$02,$1C,$02,$FC,0 ; W DATA.B $C6,$28,$10,$28,$C6,0 ; X DATA.B $C0,$20,$1E,$20,$C0,0 ; Y DATA.B $86,$8A,$92,$A2,$C2,0 ; Z DATA.W 0 page ;p.prom.ld ; list 1 ; File: CC.PROM.LD.TEXT ; Date: 15-Nov-83 ; By: L. Franklin ; ; Lboot -- Local Corvus disk boot processing ; Lboot movea.l #CPsl1typ,a1 ;get pointer to slot 1 type moveq #1,d0 ;get initial slot number ; Lboot10 move.b -1(a1,d0),d1 ;get device type cmp.b #DTlocl,d1 ;is this a local disk interface? beq.s Lboot30 ;yes, use it for booting addq #1,d0 ;update slot number cmp.w #4,d0 ;have we looked at all slots? ble.s Lboot10 ;no, check next slot moveq #-1,d7 ;set error return code bra.s Lboot90 ;return (can not find local disk) ; Lboot30 move.b d0,CPbtslot.w ;set boot slot number clr.b CPbtsrvr.w ;set boot server number lea LDblkIO,a6 ;set boot disk blk i/o subr pointer move.l a6,CPblkio.w ;* lea LDdskIO,a6 ;set boot disk i/o subr pointer move.l a6,CPdskio.w ;* ; ; fall through to Lboot10 (used by OMNINET boot too) ; page ; ; Lboot80 -- Get 2 boot blocks from Corvus disk 0.8 ; (code shared by local disk boot and OMNINET disk boot) ; Entry : A6 = address of disk I/O routine 0.8 ; Exit : lt = error 0.8 ; ge = good 0.8 ; A0 = if good then address of entry to boot code 0.8 ; Lboot80 movea.l #USRbase,a0 ;get block buffer pointer move.b CPbtsrvr.w,d6 ;get boot server number blt.s Lboot90 ;just return if invalid server number lsl.w #8,d6 move.b CPbtslot.w,d6 ;get boot slot number ;setup boot command move.w #$4404,(a0) ;put in opcode & computer type 0.8 moveq #$01,d0 ;set boot block number 0.8 move.w #$203,d1 ;read 2nd block first bsr.s LDgetBB ;get next boot block blt.s Lboot90 ;just return if error moveq #$3,d1 ;read 1st block 2nd 0.8 bsr.s LDgetBB ;get next boot block blt.s Lboot90 ;just return if error adda.w #4+12,a0 ;get pointer to boot code 0.8 ; past cmd, rslt code and file header Lboot90 rts LDgetBB move.b d0,2(a0) ;set boot block number moveq #3,d2 ;get number of bytes to send moveq #DskWrit,d5 ;get "write" command jsr (a6) ;send command adda.w d1,a0 ;adr where to put boot code move.w #513,d2 ;get number of bytes to receive moveq #DskRead,d5 ;get "read" command jsr (a6) ;read results blt.s LDgetBX ;just return if error suba.w d1,a0 ;point back at command subq.l #1,d0 ;update boot block number 0.8 LDgetBX tst.b d7 rts ;return page ; ; LDblkIO - Read or write a local disk block subroutine ; ; Enter: A0.L - Buffer address ; D0.L - Block number 0.7 ; D1.W - Drive number ; D5.W - Read ($32) or Write ($33) command ; D6.B - Slot number ; ; Exit: A0.L - Next free location in buffer ; D0.L - Updated block number 0.7 ; D7.W - IORESULT (disk controller status) ; ; All other registers are preserved. ; ; Corvus controller status register [3(a1)]: ; ; bit 7: controller ready off - ready on - not ready ; bit 6: bus direction off - host to cntlr on - cntlr to host ; LDblkIO movem.l a1/d0-d2,-(sp) ;Save registers bsr SlotAdr ;A1 = I/O port address move.w d5,d2 ;Send a read ($32) or bsr.s LDsend1 ; write ($33) block command move.l d0,d2 ;Compute drive nmbr/MSN block nmbr 0.7 swap d2 ;* 0.7 lsl.w #4,d2 ;* 0.7 or.b d1,d2 ;* 0.7 bsr.s LDsend ;Send drive number move.w d0,d2 ; bsr.s LDsend ;Send LSB of block lsr.w #8,d2 ; bsr.s LDsend ;Send MSB of block cmpi.w #DskWrit,d5 ;Are we reading or writing? bne.s LDrio1 ;Reading ; ;Write block processing ; move.w #$1FF,d2 ;Block size - 1 LDwio1 btst #7,3(a1) ;Test controller status bon.s LDwio1 ;Wait until controller ready move.b (a0)+,1(a1) ;Send a byte dbra d2,LDwio1 ;Loop until done bsr.s LDwait ;Wait for line to turn move.b 1(a1),d7 ;Fetch result code bra.s LDrtrn ;Return page ; ;Read block processing ; LDrio1 bsr.s LDwait ;Wait for the line to turn move.b 1(a1),d7 ;Fetch result code ; LDrio3 btst #7,3(a1) ;Test controller status bon.s LDrio3 ;Wait until controller ready btst #6,3(a1) ;Test bus direction boff.s LDrtrn ;Finished if "host to controller" move.b 1(a1),(a0)+ ;Store next byte bra.s LDrio3 ;Go get any more ; LDrtrn movem.l (sp)+,a1/d0-d2 ;Restore registers addq.l #1,d0 ;Update block number 0.8 move.b d7,CPdiskRC.w ;Save current disk return code 0.7 ext.w d7 ;Set return condition code rts ;Return page ; ; LDsend -- Send a byte to the disk port subroutine ; ; Enter: A1.L - I/O port address ; D2.B - Byte to send ; ; All registers are preserved. ; LDsend btst #7,3(a1) ;Test controller status bon.s LDsend ;Wait until controller ready move.b d2,1(a1) ;Send the byte rts ;Return ; ; LDsend1 -- Send first byte to the disk port subroutine ; ; Enter: A1.L - I/O port address ; D2.B - Byte to send ; ; All registers are preserved. ; LDsend0 move.w (sp)+,sr ;enable interrupts nop ;leave some time for interrupt processing LDsend1 move.w sr,-(sp) ;save interrupt level ori.w #$0700,sr ;disable interrupts btst #7,3(a1) ;test controller status bon.s LDsend0 ;wait until controller ready move.b d2,1(a1) ;send first byte move.w (sp)+,sr ;enable interrupts rts ;return ; ; LDwait -- Wait for the line to turn subroutine ; ; Enter: A1.L - I/O port address ; LDwait move.l d0,-(sp) ;save register moveq #100,d0 ;wait a little bit LDwait1 dbra d0,LDwait1 ;* move.l (sp)+,d0 ;restore register bsr.s LDwait2 ;check two times in case of glitch nop ;* ; LDwait2 btst #7,3(a1) ;test controller status bon.s LDwait2 ;wait until controller ready btst #6,3(a1) ;test bus direction boff.s LDwait2 ;wait until "controller to host" rts ;return page ; ; LDdskIO - Read from/Write to Corvus disk ; ; Enter: A0.L - Buffer address ; D2.W - Count ; D5.W - Read ($32) or Write ($33) command ; D6.B - Slot number ; ; Exit: D7.W - IORESULT (disk controller status) ; ; All other registers are preserved. ; LDdskIO movem.l d0-d3/a0-a1,-(sp);Save registers bsr SlotAdr ;A1 = I/O port address move.w d2,d3 ;get count subq.w #1,d3 ;Set DBRA loop length cmpi.w #DskWrit,d5 ;Are we reading or writing? bne.s LDdsk2 ;Reading ; ; Write Corvus disk processing ; move.b (a0)+,d2 ;get first byte bsr.s LDsend1 ;send first byte bra.s LDdsk1a ;send rest of bytes LDdsk1 move.b (a0)+,d2 ;get next byte bsr LDsend ;send next byte LDdsk1a dbra d3,LDdsk1 ;loop until done moveq #0,d7 ;force successful result code bra.s LDdsk9 ;finished ; ; Read Corvus disk processing ; LDdsk2 bsr.s LDwait ;Wait for the line to turn move.b 1(a1),d7 ;Fetch result code move.b d7,(a0)+ ;Store first byte ; LDdsk3 btst #7,3(a1) ;Test controller status bon.s LDdsk3 ;Wait until controller ready btst #6,3(a1) ;Test bus direction boff.s LDdsk9 ;Finished if "host to controller" move.b 1(a1),(a0)+ ;Store next byte bra.s LDdsk3 ;Go get any more ; LDdsk9 movem.l (sp)+,d0-d3/a0-a1;Restore registers move.b d7,CPdiskRC.w ;Save current disk return code 0.7 ext.w d7 ;Set return condition code rts ;Return page ; ; LDsync -- Synchronize with Corvus disk controller ; ; Enter: D6.B - slot number ; ; Exit: D7.W - 0 = no timeout (EQ), -1 = timeout (NE) ; ; All other registers are preserved. ; LDsync movem.l d0/a1,-(sp) ;save registers bsr SlotAdr ;get slot address ; ---- move.w #2000,d7 ;set timeout counter 0.7 move.w #3000,d7 ;set timeout counter 0.7 ; LDsync1 move.b #$FF,1(a1) ;send invalid command to controller move.w #1024,d0 ;wait about 1 ms LDsync2 dbra d0,LDsync2 ;* btst #6,3(a1) ;test bus direction bon.s LDsync3 ;go on if "controller to host" dbra d7,LDsync1 ;send invalid command again bra.s LDsync5 ;set timeout error and return ; LDsync3 btst #7,3(a1) ;test controller status boff.s LDsync6 ;go on if controller ready dbra d7,LDsync3 ;check controller status again ; LDsync5 moveq #-1,d7 ;indicate controller timeout bra.s LDsync9 ;return ; LDsync6 cmpi.b #$8F,1(a1) ;did controller respond with error? bne.s LDsync1 ;no, send invalid command again moveq #0,d7 ;indicate no controller timeout ; LDsync9 movem.l (sp)+,d0/a1 ;restore registers tst.w d7 ;set return condition code rts ;return page ;p.prom.od ; ; File: CC.PROM.OD.TEXT ; Date: 18-Nov-83 ; OMNINET disk driver data area equates ; DCmd EQU 0 ;byte - disk command offset DCdrv EQU 1+DCmd ;byte - offset for drive number DCblklo EQU 2+DCmd ;byte - LSB of block number to read or write DCblkhi EQU 3+DCmd ;byte - MSB " " DClen EQU 4+DCmd ;word - length of request (in bytes) ; result vector and header used for all setuprecv commands ; RHdr EQU 6 ; RHpktRC EQU 0+RHdr ;byte - return code from transporter RHsor EQU 1+RHdr ;byte - the source of the message RHpktLN EQU 2+RHdr ;word - total length of data portion of packet RHdskLN EQU 4+RHdr ;word - length of info returned from drive RHdskRC EQU 6+RHdr ;byte - return code from drive ; ; result vector and header for all sendmsg commands ; SHdr EQU 14 ; SHpktRC EQU 0+SHdr ;byte - return code from transporter ; EQU 1+SHdr ;byte - unused ; EQU 2+SHdr ;word - unused SHtoLN EQU 4+SHdr ;word - number of bytes to send to drive SHfmLN EQU 6+SHdr ;word - number of bytes expected from drive ; GData EQU 22 ;word - area to receive "GO" into ; area used for constructing Transporter commands ; TCmd EQU 24 ; TCop EQU 0+TCmd ;byte - op code TCrADhi EQU 1+TCmd ;byte - result address HI TCrADlo EQU 2+TCmd ;word - result address MED, LO TCsock EQU 4+TCmd ;byte - socket number TC6801Ad EQU 4+TCmd ;word - 6801 addr for peek/poke 0.8 TCdADhi EQU 5+TCmd ;byte - data buffer address HI TCdADlo EQU 6+TCmd ;word - data buffer address MED, LO TCpekpok EQU 6+TCmd ;byte - peek/poke function code 0.8 TCdtaLN EQU 8+TCmd ;word - data length TChdrLN EQU 10+TCmd ;byte - header length TCdest EQU 11+TCmd ;byte - destination host number ; ODdw EQU 36 ;lint - temporary buffer (for 3 byte nmbrs) ODdwhi EQU 37 ;byte - temporary HI ODdwlo EQU 38 ;word - temporary MID, LO ODwrAD EQU 40 ;lint - to save buffer address for CWrites ODvalid EQU 44 ;word - for marking buffer as valid EHpktRC EQU 46 ;byte - End Recv result code page ; Transporter Return Codes ; Waiting EQU $FF ; CmdAcpt EQU $FE ; Echoed EQU $C0 ;echo command was successful ; GaveUp EQU $80 ;aborted a send command after MaxRetries tries TooLong EQU $81 ;last message sent was too long for the receiver NoSockt EQU $82 ;sent to an unititialized socket HdrErr EQU $83 ;sender's header length did not match receiver's BadSock EQU $84 ;illegal socket number Inuse EQU $85 ;tried to set up a receive on an active socket BadDest EQU $86 ;sent to an illegal host number NoTrans EQU -112 ;could not strobe cmd addr to Transporter TimeOut EQU -111 ;timed out waiting for an Omninet event NoBufr EQU -110 ;tried a CRRead without a valid write buffer ; ; Transporter Opcodes ; RecvOp EQU $F0 ;SETUPRECV opcode SendOp EQU $40 ;SENDMSG opcode InitOp EQU $20 ;INIT opcode EndOp EQU $10 ;ENDRECV opcode DebOp EQU $08 ;PEEK/POKE opcode EchoOp EQU $02 ;ECHOCMD opcode WhoOp EQU $01 ;WHOAMI opcode ; Socket numbers ; RestSkt EQU $A0 ;dest. socket for REST packet CnstSkt EQU $B0 ;socket for disk server protocol CIIpSkt EQU $80 ;socket for Const II protocol 0.8 ; Const II protocol ; C2pid EQU $01FE ;Const II protocol id 0.8 C2whomg EQU $0200 ;msgtype= who msg 0.8 C2idmsg EQU $1000 ;msgtype= identification 0.8 C2dsksrv EQU $0001 ;devtype= disk server 0.8 ; Const II protocol message form 0.8 ; 0.8 C2Ppid EQU 0 ;word - protocol id 0.8 C2Pmsgtp EQU C2Ppid+2 ;word - message type 0.8 C2Psrc EQU C2Pmsgtp+2 ;word - source host number 0.8 C2Pdevtp EQU C2Psrc+2 ;word - device type 0.8 C2PwhoLn EQU C2Pdevtp+2 ;length of "who" msg 0.8 C2Pname EQU C2Pdevtp+2 ;chars - name 10 bytes 0.8 C2PmaxLn EQU C2Pname+10 ;length of other msgs 0.8 TOintvl EQU $2FFFF ;timeout interval 0.8 page ; ; Oboot -- OMNINET disk server boot processing ; Oboot tst.b CPbtsrvr.w ;is server number valid? 0.7 bge.s Oboot10 ;yes, go on 0.7 bsr ODbroad ;send broadcast message to disk srvr 0.7 ;* in order to get disk server 0.7 ;* Transporter number 0.7 move.b d7,CPbtsrvr.w ;save boot server number 0.7 Oboot10 move.b #5,CPbtslot.w ;set boot slot number lea ODblkIO,a6 ;set boot disk blk i/o subr pointer move.l a6,CPblkio.w ;* lea ODdskIO,a6 ;set boot disk i/o subr pointer move.l a6,CPdskio.w ;* bra Lboot80 ;load boot code ; (Lboot80 is in CC.PROM.LD) ; ; ODcomnd -- send simple command to Transporter ; ; Enter: D0.B - Transporter command ; D1.B - Destination host number (if ECHO) 0.7 ; D1.B - Socket number (if ENDRECV) 0.7 ; D1.B - MSB 6801 address (if PEEK/POKE) 0.8 ; ; Exit: D7.B - IORESULT (OMNINET status) ; ODcomnd movem.l a1-a3/d0,-(sp) ;save registers 0.8 move.l #CPomnibf,a1 ;get pointer to Data Area lea RHpktRc(A1), A3 ;assume not end recv 0.8 cmpi.b #EndOp, D0 ;if is a end recv use different 0.8 bne.s ODcmdgo ; result code location than 0.8 lea EHpktRC(A1), A3 ; the recv 0.8 ODcmdgo move.l A3,TCop(a1) ;(A3) = result record pointer 0.8 move.b d0,TCop(a1) ;set Transporter command move.b d1,TCsock(a1) ;set dest host number (ECHO) 0.7 ;set socket number (ENDRECV) 0.7 move.b #Waiting,(A3) ;set Transporter waiting flag 0.8 lea TCmd(A1),A2 ;get command address bsr StrobIt ;strobe command address to Transporter bne.s ODcmd9 ;Transporter not responding move.l #TOintvl,D0 ;get timeout interval 0.8 ODcmd1 move.b (A3),d7 ;get Transporter return code 0.8 cmpi.b #Waiting, d7 ;has Transporter responded? 0.8 bne.s ODcmd9 ;yes, ready to return 0.8 subq.l #1, D0 ;see if waited long enough 0.8 bpl.s ODcmd1 ;no, look again 0.8 moveq #TimeOut, d7 ;yes, set timeout error & return0.8 ODcmd9 movem.l (sp)+,a1-a3/d0 ;restore registers 0.8 move.b d7,CPomniRC.w ;save OMNINET return code 0.7 rts ;return page ; ; ODblkIO - Read or write an OMNINET disk server block subroutine ; ; Enter: A0.L - Buffer address ; D0.L - Block number 0.7 ; D1.W - Drive number ; D5.W - Read ($32) or Write ($33) command ; D6.W - Destination host number * 256 ; ; Exit: A0.L - Next free location in buffer ; D0.L - Updated block number 0.7 ; D7.W - IORESULT (OMNINET/disk controller status) ; ; All other registers are preserved. ; ODblkIO movem.l d0-d2/a1-a2,-(sp);Save registers move.l #CPomnibf,a1 ;A1 points to the start of the Data Area clr.w ODvalid(A1) ;buffer valid = False... see ODdskIO move.b D5,DCmd(A1) ;Stuff disk command - read or write move.l d0,d2 ;Compute drive nmbr/MSN block nmbr 0.7 swap d2 ;* 0.7 lsl.w #4,d2 ;* 0.7 or.b d1,d2 ;* 0.7 move.b D2,DCDrv(A1) ;stuff drive number 0.7 move.b D0,DCBlkLo(A1) ;lo order byte of block number lsr.w #8,D0 ; move.b D0,DCBlkHi(A1) ;hi order byte of block number move.w #512,DCLen(A1) ;set length to 512... cmpi.w #DskWrit,D5 ;Are we reading or writing? bne.s ODblk2 ;Reading ; ODblk1 move.w #516,SHtoLN(A1) ;number of bytes to send to drive clr.w SHfmLN(A1) ;number of bytes expected back move.l A0,ODwrAD(A1) ;save address of REST of data bsr LongCmds ;Writing bra.s ODblk3 ;return ; ODblk2 move.w #4,SHtoLN(A1) ;number of bytes to send to drive move.w #512,SHfmLN(A1) ;number of bytes expected back bsr ShortCmds ; ; ODblk3 movem.l (sp)+,d0-d2/a1-a2;Restore registers adda.w #512,a0 ;Update buffer pointer addq.l #1,d0 ;Update disk block number 0.8 move.b d7,CPdiskRC.w ;Save current disk return code 0.7 ext.w d7 ;Set return condition code rts ;Return page ; 0.7 ; ODbroad - Send broadcast message to disk server 0.7 ; 0.7 ; Exit: D7.W - disk server number 0.7 ; 0.7 ; All other registers are preserved. 0.7 ; 0.7 ODbroad movem.l d2-d6/a0,-(sp) ;save registers 0.7 move.l #NTO1,CPtimout.w;set timeout for broadcast 0.7 bsr.s ODC2broad ;do const II broadcast 0.8 bpl.s ODbrd90 ;found disk server 0.8 move.l #USRbase,a0 ;send broadcast message to disk srvr 0.7 move.b #$FF,(a0) ;* in order to get disk server 0.7 moveq #1,d2 ;* Transporter number 0.7 moveq #$33,d5 ;* 0.7 moveq #-1,d6 ;* 0.7 bsr ODdskIO ;* 0.7 moveq #$32,d5 ;* 0.7 bsr ODdskIO ;* 0.7 ODbrd90 move.l #NTO2,CPtimout.w;set timeout for normal network traffic 0.7 movem.l (sp)+,d2-d6/a0 ;restore registers 0.7 rts ;return 0.7 ; ; ODpeek - do peek at $F800 to find version number 0.8 ; 0.8 ; Exit: D7.B - peek data or error code 0.8 ; 0.8 ODpeek LEA CPomnibf.L, A1 ;omninet data area 0.8 MOVE.W #$F800, TC6801Ad(A1) ;put in 6801 addr to peek 0.8 CLR.B TCpekpok(A1) ;do peek 0.8 MOVEQ #DebOp, D0 ;peek/poke op code 0.8 MOVE.W #$F8, D1 ;ODcomnd puts D1 over TC6801Ad 0.8 BSR ODcomnd ;do peek 0.8 MOVE.B RHpktRC(A1), D7 ;get version number 0.8 RTS ; 0.8 page ; ; ODC2broad - broadcast the Const II who are you to find disk server 0.8 ; receive ident msg from disk server. 0.8 ; 0.8 ; Exit: MI - no response or error 0.8 ; PL - found disk server 0.8 ; D7.W - disk server number or error code 0.8 ; 0.8 ODC2broad ; 0.8 MOVEQ #1, D2 ;try 2 times max. 0.8 LEA CPomnibf.L, A1 ;omninet data area 0.8 ODC2b10 BSR.S Set80Rcv ;setup recv on socket $80 0.8 BNE.S ODC2Err ;error, do end recv 0.8 BSR SendWhoDS ;send who msg 0.8 BMI.S ODC2Err ;error, do end recv 0.8 MOVE.L CPtimout.W, D0 ;wait for response 0.8 ODC2wait MOVE.B RHpktRC(A1), D7 ;got it? 0.8 BEQ.S ODC2chk ;yes, check it out 0.8 SUBQ.L #1, D0 ;no, dec retry count 0.8 BNE.S ODC2wait ;if not zero test again 0.8 ODC2Err MOVEQ #EndOp, D0 ;ERROR - do endrecv 0.8 MOVE.W #CIIpSkt, D1 ; on socket $80 0.8 MOVE.W D7, -(SP) ;save error code or server host #0.8 BSR ODcomnd ;do end recv 0.8 MOVE.W (SP)+, D7 ;restore error code 0.8 DBRA D2, ODC2b10 ;do again if another retry 0.8 ODC2b90 EXT.W D7 ;set cc 0.8 RTS ;EXIT 0.8 ODC2chk BSR.S Set80Rcv ;setup recv again just in case 0.8 BNE.S ODC2Err ;error, restart 0.8 LEA USRbase.L, A0 ;verify msg is correct type 0.8 CMPI.W #C2pid, (A0) ;Const II pid? 0.8 BNE.S ODC2wait ;no, wait for correct msg 0.8 CMPI.W #C2idmsg, C2Pmsgtp(A0) ;Ident msg type? 0.8 BNE.S ODC2wait ;no, wait for correct msg 0.8 CMPI.W #C2dsksrv, C2Pdevtp(A0) ;from a disk server? 0.8 BNE.S ODC2wait ;no, wait for correct msg 0.8 ODC2bDS MOVE.W C2Psrc(A0), D7 ;get disk server host number 0.8 LEA C2Pname(A0), A0 ;move disk server name 0.8 LEA CPsrvnam.W, A1 ; into static memory 0.8 MOVEQ #C2PmaxLn-C2Pname-1, D0 ;10 bytes 0.8 ODC2move MOVE.B (A0)+, (A1)+ ; 0.8 DBRA D0, ODC2move ; 0.8 CLR.L D2 ;clear retry counter to show done0.8 BRA.S ODC2Err ;do end recv and exit 0.8 page ; ; Set80Rcv - setup a recv on socket 80 for Const II ident msg. 0.8 ; 0.8 ; Enter: A1 - omninet data area address 0.8 ; Exit: NE - error 0.8 ; EQ - setup worked 0.8 ; D7.W - error code 0.8 ; 0.8 Set80Rcv LEA USRbase.L, A0 ;address to receive ident msg 0.8 MOVE.L A0, TCdADhi-1(A1) ;put in transporter cmd block 0.8 MOVE.W #C2PmaxLn, TCdtaLN(A1) ;ident msg is 18 bytes 0.8 CLR.B TChdrLN(A1) ;socket $80 has no header area 0.8 MOVE.W #RecvOp, D0 ;setup recv 0.8 MOVE.W #CIIpSkt, D1 ; on socket $80 0.8 BSR ODcomnd ;do setup 0.8 CMPI.B #CmdAcpt, D7 ;was socket setup? 0.8 BNE.S S80Rexit ;no, report error 0.8 CLR.L D7 ;yes, show no error 0.8 S80Rexit RTS ; 0.8 page ; ; SendWhoDS - send Const II who are you msg to find disk server. 0.8 ; 0.8 ; Enter: A1 - omninet data area address 0.8 ; Exit: MI - error 0.8 ; PL - send worked 0.8 ; D7.B - error code 0.8 ; 0.8 SendWhoDS ; 0.8 LEA USRbase+$20.L, A0 ;address to put who msg 0.8 MOVE.L WhoMsg, (A0) ;move who msg from ROM 0.8 MOVE.L WhoMsg+4, 4(A0) ; to dynamic RAM 0.8 MOVE.B CPtprnbr.W, C2Psrc+1(A0) ;put in station's host # 0.8 MOVE.L A0, TCdADhi-1(A1) ;put in adr of msg as data 0.8 PEA SHdr(A1) ;result vector adr 0.8 MOVE.L (SP)+, TCrADhi-1(A1) ; put in cmd block 0.8 MOVE.B #SendOp, TCop(A1) ;send msg 0.8 MOVE.B #CIIpSkt, TCsock(A1); on socket $80 0.8 MOVE.W #C2PwhoLn, TCdtaLN(A1) ;msg length = 8 bytes 0.8 CLR.B TChdrLN(A1) ;socket $80 has no header area 0.8 MOVEQ #-1, D0 ; 0.8 MOVE.B D0, TCdest(A1) ;$FF means broadcast 0.8 MOVE.B D0, SHpktRC(A1) ;$FF means waiting for trnsprtr 0.8 LEA TCmd(A1), A2 ;stobe in cmd 0.8 BSR Strobit ; block 0.8 BNE.S SWDSexit ;timed out waiting for Ready 0.8 MOVE.L #TOintvl, D0 ;get timeout interval 0.8 SWDSwait MOVE.B SHpktRC(A1), D7 ;get result code 0.8 CMPI.B #Waiting, D7 ;has Transporter responded? 0.8 BNE.S SWDSdone ;yes, ready to return 0.8 SUBQ.L #1, D0 ;see if waited long enough 0.8 BPL.S SWDSwait ;no, look again 0.8 MOVEQ #TimeOut, D7 ;yes, set timeout error 0.8 SWDSdone MOVE.B D7, CPomniRC.w ;save OMNINET return code 0.8 SWDSexit RTS ;return 0.8 WhoMsg DATA.W C2pid ;Const II protocol id 0.8 DATA.W C2whomg ;who msg type code 0.8 DATA.W 0 ;source host number 0.8 DATA.W C2dsksrv ;disk server host type 0.8 page ; ; ODdskIO - Read from/write to Corvus disk ; ; Enter: A0.L - Buffer address ; D2.W - Count ; D5.W - Read ($32) or Write ($33) command ; D6.W - Destination host number * 256 ; ; Exit: D7.W - IORESULT (OMNINET/disk controller status) ; ; All other registers are preserved. ; ODdskIO movem.l d0-d2/a0-a2,-(sp);Save registers move.l #CPomnibf,a1 ;A1 points to the start of the Data Area moveq #-1, d0 ;get word of $FFFF 0.8 cmpi.w #DskWrit,D5 ;do we want to read or write bne.s ODdsk2 ;read ; ODdsk1 move.w D2,SHtoLN(A1) ; move.l (A0)+,DCmd(A1) ;move first four bytes of send data to DiskCmd move.l A0,ODwrAD(A1) ;save address of REST of data clr.w D7 ;force successful IOResult move.w d0, ODvalid(A1) ;mark send buffer as valid... 0.8 bra.s ODdsk9 ;return ODdsk2 cmp.w ODvalid(A1),d0 ;is send buffer valid? (=$FFFF) 0.8 beq.s ODdsk3 ;yes, go on moveq #NoBufr,D7 ;set IOresult to "no buffer" error 0.8 bra.s ODdsk6 ;return ; ODdsk3 clr.w ODvalid(A1) ;mark send buffer as invalid move.w D2,SHfmLN(A1) ; subq.w #1,SHfmLN(A1) ;subtract one for the return code 0.8 addq.l #1,A0 ;inc buffer pointer past return code 0.8 cmpi.w #4,SHtoLN(A1) ;are we doing a longcmd? bhi.s ODdsk4 ;yes bsr ShortCmds ;no bra.s ODdsk5 ; ODdsk4 bsr LongCmds ; ODdsk5 subq.l #1,A0 ;dec buffer pointer past return code 0.8 ODdsk6 ; ; the return code must be loaded explicitly since it comes from ; the header portion of the results packet.... ; move.b D7,(A0) ;stuff return code in read buffer ; ODdsk9 movem.l (sp)+,d0-d2/a0-a2;Restore registers move.b d7,CPdiskRC.w ;Save current disk return code 0.7 ext.w d7 ;Set return condition code rts ;Return page ; 0.7 ; EndRecv -- end receive on disk server socket 0.7 ; 0.7 EndRecv movem.l d0-d1,-(sp) ;save registers 0.7 moveq #EndOp,d0 ;set command to ENDRECV 0.8 move.w #CnstSkt,d1 ;set socket number 0.7 bsr ODcomnd ;do ENDRECV on disk srvr socket 0.7 movem.l (sp)+,d0-d1 ;restore registers 0.7 moveq #0,d7 ;set no error IOresult 0.7 rts ;return 0.7 page ; ; StrobIt -- Strobe command address to Transporter ; ; Enter: A2 = command address ; ; Exit: D7 = Transporter strobe status ; ; EQ = successful ; NE = Transporter not responding ; ; All other registers are preserved ; StrobIt movem.l D0-D1/A0,-(sp) ;save registers 0.8 lea RdyAdr.L,A0 ;get address of ready flag 0.8 clr.l D7 ;assume no Transporter error 0.8 move.l A2,D0 ;get command address rol.l #8,D0 ;move command address to msb ; bsr.s SBstrob ;strobe address HI beq.s SBerr ; bsr.s SBstrob ;strobe address MED beq.s SBerr ; bsr.s SBstrob ;strobe address LO beq.s SBerr ; bsr.s SBwait ;wait for Transporter ready bne.s SBexit ; ; SBerr moveq #NoTrans,d7 ;no transporter ... ; SBexit movem.l (sp)+,D0-D1/A0 ;restore registers 0.8 tst.w d7 ;set return condition code rts ;return ; SBstrob rol.l #8,D0 ;shift address byte to lsb move.b D0,StrAdr-RdyAdr(A0) ;strobe address 0.8 SBwait move.l #TOintvl,D1 ;get timeout interval 0.8 SBW1 btst #0, (A0) ;is transporter ready? bon.s SBWchk ;yes, return 0.8 subq.l #1, D0 ;see if waited long enough 0.8 bne.s SBW1 ;no, look again 0.8 bra.s SBWexit ;timed out 0.8 SBWchk nop ;check for glitch in ready 0.8 btst #0, (A0) ;is transporter ready? 0.8 boff.s SBW1 ;no, then continue to wait 0.8 SBWexit rts ;return page ; ; SetGo -- set up a receive for the 'GO' packet ; SetGo move.w #2,TCdtaLN(A1) ;2 bytes of data clr.b TChdrLN(A1) ;no header pea GData(A1) ;get address of data area move.l (SP)+,TCdADhi-1(A1) ;load data buffer address -- TCsock destroyed bra.s SetGo1 ; ; ; SetRecv -- set up a receive for the disk results and read data ; returns result in D0 ; SetRecv move.l A0,TCdADhi-1(A1) ;load data buffer address -- TCsock destroyed move.w SHfmLN(A1),TCdtaLN(A1) ; move.b #3,TChdrLN(A1) ;disk results have a hdr len of 3 ; SetGo1 move.b #Waiting,RHpktRC(A1) ;set result to FF to see it change ;prepare the command vector pea RHdr(A1) ;load result vector address move.l (SP)+,TCrADhi-1(A1) ; -- TCop destroyed move.b #RecvOp,TCop(A1) ;set up a receive move.b #CnstSkt,TCsock(A1) ; on socket B0 ; lea TCmd(A1),A2 ;get command address bsr StrobIt ;strobe command address to Transporter bne SCerr2 ;Transporter not responding move.l #TOintvl,D0 ;for time out 0.8 SC10 cmpi.b #Waiting,RHpktRC(A1) bne.s SC12 ;wait till result changes subq.l #1, D0 ;see if waited long enough 0.8 bne.s SC10 ;no, look again 0.8 bra SCerr3 ;timeout error SC12 move.b RHpktRC(A1),d0 ;get Transporter return code cmpi.b #CmdAcpt,d0 ;was command accepted? blt SCexit ;no, fatal error clr.w D0 ;indicate success bra SCexit ;return page ; SndRest -- send the rest of the data (from long command) to the disk server ; result of call is in D0, 0 = success ; SndRest move.l ODwrAD(A1),TCdADhi-1(A1);load data buffer address move.b #RestSkt,TCSock(A1) ; - TCsock destroyed subq.w #4,SHtoLN(A1) ; 0.8 bge.s SC20 ; clr.w SHtoLN(A1) ;result was negative, make it zero SC20 move.w SHtoLN(A1),TCdtaLN(A1) ;send length - 4 bytes clr.b TChdrLN(A1) ;no header for rest packets bra.s SC40 ;send it ; SndCmds -- send a disk command to the disk server ; result of call is in D0, 0 = success ; SndCmds pea DCmd(A1) ;data is the Disk command move.l (SP)+,TCdADhi-1(A1) ;load data buffer address move.b #CnstSkt,TCsock(A1) ; - TCsock destroyed moveq #4, D0 ;4 is data and header lengt 0.8 move.w D0,TCdtaLN(A1) ;disk command is 4 bytes long 0.8 cmp.w SHtoLN(A1), D0 ;are we sending less than 4 bytes ble.s SC30 ;no (dest <= src) move.w SHtoLN(A1),TCdtaLN(A1) ;less SC30 move.b D0,TChdrLN(A1) ;send header is 4 bytes 0.8 ror.w #8,d6 ;set destination host number move.b d6,TCdest(A1) rol.w #8,d6 SC40 move.b #Waiting,SHpktRC(A1) ;set result to FF to see it change pea SHdr(A1) ;load result vector address move.l (SP)+,TCrADhi-1(A1) ; -- TCop destroyed move.b #SendOp,TCop(A1) ;sendmsg opcode lea TCmd(A1),A2 ;get command address bsr StrobIt ;strobe command address to Transporter bne.s SCerr2 ;Transporter not responding SC60 move.b SHpktRC(A1), D7 ;get send result code 0.8 cmpi.b #Waiting, D7 ;still waiting? 0.8 beq.s SC60 ;yes, check status again 0.7 cmpi.b #GaveUp, D7 ;did disk srvr accept message? 0.8 beq.s SC40 ;no, try again 0.7 cmpi.b #NoSockt, D7 ;did disk srvr accept message? 0.8 beq.s SC40 ;no, try again 0.8 clr.w D0 ;indicate success 0.7 tst.b D7 ;did it work? 0.8 bge.s SCexit ;yes, return 0.7 SCerr2 move.b D7,D0 ;no transporter ... 0.8 bra.s SCexit ;return SCerr3 moveq #TimeOut,D0 ;time out ... SCexit ext.w D0 ;make return code a word rts ;return page LongCmds ; 1. set up a receive for the GO message ; bsr SetGo ; blt.s LcmdErr ;if D0 < 0 then fatal DRW error ; ; 2. send disk command ; bsr SndCmds ;doit blt.s LcmdErr ;if D0 < 0 then fatal DRW error ; ; 3. wait to receive GO ; Lcmd1 move.b RHpktRC(A1),d0 ;get Transporter return code cmpi.b #CmdAcpt,d0 ;has return code changed? beq.s Lcmd1 ;no, wait some more tst.b D0 ;successful receive? blt.s LcmdErr ;no, set error return ; ; 4. validate GO packet ; Lcmd3 move.b TCdest(A1),D0 ;response come from the right place? 0.7 cmp.b RHsor(A1),D0 ;* 0.7 bne.s Lcmd4 ;no, setup receive again 0.7 btst #7,Gdata(A1) ;disk server restart? 0.7 bon.s LongCmds ;yes, start request over 0.7 cmpi.w #'GO',Gdata(A1) ;"GO" command? 0.7 beq.s Lcmd5 ;yes, go on 0.7 ; Lcmd4 bsr SetGo ;set up for GO receive again blt.s LcmdErr ; bra.s Lcmd1 ; page ; ; 5. set up receive for results ; Lcmd5 bsr SetRecv ; blt.s LcmdErr ;if D0 < 0 then fatal DRW error ; ; 6. send REST ; bsr SndRest ; blt.s LcmdErr ; ; ; 7. wait for results ; Lcmd6 move.b RHpktRC(A1),d0 ;get Transporter return code cmpi.b #CmdAcpt,d0 ;has return code changed? beq.s Lcmd6 ;no, wait some more tst.b D0 ;successful receive? blt.s LcmdErr ;no, set error return ; ; 8. validate results ; Lcmd7 move.b TCdest(A1),D0 ;response come from the right place? 0.7 cmp.b RHsor(A1),D0 ;* 0.7 beq.s Lcmd8 ;yes 0.7 bsr SetRecv ;no, set up receive again.... 0.7 blt.s LcmdErr ;if D0 < 0 then fatal DRW error 0.7 bra.s Lcmd6 ;go back and wait again... 0.7 ; 0.7 Lcmd8 btst #7,RHdskLN(a1) ;disk server restart? 0.7 bon.s LongCmds ;yes, start request over 0.7 ;no, done with request 0.7 ; 0.7 LcmdOK move.b RHdskRC(A1),D0 ;get disk server return code 0.7 ; 0.7 LcmdErr move.w #$1FFF,d7 ;--UP- wait a little 0.8 lc1err1 dbra d7,lc1err1 ;--UP- Why???? a bug 0.8 bsr EndRecv ;end receive on disk server socket 0.7 move.b D0,D7 ;get error return code 0.7 ext.w D7 ;make return code a word 0.7 rts ;return for ShortCmds or LongCmds 0.7 page ShortCmds ; ; 1. set up a receive for the results ; bsr SetRecv ; blt.s LcmdErr ;if D0 < 0 then fatal DRW error ; ; 2. send disk command to disk server ; bsr SndCmds ;doit blt.s LcmdErr ;if D0 < 0 then fatal DRW error ; ; 3. wait to receive results ; Scmd2 move.l CPtimout.w,d7 ;get timeout value 0.7 Scmd2A move.b RHpktRC(A1),d0 ;get Transporter return code 0.7 bge.s Scmd3 ;successful receive, go on cmpi.b #CmdAcpt,d0 ;has return code changed? bne.s LcmdErr ;yes, set error return subq.l #1,d7 ;time out? bne.s Scmd2A ;no, wait some more 0.7 bra.s LcmdErr ;set error return ; ; 4. validate results ; Scmd3 move.b RHsor(A1),D7 ;get source of response cmpi.b #$FF,TCdest(a1) ;is this a broadcast? bne.s Scmd4 ;no, go on move.b d7,RHdskRC(A1) ;save disk server number bra.s LcmdOk ;return ; Scmd4 cmp.b TCdest(A1),D7 ;response come from the right place? bne.s Scmd5 ;no 0.7 btst #7,RHdskLN(a1) ;disk server restart? 0.7 bon.s ShortCmds ;yes, start request over 0.7 bra.s LcmdOK ;no, done with request 0.7 ; 0.7 Scmd5 bsr SetRecv ;set up receive again.... 0.7 blt.s LcmdErr ;if D0 < 0 then fatal DRW error 0.7 bra.s Scmd2 ;go back and wait again... 0.7 list 0 page ;p.prom.fd ;{!CC}; 0.8 ; ; File: CC.PROM.FD.TEXT ; Date: 13-May-83 ; By: Ravi Luthra ; Keith Ball ; ; ; Fboot -- Floppy disk boot processing ; Fboot move.b d0,CPbtslot.w ;set boot slot number move.b d0,CPosslot.w ;set OS slot number clr.b CPbtsrvr.w ;set boot server number 0.7 pea FDblkIO ;set boot disk blk i/o subr pointer move.l (sp)+,CPblkio.w ;* pea FDsecIO ;set boot disk sector i/o subr pointer move.l (sp)+,CPdskio.w ;* moveq #0,d0 ; 0.7 move.b d0,CPossrvr.w ;set OS server number 0.7 move.w d0,CPosblk+1.w ;set OS volume block number 0.7 move.b d0,CPosdrv.w ;set OS volume drive number 0.7 bsr FDI8sssd ;set up floppy constants bsr FDinit ;initialize floppy drive blt.s Fboot90 ;just return if error ; Fboot1 move.l #USRbase,a0 ;get block buffer pointer moveq #0,d0 ; move.w d0,d1 ; moveq #DskRead,d5 ;get read block function code ; bsr.s FDblkIO ;read block 1 of boot code blt.s Fboot90 ;just return if error bsr.s FDblkIO ;read block 2 of boot code blt.s Fboot90 ;just return if error move.l #USRbase,a0 ;get block buffer pointer ; Fboot90 rts ;return page ;FDblkIO ; ; PHILOSOPHY: The user views floppy as a set of 512 byte blocks. ; The driver then translates this block to track address, sector ; address, side. ; It then makes the necessary number of request to read sectors. ; Partial sectors are not read or written, the excess is ignored. ; Sector length of an Apple floppy is 256 bytes. ; ; RESTRICTION: Bytes per sector must be exact divisor of 512 (block size). ; The block address must be less than (2**15)/bytes per sector, ; so that when sector is formed, it fits in the D3.W. ; ; RESULTS OF SOME COMMANDS: ; ; 1) TRACK REG is incremented by 1 during STEPIN even ; though there is a seek error because the TRACK adrs ; requested exceeds the maximum track addres allowed ; ; 2) STEPOUT: the track register is not decremented below 0 ; after TRK00. The seek error bit is set. ; ; ; FDblkIO - Read/Write a Corvus floppy disk block subroutine ; ; Enter: A0.L - Buffer address ; D0.W - Block number ; D1.W - Drive number ; D5.W - Read ($32) or Write ($33) command ; ; Exit: A0.L - Next free location in buffer ; D0.W - Updated block number ; D7.W - IORESULT ; ; All other registers are preserved. ; FDblkIO MOVEM.L D0-D6/A1-A6,-(SP) ; MOVE.W #BLKSZ,D2 ;BLOCK SIZE IN BYTES MOVE.W D0,D3 ; BSR FDrdwr ; MOVEM.L (SP)+,D0-D6/A1-A6 ;restore registers ADDQ.W #1,D0 ;INC BASE BLOCK TST.B D7 ;set return condition code RTS ;return page ;FDsctIO ; ; FDsctIO - Read/Write a Corvus floppy disk sector ; ; Enter: A0.L - Buffer address ; D1.W - Bytes per sector (128 for single density) ; D3.W - Track number ; D4.W - Sector number ; D5.W - Read ($32) or Write ($33) command ; ; Exit: D7.W - IORESULT ; ; All other registers are preserved. ; ;DsecIO MOVEM.L D0-D6/A0-A6,-(SP) ;save registers ; BSR FDgetadr ;set address registers ; ;A1 = ptr to device description info ; ;A2 = ptr to slot controller registers ; ;A3 = ptr to slot static RAM ; CLR.L D0 ; ; BSR FDlcmd1 ;turn on motor and setup controller ; BSR FDseek ;get to track ; BNE.S FDsio9 ;if error, return ; CMPI.W #DskWrit,D5 ;only do write if cmd is a write ; BNE.S FDsio2 ;else do a read ; BSR FDsecW ; ; BRA.S FDsio9 ; ; ; FDsecIO CMPI.W #DskWrit,D5 ;make sure cmd is a read cmd BNE.S FDsio1 ;it is BRA FDEopcd ;it isn't, return error ; FDsio1 MOVEM.L D0-D6/A0-A6,-(SP) ;save registers BSR FDgetadr ;set address registers ;A1 = ptr to device description info ;A2 = ptr to slot controller registers ;A3 = ptr to slot static RAM CLR.L D0 ; BSR FDlcmd1 ;turn on motor and setup controller BSR FDseek ;get to track BNE.S FDsio9 ;if error, return FDsio2 BSR FDsecR ;read sector specified by D4.W ; FDsio9 BSR FDmtrof ;turn off motor MOVEM.L (SP)+,D0-D6/A0-A6 ;restore registers TST.B D7 ;set return condition code RTS ;return page ;floppy equates SVLCMD equ 0 ;SAVE OF LOCAL COMMAND ; NNMI1 equ 0 ;BIT POSITION FOR EACH STATUS BIT NNMI2 equ 1 ; NNMI3 equ 2 ; NNMI4 equ 3 ; ; NIRQ1 equ 4 ; NIRQ2 equ 5 ; NIRQ3 equ 6 ; NIRQ4 equ 7 ; ; ; Bytes per sector ; BPS8ISD equ 128 ;Single density 8" BPS8IDD equ 256 ;Double density 8" BPS5ISD equ 256 ;Apple 5 1/4" floppy ; ; Sectors per track ; SCPT8SD equ 26 ;Single density 8" SCPT8DD equ 26 ;Double density 8" SCPT5SD equ 16 ;Apple 5 1/4" floppy ; ; Tracks per side ; TKPS8SD equ 77 ;Single density 8" TKPS8DD equ 77 ;Double density 8" TKPS5SD equ 35 ;Apple 5 1/4" floppy ; ; Number of blocks per disk ; NBLK8SD equ 500 ;Single density 8" single sided NBLK8DD equ 1001 ;Double density 8" single sided NBLK5SD equ 280 ;Apple 5 1/4" floppy ; ; Error return codes ; RGOOD equ 0 ;disk accss successful RBDBLK equ -1 ;Block requested is out of range RBDUNT equ -2 ;bad unit number or driver not implemented RBDOPCO equ -3 ;Requested unit I/O function is not valid RHWRERR equ -4 ;Hardware error RLOSTDEV equ -5 ;Lost device. i.e. device went offline ; RWRPROT equ -16 ;the unit is write protected RSEEKERR equ -17 ;SEEK Error RBUSY equ -18 ;device busy RRNF equ -19 ;record not found - maybe disk is bad RNOTRDY equ -20 ;device not ready RERRUNOWN equ -64 ;error origin unknown page ;floppy hardware equates ; ; This section conatins the equates for Floppy Disk cont FD1793 ; All references are w.r.t NDEV1AD in A2 ; Prefix of 'L' means that this reference is to the 'LOCAL' ; logic on the disk controller board ; Prefix of FDC means that this referenc is to the Floppy disk controller ; ; Local disk controller board equates ; LSTRR equ 0 ;index to the local Status reg LCMDR equ 0 ;index to the local command reg ; LSDRQ equ 0 ;BIT 0 =1 DRQ LSINT equ 1 ;INTERRUPT REQUEST LS1SD2SD equ 4 ;=0 if 2 sided , =1 if one sided LS8INMIN equ 5 ;=1 if 8 inch , =0 if min LSDSKCHG equ 6 ;=0 if disk changd, 1 if not LSFMMFM equ 7 ;=1 if sigl density =0 if double ; ; Command register equates ; LCFLPSD1 equ 0 ;=0 if side 0 , =1 if side 1 LCDE0 equ 1 ;drive selct bit 0 LCDE1 equ 4 ;drive select bit 1 LCMOTOROF equ 5 ;=1 if motor to be turned off LC8INMIN equ 6 ; LCFLP8IN equ 6 ;=1 to select 8 in, =0 for 5 1/4 LCFMMFM equ 7 ;=1 to select singl density , 0 for dbl page ; ; ; Floppy disk controllers equates ; FDCAD equ $10 ;Floppy disk controller base index ; ; address of the internal registers of FDC ; FDCCMDR equ FDCAD+0 ;ADRS OF FDC COMMAMD REG FDCSTRR equ FDCAD+0 ;ADRS OF FDC STATUS REG FDCTRKR equ FDCAD+2 ;ADRS OF FDC TRACK REG FDCSECR equ FDCAD+4 ;ADRS OF FDC SECTOR REG FDCDATR equ FDCAD+6 ;ADRS OF FDC DATA REG ; ; Command code equates ; CRESTORE equ 0 ;0 0 0 0 H V R1 R0 CSEEK equ $10 ;0 0 0 1 h v r1 r0 CSTEP equ $20 ;0 0 1 U h v r1 r0 CSTEPIN equ $40 ;0 1 0 U h v r1 r0 CSTEPOUT equ $60 ;0 1 1 U h v r1 r0 ; ; Type II commands ; CRDSEC equ $80 ;1 0 0 m F2 E F1 0 CWRSEC equ $A0 ;1 0 1 m F2 E F1 0 ; ;TYpe III commands ; CRDAM equ $C0 ;1 1 0 0 0 E 0 0 CRDTRK equ $E0 ;1 1 1 0 0 E 0 0 CWRTRK equ $F0 ;1 1 1 1 0 E 0 0 CFRCINT equ $D0 ;1 1 0 1 I1 12 I3 I4 ; ; FLAGS equates -- all flags have prefix of F ; FHld equ $8 ;if =1 load head in the beginning ;if =0 unload head in beginning FVerify equ $4 ;if =1 verify destination trk else not FUpdttrk equ $10 ;if =1 update TRK reg after each STEP FSTPRT3ms equ $0 ;step rate = 3 milliseconds FSTPRT6ms equ $1 ;step rate = 6 milliseconds FSTPRT10ms equ $2 ;step rate = 10 milliseconds FSTPRT15ms equ $3 ;step rate = 15 milliseconds ; FMPS equ $10 ;M=1 if multiple sectors else =0 FDLY equ $4 ;E=1 if internal dly of 15 ms =0 no dly FSDCPM equ $8 ;F2=0 compare with side 0,=1 with side 1 FSDCMPEN equ $2 ;F1=1 enable side compare, =0 disable cmp ; FINTRDY equ $1 ;not ready to ready FINTNRDY equ $2 ;ready to not ready FINTIDXP equ $4 ;interrupt on index pulse FINTIMM equ $8 ;terminate command immediately and intrpt page ;status register equates ; ; Status register equates -- all status reg bits have prefix of S ; ;name bit position ; SBUSY equ 0 ;S0 busy ; SINDEX equ 1 ;S1 index pulse encountered SDRQ equ 1 ;S1 data request ; STRK0 equ 2 ;S2 track 00 SDTOVER equ 2 ;S2 data over run SDTUNDR equ 2 ;S2 data under run ; SCRCERR equ 3 ;S3 crc error ; SSEEKERR equ 4 ;S4 seek error SRNF equ 4 ;S4 record not found ; SHDLDD equ 5 ;S5 head loaded SRECTYP equ 5 ;S5 record type SWRFAULT equ 5 ;S5 write fault ; SWRPROT equ 6 ;S6 floppy write protected ; SNOTRDY equ 7 ;S7 floppy not ready page ;FDI....., FDinit ; ; FDI8sssd -- Set up constants for Corvus 8" single side single density ; FDI8sssd bsr FDgetadr ;set address registers ;A1 = ptr to device description info ;A2 = ptr to slot controller registers ;A3 = ptr to slot static RAM move.w #NBLK8SD,CPfdvsz(A1) ;set device size in blocks move.w #BPS8ISD,CPfbps(A1) ;set bytes per sector move.b #SCPT8SD,CPfspt(A1) ;set sectors per track move.b #TKPS8SD,CPftps(A1) ;set tracks per side bra.s FDI8ss ;set other values and return ; ; FDI8ssdd -- Set up constants for Corvus 8" single side double density ; FDI8ssdd bsr FDgetadr ;set address registers ;A1 = ptr to device description info ;A2 = ptr to slot controller registers ;A3 = ptr to slot static RAM move.w #NBLK8DD,CPfdvsz(A1) ;set device size in blocks move.w #BPS8IDD,CPfbps(A1) ;set bytes per sector move.b #SCPT8DD,CPfspt(A1) ;set sectors per track move.b #TKPS8DD,CPftps(A1) ;set tracks per side FDI8ss move.b #1,CPfspd(A1) ;set sides per disk move.b #1,CPfofst(A1) ;set first track offset rts ;return ; ; FDinit -- Initialize Corvus floppy disk drive ; FDinit BSR FDgetadr ;set address registers ;A1 = ptr to device description info ;A2 = ptr to slot controller registers ;A3 = ptr to slot static RAM CLR.L D0 ; MOVEQ #1,D1 ;A FAKE SECTOR LENGTH BSR.S FDlcmd1 ;turn on motor and setup controller BSR FDrst ;restore to track 0 BSR.S FDmtrof ;turn motor off TST.B D7 ;set return condition code RTS ;return page ;FDmtrof, FDlcmd ; ; D0.W -- FREE ; D1.W -- FREE ; D2.W -- BYTE CNT ; D3.W -- BASE BLK ADRS ; D4.W -- FREE ; D5.W -- USER CMD ; D6.W -- FREE ; ; A0.L -- USER BUFFER ADDRESS ; A1.L -- DEVICE DESCRIPTION AREA BASE ADDRESS ; A2.L -- FLOPPY CONTROLLER BASE ADDRESS ; A3.L -- STATIC RAM BASE ADDRESS ; ; ; FDmtrof -- Turn motor off ; FDmtrof move.b SVLCMD(A3),D4 ;get current local command bset #LCMOTOROF,D4 ;set motor off flag move.b D4,LCMDR(A2) ;move command to command register move.b D4,SVLCMD(A3) ;save current local command rts ;return ; ; FDlcmd -- GET THE LOCAL COMMAND FOR THIS DRIVE INTO REGISTER D0.B ; RETURNS WITH D7 CLEAR LONG ; FDlcmd bsr FDclcTS ;Calc first side trk sec ; ; form a local command in D0 ; Entry used for Read/Write a sector ; FDlcmd1 bclr #LCMOTOROF,D0 ;clear motor off bit bset #LCFLP8IN,d0 ;indicate 8 inch flp bset #LCFMMFM,d0 ;indicate 8 inch flp move.b CPosdrv(a1),d7 ;sel drive ror.w #1,d7 ;note DE0 is B0 lsl.b #2,d7 ;DE1 is B4 rol.w #2,d7 ; or.b d7,d0 ;set into d0 move.b d0,SVLCMD(a3) ;save then command move.b d0,LCMDR(a2) ;set local command register clr.l d7 ;clear error register rts ;return page ;FDrdwr FDrdwr BSR FDgetadr ;set address registers ;A1 = pointer to device description info ;A2 = pointer to slot controller registers ;A3 = pointer to slot static RAM TST.W D3 ;test base block BMI FDEblck ;jump if first blk rqstd is invalid cmp.w CPfdvsz(A1),d3 ;is it in limit bge FDEblck ;jump final block exceeds max BSR.S FDlcmd ;set local command register ;---------------------------------------------------------------- ; D0.W -- LOCAL COMMAND ; D1.W -- BYTES PER SEC ; D2.W -- WORD CNT ; D3.W -- TRACK ADDRESS ; D4.W -- SECTOR ADDRESS ; D5.W -- USER COMMAND ; D6.W -- FREE ;---------------------------------------------------------------- ; READS/WRITES ONLY COMPLETE SECTORS ; For the rest of the code: ; A0 points to the user buffer address ; A1 points to the beginning of the device ; table entry for this volume in D0 at the entry ; A2 Contains the NDEVICE address of the slot ; specified in the device table for this Volume ; A3 BASE ADDRESS OF LOCAL STATIC RAM ;---------------------------------------------------------------- bsr FDseek ;seek the desired track bne.s FDrdwr9 ;if error, return ; FDrdwr1 sub.w d1,d2 ; bmi.s FDrdwr9 ;return if no more sectors to process bsr.s FDsecRW ;process sector tst.b d7 ;d7 contains result code bne.s FDrdwr9 ;if error, return bsr FDincTS ; BNE.S FDrdwr9 ;TIMED OUT ERROR bra.s FDrdwr1 ;process next sector ; FDrdwr9 bsr FDmtrof ;turn off motor rts ;return page ;FDsecRW, FDsecR ; ; FDsecRW -- Read or write a sector of data to the floppy ; It transfer the data to/from the adrs in A0 ; from / to the floppy ; ; Enter: D5 - DskRead or DskWrit ; FDsecRW ;fall thru to FDsecR ; cmp.w #DskWrit,D5 ;see if it is a Unit write ; beq.s FDscRW1 ; bsr.s FDsecR ; bra.s FDscRW9 ;FDscRW1 bsr.s FDsecW ;FDscRW9 rts ; ; FDsecR -- Read one sector of data ; ; Enter: bytes per sec ---> D1.w ; sector adrs -----> D4.w ; buffer adrs -----> A0 ; floppy must be poitioned on desired track ; ; Exit: OS result code ---> D7 ; data to the adrs pointed by A0 ; FDrcRd equ 4 ;read sector retry count FDrcDOr equ 4 ;data overrun retry count ; FDsecR movem.l d5-d6,-(SP) ;save move.w #FDrcRd,d5 ;get read sector retry count move.l a0,a4 ;save user buf ptr ; FDsecR1 move.w #FDrcDOr,d6 ;get data overrun retry count ; FDsecR2 move.l a4,a0 ;get user buf adrs BSR FDwRdy ;WAIT FOR READY OR TIMED OUT BNE.S FDsecR9 ;TIMED OUT ERR BSR FDccRd ; btst #SDTOVER,d7 ;is ther data overrun dbeq d6,FDsecR2 ;data over run, try again. btst #SCRCERR,d7 ;is ther crc error DBEQ d5,FDsecR1 ; DO UNTIL (no crc error) ; or (no more retries left) ; FDsecR3 BSR FDrdSta ;check read status beq.S FDsecR9 ; move.l a4,a0 ; ; FDsecR9 movem.l (sp)+,d5-d6 ; tst.b d7 ;d7 contains result code rts ;return page ;FDsecW ; ; FDsecW -- Write one sector of data ; ; Enter: bytes per sec ---> D1.w ; sector adrs -----> D4.w ; buffer adrs -----> A0 ; floppy must be poitioned on desired track ; ; Exit: OS result code ---> D7 ; data to the adrs pointed by A0 ; ;FDrcWr equ 4 ;write sector retry count ;FDrcDOw equ 4 ;data overrun retry count ; ; ;FDsecW movem.l d5-d6,-(SP) ;save registers ; move.w #FDrcWr,d5 ;get write retry count ; move.l a0,a4 ;save user buf ptr ; ; ;FDsecW1 move.w #FDrcDOw,d6 ;get data overrun retry count ; ; ;FDsecW2 move.l a4,a0 ;get user buf adrs ; BSR FDwRdy ;WAIT FOR READY OR TIMED OUT ; BNE.S FDsecW9 ;TIMED OUT ERR ; BSR FDccWr ; ; btst #SDTOVER,d7 ;data overrun? ; dbeq d6,FDsecW2 ;yes, try again ; btst #SCRCERR,d7 ;CRC error? ; dbeq d5,FDsecW1 ;yes, try again ; ; ; BSR FDwrSta ;check write status ; beq.S FDsecW9 ;if no error, return ; move.l a4,a0 ; ; ; ;FDsecW9 movem.l (sp)+,d5-d6 ;restore registers ; tst.b d7 ;d7 contains result code ; rts ;return page ;FDccRd ; ***** TYPE II COMMANDS ***** ; ; FDccRd -- Read one sector of data ; ; Enter: bytes per sec ---> D1.w ; sector adrs -----> D4.w ; buffer adrs -----> A0 ; floppy must be positioned on desired track ; ; Exit: status -----> D7 ; data to the adrs pointed by A0 ; FDccRd move.w d1,-(SP) ;save subq.w #1,d1 ;byte count move.w sr,-(SP) ; ori.w #$0700,sr ;disable interrupts move.b d4,FDCSECR(A2) ; move.b #CRDSEC,FDCCMDR(A2) ;issue command move.w #25,d7 ;wait at least 28 micro-second FDccRd1 dbf d7,FDccRd1 ; ; FDccRd2 btst #SBUSY,FDCSTRR(A2) ;see if the ctlr is busy beq.S FDccRd2 ;jump if not busy ; ; ***** TIME CRITICAL LOOP ; FDccRd3 move.b LSTRR(A2),D7 ;read status btst #LSDRQ,d7 ;is DRQ there bne.s FDccRd5 ;yes , jump ; FDccRd4 btst #LSINT,D7 ;is FDC done beq.s FDccRd3 ;no, jump bra.s FDccRd6 ;ctlr terminated too soon ; FDccRd5 move.b FDCDATR(A2),(a0)+ ;get a byte from FDC dbf d1,FDccRd3 ;read the remaining bytes ; ; a complete sector has been read. ; bsr FDnRdy ; ; FDccRd6 move.b FDCSTRR(A2),d7 ;read the status move.w (sp)+,sr ;restore SR move.w (SP)+,d1 rts page ;FDccWr ; ; FDccWr -- Write one sector of data ; ; Enter: bytes per sec ---> D1.w ; sector adrs -----> D4.w ; buffer adrs -----> A0 ; floppy must be poitioned on desired track ; ; Exit: status -----> D7 ; data to the adrs pointed by A0 ; ;FDccWr move.w d1,-(SP) ;save ; subq.w #1,d1 ;byte count ; move.w sr,-(SP) ; ; ori.w #$0700,sr ;disable interrupts ; BSR.S FDccWr1 ;CALL time critical FDccWr PART ; bsr FDnRdy ; ; move.b FDCSTRR(A2),d7 ;read the status ; move.w (sp)+,sr ;restore SR ; move.w (SP)+,d1 ; ; rts ;return ; ; ; ; ;FDccWr1 move.b d4,FDCSECR(A2) ; ; move.b #CWRSEC,FDCCMDR(A2) ;issue command ; ; ; move.w #25,d7 ;wait at least 28 micro-second ;FDccWr2 dbf d7,FDccWr2 ; ; ; ;FDccWr3 btst #SBUSY,FDCSTRR(A2) ; ; beq.s FDccWr3 ; ; ; ; ; ***** TIME CRITICAL LOOP ; ; ;FDccWr4 move.b LSTRR(A2),D7 ;FDCSTRR(A2),d7 ;read status ; btst #LSDRQ,d7 ;is DRQ there ; bne.s FDccWr6 ;yes , jump ; ; ;FDccWr5 btst #LSINT,D7 ;is FDC done ; beq.s FDccWr4 ;no , jump ; rts ;terminated too soon ; ; ;FDccWr6 move.b (a0)+,FDCDATR(A2) ;move a byte to FDC ; dbf d1,FDccWr4 ;write the reamining bytes ; RTS ;return page ;FDgetadr ; ; FDgetadr -- Get pointers to device description info, controller registers, ; and static RAM for current slot ; ; Exit: A1 = pointer to device description info ; A2 = pointer to controller registers for slot ; A3 = pointer to static RAM for slot (CPosslot) ; FDgetadr movea.l #0,A1 ;get pointer to device description info move.l #NDEV1AD,A2 ;get pointer to controller registers move.b CPosslot(a1),d7 ;* ext.w d7 ;* mulu.w #DEVADOFST,d7 ;* adda.l d7,a2 ;* lea CPsl1ram.w,A3 ;get pointer to static RAM move.b CPosslot(a1),d7 ;* ext.w d7 ;* subq.w #1,d7 ;* mulu #$100,d7 ;* adda.l d7,A3 ;* rts ;return page ;FDclcTS ; ; FDclcTS -- calculate the Side, Track address and sector ; address for the First block requested by the user ; ; Enter: A1 - device table address ; D3 - block address ; ; Exit: D0.bit - side flag ; D3.w - track address ; D4.w - sector address ; FDclcTS clr.l d0 ; move.w CPfbps(A1),D1 ;get bytes per sector ext.l d3 ;clear the upper 16 bits of d3 move.l #BLKSZ,d7 ; divu d1,d7 ; mulu d7,d3 ;absolute sector adrs to d3 move.l d3,d7 ; clr.w d4 ;make sure that upper byte is 00 move.b CPfspt(A1),d4 ; divu d4,d7 ; move.w d7,d3 ;absolute track adrs to d3 swap d7 ; move.b CPfofst(a1),d4 ;get first sector offset ext.w d4 ;* add.w d7,d4 ;get sector address ; ---- bclr #LCFLPSD1,d0 ;select side 0 (already 0) move.b CPftps(A1),d7 ;get tracks per side ext.w d7 ;* cmp.w d7,d3 ;is track on side 0? blt.s FDclcT9 ;yes, return cmpi.b #1,CPfspd(a1) ;is there a side 1? beq.s FDclcT8 ;no, report error bset #LCFLPSD1,D0 ;select side 1 sub.w d7,d3 ;update track address cmp.w d7,d3 ;is track on side 1? blt.s FDclcT9 ;yes, return ; FDclcT8 bra FDEblck ;indicate block number error ; FDclcT9 clr.w d7 ;indicate no error rts ;return page ;FDincTS ; ; FDincTS -- update the sector address by one. If it was the last ; sector on the track then update the Track adrs by ; one. If it was the last track then update the side ; in the Local command reg and D0 and restore track to 0. ; ; Exit: NE - error and D7 has error code ; EQ - successful update D7 = 0 ; FDincTS addq.w #1,d4 ;increment sector number move.b CPfspt(A1),d7 ;get last sector number + 1 add.b CPfofst(A1),d7 ;* cmp.b d7,d4 ;are we past last sector? bge.s FDincT1 ;yes, go to next track clr.w d7 ;show successful bra.s FDincT9 ;return ; FDincT1 move.b CPfofst(A1),d4 ;reset sector number ext.w D4 ;* move.b CPftps(A1),d7 ;get tracks per side ; ---- cmpi.b #DTa5,CPftyp(a1);is this an Apple floppy drive? 0.7 ; ---- beq.s FDincT5 ;yes, process it 0.7 ; ; Corvus 8" floppy drive ; cmp.b d7,d3 ;are we past last track on side? bge.s FDincT2 ;yes, go to next side addq.w #1,d3 ;increment track number bsr.s FDwRdy ;wait for ready or timeout bne.s FDincT9 ;return if timeout error bsr FDccSin ;step in 1 track bsr FDskSta ;check seek status bra.s FDincT9 ;return ; FDincT2 clr.w d3 ;reset track number bset #LCFLPSD1,D0 ;Select side 1 move.b D0,LCMDR(A2) ;* bsr FDrst ;restore to track 0 ; ---- bra.s FDincT9 ;return 0.7 ; ---- ; 0.7 ; ---- ; Apple 5" floppy drive 0.7 ; ---- ; 0.7 ;DincT5 cmp.b d7,d3 ;are we past last track on side? 0.7 ; ---- bge FDEblck ;yes, report error 0.7 ; ---- addq.w #1,d3 ;increment track number 0.7 ; ---- bsr ADccSin ;step in 1 track 0.7 ; FDincT9 tst.w d7 ;set return condition codes rts ;return page ;FDwRdy ; ; FDwRdy -- WAIT UNTIL FDC SAYS DRIVE IS READY OR ; TIME OUT (NOT MORE THAN 1 SECOND) ; ; Exit: NE = timed out D7 has error result ; EQ = ready (D7 = 0) ; FDtmoHi equ 4 ;SHOULD BE AT LEAST 1 SECOND FDtmoLo equ $7FFF ;* ; FDwRdy CLR.L D7 ; MOVEM.W D5-D6,-(SP) ;SAVE D6 AND D5 MOVE.W #FDtmoLo,D5 ; MOVE.W #FDtmoHi,D6 ; ; FDwRdy1 BTST #SNOTRDY,FDCSTRR(A2) ;IS FLOPPY READY DBEQ D5,FDwRdy1 ;DO UNTIL (FLOPPY READY) OR (TIME OUT) DBEQ D6,FDwRdy1 ; BEQ.S FDwRdy9 ;DIDN'T TIME OUT MOVE.W #RNOTRDY,D7 ; ; FDwRdy9 MOVEM.W (SP)+,D5-D6 ; TST.W D7 ;SET CONDITION CODES - NE MEANS ERROR RTS ;return page ;FDseek ; ; FDseek -- ; ; It is assumed that TRACK REG contains the number of the track ; of the current position of the read write Head. ; ; Enter: D3.W - Seek track address ; FDrcSk equ 4 ;seek retry count ; FDseek BSR.S FDwRdy ;WAIT FOR READY OR TIMED OUT BNE.S FDseek9 ;TIMED OUT ERR BSR FDccSk ; BSR FDskSta ;check seek status BEQ.S FDseek9 ;there is NO error move.w d5,-(sp) ;save d5 move.w #FDrcSk,D5 ; ; FDseek1 BSR.S FDwRdy ;WAIT FOR READY OR TIMED OUT BNE.S FDseek8 ;TIMED OUT ERR BSR.S FDccRst ; BSR.S FDwRdy ;WAIT FOR READY OR TIMED OUT BNE.S FDseek8 ;TIMED OUT ERR BSR.S FDccSk ; btst #sseekerr,d7 ; DBEQ d5,FDseek1 ;try until no seek error or ;no more retries BSR FDskSta ;check seek status ; FDseek8 move.w (sp)+,d5 ; ; FDseek9 TST.B D7 ;set return condition code RTS ;return page ;FDrstW, FDrst ; ; FDrstW -- Restore the floppy to track 0 ; It exits when it has successfully restored the floppy to ; track 0 or when the retry count has exhausted. ; Then it calls the FDswSta routine to analyse status. ; Note W in FDswSta. It looks at WRprot bit of FDCSTRR. ; FDrstW movem.l a6/d6,-(sp) ; lea FDswSta,a6 ; bra.s FDrst0 ; ; ; FDrst -- same as FDrstW except no W there. ; It does not look at Write protect status bit in FDCSTRR. ; FDrst movem.l a6/d6,-(sp) ; lea FDskSta,a6 ; ; FDrst0 move.w #4,d6 ; ; FDrst1 BSR.S FDwRdy ;WAIT FOR READY OR TIMED OUT BNE.S FDrst2 ;TIMED OUT ERR bsr.s FDccRst ; jsr (a6) ; dbeq d6,FDrst1 ;do until (successful) or (tried enough) ; FDrst2 movem.l (sp)+,a6/d6 ; rts ;return page ;FDcc... ; ; ***** TYPE I COMMANDS ***** ; FDCrst equ CRESTORE+FSTPRT15ms+FVERIFY FDCstp equ CSTEP+FSTPRT6ms+FVERIFY+FUpdttrk FDCstpIn equ CSTEPIN+FSTPRT6ms+FVERIFY+FUpdttrk FDCstpOt equ CSTEPOUT+FSTPRT6ms+FVERIFY+FUpdttrk FDCseek equ CSEEK+FSTPRT6ms+FVERIFY ; ; FDccRst -- bring the floppy back to track 00 ; Then set the FDCTRKR = 0 ; Stepping pulses are given at the rate specified in cmd ; FDccRst move.b #FDCrst,FDCCMDR(A2) ;issue command bra.s FDnRdy ;wait for not ready ; ; FDccStp -- FDCTRKR+/-1 --> FDCTRKR ; FDccStp move.b #FDCstp,FDCCMDR(A2) ;issue command bra.s FDnRdy ;wait for not ready ; ; FDccSin -- FDCTRKR+1 --> FDCTRKR ; FDccSin move.b #FDCstpIn,FDCCMDR(A2) ;issue command bra.s FDnRdy ;wait for not ready ; ; FDccSot -- FDCTRKR-1 --> FDCTRKR ; FDccSot move.b #FDCstpOt,FDCCMDR(A2) ;issue command bra.s FDnRdy ;wait for not ready ; ; FDccSk -- issue a seek command. If there is a seek error, ; flip the density flag in D0 and try again ; FDccSk move.w d5,-(sp) ;save d5 move.b D3,FDCDATR(A2) ;load the desired TRACK adrs moveq #2,d5 ; ; FDccSk1 move.b #FDCseek,FDCCMDR(A2) ;issue command bsr.s FDnRdy ;wait for not ready ; ---- btst #sseekerr,d7 ; ; ---- beq FDccSk2 ;no seek error ; ---- bchg #LSFMMFM,d7 ;flip the density bit ; ---- dbf d5,FDccSk1 ; $$$ WE MAY HAVE TO FLIP $$$ ; FDccSk2 move.w (sp)+,d5 ;get back d5 rts ;return page ;FDnRdy ; ; FDnRdy -- WAIT UNTIL FDC SAYS DRIVE IS NOT BUSY OR TIME OUT ; ; Exit: D7 = controller status register (FDCSTRR) ; FDnRdy movem.w d5-D6,-(SP) ; move.w #FDtmoLo,d6 ; move.w #2,d5 ; add 3*$8000 iterations ; FDnRdy1 btst #LSINT,LSTRR(a2) ;is it busy dbNE d6,FDnRdy1 ;DO UNTIL (not busy) or (no more retries) dbNE d5,FDnRdy1 ;DO UNTIL (not busy) or (no more retries) ; FDnRdy2 movem.w (SP)+,d5-d6 ; MOVE.B FDCSTRR(A2),D7 ;GET CONTROLLER STATUS RTS ;return page ;check status ; ; Check status subroutines ; ; Exit: D7 - IORESULT code ; FDrdSta move.b FDCSTRR(A2),d7 ;read the status ; bra.s FDrwSta ; ; ; ;FDwrSta move.b FDCSTRR(A2),d7 ;read the status ; btst #SWRPROT,d7 ; ; bon.s FDEprot ; ; btst #SWRFAULT,d7 ; ; bon.s FDEherr ; ; FDrwSta btst #SCRCERR,d7 ; bon.s FDEcrc ; btst #SRNF,d7 ; bon.s FDErnf ; ; FDrwSt1 btst #SBUSY,d7 ; bon.s FDEbusy ; btst #SNOTRDY,d7 ; bon.s FDEnrdy ; bra.s FDokSta ;no error, return ; FDswSta move.b FDCSTRR(a2),d7 ; btst #SWRPROT,d7 ; bon.s FDEprot ; bra.s FDskSt1 ; ; FDskSta move.b FDCSTRR(a2),d7 ; ; FDskSt1 btst #SSEEKERR,d7 ;seek error? bon.s FDEseek ;SEEK ERROR IN RSLT CODE btst #SCRCERR,d7 ; bon.s FDEcrc ; btst #sbusy,d7 ; bon.s FDEbusy ;HARDWARE ERROR btst #SNOTRDY,d7 ; bon.s FDEnrdy ; ; FDokSta clr.w d7 ;indicate no error ; FDerSta tst.w d7 ;set return condition code rts ;return page ;set error status FDEcrc ;error -- CRC FDEblck move.w #RBDBLK,d7 ;error -- invalid block number bra.s FDerSta ;set condition code and return ; FDEunit move.w #RBDUNT,d7 ;error -- invalid unit number bra.s FDerSta ;set condition code and return ; FDEopcd move.w #RBDOPCO,d7 ;error -- invalid op code bra.s FDerSta ;set condition code and return ; FDEherr move.w #RHWRERR,d7 ;error -- hardware bra.s FDerSta ;set condition code and return ; FDEprot move.w #RWRPROT,d7 ;error -- write protect bra.s FDerSta ;set condition code and return ; FDEseek move.w #RSEEKERR,d7 ;error -- seek bra.s FDerSta ;set condition code and return ; FDErnf move.w #RRNF,d7 ;error -- record (sector) not found bra.s FDerSta ;set condition code and return ; FDEbusy move.b #CFRCINT+FINTIMM,FDCCMDR(A2) move.w #RBUSY,D7 ;error -- busy bra.s FDerSta ;set condition code and return ; FDEnrdy move.w #RNOTRDY,d7 ;error -- not ready bra.s FDerSta ;set condition code and return ; ---- page ;p.prom.ad ; 0.7 ; ---- include 'P.PROM.AD' ;Apple floppy driver 0.7 page ;p.prom.fb ; 0.7 ; ; file: cc.prom.fe.text ; date: 13-June-1983 ; Floppy driver equates for the new controller. ; BIT NUMBER DEFINITIONS ; BITD0 EQU 0 ;BIT 0 BITD1 EQU 1 ;BIT 1 BITD2 EQU 2 ;BIT 2 BITD3 EQU 3 ;BIT 3 BITD4 EQU 4 ;BIT 4 BITD5 EQU 5 ;BIT 5 BITD6 EQU 6 ;BIT 6 BITD7 EQU 7 ;BIT 7 ; Default device table values - for init procedure ; D8TYPE EQU $FF ;Bits D0 and D1, single density & 1 side D8TRKSID EQU 77 ;8" standard = 77 tracks per side D8SECTRK EQU $1A ;8" standard = 26 sectors per track D8SctrLn EQU 128 ;default sector length for FM ??127?? D5TYPE EQU $FC ;Bits D0 and D1, double density & 2 sides D5TRKSID EQU 80 ;80 tracks per side D5SECTRK EQU 9 ;9 sectors per track D5SctrLn EQU 512 ;default sector length for double density ; device table entry, drive type field(UTtyp) bit definitions ; TYPdnsty EQU BITD0 ;1=FM, 0=MFM TYPsides EQU BITD1 ;1=only SIDE 0, 0=has a SIDE 1 ; sector sizes - stored in UTblk+2 (word) ; SLfmLow EQU 128 ;minimum FM sector size SLmfmLow EQU 256 ;minimum MFM sector size page ; ; TIMER INTERRUPT VECTOR ADDRESS ; VECTOR5 EQU $000074 ;INTERRUPT VECTOR #5 ; VIA ADDRESS and offsets ; VIAstart EQU $30F61 ;base address of VIA viaT1CL EQU $30F69-VIAstart ;TIMER 1 COUNTER LOW - READ ONLY viaT1CH EQU $30F6B-VIAstart ;TIMER 1 COUNTER HIGH viaT1LL EQU $30F6D-VIAstart ;TIMER 1 LATCH LOW viaT1LH EQU $30F6F-VIAstart ;TIMER 1 LATCH HIGH viaT2LL EQU $30F71-VIAstart ;TIMER 2 LATCH LOW viaT2CH EQU $30F73-VIAstart ;TIMER 2 COUNTER HIGH viaACR EQU $30F77-VIAstart ;AUXILLARY CONTROL REGISTER viaIFR EQU $30F7B-VIAstart ;INTERRUPT FLAGS REGISTER viaIER EQU $30F7D-VIAstart ;INTERRUPT ENABLE REGISTER ; VIA REGISTER VALUES ; ACRBYTE EQU $40 ;ACR DATA - T1 FREE RUN DISABLE PB7 RUNT2 EQU $10 ;MASK TO COUNT DOWN T2 STOPT2 EQU $EF ;COMPLEMENTED RUNT2 TO STOP T2 DISABL EQU $7F ;DISABLE ALL INTERRUPTS ENBLT1 EQU $C0 ;ENABLE IRQ FOR T1 CLEAR EQU $FF ;CLEAR ALL IFR STAT BITS T2INT EQU $20 ;TIMER #2 INTERRUPT FLAG BIT TIME EQU 50000 ;50,000 MICRO SECONDS TIMEH EQU TIME/256 ;HI ORDER BYTE OF TIME VALUE TIMEL EQU TIME-(TIMEH*256) ;LOW ORDER BYTE OF TIME VALUE page ; I/O error codes ; IOEcrcer EQU -1 ;CRC error IOEioreq EQU -3 ;invalid I/O request IOEnebhrd EQU -4 ;nebulous hardware err code- indeterminable from err IOEoffln EQU -5 ;drive went off line, lost ready during cmd IOEwrprot EQU -16 ;write protected IOEunknwn EQU -64 ;unknown hardware err code- a severe hardware or a software err IOEinvblk EQU -18 ;invalid block number IOEflpto EQU -24 ;new timeout error code IOEnoT0 EQU -25 ;can't restore to track 0 IOEnfmtd EQU -26 ;can't read/write diskette, maybe not formatted IOEinvsct EQU -27 ;invalid sector length error IOEwrngC EQU -28 ;read the wrong track? IOEbdtrk EQU -29 ;track marked as bad (IBM spec) page ; Floppy Disk Controller (FDC) register indices - includes FDC chip and card ; FDCdata EQU 0 ;FDC data register - on FDC chip FDCstat EQU 2 ;FDC status register - on FDC chip FDCcntr EQU 4 ;Controller card buffer address counter FDCbffr EQU 6 ;Controller card buffer FDClocl EQU 8 ;Controller card local command(write) & status(read) ; FDC status register bit definitions ; Drv0BUSY EQU BITD0 ;drive 0 busy Drv1BUSY EQU BITD1 ;drive 1 busy Drv2BUSY EQU BITD2 ;drive 2 busy Drv3BUSY EQU BITD3 ;drive 3 busy FDCBUSY EQU BITD4 ;read or write cmd in progress NDMAmode EQU BITD5 ;Non-DMA mode operation DataDir EQU BITD6 ;data direction, 1=read FDCready EQU BITD7 ;ready to read/write data reg ; Controller card local command register bit definitions ; DevSel0 EQU BITD0 ;device select bit 0 DevSel1 EQU BITD1 ;device select bit 1 DvSenbl EQU BITD2 ;device select enable LCMtrOF EQU BITD3 ;motor off for 5 1/4" floppy only IRQenbl EQU BITD5 ;IRQ enable, allows card to interrupt 68K DMARWdir EQU BITD6 ;DMA direction, 1=controller read buffer ResetFDC EQU BITD7 ;reset the FDC ; masks for local command register ; EnblDvS EQU $04 ;enable device select DisblDS EQU $00 ;disable device select MMtrON EQU EnblDvS ;dev sel enbl, motor on, not reset DMARead EQU $40 ;set DMA for read all other bits clear DMAWrite EQU $00 ;set DMA for write all other bits clear MMtrOFF EQU DMARead+DisblDS+$08 ;motor off, disable device select, dma read MRstFDC EQU $80+DisblDS ;reset FDC, don't select device ; Controller card local status register bit definitions ; LSdskchng EQU BITD0 ;1=disk has been changed since last dev deselect LSNirq EQU BITD1 ;0=irq has occured LSNdrRdy EQU BITD6 ;0=FDD(drive) is ready LSeight EQU BITD7 ;1=8 inch disk drive page ; Internal data indices ; each slot has own data area but all drives on a slot have same parameters ; StepRate EQU 0 ;step rate in ms. {1..16} RdyTo EQU StepRate+2 ;timeout counter for ready wait FBflags EQU RdyTo+4 ;flags IDataLen EQU FBflags+2 ;data area length ; FBflags - bit flag definitions ; InDrvr EQU BITD0 ;in driver flag FBmoff EQU BITD1 ;motor on flag ; temporary data indices and lengths - allocated on stack ; CmdRslt EQU 0 ;command/result array CmdRsltLen EQU 10 ;max. # of bytes in command/result array ;must be on even word boundary and must be in this order ; Ptrack EQU CmdRslt+CmdRsltLen ;physical track number Pside EQU Ptrack+1 ;side number DrvNumb EQU Pside+1 ;drive number CurTrack EQU DrvNumb+1 ;current logical track LocalFrame EQU CurTrack+1 ;# of bytes in local stack frame ;must be on even number page ; ; FDC command definitions ; masks common for many commands ; Mside0 EQU $00 ;mask for side 0 select Mside1 EQU $04 ;mask for side 1 select Mmfmbit EQU $40 ;mask for MFM in command byte Mfmbit EQU $00 ;mask for FM in command byte ; common result array indices ; ST1 EQU $01 ;status register 1 ST2 EQU $02 ;status register 2 RSLTsctrl EQU $06 ;sector length code ; common indices into command vector for read and write ; RWcmdlen EQU $09 ;command array is 9 bytes RSLTrdwr EQU $07 ;result array length is 7 bytes ; specify command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 3 bytes : byte 1 = 0 0 0 0 0 0 1 1 | command byte ; byte 2 = <--SPT----> <---HUT---> | SPT=step rate, HUT=head unload time ; byte 3 = <-----HLT----------> ND | HLT=head load time, ND=Non-DMA mode ; ; NO result array ; CMDspcfy EQU $03 ;specify command byte ; command array codes for specify command HUTcode EQU $01 ;head unload time code, = 16 ms. ;must include head settle time in HLT parameter HLT5code EQU $32 ;head load time code, pre-shifted, = 50ms. HLT8code EQU $02 ;head load time code, pre-shifted, = 16ms. NDMAcode EQU $00 ;NOT DMA bit = run in DMA mode ; sense interrupt status command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 1 byte : byte 1 = 0 0 0 0 1 0 0 0 | command byte ; ; result array ; 2 bytes : byte 1 = <--------ST0----------> | ST0=status register 0 ; byte 2 = <---------C-----------> | C=current track(cylinder) ; CMDsnsint EQU $08 ;sense interrupt status command byte RSLTsnsint EQU $02 ;number of bytes in result array page ; sense drive status command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 2 bytes : byte 1 = 0 0 0 0 0 1 0 0 | command byte ; byte 2 = 0 0 0 0 0 HD DS1DS0 | DS1=device select bit 1,DS0=dev select bit 0 ; HD=head select ; result array ; 1 bytes : byte 1 = <--------ST3----------> | ST3=status register 3 ; CMDsnsdrv EQU $04 ;sense drive status command byte RSLTsnsdrv EQU $01 ;number of bytes in result array ; ; recalibrate command (restore drive to track 0) ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 2 bytes : byte 1 = 0 0 0 0 0 1 1 1 | command byte ; byte 2 = 0 0 0 0 0 0 DS1DS0 | DS1=device select bit 1,DS0=dev select bit 0 ; ; NO result array ; CMDrclbrt EQU $07 ;recalibrate command byte RTRYrstr EQU 2 ;number of retries allowed ; seek command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 2 bytes : byte 1 = 0 0 0 0 1 1 1 1 | command byte ; byte 2 = 0 0 0 0 0 HD DS1DS0 | DS1 & DS0=device select bits, HD=head select ; ; NO result array ; CMDseek EQU $0F ;seek command byte RTRYseek EQU 1 ;number of retries allowed ; read ID command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 2 bytes : byte 1 = 0MFM 0 0 1 0 1 0 | command byte,MFM=MFM/FM flag ; byte 2 = 0 0 0 0 0 HD DS1DS0 | DS1 & DS0=device select bits, HD=head select ; ; result array ; 7 bytes : byte 1 = <--------ST0----------> | ST0=status register 0 ; byte 2 = <--------ST1----------> | ST1=status register 1 ; byte 3 = <--------ST2----------> | ST2=status register 2 ; byte 4 = <---------C-----------> | C=current track(cylinder) ; byte 5 = <---------H-----------> | H=side ; byte 6 = <---------R-----------> | R=sector number ; byte 7 = <---------N-----------> | N=sector length code ; CMDredID EQU $0A ;read ID command byte RSLTredID EQU $07 ;number of bytes in result array page ; read sector command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 9 bytes : byte 1 = MTMFM 0 0 0 1 1 0 | command byte,MT=multitrack,MFM=MFM/FM flag ; byte 2 = 0 0 0 0 0 HD DS1DS0 | DS1 & DS0=device select bits, HD=head select ; byte 3 = <---------C-----------> | C=current track(cylinder) ; byte 4 = <---------H-----------> | H=side ; byte 5 = <---------R-----------> | R=sector number ; byte 6 = <---------N-----------> | N=sector length code ; byte 7 = <--------EOT----------> | EOT=last sector number on track ; byte 8 = <--------GPL----------> | GPL=gap 3 length ; byte 9 = <--------DTL----------> | DTL=special sector size ; ; result array -> SAME as read ID command ; CMDread EQU $06 ;read sector command byte RSLTread EQU $07 ;number of bytes in result array RTRYread EQU $02 ;do another read with other density ;and again with same density (make sure of error ; write sector command ; D7 D6 D5 D4 D3 D2 D1 D0 | ; 9 bytes : byte 1 = MTMFM 0 0 0 1 0 1 | command byte,MT=multitrack,MFM=MFM/FM flag ; byte 2 = 0 0 0 0 0 HD DS1DS0 | DS1 & DS0=device select bits, HD=head select ; byte 3 = <---------C-----------> | C=current track(cylinder) ; byte 4 = <---------H-----------> | H=side ; byte 5 = <---------R-----------> | R=sector number ; byte 6 = <---------N-----------> | N=sector length code ; byte 7 = <--------EOT----------> | EOT=last sector number on track ; byte 8 = <--------GPL----------> | GPL=gap 3 length ; byte 9 = <--------DTL----------> | DTL=special sector size ; ; result array -> SAME as read ID command ; CMDwrite EQU $05 ;read sector command byte RSLTwrite EQU $07 ;number of bytes in result array RTRYwrite EQU $02 ;do another write with other density ;and again with same density page ; FDC result byte definitions ; values for ST0 - status register 0 ; ST0ds0 EQU BITD0 ;device select bit 0 ST0ds1 EQU BITD1 ;device select bit 1 ST0hda EQU BITD2 ;head address ST0nrdy EQU BITD3 ;not ready ST0equp EQU BITD4 ;equipment check ST0skend EQU BITD5 ;seek end ST0ic0 EQU BITD6 ;interrupt code bit 0 ST0ic1 EQU BITD7 ;interrupt code bit 1 ; Masks for ST0 bits ; MIntCod EQU $C0 ;mask for interupt codes only MABstp EQU $40 ;mask for abnormal termination, cmd not finished MABrdy EQU $C0 ;mask for abnormal termination, drive changed ready MInvCod EQU $80 ;mask for invalid code MSkEnd EQU $20 ;mask for good seek and restore end MRstEnd EQU MIntCod+MSkEnd ;ST0 bits for Restore end ; bit flag definitions for ST1 - status register 1 ; ST1nadrm EQU BITD0 ;missing address mark (MA) ST1wrpro EQU BITD1 ;write protect error (NW) ST1snfnd EQU BITD2 ;sector not found (ND) ; bit D3 not used always low (0) ST1ovrrn EQU BITD4 ;overrun (OR) ST1dataer EQU BITD5 ;data error bit - CRC (DE) ; bit D6 not used always low (0) ST1endtr EQU BITD7 ;End of track (EN) ; bit flag definitions for ST1 - status register 1 ; ST2ndtam EQU BITD0 ;missing data address mark ST2bdtrk EQU BITD1 ;bad track - cylinder address = FF ST2Nscan EQU BITD2 ;scan not satisfied ST2scnHt EQU BITD3 ;scan hit, condition satisfied ST2wrngC EQU BITD4 ;cylinder address error ST2dtaer EQU BITD5 ;crc error in data field ST2ctlmk EQU BITD6 ;control mark ; bit D7 not used always low (0) ; bit flag definitions for ST3 - status register 3 ; ST3ds0 EQU BITD0 ;device select bit 0 ST3ds1 EQU BITD1 ;device select bit 1 ST3hda EQU BITD2 ;head address ST32sid EQU BITD3 ;2 sided ST3trk0 EQU BITD4 ;head at track 0 ST3rdy EQU BITD5 ;drive ready ST3wrpr EQU BITD6 ;write protected ST3falt EQU BITD7 ;drive fault page ; timeout values **** redo values **** ; FDCTimeOut EQU $0FFFF ;time out waiting for FDC chip to ;accept send or rcv of data FDDTimeOut EQU $10000 ;time out waiting for drive to come READY CMDTimeOut EQU $100000 ;time out waiting for command to finish ; ; File: CC.PROM.FB.TEXT ; Date: 13-June-83 ; Keith Ball ; ; Floppy driver for the new controller. ; ; ; ALL REGISTER VALUES ON ENTRY ARE SAVED AND RESTORED EXCEPT D0, D7 & A0 ; INTERNAL REGISTER USEAGE : ; ; D0 = temporary register ; D1 = temporary register ; D2 = count of bytes user wants then number of bytes in ; partial sector - if no partial then = sector size ; D3 = temporary register ; D4 = # of sectors to read/write (loop counter) ; D5 = starting block then current logical sector number ; D6 = count of bytes in command or result array ; D7 = current IOresult code ; ; A0 = temporary register ; A1 = temporary register ; A2 = pointer to local temporary variables (even word boundary) ; A3 = pointer to user's buffer or parameter block ; A4 = workstaton ram pointer ; A5 = Slot base address ; A6 = Static ram Base pg pointer - local data ; page ; ; FBboot -- Rev B floppy disk boot processing ; FBboot move.b d0,CPbtslot.w ;set boot slot number move.b d0,CPosslot.w ;set OS slot number clr.b CPbtsrvr.w ;set boot server number pea FBblkIO ;set boot disk blk i/o subr pointer move.l (sp)+,CPblkio.w ;* pea FBsctIO ;set boot disk sector i/o subr pointer move.l (sp)+,CPdskio.w ;* moveq #0,d0 ; move.b d0,CPossrvr.w ;set OS server number move.w d0,CPosblk+1.w ;set OS volume block number move.b d0,CPosdrv.w ;set OS volume drive number clr.l d1 ;access drive 0 bsr FBinit ;initialize floppy drive blt.s FBboot9 ;just return if error ; FBboot1 move.l #USRbase,a0 ;get block buffer pointer moveq #0,d0 ;1st boot block move.w d0,d1 ;drive number moveq #DskRead,d5 ;get read block function code ; bsr.s FBblkIO ;read block 0 of boot code blt.s FBboot9 ;just return if error bsr.s FBblkIO ;read block 1 of boot code blt.s FBboot9 ;just return if error move.l #USRbase,a0 ;get block buffer pointer ; FBboot9 rts ;return page ; ; FBblkIO - Read a Rev B floppy controller disk block subroutine ; ; Enter: A0.L - Buffer address ; D0.W - Block number ; D1.W - Drive number ; D5.W - Read ($32) or Write ($33) command ; ; Exit: A0.L - Next free location in buffer ; D0.W - Updated block number ; D7.W - IORESULT ; ; All other registers are preserved. ; FBblkIO MOVEQ #IOEioreq, D7 ;assume not read CMPI.W #DskRead, D5 ;is it a read? BNE.S FBBerror ;no, exit CLR.L D7 MOVEM.L D0-D6/A1-A6,-(SP) ;setup regs for driver MOVE.L A0, A3 ;put buffer adr and MOVE.W D0, D5 ;block number in right regs MOVE.W #BLKSZ, D2 ;read 1 block SUBA.W #LocalFrame, SP ;allocate local stack frame MOVE.L SP, A2 ;must be even # of bytes MOVE.B D1, DrvNumb(A2) ;save drive number ; Get data Ram(A6), Slot(A5), and workstation Ram(A4) pointers ; BSR FBbaseAdr BSR FBread ; ADDA.W #LocalFrame, SP ;release local stack frame MOVE.L A3, A0 ; save next free location MOVEM.L (SP)+,D0-D6/A1-A6 ;restore registers ADDQ.W #1,D0 ;INC BASE BLOCK FBBerror TST.W D7 ;set return condition code RTS page ; ; FBsctIO - Read a Corvus floppy disk sector ; ; Enter: A0.L - Buffer address ; D1.W - Drive number ; D3.B - Track number ; D4.B - Sector number ; D5.W - Read ($32) or Write ($33) command ; D6.B - side number (0 or 1) ; ; Exit: D7.W - IORESULT ; ; All other registers are preserved. ; FBsctIO MOVEM.L D0-D6/A0-A6,-(SP) ;save registers MOVE.L A0, A3 ;put buffer adr in right reg SUBA.W #LocalFrame, SP ;allocate local stack frame MOVE.L SP, A2 ;must be even # of bytes MOVE.B D1, DrvNumb(A2) ;save drive number MOVE.B D3, Ptrack(A2) ;save track number MOVE.B D6, Pside(A2) ;save side MOVE.L D4, D5 ;keep sector number ; Get data Ram(A6), Slot(A5), and workstation Ram(A4) pointers ; BSR FBbaseAdr ; on Entry: D0 = unit number MOVEQ #DMARead, D0 ;use dma in read direction BSR FBMtrON ;turn on motor and setup controller ; check for disk change ; BSR FBdChng BNE.S FBsio9 ;I/O error, turn motor off & exit BSR FBseek ;get to track BNE.S FBsio9 ;if error, return FBsio2 BSR FBsecRd ;read sector BNE.S FBsio9 ;failed BSR FBmvOUT ;move data to user's space FBsio9 BSR FBmtrOFF ;turn off motor ADDA.W #LocalFrame, SP ;release local stack frame MOVEM.L (SP)+,D0-D6/A0-A6 ;restore registers TST.W D7 ;set return condition code RTS page ; FBinit - init device ram and internal variables. ; initialize controller ; Entry: D1.W - Drive number ; ; Get local data(A2), data Ram(A6), Slot(A5), and workstation Ram(A4) pointers ; FBinit SUBA.W #LocalFrame, SP ;allocate local stack frame MOVE.L SP, A2 ;must be even # of bytes MOVE.B D1, DrvNumb(A2) ;save drive number BSR FBbaseAdr ; Put default values in device table entry ; BSR.S FBsltinit ; Bug in FDC - must specify step rate 1 ms. faster than want it ; MOVE.W #4, (A6) ;3 millisecond step rate MOVE.L #FDDTimeOut, RdyTO(A6) ;init ready timeout counter CLR.W FBflags(A6) ;clear all flags BSR.S FBctlinit ;init controller BNE.S FBIerror ;if failed try to recover ; restore ; MOVEQ #DMARead, D0 ;use dma in read direction BSR FBMtrON ;turn on motor and wait for Read BNE.S FBIexit1 ;timed out waiting for ready BSR FBrstor ;restore to track 0 BNE.S FBIerror ;failed, D7 has error code ; do read id and sense drive status to get disk and drive info ; BSR FBdrvInfo ;assumes motor is on FBIexit1 BSR FBmtrOFF ;turn off motor and deselect dri FBIexit ADDA.W #LocalFrame, SP ;release stack frame TST.W D7 RTS ; possible serious I/O error reset chip again to try to recover ; FBIerror BSR.S FBctlinit ;init controller also turns off BEQ.S FBIexit ;if ok exit BSR.S FBintFDC ;else reset controller and leave BRA.S FBIexit ; FBctlinit - init the FDC and do a Specify command ; FBctlinit BSR.S FBintFDC ;reset the FDC BRA FBspecify ;do a specify command page ; ;FBintFDC - reset the floppy disk controller ; Entry : (A5) = Slot base address ; FBintFDC MOVE.B #MRstFDC, FDClocl(A5) ;reset FDC MOVE.B #MMtrOFF, FDClocl(A5) ;set it back to normal RTS ; FBsltinit - init variables based on floppy type ; FBsltinit MOVE.B #D8TYPE, CPftyp.W ; single density and 1 side MOVE.B #D8TRKSID, CPftps.W ; default TRACKS PER SIDE MOVE.B #D8SECTRK,CPfspt.W ; default SECTORS PER TRACK MOVE.W #D8SctrLn, CPfbps.W ; default sector length BTST #LSeight, FDClocl(A5) ;is it 8 inch? BON.S FBSINex ;yes, exit else do for 5 1/4 inch MOVE.B #D5TYPE, CPftyp.W ; double density and 2 sides MOVE.B #D5TRKSID, CPftps.W ; default TRACKS PER SIDE MOVE.B #D5SECTRK,CPfspt.W ; default SECTORS PER TRACK MOVE.W #D5SctrLn, CPfbps.W ; default sector length FBSINex RTS page ; ; FBread - read block of floppy ; ; Turn on motor ; FBread MOVEQ #DMARead, D0 ;use dma in read direction BSR FBMtrON BNE.S FBRmtrOFF ;drive not come ready ; check for disk change ; BSR.S FBdChng BNE.S FBRmtrOFF ;I/O error, exit ; get starting sector, track and side and # of sectors to read ; BSR FBstSTS BNE.S FBRmtrOFF ;invalid block number BSR FBnumbSctr SUBQ.W #1, D4 ;turn into loop counter ; seek to track and build interleave table ; BSR FBseek BNE.S FBRmtrOFF ; for i := 1 to (# of sectors to read) do ; read sector, move data to user's buffer, update sector,track and side ; FBRread BSR.S FBsecRd ;read sector BNE.S FBRmtrOFF ;I/O error exit BSR FBmvOUT ;move data to user's space BSR FBupSTS ;update sector,track and side DBNE D4, FBRread ;do until(bad block) or (read al ; turn motor off and exit ; FBRmtrOFF BRA FBmtrOFF page ;common functions - put in groups so can make include files if necessary ;routines to do macro I/O operations ; ; FBdChng - check if disk has changed. If it has then find out diskette ; state and restore the drive. ; ASSUMES motor is alreay on and up to speed. ; ; Exit : (NE) = failed, I/O error ; (EQ) = worked ; FBdChng BTST #LSdskchng, FDClocl(A5) ;disk changed? BOFF.S FBDCexit ;no, exit (cc = EQ) ; restore drive ; BSR FBrstor ;restore to track 0 BNE.S FBDCexit ;failed, D7 has error code ; get diskette info ; Drop into drive info routine. page ; FBdrvInfo - get sector length, density and number of sides. ; get sides from sense drive status command and get sector ; length and density from read id command. ; try read id with current density if fails flip density flag. ; if that fails report error and stop. ; ; Exit : (NE) = failed, I/O error or no density???? ; (EQ) = worked ; do read id to find density ; FBdrvInfo MOVEQ #3, D0 ;try each density at least twice FBDIagn MOVE.W D0, -(SP) ;save retry count MOVEQ #Mside0, D3 ;need look at side 0 only BSR FBrdid ;if works will clear D7 BEQ.S FBDIok ;did command BRA.S FBDIex1 ;timedout, error exit FBDIok BSR FBrdidST ;see if command worked BEQ.S FBDIsav ;worked, save state BCHG #TYPdnsty, CPftyp.W ;try other density MOVE.W (SP)+, D0 ;get retry count DBRA D0, FBDIagn ;do until no more retries BRA.S FBDIext ;failed, exit ;save sector length from read id result ; FBDIsav BSR FBcnvSLCd ;convert sector length code and BNE.S FBDIex1 ;sector size to large error ; see if drive has side 1 ; MOVEQ #Mside0, D0 ;need look at side 0 only BSR FBsnsDrvSt ;do drive status to get # of sid BNE.S FBDIex1 ;timed out, exit BSET #TYPsides, CPftyp.W ;assume single sided BTST #ST32sid, (A2) ;test for number of sides BOFF.S FBDIex1 ;is single sided (1=2 sided) ; make sure can read side 1 ; MOVEQ #Mside1, D3 ;look at side 1 BSR FBrdid ;if works will clear D7 BNE.S FBDIex1 ;command failed timeout, exit BSR FBrdidST ;see if command worked BNE.S FBDIclr ;failed leave as 1 sided BCLR #TYPsides, CPftyp.W ;is double sided FBDIclr CLR.L D7 ;if read of side 1 failed - igno FBDIex1 MOVE.W (SP)+, D0 ;remove D0 from stack FBDIext TST.W D7 ;show error state FBDCexit RTS page ; ; FBsecRd - read 1 sector. Finds disk parameters if read function ; returns an "UNFORMATTED" error. ; ; Entry : (D5) = logical sector number ; (A2) = pointer to local stack frame ; Exit : (NE) = failed, I/O error ; (EQ) = worked ; FBsecRd MOVEQ #RTRYread, D0 ;read sector retry count ; if read fails and get "UNFORMATTED" error then retry with other density ; FBSRrtry MOVE.W D0, -(SP) ;save retry count CLR.L D7 ;make sure error code cleared MOVEQ #CMDread, D0 ;get in command BSR FBrd1 ;do read operation BNE.S FBSRex1 ;timedout, error exit BSR FBreadST ;see if worked BEQ.S FBSRex1 ;read sector, all done CMPI.W #IOEnfmtd, D7 ;not formatted error BNE.S FBSRnot ;no, retry with same density BSR.S FBdrvInfo ;get drive parameters BNE.S FBSRext ;maybe drive is not formatted FBSRnot MOVE.W (SP)+, D0 ;get retry count DBRA D0, FBSRrtry ;do until no more retries then BRA.S FBSRext ;exit with error in D7 FBSRex1 MOVE.W (SP)+, D0 ;remove retry count from stack FBSRext TST.W D7 ;show error condition RTS page ;FDC, FDD commands ; ; FBspecify - do a specify command to FDC ; Entry : (A2) = pointer to command and result array ; (A4) = prom data space pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; Exit : (NE) = failed ; (EQ) = completed ; FBspecify MOVE.L A2, A0 ;save addr of cmd array MOVE.B #CMDspcfy, (A0)+ ;put specify in command buffer ; 2nd byte is step rate code in bits D7 to D4 inclusive, HUT in D3 to D0 inclusiv ; 3rd byte is HLT code in bits D7 to D1 and NOT DMA in bit D0 ; MOVE.B #HLT8code+NDMAcode, D3 ;HLT code is pre-shifted, assume 8 inch MOVEQ #16, D1 ;step rate code goes MOVE.W (A6), D0 ;from F to 0 where F = 1 ms., ;E = 2 ms., D = 3 ms. and so on BTST #LSeight, FDClocl(A5) ;is it 8 inch? BON.S FBSPis8 ;yes, leave step as is else step div 2 LSR.W #1, D0 ;5 goes 2,4,6,..,32 milliseconds MOVE.B #HLT5code+NDMAcode, D3 ;use 5 inch HLT code FBSPis8 SUB.B D0, D1 ;formula = 16 - step rate LSL.B #4, D1 ;put step rate in correct bits ORI.B #HUTcode, D1 ;add head unload time code MOVE.B D1, (A0)+ ;put 2nd byte in command array MOVE.B D3, (A0) ;put 3rd byte in command array MOVEQ #3-1, D6 ;specify command is 3 bytes BRA FBwritCtl ;write command array to cntrllr ;FBwritCtl sets cc for error page ; FBsnsIntSt - do a Sense Interrupt Status command to FDC. Find out cause of ; interrupt. ; Entry : (A2) = pointer to command and result array ; (A4) = prom data space pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; Exit : (NE) = failed ; (EQ) = completed ; IF completed THEN at (A2) is result array of command ; (2 bytes) ; FBsnsIntSt MOVE.B #CMDsnsint, (A2) ;put command byte in buffer MOVEQ #1-1, D6 ;only 1 byte to command BSR FBwritCtl ;send command BNE.S FBSISex ;if timed out exit MOVEQ #RSLTsnsint-1, D6 ;length of result array BSR FBctlRead ;read result FBSISex FBSDSex RTS ; FBsnsDrvSt - do a Sense Drive Status command to FDC. ; ASSUMES motor is on and up to speed. ; Entry : (A2) = pointer to command and result array ; (A4) = device table entry pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; (D0) = side select: side 1=Mside1, side 0=Mside0 ; Exit : (NE) = failed ; (EQ) = completed ; IF completed THEN at (A2) is result array of command ; (1 byte: ST3) ; FBsnsDrvSt MOVE.L A2, A0 ;save addr of cmd array MOVE.B #CMDsnsdrv, (A0)+ ;put command byte in buffer ; 2nd byte: bit D2 is side and bits D1 and D0 are the device select ; OR.B DrvNumb(A6), D0 ;put side select in drive number MOVE.B D0, (A0) ;put in command array MOVEQ #2-1, D6 ;2 bytes to command BSR FBwritCtl ;send command BNE.S FBSDSex ;if timed out exit MOVEQ #RSLTsnsdrv-1, D6 ;length of result array BRA FBctlRead ;read result page ; ; FBrstor - do a recalibrate command to FDC. Puts head on Track 0. ; ASSUMES motor is on and up to speed. ; Entry : (A2) = pointer to command and result array ; (A4) = device table entry pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; Exit : (NE) = failed ; (EQ) = completed ; FBrstor MOVEQ #RTRYrstr, D0 ;restore retry count FBRSrtry MOVE.W D0, -(SP) ;save retry count MOVE.L A2, A0 ;save addr of cmd array MOVE.B #CMDrclbrt, (A0)+ ;put recalibrate in command buff ; 2nd byte is drive selected in bits D1 and D0, the other bits are 0 ; MOVE.B DrvNumb(A6), (A0) ;get drive number, put in command array MOVEQ #2-1, D6 ;2 bytes in command array BSR FBwritCtl ;write command array to controller BNE.S FBRSexit ;command timed out ; wait for command to complete ; FBRSwait BSR FBw8FDC BNE.S FBRSexit ;should there be a timeout on cm ; do Sense Interrupt Status command to get command results ; BSR.S FBsnsIntSt BNE.S FBRSexit ; first byte of result array (pointed at by A2) is ST0, see if seek end is good ; BSR FBrstrST ;find out type of error BCS.S FBRSwait ;wrong drive wait for correct one BEQ.S FBRSexit ;was good, so exit MOVE.W (SP)+, D0 ;get retry count DBRA D0, FBRSrtry ;do until no more retries then BRA.S FBRSext1 ;return failuere FBRSexit MOVE.W (SP)+, D0 ;remove retry count from stack FBRSext1 TST.W D7 ;show error condition RTS page ; ; FBseek - do a seek to track command to FDC. ; ASSUMES motor is on and up to speed. ; Entry : (A2) = pointer to local stack frame ; (A4) = device table entry pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; physical side and track setup ; Exit : (NE) = failed ; (EQ) = completed ; FBseek MOVEQ #RTRYseek, D0 ;restore retry count FBSKrtry MOVE.W D0, -(SP) ;save retry count MOVE.L A2, A0 ;save addr of cmd array MOVE.B #CMDseek, (A0)+ ;put seek cmd in command buffer ; 2nd byte is drive selected in bits D1 and D0 and head select in D2 ; BSR FBdselHD ;get device and head select byte MOVE.B Ptrack(A2), (A0) ;3rd byte: track wanted MOVEQ #3-1, D6 ;2 bytes in command array BSR FBwritCtl ;write command array to controll BNE.S FBSKexit ;command timed out ; wait for command to complete ; FBSKwait BSR FBw8FDC BNE.S FBSKexit ;should there be a timeout on cm ; do Sense Interrupt Status command to get command results ; BSR FBsnsIntSt BNE.S FBSKexit ; see if seek end is good ; BSR FBskSTAT ;find out type of error BCS.S FBSKwait ;wrong drive wait for correct one BEQ.S FBSKexit ;was good, so exit DBRA D0, FBSKrtry ;do until no more retries then BRA.S FBSKext1 ;report error FBSKexit MOVE.W (SP)+, D0 ;remove retry count from stack FBSKext1 TST.W D7 ;show error condition RTS page ; ; FBrdid - do a read id command to FDC. ; ASSUMES motor is on and up to speed. ; Entry : (A2) = pointer to command and result array ; (A4) = device table entry pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; (D3) = side select: side 1=Mside1, side 0=Mside0 ; Exit : (NE) = failed ; (EQ) = completed ; FBrdid MOVE.L A2, A0 ;save addr of cmd array MOVEQ #CMDredID, D0 ;get in command BSR FBadDnsty ;combine command and MFM/FM bit ; 2nd byte: bit D2 is side and bits D1 and D0 are the device select ; MOVE.B DrvNumb(A6), D1 ;get drive number OR.B D3, D1 ;put in side select MOVE.B D1, (A0) ;put in command array MOVEQ #2-1, D6 ;2 bytes to command BSR FBwritCtl ;send command BNE.S FBRIext ;if timed out exit ; wait for command to complete ; BSR FBw8FDC BNE.S FBRIext ;rts on next page ; get results of operation ; MOVEQ #RSLTredID-1, D6 ;length of result array BRA FBctlRead ;read result page ; ; FBrd1 - do 1 read or write sector operation. ; ASSUMES motor is on and up to speed and on correct track. ; Entry : D0 = command byte ; (A2) = pointer to command and result array ; (A4) = device table entry pointer ; (A5) = Slot base address ; (A6) = Static ram Base pg pointer - local data ; D5 = logical sector number ; Exit : (NE) = failed, time out ; (EQ) = completed ; FBrd1 MOVE.L A2, A0 ;save addr of cmd array BSR.S FBsetrdcmd ;setup the rest of the cmd array BNE.S FBR1exit ;invalid sector length error BSR FBbufCntr ;setup controller counter ; send command ; MOVEQ #RWcmdlen-1, D6 ;9 bytes to command BSR FBwritCtl ;send command BNE.S FBR1exit ;if timed out exit ; wait for command to complete ; BSR FBw8FDC BNE.S FBR1exit ;should there be a timeout on cm ; get results of operation ; MOVEQ #RSLTrdwr-1, D6 ;length of result array BSR FBctlRead ;read result FBRIext FBR1exit RTS page ;command operations support functions ; ; FBsetrdcmd - setup common portions of Read and Write command arrays. ; ; Entry : A0 = points at 2nd byte of command array ; A2 = local stack frame pointer ; A4 = device table entry pointer ; D0 = command byte ; D5 = logical sector number ; Exit : (NE) = invalid length error ; (EQ) = got code ; ; 2nd byte: bit D2 is side and bits D1 and D0 are the device select ; FBsetrdcmd BSR.S FBadDnsty ;expects D0 to have command byte BSR.S FBdselHD ;device sel and head sel byte MOVE.B Ptrack(A2), (A0)+ ; 3rd byte: track number MOVE.B Pside(A2), (A0)+ ; 4th byte: head number MOVE.B D5, (A0)+ ; 5th byte: sector number BSR.S FBcnv2slc ; 6th byte: sector size code BNE.S FBSCexit ; invalid length MOVE.B D0, (A0)+ MOVE.B CPfspt.W, (A0)+ ; 7th byte: EOT EXT.W D0 ; 8th byte: GPL, gap 3 length co MOVE.B GPLtable(D0.W), (A0)+ MOVEQ #-128, D1 ; 9th byte: DTL TST.B D0 ;use a DTL value ($80) if code BEQ.S FBSCmin ;is 0, = 128 bytes sector MOVEQ #-1, D1 ;use FF if length code > 0 FBSCmin MOVE.B D1, (A0)+ FBSCexit TST.W D7 RTS ; Gap 3 length code translation table ; GPLtable DATA.B $07 ;for 128 byte sectors DATA.B $0E ;for 256 byte sectors DATA.B $1B ;for 512 byte sectors DATA.B $35 ;for 1024 byte sectors page ; ; FBdselHD - put device and head select values in byte of command array ; Entry : A0 = pointer to byte in command array ; FBdselHD MOVE.B Pside(A2), D0 ;get head select LSL.B #2, D0 ;put in correct position OR.B DrvNumb(A6), D0 ;add drive select FBdsel10 MOVE.B D0, (A0)+ ;put in command array RTS ; ; FBadDnsty - add density bit to command ;CANNOT use D3 ; Entry : D0 = command byte ; A0 = pointer to byte in command array ; FBadDnsty MOVEQ #MfmBit, D1 ;assume is FM BTST #TYPdnsty, CPftyp.W ;is it FM? BON.S FBADfm ;yes (1=FM) MOVEQ #Mmfmbit, D1 ;no then use MFM FBADfm OR.B D1, D0 ;combine command and MFM/FM bit BRA.S FBdsel10 ;put it in command array page ; FBcnv2slc - convert sector length to sector length code. ;CANNOT use A0 ; Entry : (A4) = device table entry pointer ; Exit : (D0) = sector length code ; (NE) = invalid length error ; (EQ) = got code ; FM MFM ; sector lengths code code ; 128 00 -- ; 256 01 01 controller's buffer is 512 bytes ; 512 02 02 therefore it can not read/write ; 1024 -- 03 1024 byte sectors ; FBcnv2slc MOVE.W CPfbps.W, D1 ;get sector length in device tab CLR.B D0 ;start with code = 0 LSR.W #7, D1 ;put 4 possible bits in low orde FBC2find LSR.W #1, D1 ;shift out next bit BCS.S FBC2tst ;if set then D0 = correct code BEQ.S FBC2err ;if word clear then invalid leng ADDQ.B #1, D0 ;do next code BRA.S FBC2find FBC2tst CMPI.B #2, D0 ;is code in range - 512 <= sector BLS.S FBC2exit ;yes FBC2err MOVEQ #IOEinvsct, D7 ;invalid sector length error FBC2exit TST.W D7 ;show error status RTS ; ; FBcnvSLCd - convert sector length code to a number and save in device table. ; Entry : (A2) = address of result array from READ ID command ; (A4) = device table entry pointer ; Exit : (NE) = sector to long ; (EQ) = ok ; FM MFM ; sector length code code ; 128 00 -- ; 256 01 01 controller's buffer is 512 bytes ; 512 02 02 therefore it can not read/write ; 1024 -- 03 1024 byte sectors ; FBcnvSLCd MOVE.W #SLfmLow, D0 ;get min. sector length(128) CLR.W D1 ;make sure high order byte is cl MOVE.B RSLTsctrl(A2), D1 ;get sector length code LSL.W D1, D0 ;length = multiply of integral o MOVE.W D0, CPfbps.W ;save length in device table MOVE.B D1, D0 ;check if value is greater than BRA.S FBC2tst ;512 byte sectors page ; FBbaseAdr - Get static ram base pg address for this slot, get slot base ; address and device table entry address ; ; ; Exit : A5 = Slot base address ; A6 = Static ram Base pg pointer - local data ; FBbaseAdr ; ; FBSlotRam - calculate base pg address of static ram data area ; ; Exit : (A6) = Base pg address (a page = 256 bytes) ; FBSlotRam LEA CPsl1ram.W, A6 ;address of I/O slot Static Ram MOVE.B CPbtslot.W, D0 ;Slot number EXT.W D0 ;base := MOVE.W D0, D1 SUBQ.W #1,D0 ; ((slot - 1) * MULU #DBPoffst, D0 ; (pg length)) + ADDA.L D0, A6 ; (Slot Static ram base address) ; ;FBSltAdr - Fetches the slot base address. ; ; Entry : (D1) = slot number ; Exit : (A5) = Slot base address ; FBSltAdr LEA IOSbase.L, A5 ;slot 0 BaseBadrs MULU #IOSoffst, D1 ;slot * offset + slot 0 base ADDA.L D1, A5 ;equals this slot's base address RTS page ; ; FBctlRead - read n bytes from controller into command/result buffer ; ; Entry : (A2) = pointer to command/result array ; (A5) = slot base address ; (D6) = number of bytes to read - 1 ; Exit : (D6) = number of bytes not sent - 1 ; (NE) = timed out and array AND (D6) are invalid ; (EQ) = worked array is valid ; FBctlRead MOVE.L A2, A0 ;get address of array ; while (not timeout) and (haven't sent all the bytes) do ; FBCRloop MOVE.W #FDCTimeOut, D0 ;time out counter ;repeat until(timeout) or (FDC is ready) ; FBCRrdy BTST #FDCready, FDCstat(A5) ;Ready := FDC is ready SNE D3 ; and BTST #DataDir, FDCstat(A5) ; Data direction is READ SNE D1 AND.B D3, D1 BNE.S FBCRok ;Ready so stop waiting SUBQ.W #1, D0 ;count down timeout BMI.S FBCRrdy ;no, check again MOVEQ #IOEflpto, D7 ;timeout error BRA.S FBCRexit ;timed out so exit (also NE) FBCRok MOVE.B FDCdata(A5), (A0)+ ;get data from reg into array DBRA D6, FBCRloop ;see if more to get CLR.L D7 ;got all the data show no error FBCRexit RTS page ; ; FBwritCtl - write n bytes to controller from command/result buffer ; ; Entry : (A2) = pointer to command/result array ; (A5) = slot base address ; (D6) = number of bytes to write - 1 ; Exit : (NE) = timed out and did not finish sending array ; (EQ) = worked array is sent ; FBwritCtl MOVE.L A2, A0 ;get address of array ; while (not timeout) and (haven't sent all the bytes) do ; FBWCloop MOVE.W #FDCTimeOut, D0 ;time out counter ;repeat until(timeout) or (FDC is ready) ; FBWCrdy BTST #FDCready, FDCstat(A5) ;Ready := FDC is ready SNE D3 ; and BTST #DataDir, FDCstat(A5) ; Data direction is WRIT SEQ D1 AND.B D3, D1 BNE.S FBWCok ;Ready so stop waiting SUBQ.W #1, D0 ;count down timeout BNE.S FBWCrdy ;no, check again MOVEQ #IOEflpto, D7 ;timeout error BRA.S FBWCexit ;timed out so exit (also NE) FBWCok MOVE.B (A0)+, FDCdata(A5) ;get data from array into reg ;FDC will not give a valid ready state for 12 microseconds after ;after issuing the COMMAND byte of the command array ;code is probably slow enough to compensate w/o a wait loop (????) ;; MOVEQ #5, D1 ;wait 12 microsecs. for RQM ;;WRCwait DBRA D1, WRCwait ;to settle to correct state DBRA D6, FBWCloop ;see if more to get CLR.L D7 ;got all the data show no error FBWCexit RTS page ; FBMtrON - select drive, dma direction and turn motor on. Wait til ; drive comes ready. ;CANNOT use D3. ; ; Entry : (A2) = local stack frame pointer ; (A5) = Slot base address ; (D0) = DMARWdir bit = 1 if read dma, = 0 if write dma ; all other bits of low order byte clear!! ; Exit : (NE) = timed out waiting for drive ; (EQ) = worked array is sent ; ; Add to DMA direction bit Enable device select,motor on, disable INTS ; and NOT reset FDC ; FBMtrON ORI.B #MMtrON, D0 OR.B DrvNumb(A2), D0 ;get drive number (0..3) ;put as dev sel 0 and 1 MOVE.B D0, FDClocl(A5) ;put in local command register ; wait until ready or timeout ; MOVE.L RdyTO(A6), D1 ;time out counter FBMOwait BTST #LSNdrRdy, FDClocl(A5) ;is drive(FDD) ready? BOFF.S FBMOexit ;Ready so stop waiting SUBQ.L #1, D1 ;count down timeout BPL.S FBMOwait ;not timed out so continue MOVEQ #IOEflpto, D7 ;show timeout error FBMOexit RTS ; ; FBmtrOFF - deselect drive ; ; Entry : (A4) = device table entry pointer ; (A5) = Slot base address ; FBmtrOFF MOVE.B #DisblDS, FDClocl(A5) ;deselect drive RTS page ; ; FBw8FDC - wait for a command to finish. FDC generates an IRQ when done. ; ; Entry : (A5) = Slot base address ; Exit : (NE) = timed out waiting for command to finish ; (EQ) = command completed ; FBw8FDC MOVE.L #CMDTimeOut, D0 ;timeout counter FBW8wait BTST #LSNirq, FDClocl(A5) ;did IRQ happen BOFF.S FBW8exit ;yes, command done SUBQ.L #1, D0 ;no, see if ran out of time BPL.S FBW8wait ;if more counts do again else MOVEQ #IOEflpto, D7 ;show timeout error FBW8exit RTS ; ; FBbufCntr - setup controller counter to point to big enough buffer ; Counter is 8 bit interface to a 9 bit down count register which is used ; as address selector for the controller's buffer. ; D7 thru D1, inclsive, of interface goto D8 thru D2 of register. ; D0 of interface goes to D1 and D0 of counter register. ; ; Entry : (A5) = Slot base address ; FBbufCntr MOVE.W CPfbps.W, D0 ;counter := (SectorSize SUBQ.W #1, D0 ; - 1) LSR.W #1, D0 ; DIV 2 MOVE.B D0, FDCcntr(A5) RTS page ; ; FBmvOUT - move data out of controller buffer into user's buffer ; ; Entry : (D2) = number of bytes in partial sector ; (D4) = current sector loop counter ; FBmvOUT MOVE.W CPfbps.W, D1 ;if full sector move full sector TST.W D4 ;is this last sector BNE.S FBMVOful ;no MOVE.W D2, D1 ;then use partial length FBMVOful SUBQ.W #1, D1 ;make into loop counter BSR.S FBbufCntr ;init buffer counter FBMVOmov MOVE.B FDCbffr(A5), (A3)+ ;get data from buffer to user DBRA D1, FBMVOmov RTS page ; sector,track,side calc support routines ; ; FBstSTS - calculate starting side, track, and sector from starting block ; do logical track and sector and physical side and track ; ; Entry : (D5) = starting block ; Exit : (NE) = invalid block, other return params invalid ; (EQ) = worked ; (D3) = logical track (word) ; (D5) = logical sector (word) ; Pside and Ptrack inited with physical side and track ; FBstSTS CMPI.L #$7FFF, D5 ;block bigger than maxint BHI.S FBSSinvblk ;yes, invalid block number ; Logical Track := ( ((block #) * (block size)) DIV (sector size) ) DIV (sectors/ ; MULU #BLKSZ, D5 ;sector size divides evenly into DIVU CPfbps.W, D5 ;sector size must be 128,256, or CLR.L D1 ;get byte and make it a word MOVE.B CPfspt.W, D1 ; DIVU D1, D5 ;D5 low word is logical track MOVE.W D5, D1 ;save for later use and validation MOVE.B D1, CurTrack(A2) ;keep logical track for update MOVE.W D1, D3 ;save logical track ; logical sector number := remainder + 1 ; CLR.W D5 ;hi word of D5 is logical sector SWAP D5 ; minus 1. must add one to it ADDQ.W #1, D5 ; Calc physical side and track ; BRA.S FBphysTS FBSSinvblk MOVEQ #IOEinvblk, D7 ;invalid block number RTS page ; FBphysTS - calculate physical track and side from logical track ; Entry : D1 = logical track number ; Exit : Pside and Ptrack set up ; (NE) = invalid block, other return params invalid ; (EQ) = worked ; FBphysTS CLR.W Ptrack(A2) ;clear track and side, assume si BTST #TYPsides, CPftyp.W BON.S FBPsd0 ;is side 0 only. LSR.W #1, D1 ;ptrack := track div 2 ROXL.W Ptrack(A2) ;pside := track mod 2 shift in FBPsd0 CLR.L D0 ;get max # of tracks per side in MOVE.B CPftps.W, D0 ;a word CMP.W D0, D1 ;is physical track greater than BHI.S FBSSinvblk ;yes, invalid block number MOVE.B D1, Ptrack(A2) ;save physical track number FBUexit TST.W D7 RTS ; ; FBupSTS - update side, track and sector ; Entry : (D5) = current logical sector number ; (D4) = loop counter of sectors to read/write ; Exit : (NE) = invalid block or I/O error ; (EQ) = worked ; (D5) = updated logical sector number ; Pside and Ptrack set up ; Did seek if track changed ; FBupSTS TST.W D4 ;was this the last sector? BEQ.S FBUexit ;yes, exit ADDQ.W #1, D5 ;treat as word but value is a byte CMP.B CPfspt.W, D5 ;still in same track BLS.S FBUexit ;yes, then all done ; must update track and side ; MOVEQ #1, D5 ;reset sector number back to 1 CLR.L D1 ;holds logical track number ADDQ.B #1, CurTrack(A2) ;inc logical track number MOVE.B CurTrack(A2), D1 ;get updated track number BSR.S FBphysTS ;calc physical side and track BNE.S FBUexit ;invalid block error,track out of range ; do seek then calc new interleave table ; BRA FBseek ;seek physical track page ; ; FBnumbSctr - calculate number of sectors to read/write and number ; of bytes in partial sector ; ; Entry : D2 = number of bytes to read (word) ; Exit : D2 = number of bytes in partial sector - if no partial then = sector length ; D4 = total number of sectors to read, ; includes the partial sector ; FBnumbSctr MOVE.W CPfbps.W, D0 ;D0 = bytes per sector CLR.L D1 ;make sure no garbage in hi word MOVE.W D2, D1 ;# of full sectors := DIVU D0, D1 ;(# of bytes) DIV (sector size) MOVE.W D1, D4 ;save # of full sectors CLR.W D1 ;the remainder is the number SWAP D1 ;of bytes in partial sector TST.W D1 ;if partial is empty BEQ.S FBNpart ;then use full sector size for last ADDQ.W #1, D4 ;else total := (# of full sectors) + 1 MOVE.W D1, D0 ;and use partial byte count for last FBNpart MOVE.W D0, D2 ;if no partial then set it to sector RTS ;size else use partial count page ; error routines ; ; FBrstrST - check error for restore operation ; ; Entry : (A2) = address of result array from sense int command ; 2 bytes. 1st is ST0, 2nd is cylinder number. ; Exit : (D7) = IOresult code ; (NE) = I/O error ; (EQ) = no error ; (C) = wrong drive ; FBrstrST BSR FBchkST0 BCS.S FBrstrex ;wrong drive, exit BEQ.S FBrstrex ;no error, exit CMPI.W #IOEnoT0, D7 ;is it type w/ equipment error BNE.S FBrstrex ;no BTST #ST0equp, (A2) ;yes,drive won't ack Track 0 aft BON.S FBrstrex ;77 step pulses MOVEQ #IOEnebhrd, D7 ;give nebulous hardware err code FBrstrex RTS ; ; FBskSTAT - check error for seek operation ; ; Entry : (A2) = address of result array from sense int command ; 2 bytes. 1st is ST0, 2nd is cylinder number. ; Exit : (D7) = IOresult code ; (NE) = I/O error ; (EQ) = no error ; (C) = wrong drive ; FBskSTAT BSR.S FBchkST0 ;check ST0 for operation state BCS.S FBsksex ;wrong drive, exit BEQ.S FBsksex ;no error, exit CMPI.W #IOEnoT0, D7 ;did cmd stop in middle? BNE.S FBsksex ;no, give IOresult FBchkST0 found MOVEQ #IOEnebhrd, D7 ;give nebulous hardware err code FBsksex RTS page ; ;FBrdidST - check error for read ID operation ; Entry : (A2) = address of result array of read id command ; Exit : (D7) = IOresult code ; (NE) = I/O error ; (EQ) = no error ; FBrdidST BSR.S FBchkST0 ;see if command worked BEQ.S FBRIDSex ;worked so exit CMPI.W #IOEnoT0, D7 ;did cntrllr not finish cmd? BNE.S FBRIDSex ;no, then exit ; check if can't read disk - maybe unformatted? {check ST1} ; MOVEQ #IOEnfmtd, D7 ;assume not formatted MOVE.W (A2), D0 ;get 2nd byte of array in low by BTST #ST1snfnd, D0 ;sector not found? BON.S FBRIDSex ;yes, maybe unformatted BTST #ST1nadrm, D0 ;missing address mark? BON.S FBRIDSex ;yes, maybe unformatted ; see if CRC error ; MOVEQ #IOEcrcer, D7 ;assume have CRC error BTST #ST1dataer, D0 ;CRC error? BON.S FBRIDSex ;yes MOVEQ #IOEnebhrd, D7 ;give nebulous hardware err code FBRIDSex TST.W D7 RTS page ; ;FBreadST - check error for read sector operation ; ; Entry : (A2) = address of result array of read id command ; Exit : (D7) = IOresult code ; (NE) = I/O error ; (EQ) = no error ; FBreadST BSR.S FBrdidST ;do same tests as Read ID operat BEQ.S FBRDSTex ;no errors, read worked ; always try wrong cylinder. if is then restore and re-seek ; MOVE.B ST2(A2), D0 ;get status register 2 from resu BTST #ST2wrngC, D0 ;read the wrong track? BOFF.S FBRDST10 ;no BSR FBrstor ;do restore BNE.S FBRDSTex ;I/O error BSR FBseek ;do seek BNE.S FBRDSTex ;I/O error MOVEQ #IOEwrngC, D7 ;tell higher level what failed BRA.S FBRDSTex ; try read/write on bad track, write protect or missing data address mark ; FBRDST10 CMPI.W #IOEnebhrd, D7 ;did FBrdidST fail to find cause BNE.S FBRDSTex ;no, then exit MOVEQ #IOEbdtrk, D7 ;track marked as bad (IBM spec) BTST #ST2bdtrk, D0 BON.S FBRDSTex MOVEQ #IOEnfmtd, D7 ;missing data address mark BTST #ST2ndtam, D0 ;if is disk needs formatting BON.S FBRDSTex ;yes disk in bad shape ;not doing write ; MOVEQ #IOEwrprot, D7 ;disk write protected? ; BTST #ST1wrpro, ST1(A2) ; ; BON.S FBRDSTex ;yes MOVEQ #IOEnebhrd, D7 ;give nebulous hardware err code FBRDSTex TST.W D7 RTS page ; ;FBchkST0 - check ST0 to see if command failed or succeded ; Entry : (A2) = address of ST0 byte ; Exit : (D7) = IOresult code from ST0 check ; (NE) = I/O error ; (EQ) = no error ; (C) = wrong drive ; FBchkST0 MOVE.B (A2), D0 ;get ST0 ANDI.B #MIntCod, D0 ;check interrupt code ; see if controller tried but didn't finish ; MOVEQ #IOEnoT0, D7 ;give can't get to Track 0 CMPI.B #MABstp, D0 ;if cmd stopped in middle BEQ.S FBC0exit ;yes ; see if drive changed ready line ; CMPI.B #MABrdy, D0 BNE.S FBC0inv MOVEQ #IOEoffln, D7 ;drive went off line, lost ready MOVEQ #3, D0 ;see if have correct drive response AND.B (A2), D0 ;leave just drive sel bits CMP.B DrvNumb(A6), D0 ;is drive the same? BEQ.S FBC0exit ;correct drive, exit carry clear MOVE.W #1, CCR ;set NE and C got wrong drive BRA.S FBC0ex1 ;exit ; see if invalid code, if is then have either severe hardware error or software b ; FBC0inv MOVEQ #IOEunknwn, D7 ;give unknown hardware err code CMPI.B #MInvCod, D0 ;is it invalid? BEQ.S FBC0exit ;no, exit no errors CLR.L D7 ;show no error FBC0exit TST.W D7 ;should clear carry flag FBC0ex1 RTS page list 1 PromLength EQU % ;bytes of code end setup