module control ( input wire clock, reset, input wire rx_empty, tx_full, input wire [7:0] rx_data, output wire rx_rdreq, tx_wrreq, output wire [7:0] tx_data, output wire bus_wren, output wire [31:0] bus_addr, output wire [15:0] bus_mosi, input wire [15:0] bus_miso, input wire bus_busy, output wire led ); reg [23:0] led_counter; reg int_bus_wren; reg [31:0] int_bus_addr; reg [31:0] int_bus_cntr; reg [15:0] int_bus_mosi; reg int_rdreq, int_wrreq; reg [7:0] int_data; reg int_led; reg [1:0] byte_counter; reg [4:0] idle_counter; reg [4:0] state; reg [31:0] address, counter; reg [15:0] prefix; wire [15:0] dest, data; reg [7:0] buffer [3:0]; assign dest = {buffer[0], buffer[1]}; assign data = {buffer[2], buffer[3]}; always @(posedge clock) begin if (~rx_empty) begin int_led <= 1'b0; led_counter <= 24'd0; end else begin if (&led_counter) begin int_led <= 1'b1; end else begin led_counter <= led_counter + 24'd1; end end case(state) 0: begin int_rdreq <= 1'b1; int_wrreq <= 1'b0; idle_counter <= 5'd0; byte_counter <= 2'd0; state <= 5'd1; end 1: begin // read 4 bytes if (~rx_empty) begin idle_counter <= 5'd0; byte_counter <= byte_counter + 2'd1; buffer[byte_counter] <= rx_data; if (&byte_counter) begin int_rdreq <= 1'b0; state <= 5'd2; end end else if(|byte_counter) begin idle_counter <= idle_counter + 5'd1; if (&idle_counter) begin int_rdreq <= 1'b0; state <= 5'd0; end end end 2: begin case (dest) 16'h0000: begin // reset prefix <= 16'd0; state <= 5'd0; end 16'h0001: begin // prefix register prefix <= data; state <= 5'd0; end 16'h0002: begin // address register address <= {prefix, data}; prefix <= 16'd0; state <= 5'd0; end 16'h0003: begin // counter register counter <= {prefix, data}; prefix <= 16'd0; state <= 5'd0; end 16'h0004: begin // single write int_bus_addr <= address; int_bus_mosi <= data; int_bus_wren <= 1'b1; prefix <= 16'd0; state <= 5'd3; end 16'h0005: begin // multi read int_bus_addr <= address; int_bus_cntr <= counter; int_bus_wren <= 1'b0; prefix <= 16'd0; state <= 5'd4; end default: begin prefix <= 16'd0; state <= 5'd0; end endcase end // single write 3: begin if (~bus_busy) begin int_bus_addr <= 32'd0; int_bus_mosi <= 16'd0; int_bus_wren <= 1'b0; state <= 5'd0; end end // multi read 4: begin if (bus_busy) begin buffer[0] <= 8'd1; buffer[1] <= 8'd0; int_bus_cntr <= 32'd0; state <= 5'd7; end else begin buffer[0] <= 8'd2; buffer[1] <= 8'd0; state <= 5'd6; end end 5: begin buffer[0] <= bus_miso[7:0]; buffer[1] <= bus_miso[15:8]; state <= 5'd6; end 6: begin int_bus_addr <= int_bus_addr + 32'd1; state <= 5'd7; end 7: begin if (~tx_full) begin int_data <= buffer[0]; int_wrreq <= 1'b1; state <= 5'd8; end end 8: begin int_data <= buffer[1]; state <= 5'd9; end 9: begin if (~tx_full) begin int_wrreq <= 1'b0; if (|int_bus_cntr) begin state <= 5'd5; int_bus_cntr <= int_bus_cntr - 32'd1; end else begin state <= 5'd0; end end end default: begin state <= 5'd0; end endcase end assign bus_wren = int_bus_wren; assign bus_addr = int_bus_addr; assign bus_mosi = int_bus_mosi; assign rx_rdreq = int_rdreq & (~rx_empty); assign tx_wrreq = int_wrreq & (~tx_full); assign tx_data = int_data; assign led = int_led; endmodule