瀏覽代碼

fpga/sysclock: fix off-by-one in periodic pulse generation

H. Peter Anvin 3 年之前
父節點
當前提交
8ead1845e1
共有 1 個文件被更改,包括 26 次插入19 次删除
  1. 26 19
      fpga/sysclock.sv

+ 26 - 19
fpga/sysclock.sv

@@ -2,7 +2,7 @@
 // sysclock.sv
 //
 // Very simple unit that keeps track of time in "human" format based
-// on 32 kHz signal from the RTC. The registers have to be set from
+// on 32.768 kHz signal from the RTC. The registers have to be set from
 // software, presumably from reading the RTC.
 //
 // Register 0 contains the 2 s granular date and time in FAT filesystem format.
@@ -12,20 +12,24 @@
 // to in adcance, will write the counter when register 0 is written.
 
 module sysclock (
-		input 		  rst_n,
-		input 		  sys_clk,
-		input 		  rtc_clk,
-
-		input 		  valid,
-		input  	  	  addr,
-		output reg [31:0] rdata,
-		input [31:0] 	  wdata,
-		input [3:0] 	  wstrb
+		 input		   rst_n,
+		 input		   sys_clk,
+		 input		   rtc_clk,
+
+		 input		   valid,
+		 input		   addr,
+		 output reg [31:0] rdata,
+		 input [31:0]	   wdata,
+		 input [3:0]	   wstrb,
+
+		 output		   periodic
 		);
 
+   parameter PERIODIC_HZ_LG2 = 5;
+
    wire		rtc_clk_sync;
-   reg 		rtc_clk_q;
-   reg 		rtc_clk_stb;
+   reg		rtc_clk_q;
+   reg		rtc_clk_stb;
 
    synchronizer rtc_sync (
 			  .rst_n ( 1'b1 ),
@@ -63,16 +67,16 @@ module sysclock (
 
    function logic [7:0] tick(input [7:0] me,
 			     input [7:0] start,
-			     input 	 wrap_pre,
-			     input 	 wrap_me);
-      
+			     input	 wrap_pre,
+			     input	 wrap_me);
+
       tick = wrap_me ? start : me + wrap_pre;
    endfunction // tick
 
    // Counter read/writes holding register
    reg [15:0] tm_hold;
    reg [ 1:0] tm_whold;		// Byte enables for hold register
-   
+
    reg [15:0] tm_tick;
    reg [31:0] tm_dt;		// Day and time in FAT filesystem format
 
@@ -83,7 +87,7 @@ module sysclock (
    wire [4:0] tm_mday = tm_dt[20:16];
    wire [3:0] tm_mon  = tm_dt[24:21];
    wire [6:0] tm_year = tm_dt[31:25];
-   
+
    wire wrap_tick = rtc_clk_stb & |tm_tick;
    wire wrap_sec  = wrap_tick & (tm_2sec >= 5'd29);
    wire wrap_min  = wrap_sec  & (tm_min  >= 6'd59);
@@ -91,6 +95,9 @@ module sysclock (
    wire wrap_mday = wrap_hour & (tm_mday >= maxday(tm_mon, tm_year));
    wire wrap_mon  = wrap_mday & (tm_mon  >= 4'd12);
 
+   // Yes, it may jump if the counter is written...
+   assign periodic = tm_tick[14 - PERIODIC_HZ_LG2];
+
    always @(posedge sys_clk)
      begin
 	tm_tick      <= tm_tick + rtc_clk_stb;
@@ -114,7 +121,7 @@ module sysclock (
 	       if (wstrb[1]) tm_dt[15:8]  <= wdata[15:8];
 	       if (wstrb[2]) tm_dt[23:16] <= wdata[23:16];
 	       if (wstrb[3]) tm_dt[31:24] <= wdata[31:24];
-	    
+
 	       if (tm_whold[0]) tm_tick[7:0]  <= tm_hold[7:0];
 	       if (tm_whold[1]) tm_tick[15:8] <= tm_hold[15:8];
 	       tm_hold  <= tm_tick;
@@ -137,5 +144,5 @@ module sysclock (
        1'b0: rdata = tm_dt;
        1'b1: rdata = { tm_tick, tm_hold };
      endcase // case (addr)
-	
+
 endmodule // sysclock