!spear
! SPEAR: LANCE emulator
! RWT January 1985
! The purpose of this module is to provide the same low-level
! interface to the CSD142 2MHz Ethernet controller ("SPEAR")
! as is provided by the Am7990 10MHz controller ("LANCE").
! The level of interface provided is that of access to the
! LANCE (or SPEAR) Control/Status Registers.
! For LANCE emulation of SPEAR to be possible, the access
! has to be procedural: a function to read a CSR, and a
! routine to write to a CSR.
include "lance.inc"
option "-low-nodiag-noline-nocheck"
! LANCE interface
@16_fe0000 half lance address port
@16_fe0004 half lance data port
ownhalf lance register = 9999
externalintegerfn lance read csr(half which)
unless lance register = which start
lance address port = which
lance register = which
finish
result = lance data port
end
externalroutine lance write csr(half which,value)
unless lance register = which start
lance address port = which
lance register = which
finish
lance data port = value
end
! SPEAR INTERFACE
ownhalfarray csr(0:3) = c stop, 0, 0, bswp {The four CSRs
ownrecord (ibf)name ib {Pointer to Init Block
ownrecord (drf)name rdr,tdr {Pointers to descriptor rings
ownrecord (df)name rd,td {Pointers to current descriptors
ownhalf rdn = 0, tdn = 0 {Index (0:127) of current descs
ownhalf r mask = 0, t mask = 0 {Number of descs in ring minus one
owninteger old vector = 0
@16_1070 integer hardware vector {IPL=4: physical 2M ether device
{IPL=3: physical 10M ether device
@16_ff5fff byte spear interrupt {IPL=2: virtual 2M ether device
routinespec write csr0(integer value)
routinespec install interrupt handler
routinespec remove interrupt handler
externalintegerfn spear read csr(integer which)
result = csr(which&3)
end
externalroutine spear write csr(integer which,value)
which = which&3
if which#0 start
returnif csr(0) & c stop = 0
csr(which) = value unless csr(0)&c stop#0
else
write csr0(value)
finish
end
! INTERNAL WORKINGS START HERE
@16_010f8 routine ether open(integer port,remote)
@16_03fa8 byte ether ldte,ether lsap,ether rdte,ether rsap
@16_7fffc byte ether status
@16_7fffd byte ether data
@16_7ffff byte ether control
constbyte c
ether reset = 16_40,
ether tbe = 8,
ether drf = 4,
ether crf = 2,
ether rrf = 1,
ether rdy = 16_10,
ether stx = 16_20,
ether dtx = 16_30,
ether ack = 16_c0,
ether etx = 16_0b,
ether transparent = 2
routine ether twait
cycle ; repeatuntil etherstatusðertbe#0
end
integerfn ether dread
cycle ; repeatuntil etherstatusðerdrf#0
result = etherdata
end
integerfn ether cread
cycle ; repeatuntil etherstatusðercrf#0
result = ethercontrol
end
consthalf c
implicit clear = c err ! c intr,
explicit clear = c babl ! c cerr ! c miss ! c merr ! c rint ! c tint ! c idon,
explicit copy = c inea,
explicit set = c tdmd ! c stop ! c strt ! c init,
errors = c babl ! c cerr ! c miss ! c merr,
interrupts = c babl ! c miss ! c merr ! c rint ! c tint ! c idon
routinespec csrset(integer flags)
routine writecsr0(integer value)
csr(0) = csr(0) c
& ¬(value & explicit clear ! implicit clear ! explicit copy) c
! value & (explicit set ! explicit copy)
if value & c stop#0 start {Overrides everything else
ether status = ether reset
remove interrupt handler
csr(0) = c stop
ether status = ether crf ! ether drf
ether open(ether lsap, ether rdte <<8! ether rsap)
return
finish
if csr(0) & c init # 0 start
ether status = ether reset
csr(0) = csr(0) &¬ c stop
ib == record(csr(2)<<16+csr(1))
rmask = 1<<(ib_rcount>>3)-1
rdr == record(ib_highrad<<16+ib_lowrad)
rdn = 0; rd == rdr_desc(rdn)
tmask = 1<<(ib_tcount>>3)-1
tdr == record(ib_hightad<<16+ib_lowtad)
tdn = 0; td == tdr_desc(tdn)
ether status = 0
ether twait
ether control = ether transparent
ether twait
install interrupt handler
csr(0) = csr(0) &¬ c rxon unless ib_mode & m drx = 0
csr(0) = csr(0) &¬ c txon unless ib_mode & m dtx = 0
csr(0) = csr(0) ! c idon
finish
if csr(0) & c strt # 0 start
csr(0) = csr(0) ! c rxon if ib_mode & m drx = 0
csr(0) = csr(0) ! c txon ! c tdmd if ib_mode & m dtx = 0
finish
if csr(0) & c tdmd # 0 start
ether status = ether crf ! ether tbe
finish
csrset(0)
end
routine remove interrupt handler
hardware vector = old vector unless old vector = 0
old vector = 0
end
routine install interrupt handler
option "-low-nodiag-noline-nocheck"
label entry point
ownrecord (df)name nextdesc
ownbyte dump,char
ownhalf quota
routinespec fill buffer(record (df)name d)
routinespec empty buffer(record (df)name d)
returnunless old vector = 0
old vector = hardware vector
*lea entry point,a0
*move.l a4,-4(a0)
*move.l a0,hardware vector
return
*=0; *=0 {space for own base (A4)
entry point:
*movem.l d0-d1/d4/a0/a4,-(sp)
*lea entry point,a4
*move.l -4(a4),a4
*clr.l d4
*temp d0/d1/d4/a0
if ether status & ether crf # 0 start
char = ether control
dump = ether dread
if char = ether dtx start
ether twait; ether control = ether rdy
ether twait; ether data = 0
elseif char = ether stx
if csr(0) & c rxon = 0 start
fill buffer(nil)
elseif rd_control & r own = 0
fill buffer(nil)
csrset(c miss)
else
rd_control = rd_control ! r stp
cycle
fill buffer(rd)
exitif rd_control & r enp # 0
rdn = (rdn+1)&rmask
nextdesc == rdr_desc(rdn)
if nextdesc_control & r own = 0 start
rd_control = (rd_control ! r buff ! r oflo) &¬ r own
rd == nextdesc
exit
finish
rd == nextdesc
repeat
rd_control = rd_control &¬ r own
csrset(c rint)
finish
elseif char = ether rdy
ether twait; ether control = ether stx
ether twait; ether data = 0
quota = 512+20+14
cycle
empty buffer(td)
exitif td_control & t enp # 0
tdn = (tdn+1)&tmask
nextdesc == tdr_desc(tdn)
if nextdesc_control & t own = 0 start
td_plus = d buff ! d uflo
td_control = td_control ! t err
td == nextdesc
exit
finish
td == nextdesc
repeatuntil csr(0) & (c babl ! c inea) = c babl ! c inea
ether twait; ether control = ether etx
td_control = td_control &¬ t own
csrset(c tint)
elseif char = ether ack
if td_control & (t own ! t stp) = t own ! t stp start
ether twait; ether control = ether dtx
ether twait; ether data = 0
finish
finish
elseif csr(0) & c tdmd # 0
ether status = ether crf
if td_control & (t own ! t stp) = t own ! t stp start
ether twait; ether control = ether dtx
ether twait; ether data = 0
finish
finish
ether status = ether crf
*movem.l (sp)+,d0-d1/d4/a0/a4
*rte
routine fill buffer(record (df)name d)
half i,j
integer p
if d==nil start
cycle
if ether status & ether crf # 0 start
i = ether control; return
finish
if ether status & ether drf # 0 start
i = ether data
finish
repeat
finish
i = d_minus; j = 0
p = d_highad<<16+d_lowad
cycle
if ether status & ether crf # 0 start
d_plus = j; d_control = d_control ! t enp
i = ether control
return
finish
if ether status & ether drf # 0 start
if i=0 start
d_plus = j; return
finish
i = i+1; j = j+1; byteinteger(p) = ether data; p = p+1
finish
repeat
end
routine empty buffer(record (df)name d)
half i
integer p
i = d_minus
p = d_highad<<16+d_lowad
while i#0 cycle
i = i+1; quota = quota+1
if quota=0 start
csrset(c babl)
returnif csr(0) & c inea # 0
finish
ether twait; ether data = byteinteger(p); p = p+1
repeat
end
end
routine csrset(integer flags)
*temp d0/d1/d4/a0 {NB called from interrupt handler
csr(0) = csr(0) ! flags
csr(0) = csr(0) ! c err if csr(0) & errors # 0
csr(0) = csr(0) ! c intr if csr(0) & interrupts # 0
returnunless csr(0) & (c intr ! c inea) = (c intr ! c inea)
spear interrupt = 255
end