diff --git a/rtl/perips/xip/spi_master_transmit.sv b/rtl/perips/xip/spi_master_transmit.sv index 99914af..2193e36 100644 --- a/rtl/perips/xip/spi_master_transmit.sv +++ b/rtl/perips/xip/spi_master_transmit.sv @@ -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]; diff --git a/rtl/perips/xip/xip_core.sv b/rtl/perips/xip/xip_core.sv index 8e736e8..5a8d7de 100644 --- a/rtl/perips/xip/xip_core.sv +++ b/rtl/perips/xip/xip_core.sv @@ -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; diff --git a/rtl/perips/xip/xip_w25q64_ctrl.sv b/rtl/perips/xip/xip_w25q64_ctrl.sv index bb6b85e..c1dc1c6 100644 --- a/rtl/perips/xip/xip_w25q64_ctrl.sv +++ b/rtl/perips/xip/xip_w25q64_ctrl.sv @@ -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