# Verilog - connecting multiple bidirectional buses

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.

• You have a conflicting statement: when "write" is true, the CPUdataBus is driven by itself. – Ale..chenski Jul 4 '18 at 19:21
• That's true, I thought it looked odd, but what I wanted to say was that CPUdataBus should just be "itself" when it's acting as an output. If that makes sense – Triforcer Jul 4 '18 at 19:25
• Apparently the Verilog compiler can't make sense of what do you mean, and is looking for a driver. My Verilog is rusty, and I need to look into my projects of 10-years old to find the right language structures for you, and I feel lazy. See the Oldfart answer. – Ale..chenski Jul 4 '18 at 19:28

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;

• Thanks. I might be missing something, but in your examples, how does a data input on the RAM bus reach the CPU bus? – Triforcer Jul 4 '18 at 19:28
• These assigns are normally inside the modules. At the top level you connect all the data bus signals together. Just like on a real PCB. – Oldfart Jul 4 '18 at 19:38
• It's so obvious now you say it, thank you. I don't know why I wasn't thinking about connecting at the top level! – Triforcer Jul 4 '18 at 19:55