求指导一个verilog编写的FPGA加减法程序
该程序有add和sub两个输入,在add给一个脉冲时,grade加一,sub给一个脉冲时,grade减一,下面是我写的程序,但没实现其功能modulejishu(add,...
该程序有add和sub两个输入,在add给一个脉冲时,grade加一,sub给一个脉冲时,grade减一,下面是我写的程序,但没实现其功能
module jishu(
add,sub,CLK,RSTn,
grade,grade1,grade2
);
input add,sub,CLK,RSTn;
output [6:0]grade; //liang wei shu
output [3:0]grade1;//ge wei
output [3:0]grade2;//shi wei
reg [6:0]grade=7'd5;
reg [6:0]x;
reg [6:0]y;
reg [3:0]grade1;//ge wei
reg [3:0]grade2;//shi wei
always @ (posedge add or posedge sub)
if(add)
grade=grade+1'b1;
else if(sub)
grade=grade-1'b1;/*if(add)
grade=grade+1'b1;//zai add shang sheng yan jia 1
else
grade=grade-1'b1;
// else if(sub&&grade)
// grade=grade-1'b1;//zai sub shang sheng yan jia 1*/
always @ (posedge CLK or negedge RSTn)
if(!RSTn)begin
grade1<=4'b0;grade2<=4'b0;
end
else begin
x=grade%4'd10;y=grade/4'd10;grade1=x[3:0];grade2=y[3:0];end //qiu grade de shi wei he gei wei
endmodule
谢谢各位指导,各位的回答真的让我学到很多 展开
module jishu(
add,sub,CLK,RSTn,
grade,grade1,grade2
);
input add,sub,CLK,RSTn;
output [6:0]grade; //liang wei shu
output [3:0]grade1;//ge wei
output [3:0]grade2;//shi wei
reg [6:0]grade=7'd5;
reg [6:0]x;
reg [6:0]y;
reg [3:0]grade1;//ge wei
reg [3:0]grade2;//shi wei
always @ (posedge add or posedge sub)
if(add)
grade=grade+1'b1;
else if(sub)
grade=grade-1'b1;/*if(add)
grade=grade+1'b1;//zai add shang sheng yan jia 1
else
grade=grade-1'b1;
// else if(sub&&grade)
// grade=grade-1'b1;//zai sub shang sheng yan jia 1*/
always @ (posedge CLK or negedge RSTn)
if(!RSTn)begin
grade1<=4'b0;grade2<=4'b0;
end
else begin
x=grade%4'd10;y=grade/4'd10;grade1=x[3:0];grade2=y[3:0];end //qiu grade de shi wei he gei wei
endmodule
谢谢各位指导,各位的回答真的让我学到很多 展开
4个回答
展开全部
首先纠正下千年同志的回答:
你的第一点,请看清楚楼主两个always块第一个是grade,第二个是grade1,grade2分别表示个位十位;
第二点:脉冲信号不能做判断条件这句,我拍这胸脯告诉你,绝对可以。。只有你用时序逻辑,在时钟沿检测脉冲信号就可以,只有保证脉冲宽度大于一个时钟周期就绝对能检测到。
第三点:楼主确实有这么点不完善,不过有些时候可以预先确知某些信号同时发生也可以不考虑的。
最后的你建议,先学C再改verilog,个人意见非常不赞同。。很多软件工程师特别喜欢把写软件哦思维带到硬件描述语言中来。。调用个函数啦。。写个for,写个while什么,最后还问为啥综合报错。。。除非你是专门做测试的用systemC或者systemverilog。that's all。
有点偏题了,说楼主的问题:
你的错误:第一点,最明显的地方是 第二个always块里面,你同时用了阻塞赋值和非阻塞赋值语句,这是典型错误。时序逻辑的always块里面都用<=,组合逻辑的always块都用=。
第二,第二个语句中X,Y两个变量的赋值的表达式根本没办法正确综合,一般%这个运算符号只能出现在仿真里(也很少用)除法/只能对2的整数幂进行相除,根本不能除以10,因为这里除法的本质就是除以2^n就等同于讲寄存器的值左移n位;请问这里10等于2的几次幂啊?!
第三个错误,第一个always块,作为组合逻辑,要把所有的敏感变量加进敏感变量列表里,而且组合逻辑你就不用边缘检测posedge 了,直接always@(add or sub or grade)就可以了。
第四个错误。。你的这个组合逻辑的always块,else 语句写在else if 语句前面,这是一种很诡异的写法,能综合个什么东西出来完全想不出来。
所有,我给你的建议是,你这段程序直接推翻重新来写,全部使用标准的时序逻辑的写法,
就是你第二段“always@(posedge clk or negedge RSTn)beign……end”这种写法,它可以保证你的所有电路行为都是发生在时钟上升沿或异步复位下降沿。
其次,每个信号第一if的分支语句一定是要if (!RSTn),即RSTn为低电平时整个加法器复位。这样做的好处在于:由于所有FPGA器件自动上电的瞬间,内部各个信号的初始态都是低电平,可以保证系统有一个自动复位的过程,所有按照这样写的寄存器都会有一个初始态。而避免了不定态X。
最后,建议你四个bit位宽的个位寄存器做成一个模为10的计数器(可以加可以减,具体靠判断sub,add哪一个信号为高)。。每次计数器满时就将十位的那个寄存器加一,而当个位寄存器为零且又检测到sub减信号时,则把个位寄存器置为4‘b1001(9);将十位寄存器也减一;这样就可以实现总累加值从0~99的加减法器了 。
你的第一点,请看清楚楼主两个always块第一个是grade,第二个是grade1,grade2分别表示个位十位;
第二点:脉冲信号不能做判断条件这句,我拍这胸脯告诉你,绝对可以。。只有你用时序逻辑,在时钟沿检测脉冲信号就可以,只有保证脉冲宽度大于一个时钟周期就绝对能检测到。
第三点:楼主确实有这么点不完善,不过有些时候可以预先确知某些信号同时发生也可以不考虑的。
最后的你建议,先学C再改verilog,个人意见非常不赞同。。很多软件工程师特别喜欢把写软件哦思维带到硬件描述语言中来。。调用个函数啦。。写个for,写个while什么,最后还问为啥综合报错。。。除非你是专门做测试的用systemC或者systemverilog。that's all。
有点偏题了,说楼主的问题:
你的错误:第一点,最明显的地方是 第二个always块里面,你同时用了阻塞赋值和非阻塞赋值语句,这是典型错误。时序逻辑的always块里面都用<=,组合逻辑的always块都用=。
第二,第二个语句中X,Y两个变量的赋值的表达式根本没办法正确综合,一般%这个运算符号只能出现在仿真里(也很少用)除法/只能对2的整数幂进行相除,根本不能除以10,因为这里除法的本质就是除以2^n就等同于讲寄存器的值左移n位;请问这里10等于2的几次幂啊?!
第三个错误,第一个always块,作为组合逻辑,要把所有的敏感变量加进敏感变量列表里,而且组合逻辑你就不用边缘检测posedge 了,直接always@(add or sub or grade)就可以了。
第四个错误。。你的这个组合逻辑的always块,else 语句写在else if 语句前面,这是一种很诡异的写法,能综合个什么东西出来完全想不出来。
所有,我给你的建议是,你这段程序直接推翻重新来写,全部使用标准的时序逻辑的写法,
就是你第二段“always@(posedge clk or negedge RSTn)beign……end”这种写法,它可以保证你的所有电路行为都是发生在时钟上升沿或异步复位下降沿。
其次,每个信号第一if的分支语句一定是要if (!RSTn),即RSTn为低电平时整个加法器复位。这样做的好处在于:由于所有FPGA器件自动上电的瞬间,内部各个信号的初始态都是低电平,可以保证系统有一个自动复位的过程,所有按照这样写的寄存器都会有一个初始态。而避免了不定态X。
最后,建议你四个bit位宽的个位寄存器做成一个模为10的计数器(可以加可以减,具体靠判断sub,add哪一个信号为高)。。每次计数器满时就将十位的那个寄存器加一,而当个位寄存器为零且又检测到sub减信号时,则把个位寄存器置为4‘b1001(9);将十位寄存器也减一;这样就可以实现总累加值从0~99的加减法器了 。
展开全部
高边疆号同学说的非常好,写verilog的大忌就是先用C来写。
你的程序是想构建1个异步电路来实现加减法,但是这样可能会造成以下问题:
1、因为是不同时钟域,异步电路数据传输的时序问题;
2、add,sub是外部输入信号,没做任何滤波处理,使用其边沿触发,若有毛刺可以会造成严重问题;
3、verilog中少用除法,而模除(%)仅能仿真,无法综合,但有的FPGA可以,建议不使用;
可参考以下代码:
module jishu(
add,sub,CLK,RSTn,
grade,grade1,grade2
);
input add,sub,CLK,RSTn;
output [6:0]grade; //liang wei shu
output [3:0]grade1;//ge wei
output [3:0]grade2;//shi wei
reg [6:0]grade;
reg [3:0]grade1;//ge wei
reg [3:0]grade2;//shi wei
//构建2个标志信号和同步信号
wire add_flag;
wire sub_flag;
reg [1:0]add_sync;
reg [1:0]sub_sync;
//使用同步电路检测加减信号
always @ (posedge CLK or negedge RSTn) begin
if(!RSTn) begin
add_sync <= 2'b00;
sub_sync <= 2'b00;
end
else begin
add_sync <= {add_sync[0],add};
sub_sync <= {sub_sync[0],sub};
end
end
// add_flag = 1,为加;
// sub_flag = 1,为减;
assign add_flag <= add_sync[0] & (~add_sync[1]);
assign sub_flag <= sub_sync[0] & (~sub_sync[1]);
always @(posedge clk or negedge RSTn) begin
if(!RSTn) begin
grade <= 7'd5;
grade1 <= 4'b0101;
grade2 <= 4'b0000;
end
else begin
if((add_flag==1)&&(sub_flag==0)) begin //只加不减
grade <= grade+1;
if(grade1==4'd9) begin
grade1 <= 4'd0;
grade2 <= grade2 + 4'd1;
end
else
grade1 <= grade1 + 4'd1;
end
else if((add_flag==0)&&(sub_flag==1)) begin //只减不加
grade <= grade-1;
if(grade1==4'd1) begin
grade1 <= 4'd0;
grade2 <= grade2 - 4'd1;
end
else
grade1 <= grade1 - 4'd1;
else begin //其它状况保持原值
grade <= grade;
grade1 <= grade1;
grade2 <= grade2;
end
end
end
endmodule
以上代码随手写的,没有仿真,大方向没有问题,细节地方你自己调试下。
verilog和C语言有很多不同的地方,有些程序你仿真是可以用的,但是你还是要考虑实际电路状况,比如毛刺,异步电路的时序问题;这些都是verilog中没有讲到的地方,需要和数字电路设计想结合。希望能帮到你。。
你的程序是想构建1个异步电路来实现加减法,但是这样可能会造成以下问题:
1、因为是不同时钟域,异步电路数据传输的时序问题;
2、add,sub是外部输入信号,没做任何滤波处理,使用其边沿触发,若有毛刺可以会造成严重问题;
3、verilog中少用除法,而模除(%)仅能仿真,无法综合,但有的FPGA可以,建议不使用;
可参考以下代码:
module jishu(
add,sub,CLK,RSTn,
grade,grade1,grade2
);
input add,sub,CLK,RSTn;
output [6:0]grade; //liang wei shu
output [3:0]grade1;//ge wei
output [3:0]grade2;//shi wei
reg [6:0]grade;
reg [3:0]grade1;//ge wei
reg [3:0]grade2;//shi wei
//构建2个标志信号和同步信号
wire add_flag;
wire sub_flag;
reg [1:0]add_sync;
reg [1:0]sub_sync;
//使用同步电路检测加减信号
always @ (posedge CLK or negedge RSTn) begin
if(!RSTn) begin
add_sync <= 2'b00;
sub_sync <= 2'b00;
end
else begin
add_sync <= {add_sync[0],add};
sub_sync <= {sub_sync[0],sub};
end
end
// add_flag = 1,为加;
// sub_flag = 1,为减;
assign add_flag <= add_sync[0] & (~add_sync[1]);
assign sub_flag <= sub_sync[0] & (~sub_sync[1]);
always @(posedge clk or negedge RSTn) begin
if(!RSTn) begin
grade <= 7'd5;
grade1 <= 4'b0101;
grade2 <= 4'b0000;
end
else begin
if((add_flag==1)&&(sub_flag==0)) begin //只加不减
grade <= grade+1;
if(grade1==4'd9) begin
grade1 <= 4'd0;
grade2 <= grade2 + 4'd1;
end
else
grade1 <= grade1 + 4'd1;
end
else if((add_flag==0)&&(sub_flag==1)) begin //只减不加
grade <= grade-1;
if(grade1==4'd1) begin
grade1 <= 4'd0;
grade2 <= grade2 - 4'd1;
end
else
grade1 <= grade1 - 4'd1;
else begin //其它状况保持原值
grade <= grade;
grade1 <= grade1;
grade2 <= grade2;
end
end
end
endmodule
以上代码随手写的,没有仿真,大方向没有问题,细节地方你自己调试下。
verilog和C语言有很多不同的地方,有些程序你仿真是可以用的,但是你还是要考虑实际电路状况,比如毛刺,异步电路的时序问题;这些都是verilog中没有讲到的地方,需要和数字电路设计想结合。希望能帮到你。。
本回答被提问者采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
我给你说两点吧。
首先,grade,同一个reg变量,不能同时在两个always里被赋值。因为always是并行执行的。
第二,脉冲信号不能用作判断,如if(add),这个不对。
第三,对于两个脉冲信号add和sub来说,你没有考虑到这两个脉冲信号同时发生的状态。
FPGA是时序性和逻辑性很强的代码,刚开始学习就先用C语言写,写好之后改成verilog。慢慢就喜欢verilog的并行思维了。
首先,grade,同一个reg变量,不能同时在两个always里被赋值。因为always是并行执行的。
第二,脉冲信号不能用作判断,如if(add),这个不对。
第三,对于两个脉冲信号add和sub来说,你没有考虑到这两个脉冲信号同时发生的状态。
FPGA是时序性和逻辑性很强的代码,刚开始学习就先用C语言写,写好之后改成verilog。慢慢就喜欢verilog的并行思维了。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
写个例程给你吧,但是输出不是你想象的2个grade这种来搞,事实上没有应用会这么写。
module sub_add_cnt (
rst,
clk,
add_pulse,
sub_pulse,
cnt_out
)
input rst, clk;
input add_pulse, sub_pulse;
output [7:0] cnt_out;
reg [7:0] cnt_out;
reg add_pulse_meta, add_pulse_sync;
reg sub_pulse_meta, sub_pulse_sync;
always @ (posedge rst or posedge clk)
begin
if (rst)
begin
add_pulse_meta <= 1'b0;
add_pulse_sync <= 1'b0;
sub_pulse_meta <= 1'b0;
sub_pulse_meta <= 1'b0;
end
else
begin
add_pulse_meta <= add_pulse;
add_pulse_sync <= add_pulse_meta;
sub_pulse_meta <= sub_pulse;
sub_pulse_sync <= sub_pulse_meta;
end
end
wire add_one, sub_one;
assign add_one = add_pulse_sync && ~add_pulse_meta;
assign sub_one = sub_pulse_sync && ~sub_pulse_meta;
// add, sub counter
always @ (posedge rst or posedge clk)
begin
if (rst)
cnt_out <= 8'd0;
else
if (add_one)
cnt_out <= cnt_out + 8'd1;
else
if (sub_one)
cnt_out <= cnt_out - 8'd1;
else
cnt_out <= cnt_out;
end
endmodule
module sub_add_cnt (
rst,
clk,
add_pulse,
sub_pulse,
cnt_out
)
input rst, clk;
input add_pulse, sub_pulse;
output [7:0] cnt_out;
reg [7:0] cnt_out;
reg add_pulse_meta, add_pulse_sync;
reg sub_pulse_meta, sub_pulse_sync;
always @ (posedge rst or posedge clk)
begin
if (rst)
begin
add_pulse_meta <= 1'b0;
add_pulse_sync <= 1'b0;
sub_pulse_meta <= 1'b0;
sub_pulse_meta <= 1'b0;
end
else
begin
add_pulse_meta <= add_pulse;
add_pulse_sync <= add_pulse_meta;
sub_pulse_meta <= sub_pulse;
sub_pulse_sync <= sub_pulse_meta;
end
end
wire add_one, sub_one;
assign add_one = add_pulse_sync && ~add_pulse_meta;
assign sub_one = sub_pulse_sync && ~sub_pulse_meta;
// add, sub counter
always @ (posedge rst or posedge clk)
begin
if (rst)
cnt_out <= 8'd0;
else
if (add_one)
cnt_out <= cnt_out + 8'd1;
else
if (sub_one)
cnt_out <= cnt_out - 8'd1;
else
cnt_out <= cnt_out;
end
endmodule
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询