From 602092f271904f4715ea48ea2ca22c8ba9b84510 Mon Sep 17 00:00:00 2001 From: Jan Michel Date: Wed, 17 Aug 2022 10:49:42 +0200 Subject: [PATCH] add Pasttrec SPI files to main repository --- DBO/mdctdc.prj | 6 +- code/pasttrec_spi/README.md | 132 ++++ code/pasttrec_spi/memory.hex | 256 ++++++ code/pasttrec_spi/pasttrec_spi.vhd | 543 +++++++++++++ code/pasttrec_spi/ram_dp_pasttrec.vhd | 115 +++ code/pasttrec_spi/spi_ltc2600_pasttrec.vhd | 313 ++++++++ code/pasttrec_spi/tb/pasttrec_spi_tb.vhd | 736 ++++++++++++++++++ code/pasttrec_spi/tb/pasttrec_test_module.vhd | 113 +++ code/pasttrec_spi/tb/system_testbench.vhd | 449 +++++++++++ 9 files changed, 2660 insertions(+), 3 deletions(-) create mode 100755 code/pasttrec_spi/README.md create mode 100644 code/pasttrec_spi/memory.hex create mode 100644 code/pasttrec_spi/pasttrec_spi.vhd create mode 100644 code/pasttrec_spi/ram_dp_pasttrec.vhd create mode 100644 code/pasttrec_spi/spi_ltc2600_pasttrec.vhd create mode 100644 code/pasttrec_spi/tb/pasttrec_spi_tb.vhd create mode 100644 code/pasttrec_spi/tb/pasttrec_test_module.vhd create mode 100644 code/pasttrec_spi/tb/system_testbench.vhd diff --git a/DBO/mdctdc.prj b/DBO/mdctdc.prj index 707b2fc..2b7559d 100644 --- a/DBO/mdctdc.prj +++ b/DBO/mdctdc.prj @@ -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 index 0000000..1c4f40e --- /dev/null +++ b/code/pasttrec_spi/README.md @@ -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**
*30* - autoload enable
*29..24* - number of autoload commands (unsigned)
*23..16* - first command address
**PASTTREC #1**
*14* - autoload enable
*13..8* - number of autoload commands (unsigned)
*7..0* - first command address | Autostart settings for PASTTREC #1 & PASTTREC #2

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**
*30* - autoload enable
*29..24* - number of autoload commands (unsigned)
*23..16* - first command address
**PASTTREC #2k-1**
*14* - autoload enable
*13..8* - number of autoload commands (unsigned)
*7..0* - first command address | Autostart settings for PASTTREC #2k-1 & PASTTREC #2k
*N - total number of PASTTREC chips connected to all SPI bunches*| +| ⌈N/2⌉ - 0xFF | - | Free memory. Can be used by end user.
*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
*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
**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.
*It's bit 31 of ctrl_reg register* | +| **0xA101** | R/W | *31..0* - content to be written to SPI module ctrl_reg.
*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
*4* - override sck
*3* - override cs
*2* - invert sdo
*1* - invert sck
*0* - invert cs | *5* - override sdo
*4* - override sck
*3* - override cs
*2* - invert sdo
*1* - invert sck
*0* - invert cs | Access to override/invert register.
*It's bits 13..8 of ctrl_reg register* | +| **0xA103** | R/W | *15..6* - wait cycles (unsigned, def = 7).
*5..0* - word length (unsigned, def = 19) | *15..6* - wait cycles (unsigned, def = 7).
*5..0* - word length (unsigned, def = 19) | Access to wait cycles/word length register.
*It's bits 29..14 of ctrl_reg register* | +| **0xA10A** | W | *7* - block bit. If high SPI module will block after transaction.
*6* - start bit. If high SPI module will begin transmitting.
*5..0* - number of words to be transmitted. Required to be non zero for transmitting (unsigned) | - | Transmit data direct from memory.
**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.
| +| **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.
**If R mode the second slow control access is required**| +| **0xAA\*\*** | ----- | ------------------------ | ---------------- | **Complex operations.** | +| **0xAA00** | W | - | - | Whole system reset.
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)
*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.**
If all_bit is high, set will be loaded to all PASTTREC chips.
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 index 0000000..904c3a8 --- /dev/null +++ b/code/pasttrec_spi/memory.hex @@ -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 index 0000000..4bb87a3 --- /dev/null +++ b/code/pasttrec_spi/pasttrec_spi.vhd @@ -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 index 0000000..0e66981 --- /dev/null +++ b/code/pasttrec_spi/ram_dp_pasttrec.vhd @@ -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 index 0000000..afe496f --- /dev/null +++ b/code/pasttrec_spi/spi_ltc2600_pasttrec.vhd @@ -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 index 0000000..9e0f8f7 --- /dev/null +++ b/code/pasttrec_spi/tb/pasttrec_spi_tb.vhd @@ -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 index 0000000..dde7df7 --- /dev/null +++ b/code/pasttrec_spi/tb/pasttrec_test_module.vhd @@ -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 index 0000000..0eab279 --- /dev/null +++ b/code/pasttrec_spi/tb/system_testbench.vhd @@ -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 <> = '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 <> = '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 <> = '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 <> = '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 <> = '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 <> = '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 <> = '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 <> = '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 <> = '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; -- 2.43.0