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