Commit 919c5382 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

adding RTC module

parent eedda5bd
Loading
Loading
Loading
Loading

timing/rtc393.v

0 → 100644
+150 −0
Original line number Diff line number Diff line
/*******************************************************************************
 * Module: rtc393
 * Date:2015-07-05  
 * Author: andrey     
 * Description: Adjustable real time clock, generate 1 microsecond resolution,
 * timestamps. Provides seconds (32 bit) and microseconds (20 bits),
 * allows 24-bit accummulator-based fine adjustment
 *
 * Copyright (c) 2005-2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
 * rtc393.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  rtc393.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  rtc393 #(
        parameter RTC_ADDR=                  'h170, //TODO: assign valid address
        parameter RTC_MASK=                  'h3fc,
        parameter RTC_MHZ=                      25, // RTC input clock in MHz (should be interger number)
        parameter RTC_BITC_PREDIV =              5, // number of bits to generate 2 MHz pulses counting refclk 
        parameter RTC_SET_USEC=                  0, // 20-bit number of microseconds
        parameter RTC_SET_SEC=                   1, // 32-bit full number of seconds (und actually update timer)
        parameter RTC_SET_CORR=                  2 // write correction 16-bit signed

)   (
    input                         rst,
    input                         mclk,
    input                         refclk, // not a global clock, reference frequency < mclk/2
    // programming interface
    input                   [7:0] cmd_ad,      // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
    input                         cmd_stb,     // strobe (with first byte) for the command a/d
    
    output                 [31:0] live_sec,
    output                 [19:0] live_usec);
    
    wire  [31:0] cmd_data;
    wire   [2:0] cmd_a;
    wire         cmd_we; 

    wire         set_usec_w;  
    wire         set_sec_w;  
    wire         set_corr_w;
    
    reg  [19:0] wusec;   
    reg  [31:0] wsec;   
    reg  [15:0] corr;
    
    reg  [RTC_BITC_PREDIV-1:0] pre_cntr = 0;
    reg   [3:0] halfusec = 0; // 1-hot running pulse with 0.5 usec period
    reg   [2:0] refclk_mclk;
    reg         refclk2x_mclk;   
    reg         enable_rtc=0;
    reg         pend_set_cntr=0;
    reg         set_cntr; // valid for the full 0.5 usec
    reg  [23:0] acc;
    wire [24:0] next_acc;
    reg   [1:0] inc_usec;
    reg   [1:0] inc_sec;

    reg  [19:0] usec;
    reg  [31:0] sec;

    reg  [19:0] usec_plus1;
    reg  [31:0] sec_plus1;
    
    
    
    assign set_usec_w = cmd_we && (cmd_a == RTC_SET_USEC);
    assign set_sec_w =  cmd_we && (cmd_a == RTC_SET_SEC);
    assign set_corr_w = cmd_we && (cmd_a == RTC_SET_CORR);
    assign next_acc[24:0]= {1'b0,acc[23:0]} + {1'b0,~corr [15], {7{corr [15]}}, corr[15:0]};
    
    assign live_sec = sec;
    assign live_usec = usec;
    
    always @ (posedge mclk) begin
        if (set_usec_w) wusec <= cmd_data[19:0]; 
        if (set_sec_w)  wsec <=  cmd_data[31:0]; 
        if (set_corr_w) corr <=  cmd_data[15:0]; 
    end

    always @ (posedge rst or posedge mclk) begin
        if      (rst)       enable_rtc <= 0;
        else if (set_sec_w) enable_rtc <= 1;
    end
    
    always @ (posedge mclk) begin
        
        if (!enable_rtc || halfusec[0]) pre_cntr <= RTC_MHZ-2;
        else if (refclk2x_mclk)         pre_cntr <= pre_cntr - 1;
        
        if (!enable_rtc) halfusec <= 0;
        else             halfusec <= {halfusec[2:0], (|pre_cntr)?1'b0:1'b1};
        
        if (set_usec_w)      pend_set_cntr <= 1'b0; // just to get rid of undefined
        if (set_sec_w)       pend_set_cntr <= 1'b1;
        else if (halfusec[3])pend_set_cntr <= 1'b0;
        
    
        refclk_mclk <= {refclk_mclk[1:0], refclk};
        refclk2x_mclk <= refclk_mclk[2] ^ refclk_mclk[1];
        
        if (halfusec[1]) acc[23:0] <= set_cntr?24'h0:next_acc[23:0];
  
        if      (!enable_rtc) set_cntr <= 1'b0;
        else if (halfusec[3]) set_cntr <= pend_set_cntr;
      
      
        inc_usec <= {inc_usec[0],halfusec[1] & next_acc[24]};
        inc_sec  <= {inc_sec[0], halfusec[1] & next_acc[24] & ((usec[19:0]==20'hf423f)?1'b1:1'b0)};

        sec_plus1  <= sec + 1;
        usec_plus1 <= usec + 1;
        
        if      (set_cntr)    usec[19:0] <= wusec[19:0];
        else if (inc_sec[1])  usec[19:0] <= 20'h0;
        else if (inc_usec[1]) usec[19:0] <= usec_plus1[19:0];
      
        if      (set_cntr)    sec[31:0] <= wsec[31:0];
        else if (inc_sec[1])  sec[31:0] <= sec_plus1[31:0];
        
    end

        cmd_deser #(
        .ADDR       (RTC_ADDR),
        .ADDR_MASK  (RTC_MASK),
        .NUM_CYCLES (6),
        .ADDR_WIDTH (3),
        .DATA_WIDTH (32)
    ) cmd_deser_32bit_i (
        .rst        (rst),      // input
        .clk        (mclk),     // input
        .ad         (cmd_ad),   // input[7:0] 
        .stb        (cmd_stb),  // input
        .addr       (cmd_a),    // output[3:0] 
        .data       (cmd_data), // output[31:0] 
        .we         (cmd_we)    // output
    );
    
endmodule
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ module status_generate #(
    parameter STATUS_REG_ADDR=   7, // status register address to direct data to
    parameter PAYLOAD_BITS =     15, //6   // >=2! (2..26)
    parameter REGISTER_STATUS =  1,  // 1 - register input status data (for different clock domains),  0 - do not register (same domain)
    parameter EXTRA_WORDS=       1, // should always be >0
    parameter EXTRA_WORDS=       0, // should always be >0
    // if EXTRA_WORDS >0 the mesasges with these extra data will be generated and sent before the status message itself
    // if PAYLOAD_BITS == 0, then one status bit will still have to be provided (status input will have width of 1+32*EXTRA_WORDS),
    // but the status message will not be sent - only the data words