Added Debouncer ToggleButton and PulseButton
This commit is contained in:
parent
eea189ae61
commit
ac755932d5
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +1,2 @@
|
|||||||
docs/media/SP1-picture-with-pin-numbers.jpg filter=lfs diff=lfs merge=lfs -text
|
docs/media/SP1-picture-with-pin-numbers.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
docs/media/pinouts.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
195
PulseButton.vcd
Normal file
195
PulseButton.vcd
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
$comment Generated by Amaranth $end
|
||||||
|
$date 2025-09-20 22:27:02.816595 $end
|
||||||
|
$timescale 1 fs $end
|
||||||
|
$scope module bench $end
|
||||||
|
$scope module top $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$var wire 1 # i $end
|
||||||
|
$var wire 1 $ i$3 $end
|
||||||
|
$var wire 14 % counter $end
|
||||||
|
$var wire 1 & o $end
|
||||||
|
$var wire 1 ' o$6 $end
|
||||||
|
$var wire 1 ( last_seen $end
|
||||||
|
$scope module U$0 $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$var wire 1 # i $end
|
||||||
|
$var wire 1 ' o $end
|
||||||
|
$var wire 1 ) prevInValid $end
|
||||||
|
$var wire 14 * count $end
|
||||||
|
$var wire 1 + state $end
|
||||||
|
$var wire 1 , prevIn $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
#0
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
0"
|
||||||
|
0#
|
||||||
|
0$
|
||||||
|
b0 %
|
||||||
|
0&
|
||||||
|
0'
|
||||||
|
0(
|
||||||
|
0)
|
||||||
|
b10011100010000 *
|
||||||
|
0+
|
||||||
|
0,
|
||||||
|
$end
|
||||||
|
#500000000
|
||||||
|
1!
|
||||||
|
1)
|
||||||
|
b0 *
|
||||||
|
#1000000000
|
||||||
|
0!
|
||||||
|
#1500000000
|
||||||
|
1!
|
||||||
|
1$
|
||||||
|
1#
|
||||||
|
#2000000000
|
||||||
|
0!
|
||||||
|
#2500000000
|
||||||
|
1!
|
||||||
|
1+
|
||||||
|
1,
|
||||||
|
b10011100010000 *
|
||||||
|
1'
|
||||||
|
#3000000000
|
||||||
|
0!
|
||||||
|
#3500000000
|
||||||
|
1!
|
||||||
|
1&
|
||||||
|
1(
|
||||||
|
#4000000000
|
||||||
|
0!
|
||||||
|
#4500000000
|
||||||
|
1!
|
||||||
|
0&
|
||||||
|
b10011100010000 %
|
||||||
|
#5000000000
|
||||||
|
0!
|
||||||
|
#5500000000
|
||||||
|
1!
|
||||||
|
b10011100001111 %
|
||||||
|
#6000000000
|
||||||
|
0!
|
||||||
|
#6500000000
|
||||||
|
1!
|
||||||
|
b10011100001110 %
|
||||||
|
0$
|
||||||
|
0#
|
||||||
|
#7000000000
|
||||||
|
0!
|
||||||
|
#7500000000
|
||||||
|
1!
|
||||||
|
0,
|
||||||
|
b10011100001111 *
|
||||||
|
b10011100001101 %
|
||||||
|
#8000000000
|
||||||
|
0!
|
||||||
|
#8500000000
|
||||||
|
1!
|
||||||
|
b10011100001110 *
|
||||||
|
b10011100001100 %
|
||||||
|
#9000000000
|
||||||
|
0!
|
||||||
|
#9500000000
|
||||||
|
1!
|
||||||
|
b10011100001101 *
|
||||||
|
b10011100001011 %
|
||||||
|
#10000000000
|
||||||
|
0!
|
||||||
|
#10500000000
|
||||||
|
1!
|
||||||
|
b10011100001100 *
|
||||||
|
b10011100001010 %
|
||||||
|
#11000000000
|
||||||
|
0!
|
||||||
|
#11500000000
|
||||||
|
1!
|
||||||
|
b10011100001011 *
|
||||||
|
b10011100001001 %
|
||||||
|
1$
|
||||||
|
1#
|
||||||
|
#12000000000
|
||||||
|
0!
|
||||||
|
#12500000000
|
||||||
|
1!
|
||||||
|
1,
|
||||||
|
b10011100010000 *
|
||||||
|
b10011100001000 %
|
||||||
|
#13000000000
|
||||||
|
0!
|
||||||
|
#13500000000
|
||||||
|
1!
|
||||||
|
b10011100000111 %
|
||||||
|
#14000000000
|
||||||
|
0!
|
||||||
|
#14500000000
|
||||||
|
1!
|
||||||
|
b10011100000110 %
|
||||||
|
#15000000000
|
||||||
|
0!
|
||||||
|
#15500000000
|
||||||
|
1!
|
||||||
|
b10011100000101 %
|
||||||
|
#16000000000
|
||||||
|
0!
|
||||||
|
#16500000000
|
||||||
|
1!
|
||||||
|
b10011100000100 %
|
||||||
|
0$
|
||||||
|
0#
|
||||||
|
#17000000000
|
||||||
|
0!
|
||||||
|
#17500000000
|
||||||
|
1!
|
||||||
|
0,
|
||||||
|
b10011100001111 *
|
||||||
|
b10011100000011 %
|
||||||
|
#18000000000
|
||||||
|
0!
|
||||||
|
#18500000000
|
||||||
|
1!
|
||||||
|
b10011100001110 *
|
||||||
|
b10011100000010 %
|
||||||
|
#19000000000
|
||||||
|
0!
|
||||||
|
#19500000000
|
||||||
|
1!
|
||||||
|
b10011100001101 *
|
||||||
|
b10011100000001 %
|
||||||
|
#20000000000
|
||||||
|
0!
|
||||||
|
#20500000000
|
||||||
|
1!
|
||||||
|
b10011100001100 *
|
||||||
|
b10011100000000 %
|
||||||
|
#21000000000
|
||||||
|
0!
|
||||||
|
#21500000000
|
||||||
|
1!
|
||||||
|
b10011100001011 *
|
||||||
|
b10011011111111 %
|
||||||
|
#22000000000
|
||||||
|
0!
|
||||||
|
#22500000000
|
||||||
|
1!
|
||||||
|
b10011100001010 *
|
||||||
|
b10011011111110 %
|
||||||
|
#23000000000
|
||||||
|
0!
|
||||||
|
#23500000000
|
||||||
|
1!
|
||||||
|
b10011100001001 *
|
||||||
|
b10011011111101 %
|
||||||
|
#24000000000
|
||||||
|
0!
|
||||||
|
#24500000000
|
||||||
|
1!
|
||||||
|
b10011100001000 *
|
||||||
|
b10011011111100 %
|
||||||
|
#25000000000
|
171
ToggleButton.vcd
Normal file
171
ToggleButton.vcd
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
$comment Generated by Amaranth $end
|
||||||
|
$date 2025-09-20 22:27:02.809849 $end
|
||||||
|
$timescale 1 fs $end
|
||||||
|
$scope module bench $end
|
||||||
|
$scope module top $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$var wire 1 # i $end
|
||||||
|
$var wire 1 $ i$3 $end
|
||||||
|
$var wire 1 % o $end
|
||||||
|
$var wire 1 & last_seen $end
|
||||||
|
$var wire 1 ' o$6 $end
|
||||||
|
$scope module U$0 $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 1 " rst $end
|
||||||
|
$var wire 1 # i $end
|
||||||
|
$var wire 1 % o $end
|
||||||
|
$var wire 1 ( prevInValid $end
|
||||||
|
$var wire 14 ) count $end
|
||||||
|
$var wire 1 * state $end
|
||||||
|
$var wire 1 + prevIn $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
#0
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
0"
|
||||||
|
0#
|
||||||
|
0$
|
||||||
|
0%
|
||||||
|
0&
|
||||||
|
0'
|
||||||
|
0(
|
||||||
|
b10011100010000 )
|
||||||
|
0*
|
||||||
|
0+
|
||||||
|
$end
|
||||||
|
#500000000
|
||||||
|
1!
|
||||||
|
b0 )
|
||||||
|
1(
|
||||||
|
#1000000000
|
||||||
|
0!
|
||||||
|
#1500000000
|
||||||
|
1!
|
||||||
|
1$
|
||||||
|
1#
|
||||||
|
#2000000000
|
||||||
|
0!
|
||||||
|
#2500000000
|
||||||
|
1!
|
||||||
|
b10011100010000 )
|
||||||
|
1*
|
||||||
|
1+
|
||||||
|
1%
|
||||||
|
#3000000000
|
||||||
|
0!
|
||||||
|
#3500000000
|
||||||
|
1!
|
||||||
|
1&
|
||||||
|
1'
|
||||||
|
#4000000000
|
||||||
|
0!
|
||||||
|
#4500000000
|
||||||
|
1!
|
||||||
|
#5000000000
|
||||||
|
0!
|
||||||
|
#5500000000
|
||||||
|
1!
|
||||||
|
#6000000000
|
||||||
|
0!
|
||||||
|
#6500000000
|
||||||
|
1!
|
||||||
|
0$
|
||||||
|
0#
|
||||||
|
#7000000000
|
||||||
|
0!
|
||||||
|
#7500000000
|
||||||
|
1!
|
||||||
|
b10011100001111 )
|
||||||
|
0+
|
||||||
|
#8000000000
|
||||||
|
0!
|
||||||
|
#8500000000
|
||||||
|
1!
|
||||||
|
b10011100001110 )
|
||||||
|
#9000000000
|
||||||
|
0!
|
||||||
|
#9500000000
|
||||||
|
1!
|
||||||
|
b10011100001101 )
|
||||||
|
#10000000000
|
||||||
|
0!
|
||||||
|
#10500000000
|
||||||
|
1!
|
||||||
|
b10011100001100 )
|
||||||
|
#11000000000
|
||||||
|
0!
|
||||||
|
#11500000000
|
||||||
|
1!
|
||||||
|
b10011100001011 )
|
||||||
|
1$
|
||||||
|
1#
|
||||||
|
#12000000000
|
||||||
|
0!
|
||||||
|
#12500000000
|
||||||
|
1!
|
||||||
|
b10011100010000 )
|
||||||
|
1+
|
||||||
|
#13000000000
|
||||||
|
0!
|
||||||
|
#13500000000
|
||||||
|
1!
|
||||||
|
#14000000000
|
||||||
|
0!
|
||||||
|
#14500000000
|
||||||
|
1!
|
||||||
|
#15000000000
|
||||||
|
0!
|
||||||
|
#15500000000
|
||||||
|
1!
|
||||||
|
#16000000000
|
||||||
|
0!
|
||||||
|
#16500000000
|
||||||
|
1!
|
||||||
|
0$
|
||||||
|
0#
|
||||||
|
#17000000000
|
||||||
|
0!
|
||||||
|
#17500000000
|
||||||
|
1!
|
||||||
|
b10011100001111 )
|
||||||
|
0+
|
||||||
|
#18000000000
|
||||||
|
0!
|
||||||
|
#18500000000
|
||||||
|
1!
|
||||||
|
b10011100001110 )
|
||||||
|
#19000000000
|
||||||
|
0!
|
||||||
|
#19500000000
|
||||||
|
1!
|
||||||
|
b10011100001101 )
|
||||||
|
#20000000000
|
||||||
|
0!
|
||||||
|
#20500000000
|
||||||
|
1!
|
||||||
|
b10011100001100 )
|
||||||
|
#21000000000
|
||||||
|
0!
|
||||||
|
#21500000000
|
||||||
|
1!
|
||||||
|
b10011100001011 )
|
||||||
|
#22000000000
|
||||||
|
0!
|
||||||
|
#22500000000
|
||||||
|
1!
|
||||||
|
b10011100001010 )
|
||||||
|
#23000000000
|
||||||
|
0!
|
||||||
|
#23500000000
|
||||||
|
1!
|
||||||
|
b10011100001001 )
|
||||||
|
#24000000000
|
||||||
|
0!
|
||||||
|
#24500000000
|
||||||
|
1!
|
||||||
|
b10011100001000 )
|
||||||
|
#25000000000
|
21
docs/.obsidian/workspace.json
vendored
21
docs/.obsidian/workspace.json
vendored
@ -11,17 +11,12 @@
|
|||||||
"id": "be20a2e02f2b6437",
|
"id": "be20a2e02f2b6437",
|
||||||
"type": "leaf",
|
"type": "leaf",
|
||||||
"state": {
|
"state": {
|
||||||
"type": "canvas",
|
"type": "image",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "GameCube/Sp1 physical connector.canvas",
|
"file": "media/pinouts.png"
|
||||||
"viewState": {
|
|
||||||
"x": 72,
|
|
||||||
"y": -20,
|
|
||||||
"zoom": 0
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"icon": "lucide-layout-dashboard",
|
"icon": "lucide-image",
|
||||||
"title": "Sp1 physical connector"
|
"title": "pinouts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -174,9 +169,13 @@
|
|||||||
},
|
},
|
||||||
"active": "be20a2e02f2b6437",
|
"active": "be20a2e02f2b6437",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"GameCube/SP1.md",
|
|
||||||
"GameCube/Sp1 physical connector.canvas",
|
|
||||||
"media/SP1-picture-with-pin-numbers.jpg",
|
"media/SP1-picture-with-pin-numbers.jpg",
|
||||||
|
"IceBreaker FPGA/Pinouts for PMODs.md",
|
||||||
|
"media/pinouts.png",
|
||||||
|
"Pasted image 20250920193353.png",
|
||||||
|
"GameCube/Sp1 physical connector.canvas",
|
||||||
|
"IceBreaker FPGA",
|
||||||
|
"GameCube/SP1.md",
|
||||||
"media/Unconfirmed 13874.crdownload",
|
"media/Unconfirmed 13874.crdownload",
|
||||||
"media",
|
"media",
|
||||||
"Environment/Amaranth-Hdl project setup.md",
|
"Environment/Amaranth-Hdl project setup.md",
|
||||||
|
2
docs/IceBreaker FPGA/Pinouts for PMODs.md
Normal file
2
docs/IceBreaker FPGA/Pinouts for PMODs.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
![[pinouts.png]]
|
BIN
docs/media/pinouts.png
Normal file
BIN
docs/media/pinouts.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 MiB |
1
rebbarb/.gitignore
vendored
1
rebbarb/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
build
|
build
|
||||||
|
__pycache__
|
||||||
|
0
rebbarb/__init__.py
Normal file
0
rebbarb/__init__.py
Normal file
38
rebbarb/debouncer.py
Normal file
38
rebbarb/debouncer.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from amaranth.build import Platform
|
||||||
|
from amaranth import *
|
||||||
|
|
||||||
|
class Debouncer(Elaboratable):
|
||||||
|
|
||||||
|
def __init__(self, cycles: int):
|
||||||
|
#signals
|
||||||
|
self.i = Signal()
|
||||||
|
self.o = Signal()
|
||||||
|
|
||||||
|
#state
|
||||||
|
self.count = Signal(range(0, cycles+1), reset=cycles)
|
||||||
|
self.state = Signal()
|
||||||
|
self.prevInValid = Signal()
|
||||||
|
self.prevIn = Signal()
|
||||||
|
|
||||||
|
def elaborate(self, platform: Platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
with m.If(self.prevInValid):
|
||||||
|
with m.If(self.count == 0):
|
||||||
|
with m.If(self.prevIn ^ self.i):
|
||||||
|
m.d.sync += self.count.eq(self.count.reset)
|
||||||
|
m.d.sync += self.state.eq(self.i)
|
||||||
|
with m.Elif(self.i == self.state):
|
||||||
|
m.d.sync += self.count.eq(self.count.reset)
|
||||||
|
m.d.sync += self.state.eq(self.i)
|
||||||
|
with m.Else():
|
||||||
|
m.d.sync += self.count.eq(self.count - 1)
|
||||||
|
with m.Else():
|
||||||
|
m.d.sync += self.count.eq(0)
|
||||||
|
m.d.sync += self.prevInValid.eq(Const(1))
|
||||||
|
m.d.sync += self.state.eq(self.i)
|
||||||
|
|
||||||
|
m.d.sync += self.prevIn.eq(self.i)
|
||||||
|
m.d.comb += self.o.eq(self.state)
|
||||||
|
|
||||||
|
return m
|
59
rebbarb/pulse_button.py
Normal file
59
rebbarb/pulse_button.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from amaranth.build import Platform
|
||||||
|
from amaranth import *
|
||||||
|
|
||||||
|
from debouncer import Debouncer
|
||||||
|
|
||||||
|
class PulseButton(Elaboratable):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#signals
|
||||||
|
self.i = Signal()
|
||||||
|
self.o = Signal()
|
||||||
|
|
||||||
|
#state
|
||||||
|
self.last_seen = Signal()
|
||||||
|
self.counter = Signal(range(10000 + 1))
|
||||||
|
|
||||||
|
def elaborate(self, platform: Platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
debouncer = Debouncer(10000)
|
||||||
|
|
||||||
|
m.submodules += debouncer
|
||||||
|
|
||||||
|
m.d.comb += debouncer.i.eq(self.i)
|
||||||
|
|
||||||
|
with m.If(self.counter != 0):
|
||||||
|
m.d.sync += self.counter.eq(self.counter - 1)
|
||||||
|
with m.Else():
|
||||||
|
with m.If(self.o):
|
||||||
|
m.d.sync += self.o.eq(~self.o)
|
||||||
|
m.d.sync += self.counter.eq(10000)
|
||||||
|
|
||||||
|
with m.If((debouncer.o != self.last_seen) & (debouncer.o == 1)):
|
||||||
|
m.d.sync += self.o.eq(~self.o)
|
||||||
|
|
||||||
|
m.d.sync += self.last_seen.eq(debouncer.o)
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
from amaranth.sim import Simulator, Period
|
||||||
|
|
||||||
|
dut = PulseButton()
|
||||||
|
|
||||||
|
async def testbench(ctx):
|
||||||
|
await ctx.tick().repeat(2)
|
||||||
|
ctx.set(dut.i, True)
|
||||||
|
await ctx.tick().repeat(5)
|
||||||
|
ctx.set(dut.i, False)
|
||||||
|
await ctx.tick().repeat(5)
|
||||||
|
ctx.set(dut.i, True)
|
||||||
|
await ctx.tick().repeat(5)
|
||||||
|
ctx.set(dut.i, False)
|
||||||
|
|
||||||
|
sim = Simulator(dut)
|
||||||
|
sim.add_clock(Period(MHz=1))
|
||||||
|
sim.add_testbench(testbench)
|
||||||
|
with sim.write_vcd("PulseButton.vcd"):
|
||||||
|
sim.run_until(Period(MHz=1) * 25)
|
@ -1,20 +1,21 @@
|
|||||||
from amaranth import *
|
from amaranth import *
|
||||||
|
|
||||||
class LEDBlinker(Elaboratable):
|
from toggle_button import ToggleButton
|
||||||
def elaborate(self, platform):
|
from pulse_button import PulseButton
|
||||||
m = Module()
|
|
||||||
|
|
||||||
|
class ReBbaRb(Elaboratable):
|
||||||
|
def setup_pll(self, module, platform):
|
||||||
cd_sync = ClockDomain("sync")
|
cd_sync = ClockDomain("sync")
|
||||||
m.domains += cd_sync
|
module.domains += cd_sync
|
||||||
platform.lookup(platform.default_clk).attrs['GLOBAL'] = False
|
platform.lookup(platform.default_clk).attrs['GLOBAL'] = False
|
||||||
|
|
||||||
locked = Signal()
|
locked = Signal()
|
||||||
pllout = Signal()
|
pllout = Signal()
|
||||||
|
|
||||||
m.submodules.pll = Instance("SB_PLL40_PAD",
|
module.submodules.pll = Instance("SB_PLL40_PAD",
|
||||||
p_FEEDBACK_PATH = "SIMPLE",
|
p_FEEDBACK_PATH = "SIMPLE",
|
||||||
p_DIVR = 0,
|
p_DIVR = 0,
|
||||||
p_DIVF = 7,
|
p_DIVF = 5,
|
||||||
p_DIVQ = 1,
|
p_DIVQ = 1,
|
||||||
p_FILTER_RANGE = 1,
|
p_FILTER_RANGE = 1,
|
||||||
|
|
||||||
@ -25,6 +26,11 @@ class LEDBlinker(Elaboratable):
|
|||||||
o_PLLOUTCORE = cd_sync.clk
|
o_PLLOUTCORE = cd_sync.clk
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def elaborate(self, platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
self.setup_pll(m, platform)
|
||||||
|
|
||||||
ledr0 = platform.request("led_r")
|
ledr0 = platform.request("led_r")
|
||||||
ledg0 = platform.request("led_g")
|
ledg0 = platform.request("led_g")
|
||||||
|
|
||||||
@ -34,13 +40,34 @@ class LEDBlinker(Elaboratable):
|
|||||||
ledg3 = platform.request("led_g", 3)
|
ledg3 = platform.request("led_g", 3)
|
||||||
ledg4 = platform.request("led_g", 4)
|
ledg4 = platform.request("led_g", 4)
|
||||||
|
|
||||||
half_freq = int(42e6 // 2)
|
btn1 = platform.request("button", 1)
|
||||||
timer = Signal(range(half_freq + 1))
|
btn2 = platform.request("button", 2)
|
||||||
|
btn3 = platform.request("button", 3)
|
||||||
|
|
||||||
|
disabled = Signal()
|
||||||
|
|
||||||
|
toggle1 = ToggleButton()
|
||||||
|
m.d.comb += toggle1.i.eq(btn2.i)
|
||||||
|
m.d.comb += disabled.eq(toggle1.o)
|
||||||
|
m.submodules += toggle1
|
||||||
|
|
||||||
|
pulse1 = PulseButton()
|
||||||
|
m.d.comb += pulse1.i.eq(btn1.i)
|
||||||
|
m.submodules += pulse1
|
||||||
|
|
||||||
|
pulse2 = PulseButton()
|
||||||
|
m.d.comb += pulse2.i.eq(btn3.i)
|
||||||
|
m.submodules += pulse2
|
||||||
|
|
||||||
|
init_half_freq = int(36e6 // 2)
|
||||||
|
half_freq = Signal(range((init_half_freq + 1) * 32), init=init_half_freq // 2)
|
||||||
|
timer = Signal(range((init_half_freq + 1) * 32))
|
||||||
|
|
||||||
init = Signal()
|
init = Signal()
|
||||||
|
|
||||||
with m.If(init == 0):
|
with m.If(init == 0):
|
||||||
m.d.sync += ledg0.o.eq(255)
|
m.d.sync += ledg0.o.eq(255)
|
||||||
|
m.d.sync += half_freq.eq(init_half_freq)
|
||||||
m.d.sync += init.eq(1)
|
m.d.sync += init.eq(1)
|
||||||
|
|
||||||
with m.If(timer == half_freq):
|
with m.If(timer == half_freq):
|
||||||
@ -48,13 +75,151 @@ class LEDBlinker(Elaboratable):
|
|||||||
m.d.sync += ledg0.o.eq(~ledg0.o)
|
m.d.sync += ledg0.o.eq(~ledg0.o)
|
||||||
m.d.sync += timer.eq(0)
|
m.d.sync += timer.eq(0)
|
||||||
with m.Else():
|
with m.Else():
|
||||||
|
with m.If(~disabled):
|
||||||
m.d.sync += timer.eq(timer + 1)
|
m.d.sync += timer.eq(timer + 1)
|
||||||
|
|
||||||
|
with m.If(pulse1.o):
|
||||||
|
m.d.sync += half_freq.eq(half_freq << 1)
|
||||||
|
m.d.sync += timer.eq(0)
|
||||||
|
|
||||||
|
with m.If(pulse2.o):
|
||||||
|
m.d.sync += half_freq.eq(half_freq >> 1)
|
||||||
|
m.d.sync += timer.eq(0)
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
|
||||||
from amaranth_boards.icebreaker import ICEBreakerPlatform
|
import os
|
||||||
from amaranth.vendor import SiliconBluePlatform;
|
import subprocess
|
||||||
|
from amaranth.build import *
|
||||||
|
from amaranth.vendor import LatticeICE40Platform
|
||||||
|
|
||||||
platform = ICEBreakerPlatform()
|
def _SplitResources(*args, pins, invert=False, conn=None, attrs=None, default_name, dir):
|
||||||
platform.add_resources(platform.break_off_pmod)
|
assert isinstance(pins, (str, list, dict))
|
||||||
platform.build(LEDBlinker(), do_program=True, verbose=True, nextpnr_opts='--freq 48')
|
|
||||||
|
if isinstance(pins, str):
|
||||||
|
pins = pins.split()
|
||||||
|
if isinstance(pins, list):
|
||||||
|
pins = dict(enumerate(pins))
|
||||||
|
|
||||||
|
resources = []
|
||||||
|
for number, pin in pins.items():
|
||||||
|
ios = [Pins(pin, dir=dir, invert=invert, conn=conn)]
|
||||||
|
if attrs is not None:
|
||||||
|
ios.append(attrs)
|
||||||
|
resources.append(Resource.family(*args, number, default_name=default_name, ios=ios))
|
||||||
|
return resources
|
||||||
|
|
||||||
|
def UARTResource(*args, rx, tx, rts=None, cts=None, dtr=None, dsr=None, dcd=None, ri=None,
|
||||||
|
conn=None, attrs=None, role=None):
|
||||||
|
if any(line is not None for line in (rts, cts, dtr, dsr, dcd, ri)):
|
||||||
|
assert role in ("dce", "dte")
|
||||||
|
if role == "dte":
|
||||||
|
dce_to_dte = "i"
|
||||||
|
dte_to_dce = "o"
|
||||||
|
else:
|
||||||
|
dce_to_dte = "o"
|
||||||
|
dte_to_dce = "i"
|
||||||
|
|
||||||
|
io = []
|
||||||
|
io.append(Subsignal("rx", Pins(rx, dir="i", conn=conn, assert_width=1)))
|
||||||
|
io.append(Subsignal("tx", Pins(tx, dir="o", conn=conn, assert_width=1)))
|
||||||
|
if rts is not None:
|
||||||
|
io.append(Subsignal("rts", Pins(rts, dir=dte_to_dce, conn=conn, assert_width=1)))
|
||||||
|
if cts is not None:
|
||||||
|
io.append(Subsignal("cts", Pins(cts, dir=dce_to_dte, conn=conn, assert_width=1)))
|
||||||
|
if dtr is not None:
|
||||||
|
io.append(Subsignal("dtr", Pins(dtr, dir=dte_to_dce, conn=conn, assert_width=1)))
|
||||||
|
if dsr is not None:
|
||||||
|
io.append(Subsignal("dsr", Pins(dsr, dir=dce_to_dte, conn=conn, assert_width=1)))
|
||||||
|
if dcd is not None:
|
||||||
|
io.append(Subsignal("dcd", Pins(dcd, dir=dce_to_dte, conn=conn, assert_width=1)))
|
||||||
|
if ri is not None:
|
||||||
|
io.append(Subsignal("ri", Pins(ri, dir=dce_to_dte, conn=conn, assert_width=1)))
|
||||||
|
if attrs is not None:
|
||||||
|
io.append(attrs)
|
||||||
|
return Resource.family(*args, default_name="uart", ios=io)
|
||||||
|
|
||||||
|
def SPIFlashResources(*args, cs_n, clk, copi, cipo, wp_n=None, hold_n=None,
|
||||||
|
conn=None, attrs=None):
|
||||||
|
resources = []
|
||||||
|
|
||||||
|
io_all = []
|
||||||
|
if attrs is not None:
|
||||||
|
io_all.append(attrs)
|
||||||
|
io_all.append(Subsignal("cs", PinsN(cs_n, dir="o", conn=conn)))
|
||||||
|
io_all.append(Subsignal("clk", Pins(clk, dir="o", conn=conn, assert_width=1)))
|
||||||
|
|
||||||
|
io_1x = list(io_all)
|
||||||
|
io_1x.append(Subsignal("copi", Pins(copi, dir="o", conn=conn, assert_width=1)))
|
||||||
|
io_1x.append(Subsignal("cipo", Pins(cipo, dir="i", conn=conn, assert_width=1)))
|
||||||
|
if wp_n is not None and hold_n is not None:
|
||||||
|
io_1x.append(Subsignal("wp", PinsN(wp_n, dir="o", conn=conn, assert_width=1)))
|
||||||
|
io_1x.append(Subsignal("hold", PinsN(hold_n, dir="o", conn=conn, assert_width=1)))
|
||||||
|
resources.append(Resource.family(*args, default_name="spi_flash", ios=io_1x,
|
||||||
|
name_suffix="1x"))
|
||||||
|
|
||||||
|
io_2x = list(io_all)
|
||||||
|
io_2x.append(Subsignal("dq", Pins(" ".join([copi, cipo]), dir="io", conn=conn,
|
||||||
|
assert_width=2)))
|
||||||
|
resources.append(Resource.family(*args, default_name="spi_flash", ios=io_2x,
|
||||||
|
name_suffix="2x"))
|
||||||
|
|
||||||
|
if wp_n is not None and hold_n is not None:
|
||||||
|
io_4x = list(io_all)
|
||||||
|
io_4x.append(Subsignal("dq", Pins(" ".join([copi, cipo, wp_n, hold_n]), dir="io", conn=conn,
|
||||||
|
assert_width=4)))
|
||||||
|
resources.append(Resource.family(*args, default_name="spi_flash", ios=io_4x,
|
||||||
|
name_suffix="4x"))
|
||||||
|
|
||||||
|
return resources
|
||||||
|
|
||||||
|
def LEDResources(*args, **kwargs):
|
||||||
|
return _SplitResources(*args, **kwargs, default_name="led", dir="o")
|
||||||
|
|
||||||
|
def ButtonResources(*args, **kwargs):
|
||||||
|
return _SplitResources(*args, **kwargs, default_name="button", dir="i")
|
||||||
|
|
||||||
|
class IceBreakerPlatform(LatticeICE40Platform):
|
||||||
|
device = "iCE40UP5K"
|
||||||
|
package = "SG48"
|
||||||
|
default_clk = "clk12"
|
||||||
|
resources = [
|
||||||
|
Resource("clk12", 0, Pins("35", dir="i"), Clock(12e6), Attrs(GLOBAL=True, IO_STANDARD="SB_LVCMOS")),
|
||||||
|
|
||||||
|
*LEDResources(pins="11 37", invert=True, attrs=Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
# Semantic aliases
|
||||||
|
Resource("led_r", 0, PinsN("11", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
Resource("led_g", 0, PinsN("37", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
|
||||||
|
*ButtonResources(pins="10", invert=True, attrs=Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
|
||||||
|
UARTResource(0, rx="6", tx="9", attrs=Attrs(IO_STANDARD="SB_LVTTL", PULLUP=1)),
|
||||||
|
|
||||||
|
*SPIFlashResources(0, cs_n="16", clk="15", copi="14", cipo="17", wp_n="12", hold_n="13", attrs=Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
|
||||||
|
*LEDResources(pins={2: "7", 3: "1", 4: "2", 5: "8", 6: "3"}, conn=("pmod", 0), attrs=Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
# Semantic aliases
|
||||||
|
Resource("led_r", 1, Pins("7", dir="o", conn=("pmod", 0)), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
Resource("led_g", 1, Pins("1", dir="o", conn=("pmod", 0)), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
Resource("led_g", 2, Pins("2", dir="o", conn=("pmod", 0)), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
Resource("led_g", 3, Pins("8", dir="o", conn=("pmod", 0)), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
Resource("led_g", 4, Pins("3", dir="o", conn=("pmod", 0)), Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
*ButtonResources(pins={1: "9", 2: "4", 3: "10"}, conn=("pmod", 0), attrs=Attrs(IO_STANDARD="SB_LVCMOS")),
|
||||||
|
]
|
||||||
|
|
||||||
|
connectors = [
|
||||||
|
Connector("pmod", 0, " 4 2 47 45 - - 3 48 46 44 - -"), # PMOD1A
|
||||||
|
Connector("pmod", 1, "43 38 34 31 - - 42 36 32 28 - -"), # PMOD1B
|
||||||
|
Connector("pmod", 2, "27 25 21 19 - - 26 23 20 18 - -"), # PMOD2
|
||||||
|
]
|
||||||
|
|
||||||
|
def toolchain_program(self, products, name):
|
||||||
|
iceprog = os.environ.get("ICEPROG", "iceprog")
|
||||||
|
with products.extract("{}.bin".format(name)) as bitstream_filename:
|
||||||
|
subprocess.check_call([iceprog, bitstream_filename])
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
platform = IceBreakerPlatform()
|
||||||
|
platform.build(ReBbaRb(), do_program=True, verbose=True)
|
51
rebbarb/toggle_button.py
Normal file
51
rebbarb/toggle_button.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
from amaranth.build import Platform
|
||||||
|
from amaranth import *
|
||||||
|
|
||||||
|
from debouncer import Debouncer
|
||||||
|
|
||||||
|
class ToggleButton(Elaboratable):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#signals
|
||||||
|
self.i = Signal()
|
||||||
|
self.o = Signal()
|
||||||
|
|
||||||
|
#state
|
||||||
|
self.last_seen = Signal()
|
||||||
|
|
||||||
|
def elaborate(self, platform: Platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
debouncer = Debouncer(10000)
|
||||||
|
|
||||||
|
m.submodules += debouncer
|
||||||
|
|
||||||
|
m.d.comb += debouncer.i.eq(self.i)
|
||||||
|
|
||||||
|
with m.If((debouncer.o != self.last_seen) & (debouncer.o == 1)):
|
||||||
|
m.d.sync += self.o.eq(~self.o)
|
||||||
|
|
||||||
|
m.d.sync += self.last_seen.eq(debouncer.o)
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
from amaranth.sim import Simulator, Period
|
||||||
|
|
||||||
|
dut = ToggleButton()
|
||||||
|
|
||||||
|
async def testbench(ctx):
|
||||||
|
await ctx.tick().repeat(2)
|
||||||
|
ctx.set(dut.i, True)
|
||||||
|
await ctx.tick().repeat(5)
|
||||||
|
ctx.set(dut.i, False)
|
||||||
|
await ctx.tick().repeat(5)
|
||||||
|
ctx.set(dut.i, True)
|
||||||
|
await ctx.tick().repeat(5)
|
||||||
|
ctx.set(dut.i, False)
|
||||||
|
|
||||||
|
sim = Simulator(dut)
|
||||||
|
sim.add_clock(Period(MHz=1))
|
||||||
|
sim.add_testbench(testbench)
|
||||||
|
with sim.write_vcd("ToggleButton.vcd"):
|
||||||
|
sim.run_until(Period(MHz=1) * 25)
|
@ -1,4 +1,4 @@
|
|||||||
amaranth==0.5.7
|
amaranth @ git+https://github.com/amaranth-lang/amaranth@main
|
||||||
amaranth-boards @ git+https://github.com/amaranth-lang/amaranth-boards.git@7e24efe2f6e95afddd0c1b56f1a9423c48caa472
|
amaranth-boards @ git+https://github.com/amaranth-lang/amaranth-boards.git@7e24efe2f6e95afddd0c1b56f1a9423c48caa472
|
||||||
amaranth-yosys==0.50.0.0.post115
|
amaranth-yosys==0.50.0.0.post115
|
||||||
importlib_resources==6.5.2
|
importlib_resources==6.5.2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user