Last active
December 4, 2022 21:21
-
-
Save kpmcc/c1c5c055829edd9c4165202ec8dbd918 to your computer and use it in GitHub Desktop.
Advent of Code 2022 - Day 04 - SystemVerilog + Python + Cocotb
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
module ascii_integer_decode | |
( | |
input logic clk, | |
input logic rst, | |
input logic vld, | |
input logic [7:0] ascii_byte, | |
input logic terminate, | |
output logic eg_vld, | |
output logic [7:0] eg_int | |
); | |
initial begin | |
eg_vld = 0; | |
eg_int = 0; | |
end | |
logic[7:0] int_from_ascii = 0; | |
always_ff @ (posedge clk) begin | |
if (rst) begin | |
int_from_ascii <= 0; | |
end else begin | |
case ({terminate, vld}) | |
0: int_from_ascii <= int_from_ascii; | |
1: int_from_ascii <= (int_from_ascii * 10) + (ascii_byte - 48); | |
2: int_from_ascii <= 0; | |
3: int_from_ascii <= 0; | |
endcase | |
end | |
end | |
always_ff @ (posedge clk) begin | |
if (rst) begin | |
eg_int <= 0; | |
eg_vld <= 0; | |
end else begin | |
case ({terminate, vld}) | |
0: begin | |
eg_int <= eg_int; | |
eg_vld <= eg_vld; | |
end | |
1: begin | |
eg_int <= eg_int; | |
eg_vld <= 0; | |
end | |
2: begin | |
eg_int <= int_from_ascii; | |
eg_vld <= 1; | |
end | |
3: begin | |
eg_vld <= 0; | |
eg_int <= 0; | |
end | |
endcase | |
end | |
end | |
endmodule |
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
module constant_match # | |
( | |
parameter CONSTANT [7:0] = 0 | |
) | |
( | |
input logic[7:0] data, | |
output logic match | |
); | |
always_comb begin | |
match <= data == CONSTANT; | |
end | |
endmodule |
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
module day_04 | |
( | |
input logic clk, | |
input logic rst, | |
input logic vld, | |
input logic [7:0] data, | |
input logic eof, | |
output logic counts_vld, | |
output logic [15:0] entirely_contained_count, | |
output logic [15:0] partially_contained_count | |
); | |
initial begin | |
counts_vld = 0; | |
partially_contained_count = 0; | |
entirely_contained_count = 0; | |
end | |
logic newline; | |
logic comma; | |
logic dash; | |
symbol_scanner | |
symbol_scanner | |
( | |
.vld(vld), | |
.text_byte(data), | |
.newline(newline), | |
.comma(comma), | |
.dash(dash) | |
); | |
logic terminate_integer_decode; | |
logic ascii_integer_decode_vld; | |
always_comb begin | |
terminate_integer_decode = comma | dash | newline; | |
ascii_integer_decode_vld = vld & !(terminate_integer_decode); | |
end | |
logic integer_from_ascii_vld; | |
logic[7:0] integer_from_ascii; | |
ascii_integer_decode | |
ascii_integer_decode | |
( | |
.clk(clk), | |
.rst(rst), | |
.vld(ascii_integer_decode_vld), | |
.ascii_byte(data), | |
.terminate(terminate_integer_decode), | |
.eg_vld(integer_from_ascii_vld), | |
.eg_int(integer_from_ascii) | |
); | |
logic [1:0] demux_select = 0; | |
logic parse_error = 0; | |
always_ff @ (posedge clk) begin | |
if (rst) begin | |
demux_select <= 0; | |
end else if (vld) begin | |
case (demux_select) | |
0: demux_select <= dash ? 1 : 0; | |
1: demux_select <= comma ? 2 : 1; | |
2: demux_select <= dash ? 3 : 2; | |
3: demux_select <= newline ? 0: 3; | |
endcase | |
end | |
end | |
logic [1:0] demux_select_delayed; | |
always_ff @ (posedge clk) begin | |
demux_select_delayed <= demux_select; | |
end | |
always_ff @ (posedge clk) begin | |
if (rst) begin | |
parse_error <= 0; | |
end else begin | |
if (vld) begin | |
case (demux_select) | |
0: parse_error <= comma | newline; | |
1: parse_error <= dash | newline; | |
2: parse_error <= comma | newline; | |
3: parse_error <= dash | comma; | |
endcase | |
end | |
end | |
end | |
// numbers for the elf work ranges | |
logic [3:0] value_updated; | |
logic [7:0] a_left; | |
logic [7:0] a_right; | |
logic [7:0] b_left; | |
logic [7:0] b_right; | |
demux_4 # | |
(.WIDTH(8)) | |
demux_4 | |
( | |
.clk(clk), | |
.vld(integer_from_ascii_vld), | |
.data_in(integer_from_ascii), | |
.sel(demux_select_delayed), | |
.data_updated(value_updated), | |
.data_out({b_right, b_left, a_right, a_left}) | |
); | |
logic range_intersection_vld; | |
logic partial_intersect; | |
logic complete_intersect; | |
range_intersection | |
range_intersection | |
( | |
.clk(clk), | |
.vld (value_updated[3]), | |
.a_lo (a_left), | |
.a_hi (a_right), | |
.b_lo (b_left), | |
.b_hi (b_right), | |
.intersect_vld (range_intersection_vld), | |
.partial_intersect (partial_intersect), | |
.complete_intersect (complete_intersect) | |
); | |
always_ff @ (posedge clk) begin | |
if (rst) begin | |
entirely_contained_count <= 0; | |
partially_contained_count <= 0; | |
end else if (range_intersection_vld) begin | |
entirely_contained_count <= entirely_contained_count + complete_intersect; | |
partially_contained_count <= partially_contained_count + partial_intersect; | |
end | |
end | |
always_ff @ (posedge clk) begin | |
counts_vld <= eof; | |
end | |
initial begin | |
$dumpfile("dump.vcd"); | |
$dumpvars(1, day_04); | |
end | |
endmodule |
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
module demux_4 # | |
( | |
parameter WIDTH = 8, | |
) | |
( | |
input logic clk, | |
input logic vld, | |
input logic [WIDTH-1:0] data_in, | |
input logic [1:0] sel, | |
output logic [3:0] data_updated, | |
output logic [WIDTH*4-1:0] data_out | |
); | |
initial begin | |
data_out = 0; | |
data_updated = 0; | |
end | |
always_ff @ (posedge clk) begin | |
if (vld) begin | |
case (sel) | |
0: data_out <= {data_out[WIDTH*4-1 -: WIDTH*3], data_in}; | |
1: data_out <= {data_out[WIDTH*4-1 -: WIDTH*2], data_in, data_out[WIDTH-1:0]}; | |
2: data_out <= {data_out[WIDTH*4-1 -: WIDTH], data_in, data_out[WIDTH*2-1:0]}; | |
3: data_out <= {data_in, data_out[WIDTH*3-1:0]}; | |
endcase | |
end | |
end | |
always_ff @ (posedge clk) begin | |
case (sel) | |
0: data_updated <= {3'b000, vld}; | |
1: data_updated <= {2'b00, vld, 1'b0}; | |
2: data_updated <= {1'b0, vld, 2'b00}; | |
3: data_updated <= {vld, 3'b000}; | |
endcase | |
end | |
endmodule |
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
2-4,6-8 | |
2-3,4-5 | |
5-7,7-9 | |
2-8,3-7 | |
6-6,4-6 | |
2-6,4-8 |
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
#!/usr/bin/env python3 | |
import cocotb | |
from cocotb.clock import Clock | |
from cocotb.triggers import Timer, RisingEdge | |
from cocotb.result import TestFailure, TestSuccess | |
@cocotb.test() | |
async def part_one(dut): | |
dut.clk.value = 0 | |
dut.rst.value = 0 | |
dut.vld.value = 0 | |
dut.data.value = 0 | |
dut.eof.value = 0 | |
cocotb.start_soon(Clock(dut.clk, 4, units="ns").start()) | |
for i in range(5): | |
await RisingEdge(dut.clk) | |
test_file = "actual.txt" | |
with open(test_file, "r") as f: | |
t = f.read() | |
for c in t: | |
await RisingEdge(dut.clk) | |
dut.vld.value = 1 | |
dut.data.value = ord(c) | |
await RisingEdge(dut.clk) | |
dut.vld.value = 0 | |
dut.data.value = 0 | |
dut.eof.value = 1 | |
await RisingEdge(dut.clk) | |
dut.vld.value = 0 | |
dut.eof.value = 0 | |
for i in range(5): | |
await RisingEdge(dut.clk) | |
partial_intersect_count = int(dut.partially_contained_count.value) | |
complete_intersect_count = int(dut.entirely_contained_count.value) | |
print("partial: ", partial_intersect_count) | |
print("complete: ", complete_intersect_count) | |
raise TestSuccess() |
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
# Makefile | |
# defaults | |
SIM ?= icarus | |
TOPLEVEL_LANG ?= verilog | |
VERILOG_SOURCES += $(PWD)/../rtl/complete_day_04.v | |
# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL files | |
TOPLEVEL = day_04 | |
# Module is the basename of the Python test file | |
MODULE = main | |
# include cocotb's make rules to take care of the simulator setup | |
include $(shell cocotb-config --makefiles)/Makefile.sim |
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
module range_intersection | |
( | |
input logic clk, | |
input logic vld, | |
input logic [7:0] a_lo, | |
input logic [7:0] a_hi, | |
input logic [7:0] b_lo, | |
input logic [7:0] b_hi, | |
output logic intersect_vld, | |
output logic partial_intersect, | |
output logic complete_intersect | |
); | |
initial begin | |
intersect_vld = 0; | |
end | |
// partially contains | |
logic a_within_b = 0; | |
logic b_within_a = 0; | |
// fully contains | |
logic a_contains_b = 0; | |
logic b_contains_a = 0; | |
always_ff @ (posedge clk) begin | |
a_within_b <= ((a_lo <= b_lo) && (a_hi >= b_lo)) || | |
((a_lo <= b_hi) && (a_hi >= b_hi)); | |
b_within_a <= ((b_lo <= a_lo) && (b_hi >= a_lo)) || | |
((b_lo <= a_hi) && (b_hi >= a_hi)); | |
end | |
always_ff @ (posedge clk) begin | |
a_contains_b <= (b_lo >= a_lo) & (a_hi >= b_hi); | |
b_contains_a <= (a_lo >= b_lo) & (b_hi >= a_hi); | |
end | |
always_ff @ (posedge clk) begin | |
intersect_vld <= vld; | |
end | |
always_comb begin | |
partial_intersect = a_within_b || b_within_a; | |
complete_intersect = a_contains_b || b_contains_a; | |
end | |
endmodule |
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
module symbol_scanner | |
( | |
input logic vld, | |
input logic [7:0] text_byte, | |
output logic newline, | |
output logic comma, | |
output logic dash | |
); | |
logic comma_match; | |
logic newline_match; | |
logic dash_match; | |
constant_match # (.CONSTANT(44)) | |
match_comma( | |
.data(text_byte), | |
.match(comma_match) | |
); | |
constant_match # (.CONSTANT(10)) | |
match_newline ( | |
.data(text_byte), | |
.match(newline_match) | |
); | |
constant_match # (.CONSTANT(45)) | |
match_dash ( | |
.data(text_byte), | |
.match(dash_match) | |
); | |
always_comb begin | |
newline = vld & newline_match; | |
comma = vld & comma_match; | |
dash = vld & dash_match; | |
end | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment