"

MODULE P3040B

TITLE 'P3040B'

"Version 1 [27-FEB-23] Based on P3040A02.abl.

"Version 2 [28-SEP-23] Adopt the sixteen-state sample interval counter we use in
"the P3049A firmware, so that we can add versions with non-uniform sample rates.

"Version 3 [12-MAR-23] Correct the list of pass-through layout pads. We were 
"missing three. Our layout vector now contains twelve pads. Current consumption
"of the V3 drops from 215 uA to 212 uA. We note that this drop is not consistent
"with removal of a pull-down resistor on 1V8 or 2V7, which would draw tens of 
"micramps.

"Version 4 [07-NOV-24] Change name of eck_offset to xck_offset. Add XCK to switch
"channels. Experiment with values of xck_offset to minimize noise. Introduce
"linear shift register to generate transmit scatter from LSB of ADC rather than
"using lowest four bits. We set TP2 to ECK so we can examine transmission scatter
"and we are well-satisfied with the random distribution provided by the LSR.

declarations


"Configuration Parameters
"========================

" -------------------------------------
"| Version |  Sample Rates (SPS)       |
"|         |---------------------------
"| Number  |  X1  |  X2  |  X3  |  X4  |
"|-------------------------------------
"|   1     |  128 | 128  | 128  | 128  |
"|   2     |  256 | 256  | 256  | 256  |
"|   3     |  512 | 512  | 512  | 512  |
"|   4     | 1024 | 1024 | 1024 | 1024 |
"|   5     |  256 | 256  | 256  | 0    |
"|   6     |  512 | 512  | 512  | 0    |
"|   7     | 1024 | 1024 | 1024 | 0    |
"|         |      |      |      |      |
" -------------------------------------


"Version | Number | 
"------------------

"   D1      1     
"   D2      2 
"   D3      3 
"   D4      4
"   C2      5
"   C3      6
"   C4      7

"Set the transmitter version number

VERSION = 3;

"The channel number can be 1-14, 17-30, 33-46, 49-62, 65-78, 81-94, 97-110, 113-126,
"129-142, 145-158, 161-174, 177-190, 193-206, 209-222. These ranges correspond to
"sets 0-13 respectively. We reserve ranges 225-238 and 241-254 for test devices and
"possible future channel number ranges expansions.

channel_num = 5;

"The set number is the channel number divided by sixteen.

set_num = channel_num / 16;

"The base identifier is the channel number modulo sixteen.

base_id = channel_num % 16;


"Calibration Parameters
"======================

"Fast Clock Divisor, use to set TCK period in range 195-215 ns. Supported
"range for fck_divisor is 8 to 30.

fck_divisor = 23; 

"Frequency Low, use to center transmit spectrum in range 913-918 MHz.

frequency_low = 24;


"Parameters" 
"==========


"Version-Dependent Parameters Set Automatically.

@IF (VERSION == 1) {
  ck_divisor = 64; 
  scnt_max = 3;
}
@IF (VERSION == 2) {
  ck_divisor=32; 
  scnt_max = 3;
}
@IF (VERSION == 3) {
  ck_divisor=16; 
  scnt_max = 3;
}
@IF (VERSION == 4) {
  ck_divisor=8; 
  scnt_max = 3;
}
@IF (VERSION == 5) {
  ck_divisor = 32; 
  scnt_max = 3;
}
@IF (VERSION == 6) {
  ck_divisor=16; 
  scnt_max = 3;
}
@IF (VERSION == 7) {
  ck_divisor=8; 
  scnt_max = 3;
}

"Set the transmit clock divisor, tck_divisor, and the ring oscillator length,
"ring_length, to suit fck_divisor. The TCK period will be two gate delays
"multiplied by tck_divisor multiplied by ring_length. For 7.5-ns chips, two
"internal gate delays are roughly 9.3 ns. The ring length must be at least three.
"A ring of two gates runs too fast, causing the counter to skip values. The maximum 
"ring length in this code is 13, but ultimately is limited by the available logic 
"outputs. The tck_divisor must be two or greater. We need at least two divider 
"states to create a symmetric transmit clock signal. And tck_divisor must also be 
"at most thirty-two because we have at most five divisor bits in this
"code.

@IF (fck_divisor == 8)  {tck_divisor = 2; ring_length = 4;}
@IF (fck_divisor == 9)  {tck_divisor = 3; ring_length = 3;}
@IF (fck_divisor == 10) {tck_divisor = 2; ring_length = 5;}
@IF (fck_divisor == 11) {tck_divisor = 4; ring_length = 3;}
@IF (fck_divisor == 12) {tck_divisor = 4; ring_length = 3;}
@IF (fck_divisor == 13) {tck_divisor = 2; ring_length = 7;}
@IF (fck_divisor == 14) {tck_divisor = 5; ring_length = 3;}
@IF (fck_divisor == 15) {tck_divisor = 4; ring_length = 4;}
@IF (fck_divisor == 16) {tck_divisor = 6; ring_length = 3;}
@IF (fck_divisor == 17) {tck_divisor = 5; ring_length = 4;}
@IF (fck_divisor == 18) {tck_divisor = 7; ring_length = 3;}
@IF (fck_divisor == 19) {tck_divisor = 2; ring_length = 11;}
@IF (fck_divisor == 20) {tck_divisor = 8; ring_length = 3;}
@IF (fck_divisor == 21) {tck_divisor = 5; ring_length = 5;}
@IF (fck_divisor == 22) {tck_divisor = 2; ring_length = 13;}
@IF (fck_divisor == 23) {tck_divisor = 9; ring_length = 3;}
@IF (fck_divisor == 24) {tck_divisor = 7; ring_length = 4;}
@IF (fck_divisor == 25) {tck_divisor = 6; ring_length = 5;}
@IF (fck_divisor == 26) {tck_divisor = 8; ring_length = 4;}
@IF (fck_divisor == 27) {tck_divisor = 11; ring_length = 3;}
@IF (fck_divisor == 28) {tck_divisor = 7; ring_length = 5;}
@IF (fck_divisor == 29) {tck_divisor = 9; ring_length = 4;}
@IF (fck_divisor == 30) {tck_divisor = 3; ring_length = 13;}
@IF (fck_divisor == 31) {tck_divisor = 8; ring_length = 5;}
@IF (fck_divisor == 32) {tck_divisor = 7; ring_length = 6;}


"Rarely-changed parameters.

frequency_step=2; "HI frequency - LO frequency
enable_rf=1; "Turns on RF oscillator during transmission


"Inputs and Outputs
"==================

CK pin A3; "Clock From 32-kHz Oscillator
F4..F0 pin C1,D1,E1,F1,G1 istype 'reg'; 
!SHDN pin G8 istype 'com'; "Shutdown Control for Transmitter
TP1 pin H3 istype 'com'; "Test Point
TP2 pin H6 istype 'com'; "Test Point
TP3 pin istype 'com'; "Test Point
CONV pin A8 istype 'com'; "Convert for ADC
SDO pin A5; "Serial Data Out for ADC
SCK pin B5 istype 'com'; 
A1..A0 pin A6,A7 istype 'com'; "Channel Address
L0..L11 pin F6,F7,F8,C4,C3,D3,G4,H4,D7,D8,A2,A4; "Layout Pins


"Nodes
"=====

FCK node istype 'com,keep'; "Fast Clock
TCK node istype 'reg,keep'; "Transmission Clock
ECK node istype 'reg,keep'; "End Clock
XCK node istype 'reg,keep'; "Channel Select Clock
VCK node istype 'reg,keep'; "VCO Clock
ST0..ST8 node istype 'reg'; "Sample Timer
SCNT0..SCNT3 node istype 'reg'; "Sample Counter
R1..R12 node istype 'com,keep'; "Ring Oscillator Bit
TXS0..TXS5 node istype 'reg,pos'; "Transmitter State
ACTIVE node istype 'reg,keep'; "Active flag, one CK period
TXD node istype 'com,keep'; "Transmitter Done
TCKD0..TCKD4 node istype 'reg'; "Transmit Clock Divider
TCKDZ node istype 'reg,keep'; "Transmit Clock Divider Zero
ADC0..ADC3 node istype 'reg'; "ADC Bits
TTS0..TTS3 node istype 'reg'; "Transmit Time Shift
SDOS node istype 'reg,keep'; "SDO Synchronized
YSEL node istype 'reg'; "Select Channel Y for Transmission
YCONV node istype 'reg'; "Select Channel Y for Conversion
TXEN node istype 'com'; "Transmit Enable
BIT node istype 'com,keep'; "The output bit value
RDS node istype 'reg,keep'; "Read Sample


"Sets
"====

"Sample Timer, depends upon ck_divisor to eliminate unused bits.
"Likewise, the active time, which is the moment during the sample
"interval at which we transmit a sample, depends upon how many
"bits we have in the Sample Timer.

@IF (ck_divisor == 4) {
  "Frequency 8192 SPS, scatter is +-1 ticks.
  st = [ST1..ST0];
  active_time = [0,TTS0];
  xck_offset = 1;
}
@IF (ck_divisor == 8) {
  "Frequency 4096 SPS, scatter is +-2 ticks.
  st = [ST2..ST0];
  active_time = [0,TTS1,TTS0];
  xck_offset = 3;
}
@IF (ck_divisor == 16) {
  "Frequency 2048 SPS, scatter is +-4 ticks.
  st = [ST3..ST0];
  active_time = [0,TTS2,TTS1,TTS0];
  xck_offset = 6;
}
@IF (ck_divisor == 32) {
  "Frequency 1024 SPS, scatter is +-8 ticks.
  st = [ST4..ST0];
  active_time = [0,TTS3,TTS2,TTS1,TTS0];
  xck_offset = 7;
}
@IF (ck_divisor == 64) {
  "Frequency 512 SPS, scatter is +-8 ticks.
  st = [ST5..ST0];
  active_time = [0,0,TTS3,TTS2,TTS1,TTS0];
  xck_offset = 9;
}
@IF (ck_divisor == 128) {
  "Frequency 256 SPS, scatter is +-8 ticks.
  st = [ST6..ST0];
  active_time = [0,0,0,TTS3,TTS2,TTS1,TTS0];
  xck_offset = 11;
}
@IF (ck_divisor == 256) {
  "Frequency 128 SPS, scatter is +-8 ticks.
  st = [ST7..ST0];
  active_time = [0,0,0,0,TTS3,TTS2,TTS1,TTS0];
  xck_offset = 13;
}
@IF (ck_divisor == 512) {
  "Frequency 64 SPS, scatter is +-8 ticks.
  st = [ST8..ST0];
  active_time = [0,0,0,0,0,TTS3,TTS2,TTS1,TTS0];
  xck_offset = 15;
}

"Transmit Clock Divider, depends upon tck_divisor to eliminate unused
"bits
@IF (tck_divisor <= 4) {
  tckd = [TCKD1..TCKD0];
}
@IF (tck_divisor >= 5) & (tck_divisor <= 8) {
  tckd = [TCKD2..TCKD0];
}
@IF (tck_divisor >= 9) & (tck_divisor <= 16) {
  tckd = [TCKD3..TCKD0];
}
@IF (tck_divisor >= 17) {
  tckd = [TCKD4..TCKD0];
}

"Transmission control and counter registers.

txs = [TXS5..TXS0]; "Transmitter State
adc_bits = [ADC3..ADC0]; "ADC Bits
transmit_time_shift = [TTS3..TTS0]; "Transmit Time Shift
frequency = [F4..F0]; "Frequency Voltage for Five-Bit DAC
channel = [A1..A0];
scnt =[SCNT3..SCNT0];
I3..I0 node istype 'com'; "Transmitter ID nodes
id = [I3..I0];
CC3..CC0 node istype 'com'; "Completion Code Bits
cc =[CC3..CC0];


"Constants
"=========

num_sync_bits=11; "Number of synchronizing bits at transmission start.
num_id_bits = 4; "Number of ID bits
num_start_bits = 1; "Transmitted zero to mark data start
num_stop_bits = 2; "Not transmitted, for txs termination
num_data_bits = 16; "Number of ADC data bits
num_xmit_bits = "Number of transmission bit periods
    num_sync_bits
  + num_start_bits
  + num_id_bits
  + num_data_bits
  + num_id_bits; 
txs_done = "Final state of txs machine
    num_xmit_bits
  + num_stop_bits; 
first_sync_bit = 1;
first_start_bit = first_sync_bit + num_sync_bits;
first_id_bit = first_start_bit + num_start_bits;
first_data_bit = first_id_bit + num_id_bits;
first_cc_bit = first_data_bit + num_data_bits;
start_sck = "The txs state for first SCK falling edge
    first_data_bit - 1;
end_sck = "The txs state for last SCK falling edge
    start_sck + num_data_bits - 1;


equations

"The Sample Timer runs off the 32.678-kHz clock and counts up to
"ck_divisor-1 to give a sample interval of 32.768 kHz divided
"by ck_divisor.

st.clk = CK;
when (st == ck_divisor-1) then {
  st := 0;
} else {
  st := st+1;
}

"The ECK clock marks the final CK period in each sample period.

ECK.clk=CK;
ECK:=(st==ck_divisor-1);

"The XCK clock marks the time when we switch from one input to
"another, which will be some time before we sample the input.

XCK.clk=CK;
XCK:=(st==ck_divisor-xck_offset-1);

"When ACTIVE is asserted, we begin a burst transmission.
"When it is unasserted, we reset the burst transmission
"state machine. We must make sure that ACTIVE remains true
"for long enough for the burst transmission to complete.
"ACTIVE becomes true when the Sample Timer reaches the active
"time set at the end of the previous sample interval. This
"active time is made up of the lower four bits of the sample
"transmitted in the previous sample interval. Because these
"four bits are dominated by noise, they are random and so
"produce a random disturbance of the transmit instant, which
"avoids systematic collisions between transmitters.

ACTIVE.clk = CK;
ACTIVE := (st == active_time);

"TXD is true when the transmitter completes its burst
"transmission.

TXD=(txs==txs_done);


"Sample Selection
"================

"The Sample Counter counts sample intervals and allows us to decide
"which input to digitize and which channel number to apply to each
"sample transmission. We increment the counter at a point in the
"interval that is certainly after any sample transmission, and
"well before the end of the interval. We will be sampling the newly-
"selected signal in the last CK period of the interval. We want to
"allow our selection to settle before we take the sample.

scnt.clk=XCK;
when (scnt == scnt_max) then {
  scnt:=0;
} else {
  scnt:=scnt+1;
}

"For each sample interval, select a channel, set the identifier, and
"calculate the completion code. Enable or disable transmission. When
"we select the channel, we are selecting the channel that will be 
"digitized in this interval, and subsequently read out and transmitted
"in the next interval. The channel number we use for input Xm is m-1.
"If we are transmitting X3 in interval n, we must select the X3 channel
"in interval n-1.

@IF (VERSION == 1) # (VERSION == 2) # (VERSION == 3) # (VERSION == 4) {
  declarations 
    x1_id = base_id; 
    x2_id = base_id + 1;
    x3_id = base_id + 2;
    x4_id = base_id + 3;
  equations
  when scnt == 0  then {id=x1_id; cc=15-x1_id+set_num; channel=1; TXEN=1;}
  when scnt == 1  then {id=x2_id; cc=15-x2_id+set_num; channel=2; TXEN=1;}
  when scnt == 2  then {id=x3_id; cc=15-x3_id+set_num; channel=3; TXEN=1;}
  when scnt == 3  then {id=x4_id; cc=15-x4_id+set_num; channel=0; TXEN=1;}
} 
@IF (VERSION == 5) # (VERSION == 6) # (VERSION == 7) {
  declarations 
    x1_id = base_id; 
    x2_id = base_id + 1;
    x3_id = base_id + 2;
  equations
  when scnt == 0  then {id=x1_id; cc=15-x1_id+set_num; channel=1; TXEN=1;}
  when scnt == 1  then {id=x2_id; cc=15-x2_id+set_num; channel=2; TXEN=1;}
  when scnt == 2  then {id=x3_id; cc=15-x3_id+set_num; channel=3; TXEN=1;}
  when scnt == 3  then {id=x4_id; cc=15-x4_id+set_num; channel=0; TXEN=0;}
} 

"Transmit Clock
"=============

"The ring oscillator turns on when ACTIVE and remains
"on until TXD. Each gate in the ring adds 2 ns to the
"delay around the ring. The period of the oscillation is
"4 ns multiplied by the number of gates.

@IF (ring_length == 2) {
  [FCK,R1]=[R1,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 3) {
  [FCK,R1..R2]=[R1..R2,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 4) {
  [FCK,R1..R3]=[R1..R3,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 5) {
  [FCK,R1..R4]=[R1..R4,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 6) {
  [FCK,R1..R5]=[R1..R5,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 7) {
  [FCK,R1..R6]=[R1..R6,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 8) {
  [FCK,R1..R7]=[R1..R7,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 9) {
  [FCK,R1..R8]=[R1..R8,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 10) {
  [FCK,R1..R9]=[R1..R9,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 11) {
  [FCK,R1..R10]=[R1..R10,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 12) {
  [FCK,R1..R11]=[R1..R11,!FCK & ACTIVE & !TXD];
}
@IF (ring_length == 13) {
  [FCK,R1..R12]=[R1..R12,!FCK & ACTIVE & !TXD];
}


"The transmit clock divider runs off FCK and divides FCK down
"to 5 MHz by correct choice of fck_divisor during transmitter
"calibration. We compute two constants from fck_divisor. One
"is tck_divisor, which sets the transmit clock period as a
"multiple of the fast clock period. The other is ring_length,
"which sets the number of gates in the ring oscillator that
"generates the fast clock. We enable the transmit clock divider
"only when the transmitter is active.

tckd.aclr=!ACTIVE;
tckd.clk=FCK;
when (tckd==tck_divisor-1) then {
  tckd:=0;
} else {
  tckd:=tckd+1;
}

"We detect the transmit clock divider being zero with TCKDZ. We
"clear TCKDZ to zero when the transmitter is inactive.

TCKDZ.aclr=!ACTIVE;
TCKDZ.clk=FCK;
TCKDZ:=(tckd==0);

"The transmit clock should be close to or a little less than 5 MHz,
"with a duty cycle of exactly 50%. Each time the transmit clock counts
"down to zero, we invert the transmit clock.

TCK.aclr=!ACTIVE;
TCK.clk=TCKDZ;
TCK:=!TCK;

"The transmitter state machine steps through all its
"states when ACTIVE is asserted, and then stops in its
"final state, waiting for !ACTIVE, which will reset the
"transmitter state to zero.

txs.aclr=!ACTIVE;
txs.clk=TCK;
when (txs==txs_done) then txs:=txs
else txs:=txs+1;

"Transmit sixteen ADC bits.

when (txs>0) & (txs=1)&(txs=first_data_bit)&(txs=start_sck-2) & (txs<=end_sck+1);
CONV = !RDS;

"We synchronize SDO with TCK.

SDOS.clk = TCK;
SDOS := SDO;

"We clock the ADC bits out of the chip as we transmit them, so we have
"no need for a register in which to save them.

SCK = (txs>=start_sck) & (txs<=end_sck) & !TCK;

"Test Points. We use TP1 for the transmit clock calibration and TP2
"allows us to trigger off the end of each cycle, so we can look at
"the performance of the random scatter.

TP1=(frequency==frequency_low+frequency_step);
TP2=ECK;


"Keeper Outputs
"==============

"Forcing Outputs. We assign TP3 to be a function of the thirteen chip 
"pin whose pads we use to route power to the power pins at the center 
"of the 8x8 ball grid array. Without this declaration, these balls are 
"treated by the compiler as unconnected, and are assigned pull-up 
"resistors that consume current. We want to set them to HOLD in the
"contraint manager.

TP3=[L11..L0] != 0;

END