Convert timer to serial for smaller area. Rather untested
This commit is contained in:
parent
4aba165166
commit
b99e5b8a67
|
@ -39,8 +39,7 @@ module hazard3_riscv_timer (
|
|||
output reg timer_irq
|
||||
);
|
||||
|
||||
wire bus_write = pwrite && psel && penable;
|
||||
wire bus_read = !pwrite && psel && penable;
|
||||
wire bus_write = pwrite && psel && penable && pready;
|
||||
|
||||
localparam W_ADDR = 8;
|
||||
localparam W_DATA = 32;
|
||||
|
@ -74,46 +73,85 @@ always @ (posedge clk or negedge rst_n)
|
|||
else if (bus_write && paddr == ADDR_CTRL)
|
||||
ctrl_en <= pwdata[0];
|
||||
|
||||
wire tick = ctrl_en && !dbg_halt && tick_nrz_prev != tick_nrz_sync;
|
||||
wire tick = tick_nrz_prev != tick_nrz_sync;
|
||||
wire tick_and_increment = ctrl_en && !dbg_halt && tick;
|
||||
|
||||
// The 64-bit TIME and TIMECMP registers are processed serially, over the
|
||||
// course of 64 cycles.
|
||||
|
||||
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)
|
||||
mtime <= mtime + 1'b1;
|
||||
if (bus_write && paddr == ADDR_MTIME)
|
||||
if (tick) begin
|
||||
if (tick_and_increment) begin
|
||||
// Serially increment mtime
|
||||
{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;
|
||||
if (bus_write && paddr == ADDR_MTIMEH)
|
||||
mtime[63:32] <= pwdata;
|
||||
end
|
||||
end
|
||||
|
||||
reg [63:0] mtimecmp;
|
||||
reg mtimecmp_borrow;
|
||||
|
||||
wire mtimecmp_borrow_next = (!mtimecmp[0] && (mtime[0] || mtimecmp_borrow)) || (mtime[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
|
||||
if (bus_write && paddr == ADDR_MTIMECMP)
|
||||
// Serially subtract mtime from mtimecmp. If there is no borrow from
|
||||
// bit 63 (i.e. if mtimecmp 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;
|
||||
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}};
|
||||
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[63:32]; pready = serial_ctr == 6'h20; end
|
||||
default: begin prdata = {W_DATA{1'b0}}; pready = 1'b1; end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue