Simple VHDL Microcontroller - Page 1
Forum section: electronics / projects

author: pyrohaz
author_rank: Regular Contributor
timestamp: June 03, 2015, 01:27:18 pm
content: Hey guys,So I'm trying to write the simplest of microcontrollers - essentially a programmable state machine! And I've got a couple of things working in simulation. However, I can't get my jump instruction to work and I'm wondering if there is something specific that I'd need to to with regards to getting it to work.Code:Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity CPU isport(Data: inout std_logic_vector(13 downto 0);MAddr: out std_logic_vector(7 downto 0);EnM, WR: out std_logic;ClkI, Rst: in std_logic);end CPU;architecture C of CPU issignal PC: std_logic_vector(7 downto 0);signal InsC: std_logic_vector(5 downto 0);signal InsD: std_logic_vector(7 downto 0);signal RegA, RegB: std_logic_vector(7 downto 0);signal Flags: std_logic_vector(2 downto 0);type StateType is (Fetch, Decode, Execute, MWrite);signal State: StateType := Fetch;beginprocess(Data, ClkI, Rst)beginif(Rst = '1') thenPC <= (others => '0');State <= Fetch;RegA <= (others => '0');RegB <= (others => '0');Flags <= "000";elsif(rising_edge(ClkI)) thenif(RegA = RegB) then Flags(0) <= '1';else Flags(0) <= '0'; end if;if(RegA < RegB) then Flags(1) <= '1';else Flags(1) <= '0'; end if;if(RegA > RegB) then Flags(2) <= '1';else Flags(2) <= '0'; end if;case State iswhen Fetch =>Data <= (others => 'Z');InsD <= (others => '0');InsC <= (others => '0');MAddr <= PC;WR <= '1';EnM <= '0';State <= Decode;when Decode =>EnM <= '1';InsC <= Data(13 downto 8);InsD <= Data(7 downto 0);State <= Execute;when Execute =>if(InsC(5 downto 1) = "00001") then --Store Reg Aif(InsC(0) = '0') then RegA <= InsD;else RegB <= InsD; end if;PC <= std_logic_vector(unsigned(PC)+1);State <= Fetch;elsif(InsC(5 downto 1) = "00010") then --Incrementif(InsC(0) = '0') then RegA <= std_logic_vector(unsigned(RegA)+1);else RegB <= std_logic_vector(unsigned(RegB)+1); end if;PC <= std_logic_vector(unsigned(PC)+1);State <= Fetch;elsif(InsC(5 downto 1) = "00011") then --Decrementif(InsC(0) = '0') then RegA <= std_logic_vector(unsigned(RegA)-1);else RegB <= std_logic_vector(unsigned(RegB)-1); end if;PC <= std_logic_vector(unsigned(PC)+1);State <= Fetch;elsif(InsC(5 downto 1) = "00100") then --Andif(InsC(0) = '0') then RegA <= RegA and RegB;else RegB <= RegA and RegB; end if;PC <= std_logic_vector(unsigned(PC)+1);State <= Fetch;elsif(InsC(5 downto 1) = "00101") then --Addif(InsC(0) = '0') then RegA <= std_logic_vector(unsigned(RegA) + unsigned(RegB));else RegB <= std_logic_vector(unsigned(RegA) + unsigned(RegB)); end if;PC <= std_logic_vector(unsigned(PC)+1);State <= Fetch;elsif(InsC(5 downto 1) = "00110") then --Notif(InsC(0) = '0') then RegA <= not RegA;else RegB <= not RegB; end if;PC <= std_logic_vector(unsigned(PC)+1);State <= Fetch;elsif(InsC(5 downto 1) = "00111") then --Write Regif(InsC(0) = '0') then Data(7 downto 0) <= RegA;else Data(7 downto 0) <= RegB; end if;WR <= '0';EnM <= '0';PC <= std_logic_vector(unsigned(PC)+1);State <= MWrite;elsif(InsC = "011000") then --Jump to addressPC <= InsD;State <= Fetch;elsif(InsC(5 downto 3) = "010") then --Jump if flag setif(InsC(2 downto 0) = Flags) thenPC <= InsD;elsePC <= std_logic_vector(unsigned(PC)+1);end if;State <= Fetch;elseState <= Fetch;end if;when MWrite =>EnM <= '1';State <= Fetch;end case;end if;end process;end C;I'm simulating the system in Quartus and I have a tristateable SRAM attached to the Data and MAddr lines. My instructions are 14 bits long (6bit opcode, 8bit data) and my opcodes are:X = 0 choose RegA, X = 1 choose RegBStore 00001XInc 00010XDec 00011XAnd 00100XAdd 00101XNot 00110XWrite Reg 00111XJump 011000Jump if flag set 010XXX - The X's define which flag to jump on.Now obviously, the architecture isn't particularly efficient but I'm doing it as a learning exercise so I'm not expecting some ARM level brilliance! It doesn't even have hardware multiplication... The address that the processor jumps to after the Jump instruction is defined by the data that comes with the OpCode e.g. 011000|00000001 will jump to address 1. The same applies with most of the other instructions e.g. Storing 3 in register B: 000011|00000011.So I've set up a very small test program to try out the processor and it just doesn't seem to work properly at all. I'm literally just trying to make an increment loop like so:All byte codes are in decimal as Altera memory editor only allows unsigned decimals, weird I know!0 Store 10 in A (522, 0x20A)1 Increment A (1024, 0x400)2 Jump to 1 (6145, 0x1801)3 Jump to 10 (6154, 0x180A) This instruction should never happen!Running this very simple program doesn't seem to do what it should at all and I end up with the program executing for two loops then exiting. I'll include an image of my simulation.As you can see in the image, it starts to work. A gets initialized with the value 10 and increments twice. For some reason though, the memory address gets to 3 reading in the jump to 10 command, causing the program to cease functioning.Any help would be greatly appreciated!Thanks

author: pyrohaz
author_rank: Regular Contributor
timestamp: June 03, 2015, 05:23:21 pm
content: Aha! I've managed to solve the problem! If I split the fetch into two separate operations, resetting the memory clock in one state then setting the memory clock in another state and decoding in a third state, all works fine!

author: Anand
author_rank: Contributor
timestamp: June 04, 2015, 09:18:21 am
content: Sadly, HDL support in this forum is terrible.Here's a project that can help you with your uC:http://www.arh.pub.ro/zolih/courses/dsd_project.htmlGrab what you can.

author: John_ITIC
author_rank: Frequent Contributor
timestamp: June 04, 2015, 06:30:38 pm
content: Quote from: pyrohaz on June 03, 2015, 01:27:18 pmTake a look a this PIC IP Core I designed for FPGA use. It has Verilog included and full documentation. There are lots of CPU Cores available on the net but few bother to document their work, which makes most not very useful for learning purposes...http://www.summitsoftconsulting.com/Pic10IpCore.htm

author: pyrohaz
author_rank: Regular Contributor
timestamp: June 16, 2015, 02:51:38 pm
content: Quote from: John_ITIC on June 04, 2015, 06:30:38 pmThat's a really useful resource! I completely agree about most of the cores on the internet having minimal documentation - or being exceptionally complex for learning purposes. The MCPU is pretty useful for learning the basics of a VHDL core but isn't (to an amateur like me, of course) a particularly useful core.Thank you for your contribution everyone!