当前位置:   article > 正文

【S031】verilog 读写spi flash S25fl128L

s25fl128

SPI4种模式 - fedorayang - 博客园

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

  1. //spi_ctrl.v
  2. //0H 发送数据(写)/接收数据(读)
  3. //1H 命令(写)/状态(读)
  4. //2H 地址低(写) add_l
  5. //3H 地址中(写) add_m
  6. //4H 地址高(写) add_h
  7. // 写数据到地址0x40_0000:
  8. // 1.告知FPGA地址:先写40h到4H地址,然后写00h到3H地址,最后写00h到2H地址;
  9. // 2.告知FPGA数据:将要写的数据写入0H地址;
  10. // 3.告知FPGA命令:将写命令告知FPGA;
  11. //拆分成两部分:
  12. //1. 控制数据的产生
  13. //2. 单Byte数据发送
  14. `timescale 1ns/100ps
  15. `define SIM_OPEN 1
  16. module spi_ctrl (
  17. input clk ,
  18. input rst ,
  19. //管脚信号
  20. output spi_clk ,
  21. output spi_csn ,
  22. input spi_din ,
  23. output spi_dout ,
  24. //内部管理口
  25. input m_cs ,
  26. input m_wr ,
  27. input [2:0] m_addr ,
  28. input [7:0] m_din ,
  29. output reg [7:0] m_dout
  30. );
  31. reg [7:0] tx_data0 ;//待发送的数据寄存器
  32. reg [7:0] rx_data0 ;//已接收的数据寄存器
  33. reg [7:0] cmd ;//命令寄存器
  34. reg [7:0] state ;//状态寄存器
  35. reg [7:0] add_h ;//地址高寄存器
  36. reg [7:0] add_m ;//地址中寄存器
  37. reg [7:0] add_l ;//地址低寄存器
  38. //检测到操作
  39. wire rd_data ;
  40. wire wr_data ;
  41. reg wr_data_1d;
  42. wire rd_stata ;
  43. wire wr_cmd ;
  44. wire rd_add_h ;
  45. wire rd_add_m ;
  46. wire rd_add_l ;
  47. wire wr_add_h ;
  48. wire wr_add_m ;
  49. wire wr_add_l ;
  50. reg spi_clk_int ;
  51. wire spi_csn_int ;//由外部控制,因为一次操作不一定只有1B,此处透传
  52. wire spi_din_int ;
  53. reg spi_dout_int ;
  54. // ST:state状态机
  55. reg ST_cs ;//当前1B发送完毕
  56. reg ST_wr ;//当前1B发送完毕
  57. reg [7:0] ST_wdata ;//当前1B发送完毕
  58. wire ST_wrvld ;//当前1B发送完毕
  59. wire [7:0] ST_rdata ;//当前收到的1B有效数据
  60. parameter div_max = 8'd4 ;
  61. reg [2:0] clk_cnt ;
  62. reg clk_en ;//每次分频计数==0的这一拍有效
  63. //判断是什么操作
  64. assign rd_data = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd0})?1'b1 :1'b0 ;
  65. assign wr_data = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd0})?1'b1 :1'b0 ;
  66. assign rd_stata = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd1})?1'b1 :1'b0 ;
  67. assign wr_cmd = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd1})?1'b1 :1'b0 ;
  68. assign rd_add_h = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd2})?1'b1 :1'b0 ;
  69. assign rd_add_m = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd3})?1'b1 :1'b0 ;
  70. assign rd_add_l = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b0,3'd4})?1'b1 :1'b0 ;
  71. assign wr_add_h = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd2})?1'b1 :1'b0 ;
  72. assign wr_add_m = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd3})?1'b1 :1'b0 ;
  73. assign wr_add_l = ({m_cs,m_wr,m_addr[2:0]} == {1'b1,1'b1,3'd4})?1'b1 :1'b0 ;
  74. //锁存数据到寄存器
  75. always @(posedge clk or posedge rst)if(rst) tx_data0 <=#1 8'b0;else if(wr_data )tx_data0 <=#1 m_din;
  76. always @(posedge clk or posedge rst)if(rst) cmd <=#1 8'b0;else if(wr_cmd )cmd <=#1 m_din;
  77. always @(posedge clk or posedge rst)if(rst) add_h <=#1 8'b0;else if(wr_add_h)add_h <=#1 m_din;
  78. always @(posedge clk or posedge rst)if(rst) add_m <=#1 8'b0;else if(wr_add_m)add_m <=#1 m_din;
  79. always @(posedge clk or posedge rst)if(rst) add_l <=#1 8'b0;else if(wr_add_l)add_l <=#1 m_din;
  80. always @(posedge clk or posedge rst)if(rst) wr_data_1d <=#1 1'b0;else wr_data_1d <=#1 wr_data;
  81. // 读数据接口
  82. always @(posedge clk or posedge rst)begin
  83. if(rst)
  84. m_dout <=#1 8'b0;
  85. else begin
  86. case({rd_data,rd_stata,rd_add_h,rd_add_m,rd_add_l})
  87. 5'b00001: m_dout <=#1 add_l;
  88. 5'b00010: m_dout <=#1 add_m;
  89. 5'b00100: m_dout <=#1 add_h;
  90. 5'b01000: m_dout <=#1 state;
  91. 5'b10000: m_dout <=#1 rx_data0;
  92. default : m_dout <=#1 8'b0;
  93. endcase
  94. end
  95. end
  96. parameter NOP = 8'hff;
  97. parameter WREN = 8'h06;//md0
  98. parameter WRDI = 8'h04;//md0
  99. parameter RDSR = 8'h05;//md6
  100. parameter WRSR = 8'h01;//md6
  101. parameter RDCMD = 8'h03;//md7
  102. parameter F_RD = 8'h0B;//md8
  103. parameter PP = 8'h02;//md4
  104. parameter SE = 8'hD8;//md9
  105. parameter BE = 8'hC7;//md0
  106. parameter DP = 8'hB9;//md0
  107. parameter RES = 8'hAB;//md0
  108. parameter RDID = 8'h9F;//md6
  109. wire md0,md1,md2,md3,md4,md5,md6,md7,md8,md9,mdstop;
  110. assign md0 = (cmd==WREN)|(cmd==WRDI)|(cmd==BE)|(cmd==DP)|(cmd==RES) ;
  111. assign md4 = (cmd==PP);
  112. assign md6 = (cmd==RDSR)|(cmd==WRSR)|(cmd==RDID);
  113. assign md7 = (cmd==RDCMD);
  114. assign md8 = (cmd==F_RD);
  115. assign md9 = (cmd==SE);
  116. assign mdstop = (cmd==NOP);
  117. //判断CMD的总体路径:In/out wr 都是fpga 角度
  118. //0. md0 : cmd
  119. //1. md1 : cmd+wdata--nouse
  120. //2. md2 : cmd+addr+wdata--nouse
  121. //3. md3 : cmd+wdata+...--nouse
  122. //4. md4 : cmd+addr+wdata+...
  123. //5. md5 : cmd+rdata--nouse
  124. //6. md6 : cmd+rdata+...
  125. //7. md7 : cmd+addr+rdata+...
  126. //8. md8 : cmd+addr+dummy+rdata+rdata+...
  127. //9. md9 : cmd+addr
  128. //定义设计中使用到的参数
  129. parameter DLY = 1;
  130. `ifdef SIM_OPEN
  131. parameter IDLE = "IDLE ",
  132. SDCMD = "SDCMD ",
  133. SDDATA = "SDDATA ",
  134. SDADDH = "SDADDH ",
  135. SDADDM = "SDADDM ",
  136. SDADDL = "SDADDL ",
  137. SDDMY = "SDDMY ",
  138. RXDATA = "RXDATA ";
  139. reg[127:0] cur_state,next_state,cur_state_1d;
  140. `else
  141. parameter IDLE = 8'b00000000,
  142. SDCMD = 8'b00000001,
  143. SDDATA= 8'b00000010,
  144. SDADDH= 8'b00000100,
  145. SDADDM= 8'b00001000,
  146. SDADDL= 8'b00010000,
  147. SDDMY = 8'b00100000,
  148. RXDATA= 8'b01000000;
  149. reg[7:0] cur_state,next_state,cur_state_1d;
  150. `endif
  151. wire ST_change;
  152. assign ST_change = cur_state_1d != cur_state;
  153. always @(posedge clk) cur_state_1d <= #DLY cur_state;
  154. //第一段状态转移
  155. always@(posedge clk or negedge rst)begin
  156. if(rst == 1'b1)begin
  157. cur_state <= #DLY IDLE;
  158. end else begin
  159. cur_state <= #DLY next_state;
  160. end
  161. end
  162. //第二段产生下一状态 数据流检测序列状态变化
  163. always@(*)begin
  164. if(rst == 1'b1)begin
  165. next_state = IDLE;
  166. end
  167. else begin
  168. case(cur_state)
  169. IDLE:
  170. begin
  171. if(md0|md4|md6|md7|md8|md9)
  172. next_state =SDCMD;
  173. else
  174. next_state = IDLE;
  175. end
  176. SDCMD:
  177. begin
  178. if((md4|md7|md8|md9) &ST_wrvld)
  179. next_state = SDADDH;
  180. else if((md0&ST_wrvld)|mdstop)
  181. next_state = IDLE;
  182. else if(md6&ST_wrvld)
  183. next_state = RXDATA;
  184. else
  185. next_state = SDCMD;
  186. end
  187. SDDATA:
  188. begin
  189. if(mdstop)
  190. next_state = IDLE;
  191. else
  192. next_state = SDDATA;
  193. end
  194. SDADDH:
  195. begin
  196. if(ST_wrvld)
  197. next_state = SDADDM;
  198. else
  199. next_state = SDADDH;
  200. end
  201. SDADDM:
  202. begin
  203. if(ST_wrvld)
  204. next_state =SDADDL;
  205. else
  206. next_state = SDADDM;
  207. end
  208. SDADDL:
  209. begin
  210. if(md8&ST_wrvld)
  211. next_state = SDDMY;
  212. else if(md7 &ST_wrvld)
  213. next_state = RXDATA;
  214. else if(md4 &ST_wrvld)
  215. next_state = SDDATA;
  216. else if(md9 &ST_wrvld)
  217. next_state = IDLE;
  218. else
  219. next_state = SDADDL;
  220. end
  221. SDDMY:
  222. begin
  223. if(ST_wrvld)
  224. next_state = RXDATA;
  225. else
  226. next_state = SDDMY;
  227. end
  228. RXDATA:
  229. begin
  230. if(mdstop)
  231. next_state = IDLE;
  232. else
  233. next_state = RXDATA;
  234. end
  235. default:begin
  236. next_state = IDLE;
  237. end
  238. endcase
  239. end
  240. end
  241. // rx_data0
  242. always @(posedge clk or posedge rst)begin
  243. if(rst)
  244. rx_data0 <=#1 8'b0;
  245. else if( (cur_state==RXDATA) & ST_wrvld)
  246. rx_data0 <=#1 ST_rdata;
  247. end
  248. // ST_wdata
  249. always @(posedge clk or posedge rst)begin
  250. if(rst)
  251. ST_wdata <=#1 8'b0;
  252. else if( cur_state==SDCMD )
  253. ST_wdata <=#1 cmd;
  254. else if( cur_state==SDADDH )
  255. ST_wdata <=#1 add_h;
  256. else if( cur_state==SDADDM )
  257. ST_wdata <=#1 add_m;
  258. else if( cur_state==SDADDL )
  259. ST_wdata <=#1 add_l;
  260. else if( cur_state==SDDATA )
  261. ST_wdata <=#1 tx_data0;
  262. end
  263. // ST_cs
  264. always @(posedge clk or posedge rst)begin
  265. if(rst)
  266. ST_cs <=#1 1'b0;
  267. else if( cur_state==IDLE )
  268. ST_cs <=#1 1'b0;
  269. else if( ST_change )
  270. ST_cs <=#1 1'b1;
  271. else if( (cur_state==SDDATA)&wr_data_1d )
  272. ST_cs <=#1 1'b1;
  273. else if( (cur_state==RXDATA)&rd_data )
  274. ST_cs <=#1 1'b1;
  275. else if( ST_cs==1'b1 )
  276. ST_cs <=#1 1'b0;
  277. end
  278. // SB_wr
  279. always @(posedge clk or posedge rst)begin
  280. if(rst)
  281. ST_wr <=#1 1'b1;
  282. else if( cur_state==RXDATA )
  283. ST_wr <=#1 1'b0;
  284. else
  285. ST_wr <=#1 1'b1;
  286. end
  287. // state
  288. wire busy;
  289. reg SDEmy;//发送空
  290. reg RXFull;//接收有数据
  291. reg WaitData;//等待写入新数据
  292. assign busy = (cur_state==IDLE)?1'b0:1'b1;
  293. // WaitData
  294. always @(posedge clk or posedge rst)begin
  295. if(rst)
  296. WaitData <=#1 1'b0;
  297. else if((cur_state==SDDATA)&ST_wrvld )
  298. WaitData <=#1 1'b1;
  299. else if((cur_state!=SDDATA))
  300. WaitData <=#1 1'b0;
  301. end
  302. // SDEmy
  303. always @(posedge clk or posedge rst)begin
  304. if(rst)
  305. SDEmy <=#1 1'b0;
  306. else if((cur_state==SDDATA)&ST_wrvld )
  307. SDEmy <=#1 1'b1;
  308. else if(wr_data)
  309. SDEmy <=#1 1'b0;
  310. end
  311. // RXFull
  312. always @(posedge clk or posedge rst)begin
  313. if(rst)
  314. RXFull <=#1 1'b0;
  315. else if((cur_state==RXDATA)&ST_wrvld )
  316. RXFull <=#1 1'b1;
  317. else if(rd_data)
  318. RXFull <=#1 1'b0;
  319. end
  320. always @(posedge clk or posedge rst)begin
  321. if(rst)
  322. state <=#1 8'b0;
  323. else
  324. state <=#1 {4'b0,WaitData,RXFull,SDEmy,busy};
  325. end
  326. assign spi_csn_int = (cur_state==IDLE)?1'b1:1'b0;
  327. //通过写入命令触发FPGA发送时序操作FLASH
  328. //--------------单Byte数据发送 Single Byte 简称SB--------------
  329. // 外部输出是SPI
  330. // S25FL128L mode0|3 此代码实现mode0
  331. // FLASH在上升沿采样FPGA发出的数据,--要求:FPGA下降沿改变数据。
  332. // FPGA内部在上升沿采样FLASH发出的数据。
  333. // 内部输入输出
  334. wire SB_cs ;// input 高脉冲
  335. wire SB_wr ;// input
  336. wire[7:0] SB_wdata ;// input
  337. wire[7:0] SB_rdata ;// output
  338. wire SB_wrvld ;// output
  339. reg [7:0] SB_wdata_int ;// 锁存
  340. reg [7:0] SB_rdata_int ;// 锁存
  341. reg [3:0] SB_cnt_bit ;// 关键的计数器,bit计数器 后面全依赖此计数器
  342. reg [7:0] SB_cnt_div ;// 关键的计数器,分频计数器 后面全依赖此计数器
  343. wire SB_cnt_bit_up ;// 用于更新SB_cnt_bit
  344. assign SB_cs = ST_cs ;
  345. assign SB_wr = ST_wr ;
  346. assign SB_wdata = ST_wdata ;
  347. assign ST_wrvld = SB_wrvld ;
  348. assign ST_rdata = SB_rdata ;
  349. assign SB_cnt_bit_up = (SB_cnt_div==div_max);
  350. assign SB_rdata_up = (SB_cnt_div==div_max/2);
  351. assign SB_wrvld = (SB_cnt_div==div_max/2) && (SB_cnt_bit==4'ha);
  352. // SB_wdata_int
  353. always @(posedge clk or posedge rst)begin
  354. if(rst)
  355. SB_wdata_int <=#1 8'b0;
  356. else if(SB_cs)
  357. SB_wdata_int <=#1 SB_wdata;
  358. else if(SB_cnt_bit==4'b1)
  359. SB_wdata_int <=#1 SB_wdata_int;
  360. else if(SB_cnt_bit_up)
  361. SB_wdata_int <=#1 {SB_wdata_int[6:0],1'b0};//MSB
  362. end
  363. // reg[3:0] SB_cnt_bit;// 关键的计数器,后面全依赖此计数器
  364. always @(posedge clk or posedge rst)begin
  365. if(rst)
  366. SB_cnt_bit <=#1 4'b0;
  367. else if(SB_cs==1'b1)
  368. SB_cnt_bit <=#1 4'b1;
  369. else if(SB_cnt_bit==4'b0)
  370. SB_cnt_bit <=#1 4'b0;
  371. else if(SB_cnt_bit==4'ha && SB_cnt_bit_up)
  372. SB_cnt_bit <=#1 4'b0;
  373. else if(SB_cnt_bit_up)
  374. SB_cnt_bit <=#1 SB_cnt_bit+1'b1;
  375. end
  376. // reg [7:0] SB_cnt_div;// 关键的计数器,分频计数器 后面全依赖此计数器
  377. always @(posedge clk or posedge rst)begin
  378. if(rst)
  379. SB_cnt_div <=#1 8'h0;
  380. else if(SB_cs==1'b1)
  381. SB_cnt_div <=#1 8'b1;
  382. else if(SB_cnt_bit_up)
  383. SB_cnt_div <=#1 8'b0;
  384. else if( (SB_cnt_bit<=4'd10) && (SB_cnt_bit!=4'd0) )
  385. SB_cnt_div <=#1 SB_cnt_div+1'b1;
  386. else
  387. SB_cnt_div <=#1 8'b0;
  388. end
  389. // spi_clk_int
  390. always @(posedge clk or posedge rst)begin
  391. if(rst)
  392. spi_clk_int <=#1 1'b0;
  393. else if( (SB_cnt_bit==4'b1) ||(SB_cnt_bit==4'ha) )
  394. spi_clk_int <=#1 1'b0;
  395. else if( (SB_cnt_div==(div_max/2)) | (SB_cnt_div==div_max) )
  396. spi_clk_int <=#1 ~spi_clk_int;
  397. end
  398. // SB_rdata_int
  399. always @(posedge clk or posedge rst)begin
  400. if(rst)
  401. SB_rdata_int <=#1 8'b0;
  402. else if(SB_rdata_up)
  403. SB_rdata_int <=#1 {SB_rdata_int[6:0],spi_din_int};//MSB
  404. end
  405. assign spi_dout_int = SB_wdata_int[7] ;
  406. assign SB_rdata = SB_rdata_int ;
  407. assign spi_clk = spi_clk_int ;
  408. assign spi_csn = spi_csn_int ;
  409. assign spi_din_int = spi_din ;
  410. assign spi_dout = spi_dout_int ;
  411. endmodule

tb.v

  1. `timescale 1ns/100ps
  2. module tb ( );
  3. reg clk =0,rst =1;
  4. always clk =#5 ~clk;
  5. reg m_cs = 0 ;
  6. reg m_wr = 0 ;
  7. reg [2:0] m_addr = 0 ;
  8. reg [7:0] m_din = 0 ;
  9. wire [7:0] m_dout ;
  10. wire spi_clk ;
  11. wire spi_csn ;
  12. wire spi_din ;
  13. wire spi_dout ;
  14. parameter NOP = 8'hff;
  15. parameter WREN = 8'h06;//md0
  16. parameter WRDI = 8'h04;//md0
  17. parameter RDSR = 8'h05;//md6
  18. parameter WRSR = 8'h01;//md6
  19. parameter RDCMD = 8'h03;//md7
  20. parameter F_RD = 8'h0B;//md8
  21. parameter PP = 8'h02;//md4
  22. parameter SE = 8'hD8;//md9
  23. parameter BE = 8'hC7;//md0
  24. parameter DP = 8'hB9;//md0
  25. parameter RES = 8'hAB;//md0
  26. parameter RDID = 8'h9F;//md6
  27. //-------------产生spi_din------------
  28. reg [23:0] rand1=0;
  29. initial begin
  30. while(1) begin
  31. @(negedge spi_clk);
  32. rand1 = {$random} % 100;
  33. end
  34. end
  35. assign spi_din = rand1[0];
  36. reg[7:0] rdata_sim;
  37. reg [7:0] WaitData=8'h80;
  38. reg [31:0] index ;
  39. integer i;
  40. initial begin
  41. rst =1;
  42. #100;
  43. @(posedge clk);#1;
  44. rst =0;
  45. #100;
  46. @(posedge clk);#1;
  47. m_interfasc(1,3'h0,8'haa,rdata_sim);//数据aa
  48. m_interfasc(1,3'h2,8'h01,rdata_sim);//addh
  49. m_interfasc(1,3'h3,8'h02,rdata_sim);//addm
  50. m_interfasc(1,3'h4,8'h03,rdata_sim);//addl
  51. m_interfasc(1,3'h1,PP,rdata_sim);//cmd
  52. // #600;
  53. //pp
  54. for(i=0;i<7;i=1+i) begin
  55. index = 1;
  56. while(index)
  57. begin
  58. #100;
  59. @(posedge clk);#1;
  60. m_interfasc(0,3'h1,8'h00,rdata_sim);//读状态
  61. if(rdata_sim[3:0]==4'b1011)
  62. begin
  63. m_interfasc(1,3'h0,WaitData,rdata_sim);//数据
  64. index = 0;
  65. end
  66. end
  67. WaitData= WaitData>>1;
  68. end
  69. #1000;
  70. m_interfasc(1,3'h1,NOP,rdata_sim);//cmd
  71. #1000;
  72. // F_RD
  73. m_interfasc(1,3'h1,F_RD,rdata_sim);//cmd
  74. for(i=0;i<10;i=1+i) begin
  75. index = 1;
  76. while(index)
  77. begin
  78. #100;
  79. @(posedge clk);#1;
  80. m_interfasc(0,3'h1,8'h00,rdata_sim);//读状态
  81. if(rdata_sim[3:0]==4'b0111)
  82. begin
  83. m_interfasc(0,3'h0,8'h00,rdata_sim);//数据
  84. index = 0;
  85. end
  86. end
  87. end
  88. #1000;
  89. m_interfasc(1,3'h1,NOP,rdata_sim);//cmd
  90. end
  91. spi_ctrl U_spi_ctrl(
  92. .clk (clk ),//input clk ,
  93. .rst (rst ),//input rst ,
  94. .spi_clk (spi_clk ),//output spi_clk ,
  95. .spi_csn (spi_csn ),//output spi_csn ,
  96. .spi_din (spi_din ),//input spi_din ,
  97. .spi_dout (spi_dout ),//output spi_dout ,
  98. .m_cs (m_cs ),//output m_cs ,
  99. .m_wr (m_wr ),//output m_wr ,
  100. .m_addr (m_addr ),//output m_addr ,
  101. .m_din (m_din ),//output m_din ,
  102. .m_dout (m_dout )//output m_dout
  103. );
  104. task m_interfasc;//注意分号; 在第一行“task”语句中不能列出端口名称;
  105. input wr;
  106. input [3:0] addr;
  107. input [7:0] wdata;
  108. output reg[7:0] rdata;
  109. #100;
  110. @(posedge tb.clk);#1;
  111. tb.m_cs = 0 ;
  112. tb.m_wr = 0 ;
  113. tb.m_addr = 0 ;
  114. tb.m_din = 0 ;
  115. @(posedge tb.clk);#1;
  116. tb.m_cs = 1 ;
  117. tb.m_wr = wr ;
  118. tb.m_addr = addr ;
  119. tb.m_din = wdata ;
  120. if(wr==0) begin
  121. @(posedge tb.clk);#3;
  122. rdata = tb.m_dout ;
  123. $display("%h",rdata);
  124. end else rdata = tb.m_dout ;
  125. @(posedge tb.clk);#1;
  126. tb.m_cs = 0 ;
  127. tb.m_wr = 0 ;
  128. tb.m_addr = 0 ;
  129. tb.m_din = 0 ;
  130. endtask
  131. endmodule

runtb.do

  1. quit -sim
  2. cd D:/gaop/SIM/spi_ctrl
  3. vlib work
  4. vmap work work
  5. vlog -novopt -incr -sv -work work "./tb/*.v"
  6. vsim -novopt -t 1ns -L work work.tb
  7. log -r /*
  8. do wave.do
  9. run 100us
  10. #
  1. onerror {resume}
  2. quietly WaveActivateNextPane {} 0
  3. add wave -noupdate /tb/U_spi_ctrl/clk
  4. add wave -noupdate /tb/U_spi_ctrl/rst
  5. add wave -noupdate /tb/U_spi_ctrl/spi_clk
  6. add wave -noupdate /tb/U_spi_ctrl/spi_csn
  7. add wave -noupdate /tb/U_spi_ctrl/spi_din
  8. add wave -noupdate /tb/U_spi_ctrl/spi_dout
  9. add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_cs
  10. add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_wr
  11. add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_addr
  12. add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_din
  13. add wave -noupdate -expand -group m_x /tb/U_spi_ctrl/m_dout
  14. add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_cs
  15. add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_wr
  16. add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_wdata
  17. add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_wrvld
  18. add wave -noupdate -expand -group ST_x /tb/U_spi_ctrl/ST_rdata
  19. add wave -noupdate /tb/U_spi_ctrl/tx_data0
  20. add wave -noupdate /tb/U_spi_ctrl/rx_data0
  21. add wave -noupdate /tb/U_spi_ctrl/cmd
  22. add wave -noupdate /tb/U_spi_ctrl/add_h
  23. add wave -noupdate /tb/U_spi_ctrl/add_m
  24. add wave -noupdate /tb/U_spi_ctrl/add_l
  25. add wave -noupdate -radix ascii /tb/U_spi_ctrl/cur_state
  26. add wave -noupdate /tb/U_spi_ctrl/ST_change
  27. add wave -noupdate /tb/rdata_sim
  28. add wave -noupdate /tb/U_spi_ctrl/state
  29. add wave -noupdate /tb/U_spi_ctrl/busy
  30. add wave -noupdate /tb/U_spi_ctrl/SDEmy
  31. add wave -noupdate /tb/U_spi_ctrl/RXFull
  32. add wave -noupdate /tb/U_spi_ctrl/WaitData
  33. add wave -noupdate /tb/U_spi_ctrl/rd_stata
  34. TreeUpdate [SetDefaultTree]
  35. WaveRestoreCursors {{Cursor 1} {4052 ns} 0}
  36. quietly wave cursor active 1
  37. configure wave -namecolwidth 176
  38. configure wave -valuecolwidth 102
  39. configure wave -justifyvalue left
  40. configure wave -signalnamewidth 1
  41. configure wave -snapdistance 10
  42. configure wave -datasetprefix 0
  43. configure wave -rowmargin 4
  44. configure wave -childrowmargin 2
  45. configure wave -gridoffset 0
  46. configure wave -gridperiod 1
  47. configure wave -griddelta 40
  48. configure wave -timeline 0
  49. configure wave -timelineunits ps
  50. update
  51. WaveRestoreZoom {0 ns} {14036 ns}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56788
推荐阅读
相关标签
  

闽ICP备14008679号