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 | 60 | ||||
-rw-r--r-- | fpga/usrp2/timing/time_64bit.v | 151 | ||||
-rw-r--r-- | fpga/usrp2/timing/time_compare.v | 47 | ||||
-rw-r--r-- | fpga/usrp2/timing/time_receiver.v | 140 | ||||
-rw-r--r-- | fpga/usrp2/timing/time_sender.v | 140 | ||||
-rw-r--r-- | fpga/usrp2/timing/time_sync.v | 146 | ||||
-rw-r--r-- | fpga/usrp2/timing/time_transfer_tb.v | 50 | ||||
-rw-r--r-- | fpga/usrp2/timing/timer.v | 40 |
10 files changed, 792 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..17c7f1c36 --- /dev/null +++ b/fpga/usrp2/timing/simple_timer.v @@ -0,0 +1,60 @@ + + +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..8122cc6ea --- /dev/null +++ b/fpga/usrp2/timing/time_64bit.v @@ -0,0 +1,151 @@ + + +module time_64bit + #(parameter TICKS_PER_SEC = 32'd100000000, + parameter BASE = 0) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input pps, + output [63:0] vita_time, + output reg [63:0] vita_time_pps, + output pps_int, + input exp_time_in, output exp_time_out, + output [31:0] debug + ); + + localparam NEXT_SECS = 0; + localparam NEXT_TICKS = 1; + localparam PPS_POLSRC = 2; + localparam PPS_IMM = 3; + localparam TPS = 4; + localparam MIMO_SYNC = 5; + + reg [31:0] seconds, ticks; + wire end_of_second; + assign vita_time = {seconds,ticks}; + wire [63:0] vita_time_rcvd; + + wire [31:0] next_ticks_preset, next_seconds_preset; + wire [31:0] ticks_per_sec_reg; + 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 [31:0] mimo_secs, mimo_ticks; + wire mimo_sync_now; + wire mimo_sync; + wire [7:0] sync_delay; + + setting_reg #(.my_addr(BASE+NEXT_TICKS)) sr_next_ticks + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(next_ticks_preset),.changed()); + + setting_reg #(.my_addr(BASE+NEXT_SECS)) sr_next_secs + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(next_seconds_preset),.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+TPS), .at_reset(TICKS_PER_SEC)) sr_tps + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(ticks_per_sec_reg),.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 [31:0] ticks_plus_one = ticks + 1; + + always @(posedge clk) + if(rst) + begin + seconds <= 32'd0; + ticks <= 32'd0; + end + else if((set_imm | pps_edge) & set_on_next_pps) + begin + seconds <= next_seconds_preset; + ticks <= next_ticks_preset; + end + else if(mimo_sync_now) + begin + seconds <= mimo_secs; + ticks <= mimo_ticks; + end + else if(ticks_plus_one == ticks_per_sec_reg) + begin + seconds <= seconds + 1; + ticks <= 0; + 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_secs = vita_time_rcvd[63:32]; + assign mimo_ticks = vita_time_rcvd[31:0] + {16'd0,sync_delay}; + assign mimo_sync_now = mimo_sync & sync_rcvd & (mimo_ticks <= TICKS_PER_SEC); + + assign debug = { { 24'b0} , + { 2'b0, exp_time_in, exp_time_out, mimo_sync, mimo_sync_now, sync_rcvd, send_sync} }; + +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..cb2b6d860 --- /dev/null +++ b/fpga/usrp2/timing/time_compare.v @@ -0,0 +1,47 @@ + +// Top 32 bits are integer seconds, bottom 32 are clock ticks within a second + +module time_compare + (input [63:0] time_now, + input [63:0] trigger_time, + output now, + output early, + output late, + output too_early); + + wire sec_match = (time_now[63:32] == trigger_time[63:32]); + wire sec_late = (time_now[63:32] > trigger_time[63:32]); + + wire tick_match = (time_now[31:0] == trigger_time[31:0]); + wire tick_late = (time_now[31:0] > trigger_time[31:0]); +/* + assign now = sec_match & tick_match; + assign late = sec_late | (sec_match & tick_late); + assign early = ~now & ~late; +*/ + + /* + assign now = (time_now == trigger_time); + assign late = (time_now > trigger_time); + assign early = (time_now < trigger_time); + */ + + // Compare fewer bits instead of 64 to speed up logic + // Unused bits are not significant + // Top bit of seconds would put us in year 2038, long after + // the warranty has run out :) + // Top 5 bits of ticks are always zero for clocks less than 134MHz + // "late" can drop bottom few bits of ticks, and just delay signaling + // of late. + // "now" cannot drop those bits, it needs to be exact. + + wire [57:0] short_now = {time_now[62:32],time_now[26:0]}; + wire [57:0] short_trig = {trigger_time[62:32],trigger_time[26:0]}; + + assign now = (short_now == short_trig); + assign late = (short_now[57:5] > short_trig[57:5]); + assign early = (short_now < short_trig); + + assign too_early = (trigger_time[63:32] > (time_now[63:32] + 4)); // Don't wait too long + +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..897f71186 --- /dev/null +++ b/fpga/usrp2/timing/time_receiver.v @@ -0,0 +1,140 @@ + +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..f4ee5226a --- /dev/null +++ b/fpga/usrp2/timing/time_sender.v @@ -0,0 +1,140 @@ + + +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..c0c8e195f --- /dev/null +++ b/fpga/usrp2/timing/time_sync.v @@ -0,0 +1,146 @@ + + +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..0c164f82c --- /dev/null +++ b/fpga/usrp2/timing/time_transfer_tb.v @@ -0,0 +1,50 @@ + +`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..70c9746be --- /dev/null +++ b/fpga/usrp2/timing/timer.v @@ -0,0 +1,40 @@ + + +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 + |