Skip to content

Commit b0b8b85

Browse files
committed
Encoder not working yet
1 parent d203305 commit b0b8b85

5 files changed

Lines changed: 101 additions & 34 deletions

File tree

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,19 @@ This project leverages the Amaranth HDL to test a particle detector ASIC design.
1818

1919
## Getting Started
2020

21+
You first need install Lattice iCE40 toolchain (yosys, nextpnr, icestorm) and iverilog for simulation. On Fedora, you can install them using:
22+
```bash
23+
sudo dnf install iverilog icestorm yosys nextpnr python3-pip
24+
```
25+
26+
You can also have a look to the [OSS CAD Suite](https://github.com/YosysHQ/oss-cad-suite-build) project, which provides pre-built toolchain binaries for various platforms.
27+
2128
1. Clone the repository:
2229
```bash
2330
git clone <repository_url>
2431
cd ASIC_Counter
2532
```
26-
2. Install dependencies using uv:
33+
2. Install python dependencies using uv:
2734
```bash
2835
uv venv
2936
uv pip install -e .[dev]

asic_counter/protocol.py

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,40 +67,47 @@ def __init__(self):
6767
self.data_in = Signal(8)
6868
self.in_rdy = Signal()
6969
self.in_ack = Signal()
70+
self.eof = Signal()
71+
72+
self.uart_data_out = Signal(8)
73+
self.uart_rdy = Signal()
74+
self.uart_ack = Signal()
7075

71-
self.data_out = Signal(8)
72-
self.out_rdy = Signal()
73-
self.out_ack = Signal()
7476

7577
def elaborate(self, platform):
7678
m = Module()
7779

78-
# For simplicity, we just output the command and value when out_rdy is high
7980
with m.FSM(init="Idle") as fsm:
8081
with m.State("Idle"):
81-
with m.If(self.out_rdy & self.in_rdy):
82-
m.d.sync += self.data_out.eq(0xA5) # Start word
82+
with m.If(self.uart_rdy & self.in_ack):
83+
m.d.sync += self.uart_data_out.eq(0xA5) # Start word
84+
m.d.sync += self.uart_ack.eq(1)
8385
m.next = "Second start word"
86+
with m.Else():
87+
m.d.sync += self.uart_ack.eq(0)
88+
m.d.sync += self.in_rdy.eq(self.uart_rdy)
8489
with m.State("Second start word"):
85-
with m.If(self.out_ack):
86-
m.d.sync += self.data_out.eq(0x0F) # Second start word
87-
m.next = "Output second start word"
88-
with m.State("Output second start word"):
89-
with m.If(self.out_ack):
90-
# For simplicity, we just output a fixed command and value
91-
m.d.sync += self.data_out.eq(0b101) # Command
92-
m.next = "Output command"
93-
with m.State("Output command"):
94-
with m.If(self.out_ack):
95-
m.d.sync += self.data_out.eq(0x34) # Value LSB
96-
m.next = "Output value LSB"
97-
with m.State("Output value LSB"):
98-
with m.If(self.out_ack):
99-
m.d.sync += self.data_out.eq(0x12) # Value MSB
100-
m.next = "Output value MSB"
101-
with m.State("Output value MSB"):
102-
with m.If(self.out_ack):
103-
m.d.sync += self.out_rdy.eq(0) # Done
90+
with m.If(self.uart_rdy & self.in_ack):
91+
m.d.sync += self.uart_data_out.eq(0x0F) # Second start word
92+
m.next = "Output values"
93+
with m.Else():
94+
m.d.sync += self.uart_ack.eq(0)
95+
m.d.sync += self.in_rdy.eq(self.uart_rdy)
96+
with m.State("Output values"):
97+
with m.If(self.uart_rdy & self.in_ack):
98+
m.d.sync += self.uart_data_out.eq(self.data_in)
99+
with m.Else():
100+
m.d.sync += self.uart_ack.eq(0)
101+
m.d.sync += self.in_rdy.eq(self.uart_rdy)
102+
with m.If(self.eof):
103+
m.next = "EOF"
104+
with m.State("EOF"):
105+
m.d.sync += self.uart_data_out.eq(0xFF) # EOF marker
106+
with m.If(self.uart_rdy & self.in_ack):
107+
m.d.sync += self.uart_ack.eq(1)
104108
m.next = "Idle"
109+
with m.Else():
110+
m.d.sync += self.uart_ack.eq(0)
111+
m.d.sync += self.in_rdy.eq(self.uart_rdy)
105112

106113
return m

asic_counter/test_runner.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
from cocotb_test.simulator import run as _run
2+
from cocotb.triggers import RisingEdge
23
from amaranth.back import verilog
34
from amaranth import Signal
45
from tempfile import NamedTemporaryFile
56
import inspect
67
import os
78

9+
async def reset_dut(dut):
10+
dut.rst.value = 1
11+
for _ in range(5):
12+
await RisingEdge(dut.clk)
13+
dut.rst.value = 0
14+
for _ in range(5):
15+
await RisingEdge(dut.clk)
16+
817
def find_dut_ports(dut):
918
# Heuristic: look for Signals that are not internal (e.g., not starting with "_")
1019
ports = []
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,9 @@
22

33
from cocotb.triggers import Timer, RisingEdge
44
from cocotb.clock import Clock
5-
from asic_counter.test_runner import run_cocotb
5+
from asic_counter.test_runner import run_cocotb, reset_dut
66
from asic_counter.protocol import Decoder
77

8-
async def reset_dut(dut):
9-
dut.rst.value = 1
10-
for _ in range(5):
11-
await RisingEdge(dut.clk)
12-
dut.rst.value = 0
13-
for _ in range(5):
14-
await RisingEdge(dut.clk)
158

169
async def send_cmd(dut, cmd, value):
1710
# Send start sequence

tests/encoder/test_encoder.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import cocotb
2+
3+
from cocotb.triggers import Timer, RisingEdge
4+
from cocotb.clock import Clock
5+
from asic_counter.test_runner import run_cocotb, reset_dut
6+
from asic_counter.protocol import Encoder
7+
8+
class FakeUART:
9+
def __init__(self, dut:Encoder):
10+
self.dut:Encoder = dut
11+
self.data = []
12+
self.dut.uart_rdy.value = 1
13+
self.task = cocotb.start_soon(self.send())
14+
15+
async def send(self):
16+
self.dut.uart_rdy.value = 1
17+
while True:
18+
if self.dut.uart_ack.value == 0:
19+
await RisingEdge(self.dut.uart_ack)
20+
self.dut.uart_rdy.value = 0
21+
self.data.append(int(self.dut.uart_data_out.value))
22+
await Timer(100, units="ns") # Simulate some delay for the UART to process the data
23+
self.dut.uart_rdy.value = 1
24+
25+
async def send_data(dut:Encoder, values):
26+
dut.in_ack.value = 1
27+
for value in values:
28+
if dut.in_rdy.value == 0:
29+
await dut.in_rdy.rising_edge
30+
dut.data_in.value = value
31+
await RisingEdge(dut.clk)
32+
await RisingEdge(dut.clk)
33+
dut.eof.value = 1
34+
await RisingEdge(dut.clk)
35+
dut.in_ack.value = 0
36+
37+
38+
@cocotb.test()
39+
async def test_protocol_simple_cmds(dut:Encoder):
40+
# Drive inputs (Amaranth signals become Verilog ports)
41+
clk_gen = cocotb.start_soon(Clock(dut.clk, 1000 // 12, units="ns").start())
42+
dut.in_ack.value = 0
43+
dut.eof.value = 0
44+
await reset_dut(dut)
45+
uart = FakeUART(dut)
46+
await send_data(dut, values=[1, 2, 3, 4])
47+
await RisingEdge(dut.clk)
48+
49+
50+
def broken_test_protocol():
51+
run_cocotb(Encoder)

0 commit comments

Comments
 (0)