Skip to content

Instantly share code, notes, and snippets.

@litui
Last active October 6, 2025 03:03
Show Gist options
  • Select an option

  • Save litui/c6b3bc3899a3db83a7bb759bd743d78d to your computer and use it in GitHub Desktop.

Select an option

Save litui/c6b3bc3899a3db83a7bb759bd743d78d to your computer and use it in GitHub Desktop.
Torii-based 7seg example for Tang Primer 25K FPGA board
#!/usr/bin/env python3
# Example from https://github.com/icebreaker-fpga/icebreaker-amaranth-examples/blob/master/icebreaker/7seg_count/7seg_count.py
from torii.hdl import Elaboratable, Module, Signal, Cat
from torii.build import Resource, Subsignal, PinsN, Attrs
from torii_boards.gowin.gw5a import TangPrimer25kDockPlatform
seven_seg_pmod = [
Resource(
"seven_seg",
0,
Subsignal(
"aa", PinsN("1", dir="o", conn=("pmod", 0)), Attrs(IO_TYPE="LVCMOS33")
),
Subsignal(
"ab", PinsN("2", dir="o", conn=("pmod", 0)), Attrs(IO_TYPE="LVCMOS33")
),
Subsignal(
"ac", PinsN("3", dir="o", conn=("pmod", 0)), Attrs(IO_TYPE="LVCMOS33")
),
Subsignal(
"ad",
PinsN("4", dir="o", conn=("pmod", 0)),
Attrs(IO_TYPE="LVCMOS33"),
),
Subsignal(
"ae",
PinsN("7", dir="o", conn=("pmod", 0)),
Attrs(IO_TYPE="LVCMOS33"),
),
Subsignal(
"af",
PinsN("8", dir="o", conn=("pmod", 0)),
Attrs(IO_TYPE="LVCMOS33"),
),
Subsignal(
"ag",
PinsN("9", dir="o", conn=("pmod", 0)),
Attrs(IO_TYPE="LVCMOS33"),
),
Subsignal(
"ca",
PinsN("10", dir="o", conn=("pmod", 0)),
Attrs(IO_TYPE="LVCMOS33"),
),
)
]
class Top(Elaboratable):
def __init__(self):
self.ones_to_segs = DigitToSegments()
self.tens_to_segs = DigitToSegments()
def elaborate(self, platform):
seg_pins = platform.request("seven_seg")
m = Module()
seg_pins_cat = Signal(7)
counter = Signal(30)
ones_counter = Signal(4)
tens_counter = Signal(4)
display_state = Signal(3)
m.submodules.ones_to_segs = self.ones_to_segs
m.submodules.tens_to_segs = self.tens_to_segs
m.d.comb += [
Cat(
[
seg_pins.aa,
seg_pins.ab,
seg_pins.ac,
seg_pins.ad,
seg_pins.ae,
seg_pins.af,
seg_pins.ag,
]
).eq(seg_pins_cat),
ones_counter.eq(counter[21:25]),
tens_counter.eq(counter[25:29]),
display_state.eq(counter[2:5]),
self.ones_to_segs.digit.eq(ones_counter),
self.tens_to_segs.digit.eq(tens_counter),
]
m.d.sync += counter.eq(counter + 1)
with m.Switch(display_state):
with m.Case("00-"):
m.d.sync += seg_pins_cat.eq(self.ones_to_segs.segments)
with m.Case("010"):
m.d.sync += seg_pins_cat.eq(0)
with m.Case("011"):
m.d.sync += seg_pins.ca.eq(1)
with m.Case("10-"):
m.d.sync += seg_pins_cat.eq(self.tens_to_segs.segments)
with m.Case("110"):
m.d.sync += seg_pins_cat.eq(0)
with m.Case("111"):
m.d.sync += seg_pins.ca.eq(0)
return m
class DigitToSegments(Elaboratable):
def __init__(self):
self.digit = Signal(4)
self.segments = Signal(7)
def elaborate(self, _platform):
m = Module()
with m.Switch(self.digit):
for n, seg_val in enumerate(
[
0b0111111,
0b0000110,
0b1011011,
0b1001111,
0b1100110,
0b1101101,
0b1111101,
0b0000111,
0b1111111,
0b1101111,
0b1110111,
0b1111100,
0b0111001,
0b1011110,
0b1111001,
0b1110001,
]
):
with m.Case(n):
m.d.sync += self.segments.eq(seg_val)
return m
if __name__ == "__main__":
# In this example, explicitly show the intermediate classes used to
# execute build() to demonstrate that a user can inspect
# each part of the build process (create files, execute, program,
# and create a zip file if you have a BuildPlan instance).
plat = TangPrimer25kDockPlatform(toolchain="Apicula")
plat.add_resources(seven_seg_pmod)
# BuildPlan if do_build=False
# BuildProducts if do_build=True and do_program=False
# None otherwise.
plan = plat.build(Top(), do_build=False, do_program=False) # BuildPlan
products = plan.execute() # BuildProducts
plat.toolchain_program(products, "top") # Manally run the programmer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment