diff --git a/.github/workflows/icarus.yml b/.github/workflows/icarus.yml new file mode 100644 index 0000000..77ec4ef --- /dev/null +++ b/.github/workflows/icarus.yml @@ -0,0 +1,25 @@ +name: Icarus Verilog CI + +on: + push: + branches: [ "*" ] + pull_request: + branches: [ "*" ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y iverilog verilator + + - name: Compile with Icarus Verilog + run: iverilog -o sim_output -y rtl tb/i2c_master_tb.v + + - name: Run simulation + run: ./sim_output diff --git a/.gitignore b/.gitignore index 964df4d..4ea44bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.vvp *.kate-swp +.aider* diff --git a/rtl/axis_fifo.v b/rtl/axis_fifo.v index b8dfb0b..a33c27b 100644 --- a/rtl/axis_fifo.v +++ b/rtl/axis_fifo.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * AXI4-Stream FIFO */ -module axis_fifo # -( +module axis_fifo #( // FIFO depth in words // KEEP_WIDTH words per cycle if KEEP_ENABLE set // Rounded up to nearest power of 2 cycles @@ -39,9 +38,9 @@ module axis_fifo # parameter DATA_WIDTH = 8, // Propagate tkeep signal // If disabled, tkeep assumed to be 1'b1 - parameter KEEP_ENABLE = (DATA_WIDTH>8), + parameter KEEP_ENABLE = (DATA_WIDTH > 8), // tkeep signal width (words per cycle) - parameter KEEP_WIDTH = (DATA_WIDTH/8), + parameter KEEP_WIDTH = (DATA_WIDTH / 8), // Propagate tlast signal parameter LAST_ENABLE = 1, // Propagate tid signal @@ -73,218 +72,221 @@ module axis_fifo # // When set, s_axis_tready is always asserted // Requires FRAME_FIFO set parameter DROP_WHEN_FULL = 0 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * AXI input */ - input wire [DATA_WIDTH-1:0] s_axis_tdata, - input wire [KEEP_WIDTH-1:0] s_axis_tkeep, - input wire s_axis_tvalid, - output wire s_axis_tready, - input wire s_axis_tlast, - input wire [ID_WIDTH-1:0] s_axis_tid, - input wire [DEST_WIDTH-1:0] s_axis_tdest, - input wire [USER_WIDTH-1:0] s_axis_tuser, + input wire [DATA_WIDTH-1:0] s_axis_tdata, + input wire [KEEP_WIDTH-1:0] s_axis_tkeep, + input wire s_axis_tvalid, + output wire s_axis_tready, + input wire s_axis_tlast, + input wire [ ID_WIDTH-1:0] s_axis_tid, + input wire [DEST_WIDTH-1:0] s_axis_tdest, + input wire [USER_WIDTH-1:0] s_axis_tuser, /* * AXI output */ - output wire [DATA_WIDTH-1:0] m_axis_tdata, - output wire [KEEP_WIDTH-1:0] m_axis_tkeep, - output wire m_axis_tvalid, - input wire m_axis_tready, - output wire m_axis_tlast, - output wire [ID_WIDTH-1:0] m_axis_tid, - output wire [DEST_WIDTH-1:0] m_axis_tdest, - output wire [USER_WIDTH-1:0] m_axis_tuser, + output wire [DATA_WIDTH-1:0] m_axis_tdata, + output wire [KEEP_WIDTH-1:0] m_axis_tkeep, + output wire m_axis_tvalid, + input wire m_axis_tready, + output wire m_axis_tlast, + output wire [ ID_WIDTH-1:0] m_axis_tid, + output wire [DEST_WIDTH-1:0] m_axis_tdest, + output wire [USER_WIDTH-1:0] m_axis_tuser, /* * Status */ - output wire status_overflow, - output wire status_bad_frame, - output wire status_good_frame, - output wire status_full, - output wire status_empty + output wire status_overflow, + output wire status_bad_frame, + output wire status_good_frame, + output wire status_full, + output wire status_empty ); -parameter ADDR_WIDTH = (KEEP_ENABLE && KEEP_WIDTH > 1) ? $clog2(DEPTH/KEEP_WIDTH) : $clog2(DEPTH); + parameter ADDR_WIDTH = (KEEP_ENABLE && KEEP_WIDTH > 1) ? $clog2( + DEPTH / KEEP_WIDTH + ) : $clog2( + DEPTH + ); -// check configuration -initial begin + // check configuration + initial begin if (PIPELINE_OUTPUT < 1) begin - $error("Error: PIPELINE_OUTPUT must be at least 1 (instance %m)"); - $finish; + $error("Error: PIPELINE_OUTPUT must be at least 1 (instance %m)"); + $finish; end if (FRAME_FIFO && !LAST_ENABLE) begin - $error("Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)"); - $finish; + $error("Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)"); + $finish; end if (DROP_BAD_FRAME && !FRAME_FIFO) begin - $error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)"); - $finish; + $error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)"); + $finish; end if (DROP_WHEN_FULL && !FRAME_FIFO) begin - $error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)"); - $finish; + $error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)"); + $finish; end if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin - $error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"); - $finish; + $error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"); + $finish; end -end + end -localparam KEEP_OFFSET = DATA_WIDTH; -localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0); -localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0); -localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0); -localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); -localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); + localparam KEEP_OFFSET = DATA_WIDTH; + localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0); + localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0); + localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0); + localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0); + localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0); -reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}; -reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}; + reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH + 1{1'b0}}; + reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH + 1{1'b0}}; + reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH + 1{1'b0}}; -reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0]; -reg [WIDTH-1:0] mem_read_data_reg; -reg mem_read_data_valid_reg = 1'b0; + reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0]; + reg [WIDTH-1:0] mem_read_data_reg; + reg mem_read_data_valid_reg = 1'b0; -wire [WIDTH-1:0] s_axis; + wire [WIDTH-1:0] s_axis; -reg [WIDTH-1:0] m_axis_pipe_reg[PIPELINE_OUTPUT-1:0]; -reg [PIPELINE_OUTPUT-1:0] m_axis_tvalid_pipe_reg = 1'b0; + reg [WIDTH-1:0] m_axis_pipe_reg[PIPELINE_OUTPUT-1:0]; + reg [PIPELINE_OUTPUT-1:0] m_axis_tvalid_pipe_reg = 1'b0; -// full when first MSB different but rest same -wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -// empty when pointers match exactly -wire empty = wr_ptr_reg == rd_ptr_reg; -// overflow within packet -wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); + // full when first MSB different but rest same + wire full = wr_ptr_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); + wire full_cur = wr_ptr_cur_reg == (rd_ptr_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); + // empty when pointers match exactly + wire empty = wr_ptr_reg == rd_ptr_reg; + // overflow within packet + wire full_wr = wr_ptr_reg == (wr_ptr_cur_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); -reg drop_frame_reg = 1'b0; -reg overflow_reg = 1'b0; -reg bad_frame_reg = 1'b0; -reg good_frame_reg = 1'b0; + reg drop_frame_reg = 1'b0; + reg overflow_reg = 1'b0; + reg bad_frame_reg = 1'b0; + reg good_frame_reg = 1'b0; -assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full; + assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full; -generate + generate assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata; - if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep; - if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; - if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid; - if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest; - if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser; -endgenerate - -assign m_axis_tvalid = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1]; - -assign m_axis_tdata = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0]; -assign m_axis_tkeep = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}}; -assign m_axis_tlast = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1; -assign m_axis_tid = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}}; -assign m_axis_tdest = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}}; -assign m_axis_tuser = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}}; - -assign status_overflow = overflow_reg; -assign status_bad_frame = bad_frame_reg; -assign status_good_frame = good_frame_reg; -assign status_full = FRAME_FIFO ? full_cur || full_wr : full; -assign status_empty = empty; - -// Write logic -always @(posedge clk) begin - overflow_reg <= 1'b0; - bad_frame_reg <= 1'b0; + if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET+:KEEP_WIDTH] = s_axis_tkeep; + if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; + if (ID_ENABLE) assign s_axis[ID_OFFSET+:ID_WIDTH] = s_axis_tid; + if (DEST_ENABLE) assign s_axis[DEST_OFFSET+:DEST_WIDTH] = s_axis_tdest; + if (USER_ENABLE) assign s_axis[USER_OFFSET+:USER_WIDTH] = s_axis_tuser; + endgenerate + + assign m_axis_tvalid = m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1]; + + assign m_axis_tdata = m_axis_pipe_reg[PIPELINE_OUTPUT-1][DATA_WIDTH-1:0]; + assign m_axis_tkeep = KEEP_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}}; + assign m_axis_tlast = LAST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][LAST_OFFSET] : 1'b1; + assign m_axis_tid = ID_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}}; + assign m_axis_tdest = DEST_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}}; + assign m_axis_tuser = USER_ENABLE ? m_axis_pipe_reg[PIPELINE_OUTPUT-1][USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}}; + + assign status_overflow = overflow_reg; + assign status_bad_frame = bad_frame_reg; + assign status_good_frame = good_frame_reg; + assign status_full = FRAME_FIFO ? full_cur || full_wr : full; + assign status_empty = empty; + + // Write logic + always @(posedge clk) begin + overflow_reg <= 1'b0; + bad_frame_reg <= 1'b0; good_frame_reg <= 1'b0; if (s_axis_tready && s_axis_tvalid) begin - // transfer in - if (!FRAME_FIFO) begin - // normal FIFO mode - mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; - wr_ptr_reg <= wr_ptr_reg + 1; - end else if (full_cur || full_wr || drop_frame_reg) begin - // full, packet overflow, or currently dropping frame - // drop frame - drop_frame_reg <= 1'b1; - if (s_axis_tlast) begin - // end of frame, reset write pointer - wr_ptr_cur_reg <= wr_ptr_reg; - drop_frame_reg <= 1'b0; - overflow_reg <= 1'b1; - end - end else begin - mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis; - wr_ptr_cur_reg <= wr_ptr_cur_reg + 1; - if (s_axis_tlast) begin - // end of frame - if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin - // bad packet, reset write pointer - wr_ptr_cur_reg <= wr_ptr_reg; - bad_frame_reg <= 1'b1; - end else begin - // good packet, update write pointer - wr_ptr_reg <= wr_ptr_cur_reg + 1; - good_frame_reg <= 1'b1; - end - end + // transfer in + if (!FRAME_FIFO) begin + // normal FIFO mode + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_reg <= wr_ptr_reg + 1; + end else if (full_cur || full_wr || drop_frame_reg) begin + // full, packet overflow, or currently dropping frame + // drop frame + drop_frame_reg <= 1'b1; + if (s_axis_tlast) begin + // end of frame, reset write pointer + wr_ptr_cur_reg <= wr_ptr_reg; + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b1; end + end else begin + mem[wr_ptr_cur_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_cur_reg <= wr_ptr_cur_reg + 1; + if (s_axis_tlast) begin + // end of frame + if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin + // bad packet, reset write pointer + wr_ptr_cur_reg <= wr_ptr_reg; + bad_frame_reg <= 1'b1; + end else begin + // good packet, update write pointer + wr_ptr_reg <= wr_ptr_cur_reg + 1; + good_frame_reg <= 1'b1; + end + end + end end if (rst) begin - wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}}; + wr_ptr_reg <= {ADDR_WIDTH + 1{1'b0}}; + wr_ptr_cur_reg <= {ADDR_WIDTH + 1{1'b0}}; - drop_frame_reg <= 1'b0; - overflow_reg <= 1'b0; - bad_frame_reg <= 1'b0; - good_frame_reg <= 1'b0; + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b0; + bad_frame_reg <= 1'b0; + good_frame_reg <= 1'b0; end -end + end -// Read logic -integer j; + // Read logic + integer j; -always @(posedge clk) begin + always @(posedge clk) begin if (m_axis_tready) begin - // output ready; invalidate stage - m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b0; + // output ready; invalidate stage + m_axis_tvalid_pipe_reg[PIPELINE_OUTPUT-1] <= 1'b0; end - for (j = PIPELINE_OUTPUT-1; j > 0; j = j - 1) begin - if (m_axis_tready || ((~m_axis_tvalid_pipe_reg) >> j)) begin - // output ready or bubble in pipeline; transfer down pipeline - m_axis_tvalid_pipe_reg[j] <= m_axis_tvalid_pipe_reg[j-1]; - m_axis_pipe_reg[j] <= m_axis_pipe_reg[j-1]; - m_axis_tvalid_pipe_reg[j-1] <= 1'b0; - end + for (j = PIPELINE_OUTPUT - 1; j > 0; j = j - 1) begin + if (m_axis_tready || ((~m_axis_tvalid_pipe_reg) >> j)) begin + // output ready or bubble in pipeline; transfer down pipeline + m_axis_tvalid_pipe_reg[j] <= m_axis_tvalid_pipe_reg[j-1]; + m_axis_pipe_reg[j] <= m_axis_pipe_reg[j-1]; + m_axis_tvalid_pipe_reg[j-1] <= 1'b0; + end end if (m_axis_tready || ~m_axis_tvalid_pipe_reg) begin - // output ready or bubble in pipeline; read new data from FIFO - m_axis_tvalid_pipe_reg[0] <= 1'b0; - m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]]; - if (!empty) begin - // not empty, increment pointer - m_axis_tvalid_pipe_reg[0] <= 1'b1; - rd_ptr_reg <= rd_ptr_reg + 1; - end + // output ready or bubble in pipeline; read new data from FIFO + m_axis_tvalid_pipe_reg[0] <= 1'b0; + m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]]; + if (!empty) begin + // not empty, increment pointer + m_axis_tvalid_pipe_reg[0] <= 1'b1; + rd_ptr_reg <= rd_ptr_reg + 1; + end end if (rst) begin - rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; - m_axis_tvalid_pipe_reg <= {PIPELINE_OUTPUT{1'b0}}; + rd_ptr_reg <= {ADDR_WIDTH + 1{1'b0}}; + m_axis_tvalid_pipe_reg <= {PIPELINE_OUTPUT{1'b0}}; end -end + end endmodule diff --git a/rtl/i2c_init.v b/rtl/i2c_init.v index ebef6c1..ba1b588 100644 --- a/rtl/i2c_init.v +++ b/rtl/i2c_init.v @@ -30,38 +30,38 @@ THE SOFTWARE. * I2C init */ module i2c_init ( - input wire clk, - input wire rst, + input wire clk, + input wire rst, /* * I2C master interface */ - output wire [6:0] m_axis_cmd_address, - output wire m_axis_cmd_start, - output wire m_axis_cmd_read, - output wire m_axis_cmd_write, - output wire m_axis_cmd_write_multiple, - output wire m_axis_cmd_stop, - output wire m_axis_cmd_valid, - input wire m_axis_cmd_ready, - - output wire [7:0] m_axis_data_tdata, - output wire m_axis_data_tvalid, - input wire m_axis_data_tready, - output wire m_axis_data_tlast, + output wire [6:0] m_axis_cmd_address, + output wire m_axis_cmd_start, + output wire m_axis_cmd_read, + output wire m_axis_cmd_write, + output wire m_axis_cmd_write_multiple, + output wire m_axis_cmd_stop, + output wire m_axis_cmd_valid, + input wire m_axis_cmd_ready, + + output wire [7:0] m_axis_data_tdata, + output wire m_axis_data_tvalid, + input wire m_axis_data_tready, + output wire m_axis_data_tlast, /* * Status */ - output wire busy, + output wire busy, /* * Configuration */ - input wire start + input wire start ); -/* + /* Generic module for I2C bus initialization. Good for use when multiple devices on an I2C bus must be initialized on system start without intervention of a @@ -134,87 +134,87 @@ write 0x11223344 to register 0x0004 on devices at 0x50, 0x51, 0x52, and 0x53 */ -// init_data ROM -localparam INIT_DATA_LEN = 22; + // init_data ROM + localparam INIT_DATA_LEN = 22; -reg [8:0] init_data [INIT_DATA_LEN-1:0]; + reg [8:0] init_data[INIT_DATA_LEN-1:0]; -initial begin + initial begin // single address - init_data[0] = {2'b01, 7'h50}; // start write to address 0x50 - init_data[1] = {1'b1, 8'h00}; // write address 0x0004 + init_data[0] = {2'b01, 7'h50}; // start write to address 0x50 + init_data[1] = {1'b1, 8'h00}; // write address 0x0004 init_data[2] = {1'b1, 8'h04}; - init_data[3] = {1'b1, 8'h11}; // write data 0x11223344 + init_data[3] = {1'b1, 8'h11}; // write data 0x11223344 init_data[4] = {1'b1, 8'h22}; init_data[5] = {1'b1, 8'h33}; init_data[6] = {1'b1, 8'h44}; // multiple addresses - init_data[7] = {2'b00, 7'b0001001}; // start data block - init_data[8] = {2'b00, 7'b0000011}; // start write to current address - init_data[9] = {1'b1, 8'h00}; // write address 0x0004 + init_data[7] = {2'b00, 7'b0001001}; // start data block + init_data[8] = {2'b00, 7'b0000011}; // start write to current address + init_data[9] = {1'b1, 8'h00}; // write address 0x0004 init_data[10] = {1'b1, 8'h04}; - init_data[11] = {1'b1, 8'h11}; // write data 0x11223344 + init_data[11] = {1'b1, 8'h11}; // write data 0x11223344 init_data[12] = {1'b1, 8'h22}; init_data[13] = {1'b1, 8'h33}; init_data[14] = {1'b1, 8'h44}; - init_data[15] = {2'b00, 7'b0001000}; // start address block - init_data[16] = {2'b01, 7'h50}; // start write to address 0x50 - init_data[17] = {2'b01, 7'h51}; // start write to address 0x51 - init_data[18] = {2'b01, 7'h52}; // start write to address 0x52 - init_data[19] = {2'b01, 7'h53}; // start write to address 0x53 - init_data[20] = 9'd1; // exit mode - init_data[21] = 9'd0; // stop -end - -localparam [3:0] + init_data[15] = {2'b00, 7'b0001000}; // start address block + init_data[16] = {2'b01, 7'h50}; // start write to address 0x50 + init_data[17] = {2'b01, 7'h51}; // start write to address 0x51 + init_data[18] = {2'b01, 7'h52}; // start write to address 0x52 + init_data[19] = {2'b01, 7'h53}; // start write to address 0x53 + init_data[20] = 9'd1; // exit mode + init_data[21] = 9'd0; // stop + end + + localparam [3:0] STATE_IDLE = 3'd0, STATE_RUN = 3'd1, STATE_TABLE_1 = 3'd2, STATE_TABLE_2 = 3'd3, STATE_TABLE_3 = 3'd4; -reg [4:0] state_reg = STATE_IDLE, state_next; + reg [4:0] state_reg = STATE_IDLE, state_next; -parameter AW = $clog2(INIT_DATA_LEN); + parameter AW = $clog2(INIT_DATA_LEN); -reg [8:0] init_data_reg = 9'd0; + reg [8:0] init_data_reg = 9'd0; -reg [AW-1:0] address_reg = {AW{1'b0}}, address_next; -reg [AW-1:0] address_ptr_reg = {AW{1'b0}}, address_ptr_next; -reg [AW-1:0] data_ptr_reg = {AW{1'b0}}, data_ptr_next; + reg [AW-1:0] address_reg = {AW{1'b0}}, address_next; + reg [AW-1:0] address_ptr_reg = {AW{1'b0}}, address_ptr_next; + reg [AW-1:0] data_ptr_reg = {AW{1'b0}}, data_ptr_next; -reg [6:0] cur_address_reg = 7'd0, cur_address_next; + reg [6:0] cur_address_reg = 7'd0, cur_address_next; -reg [31:0] delay_counter_reg = 32'd0, delay_counter_next; + reg [31:0] delay_counter_reg = 32'd0, delay_counter_next; -reg [6:0] m_axis_cmd_address_reg = 7'd0, m_axis_cmd_address_next; -reg m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next; -reg m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next; -reg m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next; -reg m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next; + reg [6:0] m_axis_cmd_address_reg = 7'd0, m_axis_cmd_address_next; + reg m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next; + reg m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next; + reg m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next; + reg m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next; -reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; -reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; -reg start_flag_reg = 1'b0, start_flag_next; + reg start_flag_reg = 1'b0, start_flag_next; -reg busy_reg = 1'b0; + reg busy_reg = 1'b0; -assign m_axis_cmd_address = m_axis_cmd_address_reg; -assign m_axis_cmd_start = m_axis_cmd_start_reg; -assign m_axis_cmd_read = 1'b0; -assign m_axis_cmd_write = m_axis_cmd_write_reg; -assign m_axis_cmd_write_multiple = 1'b0; -assign m_axis_cmd_stop = m_axis_cmd_stop_reg; -assign m_axis_cmd_valid = m_axis_cmd_valid_reg; + assign m_axis_cmd_address = m_axis_cmd_address_reg; + assign m_axis_cmd_start = m_axis_cmd_start_reg; + assign m_axis_cmd_read = 1'b0; + assign m_axis_cmd_write = m_axis_cmd_write_reg; + assign m_axis_cmd_write_multiple = 1'b0; + assign m_axis_cmd_stop = m_axis_cmd_stop_reg; + assign m_axis_cmd_valid = m_axis_cmd_valid_reg; -assign m_axis_data_tdata = m_axis_data_tdata_reg; -assign m_axis_data_tvalid = m_axis_data_tvalid_reg; -assign m_axis_data_tlast = 1'b1; + assign m_axis_data_tdata = m_axis_data_tdata_reg; + assign m_axis_data_tvalid = m_axis_data_tvalid_reg; + assign m_axis_data_tlast = 1'b1; -assign busy = busy_reg; + assign busy = busy_reg; -always @* begin + always @* begin state_next = STATE_IDLE; address_next = address_reg; @@ -237,216 +237,216 @@ always @* begin start_flag_next = start_flag_reg; if (m_axis_cmd_valid | m_axis_data_tvalid) begin - // wait for output registers to clear - state_next = state_reg; + // wait for output registers to clear + state_next = state_reg; end else if (delay_counter_reg != 0) begin - // delay - delay_counter_next = delay_counter_reg - 1; - state_next = state_reg; + // delay + delay_counter_next = delay_counter_reg - 1; + state_next = state_reg; end else begin - case (state_reg) - STATE_IDLE: begin - // wait for start signal - if (~start_flag_reg & start) begin - address_next = {AW{1'b0}}; - start_flag_next = 1'b1; - state_next = STATE_RUN; - end else begin - state_next = STATE_IDLE; - end - end - STATE_RUN: begin - // process commands - if (init_data_reg[8] == 1'b1) begin - // write data - m_axis_cmd_write_next = 1'b1; - m_axis_cmd_stop_next = 1'b0; - m_axis_cmd_valid_next = 1'b1; - - m_axis_data_tdata_next = init_data_reg[7:0]; - m_axis_data_tvalid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg[8:7] == 2'b01) begin - // write address - m_axis_cmd_address_next = init_data_reg[6:0]; - m_axis_cmd_start_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg[8:4] == 5'b00001) begin - // delay - delay_counter_next = 32'd1 << (init_data_reg[3:0]+16); - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg == 9'b001000001) begin - // send stop - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_RUN; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_RUN; - end - end - STATE_TABLE_1: begin - // find address table start - if (init_data_reg == 9'b000001000) begin - // address table start - address_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_2; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 1) begin - // exit mode - address_next = address_reg + 1; - state_next = STATE_RUN; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end - end - STATE_TABLE_2: begin - // find next address - if (init_data_reg[8:7] == 2'b01) begin - // write address command - // store address and move to data table - cur_address_next = init_data_reg[6:0]; - address_ptr_next = address_reg + 1; - address_next = data_ptr_reg; - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 9'd1) begin - // exit mode - address_next = address_reg + 1; - state_next = STATE_RUN; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_TABLE_2; - end - end - STATE_TABLE_3: begin - // process data table with selected address - if (init_data_reg[8] == 1'b1) begin - // write data - m_axis_cmd_write_next = 1'b1; - m_axis_cmd_stop_next = 1'b0; - m_axis_cmd_valid_next = 1'b1; - - m_axis_data_tdata_next = init_data_reg[7:0]; - m_axis_data_tvalid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg[8:7] == 2'b01) begin - // write address - m_axis_cmd_address_next = init_data_reg[6:0]; - m_axis_cmd_start_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b000000011) begin - // write current address - m_axis_cmd_address_next = cur_address_reg; - m_axis_cmd_start_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b001000001) begin - // send stop - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - address_next = address_reg + 1; - - state_next = STATE_TABLE_3; - end else if (init_data_reg == 9'b000001001) begin - // data table start - data_ptr_next = address_reg + 1; - address_next = address_reg + 1; - state_next = STATE_TABLE_1; - end else if (init_data_reg == 9'b000001000) begin - // address table start - address_next = address_ptr_reg; - state_next = STATE_TABLE_2; - end else if (init_data_reg == 9'd1) begin - // exit mode - address_next = address_reg + 1; - state_next = STATE_RUN; - end else if (init_data_reg == 9'd0) begin - // stop - m_axis_cmd_start_next = 1'b0; - m_axis_cmd_write_next = 1'b0; - m_axis_cmd_stop_next = 1'b1; - m_axis_cmd_valid_next = 1'b1; - - state_next = STATE_IDLE; - end else begin - // invalid command, skip - address_next = address_reg + 1; - state_next = STATE_TABLE_3; - end - end - endcase + case (state_reg) + STATE_IDLE: begin + // wait for start signal + if (~start_flag_reg & start) begin + address_next = {AW{1'b0}}; + start_flag_next = 1'b1; + state_next = STATE_RUN; + end else begin + state_next = STATE_IDLE; + end + end + STATE_RUN: begin + // process commands + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_data_tdata_next = init_data_reg[7:0]; + m_axis_data_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:4] == 5'b00001) begin + // delay + delay_counter_next = 32'd1 << (init_data_reg[3:0] + 16); + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_RUN; + end + end + STATE_TABLE_1: begin + // find address table start + if (init_data_reg == 9'b000001000) begin + // address table start + address_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end + end + STATE_TABLE_2: begin + // find next address + if (init_data_reg[8:7] == 2'b01) begin + // write address command + // store address and move to data table + cur_address_next = init_data_reg[6:0]; + address_ptr_next = address_reg + 1; + address_next = data_ptr_reg; + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end + end + STATE_TABLE_3: begin + // process data table with selected address + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_data_tdata_next = init_data_reg[7:0]; + m_axis_data_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000000011) begin + // write current address + m_axis_cmd_address_next = cur_address_reg; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'b000001000) begin + // address table start + address_next = address_ptr_reg; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_3; + end + end + endcase end -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; // read init_data ROM @@ -474,26 +474,26 @@ always @(posedge clk) begin busy_reg <= (state_reg != STATE_IDLE); if (rst) begin - state_reg <= STATE_IDLE; + state_reg <= STATE_IDLE; - init_data_reg <= 9'd0; + init_data_reg <= 9'd0; - address_reg <= {AW{1'b0}}; - address_ptr_reg <= {AW{1'b0}}; - data_ptr_reg <= {AW{1'b0}}; + address_reg <= {AW{1'b0}}; + address_ptr_reg <= {AW{1'b0}}; + data_ptr_reg <= {AW{1'b0}}; - cur_address_reg <= 7'd0; + cur_address_reg <= 7'd0; - delay_counter_reg <= 32'd0; + delay_counter_reg <= 32'd0; - m_axis_cmd_valid_reg <= 1'b0; + m_axis_cmd_valid_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; - start_flag_reg <= 1'b0; + start_flag_reg <= 1'b0; - busy_reg <= 1'b0; + busy_reg <= 1'b0; end -end + end endmodule diff --git a/rtl/i2c_master.v b/rtl/i2c_master.v index 9c69b48..7a542f0 100644 --- a/rtl/i2c_master.v +++ b/rtl/i2c_master.v @@ -29,41 +29,44 @@ THE SOFTWARE. /* * I2C master */ -module i2c_master ( - input wire clk, - input wire rst, +module i2c_master #( + parameter DEBUG = 0 +) ( + input wire clk, + input wire rst_n, /* * Host interface */ - input wire [6:0] s_axis_cmd_address, - input wire s_axis_cmd_start, - input wire s_axis_cmd_read, - input wire s_axis_cmd_write, - input wire s_axis_cmd_write_multiple, - input wire s_axis_cmd_stop, - input wire s_axis_cmd_valid, - output wire s_axis_cmd_ready, - - input wire [7:0] s_axis_data_tdata, - input wire s_axis_data_tvalid, - output wire s_axis_data_tready, - input wire s_axis_data_tlast, - - output wire [7:0] m_axis_data_tdata, - output wire m_axis_data_tvalid, - input wire m_axis_data_tready, - output wire m_axis_data_tlast, + input wire [6:0] s_axis_cmd_address, + input wire s_axis_cmd_start, + input wire s_axis_cmd_read, + input wire s_axis_cmd_write, + input wire s_axis_cmd_write_multiple, + input wire s_axis_cmd_stop, + input wire s_axis_cmd_valid, + output wire s_axis_cmd_ready, + + input wire [7:0] s_axis_data_tdata, + input wire s_axis_data_tvalid, + output wire s_axis_data_tready, + input wire s_axis_data_tlast, + + output wire [7:0] m_axis_data_tdata, + output wire m_axis_data_tvalid, + input wire m_axis_data_tready, + output wire m_axis_data_tlast, + /* * I2C interface */ - input wire scl_i, - output wire scl_o, - output wire scl_t, - input wire sda_i, - output wire sda_o, - output wire sda_t, + input wire scl_i, + output wire scl_o, + output wire scl_t, + input wire sda_i, + output wire sda_o, + output wire sda_t, /* * Status @@ -72,7 +75,7 @@ module i2c_master ( output wire bus_control, output wire bus_active, output wire missed_ack, - + output wire value_has_been_written, //triggers on last value /* * Configuration */ @@ -80,7 +83,7 @@ module i2c_master ( input wire stop_on_idle ); -/* + /* I2C @@ -181,24 +184,24 @@ scl_o should not be connected directly to scl_i, only via AND logic or a tristat I/O pin. This would prevent devices from stretching the clock period. */ - -localparam [4:0] - STATE_IDLE = 4'd0, - STATE_ACTIVE_WRITE = 4'd1, - STATE_ACTIVE_READ = 4'd2, - STATE_START_WAIT = 4'd3, - STATE_START = 4'd4, - STATE_ADDRESS_1 = 4'd5, - STATE_ADDRESS_2 = 4'd6, - STATE_WRITE_1 = 4'd7, - STATE_WRITE_2 = 4'd8, - STATE_WRITE_3 = 4'd9, - STATE_READ = 4'd10, - STATE_STOP = 4'd11; - -reg [4:0] state_reg = STATE_IDLE, state_next; - -localparam [4:0] + localparam [4:0] + STATE_IDLE = 5'd0, + STATE_ACTIVE_WRITE = 5'd1, + STATE_ACTIVE_READ = 5'd2, + STATE_START_WAIT = 5'd3, + STATE_START = 5'd4, + STATE_ADDRESS_1 = 5'd5, + STATE_ADDRESS_2 = 5'd6, + STATE_WRITE_1 = 5'd7, + STATE_WRITE_2 = 5'd8, + STATE_WRITE_3 = 5'd9, + STATE_READ = 5'd10, + STATE_STOP = 5'd11; + + + reg [4:0] state_reg = STATE_IDLE, state_next; + + localparam [4:0] PHY_STATE_IDLE = 5'd0, PHY_STATE_ACTIVE = 5'd1, PHY_STATE_REPEATED_START_1 = 5'd2, @@ -216,81 +219,82 @@ localparam [4:0] PHY_STATE_STOP_2 = 5'd14, PHY_STATE_STOP_3 = 5'd15; -reg [4:0] phy_state_reg = STATE_IDLE, phy_state_next; - -reg phy_start_bit; -reg phy_stop_bit; -reg phy_write_bit; -reg phy_read_bit; -reg phy_release_bus; + wire [4:0] phy_state_reg; -reg phy_tx_data; + reg phy_start_bit; + reg phy_stop_bit; + reg phy_write_bit; + reg phy_read_bit; + reg phy_release_bus; -reg phy_rx_data_reg = 1'b0, phy_rx_data_next; + reg phy_tx_data; -reg [6:0] addr_reg = 7'd0, addr_next; -reg [7:0] data_reg = 8'd0, data_next; -reg last_reg = 1'b0, last_next; + //reg phy_rx_data_reg = 1'b0, phy_rx_data_next; + wire phy_rx_data_reg; -reg mode_read_reg = 1'b0, mode_read_next; -reg mode_write_multiple_reg = 1'b0, mode_write_multiple_next; -reg mode_stop_reg = 1'b0, mode_stop_next; + reg [6:0] addr_reg = 7'd0, addr_next; + reg [7:0] data_reg = 8'd0, data_next; + reg last_reg = 1'b0, last_next; -reg [16:0] delay_reg = 16'd0, delay_next; -reg delay_scl_reg = 1'b0, delay_scl_next; -reg delay_sda_reg = 1'b0, delay_sda_next; + reg mode_read_reg = 1'b0, mode_read_next; + reg mode_write_multiple_reg = 1'b0, mode_write_multiple_next; + reg mode_stop_reg = 1'b0, mode_stop_next; -reg [3:0] bit_count_reg = 4'd0, bit_count_next; -reg s_axis_cmd_ready_reg = 1'b0, s_axis_cmd_ready_next; + reg [3:0] bit_count_reg = 4'd0, bit_count_next; -reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; + reg s_axis_cmd_ready_reg = 1'b0, s_axis_cmd_ready_next; -reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; -reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; -reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; -reg scl_i_reg = 1'b1; -reg sda_i_reg = 1'b1; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; + reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg value_has_been_written_reg = 1'b0; -reg scl_o_reg = 1'b1, scl_o_next; -reg sda_o_reg = 1'b1, sda_o_next; + reg scl_i_reg = 1'b1; + reg sda_i_reg = 1'b1; -reg last_scl_i_reg = 1'b1; -reg last_sda_i_reg = 1'b1; + reg scl_o_reg = 1'b1, scl_o_next; + reg sda_o_reg = 1'b1, sda_o_next; -reg busy_reg = 1'b0; -reg bus_active_reg = 1'b0; -reg bus_control_reg = 1'b0, bus_control_next; -reg missed_ack_reg = 1'b0, missed_ack_next; + reg last_scl_i_reg = 1'b1; + reg last_sda_i_reg = 1'b1; -assign s_axis_cmd_ready = s_axis_cmd_ready_reg; + reg busy_reg = 1'b0; + reg bus_active_reg = 1'b0; + wire bus_control_reg; + wire phy_busy; + //reg bus_control_reg = 1'b0, bus_control_next; + reg missed_ack_reg = 1'b0, missed_ack_next; + assign value_has_been_written = value_has_been_written_reg; + assign s_axis_cmd_ready = s_axis_cmd_ready_reg; -assign s_axis_data_tready = s_axis_data_tready_reg; + assign s_axis_data_tready = s_axis_data_tready_reg; -assign m_axis_data_tdata = m_axis_data_tdata_reg; -assign m_axis_data_tvalid = m_axis_data_tvalid_reg; -assign m_axis_data_tlast = m_axis_data_tlast_reg; + assign m_axis_data_tdata = m_axis_data_tdata_reg; + assign m_axis_data_tvalid = m_axis_data_tvalid_reg; + assign m_axis_data_tlast = m_axis_data_tlast_reg; -assign scl_o = scl_o_reg; -assign scl_t = scl_o_reg; -assign sda_o = sda_o_reg; -assign sda_t = sda_o_reg; + //assign scl_o = scl_o_reg; + //assign scl_t = scl_o_reg; + //assign sda_o = sda_o_reg; + //assign sda_t = sda_o_reg; -assign busy = busy_reg; -assign bus_active = bus_active_reg; -assign bus_control = bus_control_reg; -assign missed_ack = missed_ack_reg; + assign busy = busy_reg; + assign bus_active = bus_active_reg; + assign bus_control = bus_control_reg; + assign missed_ack = missed_ack_reg; -wire scl_posedge = scl_i_reg & ~last_scl_i_reg; -wire scl_negedge = ~scl_i_reg & last_scl_i_reg; -wire sda_posedge = sda_i_reg & ~last_sda_i_reg; -wire sda_negedge = ~sda_i_reg & last_sda_i_reg; + wire scl_posedge = scl_i_reg & ~last_scl_i_reg; + wire scl_negedge = ~scl_i_reg & last_scl_i_reg; + wire sda_posedge = sda_i_reg & ~last_sda_i_reg; + wire sda_negedge = ~sda_i_reg & last_sda_i_reg; -wire start_bit = sda_negedge & scl_i_reg; -wire stop_bit = sda_posedge & scl_i_reg; + wire start_bit = sda_negedge & scl_i_reg; + wire stop_bit = sda_posedge & scl_i_reg; -always @* begin + always @* begin state_next = STATE_IDLE; phy_start_bit = 1'b0; @@ -317,581 +321,391 @@ always @* begin m_axis_data_tdata_next = m_axis_data_tdata_reg; m_axis_data_tvalid_next = m_axis_data_tvalid_reg & ~m_axis_data_tready; m_axis_data_tlast_next = m_axis_data_tlast_reg; + value_has_been_written_reg = 1'b0; missed_ack_next = 1'b0; // generate delays if (phy_state_reg != PHY_STATE_IDLE && phy_state_reg != PHY_STATE_ACTIVE) begin - // wait for phy operation - state_next = state_reg; + // wait for phy operation + state_next = state_reg; end else begin - // process states - case (state_reg) - STATE_IDLE: begin - // line idle - s_axis_cmd_ready_next = 1'b1; - - if (s_axis_cmd_ready & s_axis_cmd_valid) begin - // command valid - if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin - // read or write command - addr_next = s_axis_cmd_address; - mode_read_next = s_axis_cmd_read; - mode_write_multiple_next = s_axis_cmd_write_multiple; - mode_stop_next = s_axis_cmd_stop; - - s_axis_cmd_ready_next = 1'b0; - - // start bit - if (bus_active) begin - state_next = STATE_START_WAIT; - end else begin - phy_start_bit = 1'b1; - bit_count_next = 4'd8; - state_next = STATE_ADDRESS_1; - end - end else begin - // invalid or unspecified - ignore - state_next = STATE_IDLE; - end - end else begin - state_next = STATE_IDLE; - end - end - STATE_ACTIVE_WRITE: begin - // line active with current address and read/write mode - s_axis_cmd_ready_next = 1'b1; - - if (s_axis_cmd_ready & s_axis_cmd_valid) begin - // command valid - if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin - // read or write command - addr_next = s_axis_cmd_address; - mode_read_next = s_axis_cmd_read; - mode_write_multiple_next = s_axis_cmd_write_multiple; - mode_stop_next = s_axis_cmd_stop; - - s_axis_cmd_ready_next = 1'b0; - - if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_read) begin - // address or mode mismatch or forced start - repeated start - - // repeated start bit - phy_start_bit = 1'b1; - bit_count_next = 4'd8; - state_next = STATE_ADDRESS_1; - end else begin - // address and mode match - - // start write - s_axis_data_tready_next = 1'b1; - state_next = STATE_WRITE_1; - end - end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin - // stop command - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end else begin - // invalid or unspecified - ignore - state_next = STATE_ACTIVE_WRITE; - end - end else begin - if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin - // no waiting command and stop_on_idle selected, issue stop condition - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end else begin - state_next = STATE_ACTIVE_WRITE; - end - end - end - STATE_ACTIVE_READ: begin - // line active to current address - s_axis_cmd_ready_next = ~m_axis_data_tvalid; - - if (s_axis_cmd_ready & s_axis_cmd_valid) begin - // command valid - if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin - // read or write command - addr_next = s_axis_cmd_address; - mode_read_next = s_axis_cmd_read; - mode_write_multiple_next = s_axis_cmd_write_multiple; - mode_stop_next = s_axis_cmd_stop; - - s_axis_cmd_ready_next = 1'b0; - - if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_write) begin - // address or mode mismatch or forced start - repeated start - - // write nack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - // repeated start bit - state_next = STATE_START; - end else begin - // address and mode match - - // write ack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b0; - // start next read - bit_count_next = 4'd8; - data_next = 8'd0; - state_next = STATE_READ; - end - end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin - // stop command - // write nack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - // send stop bit - state_next = STATE_STOP; - end else begin - // invalid or unspecified - ignore - state_next = STATE_ACTIVE_READ; - end - end else begin - if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin - // no waiting command and stop_on_idle selected, issue stop condition - // write ack for previous read - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - // send stop bit - state_next = STATE_STOP; - end else begin - state_next = STATE_ACTIVE_READ; - end - end - end - STATE_START_WAIT: begin - // wait for bus idle - - if (bus_active) begin - state_next = STATE_START_WAIT; - end else begin - // bus is idle, take control - phy_start_bit = 1'b1; - bit_count_next = 4'd8; - state_next = STATE_ADDRESS_1; - end - end - STATE_START: begin - // send start bit - + // process states + case (state_reg) + STATE_IDLE: begin + // line idle + s_axis_cmd_ready_next = 1'b1; + + if (s_axis_cmd_ready & s_axis_cmd_valid) begin + // command valid + if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin + // read or write command + addr_next = s_axis_cmd_address; + mode_read_next = s_axis_cmd_read; + mode_write_multiple_next = s_axis_cmd_write_multiple; + mode_stop_next = s_axis_cmd_stop; + + s_axis_cmd_ready_next = 1'b0; + + // start bit + if (bus_active) begin + state_next = STATE_START_WAIT; + end else begin phy_start_bit = 1'b1; bit_count_next = 4'd8; state_next = STATE_ADDRESS_1; + end + end else begin + // invalid or unspecified - ignore + state_next = STATE_IDLE; end - STATE_ADDRESS_1: begin - // send address - bit_count_next = bit_count_reg - 1; - if (bit_count_reg > 1) begin - // send address - phy_write_bit = 1'b1; - phy_tx_data = addr_reg[bit_count_reg-2]; - state_next = STATE_ADDRESS_1; - end else if (bit_count_reg > 0) begin - // send read/write bit - phy_write_bit = 1'b1; - phy_tx_data = mode_read_reg; - state_next = STATE_ADDRESS_1; - end else begin - // read ack bit - phy_read_bit = 1'b1; - state_next = STATE_ADDRESS_2; - end - end - STATE_ADDRESS_2: begin - // read ack bit - missed_ack_next = phy_rx_data_reg; - - if (mode_read_reg) begin - // start read - bit_count_next = 4'd8; - data_next = 1'b0; - state_next = STATE_READ; - end else begin - // start write - s_axis_data_tready_next = 1'b1; - state_next = STATE_WRITE_1; - end - end - STATE_WRITE_1: begin - s_axis_data_tready_next = 1'b1; + end else begin + state_next = STATE_IDLE; + end + end + STATE_ACTIVE_WRITE: begin + // line active with current address and read/write mode + s_axis_cmd_ready_next = 1'b1; + + if (s_axis_cmd_ready & s_axis_cmd_valid) begin + //$display("ready and valid"); + // command valid + if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin + // read or write command + addr_next = s_axis_cmd_address; + mode_read_next = s_axis_cmd_read; + mode_write_multiple_next = s_axis_cmd_write_multiple; + mode_stop_next = s_axis_cmd_stop; + + s_axis_cmd_ready_next = 1'b0; + + if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_read) begin + // address or mode mismatch or forced start - repeated start + + // repeated start bit + phy_start_bit = 1'b1; + bit_count_next = 4'd8; + state_next = STATE_ADDRESS_1; + end else begin + // address and mode match - if (s_axis_data_tready & s_axis_data_tvalid) begin - // got data, start write - data_next = s_axis_data_tdata; - last_next = s_axis_data_tlast; - bit_count_next = 4'd8; - s_axis_data_tready_next = 1'b0; - state_next = STATE_WRITE_2; - end else begin - // wait for data - state_next = STATE_WRITE_1; - end - end - STATE_WRITE_2: begin - // send data - bit_count_next = bit_count_reg - 1; - if (bit_count_reg > 0) begin - // write data bit - phy_write_bit = 1'b1; - phy_tx_data = data_reg[bit_count_reg-1]; - state_next = STATE_WRITE_2; - end else begin - // read ack bit - phy_read_bit = 1'b1; - state_next = STATE_WRITE_3; - end - end - STATE_WRITE_3: begin - // read ack bit - missed_ack_next = phy_rx_data_reg; - - if (mode_write_multiple_reg && !last_reg) begin - // more to write - state_next = STATE_WRITE_1; - end else if (mode_stop_reg) begin - // last cycle and stop selected - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end else begin - // otherwise, return to bus active state - state_next = STATE_ACTIVE_WRITE; - end - end - STATE_READ: begin - // read data - - bit_count_next = bit_count_reg - 1; - data_next = {data_reg[6:0], phy_rx_data_reg}; - if (bit_count_reg > 0) begin - // read next bit - phy_read_bit = 1'b1; - state_next = STATE_READ; - end else begin - // output data word - m_axis_data_tdata_next = data_next; - m_axis_data_tvalid_next = 1'b1; - m_axis_data_tlast_next = 1'b0; - if (mode_stop_reg) begin - // send nack and stop - m_axis_data_tlast_next = 1'b1; - phy_write_bit = 1'b1; - phy_tx_data = 1'b1; - state_next = STATE_STOP; - end else begin - // return to bus active state - state_next = STATE_ACTIVE_READ; - end - end - end - STATE_STOP: begin - // send stop bit - phy_stop_bit = 1'b1; - state_next = STATE_IDLE; - end - endcase - end -end - -always @* begin - phy_state_next = PHY_STATE_IDLE; - - phy_rx_data_next = phy_rx_data_reg; - - delay_next = delay_reg; - delay_scl_next = delay_scl_reg; - delay_sda_next = delay_sda_reg; - - scl_o_next = scl_o_reg; - sda_o_next = sda_o_reg; - - bus_control_next = bus_control_reg; - - if (phy_release_bus) begin - // release bus and return to idle state - sda_o_next = 1'b1; - scl_o_next = 1'b1; - delay_scl_next = 1'b0; - delay_sda_next = 1'b0; - delay_next = 1'b0; - phy_state_next = PHY_STATE_IDLE; - end else if (delay_scl_reg) begin - // wait for SCL to match command - delay_scl_next = scl_o_reg & ~scl_i_reg; - phy_state_next = phy_state_reg; - end else if (delay_sda_reg) begin - // wait for SDA to match command - delay_sda_next = sda_o_reg & ~sda_i_reg; - phy_state_next = phy_state_reg; - end else if (delay_reg > 0) begin - // time delay - delay_next = delay_reg - 1; - phy_state_next = phy_state_reg; - end else begin - case (phy_state_reg) - PHY_STATE_IDLE: begin - // bus idle - wait for start command - sda_o_next = 1'b1; - scl_o_next = 1'b1; - if (phy_start_bit) begin - sda_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_START_1; - end else begin - phy_state_next = PHY_STATE_IDLE; - end - end - PHY_STATE_ACTIVE: begin - // bus active - if (phy_start_bit) begin - sda_o_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_REPEATED_START_1; - end else if (phy_write_bit) begin - sda_o_next = phy_tx_data; - delay_next = prescale; - phy_state_next = PHY_STATE_WRITE_BIT_1; - end else if (phy_read_bit) begin - sda_o_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_1; - end else if (phy_stop_bit) begin - sda_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_STOP_1; - end else begin - phy_state_next = PHY_STATE_ACTIVE; - end - end - PHY_STATE_REPEATED_START_1: begin - // generate repeated start bit - // ______ - // sda XXX/ \_______ - // _______ - // scl ______/ \___ - // - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_REPEATED_START_2; - end - PHY_STATE_REPEATED_START_2: begin - // generate repeated start bit - // ______ - // sda XXX/ \_______ - // _______ - // scl ______/ \___ - // - - sda_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_START_1; - end - PHY_STATE_START_1: begin - // generate start bit - // ___ - // sda \_______ - // _______ - // scl \___ - // - - scl_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_START_2; - end - PHY_STATE_START_2: begin - // generate start bit - // ___ - // sda \_______ - // _______ - // scl \___ - // - - bus_control_next = 1'b1; - phy_state_next = PHY_STATE_ACTIVE; - end - PHY_STATE_WRITE_BIT_1: begin - // write bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale << 1; - phy_state_next = PHY_STATE_WRITE_BIT_2; - end - PHY_STATE_WRITE_BIT_2: begin - // write bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_WRITE_BIT_3; - end - PHY_STATE_WRITE_BIT_3: begin - // write bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - phy_state_next = PHY_STATE_ACTIVE; - end - PHY_STATE_READ_BIT_1: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_2; + // start write + s_axis_data_tready_next = 1'b1; + state_next = STATE_WRITE_1; + end + end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin + // stop command + phy_stop_bit = 1'b1; + if (DEBUG) $display("from active write to idle? why?"); + state_next = STATE_IDLE; + end else begin + // invalid or unspecified - ignore + state_next = STATE_ACTIVE_WRITE; end - PHY_STATE_READ_BIT_2: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - phy_rx_data_next = sda_i_reg; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_3; + end else begin + if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin + //$display("Not here"); + // no waiting command and stop_on_idle selected, issue stop condition + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end else begin + //$display("From read to write?"); + state_next = STATE_ACTIVE_WRITE; end - PHY_STATE_READ_BIT_3: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - scl_o_next = 1'b0; - delay_next = prescale; - phy_state_next = PHY_STATE_READ_BIT_4; + end + end + STATE_ACTIVE_READ: begin + //$display("State active read"); + // line active to current address + s_axis_cmd_ready_next = ~m_axis_data_tvalid; + + if (s_axis_cmd_ready & s_axis_cmd_valid) begin + //$display("ready and valid ative read"); + // command valid + if (s_axis_cmd_read ^ (s_axis_cmd_write | s_axis_cmd_write_multiple)) begin + // read or write command + addr_next = s_axis_cmd_address; + mode_read_next = s_axis_cmd_read; + mode_write_multiple_next = s_axis_cmd_write_multiple; + mode_stop_next = s_axis_cmd_stop; + + s_axis_cmd_ready_next = 1'b0; + + if (s_axis_cmd_start || s_axis_cmd_address != addr_reg || s_axis_cmd_write) begin + // address or mode mismatch or forced start - repeated start + + // write nack for previous read + if (DEBUG) $display("mode mismatch forced restart, write nack"); + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + // repeated start bit + state_next = STATE_START; + end else begin + // address and mode match + + if (DEBUG) $display("sending ack and continue with next read"); + // write ack for previous read + phy_write_bit = 1'b1; + phy_tx_data = 1'b0; + // start next read + bit_count_next = 4'd8; + data_next = 8'd0; + state_next = STATE_READ; + end + end else if (s_axis_cmd_stop && !(s_axis_cmd_read || s_axis_cmd_write || s_axis_cmd_write_multiple)) begin + //$display("Not here active read"); + // stop command + // write nack for previous read + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + // send stop bit + state_next = STATE_STOP; + end else begin + if (DEBUG) $display("active read: invalid or unspecified - ignore.. ?"); + // invalid or unspecified - ignore + state_next = STATE_ACTIVE_READ; end - PHY_STATE_READ_BIT_4: begin - // read bit - // ________ - // sda X________X - // ____ - // scl __/ \__ - - phy_state_next = PHY_STATE_ACTIVE; + end else begin + + if (stop_on_idle & s_axis_cmd_ready & ~s_axis_cmd_valid) begin + // no waiting command and stop_on_idle selected, issue stop condition + // write ack for previous read + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + // send stop bit + if (DEBUG) $display("got last bit and received, so stopping"); + + state_next = STATE_STOP; + end else begin + //$display("Active Read: conditions: %d, %d",s_axis_cmd_ready,~s_axis_cmd_valid); + //$display("m_axis_data_tvalid %d ", m_axis_data_tvalid); + state_next = STATE_ACTIVE_READ; end - PHY_STATE_STOP_1: begin - // stop bit - // ___ - // sda XXX\_______/ - // _______ - // scl _______/ - - scl_o_next = 1'b1; - delay_scl_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_STOP_2; + end + end + STATE_START_WAIT: begin + // wait for bus idle + + if (bus_active) begin + state_next = STATE_START_WAIT; + end else begin + // bus is idle, take control + phy_start_bit = 1'b1; + bit_count_next = 4'd8; + state_next = STATE_ADDRESS_1; + end + end + STATE_START: begin + // send start bit + + phy_start_bit = 1'b1; + bit_count_next = 4'd8; + state_next = STATE_ADDRESS_1; + end + STATE_ADDRESS_1: begin + // send address + bit_count_next = bit_count_reg - 1; + if (bit_count_reg > 1) begin + // send address + phy_write_bit = 1'b1; + phy_tx_data = addr_reg[bit_count_reg-2]; + state_next = STATE_ADDRESS_1; + end else if (bit_count_reg > 0) begin + // send read/write bit + phy_write_bit = 1'b1; + phy_tx_data = mode_read_reg; + state_next = STATE_ADDRESS_1; + //$display("should be %d",mode_read_reg); + end else begin + //$display("should be 0 %d",sda_o); + // read ack bit + phy_read_bit = 1'b1; + state_next = STATE_ADDRESS_2; + end + end + STATE_ADDRESS_2: begin + // read ack bit + missed_ack_next = phy_rx_data_reg; + if (missed_ack_next) begin + if (DEBUG) $display("got NACK"); + state_next = STATE_STOP; + end else begin + if (DEBUG) $display("got ACK"); + + if (mode_read_reg) begin + // start read + bit_count_next = 4'd8; + data_next = 8'b0; + state_next = STATE_READ; + end else begin + // start write + s_axis_data_tready_next = 1'b1; + state_next = STATE_WRITE_1; end - PHY_STATE_STOP_2: begin - // stop bit - // ___ - // sda XXX\_______/ - // _______ - // scl _______/ - - sda_o_next = 1'b1; - delay_next = prescale; - phy_state_next = PHY_STATE_STOP_3; + end + end + STATE_WRITE_1: begin + s_axis_data_tready_next = 1'b1; + + if (s_axis_data_tready & s_axis_data_tvalid) begin + // got data, start write + data_next = s_axis_data_tdata; + last_next = s_axis_data_tlast; + bit_count_next = 4'd8; + s_axis_data_tready_next = 1'b0; + state_next = STATE_WRITE_2; + end else begin + // wait for data + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_2: begin + // send data + bit_count_next = bit_count_reg - 1; + if (bit_count_reg > 0) begin + // write data bit + phy_write_bit = 1'b1; + phy_tx_data = data_reg[bit_count_reg-1]; + state_next = STATE_WRITE_2; + end else begin + // read ack bit + phy_read_bit = 1'b1; + state_next = STATE_WRITE_3; + end + end + STATE_WRITE_3: begin + // read ack bit + missed_ack_next = phy_rx_data_reg; + if (missed_ack_next) begin + if (DEBUG) $display("got NACK on write"); + state_next = STATE_STOP; + end else begin + if (DEBUG) $display("got ACK on write %d", $time); + + value_has_been_written_reg = 1; //only if successful! + + if (mode_write_multiple_reg && !last_reg) begin + // more to write + state_next = STATE_WRITE_1; + end else if (mode_stop_reg) begin + // last cycle and stop selected + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end else begin + // otherwise, return to bus active state + state_next = STATE_ACTIVE_WRITE; end - PHY_STATE_STOP_3: begin - // stop bit - // ___ - // sda XXX\_______/ - // _______ - // scl _______/ - - bus_control_next = 1'b0; - phy_state_next = PHY_STATE_IDLE; + end + end + STATE_READ: begin + // read data + + bit_count_next = bit_count_reg - 1; + data_next = {data_reg[6:0], phy_rx_data_reg}; + if (bit_count_reg > 0) begin + // read next bit + phy_read_bit = 1'b1; + state_next = STATE_READ; + end else begin + // output data word + m_axis_data_tdata_next = data_next; + m_axis_data_tvalid_next = 1'b1; + m_axis_data_tlast_next = 1'b0; + if (mode_stop_reg) begin + // send nack and stop + m_axis_data_tlast_next = 1'b1; + phy_write_bit = 1'b1; + phy_tx_data = 1'b1; + state_next = STATE_STOP; + end else begin + // return to bus active state + state_next = STATE_ACTIVE_READ; end - endcase + end + end + STATE_STOP: begin + // send stop bit + phy_stop_bit = 1'b1; + state_next = STATE_IDLE; + end + default: if (DEBUG) $display("I don't think case default should get triggered"); + endcase end -end - -always @(posedge clk) begin - state_reg <= state_next; - phy_state_reg <= phy_state_next; + end + + i2c_phy phy_instance ( + .clk(clk), + .rst_n(rst_n), + .phy_start_bit(phy_start_bit), + .phy_stop_bit(phy_stop_bit), + .phy_write_bit(phy_write_bit), + .phy_read_bit(phy_read_bit), + .phy_tx_data(phy_tx_data), + .phy_release_bus(phy_release_bus), + .scl_i(scl_i), + .scl_o(scl_o), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .scl_t(scl_t), + .phy_busy(phy_busy), + .bus_control_reg(bus_control_reg), + .phy_rx_data_reg(phy_rx_data_reg), + .phy_state_reg(phy_state_reg), + .prescale(17'd3) + ); + + + always @(posedge clk or negedge rst_n) begin + if (~rst_n) begin + state_reg <= STATE_IDLE; + s_axis_cmd_ready_reg <= 1'b0; + s_axis_data_tready_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; + busy_reg <= 1'b0; + missed_ack_reg <= 1'b0; - phy_rx_data_reg <= phy_rx_data_next; + end else begin + state_reg <= state_next; - addr_reg <= addr_next; - data_reg <= data_next; - last_reg <= last_next; + addr_reg <= addr_next; + data_reg <= data_next; + last_reg <= last_next; - mode_read_reg <= mode_read_next; - mode_write_multiple_reg <= mode_write_multiple_next; - mode_stop_reg <= mode_stop_next; + mode_read_reg <= mode_read_next; + mode_write_multiple_reg <= mode_write_multiple_next; + mode_stop_reg <= mode_stop_next; - delay_reg <= delay_next; - delay_scl_reg <= delay_scl_next; - delay_sda_reg <= delay_sda_next; - bit_count_reg <= bit_count_next; + bit_count_reg <= bit_count_next; - s_axis_cmd_ready_reg <= s_axis_cmd_ready_next; + s_axis_cmd_ready_reg <= s_axis_cmd_ready_next; - s_axis_data_tready_reg <= s_axis_data_tready_next; + s_axis_data_tready_reg <= s_axis_data_tready_next; - m_axis_data_tdata_reg <= m_axis_data_tdata_next; - m_axis_data_tlast_reg <= m_axis_data_tlast_next; - m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; + m_axis_data_tdata_reg <= m_axis_data_tdata_next; + m_axis_data_tlast_reg <= m_axis_data_tlast_next; + m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; - scl_i_reg <= scl_i; - sda_i_reg <= sda_i; + scl_i_reg <= scl_i; + sda_i_reg <= sda_i; - scl_o_reg <= scl_o_next; - sda_o_reg <= sda_o_next; - last_scl_i_reg <= scl_i_reg; - last_sda_i_reg <= sda_i_reg; + last_scl_i_reg <= scl_i_reg; + last_sda_i_reg <= sda_i_reg; - busy_reg <= !(state_reg == STATE_IDLE || state_reg == STATE_ACTIVE_WRITE || state_reg == STATE_ACTIVE_READ) || !(phy_state_reg == PHY_STATE_IDLE || phy_state_reg == PHY_STATE_ACTIVE); + busy_reg <= !(state_reg == STATE_IDLE || state_reg == STATE_ACTIVE_WRITE || state_reg == STATE_ACTIVE_READ) || !(phy_state_reg == PHY_STATE_IDLE || phy_state_reg == PHY_STATE_ACTIVE); - if (start_bit) begin + if (start_bit) begin bus_active_reg <= 1'b1; - end else if (stop_bit) begin + end else if (stop_bit) begin bus_active_reg <= 1'b0; - end else begin + end else begin bus_active_reg <= bus_active_reg; - end + end - bus_control_reg <= bus_control_next; - missed_ack_reg <= missed_ack_next; - - if (rst) begin - state_reg <= STATE_IDLE; - phy_state_reg <= PHY_STATE_IDLE; - delay_reg <= 16'd0; - delay_scl_reg <= 1'b0; - delay_sda_reg <= 1'b0; - s_axis_cmd_ready_reg <= 1'b0; - s_axis_data_tready_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; - scl_o_reg <= 1'b1; - sda_o_reg <= 1'b1; - busy_reg <= 1'b0; - bus_active_reg <= 1'b0; - bus_control_reg <= 1'b0; - missed_ack_reg <= 1'b0; + missed_ack_reg <= missed_ack_next; end -end + end endmodule diff --git a/rtl/i2c_master_axil.v b/rtl/i2c_master_axil.v index 10c0625..d1c5232 100644 --- a/rtl/i2c_master_axil.v +++ b/rtl/i2c_master_axil.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * I2C master AXI lite wrapper */ -module i2c_master_axil # -( +module i2c_master_axil #( parameter DEFAULT_PRESCALE = 1, parameter FIXED_PRESCALE = 0, parameter CMD_FIFO = 1, @@ -39,45 +38,44 @@ module i2c_master_axil # parameter WRITE_FIFO_DEPTH = 32, parameter READ_FIFO = 1, parameter READ_FIFO_DEPTH = 32 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire [3:0] s_axil_awaddr, - input wire [2:0] s_axil_awprot, + input wire [ 3:0] s_axil_awaddr, + input wire [ 2:0] s_axil_awprot, input wire s_axil_awvalid, output wire s_axil_awready, input wire [31:0] s_axil_wdata, - input wire [3:0] s_axil_wstrb, + input wire [ 3:0] s_axil_wstrb, input wire s_axil_wvalid, output wire s_axil_wready, - output wire [1:0] s_axil_bresp, + output wire [ 1:0] s_axil_bresp, output wire s_axil_bvalid, input wire s_axil_bready, - input wire [3:0] s_axil_araddr, - input wire [2:0] s_axil_arprot, + input wire [ 3:0] s_axil_araddr, + input wire [ 2:0] s_axil_arprot, input wire s_axil_arvalid, output wire s_axil_arready, output wire [31:0] s_axil_rdata, - output wire [1:0] s_axil_rresp, + output wire [ 1:0] s_axil_rresp, output wire s_axil_rvalid, input wire s_axil_rready, /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t ); -/* + /* I2C @@ -295,208 +293,219 @@ I/O pin. This would prevent devices from stretching the clock period. */ -reg s_axil_awready_reg = 1'b0, s_axil_awready_next; -reg s_axil_wready_reg = 1'b0, s_axil_wready_next; -reg s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next; -reg s_axil_arready_reg = 1'b0, s_axil_arready_next; -reg [31:0] s_axil_rdata_reg = 32'd0, s_axil_rdata_next; -reg s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next; - -reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; -reg cmd_start_reg = 1'b0, cmd_start_next; -reg cmd_read_reg = 1'b0, cmd_read_next; -reg cmd_write_reg = 1'b0, cmd_write_next; -reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; -reg cmd_stop_reg = 1'b0, cmd_stop_next; -reg cmd_valid_reg = 1'b0, cmd_valid_next; -wire cmd_ready; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; -reg data_in_last_reg = 1'b0, data_in_last_next; - -wire [7:0] data_out; -wire data_out_valid; -reg data_out_ready_reg = 1'b0, data_out_ready_next; -wire data_out_last; - -reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; - -reg missed_ack_reg = 1'b0, missed_ack_next; - -assign s_axil_awready = s_axil_awready_reg; -assign s_axil_wready = s_axil_wready_reg; -assign s_axil_bresp = 2'b00; -assign s_axil_bvalid = s_axil_bvalid_reg; -assign s_axil_arready = s_axil_arready_reg; -assign s_axil_rdata = s_axil_rdata_reg; -assign s_axil_rresp = 2'b00; -assign s_axil_rvalid = s_axil_rvalid_reg; - -wire [6:0] cmd_address_int; -wire cmd_start_int; -wire cmd_read_int; -wire cmd_write_int; -wire cmd_write_multiple_int; -wire cmd_stop_int; -wire cmd_valid_int; -wire cmd_ready_int; - -wire [7:0] data_in_int; -wire data_in_valid_int; -wire data_in_ready_int; -wire data_in_last_int; - -wire [7:0] data_out_int; -wire data_out_valid_int; -wire data_out_ready_int; -wire data_out_last_int; - -wire busy_int; -wire bus_control_int; -wire bus_active_int; -wire missed_ack_int; - -wire cmd_fifo_empty = !cmd_valid_int; -wire cmd_fifo_full = !cmd_ready; -wire write_fifo_empty = !data_in_valid_int; -wire write_fifo_full = !data_in_ready; -wire read_fifo_empty = !data_out_valid; -wire read_fifo_full = !data_out_ready_int; - -reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; -reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; - -generate - -if (CMD_FIFO) begin - axis_fifo #( - .DEPTH(CMD_FIFO_DEPTH), - .DATA_WIDTH(7+5), - .KEEP_ENABLE(0), - .LAST_ENABLE(0), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - cmd_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata({cmd_address_reg, cmd_start_reg, cmd_read_reg, cmd_write_reg, cmd_write_multiple_reg, cmd_stop_reg}), - .s_axis_tkeep(0), - .s_axis_tvalid(cmd_valid_reg), - .s_axis_tready(cmd_ready), - .s_axis_tlast(1'b0), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata({cmd_address_int, cmd_start_int, cmd_read_int, cmd_write_int, cmd_write_multiple_int, cmd_stop_int}), - .m_axis_tkeep(), - .m_axis_tvalid(cmd_valid_int), - .m_axis_tready(cmd_ready_int), - .m_axis_tlast(), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign cmd_address_int = cmd_address_reg; - assign cmd_start_int = cmd_start_reg; - assign cmd_read_int = cmd_read_reg; - assign cmd_write_int = cmd_write_reg; - assign cmd_write_multiple_int = cmd_write_multiple_reg; - assign cmd_stop_int = cmd_stop_reg; - assign cmd_valid_int = cmd_valid_reg; - assign cmd_ready = cmd_ready_int; -end - -if (WRITE_FIFO) begin - axis_fifo #( - .DEPTH(WRITE_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - write_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_in_reg), - .s_axis_tkeep(0), - .s_axis_tvalid(data_in_valid_reg), - .s_axis_tready(data_in_ready), - .s_axis_tlast(data_in_last_reg), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata(data_in_int), - .m_axis_tkeep(), - .m_axis_tvalid(data_in_valid_int), - .m_axis_tready(data_in_ready_int), - .m_axis_tlast(data_in_last_int), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_in_int = data_in_reg; - assign data_in_valid = data_in_valid_reg; - assign data_in_ready = data_in_ready_int; - assign data_in_last = data_in_last_reg; -end - -if (READ_FIFO) begin - axis_fifo #( - .DEPTH(READ_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - read_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_out_int), - .s_axis_tkeep(0), - .s_axis_tvalid(data_out_valid_int), - .s_axis_tready(data_out_ready_int), - .s_axis_tlast(data_out_last_int), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(0), - // AXI output - .m_axis_tdata(data_out), - .m_axis_tkeep(), - .m_axis_tvalid(data_out_valid), - .m_axis_tready(data_out_ready_reg), - .m_axis_tlast(data_out_last), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_out = data_out_int; - assign data_out_valid = data_out_valid_int; - assign data_out_ready_int = data_out_ready_reg; - assign data_out_last = data_out_last_int; -end - -endgenerate - -always @* begin + reg s_axil_awready_reg = 1'b0, s_axil_awready_next; + reg s_axil_wready_reg = 1'b0, s_axil_wready_next; + reg s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next; + reg s_axil_arready_reg = 1'b0, s_axil_arready_next; + reg [31:0] s_axil_rdata_reg = 32'd0, s_axil_rdata_next; + reg s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next; + + reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; + reg cmd_start_reg = 1'b0, cmd_start_next; + reg cmd_read_reg = 1'b0, cmd_read_next; + reg cmd_write_reg = 1'b0, cmd_write_next; + reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; + reg cmd_stop_reg = 1'b0, cmd_stop_next; + reg cmd_valid_reg = 1'b0, cmd_valid_next; + wire cmd_ready; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + reg data_in_last_reg = 1'b0, data_in_last_next; + + wire [7:0] data_out; + wire data_out_valid; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire data_out_last; + + reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; + + reg missed_ack_reg = 1'b0, missed_ack_next; + + assign s_axil_awready = s_axil_awready_reg; + assign s_axil_wready = s_axil_wready_reg; + assign s_axil_bresp = 2'b00; + assign s_axil_bvalid = s_axil_bvalid_reg; + assign s_axil_arready = s_axil_arready_reg; + assign s_axil_rdata = s_axil_rdata_reg; + assign s_axil_rresp = 2'b00; + assign s_axil_rvalid = s_axil_rvalid_reg; + + wire [6:0] cmd_address_int; + wire cmd_start_int; + wire cmd_read_int; + wire cmd_write_int; + wire cmd_write_multiple_int; + wire cmd_stop_int; + wire cmd_valid_int; + wire cmd_ready_int; + + wire [7:0] data_in_int; + wire data_in_valid_int; + wire data_in_ready_int; + wire data_in_last_int; + + wire [7:0] data_out_int; + wire data_out_valid_int; + wire data_out_ready_int; + wire data_out_last_int; + + wire busy_int; + wire bus_control_int; + wire bus_active_int; + wire missed_ack_int; + + wire cmd_fifo_empty = !cmd_valid_int; + wire cmd_fifo_full = !cmd_ready; + wire write_fifo_empty = !data_in_valid_int; + wire write_fifo_full = !data_in_ready; + wire read_fifo_empty = !data_out_valid; + wire read_fifo_full = !data_out_ready_int; + + reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; + reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; + + generate + + if (CMD_FIFO) begin + axis_fifo #( + .DEPTH(CMD_FIFO_DEPTH), + .DATA_WIDTH(7 + 5), + .KEEP_ENABLE(0), + .LAST_ENABLE(0), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) cmd_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata({ + cmd_address_reg, + cmd_start_reg, + cmd_read_reg, + cmd_write_reg, + cmd_write_multiple_reg, + cmd_stop_reg + }), + .s_axis_tkeep(0), + .s_axis_tvalid(cmd_valid_reg), + .s_axis_tready(cmd_ready), + .s_axis_tlast(1'b0), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata({ + cmd_address_int, + cmd_start_int, + cmd_read_int, + cmd_write_int, + cmd_write_multiple_int, + cmd_stop_int + }), + .m_axis_tkeep(), + .m_axis_tvalid(cmd_valid_int), + .m_axis_tready(cmd_ready_int), + .m_axis_tlast(), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign cmd_address_int = cmd_address_reg; + assign cmd_start_int = cmd_start_reg; + assign cmd_read_int = cmd_read_reg; + assign cmd_write_int = cmd_write_reg; + assign cmd_write_multiple_int = cmd_write_multiple_reg; + assign cmd_stop_int = cmd_stop_reg; + assign cmd_valid_int = cmd_valid_reg; + assign cmd_ready = cmd_ready_int; + end + + if (WRITE_FIFO) begin + axis_fifo #( + .DEPTH(WRITE_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) write_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_in_reg), + .s_axis_tkeep(0), + .s_axis_tvalid(data_in_valid_reg), + .s_axis_tready(data_in_ready), + .s_axis_tlast(data_in_last_reg), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata(data_in_int), + .m_axis_tkeep(), + .m_axis_tvalid(data_in_valid_int), + .m_axis_tready(data_in_ready_int), + .m_axis_tlast(data_in_last_int), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_in_int = data_in_reg; + assign data_in_valid = data_in_valid_reg; + assign data_in_ready = data_in_ready_int; + assign data_in_last = data_in_last_reg; + end + + if (READ_FIFO) begin + axis_fifo #( + .DEPTH(READ_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) read_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_out_int), + .s_axis_tkeep(0), + .s_axis_tvalid(data_out_valid_int), + .s_axis_tready(data_out_ready_int), + .s_axis_tlast(data_out_last_int), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(0), + // AXI output + .m_axis_tdata(data_out), + .m_axis_tkeep(), + .m_axis_tvalid(data_out_valid), + .m_axis_tready(data_out_ready_reg), + .m_axis_tlast(data_out_last), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_out = data_out_int; + assign data_out_valid = data_out_valid_int; + assign data_out_ready_int = data_out_ready_reg; + assign data_out_last = data_out_last_int; + end + + endgenerate + + always @* begin s_axil_awready_next = 1'b0; s_axil_wready_next = 1'b0; s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_bready; @@ -526,128 +535,132 @@ always @* begin write_fifo_overflow_next = write_fifo_overflow_reg; if (s_axil_awvalid && s_axil_wvalid && !s_axil_bvalid) begin - // write operation - s_axil_awready_next = 1'b1; - s_axil_wready_next = 1'b1; - s_axil_bvalid_next = 1'b1; - - case ({s_axil_awaddr[3:2], 2'b00}) - 4'h0: begin - // status register - if (s_axil_wstrb[0]) begin - if (s_axil_wdata[3]) begin - missed_ack_next = missed_ack_int; - end - end - if (s_axil_wstrb[1]) begin - if (s_axil_wdata[10]) begin - cmd_fifo_overflow_next = 1'b0; - end - if (s_axil_wdata[13]) begin - write_fifo_overflow_next = 1'b0; - end - end + // write operation + s_axil_awready_next = 1'b1; + s_axil_wready_next = 1'b1; + s_axil_bvalid_next = 1'b1; + + case ({ + s_axil_awaddr[3:2], 2'b00 + }) + 4'h0: begin + // status register + if (s_axil_wstrb[0]) begin + if (s_axil_wdata[3]) begin + missed_ack_next = missed_ack_int; end - 4'h4: begin - // command - if (s_axil_wstrb[0]) begin - cmd_address_next = s_axil_wdata[6:0]; - end - if (s_axil_wstrb[1]) begin - cmd_start_next = s_axil_wdata[8]; - cmd_read_next = s_axil_wdata[9]; - cmd_write_next = s_axil_wdata[10]; - cmd_write_multiple_next = s_axil_wdata[11]; - cmd_stop_next = s_axil_wdata[12]; - cmd_valid_next = cmd_start_next || cmd_read_next || cmd_write_next || cmd_write_multiple_next || cmd_stop_next; - - cmd_fifo_overflow_next = cmd_fifo_overflow_next || (cmd_valid_next && !cmd_ready); - end + end + if (s_axil_wstrb[1]) begin + if (s_axil_wdata[10]) begin + cmd_fifo_overflow_next = 1'b0; end - 4'h8: begin - // data - if (s_axil_wstrb[0]) begin - data_in_next = s_axil_wdata[7:0]; - - if (s_axil_wstrb[1]) begin - // only valid with atomic 16 bit write - data_in_last_next = s_axil_wdata[9]; - end else begin - data_in_last_next = 1'b0; - end - - data_in_valid_next = 1'b1; - - write_fifo_overflow_next = write_fifo_overflow_next || !data_in_ready; - end + if (s_axil_wdata[13]) begin + write_fifo_overflow_next = 1'b0; end - 4'hC: begin - // prescale - if (!FIXED_PRESCALE && s_axil_wstrb[0]) begin - prescale_next[7:0] = s_axil_wdata[7:0]; - end - if (!FIXED_PRESCALE && s_axil_wstrb[1]) begin - prescale_next[15:8] = s_axil_wdata[15:8]; - end + end + end + 4'h4: begin + // command + if (s_axil_wstrb[0]) begin + cmd_address_next = s_axil_wdata[6:0]; + end + if (s_axil_wstrb[1]) begin + cmd_start_next = s_axil_wdata[8]; + cmd_read_next = s_axil_wdata[9]; + cmd_write_next = s_axil_wdata[10]; + cmd_write_multiple_next = s_axil_wdata[11]; + cmd_stop_next = s_axil_wdata[12]; + cmd_valid_next = cmd_start_next || cmd_read_next || cmd_write_next || cmd_write_multiple_next || cmd_stop_next; + + cmd_fifo_overflow_next = cmd_fifo_overflow_next || (cmd_valid_next && !cmd_ready); + end + end + 4'h8: begin + // data + if (s_axil_wstrb[0]) begin + data_in_next = s_axil_wdata[7:0]; + + if (s_axil_wstrb[1]) begin + // only valid with atomic 16 bit write + data_in_last_next = s_axil_wdata[9]; + end else begin + data_in_last_next = 1'b0; end - endcase + + data_in_valid_next = 1'b1; + + write_fifo_overflow_next = write_fifo_overflow_next || !data_in_ready; + end + end + 4'hC: begin + // prescale + if (!FIXED_PRESCALE && s_axil_wstrb[0]) begin + prescale_next[7:0] = s_axil_wdata[7:0]; + end + if (!FIXED_PRESCALE && s_axil_wstrb[1]) begin + prescale_next[15:8] = s_axil_wdata[15:8]; + end + end + endcase end if (s_axil_arvalid && !s_axil_rvalid) begin - // read operation - s_axil_arready_next = 1'b1; - s_axil_rvalid_next = 1'b1; - s_axil_rdata_next = 32'd0; - - case ({s_axil_araddr[3:2], 2'b00}) - 4'h0: begin - // status - s_axil_rdata_next[0] = busy_int; - s_axil_rdata_next[1] = bus_control_int; - s_axil_rdata_next[2] = bus_active_int; - s_axil_rdata_next[3] = missed_ack_reg; - s_axil_rdata_next[4] = 1'b0; - s_axil_rdata_next[5] = 1'b0; - s_axil_rdata_next[6] = 1'b0; - s_axil_rdata_next[7] = 1'b0; - s_axil_rdata_next[8] = cmd_fifo_empty; - s_axil_rdata_next[9] = cmd_fifo_full; - s_axil_rdata_next[10] = cmd_fifo_overflow_reg; - s_axil_rdata_next[11] = write_fifo_empty; - s_axil_rdata_next[12] = write_fifo_full; - s_axil_rdata_next[13] = write_fifo_overflow_reg; - s_axil_rdata_next[14] = read_fifo_empty; - s_axil_rdata_next[15] = read_fifo_full; - end - 4'h4: begin - // command - s_axil_rdata_next[6:0] = cmd_address_reg; - s_axil_rdata_next[7] = 1'b0; - s_axil_rdata_next[8] = cmd_start_reg; - s_axil_rdata_next[9] = cmd_read_reg; - s_axil_rdata_next[10] = cmd_write_reg; - s_axil_rdata_next[11] = cmd_write_multiple_reg; - s_axil_rdata_next[12] = cmd_stop_reg; - s_axil_rdata_next[13] = 1'b0; - s_axil_rdata_next[14] = 1'b0; - s_axil_rdata_next[15] = 1'b0; - end - 4'h8: begin - // data - s_axil_rdata_next[7:0] = data_out; - s_axil_rdata_next[8] = data_out_valid; - s_axil_rdata_next[9] = data_out_last; - data_out_ready_next = data_out_valid; - end - 4'hC: begin - // prescale - s_axil_rdata_next = prescale_reg; - end - endcase + // read operation + s_axil_arready_next = 1'b1; + s_axil_rvalid_next = 1'b1; + s_axil_rdata_next = 32'd0; + + case ({ + s_axil_araddr[3:2], 2'b00 + }) + 4'h0: begin + // status + s_axil_rdata_next[0] = busy_int; + s_axil_rdata_next[1] = bus_control_int; + s_axil_rdata_next[2] = bus_active_int; + s_axil_rdata_next[3] = missed_ack_reg; + s_axil_rdata_next[4] = 1'b0; + s_axil_rdata_next[5] = 1'b0; + s_axil_rdata_next[6] = 1'b0; + s_axil_rdata_next[7] = 1'b0; + s_axil_rdata_next[8] = cmd_fifo_empty; + s_axil_rdata_next[9] = cmd_fifo_full; + s_axil_rdata_next[10] = cmd_fifo_overflow_reg; + s_axil_rdata_next[11] = write_fifo_empty; + s_axil_rdata_next[12] = write_fifo_full; + s_axil_rdata_next[13] = write_fifo_overflow_reg; + s_axil_rdata_next[14] = read_fifo_empty; + s_axil_rdata_next[15] = read_fifo_full; + end + 4'h4: begin + // command + s_axil_rdata_next[6:0] = cmd_address_reg; + s_axil_rdata_next[7] = 1'b0; + s_axil_rdata_next[8] = cmd_start_reg; + s_axil_rdata_next[9] = cmd_read_reg; + s_axil_rdata_next[10] = cmd_write_reg; + s_axil_rdata_next[11] = cmd_write_multiple_reg; + s_axil_rdata_next[12] = cmd_stop_reg; + s_axil_rdata_next[13] = 1'b0; + s_axil_rdata_next[14] = 1'b0; + s_axil_rdata_next[15] = 1'b0; + end + 4'h8: begin + // data + s_axil_rdata_next[7:0] = data_out; + s_axil_rdata_next[8] = data_out_valid; + s_axil_rdata_next[9] = data_out_last; + data_out_ready_next = data_out_valid; + end + 4'hC: begin + // prescale + s_axil_rdata_next = prescale_reg; + end + endcase end -end + end -always @(posedge clk) begin + always @(posedge clk) begin s_axil_awready_reg <= s_axil_awready_next; s_axil_wready_reg <= s_axil_wready_next; s_axil_bvalid_reg <= s_axil_bvalid_next; @@ -677,63 +690,62 @@ always @(posedge clk) begin write_fifo_overflow_reg <= write_fifo_overflow_next; if (rst) begin - s_axil_awready_reg <= 1'b0; - s_axil_wready_reg <= 1'b0; - s_axil_bvalid_reg <= 1'b0; - s_axil_arready_reg <= 1'b0; - s_axil_rvalid_reg <= 1'b0; - cmd_valid_reg <= 1'b0; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - prescale_reg <= DEFAULT_PRESCALE; - missed_ack_reg <= 1'b0; - cmd_fifo_overflow_reg <= 1'b0; - write_fifo_overflow_reg <= 1'b0; + s_axil_awready_reg <= 1'b0; + s_axil_wready_reg <= 1'b0; + s_axil_bvalid_reg <= 1'b0; + s_axil_arready_reg <= 1'b0; + s_axil_rvalid_reg <= 1'b0; + cmd_valid_reg <= 1'b0; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + prescale_reg <= DEFAULT_PRESCALE; + missed_ack_reg <= 1'b0; + cmd_fifo_overflow_reg <= 1'b0; + write_fifo_overflow_reg <= 1'b0; end -end - -i2c_master -i2c_master_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .s_axis_cmd_address(cmd_address_int), - .s_axis_cmd_start(cmd_start_int), - .s_axis_cmd_read(cmd_read_int), - .s_axis_cmd_write(cmd_write_int), - .s_axis_cmd_write_multiple(cmd_write_multiple_int), - .s_axis_cmd_stop(cmd_stop_int), - .s_axis_cmd_valid(cmd_valid_int), - .s_axis_cmd_ready(cmd_ready_int), - - .s_axis_data_tdata(data_in_int), - .s_axis_data_tvalid(data_in_valid_int), - .s_axis_data_tready(data_in_ready_int), - .s_axis_data_tlast(data_in_last_int), - - .m_axis_data_tdata(data_out_int), - .m_axis_data_tvalid(data_out_valid_int), - .m_axis_data_tready(data_out_ready_int), - .m_axis_data_tlast(data_out_last_int), - - // I2C interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(busy_int), - .bus_control(bus_control_int), - .bus_active(bus_active_int), - .missed_ack(missed_ack_int), - - // Configuration - .prescale(prescale_reg), - .stop_on_idle(1'b0) -); + end + + i2c_master i2c_master_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .s_axis_cmd_address(cmd_address_int), + .s_axis_cmd_start(cmd_start_int), + .s_axis_cmd_read(cmd_read_int), + .s_axis_cmd_write(cmd_write_int), + .s_axis_cmd_write_multiple(cmd_write_multiple_int), + .s_axis_cmd_stop(cmd_stop_int), + .s_axis_cmd_valid(cmd_valid_int), + .s_axis_cmd_ready(cmd_ready_int), + + .s_axis_data_tdata (data_in_int), + .s_axis_data_tvalid(data_in_valid_int), + .s_axis_data_tready(data_in_ready_int), + .s_axis_data_tlast (data_in_last_int), + + .m_axis_data_tdata (data_out_int), + .m_axis_data_tvalid(data_out_valid_int), + .m_axis_data_tready(data_out_ready_int), + .m_axis_data_tlast (data_out_last_int), + + // I2C interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(busy_int), + .bus_control(bus_control_int), + .bus_active(bus_active_int), + .missed_ack(missed_ack_int), + + // Configuration + .prescale(prescale_reg), + .stop_on_idle(1'b0) + ); endmodule diff --git a/rtl/i2c_master_wbs_16.v b/rtl/i2c_master_wbs_16.v index d592b00..b95d87d 100644 --- a/rtl/i2c_master_wbs_16.v +++ b/rtl/i2c_master_wbs_16.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * I2C master wishbone slave wrapper (16 bit) */ -module i2c_master_wbs_16 # -( +module i2c_master_wbs_16 #( parameter DEFAULT_PRESCALE = 1, parameter FIXED_PRESCALE = 0, parameter CMD_FIFO = 1, @@ -39,34 +38,33 @@ module i2c_master_wbs_16 # parameter WRITE_FIFO_DEPTH = 32, parameter READ_FIFO = 1, parameter READ_FIFO_DEPTH = 32 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire [2:0] wbs_adr_i, // ADR_I() address - input wire [15:0] wbs_dat_i, // DAT_I() data in - output wire [15:0] wbs_dat_o, // DAT_O() data out - input wire wbs_we_i, // WE_I write enable input - input wire [1:0] wbs_sel_i, // SEL_I() select input - input wire wbs_stb_i, // STB_I strobe input - output wire wbs_ack_o, // ACK_O acknowledge output - input wire wbs_cyc_i, // CYC_I cycle input + input wire [ 2:0] wbs_adr_i, // ADR_I() address + input wire [15:0] wbs_dat_i, // DAT_I() data in + output wire [15:0] wbs_dat_o, // DAT_O() data out + input wire wbs_we_i, // WE_I write enable input + input wire [ 1:0] wbs_sel_i, // SEL_I() select input + input wire wbs_stb_i, // STB_I strobe input + output wire wbs_ack_o, // ACK_O acknowledge output + input wire wbs_cyc_i, // CYC_I cycle input /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t ); -/* + /* I2C @@ -252,198 +250,209 @@ I/O pin. This would prevent devices from stretching the clock period. */ -reg [15:0] wbs_dat_o_reg = 16'd0, wbs_dat_o_next; -reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; - -reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; -reg cmd_start_reg = 1'b0, cmd_start_next; -reg cmd_read_reg = 1'b0, cmd_read_next; -reg cmd_write_reg = 1'b0, cmd_write_next; -reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; -reg cmd_stop_reg = 1'b0, cmd_stop_next; -reg cmd_valid_reg = 1'b0, cmd_valid_next; -wire cmd_ready; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; -reg data_in_last_reg = 1'b0, data_in_last_next; - -wire [7:0] data_out; -wire data_out_valid; -reg data_out_ready_reg = 1'b0, data_out_ready_next; -wire data_out_last; - -reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; - -reg missed_ack_reg = 1'b0, missed_ack_next; - -assign wbs_dat_o = wbs_dat_o_reg; -assign wbs_ack_o = wbs_ack_o_reg; - -wire [6:0] cmd_address_int; -wire cmd_start_int; -wire cmd_read_int; -wire cmd_write_int; -wire cmd_write_multiple_int; -wire cmd_stop_int; -wire cmd_valid_int; -wire cmd_ready_int; - -wire [7:0] data_in_int; -wire data_in_valid_int; -wire data_in_ready_int; -wire data_in_last_int; - -wire [7:0] data_out_int; -wire data_out_valid_int; -wire data_out_ready_int; -wire data_out_last_int; - -wire busy_int; -wire bus_control_int; -wire bus_active_int; -wire missed_ack_int; - -wire cmd_fifo_empty = ~cmd_valid_int; -wire cmd_fifo_full = ~cmd_ready; -wire write_fifo_empty = ~data_in_valid_int; -wire write_fifo_full = ~data_in_ready; -wire read_fifo_empty = ~data_out_valid; -wire read_fifo_full = ~data_out_ready_int; - -reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; -reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; - -generate - -if (CMD_FIFO) begin - axis_fifo #( - .DEPTH(CMD_FIFO_DEPTH), - .DATA_WIDTH(7+5), - .KEEP_ENABLE(0), - .LAST_ENABLE(0), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - cmd_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata({cmd_address_reg, cmd_start_reg, cmd_read_reg, cmd_write_reg, cmd_write_multiple_reg, cmd_stop_reg}), - .s_axis_tkeep(0), - .s_axis_tvalid(cmd_valid_reg), - .s_axis_tready(cmd_ready), - .s_axis_tlast(1'b0), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata({cmd_address_int, cmd_start_int, cmd_read_int, cmd_write_int, cmd_write_multiple_int, cmd_stop_int}), - .m_axis_tkeep(), - .m_axis_tvalid(cmd_valid_int), - .m_axis_tready(cmd_ready_int), - .m_axis_tlast(), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign cmd_address_int = cmd_address_reg; - assign cmd_start_int = cmd_start_reg; - assign cmd_read_int = cmd_read_reg; - assign cmd_write_int = cmd_write_reg; - assign cmd_write_multiple_int = cmd_write_multiple_reg; - assign cmd_stop_int = cmd_stop_reg; - assign cmd_valid_int = cmd_valid_reg; - assign cmd_ready = cmd_ready_int; -end - -if (WRITE_FIFO) begin - axis_fifo #( - .DEPTH(WRITE_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - write_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_in_reg), - .s_axis_tkeep(0), - .s_axis_tvalid(data_in_valid_reg), - .s_axis_tready(data_in_ready), - .s_axis_tlast(data_in_last_reg), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata(data_in_int), - .m_axis_tkeep(), - .m_axis_tvalid(data_in_valid_int), - .m_axis_tready(data_in_ready_int), - .m_axis_tlast(data_in_last_int), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_in_int = data_in_reg; - assign data_in_valid = data_in_valid_reg; - assign data_in_ready = data_in_ready_int; - assign data_in_last = data_in_last_reg; -end - -if (READ_FIFO) begin - axis_fifo #( - .DEPTH(READ_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - read_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_out_int), - .s_axis_tkeep(0), - .s_axis_tvalid(data_out_valid_int), - .s_axis_tready(data_out_ready_int), - .s_axis_tlast(data_out_last_int), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(0), - // AXI output - .m_axis_tdata(data_out), - .m_axis_tkeep(), - .m_axis_tvalid(data_out_valid), - .m_axis_tready(data_out_ready_reg), - .m_axis_tlast(data_out_last), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_out = data_out_int; - assign data_out_valid = data_out_valid_int; - assign data_out_ready_int = data_out_ready_reg; - assign data_out_last = data_out_last_int; -end - -endgenerate - -always @* begin + reg [15:0] wbs_dat_o_reg = 16'd0, wbs_dat_o_next; + reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; + + reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; + reg cmd_start_reg = 1'b0, cmd_start_next; + reg cmd_read_reg = 1'b0, cmd_read_next; + reg cmd_write_reg = 1'b0, cmd_write_next; + reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; + reg cmd_stop_reg = 1'b0, cmd_stop_next; + reg cmd_valid_reg = 1'b0, cmd_valid_next; + wire cmd_ready; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + reg data_in_last_reg = 1'b0, data_in_last_next; + + wire [7:0] data_out; + wire data_out_valid; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire data_out_last; + + reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; + + reg missed_ack_reg = 1'b0, missed_ack_next; + + assign wbs_dat_o = wbs_dat_o_reg; + assign wbs_ack_o = wbs_ack_o_reg; + + wire [6:0] cmd_address_int; + wire cmd_start_int; + wire cmd_read_int; + wire cmd_write_int; + wire cmd_write_multiple_int; + wire cmd_stop_int; + wire cmd_valid_int; + wire cmd_ready_int; + + wire [7:0] data_in_int; + wire data_in_valid_int; + wire data_in_ready_int; + wire data_in_last_int; + + wire [7:0] data_out_int; + wire data_out_valid_int; + wire data_out_ready_int; + wire data_out_last_int; + + wire busy_int; + wire bus_control_int; + wire bus_active_int; + wire missed_ack_int; + + wire cmd_fifo_empty = ~cmd_valid_int; + wire cmd_fifo_full = ~cmd_ready; + wire write_fifo_empty = ~data_in_valid_int; + wire write_fifo_full = ~data_in_ready; + wire read_fifo_empty = ~data_out_valid; + wire read_fifo_full = ~data_out_ready_int; + + reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; + reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; + + generate + + if (CMD_FIFO) begin + axis_fifo #( + .DEPTH(CMD_FIFO_DEPTH), + .DATA_WIDTH(7 + 5), + .KEEP_ENABLE(0), + .LAST_ENABLE(0), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) cmd_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata({ + cmd_address_reg, + cmd_start_reg, + cmd_read_reg, + cmd_write_reg, + cmd_write_multiple_reg, + cmd_stop_reg + }), + .s_axis_tkeep(0), + .s_axis_tvalid(cmd_valid_reg), + .s_axis_tready(cmd_ready), + .s_axis_tlast(1'b0), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata({ + cmd_address_int, + cmd_start_int, + cmd_read_int, + cmd_write_int, + cmd_write_multiple_int, + cmd_stop_int + }), + .m_axis_tkeep(), + .m_axis_tvalid(cmd_valid_int), + .m_axis_tready(cmd_ready_int), + .m_axis_tlast(), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign cmd_address_int = cmd_address_reg; + assign cmd_start_int = cmd_start_reg; + assign cmd_read_int = cmd_read_reg; + assign cmd_write_int = cmd_write_reg; + assign cmd_write_multiple_int = cmd_write_multiple_reg; + assign cmd_stop_int = cmd_stop_reg; + assign cmd_valid_int = cmd_valid_reg; + assign cmd_ready = cmd_ready_int; + end + + if (WRITE_FIFO) begin + axis_fifo #( + .DEPTH(WRITE_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) write_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_in_reg), + .s_axis_tkeep(0), + .s_axis_tvalid(data_in_valid_reg), + .s_axis_tready(data_in_ready), + .s_axis_tlast(data_in_last_reg), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata(data_in_int), + .m_axis_tkeep(), + .m_axis_tvalid(data_in_valid_int), + .m_axis_tready(data_in_ready_int), + .m_axis_tlast(data_in_last_int), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_in_int = data_in_reg; + assign data_in_valid = data_in_valid_reg; + assign data_in_ready = data_in_ready_int; + assign data_in_last = data_in_last_reg; + end + + if (READ_FIFO) begin + axis_fifo #( + .DEPTH(READ_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) read_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_out_int), + .s_axis_tkeep(0), + .s_axis_tvalid(data_out_valid_int), + .s_axis_tready(data_out_ready_int), + .s_axis_tlast(data_out_last_int), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(0), + // AXI output + .m_axis_tdata(data_out), + .m_axis_tkeep(), + .m_axis_tvalid(data_out_valid), + .m_axis_tready(data_out_ready_reg), + .m_axis_tlast(data_out_last), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_out = data_out_int; + assign data_out_valid = data_out_valid_int; + assign data_out_ready_int = data_out_ready_reg; + assign data_out_last = data_out_last_int; + end + + endgenerate + + always @* begin wbs_dat_o_next = 8'd0; wbs_ack_o_next = 1'b0; @@ -467,129 +476,129 @@ always @* begin cmd_fifo_overflow_next = cmd_fifo_overflow_reg; write_fifo_overflow_next = write_fifo_overflow_reg; - + if (wbs_cyc_i & wbs_stb_i) begin - // bus cycle - if (wbs_we_i) begin - // write cycle - case (wbs_adr_i) - 3'h0: begin - // status register - if (wbs_sel_i[0]) begin - if (wbs_dat_i[3]) begin - missed_ack_next = missed_ack_int; - end - end - if (wbs_sel_i[1]) begin - if (wbs_dat_i[10]) begin - cmd_fifo_overflow_next = 1'b0; - end - if (wbs_dat_i[13]) begin - write_fifo_overflow_next = 1'b0; - end - end - end - 3'h2: begin - // command - if (wbs_sel_i[0]) begin - cmd_address_next = wbs_dat_i[6:0]; - end - if (wbs_sel_i[1]) begin - cmd_start_next = wbs_dat_i[8]; - cmd_read_next = wbs_dat_i[9]; - cmd_write_next = wbs_dat_i[10]; - cmd_write_multiple_next = wbs_dat_i[11]; - cmd_stop_next = wbs_dat_i[12]; - cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_write_multiple_next | cmd_stop_next); - - cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); - end - end - 3'h4: begin - // data - if (wbs_sel_i[0]) begin - data_in_next = wbs_dat_i[7:0]; - - if (wbs_sel_i[1]) begin - // only valid with atomic 16 bit write - data_in_last_next = wbs_dat_i[9]; - end else begin - data_in_last_next = 1'b0; - end - - data_in_valid_next = ~wbs_ack_o_reg; - - write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; - end - end - 3'h6: begin - // prescale - if (!FIXED_PRESCALE && wbs_sel_i[0]) begin - prescale_next[7:0] = wbs_dat_i[7:0]; - end - if (!FIXED_PRESCALE && wbs_sel_i[1]) begin - prescale_next[15:0] = wbs_dat_i[15:0]; - end - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end else begin - // read cycle - case (wbs_adr_i) - 3'h0: begin - // status - wbs_dat_o_next[0] = busy_int; - wbs_dat_o_next[1] = bus_control_int; - wbs_dat_o_next[2] = bus_active_int; - wbs_dat_o_next[3] = missed_ack_reg; - wbs_dat_o_next[4] = 1'b0; - wbs_dat_o_next[5] = 1'b0; - wbs_dat_o_next[6] = 1'b0; - wbs_dat_o_next[7] = 1'b0; - wbs_dat_o_next[8] = cmd_fifo_empty; - wbs_dat_o_next[9] = cmd_fifo_full; - wbs_dat_o_next[10] = cmd_fifo_overflow_reg; - wbs_dat_o_next[11] = write_fifo_empty; - wbs_dat_o_next[12] = write_fifo_full; - wbs_dat_o_next[13] = write_fifo_overflow_reg; - wbs_dat_o_next[14] = read_fifo_empty; - wbs_dat_o_next[15] = read_fifo_full; - end - 3'h2: begin - // command - wbs_dat_o_next[6:0] = cmd_address_reg; - wbs_dat_o_next[7] = 1'b0; - wbs_dat_o_next[8] = cmd_start_reg; - wbs_dat_o_next[9] = cmd_read_reg; - wbs_dat_o_next[10] = cmd_write_reg; - wbs_dat_o_next[11] = cmd_write_multiple_reg; - wbs_dat_o_next[12] = cmd_stop_reg; - wbs_dat_o_next[13] = 1'b0; - wbs_dat_o_next[14] = 1'b0; - wbs_dat_o_next[15] = 1'b0; - end - 3'h4: begin - // data - wbs_dat_o_next[7:0] = data_out; - wbs_dat_o_next[8] = data_out_valid; - wbs_dat_o_next[9] = data_out_last; - wbs_dat_o_next[15:10] = 6'd0; - - if (wbs_sel_i[0]) begin - data_out_ready_next = !wbs_ack_o_reg && data_out_valid; - end - end - 3'h6: begin - // prescale - wbs_dat_o_next = prescale_reg; - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end + // bus cycle + if (wbs_we_i) begin + // write cycle + case (wbs_adr_i) + 3'h0: begin + // status register + if (wbs_sel_i[0]) begin + if (wbs_dat_i[3]) begin + missed_ack_next = missed_ack_int; + end + end + if (wbs_sel_i[1]) begin + if (wbs_dat_i[10]) begin + cmd_fifo_overflow_next = 1'b0; + end + if (wbs_dat_i[13]) begin + write_fifo_overflow_next = 1'b0; + end + end + end + 3'h2: begin + // command + if (wbs_sel_i[0]) begin + cmd_address_next = wbs_dat_i[6:0]; + end + if (wbs_sel_i[1]) begin + cmd_start_next = wbs_dat_i[8]; + cmd_read_next = wbs_dat_i[9]; + cmd_write_next = wbs_dat_i[10]; + cmd_write_multiple_next = wbs_dat_i[11]; + cmd_stop_next = wbs_dat_i[12]; + cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_write_multiple_next | cmd_stop_next); + + cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); + end + end + 3'h4: begin + // data + if (wbs_sel_i[0]) begin + data_in_next = wbs_dat_i[7:0]; + + if (wbs_sel_i[1]) begin + // only valid with atomic 16 bit write + data_in_last_next = wbs_dat_i[9]; + end else begin + data_in_last_next = 1'b0; + end + + data_in_valid_next = ~wbs_ack_o_reg; + + write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; + end + end + 3'h6: begin + // prescale + if (!FIXED_PRESCALE && wbs_sel_i[0]) begin + prescale_next[7:0] = wbs_dat_i[7:0]; + end + if (!FIXED_PRESCALE && wbs_sel_i[1]) begin + prescale_next[15:0] = wbs_dat_i[15:0]; + end + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end else begin + // read cycle + case (wbs_adr_i) + 3'h0: begin + // status + wbs_dat_o_next[0] = busy_int; + wbs_dat_o_next[1] = bus_control_int; + wbs_dat_o_next[2] = bus_active_int; + wbs_dat_o_next[3] = missed_ack_reg; + wbs_dat_o_next[4] = 1'b0; + wbs_dat_o_next[5] = 1'b0; + wbs_dat_o_next[6] = 1'b0; + wbs_dat_o_next[7] = 1'b0; + wbs_dat_o_next[8] = cmd_fifo_empty; + wbs_dat_o_next[9] = cmd_fifo_full; + wbs_dat_o_next[10] = cmd_fifo_overflow_reg; + wbs_dat_o_next[11] = write_fifo_empty; + wbs_dat_o_next[12] = write_fifo_full; + wbs_dat_o_next[13] = write_fifo_overflow_reg; + wbs_dat_o_next[14] = read_fifo_empty; + wbs_dat_o_next[15] = read_fifo_full; + end + 3'h2: begin + // command + wbs_dat_o_next[6:0] = cmd_address_reg; + wbs_dat_o_next[7] = 1'b0; + wbs_dat_o_next[8] = cmd_start_reg; + wbs_dat_o_next[9] = cmd_read_reg; + wbs_dat_o_next[10] = cmd_write_reg; + wbs_dat_o_next[11] = cmd_write_multiple_reg; + wbs_dat_o_next[12] = cmd_stop_reg; + wbs_dat_o_next[13] = 1'b0; + wbs_dat_o_next[14] = 1'b0; + wbs_dat_o_next[15] = 1'b0; + end + 3'h4: begin + // data + wbs_dat_o_next[7:0] = data_out; + wbs_dat_o_next[8] = data_out_valid; + wbs_dat_o_next[9] = data_out_last; + wbs_dat_o_next[15:10] = 6'd0; + + if (wbs_sel_i[0]) begin + data_out_ready_next = !wbs_ack_o_reg && data_out_valid; + end + end + 3'h6: begin + // prescale + wbs_dat_o_next = prescale_reg; + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end end -end + end -always @(posedge clk) begin + always @(posedge clk) begin wbs_dat_o_reg <= wbs_dat_o_next; wbs_ack_o_reg <= wbs_ack_o_next; @@ -615,59 +624,58 @@ always @(posedge clk) begin write_fifo_overflow_reg <= write_fifo_overflow_next; if (rst) begin - wbs_ack_o_reg <= 1'b0; - cmd_valid_reg <= 1'b0; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - prescale_reg <= DEFAULT_PRESCALE; - missed_ack_reg <= 1'b0; - cmd_fifo_overflow_reg <= 0; - write_fifo_overflow_reg <= 0; + wbs_ack_o_reg <= 1'b0; + cmd_valid_reg <= 1'b0; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + prescale_reg <= DEFAULT_PRESCALE; + missed_ack_reg <= 1'b0; + cmd_fifo_overflow_reg <= 0; + write_fifo_overflow_reg <= 0; end -end - -i2c_master -i2c_master_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .s_axis_cmd_address(cmd_address_int), - .s_axis_cmd_start(cmd_start_int), - .s_axis_cmd_read(cmd_read_int), - .s_axis_cmd_write(cmd_write_int), - .s_axis_cmd_write_multiple(cmd_write_multiple_int), - .s_axis_cmd_stop(cmd_stop_int), - .s_axis_cmd_valid(cmd_valid_int), - .s_axis_cmd_ready(cmd_ready_int), - - .s_axis_data_tdata(data_in_int), - .s_axis_data_tvalid(data_in_valid_int), - .s_axis_data_tready(data_in_ready_int), - .s_axis_data_tlast(data_in_last_int), - - .m_axis_data_tdata(data_out_int), - .m_axis_data_tvalid(data_out_valid_int), - .m_axis_data_tready(data_out_ready_int), - .m_axis_data_tlast(data_out_last_int), - - // I2C interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(busy_int), - .bus_control(bus_control_int), - .bus_active(bus_active_int), - .missed_ack(missed_ack_int), - - // Configuration - .prescale(prescale_reg), - .stop_on_idle(1'b0) -); + end + + i2c_master i2c_master_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .s_axis_cmd_address(cmd_address_int), + .s_axis_cmd_start(cmd_start_int), + .s_axis_cmd_read(cmd_read_int), + .s_axis_cmd_write(cmd_write_int), + .s_axis_cmd_write_multiple(cmd_write_multiple_int), + .s_axis_cmd_stop(cmd_stop_int), + .s_axis_cmd_valid(cmd_valid_int), + .s_axis_cmd_ready(cmd_ready_int), + + .s_axis_data_tdata (data_in_int), + .s_axis_data_tvalid(data_in_valid_int), + .s_axis_data_tready(data_in_ready_int), + .s_axis_data_tlast (data_in_last_int), + + .m_axis_data_tdata (data_out_int), + .m_axis_data_tvalid(data_out_valid_int), + .m_axis_data_tready(data_out_ready_int), + .m_axis_data_tlast (data_out_last_int), + + // I2C interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(busy_int), + .bus_control(bus_control_int), + .bus_active(bus_active_int), + .missed_ack(missed_ack_int), + + // Configuration + .prescale(prescale_reg), + .stop_on_idle(1'b0) + ); endmodule diff --git a/rtl/i2c_master_wbs_8.v b/rtl/i2c_master_wbs_8.v index 0db2fb0..72264a8 100644 --- a/rtl/i2c_master_wbs_8.v +++ b/rtl/i2c_master_wbs_8.v @@ -29,8 +29,7 @@ THE SOFTWARE. /* * I2C master wishbone slave wrapper (8 bit) */ -module i2c_master_wbs_8 # -( +module i2c_master_wbs_8 #( parameter DEFAULT_PRESCALE = 1, parameter FIXED_PRESCALE = 0, parameter CMD_FIFO = 1, @@ -39,33 +38,32 @@ module i2c_master_wbs_8 # parameter WRITE_FIFO_DEPTH = 32, parameter READ_FIFO = 1, parameter READ_FIFO_DEPTH = 32 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst, /* * Host interface */ - input wire [2:0] wbs_adr_i, // ADR_I() address - input wire [7:0] wbs_dat_i, // DAT_I() data in - output wire [7:0] wbs_dat_o, // DAT_O() data out - input wire wbs_we_i, // WE_I write enable input - input wire wbs_stb_i, // STB_I strobe input - output wire wbs_ack_o, // ACK_O acknowledge output - input wire wbs_cyc_i, // CYC_I cycle input + input wire [2:0] wbs_adr_i, // ADR_I() address + input wire [7:0] wbs_dat_i, // DAT_I() data in + output wire [7:0] wbs_dat_o, // DAT_O() data out + input wire wbs_we_i, // WE_I write enable input + input wire wbs_stb_i, // STB_I strobe input + output wire wbs_ack_o, // ACK_O acknowledge output + input wire wbs_cyc_i, // CYC_I cycle input /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t ); -/* + /* I2C @@ -239,199 +237,210 @@ I/O pin. This would prevent devices from stretching the clock period. */ -reg [7:0] wbs_dat_o_reg = 8'd0, wbs_dat_o_next; -reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; - -reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; -reg cmd_start_reg = 1'b0, cmd_start_next; -reg cmd_read_reg = 1'b0, cmd_read_next; -reg cmd_write_reg = 1'b0, cmd_write_next; -reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; -reg cmd_stop_reg = 1'b0, cmd_stop_next; -reg cmd_valid_reg = 1'b0, cmd_valid_next; -wire cmd_ready; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; -reg data_in_last_reg = 1'b0, data_in_last_next; - -wire [7:0] data_out; -wire data_out_valid; -reg data_out_ready_reg = 1'b0, data_out_ready_next; -wire data_out_last; - -reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; - -reg missed_ack_reg = 1'b0, missed_ack_next; - -assign wbs_dat_o = wbs_dat_o_reg; -assign wbs_ack_o = wbs_ack_o_reg; - -wire [6:0] cmd_address_int; -wire cmd_start_int; -wire cmd_read_int; -wire cmd_write_int; -wire cmd_write_multiple_int; -wire cmd_stop_int; -wire cmd_valid_int; -wire cmd_ready_int; - -wire [7:0] data_in_int; -wire data_in_valid_int; -wire data_in_ready_int; -wire data_in_last_int; - -wire [7:0] data_out_int; -wire data_out_valid_int; -wire data_out_ready_int; -wire data_out_last_int; - -wire busy_int; -wire bus_control_int; -wire bus_active_int; -wire missed_ack_int; - -wire cmd_fifo_empty = ~cmd_valid_int; -wire cmd_fifo_full = ~cmd_ready; -wire write_fifo_empty = ~data_in_valid_int; -wire write_fifo_full = ~data_in_ready; -wire read_fifo_empty = ~data_out_valid; -wire read_fifo_full = ~data_out_ready_int; - -reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; -reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; - - -generate - -if (CMD_FIFO) begin - axis_fifo #( - .DEPTH(CMD_FIFO_DEPTH), - .DATA_WIDTH(7+5), - .KEEP_ENABLE(0), - .LAST_ENABLE(0), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - cmd_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata({cmd_address_reg, cmd_start_reg, cmd_read_reg, cmd_write_reg, cmd_write_multiple_reg, cmd_stop_reg}), - .s_axis_tkeep(0), - .s_axis_tvalid(cmd_valid_reg), - .s_axis_tready(cmd_ready), - .s_axis_tlast(1'b0), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata({cmd_address_int, cmd_start_int, cmd_read_int, cmd_write_int, cmd_write_multiple_int, cmd_stop_int}), - .m_axis_tkeep(), - .m_axis_tvalid(cmd_valid_int), - .m_axis_tready(cmd_ready_int), - .m_axis_tlast(), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign cmd_address_int = cmd_address_reg; - assign cmd_start_int = cmd_start_reg; - assign cmd_read_int = cmd_read_reg; - assign cmd_write_int = cmd_write_reg; - assign cmd_write_multiple_int = cmd_write_multiple_reg; - assign cmd_stop_int = cmd_stop_reg; - assign cmd_valid_int = cmd_valid_reg; - assign cmd_ready = cmd_ready_int; -end - -if (WRITE_FIFO) begin - axis_fifo #( - .DEPTH(WRITE_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - write_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_in_reg), - .s_axis_tkeep(0), - .s_axis_tvalid(data_in_valid_reg), - .s_axis_tready(data_in_ready), - .s_axis_tlast(data_in_last_reg), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(1'b0), - // AXI output - .m_axis_tdata(data_in_int), - .m_axis_tkeep(), - .m_axis_tvalid(data_in_valid_int), - .m_axis_tready(data_in_ready_int), - .m_axis_tlast(data_in_last_int), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_in_int = data_in_reg; - assign data_in_valid = data_in_valid_reg; - assign data_in_ready = data_in_ready_int; - assign data_in_last = data_in_last_reg; -end - -if (READ_FIFO) begin - axis_fifo #( - .DEPTH(READ_FIFO_DEPTH), - .DATA_WIDTH(8), - .KEEP_ENABLE(0), - .LAST_ENABLE(1), - .ID_ENABLE(0), - .DEST_ENABLE(0), - .USER_ENABLE(0), - .FRAME_FIFO(0) - ) - read_fifo_inst ( - .clk(clk), - .rst(rst), - // AXI input - .s_axis_tdata(data_out_int), - .s_axis_tkeep(0), - .s_axis_tvalid(data_out_valid_int), - .s_axis_tready(data_out_ready_int), - .s_axis_tlast(data_out_last_int), - .s_axis_tid(0), - .s_axis_tdest(0), - .s_axis_tuser(0), - // AXI output - .m_axis_tdata(data_out), - .m_axis_tkeep(), - .m_axis_tvalid(data_out_valid), - .m_axis_tready(data_out_ready_reg), - .m_axis_tlast(data_out_last), - .m_axis_tid(), - .m_axis_tdest(), - .m_axis_tuser() - ); -end else begin - assign data_out = data_out_int; - assign data_out_valid = data_out_valid_int; - assign data_out_ready_int = data_out_ready_reg; - assign data_out_last = data_out_last_int; -end - -endgenerate - -always @* begin + reg [7:0] wbs_dat_o_reg = 8'd0, wbs_dat_o_next; + reg wbs_ack_o_reg = 1'b0, wbs_ack_o_next; + + reg [6:0] cmd_address_reg = 7'd0, cmd_address_next; + reg cmd_start_reg = 1'b0, cmd_start_next; + reg cmd_read_reg = 1'b0, cmd_read_next; + reg cmd_write_reg = 1'b0, cmd_write_next; + reg cmd_write_multiple_reg = 1'b0, cmd_write_multiple_next; + reg cmd_stop_reg = 1'b0, cmd_stop_next; + reg cmd_valid_reg = 1'b0, cmd_valid_next; + wire cmd_ready; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + reg data_in_last_reg = 1'b0, data_in_last_next; + + wire [7:0] data_out; + wire data_out_valid; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire data_out_last; + + reg [15:0] prescale_reg = DEFAULT_PRESCALE, prescale_next; + + reg missed_ack_reg = 1'b0, missed_ack_next; + + assign wbs_dat_o = wbs_dat_o_reg; + assign wbs_ack_o = wbs_ack_o_reg; + + wire [6:0] cmd_address_int; + wire cmd_start_int; + wire cmd_read_int; + wire cmd_write_int; + wire cmd_write_multiple_int; + wire cmd_stop_int; + wire cmd_valid_int; + wire cmd_ready_int; + + wire [7:0] data_in_int; + wire data_in_valid_int; + wire data_in_ready_int; + wire data_in_last_int; + + wire [7:0] data_out_int; + wire data_out_valid_int; + wire data_out_ready_int; + wire data_out_last_int; + + wire busy_int; + wire bus_control_int; + wire bus_active_int; + wire missed_ack_int; + + wire cmd_fifo_empty = ~cmd_valid_int; + wire cmd_fifo_full = ~cmd_ready; + wire write_fifo_empty = ~data_in_valid_int; + wire write_fifo_full = ~data_in_ready; + wire read_fifo_empty = ~data_out_valid; + wire read_fifo_full = ~data_out_ready_int; + + reg cmd_fifo_overflow_reg = 1'b0, cmd_fifo_overflow_next; + reg write_fifo_overflow_reg = 1'b0, write_fifo_overflow_next; + + + generate + + if (CMD_FIFO) begin + axis_fifo #( + .DEPTH(CMD_FIFO_DEPTH), + .DATA_WIDTH(7 + 5), + .KEEP_ENABLE(0), + .LAST_ENABLE(0), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) cmd_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata({ + cmd_address_reg, + cmd_start_reg, + cmd_read_reg, + cmd_write_reg, + cmd_write_multiple_reg, + cmd_stop_reg + }), + .s_axis_tkeep(0), + .s_axis_tvalid(cmd_valid_reg), + .s_axis_tready(cmd_ready), + .s_axis_tlast(1'b0), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata({ + cmd_address_int, + cmd_start_int, + cmd_read_int, + cmd_write_int, + cmd_write_multiple_int, + cmd_stop_int + }), + .m_axis_tkeep(), + .m_axis_tvalid(cmd_valid_int), + .m_axis_tready(cmd_ready_int), + .m_axis_tlast(), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign cmd_address_int = cmd_address_reg; + assign cmd_start_int = cmd_start_reg; + assign cmd_read_int = cmd_read_reg; + assign cmd_write_int = cmd_write_reg; + assign cmd_write_multiple_int = cmd_write_multiple_reg; + assign cmd_stop_int = cmd_stop_reg; + assign cmd_valid_int = cmd_valid_reg; + assign cmd_ready = cmd_ready_int; + end + + if (WRITE_FIFO) begin + axis_fifo #( + .DEPTH(WRITE_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) write_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_in_reg), + .s_axis_tkeep(0), + .s_axis_tvalid(data_in_valid_reg), + .s_axis_tready(data_in_ready), + .s_axis_tlast(data_in_last_reg), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(1'b0), + // AXI output + .m_axis_tdata(data_in_int), + .m_axis_tkeep(), + .m_axis_tvalid(data_in_valid_int), + .m_axis_tready(data_in_ready_int), + .m_axis_tlast(data_in_last_int), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_in_int = data_in_reg; + assign data_in_valid = data_in_valid_reg; + assign data_in_ready = data_in_ready_int; + assign data_in_last = data_in_last_reg; + end + + if (READ_FIFO) begin + axis_fifo #( + .DEPTH(READ_FIFO_DEPTH), + .DATA_WIDTH(8), + .KEEP_ENABLE(0), + .LAST_ENABLE(1), + .ID_ENABLE(0), + .DEST_ENABLE(0), + .USER_ENABLE(0), + .FRAME_FIFO(0) + ) read_fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(data_out_int), + .s_axis_tkeep(0), + .s_axis_tvalid(data_out_valid_int), + .s_axis_tready(data_out_ready_int), + .s_axis_tlast(data_out_last_int), + .s_axis_tid(0), + .s_axis_tdest(0), + .s_axis_tuser(0), + // AXI output + .m_axis_tdata(data_out), + .m_axis_tkeep(), + .m_axis_tvalid(data_out_valid), + .m_axis_tready(data_out_ready_reg), + .m_axis_tlast(data_out_last), + .m_axis_tid(), + .m_axis_tdest(), + .m_axis_tuser() + ); + end else begin + assign data_out = data_out_int; + assign data_out_valid = data_out_valid_int; + assign data_out_ready_int = data_out_ready_reg; + assign data_out_last = data_out_last_int; + end + + endgenerate + + always @* begin wbs_dat_o_next = 8'd0; wbs_ack_o_next = 1'b0; @@ -455,130 +464,130 @@ always @* begin cmd_fifo_overflow_next = cmd_fifo_overflow_reg; write_fifo_overflow_next = write_fifo_overflow_reg; - + if (wbs_cyc_i & wbs_stb_i) begin - // bus cycle - if (wbs_we_i) begin - // write cycle - case (wbs_adr_i) - 4'h0: begin - // status - if (wbs_dat_i[3]) begin - missed_ack_next = missed_ack_int; - end - end - 4'h1: begin - // FIFO status - if (wbs_dat_i[2]) begin - cmd_fifo_overflow_next = 1'b0; - end - if (wbs_dat_i[5]) begin - write_fifo_overflow_next = 1'b0; - end - end - 4'h2: begin - // command address - cmd_address_next = wbs_dat_i; - end - 4'h3: begin - // command - cmd_start_next = wbs_dat_i[0]; - cmd_read_next = wbs_dat_i[1]; - cmd_write_next = wbs_dat_i[2]; - //cmd_write_multiple_next = wbs_dat_i[3]; - cmd_stop_next = wbs_dat_i[4]; - cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_stop_next); - - cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); - end - 4'h4: begin - // data - data_in_next = wbs_dat_i; - data_in_valid_next = ~wbs_ack_o_reg; - - write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; - end - 4'h5: begin - // reserved - end - 4'h6: begin - // prescale low - if (!FIXED_PRESCALE) begin - prescale_next[7:0] = wbs_dat_i; - end - end - 4'h7: begin - // prescale high - if (!FIXED_PRESCALE) begin - prescale_next[15:8] = wbs_dat_i; - end - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end else begin - // read cycle - case (wbs_adr_i) - 4'h0: begin - // status - wbs_dat_o_next[0] = busy_int; - wbs_dat_o_next[1] = bus_control_int; - wbs_dat_o_next[2] = bus_active_int; - wbs_dat_o_next[3] = missed_ack_reg; - wbs_dat_o_next[4] = 1'b0; - wbs_dat_o_next[5] = 1'b0; - wbs_dat_o_next[6] = 1'b0; - wbs_dat_o_next[7] = 1'b0; - end - 4'h1: begin - // FIFO status - wbs_dat_o_next[0] = cmd_fifo_empty; - wbs_dat_o_next[1] = cmd_fifo_full; - wbs_dat_o_next[2] = cmd_fifo_overflow_reg; - wbs_dat_o_next[3] = write_fifo_empty; - wbs_dat_o_next[4] = write_fifo_full; - wbs_dat_o_next[5] = write_fifo_overflow_reg; - wbs_dat_o_next[6] = read_fifo_empty; - wbs_dat_o_next[7] = read_fifo_full; - end - 4'h2: begin - // command address - wbs_dat_o_next = cmd_address_reg; - end - 4'h3: begin - // command - wbs_dat_o_next[0] = cmd_start_reg; - wbs_dat_o_next[1] = cmd_read_reg; - wbs_dat_o_next[2] = cmd_write_reg; - wbs_dat_o_next[3] = cmd_write_multiple_reg; - wbs_dat_o_next[4] = cmd_stop_reg; - wbs_dat_o_next[5] = 1'b0; - wbs_dat_o_next[6] = 1'b0; - wbs_dat_o_next[7] = 1'b0; - end - 4'h4: begin - // data - wbs_dat_o_next = data_out; - data_out_ready_next = !wbs_ack_o_reg && data_out_valid; - end - 4'h5: begin - // reserved - wbs_dat_o_next = 8'd0; - end - 4'h6: begin - // prescale low - wbs_dat_o_next = prescale_reg[7:0]; - end - 4'h7: begin - // prescale high - wbs_dat_o_next = prescale_reg[15:8]; - end - endcase - wbs_ack_o_next = ~wbs_ack_o_reg; - end + // bus cycle + if (wbs_we_i) begin + // write cycle + case (wbs_adr_i) + 4'h0: begin + // status + if (wbs_dat_i[3]) begin + missed_ack_next = missed_ack_int; + end + end + 4'h1: begin + // FIFO status + if (wbs_dat_i[2]) begin + cmd_fifo_overflow_next = 1'b0; + end + if (wbs_dat_i[5]) begin + write_fifo_overflow_next = 1'b0; + end + end + 4'h2: begin + // command address + cmd_address_next = wbs_dat_i; + end + 4'h3: begin + // command + cmd_start_next = wbs_dat_i[0]; + cmd_read_next = wbs_dat_i[1]; + cmd_write_next = wbs_dat_i[2]; + //cmd_write_multiple_next = wbs_dat_i[3]; + cmd_stop_next = wbs_dat_i[4]; + cmd_valid_next = ~wbs_ack_o_reg & (cmd_start_next | cmd_read_next | cmd_write_next | cmd_stop_next); + + cmd_fifo_overflow_next = cmd_fifo_overflow_next | (cmd_valid_next & ~cmd_ready); + end + 4'h4: begin + // data + data_in_next = wbs_dat_i; + data_in_valid_next = ~wbs_ack_o_reg; + + write_fifo_overflow_next = write_fifo_overflow_next | ~data_in_ready; + end + 4'h5: begin + // reserved + end + 4'h6: begin + // prescale low + if (!FIXED_PRESCALE) begin + prescale_next[7:0] = wbs_dat_i; + end + end + 4'h7: begin + // prescale high + if (!FIXED_PRESCALE) begin + prescale_next[15:8] = wbs_dat_i; + end + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end else begin + // read cycle + case (wbs_adr_i) + 4'h0: begin + // status + wbs_dat_o_next[0] = busy_int; + wbs_dat_o_next[1] = bus_control_int; + wbs_dat_o_next[2] = bus_active_int; + wbs_dat_o_next[3] = missed_ack_reg; + wbs_dat_o_next[4] = 1'b0; + wbs_dat_o_next[5] = 1'b0; + wbs_dat_o_next[6] = 1'b0; + wbs_dat_o_next[7] = 1'b0; + end + 4'h1: begin + // FIFO status + wbs_dat_o_next[0] = cmd_fifo_empty; + wbs_dat_o_next[1] = cmd_fifo_full; + wbs_dat_o_next[2] = cmd_fifo_overflow_reg; + wbs_dat_o_next[3] = write_fifo_empty; + wbs_dat_o_next[4] = write_fifo_full; + wbs_dat_o_next[5] = write_fifo_overflow_reg; + wbs_dat_o_next[6] = read_fifo_empty; + wbs_dat_o_next[7] = read_fifo_full; + end + 4'h2: begin + // command address + wbs_dat_o_next = cmd_address_reg; + end + 4'h3: begin + // command + wbs_dat_o_next[0] = cmd_start_reg; + wbs_dat_o_next[1] = cmd_read_reg; + wbs_dat_o_next[2] = cmd_write_reg; + wbs_dat_o_next[3] = cmd_write_multiple_reg; + wbs_dat_o_next[4] = cmd_stop_reg; + wbs_dat_o_next[5] = 1'b0; + wbs_dat_o_next[6] = 1'b0; + wbs_dat_o_next[7] = 1'b0; + end + 4'h4: begin + // data + wbs_dat_o_next = data_out; + data_out_ready_next = !wbs_ack_o_reg && data_out_valid; + end + 4'h5: begin + // reserved + wbs_dat_o_next = 8'd0; + end + 4'h6: begin + // prescale low + wbs_dat_o_next = prescale_reg[7:0]; + end + 4'h7: begin + // prescale high + wbs_dat_o_next = prescale_reg[15:8]; + end + endcase + wbs_ack_o_next = ~wbs_ack_o_reg; + end end -end + end -always @(posedge clk) begin + always @(posedge clk) begin wbs_dat_o_reg <= wbs_dat_o_next; wbs_ack_o_reg <= wbs_ack_o_next; @@ -604,59 +613,58 @@ always @(posedge clk) begin write_fifo_overflow_reg <= write_fifo_overflow_next; if (rst) begin - wbs_ack_o_reg <= 1'b0; - cmd_valid_reg <= 1'b0; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - prescale_reg <= DEFAULT_PRESCALE; - missed_ack_reg <= 1'b0; - cmd_fifo_overflow_reg <= 0; - write_fifo_overflow_reg <= 0; + wbs_ack_o_reg <= 1'b0; + cmd_valid_reg <= 1'b0; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + prescale_reg <= DEFAULT_PRESCALE; + missed_ack_reg <= 1'b0; + cmd_fifo_overflow_reg <= 0; + write_fifo_overflow_reg <= 0; end -end - -i2c_master -i2c_master_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .s_axis_cmd_address(cmd_address_int), - .s_axis_cmd_start(cmd_start_int), - .s_axis_cmd_read(cmd_read_int), - .s_axis_cmd_write(cmd_write_int), - .s_axis_cmd_write_multiple(cmd_write_multiple_int), - .s_axis_cmd_stop(cmd_stop_int), - .s_axis_cmd_valid(cmd_valid_int), - .s_axis_cmd_ready(cmd_ready_int), - - .s_axis_data_tdata(data_in_int), - .s_axis_data_tvalid(data_in_valid_int), - .s_axis_data_tready(data_in_ready_int), - .s_axis_data_tlast(data_in_last_int), - - .m_axis_data_tdata(data_out_int), - .m_axis_data_tvalid(data_out_valid_int), - .m_axis_data_tready(data_out_ready_int), - .m_axis_data_tlast(data_out_last_int), - - // I2C interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(busy_int), - .bus_control(bus_control_int), - .bus_active(bus_active_int), - .missed_ack(missed_ack_int), - - // Configuration - .prescale(prescale_reg), - .stop_on_idle(1'b0) -); + end + + i2c_master i2c_master_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .s_axis_cmd_address(cmd_address_int), + .s_axis_cmd_start(cmd_start_int), + .s_axis_cmd_read(cmd_read_int), + .s_axis_cmd_write(cmd_write_int), + .s_axis_cmd_write_multiple(cmd_write_multiple_int), + .s_axis_cmd_stop(cmd_stop_int), + .s_axis_cmd_valid(cmd_valid_int), + .s_axis_cmd_ready(cmd_ready_int), + + .s_axis_data_tdata (data_in_int), + .s_axis_data_tvalid(data_in_valid_int), + .s_axis_data_tready(data_in_ready_int), + .s_axis_data_tlast (data_in_last_int), + + .m_axis_data_tdata (data_out_int), + .m_axis_data_tvalid(data_out_valid_int), + .m_axis_data_tready(data_out_ready_int), + .m_axis_data_tlast (data_out_last_int), + + // I2C interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(busy_int), + .bus_control(bus_control_int), + .bus_active(bus_active_int), + .missed_ack(missed_ack_int), + + // Configuration + .prescale(prescale_reg), + .stop_on_idle(1'b0) + ); endmodule diff --git a/rtl/i2c_phy.v b/rtl/i2c_phy.v new file mode 100644 index 0000000..b92b18c --- /dev/null +++ b/rtl/i2c_phy.v @@ -0,0 +1,352 @@ + +`timescale 1ns / 1ps +module i2c_phy ( + input wire clk, + input wire rst_n, + + // Control signals + input wire phy_start_bit, + input wire phy_stop_bit, + input wire phy_write_bit, + input wire phy_read_bit, + input wire phy_tx_data, + input wire phy_release_bus, + + // I2C interface + input wire scl_i, + output wire scl_o, + input wire sda_i, + output wire sda_o, + output wire sda_t, + output wire scl_t, + + // Status and data + output reg phy_busy = 1'b0, + output reg bus_control_reg, + output reg phy_rx_data_reg, + output reg [4:0] phy_state_reg, + + // Configuration + input wire [16:0] prescale +); + localparam [4:0] + PHY_STATE_IDLE = 5'd0, + PHY_STATE_ACTIVE = 5'd1, + PHY_STATE_REPEATED_START_1 = 5'd2, + PHY_STATE_REPEATED_START_2 = 5'd3, + PHY_STATE_START_1 = 5'd4, + PHY_STATE_START_2 = 5'd5, + PHY_STATE_WRITE_BIT_1 = 5'd6, + PHY_STATE_WRITE_BIT_2 = 5'd7, + PHY_STATE_WRITE_BIT_3 = 5'd8, + PHY_STATE_READ_BIT_1 = 5'd9, + PHY_STATE_READ_BIT_2 = 5'd10, + PHY_STATE_READ_BIT_3 = 5'd11, + PHY_STATE_READ_BIT_4 = 5'd12, + PHY_STATE_STOP_1 = 5'd13, + PHY_STATE_STOP_2 = 5'd14, + PHY_STATE_STOP_3 = 5'd15; + + + + // Internal registers + + reg scl_o_reg = 1; + reg scl_i_reg = 1; + reg sda_i_reg = 1; + reg sda_o_reg = 1; + + + reg phy_rx_data_next = 0; + + reg [4:0] phy_state_next; + + reg [16:0] delay_reg = 17'd0, delay_next; + reg delay_scl_reg = 1'b0, delay_scl_next; + reg delay_sda_reg = 1'b0, delay_sda_next; + + reg scl_o_next = 1; + reg sda_o_next = 1; + + reg bus_control_next = 0; + + assign scl_o = scl_o_reg; + assign scl_t = scl_o_reg; + assign sda_o = sda_o_reg; + assign sda_t = sda_o_reg; + + + always @* begin + phy_state_next = PHY_STATE_IDLE; + + phy_rx_data_next = phy_rx_data_reg; + + delay_next = delay_reg; + delay_scl_next = delay_scl_reg; + delay_sda_next = delay_sda_reg; + + scl_o_next = scl_o_reg; + sda_o_next = sda_o_reg; + + bus_control_next = bus_control_reg; + + if (phy_release_bus) begin + // release bus and return to idle state + sda_o_next = 1'b1; + scl_o_next = 1'b1; + delay_scl_next = 1'b0; + delay_sda_next = 1'b0; + delay_next = 17'd0; + phy_state_next = PHY_STATE_IDLE; + end else if (delay_scl_reg) begin + // wait for SCL to match command + delay_scl_next = scl_o_reg & ~scl_i_reg; + phy_state_next = phy_state_reg; + end else if (delay_sda_reg) begin + // wait for SDA to match command + delay_sda_next = sda_o_reg & ~sda_i_reg; + phy_state_next = phy_state_reg; + end else if (delay_reg > 0) begin + // time delay + delay_next = delay_reg - 1; + phy_state_next = phy_state_reg; + end else begin + case (phy_state_reg) + PHY_STATE_IDLE: begin + //$display("idle, simply wait"); + // bus idle - wait for start command + sda_o_next = 1'b1; + scl_o_next = 1'b1; + if (phy_start_bit) begin + //$display("idle, "); + sda_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_START_1; + end else begin + phy_state_next = PHY_STATE_IDLE; + end + end + PHY_STATE_ACTIVE: begin + // bus active + if (phy_start_bit) begin + //$display("start bit should have reset"); + + sda_o_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_REPEATED_START_1; + end else if (phy_write_bit) begin + sda_o_next = phy_tx_data; + delay_next = prescale; + phy_state_next = PHY_STATE_WRITE_BIT_1; + end else if (phy_read_bit) begin + sda_o_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_1; + end else if (phy_stop_bit) begin + sda_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_STOP_1; + end else begin + //$display("Do nothing, leave things as is"); + phy_state_next = PHY_STATE_ACTIVE; + end + end + PHY_STATE_REPEATED_START_1: begin + // generate repeated start bit + // ______ + // sda XXX/ \_______ + // _______ + // scl ______/ \___ + // + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_REPEATED_START_2; + end + PHY_STATE_REPEATED_START_2: begin + // generate repeated start bit + // ______ + // sda XXX/ \_______ + // _______ + // scl ______/ \___ + // + + sda_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_START_1; + end + PHY_STATE_START_1: begin + // generate start bit + // ___ + // sda \_______ + // _______ + // scl \___ + // + + scl_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_START_2; + end + PHY_STATE_START_2: begin + // generate start bit + // ___ + // sda \_______ + // _______ + // scl \___ + // + + bus_control_next = 1'b1; + phy_state_next = PHY_STATE_ACTIVE; + end + PHY_STATE_WRITE_BIT_1: begin + // write bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale << 1; + phy_state_next = PHY_STATE_WRITE_BIT_2; + end + PHY_STATE_WRITE_BIT_2: begin + // write bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_WRITE_BIT_3; + end + PHY_STATE_WRITE_BIT_3: begin + // write bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + phy_state_next = PHY_STATE_ACTIVE; + end + PHY_STATE_READ_BIT_1: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_2; + end + PHY_STATE_READ_BIT_2: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + phy_rx_data_next = sda_i_reg; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_3; + end + PHY_STATE_READ_BIT_3: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + scl_o_next = 1'b0; + delay_next = prescale; + phy_state_next = PHY_STATE_READ_BIT_4; + end + PHY_STATE_READ_BIT_4: begin + // read bit + // ________ + // sda X________X + // ____ + // scl __/ \__ + + phy_state_next = PHY_STATE_ACTIVE; + end + PHY_STATE_STOP_1: begin + // stop bit + // ___ + // sda XXX\_______/ + // _______ + // scl _______/ + + scl_o_next = 1'b1; + delay_scl_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_STOP_2; + end + PHY_STATE_STOP_2: begin + // stop bit + // ___ + // sda XXX\_______/ + // _______ + // scl _______/ + + sda_o_next = 1'b1; + delay_next = prescale; + phy_state_next = PHY_STATE_STOP_3; + end + PHY_STATE_STOP_3: begin + // stop bit + // ___ + // sda XXX\_______/ + // _______ + // scl _______/ + + bus_control_next = 1'b0; + phy_state_next = PHY_STATE_IDLE; + end + default: begin + phy_state_next = PHY_STATE_IDLE; + end + endcase + end + end + + + always @(posedge clk or negedge rst_n) begin + + if (~rst_n) begin + phy_rx_data_reg <= 1'b0; + phy_state_reg <= PHY_STATE_IDLE; + delay_reg <= 17'd0; + delay_scl_reg <= 1'b0; + delay_sda_reg <= 1'b0; + scl_o_reg <= 1'b1; + sda_o_reg <= 1'b1; + bus_control_reg <= 1'b0; + end else begin + phy_state_reg <= phy_state_next; + + phy_rx_data_reg <= phy_rx_data_next; + + + delay_reg <= delay_next; + delay_scl_reg <= delay_scl_next; + delay_sda_reg <= delay_sda_next; + + + scl_i_reg <= scl_i; + sda_i_reg <= sda_i; + + scl_o_reg <= scl_o_next; + sda_o_reg <= sda_o_next; + + bus_control_reg <= bus_control_next; + end + end + + + +endmodule diff --git a/rtl/i2c_single_reg.v b/rtl/i2c_single_reg.v index 035238c..9b5a620 100644 --- a/rtl/i2c_single_reg.v +++ b/rtl/i2c_single_reg.v @@ -24,8 +24,8 @@ THE SOFTWARE. // Language: Verilog 2001 -`resetall -`timescale 1ns / 1ps +`resetall //comment hack verible not compatible with verilator +`timescale 1ns / 1ps //commen hack2 `default_nettype none /* @@ -33,21 +33,21 @@ THE SOFTWARE. */ module i2c_single_reg #( parameter FILTER_LEN = 4, - parameter DEV_ADDR = 7'h70 -) -( - input wire clk, - input wire rst, + parameter DEV_ADDR = 7'h70, + parameter DEBUG = 0 +) ( + input wire clk, + input wire rst_n, /* * I2C interface */ - input wire scl_i, - output wire scl_o, - output wire scl_t, - input wire sda_i, - output wire sda_o, - output wire sda_t, + input wire scl_i, + output wire scl_o, + output wire scl_t, + input wire sda_i, + output wire sda_o, + output wire sda_t, /* * Data register @@ -57,211 +57,217 @@ module i2c_single_reg #( output wire [7:0] data_out ); -localparam [4:0] - STATE_IDLE = 4'd0, - STATE_ADDRESS = 4'd1, - STATE_ACK = 4'd2, - STATE_WRITE_1 = 4'd3, - STATE_WRITE_2 = 4'd4, - STATE_READ_1 = 4'd5, - STATE_READ_2 = 4'd6, - STATE_READ_3 = 4'd7; + localparam [4:0] + STATE_IDLE = 5'd0, + STATE_ADDRESS = 5'd1, + STATE_ACK = 5'd2, + STATE_WRITE_1 = 5'd3, + STATE_WRITE_2 = 5'd4, + STATE_READ_1 = 5'd5, + STATE_READ_2 = 5'd6, + STATE_READ_3 = 5'd7; -reg [4:0] state_reg = STATE_IDLE; + reg [4:0] state_reg = STATE_IDLE; -reg [7:0] data_reg = 8'd0; -reg [7:0] shift_reg = 8'd0; + reg [7:0] data_reg = 8'd0; + reg [7:0] shift_reg = 8'd0; -reg mode_read_reg = 1'b0; + reg mode_read_reg = 1'b0; -reg [3:0] bit_count_reg = 4'd0; + reg [3:0] bit_count_reg = 4'd0; -reg [FILTER_LEN-1:0] scl_i_filter_reg = {FILTER_LEN{1'b1}}; -reg [FILTER_LEN-1:0] sda_i_filter_reg = {FILTER_LEN{1'b1}}; + reg [FILTER_LEN-1:0] scl_i_filter_reg = {FILTER_LEN{1'b0}}; + reg [FILTER_LEN-1:0] sda_i_filter_reg = {FILTER_LEN{1'b0}}; -reg scl_i_reg = 1'b1; -reg sda_i_reg = 1'b1; + reg scl_i_reg = 1'b0; + reg sda_i_reg = 1'b0; -reg sda_o_reg = 1'b1; + reg sda_o_reg = 1'b1; -reg last_scl_i_reg = 1'b1; -reg last_sda_i_reg = 1'b1; + reg last_scl_i_reg = 1'b0; + reg last_sda_i_reg = 1'b0; -assign scl_o = 1'b1; -assign scl_t = 1'b1; -assign sda_o = sda_o_reg; -assign sda_t = sda_o_reg; + assign scl_o = 1'b1; + assign scl_t = 1'b1; + assign sda_o = sda_o_reg; + assign sda_t = sda_o_reg; -assign data_out = data_reg; + assign data_out = data_reg; -wire scl_posedge = scl_i_reg && !last_scl_i_reg; -wire scl_negedge = !scl_i_reg && last_scl_i_reg; -wire sda_posedge = sda_i_reg && !last_sda_i_reg; -wire sda_negedge = !sda_i_reg && last_sda_i_reg; + wire scl_posedge = scl_i_reg && !last_scl_i_reg; + wire scl_negedge = !scl_i_reg && last_scl_i_reg; + wire sda_posedge = sda_i_reg && !last_sda_i_reg; + wire sda_negedge = !sda_i_reg && last_sda_i_reg; -wire start_bit = sda_negedge && scl_i_reg; -wire stop_bit = sda_posedge && scl_i_reg; + wire start_bit = sda_negedge && scl_i_reg; + wire stop_bit = sda_posedge && scl_i_reg; -always @(posedge clk) begin + always @(posedge clk or negedge rst_n) begin + if (~rst_n) begin + state_reg <= STATE_IDLE; + sda_o_reg <= 1'b1; + end else begin - if (start_bit) begin + if (start_bit) begin sda_o_reg <= 1'b1; - bit_count_reg = 4'd7; + bit_count_reg <= 4'd7; state_reg <= STATE_ADDRESS; - end else if (stop_bit) begin + end else if (stop_bit) begin sda_o_reg <= 1'b1; state_reg <= STATE_IDLE; - end else begin + end else begin case (state_reg) - STATE_IDLE: begin - // line idle - sda_o_reg <= 1'b1; - - state_reg <= STATE_IDLE; - end - STATE_ADDRESS: begin - // read address - sda_o_reg <= 1'b1; - - if (scl_posedge) begin - if (bit_count_reg > 0) begin - // shift in address - bit_count_reg <= bit_count_reg-1; - shift_reg <= {shift_reg[6:0], sda_i_reg}; - state_reg <= STATE_ADDRESS; - end else begin - // check address - mode_read_reg <= sda_i_reg; - if (shift_reg[6:0] == DEV_ADDR) begin - // it's a match, send ACK - state_reg <= STATE_ACK; - end else begin - // no match, return to idle - state_reg <= STATE_IDLE; - end - end + STATE_IDLE: begin + // line idle + sda_o_reg <= 1'b1; + + state_reg <= STATE_IDLE; + end + STATE_ADDRESS: begin + // read address + sda_o_reg <= 1'b1; + + if (scl_posedge) begin + if (bit_count_reg > 0) begin + // shift in address + bit_count_reg <= bit_count_reg - 1; + shift_reg <= {shift_reg[6:0], sda_i_reg}; + state_reg <= STATE_ADDRESS; + end else begin + // check address + mode_read_reg <= sda_i_reg; + if (DEBUG) $display("i2c single reg: received address %h", shift_reg[6:0]); + if (shift_reg[6:0] == DEV_ADDR) begin + + // it's a match, send ACK + state_reg <= STATE_ACK; end else begin - state_reg <= STATE_ADDRESS; + // no match, return to idle + state_reg <= STATE_IDLE; end + end + end else begin + state_reg <= STATE_ADDRESS; end - STATE_ACK: begin - // send ACK bit - if (scl_negedge) begin - sda_o_reg <= 1'b0; - bit_count_reg <= 4'd7; - if (mode_read_reg) begin - // reading - shift_reg <= data_reg; - state_reg <= STATE_READ_1; - end else begin - // writing - state_reg <= STATE_WRITE_1; - end - end else begin - state_reg <= STATE_ACK; - end + end + STATE_ACK: begin + // send ACK bit + if (scl_negedge) begin + sda_o_reg <= 1'b0; + bit_count_reg <= 4'd7; + if (mode_read_reg) begin + // reading + shift_reg <= data_reg; + state_reg <= STATE_READ_1; + end else begin + // writing + state_reg <= STATE_WRITE_1; + end + end else begin + state_reg <= STATE_ACK; end - STATE_WRITE_1: begin - // write data byte - if (scl_negedge) begin - sda_o_reg <= 1'b1; - state_reg <= STATE_WRITE_2; - end else begin - state_reg <= STATE_WRITE_1; - end + end + STATE_WRITE_1: begin + // write data byte + if (scl_negedge) begin + sda_o_reg <= 1'b1; + state_reg <= STATE_WRITE_2; + end else begin + state_reg <= STATE_WRITE_1; end - STATE_WRITE_2: begin - // write data byte - sda_o_reg <= 1'b1; - if (scl_posedge) begin - // shift in data bit - shift_reg <= {shift_reg[6:0], sda_i_reg}; - if (bit_count_reg > 0) begin - bit_count_reg <= bit_count_reg-1; - state_reg <= STATE_WRITE_2; - end else begin - data_reg <= {shift_reg[6:0], sda_i_reg}; - state_reg <= STATE_ACK; - end - end else begin - state_reg <= STATE_WRITE_2; - end + end + STATE_WRITE_2: begin + // write data byte + sda_o_reg <= 1'b1; + if (scl_posedge) begin + // shift in data bit + shift_reg <= {shift_reg[6:0], sda_i_reg}; + if (bit_count_reg > 0) begin + bit_count_reg <= bit_count_reg - 1; + state_reg <= STATE_WRITE_2; + end else begin + data_reg <= {shift_reg[6:0], sda_i_reg}; + if (DEBUG) + $display("i2c single reg: Received data: %h", {shift_reg[6:0], sda_i_reg}); + state_reg <= STATE_ACK; + end + end else begin + state_reg <= STATE_WRITE_2; end - STATE_READ_1: begin - // read data byte - if (scl_negedge) begin - // shift out data bit - {sda_o_reg, shift_reg} = {shift_reg, sda_i_reg}; - - if (bit_count_reg > 0) begin - bit_count_reg = bit_count_reg-1; - state_reg = STATE_READ_1; - end else begin - state_reg = STATE_READ_2; - end - end else begin - state_reg = STATE_READ_1; - end + end + STATE_READ_1: begin + // read data byte + if (scl_negedge) begin + // shift out data bit + {sda_o_reg, shift_reg} <= {shift_reg, sda_i_reg}; + + if (bit_count_reg > 0) begin + bit_count_reg <= bit_count_reg - 1; + state_reg <= STATE_READ_1; + end else begin + state_reg <= STATE_READ_2; + end + end else begin + state_reg <= STATE_READ_1; end - STATE_READ_2: begin - // read ACK bit - if (scl_negedge) begin - // release SDA - sda_o_reg <= 1'b1; - state_reg <= STATE_READ_3; - end else begin - state_reg <= STATE_READ_2; - end + end + STATE_READ_2: begin + // read ACK bit + if (scl_negedge) begin + // release SDA + sda_o_reg <= 1'b1; + state_reg <= STATE_READ_3; + end else begin + state_reg <= STATE_READ_2; end - STATE_READ_3: begin - // read ACK bit - if (scl_posedge) begin - if (sda_i_reg) begin - // NACK, return to idle - state_reg <= STATE_IDLE; - end else begin - // ACK, read another byte - bit_count_reg <= 4'd7; - shift_reg <= data_reg; - state_reg <= STATE_READ_1; - end - end else begin - state_reg <= STATE_READ_3; - end + end + STATE_READ_3: begin + // read ACK bit + if (scl_posedge) begin + if (sda_i_reg) begin + // NACK, return to idle + state_reg <= STATE_IDLE; + end else begin + // ACK, read another byte + bit_count_reg <= 4'd7; + shift_reg <= data_reg; + state_reg <= STATE_READ_1; + end + end else begin + state_reg <= STATE_READ_3; end + end + default: begin + if (DEBUG) $display("default output of i2c_single_reg triggered atm this does nothing"); + end endcase - end + end - if (data_latch) begin + if (data_latch) begin data_reg <= data_in; - end + end + scl_i_filter_reg <= (scl_i_filter_reg << 1) | {3'b000, scl_i}; + sda_i_filter_reg <= (sda_i_filter_reg << 1) | {3'b000, sda_i}; - scl_i_filter_reg <= (scl_i_filter_reg << 1) | scl_i; - sda_i_filter_reg <= (sda_i_filter_reg << 1) | sda_i; - - if (scl_i_filter_reg == {FILTER_LEN{1'b1}}) begin + if (scl_i_filter_reg == {FILTER_LEN{1'b1}}) begin scl_i_reg <= 1'b1; - end else if (scl_i_filter_reg == {FILTER_LEN{1'b0}}) begin + end else if (scl_i_filter_reg == {FILTER_LEN{1'b0}}) begin scl_i_reg <= 1'b0; - end + end - if (sda_i_filter_reg == {FILTER_LEN{1'b1}}) begin + if (sda_i_filter_reg == {FILTER_LEN{1'b1}}) begin sda_i_reg <= 1'b1; - end else if (sda_i_filter_reg == {FILTER_LEN{1'b0}}) begin + end else if (sda_i_filter_reg == {FILTER_LEN{1'b0}}) begin sda_i_reg <= 1'b0; - end + end - last_scl_i_reg <= scl_i_reg; - last_sda_i_reg <= sda_i_reg; + last_scl_i_reg <= scl_i_reg; + last_sda_i_reg <= sda_i_reg; - if (rst) begin - state_reg <= STATE_IDLE; - sda_o_reg <= 1'b1; end -end - + end endmodule `resetall diff --git a/rtl/i2c_slave.v b/rtl/i2c_slave.v index 11b6a39..40db57f 100644 --- a/rtl/i2c_slave.v +++ b/rtl/i2c_slave.v @@ -31,52 +31,51 @@ THE SOFTWARE. */ module i2c_slave #( parameter FILTER_LEN = 4 -) -( - input wire clk, - input wire rst, +) ( + input wire clk, + input wire rst_n, /* * Host interface */ - input wire release_bus, + input wire release_bus, - input wire [7:0] s_axis_data_tdata, - input wire s_axis_data_tvalid, - output wire s_axis_data_tready, - input wire s_axis_data_tlast, + input wire [7:0] s_axis_data_tdata, + input wire s_axis_data_tvalid, + output wire s_axis_data_tready, + input wire s_axis_data_tlast, - output wire [7:0] m_axis_data_tdata, - output wire m_axis_data_tvalid, - input wire m_axis_data_tready, - output wire m_axis_data_tlast, + output wire [7:0] m_axis_data_tdata, + output wire m_axis_data_tvalid, + input wire m_axis_data_tready, + output wire m_axis_data_tlast, /* * I2C interface */ - input wire scl_i, - output wire scl_o, - output wire scl_t, - input wire sda_i, - output wire sda_o, - output wire sda_t, + input wire scl_i, + output wire scl_o, + output wire scl_t, + input wire sda_i, + output wire sda_o, + output wire sda_t, /* * Status */ - output wire busy, - output wire [6:0] bus_address, - output wire bus_addressed, - output wire bus_active, + output wire busy, + output wire [6:0] bus_address, + output wire bus_addressed, + output wire bus_active, /* * Configuration */ - input wire enable, - input wire [6:0] device_address, - input wire [6:0] device_address_mask + input wire enable, + input wire [6:0] device_address, + input wire [6:0] device_address_mask ); -/* + /* I2C @@ -168,76 +167,86 @@ I/O pin. This would prevent devices from stretching the clock period. */ -localparam [4:0] - STATE_IDLE = 4'd0, - STATE_ADDRESS = 4'd1, - STATE_ACK = 4'd2, - STATE_WRITE_1 = 4'd3, - STATE_WRITE_2 = 4'd4, - STATE_READ_1 = 4'd5, - STATE_READ_2 = 4'd6, - STATE_READ_3 = 4'd7; + localparam [4:0] + STATE_IDLE = 5'd0, + STATE_ADDRESS = 5'd1, + STATE_ACK = 5'd2, + STATE_WRITE_1 = 5'd3, + STATE_WRITE_2 = 5'd4, + STATE_READ_1 = 5'd5, + STATE_READ_2 = 5'd6, + STATE_READ_3 = 5'd7; + + reg [4:0] state_reg = STATE_IDLE, state_next = STATE_IDLE; -reg [4:0] state_reg = STATE_IDLE, state_next; + reg [6:0] addr_reg = 7'd0, addr_next = 7'd0; + reg [7:0] data_reg = 8'd0, data_next = 8'd0; + reg data_valid_reg = 1'b0, data_valid_next = 1'b0; + reg data_out_reg_valid_reg = 1'b0, data_out_reg_valid_next = 1'b0; + reg last_reg = 1'b0, last_next = 1'b0; -reg [6:0] addr_reg = 7'd0, addr_next; -reg [7:0] data_reg = 8'd0, data_next; -reg data_valid_reg = 1'b0, data_valid_next; -reg data_out_reg_valid_reg = 1'b0, data_out_reg_valid_next; -reg last_reg = 1'b0, last_next; + reg mode_read_reg = 1'b0, mode_read_next = 1'b0; -reg mode_read_reg = 1'b0, mode_read_next; + reg [3:0] bit_count_reg = 4'd0, bit_count_next = 4'd0; -reg [3:0] bit_count_reg = 4'd0, bit_count_next; + reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next = 1'b0; -reg s_axis_data_tready_reg = 1'b0, s_axis_data_tready_next; + reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next = 8'd0; + reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next = 1'b0; + reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next = 1'b0; -reg [7:0] m_axis_data_tdata_reg = 8'd0, m_axis_data_tdata_next; -reg m_axis_data_tvalid_reg = 1'b0, m_axis_data_tvalid_next; -reg m_axis_data_tlast_reg = 1'b0, m_axis_data_tlast_next; + reg [FILTER_LEN-1:0] scl_i_filter = {FILTER_LEN{1'b1}}, scl_i_filter_next = {FILTER_LEN{1'b1}}; + reg [FILTER_LEN-1:0] sda_i_filter = {FILTER_LEN{1'b1}}, sda_i_filter_next = {FILTER_LEN{1'b1}}; -reg [FILTER_LEN-1:0] scl_i_filter = {FILTER_LEN{1'b1}}; -reg [FILTER_LEN-1:0] sda_i_filter = {FILTER_LEN{1'b1}}; + reg scl_i_reg = 1'b1, scl_i_next = 1'b1; + reg sda_i_reg = 1'b1, sda_i_next = 1'b1; -reg scl_i_reg = 1'b1; -reg sda_i_reg = 1'b1; + reg scl_o_reg = 1'b1, scl_o_next = 1'b1; + reg sda_o_reg = 1'b1, sda_o_next = 1'b1; -reg scl_o_reg = 1'b1, scl_o_next; -reg sda_o_reg = 1'b1, sda_o_next; + reg last_scl_i_reg = 1'b1, last_scl_i_next = 1'b1; + reg last_sda_i_reg = 1'b1, last_sda_i_next = 1'b1; -reg last_scl_i_reg = 1'b1; -reg last_sda_i_reg = 1'b1; + reg busy_reg = 1'b0, busy_next = 1'b0; + reg bus_active_reg = 1'b0, bus_active_next = 1'b0; + reg bus_addressed_reg = 1'b0, bus_addressed_next = 1'b0; -reg busy_reg = 1'b0; -reg bus_active_reg = 1'b0; -reg bus_addressed_reg = 1'b0, bus_addressed_next; + // Signal declarations + reg scl_posedge; + reg scl_negedge; + reg sda_posedge; + reg sda_negedge; + reg start_bit; + reg stop_bit; -assign bus_address = addr_reg; + assign bus_address = addr_reg; -assign s_axis_data_tready = s_axis_data_tready_reg; + assign s_axis_data_tready = s_axis_data_tready_reg; -assign m_axis_data_tdata = m_axis_data_tdata_reg; -assign m_axis_data_tvalid = m_axis_data_tvalid_reg; -assign m_axis_data_tlast = m_axis_data_tlast_reg; + assign m_axis_data_tdata = m_axis_data_tdata_reg; + assign m_axis_data_tvalid = m_axis_data_tvalid_reg; + assign m_axis_data_tlast = m_axis_data_tlast_reg; -assign scl_o = scl_o_reg; -assign scl_t = scl_o_reg; -assign sda_o = sda_o_reg; -assign sda_t = sda_o_reg; + assign scl_o = scl_o_reg; + assign scl_t = scl_o_reg; + assign sda_o = sda_o_reg; + assign sda_t = sda_o_reg; -assign busy = busy_reg; -assign bus_active = bus_active_reg; -assign bus_addressed = bus_addressed_reg; + assign busy = busy_reg; + assign bus_active = bus_active_reg; + assign bus_addressed = bus_addressed_reg; -assign scl_posedge = scl_i_reg && !last_scl_i_reg; -assign scl_negedge = !scl_i_reg && last_scl_i_reg; -assign sda_posedge = sda_i_reg && !last_sda_i_reg; -assign sda_negedge = !sda_i_reg && last_sda_i_reg; + always @* begin + scl_posedge = scl_i_reg && !last_scl_i_reg; + scl_negedge = !scl_i_reg && last_scl_i_reg; + sda_posedge = sda_i_reg && !last_sda_i_reg; + sda_negedge = !sda_i_reg && last_sda_i_reg; -assign start_bit = sda_negedge && scl_i_reg; -assign stop_bit = sda_posedge && scl_i_reg; + start_bit = sda_negedge && scl_i_reg; + stop_bit = sda_posedge && scl_i_reg; + end -always @* begin + always @* begin state_next = STATE_IDLE; addr_next = addr_reg; @@ -262,242 +271,244 @@ always @* begin bus_addressed_next = bus_addressed_reg; if (start_bit) begin - // got start bit, latch out data, read address - data_valid_next = 1'b0; - data_out_reg_valid_next = 1'b0; - bit_count_next = 4'd7; - m_axis_data_tlast_next = 1'b1; - m_axis_data_tvalid_next = data_out_reg_valid_reg; - bus_addressed_next = 1'b0; - state_next = STATE_ADDRESS; + // got start bit, latch out data, read address + data_valid_next = 1'b0; + data_out_reg_valid_next = 1'b0; + bit_count_next = 4'd7; + m_axis_data_tlast_next = 1'b1; + m_axis_data_tvalid_next = data_out_reg_valid_reg; + bus_addressed_next = 1'b0; + state_next = STATE_ADDRESS; end else if (release_bus || stop_bit) begin - // got stop bit or release bus command, latch out data, return to idle - data_valid_next = 1'b0; - data_out_reg_valid_next = 1'b0; - m_axis_data_tlast_next = 1'b1; - m_axis_data_tvalid_next = data_out_reg_valid_reg; - bus_addressed_next = 1'b0; - state_next = STATE_IDLE; + // got stop bit or release bus command, latch out data, return to idle + data_valid_next = 1'b0; + data_out_reg_valid_next = 1'b0; + m_axis_data_tlast_next = 1'b1; + m_axis_data_tvalid_next = data_out_reg_valid_reg; + bus_addressed_next = 1'b0; + state_next = STATE_IDLE; end else begin - case (state_reg) - STATE_IDLE: begin - // line idle - data_valid_next = 1'b0; - data_out_reg_valid_next = 1'b0; - bus_addressed_next = 1'b0; + case (state_reg) + STATE_IDLE: begin + // line idle + data_valid_next = 1'b0; + data_out_reg_valid_next = 1'b0; + bus_addressed_next = 1'b0; + state_next = STATE_IDLE; + end + STATE_ADDRESS: begin + // read address + if (scl_posedge) begin + if (bit_count_reg > 0) begin + // shift in address + bit_count_next = bit_count_reg - 1; + data_next = {data_reg[6:0], sda_i_reg}; + state_next = STATE_ADDRESS; + end else begin + // check address + if (enable && (device_address & device_address_mask) == (data_reg[6:0] & device_address_mask)) begin + // it's a match, save read/write bit and send ACK + addr_next = data_reg[6:0]; + mode_read_next = sda_i_reg; + bus_addressed_next = 1'b1; + state_next = STATE_ACK; + end else begin + // no match, return to idle state_next = STATE_IDLE; + end end - STATE_ADDRESS: begin - // read address - if (scl_posedge) begin - if (bit_count_reg > 0) begin - // shift in address - bit_count_next = bit_count_reg-1; - data_next = {data_reg[6:0], sda_i_reg}; - state_next = STATE_ADDRESS; - end else begin - // check address - if (enable && (device_address & device_address_mask) == (data_reg[6:0] & device_address_mask)) begin - // it's a match, save read/write bit and send ACK - addr_next = data_reg[6:0]; - mode_read_next = sda_i_reg; - bus_addressed_next = 1'b1; - state_next = STATE_ACK; - end else begin - // no match, return to idle - state_next = STATE_IDLE; - end - end - end else begin - state_next = STATE_ADDRESS; - end - end - STATE_ACK: begin - // send ACK bit - if (scl_negedge) begin - sda_o_next = 1'b0; - bit_count_next = 4'd7; - if (mode_read_reg) begin - // reading - s_axis_data_tready_next = 1'b1; - data_valid_next = 1'b0; - state_next = STATE_READ_1; - end else begin - // writing - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_ACK; - end + end else begin + state_next = STATE_ADDRESS; + end + end + STATE_ACK: begin + // send ACK bit + if (scl_negedge) begin + sda_o_next = 1'b0; + bit_count_next = 4'd7; + if (mode_read_reg) begin + // reading + s_axis_data_tready_next = 1'b1; + data_valid_next = 1'b0; + state_next = STATE_READ_1; + end else begin + // writing + state_next = STATE_WRITE_1; end - STATE_WRITE_1: begin - // write data byte - if (scl_negedge || !scl_o_reg) begin - sda_o_next = 1'b1; - if (m_axis_data_tvalid && !m_axis_data_tready) begin - // data waiting in output register, so stretch clock - scl_o_next = 1'b0; - state_next = STATE_WRITE_1; - end else begin - scl_o_next = 1'b1; - if (data_valid_reg) begin - // store data in output register - m_axis_data_tdata_next = data_reg; - m_axis_data_tlast_next = 1'b0; - end - data_valid_next = 1'b0; - data_out_reg_valid_next = data_valid_reg; - state_next = STATE_WRITE_2; - end - end else begin - state_next = STATE_WRITE_1; - end + end else begin + state_next = STATE_ACK; + end + end + STATE_WRITE_1: begin + // write data byte + if (scl_negedge || !scl_o_reg) begin + sda_o_next = 1'b1; + if (m_axis_data_tvalid && !m_axis_data_tready) begin + // data waiting in output register, so stretch clock + scl_o_next = 1'b0; + state_next = STATE_WRITE_1; + end else begin + scl_o_next = 1'b1; + if (data_valid_reg) begin + // store data in output register + m_axis_data_tdata_next = data_reg; + m_axis_data_tlast_next = 1'b0; + end + data_valid_next = 1'b0; + data_out_reg_valid_next = data_valid_reg; + state_next = STATE_WRITE_2; end - STATE_WRITE_2: begin - // write data byte - if (scl_posedge) begin - // shift in data bit - data_next = {data_reg[6:0], sda_i_reg}; - if (bit_count_reg > 0) begin - bit_count_next = bit_count_reg-1; - state_next = STATE_WRITE_2; - end else begin - // latch out previous data byte since we now know it's not the last one - m_axis_data_tvalid_next = data_out_reg_valid_reg; - data_out_reg_valid_next = 1'b0; - data_valid_next = 1'b1; - state_next = STATE_ACK; - end - end else begin - state_next = STATE_WRITE_2; - end + end else begin + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_2: begin + // write data byte + if (scl_posedge) begin + // shift in data bit + data_next = {data_reg[6:0], sda_i_reg}; + if (bit_count_reg > 0) begin + bit_count_next = bit_count_reg - 1; + state_next = STATE_WRITE_2; + end else begin + // latch out previous data byte since we now know it's not the last one + m_axis_data_tvalid_next = data_out_reg_valid_reg; + data_out_reg_valid_next = 1'b0; + data_valid_next = 1'b1; + state_next = STATE_ACK; end - STATE_READ_1: begin - // read data byte - if (s_axis_data_tready && s_axis_data_tvalid) begin - // data valid; latch it in - s_axis_data_tready_next = 1'b0; - data_next = s_axis_data_tdata; - data_valid_next = 1'b1; - end else begin - // keep ready high if we're waiting for data - s_axis_data_tready_next = !data_valid_reg; - end - - if (scl_negedge || !scl_o_reg) begin - // shift out data bit - if (!data_valid_reg) begin - // waiting for data, so stretch clock - scl_o_next = 1'b0; - state_next = STATE_READ_1; - end else begin - scl_o_next = 1'b1; - {sda_o_next, data_next} = {data_reg, 1'b0}; - - if (bit_count_reg > 0) begin - bit_count_next = bit_count_reg-1; - state_next = STATE_READ_1; - end else begin - state_next = STATE_READ_2; - end - end - end else begin - state_next = STATE_READ_1; - end + end else begin + state_next = STATE_WRITE_2; + end + end + STATE_READ_1: begin + // read data byte + if (s_axis_data_tready && s_axis_data_tvalid) begin + // data valid; latch it in + s_axis_data_tready_next = 1'b0; + data_next = s_axis_data_tdata; + data_valid_next = 1'b1; + end else begin + // keep ready high if we're waiting for data + s_axis_data_tready_next = !data_valid_reg; + end + + if (scl_negedge || !scl_o_reg) begin + // shift out data bit + if (!data_valid_reg) begin + // waiting for data, so stretch clock + scl_o_next = 1'b0; + state_next = STATE_READ_1; + end else begin + scl_o_next = 1'b1; + {sda_o_next, data_next} = {data_reg, 1'b0}; + + if (bit_count_reg > 0) begin + bit_count_next = bit_count_reg - 1; + state_next = STATE_READ_1; + end else begin + state_next = STATE_READ_2; + end end - STATE_READ_2: begin - // read ACK bit - if (scl_negedge) begin - // release SDA - sda_o_next = 1'b1; - state_next = STATE_READ_3; - end else begin - state_next = STATE_READ_2; - end + end else begin + state_next = STATE_READ_1; + end + end + STATE_READ_2: begin + // read ACK bit + if (scl_negedge) begin + // release SDA + sda_o_next = 1'b1; + state_next = STATE_READ_3; + end else begin + state_next = STATE_READ_2; + end + end + STATE_READ_3: begin + // read ACK bit + if (scl_posedge) begin + if (sda_i_reg) begin + // NACK, return to idle + state_next = STATE_IDLE; + end else begin + // ACK, read another byte + bit_count_next = 4'd7; + s_axis_data_tready_next = 1'b1; + data_valid_next = 1'b0; + state_next = STATE_READ_1; end - STATE_READ_3: begin - // read ACK bit - if (scl_posedge) begin - if (sda_i_reg) begin - // NACK, return to idle - state_next = STATE_IDLE; - end else begin - // ACK, read another byte - bit_count_next = 4'd7; - s_axis_data_tready_next = 1'b1; - data_valid_next = 1'b0; - state_next = STATE_READ_1; - end - end else begin - state_next = STATE_READ_3; - end - end - endcase + end else begin + state_next = STATE_READ_3; + end + end + default: $display("default of slave triggered, do nothing"); + endcase end -end + end + + always @(posedge clk or negedge rst_n) begin + if (~rst_n) begin + state_reg <= STATE_IDLE; + s_axis_data_tready_reg <= 1'b0; + m_axis_data_tvalid_reg <= 1'b0; + scl_o_reg <= 1'b1; + sda_o_reg <= 1'b1; + busy_reg <= 1'b0; + bus_active_reg <= 1'b0; + bus_addressed_reg <= 1'b0; + end else begin -always @(posedge clk) begin - state_reg <= state_next; + state_reg <= state_next; - addr_reg <= addr_next; - data_reg <= data_next; - data_valid_reg <= data_valid_next; - data_out_reg_valid_reg <= data_out_reg_valid_next; - last_reg <= last_next; + addr_reg <= addr_next; + data_reg <= data_next; + data_valid_reg <= data_valid_next; + data_out_reg_valid_reg <= data_out_reg_valid_next; + last_reg <= last_next; - mode_read_reg <= mode_read_next; + mode_read_reg <= mode_read_next; - bit_count_reg <= bit_count_next; + bit_count_reg <= bit_count_next; - s_axis_data_tready_reg <= s_axis_data_tready_next; + s_axis_data_tready_reg <= s_axis_data_tready_next; - m_axis_data_tdata_reg <= m_axis_data_tdata_next; - m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; - m_axis_data_tlast_reg <= m_axis_data_tlast_next; + m_axis_data_tdata_reg <= m_axis_data_tdata_next; + m_axis_data_tvalid_reg <= m_axis_data_tvalid_next; + m_axis_data_tlast_reg <= m_axis_data_tlast_next; - scl_i_filter <= (scl_i_filter << 1) | scl_i; - sda_i_filter <= (sda_i_filter << 1) | sda_i; + scl_i_filter <= (scl_i_filter << 1) | {3'b000, scl_i}; + sda_i_filter <= (sda_i_filter << 1) | {3'b000, sda_i}; - if (scl_i_filter == {FILTER_LEN{1'b1}}) begin + if (scl_i_filter == {FILTER_LEN{1'b1}}) begin scl_i_reg <= 1'b1; - end else if (scl_i_filter == {FILTER_LEN{1'b0}}) begin + end else if (scl_i_filter == {FILTER_LEN{1'b0}}) begin scl_i_reg <= 1'b0; - end + end - if (sda_i_filter == {FILTER_LEN{1'b1}}) begin + if (sda_i_filter == {FILTER_LEN{1'b1}}) begin sda_i_reg <= 1'b1; - end else if (sda_i_filter == {FILTER_LEN{1'b0}}) begin + end else if (sda_i_filter == {FILTER_LEN{1'b0}}) begin sda_i_reg <= 1'b0; - end + end - scl_o_reg <= scl_o_next; - sda_o_reg <= sda_o_next; + scl_o_reg <= scl_o_next; + sda_o_reg <= sda_o_next; - last_scl_i_reg <= scl_i_reg; - last_sda_i_reg <= sda_i_reg; + last_scl_i_reg <= scl_i_reg; + last_sda_i_reg <= sda_i_reg; - busy_reg <= !(state_reg == STATE_IDLE); + busy_reg <= !(state_reg == STATE_IDLE); - if (start_bit) begin + if (start_bit) begin bus_active_reg <= 1'b1; - end else if (stop_bit) begin + end else if (stop_bit) begin bus_active_reg <= 1'b0; - end else begin + end else begin bus_active_reg <= bus_active_reg; - end + end - bus_addressed_reg <= bus_addressed_next; + bus_addressed_reg <= bus_addressed_next; - if (rst) begin - state_reg <= STATE_IDLE; - s_axis_data_tready_reg <= 1'b0; - m_axis_data_tvalid_reg <= 1'b0; - scl_o_reg <= 1'b1; - sda_o_reg <= 1'b1; - busy_reg <= 1'b0; - bus_active_reg <= 1'b0; - bus_addressed_reg <= 1'b0; end -end - + end endmodule diff --git a/rtl/i2c_slave_axil_master.v b/rtl/i2c_slave_axil_master.v index 2668642..083a9e3 100644 --- a/rtl/i2c_slave_axil_master.v +++ b/rtl/i2c_slave_axil_master.v @@ -29,64 +29,62 @@ THE SOFTWARE. /* * I2C slave AXI lite master wrapper */ -module i2c_slave_axil_master # -( +module i2c_slave_axil_master #( parameter FILTER_LEN = 4, parameter DATA_WIDTH = 32, // width of data bus in bits parameter ADDR_WIDTH = 16, // width of address bus in bits - parameter STRB_WIDTH = (DATA_WIDTH/8) -) -( - input wire clk, - input wire rst, + parameter STRB_WIDTH = (DATA_WIDTH / 8) +) ( + input wire clk, + input wire rst, /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t, + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t, /* * AXI lite master interface */ - output wire [ADDR_WIDTH-1:0] m_axil_awaddr, - output wire [2:0] m_axil_awprot, - output wire m_axil_awvalid, - input wire m_axil_awready, - output wire [DATA_WIDTH-1:0] m_axil_wdata, - output wire [STRB_WIDTH-1:0] m_axil_wstrb, - output wire m_axil_wvalid, - input wire m_axil_wready, - input wire [1:0] m_axil_bresp, - input wire m_axil_bvalid, - output wire m_axil_bready, - output wire [ADDR_WIDTH-1:0] m_axil_araddr, - output wire [2:0] m_axil_arprot, - output wire m_axil_arvalid, - input wire m_axil_arready, - input wire [DATA_WIDTH-1:0] m_axil_rdata, - input wire [1:0] m_axil_rresp, - input wire m_axil_rvalid, - output wire m_axil_rready, + output wire [ADDR_WIDTH-1:0] m_axil_awaddr, + output wire [ 2:0] m_axil_awprot, + output wire m_axil_awvalid, + input wire m_axil_awready, + output wire [DATA_WIDTH-1:0] m_axil_wdata, + output wire [STRB_WIDTH-1:0] m_axil_wstrb, + output wire m_axil_wvalid, + input wire m_axil_wready, + input wire [ 1:0] m_axil_bresp, + input wire m_axil_bvalid, + output wire m_axil_bready, + output wire [ADDR_WIDTH-1:0] m_axil_araddr, + output wire [ 2:0] m_axil_arprot, + output wire m_axil_arvalid, + input wire m_axil_arready, + input wire [DATA_WIDTH-1:0] m_axil_rdata, + input wire [ 1:0] m_axil_rresp, + input wire m_axil_rvalid, + output wire m_axil_rready, /* * Status */ - output wire busy, - output wire bus_addressed, - output wire bus_active, + output wire busy, + output wire bus_addressed, + output wire bus_active, /* * Configuration */ - input wire enable, - input wire [6:0] device_address + input wire enable, + input wire [6:0] device_address ); -/* + /* I2C @@ -195,38 +193,38 @@ I/O pin. This would prevent devices from stretching the clock period. */ -// for interfaces that are more than one word wide, disable address lines -parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); -// width of data port in words -parameter WORD_WIDTH = STRB_WIDTH; -// size of words -parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH; + // for interfaces that are more than one word wide, disable address lines + parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); + // width of data port in words + parameter WORD_WIDTH = STRB_WIDTH; + // size of words + parameter WORD_SIZE = DATA_WIDTH / WORD_WIDTH; -parameter WORD_PART_ADDR_WIDTH = $clog2(WORD_SIZE/8); + parameter WORD_PART_ADDR_WIDTH = $clog2(WORD_SIZE / 8); -parameter ADDR_WIDTH_ADJ = ADDR_WIDTH+WORD_PART_ADDR_WIDTH; + parameter ADDR_WIDTH_ADJ = ADDR_WIDTH + WORD_PART_ADDR_WIDTH; -parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ+7)/8; + parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ + 7) / 8; -// bus width assertions -initial begin + // bus width assertions + initial begin if (WORD_WIDTH * WORD_SIZE != DATA_WIDTH) begin - $error("Error: AXI data width not evenly divisble"); - $finish; + $error("Error: AXI data width not evenly divisble"); + $finish; end - if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin - $error("Error: AXI word width must be even power of two"); - $finish; + if (2 ** $clog2(WORD_WIDTH) != WORD_WIDTH) begin + $error("Error: AXI word width must be even power of two"); + $finish; end - if (8*2**$clog2(WORD_SIZE/8) != WORD_SIZE) begin - $error("Error: AXI word size must be a power of two multiple of 8 bits"); - $finish; + if (8 * 2 ** $clog2(WORD_SIZE / 8) != WORD_SIZE) begin + $error("Error: AXI word size must be a power of two multiple of 8 bits"); + $finish; end -end + end -localparam [2:0] + localparam [2:0] STATE_IDLE = 3'd0, STATE_ADDRESS = 3'd1, STATE_READ_1 = 3'd2, @@ -234,47 +232,53 @@ localparam [2:0] STATE_WRITE_1 = 3'd4, STATE_WRITE_2 = 3'd5; -reg [2:0] state_reg = STATE_IDLE, state_next; - -reg [7:0] count_reg = 8'd0, count_next; -reg last_cycle_reg = 1'b0; - -reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; -reg [DATA_WIDTH-1:0] data_reg = {DATA_WIDTH{1'b0}}, data_next; - -reg m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next; -reg [STRB_WIDTH-1:0] m_axil_wstrb_reg = {STRB_WIDTH{1'b0}}, m_axil_wstrb_next; -reg m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next; -reg m_axil_bready_reg = 1'b0, m_axil_bready_next; -reg m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next; -reg m_axil_rready_reg = 1'b0, m_axil_rready_next; - -reg busy_reg = 1'b0; - -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; - -wire [7:0] data_out; -wire data_out_valid; -wire data_out_last; -reg data_out_ready_reg = 1'b0, data_out_ready_next; - -assign m_axil_awaddr = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], {ADDR_WIDTH-VALID_ADDR_WIDTH{1'b0}}}; -assign m_axil_awprot = 3'b010; -assign m_axil_awvalid = m_axil_awvalid_reg; -assign m_axil_wdata = data_reg; -assign m_axil_wstrb = m_axil_wstrb_reg; -assign m_axil_wvalid = m_axil_wvalid_reg; -assign m_axil_bready = m_axil_bready_reg; -assign m_axil_araddr = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], {ADDR_WIDTH-VALID_ADDR_WIDTH{1'b0}}}; -assign m_axil_arprot = 3'b010; -assign m_axil_arvalid = m_axil_arvalid_reg; -assign m_axil_rready = m_axil_rready_reg; - -assign busy = busy_reg; - -always @* begin + reg [2:0] state_reg = STATE_IDLE, state_next; + + reg [7:0] count_reg = 8'd0, count_next; + reg last_cycle_reg = 1'b0; + + reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; + reg [DATA_WIDTH-1:0] data_reg = {DATA_WIDTH{1'b0}}, data_next; + + reg m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next; + reg [STRB_WIDTH-1:0] m_axil_wstrb_reg = {STRB_WIDTH{1'b0}}, m_axil_wstrb_next; + reg m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next; + reg m_axil_bready_reg = 1'b0, m_axil_bready_next; + reg m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next; + reg m_axil_rready_reg = 1'b0, m_axil_rready_next; + + reg busy_reg = 1'b0; + + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; + + wire [7:0] data_out; + wire data_out_valid; + wire data_out_last; + reg data_out_ready_reg = 1'b0, data_out_ready_next; + + assign m_axil_awaddr = { + addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], + {ADDR_WIDTH - VALID_ADDR_WIDTH{1'b0}} + }; + assign m_axil_awprot = 3'b010; + assign m_axil_awvalid = m_axil_awvalid_reg; + assign m_axil_wdata = data_reg; + assign m_axil_wstrb = m_axil_wstrb_reg; + assign m_axil_wvalid = m_axil_wvalid_reg; + assign m_axil_bready = m_axil_bready_reg; + assign m_axil_araddr = { + addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH], + {ADDR_WIDTH - VALID_ADDR_WIDTH{1'b0}} + }; + assign m_axil_arprot = 3'b010; + assign m_axil_arvalid = m_axil_arvalid_reg; + assign m_axil_rready = m_axil_rready_reg; + + assign busy = busy_reg; + + always @* begin state_next = STATE_IDLE; count_next = count_reg; @@ -295,145 +299,145 @@ always @* begin m_axil_rready_next = 1'b0; case (state_reg) - STATE_IDLE: begin - // idle, wait for I2C interface - - if (data_out_valid) begin - // store address and write - count_next = ADDR_WORD_WIDTH-1; - state_next = STATE_ADDRESS; - end else if (data_in_ready && !data_in_valid_reg) begin - // read - m_axil_arvalid_next = 1'b1; - m_axil_rready_next = 1'b1; - state_next = STATE_READ_1; - end + STATE_IDLE: begin + // idle, wait for I2C interface + + if (data_out_valid) begin + // store address and write + count_next = ADDR_WORD_WIDTH - 1; + state_next = STATE_ADDRESS; + end else if (data_in_ready && !data_in_valid_reg) begin + // read + m_axil_arvalid_next = 1'b1; + m_axil_rready_next = 1'b1; + state_next = STATE_READ_1; end - STATE_ADDRESS: begin - // store address - data_out_ready_next = 1'b1; - - if (data_out_ready_reg && data_out_valid) begin - // store pointers - addr_next[8*count_reg +: 8] = data_out; - count_next = count_reg - 1; - if (count_reg == 0) begin - // end of header - // set initial word offset - if (ADDR_WIDTH == VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin - count_next = 0; - end else begin - count_next = addr_next[ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH-1:0]; - end - m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; - data_next = {DATA_WIDTH{1'b0}}; - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - // start writing - state_next = STATE_WRITE_1; - end - end else begin - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_ADDRESS; - end - end + end + STATE_ADDRESS: begin + // store address + data_out_ready_next = 1'b1; + + if (data_out_ready_reg && data_out_valid) begin + // store pointers + addr_next[8*count_reg+:8] = data_out; + count_next = count_reg - 1; + if (count_reg == 0) begin + // end of header + // set initial word offset + if (ADDR_WIDTH == VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin + count_next = 0; end else begin - state_next = STATE_ADDRESS; + count_next = addr_next[ADDR_WIDTH_ADJ-VALID_ADDR_WIDTH-1:0]; end - end - STATE_READ_1: begin - // wait for data - m_axil_rready_next = 1'b1; - - if (m_axil_rready && m_axil_rvalid) begin - // read cycle complete, store result - m_axil_rready_next = 1'b0; - data_next = m_axil_rdata; - addr_next = addr_reg + (1 << (ADDR_WIDTH-VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - state_next = STATE_READ_2; + m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; + data_next = {DATA_WIDTH{1'b0}}; + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_1; + // start writing + state_next = STATE_WRITE_1; end - end - STATE_READ_2: begin - // send data - if (data_out_valid || !bus_addressed) begin - // no longer addressed or now addressed for write, return to idle - state_next = STATE_IDLE; - end else if (data_in_ready && !data_in_valid_reg) begin - // transfer word and update pointers - data_in_next = data_reg[8*count_reg +: 8]; - data_in_valid_next = 1'b1; - count_next = count_reg + 1; - if (count_reg == (STRB_WIDTH*WORD_SIZE/8)-1) begin - // end of stored data word; return to idle - count_next = 0; - state_next = STATE_IDLE; - end else begin - state_next = STATE_READ_2; - end + end else begin + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_2; + state_next = STATE_ADDRESS; end + end + end else begin + state_next = STATE_ADDRESS; end - STATE_WRITE_1: begin - // write data - data_out_ready_next = 1'b1; - - if (data_out_ready_reg && data_out_valid) begin - // store word - data_next[8*count_reg +: 8] = data_out; - count_next = count_reg + 1; - m_axil_wstrb_next[count_reg >> ((WORD_SIZE/8)-1)] = 1'b1; - if (count_reg == (STRB_WIDTH*WORD_SIZE/8)-1 || data_out_last) begin - // have full word or at end of block, start write operation - count_next = 0; - m_axil_awvalid_next = 1'b1; - m_axil_wvalid_next = 1'b1; - m_axil_bready_next = 1'b1; - state_next = STATE_WRITE_2; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_1; - end + end + STATE_READ_1: begin + // wait for data + m_axil_rready_next = 1'b1; + + if (m_axil_rready && m_axil_rvalid) begin + // read cycle complete, store result + m_axil_rready_next = 1'b0; + data_next = m_axil_rdata; + addr_next = addr_reg + (1 << (ADDR_WIDTH - VALID_ADDR_WIDTH + WORD_PART_ADDR_WIDTH)); + state_next = STATE_READ_2; + end else begin + state_next = STATE_READ_1; + end + end + STATE_READ_2: begin + // send data + if (data_out_valid || !bus_addressed) begin + // no longer addressed or now addressed for write, return to idle + state_next = STATE_IDLE; + end else if (data_in_ready && !data_in_valid_reg) begin + // transfer word and update pointers + data_in_next = data_reg[8*count_reg+:8]; + data_in_valid_next = 1'b1; + count_next = count_reg + 1; + if (count_reg == (STRB_WIDTH * WORD_SIZE / 8) - 1) begin + // end of stored data word; return to idle + count_next = 0; + state_next = STATE_IDLE; + end else begin + state_next = STATE_READ_2; + end + end else begin + state_next = STATE_READ_2; end - STATE_WRITE_2: begin - // wait for write completion + end + STATE_WRITE_1: begin + // write data + data_out_ready_next = 1'b1; + + if (data_out_ready_reg && data_out_valid) begin + // store word + data_next[8*count_reg+:8] = data_out; + count_next = count_reg + 1; + m_axil_wstrb_next[count_reg>>((WORD_SIZE/8)-1)] = 1'b1; + if (count_reg == (STRB_WIDTH * WORD_SIZE / 8) - 1 || data_out_last) begin + // have full word or at end of block, start write operation + count_next = 0; + m_axil_awvalid_next = 1'b1; + m_axil_wvalid_next = 1'b1; m_axil_bready_next = 1'b1; - - if (m_axil_bready && m_axil_bvalid) begin - // end of write operation - data_next = {DATA_WIDTH{1'b0}}; - addr_next = addr_reg + (1 << (ADDR_WIDTH-VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - m_axil_bready_next = 1'b0; - m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; - if (last_cycle_reg) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_2; - end + state_next = STATE_WRITE_2; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_1; end + end + STATE_WRITE_2: begin + // wait for write completion + m_axil_bready_next = 1'b1; + + if (m_axil_bready && m_axil_bvalid) begin + // end of write operation + data_next = {DATA_WIDTH{1'b0}}; + addr_next = addr_reg + (1 << (ADDR_WIDTH - VALID_ADDR_WIDTH + WORD_PART_ADDR_WIDTH)); + m_axil_bready_next = 1'b0; + m_axil_wstrb_next = {STRB_WIDTH{1'b0}}; + if (last_cycle_reg) begin + // end of transaction + state_next = STATE_IDLE; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_2; + end + end endcase -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; count_reg <= count_next; if (data_out_ready_reg & data_out_valid) begin - last_cycle_reg <= data_out_last; + last_cycle_reg <= data_out_last; end addr_reg <= addr_next; @@ -454,56 +458,55 @@ always @(posedge clk) begin data_out_ready_reg <= data_out_ready_next; if (rst) begin - state_reg <= STATE_IDLE; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - m_axil_awvalid_reg <= 1'b0; - m_axil_wvalid_reg <= 1'b0; - m_axil_bready_reg <= 1'b0; - m_axil_arvalid_reg <= 1'b0; - m_axil_rready_reg <= 1'b0; - busy_reg <= 1'b0; + state_reg <= STATE_IDLE; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + m_axil_awvalid_reg <= 1'b0; + m_axil_wvalid_reg <= 1'b0; + m_axil_bready_reg <= 1'b0; + m_axil_arvalid_reg <= 1'b0; + m_axil_rready_reg <= 1'b0; + busy_reg <= 1'b0; end -end - -i2c_slave #( - .FILTER_LEN(FILTER_LEN) -) -i2c_slave_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .release_bus(1'b0), - - .s_axis_data_tdata(data_in_reg), - .s_axis_data_tvalid(data_in_valid_reg), - .s_axis_data_tready(data_in_ready), - .s_axis_data_tlast(1'b0), - - .m_axis_data_tdata(data_out), - .m_axis_data_tvalid(data_out_valid), - .m_axis_data_tready(data_out_ready_reg), - .m_axis_data_tlast(data_out_last), - - // I2C Interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(), - .bus_address(), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - - // Configuration - .enable(enable), - .device_address(device_address), - .device_address_mask(7'h7f) -); + end + + i2c_slave #( + .FILTER_LEN(FILTER_LEN) + ) i2c_slave_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .release_bus(1'b0), + + .s_axis_data_tdata (data_in_reg), + .s_axis_data_tvalid(data_in_valid_reg), + .s_axis_data_tready(data_in_ready), + .s_axis_data_tlast (1'b0), + + .m_axis_data_tdata (data_out), + .m_axis_data_tvalid(data_out_valid), + .m_axis_data_tready(data_out_ready_reg), + .m_axis_data_tlast (data_out_last), + + // I2C Interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(), + .bus_address(), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + + // Configuration + .enable(enable), + .device_address(device_address), + .device_address_mask(7'h7f) + ); endmodule diff --git a/rtl/i2c_slave_wbm.v b/rtl/i2c_slave_wbm.v index b586365..445054c 100644 --- a/rtl/i2c_slave_wbm.v +++ b/rtl/i2c_slave_wbm.v @@ -29,54 +29,52 @@ THE SOFTWARE. /* * I2C slave wishbone master wrapper */ -module i2c_slave_wbm # -( - parameter FILTER_LEN = 4, - parameter WB_DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64) - parameter WB_ADDR_WIDTH = 32, // width of address bus in bits - parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH/8) // width of word select bus (1, 2, 4, or 8) -) -( - input wire clk, - input wire rst, +module i2c_slave_wbm #( + parameter FILTER_LEN = 4, + parameter WB_DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64) + parameter WB_ADDR_WIDTH = 32, // width of address bus in bits + parameter WB_SELECT_WIDTH = (WB_DATA_WIDTH / 8) // width of word select bus (1, 2, 4, or 8) +) ( + input wire clk, + input wire rst, /* * I2C interface */ - input wire i2c_scl_i, - output wire i2c_scl_o, - output wire i2c_scl_t, - input wire i2c_sda_i, - output wire i2c_sda_o, - output wire i2c_sda_t, + input wire i2c_scl_i, + output wire i2c_scl_o, + output wire i2c_scl_t, + input wire i2c_sda_i, + output wire i2c_sda_o, + output wire i2c_sda_t, /* * Wishbone interface */ - output wire [WB_ADDR_WIDTH-1:0] wb_adr_o, // ADR_O() address - input wire [WB_DATA_WIDTH-1:0] wb_dat_i, // DAT_I() data in - output wire [WB_DATA_WIDTH-1:0] wb_dat_o, // DAT_O() data out - output wire wb_we_o, // WE_O write enable output - output wire [WB_SELECT_WIDTH-1:0] wb_sel_o, // SEL_O() select output - output wire wb_stb_o, // STB_O strobe output - input wire wb_ack_i, // ACK_I acknowledge input - input wire wb_err_i, // ERR_I error input - output wire wb_cyc_o, // CYC_O cycle output + output wire [ WB_ADDR_WIDTH-1:0] wb_adr_o, // ADR_O() address + input wire [ WB_DATA_WIDTH-1:0] wb_dat_i, // DAT_I() data in + output wire [ WB_DATA_WIDTH-1:0] wb_dat_o, // DAT_O() data out + output wire wb_we_o, // WE_O write enable output + output wire [WB_SELECT_WIDTH-1:0] wb_sel_o, // SEL_O() select output + output wire wb_stb_o, // STB_O strobe output + input wire wb_ack_i, // ACK_I acknowledge input + input wire wb_err_i, // ERR_I error input + output wire wb_cyc_o, // CYC_O cycle output /* * Status */ - output wire busy, - output wire bus_addressed, - output wire bus_active, + output wire busy, + output wire bus_addressed, + output wire bus_active, /* * Configuration */ - input wire enable, - input wire [6:0] device_address + input wire enable, + input wire [6:0] device_address ); -/* + /* I2C @@ -185,38 +183,38 @@ I/O pin. This would prevent devices from stretching the clock period. */ -// for interfaces that are more than one word wide, disable address lines -parameter WB_VALID_ADDR_WIDTH = WB_ADDR_WIDTH - $clog2(WB_SELECT_WIDTH); -// width of data port in words (1, 2, 4, or 8) -parameter WB_WORD_WIDTH = WB_SELECT_WIDTH; -// size of words (8, 16, 32, or 64 bits) -parameter WB_WORD_SIZE = WB_DATA_WIDTH/WB_WORD_WIDTH; + // for interfaces that are more than one word wide, disable address lines + parameter WB_VALID_ADDR_WIDTH = WB_ADDR_WIDTH - $clog2(WB_SELECT_WIDTH); + // width of data port in words (1, 2, 4, or 8) + parameter WB_WORD_WIDTH = WB_SELECT_WIDTH; + // size of words (8, 16, 32, or 64 bits) + parameter WB_WORD_SIZE = WB_DATA_WIDTH / WB_WORD_WIDTH; -parameter WORD_PART_ADDR_WIDTH = $clog2(WB_WORD_SIZE/8); + parameter WORD_PART_ADDR_WIDTH = $clog2(WB_WORD_SIZE / 8); -parameter ADDR_WIDTH_ADJ = WB_ADDR_WIDTH+WORD_PART_ADDR_WIDTH; + parameter ADDR_WIDTH_ADJ = WB_ADDR_WIDTH + WORD_PART_ADDR_WIDTH; -parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ+7)/8; + parameter ADDR_WORD_WIDTH = (ADDR_WIDTH_ADJ + 7) / 8; -// bus width assertions -initial begin + // bus width assertions + initial begin if (WB_WORD_WIDTH * WB_WORD_SIZE != WB_DATA_WIDTH) begin - $error("Error: WB data width not evenly divisble"); - $finish; + $error("Error: WB data width not evenly divisble"); + $finish; end - if (2**$clog2(WB_WORD_WIDTH) != WB_WORD_WIDTH) begin - $error("Error: WB word width must be even power of two"); - $finish; + if (2 ** $clog2(WB_WORD_WIDTH) != WB_WORD_WIDTH) begin + $error("Error: WB word width must be even power of two"); + $finish; end - if (8*2**$clog2(WB_WORD_SIZE/8) != WB_WORD_SIZE) begin - $error("Error: WB word size must be a power of two multiple of 8 bits"); - $finish; + if (8 * 2 ** $clog2(WB_WORD_SIZE / 8) != WB_WORD_SIZE) begin + $error("Error: WB word size must be a power of two multiple of 8 bits"); + $finish; end -end + end -localparam [2:0] + localparam [2:0] STATE_IDLE = 3'd0, STATE_ADDRESS = 3'd1, STATE_READ_1 = 3'd2, @@ -224,40 +222,43 @@ localparam [2:0] STATE_WRITE_1 = 3'd4, STATE_WRITE_2 = 3'd5; -reg [2:0] state_reg = STATE_IDLE, state_next; + reg [2:0] state_reg = STATE_IDLE, state_next; -reg [7:0] count_reg = 8'd0, count_next; -reg last_cycle_reg = 1'b0; + reg [7:0] count_reg = 8'd0, count_next; + reg last_cycle_reg = 1'b0; -reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; -reg [WB_DATA_WIDTH-1:0] data_reg = {WB_DATA_WIDTH{1'b0}}, data_next; + reg [ADDR_WIDTH_ADJ-1:0] addr_reg = {ADDR_WIDTH_ADJ{1'b0}}, addr_next; + reg [WB_DATA_WIDTH-1:0] data_reg = {WB_DATA_WIDTH{1'b0}}, data_next; -reg wb_we_o_reg = 1'b0, wb_we_o_next; -reg [WB_SELECT_WIDTH-1:0] wb_sel_o_reg = {WB_SELECT_WIDTH{1'b0}}, wb_sel_o_next; -reg wb_stb_o_reg = 1'b0, wb_stb_o_next; -reg wb_cyc_o_reg = 1'b0, wb_cyc_o_next; + reg wb_we_o_reg = 1'b0, wb_we_o_next; + reg [WB_SELECT_WIDTH-1:0] wb_sel_o_reg = {WB_SELECT_WIDTH{1'b0}}, wb_sel_o_next; + reg wb_stb_o_reg = 1'b0, wb_stb_o_next; + reg wb_cyc_o_reg = 1'b0, wb_cyc_o_next; -reg busy_reg = 1'b0; + reg busy_reg = 1'b0; -reg [7:0] data_in_reg = 8'd0, data_in_next; -reg data_in_valid_reg = 1'b0, data_in_valid_next; -wire data_in_ready; + reg [7:0] data_in_reg = 8'd0, data_in_next; + reg data_in_valid_reg = 1'b0, data_in_valid_next; + wire data_in_ready; -wire [7:0] data_out; -wire data_out_valid; -wire data_out_last; -reg data_out_ready_reg = 1'b0, data_out_ready_next; + wire [7:0] data_out; + wire data_out_valid; + wire data_out_last; + reg data_out_ready_reg = 1'b0, data_out_ready_next; -assign wb_adr_o = {addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH], {WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH{1'b0}}}; -assign wb_dat_o = data_reg; -assign wb_we_o = wb_we_o_reg; -assign wb_sel_o = wb_sel_o_reg; -assign wb_stb_o = wb_stb_o_reg; -assign wb_cyc_o = wb_cyc_o_reg; + assign wb_adr_o = { + addr_reg[ADDR_WIDTH_ADJ-1:ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH], + {WB_ADDR_WIDTH - WB_VALID_ADDR_WIDTH{1'b0}} + }; + assign wb_dat_o = data_reg; + assign wb_we_o = wb_we_o_reg; + assign wb_sel_o = wb_sel_o_reg; + assign wb_stb_o = wb_stb_o_reg; + assign wb_cyc_o = wb_cyc_o_reg; -assign busy = busy_reg; + assign busy = busy_reg; -always @* begin + always @* begin state_next = STATE_IDLE; count_next = count_reg; @@ -276,152 +277,152 @@ always @* begin wb_cyc_o_next = 1'b0; case (state_reg) - STATE_IDLE: begin - // idle, wait for I2C interface - wb_we_o_next = 1'b0; - - if (data_out_valid) begin - // store address and write - count_next = ADDR_WORD_WIDTH-1; - state_next = STATE_ADDRESS; - end else if (data_in_ready & ~data_in_valid_reg) begin - // read - wb_cyc_o_next = 1'b1; - wb_stb_o_next = 1'b1; - wb_sel_o_next = {WB_SELECT_WIDTH{1'b1}}; - state_next = STATE_READ_1; - end + STATE_IDLE: begin + // idle, wait for I2C interface + wb_we_o_next = 1'b0; + + if (data_out_valid) begin + // store address and write + count_next = ADDR_WORD_WIDTH - 1; + state_next = STATE_ADDRESS; + end else if (data_in_ready & ~data_in_valid_reg) begin + // read + wb_cyc_o_next = 1'b1; + wb_stb_o_next = 1'b1; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b1}}; + state_next = STATE_READ_1; end - STATE_ADDRESS: begin - // store address - data_out_ready_next = 1'b1; - - if (data_out_ready_reg & data_out_valid) begin - // store pointers - addr_next[8*count_reg +: 8] = data_out; - count_next = count_reg - 1; - if (count_reg == 0) begin - // end of header - // set initial word offset - if (WB_ADDR_WIDTH == WB_VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin - count_next = 0; - end else begin - count_next = addr_next[ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH-1:0]; - end - wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; - data_next = {WB_DATA_WIDTH{1'b0}}; - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - // start writing - state_next = STATE_WRITE_1; - end - end else begin - if (data_out_last) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_ADDRESS; - end - end + end + STATE_ADDRESS: begin + // store address + data_out_ready_next = 1'b1; + + if (data_out_ready_reg & data_out_valid) begin + // store pointers + addr_next[8*count_reg+:8] = data_out; + count_next = count_reg - 1; + if (count_reg == 0) begin + // end of header + // set initial word offset + if (WB_ADDR_WIDTH == WB_VALID_ADDR_WIDTH && WORD_PART_ADDR_WIDTH == 0) begin + count_next = 0; end else begin - state_next = STATE_ADDRESS; + count_next = addr_next[ADDR_WIDTH_ADJ-WB_VALID_ADDR_WIDTH-1:0]; end - end - STATE_READ_1: begin - // wait for ack - wb_cyc_o_next = 1'b1; - wb_stb_o_next = 1'b1; - - if (wb_ack_i || wb_err_i) begin - // read cycle complete, store result - data_next = wb_dat_i; - addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - wb_cyc_o_next = 1'b0; - wb_stb_o_next = 1'b0; - wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; - state_next = STATE_READ_2; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; + data_next = {WB_DATA_WIDTH{1'b0}}; + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_1; + // start writing + state_next = STATE_WRITE_1; end - end - STATE_READ_2: begin - // send data - if (data_out_valid | !bus_addressed) begin - // no longer addressed or now addressed for write, return to idle - state_next = STATE_IDLE; - end else if (data_in_ready & ~data_in_valid_reg) begin - // transfer word and update pointers - data_in_next = data_reg[8*count_reg +: 8]; - data_in_valid_next = 1'b1; - count_next = count_reg + 1; - if (count_reg == (WB_SELECT_WIDTH*WB_WORD_SIZE/8)-1) begin - // end of stored data word; return to idle - count_next = 0; - state_next = STATE_IDLE; - end else begin - state_next = STATE_READ_2; - end + end else begin + if (data_out_last) begin + // end of transaction + state_next = STATE_IDLE; end else begin - state_next = STATE_READ_2; + state_next = STATE_ADDRESS; end + end + end else begin + state_next = STATE_ADDRESS; end - STATE_WRITE_1: begin - // write data - data_out_ready_next = 1'b1; - - if (data_out_ready_reg & data_out_valid) begin - // store word - data_next[8*count_reg +: 8] = data_out; - count_next = count_reg + 1; - wb_sel_o_next[count_reg >> ((WB_WORD_SIZE/8)-1)] = 1'b1; - if (count_reg == (WB_SELECT_WIDTH*WB_WORD_SIZE/8)-1 || data_out_last) begin - // have full word or at end of block, start write operation - count_next = 0; - wb_we_o_next = 1'b1; - wb_cyc_o_next = 1'b1; - wb_stb_o_next = 1'b1; - state_next = STATE_WRITE_2; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_1; - end + end + STATE_READ_1: begin + // wait for ack + wb_cyc_o_next = 1'b1; + wb_stb_o_next = 1'b1; + + if (wb_ack_i || wb_err_i) begin + // read cycle complete, store result + data_next = wb_dat_i; + addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); + wb_cyc_o_next = 1'b0; + wb_stb_o_next = 1'b0; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; + state_next = STATE_READ_2; + end else begin + state_next = STATE_READ_1; + end + end + STATE_READ_2: begin + // send data + if (data_out_valid | !bus_addressed) begin + // no longer addressed or now addressed for write, return to idle + state_next = STATE_IDLE; + end else if (data_in_ready & ~data_in_valid_reg) begin + // transfer word and update pointers + data_in_next = data_reg[8*count_reg+:8]; + data_in_valid_next = 1'b1; + count_next = count_reg + 1; + if (count_reg == (WB_SELECT_WIDTH * WB_WORD_SIZE / 8) - 1) begin + // end of stored data word; return to idle + count_next = 0; + state_next = STATE_IDLE; + end else begin + state_next = STATE_READ_2; + end + end else begin + state_next = STATE_READ_2; end - STATE_WRITE_2: begin - // wait for ack + end + STATE_WRITE_1: begin + // write data + data_out_ready_next = 1'b1; + + if (data_out_ready_reg & data_out_valid) begin + // store word + data_next[8*count_reg+:8] = data_out; + count_next = count_reg + 1; + wb_sel_o_next[count_reg>>((WB_WORD_SIZE/8)-1)] = 1'b1; + if (count_reg == (WB_SELECT_WIDTH * WB_WORD_SIZE / 8) - 1 || data_out_last) begin + // have full word or at end of block, start write operation + count_next = 0; + wb_we_o_next = 1'b1; wb_cyc_o_next = 1'b1; wb_stb_o_next = 1'b1; - - if (wb_ack_i || wb_err_i) begin - // end of write operation - data_next = {WB_DATA_WIDTH{1'b0}}; - addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); - wb_cyc_o_next = 1'b0; - wb_stb_o_next = 1'b0; - wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; - if (last_cycle_reg) begin - // end of transaction - state_next = STATE_IDLE; - end else begin - state_next = STATE_WRITE_1; - end - end else begin - state_next = STATE_WRITE_2; - end + state_next = STATE_WRITE_2; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_1; + end + end + STATE_WRITE_2: begin + // wait for ack + wb_cyc_o_next = 1'b1; + wb_stb_o_next = 1'b1; + + if (wb_ack_i || wb_err_i) begin + // end of write operation + data_next = {WB_DATA_WIDTH{1'b0}}; + addr_next = addr_reg + (1 << (WB_ADDR_WIDTH-WB_VALID_ADDR_WIDTH+WORD_PART_ADDR_WIDTH)); + wb_cyc_o_next = 1'b0; + wb_stb_o_next = 1'b0; + wb_sel_o_next = {WB_SELECT_WIDTH{1'b0}}; + if (last_cycle_reg) begin + // end of transaction + state_next = STATE_IDLE; + end else begin + state_next = STATE_WRITE_1; + end + end else begin + state_next = STATE_WRITE_2; end + end endcase -end + end -always @(posedge clk) begin + always @(posedge clk) begin state_reg <= state_next; count_reg <= count_next; if (data_out_ready_reg & data_out_valid) begin - last_cycle_reg <= data_out_last; + last_cycle_reg <= data_out_last; end addr_reg <= addr_next; @@ -440,53 +441,52 @@ always @(posedge clk) begin data_out_ready_reg <= data_out_ready_next; if (rst) begin - state_reg <= STATE_IDLE; - data_in_valid_reg <= 1'b0; - data_out_ready_reg <= 1'b0; - wb_stb_o_reg <= 1'b0; - wb_cyc_o_reg <= 1'b0; - busy_reg <= 1'b0; + state_reg <= STATE_IDLE; + data_in_valid_reg <= 1'b0; + data_out_ready_reg <= 1'b0; + wb_stb_o_reg <= 1'b0; + wb_cyc_o_reg <= 1'b0; + busy_reg <= 1'b0; end -end - -i2c_slave #( - .FILTER_LEN(FILTER_LEN) -) -i2c_slave_inst ( - .clk(clk), - .rst(rst), - - // Host interface - .release_bus(1'b0), - - .s_axis_data_tdata(data_in_reg), - .s_axis_data_tvalid(data_in_valid_reg), - .s_axis_data_tready(data_in_ready), - .s_axis_data_tlast(1'b0), - - .m_axis_data_tdata(data_out), - .m_axis_data_tvalid(data_out_valid), - .m_axis_data_tready(data_out_ready_reg), - .m_axis_data_tlast(data_out_last), - - // I2C Interface - .scl_i(i2c_scl_i), - .scl_o(i2c_scl_o), - .scl_t(i2c_scl_t), - .sda_i(i2c_sda_i), - .sda_o(i2c_sda_o), - .sda_t(i2c_sda_t), - - // Status - .busy(), - .bus_address(), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - - // Configuration - .enable(enable), - .device_address(device_address), - .device_address_mask(7'h7f) -); + end + + i2c_slave #( + .FILTER_LEN(FILTER_LEN) + ) i2c_slave_inst ( + .clk(clk), + .rst(rst), + + // Host interface + .release_bus(1'b0), + + .s_axis_data_tdata (data_in_reg), + .s_axis_data_tvalid(data_in_valid_reg), + .s_axis_data_tready(data_in_ready), + .s_axis_data_tlast (1'b0), + + .m_axis_data_tdata (data_out), + .m_axis_data_tvalid(data_out_valid), + .m_axis_data_tready(data_out_ready_reg), + .m_axis_data_tlast (data_out_last), + + // I2C Interface + .scl_i(i2c_scl_i), + .scl_o(i2c_scl_o), + .scl_t(i2c_scl_t), + .sda_i(i2c_sda_i), + .sda_o(i2c_sda_o), + .sda_t(i2c_sda_t), + + // Status + .busy(), + .bus_address(), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + + // Configuration + .enable(enable), + .device_address(device_address), + .device_address_mask(7'h7f) + ); endmodule diff --git a/tb/axil.py b/tb/axil.py index 0cce06d..850b41c 100644 --- a/tb/axil.py +++ b/tb/axil.py @@ -544,4 +544,3 @@ def read_logic(): s_axil_rvalid.next = False return instances() - diff --git a/tb/axis_ep.py b/tb/axis_ep.py index 351df0b..d03376f 100644 --- a/tb/axis_ep.py +++ b/tb/axis_ep.py @@ -519,4 +519,3 @@ def logic(): first = True return instances() - diff --git a/tb/i2c.py b/tb/i2c.py index aa7fad6..cf48fd6 100644 --- a/tb/i2c.py +++ b/tb/i2c.py @@ -506,5 +506,3 @@ def logic(): break return instances() - - diff --git a/tb/i2c_master_tb.v b/tb/i2c_master_tb.v new file mode 100644 index 0000000..5690f9f --- /dev/null +++ b/tb/i2c_master_tb.v @@ -0,0 +1,621 @@ +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for i2c_master + */ +module i2c_master_tb; + + // Parameters + + parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) + parameter ENABLE_DEVICE_3 = 1; // Set to 0 to disable device 3 + parameter ENABLE_DEVICE_4 = 1; // Set to 0 to disable device 4 + + reg clk = 0; + reg rst = 0; + wire rst_n; + assign rst_n=~rst; + reg [7:0] current_test = 0; + + // I2C master signals + reg [6:0] s_axis_cmd_address = 0; + reg s_axis_cmd_start = 0; + reg s_axis_cmd_read = 0; + reg s_axis_cmd_write = 0; + reg s_axis_cmd_write_multiple = 0; + reg s_axis_cmd_stop = 0; + reg s_axis_cmd_valid = 0; + reg [7:0] s_axis_data_tdata = 0; + reg s_axis_data_tvalid = 0; + reg s_axis_data_tlast = 0; + reg m_axis_data_tready = 0; + reg scl_i = 1; + reg sda_i = 1; + reg [15:0] prescale = 0; + reg stop_on_idle = 0; + + + wire s_axis_cmd_ready; + wire s_axis_data_tready; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire scl_o; + wire scl_t; + wire sda_o; + wire sda_t; + wire busy; + wire bus_control; + wire bus_active; + wire missed_ack; + wire value_has_been_written; //never used + + // Wires for modeling pull-up resistors and open-drain outputs + wire scl_wire; + wire sda_wire; + + // Dummy registers + reg sda2 = 1; + reg scl2 = 1; + + task wait_for_success; + reg continue_waiting; + begin + continue_waiting = 1; + while (continue_waiting) begin + @(posedge missed_ack or posedge value_has_been_written or posedge m_axis_data_tvalid or posedge s_axis_cmd_stop); + if (missed_ack) begin + s_axis_data_tvalid = 1; + $display("missed ack detected we retry happily?"); + end else if (value_has_been_written | m_axis_data_tvalid | s_axis_cmd_stop) begin + s_axis_data_tvalid = 0; + s_axis_cmd_valid = 0; + continue_waiting = 0; + end + end + end + endtask + // Generate block for Device 3 + generate + if (ENABLE_DEVICE_3) begin : device_3 + wire sda_o_3; + wire sda_t_3; + wire scl_o_3; + wire scl_t_3; + reg [7:0] data_in_3; + reg data_latch_3; + wire [7:0] data_out_3; + + i2c_single_reg #( + .FILTER_LEN(4), + .DEV_ADDR (7'h70), + .DEBUG(1) + ) i2c_reg ( + .clk(clk), + .rst_n, + .scl_i(scl_wire), + .scl_o(scl_o_3), + .scl_t(scl_t_3), + .sda_i(sda_wire), + .sda_o(sda_o_3), + .sda_t(sda_t_3), + .data_in(data_in_3), + .data_latch(data_latch_3), + .data_out(data_out_3) + ); + + + // Task to test i2c_single_reg writing + task test_i2c_single_reg_writing; + begin + $display("Testing i2c_single_reg writing"); + //wait_for_ready(); + i2c_start(7'h70, 0); + s_axis_data_tdata = 8'd55; + s_axis_data_tvalid = 1; + wait_for_success; + + wait_for_ready(); + if (data_out_3 != 8'd55) $fatal(1, "We didn't get what we sent"); + $display("Received data %d", data_out_3); + end + endtask + + // Task to test i2c_single_reg reading + task test_i2c_single_reg_reading; + begin + $display("Testing i2c_single_reg reading"); + data_latch_3 = 1; + data_in_3 = 8'd123; + m_axis_data_tready = 1; + #(CLK_PERIOD); + data_latch_3 = 0; + i2c_start(7'h70, 1); + wait_for_success; + //@(posedge m_axis_data_tvalid); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'd123) $fatal(1, "We didn't get what we sent"); + end + endtask + + end else begin : device_3 + wire scl_o_3 = 1'b1; + wire sda_o_3 = 1'b1; + reg data_out_3 = 1'b1; + + task test_i2c_single_reg_writing; + $display("not implemented"); + endtask + + // Task to test i2c_single_reg reading + task test_i2c_single_reg_reading; + $display("not implemented"); + endtask + + + end + endgenerate + + // Generate block for Device 4 + generate + if (ENABLE_DEVICE_4) begin : device_4 + wire sda_o_4; + wire sda_t_4; + wire scl_o_4; + wire scl_t_4; + wire [7:0] m_axis_data_tdata_4; + wire m_axis_data_tvalid_4; + reg m_axis_data_tready_4; + wire m_axis_data_tlast_4; + reg [7:0] s_axis_data_tdata_4; + reg s_axis_data_tvalid_4; + wire s_axis_data_tready_4; + reg s_axis_data_tlast_4; + wire busy_4; + wire [6:0] bus_address_4; + wire bus_addressed_4; + wire bus_active_4; + reg release_bus_4; + reg enable_4; + reg [6:0] device_address_4; + reg [6:0] device_address_mask_4; + + i2c_slave #( + .FILTER_LEN(4) + ) i2c_slave_inst ( + .clk(clk), + .rst_n, + .release_bus(release_bus_4), + .s_axis_data_tdata(s_axis_data_tdata_4), + .s_axis_data_tvalid(s_axis_data_tvalid_4), + .s_axis_data_tready(s_axis_data_tready_4), + .s_axis_data_tlast(s_axis_data_tlast_4), + .m_axis_data_tdata(m_axis_data_tdata_4), + .m_axis_data_tvalid(m_axis_data_tvalid_4), + .m_axis_data_tready(m_axis_data_tready_4), + .m_axis_data_tlast(m_axis_data_tlast_4), + .scl_i(scl_wire), + .scl_o(scl_o_4), + .scl_t(scl_t_4), + .sda_i(sda_wire), + .sda_o(sda_o_4), + .sda_t(sda_t_4), + .busy(busy_4), + .bus_address(bus_address_4), + .bus_addressed(bus_addressed_4), + .bus_active(bus_active_4), + .enable(enable_4), + .device_address(device_address_4), + .device_address_mask(device_address_mask_4) + ); + + task test_write_to_i2c_slave; + begin + $display("Testing writing to i2c_slave (device_4)"); + enable_4 = 1; + device_address_4 = 7'h42; // Set slave address + device_address_mask_4 = 7'h7F; // Check all bits + + i2c_start(7'h42, 0); // Start write operation + s_axis_data_tdata = 8'hAA; // Data to write + s_axis_data_tvalid = 1; + stop_on_idle = 1; + wait_for_success; + + wait_for_ready(); + + if (m_axis_data_tdata_4 !== 8'hAA) $fatal(1, "First byte mismatch"); + s_axis_data_tdata = 8'h55; // Second byte to write + s_axis_data_tvalid = 1; + s_axis_cmd_valid = 1; //still valid + s_axis_cmd_write = 1; //really write the second + + wait_for_ready(); + #(CLK_PERIOD * 120); //for verilator + if (m_axis_data_tdata_4 !== 8'h55) begin + // It seems verilator has trouble with this + $display("instead of 55 we get %h", m_axis_data_tdata_4); + $fatal(1, "Second byte mismatch"); + end + + s_axis_cmd_valid = 0; + wait_for_ready(); + + #(CLK_PERIOD * 10); // Wait for slave to process + + $display("Write to i2c_slave successful"); + end + endtask + + // Task to test reading from i2c_slave + task test_read_from_i2c_slave; + begin + $display("Testing reading from i2c_slave (device_4)"); + enable_4 = 1; + device_address_4 = 7'h42; // Set slave address + device_address_mask_4 = 7'h7F; // Check all bits + + // Prepare data to be read + s_axis_data_tdata_4 = 8'hCC; + s_axis_data_tvalid_4 = 1; + i2c_start(7'h42, 1); // Start read operation + m_axis_data_tready = 1; + $display("i2c start was started and now waiting for m_axis_data_tvalid.."); + wait_for_success; + s_axis_data_tvalid_4 = 0; + if (m_axis_data_tdata !== 8'hCC) $fatal(1, "First read byte mismatch"); + + s_axis_cmd_valid = 1; //read 2 times + s_axis_cmd_read = 1; + s_axis_data_tvalid_4 = 1; + s_axis_data_tdata_4 = 8'hDD; + wait_for_success; + if (m_axis_data_tdata !== 8'hDD) $fatal(1, "Second read byte mismatch"); + + s_axis_cmd_valid = 0; + wait_for_ready(); + + $display("Read from i2c_slave successful"); + end + endtask + + // Task to test bus release, incomplete (not done) + task test_bus_release; + begin + $display("Testing bus release for i2c_slave (device_4)"); + enable_4 = 1; + device_address_4 = 7'h42; // Set slave address + device_address_mask_4 = 7'h7F; // Check all bits + + i2c_start(7'h42, 0); // Start write operation + #(CLK_PERIOD * 10); + + if (!bus_active_4) $fatal(1, "Bus should be active"); + + release_bus_4 = 1; + #(CLK_PERIOD); + release_bus_4 = 0; + + #(CLK_PERIOD * 10); + + if (bus_active_4) $fatal(1, "Bus should not be active after release"); + + $display("Bus release test successful"); + end + endtask + + end else begin : device_4 + wire scl_o_4 = 1'b1; + wire sda_o_4 = 1'b1; + reg m_axis_data_tready_4 = 0; + + task test_write_to_i2c_slave; + begin + $display("not implemented"); + end + endtask + task test_read_from_i2c_slave; + begin + $display("not implemented"); + end + endtask + + end + + endgenerate + + // Model pull-up resistors with weak pull-ups + pullup (scl_wire); + pullup (sda_wire); + + // Model open-drain outputs, including conditional devices + assign scl_wire = (scl_o & scl2 & device_3.scl_o_3 & device_4.scl_o_4) ? 1'bz : 1'b0; + assign sda_wire = (sda_o & sda2 & device_3.sda_o_3 & device_4.sda_o_4) ? 1'bz : 1'b0; + + + always #(CLK_PERIOD / 2) clk <= ~clk; + + // Sample the bus with non-blocking assignments to avoid race conditions + always @(posedge clk or posedge rst) begin + if (rst) begin + scl_i <= 1'b1; + sda_i <= 1'b1; + end else begin + scl_i <= scl_wire; + sda_i <= sda_wire; + + // Assert that sda_i is not X + if (sda_i === 1'bx) begin + + $display("sda4 %d", device_4.sda_o_4); + + $fatal(1, "sda_i is X at time %t", $time); + end + end + end + + initial begin + // dump file + $dumpfile("i2c_master_tb.vcd"); + $dumpvars(0, i2c_master_tb); + + end + + i2c_master UUT ( + .clk(clk), + .rst_n, + .s_axis_cmd_address(s_axis_cmd_address), + .s_axis_cmd_start(s_axis_cmd_start), + .s_axis_cmd_read(s_axis_cmd_read), + .s_axis_cmd_write(s_axis_cmd_write), + .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), + .s_axis_cmd_stop(s_axis_cmd_stop), + .s_axis_cmd_valid(s_axis_cmd_valid), + .s_axis_cmd_ready(s_axis_cmd_ready), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_control(bus_control), + .bus_active(bus_active), + .missed_ack(missed_ack), + .value_has_been_written(value_has_been_written), + .prescale(prescale), + .stop_on_idle(stop_on_idle) + ); + + task initialize_testbench; + begin + clk = 0; + rst = 1; + s_axis_cmd_address = 0; + s_axis_cmd_start = 0; + s_axis_cmd_read = 0; + s_axis_cmd_write = 0; + s_axis_cmd_write_multiple = 0; + s_axis_cmd_stop = 0; + s_axis_cmd_valid = 0; + s_axis_data_tdata = 0; + s_axis_data_tvalid = 0; + s_axis_data_tlast = 0; + m_axis_data_tready = 0; + scl_i = 1; + sda_i = 1; + prescale = 0; + stop_on_idle = 0; + sda2 = 1; + scl2 = 1; + + #10 rst = 0; + end + endtask + + task i2c_start; + input [6:0] address; + input is_read; + begin + s_axis_cmd_address = address; + //s_axis_cmd_start = 1; + s_axis_cmd_read = is_read; + s_axis_cmd_write = !is_read; + s_axis_cmd_valid = 1; + + //cant enforce anyway + + //@(negedge sda_wire); + //@(negedge scl_wire); //start condition done! + + //s_axis_cmd_start = 0; + //s_axis_cmd_read = 0; + //s_axis_cmd_write = 0; + //s_axis_cmd_valid = 0; + end + endtask + + task send_byte; + input [7:0] byte_to_send; + integer i; + begin + for (i = 7; i >= 0; i = i - 1) begin + sda2 = byte_to_send[i]; + @(negedge scl_o); + end + end + + endtask + + task wait_for_ready; + begin + $display("Waiting for ready"); + @(posedge s_axis_cmd_ready); + #CLK_PERIOD; + end + endtask + + task send_ack; + begin + @(negedge scl_o); + sda2 = 0; + #CLK_PERIOD; + @(negedge scl_o); + sda2 = 1; + end + endtask + + // Task to test NACK handling + task test_nack_handling; + begin + $display("Testing NACK handling."); + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10100101; + s_axis_data_tvalid = 1; + @(posedge missed_ack); + $display("NACK expected!"); + wait_for_ready(); + end + endtask + + // Task to test writing + task test_writing; + begin + $display("Testing Writing."); + i2c_start(7'b0000001, 0); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + repeat (7) @(negedge scl_o); + s_axis_cmd_valid = 0; + send_ack(); + @(negedge scl_o); + //send_byte(8'b01111111); + wait_for_ready(); + end + endtask + // Task to test writing + task test_write_weird; + begin + $display("Testing something write weird."); + i2c_start(7'h70, 0); + $display("send address?"); + @(posedge s_axis_data_tready); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + wait_for_success; + $display("success %b", device_3.data_out_3); + //wait 1000 cycles + #1000; + s_axis_cmd_valid = 1; + s_axis_data_tdata = 8'd2; + s_axis_data_tvalid = 1; + wait_for_success; + $display("success %b", device_3.data_out_3); + #1000; + stop_on_idle = 1; + + //repeat (7) @(negedge scl_o); + //send_ack(); + //@(negedge scl_o); + //send_byte(8'b01111111); + wait_for_ready(); + end + endtask + + task test_read_weird; + begin + stop_on_idle = 0; + $display("Testing something read weird."); + i2c_start(7'h70, 1); + m_axis_data_tready = 1; + wait_for_success; + m_axis_data_tready = 0; + $display("success %b", m_axis_data_tdata); + //wait 1000 cycles + #1000; + s_axis_cmd_valid = 1; + m_axis_data_tready = 1; + wait_for_success; + $display("success %b", m_axis_data_tdata); + #1000; + stop_on_idle = 1; + + //repeat (7) @(negedge scl_o); + //send_ack(); + //@(negedge scl_o); + //send_byte(8'b01111111); + wait_for_ready(); + end + endtask + + + // Task to test reading + task test_reading; + begin + $display("Testing reading."); + s_axis_data_tdata = 8'b10101111; + s_axis_data_tvalid = 1; + i2c_start(7'b0000001, 1); + repeat (8) @(negedge scl_o); + s_axis_cmd_valid = 0; + send_ack(); + send_byte(8'b01111111); + s_axis_cmd_read = 1; + s_axis_cmd_valid = 1; + m_axis_data_tready = 1; + @(negedge scl_o); + + if (sda_wire) #1000 $fatal(1, "Got NACK from master"); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + if (m_axis_data_tdata != 8'b01111111) $fatal(1, "We didn't get what we sent"); + #(CLK_PERIOD); + stop_on_idle = 1; + send_byte(8'd69); + @(posedge m_axis_data_tvalid); + if (m_axis_data_tdata != 8'd69) $fatal(1, "We didn't get what we sent"); + $display("Received m_axis_data_tdata %d", m_axis_data_tdata); + s_axis_cmd_valid = 0; + wait_for_ready(); + end + endtask + // Task to test writing to i2c_slave + initial begin + /*new goal: read 1, then decide wether to stop or read 2. both options + * must be allowed*/ + $display("Starting I2C Master test"); + initialize_testbench; + stop_on_idle = 1; + device_3.test_i2c_single_reg_writing(); + test_nack_handling(); //killing time for dev3 it needs time to initialize + test_read_weird(); + device_3.test_i2c_single_reg_writing(); + stop_on_idle = 0; + test_write_weird(); + test_writing(); + + #1000; //stopping + + test_reading(); + wait_for_ready(); + device_3.test_i2c_single_reg_reading(); + #1000; //stopping + //we are always ready + device_4.m_axis_data_tready_4 = 1; + device_4.test_write_to_i2c_slave(); + device_4.test_read_from_i2c_slave(); + // test_bus_release(); + + #1000; + $finish; + end +endmodule diff --git a/tb/i2c_phy_tb.sv b/tb/i2c_phy_tb.sv new file mode 100644 index 0000000..218625d --- /dev/null +++ b/tb/i2c_phy_tb.sv @@ -0,0 +1,210 @@ +`timescale 1ns / 1ps + +module i2c_phy_tb; + + // Parameters + parameter CLK_PERIOD = 10; // 10ns clock period (100MHz clock) + + // Signals + reg clk = 0; + reg rst = 1; + reg phy_start_bit = 0; + reg phy_stop_bit = 0; + reg phy_write_bit = 0; + reg phy_read_bit = 0; + reg phy_tx_data = 0; + reg phy_release_bus = 0; + reg scl_i = 1;//Technically they are not registers but in testbench we need to store them somewhere + wire scl_o; + reg sda_i = 1; + wire sda_o; + reg sda2 = 1; //dummy registers + reg scl2 = 1; + wire sda_t; + wire scl_t; + wire phy_busy; + wire bus_control_reg; + wire phy_rx_data_reg; + wire [4:0] phy_state_reg; + + // Clock generation + always #(CLK_PERIOD / 2) clk <= ~clk; + + // Tri-state buffer modeling + wire scl_wire; + wire sda_wire; + + reg scl_i_reg_tb, sda_i_reg_tb; + // Model pull-up resistors with weak pull-ups + pullup (scl_wire); + pullup (sda_wire); + + // Model open-drain outputs + assign scl_wire = (scl_o & scl2) ? 1'bz : 1'b0; + assign sda_wire = (sda_o & sda2) ? 1'bz : 1'b0; + + // Sample the bus with non-blocking assignments to avoid race conditions + always @(posedge clk or posedge rst) begin + if (rst) begin + scl_i_reg_tb <= 1'b1; + sda_i_reg_tb <= 1'b1; + end else begin + scl_i_reg_tb <= scl_wire; + sda_i_reg_tb <= sda_wire; + + // Assert that sda_i_reg is not X + if (sda_i_reg_tb === 1'bx) $fatal(1, "sda_i_reg is X at time %t", $time); + end + end + + + + // Instantiate the i2c_phy module + i2c_phy uut ( + .clk(clk), + .rst(rst_n), + .phy_start_bit(phy_start_bit), + .phy_stop_bit(phy_stop_bit), + .phy_write_bit(phy_write_bit), + .phy_read_bit(phy_read_bit), + .phy_tx_data(phy_tx_data), + .phy_release_bus(phy_release_bus), + .scl_i(scl_i_reg_tb), + .scl_o(scl_o), + .sda_i(sda_i_reg_tb), + .sda_o(sda_o), + .sda_t(sda_t), + .scl_t(scl_t), + .phy_busy(phy_busy), + .bus_control_reg(bus_control_reg), + .phy_rx_data_reg(phy_rx_data_reg), + .phy_state_reg(phy_state_reg), + .prescale(17'd3) + ); + task initialize; + begin + rst = 0; + phy_start_bit = 0; + phy_stop_bit = 0; + phy_write_bit = 0; + phy_read_bit = 0; + phy_tx_data = 0; + phy_release_bus = 0; + end + endtask + + task reset; + begin + rst = 0; + #(CLK_PERIOD * 5); + rst = 1; + #(CLK_PERIOD * 5); + end + endtask + task write_operation(input tx_data); + begin + wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE + phy_write_bit = 1; + phy_tx_data = tx_data; + #(CLK_PERIOD * 2); + end + endtask + task read_operation; + begin + wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE + phy_write_bit = 0; + phy_read_bit = 1; + #(CLK_PERIOD * 2); + end + endtask + + task wait_for_idle; + begin + wait (phy_state_reg == 5'd0); // Assuming PHY_STATE_IDLE is 5'd0 + end + endtask + + // Specific test scenarios + task test_write_byte; + begin + $display("Testing write byte operation"); + phy_start_bit = 1; + #(CLK_PERIOD); + phy_start_bit = 0; + + // Write byte 0x81 (10000001) + write_operation(1); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(1); + + // Read ACK + //Send ACK + sda2 = 0; + read_operation; + wait (phy_state_reg == 5'd1); // Wait for PHY_STATE_ACTIVE + sda2 = 1; //pull sda2 back up + if (phy_rx_data_reg != 0) $finish(1,"Expecting ACK but found NACK: %d ", phy_rx_data_reg); + end + endtask + + task test_read_byte; + begin + $display("Testing read byte operation"); + phy_start_bit = 1; + #(CLK_PERIOD); + phy_start_bit = 0; + + // Send read command (e.g., 0xA1 for read) + write_operation(1); + write_operation(0); + write_operation(1); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(0); + write_operation(1); + + // Read ACK + read_operation; + + // Read byte + repeat (8) begin + read_operation; + end + + // Send NACK + write_operation(1); + end + endtask + + // Main test procedure + initial begin + $display("Starting I2C PHY Test"); + initialize; + $display("Initialized"); + reset; + $display("reseted"); + + $display("Test write"); + test_write_byte; + $display("Test idle?"); + //wait_for_idle; + + //test_read_byte; + //wait_for_idle; + + $display("I2C PHY Test Completed"); + $finish; + end + // Optional: Dump waveforms + initial begin + $dumpfile("i2c_phy_tb.vcd"); + $dumpvars(0, i2c_phy_tb); + end + +endmodule diff --git a/tb/test_i2c.py b/tb/test_i2c.py index 6a77cd8..7661c9e 100755 --- a/tb/test_i2c.py +++ b/tb/test_i2c.py @@ -233,4 +233,3 @@ def test_bench(): if __name__ == '__main__': print("Running test...") test_bench() - diff --git a/tb/test_i2c_init.v b/tb/test_i2c_init.v index 9fe4b72..f26eda4 100644 --- a/tb/test_i2c_init.v +++ b/tb/test_i2c_init.v @@ -31,76 +31,59 @@ THE SOFTWARE. */ module test_i2c_init; -// Parameters - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg m_axis_cmd_ready = 0; -reg m_axis_data_tready = 0; -reg start = 0; - -// Outputs -wire [6:0] m_axis_cmd_address; -wire m_axis_cmd_start; -wire m_axis_cmd_read; -wire m_axis_cmd_write; -wire m_axis_cmd_write_multiple; -wire m_axis_cmd_stop; -wire m_axis_cmd_valid; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire busy; - -initial begin + // Parameters + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg m_axis_cmd_ready = 0; + reg m_axis_data_tready = 0; + reg start = 0; + + // Outputs + wire [6:0] m_axis_cmd_address; + wire m_axis_cmd_start; + wire m_axis_cmd_read; + wire m_axis_cmd_write; + wire m_axis_cmd_write_multiple; + wire m_axis_cmd_stop; + wire m_axis_cmd_valid; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire busy; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - m_axis_cmd_ready, - m_axis_data_tready, - start); - $to_myhdl( - m_axis_cmd_address, - m_axis_cmd_start, - m_axis_cmd_read, - m_axis_cmd_write, - m_axis_cmd_write_multiple, - m_axis_cmd_stop, - m_axis_cmd_valid, - m_axis_data_tdata, - m_axis_data_tvalid, - m_axis_data_tlast, - busy - ); + $from_myhdl(clk, rst, current_test, m_axis_cmd_ready, m_axis_data_tready, start); + $to_myhdl(m_axis_cmd_address, m_axis_cmd_start, m_axis_cmd_read, m_axis_cmd_write, + m_axis_cmd_write_multiple, m_axis_cmd_stop, m_axis_cmd_valid, m_axis_data_tdata, + m_axis_data_tvalid, m_axis_data_tlast, busy); // dump file $dumpfile("test_i2c_init.lxt"); $dumpvars(0, test_i2c_init); -end - -i2c_init -UUT ( - .clk(clk), - .rst(rst), - .m_axis_cmd_address(m_axis_cmd_address), - .m_axis_cmd_start(m_axis_cmd_start), - .m_axis_cmd_read(m_axis_cmd_read), - .m_axis_cmd_write(m_axis_cmd_write), - .m_axis_cmd_write_multiple(m_axis_cmd_write_multiple), - .m_axis_cmd_stop(m_axis_cmd_stop), - .m_axis_cmd_valid(m_axis_cmd_valid), - .m_axis_cmd_ready(m_axis_cmd_ready), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .busy(busy), - .start(start) -); + end + + i2c_init UUT ( + .clk(clk), + .rst(rst), + .m_axis_cmd_address(m_axis_cmd_address), + .m_axis_cmd_start(m_axis_cmd_start), + .m_axis_cmd_read(m_axis_cmd_read), + .m_axis_cmd_write(m_axis_cmd_write), + .m_axis_cmd_write_multiple(m_axis_cmd_write_multiple), + .m_axis_cmd_stop(m_axis_cmd_stop), + .m_axis_cmd_valid(m_axis_cmd_valid), + .m_axis_cmd_ready(m_axis_cmd_ready), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .busy(busy), + .start(start) + ); endmodule diff --git a/tb/test_i2c_master.v b/tb/test_i2c_master.v index 2622438..3766600 100644 --- a/tb/test_i2c_master.v +++ b/tb/test_i2c_master.v @@ -31,119 +31,90 @@ THE SOFTWARE. */ module test_i2c_master; -// Parameters - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [6:0] s_axis_cmd_address = 0; -reg s_axis_cmd_start = 0; -reg s_axis_cmd_read = 0; -reg s_axis_cmd_write = 0; -reg s_axis_cmd_write_multiple = 0; -reg s_axis_cmd_stop = 0; -reg s_axis_cmd_valid = 0; -reg [7:0] s_axis_data_tdata = 0; -reg s_axis_data_tvalid = 0; -reg s_axis_data_tlast = 0; -reg m_axis_data_tready = 0; -reg scl_i = 1; -reg sda_i = 1; -reg [15:0] prescale = 0; -reg stop_on_idle = 0; - -// Outputs -wire s_axis_cmd_ready; -wire s_axis_data_tready; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire scl_o; -wire scl_t; -wire sda_o; -wire sda_t; -wire busy; -wire bus_control; -wire bus_active; -wire missed_ack; - -initial begin + // Parameters + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [6:0] s_axis_cmd_address = 0; + reg s_axis_cmd_start = 0; + reg s_axis_cmd_read = 0; + reg s_axis_cmd_write = 0; + reg s_axis_cmd_write_multiple = 0; + reg s_axis_cmd_stop = 0; + reg s_axis_cmd_valid = 0; + reg [7:0] s_axis_data_tdata = 0; + reg s_axis_data_tvalid = 0; + reg s_axis_data_tlast = 0; + reg m_axis_data_tready = 0; + reg scl_i = 1; + reg sda_i = 1; + reg [15:0] prescale = 0; + reg stop_on_idle = 0; + + // Outputs + wire s_axis_cmd_ready; + wire s_axis_data_tready; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire scl_o; + wire scl_t; + wire sda_o; + wire sda_t; + wire busy; + wire bus_control; + wire bus_active; + wire missed_ack; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - s_axis_cmd_address, - s_axis_cmd_start, - s_axis_cmd_read, - s_axis_cmd_write, - s_axis_cmd_write_multiple, - s_axis_cmd_stop, - s_axis_cmd_valid, - s_axis_data_tdata, - s_axis_data_tvalid, - s_axis_data_tlast, - m_axis_data_tready, - scl_i, - sda_i, - prescale, - stop_on_idle - ); - $to_myhdl( - s_axis_cmd_ready, - s_axis_data_tready, - m_axis_data_tdata, - m_axis_data_tvalid, - m_axis_data_tlast, - scl_o, - scl_t, - sda_o, - sda_t, - busy, - bus_control, - bus_active, - missed_ack - ); + $from_myhdl(clk, rst, current_test, s_axis_cmd_address, s_axis_cmd_start, s_axis_cmd_read, + s_axis_cmd_write, s_axis_cmd_write_multiple, s_axis_cmd_stop, s_axis_cmd_valid, + s_axis_data_tdata, s_axis_data_tvalid, s_axis_data_tlast, m_axis_data_tready, + scl_i, sda_i, prescale, stop_on_idle); + $to_myhdl(s_axis_cmd_ready, s_axis_data_tready, m_axis_data_tdata, m_axis_data_tvalid, + m_axis_data_tlast, scl_o, scl_t, sda_o, sda_t, busy, bus_control, bus_active, + missed_ack); // dump file $dumpfile("test_i2c_master.lxt"); $dumpvars(0, test_i2c_master); -end - -i2c_master -UUT ( - .clk(clk), - .rst(rst), - .s_axis_cmd_address(s_axis_cmd_address), - .s_axis_cmd_start(s_axis_cmd_start), - .s_axis_cmd_read(s_axis_cmd_read), - .s_axis_cmd_write(s_axis_cmd_write), - .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), - .s_axis_cmd_stop(s_axis_cmd_stop), - .s_axis_cmd_valid(s_axis_cmd_valid), - .s_axis_cmd_ready(s_axis_cmd_ready), - .s_axis_data_tdata(s_axis_data_tdata), - .s_axis_data_tvalid(s_axis_data_tvalid), - .s_axis_data_tready(s_axis_data_tready), - .s_axis_data_tlast(s_axis_data_tlast), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .scl_i(scl_i), - .scl_o(scl_o), - .scl_t(scl_t), - .sda_i(sda_i), - .sda_o(sda_o), - .sda_t(sda_t), - .busy(busy), - .bus_control(bus_control), - .bus_active(bus_active), - .missed_ack(missed_ack), - .prescale(prescale), - .stop_on_idle(stop_on_idle) -); + end + + i2c_master UUT ( + .clk(clk), + .rst(rst), + .s_axis_cmd_address(s_axis_cmd_address), + .s_axis_cmd_start(s_axis_cmd_start), + .s_axis_cmd_read(s_axis_cmd_read), + .s_axis_cmd_write(s_axis_cmd_write), + .s_axis_cmd_write_multiple(s_axis_cmd_write_multiple), + .s_axis_cmd_stop(s_axis_cmd_stop), + .s_axis_cmd_valid(s_axis_cmd_valid), + .s_axis_cmd_ready(s_axis_cmd_ready), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_control(bus_control), + .bus_active(bus_active), + .missed_ack(missed_ack), + .prescale(prescale), + .stop_on_idle(stop_on_idle) + ); endmodule diff --git a/tb/test_i2c_master_axil.v b/tb/test_i2c_master_axil.v index de6995d..4e8a7c6 100644 --- a/tb/test_i2c_master_axil.v +++ b/tb/test_i2c_master_axil.v @@ -31,127 +31,100 @@ THE SOFTWARE. */ module test_i2c_master_axil; -// Parameters -parameter DEFAULT_PRESCALE = 1; -parameter FIXED_PRESCALE = 0; -parameter CMD_FIFO = 1; -parameter CMD_FIFO_DEPTH = 32; -parameter WRITE_FIFO = 1; -parameter WRITE_FIFO_DEPTH = 32; -parameter READ_FIFO = 1; -parameter READ_FIFO_DEPTH = 32; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [3:0] s_axil_awaddr = 0; -reg [2:0] s_axil_awprot = 0; -reg s_axil_awvalid = 0; -reg [31:0] s_axil_wdata = 0; -reg [3:0] s_axil_wstrb = 0; -reg s_axil_wvalid = 0; -reg s_axil_bready = 0; -reg [3:0] s_axil_araddr = 0; -reg [2:0] s_axil_arprot = 0; -reg s_axil_arvalid = 0; -reg s_axil_rready = 0; -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; - -// Outputs -wire s_axil_awready; -wire s_axil_wready; -wire [1:0] s_axil_bresp; -wire s_axil_bvalid; -wire s_axil_arready; -wire [31:0] s_axil_rdata; -wire [1:0] s_axil_rresp; -wire s_axil_rvalid; -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; - -initial begin + // Parameters + parameter DEFAULT_PRESCALE = 1; + parameter FIXED_PRESCALE = 0; + parameter CMD_FIFO = 1; + parameter CMD_FIFO_DEPTH = 32; + parameter WRITE_FIFO = 1; + parameter WRITE_FIFO_DEPTH = 32; + parameter READ_FIFO = 1; + parameter READ_FIFO_DEPTH = 32; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [3:0] s_axil_awaddr = 0; + reg [2:0] s_axil_awprot = 0; + reg s_axil_awvalid = 0; + reg [31:0] s_axil_wdata = 0; + reg [3:0] s_axil_wstrb = 0; + reg s_axil_wvalid = 0; + reg s_axil_bready = 0; + reg [3:0] s_axil_araddr = 0; + reg [2:0] s_axil_arprot = 0; + reg s_axil_arvalid = 0; + reg s_axil_rready = 0; + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + + // Outputs + wire s_axil_awready; + wire s_axil_wready; + wire [1:0] s_axil_bresp; + wire s_axil_bvalid; + wire s_axil_arready; + wire [31:0] s_axil_rdata; + wire [1:0] s_axil_rresp; + wire s_axil_rvalid; + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - s_axil_awaddr, - s_axil_awprot, - s_axil_awvalid, - s_axil_wdata, - s_axil_wstrb, - s_axil_wvalid, - s_axil_bready, - s_axil_araddr, - s_axil_arprot, - s_axil_arvalid, - s_axil_rready, - i2c_scl_i, - i2c_sda_i - ); - $to_myhdl( - s_axil_awready, - s_axil_wready, - s_axil_bresp, - s_axil_bvalid, - s_axil_arready, - s_axil_rdata, - s_axil_rresp, - s_axil_rvalid, - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t - ); + $from_myhdl(clk, rst, current_test, s_axil_awaddr, s_axil_awprot, s_axil_awvalid, s_axil_wdata, + s_axil_wstrb, s_axil_wvalid, s_axil_bready, s_axil_araddr, s_axil_arprot, + s_axil_arvalid, s_axil_rready, i2c_scl_i, i2c_sda_i); + $to_myhdl(s_axil_awready, s_axil_wready, s_axil_bresp, s_axil_bvalid, s_axil_arready, + s_axil_rdata, s_axil_rresp, s_axil_rvalid, i2c_scl_o, i2c_scl_t, i2c_sda_o, + i2c_sda_t); // dump file $dumpfile("test_i2c_master_axil.lxt"); $dumpvars(0, test_i2c_master_axil); -end - -i2c_master_axil #( - .DEFAULT_PRESCALE(DEFAULT_PRESCALE), - .FIXED_PRESCALE(FIXED_PRESCALE), - .CMD_FIFO(CMD_FIFO), - .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), - .WRITE_FIFO(WRITE_FIFO), - .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), - .READ_FIFO(READ_FIFO), - .READ_FIFO_DEPTH(READ_FIFO_DEPTH) -) -UUT ( - .clk(clk), - .rst(rst), - .s_axil_awaddr(s_axil_awaddr), - .s_axil_awprot(s_axil_awprot), - .s_axil_awvalid(s_axil_awvalid), - .s_axil_awready(s_axil_awready), - .s_axil_wdata(s_axil_wdata), - .s_axil_wstrb(s_axil_wstrb), - .s_axil_wvalid(s_axil_wvalid), - .s_axil_wready(s_axil_wready), - .s_axil_bresp(s_axil_bresp), - .s_axil_bvalid(s_axil_bvalid), - .s_axil_bready(s_axil_bready), - .s_axil_araddr(s_axil_araddr), - .s_axil_arprot(s_axil_arprot), - .s_axil_arvalid(s_axil_arvalid), - .s_axil_arready(s_axil_arready), - .s_axil_rdata(s_axil_rdata), - .s_axil_rresp(s_axil_rresp), - .s_axil_rvalid(s_axil_rvalid), - .s_axil_rready(s_axil_rready), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t) -); + end + + i2c_master_axil #( + .DEFAULT_PRESCALE(DEFAULT_PRESCALE), + .FIXED_PRESCALE(FIXED_PRESCALE), + .CMD_FIFO(CMD_FIFO), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .WRITE_FIFO(WRITE_FIFO), + .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), + .READ_FIFO(READ_FIFO), + .READ_FIFO_DEPTH(READ_FIFO_DEPTH) + ) UUT ( + .clk(clk), + .rst(rst), + .s_axil_awaddr(s_axil_awaddr), + .s_axil_awprot(s_axil_awprot), + .s_axil_awvalid(s_axil_awvalid), + .s_axil_awready(s_axil_awready), + .s_axil_wdata(s_axil_wdata), + .s_axil_wstrb(s_axil_wstrb), + .s_axil_wvalid(s_axil_wvalid), + .s_axil_wready(s_axil_wready), + .s_axil_bresp(s_axil_bresp), + .s_axil_bvalid(s_axil_bvalid), + .s_axil_bready(s_axil_bready), + .s_axil_araddr(s_axil_araddr), + .s_axil_arprot(s_axil_arprot), + .s_axil_arvalid(s_axil_arvalid), + .s_axil_arready(s_axil_arready), + .s_axil_rdata(s_axil_rdata), + .s_axil_rresp(s_axil_rresp), + .s_axil_rvalid(s_axil_rvalid), + .s_axil_rready(s_axil_rready), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t) + ); endmodule diff --git a/tb/test_i2c_master_wbs_16.v b/tb/test_i2c_master_wbs_16.v index ff5573a..2f3be53 100644 --- a/tb/test_i2c_master_wbs_16.v +++ b/tb/test_i2c_master_wbs_16.v @@ -31,94 +31,75 @@ THE SOFTWARE. */ module test_i2c_master_wbs_16; -// Parameters -parameter DEFAULT_PRESCALE = 1; -parameter FIXED_PRESCALE = 0; -parameter CMD_FIFO = 1; -parameter CMD_FIFO_DEPTH = 32; -parameter WRITE_FIFO = 1; -parameter WRITE_FIFO_DEPTH = 32; -parameter READ_FIFO = 1; -parameter READ_FIFO_DEPTH = 32; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [2:0] wbs_adr_i = 0; -reg [15:0] wbs_dat_i = 0; -reg wbs_we_i = 0; -reg [1:0] wbs_sel_i = 0; -reg wbs_stb_i = 0; -reg wbs_cyc_i = 0; -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; - -// Outputs -wire [15:0] wbs_dat_o; -wire wbs_ack_o; -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; - -initial begin + // Parameters + parameter DEFAULT_PRESCALE = 1; + parameter FIXED_PRESCALE = 0; + parameter CMD_FIFO = 1; + parameter CMD_FIFO_DEPTH = 32; + parameter WRITE_FIFO = 1; + parameter WRITE_FIFO_DEPTH = 32; + parameter READ_FIFO = 1; + parameter READ_FIFO_DEPTH = 32; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [2:0] wbs_adr_i = 0; + reg [15:0] wbs_dat_i = 0; + reg wbs_we_i = 0; + reg [1:0] wbs_sel_i = 0; + reg wbs_stb_i = 0; + reg wbs_cyc_i = 0; + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + + // Outputs + wire [15:0] wbs_dat_o; + wire wbs_ack_o; + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - wbs_adr_i, - wbs_dat_i, - wbs_we_i, - wbs_sel_i, - wbs_stb_i, - wbs_cyc_i, - i2c_scl_i, - i2c_sda_i - ); - $to_myhdl( - wbs_dat_o, - wbs_ack_o, - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t - ); + $from_myhdl(clk, rst, current_test, wbs_adr_i, wbs_dat_i, wbs_we_i, wbs_sel_i, wbs_stb_i, + wbs_cyc_i, i2c_scl_i, i2c_sda_i); + $to_myhdl(wbs_dat_o, wbs_ack_o, i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t); // dump file $dumpfile("test_i2c_master_wbs_16.lxt"); $dumpvars(0, test_i2c_master_wbs_16); -end - -i2c_master_wbs_16 #( - .DEFAULT_PRESCALE(DEFAULT_PRESCALE), - .FIXED_PRESCALE(FIXED_PRESCALE), - .CMD_FIFO(CMD_FIFO), - .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), - .WRITE_FIFO(WRITE_FIFO), - .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), - .READ_FIFO(READ_FIFO), - .READ_FIFO_DEPTH(READ_FIFO_DEPTH) -) -UUT ( - .clk(clk), - .rst(rst), - .wbs_adr_i(wbs_adr_i), - .wbs_dat_i(wbs_dat_i), - .wbs_dat_o(wbs_dat_o), - .wbs_we_i(wbs_we_i), - .wbs_sel_i(wbs_sel_i), - .wbs_stb_i(wbs_stb_i), - .wbs_ack_o(wbs_ack_o), - .wbs_cyc_i(wbs_cyc_i), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t) -); + end + + i2c_master_wbs_16 #( + .DEFAULT_PRESCALE(DEFAULT_PRESCALE), + .FIXED_PRESCALE(FIXED_PRESCALE), + .CMD_FIFO(CMD_FIFO), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .WRITE_FIFO(WRITE_FIFO), + .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), + .READ_FIFO(READ_FIFO), + .READ_FIFO_DEPTH(READ_FIFO_DEPTH) + ) UUT ( + .clk(clk), + .rst(rst), + .wbs_adr_i(wbs_adr_i), + .wbs_dat_i(wbs_dat_i), + .wbs_dat_o(wbs_dat_o), + .wbs_we_i(wbs_we_i), + .wbs_sel_i(wbs_sel_i), + .wbs_stb_i(wbs_stb_i), + .wbs_ack_o(wbs_ack_o), + .wbs_cyc_i(wbs_cyc_i), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t) + ); endmodule diff --git a/tb/test_i2c_master_wbs_8.v b/tb/test_i2c_master_wbs_8.v index 7eeedbf..12a71f2 100644 --- a/tb/test_i2c_master_wbs_8.v +++ b/tb/test_i2c_master_wbs_8.v @@ -31,91 +31,73 @@ THE SOFTWARE. */ module test_i2c_master_wbs_8; -// Parameters -parameter DEFAULT_PRESCALE = 1; -parameter FIXED_PRESCALE = 0; -parameter CMD_FIFO = 1; -parameter CMD_FIFO_DEPTH = 32; -parameter WRITE_FIFO = 1; -parameter WRITE_FIFO_DEPTH = 32; -parameter READ_FIFO = 1; -parameter READ_FIFO_DEPTH = 32; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg [2:0] wbs_adr_i = 0; -reg [7:0] wbs_dat_i = 0; -reg wbs_we_i = 0; -reg wbs_stb_i = 0; -reg wbs_cyc_i = 0; -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; - -// Outputs -wire [7:0] wbs_dat_o; -wire wbs_ack_o; -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; - -initial begin + // Parameters + parameter DEFAULT_PRESCALE = 1; + parameter FIXED_PRESCALE = 0; + parameter CMD_FIFO = 1; + parameter CMD_FIFO_DEPTH = 32; + parameter WRITE_FIFO = 1; + parameter WRITE_FIFO_DEPTH = 32; + parameter READ_FIFO = 1; + parameter READ_FIFO_DEPTH = 32; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg [2:0] wbs_adr_i = 0; + reg [7:0] wbs_dat_i = 0; + reg wbs_we_i = 0; + reg wbs_stb_i = 0; + reg wbs_cyc_i = 0; + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + + // Outputs + wire [7:0] wbs_dat_o; + wire wbs_ack_o; + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - wbs_adr_i, - wbs_dat_i, - wbs_we_i, - wbs_stb_i, - wbs_cyc_i, - i2c_scl_i, - i2c_sda_i - ); - $to_myhdl( - wbs_dat_o, - wbs_ack_o, - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t - ); + $from_myhdl(clk, rst, current_test, wbs_adr_i, wbs_dat_i, wbs_we_i, wbs_stb_i, wbs_cyc_i, + i2c_scl_i, i2c_sda_i); + $to_myhdl(wbs_dat_o, wbs_ack_o, i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t); // dump file $dumpfile("test_i2c_master_wbs_8.lxt"); $dumpvars(0, test_i2c_master_wbs_8); -end - -i2c_master_wbs_8 #( - .DEFAULT_PRESCALE(DEFAULT_PRESCALE), - .FIXED_PRESCALE(FIXED_PRESCALE), - .CMD_FIFO(CMD_FIFO), - .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), - .WRITE_FIFO(WRITE_FIFO), - .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), - .READ_FIFO(READ_FIFO), - .READ_FIFO_DEPTH(READ_FIFO_DEPTH) -) -UUT ( - .clk(clk), - .rst(rst), - .wbs_adr_i(wbs_adr_i), - .wbs_dat_i(wbs_dat_i), - .wbs_dat_o(wbs_dat_o), - .wbs_we_i(wbs_we_i), - .wbs_stb_i(wbs_stb_i), - .wbs_ack_o(wbs_ack_o), - .wbs_cyc_i(wbs_cyc_i), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t) -); + end + + i2c_master_wbs_8 #( + .DEFAULT_PRESCALE(DEFAULT_PRESCALE), + .FIXED_PRESCALE(FIXED_PRESCALE), + .CMD_FIFO(CMD_FIFO), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .WRITE_FIFO(WRITE_FIFO), + .WRITE_FIFO_DEPTH(WRITE_FIFO_DEPTH), + .READ_FIFO(READ_FIFO), + .READ_FIFO_DEPTH(READ_FIFO_DEPTH) + ) UUT ( + .clk(clk), + .rst(rst), + .wbs_adr_i(wbs_adr_i), + .wbs_dat_i(wbs_dat_i), + .wbs_dat_o(wbs_dat_o), + .wbs_we_i(wbs_we_i), + .wbs_stb_i(wbs_stb_i), + .wbs_ack_o(wbs_ack_o), + .wbs_cyc_i(wbs_cyc_i), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t) + ); endmodule diff --git a/tb/test_i2c_slave.v b/tb/test_i2c_slave.v index 247ab17..4d0c725 100644 --- a/tb/test_i2c_slave.v +++ b/tb/test_i2c_slave.v @@ -31,104 +31,79 @@ THE SOFTWARE. */ module test_i2c_slave; -// Parameters -parameter FILTER_LEN = 2; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg release_bus = 0; -reg [7:0] s_axis_data_tdata = 0; -reg s_axis_data_tvalid = 0; -reg s_axis_data_tlast = 0; -reg m_axis_data_tready = 0; -reg scl_i = 1; -reg sda_i = 1; -reg enable = 0; -reg [6:0] device_address = 0; -reg [6:0] device_address_mask = 0; - -// Outputs -wire s_axis_data_tready; -wire [7:0] m_axis_data_tdata; -wire m_axis_data_tvalid; -wire m_axis_data_tlast; -wire scl_o; -wire scl_t; -wire sda_o; -wire sda_t; -wire busy; -wire [6:0] bus_address; -wire bus_addressed; -wire bus_active; - -initial begin + // Parameters + parameter FILTER_LEN = 2; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg release_bus = 0; + reg [7:0] s_axis_data_tdata = 0; + reg s_axis_data_tvalid = 0; + reg s_axis_data_tlast = 0; + reg m_axis_data_tready = 0; + reg scl_i = 1; + reg sda_i = 1; + reg enable = 0; + reg [6:0] device_address = 0; + reg [6:0] device_address_mask = 0; + + // Outputs + wire s_axis_data_tready; + wire [7:0] m_axis_data_tdata; + wire m_axis_data_tvalid; + wire m_axis_data_tlast; + wire scl_o; + wire scl_t; + wire sda_o; + wire sda_t; + wire busy; + wire [6:0] bus_address; + wire bus_addressed; + wire bus_active; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - release_bus, - s_axis_data_tdata, - s_axis_data_tvalid, - s_axis_data_tlast, - m_axis_data_tready, - scl_i, - sda_i, - enable, - device_address, - device_address_mask - ); - $to_myhdl( - s_axis_data_tready, - m_axis_data_tdata, - m_axis_data_tvalid, - m_axis_data_tlast, - scl_o, - scl_t, - sda_o, - sda_t, - busy, - bus_address, - bus_addressed, - bus_active - ); + $from_myhdl(clk, rst, current_test, release_bus, s_axis_data_tdata, s_axis_data_tvalid, + s_axis_data_tlast, m_axis_data_tready, scl_i, sda_i, enable, device_address, + device_address_mask); + $to_myhdl(s_axis_data_tready, m_axis_data_tdata, m_axis_data_tvalid, m_axis_data_tlast, scl_o, + scl_t, sda_o, sda_t, busy, bus_address, bus_addressed, bus_active); // dump file $dumpfile("test_i2c_slave.lxt"); $dumpvars(0, test_i2c_slave); -end - -i2c_slave #( - .FILTER_LEN(FILTER_LEN) -) -UUT ( - .clk(clk), - .rst(rst), - .release_bus(release_bus), - .s_axis_data_tdata(s_axis_data_tdata), - .s_axis_data_tvalid(s_axis_data_tvalid), - .s_axis_data_tready(s_axis_data_tready), - .s_axis_data_tlast(s_axis_data_tlast), - .m_axis_data_tdata(m_axis_data_tdata), - .m_axis_data_tvalid(m_axis_data_tvalid), - .m_axis_data_tready(m_axis_data_tready), - .m_axis_data_tlast(m_axis_data_tlast), - .scl_i(scl_i), - .scl_o(scl_o), - .scl_t(scl_t), - .sda_i(sda_i), - .sda_o(sda_o), - .sda_t(sda_t), - .busy(busy), - .bus_address(bus_address), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - .enable(enable), - .device_address(device_address), - .device_address_mask(device_address_mask) -); + end + + i2c_slave #( + .FILTER_LEN(FILTER_LEN) + ) UUT ( + .clk(clk), + .rst(rst), + .release_bus(release_bus), + .s_axis_data_tdata(s_axis_data_tdata), + .s_axis_data_tvalid(s_axis_data_tvalid), + .s_axis_data_tready(s_axis_data_tready), + .s_axis_data_tlast(s_axis_data_tlast), + .m_axis_data_tdata(m_axis_data_tdata), + .m_axis_data_tvalid(m_axis_data_tvalid), + .m_axis_data_tready(m_axis_data_tready), + .m_axis_data_tlast(m_axis_data_tlast), + .scl_i(scl_i), + .scl_o(scl_o), + .scl_t(scl_t), + .sda_i(sda_i), + .sda_o(sda_o), + .sda_t(sda_t), + .busy(busy), + .bus_address(bus_address), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + .enable(enable), + .device_address(device_address), + .device_address_mask(device_address_mask) + ); endmodule diff --git a/tb/test_i2c_slave_axil_master.v b/tb/test_i2c_slave_axil_master.v index 73d01a9..7e9e039 100644 --- a/tb/test_i2c_slave_axil_master.v +++ b/tb/test_i2c_slave_axil_master.v @@ -31,134 +31,103 @@ THE SOFTWARE. */ module test_i2c_slave_axil_master; -// Parameters -parameter FILTER_LEN = 4; -parameter DATA_WIDTH = 32; -parameter ADDR_WIDTH = 16; -parameter STRB_WIDTH = (DATA_WIDTH/8); - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; -reg m_axil_awready = 0; -reg m_axil_wready = 0; -reg [1:0] m_axil_bresp = 0; -reg m_axil_bvalid = 0; -reg m_axil_arready = 0; -reg [DATA_WIDTH-1:0] m_axil_rdata = 0; -reg [1:0] m_axil_rresp = 0; -reg m_axil_rvalid = 0; -reg enable = 0; -reg [6:0] device_address = 0; - -// Outputs -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; -wire [ADDR_WIDTH-1:0] m_axil_awaddr; -wire [2:0] m_axil_awprot; -wire m_axil_awvalid; -wire [DATA_WIDTH-1:0] m_axil_wdata; -wire [STRB_WIDTH-1:0] m_axil_wstrb; -wire m_axil_wvalid; -wire m_axil_bready; -wire [ADDR_WIDTH-1:0] m_axil_araddr; -wire [2:0] m_axil_arprot; -wire m_axil_arvalid; -wire m_axil_rready; -wire busy; -wire bus_addressed; -wire bus_active; - -initial begin + // Parameters + parameter FILTER_LEN = 4; + parameter DATA_WIDTH = 32; + parameter ADDR_WIDTH = 16; + parameter STRB_WIDTH = (DATA_WIDTH / 8); + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + reg m_axil_awready = 0; + reg m_axil_wready = 0; + reg [1:0] m_axil_bresp = 0; + reg m_axil_bvalid = 0; + reg m_axil_arready = 0; + reg [DATA_WIDTH-1:0] m_axil_rdata = 0; + reg [1:0] m_axil_rresp = 0; + reg m_axil_rvalid = 0; + reg enable = 0; + reg [6:0] device_address = 0; + + // Outputs + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + wire [ADDR_WIDTH-1:0] m_axil_awaddr; + wire [2:0] m_axil_awprot; + wire m_axil_awvalid; + wire [DATA_WIDTH-1:0] m_axil_wdata; + wire [STRB_WIDTH-1:0] m_axil_wstrb; + wire m_axil_wvalid; + wire m_axil_bready; + wire [ADDR_WIDTH-1:0] m_axil_araddr; + wire [2:0] m_axil_arprot; + wire m_axil_arvalid; + wire m_axil_rready; + wire busy; + wire bus_addressed; + wire bus_active; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - i2c_scl_i, - i2c_sda_i, - m_axil_awready, - m_axil_wready, - m_axil_bresp, - m_axil_bvalid, - m_axil_arready, - m_axil_rdata, - m_axil_rresp, - m_axil_rvalid, - enable, - device_address - ); - $to_myhdl( - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t, - m_axil_awaddr, - m_axil_awprot, - m_axil_awvalid, - m_axil_wdata, - m_axil_wstrb, - m_axil_wvalid, - m_axil_bready, - m_axil_araddr, - m_axil_arprot, - m_axil_arvalid, - m_axil_rready, - busy, - bus_addressed, - bus_active - ); + $from_myhdl(clk, rst, current_test, i2c_scl_i, i2c_sda_i, m_axil_awready, m_axil_wready, + m_axil_bresp, m_axil_bvalid, m_axil_arready, m_axil_rdata, m_axil_rresp, + m_axil_rvalid, enable, device_address); + $to_myhdl(i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t, m_axil_awaddr, m_axil_awprot, + m_axil_awvalid, m_axil_wdata, m_axil_wstrb, m_axil_wvalid, m_axil_bready, + m_axil_araddr, m_axil_arprot, m_axil_arvalid, m_axil_rready, busy, bus_addressed, + bus_active); // dump file $dumpfile("test_i2c_slave_axil_master.lxt"); $dumpvars(0, test_i2c_slave_axil_master); -end - -i2c_slave_axil_master #( - .FILTER_LEN(FILTER_LEN), - .DATA_WIDTH(DATA_WIDTH), - .ADDR_WIDTH(ADDR_WIDTH), - .STRB_WIDTH(STRB_WIDTH) -) -UUT ( - .clk(clk), - .rst(rst), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t), - .m_axil_awaddr(m_axil_awaddr), - .m_axil_awprot(m_axil_awprot), - .m_axil_awvalid(m_axil_awvalid), - .m_axil_awready(m_axil_awready), - .m_axil_wdata(m_axil_wdata), - .m_axil_wstrb(m_axil_wstrb), - .m_axil_wvalid(m_axil_wvalid), - .m_axil_wready(m_axil_wready), - .m_axil_bresp(m_axil_bresp), - .m_axil_bvalid(m_axil_bvalid), - .m_axil_bready(m_axil_bready), - .m_axil_araddr(m_axil_araddr), - .m_axil_arprot(m_axil_arprot), - .m_axil_arvalid(m_axil_arvalid), - .m_axil_arready(m_axil_arready), - .m_axil_rdata(m_axil_rdata), - .m_axil_rresp(m_axil_rresp), - .m_axil_rvalid(m_axil_rvalid), - .m_axil_rready(m_axil_rready), - .busy(busy), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - .enable(enable), - .device_address(device_address) -); + end + + i2c_slave_axil_master #( + .FILTER_LEN(FILTER_LEN), + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH) + ) UUT ( + .clk(clk), + .rst(rst), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t), + .m_axil_awaddr(m_axil_awaddr), + .m_axil_awprot(m_axil_awprot), + .m_axil_awvalid(m_axil_awvalid), + .m_axil_awready(m_axil_awready), + .m_axil_wdata(m_axil_wdata), + .m_axil_wstrb(m_axil_wstrb), + .m_axil_wvalid(m_axil_wvalid), + .m_axil_wready(m_axil_wready), + .m_axil_bresp(m_axil_bresp), + .m_axil_bvalid(m_axil_bvalid), + .m_axil_bready(m_axil_bready), + .m_axil_araddr(m_axil_araddr), + .m_axil_arprot(m_axil_arprot), + .m_axil_arvalid(m_axil_arvalid), + .m_axil_arready(m_axil_arready), + .m_axil_rdata(m_axil_rdata), + .m_axil_rresp(m_axil_rresp), + .m_axil_rvalid(m_axil_rvalid), + .m_axil_rready(m_axil_rready), + .busy(busy), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + .enable(enable), + .device_address(device_address) + ); endmodule diff --git a/tb/test_i2c_slave_wbm.v b/tb/test_i2c_slave_wbm.v index cedbe2b..4cd60a0 100644 --- a/tb/test_i2c_slave_wbm.v +++ b/tb/test_i2c_slave_wbm.v @@ -31,104 +31,80 @@ THE SOFTWARE. */ module test_i2c_slave_wbm; -// Parameters -parameter FILTER_LEN = 4; -parameter WB_DATA_WIDTH = 32; -parameter WB_ADDR_WIDTH = 16; -parameter WB_SELECT_WIDTH = WB_DATA_WIDTH/8; - -// Inputs -reg clk = 0; -reg rst = 0; -reg [7:0] current_test = 0; - -reg i2c_scl_i = 1; -reg i2c_sda_i = 1; -reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0; -reg wb_ack_i = 0; -reg wb_err_i = 0; -reg enable = 0; -reg [6:0] device_address = 0; - -// Outputs -wire i2c_scl_o; -wire i2c_scl_t; -wire i2c_sda_o; -wire i2c_sda_t; -wire [WB_ADDR_WIDTH-1:0] wb_adr_o; -wire [WB_DATA_WIDTH-1:0] wb_dat_o; -wire wb_we_o; -wire [WB_SELECT_WIDTH-1:0] wb_sel_o; -wire wb_stb_o; -wire wb_cyc_o; -wire busy; -wire bus_addressed; -wire bus_active; - -initial begin + // Parameters + parameter FILTER_LEN = 4; + parameter WB_DATA_WIDTH = 32; + parameter WB_ADDR_WIDTH = 16; + parameter WB_SELECT_WIDTH = WB_DATA_WIDTH / 8; + + // Inputs + reg clk = 0; + reg rst = 0; + reg [7:0] current_test = 0; + + reg i2c_scl_i = 1; + reg i2c_sda_i = 1; + reg [WB_DATA_WIDTH-1:0] wb_dat_i = 0; + reg wb_ack_i = 0; + reg wb_err_i = 0; + reg enable = 0; + reg [6:0] device_address = 0; + + // Outputs + wire i2c_scl_o; + wire i2c_scl_t; + wire i2c_sda_o; + wire i2c_sda_t; + wire [WB_ADDR_WIDTH-1:0] wb_adr_o; + wire [WB_DATA_WIDTH-1:0] wb_dat_o; + wire wb_we_o; + wire [WB_SELECT_WIDTH-1:0] wb_sel_o; + wire wb_stb_o; + wire wb_cyc_o; + wire busy; + wire bus_addressed; + wire bus_active; + + initial begin // myhdl integration - $from_myhdl( - clk, - rst, - current_test, - i2c_scl_i, - i2c_sda_i, - wb_dat_i, - wb_ack_i, - wb_err_i, - enable, - device_address - ); - $to_myhdl( - i2c_scl_o, - i2c_scl_t, - i2c_sda_o, - i2c_sda_t, - wb_adr_o, - wb_dat_o, - wb_we_o, - wb_sel_o, - wb_stb_o, - wb_cyc_o, - busy, - bus_addressed, - bus_active - ); + $from_myhdl(clk, rst, current_test, i2c_scl_i, i2c_sda_i, wb_dat_i, wb_ack_i, wb_err_i, enable, + device_address); + $to_myhdl(i2c_scl_o, i2c_scl_t, i2c_sda_o, i2c_sda_t, wb_adr_o, wb_dat_o, wb_we_o, wb_sel_o, + wb_stb_o, wb_cyc_o, busy, bus_addressed, bus_active); // dump file $dumpfile("test_i2c_slave_wbm.lxt"); $dumpvars(0, test_i2c_slave_wbm); -end - -i2c_slave_wbm #( - .FILTER_LEN(FILTER_LEN), - .WB_DATA_WIDTH(WB_DATA_WIDTH), - .WB_ADDR_WIDTH(WB_ADDR_WIDTH), - .WB_SELECT_WIDTH(WB_SELECT_WIDTH) -) -UUT ( - .clk(clk), - .rst(rst), - .i2c_scl_i(i2c_scl_i), - .i2c_scl_o(i2c_scl_o), - .i2c_scl_t(i2c_scl_t), - .i2c_sda_i(i2c_sda_i), - .i2c_sda_o(i2c_sda_o), - .i2c_sda_t(i2c_sda_t), - .wb_adr_o(wb_adr_o), - .wb_dat_i(wb_dat_i), - .wb_dat_o(wb_dat_o), - .wb_we_o(wb_we_o), - .wb_sel_o(wb_sel_o), - .wb_stb_o(wb_stb_o), - .wb_ack_i(wb_ack_i), - .wb_err_i(wb_err_i), - .wb_cyc_o(wb_cyc_o), - .busy(busy), - .bus_addressed(bus_addressed), - .bus_active(bus_active), - .enable(enable), - .device_address(device_address) -); + end + + i2c_slave_wbm #( + .FILTER_LEN(FILTER_LEN), + .WB_DATA_WIDTH(WB_DATA_WIDTH), + .WB_ADDR_WIDTH(WB_ADDR_WIDTH), + .WB_SELECT_WIDTH(WB_SELECT_WIDTH) + ) UUT ( + .clk(clk), + .rst(rst), + .i2c_scl_i(i2c_scl_i), + .i2c_scl_o(i2c_scl_o), + .i2c_scl_t(i2c_scl_t), + .i2c_sda_i(i2c_sda_i), + .i2c_sda_o(i2c_sda_o), + .i2c_sda_t(i2c_sda_t), + .wb_adr_o(wb_adr_o), + .wb_dat_i(wb_dat_i), + .wb_dat_o(wb_dat_o), + .wb_we_o(wb_we_o), + .wb_sel_o(wb_sel_o), + .wb_stb_o(wb_stb_o), + .wb_ack_i(wb_ack_i), + .wb_err_i(wb_err_i), + .wb_cyc_o(wb_cyc_o), + .busy(busy), + .bus_addressed(bus_addressed), + .bus_active(bus_active), + .enable(enable), + .device_address(device_address) + ); endmodule diff --git a/tb/wb.py b/tb/wb.py index b618ef8..515a266 100644 --- a/tb/wb.py +++ b/tb/wb.py @@ -438,4 +438,3 @@ def logic(): print("[%s] Read word a:0x%08x d:%s" % (name, addr, " ".join(("{:02x}".format(c) for c in bytearray(data))))) return instances() -