Skip to content

TheDeepestSpace/aoc-2025

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CI

Advent of Code 2025 -- Day 10 solution

This repo contains SystemVerilog implementation for Day 10 of Advent of Code 2025. It is implemented as an accelerator, with structured input fed from a controller. High-level architecture is as follows:

flowchart TB
  subgraph Day 10
    subgraph Controller
      python-script[Python script 🐍]
    end
    subgraph accelerator[Accelerator 🏎️]
      subgraph top-level[Top level]
        input-reader[Input reader 👓]
        subgraph configure-machine[Configure machine]
          compute-rref[Compute RREF 🔢]
          enumerate-solutions[Enumerate solutions 📋]

          compute-rref -- RREF data --> enumerate-solutions
        end
        output-writer[Output writer ✍️]

        input-reader -- structured input --> configure-machine
        configure-machine -- structured output --> output-writer
      end
    end

    python-script -- AXI stream --> top-level
    top-level -- AXI stream --> python-script
  end
Loading

The crux of the problem is representing the input buttons as an augmented matrix of binary elements with columns being "buttons" (or, rather, their effect on the lights of the machine), RHS being the target arrangement of the lights. The augmented matrix is a GF(2) matrix, i.e. the elements are either zeros or ones and the add operation is represented by XOR. The augmented matrix is converted to its RREF representation in gf2_rref module, then enumerate_solutions takes over to build up the null bases over free variables and iterates over the possible solutions. configure_machine module orchestrates these two modules and tracks the solution involving minimum number of button presses.

On the top level, day10 module deals with parsing the AXI input from the controller into structured data via day10_input_reader, which is then passed to configure_machine, and then structured output data is converted into output AXI stream in day10_output_writer to be sent back to the controller.

Optimization

The accelerator design pipelines input capture, RREF process, solution enumeration, and writeout as highlighted with respect to the main FSM waveforms below:

pipelining as seen on waveforms

Testing

Major modules gf2_rref, enumerate_solutions and configure_machine have a couple of reality-check tests in their corresponding folder in tests/. There is also a single integration test that hooks up the controller to the accelerator via Cocotb's AXI extension to confirm the overall operation of the system.

Running the tests:

$ make test # for unit tests
$ make test_integration

Example output from the integration test1:

[machine 1] expected:
[machine 1] [.##.]
[machine 1] configuring: (in 2 button presses)
[machine 1] [....]
[machine 1] [.#.#]
[machine 1] [.##.]
[machine 1] done configuring
[machine 1] lights match target arrangement: True
[machine 2] expected:
[machine 2] [...#.]
[machine 2] configuring: (in 3 button presses)
[machine 2] [.....]
[machine 2] [#...#]
...

Scaling

The design's scale is configurable via MAX_NUM_LIGHTS and MAX_NUM_BUTTONS at instantiation of the top level module day10. This allows to configure the design for various input data sizes. Current limits are upper bound of an 8-bit number, since this is max that current I/O setup can handle, but can be extended to support larger numbers.

I/O

To avoid ASCII-level parsing on the RTL front, a basic binary protocol was designed to send the parsed data to the accelerator. For each input controller sends:

  • 8-bit unsigned number of lights for a given machine
  • N bits corresponding to the target lights arrangement for the machine, where N corresponds to the number of lights; ceild to next 8-bit boundary
  • 8-bit unsigned number for buttons for a given machine
  • M*N bits corresponding to a list of button's affects on the machine's lights, where M corresponds to the number of buttons; each button's data is ceild to next 8-bit boundary

On the receiving side, the controller receives:

  • 8-bit unsigned number representing minimum number of buttons to press for a given machine
  • M bit corresponding to the mask of buttons that need to be pressed in order to achieve the target arrangement, where M corresponds to the number of buttons for that machine (since processing is currently sequential, the controller knows that the machine it last sent the data of is the one its reading the data for); this data is used to display an ASCII representation of the configuration process for each machine

RTL extracts structued day10_input_ifs form the corresponding fields rather than interpreting textual syntax.

Hardening

To confirm that the design is synthesizable, it has been hardened for ASIC tape-out via Tiny Tapeout's template repository and is available in this downstream repo: https://github.com/TheDeepestSpace/aoc-2025-ttsky.

Methodology

For this project I decided to try following SVLint's approach to writing SystemVerilog, which entails a lot restrictions when using combinational and sequential logic. For instance, avoiding begin and end keywords within always_comb blocks to limit potential for inferred latches, and being more explicit with if statements. Generally I feel like it made me pay more attention to the design process as well as how my code is interpreted by both other people and machines.

Development

This repository contains a devcontainer setup that includes all the necessary tools needed for development and testing, with specific setup for VScode.

Debugging profiles for VaporView has also been checked into version control.

Future improvements

The current design prioritizes architectural clarity over aggressive optimization. Future work could explore:

  • more aggressive pipelining for higher throughput
  • parallelizing processing to provide another dimension for scaling
  • adding SystemVerilog assertions to enforce internal invariants and external protocol compliance
  • expansion of test coverage to include additional edge cases (e.g. no-solution, maximum-dimensions inputs)
  • implementation of error handling on the accelerator side to detect and handle incorrectly structured inputs

Related work

Checkout my solution for Day 1 written in Hardcaml: https://github.com/TheDeepestSpace/aoc-2025-hardcaml

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors