实验二:基本的组合逻辑电路
这里只展示2.3的一部分代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module decoder_3to8(in, out); input [2:0] in; output reg [7:0] out; always@(in) case(in) 3'b000 : out[7:0] = 8'b11111110; 3'b001 : out[7:0] = 8'b11111101; 3'b010 : out[7:0] = 8'b11111011; 3'b011 : out[7:0] = 8'b11110111; 3'b100 : out[7:0] = 8'b11101111; 3'b101 : out[7:0] = 8'b11011111; 3'b110 : out[7:0] = 8'b10111111; default : out[7:0] = 8'b01111111; endcase endmodule
这里我需要提一点,就是always语句或者initial语句里面是数据流的形式,数据流的形式和其他形式的区别有以下几点
左边的元素一定是reg类型的
不允许使用assign赋值
@(…..)表示…..里面的值发生变化的时候就进入语句块
这里可以使用case(…)来模仿C里面的switch语句来进行赋值(真值表) 用逻辑函数也可以(做运算或者申明逻辑门[逻辑门之间使用wire连接])
对于4-16的亦是如此
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 module decoder_4to16(in, out); input [3:0] in; output reg [7:0] out; always@(in) begin case(in) 4'b0000 : out[7:0] = 8'b11000000; 4'b0001 : out[7:0] = 8'b11111001; 4'b0010 : out[7:0] = 8'b10100100; 4'b0011 : out[7:0] = 8'b10110000; 4'b0100 : out[7:0] = 8'b10011001; 4'b0101 : out[7:0] = 8'b10010010; 4'b0110 : out[7:0] = 8'b10000010; 4'b0111 : out[7:0] = 8'b11111000; 4'b1000 : out[7:0] = 8'b10000000; 4'b1001 : out[7:0] = 8'b10011000; 4'b1010 : out[7:0] = 8'b10001000; 4'b1011 : out[7:0] = 8'b10000011; 4'b1100 : out[7:0] = 8'b11000110; 4'b1101 : out[7:0] = 8'b10100001; 4'b1110 : out[7:0] = 8'b10000110; default : out[7:0] = 8'b10001110; endcase end endmodule
最后使用结构声明来组装零件
1 2 3 4 5 6 7 8 9 10 11 module Last(SW, SEG, AN, LED); input [15:0] SW; // 16位拨动开关 output [7:0] SEG; // 7段数码管驱动,低电平有效 output [7:0] AN; // 7段数码管片选信号,低电平有效 output [15:0] LED; // 16位LED显示 decoder_3to8(.in(SW[15:13]), .out(AN[7:0])); decoder_4to16(.in(SW[3:0]), .out(SEG[7:0])); assign LED[15:0] = SW[15:0]; endmodule
说明一下.xxx(yyy)说明yyy这个值传进结构声明中xxx这个变量,.in(SW[15:13])表示SW[15:13]这个东西放到decoder_3to8里面的in
实验三:简单的同步时许逻辑电路
首先就是滤波器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 module divider(clk, clk_N); input clk; // 系统时钟 output reg clk_N; // 分频后的时钟 parameter N = 100_000_000; // 1Hz的时钟,N=fclk/fclk_N reg [31:0] counter; /* 计数器变量,通过计数实现分频。当计数器从0计数到(N/2-1)时,输出时钟翻转,计数器清零 */ initial begin // 赋初始值 counter = 0; clk_N = 0; end always @(posedge clk) // 时钟上升 begin counter <= counter + 1; if (counter > N / 2) begin clk_N <= ~clk_N; counter <= 0; end end endmodule
posedge代表上升的意思,这个就是clk(板子里面的E3)每一次上升就会触发,其实板子里面的E3会一直变化(速度非常快)这个就是板子里的E3变化了1亿次之后就会传输一个信号出去的意思
就是clk进.clk_N出clk变化100000000次,clk_N变化一次,这个就是分频的定义,所以说在always里面加上了一个if语句就是这个意思
1 2 3 4 5 6 7 8 9 module counter(clk, out); input clk; // 计数时钟 output reg [2:0] out; // 计数值 always @(posedge clk) // 在时钟上升沿计数器加1 begin out <= out + 1; end endmodule
计数器,就是每一次clk上升out就会加1,至于触发器怎么用,咱也不用管,就说明功能就完事了
第三个实验就是测试一下计数器和过滤器组合的原理
1 2 3 4 5 6 7 8 module divide_and_count(clk, out); input clk; output [2:0] out; wire clk_tmp; divider d1(.clk(clk), .clk_N(clk_tmp)); counter c1(.clk(clk_tmp), .out(out[2:0])); endmodule
这个是不是有点像Java里面的装饰器,对传进来的信号进行逐级装饰,传递来的信号经过计数器的转化进行输出
实验四:只读存储器:打个表就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 module rom8x4(addr, data); input [2:0] addr; // 地址 output [3:0] data; // 地址addr处存储的数据 reg [3: 0] mem [7: 0]; // 8个4位的存储器 initial // 初始化存储器 begin mem[0]=4'b0000; mem[1]=4'b0010; mem[2]=4'b0100; mem[3]=4'b0110; mem[4]=4'b1000; mem[5]=4'b1010; mem[6]=4'b1100; mem[7]=4'b1110; end assign data[3:0] = mem[addr]; // 读取addr单元的值输出 endmodule
下面就是把信号分解成七位表示器了.上面提到过
最后把这些东西组在一块,又用到组织模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module dynamic_scan(clk, SEG, AN); input clk; // 系统时钟 output [7:0] SEG; // 分别对应CA、CB、CC、CD、CE、CF、CG和DP output [7:0] AN; // 8位数码管片选信 wire clk_tmp; wire [2:0] num; wire [3:0] code; divider d1(.clk(clk), .clk_N(clk_tmp)); counter c1(.clk(clk_tmp), .out(num[2:0])); decoder_3to8(.in(num[2:0]), .out(AN[7:0])); rom8x4(.addr(num[2:0]), .data(code[3:0])); decoder_4to16(.in(code[3:0]), .out(SEG[7:0])); endmodule
可以使用wire连接,也可以直接你的输出就是我的输入