First pass at a 64-bit system timer
This commit is contained in:
parent
924967ee72
commit
4aba165166
|
@ -0,0 +1,2 @@
|
|||
file hazard3_riscv_timer.v
|
||||
file ../debug/cdc/hazard3_sync_1bit.v
|
|
@ -0,0 +1,120 @@
|
|||
/**********************************************************************
|
||||
* DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE *
|
||||
* Version 3, April 2008 *
|
||||
* *
|
||||
* Copyright (C) 2021 Luke Wren *
|
||||
* *
|
||||
* Everyone is permitted to copy and distribute verbatim or modified *
|
||||
* copies of this license document and accompanying software, and *
|
||||
* changing either is allowed. *
|
||||
* *
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION *
|
||||
* *
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO. *
|
||||
* 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. *
|
||||
* *
|
||||
*********************************************************************/
|
||||
|
||||
// Implementation of standard RISC-V timer (mtime/mtimeh mtimecmp/mtimecmph)
|
||||
// accessed over 32-bit data bus. Ticks on both edges of tick_nrz, which is
|
||||
// provided by some external timebase, and is assumed to be asynchronous to
|
||||
// clk. Nothing fancy, just a simple implementation of the spec.
|
||||
|
||||
module hazard3_riscv_timer (
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
input wire psel,
|
||||
input wire penable,
|
||||
input wire pwrite,
|
||||
input wire [7:0] paddr,
|
||||
input wire [31:0] pwdata,
|
||||
output reg [31:0] prdata,
|
||||
output wire pready,
|
||||
output wire pslverr,
|
||||
|
||||
input wire dbg_halt,
|
||||
input wire tick_nrz,
|
||||
|
||||
output reg timer_irq
|
||||
);
|
||||
|
||||
wire bus_write = pwrite && psel && penable;
|
||||
wire bus_read = !pwrite && psel && penable;
|
||||
|
||||
localparam W_ADDR = 8;
|
||||
localparam W_DATA = 32;
|
||||
|
||||
localparam ADDR_CTRL = 8'h00;
|
||||
localparam ADDR_MTIME = 8'h08;
|
||||
localparam ADDR_MTIMEH = 8'h0c;
|
||||
localparam ADDR_MTIMECMP = 8'h10;
|
||||
localparam ADDR_MTIMECMPH = 8'h14;
|
||||
|
||||
wire tick_nrz_sync;
|
||||
|
||||
hazard3_sync_1bit tick_sync_u (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.i (tick_nrz),
|
||||
.o (tick_nrz_sync)
|
||||
);
|
||||
|
||||
reg tick_nrz_prev;
|
||||
always @ (posedge clk or negedge rst_n)
|
||||
if (!rst_n)
|
||||
tick_nrz_prev <= 1'b0;
|
||||
else
|
||||
tick_nrz_prev <= tick_nrz_sync;
|
||||
|
||||
reg ctrl_en;
|
||||
always @ (posedge clk or negedge rst_n)
|
||||
if (!rst_n)
|
||||
ctrl_en <= 1'b1;
|
||||
else if (bus_write && paddr == ADDR_CTRL)
|
||||
ctrl_en <= pwdata[0];
|
||||
|
||||
wire tick = ctrl_en && !dbg_halt && tick_nrz_prev != tick_nrz_sync;
|
||||
|
||||
reg [63:0] mtime;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mtime <= 64'h0;
|
||||
end else begin
|
||||
if (tick)
|
||||
mtime <= mtime + 1'b1;
|
||||
if (bus_write && paddr == ADDR_MTIME)
|
||||
mtime[31:0] <= pwdata;
|
||||
if (bus_write && paddr == ADDR_MTIMEH)
|
||||
mtime[63:32] <= pwdata;
|
||||
end
|
||||
end
|
||||
|
||||
reg [63:0] mtimecmp;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mtimecmp <= 64'h0;
|
||||
timer_irq <= 1'b0;
|
||||
end else begin
|
||||
if (bus_write && paddr == ADDR_MTIMECMP)
|
||||
mtimecmp[31:0] <= pwdata;
|
||||
if (bus_write && paddr == ADDR_MTIMECMPH)
|
||||
mtimecmp[63:32] <= pwdata;
|
||||
timer_irq <= mtime >= mtimecmp; // oof
|
||||
end
|
||||
end
|
||||
|
||||
always @ (*) begin
|
||||
case (paddr)
|
||||
ADDR_CTRL: prdata = {{W_DATA-1{1'b0}}, ctrl_en};
|
||||
ADDR_MTIME: prdata = mtime[31:0];
|
||||
ADDR_MTIMEH: prdata = mtime[63:32];
|
||||
ADDR_MTIMECMP: prdata = mtimecmp[31:0];
|
||||
ADDR_MTIMECMPH: prdata = mtimecmp[63:32];
|
||||
default: prdata = {W_DATA{1'b0}};
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue