2
0

sysclock.sv 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // sysclock.sv
  3. //
  4. // Very simple unit that keeps track of time in "human" format based
  5. // on 32.768 kHz signal from the RTC. The registers have to be set from
  6. // software, presumably from reading the RTC.
  7. //
  8. // Register 0 contains the 2 s granular date and time in FAT filesystem format.
  9. // Register 1 contains two copies of a 16-bit 32 kHz counter:
  10. // the upper half contains the current counter, and the lower half is
  11. // a holding register updated when register 0 is read, and, if written
  12. // to in adcance, will write the counter when register 0 is written.
  13. module sysclock (
  14. input rst_n,
  15. input sys_clk,
  16. input rtc_clk,
  17. output rtc_clk_s,
  18. input valid,
  19. input addr,
  20. output reg [31:0] rdata,
  21. input [31:0] wdata,
  22. input [3:0] wstrb,
  23. output periodic,
  24. output [15:0] rtc_ctr
  25. );
  26. parameter PERIODIC_HZ_LG2 = 5;
  27. synchronizer synchro (
  28. .rst_n ( 1'b1 ),
  29. .clk ( sys_clk ),
  30. .d ( rtc_clk ),
  31. .q ( rtc_clk_s )
  32. );
  33. reg rtc_clk_q;
  34. reg rtc_clk_stb;
  35. always @(posedge sys_clk)
  36. begin
  37. rtc_clk_q <= rtc_clk_s;
  38. rtc_clk_stb <= rtc_clk_s & ~rtc_clk_q;
  39. end
  40. function logic [4:0] maxday(input [3:0] mon,
  41. input [6:0] year);
  42. case (mon)
  43. 4'd4, // April
  44. 4'd6, // June
  45. 4'd9, // September
  46. 4'd11: begin // November
  47. maxday = 5'd30;
  48. end
  49. 4'd2: begin // February
  50. if ((|year[1:0]) | (year == (2100 - 1980)))
  51. maxday = 5'd28;
  52. else
  53. maxday = 5'd29;
  54. end
  55. default: begin
  56. maxday = 5'd31;
  57. end
  58. endcase // case (mon)
  59. endfunction // mdays
  60. function logic [7:0] tick(input [7:0] me,
  61. input [7:0] start,
  62. input wrap_pre,
  63. input wrap_me);
  64. tick = wrap_me ? start : me + wrap_pre;
  65. endfunction // tick
  66. // Counter read/writes holding register
  67. reg [15:0] tm_hold;
  68. reg [ 1:0] tm_whold; // Byte enables for hold register
  69. reg [15:0] tm_tick;
  70. reg [31:0] tm_dt; // Day and time in FAT filesystem format
  71. wire [4:0] tm_2sec = tm_dt[4:0];
  72. wire [5:0] tm_min = tm_dt[10:5];
  73. wire [4:0] tm_hour = tm_dt[15:11];
  74. wire [4:0] tm_mday = tm_dt[20:16];
  75. wire [3:0] tm_mon = tm_dt[24:21];
  76. wire [6:0] tm_year = tm_dt[31:25];
  77. wire wrap_tick = rtc_clk_stb & &tm_tick;
  78. wire wrap_sec = wrap_tick & (tm_2sec >= 5'd29);
  79. wire wrap_min = wrap_sec & (tm_min >= 6'd59);
  80. wire wrap_hour = wrap_min & (tm_hour >= 5'd23);
  81. wire wrap_mday = wrap_hour & (tm_mday >= maxday(tm_mon, tm_year));
  82. wire wrap_mon = wrap_mday & (tm_mon >= 4'd12);
  83. // Yes, it may jump if the counter is written, that is intentional
  84. assign periodic = tm_tick[14 - PERIODIC_HZ_LG2];
  85. assign rtc_ctr = tm_tick;
  86. always @(posedge sys_clk)
  87. begin
  88. tm_tick <= tm_tick + rtc_clk_stb;
  89. tm_dt[4:0] <= tick(tm_2sec, 5'd0, wrap_tick, wrap_sec);
  90. tm_dt[10:5] <= tick(tm_min, 6'd0, wrap_sec, wrap_min);
  91. tm_dt[15:11] <= tick(tm_hour, 4'd0, wrap_min, wrap_hour);
  92. tm_dt[20:16] <= tick(tm_mday, 5'd1, wrap_hour, wrap_mday);
  93. tm_dt[24:21] <= tick(tm_mon, 4'd1, wrap_mday, wrap_mon);
  94. tm_dt[31:25] <= tick(tm_year, 7'hxx, wrap_mon, 1'b0);
  95. if (~rst_n)
  96. begin
  97. tm_hold <= tm_tick;
  98. tm_whold <= 2'b00;
  99. end
  100. else if (valid)
  101. case (addr)
  102. 1'b0: begin
  103. // Datetime register
  104. if (wstrb[0]) tm_dt[7:0] <= wdata[7:0];
  105. if (wstrb[1]) tm_dt[15:8] <= wdata[15:8];
  106. if (wstrb[2]) tm_dt[23:16] <= wdata[23:16];
  107. if (wstrb[3]) tm_dt[31:24] <= wdata[31:24];
  108. if (tm_whold[0]) tm_tick[7:0] <= tm_hold[7:0];
  109. if (tm_whold[1]) tm_tick[15:8] <= tm_hold[15:8];
  110. tm_hold <= tm_tick;
  111. tm_whold <= 2'b00;
  112. end // case: 1'b0
  113. 1'b1: begin
  114. // Tick register
  115. if (wstrb[0]) tm_hold[7:0] <= wdata[7:0];
  116. if (wstrb[1]) tm_hold[15:8] <= wdata[15:8];
  117. if (wstrb[2]) tm_tick[7:0] <= wdata[23:16];
  118. if (wstrb[3]) tm_tick[15:8] <= wdata[31:24];
  119. tm_whold <= tm_whold | wstrb[1:0];
  120. end
  121. endcase // case (addr)
  122. end // always @ (posedge sys_clk)
  123. // Read data MUX
  124. always @(*)
  125. case (addr)
  126. 1'b0: rdata = tm_dt;
  127. 1'b1: rdata = { tm_tick, tm_hold };
  128. endcase // case (addr)
  129. endmodule // sysclock