⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mc8051.vhd

📁 Toplevel VHDL Structural model of a system containing 8051
💻 VHD
📖 第 1 页 / 共 5 页
字号:
    P2    <= std_logic_vector(to_high_imped(p2_latch))
                     WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED;
    P3    <= std_logic_vector(to_high_imped(p3_latch))
                     WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED;

    -- when the ctrl is asserted (by get_pmem or main) then
    -- force the addr/data value out the port
    P0    <= std_logic_vector(p0_addr)  WHEN p0_ctrl = '1' ELSE 
                     (OTHERS => 'Z');
    P2    <= std_logic_vector(p2_addr)  WHEN p2_ctrl = '1' ELSE
                     (OTHERS => 'Z');

    -- always enable the UART for mode 2
--    p3_ctrl(0) <= 'Z';
    p3_ctrl(1) <= '1';
--    P3(0)  <= rxd_internal    WHEN p3_ctrl(0) = '1' ELSE 'Z';
    rxd_internal <= P3(0);
    P3(1)  <= txd_internal    WHEN p3_ctrl(1) = '1' ELSE 'Z';

    -- whenever there is a falling edge on the interrupt pin, it will
    -- be sent to the interrupt processor (which may acknowledge or mask)
    -- for a level sensitive interrupt (it? = 0) the rising edge of the pin
    -- will clear out this internal signal.  For an edge sensitve interrupt
    -- (it? = 1) the acknowledge from the interrupt processor will clear
    int0_n_internal <= '0' WHEN falling_edge(p3(2)) ELSE
                       '1' WHEN rising_edge(p3(2)) AND it0 = '0' ELSE
                       '1' WHEN interrupt_ack = '1' AND it0 = '1' ELSE
                       int0_n_internal;

    int1_n_internal <= '0' WHEN falling_edge(p3(3)) ELSE
                       '1' WHEN rising_edge(p3(3)) AND it1 = '0' ELSE
                       '1' WHEN interrupt_ack = '1' AND it1 = '1' ELSE
                       int1_n_internal;

    t0_internal <= P3(4);
    t1_internal <= P3(5);

    P3(6)  <= wr_n_internal   WHEN p3_ctrl(6) = '1' ELSE 'Z';
    P3(7)  <= rd_n_internal   WHEN p3_ctrl(7) = '1' ELSE 'Z';
 
    --===============================================================
    --    Process Statements
    --===============================================================
    ------------------------------------------------------------------------
    -- The oscillator process will follow the XTAL clock signal and
    -- advance the current state.  The states are s1p1, s1p2, s2p1, s2p2,
    -- up to s6p1 and s6p2.
    ------------------------------------------------------------------------
    oscillator : PROCESS (XTAL1) IS
        VARIABLE last_falling_edge_time : TIME    := 0 ns;
        VARIABLE startup_count          : INTEGER := 0;
    BEGIN
        IF falling_edge(XTAL1) THEN
            IF startup_count < 3 THEN
                cycle_state <= init;
                startup_count := startup_count + 1;
                last_falling_edge_time := NOW;
            ELSE
                cycle_state <= inc(cycle_state);  -- increment the current state,
                -- and loop back from s6p2 to s1p1
                TCLCL <= NOW - last_falling_edge_time;
                last_falling_edge_time := NOW;
            END IF;
        END IF;
    END PROCESS oscillator;
 
    ------------------------------------------------------------------------
    -- The process get_pmem is responsible for reading all of the program
    -- memory (whetere internal or external) and feeding the read bytes to
    -- the process main through the signals pmem_s1_byte and pmem_s4_byte.
    -- If there has been a transaction on pc, this process will set
    -- its internal addr to the value of pc at state s4p1.  Then, if needed,
    -- it will output this addr at s5p1 and then read in the appropriate data
    -- at s1p1.  Then it increments its internal addr and will read the next
    -- byte at s4p1.  It will continue to increment the internal addr until
    -- there is another transaction on pc.
    -------------------------------------------------------------------------
    get_pmem : PROCESS(cycle_state, pc'TRANSACTION) IS
        VARIABLE addr        : INTEGER := 0;
        VARIABLE pmem        : program_mem_T;     -- the program memory
        VARIABLE prog_loaded : BOOLEAN := FALSE;  -- true after pmem is updated
        VARIABLE resync      : BOOLEAN := FALSE;  -- set true when pc changes
        VARIABLE port_to_01  : bit_vector(7 DOWNTO 0);
 
    BEGIN
        IF NOT prog_loaded THEN
            IF (ea_n = '1' or ea_n = 'H') THEN
                load_program(program_filename,pmem);
            END IF;
            -- Set default values for control lines
            psen_n <= '1';
            p0_ctrl <= 'Z';
            p2_ctrl <= 'Z';
            p0_reset <= '0';
            prog_loaded := TRUE;
        ELSE
            -- If process main has acknowledged a reset, then
            -- clear the p0 reset line.
            IF p0_reset_ack <= '1' THEN
                p0_reset <= '0';
            END IF;

            -- If there has been a transaction on pc, and it is
            -- not the initial start-up state, then flag the
            -- resync variable
            IF pc'ACTIVE THEN
                resync := TRUE;
            END IF;

            -- If the process main is trying to read a data byte
            -- from external mem, yield to it by putting ctrl's
            -- to high impedance
            IF port_req = '1' THEN
                p0_ctrl <= 'Z';
                p2_ctrl <= 'Z';
                p0_addr <= "ZZZZZZZZ";
                p2_addr <= "ZZZZZZZZ";
                ale_pm <= '0';
                psen_n <= '1';

            ELSIF reset_pmem = '1' THEN
                resync := TRUE;
                addr := 0;
            ELSIF cycle_state'ACTIVE THEN
                CASE cycle_state IS
                WHEN init =>
                    NULL;
                WHEN s1p1 =>
                -- read in the current byte from pmem
                    IF ( addr > 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
                        IF Is_X(P0) THEN
                           pmem_s1_byte <= unsigned'("00000000"); 
                           bad_data <= '1';
                        ELSE
                           port_to_01 := to_bitVector(P0);
                           pmem_s1_byte <= unsigned(to_stdlogicvector(port_to_01));
                           bad_data <= '0';
                        END IF;
                    ELSE -- fetch from internal memory
                        pmem_s1_byte <= pmem(addr);
                    END IF;
                WHEN s4p1 =>
                -- read in the current byte from pmem
                    IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
                        port_to_01 := to_bitVector(P0);
                        pmem_s4_byte <= unsigned(to_stdlogicvector(port_to_01));
                    ELSE -- fetch from internal memory
                        pmem_s4_byte <= pmem(addr);
                    END IF;
                WHEN s1p2 | s4p2 =>
                    IF resync THEN
                        addr := conv_integer(pc);
                        resync := FALSE;
                    ELSE
                        addr := addr + 1;
                    END IF;
                    -- strobe ale if next addr is external
                    -- rewrite p0_latch to all 1's
                    IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
                        ale_pm <= '1';
                        psen_n <= '1';
                        p0_reset <= '1';
                    END IF;
                WHEN s2p1 | s5p1 =>
                -- drive port 0 and port 2 if addr is external
                    IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
                        p0_addr <= conv_unsigned(addr MOD 256, 8);
                        p2_addr <= conv_unsigned(addr / 256, 8);
                        p0_ctrl <= '1';
                        p2_ctrl <= '1';
                    ELSE
                        p0_ctrl <= 'Z';
                        p2_ctrl <= 'Z';
                    END IF;
                WHEN s2p2 | s5p2 =>  -- drive ale to zero
                    IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
                        ale_pm <= '0';
                    END IF;
                WHEN s3p1 | s6p1 => -- drive psen low
                    IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
                        psen_n <= '0';
                        p0_addr <= "ZZZZZZZZ";
                    END IF;
                WHEN s3p2  | s6p2 =>
                    NULL;
                END CASE;
            END IF;
        END IF;
 
    END PROCESS get_pmem;

    ------------------------------------------------------------------------
    -- This is the main process of the microcomputer.  It will check the
    -- opcode and perform the action.
    ------------------------------------------------------------------------
    main : PROCESS
 
        VARIABLE opcode       : bVec;            -- the opcode for this cycle
        VARIABLE temp1, temp2 : bVec;            -- temp use only
        VARIABLE temp_int     : INTEGER;         -- temp use only
        VARIABLE temp_pc      : wVec;            -- temp pc storage
        VARIABLE init_done    : BOOLEAN := FALSE;
        -- set to true once the initializing is done in the first cycle
        VARIABLE ie_stored    : bVec;        -- stores ie reg when servicing an interrupt
        VARIABLE pc_int       : INTEGER;     -- only used for report
 
        -- set_sfr (set the default value of the special function registers)
        PROCEDURE set_sfr IS
        BEGIN
            acc     <= "00000000";
            b       <= "00000000";
            psw     <= "00000000";
            sp      <= "00000111";
            dpl     <= "00000000";
            dph     <= "00000000";
            p0_latch  <= "11111111";
            p1_latch  <= "11111111";
            p2_latch  <= "11111111";
            p3_latch  <= "11111111";
            ie <= "00000000";
            ip <= "00000000";
     --       pcon <= "00000000";
     --     scon, tcon, th0, th1, tl0, tl1, tmod 
        END PROCEDURE set_sfr;
 
 ------------------------------------------------Memory Handling Procedures
        -- Note that the following impure functions and procedures all use
        -- the program and/or data memory which is defined as a signal.
        -- However, when reading from addr's 80,90,A0,B0 for some will
        -- read the port directly, while others will read the ram mirror.
        -- Those that read the mirror (latch) are ANL, ORL, XRL, JBC,
        -- CPL, INC, DEC, DJNZ, MOV PX.Y, CLR PX.Y, SETB PX.Y
 
        -- get_byte_dmem will return the value of the byte at byte address
        -- depending upon if direct or indirect addressing is being used.
        -- it will also check if an event has occured on a serial control
        -- or buffer and will copy that into the ram
        IMPURE FUNCTION get_byte_dmem(
            CONSTANT addr : IN bvec;
            CONSTANT mode : IN access_type;
            CONSTANT read_latch : IN BOOLEAN := FALSE
        ) RETURN bvec IS
            VARIABLE addr_int   : INTEGER;
            VARIABLE byte_slice : bVec;
        BEGIN
            addr_int := conv_integer(addr);
            IF addr_int < 128 THEN
                byte_slice := lo_dmem(addr_int);
            ELSIF mode = indirect THEN
                byte_slice := indirect_hi_dmem(addr_int);
            ELSIF (NOT read_latch) AND (addr_int=16#80#) THEN -- read the port itself
                byte_slice := unsigned(P0);
            ELSIF (NOT read_latch) AND (addr_int=16#90#) THEN -- read the port itself
                byte_slice := unsigned(P1);
            ELSIF (NOT read_latch) AND (addr_int=16#A0#) THEN -- read the port itself
                byte_slice := unsigned(P2);
            ELSIF (NOT read_latch) AND (addr_int=16#B0#) THEN -- read the port itself
                byte_slice := unsigned(P3);
            -- read from sbuf
            ELSIF addr_int = 16#99# THEN
               byte_slice := sbuf_dup;
            ELSIF addr_int = 16#98# THEN
               byte_slice := scon_out;
            ELSE
                byte_slice := direct_hi_dmem(addr_int);
            END IF;
            RETURN(byte_slice);
        END FUNCTION get_byte_dmem;

        -- set_byte_dmem will set the value of the byte at address (addr)
        -- using the appropriate memory for direct / indirect accessing.
        PROCEDURE set_byte_dmem(
            CONSTANT addr : IN bvec;
            CONSTANT val  : IN bVec;
            CONSTANT mode : IN access_type
        ) IS
            VARIABLE addr_int   : INTEGER;
        BEGIN
            addr_int := conv_integer(addr);
            IF addr_int < 128 THEN
                lo_dmem(addr_int) <= val;
            ELSIF mode = indirect THEN
                indirect_hi_dmem(addr_int) <= val;
            -- write to sbuf
            ELSIF addr_int = 16#99# THEN
               addr_gb <= "10011001";
               data_gb <= val;
               wr_gb <= '1';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -