SURF  1.0
SaciMaster.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : SaciMaster.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2012-08-10
5 -- Last update: 2013-03-01
6 -------------------------------------------------------------------------------
7 -- Description: Saci Master Module
8 -------------------------------------------------------------------------------
9 -- This file is part of 'SLAC Firmware Standard Library'.
10 -- It is subject to the license terms in the LICENSE.txt file found in the
11 -- top-level directory of this distribution and at:
12 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
13 -- No part of 'SLAC Firmware Standard Library', including this file,
14 -- may be copied, modified, propagated, or distributed except according to
15 -- the terms contained in the LICENSE.txt file.
16 -------------------------------------------------------------------------------
17 
18 library IEEE;
19 use IEEE.std_logic_1164.all;
20 use ieee.numeric_std.all;
21 
22 use work.StdRtlPkg.all;
23 use work.SaciMasterPkg.all;
24 
25 --! @see entity
26  --! @ingroup protocols_saci
27 entity SaciMaster is
28 
29  generic (
30  TPD_G : time := 1 ns;
31  SYNCHRONIZE_CONTROL_G : boolean := true);
32 
33  port (
34  clk : in sl; -- Main clock
35  rst : in sl;
36 
37  -- Serial interface
38  saciClk : out sl;
39  saciSelL : out slv(SACI_NUM_SLAVES_C-1 downto 0);
40  saciCmd : out sl;
41  saciRsp : in sl;
42 
43  -- Parallel interface
46 
47 end entity SaciMaster;
48 
49 architecture rtl of SaciMaster is
50 
51  type SynchronizerType is record
52  tmp : sl;
53  sync : sl;
54  last : sl;
55  end record;
56 
57  type SynchronizerArray is array (natural range <>) of SynchronizerType;
58 
59  constant SYNCHRONIZER_INIT_0_C : SynchronizerType := (tmp => '0', sync => '0', last => '0');
60  constant SYNCHRONIZER_INIT_1_C : SynchronizerType := (tmp => '1', sync => '1', last => '1');
61 
62  procedure synchronize (
63  input : in sl;
64  current : in SynchronizerType;
65  nextOut : out SynchronizerType) is
66  begin
67  nextOut.tmp := input;
68  nextOut.sync := current.tmp;
69  nextOut.last := current.sync;
70  end procedure;
71 
72  -- Simplified. Can be used when v := r has already been called.
73  procedure synchronize (
74  var : inout SynchronizerType;
75  input : in sl) is
76  begin
77  var.last := var.sync;
78  var.sync := var.tmp;
79  var.tmp := input;
80  end procedure synchronize;
81 
82  procedure synchronize (
83  input : in slv;
84  current : in SynchronizerArray;
85  nextOut : out SynchronizerArray) is
86  begin
87  for i in input'range loop
88  synchronize(input(i), current(i), nextOut(i));
89  end loop;
90  end procedure;
91 
92  -- Simplified. Can be used when v := r has already been called.
93  procedure synchronize (
94  var : inout SynchronizerArray;
95  input : in slv) is
96  begin
97  for i in input'range loop
98  synchronize(var(i), input(i));
99  end loop;
100  end procedure synchronize;
101 
102  procedure shiftInLeft (
103  i : in sl;
104  r : in slv;
105  v : out slv) is
106  begin
107  if (r'ascending) then
108  v := r(r'low+1 to r'high) & i;
109  else
110  v := r(r'high-1 downto r'low) & i;
111  end if;
112  end procedure shiftInLeft;
113 
114  type StateType is (IDLE_S, CHIP_SELECT_S, TX_S, RX_START_S, RX_HEADER_S, RX_DATA_S, ACK_S);
115 
116  type RegType is record
117  reqSync : SynchronizerType;
118  resetSync : SynchronizerType;
119  state : StateType;
120  shiftReg : slv(52 downto 0);
121  shiftCount : unsigned(5 downto 0);
122 
123  saciSelL : slv(SACI_NUM_SLAVES_C-1 downto 0);
124  saciCmd : sl;
126  end record RegType;
127 
128  signal r, rin : RegType;
129  signal saciRspFall : sl;
130 
131 begin
132 
133  saciClk <= '0' when r.state = IDLE_S and r.reqSync.sync = '0' else
134  clk;
135 
136  --------------------------------------------------------------------------------------------------
137  -- Capture serial input on falling edge of clock
138  --------------------------------------------------------------------------------------------------
139  fall : process (clk, rst) is
140  begin
141  if (rst = '1') then
142  saciRspFall <= '0' after TPD_G;
143  elsif (falling_edge(clk)) then
144  saciRspFall <= saciRsp after TPD_G;
145  end if;
146  end process fall;
147 
148  seq : process (clk, rst) is
149  begin
150  if (rst = '1') then
151  r.reqSync <= SYNCHRONIZER_INIT_0_C after TPD_G;
152  r.resetSync <= SYNCHRONIZER_INIT_0_C after TPD_G;
153  r.state <= IDLE_S after TPD_G;
154  r.shiftReg <= (others => '0') after TPD_G;
155  r.shiftCount <= (others => '0') after TPD_G;
156  r.saciSelL <= (others => '1') after TPD_G;
157  r.saciCmd <= '0' after TPD_G;
158  r.saciMasterOut.ack <= '0' after TPD_G;
159  r.saciMasterOut.fail <= '0' after TPD_G;
160  r.saciMasterOut.rdData <= (others => '0') after TPD_G;
161  elsif (rising_edge(clk)) then
162  r <= rin after TPD_G;
163  end if;
164  end process seq;
165 
166  comb : process (r, saciRspFall, saciMasterIn) is
167  variable rVar : RegType;
168  variable reqVar : sl;
169  variable resetVar : sl;
170  begin
171  rVar := r;
172 
173 
174  -- Synchronize control inputs to serial clock
175  synchronize(saciMasterIn.req, r.reqSync, rVar.reqSync);
176  synchronize(saciMasterIn.reset, r.resetSync, rVar.resetSync);
177  if (SYNCHRONIZE_CONTROL_G) then
178  reqVar := r.reqSync.sync;
179  resetVar := r.resetSync.sync;
180  else
181  reqVar := saciMasterIn.req;
182  resetVar := saciMasterIn.reset;
183  end if;
184 
185  rVar.shiftCount := (others => '0');
186  rVar.saciMasterOut.ack := '0';
187 
188  if (resetVar = '1') then
189  rVar.saciSelL := (others => '1');
190  rVar.shiftReg := (others => '0');
191  rVar.shiftCount := (others => '0');
192  rVar.state := IDLE_S;
193  rVar.saciMasterOut.ack := '1';
194  else
195 
196  case (r.state) is
197  when IDLE_S =>
198  rVar.saciMasterOut.fail := '0';
199  rVar.saciSelL := (others => '1');
200  rVar.shiftReg := (others => '0');
201  rVar.shiftCount := (others => '0');
202  if (reqVar = '1') then
203  -- New command, load shift reg
204  rVar.shiftReg(52) := '1'; -- Start bit
205  rVar.shiftReg(51) := saciMasterIn.op;
206  rVar.shiftReg(50 downto 44) := saciMasterIn.cmd;
207  rVar.shiftReg(43 downto 32) := saciMasterIn.addr;
208  if (saciMasterIn.op = '1') then
209  rVar.shiftReg(31 downto 0) := saciMasterIn.wrData;
210  else
211  rVar.shiftReg(31 downto 0) := (others => '0');
212  end if;
213  rVar.state := CHIP_SELECT_S;
214  end if;
215 
216  when CHIP_SELECT_S =>
217  rVar.saciSelL := (others => '1');
218  rVar.saciSelL(to_integer(unsigned(saciMasterIn.chip))) := '0';
219  rVar.state := TX_S;
220 
221  when TX_S =>
222  -- Shift out data on saciCmd
223  rVar.saciCmd := r.shiftReg(52);
224  rVar.shiftReg := r.shiftReg(51 downto 0) & '0';
225  rVar.shiftCount := r.shiftCount + 1;
226  if (saciMasterIn.op = '0' and r.shiftCount = 21) then -- Read
227  rVar.state := RX_START_S;
228  elsif (saciMasterIn.op = '1' and r.shiftCount = 53) then -- Write
229  rVar.state := RX_START_S;
230  end if;
231 
232  when RX_START_S =>
233  -- Wait for saciRsp start bit
234  rVar.shiftCount := (others => '0');
235  if (saciRspFall = '1') then
236  rVar.state := RX_HEADER_S;
237  end if;
238 
239  when RX_HEADER_S =>
240  -- Shift data in and check that header is correct
241  rVar.shiftCount := r.shiftCount + 1;
242  shiftInLeft(saciRspFall, r.shiftReg, rVar.shiftReg);
243  if (r.shiftCount = 20) then
244  if (r.shiftReg(19) /= saciMasterIn.op or
245  r.shiftReg(18 downto 12) /= saciMasterIn.cmd or
246  r.shiftReg(11 downto 0) /= saciMasterIn.addr) then
247  rVar.saciMasterOut.fail := '1';
248  end if;
249  if (saciMasterIn.op = '0') then
250  rVar.state := RX_DATA_S;
251  else
252  rVar.state := ACK_S;
253  end if;
254  end if;
255 
256  when RX_DATA_S =>
257  rVar.shiftCount := r.shiftCount + 1;
258  shiftInLeft(saciRspFall, r.shiftReg, rVar.shiftReg);
259  if (r.shiftCount = 51) then
260  rVar.state := ACK_S;
261  end if;
262 
263  when ACK_S =>
264  rVar.saciMasterOut.ack := '1';
265  rVar.saciMasterOut.rdData := r.shiftReg(31 downto 0);
266  if (reqVar = '0') then
267  rVar.saciMasterOut.ack := '0';
268  rVar.saciMasterOut.fail := '0';
269  rVar.state := IDLE_S;
270  end if;
271 
272  when others => null;
273  end case;
274 
275  end if;
276 
277  rin <= rVar;
278 
279  saciSelL <= r.saciSelL;
280  saciCmd <= r.saciCmd;
282 
283  end process comb;
284 
285 end architecture rtl;
slv( 11 downto 0) addr
std_logic sl
Definition: StdRtlPkg.vhd:28
slv( 31 downto 0) wrData
out saciMasterOutSaciMasterOutType
Definition: SaciMaster.vhd:45
_library_ IEEEIEEE
Definition: StdRtlPkg.vhd:18
slv( 6 downto 0) cmd
out saciSelLslv( SACI_NUM_SLAVES_C- 1 downto 0)
Definition: SaciMaster.vhd:39
in rstsl
Definition: SaciMaster.vhd:35
TPD_Gtime := 1 ns
Definition: SaciMaster.vhd:30
positive := 4 SACI_NUM_SLAVES_C
SYNCHRONIZE_CONTROL_Gboolean := true
Definition: SaciMaster.vhd:31
out saciClksl
Definition: SaciMaster.vhd:38
in saciRspsl
Definition: SaciMaster.vhd:41
out saciCmdsl
Definition: SaciMaster.vhd:40
slv( 31 downto 0) rdData
in clksl
Definition: SaciMaster.vhd:34
slv( SACI_CHIP_WIDTH_C- 1 downto 0) chip
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
in saciMasterInSaciMasterInType
Definition: SaciMaster.vhd:44