Skip to content

Commit 00261d2

Browse files
committed
wip
1 parent 69c45df commit 00261d2

File tree

7 files changed

+203
-46
lines changed

7 files changed

+203
-46
lines changed

hdl/ip/vhd/i2c/i2c_core.vhd

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

4343
architecture rtl of i2c_core is
4444

45-
type state_t is (IDLE, START, WAIT_START, WAIT_ADDR, ADDR_ACK, READ, WRITE, WAIT_WRITE_ACK, STOP, WAIT_STOP);
45+
type state_t is (IDLE, START, WAIT_START, WAIT_ADDR_ACK, READ, WRITE, WAIT_WRITE_ACK, STOP, WAIT_STOP);
4646

4747
type sm_reg_t is record
4848
state : state_t;
@@ -108,8 +108,6 @@ begin
108108
is_read := '0' when sm_reg.cmd.op = WRITE else '1';
109109

110110
-- defaults
111-
v.do_start := '0';
112-
v.do_stop := '0';
113111
v.tx_byte_valid := '0';
114112

115113
case sm_reg.state is
@@ -124,25 +122,18 @@ begin
124122
-- single cycle state to initiate a START
125123
when START =>
126124
v.state := WAIT_START;
127-
v.do_start := '1';
128125

129126
-- wait for link layer to finish START sequence and load up the address byte
130127
when WAIT_START =>
128+
v.tx_byte := sm_reg.cmd.addr & is_read;
129+
v.tx_byte_valid := '1';
131130
if ll_ready then
132-
v.state := WAIT_ADDR;
133-
v.tx_byte := sm_reg.cmd.addr & is_read;
134-
v.tx_byte_valid := '1';
135-
end if;
136-
137-
-- wait for address byte to have been sent
138-
when WAIT_ADDR =>
139-
if ll_ready then
140-
v.state := ADDR_ACK;
131+
v.state := WAIT_ADDR_ACK;
141132
end if;
142133

143-
-- take action based off the operation type and the ACK
144-
when ADDR_ACK =>
145-
if ll_ackd_valid then
134+
-- wait for address byte to have been sent and for the peripheral to ACK
135+
when WAIT_ADDR_ACK =>
136+
if ll_ready = '1' and ll_ackd_valid = '1' then
146137
if ll_ackd then
147138
if sm_reg.cmd.op = Read or sm_reg.in_random_read then
148139
v.state := READ;
@@ -160,7 +151,6 @@ begin
160151
-- TODO: address nack error
161152
v.state := STOP;
162153
end if;
163-
164154
end if;
165155

166156
-- read as many bytes as requested
@@ -207,7 +197,6 @@ begin
207197
-- initiate a STOP and clear state
208198
when STOP =>
209199
v.state := WAIT_STOP;
210-
v.do_stop := '1';
211200
v.bytes_done := (others => '0');
212201
v.in_random_read := false;
213202

@@ -218,6 +207,10 @@ begin
218207
end if;
219208
end case;
220209

210+
-- next state logic
211+
v.do_start := '1' when v.state = START else '0';
212+
v.do_stop := '1' when v.state = STOP else '0';
213+
221214
sm_reg_next <= v;
222215
end process;
223216

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

+12-9
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ architecture rtl of i2c_link_layer is
7373
WAIT_TBUF,
7474
START_SETUP,
7575
START_HOLD,
76+
HANDLE_NEXT_PRE,
7677
HANDLE_NEXT,
7778
BYTE_TX,
7879
BYTE_RX,
@@ -162,8 +163,7 @@ begin
162163
begin
163164
if reset then
164165
scl_oe <= '0';
165-
scl_redge <= '0';
166-
scl_fedge <= '0';
166+
scl_oe_last <= '0';
167167
elsif rising_edge(clk) then
168168
scl_oe_last <= scl_oe;
169169
v_scl_oe_next := not scl_oe;
@@ -238,8 +238,6 @@ begin
238238
v.rx_ack_valid := '0';
239239
v.rx_data_valid := '0';
240240

241-
v.ready := '1' when sm_reg.state = IDLE or sm_reg.state = HANDLE_NEXT else '0';
242-
243241
-- after a scl fedge sda should be updated
244242
if scl_fedge then
245243
v.sda_change := '1';
@@ -283,13 +281,16 @@ begin
283281
when START_HOLD =>
284282
v.sda_oe := '1';
285283
if sm_count_done then
286-
v.state := HANDLE_NEXT;
284+
v.state := HANDLE_NEXT_PRE;
287285
v.scl_start := '1'; -- drop SCL to finish START condition
288286
v.scl_active := '1'; -- begin free running counter for SCL transitions
289287
else
290288
v.count_decr := '1';
291289
end if;
292290

291+
when HANDLE_NEXT_PRE =>
292+
v.state := HANDLE_NEXT;
293+
293294
when HANDLE_NEXT =>
294295
if tx_start then
295296
-- A repeated start was issued mid-transaction
@@ -309,9 +310,8 @@ begin
309310

310311
-- Clock out a byte and then wait for an ACK
311312
when BYTE_TX =>
312-
v.sda_oe := not sm_reg.data(0);
313-
314313
if transition_sda = '1' and sm_reg.sda_change = '1' then
314+
v.sda_oe := not sm_reg.data(0);
315315
v.data := '1' & sm_reg.data(7 downto 1);
316316
v.sda_change := '0';
317317

@@ -328,7 +328,7 @@ begin
328328
v.sda_oe := '0';
329329

330330
if scl_redge then
331-
v.state := HANDLE_NEXT;
331+
v.state := HANDLE_NEXT_PRE;
332332
v.rx_ack := not sda_in_syncd;
333333
v.rx_ack_valid := '1';
334334
end if;
@@ -362,7 +362,7 @@ begin
362362
v.sda_oe := '0';
363363
v.ack_sending := '0';
364364
v.sda_change := '0';
365-
v.state := HANDLE_NEXT;
365+
v.state := HANDLE_NEXT_PRE;
366366
end if;
367367

368368
-- drive SDA through final SCL cycle
@@ -390,6 +390,9 @@ begin
390390

391391
end case;
392392

393+
-- next state logic
394+
v.ready := '1' when (v.state = IDLE or v.state = HANDLE_NEXT_PRE or v.state = HANDLE_NEXT) else '0';
395+
393396
sm_reg_next <= v;
394397
end process;
395398

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

+26-15
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ architecture model of i2c_peripheral is
3333
GET_START_BYTE,
3434
GET_REG_BYTE,
3535
SEND_ACK,
36+
SEND_NACK,
3637
SEND_BYTE,
3738
GET_BYTE,
3839
GET_ACK,
@@ -41,13 +42,13 @@ architecture model of i2c_peripheral is
4142

4243
signal state : state_t := IDLE;
4344

44-
signal start_detected : std_logic := '0';
45+
signal start_condition : std_logic := '0';
4546
signal rx_data : std_logic_vector(7 downto 0) := (others => '0');
4647
signal rx_bit_count : unsigned(3 downto 0) := (others => '0');
4748
signal rx_done : std_logic := '0';
4849
begin
4950

50-
start_detected <= '1' when sda = '0' and state = IDLE else '0';
51+
start_condition <= '1' when sda = '0' and state = IDLE else '0';
5152

5253
message_handler: process
5354
variable msg_type : msg_type_t;
@@ -60,27 +61,37 @@ begin
6061
transaction_sm: process
6162
variable event_msg : msg_t;
6263
begin
63-
wait on start_detected;
64+
wait on start_condition;
6465
event_msg := new_msg(got_start);
6566
send(net, i2c_peripheral_vc.p_actor, event_msg);
6667

6768
state <= GET_START_BYTE;
6869
wait on rx_done;
69-
state <= SEND_ACK;
70+
if rx_data(7 downto 1) = i2c_peripheral_vc.address then
71+
state <= SEND_ACK;
72+
event_msg := new_msg(address_matched);
73+
send(net, i2c_peripheral_vc.p_actor, event_msg);
74+
else
75+
state <= SEND_NACK;
76+
event_msg := new_msg(address_different);
77+
send(net, i2c_peripheral_vc.p_actor, event_msg);
78+
end if;
7079
end process;
7180

7281
rx_done <= '1' when rx_bit_count = 8 else '0';
7382

74-
-- receive_sm: process
75-
-- variable data_next : std_logic_vector(7 downto 0) := (others => '0');
76-
-- begin
77-
-- if state = GET_START_BYTE then
78-
-- wait until rising_edge(scl);
79-
-- data_next := sda & rx_data(7 downto 1);
80-
-- rx_bit_count <= rx_bit_count + 1;
81-
-- else
82-
-- rx_bit_count <= (others => '0');
83-
-- end if;
84-
-- end process;
83+
receive_sm: process
84+
variable data_next : std_logic_vector(7 downto 0) := (others => '0');
85+
begin
86+
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
91+
rx_bit_count <= (others => '0');
92+
end if;
93+
94+
rx_data <= data_next;
95+
end process;
8596

8697
end architecture;

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ package i2c_peripheral_pkg is
1717

1818
-- Message definitions
1919
constant got_start : msg_type_t := new_msg_type("got_start");
20-
constant start_byte : msg_type_t := new_msg_type("start_byte");
2120
constant address_matched : msg_type_t := new_msg_type("address_matched");
21+
constant address_different : msg_type_t := new_msg_type("address_different");
2222
constant send_ack : msg_type_t := new_msg_type("send_ack");
2323
constant got_ack : msg_type_t := new_msg_type("got_ack");
2424
constant send_byte : msg_type_t := new_msg_type("send_byte");
@@ -29,7 +29,6 @@ package i2c_peripheral_pkg is
2929
address : std_logic_vector(6 downto 0);
3030
-- private
3131
p_actor : actor_t;
32-
p_ack_actor : actor_t;
3332
p_memory : memory_t;
3433
p_logger : logger_t;
3534
end record;
@@ -57,7 +56,6 @@ package body i2c_peripheral_pkg is
5756
return (
5857
address => address,
5958
p_actor => new_actor(name),
60-
p_ack_actor => new_actor(name & "_ack"),
6159
p_memory => to_vc_interface(memory, logger),
6260
p_logger => logger
6361
);

hdl/ip/vhd/i2c/sims/i2c_tb.vhd

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,6 @@ begin
7070
end process;
7171

7272
-- Example total test timeout dog
73-
test_runner_watchdog(runner, 10 us);
73+
test_runner_watchdog(runner, 1 ms);
7474

7575
end tb;

hdl/ip/vhd/i2c/sims/i2c_tb_pkg.vhd

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
-- This Source Code Form is subject to the terms of the Mozilla Public
2+
-- License, v. 2.0. If a copy of the MPL was not distributed with this
3+
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
--
5+
-- Copyright 2024 Oxide Computer Company
6+
7+
library ieee;
8+
use ieee.std_logic_1164.all;
9+
use ieee.numeric_std.all;
10+
11+
library vunit_lib;
12+
context vunit_lib.vunit_context;
13+
context vunit_lib.com_context;
14+
context vunit_lib.vc_context;
15+
16+
use work.i2c_peripheral_pkg.all;
17+
18+
package i2c_tb_pkg is
19+
20+
procedure start_byte_ack (
21+
signal net : inout network_t;
22+
constant i2c_peripheral_vc : i2c_peripheral_t;
23+
variable ack : inout boolean;
24+
);
25+
26+
end package;
27+
28+
package body i2c_tb_pkg is
29+
30+
procedure start_byte_ack (
31+
signal net : inout network_t;
32+
constant i2c_peripheral_vc : i2c_peripheral_t;
33+
variable ack : inout boolean;
34+
) is
35+
variable msg : msg_t;
36+
begin
37+
receive(net, i2c_peripheral_vc.p_actor, msg);
38+
if message_type(msg) = got_start then
39+
40+
end if;
41+
end procedure;
42+
43+
end package body;

0 commit comments

Comments
 (0)