Skip to content

Instantly share code, notes, and snippets.

@sergev
Created January 13, 2022 01:40
Show Gist options
  • Save sergev/7bd35daf1318fd4bc2085ac54478b199 to your computer and use it in GitHub Desktop.
Save sergev/7bd35daf1318fd4bc2085ac54478b199 to your computer and use it in GitHub Desktop.
Calyx example: result of compiling language-tutorial-compute.futil into Verilog
/**
* Core primitives for Calyx.
* Implements core primitives used by the compiler.
*
* Conventions:
* - All parameter names must be SNAKE_CASE and all caps.
* - Port names must be snake_case, no caps.
*/
`default_nettype none
module std_const #(
parameter WIDTH = 32,
parameter VALUE = 0
) (
output logic [WIDTH - 1:0] out
);
assign out = VALUE;
endmodule
module std_wire #(
parameter WIDTH = 32
) (
input logic [WIDTH - 1:0] in,
output logic [WIDTH - 1:0] out
);
assign out = in;
endmodule
module std_slice #(
parameter IN_WIDTH = 32,
parameter OUT_WIDTH = 32
) (
input wire logic [ IN_WIDTH-1:0] in,
output logic [OUT_WIDTH-1:0] out
);
assign out = in[OUT_WIDTH-1:0];
`ifdef VERILATOR
always_comb begin
if (IN_WIDTH < OUT_WIDTH)
$error(
"std_slice: Input width less than output width\n",
"IN_WIDTH: %0d", IN_WIDTH,
"OUT_WIDTH: %0d", OUT_WIDTH
);
end
`endif
endmodule
module std_pad #(
parameter IN_WIDTH = 32,
parameter OUT_WIDTH = 32
) (
input wire logic [IN_WIDTH-1:0] in,
output logic [OUT_WIDTH-1:0] out
);
localparam EXTEND = OUT_WIDTH - IN_WIDTH;
assign out = { {EXTEND {1'b0}}, in};
`ifdef VERILATOR
always_comb begin
if (IN_WIDTH > OUT_WIDTH)
$error(
"std_pad: Output width less than input width\n",
"IN_WIDTH: %0d", IN_WIDTH,
"OUT_WIDTH: %0d", OUT_WIDTH
);
end
`endif
endmodule
module std_not #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] in,
output logic [WIDTH-1:0] out
);
assign out = ~in;
endmodule
module std_and #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left & right;
endmodule
module std_or #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left | right;
endmodule
module std_xor #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left ^ right;
endmodule
module std_add #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left + right;
endmodule
module std_sub #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left - right;
endmodule
module std_gt #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic out
);
assign out = left > right;
endmodule
module std_lt #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic out
);
assign out = left < right;
endmodule
module std_eq #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic out
);
assign out = left == right;
endmodule
module std_neq #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic out
);
assign out = left != right;
endmodule
module std_ge #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic out
);
assign out = left >= right;
endmodule
module std_le #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic out
);
assign out = left <= right;
endmodule
module std_lsh #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left << right;
endmodule
module std_rsh #(
parameter WIDTH = 32
) (
input wire logic [WIDTH-1:0] left,
input wire logic [WIDTH-1:0] right,
output logic [WIDTH-1:0] out
);
assign out = left >> right;
endmodule
/// this primitive is intended to be used
/// for lowering purposes (not in source programs)
module std_mux #(
parameter WIDTH = 32
) (
input wire logic cond,
input wire logic [WIDTH-1:0] tru,
input wire logic [WIDTH-1:0] fal,
output logic [WIDTH-1:0] out
);
assign out = cond ? tru : fal;
endmodule
/// Memories
module std_reg #(
parameter WIDTH = 32
) (
input wire [ WIDTH-1:0] in,
input wire write_en,
input wire clk,
input wire reset,
// output
output logic [WIDTH - 1:0] out,
output logic done
);
always_ff @(posedge clk) begin
if (reset) begin
out <= 0;
done <= 0;
end else if (write_en) begin
out <= in;
done <= 1'd1;
end else done <= 1'd0;
end
endmodule
module std_mem_d1 #(
parameter WIDTH = 32,
parameter SIZE = 16,
parameter IDX_SIZE = 4
) (
input wire logic [IDX_SIZE-1:0] addr0,
input wire logic [ WIDTH-1:0] write_data,
input wire logic write_en,
input wire logic clk,
output logic [ WIDTH-1:0] read_data,
output logic done
);
logic [WIDTH-1:0] mem[SIZE-1:0];
/* verilator lint_off WIDTH */
assign read_data = mem[addr0];
always_ff @(posedge clk) begin
if (write_en) begin
mem[addr0] <= write_data;
done <= 1'd1;
end else done <= 1'd0;
end
endmodule
module std_mem_d2 #(
parameter WIDTH = 32,
parameter D0_SIZE = 16,
parameter D1_SIZE = 16,
parameter D0_IDX_SIZE = 4,
parameter D1_IDX_SIZE = 4
) (
input wire logic [D0_IDX_SIZE-1:0] addr0,
input wire logic [D1_IDX_SIZE-1:0] addr1,
input wire logic [ WIDTH-1:0] write_data,
input wire logic write_en,
input wire logic clk,
output logic [ WIDTH-1:0] read_data,
output logic done
);
/* verilator lint_off WIDTH */
logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0];
assign read_data = mem[addr0][addr1];
always_ff @(posedge clk) begin
if (write_en) begin
mem[addr0][addr1] <= write_data;
done <= 1'd1;
end else done <= 1'd0;
end
endmodule
module std_mem_d3 #(
parameter WIDTH = 32,
parameter D0_SIZE = 16,
parameter D1_SIZE = 16,
parameter D2_SIZE = 16,
parameter D0_IDX_SIZE = 4,
parameter D1_IDX_SIZE = 4,
parameter D2_IDX_SIZE = 4
) (
input wire logic [D0_IDX_SIZE-1:0] addr0,
input wire logic [D1_IDX_SIZE-1:0] addr1,
input wire logic [D2_IDX_SIZE-1:0] addr2,
input wire logic [ WIDTH-1:0] write_data,
input wire logic write_en,
input wire logic clk,
output logic [ WIDTH-1:0] read_data,
output logic done
);
/* verilator lint_off WIDTH */
logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0][D2_SIZE-1:0];
assign read_data = mem[addr0][addr1][addr2];
always_ff @(posedge clk) begin
if (write_en) begin
mem[addr0][addr1][addr2] <= write_data;
done <= 1'd1;
end else done <= 1'd0;
end
endmodule
module std_mem_d4 #(
parameter WIDTH = 32,
parameter D0_SIZE = 16,
parameter D1_SIZE = 16,
parameter D2_SIZE = 16,
parameter D3_SIZE = 16,
parameter D0_IDX_SIZE = 4,
parameter D1_IDX_SIZE = 4,
parameter D2_IDX_SIZE = 4,
parameter D3_IDX_SIZE = 4
) (
input wire logic [D0_IDX_SIZE-1:0] addr0,
input wire logic [D1_IDX_SIZE-1:0] addr1,
input wire logic [D2_IDX_SIZE-1:0] addr2,
input wire logic [D3_IDX_SIZE-1:0] addr3,
input wire logic [ WIDTH-1:0] write_data,
input wire logic write_en,
input wire logic clk,
output logic [ WIDTH-1:0] read_data,
output logic done
);
/* verilator lint_off WIDTH */
logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0][D2_SIZE-1:0][D3_SIZE-1:0];
assign read_data = mem[addr0][addr1][addr2][addr3];
always_ff @(posedge clk) begin
if (write_en) begin
mem[addr0][addr1][addr2][addr3] <= write_data;
done <= 1'd1;
end else done <= 1'd0;
end
endmodule
`default_nettype wire
module main (
input logic go,
output logic done,
input logic go0,
input logic clk,
input logic reset,
output logic done0
);
string DATA;
int CODE;
initial begin
CODE = $value$plusargs("DATA=%s", DATA);
$display("DATA (path to meminit files): %s", DATA);
$readmemh({DATA, "/mem.dat"}, mem.mem);
end
final begin
$writememh({DATA, "/mem.out"}, mem.mem);
end
logic mem_addr0;
logic [31:0] mem_write_data;
logic mem_write_en;
logic mem_clk;
logic [31:0] mem_read_data;
logic mem_done;
logic [31:0] val_in;
logic val_write_en;
logic val_clk;
logic val_reset;
logic [31:0] val_out;
logic val_done;
logic [31:0] add_left;
logic [31:0] add_right;
logic [31:0] add_out;
logic [1:0] fsm_in;
logic fsm_write_en;
logic fsm_clk;
logic fsm_reset;
logic [1:0] fsm_out;
logic fsm_done;
initial begin
mem_addr0 = 1'd0;
mem_write_data = 32'd0;
mem_write_en = 1'd0;
mem_clk = 1'd0;
val_in = 32'd0;
val_write_en = 1'd0;
val_clk = 1'd0;
val_reset = 1'd0;
add_left = 32'd0;
add_right = 32'd0;
fsm_in = 2'd0;
fsm_write_en = 1'd0;
fsm_clk = 1'd0;
fsm_reset = 1'd0;
end
std_mem_d1 # (
.IDX_SIZE(1),
.SIZE(1),
.WIDTH(32)
) mem (
.addr0(mem_addr0),
.clk(mem_clk),
.done(mem_done),
.read_data(mem_read_data),
.write_data(mem_write_data),
.write_en(mem_write_en)
);
std_reg # (
.WIDTH(32)
) val (
.clk(val_clk),
.done(val_done),
.in(val_in),
.out(val_out),
.reset(val_reset),
.write_en(val_write_en)
);
std_add # (
.WIDTH(32)
) add (
.left(add_left),
.out(add_out),
.right(add_right)
);
std_reg # (
.WIDTH(2)
) fsm (
.clk(fsm_clk),
.done(fsm_done),
.in(fsm_in),
.out(fsm_out),
.reset(fsm_reset),
.write_en(fsm_write_en)
);
assign done =
fsm_out == 2'd3 ? 1'd1 : 1'd0;
assign done0 =
fsm_out == 2'd3 ? 1'd1 : 1'd0;
assign add_left =
~val_done & fsm_out == 2'd1 & (go | go0) ? val_out : 32'd0;
assign add_right =
~val_done & fsm_out == 2'd1 & (go | go0) ? 32'd4 : 32'd0;
assign fsm_clk =
1'b1 ? clk : 1'd0;
assign fsm_in =
fsm_out == 2'd3 ? 2'd0 :
fsm_out == 2'd0 & val_done & (go | go0) ? 2'd1 :
fsm_out == 2'd1 & val_done & (go | go0) ? 2'd2 :
fsm_out == 2'd2 & mem_done & (go | go0) ? 2'd3 : 2'd0;
assign fsm_reset =
1'b1 ? reset : 1'd0;
assign fsm_write_en =
fsm_out == 2'd0 & val_done & (go | go0) | fsm_out == 2'd1 & val_done & (go | go0) | fsm_out == 2'd2 & mem_done & (go | go0) | fsm_out == 2'd3 ? 1'd1 : 1'd0;
assign mem_addr0 =
~mem_done & fsm_out == 2'd2 & (go | go0) | ~val_done & fsm_out == 2'd0 & (go | go0) ? 1'd0 : 1'd0;
assign mem_clk =
1'b1 ? clk : 1'd0;
assign mem_write_data =
~mem_done & fsm_out == 2'd2 & (go | go0) ? val_out : 32'd0;
assign mem_write_en =
~mem_done & fsm_out == 2'd2 & (go | go0) ? 1'd1 : 1'd0;
assign val_clk =
1'b1 ? clk : 1'd0;
assign val_in =
~val_done & fsm_out == 2'd1 & (go | go0) ? add_out :
~val_done & fsm_out == 2'd0 & (go | go0) ? mem_read_data : 32'd0;
assign val_reset =
1'b1 ? reset : 1'd0;
assign val_write_en =
~val_done & fsm_out == 2'd0 & (go | go0) | ~val_done & fsm_out == 2'd1 & (go | go0) ? 1'd1 : 1'd0;
always_comb begin
if(~$onehot0({fsm_out == 2'd2 & mem_done & (go | go0), fsm_out == 2'd1 & val_done & (go | go0), fsm_out == 2'd0 & val_done & (go | go0), fsm_out == 2'd3})) begin
$fatal(2, "Multiple assignment to port `fsm.in'.");
end
if(~$onehot0({~val_done & fsm_out == 2'd0 & (go | go0), ~val_done & fsm_out == 2'd1 & (go | go0)})) begin
$fatal(2, "Multiple assignment to port `val.in'.");
end
end
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment