axi_laser_driver: Initial commit

The laser driver contains the axi_pulse_gen's IP and an additional
register map which controls/monitor the laser driver enable control line
and the over temperature warning line (OTW).

It also contains an interrupt logic, which allows to generate an
interrupt in function of the generated pulse or incoming OTW signal.

The IPs register maps looks as follow:

0x00 - axi_pulse_gen register map
0x80 - axi_laser_driver register map
  0x80 - DRIVER_ENABLE
  0x84 - DRIVER_OTW
  0x88 - EXT_CLK_COUNTER
  0xA0 - IRQ_MASK
  0xA4 - IRQ_SOURCE
  0xA8 - IRQ_PENDING
  0xAC - SEQUENCER_CONTROL
         0 - SEQUENCER_ENABLE
         1 - AUTO_SEQUENCER_ENABLED
  0xB0 - SEQUENCER_SYNC_OFFSET
  0xB4 - AUTO_SEQUENCE
         [ 1: 0] - CHANNEL_SEL_0
         [ 5: 4] - CHANNEL_SEL_1
         [ 9: 8] - CHANNEL_SEL_2
         [13:12] - CHANNEL_SEL_3
  0xB8 - MANUAL_SEQUENCE
         [ 1: 0] - MANUAL_CHANNEL_SEL

Current interrupt sources scheme is:
    - bit 0 : pulse (triggered by the level of the pulse)
    - bit 1 : OTW_N enter (triggered by positive edge of the OTW_N)
    - bit 2 : OTW_N exit (triggered by the level of the pulse)

Generate a reset signal before the pulse which can be used to reset
various IP's of the data path (eg. pack/cpack). This can help to clear out the
internal buffers and registers of these IP, starting clean at the moment when
the actual pulse arrives.

The sequencer has an auto and a manual mode, and can be set to custom
sequences of the TIA channel selection lines sate.

The sequencer in auto mode is synchronized to the pulse, it will change
its state before a generated pulse which will drive the lasers. The
offset between the sequencer beat and the laser driver pulse can be
modified through an AXI register.
main
Istvan Csomortani 2019-03-19 12:05:14 +00:00 committed by István Csomortáni
parent d4200aee9a
commit 75d1379618
6 changed files with 707 additions and 0 deletions

View File

@ -45,6 +45,7 @@ clean:
$(MAKE) -C axi_hdmi_tx clean
$(MAKE) -C axi_i2s_adi clean
$(MAKE) -C axi_intr_monitor clean
$(MAKE) -C axi_laser_driver clean
$(MAKE) -C axi_logic_analyzer clean
$(MAKE) -C axi_mc_controller clean
$(MAKE) -C axi_mc_current_monitor clean
@ -157,6 +158,7 @@ lib:
$(MAKE) -C axi_hdmi_tx
$(MAKE) -C axi_i2s_adi
$(MAKE) -C axi_intr_monitor
$(MAKE) -C axi_laser_driver
$(MAKE) -C axi_logic_analyzer
$(MAKE) -C axi_mc_controller
$(MAKE) -C axi_mc_current_monitor

View File

@ -0,0 +1,18 @@
####################################################################################
## Copyright 2018(c) Analog Devices, Inc.
## Auto-generated, do not modify!
####################################################################################
LIBRARY_NAME := axi_laser_driver
GENERIC_DEPS += ../common/up_clock_mon.v
GENERIC_DEPS += axi_laser_driver.v
GENERIC_DEPS += axi_laser_driver_regmap.v
XILINX_DEPS += axi_laser_driver_constr.xdc
XILINX_DEPS += axi_laser_driver_ip.tcl
XILINX_LIB_DEPS += axi_pulse_gen
XILINX_LIB_DEPS += util_cdc
include ../scripts/library.mk

View File

@ -0,0 +1,301 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2019 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core 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.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module axi_laser_driver #(
parameter ID = 0,
parameter [0:0] ASYNC_CLK_EN = 1,
parameter PULSE_WIDTH = 7,
parameter PULSE_PERIOD = 10 )(
// axi interface
input s_axi_aclk,
input s_axi_aresetn,
input s_axi_awvalid,
input [15:0] s_axi_awaddr,
input [ 2:0] s_axi_awprot,
output s_axi_awready,
input s_axi_wvalid,
input [31:0] s_axi_wdata,
input [ 3:0] s_axi_wstrb,
output s_axi_wready,
output s_axi_bvalid,
output [ 1:0] s_axi_bresp,
input s_axi_bready,
input s_axi_arvalid,
input [15:0] s_axi_araddr,
input [ 2:0] s_axi_arprot,
output s_axi_arready,
output s_axi_rvalid,
output [ 1:0] s_axi_rresp,
output [31:0] s_axi_rdata,
input s_axi_rready,
// external clock and control/status signals
input ext_clk,
output driver_en_n,
output driver_pulse,
input driver_otw_n,
output driver_dp_reset,
output reg [ 1:0] tia_chsel,
// interrupt
output irq);
// internal signals
reg up_wack = 1'b0;
reg up_rack = 1'b0;
reg [31:0] up_rdata = 32'b0;
reg driver_pulse_int_d = 1'b0;
reg [ 1:0] sequence_counter = 2'b00;
// internal signals
wire clk;
wire up_clk;
wire up_rstn;
wire up_rreq_s;
wire up_rack_ld_s;
wire up_rack_pwm_s;
wire [13:0] up_raddr_s;
wire [31:0] up_rdata_ld_s;
wire [31:0] up_rdata_pwm_s;
wire up_wreq_s;
wire up_wack_ld_s;
wire up_wack_pwm_s;
wire [13:0] up_waddr_s;
wire [31:0] up_wdata_s;
wire [31:0] pulse_width_s;
wire [31:0] pulse_period_s;
wire load_config_s;
wire pulse_gen_resetn;
wire [31:0] pulse_counter_s;
wire driver_pulse_int_s;
wire [31:0] up_ext_clk_count_s;
wire sequence_en_s;
wire auto_sequence_s;
wire [31:0] sequence_offset_s;
wire [ 1:0] auto_seq0_s;
wire [ 1:0] auto_seq1_s;
wire [ 1:0] auto_seq2_s;
wire [ 1:0] auto_seq3_s;
wire [ 1:0] manual_select_s;
// local parameters
localparam [31:0] CORE_VERSION = {16'h0001, /* MAJOR */
8'h00, /* MINOR */
8'h61}; /* PATCH */ // 1.00.a
localparam [31:0] CORE_MAGIC = 32'h4C534452; // LSDR
assign up_clk = s_axi_aclk;
assign up_rstn = s_axi_aresetn;
// register maps
axi_pulse_gen_regmap #(
.ID (ID),
.CORE_MAGIC (CORE_MAGIC),
.CORE_VERSION (CORE_VERSION),
.ASYNC_CLK_EN (ASYNC_CLK_EN),
.PULSE_WIDTH (PULSE_WIDTH),
.PULSE_PERIOD (PULSE_PERIOD))
i_pwm_regmap (
.ext_clk (ext_clk),
.clk_out (clk),
.pulse_gen_resetn (pulse_gen_resetn),
.pulse_width (pulse_width_s),
.pulse_period (pulse_period_s),
.load_config (load_config_s),
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack_pwm_s),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata_pwm_s),
.up_rack (up_rack_pwm_s));
axi_laser_driver_regmap #(
.ID (ID),
.LASER_DRIVER_ID (1))
i_laser_driver_regmap (
.clk (clk),
.driver_en_n (driver_en_n),
.driver_otw_n (driver_otw_n),
.pulse (driver_pulse_int_s),
.up_ext_clk_count (up_ext_clk_count_s),
.irq (irq),
.sequence_en (sequence_en_s),
.auto_sequence (auto_sequence_s),
.sequence_offset (sequence_offset_s),
.auto_seq0 (auto_seq0_s),
.auto_seq1 (auto_seq1_s),
.auto_seq2 (auto_seq2_s),
.auto_seq3 (auto_seq3_s),
.manual_select (manual_select_s),
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack_ld_s),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata_ld_s),
.up_rack (up_rack_ld_s));
// read interface merge
always @(posedge up_clk) begin
if (up_rstn == 0) begin
up_wack <= 'd0;
up_rack <= 'd0;
up_rdata <= 'd0;
end else begin
up_wack <= up_wack_ld_s | up_wack_pwm_s;
up_rack <= up_rack_ld_s | up_rack_pwm_s;
up_rdata <= up_rdata_ld_s | up_rdata_pwm_s;
end
end
// generic PWM generator's
util_pulse_gen #(
.PULSE_WIDTH(PULSE_WIDTH),
.PULSE_PERIOD(PULSE_PERIOD))
i_laser_driver_pulse (
.clk (clk),
.rstn (pulse_gen_resetn),
.pulse_width (pulse_width_s),
.pulse_period (pulse_period_s),
.load_config (load_config_s),
.pulse (driver_pulse_int_s),
.pulse_counter (pulse_counter_s));
// data path reset generation
// this logic will generate a reset signal right before the generated pulse
// in order to use it for resetting the cpack module, to synchronize it to
// the driver pulse
always @(posedge clk) begin
driver_pulse_int_d <= driver_pulse_int_s;
end
assign driver_dp_reset = driver_pulse_int_s & ~driver_pulse_int_d;
assign driver_pulse = driver_pulse_int_d;
// clock monitor for the external clock
up_clock_mon i_clock_mon (
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_d_count (up_ext_clk_count_s),
.d_rst (~pulse_gen_resetn),
.d_clk (ext_clk));
// TIA sequencer
always @(posedge clk) begin
if (sequence_en_s == 1'b0) begin
sequence_counter <= 2'b00;
end else begin
if (pulse_counter_s == sequence_offset_s) begin
if (auto_sequence_s) begin
sequence_counter <= sequence_counter + 1'b1;
end
end
end
end
always @(posedge clk) begin
if (sequence_en_s == 1'b0) begin
tia_chsel <= 2'b0;
end else begin
if (pulse_counter_s == sequence_offset_s) begin
if (auto_sequence_s) begin
case (sequence_counter)
2'b00 : tia_chsel <= auto_seq0_s;
2'b01 : tia_chsel <= auto_seq1_s;
2'b10 : tia_chsel <= auto_seq2_s;
2'b11 : tia_chsel <= auto_seq3_s;
default : tia_chsel <= 2'b00;
endcase
end else begin
tia_chsel <= manual_select_s;
end
end
end
end
// AXI Memory Mapped Wrapper
up_axi #(
.ADDRESS_WIDTH(14))
i_up_axi (
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_axi_awvalid (s_axi_awvalid),
.up_axi_awaddr (s_axi_awaddr),
.up_axi_awready (s_axi_awready),
.up_axi_wvalid (s_axi_wvalid),
.up_axi_wdata (s_axi_wdata),
.up_axi_wstrb (s_axi_wstrb),
.up_axi_wready (s_axi_wready),
.up_axi_bvalid (s_axi_bvalid),
.up_axi_bresp (s_axi_bresp),
.up_axi_bready (s_axi_bready),
.up_axi_arvalid (s_axi_arvalid),
.up_axi_araddr (s_axi_araddr),
.up_axi_arready (s_axi_arready),
.up_axi_rvalid (s_axi_rvalid),
.up_axi_rresp (s_axi_rresp),
.up_axi_rdata (s_axi_rdata),
.up_axi_rready (s_axi_rready),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata),
.up_rack (up_rack));
endmodule

View File

@ -0,0 +1,20 @@
set_property ASYNC_REG TRUE \
[get_cells -hier {*cdc_sync_stage1_reg*}] \
[get_cells -hier {*cdc_sync_stage2_reg*}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_driver_otw_sync/cdc_sync_stage1_reg[0]/D}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_pulse_sync/cdc_sync_stage1_reg[0]/D}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_sequencer_sync/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_sequence_offset_sync/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_sequence_control_sync/cdc_sync_stage1_reg[*]/D}]

View File

@ -0,0 +1,96 @@
# ip
source ../scripts/adi_env.tcl
source $ad_hdl_dir/library/scripts/adi_ip.tcl
adi_ip_create axi_laser_driver
adi_ip_files axi_laser_driver [list \
"$ad_hdl_dir/library/common/up_clock_mon.v" \
"axi_laser_driver_constr.xdc" \
"axi_laser_driver_regmap.v" \
"axi_laser_driver.v"]
adi_ip_properties axi_laser_driver
adi_ip_ttcl axi_laser_driver "$ad_hdl_dir/library/axi_pulse_gen/axi_pulse_gen_constr.ttcl"
adi_ip_add_core_dependencies { \
analog.com:user:util_cdc:1.0 \
analog.com:user:axi_pulse_gen:1.0 \
}
set cc [ipx::current_core]
set_property display_name "ADI AXI Laser Driver" $cc
set_property description "ADI AXI Laser Driver" $cc
## define ext_clk port as a clock interface
adi_add_bus ext_clk slave \
"xilinx.com:signal:clock_rtl:1.0" \
"xilinx.com:signal:clock:1.0" \
[list {"ext_clk" "CLK"} ]
adi_set_ports_dependency "ext_clk" \
"(spirit:decode(id('MODELPARAM_VALUE.ASYNC_CLK_EN')) = 1)" 0
## Parameter validation
set_property -dict [list \
"value_format" "bool" \
"value" "true" \
] \
[ipx::get_user_parameters ASYNC_CLK_EN -of_objects $cc]
set_property -dict [list \
"value_format" "bool" \
"value" "true" \
] \
[ipx::get_hdl_parameters ASYNC_CLK_EN -of_objects $cc]
set_property -dict [list \
"value_validation_type" "range_long" \
"value_validation_range_minimum" "0" \
"value_validation_range_maximum" "2147483647" \
] \
[ipx::get_user_parameters PULSE_WIDTH -of_objects $cc]
set_property -dict [list \
"value_validation_type" "range_long" \
"value_validation_range_minimum" "0" \
"value_validation_range_maximum" "2147483647" \
] \
[ipx::get_user_parameters PULSE_PERIOD -of_objects $cc]
## Customize XGUI layout
## Remove the automatically generated GUI page
ipgui::remove_page -component $cc [ipgui::get_pagespec -name "Page 0" -component $cc]
ipx::save_core $cc
## Create a new GUI page
ipgui::add_page -name {AXI Pulse Generator} -component $cc -display_name {AXI Pulse Generator}
set page0 [ipgui::get_pagespec -name "AXI Pulse Generator" -component $cc]
ipgui::add_param -name "ASYNC_CLK_EN" -component $cc -parent $page0
set_property -dict [list \
"display_name" "ASYNC_CLK_EN" \
"tooltip" "External clock for the counter" \
"widget" "checkBox" \
] [ipgui::get_guiparamspec -name "ASYNC_CLK_EN" -component $cc]
ipgui::add_param -name "PULSE_WIDTH" -component $cc -parent $page0
set_property -dict [list \
"display_name" "Pulse width" \
"tooltip" "Pulse width of the generated signal. The unit interval is the system or external clock period." \
] [ipgui::get_guiparamspec -name "PULSE_WIDTH" -component $cc]
ipgui::add_param -name "PULSE_PERIOD" -component $cc -parent $page0
set_property -dict [list \
"display_name" "Pulse period" \
"tooltip" "Period of the generated signal. The unit interval is the system or external clock period." \
] [ipgui::get_guiparamspec -name "PULSE_PERIOD" -component $cc]
## Save the modifications
ipx::create_xgui_files $cc
ipx::save_core $cc

View File

@ -0,0 +1,270 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2019 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core 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.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module axi_laser_driver_regmap #(
parameter ID = 0,
parameter LASER_DRIVER_ID = 1 )(
// control and status signals
input clk,
output driver_en_n,
input driver_otw_n,
input pulse,
output reg irq,
input [31:0] up_ext_clk_count,
// TIA sequencer
output sequence_en,
output auto_sequence,
output [31:0] sequence_offset,
output [ 1:0] auto_seq0,
output [ 1:0] auto_seq1,
output [ 1:0] auto_seq2,
output [ 1:0] auto_seq3,
output [ 1:0] manual_select,
// processor interface
input up_rstn,
input up_clk,
input up_wreq,
input [13:0] up_waddr,
input [31:0] up_wdata,
output reg up_wack,
input up_rreq,
input [13:0] up_raddr,
output reg [31:0] up_rdata,
output reg up_rack
);
// internal registers
reg up_driver_en_n = 1'b0;
reg [2:0] up_irq_mask = 3'b111;
reg [2:0] up_irq_source = 3'b000;
reg up_driver_otw_n_int = 1'b1;
reg up_sequence_en = 1'b0;
reg up_auto_sequence = 1'b1;
reg [31:0] up_sequence_offset = 32'b1;
reg [ 1:0] up_auto_seq0 = 2'b00;
reg [ 1:0] up_auto_seq1 = 2'b01;
reg [ 1:0] up_auto_seq2 = 2'b10;
reg [ 1:0] up_auto_seq3 = 2'b11;
reg [ 1:0] up_manual_select = 2'b00;
// internal signals
wire up_wreq_int_s;
wire up_rreq_int_s;
wire up_driver_otw_n_s;
wire [2:0] up_irq_pending_s;
wire [2:0] up_irq_trigger_s;
wire [2:0] up_irq_source_clear_s;
wire up_driver_otw_n_enter_s;
wire up_driver_otw_n_exit_s;
// map the laser driver registers into the address space
assign up_wreq_int_s = (up_waddr[13:5] == LASER_DRIVER_ID) ? up_wreq : 1'b0;
assign up_rreq_int_s = (up_raddr[13:5] == LASER_DRIVER_ID) ? up_rreq : 1'b0;
always @(posedge up_clk) begin
if (up_rstn == 0) begin
up_wack <= 1'b0;
up_driver_en_n <= 1'b1; // by default laser is disabled
up_irq_mask <= 3'b111;
up_sequence_en <= 1'b0;
up_auto_sequence <= 1'b1;
up_sequence_offset <= 32'b0;
up_auto_seq0 <= 2'b00;
up_auto_seq1 <= 2'b01;
up_auto_seq2 <= 2'b10;
up_auto_seq3 <= 2'b11;
up_manual_select <= 2'b00;
end else begin
up_wack <= up_wreq_int_s;
if ((up_wreq_int_s == 1'b1) && (up_waddr[3:0] == 4'h0)) begin
up_driver_en_n <= up_wdata[0];
end
if ((up_wreq_int_s == 1'b1) && (up_waddr[3:0] == 4'h8)) begin
up_irq_mask <= up_wdata[2:0];
end
if ((up_wreq_int_s == 1'b1) && (up_waddr[3:0] == 4'hB)) begin
up_sequence_en <= up_wdata[0];
up_auto_sequence <= up_wdata[1];
end
if ((up_wreq_int_s == 1'b1) && (up_waddr[3:0] == 4'hC)) begin
up_sequence_offset <= up_wdata;
end
if ((up_wreq_int_s == 1'b1) && (up_waddr[3:0] == 4'hD)) begin
up_auto_seq0 <= up_wdata[1:0];
up_auto_seq1 <= up_wdata[5:4];
up_auto_seq2 <= up_wdata[9:8];
up_auto_seq3 <= up_wdata[13:12];
end
if ((up_wreq_int_s == 1'b1) && (up_waddr[3:0] == 4'hE)) begin
up_sequence_offset <= up_wdata[1:0];
end
end
end
always @(posedge up_clk) begin
if (up_rstn == 0) begin
up_rack <= 1'b0;
up_rdata <= 32'b0;
end else begin
up_rack <= up_rreq_int_s;
if (up_rreq_int_s == 1'b1) begin
case (up_raddr[4:0])
5'h00: up_rdata <= {31'h0, up_driver_en_n};
5'h01: up_rdata <= {31'h0, up_driver_otw_n_s};
5'h02: up_rdata <= up_ext_clk_count;
5'h08: up_rdata <= {29'h0, up_irq_mask};
5'h09: up_rdata <= {29'h0, up_irq_source};
5'h0A: up_rdata <= {29'h0, up_irq_pending_s};
5'h0B: up_rdata <= {30'h0, up_auto_sequence, up_sequence_en};
5'h0C: up_rdata <= up_sequence_offset;
5'h0D: up_rdata <= {16'h0, up_auto_seq3, 2'b0, up_auto_seq2, 2'b0, up_auto_seq1, 2'b0, up_auto_seq0};
5'h0E: up_rdata <= {30'h0, up_manual_select};
default: up_rdata <= 0;
endcase
end else begin
up_rdata <= 32'd0;
end
end
end
assign driver_en_n = up_driver_en_n;
always @(posedge up_clk) begin
up_driver_otw_n_int <= up_driver_otw_n_s;
end
// negative edge of otw_n - system enters into an over temperature state
assign up_driver_otw_n_enter_s = ~up_driver_otw_n_s & up_driver_otw_n_int;
// positive edge of otw_n - system exits from an over temperature state
assign up_driver_otw_n_exit_s = up_driver_otw_n_s & ~up_driver_otw_n_int;
// Interrupt handling - it can be generated by a generated pulse or an over
// temperature warning signal
assign up_irq_pending_s = ~up_irq_mask & up_irq_source;
assign up_irq_trigger_s = {up_driver_otw_n_exit_s, up_driver_otw_n_enter_s, up_pulse};
assign up_irq_source_clear_s = (up_wreq_int_s == 1'b1 && up_waddr[3:0] == 4'hA) ? up_wdata[2:0] : 3'b000;
always @(posedge up_clk) begin
if (up_rstn == 1'b0) begin
irq <= 1'b0;
end else begin
irq <= |up_irq_pending_s;
end
end
always @(posedge up_clk) begin
if (up_rstn == 1'b0) begin
up_irq_source <= 3'b000;
end else begin
up_irq_source <= up_irq_trigger_s | (up_irq_source & ~up_irq_source_clear_s);
end
end
// CDC logic
sync_bits #(
.NUM_OF_BITS (1),
.ASYNC_CLK (1))
i_driver_otw_sync (
.in_bits (driver_otw_n),
.out_clk (up_clk),
.out_resetn (1'b1),
.out_bits (up_driver_otw_n_s));
sync_bits #(
.NUM_OF_BITS (1),
.ASYNC_CLK (1))
i_pulse_sync (
.in_bits (pulse),
.out_clk (up_clk),
.out_resetn (1'b1),
.out_bits (up_pulse));
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_sequence_control_sync (
.in_bits ({up_auto_sequence, up_sequence_en}),
.out_clk (clk),
.out_resetn (1'b1),
.out_bits ({auto_sequence, sequence_en}));
sync_bits #(
.NUM_OF_BITS (10),
.ASYNC_CLK (1))
i_sequencer_sync (
.in_bits ({up_auto_seq3,
up_auto_seq2,
up_auto_seq1,
up_auto_seq0,
up_manual_select
}),
.out_clk (clk),
.out_resetn (1'b1),
.out_bits ({auto_seq3,
auto_seq2,
auto_seq1,
auto_seq0,
manual_select
}));
sync_bits #(
.NUM_OF_BITS (32),
.ASYNC_CLK (1))
i_sequence_offset_sync (
.in_bits (up_sequence_offset),
.out_clk (clk),
.out_resetn (1'b1),
.out_bits (sequence_offset));
endmodule