josuah.net | panoramix-labs.fr
When dealing with hardware there is often the need to convert input number to a binary flag output like so:
sel en 0 => 0b1110 1 => 0b1101 2 => 0b1011 ...
For instance, if there are modules plugged like so:
┌─────┐ │ t0 │ ┌───────en0 │ │ ┌───data │ ┌───────────┐ │ │ └─────┘ │ decoder │ │ │ ┌─────┐ │ en0───┘ │ │ t1 │ ─sel en1───────────en1 │ ─data en2───┐ ├───data │ │ │ │ │ └─────┘ │ data───│───┤ ┌─────┐ └───────────┘ │ │ │ t2 │ └───────en2 │ └───data │ └─────┘
Above, there are two inputs: sel
and data
. The sel
signal would be turning only one of the enX
signal on at a time:
en0
if it is 0,en1
if it is 1,en2
if it is 2.It is frequent to have an "enable" signal, (SPI, memories...). This construct is ubiquitous, as you would have noticed there is only one data
signal shared with every other chip.
Then the selection signal sel
permits to choose which of the 3 targets (t0
, t1
, t2
) to communicate with with the shared data
bus. by telling each target:
Which of high or low means listen or ignore is a matter of convention.
I/O are scarce resources on a chip, and this is a very frequently encountered problem. There are actually a lot of small ASICs doing exactly this:
https://octopart.com/search?category_id=4287 ASICs on octopart, going as low as 10 cents for 8 outputs
It is also encountered while in hardware description languages (HDL) designs every time there is a bus with an address field: multiple targets (t0
, t1
, t2
) would read an address port (like sel
above).
Addresses are written at the same time as data and if the address matches, then the data is used, otherwise, it is ignored.
It looks like each target instance is monitoring the sel
address port itself, but when pulling all this monitoring logic and putting it in common, the same construct as above is reproduced: just a matter of point of view.
Here is what happen if we let each device decode its own address:
┌─────┐ │ t0 │ ┌──────addr │ │ ┌───data │ │ │ └─────┘ │ │ ┌─────┐ │ │ │ t1 │ ├──────addr │ │ ├───data │ │ │ └─────┘ data──│──┤ ┌─────┐ addr──┤ │ │ t2 │ └──────addr │ └───data │ └─────┘
The principle behind this is a demultiplexer, and has a reverse operation: a multiplexer.
Depending on a two-bits address (1 and 2), a multiplexer would select which of A, B, C or D transmit to the output Z:
12 || │`. A─┤ │ B─┤ │_Z C─┤ │ D─┤ │ │,'
I would like to implement the opposite: based on the address, I want to select the output.
There might be much to read about this on the Internet, I will see what solution I come-up with for my various use-cases. If you want me to write about it, ping me at me@josuah.net
, I might have tried a few things by then.
https://www.eevblog.com/forum/fpga/address-decoder/
In verilog, using a generate
macro is an easy way to implement it, looping 3 times (in this example) over a variable such as i
, and have addr == i
for matching the slave device to use.
An alternate way is to use the shift operator, that is peforming the decoder function on its own. FPGA work with gates, not assembly statements, so the compiler (such as yosys) will be the one to pick a mesh of gates that solves it.