1
0
Fork 0
mirror of https://git.sr.ht/~kivikakk/niar synced 2024-12-22 12:22:25 +00:00

roll template in.

This commit is contained in:
Asherah Connor 2024-06-16 17:19:44 +03:00
parent 3e8126f5a5
commit 2679e43c02
12 changed files with 244 additions and 1 deletions

9
.editorconfig Normal file
View 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

View file

@ -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
View 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
View file

@ -0,0 +1,3 @@
__pycache__
/build
*.vcd

76
template/cxxrtl/main.cc Normal file
View 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;
}

View 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]

View file

@ -0,0 +1,3 @@
from . import NewProject
NewProject().main()

View 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

View 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
View 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"

View file

View 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()