functions.sv 2.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
`default_nettype none

typedef enum {FOO, BAR} State_t;

typedef struct packed {
    State_t state;
    logic [31:0] data;
} MyStruct_t;

module Example(
    input logic clock, clear,
    input logic [7:0] dataIn,
    output logic check1, check2,
    output logic [63:0] checkData
);

    // The automatic keyword here is super confusing, but generally does what
    // you expect a C function to do. Sadly VTR doesn't support the automatic
    // keyword.
    function automatic State_t swapState(State_t state);
        // The state variable is not shadowing the state variable in the global
        // function since the function is declared above the state variable
        // (Declaring functions at the start of the module before module scope
        // variables is a good practice to avoid accidentally using a module scope
        // in a function)
        unique case(state)
            FOO: return BAR;
            BAR: return FOO;
        endcase
    endfunction : swapState

    State_t state;

    always_ff @(posedge clock)
        if(clear)
            state <= FOO;
        else
            state <= swapState(state);

    logic [15:0] magicToken;
    assign magicToken = 16'habcd;

    function automatic MyStruct_t packStruct(State_t state, logic [7:0] data);
        // Something interesting about system verilog is that all local variable
        // declarations must be first in the function (at least for VCS to
        // compile it)
        logic [31:0] fullData;
        State_t nextState;
        // System Verilog functions can also access "local" variables from the
        // module scope. This means that any variable with the same name in the
        // function as something else defined in the module is shadowing the
        // module variable (e.g. state in this function)
        fullData = {~data, data, magicToken};
        nextState = swapState(state);
        return '{
            state: nextState,
            data: fullData
        };
    endfunction

    MyStruct_t myStruct;
    assign myStruct = packStruct(state, dataIn);

    function automatic logic doCheck(MyStruct_t inputStruct);
        return inputStruct.state == FOO;
    endfunction : doCheck

    assign check1 = doCheck(myStruct);

    MyStruct_t myStruct2;
    always_comb begin
        myStruct2 = packStruct(swapState(state), ~dataIn);
        check2 = doCheck(myStruct2);
    end

    assign checkData = {myStruct.data, myStruct2.data};



endmodule