`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 26.09.2019 10:50:36
// Design Name: 
// Module Name: port
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module port(
    input clock,
    input reset,
    input wr_en,
    input rd_en,
    input en_IDR,
    input en_ODR,
    input en_MODER,
    inout [15:0] pin,
    inout [31:0] data_bus
);

    reg [15:0] IDR;
    reg [15:0] ODR;
    reg [31:0] MODER;


    // IDR register
    integer i;
    always@(posedge clock or posedge reset)
        if(reset)
            IDR <= 16'b0;
        else
            for(i=0; i<16; i=i+1)
                if(!MODER[i*2])
                    IDR[i] <= pin[i];
    
    // ODR register
    always@(posedge clock or posedge reset)
        if(reset)
            ODR <= 16'b0;
        else
            if(wr_en && en_ODR)
                ODR <= data_bus;
 
    // MODER register 
    always@(posedge clock or posedge reset)
        if(reset)
            MODER <= 32'b0;
        else
            if(wr_en && en_MODER)
                MODER <= data_bus;
     
    // bus management
    assign data_bus = (rd_en && en_IDR) ? {16'b0,IDR} : 32'bz;
    assign data_bus = (rd_en && en_ODR) ? {16'b0,ODR} : 32'bz;
    assign data_bus = (rd_en && en_MODER) ? MODER : 32'bz;
     
    // pins management
    assign pin[0] = MODER[0*2] ? ODR[0] : 1'bz;
    assign pin[1] = MODER[1*2] ? ODR[1] : 1'bz;
    assign pin[2] = MODER[2*2] ? ODR[2] : 1'bz;
    assign pin[3] = MODER[3*2] ? ODR[3] : 1'bz;
    assign pin[4] = MODER[4*2] ? ODR[4] : 1'bz;
    assign pin[5] = MODER[5*2] ? ODR[5] : 1'bz;
    assign pin[6] = MODER[6*2] ? ODR[6] : 1'bz;
    assign pin[7] = MODER[7*2] ? ODR[7] : 1'bz;
    assign pin[8] = MODER[8*2] ? ODR[8] : 1'bz;
    assign pin[9] = MODER[9*2] ? ODR[9] : 1'bz;
    assign pin[10] = MODER[10*2] ? ODR[10] : 1'bz;
    assign pin[11] = MODER[11*2] ? ODR[11] : 1'bz;
    assign pin[12] = MODER[12*2] ? ODR[12] : 1'bz;
    assign pin[13] = MODER[13*2] ? ODR[13] : 1'bz;
    assign pin[14] = MODER[14*2] ? ODR[14] : 1'bz;
    assign pin[15] = MODER[15*2] ? ODR[15] : 1'bz;
                
endmodule
