1 |
70 |
zero_gravi |
-- #################################################################################################
|
2 |
|
|
-- # << NEORV32 - Execute In Place (XIP) Module >> #
|
3 |
|
|
-- # ********************************************************************************************* #
|
4 |
|
|
-- # This module allows the CPU to execute code (and read constant data) directly from an SPI #
|
5 |
|
|
-- # flash memory. Two host ports are implemented: one for accessing the control and status #
|
6 |
|
|
-- # registers (mapped to the processor's IO space) and one for the actual instruction/data fetch. #
|
7 |
|
|
-- # The actual address space mapping of the "instruction/data interface" is done by programming #
|
8 |
|
|
-- # special control register bits. #
|
9 |
|
|
-- # ********************************************************************************************* #
|
10 |
|
|
-- # BSD 3-Clause License #
|
11 |
|
|
-- # #
|
12 |
|
|
-- # Copyright (c) 2022, Stephan Nolting. All rights reserved. #
|
13 |
|
|
-- # #
|
14 |
|
|
-- # Redistribution and use in source and binary forms, with or without modification, are #
|
15 |
|
|
-- # permitted provided that the following conditions are met: #
|
16 |
|
|
-- # #
|
17 |
|
|
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
18 |
|
|
-- # conditions and the following disclaimer. #
|
19 |
|
|
-- # #
|
20 |
|
|
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
|
21 |
|
|
-- # conditions and the following disclaimer in the documentation and/or other materials #
|
22 |
|
|
-- # provided with the distribution. #
|
23 |
|
|
-- # #
|
24 |
|
|
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
|
25 |
|
|
-- # endorse or promote products derived from this software without specific prior written #
|
26 |
|
|
-- # permission. #
|
27 |
|
|
-- # #
|
28 |
|
|
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
|
29 |
|
|
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
|
30 |
|
|
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
|
31 |
|
|
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
32 |
|
|
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
|
33 |
|
|
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
|
34 |
|
|
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
35 |
|
|
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
|
36 |
|
|
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
|
37 |
|
|
-- # ********************************************************************************************* #
|
38 |
|
|
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
|
39 |
|
|
-- #################################################################################################
|
40 |
|
|
|
41 |
|
|
library ieee;
|
42 |
|
|
use ieee.std_logic_1164.all;
|
43 |
|
|
use ieee.numeric_std.all;
|
44 |
|
|
|
45 |
|
|
library neorv32;
|
46 |
|
|
use neorv32.neorv32_package.all;
|
47 |
|
|
|
48 |
|
|
entity neorv32_xip is
|
49 |
|
|
port (
|
50 |
|
|
-- global control --
|
51 |
|
|
clk_i : in std_ulogic; -- global clock line
|
52 |
|
|
rstn_i : in std_ulogic; -- global reset line, low-active
|
53 |
|
|
-- host access: control register access port --
|
54 |
|
|
ct_addr_i : in std_ulogic_vector(31 downto 0); -- address
|
55 |
|
|
ct_rden_i : in std_ulogic; -- read enable
|
56 |
|
|
ct_wren_i : in std_ulogic; -- write enable
|
57 |
|
|
ct_data_i : in std_ulogic_vector(31 downto 0); -- data in
|
58 |
|
|
ct_data_o : out std_ulogic_vector(31 downto 0); -- data out
|
59 |
|
|
ct_ack_o : out std_ulogic; -- transfer acknowledge
|
60 |
|
|
-- host access: instruction fetch access port (read-only) --
|
61 |
|
|
if_addr_i : in std_ulogic_vector(31 downto 0); -- address
|
62 |
|
|
if_rden_i : in std_ulogic; -- read enable
|
63 |
|
|
if_data_o : out std_ulogic_vector(31 downto 0); -- data out
|
64 |
|
|
if_ack_o : out std_ulogic; -- transfer acknowledge
|
65 |
|
|
-- status --
|
66 |
|
|
xip_en_o : out std_ulogic; -- XIP enable
|
67 |
|
|
xip_acc_o : out std_ulogic; -- pending XIP access
|
68 |
|
|
xip_page_o : out std_ulogic_vector(03 downto 0); -- XIP page
|
69 |
|
|
-- clock generator --
|
70 |
|
|
clkgen_en_o : out std_ulogic; -- enable clock generator
|
71 |
|
|
clkgen_i : in std_ulogic_vector(07 downto 0);
|
72 |
|
|
-- SPI device interface --
|
73 |
|
|
spi_csn_o : out std_ulogic; -- chip-select, low-active
|
74 |
|
|
spi_clk_o : out std_ulogic; -- serial clock
|
75 |
|
|
spi_data_i : in std_ulogic; -- device data output
|
76 |
|
|
spi_data_o : out std_ulogic -- controller data output
|
77 |
|
|
);
|
78 |
|
|
end neorv32_xip;
|
79 |
|
|
|
80 |
|
|
architecture neorv32_xip_rtl of neorv32_xip is
|
81 |
|
|
|
82 |
|
|
-- IO space: module base address --
|
83 |
|
|
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
|
84 |
|
|
constant lo_abb_c : natural := index_size_f(xip_size_c); -- low address boundary bit
|
85 |
|
|
|
86 |
|
|
-- CT register access control --
|
87 |
|
|
signal ct_acc_en : std_ulogic; -- module access enable
|
88 |
|
|
signal ct_addr : std_ulogic_vector(31 downto 0); -- access address
|
89 |
|
|
signal ct_wren : std_ulogic; -- word write enable
|
90 |
|
|
signal ct_rden : std_ulogic; -- read enable
|
91 |
|
|
|
92 |
|
|
-- control register --
|
93 |
|
|
constant ctrl_enable_c : natural := 0; -- r/w: module enable
|
94 |
|
|
constant ctrl_spi_prsc0_c : natural := 1; -- r/w: SPI clock prescaler select - bit 0
|
95 |
|
|
constant ctrl_spi_prsc1_c : natural := 2; -- r/w: SPI clock prescaler select - bit 1
|
96 |
|
|
constant ctrl_spi_prsc2_c : natural := 3; -- r/w: SPI clock prescaler select - bit 2
|
97 |
|
|
constant ctrl_spi_cpol_c : natural := 4; -- r/w: SPI (idle) clock polarity
|
98 |
|
|
constant ctrl_spi_cpha_c : natural := 5; -- r/w: SPI clock phase
|
99 |
|
|
constant ctrl_spi_nbytes0_c : natural := 6; -- r/w: SPI number of bytes in transmission (1..9) - bit 0
|
100 |
|
|
constant ctrl_spi_nbytes3_c : natural := 9; -- r/w: SPI number of bytes in transmission (1..9) - bit 3
|
101 |
|
|
constant ctrl_xip_enable_c : natural := 10; -- r/w: XIP access mode enable
|
102 |
|
|
constant ctrl_xip_abytes0_c : natural := 11; -- r/w: XIP number of address bytes (0=1,1=2,2=3,3=4) - bit 0
|
103 |
|
|
constant ctrl_xip_abytes1_c : natural := 12; -- r/w: XIP number of address bytes (0=1,1=2,2=3,3=4) - bit 1
|
104 |
|
|
constant ctrl_rd_cmd0_c : natural := 13; -- r/w: SPI flash read command - bit 0
|
105 |
|
|
constant ctrl_rd_cmd7_c : natural := 20; -- r/w: SPI flash read command - bit 7
|
106 |
|
|
constant ctrl_page0_c : natural := 21; -- r/w: XIP memory page - bit 0
|
107 |
|
|
constant ctrl_page3_c : natural := 24; -- r/w: XIP memory page - bit 3
|
108 |
|
|
constant ctrl_spi_csen_c : natural := 25; -- r/w: SPI chip-select enabled
|
109 |
|
|
constant ctrl_highspeed_c : natural := 26; -- r/w: SPI high-speed mode enable (ignoring ctrl_spi_prsc)
|
110 |
|
|
--
|
111 |
|
|
constant ctrl_phy_busy_c : natural := 30; -- r/-: SPI PHY is busy when set
|
112 |
|
|
constant ctrl_xip_busy_c : natural := 31; -- r/-: XIP access in progress
|
113 |
|
|
--
|
114 |
|
|
signal ctrl : std_ulogic_vector(26 downto 0);
|
115 |
|
|
|
116 |
|
|
-- Direct SPI access registers --
|
117 |
|
|
signal spi_data_lo : std_ulogic_vector(31 downto 0);
|
118 |
|
|
signal spi_data_hi : std_ulogic_vector(31 downto 0); -- write-only!
|
119 |
|
|
signal spi_trigger : std_ulogic; -- trigger direct SPI operation
|
120 |
|
|
|
121 |
|
|
-- XIP access address --
|
122 |
|
|
signal xip_addr : std_ulogic_vector(31 downto 0);
|
123 |
|
|
|
124 |
|
|
-- SPI access fetch arbiter --
|
125 |
|
|
type arbiter_state_t is (S_DIRECT, S_IDLE, S_TRIG, S_BUSY);
|
126 |
|
|
type arbiter_t is record
|
127 |
|
|
state : arbiter_state_t;
|
128 |
|
|
state_nxt : arbiter_state_t;
|
129 |
|
|
addr : std_ulogic_vector(31 downto 0);
|
130 |
|
|
busy : std_ulogic;
|
131 |
|
|
end record;
|
132 |
|
|
signal arbiter : arbiter_t;
|
133 |
|
|
|
134 |
|
|
-- SPI clock --
|
135 |
|
|
signal spi_clk_en : std_ulogic;
|
136 |
|
|
|
137 |
|
|
-- Component: SPI PHY --
|
138 |
|
|
component neorv32_xip_phy
|
139 |
|
|
port (
|
140 |
|
|
-- global control --
|
141 |
|
|
clk_i : in std_ulogic; -- clock
|
142 |
|
|
spi_clk_en_i : in std_ulogic; -- pre-scaled SPI clock-enable
|
143 |
|
|
-- operation configuration --
|
144 |
|
|
cf_enable_i : in std_ulogic; -- module enable (reset if low)
|
145 |
|
|
cf_cpha_i : in std_ulogic; -- clock phase
|
146 |
|
|
cf_cpol_i : in std_ulogic; -- clock idle polarity
|
147 |
|
|
-- operation control --
|
148 |
|
|
op_start_i : in std_ulogic; -- trigger new transmission
|
149 |
|
|
op_csen_i : in std_ulogic; -- actually enabled device for transmission
|
150 |
|
|
op_busy_o : out std_ulogic; -- transmission in progress when set
|
151 |
|
|
op_nbytes_i : in std_ulogic_vector(03 downto 0); -- actual number of bytes to transmit (1..9)
|
152 |
|
|
op_wdata_i : in std_ulogic_vector(71 downto 0); -- write data
|
153 |
|
|
op_rdata_o : out std_ulogic_vector(31 downto 0); -- read data
|
154 |
|
|
-- SPI interface --
|
155 |
|
|
spi_csn_o : out std_ulogic;
|
156 |
|
|
spi_clk_o : out std_ulogic;
|
157 |
|
|
spi_data_i : in std_ulogic;
|
158 |
|
|
spi_data_o : out std_ulogic
|
159 |
|
|
);
|
160 |
|
|
end component;
|
161 |
|
|
|
162 |
|
|
-- PHY interface --
|
163 |
|
|
type phy_if_t is record
|
164 |
|
|
start : std_ulogic; -- trigger new transmission
|
165 |
|
|
busy : std_ulogic; -- transmission in progress when set
|
166 |
|
|
wdata : std_ulogic_vector(71 downto 0); -- write data
|
167 |
|
|
rdata : std_ulogic_vector(31 downto 0); -- read data
|
168 |
|
|
end record;
|
169 |
|
|
signal phy_if : phy_if_t;
|
170 |
|
|
|
171 |
|
|
begin
|
172 |
|
|
|
173 |
|
|
-- Access Control (IO/CTRL port) ----------------------------------------------------------
|
174 |
|
|
-- -------------------------------------------------------------------------------------------
|
175 |
|
|
ct_acc_en <= '1' when (ct_addr_i(hi_abb_c downto lo_abb_c) = xip_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
176 |
|
|
ct_addr <= xip_base_c(31 downto lo_abb_c) & ct_addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
177 |
|
|
ct_wren <= ct_acc_en and ct_wren_i;
|
178 |
|
|
ct_rden <= ct_acc_en and ct_rden_i;
|
179 |
|
|
|
180 |
|
|
|
181 |
|
|
-- Control Read/Write Access --------------------------------------------------------------
|
182 |
|
|
-- -------------------------------------------------------------------------------------------
|
183 |
|
|
ctrl_rw_access : process(rstn_i, clk_i)
|
184 |
|
|
begin
|
185 |
|
|
if (rstn_i = '0') then
|
186 |
|
|
ctrl <= (others => '-');
|
187 |
|
|
ctrl(ctrl_enable_c) <= '0'; -- required
|
188 |
|
|
ctrl(ctrl_xip_enable_c) <= '0'; -- required
|
189 |
|
|
spi_data_lo <= (others => '-');
|
190 |
|
|
spi_data_hi <= (others => '-');
|
191 |
|
|
spi_trigger <= '-';
|
192 |
|
|
--
|
193 |
|
|
ct_data_o <= (others => '-');
|
194 |
|
|
ct_ack_o <= '-';
|
195 |
|
|
elsif rising_edge(clk_i) then
|
196 |
|
|
-- access acknowledge --
|
197 |
|
|
ct_ack_o <= ct_wren or ct_rden;
|
198 |
|
|
|
199 |
|
|
-- defaults --
|
200 |
|
|
spi_trigger <= '0';
|
201 |
|
|
|
202 |
|
|
-- write access --
|
203 |
|
|
if (ct_wren = '1') then -- only full-word writes!
|
204 |
|
|
|
205 |
|
|
-- control register --
|
206 |
|
|
if (ct_addr = xip_ctrl_addr_c) then
|
207 |
|
|
ctrl(ctrl_enable_c) <= ct_data_i(ctrl_enable_c);
|
208 |
|
|
ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ct_data_i(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
|
209 |
|
|
ctrl(ctrl_spi_cpol_c) <= ct_data_i(ctrl_spi_cpol_c);
|
210 |
|
|
ctrl(ctrl_spi_cpha_c) <= ct_data_i(ctrl_spi_cpha_c);
|
211 |
|
|
ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ct_data_i(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
|
212 |
|
|
ctrl(ctrl_xip_enable_c) <= ct_data_i(ctrl_xip_enable_c);
|
213 |
|
|
ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ct_data_i(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
|
214 |
|
|
ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ct_data_i(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
|
215 |
|
|
ctrl(ctrl_page3_c downto ctrl_page0_c) <= ct_data_i(ctrl_page3_c downto ctrl_page0_c);
|
216 |
|
|
ctrl(ctrl_spi_csen_c) <= ct_data_i(ctrl_spi_csen_c);
|
217 |
|
|
ctrl(ctrl_highspeed_c) <= ct_data_i(ctrl_highspeed_c);
|
218 |
|
|
end if;
|
219 |
|
|
|
220 |
|
|
-- SPI direct data access register lo --
|
221 |
|
|
if (ct_addr = xip_data_lo_addr_c) then
|
222 |
|
|
spi_data_lo <= ct_data_i;
|
223 |
|
|
end if;
|
224 |
|
|
|
225 |
|
|
-- SPI direct data access register hi --
|
226 |
|
|
if (ct_addr = xip_data_hi_addr_c) then
|
227 |
|
|
spi_data_hi <= ct_data_i;
|
228 |
|
|
spi_trigger <= '1'; -- trigger direct SPI transaction
|
229 |
|
|
end if;
|
230 |
|
|
end if;
|
231 |
|
|
|
232 |
|
|
-- read access --
|
233 |
|
|
ct_data_o <= (others => '0');
|
234 |
|
|
if (ct_rden = '1') then
|
235 |
|
|
case ct_addr(3 downto 2) is
|
236 |
|
|
when "00" => -- 'xip_ctrl_addr_c' - control register
|
237 |
|
|
ct_data_o(ctrl_enable_c) <= ctrl(ctrl_enable_c);
|
238 |
|
|
ct_data_o(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
|
239 |
|
|
ct_data_o(ctrl_spi_cpol_c) <= ctrl(ctrl_spi_cpol_c);
|
240 |
|
|
ct_data_o(ctrl_spi_cpha_c) <= ctrl(ctrl_spi_cpha_c);
|
241 |
|
|
ct_data_o(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
|
242 |
|
|
ct_data_o(ctrl_xip_enable_c) <= ctrl(ctrl_xip_enable_c);
|
243 |
|
|
ct_data_o(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
|
244 |
|
|
ct_data_o(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
|
245 |
|
|
ct_data_o(ctrl_page3_c downto ctrl_page0_c) <= ctrl(ctrl_page3_c downto ctrl_page0_c);
|
246 |
|
|
ct_data_o(ctrl_spi_csen_c) <= ctrl(ctrl_spi_csen_c);
|
247 |
|
|
ct_data_o(ctrl_highspeed_c) <= ctrl(ctrl_highspeed_c);
|
248 |
|
|
--
|
249 |
|
|
ct_data_o(ctrl_phy_busy_c) <= phy_if.busy;
|
250 |
|
|
ct_data_o(ctrl_xip_busy_c) <= arbiter.busy;
|
251 |
|
|
when "10" => -- 'xip_data_lo_addr_c' - SPI direct data access register lo
|
252 |
|
|
ct_data_o <= phy_if.rdata;
|
253 |
|
|
when others => -- unavailable (not implemented or write-only)
|
254 |
|
|
ct_data_o <= (others => '0');
|
255 |
|
|
end case;
|
256 |
|
|
end if;
|
257 |
|
|
end if;
|
258 |
|
|
end process ctrl_rw_access;
|
259 |
|
|
|
260 |
|
|
-- XIP enabled --
|
261 |
|
|
xip_en_o <= ctrl(ctrl_enable_c);
|
262 |
|
|
|
263 |
|
|
-- XIP page output --
|
264 |
|
|
xip_page_o <= ctrl(ctrl_page3_c downto ctrl_page0_c);
|
265 |
|
|
|
266 |
|
|
|
267 |
|
|
-- XIP Address Computation Logic ----------------------------------------------------------
|
268 |
|
|
-- -------------------------------------------------------------------------------------------
|
269 |
|
|
xip_access_logic: process(arbiter.addr, ctrl)
|
270 |
|
|
variable tmp_v : std_ulogic_vector(31 downto 0);
|
271 |
|
|
begin
|
272 |
|
|
tmp_v(31 downto 28) := "0000";
|
273 |
|
|
tmp_v(27 downto 00) := arbiter.addr(27 downto 00);
|
274 |
|
|
case ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) is -- shift address bits to be MSB-aligned
|
275 |
|
|
when "00" => xip_addr <= tmp_v(07 downto 0) & x"000000"; -- 1 address byte
|
276 |
|
|
when "01" => xip_addr <= tmp_v(15 downto 0) & x"0000"; -- 2 address bytes
|
277 |
|
|
when "10" => xip_addr <= tmp_v(23 downto 0) & x"00"; -- 3 address bytes
|
278 |
|
|
when others => xip_addr <= tmp_v(31 downto 0); -- 4 address bytes
|
279 |
|
|
end case;
|
280 |
|
|
end process xip_access_logic;
|
281 |
|
|
|
282 |
|
|
|
283 |
|
|
-- SPI Access Arbiter ---------------------------------------------------------------------
|
284 |
|
|
-- -------------------------------------------------------------------------------------------
|
285 |
|
|
arbiter_sync: process(clk_i)
|
286 |
|
|
begin
|
287 |
|
|
if rising_edge(clk_i) then
|
288 |
|
|
if (ctrl(ctrl_enable_c) = '0') or (ctrl(ctrl_xip_enable_c) = '0') then -- sync reset
|
289 |
|
|
arbiter.state <= S_DIRECT;
|
290 |
|
|
else
|
291 |
|
|
arbiter.state <= arbiter.state_nxt;
|
292 |
|
|
end if;
|
293 |
|
|
arbiter.addr <= if_addr_i; -- buffer address (reducing fan-out on CPU's address net)
|
294 |
|
|
end if;
|
295 |
|
|
end process arbiter_sync;
|
296 |
|
|
|
297 |
|
|
|
298 |
|
|
-- FSM - combinatorial part --
|
299 |
|
|
arbiter_comb: process(arbiter, ctrl, xip_addr, phy_if, if_rden_i, if_addr_i, spi_data_hi, spi_data_lo, spi_trigger)
|
300 |
|
|
begin
|
301 |
|
|
-- arbiter defaults --
|
302 |
|
|
arbiter.state_nxt <= arbiter.state;
|
303 |
|
|
|
304 |
|
|
-- bus interface defaults --
|
305 |
|
|
if_data_o <= (others => '0');
|
306 |
|
|
if_ack_o <= '0';
|
307 |
|
|
|
308 |
|
|
-- SPI PHY interface defaults --
|
309 |
|
|
phy_if.start <= '0';
|
310 |
|
|
phy_if.wdata <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) & xip_addr & x"00000000"; -- MSB-aligned: CMD + address + 32-bit zero data
|
311 |
|
|
|
312 |
|
|
-- fsm --
|
313 |
|
|
case arbiter.state is
|
314 |
|
|
|
315 |
|
|
when S_DIRECT => -- XIP access disabled: allow direct SPI access
|
316 |
|
|
-- ------------------------------------------------------------
|
317 |
|
|
phy_if.wdata <= spi_data_hi & spi_data_lo & x"00"; -- MSB-aligned data
|
318 |
|
|
phy_if.start <= spi_trigger;
|
319 |
|
|
arbiter.state_nxt <= S_IDLE;
|
320 |
|
|
|
321 |
|
|
when S_IDLE => -- XIP: wait for new bus request
|
322 |
|
|
-- ------------------------------------------------------------
|
323 |
|
|
if (if_rden_i = '1') and (if_addr_i(31 downto 28) = ctrl(ctrl_page3_c downto ctrl_page0_c)) then
|
324 |
|
|
arbiter.state_nxt <= S_TRIG;
|
325 |
|
|
end if;
|
326 |
|
|
|
327 |
|
|
when S_TRIG => -- XIP: trigger flash read
|
328 |
|
|
-- ------------------------------------------------------------
|
329 |
|
|
phy_if.start <= '1';
|
330 |
|
|
arbiter.state_nxt <= S_BUSY;
|
331 |
|
|
|
332 |
|
|
when S_BUSY => -- XIP: wait for PHY to complete operation
|
333 |
|
|
-- ------------------------------------------------------------
|
334 |
|
|
if (phy_if.busy = '0') then
|
335 |
|
|
if_data_o <= phy_if.rdata;
|
336 |
|
|
if_ack_o <= '1';
|
337 |
|
|
arbiter.state_nxt <= S_IDLE;
|
338 |
|
|
end if;
|
339 |
|
|
|
340 |
|
|
when others => -- undefined
|
341 |
|
|
-- ------------------------------------------------------------
|
342 |
|
|
arbiter.state_nxt <= S_IDLE;
|
343 |
|
|
|
344 |
|
|
end case;
|
345 |
|
|
end process arbiter_comb;
|
346 |
|
|
|
347 |
|
|
-- arbiter status --
|
348 |
|
|
arbiter.busy <= '1' when (arbiter.state = S_TRIG) or (arbiter.state = S_BUSY) else '0'; -- actual XIP access in progress
|
349 |
|
|
|
350 |
|
|
-- status output --
|
351 |
|
|
xip_acc_o <= arbiter.busy;
|
352 |
|
|
|
353 |
|
|
|
354 |
|
|
-- SPI Clock Generator --------------------------------------------------------------------
|
355 |
|
|
-- -------------------------------------------------------------------------------------------
|
356 |
|
|
-- enable clock generator --
|
357 |
|
|
clkgen_en_o <= ctrl(ctrl_enable_c);
|
358 |
|
|
|
359 |
|
|
-- clock select --
|
360 |
|
|
spi_clk_en <= clkgen_i(to_integer(unsigned(ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c)))) or ctrl(ctrl_highspeed_c);
|
361 |
|
|
|
362 |
|
|
|
363 |
|
|
-- SPI Physical Interface -----------------------------------------------------------------
|
364 |
|
|
-- -------------------------------------------------------------------------------------------
|
365 |
|
|
neorv32_xip_phy_inst: neorv32_xip_phy
|
366 |
|
|
port map (
|
367 |
|
|
-- global control --
|
368 |
|
|
clk_i => clk_i,
|
369 |
|
|
spi_clk_en_i => spi_clk_en,
|
370 |
|
|
-- operation configuration --
|
371 |
|
|
cf_enable_i => ctrl(ctrl_enable_c), -- module enable (reset if low)
|
372 |
|
|
cf_cpha_i => ctrl(ctrl_spi_cpha_c), -- clock phase
|
373 |
|
|
cf_cpol_i => ctrl(ctrl_spi_cpol_c), -- clock idle polarity
|
374 |
|
|
-- operation control --
|
375 |
|
|
op_start_i => phy_if.start, -- trigger new transmission
|
376 |
|
|
op_csen_i => ctrl(ctrl_spi_csen_c), -- actually enabled device for transmission
|
377 |
|
|
op_busy_o => phy_if.busy, -- transmission in progress when set
|
378 |
|
|
op_nbytes_i => ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c), -- actual number of bytes to transmit
|
379 |
|
|
op_wdata_i => phy_if.wdata, -- write data
|
380 |
|
|
op_rdata_o => phy_if.rdata, -- read data
|
381 |
|
|
-- SPI interface --
|
382 |
|
|
spi_csn_o => spi_csn_o,
|
383 |
|
|
spi_clk_o => spi_clk_o,
|
384 |
|
|
spi_data_i => spi_data_i,
|
385 |
|
|
spi_data_o => spi_data_o
|
386 |
|
|
);
|
387 |
|
|
|
388 |
|
|
|
389 |
|
|
end neorv32_xip_rtl;
|
390 |
|
|
|
391 |
|
|
|
392 |
|
|
-- ############################################################################################################################
|
393 |
|
|
-- ############################################################################################################################
|
394 |
|
|
|
395 |
|
|
|
396 |
|
|
-- #################################################################################################
|
397 |
|
|
-- # << NEORV32 - XIP Module - SPI Physical Interface >> #
|
398 |
|
|
-- # ********************************************************************************************* #
|
399 |
|
|
-- # BSD 3-Clause License #
|
400 |
|
|
-- # #
|
401 |
|
|
-- # Copyright (c) 2022, Stephan Nolting. All rights reserved. #
|
402 |
|
|
-- # #
|
403 |
|
|
-- # Redistribution and use in source and binary forms, with or without modification, are #
|
404 |
|
|
-- # permitted provided that the following conditions are met: #
|
405 |
|
|
-- # #
|
406 |
|
|
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
407 |
|
|
-- # conditions and the following disclaimer. #
|
408 |
|
|
-- # #
|
409 |
|
|
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
|
410 |
|
|
-- # conditions and the following disclaimer in the documentation and/or other materials #
|
411 |
|
|
-- # provided with the distribution. #
|
412 |
|
|
-- # #
|
413 |
|
|
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
|
414 |
|
|
-- # endorse or promote products derived from this software without specific prior written #
|
415 |
|
|
-- # permission. #
|
416 |
|
|
-- # #
|
417 |
|
|
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
|
418 |
|
|
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
|
419 |
|
|
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
|
420 |
|
|
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
421 |
|
|
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
|
422 |
|
|
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
|
423 |
|
|
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
424 |
|
|
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
|
425 |
|
|
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
|
426 |
|
|
-- # ********************************************************************************************* #
|
427 |
|
|
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
|
428 |
|
|
-- #################################################################################################
|
429 |
|
|
|
430 |
|
|
library ieee;
|
431 |
|
|
use ieee.std_logic_1164.all;
|
432 |
|
|
use ieee.numeric_std.all;
|
433 |
|
|
|
434 |
|
|
library neorv32;
|
435 |
|
|
use neorv32.neorv32_package.all;
|
436 |
|
|
|
437 |
|
|
entity neorv32_xip_phy is
|
438 |
|
|
port (
|
439 |
|
|
-- global control --
|
440 |
|
|
clk_i : in std_ulogic; -- clock
|
441 |
|
|
spi_clk_en_i : in std_ulogic; -- pre-scaled SPI clock-enable
|
442 |
|
|
-- operation configuration --
|
443 |
|
|
cf_enable_i : in std_ulogic; -- module enable (reset if low)
|
444 |
|
|
cf_cpha_i : in std_ulogic; -- clock phase
|
445 |
|
|
cf_cpol_i : in std_ulogic; -- clock idle polarity
|
446 |
|
|
-- operation control --
|
447 |
|
|
op_start_i : in std_ulogic; -- trigger new transmission
|
448 |
|
|
op_csen_i : in std_ulogic; -- actually enabled device for transmission
|
449 |
|
|
op_busy_o : out std_ulogic; -- transmission in progress when set
|
450 |
|
|
op_nbytes_i : in std_ulogic_vector(03 downto 0); -- actual number of bytes to transmit (1..9)
|
451 |
|
|
op_wdata_i : in std_ulogic_vector(71 downto 0); -- write data
|
452 |
|
|
op_rdata_o : out std_ulogic_vector(31 downto 0); -- read data
|
453 |
|
|
-- SPI interface --
|
454 |
|
|
spi_csn_o : out std_ulogic;
|
455 |
|
|
spi_clk_o : out std_ulogic;
|
456 |
|
|
spi_data_i : in std_ulogic;
|
457 |
|
|
spi_data_o : out std_ulogic
|
458 |
|
|
);
|
459 |
|
|
end neorv32_xip_phy;
|
460 |
|
|
|
461 |
|
|
architecture neorv32_xip_phy_rtl of neorv32_xip_phy is
|
462 |
|
|
|
463 |
|
|
-- controller --
|
464 |
|
|
type ctrl_state_t is (S_IDLE, S_START, S_RTX_A, S_RTX_B, S_DONE);
|
465 |
|
|
type ctrl_t is record
|
466 |
|
|
state : ctrl_state_t;
|
467 |
|
|
sreg : std_ulogic_vector(71 downto 0); -- only the lowest 32-bit are used as RX data
|
468 |
|
|
bitcnt : std_ulogic_vector(06 downto 0);
|
469 |
|
|
di_sync : std_ulogic;
|
470 |
|
|
csen : std_ulogic;
|
471 |
|
|
end record;
|
472 |
|
|
signal ctrl : ctrl_t;
|
473 |
|
|
|
474 |
|
|
begin
|
475 |
|
|
|
476 |
|
|
-- Serial Interface Control Unit ----------------------------------------------------------
|
477 |
|
|
-- -------------------------------------------------------------------------------------------
|
478 |
|
|
control_unit: process(clk_i)
|
479 |
|
|
begin
|
480 |
|
|
if rising_edge(clk_i) then
|
481 |
|
|
if (cf_enable_i = '0') then
|
482 |
|
|
spi_clk_o <= '0';
|
483 |
|
|
spi_csn_o <= '1';
|
484 |
|
|
--
|
485 |
|
|
ctrl.state <= S_IDLE;
|
486 |
|
|
ctrl.csen <= '-';
|
487 |
|
|
ctrl.sreg <= (others => '-');
|
488 |
|
|
ctrl.bitcnt <= (others => '-');
|
489 |
|
|
ctrl.di_sync <= '-';
|
490 |
|
|
else
|
491 |
|
|
-- defaults --
|
492 |
|
|
spi_clk_o <= cf_cpol_i;
|
493 |
|
|
spi_csn_o <= '1'; -- de-selected by default
|
494 |
|
|
ctrl.di_sync <= spi_data_i;
|
495 |
|
|
|
496 |
|
|
-- fsm --
|
497 |
|
|
case ctrl.state is
|
498 |
|
|
|
499 |
|
|
when S_IDLE => -- wait for new transmission trigger
|
500 |
|
|
-- ------------------------------------------------------------
|
501 |
|
|
ctrl.bitcnt <= op_nbytes_i & "000"; -- number of bytes
|
502 |
|
|
ctrl.csen <= op_csen_i;
|
503 |
|
|
if (op_start_i = '1') then
|
504 |
|
|
ctrl.sreg <= op_wdata_i;
|
505 |
|
|
ctrl.state <= S_START;
|
506 |
|
|
end if;
|
507 |
|
|
|
508 |
|
|
when S_START => -- sync start of transmission
|
509 |
|
|
-- ------------------------------------------------------------
|
510 |
|
|
spi_csn_o <= not ctrl.csen;
|
511 |
|
|
if (spi_clk_en_i = '1') then
|
512 |
|
|
ctrl.state <= S_RTX_A;
|
513 |
|
|
end if;
|
514 |
|
|
|
515 |
|
|
when S_RTX_A => -- first half of bit transmission
|
516 |
|
|
-- ------------------------------------------------------------
|
517 |
|
|
spi_csn_o <= not ctrl.csen;
|
518 |
|
|
spi_clk_o <= cf_cpha_i xor cf_cpol_i;
|
519 |
|
|
if (spi_clk_en_i = '1') then
|
520 |
|
|
ctrl.bitcnt <= std_ulogic_vector(unsigned(ctrl.bitcnt) - 1);
|
521 |
|
|
ctrl.state <= S_RTX_B;
|
522 |
|
|
end if;
|
523 |
|
|
|
524 |
|
|
when S_RTX_B => -- second half of bit transmission
|
525 |
|
|
-- ------------------------------------------------------------
|
526 |
|
|
spi_csn_o <= not ctrl.csen;
|
527 |
|
|
spi_clk_o <= not (cf_cpha_i xor cf_cpol_i);
|
528 |
|
|
if (spi_clk_en_i = '1') then
|
529 |
|
|
ctrl.sreg <= ctrl.sreg(ctrl.sreg'left-1 downto 0) & ctrl.di_sync;
|
530 |
|
|
if (or_reduce_f(ctrl.bitcnt) = '0') then -- all bits transferred?
|
531 |
|
|
ctrl.state <= S_DONE; -- transmission done
|
532 |
|
|
else
|
533 |
|
|
ctrl.state <= S_RTX_A; -- next bit
|
534 |
|
|
end if;
|
535 |
|
|
end if;
|
536 |
|
|
|
537 |
|
|
when S_DONE => -- transmission done
|
538 |
|
|
-- ------------------------------------------------------------
|
539 |
|
|
spi_csn_o <= not ctrl.csen;
|
540 |
|
|
if (spi_clk_en_i = '1') then
|
541 |
|
|
ctrl.state <= S_IDLE;
|
542 |
|
|
end if;
|
543 |
|
|
|
544 |
|
|
when others => -- undefined
|
545 |
|
|
-- ------------------------------------------------------------
|
546 |
|
|
ctrl.state <= S_IDLE;
|
547 |
|
|
|
548 |
|
|
end case;
|
549 |
|
|
end if;
|
550 |
|
|
end if;
|
551 |
|
|
end process control_unit;
|
552 |
|
|
|
553 |
|
|
-- serial unit busy --
|
554 |
|
|
op_busy_o <= '0' when (ctrl.state = S_IDLE) else '1';
|
555 |
|
|
|
556 |
|
|
-- serial data output --
|
557 |
|
|
spi_data_o <= ctrl.sreg(ctrl.sreg'left);
|
558 |
|
|
|
559 |
|
|
-- RX data --
|
560 |
|
|
op_rdata_o <= ctrl.sreg(31 downto 0);
|
561 |
|
|
|
562 |
|
|
|
563 |
|
|
end neorv32_xip_phy_rtl;
|