CUGA-1

From Hamsterworks Wiki!

Jump to: navigation, search

This will be a complete hand rolled processor.

This FPGA Project was started June 2011.

Contents

Background

I always wanted to build my own CPU, and here's my chance!

Features I want to support - Interrupts - Memory access enforcement - Virtual memory - Virtualisation

Project status

Project started, with initial design started.

ALU Data paths

Cuga1 datapaths.png

The processor is based around three buses - the A (blue), B (green) and C (red) buses. Because this is an FPGA project these buses are implemented using multiplexers - internally FPGAs don't have tri-state logic, and having the tools fake just doesn't seem right. There are three places where three input multiplexers are required, when implemented this might create one "slow" path and two "fast" paths (the fast path having to pass through two multiplexers.

In this sketch the above doesn't show most of the control signals. But I'm making this up as I go along!

As of 31Jul2011 top lecwl object for the ALU is:

entity integer_core is
    Port (    clk      : in  STD_LOGIC;

            -- ALU control
            alu_mode    : in  std_logic_vector(2 downto 0);
            alu_thru_b   : in  std_logic;
            carry_in      : in  std_logic;
            carry_8      : out std_logic;
            carry_16      : out std_logic;
            carry_32      : out std_logic;
            zero_8      : out std_logic;
            zero_16      : out std_logic;
            zero_32      : out std_logic;
           
           -- Address register control
           addr_out_alu : in  STD_LOGIC;
           addr_out_pc  : in  STD_LOGIC;
           
           constant_sel   : in    STD_LOGIC_VECTOR(2 downto 0);
           -- Bus routing
           bus_a_datain   : in  STD_LOGIC;
           bus_a_const   : in  STD_LOGIC;
           bus_b_pc      : in  STD_LOGIC;
           bus_b_flags   : in  STD_LOGIC;

           -- Program counter control
           pc_write      : in  STD_LOGIC;
           pc_write_alu_out   : in  STD_LOGIC;
           pc_offset      : in  STD_LOGIC_VECTOR (2 downto 0);
           
           -- Register select/control
           regSelA        : in  STD_LOGIC_VECTOR (3 downto 0);
           regSelB        : in  STD_LOGIC_VECTOR (3 downto 0);
           commit         : in  STD_LOGIC;
           rollback       : in  STD_LOGIC;
           regWrite       : in  STD_LOGIC;

           -- major buses
           data_in      : in  STD_LOGIC_VECTOR (31 downto 0);
           data_out      : out STD_LOGIC_VECTOR (31 downto 0);
           address       : out STD_LOGIC_VECTOR (31 downto 0)
          );
end integer_core;

Register set

Due to the internals of an FPGA, the register set will be based around a set of 16 registers (matching the performance of the FPGA's 4x4 lookup tables. Because the register set will be implemented as dual port RAM, the contents of two registers will available at any time, but only one register will be writable.

Because I want to support virtual memory I need some way of rolling back partially complete transactions. My plan is to use two register banks, and a bit vector to keep track of which one is current and directing the writes into the other bank.

When a instruction commits the bit vector will be updated by XORing a mask based on the updated registers. Should an instruction need to be rolled out (e.g. due to page fault or instruction trap) the bit vector will not be updated, preserving the register's original contents. In general, the registers will be committed while the next instruction is being fetched.

The register bank will supply values to the A and B buses, and accept writes from the C bus.

Word size

I don't have any firm view on word size at the moment, other than the address size will be the word size, and the word size will be 2^n*8 bits. So the choices are 16, 32 or 64, with 64 bits being too large for implementation in a small FPGA. 32 bits is the way to go, and maybe drop down to 16 bits if it proves to be too big.

Constant store

A dedicated read-only store will also be able to supply a set of constants to the B Bus (e.g 0, +1, -1 or others such as offsets within the IRQ frame).

Value Reason
0 For do-nothings or when adding just the carry flag
1 Increment, updating the stack pointer
-1 Decrements, and updating the stack pointer
2 Size of a an interrupt stack frame
-2 Size of a an interrupt stack frame
4,8,16... Bit masks for bit operations

ALU

The ALU will take values from the A and B buses and compute a result to place on the C bus. It will also update the relevant processor status flags.

ALU operations

Mode bits Operation Notes
000 C = A alu_thru_b = '0'
000 C = B alu_thru_b = '1'
001 C = A and B
001 C = A or B
001 C = A xor B
001 C = A + B
001 C = A + B + carry Add with carry
001 C = A + not B + 1 Subtract
001 C = A + not B + carry Subtract with borrow

Memory interface

Memory Address Register

The memory interface will consist of the Address register, feed from either the A or C bus, or from the Program counter with an offset added. Because the Address register can be source from either side of the ALU operations like PUSH and POP can be optimised.

The Memory Address register is overwritten with any memory operation the value can't be assumed to persist outside of the current instruction.

DataIn Register

When a memory read completes, the result is stored in the DataIn register, which can be placed onto the A bus. Logic before this register deals with memory alignment issues.

As the value in the Data In register is overwritten with any memory read the value can't be assumed to persist outside of the current instruction.

DataOut Register

Data to be written to memory is placed into the data out register. Along with the value, the execution unit will supply the size of the write area to the MMU, allowing for a trap to be generated in anticipation of a future write for this instruction causing a trap (e.g. running out of stack when an IRQ occurs).

As the data value in the Data Out register can't be retrieved, the value can't be assumed to persist outside of the current instruction.

Definition for the integer core

This is the definition of the integer core. I've got it here for reference.

entity integer_core is
    Port ( clk      : in  STD_LOGIC;

           -- ALU control
           alu_mode : in  std_logic_vector(2 downto 0);
           carry_in : in  std_logic;
           carry_8  : out std_logic;
           carry_16 : out std_logic;
           carry_32 : out std_logic;
           zero_8   : out std_logic;
           zero_16  : out std_logic;
           zero_32  : out std_logic;
           
           -- Address register control
           addr_out_alu : in  STD_LOGIC;
           addr_out_pc  : in  STD_LOGIC;
           
           constant_sel   : in    STD_LOGIC_VECTOR(2 downto 0);
           -- Bus routing
           bus_a_datain  : in  STD_LOGIC;
           bus_a_const   : in  STD_LOGIC;
           bus_b_pc      : in  STD_LOGIC;
           bus_b_flags   : in  STD_LOGIC;

           -- Program counter control
           pc_write         : in  STD_LOGIC;
           pc_write_alu_out : in  STD_LOGIC;
           pc_offset        : in  STD_LOGIC_VECTOR (2 downto 0);
           
           -- Register select/control
           regSelA  : in  STD_LOGIC_VECTOR (3 downto 0);
           regSelB  : in  STD_LOGIC_VECTOR (3 downto 0);
           commit   : in  STD_LOGIC;
           rollback : in  STD_LOGIC;
           regWrite : in  STD_LOGIC;

           -- major buses
           data_in    : in  STD_LOGIC_VECTOR (31 downto 0);
           data_out   : out STD_LOGIC_VECTOR (31 downto 0);
           address    : out STD_LOGIC_VECTOR (31 downto 0)
          );
end integer_core;

Personal tools