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

📄 mc8051.vhd

📁 8051的VHDL IP核
💻 VHD
📖 第 1 页 / 共 5 页
字号:
                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';               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-- IF MORE SFR's need to be added, place the WRITES here in the form below-- ELSIF addr_int = 16#(desired addresss)# THEN--   sfr <= val; --   also copy the val to direct_hi_dmem if it is not included in the--   reads in get_byte_dmem             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!

⌨️ 快捷键说明

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