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"
--- /dev/null
+
+# 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.
+
+
+
+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/\*
+
--- /dev/null
+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
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;