`default_nettype none // Technically the tool could do something much smarter than having a bunch of // macros everywhere, but this is the easiest way I know to make it clear what // is happening. // "packed" structs are effectively a single bit-vector that has syntactic sugar // to access specific parts. SystemVerilog struct layout is amusingly the // complete opposite of C struct layout `define InnerStruct_t_data [32:1] `define InnerStruct_t_valid [0:0] `define MODE_T\ parameter MODE_A = 32'b0;\ parameter MODE_B = 32'b1 // Nested structs are a bit trickier to resolve `define OuterStruct_t_inner [64:32] `define OuterStruct_t_mode [31:0] module Example( input wire clock, clear, output reg success ); `MODE_T; // Verilog must unfuse these declarations since *_in is a reg and *_out is a wire reg [31:0] data_in; wire [31:0] data_out; reg valid_in; wire valid_out; reg [31:0] mode_in; wire [31:0] mode_out; wire [64:0] object; // Sadly Verilog doesn't support built-in functions like $bits or $clog2 // (these are the only functions that I've used in my core and would expect // to synthesize. Luckily the implementation is easy-ish) always @(posedge clock) begin if(clear) begin data_in <= 32'h0; valid_in <= 1'b0; mode_in <= MODE_A; end else if(mode_in == MODE_A) begin valid_in <= 1'b1; mode_in <= MODE_B; data_in <= data_in + 32'd65; // Magically computed by looking at the type object end else begin mode_in <= MODE_A; data_in <= data_in + 32'h1; valid_in <= 1'b1; end end StructCompose compose( .data(data_in), .valid(valid_in), .mode(mode_in), .object(object) ); StructDecompose decompose( .data(data_out), .valid(valid_out), .mode(mode_out), .object(object) ); always @* begin success = 1'b0; if(data_in == data_out) if(valid_in == valid_out) if(mode_in == mode_out) success = 1'b1; end endmodule module StructCompose( input wire [31:0] data, input wire valid, input wire [31:0] mode, output reg [64:0] object ); // Technically the tool could inline all of this, but it's easier to // understand if the structs are built separately. reg [32:0] __inner; always @* begin __inner `InnerStruct_t_data = data; __inner `InnerStruct_t_valid = valid; object `OuterStruct_t_mode = mode; object `OuterStruct_t_inner = __inner; end endmodule module StructDecompose( input wire [64:0] object, output reg [31:0] data, output reg valid, output reg [31:0] mode ); // Technically the tool could inline the bit selection directly reg [32:0] __inner; always @* begin __inner = object `OuterStruct_t_inner; data = __inner `InnerStruct_t_data; valid = __inner `InnerStruct_t_valid; mode = object `OuterStruct_t_mode; end endmodule