📄 mc8051.vhd
字号:
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 + -