Skip to content

Commit d63c17f

Browse files
committed
implement pat for the watchdog and two basic tests
1 parent f49ee09 commit d63c17f

File tree

2 files changed

+107
-34
lines changed

2 files changed

+107
-34
lines changed

src/peripheral.v

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,37 @@ module tqvp_stevej_watchdog (
4343
window_close <= 32'b0;
4444
watchdog_enabled <= 1'b0;
4545
pat <= 1'b0;
46+
saw_pat <= 1'b0;
47+
timer <= 0;
4648
end else begin
4749
if (address == 6'h0) begin // Address 0 is ENABLE
4850
if (data_write_n != 2'b11) watchdog_enabled <= data_in[0];
4951
end
5052

53+
if (address == 6'h1) begin // Address 1 is WINDOW_START
54+
if (data_write_n != 2'b11) window_start <= data_in;
55+
end
56+
57+
if (address == 6'h2) begin // Address 2 is WINDOW_CLOSE
58+
if (data_write_n != 2'b11) window_close <= data_in;
59+
end
60+
61+
if (address == 6'h3) begin // Address 3 is PAT
62+
if (data_write_n != 2'b11) begin
63+
saw_pat <= 1;
64+
timer <= 0;
65+
end
66+
end else begin
67+
saw_pat <= 0;
68+
end
69+
5170
if (!timer_expired) begin
5271
timer <= timer + 1;
53-
end else if (data_in[0]) begin
54-
// the watchdog is being patted so reset the timer.
55-
timer <= 0;
56-
// register output that we've seen a pat.
57-
saw_pat <= 1;
58-
end else if (!data_in[0]) begin
59-
saw_pat <= 0;
6072
end
6173

6274
end
6375
end
76+
6477
reg [31:0] example_data;
6578
wire timer_expired;
6679
reg [31:0] timer;
@@ -73,10 +86,21 @@ module tqvp_stevej_watchdog (
7386
assign interrupt_high = timer_expired;
7487
assign interrupt_low = !timer_expired;
7588
assign user_interrupt = interrupt_high;
76-
assign uo_out = {interrupt_high, interrupt_low, saw_pat, 5'b0_0000};
77-
78-
// Unused
79-
assign data_out = 32'h0;
89+
assign uo_out = {interrupt_high, interrupt_low, saw_pat, watchdog_enabled, 4'b0000};
90+
91+
// Addresses
92+
// 0x0: Enabled
93+
// 0x1: WINDOW_OPEN
94+
// 0x2: WINDOW_CLOSE
95+
// 0x3: PAT
96+
// 0x4: reflects ui_in
97+
// Default: 0
98+
assign data_out = (address == 6'h0) ? {31'h0, watchdog_enabled} :
99+
(address == 6'h1) ? window_start :
100+
(address == 6'h2) ? window_close :
101+
(address == 6'h3) ? {31'h0, saw_pat} :
102+
(address == 6'h4) ? {24'h0, ui_in} :
103+
32'h0;
80104

81105
// All reads complete in 1 clock
82106
assign data_ready = 1;
@@ -100,7 +124,6 @@ module tqvp_stevej_watchdog (
100124
f_past_valid <= 1'b1;
101125
end
102126

103-
104127
always @(posedge clk) begin
105128
if (f_past_valid) begin
106129
// the timer can only expire if the watchdog is enabled

test/test.py

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from tqv import TinyQV
99

1010
@cocotb.test()
11-
async def test_project(dut):
11+
async def test_enabled_without_window(dut):
1212
dut._log.info("Start")
1313

1414
# Set the clock period to 100 ns (10 MHz)
@@ -27,11 +27,11 @@ async def test_project(dut):
2727

2828
dut._log.info("Test project behavior")
2929

30-
# Test register write and read back
31-
await tqv.write_word_reg(0, 0x12345678)
32-
assert await tqv.read_byte_reg(0) == 0x78
33-
assert await tqv.read_hword_reg(0) == 0x5678
34-
assert await tqv.read_word_reg(0) == 0x12345678
30+
# Test enabling watchdog timer by writing to interrupt.
31+
await tqv.write_word_reg(0, 0x1)
32+
assert await tqv.read_byte_reg(0) == 0x1
33+
assert await tqv.read_hword_reg(0) == 0x1
34+
assert await tqv.read_word_reg(0) == 0x1
3535

3636
# Set an input value, in the example this will be added to the register value
3737
dut.ui_in.value = 30
@@ -40,19 +40,10 @@ async def test_project(dut):
4040
# and a further clock is required for the output to propagate.
4141
await ClockCycles(dut.clk, 3)
4242

43-
# The following assersion is just an example of how to check the output values.
44-
# Change it to match the actual expected output of your module:
45-
assert dut.uo_out.value == 0x96
43+
assert dut.uo_out.value == 0b1001_0000
4644

47-
# Input value should be read back from register 1
48-
assert await tqv.read_byte_reg(4) == 30
49-
50-
# Zero should be read back from register 2
51-
assert await tqv.read_word_reg(8) == 0
52-
53-
# A second write should work
54-
await tqv.write_word_reg(0, 40)
55-
assert dut.uo_out.value == 70
45+
# Input value of 0 should be read back from register 1 as it was never set.
46+
assert await tqv.read_byte_reg(1) == 0
5647

5748
# Test the interrupt, generated when ui_in[6] goes high
5849
dut.ui_in[6].value = 1
@@ -66,7 +57,66 @@ async def test_project(dut):
6657
# Interrupt doesn't clear
6758
await ClockCycles(dut.clk, 10)
6859
assert dut.uio_out[0].value == 1
69-
70-
# Write bottom bit of address 8 high to clear
71-
await tqv.write_byte_reg(8, 1)
72-
assert dut.uio_out[0].value == 0
60+
61+
62+
# Test that enabling the watchdog timer with a WINDOW_CLOSE of results in a set watchdog
63+
@cocotb.test()
64+
async def test_enabled_with_window_close(dut):
65+
dut._log.info("Start")
66+
67+
# Set the clock period to 100 ns (10 MHz)
68+
clock = Clock(dut.clk, 100, units="ns")
69+
cocotb.start_soon(clock.start())
70+
71+
# Interact with your design's registers through this TinyQV class.
72+
# This will allow the same test to be run when your design is integrated
73+
# with TinyQV - the implementation of this class will be replaces with a
74+
# different version that uses Risc-V instructions instead of the SPI
75+
# interface to read and write the registers.
76+
tqv = TinyQV(dut)
77+
# Reset
78+
await tqv.reset()
79+
80+
dut._log.info("Test project behavior")
81+
# Test writing 10 to WATCHDOG_CLOSE register
82+
await tqv.write_word_reg(1, 0xA)
83+
84+
# Test enabling watchdog timer by writing to interrupt.
85+
await tqv.write_word_reg(0, 0x1)
86+
87+
await ClockCycles(dut.clk, 5)
88+
# watchdog has been enabled, no pat seen, timer not expired
89+
assert dut.uo_out.value == 0b01010000
90+
91+
# Test that enabling the watchdog timer with a WINDOW_CLOSE of 10 results in an expired timer in 10 cycles.
92+
@cocotb.test()
93+
async def test_enabled_with_window_close(dut):
94+
dut._log.info("Start")
95+
96+
# Set the clock period to 100 ns (10 MHz)
97+
clock = Clock(dut.clk, 100, units="ns")
98+
cocotb.start_soon(clock.start())
99+
100+
# Interact with your design's registers through this TinyQV class.
101+
# This will allow the same test to be run when your design is integrated
102+
# with TinyQV - the implementation of this class will be replaces with a
103+
# different version that uses Risc-V instructions instead of the SPI
104+
# interface to read and write the registers.
105+
tqv = TinyQV(dut)
106+
# Reset
107+
await tqv.reset()
108+
109+
dut._log.info("Test project behavior")
110+
# Test writing 10 to WATCHDOG_CLOSE register
111+
await tqv.write_word_reg(1, 0xA)
112+
113+
# Test enabling watchdog timer by writing to interrupt.
114+
await tqv.write_word_reg(0, 0x1)
115+
116+
await ClockCycles(dut.clk, 10)
117+
# watchdog has been enabled, no pat seen, timer expired
118+
assert dut.uo_out.value == 0b10010000
119+
120+
121+
# Test that enabling the watchdog timer with a WINDOW_OPEN of 5 and a WINDOW_CLOSE of 10 doesn't
122+
# trigger outside the window but does trigger inside the window.

0 commit comments

Comments
 (0)