`resetall
`timescale 1ns / 1ps
`default_nettype none

module util_reg #
(
    parameter integer AXI_ADDR_WIDTH	= 32,
    parameter integer AXI_DATA_WIDTH	= 32    
)
(
    // AXI4L Config Interface
    axi4l_intf.slave    ctrl_if,

    output wire [31:0]  gpo,
    input  wire [31:0]  gpi,
	output wire         fan_pwm,
	input  wire [31:0]  datecode,
	input  wire [31:0]  timecode
);

// ------------------------------
// AXIL Decode
// ------------------------------
wire [AXI_ADDR_WIDTH-1 : 0]		raddr;
wire [AXI_ADDR_WIDTH-1 : 0]		waddr;
wire 						    rden;
wire 						    wren;
wire [AXI_DATA_WIDTH-1 : 0]		wdata;
reg [AXI_DATA_WIDTH-1 : 0]		rdata;


axil_slave 
# (
	.DATA_WIDTH(AXI_DATA_WIDTH),
	.ADDR_WIDTH(AXI_ADDR_WIDTH)
) axil_slave_i 
(
	// AXIL Slave
	.S_AXI_ACLK(ctrl_if.clk),
	.S_AXI_ARESETN(ctrl_if.resetn),
	.S_AXI_AWADDR(ctrl_if.awaddr),
	.S_AXI_AWPROT(ctrl_if.awprot),
	.S_AXI_AWVALID(ctrl_if.awvalid),
	.S_AXI_AWREADY(ctrl_if.awready),
	.S_AXI_WDATA(ctrl_if.wdata),
	.S_AXI_WSTRB(ctrl_if.wstrb),
	.S_AXI_WVALID(ctrl_if.wvalid),
	.S_AXI_WREADY(ctrl_if.wready),
	.S_AXI_BRESP(ctrl_if.bresp),
	.S_AXI_BVALID(ctrl_if.bvalid),
	.S_AXI_BREADY(ctrl_if.bready),
	.S_AXI_ARADDR(ctrl_if.araddr),
	.S_AXI_ARPROT(ctrl_if.arprot),
	.S_AXI_ARVALID(ctrl_if.arvalid),
	.S_AXI_ARREADY(ctrl_if.arready),
	.S_AXI_RDATA(ctrl_if.rdata),
	.S_AXI_RRESP(ctrl_if.rresp),
	.S_AXI_RVALID(ctrl_if.rvalid),
	.S_AXI_RREADY(ctrl_if.rready),	
	
	.raddr(raddr),
	.waddr(waddr),
	.wren(wren),
	.rden(rden),
	.wdata(wdata),
	.rdata(rdata)
);

// ------------------------------
// Config Registers
// ------------------------------
wire reset;
assign reset = ~ctrl_if.resetn;
reg [31:0]  scratch;
reg [31:0]  reg_gpo; 
reg [24:0]  pwm_period; 
reg [24:0]  pwm_pulsewidth; 


always @ (posedge ctrl_if.clk) begin
    if (~ctrl_if.resetn) begin
    scratch <= 0;
    reg_gpo <= 0;
    pwm_period <= 1500000;
    pwm_pulsewidth <= 500000;
    end else begin
        if (wren) begin
            if ( waddr[15:0] == 'h004 ) 
                scratch <= wdata;
            if ( waddr[15:0] == 'h008 ) 
                reg_gpo <= wdata;
            if ( waddr[15:0] == 'h010 ) 
                pwm_period <= wdata;
            if ( waddr[15:0] == 'h014 ) 
                pwm_pulsewidth <= wdata;
        end
    end
end   



always @ (posedge ctrl_if.clk) begin
    if (rden) begin
        if (raddr[11:0] == 'h000)
            rdata <= 'h12345678;
        if (raddr[11:0] == 'h004)
            rdata <= scratch;
        if (raddr[11:0] == 'h008)
            rdata <= reg_gpo;        
        if (raddr[11:0] == 'h00C)
            rdata <= gpi;           
        if (raddr[11:0] == 'h010)
            rdata <= pwm_period;       
        if (raddr[11:0] == 'h014)
            rdata <= pwm_pulsewidth;    
        if (raddr[11:0] == 'h100)
            rdata <= datecode;       
        if (raddr[11:0] == 'h104)
            rdata <= timecode;                                                                                                   
    end
end

assign gpo = reg_gpo;

// ------------------------------
// Fan PWM
// ------------------------------
reg [24:0]  pwm_cnt; 
reg pwm_out;

assign fan_pwm = ~pwm_out;

always @ (posedge ctrl_if.clk) begin
	if (pwm_cnt < pwm_period) begin
		pwm_cnt <= pwm_cnt + 1;
	end else begin
		pwm_cnt <= 0;
	end

	if (pwm_cnt < pwm_pulsewidth) begin
		pwm_out <= 1'b1;
	end else begin
		pwm_out <= 1'b0;
	end

end


endmodule


`resetall