V8/usr/sys/kdi/main.s
/*
* This version of kmc-cpu interface uses two circular buffers.
* Cmdbuf is used to pass command to kmc;
* statbuf is used to report status.
* Csr4~5 are the head/tail of the cmdbuf, and csr6~7 for statbuf.
*
* When csr0 is 0, kmc is idle and does nothing.
* The cpu will set csr to 1 and pass cmdbuf/statbuf addresses
* in csr4~7.
* Then the kmc will set csr0 to 2 and stay at this state forever.
*
*
* Permanently assigned registers:
*
* Channel dependent assigned registers:
*
* r14 - free kmc queue pointer
* r9 - channel #
* r8 - group number currently being serviced
* r10 - address of current line-table entry
*/
#define C_RLEN 0 /* read length */
#define C_RADDR 2 /* read address */
#define C_RULEN 5 /* uncheck input in RADDR */
#define C_XLEN 7 /* write length */
#define C_XADDR 9 /* write address */
#define C_RQ 12 /* un-ack input: in host memory */
#define C_RBLEN 13 /* length */
#define C_RB 15 /* un-check input: waiting for trailer */
#define C_S 16 /* next seq# to be sent */
#define C_R 17 /* last seq# echoed */
#define C_A 18 /* last seq# acked */
#define C_C 19 /* last seq# received */
#define C_TA0 20 /* trailer: BOT/BOTM/BOTS/SOI */
#define C_TA1 21 /* len of trailer data */
#define C_TA2 22 /* 1st byte of trailer/SOI data */
#define C_TA3 23 /* 2nd byte of trailer/SOI data */
#define C_RSEQ 24 /* seq# for this block */
#define C_XCNTL 25 /* cntl char following the data */
#define C_X 26 /* state of the chan */
#define C_X1 27 /* state of the chan (ovf from C_X) */
#define C_Y 28 /* input state */
#define C_ITIME 29 /* timer for last char input */
#define C_INITIM 30 /* initial value for ITIME */
/*
* define bits in C_X
* bits 0-2 are exclusive
*/
#define XIDLE (1<<0) /* chan is uninitialized */
#define XACT (1<<1) /* chan is initialized */
#define XINIT (1<<2) /* chan is in the init stage */
/*
* define bits in C_X1 (overflowed from C_X)
*/
#define XNIL (1<<0) /* send trailer only */
#define XREJ (1<<3) /* hasn't rcv ECHO since last REJ */
#define XBLK (1<<4) /* set if block mode, else char mode */
#define XENQ (1<<5) /* has sent ENQ and not rcv ECHO yet */
#define XACK (1<<6) /* C_S has been incremented since ENQ/CHECK */
#define XBOTM (1<<7) /* send BOTM (instead of BOT) */
/*
* define bits in C_Y
*/
#define YTIMACT (1<<0) /* timer active */
#define YEXPIRE (1<<1) /* timer expires */
#define YBLOCK (1<<5) /* rcv return on block boundary */
#define YTIME (1<<6) /* rcv return on time expires */
/*
* Define useful constants
*/
#define NIL 0377
#define NULL 0377
#define NUL 0377
#define ZERO 0
/*
* Datakit and protocol related constant
*/
#define DKCHUNK 16 /* packet size - don't change */
#define CHANMODS 96 /* # of channels per module */
#define NGRP CHANMODS/8-1 /* # of bytes for bit map */
#define BUFSIZ 10 /* size of cmdbuf, statbuf, etc */
#define MAXBADPK 64 /* bad packet received before complaining */
#define DKBMASK 03 /* seq # is 0 to 3 */
#define WINDOW 07 /* max window size */
#define DKBLOCK 28 /* block size before trailer */
#define BSIZE 64 /* size (9-bits) of each host buffer */
#define BSIZE2 BSIZE*2 /* size in bytes */
/*
* protocol cntl patterns
*/
#define I_SEQ 0010 /* 8 sequence numbers to end trailers */
#define I_ECHO 0020 /* 8 echoes, data given to host */
#define I_REJ 0030 /* 8 rejections, transmission error */
#define I_ACK 0040 /* first of 8 acks, correct reception */
#define I_BOT 0050 /* normal beginning of trailer */
#define I_BOTM 0051 /* trailer with more data to follow */
#define I_BOTS 0052 /* seq update algorithm on this trailer */
#define I_SOI 0053 /* start of interrupt trailer */
#define I_EOI 0054 /* end of interrupt trailer */
#define I_ENQ 0055 /* xmitter request flow/error status */
#define I_CHECK 0056 /* xmitter request error status */
#define I_INITREQ 0057 /* request initialization */
#define I_INIT0 0060 /* disable trailer processing */
#define I_INIT1 0061 /* enable trailer processing */
#define I_AINIT 0062 /* response to INIT0/INIT1 */
/*
* command type
*/
#define KC_INIT 1 /* init: 0,0,0,0 */
#define KC_SEND 2 /* send: len, cntl, mode, addr */
#define KC_RCVB 3 /* rcv: len, time, mode, addr */
#define KC_CLOSE 4 /* close: 0, 0, 0, 0 */
#define KC_XINIT 5 /* re-init xmitter: 0, 0, 0, 0 */
#define KC_CMD 6 /* cmd to kmc: cmd, 0, 0, 0 */
#define KC_FLAG 7 /* i/oflag: iflag, oflaghi, oflaglo, 0 */
#define KC_SOI 8 /* send express: (byte2<<8)|byte1, 0, 0, 0 */
#define KC_TDK 9 /* send to tdk: ctl, 0, 0, 0 */
/*
* report type
*/
#define KS_SEND 20 /* send: 0, 0, 0, 0 */
#define KS_RDB 21 /* rcv: residue len, cntl, mode, 0 */
#define KS_EOI 22 /* rcv express: (byte2<<8)|byte1, 0, 0, 0 */
#define KS_CNTL 23 /* rcv tdk cntl: 0, cntl, 0, 0 */
#define KS_ERR 24 /* error: code, 0, 0, 0 */
/*
* sub command bits for KC_CMD
*/
#define OFLUSH (1<<1) /* Flush output */
#define OSPND (1<<2) /* Suspend output */
#define ORSME (1<<3) /* Resume output */
/*
* KC_RCVB mode
*/
#define CBLOCK (1<<5) /* return on block boundary */
#define CTIME (1<<6) /* return on time expires */
/*
* KS_RDB mode
*/
#define SFULL (1<<0) /* buffer full */
#define SCNTL (1<<1) /* cntl char rcv */
#define SABORT (1<<3) /* rcv aborted */
#define SBLOCK (1<<5) /* block boundary */
#define STIME (1<<6) /* timer expires */
/*
* define bit pattern
*/
#define BIT0 (1<<0)
#define BIT1 (1<<1)
#define BIT2 (1<<2)
#define BIT3 (1<<3)
#define BIT4 (1<<4)
#define BIT5 (1<<5)
#define BIT6 (1<<6)
#define BIT7 (1<<7)
#define CLT0 0
#define CLT1 010
#define CLK1MS 16
#define R_TIMER 6 /* multiple of 50 us (300us here) */
/*
* head/tail of circular buffers
*/
#define HC csr4 /* head of cmdbuf */
#define TC csr5 /* tail of cmdbuf */
#define HS csr6 /* head of statbuf */
#undef TS
#define TS csr7 /* tail of statbuf */
/*
* Define bits in npr
*/
#define NRQ (1<<0)
#define OUT (1<<4)
#define BYTE (1<<7)
/*
* Define bits in nprx
*/
#define NEM (1<<0)
#define ACLO (1<<1)
#define PCLK (1<<4)
#define VEC4 (1<<6)
#define BRQ (1<<7)
/*
* Define check point code
*/
#define B0_KCSO (1<<0) /* enter KC_SOI cmd */
#define B0_KCCM (1<<1) /* enter KC_CMD cmd */
#define B0_KCFG (1<<2) /* enter KC_FLAG cmd */
#define B0_KC1 (1<<3) /* enter KC_ONE cmd */
#define B0_KCSD (1<<4) /* enter KC_SEND cmd */
#define B0_KCRB (1<<5) /* enter KC_RCVB cmd */
#define B0_KCIT (1<<6) /* enter KC_INIT cmd */
#define B0_KCCS (1<<7) /* enter KC_CLOSE cmd */
#define B1_ENT (1<<0) /* enter output seg */
#define B1_CNTL (1<<1) /* send XCNTL */
#define B1_ERO (1<<2) /* enter robin */
#define B1_SPK (1<<4) /* issue D_XPACK */
#define B1_ENRO (1<<5) /* endrobin */
#define B1_EXIT (1<<7) /* exit output */
#define B2_ENT (1<<0) /* enter input seq */
#define B2_CNTL (1<<1) /* control packet */
#define B2_SUP (1<<2) /* rcv sup cntl char */
#define B2_NWWT (1<<3) /* rcv not well form trailer */
#define B2_REP (1<<4) /* KS_RDB interrupt */
#define B2_DATA (1<<6) /* data packet */
#define B2_EXIT (1<<7) /* exit input seg */
#define B3_SEQ (1<<0) /* rcv SEQ */
#define B3_ECHO (1<<1) /* rcv ECHO */
#define B3_ACK (1<<2) /* rcv ACK */
#define B3_REJ (1<<3) /* rcv REJ */
#define B3_CHK (1<<4) /* rcv CHK */
#define B3_ENQ (1<<5) /* rcv ENQ */
#define B4_EOI (1<<0) /* rcv EOI */
#define B4_BOT (1<<1) /* rcv BOT */
#define B4_IN1 (1<<2) /* rcv INIT1 */
#define B4_IN0 (1<<3) /* rcv INIT0 */
#define B4_AIN (1<<4) /* rcv AINIT*/
#define B4_IREQ (1<<5) /* rcv INITREQ */
#define B5_ENT (1<<0) /* enter rcv */
#define B5_PLEN (1<<1) /* plen >= RLEN */
#define B5_ODD (1<<2) /* r_odd */
#define B5_REP (1<<3) /* report READ comp */
#define B5_MOVE (1<<4) /* partial buffer */
#define B5_AJAX (1<<5) /* enter clean() */
#define B5_EXIT (1<<6) /* exit rcv */
#define B5_TIME (1<<7) /* timer expires */
#define B6_POST (1<<0) /* output postprocessing */
#define B6_NL (1<<1) /* NL */
#define B6_CR (1<<2) /* CR */
#define B6_TAB (1<<3) /* TAB */
#define B6_BS (1<<4) /* back space */
#define B6_VT (1<<5) /* VT */
#define B6_FF (1<<6) /* FF */
#define B7_IFL (1<<0) /* flush input */
#define B7_OFL (1<<1) /* flush output */
#define B7_OSP (1<<2) /* suspend output */
#define B7_ORE (1<<3) /* resume output */
#define B7_IUB (1<<4) /* unblock input */
#define B7_IBL (1<<5) /* block input */
#define B7_BRK (1<<6) /* send break */
/*
* Define error codes
*/
#define E_SW 00 /* dispatcher switch */
#define E_BUS 01 /* Unibus error */
#define E_IPANIC 02 /* input routine panic */
#define E_CMD 03 /* command unknown */
#define E_NOQB 04 /* run out of queue or buffer */
#define E_DUP 05 /* duplicate SEND */
#define E_ODKOVF 06 /* output routine panic */
#define E_UMETA 07 /* un-recognized cntl char */
#define E_SYS1 041 /* system error 1 */
#define E_SYS2 042 /* system error 2 */
#ifdef DR11C
/*
* specific declarations for dr11-c
*/
#define DKRDONE (1<<7) /* 15-th bit */
#define DKTDONE (1<<7) /* 7-th bit */
#define DKCOM (3<<0) /* 01 bits */
#define DKTENAB (1<<6) /* 6-th bit */
#define DKRENAB (1<<5) /* 5-th bit */
#define DKDATA (1<<0) /* 8-th bit */
#define DKMARK (1<<1) /* 9-th bit */
#define ILO idl
#define IHI idh
#define OLO odl
#define OHI odh
#define D_OSEQ 0
#define D_READ 1
#define D_WRITE 2
#define D_XPACK 3
#define D_WHEAD (1<<1) /* 9-th bit */
#define D_WDATA (1<<0) /* data byte */
#define D_WCNTL 0 /* control byte */
#endif
#ifdef KDI
/*
* specific declarations for dki board
*/
#define ILO lur0
#define IHI lur5
#define OLO lur0
#define OHI lur1
#define DKFRDY (1<<0) /* data from dk ready */
#define TRQRDY (1<<1) /* seq# rdy: xmit done */
#define D_OSEQ (0<<6)
#define D_RESET (0<<6)
#define D_READ (1<<6)
#define D_WHEAD 0202
#define D_WDATA 0201
#define D_WCNTL 0200
#define D_XPACK 0301
#endif
/*
* MACRO definition
*/
/*
* Define the "BUSWAIT" macro
* not test NMEM is dangereous if memory does not exist, but fast
*/
#define BUSWAIT\
5: mov npr,brg;\
br0 5b /* loop until ~NRQ */
/*
* Macros to get and release queue entries
* r14 points to the list of available queue entries
*/
#define FREEQ(X)\
mov 03,brg;\
and brg,X,%mar;\
mov ~03,brg;\
and brg,X,mar;\
mov r14,mem;\
mov X,brg;\
mov brg,r14
#define GETQ(X,Y)\
mov r14,brg;\
brz Y;\
mov brg,X;\
mov 03,brg;\
and brg,X,%mar;\
mov ~03,brg;\
and brg,X,mar;\
mov mem,r14
/*
* QA(REG) : QA converts a queue pointer to mar & %mar form.
* REG is a scratch pad register and has the format:
* bits 7-2 from REG + 00 forms the offset within a page
* bits 1-0 is the page number
* Queues are 4-byte long, so it always fall in 4-byte boundary
* Queues can only be located in the first 4 pages
*/
#define QA(REG)\
mov ~03,brg;\
and brg,REG,mar;\
mov 03,brg;\
and brg,REG,%mar
/*
* GEBI(X,ADDR) : get a free buffer index
* 'bmap' to 'bmap'+16 indicate 128 buffers, each 128 bytes.
* A '1' in i-th bit postion indicates i-th buffer is buzy
* GEBI finds the first free buffer and returns its number
* in register X. If no buffer is free, jump to ADDR
* Turn on i-th bit
* X can't be r0
* using r0, X, brg, mar, %mar
*/
#define GEBI(X,ADDR)\
mov 0,brg;\
mov brg,X;\
mov 1,brg;\
mov brg,r0;\
mov bmap,mar;\
mov %bmap,%mar;\
5: mov mem,brg;\
brz 8f;\
6: br0 7f;\
br 9f;\
7: inc X;\
asl r0;\
mov 0,brg>>;\
br 6b;\
8: mov 8,brg|mar++;\
add brg,X,X|brg;\
br7 ADDR;\
br 5b;\
9: or mem,r0,mem
/*
* IBEG(X) : return buffer index X to pool (i.e. turn off bit in 'bmap')
* X can't be r0
* using r0, X, brg, mar, %mar
*/
#define IBEG(X)\
mov X,brg;\
brz 9f;\
mov bmap0,mar;\
mov %bmap0,%mar;\
6: mov 8,brg|mar++;\
sub brg,X;\
brc 6b;\
add brg,X;\
mov 1,brg;\
mov brg,r0;\
7: dec X;\
brz 8f;\
asl r0,r0|brg;\
br 7b;\
8: mov 0,r0;\
addn brg,r0;\
and mem,r0,mem;\
9:
/*
* BITA(I,X,Y,Z): buffer index (in I) to address (X:LSB, Y, Z:MSB)
*/
#define BITA(I,X,Y,Z)\
mov baddr,mar;\
mov %baddr,%mar;\
mov mem,X|mar++;\
mov mem,Y|mar++;\
mov mem,Z;\
8: dec I;\
brz 9f;\
mov BSIZE2,brg;\
add brg,X;\
adc Y;\
adc Z;\
br 8b;\
9:
/*
* Subroutine CALL and RETURN macros
*/
#define CALL(X,SAVE)\
mov %SAVE,%mar;\
mov SAVE,mar;\
mov %9f,mem|mar++;\
mov 9f,mem;\
mov %X,brg;\
mov brg,pcr;\
jmp X;\
9:
#define RETURN(SAVE) \
mov %SAVE,%mar;\
mov SAVE,mar;\
mov mem,pcr|mar++;\
jmp (mem)
/*
* ERROR(X) --- store error code in brg, jump to errlog
*/
#define ERROR(X) \
mov %errlog,brg;\
mov brg,pcr;\
mov X,brg;\
jmp errlog
/*
* Macro BRB(X,Y,Z): if bit Y is on in X, then branch to Z
* X is a scratch pat register
* Macro BRP(X,Y,Z): if bit Y is on in X, then branch to Z
* X may not be a scratch pat register
*/
#define BRB(X,Y,Z) \
mov ~Y,brg;\
or brg,X,-;\
brz Z
#define BRP(X,Y,Z) \
mov X,r0;\
mov ~Y,brg;\
or brg,r0,-;\
brz Z
/*
* CHK(X,Y): set flag X on Y-th check word
*/
#ifdef CHECK
#define CHK(X,Y)\
mov Y,brg;\
mov brg,r0;\
mov check,brg;\
add brg,r0,mar;\
mov %check,%mar;\
mov X,brg;\
mov brg,r0;\
or mem,r0,mem
#else
#define CHK(X,Y)
#endif
/*
* CHK1(X,Y): set flag X on Y-th check word
* same as CHK except restore page register (r8)
*/
#ifdef CHECK
#define CHK1(X,Y)\
CHK(X,Y);\
mov r8,%mar
#else
#define CHK1(X,Y)
#endif
/*
* GLTE(CHAN) : CHAN is the channel #
* LTE size is 32 bytes for each channel
* When exit, r8(%mar), r10(mar) = addr of LTE
* Using r8, r10, brg, mar, mem
*/
#define GLTE(CHAN)\
mov CHAN,brg;\
mov brg,brg>>;\
mov brg,brg>>;\
mov brg,brg>>;\
mov brg,r8;\
mov 0340,brg;\
and brg,r8,brg;\
mov brg,r10|mar;\
mov 037,brg;\
and brg,r8;\
mov %dzst,brg;\
add brg,r8,r8|%mar
/*
* INCA(X,Y,Z,AMOUNT) - inc the content of registers X, Y, Z
* (Z most significant) by AMOUNT
* X, Y, Z are scratch pad registers
* Using X, Y, Z, brg
*/
#define INCA(X,Y,Z,AMOUNT)\
mov AMOUNT,brg;\
add brg,X;\
adc Y;\
adc Z
/*
* SPUTTWO(Z,ERR) - put two bytes from odl & odh to cpu
* cpu addresses are in oal (bits 7-0), oah (bits 15-8),
* and Z (bits 17-16)
* If error, go to ERR.
* When exit, cpu addresses are NOT incremented by 2
* Does NOT wait for UNIBUS to complete
* Using r0, r1, brg, npr, oal, oah, odl, odh, mar, mem, X, Y, Z.
*/
#define SPUTTWO(Z,ERR)\
asl Z,brg;\
mov brg,r0;\
asl r0;\
mov nprx,r1;\
mov ~(BRQ|ACLO|(3<<2)),brg;\
and brg,r1,brg;\
or brg,r0,nprx /* set up bits 17-16 */;\
mov NRQ|OUT,brg;\
mov brg,npr /* issue unibus request */;\
BUSWAIT
/*
* PUTTWO(X,Y,Z,ERR) - put two bytes from odl & odh to cpu
* cpu addresses are stored in X (bits 7-0)
* Y (bits 15-8) and Z (bits 17-16)
* If error, go to ERR.
* When exit, cpu addresses are incremented by 2
* Using r0, r1, brg, npr, oal, oah, odl, odh, mar, mem, X, Y, Z.
*/
#define PUTTWO(X,Y,Z,ERR)\
mov X,brg;\
mov brg,oal;\
mov Y,brg;\
mov brg,oah;\
SPUTTWO(Z,ERR);\
INCA(X,Y,Z,2);\
BUSWAIT
/*
* SPUTONE(Z,ERR) - put one bytes from odl/odh to cpu
* cpu addresses are in oal (bits 7-0), oah (bits 15-8),
* and Z (bits 17-16)
* If error, go to ERR.
* When exit, cpu addresses are NOT incremented by 1
* Does NOT wait for UNIBUS to complete
* Using r0, r1, brg, npr, oal, oah, odl, odh, mar, mem, Z.
*/
#define SPUTONE(Z,ERR)\
asl Z,brg;\
mov brg,r0;\
asl r0;\
mov nprx,r1;\
mov ~(BRQ|ACLO|(3<<2)),brg;\
and brg,r1,brg;\
or brg,r0,nprx /* set up bits 17-16 */;\
mov NRQ|OUT|BYTE,brg;\
mov brg,npr /* issue unibus request */;\
BUSWAIT
/*
* PUTONE(X,Y,Z,ERR) - put one bytes from odl/odh to cpu
* cpu addresses are stored in X (bits 7-0)
* Y (bits 15-8) and Z (bits 17-16)
* If error, go to ERR.
* When exit, cpu addresses are incremented by 1
* Using r0, r1, brg, npr, oal, oah, odl, odh, mar, mem, X, Y, Z.
*/
#define PUTONE(X,Y,Z,ERR)\
mov X,brg;\
mov brg,oal;\
mov Y,brg;\
mov brg,oah;\
SPUTONE(Z,ERR);\
INCA(X,Y,Z,1);\
BUSWAIT
/*
* SGETTWO(X,Y,Z,ERR) - get two bytes into idl & idh from cpu
* cpu addresses are stored in X (bits 7-0)
* Y (bits 15-8) and Z (bits 17-16)
* If error, go to ERR.
* Does NOT wait for UNIBUS to complete
* When exit, cpu addresses are incremented by 2
* Using r0, brg, npr, ial, iah, idl, idh, mar, mem, X, Y, Z.
*/
#define SGETTWO(X,Y,Z,ERR)\
mov X,brg;\
mov brg,ial;\
mov Y,brg;\
mov brg,iah;\
asl Z,brg;\
mov brg,r0;\
asl r0;\
mov NRQ,brg;\
or brg,r0,npr;\
INCA(X,Y,Z,2);\
BUSWAIT
/*
* GETTWO(X,Y,Z,ERR) - get two bytes into idl & idh from cpu
* cpu addresses are stored in X (bits 7-0)
* Y (bits 15-8) and Z (bits 17-16)
* If error, go to ERR.
* When exit, cpu addresses are incremented by 2
* Using r0, brg, npr, ial, iah, idl, idh, mar, mem, X, Y, Z.
*/
#define GETTWO(X,Y,Z,ERR)\
SGETTWO(X,Y,Z,ERR);\
BUSWAIT
/*
* MOD1(X,Y,Z) : Z = (X==Y)? 0 : X
* X, Y, Z are scratch pad registers
* X, Y won't be changed when returned
* Using brg
*/
#define MOD1(X,Y,Z)\
mov X,brg;\
addn brg,Y,-;\
brz 8f;\
br 9f;\
8: mov 0,brg;\
9: mov brg,Z
/*
* MOD0(X,Y,Z) - Z = (X<0)? (X+Y) : (X)
* X, Y, Z are scratch pad registers
* X, Y won't be changed when returned
* Using brg
*/
#define MOD0(X,Y,Z)\
mov X,brg;\
br7 8f;\
br 9f;\
8: add brg,Y,brg;\
9: mov brg,Z
/*
* TIMES(W,X,Y,Z) - Y(hibyte)Z(low) = W * X
* W, X, Y, Z are scratch pad registers
* W, X, Y, Z can't be the same
* X, Y, Z can't be r0
* X, W won't be changed when returned
* Using brg, r0
*/
#define TIMES(W,X,Y,Z)\
mov 0,brg;\
mov brg,Y;\
mov brg,Z;\
mov W,brg;\
mov brg,r0;\
mov X,brg;\
8: dec r0;\
brz 9f;\
add brg,Z;\
adc Y;\
br 8b;\
9:
/*
* BIT(X,Y) - bit pattern - Y = (1 << (x))
* X, Y are scratch pat registers and can't be the same
* usually 0 <= X <= 7
*/
#define BIT(X,Y)\
mov 1,brg;\
mov brg,Y;\
8: dec X;\
brz 9f;\
asl Y;\
br 8b;\
9:
/*
* SENDDATA(HI,LO) : send HI to lur1 and LO to lur0
* using brg, lur0, lur1, lur2 (if KDI)
* using brg, odl, odh, oal, oah, mem, mar, npr, nprx, r0 (DR11C)
*/
#define SENDDATA(HI,LO) \
mov HI,brg;\
mov brg,OHI;\
mov LO,brg;\
mov brg,OLO;\
SENDD
#ifdef KDI
#ifdef CPM422
/*
* cpm422 can't send an envelop within 2us
* using brg, r0
*/
#define D422(X) DELAY(X)
#else
#define D422(X)
#endif
/*
* DELAY(X): some time
* delay 400*(X+1) ns
* using r0, brg
*/
#define DELAY(X) \
mov X,brg;\
mov brg,r0;\
9: dec r0;\
brc 9b
/*
* READDATA(LOC) : read data in lur0 (lo byte) and lur5 (hi byte)
* if data is not ready (i.e. DKFRDY (bit 0) is not set), goto LOC.
* using lur0, lur1, lur5, lur6, brg
*/
#define READDATA(LOC) \
mov lur6,brg;\
br0 8f;\
br LOC;\
8:
/*
* SENDD : OLO and OHI have been loaded, just trigger lur2
*/
#define SENDD\
mov 0,brg;\
mov brg,lur2 /* strobe */
/*
* SENDHEAD(CHAN): send DKMARK with channel #
* using brg, lur0, lur1, lur2
*/
#define SENDHEAD(CHAN)\
SENDDATA(D_WHEAD,CHAN)
/*
* SENDPACK(SEQ) : send seq# to seq fifo
* SEQ is in a scratch pad register
* using brg, lur1, lur2, SEQ
* using also lur6 to check that the transmitter becomes
* ready again. We busy wait until it does.
* We the read the sequence number so that the busy
* wait loop will be valid the next time
*/
#define SENDPACK(SEQ) \
mov D_XPACK,brg;\
mov brg,lur1;\
SENDD;\
1: mov lur6,brg;\
br1 1f;\
br 1b;\
1: mov D_OSEQ,brg;\
mov brg,lur1;\
mov lur1,brg /*read strobe*/
/*
* SENDCMD(CMD)
*/
#define SENDCMD(CMD)\
mov CMD,brg;\
mov brg,lur1;\
D422(3)
#else
/*
* DR11-C specific macros
*/
/*
* DELAY(X): DR11C is slow enough and don't need delay
*/
#define DELAY(X)
/*
* READCMD : read csr word in the DR-11C
* Input: csraddr is the csr unibus address
* Output: idl (low-byte) and idh (hi-byte) of the csr
* Using ial, iah, mar, mem, r0, brg, npr
*/
#define READCMD\
mov %csraddr,%mar;\
mov csraddr,mar;\
READDR
/*
* READDATA : read dki word of the DR-11C
* Input: dkiaddr is the dki unibus address
* Output: idl (low-byte) and idh (hi-byte) of the dki
* Using ial, iah, mar, mem, r0, brg, npr
*/
#define READDATA(LOC)\
READCMD;\
mov idh,brg;\
br7 9f;\
br LOC;\
9:;\
mov %dkiaddr,%mar;\
mov dkiaddr,mar;\
READDR
/*
* READDR : read a word whose unibus addr is pointed by mar
*/
#define READDR\
mov mem,ial|mar++;\
mov mem,iah|mar++;\
mov mem,r0;\
asl r0;\
asl r0;\
mov NRQ,brg;\
or brg,r0,npr;\
BUSWAIT
/*
/*
* WRITEDR : write odl and odh to unibus addr pointed by mar
*/
#define WRITEDR\
mov nprx,r0;\
mov ~(BRQ|ACLO|(3<<2)),brg;\
and brg,r0,brg;\
mov mem,oal|mar++;\
mov mem,oah|mar++;\
mov mem,r0;\
asl r0;\
asl r0;\
or brg,r0,nprx;\
mov OUT|NRQ,brg;\
mov brg,npr;\
BUSWAIT
/*
* SENDCMD : Issue a DR-11C command by outputing csr
* Using odl, odh, oal, oah, mar, mem, brg, npr, nprx, r0
*/
#define SENDCMD(CMD)\
mov CMD,brg;\
mov brg,odl;\
mov 0,brg;\
mov brg,odh;\
mov %csraddr,%mar;\
mov csraddr,mar;\
WRITEDR
/*
* SENDD: OHI, OLO have been loaded
* Using odl, odh, oal, oah, mar, mem, brg, npr, nprx, r0
*/
#define SENDD\
mov %dkoaddr,%mar;\
mov dkoaddr,mar;\
WRITEDR
/*
* SENDHEAD(CHAN) : send DKMARK with channel #
* channel # can't be in r0
* using odl, odh, oal, oah, mar, %mar, mem, brg, npr, nprx, r0
*/
#define SENDHEAD(CHAN) \
SENDCMD(D_WRITE);\
SENDDATA(D_WHEAD,CHAN)
/*
* SENDPACK(SEQ) : send seq# to seq fifo
* SEQ can't be in r0
* using odl, odh, oal, oah, mar, %mar, mem, brg, npr, nprx, r0
*/
#define SENDPACK(SEQ) \
SENDCMD(D_XPACK);\
SENDDATA(SEQ,ZERO)
#endif
/*
* Data definitions
*/
.data
/*
* Global data structures
*/
.org 0
/*
* check point code
*/
check: .byte 0,0,0,0,0,0,0
/*
* 1 ms timer
* 16 times 50-us timer expires ==> set this timer
*/
clk1ms: .byte 0
/*
* 5 sec timer : 4096 * 1ms
* Every time clk1ms expires (1ms gone by), clk5s gets decremented
*/
clk5s: .byte 0,0
/*
* temp storage
*/
tmp: .byte 0,0,0,0,0,0,0,0,0,0,0,0
/*
* return code: code, lenlo, lenhi, cntl, mode
*/
repinfo: .byte 0
replen: .byte 0,0
repctl: .byte 0
repmode: .byte 0
/*
* report seq#
*/
kseq: .byte 0
/*
* # of bad packets received so far
*/
badpack: .byte 0
/*
* temp storage for output routine
*/
blklen: .byte 0
/*
* a flag indicates a cntl char was rcv (used in subr.s)
*/
icntl: .byte 0
/*
* input state: bit7 - RBLEN>0; bit0 - 1st byte of a pair is now in odl
*/
iflag: .byte 0
/*
* chan#
*/
chan: .byte 0
/*
* seq#
*/
pseq: .byte 0
/*
* save r13/r12/r1/... when calling 'rcv'
*/
rcvsave: .byte 0,0,0,0
/*
* save area for r12 in report
*/
repsave: .byte 0,0,0,0
/*
* buffer map: 16 locations indicate 16*8 (128) buffers, each 128 bytes
*/
bmap0: .byte 0
bmap: .org .+16
/*
* timer map: for max 96 channels
*/
timemap: .org .+12
/*
* bit pattern
*/
bitpatt: .byte BIT0,BIT1,BIT2,BIT3,BIT4,BIT5,BIT6,BIT7
/*
* starting addresses of host buffer
*/
baddr: .byte 0,0,0
/*
* Addresses for cmdbuf, tail of cmdbuf, statbuf, head of statbuf,
*/
cbaddr: .byte 0,0,0
cbtail: .byte 0,0,0
sbaddr: .byte 0,0,0
sbhead: .byte 0,0,0
/*
* CALL/RETURN return address
*/
s.send: .byte 0,0
s.rcv: .byte 0,0
s.report: .byte 0,0
s.clean: .byte 0,0
s.copy1: .byte 0,0
s.cktimer: .byte 0,0
s.strailer: .byte 0,0
/*
* dr11c specific
*/
#ifdef DR11C
/*
* every time PCLK expires, r_timer gets decremented.
* if r_timer reaches -1, then read CSR to check R/TDONE
*/
r_timer: .byte 0
/*
* UNIBUS addresses for the DR11C
* Bits 7-0 in 1st byte, 15-8 in 2nd, 17-16 in 3rd (right-adjust)
*/
csraddr: .byte 0,0,0
dkoaddr: .byte 0,0,0
dkiaddr: .byte 0,0,0
#endif
/*
* output active queue
*/
outq: .byte NIL
outq1: .byte NIL /* work area */
/*
* Queue entries
*/
inqueue:
.org 4*256
/*
* LTE tables from page 4 to 15, each entry is 32 bytes
*/
dzst:
/*
* Instruction text starts here
*/
.text
/*
* Segment 0
*
* This is the main segment
*/
.org 0
seg0:
init:
/*
* Set csr0 to idle state (i.e. 0)
*/
mov 0,brg
mov brg,csr0
/*
* initialize all global variables
*/
mov brg,mar
mov brg,%mar
mov inqueue-1,brg
mov brg,r0
init1:
mov 0,mem|mar++
dec r0
brc init1
/*
* initialize special variables (~0)
*/
mov outq,mar
mov %outq,%mar
mov NIL,mem|mar++
mov NIL,mem|mar++
mov %bitpatt,%mar
mov bitpatt,mar
mov 7,r7
mov 1,r1
1:
mov r1,mem|mar++
dec r7
brz 2f
asl r1
br 1b
2:
/*
* Initialize the free-buffer list
* page 0-7 is for global data and queues
* page 8-15 for LTE entries
*/
#define NLTE (CHANMODS+7)/8
#define NPQ 4
#define NQE ((NPQ*256-((inqueue+3)&~3))/4)
/*
* Initialize the list of available queue entries
*/
mov NIL,brg
mov brg,r14
mov (inqueue+3)&~3,brg
mov brg,r0
mov NQE-2,brg
mov brg,r1
init4:
FREEQ(r0)
mov 4,brg /* queue is 4-byte long */
add brg,r0
adc r0
dec r1
brc init4
/*
* Initialize LTE queue pointers
*/
mov CHANMODS-1,brg
mov brg,r9
init6:
/*
* reset all LTE values: (can be done globally)
*/
GLTE(r9)
mov 31,brg /* 32: size of LTE */
mov brg,r0
1:
mov 0,mem|mar++
dec r0
brc 1b
/*
* initialized C_X to idle and RQ/RB to nil
* initailize whatever else is needed
*/
mov r8,%mar
mov C_X,brg
add brg,r10,mar
mov XIDLE,mem
mov C_RQ,brg
add brg,r10,mar
mov NIL,mem
mov C_RB,brg
add brg,r10,mar
mov NIL,mem
dec r9
brc init6
/*
* Go to disp
*/
br disp
/*
* Dispatcher loop--keep looking for something to do
*/
disp:
/*
* If csr0 == 0, does nothing and loop.
* If csr0 == 1, read addresses from csr2~7.
* If csr0 == 2, normal operation (i.e. take command from
* cmdbuff and put report to statbuf).
*/
mov csr0,brg
mov 3,r3
and brg,r3,brg
br1 disp2 /* normal operation */
br0 disp1 /* direct command */
mov brg,r0
dec r0,-
brz disp /* idle */
ERROR(E_SW)
disp1:
/*
* Get init information from structure pointed by csr2~4
* struct init {
* paddr_t *cmdaddr;
* paddr_t *stataddr;
* paddr_t *bufaddr
* paddr_t *csraddr
* };
*/
mov csr2,r13
mov csr3,r12
mov csr4,r11
GETTWO(r13,r12,r11,err_bus)
mov idl,r5
GETTWO(r13,r12,r11,err_bus)
mov cbaddr,mar
mov %cbaddr,%mar
mov idl,mem|mar++ /* cbaddr */
mov idh,mem|mar++
mov r5,mem|mar++
mov idl,mem|mar++ /* cbtail */
mov idh,mem|mar++
mov r5,mem|mar++
GETTWO(r13,r12,r11,err_bus)
mov idl,r5
GETTWO(r13,r12,r11,err_bus)
mov sbaddr,mar
mov %sbaddr,%mar
mov idl,mem|mar++ /* sbaddr */
mov idh,mem|mar++
mov r5,mem|mar++
mov idl,mem|mar++ /* sbhead */
mov idh,mem|mar++
mov r5,mem|mar++
GETTWO(r13,r12,r11,err_bus)
mov idl,r5
GETTWO(r13,r12,r11,err_bus)
mov baddr,mar
mov %baddr,%mar
mov idl,mem|mar++ /* bufaddr */
mov idh,mem|mar++
mov r5,mem|mar++
#ifdef KDI
/*
* Issue D_RESET command and set dko to 0 to clear all fifo's
*/
mov D_RESET,brg
mov brg,lur1
mov brg,lur2
#else
/*
* Record the unibus address (csr) for this DR-11
* addr(dko) = addr(csr) + 2
* addr(dki) = addr(csr) + 4
*/
GETTWO(r13,r12,r11,err_bus)
mov idl,r5
GETTWO(r13,r12,r11,err_bus)
mov idl,r7
mov idh,r6
mov 3,brg
mov brg,r5 /* io page */
mov %csraddr,%mar
mov csraddr,mar
mov r7,mem|mar++
mov r6,mem|mar++
mov r5,mem|mar++
/*
* Now mar points to dkoaddr
*/
mov 2,brg
add brg,r7,mem|mar++
adc r6,mem|mar++
adc r5,mem|mar++
/*
* Now mar points to dkiaddr
*/
mov 4,brg
add brg,r7,mem|mar++
adc r6,mem|mar++
adc r5,mem
/*
* Issue D_OSEQ command and set dko to 0 to clear all fifo's
*/
mov D_OSEQ,brg
mov brg,odl
mov 0,brg
mov brg,odh
SENDCMD(D_OSEQ)
SENDDATA(ZERO,ZERO)
#endif
/*
* Now set csr0 to 2 (i.e. normal operation)
* Set head/tail of all circular buffers to 0
*/
mov 0,brg
mov brg,csr2
mov brg,csr3
mov brg,csr4
mov brg,csr5
mov brg,csr6
mov brg,csr7
mov 2,brg
mov brg,csr0
br disp
disp2:
/*
* This is normal operation loop
*/
mov csr0,brg
br0 disp2
/*
* assume kmc is fast enough so that cmdbuf never overflows
* If HC==TC, then no command available and loop
*/
mov HC,brg /* head of cmdbuf */
mov TC,r0 /* tail of cmdbuf */
addn brg,r0,-
brz disp3
/*
* Read the command pointed by TC
* Put k_type in r1, k_chan in r9, k_len in r7-r6,
* k_ctl/time in r5, k_mode in r4, k_addr in r3-r2-idl-idh
*/
mov cbtail,mar
mov %cbtail,%mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r11|mar++
GETTWO(r13,r12,r11,err_bus)
mov idl,r1
GETTWO(r13,r12,r11,err_bus)
mov idl,r9
GETTWO(r13,r12,r11,err_bus)
mov idl,r7
mov idh,r6
GETTWO(r13,r12,r11,err_bus)
mov idl,r5
mov idh,r4
GETTWO(r13,r12,r11,err_bus)
mov idl,r3
mov idh,r2
GETTWO(r13,r12,r11,err_bus)
/*
* Now modify TC and cbtail.
* If TC==BUFSIZ-1, then TC=0 and cbtail=cbaddr
*/
mov TC,r0
mov BUFSIZ-1,brg
sub brg,r0,- /* TC-(BUFSIZ-1) */
brc 1f
inc r0,TC
br 2f
1: mov 0,brg /* reset TC */
mov brg,TC
mov cbaddr,mar
mov %cbaddr,%mar
mov mem,r13|mar++
mov mem,r12|mar++
mov mem,r11
2:
/*
* Restore cbtail
*/
mov cbtail,mar
mov %cbtail,%mar
mov r13,mem|mar++
mov r12,mem|mar++
mov r11,mem|mar++
/*
* Decode the command
* switch (k_type) {
* case KC_SEND: goto kc_send;
* case KC_RCVB: goto kc_rcvb;
* case KC_SOI: goto kc_soi;
* case KC_CMD: goto kc_cmd;
* case KC_FLAG: goto kc_flag;
* case KC_TDK: goto kc_tdk;
* case KC_XINIT: goto kc_xinit;
* case KC_CLOSE: goto kc_close;
* case KC_INIT: goto kc_init;
* }
*/
GLTE(r9) /* set up r8/r10 */
mov KC_SEND,brg
addn brg,r1,-
brz kc_send
mov KC_RCVB,brg
addn brg,r1,-
brz kc_rcvb
mov KC_SOI,brg
addn brg,r1,-
brz kc_soi
mov KC_CMD,brg
addn brg,r1,-
brz kc_cmd
mov KC_FLAG,brg
addn brg,r1,-
brz kc_flag
mov KC_TDK,brg
addn brg,r1,-
brz kc_tdk
mov KC_XINIT,brg
addn brg,r1,-
brz kc_xinit
mov KC_CLOSE,brg
addn brg,r1,-
brz kc_close
mov KC_INIT,brg
addn brg,r1,-
brz kc_init
ERROR(E_CMD)
br disp3
kc_init:
/*
* Process a KC_INIT command
* r5 is either D_CALL or D_IDL1
* C_X = XINIT; goto kc_reset
*/
CHK1(B0_KCIT,0)
mov C_X,brg
add brg,r10,mar
mov XINIT,mem
br kc_reset /* expect to rcv D_TALK from ty-4 */
kc_xinit:
/*
* Process a KC_XINIT command
* C_X = XINIT; C_XLEN = 0; send(INIT1);
*/
CHK1(B0_KCIT,0)
mov C_X,brg
add brg,r10,mar
mov XINIT,mem|mar++
/*
mov 0,mem
*/
mov C_XLEN,brg
add brg,r10,mar
mov 0,mem|mar++
mov 0,mem
mov C_XCNTL,brg
add brg,r10,mar
mov 0,mem
mov I_INIT1,brg
mov brg,r1
CALL(send,s.send) /* can simply goto 'time' */
br disp3
kc_close:
/*
* process KC_CLOSE command
* k_chan is the channel #
* if (C_RLEN) report(KS_RDB, chan);
* goto kc_reset
*/
CHK1(B0_KCCS,0)
mov C_X,brg
add brg,r10,mar
mov XIDLE,mem|mar++
mov 0,mem /* C_X1 = 0 */
mov C_RLEN,brg
add brg,r10,mar
mov mem,r7|brg
mov brg,r0|mar++
mov mem,r6
or mem,r0
dec r0,-
brz kc_reset
/*
* report (KS_RDB,chan) with mode SABORT
*/
mov repinfo,mar
mov %repinfo,%mar
mov KS_RDB,mem|mar++
mov r7,mem|mar++ /* residue length */
mov r6,mem|mar++
mov 0,mem|mar++ /* cntl char */
mov SABORT,mem /* RCV mode */
CALL(report,s.report)
kc_reset:
/*
* Reset RLEN, XLEN.
* while (RQ!=NIL) free the queues and buffers
*/
mov r8,%mar
mov C_RLEN,brg
add brg,r10,mar
mov 0,mem|mar++
mov 0,mem
mov C_RBLEN,brg
add brg,r10,mar
mov 0,mem|mar++
mov 0,mem
mov C_TA0,brg
add brg,r10,mar
mov 0,mem|mar++
mov 0,mem
mov C_C,brg
add brg,r10,mar
mov 0,mem
mov C_RQ,brg
add brg,r10,mar
mov mem,r2
brz kc_rs2
mov NIL,mem
CALL(clean,s.clean)
mov r8,%mar
kc_rs2:
mov C_RB,brg
add brg,r10,mar
mov mem,r2
brz kc_rs4
mov NIL,mem
CALL(clean,s.clean)
kc_rs4:
mov r8,%mar
mov C_XLEN,brg
add brg,r10,mar
mov 0,mem|mar++
mov 0,mem
mov C_XCNTL,brg
add brg,r10,mar
mov 0,mem
/*
* remove chan# from 'outq'
* r2 is running pointer for outq (currently looked at)
* r3 is the next outq entry
* r4 is the running pointer for outq1
*/
mov outq,mar
mov %outq,%mar
mov mem,r2
kc_rs6:
brz kc_rs14
QA(r2)
mov mem,r3
mov NIL,mem|mar++
addn mem,r9,-
brz kc_rs12 /* delete this chan# */
mov outq1,mar
mov %outq1,%mar
kc_rs8:
mov mem,r4
brz kc_rs10
QA(r4)
br kc_rs8 /* try to find the end of outq1 */
kc_rs10:
/*
* found the end of outq1, append r2 here
*/
mov r2,mem
kc_rs11:
/*
* put r3 in r2 position
*/
mov r3,brg
mov brg,r2
br kc_rs6
kc_rs12:
FREEQ(r2)
br kc_rs11
kc_rs14:
/*
* restore outq from outq1
*/
mov outq1,mar
mov %outq1,%mar
mov mem,brg
mov outq,mar
mov %outq,%mar
mov brg,mem|mar++
mov NIL,mem
br disp3
kc_soi:
/*
* Process a KC_SOI command
* send 2 bytes in r7 (lo) and r6 (hi) to chan r9
* bypass error/flow control mechanism
*/
CHK1(B0_KCSO,0)
mov tmp,mar
mov %tmp,%mar
mov r9,mem|mar++
mov D_WHEAD,mem|mar++
mov I_SOI,mem|mar++
mov D_WCNTL,mem|mar++
mov r7,mem|mar++
mov D_WDATA,mem|mar++
mov r6,mem|mar++
mov D_WDATA,mem|mar++
mov I_EOI,mem|mar++
mov D_WCNTL,mem|mar++
mov ZERO,mem|mar++ /* seq# */
mov D_XPACK,mem|mar++
#ifdef DR11C
SENDCMD(D_WRITE) /* for dr11-c */
#endif
mov 0,brg
mov brg,r5
kc_so1:
mov %tmp,%mar
mov tmp,brg
add brg,r5,mar
mov mem,OLO|mar++
mov mem,OHI|mar++
SENDD
inc r5
inc r5
mov 10,brg
addn brg,r5,-
brz kc_so3 /* issue XPACK */
brc disp3
br kc_so1
kc_so3:
SENDCMD(D_XPACK) /* dor dr11-c */
br kc_so1
kc_send:
/*
* Process a KC_SEND command
* The format is:
* k_chan is the chan #
* r7-r6: XLEN; r5: XCNTL; r4: mode; idl-idh-r3: XADDR;
*/
CHK1(B0_KCSD,0)
/*
* If this chan already in output waiting (C_XLEN!=0), error
*/
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 1f
br err_dup
1:
/*
* Fill LTE info
*/
mov C_XLEN,brg
add brg,r10,mar
mov r7,mem|mar++ /* C_XLEN */
mov r6,mem|mar++
mov idl,mem|mar++ /* C_XADDR */
mov idh,mem|mar++
mov r3,mem|mar++
mov C_XCNTL,brg
add brg,r10,mar
mov r5,mem
/*
* if mode = XBOTM (i.e. 1<<7), set this bit in C_X1;
* otherwise reset this bit
*/
mov C_X1,brg
add brg,r10,mar
mov mem,r0
mov ~XBOTM,brg
or brg,r4,-
brz 1f
and brg,r0,mem
br 2f
1:
orn brg,r0,mem
2:
/*
* if xlen (r7,r6) and xcntl (r5) are all 0, set XNIL for sending
* trailer only
*/
mov r7,brg
or brg,r6,brg
or brg,r5
dec r5,-
brz kc_sn6
/*
* if the channel is not active (i.e. hasn't rcv ainit)
*/
mov C_X,brg
add brg,r10,mar
mov mem,brg
br1 kc_sn2 /* XACT is set */
br disp3
kc_sn2:
/*
* this channel is output active: put it in 'outq'
*/
GETQ(r1,noqb)
mov NIL,mem|mar++
mov r9,mem
mov outq,mar
mov %outq,%mar
kc_sn3:
mov mem,r2
brz kc_sn5
QA(r2)
br kc_sn3
kc_sn5:
mov r1,mem
br disp3
kc_sn6:
/*
* send trailer mode is on (i.e. 0 data byte, no cntl byte)
*/
mov C_X,brg
add brg,r10,mar
mov mem,brg|mar++
mov mem,r7
mov XNIL,mem
or mem,r7,mem
br1 kc_sn7
br disp3 /* hasn't rcv ainit */
kc_sn7:
CALL(strailer,s.strailer)
br disp3
kc_rcvb:
/*
* process a receive-buffer command
* The format is:
* k_chan is the chan# to be input
* r7-r6: RLEN; r5: INITIM; r4: mode; idl-idh-r3: RADDR;
*/
CHK1(B0_KCRB,0)
mov C_RLEN,brg
add brg,r10,mar
mov mem,r13
mov r7,mem|mar++
mov mem,r12
mov r6,mem|mar++
mov idl,mem|mar++ /* RADDR */
mov idh,mem|mar++
mov r3,mem
mov C_INITIM,brg
add brg,r10,mar
mov r5,mem
mov C_Y,brg
add brg,r10,mar
mov r4,mem
/*
* If there was an unfinished read-buf, report it
* i.e. if C_RLEN > 0
*/
mov r13,brg
or brg,r12,brg
mov brg,r0
dec r0,-
brz kc_rc4
/*
* abort the old pending read
* report whatever having been received
*/
mov %repinfo,%mar
mov repinfo,mar
mov KS_RDB,mem|mar++
mov r13,mem|mar++
mov r12,mem|mar++ /* residue length */
mov 0,mem|mar++ /* cntl */
mov SABORT,mem /* mode */
CALL(report,s.report)
kc_rc4:
/*
* if (char mode && YTIME && (RB != NULL)) set YEXPIRE
*/
mov r8,%mar
mov C_X1,brg
add brg,r10,mar
mov mem,r0
mov XBLK,brg
orn brg,r0,-
brz kc_rc7
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YTIME,brg
orn brg,r0,-
brz 1f
mov C_RB,brg
br kc_rc8
1:
mov C_RB,brg
add brg,r10,mar
mov mem,brg
brz disp3
/*
* set YEXPIRE
*/
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YEXPIRE,brg
or brg,r0,mem
kc_rc6:
/*
* call rcv to copy RQ/RB to RADDR
*/
CALL(rcv,s.rcv) /* copy C_RQ to RADDR */
br disp3
kc_rc7: mov C_RQ,brg
kc_rc8: add brg,r10,mar
mov mem,brg
brz disp3
br kc_rc6
kc_cmd:
/*
* process KC_CMD command
* k_chan is the chan #
* r7 is the subcommand
* only OFLUSH is implemented, others will be added later
*/
CHK1(B0_KCCM,0)
br kc_rs4
kc_flag:
/*
* process KC_FLAG command
* k_chan is the chan #
* 1st two bytes (r7-r6) are iflag, next two (r5-r4) are oflag
* TO BE DONE LATER
CHK1(B0_KCFG,0)
*/
br disp3
kc_one:
/*
* process KC_ONE command
* k_chan is the chan #
* send one byte (control byte) in r7 to ty-4
* TO BE ADDED LATER
CHK1(B0_KC1,0)
*/
br disp3
kc_tdk:
/*
* process KC_TDK command
* k_chan is the chan #
* TO BE ADDED LATER
*/
br disp3
kc_stime:
/*
* process KC_STIME command
* k_chan is the chan #
* r7 is the timer value
* TO BE ADDED LATER
*/
br disp3
disp3:
#ifdef KDI
/*
* check input data ready and output completion
* input ready is indicated by DKFRDY (bit 0)
* output ready is indicated by TRQRDY (bit 1)
*/
mov lur6,brg
br0 csrck2
/*
* since we are not reading seq fifo, bit 1 is always set
br1 csrck4
*/
#endif
BRP(nprx,PCLK,tick)
br disp2
tick:
/*
* 50-us timer expires, restart the timer
*/
mov nprx,r0
mov ~(BRQ|ACLO),brg
and brg,r0
mov PCLK,brg
or brg,r0,nprx
#ifdef DR11C
/*
* Dec the r_timer, and goto r_expire if r_timer reaches -1
*/
mov r_timer,mar
mov %r_timer,%mar
mov mem,r0
dec r0,mem
brz r_expire
br tick1
r_expire:
/*
* reset r_timer
*/
mov R_TIMER,mem
/*
* check input data ready, then output completion
*/
READCMD /* get csr in idl & idh */
/*
* If there is an input character available then go to csrck2
* DKRDONE is 1<<15 in dkcsr
*/
mov idh,brg
br7 csrck2
/*
* If there is an output data request then go to csrck4
* DKTDONE is 1<<7 in dkcsr
mov idl,brg
br7 csrck4
*/
#endif
tick1:
/*
* dec the 1ms timer and return if the result is non-negative
*/
mov clk1ms,mar
mov %clk1ms,%mar
mov mem,r0
dec r0,mem
brc tick10
mov CLK1MS,mem /* restore timer */
mov NGRP,brg
mov brg,r6
tick2:
/*
* 1ms timer expires: dec ITIME for each input chan which on timemap
* r6: row, r7: column, r5: map itself
*/
mov %timemap,%mar
mov timemap,brg
add brg,r6,mar
mov mem,r5|brg|mar++
mov 7,r7
tick3:
dec r5,-
brz tick4
tick3.2:
br7 tick5
asl r5,r5|brg
dec r7
br tick3.2
tick3.5:
asl r5,r5|brg
dec r7
brc tick3
tick4:
dec r6
brc tick2
br tick9
tick5:
/*
* found this channel (r6<<2 + r7) is timer active (i.e. YTIMACT)
*/
mov r6,brg
mov brg,r9
asl r9
asl r9
asl r9
mov r7,brg
add brg,r9 /* r9 is the chan # */
GLTE(r9)
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YTIME,brg
orn brg,r0,-
brz tick7
br timeerr
tick7:
/*
* timer processing is enabled for this chan
*/
mov YEXPIRE,brg
orn brg,r0,-
brz timeerr
mov YTIMACT,brg
orn brg,r0,-
brz 1f
br timeerr /* timer not active */
1:
/*
* timer is active, dec ITIME
*/
mov C_ITIME,brg
add brg,r10,mar
mov mem,r0
dec r0,mem
brc tick3.5 /* not reach zero yet */
/*
* timer expires: set YEXPIRE
*/
mov C_Y,brg
add brg,r10,mar
mov mem,r0
mov YEXPIRE,brg
or brg,r0,mem
/*
* YEXPIRE is set: call 'rcv'
*/
mov %rcvsave,%mar
mov rcvsave,mar
mov r5,mem|mar++
mov r6,mem|mar++
mov r7,mem|mar++
CALL(rcv,s.rcv)
mov %rcvsave,%mar
mov rcvsave,mar
mov mem,r5|mar++
mov mem,r6|mar++
mov mem,r7|mar++
CHK(B5_TIME,5)
tick8:
/*
* reset timemap for this chan
* the following was done in 'rcv'
mov %bitpatt,%mar
mov bitpatt,brg
add brg,r7,mar
mov mem,r0
mov %timemap,%mar
mov timemap,brg
add brg,r6,mar
xor mem,r0,mem
*/
br tick3.5
timeerr:
/*
* should never happen: will be removed after being debugged
*/
mov 0222,brg
mov brg,r15
br .
tick9:
/*
* dec 5 sec timer, goto timeout if expires
* steals this 50-us cycle and 'time' no returns
*/
mov clk5s,mar
mov %clk5s,%mar
mov mem,r0
dec r0
mov r0,mem|mar++
mov mem,r1
mov 0,brg
subc brg,r1,mem
and mem,r0,-
brz time
tick10:
/*
* if (outq) goto csrck4;
* This is the replacement of sending a dummy packet to chan 511
*/
mov outq,mar
mov %outq,%mar
mov mem,r0
brz disp2
csrck4:
/*
* Output data request--jump to output segment
*/
mov %out,brg
mov brg,pcr
jmp out
csrck2:
/*
* Input data available--jump to input segment
*/
mov %in,brg
mov brg,pcr
jmp in
time:
/*
* timeout routine
* for each active chan, if (S != R+1) send ENQ
*/
/*
* reinitialize the clk5s
*/
mov clk5s,mar
mov %clk5s,%mar
mov CLT0,mem|mar++
mov CLT1,mem
mov CHANMODS,brg
mov brg,r9 /* channel # */
time1:
dec r9
brz disp2
GLTE(r9) /* setup r8/r10 for LTE */
mov C_X,brg
add brg,r10,mar
mov mem,brg
br0 time1 /* bit 0 indicates un-initialized */
br1 time2 /* bit 1 indicates initialized */
/*
* INIT1 was sent and no reply; keep sending INIT1
*/
mov I_INIT1,brg
br time3
time2:
/*
* chan is active, if (S!=R+1) send ENQ
*/
mov C_S,brg
add brg,r10,mar
mov mem,r1|mar++
mov mem,r0
inc r0
mov WINDOW,brg
and brg,r0,brg
addn brg,r1,-
brz time1
mov C_X1,brg
add brg,r10,mar
mov mem,r0
mov ~(XACK|XREJ),brg
and brg,r0 /* reset XACK and XREJ */
mov XENQ,brg
or brg,r0,mem /* set XENQ */
mov I_ENQ,brg
time3:
mov brg,r1
CALL(send,s.send) /* argument in r9, r1 */
br time1
err_bus:
/*
* The Unibus transfer fails to complete within 20 usec
* Clear NEM bit, queue the error, and go to disp
*/
mov nprx,r0
mov ~(BRQ|ACLO|NEM),brg
and brg,r0,nprx
ERROR(E_BUS)
br disp
err_dup:
/*
* Two SEND command
*/
ERROR(E_DUP)
br disp
noqb:
/*
* no queue or buffer
*/
ERROR(E_NOQB)
br disp
errlog:
/*
* r9 - chan#
* brg - error code
* after interrupt cpu, go to init and wait for reinitialization
*/
mov repinfo,mar
mov %repinfo,%mar
mov KS_ERR,mem|mar++
mov brg,mem
CALL(report,s.report)
br disp2
/*
* End of segment 0
*/
endseg0:
/*
* Pick up code from other segments
*/
#include "output.s"
#include "input.s"
#include "subr.s"