BRAM Refactoring & Clock Speed Optimization
Motivation
The original HaDes-V BRAM model used a dual-port memory design that supplied data on the falling edge of the clock. This forced the entire read path, BRAM address decode, memory array access, and the Wishbone ACK/data multiplexing, to complete within a single half-cycle. The synthesizer could not pipeline this path, limiting the achievable system frequency to approximately 50 MHz on the Basys 3 target.
For DOOM, every additional MHz directly translates into more instructions per second, which means more rendering throughput and a smoother frame rate. Increasing the clock speed to 75 MHz was therefore a key performance goal.
BRAM Refactoring
The wishbone_ram.sv module was redesigned to remove the falling-edge behavior and instead operate as a conventional single-cycle memory:
always_ff @(posedge clk) begin
if (rst) begin
port_a.ack <= 0;
port_a.err <= 0;
port_a.dat_miso <= 0;
end else begin
port_a.ack <= 0;
port_a.err <= 0;
if (port_a.cyc && port_a.stb && !port_a.ack) begin
if (port_a.adr >= ADDRESS && port_a.adr < ADDRESS + SIZE) begin
port_a.ack <= 1;
if (!port_a.we) begin
port_a.dat_miso <= memory[port_a.adr - ADDRESS];
end else begin
// Byte-level writes via sel mask
end
end else begin
port_a.err <= 1;
end
end
end
end
The key changes were:
- Synchronous reads: data is now registered and available on the next rising edge, giving the toolchain a full clock cycle for the memory access path
- Simplified control:
ackis asserted unconditionally on the next cycle for valid accesses, rather than using the half-clock scheme - Byte-level writes preserved: write masking via
selremains unchanged for correct sub-word writes
Clock Speed Increase
With the BRAM timing path resolved, the MMCM configuration in clk_params.sv was adjusted to raise the CPU clock from 50 MHz to 75 MHz:
localparam real MMCM_MUL = 6.000; // VCO: 100 MHz * 6 = 600 MHz
localparam int MMCM_DIV = 1; // Input divider
localparam real MMCM_DIV_75 = 8.000; // 600 MHz / 8 = 75 MHz (CPU)
localparam int MMCM_DIV_200 = 3; // 600 MHz / 3 = 200 MHz (MIG refclk)
The 600 MHz VCO output drives both the 75 MHz system clock (for the CPU, caches, and peripherals) and the 200 MHz reference clock (for the DDR2 MIG controller).
Pipeline Adjustments
The instruction fetch stage (fetch_stage.sv) and memory stage (memory_stage.sv) were updated to account for the single-cycle BRAM access model. The memory stage’s BRAM read path now correctly expects data on the next cycle, and the stall/forwarding logic around memory operations was tightened to prevent mis-speculations.
Result
The CPU core now runs at a stable 75 MHz on the Nexys 4 DDR, a 50% increase over the original 50 MHz Basys 3 design. This clock speed was maintained throughout all subsequent additions (caches, M-Extension, peripherals), and the timing analysis consistently passes with the Explore-directive place-and-route flow used in the synthesis script.