mowenhui28 发表于 2009-12-27 11:19:56

verilog 程序编译问题

我要实现fre初值为10000,若按一下复位开关add,则fre*2;若按一下dec,则fre/2的操作,仿真出不来,如果减少一个敏感信号就可以,不知为啥,那位高手赐教,不胜感激

module fre_set(add,dec,fre);
input add,dec;
output reg fre;
initial fre=1000000;
always@(negedge add or negedge dec)
begin
if(~add) fre=fre*2;
if(~dec) fre=fre/2;
else fre=fre;
end
endmodule

mowenhui28 发表于 2009-12-27 11:25:07

我换了一种方法改成这样 也不行
module fre_set(add,dec,fre);
input add,dec;
output reg fre;
reg num=0;
reg num1=0,num2=0;
initial fre=40;       
always@(negedge add or negedge dec)
        begin
                if(~add) num1=num1+1;
                if(~dec) num2=num2+1;
                num=num1-num2;
        end
always @(num)
        begin
                case(num)
                -1: begin fre=fre/2;num=0; end
                0:begin fre=fre;num=0;   end
                1:begin fre=fre*2;num=0; end
                endcase
        end
endmodule

Fourier00 发表于 2009-12-27 14:30:07

先把 add 和 dec检测上升沿,然后
然后再时钟的上升沿去对计数器进行×和除乘除就用就直接取高位移动就可以

mowenhui28 发表于 2009-12-27 15:55:18

回复【2楼】Fourier00
-----------------------------------------------------------------------

具体程序怎样写啊? 我试了n多个方法,不是编译出错就是编译通过但没效果,感觉用单片机C51写就简简单单几句话的事到了verilog好难啊!!

Fourier00 发表于 2009-12-27 16:02:46

verilog比c语言简单多了记住这点你就可以写出好代码了
组合逻辑成这样
always@(*)
begin
yyy = zzzz zzzz
end


时序逻辑写成这样
always@(posedge clk or negedge rst_n)
begin
      if(rst_n == 1'b0)
         xxx <= xx'd0
      else
         xxx <=yyy
end

mowenhui28 发表于 2009-12-27 16:31:33

回复【4楼】Fourier00
-----------------------------------------------------------------------

嗯 谢谢 这个我知道
现在我的问题就是只能实现一个按键的操作(只能乘或只能除),仿真也是,把两个键综合在一起就不行了很是郁闷!

Fourier00 发表于 2009-12-27 16:57:04

那你知道,那写出来的是时序逻辑还是组合逻辑,你知道你写的是什么电路吗

Fourier00 发表于 2009-12-27 16:58:00

always@(negedge add or negedge dec)
begin
if(~add) num1=num1+1;
if(~dec) num2=num2+1;
num=num1-num2;
end
你能画一些这个电路吗?

mowenhui28 发表于 2009-12-27 17:13:36

应该属于时序逻辑啊   感觉我写verilog还没从c51的思维转换过来 都是用单片机的思想 呵呵!

edwin 发表于 2009-12-27 22:09:23

回复【8楼】mowenhui28
-----------------------------------------------------------------------

你的程序,组合逻辑和时序逻辑混杂在一起,下降沿写的是时序,
后面又是组合逻辑
还有你的按钮根据按下就硬件高低电平的变化检测边沿,最好是用两个寄存器

msdy 发表于 2009-12-27 22:24:44

if(~add) fre=fre*2;
if(~dec) fre=fre/2; 这个地方为什么要这样写呢?一般都这样写:
if(add==1'b0) fre=fre*2;
if(dec==1'b0) fre=fre/2;

minux 发表于 2009-12-27 22:32:27

【10楼】 msdy

没觉得那么写有啥问题啊……

ngzhang 发表于 2009-12-27 22:39:39

除号不可综合。自己写除法器。

mowenhui28 发表于 2009-12-28 08:53:04

回复【10楼】msdy
-----------------------------------------------------------------------

回复【12楼】ngzhang 兽哥
-----------------------------------------------------------------------

乘法用左移<<除法用右移>> 也可以呀

mowenhui28 发表于 2009-12-28 08:57:46

回复【9楼】edwin
-----------------------------------------------------------------------

两个寄存器的我改成这样了但编译通过,仿真、实际也都没出来啊!崩溃!!哪里有问题么?

module fre_set(clk,add,dec,fre);
input clk,add,dec;
output reg fre;
reg fre_add,fre_dec;
reg num1,num2;
initial fre=40;
always@(negedge add)
begin
    if(~add) begin fre_add=fre*2;num1=1;end
    else   begin fre_add=fre_add;num1=0;end
end

always@(negedge dec)
begin
    if(~dec) begin fre_dec=fre_dec/2;num2=1;end
    else   begin fre_dec=fre_dec;num2=0;end
end

always@(posedge clk)
        begin
                case({num1,num2})
                2'b10:fre=fre_add;
                2'b01:fre=fre_dec;
                default:fre=fre;
                endcase
        end
endmodule

edwin 发表于 2009-12-29 12:17:04

回复【14楼】mowenhui28
-----------------------------------------------------------------------

module fre_set(clk,add,dec,fre,rst);
input clk,add,dec,rst;
output fre;
reg fre,fre_p;
regadd_p, dec_p;

//reg fre_add,fre_dec;
//reg num1,num2;
//initial fre=40;   
always@(posedge clk)//negedge add)
begin
    if(rst) begin fre_p<=40;
                       add_p<=0;
                                                dec_p<=0;
                end   
    else   begin fre<=fre_p;
                      add_p<=add;
                                          dec_p<=dec;
                end
end

always@(add or add_p ordec or dec_p or fre_p)
begin   
//fre_p=fre;
        if ( add_p ==1 && add ==0)
        fre_p=fre_p*2;
       else fre_p=fre_p;
       if ( dec_p ==1 && dec ==0)
        fre_p=(fre_p>>1);
       else fre_p=fre_p;
       
       end
       
          
        /*
    if(~dec) begin fre_dec=fre_dec/2;num2=1;end
    else   begin fre_dec=fre_dec;num2=0;end
end

always@(posedge clk)
begin   
case({num1,num2})
2'b10:fre=fre_add;
2'b01:fre=fre_dec;
default:fre=fre;
endcase
end
*/
endmodule


我仿真可以,试试这个

mowenhui28 发表于 2009-12-29 14:00:47

奇怪 我按这个编译都报错啊而且你同一个fre_p怎么能在两个always里赋值呢? 我把
if(rst) beginfre_p<=40;
               add_p<=0;
               dec_p<=0;
          end
这段放到initial里去了 编译通过 但仿真输出却是出 X(未知状态)

edwin 发表于 2009-12-29 20:02:29

组合逻辑要和时序逻辑分开
我编译都通过了 仿真也可以啊
估计是你的TEST BENCH 的赋值有不确定的状态

mowenhui28 发表于 2009-12-30 08:47:24

回复【16楼】mowenhui28
-----------------------------------------------------------------------

http://cache.amobbs.com/bbs_upload782111/files_24/ourdev_520507.png
(原文件名:QQ截图未命名.png)

奇怪!

ygxycp 发表于 2009-12-30 09:02:39

几个疑点:

1:initial   不能被综合吧?

2:除法和乘法不能直接用吧?可不像在单片机里面写C程序。。。。。。。

minux 发表于 2009-12-30 12:03:54

【19楼】 ygxycp
FPGA里面的initial如果用来赋初值或者加载RAM之类是可以综合的,但是请注意根据场合使用!

mowenhui28 发表于 2009-12-30 13:08:47

还是不行 我现在只能用另外的方式了就是用dec做拨码,拨1时按复位开关add做乘法,拨0时按add做除法,先只能这样了
看似简单的操作在verilog里还真麻烦

edwin 发表于 2009-12-30 14:41:11

initial 不能被综合
乘法可以 除法不行

上次代码发的有点问题


module fre_set(clk,add,dec,fre,rst);
input clk,add,dec,rst;
output fre;

reg fre,fre_p;
regadd_p, dec_p;


always@(posedge clk)
begin
    if(rst==1) begin
                                               
                       fre<=40;
                       add_p<=0;
                                                dec_p<=0;
                end   
    else   begin fre<=fre_p;
                      add_p<=add;
                                          dec_p<=dec;
                end
end

always@(*)
begin   
    fre_p=fre;
//fre_p=fre;
        if ( add_p ==1 && add ==0)
        fre_p=fre_p*2;
       else fre_p=fre_p;
       if ( dec_p ==1 && dec ==0)
        fre_p=(fre_p>>1);
       else fre_p=fre_p;
       
       end
       
          
       
endmodule

edwin 发表于 2009-12-30 14:43:45

测试TB如下

module fre_tb;

        // Inputs
        reg clk;
        reg add;
        reg dec;
        reg rst;

        // Outputs
        wire fre;

        // Instantiate the Unit Under Test (UUT)
        fre_set uut (
                .clk(clk),
                .add(add),
                .dec(dec),
                .fre(fre),
                .rst(rst)
        );
always#5clk=~clk ;
        initial begin
                // Initialize Inputs
                clk = 0;
                add = 0;
                dec = 0;
                rst = 0;

                // Wait 100 ns for global reset to finish
                #100;
   rst = 1;
                #100;
   rst = 0;
                add=1;
                #100;
                add=0;
                #100;
                dec=1;
                #100;
                dec=0;
                #1000;
               
               
      
                // Add stimulus here

        end
      
endmodule

mowenhui28 发表于 2009-12-31 15:59:48

OK! 可以啦按edwin的方法这个问题终于解决啦   不过测试TB那段是干啥的没看懂初学呵呵   
不过你说initial不能综合但我加进去是可以的啊initial fre=40;

相当感谢 edwin 以及其他热心帮助我的朋友谢谢你们!!

edwin 发表于 2009-12-31 21:05:11

那段就是仿真用的啊 ,你不用的啊?
那你怎么知道可以了不?

mowenhui28 发表于 2010-1-2 14:57:33

我是直接用波形仿真的啊硬件也实现啦   没用到测试TB啊

minux 发表于 2010-1-2 16:22:31

对于FPGA,initial一般是可以综合的,但是需要根据情况使用。

比如面向ASIC的时候就不能在可综合代码里面用initial来初始化,不过如果只是面向FPGA,确实有这个需要的话,
用initial是可以的。

ngzhang 发表于 2010-1-2 18:49:18

不要在任何RTL代码中使用initail语句。该语句的使用会造成很多未知的问题。另外,大部分综合工具也不支持或对initail语句的综合的行为不好确定。包括:
ISE 11.3中的 XST,synplify pro 9.6.1,altera qantas2 。
以synplify pro 9.6.1来举例,如果在RTL代码中使用initail语句,工具会做出如下提示:
Initial statement will only initialize memories through the usage of $readmemh and $readmemb. Everything else is ignored
意思就是写了也白写。
在XST中,使用initial来赋初值,与直接写出逻辑复位的作用是不同的,如果目的是为了省掉复位逻辑,那我劝你不要这样做,往往会把时序电路变成含有latch的东西。
最后的建议就是,如果像我一样,自认为赶不上27楼的水平,就别让initial这个关键字出现在自己的rtl代码里。

astudent 发表于 2010-1-2 18:53:39

关注
页: [1]
查看完整版本: verilog 程序编译问题