Skip to content

Verilog doesn't useelse so memory not inferred as RAM #709

@sclukey

Description

@sclukey

Chisel seems to not like using else and else if in Verilog code, and this has caused a problem with my RAM block not being inferred by the Vivado synthesizer because it thinks there are more write ports than there actually are. As a minimal example, this Chisel code

class VectorWriter() extends Module {
    val io = new Bundle {
        val mode = Bool(INPUT)
        val rw_addr = UInt(INPUT, width=8)
        val w_addr = UInt(INPUT, width=8)
        val writeData = UInt(INPUT, width=16)
        val readData = UInt(OUTPUT, width=16)
    }

    val memory = Mem(UInt(width=16), 256)

    when(io.mode) {
        memory(io.rw_addr) := io.writeData
    } .otherwise {
        memory(io.w_addr) := io.writeData
    }

    io.readData := memory(io.rw_addr)
}

results in this Verilog

module VectorWriter(input clk,
    input  io_mode,
    input [7:0] io_rw_addr,
    input [7:0] io_w_addr,
    input [15:0] io_writeData,
    output[15:0] io_readData
);

  wire[15:0] T0;
  reg [15:0] memory [255:0];
  wire[15:0] T1;
  wire T2;
  wire[15:0] T3;

  assign io_readData = T0;
  assign T0 = memory[io_rw_addr];
  assign T2 = io_mode ^ 1'h1;

  always @(posedge clk) begin
    if (T2)
      memory[io_w_addr] <= io_writeData;
    if (io_mode)
      memory[io_rw_addr] <= io_writeData;
  end
endmodule

The memory registers should be implemented as a RAM with one read port and one write port. However, when synthesizing this code the Vivado synthesizer gives this warning saying that this is not possible:

WARNING: [Synth 8-4767] Trying to implement RAM 'memory_reg' in registers. Block RAM or DRAM implementation is not possible; see log for reasons.
Reason is one or more of the following :
    1: RAM has multiple writes via different ports in same process. If RAM inferencing intended, write to one port per process. 
    2: Unable to determine number of words or word size in RAM. 
    3: No valid read/write found for RAM. 
RAM "memory_reg" dissolved into registers

In this case the reason is number 1. Because the writes to the RAM are in independent if statements, the synthesizer thinks that both writes might happen at the same time, so it cannot be a single port RAM.

Now, obviously the if statements are never both going to be true, and if I were hand-writing the Verilog I would write this (just like the Chisel)

    if (io_mode)
      memory[io_rw_addr] <= io_writeData;
    else
      memory[io_w_addr] <= io_writeData;

which is inferred correctly as a RAM block.

The Verilog output seems counterintuitive and in this case problematic, so I think this is an issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions