SURF  1.0
I2cRegSlave.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : I2cRegSlave.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-01-16
5 -- Last update: 2014-03-13
6 -------------------------------------------------------------------------------
7 -- Description: Implements an I2C slave attached to a generic RAM interface.
8 -- Protocol is simple: Address of configurable size, followed by data of
9 -- configurable size.
10 -------------------------------------------------------------------------------
11 -- This file is part of 'SLAC Firmware Standard Library'.
12 -- It is subject to the license terms in the LICENSE.txt file found in the
13 -- top-level directory of this distribution and at:
14 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
15 -- No part of 'SLAC Firmware Standard Library', including this file,
16 -- may be copied, modified, propagated, or distributed except according to
17 -- the terms contained in the LICENSE.txt file.
18 -------------------------------------------------------------------------------
19 
20 library ieee;
21 use ieee.std_logic_1164.all;
22 use ieee.numeric_std.all;
23 
24 use work.StdRtlPkg.all;
25 use work.I2cPkg.all;
26 
27 --! @see entity
28  --! @ingroup protocols_i2c
29 entity I2cRegSlave is
30  generic (
31  TPD_G : time := 1 ns;
32  -- Generics passed down to I2cSlave
33  TENBIT_G : integer range 0 to 1 := 0;
34  I2C_ADDR_G : integer range 0 to 1023 := 0;
35  OUTPUT_EN_POLARITY_G : integer range 0 to 1 := 0;
36  FILTER_G : integer range 2 to 512 := 4;
37  -- RAM generics
38  ADDR_SIZE_G : positive := 2; -- in bytes
39  DATA_SIZE_G : positive := 1; -- in bytes
40  ENDIANNESS_G : integer range 0 to 1 := 0); -- 0=LE, 1=BE
41  port (
42  sRst : in sl := '0';
43  aRst : in sl := '0';
44  clk : in sl;
45  -- Front End Ram Interface
46  addr : out slv((8*ADDR_SIZE_G)-1 downto 0);
47  wrEn : out sl;
48  wrData : out slv((8*DATA_SIZE_G)-1 downto 0);
49  rdEn : out sl;
50  rdData : in slv((8*DATA_SIZE_G)-1 downto 0);
51  -- I2C Signals
54 end entity I2cRegSlave;
55 
56 architecture rtl of I2cRegSlave is
57 
58  type StateType is (IDLE_S, ADDR_S, WRITE_DATA_S, READ_DATA_S);
59 
60  type RegType is record
61  state : StateType;
62  byteCnt : unsigned(bitSize(maximum(ADDR_SIZE_G, DATA_SIZE_G))-1 downto 0);
63 
64  addr : unsigned((8*ADDR_SIZE_G)-1 downto 0);
65  wrEn : sl;
66  wrData : slv((8*DATA_SIZE_G)-1 downto 0);
67  rdEn : sl;
68  i2cSlaveIn : I2cSlaveInType; -- Signals to i2cSlave
69  end record RegType;
70 
71  constant REG_INIT_C : RegType := (
72  state => IDLE_S,
73  byteCnt => (others => '0'),
74  addr => (others => '0'),
75  wrEn => '0',
76  wrData => (others => '0'),
77  rdEn => '0',
78  i2cSlaveIn => I2C_SLAVE_IN_INIT_C);
79 
80  signal r : RegType := REG_INIT_C;
81  signal rin : RegType;
82  signal i2cSlaveOut : I2cSlaveOutType; -- From i2cSlave
83  signal i2cSlaveIn : I2cSlaveInType; -- To I2cSlave
84 
85  function getIndex (
86  byteCount : unsigned;
87  totalBytes : positive)
88  return integer is
89  begin
90  if (ENDIANNESS_G = 0) then
91  -- little endian
92  return to_integer(byteCount)*8;
93  else
94  -- big endian
95  return (totalBytes-1-to_integer(byteCount))*8;
96  end if;
97  end function getIndex;
98 
99 begin
100 
101  I2cSlave_1 : entity work.I2cSlave
102  generic map (
103  TENBIT_G => TENBIT_G,
106  FILTER_G => FILTER_G,
107  RMODE_G => 0,
108  TMODE_G => 0)
109  port map (
110  sRst => sRst,
111  aRst => aRst,
112  clk => clk,
113  i2cSlaveIn => i2cSlaveIn,
114  i2cSlaveOut => i2cSlaveOut,
115  i2ci => i2ci,
116  i2co => i2co);
117 
118  comb : process (rdData, r, i2cSlaveOut, sRst) is
119  variable v : RegType;
120  variable byteCntVar : integer;
121  variable addrIndexVar : integer;
122  variable dataIndexVar : integer;
123  begin
124  v := r;
125 
126  byteCntVar := to_integer(r.byteCnt);
127  addrIndexVar := getIndex(r.byteCnt, ADDR_SIZE_G);
128  dataIndexVar := getIndex(r.byteCnt, DATA_SIZE_G);
129 
130  -- Enable the i2cSlave after reset
131  v.i2cSlaveIn.enable := '1';
132 
133  -- Read and Write enables are pulsed, defualt to 0
134  v.wrEn := '0';
135  v.rdEn := '0';
136 
137  -- Pulse rxAck or wait until rxValid drops?
138  -- Can get away with pulsing.
139  v.i2cSlaveIn.rxAck := '0';
140 
141  -- Auto increment the address after each read or write
142  -- This enables bursts.
143  if (r.wrEn = '1' or r.rdEn = '1') then
144  v.addr := r.addr + 1;
145  end if;
146 
147  -- Tx Data always valid, assigned based on byte cnt
148  v.i2cSlaveIn.txValid := '1';
149 
150  case (r.state) is
151  when IDLE_S =>
152  v.byteCnt := (others => '0');
153  -- Get txData ready in case a read occurs.
154  v.i2cSlaveIn.txData := rdData(dataIndexVar+7 downto dataIndexVar);
155 
156  -- Wait here for slave to be addressed
157  if (i2cSlaveOut.rxActive = '1') then
158  -- Slave has been addressed for a write on the i2c bus
159  -- This write will consist of the ram address
160  v.state := ADDR_S;
161  v.addr := (others => '0');
162 
163  elsif (i2cSlaveOut.txActive = '1') then
164  v.state := READ_DATA_S;
165  end if;
166 
167  when ADDR_S =>
168  if (i2cSlaveOut.rxValid = '1') then
169  -- Received a byte of the address
170  v.addr(addrIndexVar+7 downto addrIndexVar) := unsigned(i2cSlaveOut.rxData);
171  v.byteCnt := r.byteCnt + 1;
172  if (r.byteCnt = ADDR_SIZE_G-1) then
173  v.byteCnt := (others => '0');
174  v.state := WRITE_DATA_S;
175  end if;
176  end if;
177 
178  if (i2cSlaveOut.rxActive = '0') then
179  -- Didn't get enough bytes, go back to idle
180  v.state := IDLE_S;
181  v.byteCnt := (others => '0');
182  end if;
183 
184  when WRITE_DATA_S =>
185  if (i2cSlaveOut.rxValid = '1') then
186  -- Received another byte
187  v.wrData(dataIndexVar+7 downto dataIndexVar) := i2cSlaveOut.rxData;
188  v.byteCnt := r.byteCnt + 1;
189 -- v.i2cSlaveIn.rxAck := '1';
190  if (byteCntVar = DATA_SIZE_G -1) then
191  -- Received a whole word. Increment addr, reset byteCnt
192  v.wrEn := '1';
193  v.byteCnt := (others => '0');
194  end if;
195  end if;
196 
197  if (i2cSlaveOut.rxActive = '0') then
198  v.state := IDLE_S;
199  end if;
200 
201  when READ_DATA_S =>
202  v.i2cSlaveIn.txData := rdData(dataIndexVar+7 downto dataIndexVar);
203  if (i2cSlaveOut.txAck = '1') then
204  -- Byte was sent
205  v.byteCnt := r.byteCnt + 1;
206  if (byteCntVar = DATA_SIZE_G - 1) then
207  -- Word was sent. Increment addr to get next word, reset byteCnt
208  v.rdEn := '1';
209  v.byteCnt := (others => '0');
210  end if;
211  end if;
212 
213  if (i2cSlaveOut.txActive = '0') then
214  v.state := IDLE_S;
215  end if;
216 
217 
218  when others => null;
219  end case;
220 
221  ------------------------------------------------------------------------------------------------
222  -- Synchronous Reset
223  ------------------------------------------------------------------------------------------------
224  if (sRst = '1') then
225  v := REG_INIT_C;
226 -- v.state := IDLE_S;
227 -- v.byteCnt := (others => '0');
228 -- v.addr := (others => '0');
229 -- v.wrEn := '0';
230 -- v.wrData := (others => '0');
231 -- v.rdEn := '0';
232 -- v.i2cSlaveIn.enable := '0';
233 -- v.i2cSlaveIn.txValid := '0';
234 -- v.i2cSlaveIn.txData := (others => '0');
235 -- v.i2cSlaveIn.rxAck := '0';
236  end if;
237 
238  ------------------------------------------------------------------------------------------------
239  -- Signal Assignments
240  ------------------------------------------------------------------------------------------------
241  -- Update registers
242  rin <= v;
243 
244  -- Internal signals
245  i2cSlaveIn <= r.i2cSlaveIn;
246  i2cSlaveIn.rxAck <= i2cSlaveOut.rxValid; -- Always ack
247 
248  -- Update Outputs
249  addr <= slv(r.addr);
250  wrData <= r.wrData;
251  wrEn <= r.wrEn;
252  rdEn <= r.rdEn;
253 
254  end process comb;
255 
256  seq : process (clk, aRst) is
257  begin
258  if (aRst = '1') then
259  r <= REG_INIT_C after TPD_G;
260 -- r.state <= IDLE_S after TPD_G;
261 -- r.byteCnt <= (others => '0') after TPD_G;
262 -- r.addr <= (others => '0') after TPD_G;
263 -- r.wrEn <= '0' after TPD_G;
264 -- r.wrData <= (others => '0') after TPD_G;
265 -- r.rdEn <= '0' after TPD_G;
266 -- r.i2cSlaveIn.enable <= '0' after TPD_G;
267 -- r.i2cSlaveIn.txValid <= '0' after TPD_G;
268 -- r.i2cSlaveIn.txData <= (others => '0') after TPD_G;
269 -- r.i2cSlaveIn.rxAck <= '0' after TPD_G;
270  elsif (rising_edge(clk)) then
271  r <= rin after TPD_G;
272  end if;
273  end process seq;
274 
275 end architecture rtl;
I2C_ADDR_Ginteger range 0 to 1023:= 0
Definition: I2cSlave.vhd:87
out i2coi2c_out_type
Definition: I2cRegSlave.vhd:53
OUTPUT_EN_POLARITY_Ginteger range 0 to 1:= 0
Definition: I2cRegSlave.vhd:35
RMODE_Ginteger range 0 to 1:= 0
Definition: I2cSlave.vhd:90
in clkstd_ulogic
Definition: I2cSlave.vhd:96
TMODE_Ginteger range 0 to 1:= 0
Definition: I2cSlave.vhd:92
FILTER_Ginteger range 2 to 512:= 4
Definition: I2cSlave.vhd:89
FILTER_Ginteger range 2 to 512:= 4
Definition: I2cRegSlave.vhd:36
out rdEnsl
Definition: I2cRegSlave.vhd:49
i2c_in_type
Definition: I2cPkg.vhd:34
std_logic sl
Definition: StdRtlPkg.vhd:28
in sRstsl := '0'
Definition: I2cRegSlave.vhd:42
out wrEnsl
Definition: I2cRegSlave.vhd:47
in sRststd_ulogic := '0'
Definition: I2cSlave.vhd:94
sl rxValid
Definition: I2cPkg.vhd:141
I2cSlaveInType
Definition: I2cPkg.vhd:126
out wrDataslv(( 8* DATA_SIZE_G)- 1 downto 0)
Definition: I2cRegSlave.vhd:48
OUTPUT_EN_POLARITY_Ginteger range 0 to 1:= 0
Definition: I2cSlave.vhd:88
sl txValid
Definition: I2cPkg.vhd:128
ADDR_SIZE_Gpositive := 2
Definition: I2cRegSlave.vhd:38
I2C_ADDR_Ginteger range 0 to 1023:= 0
Definition: I2cRegSlave.vhd:34
sl rxActive
Definition: I2cPkg.vhd:140
slv( 7 downto 0) txData
Definition: I2cPkg.vhd:129
in aRststd_ulogic := '0'
Definition: I2cSlave.vhd:95
TPD_Gtime := 1 ns
Definition: I2cRegSlave.vhd:31
sl txActive
Definition: I2cPkg.vhd:143
i2c_out_type
Definition: I2cPkg.vhd:41
TENBIT_Ginteger range 0 to 1:= 0
Definition: I2cRegSlave.vhd:33
in rdDataslv(( 8* DATA_SIZE_G)- 1 downto 0)
Definition: I2cRegSlave.vhd:50
DATA_SIZE_Gpositive := 1
Definition: I2cRegSlave.vhd:39
slv( 7 downto 0) rxData
Definition: I2cPkg.vhd:142
I2cSlaveInType :=(enable => '0',txValid => '0',txData =>( others => '0'),rxAck => '0') I2C_SLAVE_IN_INIT_C
Definition: I2cPkg.vhd:133
I2cSlaveOutType
Definition: I2cPkg.vhd:139
in i2cSlaveInI2cSlaveInType
Definition: I2cSlave.vhd:98
out addrslv(( 8* ADDR_SIZE_G)- 1 downto 0)
Definition: I2cRegSlave.vhd:46
sl rxAck
Definition: I2cPkg.vhd:130
ENDIANNESS_Ginteger range 0 to 1:= 0
Definition: I2cRegSlave.vhd:40
in i2cii2c_in_type
Definition: I2cSlave.vhd:101
sl txAck
Definition: I2cPkg.vhd:144
out i2coi2c_out_type
Definition: I2cSlave.vhd:103
TENBIT_Ginteger range 0 to 1:= 0
Definition: I2cSlave.vhd:86
in i2cii2c_in_type
Definition: I2cRegSlave.vhd:52
std_ulogic enable
Definition: I2cPkg.vhd:46
out i2cSlaveOutI2cSlaveOutType
Definition: I2cSlave.vhd:99
_library_ ieeeieee
in aRstsl := '0'
Definition: I2cRegSlave.vhd:43
std_logic_vector slv
Definition: StdRtlPkg.vhd:29