Trailing-Edge
-
PDP-10 Archives
-
bb-ev83b-bm
-
tcpip-sources/tcpsim.mac
There are 2 other files named tcpsim.mac in the archive. Click here to see a list.
SUBTTL TCP Simulation Definitions - Full Duplex, Serially Reusable
IFN TCPF,< ; TCP Support Routines
; The TCP simulation routines require the following JSYS redefinitions
; for JSYSi to be simulated
REPEAT 0,<
OPDEF $GTJFN [CALL TCPGJF]
OPDEF $OPENF [CALL TCPOPN]
OPDEF $BIN [CALL TCPBIN]
OPDEF $BOUT [CALL TCPBOU]
OPDEF $SIN [CALL TCPSIN]
OPDEF $SOUT [CALL TCPSOU]
OPDEF $CLOSF [CALL TCPCLO]
OPDEF $MTOPR [CALL TCPMTP]
OPDEF $GTSTS [CALL TCPGST]
OPDEF $JFNS [CALL TCPJFS]
OPDEF $RFBSZ [CALL TCPRBS]
OPDEF $SFBSZ [CALL TCPSBS]
; OPDEF $CFIBF [CALL TCPCIB]
; OPDEF $CFOBF [CALL TCPCOB]
> ; End of REPEAT 0
; User defined sizes -- these are the defaults if the user has not
; previously specified them. If only one connection is to be used,
; TCPFB may be left undefined (or 0) and all storage for the
; connection will be allocated herein. If multiple connections
; are to be used, TCPFB should be set to 1 (no storage will be
; allocated herein) and the user must allocate storage (a "nameCON"
; and "nameBUF" per connection, and a single "JFNTXS"); the macro
; TCPFIL may be used with a "NAME" of five or fewer characters.
; Note that TCPFIL must not be invoked below location 200.
; Note that the number of buffers per connection per direction
; (T.NDBF) and the size (words) of each buffer (T.BFSZ) should
; be specified before TCPFIL is invoked.
; The simulated GTJFN and OPENF have "non-standard" parameters,
; see the comments at the beginning of TCPGJF: and TCPOPN:,
; respectively.
IFNDEF T.NDBF,<T.NDBF==4> ; # of data buffers for each direction
IFNDEF T.BFSZ,<T.BFSZ==200> ; # of words in each
IFNDEF TCPFB,<TCPFB==0> ; 0 - use internal buffers
; 1 - User will supply buffers
IFNDEF TCPOLD,<TCPOLD==0> ; Non-zero for old connection descriptor fmt
IFNDEF RXTMOT,<RXTMOT==^D120> ; Transmission timeout
IFNDEF RXPARS,<RXPARS==0> ; Standard algorithm
; Flags in LH of .TCPBF
;TCPMSK==TCP%ER!TCP%LE!TCP%PE!TCP%EC ; Mask of condition code bits
MSKSTR (TCP$EC,.TCPBF,TCP%EC) ; Extract error code from buffer header
MSKSTR (T$BSZ,0,OF%BSZ)
; Define offsets in (internal) connection file status block (nameCON:)
T.JFN==0 ; Pseudo JFN (Address of this location)
T.CDB==T.JFN+1 ; Connection descriptor block
; Above are user interface, below are internal to simulation routines
T.JCN==T.CDB+.TCPCS ; JCN of this connection, if open, or 0
T.BSZO==T.JCN+1 ; Data buffer size, octets (constant)
T.BSZ==T.BSZO+1 ; Simulated byte size (same for I & O)
T.STS==T.BSZ+1 ; Simulated file status (combined)
xx=GS%OPN ; Connection is open
xx=GS%RDF ; Open for reading
xx=GS%WRF ; Open for writing
xx=GS%EOF ; Received FIN
xx=GS%ERR ; Error detected
T.CUR==T.STS+1 ; I & O ; Address of current buffer header
T.CNT==T.CUR+2 ; I & O ; Bytes in current buffer
T.PTR==T.CNT+2 ; I & O ; Byte pointer to current buffer
T.SVC==T.PTR+2 ; I & O ; Saved count (TPC)
T.SVD==T.SVC+2 ; I & O ; Saved data (TPD)
T.HDR==T.SVD+2 ; I then O ; Ring headers begin here
T.SIZE==T.HDR ; Size of block exclusive of headers
DEFINE TCPFIL (NAME),<
NAME'CON: BLOCK T.SIZE ; File control block followed by
BLOCK 2*T.NDBF*.TCPBS ; Buffer headers
NAME'BUF: BLOCK 2*T.BFSZ*T.NDBF ; Data buffers
IFNDEF JFNTXS,<JFNTXS:BLOCK 60> ; Data area for JFNS simulation
IF2 <IFE JFNTXS-.,< BLOCK 60>> ; If it was here on pass1, here on 2
> ; End of DEFINE TCPFIL
IFE TCPFB,<TCPFIL DAT> ; Use internal buffers
; Internal Registers ;***** Beware Order BIN/SIN BOUT/SOUT
TIB==5 ;*** ; Data byte Temp
TPD==6 ;*** ; - TCP packed data -
TOB==7 ;*** ; Temp Data byte
TPC==10 ; TPD bits # left # left
; (32 to 0) to read to fill
TBC==11 ; # Bits in TIB TOB
; (T.BSZ to 0)
TFSB==12 ; Points to T.JFN
TAC0==13 ; *** LAST ; Points to "saved" AC0
SUBTTL TCP Simulation - TCPGJF - Funny GTJFN
;IFE TCPFB ; Use internal buffers
; Set host address(es) and port(s) into connection block at
; nameCON+T.CDB
; A/ 0
; C/ TCP OPEN flags,,0 ; Flags: TCP%FS, TCP%WT
; $GTJFN (CALL TCPGJF) ; Simulate GTJFN & create connection
;Ret+1: error
;Ret+2: OK
; or
;IFN TCPFB ; User supplies buffers
; Set host address(es) and port(s) into connection block at
; nameCON+T.CDB
; A/ 0,,Address of pseudo JFN variable (nameCON)
; B/ -#Buffers (-T.NDBF),,Location of buffers (nameBUF)
; C/ TCP OPEN flags,,Size of each buffer (T.BFSZ)
; $GTJFN (CALL TCPGJF) ; Simulate GTJFN & create connection
;Ret+1: error
;Ret+2: OK
TCPGJF: TXNE A,GJ%SHT ; Decide if real or TCP call
JRST [GTJFN ; GJ%SHT set means real
SKIPA ; Error return
AOS (P) ; Ok return
RET]
IFE TCPFB,< ; Use internal buffers
MOVEI A,DATCON ; Connection data header address
MOVE B,[-T.NDBF,,DATBUF] ; # & address of data buffers
HRRI C,T.BFSZ ; Size of each buffer (words)
> ; End of TCPFB
CALL TCPINI ; Save things, enter simulation context
SUBTTL TCP Simulation - TCPGJF, cont. - Initialize file conn. info.
SKIPLE T.JFN(TFSB) ; Already been here?
JRST TCPGJI ; Yes
SETZM T.JCN+1(TFSB) ; Zero nameCON & buffer headers
HRRI D,T.JCN+1+1(TFSB) ; Build BLT word
HRLI D,T.JCN+1(TFSB)
HLRE TIB,B ; Find last buffer header end address
MOVNS TIB ; # buffer headers, per direction
ASH TIB,1 ; Total, both directions
IMULI TIB,.TCPBS ; Total words
ADDI TIB,T.SIZE-1(TFSB) ; End address
BLT D,(TIB) ; Clear everything
HRRZ TBC,C ; Buffer size, words
ASH TBC,2 ; Get size in (8-bit) bytes
MOVEM TBC,T.BSZO(TFSB) ; Store for later use
MOVEI D,T.HDR(TFSB) ; Location of first input ring header
TXO D,TCP%DN ; Buffer belongs to program
HRRI TPC,(TFSB) ; First do Input side
HRLI TPC,-2 ; Input, then output
MOVEM B,TIB ; Save AOBJN count in left half
INIRNG: HRRZM D,T.CUR(TPC) ; First buffer header
HRRZM B,T.PTR(TPC) ; First data buffer for pointer
HLL B,TIB ; Count of buffers in ring
INIRNL: HLLZM D,.TCPBF(D) ; TCP%DN
HRRZM B,.TCPBA(D) ; Set data buffer address into header
MOVEM TBC,.TCPBC(D) ; Set byte count
ADDI D,.TCPBS ; Step to next buffer header
ADDI B,-1(C) ; Step to next data buffer (-1 for AOBJN)
HRRM D,-.TCPBS(D) ; Point previous header to this one
AOBJN B,INIRNL ; Loop thru all buffers
MOVE TOB,T.CUR(TPC) ; First buffer header
HRRM TOB,-.TCPBS(D) ; Close ring
AOBJN TPC,INIRNG ; Back for output
HRLI B,(POINT 32) ; Construct 4-byte pointer
HLLM B,T.PTR(TFSB) ; To Input
HLLM B,T.PTR+1(TFSB) ; To Output
TCPGJI: HRRZM A,T.JFN(TFSB) ; Initialized (Pseudo JFN)
SUBTTL TCP Simulation - TCPGJN, cont., Establish the connection
MOVEI A,T.CDB(TFSB) ; Connection descriptor block
IFN TCPOLD,<SKIPE TENEX ; TENEX has old CDB format
ADDI A,1> ; so adjust pointer accordingly
HLL A,C(TAC0) ; Flags
MOVX B,RXTMOT ; Retransmission timeout
MOVX C,RXPARS ; Retransmission parameters
OPEN
JRST TCPGJX
MOVEM A,T.JCN(TFSB) ; Save JCN
MOVX A,GS%OPN
MOVEM A,T.STS(TFSB) ; Flag open
AOS -2(TAC0) ; Skip return
HRRZM TFSB,A(TAC0) ; To be returned
SETZB TPD,TPC ; No packing state to be saved
RET ; Go leave simulation context
; OPEN failed, analyze reason & ABORT JCN
TCPGJX: HRRZ C,A ; Error code
ANDI C,37 ; Just error code
HLRZS A ; Possible JCN
JUMPE A,TCPGJY ; No JCN
TXO A,TCP%JS
ABORT ; Abort that JCN
JFCL
TCPGJY:
SETOM T.JFN(TFSB) ; No useful connection
MOVX B,GJFX24 ; Default error code
CAIN C,^D1 ; Argument error
MOVX B,GJFX40 ; "Undefined attribute"
CAIN C,^D4 ; Resource shortage
MOVX B,GJFX22 ; "Insufficient resources"
CAIN C,^D5 ; Wild FH/FP only allowed if listening
MOVX B,GJFX31 ; "Invalid wildcard"
CAIN C,^D6 ; Connection already exists (error??)
MOVX B,GJFX27 ; "File already exists"
CAIN C,^D7 ; Rejected/reset
MOVX B,OPNX21 ; "Connection refused"
CAIN C,^D9 ; Transmission timeout
MOVX B,NSPX17 ; "Process aborted, timed out, or..."
MOVEM B,A(TAC0) ; To be returned
CALL SETERR ; Set process error code
SETZB TPD,TPC
RET
SUBTTL TCP Simulation - TCPOPN - Funny OPENF
; A/ nameCON
; B/ FLD(n,OF%BSZ)!OF%RD!OF%WR
; CALL TCPOPN
;Ret+1: error
;Ret+2: OK
TCPOPN: TRNN A,777600 ; JFN or TCP connection?
JRST [OPENF ; JFN
SKIPA ; Error return
AOS (P) ; Skip return
RET]
PUSH P,C ; Save a register
MOVX C,DESX3 ; "JFN is not assigned"
SKIPLE T.JFN(A) ; Initialized? and
SKIPN T.JCN(A) ; Connection still open?
JRST TCPOPE ; No, error
MOVE C,T.STS(A) ; Current status
TXNE B,OF%RD ; Process READ bit
CALL TCPRED
TXNE B,OF%WR!OF%APP ; Process WRITE bit
CALL TCPWRT
MOVEM C,T.STS(A) ; Update status
LOAD C,T$BSZ,+B ; Get byte size
SKIPN C ; Zero means 36
MOVX C,^D36
CAIL C,1 ; Olny allow 1
CAILE C,^D36 ; to 36
JRST TCPOPB ; Invalid size
MOVEM C,T.BSZ(A) ; Set new size
AOS -1(P) ; Skip return
JRST TCPOPX
; Open errors
TCPOPB: MOVX B,SFBSX2 ; "Invalid byte size"
TCPOPE: MOVX A,<.FHSLF>
MOVE B,C ; Error code
CALL SETERR ; Set process error code
MOVE A,B ; Return code too
TCPOPX:
POP P,C
RET
SUBTTL TCP Simulation - TCPOPN - Transfer direction processing
TCPRED: TXON C,GS%RDF ; Already reading?
RET ; No
; Yes, do it again
SETZM T.SVC(A) ; No partial word
SETZM T.CNT(A) ; No more data in buffer
RET
TCPWRT: TXON C,GS%WRF ; Already writing?
RET ; No
; Yes, do it again
RET ; Should have done a PUSH to get
; things synced
SETZM T.SVC+1(A) ; No partial word
SETZM T.CNT+1(A) ; No more data in buffer
RET
SUBTTL TCP Simulation - TCPBIN - Simulate BIN
TCPBIN: TRNN A,777600 ; JFN or TCP connection?
JRST [BIN ; JFN
ERCAL TERJMI
RET]
SETZ B, ; Return NULL byte on error
SKIPN T.JCN(A) ; Connection ok?
CALL TERJMI ;RET ; Illegal inst. ;No, return null byte
CALL TCPINI ; Save state
MOVX D,^D<60*60> ; Give up after an hour
; Simulate BIN by SIN of 1 byte to saved B on stack
MOVE TBC,T.BSZ(TFSB) ; User byte size
MOVEI B,B(TAC0) ; Build byte pointer to saved B
DPB TBC,[POINT 6,B,5] ; Set byte position
DPB TBC,[POINT 6,B,11] ; Set byte size
MOVNI C,1 ; Want one byte there
CALLRET TCPBI ; TCP to user
SUBTTL TCP Simulation - TCPSIN - Simulate SIN
; Only C .LT. 0 case is simulated
TCPSIN: TRNN A,777600 ; JFN or TCP connection?
JRST [SIN ; JFN
ERCAL TERJMP
RET]
SKIPGE C ; Only neg count SIN supported
SKIPN T.JCN(A) ; Still open?
CALL TERJMP ; or I ; No, do nothing
TLC B,777777
TLCN B,777777
HRLI B,(POINT 7,0)
CALL TCPINI ; Save state
MOVX D,^D<60*60> ; Give up after an hour
CALL TCPBI ; TCP to user
MOVEM B,B(TAC0) ; B to be returned
MOVEM C,C(TAC0) ; C too
SETZ C,
IDPB C,B ; End string with NULL
RET ; To save/restore state
SUBTTL TCP Simulation - TCPBI - Unpack TCP into arbitrary size bytes
; B/ Byte pointer, C/ - byte count, D/ Timeout, sec, TFSB
; TIB TPD
; +----------------------+------------------+
; ! 0 !<----v---->! xxxx !
; +----------------------+-----!------------+
; TBC/ (T.BSZ) TPC/ n
;
; +----------------------+------------------+
; ! 0 !<---v--->!<--v-->! xxxxxxxx !
; +-----------------!----+---!--------------+
; TBC/ (T.BSZ)-a TPC/ n-a where a=min(n,(T.BSZ))
TCPBI: SETZ TIB, ; Clear user byte
MOVE TBC,T.BSZ(TFSB) ; User byte size
JUMPLE TPC,TCPBI3 ; Need bits to unpack
TCPBI2: CAML TPC,TBC ; Able to fill user byte?
JRST TCPBI6 ; Yes, TPC .ge. TBC
LSHC TIB,(TPC) ; Empty 32-bit word
SUB TBC,TPC ; Bits still needed in byte (.GT.0)
TCPBI3: SKIPLE TPC,T.CNT(TFSB) ; TCP bytes left in buffer
JRST TCPBI4 ; Have some
CALL GETBUF ; None, get another buffer
MOVE TOB,T.STS(TFSB) ; Get status bits
TXNN TOB,GS%EOF+GS%ERR ; End of file? (or error)
JRST TCPBI3 ; No, go get its actual byte count
SETZ TPD, ; Yes, return NULL
JRST TCPBI5
; Get next (4) bytes from TCP
TCPBI4: SUBI TPC,4 ; Assume 4 TCP bytes in buffer
MOVEM TPC,T.CNT(TFSB) ; Update count remaining
ILDB TPD,T.PTR(TFSB) ; Get 32-bits
LSH TPD,4 ; Left justify
SKIPLE TPC ; Get all 4 TCP bytes?
TCPBI5: SETZ TPC, ; Yes
ADDI TPC,4 ; # There
LSH TPC,^D3 ; # bits therein
JRST TCPBI2 ; Go finish byte
; Have enough packed data to complete a user byte
TCPBI6: LSHC TIB,(TBC) ; Complete byte
SUB TPC,TBC ; Bits left in 32-bit word
IDPB TIB,B ; Byte to user
MOVE TOB,T.STS(TFSB) ; Get status
TXNN TOB,GS%EOF+GS%ERR ; Unless EOF or error
AOJN C,TCPBI ; Loop if want another byte
RET ; Go finish off
SUBTTL TCP Simulation - GETBUF - Get another buffer
; Simulation state - TFSB
; MOVX D,<Timeout, seconds>
; CALL GETBUF
GETBUF: PUSH P,D ; Save registers
PUSH P,C
PUSH P,B
MOVE B,T.CUR(TFSB) ; Get pointer to current buffer head
; Finished with current buffer, ask for it to be refilled
GETBU0: MOVE C,T.BSZO(TFSB) ; Reset maximum buffer count
MOVEM C,.TCPBC(B) ; In buffer header
MOVE A,T.JCN(TFSB) ; Get the JCN
RECV ; Start input on this buffer
DPB A,[POINT 8,.TCPBF(B),7] ; Save error code, process later
; Step to next buffer and begin processing it
HRRZ B,0(B) ; Step to next buffer
HRRZM B,T.CUR(TFSB) ; Make it be current
GETBU1: MOVE C,.TCPBF(B) ; Get flags of this new buffer
TXNN C,TCP%ER!TCP%DN ; Error code or done yet?
JRST GETBU2 ; No, wait
TXNE C,TCP%ER ; Error?
JRST GETERR ; Yes
; Buffer ok to process, see if it has any data
MOVE C,T.BSZO(TFSB) ; Total bytes
SUB C,.TCPBC(B) ; Less bytes not xferred
JUMPE C,GETBU0 ; If none, get next buffer
; Setup to read data from buffer
MOVEM C,T.CNT(TFSB) ; Set bytes left in current buffer
MOVE C,.TCPBA(B) ; Get buffer address
HRLI C,(POINT 32)
MOVEM C,T.PTR(TFSB) ; Set byte pointer
POP P,B
POP P,C
POP P,D
RET
SUBTTL TCP Simulation - GETBUF - Wait for buffer, or error
; Wait for next buffer of data to arrive
GETBU2: MOVE D,B-D(P) ; Timeout count
MOVX A,^D1000 ; One second
GETBU3: DISMS ; Wait a second
MOVE C,.TCPBF(B) ; Get flags of buffer
TXNN C,TCP%ER!TCP%DN ; Error code or done yet?
SOJG D,GETBU3 ; No, haven't timedout, wait
JUMPG D,GETBU1 ; If count remains, go look again
; Waited too long, give up
; Error code returned
GETERR: MOVE D,T.STS(TFSB) ; Current status
LOAD C,TCP$EC,(B) ; Extract error code
CAIE C,^D12 ; Is it "Connection Closing"?
TXOA D,GS%EOF+GS%ERR ; No, so it is a real error
TXO D,GS%EOF ; Closing, so only set EOF bit
; TXZ D,GS%OPN ; No longer open
JFCL
MOVEM D,T.STS(TFSB) ; Save status
SKIPE A,T.JCN(TFSB) ; Get back JCN of connection
ABORT ; And abort it
JFCL ; Shouldn't fail...
SETZM T.JCN(TFSB) ; Closed, no more JCN
POP P,B
POP P,C
POP P,D
RET
SUBTTL TCP Simulation - TCPBOU - Simulate BOUT for TCP connection
TCPBOU: TRNN A,777600 ; JFN or TCP connection?
JRST [BOUT ; JFN
ERCAL TERJMI
RET]
SKIPN T.JCN(A) ; Connection still open?
CALL TERJMI ; No.
CALL TCPINO ; Save state
; Change BOUT to transparent SOUT of 1 byte from TOB
MOVE TOB,B ; Data
; Forget pointer will skip into TCPBO
MOVNI C,1 ; One byte
CALLRET TCPBO1 ; User to TCP
SUBTTL TCP Simulation - TCPSOU - Simulate SOUT
; C .LT. 0 case processed directly, others converted to it by scanning
TCPSOU: TRNN A,777600 ; JFN or TCP connection?
JRST [SOUT ; JFN
ERCAL TERJMP
RET]
SKIPN T.JCN(A) ; Connection still open?
CALL TERJMP ; or I ; No, do nothing
TLC B,777777
TLCN B,777777
HRLI B,(POINT 7,0)
CALL TCPINO ; Save state
JUMPL C,TCPSO4 ; Exact count case all set
; Count characters
MOVNS C ; Positive (max) count into
HRLZS C ; AOBJN counter
SKIPN C ; C.EQ.0 or C was .GT.0
TLOA C,770000 ; C.EQ.0, big count and zero D
SKIPA ; C was .GT.0, now has count, D set
SETZ D, ; C.EQ.0 - search til NUL
TCPSO2: ILDB A,B ; Get next character
CAME A,D ; What we're looking for?
AOBJN C,TCPSO2 ; No, look further
SKIPGE C ; Stopped by count or character?
SKIPN D ; Character, and searching for NUL?
SKIPA ; Count, or NUL
ADDI C,1 ; Non-NUL character should be sent
MOVNI C,(C) ; Set C to - number of characters
MOVE B,B(TAC0) ; Restore original pointer
SKIPN C ; Anything to output?
RET ; No characters, done, go save/restore
TCPSO4:
; Have the exact count
CALL TCPBO ; User to TCP
MOVEM B,B(TAC0) ; B to be returned
MOVEM C,C(TAC0) ; C too
RET ; All done, go save/restore
SUBTTL TCP Simulation - TCPBO - Pack arbitrary bytes into TCP
; B/ Byte pointer, C/ Negative byte count, TFSB
; TPD TOB
; +--------------------------+-----------------+
; !0000!<---v--->!packed data! xxxxx !<---v--->!
; +---------!----------------+------------!----+
; TPC/ n T.BSZ/ n
; +--------------------------+-----------------+
; !0000!<---v--->!packed data!<---v--->! xxxxx !
; +---------!----------------+----!------------+
; TPC/ n TBC/ (T.BSZ)
; +--------------------------+-----------------+
; !0000!<-v->! packed data !<-v->! xxxxxxxxx !
; +-------!------------------+--!--------------+
; TPC/ n-a TBC/ (T.BSZ)-a where a=min(n,(T.BSZ))
TCPBO: ILDB TOB,B ; Get next user data byte
TCPBO1: MOVE TBC,T.BSZ(TFSB) ; User byte size
MOVN TIB,TBC ; For left-justify
LSH TOB,^D36(TIB) ; Drop unused bits on left
JUMPLE TPC,TCPBO4 ; Need word to pack
TCPBO2: CAMLE TPC,TBC ; Able to fill 32-bit word?
JRST TCPBO6 ; No
LSHC TPD,(TPC) ; Fill 32-bit word
SUB TBC,TPC ; Bits left in byte for next word
MOVE TIB,T.CNT+1(TFSB) ; Bytes used in output buffer
CAML TIB,T.BSZO(TFSB) ; Buffer full?
CALL SNDBUF ; Yes, get another
IDPB TPD,T.PTR+1(TFSB) ; 4 TCP bytes into send buffer
MOVX TIB,4
ADDM TIB,T.CNT+1(TFSB) ; Into buffer
; SETZ TPD,
TCPBO4: MOVEI TPC,^D32 ; 4 empty TCP bytes
JUMPN TBC,TCPBO2 ; Back if more bits in user byte
JRST TCPBO8 ; Done with this byte, see if another
TCPBO6: LSHC TPD,(TBC) ; Finish byte
SUB TPC,TBC ; Room left in 32-bit word
; SETZ TBC,
TCPBO8: AOJN C,TCPBO ; Loop if more bytes to process?
RET
SUBTTL TCP Simulation - SNDBUF - Send a buffer and set up the next one
; Simulation state - TFSB
; CALL SNDBUF
SNDBUF: PUSH P,D
PUSH P,C
PUSH P,B
MOVE B,T.CUR+1(TFSB) ; Pointer to current buffer head
MOVE C,T.CNT+1(TFSB) ; Get # of bytes in buffer to be sent
MOVEM C,.TCPBC(B) ; Into buffer header
SNDBU1: SKIPN A,T.JCN(TFSB) ; Get JCN
JRST SNDERR
MOVX C,RXTMOT ; Time out in 2 minutes
MOVX D,RXPARS ; Standard rexmit
SEND ; Send the buffer
JRST [ANDI A,40!37 ; Error code
CAIE A,00+^D4 ; Temporary resource shortage?
JRST SNDERR ; No. Send error
MOVX A,^D1000
DISMS
JRST SNDBU1] ; Try again
; Move to next buffer, make sure last send completed ok
MOVE B,.TCPBF(B) ; Link to next buffer header
HRRZM B,T.CUR+1(TFSB) ; Make it current
SNDBU2: MOVE C,.TCPBF(B) ; Get (old) flags of this buffer
TXNE C,TCP%ER ; Error?
JRST SNDERR ; Yes, handle that
TXNN C,TCP%DN ; Done?
JRST SNDBU3 ; No, have to wait
; Last send completed ok, setup pointers & zero count before filling it
HRRZS .TCPBF(B) ; Clear all flags for next time
MOVE C,.TCPBA(B) ; Get data buffer address
HRLI C,(POINT 32)
MOVEM C,T.PTR+1(TFSB) ; Write pointer
SETZM T.CNT+1(TFSB) ; Empty buffer
POP P,B
POP P,C
POP P,D
RET
SUBTTL TCP Simulation - SNDBUF - Wait for data to be sent, or error
; Wait til buffer has been sent (window must be zero)
SNDBU3: MOVX A,^D1000
DISMS
JRST SNDBU2
SNDERR: SKIPE A,T.JCN(TFSB) ; Get JCN
ABORT ; Reset connection
JFCL
SETZM T.JCN(TFSB) ; Connection closed, JCN gone
MOVX C,GS%ERR ; Remember error
MOVEM C,T.STS(TFSB)
POP P,B
POP P,C
POP P,D
RET
SUBTTL TCP Simulation - TCPRBS, TCPSBS - Simulate RFBSZ and SFBSZ
TCPRBS: TRNN A,777600 ; JFN or TCP connection?
JRST [RFBSZ ; JFN
SKIPA ; Error return
AOS (P) ; Skip return
RET]
PUSH P,B
SKIPN T.JCN(A) ; Open?
JRST $DESX3
MOVE B,T.STS(A)
TXNN B,GS%OPN
JRST $DESX5
MOVE B,T.BSZ(A) ; Current size
MOVEM B,(P) ; To be returned
JRST TCPXBX ; Leave
TCPSBS: TRNN A,777600 ; JFN or TCP connection?
JRST [SFBSZ ; JFN
SKIPA ; Error return
AOS (P) ; Skip return
RET]
PUSH P,B
SKIPN T.JCN(A) ; Open?
JRST $DESX3
MOVE B,T.STS(A)
TXNN B,GS%OPN
JRST $DESX5
TXC B,GS%RDF!GS%WRF
TXCN B,GS%RDF!GS%WRF
JRST $SFBX1 ; Should be one or other
SKIPN B,(P) ; Desired size
MOVX B,^D36 ; Zero is a word
CAIL B,1 ; Better be 1-36
CAILE B,^D36
JRST $SFBX2 ; Or error
MOVEM B,T.BSZ(A) ; Set new size
TCPXBX: AOS -1(P) ; Skip return
POP P,B
RET
$SFBX1: SKIPA A,[SFBSX1]
$SFBX2: MOVX A,SFBSX2
JRST TCPXBZ
$DESX3: SKIPA A,[DESX3]
$DESX5: MOVX A,DESX5
TCPXBZ: POP P,B
RET ; Error return
SUBTTL TCP Simulation - TCPGST, TCPMTP - Simulate GTSTS and MTOPR
TCPGST: TRNN A,777600 ; JFN or TCP connection?
JRST [GTSTS ; JFN
ERCAL TERJMP
RET]
MOVE B,T.STS(A) ; The status word
SKIPE T.JCN(A) ; Connection ok?
TXOA B,GS%OPN ; Yes, say open
TXZ B,GS%OPN ; No, say not open
RET
; Simulate MTOPR for a TCP connection
TCPMTP: TRNN A,777600 ; JFN or TCP connection?
JRST [MTOPR ; JFN
ERCAL TERJMI
RET]
SKIPE T.JCN(A) ; Connection ok?
CAIE B,.MOSND ; Only MTOPR 21 is simulated
RET ; Ignore others
CALL TCPINO ; Get output state
TCPSNL: MOVE C,T.CNT+1(TFSB) ; See if buffer is full
CAME C,T.BSZO(TFSB)
JRST TCPSN2 ; No, so any partial byte will fit in it
CAIE TPC,0 ; Have any data bits beyond full buffer
CAIL TPC,^D32 ; Empty count
JRST TCPSN4 ; No, just send (full) buffer
CALL SNDBUF ; First send full buffer
TCPSN2:
CAIE TPC,0 ; Any remaining bits?
CAIL TPC,^D32 ; Empty count
JRST TCPSN4 ; No, all set
LSH TPD,(TPC) ; Pack data left
IDPB TPD,T.PTR+1(TFSB) ; Into TCP buffer
MOVNS TPC
ADDI TPC,^D32+7 ; Bits used + 7
LSH TPC,-3 ; Bytes used
ADDM TPC,T.CNT+1(TFSB) ; In TCP remaining bits
SETZB TPC,TPD ; No bits left
TCPSN4:
MOVE B,T.CUR+1(TFSB) ; Get pointer to current buffer
MOVX C,TCP%PU
IORM C,.TCPBF(B) ; Mark the buffer as PUSH
CALLRET SNDBUF ; Send it
SUBTTL TCP Simulation - TCPCLO/CLOSET - Simulate CLOSF
; A/ (CO%WCL!)nameCON
TCPCLO: TRNN A,777600 ; JFN or TCP connection?
JRST [CLOSF ; JFN
SKIPA
AOS (P) ; Skip return
RET]
SKIPN T.JCN(A) ; Be sure it's still open
RET ; Already closed or aborted
CALL TCPINO ; Get output state
MOVX TOB,1 ; Assume no errors, skip return
SKIPN T.CNT+1(TFSB) ; Have any data
SKIPE T.SVC+1(TFSB) ; or bits?
SKIPA ; Yes, send them
JRST TCPCLS ; No, just close
MOVE B,T.STS(TFSB) ; Get status
TXNE B,GS%WRF ; Sending?
CALL TCPSNL ; Send final buffer if any
TCPCLS: ; TPC and TPD should be zero here
MOVE A,T.JCN(TFSB)
; MOVE B,A(TAC0) ; Flags in left half
; TXNE B,CO%WCL ; Wait?
; TXO A,TCP%WT ; Yes
CLOSE ; Tell other end to close it up
SETZ TOB, ; Error return
MOVX D,<<RXTMOT*2+10>/10> ; Short timeout for GETBUF here
MOVX B,<-^D8,,0> ; Allow 8 buffers
TCLOOP: CALL GETBUF ; Start input
SKIPN A,T.JCN(TFSB) ; Is it closed yet?
JRST TCXT ; Yes, done
AOJN B,TCLOOP ; No, try next buffer
ABORT ; Tried all 10, give up
SETZ TOB, ; Error return
TCXT: SETZB TPC,TPD ; Nothing remaining
MOVX B,GS%OPN
ANDCAM B,T.STS(TFSB) ; No longer open
SETZM T.JCN(TFSB) ; No JCN either
ADDM TOB,-2(TAC0) ; Possible skip return
RET ; Go save/restore state
SUBTTL TCP Simulation - TCPJFS - Simulate JFNS
TCPJFS: TRNN A,777600 ; JFN or TCP connection?
JRST [JFNS ; JFN
ERCAL TERJMI
RET]
PUSH P,A
HRROI A,JFNTXS
JFNS
ERJMP TERJMA
POP P,A
PUSH P,B
PUSH P,C
HRROI B,JFNTXS
SETZ C,
$SOUT
POP P,C
POP P,B
RET
; Simulate error return to ERJMP/ERCAL
TERJMA: MOVE A,(P) ; Restore A & leave garbage
TERJMP: SETZM (P) ; Return if neither
TERJMI: PUSH P,A ; Get a reg, ITRAP if neither
HLRZ A,@-2(P) ; Get instruction at return address
CAIN A,(ERJMP)
JRST TEJMP
CAIN A,(ERCAL)
JRST TECAL
SKIPE -1(P) ; Neither, what to do
0 ; Make illegal instruction
JRST TEXIT ; Continue
TECAL: MOVE A,@-2(P) ; ERCAL instruction
HLL A,-2(P) ; Fake return to get there (user flags)
AOS -2(P) ; Return from ERCAL
PUSH P,(P) ; Move saved A down
MOVEM A,-2(P) ; Fake return to get there
JRST TEXIT
TEJMP: MOVE A,@-2(P) ; ERJMP instruction
TERET: HRRM A,-2(P) ; Fake return to ERJMP
TEXIT: POP P,A ; Restore A
POP P,(P) ; Drop flag
RET
SETERR: MOVX A,<.FHSLF>
SETER ; Set system error message for ERSTR
ERJMP .+1 ; TENEX does skip return, TOPS20 doesn't
RET
SUBTTL TCP Simulation - TCPINI, TCPINO - Enter/Exit Simulation Context
; Return from simulated instruction
; P---) Return from CALL TCPINx
; Becomes
; Return from simulated instruction
; Return from CALL TCPINx
; I(0)/O(1) flag
; Saved A-TAC0
; P---) Return to restore code
TCPINI: PUSH P,[0] ; Input entry
SKIPA
TCPINO: PUSH P,[1] ; Output entry
TNR==TAC0-A+1 ; Number of registers saved
ADD P,[TNR,,TNR] ; Reserve room on stack
MOVEM TAC0,(P) ; Save last
HRLI TAC0,TAC0-TNR+1 ; First register
HRRI TAC0,1-TNR(P) ; Address for first
BLT TAC0,-1(P) ; Save registers
MOVEI TAC0,-TAC0(P) ; (Pseudo) saved AC0
HRRZI TFSB,(A) ; Address of T.JFN
ADD TFSB,-TNR(P) ; Bump by one if Output
MOVE TPC,T.SVC(TFSB) ; Restore last state
MOVE TPD,T.SVD(TFSB)
SUB TFSB,-TNR(P) ; Point to T.JFN
CALL @-1-TNR(P) ; Continue
ADD TFSB,-TNR(P) ; Bump by one if Output
MOVEM TPC,T.SVC(TFSB) ; And bits left in it
MOVEM TPD,T.SVD(TFSB) ; Save partial 32-bit word
; SUB TFSB,-TNR(P) ; Point to T.JFN
HRLI TAC0,1-TNR(P) ; Restore registers
HRRI TAC0,1+TAC0-TNR
BLT TAC0,TAC0
SUB P,[TNR+1+1,,TNR+1+1] ; Remove registers & flag & entry PC
RET ; Back to user after simulation
TLITS:; LIT
XLIST
LIT
LIST
> ; End of IFN TCPF conditional
SUBTTL