Restructured Amaranth code to be able to import sibling modules

This commit is contained in:
Roflin committed 2022-01-22 19:28:29 +01:00
1 parent 7780e14887
commit 4a2d2b4881
91 files changed
+518 -356

No files matched your search

+2 -1
View File
@@ -1,3 +1,4 @@
*.vcd
*.v
**/__pycache__
**/__pycache__
venv
-74
View File
@@ -1,74 +0,0 @@
from amaranth import *
class UpCounter(Elaboratable):
"""
A 16-bit up counter with a fixed limit.
Parameters
----------
limit : int
The value at which the counter overflows.
Attributes
----------
en : Signal, in
The counter is incremented if ``en`` is asserted, and retains
its value otherwise.
ovf : Signal, out
``ovf`` is asserted when the counter reaches its limit.
"""
def __init__(self, limit):
self.limit = limit
# Ports
self.en = Signal()
self.ovf = Signal()
# State
self.count = Signal(16)
def elaborate(self, platform):
m = Module()
m.d.comb += self.ovf.eq(self.count == self.limit)
with m.If(self.en):
with m.If(self.ovf):
m.d.sync += self.count.eq(0)
with m.Else():
m.d.sync += self.count.eq(self.count + 1)
return m
from amaranth.sim import Simulator
dut = UpCounter(25)
def bench():
# Disabled counter should not overflow.
yield dut.en.eq(0)
for _ in range(30):
yield
assert not (yield dut.ovf)
# Once enabled, the counter should overflow in 25 cycles.
yield dut.en.eq(1)
for _ in range(25):
yield
assert not (yield dut.ovf)
yield
assert (yield dut.ovf)
# The overflow should clear in one cycle.
yield
assert not (yield dut.ovf)
sim = Simulator(dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(bench)
with sim.write_vcd("up_counter.vcd"):
sim.run()
from amaranth_boards.icebreaker import *
ICEBreakerPlatform().build(UpCounter(25), do_program=True)
-110
View File
@@ -1,110 +0,0 @@
import enum
import sys
import os
from amaranth.build import Platform
from amaranth import *
from amaranth.sim import Simulator
class ClockState(enum.Enum):
LOW = 0
FALLING = 1
HIGH = 2
RISING = 3
class ExiClock(Elaboratable):
def __init__(self):
# Ports
self.exiClk = Signal()
self.exiClkState = Signal(2)
# State
self.prevExiClkValid = Signal()
self.prevExiClk = Signal()
self.prevExiClkState = Signal(2)
def elaborate(self, platform: Platform):
m = Module()
with m.If(self.prevExiClkValid):
with m.If(self.prevExiClkState == ClockState.FALLING):
m.d.comb += self.exiClkState.eq(ClockState.LOW)
with m.Elif(self.prevExiClkState == ClockState.RISING):
m.d.comb += self.exiClkState.eq(ClockState.HIGH)
with m.Else():
with m.If(self.prevExiClk ^ self.exiClk):
m.d.comb += self.exiClkState.eq(Cat(1, self.exiClk))
with m.Else():
m.d.comb += self.exiClkState.eq(Cat(0, self.exiClk))
m.d.sync += self.prevExiClkState.eq(self.exiClkState)
m.d.sync += self.prevExiClk.eq(self.exiClk)
m.d.sync += self.prevExiClkValid.eq(1)
return m
#####
# TestBench
#####
class TestBench:
def __init__(self):
pass
def FlipExiClock(self, dut):
yield dut.exiClk.eq(~dut.exiClk)
def clockTest(self):
dut = self.dut
yield dut.exiClk.eq(0)
yield
yield from self.FlipExiClock(dut)
yield
assert (yield dut.exiClkState) == ClockState.RISING.value
yield
assert (yield dut.exiClkState) == ClockState.HIGH.value
yield
yield from self.FlipExiClock(dut)
yield
assert (yield dut.exiClkState) == ClockState.FALLING.value
yield
assert (yield dut.exiClkState) == ClockState.LOW.value
yield
def simulate(self):
self.dut = ExiClock()
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.clockTest)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ExiClock.vcd"):
sim.run()
#####
# Main portion
#####
def main():
if(len(sys.argv) == 2):
if sys.argv[1] == "s":
bench = TestBench()
bench.simulate()
if sys.argv[1] == "v":
mod = ExiClock()
with open(os.path.dirname(os.path.abspath(__file__)) + "/ExiClock.v", "w") as f:
f.write(verilog.convert(mod, ports=[mod.exiClk, mod.exiClkState]))
else:
bench = TestBench()
bench.simulate()
if __name__ == "__main__":
main()
-22
View File
@@ -1,22 +0,0 @@
from amaranth import *
class LEDBlinker(Elaboratable):
def elaborate(self, platform):
m = Module()
led = platform.request("led")
half_freq = int(platform.default_clk_frequency // 2)
timer = Signal(range(half_freq + 1))
with m.If(timer == half_freq):
m.d.sync += led.eq(~led)
m.d.sync += timer.eq(0)
with m.Else():
m.d.sync += timer.eq(timer + 1)
return m
from amaranth_boards.icebreaker import *
ICEBreakerPlatform().build(LEDBlinker(), do_program=True)
+39
View File
@@ -0,0 +1,39 @@
from amaranth.build import Platform
from amaranth import *
class Debouncer(Elaboratable):
def __init__(self, cycles: int):
#signals
self.input = Signal()
self.output = 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.input):
m.d.sync += self.count.eq(self.count.reset)
m.d.sync += self.state.eq(self.input)
with m.Elif(self.input == self.state):
m.d.sync += self.count.eq(self.count.reset)
m.d.sync += self.state.eq(self.input)
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.input)
m.d.sync += self.prevIn.eq(self.input)
m.d.comb += self.output.eq(self.state)
return m
+45
View File
@@ -0,0 +1,45 @@
import enum
from amaranth.build import Platform
from amaranth import *
class ClockState(enum.Enum):
LOW = 0
FALLING = 1
HIGH = 2
RISING = 3
class ExiClock(Elaboratable):
def __init__(self):
# Ports
self.exiClk = Signal()
self.exiClkState = Signal(2)
# State
self.prevExiClkValid = Signal()
self.prevExiClk = Signal()
self.prevExiClkState = Signal(2)
def elaborate(self, platform: Platform):
m = Module()
with m.If(self.prevExiClkValid):
with m.If(self.prevExiClkState == ClockState.FALLING):
m.d.comb += self.exiClkState.eq(ClockState.LOW)
with m.Elif(self.prevExiClkState == ClockState.RISING):
m.d.comb += self.exiClkState.eq(ClockState.HIGH)
with m.Else():
with m.If(self.prevExiClk ^ self.exiClk):
m.d.comb += self.exiClkState.eq(Cat(1, self.exiClk))
with m.Else():
m.d.comb += self.exiClkState.eq(Cat(0, self.exiClk))
m.d.sync += self.prevExiClkState.eq(self.exiClkState)
m.d.sync += self.prevExiClk.eq(self.exiClk)
m.d.sync += self.prevExiClkValid.eq(1)
return m
+23
View File
@@ -0,0 +1,23 @@
from amaranth.build import Platform
from amaranth import *
from ExiDecoders.GetId import GetId
class ExiDecoder(Elaboratable):
def __init__(self):
#ports
self.request = Signal(16)
self.request_type = Signal(1)
#state
def elaborate(self, platform: Platform):
m = Module()
getId = GetId()
m.submodules += getId
m.d.comb += getId.request.eq(self.request)
m.d.comb += self.request_type[0].eq(getId.isGetId)
return m
+51
View File
@@ -0,0 +1,51 @@
from ReBba.Components.ShiftRegister import ShiftRegister
from ReBba.Components.ExiClock import ClockState
from amaranth import Const, Elaboratable, Module, Signal
from amaranth.build import Platform
class ExiRequest(Elaboratable):
def __init__(self):
#ports
self.request = Signal(16)
self.nen = Signal(1)
self.rst = Signal(1)
self.exiClkState = Signal(2)
self.exiIn = Signal(1)
self.requestComplete = Signal(1)
#state
self.disableShift = Signal(1, reset=0)
self.shiftRegister = ShiftRegister(16)
self.clockCount = Signal(5, reset=0)
def elaborate(self, platform: Platform):
m = Module()
m.submodules += self.shiftRegister
m.d.comb += self.request.eq(self.shiftRegister.data)
m.d.comb += self.shiftRegister.inb.eq(self.exiIn)
m.d.comb += self.shiftRegister.exiClkState.eq(self.exiClkState)
m.d.comb += self.shiftRegister.nen.eq(self.disableShift)
with m.If(~self.nen):
with m.If(self.clockCount != 16):
with m.If(self.exiClkState == ClockState.FALLING):
m.d.sync += self.clockCount.eq(self.clockCount + 1)
with m.If(self.clockCount == 16):
m.d.comb += self.disableShift.eq(Const(1))
m.d.comb += self.requestComplete.eq(Const(1))
with m.If(self.rst):
m.d.comb += self.request.eq(self.request.reset)
m.d.sync += self.clockCount.eq(self.clockCount.reset)
m.d.comb += self.disableShift.eq(self.disableShift.reset)
m.d.comb += self.shiftRegister.rst.eq(self.rst)
return m
+29
View File
@@ -0,0 +1,29 @@
from ReBba.Components.ExiClock import ClockState
from amaranth import *
from amaranth.build import Platform
class ShiftRegister(Elaboratable):
def __init__(self, width):
self.width = width
# Ports
self.nen = Signal()
self.exiClkState = Signal(2)
self.rst = Signal()
self.inb = Signal()
self.data = Signal(self.width, reset=0)
def elaborate(self, platform: Platform):
m = Module()
with m.If(self.rst):
m.d.sync += self.data.eq(self.data.reset)
with m.If(~self.nen):
with m.If(self.exiClkState == ClockState.FALLING):
m.d.sync += self.data.eq(self.data.shift_left(1) | self.inb )
return m
+19
View File
@@ -0,0 +1,19 @@
from amaranth.build import Platform
from amaranth import Signal, Const, Module, Elaboratable
class GetId(Elaboratable):
def __init__(self):
self.request = Signal(16)
self.isGetId = Signal()
pass
def elaborate(self, platform: Platform):
m = Module()
with m.If(self.request == 0):
m.d.comb += self.isGetId.eq(Const(1))
with m.Else():
m.d.comb += self.isGetId.eq(Const(0))
return m
+31 -13
View File
@@ -7,7 +7,9 @@ from amaranth.sim import Simulator
from amaranth_boards.icebreaker import *
from ExiClock import ExiClock
from ShiftRegister import ShiftRegister
from ExiRequest import ExiRequest
from Debouncer import Debouncer
from ExiDecoder import ExiDecoder
class ReBba(Elaboratable):
def __init__(self):
@@ -16,6 +18,9 @@ class ReBba(Elaboratable):
def elaborate(self, platform: Platform):
m = Module()
uledg = platform.request("led_g", 0)
uledr = platform.request("led_r", 0)
led1 = platform.request("led_g", 1)
led2 = platform.request("led_g", 4)
led3 = platform.request("led_g", 2)
@@ -26,23 +31,36 @@ class ReBba(Elaboratable):
btn2 = platform.request("button", 2)
btn3 = platform.request("button", 3)
debounce1 = Debouncer(10000)
m.submodules += debounce1
m.d.comb += debounce1.input.eq(btn3)
exiClk = ExiClock()
m.submodules += exiClk
sr = ShiftRegister(5)
m.submodules += sr
m.d.comb += exiClk.exiClk.eq(debounce1.output)
exiReq = ExiRequest()
m.submodules += exiReq
m.d.comb += led1.eq(sr.data[0])
m.d.comb += led2.eq(sr.data[1])
m.d.comb += led3.eq(sr.data[2])
m.d.comb += led4.eq(sr.data[3])
m.d.comb += led5.eq(sr.data[4])
m.d.comb += exiReq.exiClkState.eq(exiClk.exiClkState)
m.d.comb += exiReq.exiIn.eq(btn1)
m.d.comb += exiReq.rst.eq(btn2)
m.d.comb += exiClk.exiClk.eq(btn3)
m.d.comb += led1.eq(exiReq.request[0])
m.d.comb += led2.eq(exiReq.request[1])
m.d.comb += led3.eq(exiReq.request[2])
m.d.comb += led4.eq(exiReq.request[3])
m.d.comb += sr.rst.eq(btn2)
m.d.comb += sr.inb.eq(btn1)
m.d.comb += sr.nen.eq(Const(0))
m.d.comb += sr.exiClkState.eq(exiClk.exiClkState)
m.d.comb += led5.eq(exiReq.requestComplete)
exiDec = ExiDecoder()
m.submodules += exiDec
m.d.comb += exiDec.request.eq(exiReq.request)
m.d.comb += uledr.eq(exiDec.request_type[0])
m.d.comb += uledg.eq(exiReq.requestComplete)
return m
+54
View File
@@ -0,0 +1,54 @@
from ReBba.Components.Debouncer import Debouncer
from amaranth import Const
from amaranth.sim import Simulator
import os
class TestBench:
def __init__(self):
pass
def holdTest(self):
dut = self.dut
yield
yield
yield dut.input.eq(Const(1))
yield
yield dut.input.eq(Const(0))
yield
for _ in range(5):
assert(yield(dut.output) == 1)
yield
yield dut.input.eq(Const(1))
yield
yield dut.input.eq(Const(0))
yield
for _ in range(16):
assert(yield(dut.output) == 1)
yield
assert(yield(dut.output) == 0)
yield
yield
def simulate(self):
self.dut = Debouncer(15)
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.holdTest)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/Debouncer.vcd"):
sim.run()
def main():
bench = TestBench()
bench.simulate()
if __name__ == "__main__":
main()
+48
View File
@@ -0,0 +1,48 @@
from ReBba.Components.ExiClock import ClockState, ExiClock
from ReBba.TestBenches.SimHelpers.ExiSimHelper import exiClockCycle
from amaranth.sim import Simulator
import os
class TestBench:
def __init__(self):
pass
def FlipExiClock(self, dut):
yield dut.exiClk.eq(~dut.exiClk)
def clockTest(self):
dut = self.dut
yield dut.exiClk.eq(0)
yield
yield from self.FlipExiClock(dut)
yield
assert (yield dut.exiClkState) == ClockState.RISING.value
yield
assert (yield dut.exiClkState) == ClockState.HIGH.value
yield
yield from self.FlipExiClock(dut)
yield
assert (yield dut.exiClkState) == ClockState.FALLING.value
yield
assert (yield dut.exiClkState) == ClockState.LOW.value
yield
def simulate(self):
self.dut = ExiClock()
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.clockTest)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ExiClock.vcd"):
sim.run()
def main():
bench = TestBench()
bench.simulate()
if __name__ == "__main__":
main()
+65
View File
@@ -0,0 +1,65 @@
from ReBba.Components.ExiRequest import ExiRequest
from SimHelpers.ExiSimHelper import exiClockCycle, resetDut
from amaranth import Const
from amaranth.sim import Simulator
import os
class TestBench:
def __init__(self):
pass
def requestTest(self):
dut = self.dut
yield dut.nen.eq(Const(0))
def afterLow0():
assert((yield dut.requestComplete) == 0)
def afterLow1():
assert((yield dut.requestComplete) == 1)
for i in range(15):
yield dut.exiIn.eq(~dut.exiIn)
yield from exiClockCycle(dut.exiClkState, AfterLow=afterLow0)
yield dut.exiIn.eq(~dut.exiIn)
yield from exiClockCycle(dut.exiClkState, AfterLow=afterLow1)
assert((yield dut.requestComplete) == 1)
yield from exiClockCycle(dut.exiClkState)
assert((yield dut.requestComplete) == 1)
yield from resetDut(dut.rst)
for i in range(15):
yield dut.exiIn.eq(~dut.exiIn)
yield from exiClockCycle(dut.exiClkState, AfterLow=afterLow0)
yield dut.exiIn.eq(~dut.exiIn)
yield from exiClockCycle(dut.exiClkState, AfterLow=afterLow1)
def simulate(self):
self.dut = ExiRequest()
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.requestTest)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ExiRequest.vcd"):
sim.run()
#####
# Main portion
#####
def main():
bench = TestBench()
bench.simulate()
if __name__ == "__main__":
main()
@@ -0,0 +1,79 @@
from amaranth import Elaboratable
from ReBba.Components.ShiftRegister import ShiftRegister
from ReBba.TestBenches.SimHelpers.ExiSimHelper import exiClockCycle
from amaranth.sim import Simulator
import os
class TestBench:
def __init__(self):
pass
def enabled_test(self):
dut = self.dut
def afterAny():
assert not (yield dut.data)
# Disabled ShiftRegister should not Change.
yield dut.nen.eq(1)
for _ in range(10):
yield dut.inb.eq(~dut.inb)
yield from exiClockCycle(dut.exiClkState, AfterHigh=afterAny, AfterFalling=afterAny, AfterLow=afterAny, AfterRising=afterAny)
def normal_operation(self):
dut = self.dut
def oracle(i):
if i == 0: return 0x01
if i == 1: return 0x02
if i == 2: return 0x05
if i == 3: return 0x0A
if i == 4: return 0x15
if i == 5: return 0x2A
if i == 6: return 0x55
if i == 7: return 0xAA
if i == 8: return 0x55
if i == 9: return 0xAA
expectedOutput = 0
def afterLow():
assert (yield dut.data) == expectedOutput
yield dut.nen.eq(0)
for i in range(10):
expectedOutput = oracle(i)
yield dut.inb.eq(~dut.inb)
yield from exiClockCycle(dut.exiClkState, AfterLow=afterLow)
def simulate(self):
self.dut = ShiftRegister(8)
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.enabled_test)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ShiftRegister_enable.vcd"):
sim.run()
self.dut = ShiftRegister(8)
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.normal_operation)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ShiftRegister_shift.vcd"):
sim.run()
def main():
bench = TestBench()
bench.simulate()
if __name__ == "__main__":
main()
@@ -0,0 +1,30 @@
from typing import Callable
from ReBba.Components.ExiClock import ClockState
from amaranth import Const, Elaboratable, Signal
def empty():
yield None
def exiClockCycle(exiClock: Signal, AfterHigh: Callable = empty, AfterFalling: Callable = empty, AfterLow: Callable = empty, AfterRising: Callable = empty):
yield exiClock.eq(ClockState.HIGH)
yield
yield from AfterHigh()
yield
yield exiClock.eq(ClockState.FALLING)
yield from AfterFalling()
yield exiClock.eq(ClockState.LOW)
yield
yield from AfterLow()
yield
yield exiClock.eq(ClockState.RISING)
yield from AfterRising()
def resetDut(rst: Signal):
yield
yield rst.eq(Const(1))
yield
yield rst.eq(Const(0))
yield
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-136
View File
@@ -1,136 +0,0 @@
import os
import sys
from amaranth import *
from amaranth.build import Platform
from amaranth.back import verilog
from amaranth.sim import Simulator
from ExiClock import ClockState
#####
# Hardware Description.
#####
class ShiftRegister(Elaboratable):
def __init__(self, width):
self.width = width
# Ports
self.nen = Signal()
self.exiClkState = Signal(2)
self.rst = Signal()
self.inb = Signal()
self.data = Signal(self.width, reset=0)
def elaborate(self, platform: Platform):
m = Module()
with m.If(self.rst):
m.d.sync += self.data.eq(self.data.reset)
with m.If(~self.nen):
with m.If(self.exiClkState == ClockState.FALLING):
m.d.sync += self.data.eq(self.data.shift_left(1) | self.inb )
return m
#####
# TestBench
#####
class TestBench:
def __init__(self):
pass
def simExiClock(self, dut):
yield dut.exiClk.eq(~dut.exiClk)
def enabled_test(self):
dut = self.dut
# Disabled ShiftRegister should not Change.
yield dut.nen.eq(1)
for _ in range(10):
yield dut.inb.eq(~dut.inb)
yield from self.simExiClock(dut)
yield from self.simExiClock(dut)
assert not (yield dut.data)
yield
yield
yield
yield from self.simExiClock(dut)
yield from self.simExiClock(dut)
assert not (yield dut.data)
yield
yield
yield
def normal_operation(self):
dut = self.dut
def oracle(i):
if i == 0: return 0x01
if i == 1: return 0x02
if i == 2: return 0x05
if i == 3: return 0x0A
if i == 4: return 0x15
if i == 5: return 0x2A
if i == 6: return 0x55
if i == 7: return 0xAA
if i == 8: return 0x55
if i == 9: return 0xAA
yield dut.nen.eq(0)
for i in range(10):
yield dut.inb.eq(~dut.inb)
yield from self.simExiClock(dut)
yield
yield
yield from self.simExiClock(dut)
yield
yield
assert (yield dut.data) == oracle(i)
def simulate(self):
self.dut = ShiftRegister(8)
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.enabled_test)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ShiftRegister_enable.vcd"):
sim.run()
self.dut = ShiftRegister(8)
sim = Simulator(self.dut)
sim.add_clock(1e-6) # 1 MHz
sim.add_sync_process(self.normal_operation)
with sim.write_vcd(os.path.dirname(os.path.abspath(__file__)) + "/ShiftRegister_shift.vcd"):
sim.run()
#####
# Main portion
#####
def main():
if(len(sys.argv) == 2):
if sys.argv[1] == "s":
bench = TestBench()
bench.simulate()
if sys.argv[1] == "v":
mod = ShiftRegister(8)
with open(os.path.dirname(os.path.abspath(__file__)) + "/shift_register.v", "w") as f:
f.write(verilog.convert(mod, ports=[mod.exiClk, mod.inb, mod.data]))
else:
bench = TestBench()
bench.simulate()
if __name__ == "__main__":
main()
+3
View File
@@ -0,0 +1,3 @@
from setuptools import setup, find_packages
setup(name='ReBba', version='0.1', packages=find_packages())