高手看看,能不能确定是FPGA板的问题?有代码有波形
本帖最后由 sme 于 2013-11-16 12:04 编辑买了一块FPGA板,以前在spartan3/spartan6上好好的项目,弄到这块Artix-7上,出问题了。用片内逻辑分析仪抓了半天信号,发现是RAM问题,将电路反复复位(由上位机控制,在电路内部产生复位信号)、运行,RAM中的数据会变。
(RAM当程序ROM用,由上位机下载进去,下载完后不再更新。RAM速度为6~12MHz)。
1. 首选怀疑是不是电路有问题
用100MHz的时钟来抓we信号,没有发现we有高电平。
2. 难道有毛刺?把we接成0,上位机不更新RAM,只在综合时将初始值置进去。
仍然会出错。
3. 多放一片一样的RAM,地址、时钟、we全接一样,两片RAM的输出做个比较电路,以检测ROM内容是否发生变化。
结果:会发生变化。即使we接0,也会。
我个人觉得,一片RAM,WE接地,但是初始化进去的数据却会随机改变,硬说是我电路的设计问题,我是无法接受的。
结论在16、21、22楼。
高手在民间啊。
厂家的技术,一会是软件问题,一会是IO问题,另外又是代码问题:
不要用parameter!
U_DLY的延时,仿真和综合结果会不一样!
1<<ADDR_WIDTH,这种写法不对!
mem文件和RAM深度不一致!
看图,两片RAM的输出,u_irom/dout和u_irom_ref/dout和code对比,有不一致的。
这个错得更多 本帖最后由 sme 于 2013-11-15 17:27 编辑
为了简单,我又做了实验,单独做了个工程,就放两片RAM和比较电路,并把它发给了厂家的技术人员。
附件里是源代码,高手可以看下。
使用这个电路,按板上的复位键,会随机出错(rom_err=1)。
为了验证是不是我的板子有缺陷,让厂家也用他们手头的板子了试验,结果是:按复位键,rom_err会随机出现1。
和我的结果一样。
证明至少两边的板子是一样的现象。
我的工程,用片内逻辑分析仪抓到的,两个RAM的输出出现不一致。 厂家的答复是:
用他们自己的代码不会出现问题,我的问题是随机现象,是设计问题。
在这里高手看一下,我的设计到底有什么问题? rom的描述:
`define U_DLY 1
`timescale 1ns/1ns
module c8051f_irom (
clk,
addr,
di,
we,
oe,
ce,
dout
);
parameter ADDR_W = 14;
parameter BUS_W = 8;
parameter ROM_FILE = "HIDtoUART.mem";
input clk;
input addr;
input di;
input we;
input oe;
input ce;
output dout;
`ifdef ASIC
`else
reg mem [(1<<ADDR_W)-1:0];
reg rd_addr;
initial
begin
$readmemh(ROM_FILE,mem);
$display("**************************************************************");
$display("* *");
$display("*Read code file from file %s *",ROM_FILE);
$display("* *");
$display("**************************************************************");
end
always @(posedge clk)
begin
if (ce & we)
mem <= #`U_DLY di;
rd_addr <= #`U_DLY addr;
end
assign #`U_DLY dout = (ce & oe) ? mem : 8'h00;
`endif
endmodule 帮顶,等高手。。。{:smile:} 本帖最后由 sme 于 2013-11-15 17:32 编辑
rom的调用:
wire irom_read_data;
wire irom_ref_data;
c8051f_irom #(`ROM_ADDR_WIDTH) u_irom (
.clk (rom_clk),
.addr (irom_addr[`ROM_ADDR_WIDTH-1:0]),
.di (8'h00), // irom_addr),
.we (xween), // 这引脚接到FPGA的引脚,用拔动开关,控制写信号是否有效。如果外部接到高电平,则ram内容全被全写成0,可以看到rom_err为高;当外部接低电平时,当ROM用
.oe (1'b1),
.ce (1'b1),
.dout (irom_read_data)
);
c8051f_irom #(`ROM_ADDR_WIDTH) u_irom_ref (
.clk (rom_clk),
.addr (irom_addr[`ROM_ADDR_WIDTH-1:0]),
.di (8'h00),
.we (1'b0), // 这个接成0,当ROM用
.oe (1'b1),
.ce (1'b1),
.dout (irom_ref_data)
); 两个rom 的输出进行比较:
`ifdef ASYNC_RESET
always @(negedge rst_n2 or posedge rom_clk)
`else
always @(posedge rom_clk)
`endif
begin
if (!rst_n2)
rom_err <= 1'b0;
else
rom_err <= irom_read_data != irom_ref_data;
end 本来不想回帖,回了也是灌水。。。{:dizzy:} WM_CH 发表于 2013-11-15 17:30 static/image/common/back.gif
本来不想回帖,回了也是灌水。。。
电路很简单,用心去看,一定能了解。 除了Verilog,Waveform. FPGA还有很多东西,比如你这个问题需要赶紧看timing report.
我个人猜测主要问题出在:
reg mem [(1<<ADDR_W)-1:0];
这种写法,导致mem逻辑巨大。跑不到12M。
建议有三个:
[*]减小RAM尺寸,减小到1KBYE,从新实验,如果过了,那说明猜的没错。
[*]给CLK增加一条Clock约束,约到大于12M,然后再用12M做测试。
[*]芯片自带ROM/RAM的IP要用起来。
本帖最后由 sme 于 2013-11-16 09:10 编辑
uindex 发表于 2013-11-16 00:53 static/image/common/back.gif
除了Verilog,Waveform. FPGA还有很多东西,比如你这个问题需要赶紧看timing report.
我个人猜测主要问题出 ...
谢谢你的回复,个人认为并不是以上原因。
1. 关于mem的写法,这个是没有问题的,只是定义了两个参数而已,用参数没理由就导致RAM巨大。
下面是xilinx的Language Template的写法:
parameter RAM_WIDTH = <ram_width>;
parameter RAM_ADDR_BITS = <ram_addr_bits>;
(* RAM_STYLE="{AUTO | BLOCK |BLOCK_POWER1 | BLOCK_POWER2}" *)
reg <ram_name> [(2**RAM_ADDR_BITS)-1:0];
reg <output_data>;
<reg_or_wire> <address>;
<reg_or_wire> <input_data>;
//The following code is only necessary if you wish to initialize the RAM
//contents via an external file (use $readmemb for binary data)
initial
$readmemh("<data_file_name>", <rom_name>, <begin_address>, <end_address>);
always @(posedge <clock>)
if (<ram_enable>) begin
if (<write_enable>)
<ram_name>[<address>] <= <input_data>;
<output_data> <= <ram_name>[<address>];
end
由上可见,同样是使用的参数定义。
定义参是为了调用方便,没有规定不能用参数吧?1<<n 和2**n是一样的。我给的ADDR_W是的14,综合出来的就是16KB,结果并没有错。
2. 减小RAM尺寸
这个上班了我会再试。
3. 增加约束。
我是从spartan3/spartan6换到artix-7,这种跑1、20M时钟的电路,很轻易。
并且,我估的这个测试工程,就2片RAM,没有理由连12M都跑不到。
再,你看我在二楼的图片,我是用的100MHz的时钟来找取ROM的信号,ROM的速度完全没有问题。
4. 用IP
之所以不用IP,是为了移值方便。我自己做的东西,除了跟物理特性有关的,像DCM、PLL等,能不用IP尽量不用IP,这样换型号最方便。
做的这个测试工程,已经是精简至极,我觉得只要RAM的WE是无效的,没有理由RAM内容会变化。
之前我是整个项目出错,找了好久才发现是RAM的问题。通过片内逻辑分析仪可以确定,时序、速度都没问题,百思不得其解,然后才想到调用两次来比较结果,确认不是电路会存在误写导致数据出错。 这个地方 应该是时钟有毛刺引起的,你给了一个分频时钟,然后这个时钟可能有毛刺,导致ram的地址出现了亚稳态,然后ram里面的数据被修改了,ram应用中即使是不写使能不为1,只要是读写地址出现了亚稳态都会修改ram里面的数据,我建议LZ把时钟修改成时钟使能,而不是直接用作时钟 Fourier00 发表于 2013-11-16 10:47 static/image/common/back.gif
这个地方 应该是时钟有毛刺引起的,你给了一个分频时钟,然后这个时钟可能有毛刺,导致ram的地址出现了亚稳 ...
嗯,兄弟这句话确实有一定的道理。
我有两个疑问:
1. 分频时钟有毛刺
个人认为这不太可能。不管是用同步分频,还是使用2分频的异步串联,只要最后抽出来的时钟,是从寄存器出来,都不可能有毛刺。
2. 分频电路如下:
`ifdef ASYNC_RESET
always @(negedge rst_n or posedge clk100m)
`else
always @(posedge clk100m)
`endif
begin
if (!rst_n)
div <= 8'h00;
else
div <= div + 1;
end
assign rom_clk = div; // 100MHz/8
这种除8的电路,应该是没有毛刺的。 还有一种可能就是你的异步复位没有做同步化引起的,同时时钟也不稳定,导致ram里面的数据被改写
`define ROM_ADDR_WIDTH 14
`define ASYNC_RESET 1
module top (
input clk100m,
input rst,
input xween /* synthesis xc_pulldown = 1 */,
output rom_clk,
output reg rom_err
);
reg div;
reg rst_n_ff;
wire rst_n;
reg rst_1syn;
reg rst_2syn;
wirerst_n ;
wirerom_clk ;
always @(posedge clk100m)
begin
rst_1syn <= ~rst;
rst_2syn <= rst_1syn;
end
assign rst_n =rst_2syn;
always @(negedge rst_n or posedge clk100m)
begin
if (!rst_n)
div <= 8'h00;
else
div <= div + 1;
end
assign rom_clk = (div == 3'd0)?1'b1:1'b0; // 100MHz/8
reg [`ROM_ADDR_WIDTH-1:0] irom_addr;
always @(negedge rst_n or posedge clk100m)
begin
if (!rst_n)
irom_addr <= 0;
else if(rom_clk == 1'b1)
irom_addr <= irom_addr + 1;
end
wire irom_read_data;
wire irom_ref_data;
c8051f_irom #(`ROM_ADDR_WIDTH) u_irom (
.clk (clk),
.addr (irom_addr[`ROM_ADDR_WIDTH-1:0]),
.di (8'h00), // irom_addr),
.we (xween),
.oe (1'b1),
.ce (1'b1),
.dout (irom_read_data)
);
c8051f_irom #(`ROM_ADDR_WIDTH) u_irom_ref (
.clk (clk),
.addr (irom_addr[`ROM_ADDR_WIDTH-1:0]),
.di (8'h00),
.we (1'b0),
.oe (1'b1),
.ce (1'b1),
.dout (irom_ref_data)
);
always @(negedge rst_n or posedge clk100m)
begin
if (!rst_n)
rom_err <= 1'b0;
else
rom_err <= irom_read_data != irom_ref_data;
end
endmodule
Fourier00 发表于 2013-11-16 10:59 static/image/common/back.gif
还有一种可能就是你的异步复位没有做同步化引起的,同时时钟也不稳定,导致ram里面的数据被改写
...
这个可能说到点子上了,我想想。 Fourier00 发表于 2013-11-16 11:00 static/image/common/back.gif
我明白你的意思,使用使能的方式,有两个问题:
1. 与我的IC不符。
做IC时是有不少分频时钟的,做FPGA是为了ASIC的前期验证。
2. 这种方式,耗电会大不少,因为整个电路都是以最高频率在运行。当然,FPGA耗电大点无所谓。 sme 发表于 2013-11-16 11:05 static/image/common/back.gif
我明白你的意思,使用使能的方式,有两个问题:
1. 与我的IC不符。
做IC时是有不少分频时钟的,做FPGA是 ...
FPGA 里面不推荐使用分频时钟的,做ASIC验证 应该有一定的规则来处理这种分频时钟的吧,比如说时钟使能,或者说分频出去在上锁相环然后上全局,我没有做过ASIC验证,所以不知道你们这些是怎么处理的,还有就是分频时钟其实分频了反转率降低了,动态功耗会下降,但是相比与直接的时钟降频来说,静态功耗还是会要高些 本帖最后由 sme 于 2013-11-16 11:32 编辑
Fourier00 发表于 2013-11-16 10:59 static/image/common/back.gif
还有一种可能就是你的异步复位没有做同步化引起的,同时时钟也不稳定,导致ram里面的数据被改写
...
你说的这点,可能要从RAM的电路结构入手。
我曾经反向过由foundry提供的memory compiler出来的RAM,其原理、结构可能和FPGA里的block RAM一样。
同步RAM的信号,通常是CLK、CE、OE、WE、ADDR、DI。
OE在这里不考虑,只控制输出的buffer。
其它的信号,利用CLK来采样。
CLK的处理,最为关键。我看到的电路,是利用CLK产生一极窄的单击脉冲,来锁存输入信号。
ADDR、DI等输入信号的变化,在CLK边沿无效时,是不会影响电路的任何功能。
但在CLK的单击脉冲这段时间内,如果WE无效,是作读操作,由ADDR来确定选中的RAM单元。
一个RAM单元一般都是6T结构,同一时刻,其bit line选中的同一列中,只能选中一行,如果选中了多行,就可能会改写数据。
如果此时ADDR在变化,就会出现word line选择的毛刺,可能有多行被选中。
回到我的电路:
rom_clk是12.5MHz,其地址线也是由rom_clk计数产生,因此不管地址和时钟是用同一沿,或是分别用上升、下降沿,其setup/hold都满足。
并且,rom_clk应该也无毛刺。
问题出在复位上。
当异步复位发生时,有可能正好发生在rom_clk的有效沿,而此时ADDR也会复位。这一组ADDR在此时的变化,会导致Setup/hold不满足,从而使RAM的WE即使无效,其数据也有可能被改。
{:sweat:} 亚稳态修改ram Fourier00 发表于 2013-11-16 11:45 static/image/common/back.gif
亚稳态修改ram
嗯,应该就是这个问题。{:handshake:} 菜鸟一枚,只是来学习的!谢谢高手分享~ 楼主公布一下修改后的测试结果把; jm2011 发表于 2013-11-16 22:33 static/image/common/back.gif
楼主公布一下修改后的测试结果把;
已经通过测试,就是异步复位的原因。 菜鸟观摩了!{:sweat:} 呵呵,异步复位同步释放。话说楼主不是在广告区做mcu ic定制的那位? winster321 发表于 2013-11-17 09:09 static/image/common/back.gif
呵呵,异步复位同步释放。话说楼主不是在广告区做mcu ic定制的那位?
嗯,是的。
这个问题,异步复位、同步释放,也是解决不了的。和异步复位、异步释放比起来,只是将出错机率减少了50%。
页:
[1]