{"task_id":"spi_controller","description":"SPI Controller with multiple state machine, clock divider, and protocol handling","header":"module spi_controller (\n input clk,\n input rst_n,\n input [7:0] data_in,\n input start,\n input cpol,\n input cpha,\n output reg [7:0] data_out,\n output reg busy,\n output reg spi_clk,\n output reg mosi,\n input miso\n);","module_code":"module spi_controller (\n input clk,\n input rst_n,\n input [7:0] data_in,\n input start,\n input cpol,\n input cpha,\n output reg [7:0] data_out,\n output reg busy,\n output reg spi_clk,\n output reg mosi,\n input miso\n);\n localparam IDLE = 4'd0, CLK_LOW = 4'd1, CLK_HIGH = 4'd2, SAMPLE = 4'd3, SHIFT = 4'd4, STOP = 4'd5, ERROR = 4'd6, PREPARE = 4'd7, TURNAROUND = 4'd8, DUMMY = 4'd9;\n localparam DIV_2 = 3'd0, DIV_4 = 3'd1, DIV_8 = 3'd2, DIV_16 = 3'd3;\n reg [3:0] state, next_state;\n reg [3:0] bit_count;\n reg [2:0] clk_div;\n reg [2:0] div_counter;\n reg internal_clk;\n reg [7:0] shift_reg;\n reg error_flag;\n reg mode_fault;\n\n always @(posedge clk or negedge rst_n) begin\n if (!rst_n) begin\n internal_clk <= 1'b0;\n div_counter <= 3'd0;\n end else if (state == IDLE) begin\n internal_clk <= 1'b0;\n div_counter <= 3'd0;\n end else begin\n if (div_counter >= clk_div) begin\n div_counter <= 3'd0;\n internal_clk <= ~internal_clk;\n end else begin\n div_counter <= div_counter + 1'b1;\n end\n end\n end\n\n always @(*) begin\n next_state = state;\n case (state)\n IDLE: if (start && !busy) next_state = PREPARE;\n PREPARE: next_state = TURNAROUND;\n TURNAROUND: next_state = CLK_LOW;\n CLK_LOW: next_state = (!cpha) ? SAMPLE : SHIFT;\n CLK_HIGH: begin\n if (cpha) next_state = SAMPLE;\n else if (bit_count == 4'd0) next_state = STOP;\n else next_state = CLK_LOW;\n end\n SAMPLE: next_state = (bit_count == 4'd0) ? CLK_HIGH : SHIFT;\n SHIFT: next_state = CLK_HIGH;\n STOP: next_state = DUMMY;\n DUMMY: next_state = IDLE;\n ERROR: next_state = (mode_fault) ? ERROR : IDLE;\n default: next_state = IDLE;\n endcase\n end\n\n always @(posedge clk or negedge rst_n) begin\n if (!rst_n) begin\n state <= IDLE;\n bit_count <= 4'd7;\n shift_reg <= 8'd0;\n data_out <= 8'd0;\n busy <= 1'b0;\n mosi <= 1'b0;\n error_flag <= 1'b0;\n mode_fault <= 1'b0;\n clk_div <= DIV_4;\n end else begin\n state <= next_state;\n case (state)\n IDLE: begin\n busy <= 1'b0;\n bit_count <= 4'd7;\n if (start && !busy) begin busy <= 1'b1; shift_reg <= data_in; end\n end\n PREPARE: begin busy <= 1'b1; mosi <= shift_reg[7]; end\n TURNAROUND: mosi <= 1'b0;\n CLK_LOW: if (cpha == 1'b0) mosi <= shift_reg[7];\n SAMPLE: begin\n if (cpha == 1'b1) mosi <= shift_reg[7];\n shift_reg <= {shift_reg[6:0], miso};\n end\n SHIFT: begin\n shift_reg <= {shift_reg[6:0], miso};\n if (bit_count > 4'd0) bit_count <= bit_count - 1'b1;\n end\n CLK_HIGH: begin\n if (cpha == 1'b0) begin\n shift_reg <= {shift_reg[6:0], miso};\n if (bit_count > 4'd0) bit_count <= bit_count - 1'b1;\n end\n if (error_flag) mode_fault <= 1'b1;\n end\n STOP: begin data_out <= shift_reg; busy <= 1'b0; mosi <= 1'b0; end\n DUMMY: busy <= 1'b0;\n ERROR: busy <= 1'b1;\n endcase\n end\n end\nendmodule","testbench":"`timescale 1ns / 1ps\nmodule tb_spi_controller;\n reg clk, rst_n, start, cpol, cpha, miso;\n reg [7:0] data_in;\n wire [7:0] data_out;\n wire busy, spi_clk, mosi;\n spi_controller dut (.clk(clk), .rst_n(rst_n), .data_in(data_in), .start(start), .cpol(cpol), .cpha(cpha), .data_out(data_out), .busy(busy), .spi_clk(spi_clk), .mosi(mosi), .miso(miso));\n always #5 clk = ~clk;\n initial begin clk=0; rst_n=0; data_in=8'h00; start=0; cpol=0; cpha=0; miso=0; #20 rst_n=1; #10;\n @(posedge clk); data_in=8'hA5; start=1; @(posedge clk); start=0;\n wait(busy==0); #50;\n @(posedge clk); data_in=8'h5A; start=1; cpol=1; cpha=1; @(posedge clk); start=0;\n wait(busy==0); #50;\n @(posedge clk); data_in=8'hFF; start=1; cpol=0; cpha=1; @(posedge clk); start=0;\n wait(busy==0); #100; $finish;\n end\nendmodule","task_number":1} {"task_id":"i2c_controller","description":"I2C Master Controller with FSM, clock stretching, and arbitration","header":"module i2c_master (\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 ack_err,\n inout scl,\n inout sda\n);","module_code":"module i2c_master (\n input clk, input rst_n, input [6:0] addr, input rw, input [7:0] data_in, input start_tx,\n output reg [7:0] data_out, output reg busy, output reg ack_err, inout scl, inout sda\n);\n localparam IDLE=5'd0, START=5'd1, ADDR_W=5'd2, ADDR_R=5'd3, ACK1=5'd4, DATA_WR=5'd5, DATA_RD=5'd6, ACK2=5'd7, NACK=5'd8, STOP=5'd9, ERROR=5'd10, CLOCK_STRETCH=5'd11, ARBITRATION_LOST=5'd12, RESTART=5'd13;\n localparam THIGH=4'd2, TLOW=4'd2;\n reg [4:0] state, next_state;\n reg [3:0] bit_count;\n reg [7:0] tx_shift, rx_shift;\n reg scl_en, sda_en, sda_in, stretch_en;\n reg [3:0] stretch_cnt;\n reg arbitration_lost, first_bit;\n assign scl = scl_en ? 1'b0 : 1'bz;\n assign sda = sda_en ? 1'b0 : 1'bz;\n assign sda_in = sda;\n\n always @(posedge clk or negedge rst_n) begin\n if (!rst_n) begin stretch_cnt <= 4'd0;\n end else if (stretch_en) begin\n if (stretch_cnt >= THIGH) begin stretch_cnt <= 4'd0; stretch_en <= 1'b0; end\n else stretch_cnt <= stretch_cnt + 1'b1;\n end\n end\n\n always @(*) begin\n next_state = state;\n case (state)\n IDLE: if (start_tx && !busy) next_state = START;\n START: next_state = (scl_in==1'b1 && sda_in==1'b0) ? ADDR_W : ERROR;\n ADDR_W: if (bit_count==4'd0) next_state = ACK1;\n ADDR_R: if (bit_count==4'd0) next_state = ACK1;\n ACK1: begin\n if (sda_in==1'b0) next_state = (rw==1'b0) ? DATA_WR : DATA_RD;\n else next_state = (arbitration_lost) ? ARBITRATION_LOST : NACK;\n end\n ACK2: next_state = (sda_in==1'b0) ? DATA_WR : STOP;\n STOP: next_state = (scl_in==1'b1 && sda_in==1'b1) ? IDLE : CLOCK_STRETCH;\n CLOCK_STRETCH: if (scl_in==1'b1) next_state = (sda_in==1'b1) ? IDLE : STOP;\n ERROR: next_state = STOP;\n default: next_state = IDLE;\n endcase\n end\n\n always @(posedge clk or negedge rst_n) begin\n if (!rst_n) begin state<=IDLE; busy<=0; bit_count<=4'd7; tx_shift<=0; rx_shift<=0; data_out<=0; ack_err<=0; scl_en<=0; sda_en<=0; stretch_en<=0; arbitration_lost<=0; first_bit<=1;\n end else begin\n state <= next_state;\n case (state)\n IDLE: begin busy<=0; scl_en<=0; sda_en<=0; ack_err<=0; bit_count<=4'd7; if (start_tx&&!busy) begin busy<=1; tx_shift<={addr,rw}; end end\n START: begin busy<=1; sda_en<=1; tx_shift<={addr,rw}; bit_count<=4'd7; end\n ADDR_W: begin scl_en<=1; sda_en<=1; if(bit_count>0) begin sda_en<=tx_shift[7]; tx_shift<={tx_shift[6:0],1'b0}; bit_count<=bit_count-1; end else begin sda_en<=0; bit_count<=4'd7; end end\n ACK1: sda_en<=0;\n DATA_WR: begin scl_en<=1; sda_en<=1; tx_shift<=data_in; bit_count<=4'd7; end\n DATA_RD: begin scl_en<=1; sda_en<=0; rx_shift<={rx_shift[6:0],sda_in}; if(bit_count>0) bit_count<=bit_count-1; else data_out<={rx_shift[6:0],sda_in}; end\n ACK2: sda_en<=(rw==0)?0:1;\n NACK: sda_en<=1;\n STOP: begin sda_en<=1; scl_en<=1; end\n CLOCK_STRETCH: begin scl_en<=0; stretch_en<=1; end\n endcase\n end\n end\nendmodule","testbench":"`timescale 1ns/1ps\nmodule tb_i2c_master;\n reg clk,rst_n,start_tx,rw; reg[6:0] addr; reg[7:0] data_in;\n wire[7:0] data_out; wire busy,ack_err,scl,sda;\n pullup(sda); pullup(scl);\n i2c_master dut(.clk(clk),.rst_n(rst_n),.addr(addr),.rw(rw),.data_in(data_in),.start_tx(start_tx),.data_out(data_out),.busy(busy),.ack_err(ack_err),.scl(scl),.sda(sda));\n always #5 clk=~clk;\n initial begin clk=0; rst_n=0; addr=7'h50; rw=0; data_in=8'h00; start_tx=0; #20 rst_n=1; #30;\n @(posedge clk); addr=7'h50; rw=0; data_in=8'hA5; start_tx=1; @(posedge clk); start_tx=0;\n wait(busy==0); #100;\n @(posedge clk); addr=7'h50; rw=1; start_tx=1; @(posedge clk); start_tx=0;\n wait(busy==0); #100; $finish;\n end\nendmodule","task_number":2}