mirror of https://github.com/zachjs/sv2v.git
117 lines
3.1 KiB
Verilog
117 lines
3.1 KiB
Verilog
`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 |