Skip to content

Commit ae671ec

Browse files
committed
more sim wip
1 parent 00261d2 commit ae671ec

8 files changed

+254
-104
lines changed

hdl/ip/vhd/i2c/i2c_core.vhd

+18-11
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,17 @@ end entity;
4242

4343
architecture rtl of i2c_core is
4444

45-
type state_t is (IDLE, START, WAIT_START, WAIT_ADDR_ACK, READ, WRITE, WAIT_WRITE_ACK, STOP, WAIT_STOP);
45+
type state_t is (
46+
IDLE,
47+
START,
48+
WAIT_START,
49+
WAIT_ADDR_ACK,
50+
READ,
51+
WRITE,
52+
WAIT_WRITE_ACK,
53+
STOP,
54+
WAIT_STOP
55+
);
4656

4757
type sm_reg_t is record
4858
state : state_t;
@@ -135,10 +145,9 @@ begin
135145
when WAIT_ADDR_ACK =>
136146
if ll_ready = '1' and ll_ackd_valid = '1' then
137147
if ll_ackd then
148+
v.bytes_done := (others => '0');
138149
if sm_reg.cmd.op = Read or sm_reg.in_random_read then
139150
v.state := READ;
140-
-- set bytes done to 1 to handle the single byte read case
141-
v.bytes_done := (0 => '1', others => '0');
142151
-- nack after the first byte when only reading one byte
143152
v.do_ack := '0' when sm_reg.cmd.len = 1 else '1';
144153
else
@@ -155,14 +164,12 @@ begin
155164

156165
-- read as many bytes as requested
157166
when READ =>
158-
if ll_rx_data_valid then
159-
if sm_reg.cmd.len = sm_reg.bytes_done then
160-
v.state := STOP;
161-
else
162-
v.bytes_done := sm_reg.bytes_done + 1;
163-
-- nack the next byte if it is the last
164-
v.do_ack := '0' when sm_reg.cmd.len = sm_reg.bytes_done + 1 else '1';
165-
end if;
167+
if sm_reg.cmd.len = sm_reg.bytes_done then
168+
v.state := STOP;
169+
elsif ll_rx_data_valid then
170+
v.bytes_done := sm_reg.bytes_done + 1;
171+
-- nack the next byte if it is the last
172+
v.do_ack := '0' when sm_reg.cmd.len = v.bytes_done else '1';
166173
end if;
167174

168175
-- transmit the next byte

hdl/ip/vhd/i2c/link_layer/i2c_link_layer.vhd

+20-22
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ architecture rtl of i2c_link_layer is
8787
type sm_reg_t is record
8888
-- state
8989
state : state_t;
90-
bits_shifted : natural range 0 to 7;
90+
bits_shifted : natural range 0 to 8;
9191

9292
-- control
9393
ready : std_logic;
@@ -239,7 +239,9 @@ begin
239239
v.rx_data_valid := '0';
240240

241241
-- after a scl fedge sda should be updated
242-
if scl_fedge then
242+
if scl_fedge = '1' and (sm_reg.state = BYTE_TX or
243+
sm_reg.state = ACK_TX or
244+
sm_reg.state = STOP_SDA) then
243245
v.sda_change := '1';
244246
end if;
245247

@@ -301,26 +303,25 @@ begin
301303
v.state := STOP_SDA;
302304
elsif tx_data_valid then
303305
-- data to transmit
304-
v.state := BYTE_TX;
305-
v.data := tx_data;
306+
v.state := BYTE_TX;
307+
v.data := tx_data;
308+
v.sda_change := '1';
306309
else
307310
-- if nothing else, read
308311
v.state := BYTE_RX;
309312
end if;
310313

311314
-- Clock out a byte and then wait for an ACK
312315
when BYTE_TX =>
313-
if transition_sda = '1' and sm_reg.sda_change = '1' then
316+
if transition_sda = '1' and sm_reg.bits_shifted = 8 then
317+
v.state := ACK_RX;
318+
v.sda_change := '0';
319+
v.bits_shifted := 0;
320+
elsif transition_sda = '1' and sm_reg.sda_change = '1' then
314321
v.sda_oe := not sm_reg.data(0);
315322
v.data := '1' & sm_reg.data(7 downto 1);
316323
v.sda_change := '0';
317-
318-
if sm_reg.bits_shifted = 7 then
319-
v.state := ACK_RX;
320-
v.bits_shifted := 0;
321-
else
322-
v.bits_shifted := sm_reg.bits_shifted + 1;
323-
end if;
324+
v.bits_shifted := sm_reg.bits_shifted + 1;
324325
end if;
325326

326327
-- See if the target ACKs
@@ -337,16 +338,13 @@ begin
337338
when BYTE_RX =>
338339
v.sda_oe := '0';
339340

340-
if scl_redge then
341-
v.data := sda_in_syncd & sm_reg.data(7 downto 1);
342-
343-
if sm_reg.bits_shifted = 7 then
344-
v.state := ACK_TX;
345-
v.rx_data_valid := '1';
346-
v.bits_shifted := 0;
347-
else
348-
v.bits_shifted := sm_reg.bits_shifted + 1;
349-
end if;
341+
if sm_reg.bits_shifted = 8 then
342+
v.state := ACK_TX;
343+
v.rx_data_valid := '1';
344+
v.bits_shifted := 0;
345+
elsif scl_redge then
346+
v.data := sda_in_syncd & sm_reg.data(7 downto 1);
347+
v.bits_shifted := sm_reg.bits_shifted + 1;
350348
end if;
351349

352350
-- ACK the target

hdl/ip/vhd/i2c/sims/i2c_cmd_vc_pkg.vhd

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ package body i2c_cmd_vc_pkg is
7676
push(msg, cmd.reg);
7777
push(msg, cmd.len);
7878
send(net, i2c_cmd_vc.p_actor, msg);
79-
wait_until_idle(net, i2c_cmd_vc.p_actor);
79+
-- wait_until_idle(net, i2c_cmd_vc.p_actor);
8080
end;
8181

8282

hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd

+111-15
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ architecture model of i2c_peripheral is
3030

3131
type state_t is (
3232
IDLE,
33-
GET_START_BYTE,
34-
GET_REG_BYTE,
3533
SEND_ACK,
3634
SEND_NACK,
3735
SEND_BYTE,
@@ -43,55 +41,153 @@ architecture model of i2c_peripheral is
4341
signal state : state_t := IDLE;
4442

4543
signal start_condition : std_logic := '0';
44+
signal stop_condition : std_logic := '0';
45+
signal sda_last : std_logic := 'H';
4646
signal rx_data : std_logic_vector(7 downto 0) := (others => '0');
4747
signal rx_bit_count : unsigned(3 downto 0) := (others => '0');
4848
signal rx_done : std_logic := '0';
49+
signal rx_ackd : boolean := FALSE;
50+
signal tx_data : std_logic_vector(7 downto 0) := (others => '0');
51+
signal tx_bit_count : unsigned(3 downto 0) := (others => '0');
52+
signal tx_done : std_logic := '0';
53+
54+
signal in_receiving_state : boolean := FALSE;
55+
signal in_transmitting_state : boolean := FALSE;
4956
begin
5057

51-
start_condition <= '1' when sda = '0' and state = IDLE else '0';
58+
start_condition <= '1' when sda_last = 'H' and sda = '0' and scl = 'H' else '0';
59+
stop_condition <= '1' when sda_last = '0' and sda = 'H' and scl = 'H' else '0';
60+
61+
-- message_handler: process
62+
-- variable msg_type : msg_type_t;
63+
-- variable request_msg, reply_msg : msg_t;
64+
-- begin
65+
-- receive(net, i2c_peripheral_vc.p_actor, request_msg);
66+
-- msg_type := message_type(request_msg);
67+
-- end process;
5268

53-
message_handler: process
54-
variable msg_type : msg_type_t;
55-
variable request_msg, reply_msg : msg_t;
69+
-- sample SDA regularly to catch transitions
70+
sda_monitor: process
5671
begin
57-
receive(net, i2c_peripheral_vc.p_actor, request_msg);
58-
msg_type := message_type(request_msg);
72+
wait for 20 ns;
73+
sda_last <= sda;
5974
end process;
6075

6176
transaction_sm: process
62-
variable event_msg : msg_t;
77+
variable event_msg : msg_t;
78+
variable is_read : boolean := FALSE;
6379
begin
80+
-- IDLE: wait for a START
6481
wait on start_condition;
6582
event_msg := new_msg(got_start);
6683
send(net, i2c_peripheral_vc.p_actor, event_msg);
84+
state <= GET_BYTE;
6785

68-
state <= GET_START_BYTE;
86+
-- GET_BYTE: check address and acknowledge appropriately
6987
wait on rx_done;
88+
wait until falling_edge(scl);
7089
if rx_data(7 downto 1) = i2c_peripheral_vc.address then
7190
state <= SEND_ACK;
91+
is_read := rx_data(0) = '1';
7292
event_msg := new_msg(address_matched);
7393
send(net, i2c_peripheral_vc.p_actor, event_msg);
7494
else
7595
state <= SEND_NACK;
7696
event_msg := new_msg(address_different);
7797
send(net, i2c_peripheral_vc.p_actor, event_msg);
7898
end if;
99+
100+
-- SEND_ACK/NACK: acknowledge the START byte
101+
wait until falling_edge(scl);
102+
if state = SEND_ACK then
103+
if is_read then
104+
state <= SEND_BYTE;
105+
else
106+
state <= GET_BYTE;
107+
end if;
108+
else
109+
-- NACK'd
110+
state <= GET_STOP;
111+
end if;
112+
wait until rising_edge(scl);
113+
114+
if is_read then
115+
-- loop to respond to a controller read request
116+
while state /= GET_STOP loop
117+
-- SEND_BYTE: send the byte and then wait for an acknowledge
118+
wait on tx_done;
119+
wait until rising_edge(scl);
120+
state <= GET_ACK;
121+
122+
-- GET_ACK: see if the controller wants to continue reading or is finished
123+
wait on rx_done;
124+
state <= SEND_BYTE when rx_ackd else GET_STOP;
125+
end loop;
126+
end if;
127+
128+
-- GET_STOP: wait for a STOP
129+
wait on stop_condition;
130+
event_msg := new_msg(got_stop);
131+
send(net, i2c_peripheral_vc.p_actor, event_msg);
132+
state <= IDLE;
79133
end process;
80134

81-
rx_done <= '1' when rx_bit_count = 8 else '0';
135+
in_receiving_state <= state = GET_BYTE or state = GET_ACK;
136+
rx_done <= '1' when (state = GET_BYTE and rx_bit_count = 8) or
137+
(state = GET_ACK and rx_bit_count = 1)
138+
else '0';
82139

83140
receive_sm: process
84141
variable data_next : std_logic_vector(7 downto 0) := (others => '0');
142+
variable sda_v : std_logic;
85143
begin
86144
wait until rising_edge(scl);
87-
if state = GET_START_BYTE then
88-
data_next := sda & rx_data(7 downto 1);
89-
rx_bit_count <= rx_bit_count + 1;
90-
else
145+
146+
if rx_done then
91147
rx_bit_count <= (others => '0');
148+
elsif state = GET_ACK then
149+
-- '0' = ACK, 'H' = NACK
150+
rx_ackd <= TRUE when sda = '0' else FALSE;
151+
rx_bit_count <= to_unsigned(1, rx_bit_count'length);
152+
elsif state = GET_BYTE then
153+
sda_v := '1' when sda = 'H' else '0';
154+
data_next := sda_v & rx_data(7 downto 1);
155+
rx_bit_count <= rx_bit_count + 1;
92156
end if;
93157

94158
rx_data <= data_next;
95159
end process;
96160

161+
162+
in_transmitting_state <= state = SEND_ACK or state = SEND_NACK or state = SEND_BYTE;
163+
tx_done <= '1' when ((state = SEND_ACK or state = SEND_ACK) and tx_bit_count = 1) or
164+
(state = SEND_BYTE and tx_bit_count = 8)
165+
else '0';
166+
167+
transmit_sm: process
168+
variable data_next : std_logic_vector(7 downto 0) := X"CC";
169+
begin
170+
if tx_done then
171+
tx_bit_count <= (others => '0');
172+
end if;
173+
174+
wait until falling_edge(scl);
175+
-- delay the SDA transition to a bit after SCL falls to allow the controller to release SDA
176+
wait for 25 ns;
177+
178+
if tx_done then
179+
-- release bus
180+
sda <= 'H';
181+
elsif state = SEND_ACK or state = SEND_NACK then
182+
sda <= '0' when state = SEND_ACK else 'H';
183+
tx_bit_count <= to_unsigned(1, tx_bit_count'length);
184+
elsif state = SEND_BYTE then
185+
sda <= 'H' when data_next(to_integer(tx_bit_count)) = '1' else '0';
186+
tx_bit_count <= tx_bit_count + 1;
187+
end if;
188+
189+
wait until rising_edge(scl);
190+
191+
end process;
192+
97193
end architecture;

hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd

+59
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ package i2c_peripheral_pkg is
2323
constant got_ack : msg_type_t := new_msg_type("got_ack");
2424
constant send_byte : msg_type_t := new_msg_type("send_byte");
2525
constant got_byte : msg_type_t := new_msg_type("got_byte");
26+
constant got_stop : msg_type_t := new_msg_type("got_stop");
2627

2728
type i2c_peripheral_t is record
2829
-- I2C peripheral address
@@ -42,6 +43,23 @@ package i2c_peripheral_pkg is
4243
logger : logger_t := i2c_peripheral_vc_logger
4344
) return i2c_peripheral_t;
4445

46+
procedure expect_message (
47+
signal net : inout network_t;
48+
constant vc : i2c_peripheral_t;
49+
constant expected_msg : msg_type_t;
50+
);
51+
52+
procedure expect_stop (
53+
signal net : inout network_t;
54+
constant vc : i2c_peripheral_t;
55+
);
56+
57+
procedure start_byte_ack (
58+
signal net : inout network_t;
59+
constant vc : i2c_peripheral_t;
60+
variable ack : out boolean;
61+
);
62+
4563
end package;
4664

4765
package body i2c_peripheral_pkg is
@@ -61,4 +79,45 @@ package body i2c_peripheral_pkg is
6179
);
6280
end;
6381

82+
procedure expect_message (
83+
signal net : inout network_t;
84+
constant vc : i2c_peripheral_t;
85+
constant expected_msg : msg_type_t;
86+
) is
87+
variable msg : msg_t;
88+
variable matched : boolean;
89+
begin
90+
receive(net, vc.p_actor, msg);
91+
matched := message_type(msg) = expected_msg;
92+
check_true(matched, "Received message did not match expected message.");
93+
end procedure;
94+
95+
procedure expect_stop (
96+
signal net : inout network_t;
97+
constant vc : i2c_peripheral_t;
98+
) is
99+
begin
100+
expect_message(net, vc, got_stop);
101+
end procedure;
102+
103+
procedure start_byte_ack (
104+
signal net : inout network_t;
105+
constant vc : i2c_peripheral_t;
106+
variable ack : out boolean;
107+
) is
108+
variable msg : msg_t;
109+
begin
110+
-- receive START event
111+
receive(net, vc.p_actor, msg);
112+
if message_type(msg) = got_start then
113+
-- receive START byte ack
114+
receive(net, vc.p_actor, msg);
115+
if message_type(msg) = address_matched then
116+
ack := true;
117+
elsif message_type(msg) = address_different then
118+
ack := false;
119+
end if;
120+
end if;
121+
end procedure;
122+
64123
end package body;

0 commit comments

Comments
 (0)