Search code examples
verilog

Helper function to define string results?


In my Verilog code, I have such statements

$display("    %s r%h, r%h",
         instrH == ALU8_ADD ? "add" :
         instrH == ALU8_ADC ? "adc" :
         instrH == ALU8_SUB ? "sub" :
         instrH == ALU8_SBC ? "sbc" :
         instrH == ALU8_OR  ? "or" :
         instrH == ALU8_AND ? "and" :
         instrH == ALU8_TCM ? "tcm" :
         instrH == ALU8_TM  ? "tm" :
         instrH == ALU8_CP  ? "cp" :
         instrH == ALU8_XOR ? "xor" : "?",
         secondH, secondL);

which are helpful for the test bench debug logging. I want to extract this part

         instrH == ALU8_ADD ? "add" :
         instrH == ALU8_ADC ? "adc" :
         instrH == ALU8_SUB ? "sub" :
         instrH == ALU8_SBC ? "sbc" :
         instrH == ALU8_OR  ? "or" :
         instrH == ALU8_AND ? "and" :
         instrH == ALU8_TCM ? "tcm" :
         instrH == ALU8_TM  ? "tm" :
         instrH == ALU8_CP  ? "cp" :
         instrH == ALU8_XOR ? "xor" : "?",

into some kind of "function", so this is just defined at one location and use it later similar to:

$display("    %s r%h, r%h",
         alu8OpName(instrH),
         secondH, secondL);

How can I define a function returning a string?


Solution

  • There are no string types in Verilog. You can declare a bit vector with multiple of 8-bit bytes to hold the largest possible string literal and return that. Null bytes 8'h00 get printed as spaces.

    function [1:3*8] alu8OpName( //maximum of 3 characters
        input [3:0] instrH);
    begin
        alu8OpName = instrH == ALU8_ADD ? "add" :
                     instrH == ALU8_ADC ? "adc" :
                     instrH == ALU8_SUB ? "sub" :
                     instrH == ALU8_SBC ? "sbc" :
                     instrH == ALU8_OR  ? "or" :
                     instrH == ALU8_AND ? "and" :
                     instrH == ALU8_TCM ? "tcm" :
                     instrH == ALU8_TM  ? "tm" :
                     instrH == ALU8_CP  ? "cp" :
                     instrH == ALU8_XOR ? "xor" : "?";
    end
    endfunction
    

    But this kind of nested conditional operator is better written as a case statement.

    function [1:3*8] alu8OpName( //maximum of 3 characters
        input [3:0] instrH);
    case (instrH)
       ALU8_ADD: alu8OpName = "add";
       ALU8_ADC: alu8OpName = "adc";
       ALU8_SUB: alu8OpName = "sub";
       ...
       default:  alu8OpName = "???";
    endcase
    endfunction
    

    And if you are using SystemVerilog, this would be much easier to write with a string function

    function string alu8OpName(
        input [3:0] instrH);
    case (instrH)
       ALU8_ADD: return "add";
       ALU8_ADC: return "adc";
       ALU8_SUB: return "sub";
       ...
       default:  return "?";
    endcase
    endfunction