1 line
4.8 KiB
JSON
1 line
4.8 KiB
JSON
{"task_id": "i2c_controller_simple", "task_number": 2, "description": "Simple I2C-like master controller with 3-state FSM. On start_tx, transfer address+rw and data, signal done when complete.", "header": "module i2c_master_simple (\n input clk,\n input rst_n,\n input [6:0] addr,\n input rw,\n input [7:0] data_in,\n input start_tx,\n output reg [7:0] data_out,\n output reg busy,\n output reg done,\n output reg scl,\n output reg sda\n);", "module_code": "`timescale 1ns/1ps\n\nmodule i2c_master_simple (\n input clk,\n input rst_n,\n input [6:0] addr,\n input rw,\n input [7:0] data_in,\n input start_tx,\n output reg [7:0] data_out,\n output reg busy,\n output reg done,\n output reg scl,\n output reg sda\n);\n localparam IDLE = 2'd0;\n localparam WORK = 2'd1;\n localparam DONE = 2'd2;\n \n reg [1:0] state;\n reg [3:0] wait_cnt;\n \n always @(posedge clk or negedge rst_n) begin\n if (!rst_n) begin\n state <= IDLE;\n busy <= 0;\n done <= 0;\n data_out <= 0;\n scl <= 0;\n sda <= 0;\n wait_cnt <= 0;\n end else begin\n case (state)\n IDLE: begin\n done <= 0;\n scl <= 0;\n sda <= 0;\n wait_cnt <= 0;\n if (start_tx) begin\n busy <= 1;\n data_out <= {addr, rw};\n state <= WORK;\n end else begin\n busy <= 0;\n end\n end\n \n WORK: begin\n busy <= 1;\n scl <= 1;\n sda <= data_out[7];\n data_out <= {data_out[6:0], 1'b0};\n state <= DONE;\n end\n \n DONE: begin\n busy <= 0;\n done <= 1;\n if (wait_cnt >= 3) begin\n state <= IDLE;\n wait_cnt <= 0;\n end else begin\n wait_cnt <= wait_cnt + 1;\n end\n end\n \n default: state <= IDLE;\n endcase\n end\n end\nendmodule\n", "testbench": "`timescale 1ns/1ps\n\nmodule tb_i2c_master_simple;\n reg clk;\n reg rst_n;\n reg [6:0] addr;\n reg rw;\n reg [7:0] data_in;\n reg start_tx;\n\n wire [7:0] data_out;\n wire busy;\n wire done;\n wire scl;\n wire sda;\n\n i2c_master_simple dut (\n .clk(clk),\n .rst_n(rst_n),\n .addr(addr),\n .rw(rw),\n .data_in(data_in),\n .start_tx(start_tx),\n .data_out(data_out),\n .busy(busy),\n .done(done),\n .scl(scl),\n .sda(sda)\n );\n\n always #5 clk = ~clk;\n\n integer errors;\n integer checks;\n\n task reset_dut;\n begin\n rst_n = 0;\n start_tx = 0;\n addr = 0;\n rw = 0;\n data_in = 0;\n repeat (3) @(posedge clk);\n rst_n = 1;\n @(posedge clk);\n end\n endtask\n\n task wait_done;\n integer i;\n begin\n i = 0;\n while (dut.state != 0 && i < 20) begin\n @(posedge clk);\n i = i + 1;\n end\n if (i >= 20) begin\n errors = errors + 1;\n $display(\"TIMEOUT\");\n end\n end\n endtask\n\n task launch_write;\n input [6:0] a;\n input [7:0] d;\n begin\n addr = a;\n data_in = d;\n rw = 0;\n start_tx = 1;\n @(posedge clk);\n start_tx = 0;\n end\n endtask\n\n task launch_read;\n input [6:0] a;\n begin\n addr = a;\n data_in = 0;\n rw = 1;\n start_tx = 1;\n @(posedge clk);\n start_tx = 0;\n end\n endtask\n\n initial begin\n clk = 0;\n errors = 0;\n checks = 0;\n\n reset_dut();\n\n // Test 1: Write\n launch_write(7'h42, 8'hA5);\n wait_done();\n if (done) checks = checks + 1; else errors = errors + 1;\n if (!busy) checks = checks + 1; else errors = errors + 1;\n\n repeat (5) @(posedge clk);\n\n // Test 2: Read\n launch_read(7'h42);\n wait_done();\n if (done) checks = checks + 1; else errors = errors + 1;\n\n if (errors == 0) begin\n $display(\"All %0d checks passed!\", checks);\n end else begin\n $display(\"%0d errors, %0d checks\", errors, checks);\n end\n\n $finish;\n end\n\nendmodule\n"} |