Skip to content

Commit 0a9aff8

Browse files
committed
Add a simple cocotb example
This commit adds an example that uses the Cocotb framework to validate behavior of the Verilog file converted from a simple DSLX code Internal-tag: [#46586] Signed-off-by: Robert Winkler <rwinkler@antmicro.com>
1 parent 0d26baa commit 0a9aff8

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

xls/examples/cocotb/BUILD

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2023 The XLS Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
load("@rules_hdl//cocotb:cocotb.bzl", "cocotb_test")
16+
load("@xls_pip_deps//:requirements.bzl", "requirement")
17+
load("//xls/build_rules:xls_build_defs.bzl", "xls_dslx_verilog")
18+
19+
xls_dslx_verilog(
20+
name = "running_counter_verilog",
21+
srcs = ["running_counter.x"],
22+
deps = [],
23+
codegen_args = {
24+
"delay_model": "unit",
25+
"clock_period_ps": "5000",
26+
"reset": "rst",
27+
"module_name": "RunningCounter",
28+
"use_system_verilog": "false",
29+
"streaming_channel_data_suffix": "_data",
30+
},
31+
dslx_top = "RunningCounter",
32+
verilog_file = "running_counter.v",
33+
)
34+
35+
cocotb_test(
36+
name = "running_counter_cocotb",
37+
hdl_toplevel = "RunningCounter",
38+
hdl_toplevel_lang = "verilog",
39+
test_module = [
40+
"cocotb_running_counter.py",
41+
],
42+
verilog_sources = [
43+
"timescale.v",
44+
"dumpvcd.v",
45+
":running_counter.v",
46+
],
47+
deps = [
48+
requirement("cocotb"),
49+
requirement("cocotb_bus"),
50+
"//xls/simulation/cocotb:cocotb_xls",
51+
],
52+
)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright 2023 The XLS Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import cocotb
16+
17+
from cocotb.clock import Clock
18+
from cocotb.triggers import Event, ClockCycles
19+
from cocotb.binary import BinaryValue
20+
21+
from cocotb_bus.scoreboard import Scoreboard
22+
from cocotb_xls import XLSChannelDriver, XLSChannelMonitor
23+
24+
from typing import List, Any
25+
26+
27+
def list_to_binary_value(data: List, n_bits: int = 32, bigEndian=False) -> List[BinaryValue]:
28+
return [BinaryValue(x, n_bits, bigEndian) for x in data]
29+
30+
31+
def init_sim(dut, data_to_send: List[BinaryValue], data_to_recv: List[BinaryValue]):
32+
clock = Clock(dut.clk, 10, units="us")
33+
34+
driver = XLSChannelDriver(dut, "running_counter__base_r", dut.clk)
35+
monitor = XLSChannelMonitor(dut, "running_counter__cnt_s", dut.clk)
36+
37+
scoreboard = Scoreboard(dut, fail_immediately=True)
38+
scoreboard.add_interface(monitor, data_to_recv)
39+
40+
total_of_packets = len(data_to_recv)
41+
terminate = Event("Last packet of data received")
42+
43+
def terminate_cb(transaction):
44+
if monitor.stats.received_transactions == total_of_packets:
45+
terminate.set()
46+
47+
monitor.add_callback(terminate_cb)
48+
monitor.bus.rdy.setimmediatevalue(1)
49+
50+
return (clock, driver, terminate)
51+
52+
53+
@cocotb.coroutine
54+
async def reset(clk, rst, cycles=1):
55+
rst.setimmediatevalue(1)
56+
await ClockCycles(clk, cycles)
57+
rst.value = 0
58+
59+
60+
@cocotb.test(timeout_time=10, timeout_unit="ms")
61+
async def counter_test(dut):
62+
data_to_send = list_to_binary_value([0x100, 0x100, 0x100])
63+
data_to_recv = list_to_binary_value([0x102, 0x103, 0x104])
64+
65+
(clock, driver, terminate) = init_sim(dut, data_to_send, data_to_recv)
66+
67+
cocotb.start_soon(clock.start())
68+
await reset(dut.clk, dut.rst, 10)
69+
await driver.write(data_to_send)
70+
await terminate.wait()

xls/examples/cocotb/dumpvcd.v

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2023 The XLS Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
module wavedump();
16+
initial begin
17+
$dumpfile("dump.vcd");
18+
$dumpvars(0, RunningCounter);
19+
end
20+
endmodule

xls/examples/cocotb/running_counter.x

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2023 The XLS Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import std
16+
17+
proc RunningCounter {
18+
base_r: chan<u32> in;
19+
cnt_s: chan<u32> out;
20+
21+
init { u32:0 }
22+
23+
config(base_r: chan<u32> in, cnt_s: chan<u32> out) {
24+
(base_r, cnt_s)
25+
}
26+
27+
next(tok: token, cnt: u32) {
28+
let (tok, base, base_valid) = recv_non_blocking(tok, base_r, u32:0);
29+
let tok = send_if(tok, cnt_s, base_valid, cnt + base);
30+
let cnt_next = cnt + u32:1;
31+
cnt_next
32+
}
33+
}
34+
35+
#[test_proc]
36+
proc RunningCounterTester {
37+
terminator: chan<bool> out;
38+
base_s: chan<u32> out;
39+
cnt_r: chan<u32> in;
40+
41+
init { u32:0 }
42+
43+
config (terminator: chan<bool> out) {
44+
let (base_s, base_r) = chan<u32>;
45+
let (cnt_s, cnt_r) = chan<u32>;
46+
47+
spawn RunningCounter(base_r, cnt_s);
48+
(terminator, base_s, cnt_r)
49+
}
50+
51+
next(tok: token, recv_cnt: u32) {
52+
let next_state = if (recv_cnt < u32:10) {
53+
let tok = send(tok, base_s, u32:1);
54+
let (tok, cnt) = recv(tok, cnt_r);
55+
56+
trace_fmt!("Received {} cnt", recv_cnt);
57+
assert_lt(u32:1, cnt);
58+
59+
recv_cnt + u32:1
60+
} else {
61+
send(tok, terminator, true);
62+
u32:0
63+
};
64+
65+
(next_state)
66+
}
67+
}

0 commit comments

Comments
 (0)