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

📄 mc8051.vhd

📁 Toplevel VHDL Structural model of a system containing 8051
💻 VHD
📖 第 1 页 / 共 5 页
字号:
               WAIT UNTIL acknow = '1';
               wr_gb <= 'L';
               addr_gb <= "ZZZZZZZZ";
               data_gb <= "ZZZZZZZZ";
            -- write to scon
            ELSIF addr_int = 16#98# THEN
               direct_hi_dmem(addr_int) <= val;
               addr_gb <= "10011000";
               data_gb <= val;
               wr_gb <= '1';
               WAIT UNTIL acknow = '1';
               wr_gb <= 'L';
               addr_gb <= "ZZZZZZZZ";
               data_gb <= "ZZZZZZZZ";
            -- write to timer1H
            ELSIF addr_int = 16#8D# THEN
                timer1H <= val;
                direct_hi_dmem(addr_int) <= val;
            ELSE             
                direct_hi_dmem(addr_int) <= val;
            END IF;
        END PROCEDURE set_byte_dmem;

        -- get_reg will get the value of register (number) based upon
        -- the current bank number as defined in register select (rs)
        IMPURE FUNCTION get_reg(
            CONSTANT number : IN unsigned(2 DOWNTO 0)
        ) RETURN bVec IS
            VARIABLE addr : bvec;
        BEGIN
            addr := unsigned'("000") & rs & number;
            RETURN get_byte_dmem(addr, direct); 
        END FUNCTION get_reg;
 
        -- set_reg will set the value of register (number) based upon
        -- the current bank number as defined in register select (rs)
        PROCEDURE set_reg(
            CONSTANT number : IN unsigned(2 DOWNTO 0);
            CONSTANT value  : IN bVec
        ) IS
            VARIABLE addr  : bvec;
        BEGIN
            addr := unsigned'("000") & rs & number;
            set_byte_dmem(addr, value, direct);
        END PROCEDURE set_reg;

        -- get_bit_dmem will return the value of the bit at bit address (addr)
        -- will always use direct mem
        IMPURE FUNCTION get_bit_dmem(
            CONSTANT addr : IN bVec;
            CONSTANT read_latch : IN BOOLEAN := FALSE
        ) RETURN std_logic IS
            VARIABLE byte_slice : bVec;
            VARIABLE addr1      : bVec; 
        BEGIN
            IF addr(7) = '0' THEN  -- if addr < 16#80 THEN
                addr1 := unsigned'("0010") & addr(6 DOWNTO 3); 
            ELSIF addr(7) = '1' THEN  -- if addr > 16#80 THEN
                addr1 := addr(7 DOWNTO 3) & unsigned'("000");
            ELSE
                REPORT "8051 Internal Error: Bad address in get_bit_dmem";
            END IF;
            byte_slice := get_byte_dmem(addr1,direct,read_latch); -- read latch
            RETURN(byte_slice(conv_integer(addr(2 DOWNTO 0))));
        END FUNCTION get_bit_dmem;
 
        -- set_bit_dmem will set the value of the bit at bit address (addr)
        -- always assumed to be a "Read Modify Write" instruction, so that
        -- setting a bit to the port will read the surrounding bits from the
        -- port mirror (latch).
        PROCEDURE set_bit_dmem(
            CONSTANT addr : IN bvec;
            CONSTANT val  : IN std_logic
        ) IS
            VARIABLE byte_slice : bvec;
            VARIABLE addr1      : bvec; 
        BEGIN
            IF addr(7) = '0' THEN  -- if addr < 16#80 THEN
                addr1 := unsigned'("0010") & addr(6 DOWNTO 3); 
            ELSIF addr(7) = '1' THEN  -- if addr > 16#80 THEN
                addr1 := addr(7 DOWNTO 3) & unsigned'("000");
            ELSE
                REPORT "8051 Internal Error: Bad address in get_bit_dmem";
            END IF;
            byte_slice := get_byte_dmem(addr1,direct,TRUE); -- read latch
            byte_slice(conv_integer(addr(2 DOWNTO 0))) := val;
            set_byte_dmem(addr1,byte_slice,direct);
        END PROCEDURE set_bit_dmem;
 
-------------------------------------------End of Memory Handling Procdures
 
-------------------------------------------procedure get data
        -- This function will get data from either data memory, a register,
        -- or direct (from program memory) based on the opcode passed.
        -- It uses the following table for the last few digits of the opcode
        --    0000, 0001, 0010, 0011   Not found by this procedure!
        --    0100  :  Use immediate data in program memory
        --    0101  :  Use direct address
        --    011i  :  Use data at address contained in register 0 or 1 (i)
        --    1rrr  :  Use register rrr
        PROCEDURE get_data(
            CONSTANT opcode     : IN    bVec;    -- opcode used to select data
            VARIABLE data       : INOUT bVec;    -- The 8-bits of data
            CONSTANT read_latch : IN    BOOLEAN := FALSE
        ) IS
            VARIABLE nxt_pmem1  : bVec;          -- Temporary data
        BEGIN
            IF opcode(3) = '1' THEN           -- use register
                data := get_reg(opcode(2 DOWNTO 0));
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "101") THEN -- use direct memory
                data := get_byte_dmem(pmem_s4_byte, direct, read_latch);
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "100") THEN -- use immediate data
                data := pmem_s4_byte;
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "110") THEN -- use data @R0
                data := get_byte_dmem(get_reg("000"),indirect) ;
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "111") THEN -- use data @R1
                data := get_byte_dmem(get_reg("001"), indirect);
            END IF;
        END PROCEDURE get_data;
 
        FUNCTION advance_pc(
            CONSTANT opcode    : IN    bVec    -- opcode used to select data
        ) RETURN INTEGER IS
            VARIABLE pc_inc : INTEGER;
        BEGIN
            IF opcode(3) = '1' THEN           -- use register
                pc_inc := 0;
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "101") THEN -- use direct memory
                pc_inc := 1;
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "100") THEN -- use immediate data
                pc_inc := 1;
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "110") THEN -- use data @R0
                pc_inc := 0;
            ELSIF opcode(2 DOWNTO 0) =unsigned'( "111") THEN -- use data @R1
                pc_inc := 0;
            END IF;
            RETURN pc_inc;
        END FUNCTION advance_pc;
 
 
-------------------------------------------procedure handle add
        -- This function handles the carry's and adding for the ADD and ADDC
         -- opcodes.
        PROCEDURE handle_add(
            CONSTANT opcode : IN    bVec;   -- The opcode, used to select the 2nd operand
            CONSTANT cy_in  : IN    std_logic  -- set to '0' for ADD, cy for ADDC
 
        ) IS
            VARIABLE operand2   : bVec;     -- the 2nd operand
            VARIABLE new_sum    : INTEGER;  -- the new sum to be put in the acc
            VARIABLE pc_inc     : INTEGER;  -- amount to increment pc
       BEGIN
            pc <= pc + 1 + advance_pc(opcode);
            WAIT UNTIL cycle_state = s5p1;
            get_data(opcode, operand2);
            new_sum := conv_integer(acc) + conv_integer(operand2) + conv_integer(cy_in);
            -- Set carry flag if there is a carry out of bit 7
            IF new_sum > 255 THEN
                cy <= '1';
            ELSE
                cy <= '0';
            END IF;
            -- Set aux. carry flag if there is a carry out of bit 3
            IF (conv_integer(acc(3 DOWNTO 0))+conv_integer(operand2(3 DOWNTO 0))+
                conv_integer(cy_in)) > 15 THEN
                ac <= '1';
            ELSE
                ac <= '0';
            END IF;
            -- Set OV if there is a carry from bit 6 but not bit 7, or
            -- if there is a carry from 7 but none from 6.  Otherwise, clear.
            IF conv_integer(acc(6 DOWNTO 0))+conv_integer(operand2(6 DOWNTO 0)) > 127 THEN
                                       -- There is a carry from 6
               IF new_sum > 255 THEN   -- and from 7
                  ov <= '0';           -- so clear overflow
               ELSE                    -- If there is not a carry from 7,
                  ov <= '1';           -- then set overflow
               END IF;
            ELSE                       -- If there is not a carry from 6
               IF NEW_sum > 255 THEN   -- and there is from 7
                  ov <= '1';           -- set overflow.
                ELSE                    -- If there is not a carry from 7,
                  ov <= '0';           -- then clear overflow
               END IF;
            END IF;
            -- Finally, put the new sum into the acc (getting rid of any overflow)
            acc <= conv_unsigned(new_sum, 8);
        END PROCEDURE handle_add;
 
-------------------------------------------procedure handle sub
        -- This function handles the carry's and subtracting for the SUBB opcode
        PROCEDURE handle_sub(
            CONSTANT opcode : IN    bVec   -- The opcode, used to select the 2nd operand
        ) IS
            VARIABLE acc_int,op2_int,cy_int : INTEGER;-- bits converted to int
            VARIABLE operand2  : bVec;                -- the 2nd operand
            VARIABLE new_diff  : INTEGER;             -- the new diff for acc
        BEGIN
            pc <= pc + 1 + advance_pc(opcode);
            WAIT UNTIL cycle_state = s5p1;
            get_data(opcode, operand2);
            acc_int := conv_integer(acc);
            op2_int := conv_integer(operand2);
            cy_int  := conv_integer(cy);
            IF acc_int > op2_int + cy_int THEN
               new_diff := acc_int - (op2_int + cy_int);
               cy <= '0';  -- clear cy (borrow) flag
            ELSE
               -- If the subtractants are larger than the acc, set
               -- borrow and add 256 to acc
               new_diff := (acc_int + 256) - (op2_int + cy_int);
               cy <= '1';  -- set cy (borrow) flag
            END IF;
            -- Decide if aux. carry needs to be set or cleared (lower 4 bits)
            IF conv_integer(acc(3 DOWNTO 0)) >
              (conv_integer(operand2(3 DOWNTO 0)) + cy_int) THEN
                ac <= '0';
            ELSE
                ac <= '1';
            END IF;
            -- Set OV if there is borrow into bit 6 but not bit 7, or
            -- into bit 7 but not bit 6.  Otherwise, clear.
            IF conv_integer(acc(6 DOWNTO 0)) <
               conv_integer(operand2(6 DOWNTO 0)) + cy_int THEN
                                -- There is a borrow into bit 6
               IF acc_int > op2_int + cy_int THEN
                                -- but not into bit 7
                  ov <= '1';    -- so set ov (overflow)
               ELSE             -- There is not a borrow into bit 7
                  ov <= '0';    -- so clear overflow
               END IF;
            ELSE                -- There is not a borrow into bit 6
               IF acc_int > op2_int + cy_int THEN
                                -- and not into 7
                  ov <= '0';    -- then clear overflow
               ELSE             -- There is a borrow into bit 7
                  ov <= '1';    -- So set overflow
               END IF;
            END IF;
            -- Set AC if there is a borrow into bit 3, otherwise reset it
            IF conv_integer(acc(3 DOWNTO 0)) <
               conv_integer(operand2(3 DOWNTO 0)) + cy_int THEN
                ac <= '1';
            ELSE
                ac <= '0';
            END IF;
            acc <= conv_unsigned(new_diff, 8);
        END PROCEDURE handle_sub;
 
 
------------------------------------------- Begin the Process main
        --VARIABLE first_inst : BOOLEAN := TRUE;
    BEGIN  -- process main
 
    -- There are six states to a machine cycle, some commands take
    -- more than one cycle.  However, here is the general timing
    -- State 1 Pulse 1 - The opcode is read in by the get_pmem process
    -- State 1 Pulse 2 - The next address (pc + 1) is stored for output
    --                   by the get_pmem process
    -- State 2 Pulse 1 - Process main reads the opcode and decodes it.
    --                   pc is updated if it is a one cycle code
    --                   the operation is completed if no more data required
    -- State 4 Pulse 1 - The next data (at pc + 1) is read in by get_pmem
    -- State 4 Pulse 2 - If pc was updated, the new pc addr is stored by
    --                   process get_pmem.  Otherwise, addr for pc + 2 is
    --                   stored.
    -- State 5 Pulse 1 - The new pmem data (s4p1) is read by process main, if
    --                   necessary, and operations performed.  pc updated
    --
    -- Last cycle of a multi-cycle opcode:
    -- State 1 Pulse 1 - The pc has not been changed since this opcode
    --                   was deciphered, so the next byte of pmem (at pc + 2)
    --                   is read by process get_pmem.
    -- State 1 Pulse 2 - The next address (pc + 3) is stored for later use
    --                   in process get_pmem.
    -- State 2 Pulse 1 - The byte of s1p1 is read in by process main, and
    --                   any operations performed
    --                   pc is now updated
    -- State 4 Pulse 1 - The next data (pc + 4) is read by process get_pmem
    -- State 4 Pulse 2 - The new pc is read and stored for output.
    -- State 5 Pulse 1 - The opcode should be done by now!
 


        -- set init values
        IF NOT init_done THEN
            set_sfr;
            reset_pmem <= '1';

⌨️ 快捷键说明

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