sky06笔记下

本文详细介绍了数字逻辑设计中的边沿检测、计数器、状态机(如Mearly/Moore型)、移位寄存器以及FSM的应用,探讨了组合逻辑与时序逻辑的区别,并提供了可综合代码的建议,强调了控制path和datapath的区分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.边沿检测
检测输入信号din的上升沿,并输出pulse

module edge_check (
clk,
rstn,
din,
pulse
);
input wire clk,rstn;
input wire din;
output reg pulse;

wire din_dly;

always @(posedge clk or negedge rstn)begin
	if(!rstn)
		din_dly <= 1'b0;
	else
		din_dly <= din;		
end

pulse = din & (!din_dly);
endmodule

2.计数器

module counter(
clk,
rstn,
en,
cnt
);
input wire clk,rstn,en;
output reg [3:0] cnt;
always @(posedge clk or negedge rstn)begin
	if (!rstn)
		cnt <= 4'b0;
	else if (en)
		cnt <= cnt + 1;
	else 
		cnt <= cnt;
end
endmodule

testbench:

module tb_counter();

reg clk,rstn,en;

always #5 clk = ~clk;

initial begin
    clk = 0;
    rstn = 1;
    en = 0;
    #20;
    #1;
    rstn = 0;
    #30;
    rstn = 1;
    en = 1;
    #500;
    en = 0;
    #200;
    $finish();
end

counter u_counter(
    .clk    (clk),
    .rstn   (rstn),
    .en     (en),
    .cnt    (  )
);
endmodule

sim:
在这里插入图片描述

3.时序逻辑电路有rstn端,为什么组合电路没有?
电路由一堆时序逻辑和组合逻辑组成,如果时序逻辑全都复位到固定值,组合逻辑的输入也是固定值,那么组合逻辑的输出也是固定值。

4.移位寄存器shift-register
shift to higher bit

reg [3:0] sf;
always @(posedge clk)begin
	sf <= {sf[2:0],din};
end

shift to lower bit

reg [3:0] sf;
always @(posedge clk)begin
	sf <= {din,sf[3:1]};
end

双向shift:

reg [3:0] sf;
wire dir;
always @(posedge clk)begin
	if (dir == 0)
		sf <= {sf[2:0],din};
	else
		sf <= {din,sf[3:1]};
end

5.状态机类型
Mearly型:输出由当前状态和输入共同决定;
Moore型:输出只与当前状态有关。
实际工程设计中,主要关心逻辑功能,不太关心类型。因为在PPA上,没有明显优劣。
6.用FSM实现“1011”序列检测,每周期输入1bit,检测到1011后,在下一周期输出一个周期的高电平。

module detect(
clk,
rstn,
din,
en,
dout
);
input wire clk,rstn,din,en;
output reg dout;
reg [1:0] state,nstate;

parameter [1:0] s_idle = 00;
parameter [1:0] s_1 = 01;
parameter [1:0] s_10 = 10;
parameter [1:0] s_101 = 11;
//简洁写法parameter [1:0]  s_idle = 'd0, s_1 = 'd1, s_10 = 'd2, s_101 = 'd3;
//时序逻辑
always @(posedge clk or negedge rstn)begin
	if (!rstn)
		state <= s_idle;
	else if (en)
	  state <= nstate;	
end
always @(posedge clk or negedge rstn)
	if (!rstn)
		dout <= 1'b0;
	else if(en &&(state == s_101)&&din)
		dout <= 1'b1;
	else 
		dout <= 1'b0;
//组合逻辑
always @(*)begin
if(en)begin
	case(state)
		s_idle:if (din == 1) nstate = s_1; else nstate = s_idle;
		s_1:   if (din == 1) nstate = s_1; else nstate = s_10;
		s_10:  if (din == 1) nstate = s_101; else nstate = s_idle;
		s_101: if (din == 1) nstate = s_1; else nstate = s_10;
		default:nstate = s_idle;
	endcase
end
else 
	nstate = state;//en无效的话,次态等于现态。
endmodule

if ,else if 要配全,否则会综合出latch。
testbench:

module tb_detect();
    reg clk,rstn,din,en;
    wire dout;

    always #5 clk = ~clk;
    initial begin
        clk = 0;
        rstn = 1;
        din = 0;
        en =0;
        #20;
        #1;
        rstn = 0;
        #20;
        rstn = 1;
        en = 1;
        repeat(20)begin
			@(posedge clk) din <= {$random}%2; //产生20个随机1bit数
		end
        repeat(5) @(posedge clk);
        $finish();
    end
detect u_detect(
.clk (clk),
.rstn (rstn),
.din (din),
.en (en),
.dout (dout)
);
endmodule

在这里插入图片描述也可以s_idle,s_1,s_10,s_101,s_1011五种状态来写,但是state和nstate就需要3bit位宽来储存,会消耗更多的资源。
7.较长的序列检测,比如0110101,且中间有重叠部分。
用shift_register,以1011为例:

module detect_shift(
clk,
rstn,
en,
din,
match
);
input wire clk,rstn,en,din;
output reg match;

reg [2:0] shift_reg;
always @(posedge clk or negedge rstn)begin
	if(!rstn)
		shift_reg <= 3'b0;
	else
		shift_reg <= {shift_reg[1:0],din};
end
always @(posedge clk or negedge rstn)begin
	if(!rstn)
		match <= 1'b0;
	else if (en&&(shift_reg == 3'b101)&&din)
		match <= 1'b1;
	else
		match <= 1'b0;
end

//second way
/*
reg [3:0] shift_reg;
always @(posedge clk or negedge rstn)begin
	if(!rstn)
		shift_reg <= 4'b0;
	else
		shift_reg <= {shift_reg[2:0],din};
end
always @(posedge clk or negedge rstn)begin
	if(!rstn)
		match <= 1'b0;
	else if (en&&(shift_reg == 4'b1011))
		match <= 1'b1;
	else
		match <= 1'b0;
end

endmodule

在这里插入图片描述second way波形上看match信号在1011的后两个周期出现,不符合在下一周期输出一个周期的高电平。
在这里插入图片描述8.function组成
function [返回值位宽] 返回值(function name);
input [] xx;//可以有多个输入,但只有一个返回值
begin
……
end
endfunction
function通常用来描述组合逻辑的功能,因为function里面的语句不能有时延,#1, @posedge clk这种不能写。

9.task组成
task task_name;
input ;
output ;//可定义多个output
begin
@(posedge clk); #1;
end
endtask

function和task都是在module内部定义的,task可以直接访问module内已经定义好的reg变量,不能对wire型赋值。task可以有时延语句。
function可综合,task如果没有定义时延也可以综合。
系统function:$获取当前仿真时间。

19.一个实用功能通常分为两段主要逻辑功能:control path ;data path.
20.所有过程赋值语句块(always,initial)中的非阻塞赋值(<=)是同时进行的;
在同一个过程赋值语句块中,阻塞赋值(=)是顺序执行的;
在不同的过程赋值语句块中,阻塞赋值的循序语法没有定义。根据工具不同而不同。虽然在不可综合代码中,可以在两个always block里对同一个信号赋值,但是要避免在同一个时间点对其赋值,否者无法确定执行顺序。
21.可综合code建议
1.组合逻辑使用=赋值;
2.时序逻辑使用<=赋值;
3.#1(delay)可以用,综合会被忽略;
4.不要在多个语句块中,对同一个变量赋值,会导致多驱动,工具会报错。
5.在一个always块内,一次触发对同一个信号最多只赋值一次。以下情况不允许。可以通过多定义几个变量来解决。

always @(posedge clk)begin
if(add)
	mac <= mac_w;
if(sub)
	mac <= mac_w2;
end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值