数字IC设计/FPGA笔试代码汇总
26 Feb 2020 19977字 67分 次 Digital IC Design Verilog HDL打赏作者 CC BY 4.0 (除特别声明或转载文章外)
1 前言
总结一下数字IC设计和FPGA开发等笔试代码题。
2 边沿检测
位宽可定制的多bit信号边沿检测,输出一个周期宽度的脉冲信号:
//------------------------------------------------------------------------------
//
//Module Name: Edge_Detection.sv
//Department: Xidian University
//Function Description: 边沿检测
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-02-26
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Edge_Detection #(
parameter BIT_WIDTH = 8
)(
input clk,
input rst_n,
input [BIT_WIDTH-1:0] edge_in, //输入
output [BIT_WIDTH-1:0] edge_p, //上升沿输出
output [BIT_WIDTH-1:0] edge_n //下降沿输出
);
logic [BIT_WIDTH-1:0] edge_r1,edge_r2; //两级寄存
always_ff@(posedge clk, negedge rst_n) begin
if(!rst_n) begin
edge_r1 <= #1 '0;
edge_r2 <= #1 '0;
end
else begin
edge_r1 <= #1 edge_in;
edge_r2 <= #1 edge_r1;
end
end
assign edge_p = edge_r1 & ~edge_r2;
assign edge_n = ~edge_r1 & edge_r2;
endmodule
3 串转并
位宽可定制的串转并模块:
//------------------------------------------------------------------------------
//
//Module Name: Deserializer.v
//Department: Xidian University
//Function Description: 解串器
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-02-26
//
//-----------------------------------------------------------------------------------
//
//Version Modified History
//V1.0 位宽可定制的串转并模块
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Deserializer #(
parameter DATA_WIDTH = 8,
MSB_LSB = 1 //MSB先为1,LSB先为0
)(
input clk,
input rst_n,
input data_in,
output reg [DATA_WIDTH-1:0] data_out
);
//位宽计算函数
function integer clogb2 (input integer depth);
begin
for (clogb2=0; depth>0; clogb2=clogb2+1)
depth = depth >>1;
end
endfunction
logic [clogb2(DATA_WIDTH)-1:0] cnt;
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
cnt <= #1 '0;
else if(cnt >= DATA_WIDTH-1)
cnt <= #1 '0;
else
cnt <= #1 cnt + 1;
end
logic [DATA_WIDTH-1:0] data_out_r;
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
data_out_r <= #1 '0;
else
case(MSB_LSB)
1'b0:data_out_r <= #1 {data_in,data_out_r[DATA_WIDTH-1:1]};
1'b1:data_out_r <= #1 {data_out_r[DATA_WIDTH-2:0],data_in};
endcase
end
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
data_out <= #1 '0;
else if(cnt == DATA_WIDTH-1)
data_out <= #1 data_out_r;
else
data_out <= #1 data_out;
end
endmodule
4 序列检测器
有“1011”序列输入时输出为1,其他情况下输出为0:
//------------------------------------------------------------------------------
//
//Module Name: Sequence_Detection.sv
//Department: Xidian University
//Function Description: 序列检测器
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-02-26
//
//-----------------------------------------------------------------------------------
//
//Version Modified History
//V1.0
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Sequence_Detection (
input clk,
input rst_n,
input data_in, //数据输入
output reg flag //检测到1011输出一个周期的高电平
);
//===============================================
//三段式状态机
//-----------------------------------------------
//枚举法 四个状态
enum reg [1:0]{
zero,
one,
two,
three
}state,next_state;
//-----------------------------------------------
//状态解码
always_comb begin
case(state)
zero:begin
if(data_in)
next_state = one;
else
next_state = zero;
end
one:begin
if(data_in)
next_state = one;
else
next_state = two;
end
two:begin
if(data_in)
next_state = three;
else
next_state = zero;
end
three: next_state = zero;
default:next_state = zero;
endcase
end
//-----------------------------------------------
//状态转换
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
state <= #1 zero;
else
state <= #1 next_state;
end
//-----------------------------------------------
//输出
always_comb begin
case(state)
zero: flag = '0;
one: flag = '0;
two: flag = '0;
three: begin
if(data_in)
flag = '1;
else
flag = '0;
end
default:flag = '0;
endcase
end
endmodule
5 异步复位同步释放
同步复位要求复位有效信号需要保持一个周期才能被采集,异步复位的问题在于,如果异步复位信号在触发器时钟有效沿附近“释放”(复位信号从有效变为无效)的话,可能会导致触发器输出的亚稳态。所以需要将异步复位的释放信号打一拍:
//------------------------------------------------------------------------------
//
//Module Name: Asy_Rst_Syn.sv
//Department: Xidian University
//Function Description: 异步复位同步释放
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana 2019-7-8
//
//-----------------------------------------------------------------------------------
module Asy_Rst_Syn(
input clk, //时钟
input rst_n, //异步复位
output asy_rst_n //异步复位同步释放
);
//----------------------------------------------
reg [1:0] rst_shift;
always_ff@(posedge clk, negedge rst_n) begin
if(!rst_n)
rst_shift[1:0] <= #1 2'b00;
else
rst_shift[1:0] <= #1 {rst_shift[0],1'b1};
end
assign asy_rst_n = rst_shift[1];
endmodule
6 门控时钟
直接将时钟和使能信号相与显然不太行,会有毛刺,所以需要用到一个锁存器:
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-02-28
//
//-----------------------------------------------------------------------------------
//
//Version Modified History
//V1.0
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Clock_Gating_Cell(
input clk, //时钟
input en, //使能
output gclk //门控时钟
);
logic en_latch; //锁存后的使能信号
//=================================================
//锁存器锁存使能信号
always_latch begin
if(!clk)
en_latch = en;
end
//=================================================
//产生门控时钟
assign gclk = clk & en_latch;
endmodule
7 时钟切换电路
直接用MUX显然是不行,会产生毛刺。所以要用一個類似RS鎖存器的結構:
//------------------------------------------------------------------------------
//
//Module Name: Clock_Switch.sv
//Department: Xidian University
//Function Description: 时钟切换
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-02-27
//
//-----------------------------------------------------------------------------------
//
//Version Modified History
//V1.0
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Clock_Switch(
input clk_a, //时钟a
input clk_b, //时钟b
input rst_n, //复位
input select, //时钟切换,0为时钟a
output clk_out //切换后的时钟
);
logic decide_a,decide_b; //select和另一时钟域同步后的decide相与的结果
logic out_a_p,out_a_n; //时钟a域对decide的两级同步
logic out_b_p,out_b_n; //时钟b域对decide的两级同步
assign decide_a = ~select & ~out_b_n; //select为0且同步后的信号为0
assign decide_b = select & ~out_a_n; //select为0且同步后的信号为1
//=================================================================
//A时钟域正负沿两级同步
always_ff@(posedge clk_a, negedge rst_n)begin
if(!rst_n)
out_a_p <= #1 '0;
else
out_a_p <= #1 decide_a;
end
always_ff@(negedge clk_a, negedge rst_n)begin
if(!rst_n)
out_a_n <= #1 '0;
else
out_a_n <= #1 out_a_p;
end
//=================================================================
//B时钟域正负沿两级同步
always_ff@(posedge clk_b, negedge rst_n)begin
if(!rst_n)
out_b_p <= #1 '0;
else
out_b_p <= #1 decide_b;
end
always_ff@(negedge clk_b, negedge rst_n)begin
if(!rst_n)
out_b_n <= #1 '0;
else
out_b_n <= #1 out_b_p;
end
assign clk_out = (out_a_n & clk_a) | (out_b_n & clk_b); //输出
endmodule
其中两级寄存是为了消除ab时钟不同源情况下的亚稳态;负边沿触发的寄存器不能改为正边沿触发,否则还是会产生毛刺;前一级寄存正负边沿触发均可,这里用正边沿触发是为了缩短间隔时间。实现电路参考站点:防止毛刺的时钟切换电路的设计思想。
8 跨时钟域信号传输
8.1 慢时钟域到快时钟域
1bit信号从慢时钟域同步到快时钟域:
//------------------------------------------------------------------------------
//
//Module Name: Asy_Signal_Transmission.sv
//Department: Xidian University
//Function Description: 跨时钟域信号传输(慢到快)
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-3-1
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Asy_Signal_Transmission(
input clk,
input rst_n,
input data_in,
input data_out
);
reg [1:0] data_r;
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
data_r <= #1 '0;
else
data_r <= #1 {data_r[0],data_in};
end
assign data_out = data_r[1];
endmodule
8.2 快时钟域到慢时钟域
1bit信号从快时钟域同步到慢时钟域,这时候用双寄存是不可靠的,例如快时钟域的信号高电平持续时间远小于慢时钟域的时钟周期且不在慢时钟的上升沿发生。
第一个解决方法是结绳法:
//------------------------------------------------------------------------------
//
//Module Name: Asy_Signal_Transmission.sv
//Department: Xidian University
//Function Description: 跨时钟域信号传输(快到慢)
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-3-1
//
//------------------------------------------------------------------------------
`timescale 1ns/1ns
module Asy_Signal_Transmission(
input clk, //慢时钟
input data_in, //数据输入
output data_out //数据输出
);
logic clr_n; //寄存器清零
logic data_r [4]; //四级寄存
assign clr_n = data_r[2] & data_r[3]; //输出一个脉冲后立即清零清零
//===================================================
//两级寄存器同步
always_ff@(posedge data_in, posedge clr_n)begin
if(clr_n)
data_r[0] <= #1 '0;
else
data_r[0] <= #1 '1;
end
always_ff@(posedge clk, posedge clr_n)begin
if(clr_n)
data_r[1] <= #1 '0;
else
data_r[1] <= #1 data_r[0];
end
//===================================================
//多一级寄存判断输出
always_ff@(posedge clk, posedge clr_n)begin
if(clr_n)
data_r[2] <= #1 '0;
else
data_r[2] <= #1 data_r[1];
end
always_ff@(posedge clk, posedge clr_n)begin
if(clr_n)
data_r[3] <= #1 '0;
else
data_r[3] <= #1 data_r[2];
end
//===================================================
//输出
assign data_out = data_r[2] && ~data_r[3];
endmodule
结绳法不需要用到快时钟,而输出信号的脉冲只有一个时钟周期。
还有一种方法是对输入信号的脉冲进行拓展:
//------------------------------------------------------------------------------
//
//Module Name: Asy_Signal_Transmission.sv
//Department: Xidian University
//Function Description: 跨时钟域信号传输(快到慢)
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-3-1
//
//------------------------------------------------------------------------------
`timescale 1ns/1ns
module Asy_Signal_Transmission(
input clk_a, //慢时钟
input clk_b, //快时钟
input rst_n,
input data_in, //数据输入
output data_out //数据输出
);
logic data_expand_a;
logic [1:0] data_r_b;
logic [1:0] data_r_a;
//================================================
//在慢时钟域拓展输入信号
always_ff@(posedge clk_a, negedge rst_n)begin
if(!rst_n)
data_expand_a = #1 '0;
else if(data_in)
data_expand_a = #1 '1;
else if(data_r_a[1])
data_expand_a = #1 '0;
else
data_expand_a = #1 data_expand_a;
end
//================================================
//将拓展后的信号同步到快时钟域
always_ff@(posedge clk_b, negedge rst_n)begin
if(!rst_n)
data_r_b = #1 '0;
else
data_r_b = #1 {data_r_b[0],data_expand_a};
end
//================================================
//输出
assign data_out = data_r_b[1];
//================================================
//将快时钟域的拓展信号同步到慢时钟域
always_ff@(posedge clk_a, negedge rst_n)begin
if(!rst_n)
data_r_a = #1 '0;
else
data_r_a = #1 {data_r_a[0],data_r_b[1]};
end
endmodule
当输入信号的脉冲大于三个时钟周期时,输出信号才能正确反映脉冲宽度。
9 异步双端口RAM
位宽、深度可定制,A口读出,B口写入,支持片选和读写请求的异步双端口RAM:
//------------------------------------------------------------------------------
//
//Module Name: Asy_DPRAM.sv
//Department: Xidian University
//Function Description: 异步双端口RAM
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-2-26
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Asy_DPRAM #(
parameter DATA_WIDTH = 8,
ADDR_WIDTH = 8
)(
input clk_a,
input clk_b,
input rst_n,
input cs_n,
input en_a,
input [ADDR_WIDTH-1:0] addr_a,
output reg [DATA_WIDTH-1:0] data_a,
input en_b,
input [ADDR_WIDTH-1:0] addr_b,
input [DATA_WIDTH-1:0] data_b,
);
parameter DATA_DIPTH = 1 << ADDR_WIDTH;
reg [DATA_WIDTH-1:0] ram [DATA_DIPTH];
always_ff@(posedge clk_a, negedge rst_n)begin
if(!rst_n)
data_a <= #1 '0;
else if(!cs_n&en_a)
data_a <= #1 ram[addr_a];
else
data_a <= #1 data_a;
end
always_ff@(posedge clk_b, negedge rst_n) begin
if(!rst_n)begin
for(int i=0;i<DATA_DIPTH;i++)
ram[addr_b] <= #1 '0;
end
else if(!cs_n&en_b)
ram[addr_b] <= #1 data_b;
end
endmodule
10 任意奇数分频器
//------------------------------------------------------------------------------
//
//Module Name: Odd_Frequency_Divider.v
//Department: Xidian University
//Function Description: 任意奇数分频器
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2020-2-22
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Odd_Frequency_Divider #(
parameter DIV_COEFF = 3
)(
input clk,
input rst_n,
input en,
output clk_out
);
//位宽计算函数
function integer clogb2 (input integer depth);
begin
for (clogb2=0; depth>0; clogb2=clogb2+1)
depth = depth >>1;
end
endfunction
reg [clogb2(DIV_COEFF)-1:0] cnt;
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
cnt <= #1 '0;
else if(cnt >= DIV_COEFF-1)
cnt <= #1 '0;
else
cnt <= cnt + 1;
end
logic clk_pos,clk_neg;
always_ff@(posedge clk, negedge rst_n)begin
if(!rst_n)
clk_pos <= #1 '0;
else if(cnt <= (DIV_COEFF-1)/2)
clk_pos <= #1 '1;
else
clk_pos <= #1 '0;
end
always_ff@(negedge clk, negedge rst_n)begin
if(!rst_n)
clk_neg <= #1 '0;
else if(cnt <= (DIV_COEFF-1)/2)
clk_neg <= #1 '1;
else
clk_neg <= #1 '0;
end
assign clk_out = clk_pos & clk_neg;
endmodule
11 同步FIFO
位宽、深度可定制的同步FIFO:
//------------------------------------------------------------------------------
//
//Module Name: Syn_FIFO.sv
//Department: Xidian University
//Function Description: 同步FIFO
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2019-11-2
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Syn_FIFO# (
parameter DATA_WIDTH = 8, //定义FIFO数据位宽、地址位宽
parameter ADDR_WIDTH = 8
)(
/************ 时钟和复位 ************/
input clk, //时钟
input rst_n, //复位
/************ 读写使能 *************/
input wr_en, //写使能
input rd_en, //读使能
/*********** 数据输入输出 ***********/
input [DATA_WIDTH-1:0] data_in, //数据输入
output reg [DATA_WIDTH-1:0] data_out, //数据输出
/************* 标志位 *************/
output full, //满标志
output empty //空标志
);
parameter FIFO_DEPTH = (1 << ADDR_WIDTH); //根据FIFO地址位宽定制FIFO深度
logic wr_en_r;
logic rd_en_r;
logic [ADDR_WIDTH :0] wr_pointer; //写指针
logic [ADDR_WIDTH :0] rd_pointer; //读指针
logic [ADDR_WIDTH-1:0] wr_addr;
logic [ADDR_WIDTH-1:0] rd_addr;
reg [DATA_WIDTH-1:0] fifo [FIFO_DEPTH]; //寄存器组
//==============================================================
//使能同步
always_ff@(posedge clk, negedge rst_n) begin
if(!rst_n) begin
wr_en_r <= #1 1'b0;
rd_en_r <= #1 1'b0;
end
else begin
wr_en_r <= #1 wr_en;
rd_en_r <= #1 rd_en;
end
end
//==============================================================
//指针递增
always_ff@(posedge clk, negedge rst_n) begin
if(!rst_n)begin
wr_pointer <= #1 '0;
end
else if(wr_en_r && (!full)) begin
wr_pointer <= #1 wr_pointer + 1;
end
end
always_ff@(posedge clk, negedge rst_n) begin
if(!rst_n)begin
rd_pointer <= #1 '0;
end
else if(rd_en_r && (!empty)) begin
rd_pointer <= #1 rd_pointer + 1;
end
end
//==============================================================
//读写地址
assign wr_addr = wr_pointer[ADDR_WIDTH-1:0];
assign rd_addr = rd_pointer[ADDR_WIDTH-1:0];
//==============================================================
//读写
always_ff@(posedge clk)begin
if(wr_en_r && (!full))
fifo[wr_addr] <= #1 data_in;
end
always_ff@(posedge clk)begin
if(rd_en_r && (!empty))
data_out <= #1 fifo[rd_addr];
end
//==============================================================
//空满判断
assign full = ( wr_pointer == {~rd_pointer[ADDR_WIDTH],rd_pointer[ADDR_WIDTH-1:0]} );
assign empty = ( wr_pointer == rd_pointer );
endmodule
12 异步FIFO
位宽、深度可定制的异步FIFO:
//------------------------------------------------------------------------------
//
//Module Name: Asy_FIFO.v
//Department: Xidian University
//Function Description: 异步FIFO
//
//------------------------------------------------------------------------------
//
//Version Design Coding Simulata Review Rel data
//V1.0 Verdvana Verdvana Verdvana 2019-6-22
//
//-----------------------------------------------------------------------------------
`timescale 1ns/1ns
module Asy_FIFO #(
parameter DATA_WIDTH = 8,
parameter ADDR_WIDTH = 8
)(
/************* 时钟 *************/
input wr_clk,
input rd_clk,
/************* 使能 *************/
input wr_en,
input rd_en,
/************* 复位 *************/
input rst_n,
/************* 标志 *************/
output full,
output empty,
/************* 数据 *************/
input [DATA_WIDTH-1:0] data_in,
output reg [DATA_WIDTH-1:0] data_out
);
//==============================================================
//信號定义
parameter FIFO_DEPTH = ( 1 << ADDR_WIDTH ); //FIFO深度定义
reg [DATA_WIDTH-1:0] fifo [FIFO_DEPTH]; //寄存器组,存储数据
logic wr_en_r; //写使能寄存
logic rd_en_r; //读使能寄存
logic [ADDR_WIDTH-1:0] wr_addr; //写地址
logic [ADDR_WIDTH-1:0] rd_addr; //读地址
logic [ADDR_WIDTH :0] wr_pointer; //写指针
logic [ADDR_WIDTH :0] rd_pointer; //读指针
logic [ADDR_WIDTH :0] wr_addr_gray; //写地址格雷码
logic [ADDR_WIDTH :0] rd_addr_gray; //读地址格雷码
logic [ADDR_WIDTH :0] wr_addr_gray_d1; //消除亚稳态一级寄存器
logic [ADDR_WIDTH :0] wr_addr_gray_d2; //消除亚稳态二级寄存器
logic [ADDR_WIDTH :0] rd_addr_gray_d1; //消除亚稳态一级寄存器
logic [ADDR_WIDTH :0] rd_addr_gray_d2; //消除亚稳态二级寄存器
//==============================================================
//寄存使能信号
always_ff@(posedge wr_clk)begin
wr_en_r <= #1 wr_en;
end
always_ff@(posedge rd_clk)begin
rd_en_r <= #1 rd_en;
end
//==============================================================
//读写指针递增
always_ff@(posedge wr_clk, negedge rst_n) begin
if(!rst_n)
wr_pointer <= #1 'h0;
else if(wr_en_r && (~full))
wr_pointer <= #1 wr_pointer + 1;
else
wr_pointer <= #1 wr_pointer;
end
always_ff@(posedge rd_clk, negedge rst_n) begin
if(!rst_n)
rd_pointer <= #1 'h0;
else if(rd_en_r && (~empty))
rd_pointer <= #1 rd_pointer + 1;
else
rd_pointer <= #1 rd_pointer;
end
//==============================================================
//产生读写地址
assign wr_addr = wr_pointer[ADDR_WIDTH-1:0]; //写地址为写指针去掉最高位
assign rd_addr = rd_pointer[ADDR_WIDTH-1:0]; //读地址为读指针去掉最高位
//==============================================================
//读写
always_ff@(posedge wr_clk) begin
if(wr_en_r && (~full))
fifo[wr_addr] <= #1 data_in;
end
always_ff@(posedge rd_clk) begin
if(rd_en_r && (~empty))
data_out <= #1 fifo[rd_addr];
end
//==============================================================
//产生读写地址格雷码
assign wr_addr_gray = (wr_pointer >> 1) ^ wr_pointer; //产生写地址格雷码
assign rd_addr_gray = (rd_pointer >> 1) ^ rd_pointer; //产生读地址格雷码
//==============================================================
//寫指针格雷码同步化
always_ff@(posedge rd_clk ) begin
wr_addr_gray_d1 <= #1 wr_addr_gray; //将写地址的格雷码转移到读时钟域,方便与读地址格雷码比较
wr_addr_gray_d2 <= #1 wr_addr_gray_d1; //两级触发消除亚稳态
end
//==============================================================
//读指针格雷码同步化
always_ff@(posedge wr_clk) begin
rd_addr_gray_d1 <= #1 rd_addr_gray; //将读地址的格雷码转移到写时钟域,方便与写地址格雷码比较
rd_addr_gray_d2 <= #1 rd_addr_gray_d1; //两级触发消除亚稳态
end
//==============================================================
//空满判断
assign full = (wr_addr_gray == {~(rd_addr_gray_d2[ADDR_WIDTH-:2]),rd_addr_gray_d2[ADDR_WIDTH-2:0]}); //写地址格雷码与读地址同步后的格雷码的高两位不同 即为满
assign empty = ( rd_addr_gray == wr_addr_gray_d2 );
endmodule
13 加法器
13.1 半加器
module Half_Adder(
input logic a,b, //输入
output logic c,s //结果位和进位位
);
assign c = a && b;
assign s = a ^ b;
//assign {c,s} = a + b;
endmodule
13.2 全加器
module Full_Adder(
input logic a,b,cin //输入
output logic cout,s //结果位和进位位
);
assign c = (a && b) || (cin && (a || b));
assign s = a ^ b ^ cin;
endmodule
14 减法器
14.1 半减器
module Half_Subtractor(
input logic a,b, //输入
output logic c,s //结果位和进位位
);
assign c = !a && b;
assign s = a ^ b;
endmodule
14.2 全减器
module Full_Subtractor(
input logic a,b,cin //输入
output logic cout,s //结果位和进位位
);
assign c = (a && !b) || (!cin && a) || (cin && b);
assign s = a ^ b ^ cin;
endmodule
15 乘法器
15.1 移位相加乘法器
告辞