| `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 |