Remove unused/untested RISC-V timer implementation
This commit is contained in:
parent
ea2b8888a4
commit
11596a5bd7
|
@ -1 +0,0 @@
|
|||
file hazard3_riscv_timer.v
|
|
@ -1,164 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| Copyright (C) 2021-2022 Luke Wren |
|
||||
| SPDX-License-Identifier: Apache-2.0 |
|
||||
\*****************************************************************************/
|
||||
|
||||
// Implementation of standard RISC-V timer (mtime/mtimeh mtimecmp/mtimecmph)
|
||||
// accessed over 32-bit data bus.
|
||||
//
|
||||
// This is written for minimal area on FPGA -- in particular, it uses 64-bit
|
||||
// serial increment and compare -- so is not the best solution for less
|
||||
// resource-constrained platforms, because it can't count faster than once
|
||||
// per 64 cycles, and bus accesses can be delayed for up to 63 timer ticks
|
||||
// whilst the serial counter rotates to the correct bus alignment. The serial
|
||||
// operations are also quite energy-intensive.
|
||||
//
|
||||
// Tie tick high for a 64-cycle timebase. tick must be free-running, i.e. must
|
||||
// not be held low indefinitely, because this would also halt the serial
|
||||
// mtimecmp comparison. To pause the timer due to an external event, assert
|
||||
// dbg_halt high. To pause from software, write 0 to CTRL.EN.
|
||||
|
||||
`default_nettype none
|
||||
|
||||
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 reg pready,
|
||||
output wire pslverr,
|
||||
|
||||
input wire dbg_halt,
|
||||
|
||||
input wire tick,
|
||||
|
||||
output reg timer_irq
|
||||
);
|
||||
|
||||
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 bus_write = pwrite && psel && penable && pready;
|
||||
|
||||
reg ctrl_en;
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
ctrl_en <= 1'b1;
|
||||
end else if (bus_write && paddr == ADDR_CTRL) begin
|
||||
ctrl_en <= pwdata[0];
|
||||
end
|
||||
end
|
||||
|
||||
wire tick_and_increment = ctrl_en && !dbg_halt && tick;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// mtime and serial increment
|
||||
|
||||
// Increment takes place over the course of 64 ticks. The mtime register is
|
||||
// constantly rotating to bring a new serial bit into position 0.
|
||||
|
||||
reg [5:0] serial_ctr;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
serial_ctr <= 6'h00;
|
||||
end else if (tick) begin
|
||||
serial_ctr <= serial_ctr + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
reg [63:0] mtime;
|
||||
reg mtime_carry;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mtime <= 64'h0;
|
||||
mtime_carry <= 1'b1;
|
||||
end else begin
|
||||
if (tick) begin
|
||||
if (tick_and_increment) begin
|
||||
{mtime_carry, mtime[63]} <= mtime_carry + mtime[0];
|
||||
mtime[62:0] <= mtime[63:1];
|
||||
end else begin
|
||||
// Still keep rotating the register, so writes can take place,
|
||||
// and so we can continuously compare with mtimecmp.
|
||||
mtime <= {mtime[0], mtime[63:1]};
|
||||
end
|
||||
// Preload carry for increment
|
||||
if (serial_ctr == 6'h3f)
|
||||
mtime_carry <= 1'b1;
|
||||
end
|
||||
// Only the lower half is written; pready is driven so that the write
|
||||
// occurs at the correct time and hence bit-alignment.
|
||||
if (bus_write && (paddr == ADDR_MTIME || paddr == ADDR_MTIMEH))
|
||||
mtime[31:0] <= pwdata;
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// mtimecmp and serial comparison
|
||||
|
||||
// The timer IRQ is only updated every 64 ticks, when we finish a new
|
||||
// comparison. This is permitted by the RISC-V privileged spec: before
|
||||
// returning, the IRQ handler should poll mtip until it sees the IRQ
|
||||
// deassert.
|
||||
|
||||
reg [63:0] mtimecmp;
|
||||
reg mtimecmp_borrow;
|
||||
|
||||
wire mtimecmp_borrow_next =
|
||||
(!mtime[0] && (mtimecmp[0] || mtimecmp_borrow))
|
||||
|| (mtimecmp[0] && mtimecmp_borrow);
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mtimecmp <= 64'h0;
|
||||
mtimecmp_borrow <= 1'b0;
|
||||
timer_irq <= 1'b0;
|
||||
end else begin
|
||||
// Serially subtract mtimecmp from mtime. If there is no borrow from
|
||||
// bit 63 (i.e. if mtime was greater or equal) then assert IRQ.
|
||||
if (tick) begin
|
||||
mtimecmp_borrow <= mtimecmp_borrow_next;
|
||||
mtimecmp <= {mtimecmp[0], mtimecmp[63:1]};
|
||||
if (serial_ctr == 6'h3f) begin
|
||||
mtimecmp_borrow <= 1'b0;
|
||||
timer_irq <= !mtimecmp_borrow_next;
|
||||
end
|
||||
end
|
||||
if (bus_write && (paddr == ADDR_MTIMECMP || paddr == ADDR_MTIMECMPH))
|
||||
mtimecmp[31:0] <= pwdata;
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Bus read mux
|
||||
|
||||
// Only the lower half of each 64-bit counter register is exposed to the bus,
|
||||
// using the serial counter to make sure the correct bits are aligned with
|
||||
// the bus window at the point the bus access finishes. Note pready is only
|
||||
// valid during the access phase (& is ignored during setup phase).
|
||||
|
||||
always @ (*) case (paddr)
|
||||
ADDR_CTRL: begin prdata = {{W_DATA-1{1'b0}}, ctrl_en}; pready = 1'b1; end
|
||||
ADDR_MTIME: begin prdata = mtime[31:0]; pready = serial_ctr == 6'h00; end
|
||||
ADDR_MTIMEH: begin prdata = mtime[31:0]; pready = serial_ctr == 6'h20; end
|
||||
ADDR_MTIMECMP: begin prdata = mtimecmp[31:0]; pready = serial_ctr == 6'h00; end
|
||||
ADDR_MTIMECMPH: begin prdata = mtimecmp[31:0]; pready = serial_ctr == 6'h20; end
|
||||
default: begin prdata = {W_DATA{1'b0}}; pready = 1'b1; end
|
||||
endcase
|
||||
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
Loading…
Reference in New Issue