; BCPL Microcode for running Diablo Port Audio Terminal
; Last modified by L. Stewart: March 15, 1980 3:25 PM

; Microcode command file for Audio Terminal
; MU/l ATmc.mu
; PackMu ATmc.mb ATmc.br 160376 // Alto II
; PackMu ATmc.mb ATmc.br 177376 // Alto I

; Task assignments and BCPL emulator-routine entry points.

; Alto II version
%17,1777,0, Novem, L1, L2, L3, L4, L5, L6, L7, MRT, DWT, CURT, DHT, DVT, L15;

; Alto I version
; %17,1777,0, Novem, L1, L2, L3, L4, L5, L6, L7, MRT, L11, L12, L13, L14, L15;

%1,1777,20,Start;
%1,1777,21,AudioInit;
%1,1777,22,AudioStart;
%1,1777,23,AudioEnqueue;

#AltoConsts23.mu;

L1: TASK, :L1;
L2: TASK, :L2;
L3: TASK, :L3;
L4: TASK, :L4;
L5: TASK, :L5;
L6: TASK, :L6;
L7: TASK, :L7;
; L10: TASK, :L10;
Memory refresh task

; For Alto II, comment out L11, L12, L13, and L 14
; L11: TASK, :L11;
Display Word Task
; L12: TASK, :L12;
Cursor Task
; L13: TASK, :L13;
Display horizontal task
; L14: TASK, :L14;
Display Vertical Task

L15: TASK, :L15;

; For Alto I
; #CATMRT.mu;
contains MRT

; For Alto II
#CATIIMRT.mu;
contains MRT
#GateDisplay.mu;
contains DHT, DVT, CURT, DWT

;BCPL Emulator routines (via JMPRAM)
; Arg1 in AC0
; Ram Location
Routine
;
20SetBLV -- Silent boot code (doesn’t do the StartIO) for BCPL
;
21AudioInit
;
22AudioStart
;
23AudioEnqueue

; Register definitions
$AC0
$R3;
$AC3
$R0;
$LastL
$R40;

$IACB
$R71;input Audio Control Block
$IPtr
$R72;data block pointer
$ICount
$R73;word count
$RData
$R14;input assembly register
$OACB
$R74;output Audio Control Block
$OPtr
$R75;
$OCount
$R76;
$WData
$R15;output word register
$NCount
$R60;

; Temporaries
$Temp2
$R63;
$Temp
$R16;In Data

; Constants
$OREMask
$4000;
$DataMask
$170000;
$Strobe
$1;command word strobe

; Silent boot interface

TStart:
TASK;
NStart:
NOP;
Novem:
SWMODE;
1Start:
:Start;

Start:
RMR ← AC0, :Novem;Set RMR -- classical location for it

; This must run with MRT disabled (i.e. running in ROM)

AudioInit:
L ← 0;
NCount ← L;
IACB ← L;
OACB ← L;
OCount ← L;
ICount ← L,TASK;
WData ← L;

T ← 177000;Clear ready bit in hardware
MAR ← 16 + T;
L ← Strobe;
MD ← LastL;
MAR ← 16 + T;
L ← 0, TASK;
MD ← LastL,:NStart;

; On entry to AudioEnqueue, AC0 points to the new ACB, AC3 to the old

!1,2,Fail, Link;

AudioEnqueue:
MAR ← AC3;
L ← 0;
SINK ← MD,BUS=0;
MAR ← AC3+1,:Fail;!1,2,Fail, Link;
Link:
NOP;
MD ← AC0,TASK,:NStart;
Fail:
AC0 ← L,TASK,:NStart;

; AudioStart expects AC0 to be IACB and AC3 to be OACB.
; n. b. A 0 starting value means none...
;
; Format of an ACB (Even word aligned)
; word 0: Flags
Goes non-zero on completion
; word 1: Next ACB
pointer to next ACB
; word 2:
Pointerpointer to data block
; word 3:
Countsize of block (in words)

AudioStart:
L ← AC0;
IACB ← L;
L ← AC3;
OACB ← L;
L ← 0;
ICount ← L,TASK;
OCount ← L,:Novem;

; This code runs as part of MRT

!1,2,Ready,NotYet;

AudioTest:
T ← 177000;
MAR ← 30 + T;
T ← OREMask;two cycles here! (compute portout?)
L ← T ← MD AND T;
L ← DataMask AND T, SH=0;
Temp2 ← L,:Ready;!1,2,Ready,NotYet;

NotYet:
TASK;
NOP,:ATDone;back to MRT

!1,2,RightB,LeftB;
!1,2,IBMore,IBDone;
!1,2,ICMore,ICDone;
!1,2,OBMore,OBDone;
!1,2,OCMore,OCDone;

Ready:
; write data
T ← 177000;
MAR ← 16 + T;
T ← 177400;
L ← WData AND T;
MD ← LastL, TASK;
Temp ← L;

; Strobe it in
T ← 177000;
MAR ← 16 + T;
L ← Temp + 1;we know 1 is Strobe
MD ← LastL;

; Now read next nibble
MAR ← 30 + T;#177030
T ← DataMask;
L ← MD AND T,TASK;
Temp ← L;

; Turn off strobe
T ← 177000;
MAR ← 16 + T;
T ← 177400;
L ← WData AND T, TASK;
MD ← LastL;

L ← Temp, TASK;
Temp ← L RSH 1;
L ← Temp, TASK;
Temp ← L RSH 1;
L ← Temp, TASK;
Temp ← L RSH 1;
L ← Temp, TASK;
Temp ← L RSH 1;
T ← Temp;
L ← Temp2 OR T, TASK;
Temp ← L;
; Now input byte is left justified in Temp

SINK ← NCount, BUS=0;
L ← 0,:RightB;!1,2,RightB,LeftB;

;Assume Temp holds left justified nibble.

; Left Byte
LeftB:
L ← ALLONES;
NCount ← L;
L ← Temp, TASK;
RData ← L LCY 8;
L ← WData,TASK;swab WData
WData ← L LCY 8,:ATDone;

; Right byte
RightB:
NCount ← L;
T ← RData;
L ← Temp OR T, TASK;
RData ← L LCY 8,:WTIn;

; Once per word code (250 microseconds)

WTIn:
L ← ICount-1, BUS=0, TASK;decrement input count
ICount ← L,:IBMore;!1,2,IBMore,IBDone; (input block)

; Block completion, input

IBDone:
MAR ← L ← IACB,BUS=0;
T ← 2,:ICMore;!1,2,ICMore,ICDone; (input chain)
ICMore:
MD ← LastL;
L ← MD;
MAR ← LastL+T;
IACB ← L;
;
predecrement ptr because we increment it before use
L ← MD - 1;
;
we test count for zero before decrementing it
;
since we are starting a new block, ICount must be decremented
;
to account for the store in IBMore below.
T ← MD - 1;
IPtr ← L, L ← T, TASK;
ICount ← L,: IBMore;

ICDone:
L ← 0, TASK;leave count at 0
ICount ← L,:WTOut;

IBMore:
MAR ← L ← IPtr+1;we increment ptr before use
IPtr ← L;
L ← RData, TASK;
MD ← LastL,:WTOut;

WTOut:
L ← OCount-1, BUS=0, TASK;decrement output count
OCount ← L,:OBMore;!1,2,OBMore,OBDone;

; Block completion, output

OBDone:
MAR ← L ← OACB,BUS=0;
T ← 2,:OCMore;!1,2,OCMore,OCDone;
OCMore:
MD ← LastL;
L ← MD;
MAR ← LastL+T;
OACB ← L;
;
predecrement ptr because we increment it before use
L ← MD - 1;
;
we test count for zero before decrementing it
;
OCount must be decremented to account for the fetch in
;
OBMore below.
T ← MD - 1;
OPtr ← L, L ← T, TASK;
OCount ← L,: OBMore;

OCDone:
L ← 0;
WData ← 0, TASK;
OCount ← L,:ATDone;leave count at 0

OBMore:
MAR ← L ← OPtr+1;
OPtr ← L;
L ← MD, TASK;
WData ← L,:ATDone;

;; December 24, 1979 5:59 PM L. Stewart. created file
;; December 25, 1979 8:18 PM L. Stewart. task code
;; December 28, 1979 10:43 PM L. Stewart. new design