Electronics > FPGA


(1/3) > >>

I am still fairly new to all this but have been wanting to get a softcore going. When I finally realized how much was involved I backed off that plan. I have since found some code in VHDL @ https://www.fpga4student.com/2017/09/vhdl-code-for-mips-processor.html that comes with a testbench. The starting point is the ALU. I watched some videos to try and understand what all the ALU does. The basic idea, if I understand it correctly, is that you create op codes for what all you want the ALU to do. In the case of the above it looks like a 3 bit op code that adds, subtracts, AND, OR, with a comparator(?). Should it do more? Could it do more? Is that case statement the best way to go? On the same website there is another ALU with a 4 bit op code by itself that has multiplication, division, left and right shift, and so on as well as the above mentioned functions. I guess I'm kind of wondering why they didn't use the same thing for both? Still learning here and am curious of y'alls opinions. Thanks ahead of time.

That's a really interesting site, thanks for the link!  The processor, as described, is a very minimal implementation.  It only has 256 words of RAM.  The ALU will do 5 operations out of a maximum of 8.  You could possibly add 3 more if you think of them.  Multiply and divide are candidates but they won't be single cycle instructions.  Multiply can be on some machines but divide is just ugly.

Before you worry about how the ALU works, you need to understand how the CPU works from 10,000 feet up.  Memory contains instructions, instructions direct data flow through the ALU as well as branch instructions and such.  Part of the 16 bit instruction is the ALU operation code.  Look at VHDL Code for Control Unit to see all of the instructions.

Look at the non-ALU instructions like beq, lw and sw, j, and jal.  These stand for branch if equal, load word to register, store word from register, jump and (Jump And Link) which is a 'call' instruction for branching to a subroutine.  The return address is stored in R2 (I believe).

This is an interesting starter CPU.  There are certainly more complete examples but this might be a good place to start.

I use the case statement for that kind of thing all the time.  The alternative might be an if-elsif-else structure and that forms a priority tree which is likely a good deal slower.

There are cleaner ways to code the process.  You can move all the default <signal <= '0';> stuff to just ahead of the case statement and then you don't need to duplicate the assignments in every case.  When a particular case needs to assert a non-default value, just write it in.  VHDL will create hardware that uses the last value that is assigned.

Here's what it looks like for the process up to the first case:

--- Code: ---    process(State, BEN, IR,MemReady, Immediate, PSR, Interrupt)
        -- set default values for all signals
        GateBusSelect   <= GatePC;
        MIOenable       <= '0';
        LD_MAR          <= '0';
        LD_MDR          <= '0';
        LD_IR           <= '0';
        LD_BEN          <= '0';
        LD_PC           <= '0';
        LD_Reg          <= '0';  -- many other signals omitted
        case State is
            when  0     =>  -- Branch Instruction
                            if BEN = '1' then
                                NextState   <= 22;  -- branch is taken
                                NextState   <= 18;  -- branch not taken   
                            end if;

--- End code ---

Get the book "Free Range VHDL"  http://freerangefactory.org/pdf/df344hdh4h8kjfh3500ft2/free_range_vhdl.pdf

Make certain that every output is defined under every condition of the case statement or you will generate latches.  My most frequent error is adding a signal to a FSM and forgetting to add a default entry.

What's it good for?

It turns out that a tiny core is often just the right thing when you need to manipulate external signals that you don't want to code in logic.  Maybe it's a disk controller, maybe it's an external device of some other kind.  Something where it is easier to handle it in CPU code than VHDL.

You can arrange for your signals to be one of the registers by not connecting a particular register to memory and just delivering inputs when the register is read.  You could use a second register for outputs.


Better yet, create  INP and OUT instructions sort of like lw and sw.  Instead of a register address, you would have an IO address.

Next progression would be to add some kind of interrupt structure, probably vectored to specific addresses in low memory.

I do actually have Free range VHDL downloaded, as suggested to you at an earlier date. I will take a look at the CPU and all the codes. Thanks for the help and suggestions. I will keep going with this one.

I just installed Vivado on a new machine so I downloaded the files and they do indeed simulate and synthesize.  I would be targeting a Digilent Nexys 4 DDR board but before I can do that, I need to convert the 16 bit pc_out and alu_result vectors to 7 segment displays.  I have no reason to believe this thing has any issues, it looks pretty clean.

The Nexys 4 DDR is obsolete and has been replaced by the Nexys A7


It just happens to have 8 7-segment digits, perfect for the application.  It's also my favorite board for playing with these kinds of things because it has a lot of gadgets on the board.


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version