From: Jan Michel Date: Thu, 13 Aug 2015 12:05:08 +0000 (+0200) Subject: Adding Michaels Flash-tool to template design X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=fbe92444c33a44a45167c23fed1b7f1a54eaf335;p=trb3sc.git Adding Michaels Flash-tool to template design Adding option for backplane serdes to config --- diff --git a/code/load_settings.vhd b/code/load_settings.vhd new file mode 100644 index 0000000..a89f4f4 --- /dev/null +++ b/code/load_settings.vhd @@ -0,0 +1,667 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + +entity load_settings is + generic( + HEADER_PAGE_ADDR : std_logic_vector(15 downto 0) := x"7000"; + + -- = floor(256/6), because 256 bytes per page, 6 bytes per register + REGISTERS_PER_PAGE : integer := 42 + ); + port( + CLK : in std_logic; + RST : in std_logic; + + -- the bus handler signals + BUS_RX : in CTRLBUS_RX; + BUS_TX : out CTRLBUS_TX; + + IS_ACTIVE : out std_logic; + + BUS_MASTER_TX : out CTRLBUS_RX; + BUS_MASTER_RX : in CTRLBUS_TX; + + SPI_MOSI : out std_logic; + SPI_MISO : in std_logic; + SPI_SCK : out std_logic; + SPI_NCS : out std_logic + + ); +end entity; + + + +architecture load_settings_arch of load_settings is + + + +-- -- local register addresses + +constant ADDR_TAKE_SPI : std_logic_vector( 7 downto 0) := x"00"; +constant ADDR_NCS : std_logic_vector( 7 downto 0) := x"02"; +constant ADDR_DATA_IN : std_logic_vector( 7 downto 0) := x"03"; +constant ADDR_DATA_OUT : std_logic_vector( 7 downto 0) := x"04"; +constant ADDR_TRANSMISSION_COUNTER : std_logic_vector( 7 downto 0) := x"05"; + +constant ADDR_PAGE_SELECT : std_logic_vector( 7 downto 0) := x"06"; +constant ADDR_PAGE_POS : std_logic_vector( 7 downto 0) := x"07"; +constant ADDR_POP_PAGE_DATA : std_logic_vector( 7 downto 0) := x"08"; +constant ADDR_POP_PAGE_NOBYTES : std_logic_vector( 7 downto 0) := x"09"; +constant ADDR_FEEDBACK : std_logic_vector( 7 downto 0) := x"0A"; +constant ADDR_PARSE_TRIGGER : std_logic_vector( 7 downto 0) := x"0B"; +constant ADDR_SC_WRITE_ERRORS : std_logic_vector( 7 downto 0) := x"0C"; + +-- -- spi related signals + +signal take_spi : std_logic := '0'; +signal spi_ncs_latch : std_logic := '1'; +signal spi_ready, spi_trigger : std_logic; + +signal spi_data_in : std_logic_vector(7 downto 0); +signal spi_data_out : std_logic_vector(7 downto 0); + +-- signal loopback : std_logic; + +signal transmission_counter : std_logic_vector(15 downto 0) := x"0000"; + +-- page ram handling + +signal ram_wr : std_logic; +signal ram_addr : std_logic_vector(7 downto 0); +signal ram_dout : std_logic_vector(7 downto 0); +signal ram_din : std_logic_vector(7 downto 0); + +signal ram_waddr, ram_raddr : std_logic_vector(7 downto 0); +signal select_write_ram : std_logic := '0'; + +signal page_number : std_logic_vector(15 downto 0); + +-- signals for READ_PAGE_TO_RAM process + +type read_page_state_t is (IDLE,SEND_CMD,SEND_A0,SEND_A1,SEND_A2,READ_DATA,WAIT_FOR_SPI_READY,STORE_DATA); +signal read_page_state,next_read_page_state : read_page_state_t := IDLE; +signal trigger_read_page : std_logic; +signal read_page_ready : std_logic; +signal ram_wr_pointer : std_logic_vector (7 downto 0); + +-- signal read_page_init_counter : std_logic_vector (8 downto 0) := (others => '0'); + +-- signals for the POP_PAGE_DATA process +signal trigger_pop_page_data : std_logic; +-- signal pop_page_word_counter : integer range 0 to 63; +signal pop_page_position, new_pop_page_position : integer range 0 to 255 := 0; +signal set_pop_page_position : std_logic := '0'; +signal pop_page_noBytes : integer range 0 to 255; +signal pop_page_noBytes_popped : integer range 0 to 255; +signal pop_page_noBytes_pushed : integer range 0 to 255; +signal pop_page_ram_delay : integer range 0 to 2; +type pop_page_state_t is (IDLE,ACTIVE); +signal pop_page_state : pop_page_state_t := IDLE; +signal pop_page_data_word : std_logic_vector (31 downto 0); +signal pop_page_data_ready : std_logic; +-- signal pop_page_rewind : std_logic; + + + +-- signals for the PARSE_PAGE process + +signal parse_trigger : std_logic; +type parse_state_t is ( + IDLE, + READ_HEADER_PAGE, + WAIT4PAGE, + WAIT4RAM, + VERIFY_START_STRING, + GET_NO_REGISTERS, + STORE_NO_REGISTERS, + GET_NO_PAGES, + STORE_NO_PAGES, + READ_NEXT_PAGE, + READ_SC_ADDR, + STORE_SC_ADDR, + READ_SC_VALUE, + STORE_SC_VALUE, + SEND_SC_DATA, + WAIT4_SC_ACK, + SUCCESS,FAIL); +signal parse_state : parse_state_t := IDLE; +signal next_parse_state : parse_state_t := IDLE; +signal parse_counter : integer range 0 to 255; + +signal parse_feedback : std_logic_vector(31 downto 0) := (others=>'0'); + +signal registers_to_read : std_logic_vector(31 downto 0); +signal pages_to_read : std_logic_vector(31 downto 0); + +signal current_sc_addr : std_logic_vector(15 downto 0); +signal current_sc_value : std_logic_vector(31 downto 0); + +signal sc_ack_timeout : integer range 0 to 31; +signal sc_write_errors : std_logic_vector(31 downto 0) := (others =>'0'); + + + +type header_string_t is array(7 downto 0) of std_logic_vector(7 downto 0); +-- 53 4c 4f 57 43 54 52 4c +-- a set of ascii characters that reads "SLOWCTRL" +signal header_string : header_string_t := ( 0=>x"53", 1=>x"4c", 2=>x"4f", 3=>x"57", 4=>x"43", 5=>x"54", 6=>x"52", 7=>x"4c"); + +begin + + +THE_SPI_MASTER : entity work.spi_master_generic + generic map( + WORDSIZE => 8, + CPOL => '0', + CPHA => '0', + SPI_CLOCK_DIVIDER => 10 + ) + port map( + MOSI => SPI_MOSI, + MISO => SPI_MISO, + SCK => SPI_SCK, + + CLK => CLK, + RST => RST, + + DATA_OUT => spi_data_out, + DATA_IN => spi_data_in, + + TRANSFER_COMPLETE => spi_ready, + TRIGGER_TRANSFER => spi_trigger + ); + +THE_PAGE_RAM : entity work.ram + generic map( + depth => 8, + width => 8 + ) + port map( + CLK => CLK, + wr => ram_wr, + a => ram_addr, + dout => ram_dout, + din => ram_din + ); + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Memory Interface +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + +IS_ACTIVE <= take_spi; +SPI_NCS <= spi_ncs_latch; + +-- multiplexed access to the page ram address input +ram_addr <= ram_waddr when (select_write_ram = '1') else ram_raddr; + +-- POP_PAGE_DATA : process begin +-- -- read 32 bit from the page, to send it over trb_net +-- wait until rising_edge(CLK); +-- +-- pop_page_data_ready <= '0'; +-- +-- case pop_page_state is +-- when IDLE => +-- ram_raddr <= x"00"; +-- pop_page_byte_counter <= 0; +-- +-- if pop_page_rewind = '1' then +-- pop_page_word_counter <= 0; +-- end if; +-- +-- if trigger_pop_page_data = '1' then +-- pop_page_state <= READ_BYTE; +-- end if; +-- +-- when READ_BYTE => +-- ram_raddr <= std_logic_vector(to_unsigned(pop_page_byte_counter + pop_page_word_counter*4,8)); +-- pop_page_state <= WAIT4RAM; +-- when WAIT4RAM => +-- pop_page_state <= PUSH_BYTE; +-- when PUSH_BYTE => +-- pop_page_data_word( (pop_page_byte_counter*8 + 7) downto (pop_page_byte_counter*8) ) <= ram_dout; +-- if pop_page_byte_counter < 3 then +-- pop_page_state <= READ_BYTE; +-- pop_page_byte_counter <= pop_page_byte_counter +1; +-- else -- pushed last byte +-- pop_page_state <= IDLE; +-- pop_page_word_counter <= pop_page_word_counter +1; +-- pop_page_data_ready <= '1'; +-- end if; +-- end case; +-- +-- if RST = '1' then +-- pop_page_state <= IDLE; +-- end if; +-- end process; + +POP_PAGE_DATA : process begin + -- read n byte from the ram to a 32 bit output register "pop_page_data_word", new bytes get shifted in from the right + wait until rising_edge(CLK); + pop_page_data_ready <= '0'; + + case pop_page_state is + when IDLE => + + pop_page_ram_delay <= 0; + + if set_pop_page_position = '1' then + pop_page_position <= new_pop_page_position; + end if; + + if trigger_pop_page_data = '1' then + pop_page_state <= ACTIVE; + pop_page_noBytes_popped <= 0; + pop_page_noBytes_pushed <= 0; + pop_page_data_word <= (others => '0'); -- reset output register + end if; + + when ACTIVE => + + ram_raddr <= std_logic_vector(to_unsigned(pop_page_position,8)); -- give address to ram + + if pop_page_noBytes_popped < pop_page_noBytes then + pop_page_position <= pop_page_position +1; -- increment ram pointer + pop_page_noBytes_popped <= pop_page_noBytes_popped +1; + end if; + + -- set first addr when ram_delay = 0, do nothing when ram_delay = 1, use ram_dout when ram_delay = 2 + if pop_page_ram_delay < 2 then + pop_page_ram_delay <= pop_page_ram_delay +1; + else -- now ram is ready + -- shift old content to the left + pop_page_data_word(31 downto 8) <= pop_page_data_word(23 downto 0); + -- shift in new byte from the ram + pop_page_data_word(7 downto 0) <= ram_dout; + pop_page_noBytes_pushed <= pop_page_noBytes_pushed +1; + + if pop_page_noBytes_pushed = (pop_page_noBytes -1) then -- this is the last byte we want + pop_page_state <= IDLE; + pop_page_data_ready <= '1'; + end if; + end if; + end case; + + if RST = '1' then + pop_page_state <= IDLE; + end if; +end process; + + + +READ_PAGE_TO_RAM : process begin +-- read a complete page from flash and store it in the page ram + wait until rising_edge(CLK); + + spi_trigger <= '0'; + ram_wr <= '0'; + read_page_ready <= '0'; + select_write_ram <= '0'; -- free access to ram_addr again + + case read_page_state is + + when IDLE => + spi_ncs_latch <= '1'; + if trigger_read_page = '1' then + read_page_state <= SEND_CMD; + spi_ncs_latch <= '0'; + end if; + + when WAIT_FOR_SPI_READY => + if spi_ready = '1' then + read_page_state <= next_read_page_state; + end if; + + when SEND_CMD => + spi_data_in <= x"03"; -- the read command for the flash + spi_trigger <= '1'; + read_page_state <= WAIT_FOR_SPI_READY; + next_read_page_state <= SEND_A0; + + when SEND_A0 => + spi_data_in <= page_number(15 downto 8); + spi_trigger <= '1'; + read_page_state <= WAIT_FOR_SPI_READY; + next_read_page_state <= SEND_A1; + + when SEND_A1 => + spi_data_in <= page_number(7 downto 0); + spi_trigger <= '1'; + read_page_state <= WAIT_FOR_SPI_READY; + next_read_page_state <= SEND_A2; + + when SEND_A2 => + spi_data_in <= x"00"; + spi_trigger <= '1'; + read_page_state <= WAIT_FOR_SPI_READY; + next_read_page_state <= READ_DATA; + ram_wr_pointer <= x"00"; -- go to beginning of ram + + when READ_DATA => + spi_data_in <= x"00"; + spi_trigger <= '1'; + read_page_state <= WAIT_FOR_SPI_READY; + next_read_page_state <= STORE_DATA; + + when STORE_DATA => + select_write_ram <= '1'; -- take exclusive access to ram_addr + ram_wr <= '1'; + ram_din <= spi_data_out; + ram_waddr <= ram_wr_pointer; + -- increment ram address + if unsigned(ram_wr_pointer) < 255 then + ram_wr_pointer <= std_logic_vector(unsigned(ram_wr_pointer)+1); + read_page_state <= READ_DATA; + else -- we just read in the last byte + read_page_ready <= '1'; + read_page_state <= IDLE; + end if; + + + end case; + + if RST = '1' then + read_page_state <= IDLE; + end if; + + +-- -- init ram with bogus data +-- +-- if unsigned(read_page_init_counter) < 256 then +-- select_write_ram <= '1'; +-- read_page_init_counter <= std_logic_vector(unsigned(read_page_init_counter)+1); +-- ram_wr <= '1'; +-- ram_waddr <= read_page_init_counter(7 downto 0); +-- ram_din <= read_page_init_counter(7 downto 0); +-- end if; + + + +end process; + + +PARSE : process begin + wait until rising_edge(CLK); + + trigger_read_page <= '0'; + trigger_pop_page_data <= '0'; + set_pop_page_position <= '0'; + + BUS_MASTER_TX.data <= (others => '0'); + BUS_MASTER_TX.addr <= (others => '0'); + BUS_MASTER_TX.write <= '0' ; + BUS_MASTER_TX.read <= '0' ; + BUS_MASTER_TX.timeout <= '0' ; + + case parse_state is + + when IDLE => + take_spi <= '0'; + if parse_trigger = '1' then + parse_state <= READ_HEADER_PAGE; + take_spi <= '1'; + sc_write_errors <= (others => '0'); + end if; + + when READ_HEADER_PAGE => + page_number <= HEADER_PAGE_ADDR; + trigger_read_page <= '1'; + parse_state <= WAIT4PAGE; + parse_counter <= 0; + next_parse_state <= VERIFY_START_STRING; + + when WAIT4PAGE => + if read_page_ready = '1' then + parse_state <= next_parse_state; + end if; + + when VERIFY_START_STRING => + parse_state <= WAIT4RAM; + next_parse_state <= VERIFY_START_STRING; + + + + if parse_counter = 0 then + pop_page_noBytes <= 1; + new_pop_page_position <= 0; + set_pop_page_position <= '1'; + else + if parse_counter = 8 then + -- so far everything has evaluated fine + parse_state <= GET_NO_REGISTERS; + end if; + -- if one of the characters is not there, goto FAIL + if not(pop_page_data_word(7 downto 0) = header_string(parse_counter-1)) then + parse_state <= FAIL; + end if; + end if; + + if parse_counter < 8 then + trigger_pop_page_data <= '1'; + parse_counter <= parse_counter +1; + end if; + + when WAIT4RAM => + if pop_page_data_ready = '1' then + parse_state <= next_parse_state; + end if; + + when GET_NO_REGISTERS => + pop_page_noBytes <= 4; + trigger_pop_page_data <= '1'; + + next_parse_state <= STORE_NO_REGISTERS; + parse_state <= WAIT4RAM; + + when STORE_NO_REGISTERS => + registers_to_read <= pop_page_data_word; + parse_state <= GET_NO_PAGES; + + when GET_NO_PAGES => + trigger_pop_page_data <= '1'; + + next_parse_state <= STORE_NO_PAGES; + parse_state <= WAIT4RAM; + + when STORE_NO_PAGES => + pages_to_read <= pop_page_data_word; + parse_state <= READ_NEXT_PAGE; + + + when READ_NEXT_PAGE => + + if unsigned(pages_to_read) > 0 then + page_number <= std_logic_vector(unsigned(page_number)+1); + trigger_read_page <= '1'; + parse_state <= WAIT4PAGE; + parse_counter <= 0; + + -- reset page read position + new_pop_page_position <= 0; + set_pop_page_position <= '1'; + pages_to_read <= std_logic_vector(unsigned(pages_to_read)-1); + + next_parse_state <= READ_SC_ADDR; + else + parse_state <= SUCCESS; + end if; + + when READ_SC_ADDR => + pop_page_noBytes <= 2; + trigger_pop_page_data <= '1'; + next_parse_state <= STORE_SC_ADDR; + parse_state <= WAIT4RAM; + + when STORE_SC_ADDR => + current_sc_addr <= pop_page_data_word(15 downto 0); + parse_state <= READ_SC_VALUE; + + when READ_SC_VALUE => + pop_page_noBytes <= 4; + trigger_pop_page_data <= '1'; + next_parse_state <= STORE_SC_VALUE; + parse_state <= WAIT4RAM; + + when STORE_SC_VALUE => + current_sc_value <= pop_page_data_word; + parse_state <= SEND_SC_DATA; + registers_to_read <= std_logic_vector(unsigned(registers_to_read)-1); + + when SEND_SC_DATA => + BUS_MASTER_TX.data <= current_sc_value; + BUS_MASTER_TX.addr <= current_sc_addr; + BUS_MASTER_TX.write <= '1'; + parse_state <= WAIT4_SC_ACK; + sc_ack_timeout <= 31; + + when WAIT4_SC_ACK => + if sc_ack_timeout = 0 + or BUS_MASTER_RX.ack = '1' + or BUS_MASTER_RX.wack = '1' + or BUS_MASTER_RX.rack = '1' + or BUS_MASTER_RX.nack = '1' + or BUS_MASTER_RX.unknown = '1' then + + -- timeout or error + if sc_ack_timeout = 0 + or BUS_MASTER_RX.rack = '1' + or BUS_MASTER_RX.nack = '1' + or BUS_MASTER_RX.unknown = '1' then + sc_write_errors <= std_logic_vector(unsigned(sc_write_errors)+1); + end if; + + parse_counter <= parse_counter +1; + parse_state <= READ_SC_ADDR; + + if parse_counter >= (REGISTERS_PER_PAGE -1) then + if unsigned(pages_to_read) > 0 then + parse_state <= READ_NEXT_PAGE; + else + parse_state <= SUCCESS; + end if; + end if; + + if unsigned(registers_to_read) = 0 then + parse_state <= SUCCESS; + end if; + + else + sc_ack_timeout <= sc_ack_timeout -1; + end if; + + when SUCCESS => + parse_state <= IDLE; + parse_feedback <= current_sc_addr & current_sc_value(15 downto 0); + + when FAIL => + parse_state <= IDLE; + parse_feedback <= x"000000F0"; + + end case; + + if RST = '1' then + parse_state <= IDLE; + sc_write_errors <= (others => '0'); + end if; + +end process; + + +sync : process begin + wait until rising_edge(CLK); + BUS_TX.data <= (others => '0'); -- default + BUS_TX.nack <= '0'; + BUS_TX.unknown <= '0'; + BUS_TX.ack <= '0'; + +-- spi_trigger <= '0'; +-- trigger_read_page <= '0'; +-- trigger_pop_page_data <= '0'; +-- set_pop_page_position <= '0'; + parse_trigger <= '0'; + + if( BUS_RX.write = '1') then -- got a write command + BUS_TX.ack <= '1'; + + case BUS_RX.addr(7 downto 0) is + when ADDR_TAKE_SPI => +-- take_spi <= BUS_RX.data(0); + when ADDR_DATA_IN => +-- spi_data_in <= BUS_RX.data(7 downto 0); +-- spi_trigger <= '1'; + when ADDR_NCS => +-- spi_ncs_latch <= BUS_RX.data(0); + + when ADDR_PAGE_SELECT => +-- page_number <= BUS_RX.data(15 downto 0); +-- trigger_read_page <= '1'; + when ADDR_PAGE_POS => +-- set_pop_page_position <= '1'; +-- new_pop_page_position <= to_integer(unsigned(BUS_RX.data(7 downto 0))); + when ADDR_POP_PAGE_NOBYTES => +-- pop_page_noBytes <= to_integer(unsigned(BUS_RX.data(7 downto 0))); + when ADDR_PARSE_TRIGGER => + parse_trigger <= '1'; + when others => + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '1'; + end case; + end if; + + if( BUS_RX.read = '1') then -- got a read command + BUS_TX.ack <= '1'; + BUS_TX.data(15 downto 0) <= (others => '0'); + case BUS_RX.addr(7 downto 0) is + when ADDR_TAKE_SPI => + BUS_TX.data(0) <= take_spi; + when ADDR_DATA_OUT => + BUS_TX.data(7 downto 0) <= spi_data_out; + when ADDR_DATA_IN => + BUS_TX.data(7 downto 0) <= spi_data_in; + when ADDR_TRANSMISSION_COUNTER => + BUS_TX.data(15 downto 0) <= transmission_counter; + when ADDR_NCS => + BUS_TX.data(0) <= spi_ncs_latch; + when ADDR_PAGE_SELECT => + BUS_TX.data(15 downto 0) <= page_number; + when ADDR_POP_PAGE_NOBYTES => + BUS_TX.data(7 downto 0) <= std_logic_vector(to_unsigned(pop_page_noBytes,8)); + when ADDR_POP_PAGE_DATA => +-- trigger_pop_page_data <= '1'; + BUS_TX.ack <= '0'; -- don't ack yet, wait for pop_page_data_ready + when ADDR_FEEDBACK => + BUS_TX.data <= parse_feedback; + when ADDR_SC_WRITE_ERRORS => + BUS_TX.data <= sc_write_errors; + -- DEFAULT -- + when others => + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '1'; + end case; + end if; + + if pop_page_data_ready = '1' then + BUS_TX.data(31 downto 0) <= pop_page_data_word; + BUS_TX.ack <= '1'; + end if; + + if RST = '1' then + transmission_counter <= (others => '0'); + end if; + + if(spi_ready = '1') then + transmission_counter <= std_logic_vector(unsigned(transmission_counter) +1); + end if; + + +end process; + + +end architecture; + diff --git a/code/spi_master_generic.vhd b/code/spi_master_generic.vhd new file mode 100644 index 0000000..576a124 --- /dev/null +++ b/code/spi_master_generic.vhd @@ -0,0 +1,174 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use trb_net_std.all; + + + +entity spi_master_generic is + generic( + -- default settings are: + -- wordsize 8 bits, sck idle=LO + -- data is valid at rising edges + WORDSIZE : integer := 8; + CPOL : std_logic := '0'; + CPHA : std_logic := '0'; + SPI_CLOCK_DIVIDER : integer := 5 -- 100 MHz/5 = 20 MHz + + ); + port( + CLK : in std_logic; + RST : in std_logic; + + DATA_OUT : out std_logic_vector(WORDSIZE-1 downto 0); + DATA_IN : in std_logic_vector(WORDSIZE-1 downto 0); + TRANSFER_COMPLETE : out std_logic; + TRIGGER_TRANSFER : in std_logic; + + MOSI : out std_logic; + MISO : in std_logic; + SCK : out std_logic + + ); +end entity; + + + +architecture spi_master_generic_arch of spi_master_generic is + +signal sck_rise,sck_fall : std_logic; +signal sck_raw,sck_raw_buf,sck_gate : std_logic := '0'; +signal transition_strobe, sample_strobe, sample_strobe_buf : std_logic; +signal trigger_transfer_latch : std_logic := '0'; + + +-- sck generation +signal bit_counter : integer range 0 to WORDSIZE-1 := 0; +signal sck_clock_div_counter : integer range 0 to (SPI_CLOCK_DIVIDER-1) :=0; + + +-- transfer state machine +type transfer_state_t is (IDLE,TRANSFER); +signal transfer_state : transfer_state_t := IDLE; + +-- internal data transmission +signal data_out_buffer : std_logic_vector((WORDSIZE-1) downto 0); +signal data_in_buffer : std_logic_vector((WORDSIZE-1) downto 0); +signal data_out_ready : std_logic; + + + +begin + + +---------------------------- +-- SCK Generation +---------------------------- + +generate_sck : process begin + +-- Generate a square wave with frequency CLK/SPI_CLOCK_DIVIDER +-- more precisely, generate strobes at the rising and falling +-- edges of such a square wave + + wait until rising_edge(CLK); + + sck_rise <= '0'; + sck_fall <= '0'; + sck_raw_buf <= sck_raw; -- delayed by one CLK cycle + + sck_clock_div_counter <= sck_clock_div_counter + 1; + if sck_clock_div_counter >= (SPI_CLOCK_DIVIDER -1) then + sck_clock_div_counter <= 0; + end if; + + if sck_clock_div_counter = 0 then + sck_rise <= '1'; + sck_raw <= '1'; + end if; + + if sck_clock_div_counter = (SPI_CLOCK_DIVIDER/2) then + sck_fall <= '1'; + sck_raw <= '0'; + end if; + +end process; + +-- multiplexers to accomodate different SPI modes +transition_strobe <= sck_rise when (CPHA = '1') else sck_fall; +sample_strobe <= sck_fall when (CPHA = '1') else sck_rise; + + +transfer_state_machine : process begin + wait until rising_edge(CLK); + trigger_transfer_latch <= trigger_transfer_latch or TRIGGER_TRANSFER; -- latch transfer trigger + + case transfer_state is + when IDLE => + -- start transfer at next full sck cycle + if (transition_strobe = '1') and (trigger_transfer_latch = '1') then + sck_gate <= '1'; + transfer_state <= TRANSFER; + trigger_transfer_latch <= '0'; -- clear your trigger memory + end if; + when TRANSFER => + if transition_strobe = '1' then + if bit_counter < (WORDSIZE-1) then + -- after processing bits 0-(WORDSIZE-2) + bit_counter <= bit_counter + 1; + else + -- after last bit (WORDSIZE-1) + bit_counter <= 0; + sck_gate <= '0'; + transfer_state <= IDLE; + end if; + end if; + end case; + + if RST = '1' then + transfer_state <= IDLE; + bit_counter <= 0 ; + sck_gate <= '0'; + end if; + +end process; + + +sample_and_hold_data_in : process begin + wait until rising_edge(CLK); + if TRIGGER_TRANSFER = '1' then + data_in_buffer <= DATA_IN; + end if; +end process; + + +rx_process : process begin + wait until rising_edge(CLK); + sample_strobe_buf <= sample_strobe; + data_out_ready <= '0'; + TRANSFER_COMPLETE <= '0'; + + if sample_strobe_buf = '1' then + data_out_buffer( (WORDSIZE-1) - bit_counter ) <= MISO; + if bit_counter = (WORDSIZE-1) then + data_out_ready <= '1'; + end if; + end if; + + if data_out_ready = '1' then + DATA_OUT <= data_out_buffer; + TRANSFER_COMPLETE <= '1'; + end if; + +end process; + +sync_output : process begin + wait until rising_edge(CLK); + + SCK <= CPOL xor ( sck_raw_buf and sck_gate ); -- accomodate for reversed clock polarity + MOSI <= data_in_buffer( (WORDSIZE-1) - bit_counter ) and sck_gate; + +end process; + + +end architecture; \ No newline at end of file diff --git a/code/trb3sc_tools.vhd b/code/trb3sc_tools.vhd index 965bb08..24286b5 100644 --- a/code/trb3sc_tools.vhd +++ b/code/trb3sc_tools.vhd @@ -46,6 +46,11 @@ entity trb3sc_tools is BUS_RX : in CTRLBUS_RX; BUS_TX : out CTRLBUS_TX; + --Control master for default settings + BUS_MASTER_IN : in CTRLBUS_TX; + BUS_MASTER_OUT : out CTRLBUS_RX; + BUS_MASTER_ACTIVE : out std_logic; + DEBUG_OUT : out std_logic_vector(31 downto 0) ); end entity; @@ -54,14 +59,19 @@ end entity; architecture trb3sc_tools_arch of trb3sc_tools is -signal busflash_rx, busspi_rx, busadc_rx, bussed_rx, busuart_rx : CTRLBUS_RX; -signal busflash_tx, busspi_tx, busadc_tx, bussed_tx, busuart_tx : CTRLBUS_TX; +signal busflash_rx, busspi_rx, busadc_rx, bussed_rx, busuart_rx, busflashset_rx : CTRLBUS_RX; +signal busflash_tx, busspi_tx, busadc_tx, bussed_tx, busuart_tx, busflashset_tx : CTRLBUS_TX; signal spi_sdi, spi_sdo, spi_sck : std_logic; signal spi_cs : std_logic_vector(15 downto 0); signal lcd_cs, lcd_dc, lcd_mosi, lcd_sck, lcd_rst : std_logic; signal uart_rx, uart_tx : std_logic; +signal flashset_active : std_logic; +signal flash_cs_i, flash_clk_i, flash_out_i : std_logic; +signal flash_cs_s, flash_clk_s, flash_out_s : std_logic; + + begin --------------------------------------------------------------------------- @@ -69,9 +79,9 @@ begin --------------------------------------------------------------------------- THE_BUS_HANDLER : entity work.trb_net16_regio_bus_handler_record generic map( - PORT_NUMBER => 5, - PORT_ADDRESSES => (0 => x"0000", 1 => x"0400", 2 => x"0480", 3 => x"0500", 4 => x"0600", others => x"0000"), - PORT_ADDR_MASK => (0 => 9, 1 => 5, 2 => 5, 3 => 1, 4 => 2, others => 0), + PORT_NUMBER => 6, + PORT_ADDRESSES => (0 => x"0000", 1 => x"0400", 2 => x"0480", 3 => x"0500", 4 => x"0600", 5 => x"0180", others => x"0000"), + PORT_ADDR_MASK => (0 => 9, 1 => 5, 2 => 5, 3 => 1, 4 => 2, 5 => 4, others => 0), PORT_MASK_ENABLE => 1 ) port map( @@ -86,11 +96,13 @@ begin BUS_RX(2) => busadc_rx, BUS_RX(3) => bussed_rx, BUS_RX(4) => busuart_rx, + BUS_RX(5) => busflashset_rx, BUS_TX(0) => busflash_tx, BUS_TX(1) => busspi_tx, BUS_TX(2) => busadc_tx, BUS_TX(3) => bussed_tx, BUS_TX(4) => busuart_tx, + BUS_TX(5) => busflashset_tx, STAT_DEBUG => open ); @@ -111,12 +123,43 @@ begin DO_REBOOT_IN => REBOOT_IN, PROGRAMN => PROGRAMN, - SPI_CS_OUT => FLASH_CS, - SPI_SCK_OUT => FLASH_CLK, - SPI_SDO_OUT => FLASH_OUT, + SPI_CS_OUT => flash_cs_i, + SPI_SCK_OUT => flash_clk_i, + SPI_SDO_OUT => flash_out_i, SPI_SDI_IN => FLASH_IN ); + +--------------------------------------------------------------------------- +-- Load Settings from Flash +--------------------------------------------------------------------------- +THE_FLASH_REGS : entity work.load_settings + port map( + CLK => CLK, + RST => RESET, + + -- the bus handler signals + BUS_RX => busflashset_rx, + BUS_TX => busflashset_tx, + + IS_ACTIVE => flashset_active, + + BUS_MASTER_TX => BUS_MASTER_OUT, + BUS_MASTER_RX => BUS_MASTER_IN, + + SPI_MOSI => flash_out_s, + SPI_MISO => FLASH_IN, + SPI_SCK => flash_clk_s, + SPI_NCS => flash_cs_s + + ); + + BUS_MASTER_ACTIVE <= flashset_active; + FLASH_CS <= flash_cs_i when flashset_active = '0' else flash_cs_s; + FLASH_CLK <= flash_clk_i when flashset_active = '0' else flash_clk_s; + FLASH_OUT <= flash_out_i when flashset_active = '0' else flash_out_s; + + --------------------------------------------------------------------------- -- SED Detection --------------------------------------------------------------------------- diff --git a/pinout/basic_constraints.lpf b/pinout/basic_constraints.lpf index 785d385..9692b0c 100644 --- a/pinout/basic_constraints.lpf +++ b/pinout/basic_constraints.lpf @@ -46,6 +46,7 @@ REGION "REGION_SPI" "R19C150D" 20 20 DEVSIZE; LOCATE UGROUP "THE_TOOLS/THE_SPI_RELOAD/THE_SPI_MASTER/SPI_group" REGION "REGION_SPI" ; LOCATE UGROUP "THE_TOOLS/THE_SPI_RELOAD/THE_SPI_MEMORY/SPI_group" REGION "REGION_SPI" ; +LOCATE COMP "THE_MEDIA_INTERFACE/gen_pcs0.THE_SERDES/PCSD_INST" SITE "PCSA" ; LOCATE COMP "THE_MEDIA_INTERFACE/gen_pcs3.THE_SERDES/PCSD_INST" SITE "PCSB" ; REGION "MEDIA_UPLINK" "R102C55D" 13 50; LOCATE UGROUP "THE_MEDIA_INTERFACE/media_interface_group" REGION "MEDIA_UPLINK" ; diff --git a/template/config.vhd b/template/config.vhd index 2f2ec1f..abe29a0 100644 --- a/template/config.vhd +++ b/template/config.vhd @@ -21,7 +21,9 @@ package config is constant INIT_ADDRESS : std_logic_vector := x"F3CC"; constant BROADCAST_SPECIAL_ADDR : std_logic_vector := x"60"; - +--set to 0 for backplane serdes, set to 3 for front SFP serdes + constant SERDES_NUM : integer := 0; + constant INCLUDE_UART : integer := c_YES; constant INCLUDE_SPI : integer := c_YES; constant INCLUDE_LCD : integer := c_YES; diff --git a/template/trb3sc_basic.prj b/template/trb3sc_basic.prj index 00d82b3..dbda519 100644 --- a/template/trb3sc_basic.prj +++ b/template/trb3sc_basic.prj @@ -112,6 +112,8 @@ add_file -vhdl -lib work "../../trbnet/special/uart.vhd" add_file -vhdl -lib work "../../trbnet/special/uart_rec.vhd" add_file -vhdl -lib work "../../trbnet/special/uart_trans.vhd" add_file -vhdl -lib work "../../trbnet/special/spi_ltc2600.vhd" +add_file -vhdl -lib work "../../trb3sc/code/load_settings.vhd" +add_file -vhdl -lib work "../../trb3sc/code/spi_master_generic.vhd" #SlowControl files add_file -vhdl -lib work "../../trbnet/trb_net16_regio_bus_handler.vhd" diff --git a/template/trb3sc_basic.vhd b/template/trb3sc_basic.vhd index c349bec..200f19f 100644 --- a/template/trb3sc_basic.vhd +++ b/template/trb3sc_basic.vhd @@ -128,23 +128,22 @@ architecture trb3sc_arch of trb3sc_basic is signal readout_rx : READOUT_RX; signal readout_tx : readout_tx_array_t(0 to 0); - signal ctrlbus_rx, bussci_rx, bustools_rx, bustc_rx : CTRLBUS_RX; - signal ctrlbus_tx, bussci_tx, bustools_tx, bustc_tx : CTRLBUS_TX; + signal ctrlbus_rx, bussci_rx, bustools_rx, bustc_rx, bus_master_out, handlerbus_rx : CTRLBUS_RX; + signal ctrlbus_tx, bussci_tx, bustools_tx, bustc_tx, bus_master_in : CTRLBUS_TX; signal common_stat_reg : std_logic_vector(std_COMSTATREG*32-1 downto 0) := (others => '0'); signal common_ctrl_reg : std_logic_vector(std_COMCTRLREG*32-1 downto 0); signal sed_error_i : std_logic; signal clock_select : std_logic; + signal bus_master_active : std_logic; signal spi_cs, spi_mosi, spi_miso, spi_clk : std_logic_vector(15 downto 0); signal timer : TIMERS; signal lcd_data : std_logic_vector(511 downto 0); - - signal timer : TIMERS; - signal lcd_data : std_logic_vector(511 downto 0); + signal sfp_los_i, sfp_txdis_i, sfp_prsnt_i : std_logic; attribute syn_keep of GSR_N : signal is true; attribute syn_preserve of GSR_N : signal is true; @@ -192,7 +191,7 @@ THE_CLOCK_RESET : entity work.clock_reset_handler THE_MEDIA_INTERFACE : entity work.med_ecp3_sfp_sync generic map( - SERDES_NUM => 3, + SERDES_NUM => SERDES_NUM, IS_SYNC_SLAVE => c_YES ) port map( @@ -213,9 +212,9 @@ THE_CLOCK_RESET : entity work.clock_reset_handler --SFP Connection SD_REFCLK_P_IN => '0', SD_REFCLK_N_IN => '0', - SD_PRSNT_N_IN => SFP_MOD0(1), - SD_LOS_IN => SFP_LOS(1), - SD_TXDIS_OUT => SFP_TX_DIS(1), + SD_PRSNT_N_IN => sfp_prsnt_i, + SD_LOS_IN => sfp_los_i, + SD_TXDIS_OUT => sfp_txdis_i, --Control Interface BUS_RX => bussci_rx, BUS_TX => bussci_tx, @@ -225,8 +224,17 @@ THE_CLOCK_RESET : entity work.clock_reset_handler ); SFP_TX_DIS(0) <= '1'; - - + gen_sfp_con : if SERDES_NUM = 3 generate + sfp_los_i <= SFP_LOS(1); + sfp_prsnt_i <= SFP_MOD0(1); + SFP_TX_DIS(1) <= sfp_txdis_i; + end generate; + gen_bpl_con : if SERDES_NUM = 0 generate + sfp_los_i <= BACK_GPIO(1); + sfp_prsnt_i <= BACK_GPIO(1); + BACK_GPIO(0) <= sfp_txdis_i; + end generate; + --------------------------------------------------------------------------- -- Endpoint --------------------------------------------------------------------------- @@ -267,6 +275,7 @@ THE_ENDPOINT : entity work.trb_net16_endpoint_hades_full_handler_record REGIO_COMMON_CTRL_REG_OUT => common_ctrl_reg, --0x20 BUS_RX => ctrlbus_rx, BUS_TX => ctrlbus_tx, + ONEWIRE_INOUT => TEMPSENS, --Timing registers TIMERS_OUT => timer @@ -275,6 +284,9 @@ THE_ENDPOINT : entity work.trb_net16_endpoint_hades_full_handler_record --------------------------------------------------------------------------- -- Bus Handler --------------------------------------------------------------------------- + + handlerbus_rx <= ctrlbus_rx when bus_master_active = '0' else bus_master_out; + THE_BUS_HANDLER : entity work.trb_net16_regio_bus_handler_record generic map( PORT_NUMBER => 3, @@ -286,7 +298,7 @@ THE_ENDPOINT : entity work.trb_net16_endpoint_hades_full_handler_record CLK => clk_sys, RESET => reset_i, - REGIO_RX => ctrlbus_rx, + REGIO_RX => handlerbus_rx, REGIO_TX => ctrlbus_tx, BUS_RX(0) => bustools_rx, --Flash, SPI, UART, ADC, SED @@ -333,7 +345,10 @@ THE_ENDPOINT : entity work.trb_net16_endpoint_hades_full_handler_record --Slowcontrol BUS_RX => bustools_rx, BUS_TX => bustools_tx, - + --Control master for default settings + BUS_MASTER_IN => ctrlbus_tx, + BUS_MASTER_OUT => bus_master_out, + BUS_MASTER_ACTIVE => bus_master_active, DEBUG_OUT => open );