博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
20181118 一些FPGA入门作业
阅读量:5793 次
发布时间:2019-06-18

本文共 8831 字,大约阅读时间需要 29 分钟。

这是一份作业,为了完成任务而写,学习嘛。

目标:1、学习Markdown的写法。2、暂时没想到。

参考资料:

http://ecdav.cuc.edu.cn/web_root/ShiYanJiaoXue/Verilog_Starter_Tutorial/content.htm
---

多路选择器

任务:做一个4选1的mux,并且进行波形仿真。

//4选1多路选择器module mux4x1(//命名要求,全部大写表示端口    SEL,    IN0,    IN1,    IN2,    IN3,    OUT);//模块端口声明部分    //参数部分    parameter WL = 8;//定义可变参数,便于模块扩展例化    //这里有个问题:    //这个INX怎么才能“参数化”,类似于C语言的“不定参数”,那不就更方便了么,可惜不得其法    //端口描述部分,描述端口的方向    input [WL-1:0] IN0,IN1,IN2,IN3;    input [1:0]SEL;    output [WL-1:0] OUT;    //?这个叫啥?    //语法贼麻烦    reg [WL-1:0] OUT;    //多路选择器的主要代码    always @ (IN0 or IN1 or IN2 or IN3 or SEL) begin        case (SEL)        2'b00: OUT = IN0;        2'b01: OUT = IN1;        2'b10: OUT = IN2;        2'b11: OUT = IN3;        //所有情况写完了就不需要default了        endcase        /*//这种写法y也行,但是生成的RTL图不一样        if(SEL==0)OUT = IN0;        else        if(SEL==1)OUT = IN1;        else        if(SEL==2)OUT = IN2;        else        OUT = IN3;        */    endendmodule

扔到Quartus II 9.0里进行编译,仿真,截图如下:

1457443-20181118162417053-877791789.png

按我所认识的组合逻辑电路来说,当SEL发生变化的时候,OUT也应该或者很快地发生变化才对。然而,从仿真结果可以看到,SEL变化和OUT变化相差大概8个ns,可能这就是所谓的线路延迟吧。图中的“毛刺”,估计是由一个值变化到另一个值所产生的“中间值”吧。


交叉开关

交叉开关是多路选择器mux的一种变形,它可以用SELx表示选择输入INn到输出OUTn。

任务:编写一个4X4路交叉开关的RTL。

//交叉开关,Crossbar Switchmodule crossbarswitch4x4(    IN0, IN1, IN2, IN3,    SEL0, SEL1, SEL2, SEL3,    OUT0, OUT1, OUT2, OUT3);    parameter WL = 16;    input [WL-1:0] IN0,IN1,IN2,IN3;    input [1:0] SEL0,SEL1,SEL2,SEL3;    output reg [WL-1:0] OUT0,OUT1,OUT2,OUT3;    //例化4个4选1多路选择器    //这里有个例化时修改参数的语法    mux4x1 #(.WL(WL)) mux4x1_u0(        .IN0(IN0),.IN1(IN1),.IN2(IN2),.IN3(IN3),        .SEL(SEL0),        .OUT(OUT0)    );    mux4x1 mux4x1_u1(        .IN0(IN0),.IN1(IN1),.IN2(IN2),.IN3(IN3),        .SEL(SEL1),        .OUT(OUT1)    );    mux4x1 mux4x1_u2(        .IN0(IN0),.IN1(IN1),.IN2(IN2),.IN3(IN3),        .SEL(SEL2),        .OUT(OUT2)    );    mux4x1 mux4x1_u3(        .IN0(IN0),.IN1(IN1),.IN2(IN2),.IN3(IN3),        .SEL(SEL3),        .OUT(OUT3)    );fendmodule

不仿真了。


优先编码器

常用的组合逻辑电路,如果多个条件同时成立,则按照最高优先级的条件输出。

任务:编写一个8位优先编码器,然后编译,看RTL View。

思路:以74148逻辑芯片为例,按照其真值表编写8-3优先编码器。

//8位优先编码器,Priority Encodermodule priorityencoder8x3(    input [7:0]IN,    output reg [2:0]OUT);    //生成的RTL View很难看……    always @ (IN) begin        casez(IN)        //casez认为?可以代表0或1或z,而casex还包括x        //据说,x为仿真初态,仿真会出问题?        8'b0???????: OUT = 3'b000;        8'b10??????: OUT = 3'b001;        8'b110?????: OUT = 3'b010;        8'b1110????: OUT = 3'b011;        8'b11110???: OUT = 3'b100;        8'b111110??: OUT = 3'b101;        8'b1111110?: OUT = 3'b110;        8'b11111110: OUT = 3'b111;        default: OUT = 3'b111;        endcase    endendmodule

图片太长,不好截图。(大概就是输入端接到一个8-256的译码器上,然后译码器的某些管脚做一个或运算,输出)


译码器

要求1:写一个4-16译码器。

module decoder4x16(    input  [3:0] IN,    output reg [15:0] OUT);    always @ (IN) begin        case(IN)            4'b0000: OUT = 8'b0000000000000001;            4'b0001: OUT = 8'b0000000000000010;            4'b0010: OUT = 8'b0000000000000100;            4'b0011: OUT = 8'b0000000000001000;            4'b0100: OUT = 8'b0000000000010000;            4'b0101: OUT = 8'b0000000000100000;            4'b0110: OUT = 8'b0000000001000000;            4'b0111: OUT = 8'b0000000010000000;            4'b1000: OUT = 8'b0000000100000000;            4'b1001: OUT = 8'b0000001000000000;            4'b1010: OUT = 8'b0000010000000000;            4'b1011: OUT = 8'b0000100000000000;            4'b1100: OUT = 8'b0001000000000000;            4'b1101: OUT = 8'b0010000000000000;            4'b1110: OUT = 8'b0100000000000000;            4'b1111: OUT = 8'b1000000000000000;        endcase    endendmodule

要求2:对比资源开销。

要求3:观看RTL图。

1457443-20181118162408209-896159166.png

可见,代码生成了一个很漂亮的译码器。


加法器

加法器是很常见的电路,主要包括无符号加法器和补码加法器。

  • 无符号加法器,不包括符号位,常用于计数器累加和地址序号表示里
  • 补码加法器,最高位表示符号位(0+,1-),其余位置为数字的补码(正数不变,负数取反+1),便于数字电路进行加减法运算

    无符号加法器

module unsignedadder3(    input [3:0] IN1,    input [3:0] IN2,    output reg [4:0] OUT//多1位表示溢出);    always@(IN1 or IN2) begin        OUT = IN1 + IN2;    endendmodule

要求1:观察逻辑门电路造成的延迟,并说明,2比特的信号00翻转成11,能做到绝对的同时翻转么?

1457443-20181118162401909-1874037929.png

延迟大概比10ns少一点;很显然,不能同时翻转(万一运气好呢)。

要求2:将该加法器改成8位加法器,观察输出延迟。

代码略。
1457443-20181118162356377-2012776029.png

毛刺时间似乎增加了。想想也是,位数多了,就不靠谱了。

补码加法器

补码加法器的要点是:1、声明变量带一个signed,2、最高位为符号位,其余位为原数的补码。

module signedadder3(    input signed [3:0] IN1,    input signed [3:0] IN2,    output reg signed [4:0] OUT//多1位表示溢出);    always@(IN1 or IN2) begin        OUT = IN1 + IN2;    endendmodule

要求1:把输出改成4位宽,问什么时候的输出才是正确的?

(这里采用不改代码,改仿真器的方法做实验。)
1457443-20181118162348914-1021636672.png

当且仅当,原来两数相加没有产生溢出时才是正确的,其他情况下都会出现奇怪的问题。图中,正常情况下,-2+-8=-10,然而最高符号位不见了,就变成了6……

要求2:把输入改成8位宽,对比波形图。

1457443-20181118162342675-418550112.png

不会观察……反正毛刺持续时间更长了。

带流水线的加法器

要点,纯组合逻辑的延迟时间不一致,或者说过长。有时需要(基本上都要吧)让它们走上时序的“正轨”。——用D触发器等,把较大的组合逻辑变成小块的组合逻辑+时序逻辑。

示例代码如下:

module unsignedadderwithpipline(    input [3:0] IN1,    input [3:0] IN2,    input CLK,    output reg [4:0] OUT);    reg [3:0] in1_d1R, in2_d1R;    reg [4:0] adder_out;    always@(posedge CLK) begin // 生成D触发器的always块        in1_d1R <= IN1;        in2_d1R <= IN2;        OUT     <= adder_out;    end    always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块        adder_out = in1_d1R + in2_d1R;    endendmodule

观察波形图如下:

1457443-20181118162335219-185694560.png

确实要比组合逻辑实现的好看多了。


乘法器

乘法器是非常消耗逻辑器件的组合逻辑!尤其是对于那些内部木有乘法器的FPGA芯片而言。

(实验太多了……直接上代码吧)

module multiplier(    input [8:0] IN1,    input [8:0] IN2,    output reg [15:0] OUT);    always@(IN1 or IN2) begin        OUT = IN1 * IN2;    endendmodule

选择一个没有乘法器的芯片,观察资源消耗。

1457443-20181118162328603-1042150180.png

另一个自带乘法器的芯片,消耗资源为0。

1457443-20181118162322818-477753993.png

RTL Viewer


计数器

计数器有这么一些接口功能:

1、计数溢出OV,2、计数时能EN,3、计数清零CLR,4、计数置数LOAD等。

实验要求:

1、设计一个最简单的计数器,输入为CLK,输出为OV,当计数到最大值时OV输出1。
代码如下:

module counter(    input CLK,    output reg OV,    output reg [3:0] data);    reg [3:0] data_next;    parameter MAX_VALUE = 9;    always@(*) begin //下一状态的组合逻辑        if(data

1457443-20181118162254312-1956142520.png

由图可知,没来9个上升沿,OV就由0变1,但是,与CLK的上升沿相比有一定延迟。

2、设计一个较为复杂的计数器,带有多种信号,其中CLR优先级最高,EN次之,LOAD最低。

代码如下:

module counter(    input CLK,    input EN,    input CLR,    input LOAD,    input [3:0] ldata,    input RST,    output reg OV,    output reg [3:0] data);    reg [3:0] data_next;    parameter MAX_VALUE = 9;    always@(*) begin        if(CLR) begin           //清零有效            data_next = 0;        end        else begin              //清零无效            if(EN) begin        //始能有效                if(LOAD) begin  //置数有效                    data_next = ldata;                end                else begin      //置数无效                    if(data

状态机

要点:1、相当于C语言中的ifelse,2、尽量使用三段式写法。对于规范写法的状态机,EDA工具可以识别出来并优化。

实验要求:

设计一个用于识别2进制序列“1011”的状态机。
基本要求:
电路每个时钟周期输入1比特数据,当捕获到1011的时钟周期,电路输出1,否则输出0
使用序列101011010作为测试序列
扩展要求:
给你的电路添加输入使能端口,只有输入使能EN为1的时钟周期,才从输入的数据端口向内部获取1比特序列数据。

代码如下:

module fsm3(    input CLK,    input RST,    input IN,    input EN,    output reg OUT);reg [3:0] state;reg [3:0] next_state;//计算下一状态always @ (EN or IN or state) begin    if(EN) begin        case(state)        4'b0000:if(IN) next_state = 4'b1000; else next_state = 4'b0000;        4'b0001:if(IN) next_state = 4'b1000; else next_state = 4'b0000;        4'b0010:if(IN) next_state = 4'b1001; else next_state = 4'b0001;        4'b0011:if(IN) next_state = 4'b1001; else next_state = 4'b0001;        4'b0100:if(IN) next_state = 4'b1010; else next_state = 4'b0010;        4'b0101:if(IN) next_state = 4'b1010; else next_state = 4'b0010;        4'b0110:if(IN) next_state = 4'b1011; else next_state = 4'b0011;        4'b0111:if(IN) next_state = 4'b1011; else next_state = 4'b0011;        4'b1000:if(IN) next_state = 4'b1100; else next_state = 4'b0100;        4'b1001:if(IN) next_state = 4'b1100; else next_state = 4'b0100;        4'b1010:if(IN) next_state = 4'b1101; else next_state = 4'b0101;        4'b1011:if(IN) next_state = 4'b1101; else next_state = 4'b0101;        4'b1100:if(IN) next_state = 4'b1110; else next_state = 4'b0110;        4'b1101:if(IN) next_state = 4'b1110; else next_state = 4'b0110;        4'b1110:if(IN) next_state = 4'b1111; else next_state = 4'b0111;        4'b1111:if(IN) next_state = 4'b1111; else next_state = 4'b0111;        endcase    endend//计算输出always @ (state) begin  if(state == 4'b1011)     OUT = 1'b1;  else     OUT = 1'b0;end//状态变换always @ (posedge CLK or posedge RST)begin  if(RST)    state <= 4'b0000;  else    state <= next_state;endendmodule

1457443-20181118162306550-1357966613.png

在计算下一状态部分,我也尝试过使用以下写法:

next_state = {IN,state[3:1]};

然而,这种写法会导致毛刺的出现(为什么呢?)


移位寄存器

要点:移位寄存器通常用于串入并出,或并入串出……比如UART、SPI、I2C等常见的串行通信协议,把数据从FPGA内部送到外部芯片中去。

实验要求:

设计一个如本节“电路描述”部分的“带加载使能和移位使能的并入串出”的移位寄存器,电路的RTL结构图如“电路描述”部分的RTL结构图所示。
1457443-20181118162230071-1295727807.png

代码如下:

module p2sshifter(    input [3:0] IN,    input CLK,    input RST,    input LOAD,    input EN,    output OUT);    reg [3:0] data;    reg [3:0] data_next;    assign OUT = data[0];    always@(EN or LOAD)begin        if(EN)begin            if(LOAD)begin                data_next = IN;            end            else begin                data_next = {1'b0,data[3:1]};            end        end    end    always@(posedge CLK or posedge RST)begin        if(RST)            data <= 0;        else            data <= data_next;    endendmodule

波形图如下:

1457443-20181118162241244-310770319.png

输出了1010……,就这样吧。

转载于:https://www.cnblogs.com/AmnesiaBeing/p/9978303.html

你可能感兴趣的文章
【IL】IL生成exe的方法
查看>>
leetcode------Triangle
查看>>
network
查看>>
测试工程师速成手册
查看>>
实验一 查看CPU和内存,用机器指令和汇编指令编程
查看>>
Exchange 2013 RTM安装部署过程
查看>>
批量部署Windows NanoServer 2016 With Hyper-V
查看>>
Summary interview question for Project Manager -2
查看>>
ORACLE 11G在Linux下的标准安装方法(下)
查看>>
三星的“后手机时代”:电视崛起,构建新生态叫板Android
查看>>
在vSphere网络中不能只在交换机一端配置链路聚合
查看>>
易信对决微信:市场需要挑战者
查看>>
2015年值得关注的几个WEB技术
查看>>
项目组CentOS开发环境的搭建
查看>>
Zen Cart 如何添加地址栏上的小图标
查看>>
2012.11.10项目经理考试核心关注点1_《系统集成项目管理工程师软考辅导——3年真题透解与全真模拟》...
查看>>
又到红包季,QQ红包强势出击欲何为?
查看>>
大学课程能给我们带来什么?——“我们能从大学得到什么”系列之三
查看>>
webdis实现Redis的http接口及多数据格式共享 [含json,restful]
查看>>
网站另类推广玩法心得
查看>>