mirror of
https://github.com/PDP-10/its.git
synced 2026-03-06 11:23:32 +00:00
540 lines
12 KiB
Groff
Executable File
540 lines
12 KiB
Groff
Executable File
;;; General info and instructions for the config file:
|
||
;;; This uses 3com buffers 10. for receive and 11. for xmit. This
|
||
;;; corresponds to addresses [150000-154000) and [154000-160000)
|
||
;;; respectively.
|
||
;;; Therefore, free memory may not be greater than 150000.
|
||
|
||
.lif z %defin
|
||
.title 3com Ethernet Driver
|
||
.sbttl 3com Ethernet Driver: Definitions, Macros and Code
|
||
|
||
.iif z %defin, .nlist ;don't list definitions and macros if not
|
||
;defining them
|
||
|
||
.if nz %defin ;only define symbols when we are supposed to
|
||
|
||
defnet 3cm ;declare 3com packet driver
|
||
|
||
.pkhrd < ;;; for packet transmit (received packet is copied)
|
||
..word $3cpdt,0 ;3com packet data
|
||
..word $3cpda,3 ;destination address
|
||
..word $3cpty,1 ;protocol type
|
||
>
|
||
|
||
.if p1
|
||
.sbttl -- Definitions
|
||
|
||
;;
|
||
;;;;;; Status and Control Registers
|
||
;;
|
||
|
||
3c.rcv==0 ;receive control
|
||
3c.xmt==2 ;transmit control
|
||
|
||
;;
|
||
;;;;;; receive control register bits
|
||
;;
|
||
|
||
3c%rdn==bit.07 ;[R ] receiver done
|
||
3c%rie==bit.06 ;[R/W] receiver interrupt enable
|
||
3c%rcl==bit.05 ;[ /W] receiver clear
|
||
3c%rsb==bit.04 ;[ /W] set receiver buffer number
|
||
3c%rbn==000017 ;[R/W] receiver buffer number
|
||
|
||
;;
|
||
;;;;;; xmit control register bits
|
||
;;
|
||
|
||
3c%jam==bit.15 ;[R ] xmitting packet was jammed
|
||
3c%jie==bit.14 ;[R/W] jam interrupt enable
|
||
3c%jcl==bit.13 ;[ /W] clear jam and retransmit
|
||
|
||
3c%clr==bit.08 ;[ W] clear entire board
|
||
|
||
3c%xdn==bit.07 ;[R ] transmitter done
|
||
3c%xie==bit.06 ;[R/W] transmitter interrupt enable
|
||
3c%xcl==bit.05 ;[ /W] transmitter clear
|
||
3c%xsb==bit.04 ;[ /W] set transmitter buffer number
|
||
3c%xbn==000017 ;[R/W] transmitter buffer number
|
||
|
||
;;
|
||
;;;;;; Extra Unibus bits in the receiver register
|
||
;;
|
||
.if z qbus ;;; if not qbus (i.e. unibus)
|
||
|
||
3c%ast==bit.14 ;[R/W] Step the address recognition loop
|
||
3c%aro==bit.13 ;[R/W] Set when using rom addrss recognition
|
||
3c%awc==bit.12 ;[R/W] address recognition memory write clock bit
|
||
3c%adr==-1-<17_8> ;[R/W] Various data (BIC mask)
|
||
|
||
.endc qbus
|
||
|
||
.endc p1
|
||
|
||
.sbttl -- Macros
|
||
|
||
n3com==0 ;no 3com boards yet
|
||
|
||
.macro 3com vec,csr,ethad0,ethad2,ethad4,chaddr
|
||
.iif nz n3com, .error WRONG-O, cons breath, can't define more than one 3com
|
||
.iif z n3com, 3cmnet==nnet ;base net object of first 3com board
|
||
.if p2
|
||
%%==.
|
||
.=3c$vec+<2*n3com>
|
||
.word vec
|
||
.=3c$csr+<2*n3com>
|
||
.word csr
|
||
.if nz qbus
|
||
.=3c$ad0+<2*n3com>
|
||
.byte ethad0
|
||
.=3c$ad2+<2*n3com>
|
||
.byte ethad2
|
||
.=3c$ad4+<2*n3com>
|
||
.byte ethad4
|
||
.endc qbus
|
||
.if nz ncpchs
|
||
.=3c$cha+<2*n3com>
|
||
.word chaddr
|
||
.endc
|
||
.=%%
|
||
.endc
|
||
n3com==n3com+1
|
||
nnet==nnet+1
|
||
.endm
|
||
|
||
.endc %defin
|
||
|
||
.iif z %defin, .list ;start listing again
|
||
|
||
.iif nz %defin, .nlist ;don't list code if only doing definitions
|
||
|
||
.if z %defin ;only do code if not defining symbols
|
||
|
||
.sbttl -- Code
|
||
|
||
.iif z net3cm, .error 3com being included without support in PKTNCP
|
||
|
||
;;
|
||
;;;;;; Tables
|
||
;;
|
||
|
||
3c$vec: .blkw n3com ;table of interrupt vector addresses
|
||
3c$csr: .blkw n3com ;table of control/status base addresses
|
||
.if nz qbus
|
||
3c$ad0: .blkw n3com ;high 16 bits of ethernet address
|
||
3c$ad2: .blkw n3com ;middle 16 bits of ethernet address
|
||
3c$ad4: .blkw n3com ;low 16 bits of ethernet address
|
||
.endc qbus
|
||
.if nz ncpchs
|
||
3c$cha: .blkw n3com ;CHAOS address of this interface
|
||
.endc
|
||
.if nz ncpip
|
||
3c$in1: .blkw n3com ;high word of internet address
|
||
3c$in2: .blkw n3com ;low word of internet address
|
||
.endc
|
||
|
||
;;
|
||
;;;;;; Interrupt vector pointers and such
|
||
;;
|
||
|
||
3c$brk:
|
||
.rept n3com
|
||
.lif z .rpcnt
|
||
3c$rbk::
|
||
jsr r5,@#3crint
|
||
.word netobj+<2*3cmnet>+<2*.rpcnt>
|
||
.lif z .rpcnt
|
||
3c$xbk::
|
||
jsr r5,@#3cxint
|
||
.word netobj+<2*3cmnet>+<2*.rpcnt>
|
||
.lif z .rpcnt
|
||
3c$jbk::
|
||
jsr r5,@#3cjint
|
||
.word netobj+<2*3cmnet>+<2*.rpcnt>
|
||
.endr
|
||
l3c$brk==<.-3c$brk>/n3com
|
||
|
||
3c$vrp: .rept n3com ;vector receive pointers
|
||
.word 3c$rbk+<l3c$brk*.rpcnt>
|
||
.endr
|
||
3c$vxp: .rept n3com ;vector xmit pointers
|
||
.word 3c$xbk+<l3c$brk*.rpcnt>
|
||
.endr
|
||
3c$vjp: .rept n3com ;vector jam pointers
|
||
.word 3c$jbk+<l3c$brk*.rpcnt>
|
||
.endr
|
||
|
||
;;
|
||
;;;;;; A 3com hardware object
|
||
;;
|
||
|
||
dsect <
|
||
.blkb l$nt ;a basic network object
|
||
$3ccsr==$ntcsr ;3com CSR in the net CSR
|
||
|
||
$3crba:: .blkw 1 ;receive buffer address
|
||
$3cxba:: .blkw 1 ;xmit buffer address
|
||
|
||
$3cdmn:: .blkw 1 ;daemon flags
|
||
%3crdn==040000 ;receiver is done
|
||
%3cxmt==004000 ;xmit in progress
|
||
%3cxpk==002000 ;xmit packets on the queue
|
||
|
||
$3crqu:: .blkb 1 ;receive queue byte operation
|
||
$3cxqu:: .blkb 1 ;xmit queue byte operation
|
||
|
||
>,l$3c
|
||
|
||
;;
|
||
;;;;;; Interrupt routines
|
||
;;
|
||
|
||
.wscalar $3ckik ;;; set when the daemon process needs kicking
|
||
|
||
3crint: mov @(r5),r5 ;get the hardware object
|
||
.if nz qbus ;assumes only one interface
|
||
loop < ;exit if ok
|
||
cmp 3cqad0,nt.eth+0(r5)
|
||
if eq,<
|
||
cmp 3cqad2,nt.eth+2(r5)
|
||
if eq,<
|
||
cmp 3cqad4,nt.eth+4(r5)
|
||
exitl eq
|
||
> >
|
||
else <
|
||
cmp 3cqad0,#-1
|
||
if eq,<
|
||
cmp 3cqad2,#-1
|
||
if eq,<
|
||
cmp 3cqad4,#-1
|
||
exitl eq
|
||
> > >
|
||
push r4
|
||
mov $3ccsr(r5),r4
|
||
call 3c$rcl
|
||
pop r4
|
||
br 10$
|
||
>
|
||
.endc qbus
|
||
bis #%3crdn,$3cdmn(r5) ;tell the daemon the receiver is done
|
||
mov $3ccsr(r5),r5 ;get the CSR
|
||
bicb #3c%rie,3c.rcv(r5) ;disable interrupts
|
||
mov #1,$3ckik ;kick the daemon for rcv
|
||
10$: pop r5
|
||
rti
|
||
|
||
3cxint: mov @(r5),r5 ;get the hardware object
|
||
bic #%3cxmt,$3cdmn(r5) ;xmitter no longer xmitting
|
||
netmet ou
|
||
mov $3ccsr(r5),r5
|
||
bis #3c%xcl,3c.xmt(r5)
|
||
mov #1,$3ckik ;kick the daemon for xmit
|
||
pop r5
|
||
rti
|
||
|
||
;;; this code does not do binary exponential backoff
|
||
3cjint: mov @(r5),r5 ;get hardware object
|
||
netmet ab ;count an abort
|
||
mov $3ccsr(r5),r5 ;get the CSR
|
||
bis #3c%jcl,3c.xmt(r5) ;retransmit
|
||
pop r5
|
||
rti
|
||
|
||
|
||
|
||
3c$dmn: loop <
|
||
clr $3ckik ;about to process everything
|
||
push #netobj+<2*3cmnet>
|
||
loop <
|
||
mov @(sp),r5 ;get hardware object
|
||
if ne,<
|
||
mov $3ccsr(r5),r4
|
||
bit #%3crdn,$3cdmn(r5) ;receiver done?
|
||
if ne,<call 3c$rcv> ;receive the packet
|
||
call 3c$xmt ;try and xmit
|
||
>
|
||
add #2,(sp)
|
||
cmp (sp),#netobj+<2*3cmnet>+<2*n3com>
|
||
rptl lo
|
||
>
|
||
pop * ;flush pointer
|
||
.regs #hng.ne,#$3ckik,#zero
|
||
.hang
|
||
rptl
|
||
>
|
||
|
||
|
||
3c$rcv: bic #%3crdn,$3cdmn(r5)
|
||
loop < ;easy way to exit
|
||
movb 3c.rcv(r4),r3 ;get the buffer
|
||
exitl pl ;nothing there
|
||
mov $3crba(r5),r3 ;get receiver buffer address
|
||
mov (r3),r1 ;get the offset to end
|
||
if mi,< ;checksum error
|
||
netmet cr ;indicate crc error
|
||
exitl
|
||
>
|
||
bic #mask11,r1 ;get only the real offset bits
|
||
cmp r1,#3777 ;was there a length error?
|
||
if eq,< ;length error on the net
|
||
netmet bl ;count it
|
||
exitl
|
||
>
|
||
sub #528.+4+<2*<3+3+1>>,r1 ;don't count extra 3com
|
||
;space, checksum bytes,
|
||
;or ethernet header
|
||
mov r1,r0 ;save data size
|
||
add #$pktdt,r1 ;add program header
|
||
cmp r1,#pksiz. ;is it big enough for anybody?
|
||
if lo,<netmet ot
|
||
exitl>
|
||
cmp r1,#pksiz$ ;too big?
|
||
if hi,<netmet ot
|
||
exitl>
|
||
call pktall ;get a packet
|
||
if eq,<netmet ot
|
||
exitl>
|
||
push r1 ;save pointer
|
||
add #$pktdt,r1 ;point to packet data
|
||
add #528.+<2*<3+3>>,r3 ;point at type word
|
||
inc r0 ;round up...
|
||
asr r0 ;...word count
|
||
mov (r3)+,r2 ;get type word
|
||
loop <
|
||
mov (r3)+,(r1)+
|
||
sorl r0
|
||
>
|
||
pop r1
|
||
bis #%pkt08,$pktfl(r1) ;declare packet safe for 8 bit
|
||
call 3c$rcl
|
||
jcall ethrcv ;receive an ethernet packet
|
||
>
|
||
3c$rcl: movb #3c%rcl,3c.rcv(r4) ;cycle the receiver fifo
|
||
movb $3crqu(r5),3c.rcv(r4) ;queue the receive packet
|
||
return
|
||
|
||
|
||
|
||
3c$xmt: loop < ;easy exit mechanism
|
||
bit #%3cxmt,$3cdmn(r5) ;xmit already in progress
|
||
exitl ne ;yes, don't do xmit
|
||
call ntremq ;get a packet
|
||
exitl eq ;nothing there
|
||
bis #%3cxmt,$3cdmn(r5) ;xmit now in progress
|
||
mov $3cxba(r5),r3 ;get pointer to base of 3com buffer
|
||
mov $pktxs(r1),r2 ;get xmit count
|
||
mov r2,r0
|
||
cmp r0,#60. ;must be at least 60 bytes
|
||
if lo,<mov #60.,r0>
|
||
neg r0
|
||
add #4000,r0 ;offset pointer
|
||
mov r0,(r3) ;set it for the hardware
|
||
add r0,r3 ;get to beginning of packet
|
||
push r1
|
||
add #$3cpdt,r1 ;point to packet data
|
||
|
||
mov (r1)+,(r3)+ ;stuff destination address
|
||
mov (r1)+,(r3)+
|
||
mov (r1)+,(r3)+
|
||
mov nt.eth+0(r5),(r3)+ ;stuff source address
|
||
mov nt.eth+2(r5),(r3)+
|
||
mov nt.eth+4(r5),(r3)+
|
||
mov (r1)+,(r3)+ ;stuff protocol type
|
||
|
||
sub #2*<3+3+1>,r2 ;count ethernet header words,
|
||
asr r2 ;to word count
|
||
loop <
|
||
mov (r1)+,(r3)+ ;copy
|
||
sorl r2
|
||
>
|
||
pop r1
|
||
movb $3cxqu(r5),3c.xmt(r4) ;queue the xmit packet
|
||
jcall pktngv ;free packet if not on user list
|
||
>
|
||
return
|
||
|
||
;;
|
||
;;;;;; Qbus/Unibus finish setup
|
||
;;
|
||
|
||
3c$set: clr $3cdmn(r5) ;no daemon functions
|
||
|
||
movb #10.+3c%rsb+3c%rie,$3crqu(r5) ;receive queue command
|
||
movb #11.+3c%xsb+3c%xie,$3cxqu(r5) ;xmit queue command
|
||
|
||
mov #<10.*2048.>+100000,$3crba(r5) ;receive buffer address
|
||
mov #<11.*2048.>+100000,$3cxba(r5) ;xmit buffer address
|
||
;;;--------------------*** initialize all of memory
|
||
.if z qbus ;for unibus
|
||
lock 7
|
||
push r0,@#114,@#116 ;save parity error trap
|
||
mov #120$,@#114
|
||
mov #pr7,@#116 ;setup the new
|
||
mov #100000,r0
|
||
mov #160000-100000,r1
|
||
loop <
|
||
movb (r0),(r0) ;frob the memory
|
||
inc r0
|
||
sorl r1
|
||
exitl
|
||
120$: clrb (r0)
|
||
rti
|
||
>
|
||
pop @#116,@#114,r0
|
||
unlock
|
||
.iff ;for qbus, doesn't need it
|
||
.endc
|
||
;;;--------------------*** setup for address recognition
|
||
.if z qbus ;for unibus
|
||
mov #3c%aro,3c.rcv(r4) ;use the ROM
|
||
call 200$ ;get a word
|
||
mov r1,nt.eth+0(r5) ;keep it
|
||
call 200$ ;the second one
|
||
mov r1,nt.eth+2(r5)
|
||
call 200$ ;the third (and last)
|
||
mov r1,nt.eth+4(r5)
|
||
loop < ;local subroutines
|
||
exitl
|
||
200$: push #0
|
||
mov #4,r1
|
||
loop <
|
||
clc
|
||
.rept 4
|
||
ror (sp)
|
||
.endr
|
||
mov 3c.rcv(r4),r2
|
||
bic #3c%adr,r2
|
||
ash #4,r2
|
||
bis r2,(sp)
|
||
call 220$
|
||
sorl r1
|
||
>
|
||
pop r1
|
||
return
|
||
220$: mov #3c%aro+3c%ast,r2 ;set to half step
|
||
mov #3c%aro,r3 ;clear to finish the step (sigh)
|
||
add #3c.rcv,r4
|
||
.rept 4 ;gross me out!!
|
||
mov r2,(r4)
|
||
mov r3,(r4)
|
||
.endr
|
||
sub #3c.rcv,r4
|
||
return
|
||
>
|
||
|
||
.rept 2 ;just to make sure
|
||
mov #3c%aro+<7_8>,3c.rcv(r4)
|
||
.endr
|
||
.iff ;for qbus
|
||
mov 3c$ad0(r0),nt.eth+0(r5)
|
||
mov 3c$ad2(r0),nt.eth+2(r5)
|
||
mov 3c$ad4(r0),nt.eth+4(r5)
|
||
|
||
3cqad0=100000+<10.*2048.>+528. ;destination address of recv packet
|
||
3cqad2=3cqad0+2
|
||
3cqad4=3cqad0+4
|
||
.endc
|
||
;;;--------------------*** arm the board
|
||
movb $3crqu(r5),3c.rcv(r4)
|
||
mov #3c%jie,3c.xmt(r4)
|
||
return
|
||
|
||
.wscalar $3cnup ;number of alive 3com boards
|
||
|
||
3cini: clr $3cnup
|
||
clr r0
|
||
loop <
|
||
call 3cinit
|
||
add #2,r0
|
||
cmp r0,#n3com*2
|
||
rptl lo
|
||
>
|
||
tst $3cnup
|
||
if ne,<
|
||
.regs #3c$dmn,#40,#100_8 ;start up the daemon
|
||
.usrgo
|
||
if cs,<bpt>
|
||
>
|
||
return
|
||
|
||
3cinit: mov 3c$csr(r0),r4
|
||
call nxmcat
|
||
3cmnxm
|
||
mov #3c%clr,3c.xmt(r4)
|
||
inc $3cnup
|
||
call nxmclr
|
||
|
||
mov 3c$vec(r0),r2
|
||
mov 3c$vrp(r0),(r2)+ ;receiver interrupt
|
||
mov #pr6,(r2)+ ;at priority 6
|
||
mov 3c$vjp(r0),(r2)+ ;jam interrupt
|
||
mov #pr5,(r2)+ ;at priority 5
|
||
mov 3c$vxp(r0),(r2)+ ;xmit complete interrupt
|
||
mov #pr4,(r2)+ ;at priority 4
|
||
|
||
mov #l$3c,r5 ;length of a hardware object
|
||
call ntmake ;make it
|
||
if eq,<bpt> ;oops
|
||
mov r5,netobj+<2*3cmnet>(r0) ;savve device in network table
|
||
mov r4,$ntcsr(r5)
|
||
|
||
call 3c$set ;setup the rest of the registers
|
||
mov #3cetgv,nt$eth(r5) ;routine to send ethernet packets to interface
|
||
|
||
.if nz ncpchs
|
||
mov #3cchgv,nt$chs(r5) ;routine to send chaos packets to interface
|
||
mov 3c$cha(r0),nt.chs(r5) ;my address on chaos net
|
||
mov #12.,$ctrcv(r5) ;3coms a little more expensive than standard
|
||
.endc
|
||
|
||
.if nz ncpip
|
||
.endc
|
||
|
||
mov r0,r4 ;get 3com index into r4
|
||
add #<3cmnet*2>,r4 ;now network index
|
||
jcall ntmak1 ;finish making the object
|
||
|
||
3cmnxm: clr netobj+<2*3cmnet>(r0) ;no network object
|
||
return
|
||
|
||
3cetgv: mov r0,$3cpty(r1)
|
||
mov r2,$3cpda+0(r1)
|
||
mov r3,$3cpda+2(r1)
|
||
mov r4,$3cpda+4(r1)
|
||
|
||
add #<2*<3+3+1>>+1,$pktxs(r1) ;add ethernet header and word rounding
|
||
bic #1,$pktxs(r1) ;now even byte count
|
||
mov #1,$3ckik ;kick the daemon
|
||
jcall ntputq
|
||
|
||
.if nz ncpchs
|
||
|
||
;;; call @nt$chs(r5),[r5:=object, r1:=packet, r2:=hardware_destination]
|
||
|
||
3cchgv: call cpks08 ;make packet safe for 8 bit hardware
|
||
|
||
push r0,r3,r4
|
||
mov #%etchs,r0 ;protocol in r0
|
||
call ethtrn
|
||
if cs,<call pktngv>
|
||
else <call 3cetgv>
|
||
pop r4,r3,r0
|
||
return
|
||
|
||
.endc ncpchs
|
||
****
|
||
|
||
$insrt 3com,kludge ;redefine symbols for the 11 simulator
|
||
|
||
.endc %defin
|
||
|
||
.iif nz %defin, .list ;start listing as usual
|
||
|
||
|
||
;; local modes:
|
||
;; mode:midas
|
||
;; auto fill mode:
|
||
;; fill column:75
|
||
;; comment column:32
|
||
;; end:
|