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