0
\$\begingroup\$

So, i'm trying to get familiar with VHDL and FPGA's and thought designing a simple processor would be a good idea...

I've implemented the instruction memory, a instruction register, a couple of general purpose registers and the opcode decoder with two basic instructions "load" and "move". The registers and the opcode decoder are connected to a bi-directional 16-bit bus that is controlled by the opcode decoder. Everything works as intended in the simulator but as i try to run it on the actual hardware nothing really works. From looking at the schematics generated during synthesis its obvious that the bus is the main issue.

If i synthesize the register modules by themselves i get the IOBUF's that i would expect are needed for the bi-directional bus to work, but when the modules are used in a bigger design it gets replaced with some other complicated logic that obviously doesn't work.

I've tried using dont_touch and a bunch of other attributes to keep the original synthesis of the modules, but this generates "multiple driver" errors during implementation.

I've been stuck on this bus thing for quite some time and i'm not getting anywhere so perhaps someone who actually knows what they're doing can point me in the right direction...

Oh and i'm using Vivado with the Basys3 dev-board if that's important. If any other information is needed, please feel free to ask. Thanks!

\$\endgroup\$
5
  • \$\begingroup\$ Show us your code and the results. Explain precisely what you mean by "obviously doesn't work". You should be able to create internal bidirectional buses. \$\endgroup\$ Jul 31, 2021 at 11:54
  • \$\begingroup\$ @ElliotAlderson true internal bidir buses ... on which FPGAs? \$\endgroup\$
    – user16324
    Jul 31, 2021 at 12:30
  • \$\begingroup\$ @user_1818839 What do you mean by "true internal bidir"? I meant a named signal in the behavioral design that allows information to be passed in either direction. I don't care how the synthesis tools implement it, as long as it works. \$\endgroup\$ Jul 31, 2021 at 14:29
  • \$\begingroup\$ @ElliotAlderson Ah, that will be transformed by synthesis into unidir buses per answer. \$\endgroup\$
    – user16324
    Jul 31, 2021 at 15:53
  • \$\begingroup\$ @user_1818839 Yes, in my experience you end up with lots of multiplexers and it is not an efficient solution. Nevertheless, I hoped the OP would give us more than "obviously doesn't work". \$\endgroup\$ Jul 31, 2021 at 16:32

1 Answer 1

2
\$\begingroup\$

The secret sauce (if you're using FPGAs newer than Xilinx XC4000) is : don't use bidirectional buses inside the FPGA.

There is one Read bus (everything reads from it) and everything has its own Write bus (which thus never needs to be shared, or tristated). All these Write buses go to one big multiplexer, which drives the Read bus.

The multiplexer is controlled by the address decoding logic (and/or bus arbitration logic if you have more than one bus master, e.g. DMA controllers or multi-core CPUs). Can be extended to multiple Read buses and multiple muxes for multiprocessors, but get familiar with the single Read bus first.

One implementation of the multiplexer is to use the convention that each Write bus is '0' unless explicitly driven (e.g. replacing 'Z' with '0', or adding a 'L' pulldown and letting synthesis make the obvious transformation, or having the address decoder drive '0' to an AND gate on the Write bus) - then the mux itself reduces to a large OR structure.

Or, simply write the mux as a mux and let synth take care of all that.

Every Xilinx FPGA newer than XC4000 (possibly the first generation Virtex, in was SO long ago I can't remember any more) has transformed VHDL "internal bidirectional bus" code using tristates, into exactly this logic eliminating the tristates, and AFAIK almost all other FPGAs have followed this approach some time in the (approx) quarter century since.

Your external bus interface can of course use tristates on a bidirectional bus; internally, it will translate to the above.

Most newer design hides all the details in "AXI bus IP cores" ... for portability you may want to consider doing the same, but if you're rolling your own CPU you may want to roll your own bus too; it's not that difficult.

\$\endgroup\$
4
  • \$\begingroup\$ Cool cool cool! As i said, I'm very new to this, but it just seemed to me that a bi-directional bus would be, by far, the more efficient way to implement this, resource wise, but i guess that might not be true. Is there any particular reason that buses are done in the way you explained? \$\endgroup\$ Jul 31, 2021 at 14:44
  • \$\begingroup\$ I believe the internal routing doesn't lend itself to tristates, and direct logic implementations were faster anyway. \$\endgroup\$
    – user16324
    Jul 31, 2021 at 15:55
  • \$\begingroup\$ worked like a charm, thank you. \$\endgroup\$ Jul 31, 2021 at 22:06
  • \$\begingroup\$ One thing to think about is how do you test an on-chip tristate bus? On a board, they use bed of nails testers to probe the board an verify that a tristate is really acting like a tristate - ie: it can be either pulled up or down. \$\endgroup\$
    – Jim Lewis
    Aug 2, 2021 at 11:08

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.