Electronic – Verilog – connecting multiple bidirectional buses

bidirectionalfpgaprogrammable-logicverilog

I've been designing a retro computer in verilog as an exercise and so far have a simple 8-bit CPU that communicates directly with a single RAM chip via a bidirectional data port. This works great in my testing, however the need has arisen to include a second RAM on a different bus, as video RAM that both the CPU and a graphics processor can interact with. To achieve this, I implemented a memory controller module. This module connects directly to both RAM chips on separate buses, and reads/writes to/from the CPU now have to go through this module.

Simplified module connections:

module memcontroller(inout[7:0] CPUdataBus, inout[7:0] RAMdataBUS, inout[7:0] VRAMdataBus)

When connecting the CPU directly with the RAM, I would just set the data bus to Hi-Z to use it as an input and read data from RAM. However, now I do this on the "RAMdataBUS" port and need a way to "connect" the input to the CPUdataBus port, which I can't figure out.

Perhaps naively, I thought something like this would work:

assign CPUdataBus = write ? CPUdataBus : RAMdataBUS;
assign RAMdataBUS = write ? CPUdataBus : 8'hZZ;

Which produces during synthesis:

RAMdataBus[7]" has multiple drivers due to the always-enabled I/O buffer "CPUdataBus[7]"

for each bit

There's likely a really obvious reason why this is invalid, but nonetheless I can't find a solution to the problem or fully understand the error.

Best Answer

Think of this in terms of hardware. RAMdataBUS outputs data or is tri-stated. But CPUdataBus is a mux. You can't connect a tristate to a mux. You can connect a tri-sate bus to anther tri-state bus.

Assuming write is the CPU write the CPU bus should be driven when writing, but tri-state when reading:

assign CPUdataBus = write ? CPUdataOut : 8'hZZ;

The memory bus should be driven (by the memory) when reading, but tri-state when writing:

assign RAMdataBUS = !write ? memory_data_out :  8'hZZ;

But that is not correct if you have multiple memories. Then it becomes:

assign RAMdataBUS = !write && this_mem_selected ? memory_data_out :  8'hZZ;