📄 mc8051.vhd
字号:
std_logic_vector(p0_addr) WHEN p0_ctrl = '1' ELSE std_logic_vector(to_high_imped(p0_latch)) WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED; P1 <= (OTHERS => 'Z') WHEN rst = '1' ELSE std_logic_vector(to_high_imped(p1_latch)) WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED; P2 <= (OTHERS => 'Z') WHEN rst = '1' ELSE std_logic_vector(p2_addr) WHEN p2_ctrl = '1' ELSE std_logic_vector(to_high_imped(p2_latch)) WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED; P3 <= (OTHERS => 'Z') WHEN rst = '1' ELSE std_logic_vector(to_high_imped(p3_latch)) WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED; -- always enable the UART for mode 2-- p3_ctrl(0) <= 'Z';-- P3(0) <= rxd_internal WHEN p3_ctrl(0) = '1' ELSE 'Z'; p3_ctrl(1) <= '1'; rxd_internal <= P3(0); P3(1) <= txd_internal WHEN p3_ctrl(1) = '1' AND rst = '0' ELSE 'Z'; -- whenever there is a falling edge on the interrupt pin, it will -- be sent to the interrupt processor (which may acknowledge or mask) -- for a level sensitive interrupt (it? = 0) the rising edge of the pin -- will clear out this internal signal. For an edge sensitve interrupt -- (it? = 1) the acknowledge from the interrupt processor will clear int0_n_internal <= '0' WHEN falling_edge(p3(2)) ELSE '1' WHEN rising_edge(p3(2)) AND it0 = '0' ELSE '1' WHEN interrupt_ack = '1' AND it0 = '1' ELSE int0_n_internal; int1_n_internal <= '0' WHEN falling_edge(p3(3)) ELSE '1' WHEN rising_edge(p3(3)) AND it1 = '0' ELSE '1' WHEN interrupt_ack = '1' AND it1 = '1' ELSE int1_n_internal; t0_internal <= P3(4); t1_internal <= P3(5); P3(6) <= wr_n_internal WHEN p3_ctrl(6) = '1' AND rst = '0' ELSE 'Z'; P3(7) <= rd_n_internal WHEN p3_ctrl(7) = '1' AND rst = '0' ELSE 'Z'; --=============================================================== -- Process Statements --=============================================================== ------------------------------------------------------------------------ -- The oscillator process will follow the XTAL clock signal and -- advance the current state. The states are s1p1, s1p2, s2p1, s2p2, -- up to s6p1 and s6p2. ------------------------------------------------------------------------ oscillator : PROCESS (XTAL1) IS VARIABLE last_falling_edge_time : TIME := 0 ns; VARIABLE startup_count : INTEGER := 0; BEGIN IF falling_edge(XTAL1) THEN IF startup_count < 3 THEN cycle_state <= init; startup_count := startup_count + 1; last_falling_edge_time := NOW; ELSE cycle_state <= inc(cycle_state); -- increment the current state, -- and loop back from s6p2 to s1p1 TCLCL <= NOW - last_falling_edge_time; last_falling_edge_time := NOW; END IF; END IF; END PROCESS oscillator; ------------------------------------------------------------------------ -- The process get_pmem is responsible for reading all of the program -- memory (whetere internal or external) and feeding the read bytes to -- the process main through the signals pmem_s1_byte and pmem_s4_byte. -- If there has been a transaction on pc, this process will set -- its internal addr to the value of pc at state s4p1. Then, if needed, -- it will output this addr at s5p1 and then read in the appropriate data -- at s1p1. Then it increments its internal addr and will read the next -- byte at s4p1. It will continue to increment the internal addr until -- there is another transaction on pc. ------------------------------------------------------------------------- get_pmem : PROCESS(cycle_state, pc'TRANSACTION) IS VARIABLE addr : INTEGER := 0; VARIABLE pmem : program_mem_T; -- the program memory VARIABLE prog_loaded : BOOLEAN := FALSE; -- true after pmem is updated VARIABLE resync : BOOLEAN := FALSE; -- set true when pc changes VARIABLE port_to_01 : bit_vector(7 DOWNTO 0); BEGIN -- Put lines at HiZ if the processor is in reset state IF rst = '1' THEN psen_n <= 'Z'; ale_pm <= 'Z'; p0_ctrl <= 'Z'; p2_ctrl <= 'Z'; p0_addr <= "ZZZZZZZZ"; p2_addr <= "ZZZZZZZZ"; ELSIF NOT prog_loaded THEN IF (ea_n = '1' or ea_n = 'H') THEN load_program(program_filename,pmem); END IF; -- Set default values for control lines psen_n <= '1'; p0_ctrl <= 'Z'; p2_ctrl <= 'Z'; p0_reset <= '0'; prog_loaded := TRUE; ELSE -- If process main has acknowledged a reset, then -- clear the p0 reset line. IF p0_reset_ack <= '1' THEN p0_reset <= '0'; END IF; -- If there has been a transaction on pc, and it is -- not the initial start-up state, then flag the -- resync variable IF pc'ACTIVE THEN resync := TRUE; END IF; -- If the process main is trying to read a data byte -- from external mem, yield to it by putting ctrl's -- to high impedance IF port_req = '1' THEN psen_n <= '1'; ale_pm <= '0'; p0_ctrl <= 'Z'; p2_ctrl <= 'Z'; p0_addr <= "ZZZZZZZZ"; p2_addr <= "ZZZZZZZZ"; ELSIF reset_pmem = '1' THEN resync := TRUE; addr := 0; ELSIF cycle_state'ACTIVE THEN CASE cycle_state IS WHEN init => NULL; WHEN s1p1 => -- read in the current byte from pmem IF ( addr > 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN IF Is_X(P0) THEN pmem_s1_byte <= unsigned'("00000000"); bad_data <= '1'; ELSE port_to_01 := to_bitVector(P0); pmem_s1_byte <= unsigned(to_stdlogicvector(port_to_01)); bad_data <= '0'; END IF; ELSE -- fetch from internal memory pmem_s1_byte <= pmem(addr); END IF; WHEN s4p1 => -- read in the current byte from pmem IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN port_to_01 := to_bitVector(P0); pmem_s4_byte <= unsigned(to_stdlogicvector(port_to_01)); ELSE -- fetch from internal memory pmem_s4_byte <= pmem(addr); END IF; WHEN s1p2 | s4p2 => IF resync THEN addr := conv_integer(pc); resync := FALSE; ELSE addr := addr + 1; END IF; -- strobe ale if next addr is external -- rewrite p0_latch to all 1's IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN ale_pm <= '1'; psen_n <= '1'; p0_reset <= '1'; END IF; WHEN s2p1 | s5p1 => -- drive port 0 and port 2 if addr is external IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN p0_addr <= conv_unsigned(addr MOD 256, 8); p2_addr <= conv_unsigned(addr / 256, 8); p0_ctrl <= '1'; p2_ctrl <= '1'; ELSE p0_ctrl <= 'Z'; p2_ctrl <= 'Z'; END IF; WHEN s2p2 | s5p2 => -- drive ale to zero IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN ale_pm <= '0'; END IF; WHEN s3p1 | s6p1 => -- drive psen low IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN psen_n <= '0'; p0_addr <= "ZZZZZZZZ"; END IF; WHEN s3p2 | s6p2 => NULL; END CASE; END IF; END IF; 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 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 -- 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_latch <= "11111111"; ie <= "00000000"; ip <= "00000000"; -- pcon <= "00000000"; -- scon, tcon, th0, th1, tl0, tl1, tmod END PROCEDURE set_sfr; ------------------------------------------------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#98# THEN-- byte_slice := ad_data;-- IF MORE SFR's need to be added, place the READS here in the form above-- ELSIF addr_int = 16#(desired addresss)# THEN-- byte_slice := (data_valute); ELSE byte_slice := direct_hi_dmem(addr_int); END IF; RETURN(byte_slice); END FUNCTION get_byte_dmem; -- 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -