-- Design for overlap fetch/execute AIZUP -- The aizup cpu + ken's shell LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY shell IS PORT ( rxdat : IN std_logic; xclk : IN std_logic; rxstb : IN std_logic; txstb : IN std_logic; txdat : OUT std_logic; clk : IN std_logic; addr : BUFFER std_logic_vector(15 DOWNTO 0); data : INOUT std_logic_vector(7 DOWNTO 0); rd : BUFFER std_logic; wr : BUFFER std_logic; ramcs : OUT std_logic; sevseg: OUT std_logic_vector(6 DOWNTO 0) ); END shell; ARCHITECTURE one OF shell IS COMPONENT cpu PORT ( clk : IN std_logic; addr : BUFFER std_logic_vector(15 DOWNTO 0); data : INOUT std_logic_vector(7 DOWNTO 0); rd : BUFFER std_logic; wr : BUFFER std_logic; --ramcs : OUT std_logic; sevseg: OUT std_logic_vector(6 DOWNTO 0); din : IN std_logic_vector(15 DOWNTO 0); dout : OUT std_logic_vector(7 DOWNTO 0); dsel : IN std_logic_vector(1 DOWNTO 0) ); END COMPONENT; SIGNAL din : std_logic_vector(15 DOWNTO 0); SIGNAL clksel : std_logic_vector(4 DOWNTO 0); SIGNAL dsel : std_logic_vector(1 DOWNTO 0); SIGNAL dout : std_logic_vector(7 DOWNTO 0); SIGNAL txshift : std_logic_vector(7 DOWNTO 0); SIGNAL txshiftnext: std_logic_vector(7 DOWNTO 0); SIGNAL rxshift : std_logic_vector(22 DOWNTO 0); SIGNAL clkdiv : std_logic_vector(23 DOWNTO 0); SIGNAL cpuclk : std_logic; BEGIN u1: cpu PORT MAP ( clk => cpuclk, addr => addr, data => data, rd => rd, wr => wr, --ramcs => ramcs, sevseg => sevseg, din => din, dout => dout, dsel => dsel ); -- select ram ramcs <='0'; -- Drive serial interface WITH txstb SELECT txshiftnext <= txshift(6 DOWNTO 0)&'0' WHEN '0', dout WHEN OTHERS; txrx: PROCESS BEGIN WAIT UNTIL (xclk'event AND xclk='0'); rxshift <= rxshift(21 DOWNTO 0)&(NOT rxdat); txshift <= txshiftnext; END PROCESS txrx; rx: PROCESS BEGIN WAIT UNTIL (rxstb'event AND rxstb='1'); din <= rxshift(15 DOWNTO 0); dsel <= rxshift(17 DOWNTO 16); clksel <= rxshift(22 DOWNTO 18); END PROCESS rx; txdat <= txshift(7); -- Run clock divider PROCESS BEGIN WAIT UNTIL (clk'event AND clk='1'); clkdiv <= clkdiv + 1; END PROCESS; WITH clksel SELECT cpuclk <= clk WHEN "00000", clkdiv(0) WHEN "00001", clkdiv(1) WHEN "00010", clkdiv(2) WHEN "00011", clkdiv(3) WHEN "00100", clkdiv(4) WHEN "00101", clkdiv(5) WHEN "00110", clkdiv(6) WHEN "00111", clkdiv(7) WHEN "01000", clkdiv(8) WHEN "01001", clkdiv(9) WHEN "01010", clkdiv(10) WHEN "01011", clkdiv(11) WHEN "01100", clkdiv(12) WHEN "01101", clkdiv(13) WHEN "01110", clkdiv(14) WHEN "01111", clkdiv(15) WHEN "10000", clkdiv(16) WHEN "10001", clkdiv(17) WHEN "10010", clkdiv(18) WHEN "10011", clkdiv(19) WHEN "10100", clkdiv(20) WHEN "10101", clkdiv(21) WHEN "10110", clkdiv(22) WHEN "10111", clkdiv(23) WHEN "11000", '0' WHEN "11110", '1' WHEN "11111", '0' WHEN OTHERS; END one; --------------------------------------------------------------------------- -- Design based on the AIZUP architecture. -- CPU is a four register, 8 bit data/instruction, load/store machine. LIBRARY ieee; USE ieee.std_logic_1164.all; -- standard logic USE ieee.std_logic_unsigned.all; -- arithmetic stuff ENTITY cpu IS PORT( clk: IN std_logic; -- clock rd: BUFFER std_logic; -- mem read cntl wr: BUFFER std_logic; -- mem write cntl addr: BUFFER std_logic_vector(15 downto 0);-- the address bus data: INOUT std_logic_vector(7 downto 0); -- the data bus sevseg: OUT std_logic_vector(6 downto 0); -- segven segment display din : IN std_logic_vector(15 DOWNTO 0); -- shell data in dout : OUT std_logic_vector(7 DOWNTO 0); -- shell data out dsel : IN std_logic_vector(1 DOWNTO 0) -- shell data out select ); END cpu; ARCHITECTURE one OF cpu IS --op codes TYPE opcodes IS (nopx, addx, subx, orx, andx, xorx, movx, ldx, stx, addix, subix, srolx, srohx, bzx, bnzx, brax); SIGNAL op: opcodes; -- reset signal SIGNAL reset: std_logic; -- IR, PC SIGNAL ir: std_logic_vector(7 downto 0); --instruction register SIGNAL pc: std_logic_vector(7 downto 0); --program counter SIGNAL PCload: std_logic; --gates the PC load SIGNAL PCaddSel: std_logic; --selects PC increment 0=1 1=2 3=displacement SIGNAL PCinc: std_logic_vector(7 downto 0); --increment value SIGNAL PCnew: std_logic_vector(7 downto 0); --incrmented PC -- DATA from IR SIGNAL imm2, imm4, imm8: std_logic_vector(7 downto 0); -- bits from IR extended SIGNAL disp: std_logic_vector(7 downto 0); --sign extended 4 bit const for PC relative branch -- MEMORY interface SIGNAL MASel: std_logic; --memory address select: 0=PC, 1=(Rs) SIGNAL AtoBus: std_logic; --gates the A bus output onto the memory data bus -- DATA registers SIGNAL r0, r1, r2, r3: std_logic_vector(7 downto 0); SIGNAL rdata: std_logic_vector(7 downto 0); -- register outputs SIGNAL Aout, Bout: std_logic_vector(7 downto 0); --register input bus SIGNAL RegDSel: std_logic; --data source for rdata reg write: 0=ALUout 1=data bus SIGNAL ALUBSel: std_logic_vector(1 downto 0); --data source for ALU b input: 0=Bout 1=imm2 2=imm4 3=imm8 SIGNAL ASel: std_logic_vector(1 downto 0); --selects A register output SIGNAL BSel: std_logic_vector(1 downto 0); --selects B register output SIGNAL we: std_logic; --enables a register load -- ALU SIGNAL Bin: std_logic_vector(7 downto 0); SIGNAL ALUop: std_logic_vector(2 downto 0); --selects ALU function SIGNAL ALUout: std_logic_vector(7 downto 0); --ALU result SIGNAL zne: std_logic; --gates the Z and N register loads SIGNAL z: std_logic; --the Z and N registers BEGIN -- *********************************** --debugger shell interface reset <= din(0); WITH dsel SELECT dout <= addr(7 downto 0) WHEN "00" , data WHEN "01", pc WHEN "10", ir WHEN "11" , "11111111" WHEN OTHERS ; -- *********************************** -- 7-seg decoder WITH r3(3 downto 0) SELECT sevseg <= "0111111" WHEN "0000", "0000110" WHEN "0001", "1011011" WHEN "0010", "1001111" WHEN "0011", "1100110" WHEN "0100", "1101101" WHEN "0101", "1111101" WHEN "0110", "0000111" WHEN "0111", "1111111" WHEN "1000", "1101111" WHEN "1001", "1110111" WHEN "1010", "1111100" WHEN "1011", "0111001" WHEN "1100", "1011110" WHEN "1101", "1111001" WHEN "1110", "1110001" WHEN OTHERS; -- *********************************** -- OPcode decoder WITH ir(7 downto 4) SELECT op <= nopx WHEN "0000", addx WHEN "0001", subx WHEN "0010", orx WHEN "0011", andx WHEN "0100", xorx WHEN "0101", movx WHEN "0110", ldx WHEN "0111", stx WHEN "1000", addix WHEN "1001", subix WHEN "1010", srolx WHEN "1011", srohx WHEN "1100", bzx WHEN "1101", bnzx WHEN "1110", brax WHEN OTHERS; -- *********************************** -- constants from the IR imm2 <= "000000" & ir(1 downto 0); -- 2 bits immediate imm4 <= "0000" & ir(3 downto 0) ; -- 4 bit immed for r0 imm8 <= ir(3 downto 0) & "0000" ; -- high 4 bits for r0 disp <= ir(3) & ir(3) & ir(3) & ir(3) & ir(3 downto 0); --jump offset -- *********************************** -- memory control MASel <= '1' WHEN (op=stx OR op=ldx) ELSE '0'; WITH MASel SELECT addr <= "00000000" & pc WHEN '0', -- during fetch phase "00000000" & Bout WHEN '1', -- during exec phase "00000000" & pc WHEN OTHERS; rd <= '0' WHEN ( op/=stx AND clk='0') ELSE '1'; wr <= '0' WHEN (op=stx AND clk='0') -- store data ELSE '1'; -- A bus to memory data <= Aout WHEN wr='0' ELSE "ZZZZZZZZ"; -- floats the bus -- *********************************** -- Program Counter control PCaddSel <= '1' WHEN (op=bzx AND z='1') OR (op=bnzx AND z='0') OR op=brax ELSE '0'; WITH PCaddSel SELECT PCinc <= "00000001" WHEN '0', disp WHEN OTHERS; PCnew <= pc + PCinc; -- the updated verion of the PC -- *********************************** -- register controls -- set up register data select RegDSel <= '1' WHEN op=ldx ELSE '0'; -- route the input data WITH RegDSel SELECT rdata <= ALUout WHEN '0', data WHEN OTHERS; -- choose a register for output A, srol or sroh always loads r0 ASel <= "00" WHEN (op=srolx OR op=srohx) ELSE ir(3 downto 2) ; -- choose a register for output B, r2 or r3 used for ld/st disp BSel <= ir(1 downto 0) ; -- write enable for registers; disable for 4 opcodes we <= '0' WHEN (op=stx OR op=bzx OR op=bnzx OR op=brax) ELSE '1' ; -- A output WITH ASel SELECT Aout <= r0 WHEN "00", r1 WHEN "01", r2 WHEN "10", r3 WHEN OTHERS; -- B output WITH BSel SELECT Bout <= r0 WHEN "00", r1 WHEN "01", r2 WHEN "10", r3 WHEN OTHERS; -- *********************************** -- ALU controls -- control the B input to the ALU ALUbSel <= "01" WHEN (op=addix OR op=subix) ELSE -- 2 bit DataImm "10" WHEN (op=srolx) ELSE -- 4 bit r0 load low "11" WHEN (op=srohx) ELSE -- 4 bit r0 load high "00"; --Bout -- ALU B input WITH ALUbSel SELECT Bin <= Bout WHEN "00", imm2 WHEN "01", imm4 WHEN "10", imm8 WHEN OTHERS; -- ALU function control ALUop <= "000" WHEN (op=movx OR op=srohx) ELSE "001" WHEN (op=orx OR op=srolx) ELSE "010" WHEN op=xorx ELSE "011" WHEN op=andx ELSE "100" WHEN (op=subx OR op=subix) ELSE "101" WHEN (op=addx OR op=addix) ELSE "000" ; -- ALU WITH ALUop SELECT ALUout <= Bin WHEN "000", Aout OR Bin WHEN "001", Aout XOR Bin WHEN "010", Aout AND Bin WHEN "011", Aout - Bin WHEN "100", Aout + Bin WHEN "101", Bin WHEN OTHERS; -- zero flag control zne <= '0' WHEN (op=stx OR op=ldx OR op=bzx OR op=bnzx OR op=brax) ELSE '1' ; -- *********************************** -- Timing, reset, and register updates PROCESS (clk, reset) BEGIN IF reset='0' THEN pc <= "00000000"; -- reset to address zero ir <= "00000000"; -- inst is nop r3 <= "11111111"; -- for testing ELSIF (clk='1' AND clk'event) THEN --update ir and pc IF (op=stx OR op=ldx) THEN ir <= "00000000"; -- nop and PC NOT updated ELSE ir <= data; pc <= PCnew; END IF; --update registers IF we='1' THEN CASE ASel IS WHEN "00" => r0 <= rdata; WHEN "01" => r1 <= rdata; WHEN "10" => r2 <= rdata; WHEN "11" => r3 <= rdata; WHEN OTHERS => NULL; END CASE; END IF; IF zne='1' THEN IF aluout=0 THEN z <= '1'; ELSE z <= '0'; END IF; END IF; END IF; -- the clock if END PROCESS; END one;