Files
Arquivotheca.SunOS-4.1.4/sys/sundev/zs_asm.s
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

322 lines
7.8 KiB
ArmAsm

/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
#include "assym.s"
#include <machine/asm_linkage.h>
#include <machine/mmu.h>
#include <machine/psl.h>
#include <sundev/zsreg.h>
#ifndef sun4 ************************************
.data
.asciz "@(#)zs_asm.s 1.1 94/10/31"
.even
.text
/*
* We come here for auto-vectored interrupts
* (All Sun-2s and the Sun-3 Model 25)
* We assume that the most recently interrupting
* chip is interrupting again and read the vector out of the
* chip and branch to the right routine. The "special receive"
* interrupt routine gets control if the assumption was wrong
* and performs the longer task of figuring out who is really interrupting
* and why.
*/
.globl zslevel6, _zscurr
zslevel6:
movl a1,sp@- | save a1
movl a0,sp@- | save a0
movl _zscurr,a0 | get most active channel desc
movl a0@(ZS_ADDR),a1 | get hardware channel addr
movb #2,a1@ | read from reg 2 in channel B
/* we need at least 1.6 usec recovery time between here ... */
movl d1,sp@- | recovery time - save d1, d0
movl d0,sp@- | recovery time - save d1, d0
#ifdef sun3
nop; nop; nop; nop; nop; nop | additional recovery time
#endif sun3
/* ... and here */
movb a1@,d0
btst #3,d0 | channel A?
beq 1f | no, skip
subw #ZSSIZE,a0 | point to channel A
1: andw #6,d0 | get vector bits
addw d0,d0 | get multiple of 4
pea a0@ | push argument
movl a0@(0,d0:w),a0 | get routine address
jsr a0@ | call routine
movl sp@+,a0 | pop argument
movl a0@(ZS_ADDR),a1 | get hardware channel addr
movb #ZSWR0_CLR_INTR,a1@ | reset interrupt
moveml sp@+,#0x0303 | restore all saved regs
addql #1,_cnt+V_INTR | increment io interrupt count
rte | and return!
#ifdef sun3
/*
* Vector stubs for SCCs
* Each SCC requires 8 vectors - 4 for each channel, channel B before channel A
*/
.globl _zscom
#define ZSSTUB(chip,chan,src) \
zsv/**/chip/**/chan/**/src: \
zs/**/chip/**/chan/**/src = ZSSIZE*(chip*2+chan); \
zv/**/chip/**/chan/**/src = ZSSIZE*(chip*2+chan)+(4*src); \
moveml #0xC0C0,sp@-; \
pea _zscom+zs/**/chip/**/chan/**/src; \
movl _zscom+zv/**/chip/**/chan/**/src,a0; \
jsr a0@; \
addql #4,sp; \
movl _zscom+zs/**/chip/**/chan/**/src+ZS_ADDR,a1; \
movb #ZSWR0_CLR_INTR,a1@; \
moveml sp@+,#0x0303; \
addql #1,_cnt+V_INTR; \
rte; \
.data; \
.long zsv/**/chip/**/chan/**/src; \
.text
.data
.globl _zsvectab
_zsvectab:
.text
#include "zs.h"
#if NZS > 0
ZSSTUB(0,1,0); ZSSTUB(0,1,1); ZSSTUB(0,1,2); ZSSTUB(0,1,3);
ZSSTUB(0,0,0); ZSSTUB(0,0,1); ZSSTUB(0,0,2); ZSSTUB(0,0,3);
#endif
#if NZS > 1
ZSSTUB(1,1,0); ZSSTUB(1,1,1); ZSSTUB(1,1,2); ZSSTUB(1,1,3);
ZSSTUB(1,0,0); ZSSTUB(1,0,1); ZSSTUB(1,0,2); ZSSTUB(1,0,3);
#endif
#if NZS > 2
ZSSTUB(2,1,0); ZSSTUB(2,1,1); ZSSTUB(2,1,2); ZSSTUB(2,1,3);
ZSSTUB(2,0,0); ZSSTUB(2,0,1); ZSSTUB(2,0,2); ZSSTUB(2,0,3);
#endif
#if NZS > 3
ERROR - too many ZSs
#endif
#endif sun3
#ifdef sun3
#include <sun3/interreg.h>
/*
* Turn on a zs soft interrupt - Sun-3
*/
ENTRY(setzssoft)
bset #IR_SOFT_INT3_BIT,INTERREG
rts
/*
* Test and clear a zs soft interrupt - Sun-3
*/
ENTRY(clrzssoft)
movl #0,d0
bclr #IR_SOFT_INT3_BIT,INTERREG
jeq 1f
movl #1,d0
1: rts
#endif sun3
#ifdef sun2
#include <sun2/enable.h>
ZSSOFTMASK = ENA_SOFT_INT_3
/*
* Turn on a zs soft interrupt - Sun-2
*/
ENTRY(setzssoft)
movc dfc,a1
movl #FC_MAP,d0 | set to address FC_MAP space
movc d0,dfc
1:
movl #ZSSOFTMASK,d0
orw d0,enablereg | enable the interrupt
movw enablereg,d0 | get it in a reg
movsw d0,ENABLEREG | put enable register back
cmpw enablereg,d0 | see if someone higher changed it
bne 1b | if so, try again
movc a1,dfc | restore dfc
rts
/*
* Test and clear a zs soft interrupt - Sun-2
*/
ENTRY(clrzssoft)
movw enablereg,d0
andl #ZSSOFTMASK,d0 | clear d0 if no intr
beq 2f
movc dfc,a1
movl #FC_MAP,d0 | set to address FC_MAP space
movc d0,dfc
1:
movl #~ZSSOFTMASK,d0
andw d0,enablereg | enable the interrupt
movw enablereg,d0 | get it in a reg
movsw d0,ENABLEREG | put enable register back
cmpw enablereg,d0 | see if someone higher changed it
bne 1b | if so, try again
movc a1,dfc | restore dfc
movl #1,d0 | return true
2:
rts
#endif sun2
/*
* Read a control register in the chip
*/
ENTRY(zszread)
movl sp@(4),a1 | chip address
movb sp@(0xb),a1@ | write register number
#ifdef sun3
moveq #20,d0 | DELAY(2)
movl _cpudelay,d1
asrl d1,d0
1: subql #1,d0
bgts 1b
#else
/* need 1.6 usec recovery here */
clrl d0
nop; nop; nop
/* that was actually 1.8 */
#endif sun3
movb a1@,d0 | get returned register
rts
/*
* Write a control register in the chip
*/
ENTRY(zszwrite)
movl sp@(4),a1 | chip address
movb sp@(0xb),a1@ | write register number
#ifdef sun3
moveq #20,d0 | DELAY(2)
movl _cpudelay,d1
asrl d1,d0
1: subql #1,d0
bgts 1b
#else
/* 1.6 usec recovery plus slop for buffered video writes */
nop; nop; nop; nop; nop
#endif sun3
movb sp@(0xf),a1@ | write data
rts
#else sun4 ************************************
.seg "data"
.asciz "@(#)zs_asm.s 1.7 86/04/15"
.align 4
.seg "text"
#include <sun4/intreg.h>
/* 1.6 usec UART recovery time. XXX clock dependent. */
#define ZSRECOVER() \
mov 9, %o5; \
0: deccc %o5; \
bnz 0b; \
nop;
/*
* We come here for auto-vectored interrupts
* We assume that the most recently interrupting
* chip is interrupting again and read the vector out of the
* chip and branch to the right routine. The "special receive"
* interrupt routine gets control if the assumption was wrong
* and performs the longer task of figuring out who is really interrupting
* and why.
*/
.global _zscurr
ENTRY(zslevel12)
save %sp, -SA(MINFRAME), %sp ! get a new window
set _zscurr, %g1 ! most active channel desc pointer
ld [%g1], %l0 ! read it
mov 2, %g2 ! register number 2 in channel B
ld [%l0 + ZS_ADDR], %l1 ! get address of hardware channel
stb %g2, [%l1] ! set register to read
ZSRECOVER();
ldub [%l1], %l2 ! get interrupt vector number
ZSRECOVER();
btst 8, %l2 ! channel A?
bnz,a 1f ! if not anull next instruction
sub %l0, ZSSIZE, %l0 ! point to channel A's descriptor
1:
and %l2, 6, %l2 ! get vetor bits
add %l2, %l2, %l2 ! get multiple of 4
ld [%l0 + %l2], %g1 ! get address of routine to call
call %g1 ! go to it
mov %l0, %o0 ! delay slot, fix argument
ld [%l0 + ZS_ADDR], %l1 ! get address of hardware channel
mov ZSWR0_CLR_INTR, %g2 ! value to clear interrupt
stb %g2, [%l1] ! clear interrupt
ZSRECOVER();
ret
restore
/*
* Turn on a zs soft interrupt.
*/
ENTRY(setzssoft)
mov %psr, %g2
or %g2, PSR_PIL, %g1 ! spl hi to protect intreg update
mov %g1, %psr
nop; nop; ! psr delay
set INTREG_ADDR, %o0 ! set address of interrupt register
ldub [%o0], %o1 ! read it
bset IR_SOFT_INT6, %o1 ! set zs soft interrupt bit
stb %o1, [%o0] ! write it out
mov %g2, %psr ! restore psr
nop ! psr delay
retl ! leaf routine return
nop
/*
* Test and clear a zs soft interrupt.
*/
ENTRY(clrzssoft)
set INTREG_ADDR, %o1 ! set address of interrupt register
ldub [%o1], %o2 ! read it
btst IR_SOFT_INT6, %o2 ! was there an interrupt pending?
bz,a 1f ! no, simply return 0
mov 0, %o0 ! return value
mov %psr, %g2
or %g2, PSR_PIL, %g1 ! spl hi to protect intreg update
mov %g1, %psr
nop; nop; ! psr delay
mov 1, %o0 ! otherwise one was pending
ldub [%o1], %o2 ! read it
bclr IR_SOFT_INT6, %o2 ! clear zs soft int bit
stb %o2, [%o1] ! write interrupt register
mov %g2, %psr ! restore psr
nop ! psr delay
1:
retl
nop
/*
* Read a control register in the chip
*/
ENTRY(zszread)
stb %o1, [%o0] ! write register number
ZSRECOVER();
ldub [%o0], %o0 ! read register
ZSRECOVER();
retl
nop
/*
* Write a control register in the chip
*/
ENTRY(zszwrite)
stb %o1, [%o0] ! write register number
ZSRECOVER();
stb %o2, [%o0] ! write data
ZSRECOVER();
retl
nop
#endif !sun4 *************************************