I've been looking into inferring true dual-port (TDP) FPGA BRAMs in Chisel, and wanted to get a few opinions on this. (Note: I've only access to Xilinx FPGAs, tried this with only Vivado 2014.x so far -- might be different for Altera and more recent Vivado versions. If you have some experience with other synth tools, please share your wisdom :))
With Chisel-generated Verilog, inferring single-port BRAMs seem to work fine (i.e. a Mem() with one read-write port) but so far I've had no success for dual-port BRAMs. I've experimented with manually modifying the generated Verilog to see which changes are needed, and it looks like the issue is both ports being in a single "always @(posedge clk)" block. Separating the second port's statements into a separate block seems to infer TDP BRAMs just fine.
1) Use BlackBox to instantiate parametrizable Verilog infers BRAMs properly, adding a simple BRAM model in the BlackBox to support emulation as well. I've had a go at this at
https://github.com/maltanar/fpga-tidbits/blob/platform-layer/on-chip-memory/DualPortBRAM.scala -- not tested extensively but it works. The disadvantage here is having to manually add the Verilog code for synthesis, and having to use this Verilog model for the BRAM as a fixed building block (arguably the way it should be anyway, but the model should be flexible).
2) Somehow force Chisel to generate a separate always block for the second port. Haven't tried this, but so far it this only seems to be possible by adding a new clock domain and making the port2 signals go through that. This makes good sense for the dual-port dual-clock BRAM case, but I want to keep my design simple and stick to a single clock domain (creating a new Clock that uses implicitClock as the clocking source still creates a new domain and adds the new clock ports up the hierarchy).
Yaman