VL5 位拆分与运算
1 自己犯的错误
(1)语法错误
在begin end块 后面加了" ; "
case(sel)
2'b00: begin validout<=0; out<=0; end;
2'b01: begin validout<=1; out<=d0 + d1; end;
2'b10: begin validout<=1; out<=d0 + d2; end;
2'b11: begin validout<=1; out<=d0 + d3; end;
endcase
(2)题目描述 与 所给代码框架不符
题干要求输出为 reg
但是平台给出的输出为wire
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
我按照题目要求写的代码,编译有错,提醒【validout不是data_cal中的有效值】
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
wire [7:0] load_d = (sel==0) ? d : load_d;
wire d0 = load_d[3:0];
wire d1 = load_d[7:4];
wire d2 = load_d[11:8];
wire d3 = load_d[15:12];
always@(posedge clk , negedge rst) begin
if(rst==0)begin
validout<=0;
out<=0;
end else begin
case(sel)
2'b00: begin validout<=0; out<=0; end
2'b01: begin validout<=1; out<=d0 + d1; end
2'b10: begin validout<=1; out<=d0 + d2; end
2'b11: begin validout<=1; out<=d0 + d3; end
endcase
end
end
//*************code***********//
endmodule
提醒错误如下:
我擅自更改平台所给输出信号类型,可以得到仿真结果,但是【压根不对】
可以看到 标准的out值都变成了全0,就是说紊乱了
【结论】输出的数据类型,以平台所给的模块代码框架中声明的类型为准。
(4)在错误中摸索
思路:使用纯组合逻辑
摸索1:使用case语句
代码
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
wire [7:0] load_d = (sel==0) ? d : load_d;
wire d0 = load_d[3:0];
wire d1 = load_d[7:4];
wire d2 = load_d[11:8];
wire d3 = load_d[15:12];
assign validout = (sel==0) ? 0 : 1;
always@(sel) begin
case(sel)
2'b00: out=d0;
2'b01: out=d0 + d1;
2'b10: out=d0 + d2;
2'b11: out=d0 + d3;
endcase
end
//*************code***********//
endmodule
提示错误:out在data_cal中不是有效的值
最后这个提示错误的原因是【被赋值的信号都应该是reg型】
解决:使用一个reg型的中间变量,而wire型输出直接取自这个reg值即可
代码如下
reg [4:0] inner_out=0;
assign out = inner_out;
always@(sel) begin
case(sel)
2'b00: inner_out = d0;
2'b01: inner_out =d0 + d1;
2'b10: inner_out =d0 + d2;
2'b11: inner_out =d0 + d3;
endcase
end
摸索2:使用三目运算符
代码
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
wire [7:0] load_d = (sel==0) ? d : load_d;
wire d0 = load_d[3:0];
wire d1 = load_d[7:4];
wire d2 = load_d[11:8];
wire d3 = load_d[15:12];
assign validout = (sel==0) ? 0 : 1;
assign out = (sel==2'b00) ? d0 :
(sel==2'b01) ? (d0 + d1) :
(sel==2'b10) ? (d0 + d2) :
(sel==2'b11) ? (d0 + d3) ;
//*************code***********//
endmodule
提示错误:语法错误
(3)还有俩本质错误
所以上面的错误可能都不是错误
①错误1:我声明的内部数据位数有误
wire d0 = load_d[3:0];
wire d1 = load_d[7:4];
wire d2 = load_d[11:8];
wire d3 = load_d[15:12];
②错误2:我TestBench中未对sel输入信号做设置
initial fork
sel=0;
#13 sel=1;
#20 sel=2;
#30 sel=3;
join
(4)又发现本质错误:模块框图中的clk和rst关键信号没用到
有这俩关键信号在,说明模块内部还是需要时序逻辑的。而我使用了纯纯的组合逻辑,所以必然是一直都是错误的
这也解释了为啥我的放着结果一直是高阻态【因为我没有用clk把组合逻辑每步计算的结果隔离开】
【解决】内部逻辑需要使用时序逻辑,而使用组合逻辑来满足输出。
【教训】真就是很奇怪的考察点,但也怪自己粗心。
(5)好吧,又一个原则性错误
我把输入信号的位数搞错了。显然这个输入d的位数是16位的,而我将其赋值给了8位的数,所以出现了特别奇怪的仿真结果
代码
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
wire [7:0] load_d = (sel==0) ? d : load_d;
仿真结果
正确啦
1 题目 + 代码 + TestBench
代码
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
wire [15:0] load_d = (sel==0) ? d : load_d;
// reg [4:0] inner_out=0;
wire [3:0] d0 = load_d[3:0];
wire [3:0] d1 = load_d[7:4];
wire [3:0] d2 = load_d[11:8];
wire [3:0] d3 = load_d[15:12];
reg flag;
reg [4:0] inner_out=0;
assign validout = flag;
assign out = inner_out;
// always@(sel) begin
// case(sel)
// 2'b00: inner_out = d0;
// 2'b01: inner_out =d0 + d1;
// 2'b10: inner_out =d0 + d2;
// 2'b11: inner_out =d0 + d3;
// endcase
// end
// assign out = (sel==2'b00) ? d0 :
// (sel==2'b01) ? (d0 + d1) :
// (sel==2'b10) ? (d0 + d2) :
// (sel==2'b11) ? (d0 + d3) ;
// assign out = (sel==2'b00) ? d0 : d1;
always@(posedge clk , negedge rst) begin
if(rst==0) begin
flag<=0;
inner_out<=0;
end else begin
case(sel)
2'b00: begin flag<=0; inner_out<=0; end
2'b01: begin flag<=1; inner_out<=d0 + d1; end
2'b10: begin flag<=1; inner_out<=d0 + d2; end
2'b11: begin flag<=1; inner_out<=d0 + d3; end
endcase
end
end
//*************code***********//
endmodule
TestBench
`timescale 1ns/1ns
module testbench();
reg clk=0;
initial
repeat(100) #1 clk = ~clk; // Create clock with period=10
// A testbench
reg rst;
reg [1:0] sel;
reg [15:0] d;
wire validout;
wire [4:0] out;
data_cal u_data_cal(clk,rst,d,sel,out,validout);
initial begin
rst =0;
#5 rst=1;
end
initial fork
#10 d=16'b10000_10000_100001;
#20 d=16'b10000_10000_100011;
join
initial fork
sel=0;
#13 sel=1;
#20 sel=2;
#30 sel=3;
join
//end
initial begin
$dumpfile("out.vcd");
// This will dump all signal, which may not be useful
//$dumpvars;
// dumping only this module
//$dumpvars(1, testbench);
// dumping only these variable
// the first number (level) is actually useless
$dumpvars(0, testbench);
end
endmodule