文章目录
前言
HDL- bits 记录
HDL-bits
一、Verilog language
1. basic
1. Four wires
Create a module with 3 inputs and 4 outputs that behaves like wires that makes these connections:
a -> w
b -> x
b -> y
c -> z
module top_module(
input a,b,c,
output w,x,y,z );
assign w = a;
assign x = b;
assign y = b;
assign z = c;
endmodule
2. Inverter
Create a module that implements a NOT gate.
module top_module( input in, output out );
assign out = ~in;
endmodule
3. NOR gate
Verilog has separate bitwise-OR (|) and logical-OR (||) operators
module top_module(
input a,
input b,
output out );
assign out = !(a || b);
or assign out = !(a | b);
endmodule
4. XNOR gate
The bitwise-XOR operator is ^. There is no logical-XOR operator.
module top_module(
input a,
input b,
output out );
assign out = ~(a^b);
endmodule
5. Declaring wires
module top_module (
input in, // Declare an input wire named "in"
output out // Declare an output wire named "out"
);
wire not_in; // Declare a wire named "not_in"
assign out = ~ not_in; // Assign a value to out (create a NOT gate).
assign not_in = ~ in; // Assign a value to not_in (create another NOT gate).
endmodule // End of module "top_module"
`default_nettype none
module top_module(
input a,
input b,
input c,
input d,
output out,
output out_n );
wire two_wires, one_wires;
assign two_wires = a & b;
assign one_wires = two_wires || (c & d);
assign out_n = ~one_wires;
assign out = one_wires;
endmodule
wire w1, w2; // Declare two wires (named w1 and w2)
assign w1 = a&b; // First AND gate
assign w2 = c&d; // Second AND gate
assign out = w1|w2; // OR gate: Feeds both 'out' and the NOT gate
assign out_n = ~out; // NOT gate
6. 7458 chip
module top_module (
input p1a, p1b, p1c, p1d, p1e, p1f,
output p1y,
input p2a, p2b, p2c, p2d,
output p2y );
wire w1,w2,w3,w4;
assign w1 = p1a & p1b & p1c;
assign w2 = p1d & p1e & p1f;
assign w3 = p2a & p2b;
assign w4 = p2c & p2d;
assign p2y = w3 || w4;
assign p1y = w1 || w2;
endmodule
2. Vectors
1. Vectors
wire [99:0] my_vector; // Declare a 100-element vector
assign out = my_vector[10]; // Part-select one bit out of the vector
module top_module (
input wire [2:0] vec,
output wire [2:0] outv,
output wire o2,
output wire o1,
output wire o0 ); // Module body starts after module declaration
assign outv = vec;
assign o0 = vec[0];
assign o1 = vec[1];
assign o2 = vec[2];
assign {o2,o1,o0} = vec;
endmodule
2. Vectors in more detail
Declaring Vectors
wire [7:0] w; // 8-bit wire
reg [4:1] x; // 4-bit reg
output reg [0:0] y; // 1-bit reg that is also an output port (this is still a vector)
input wire [3:-2] z; // 6-bit wire input (negative ranges are allowed)
output [3:0] a; // 4-bit output wire. Type is 'wire' unless specified otherwise.
wire [0:7] b; // 8-bit wire where b[0] is the most-significant bit.
Implicit nets
wire [2:0] a, c; // Two vectors
assign a = 3'b101; // a = 101
assign b = a; // b = 1 implicitly-created wire
assign c = b; // c = 001 <-- bug
my_module i1 (d,e); // d and e are implicitly *one-bit wide* if not declared.
// This could be a bug *if the port was intended to be a vector*.
Adding `default_nettype none would make the second line of code an error, which makes the bug more visible.
Unpacked vs. Packed Arrays
reg [7:0] mem [255:0]; // 256 unpacked elements, each of which is a 8-bit packed vector of reg.
reg mem2 [28:0]; // 29 unpacked elements, each of which is a 1-bit reg.
Accessing Vector Elements: Part-Select
w[3:0] // Only the lower 4 bits of w
x[1] // The lowest bit of x
x[1:1] // ...also the lowest bit of x
z[-1:-2] // Two lowest bits of z
b[3:0] // Illegal. Vector part-select must match the direction of the declaration.
b[0:3] // The *upper* 4 bits of b.
assign w[3:0] = b[0:3]; // Assign upper 4 bits of b to lower 4 bits of w. w[3]=b[0], w[2]=b[1], etc.
A Bit of Practice
Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper [15:8] bytes.
`default_nettype none // Disable implicit nets. Reduces some types of bugs.
module top_module(
input wire [15:0] in,
output wire [7:0] out_hi,
output wire [7:0] out_lo );
assign out_hi = in[15:8];
assign out_lo = in[7:0];
// Concatenation operator also works: assign {out_hi, out_lo} = in;
endmodule
3. Vector part select
A 32-bit vector can be viewed as containing 4 bytes (bits [31:24], [23:16], etc.). Build a circuit that will reverse the byte ordering of the 4-byte word.
AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa
module top_module (
input [31:0] in,
output [31:0] out
);
assign out[31:24] = in[ 7: 0];
assign out[23:16] = in[15: 8];
assign out[15: 8] = in[23:16];
assign out[ 7: 0] = in[31:24];
endmodule
4. bitwise operators
module top_module(
input [2:0] a,
input [2:0] b,
output [2:0] out_or_bitwise,
output out_or_logical,
output [5:0] out_not
);
assign out_or_bitwise = a | b;
assign out_or_logical = a || b;
assign out_not[2:0] = ~a; // Part-select on left side is o.
assign out_not[5:3] = ~b; //Assigning to [5:3] does not conflict with [2:0]
endmodule
4. Four-input gates
Build a combinational circuit with four inputs, in[3:0].
There are 3 outputs:
out_and: output of a 4-input AND gate.
out_or: output of a 4-input OR gate.
out_xor: output of a 4-input XOR gate.
module top_module(
input [3:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = ∈
assign out_or = |in;`在这里插入代码片`
assign out_xor = ^in;
endmodule
5. vector concatenate operator
{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010 // 4'ha and 4'd10 are both 4'b1010 in binary
input [15:0] in;
output [23:0] out;
assign {out[7:0], out[15:8]} = in; // Swap two bytes. Right side and left side are both 16-bit vectors.
assign out[15:0] = {in[7:0], in[15:8]}; // This is the same thing.
assign out = {in[7:0], in[15:8]}; // This is different. The 16-bit vector on the right is extended to
// match the 24-bit vector on the left, so out[23:16] are zero.
// In the first two examples, out[23:16] are not assigned.
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );
assign {w,x,y,z} = {a, b, c, d, e, f,2'b11};
endmodule
6. Vector reversal 1
Given an 8-bit input vector [7:0], reverse its bit ordering.
module top_module (
input [7:0] in,
output [7:0] out
);
assign {out[0],out[1],out[2],out[3],out[4],out[5],out[6],out[7]} = in;
/*
// I know you're dying to know how to use a loop to do this:
// Create a combinational always block. This creates combinational logic that computes the same result
// as sequential code. for-loops describe circuit *behaviour*, not *structure*, so they can only be used
// inside procedural blocks (e.g., always block).
// The circuit created (wires and gates) does NOT do any iteration: It only produces the same result
// AS IF the iteration occurred. In reality, a logic synthesizer will do the iteration at compile time to
// figure out what circuit to produce. (In contrast, a Verilog simulator will execute the loop sequentially
// during simulation.)
always @(*) begin
for (int i=0; i<8; i++) // int is a SystemVerilog type. Use integer for pure Verilog.
out[i] = in[8-i-1];
end
// It is also possible to do this with a generate-for loop. Generate loops look like procedural for loops,
// but are quite different in concept, and not easy to understand. Generate loops are used to make instantiations
// of "things" (Unlike procedural loops, it doesn't describe actions). These "things" are assign statements,
// module instantiations, net/variable declarations, and procedural blocks (things you can create when NOT inside
// a procedure). Generate loops (and genvars) are evaluated entirely at compile time. You can think of generate
// blocks as a form of preprocessing to generate more code, which is then run though the logic synthesizer.
// In the example below, the generate-for loop first creates 8 assign statements at compile time, which is then
// synthesized.
// Note that because of its intended usage (generating code at compile time), there are some restrictions
// on how you use them. Examples: 1. Quartus requires a generate-for loop to have a named begin-end block
// attached (in this example, named "my_block_name"). 2. Inside the loop body, genvars are read only.
generate
genvar i;
for (i=0; i<8; i = i+1) begin: my_block_name
assign out[i] = in[8-i-1]; 这样不行
end
endgenerate
*/
endmodule
7. replication
{num{vector}} This replicates vector by num times. num must be a constant. Both sets of braces are required.
Examples:
{5{1'b1}} // 5'b11111 (or 5'd31 or 5'h1f)
{2{a,b,c}} // The same as {a,b,c,a,b,c}
{3'd5, {2{3'd6}}} // 9'b101_110_110. It's a concatenation of 101 with
// the second vector, which is two copies of 3'b110.
module top_module (
input [7:0] in,
output [31:0] out );//
// assign out = { replicate-sign-bit , the-input };
assign out = {{24{in[7]}},in};
endmodule
module top_module (
input a, b, c, d, e,
output [24:0] out );
// The output is XNOR of two vectors created by
// concatenating and replicating the five inputs.
// assign out = ~{ ... } ^ { ... };
assign out = ~{{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}} ^ {{5{a,b,c,d,e}}};
endmodule
3. Modules: Hierarchy
1. Modules
module mod_a ( input in1, input in2, output out );
// Module body
endmodule
1. By position
mod_a instance1 ( wa, wb, wc );
connects signal wa (outside the new module) to the first port (in1) of the new module, wb to the second port (in2), and wc to the third port (out).
2. By name
mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );
module top_module ( input a, input b, output out );
//mod_a instance1( .out(out), .in1(a), .in2(b));
mod_a instance2(a,b,out);
endmodule
2. Three Modules
module my_dff ( input clk, input d, output q );
module top_module ( input clk, input d, output q );
wire q1, q2;
my_dff inst1(clk, d, q1);
my_dff inst2(clk, q1, q2);
my_dff inst3(clk, q2, q );
endmodule
3. Module shift8
module my_dff8 ( input clk, input [7:0] d, output [7:0] q );
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
logic [7:0] q1, q2, q3;
my_dff8 fifo1(clk, d, q1);
my_dff8 fifo2(clk, q1, q2);
my_dff8 fifo3(clk, q2, q3);
always @(*) begin
case(sel)
2'b00: begin q = d; end // 注意这里不能用 assign q = d; 编译不通过
2'b01: begin q = q1; end
2'b10: begin q = q2; end
2'b11: begin q = q3; end
endcase
end
endmodule
4. Adder1
16-bit a + b + cin
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout;
reg [15:0] sum1,sum2;
add16 low_bit (a[15:0], b[15:0], 0, sum1[15:0], cout);
add16 high_bit(a[31:16], b[31:16],cout,sum2[15:0], 0);
assign sum = {sum2[15:0],sum1[15:0]};
endmodule
5. Adder2***
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
module add1 ( input a, input b, input cin, output sum, output cout );
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout;
reg [15:0] sum1,sum2;
add16 low_bit (a[15:0], b[15:0], 0, sum1,cout);
add16 high_bit (a[31:16],b[31:16],cout,sum2,0);
assign sum = {sum2,sum1};
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
//assign sum = a^b^cin;
//assign cout = a&b | a&cin | b&cin;
assign {cout,sum} = a+b+cin;
endmodule
6. carry-select addr
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout;
reg [15:0] sum1,sum2,sum3; //wire [15:0] sum1,sum2,sum3;
add16 low_bit(a[15:0], b[15:0], 0, sum1, cout);
add16 hi1_bit(a[31:16], b[31:16], 0, sum2, 0); //cout 一定要为0,或者不写,否则编译不通过
add16 hi2_bit(a[31:16], b[31:16], 1, sum3, 0);
always@(*) begin
case(cout)
0: begin sum = {sum2,sum1}; end
1: begin sum = {sum3,sum1}; end
endcase
end
endmodule
7. Addr-subtractor
module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );
`default_nettype none
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire cout;
wire [31:0] c;
wire [15:0] sum1, sum2;
assign c = b^{32{sub}};
假如是assign c = b^sub; 会dismatch,因为sub是1bit
//if sub=1,c=~b; if sub = 0,c=b;
add16 low (a[15:0], c[15:0], sub, sum1, cout);
add16 high(a[31:16], c[31:16], cout, sum2, 0);
assign sum = {sum2,sum1};
endmodule
Procedures
1. always blocks(combinational, clocked)
For synthesizing hardware, two types of always blocks are relevant:
- Combinational: always @(*)
- Clocked: always @(posedge clk)
程序块中的连续赋值不要写,虽然可以写,但是不能合成电路;
两者都将在任何输入(右侧)改变值时重新计算输出:
assign out1 = a & b | c ^ d;
always @(*) out2 = a & b | c ^ d;
赋值语句的左手边必须是网络类型(例如,wire),而过程赋值语句的左手边(在always块中)必须是变量类型(例如,reg)。
在有时钟的always块中,使用非阻塞赋值。
// synthesis verilog_input_version verilog_2001
module top_module(
input clk,
input a,
input b,
output wire out_assign,
output reg out_always_comb,
output reg out_always_ff );
assign out_assign = a^b;
always @(*) begin
out_always_comb = a^b;
end
always @(posedge clk) begin
out_always_ff <= a^b;
end
endmodule
2. if statement
1. assign out = (condition) ? x : y;
2. always @(*) begin
if (condition) begin
out = x;
end
else begin
out = y;
end
end
学习如何避免产生 latch, 比如在 always 块中所列举的情况没有完全,会出现你没有列举的情况时,那输出会是什么呢?Verilog的答案是:保持输出不变。这种“保持输出不变”的行为意味着需要记住当前状态,从而产生latch。组合逻辑不能保存任何状态。组合电路必须在所有条件下为所有输出分配一个值。 这通常意味着始终需要为输出分配 else 子句或默认值。
// synthesis verilog_input_version verilog_2001
module top_module (
input cpu_overheated,
output reg shut_off_computer,
input arrived,
input gas_tank_empty,
output reg keep_driving ); //
always @(*) begin
if (cpu_overheated)
shut_off_computer = 1;
else
shut_off_computer = 0;
end
always @(*) begin
if (~arrived)
keep_driving = ~gas_tank_empty;
else
keep_driving = 0;
end
endmodule
3. case statement
always @(*) begin // This is a combinational circuit
case (in)
1'b1: begin
out = 1'b1; // begin-end if >1 statement
end
1'b0: out = 1'b0;
default: out = 1'bx;
endcase
end
// synthesis verilog_input_version verilog_2001
module top_module (
input [2:0] sel,
input [3:0] data0,
input [3:0] data1,
input [3:0] data2,
input [3:0] data3,
input [3:0] data4,
input [3:0] data5,
output reg [3:0] out );//
always@(*) begin // This is a combinational circuit
case(sel)
3'b000: out = data0;
3'b001: out = data1;
3'b010: out = data2;
3'b011: out = data3;
3'b100: out = data4;
3'b101: out = data5;
default: out = 0;
endcase
end
endmodule
4. priority encoder 优先编码器
优先级编码器是一种组合电路,当给定输入位矢量时,输出矢量中第一个1位的位置。 例如,给定输入 8’b100 1 0000 的 8 位优先级编码器将输出 3’d4,因为 bit[4] 是第一个高位。构建 4 位优先级编码器。对于此问题,如果输入位均为零,则输出为零。请注意,4 位数字有 16 种可能的组合。
// synthesis verilog_input_version verilog_2001
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @(*) begin
case(in)
4'b0000: pos = 0;
4'b0001: pos = 0;
4'b0010: pos = 1;
4'b0100: pos = 2;
4'b1000: pos = 3;
4'b0011: pos = 0;
4'b0110: pos = 1;
4'b1100: pos = 2;
4'b0101: pos = 0;
4'b1010: pos = 1;
4'b1001: pos = 0;
4'b0111: pos = 0;
4'b1110: pos = 1;
4'b1011: pos = 0;
4'b1101: pos = 0;
4'b1111: pos = 0;
endcase
end
endmodule
4. casez
It treats bits that have the value z as don’t-care in the comparison.
always @(*) begin
casez (in[3:0])
4'bzzz1: out = 0; // in[3:1] can be anything
4'bzz1z: out = 1;
4'bz1zz: out = 2;
4'b1zzz: out = 3;
default: out = 0;
endcase
end
case语句的行为就好像每个项都是按顺序检查的(实际上,这是一个大的组合逻辑函数)。注意某些输入(例如,4’b1111)如何匹配多个case项。选择第一个匹配项(因此4’b1111匹配第一个项,out = 0,但不匹配后面的任何项)。
// synthesis verilog_input_version verilog_2001
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*) begin
casez (in[7:0])
8'bzzzz_zzz1: pos = 0;
8'bzzzz_zz10: pos = 1;
8'bzzzz_z100: pos = 2;
8'bzzzz_1000: pos = 3;
8'bzzz1_0000: pos = 4;
8'bzz10_0000: pos = 5;
8'bz100_0000: pos = 6;
8'b1000_0000: pos = 7;
endcase
end
endmodule
5. avoid latches
假设你正在构建一个电路来处理来自PS/2键盘的游戏扫描码。给定接收到的扫描码的最后两个字节,您需要指示键盘上的一个方向键是否被按下。这涉及到一个相当简单的映射,它可以实现为带有四个case的case语句(或if-elseif)。
你的电路有一个16位输入和四个输出。构建识别这四种扫描码并断言正确输出的电路。
为了避免产生锁存, 所有输出都必须在所有可能的条件下赋值(参见always_if2)。仅仅有一个违约情况是不够的。您必须为所有四种情况和默认情况下的所有四个输出分配一个值。这可能涉及许多不必要的输入。一个简单的方法是在case语句之前给输出赋一个“默认值”:
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
... // Set to 1 as necessary.
endcase
end
这种代码风格确保输出在所有可能的情况下都被赋值(0),除非case语句重写了赋值。这也意味着default: case项不再需要。
提醒:逻辑合成器生成一个组合电路,其行为等价于代码所描述的。硬件不会按顺序“执行”代码行。
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up );
always @(*) begin
left = 1'b0;
down = 1'b0;
right= 1'b0;
up = 1'b0;
case(scancode)
16'he06b: left = 1'b1;
16'he072: down = 1'b1;
16'he074: right= 1'b1;
16'he075: up = 1'b1;
endcase
end
endmodule
more verilog Features
1. conditional ternary operator 三元条件运算符
(condition ? if_true : if_false)
(0 ? 3 : 5) // This is 5 because the condition is false.
(sel ? b : a) // A 2-to-1 multiplexer between a and b selected by sel.
always @(posedge clk) // A T-flip-flop.
q <= toggle ? ~q : q;
always @(*) // State transition logic for a one-input FSM
case (state)
A: next = w ? B : A;
B: next = w ? A : B;
endcase
assign out = ena ? q : 1'bz; // A tri-state buffer
((sel[1:0] == 2'h0) ? a : // A 3-to-1 mux
(sel[1:0] == 2'h1) ? b :
c )
比较大小
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);//
wire [7:0] result1, result2;
assign result1 = (a>b)? b:a;
assign result2 = (c>d)? d:c;
assign min = (result1>result2)? result2:result1;
// assign intermediate_result1 = compare? true: false;
endmodule
2. reduction operators
单目运算符
& a[3:0] // AND: a[3]&a[2]&a[1]&a[0]. Equivalent to (a[3:0] == 4'hf)
| b[3:0] // OR: b[3]|b[2]|b[1]|b[0]. Equivalent to (b[3:0] != 4'h0)
^ c[2:0] // XOR: c[2]^c[1]^c[0]
奇偶校验(parity)通常用作通过不完善通道传输数据时检测错误的一种简单方法。
Create a circuit that will compute a parity bit for a 8-bit byte (which will add a 9th bit to the byte).
将使用“偶数”奇偶校验,奇偶校验位只是所有8个数据位的XOR。
module top_module (
input [7:0] in,
output parity);
assign parity = ^in;
endmodule
3. vector100r
Given a 100-bit input vector [99:0], reverse its bit ordering.
module top_module(
input [99:0] in,
output [99:0] out
);
always @(*) begin
for(int i = 0; i<100; i++) begin
out[i] = in[99-i];
end
end
endmodule
A for loop (in a combinational always block or generate block) would be useful here. I would prefer a combinational always block in this case because module instantiations (which require generate blocks) aren’t needed.
4. Popcount 255 总体计数
数in中1的个数
module top_module(
input [254:0] in,
output [7:0] out
);
reg [7:0] cnt;
integer i;
always @(*) begin
cnt = 'd0;
for (i=0;i<255;i=i+1) begin
cnt = (in[i])? (cnt+1'b1):cnt;
end
end
assign out = cnt;
endmodule
5. Adder100i **
通过实例化 100 个全加器来创建一个 100 位二进制行波进位加法器。加法器将两个 100 位数字和一个随身数字相加,以产生 100 位总和并执行。实际实例化全加器,还要从行波进位加法器中的每个全加器输出执行。cout[99]是最后一个全加器的最终执行。
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
always @(*) begin
cout = 0;
sum = 0;
for(int i = 0; i<100; i++)begin
if(i == 0)
{cout[i],sum[i]} = a[i] + b[i] + cin;
else
{cout[i],sum[i]} = a[i] + b[i] + cout[i-1]; // 注意cout[i-1] 而不是cout[i]
end
end
endmodule
6. Bcdadd100**
module bcd_fadd (
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
以一个四位的全加器模块,计算两个输入数据的相加,其位宽为400。
module top_module(
input [399:0] a,b,
input cin,
output cout,
output [399:0] sum
);
wire [99:0] cin_cnt;
genvar i;
generate
for (i=0;i<100;i=i+1) begin:test
if (i == 0) begin
bcd_fadd bcd_fadd_inst(a[3:0],b[3:0],cin,cin_cnt[0],sum[3:0]);
end
else begin
bcd_fadd bcd_fadd_inst(a[4*(i+1)-1:4*i],b[4*(i+1)-1:4*i],cin_cnt[i-1],cin_cnt[i],sum[4*(i+1)-1:4*i]);
end
end
assign cout = cin_cnt[99];
endgenerate
endmodule
二、circuits
Combinational logic
basic Gates
1.truth tables
module top_module(
input x3,
input x2,
input x1, // three inputs
output f // one output
);
assign f = x3 ? x1 : x2;
endmodule
2. combine circuits A and B
module top_module (input x, input y, output z);
wire z_a1,z_a2,z_b1,z_b2;
assign z_a1 = (x ^ y) & x;
assign z_a2 = (x ^ y) & x;
assign z_b1 = ~(x ^ y);
assign z_b2 = ~(x ^ y);
assign z = (z_a1 | z_b1) ^ (z_a2 & z_b2);
endmodule
3. ring or vibrate
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
assign ringer = ((ring == 1'b1) && (vibrate_mode == 1'b0)) ? 1:0;
assign motor = ((ring == 1'b1) & (vibrate_mode == 1'b1)) ? 1:0; // & 会有warning,要用 &&
endmodule
4. Thermostat 恒温器**
恒温器有两种模式:
- 加热模式(mode = 1)和冷却模式(mode = 0),在加热模式下,温度过低(too_cold = 1)时打开加热器,但不使用空调。
- 在制冷模式下,当温度过高(too_hot = 1)时,请打开空调,但不要打开暖气。
- 当加热器或空调打开时,也要打开风扇,让空气流通。
- 此外,用户还可以要求打开风扇(fan_on = 1),即使加热器和空调关闭。
module top_module (
input too_cold,
input too_hot,
input mode,
input fan_on,
output heater,
output aircon,
output fan
);
assign heater = too_cold & mode;
assign aircon = too_hot & (~mode);
assign fan = fan_on | aircon | heater;
endmodule
5. Gates and Vectors
给你一个4位的输入向量[3:0]。我们想知道每个比特和它的邻居之间的关系:
- out_both: 这个输出向量的每一位都应该表明对应的输入位和它左边的邻居(更高的下标)是否都是“1”。例如,out_both[2]应该表示[2]和[3]中是否都是1。因为在[3]中左边没有邻居,所以答案很明显,所以我们不需要知道out_both[3]。
- out_any: 这个输出向量的每一位都应该表明是否有任何对应的输入位和它右边的邻居是“1”。例如,out_any[2]应该指示[2]或[1]中的任何一个为1。因为在[0]中右边没有邻居,所以答案很明显,所以我们不需要知道out_any[0]。
- out_different: 这个输出向量的每一位都应该表明对应的输入位与它左边的邻居是否不同。例如,out_different[2]应该表示[2]中的内容与[3]中的内容是否不同。对于这一部分,将向量视为环绕,因此[3]中左边的邻居在[0]中。
module top_module(
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );
assign out_both[2] = in[3] & in[2];
assign out_both[1] = in[1] & in[2];
assign out_both[0] = in[1] & in[0];
assign out_any[3] = in[3] | in[2];
assign out_any[2] = in[1] | in[2];
assign out_any[1] = in[1] | in[0];
assign out_different[3] = (in[3] != in[0]);
assign out_different[2] = (in[3] != in[2]);
assign out_different[1] = (in[1] != in[2]);
assign out_different[0] = (in[1] != in[0]);
endmodule
在[99:0]中给你一个100位的输入向量。我们想知道每个比特和它的邻居之间的关系:
out_both: 这个输出向量的每一位都应该表明对应的输入位和它左边的邻居是否都是“1”。例如,out_both[98]应该表示[98]和[99]中是否都是1。因为in[99]左边没有邻居,所以答案很明显,所以我们不需要知道out_both[99]。
out_any: 这个输出向量的每一位都应该表明是否有任何对应的输入位和它右边的邻居是“1”。例如,out_any[2]应该指示[2]或[1]中的任何一个为1。因为在[0]中右边没有邻居,所以答案很明显,所以我们不需要知道out_any[0]。
out_different: 这个输出向量的每一位都应该表明对应的输入位与它左边的邻居是否不同。例如,out_different[98]应该表示[98]中是否与[99]中不同。对于这一部分,将向量视为环绕,因此在[99]中左侧的邻居在[0]中。
module top_module(
input [99:0] in,
output [98:0] out_both,
output [99:1] out_any,
output [99:0] out_different );
assign out_both[98:0] = in[99:1] & in[98:0];
assign out_any[99:1] = in[99:1] | in[98:0];
assign out_different[98:0] = (in[98:0] ^ in[99:1]);
assign out_different[99] = (in[99] ^ in[0]); // 用 != 不行,因为!= 不是位比较符, ^ 是位比较符
endmodule
Multiplexers
2 to 1 multiplexer, 2 to 1 bus multiplexer
module top_module(
input a, b, sel,
output out
);
assign out = sel?b:a;
endmodule
module top_module(
input [99:0] a, b,
input sel,
output [99:0] out
);
assign out = sel?b:a;
endmodule
9 to 1 multiplexer
创建 16 位宽、9 对 1 多路复用器。sel=0 选择 a,sel=1 选择 b,依此类推。对于未使用的情况(sel=9 到 15),请将所有输出位设置为“ffff”。
module top_module(
input [15:0] a, b, c, d, e, f, g, h, i,
input [3:0] sel,
output [15:0] out );
always @(*) begin
case (sel)
4'b0000: out = a;
4'b0001: out = b;
4'b0010: out = c;
4'b0011: out = d;
4'b0100: out = e;
4'b0101: out = f;
4'b0110: out = g;
4'b0111: out = h;
4'b1000: out = i;
default: out = 16'hffff;
endcase
end
endmodule
256 to 1 multiplexer**
创建一个1位宽256对1的多路复用器。256个输入都被打包成一个256位的输入向量。
Sel =0选择[0]中的位,Sel =1选择[1]中的位,Sel =2选择[2]中的位,以此类推。
module top_module(
input [255:0] in,
input [7:0] sel,
output out );
assign out = in[sel];
endmodule
256 to 1 4bit multiplexer***
创建一个4位宽256对1的多路复用器。256个4位输入都被打包成一个1024位输入向量。
Sel =0应该选择[3:0]中的位,Sel =1选择[7:4]中的位,Sel =2选择[11:8]中的位,等等。.
module top_module(
input [1023:0] in,
input [7:0] sel,
output [3:0] out );
assign out = in[(sel+1)*4-1 -: 4];
//assign out = in[(sel+1)*4-1 -: 4*sel]; 这样不通过编译,不能两端是变量
endmodule
Arithmetic circuits 运算电路
half adder
module top_module(
input a, b,
output cout, sum );
assign {cout,sum} = a + b;
endmodule
full adder
module top_module(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a + b + cin;
endmodule
100bit binary adder ***
module top_module(
input [99:0] a, b,
input cin,
output cout,
output [99:0] sum );
assign {cout,sum} = a + b + cin;
endmodule
3-bit binary adder
创建3个实例来创建一个3位二进制波纹进位加法器。
加法器将两个3位数字和一个进位相加以产生3位和并执行。
为了鼓励您实际实例化完整加法器,还需要在波纹进位加法器中输出每个完整加法器的进位。
Cout[2]是最后一个完整加法器的最后一个执行结果,是您通常看到的执行结果。
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
assign {cout[0],sum[0]} = a[0] + b[0] + cin;
assign {cout[1],sum[1]} = a[1] + b[1] + cout[0];
assign {cout[2],sum[2]} = a[2] + b[2] + cout[1];
endmodule
adder ***
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum);
wire cout0,cout1,cout2;
assign {cout0,sum[0]} = x[0] + y[0];
assign {cout1,sum[1]} = x[1] + y[1] + cout0;
assign {cout2,sum[2]} = x[2] + y[2] + cout1;
assign {sum[4],sum[3]} = x[3] + y[3] + cout2;
endmodule
signed addition overflow***
假设你有两个8位2的补码数,a[7:0]和b[7:0]。这些数字相加得到s[7:0]。还要计算是否发生了(带符号的)溢出。
当两个正数相加得到负数,或者两个负数相加得到正数时,就会发生有符号溢出。
有几种方法可以检测溢出: 可以通过比较输入和输出数字的符号来计算溢出,也可以通过执行位n和n-1来计算溢出。
两个正数相加符号位变成了1表示溢出,两个负数相加符号位变成了0表示溢出。
module top_module (
input [7:0] a,
input [7:0] b,
output [7:0] s,
output overflow
);
assign s = a + b;
assign overflow = (a[7] & b[7] & ~s[7]) | (~a[7] & ~b[7] & s[7]);
endmodule
4 digit BCD adder***
module bcd_fadd (
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
实例化 4 个bcd_fadd模块以创建 4 位 BCD 纹波携带加法器。加法器应添加两个 4 位 BCD 数字(打包成 16 位向量)和进位值,以生成 4 位总和并执行。
module top_module (
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
wire cout1, cout2, cout3;
bcd_fadd inst1(a[3:0], b[3:0], cin, cout1, sum[3:0]);
bcd_fadd inst2(a[7:4], b[7:4], cout1, cout2, sum[7:4]);
bcd_fadd inst3(a[11:8], b[11:8], cout2, cout3, sum[11:8]);
bcd_fadd inst4(a[15:12], b[15:12], cout3, cout, sum[15:12]);
endmodule
karnaugh map 卡诺图 to circuit
3-variable
module top_module(
input a,
input b,
input c,
output out );
assign out = b | c | a;
endmodule
4-variable
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = (~b & ~c) | (~a & ~d) | (a&c&d) | (b&c&d);
endmodule
对d不care,就成功了?
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = (~b&c) | (a&c) | (a&~d);
or assign out = (a&~c&~d)|(~b&c)|(a&b&c); ???
endmodule
module top_module(
input a,
input b,
input c,
input d,
output out );
wire a1, a2, a3, a4;
assign a1 = (a&b) | (~a & ~b);
assign a2 = (~c&d) | (c&~d);
assign a3 = (c&d) | (~c & ~d);
assign a4 = (~a&b) | (a&~b);
assign out = a1&a2 | a3&a4;
endmodule
karnaugh map
d is don’t-care,
module top_module (
input [4:1] x,
output f );
assign f = (x[1]&x[2]&~x[3]&x[4]) | (~x[1] & x[3]);
endmodule
k-map implemented with a multiplexer
module top_module (
input c,
input d,
output [3:0] mux_in
);
assign mux_in[0] = c | d;
assign mux_in[1] = 'd0;
assign mux_in[2] = ~d;
assign mux_in[3] = c & d;
endmodule