diff options
Diffstat (limited to 'fpga/usrp2/timing')
| -rw-r--r-- | fpga/usrp2/timing/.gitignore | 2 | ||||
| -rw-r--r-- | fpga/usrp2/timing/Makefile.srcs | 16 | ||||
| -rw-r--r-- | fpga/usrp2/timing/simple_timer.v | 77 | ||||
| -rw-r--r-- | fpga/usrp2/timing/time_64bit.v | 162 | ||||
| -rw-r--r-- | fpga/usrp2/timing/time_compare.v | 34 | ||||
| -rw-r--r-- | fpga/usrp2/timing/time_receiver.v | 157 | ||||
| -rw-r--r-- | fpga/usrp2/timing/time_sender.v | 157 | ||||
| -rw-r--r-- | fpga/usrp2/timing/time_sync.v | 163 | ||||
| -rw-r--r-- | fpga/usrp2/timing/time_transfer_tb.v | 67 | ||||
| -rw-r--r-- | fpga/usrp2/timing/timer.v | 57 | 
10 files changed, 892 insertions, 0 deletions
| diff --git a/fpga/usrp2/timing/.gitignore b/fpga/usrp2/timing/.gitignore new file mode 100644 index 000000000..515552fdb --- /dev/null +++ b/fpga/usrp2/timing/.gitignore @@ -0,0 +1,2 @@ +/a.out +/*.vcd diff --git a/fpga/usrp2/timing/Makefile.srcs b/fpga/usrp2/timing/Makefile.srcs new file mode 100644 index 000000000..0cf9372d3 --- /dev/null +++ b/fpga/usrp2/timing/Makefile.srcs @@ -0,0 +1,16 @@ +# +# Copyright 2010 Ettus Research LLC +# + +################################################## +# Timing Sources +################################################## +TIMING_SRCS = $(abspath $(addprefix $(BASE_DIR)/../timing/, \ +time_64bit.v \ +time_compare.v \ +time_receiver.v \ +time_sender.v \ +time_sync.v \ +timer.v \ +simple_timer.v \ +)) diff --git a/fpga/usrp2/timing/simple_timer.v b/fpga/usrp2/timing/simple_timer.v new file mode 100644 index 000000000..56ba8ffe8 --- /dev/null +++ b/fpga/usrp2/timing/simple_timer.v @@ -0,0 +1,77 @@ +// +// 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 simple_timer +  #(parameter BASE=0) +   (input clk, input reset, +    input set_stb, input [7:0] set_addr, input [31:0] set_data, +    output reg onetime_int, output reg periodic_int); + +   reg [31:0]  onetime_ctr; +   always @(posedge clk) +     if(reset) +       begin +	  onetime_int 	  <= 0; +	  onetime_ctr 	  <= 0; +       end +     else +       if(set_stb & (set_addr == BASE)) +	 begin +	    onetime_int   <= 0; +	    onetime_ctr   <= set_data; +	 end +       else  +	 begin +	    if(onetime_ctr == 1) +	      onetime_int <= 1; +	    if(onetime_ctr != 0) +	      onetime_ctr <= onetime_ctr - 1; +	    else +	      onetime_int <= 0; +	 end // else: !if(set_stb & (set_addr == BASE)) +    +   reg [31:0]  periodic_ctr, period; +   always @(posedge clk) +     if(reset) +       begin +	  periodic_int 	     <= 0; +	  periodic_ctr 	     <= 0; +	  period 	     <= 0; +       end +     else +       if(set_stb & (set_addr == (BASE+1))) +	 begin +	    periodic_int     <= 0; +	    periodic_ctr     <= set_data; +	    period 	     <= set_data; +	 end +       else  +	 if(periodic_ctr == 1) +	   begin +	      periodic_int   <= 1; +	      periodic_ctr   <= period; +	   end +	 else +	   if(periodic_ctr != 0) +	     begin +		periodic_int <= 0; +		periodic_ctr <= periodic_ctr - 1; +	     end +    +endmodule // simple_timer diff --git a/fpga/usrp2/timing/time_64bit.v b/fpga/usrp2/timing/time_64bit.v new file mode 100644 index 000000000..6f335890e --- /dev/null +++ b/fpga/usrp2/timing/time_64bit.v @@ -0,0 +1,162 @@ +// +// Copyright 2011-2012 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_64bit +  #( +    parameter BASE = 0) +   (input clk, input rst, +    input set_stb, input [7:0] set_addr, input [31:0] set_data,   +    input pps, +    output reg [63:0] vita_time, +    output reg [63:0] vita_time_pps, +    output pps_int, +    input exp_time_in, output exp_time_out, +    output reg good_sync, +    output [31:0] debug +    ); +    +   localparam 	   NEXT_TICKS_HI = 0; +   localparam 	   NEXT_TICKS_LO = 1; +   localparam      PPS_POLSRC = 2; +   localparam      PPS_IMM = 3; +   localparam      MIMO_SYNC = 5; +    +   reg [63:0] 	   ticks; + +   always @(posedge clk) +     vita_time <= ticks; +    +   wire [63:0] 	   vita_time_rcvd; +    +   wire [63:0] 	   next_ticks_preset; +   wire 	   set_on_pps_trig; +   reg 		   set_on_next_pps; +   wire 	   pps_polarity, pps_source, set_imm; +   reg [1:0] 	   pps_del; +   reg 		   pps_reg_p, pps_reg_n, pps_reg; +   wire 	   pps_edge; + +   reg [15:0] 	   sync_counter; +   wire 	   sync_rcvd; +   wire [63:0] 	   mimo_ticks; +   wire 	   mimo_sync_now; +   wire 	   mimo_sync; +   wire [7:0] 	   sync_delay; +    +   setting_reg #(.my_addr(BASE+NEXT_TICKS_LO)) sr_next_ticks_lo +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(next_ticks_preset[31:0]),.changed()); +    +   setting_reg #(.my_addr(BASE+NEXT_TICKS_HI)) sr_next_ticks_hi +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(next_ticks_preset[63:32]),.changed(set_on_pps_trig)); + +   setting_reg #(.my_addr(BASE+PPS_POLSRC), .width(2)) sr_pps_polsrc +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out({pps_source,pps_polarity}),.changed()); + +   setting_reg #(.my_addr(BASE+PPS_IMM), .width(1)) sr_pps_imm +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(set_imm),.changed()); + +   setting_reg #(.my_addr(BASE+MIMO_SYNC), .at_reset(0), .width(9)) sr_mimosync +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out({mimo_sync,sync_delay}),.changed()); + +   always @(posedge clk)  pps_reg_p <= pps;    +   always @(negedge clk)  pps_reg_n <= pps; +   always @* pps_reg <= pps_polarity ? pps_reg_p : pps_reg_n; +    +   always @(posedge clk) +     if(rst) +       pps_del <= 2'b00; +     else +       pps_del <= {pps_del[0],pps_reg}; + +   assign pps_edge = pps_del[0] & ~pps_del[1]; + +   always @(posedge clk) +     if(pps_edge) +       vita_time_pps <= vita_time; +    +   always @(posedge clk) +     if(rst) +       set_on_next_pps <= 0; +     else if(set_on_pps_trig) +       set_on_next_pps <= 1; +     else if(set_imm | pps_edge) +       set_on_next_pps <= 0; + +   wire [63:0] 	   ticks_plus_one = ticks + 1; +    +   always @(posedge clk) +     if(rst) +       begin +	  ticks <= 64'd0; +       end +     else if((set_imm | pps_edge) & set_on_next_pps) +       begin +	  ticks <= next_ticks_preset; +       end +     else if(mimo_sync_now) +       begin +	  ticks <= mimo_ticks; +       end +     else +       ticks <= ticks_plus_one; + +   assign pps_int = pps_edge; + +   // MIMO Connector Time Sync +   wire send_sync = (sync_counter == 59999); // X % 10 = 9 + +   always @(posedge clk) +     if(rst) +       sync_counter <= 0; +     else +       if(send_sync) +	 sync_counter <= 0; +       else +	 sync_counter <= sync_counter + 1; +    +   time_sender time_sender +     (.clk(clk),.rst(rst), +      .vita_time(vita_time), +      .send_sync(send_sync), +      .exp_time_out(exp_time_out) ); + +   time_receiver time_receiver +     (.clk(clk),.rst(rst), +      .vita_time(vita_time_rcvd), +      .sync_rcvd(sync_rcvd), +      .exp_time_in(exp_time_in) ); + +   assign mimo_ticks = vita_time_rcvd[63:0] + {48'd0,sync_delay}; +   assign mimo_sync_now = mimo_sync & sync_rcvd; + +   assign debug = { { 24'b0} , +		    { 2'b0, exp_time_in, exp_time_out, mimo_sync, mimo_sync_now, sync_rcvd, send_sync} }; + +   always @(posedge clk) +     if(rst) +       good_sync <= 0; +     else if(sync_rcvd) +       good_sync <= 1; +    +endmodule // time_64bit diff --git a/fpga/usrp2/timing/time_compare.v b/fpga/usrp2/timing/time_compare.v new file mode 100644 index 000000000..21607f51c --- /dev/null +++ b/fpga/usrp2/timing/time_compare.v @@ -0,0 +1,34 @@ +// +// Copyright 2011-2012 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/>. +// + + +// 64 bits worth of ticks + +module time_compare +  (input [63:0] time_now, +   input [63:0] trigger_time, +   output now, +   output early, +   output late, +   output too_early); + +    assign now = time_now == trigger_time; +    assign late = time_now > trigger_time; +    assign early = ~now & ~late; +    assign too_early = 0; //not implemented + +endmodule // time_compare diff --git a/fpga/usrp2/timing/time_receiver.v b/fpga/usrp2/timing/time_receiver.v new file mode 100644 index 000000000..a03337552 --- /dev/null +++ b/fpga/usrp2/timing/time_receiver.v @@ -0,0 +1,157 @@ +// +// 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_receiver +  (input clk, input rst, +   output reg [63:0] vita_time, +   output reg sync_rcvd, +   input exp_time_in); + +   wire       code_err, disp_err, dispout, complete_word; +   reg 	      disp_reg; +   reg [9:0]  shiftreg; +   reg [3:0]  bit_count; +   wire [8:0] dataout; +   reg [8:0]  dataout_reg; + +   reg 	      exp_time_in_reg, exp_time_in_reg2; +    +   always @(posedge clk)  exp_time_in_reg <= exp_time_in; +   always @(posedge clk)  exp_time_in_reg2 <= exp_time_in_reg; +    +   always @(posedge clk) +     shiftreg <= {exp_time_in_reg2, shiftreg[9:1]}; + +   localparam COMMA_0 = 10'h283; +   localparam COMMA_1 = 10'h17c; +    +   wire       found_comma = (shiftreg == COMMA_0) | (shiftreg == COMMA_1); +   wire       set_disp = (shiftreg == COMMA_1); + +   always @(posedge clk) +     if(rst) +       bit_count <= 0; +     else if(found_comma | complete_word) +       bit_count <= 0; +     else  +       bit_count <= bit_count + 1; +   assign     complete_word = (bit_count == 9); + +   always @(posedge clk) +     if(set_disp) +       disp_reg <= 1; +     else if(complete_word) +       disp_reg <= dispout; + +   always @(posedge clk) +     if(complete_word) +       dataout_reg <= dataout; +      +   decode_8b10b decode_8b10b  +     (.datain(shiftreg),.dispin(disp_reg), +      .dataout(dataout),.dispout(dispout), +      .code_err(code_err),.disp_err(disp_err) ); + +   reg 	      error; +   always @(posedge clk) +     if(complete_word) +       error <= code_err | disp_err; +    +   localparam STATE_IDLE = 0; +   localparam STATE_T0 = 1; +   localparam STATE_T1 = 2; +   localparam STATE_T2 = 3; +   localparam STATE_T3 = 4; +   localparam STATE_T4 = 5; +   localparam STATE_T5 = 6; +   localparam STATE_T6 = 7; +   localparam STATE_T7 = 8; +   localparam STATE_TAIL = 9; +    +   localparam HEAD = 9'h13c;    +   localparam TAIL = 9'h1F7; +    +   reg [3:0]  state; +   reg [63:0] vita_time_pre; +   reg 	      sync_rcvd_pre; +       +   always @(posedge clk) +     if(rst) +       state <= STATE_IDLE; +     else if(complete_word) +       if(code_err | disp_err) +	 state <= STATE_IDLE; +       else +	 case(state) +	   STATE_IDLE : +	     if(dataout_reg == HEAD) +	       state <= STATE_T0; +	   STATE_T0 : +	     begin +		vita_time_pre[63:56] <= dataout_reg[7:0]; +		state <= STATE_T1; +	     end +	   STATE_T1 : +	     begin +		vita_time_pre[55:48] <= dataout_reg[7:0]; +		state <= STATE_T2; +	     end +	   STATE_T2 : +	     begin +		vita_time_pre[47:40] <= dataout_reg[7:0]; +		state <= STATE_T3; +	     end +	   STATE_T3 : +	     begin +		vita_time_pre[39:32] <= dataout_reg[7:0]; +		state <= STATE_T4; +	     end +	   STATE_T4 : +	     begin +		vita_time_pre[31:24] <= dataout_reg[7:0]; +		state <= STATE_T5; +	     end +	   STATE_T5 : +	     begin +		vita_time_pre[23:16] <= dataout_reg[7:0]; +		state <= STATE_T6; +	     end +	   STATE_T6 : +	     begin +		vita_time_pre[15:8] <= dataout_reg[7:0]; +		state <= STATE_T7; +	     end +	   STATE_T7 : +	     begin +		vita_time_pre[7:0] <= dataout_reg[7:0]; +		state <= STATE_TAIL; +	     end +	   STATE_TAIL : +	     state <= STATE_IDLE; +	 endcase // case(state) +    +   always @(posedge clk) +     if(rst) +       sync_rcvd_pre <= 0; +     else +       sync_rcvd_pre <= (complete_word & (state == STATE_TAIL) & (dataout_reg[8:0] == TAIL)); + +   always @(posedge clk) sync_rcvd <= sync_rcvd_pre; +   always @(posedge clk) vita_time <= vita_time_pre; +    +endmodule // time_sender diff --git a/fpga/usrp2/timing/time_sender.v b/fpga/usrp2/timing/time_sender.v new file mode 100644 index 000000000..fdf6b1240 --- /dev/null +++ b/fpga/usrp2/timing/time_sender.v @@ -0,0 +1,157 @@ +// +// 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_sender +  (input clk, input rst, +   input [63:0] vita_time, +   input send_sync, +   output reg exp_time_out); + +   reg [7:0] datain; +   reg 	     k; +   wire [9:0] dataout; +   reg [9:0]  dataout_reg; +   reg 	      disp_reg; +   wire       disp, new_word; +   reg [4:0]  state; +   reg [3:0]  bit_count; +    +   encode_8b10b encode_8b10b  +     (.datain({k,datain}),.dispin(disp_reg), +      .dataout(dataout),.dispout(disp)); + +   always @(posedge clk) +     if(rst) +       disp_reg <= 0; +     else if(new_word) +       disp_reg <= disp; +    +   always @(posedge clk) +     if(rst) +       dataout_reg <= 0; +     else if(new_word) +       dataout_reg <= dataout; +     else +       dataout_reg <= {1'b0,dataout_reg[9:1]}; +    +   always @(posedge clk) +     exp_time_out <= dataout_reg[0]; +    +   assign    new_word = (bit_count == 9); +    +   always @(posedge clk) +     if(rst) +       bit_count <= 0; +     else if(new_word | send_sync) +       bit_count <= 0; +     else +       bit_count <= bit_count + 1; + +   localparam SEND_IDLE = 0; +   localparam SEND_HEAD = 1; +   localparam SEND_T0 = 2; +   localparam SEND_T1 = 3; +   localparam SEND_T2 = 4; +   localparam SEND_T3 = 5; +   localparam SEND_T4 = 6; +   localparam SEND_T5 = 7; +   localparam SEND_T6 = 8; +   localparam SEND_T7 = 9; +   localparam SEND_TAIL = 10; + +   localparam COMMA = 8'hBC; +   localparam HEAD = 8'h3C; +   localparam TAIL = 8'hF7; +    +   reg [63:0] vita_time_reg; +    +   always @(posedge clk) +     if(rst) +       vita_time_reg <= 0; +     else if(send_sync) +       vita_time_reg <= vita_time; +    +   always @(posedge clk) +     if(rst) +       begin +	  {k,datain} <= 0; +	  state <= SEND_IDLE; +       end +     else +       if(send_sync) +	 state <= SEND_HEAD; +       else if(new_word) +	 case(state) +	   SEND_IDLE : +	     {k,datain} <= {1'b1,COMMA}; +	   SEND_HEAD : +	     begin +		{k,datain} <= {1'b1, HEAD}; +		state <= SEND_T0; +	     end +	   SEND_T0 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[63:56] }; +		state <= SEND_T1; +	     end +	   SEND_T1 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[55:48]}; +		state <= SEND_T2; +	     end +	   SEND_T2 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[47:40]}; +		state <= SEND_T3; +	     end +	   SEND_T3 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[39:32]}; +		state <= SEND_T4; +	     end +	   SEND_T4 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[31:24]}; +		state <= SEND_T5; +	     end +	   SEND_T5 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[23:16]}; +		state <= SEND_T6; +	     end +	   SEND_T6 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[15:8]}; +		state <= SEND_T7; +	     end +	   SEND_T7 : +	     begin +		{k,datain} <= {1'b0, vita_time_reg[7:0]}; +		state <= SEND_TAIL; +	     end +	   SEND_TAIL : +	     begin +		{k,datain} <= {1'b1, TAIL}; +		state <= SEND_IDLE; +	     end +	   default : +	     state <= SEND_IDLE; +	 endcase // case(state) +    +endmodule // time_sender 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 diff --git a/fpga/usrp2/timing/time_transfer_tb.v b/fpga/usrp2/timing/time_transfer_tb.v new file mode 100644 index 000000000..288540702 --- /dev/null +++ b/fpga/usrp2/timing/time_transfer_tb.v @@ -0,0 +1,67 @@ +// +// 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/>. +// + + +`timescale 1ns / 1ps + +module time_transfer_tb(); + +   reg clk = 0, rst = 1; +   always #5 clk = ~clk; +    +   initial  +     begin +	@(negedge clk); +	@(negedge clk); +	rst <= 0; +     end + +   initial $dumpfile("time_transfer_tb.vcd"); +   initial $dumpvars(0,time_transfer_tb); +    +   initial #100000000 $finish; + +   wire exp_time, pps, pps_rcv; +   wire [63:0] vita_time_rcv; +   reg [63:0]  vita_time = 0; +   reg [63:0]  counter = 0; + +   localparam  PPS_PERIOD = 439; // PPS_PERIOD % 10 must = 9 +   always @(posedge clk) +     if(counter == PPS_PERIOD) +       counter <= 0; +     else +       counter <= counter + 1; +   assign      pps = (counter == (PPS_PERIOD-1)); +    +   always @(posedge clk) +     vita_time <= vita_time + 1; +    +   time_sender time_sender +     (.clk(clk),.rst(rst), +      .vita_time(vita_time), +      .send_sync(pps), +      .exp_time_out(exp_time) ); + +   time_receiver time_receiver +     (.clk(clk),.rst(rst), +      .vita_time(vita_time_rcv), +      .sync_rcvd(pps_rcv), +      .exp_time_in(exp_time) ); + +   wire [31:0] delta = vita_time - vita_time_rcv; +endmodule // time_transfer_tb diff --git a/fpga/usrp2/timing/timer.v b/fpga/usrp2/timing/timer.v new file mode 100644 index 000000000..216a9294c --- /dev/null +++ b/fpga/usrp2/timing/timer.v @@ -0,0 +1,57 @@ +// +// 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 timer +  (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, input [31:0] master_time_i, +   output int_o ); + +   reg [31:0] time_wb; +   always @(posedge wb_clk_i) +     time_wb <= master_time_i; + +   assign     ack_o = stb_i; + +   reg [31:0] int_time; +   reg 	      int_reg; +    +   always @(posedge sys_clk_i) +     if(rst_i) +       begin +	  int_time <= 0; +	  int_reg <= 0; +       end +     else if(|int_time && (master_time_i == int_time)) +       begin +	  int_time <= 0; +	  int_reg <= 1; +       end +     else if(stb_i & we_i) +       begin +	  int_time <= dat_i; +	  int_reg <= 0; +       end + +   assign dat_o = time_wb; +   assign int_o = int_reg; +    +endmodule // timer + | 
