Altera Code for 8-bit Input/Output Port


SUBDESIGN ea_io
(
    E               :  INPUT;   % E-Clock %
    R_W             :  INPUT;   % R/W Line %
    RESETn          :  INPUT;   % Reset line %

    PA[7..0]        :  BIDIR;   % Address and Data (15-8) from HC12 %
    PB[7..0]        :  BIDIR;   % Address and Data (7-0) from HC12 %

    EA[7..0]        :  BIDIR;   % Expansion Port A %
)


VARIABLE
    demux[15..0]    :  DFF;    % Demuliplexed address internal %

    IDB[7..0]       :  NODE;   % Internal data bus %

    EAI[7..0]       :  DFFE;   % Internal expansion Port A register %
    CTRLE0          :  DFFE;   % Bit to make EA an output port (DDRA bit) %
    PA_OE           :  NODE;   % High when we want to send data to HC12 on %
                               % the HC12's Port A %
BEGIN

% ***********************************************************************%
% Address decoding and demultiplexing                                    %
% Latch address on rising edge of E clock                                %
% ***********************************************************************%

    demux[15..8].d = PA[7..0];
    demux[7..0].d = PB[7..0];
    demux[15..0].clk = E; 
    
% ***********************************************************************%
% Start of expansion ports                                               %
% ***********************************************************************%

%   A write to address 0x0400 writes to the internal EA flip flops %
%   Writes take place on the falling edge of E clock %

    EAI[].clk = !E;
    EAI[].ena = (demux[15..0].q == H"0400") & (R_W == GND);
    EAI[].d   = PA[];
    EAI[].clrn = RESETn; 

%   A write to address 0x0402 writes to expansion control register %

    CTRLE0.clk = !E;
    CTRLE0.ena = (demux[15..0].q == H"0402") & (R_W == GND);
    CTRLE0.d   = PA0;
    CTRLE0.clrn = RESETn;

%   If Bit 0 of CTRLE is 1, EA is an output port; drive data from the %
%   internal register onto the EA lines %
%   If Bit 0 of CTRLE is 0, EA reads data from outside %

    EA[7] = TRI(EAI[7], CTRLE0);
    EA[6] = TRI(EAI[6], CTRLE0);
    EA[5] = TRI(EAI[5], CTRLE0);
    EA[4] = TRI(EAI[4], CTRLE0);
    EA[3] = TRI(EAI[3], CTRLE0);
    EA[2] = TRI(EAI[2], CTRLE0);
    EA[1] = TRI(EAI[1], CTRLE0);
    EA[0] = TRI(EAI[0], CTRLE0);

%  A read from address 0x0400 reads the expansion port A %
%  A read from address 0x0402 reads the expansion control register %
%  Put the data from the expansion ports or control regiser onto the %
%  internal data bus Otherwise, put 0x00 onto the internal data bus %

    IF (demux[15..0].q == H"0400") THEN
            IDB[7..0] = EA[7..0];
    ELSIF (demux[15..0].q == H"0402") THEN
            IDB[7..1] = 0;
            IDB[0] = CTRLE0.q;
    ELSE
            IDB[7..0] = H"0000";
    END IF;

%  If reading from address 0x0400 or 0x0402, we need to drive the %
%  Port A lines when E is high %

    IF (R_W==VCC) & (E == VCC) &
       ((demux[15..0].q == H"0400") # (demux[15..0].q == H"0402"))
    THEN
           PA_OE = VCC;
    ELSE
           PA_OE = GND;
    END IF;

%  Here's where we put the internal data bus values onto Port A %

    PA[7] = TRI(IDB[7], PA_OE);
    PA[6] = TRI(IDB[6], PA_OE);
    PA[5] = TRI(IDB[5], PA_OE);
    PA[4] = TRI(IDB[4], PA_OE);
    PA[3] = TRI(IDB[3], PA_OE);
    PA[2] = TRI(IDB[2], PA_OE);
    PA[1] = TRI(IDB[1], PA_OE);
    PA[0] = TRI(IDB[0], PA_OE);

END;