中國科學院大學數字集成電路作業開源——第4-5章
1、基礎概念問題
1.1請簡要描述10進制整數與16進制整數之間相互轉換方法?
方法1:將10進制整數通過除2取余數的方法得到2進制表示,再將2進制數按照每4位表示一個16進制數的方式轉成16進制表示。
方法2:將10進制整數通過除16取余數的方法直接得到16進制表示。
方法1例子:30轉2進制0001_1110,對應16進制1E
方法2例子:30=30/16=1余下14,14對應的是E。所以30=1E
1.2 請簡要描述數的原碼、反碼和補碼的表示方式和對應表示數值范圍?
原碼:原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值
[+1]原 = 0000 0001
[-1]原 = 1000 0001
8位二進制表示數的范圍:[-127 , 127]
反碼:正數的反碼是其本身。負數的反碼是在其原碼的基礎上, 符號位不變,其余各個位取反
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
8位二進制表示數的范圍:[-127 , 127]
補碼:正數的補碼就是其本身。負數的補碼是在其原碼的基礎上, 符號位不變, 其余各位取反, 最后+1. (即在反碼的基礎上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]補
[-1] = [10000001]原 = [11111110]反 = [11111111]補
8位二進制表示數的范圍:[-128 , 127]
1.3 請簡要描述格雷碼編碼方式和優點,並具體給出5位格雷碼映射關系表格?
格雷碼:在一組數的編碼中,使得任意兩個相鄰的代碼只有一位二進制數不同。二進制轉變為格雷碼通過相鄰位異或實現
優點:在相鄰位間轉換時,只有一位產生變化。大大地減少了由一個狀態到下一個狀態時邏輯的混淆。
自然二進制數 | 5位格雷碼 |
---|---|
00000 | 00000 |
00001 | 00001 |
00010 | 00011 |
00011 | 00010 |
00100 | 00110 |
00101 | 00111 |
00110 | 00101 |
00111 | 00100 |
01000 | 01100 |
01001 | 01101 |
01010 | 01111 |
01011 | 01110 |
01100 | 01010 |
01101 | 01011 |
01110 | 01001 |
01111 | 01000 |
10000 | 11000 |
10001 | 11001 |
10010 | 11011 |
10011 | 11010 |
10100 | 11110 |
10101 | 11111 |
10110 | 11101 |
10111 | 11100 |
11000 | 10100 |
11001 | 10101 |
11010 | 10111 |
11011 | 10110 |
11100 | 10010 |
11101 | 10011 |
11110 | 10001 |
11111 | 10000 |
1.4 請簡要描述IEEE 754標准中32位單精度浮點數格式、范圍和精度?簡要比較並分析浮點數和定點數在硬件實現方面的優缺點。
浮點數:優點:能夠表示高精度,范圍大
缺點:計算電路非常復雜
定點數:優點:計算電路很簡單
缺點:不能夠表示高精度,范圍小
2 基於VerilogHDL進行邏輯電路設計
2.1跑表
設計一個跑表時序邏輯電路,通過按鈕控制及數字顯示,有時分秒顯示,可以清零、開始和暫停。系統主時鍾頻率為10 MHz。
其中按鈕Clear實現清零功能(任意狀態按下時分秒值清零並停止計時)、按鈕Start/Stop實現開始和暫停功能(若當前狀態為停止則按下繼續進行計時,若當前狀態為計時則按下暫停計時)。
數字顯示為XX : XX : XX形式,時分秒各為2位數字。對每位數字使用4位二進制編碼輸出表示(hr_h[3:0],hr_l[3:0] : min_h[3:0],min_l[3:0] : sec_h[3:0],sec_l[3:0])。
頂層模塊名為stop_watch,輸入輸出功能定義:
名稱 | 方向 | 位寬 | 描述 |
---|---|---|---|
clk | I | 1 | 系統時鍾,10 MHz |
rst_n | I | 1 | 異步復位,低電平有效 |
clear | I | 1 | 清零按鈕,上升沿有效 |
start_stop | I | 1 | 開始/暫停按鈕,上升沿有效 |
hr_h | O | 4 | 時高位輸出,取值0~9 |
hr_l | O | 4 | 時低位輸出,取值0~9 |
min_h | O | 4 | 分高位輸出,取值0~9 |
min_l | O | 4 | 分低位輸出,取值0~9 |
sec_h | O | 4 | 秒高位輸出,取值0~9 |
sec_l | O | 4 | 秒低位輸出,取值0~9 |
設計要求:
Verilog實現代碼可綜合,給出綜合以及仿真結果(說明:為加快仿真速度,代碼用於仿真時可以縮短秒計數周期,如每100個時鍾周期更新一次秒計數值,正常情況下每10000000個時鍾周期才更新一次秒計數值)。
設計思路:
用counter子模塊實現計數,counter子模塊的功能包括:reset復位,clear清零,計數滿后自動清零並輸出full脈沖。
最低一級的sec_l用clk驅動,用sec_l得到full信號去驅動sec_h,用sec_h的full信號去驅動min_l……一直這樣向上計數。
頂層stop_watch調用counter子模塊連接實現計數功能。用兩段式狀態機實現STOP和START的狀態切換功能,以及產生門控時鍾信號,用來控制計數器工作或停止。
考慮到實際使用的合理性,在計數時,秒鍾和分鍾最大計數值只有59,小時可以最大計數到99(因為題目只說了跑表,沒說是時鍾,所以我就沒有限制不超過24h)
代碼實現:
counter子模塊
module counter (
input clk,
input rst_n,
input clear,
input [3:0] thresh,
output full,
output [3:0] cnt_v
);
reg [3:0] cnt;
reg f;
always @(posedge clk or posedge clear or negedge rst_n) begin
if(rst_n == 1'b0) begin
cnt <= 4'b0;
f <= 1'b0;
end
else begin
if(clear == 1'b1) begin
cnt <= 4'b0;
f <= 1'b0;
end
else if(cnt_v == thresh) begin
cnt <= 4'b0;
f <= 1'b1;
end
else begin
cnt <= cnt + 1'b1;
f <= 1'b0;
end
end
end
assign cnt_v = cnt;
assign full = f;
endmodule
counter的testbench
module testbench();
reg clk;
reg rst_n;
reg [3:0] thresh;
wire full;
wire [3:0] cnt_v;
initial begin
clk <= 1'b0;
rst_n <= 1'b0;
thresh <= 4'b0000;
#10
rst_n <= 1'b1;
thresh <= 4'b1001;
end
always #10 clk <= ~clk;
counter u_cnt(.clk(clk),.rst_n(rst_n),.thresh(thresh),.full(full),.cnt_v(cnt_v));
endmodule
stop_watch頂層
module stop_watch (
input clk,
input rst_n,
input clear,
input start_stop,
output [3:0] hr_h,
output [3:0] hr_l,
output [3:0] min_h,
output [3:0] min_l,
output [3:0] sec_h,
output [3:0] sec_l
);
reg clk_en;
wire clk_gated;
parameter thresh_h = 4'b0101;
parameter thresh_l = 4'b1001;
wire full_sec_l;
wire full_sec_h;
wire full_min_l;
wire full_min_h;
wire full_hr_l;
parameter START = 1'b0;
parameter STOP = 1'b1;
reg current_state;
reg next_state;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
current_state <= START;
end
else begin
current_state <= next_state;
end
end
always @(*) begin
case(current_state)
START: begin
if (clear|start_stop) begin
next_state = STOP;
clk_en = 1'b0;
end
end
STOP: begin
if (start_stop) begin
next_state = START;
clk_en = 1'b1;
end
end
default: next_state = START;
endcase
end
assign clk_gated = clk_en & clk;
counter u_cnt_0(.clk(clk_gated),.rst_n(rst_n),.clear(clear),.thresh(thresh_l),.full(full_sec_l),.cnt_v(sec_l));
counter u_cnt_1(.clk(full_sec_l),.rst_n(rst_n),.clear(clear),.thresh(thresh_h),.full(full_sec_h),.cnt_v(sec_h));
counter u_cnt_2(.clk(full_sec_h),.rst_n(rst_n),.clear(clear),.thresh(thresh_l),.full(full_min_l),.cnt_v(min_l));
counter u_cnt_3(.clk(full_min_l),.rst_n(rst_n),.clear(clear),.thresh(thresh_h),.full(full_min_h),.cnt_v(min_h));
counter u_cnt_4(.clk(full_min_h),.rst_n(rst_n),.clear(clear),.thresh(thresh_h),.full(full_hr_l),.cnt_v(hr_l));
counter u_cnt_5(.clk(full_hr_l),.rst_n(rst_n),.clear(clear),.thresh(thresh_h),.full(),.cnt_v(hr_h));
endmodule
stop_watch的testbench
module testbench();
reg clk;
reg rst_n;
reg clear;
reg start_stop;
wire [3:0] hr_l,hr_h,min_h,min_l,sec_h,sec_l;
initial begin
clk <= 1'b0;
rst_n <= 1'b0;
clear <= 1'b0;
start_stop <= 1'b0;
#1
rst_n <= 1'b1;
#10
clear <= 1'b1;
#1
clear <= 1'b0;
#10
start_stop <= 1'b1;
#1
start_stop <= 1'b0;
#10
start_stop <= 1'b1;
#1
start_stop <= 1'b0;
#10
start_stop <= 1'b1;
#1
start_stop <= 1'b0;
end
always #1 clk <= ~clk;
stop_watch u_stop_watch(
.clk(clk),
.rst_n(rst_n),
.clear(clear),
.start_stop(start_stop),
.hr_h(hr_h),
.hr_l(hr_l),
.min_h(min_h),
.min_l(min_l),
.sec_h(sec_h),
.sec_l(sec_l)
);
endmodule
仿真結果:
counter:計數功能,計數滿后自動清零並產生full脈沖
stop_watch:clear實現清零功能(任意狀態按下時分秒值清零並停止計時)。
stop_watch:start/stop實現開始和暫停功能(若當前狀態為停止則按下繼續進行計時,若當前狀態為計時則按下暫停計時)。
stop_watch:計數功能體現(00:00:00—00:02:04)
2.2快速加法器
實現快速加法器組合邏輯,要實現的功能如下:
輸入為兩個16位有符號數,輸出17位相加結果。要求采用超前進位(Carry-look-ahead)結構。
計算例子:
0110000010000000 + 1000000000000001 = 11110000010000001
(24704) + (-32767) = (-8063)
頂層模塊名為add_tc_16_16,輸入輸出功能定義:
名稱 | 方向 | 位寬 | 描述 |
---|---|---|---|
a | I | 16 | 輸入數據,二進制補碼 |
b | I | 16 | 輸入數據,二進制補碼 |
sum | O | 17 | 輸出和a + b,二進制補碼 |
設計要求:
Verilog實現代碼可綜合,邏輯延遲越小越好,給出綜合以及仿真結果(參考ASIC綜合結果:SMIC 55nm工藝下工作時鍾頻率大於500 MHz)。
設計思路:
設計圖紙如下圖所示(紅色箭頭為進位傳播方向)
設計子模塊Carry4實現4位的進位邏輯,使用5個Carry4子模塊按照圖紙所示方式進行連接完成16位超前進位加法器。
對於最高位的處理,進行深入一點的思考。如果兩個16位的運算沒有發生溢出,那么第17位應該是符號位拓展。但如果發生了溢出的話,第17就就得作為符號位了。符號位的確定方式應該是根據最高進位來決定。所以先進行溢出檢測,最高位由溢出信號來進行控制。
最后測試時我用了一組非溢出的數,和正數溢出、負數溢出各一組的數。
代碼實現:
Carry4子模塊
module Carry4(
input [3:0] p,
input [3:0] g,
input cin,
output P,G,
output [2:0] cout
);
assign P = &p;
assign G = g[3]|(p[3]&g[2])|(p[3]&p[2]&g[1])|(p[3]&p[2]&p[1]&g[0]);
assign cout[0] = g[0]|(p[0]&cin);
assign cout[1] = g[1]|(p[1]&g[0])|(p[1]&p[0]&cin);
assign cout[2] = g[2]|(p[2]&g[1])|(p[2]&p[1]&g[0])|(p[2]&p[1]&p[0]&cin);
endmodule
add_tc_16_16頂層
module add_tc_16_16 (
input [15:0] a,
input [15:0] b,
output [16:0] sum
);
wire [15:0] p = a|b;
wire [15:0] g = a&b;
wire [3:0] P,G;
wire [15:0] c;
wire [15:0] out;
wire overflow;
wire sign;
assign c[0] = 1'b0;
Carry4 U_Carry4_0(.p(p[3:0]),.g(g[3:0]),.cin(c[0]),.P(P[0]),.G(G[0]),.cout(c[3:1]));
Carry4 U_Carry4_1(.p(p[7:4]),.g(g[7:4]),.cin(c[4]),.P(P[1]),.G(G[1]),.cout(c[7:5]));
Carry4 U_Carry4_2(.p(p[11:8]),.g(g[11:8]),.cin(c[8]),.P(P[2]),.G(G[2]),.cout(c[11:9]));
Carry4 U_Carry4_3(.p(p[15:12]),.g(g[15:12]),.cin(c[12]),.P(P[3]),.G(G[3]),.cout(c[15:13]));
Carry4 U_Carry4_4(.p(P),.g(G),.cin(c[0]),.P(),.G(),.cout({c[12],c[8],c[4]}));
assign cout = (a[15] & b[15]) | (a[15] & c[15]) | (b[15] & c[15]);
assign out = (~a & ~b & c) | (~a & b & ~c) | (a & ~b & ~c) | (a & b & c);
assign overflow = (out[15] & ~a[15] & ~b[15]) | (~out[15] & a[15] & b[15]);
assign sign = (overflow & cout) | (~overflow & out[15]);
assign sum = {sign,out};
endmodule
testbench:
module testbench();
reg [15:0] a;
reg [15:0] b;
wire [16:0] sum;
initial begin
a <= 16'b0110_0000_1000_0000;
b <= 16'b1000_0000_0000_0001;
#10
a <= 16'b1000_0000_0000_0001;
b <= 16'b1000_0000_0000_0001;
#10
a <= 16'b0111_1111_1111_1111;
b <= 16'b0111_1111_1111_1111;
end
add_tc_16_16 U_Add16(
.a(a),
.b(b),
.sum(sum)
);
endmodule
仿真結果:
三組測試輸入
0110000010000000 + 1000000000000001 = 11110000010000001
1000000000000001 + 1000000000000001 = 10000000000000010
0111111111111111 + 0111111111111111 = 01111111111111110
第一組數沒有溢出,最高位是符號位拓展,后兩者發生了溢出,最高位根據進位來決定
2.3快速乘法器
實現快速乘法器組合邏輯,要實現的功能如下:
輸入為兩個16位有符號數,輸出32位相乘結果。要求采用Booth編碼和Wallace樹型結構。
計算例子:
0110000010000000 * 1000000000000001 = 11001111110000000110000010000000
(24704) * (-32767) = (-809475968)
頂層模塊名為mul_tc_16_16,輸入輸出功能定義:
名稱 | 方向 | 位寬 | 描述 |
---|---|---|---|
a | I | 16 | 輸入數據,二進制補碼 |
b | I | 16 | 輸入數據,二進制補碼 |
product | O | 32 | 輸出乘積a * b,二進制補碼 |
設計要求:
Verilog實現代碼可綜合,邏輯延遲越小越好,給出綜合以及仿真結果(參考ASIC綜合結果:SMIC 55nm工藝下工作時鍾頻率大於500 MHz)。
設計思路:
本題目要求實現16位快速乘法器,我采用了Radix-4的booth編碼用於產生部分積以及wallence tree的加法器結構
設計參考自下圖:
先通過Radix-4 Booth編碼電路將輸入B進行編碼(booth_enc),再與A一起產生8個部分積(gen_prod),在booth子模塊中進行它們的連接。這8個部分積通過Wallence Tree結構的加法樹移位求和后(6個CSA (adder)),最后通過RSA(adder)求和得到乘算結果,在wallence tree子模塊中進行他們的連接。頂層文件mul_tc_16_16連接booth和wallence_tree。
參考資料:https://zhuanlan.zhihu.com/p/143802580
代碼實現:
booth_enc booth編碼
module booth_enc (
input [2:0] code,
output neg,
output zero,
output one,
output two
);
assign neg = code[2];
assign zero = (code == 3'b000) || (code == 3'b111);
assign two = (code == 3'b100) || (code == 3'b011);
assign one = !zero & !two;
endmodule
gen_prod 用於控制部分積的產生
module gen_prod (
input [15:0] a,
input neg,
input zero,
input one,
input two,
output [31:0] prod
);
reg [31:0] prod_pre;
always @(*) begin
prod_pre = 32'b0;
if(zero) prod_pre = 32'b0;
else if(one) prod_pre = {{16{a[15]}},a};
else if(two) prod_pre = {{15{a[15]}},a,1'b0};
end
assign prod = neg ? (~prod_pre + 1'b1) : prod_pre;
endmodule
booth 完整booth編碼模塊
module booth (
input [15:0] a,
input [15:0] b,
output [31:0] prod_0,
output [31:0] prod_1,
output [31:0] prod_2,
output [31:0] prod_3,
output [31:0] prod_4,
output [31:0] prod_5,
output [31:0] prod_6,
output [31:0] prod_7
);
wire [7:0] neg;
wire [7:0] zero;
wire [7:0] one;
wire [7:0] two;
booth_enc u_booth_enc_0(.code({b[1:0],1'b0}),.neg(neg[0]),.zero(zero[0]),.one(one[0]),.two(two[0]));
booth_enc u_booth_enc_1(.code(b[3:1]),.neg(neg[1]),.zero(zero[1]),.one(one[1]),.two(two[1]));
booth_enc u_booth_enc_2(.code(b[5:3]),.neg(neg[2]),.zero(zero[2]),.one(one[2]),.two(two[2]));
booth_enc u_booth_enc_3(.code(b[7:5]),.neg(neg[3]),.zero(zero[3]),.one(one[3]),.two(two[3]));
booth_enc u_booth_enc_4(.code(b[9:7]),.neg(neg[4]),.zero(zero[4]),.one(one[4]),.two(two[4]));
booth_enc u_booth_enc_5(.code(b[11:9]),.neg(neg[5]),.zero(zero[5]),.one(one[5]),.two(two[5]));
booth_enc u_booth_enc_6(.code(b[13:11]),.neg(neg[6]),.zero(zero[6]),.one(one[6]),.two(two[6]));
booth_enc u_booth_enc_7(.code(b[15:13]),.neg(neg[7]),.zero(zero[7]),.one(one[7]),.two(two[7]));
gen_prod gen_prod_0(.a(a),.neg(neg[0]),.zero(zero[0]),.one(one[0]),.two(two[0]),.prod(prod_0));
gen_prod gen_prod_1(.a(a),.neg(neg[1]),.zero(zero[1]),.one(one[1]),.two(two[1]),.prod(prod_1));
gen_prod gen_prod_2(.a(a),.neg(neg[2]),.zero(zero[2]),.one(one[2]),.two(two[2]),.prod(prod_2));
gen_prod gen_prod_3(.a(a),.neg(neg[3]),.zero(zero[3]),.one(one[3]),.two(two[3]),.prod(prod_3));
gen_prod gen_prod_4(.a(a),.neg(neg[4]),.zero(zero[4]),.one(one[4]),.two(two[4]),.prod(prod_4));
gen_prod gen_prod_5(.a(a),.neg(neg[5]),.zero(zero[5]),.one(one[5]),.two(two[5]),.prod(prod_5));
gen_prod gen_prod_6(.a(a),.neg(neg[6]),.zero(zero[6]),.one(one[6]),.two(two[6]),.prod(prod_6));
gen_prod gen_prod_7(.a(a),.neg(neg[7]),.zero(zero[7]),.one(one[7]),.two(two[7]),.prod(prod_7));
endmodule
adder 加法器,可以聲明位寬
module adder#(parameter DATA_WIDTH = 1) (
input [DATA_WIDTH-1:0] a,
input [DATA_WIDTH-1:0] b,
input [DATA_WIDTH-1:0] cin,
output [DATA_WIDTH-1:0] cout,
output [DATA_WIDTH-1:0] s
);
generate
genvar index;
for (index = 0; index < DATA_WIDTH ; index = index + 1'b1) begin
assign {cout[index],s[index]} = a[index] + b[index] + cin[index];
end
endgenerate
endmodule
wallence_tree 用加法器連接成wallence tree
module wallence_tree (
input [31:0] prod_0,
input [31:0] prod_1,
input [31:0] prod_2,
input [31:0] prod_3,
input [31:0] prod_4,
input [31:0] prod_5,
input [31:0] prod_6,
input [31:0] prod_7,
output [31:0] product
);
wire [31:0] csa_0_c;
wire [31:0] csa_0_s;
wire [31:0] csa_1_c;
wire [31:0] csa_1_s;
wire [31:0] csa_2_c;
wire [31:0] csa_2_s;
wire [31:0] csa_3_c;
wire [31:0] csa_3_s;
wire [31:0] csa_4_c;
wire [31:0] csa_4_s;
wire [31:0] csa_5_c;
wire [31:0] csa_5_s;
adder #(.DATA_WIDTH(32)) u_csa_0(.a(prod_0),.b(prod_1<<2),.cin(prod_2<<4),.cout(csa_0_c),.s(csa_0_s));
adder #(.DATA_WIDTH(32)) u_csa_1(.a(prod_3<<6),.b(prod_4<<8),.cin(prod_5<<10),.cout(csa_1_c),.s(csa_1_s));
adder #(.DATA_WIDTH(32)) u_csa_2(.a(csa_1_c),.b(prod_6<<12),.cin(prod_7<<14),.cout(csa_2_c),.s(csa_2_s));
adder #(.DATA_WIDTH(32)) u_csa_3(.a(csa_0_c),.b(csa_0_s),.cin(csa_1_s),.cout(csa_3_c),.s(csa_3_s));
adder #(.DATA_WIDTH(32)) u_csa_4(.a(csa_2_s),.b(csa_3_s),.cin(csa_3_c),.cout(csa_4_c),.s(csa_4_s));
adder #(.DATA_WIDTH(32)) u_csa_5(.a(csa_2_c),.b(csa_4_s),.cin(csa_4_c),.cout(csa_5_c),.s(csa_5_s));
adder #(.DATA_WIDTH(32)) u_rsa(.a(csa_5_s),.b(csa_5_c << 1),.cin(32'b0),.cout(),.s(product));
endmodule
mul_tc_16_16 頂層模塊
module mul_tc_16_16 (
input [15:0] a,
input [15:0] b,
output [31:0] product
);
wire [31:0] prod_0;
wire [31:0] prod_1;
wire [31:0] prod_2;
wire [31:0] prod_3;
wire [31:0] prod_4;
wire [31:0] prod_5;
wire [31:0] prod_6;
wire [31:0] prod_7;
booth u_booth(
.a(a),
.b(b),
.prod_0(prod_0),
.prod_1(prod_1),
.prod_2(prod_2),
.prod_3(prod_3),
.prod_4(prod_4),
.prod_5(prod_5),
.prod_6(prod_6),
.prod_7(prod_7)
);
wallence_tree u_wallence_tree(
.prod_0(prod_0),
.prod_1(prod_1),
.prod_2(prod_2),
.prod_3(prod_3),
.prod_4(prod_4),
.prod_5(prod_5),
.prod_6(prod_6),
.prod_7(prod_7),
.product(product)
);
endmodule
testbench
module testbench ();
reg [15:0] a;
reg [15:0] b;
wire [31:0] product;
initial begin
a <= 16'b0110_0000_1000_0000;
b <= 16'b1000_0000_0000_0001;
end
mul_tc_16_16 u_uml_tc_16_16(
.a(a),
.b(b),
.product(product)
);
endmodule
仿真結果:
0110000010000000 * 1000000000000001 = 11001111110000000110000010000000
(24704) * (-32767) = (-809475968)
部分積(prod0—prod7)與手算的結果也是一致的
2.4桶形移位器
實現桶形移位器組合邏輯,要實現的功能如下:
輸入為32位二進制向量,根據方向和位移值輸出循環移位后的32位結果。例如:
輸入向量00011000101000000000000000000000,方向左,位移值10,輸出向量10000000000000000000000001100010;
輸入向量00000000111111110000000000000011,方向右,位移植20,輸出向量11110000000000000011000000001111.
頂層模塊名為bsh_32,輸入輸出功能定義:
名稱 | 方向 | 位寬 | 描述 |
---|---|---|---|
data_in | I | 32 | 輸入數據 |
dir | I | 1 | 位移方向 0:循環左移 1:循環右移 |
sh | I | 5 | 位移值,取值0~31 |
data_out | O | 32 | 輸出數據 |
設計要求:
Verilog實現代碼可綜合,邏輯延遲越小越好,給出綜合以及仿真結果。
設計思路:
設計參考自下圖:
在上圖的基礎上增加的功能主要有:移動方向的控制;移位碼共有五位,因此共有五層的移位邏輯;循環移位。
代碼實現:
module bsh_32 (
input [31:0] data_in,
input dir,
input [4:0] sh,
output [31:0] data_out
);
reg [31:0] out;
always @(*) begin
case(dir)
1'b0: begin
out = sh[0] ? {data_in[30:0], data_in[31]} : data_in;
out = sh[1] ? {out[29:0], out[31:30]} : out;
out = sh[2] ? {out[27:0], out[31:28]} : out;
out = sh[3] ? {out[23:0], out[31:24]} : out;
out = sh[4] ? {out[15:0], out[31:16]} : out;
end
1'b1:begin
out = sh[0] ? {data_in[0], data_in[31:1]} : data_in;
out = sh[1] ? {out[1:0], out[31:2]} : out;
out = sh[2] ? {out[3:0], out[31:4]} : out;
out = sh[3] ? {out[7:0], out[31:8]} : out;
out = sh[4] ? {out[15:0], out[31:16]} : out;
end
endcase
end
assign data_out = out;
endmodule
testbench
module testbench();
reg [31:0] data_in;
reg dir;
reg [4:0] sh;
wire [31:0] data_out;
initial begin
data_in <= 32'b0001_1000_1010_0000_0000_0000_0000_0000;
dir <= 1'b0;
sh <= 5'd10;
#10
data_in <= 32'b0000_0000_1111_1111_0000_0000_0000_0011;
dir <= 1'b1;
sh <= 5'd20;
end
bsh_32 u_bsh_32(
.data_in(data_in),
.dir(dir),
.sh(sh),
.data_out(data_out)
);
endmodule
仿真結果:
輸入向量00011000101000000000000000000000,方向左,位移值10,輸出向量10000000000000000000000001100010;
輸入向量00000000111111110000000000000011,方向右,位移值20,輸出向量11110000000000000011000000001111.