分享我写的一个程序,利用STARTUPE3原语实现读写配置flash,用的是VU3P+S25FL256S flash,有需要的可以参考一下。
`timescale 1ns / 1ps
module top(
input sys_clk,
output led
);
reg rst_n;
wire Read_tx_en;
wire MISO;
wire CS;
wire SCK;
wire MOSI;
wire [31:0] Read_Usr_Addr;
wire [7:0] Read_Usr_Cmd;
wire [7:0] DATA_OUT;
wire Write_tx_en;
wire Write_en;
wire [31:0] Write_Usr_Addr;
wire [7:0] Write_Usr_Cmd;
wire [7:0] Write_Usr_Data;
wire Erase_en;
wire [31:0] Erase_Addr;
wire [7:0] Erase_Cmd;
wire Read_Cmd_Send_Ok;
wire Read_Addr_Send_Ok;
wire Read_Data_Ok;
wire Write_Cmd_Send_Ok;
wire Write_Addr_Send_Ok;
wire Write_Data_Ok;
wire Write_Enable_Ok;
wire Erase_Ok;
//wire sys_clk;
// clk_wiz_0 clk_wiz_0_u
// (
// // Clock out ports
// .clk_out1(sys_clk), // output clk_out1
// // Status and control signals
// .reset(1'b0), // input reset
// .locked(), // output locked
// // Clock in ports
// .clk_in1(clk_100M)
// ); // input clk_in1
vio_0 your_instance_name (
.clk(sys_clk), // input wire clk
.probe_in0(), // input wire [0 : 0] probe_in0
.probe_in1(), // input wire [0 : 0] probe_in1
.probe_in2(), // input wire [0 : 0] probe_in2
.probe_out0(Read_tx_en), // output wire [0 : 0] probe_out0
.probe_out1(Read_Usr_Addr), // output wire [31 : 0] probe_out1
.probe_out2(Read_Usr_Cmd), // output wire [7 : 0] probe_out2
.probe_out3(Write_tx_en), // output wire [0 : 0] probe_out3
.probe_out4(Write_Usr_Addr), // output wire [31 : 0] probe_out4
.probe_out5(Write_Usr_Cmd), // output wire [7 : 0] probe_out5
.probe_out6(Write_Usr_Data), // output wire [7 : 0] probe_out6
.probe_out7(Erase_en), // output wire [0 : 0] probe_out7
.probe_out8(Erase_Addr), // output wire [31 : 0] probe_out8
.probe_out9(Erase_Cmd) // output wire [7 : 0] probe_out9
);
Read_Write_SignalBytes Read_Write_SignalBytes_u(
.sys_clk(sys_clk),
.rst_n(rst_n),
.Read_tx_en(Read_tx_en), //发送使能
.MISO(MISO),
.Read_Usr_Addr(Read_Usr_Addr),
.Read_Usr_Cmd(Read_Usr_Cmd),
.Write_tx_en(Write_tx_en), //发送完 写使能 紧接着就发送地址和数据
.Write_en(Write_en),
.Write_Usr_Addr(Write_Usr_Addr),
.Write_Usr_Cmd(Write_Usr_Cmd),
.Write_Usr_Data(Write_Usr_Data),
.Erase_en(Erase_en),
.Erase_Addr(Erase_Addr),
.Erase_Cmd(Erase_Cmd),
.CS(CS),
.SCK(SCK),
.MOSI(MOSI),
.DATA_OUT(DATA_OUT),
.Read_Cmd_Send_Ok(Read_Cmd_Send_Ok),
.Read_Addr_Send_Ok(Read_Addr_Send_Ok),
.Read_Data_Ok(Read_Data_Ok),
.Write_Cmd_Send_Ok(Write_Cmd_Send_Ok),
.Write_Addr_Send_Ok(Write_Addr_Send_Ok),
.Write_Data_Ok(Write_Data_Ok),
.Write_Enable_Ok(Write_Enable_Ok),
.Erase_Ok(Erase_Ok)
);
STARTUPE3 #(
.PROG_USR("FALSE"),
.SIM_CCLK_FREQ(0.0) // Set the Configuration Clock Frequency (ns) for simulation
)
STARTUPE3_inst (
.CFGCLK(), // 1-bit output: Configuration main clock output
.CFGMCLK(), // 1-bit output: Configuration internal oscillator clock output
.DI({1'b0,1'b0,MISO,1'b0}), // 4-bit output: Allow receiving on the D input pin
.EOS(), // 1-bit output: Active-High output signal indicating the End Of Startup
.PREQ(), // 1-bit output: PROGRAM request to fabric output
.DO({1'b0,1'b0,1'b0,MOSI}), // 4-bit input: Allows control of the D pin output
.DTS(4'b0000), // 4-bit input: Allows tristate of the D pin
.FCSBO(CS), // 1-bit input: Controls the FCS_B pin for flash access
.FCSBTS(0), // 1-bit input: Tristate the FCS_B pin
.GSR(0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port)
.GTS(0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name)
.KEYCLEARB(0), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM)
.PACK(0), // 1-bit input: PROGRAM acknowledge input
.USRCCLKO(SCK), // 1-bit input: User CCLK input
.USRCCLKTS(0), // 1-bit input: User CCLK 3-state enable input
.USRDONEO(), // 1-bit input: User DONE pin output control
.USRDONETS(0) // 1-bit input: User DONE 3-state enable output
);
reg [27:0] cnt;
assign led = (cnt == 28'd100_000_000) ? ~led : led;
always @(posedge sys_clk) begin
if (cnt > 28'd100_000_000) begin
cnt <= 28'd0;
rst_n <= 1'b1;
end
else
cnt <= cnt + 1'b1;
end
(*MARK_DEBUG = "TRUE"*)reg Read_tx_en_ila;
(*MARK_DEBUG = "TRUE"*)reg MISO_ila;
(*MARK_DEBUG = "TRUE"*)reg CS_ila;
(*MARK_DEBUG = "TRUE"*)reg SCK_ila;
(*MARK_DEBUG = "TRUE"*)reg MOSI_ila;
(*MARK_DEBUG = "TRUE"*)reg [31:0] Read_Usr_Addr_ila;
(*MARK_DEBUG = "TRUE"*)reg [7:0] Read_Usr_Cmd_ila;
(*MARK_DEBUG = "TRUE"*)reg [7:0] DATA_OUT_ila;
(*MARK_DEBUG = "TRUE"*)reg Write_tx_en_ila;
(*MARK_DEBUG = "TRUE"*)reg [31:0] Write_Usr_Addr_ila;
(*MARK_DEBUG = "TRUE"*)reg [7:0] Write_Usr_Cmd_ila;
(*MARK_DEBUG = "TRUE"*)reg [7:0] Write_Usr_Data_ila;
(*MARK_DEBUG = "TRUE"*)reg Erase_en_ila;
(*MARK_DEBUG = "TRUE"*)reg [31:0] Erase_Addr_ila;
(*MARK_DEBUG = "TRUE"*)reg [7:0] Erase_Cmd_ila;
(*MARK_DEBUG = "TRUE"*)reg Read_Cmd_Send_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Read_Addr_Send_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Read_Data_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Write_Cmd_Send_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Write_Addr_Send_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Write_Data_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Write_Enable_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg Erase_Ok_ila;
(*MARK_DEBUG = "TRUE"*)reg rst_n_ila;
always @(posedge sys_clk) begin
Read_tx_en_ila <= Read_tx_en;
MISO_ila <= MISO;
CS_ila <= CS;
SCK_ila <= SCK;
MOSI_ila <= MOSI;
Read_Usr_Addr_ila <= Read_Usr_Addr;
Read_Usr_Cmd_ila <= Read_Usr_Cmd;
DATA_OUT_ila <= DATA_OUT;
Write_tx_en_ila <= Write_tx_en;
Write_Usr_Addr_ila <= Write_Usr_Addr;
Write_Usr_Cmd_ila <= Write_Usr_Cmd;
Write_Usr_Data_ila <= Write_Usr_Data;
Erase_en_ila <= Erase_en;
Erase_Addr_ila <= Erase_Addr;
Erase_Cmd_ila <= Erase_Cmd;
Read_Cmd_Send_Ok_ila <= Read_Cmd_Send_Ok;
Read_Addr_Send_Ok_ila <= Read_Addr_Send_Ok;
Read_Data_Ok_ila <= Read_Data_Ok;
Write_Cmd_Send_Ok_ila <= Write_Cmd_Send_Ok;
Write_Addr_Send_Ok_ila <= Write_Addr_Send_Ok;
Write_Data_Ok_ila <= Write_Data_Ok;
Write_Enable_Ok_ila <= Write_Enable_Ok;
Erase_Ok_ila <= Erase_Ok;
rst_n_ila <= rst_n;
end
endmodule
`timescale 1ns / 1ps
module Read_Write_SignalBytes(
input sys_clk,
input rst_n,
input Read_tx_en, //发送使能
input MISO,
input [31:0] Read_Usr_Addr,
input [7:0] Read_Usr_Cmd,
input Write_tx_en,
input Write_en,
input [31:0] Write_Usr_Addr,
input [7:0] Write_Usr_Cmd,
input [7:0] Write_Usr_Data,
input Erase_en,
input [31:0] Erase_Addr,
input [7:0] Erase_Cmd,
output reg CS,
output reg SCK,
output reg MOSI,
output reg [7:0] DATA_OUT,
output reg Read_Cmd_Send_Ok,
output reg Read_Addr_Send_Ok,
output reg Read_Data_Ok,
output reg Write_Cmd_Send_Ok,
output reg Write_Addr_Send_Ok,
output reg Write_Data_Ok,
output reg Write_Enable_Ok,
output reg Erase_enable_Ok,
output reg Erase_Ok
);
// 写数据发送使能
reg [5:0] cnt;
reg Write_tx_en_dly1;
reg Write_tx_en_dly2;
wire Write_tx_en_pos;
reg Write_tx_en_pos_dly;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
Write_tx_en_dly1 <= 1'b0;
Write_tx_en_dly2 <= 1'b0;
end
else begin
{Write_tx_en_dly2, Write_tx_en_dly1} <= {Write_tx_en_dly1, Write_tx_en};
end
end
assign Write_tx_en_pos = ~Write_tx_en_dly2 & Write_tx_en_dly1;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
Write_tx_en_pos_dly <= 1'b0;
end
else begin
Write_tx_en_pos_dly <= Write_tx_en_pos;
end
end
// 写使能 发送使能
reg [7:0] Enable_Data = 8'h06;
reg [1:0] Write_en_dly;
wire Write_en_pos;
reg Write_en_pos_dly;
assign Write_en_pos = ~Write_en_dly[1] & Write_en_dly[0];
always @(posedge sys_clk) begin
Write_en_dly[1:0] <= {Write_en_dly[0],Write_en};
Write_en_pos_dly <= Write_en_pos;
end
// 读数据发送使能
reg tx_en_dly1;
reg tx_en_dly2;
wire tx_en_pos;
reg tx_en_pos_dly;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_en_dly1 <= 1'b0;
tx_en_dly2 <= 1'b0;
end
else begin
{tx_en_dly2, tx_en_dly1} <= {tx_en_dly1, Read_tx_en};
end
end
assign tx_en_pos = ~tx_en_dly2 & tx_en_dly1;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
tx_en_pos_dly <= 1'b0;
end
else begin
tx_en_pos_dly <= tx_en_pos;
end
end
// 擦除使能
reg [1:0] Erase_en_dly;
reg Erase_en_pos_dly;
wire Erase_en_pos;
assign Erase_en_pos = ~Erase_en_dly[1] & Erase_en_dly[0];
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
Erase_en_dly <= 2'd0;
end
else begin
Erase_en_dly[1:0] <= {Erase_en_dly[0], Erase_en};
Erase_en_pos_dly <= Erase_en_pos;
end
end
// 读数据的逻辑
reg [16:0] Current_State = 17'd0;
parameter READY = 17'b0_0000_0000_0000_0000;
parameter READ_CMD = 17'b0_0000_0000_0000_0001;
parameter READ_ADDR = 17'b0_0000_0000_0000_0010;
parameter READ_DATA = 17'b0_0000_0000_0000_0100;
parameter READ_FINISH = 17'b0_0000_0000_0000_1000;
// 写数据得逻辑
parameter WRITE_READY = 17'b0_1000_0000_0000_0000;
parameter WRITE_CMD = 17'b0_0000_0000_0001_0000;
parameter WRITE_ADDR = 17'b0_0000_0000_0010_0000;
parameter WRITE_DATA = 17'b0_0000_0000_0100_0000;
parameter WRITE_FINISH = 17'b0_0000_0000_1000_0000;
// 写使能的逻辑
parameter WRITE_ENABLE = 17'b0_0000_0001_0000_0000;
parameter WRITE_OVER = 17'b0_0000_0010_0000_0000;
// 擦除sector的逻辑
parameter ERASE_ENABLE = 17'b0_0000_0100_0000_0000;
parameter ERASE_OVER = 17'b0_0000_1000_0000_0000;
parameter ERASE_READY = 17'b1_0000_0000_0000_0000;
parameter ERASE_CMD = 17'b0_0001_0000_0000_0000;
parameter ERASE_ADDR = 17'b0_0010_0000_0000_0000;
parameter ERASE_FINISH = 17'b0_0100_0000_0000_0000;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
CS <= 1'b1;
MOSI <= 1'b0;
cnt <= 5'd0;
Current_State <= READY;
Read_Cmd_Send_Ok <= 1'b0;
Read_Addr_Send_Ok <= 1'b0; //发送完成
Read_Data_Ok <= 1'b0;
Write_Cmd_Send_Ok <= 1'b0;
Write_Addr_Send_Ok <= 1'b0;
Write_Data_Ok <= 1'b0;
Write_Enable_Ok <= 1'b0;
Erase_enable_Ok <= 1'b0;
Erase_Ok <= 1'b0;
Enable_Data <= 8'h06;
end
else begin
case (Current_State)
READY:begin
if (tx_en_pos_dly) begin // 读使能
CS <= 1'b0;
MOSI <= Read_Usr_Cmd[7];
Current_State <= READ_CMD;
end
else if (Write_en_pos_dly) begin
CS <= 1'b0;
MOSI <= Enable_Data[7];
Current_State <= WRITE_ENABLE;
end
else if (Write_tx_en_pos_dly) begin //写数据使能
CS <= 1'b0;
MOSI <= Enable_Data[7];
Current_State <= WRITE_ENABLE; //写发送写使能
end
else if (Erase_en_pos_dly) begin //擦除使能
CS <= 1'b0;
MOSI <= Enable_Data[7];
Current_State <= ERASE_ENABLE;
end
else begin
CS <= 1'b1;
Current_State <= READY;
end
end
//擦除数据的逻辑
ERASE_ENABLE: begin
if (cnt <= 5'd6)begin
if (SCK) begin
MOSI <= Enable_Data[6-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Erase_enable_Ok <= 1'b1;
Current_State <= ERASE_OVER;
end
end
ERASE_OVER: begin
CS <= 1'b1;
MOSI <= 1'b0;
Erase_enable_Ok <= 1'b0;
Current_State <= ERASE_READY;
end
ERASE_READY:begin
CS <= 1'b0;
MOSI <= Erase_Cmd[7];
Current_State <= ERASE_CMD;
end
ERASE_CMD:begin
if (cnt <= 5'd6) begin
if (SCK) begin
MOSI <= Erase_Cmd[6-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Current_State <= ERASE_ADDR;
end
end
ERASE_ADDR:begin
if (cnt <= 5'd31) begin
if (SCK) begin
MOSI <= Erase_Addr[31-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Current_State <= ERASE_FINISH;
Erase_Ok <= 1'b1;
end
end
ERASE_FINISH:begin
Erase_Ok <= 1'b0;
CS <= 1'b1;
Current_State <= READY;
MOSI <= 1'b0;
end
// 读数据的逻辑
READ_CMD:begin
if (cnt <= 5'd6) begin
if (SCK) begin
MOSI <= Read_Usr_Cmd[6-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Current_State <= READ_ADDR;
Read_Cmd_Send_Ok <= 1'b1;
end
end
READ_ADDR:begin
Read_Cmd_Send_Ok <= 1'b0;
if (cnt <= 5'd31) begin
if (SCK) begin
MOSI <= Read_Usr_Addr[31-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Read_Addr_Send_Ok <= 1'b1;
Current_State <= READ_DATA;
end
end
READ_DATA:begin
Read_Addr_Send_Ok <= 1'b0;
if (cnt <= 5'd7) begin
if (!SCK) begin
DATA_OUT[7-cnt] <= MISO;
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Current_State <= READ_FINISH;
Read_Data_Ok <= 1'b1;
end
end
READ_FINISH:begin
Read_Data_Ok <= 1'b0;
CS <= 1'b1;
Current_State <= READY;
//SCK <= 1'b0;
MOSI <= 1'b0;
end
// 写 写使能
WRITE_ENABLE:begin
if (cnt <= 5'd6) begin
if (SCK) begin
MOSI <= Enable_Data[6-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
Write_Enable_Ok <= 1'b1;
cnt <= 5'd0;
Current_State <= WRITE_OVER;
end
end
WRITE_OVER:begin
CS <= 1'b1;
MOSI <= 1'b0;
Write_Enable_Ok <= 1'b0;
Current_State <= WRITE_READY;
end
// 写数据的逻辑
WRITE_READY:begin
CS <= 1'b0;
MOSI <= Write_Usr_Cmd[7];
Current_State <= WRITE_CMD;
end
WRITE_CMD:begin
if (cnt <= 5'd6) begin
if (SCK) begin
MOSI <= Write_Usr_Cmd[6-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Current_State <= WRITE_ADDR;
Write_Cmd_Send_Ok <= 1'b1;
end
end
WRITE_ADDR:begin
Write_Cmd_Send_Ok <= 1'b0;
if (cnt <= 5'd31) begin
if (SCK) begin
MOSI <= Write_Usr_Addr[31-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Write_Addr_Send_Ok <= 1'b1;
Current_State <= WRITE_DATA;
end
end
WRITE_DATA:begin
Write_Addr_Send_Ok <= 1'b0;
if (cnt <= 5'd7) begin
if (SCK) begin
MOSI <= Write_Usr_Data[7-cnt];
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
else begin
cnt <= 5'd0;
Current_State <= WRITE_FINISH;
Write_Data_Ok <= 1'b1;
end
end
WRITE_FINISH:begin
Write_Data_Ok <= 1'b0;
CS <= 1'b1;
Current_State <= READY;
//SCK <= 1'b0;
MOSI <= 1'b0;
end
default:begin
CS <= 1'b1;
Current_State <= READY;
SCK <= 1'b0;
MOSI <= 1'b0;
end
endcase
end
end
always @(posedge sys_clk) begin
if (!CS) begin
SCK <= ~SCK;
end
else begin
SCK <= 1'b0;
end
end
endmodule