mirror of
https://git.sr.ht/~kivikakk/niar
synced 2024-12-22 17:42: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.
|
See the [template project] for usage.
|
||||||
|
|
||||||
[Amaranth]: https://amaranth-lang.org/
|
[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