Init
This commit is contained in:
870
sys/sbusdev/fd_asm.s
Normal file
870
sys/sbusdev/fd_asm.s
Normal file
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
/* @(#)fd_asm.s 1.1 94/10/31 SMI */
|
||||
/*
|
||||
* Copyright (c) 1989 by Sun Microsystems, Inc.
|
||||
*/
|
||||
/*
|
||||
* Campus 1 low level floppy hardware interrupt handler.
|
||||
*
|
||||
* This is hardwired onto level 11 all by itself. It is needed to handle
|
||||
* the floppy data transfers without DMA. The basic flow of operations is:
|
||||
* device driver calculates parameters
|
||||
* device driver sets up fdintr_* values for this interrupt handler
|
||||
* device driver starts operation
|
||||
* device driver sleeps on someplace where its software interrupt handler
|
||||
* will wake it.
|
||||
* this interrupt handler does the data/result xfer for read/write/formats
|
||||
* (or sense status for recalibrate/seek)
|
||||
* then this interrupt handler sets a flag for the floppy soft interrupt
|
||||
* handler and sets its bit in the interrupt control register
|
||||
* the floppy software interrupt handler does whatever it needs to,
|
||||
* (like retries, wake of upper levels, ... )
|
||||
* and clears the opmode value to "reset" the hardware level.
|
||||
*
|
||||
*
|
||||
* NOTES ON TRAPS
|
||||
* This code is called directly out of the trap table and
|
||||
* RUNS WITH TRAPS DISABLED! Therefore it must be PERFECTLY ROBUST!
|
||||
*
|
||||
* Some things to remember:
|
||||
* when a trap is taken, traps are disabled: SO we must be *VERY CAREFUL*
|
||||
* when a trap is taken, PC and nPC go into r17/%l1 and r18/%l2, respectively
|
||||
* the TRAP() macro is: #define TRAP(H) b (H); mov %psr,%l0; nop; nop;
|
||||
* I have only the registers %l0-%l7 to work with.
|
||||
* - and %l0 - %l2 are already used.
|
||||
* the two instructions to return from trap are: jmpl ; rett
|
||||
* - ie: jmp %l1 ! return
|
||||
* rett %l2
|
||||
*
|
||||
* TODO:
|
||||
* () decide on status returned, now it is just 0 = ok, !0 = !ok
|
||||
*/
|
||||
|
||||
#define I82077
|
||||
|
||||
#include <machine/auxio.h>
|
||||
#include <machine/intreg.h>
|
||||
#include <machine/asm_linkage.h>
|
||||
|
||||
#include <machine/mmu.h>
|
||||
|
||||
/* these defines are always the same for 82072 controller chip */
|
||||
#define RQM 0x80
|
||||
#define DIO 0x40
|
||||
#define NDM 0x20
|
||||
#define CB 0x10
|
||||
#define SENSE_INTERRUPT_STATUS 0x08
|
||||
|
||||
|
||||
#ifdef COMMENT /* just a (longish) comment of pseudocode */
|
||||
fdc_hardintr()
|
||||
{
|
||||
int timeoutcntr; /* timeout counter NYD XXX NOT USED? TBD */
|
||||
register u_char *fdc; /* pointer to fdc registers */
|
||||
register int len;
|
||||
register char *addr;
|
||||
|
||||
fdc = fdctlr_reg;
|
||||
|
||||
switch( fdintr_opmode ) {
|
||||
case 1:
|
||||
/* read/write/format data xfer - during data xfer phase */
|
||||
/***timeoutcntr = fdintr_timeout; /* XXX NYD TBD NOT USED? */
|
||||
len = fdintr_len;
|
||||
addr = fdintr_addr;
|
||||
|
||||
/* if the fifo ready bit set, then data available */
|
||||
while( *fdc & RQM ) {
|
||||
if( (*fdc & NDM) == 0 ) {
|
||||
/* whoops! things blew up, abandon it */
|
||||
/* DON'T send terminal count, it clears status*/
|
||||
fdintr_len = len;
|
||||
fdintr_addr = addr;
|
||||
fdintr_opmode = 3;
|
||||
goto results;
|
||||
}
|
||||
/* NDM is set, that means data */
|
||||
/* if input data, then input; else output */
|
||||
if( *fdc & DIO )
|
||||
*addr++ = *fifo;
|
||||
else
|
||||
*fifo = *addr++;
|
||||
len--;
|
||||
/* if length went to 0, then send the TC */
|
||||
if( len == 0 )
|
||||
goto end_xfr;
|
||||
}
|
||||
/* no more data, stash updated len, addr */
|
||||
fdintr_len = len;
|
||||
fdintr_addr = addr;
|
||||
break;
|
||||
/*****/
|
||||
end_xfr:
|
||||
/* start send terminal count pulse */
|
||||
*(char *)AUXIO_REG |= (AUX_TC|AUX_MBO);
|
||||
/* save updated len, addr (is also a DELAY for TC) */
|
||||
fdintr_len = len;
|
||||
fdintr_addr = addr;
|
||||
/* clear the terminal count pulse */
|
||||
*(char *)AUXIO_REG =
|
||||
AUX_MBO | ((*(char *)AUXIO_REG) & ~AUX_TC);
|
||||
/* set "this is status phase" */
|
||||
fdintr_opmode = 3;
|
||||
return;
|
||||
break;
|
||||
case 2:
|
||||
/* recal,seek - no result phase, must do sense interrupt status */
|
||||
sense_int_stat:
|
||||
while( *fdc & CB ) ;
|
||||
while( ! (*fdc & RQM) ) ;
|
||||
*fifo = SENSE_INTERRUPT_STATUS;
|
||||
while( ! (*fdc & RQM) ) ;
|
||||
fdintr_statbuf[0] = *fifo;
|
||||
while( ! (*fdc & RQM) ) ;
|
||||
fdintr_statbuf[1] = *fifo;
|
||||
goto notify; /* now tell upper layer that things are done */
|
||||
break;
|
||||
|
||||
case 3:
|
||||
results:
|
||||
/* result phase of regular ops, gather status */
|
||||
addr = fdintr_statp; /* get ptr to status buf */
|
||||
while( *fdc & CB ) { /* while chip is still "busy" */
|
||||
while( (*fdc & (RQM|DIO)) != (RQM|DIO) )
|
||||
;
|
||||
*addr++ = *fifo;
|
||||
}
|
||||
fdintr_statp = addr; /* save updated ptr */
|
||||
goto notify; /* now tell upper layer that things are done */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* no drive, no operation, ... */
|
||||
fdintr_spurious++;
|
||||
if( fdc != 0 )
|
||||
goto sense_int_stat;
|
||||
/* shall we do a reset to the FDC ? XXX NYD TBD */
|
||||
}
|
||||
goto out;
|
||||
/*******/
|
||||
|
||||
notify:
|
||||
/* set bit in soft interrupt register */
|
||||
#ifndef sun4m
|
||||
*(u_char *)INTREG_ADDR |= IR_SOFT_INT4;
|
||||
#else sun4m
|
||||
send_dirint(get_processorid(), 4);
|
||||
#endif sun4m
|
||||
/* set software interrupt flag */
|
||||
fdintr_opmode = 4;
|
||||
fdintr_status = 0;
|
||||
|
||||
out:
|
||||
restore_psr_with_delay;
|
||||
return_from_trap;
|
||||
}
|
||||
#endif COMMENT
|
||||
|
||||
|
||||
/* start of assembler source */
|
||||
/*
|
||||
* private data for this interrupt handler
|
||||
* I = input, set before starting operation
|
||||
* O = output, available *after* this invokes the software level
|
||||
*/
|
||||
.seg "data"
|
||||
.align 4
|
||||
|
||||
/* I: 1 = read/write/format, 2 = seek/recal; O: 4 = done */
|
||||
/* 3 = internal state -waiting for results */
|
||||
/* only set if operation is actually pending - KEEP CLEAR OTHERWISE! */
|
||||
.global _fdintr_opmode
|
||||
_fdintr_opmode:
|
||||
.word 0x0
|
||||
|
||||
/* I/O: (current) data xfer address */
|
||||
.global _fdintr_addr
|
||||
_fdintr_addr:
|
||||
.word 0x0
|
||||
|
||||
/* I: data xfer length; O: remainder */
|
||||
.global _fdintr_len
|
||||
_fdintr_len:
|
||||
.word 0x0
|
||||
|
||||
/* I: n/a; O: 0 = ok, TBD XXX NYD errors */
|
||||
.global _fdintr_status
|
||||
_fdintr_status:
|
||||
.word 0x0
|
||||
|
||||
/* timeout value for ??? */
|
||||
/* NOT USED YET/EVER??? XXX TBD NYD NEVER MAYBE */
|
||||
.global _fdintr_timeout
|
||||
_fdintr_timeout:
|
||||
.word 0x0
|
||||
|
||||
/* count of spurious interrupts */
|
||||
.global _fdintr_spurious
|
||||
_fdintr_spurious:
|
||||
.word 0x0
|
||||
|
||||
/* I: pointer to fdintr_statbuf; O: n/a */
|
||||
.global _fdintr_statp
|
||||
_fdintr_statp:
|
||||
.word _fdintr_statbuf + 0x0
|
||||
|
||||
/*XXX status of number of interrupts! */
|
||||
.global _fdintr_nints
|
||||
_fdintr_nints:
|
||||
.word 0
|
||||
|
||||
|
||||
/*
|
||||
* WARNING, DANGER - if there is ever an interrupt and this address is
|
||||
* not * setup (by fdattach) then things may/will hang! (depends on
|
||||
* what's at 0)
|
||||
*/
|
||||
/* pointer to fdc registers, set by fdattach() */
|
||||
.global _fdctlr_reg
|
||||
_fdctlr_reg:
|
||||
.word 0x0
|
||||
#ifdef I82077
|
||||
.global _fd_msr
|
||||
_fd_msr:
|
||||
.word 0x0
|
||||
.global _fd_dsr
|
||||
_fd_dsr:
|
||||
.word 0x0
|
||||
.global _fd_dor
|
||||
_fd_dor:
|
||||
.word 0x0
|
||||
.global _fd_dir
|
||||
_fd_dir:
|
||||
.word 0x0
|
||||
.global _fd_fifo
|
||||
_fd_fifo:
|
||||
.word 0x0
|
||||
#endif I82077
|
||||
|
||||
/* I: n/a; O: 10 bytes of status buffer */
|
||||
.global _fdintr_statbuf
|
||||
_fdintr_statbuf:
|
||||
.word 0xAAAAAAAA
|
||||
.word 0xBBBBBBBB
|
||||
.word 0xCCCCCCCC
|
||||
.word 0xDDDDDDDD
|
||||
|
||||
/*
|
||||
* fdc_hardintr - interrupt function to do DMA-like operation for floppy
|
||||
* Since it is the only thing on level 11 on a Campus, we can just
|
||||
* call this thing directly from trap table.
|
||||
* WE RUN WITH TRAPS DISABLED! - BE CAREFUL!
|
||||
* I have only the registers %l0-%l7 to work with! (and %l{0-2} are already used)
|
||||
*/
|
||||
/*
|
||||
* CODING CONVENTIONS
|
||||
* REGISTER USAGE - is as shown by the following defines
|
||||
* INSTRUCTIONS following BRANCH - have a "!!" comment delimiter
|
||||
*/
|
||||
#define Fdc %l3 /* csr - the pointer to the chip's registers */
|
||||
#define Adr %l4 /* addr - the data address pointer */
|
||||
#define Len %l5 /* len - length of data */
|
||||
#define Ptr %l6 /* misc ptr */
|
||||
#define Tmp %l7 /* scratch */
|
||||
|
||||
.seg "text"
|
||||
.global _fdc_hardintr
|
||||
_fdc_hardintr:
|
||||
#ifdef MEASURE_TIME
|
||||
/* START: set the LED */
|
||||
sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
or Tmp, AUX_LED|AUX_MBO, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
#endif MEASURE_TIME
|
||||
|
||||
/*XXX DEBUG ??? */
|
||||
sethi %hi(_fdintr_nints), Ptr ! load ptr to count of ints
|
||||
ld [Ptr + %lo(_fdintr_nints)], Tmp
|
||||
add Tmp, 0x1, Tmp
|
||||
st Tmp, [Ptr + %lo(_fdintr_nints)]
|
||||
#ifdef I82077
|
||||
/*
|
||||
* This routine only uses 2 8207[27] registers, the msr and fifo
|
||||
* registers. In the two configurations, the addresses of the msr
|
||||
* are different, but the fifo always directly follows the msr.
|
||||
* For this reason, we stuff the address of msr into Fdc instead
|
||||
* of the base address of the chip's registers.
|
||||
*/
|
||||
sethi %hi(_fd_msr), Ptr ! load ptr to msr into Fdc
|
||||
ld [Ptr + %lo(_fd_msr)], Fdc
|
||||
#else
|
||||
sethi %hi(_fdctlr_reg), Ptr ! load ptr to csr into Fdc
|
||||
ld [Ptr + %lo(_fdctlr_reg)], Fdc
|
||||
#endif I82077
|
||||
|
||||
/*
|
||||
* switch( opmode ) {
|
||||
*/
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
ld [Ptr + %lo(_fdintr_opmode)], Tmp
|
||||
cmp Tmp, 1 !case 1: read/write data-xfr
|
||||
be L10
|
||||
cmp Tmp, 2 !case 2: seek/recalibrate ?
|
||||
be L21
|
||||
cmp Tmp, 3 !case 3: results ?
|
||||
be L30
|
||||
|
||||
! default: SPURIOUS INTERRUPT! XXX NYD hope we NEVER GET HERE!
|
||||
sethi %hi(_fdintr_spurious), Ptr !! spurious++
|
||||
ld [Ptr + %lo(_fdintr_spurious)], Tmp
|
||||
add Tmp, 0x1, Tmp
|
||||
st Tmp, [Ptr + %lo(_fdintr_spurious)] !!
|
||||
! pray and test that the controller is mapped in!
|
||||
tst Fdc
|
||||
bne L21 ! yes, do a sense interrupt status
|
||||
nop
|
||||
b L900 ! no, just exit
|
||||
nop
|
||||
/**********/
|
||||
|
||||
/*
|
||||
* case 1:
|
||||
* read/write/format data-xfer case - they have a result phase
|
||||
*/
|
||||
L10:
|
||||
#ifdef NEVER /* no timeout stuff just yet */
|
||||
sethi %hi(_fdintr_timeout), %__
|
||||
ld [%__ + %lo(_fdintr_timeout)], %__
|
||||
st %__, [%fp + -0x4]
|
||||
#endif NEVER
|
||||
sethi %hi(_fdintr_len), Ptr ! len into Len
|
||||
ld [Ptr + %lo(_fdintr_len)], Len
|
||||
sethi %hi(_fdintr_addr), Ptr ! addr into Adr
|
||||
ld [Ptr + %lo(_fdintr_addr)], Adr
|
||||
|
||||
/* while the fifo ready bit set, then data/status available */
|
||||
/* while( *csr & RQM ) { */
|
||||
L11: ldub [Fdc], Tmp ! get msr
|
||||
andcc Tmp, RQM, %g0
|
||||
be L19 ! branch if bit clear
|
||||
|
||||
/* if NDM is set, that means data */
|
||||
andcc Tmp, NDM, %g0 !! if( *csr & NDM ) {
|
||||
be L803 ! if ! set, is status!
|
||||
|
||||
/* check for input vs. output data */
|
||||
andcc Tmp, DIO, %g0 !! _if( *csr & DIO ) {
|
||||
be L13
|
||||
sub Len, 0x1, Len !! len--
|
||||
|
||||
ldub [Fdc + 0x1], Tmp ! DIO set, *addr = *fifo
|
||||
b L12
|
||||
stb Tmp, [Adr] !!
|
||||
|
||||
L13: ldsb [Adr], Tmp ! _}else{ DIO clear, *fifo = *addr
|
||||
stb Tmp, [Fdc + 0x1]
|
||||
! _} end if *csr & DIO
|
||||
/* addr++; len--; if(len==0) send TC */
|
||||
L12: ! moved len-- up beneath test DIO branch
|
||||
tst Len ! if( len == 0 ) send TC
|
||||
bne L11 ! branch if not, back to while( ..RQM )
|
||||
add Adr, 0x1, Adr !! addr++ } /* end of *csr & NDM */
|
||||
/* if ( Len == 0 ) goto end_xfr */
|
||||
b L801
|
||||
nop
|
||||
|
||||
/* } end while( *csr & RQM ) */
|
||||
L19: /* save updated len, addr */
|
||||
sethi %hi(_fdintr_len), Ptr
|
||||
st Len, [Ptr + %lo(_fdintr_len)]
|
||||
sethi %hi(_fdintr_addr), Ptr
|
||||
b L900 ! not done yet, return
|
||||
st Adr, [Ptr + %lo(_fdintr_addr)] !!
|
||||
/**********/
|
||||
|
||||
/*
|
||||
* END OF TRANSFER - if read/write, toggle the TC bit in AUXIO_REG
|
||||
* then save status and set state = 3.
|
||||
*/
|
||||
/* end_xfr: */
|
||||
L801: sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
or Tmp, AUX_MBO|AUX_TC, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
/* begin TC delay */
|
||||
! five nops provide 100ns of delay at 10MIPS to ensure
|
||||
! TC is wide enough at slowest possible floppy clock (500ns @ 250Kbps)
|
||||
/*
|
||||
* (do something usefull in delay)
|
||||
* stash len and addr before they get lost
|
||||
*/
|
||||
L802: sethi %hi(_fdintr_len), Ptr
|
||||
st Len, [Ptr + %lo(_fdintr_len)]
|
||||
sethi %hi(_fdintr_addr), Ptr
|
||||
st Adr, [Ptr + %lo(_fdintr_addr)]
|
||||
nop
|
||||
/* end TC delay */
|
||||
! now clear the TC bit
|
||||
sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
and Tmp, ~AUX_TC, Tmp
|
||||
or Tmp, AUX_MBO, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
|
||||
/* opmode = 3 to indicate going into status mode */
|
||||
mov 0x3, Tmp
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
b L900
|
||||
st Tmp, [Ptr + %lo(_fdintr_opmode)] !!
|
||||
/***********/
|
||||
|
||||
/*
|
||||
* error status state: save old pointers, go direct to result snarfing
|
||||
*/
|
||||
L803: sethi %hi(_fdintr_len), Ptr
|
||||
st Len, [Ptr + %lo(_fdintr_len)]
|
||||
sethi %hi(_fdintr_addr), Ptr
|
||||
st Adr, [Ptr + %lo(_fdintr_addr)]
|
||||
mov 0x3, Tmp
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
b L30
|
||||
st Tmp, [Ptr + %lo(_fdintr_opmode)] !!
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* case 2:
|
||||
* recalibrate/seek - no result phase, must do sense interrupt status
|
||||
*/
|
||||
/* sense_int_stat: */
|
||||
L21: ldub [Fdc], Tmp ! Tmp = *csr
|
||||
L22: andcc Tmp, CB, Tmp ! is CB set?
|
||||
bne L22 ! yes, keep waiting
|
||||
ldub [Fdc], Tmp !! Tmp = *csr
|
||||
|
||||
/* wait!!! should we check rqm first??? ABSOLUTELY YES!!!! */
|
||||
L23: ldub [Fdc], Tmp ! busy wait until RQM set
|
||||
andcc Tmp, RQM, Tmp
|
||||
be L23 ! branch if bit clear
|
||||
nop
|
||||
mov 0x8, Tmp ! cmd for SENSE_INTERRUPT_STATUS
|
||||
stb Tmp, [Fdc + 0x1]
|
||||
|
||||
/* NOTE: we ignore DIO here, assume it is set before RQM! */
|
||||
L24: ldub [Fdc], Tmp ! busy wait until RQM set
|
||||
andcc Tmp, RQM, Tmp
|
||||
be L24 ! branch if bit clear
|
||||
nop
|
||||
|
||||
! fdintr_statbuf[0] = *fifo;
|
||||
ldub [Fdc + 0x1], Tmp
|
||||
sethi %hi(_fdintr_statbuf), Ptr
|
||||
stb Tmp, [Ptr + %lo(_fdintr_statbuf)]
|
||||
|
||||
L26: ldub [Fdc], Tmp ! busy wait until RQM set
|
||||
andcc Tmp, RQM, Tmp
|
||||
be L26 ! branch if bit clear
|
||||
nop
|
||||
|
||||
/* fdintr_statbuf[1] = *fifo; */
|
||||
ldub [Fdc + 0x1], Tmp
|
||||
sethi %hi(_fdintr_statbuf + 0x1), Ptr
|
||||
b L40
|
||||
stb Tmp, [Ptr + %lo(_fdintr_statbuf + 0x1)] !!
|
||||
|
||||
|
||||
/*
|
||||
* case 3: result mode
|
||||
* are in result mode make sure all status bytes are read out
|
||||
*/
|
||||
L30: sethi %hi(_fdintr_statp), Adr ! &statp in Adr
|
||||
ld [Adr + %lo(_fdintr_statp)], Ptr ! statp is Ptr
|
||||
sethi %hi(_fdintr_statbuf+10), Len ! Len is limit for status bytes
|
||||
or Len, %lo(_fdintr_statbuf+10), Len
|
||||
ldub [Fdc], Tmp !
|
||||
L34: andcc Tmp, CB, %g0 ! is CB set?
|
||||
be L32 ! no, jump around, must be fini
|
||||
nop
|
||||
! are *both* RQM and DIO set?
|
||||
andcc Tmp, RQM, %g0
|
||||
be L33
|
||||
nop
|
||||
andcc Tmp, DIO, %g0
|
||||
be L33
|
||||
nop
|
||||
ldub [Fdc + 0x1], Tmp ! *fifo into Tmp
|
||||
stb Tmp, [Ptr]
|
||||
! check to see if status buffer ptr is at/past limit
|
||||
/*XXX limits? */
|
||||
cmp Ptr, Len
|
||||
bge L33 ! if past, don't increment!
|
||||
nop
|
||||
add Ptr, 0x1, Ptr ! statp++ in Ptr
|
||||
L33: b L34 ! back to while( *Fdc & CB )
|
||||
ldub [Fdc], Tmp !
|
||||
|
||||
L32: ! stash updated statp and go to notify
|
||||
b L40
|
||||
st Ptr, [Adr + %lo(_fdintr_statp)] !!
|
||||
|
||||
|
||||
/* notify: */ /* set bit in software interrupt register */
|
||||
L40: /* *(uchar *)INTREG_ADDR |= IR_SOFT_INT4 */
|
||||
#ifndef sun4m
|
||||
sethi %hi(INTREG_ADDR), Ptr
|
||||
ldub [Ptr + %lo(INTREG_ADDR)], Tmp
|
||||
or Tmp, IR_SOFT_INT4, Tmp
|
||||
stb Tmp, [Ptr + %lo(INTREG_ADDR)]
|
||||
#else sun4m
|
||||
/*
|
||||
* set a pending level 4 software interrupt
|
||||
* we are probably going to be the master,
|
||||
* and if we are not then it will be vectored
|
||||
* to the proper master.
|
||||
*/
|
||||
GETCPU(Tmp) ! get module id, 8..11
|
||||
and Tmp, 3, Tmp ! mask to 0..3
|
||||
sll Tmp, 12, Tmp ! shift for +0x1000 per mid
|
||||
set V_INT_REGS, Ptr
|
||||
add Ptr, Tmp, Ptr ! calculate location of OUR int reg
|
||||
set IR_SOFT_INT4, Tmp
|
||||
st Tmp, [Ptr+8] ! send the softint
|
||||
#endif sun4m
|
||||
|
||||
/* opmode = 4; status = 0; */
|
||||
mov 0x4, Tmp
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
st Tmp, [Ptr + %lo(_fdintr_opmode)]
|
||||
mov 0x0, Tmp
|
||||
sethi %hi(_fdintr_status), Ptr
|
||||
st Tmp, [Ptr + %lo(_fdintr_status)]
|
||||
|
||||
/* out: */
|
||||
L900:
|
||||
#ifdef MEASURE_TIME
|
||||
/* END: clear the LED */
|
||||
sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
and Tmp, ~AUX_LED, Tmp
|
||||
or Tmp, AUX_MBO, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
#endif MEASURE_TIME
|
||||
mov %l0, %psr ! restore psr - and user's ccodes
|
||||
nop
|
||||
nop
|
||||
jmp %l1 ! return from interrupt
|
||||
rett %l2
|
||||
.empty
|
||||
|
||||
.global _fdc_intr
|
||||
_fdc_intr:
|
||||
save %sp, -96, %sp
|
||||
#ifdef MEASURE_TIME
|
||||
/* START: set the LED */
|
||||
sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
or Tmp, AUX_LED|AUX_MBO, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
#endif MEASURE_TIME
|
||||
|
||||
! Assume interrupt is from Floppy, unless otherwise overwritten (%i0)
|
||||
mov 0x1, %i0
|
||||
|
||||
/*XXX DEBUG ??? */
|
||||
sethi %hi(_fdintr_nints), Ptr ! load ptr to count of ints
|
||||
ld [Ptr + %lo(_fdintr_nints)], Tmp
|
||||
add Tmp, 0x1, Tmp
|
||||
st Tmp, [Ptr + %lo(_fdintr_nints)]
|
||||
#ifdef I82077
|
||||
/*
|
||||
* This routine only uses 2 8207[27] registers, the msr and fifo
|
||||
* registers. In the two configurations, the addresses of the msr
|
||||
* are different, but the fifo always directly follows the msr.
|
||||
* For this reason, we stuff the address of msr into Fdc instead
|
||||
* of the base address of the chip's registers.
|
||||
*/
|
||||
sethi %hi(_fd_msr), Ptr ! load ptr to msr into Fdc
|
||||
ld [Ptr + %lo(_fd_msr)], Fdc
|
||||
#else
|
||||
sethi %hi(_fdctlr_reg), Ptr ! load ptr to csr into Fdc
|
||||
ld [Ptr + %lo(_fdctlr_reg)], Fdc
|
||||
#endif I82077
|
||||
|
||||
/*
|
||||
* switch( opmode ) {
|
||||
*/
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
ld [Ptr + %lo(_fdintr_opmode)], Tmp
|
||||
cmp Tmp, 1 !case 1: read/write data-xfr
|
||||
be L100
|
||||
cmp Tmp, 2 !case 2: seek/recalibrate ?
|
||||
be L210
|
||||
cmp Tmp, 3 !case 3: results ?
|
||||
be L300
|
||||
nop
|
||||
|
||||
|
||||
! do a sense interrupt status
|
||||
|
||||
tst Fdc
|
||||
bne L210
|
||||
nop
|
||||
|
||||
! Return 0, interrupt is not from Floppy.
|
||||
b L9000 ! no, just exit with Zero return
|
||||
mov 0x0, %i0
|
||||
/**********/
|
||||
|
||||
/*
|
||||
* case 1:
|
||||
* read/write/format data-xfer case - they have a result phase
|
||||
*/
|
||||
L100:
|
||||
#ifdef NEVER /* no timeout stuff just yet */
|
||||
sethi %hi(_fdintr_timeout), %__
|
||||
ld [%__ + %lo(_fdintr_timeout)], %__
|
||||
st %__, [%fp + -0x4]
|
||||
#endif NEVER
|
||||
sethi %hi(_fdintr_len), Ptr ! len into Len
|
||||
ld [Ptr + %lo(_fdintr_len)], Len
|
||||
sethi %hi(_fdintr_addr), Ptr ! addr into Adr
|
||||
ld [Ptr + %lo(_fdintr_addr)], Adr
|
||||
|
||||
/* while the fifo ready bit set, then data/status available */
|
||||
/* while( *csr & RQM ) { */
|
||||
L110: ldub [Fdc], Tmp ! get msr
|
||||
andcc Tmp, RQM, %g0
|
||||
be L190 ! branch if bit clear
|
||||
|
||||
/* if NDM is set, that means data */
|
||||
andcc Tmp, NDM, %g0 !! if( *csr & NDM ) {
|
||||
be L8030 ! if ! set, is status!
|
||||
|
||||
/* check for input vs. output data */
|
||||
andcc Tmp, DIO, %g0 !! _if( *csr & DIO ) {
|
||||
be L130
|
||||
sub Len, 0x1, Len !! len--
|
||||
|
||||
ldub [Fdc + 0x1], Tmp ! DIO set, *addr = *fifo
|
||||
b L120
|
||||
stb Tmp, [Adr] !!
|
||||
|
||||
L130: ldsb [Adr], Tmp ! _}else{ DIO clear, *fifo = *addr
|
||||
stb Tmp, [Fdc + 0x1]
|
||||
! _} end if *csr & DIO
|
||||
/* addr++; len--; if(len==0) send TC */
|
||||
L120: ! moved len-- up beneath test DIO branch
|
||||
tst Len ! if( len == 0 ) send TC
|
||||
bne L110 ! branch if not, back to while( ..RQM )
|
||||
add Adr, 0x1, Adr !! addr++ } /* end of *csr & NDM */
|
||||
/* if ( Len == 0 ) goto end_xfr */
|
||||
b L8010
|
||||
nop
|
||||
|
||||
/* } end while( *csr & RQM ) */
|
||||
L190: /* save updated len, addr */
|
||||
sethi %hi(_fdintr_len), Ptr
|
||||
st Len, [Ptr + %lo(_fdintr_len)]
|
||||
sethi %hi(_fdintr_addr), Ptr
|
||||
b L9000 ! not done yet, return
|
||||
st Adr, [Ptr + %lo(_fdintr_addr)] !!
|
||||
/**********/
|
||||
|
||||
/*
|
||||
* END OF TRANSFER - if read/write, toggle the TC bit in AUXIO_REG
|
||||
* then save status and set state = 3.
|
||||
*/
|
||||
/* end_xfr: */
|
||||
L8010: sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
or Tmp, AUX_MBO|AUX_TC, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
/* begin TC delay */
|
||||
! five nops provide 100ns of delay at 10MIPS to ensure
|
||||
! TC is wide enough at slowest possible floppy clock (500ns @ 250Kbps)
|
||||
/*
|
||||
* (do something usefull in delay)
|
||||
* stash len and addr before they get lost
|
||||
*/
|
||||
L8020: sethi %hi(_fdintr_len), Ptr
|
||||
st Len, [Ptr + %lo(_fdintr_len)]
|
||||
sethi %hi(_fdintr_addr), Ptr
|
||||
st Adr, [Ptr + %lo(_fdintr_addr)]
|
||||
nop
|
||||
/* end TC delay */
|
||||
! now clear the TC bit
|
||||
sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
and Tmp, ~AUX_TC, Tmp
|
||||
or Tmp, AUX_MBO, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
|
||||
/* opmode = 3 to indicate going into status mode */
|
||||
mov 0x3, Tmp
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
b L9000
|
||||
st Tmp, [Ptr + %lo(_fdintr_opmode)] !!
|
||||
/***********/
|
||||
|
||||
/*
|
||||
* error status state: save old pointers, go direct to result snarfing
|
||||
*/
|
||||
L8030: sethi %hi(_fdintr_len), Ptr
|
||||
st Len, [Ptr + %lo(_fdintr_len)]
|
||||
sethi %hi(_fdintr_addr), Ptr
|
||||
st Adr, [Ptr + %lo(_fdintr_addr)]
|
||||
mov 0x3, Tmp
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
b L300
|
||||
st Tmp, [Ptr + %lo(_fdintr_opmode)] !!
|
||||
/*******************************/
|
||||
|
||||
/*
|
||||
* case 2:
|
||||
* recalibrate/seek - no result phase, must do sense interrupt status
|
||||
*/
|
||||
/* sense_int_stat: */
|
||||
L210: ldub [Fdc], Tmp ! Tmp = *csr
|
||||
L220: andcc Tmp, CB, Tmp ! is CB set?
|
||||
bne L220 ! yes, keep waiting
|
||||
ldub [Fdc], Tmp !! Tmp = *csr
|
||||
|
||||
/* wait!!! should we check rqm first??? ABSOLUTELY YES!!!! */
|
||||
L230: ldub [Fdc], Tmp ! busy wait until RQM set
|
||||
andcc Tmp, RQM, Tmp
|
||||
be L230 ! branch if bit clear
|
||||
nop
|
||||
mov 0x8, Tmp ! cmd for SENSE_INTERRUPT_STATUS
|
||||
stb Tmp, [Fdc + 0x1]
|
||||
|
||||
/* NOTE: we ignore DIO here, assume it is set before RQM! */
|
||||
L240: ldub [Fdc], Tmp ! busy wait until RQM set
|
||||
andcc Tmp, RQM, Tmp
|
||||
be L240 ! branch if bit clear
|
||||
nop
|
||||
|
||||
! fdintr_statbuf[0] = *fifo;
|
||||
ldub [Fdc + 0x1], Tmp
|
||||
sethi %hi(_fdintr_statbuf), Ptr
|
||||
stb Tmp, [Ptr + %lo(_fdintr_statbuf)]
|
||||
|
||||
L260: ldub [Fdc], Tmp ! busy wait until RQM set
|
||||
andcc Tmp, RQM, Tmp
|
||||
be L260 ! branch if bit clear
|
||||
nop
|
||||
|
||||
/* fdintr_statbuf[1] = *fifo; */
|
||||
ldub [Fdc + 0x1], Tmp
|
||||
sethi %hi(_fdintr_statbuf + 0x1), Ptr
|
||||
b L400
|
||||
stb Tmp, [Ptr + %lo(_fdintr_statbuf + 0x1)] !!
|
||||
|
||||
|
||||
/*
|
||||
* case 3: result mode
|
||||
* are in result mode make sure all status bytes are read out
|
||||
*/
|
||||
L300: sethi %hi(_fdintr_statp), Adr ! &statp in Adr
|
||||
ld [Adr + %lo(_fdintr_statp)], Ptr ! statp is Ptr
|
||||
sethi %hi(_fdintr_statbuf+10), Len ! Len is limit for status bytes
|
||||
or Len, %lo(_fdintr_statbuf+10), Len
|
||||
ldub [Fdc], Tmp !
|
||||
L340: andcc Tmp, CB, %g0 ! is CB set?
|
||||
be L320 ! no, jump around, must be fini
|
||||
nop
|
||||
! are *both* RQM and DIO set?
|
||||
andcc Tmp, RQM, %g0
|
||||
be L330
|
||||
nop
|
||||
andcc Tmp, DIO, %g0
|
||||
be L330
|
||||
nop
|
||||
ldub [Fdc + 0x1], Tmp ! *fifo into Tmp
|
||||
stb Tmp, [Ptr]
|
||||
! check to see if status buffer ptr is at/past limit
|
||||
/*XXX limits? */
|
||||
cmp Ptr, Len
|
||||
bge L330 ! if past, don't increment!
|
||||
nop
|
||||
add Ptr, 0x1, Ptr ! statp++ in Ptr
|
||||
L330: b L340 ! back to while( *Fdc & CB )
|
||||
ldub [Fdc], Tmp !
|
||||
|
||||
L320: ! stash updated statp and go to notify
|
||||
b L400
|
||||
st Ptr, [Adr + %lo(_fdintr_statp)] !!
|
||||
|
||||
|
||||
/* notify: */ /* set bit in software interrupt register */
|
||||
L400: /* *(uchar *)INTREG_ADDR |= IR_SOFT_INT4 */
|
||||
#ifndef sun4m
|
||||
sethi %hi(INTREG_ADDR), Ptr
|
||||
ldub [Ptr + %lo(INTREG_ADDR)], Tmp
|
||||
or Tmp, IR_SOFT_INT4, Tmp
|
||||
stb Tmp, [Ptr + %lo(INTREG_ADDR)]
|
||||
#else sun4m
|
||||
/*
|
||||
* set a pending level 4 software interrupt
|
||||
* we are probably going to be the master,
|
||||
* and if we are not then it will be vectored
|
||||
* to the proper master.
|
||||
*/
|
||||
GETCPU(Tmp) ! get module id, 8..11
|
||||
and Tmp, 3, Tmp ! mask to 0..3
|
||||
sll Tmp, 12, Tmp ! shift for +0x1000 per mid
|
||||
set V_INT_REGS, Ptr
|
||||
add Ptr, Tmp, Ptr ! calculate location of OUR int reg
|
||||
set IR_SOFT_INT4, Tmp
|
||||
st Tmp, [Ptr+8] ! send the softint
|
||||
#endif sun4m
|
||||
|
||||
/* opmode = 4; status = 0; */
|
||||
mov 0x4, Tmp
|
||||
sethi %hi(_fdintr_opmode), Ptr
|
||||
st Tmp, [Ptr + %lo(_fdintr_opmode)]
|
||||
mov 0x0, Tmp
|
||||
sethi %hi(_fdintr_status), Ptr
|
||||
st Tmp, [Ptr + %lo(_fdintr_status)]
|
||||
|
||||
/* out: */
|
||||
L9000:
|
||||
#ifdef MEASURE_TIME
|
||||
/* END: clear the LED */
|
||||
sethi %hi(AUXIO_REG), Ptr
|
||||
ldub [Ptr + %lo(AUXIO_REG)], Tmp
|
||||
and Tmp, ~AUX_LED, Tmp
|
||||
or Tmp, AUX_MBO, Tmp
|
||||
stb Tmp, [Ptr + %lo(AUXIO_REG)]
|
||||
#endif MEASURE_TIME
|
||||
ret
|
||||
restore
|
||||
.empty
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef I82077
|
||||
/*
|
||||
* Turn on or off bits in the digital output register.
|
||||
*
|
||||
* fd_set_dor(bit, flag)
|
||||
* int bit; bit mask in the dor
|
||||
* int flag; 0 = off, otherwise on
|
||||
*/
|
||||
ENTRY(fd_set_dor)
|
||||
|
||||
tst %o1
|
||||
set _fd_dor, %o2 ! get address of address of dor
|
||||
ld [%o2], %o2 ! get address of dor
|
||||
ldub [%o2], %g1 ! read dor
|
||||
bnz,a 1f
|
||||
bset %o0, %g1 ! on
|
||||
bclr %o0, %g1 ! off
|
||||
1:
|
||||
stb %g1, [%o2] ! write dor
|
||||
|
||||
retl
|
||||
nop
|
||||
#endif I82077
|
||||
Reference in New Issue
Block a user