A computer executes programs by following instructions. The instructions belong to an an instruction set. As mentioned in Chapter Welcome, we will use a subset of the OR1K instruction set as the instruction set for our computer.
As a first step, we will try to build a computer with only one instruction. Although somewhat restricted, this computer will be able to
We will start with deciding on a program to run our our computer. The program will be stored in a memory, and its instructions will be read, one by one, and actions will be taken.
Our computer needs a program in order to run. Before creating the program, we select an instruction to use.
We look in the OpenRISC 100 Architecture Manual, and we find the instruction l.movhi rD, K on page 81. This instruction takes a 16-bit value K, and shifts it left by 16-bits, and then places the resulting value in the register rD.
We need to put our instructions in memory.
Design a memory where the program can be stored. A memory implementation in VHDL is shown in Figure 11.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_textio.all; library std; use std.textio.all; library work; use work.string_lib.all; entity memory is generic (address_width: integer := 32; data_width: integer := 32; size: integer := 256); port( clk: in std_logic; write_enable: in std_logic; address: in std_logic_vector(address_width-1 downto 0); data_in: in std_logic_vector(data_width-1 downto 0); data_out: out std_logic_vector(data_width-1 downto 0)); end memory; architecture rtl of memory is type memory_type is array(0 to size-1) of std_logic_vector(data_width-1 downto 0); impure function init_memory return memory_type is file in_file: text is in "memory_contents.txt"; variable in_line: line; variable s: std_logic_vector(data_width-1 downto 0); variable memory: memory_type; begin report "length of memory is " & integer'image(memory'length); for i in 1 to integer(memory'length) loop if not endfile(in_file) then readline(in_file, in_line); hread(in_line, s); memory(i-1) := s; else memory(i-1) := (others => 'X'); end if; end loop; return memory; end function; signal memory: memory_type := init_memory; begin update: process(clk) begin if rising_edge(clk) then if write_enable = '1' then memory(to_integer(unsigned(address))) <= data_in; end if; end if; end process; data_out <= memory(to_integer(unsigned(address))); end rtl;
Figure 11. A memory in VHDL.
Create a pc that reads addresses expressed in bytes. Meaning that it increments itself with four for each instruction read. A program counter implementation in VHDL is shown in Figure 12.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity pc is generic (pc_width: integer := 32); port( clk: in std_logic; pc_out: out std_logic_vector(pc_width-1 downto 0) := (others => '0')); end pc; architecture rtl of pc is signal pc_value: std_logic_vector(pc_width-1 downto 0) := (others => '0'); begin update: process(clk) begin if rising_edge(clk) then pc_value <= std_logic_vector(unsigned(pc_value) + 4); end if; end process; pc_out <= pc_value; end rtl;
Figure 12. A program counter in VHDL.
We must interpret the instruction. We must take actions, in the form of writing parts of the instruction - the K value - into a register. We make a register bank with a destination register selection, and a data input, and a write enable (feels good to have that).
Here we wire the pieces together, and create a functioning computer, albeit with only one instruction! More to come, continue reading!