Author Topic: Address decoder  (Read 1451 times)

0 Members and 1 Guest are viewing this topic.

Offline josuahTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: fr
    • josuah.net
Address decoder
« on: April 22, 2022, 04:13:08 pm »
Hello engineers and hobbyists!

This seems like a frequent use-case: turning an address into a bit saying "it's my turn" or "ignore the data".

For that, just an equal sign works:

Code: [Select]
if (address == 0x3F)
But if we look at things from the opposite angle, it might be seen as turning an address into an array of "clock select" signal, one bit per peripheral. Like it is on SPI, with an "enable" signal (en0, en1, en2...).

Code: [Select]
                         ┌─────┐
                         │ t0  │
                 ┌───────en0   │
                 │   ┌───data  │
 ┌───────────┐   │   │   └─────┘
 │ decoder   │   │   │   ┌─────┐
 │         en0───┘   │   │ t1  │
─sel       en1───────────en1   │
─data      en2───┐   ├───data  │
 │           │   │   │   └─────┘
 │        data───│───┤   ┌─────┐
 └───────────┘   │   │   │ t2  │
                 └───────en2   │
                     └───data  │
                         └─────┘

This would permit me to write modules with all the "bus" architecture out of the way.

For instance (I do not know VHDL yet, so it is Verilog): using https://stackoverflow.com/questions/1378159/ I could then make a batch of PWM channels in an array of CHANNELS instances:

Code: [Select]
        wb_pwm_channel #(
                .BITS(BITS)
        ) channel[CHANNELS-1:0] (
                .wb_clk_i(wb_clk_i),
                .wb_rst_i(wb_rst_i),
                .wb_dat_i(wb_dat_i[BITS-1:0]),
                .wb_stb_i(channel_sel),
                .pwm_counter(counter),
                .pwm_channel(pwm)
        );

Here, wb_* are some of the BUS signals (wishbone), pwm_* are used for the bus logic, and channel_sel would be an array of CHANNELS bits, and as per the Verilog syntax, each bits would get dispatched to one instance making it its "enable" signal.

I am much a beginner, yet I did not come across the name of the well-known method for doing this.

Any hint?

More lengthy description of the problem: https://www.josuah.net/blog/1650637875/
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: Address decoder
« Reply #1 on: April 22, 2022, 05:19:49 pm »
I am much a beginner, yet I did not come across the name of the well-known method for doing this.

It's a selector. (If it was a Selecter, it would be a ska band.)

The idea is that you decode the address, gate it with a write enable, and if the address matches while write enable is asserted, you assert your enable strobe.

So for each "thing" you want to control, you have a bit of logic with an address comparator and the write enable gate.

I'm not sure why this is complicated?
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2806
  • Country: nz
Re: Address decoder
« Reply #2 on: April 22, 2022, 08:52:24 pm »
With this sort of decoding it can sometimes pay to be mindful of the underlying FPGA architecture. If you are on a "LUT6" architecture, it is most efficient to decode 6 bits at a time, as decoding more will require the use of additional lookup tables and or logic elements, and possibly slow the design.

So when I make register banks for a peripheral I tend to give them 16 addresses, even if they only need a handful. That way the decoding of "write enable" for an individual register will be the the lowest 4 address bits, the "enable signal" and the "write enable" for the peripheral.

It's not a hard or fast rule, but it does help me make sure that I'm not using excessive resources in the decoding that could be used elsewhere, or slowing things down.

It also is one less somewhat arbitrary design decision to make... how much register address space should a peripheral have? 16 addresses (unless it needs more).

 It is somewhat pointless have less, as it will not save logic resources, nor will it be any faster.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline josuahTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: fr
    • josuah.net
Re: Address decoder
« Reply #3 on: April 23, 2022, 01:12:06 am »
Much grateful of that precious feedback.

(listenning at "On My Radio by Selecter" as I read through the answers)

Quote
It's a selector.

What a searchable name we got there! Search Engine time!

Quote
You have a bit of logic with an address comparator and the write enable gate.
I'm not sure why this is complicated?

Not sure it is coplicated.  I identified a thing, and liked to put a name on it.

The rest is choosing the appropriate HDL syntax and coming-up with a nice gateware. Talking of which...

Quote
If you are on a "LUT6" architecture,

That introduces me to FPGA Architecture! I had no idea that there was some kind of "ARMv6" vs "ARMv7" vs "AVR" vs RISC-V (woops! not much open-FPGA architecture yet...) for FPGA.

Quote
So when I make register banks for a peripheral I tend to give them 16 addresses, even if they only need a handful. That way the decoding of "write enable" for an individual register will be the the lowest 4 address bits, the "enable signal" and the "write enable" for the peripheral.

I could have spent a stupid amount of time on simply choosing these numbers, and changing them over and over.
Yes, that will help me too.

I will update this thread when I get some result...
 

Online Someone

  • Super Contributor
  • ***
  • Posts: 4684
  • Country: au
    • send complaints here
Re: Address decoder
« Reply #4 on: April 23, 2022, 01:40:48 am »
        wb_pwm_channel #(
                .BITS(BITS)
        ) channel[CHANNELS-1:0] (
                .wb_clk_i(wb_clk_i),
                .wb_rst_i(wb_rst_i),
                .wb_dat_i(wb_dat_i[BITS-1:0]),
                .wb_stb_i(channel_sel),
                .pwm_counter(counter),
                .pwm_channel(pwm)
        );

Here, wb_* are some of the BUS signals (wishbone), pwm_* are used for the bus logic, and channel_sel would be an array of CHANNELS bits, and as per the Verilog syntax, each bits would get dispatched to one instance making it its "enable" signal.

I am much a beginner, yet I did not come across the name of the well-known method for doing this.
Its high level code (HDL), there is not only one way to do it. Everything is specific in the context and rarely will people agree on what is the best way to do it.

Personally, I wouldn't break apart the decoding and the instantiations unless they were non-uniform addresses (even then I'd probably keep them together)

genvar j;
generate
for (j=0; j<8; j=j+1)
  begin
  wb_pwm_channel #(
    .BITS(BITS)
    ) channel (
    .wb_clk_i(wb_clk_i),
    .wb_rst_i(wb_rst_i),
    .wb_dat_i(wb_dat_i[BITS-1:0]),
    .wb_stb_i(wb_stb_i && (wb_addr_i[3:0] == j)),
    .pwm_counter(counter[j]),
    .pwm_channel(pwm[j])
    );
  end
endgenerate
 

Offline josuahTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: fr
    • josuah.net
Re: Address decoder
« Reply #5 on: April 23, 2022, 12:37:03 pm »
It looks like Verilog (and most likely many other HDLs too) is having sort of a decoder operator: bitshifts.

It converts 0b0011 into 0b1000, so with some of bit twiddling:

Code: [Select]
        wb_pwm_channel #(
                .BITS(BITS)
        ) channel[CHANNELS-1:0] (
                .wb_clk_i(wb_clk_i),
                .wb_rst_i(wb_rst_i),
                .wb_stb_i({ {CHANNELS-1{1'b0}}, wb_stb_i } << wb_adr_i),
                .wb_dat_i(wb_dat_i[BITS-1:0]),
                .pwm_counter(counter),
                .pwm_channel(pwm)
        );

There is padding here to make sure wb_stb_i gets a CHANNELS-long input (dispatched over the CHANNELS modules): { {CHANNELS-1{1'b0}}, wb_stb_i }. SystemVerilog (CHANNELS-1)'(wb_stb_i) static cast (is that the name?) syntax would have made this more readable.

That is shorter, but not more readable, and much less obvious at first glance, than using a generate block.

I learned quite a few things, thank you all three.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf