digital electronics

profilestrength
W7_3_InsideUoSEducationalProcessor.pdf

1

Digital Systems and Microprocessor Design (H7068)

Daniel Roggen [email protected]

7.3. Inside UoS Educational Processor

2

Architecture

3

VHDL files

• cpu.vhd: top file for CPU

• cpusequencer.vhd: fetch/execute sequence

• cpuregbank.vhd: register file

• cpualu.vhd: ALU

4

Fetch/Execute sequence

• 3 clock cycles per instruction – Fetch high

– Fetch low

– Execute...

• Circuit must organize this sequence

5

Fetch/Execute sequence

• In cpusequencer.vhd

• Up counter until 2 (10b): 00=fetchh, 01=fetchl, 10=exec

6

Fetch/Execute sequence

entity cpusequencer is

port(

clk : in STD_LOGIC;

rst : in STD_LOGIC;

en : in STD_LOGIC;

seq : out STD_LOGIC_VECTOR(1 downto 0)

);

end cpusequencer;

• clk: clock

• rst: reset

• en: enable (currently not used: always wired to 1)

• seq: 2-bit code for fetchh, fetchl, exec

7

Fetch/Execute sequence

process(clk)

begin

if rising_edge(clk) then

if rst='1' then

s<="00";

else

if en='1' then

if s="10" then

s <= "00";

else

s <= s+1;

end if;

end if;

end if;

end if;

end process;

seq <= s;

clock in sensitivity list

All happens on rising clock edge

Reset

Normal behavior: if enabled, increment and wrap around at 2

• VHDL does additions with '+'! • Not taught in this module. • Synthesizer chooses an

implementation on its own • Choice not critical here with 2

bits; with more bits specific adder architectures may be preferred

8

Register file (register bank)

All D FF with enable and reset (synchronous)

registers RA-RD

9

Register file (register bank)

• Reminder: move instruction

• Always operation between dst and src, with result in dst

• Let's consider what to read from our register bank: – The register defined by dst and src (even if we deal with an

immediate-this is handled elsewhere

Instructions instruction(15..8) Instruction(7..0)

Move Opcode dd#m sd#m dreg src

mov r, r 0 0 0 0 0 0 r r - - - - - - r r

mov r, i 0 0 0 1 0 0 r r i i i i i i i i

mov r, [r] 0 0 0 0 0 1 r r - - - - - - r r

mov r, [i] 0 0 0 1 0 1 r r i i i i i i i i

mov [r], r 0 0 0 0 1 0 r r - - - - - - r r

mov [r], i 0 0 0 1 1 0 r r i i i i i i i i

10

Register file (register bank)

entity cpuregbank is

port(

clk : in STD_LOGIC;

rrd1 : in STD_LOGIC_VECTOR(1 downto 0);

rrd2 : in STD_LOGIC_VECTOR(1 downto 0);

rwr : in STD_LOGIC_VECTOR(1 downto 0);

rwren : in STD_LOGIC;

rst : in STD_LOGIC;

d : in STD_LOGIC_VECTOR(7 downto 0);

q1 : out STD_LOGIC_VECTOR(7 downto 0);

q2 : out STD_LOGIC_VECTOR(7 downto 0);

-- Only for debugging

dbg_qa : out STD_LOGIC_VECTOR(7 downto 0);

dbg_qb : out STD_LOGIC_VECTOR(7 downto 0);

dbg_qc : out STD_LOGIC_VECTOR(7 downto 0);

dbg_qd : out STD_LOGIC_VECTOR(7 downto 0)

);

end cpuregbank;

register to read from (the 2 bits come from src or dst in the instruction!)

outputs of the register bank

This would not be here in a "production" processor: here to display the content of the register on the 7 segment display

register to write to (always dst)

rwren: enable write d: data to write

11

Register file (register bank)

architecture Behavioral of cpuregbank is

signal enables: STD_LOGIC_VECTOR(3 downto 0);

signal qa,qb,qc,qd: STD_LOGIC_VECTOR(7 downto 0);

begin

ra: entity work.dffre generic map (N=>8) port map(clk=>clk,en=>enables(0),rst=>rst,d=>d,q=>qa);

rb: entity work.dffre generic map (N=>8) port map(clk=>clk,en=>enables(1),rst=>rst,d=>d,q=>qb);

rc: entity work.dffre generic map (N=>8) port map(clk=>clk,en=>enables(2),rst=>rst,d=>d,q=>qc);

rd: entity work.dffre generic map (N=>8) port map(clk=>clk,en=>enables(3),rst=>rst,d=>d,q=>qd);

enable each register q: output of each register

Instantiate a register with reset and enable.

Generic map: parameterized register.

12

Register file (register bank)

with rwr select

enables <="0001" and rwren&rwren&rwren&rwren when "00",

"0010" and rwren&rwren&rwren&rwren when "01",

"0100" and rwren&rwren&rwren&rwren when "10",

"1000" and rwren&rwren&rwren&rwren when others;

with rrd1 select

q1 <= qa when "00",

qb when "01",

qc when "10",

qd when others;

with rrd2 select

q2 <= qa when "00",

qb when "01",

qc when "10",

qd when others;

2-4 decoder: when write is enabled one of the register is enabled for write

first output multiplexer

second output multiplexer

13

Register

entity dffre is

generic (N : integer);

port(

clk : in STD_LOGIC;

en : in STD_LOGIC;

rst: in STD_LOGIC;

d : in STD_LOGIC_VECTOR(N-1 downto 0);

q : out STD_LOGIC_VECTOR(N-1 downto 0)

);

end dffre;

generic: useful to create components that can be parameterized

Here N is the number of bits of the D flip-flop

generic: useful to create components that can be parameterized

14

Register

architecture Behavioral of dffre is

begin

process(clk)

begin

if rising_edge(clk) then

if rst='1' then

q<=(others=>'0');

else

if en='1' then

q<=d;

end if;

end if;

end if;

end process;

all on rising edge

synchronous reset

copy if enabled

15

VHDL generic

In the component declaration:

entity entity_name is

generic (generic list);

port (port list);

end entity_name;

In the component instantiation:

label: entity work.comp_name

generic map (generic_association_list)

port map (port_association_list);

16

ALU

• A, B: input of the ALU (8 bits)

• aluop: operation to perform (5 bits) – bit 14 to bit 10 of instruction to identify the type of operation

– (part opcode and part other bits of the instruction)

• Implemented as multiplexer

• flags as discrete logic

17

ALU Instructions instruction(15..8) Instruction(7..0)

ALU 2 op opcode ALU op dreg src

add r, r 0 0 1 0 0 0 r r - - - - - - r r

add r, i 0 0 1 1 0 0 r r i i i i i i i i

xor r, r 0 1 0 0 0 0 r r - - - - - - r r

IR /

Test opco de

ALU op dr eg

immedite / reg

cmp r, r 0 1 0 0 0 1 r r - - - - - - r r

cmp r, i 0 1 0 1 0 1 r r i i i i i i i i

Instructions instruction(15..8) Instruction(7..0)

ALU 1 op opcode ALU op dreg

not r 0 1 1 0 0 0 r r - - - - - - - -

shr r 0 1 1 0 0 1 r r - - - - - - - -

... Only the bits in red are necessary to define the ALU operation!

18

ALU

entity cpualu is

port (

clk : in STD_LOGIC;

rst : in STD_LOGIC;

op : in STD_LOGIC_VECTOR(4 downto 0);

a : in STD_LOGIC_VECTOR(7 downto 0);

b : in STD_LOGIC_VECTOR(7 downto 0);

q : out STD_LOGIC_VECTOR(7 downto 0);

f : out STD_LOGIC_VECTOR(3 downto 0)

);

end cpualu;

Output

Flags

• Flags are always returned, but only used if the instruction is "cmp": control unit stores the flag in a flag register

Input A,B

19

ALU

r <= a+b when op(4 downto 3)="01" and op(1 downto 0)="00" else

sub(7 downto 0) when op(4 downto 3)="01" and op(1 downto 0)="01" else

a and b when op(4 downto 3)="01" and op(1 downto 0)="10" else

a or b when op(4 downto 3)="01" and op(1 downto 0)="11" else

a xor b when op(4 downto 3)="10" and op(1 downto 0)="00" else

not a when op(4 downto 0)="11000" else

'0'&a(7 downto 1) when op(4 downto 0)="11001" else

a(0)&a(7 downto 1) when op(4 downto 0)="11010" else

a(7)&a(7 downto 1) when op(4 downto 0)="11011" else

a(6 downto 0)&a(7) when op(4 downto 0)="11100" else

"00000000";

• Multiplexer

• Can you recognize an instruction?

• Add is 001000rr ------rr

• or 001100rr iiiiiiii

• (in red op)

• Therefore we react is op(4..3)=01 and op(1..0)=00

20

ALU

sf <= sub(7);

zf <= not(sub(7) or sub(6) or sub(5) or sub(4) or sub(3) or sub(2) or sub(1) or sub(0));

cf <= sub(8);

ovf <= (not a(7) and b(7) and sub(7)) or (a(7) and not b(7) and not sub(7));

f<=zf&ovf&cf&sf;

q<=r;

• Sign flag is bit 7 of the subtraction

• Zero flag obtained by oring

• Carry flag is bit 8 of the subtraction (only 8 bits are returned but subtraction done on 9 bits to obtain the carry)

• Overflow flag: triggers when the result flips sign: – positive minus negative must give positive

– negative minus positive must give negative

– Otherwise it's an overflow

Combine flags in a vector

21

Top level CPU entity

entity cpu is

generic(N : integer);

port(

clk : in STD_LOGIC;

rst : in STD_LOGIC;

ext_in : in STD_LOGIC_VECTOR(7 downto 0);

ext_out : out STD_LOGIC_VECTOR(7 downto 0);

ram_we : out STD_LOGIC;

ram_address : out STD_LOGIC_VECTOR(N-1 downto 0);

ram_datawr : out STD_LOGIC_VECTOR(7 downto 0);

ram_datard : in STD_LOGIC_VECTOR(7 downto 0);

-- Only for debugging

dbg_qa : out STD_LOGIC_VECTOR(7 downto 0);

dbg_qb : out STD_LOGIC_VECTOR(7 downto 0);

dbg_qc : out STD_LOGIC_VECTOR(7 downto 0);

dbg_qd : out STD_LOGIC_VECTOR(7 downto 0);

dbg_instr : out STD_LOGIC_VECTOR(15 downto 0);

dbg_seq : out STD_LOGIC_VECTOR(1 downto 0);

dbg_flags : out STD_LOGIC_VECTOR(3 downto 0)

);

end cpu;

External interface

Memory interface

22

CPU: instantiating the register bank comp_regs: entity work.cpuregbank port map(

clk=>clk,rst=>rst,

rrd1=>instruction(9 downto 8),

rrd2=>instruction(1 downto 0),

rwr=>instruction(9 downto 8),

rwren=>regwren,

d=>wrdata,

q1=>reg1out,q2=>reg2out);

• The instruction set is designed to help the control unit

• Source and destination always in the same location in the instruction – reg1out is the value in the "dst" register

– reg2out is the value in the "src" register

• It does not hurt to "wire up" src and dst to the register bank, even if the instruction does not use src/dst (the control unit handles that)

• Write only occurs with a Move or an ALU instruction!

1st register is "dst" 2nd register is "src"

write register is "dst "

Controls the write

1st and 2nd register output

23

CPU: source (helper signal)

source <= reg2out when instruction(12)='0' else

instruction(7 downto 0);

• Many instructions use a "source": Move, ALU, Jump, out

• All these instructions use as source: – an immediate in the lower 8 bits of the instruction if R#/I=1

– a register (output of the register bank) if R#/I=0

• R#/I is always instruction(12)

• source takes care of providing the right source (immediate or register) using a multiplexer – Either the immediate – or the 2nd output of register bank reg2out (src)

24

CPU: instantiating fetch/execute

comp_seq: entity work.cpusequencer port map(clk=>clk,rst=>rst,en=>'1',seq=>seq);

fetchh <= '1' when seq="00" else

'0';

fetchl <= '1' when seq="01" else

'0';

execute <= '1' when seq="10" else

'0';

fetch <= fetchl or fetchh; Helper signals - not mandatory but makes reading simpler

25

CPU: fetch instruction

comp_instrh: entity work.dffre generic map(N=>8)

port map(clk=>clk,rst=>rst,en=>fetchh,d=>ram_datard, q=>instruction(15 downto 8));

comp_instrl: entity work.dffre generic map(N=>8) port map(clk=>clk,rst=>rst,en=>fetchl,d=>ram_datard, q=>instruction(7 downto 0));

• instruction is the 16-bit instruction read from memory

• It is 16-bit register realized by two 8-bit D flip-flops

• First flip-flop enabled on "fetch high"

• Second flip-flop enabled on "fetch low"

26

CPU: Program counter / instruction pointer

comp_ip: entity work.dffre generic map(N=>N) port map(clk=>clk,rst=>rst,en=>'1',d=>ipnext,q=>ip);

ipnext <= ip+1 when fetch='1' else

ip when jump='0' else

jumpip;

• ip is the address where the instruction is read from

• N-bit D flip-flop – In the laboratory N is 5 bits (0...1F). It's a Design choice

• ipnext is the input of the D flip-flop

27

CPU: Program counter / instruction pointer

comp_ip: entity work.dffre generic map(N=>N) port map(clk=>clk,rst=>rst,en=>'1',d=>ipnext,q=>ip);

ipnext <= ip+1 when fetch='1' else

ip when jump='0' else

jumpip;

• When to write: at each clock cycle!

• What to write: – Fetch (high or low): ipnext = ip+1

– Exec: • ipnext does not change if the instruction is not a jump

• ipnext changes if it is an absolute jump, or a conditional jump with the condition valid

– (indicated by the signal jump)

28

CPU: Jump

• Unconditional jumps for 101x000 only

• Address is register or immediate: it is source defined before

Instructions instruction(15..8) Instruction(7..0)

Jump Unsigned: JA, JAE, JB, JBE

opcode Jump type immedite / reg

jmp r 1 0 1 0 0 0 0 0 - - - - - - r r

jmp i 1 0 1 1 0 0 0 0 i i i i i i i i

je/jz r 1 0 1 0 0 0 0 1 - - - - - - r r

je/jz i 1 0 1 1 0 0 0 1 i i i i i i i i

jne/jnz r 1 0 1 0 1 0 0 1 - - - - - - r r

jne/jnz i 1 0 1 1 1 0 0 1 i i i i i i i i

ja r 1 0 1 0 0 0 1 0 - - - - - - r r

ja i 1 0 1 1 0 0 1 0 i i i i i i i i

jb r 1 0 1 0 1 0 1 1 - - - - - - r r

jb i 1 0 1 1 1 0 1 1 i i i i i i i i

IR /

29

CPU: Jump

jumpip <= source(N-1 downto 0);

jump <= '1' when instruction(15 downto 13) = "101" and jumpconditionvalid='1' else

'0';

jumpconditionvalid <=

'1' when instruction(11 downto 8) = "0000" else

-- je/jz

'1' when instruction(11 downto 8) = "0001" and zf='1' else

-- jne/jnz

'1' when instruction(11 downto 8) = "1001" and zf='0' else

-- ja

'1' when instruction(11 downto 8) = "0010" and zf='0' and cf='0' else

-- jb

'1' when instruction(11 downto 8) = "1011" and zf='0' and cf='1'

else '0';

Where to jump if we were to do it

jump if there is a jump instruction and the jump condition is valid

always valid (unconditional jump)

Conditional jump when not zero: check the zero flag

30

CPU: when to write to register

• regwren: helper signal indicating when to write to register (register file)

• Write to register only during execute cycle

• And: – The instruction is a Move

– Or the instruction is ALU (but not "cmp")

– Or the instruction is In

31

CPU: what to write

• wrdata: helper signal containing the data to write: – Data for memory and register write

– wrdata is connected to the register bank write input!

• What to write: – Move direct instruction: the data to write is "source" (either immediate or

register)

– Move from memory instr.: write what the memory chip provides

– ALU instruction: write the output of the ALU

– In instruction: write what is on the input of the external interface

32

CPU: memory interface

• What to write (put on the data bus)? – wrdata always

• What to put on the address bus?

• When to write?

33

CPU: memory interface

ram_address <= ip when fetch='1' else reg2out(N-1 downto 0) when instruction(15 downto 10)="000001" else instruction(N-1 downto 0) when instruction(15 downto 10)="000101" else reg1out(N-1 downto 0) when instruction(15 downto 10)="000010" else reg1out(N-1 downto 0) when instruction(15 downto 10)="000110" else (others=>'0');

• Address: – IP during the fetch cycles

– The content of the src register or of the immediate for a move from memory

– the content of the dst register for a move to memory

– Otherwise zero • Explains why the first CPU lab showed always a zero on the

address!

34

CPU: when to write to memory?

• Move to memory during the exec cycle: – mov [b],23h

ram_we <=

'1' when execute='1' and instruction(15 downto 13)="000" and instruction(11 downto 10)="10"

else '0';

35

CPU: External interface

• External interface output is an 8-bit D flip-flop

• When to write: during exec when instruction is "out"

• What to write: source (i.e. register or immediate)

comp_regextout :

entity work.dffre generic map (N=>8)

port map(clk=>clk,rst=>rst,en=>ext_wren, d=>source,q=>ext_out);

ext_wren <=

'1' when execute='1' and instruction(15 downto 13) = "110" and instruction(11 downto 10)="00"

else '0';

36

CPU: flags

• SF, CF, OF, ZF are stored in a 4-bit D flip-flop

• When to write: during exec and "cmp" instruction

• What to write: the flag output of the ALU

comp_flags: entity work.dffre

generic map(N=>4)

port map(clk=>clk,rst=>rst,en=>flagwren,d=>alufout,q=>flags);

flagwren <= '1' when execute='1' and instruction(15 downto 13)="010" and instruction(11 downto 10)="01"

else '0';

37

38

39

Summary

• Brief insight into the processor architecture

• Basic understanding of the control unit function: – deciding what and when to "store" data in register

• Sufficient knowledge to perform the lab & coursework assignment on: – Modifying the instruction set (adding instruction)

– Tracing the state of key signals for a given instruction