V8/usr/sys/kdi/subr.s
/*
* subroutine
*/
.org 3072
seg3:
r_err_bus:
/*
* Unibus request fails to complete within 20 usec
* currently is not tested
*/
mov %err_bus,brg
mov brg,pcr
jmp err_bus
rcv:
/*
* copy packets from C_RQ to C_RADDR (from host to host for XBLK)
* copy from C_RB to C_RADDR for ~XBLK
* input : r9 is the chan #, r8/r10 point to LTE
* Registers are used as follows:
* r15 - repmode
* r13(LSB), r12, r11 - ptr2 (RADDR)
* r9 - chan #
* r8/r10 - LTE address
* r7 - RQ
* r6(LSB), r5, r4(MSB) - stage 2 buffer
* r3 - plen
* r2 - len
*/
CHK(B5_ENT,5)
/*
mov repsave,mar
mov %repsave,%mar
mov r12,mem
*/
mov 0,brg
mov brg,r15
mov repctl,mar
mov %repctl,%mar
mov 0,mem /* flag to indicate no CNTL rcv yet */
/*
* set STIME if timer expires
*/
mov r8,%mar
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YEXPIRE,brg
orn brg,r0,-
brz 1f
br 2f
1: mov STIME,brg
or brg,r15
2:
/*
* put RADDR into r13, r12, r11
* put RQ/RB into r7
* RQ and RADDR will be restored with the new value after the while loop
*/
mov C_X1,brg
add brg,r10,mar
mov mem,r0
mov XBLK,brg
orn brg,r0,-
brz 1f
mov C_RB,brg
br 2f
1: /* block mode */
mov C_RQ,brg
2: add brg,r10,mar
mov mem,r7
brz r_ex2
mov C_RADDR,brg
add brg,r10,mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r11
r_while:
/*
* while ((C_RLEN>0) && (C_RQ!=NULL))
*/
mov r7,r7
brz r_endwhile
mov C_RLEN,brg
add brg,r10,mar
mov mem,r0
mov mem,r2|mar++
mov mem,r1
or mem,r0
dec r0,-
brz r_endwhile
/*
* len222 = len = min(plen,C_RLEN);
*/
QA(r7)
mov mem,mem|mar++
mov mem,r3|mar++ /* plen */
mov mem,idl|mar++ /* *pdata */
dec r3,- /* test for rej packet */
brz r_rq
/*
* r2,r1 -= len222
*/
mov r8,%mar
mov C_RLEN,brg
add brg,r10,mar
mov r3,brg
sub brg,r2
mov 0,brg
subc brg,r1
brc 1f
/*
* case: plen > C_RLEN
* len = C_RLEN (r2)
* C_RLEN = 0
* plen (r3) = plen - len
*/
mov mem,r2
mov 0,mem|mar++
mov 0,mem
CHK(B5_PLEN,5)
mov r2,brg
sub brg,r3
br 2f
1:
/*
* case: plen <= C_RLEN
* C_RLEN is now in r2, r1
* len = plen (r3)
* plen = 0;
*/
mov r2,mem|mar++
mov r1,mem
mov r3,brg
mov brg,r2
sub brg,r3 /* plen = 0 */
2:
/*
* idl is the buffer index
* let r6-r4 points to pdata
*/
mov idl,brg
mov brg,r1
BITA(r1,r6,r5,r4)
/*
* while (len--) *ptr2++ = *ptr1++;
* test 'r13' for even or odd first
*/
mov r13,brg
br0 r_odd
br r_even
r_odd:
/*
* copy one byte
*/
CHK(B5_ODD,5)
GETTWO(r6,r5,r4,r_err_bus)
dec r2
mov idh,brg
br0 1f
br r_cnt1 /* cntl is rcv */
1:
mov idl,brg
mov brg,odl
mov brg,odh
PUTONE(r13,r12,r11,r_err_bus)
dec r2,-
brz r_done
r_even:
/*
* copy two bytes at a time
*/
mov 2,brg
sub brg,r2,- /* len - 2 */
brc 1f
brz r_odd
br r_done
1:
GETTWO(r6,r5,r4,r_err_bus)
dec r2
mov idh,brg
br0 1f
br r_cnt1 /* cntl is rcv */
1:
mov idl,brg
mov brg,odl
GETTWO(r6,r5,r4,r_err_bus)
dec r2
mov idh,brg
br0 1f
br r_cnt0
1:
mov idl,brg
mov brg,odh
PUTTWO(r13,r12,r11,r_err_bus)
br r_even
r_done:
/*
* this is the end of copy
* if (plen==0) ?
*/
dec r3,-
brz r_rq
/*
* plen != 0, move data to the front of the buffer
* while (plen--) *ptr2++ = *ptr1++
* ptr2 in r13-11 (pdata[0]), ptr1 in r6-r4 (pdata[plen])
*/
CHK(B5_MOVE,5)
mov tmp,mar
mov %tmp,%mar
mov r13,mem|mar++
mov r12,mem|mar++
mov r11,mem
QA(r7)
mov mem,mem|mar++
mov r3,mem /* store plen */
mov mem,idl|mar++ /* idl = plen */
mov mem,r3 /* points to pdata[0] */
BITA(r3,r13,r12,r11)
mov idl,brg
mov brg,r3
r_move:
/*
* while (plen--) ....
*/
dec r3,-
brz r_ret
GETTWO(r6,r5,r4,r_err_bus)
mov idl,brg
mov brg,odl
mov idh,brg
mov brg,odh
PUTTWO(r13,r12,r11,r_err_bus)
dec r3 /* move 2-bytes: 1 9-bit envelop */
br r_move
r_ret:
/*
* restore r13, r12, r11
*/
mov tmp,mar
mov %tmp,%mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r11
/*
* now test if cntl was rcv
*/
mov repctl,mar
mov %repctl,%mar
mov mem,r0
dec r0,-
brc r_cnt3 /* rcv cntl flag set */
br r_rp2 /* plen>0, then RLEN must be 0 */
r_rq:
/*
* RQ = Pnext;
* release buffer and queue
* send echo or rej if pseq!=0
*/
mov r7,brg
mov brg,r5 /* r5 = old RQ */
QA(r5)
mov mem,r7|mar++ /* r7 = new RQ */
mov 0,mem|mar++ /* plen = 0 */
mov mem,r6 /* r6 = buf pointer */
mov NIL,mem|mar++
mov mem,r1 /* pseq */
mov mem,r2
mov 0,mem
FREEQ(r5)
IBEG(r6)
dec r1,-
brz r_rq2
/*
* if pseq&0370 == I_SEQ: pseq += I_ECHO - I_SEQ; set SBLOCK
*/
mov ~WINDOW,brg
and brg,r2
mov I_SEQ,brg
xor brg,r2
dec r2,-
brc r_rq1
mov WINDOW,brg
and brg,r1
mov I_ECHO,brg
or brg,r1 /* r1 = ECHO + seq */
/*
* if YBLOCK is set, set SBLOCK
*/
mov r8,%mar
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YBLOCK,brg
orn brg,r0,-
brz 1f
br r_rq1
1:
mov SBLOCK,brg
or brg,r15 /* reach end of a block */
r_rq1:
CALL(send,s.send)
mov r8,%mar
mov C_C,brg
add brg,r10,mar
mov r1,mem
r_rq2:
mov repctl,mar
mov %repctl,%mar
mov mem,r0
dec r0,-
brc r_cnt3
r_report:
/*
* if C_RLEN==0 report(KS_RDB,r9)
*/
mov r8,%mar
mov C_RLEN,brg
add brg,r10,mar
mov mem,r0|mar++
or mem,r0
dec r0,-
brz r_rp2
mov SBLOCK,brg
orn brg,r15,-
brz r_rp3
br r_while
r_rp2:
mov SFULL,brg
or brg,r15 /* RLEN reaches 0 */
r_rp3:
/*
* save r7 and r13,r12, r11 here
* report READ completion: code in r15.
*/
CHK(B5_REP,5)
mov r8,%mar
mov C_RLEN,brg
add brg,r10,mar
mov mem,r2
mov 0,mem|mar++
mov mem,r3
mov 0,mem
mov %repinfo,%mar
mov repinfo,mar
mov KS_RDB,mem|mar++
mov r2,mem|mar++
mov r3,mem|mar++
mov mem,mem|mar++ /* cntl char */
mov r15,mem
CALL(report,s.report)
mov r8,%mar
br r_ex0
r_endwhile:
/*
* Restore RADDR from r13, r12, r11
* Restore RQ or RB (if ~XBLK) from r7
*/
dec r15,-
brc r_rp3
mov r8,%mar
mov C_RADDR,brg
add brg,r10,mar
mov r13,mem|mar++
mov r12,mem|mar++
mov r11,mem
r_ex0:
mov C_X1,brg
add brg,r10,mar
mov mem,r0
mov XBLK,brg
orn brg,r0,-
brz 1f
mov C_RB,brg
br 2f
1: /* block mode */
mov C_RQ,brg
2: add brg,r10,mar
mov r7,mem
r_exit:
CHK(B5_EXIT,5)
/*
mov repsave,mar
mov %repsave,%mar
mov mem,r12
*/
RETURN(s.rcv)
r_ex2:
dec r15,-
brc r_rp3
br r_exit
r_cnt0:
/*
* copy 1 byte to RADDR and report completion for SCNTL
*/
mov odl,brg
mov brg,odh
PUTONE(r13,r12,r11,r_err_bus)
r_cnt1:
/*
* len (r2) may not be 0
* adjust RLEN and plen
*/
mov r2,brg
add brg,r3
mov 0,r0
inc r2
mov r8,%mar
mov C_RLEN,brg
add brg,r10,mar
add mem,r2,mem|mar++
addc mem,r0,mem
mov repctl,mar
mov %repctl,%mar
mov idl,mem
br r_done
r_cnt3:
/*
* prepare for report
*/
mov SCNTL,brg
or brg,r15
br r_rp3
clean:
/*
* r2 is a queue pointer: release all queues/buffers
* using r0, r2, r3, brg, mar, %mar
*/
CHK(B5_AJAX,5)
c_1:
mov r2,brg
brz c_exit
mov brg,r0
QA(r0)
mov mem,r2|mar++ /* pnext */
mov 0,mem|mar++ /* plen */
mov mem,r3
mov NIL,mem|mar++ /* *pdata */
mov 0,mem /* pseq */
FREEQ(r0)
IBEG(r3)
br c_1
c_exit:
RETURN(s.clean)
send:
/*
* This subroutine sends a 1-byte (in r1) meta packet on chan r9
*/
SENDHEAD(r9)
D422(4)
SENDDATA(D_WCNTL,r1)
D422(4)
SENDPACK(r1)
D422(4)
SENDCMD(D_READ)
RETURN(s.send)
report:
mov csr0,brg
br0 report /* csr0==3, loop forever */
/*
* kin is 12 bytes: KS_SEND info 4 bytes ==> INCA(8)
* KS_RDB info 8 bytes ==> INCA(4)
* KS_EOI, KS_ERR info 6 bytes ==> INCA(6)
* r9 - channel #
* repinfo: code, lenlo, lenhi, cntl, mode
* r1, r12, r13 are saved and restored when exit
* this implementation is fast but use 70 more instructions than:
* have a loop to put info in repinfo to odl/odh for PUTTWO
* Modify HS and sbhead
* Interrupt cpu
* using r0, r1, r2, r9, r11, r12, r13, npr, mar, %mar, odl, odh, oal, oah, brg
*/
mov repsave,mar
mov %repsave,%mar
mov r1,mem|mar++
mov r12,mem|mar++
mov r13,mem|mar++
mov sbhead,mar
mov %sbhead,%mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r11
mov %repinfo,%mar
mov repinfo,mar
mov mem,odl
mov mem,r2 /* r2 = (repinfo) */
mov kseq,mar
mov %kseq,%mar
mov mem,odh /* for debugging */
mov mem,r0
inc r0,mem
PUTTWO(r13,r12,r11,r_err_bus)
mov r9,brg
mov brg,odl /* chan# */
PUTTWO(r13,r12,r11,r_err_bus)
mov KS_SEND,brg
addn brg,r2,-
brz rp2
/*
* report is KS_RDB and others
*/
mov %replen,%mar
mov replen,mar
mov mem,odl|mar++ /* lenlo */
mov mem,odh /* lenhi */
PUTTWO(r13,r12,r11,r_err_bus)
mov %repctl,%mar
mov repctl,mar
mov mem,odl|mar++
mov mem,odh
PUTTWO(r13,r12,r11,r_err_bus)
mov KS_RDB,brg
addn brg,r2,-
brz rp3
br rp4
rp2:
/*
* report is KS_SEND
*/
mov 8,brg
br rpy
rp2.5:
/*
* reset bit map for chan# in r9
*/
mov 7,brg
and brg,r9,brg
mov brg,r0
mov %bitpatt,%mar
mov bitpatt,brg
add brg,r0,mar
mov mem,r0
mov r9,brg
mov 0,brg>>
mov 0,brg>>
mov 0,brg>>
mov brg,r2
mov %timemap,%mar
mov timemap,brg
add brg,r2,mar
or mem,r0,mem /* turn bit on */
xor mem,r0,mem /* turn bit off */
br rp4
rp3:
/*
* report was KS_RDB
* reset C_Y and RULEN
*/
mov r8,%mar
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov 0,mem /* reset READ mode */
mov C_RULEN,brg
add brg,r10,mar
mov 0,mem|mar++
mov 0,mem
/*
* if YTIMACT, reset bit in timemap
*/
mov YTIMACT,brg
orn brg,r0,-
brz rp2.5
rp4:
mov 4,brg
rpy:
/*
* brg: increment count
* Now modify HS and sbhead
* If HS==BUFSIZ-1, then HS=0 and sbhead=sbaddr
*/
mov brg,odl
mov HS,r0
mov BUFSIZ-1,brg
sub brg,r0,- /* HS-(BUFSIZ-1) */
brc 1f
inc r0,HS
INCA(r13,r12,r11,odl)
br 2f
1: mov 0,brg /* reset HS */
mov brg,HS
mov sbaddr,mar
mov %sbaddr,%mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r11
2:
/*
* Restore sbhead
*/
mov sbhead,mar
mov %sbhead,%mar
mov r13,mem|mar++
mov r12,mem|mar++
mov r11,mem|mar++
/*
* Send interrupt 2 to the PDP-11
*/
mov 0200,brg
mov brg,csr2 /* RDYO to csr2 for kmc.c */
mov nprx,brg|r0
br7 1f
mov BRQ|VEC4,brg
mov brg,nprx
1:
/*
* restore r1, r12, r13
*/
mov repsave,mar
mov %repsave,%mar
mov mem,r1|mar++
mov mem,r12|mar++
mov mem,r13|mar++
RETURN(s.report)
copy1:
/*
* r13 is set to (1<<0) and bit 6 (block/char mode) unchanged because:
* rblen == 0; c_ta0 == 0; rlen>0; raddr will become odd after copy1
* r12.0 is 1; reset r12 when exit
* copy odl to raddr and restore r1 before return
* raddr is in oal, oah, r11
* since rlen, raddr, rulen were changed for 2 bytes
* adjustments are needed here
*/
mov (1<<6),brg
and brg,r13 /* preserve block/char mode bit */
mov r1,brg
mov brg,idh /* save r1 */
mov odl,brg
mov brg,odh
SPUTONE(r11,r_err_bus)
mov r8,%mar
mov C_RLEN,brg
add brg,r10,mar
mov 1,r1|brg
or brg,r13 /* set bit 0 (radd odd) */
mov 0,r0|brg
mov brg,r12 /* reset r12 */
add mem,r1,mem|mar++ /* inc rlen */
addc mem,r0,mem|mar++
mov mem,r11
dec r11,mem|mar++ /* dec raddr */
mov mem,r11
subc brg,r11,mem|mar++
mov mem,r11
subc brg,r11,mem|mar++
mov mem,r11
dec r11,mem|mar++ /* dec rulen */
mov mem,r11
subc brg,r11,mem|mar++
/*
* restore r1 from idh and return
*/
mov idh,brg
mov brg,r1
RETURN(s.copy1)
cktimer:
/*
* check timer status: it is called from input routine:
* if char mode and channel # is changed or fifo is empty;
* if rulen>0 && rlen==0, reset rulen to 0, report SFULL, and return
* if (c_rb==nil && c_rulen==0) return;
* if (YTIME) set YEXPIRE or turn on timer
* call 'rcv'
* r1 has to be preserved
* r9: channel number
* using: r0, ....
*/
mov r8,%mar
mov C_RULEN,brg
add brg,r10,mar
mov mem,r2|mar++
or mem,r2
dec r2,-
brz ct_3
/*
* if rlen==0, report SFULL
*/
mov C_RLEN,brg
add brg,r10,mar
mov mem,r0|mar++
or mem,r0
dec r0,-
brc ct_4
mov %repinfo,%mar
mov repinfo,mar
mov KS_RDB,mem|mar++
mov 0,mem|mar++ /* residue length */
mov 0,mem|mar++
mov 0,mem|mar++ /* cntl char */
mov SFULL,mem /* mode */
CALL(report,s.report)
br ct_9
ct_3:
mov C_RB,brg
add brg,r10,mar
mov mem,brg
brz ct_9
ct_4:
/*
* check if timeout mode
*/
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YTIME,brg
orn brg,r0,-
brz 1f
br ct_7
1:
mov YEXPIRE,brg
orn brg,r0,brg
brz ct_7 /* timer already expires */
mov YTIMACT,brg
orn brg,r0,-
brz ct_7 /* timer already active */
/*
* set timer active and load initial timer value
*/
or brg,r0,mem /* set YTIMACT */
mov C_INITIM,brg
add brg,r10,mar
mov mem,r0
mov C_ITIME,brg
add brg,r10,mar
dec r0,mem
brc ct_10
/*
* timer expires: INITIM is 0
*/
mov 0,mem
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YEXPIRE,brg
or brg,r0
mov ~YTIMACT,brg
and brg,r0,mem
ct_7:
/*
* timer expires, call rcv
* save r1 here before calling 'rcv'
*/
mov %rcvsave,%mar
mov rcvsave,mar
mov r13,mem|mar++
mov r12,mem|mar++
mov r1,mem|mar++
CALL(rcv,s.rcv)
mov %rcvsave,%mar
mov rcvsave,mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r1
ct_9:
RETURN(s.cktimer)
ct_10:
/*
* timer not expire: turn on bitmap and set YTIMACT
*/
mov r9,brg
mov 7,r7
and brg,r7
mov 0,brg>>
mov 0,brg>>
mov 0,brg>>
mov brg,r0
mov %bitpatt,%mar
mov bitpatt,brg
add brg,r7,mar
mov mem,r7
mov %timemap,%mar
mov timemap,brg
add brg,r0,mar
or mem,r7,mem
br ct_7
strailer:
/*
* XNIL is set, send trailer-only on this channel
* chan# is not on 'outq'
* r9, r8/r10 is set up
* using r0, r1, r2, ...
*/
mov r8,%mar
mov C_S,brg
add brg,r10,mar
mov mem,r0
mov I_SEQ,brg
or brg,r0,brg
mov brg,r1
inc r0
mov WINDOW,brg
and brg,r0,mem
mov C_X1,brg
add brg,r10,mar
mov mem,r0
mov XBOTM,brg
orn brg,r0,-
brz 1f
mov I_BOT,brg
br 2f
1: mov I_BOTM,brg
2: mov brg,r2
SENDHEAD(r9)
D422(4)
SENDDATA(D_WCNTL,r2)
D422(4)
SENDDATA(D_WDATA,0)
D422(4)
SENDDATA(D_WDATA,0)
D422(4)
SENDDATA(D_WCNTL,r1)
D422(4)
SENDPACK(r0)
D422(4)
SENDCMD(D_READ)
RETURN(s.strailer)
/*
* end of segment 3
*/
endseg3: