📄 mc8051.vhd
字号:
END PROCESS get_pmem; ------------------------------------------------------------------------ -- This is the main process of the microcomputer. It will check the -- opcode and perform the action. ------------------------------------------------------------------------ main : PROCESS VARIABLE opcode : bVec; -- the opcode for this cycle VARIABLE temp1, temp2 : bVec; -- temp use only VARIABLE wtemp : wVec; -- temp use only VARIABLE temp_int : INTEGER; -- temp use only VARIABLE temp_pc : wVec; -- temp pc storage VARIABLE init_done : BOOLEAN := FALSE; -- set to true once the initializing is done in the first cycle VARIABLE ie_stored : bVec; -- stores ie reg when servicing an interrupt VARIABLE pc_int : INTEGER; -- only used for report ------------------------------------------------Memory Handling Procedures -- Note that the following impure functions and procedures all use -- the program and/or data memory which is defined as a signal. -- However, when reading from addr's 80,90,A0,B0 for some will -- read the port directly, while others will read the ram mirror. -- Those that read the mirror (latch) are ANL, ORL, XRL, JBC, -- CPL, INC, DEC, DJNZ, MOV PX.Y, CLR PX.Y, SETB PX.Y -- get_byte_dmem will return the value of the byte at byte address -- depending upon if direct or indirect addressing is being used. -- it will also check if an event has occured on a serial control -- or buffer and will copy that into the ram IMPURE FUNCTION get_byte_dmem( CONSTANT addr : IN bvec; CONSTANT mode : IN access_type; CONSTANT read_latch : IN BOOLEAN := FALSE ) RETURN bvec IS VARIABLE addr_int : INTEGER; VARIABLE byte_slice : bVec; BEGIN addr_int := conv_integer(addr); IF addr_int < 128 THEN byte_slice := lo_dmem(addr_int); ELSIF mode = indirect THEN byte_slice := indirect_hi_dmem(addr_int); ELSIF (NOT read_latch) AND (addr_int=16#80#) THEN -- read the port itself byte_slice := unsigned(P0); ELSIF (NOT read_latch) AND (addr_int=16#90#) THEN -- read the port itself byte_slice := unsigned(P1); ELSIF (NOT read_latch) AND (addr_int=16#A0#) THEN -- read the port itself byte_slice := unsigned(P2); ELSIF (NOT read_latch) AND (addr_int=16#B0#) THEN -- read the port itself byte_slice := unsigned(P3); -- read from sbuf ELSIF addr_int = 16#99# THEN byte_slice := sbuf_dup; ELSIF addr_int = 16#98# THEN byte_slice := scon_out; ELSIF addr_int = 16#8A# THEN byte_slice := TL0; ELSIF addr_int = 16#8B# THEN byte_slice := TH0; ELSIF addr_int = 16#8C# THEN byte_slice := TL1; ELSIF addr_int = 16#8D# THEN byte_slice := TH1; -- TCON ELSIF addr_int = 16#88# THEN byte_slice := direct_hi_dmem(addr_int); byte_slice(7) := TF1; byte_slice(5) := TF0; byte_slice(3) := not int1_n_internal; byte_slice(1) := not int0_n_internal; ELSE byte_slice := direct_hi_dmem(addr_int); END IF; RETURN(byte_slice); END FUNCTION get_byte_dmem; -- set_acc will set the value of the accumulator and update PSW PROCEDURE set_acc( CONSTANT val : IN bVec ) IS variable temp_int: integer; BEGIN acc <= val; -- 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; END PROCEDURE set_acc; -- set_byte_dmem will set the value of the byte at address (addr) -- using the appropriate memory for direct / indirect accessing. PROCEDURE set_byte_dmem( CONSTANT addr : IN bvec; CONSTANT val : IN bVec; CONSTANT mode : IN access_type ) IS VARIABLE addr_int : INTEGER; BEGIN addr_int := conv_integer(addr); IF addr_int < 128 THEN 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"; ELSIF addr_int = 16#8A# THEN TL0_main <= val; ELSIF addr_int = 16#8B# THEN TL1_main <= val; ELSIF addr_int = 16#8C# THEN TH0_main <= val; ELSIF addr_int = 16#8D# THEN TH1_main <= val; -- TCON ELSIF addr_int = 16#88# THEN direct_hi_dmem(addr_int) <= val; TF1_main <= val(7); TF0_main <= val(5); -- ACC ELSIF addr_int = 16#E0# THEN set_acc(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; VARIABLE ret_val : std_ulogic; 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 ret_val := byte_slice(conv_integer(addr(2 DOWNTO 0))); -- Check for particular SFRs IF addr = 16#8F# THEN ret_val := TF1; ELSIF addr = 16#8D# THEN ret_val := TF0; ELSIF addr = 16#8B# THEN ret_val := not int1_n_internal; ELSIF addr = 16#89# THEN ret_val := not int0_n_internal; END IF; RETURN(ret_val); 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 = 16#D0# THEN report "Assigning to parity bit has no effect" severity warning; RETURN; END IF; 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); -- Check for particular SFRs IF addr = 16#8F# THEN TF1_main <= val; ELSIF addr = 16#8D# THEN TF0_main <= val; END IF; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -