When a computer executes instructions, it often needs intermidiate storage places. Reading instructions from memory, writing results back to memory. For example adding numbers, and writing back only when all numbers have been added. Then registers can be used, to hold the intermediate sum, while the calculation is ongoing. We can refer to such a row using the term register. Another use of registers is for addressing. In this scenario, the value stored in the register is an address, addressing a part of the memory. One such register is holding an address pointing to the next instruction to be executed. This register is referred to as the program counter.
A D flip-flop can store one bit. We can imagine a register as a row of D flip-flops, each storing one bit, with the possibility to load new values into all D flip-flops simultaneously.
A register implementation in VHDL is shown in Figure 6.
library ieee; use ieee.std_logic_1164.all; entity n_bit_register is generic (N: integer := 8); port( clk: in std_logic; data_in: in std_logic_vector(N-1 downto 0); data_out: out std_logic_vector(N-1 downto 0)); end n_bit_register; architecture rtl of n_bit_register is signal reg_value: std_logic_vector(N-1 downto 0); begin update: process(clk) begin if rising_edge(clk) then reg_value <= data_in; end if; end process; data_out <= reg_value; end rtl;
Figure 6. A register in VHDL.
The code in Figure 6 defines an entity called n_bit_register. The entity has a port where inputs and outputs are defined. We have two inputs, called clk and data_in, and we have one output, called data_out.
The architecture block defines a variable called reg_value. The variable reg_value will contain the actual value stored in the register.
OBJS := n_bit_register.o n_bit_register_tb.o n_bit_register_tb: $(OBJS) ghdl -e $@ %.o: %.vhdl ghdl -a $< .PHONY: clean clean: rm n_bit_register_tb $(OBJS) e~n_bit_register_tb.o \ work-obj93.cf
Figure 7. A makefile for building and running the register in Figure 6.