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.

  • \$\begingroup\$ You have a conflicting statement: when "write" is true, the CPUdataBus is driven by itself. \$\endgroup\$ – Ale..chenski Jul 4 '18 at 19:21
  • \$\begingroup\$ 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 \$\endgroup\$ – Triforcer Jul 4 '18 at 19:25
  • \$\begingroup\$ 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. \$\endgroup\$ – 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;
  • \$\begingroup\$ Thanks. I might be missing something, but in your examples, how does a data input on the RAM bus reach the CPU bus? \$\endgroup\$ – Triforcer Jul 4 '18 at 19:28
  • \$\begingroup\$ 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. \$\endgroup\$ – Oldfart Jul 4 '18 at 19:38
  • \$\begingroup\$ 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! \$\endgroup\$ – Triforcer Jul 4 '18 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.