// timer.v module timer( PCLK, PENABLE, PSEL, PRESETN, PWRITE, PREADY, PSLVERR, PADDR, PWDATA, PRDATA, TCLK, CAPTURE, test_out, FABINT, PWM1, PWM2); // APB Bus Interface input PCLK,PENABLE, PSEL, PRESETN, PWRITE; input [31:0] PWDATA; input [4:0] PADDR; output [31:0] PRDATA; output PREADY, PSLVERR; // Timer Interface input TCLK; input CAPTURE; output FABINT; output PWM1, PWM2; // Test Interface output [3:0] test_out; // Clock Domain synchronization reg PREADY; reg [1:0] fsm; //state machine register for pclk domain reg fsm_tclk; // state machine register for tclk domain reg [31:0] PRDATA; // Timer reg [31:0] Counter; reg [31:0] Load; reg [31:0] Compare; reg [31:0] CaptureSync; reg [31:0] CaptureASync; reg [1:0] interrupt_status; reg capture_status; // indicates if the capture happened or not reg capture_status_async; reg TimerEn; // Timer enable reg LoadEnReg; // Register Load enable reg FABINT; reg timer_int; // TCLK domain interrupt reg timer_capture_sync_int; reg reset_int; reg reset_capture_sync; reg reset_capture_async; reg InterruptEn; // enable interrupts reg CompareEn; // enable Compare interrupt reg OverflowEn; // enable Overflow interrupt reg CaptureEn; // enable Capture interrupt reg PWMEn; // enable PWM reg CaptureOverwrite; // indicates if the capture value has been overwritten or not reg PWM1, PWM2; // PWM signals wire CAPTURE; // Capture Interrupt reg capture_intrpt_temp, capture_intrpt_temp1, capture_intrpt_temp2; // interrupt pulse signals reg intrpt_temp, intrpt_temp1, intrpt_temp2; // Handshaking signals reg reg_load_en0, reg_load_en1, reg_load_en2; reg reg_load_ack0, reg_load_ack1, reg_load_ack2; // Test Outputs wire [3:0] test_out; assign test_out[0] = 1'b0; assign test_out[1] = 1'b0; assign test_out[2] = 1'b0; assign test_out[3] = 1'b0; assign PSLVERR = 1'b0; // Handshaking signal PCLK signals to TCLK always@(posedge PCLK or negedge PRESETN) if(~PRESETN) begin reg_load_en1 <= 1'b0; reg_load_en2 <= 1'b0; end else begin reg_load_en1 <= reg_load_en0; reg_load_en2 <= reg_load_en1; end // Handshaking signal TCLK signals to PCLK always@(posedge TCLK or negedge PRESETN) if(~PRESETN) begin reg_load_ack1 <= 1'b0; reg_load_ack2 <= 1'b0; end else begin reg_load_ack1 <= reg_load_ack0; reg_load_ack2 <= reg_load_ack1; end // Handle APB Bus read and writes and inform TCLK clock domain always@(posedge PCLK or negedge PRESETN) if(~PRESETN) begin fsm <= 2'b00; PREADY <= 1'b1; reg_load_en0 <= 1'b0; end else begin case (fsm) 2'b00 : begin if (~PSEL) begin // not for us fsm <= 2'b00; end else begin fsm <= 2'b01; // advance to next state PREADY <= 1'b0; // signal we are not ready reg_load_en0 <= 1'b1; // inform other clock domain end end 2'b01 : begin if(reg_load_ack2 == 1'b1) begin fsm <= 2'b10; reg_load_en0 <= 1'b0; end end 2'b10 : begin if(reg_load_ack2 == 1'b0) begin fsm <= 2'b11; PREADY <= 1'b1; // we are ready end end 2'b11 : begin fsm <= 2'b00; end default : fsm <= 2'b00; endcase end /* Synchonization of Asynchronous interrupt input */ always@(posedge PCLK or posedge timer_int or posedge timer_capture_sync_int) if(timer_int || timer_capture_sync_int) begin intrpt_temp <= 1'b0; intrpt_temp1 <= 1'b0; intrpt_temp2 <= 1'b0; end else begin intrpt_temp <= 1'b1; intrpt_temp1 <= intrpt_temp; intrpt_temp2 <= intrpt_temp1; end /* Pulse detection and pulse generation logic */ always@(posedge PCLK or negedge PRESETN or posedge reset_int) if(~PRESETN || reset_int) begin FABINT <= 1'b0; end else begin if(intrpt_temp1 == 1'b1 && intrpt_temp2 == 1'b0) begin FABINT <= 1'b1; end else begin FABINT <= 1'b0; end end always@(posedge TCLK or negedge PRESETN) if(~PRESETN) begin fsm_tclk <= 1'b0; reg_load_ack0 <= 1'b0; LoadEnReg <= 1'b0; TimerEn <= 1'b0; Load <= 32'h00000000; Compare <= 32'h00000000; InterruptEn <= 1'b0; CompareEn <= 1'b0; OverflowEn <= 1'b0; CaptureEn <= 1'b0; PWMEn <= 1'b0; end else begin case (fsm_tclk) 1'b0: begin if(reg_load_en2 == 1'b1) // signal from other clock domain begin if(PWRITE) begin // it's a write case(PADDR[4:2]) 3'b000: begin // Timer Load register Load <= PWDATA; LoadEnReg <= 1'b1; end 3'b001: begin // Timer Value, no write LoadEnReg <= 1'b0; end 3'b010: begin // Timer Control LoadEnReg <= 1'b0; TimerEn <= PWDATA[0]; InterruptEn <= PWDATA[1]; CompareEn <= PWDATA[2]; OverflowEn <= PWDATA[3]; PWMEn <= PWDATA[4]; CaptureEn <= PWDATA[5]; // PWDATA[6] is read only end 3'b011: begin // Compare LoadEnReg <= 1'b0; Compare <= PWDATA; end 3'b100: begin // Interrupt Status LoadEnReg <= 1'b0; end 3'b101: begin // spare LoadEnReg <= 1'b0; end 3'b110: begin // spare LoadEnReg <= 1'b0; end 3'b111: begin // spare LoadEnReg <= 1'b0; end endcase end else begin // it's a read case(PADDR[4:2]) 3'b000: begin // Timer Load register PRDATA <= Load; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; reset_int <= 1'b0; end 3'b001: begin // Timer Value, no write PRDATA <= Counter; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; reset_int <= 1'b0; end 3'b010: begin // Timer Control PRDATA[31:1] <= 27'h00000000; PRDATA[0] <= TimerEn; PRDATA[1] <= InterruptEn; PRDATA[2] <= CompareEn; PRDATA[3] <= OverflowEn; PRDATA[4] <= PWMEn; PRDATA[5] <= CaptureEn; PRDATA[6] <= CaptureOverwrite; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; reset_int <= 1'b0; end 3'b011: begin // Compare PRDATA <= Compare; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; reset_int <= 1'b0; end 3'b100: begin // Interrupt Status PRDATA[31:4] <= 30'h00000000; PRDATA[1:0] <= interrupt_status; PRDATA[2] <= capture_status; PRDATA[3] <= capture_status_async; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; reset_int <= 1'b1; end 3'b101: begin // Read CaptureSync PRDATA <= CaptureSync; reset_int <= 1'b0; reset_capture_sync <= 1'b1; reset_capture_async <= 1'b0; end 3'b110: begin // Read CaptureASync PRDATA <= CaptureASync; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b1; reset_int <= 1'b0; end 3'b111: begin // spare reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; reset_int <= 1'b0; end endcase end fsm_tclk <= 1'b1; // advance state reg_load_ack0 <= 1'b1; // signal other domain end end 1'b1: begin if (reg_load_en2 == 1'b0) begin fsm_tclk <= 1'b0; reg_load_ack0 <= 1'b0; LoadEnReg <= 1'b0; reset_int <= 1'b0; reset_capture_sync <= 1'b0; reset_capture_async <= 1'b0; end end default: fsm_tclk <= 1'b0; endcase end always@(posedge TCLK or negedge PRESETN or posedge reset_int) if(~PRESETN) begin Counter <= 32'h00000000; timer_int <= 1'b0; interrupt_status <= 2'b00; PWM1 <= 1'b0; end else begin if(reset_int) begin timer_int <= 1'b0; interrupt_status <= 32'h00000000; end else begin if(LoadEnReg == 1'b1) begin Counter <= 32'h00000000; timer_int <= 1'b0; end else if(TimerEn == 1'b1) begin if(Counter == Load) begin Counter <= 32'h00000000; PWM1 <= 1'b0; if(InterruptEn & OverflowEn) begin timer_int <= 1'b1; interrupt_status[0] <= 1'b1; end else begin timer_int <= 1'b0; end end else begin if(Counter == Compare & InterruptEn & CompareEn) begin timer_int <= 1'b1; interrupt_status[1] <= 1'b1; end else begin timer_int <= 1'b0; end if(Counter == Compare & PWMEn) begin PWM1 <= 1'b1; end Counter <= Counter + 1; end end end end always@(posedge TCLK or negedge CAPTURE) if(~CAPTURE) begin capture_intrpt_temp <= 1'b0; capture_intrpt_temp1 <= 1'b0; capture_intrpt_temp2 <= 1'b0; end else begin capture_intrpt_temp <= 1'b1; capture_intrpt_temp1 <= capture_intrpt_temp; capture_intrpt_temp2 <= capture_intrpt_temp1; end /* Pulse detection logic */ always@(posedge TCLK or negedge PRESETN or posedge reset_capture_sync) if(~PRESETN || reset_capture_sync) begin timer_capture_sync_int <= 1'b0; capture_status <= 1'b0; CaptureSync <= 32'h00000000; CaptureOverwrite <= 1'b0; end else begin if(CaptureEn && capture_intrpt_temp1 == 1'b1 && capture_intrpt_temp2 == 1'b0) begin if(capture_status) begin CaptureOverwrite <= 1'b1; end CaptureSync <= Counter; timer_capture_sync_int <= 1'b1; capture_status <= 1'b1; end else begin timer_capture_sync_int <= 1'b0; end end always@(posedge CAPTURE or negedge PRESETN or posedge reset_capture_async) if(~PRESETN || reset_capture_async) begin capture_status_async <= 1'b0; CaptureASync <= 32'h00000000; end else begin if(CaptureEn && CAPTURE && ~capture_status_async) begin capture_status_async <= 1'b1; CaptureASync <= Counter; end end always@* PWM2 <= PWM1; endmodule