Restructured Amaranth code to be able to import sibling modules
This commit is contained in:
parent
7780e14887
commit
4a2d2b4881
1
re-bba/.gitignore
vendored
1
re-bba/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
*.vcd
|
||||
*.v
|
||||
**/__pycache__
|
||||
venv
|
||||
|
@ -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)
|
@ -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()
|
@ -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
re-bba/ReBba/Components/Debouncer.py
Normal file
39
re-bba/ReBba/Components/Debouncer.py
Normal 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
re-bba/ReBba/Components/ExiClock.py
Normal file
45
re-bba/ReBba/Components/ExiClock.py
Normal 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
re-bba/ReBba/Components/ExiDecoder.py
Normal file
23
re-bba/ReBba/Components/ExiDecoder.py
Normal 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
re-bba/ReBba/Components/ExiRequest.py
Normal file
51
re-bba/ReBba/Components/ExiRequest.py
Normal 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
re-bba/ReBba/Components/ShiftRegister.py
Normal file
29
re-bba/ReBba/Components/ShiftRegister.py
Normal 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
re-bba/ReBba/ExiDecoders/GetId.py
Normal file
19
re-bba/ReBba/ExiDecoders/GetId.py
Normal 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
|
@ -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 += 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 += exiClk.exiClk.eq(debounce1.output)
|
||||
|
||||
m.d.comb += exiClk.exiClk.eq(btn3)
|
||||
exiReq = ExiRequest()
|
||||
m.submodules += exiReq
|
||||
|
||||
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 += exiReq.exiClkState.eq(exiClk.exiClkState)
|
||||
m.d.comb += exiReq.exiIn.eq(btn1)
|
||||
m.d.comb += exiReq.rst.eq(btn2)
|
||||
|
||||
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 += 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
re-bba/ReBba/TestBenches/DebouncerTb.py
Normal file
54
re-bba/ReBba/TestBenches/DebouncerTb.py
Normal 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
re-bba/ReBba/TestBenches/ExiClockTb.py
Normal file
48
re-bba/ReBba/TestBenches/ExiClockTb.py
Normal 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
re-bba/ReBba/TestBenches/ExiRequestTb.py
Normal file
65
re-bba/ReBba/TestBenches/ExiRequestTb.py
Normal 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()
|
79
re-bba/ReBba/TestBenches/ShiftRegisterTb.py
Normal file
79
re-bba/ReBba/TestBenches/ShiftRegisterTb.py
Normal file
@ -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()
|
||||
|
||||
|
||||
|
30
re-bba/ReBba/TestBenches/SimHelpers/ExiSimHelper.py
Normal file
30
re-bba/ReBba/TestBenches/SimHelpers/ExiSimHelper.py
Normal file
@ -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
|
@ -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()
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
re-bba/setup.py
Normal file
3
re-bba/setup.py
Normal file
@ -0,0 +1,3 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='ReBba', version='0.1', packages=find_packages())
|
Loading…
Reference in New Issue
Block a user