Kaynağa Gözat

fpga/max80: 32 kHz RTC clock isn't working, workaround

The 32 kHz RTC clock is an open drain signal, but there is no
pull-up, and because it feeds a clock pin the FPGA doesn't have one to
offer.

Substitute a clock divider from the 84 MHz system clock.
H. Peter Anvin 3 yıl önce
ebeveyn
işleme
7c6cbc57c6
1 değiştirilmiş dosya ile 57 ekleme ve 7 silme
  1. 57 7
      fpga/max80.sv

+ 57 - 7
fpga/max80.sv

@@ -479,6 +479,35 @@ module max80 (
 
    // Embedded RISC-V CPU
    parameter cpu_fast_mem_bits = 13; /* 2^[this] * 4 bytes */
+
+   // Edge-triggered system IRQs not necessarily associated
+   // with a specific I/O device. picorv32 latches interrupts
+   // but doesn't edge detect for a slow signal, so do it
+   // here instead and use level triggered signalling to the
+   // CPU.
+   wire [31:0] cpu_eoi;
+   reg  [31:0] cpu_eoi_q;
+
+   tri0 [15:3] sys_irq;
+   reg  [15:3] sys_irq_q;
+   reg  [15:3] sys_irq_pending;
+
+   always @(negedge rst_n or posedge sys_clk)
+     if (~rst_n)
+       begin
+	  sys_irq_q <= 1'b0;
+	  cpu_eoi_q <= 1'b0;
+	  sys_irq_pending <= 13'b0;
+       end
+     else
+       begin
+	  sys_irq_q <= sys_irq;
+	  cpu_eoi_q <= cpu_eoi;
+
+	  sys_irq_pending <= (sys_irq & ~sys_irq_q)
+	    | (sys_irq_pending & ~(cpu_eoi[15:3] & ~cpu_eoi_q[15:3]));
+       end
+
    picorv32 #(
 	      .ENABLE_COUNTERS ( 1 ),
 	      .ENABLE_COUNTERS64 ( 1 ),
@@ -496,8 +525,7 @@ module max80 (
 	      .ENABLE_IRQ ( 1 ),
 	      .ENABLE_IRQ_QREGS ( 1 ),
 	      .ENABLE_IRQ_TIMER ( 1 ),
-	      .LATCHED_IRQ ( 32'h0000_0007 ), // Device IRQs are level
-	      .MASKED_IRQ  ( 32'h0000_fff8 ), // Unused IRQs for now
+	      .LATCHED_IRQ ( 32'h0000_0007 ),
 	      .PROGADDR_RESET ( 32'h0000_0000 ),
 	      .PROGADDR_IRQ ( 32'h0000_0020 ),
 	      .REGS_INIT_ZERO ( 1 ),
@@ -523,8 +551,8 @@ module max80 (
 	.mem_la_addr  ( cpu_la_addr ),
 	.mem_la_wstrb ( cpu_la_wstrb ),
 
-	.irq ( { iodev_irq, 16'b0 } ),
-	.eoi ( )
+	.irq ( { iodev_irq, sys_irq_pending, 3'b000 } ),
+	.eoi ( cpu_eoi )
 	);
 
    // cpu_mem_ready is always true for fast memory; for SDRAM we have to
@@ -708,18 +736,40 @@ module max80 (
    assign sd_dat[2:1] = 2'bzz;
 
    // System local clock (not an RTC, but settable from one)
+   // Also provides a periodic interrupt (set to 32 Hz)
    wire [31:0] sysclock_rdata;
 
-   sysclock sysclock (
+   // XXX: the RTC 32 kHz signal is missing a pull-up,
+   // so it will require board rework. For now, use an
+   // divider down from the 84 MHz system clock. The
+   // error is about 200 ppm; a proper NCO could do better.
+
+   reg [10:0]  ctr_64khz;
+   reg	       ctr_32khz;
+   always @(posedge sys_clk)
+     begin
+	if (~|ctr_64khz)
+	  begin
+	     ctr_32khz <= ~ctr_32khz;
+	     ctr_64khz <= 11'd1280;
+	  end
+	else
+	  ctr_64khz <= ctr_64khz - 1'b1;
+     end
+
+   sysclock #(.PERIODIC_HZ_LG2 ( 5 ))
+   sysclock (
 		      .rst_n ( rst_n ),
 		      .sys_clk ( sys_clk ),
-		      .rtc_clk ( rtc_32khz ),
+		      .rtc_clk ( ctr_32khz ),
 
 		      .wdata   ( cpu_mem_wdata ),
 		      .rdata   ( sysclock_rdata ),
 		      .valid   ( iodev[5] ),
 		      .wstrb   ( cpu_mem_wstrb ),
-		      .addr    ( cpu_mem_addr[2] )
+		      .addr    ( cpu_mem_addr[2] ),
+
+		      .periodic ( sys_irq[3] )
 		      );
    //
    // I/O device input data MUX