Skip to content

Commit c1d28dd

Browse files
committed
Add configurable mtime divider
1 parent 5ec5220 commit c1d28dd

File tree

3 files changed

+65
-21
lines changed

3 files changed

+65
-21
lines changed

docs/info.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ See also [debug docs](debug.md)
5151

5252
| Register | Address | Description |
5353
| -------- | ------- | ----------- |
54+
| MTIME_DIVIDER | 0x800002C | MTIME counts at clock / (MTIME_DIVIDER + 1). Bits 0 and 1 are fixed at 1, so multiples of 4MHz are supported. |
5455
| MTIME | 0xFFFFF00 (RW) | Get/set the 1MHz time count |
5556
| MTIMECMP | 0xFFFFF04 (RW) | Get/set the time to trigger the timer interrupt |
5657

src/project.v

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module tt_um_tt_tinyQV #(parameter CLOCK_MHZ=64) (
2121
localparam PERI_GPIO_OUT_SEL = 4'h3;
2222
localparam PERI_DEBUG_UART = 4'h6;
2323
localparam PERI_DEBUG_UART_STATUS = 4'h7;
24+
localparam PERI_TIME_LIMIT = 4'hB;
2425
localparam PERI_DEBUG = 4'hC;
2526
localparam PERI_USER = 4'hF;
2627

@@ -85,6 +86,7 @@ module tt_um_tt_tinyQV #(parameter CLOCK_MHZ=64) (
8586
wire debug_uart_tx_start = write_n != 2'b11 && connect_peripheral == PERI_DEBUG_UART;
8687

8788
// Time
89+
reg [6:2] time_limit;
8890
wire time_pulse;
8991

9092
// Peripherals interface
@@ -193,6 +195,7 @@ module tt_um_tt_tinyQV #(parameter CLOCK_MHZ=64) (
193195
case (connect_peripheral)
194196
PERI_GPIO_OUT_SEL:data_from_read = {24'h0, gpio_out_sel, 6'h0};
195197
PERI_DEBUG_UART_STATUS: data_from_read = {31'h0, debug_uart_tx_busy};
198+
PERI_TIME_LIMIT: data_from_read = {25'h0, time_limit, 2'b11};
196199
PERI_USER: data_from_read = peri_data_out;
197200
default: data_from_read = 32'hFFFF_FFFF;
198201
endcase
@@ -204,9 +207,11 @@ module tt_um_tt_tinyQV #(parameter CLOCK_MHZ=64) (
204207
always @(posedge clk) begin
205208
if (!rst_reg_n) begin
206209
gpio_out_sel <= {!ui_in[0], 1'b0};
210+
time_limit <= (CLOCK_MHZ / 4 - 1);
207211
end
208212
if (write_n != 2'b11) begin
209213
if (connect_peripheral == PERI_GPIO_OUT_SEL) gpio_out_sel <= data_to_write[7:6];
214+
if (connect_peripheral == PERI_TIME_LIMIT) time_limit <= data_to_write[6:2];
210215
end
211216
end
212217

@@ -219,29 +224,17 @@ module tt_um_tt_tinyQV #(parameter CLOCK_MHZ=64) (
219224
.uart_tx_busy(debug_uart_tx_busy)
220225
);
221226

222-
reg [5:0] time_count;
223-
224-
generate
225-
if (CLOCK_MHZ == 64) begin
226-
always @(posedge clk) begin
227-
if (!rst_reg_n) begin
228-
time_count <= 0;
229-
end else begin
230-
time_count <= time_count + 1;
231-
end
232-
end
227+
reg [6:0] time_count;
228+
229+
always @(posedge clk) begin
230+
if (!rst_reg_n) begin
231+
time_count <= 0;
233232
end else begin
234-
always @(posedge clk) begin
235-
if (!rst_reg_n) begin
236-
time_count <= 0;
237-
end else begin
238-
if (time_count == (CLOCK_MHZ - 1)) time_count <= 0;
239-
else time_count <= time_count + 1;
240-
end
241-
end
233+
if (time_pulse) time_count <= 0;
234+
else time_count <= time_count + 1;
242235
end
243-
endgenerate
244-
assign time_pulse = time_count == (CLOCK_MHZ - 1);
236+
end
237+
assign time_pulse = time_count == {time_limit, 2'b11};
245238

246239
// Debug
247240
always @(posedge clk) begin

test/test.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,56 @@ async def test_timer(dut):
176176
await send_instr(dut, InstructionCSRRS(a0, x0, csrnames.mcause).encode())
177177
assert await read_reg(dut, a0) == 0x80000007
178178

179+
@cocotb.test()
180+
async def test_time_limit(dut):
181+
dut._log.info("Start")
182+
183+
clock = Clock(dut.clk, 15.624, units="ns")
184+
cocotb.start_soon(clock.start())
185+
186+
# Reset
187+
await reset(dut)
188+
189+
# Should start reading flash after 1 cycle
190+
await ClockCycles(dut.clk, 1)
191+
await start_read(dut, 0)
192+
193+
# Read time limit
194+
await send_instr(dut, InstructionLW(x1, tp, 0x2c).encode())
195+
assert await read_reg(dut, x1) == 0x3f
196+
197+
# Halve the divider, time should now advance twice as fast
198+
await send_instr(dut, InstructionADDI(x1, x0, 0x1f).encode())
199+
await send_instr(dut, InstructionSW(tp, x1, 0x2c).encode())
200+
201+
# Read time
202+
await send_instr(dut, InstructionLW(x1, x0, -0x100).encode())
203+
start_time = await read_reg(dut, x1)
204+
205+
await start_nops(dut)
206+
await Timer(5, "us")
207+
await stop_nops()
208+
209+
# Read time
210+
await send_instr(dut, InstructionLW(x1, x0, -0x100).encode())
211+
assert start_time+10 <= await read_reg(dut, x1) <= start_time+12
212+
213+
# Set divider to 96, time should advance more slowly
214+
await send_instr(dut, InstructionADDI(x1, x0, 0x5f).encode())
215+
await send_instr(dut, InstructionSW(tp, x1, 0x2c).encode())
216+
217+
# Read time
218+
await send_instr(dut, InstructionLW(x1, x0, -0x100).encode())
219+
start_time = await read_reg(dut, x1)
220+
221+
await start_nops(dut)
222+
await Timer(9, "us")
223+
await stop_nops()
224+
225+
# Read time
226+
await send_instr(dut, InstructionLW(x1, x0, -0x100).encode())
227+
assert start_time+6 <= await read_reg(dut, x1) <= start_time+8
228+
179229
@cocotb.test()
180230
async def test_csr(dut):
181231
dut._log.info("Start")

0 commit comments

Comments
 (0)