/* * Subroutines */ .org 3072 seg3: /* * KMC initialization */ init: mov 0,brg mov brg,r13 mov brg,r14 mov brg,csr2 mov IEO,brg mov brg,csr0 /* * Initialize the free-buffer list */ #define NPQ 3 #define NQE (NPQ*256-((inqueue+3)&~3))/4 /* * Define the number of 16-byte input buffers */ #define NBUF 16*(16-4-NPQ) mov NPQ,brg mov brg,r0 mov NBUF-1,brg mov brg,r1 mov NIL,brg mov brg,r11 init2: RELEASE(r0); mov 16,brg add brg,r0 adc r0 dec r1 brc init2 /* * Initialize the list of available queue entries */ mov NIL,brg mov brg,r12 mov (inqueue+3)&~3,brg mov brg,r0 mov NQE-1,brg mov brg,r1 init4: FREEQ(r0) mov 4,brg add brg,r0 adc r0 dec r1 brc init4 /* * Initialize LTE queue pointers */ mov 3,brg mov brg,r8 init6: mov %dzst,brg add brg,r8,%mar mov 7,r7|mar init8: mov mem,r10 mov OUTBUF,brg add brg,r10,mar mov NIL,mem|mar++ mov NIL,mem|mar++ mov NIL,mem dec r7,r7|mar brc init8 dec r8 brc init6 /* * Return to caller */ RETURN /* * Carrier-on status check--executed once every 12.8 msec for each DZ */ mdmcheck: /* * If the 12.8 millisecond timer hasn't expired yet * then go to disp */ mov clock2,mar mov mem,r0 dec r0,mem brc dispret3 /* * Set up a unibus request for the current value of MSR */ mov csrget,mar mov mem,r2|mar++ mov mem,r1|mar++ mov mem,r0 mov 6,brg add brg,r2,brg mov brg,ial adc r1,brg mov brg,iah adc r0 mov 3,brg and brg,r0 asl r0 asl r0 mov NRQ,brg or brg,r0,npr /* * Wait for the unibus transfer to complete. * If an error occurs then go to buserr3. */ BUSWAIT(buserr3) /* * Get the previous value of the carrier-on status indicators * and save the new value. If the new value is the same as the * previous value then go to disp */ mov costatus,mar mov mem,r2 mov idh,mem addn mem,r2,- brz dispret3 /* * Initialize regs for loop which follows */ mov 0,brg mov brg,r7 mov 1,r1 /* * Set a bit in r2 for each line with changed status */ xor mem,r2 mov mem,r3 /* * Step through all lines for this DZ. * * For each line with changed status, set the carrier-on * flag on or off as appropriate */ mdmchk2: mov r1,brg orn brg,r2,- brz 1f br 2f 1: mov r7,mar mov mem,r10 mov FLAGS,brg add brg,r10,mar mov mem,r0 mov r1,brg orn brg,r3,- brz 1f mov ~CARR_ON,brg and brg,r0,mem br 2f 1: mov CARR_ON,brg or brg,r0,mem 2: asl r1 inc r7 mov 7,brg addn brg,r7,- brc 1f br mdmchk2 1: /* * If a carrier-on change report has already been requested for this DZ * then go to disp */ mov status,mar mov mem,r2 mov 1<<2,brg orn brg,r2,- brz dispret3 mov 1<<2,brg or brg,r2,mem /* * Insert the page for the current DZ at the end of the * coc-report-needed queue */ mov coclink,mar mov NIL,mem mov tailcocq,mar mov %tailcocq,%mar mov mem,r0 brz 1f mov r8,mem mov %dzst,brg add brg,r0,%mar mov coclink,mar mov r8,mem br 2f 1: mov headcocq,mar mov r8,mem|mar++ mov r8,mem 2: /* * Set the global flag which indicates that a * carrier-on change report has been requested */ mov CHKCOCQ,brg or brg,r14 /* * Go to disp */ br . br dispret3 /* * The 50-microsecond hardware timer has expired */ tick: /* * Reset the 50-microsecond timer */ mov nprx,r0 mov ~(BRQ|ACLO|(3<<2)),brg and brg,r0 mov PCLK,brg or brg,r0,nprx /* * The effect of the following code is to schedule a * csr check for a different DZ every 50(?) microseconds. * Since there are four possible DZ's, each DZ gets scheduled * for a csr check every 200 microseconds. This is approximately * a factor of five better than we need for 9600 baud (one character * every 1042 microseconds). */ /* * Increment r15. */ inc r15 /* * Set the DZ number from bits 1-0 of r15. */ mov 3,brg and brg,r15,brg mov brg,r8 /* * Set page register to page for this DZ */ mov %dzst,brg add brg,r8,%mar /* * If a base-in command has not been received yet for this DZ * then go to disp */ mov status,mar mov mem,brg br7 1f br dispret3 1: /* * If a csr check has already been requested for this DZ * then go to delaycheck */ br0 delaycheck /* * Set the bit which indicates that a csr check has already * been scheduled */ mov 1<<0,r1 or mem,r1,mem /* * Insert the page for the current DZ at the end of the * csr-check-needed queue */ mov csrlink,mar mov NIL,mem mov tailcsrq,mar mov %tailcsrq,%mar mov mem,r0 brz 1f mov r8,mem mov %dzst,brg add brg,r0,%mar mov csrlink,mar mov r8,mem br 2f 1: mov headcsrq,mar mov r8,mem|mar++ mov r8,mem 2: /* * Set global flag to indicate that a csr check has been requested */ mov CHKCSRQ,brg or brg,r14 delaycheck: /* * Set page register to page for this DZ */ mov %dzst,brg add brg,r8,%mar /* * Decrement the 16.7 msec timer. If the result is * non-negative then go to mdmcheck */ mov clock1,mar mov mem,r0 dec r0,mem brc dispret3 /* *** temp for testing *** */ /* brc mdmcheck */ /* * Reset the 16.7 msec timer */ mov 50,mem /* * The 16.7 msec timer has expired. Therefore we need to decrement * the count field for each lte which is currently in the twait * state (delaying) */ /* * Initialize registers for loop which follows */ mov 5,r5 mov 7,r7|mar /* * The following loop is executed once for each lte * in the page for the selected DZ. * * If we find a line which is in the twait state * then we decrement the count field of the lte. * If the result is negative then we put the line * back into state 1 and enable the line. */ delaych1: /* * Get the address of the lte * * If state == 5 (twait) then go to delaych3 * * Note that the following code assumes that STATE is the * first cell in the lte and that the memory-address * register (mar) has already been loaded from r7 */ mov mem,r10|mar addn mem,r5,- brz delaych3 /* * Test for end of loop */ delaych2: /* * Decrement the current entry number. If the result is * non-negative then go to delaych1 */ dec r7,r7|mar brc delaych1 /* * Go to delaych4 */ br delaych4 /* * We get here when we find a line with STATE == 5 (twait) */ delaych3: /* * Decrement the count field of the lte. If the result is * non-negative then go to delaych2 */ mov COUNT,brg add brg,r10,mar mov mem,r0 dec r0,mem brc delaych2 /* * The time has elapsed, if a break was being transmitted call ubreak */ mov FLAGS1,brg add brg,r10,mar mov mem,r0 mov OUTBRK,brg orn brg,r0,- brz 1f br 2f 1: /* * Turn off treak bit */ CALL(ubreak) mov %dzst,brg add brg,r8,%mar br delaych2 2: /* * Continue sending data. */ /* * Set state = 1 (sending normal data) */ mov STATE,brg add brg,r10,mar mov 1,mem /* * Turn on the enable bit for this line */ CALL(enable) mov %dzst,brg add brg,r8,%mar /* * Go to delaych2 */ br delaych2 /* * End of above loop */ delaych4: /* * Input time-out test * * Loop through all eight lines for this DZ. For each line with a non-empty * input queue, if the timer has expired then put the line on the * input-ready queue */ mov 7,r7 1: mov r7,mar mov mem,r10 /* * See if timer is active */ mov FLAGS1,brg add brg,r10,mar mov mem,r0 mov TIMACT,brg orn brg,r0,- brz 2f br 3f 2: /* * Timer is active, decrement ITIME */ mov ITIME,brg add brg,r10,mar mov mem,r0 dec r0,mem brc 3f /* * Timer has expired, queue input and reset TIMER */ mov FLAGS1,brg add brg,r10,mar mov mem,r0 mov ~TIMACT,brg and brg,r0,mem CALL(queue) mov %dzst,brg add brg,r8,%mar 3: dec r7 brc 1b /* * Return to dispatcher */ br dispret3 /* * The following code checks for output character completions * and input data ready in the silo */ csrcheck: /* * If the check-CSR queue is empty then error */ mov headcsrq,mar mov %headcsrq,%mar mov mem,r8 brz csrcout mov %dzst,brg add brg,r8,%mar /* * Set up a unibus request for the current value of CSR */ mov csrget,mar mov mem,ial|mar++ mov mem,iah|mar++ mov mem,r0 asl r0 asl r0 mov NRQ,brg or brg,r0,npr /* * Wait for the unibus transfer to complete. * If an error occurs then go to buserr0. */ BUSWAIT(buserr3) /* * If there is an input character available then go to csrchk2 */ mov idl,brg br7 csrchk2 /* * If there is an output data request then go to csrchk4 */ mov idh,brg br7 csrchk4 /* * Clear the bit that indicates that a csr check has been scheduled for this page */ mov status,mar mov ~(1<<0),brg mov brg,r0 and mem,r0,mem /* * Remove the current DZ from the csr-check-needed queue; * if the queue is empty then clear the CHKCSRQ bit in r14 */ mov csrlink,mar mov mem,brg mov %headcsrq,%mar mov headcsrq,mar mov brg,mem|mar++ brz 1f br 2f 1: mov brg,mem csrcout: mov ~CHKCSRQ,brg and brg,r14 2: /* * Go to disp */ br dispret3 /* * Input data available--jump to input segment */ csrchk2: mov %inchar,brg mov brg,pcr jmp inchar /* * Output data request--jump to output segment */ csrchk4: mov %outreq,brg mov brg,pcr jmp outreq dispret3: mov %disp,brg mov brg,pcr jmp disp /* * The following code queues and error report */ erqueue: /* * If an error has already been queued for this dz just return */ mov %dzst,brg add brg,r8,%mar mov status,mar mov mem,r0 mov 1<<5,brg orn brg,r0,- brz 2f or brg,r0,mem /* * Increment the error counter */ mov errcnt,mar mov mem,r0 inc r0,mem /* * Get the driver's idea of the DZ number and combine it with the line * number to get the minor device number */ mov dznr,mar mov mem,r0 asl r0 asl r0 asl r0 mov 07,brg and brg,r7,brg or brg,r0 /* * Queue an error for this line */ GETQ(r4,queuerr3) mov NIL,mem|mar++ /* * Put dznr<<3|line number in second byte */ mov r0,mem|mar++ /* * Put error number into third byte */ mov r1,mem|mar++ /* * Save r8 */ mov r8,mem mov %tailerrq,%mar mov tailerrq,mar mov mem,r0 brz 1f mov r4,mem mov 03,brg and brg,r0,%mar mov ~03,brg and brg,r0,mar mov r4,mem br 2f 1: mov headerrq,mar mov r4,mem|mar++ mov r4,mem /* * Indicat an error queued */ 2: mov CHKERRQ,brg or brg,r14 RETURN /* * Unibus error */ buserr3: /* * Clear the non-existent memory bit */ mov nprx,r0 mov ~(BRQ|ACLO|NEM),brg and brg,r0,nprx ERROR(BUSERR3) br dispret3 queuerr3: /* * No queue entries to queue an error, tough */ br . endseg3: