I'm building a small RISC FPGA CPU on an Artix-7 (Arty A7-100 (xc7a100tcsg324-1) board. It runs fine, most instructions take three clocks (non-pipelined), but due to crazy net delays, can only run at 100/50 MHz. 100 MHz for RAM which governs the speed of other signals. Most of the lowest-slack paths are those connecting to the RAM. I used the Clock Generator Wizard to create a dual output clocking IP.
The problem is that I'm using almost all the BlockRAM on the device, so my signal fanout looks like this (e.g. this is the signal fanout for ram_dinb to the BlockRAM, other connections are similar):
At 100 Mhz, the timing requirement is of course 10.0 ns. My Net delay here is 8.907, which seems absurdly high... but when I highlight and zoom in on these paths, they meander all over the place, so no wonder the net delay is so high...
So I studied a bit and even tried using the many horizontal BUFHCEs available, but this immediately failed because I used the Block Memory Generator to create this 256K-word RAM, it looks monolithic, even though it spans the entire die. So for example if I wanted to use this on a single BlockRAM primitive in region X1Y2, I might use something like:
wire clk_ram_12; // region X1Y2
BUFHCE #( .CE_TYPE("SYNC"), .INIT_OUT(0) )
BUFHCE_ram_12 (
.O(clk_ram_12),
.CE(1'b1),
.I(clk_ram) // from the MMCM
);
Except that the Block Memory Generator interface only allows for two clock connections at the module level, not to mention all the other signals like data, address, etc.
RAM256 ram (
.clka(clk_ram),
.wea(2'b00), // Never write to port A because it's connected to the program counter.
.addra(pc),
.dina(18'b0), // Never write to port A because it's connected to the program counter.
.douta(ram_douta),
.clkb(clk_ram),
.web(ram_web),
.addrb(ram_addrb),
.dinb(ram_dinb),
.doutb(ram_doutb)
);
I feel like I'm missing something fundamental here. Is there any way I can speed this up? Or am I hopelessly painted into a corner with this BlockRAM? Even if I create a clock tree using BUFHCE and BUFG primitives somehow, it still doesn't solve my problems for other signals, like data, address, write-enable, etc. I've been reading Xilinx user guides for two days now with no promising ideas.