📄 mc8051.vhd
字号:
P2 <= std_logic_vector(to_high_imped(p2_latch))
WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED;
P3 <= std_logic_vector(to_high_imped(p3_latch))
WHEN cycle_state=s1p1 AND falling_edge(xtal1) ELSE UNAFFECTED;
-- when the ctrl is asserted (by get_pmem or main) then
-- force the addr/data value out the port
P0 <= std_logic_vector(p0_addr) WHEN p0_ctrl = '1' ELSE
(OTHERS => 'Z');
P2 <= std_logic_vector(p2_addr) WHEN p2_ctrl = '1' ELSE
(OTHERS => 'Z');
-- always enable the UART for mode 2
-- p3_ctrl(0) <= 'Z';
p3_ctrl(1) <= '1';
-- P3(0) <= rxd_internal WHEN p3_ctrl(0) = '1' ELSE 'Z';
rxd_internal <= P3(0);
P3(1) <= txd_internal WHEN p3_ctrl(1) = '1' 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' ELSE 'Z';
P3(7) <= rd_n_internal WHEN p3_ctrl(7) = '1' 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
IF 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
p0_ctrl <= 'Z';
p2_ctrl <= 'Z';
p0_addr <= "ZZZZZZZZ";
p2_addr <= "ZZZZZZZZ";
ale_pm <= '0';
psen_n <= '1';
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;
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
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';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -