diff options
Diffstat (limited to 'fpga/usrp2/timing/time_sync.v')
-rw-r--r-- | fpga/usrp2/timing/time_sync.v | 163 |
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 |