1.摘要:
这里记录一下顶层文件的框架,主要是对命令的控制。具体详情看前面三篇博客记录的内容。
2.FPGA设计
2.1、时序图
具体流程和状态机跳转如下图所示:
注意:这个状态主要是为了这款芯片各个命令的功能,纯验证使用的。感觉验证完之后最简单的框架应该是:上电-复位-写-读,都是用SPI QUAD模式最为简单明了方便,更适合项目使用。

代码如下:
根据spi和qspi两个模块输出的ready的上升沿信号来作为状态机跳转的条件。
wire w_spi_data_ready = w_spi_ready && !r_spi_ready; //SPI/QSPI数据处理完成标志
wire w_qspi_data_ready = w_qspi_ready && !r_qspi_ready ;
always @(*)
begin
if (!rstn_i)
r_fsm_next = 'd0 ;
else begin
case (r_fsm_current)
FSM_PSRAM_IDLE :
r_fsm_next = (w_power_up_flag)?FSM_POWER_UP:FSM_PSRAM_IDLE;//等待200us启动
FSM_POWER_UP :
r_fsm_next = (r_fsm_cnt >= 'd10)?FSM_RSTEN:FSM_POWER_UP ;//增加等待延时
FSM_RSTEN :
r_fsm_next = (w_spi_data_ready)?FSM_RST:FSM_RSTEN ;
FSM_RST :
r_fsm_next = (w_spi_data_ready)?FSM_READ_ID:FSM_RST ;
FSM_READ_ID :
r_fsm_next = (w_spi_data_ready)?FSM_MODE_QPI:FSM_READ_ID ;
FSM_MODE_QPI :
r_fsm_next = (w_spi_data_ready)?FSM_WRITE:FSM_MODE_QPI ;
FSM_WRITE :
r_fsm_next = (w_qspi_data_ready)?FSM_READ:FSM_WRITE ;
FSM_READ :
r_fsm_next = (w_qspi_data_ready)?FSM_MODE_QPI_EXIT:FSM_READ ;
FSM_MODE_QPI_EXIT :
r_fsm_next = (w_qspi_data_ready)?FSM_READ_END:FSM_MODE_QPI_EXIT ;
FSM_READ_END :
r_fsm_next = FSM_RSTEN ;
default :
r_fsm_next = FSM_PSRAM_IDLE ;
endcase
end
end
2.2、写命令/地址/数据
对于写入的命令是预制的,外部接口只能决定读写和地址。对于命令则根据状态机来控制:
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i) begin
r_spi_driver_valin <= 1'b0 ;
r_spi_driver_cmdin <= 'd0 ;
end else if ((r_fsm_current == FSM_RSTEN) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_RESET_ENABLE ;
end else if ((r_fsm_current == FSM_RST) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_RESET ;
end else if ((r_fsm_current == FSM_READ_ID) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_READ_ID ;
end else if ((r_fsm_current == FSM_WRAP_BOUNDARY_TOGGLE) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_WRAP_BOUNDARY_TOGGLE ;
end else if ((r_fsm_current == FSM_MODE_QPI) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_ENTER_QUAD_MODE ;
end else begin
r_spi_driver_valin <= 1'b0 ;
r_spi_driver_cmdin <= r_spi_driver_cmdin ;
end
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i) begin
r_qspi_driver_valin <= 1'b0;
r_qspi_driver_cmdin <= 'd0 ;
end else if ((r_fsm_current == FSM_WRITE) && w_qspi_ready && (r_fsm_cnt == 'd0)) begin
r_qspi_driver_valin <= 1'b1 ;
r_qspi_driver_cmdin <= PSRAM_QUAD_WRITE ;
end else if ((r_fsm_current == FSM_READ) && w_qspi_ready && (r_fsm_cnt == 'd0)) begin
r_qspi_driver_valin <= 1'b1 ;
r_qspi_driver_cmdin <= PSRAM_FAST_READ_QUAD ;
end else if ((r_fsm_current == FSM_MODE_QPI_EXIT) && w_qspi_ready && (r_fsm_cnt == 'd0)) begin
r_qspi_driver_valin <= 1'b1 ;
r_qspi_driver_cmdin <= PSRAM_EXIT_QUAD_MODE ;
end else begin
r_qspi_driver_valin <= 'd0;
r_qspi_driver_cmdin <= r_qspi_driver_cmdin;
end
end
实际效果如下:

如果是写地址和写数据,这个是要由上层模块提供,我这里是自己整个计数器模拟真实数据的。纯属作为测试数据使用。
`timescale 1ns / 1ns
module TOP(
input wire clk_i ,
inout wire QSPI_SI_SIO0 ,
inout wire QSPI_SO_SIO1 ,
inout wire QSPI_SIO2 ,
inout wire QSPI_SIO3 ,
output wire QSPI_CLK ,
output wire QSPI_CS
);
wire w_clk_80m ;
wire w_locked ;
localparam DATA_LEN = 8'd128 ;
(* PAP_MARK_DEBUG="1" *)reg [7:0] cnt ;
reg [7:0] cnt_1d ;
reg [7:0] cnt_2d ;
reg [7:0] cnt_3d ;
reg [23:0] PsRamCtrAddr = 24'h01050F ;
(* PAP_MARK_DEBUG="1" *)reg PsRamCtrWr ;
(* PAP_MARK_DEBUG="1" *)reg [31:0] PsRamCtrWrDat ;
(* PAP_MARK_DEBUG="1" *)wire PsRamCtrBusy ;
reg r_PsRamCtrBusy ;
wire [7:0] PsRamCtrBrust ;
reg [1:0] cnt_4freq ;
reg [1:0] r_cnt_4freq ;
(* PAP_MARK_DEBUG="1" *)reg [2:0] fsm_current ;
reg [2:0] fsm_next ;
//*****************************************************************************************//
clock_rst_n#(
.RST_CNT ('d100 )
)clock_rst_n_inst(
.i_clk (w_clk_80m ),
.o_rst_n (rst_n )
);
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n)
fsm_current <= 'd0 ;
else
fsm_current <= fsm_next ;
end
always @(*) begin
case (fsm_current)
0 :
if (!PsRamCtrBusy && r_PsRamCtrBusy)
fsm_next = 'd1 ;
else
fsm_next = 'd0 ;
1 :
if (cnt == DATA_LEN*4 - 1)
fsm_next = 'd2 ;
else
fsm_next = 'd1 ;
2 :
fsm_next = 'd0 ;
default :
fsm_next = 'd0 ;
endcase
end
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n)
r_PsRamCtrBusy <= 'd0 ;
else
r_PsRamCtrBusy <= PsRamCtrBusy ;
end
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n)
cnt <= 'd0 ;
else if (cnt == DATA_LEN*4 - 1)
cnt <= 'd0 ;
else if (fsm_current == 'd1 && !PsRamCtrBusy)
cnt <= cnt + 'd1 ;
else
cnt <= 'd0 ;
end
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n)
cnt_4freq <= 'd0 ;
else if (cnt_4freq == 2'b11)
cnt_4freq <= 'd0 ;
else if (fsm_current == 'd1 && !PsRamCtrBusy)
cnt_4freq <= cnt_4freq + 'd1 ;
else
cnt_4freq <= 'd0 ;
end
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n)
r_cnt_4freq <= 'd0 ;
else
r_cnt_4freq <= cnt_4freq ;
end
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n) begin
cnt_1d <= 'd0 ;
cnt_2d <= 'd0 ;
cnt_3d <= 'd0 ;
end else begin
cnt_1d <= cnt ;
cnt_2d <= cnt_1d ;
cnt_3d <= cnt_2d ;
end
end
always @(posedge w_clk_80m, negedge rst_n) begin
if (!rst_n) begin
PsRamCtrWrDat <= 'd0 ;
PsRamCtrWr <= 'd0 ;
end else if (cnt_4freq == 2'b11) begin
PsRamCtrWrDat <= {cnt,cnt_1d,cnt_2d,cnt_3d} ;
PsRamCtrWr <= 1'b1 ;
end else begin
PsRamCtrWrDat <= 'd0 ;
PsRamCtrWr <= 'd0 ;
end
end
Clock_Generater Clock_Generater_inst (
.clkin1 (clk_i ),// input
.pll_lock (w_locked ),// output
.clkout0 (w_clk_80m ) // output
);
APS6404L_PSRAM_Driver APS6404L_PSRAM_Driver_inst(
.clk_i (w_clk_80m ), //
.rstn_i (rst_n ),
//QSPI
.QSPI_SI_SIO0 (QSPI_SI_SIO0 ),
.QSPI_SO_SIO1 (QSPI_SO_SIO1 ),
.QSPI_SIO2 (QSPI_SIO2 ),
.QSPI_SIO3 (QSPI_SIO3 ),
.QSPI_CLK (QSPI_CLK ),
.QSPI_CS (QSPI_CS ),
//**********************User port*********************************
//Ctr模块接口
.PsRamCtrCs (PsRamCtrWr ), //
.PsRamCtrWr (PsRamCtrWr ), //Valid
.PsRamCtrRd (1'b1 ), //Valid
.PsRamCtrAddr (PsRamCtrAddr ), //0001:{8'b0,wr_addr},0010:{8'b0,rd_addr},0100:wr_data
.PsRamCtrWrDat (PsRamCtrWrDat ),
.PsRamCtrBrust (DATA_LEN ),
.PsRamCtrBusy (PsRamCtrBusy ), //PSRAM就绪(可写)
.PsRamCtrRdDat (), //{d3,d2,d1,d0}
.PsRamCtrDatValid ()
);
endmodule
然后就没有了,就剩个FIFO缓存模块,没有任何技巧就是存个数据,注意别满别空,深度注意一下就行。
2.3、输出端口
输出端口是inout类型,我这里写的纯属是因为验证两种时序,不属于inout赋值,电路综合出来AND电路了,但是问题不大。
(* PAP_MARK_DEBUG="1" *)wire spi_mosi = (spi_data_flag)?QSPI_SO_SIO1:1'b0;
(* PAP_MARK_DEBUG="1" *)wire w_spi_miso ;
wire w_qspi_si0 = (qspi_rddata_flag)?QSPI_SI_SIO0 :1'b0;
wire w_qspi_si1 = (qspi_rddata_flag)?QSPI_SO_SIO1 :1'b0;
wire w_qspi_si2 = (qspi_rddata_flag)?QSPI_SIO2 :1'b0;
wire w_qspi_si3 = (qspi_rddata_flag)?QSPI_SIO3 :1'b0;
assign QSPI_SI_SIO0 = (spi_cmd_flag | spi_addr_flag)?w_spi_miso:((qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so0:1'bz);
assign QSPI_SO_SIO1 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so1:1'bz;
assign QSPI_SIO2 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so2:1'bz;
assign QSPI_SIO3 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so3:1'bz;
/*************output************************************/
assign QSPI_CLK = w_spi_clk | w_qspi_clk ;
assign QSPI_CS = w_spi_cs & w_qspi_cs ;
assign PsRamCtrBusy = r_busy | w_fifo_wr_ready | r_wrfull_flag ; //w_fifo_wr_ready低有效
assign PsRamCtrRdDat = w_qspi_rddata ;
assign PsRamCtrDatValid = w_qspi_rdval ;
3.顶层源代码
顶层比较简单,没有复杂东西,就是控制命令跳转。
`timescale 1ns/1ns
module APS6404L_PSRAM_Driver(
input wire clk_i , //100M
input wire rstn_i ,
//QSPI
/*synthesis PAP_MARK_DEBUG="1"*/inout wire QSPI_SI_SIO0 ,
/*synthesis PAP_MARK_DEBUG="1"*/inout wire QSPI_SO_SIO1 ,
/*synthesis PAP_MARK_DEBUG="1"*/inout wire QSPI_SIO2 ,
/*synthesis PAP_MARK_DEBUG="1"*/inout wire QSPI_SIO3 ,
/*synthesis PAP_MARK_DEBUG="1"*/output wire QSPI_CLK ,
/*synthesis PAP_MARK_DEBUG="1"*/output wire QSPI_CS ,
//**********************User port*********************************
//Ctr模块接口
input wire PsRamCtrCs , //
input wire PsRamCtrWr , //Valid
input wire PsRamCtrRd , //Valid
input wire [23:0] PsRamCtrAddr , //0001:{8'b0,wr_addr},0010:{8'b0,rd_addr},0100:wr_data
input wire [31:0] PsRamCtrWrDat ,
input wire [7:0] PsRamCtrBrust ,
output wire PsRamCtrBusy , //PSRAM就绪(可写)
output wire [7:0] PsRamCtrRdDat , //
output wire PsRamCtrDatValid
);
localparam PSRAM_READ = 8'h03 ,
PSRAM_FAST_READ = 8'h0B ,
PSRAM_FAST_READ_QUAD = 8'hEB ,
PSRAM_WRITE = 8'h02 ,
PSRAM_QUAD_WRITE = 8'h38 ,
PSRAM_ENTER_QUAD_MODE = 8'h35 ,
PSRAM_EXIT_QUAD_MODE = 8'hF5 ,
PSRAM_RESET_ENABLE = 8'h66 ,
PSRAM_RESET = 8'h99 ,
PSRAM_WRAP_BOUNDARY_TOGGLE = 8'hC0 ,
PSRAM_READ_ID = 8'h9F ,
KGD_ID = 8'h5D ;
parameter FSM_PSRAM_IDLE = 5'd0 ,
FSM_POWER_UP = 5'd1 ,
FSM_RSTEN = 5'd2 ,
FSM_RST = 5'd3 ,
FSM_READ_ID = 5'd4 ,
FSM_WRAP_BOUNDARY_TOGGLE = 5'd5 ,
FSM_MODE_QPI = 5'd6 ,
FSM_WRITE = 5'd7 ,
FSM_READ = 5'd8 ,
FSM_READ_END = 5'd9 ,
FSM_MODE_QPI_EXIT = 5'd10 ;
/*************FSM***************************************/
(* PAP_MARK_DEBUG="1" *)reg [4:0] r_fsm_current ;
reg [4:0] r_fsm_next ;
(* PAP_MARK_DEBUG="1" *)reg [9:0] r_fsm_cnt ;
reg [19:0] r_power_up_cnt ;
/************READ ID************************************/
(* PAP_MARK_DEBUG="1" *)reg r_read_id_KGD ;
/************DATA***************************************/
(* PAP_MARK_DEBUG="1" *)reg r_spi_driver_valin ;
(* PAP_MARK_DEBUG="1" *)reg [7:0] r_spi_driver_cmdin ;
(* PAP_MARK_DEBUG="1" *)reg r_qspi_driver_valin ;
(* PAP_MARK_DEBUG="1" *)reg [7:0] r_qspi_driver_cmdin ;
reg r_spi_ready ;
reg r_qspi_ready ;
(* PAP_MARK_DEBUG="1" *)reg r_busy ;
(* PAP_MARK_DEBUG="1" *)reg [9:0] r_wr_cnt ;
(* PAP_MARK_DEBUG="1" *)reg r_wrfull_flag ;
//*****************************************WIRE*************************************************//
wire spi_cmd_flag ;
wire spi_addr_flag ;
wire spi_data_flag ;
wire spi_wrcmd_8bit = (r_fsm_current == FSM_RSTEN) || (r_fsm_current == FSM_RST)|| (r_fsm_current == FSM_WRAP_BOUNDARY_TOGGLE) || (r_fsm_current == FSM_MODE_QPI);
wire qspi_cmd_flag ;
wire qspi_addr_flag ;
wire qspi_wrdata_flag ;
wire qspi_rddata_flag ;
wire w_qspi_so0 ;
wire w_qspi_so1 ;
wire w_qspi_so2 ;
wire w_qspi_so3 ;
wire exit_qspi_flag = (r_fsm_current == FSM_MODE_QPI_EXIT);
wire qspi_wr_en = (r_fsm_current == FSM_WRITE);
wire qspi_rd_en = (r_fsm_current == FSM_READ);
(* PAP_MARK_DEBUG="1" *)wire w_spi_ready ;
(* PAP_MARK_DEBUG="1" *)wire w_spi_clk ;
(* PAP_MARK_DEBUG="1" *)wire w_spi_cs ;
(* PAP_MARK_DEBUG="1" *)wire w_qspi_ready ;
(* PAP_MARK_DEBUG="1" *)wire w_qspi_clk ;
(* PAP_MARK_DEBUG="1" *)wire w_qspi_cs ;
wire [7:0] w_spi_rddata;
(* PAP_MARK_DEBUG="1" *)wire w_spi_rdval ;
wire [7:0] w_qspi_rddata;
(* PAP_MARK_DEBUG="1" *)wire w_qspi_rdval ;
(* PAP_MARK_DEBUG="1" *)wire w_power_up_flag = (r_power_up_cnt >= 'd20000) ? 1'b1:1'b0 ;
wire w_spi_data_ready = w_spi_ready && !r_spi_ready; //SPI/QSPI数据处理完成标志
wire w_qspi_data_ready = w_qspi_ready && !r_qspi_ready ;
wire w_qspi_wr_requset ;
wire w_fifo_wr_ready ;
wire [7:0] w_qspi_wr_data ;
wire w_qspi_wr_data_val ;
/*************************Decoder CMD&DATA*************************************/
(* PAP_MARK_DEBUG="1" *)wire spi_mosi = (spi_data_flag)?QSPI_SO_SIO1:1'b0;
(* PAP_MARK_DEBUG="1" *)wire w_spi_miso ;
wire w_qspi_si0 = (qspi_rddata_flag)?QSPI_SI_SIO0 :1'b0;
wire w_qspi_si1 = (qspi_rddata_flag)?QSPI_SO_SIO1 :1'b0;
wire w_qspi_si2 = (qspi_rddata_flag)?QSPI_SIO2 :1'b0;
wire w_qspi_si3 = (qspi_rddata_flag)?QSPI_SIO3 :1'b0;
assign QSPI_SI_SIO0 = (spi_cmd_flag | spi_addr_flag)?w_spi_miso:((qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so0:1'bz);
assign QSPI_SO_SIO1 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so1:1'bz;
assign QSPI_SIO2 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so2:1'bz;
assign QSPI_SIO3 = (qspi_cmd_flag | qspi_addr_flag | qspi_wrdata_flag)?w_qspi_so3:1'bz;
/*************output************************************/
assign QSPI_CLK = w_spi_clk | w_qspi_clk ;
assign QSPI_CS = w_spi_cs & w_qspi_cs ;
assign PsRamCtrBusy = r_busy | w_fifo_wr_ready | r_wrfull_flag ; //w_fifo_wr_ready低有效
assign PsRamCtrRdDat = w_qspi_rddata ;
assign PsRamCtrDatValid = w_qspi_rdval ;
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_fsm_current <= 'd0 ;
else
r_fsm_current <= r_fsm_next ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_fsm_cnt <= 'd0 ;
else if (r_fsm_current != r_fsm_next)
r_fsm_cnt <= 'd0 ;
else
r_fsm_cnt <= r_fsm_cnt + 'd1 ;
end
always @(*)
begin
if (!rstn_i)
r_fsm_next = 'd0 ;
else begin
case (r_fsm_current)
FSM_PSRAM_IDLE :
r_fsm_next = (w_power_up_flag)?FSM_POWER_UP:FSM_PSRAM_IDLE;//等待200us启动
FSM_POWER_UP :
r_fsm_next = (r_fsm_cnt >= 'd10)?FSM_RSTEN:FSM_POWER_UP ;//增加等待延时
FSM_RSTEN :
r_fsm_next = (w_spi_data_ready)?FSM_RST:FSM_RSTEN ;
FSM_RST :
r_fsm_next = (w_spi_data_ready)?FSM_READ_ID:FSM_RST ;
FSM_READ_ID :
r_fsm_next = (w_spi_data_ready)?FSM_MODE_QPI:FSM_READ_ID ;
FSM_MODE_QPI :
r_fsm_next = (w_spi_data_ready)?FSM_WRITE:FSM_MODE_QPI ;
FSM_WRITE :
r_fsm_next = (w_qspi_data_ready)?FSM_READ:FSM_WRITE ;
FSM_READ :
r_fsm_next = (w_qspi_data_ready)?FSM_MODE_QPI_EXIT:FSM_READ ;
FSM_MODE_QPI_EXIT :
r_fsm_next = (w_qspi_data_ready)?FSM_READ_END:FSM_MODE_QPI_EXIT ;
FSM_READ_END :
r_fsm_next = FSM_RSTEN ;
default :
r_fsm_next = FSM_PSRAM_IDLE ;
endcase
end
end
//达到稳定VDD至少150us以上
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_power_up_cnt <= 'd0 ;
else if (r_power_up_cnt >= 'd20_000)
r_power_up_cnt <= r_power_up_cnt ;
else
r_power_up_cnt <= r_power_up_cnt + 'd1 ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_read_id_KGD <= 1'b0 ;
else if (r_fsm_current == FSM_RSTEN || r_fsm_current == FSM_RST)
r_read_id_KGD <= 1'b0 ;
else if (w_spi_rdval && (w_spi_rddata == KGD_ID))
r_read_id_KGD <= 'd1 ;
else
r_read_id_KGD <= r_read_id_KGD ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_wr_cnt <= 'd0 ;
else if (!r_busy & !w_fifo_wr_ready & PsRamCtrWr & (r_wr_cnt == PsRamCtrBrust - 1))
r_wr_cnt <= 'd0 ;
else if (!r_busy & !w_fifo_wr_ready & !r_wrfull_flag & PsRamCtrWr)
r_wr_cnt <= r_wr_cnt + 'd1 ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_wrfull_flag <= 'd0 ;
else if (w_spi_rdval && (w_spi_rddata == KGD_ID))
r_wrfull_flag <= 'd0 ;
else if (!r_busy & !w_fifo_wr_ready & PsRamCtrWr & (r_wr_cnt == PsRamCtrBrust - 1))
r_wrfull_flag <= 'd1 ;
else
r_wrfull_flag <= r_wrfull_flag ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_busy <= 'd1 ;
else if (w_spi_rdval && (w_spi_rddata == KGD_ID))
r_busy <= 'd0 ;
else if ((r_fsm_current == FSM_WRITE) & w_qspi_data_ready)
r_busy <= 'd1 ;
else
r_busy <= r_busy ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_spi_ready <= 1'b0 ;
else
r_spi_ready <= w_spi_ready ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i) begin
r_spi_driver_valin <= 1'b0 ;
r_spi_driver_cmdin <= 'd0 ;
end else if ((r_fsm_current == FSM_RSTEN) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_RESET_ENABLE ;
end else if ((r_fsm_current == FSM_RST) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_RESET ;
end else if ((r_fsm_current == FSM_READ_ID) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_READ_ID ;
end else if ((r_fsm_current == FSM_WRAP_BOUNDARY_TOGGLE) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_WRAP_BOUNDARY_TOGGLE ;
end else if ((r_fsm_current == FSM_MODE_QPI) && w_spi_ready && (r_fsm_cnt == 'd0)) begin
r_spi_driver_valin <= 1'b1 ;
r_spi_driver_cmdin <= PSRAM_ENTER_QUAD_MODE ;
end else begin
r_spi_driver_valin <= 1'b0 ;
r_spi_driver_cmdin <= r_spi_driver_cmdin ;
end
end
//**************************************************SPI***********************************************//
spi_drive#(
.P_DATA_WIDTH (8 ),
.P_ADDR_WIDTH (24 ),
.P_CPOL (0 ),
.P_CPHL (0 )
)spi_drive_inst(
.i_clk (clk_i ),
.i_rst (!rstn_i ),
.o_spi_clk (w_spi_clk ),
.o_spi_cs (w_spi_cs ),
.i_spi_mosi (spi_mosi ),
.o_spi_miso (w_spi_miso ),
.i_spi_8bit_cmd (spi_wrcmd_8bit ),
.o_spi_cmd_flag (spi_cmd_flag ),
.o_spi_addr_flag (spi_addr_flag ),
.o_spi_data_flag (spi_data_flag ),
.i_user_cmd (r_spi_driver_cmdin ),
.i_user_addr (24'd0 ),
.i_user_valid (r_spi_driver_valin ),
.o_user_ready (w_spi_ready ),
.o_user_read_data (w_spi_rddata ),
.o_user_read_valid (w_spi_rdval )
);
//**************************************************QSPI***********************************************//
wire fifo_rst = (r_fsm_current == FSM_RSTEN)?1'b1:1'b0 ;
Data_PreProcessing Data_PreProcessing_inst(
.clk_i (clk_i ), //100M
.rstn_i (rstn_i ), //
.PsRamCtrCs (PsRamCtrCs ), //
.PsRamCtrWr (PsRamCtrWr ), //Valid
.PsRamCtrRd (PsRamCtrRd ), //Valid
.PsRamCtrAddr (PsRamCtrAddr ), //0001:{8'b0,wr_addr},0010:{8'b0,rd_addr},0100:wr_data
.PsRamCtrWrDat (PsRamCtrWrDat ),
.PsRamCtrBrust (PsRamCtrBrust - 1 ),
.i_fifo_rst (fifo_rst ),
.i_qspi_wr_req (w_qspi_wr_requset ),
.o_qspi_wr_data (w_qspi_wr_data ),
.o_fifo_wr_ready (w_fifo_wr_ready ), //Active Hign
.o_qspi_wr_val (w_qspi_wr_data_val )
);
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_qspi_ready <= 1'b0 ;
else
r_qspi_ready <= w_qspi_ready ;
end
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i) begin
r_qspi_driver_valin <= 1'b0;
r_qspi_driver_cmdin <= 'd0 ;
end else if ((r_fsm_current == FSM_WRITE) && w_qspi_ready && (r_fsm_cnt == 'd0)) begin
r_qspi_driver_valin <= 1'b1 ;
r_qspi_driver_cmdin <= PSRAM_QUAD_WRITE ;
end else if ((r_fsm_current == FSM_READ) && w_qspi_ready && (r_fsm_cnt == 'd0)) begin
r_qspi_driver_valin <= 1'b1 ;
r_qspi_driver_cmdin <= PSRAM_FAST_READ_QUAD ;
end else if ((r_fsm_current == FSM_MODE_QPI_EXIT) && w_qspi_ready && (r_fsm_cnt == 'd0)) begin
r_qspi_driver_valin <= 1'b1 ;
r_qspi_driver_cmdin <= PSRAM_EXIT_QUAD_MODE ;
end else begin
r_qspi_driver_valin <= 'd0;
r_qspi_driver_cmdin <= r_qspi_driver_cmdin;
end
end
reg [23:0] r_psram_wr_addr ;
always @(posedge clk_i, negedge rstn_i)
begin
if (!rstn_i)
r_psram_wr_addr <= 'd0 ;
else if (PsRamCtrWr)
r_psram_wr_addr <= PsRamCtrAddr ;
end
qspi_drive#(
.P_DATA_WIDTH (8 ),
.P_ADDR_WIDTH (24 ),
.P_CPOL (0 ),
.P_CPHL (0 )
)qspi_drive_inst(
.i_clk (clk_i ),
.i_rst (!rstn_i ),
.o_spi_clk (w_qspi_clk ),
.o_spi_cs (w_qspi_cs ),
.i_qspi_sio0 (w_qspi_si0 ),
.i_qspi_sio1 (w_qspi_si1 ),
.i_qspi_sio2 (w_qspi_si2 ),
.i_qspi_sio3 (w_qspi_si3 ),
.o_qspi_sio0 (w_qspi_so0 ),
.o_qspi_sio1 (w_qspi_so1 ),
.o_qspi_sio2 (w_qspi_so2 ),
.o_qspi_sio3 (w_qspi_so3 ),
.o_qspi_cmd_flag (qspi_cmd_flag ),
.o_qspi_addr_flag (qspi_addr_flag ),
.o_qspi_wrdata_flag (qspi_wrdata_flag ),
.o_qspi_rddata_flag (qspi_rddata_flag ),
.i_fifo_full (w_fifo_wr_ready ),
.i_exit_qpi_mode (exit_qspi_flag ),
.i_qspi_wren (qspi_wr_en ),
.i_qspi_rden (qspi_rd_en ),
.i_write_length (PsRamCtrBrust - 1 ),
.i_read_length (PsRamCtrBrust - 1 ),
.o_wr_requset (w_qspi_wr_requset ),
.i_user_cmd (r_qspi_driver_cmdin ),
.i_user_wr_addr (r_psram_wr_addr ),
.i_user_data (w_qspi_wr_data ),
.i_user_data_val (w_qspi_wr_data_val ),
.i_user_cmd_valid (r_qspi_driver_valin ),
.o_user_ready (w_qspi_ready ),
.o_user_read_data (w_qspi_rddata ),
.o_user_read_valid (w_qspi_rdval )
);
endmodule