aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/timing/time_sync.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp2/timing/time_sync.v')
-rw-r--r--fpga/usrp2/timing/time_sync.v163
1 files changed, 163 insertions, 0 deletions
diff --git a/fpga/usrp2/timing/time_sync.v b/fpga/usrp2/timing/time_sync.v
new file mode 100644
index 000000000..a823e9e1b
--- /dev/null
+++ b/fpga/usrp2/timing/time_sync.v
@@ -0,0 +1,163 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program 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.
+//
+// This program 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/>.
+//
+
+
+
+module time_sync
+ (input wb_clk_i, input rst_i,
+ input cyc_i, input stb_i, input [2:0] adr_i,
+ input we_i, input [31:0] dat_i, output [31:0] dat_o, output ack_o,
+ input sys_clk_i, output [31:0] master_time_o,
+ input pps_posedge, input pps_negedge,
+ input exp_pps_in, output exp_pps_out,
+ output reg int_o,
+ output reg epoch_o,
+ output reg pps_o );
+
+ wire [31:0] master_time_rcvd;
+ reg [31:0] master_time;
+ reg [31:0] delta_time;
+
+ reg internal_tick;
+ wire sync_rcvd, pps_ext;
+ reg [31:0] tick_time, tick_time_wb;
+ wire tick_free_run;
+ reg tick_int_enable, tick_source, external_sync;
+ reg [31:0] tick_interval;
+ reg sync_on_next_pps;
+ reg sync_every_pps;
+ reg pps_edge;
+
+ // Generate master time
+ always @(posedge sys_clk_i)
+ if(rst_i)
+ master_time <= 0;
+ else if(external_sync & sync_rcvd)
+ master_time <= master_time_rcvd + delta_time;
+ else if(pps_ext & (sync_on_next_pps|sync_every_pps))
+ master_time <= 0;
+ else
+ master_time <= master_time + 1;
+ assign master_time_o = master_time;
+
+ time_sender time_sender
+ (.clk(sys_clk_i),.rst(rst_i),
+ .master_time(master_time),
+ .send_sync(internal_tick),
+ .exp_pps_out(exp_pps_out) );
+
+ time_receiver time_receiver
+ (.clk(sys_clk_i),.rst(rst_i),
+ .master_time(master_time_rcvd),
+ .sync_rcvd(sync_rcvd),
+ .exp_pps_in(exp_pps_in) );
+
+ assign ack_o = stb_i;
+ wire wb_write = cyc_i & stb_i & we_i;
+ wire wb_read = cyc_i & stb_i & ~we_i;
+ wire wb_acc = cyc_i & stb_i;
+
+ always @(posedge wb_clk_i)
+ if(rst_i)
+ begin
+ tick_source <= 0;
+ tick_int_enable <= 0;
+ external_sync <= 0;
+ tick_interval <= 100000-1; // default to 1K times per second
+ delta_time <= 0;
+ pps_edge <= 0;
+ sync_every_pps <= 0;
+ end
+ else if(wb_write)
+ case(adr_i[2:0])
+ 3'd0 :
+ begin
+ tick_source <= dat_i[0];
+ tick_int_enable <= dat_i[1];
+ external_sync <= dat_i[2];
+ pps_edge <= dat_i[3];
+ sync_every_pps <= dat_i[4];
+ end
+ 3'd1 :
+ tick_interval <= dat_i;
+ 3'd2 :
+ delta_time <= dat_i;
+ 3'd3 :
+ ;
+ // Do nothing here, this is to arm the sync_on_next
+ endcase // case(adr_i[2:0])
+
+ always @(posedge sys_clk_i)
+ if(rst_i)
+ sync_on_next_pps <= 0;
+ else if(pps_ext)
+ sync_on_next_pps <= 0;
+ else if(wb_write & (adr_i[2:0] == 3))
+ sync_on_next_pps <= 1;
+
+ always @(posedge sys_clk_i)
+ if(internal_tick)
+ tick_time <= master_time;
+
+ always @(posedge wb_clk_i)
+ tick_time_wb <= tick_time;
+
+ assign dat_o = tick_time_wb;
+
+ always @(posedge sys_clk_i)
+ internal_tick <= (tick_source == 0) ? tick_free_run : pps_ext;
+
+ reg [31:0] counter;
+ always @(posedge sys_clk_i)
+ if(rst_i)
+ counter <= 0;
+ else if(tick_free_run)
+ counter <= 0;
+ else
+ counter <= counter + 1;
+ assign tick_free_run = (counter >= tick_interval);
+
+ // Properly Latch and edge detect External PPS input
+ reg pps_in_d1, pps_in_d2;
+ always @(posedge sys_clk_i)
+ begin
+ pps_in_d1 <= pps_edge ? pps_posedge : pps_negedge;
+ pps_in_d2 <= pps_in_d1;
+ end
+ assign pps_ext = pps_in_d1 & ~pps_in_d2;
+
+ always @(posedge sys_clk_i)
+ pps_o <= pps_ext;
+
+ // Need to register this?
+ reg internal_tick_d1;
+ always @(posedge sys_clk_i) internal_tick_d1 <= internal_tick;
+
+ always @(posedge wb_clk_i)
+ if(rst_i)
+ int_o <= 0;
+ else if(tick_int_enable & (internal_tick | internal_tick_d1))
+ int_o <= 1;
+ else
+ int_o <= 0;
+
+ always @(posedge sys_clk_i)
+ if(rst_i)
+ epoch_o <= 0;
+ else
+ epoch_o <= (master_time_o[27:0] == 0);
+endmodule // time_sync