@@ -11,6 +11,7 @@ use ieee.numeric_std.all;
11
11
library vunit_lib;
12
12
context vunit_lib.vunit_context;
13
13
context vunit_lib.com_context;
14
+ context vunit_lib.vc_context;
14
15
use vunit_lib.sync_pkg.all ;
15
16
16
17
use work.tristate_if_pkg.all ;
@@ -42,23 +43,21 @@ architecture model of i2c_peripheral is
42
43
43
44
signal state : state_t := IDLE;
44
45
45
- signal start_condition : std_logic := '0' ;
46
- signal stop_condition : std_logic := '0' ;
46
+ signal start_condition : boolean := FALSE ;
47
+ signal stop_condition : boolean := FALSE ;
47
48
signal sda_last : std_logic := '1' ;
48
49
signal rx_data : std_logic_vector (7 downto 0 ) := (others => '0' );
49
50
signal rx_bit_count : unsigned (3 downto 0 ) := (others => '0' );
50
51
signal rx_done : std_logic := '0' ;
51
52
signal rx_ackd : boolean := FALSE ;
52
- signal tx_data : std_logic_vector (7 downto 0 ) := (others => '0' );
53
53
signal tx_bit_count : unsigned (3 downto 0 ) := (others => '0' );
54
54
signal tx_done : std_logic := '0' ;
55
55
56
- signal in_receiving_state : boolean := FALSE ;
57
- signal in_transmitting_state : boolean := FALSE ;
58
-
59
56
signal scl_oe : std_logic := '0' ;
60
57
signal sda_oe : std_logic := '0' ;
61
58
59
+ signal reg_addr : unsigned (7 downto 0 ) := (others => '0' );
60
+ signal is_addr_set : boolean := FALSE ;
62
61
begin
63
62
-- I2C interface is open-drain
64
63
scl_if.o <= '0' ;
67
66
scl_if.oe <= scl_oe;
68
67
sda_if.oe <= sda_oe;
69
68
70
- start_condition <= '1' when sda_last = '1' and sda_if.i = '0' and scl_if.i = '1' else '0 ' ;
71
- stop_condition <= '1' when sda_last = '0' and sda_if.i = '1' and scl_if.i = '1' else '0 ' ;
69
+ start_condition <= sda_last = '1' and sda_if.i = '0' and scl_if.i = '1' ;
70
+ stop_condition <= sda_last = '0' and sda_if.i = '1' and scl_if.i = '1' ;
72
71
73
72
-- message_handler: process
74
73
-- variable msg_type : msg_type_t;
88
87
transaction_sm : process
89
88
variable event_msg : msg_t;
90
89
variable is_read : boolean := FALSE ;
90
+ variable stop_during_write : boolean := FALSE ;
91
91
begin
92
92
-- IDLE: wait for a START
93
93
wait on start_condition;
97
97
98
98
-- GET_BYTE: check address and acknowledge appropriately
99
99
wait on rx_done;
100
- wait until falling_edge (scl_if.i);
101
100
if rx_data(7 downto 1 ) = address(i2c_peripheral_vc) then
102
101
state <= SEND_ACK;
103
102
is_read := rx_data(0 ) = '1' ;
@@ -110,6 +109,7 @@ begin
110
109
end if ;
111
110
112
111
-- SEND_ACK/NACK: acknowledge the START byte
112
+ wait on tx_done;
113
113
wait until falling_edge (scl_if.i);
114
114
if state = SEND_ACK then
115
115
if is_read then
@@ -121,7 +121,7 @@ begin
121
121
-- NACK'd
122
122
state <= GET_STOP;
123
123
end if ;
124
- wait until rising_edge (scl_if.i);
124
+ -- wait until rising_edge(scl_if.i);
125
125
126
126
if is_read then
127
127
-- loop to respond to a controller read request
@@ -137,69 +137,113 @@ begin
137
137
-- the loop condition needs this to realize when state gets set to GET_STOP
138
138
wait for 1 ns ;
139
139
end loop ;
140
+ else
141
+ -- loop to respond to a controller write request
142
+ while state /= GET_STOP loop
143
+ if stop_condition then
144
+ state <= GET_STOP;
145
+ -- the loop condition needs this to realize when state gets set to GET_STOP
146
+ wait for 1 ns ;
147
+ end if ;
148
+
149
+ -- GET_BYTE: get the byte and then send an acknowledge
150
+ wait on rx_done;
151
+ state <= GET_STOP when stop_condition else SEND_ACK;
152
+ -- the loop condition needs this to realize when state gets set to GET_STOP
153
+ wait for 1 ns ;
154
+
155
+ if state /= GET_STOP then
156
+ wait on tx_done;
157
+ wait until falling_edge (scl_if.i);
158
+ state <= GET_BYTE;
159
+
160
+ if is_addr_set then
161
+ write_word(memory(i2c_peripheral_vc), to_integer (reg_addr), rx_data);
162
+ event_msg := new_msg(got_byte);
163
+ send(net, i2c_peripheral_vc.p_actor, event_msg);
164
+ reg_addr <= reg_addr + 1 ;
165
+ else
166
+ is_addr_set <= TRUE ;
167
+ reg_addr <= unsigned (rx_data);
168
+ end if ;
169
+ else
170
+ stop_during_write := TRUE ;
171
+ end if ;
172
+ end loop ;
140
173
end if ;
141
174
142
175
-- GET_STOP: wait for a STOP
143
- wait on stop_condition;
176
+ wait until ( stop_condition or stop_during_write) ;
144
177
event_msg := new_msg(got_stop);
145
178
send(net, i2c_peripheral_vc.p_actor, event_msg);
146
179
state <= IDLE;
180
+ stop_during_write := FALSE ;
147
181
end process ;
148
182
149
- in_receiving_state <= state = GET_BYTE or state = GET_ACK;
150
183
rx_done <= '1' when (state = GET_BYTE and rx_bit_count = 8 ) or
151
- (state = GET_ACK and rx_bit_count = 1 )
184
+ (state = GET_ACK and rx_bit_count = 1 ) or
185
+ stop_condition
152
186
else '0' ;
153
187
154
188
receive_sm : process
155
189
variable data_next : std_logic_vector (7 downto 0 ) := (others => '0' );
156
190
begin
157
191
wait until rising_edge (scl_if.i);
158
192
159
- if rx_done then
160
- rx_bit_count <= (others => '0' );
161
- elsif state = GET_ACK then
193
+ if state = GET_ACK then
162
194
-- '0' = ACK, '1' = NACK
163
195
rx_ackd <= TRUE when sda_if.i = '0' else FALSE ;
164
- rx_bit_count <= to_unsigned (1 , rx_bit_count'length );
165
196
elsif state = GET_BYTE then
166
197
data_next := sda_if.i & rx_data(7 downto 1 );
167
- rx_bit_count <= rx_bit_count + 1 ;
168
198
end if ;
169
199
170
200
rx_data <= data_next;
201
+
202
+ wait until falling_edge (scl_if.i);
203
+
204
+ if state = GET_ACK then
205
+ rx_bit_count <= to_unsigned (1 , rx_bit_count'length );
206
+ elsif state = GET_BYTE then
207
+ rx_bit_count <= rx_bit_count + 1 ;
208
+ else
209
+ rx_bit_count <= (others => '0' );
210
+ end if ;
171
211
end process ;
172
212
173
213
174
- in_transmitting_state <= state = SEND_ACK or state = SEND_NACK or state = SEND_BYTE;
175
214
tx_done <= '1' when ((state = SEND_ACK or state = SEND_ACK) and tx_bit_count = 1 ) or
176
215
(state = SEND_BYTE and tx_bit_count = 8 )
177
216
else '0' ;
178
217
179
218
transmit_sm : process
180
- variable data_next : std_logic_vector (7 downto 0 ) := X"CC" ;
219
+ variable data_v : std_logic_vector (7 downto 0 ) := X"CC" ;
181
220
begin
182
- if tx_done then
183
- tx_bit_count <= (others => '0' );
184
- end if ;
185
-
186
221
wait until falling_edge (scl_if.i);
187
222
-- delay the SDA transition to a bit after SCL falls to allow the controller to release SDA
188
- wait for 25 ns ;
189
-
190
- if tx_done then
191
- -- release bus
192
- sda_oe <= '0' ;
193
- elsif state = SEND_ACK or state = SEND_NACK then
223
+ wait for 100 ns ;
224
+ if state = SEND_ACK or state = SEND_NACK then
194
225
sda_oe <= '1' when state = SEND_ACK else '0' ;
195
- tx_bit_count <= to_unsigned (1 , tx_bit_count'length );
196
226
elsif state = SEND_BYTE then
197
- sda_oe <= not data_next(to_integer (tx_bit_count));
198
- tx_bit_count <= tx_bit_count + 1 ;
227
+ if tx_bit_count = 0 then
228
+ data_v := read_word(i2c_peripheral_vc.p_buffer.p_memory_ref, natural (to_integer (reg_addr)), 1 );
229
+ end if ;
230
+ sda_oe <= not data_v(to_integer (tx_bit_count));
231
+ else
232
+ -- release the bus
233
+ sda_oe <= '0' ;
199
234
end if ;
200
235
201
236
wait until rising_edge (scl_if.i);
202
237
238
+ -- update counter once bit has been sampled
239
+ if state = SEND_ACK or state = SEND_NACK then
240
+ tx_bit_count <= to_unsigned (1 , tx_bit_count'length );
241
+ elsif state = SEND_BYTE then
242
+ tx_bit_count <= tx_bit_count + 1 ;
243
+ else
244
+ tx_bit_count <= (others => '0' );
245
+ end if ;
246
+
203
247
end process ;
204
248
205
249
end architecture ;
0 commit comments