赞
踩
使用握手信号实现跨时钟域传输
- module data_driver(
- input clk_a,
- input rst_n,
- input data_ack,
- output reg [3:0]data,
- output reg data_req
- );
- reg data_ack_reg_1;
- reg data_ack_reg_2;
- reg data_ack_reg_3;
- reg [9:0] cnt;
- always @ (posedge clk_a or negedge rst_n)
- if (!rst_n)
- begin
- data_ack_reg_1 <= 0;
- data_ack_reg_2 <= 0;
- data_ack_reg_3 <= 0;
- end
- else
- begin
- data_ack_reg_1 <= data_ack;
- data_ack_reg_2 <= data_ack_reg_1;
- data_ack_reg_3 <= data_ack_reg_2;
- end
-
- always @ (posedge clk_a or negedge rst_n)
- if (!rst_n)
- begin
- data <= 0;
- end
- else if(data_ack_reg_2 && !data_ack_reg_3)
- begin
- data <= data+1;
- end
- else begin
- data <= data;
- end
- //同时在data_ack有效之后,开始计数五个时钟,之后发送新的数据,也就是再一次拉高data_req.
- always @ (posedge clk_a or negedge rst_n)
- if (!rst_n)
- cnt <= 0;
- else if (data_ack_reg_2 && !data_ack_reg_3)
- cnt <= 0;
- else if (data_req)
- cnt <= cnt;
- else
- cnt <= cnt+1;
-
- always @ (posedge clk_a or negedge rst_n)
- if (!rst_n)
- data_req <= 0;
- else if (cnt == 3'd4)
- data_req <= 1'b1;
- else if (data_ack_reg_2 && !data_ack_reg_3)
- data_req <= 1'b0;
- else
- data_req <= data_req;
-
- endmodule
-
- module data_receiver(
- input clk_b,
- input rst_n,
- output reg data_ack,
- input [3:0]data,
- input data_req
- );
-
- reg [3:0]data_in_reg;
- reg data_req_reg_1;
- reg data_req_reg_2;
- reg data_req_reg_3;
- always @ (posedge clk_b or negedge rst_n)
- if (!rst_n)
- begin
- data_req_reg_1 <= 0;
- data_req_reg_2 <= 0;
- data_req_reg_3 <= 0;
- end
- else
- begin
- data_req_reg_1 <= data_req;
- data_req_reg_2 <= data_req_reg_1;
- data_req_reg_3 <= data_req_reg_2;
- end
-
- always @ (posedge clk_b or negedge rst_n)
- if (!rst_n)
- data_ack <= 0;
- else if (data_req_reg_1)
- data_ack <= 1;
- else data_ack <=0 ;
-
- always @ (posedge clk_b or negedge rst_n)
- if (!rst_n)
- data_in_reg <= 0;
- else if (data_req_reg_2 && !data_req_reg_3)
- data_in_reg <= data;
- else data_in_reg <= data_in_reg ;
-
- endmodule

序列产生
- 方法一(状态机)
- module sequence_generator(
- input clk,
- input rst_n,
- output data
- );
-
- parameter S0 = 3'd0;
- parameter S1 = 3'd1;
- parameter S2 = 3'd2;
- parameter S3 = 3'd3;
- parameter S4 = 3'd4;
- parameter S5 = 3'd5;
-
- reg [2:0] state;
- reg [2:0] next_state;
-
- always @ (posedge clk or negedge rst_n) begin
- if (rst_n == 1'b0) begin
- state <= S0;
- end
- else
- state <= next_state;
- end
-
- reg [3:0] data_reg;
- always @ (*) begin
- if (rst_n == 1'b0) begin
- next_state = S0;
- data_reg = 4'b0010;
- end
- else begin
- case (state)
- S0 : begin
- next_state = S1;
- data_reg = 4'b0010;
- end
- S1 : begin
- next_state = S2;
- data_reg = 4'b0101;
- end
- S2 : begin
- next_state = S3;
- data_reg = 4'b1011;
- end
- S3 : begin
- next_state = S4;
- data_reg = 4'b0110;
- end
- S4 : begin
- next_state = S5;
- data_reg = 4'b1100;
- end
- S5 : begin
- next_state = S0;
- data_reg = 4'b1001;
- end
- default : begin
- next_state = S0;
- data_reg = 4'b0010;
- end
- endcase
- end
- end
- assign data = data_reg[3];
- endmodule
-
- 方法二 移位寄存器
- module sequence_generator(
- input clk,
- input rst_n,
- output reg data
- );
-
- reg [5:0] q;
-
- always@(posedge clk or negedge rst_n)
- if (!rst_n)
- q <= 6'b001011;
- else
- q <= {q[4:0],q[5]};
-
- always@(posedge clk or negedge rst_n)
- if (!rst_n)
- data <= 1'd0;
- else
- data <= q[5];
- endmodule
-
- 方法三 计数器加case语句
- module sequence_generator(
- input clk,
- input rst_n,
- output data
- );
- reg [2:0] cnt;
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n) cnt<=3'b0;
- else begin
- if(cnt==3'd5)
- cnt<=3'b0;
- else cnt<=cnt+1'b1;
- end
- end
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n) data<=1'b0;
- else begin
- case(cnt)
- 3'd0:data<=1'b0;
- 3'd1:data<=1'b0;
- 3'd2:data<=1'b1;
- 3'd3:data<=1'b0;
- 3'd4:data<=1'b1;
- 3'd5:data<=1'b1;
- default : data <= 1'b0;
- endcase
- end
- end
- endmodule

序列检测 本次检测序列为10010
- 方法:画状态转移图采用状态机实现
- module sequential_detector(clk, reset, d, y);
- //输入输出端口定义
- input clk, reset, d;
- output y;
-
- //内部寄存器及连线定义
- reg [2 : 0] state;
- wire y;
-
- //状态编码
- parameter idle = 3'b000, s1 = 3'b001, s2 = 3'b010, s3 = 3'b011,
- s4 = 3'b100, s5 = 3'b101, s6 = 3'b110, s7 = 3'b111;
-
- //状态机实现
- always@(posedge clk or posedge reset)
- begin
- if(reset) state <= idle;
- else
- begin
- casex(state)
- idle: begin
- if(d == 1) state <= s1;
- else state <= idle;
- end
- s1: begin
- if(d == 0) state <= s2;
- else state <= s1;
- end
- s2: begin
- if(d == 0) state <= s3;
- else state <= s7;
- end
- s3: begin
- if(d == 1) state <= s4;
- else state <= s6;
- end
- s4: begin
- if(d == 0) state <= s5;
- else state <= s1;
- end
- s5: begin
- if(d == 1) state <= s1;
- else state <= s3;
- end
- s6: begin
- if(d == 1) state <= s7;
- else state <= s6;
- end
- s7: begin
- if(d == 1) state <= s1;
- else state <= s2;
- end
- default: state <= idle;
- endcase
- end
- end
-
- //用组合逻辑实现输出
- assign y = (state == s4 && d == 0) ? 1 : 0;
- endmodule

串转并
- 方法:移位寄存器
- module serial2paraller(
- input clk,
- input rst_n,
- input d,
- output reg [3:0]q,
- output reg q_valid
- );
- reg [3:0]data;
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- data <= 4'b0;
- else
- data <= {data[2:0],d};
- end
-
- reg [1:0] cnt;
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- cnt <= 2'd0;
- else if (cnt == 2'd3)
- cnt <= 2'd0;
- else
- cnt <= cnt + 1'b1;
- end
-
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- q <= 4'b0;
- else
- q <= data;
- end
-
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- q_valid <= 1'b0;
- else if (cnt == 2'd3)
- q_valid <= 1'b1;
- else
- q_valid <= 1'b0;
- end
-
- endmodule

并转串
- 方法:移位寄存器
- module paraller2serial(
- input clk,
- input rst_n,
- input [4:0]d,
- input en,
- output q
- );
- reg[4:0]data;
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- data <= 5'b0;
- else if(en)
- data <= d;
- else
- data <= data << 1;
- end
- assign q = data[4];
- endmodule

glitch-free电路
第一种:两个时钟之间有倍数关系
- 方法:将sel信号分别在不同时钟信号下进行打拍同步
- module syn_clk_glitch_free(
- input wire clk0 ,
- input wire clk1 ,
- input wire rst ,
- input wire sel ,
- output wire clk_out
- );
- reg q0, q1;
-
- always@(negedge clk0 or negedge rst)
- if(!rst)
- q0 <= 0;
- else
- q0 <= ~sel & ~q1;
-
- always@(negedge clk1 or negedge rst)
- if(!rst)
- q1 <= 0;
- else
- q1 <= sel & ~q0;
-
- assign clk_out = (q0 & clk0) | (q1 & clk1);
-
- endmodule

第一点:采用下降沿寄存器,下降沿寄存,可以保证下降沿到来之前输出端保持不变,这样就不会斩断当前时钟了
第二点:即使当前SELECT突然变化了,也必须等待到当前时钟的下降沿到来才能去使当前时钟无效,这一段时间就避免了毛刺
第二种:异步时钟
- 方法:将SEL信号与一个时钟域到另一个时钟域的反馈,进行打拍
- module asyn_clk_glitch_free(
- input wire clk0 ,
- input wire clk1 ,
- input wire rst ,
- input wire sel ,
- output wire clk_out
- );
- reg q0, q1, q2, q3;
-
- always @ (posedge clk0 or negedge rst)
- if(!rst)
- q0 <= 0;
- else
- q0 <= ~sel & ~q3;
-
- always@(negedge clk0 or negedge rst)
- if(!rst)
- q1 <= 0;
- else
- q1 <= q0;
-
- always @ (posedge clk1 or negedge rst)
- if(!rst)
- q2 <= 0;
- else
- q2 <= sel & ~q1;
-
- always@(negedge clk1 or negedge rst)
- if(!rst)
- q3 <= 0;
- else
- q3 <= q2;
-
- assign clk_out = (q1 & clk0) | (q3 & clk1);
-
- endmodule

同步时钟:两个同源时钟、两个同频(倍频)且同相或者两个同频(倍频)且有固定相位差
异步时钟:不同源、同源但频率比不是整数倍、同源虽频率比为整数倍但不满足时序要求
原理:利用公式1. Pi = ai ⊕ bi (可以写为ai + bi)2. Gi = aibi 3. Ci = Gi + Ci-1Pi 4. Si = Pi ⊕ Ci-1
无损定点化
将小数部分一直乘2直到出现小数部分小于0.5的次数,该次数即为最小位数的无损量化位数
计数器设计
数字电子技术基础(阎石)P100
线与逻辑
OD门
verilog阻塞与非阻塞的定义与区别
阻塞语句在Verilog中使用=运算符进行编码,并在创建组合逻辑时使用。该运算符阻止模拟器执行后续语句,直到完成当前求值和赋值。
非阻塞语句在 Verilog 中使用 <= 运算符进行编码,在时钟进程中对触发器进行编码时始终使用。赋值将推迟到计算完所有后续语句。 这允许并行或并发执行语句
格雷码转二级制码
verilog中function的使用
函数只能在模块中定义,位置任意,并在模块的任何地方引用,作用范围也局限于此模块。
特点:
1)不含有任何延迟、时序或时序控制逻辑
2)至少有一个输入变量
3)只有一个返回值,且没有输出
4)不含有非阻塞赋值语句
5)函数可以调用其他函数,但是不能调用任务
6)函数不能单独作为一条语句出现,只能放在赋值语言的右端
函数在声明时,会隐式的声明一个宽度为 range、 名字为 function_id 的寄存器变量,函数的返回值通过这个变量进行传递。当该寄存器变量没有指定位宽时,默认位宽为 1。
在 Verilog 中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。若某个函数在两个不同的地方同时并发的调用,那么两个函数调用行为同时对同一块地址进行操作,会导致不确定的函数结果。
Verilog 用关键字 automatic 来对函数进行说明,此类函数在调用时是可以自动分配新的内存空间的,也可以理解为是可递归的。因此,automatic 函数中声明的局部变量不能通过层次命名进行访问,但是 automatic 函数本身可以通过层次名进行调用。
阶乘例子:
- wire [31:0] results3 = factorial(4);
- function automatic integer factorial ;
- input integer data ;
- integer i ;
- begin
- factorial = (data>=2)? data * factorial(data-1) : 1 ;
- end
- endfunction // factorial
verilog中task的使用
任务更像一个过程,不仅能完成函数的功能,还可以包含时序控制逻辑。
特点:
a)任务可以没有或者有多个输入,且端口声明可以为 inout 型
b)任务可以没有或者有多个输出
c)任务没有返回值
d)任务可以在非零时刻执行
e)任务不能出现 always 语句,但可以包含其他时序控制,如延时语句
f)任务可以调用函数和任务
g)任务可以作为一条单独的语句出现语句块中
进行任务的逻辑设计时,可以把 input 声明的端口变量看做 wire 型,把 output 声明的端口变量看做 reg 型。但是不需要用 reg 对 output 端口再次说明。
- task xor_oper_iner;
- input [N-1:0] numa;
- input [N-1:0] numb;
- output [N-1:0] numco ;
- //output reg [N-1:0] numco ; //无需再注明 reg 类型,虽然注明也可能没错
- #3 numco = numa ^ numb ;
- //assign #3 numco = numa ^ numb ; //不用assign,因为输出默认是reg
- endtask
输入端连接的模块内信号可以是 wire 型,也可以是 reg 型。输出端连接的模块内信号要求一定是 reg 型,这点需要注意。
- G = B ^ (B >>1)
- B[i-1] = G[i-1] ^ B[i]
- // 用function封装起来的gray to bin
- function [5:0] gray2bin;
- input [5:0]gray_in;
- reg [5:0]gray_code;
- reg [5:0]bin_code;
- integer i,j;
- reg tmp;
- begin
- gray_code=gray_in;
- for(i=0;i<=5;i=i+1)
- begin
- tmp=1’b0;
- for(j=i;j<=5;j=j+1)
- tmp=gray_code^tmp;
- bin_code[i]=tmp;
- end
- gray2bin=bin_code;
- end
- endfunction
- assign data=gray2bin(gray_bin); //调用
-
- // 一种参数化格雷码转二进制码的方法
- module gray2bin (bin, gray);
- parameter SIZE = 4;
- output [SIZE-1:0] bin;
- input [SIZE-1:0] gray;
- reg [SIZE-1:0] bin;
- integer i;
- always @(gray)
- for (i=0; i<SIZE; i=i+1)
- bin[i] = ^(gray>>i);
- endmodule

同步fifo
- `timescale 1ns/1ns
-
- module syn_fifo#(
- parameter WIDTH = 8,
- parameter DEPTH = 16
- )(
- input clk ,
- input rst_n ,
- input winc ,
- input rinc ,
- input [WIDTH-1:0] wdata ,
-
- output reg wfull ,
- output reg rempty ,
- output wire [WIDTH-1:0] rdata
- );
- // 用localparam定义一个参数,可以在文件内使用
- localparam ADDR_WIDTH = $clog2(DEPTH);
-
- reg [ADDR_WIDTH:0] waddr;
- reg [ADDR_WIDTH:0] raddr;
- //第一部分---写地址产生逻辑
- always @ (posedge clk or negedge rst_n) begin
- if(~rst_n) begin
- waddr <= 'b0;
- end
- else begin
- if( winc && ~wfull ) begin
- waddr <= waddr + 1'b1;
- end
- else begin
- waddr <= waddr;
- end
- end
- end
- // 第二部分---读地址产生逻辑
- always @ (posedge clk or negedge rst_n) begin
- if(~rst_n) begin
- raddr <= 'b0;
- end
- else begin
- if( rinc && ~rempty ) begin
- raddr <= raddr + 1'b1;
- end
- else begin
- raddr <= raddr;
- end
- end
- end
-
- // 第三部分---读空以及写满信号产生
- always @ (posedge clk or negedge rst_n) begin
- if(~rst_n) begin
- wfull <= 'b0;
- rempty <= 'b0;
- end
- else begin
- wfull <= (raddr == {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH-1:0]});
- rempty <= (raddr == waddr);
- end
- end
-
- // 带有 parameter 参数的例化格式
- dual_port_RAM
- #(
- .DEPTH(DEPTH),
- .WIDTH(WIDTH)
- )
- dual_port_RAM_U0
- (
- .wclk(clk),
- .wenc(winc && ~wfull),
- .waddr(waddr[ADDR_WIDTH-1:0]),
- .wdata(wdata),
- .rclk(clk),
- .renc(rinc && ~rempty),
- .raddr(raddr[ADDR_WIDTH-1:0]),
- .rdata(rdata)
- );
- endmodule
-
- /**************RAM 子模块*************/
- // 该模块是一个简单双端口ram
- module dual_port_RAM #(parameter DEPTH = 16,
- parameter WIDTH = 8)(
- input wclk
- ,input wenc
- ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
- ,input [WIDTH-1:0] wdata //数据写入
- ,input rclk
- ,input renc
- ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
- ,output reg [WIDTH-1:0] rdata //数据输出
- );
-
- reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
-
- always @(posedge wclk) begin
- if(wenc)
- RAM_MEM[waddr] <= wdata;
- end
-
- always @(posedge rclk) begin
- if(renc)
- rdata <= RAM_MEM[raddr];
- end
-
- endmodule

RCA(行波进位加法器)
CSR(进位保存加法器)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。