mirror of
https://git.sr.ht/~kivikakk/niar
synced 2024-12-22 12:02:24 +00:00
roll template in.
This commit is contained in:
parent
3e8126f5a5
commit
2679e43c02
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 100
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
|
@ -5,5 +5,5 @@ A small framework for building projects with [Amaranth].
|
|||
See the [template project] for usage.
|
||||
|
||||
[Amaranth]: https://amaranth-lang.org/
|
||||
[template project]: https://github.com/kivikakk/niar-template
|
||||
[template project]: https://github.com/kivikakk/niar/tree/main/template
|
||||
|
||||
|
|
9
template/.editorconfig
Normal file
9
template/.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 100
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
3
template/.gitignore
vendored
Normal file
3
template/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
__pycache__
|
||||
/build
|
||||
*.vcd
|
76
template/cxxrtl/main.cc
Normal file
76
template/cxxrtl/main.cc
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
#include <cxxrtl/cxxrtl_vcd.h>
|
||||
#include <newproject.h>
|
||||
|
||||
static cxxrtl_design::p_newproject top;
|
||||
static cxxrtl::vcd_writer vcd;
|
||||
static uint64_t vcd_time = 0;
|
||||
|
||||
static void step() {
|
||||
top.p_clk.set(true);
|
||||
top.step();
|
||||
vcd.sample(vcd_time++);
|
||||
top.p_clk.set(false);
|
||||
top.step();
|
||||
vcd.sample(vcd_time++);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::optional<std::string> vcd_out = std::nullopt;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--vcd") == 0 && argc >= (i + 2)) {
|
||||
vcd_out = std::string(argv[++i]);
|
||||
} else {
|
||||
std::cerr << "unknown argument \"" << argv[i] << "\"" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (vcd_out.has_value()) {
|
||||
debug_items di;
|
||||
top.debug_info(&di, nullptr, "top ");
|
||||
vcd.add(di);
|
||||
}
|
||||
|
||||
top.p_rst.set(true);
|
||||
step();
|
||||
|
||||
top.p_rst.set(false);
|
||||
|
||||
// ledr should be low or high according to 'expected', where each element
|
||||
// represents 1/4th of a second. ledg should always be high.
|
||||
//
|
||||
// This mirrors TestTop in Python.
|
||||
int rc = 0;
|
||||
bool done = false;
|
||||
|
||||
std::vector<int> expected = {0, 1, 1, 0, 0, 1, 1, 0};
|
||||
for (std::vector<int>::size_type i = 0; i < expected.size() && !done; ++i) {
|
||||
for (int j = 0; j < (CLOCK_HZ / 4); ++j) {
|
||||
if (top.p_ledr.get<int>() != expected[i]) {
|
||||
std::cerr << "unexpected ledr at i(" << i << "), j(" << j << ")"
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
assert(top.p_ledg);
|
||||
|
||||
step();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "finished on cycle " << (vcd_time >> 1) << std::endl;
|
||||
|
||||
if (vcd_out.has_value()) {
|
||||
std::ofstream of(*vcd_out);
|
||||
of << vcd.buffer;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
13
template/newproject/__init__.py
Normal file
13
template/newproject/__init__.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import niar
|
||||
|
||||
from . import rtl
|
||||
from .targets import cxxrtl, icebreaker, ulx3s
|
||||
|
||||
__all__ = ["NewProject"]
|
||||
|
||||
|
||||
class NewProject(niar.Project):
|
||||
name = "newproject"
|
||||
top = rtl.Top
|
||||
targets = [icebreaker, ulx3s]
|
||||
cxxrtl_targets = [cxxrtl]
|
3
template/newproject/__main__.py
Normal file
3
template/newproject/__main__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from . import NewProject
|
||||
|
||||
NewProject().main()
|
65
template/newproject/rtl/__init__.py
Normal file
65
template/newproject/rtl/__init__.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
from amaranth import Module, Signal
|
||||
from amaranth.lib import wiring
|
||||
from amaranth.lib.wiring import Out
|
||||
|
||||
from ..targets import cxxrtl, icebreaker, ulx3s
|
||||
|
||||
__all__ = ["Top"]
|
||||
|
||||
|
||||
class Top(wiring.Component):
|
||||
def __init__(self, platform):
|
||||
if isinstance(platform, cxxrtl):
|
||||
super().__init__(
|
||||
{
|
||||
"ledr": Out(1),
|
||||
"ledg": Out(1),
|
||||
}
|
||||
)
|
||||
else:
|
||||
super().__init__({})
|
||||
|
||||
def elaborate(self, platform):
|
||||
|
||||
m = Module()
|
||||
|
||||
m.submodules.blinker = blinker = Blinker()
|
||||
|
||||
match platform:
|
||||
case icebreaker():
|
||||
m.d.comb += platform.request("led_r").o.eq(blinker.ledr)
|
||||
m.d.comb += platform.request("led_g").o.eq(blinker.ledg)
|
||||
|
||||
case ulx3s():
|
||||
m.d.comb += platform.request("led", 0).o.eq(blinker.ledr)
|
||||
m.d.comb += platform.request("led", 1).o.eq(blinker.ledg)
|
||||
|
||||
case cxxrtl():
|
||||
m.d.comb += self.ledr.eq(blinker.ledr)
|
||||
m.d.comb += self.ledg.eq(blinker.ledg)
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class Blinker(wiring.Component):
|
||||
ledr: Out(1)
|
||||
ledg: Out(1)
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
m.d.comb += self.ledg.eq(1)
|
||||
|
||||
timer_top = (int(platform.default_clk_frequency) // 2) - 1
|
||||
timer_half = (int(platform.default_clk_frequency) // 4) - 1
|
||||
timer_reg = Signal(range(timer_top), init=timer_half)
|
||||
|
||||
with m.If(timer_reg == 0):
|
||||
m.d.sync += [
|
||||
self.ledr.eq(~self.ledr),
|
||||
timer_reg.eq(timer_top),
|
||||
]
|
||||
with m.Else():
|
||||
m.d.sync += timer_reg.eq(timer_reg - 1)
|
||||
|
||||
return m
|
17
template/newproject/targets.py
Normal file
17
template/newproject/targets.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
import niar
|
||||
from amaranth_boards.icebreaker import ICEBreakerPlatform
|
||||
from amaranth_boards.ulx3s import ULX3S_45F_Platform
|
||||
|
||||
__all__ = ["icebreaker", "ulx3s", "cxxrtl"]
|
||||
|
||||
|
||||
class icebreaker(ICEBreakerPlatform):
|
||||
pass
|
||||
|
||||
|
||||
class ulx3s(ULX3S_45F_Platform):
|
||||
pass
|
||||
|
||||
|
||||
class cxxrtl(niar.CxxrtlPlatform):
|
||||
default_clk_frequency = 3_000_000.0
|
18
template/pyproject.toml
Normal file
18
template/pyproject.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
[project]
|
||||
name = "newproject"
|
||||
version = "0.0"
|
||||
description = ""
|
||||
authors = [
|
||||
{name = "name", email = "email@example.com"},
|
||||
]
|
||||
dependencies = [
|
||||
"amaranth >= 0.5, < 0.7",
|
||||
"amaranth-boards",
|
||||
"niar >= 0.1",
|
||||
]
|
||||
requires-python = ">=3.8"
|
||||
license = {text = "BSD-2-Clause"}
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
0
template/tests/__init__.py
Normal file
0
template/tests/__init__.py
Normal file
30
template/tests/test_top.py
Normal file
30
template/tests/test_top.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
import unittest
|
||||
|
||||
from amaranth.hdl import Fragment
|
||||
from amaranth.sim import Simulator
|
||||
|
||||
from newproject.rtl import Blinker
|
||||
|
||||
|
||||
class test:
|
||||
simulation = True
|
||||
default_clk_frequency = 8.0
|
||||
|
||||
|
||||
class TestBlinker(unittest.TestCase):
|
||||
platform = test()
|
||||
|
||||
def test_blinks(self):
|
||||
dut = Blinker()
|
||||
|
||||
async def testbench(ctx):
|
||||
for ledr in [0, 1, 1, 0, 0, 1, 1, 0]:
|
||||
for _ in range(2):
|
||||
assert ctx.get(dut.ledr) == ledr
|
||||
assert ctx.get(dut.ledg)
|
||||
await ctx.tick()
|
||||
|
||||
sim = Simulator(Fragment.get(dut, self.platform))
|
||||
sim.add_clock(1 / 8)
|
||||
sim.add_testbench(testbench)
|
||||
sim.run()
|
Loading…
Reference in a new issue