📄 mc8051.vhd
字号:
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; -- 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; -- resolve2 resolves two signals into one -- Used for SFRs written to by processes other than main PROCEDURE resolve2 (signal first, second: in bvec; signal output: out bvec) IS BEGIN if second'event then output <= second; end if; if first'event then output <= first; end if; END PROCEDURE resolve2; PROCEDURE resolve2 (signal first, second: in std_logic; signal output: out std_logic) IS BEGIN if second'event then output <= second; end if; if first'event then output <= first; end if; END PROCEDURE resolve2; -- 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 set_byte_dmem("10110000", "11111111", direct); ie <= "00000000"; ip <= "00000000"; tmod <= "00000000"; pcon <= "00000000"; -- scon, tcon, th0, th1, tl0, tl1 -- SCON set_byte_dmem("10011000", "00000000", direct); -- TCON set_byte_dmem("10001000", "00000000", direct); -- TH0 set_byte_dmem("10001100", "00000000", direct); -- TH1 set_byte_dmem("10001101", "00000000", direct); -- TL0 set_byte_dmem("10001010", "00000000", direct); -- TL1 set_byte_dmem("10001011", "00000000", direct); END PROCEDURE set_sfr; ------------------------------------------- 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! -- rst = 'U' handles case where we start up in reset mode, but -- the processor hasn't detected that yet IF rst = '1' or rst = 'H' or rst = 'U' THEN init_gb <= FALSE; init_done := FALSE; WAIT UNTIL rst = '0'; END IF; -- set init values IF NOT init_done THEN set_sfr; reset_pmem <= '1'; pc <= "0000000000000000"; -- Set any signals driven from this process to 'Z' p0_addr <= "ZZZZZZZZ"; p2_addr <= "ZZZZZZZZ"; p0_ctrl <= 'Z'; p2_ctrl <= 'Z'; rd_n_internal <= '1'; wr_n_internal <= '1'; WAIT UNTIL cycle_state = s4p1; init_done := TRUE; init_gb <= TRUE; reset_pmem <= '0'; END IF; WAIT UNTIL cycle_state = s2p1; -- When a data / addr value is written to P0, then it is -- reset to all 1's. The get_pmem process cannot do that -- by itself, so we will implement that here. IF p0_reset = '1' THEN p0_latch <= "11111111"; p0_reset_ack <= '1'; END IF; IF p0_reset = '0' THEN p0_reset_ack <= '0'; END IF; -- The parity bit (bit 0 of PSW) is automatically set / cleared -- to indicate an odd / even number of 1's in acc temp_int := 0; FOR k IN acc'RANGE LOOP temp_int := conv_integer(acc(k)) + temp_int; END LOOP; IF (temp_int MOD 2 = 1) THEN PSW(0) <= '1'; ELSE PSW(0) <= '0'; END IF; ------------INTERRUPTS------------------ -- Check to see if an interrupt needs to be processed -- Only check for serial at the moment -- determine the new PC in order of same-level priority -- and set the new processor priority depending upon -- IP register setting IF ea = '1' AND (en_x0 = '1' AND int0_n_internal = '0') AND -- ext 0 (current_priority = "00" OR (current_priority = "01" AND IP(0) = '1')) THEN -- LCALL WAIT UNTIL cycle_state = s2p1; -- wait for next cycle temp_pc := pc; set_byte_dmem(sp + 1, temp_pc(7 DOWNTO 0), indirect); set_byte_dmem(sp + 2, temp_pc(15 DOWNTO 8), indirect); sp <= sp + 2; -- update stack pointer to point to the new data previous_priority <= current_priority; current_priority(1) <= IP(0); current_priority(0) <= '1'; pc <= "0000000000000011"; -- 03 WAIT UNTIL cycle_state = s4p1; ELSIF ea = '1' AND (en_t0 = '1' AND TF0 = '1') AND -- timer 0 (current_priority = "00" OR (current_priority = "01" AND IP(1) = '1')) THEN -- LCALL WAIT UNTIL cycle_state = s2p1; -- wait for next cycle temp_pc := pc; set_byte_dmem(sp + 1, temp_pc(7 DOWNTO 0), indirect); set_byte_dmem(sp + 2, temp_pc(15 DOWNTO 8), indirect); sp <= sp + 2; -- update stack pointer to point to the new data previous_priority <= current_priority; current_priority(1) <= IP(1); current_priority(0) <= '1'; pc <= "0000000000001011"; -- 0B -- Interrupt flag cleared in hardware TF0_main <= '0'; WAIT UNTIL cycle_state = s4p1; ELSIF ea = '1' AND (en_x1 = '1' AND int1_n_internal = '0') AND -- ext 1 (current_priority = "00" OR (current_priority = "01" AND IP(2) = '1')) THEN -- LCALL WAIT UNTIL cycle_state = s2p1; -- wait for next cycle temp_pc := pc; set_byte_dmem(sp + 1, temp_pc(7 DOWNTO 0), indirect); set_byte_dmem(sp + 2, temp_pc(15 DOWNTO 8), indirect); sp <= sp + 2; -- update stack pointer to point to the new data previous_priority <= current_priority;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -