"
module P2101X

title 'P2101X'

declarations

"The A2101X is a version of the A2101 that imitates a Raft"
"Controller Module so we can test serial communication. We"
"use the input socket on the A2101A/X assembly, which is"
"socket number eight. 

"Version 2: [05-FEB-09] Correct polarity of Channel 8 LVDS"
"inputs and outputs."

"Version 1: [04-FEB-09] Create receiver, clock manager, serial"
"controller (based upon A2101A code) and serial transmitter (also"
"based upon A2101A code)."

"Monitor Pins"
SW1 pin 168; "Switch 1, RESET"
SW2 pin 172; "Switch 2, CONFIG"
TP1..TP3 pin 27,26,25 istype 'com'; "Test Points"
LED1..LED4 pin 173,171,170,169 istype 'com'; "Indicator LEDs"
!PRST pin 174; "Power-Up Reset"

"Clock Pins"
LCK pin 154; "Local Clock, CLK3, 50 MHz"
RCK pin 66; "Reference Clock, CLK1, 32.768 kHz"
CLK2 pin 70 istype 'com'; "To CLK2"
CK pin 68; "Master Clock, CLK2, 50 MHz from LCK or SCK8."
FCK pin 156; "Fast Clock, CLK0, 200 MHz."
MCI pin 151 istype 'com'; "Multiplier Clock Input"
MS0 pin 158 istype 'com'; "Multiplier Set 0"
MS1 pin 152 istype 'com'; "Multiplier Set 1"

"RAM Interface"
RCE1 pin 62 istype 'com'; "RAM 1 Chip Enable"
RCD1 pin 64 istype 'com'; "RAM 1 Chip Disable"
!ROE1 pin 80 istype 'com'; "RAM 1 Output Enable"
!RWR1 pin 63 istype 'com'; "RAM 1 Write"
RCE2 pin 35 istype 'com'; "RAM 2 Chip Enable"
RCD2 pin 34 istype 'com'; "RAM 2 Chip Disable"
!ROE2 pin 36 istype 'com'; "RAM 2 Output Enable"
!RWR2 pin 37 istype 'com'; "RAM 2 Write"
RA0..RA20 pin 71,72,73,74,75,85,84,83,82,81,51,50,
  49,48,47,57,58,59,60,61,52 istype 'com'; "RAM Address Bits"
ram_addr = [RA20..RA0];
RD0..RD7 pin 54,53,38,39,86,87,77,76 istype 'com'; "RAM Data Bits"
ram_data = [RD7..RD0];

"TCM Interface"
!SCK8,!SDO8,!SAO8 pin 147,149,148; 
  "Serial Clock, Serial Data Out, Serial Auxilliary Out, Channel 8"
!SDI8 pin 150 istype 'com'; "Serial Data In, Channel 8"

"Nodes and Sets"
DA0..DA21 node istype 'reg'; "Data Address"
data_addr = [DA21..DA0];
dab0=[DA7..DA0]; "data address byte zero"
dab1=[DA15..DA8]; "data address byte one"
dab2=[DA21..DA16]; "data address byte two"
CKD node istype 'com'; "clock detect"
DAC0 node istype 'com,keep'; "data address carry from byte zero"
DAC1 node istype 'com,keep'; "data address carry from byte one"
DAI node istype 'reg,keep,pos'; "data address increment"
DRC node istype 'com,keep'; "decrement repeat counter"
EI node istype 'reg'; "execute indicator"
RAMSEL node istype 'com,keep,pos'; "RAM Select"
RC0..RC23 node istype 'reg,keep'; "repeat counter"
rcb0=[RC7..RC0]; "repeat counter byte zero"
rcb1=[RC15..RC8]; "repeat counter byte one"
rcb2=[RC23..RC16]; "repeat counter byte two"
repeat_counter=[RC23..RC0]; "repeat counter"
RCZ node istype 'com,keep'; "repeat counter zero"
RCZ0 node istype 'com,keep'; "repeat counter zero in byte zero"
RCZ1 node istype 'com,keep'; "repeat counter zero in byte one"
RCZ2 node istype 'com,keep'; "repeat counter zero in byte two"
RESET node istype 'com'; "Reset"
RCVD node istype 'reg'; "Receiving Data"
RCVI node istype 'reg'; "Receiving Instruction"
RIR0..RIR7 node istype 'reg'; "Received Instruction Register"
rir = [RIR7..RIR0];
SCS0..SCS5 node istype 'reg,pos,keep'; "serial controller state"
scs = [SCS5..SCS0];
SDIFL node istype 'com,pos,keep'; "Serial Data In Force LO"
SDR0..SDR7 node istype 'reg'; "Serial Data Register"
sdr = [SDR7..SDR0];
SDS node istype 'reg,pos'; "Serial Data Strobe"
SRS0..SRS3 node istype 'reg'; "Serial Receiver State"
srs = [SRS3..SRS0];
SDA node istype 'com,pos,keep'; "Shift Data Address"
SIR node istype 'com'; "Serial Instruction Ready"
SRC node istype 'com,pos,keep'; "Shift Receive Counter"
STA node istype 'com,pos,keep'; "Serial Transmitter Activate"
STD node istype 'com,keep'; "Serial Transmit Done"
STS0..STS3 node istype 'reg'; "Serial Transmit State"
sts = [STS3..STS0];
SW node istype 'com'; "Serial Write"
SDR node istype 'com,pos,keep'; "Serial Data Ready"


equations


"Clock Generator"
"---------------"

"The fast clock is always generated from the local clock"
MS0 = 0;
MS1 = 0;
MCI = LCK;

declarations
  CKDT0..CKDT3 node istype 'reg'; "Clock Detector"
  ckdt = [CKDT3..CKDT0];
  SCKS node istype 'reg'; "Serial Clock Synchronized"
  SCKSD node istype 'reg'; "SCKS Delayed"
  SCKE node istype 'reg'; "Serial Clock Edge"
equations

"We count edges of FCK, and reset the counter on every"
"rising edge of SCK. If the counter reaches 15, we"
"assume there is no SCK. Otherwise, there must be SCK of"
"at least FCK/16 = 12 MHz."
[SCKS,SCKSD,SCKE].clk = FCK;
SCKS := SCK8;
SCKSD := SCKS;
SCKE := SCKS & !SCKSD;
ckdt.clk = FCK;
ckdt.aclr = SCKE;
when ckdt==15 then ckdt:=ckdt;
else ckdt:=ckdt+1;
CKD = ckdt!=15;

"If we detect a clock on the serial input, we use it as the"
"master clock. Otherwise we run on the local clock.
"when CKD then CLK2 = SCK8;
"else CLK2 = LCK;
"WARNING: above code has problems. Will debug later."
CLK2 = SCK8;


"Data Address"
"------------"

"We clock the data address on the rising edge of CK."
[dab0,dab1,dab2].clk = CK;
[dab0,dab1,dab2].aclr = RESET;

"The data address carry outputs simplify the counter logic."
DAC0 = (dab0==^hFF);
DAC1 = (dab1==^hFF);

"Data Address Increment is clocked by !CK. Any state machine"
"may assert it, but no state machine may unassert it. The"
"variable is unasserted when its state is unspecified, hence"
"the 'pos' directive in its node declaration. We increment"
"the data address by one on each rising edge of CK for which"
"we assert DAI."
DAI.clk = !CK;
when DAI then
{
  dab0 := dab0+1;
  when DAC0 then dab1 := dab1+1;
  else dab1 := dab1;
  when DAC1 & DAC0 then dab2 := dab2+1;
  else dab2 := dab2;
} else {
  when SDA then {
    dab0 := sdr;
    dab1 := dab0;
    dab2 := [DA13..DA8];
  } else {
    dab0 := dab0;
    dab1 := dab1;
    dab2 := dab2;    
  }
}


"RAM Interface"
"-------------"

"We select the RAM on Serial Data Strobe with BUSY"
"or CDS and RAM portal access when !BUSY."
RAMSEL = SDS;

"The RAM address is made up of the lower 21 bits"
"of the data address."
ram_addr = [DA20..DA0];

"We select RAM1 when DA21=0, and RAM2 when DA21=0."
"Here we're using the RAM disable lines, so RAM1"
"is selected by !DA21 (lower 2MBytes) and RAM2"
"is selected by DA21 (upper 2 MBytes).""
RCD1 = !DA21;
RCD2 = DA21;

"We use RAMSEL to enable the RAM chips. Note that they"
"will be enabled only when their RCD lines are unasserted."
RCE1 = RAMSEL;
RCE2 = RAMSEL;

"We route control data and ram data with SW and CW when"
"we have BUSY and !BUSY respectively."
RWR1 = SW;
RWR2 = SW;
ROE1 = !SW;
ROE2 = !SW;
ram_data.oe = RWR1 # RWR2;

"We assert DAI for one clock period whenever we read"
"or write from RAM. We use the rca state machine to"
"detect the assertion of RAMSEL followed by un-assertion."
"At the end of the cycle, we assert DAI for one CK period"
"so that we increment the data address."
declarations
RCA0..RCA1 node istype 'reg'; "RAM Cycle Active"
rca = [RCA1..RCA0];
equations

rca.aclr = RESET;
rca.clk = CK;
state_diagram rca
  state 0: if RAMSEL then 1 else 0;
  state 1: if !RAMSEL then 2 else 1;
  state 2: goto 0;
equations 
when (rca == 2) then DAI := 1;




"Serial Controller"
"-----------------"

declarations
error_inst=^d0;
write_inst=1;
read_inst=2;
abort_inst=3;
reset_inst=4;
execute_inst=5;
data_inst=6;
null_inst=255;

scs_rest=0;
scs_done=255;
scs_write_1=3;
scs_write_2=4;
scs_write_3=5;
scs_write_4=6;
scs_write_5=7;
scs_write_6=8;
scs_write_7=9;
scs_write_8=10;
scs_write_9=11;
scs_read_1=13;
scs_read_2=14;
scs_reset=15;
scs_execute=16;
equations


"We clock the Serial Controller State with CK."
scs.aclr=RESET;
scs.clk=CK;

"The Serial Controller sits in its rest state until it"
"detects rir!=null_instruction. At any time during its 
"job executions, reception of an abort instruction will"
"return the controller to its rest state."
state_diagram scs;

  state scs_rest: 
    case 
      rir==write_inst:scs_write_1;
      rir==read_inst:scs_write_1;
      rir==abort_inst:scs_done;
      rir==reset_inst:scs_reset;
      rir==execute_inst:scs_execute;
      (rir>execute_inst) & (rir=scs_write_5) & (scs<=scs_write_8) then
  SRC = SDR;
when (scs>=scs_write_1) & (scs<=scs_write_4) then
  SDA = SDR;
when (scs==scs_write_9) then {
  DRC = SDR;
  ram_data = sdr;
  SDS := SDR;
  SW = 1;
}
when (scs==scs_read_1) then STA = !STD;
when (scs==scs_read_2) then {
  SW = 0;
  SDS := (sts>=1) & (sts<=11);
  STA = !STD;
  DRC = (sts==11);
}

"We use RESET to reset all internal registers." 
RESET = PRST # !SW1 # (scs==scs_reset);

"We use EI to indicate an execute instruction."
EI.clk=CK;
EI.aclr=RESET;
when (scs==scs_execute) then EI:=!EI;
else EI:=EI;


"Repeat Counter"
"--------------"

repeat_counter.clk=CK;
repeat_counter.aclr=RESET;

RCZ0=(rcb0==0);
RCZ1=(rcb1==0);
RCZ2=(rcb2==0);
RCZ=RCZ0 & RCZ1 & RCZ2;

"We decrement the repeat counter when DRC and the counter."
"is not zero. We shift new values into the repeat counter on"
"SRC."
when DRC & !RCZ then
{
  rcb0:=rcb0-1;
  when RCZ0 then rcb1:=rcb1-1;
  else rcb1:=rcb1;
  when RCZ0 & RCZ1 then rcb2:=rcb2-1;
  else rcb2:=rcb2;
} else {
  when SRC then {
    rcb0:=sdr;
    rcb1:=rcb0;
    rcb2:=rcb1;
  } else {
    repeat_counter:=repeat_counter;
  }
}


"Serial Transmitter"
"------------------"

sts.clk=!CK;
sts.aclr=RESET;
state_diagram sts;
  state 0:if STA then 1 else 0;
  state 1:goto 2; "start bit LO"
  state 2:goto 3; "data/instruction bit"
  state 3:goto 4; "data bit 7"
  state 4:goto 5;
  state 5:goto 6;
  state 6:goto 7;
  state 7:goto 8;
  state 8:goto 9;
  state 9:goto 10;
  state 10:goto 11; "data bit 0"
  state 11:goto 12; "stop bit HI"
  state 12:if !STA then 0 else 12;
equations

STD = (sts==12);

"Send data instruction, code 6, bit stream: 00000001101"
when (scs==scs_read_1) then {
  SDIFL = (sts>=1) & (sts<=7)
    # (sts==10);
}

"Send ram data, bit stream: 01xxxxxxxx1
when (scs==scs_read_2) then {
  SDIFL = (sts==1)
    # (sts==3) & !RD7
    # (sts==4) & !RD6
    # (sts==5) & !RD5
    # (sts==6) & !RD4
    # (sts==7) & !RD3
    # (sts==8) & !RD2
    # (sts==9) & !RD1
    # (sts==10) & !RD0
}

SDI8 = !SDIFL;


"Serial Receiver"
"---------------"

srs.clk=CK;
srs.aclr=RESET;
state_diagram srs;
  state 0:if !SDO8 then 1 else 0; "wait for start bit LO"
  state 1:goto 2; "1=data 0=instruction"
  state 2:goto 3; "data bit 7"
  state 3:goto 4; 
  state 4:goto 5;
  state 5:goto 6;
  state 6:goto 7;
  state 7:goto 8;
  state 8:goto 9;
  state 9:goto 10; "data bit 0"
  state 10: if SDO8 then 0 else 11; "1=stop, serial word ready"
  state 11: if SDO8 then 0 else 11; "waiting for stop bit"
equations

RCVD.clk=CK;
RCVD.aclr=RESET;
state_diagram RCVD;
  state 0: 
    if (srs==1) & SDO8 then 1;
    else 0;

  state 1:
    if (srs==10) then 0;
    else 1;
equations

RCVI.clk=CK;
RCVI.aclr=RESET;
state_diagram RCVI;
  state 0: 
    if (srs==1) & !SDO8 then 1;
    else 0;

  state 1:
    if (srs==10) then 0;
    else 1;
equations

SDR = (srs==10) & RCVD;
SIR = (srs==10) & RCVI;

sdr.clk=CK;
sdr.aclr=RESET;
when (srs==0) then sdr:=sdr;
when (srs==1) then sdr:=0;
when (srs>=2) & (srs<=9) then [SDR7..SDR0] := [SDR6..SDR0,SDO8];
when (srs==10) then sdr:=sdr;
 
rir.clk=CK;
rir.ap=RESET;
when (scs==scs_done) then {
  rir:=null_inst;
} else {
  when SIR then rir:=sdr;
  else rir:=rir;
}


"Indicators Lamps"
"----------------"

LED1 = RCZ & CKD;
LED2 = EI;
LED3 = (scs==scs_read_2) # (scs==scs_write_9);
LED4 = RESET;


"Test Points"
"-----------"

TP1 = (srs>=1) & (srs<=2);
TP2 = (sts>=1) & (sts<=2);
TP3 = SDI8;
end