Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron-Hartwig committed Nov 15, 2024
1 parent 69c45df commit 00261d2
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 46 deletions.
29 changes: 11 additions & 18 deletions hdl/ip/vhd/i2c/i2c_core.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ end entity;

architecture rtl of i2c_core is

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

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

-- defaults
v.do_start := '0';
v.do_stop := '0';
v.tx_byte_valid := '0';

case sm_reg.state is
Expand All @@ -124,25 +122,18 @@ begin
-- single cycle state to initiate a START
when START =>
v.state := WAIT_START;
v.do_start := '1';

-- wait for link layer to finish START sequence and load up the address byte
when WAIT_START =>
v.tx_byte := sm_reg.cmd.addr & is_read;
v.tx_byte_valid := '1';
if ll_ready then
v.state := WAIT_ADDR;
v.tx_byte := sm_reg.cmd.addr & is_read;
v.tx_byte_valid := '1';
end if;

-- wait for address byte to have been sent
when WAIT_ADDR =>
if ll_ready then
v.state := ADDR_ACK;
v.state := WAIT_ADDR_ACK;
end if;

-- take action based off the operation type and the ACK
when ADDR_ACK =>
if ll_ackd_valid then
-- wait for address byte to have been sent and for the peripheral to ACK
when WAIT_ADDR_ACK =>
if ll_ready = '1' and ll_ackd_valid = '1' then
if ll_ackd then
if sm_reg.cmd.op = Read or sm_reg.in_random_read then
v.state := READ;
Expand All @@ -160,7 +151,6 @@ begin
-- TODO: address nack error
v.state := STOP;
end if;

end if;

-- read as many bytes as requested
Expand Down Expand Up @@ -207,7 +197,6 @@ begin
-- initiate a STOP and clear state
when STOP =>
v.state := WAIT_STOP;
v.do_stop := '1';
v.bytes_done := (others => '0');
v.in_random_read := false;

Expand All @@ -218,6 +207,10 @@ begin
end if;
end case;

-- next state logic
v.do_start := '1' when v.state = START else '0';
v.do_stop := '1' when v.state = STOP else '0';

sm_reg_next <= v;
end process;

Expand Down
21 changes: 12 additions & 9 deletions hdl/ip/vhd/i2c/link_layer/i2c_link_layer.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ architecture rtl of i2c_link_layer is
WAIT_TBUF,
START_SETUP,
START_HOLD,
HANDLE_NEXT_PRE,
HANDLE_NEXT,
BYTE_TX,
BYTE_RX,
Expand Down Expand Up @@ -162,8 +163,7 @@ begin
begin
if reset then
scl_oe <= '0';
scl_redge <= '0';
scl_fedge <= '0';
scl_oe_last <= '0';
elsif rising_edge(clk) then
scl_oe_last <= scl_oe;
v_scl_oe_next := not scl_oe;
Expand Down Expand Up @@ -238,8 +238,6 @@ begin
v.rx_ack_valid := '0';
v.rx_data_valid := '0';

v.ready := '1' when sm_reg.state = IDLE or sm_reg.state = HANDLE_NEXT else '0';

-- after a scl fedge sda should be updated
if scl_fedge then
v.sda_change := '1';
Expand Down Expand Up @@ -283,13 +281,16 @@ begin
when START_HOLD =>
v.sda_oe := '1';
if sm_count_done then
v.state := HANDLE_NEXT;
v.state := HANDLE_NEXT_PRE;
v.scl_start := '1'; -- drop SCL to finish START condition
v.scl_active := '1'; -- begin free running counter for SCL transitions
else
v.count_decr := '1';
end if;

when HANDLE_NEXT_PRE =>
v.state := HANDLE_NEXT;

when HANDLE_NEXT =>
if tx_start then
-- A repeated start was issued mid-transaction
Expand All @@ -309,9 +310,8 @@ begin

-- Clock out a byte and then wait for an ACK
when BYTE_TX =>
v.sda_oe := not sm_reg.data(0);

if transition_sda = '1' and sm_reg.sda_change = '1' then
v.sda_oe := not sm_reg.data(0);
v.data := '1' & sm_reg.data(7 downto 1);
v.sda_change := '0';

Expand All @@ -328,7 +328,7 @@ begin
v.sda_oe := '0';

if scl_redge then
v.state := HANDLE_NEXT;
v.state := HANDLE_NEXT_PRE;
v.rx_ack := not sda_in_syncd;
v.rx_ack_valid := '1';
end if;
Expand Down Expand Up @@ -362,7 +362,7 @@ begin
v.sda_oe := '0';
v.ack_sending := '0';
v.sda_change := '0';
v.state := HANDLE_NEXT;
v.state := HANDLE_NEXT_PRE;
end if;

-- drive SDA through final SCL cycle
Expand Down Expand Up @@ -390,6 +390,9 @@ begin

end case;

-- next state logic
v.ready := '1' when (v.state = IDLE or v.state = HANDLE_NEXT_PRE or v.state = HANDLE_NEXT) else '0';

sm_reg_next <= v;
end process;

Expand Down
41 changes: 26 additions & 15 deletions hdl/ip/vhd/i2c/sims/i2c_peripheral.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ architecture model of i2c_peripheral is
GET_START_BYTE,
GET_REG_BYTE,
SEND_ACK,
SEND_NACK,
SEND_BYTE,
GET_BYTE,
GET_ACK,
Expand All @@ -41,13 +42,13 @@ architecture model of i2c_peripheral is

signal state : state_t := IDLE;

signal start_detected : std_logic := '0';
signal start_condition : std_logic := '0';
signal rx_data : std_logic_vector(7 downto 0) := (others => '0');
signal rx_bit_count : unsigned(3 downto 0) := (others => '0');
signal rx_done : std_logic := '0';
begin

start_detected <= '1' when sda = '0' and state = IDLE else '0';
start_condition <= '1' when sda = '0' and state = IDLE else '0';

message_handler: process
variable msg_type : msg_type_t;
Expand All @@ -60,27 +61,37 @@ begin
transaction_sm: process
variable event_msg : msg_t;
begin
wait on start_detected;
wait on start_condition;
event_msg := new_msg(got_start);
send(net, i2c_peripheral_vc.p_actor, event_msg);

state <= GET_START_BYTE;
wait on rx_done;
state <= SEND_ACK;
if rx_data(7 downto 1) = i2c_peripheral_vc.address then
state <= SEND_ACK;
event_msg := new_msg(address_matched);
send(net, i2c_peripheral_vc.p_actor, event_msg);
else
state <= SEND_NACK;
event_msg := new_msg(address_different);
send(net, i2c_peripheral_vc.p_actor, event_msg);
end if;
end process;

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

-- receive_sm: process
-- variable data_next : std_logic_vector(7 downto 0) := (others => '0');
-- begin
-- if state = GET_START_BYTE then
-- wait until rising_edge(scl);
-- data_next := sda & rx_data(7 downto 1);
-- rx_bit_count <= rx_bit_count + 1;
-- else
-- rx_bit_count <= (others => '0');
-- end if;
-- end process;
receive_sm: process
variable data_next : std_logic_vector(7 downto 0) := (others => '0');
begin
wait until rising_edge(scl);
if state = GET_START_BYTE then
data_next := sda & rx_data(7 downto 1);
rx_bit_count <= rx_bit_count + 1;
else
rx_bit_count <= (others => '0');
end if;

rx_data <= data_next;
end process;

end architecture;
4 changes: 1 addition & 3 deletions hdl/ip/vhd/i2c/sims/i2c_peripheral_pkg.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ package i2c_peripheral_pkg is

-- Message definitions
constant got_start : msg_type_t := new_msg_type("got_start");
constant start_byte : msg_type_t := new_msg_type("start_byte");
constant address_matched : msg_type_t := new_msg_type("address_matched");
constant address_different : msg_type_t := new_msg_type("address_different");
constant send_ack : msg_type_t := new_msg_type("send_ack");
constant got_ack : msg_type_t := new_msg_type("got_ack");
constant send_byte : msg_type_t := new_msg_type("send_byte");
Expand All @@ -29,7 +29,6 @@ package i2c_peripheral_pkg is
address : std_logic_vector(6 downto 0);
-- private
p_actor : actor_t;
p_ack_actor : actor_t;
p_memory : memory_t;
p_logger : logger_t;
end record;
Expand Down Expand Up @@ -57,7 +56,6 @@ package body i2c_peripheral_pkg is
return (
address => address,
p_actor => new_actor(name),
p_ack_actor => new_actor(name & "_ack"),
p_memory => to_vc_interface(memory, logger),
p_logger => logger
);
Expand Down
2 changes: 1 addition & 1 deletion hdl/ip/vhd/i2c/sims/i2c_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ begin
end process;

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

end tb;
43 changes: 43 additions & 0 deletions hdl/ip/vhd/i2c/sims/i2c_tb_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
--
-- Copyright 2024 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
context vunit_lib.vc_context;

use work.i2c_peripheral_pkg.all;

package i2c_tb_pkg is

procedure start_byte_ack (
signal net : inout network_t;
constant i2c_peripheral_vc : i2c_peripheral_t;
variable ack : inout boolean;
);

end package;

package body i2c_tb_pkg is

procedure start_byte_ack (
signal net : inout network_t;
constant i2c_peripheral_vc : i2c_peripheral_t;
variable ack : inout boolean;
) is
variable msg : msg_t;
begin
receive(net, i2c_peripheral_vc.p_actor, msg);
if message_type(msg) = got_start then

end if;
end procedure;

end package body;
Loading

0 comments on commit 00261d2

Please sign in to comment.