花了近两三个星期,从夏宇闻的书中一行行敲下代码,然后再在questasim仿真器下进行修改、编译和仿真。出现了很多错误,一一改正,学到了不少东西,由于记性太烂,过后即忘,逼着自己写下自己从中学到的知识点,以及一些自己的心得。
EEPROM行为模型:
1. 首先用verilog编写出eeprom的行为模型,因为我们在这里主要是设计读写控制器,eeprom只是仿真时需要的,所以只需要编写出其行为模型。我们可以用延时控制语句,事件控制语句。
2. EEPROM有一个输入端口scl,和一个双向端口sda。
3. EEPROM中的寄存器有地址寄存器(address),控制字节寄存器(ctrl_byte),数据字节寄存器(data_byte),以及状态寄存器,还有一个outflag寄存器,控制sda的双向端口特性。
4. 由于其不必综合,我们首先将其中的所有寄存器、存储单元都初始化。
EEPROM的读写时序是这样的:
Ø scl作为串行的时钟信号在时钟为高电平时,如果检测到sda的上升沿,开始启动。
Ø 之后sda在低电平时给其赋值,在scl高电平到来时其已经稳定,并且在scl高电平期间保持不变。所以可在@posedgescl时将sda的值赋给eeprom中的地址或者数据寄存器。
Ø 写EEPROM用到shift_in这个任务,这个任务有输出shift,需要注意的是只有当任务全部执行完,输出才会传递到参数中。如:shiftin(ctrl_byte),尽管在任务执行的过程中shift值在不断变化,但ctrl_byte只在任务完成后才改变。
Ø 当从EEPROM中读出数据时,此时outflag有效,sda在scl为低电平时将寄存器中的数据通过shift_out任务传送至sda。
Ø 在scl的高电平如果检测到sda的上升沿,则数据传输结束。
EEPROM读写控制器的可综合Verilog代码:
1. 基本原理:在写的过程中,包括写入地址,写入数据,将从信号源来的并行地址信号,并行数据信号转变成串行的SDA信号,输入到EEPROM中
在读的过程中,接受由EEPROM来的SDA信号,将其转变为并行数据信号输出。
2. Input:WR,RD,ADDRESS,CLK,RESET
Output:SCL,ACK
Inout:SDA,DATA
3. 读写控制的状态机。
是读写控制器的主状态,在ctrl_write这个状态中,需要将输入的控制信号转变为SDA。
在这个设计中用到了几个嵌套状态机: 启动任务,串行转并行任务,并行转串行任务,结束任务。
这里说明一点,并不是所有的任务都是不可综合的,只要任务中没有延时控制语句,时间控制语句,是可以综合的。这里的所有人物都是always语句块,是可以综合的。
这里是如何控制双向端口SDA取各种数据呢?用组合逻辑实现!
1,当写数据的时候,SDA就接受外部传来的数据。
2,当读数据的时候SDA接收由EEPROM传来的数据,
3,由于SDA控制读写的开始和结束,SDA也应产生开始和结束的信号。
其verilog代码如下:
// 串行数据在开关的控制下有顺序地输入输出
assign sda1 = (link_head) ? head_buf[1] : 1'b0;
assign sda2 = (link_write) ? sh8out_buf[7] : 1'b0;
assign sda3 = (link_stop) ? stop_buf[1] : 1'b0;
assign sda4 = (sda1 | sda2 |sda3);
assign SDA = (link_sda) ? sda4 : 1'bz;
assign DATA = (link_read) ? data_from_rm : 8'hzz;
最后是仿真信号源的verilog代码模型:
1. 首先产生时钟信号。
2. 数据信号和地址信号首先按照16进制的格式事先存放在dat数据文件中,分别可命名为addr.dat和data.dat.
3. 初始化时将这两个文件中的数据分别存放到寄存器组中。
$readmemh("C:/questasim_10.1c/examples/work/eeprom_top/addr.dat",addr_mem); // 地址数据存入地址存储器。
$readmemh("C:/questasim_10.1c/examples/work/eeprom_top/data.dat",data_mem); //写入EEPROM的数据存入数据存储器。
4. 将要写入EEPROM的数据和地址都存放在一个文件中
OUTFILE= $fopen("C:/questasim_10.1c/examples/work/eeprom_top/eeprom.dat");
$fdisplay(OUTFILE, “%oh %oh” , ADDR, data_to_eeprom);
$fclose(OUTFILE)
5. 然后依次读出数据,给出地址从eeprom中读出数据,读出数据之后与存储在文件中的数据进行比较,如果一致则说明读写正确。