flash解释:
W25Q128BV-datasheet中文资料 - 夜下青灯 - 博客园
极性的定义
在芯片资料上极性和相位一般表示为CPOL(Clock POLarity)和CPHA(Clock PHAse), 极性和相位组合成4种工作模式。
CPOL CPHA
MODE0 0 0
MODE1 0 1
MODE2 1 0
MODE3 1 1
CPOL: SPI空闲时的时钟信号电平(1:高电平, 0:低电平)
CPHA: SPI在时钟第几个边沿采样(1:第二个边沿开始, 0:第一个边沿开始
MODE0 :时钟默认是0,第0个沿
MODE1 :时钟默认是1,第1个沿
S25fl128L芯片特性
目的实现最高速率133MHz
SDR:在上升沿采样输入数据,在下降沿输出数据。
DDR:command/instruction还是在上升沿采样输入数据,
在command/instruction完成之后的第一个上升沿采样address/rxdata输入数据,
紧接着是下降沿采样输入数据。
在dummy完成后的第一个下降沿输出数据是。
command protocol
command =8bit instruction + address + modifier + latency +data transfer
1-1-1 command protocol: single bit data 传输 instruction+addr+data
之前本计划让时钟一直有效,控制CS#来操作flash,结果发现行不通,因为一个完整的command不允许中途CS#变化。
为什么 instruction是单线传输的?
因为flash需要兼容x1/2/4模式,只能通过 instruction来区分不同模式,
如果 instruction也采用4线模式,那么在x1/x2是无法识别的。
如果 instruction都采用x1,那么兼容x1/2/4都可识别。
Continuous Read Mode是什么?
FPGA在address之后发送 instruction modifer bits,暗示下一个命令与当前命令一样,下一次就不用传输 instruction,只需要传输address+ mode bits;
mode bits 发起或者结束 Continuous Read Mode;
所有的都是MSB高字节先进入flash
时序图
各种命令时序
SDR x1
SDR x4
DDR x1
DDR x4
如何访问寄存器?
通过特定的instruction。
如何访问Security Regions?
Size=1024B ,分成4个regions.如果regions没有保护和锁定,那么可以正常读写。CR1NV[5:2]:LockBits,只能写入一次OTP(OneTimePragram),写入后永久有效。
region2&3可以通过PR(ProtectionRsgister)临时保护不被擦写,操作IRP寄存器[2],当密码正确可以解除保护。
如何访问ID Address Space?
通过RDID Command(9FH)来读取ID值。
什么是SFDP ?如何访问SFDP ?
RSFDP Command (5AH)
SFDP的数据在出厂时就被固定住,无法修改,只供查询使用。厂商识别码等一系列的功能和参数信息
https://blog.csdn.net/bingquan3333/article/details/81872475
https://www.taterli.com/2984/
1-1-1表示什么意思?
数字表示的是使用的线宽,顺序是
instruction-address-data
Single 1-1-1 instruction (SI) + addr (SI) + data (SO )
Dual O 1-1-2 instruction (SI) + addr (SI) + data (IO0&IO1)
Dual IO 1-2-2 ...
Quad O 1-1-4 ...
Quad IO 1-4-4 ...
QPI 4-4-4 ...
Non-volatile寄存器的作用:
1.在上电或者复位flash芯片之后,给volatile寄存器提供初始值。
2.保护bits一次写入
配置寄存器1的内容:
1.设置Security Rigion Lock Bits
2.设置默认Quad
配置寄存器2的内容:
1.QPI模式
2.默认地址长度24|32
需求:
对FLASH进行读写擦除操作。
读操作能否只读单个Byte?
可以读任意1B,读完当前Byte只要CS#没有拉高,不用重新给地址,地址会自动+1,后续数据会持续移出。
read和fastread的区别在于支持的最大的时钟频率不同。
READ
FAST_READ
写操作能否只写单个Byte?
可以
page program 02H
single Byte program必须先WREN使能;
Page Program
写之前是否要擦除?
sector Erase 20H
Half Block Erase 52H
Block Erase D8H
擦除需要时间,FPGA通过查看WIP bit在状态寄存器1 来确定擦除是否完成。1:未完成,0:完成
command summary
具体实现
WREN 06H
WRDI 04H
RDSR 05H
WRSR 01H
RDCMD 03H
F_RD 0BH
PP 02H
PP命令,每次只能连续写入1page 256Byte
SE D8h
BE C7H
DP B9H
RES ABH
RDID 9FH
verilog实现
spi_ctrl.v
//spi_ctrl.v
//0H 发送数据(写)/接收数据(读)
//1H 命令(写)/状态(读)
//2H 地址低(写) add_l
//3H 地址中(写) add_m
//4H 地址高(写) add_h
// 写数据到地址0x40_0000:
// 1.告知FPGA地址:先写40h到4H地址,然后写00h到3H地址,最后写00h到2H地址;
// 2.告知FPGA数据:将要写的数据写入0H地址;
// 3.告知FPGA命令:将写命令告知FPGA;
//拆分成两部分:
//1. 控制数据的产生
//2. 单Byte数据发送
`timescale 1ns/100ps
`define SIM_OPEN 1
module spi_ctrl (
input clk ,
input rst ,
//管脚信号
output spi_clk ,
output spi_csn ,
input spi_din ,
output spi_dout ,
//内部管理口
input m_cs ,
input m_wr ,
input [2:0] m_addr ,
input [7:0] m_din ,
output reg [7:0] m_dout
);
reg [7:0] tx_data0 ;//待发送的数据寄存器
reg [7:0] rx_data0 ;//已接收的数据寄存器
reg [7:0] cmd ;//命令寄存器
reg [7:0] state ;//状态寄存器
reg [7:0] add_h ;//地址高寄存器
reg [7:0] add_m ;//地址中寄存器
reg [7:0] add_l ;//地址低寄存器
//检测到操作
wire rd_data ;
wire wr_data ;
reg wr_data_1d;
wire rd_stata ;
wire wr_cmd ;
wire rd_add_h ;
wire rd_add_m ;
wire rd_add_l ;
wire wr_add_h ;
wire wr_add_m ;
wire wr_add_l ;
reg spi_clk_int ;
wire spi_csn_int ;//由外部控制,因为一次操作不一定只有1B,此处透传
wire spi_din_int ;
reg spi_dout_int ;
// ST:state状态机
reg ST_cs ;//当前1B发送完毕
reg ST_wr ;//当前1B发送完毕
reg [7:0] ST_wdata ;//当前1B发送完毕
wire ST_wrvld ;//当前1B发送完毕
wire [7:0] ST_rdata ;//当前收到的1B有效数据
parameter div_max = 8'd4 ;
reg [2:0] clk_cnt ;
reg clk_en ;//每次分频计数==0的这一拍有效
//判断是什么操作
assign rd_data = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd0})?1'b1 :1'b0 ;
assign wr_data = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd0})?1'b1 :1'b0 ;
assign rd_stata = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd1})?1'b1 :1'b0 ;
assign wr_cmd = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd1})?1'b1 :1'b0 ;
assign rd_add_h = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd2})?1'b1 :1'b0 ;
assign rd_add_m = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd3})?1'b1 :1'b0 ;
assign rd_add_l = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd4})?1'b1 :1'b0 ;
assign wr_add_h = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd2})?1'b1 :1'b0 ;
assign wr_add_m = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd3})?1'b1 :1'b0 ;
assign wr_add_l = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd4})?1'b1 :1'b0 ;
//锁存数据到寄存器
always @(posedge clk or posedge rst)if(rst) tx_data0 <=#1 8'b0;else if(wr_data )tx_data0 <=#1 m_din;
always @(posedge clk or posedge rst)if(rst) cmd <=#1 8'b0;else if(wr_cmd )cmd <=#1 m_din;
always @(posedge clk or posedge rst)if(rst) add_h <=#1 8'b0;else if(wr_add_h)add_h <=#1 m_din;
always @(posedge clk or posedge rst)if(rst) add_m <=#1 8'b0;else if(wr_add_m)add_m <=#1 m_din;
always @(posedge clk or posedge rst)if(rst) add_l <=#1 8'b0;else if(wr_add_l)add_l <=#1 m_din;
always @(posedge clk or posedge rst)if(rst) wr_data_1d <=#1 1'b0;else wr_data_1d <=#1 wr_data;
// 读数据接口
always @(posedge clk or posedge rst)begin
if(rst)
m_dout <=#1 8'b0;
else begin
case({rd_data,rd_stata,rd_add_h,rd_add_m,rd_add_l})
5'b00001: m_dout <=#1 add_l;
5'b00010: m_dout <=#1 add_m;
5'b00100: m_dout <=#1 add_h;
5'b01000: m_dout <=#1 state;
5'b10000: m_dout <=#1 rx_data0;
default : m_dout <=#1 8'b0;
endcase
end
end
parameter NOP = 8'hff;
parameter WREN = 8'h06;//md0
parameter WRDI = 8'h04;//md0
parameter RDSR = 8'h05;//md6
parameter WRSR = 8'h01;//md6
parameter RDCMD = 8'h03;//md7
parameter F_RD = 8'h0B;//md8
parameter PP = 8'h02;//md4
parameter SE = 8'hD8;//md9
parameter BE = 8'hC7;//md0
parameter DP = 8'hB9;//md0
parameter RES = 8'hAB;//md0
parameter RDID = 8'h9F;//md6
wire md0,md1,md2,md3,md4,md5,md6,md7,md8,md9,mdstop;
assign md0 = (cmd==WREN)|(cmd==WRDI)|(cmd==BE)|(cmd==DP)|(cmd==RES) ;
assign md4 = (cmd==PP);
assign md6 = (cmd==RDSR)|(cmd==WRSR)|(cmd==RDID);
assign md7 = (cmd==RDCMD);
assign md8 = (cmd==F_RD);
assign md9 = (cmd==SE);
assign mdstop = (cmd==NOP);
//判断CMD的总体路径:In/out wr 都是fpga 角度
//0. md0 : cmd
//1. md1 : cmd+wdata--nouse
//2. md2 : cmd+addr+wdata--nouse
//3. md3 : cmd+wdata+...--nouse
//4. md4 : cmd+addr+wdata+...
//5. md5 : cmd+rdata--nouse
//6. md6 : cmd+rdata+...
//7. md7 : cmd+addr+rdata+...
//8. md8 : cmd+addr+dummy+rdata+rdata+...
//9. md9 : cmd+addr
//定义设计中使用到的参数
parameter DLY = 1;
`ifdef SIM_OPEN
parameter IDLE = "IDLE ",
SDCMD = "SDCMD ",
SDDATA = "SDDATA ",
SDADDH = "SDADDH ",
SDADDM = "SDADDM ",
SDADDL = "SDADDL ",
SDDMY = "SDDMY ",
RXDATA = "RXDATA ";
reg[127:0] cur_state,next_state,cur_state_1d;
`else
parameter IDLE = 8'b00000000,
SDCMD = 8'b00000001,
SDDATA= 8'b00000010,
SDADDH= 8'b00000100,
SDADDM= 8'b00001000,
SDADDL= 8'b00010000,
SDDMY = 8'b00100000,
RXDATA= 8'b01000000;
reg[7:0] cur_state,next_state,cur_state_1d;
`endif
wire ST_change;
assign ST_change = cur_state_1d != cur_state;
always @(posedge clk) cur_state_1d <= #DLY cur_state;
//第一段状态转移
always@(posedge clk or negedge rst)begin
if(rst == 1'b1)begin
cur_state <= #DLY IDLE;
end else begin
cur_state <= #DLY next_state;
end
end
//第二段产生下一状态 数据流检测序列状态变化
always@(*)begin
if(rst == 1'b1)begin
next_state = IDLE;
end
else begin
case(cur_state)
IDLE:
begin
if(md0|md4|md6|md7|md8|md9)
next_state =SDCMD;
else
next_state = IDLE;
end
SDCMD:
begin
if((md4|md7|md8|md9) &ST_wrvld)
next_state = SDADDH;
else if((md0&ST_wrvld)|mdstop)
next_state = IDLE;
else if(md6&ST_wrvld)
next_state = RXDATA;
else
next_state = SDCMD;
end
SDDATA:
begin
if(mdstop)
next_state = IDLE;
else
next_state = SDDATA;
end
SDADDH:
begin
if(ST_wrvld)
next_state = SDADDM;
else
next_state = SDADDH;
end
SDADDM:
begin
if(ST_wrvld)
next_state =SDADDL;
else
next_state = SDADDM;
end
SDADDL:
begin
if(md8&ST_wrvld)
next_state = SDDMY;
else if(md7 &ST_wrvld)
next_state = RXDATA;
else if(md4 &ST_wrvld)
next_state = SDDATA;
else if(md9 &ST_wrvld)
next_state = IDLE;
else
next_state = SDADDL;
end
SDDMY:
begin
if(ST_wrvld)
next_state = RXDATA;
else
next_state = SDDMY;
end
RXDATA:
begin
if(mdstop)
next_state = IDLE;
else
next_state = RXDATA;
end
default:begin
next_state = IDLE;
end
endcase
end
end
// rx_data0
always @(posedge clk or posedge rst)begin
if(rst)
rx_data0 <=#1 8'b0;
else if( (cur_state==RXDATA) & ST_wrvld)
rx_data0 <=#1 ST_rdata;
end
// ST_wdata
always @(posedge clk or posedge rst)begin
if(rst)
ST_wdata <=#1 8'b0;
else if( cur_state==SDCMD )
ST_wdata <=#1 cmd;
else if( cur_state==SDADDH )
ST_wdata <=#1 add_h;
else if( cur_state==SDADDM )
ST_wdata <=#1 add_m;
else if( cur_state==SDADDL )
ST_wdata <=#1 add_l;
else if( cur_state==SDDATA )
ST_wdata <=#1 tx_data0;
end
// ST_cs
always @(posedge clk or posedge rst)begin
if(rst)
ST_cs <=#1 1'b0;
else if( cur_state==IDLE )
ST_cs <=#1 1'b0;
else if( ST_change )
ST_cs <=#1 1'b1;
else if( (cur_state==SDDATA)&wr_data_1d )
ST_cs <=#1 1'b1;
else if( (cur_state==RXDATA)&rd_data )
ST_cs <=#1 1'b1;
else if( ST_cs==1'b1 )
ST_cs <=#1 1'b0;
end
// SB_wr
always @(posedge clk or posedge rst)begin
if(rst)
ST_wr <=#1 1'b1;
else if( cur_state==RXDATA )
ST_wr <=#1 1'b0;
else
ST_wr <=#1 1'b1;
end
// state
wire busy;
reg SDEmy;//发送空
reg RXFull;//接收有数据
reg WaitData;//等待写入新数据
assign busy = (cur_state==IDLE)?1'b0:1'b1;
// WaitData
always @(posedge clk or posedge rst)begin
if(rst)
WaitData <=#1 1'b0;
else if((cur_state==SDDATA)&ST_wrvld )
WaitData <=#1 1'b1;
else if((cur_state!=SDDATA))
WaitData <=#1 1'b0;
end
// SDEmy
always @(posedge clk or posedge rst)begin
if(rst)
SDEmy <=#1 1'b0;
else if((cur_state==SDDATA)&ST_wrvld )
SDEmy <=#1 1'b1;
else if(wr_data)
SDEmy <=#1 1'b0;
end
// RXFull
always @(posedge clk or posedge rst)begin
if(rst)
RXFull <=#1 1'b0;
else if((cur_state==RXDATA)&ST_wrvld )
RXFull <=#1 1'b1;
else if(rd_data)
RXFull <=#1 1'b0;
end
always @(posedge clk or posedge rst)begin
if(rst)
state <=#1 8'b0;
else
state <=#1 {4'b0,WaitData,RXFull,SDEmy,busy};
end
assign spi_csn_int = (cur_state==IDLE)?1'b1:1'b0;
//通过写入命令触发FPGA发送时序操作FLASH
//--------------单Byte数据发送 Single Byte 简称SB--------------
// 外部输出是SPI
// S25FL128L mode0|3 此代码实现mode0
// FLASH在上升沿采样FPGA发出的数据,--要求:FPGA下降沿改变数据。
// FPGA内部在上升沿采样FLASH发出的数据。
// 内部输入输出
wire SB_cs ;// input 高脉冲
wire SB_wr ;// input
wire[7:0] SB_wdata ;// input
wire[7:0] SB_rdata ;// output
wire SB_wrvld ;// output
reg [7:0] SB_wdata_int ;// 锁存
reg [7:0] SB_rdata_int ;// 锁存
reg [3:0] SB_cnt_bit ;// 关键的计数器,bit计数器 后面全依赖此计数器
reg [7:0] SB_cnt_div ;// 关键的计数器,分频计数器 后面全依赖此计数器
wire SB_cnt_bit_up ;// 用于更新SB_cnt_bit
assign SB_cs = ST_cs ;
assign SB_wr = ST_wr ;
assign SB_wdata = ST_wdata ;
assign ST_wrvld = SB_wrvld ;
assign ST_rdata = SB_rdata ;
assign SB_cnt_bit_up = (SB_cnt_div==div_max);
assign SB_rdata_up = (SB_cnt_div==div_max/2);
assign SB_wrvld = (SB_cnt_div==div_max/2) && (SB_cnt_bit==4'ha);
// SB_wdata_int
always @(posedge clk or posedge rst)begin
if(rst)
SB_wdata_int <=#1 8'b0;
else if(SB_cs)
SB_wdata_int <=#1 SB_wdata;
else if(SB_cnt_bit==4'b1)
SB_wdata_int <=#1 SB_wdata_int;
else if(SB_cnt_bit_up)
SB_wdata_int <=#1 {SB_wdata_int[6:0],1'b0};//MSB
end
// reg[3:0] SB_cnt_bit;// 关键的计数器,后面全依赖此计数器
always @(posedge clk or posedge rst)begin
if(rst)
SB_cnt_bit <=#1 4'b0;
else if(SB_cs==1'b1)
SB_cnt_bit <=#1 4'b1;
else if(SB_cnt_bit==4'b0)
SB_cnt_bit <=#1 4'b0;
else if(SB_cnt_bit==4'ha && SB_cnt_bit_up)
SB_cnt_bit <=#1 4'b0;
else if(SB_cnt_bit_up)
SB_cnt_bit <=#1 SB_cnt_bit+1'b1;
end
// reg [7:0] SB_cnt_div;// 关键的计数器,分频计数器 后面全依赖此计数器
always @(posedge clk or posedge rst)begin
if(rst)
SB_cnt_div <=#1 8'h0;
else if(SB_cs==1'b1)
SB_cnt_div <=#1 8'b1;
else if(SB_cnt_bit_up)
SB_cnt_div <=#1 8'b0;
else if( (SB_cnt_bit<=4'd10) && (SB_cnt_bit!=4'd0) )
SB_cnt_div <=#1 SB_cnt_div+1'b1;
else
SB_cnt_div <=#1 8'b0;
end
// spi_clk_int
always @(posedge clk or posedge rst)begin
if(rst)
spi_clk_int <=#1 1'b0;
else if( (SB_cnt_bit==4'b1) ||(SB_cnt_bit==4'ha) )
spi_clk_int <=#1 1'b0;
else if( (SB_cnt_div==(div_max/2)) | (SB_cnt_div==div_max) )
spi_clk_int <=#1 ~spi_clk_int;
end
// SB_rdata_int
always @(posedge clk or posedge rst)begin
if(rst)
SB_rdata_int <=#1 8'b0;
else if(SB_rdata_up)
SB_rdata_int <=#1 {SB_rdata_int[6:0],spi_din_int};//MSB
end
assign spi_dout_int = SB_wdata_int[7] ;
assign SB_rdata = SB_rdata_int ;
assign spi_clk = spi_clk_int ;
assign spi_csn = spi_csn_int ;
assign spi_din_int = spi_din ;
assign spi_dout = spi_dout_int ;
endmodule
tb.v
`timescale 1ns/100ps
module tb ( );
reg clk =0,rst =1;
always clk =#5 ~clk;
reg m_cs = 0 ;
reg m_wr = 0 ;
reg [2:0] m_addr = 0 ;
reg [7:0] m_din = 0 ;
wire [7:0] m_dout ;
wire spi_clk ;
wire spi_csn ;
wire spi_din ;
wire spi_dout ;
parameter NOP = 8'hff;
parameter WREN = 8'h06;//md0
parameter WRDI = 8'h04;//md0
parameter RDSR = 8'h05;//md6
parameter WRSR = 8'h01;//md6
parameter RDCMD = 8'h03;//md7
parameter F_RD = 8'h0B;//md8
parameter PP = 8'h02;//md4
parameter SE = 8'hD8;//md9
parameter BE = 8'hC7;//md0
parameter DP = 8'hB9;//md0
parameter RES = 8'hAB;//md0
parameter RDID = 8'h9F;//md6
//-------------产生spi_din------------
reg [23:0] rand1=0;
initial begin
while(1) begin
@(negedge spi_clk);
rand1 = {$random} % 100;
end
end
assign spi_din = rand1[0];
reg[7:0] rdata_sim;
reg [7:0] WaitData=8'h80;
reg [31:0] index ;
integer i;
initial begin
rst =1;
#100;
@(posedge clk);#1;
rst =0;
#100;
@(posedge clk);#1;
m_interfasc(1,3'h0,8'haa,rdata_sim);//数据aa
m_interfasc(1,3'h2,8'h01,rdata_sim);//addh
m_interfasc(1,3'h3,8'h02,rdata_sim);//addm
m_interfasc(1,3'h4,8'h03,rdata_sim);//addl
m_interfasc(1,3'h1,PP,rdata_sim);//cmd
// #600;
//pp
for(i=0;i<7;i=1+i) begin
index = 1;
while(index)
begin
#100;
@(posedge clk);#1;
m_interfasc(0,3'h1,8'h00,rdata_sim);//读状态
if(rdata_sim[3:0]==4'b1011)
begin
m_interfasc(1,3'h0,WaitData,rdata_sim);//数据
index = 0;
end
end
WaitData= WaitData>>1;
end
#1000;
m_interfasc(1,3'h1,NOP,rdata_sim);//cmd
#1000;
// F_RD
m_interfasc(1,3'h1,F_RD,rdata_sim);//cmd
for(i=0;i<10;i=1+i) begin
index = 1;
while(index)
begin
#100;
@(posedge clk);#1;
m_interfasc(0,3'h1,8'h00,rdata_sim);//读状态
if(rdata_sim[3:0]==4'b0111)
begin
m_interfasc(0,3'h0,8'h00,rdata_sim);//数据
index = 0;
end
end
end
#1000;
m_interfasc(1,3'h1,NOP,rdata_sim);//cmd
end
spi_ctrl U_spi_ctrl(
.clk (clk ),//input clk ,
.rst (rst ),//input rst ,
.spi_clk (spi_clk ),//output spi_clk ,
.spi_csn (spi_csn ),//output spi_csn ,
.spi_din (spi_din ),//input spi_din ,
.spi_dout (spi_dout ),//output spi_dout ,
.m_cs (m_cs ),//output m_cs ,
.m_wr (m_wr ),//output m_wr ,
.m_addr (m_addr ),//output m_addr ,
.m_din (m_din ),//output m_din ,
.m_dout (m_dout )//output m_dout
);
task m_interfasc;//注意分号; 在第一行“task”语句中不能列出端口名称;
input wr;
input [3:0] addr;
input [7:0] wdata;
output reg[7:0] rdata;
#100;
@(posedge tb.clk);#1;
tb.m_cs = 0 ;
tb.m_wr = 0 ;
tb.m_addr = 0 ;
tb.m_din = 0 ;
@(posedge tb.clk);#1;
tb.m_cs = 1 ;
tb.m_wr = wr ;
tb.m_addr = addr ;
tb.m_din = wdata ;
if(wr==0) begin
@(posedge tb.clk);#3;
rdata = tb.m_dout ;
$display("%h",rdata);
end else rdata = tb.m_dout ;
@(posedge tb.clk);#1;
tb.m_cs = 0 ;
tb.m_wr = 0 ;
tb.m_addr = 0 ;
tb.m_din = 0 ;
endtask
endmodule
runtb.do
quit -sim
cd D:/gaop/SIM/spi_ctrl
vlib work
vmap work work
vlog -novopt -incr -sv -work work "./tb/*.v"
vsim -novopt -t 1ns -L work work.tb
log -r /*
do wave.do
run 100us
#
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb/U_spi_ctrl/clk
add wave -noupdate /tb/U_spi_ctrl/rst
add wave -noupdate /tb/U_spi_ctrl/spi_clk
add wave -noupdate /tb/U_spi_ctrl/spi_csn
add wave -noupdate /tb/U_spi_ctrl/spi_din
add wave -noupdate /tb/U_spi_ctrl/spi_dout
add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_cs
add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_wr
add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_addr
add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_din
add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_dout
add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_cs
add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_wr
add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_wdata
add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_wrvld
add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_rdata
add wave -noupdate /tb/U_spi_ctrl/tx_data0
add wave -noupdate /tb/U_spi_ctrl/rx_data0
add wave -noupdate /tb/U_spi_ctrl/cmd
add wave -noupdate /tb/U_spi_ctrl/add_h
add wave -noupdate /tb/U_spi_ctrl/add_m
add wave -noupdate /tb/U_spi_ctrl/add_l
add wave -noupdate -radix ascii /tb/U_spi_ctrl/cur_state
add wave -noupdate /tb/U_spi_ctrl/ST_change
add wave -noupdate /tb/rdata_sim
add wave -noupdate /tb/U_spi_ctrl/state
add wave -noupdate /tb/U_spi_ctrl/busy
add wave -noupdate /tb/U_spi_ctrl/SDEmy
add wave -noupdate /tb/U_spi_ctrl/RXFull
add wave -noupdate /tb/U_spi_ctrl/WaitData
add wave -noupdate /tb/U_spi_ctrl/rd_stata
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {4052 ns} 0}
quietly wave cursor active 1
configure wave -namecolwidth 176
configure wave -valuecolwidth 102
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ps
update
WaveRestoreZoom {0 ns} {14036 ns}