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– Ale..chenski2018年07月04日 19:21:51 +00:00Commented 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– Triforcer2018年07月04日 19:25:16 +00:00Commented 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\$Ale..chenski– Ale..chenski2018年07月04日 19:28:32 +00:00Commented Jul 4, 2018 at 19:28
1 Answer 1
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– Triforcer2018年07月04日 19:28:58 +00:00Commented 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– Oldfart2018年07月04日 19:38:57 +00:00Commented 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– Triforcer2018年07月04日 19:55:28 +00:00Commented Jul 4, 2018 at 19:55
Explore related questions
See similar questions with these tags.