Artlav
Full Member level 2
Let's say i have a parallel static RAM that is running at one frequency (8 MHz), and a CPU (in the FPGA) tthat is running at a higher frequency (16MHz).
The CPU asserts a read or write signal, the RAM gets accessed, sets a done flag for one clock, the CPU sees the flag and deassert the request signal.
It all works fine when they both use the same clock, but if i lower the RAM clock (either from dividing the CPU one or async from a PLL), things start to lock up and act weird.
I suspect this needs some sort of synchronization. I tried to sync the done flag (running theory was that the flag stays up as the CPU carries on and messes something up on next reads) and read and write flags (just in case), as described here: http://fpga4fun.com/CrossClockDomain2.html
However, that had no effect (maybe even made it worse, since with the sync it locks up almost reliably).
What can i be doing wrong?
How is this normally done?
The code for the RAM controller:
The CPU asserts a read or write signal, the RAM gets accessed, sets a done flag for one clock, the CPU sees the flag and deassert the request signal.
It all works fine when they both use the same clock, but if i lower the RAM clock (either from dividing the CPU one or async from a PLL), things start to lock up and act weird.
I suspect this needs some sort of synchronization. I tried to sync the done flag (running theory was that the flag stays up as the CPU carries on and messes something up on next reads) and read and write flags (just in case), as described here: http://fpga4fun.com/CrossClockDomain2.html
However, that had no effect (maybe even made it worse, since with the sync it locks up almost reliably).
What can i be doing wrong?
How is this normally done?
The code for the RAM controller:
Code:
//----------------------------------------------------------------------------//
module ffram_controller(
input rst,
input clk,
output reg [14:0] fram_addr,
inout [15:0] fram_io,
output reg fram_oe,
output reg fram_we,
output reg fram_ce,
input [31:0] addr,
input [31:0] data2mem,
output reg [31:0] data2cpu,
input re,
input we,
output reg done
);
//----------------------------------------------------------------------------//
reg [2:0] state;
reg [15:0] xlate_data;
wire [14:0] xlate_addr;
//----------------------------------------------------------------------------//
parameter [2:0] idle=3'd0;
parameter [2:0] re_a=3'd1;
parameter [2:0] re_b=3'd2;
parameter [2:0] we_a=3'd3;
parameter [2:0] we_b=3'd4;
parameter [2:0] we_c=3'd5;
parameter [2:0] skip=3'd6;
//----------------------------------------------------------------------------//
assign xlate_addr=addr[15:1];
//----------------------------------------------------------------------------//
always @(posedge clk)
begin
if(rst)begin
data2cpu<=0;
state<=idle;
done<=0;
fram_addr<=15'h7FFF;
xlate_data<=16'hFFFF;
fram_oe<=1;
fram_we<=1;
fram_ce<=1;
end else begin
case(state)
idle:begin
done<=0;
fram_oe<=1;
fram_we<=1;
fram_ce<=1;
if(re)begin
state<=re_a;
fram_addr<=xlate_addr;
fram_oe<=0;
fram_we<=1;
fram_ce<=0;
end
if(we)begin
state<=we_a;
fram_addr<=xlate_addr;
xlate_data<=data2mem[15:0];
fram_oe<=1;
fram_we<=0;
fram_ce<=0;
end
end
re_a:begin
data2cpu[15:0]<=fram_io;
fram_addr<=xlate_addr+1'd1;
state<=re_b;
end
re_b:begin
data2cpu[31:16]<=fram_io;
done<=1;
state<=skip;
fram_oe<=1;
fram_we<=1;
fram_ce<=1;
end
we_a:begin
fram_we<=1;
state<=we_b;
end
we_b:begin
xlate_data<=data2mem[31:16];
fram_addr<=xlate_addr+1'd1;
fram_we<=0;
state<=we_c;
end
we_c:begin
done<=1;
state<=skip;
fram_oe<=1;
fram_we<=1;
fram_ce<=1;
end
skip:begin
done<=0;
state<=idle;
end
endcase
end
end
//----------------------------------------------------------------------------//
assign fram_io=we?xlate_data:16'bzzzzzzzzzzzzzzzz;
//----------------------------------------------------------------------------//
endmodule
//----------------------------------------------------------------------------//