eFEX firmware  1.7.3
ATLAS l1-calo - electron and tau feature extraction firmware for eFEX boards

Back to eFEX documentation
spi32_8_control.vhd
Go to the documentation of this file.
1 
9 
10 library IEEE;
11 use IEEE.std_logic_1164.all;
12 use IEEE.std_logic_arith.all;
13 use IEEE.std_logic_unsigned.all;
15 entity spi32_8_control is
16  generic(
17  ADDR_WIDTH: natural;-- size of buffer memory, outgoing + incoming.
18  BYTE_SPI: boolean := FALSE);
19  port (
21  spi_clk : in std_logic;
23  reset : in std_logic;
25  outgoing_data : in std_logic_vector( 31 downto 0);
27  incoming_data : out std_logic_vector( 31 downto 0);
29  run_spi : in std_logic;
31  busy : out std_logic := '0';
33  transfer_count : in std_logic_vector( ADDR_WIDTH + 1 downto 0);
35  ram_ptr : out std_logic_vector( ADDR_WIDTH - 2 downto 0);
37  ram_write : out std_logic := '0';
39  clk_en : out std_logic := '0';
41  cs_n : out std_logic := '1';
43  mosi : out std_logic := '0';
45  miso : in std_logic := '0'
46  );
47 end spi32_8_control ;
49 
50 architecture rtl of spi32_8_control is
51 
52 constant MSB_FIRST : boolean := BYTE_SPI;-- FALSE for PLL chips
53 constant BIG_FRAME : boolean := BYTE_SPI;-- if set: send inside one big cs_n frame
54 constant TRAP_CODE : boolean := not BYTE_SPI;-- if set: trap otp code before PLL
55 
56 --signal run_spi : std_logic := '0';
57 
58 type shiftstate is ( idle, start_frame, read_mem, shift_io, write_mem, end_frame );
59 signal sequencer : shiftstate := idle;
60 
61 signal shift_count : integer range 0 to 32 := 0;
62 signal shift_register : std_logic_vector(31 downto 0) := (others => '0');
63 signal mosi_data : std_logic_vector(31 downto 0) := (others => '0');
64 
65 signal miso_rising : std_logic;
66 signal le_int : std_logic := '0';
67 
68 signal ram_index_u : unsigned(ADDR_WIDTH - 1 downto 0) := (others => '0');
69 signal num_words : std_logic_vector(ADDR_WIDTH - 1 downto 0);
70 signal num_32words : unsigned(ADDR_WIDTH - 1 downto 0);
71 signal ram_index_slv : std_logic_vector(ADDR_WIDTH - 1 downto 0) := (others => '0');
72 
73 constant otp_code : std_logic_vector(31 downto 0) := x"0000A03F";-- eeprom OTP command
74 
75 attribute dont_touch : string;
76 attribute dont_touch of ram_index_u : signal is "true";
77 attribute dont_touch of num_32words : signal is "true";
78 
79 alias rem_bytes is transfer_count(1 downto 0);
80 signal term_le : std_logic := '0';
81 
82 begin
83 
84 bit_order: for i in 0 to 31 generate
85  mosi_data(i) <= outgoing_data(31-i) when MSB_FIRST else outgoing_data(i);
86  incoming_data(i) <= shift_register(31-i) when MSB_FIRST else shift_register(i);
87  end generate;
88 
89 
90 -- synch: entity work.command_sync
91  -- port map (
92  -- clk => spi_clk,
93  -- reset => reset,
94  -- command_in => do_spi,
95  -- command_out => run_spi
96  -- );
97 
98 -------------------------------------------------------------------------------
99 -- state machine transitions
100 -------------------------------------------------------------------------------
101 
102 spi_sequencer: process(spi_clk,reset,sequencer,run_spi,shift_count)
103  begin
104  if rising_edge(spi_clk) then
105 
106  shift_count <= 0;
107  ram_index_u <= ram_index_u;
108 
109  if reset = '1' then
110  sequencer <= idle;
111  else
112 
113  case sequencer is
114  when idle =>
115  ram_index_u <= (others => '0');
116  if (run_spi = '1' ) then
117  sequencer <= start_frame;
118  end if;
119  busy <= '0';
120  when start_frame => -- check if any (more) words to send
121  if (ram_index_u = num_32words) then
122  sequencer <= idle;
123  else
124  sequencer <= read_mem;
125  end if;
126  busy <= '1';
127  when read_mem =>
128  sequencer <= shift_io;
129  when shift_io =>
130  shift_count <= shift_count + 1;
131  if (shift_count = 31 ) then
132  sequencer <= write_mem;
133  end if;
134  when write_mem =>
135  sequencer <= end_frame;
136  when end_frame =>
137  sequencer <= start_frame;
138  ram_index_u <= ram_index_u + 1;
139  when others =>
140  sequencer <= idle;
141  end case;
142  end if;
143 
144  miso_rising <= miso;
145 
146  end if;
147 
148  end process spi_sequencer;
149 
150  ram_index_slv <= std_logic_vector(ram_index_u);
151 
152  ram_ptr <= ram_index_slv( ADDR_WIDTH - 2 downto 0);
153 
154 -------------------------------------------------------------------------------
155 -- serdes input / output shift register
156 -------------------------------------------------------------------------------
157 
158 serdes: process(spi_clk,shift_register)
159  begin
160 
161  if falling_edge(spi_clk) then
162 
163  ram_write <= '0';
164  shift_register <= shift_register;
165 
166  case sequencer is
167  when read_mem => -- and trap PLL eeprom OTP instruction. substitute zero
168  if (TRAP_CODE and outgoing_data = otp_code) then
169  shift_register <= (others => '0');
170  else
171  shift_register <= mosi_data;
172  end if;
173  when shift_io | write_mem => -- needs one extra shift in to grab last bit
174  shift_register <= miso_rising & shift_register (31 downto 1) ;
175  when others => null;
176  end case;
177 
178  if sequencer = write_mem then ram_write <= '1'; end if;
179 
180  mosi <= shift_register (0);
181 
182  end if;
183  end process serdes;
184 
185 -------------------------------------------------------------------------------
186 -- chip and clock enable options
187 -------------------------------------------------------------------------------
188 
189 gen_enable_words: if not BYTE_SPI generate
190 
191  num_32words <= unsigned(transfer_count( ADDR_WIDTH - 1 downto 0));
192 
193 chip_enable: process(spi_clk,shift_register)
194  begin
195 
196  if falling_edge(spi_clk) then
197 
198  le_int <= '0';
199  clk_en <= '0';
200 
201  case sequencer is
202  when shift_io =>
203  le_int <= '1';
204  clk_en <= '1';
205  when others => null;
206  end case;
207 
208  end if;
209  end process chip_enable;
210 end generate;
211 
212 -------------------------------------------------------------------------------
213 
214 gen_enable_bytes: if BYTE_SPI generate
215 
216  with rem_bytes select
217  num_32words <= unsigned(transfer_count( ADDR_WIDTH + 1 downto 2)) when "00",
218  unsigned(transfer_count( ADDR_WIDTH + 1 downto 2)) + 1 when others;
219 
220 chip_enable: process(spi_clk,shift_register)
221  begin
222 
223  if falling_edge(spi_clk) then
224 
225  le_int <= '0';
226  clk_en <= '0';
227 
228  case sequencer is
229  when idle =>
230  term_le <= '0';
231  when start_frame | read_mem | write_mem | end_frame =>
232  if (term_le = '0' ) then le_int <= '1'; end if;
233  when shift_io =>
234  if (ram_index_u +1 = num_32words) then
235  if ((rem_bytes = "00" ) or
236  (rem_bytes = "01" and shift_count < 8) or
237  (rem_bytes = "10" and shift_count < 16) or
238  (rem_bytes = "11" and shift_count < 24)) then
239  le_int <= '1'; clk_en <= '1';
240  term_le <= '1';
241  else
242  le_int <= '0'; clk_en <= '0';-- continue shifting to align bits
243  end if;
244  else
245  le_int <= '1'; clk_en <= '1';
246  end if;
247  when others => null;
248  end case;
249 
250  end if;
251  end process chip_enable;
252 
253 end generate;
254 -------------------------------------------------------------------------------
255 
256  cs_n <= not le_int;
257 
258 end;
259 
260 
icontroller for SPI interface PLL chips of FTM /eFEX
icontroller for SPI interface PLL chips of FTM /eFEX
in reset std_logic
reset
out cs_n std_logic := '1'
chip select of the spi flssh
out incoming_data std_logic_vector( 31 downto 0)
data from the spi flash
out busy std_logic := '0'
busy
in outgoing_data std_logic_vector( 31 downto 0)
data going to the spi flash
in run_spi std_logic
run spi controller
in transfer_count std_logic_vector( ADDR_WIDTH+ 1 downto 0)
data transfer count
out clk_en std_logic := '0'
clock enable
out mosi std_logic := '0'
mosi to spi flash
in miso std_logic := '0'
miso from spi flash
out ram_write std_logic := '0'
write enable of the ram
in spi_clk std_logic
spi clock
out ram_ptr std_logic_vector( ADDR_WIDTH- 2 downto 0)
ram pointer