rtl:perips:xip: add qspi mode support

Signed-off-by: liangkangnan <liangkangnan@163.com>
verilator
liangkangnan 2023-04-04 11:09:10 +08:00
parent e379fdd445
commit 574474acc8
3 changed files with 186 additions and 72 deletions

View File

@ -23,7 +23,7 @@ module spi_master_transmit (
input logic read_i, // 0: write, 1: read
input logic [1:0] spi_mode_i, // 0: Standard SPI, 1: Dual SPI, 2: Quad SPI, 3: Standard SPI
input logic [1:0] cp_mode_i, // [1]表示CPOL, [0]表示CPHA
input logic [1:0] data_width_i, // 数据宽度, 0: 8bits, 1: 16bits, 2: 32bits, 3: 8bits
input logic [1:0] data_width_i, // 数据宽度, 0: 8bits, 1: 16bits, 2: 24bits, 3: 32bits
input logic [31:0] data_i, // 数据输入
input logic [2:0] div_ratio_i, // 分频比(2 ^ div_ratio_i)
input logic msb_first_i, // 1: MSB, 0: LSB
@ -55,9 +55,15 @@ module spi_master_transmit (
output logic spi_dq3_oe_o
);
// SPI模式
localparam MODE_STAND_SPI = 2'b00;
localparam MODE_DUAL_SPI = 2'b01;
localparam MODE_QUAD_SPI = 2'b10;
// 数据宽度
localparam SPI_DATA_WIDTH_8 = 2'b00;
localparam SPI_DATA_WIDTH_16 = 2'b01;
localparam SPI_DATA_WIDTH_24 = 2'b10;
localparam SPI_DATA_WIDTH_32 = 2'b11;
localparam S_IDLE = 3'b001;
localparam S_DATA = 3'b010;
@ -173,28 +179,34 @@ module spi_master_transmit (
if (edge_cnt_q != 8'd0) begin
case (spi_mode_q)
MODE_STAND_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
out_data_d = {out_data_q[14:0], 1'b0};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
out_data_d = {out_data_q[30:0], 1'b0};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
out_data_d = {out_data_q[22:0], 1'b0};
end else begin
out_data_d = {out_data_q[6:0], 1'b0};
end
end
MODE_DUAL_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
out_data_d = {out_data_q[13:0], 2'b0};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
out_data_d = {out_data_q[29:0], 2'b0};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
out_data_d = {out_data_q[21:0], 2'b0};
end else begin
out_data_d = {out_data_q[5:0], 2'b0};
end
end
MODE_QUAD_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
out_data_d = {out_data_q[11:0], 4'b0};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
out_data_d = {out_data_q[27:0], 4'b0};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
out_data_d = {out_data_q[19:0], 4'b0};
end else begin
out_data_d = {out_data_q[3:0], 4'b0};
end
@ -206,28 +218,34 @@ module spi_master_transmit (
end else begin
case (spi_mode_q)
MODE_STAND_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
in_data_d = {in_data_q[14:0], spi_dq1_i};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
in_data_d = {in_data_q[30:0], spi_dq1_i};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
in_data_d = {in_data_q[22:0], spi_dq1_i};
end else begin
in_data_d = {in_data_q[6:0], spi_dq1_i};
end
end
MODE_DUAL_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
in_data_d = {in_data_q[13:0], spi_dq1_i, spi_dq0_i};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
in_data_d = {in_data_q[29:0], spi_dq1_i, spi_dq0_i};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
in_data_d = {in_data_q[21:0], spi_dq1_i, spi_dq0_i};
end else begin
in_data_d = {in_data_q[5:0], spi_dq1_i, spi_dq0_i};
end
end
MODE_QUAD_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
in_data_d = {in_data_q[11:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
in_data_d = {in_data_q[27:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
in_data_d = {in_data_q[19:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end else begin
in_data_d = {in_data_q[3:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end
@ -241,28 +259,34 @@ module spi_master_transmit (
if (!cp_mode_q[0]) begin
case (spi_mode_q)
MODE_STAND_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
out_data_d = {out_data_q[14:0], 1'b0};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
out_data_d = {out_data_q[30:0], 1'b0};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
out_data_d = {out_data_q[22:0], 1'b0};
end else begin
out_data_d = {out_data_q[6:0], 1'b0};
end
end
MODE_DUAL_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
out_data_d = {out_data_q[13:0], 2'b0};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
out_data_d = {out_data_q[29:0], 2'b0};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
out_data_d = {out_data_q[21:0], 2'b0};
end else begin
out_data_d = {out_data_q[5:0], 2'b0};
end
end
MODE_QUAD_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
out_data_d = {out_data_q[11:0], 4'b0};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
out_data_d = {out_data_q[27:0], 4'b0};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
out_data_d = {out_data_q[19:0], 4'b0};
end else begin
out_data_d = {out_data_q[3:0], 4'b0};
end
@ -273,28 +297,34 @@ module spi_master_transmit (
end else begin
case (spi_mode_q)
MODE_STAND_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
in_data_d = {in_data_q[14:0], spi_dq1_i};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
in_data_d = {in_data_q[30:0], spi_dq1_i};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
in_data_d = {in_data_q[22:0], spi_dq1_i};
end else begin
in_data_d = {in_data_q[6:0], spi_dq1_i};
end
end
MODE_DUAL_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
in_data_d = {in_data_q[13:0], spi_dq1_i, spi_dq0_i};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
in_data_d = {in_data_q[29:0], spi_dq1_i, spi_dq0_i};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
in_data_d = {in_data_q[21:0], spi_dq1_i, spi_dq0_i};
end else begin
in_data_d = {in_data_q[5:0], spi_dq1_i, spi_dq0_i};
end
end
MODE_QUAD_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
in_data_d = {in_data_q[11:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
in_data_d = {in_data_q[27:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
in_data_d = {in_data_q[19:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end else begin
in_data_d = {in_data_q[3:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
end
@ -356,33 +386,40 @@ module spi_master_transmit (
endcase
end
// 沿个数
always_comb begin
total_edge_cnt_d = 8'd63;
case (spi_mode_q)
MODE_STAND_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
total_edge_cnt_d = 8'd31;
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
total_edge_cnt_d = 8'd63;
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
total_edge_cnt_d = 8'd47;
end else begin
total_edge_cnt_d = 8'd15;
end
end
MODE_DUAL_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
total_edge_cnt_d = 8'd15;
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
total_edge_cnt_d = 8'd31;
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
total_edge_cnt_d = 8'd23;
end else begin
total_edge_cnt_d = 8'd7;
end
end
MODE_QUAD_SPI : begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
total_edge_cnt_d = 8'd7;
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
total_edge_cnt_d = 8'd15;
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
total_edge_cnt_d = 8'd11;
end else begin
total_edge_cnt_d = 8'd3;
end
@ -423,6 +460,7 @@ module spi_master_transmit (
end
end
// 输入输出引脚
always_comb begin
spi_dq0_d = 1'b0;
spi_dq1_d = 1'b0;
@ -435,10 +473,12 @@ module spi_master_transmit (
case (spi_mode_q)
MODE_STAND_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
spi_dq0_d = out_data_d[15];
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
spi_dq0_d = out_data_d[31];
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
spi_dq0_d = out_data_d[23];
end else begin
spi_dq0_d = out_data_d[7];
end
@ -446,12 +486,15 @@ module spi_master_transmit (
end
MODE_DUAL_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
spi_dq0_d = out_data_d[14];
spi_dq1_d = out_data_d[15];
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
spi_dq0_d = out_data_d[30];
spi_dq1_d = out_data_d[31];
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
spi_dq0_d = out_data_d[22];
spi_dq1_d = out_data_d[23];
end else begin
spi_dq0_d = out_data_d[6];
spi_dq1_d = out_data_d[7];
@ -466,16 +509,21 @@ module spi_master_transmit (
end
MODE_QUAD_SPI: begin
if (data_width_q == 2'd1) begin
if (data_width_q == SPI_DATA_WIDTH_16) begin
spi_dq0_d = out_data_d[12];
spi_dq1_d = out_data_d[13];
spi_dq2_d = out_data_d[14];
spi_dq3_d = out_data_d[15];
end else if (data_width_q == 2'd2) begin
end else if (data_width_q == SPI_DATA_WIDTH_32) begin
spi_dq0_d = out_data_d[28];
spi_dq1_d = out_data_d[29];
spi_dq2_d = out_data_d[30];
spi_dq3_d = out_data_d[31];
end else if (data_width_q == SPI_DATA_WIDTH_24) begin
spi_dq0_d = out_data_d[20];
spi_dq1_d = out_data_d[21];
spi_dq2_d = out_data_d[22];
spi_dq3_d = out_data_d[23];
end else begin
spi_dq0_d = out_data_d[4];
spi_dq1_d = out_data_d[5];

View File

@ -14,10 +14,7 @@
limitations under the License.
*/
module xip_core #(
parameter int unsigned TX_FIFO_DEPTH = 8,
parameter int unsigned RX_FIFO_DEPTH = 8
)(
module xip_core(
input logic clk_i,
input logic rst_ni,
@ -55,9 +52,10 @@ module xip_core #(
localparam OP_READ = 2'b00;
localparam OP_WRITE = 2'b01;
localparam OP_SECTOR_ERASE = 2'b10;
localparam OP_QUAD_ENABLE = 2'b11;
localparam S_IDLE = 2'b01;
localparam S_WAIT = 2'b10;
localparam S_IDLE = 2'b01;
localparam S_WAIT_VALID = 2'b10;
logic[1:0] state_d, state_q;
logic valid_d, valid_q;
@ -68,9 +66,24 @@ module xip_core #(
logic valid;
// 去掉基地址
assign addr = {9'h0, addr_i[22:0]};
// addr_i[23], 1: 表示擦除扇区; 0: 表示编程数据
assign op = (!we_i) ? OP_READ : addr_i[23] ? OP_SECTOR_ERASE : OP_WRITE;
assign addr = {10'h0, addr_i[21:0]};
// addr_i[23:22], 11使能Quad SPI模式10: 擦除扇区; 00: 编程数据
always_comb begin
op = '0;
if (we_i) begin
if (addr_i[23] & addr_i[22]) begin
op = OP_QUAD_ENABLE;
end else if (addr_i[23]) begin
op = OP_SECTOR_ERASE;
end else begin
op = OP_WRITE;
end
end else begin
op = OP_READ;
end
end
assign gnt_o = (req_i & (state_q == S_IDLE));
assign rvalid_o = valid_q;
@ -85,11 +98,11 @@ module xip_core #(
S_IDLE: begin
valid_d = 1'b0;
if (req_i) begin
state_d = S_WAIT;
state_d = S_WAIT_VALID;
end
end
S_WAIT: begin
S_WAIT_VALID: begin
if (valid) begin
state_d = S_IDLE;
valid_d = 1'b1;

View File

@ -50,7 +50,8 @@ module xip_w25q64_ctrl(
// 数据宽度
localparam SPI_DATA_WIDTH_8 = 2'b00;
localparam SPI_DATA_WIDTH_16 = 2'b01;
localparam SPI_DATA_WIDTH_32 = 2'b10;
localparam SPI_DATA_WIDTH_24 = 2'b10;
localparam SPI_DATA_WIDTH_32 = 2'b11;
// 2分频
localparam SPI_CLK_DIV = 3'd1;
// SPI极性
@ -59,20 +60,25 @@ module xip_w25q64_ctrl(
localparam OP_READ = 2'b00;
localparam OP_WRITE = 2'b01;
localparam OP_SECTOR_ERASE = 2'b10;
localparam OP_QUAD_ENABLE = 2'b11;
localparam STATE_NUM = 12;
localparam S_IDLE = 12'h001;
localparam S_SS_LOW = 12'h002;
localparam S_SS_HIGH = 12'h004;
localparam S_WRITE_ENABLE = 12'h008;
localparam S_WRITE_DISABLE = 12'h010;
localparam S_SECTOR_ERASE = 12'h020;
localparam S_PAGE_PROGRAM = 12'h040;
localparam S_WRITE_DATA = 12'h080;
localparam S_READ_DATA = 12'h100;
localparam S_READ = 12'h200;
localparam S_READ_STATUS = 12'h400;
localparam S_CHECK_WIP = 12'h800;
localparam STATE_NUM = 16;
localparam S_IDLE = 16'h001;
localparam S_SS_LOW = 16'h002;
localparam S_SS_HIGH = 16'h004;
localparam S_WRITE_ENABLE = 16'h008;
localparam S_WRITE_DISABLE = 16'h010;
localparam S_SECTOR_ERASE = 16'h020;
localparam S_PAGE_PROGRAM = 16'h040;
localparam S_WRITE_DATA = 16'h080;
localparam S_READ_DATA = 16'h100;
localparam S_READ32 = 16'h200;
localparam S_READ_STATUS = 16'h400;
localparam S_CHECK_WIP = 16'h800;
localparam S_QUAD_ENABLE = 16'h1000;
localparam S_READ8 = 16'h2000;
localparam S_QUAD_WRITE_ADDR= 16'h4000;
localparam S_READ_DUMMY = 16'h8000;
logic [STATE_NUM-1:0] state_d, state_q;
logic [STATE_NUM-1:0] next_state_d, next_state_q;
@ -119,7 +125,7 @@ module xip_w25q64_ctrl(
op_d = op_i;
wdata_d = wdata_i;
state_d = S_SS_LOW;
if ((op_i == OP_WRITE) | (op_i == OP_SECTOR_ERASE)) begin
if ((op_i == OP_WRITE) | (op_i == OP_SECTOR_ERASE) | (op_i == OP_QUAD_ENABLE)) begin
next_state_d = S_WRITE_ENABLE;
end else begin
next_state_d = S_READ_DATA;
@ -143,8 +149,10 @@ module xip_w25q64_ctrl(
data_d = 8'h06;
if (op_q == OP_SECTOR_ERASE) begin
next_state_d = S_SECTOR_ERASE;
end else begin
end else if (op_q == OP_WRITE) begin
next_state_d = S_PAGE_PROGRAM;
end else begin
next_state_d = S_QUAD_ENABLE;
end
state_d = S_SS_HIGH;
end
@ -162,13 +170,25 @@ module xip_w25q64_ctrl(
end
end
S_QUAD_ENABLE: begin
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b0;
spi_mode_d = MODE_STAND_SPI;
data_width_d = SPI_DATA_WIDTH_24;
data_d = {8'h01, 8'h00, 8'h02};
state_d = S_SS_HIGH;
next_state_d = S_READ_STATUS;
end
end
S_PAGE_PROGRAM: begin
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b0;
spi_mode_d = MODE_STAND_SPI;
data_width_d = SPI_DATA_WIDTH_32;
data_d = {8'h02, addr_q[23:0]};
data_d = {8'h32, addr_q[23:0]};
state_d = S_WRITE_DATA;
end
end
@ -177,7 +197,7 @@ module xip_w25q64_ctrl(
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b0;
spi_mode_d = MODE_STAND_SPI;
spi_mode_d = MODE_QUAD_SPI;
data_width_d = SPI_DATA_WIDTH_32;
data_d = wdata_q;
state_d = S_SS_HIGH;
@ -204,11 +224,21 @@ module xip_w25q64_ctrl(
spi_mode_d = MODE_STAND_SPI;
data_width_d = SPI_DATA_WIDTH_8;
data_d = 8'h05;
state_d = S_READ;
state_d = S_READ8;
next_state_d = S_CHECK_WIP;
end
end
S_READ8: begin
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b1;
spi_mode_d = MODE_STAND_SPI;
data_width_d = SPI_DATA_WIDTH_8;
state_d = S_SS_HIGH;
end
end
S_CHECK_WIP: begin
if (spi_idle) begin
// flash is in WIP
@ -227,18 +257,41 @@ module xip_w25q64_ctrl(
start_d = 1'b1;
read_d = 1'b0;
spi_mode_d = MODE_STAND_SPI;
data_width_d = SPI_DATA_WIDTH_32;
data_d = {8'h03, addr_q[23:0]};
state_d = S_READ;
data_width_d = SPI_DATA_WIDTH_8;
data_d = 8'hEB;
state_d = S_QUAD_WRITE_ADDR;
next_state_d = S_IDLE;
end
end
S_READ: begin
S_QUAD_WRITE_ADDR: begin
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b0;
spi_mode_d = MODE_QUAD_SPI;
data_width_d = SPI_DATA_WIDTH_32;
data_d = {addr_q[23:0], 8'h00};
state_d = S_READ_DUMMY;
next_state_d = S_IDLE;
end
end
S_READ_DUMMY: begin
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b1;
spi_mode_d = MODE_STAND_SPI;
spi_mode_d = MODE_QUAD_SPI;
data_width_d = SPI_DATA_WIDTH_16;
state_d = S_READ32;
next_state_d = S_IDLE;
end
end
S_READ32: begin
if (spi_idle) begin
start_d = 1'b1;
read_d = 1'b1;
spi_mode_d = MODE_QUAD_SPI;
data_width_d = SPI_DATA_WIDTH_32;
state_d = S_SS_HIGH;
end