123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- `define IO_MAX max(ilog2c(width)-1, 1)
- function reg [7:0] shift_in
- (
- input [7:0] prev,
- input [7:0] in,
- input [1:0] xwidth,
- input [0:0] lsb
- );
- (* full_case *)
- case (xwidth)
- 2'd0:
- shift_in = lsb ? { in[0], prev[7:1] } : { prev[6:0], in[0] };
- 2'd1:
- shift_in = lsb ? { in[1:0], prev[7:2] } : { prev[5:0], in[1:0] };
- 2'd2:
- shift_in = lsb ? { in[3:0], prev[7:4] } : { prev[3:0], in[3:0] };
- 2'd3:
- shift_in = in;
- endcase
- endfunction
- module spi_master
- #(
- parameter width = 1,
- parameter n_cs = 1,
- parameter cs_delay = 1,
- parameter latch_q = 1
- )
- (
- input rst_n,
- input clk,
- input clk_en,
- input [7:0] d,
- output [7:0] q,
- input req,
- input dir,
- input [1:0] iowidth,
- output reg sack,
- output reg eack,
- input idle_io,
- input cpol,
- input lsb,
- input [n_cs-1:0] cs,
- output reg spi_sck,
- inout [`IO_MAX:0] spi_io, // SPI data
- output [n_cs-1:0] spi_cs_n
- );
- localparam io_max = `IO_MAX;
- localparam iowidth_max = ilog2c(width);
- localparam ctr_max = max(ilog2c(cs_delay)-1,2);
- reg spi_active;
- reg [((width > 2) ? 1 : 0):0] spi_width;
- reg [ctr_max:0] spi_ctr;
- reg [n_cs-1:0] spi_cs_q;
- reg [io_max:0] spi_out_q;
- reg [1:0] spi_oe_q;
- reg d_dir;
- reg [7:0] d_out;
- reg [7:0] d_in;
- reg [7:0] q_q;
- assign spi_cs_n = ~spi_cs_q;
- assign q = latch_q ? q_q : d_in;
- wire spi_cs_changed = |(spi_cs_q ^ cs);
-
- wire [1:0] spi_oe = (width > 1) ? spi_oe_q : 2'b10;
- assign spi_io[0] = spi_oe[0] ? spi_out_q[0] : 1'bz;
- assign spi_io[io_max:1] = spi_oe[1] ? spi_out_q[io_max:1] : {io_max{1'bz}};
-
-
- wire [1:0] iowidth_in = (iowidth > iowidth_max) ? 2'bxx : iowidth;
-
- wire [3:0] spi_width_n = 1'b1 << spi_width;
- wire [io_max:0] idle_allio = {(io_max+1){idle_io}};
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- begin
- spi_sck <= 1'b0;
- spi_active <= 1'b0;
- spi_width <= 4'b0001;
- spi_ctr <= 1'b0;
- spi_cs_q <= 1'b0;
- spi_out_q <= idle_allio;
- spi_oe_q <= 2'b10;
- sack <= 1'b0;
- eack <= 1'b0;
- d_out <= idle_allio;
- d_in <= 8'hxx;
- q_q <= 8'hxx;
- end
- else
- begin
-
- sack <= 1'b0;
- eack <= 1'b0;
- if (clk_en)
- begin
- spi_ctr <= spi_ctr - 1'b1;
- spi_sck <= (spi_ctr[0] & spi_active) ^ cpol;
- if (~spi_ctr[0])
- begin
- d_in <= shift_in(d_in, spi_io, spi_width, lsb);
- end
- else
- begin
- spi_out_q <= idle_allio;
- if (spi_active)
- begin
- if (~|spi_ctr[ctr_max:1])
- begin
- eack <= 1'b1;
- q_q <= d_in;
- spi_active <= 1'b0;
- end
- if (spi_width > iowidth_max)
- begin
-
- d_out <= 8'hxx;
- spi_out_q <= {(io_max+1){1'bx}};
- end
- else
- begin
- d_out <= shift_in(d_out, {8{idle_io}},
- spi_width, lsb);
-
- (* full_case *)
- casez ( {spi_width, lsb} )
- 3'b00_0: spi_out_q[1] <= d_out[7];
- 3'b00_1: spi_out_q[1] <= d_out[0];
- 3'b01_0: spi_out_q[1:0] <= d_out[7:6];
- 3'b01_1: spi_out_q[1:0] <= d_out[1:0];
- 3'b10_0: spi_out_q[3:0] <= d_out[7:4];
- 3'b10_1: spi_out_q[3:0] <= d_out[3:0];
- 3'b11_?: spi_out_q <= d_out;
- endcase
- end
- end
- else
- begin
- spi_cs_q <= cs;
- d_out <= d;
- if (cs_delay != 0 &&
- (spi_cs_changed | ~|spi_ctr[ctr_max:1]))
- begin
- if (spi_cs_changed)
- spi_ctr[ctr_max:1] <= cs_delay;
- spi_oe_q <= 2'b10;
- end
- else if (req &&
- (cs_delay == 0 || ~|spi_ctr[ctr_max:1]))
- begin
- if (iowidth <= iowidth_max)
- begin
- spi_width <= iowidth;
- spi_ctr[ctr_max:1] <= 3'd8 >> iowidth;
- spi_oe_q <=
- |iowidth ? {2{dir}} : 2'b10;
- spi_active <= 1'b1;
- sack <= 1'b1;
- end
- else
- begin
-
-
- spi_width <= 2'bxx;
- spi_ctr[ctr_max:1] <= {ctr_max{1'bx}};
- spi_oe_q <= 2'bxx;
- spi_active <= 1'bx;
- sack <= 1'bx;
- end
- end
- end
- end
- end
- end
- endmodule
|