3
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ You have a conflicting statement: when "write" is true, the CPUdataBus is driven by itself. \$\endgroup\$ Commented Jul 4, 2018 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
    Commented Jul 4, 2018 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\$ Commented Jul 4, 2018 at 19:28

1 Answer 1

4
\$\begingroup\$

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;
\$\endgroup\$
3
  • \$\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
    Commented Jul 4, 2018 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
    Commented Jul 4, 2018 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
    Commented Jul 4, 2018 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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