Single Input to Array of Custom Modules in Verilog

812 views Asked by At

So I have an array of 4 RAM modules that I want to be able to read/write to based on two different selector signals. Right now I'm instantiating the RAM using intermediary signals:

    genvar i;
    generate
    for (i = 0; i < regnum; i=i+1) begin: regs    
         rfram_generic rf (clk,rst,ce_a_int[i],addr_a_int[i],do_a_int[i],
                               ce_b_int[i],addr_b_int[i],do_b_int[i],
                               ce_w_int[i],we_w_int[i],addr_w_int[i],
                               di_w_int[i]);
    end
    endgenerate

And I want to select the RAM to use using either head or tail signals (2-bit vectors). Any ideas how to do this?

3

There are 3 answers

0
mrkj On BEST ANSWER

I'm new here and can't comment on questions yet, but in response to Marty: most FPGA synthesis tools will translate internal multisource signals with tristate values into MUX-like logic, where possible. See, for instance: a description of old tristate-to-logic behaviour that sounds accurate to me.

As a recommendation to Adam, you're probably better off making this explicit in your code by performing the masking yourself rather than using the tristates. This will improve portability, give you more predictable results, and serve as self-documentation if anybody ever has to revisit your code.

However, making some guesses based on your solution, it would probably make sense to simply mask off the clock enable on the write port and mux the output of the read port. For instance:

reg [WIDTH-1:0] do_a,do_b;
always @(*) do_a = do_a_int[head];
always @(*) do_b = do_b_int[tail];
generate
   genvar i;
   for (i = 0; i < regnum; i=i+1) begin: regs    
      rfram_generic rf (clk,rst,
                        ce_a,addr_a,do_a_int[i],
                        ce_b,addr_b,do_b_int[i],
                        ce_w,head==i?we_w:1'b0,addr_w,di_w);
   end
endgenerate

This will probably result in less complex logic (i.e., better area and delay) than your solution.

0
danielpoe On

glad to hear you found a solution for your problem. I must admit I didn't fully understand what you were up to, but one comment, you can also use if inside generate statements and thus instantiate different modules or use different signals dependent on the genvar, e.g.:

generate
    genvar i;
    for (i = 0; i < regnum; i=i+1) begin: regs
        if (i == head) begin
            rfram_generic_a rf(...);
        end else if (i == tail) begin
            rfram_generic_b rf(...);
        end else begin
            rfram_generic_c rf(...);
        end
    end
endgenerate
1
Adam On

I think I figured it out, gotta use a generate statement:

genvar i;
generate 
    for (i = 0; i < regnum; i=i+1) begin: sigassign
        //read from the checkpoint in progress
        assign ce_a_int[i] = (head == i) ? ce_a : 'bz;
        assign addr_a_int[i] = (head == i) ? addr_a : 'bz;
        assign do_a = (head == i) ? do_a_int[i] : 'bz;
        //write to the checkpoint in progress
        assign ce_w_int[i] = (head == i) ? ce_w : 'bz;
        assign we_w_int[i] = (head == i) ? we_w : 'bz;
        assign addr_w_int[i] = (head == i) ? addr_w : 'bz;
        assign di_w_int[i] = (head == i) ? di_w : 'bz;
        //read from the last stable checkpoint
        assign ce_b_int[i] = (tail == i) ? ce_b : 'bz;
        assign addr_b_int[i] = (tail == i) ? addr_b : 'bz;
        assign do_b = (tail == i) ? do_b_int[i] : 'bz;
    end
endgenerate