SURF  1.0
AxiSpiMaster.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : AxiSpiMaster.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2015-01-12
5 -- Last update: 2017-07-10
6 -------------------------------------------------------------------------------
7 -- Description: Axi lite interface for a single chip "generic SPI master"
8 -- For multiple chips on single bus connect multiple cores
9 -- to multiple AXI crossbar slaves and use Chip select outputs
10 -- (coreCsb) to multiplex select the addressed outputs (coreSDout and
11 -- coreSclk).
12 -- The coreCsb is active low. And active only if the corresponding
13 -- Axi Crossbar Slave is addressed.
14 -- DATA_SIZE_G - Corresponds to total read or write command size (not just data size).
15 -- Example: DATA_SIZE_G = 24
16 -- 1-bit command, 15-bit address word and 8-bit data
17 -------------------------------------------------------------------------------
18 -- This file is part of 'SLAC Firmware Standard Library'.
19 -- It is subject to the license terms in the LICENSE.txt file found in the
20 -- top-level directory of this distribution and at:
21 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
22 -- No part of 'SLAC Firmware Standard Library', including this file,
23 -- may be copied, modified, propagated, or distributed except according to
24 -- the terms contained in the LICENSE.txt file.
25 -------------------------------------------------------------------------------
26 
27 library ieee;
28 use ieee.std_logic_1164.all;
29 use ieee.std_logic_arith.all;
30 use ieee.std_logic_unsigned.all;
31 
32 library unisim;
33 use unisim.vcomponents.all;
34 
35 use work.StdRtlPkg.all;
36 use work.AxiLitePkg.all;
37 
38 --! @see entity
39  --! @ingroup protocols_spi
40 entity AxiSpiMaster is
41  generic (
42  TPD_G : time := 1 ns;
44  ADDRESS_SIZE_G : natural := 15;
45  DATA_SIZE_G : natural := 8;
46  MODE_G : string := "RW"; -- Or "WO" (write only), "RO" (read only)
47  CPHA_G : sl := '0';
48  CPOL_G : sl := '0';
49  CLK_PERIOD_G : real := 6.4E-9;
50  SPI_SCLK_PERIOD_G : real := 100.0E-6;
51  SPI_NUM_CHIPS_G : positive := 1
52  );
53  port (
54  axiClk : in sl;
55  axiRst : in sl;
56 
61 
62  coreSclk : out sl;
63  coreSDin : in sl;
64  coreSDout : out sl;
65  coreCsb : out sl; -- coreCsb is for legacy firmware without SPI_NUM_CHIPS_G generic
66  coreMCsb : out slv(SPI_NUM_CHIPS_G-1 downto 0)
67  );
68 end entity AxiSpiMaster;
69 
70 architecture rtl of AxiSpiMaster is
71 
72  -- AdcCore Outputs
73  constant PACKET_SIZE_C : positive := ite(MODE_G = "RW", 1, 0) + ADDRESS_SIZE_G + DATA_SIZE_G; -- "1+" For R/W command bit
74  constant CHIP_BITS_C : integer := log2(SPI_NUM_CHIPS_G);
75 
76  signal rdData : slv(PACKET_SIZE_C-1 downto 0);
77  signal rdEn : sl;
78 
79  type StateType is (WAIT_AXI_TXN_S, WAIT_CYCLE_S, WAIT_SPI_TXN_DONE_S);
80 
81  -- Registers
82  type RegType is record
83  state : StateType;
86  -- Adc Core Inputs
87  wrData : slv(PACKET_SIZE_C-1 downto 0);
88  chipSel : slv(CHIP_BITS_C-1 downto 0);
89  wrEn : sl;
90  end record RegType;
91 
92  constant REG_INIT_C : RegType := (
93  state => WAIT_AXI_TXN_S,
96  wrData => (others => '0'),
97  chipSel => (others => '0'),
98  wrEn => '0');
99 
100  signal r : RegType := REG_INIT_C;
101  signal rin : RegType;
102  signal csb : slv(SPI_NUM_CHIPS_G-1 downto 0);
103 
104 begin
105 
106  comb : process (axiReadMaster, axiRst, axiWriteMaster, r, rdData, rdEn) is
107  variable v : RegType;
108  variable axiStatus : AxiLiteStatusType;
109  begin
110  v := r;
111 
113 
114  case (r.state) is
115  when WAIT_AXI_TXN_S =>
116 
117  if (axiStatus.writeEnable = '1') then
118  if (MODE_G = "RO") then
119  axiSlaveWriteResponse(v.axiWriteSlave, AXI_ERROR_RESP_G);
120  else
121 
122  -- No write bit when mode is write-only
123  if (MODE_G /= "WO") then
124  v.wrData(PACKET_SIZE_C-1) := '0';
125  end if;
126 
127  -- Address (make sure that the assigned AXI address in the crossbar is big enough)
128  if (ADDRESS_SIZE_G > 0) then
129  v.wrData(DATA_SIZE_G+ADDRESS_SIZE_G-1 downto DATA_SIZE_G) := axiWriteMaster.awaddr(2+ADDRESS_SIZE_G-1 downto 2);
130  end if;
131  -- Data
132  v.wrData(DATA_SIZE_G-1 downto 0) := axiWriteMaster.wdata(DATA_SIZE_G-1 downto 0);
133  -- Chip select
134  v.chipSel := axiWriteMaster.awaddr(SPI_NUM_CHIPS_G+ADDRESS_SIZE_G+1 downto 2+ADDRESS_SIZE_G);
135  v.wrEn := '1';
136  v.state := WAIT_CYCLE_S;
137  end if;
138  end if;
139 
140  if (axiStatus.readEnable = '1') then
141  if (MODE_G = "WO") then
142  axiSlaveReadResponse(v.axiReadSlave, AXI_ERROR_RESP_G);
143  else
144 
145  -- No read bit when mode is read-only
146  if (MODE_G /= "RO") then
147  v.wrData(PACKET_SIZE_C-1) := '1';
148  end if;
149 
150  -- Address
151  if (ADDRESS_SIZE_G > 0) then
152  v.wrData(DATA_SIZE_G+ADDRESS_SIZE_G-1 downto DATA_SIZE_G) := axiReadMaster.araddr(2+ADDRESS_SIZE_G-1 downto 2);
153  -- Setting data segment to all 1 allows it to float so that slave side can drive it
154  -- in shared sdio configurations
155  v.wrData(DATA_SIZE_G-1 downto 0) := (others => '1');
156  end if;
157 
158  -- If there are no address bits, readback will reuse the last wrData when shifting
159  v.chipSel := axiReadMaster.araddr(SPI_NUM_CHIPS_G+ADDRESS_SIZE_G+1 downto 2+ADDRESS_SIZE_G);
160  v.wrEn := '1';
161  v.state := WAIT_CYCLE_S;
162  end if;
163  end if;
164 
165  when WAIT_CYCLE_S =>
166  -- Wait for rdEn to drop
167  if (rdEn = '0') then
168  v.wrEn := '0';
169  v.state := WAIT_SPI_TXN_DONE_S;
170  end if;
171 
172  when WAIT_SPI_TXN_DONE_S =>
173 
174  if (rdEn = '1') then
175  v.state := WAIT_AXI_TXN_S;
176  if (r.wrData(PACKET_SIZE_C-1) = '0') then
177  -- Finish write
178  axiSlaveWriteResponse(v.axiWriteSlave);
179  else
180  -- Finish read
181  v.axiReadSlave.rdata := (others => '0');
182  v.axiReadSlave.rdata(DATA_SIZE_G-1 downto 0) := rdData(DATA_SIZE_G-1 downto 0);
183  axiSlaveReadResponse(v.axiReadSlave);
184  end if;
185  end if;
186 
187  when others => null;
188  end case;
189 
190  -- Check if single access
191  if (SPI_NUM_CHIPS_G = 1) then
192  v.chipSel := (others => '0');
193  end if;
194 
195  if (axiRst = '1') then
196  v := REG_INIT_C;
197  end if;
198 
199  rin <= v;
200 
203 
204  end process comb;
205 
206  seq : process (axiClk) is
207  begin
208  if (rising_edge(axiClk)) then
209  r <= rin after TPD_G;
210  end if;
211  end process seq;
212 
213  SpiMaster_1 : entity work.SpiMaster
214  generic map (
215  TPD_G => TPD_G,
217  DATA_SIZE_G => PACKET_SIZE_C,
218  CPHA_G => CPHA_G,
219  CPOL_G => CPOL_G,
222  port map (
223  clk => axiClk,
224  sRst => axiRst,
225  chipSel => r.chipSel,
226  wrEn => r.wrEn,
227  wrData => r.wrData,
228  rdEn => rdEn,
229  rdData => rdData,
230  spiCsL => csb,
231  spiSclk => coreSclk,
232  spiSdi => coreSDout,
233  spiSdo => coreSDin);
234 
235  coreCsb <= csb(0);
236  coreMCsb <= csb;
237 
238 end architecture rtl;
out axiReadSlaveAxiLiteReadSlaveType
_library_ unisimunisim
in axiWriteMasterAxiLiteWriteMasterType
out spiCsLslv( NUM_CHIPS_G- 1 downto 0)
Definition: SpiMaster.vhd:49
in wrDataslv( DATA_SIZE_G- 1 downto 0)
Definition: SpiMaster.vhd:43
in axiReadMasterAxiLiteReadMasterType
MODE_Gstring := "RW"
CLK_PERIOD_Greal := 6.4E-9
_library_ ieeeieee
out coreSDoutsl
AxiLiteWriteMasterType
Definition: AxiLitePkg.vhd:111
std_logic sl
Definition: StdRtlPkg.vhd:28
out rdDataslv( DATA_SIZE_G- 1 downto 0)
Definition: SpiMaster.vhd:46
slv( 31 downto 0) rdata
Definition: AxiLitePkg.vhd:89
SPI_NUM_CHIPS_Gpositive := 1
in wrEnsl
Definition: SpiMaster.vhd:42
SPI_SCLK_PERIOD_Greal := 1.0E-6
Definition: SpiMaster.vhd:35
TPD_Gtime := 1 ns
slv( 31 downto 0) wdata
Definition: AxiLitePkg.vhd:117
AXI_ERROR_RESP_Gslv( 1 downto 0) := AXI_RESP_DECERR_C
CPOL_Gsl := '0'
AxiLiteStatusType axiStatus
Definition: AxiLitePkg.vhd:183
out rdEnsl
Definition: SpiMaster.vhd:45
in chipSelslv( log2(NUM_CHIPS_G )- 1 downto 0)
Definition: SpiMaster.vhd:41
CPHA_Gsl := '0'
Definition: SpiMaster.vhd:32
in spiSdosl
Definition: SpiMaster.vhd:52
CPOL_Gsl := '0'
Definition: SpiMaster.vhd:33
slv( 1 downto 0) := "11" AXI_RESP_DECERR_C
Definition: AxiLitePkg.vhd:49
out coreSclksl
TPD_Gtime := 1 ns
Definition: SpiMaster.vhd:29
CPHA_Gsl := '0'
AxiLiteReadMasterType
Definition: AxiLitePkg.vhd:59
DATA_SIZE_Gnatural := 8
NUM_CHIPS_Gpositive range 1 to 8:= 4
Definition: SpiMaster.vhd:30
slv( 31 downto 0) awaddr
Definition: AxiLitePkg.vhd:113
ADDRESS_SIZE_Gnatural := 15
AxiLiteReadSlaveType :=(arready => '0',rdata =>( others => '0'),rresp =>( others => '0'),rvalid => '0') AXI_LITE_READ_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:95
SPI_SCLK_PERIOD_Greal := 100.0E-6
out coreCsbsl
AxiLiteReadSlaveType
Definition: AxiLitePkg.vhd:85
out spiSclksl
Definition: SpiMaster.vhd:50
DATA_SIZE_Gnatural := 16
Definition: SpiMaster.vhd:31
out spiSdisl
Definition: SpiMaster.vhd:51
out coreMCsbslv( SPI_NUM_CHIPS_G- 1 downto 0)
out axiWriteSlaveAxiLiteWriteSlaveType
slv( 31 downto 0) araddr
Definition: AxiLitePkg.vhd:61
in clksl
Definition: SpiMaster.vhd:38
in sRstsl
Definition: SpiMaster.vhd:39
CLK_PERIOD_Greal := 8.0E-9
Definition: SpiMaster.vhd:34
AxiLiteWriteSlaveType :=(awready => '0',wready => '0',bresp =>( others => '0'),bvalid => '0') AXI_LITE_WRITE_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:156
std_logic_vector slv
Definition: StdRtlPkg.vhd:29