mirror of
https://github.com/PDP-10/its.git
synced 2026-04-17 08:51:08 +00:00
446 lines
12 KiB
Plaintext
Executable File
446 lines
12 KiB
Plaintext
Executable File
|
||
.lif z %defin
|
||
.title CHAOS-11 support
|
||
.sbttl CHAOS-11 support: 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 c11 ;declare running with Chaos-11 hardware
|
||
|
||
.pkhrd < ;; needed packet fields for hardware
|
||
..word $c1hrd,1 ;hardware destination
|
||
>
|
||
|
||
.if p1
|
||
.sbttl -- Definitions
|
||
|
||
|
||
;;
|
||
;;;;;; hardware definitions for the chaos-11 hardware
|
||
;;
|
||
|
||
CH.CSR==0 ;OFFSET OF COMMAND STATE REG FROM THE BASE ADDRESS
|
||
%CATIE==1 ;0 FORMERLY XMT BUSY NOW QUAD TIMER INTERRUPT ENABLE (R/W)
|
||
%CALPBK==2 ;1 LOOP BACK MODE (DOESN'T USE CABLE WHEN ON) (R/W)
|
||
%CASPY==4 ;2 RECIEVE MSGS FOR ANY DESTINATION (R/W)
|
||
%CARCL==10 ;3 CLEAR THE RECEIVER. WRITING A 1 CLEARS RCV DONE
|
||
; AND ENABLES THE RECEIVER TO GOBBLE ANOTHER MESSAGE (WO)
|
||
%CAREN==20 ;4 RCV INT ENB (R/W)
|
||
%CATEN==40 ;5 XMT INT ENB (R/W)
|
||
%CATAB==100 ;6 TRANSMIT ABORTED BY ETHER CONFLICT (RO)
|
||
%CATDN==200 ;7 TRANSMIT DONE. SET WHEN TRANSMITTER IS DONE
|
||
%CATCL==400 ;8 CLEAR THE TRANSMITTER MAKING IT READY (WO)
|
||
;9-12 LOST COUNT (RO) [# MSGS RCVED WITH RCV BFR FULL]
|
||
; WHEN MSG IS WAITING IN BUFFER, THIS COUNTS
|
||
; THE MESSAGES THAT MATCHED OUR DESTINATION OR
|
||
; WERE BROADCAST, BUT COULDN'T BE RECIEVED.
|
||
; WHEN RECEIVER IS RE-ENABLED (WRITE 1 INTO %CARDN)
|
||
; THE COUNT IS THEN CLEARED.
|
||
; WHEN A MESSAGE IS LOST, RECEIVER ZAPS ETHER
|
||
; SO TRANSMITTER WILL ABORT (IF MESSAGE WAS DESTINED
|
||
; TO US.)
|
||
%CARST==20000 ;13 I/O RESET (WO)
|
||
%CAERR==40000 ;14 CRC ERROR (RO)
|
||
%CARDN==100000 ;15 RCV DONE.
|
||
|
||
CH.MYN==2 ;OFFSET OF MY # (READ ONLY)
|
||
;RETURNS THE [SOURCE] HOST# OF THIS INTERFACE.
|
||
CH.NET==3 ;OFFSET FOR READING SUBNET #
|
||
|
||
CH.WBF==2 ;OFFSET OF WRITE BUFFER (WRITE ONLY)
|
||
;FIRST WAIT FOR TDONE. (OR SET IT VIA CSR)
|
||
;FIRST WORD IN RESETS TRANSMITTER AND CLEARS TDONE.
|
||
;STORE INTO THIS REGISTER TO WRITE WORDS OF MESSAGE,
|
||
;LAST WORD IN IS DESTINATION ADDRESS, THEN READ CAIXMT.
|
||
;SOURCE ADDRESS AND CHECK WORD PUT IN BY HARDWARE.
|
||
|
||
CH.RBF==4 ;OFFSET OF READ BUFFER (READ ONLY)
|
||
;THE FIRST WORD READ WILL BE FILLED TO THE LEFT
|
||
;TO MAKE THE MESSAGE RECIEVED A MULTIPLE OF 16 BITS.
|
||
;IF THE NUMBER OF DATA BITS IN THE MESSAGE WAS A
|
||
;MULTIPLE OF 16, THIS WORD WILL BE THE FIRST WORD PUT
|
||
;INTO THE BUFFER BY THE TRANSMITTING HOST.
|
||
;THE LAST 3 WORDS READ ARE DESTINATION, SOURCE, CHECK.
|
||
|
||
CH.RBC==6 ;OFFSET OF RECEIVE BIT COUNTER (READ ONLY)
|
||
;WHEN A MESSAGE HAS BEEN RECEIVED THIS IS ONE LESS THAN
|
||
;THE NUMBER OF BITS IN THE MESSAGE (16 X THE
|
||
;NUMBER OF WORDS INCLUDING THE THREE OVERHEAD WORDS.)
|
||
;AFTER THE LAST WORD (THE CRC WORD) HAS BEEN READ, IT IS 7777
|
||
;BITS 10 AND 11 ARE THE HIGH ORDER BITS, AND IF THEY ARE ONE,
|
||
;THEN THERE WAS A BUFFER OVERFLOW
|
||
|
||
;NOTE: FOR THE Q-BUS VERSION OF THE INTERFACE (FOR LSI-11'S)
|
||
;WRITING CAIMYN INTO CAIRBC INITIATES TRANSMISSION.
|
||
|
||
CH.XMT==12 ;READING THIS OFFSET INITIATES TRANSMISSION (!!)
|
||
;THE VALUE READ IS ONE'S OWN HOST#.
|
||
;**** NOTE COMMENT ABOVE UNDER CAIRBF FOR LSI-11'S ****
|
||
|
||
CH.TMR==20 ;OFFSET OF INTERVAL TIMER
|
||
|
||
%c1max==16.+488. ;largest hardware packet size
|
||
|
||
.endc p1
|
||
|
||
****
|
||
.sbttl -- Macros
|
||
****
|
||
|
||
nch11==0 ;no CH11s to start with
|
||
|
||
.macro ch11 vec,csr,roudem,slow
|
||
.iif z nch11, c11net==nnet ;base net object of chaos-11 network objects
|
||
.if p2
|
||
%%==.
|
||
.=c1$vec+<2*nch11>
|
||
.word vec
|
||
.=c1$csr+<2*nch11>
|
||
.word csr
|
||
.=c1$cst+<2*nch11>
|
||
.word 11.+0'roudem
|
||
.=c1$slo+<2*nch11>
|
||
.word 0'slow
|
||
.=%%
|
||
.endc
|
||
nch11==nch11+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 netc11, .error CHAOS-11 being included without support in PKTNCP
|
||
|
||
;;
|
||
;;;;;; Tables and pointers
|
||
;;
|
||
|
||
c1$vec: .blkw nch11 ;table of interrupt vectors
|
||
c1$csr: .blkw nch11 ;table of control/status registers
|
||
c1$cst: .blkw nch11 ;table of routing cost
|
||
c1$slo: .blkw nch11 ;is this a slow interface?
|
||
|
||
c1$brk:
|
||
.rept nch11
|
||
jsr r5,@#c1int
|
||
.word netobj+<2*c11net>+<2*.rpcnt>
|
||
.endr
|
||
lc1$brk==<.-c1$brk>/nch11
|
||
|
||
c1$vad: ;addresses at the vectors
|
||
.rept nch11
|
||
.word c1$brk+<.rpcnt*lc1$brk>
|
||
.endr
|
||
|
||
;;
|
||
;;;;;; A hardware object
|
||
;;
|
||
|
||
dsect <
|
||
.blkb l$nt ;length of a standard network object
|
||
|
||
$c1lok:: .blkw 1 ;device service lock
|
||
$c1run:: .blkw 1 ;keep the process running flag
|
||
$c1sup:: .blkw 1 ;bits that are "supposed" to be on
|
||
$c1xla:: .blkw 1 ;alst one sent (for aborts)
|
||
$c1xna:: .blkw 1 ;number of aborts for the current packet
|
||
$c1slo:: .blkw 1 ;is this a slow interface
|
||
>,l$c11
|
||
|
||
|
||
;;; The CHAOS-11 interrupt vector points to a JSR R5,@#C1INT. This
|
||
;;; pushes r5 on the stack and leaves r5 pointing to a pointer to the
|
||
;;; object. Therefore the object can be obtained by mov @(r5),r5.
|
||
;;; Note that this does not do anything with a packet; all packet
|
||
;;; frobing for this device is done at program level. The only thing
|
||
;;; this does is turn off interrupts and kick the service process.
|
||
|
||
c1int: mov @(r5),r5 ;pick up the object
|
||
push @$ntcsr(r5) ;get the CSR value on the stack
|
||
bic #-1-<%caten+%caren>,(sp) ;get only int enable bits
|
||
bis (sp)+,$c1sup(r5) ;and say we should restore those
|
||
bic #%caten+%caren,@$ntcsr(r5) ;turn off all interrupts
|
||
mov #1,$c1run(r5) ;tell the service routine to keep running
|
||
inc $c1lok(r5) ;try to grab the lock
|
||
if eq,<
|
||
mtps 4(sp) ;restore previous interrupt priority (under
|
||
;r5 and address)
|
||
.intstk < ;on the interrupt stack
|
||
call c1$int ;service this interface
|
||
> >
|
||
dec $c1lok(r5) ;release the lock
|
||
pop r5 ;restore reg
|
||
rti ;and conclude interrupt
|
||
|
||
|
||
;;; This is the routine that actually frobs the packets in and out of
|
||
;;; the CHAOS-11 hardware. All registers except r5 must be saved before
|
||
;;; using.
|
||
|
||
;;; registers:
|
||
;;; r5 base of hardware object
|
||
;;; r4 CSR address (not set up on entry)
|
||
|
||
c1$int: push r4,r3,r2,r1,r0 ;save entire register set (r5 known to be bashable)
|
||
mov $ntcsr(r5),r4 ;get CSR address
|
||
loop <
|
||
lock 7 ;don't lose a wakeup
|
||
tst $c1run(r5) ;keep running?
|
||
if eq,<
|
||
pop * ;about to return, throw away old priority.
|
||
;A valid priority will get set by the RTI
|
||
;of the person that called us.
|
||
bis #%caren,$c1sup(r5) ;always enable receiver interrupts
|
||
bis $c1sup(r5),(r4) ;turn on other bits that are supposed to be on
|
||
pop r0,r1,r2,r3,r4 ;restore register set
|
||
return
|
||
>
|
||
unlock
|
||
clr $c1run(r5)
|
||
|
||
bit #%cardn,(r4) ;receiver done
|
||
if ne,<
|
||
call c1rint ;simulate a receiver interrupt
|
||
inc $c1run(r5) ;keep the process running
|
||
>
|
||
|
||
bit #%caten,$c1sup(r5) ;waiting for interrupt?
|
||
if ne,< ;yup
|
||
bit #%catdn,(r4) ;transmitter ready?
|
||
if ne,<
|
||
call c1xint ;go transmit it
|
||
inc $c1run(r5) ;keep the process running
|
||
> >
|
||
rptl ;keep looping
|
||
>
|
||
|
||
|
||
|
||
c1rint:
|
||
clr r1 ;no packet to start with
|
||
loop < ;allow for easy exit on error conditions
|
||
bit #%caerr,(r4) ;CRC error?
|
||
if ne,< netmet cr
|
||
exitl>
|
||
mov ch.rbc(r4),r3 ;get the bit count
|
||
inc r3 ;hardware doesn't count one
|
||
bit #17,r3 ;better be multiple of 16 bits
|
||
if ne,< netmet bl ;bad length
|
||
exitl>
|
||
ash #-3,r3 ;convert to bytes
|
||
sub #2*3,r3 ;don't count 3 hardware words
|
||
cmp r3,#<pksiz.-$pktdt> ;minimum size of all packets
|
||
if lo,< netmet ot ;other reason for rejecting
|
||
exitl>
|
||
.iif le %c1max-<pksiz$-$pktdt>, %%==%c1max
|
||
.iif le <pksiz$-$pktdt>-%c1max, %%==<pksiz$-$pktdt>
|
||
cmp r3,#%% ;range check the high end
|
||
if hi,< netmet ot ;other reason for rejecting
|
||
exitl>
|
||
mov r3,r1
|
||
add #$pktdt,r1 ;size of packet needed
|
||
call pktall
|
||
if eq,< netmet ot ;lost for an "other" reason
|
||
exitl>
|
||
mov r1,r2 ;get pointer to packet
|
||
add #$pktdt,r2 ;go to the data portion
|
||
add #ch.rbf,r4 ;point to read buffer
|
||
neg r3 ;negative offset
|
||
call 100$(r3) ;get those bytes in a hurry
|
||
cmp (r4),(r4) ;skip destination and hardware source
|
||
tst (r4) ;skip CRC code
|
||
sub #ch.rbf,r4 ;go back to CSR
|
||
bit #%caerr,(r4) ;CRC error?
|
||
if ne,< ;yup, sigh
|
||
netmet c2
|
||
call pktfre
|
||
exitl
|
||
>
|
||
>
|
||
|
||
mov (r4),r2 ;get the CSR to get the lost count
|
||
swab r2
|
||
asr r2
|
||
bic #mask4,r2 ;finally have the lost count
|
||
netmet lo,r2 ;count them as lost
|
||
bis #%carcl,(r4) ;tell the hardware we are clear to receive
|
||
bis #%caren,$c1sup(r5) ;and tell the software to arm receive interrupts
|
||
tst r1
|
||
if eq,<return> ;if no packet, just return
|
||
bis #%pkt08,$pktfl(r1) ;declare packet safe for 8 bit
|
||
.if nz ncpchs
|
||
tstb $pktdt(r1) ;is it chaos protocol?
|
||
if eq,<jcall chsrcv> ;go receive the chaos packet
|
||
.endc
|
||
.if nz ncpip
|
||
.endc
|
||
netmet ot ;reject if not known protocol
|
||
jcall pktfre ;free the packet
|
||
|
||
.rept %c1max/2
|
||
mov (r4),(r2)+
|
||
.endr
|
||
100$: return
|
||
|
||
c1xint: mov $c1xla(r5),r1 ;get the last packet transmitted
|
||
if ne,< ;if there was one
|
||
clr $c1xla(r5)
|
||
bit #%catab,(r4) ;check for transmit abort
|
||
if ne,< ;yup, had an abort
|
||
netmet ab ;count another abort
|
||
inc $c1xna(r5) ;up the number of aborts for this packet
|
||
cmp $c1xna(r5),#8 ;allow 8 aborts
|
||
blt c1xtrn ;try and transmit it again
|
||
>
|
||
else <netmet ou> ;count the packet as successfully out
|
||
c1xin0: call pktngv ;free packet if not on user list
|
||
>
|
||
clr $c1xna(r5) ;no aborts yet
|
||
|
||
c1xin1: call ntremq ;remove a packet from the net device
|
||
if eq,<
|
||
c1xin2: bic #%caten,$c1sup(r5) ;disarm xmit interrupts
|
||
return
|
||
>
|
||
c1xtrn: cmp $pktul(r1),#+1 ;if user link +1, then we can throw it away
|
||
if eq,< call pktfre ;free it
|
||
br c1xin1 > ;go try another
|
||
bis #%catcl,(r4) ;clear the transmitter
|
||
mov $pktxs(r1),r3 ;get number of data bytes (rounded up to word)
|
||
cmp r3,#%c1max ;is it within range
|
||
bgt c1xin0 ;if too big, throw it away
|
||
mov r1,r2 ;get pointer to packet
|
||
add #$pktdt,r2 ;go up to the base of the packet
|
||
add #ch.wbf,r4 ;go to the write buffer
|
||
neg r3 ;negative address offset
|
||
call 10$(r3) ;push the packet in fast
|
||
mov $c1hrd(r1),(r4) ;hardware destination
|
||
sub #ch.wbf,r4 ;go back to the base
|
||
tst ch.xmt(r4) ;go Go GO!!
|
||
mov r1,$c1xla(r5) ;this was the last one transmitted
|
||
mov time,$pktxt(r1) ;remember the time for retransmission
|
||
tst $c1slo(r5) ;slow?
|
||
if ne,<bic #%caten,$c1sup(r5)> ;yes, wait until the clock ticks
|
||
return
|
||
|
||
.rept %c1max/2
|
||
mov (r2)+,(r4)
|
||
.endr
|
||
10$: return
|
||
|
||
.syclk c1cint
|
||
|
||
c1slon: .word 2
|
||
c1slct: .word 2
|
||
|
||
c1cint: dec c1slct
|
||
if le,<
|
||
mov c1slon,c1slct
|
||
push r0,r5
|
||
clr r0
|
||
loop <
|
||
tst c1$slo(r0)
|
||
if ne,<
|
||
mov netobj+<2*c11net>(r0),r5
|
||
tst $ntxqu(r5)
|
||
if ne,<bis #%caten,@$ntcsr(r5)>
|
||
>
|
||
add #2,r0
|
||
cmp r0,#nch11*2
|
||
rptl lo
|
||
>
|
||
pop r5,r0
|
||
>
|
||
return
|
||
|
||
|
||
c1ini: clr r0 ;index
|
||
loop <
|
||
call c1init
|
||
add #2,r0
|
||
cmp r0,#nch11*2
|
||
rptl lo
|
||
>
|
||
return
|
||
|
||
c1init: ;actually init one device
|
||
mov c1$csr(r0),r4 ;get the csr
|
||
call nxmcat
|
||
c1nxm
|
||
mov #%carst,(r4) ;reset the board
|
||
tst ch.myn(r4) ;get my hardware address
|
||
call nxmclr
|
||
|
||
mov c1$vec(r0),r2 ;get interrupt vector
|
||
mov c1$vad(r0),(r2)+ ;set vector address
|
||
mov #pr5,(r2)+
|
||
mov c1$vad(r0),(r2)+ ;and for interval timer??
|
||
mov #pr5,(r2)+
|
||
|
||
mov #l$c11,r5
|
||
call ntmake ;make the network object
|
||
if eq,<bpt> ;oops
|
||
mov r5,netobj+<2*c11net>(r0) ;save device in network table
|
||
mov r4,$ntcsr(r5) ;save CSR address
|
||
mov #-1,$c1lok(r5) ;preset the lock to free
|
||
mov c1$slo(r0),$c1slo(r5);slowness
|
||
|
||
.if nz ncpchs
|
||
mov #c1chgv,nt$chs(r5) ;routine to send chaos packets to interface
|
||
mov ch.myn(r4),nt.chs(r5) ;my address on chaos net
|
||
mov c1$cst(r0),$ctrcv(r5) ;routing cost for this interface
|
||
.endc
|
||
|
||
.if nz ncpip
|
||
.endc
|
||
|
||
mov #%carcl+%caren+%caten,(r4) ;clear receiver and allow
|
||
;interrupts
|
||
mov r0,r4 ;get chaos index into r4
|
||
add #<c11net*2>,r4 ;now network index
|
||
jcall ntmak1 ;finish making the object
|
||
|
||
c1nxm: clr netobj+<2*c11net>(r0) ;no network object
|
||
return
|
||
|
||
|
||
.if nz ncpchs
|
||
|
||
;;; call @nt$chs(r5)[r5:=object, r1:=packet, r2:=hardware_destination(if_needed)]
|
||
|
||
c1chgv: call cpks08 ;make packet safe for 8 bit hardware
|
||
mov r2,$c1hrd(r1) ;set the hardware destination
|
||
inc $pktxs(r1) ;round up to word boundary...
|
||
bic #1,$pktxs(r1) ;...
|
||
lock 6
|
||
call nt$ptq ;put it on the queue
|
||
tst $c1slo(r5) ;slow interface?
|
||
if eq,<bis #%caten,@$ntcsr(r5)> ;signal xmit interrupt
|
||
unlock
|
||
return
|
||
|
||
.endc
|
||
|
||
.endc %defin
|
||
|
||
.iif nz %defin, .list ;start listing as usual
|
||
|
||
|
||
;; local modes:
|
||
;; mode:midas
|
||
;; auto fill mode:
|
||
;; fill column:75
|
||
;; comment column:32
|
||
;; end:
|