Created
January 13, 2022 01:40
-
-
Save sergev/7bd35daf1318fd4bc2085ac54478b199 to your computer and use it in GitHub Desktop.
Calyx example: result of compiling language-tutorial-compute.futil into Verilog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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