/* * Output segment */ .org 1024 seg1: charsw: /* br o_isbs /* 010 - BS */ /* br o_isht /* 011 - HT */ /* br o_isnl /* 012 - NL */ /* br o_isvt /* 013 - VT */ /* br o_isff /* 014 - FF */ /* br o_iscr /* 015 - CR */ /* br o_sendit /* 016 - SO */ /* br o_sendit /* 017 - SI */ out: /* * This is equivalent to xmit routine */ CHK(B1_ENT,1) /* check point */ /* * Registers are used as follows: * r15 - flag * r14 - free queue pointer * r13 - bit 7-0 of XADDR * r12 - bit 15-8 of XADDR * r11 - bit 17-16 of XADDR * r9 - chan# * r8/r10 - LTE address * r7 - blklen, pklen * r6,r5 - XLEN * r4 - C_S * r3 - C_R * r2 - blklen * */ /* * outq is a linked list for all output active channels */ CHK(B1_ERO,1) /* check point */ mov outq,mar mov %outq,%mar mov mem,r2|mar++ /* outq1 = outq */ mov r2,mem o_robin: /* * while (outq1) (pointer in r2) */ brz o_bye QA(r2) mov mem,r2|mar++ mov mem,r9 mov outq1,mar mov %outq1,%mar mov r2,mem GLTE(r9) /* set up r8/r10 */ /* * if (C_S ^ C_R)&DKBMASK), then the chan is blocked */ mov C_S,brg add brg,r10,mar mov mem,r4|mar++ xor mem,r4,brg mov brg,r0 mov DKBMASK,brg and brg,r0 dec r0,- brz o_endrobin mov mem,r3|mar++ mov mem,r2 /* r2 = C_A */ /* * r15 is a flag: * bit 0 - C_S == C_R * bit 1 - mlen == 0 * bit 4 - send XCNTL */ mov C_XCNTL,brg add brg,r10,mar mov mem,r0 dec r0,- brz 1f mov (1<<4),brg br 2f 1: mov 0,brg 2: mov brg,r15 /* * mlen' (in r1/r2) = (S-A-1)&07 * DKBLOCK */ mov r2,brg addn brg,r4,brg /* brg=C_S-C_A-1 */ mov brg,r5 mov WINDOW,brg and brg,r5 mov DKBLOCK,brg mov brg,r6 TIMES(r5,r6,r2,r1) /* * if (mlen'<XLEN) {mlen=XLEN-mlen'; goto o_while;} * else if (mlen'>XLEN) { goto o_endrobin; } * else if (mlen'=XLEN) { goto o_cntl; } * * mlen (r6/5) = XLEN (r6/5) - mlen' (r1/r2) */ mov C_XLEN,brg add brg,r10,mar mov mem,r6|mar++ mov mem,r5|mar++ mov r1,brg sub brg,r6 mov r2,brg subc brg,r5,r5|brg brc 1f /* * XLEN < mlen': no data to go out */ br o_endrobin 1: /* * see if mlen==0 */ or brg,r6,brg mov brg,r0 dec r0,- brz o_cntl /* send XCNTL, if any */ /* * ptr = C_XADDR+mlen' */ add mem,r1,brg|mar++ mov brg,r13 addc mem,r2,brg|mar++ mov brg,r12 mov mem,r11 adc r11 o_while: /* * blklen (in r2) = min{mlen, DKBLOCK} * mlen -= blklen */ mov DKBLOCK+1,brg sub brg,r6 mov 0,brg subc brg,r5 brc o_chunk /* * mlen <= DKBLOCK: blklen = mlen; mlen = 0; */ mov DKBLOCK+1,brg add brg,r6,brg mov brg,r2 mov brg,r7 mov 0,brg mov brg,r6 mov brg,r5 mov (1<<1),brg or brg,r15 br o_blk o_chunk: /* * mlen > DKBLOCK: blklen = DKBLOCK; mlen -= DKBLOCK; */ inc r6 adc r5 mov DKBLOCK,brg mov brg,r2 mov brg,r7 o_blk: /* * now wants to send a block with len in r2 * pklen (r1) = min{r2, DKCHUNK} * blklen -= pklen */ mov DKCHUNK,brg sub brg,r2 brc 1f /* * r2 < DKCHUNK: r1 = r2; r2 = 0; */ add brg,r2,brg mov brg,r1 dec r1,- brz o_tail /* go send trailer */ mov 0,brg mov brg,r2 br 2f 1: /* * r2 >= DKCHUNK: r1 = DKCHUNK; r2 -= DKCHUNK; */ mov brg,r1 2: o_mark: /* * Now send the DKMARK with chan# */ SENDHEAD(r9) /* * output the rest of the data * if r13 is odd, get one byte first */ mov r13,brg br0 o_getone o_gettwo: /* * Get another two bytes of data for this channel */ SGETTWO(r13,r12,r11,o_err_bus) /* * Send two bytes out to CIM * if pklen is zero, then issue send-packet command * otherwise, go back to get another two bytes * Now odh was set to DKDATA */ dec r1 BUSWAIT SENDDATA(D_WDATA,idl) dec r1 /* pklen-- */ brz o_sodd o_sendhi: D422(3) SENDDATA(D_WDATA,idh) /* send the hi byte */ dec r1,- /* pklen-- */ brz o_sendpack br o_gettwo o_getone: /* * get 2 bytes, throw away the low byte * send the hi byte */ dec r13 mov 0,brg subc brg,r12 subc brg,r11 /* back up to even address */ dec r1 GETTWO(r13,r12,r11,o_err_bus) br o_sendhi o_sodd: /* * hi byte has not been sent yet: dec addr by 1 */ mov 0,brg dec r13 subc brg,r12 subc brg,r11 o_sendpack: /* * if r2 (running blklen) > 0, issue XPACK and goto o_blk */ dec r2,- brz o_pack2 /* * Having loaded a whole packet, now issue the * transmit-packet command, i.e. dkcsr=D_XPACK */ CHK(B1_SPK,1) /* check point */ D422(2) SENDPACK(r1) br o_blk /* go back to send another packet */ o_pack2: /* * if r7-1 (fixed blklen) & 014 == 014, issue XPACK and send trailer * in the next packet * else don't issue XPACK and send trailer in this packet */ dec r7,brg mov brg,r0 mov 014,brg orn brg,r0 brz 1f br o_ta1 1: SENDPACK(r1) D422(4) o_tail: /* * just sent a block, now send the trailer * MARK+chan# BOT blklen 0 SEQ+C_S */ SENDHEAD(r9) o_ta1: D422(2) mov r15,brg br1 o_ta3 o_ta1.5: mov I_BOTM,brg o_ta2: mov brg,r0 SENDDATA(D_WCNTL,r0) D422(4) SENDDATA(D_WDATA,r7) o_ta2.5: D422(4) SENDDATA(D_WDATA,ZERO) D422(3) mov I_SEQ,brg or brg,r4,brg mov brg,r0 SENDDATA(D_WCNTL,r0) D422(4) SENDPACK(r1) /* * C_S++ and set XACK */ inc r4 /* C_S + 1 */ mov WINDOW,brg and brg,r4 mov r8,%mar mov C_X1,brg add brg,r10,mar mov mem,r0 mov XACK,brg or brg,r0,mem /* * r2 - pklen * Now r6/r5 is the real mlen * while (mlen && C_S != C_R) { */ mov r3,brg xor brg,r4,brg mov brg,r0 mov DKBMASK,brg and brg,r0 dec r0,- brz o_end1 mov r15,brg br1 o_ta5 br o_while o_ta3: /* * reach end of this xmit buffer */ mov r15,brg br4 o_ta5 o_ta4: mov r8,%mar mov C_X1,brg add brg,r10,mar mov mem,r0 mov ~XBOTM,brg or brg,r0,- brz 1f mov I_BOT,brg br o_ta2 1: mov I_BOTM,brg br o_ta2 o_ta5: /* * check if XCNTL to be sent */ mov r15,brg br4 1f br o_end1 /* no XCNTL */ 1: /* * reset bit 4 so that next time around we will not duplicate */ mov ~(1<<4),brg and brg,r15 /* * check if blklen<DKBLOCK: send XCNTL in this block */ mov DKBLOCK,brg addn brg,r7,- brz o_ta1.5 /* send XCNTL in next block */ /* * send XCNT in this block: see if in the same chunk * if the last chunk size was 12-16, then start a new chunk */ dec r7,brg mov brg,r0 mov ~014,brg or brg,r0,- brz o_ta6 /* r7 was 16, 15, 14, or 13 */ or brg,r7,- brz o_ta6 /* r7 was 12 */ br o_ta8 o_ta6: /* * finish the old chunk, restart with a new chunk */ SENDPACK(r1) D422(4) o_ta7: SENDHEAD(r9) D422(2) o_ta8: CHK(B1_CNTL,1) mov r8,%mar mov C_XCNTL,brg add brg,r10,mar SENDDATA(D_WCNTL,mem) /* send cntl */ inc r7 br o_ta4 o_cntl: /* * send XCNTL, if any */ mov r15,brg br4 1f br o_endrobin 1: /* * now send the single XCNTL in a block by itself * code should look like: * SENDHEAD(r9) * SENDDATA(D_WCNTL,r1) * mov I_BOT,brg * mov brg,r1 * SENDDATA(D_WCNTL,r1) * mov 1,r1 * SENDDATA(D_WDATA,r1) * br o_ta2.5 * * the reason we goto o_tail is to save text space and slightly slower */ mov (1<<1),brg /* indicate mlen == 0 */ or brg,r15 mov 0,brg /* is 0, will be 1 later */ mov brg,r7 br o_ta7 o_done: /* * mlen is 0: we can send CHECK here or do nothing mov I_CHECK,brg mov brg,r1 CALL(send,s.send) */ o_end1: /* * save r4 in C_S */ mov r8,%mar mov C_S,brg add brg,r10,mar mov r4,mem /* restore C_S */ o_endrobin: /* * BEWARE issue D_WRITE in the while loop, instead of robin loop. * inc r9 and go to robin loop. */ CHK(B1_ENRO,1) /* check point */ mov outq1,mar mov %outq1,%mar mov mem,r2 br o_robin o_bye: o_disp: /* * return to main dispatch loop */ CHK(B1_EXIT,1) /* check point */ mov %disp2,brg mov brg,pcr jmp disp2 o_err_bus: /* * Unibus request fails to complete within 20 usec */ mov %err_bus,brg mov brg,pcr jmp err_bus ii_init: /* * send(r9, I_AINIT); */ mov I_AINIT,brg mov brg,r1 CALL(send,s.send) /* argument in r9, r1 */ mov r5,brg /* r5=0 for init0, r5=1 for init1 */ br0 i_init1 br i_init0 i_init1: /* * set block mode * reset TA0-TA3, RSEQ, RBLEN, RULEN * release all queues and buffers from C_RB, C_RQ */ CHK(B4_IN1,4) mov r8,%mar mov C_X1,brg add brg,r10,mar mov XBLK,brg mov brg,r0 or mem,r0,mem /* set block mode */ mov C_TA0,brg add brg,r10,mar mov 0,mem|mar++ mov 0,mem|mar++ mov 0,mem|mar++ mov 0,mem|mar++ mov C_RSEQ,brg add brg,r10,mar mov 0,mem mov C_RULEN,brg add brg,r10,mar mov 0,mem|mar++ mov 0,mem|mar++ /* RULEN = 0 */ mov C_RBLEN,brg add brg,r10,mar mov 0,mem|mar++ mov 0,mem|mar++ /* RBLEN = 0 */ mov mem,r2 /* r2 = C_RB */ brz i_11 mov NIL,mem CALL(clean,s.clean) i_11: mov r8,%mar mov C_RQ,brg add brg,r10,mar mov mem,r2 /* r2 = C_RQ */ brz ii_loop mov NIL,mem CALL(clean,s.clean) br ii_loop i_init0: /* * set char mode */ CHK(B4_IN0,4) mov r8,%mar mov C_X1,brg add brg,r10,mar mov ~XBLK,brg mov brg,r0 and mem,r0,mem /* set char mode */ br ii_loop ii_ainit: /* * S = 1, R = 0, A = 0; * X = XACT; */ CHK(B4_AIN,4) mov r8,%mar mov C_S,brg add brg,r10,mar mov 1,mem|mar++ /* S = 1 */ mov 0,mem|mar++ /* R = 0 */ mov 0,mem /* A = 0 */ mov C_X,brg add brg,r10,mar mov XACT,mem|mar++ mov mem,r0 /* C_X1 */ mov XNIL,brg orn brg,r0,- brz i_ai5 /* send trailer only */ mov C_XLEN,brg add brg,r10,mar mov mem,r0|mar++ or mem,r0 mov C_XCNTL,brg add brg,r10,mar or mem,r0 dec r0,- brz ii_loop /* * this channel is output active: put it in 'outq' */ GETQ(r1,o_noqb) mov NIL,mem|mar++ mov r9,mem mov %outq,%mar mov outq,mar i_ai2: mov mem,r2 brz i_ai3 QA(r2) br i_ai2 i_ai3: mov r1,mem br ii_loop i_ai5: /* * send trailer-only mode */ CALL(strailer,s.strailer) br ii_loop ii_req: /* * send I_INIT1 * X = XINIT; */ CHK(B4_IREQ,4) mov I_INIT1,brg mov brg,r1 CALL(send,s.send) mov r8,%mar mov C_X,brg add brg,r10,mar mov XINIT,mem br ii_loop ii_enq: /* * send C_C */ CHK(B3_ENQ,3) mov r8,%mar mov C_C,brg add brg,r10,mar mov mem,r1 CALL(send,s.send) ii_check: /* * send ACK+C_RSEQ * release C_RB */ CHK(B3_CHK,3) mov r8,%mar mov C_RSEQ,brg add brg,r10,mar mov mem,r1 mov I_ACK,brg or brg,r1 CALL(send,s.send) mov r8,%mar mov C_RB,brg add brg,r10,mar mov mem,r2 brz ii_loop mov NIL,mem CALL(clean,s.clean) mov %i_ebmode,brg mov brg,pcr jmp i_ebmode ii_eoi: /* * if TA0==SOI and TA1==2, then report KS_EOI * TA0,TA1 = 0; */ CHK(B4_EOI,4) mov r8,%mar mov C_TA0,brg add brg,r10,mar mov mem,r7 mov 0,mem|mar++ mov mem,r6 mov 0,mem|mar++ mov I_SOI,brg addn brg,r7,- brz 1f br ii_loop 1: mov 2,brg addn brg,r6,- brz 1f br ii_loop 1: /* * report 2 bytes in TA2, TA3 */ mov mem,r7|mar++ /* TA2 */ mov mem,r6 /* TA3 */ mov %repinfo,%mar mov repinfo,mar mov KS_EOI,mem|mar++ mov r7,mem|mar++ /* lo byte */ mov r6,mem|mar++ /* hi byte */ br ii_rpt /* goto CALL(report,s.report) */ ii_tdkcl: /* * rcv a tdk control char, report tdk cntl */ mov repinfo,mar mov %repinfo,%mar mov KS_CNTL,mem|mar++ mov 0,mem|mar++ mov 0,mem|mar++ mov r1,mem|mar++ ii_rpt: CALL(report,s.report) ii_loop: /* * return to i_loop */ mov %i_loop,brg mov brg,pcr jmp i_loop o_noqb: /* * run out of queues and buffers */ mov %noqb,brg mov brg,pcr jmp noqb endseg1: