]> jspc29.x-matter.uni-frankfurt.de Git - mdcupgrade.git/commitdiff
add Pasttrec SPI files to main repository
authorJan Michel <j.michel@gsi.de>
Wed, 17 Aug 2022 08:49:42 +0000 (10:49 +0200)
committerJan Michel <j.michel@gsi.de>
Wed, 17 Aug 2022 08:50:17 +0000 (10:50 +0200)
DBO/mdctdc.prj
code/pasttrec_spi/README.md [new file with mode: 0755]
code/pasttrec_spi/memory.hex [new file with mode: 0644]
code/pasttrec_spi/pasttrec_spi.vhd [new file with mode: 0644]
code/pasttrec_spi/ram_dp_pasttrec.vhd [new file with mode: 0644]
code/pasttrec_spi/spi_ltc2600_pasttrec.vhd [new file with mode: 0644]
code/pasttrec_spi/tb/pasttrec_spi_tb.vhd [new file with mode: 0644]
code/pasttrec_spi/tb/pasttrec_test_module.vhd [new file with mode: 0644]
code/pasttrec_spi/tb/system_testbench.vhd [new file with mode: 0644]

index 707b2fc9ba1d007822e6b3a2dd9de838c0fe9c8d..2b7559d7c014555730f45c68a40295fd92bf1de9 100644 (file)
@@ -251,9 +251,9 @@ add_file -vhdl -lib work "../../clocked_tdc/code/Decoder.vhd"
 add_file -vhdl -lib work "../../clocked_tdc/code/HitBuffer.vhd"
 add_file -vhdl -lib work "../../clocked_tdc/code/ReadoutHandler.vhd"
 
-add_file -vhdl -lib work "../../mdcupgrade_spi_pasttrec/SPI/code/ram_dp_pasttrec.vhd"
-add_file -vhdl -lib work "../../mdcupgrade_spi_pasttrec/SPI/code/spi_ltc2600_pasttrec.vhd"
-add_file -vhdl -lib work "../../mdcupgrade_spi_pasttrec/SPI/code/pasttrec_spi.vhd"
+add_file -vhdl -lib work "../code/pasttrec_spi/ram_dp_pasttrec.vhd"
+add_file -vhdl -lib work "../code/pasttrec_spi/spi_ltc2600_pasttrec.vhd"
+add_file -vhdl -lib work "../code/pasttrec_spi/pasttrec_spi.vhd"
 
 
 
diff --git a/code/pasttrec_spi/README.md b/code/pasttrec_spi/README.md
new file mode 100755 (executable)
index 0000000..1c4f40e
--- /dev/null
@@ -0,0 +1,132 @@
+
+# mdcupgrade_spi_pasttrec
+
+Top level module for SPI communication with PASTTREC chips: 
+
+> SPI/code/pasttrec_spi.vhd
+
+## Hierarchy 
+
+* loader.vhd
+  + *MEMORY*:                  **ram_dp_pasttrec.vhd**                         - updated version of ram_dp.vhd
+  + *SPI_INTERFACE*:    **spi_ltc2600_pasttrec.vhd**   - updated version of spi_ltc2600.vhd                               
+
+## Top-level module instantiation
+
+The maximum number of connected PASTTREC chips to the whole system is 16. Every PASTTREC chip within one SPI bunch should have a unique chip id.
+
+### Generic map
+| Name        | Type                                                                   | Default |  Description                         |
+| ----------- | ----------                                                             | ---                   | ----------------------------------- |
+| SPI_BUNCHES | integer range 1 to 4   | 1                     | Number of SPI bunches connected to the module         |
+| SPI_PASTTREC_PER_BUNCH  | integer range 1 to 4 | 4 | Number of PASTTREC chips connected to each bunch |
+| SPI_CHIP_IDs   | std_logic_vector(31 downto 0) | | Chip ids of connected  PASTTRECs|
+
+The last parameter SPI_CHIP_IDs should be filled with all chip ids used in a system. The two least significant bytes set the id for first PASTTREC in the first SPI bunch, while the SPI_CHIP_IDs(2k + 1 downto 2k) sets chips id for PASTTREC #k+1.
+
+Example: 2 SPI bunches with 2 PASTTRECs in each. First bunch’ chip ids: 00 01. Second bunch’ chip ids: 01 10. Then SPI_CHIP_IDs must be filled with x"000000" & “10010100”.
+### Port  map
+| Name        | Type       | Mode | Description                         |
+| ----------- | ---------- | ---- | ----------------------------------- |
+| CLK         | std_logic  | In   | Clock signal                        |
+| BUS_RX      | CTRLBUS_RX | In   | Slow control input                  |
+| BUS_TX      | CTRLBUS_TX | Out  | Slow control output                 |
+| RST_IN      | std_logic  | In   | Reset                               |
+| SPI_CS_OUT  | std_logic_vector(*SPI_BUNCHES-1* downto *0*)  | Out  | SPI chip-select signal. Active-low. |
+| SPI_SDI_IN  | std_logic_vector(*SPI_BUNCHES-1* downto *0*)  | In   | SPI serial data in signal.          |
+| SPI_SDO_OUT | std_logic_vector(*SPI_BUNCHES-1* downto *0*)  | Out  | SPI serial data out signal.         |
+| SPI_SCK_OUT | std_logic_vector(*SPI_BUNCHES-1* downto *0*)  | Out  | SPI clock out signal.               |
+| SPI_RST_OUT | std_logic_vector(*SPI_BUNCHES-1* downto *0*)  | Out  | SPI reset signal. Active-low.       |
+
+## Memory
+
+Whole system shares one common memory, implemented in ram_dp_pasttrec.vhd. For test purposes, it's content is loaded from file during compilation.
+
+| Address     | Content                                                      | Description                                                  |
+| ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
+| 0x00  | 0x0000| Zero word. Can't be overided.|
+| 0x01  | - | SPI single word buffer. Forbidden for writing during transmitting. **Not for end user** |
+| 0x02  | **PASTTREC #2**<br>*30* - autoload enable<br>*29..24* - number of autoload commands (unsigned)<br>*23..16* - first command address<br>**PASTTREC #1**<br>*14* - autoload enable<br/>*13..8* - number of autoload commands (unsigned)<br/>*7..0* - first command address | Autostart settings for PASTTREC #1 & PASTTREC #2<br><br>Example: *0x00004C10* will trigger loading 12 commands starting from memory adress 0x10 for PASTTREC #1 *(it's black_settings_pt15_g1_thr127 set)*            |
+| up to 0x02 + ⌈N/2⌉ - 1   | **PASTTREC #2k**<br/>*30* - autoload enable<br/>*29..24* - number of autoload commands (unsigned)<br/>*23..16* - first command address<br/>**PASTTREC #2k-1**<br/>*14* - autoload enable<br/>*13..8* - number of autoload commands (unsigned)<br/>*7..0* - first command address      |       Autostart settings for PASTTREC #2k-1 & PASTTREC #2k <br>*N - total number of PASTTREC chips connected to all SPI bunches*|
+| ⌈N/2⌉ - 0xFF | -  | Free memory. Can be used by end user.<br>*N - total number of PASTTREC chips connected to all SPI bunches*  |
+
+### Predefined sets of commands
+There are 3 predefined sets of commands already in memory
+
+* *0x10*: **black_settings_pt15_g1_thr127**   *(12 commands)*
+* *0x20*: **black_settings_pt20_g1_thr127**  *(12 commands)*
+* *0x30*: **blue_settings_pt10_g1_thr127**   *(12 commands)*
+
+### Example of storing set in memory 
+##### Format of commands in memory
+| bits | meaning | is required |
+| - | - | - |
+| *18..15* | header | yes |
+| *14..13* | chip id | in most cases no, as it will be overwritten during transmitting |
+| *12*  | *1* - read mode<br>*0* - write mode | yes |
+| *11..8* | PASTTREC register address | yes |
+| *7..0* | data| yes |
+##### First few commands for set *black_settings_pt15_g1_thr127*
+| address | data |
+| -- | -- |
+| *0x10* | *0x00050019* |
+| *0x11* | *0x0005011e* |
+| *0x12* | *0x00050215* |
+| *0x13* | *0x0005037f* |
+| *0x14* | *0x0005040f* |
+| ... | ... |
+
+
+
+## Slow control
+
+### General rules
+
+* For every command, the module should respond with either ack or nack or unknown bit not later than 5 clock cycles.
+* If second commands arrives earlier than module send response for first one, it'll be ignored.
+* In a whole system, the PASTTREC chips are identified by a number _k_ within a range 0 to SPI_BUNCHES x SPI_PASTTREC_PER_BUNCH - 1. The exact chip id for every PASTTREC is assigned as SPI_CHIP_IDs(2*k* + 1 downto 2*k*)
+
+### Protocol
+
+| BUS_RX.addr                                       | Access mode | BUX_RX.data (only in W mode)                                 | BUX_TX.data                                                  | Description                                                  |
+| ------------------------------------------------- | ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
+| **0xA0\*\***                                      | -----       | ------------------------                                     | ----------------                                             | **Memory access**                                            |
+| **0xA0** & addr[7..0]                             | R/W         | *31..0* - content to be written to memory cell *addr[7..0]*. | *31..0* - content of memory cell *addr[7..0*].               | Memory access<br>**Access to *0xA001* is forbidden during SPI transmitting.** |
+| **0xA1\*\***                                      | -----       | ------------------------                                     | ----------------                                             | **SPI module access**                                        |
+| **0xA100**                                        | W           | *31* - reset bit. High - active.                             | -                                                            | Set SPI module fsm reset high.<br>*It's bit 31 of ctrl_reg register* |
+| **0xA101**                                        | R/W         | *31..0* - content to be written to SPI module ctrl_reg.<br>*Bits 6 and 7 can be high if and only if at least one of bits 5..0 is high.* | *31..0* - content of SPI module ctrl register                | Full access to SPI control register.                         |
+| **0xA102**                                        | R/W         | *5* - override sdo <br>*4* - override sck <br/>*3* - override cs <br/>*2* - invert sdo <br/>*1* - invert sck <br/>*0* - invert cs | *5* - override sdo <br/>*4* - override sck <br/>*3* - override cs <br/>*2* - invert sdo <br/>*1* - invert sck <br/>*0* - invert cs | Access to override/invert register.<br>*It's bits 13..8 of ctrl_reg register* |
+| **0xA103**                                        | R/W         | *15..6* - wait cycles (unsigned, def = 7).<br>*5..0* - word length (unsigned, def = 19) | *15..6* - wait cycles (unsigned, def = 7).<br/>*5..0* - word length (unsigned, def = 19) | Access to wait cycles/word length register.<br>*It's bits 29..14 of ctrl_reg register* |
+| **0xA10A**                                        | W           | *7* - block bit. If high SPI module will block after transaction.<br>*6* - start bit. If high SPI module will begin transmitting.<br>*5..0* - number of words to be transmitted. Required to be non zero for transmitting (unsigned) | -                                                            | Transmit data direct from memory. <br>**Not for end user.**  |
+| **0xA10B**                                        | R           | -                                                            | *31..0* - content of SPI readback register.                  | Read readback registed of SPI module. Can contain up to 4 last PASTTREC responces. Disable SPI blocking.<br> |
+| **0xA2\*\***                                      | -----       | ------------------------                                     | ----------------                                             | **PASTTREC access.**                                         |
+| **0xA2** & chip_num[3..0] & reg_no[3..0]    | R/W           | *7..0* - content to be written to PASTTREC register *reg_no[3..0]*. | -                                                            | PASTTREC chip registers access.<br>**If R mode the second slow control access is required**|
+| **0xAA\*\***                                      | -----       | ------------------------                                     | ----------------                                             | **Complex operations.**                                      |
+| **0xAA00**                                        | W           | -                                                            | -                                                            | Whole system reset.<br>Execute reset & autostart sequence of PASTTREC. |
+| **0xAA** & chip_num[3..0] & all_bit & **001** | W           | *13..8* - number of commands in set. (unsigned, should be at least 1)<br>*7..0* - address of first command in memory. | -                                                            | Load set of commands from memory to PASTTREC  chip. **Bits 14..13 of command will be overwritten with actual chip_id before transmitting.**<br>If all_bit is high, set will be loaded to all PASTTREC chips.<br>If all_bit is low, set will be loaded only to PASTTREC number = chip_num[3..0]. |
+
+## Reading data from PASTTREC
+
+To read content of PASTTREC register it's required to send two slow control requests:
+* **0xA2\*\*** - Chip register access for loading content of PASTTREC register to readback SPI register.
+* **0xA10B** - Readback register reading
+
+## Reset & autostart sequence
+
+During reset sequence firstly the module will send two words with low and high RST_OUT values for resetting all PASTTREC chips.
+
+![image](https://i.ibb.co/7kqqP1n/reset.png)
+
+After this, the module will begin transmitting the configuration commands for every PASTTREC chip one by one, first for chip #1. It can be configured with memory registers 0x02, etc. **For every particular command, the chip_id will be overwritten with the actual one!**
+
+## Files
+
+Code:
+
+> SPI/code/\*
+
+Simulation files:
+
+> SPI/sim/\*
+> SPI/syssim/\*
+
diff --git a/code/pasttrec_spi/memory.hex b/code/pasttrec_spi/memory.hex
new file mode 100644 (file)
index 0000000..904c3a8
--- /dev/null
@@ -0,0 +1,256 @@
+00000000
+00000000
+4C304C30
+4C304C30
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00050019
+0005011e
+00050215
+0005037f
+0005040f
+0005050f
+0005060f
+0005070f
+0005080f
+0005090f
+00050a0f
+00050b0f
+00000000
+00000000
+00000000
+00000000
+0005001a
+0005011e
+00050215
+0005037f
+0005040f
+0005050f
+0005060f
+0005070f
+0005080f
+0005090f
+00050a0f
+00050b0f
+00000000
+00000000
+00000000
+00000000
+00050018
+0005011e
+00050215
+0005037f
+0005040f
+0005050f
+0005060f
+0005070f
+0005080f
+0005090f
+00050a0f
+00050b0f
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
diff --git a/code/pasttrec_spi/pasttrec_spi.vhd b/code/pasttrec_spi/pasttrec_spi.vhd
new file mode 100644 (file)
index 0000000..4bb87a3
--- /dev/null
@@ -0,0 +1,543 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.trb_net_std.all;
+--use work.clocked_tdc_pkg.all;
+
+use IEEE.math_real."ceil";
+use IEEE.math_real."log2";
+
+entity pasttrec_spi is
+    generic (
+        SPI_BUNCHES             : integer range 1 to 4 := 1;
+        SPI_PASTTREC_PER_BUNCH  : integer range 1 to 4 := 4;
+        SPI_CHIP_IDs            : std_logic_vector(2*4*4 - 1 downto 0)
+    );
+    port(
+        CLK             : in std_logic;
+        BUS_RX          : in CTRLBUS_RX;
+        BUS_TX          : out CTRLBUS_TX;
+
+        RST_IN          : in std_logic;
+
+        SPI_CS_OUT      : out std_logic_vector(SPI_BUNCHES-1 downto 0);
+        SPI_SDI_IN      : in  std_logic_vector(SPI_BUNCHES-1 downto 0);
+        SPI_SDO_OUT     : out std_logic_vector(SPI_BUNCHES-1 downto 0);
+        SPI_SCK_OUT     : out std_logic_vector(SPI_BUNCHES-1 downto 0);
+        SPI_RST_OUT     : out std_logic_vector(SPI_BUNCHES-1 downto 0)
+    );
+end entity;
+
+architecture arch of pasttrec_spi is
+    signal mem_write            : std_logic;
+    signal mem_addr1            : std_logic_vector (7 downto 0)     := x"00";
+    signal mem_data_out1        : std_logic_vector (31 downto 0);
+    signal mem_data_in1         : std_logic_vector (31 downto 0);
+    signal mem_addr2            : std_logic_vector (7 downto 0)     := x"00";
+    signal mem_data_out2        : std_logic_vector (31 downto 0);
+    signal mem_addr3            : std_logic_vector (7 downto 0)     := x"00";
+    signal mem_data_out3        : std_logic_vector (31 downto 0);
+    signal spi_ram_data         : std_logic_vector (31 downto 0);
+    --signal clk_inv              : std_logic;
+    signal SKIP_AUTOSTART_SEQUENCE : std_logic := '1';
+
+    signal spi_res         : std_logic;
+    signal spi_read        : std_logic;
+    signal spi_write       : std_logic;
+    signal spi_busy        : std_logic;
+    signal spi_ack         : std_logic;
+    signal spi_unk         : std_logic;
+    signal spi_addr        : std_logic_vector (3 downto 0);
+    signal spi_data_in     : std_logic_vector (31 downto 0);
+    signal spi_data_out    : std_logic_vector (31 downto 0);
+    signal spi_ram_busy    : std_logic;
+    signal spi_cs_out_intrnl: std_logic;
+    signal spi_sdi_in_intrnl: std_logic;
+    signal spi_sdo_out_intrnl: std_logic;
+    signal spi_sck_out_intrnl: std_logic;
+
+    signal spi_reg_access  : std_logic;
+    signal spi_reg_rw      : std_logic; -- 1-read, 0-write
+    signal spi_reg_addr    : std_logic_vector(3 downto 0);
+    signal spi_reg_data    : std_logic_vector(31 downto 0);
+    constant spi_ram_addr    : std_logic_vector(7 downto 0)   := x"01";
+    signal spi_ram_offset  : integer range 0 to 63;
+
+    signal spi_active_bunch             : std_logic_vector(SPI_BUNCHES - 1 downto 0) := (others => '0');
+    signal spi_active_bunch_sc          : std_logic_vector(SPI_BUNCHES - 1 downto 0) := (others => '0');
+    signal spi_active_bunch_autoload    : std_logic_vector(SPI_BUNCHES - 1 downto 0) := (others => '0');
+
+    signal sc_ram_access   : std_logic;
+    signal sc_unknown      : std_logic;
+    signal sc_busy         : std_logic;
+    signal sc_spi_access   : std_logic;
+    signal sc_ack          : std_logic;
+    signal sc_reset_req    : std_logic;
+
+    signal autoload_chipid : integer range 0 to SPI_BUNCHES*SPI_PASTTREC_PER_BUNCH - 1;
+    signal autoload_en     : std_logic;
+    signal autoload_num    : integer range 0 to 63;
+    signal autoload_addr   : std_logic_vector(7 downto 0);
+
+    signal load_chipid     : integer range 0 to SPI_BUNCHES*SPI_PASTTREC_PER_BUNCH - 1;
+    signal load_all        : std_logic;
+    signal load_trigger    : std_logic;
+    signal load_num        : integer range 0 to 63;
+    signal load_addr       : std_logic_vector(7 downto 0);
+    signal load_past_id    : integer range 0 to SPI_BUNCHES*SPI_PASTTREC_PER_BUNCH - 1;
+
+    signal spi_fsm_control      : std_logic := '0';
+    signal spi_fsm_control_addr : std_logic_vector(7 downto 0) := x"00";
+    signal spi_fsm_control_chipid       : std_logic_vector(1 downto 0) := "00";
+    signal spi_fsm_control_chipid_en    : std_logic := '0';
+
+    type spi_fsm_t is (RESET, SOFTRESET, SPI_CONF, IDLE, PASTTREC_RESET_PHASE1, PASTTREC_RESET_PHASE2, PASTTREC_RESET_PHASE3, PASTTREC_RESET_PHASE4, PASTTREC_RESET_PHASE5, SPI_REGS_ACCESS, PASTTREC_PREAUTOLOAD, PASTTREC_AUTOLOAD_CONF1, PASTTREC_AUTOLOAD_CONF2, PASTTREC_AUTOLOAD, PASTTREC_AUTOLOAD_WAIT1, PASTTREC_AUTOLOAD_WAIT2, PASTTREC_AUTOLOAD_NEXT, PASTTREC_LOAD, PASTTREC_LOAD_WAIT1, PASTTREC_LOAD_WAIT2);
+    signal spi_fsm_state            : spi_fsm_t     := RESET;
+
+    type sc_fsm_t is (IDLE,WAIT_FOR_SPI, WAIT_FOR_RAM);
+    signal sc_fsm_state             : sc_fsm_t      := IDLE;
+
+    constant PASTTREC_CMD_WIDTH     :   integer :=  19;
+    constant PASTTREC_WAIT_CYCLES   :   integer :=  7;
+begin
+
+    mem_addr3   <= std_logic_vector(to_unsigned(spi_ram_offset + to_integer(unsigned(spi_ram_addr)), 8)) when ( spi_fsm_control = '0' ) else std_logic_vector(to_unsigned(spi_ram_offset + to_integer(unsigned(spi_fsm_control_addr)), 8));
+
+    spi_active_bunch    <= spi_active_bunch_sc when spi_fsm_control = '0' else spi_active_bunch_autoload;
+
+    SPI_OUTPUTS_ASSIGMENT: for i in 0 to SPI_BUNCHES - 1 generate
+        SPI_CS_OUT(i)  <= spi_cs_out_intrnl     or not spi_active_bunch(i);
+        SPI_SCK_OUT(i) <= spi_sck_out_intrnl and spi_active_bunch(i);
+        SPI_SDO_OUT(i) <= spi_sdo_out_intrnl and spi_active_bunch(i);
+    end generate SPI_OUTPUTS_ASSIGMENT;
+    spi_sdi_in_intrnl   <= or_all(spi_active_bunch and SPI_SDI_IN);
+
+    SPI_FSM:   process
+        variable tmp    : std_logic_vector(31 downto 0) := (others => '0');
+    begin
+        wait until rising_edge(CLK);
+        spi_res         <= '0';
+        spi_read        <= '0';
+        spi_write       <= '0';
+        spi_addr        <= x"0";
+        spi_data_in     <= (others => '0');
+        --mem_addr2       <= (others => '0');
+        SPI_RST_OUT     <= (others => '1');
+
+        case spi_fsm_state is
+            when RESET      =>
+                SKIP_AUTOSTART_SEQUENCE <= '1';
+                spi_fsm_state <= SOFTRESET;
+            when SOFTRESET      =>
+                if SKIP_AUTOSTART_SEQUENCE = '1' then
+                    spi_fsm_state <= IDLE;
+                else
+                    spi_res     <=  '1';
+                    spi_fsm_state   <=  SPI_CONF;
+                    spi_fsm_control<= '1';
+                    spi_active_bunch_autoload <= (others => '0');
+                end if;
+            when SPI_CONF   =>  -- word_length 19
+                spi_write   <= '1';
+                spi_addr    <= x"1";
+                tmp         := (others => '0');
+                tmp(29 downto 20)   := std_logic_vector(to_unsigned(PASTTREC_WAIT_CYCLES, 10));
+                tmp(19 downto 14)   := std_logic_vector(to_unsigned(PASTTREC_CMD_WIDTH, 6));
+                spi_data_in <= tmp;
+                spi_fsm_state   <=  PASTTREC_RESET_PHASE1;
+            when PASTTREC_RESET_PHASE1 =>
+                --SPI_RST_OUT <= (others => '0');
+                spi_write       <= '1';
+                spi_addr        <= x"A";
+                spi_data_in     <= (others => '0');
+                spi_data_in (7 downto 0)    <= "01000001";
+                spi_fsm_control_addr    <= x"00";
+                spi_fsm_state   <= PASTTREC_RESET_PHASE2;
+            when PASTTREC_RESET_PHASE2 =>
+                SPI_RST_OUT <= (others => '0');
+                spi_active_bunch_autoload <= (others => '1');
+                if spi_ram_busy = '1' then
+                    spi_fsm_state <= PASTTREC_RESET_PHASE3;
+                end if;
+            when PASTTREC_RESET_PHASE3 =>
+                SPI_RST_OUT <= (others => '0');
+                if spi_ram_busy = '0' then
+                    spi_write   <= '1';
+                    spi_addr    <= x"A";
+                    spi_data_in <= (others => '0');
+                    spi_data_in (7 downto 0) <= "01000001";
+                    spi_fsm_state <= PASTTREC_RESET_PHASE4;
+                end if;
+            when PASTTREC_RESET_PHASE4 =>
+                if spi_ram_busy = '1' then
+                    spi_fsm_state <= PASTTREC_RESET_PHASE5;
+                end if;
+            when PASTTREC_RESET_PHASE5 =>
+                if spi_ram_busy = '0' then
+                    spi_fsm_state <= PASTTREC_PREAUTOLOAD;
+                end if;
+            when PASTTREC_PREAUTOLOAD  =>
+                spi_fsm_control_chipid_en <= '1';
+                autoload_chipid <= 0;
+                mem_addr2       <= x"02";
+                spi_fsm_state   <= PASTTREC_AUTOLOAD_CONF1;
+            when PASTTREC_AUTOLOAD_CONF1=>
+                spi_fsm_state   <= PASTTREC_AUTOLOAD_CONF2;
+            when PASTTREC_AUTOLOAD_CONF2=>
+                if autoload_chipid rem 2 = 0 then
+                    autoload_addr   <= mem_data_out2(7 downto 0);
+                    autoload_num    <= to_integer(unsigned(mem_data_out2(13 downto 8)));
+                    autoload_en     <= mem_data_out2(14);
+                else
+                    autoload_addr   <= mem_data_out2(23 downto 16);
+                    autoload_num    <= to_integer(unsigned(mem_data_out2(29 downto 24)));
+                    autoload_en     <= mem_data_out2(30);
+                end if;
+                spi_fsm_control_chipid <= SPI_CHIP_IDs(2*autoload_chipid + 1 downto 2*autoload_chipid);
+                spi_fsm_state   <= PASTTREC_AUTOLOAD;
+            when PASTTREC_AUTOLOAD  =>
+                if autoload_en = '1' then
+                    spi_fsm_control_addr    <= autoload_addr;
+                    spi_write       <= '1';
+                    spi_addr        <= x"A";
+                    spi_data_in     <= (others => '0');
+                    spi_active_bunch_autoload <= (others => '0');
+                    spi_active_bunch_autoload(autoload_chipid / SPI_PASTTREC_PER_BUNCH) <= '1';
+                    spi_data_in (7 downto 0)    <= "01" & std_logic_vector(to_unsigned(autoload_num,6));
+                    spi_fsm_state   <= PASTTREC_AUTOLOAD_WAIT1;
+                else
+                    spi_fsm_state   <= PASTTREC_AUTOLOAD_NEXT;
+                end if;
+            when PASTTREC_AUTOLOAD_WAIT1  =>
+                if (spi_ram_busy = '1') then
+                    spi_fsm_state <= PASTTREC_AUTOLOAD_WAIT2;
+                end if;
+            when PASTTREC_AUTOLOAD_WAIT2  =>
+                if (spi_ram_busy = '0') then
+                    spi_fsm_state <= PASTTREC_AUTOLOAD_NEXT;
+                end if;
+            when PASTTREC_AUTOLOAD_NEXT   =>
+                if(autoload_chipid = SPI_PASTTREC_PER_BUNCH * SPI_BUNCHES - 1) then
+                    spi_fsm_state <= IDLE;
+                    spi_fsm_control <= '0';
+                    spi_fsm_control_chipid_en <= '0';
+                else
+                    autoload_chipid <= autoload_chipid + 1;
+                    spi_fsm_state   <= PASTTREC_AUTOLOAD_CONF1;
+                    if autoload_chipid rem 2 = 1 then
+                        mem_addr2 <= std_logic_vector(to_unsigned(to_integer(unsigned(mem_addr2)) + 1,8));
+                    end if;
+                end if;
+            when IDLE       =>
+                if spi_reg_access = '1' then
+                    spi_fsm_state <= SPI_REGS_ACCESS;
+                elsif sc_reset_req = '1' then
+                    spi_fsm_state <= SOFTRESET;
+                elsif load_trigger='1' then
+                    load_chipid   <= load_past_id;
+                    spi_fsm_control_chipid <= SPI_CHIP_IDs(2*load_past_id + 1 downto 2*load_past_id);
+                    spi_fsm_control <= '1';
+                    spi_fsm_control_chipid_en <= '1';
+                    spi_fsm_control_addr <= load_addr;
+                    spi_fsm_state <= PASTTREC_LOAD;
+                end if;
+            when SPI_REGS_ACCESS =>
+                if spi_reg_rw = '1' then
+                    spi_read    <= '1';
+                else
+                    spi_write   <= '1';
+                end if;
+                spi_addr    <= spi_reg_addr;
+                spi_data_in <= spi_reg_data;
+                spi_fsm_state <= IDLE;
+            when PASTTREC_LOAD  =>
+                spi_write <= '1';
+                spi_addr        <= x"A";
+                spi_data_in     <= (others => '0');
+                spi_active_bunch_autoload <= (others => '0');
+                spi_active_bunch_autoload(load_chipid / SPI_PASTTREC_PER_BUNCH) <= '1';
+                spi_data_in (7 downto 0)    <= "01" & std_logic_vector(to_unsigned(load_num,6));
+                spi_fsm_state   <= PASTTREC_LOAD_WAIT1;
+            when PASTTREC_LOAD_WAIT1  =>
+                if (spi_ram_busy = '1') then
+                    spi_fsm_state <= PASTTREC_LOAD_WAIT2;
+                end if;
+            when PASTTREC_LOAD_WAIT2  =>
+                if (spi_ram_busy = '0') then
+                    if load_all = '1' and load_chipid /= SPI_BUNCHES * SPI_PASTTREC_PER_BUNCH - 1 then
+                        load_chipid <= load_chipid + 1;
+                        spi_fsm_control_chipid <= SPI_CHIP_IDs(2*(load_chipid+1) + 1 downto 2*(load_chipid+1));
+                        spi_fsm_state <= PASTTREC_LOAD;
+                    else
+                        spi_fsm_state <= IDLE;
+                        spi_fsm_control <= '0';
+                        spi_fsm_control_chipid_en   <= '0';
+                    end if;
+                end if;
+            when others     =>
+                spi_fsm_state   <= RESET;
+        end case;
+      
+        if BUS_RX.write = '1' and BUS_RX.addr(15 downto 8) = x"0A" then
+            SKIP_AUTOSTART_SEQUENCE <= '0'; 
+        end if;
+
+        if RST_IN = '1' then
+            spi_fsm_state <= RESET;
+        end if;
+    end process SPI_FSM;
+
+    SLOW_CTRL_FSM: process
+    begin
+        wait until rising_edge(CLK);
+        BUS_TX.ack      <= '0';
+        BUS_TX.unknown  <= '0';
+        BUS_TX.nack     <= '0';
+        BUS_TX.wack     <= '0';
+        BUS_TX.rack     <= '0';
+        BUS_TX.data     <= (others => '0');
+
+        case sc_fsm_state is
+            when IDLE           =>
+                if      sc_unknown       = '1' then
+                    BUS_TX.unknown  <= '1';
+                elsif   sc_busy          = '1' then
+                    BUS_TX.nack     <= '1';
+                elsif   sc_ram_access    = '1' then
+                    sc_fsm_state    <= WAIT_FOR_RAM;
+                elsif   sc_spi_access    = '1' then
+                    sc_fsm_state    <= WAIT_FOR_SPI;
+                elsif   sc_ack           = '1' then
+                    BUS_TX.ack      <= '1';
+                end if;
+            when WAIT_FOR_RAM   =>
+                BUS_TX.ack      <= '1';
+                BUS_TX.data     <= mem_data_out1;
+                sc_fsm_state    <= IDLE;
+            when WAIT_FOR_SPI   =>
+                if spi_ack = '1' then
+                    BUS_TX.ack  <= '1';
+                    BUS_TX.data <= spi_data_out;
+                    sc_fsm_state<= IDLE;
+                elsif spi_busy = '1' then
+                    BUS_TX.nack <= '1';
+                    BUS_TX.data <= spi_data_out;
+                    sc_fsm_state<= IDLE;
+                elsif spi_unk  = '1' then
+                    BUS_TX.unknown  <= '1';
+                    BUS_TX.data <= spi_data_out;
+                    sc_fsm_state    <= IDLE;
+                end if;
+            when others         =>
+                sc_fsm_state    <= IDLE;
+        end case;
+        if RST_IN = '1' or spi_fsm_state = SOFTRESET then
+            sc_fsm_state <= IDLE;
+        end if;
+    end process SLOW_CTRL_FSM;
+
+    SPI_MEMORY_BUS: process(mem_data_out3, spi_fsm_control_chipid_en, spi_fsm_control_chipid)
+    begin
+        spi_ram_data <= mem_data_out3;
+        if spi_fsm_control_chipid_en = '1' then
+            spi_ram_data(14 downto 13) <= spi_fsm_control_chipid;
+        end if;
+    end process SPI_MEMORY_BUS;
+
+    MEMORY: entity work.ram_dp_pasttrec
+        generic map(
+            depth   => 8,
+            width   => 32,
+            initfile=> "../code/memory.hex"
+        )
+        port map(
+            CLK   => CLK,
+            wr1   => mem_write,
+            a1    => mem_addr1,
+            dout1 => mem_data_out1,
+            din1  => mem_data_in1,
+            a2    => mem_addr2,
+            dout2 => mem_data_out2,
+            a3    => mem_addr3,
+            dout3 => mem_data_out3
+        );
+
+    SPI_INTERFACE: entity work.spi_ltc2600_pasttrec
+        generic map(
+            BITS            =>  PASTTREC_CMD_WIDTH,
+            WAITCYCLES      =>  PASTTREC_WAIT_CYCLES
+        ) port map(
+            CLK_IN          =>  CLK,
+            RESET_IN        =>  spi_res,
+            BUS_READ_IN     =>  spi_read,
+            BUS_WRITE_IN    =>  spi_write,
+            BUS_BUSY_OUT    =>  spi_busy,
+            BUS_ACK_OUT     =>  spi_ack,
+            BUS_UNK_OUT     =>  spi_unk,
+            BUS_ADDR_IN     =>  spi_addr,
+            BUS_DATA_IN     =>  spi_data_in,
+            BUS_DATA_OUT    =>  spi_data_out,
+            SPI_CS_OUT      =>  spi_cs_out_intrnl,
+            SPI_SDI_IN      =>  spi_sdi_in_intrnl,
+            SPI_SDO_OUT     =>  spi_sdo_out_intrnl,
+            SPI_SCK_OUT     =>  spi_sck_out_intrnl,
+            RAM_BUSY        =>  spi_ram_busy,
+            RAM_OFFSET      =>  spi_ram_offset,
+            RAM_DATA        =>  spi_ram_data
+        );
+
+    SLOW_CONTROL : process
+        constant PAST_ID_WIDTH : integer  := integer(ceil(log2(real(SPI_BUNCHES * SPI_PASTTREC_PER_BUNCH))));
+        variable past_id       : std_logic_vector(PAST_ID_WIDTH - 1 downto 0);
+        variable active_bunches: std_logic_vector(SPI_BUNCHES-1 downto 0);
+        variable active_chip_id: std_logic_vector(1 downto 0);
+    begin
+        wait until rising_edge(CLK);
+        mem_addr1       <= x"00";
+        mem_write       <= '0';
+        mem_data_in1    <= x"00000000";
+
+        sc_ram_access   <= '0';
+        sc_unknown      <= '0';
+        sc_busy         <= '0';
+        sc_ack          <= '0';
+        sc_spi_access   <= '0';
+        sc_reset_req    <= '0';
+
+        spi_reg_access  <= '0';
+
+        load_trigger    <= '0';
+
+        if sc_fsm_state = IDLE then
+            if BUS_RX.write = '1' then
+                --BUS_TX.ack  <= '1';
+                if spi_fsm_state = IDLE then
+                    if BUS_RX.addr(15 downto 8) = x"00" then            -- MEMORY
+                        if BUS_RX.addr = x"a001" and spi_ram_busy = '1' then
+                            sc_busy <= '1';
+                        else
+                            mem_addr1       <= BUS_RX.addr (7 downto 0);
+                            mem_data_in1    <= BUS_RX.data;
+                            mem_write       <= '1';
+                            sc_ram_access   <= '1';
+                        end if;
+                    elsif BUS_RX.addr(15 downto 8) = x"01" and BUS_RX.addr(7 downto 4) = x"0" then            -- SPI REGISTERS
+                        if spi_ram_busy = '1' and BUS_RX.addr(3 downto 0) /= "0000" then
+                            sc_busy <= '1';
+                        else
+                            spi_reg_access  <= '1';
+                            spi_reg_rw      <= '0';
+                            spi_reg_addr    <= BUS_RX.addr (3 downto 0);
+                            spi_reg_data    <= BUS_RX.data;
+                            sc_spi_access   <= '1';
+                        end if;
+                    elsif BUS_RX.addr(15 downto 8) = x"02" and or_all(BUS_RX.addr(7 downto 4 + PAST_ID_WIDTH)) = '0' then         -- PASTTREC REGISTERS
+                        past_id := BUS_RX.addr(4 + PAST_ID_WIDTH - 1 downto 4);
+                        active_bunches := (others => '0');
+                        active_bunches(to_integer(unsigned( past_id)) / SPI_PASTTREC_PER_BUNCH) := '1';
+                        active_chip_id := SPI_CHIP_IDs( to_integer(unsigned( past_id))*2+1 downto to_integer(unsigned( past_id))*2 );
+                        
+                        if spi_ram_busy = '1' or spi_fsm_state /= IDLE then
+                            sc_busy <= '1';
+                        elsif to_integer(unsigned(past_id)) >= SPI_PASTTREC_PER_BUNCH * SPI_BUNCHES then
+                            sc_unknown <= '1';
+                        else    
+                            spi_active_bunch_sc <= active_bunches;
+
+                            mem_addr1       <= x"01";
+                            mem_write       <= '1';
+                            mem_data_in1    <= (others => '0');
+                            mem_data_in1(7 downto 0)    <= BUS_RX.data(7 downto 0);
+                            mem_data_in1(11 downto 8)   <= BUS_RX.addr(3 downto 0);
+                            mem_data_in1(12)            <= '0';
+                            mem_data_in1(14 downto 13)  <= active_chip_id;
+                            mem_data_in1(18 downto 15)  <= "1010";
+
+                            --spi_ram_addr    <= x"01";
+
+                            spi_reg_access  <= '1';
+                            spi_reg_rw      <= '0';
+                            spi_reg_addr    <= x"A";
+                            spi_reg_data    <= (others => '0');
+                            spi_reg_data(7 downto 0)    <= "01000001";
+                            sc_spi_access   <= '1';
+                        end if;
+
+                    elsif BUS_RX.addr(15 downto 8) = x"0A" then         -- CMD
+                        if BUS_RX.addr(7 downto 0) = x"00" then
+                            sc_reset_req    <= '1';
+                            sc_ack          <= '1';
+                        elsif BUS_RX.addr(2 downto 0) = o"1" then
+                            if BUS_RX.addr(3) = '1' then
+                                load_past_id <= 0;
+                            else
+                                load_past_id <= to_integer(unsigned(BUS_RX.addr(7 downto 4)));
+                            end if;
+                            if BUS_RX.addr(3) = '0' and to_integer(unsigned(BUS_RX.addr(7 downto 4))) >= SPI_BUNCHES * SPI_PASTTREC_PER_BUNCH then
+                                sc_unknown <= '1';
+                            else
+                                load_trigger    <= '1';
+                                load_all<= BUS_RX.addr(3);
+                                load_addr   <= BUS_RX.data(7 downto 0);
+                                load_num    <= to_integer(unsigned( BUS_RX.data(13 downto 8) ));
+                                sc_ack <= '1';
+                            end if;
+                        else
+                            sc_unknown <= '1';
+                        end if;
+                    else
+                        sc_unknown <= '1';
+                    end if;
+                else
+                    sc_busy   <= '1';
+                end if;
+            elsif BUS_RX.read = '1' then
+                if BUS_RX.addr(15 downto 8) = x"00" then
+                    mem_addr1       <= BUS_RX.addr(7 downto 0);
+                    sc_ram_access   <= '1';
+                elsif BUS_RX.addr(15 downto 8) = x"01" then
+                    spi_reg_access  <= '1';
+                    spi_reg_rw      <= '1';
+                    spi_reg_addr    <= BUS_RX.addr (3 downto 0);
+                    sc_spi_access   <= '1';
+                elsif BUS_RX.addr(15 downto 8) = x"02" and or_all(BUS_RX.addr(7 downto 4 + PAST_ID_WIDTH)) = '0' then         -- PASTTREC REGISTERS
+                    past_id := BUS_RX.addr(4 + PAST_ID_WIDTH - 1 downto 4);
+                    active_bunches := (others => '0');
+                    active_bunches(to_integer(unsigned( past_id)) / SPI_PASTTREC_PER_BUNCH) := '1';
+                    active_chip_id := SPI_CHIP_IDs( to_integer(unsigned( past_id))*2+1 downto to_integer(unsigned( past_id))*2 );
+                    
+                    if spi_ram_busy = '1' or spi_fsm_state /= IDLE then
+                        sc_busy <= '1';
+                    elsif to_integer(unsigned(past_id)) >= SPI_PASTTREC_PER_BUNCH * SPI_BUNCHES then
+                        sc_unknown <= '1';
+                    else    
+                        spi_active_bunch_sc <= active_bunches;
+
+                        mem_addr1       <= x"01";
+                        mem_write       <= '1';
+                        mem_data_in1    <= (others => '0');
+                        mem_data_in1(7 downto 0)    <= x"00";
+                        mem_data_in1(11 downto 8)   <= BUS_RX.addr(3 downto 0);
+                        mem_data_in1(12)            <= '1';
+                        mem_data_in1(14 downto 13)  <= active_chip_id;
+                        mem_data_in1(18 downto 15)  <= "1010";
+
+                            --spi_ram_addr    <= x"01";
+
+                        spi_reg_access  <= '1';
+                        spi_reg_rw      <= '0';
+                        spi_reg_addr    <= x"A";
+                        spi_reg_data    <= (others => '0');
+                        spi_reg_data(7 downto 0)    <= "01000001";
+                        sc_spi_access   <= '1';
+                    end if;
+                else
+                    sc_unknown      <= '1';
+                end if;
+            end if;
+        end if;
+    end process;
+
+end architecture;
diff --git a/code/pasttrec_spi/ram_dp_pasttrec.vhd b/code/pasttrec_spi/ram_dp_pasttrec.vhd
new file mode 100644 (file)
index 0000000..0e66981
--- /dev/null
@@ -0,0 +1,115 @@
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.std_logic_ARITH.ALL;
+USE IEEE.std_logic_UNSIGNED.ALL;
+
+use std.textio.all;
+
+library work;
+use work.trb_net_std.all;
+
+entity ram_dp_pasttrec is
+  generic(
+    depth : integer := 2;
+    width : integer := 4;
+    initfile : string := ""
+    );
+  port(
+    CLK   : in  std_logic;
+    wr1   : in  std_logic;
+    a1    : in  std_logic_vector(depth-1 downto 0);
+    dout1 : out std_logic_vector(width-1 downto 0);
+    din1  : in  std_logic_vector(width-1 downto 0);
+    a2    : in  std_logic_vector(depth-1 downto 0);
+    dout2 : out std_logic_vector(width-1 downto 0);
+    a3    : in  std_logic_vector(depth-1 downto 0);
+    dout3 : out std_logic_vector(width-1 downto 0)
+    );
+end entity;
+
+architecture ram_dp_arch of ram_dp_pasttrec is
+    type ram_t is array(0 to 2**depth-1) of std_logic_vector(width-1 downto 0);
+
+    impure function read_from_file(filename : string) return ram_t is
+        file text_file      : text open read_mode is filename;
+        variable text_line  : line;
+        variable mem        : ram_t;
+        variable c : character;
+        variable offset : integer;
+        variable hex_val : std_logic_vector(3 downto 0);
+    begin
+        for i in 0 to 2**depth-1 loop
+            readline(text_file, text_line);
+            --hread(text_line, mem(i));
+
+            offset := 0;
+
+            while offset < mem(i)'high loop
+            read(text_line, c);
+
+            case c is
+                when '0' => hex_val := "0000";
+                when '1' => hex_val := "0001";
+                when '2' => hex_val := "0010";
+                when '3' => hex_val := "0011";
+                when '4' => hex_val := "0100";
+                when '5' => hex_val := "0101";
+                when '6' => hex_val := "0110";
+                when '7' => hex_val := "0111";
+                when '8' => hex_val := "1000";
+                when '9' => hex_val := "1001";
+                when 'A' | 'a' => hex_val := "1010";
+                when 'B' | 'b' => hex_val := "1011";
+                when 'C' | 'c' => hex_val := "1100";
+                when 'D' | 'd' => hex_val := "1101";
+                when 'E' | 'e' => hex_val := "1110";
+                when 'F' | 'f' => hex_val := "1111";
+
+                when others =>
+                hex_val := "XXXX";
+                assert false report "Found non-hex character '" & c & "'";
+            end case;
+
+            mem(i)(mem(i)'high - offset
+                downto mem(i)'high - offset - 3) := hex_val;
+            offset := offset + 4;
+
+            end loop;
+
+        end loop;
+        return mem;
+    end function;
+
+    SIGNAL ram : ram_t := read_from_file(initfile);
+--  signal ram : std_logic_vector(2**depth*width-1 downto 0)  := content;
+begin
+
+
+  process(CLK)
+    begin
+      if rising_edge(CLK) then
+        if a1 /= x"00" then
+            if wr1 = '1' then
+                ram(conv_integer(a1))   <= din1;
+                dout1                   <= din1;
+            else
+                dout1 <= ram(conv_integer(a1));
+            end if;
+        else
+            dout1 <= x"00000000";
+        end if;
+
+        if a2 /= x"00" then
+            dout2 <= ram(conv_integer(a2));
+        else
+            dout2 <= x"00000000";
+        end if;
+        if a3 /= x"00" then
+            dout3 <= ram(conv_integer(a3));
+        else
+            dout3 <= x"00000000";
+        end if;
+      end if;
+    end process;
+
+end architecture;
diff --git a/code/pasttrec_spi/spi_ltc2600_pasttrec.vhd b/code/pasttrec_spi/spi_ltc2600_pasttrec.vhd
new file mode 100644 (file)
index 0000000..afe496f
--- /dev/null
@@ -0,0 +1,313 @@
+library IEEE;
+use IEEE.STD_LOGIC_1164.all;
+use IEEE.numeric_std.all;
+
+library work;
+use work.trb_net_std.all;
+
+entity spi_ltc2600_pasttrec is
+  generic(
+    BITS       : integer range 8 to 32   := 32;
+    WAITCYCLES : integer range 2 to 1024 := 7
+    );
+  port(
+    CLK_IN       : in  std_logic;
+    RESET_IN     : in  std_logic;
+    -- Slave bus
+    BUS_READ_IN  : in  std_logic;
+    BUS_WRITE_IN : in  std_logic;
+    BUS_BUSY_OUT : out std_logic;
+    BUS_ACK_OUT  : out std_logic;
+    BUS_UNK_OUT  : out std_logic;
+    BUS_ADDR_IN  : in  std_logic_vector(3 downto 0);
+    BUS_DATA_IN  : in  std_logic_vector(31 downto 0);
+    BUS_DATA_OUT : out std_logic_vector(31 downto 0);
+    -- SPI connections
+    SPI_CS_OUT   : out std_logic;
+    SPI_SDI_IN   : in  std_logic;
+    SPI_SDO_OUT  : out std_logic;
+    SPI_SCK_OUT  : out std_logic;
+    -- EXTERNAL RAM
+    RAM_BUSY    : out std_logic;
+    RAM_OFFSET  : out integer range 0 to 63;
+    RAM_DATA    : in  std_logic_vector(31 downto 0)
+    );
+end entity;
+
+
+architecture spi_ltc2600_arch of spi_ltc2600_pasttrec is
+
+
+  signal ram_addr       : integer range 0 to 63;
+  --signal ram_data       : std_logic_vector(31 downto 0);
+  signal ctrl_reg       : std_logic_vector(31 downto 0) := (others => '0');
+  signal start          : std_logic;
+--   signal invert_reg     : std_logic;
+  signal override_cs, override_sck, override_sdo : std_logic := '0';
+  signal invert_cs, invert_sck, invert_sdo       : std_logic := '0';
+  
+  signal spi_cs  : std_logic;
+  signal spi_sck : std_logic;
+  signal spi_sdo : std_logic;
+  signal spi_sdi : std_logic;
+
+  signal word_count : integer range 0 to 63 := 1;
+  signal bit_count  : integer range 0 to BITS-1;
+  signal time_count : integer range 0 to 1023;
+  signal readback   : std_logic_vector(31 downto 0);
+  signal blocked    : std_logic :='0';
+  signal reset_fsm  : std_logic;
+  type   fsm_t is (IDLE, WAIT_STATE, SET, TOGGLE_CS, TOGGLE_CS_0, TOGGLE_CS_1, TOGGLE_CS_2, FINISH, PRESTART, PRESTART2);
+  signal fsm_state : fsm_t;
+  signal word_length : integer range 0 to BITS := BITS;
+  
+  signal wait_cycles : integer range 0 to 1023 := WAITCYCLES;
+  
+begin
+
+    --CTRL_REG               spi_ltc2600
+    --mod
+    --BITS            option
+    --31              reset
+    --30              --
+    --29..20      wait_cycles
+    --19..14      word_length
+    --13              override_sdo
+    --12              override_sck
+    --11              override_cs
+    --10              invert_sdo
+    --9                   invert_sck
+    --8                   invert_cs
+    --7                   block
+    --6                   start
+    --5..0            word_count
+
+    reset_fsm       <=  ctrl_reg(31);
+    wait_cycles     <=  to_integer(unsigned(ctrl_reg(29 downto 20)));
+    word_length     <=  to_integer(unsigned(ctrl_reg(19 downto 14)));
+    override_sdo    <=  ctrl_reg(13);
+    override_sck    <=  ctrl_reg(12);
+    override_cs     <=  ctrl_reg(11);
+    invert_sdo      <=  ctrl_reg(10);
+    invert_sck      <=  ctrl_reg(9);
+    invert_cs       <=  ctrl_reg(8);
+    blocked         <=  ctrl_reg(7);
+    start           <=  ctrl_reg(6);
+
+    RAM_OFFSET      <= ram_addr;
+
+    PROC_MEM : process
+    begin
+        wait until rising_edge(CLK_IN);
+
+        BUS_ACK_OUT  <= '0';
+        BUS_UNK_OUT  <= '0';
+        BUS_BUSY_OUT <= '0';
+        BUS_DATA_OUT <= (others => '0');
+        ctrl_reg(6)  <= '0';
+        ctrl_reg(31) <= '0';
+
+        if BUS_WRITE_IN = '1' then
+            if fsm_state = IDLE and blocked = '0' then
+                BUS_ACK_OUT <= '1';
+                if BUS_ADDR_IN(3 downto 0) = x"0" then                                   -- RESET
+                    ctrl_reg(31) <= BUS_DATA_IN(31);
+                elsif BUS_ADDR_IN(3 downto 0) = x"1" then                                   -- all CTRL_REG
+                    ctrl_reg    <= BUS_DATA_IN(31 downto 0);
+                    ctrl_reg(7) <= BUS_DATA_IN(7) and or_all(BUS_DATA_IN(5 downto 0));
+                    ctrl_reg(6) <= BUS_DATA_IN(6) and or_all(BUS_DATA_IN(5 downto 0));
+                elsif BUS_ADDR_IN(3 downto 0) = x"2" then                                   -- override / invert
+                    ctrl_reg(13 downto 8)       <= BUS_DATA_IN(5 downto 0);
+                elsif BUS_ADDR_IN(3 downto 0) = x"3" then                                   -- wait_cycles / word_length
+                    ctrl_reg(29 downto 14)      <= BUS_DATA_IN(15 downto 0);
+                elsif BUS_ADDR_IN(3 downto 0) = x"A" then  --0x11                           -- start transmitting
+                    ctrl_reg(7 downto 0)        <= BUS_DATA_IN(7 downto 0);
+                    ctrl_reg(7) <= BUS_DATA_IN(7) and or_all(BUS_DATA_IN(5 downto 0));
+                    ctrl_reg(6) <= BUS_DATA_IN(6) and or_all(BUS_DATA_IN(5 downto 0));
+                else
+                    BUS_ACK_OUT <= '0';
+                    BUS_UNK_OUT <= '1';
+                end if;
+            elsif BUS_ADDR_IN = "0000" then   --Reg. 0x13
+                ctrl_reg(31)   <= BUS_DATA_IN(31);
+                BUS_ACK_OUT <= '1';
+            else
+                BUS_BUSY_OUT <= '1';
+            end if;
+        end if;
+
+        if BUS_READ_IN = '1' then
+            BUS_ACK_OUT <= '1';
+            if BUS_ADDR_IN(3 downto 0) = x"1" then                   -- all CTRL_REG
+                BUS_DATA_OUT <= ctrl_reg;
+            elsif BUS_ADDR_IN(3 downto 0) = x"2" then                   -- override / invert
+                BUS_DATA_OUT(5 downto 0)  <= ctrl_reg(13 downto 8);
+            elsif BUS_ADDR_IN(3 downto 0) = x"3" then                   -- wait_cycles / word_length
+                BUS_DATA_OUT(15 downto 0) <= ctrl_reg(29 downto 14);
+            elsif BUS_ADDR_IN(3 downto 0) = x"B" then                   -- receiving
+                BUS_DATA_OUT <= readback;
+                ctrl_reg(7)  <= '0';
+            else
+                BUS_ACK_OUT <= '0';
+                BUS_UNK_OUT <= '1';
+            end if;
+        end if;
+
+    end process;
+
+
+    PROC_FSM : process
+    begin
+        wait until rising_edge(CLK_IN);
+        case fsm_state is
+        when IDLE =>
+
+            if start = '1' then
+                ram_addr   <= 0;
+                word_count <= to_integer(unsigned(ctrl_reg(5 downto 0)));
+                bit_count  <= word_length-1;
+                time_count <= wait_cycles;
+                fsm_state  <= PRESTART;
+                spi_cs     <= '1';
+                spi_sck    <= '0';
+            else
+                spi_cs  <= '0';
+                spi_sck <= '0';
+            end if;
+
+        when PRESTART =>
+            fsm_state <= PRESTART2;
+
+        when PRESTART2 =>
+            spi_sdo <= RAM_DATA(bit_count);
+            bit_count <= bit_count - 1;
+            fsm_state <= WAIT_STATE;
+
+        when WAIT_STATE =>
+            if time_count = 0 then
+            fsm_state <= SET;
+            else
+            time_count <= time_count - 1;
+            end if;
+
+        when SET =>
+            time_count <= wait_cycles;
+            spi_sck    <= not spi_sck;
+            if spi_sck = '1' then
+                spi_sdo <= RAM_DATA(bit_count);
+                if bit_count <= 6 then
+                    readback  <= readback(30 downto 0) & spi_sdi;
+                end if;
+                if bit_count /= 0 then
+                    bit_count <= bit_count - 1;
+                    fsm_state <= WAIT_STATE;
+                else
+                    ram_addr  <= ram_addr + 1;
+                    bit_count <= word_length-1;
+                    if ram_addr /= word_count -1 then
+                        fsm_state <= TOGGLE_CS;
+                    else
+                        fsm_state <= FINISH;
+                        time_count <= 0;
+                    end if;
+                end if;
+            else
+                fsm_state <= WAIT_STATE;
+            end if;
+        when TOGGLE_CS =>
+            if time_count = 0 and spi_sck = '0' then
+                time_count <= wait_cycles;
+                spi_sck    <= not spi_sck;
+            elsif time_count = 0 and spi_sck = '1' then
+                fsm_state <= TOGGLE_CS_0;
+                spi_sck    <= not spi_sck;
+                readback  <= readback(30 downto 0) & spi_sdi;
+                spi_cs     <= '0';
+                spi_sdo    <= '0';
+                time_count <= wait_cycles;
+            else
+                time_count <= time_count - 1;
+            end if;
+        when TOGGLE_CS_0 =>
+            if time_count = 0 then
+                spi_sck    <= not spi_sck;
+                fsm_state  <= TOGGLE_CS_1;
+                time_count <= wait_cycles;
+            else
+                time_count <= time_count - 1;
+            end if;
+        when TOGGLE_CS_1 =>
+            if time_count = 0 then
+                spi_cs     <= '1';
+                --spi_sck    <= not spi_sck;
+                bit_count  <= word_length-1;
+                fsm_state  <= SET;
+                time_count <= wait_cycles;
+            else
+                time_count <= time_count - 1;
+            end if;
+        when TOGGLE_CS_2 =>
+            time_count <= time_count - 1;
+            if time_count = 0 then
+            spi_sck    <= not spi_sck;
+            fsm_state  <= WAIT_STATE;
+            time_count <= wait_cycles;
+            end if;
+        when FINISH =>
+
+            if time_count = 0 then
+                if spi_sck = '0' then
+                    time_count <= (12*wait_cycles);
+                else
+                    fsm_state <= IDLE;
+                    spi_sck   <= '0';
+                end if;
+            else
+                time_count <= time_count - 1;
+                if time_count = 11*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 1
+                elsif time_count = 10*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 0
+                    readback   <= readback(30 downto 0) & spi_sdi;
+                    spi_sdo    <= '0';
+                    spi_cs     <= '0';
+                elsif time_count = 9*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 1
+                elsif time_count = 8*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 0
+                elsif time_count = 7*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 1
+                elsif time_count = 6*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 0
+                elsif time_count = 5*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 1
+                elsif time_count = 4*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 0
+                elsif time_count = 3*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 1
+                elsif time_count = 2*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 0
+                elsif time_count = 1*wait_cycles then
+                    spi_sck    <= not spi_sck; -- to 1
+                end if;
+            end if;
+        end case;
+        if RESET_IN = '1' or reset_fsm = '1' then
+            fsm_state <= IDLE;
+            spi_cs  <= '0';
+            spi_sck <= '0';
+            spi_sdo <= '0';
+            readback  <= (others => '0');
+        end if;
+    end process;
+
+    -- Outputs and Inputs
+    RAM_BUSY <= '1' when fsm_state /= IDLE else '0';
+
+    spi_sdi <= (SPI_SDI_IN and spi_cs);
+
+    SPI_CS_OUT      <= not ((spi_cs and not override_cs)  xor invert_cs);
+    SPI_SDO_OUT     <=      (spi_sdo   and spi_cs and not override_sdo) xor invert_sdo;
+    SPI_SCK_OUT     <=      (spi_sck   and not override_sck) xor invert_sck;
+  
+end architecture;
diff --git a/code/pasttrec_spi/tb/pasttrec_spi_tb.vhd b/code/pasttrec_spi/tb/pasttrec_spi_tb.vhd
new file mode 100644 (file)
index 0000000..9e0f8f7
--- /dev/null
@@ -0,0 +1,736 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use std.textio.all;
+
+use IEEE.math_real.all;
+
+library work;
+use work.trb_net_std.all;
+use work.clocked_tdc_pkg.all;
+
+entity pasttrec_spi_tb is
+end entity;
+
+architecture tb of pasttrec_spi_tb is
+    signal CLK    : std_logic;
+    signal BUS_RX : CTRLBUS_RX;
+    signal BUS_TX : CTRLBUS_TX;
+
+    signal RST_IN : std_logic;
+
+    signal SPI_CS_OUT      : std_logic;
+    signal SPI_SDI_IN      : std_logic;
+    signal SPI_SDO_OUT     : std_logic;
+    signal SPI_SCK_OUT     : std_logic;
+    signal SPI_RST_OUT     : std_logic;
+
+    constant TbPeriod : time := 5 ns; -- EDIT Put right period here
+    signal TbSimEnded : std_logic := '0';
+
+    type spi_hist_t is array(0 to 10000) of std_logic_vector(18 downto 0);
+    signal spi_hist        : spi_hist_t;
+    signal spi_hist_ind    : integer := 0;
+    signal spi_catch_active: std_logic := '0';
+
+    procedure echo (arg : in string := "") is
+    begin
+        std.textio.write(std.textio.output, arg);
+    end procedure echo;
+
+    type ram_t is array(0 to 2**8-1) of std_logic_vector(32-1 downto 0);
+    impure function read_from_file(filename : string) return ram_t is
+        file text_file      : text open read_mode is filename;
+        variable text_line  : line;
+        variable mem        : ram_t;
+    begin
+        for i in 0 to 2**8-1 loop
+            readline(text_file, text_line);
+            hread(text_line, mem(i));
+        end loop;
+        return mem;
+    end function;
+
+    SIGNAL ram : ram_t := read_from_file("../code/memory.hex");
+
+    signal wait_for_responce : std_logic_vector(2 downto 0);
+    signal wait_en           : std_logic := '0';
+    signal wait_cnt          : integer :=0;
+    signal wait_end          : std_logic := '0';
+    signal wait_error        : std_logic := '0';
+    constant max_wait_cnt    : integer := 5;
+begin
+
+    responce_proc : process
+        variable tmp : std_logic_vector(2 downto 0);
+    begin
+        wait until falling_edge(CLK);
+        wait_end <= '0';
+        wait_error <= '0';
+
+        if wait_en = '0' then
+            wait_cnt <= 0;
+        else
+            assert wait_cnt < max_wait_cnt report "Timeout violated!";
+            if not(wait_cnt < max_wait_cnt) then
+                wait_end <= '1';
+                wait_error <= '1';
+            elsif (BUS_TX.ack = '1' or BUS_TX.nack = '1' or BUS_TX.unknown = '1') then
+                tmp := BUS_TX.ack & BUS_TX.nack & BUS_TX.unknown;
+                assert (BUS_TX.ack = wait_for_responce(2) and BUS_TX.nack = wait_for_responce(1) and BUS_TX.unknown = wait_for_responce(0)) report "Incorrect answer. Shoud be: " & to_string(wait_for_responce) & " actual is: " & to_string(tmp);
+                if not (BUS_TX.ack = wait_for_responce(2) and BUS_TX.nack = wait_for_responce(1) and BUS_TX.unknown = wait_for_responce(0)) then
+                    wait_end <= '1';
+                    wait_error <= '1';
+                else
+                    wait_end <= '1';
+                end if;
+            else
+                wait_cnt <= wait_cnt + 1;
+            end if;
+        end if;
+    end process;
+
+    dut : entity work.pasttrec_spi
+    generic map(
+        SPI_BUNCHES => 1,
+        SPI_PASTTREC_PER_BUNCH => 4,
+        SPI_CHIP_IDs => (7 downto 0 => "11100100", others => '0')
+    )port map (
+                CLK    => CLK,
+                BUS_RX => BUS_RX,
+                BUS_TX => BUS_TX,
+
+                RST_IN => RST_IN,
+
+                SPI_CS_OUT(0)  =>  SPI_CS_OUT,
+                SPI_SDI_IN(0)  =>  SPI_SDI_IN,
+                SPI_SDO_OUT(0) =>  SPI_SDO_OUT,
+                SPI_SCK_OUT(0) =>  SPI_SCK_OUT,
+                SPI_RST_OUT(0) =>  SPI_RST_OUT
+              );
+
+    -- Clock generation
+    clocking: process
+    begin
+        CLK <= '1';
+        wait for TbPeriod / 2;
+        CLK <= '0';
+        wait for TbPeriod / 2;
+        if TbSimEnded = '1' then
+            wait;
+        end if;
+    end process clocking;
+
+    stimuli : process
+        variable data           : std_logic_vector(18 downto 0);
+        variable num_of_errors  : integer := 0;
+        variable tmp            : std_logic_vector(31 downto 0);
+        variable index          : integer := 0;
+        variable start_autoload_ind : integer;
+    begin
+        -- EDIT Adapt initialization as needed
+        BUS_RX.data     <= (others => '0');
+        BUS_RX.addr     <= (others => '0');
+        BUS_RX.write    <= '0';
+        BUS_RX.read     <= '0';
+        BUS_RX.timeout  <= '0';
+        RST_IN          <= '1';
+        SPI_SDI_IN      <= '1';
+
+        wait for 4 * TbPeriod;
+        wait until falling_edge(CLK);
+        RST_IN          <= '0';
+
+
+        wait until rising_edge(SPI_RST_OUT);
+        wait until rising_edge(SPI_CS_OUT);
+        wait for 5000*TbPeriod;
+
+        wait for 10 * TbPeriod;
+        wait until falling_edge(CLK);
+
+        echo ("MEMORY CHECK ---------------------------" & lf);
+        for i in 0 to 16 loop
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '1';
+            BUS_RX.addr <= x"a0" & std_logic_vector(to_unsigned(i, 8));
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '0';
+
+            --------------- WAIT BLOCK------------------
+            wait_for_responce <= "100";
+            wait_en <= '1';
+            wait until rising_edge(CLK) and wait_end = '1';
+            if wait_error = '1' then
+                num_of_errors := num_of_errors + 1;
+            end if;
+            wait_en <= '0';
+            --------------- END WAIT BLOCK------------------
+
+            echo( "Memory addr=" & integer'image(i) & "  DATA: " & to_hstring(BUS_TX.data) & lf);
+            assert BUS_TX.data = ram(i) report "MEMORY ERROR";
+            if BUS_TX.data /= ram(i) then
+                num_of_errors := num_of_errors + 1;
+            end if;
+        end loop;
+        echo ("ERRORS: " & integer'image(num_of_errors) & "------------" & lf & lf & lf);
+
+
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a002";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a003";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+
+        wait for 5 * TbPeriod;
+
+        echo ("SPI REGISTERS CHECK ---------------------------" & lf);
+
+        for i in 0 to 2**15-1 loop
+            wait until falling_edge(CLK);
+            BUS_RX.write <= '1';
+            BUS_RX.addr  <= x"a101";
+            tmp(31 downto 8):= std_logic_vector(to_unsigned(i,24));
+            tmp(7 downto 0) := "00000000";
+            if to_integer(unsigned (tmp(19 downto 14))) > 19 then
+                tmp(19 downto 14) := std_logic_vector(to_unsigned(19, 6));
+            end if;
+            BUS_RX.data  <= tmp;
+            wait until falling_edge(CLK);
+            BUS_RX.write <= '0';
+
+            --------------- WAIT BLOCK------------------
+            wait_for_responce <= "100";
+            wait_en <= '1';
+            wait until rising_edge(CLK) and wait_end = '1';
+            if wait_error = '1' then
+                num_of_errors := num_of_errors + 1;
+            end if;
+            wait_en <= '0';
+            --------------- END WAIT BLOCK------------------
+
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '1';
+            BUS_RX.addr  <= x"a101";
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '0';
+
+            --------------- WAIT BLOCK------------------
+            wait_for_responce <= "100";
+            wait_en <= '1';
+            wait until rising_edge(CLK) and wait_end = '1';
+            if wait_error = '1' then
+                num_of_errors := num_of_errors + 1;
+            end if;
+            wait_en <= '0';
+            --------------- END WAIT BLOCK------------------
+
+            assert BUS_TX.data = tmp report "Incorrect data";
+            if not (BUS_TX.data = tmp) then
+                num_of_errors := num_of_errors+1;
+            end if;
+
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '1';
+            BUS_RX.addr  <= x"a102";
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '0';
+
+            --------------- WAIT BLOCK------------------
+            wait_for_responce <= "100";
+            wait_en <= '1';
+            wait until rising_edge(CLK) and wait_end = '1';
+            if wait_error = '1' then
+                num_of_errors := num_of_errors + 1;
+            end if;
+            wait_en <= '0';
+            --------------- END WAIT BLOCK------------------
+
+            assert BUS_TX.data(5 downto 0) = tmp(13 downto 8) report "Incorrect data";
+            if not (BUS_TX.data(5 downto 0) = tmp(13 downto 8)) then
+                num_of_errors := num_of_errors+1;
+            end if;
+
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '1';
+            BUS_RX.addr  <= x"a107";
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '0';
+
+            --------------- WAIT BLOCK------------------
+            wait_for_responce <= "001";
+            wait_en <= '1';
+            wait until rising_edge(CLK) and wait_end = '1';
+            if wait_error = '1' then
+                num_of_errors := num_of_errors + 1;
+            end if;
+            wait_en <= '0';
+            --------------- END WAIT BLOCK------------------
+
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '1';
+            BUS_RX.addr  <= x"a103";
+            wait until falling_edge(CLK);
+            BUS_RX.read <= '0';
+
+            --------------- WAIT BLOCK------------------
+            wait_for_responce <= "100";
+            wait_en <= '1';
+            wait until rising_edge(CLK) and wait_end = '1';
+            if wait_error = '1' then
+                num_of_errors := num_of_errors + 1;
+            end if;
+            wait_en <= '0';
+            --------------- END WAIT BLOCK------------------
+
+            assert BUS_TX.data(15 downto 0) = tmp(29 downto 14) report "Incorrect data";
+            if not (BUS_TX.data(15 downto 0) = tmp(29 downto 14)) then
+                num_of_errors := num_of_errors+1;
+            end if;
+
+        end loop;
+        echo ("ERRORS: " & integer'image(num_of_errors) & "------------" & lf & lf & lf);
+
+        wait until falling_edge(CLK);
+        report "SPI REGISTERS RESET ---------------------------" & lf;
+        RST_IN <= '1';
+        wait until falling_edge(CLK);
+        RST_IN <= '0';
+
+        wait until rising_edge(SPI_RST_OUT);
+        wait until rising_edge(SPI_CS_OUT);
+        wait for 150*TbPeriod;
+        spi_catch_active <= '1';
+        wait until falling_edge(CLK);
+
+        echo ("PASTTREC REGISTERS WRITE CHECK ---------------------------" & lf);
+        --wait;
+        for chip_id in 0 to 3 loop
+            for reg_no in 0 to 15 loop
+                for data in 0 to 2*8 - 1 loop
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '1';
+                    BUS_RX.addr  <= x"a2" & "00" & std_logic_vector(to_unsigned(chip_id,2)) & std_logic_vector(to_unsigned(reg_no,4));
+                    BUS_RX.data  <= std_logic_vector(to_unsigned(data ,32));
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '0';
+
+                    --------------- WAIT BLOCK------------------
+                    wait_for_responce <= "100";
+                    wait_en <= '1';
+                    wait until rising_edge(CLK) and wait_end = '1';
+                    if wait_error = '1' then
+                        num_of_errors := num_of_errors + 1;
+                    end if;
+                    wait_en <= '0';
+                    --------------- END WAIT BLOCK------------------
+
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '1';
+                    BUS_RX.addr  <= x"a2" & "00" & std_logic_vector(to_unsigned(chip_id,2)) & std_logic_vector(to_unsigned(15-reg_no,4));
+                    BUS_RX.data  <= std_logic_vector(to_unsigned(2*8-1-data ,32));
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '0';
+
+                    --------------- WAIT BLOCK------------------
+                    wait_for_responce <= "010";
+                    wait_en <= '1';
+                    wait until rising_edge(CLK) and wait_end = '1';
+                    if wait_error = '1' then
+                        num_of_errors := num_of_errors + 1;
+                    end if;
+                    wait_en <= '0';
+                    --------------- END WAIT BLOCK------------------
+
+                    wait for 10*TbPeriod;
+
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '1';
+                    BUS_RX.addr  <= x"a2" & "00" & std_logic_vector(to_unsigned(chip_id,2)) & std_logic_vector(to_unsigned(15-reg_no,4));
+                    BUS_RX.data  <= std_logic_vector(to_unsigned(2*8-1-data ,32));
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '0';
+
+                    --------------- WAIT BLOCK------------------
+                    wait_for_responce <= "010";
+                    wait_en <= '1';
+                    wait until rising_edge(CLK) and wait_end = '1';
+                    if wait_error = '1' then
+                        num_of_errors := num_of_errors + 1;
+                    end if;
+                    wait_en <= '0';
+                    --------------- END WAIT BLOCK------------------
+
+                    wait for 10*TbPeriod;
+
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '1';
+                    BUS_RX.addr  <= x"a7" & "00" & std_logic_vector(to_unsigned(chip_id,2)) & std_logic_vector(to_unsigned(15-reg_no,4));
+                    wait until falling_edge(CLK);
+                    BUS_RX.write <= '0';
+
+                    --------------- WAIT BLOCK------------------
+                    wait_for_responce <= "001";
+                    wait_en <= '1';
+                    wait until rising_edge(CLK) and wait_end = '1';
+                    if wait_error = '1' then
+                        num_of_errors := num_of_errors + 1;
+                    end if;
+                    wait_en <= '0';
+                    --------------- END WAIT BLOCK------------------
+
+
+                    wait until rising_edge(SPI_CS_OUT);
+                    wait for 100*TbPeriod;
+                end loop;
+            end loop;
+        end loop;
+
+        wait for 100*TbPeriod;
+
+
+        for chip_id in 0 to 3 loop
+            for reg_no in 0 to 15 loop
+                for data_reg in 0 to 2*8 - 1 loop
+                    data := spi_hist(index);
+                    index := index + 1;
+                    assert data = "1010" & std_logic_vector(to_unsigned(chip_id,2)) & '0' & std_logic_vector(to_unsigned(reg_no,4)) & std_logic_vector(to_unsigned(data_reg, 8)) report "Incorrect SPI: data is " & to_string(data) & " but should be " & to_string("1010" & std_logic_vector(to_unsigned(chip_id,2)) & '0' & std_logic_vector(to_unsigned(reg_no,4)) & std_logic_vector(to_unsigned(data_reg, 8)));
+                    if not (data = "1010" & std_logic_vector(to_unsigned(chip_id,2)) & '0' & std_logic_vector(to_unsigned(reg_no,4)) & std_logic_vector(to_unsigned(data_reg, 8))) then
+                        num_of_errors := num_of_errors + 1;
+                    end if;
+                end loop;
+            end loop;
+        end loop;
+
+        --echo( lf & lf & lf & "----------------------------" &lf&"SPI history:"&lf);
+        --echo("             HEX | HEADER | ADDR | R/W | REG  | DATA" & lf );
+        --for i in 0 to spi_hist_ind - 1 loop
+            --data := spi_hist(i);
+            --echo( "SPI CATCH: " & to_hstring(data) & " |  " & to_string(data(18 downto 15)) & "  |  " & to_string(data(14 downto 13)) & "  |  " & to_string(data(12)) & "  | " & to_string(data(11 downto 8)) & " | " & to_string(data(7 downto 0))  & lf);
+        --end loop;
+
+        echo (lf& "SC RESET" & lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & x"00";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait for 5*TbPeriod;
+        assert SPI_RST_OUT  = '0' report "SC RESET failed!";
+        if SPI_RST_OUT  /= '0' then
+            num_of_errors := num_of_errors+1;
+        end if;
+        wait until rising_edge(SPI_RST_OUT);
+        wait until rising_edge(SPI_CS_OUT);
+        wait for 5000*TbPeriod;
+        wait for 150*TbPeriod;
+        assert spi_hist(spi_hist_ind - 1) = std_logic_vector(to_unsigned(0,19)) and spi_hist(spi_hist_ind - 2) = std_logic_vector(to_unsigned(0,19)) report "SC RESET Failed!";
+        if not(spi_hist(spi_hist_ind - 1) = std_logic_vector(to_unsigned(0,19)) and spi_hist(spi_hist_ind - 2) = std_logic_vector(to_unsigned(0,19))) then
+            num_of_errors := num_of_errors + 1;
+        end if;
+
+        wait for 100*TbPeriod;
+        echo (lf& "SC AUTOLOAD SET" & lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a0" & x"02";
+        BUS_RX.data  <= "0100" & x"5" & x"10" & "0111" & x"F" & x"20";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a0" & x"03";
+        BUS_RX.data  <= "0100" & x"3" & x"10" & "0000" & x"0" & x"00";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & x"00";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        start_autoload_ind := spi_hist_ind;
+        wait for 1000000*TbPeriod;
+
+        if (spi_hist_ind - start_autoload_ind) /= 2+63+5+3 then
+            report "Incorrect number of SPI commands! Actual is " & integer'image(spi_hist_ind-start_autoload_ind);
+            num_of_errors := num_of_errors + 1;
+        end if;
+
+        for i in start_autoload_ind to spi_hist_ind - 1 loop
+            if i - start_autoload_ind = 0 or i - start_autoload_ind = 1 then
+                if spi_hist(i) /= std_logic_vector(to_unsigned(0,19)) then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind);
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            elsif i-start_autoload_ind < 63 + 2 then
+                if spi_hist(i) /= ram(32 + i - start_autoload_ind - 2)(18 downto 0) then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind);
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            elsif i-start_autoload_ind < 5 + 63 + 2 then
+                if spi_hist(i) /= ram(16 + i - start_autoload_ind - 2 - 63)(18 downto 0) then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind);
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            elsif i-start_autoload_ind < 3 + 5 + 63 + 2 then
+                if spi_hist(i) /= ram(16 + i - start_autoload_ind - 2 - 63 - 5)(18 downto 0) then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind);
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            else
+                report "Incorrect SPI! " & integer'image(i-start_autoload_ind);
+                num_of_errors := num_of_errors + 1;
+            end if;
+        end loop;
+
+        echo (lf & "-------------" & lf & "ERRORS: " & integer'image(num_of_errors) &lf & "-------------" & lf);
+
+        echo ("Test load CMD" & lf);
+        start_autoload_ind := spi_hist_ind;
+        wait for 10*TbPeriod;
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & '0' & "0010" & "001";
+        BUS_RX.data  <= x"0000" & x"0A" & x"10";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait for 5000*TbPeriod;
+
+        if (spi_hist_ind - start_autoload_ind) /= 10 then
+            report "Incorrect number of SPI commands! Actual is " & integer'image(spi_hist_ind-start_autoload_ind);
+            num_of_errors := num_of_errors + 1;
+        end if;
+
+        for i in start_autoload_ind to spi_hist_ind - 1 loop
+            if i - start_autoload_ind  < 10 then
+                if spi_hist(i)(12 downto 0) /= ram(16 + i - start_autoload_ind)(12 downto 0) or spi_hist(i)(18 downto 15) /= ram(16 + i - start_autoload_ind)(18 downto 15) or spi_hist(i)(14 downto 13) /= "10" then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i));
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            else
+                report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i));
+                num_of_errors := num_of_errors + 1;
+            end if;
+        end loop;
+
+        echo (lf & lf  & "Single load test ended. Errors: " & integer'image(num_of_errors) & lf & lf );
+
+        wait for 300*TbPeriod;
+
+        start_autoload_ind := spi_hist_ind;
+        wait for 10*TbPeriod;
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & '1' & "0000" & "001";
+        BUS_RX.data  <= x"0000" & x"0B" & x"10";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait for 4*5000*TbPeriod;
+
+        if (spi_hist_ind - start_autoload_ind) /= 4*11 then
+            report "Incorrect number of SPI commands! Actual is " & integer'image(spi_hist_ind-start_autoload_ind);
+            num_of_errors := num_of_errors + 1;
+        end if;
+
+        for i in start_autoload_ind to spi_hist_ind - 1 loop
+            if i - start_autoload_ind  < 11 then
+                if spi_hist(i)(12 downto 0) /= ram(16 + i - start_autoload_ind)(12 downto 0) or spi_hist(i)(18 downto 15) /= ram(16 + i - start_autoload_ind)(18 downto 15) or spi_hist(i)(14 downto 13) /= "00" then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i)) & " Should be: " & to_hstring(ram(16+i-start_autoload_ind));
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            elsif i - start_autoload_ind  < 11 *2 then
+                if spi_hist(i)(12 downto 0) /= ram(16 + i - start_autoload_ind - 11)(12 downto 0) or spi_hist(i)(18 downto 15) /= ram(16 + i - start_autoload_ind - 11)(18 downto 15) or spi_hist(i)(14 downto 13) /= "01" then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i)) & " Should be: " & to_hstring(ram(16+i-start_autoload_ind-1*11));
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            elsif i - start_autoload_ind  < 11 *3 then
+                if spi_hist(i)(12 downto 0) /= ram(16 + i - start_autoload_ind - 2*11)(12 downto 0) or spi_hist(i)(18 downto 15) /= ram(16 + i - start_autoload_ind - 2*11)(18 downto 15) or spi_hist(i)(14 downto 13) /= "10" then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i)) & " Should be: " & to_hstring(ram(16+i-start_autoload_ind-2*11));
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            elsif i - start_autoload_ind  < 11 *4 then
+                if spi_hist(i)(12 downto 0) /= ram(16 + i - start_autoload_ind - 3*11)(12 downto 0) or spi_hist(i)(18 downto 15) /= ram(16 + i - start_autoload_ind - 3 * 11)(18 downto 15) or spi_hist(i)(14 downto 13) /= "11" then
+                    report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i)) & " Should be: " & to_hstring(ram(16+i-start_autoload_ind-3*11));
+                    num_of_errors := num_of_errors + 1;
+                end if;
+            else
+                report "Incorrect SPI! " & integer'image(i-start_autoload_ind) & " Actual data is: " & to_hstring(spi_hist(i));
+                num_of_errors := num_of_errors + 1;
+            end if;
+        end loop;
+
+        echo (lf & "-------------" & lf & "ERRORS: " & integer'image(num_of_errors) &lf & "-------------" & lf);
+
+        wait for 5000*TbPeriod;
+        echo ("SPI reset test during transmitting." & lf);
+        spi_catch_active    <= '0';
+        wait for 10*TbPeriod;
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a202";
+        BUS_RX.data  <= x"000000" & x"AB";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait for 100*TbPeriod;
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a100";
+        BUS_RX.data  <= x"F0000000";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        report "Send reset signal";
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 5*TbPeriod;
+        if SPI_CS_OUT   /= '1' then
+            report "Reset insuccesful!";
+            num_of_errors := num_of_errors + 1;
+        end if;
+
+        echo (lf & "-------------" & lf & "ERRORS: " & integer'image(num_of_errors) &lf & "-------------" & lf);
+
+        wait;
+    end process;
+
+    SPI_CATCH: process
+        variable data : std_logic_vector (18 downto 0);
+    begin
+        wait until falling_edge(SPI_CS_OUT);
+        if spi_catch_active='1' then
+            loop
+                for i in 18 downto 0 loop
+                    wait until rising_edge(SPI_SCK_OUT);
+                    data (i) := SPI_SDO_OUT;
+                end loop;
+                --report "SPI CATCH: " & to_hstring(data) & " | " & to_string(data(18 downto 15)) & " | ADDR " & to_string(data(14 downto 13)) & " | R/W " & to_string(data(12)) & " | REG " & to_string(data(11 downto 8)) & " | DATA " & to_string(data(7 downto 0));
+                spi_hist(spi_hist_ind) <= data;
+                spi_hist_ind <= spi_hist_ind + 1;
+                wait until rising_edge(SPI_CS_OUT) OR falling_edge(SPI_SCK_OUT);
+                exit when SPI_CS_OUT = '1';
+            end loop;
+        end if;
+    end process;
+
+end tb;
+
+-- Configuration block below is required by some simulators. Usually no need to edit.
+
+configuration cfg_tb_loader of tb_loader is
+    for tb
+    end for;
+end cfg_tb_loader;
diff --git a/code/pasttrec_spi/tb/pasttrec_test_module.vhd b/code/pasttrec_spi/tb/pasttrec_test_module.vhd
new file mode 100644 (file)
index 0000000..dde7df7
--- /dev/null
@@ -0,0 +1,113 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity pasttrec_test_module is
+    generic (
+        chipid  : std_logic_vector(1 downto 0)
+    );
+    port(
+        SCK : in std_logic;
+        SDO : in std_logic;
+        SDI : out std_logic := 'Z';
+        RST : in std_logic
+    );
+end entity;
+
+architecture tb of pasttrec_test_module is
+    signal bitcounter   : integer range 0 to 25;
+    --signal datavector   : std_logic_vector(18 downto 0);
+
+    signal rstcounter   : integer range 0 to 7;
+    signal isok         : std_logic;
+    signal rw           : std_logic;
+    signal addr         : std_logic_vector(3 downto 0);
+    signal data         : std_logic_vector(7 downto 0);
+
+    type fsm_t  is (IDLE, CMD, RESET,RESET2);
+    signal fsm : fsm_t;
+
+    type ram_t is array(0 to 15) of std_logic_vector(7 downto 0);
+    signal ram : ram_t;
+begin
+
+    FSM_PROC: process
+    begin
+        wait until rising_edge(SCK);
+        SDI <= 'Z';
+        case fsm is
+            when RESET =>
+                if RST = '1' then
+                    fsm <= RESET2;
+                end if;
+            when RESET2 =>
+                if rstcounter = 0 then
+                    fsm <= IDLE;
+                    bitcounter <= 0;
+                    ram <= (others => x"00");
+                else
+                    rstcounter <= rstcounter - 1;
+                end if;
+            when IDLE =>
+                if SDO = '1' then
+                    fsm <= CMD;
+                    bitcounter <= 1;
+                    isok <= '1';
+                end if;
+            when CMD  =>
+                bitcounter <= bitcounter + 1;
+                if (bitcounter = 1 and SDO /= '0')
+                    or (bitcounter = 2 and SDO /= '1')
+                    or (bitcounter = 3 and SDO /= '0')
+                then
+                    isok <= '0';
+                    fsm <= IDLE;
+                elsif (bitcounter = 4 and SDO /= chipid(1))
+                    or (bitcounter = 5 and SDO /= chipid(0))
+                then
+                    isok <= '0';
+                elsif bitcounter = 6 then
+                    rw <= SDO;
+                elsif bitcounter = 7 then
+                    addr(3) <= SDO;
+                elsif bitcounter = 8 then
+                    addr(2) <= SDO;
+                elsif bitcounter = 9 then
+                    addr(1) <= SDO;
+                elsif bitcounter = 10 then
+                    addr(0) <= SDO;
+                    if isok = '1' then
+                        SDI <= '0';
+                    end if;
+                end if;
+                if bitcounter >= 11 and bitcounter <= 18 and isok = '1' then
+                    data(11+7-bitcounter) <= SDO;
+                    if rw = '0' then
+                        SDI <= SDO;
+                        ram(to_integer(unsigned(addr)))(11+7-bitcounter) <= SDO;
+                    else
+                        SDI <= ram(to_integer(unsigned(addr)))(11+7-bitcounter);
+                    end if;
+                end if;
+                if bitcounter >= 19 and bitcounter <= 21 and isok = '1' then
+                    SDI <= '0';
+                end if;
+                if bitcounter = 19 and SDO /= '0' and isok = '1' then
+                    report "Incorrect end. Should be zero.";
+                end if;
+                if bitcounter >= 20 then
+                    if SDO = '1' then
+                        bitcounter <= 1;
+                        isok <= '1';
+                    else
+                        fsm <= IDLE;
+                        bitcounter <= 0;
+                    end if;
+                end if;
+        end case;
+        if RST = '0' then
+            fsm <= RESET;
+            rstcounter <= 5;
+        end if;
+    end process FSM_PROC;
+end architecture;
diff --git a/code/pasttrec_spi/tb/system_testbench.vhd b/code/pasttrec_spi/tb/system_testbench.vhd
new file mode 100644 (file)
index 0000000..0eab279
--- /dev/null
@@ -0,0 +1,449 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use std.textio.all;
+use IEEE.math_real.all;
+
+library work;
+use work.trb_net_std.all;
+--use work.clocked_tdc_pkg.all;
+
+entity system_testbench is
+end entity;
+
+architecture tb of system_testbench is
+    signal CLK    : std_logic;
+    signal BUS_RX : CTRLBUS_RX;
+    signal BUS_TX : CTRLBUS_TX;
+
+    signal RST_IN : std_logic;
+
+    signal SPI_CS_OUT      : std_logic_vector(2 downto 0);
+    signal SPI_SDI_IN      : std_logic_vector(2 downto 0);
+    signal SPI_SDO_OUT     : std_logic_vector(2 downto 0);
+    signal SPI_SCK_OUT     : std_logic_vector(2 downto 0);
+    signal SPI_RST_OUT     : std_logic_vector(2 downto 0);
+
+    constant TbPeriod : time := 5 ns; -- EDIT Put right period here
+    signal TbSimEnded : std_logic := '0';
+
+    type ram_t is array(0 to 2**8-1) of std_logic_vector(32-1 downto 0);
+    impure function read_from_file(filename : string) return ram_t is
+        file text_file      : text open read_mode is filename;
+        variable text_line  : line;
+        variable mem        : ram_t;
+    begin
+        for i in 0 to 2**8-1 loop
+            readline(text_file, text_line);
+            hread(text_line, mem(i));
+        end loop;
+        return mem;
+    end function;
+    SIGNAL ram : ram_t := read_from_file("../code/memory.hex");
+
+    procedure echo (arg : in string := "") is
+    begin
+        std.textio.write(std.textio.output, arg);
+    end procedure echo;
+
+    signal wait_for_responce : std_logic_vector(2 downto 0);
+    signal wait_en           : std_logic := '0';
+    signal wait_cnt          : integer :=0;
+    signal wait_end          : std_logic := '0';
+    signal wait_error        : std_logic := '0';
+    constant max_wait_cnt    : integer := 5;
+begin
+
+    dut : entity work.pasttrec_spi
+    generic map(
+        SPI_BUNCHES => 3,
+        SPI_PASTTREC_PER_BUNCH => 2,
+        SPI_CHIP_IDs => x"00000"&"100110011001"
+    )port map (
+                CLK    => CLK,
+                BUS_RX => BUS_RX,
+                BUS_TX => BUS_TX,
+
+                RST_IN => RST_IN,
+
+                SPI_CS_OUT  =>  SPI_CS_OUT,
+                SPI_SDI_IN  =>  SPI_SDI_IN,
+                SPI_SDO_OUT =>  SPI_SDO_OUT,
+                SPI_SCK_OUT =>  SPI_SCK_OUT,
+                SPI_RST_OUT =>  SPI_RST_OUT
+              );
+
+    -- Clock generation
+    clocking: process
+    begin
+        CLK <= '1';
+        wait for TbPeriod / 2;
+        CLK <= '0';
+        wait for TbPeriod / 2;
+        if TbSimEnded = '1' then
+            wait;
+        end if;
+    end process clocking;
+
+
+    PASTTREC1: entity work.pasttrec_test_module
+    generic map(
+        chipid => "01"
+    )port map(
+            SCK => SPI_SCK_OUT(0),
+            SDO => SPI_SDO_OUT(0),
+            SDI => SPI_SDI_IN(0),
+            RST => SPI_RST_OUT(0)
+        );
+
+    PASTTREC2: entity work.pasttrec_test_module
+    generic map(
+        chipid => "10"
+    )port map(
+            SCK => SPI_SCK_OUT(0),
+            SDO => SPI_SDO_OUT(0),
+            SDI => SPI_SDI_IN(0),
+            RST => SPI_RST_OUT(0)
+        );
+
+    PASTTREC3: entity work.pasttrec_test_module
+    generic map(
+        chipid => "01"
+    )port map(
+            SCK => SPI_SCK_OUT(1),
+            SDO => SPI_SDO_OUT(1),
+            SDI => SPI_SDI_IN(1),
+            RST => SPI_RST_OUT(1)
+        );
+
+    PASTTREC4: entity work.pasttrec_test_module
+    generic map(
+        chipid => "10"
+    )port map(
+            SCK => SPI_SCK_OUT(1),
+            SDO => SPI_SDO_OUT(1),
+            SDI => SPI_SDI_IN(1),
+            RST => SPI_RST_OUT(1)
+        );
+
+    PASTTREC5: entity work.pasttrec_test_module
+    generic map(
+        chipid => "01"
+    )port map(
+            SCK => SPI_SCK_OUT(2),
+            SDO => SPI_SDO_OUT(2),
+            SDI => SPI_SDI_IN(2),
+            RST => SPI_RST_OUT(2)
+        );
+
+    PASTTREC6: entity work.pasttrec_test_module
+    generic map(
+        chipid => "10"
+    )port map(
+            SCK => SPI_SCK_OUT(2),
+            SDO => SPI_SDO_OUT(2),
+            SDI => SPI_SDI_IN(2),
+            RST => SPI_RST_OUT(2)
+        );
+
+
+    stimuli : process
+        variable num_of_errors : integer := 0;
+    begin
+        wait for 10*TbPeriod;
+        RST_IN  <= '1';
+        wait for 10*TbPeriod;
+        RST_IN  <= '0';
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+
+        wait for 1000*TbPeriod;
+
+
+        echo("Load to 2 chip"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & "0" & "0001" & o"1";
+        BUS_RX.data  <= x"0000" & x"0F" & x"50";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+        wait for 100*TbPeriod;
+
+        echo("Load to 3 chip"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & "0" & "0010" & o"1";
+        BUS_RX.data  <= x"0000" & x"0F" & x"60";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+        wait for 100*TbPeriod;
+
+        echo("Load to 1 chip"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & "0" & "0000" & o"1";
+        BUS_RX.data  <= x"0000" & x"0F" & x"40";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+        wait for 100*TbPeriod;
+
+        echo("Load to 4 chip"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & "0" & "0011" & o"1";
+        BUS_RX.data  <= x"0000" & x"0F" & x"70";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+
+        echo("Load to 5 chip"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & "0" & "0100" & o"1";
+        BUS_RX.data  <= x"0000" & x"0F" & x"80";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+
+        echo("Load to 6 chip"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & "0" & "0101" & o"1";
+        BUS_RX.data  <= x"0000" & x"0F" & x"90";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+
+
+        wait for 1000*TbPeriod;
+
+        report ("Read attempt"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.read <= '1';
+        BUS_RX.addr  <= x"a1" & x"0B";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.read <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        report ("Responce: " & to_hstring( BUS_TX.data) & lf);
+        wait for 1000*TbPeriod;
+
+
+        -------------MEMORY AUTO START CLEAN
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a002";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"a003";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        ------------------RESET
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aa00";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+        wait for 10*TbPeriod;
+
+         report ("Load to all chips"&lf);
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '1';
+        BUS_RX.addr  <= x"aA" & x"81";
+        BUS_RX.data  <= x"0000" & x"FF" & x"10";
+        wait until falling_edge(CLK);
+        BUS_RX.write <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait for 10*TbPeriod;
+        wait until <<signal .system_testbench.dut.spi_fsm_control : std_logic>> = '0';
+
+        wait for 1000*TbPeriod;
+
+        report ("Read attempt"&lf);
+
+        wait until falling_edge(CLK);
+        BUS_RX.read <= '1';
+        BUS_RX.addr  <= x"a2" & x"0" & x"2";
+        wait until falling_edge(CLK);
+        BUS_RX.read <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        wait until rising_edge(SPI_CS_OUT(0));
+        wait for 100*TbPeriod;
+        wait until falling_edge(CLK);
+        BUS_RX.read <= '1';
+        BUS_RX.addr  <= x"a1" & x"0B";
+        BUS_RX.data  <= x"00000000";
+        wait until falling_edge(CLK);
+        BUS_RX.read <= '0';
+        --------------- WAIT BLOCK------------------
+        wait_for_responce <= "100";
+        wait_en <= '1';
+        wait until rising_edge(CLK) and wait_end = '1';
+        if wait_error = '1' then
+            num_of_errors := num_of_errors + 1;
+        end if;
+        wait_en <= '0';
+        --------------- END WAIT BLOCK------------------
+        report ("Responce: " & to_hstring( BUS_TX.data) & lf);
+
+        TbSimEnded <= '1';
+        echo (lf & "-------------" & lf & "END | ERRORS: " & integer'image(num_of_errors) &lf & "-------------" & lf);
+        wait;
+    end process;
+
+
+
+    responce_proc : process
+        variable tmp : std_logic_vector(2 downto 0);
+    begin
+        wait until falling_edge(CLK);
+        wait_end <= '0';
+        wait_error <= '0';
+
+        if wait_en = '0' then
+            wait_cnt <= 0;
+        else
+            assert wait_cnt < max_wait_cnt report "Timeout violated!";
+            if not(wait_cnt < max_wait_cnt) then
+                wait_end <= '1';
+                wait_error <= '1';
+            elsif (BUS_TX.ack = '1' or BUS_TX.nack = '1' or BUS_TX.unknown = '1') then
+                tmp := BUS_TX.ack & BUS_TX.nack & BUS_TX.unknown;
+                assert (BUS_TX.ack = wait_for_responce(2) and BUS_TX.nack = wait_for_responce(1) and BUS_TX.unknown = wait_for_responce(0)) report "Incorrect answer. Shoud be: " & to_string(wait_for_responce) & " actual is: " & to_string(tmp);
+                if not (BUS_TX.ack = wait_for_responce(2) and BUS_TX.nack = wait_for_responce(1) and BUS_TX.unknown = wait_for_responce(0)) then
+                    wait_end <= '1';
+                    wait_error <= '1';
+                else
+                    wait_end <= '1';
+                end if;
+            else
+                wait_cnt <= wait_cnt + 1;
+            end if;
+        end if;
+    end process;
+end architecture;