桶形移位器
module barrel_shifter(shamt,din,LR,AL,dout);
input [2:0] shamt;
input [7:0] din;
input LR; // left:LR = 1, rgiht:LR = 0
input AL; // athi:AL = 1, logical:AL = 0
output reg [7:0] dout;
always @(*) begin
if(LR == 1)begin // left shift
dout = shamt[2] ? {din[3:0], 4'b0} : din;
dout = shamt[1] ? {dout[5:0], 2'b0} : dout;
dout = shamt[0] ? {dout[6:0], 1'b0} : dout;
end
else begin // right shift
if(AL == 1)begin
dout = shamt[2] ? {{ 4{din[7]}}, din[7:4]} : din;
dout = shamt[1] ? {{ 2{dout[7]}}, dout[7:2]} : dout;
dout = shamt[0] ? {{ 1{dout[7]}}, dout[7:1]} : dout;
end
else begin
dout = shamt[2] ? {4'b0, din[7:4]} : din;
dout = shamt[1] ? {2'b0, dout[7:2]} : dout;
dout = shamt[0] ? {1'b0, dout[7:1]} : dout;
end
end
end
endmodule
主要思想是根据shamt的值来确定移位,第一级利用shamt[0]来控制是否需要移动一位,第二级在第一级的移动结果上用shamt[1]来控制是否要移动两位,第三级在第二级的基础上再对应判断是否要移动四位。例如shamt为111,即移动1位+移动2位+移动4位=移动7位。
随机数发生器
top.v
module top (
input clk,
input rst,
output reg [7:0] num,
output reg [3:0] num0,
output reg [3:0] num1,
output reg [6:0] seg0,
output reg [6:0] seg1
);
reg x;
always@(posedge clk)begin
if(rst) begin num = 8'b00000001;end
else begin
x = num[4] ^ num[3] ^ num[2] ^ num[0]; // 串行阻塞赋值
num = {x,num[7:1]};
end
end
assign num0 = num[3:0];
assign num1 = num[7:4];
seg my_seg(
.clk(clk),
.rst(rst),
.num0(num0),
.num1(num1),
.seg0(seg0),
.seg1(seg1)
);
endmodule
由于x要先于下一条语句算出 所以使用串行阻塞赋值。
=
为阻塞赋值 有先后顺序。 <=
为非阻塞赋值,所有语句一起执行。
begin ··· end
为串行语句, fork ··· join
为并行语句。
seg.v
module seg (
input clk,
input rst,
input [3:0] num0,
input [3:0] num1,
output reg [6:0] seg0,
output reg [6:0] seg1
);
wire [6:0] segs [15:0];
assign segs[0] = 7'b0000001; // nvboard 0为发光 1为熄灭
assign segs[1] = 7'b1001111;
assign segs[2] = 7'b0010010;
assign segs[3] = 7'b0000110;
assign segs[4] = 7'b1001100;
assign segs[5] = 7'b0100100;
assign segs[6] = 7'b0100000;
assign segs[7] = 7'b0001111;
assign segs[8] = 7'b0000000;
assign segs[9] = 7'b0001100;
assign segs[10] = 7'b0001000;
assign segs[11] = 7'b1100000;
assign segs[12] = 7'b0110001;
assign segs[13] = 7'b1000010;
assign segs[14] = 7'b0110000;
assign segs[15] = 7'b0111000;
always@(posedge clk)begin
case (num0)
4'd0 :seg0 = segs[0];
4'd1 :seg0 = segs[1];
4'd2 :seg0 = segs[2];
4'd3 :seg0 = segs[3];
4'd4 :seg0 = segs[4];
4'd5 :seg0 = segs[5];
4'd6 :seg0 = segs[6];
4'd7 :seg0 = segs[7];
4'd8 :seg0 = segs[8];
4'd9 :seg0 = segs[9];
4'd10:seg0 = segs[10];
4'd11:seg0 = segs[11];
4'd12:seg0 = segs[12];
4'd13:seg0 = segs[13];
4'd14:seg0 = segs[14];
4'd15:seg0 = segs[15];
default: seg0 = segs[0];
endcase
case (num1)
4'd0 :seg1 = segs[0];
4'd1 :seg1 = segs[1];
4'd2 :seg1 = segs[2];
4'd3 :seg1 = segs[3];
4'd4 :seg1 = segs[4];
4'd5 :seg1 = segs[5];
4'd6 :seg1 = segs[6];
4'd7 :seg1 = segs[7];
4'd8 :seg1 = segs[8];
4'd9 :seg1 = segs[9];
4'd10:seg0 = segs[10];
4'd11:seg0 = segs[11];
4'd12:seg0 = segs[12];
4'd13:seg0 = segs[13];
4'd14:seg0 = segs[14];
4'd15:seg0 = segs[15];
default: seg1 = segs[0];
endcase
end
endmodule
sim_mian.cpp
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<nvboard.h>
#include"Vtop.h"
#include"verilated.h"
#include"verilated_vcd_c.h"
void nvboard_bind_all_pins(Vtop* top);
int main(int argc, char** argv) {
VerilatedContext* contextp = new VerilatedContext;
contextp->traceEverOn(true);
contextp->commandArgs(argc, argv);
Vtop* top = new Vtop{contextp};
nvboard_bind_all_pins(top);
nvboard_init();
VerilatedVcdC* m_trace = new VerilatedVcdC;
top->trace(m_trace, 99);
m_trace->open("wave.vcd");
top->clk = 0;
top->rst = 1;
while (!contextp->gotFinish()) {
contextp->timeInc(1);
nvboard_update();
//top->clk = !top->clk; // 用按钮控制clk 所以不需要在这里更新clk
top->eval();
m_trace->dump(contextp->time());
}
m_trace->close();
delete top;
delete contextp;
return 0;
}
top.nxdc
top=top
clk SW1
rst SW0
seg0 (SEG0A, SEG0B, SEG0C, SEG0D, SEG0E, SEG0F, SEG0G)
seg1 (SEG1A, SEG1B, SEG1C, SEG1D, SEG1E, SEG1F, SEG1G)
注意首先要在rst=1
下用按钮给几个时钟上升沿用于初始化