Search code examples
loopscaseveriloghdl

Replacing case statement in Verilog


I have a set of multiple registers with addresses ranging from 0x20 to 0x60. if processor wants to reads any of these registers at any point of time, i had to send the corresponding register data.Right now i am using case statement by specifying all the registers addresses and assigning the register data to data bus.

can we do any simplification in terms of lines of code.

for e.g.

always @(posedge clk) begin
    if (!fpga_rst)   begin 
      dataout <=  16'd0;
    end
    else  if (!rd_en) begin
      case (reg_addr)

    0x0012: dataout <= fpga_ver_reg;  
    0x0014                : dataout <= act0_reg;
    0x0016                : dataout <= act1_reg;
    0x0018                : dataout <= list0_reg;      
    0x001A                : dataout <=list1_reg;      
    0x001C                : dataout <= dr_reg;
    0x001D                : dataout <= dr0_reg; 
    0x001F                : dataout <= dr1_reg; 
    0x0020                : dataout <= dr2_reg;
    e.t.c

    0x0040                       : dataout <= cr2_reg;

    end case

Solution

  • As written, I don't think so. Since each register has a different name, you can't combine them into a loop.

    If your registers were part of an array and all had the same name, you could do something like the following:

    integer i;
    parameter BASEADDR=0x20;
    reg [15:0] myregs [31:0];
    
    always@(posedge clk) begin
        ... // some reset
        for (i=0; i<32; i=i+1) begin
            if (reg_addr == BASEADDR + i*2)
                dataout <= myregs[i];
        end
    end
    

    This might be shorter in terms of lines of code, but you'll lose the advantage of giving each register it's own name, which might improve readability or the understanding of your circuit.

    Alternatively, you could do this, and then assign each of myregs to a 'named' reg (like dr2_reg), but that won't actually make your code shorter, only move the length to another spot.

    You might also be able to split the difference, by doing something like this:

    integer i;
    parameter DREGBASEADDR=0x1C;
    parameter CREGBASEADDR=0x36;
    ...
    reg [15:0] dregs [2:0];
    reg [15:0] cregs [2:0];
    ...
    
    always@(posedge clk) begin
        ... // some reset
        for (i=0; i<3; i=i+1) begin
            if (reg_addr == CREGBASEADDR + i*2)
                dataout <= cregs[i];
            else if (reg_addr == DBASEREGADDR + i*2)
                dataout <= dregs[i];
            ...
        end
    end
    

    If you can group some of the names together into arrays, it might be shorter, depending on how big the groups are.