CS355 Sylabus

# Decoding an Assembler Instruction

• We have seen - so far - how the CPU fetches the "next" assembler instruction from the memory at the address given by the PC register.

The next phase in the instruction execution cycle is to decode the assembler instruction.

Decoding means: find out what the assembler instruction means

• Before we can talk about decoding an assembler instruction, we need to know how each instruction is encoded...

• The assembler encoding is designed by each CPU manufacturer to their own liking...

Various motivations of differing importance will dictate the design, such as: fixed vs. variable length, how many registers does the CPU have, what can each register do, etc.

We will use a very simple-minded assembler code to illutsrate the CPU. Also, a simple assembler code will simplify the decoding process.

• The assembler code that our tou CPU will execute will be:

• Fixed length
• have very limited addressing modes

• The following is the assembler instruction encoding that we will use:

Instruction code Mnemonic Instruction Meaning
0000xxxxxxxxxxxx LODD Load Direct ac <- mem[x]
0001xxxxxxxxxxxx STOD Store Direct mem[x] <- mem[x]
0011xxxxxxxxxxxx SUBD Subtract Direct ac <- ac - mem[x]
0100xxxxxxxxxxxx JPOS Jump positive if ac > 0 then pc <- x
0101xxxxxxxxxxxx JZER Jump zero if ac = 0 then pc <- x
0110xxxxxxxxxxxx JUMP Jump always pc <- x
0111xxxxxxxxxxxx LODC Load constant ac <- x
1000xxxxxxxxxxxx LODL Load local ac <- mem[sp + x]
1001xxxxxxxxxxxx STOL Store local mem[sp + x] <- ac
1011xxxxxxxxxxxx SUBL Subtract local ac = ac - mem[sp + x]
1100xxxxxxxxxxxx JNEG Jump negative if ac < 0 then pc <- x
1101xxxxxxxxxxxx JNZE Jump nonzero if ac != 0 then pc <- x
1110xxxxxxxxxxxx CALL Call subroutine sp <- sp-1; mem[sp] <- pc; pc <- x
1111000000000000 PUSHI Push Indirect sp <- sp-1; mem[sp] <- mem[ac]
1111000100000000 POPI Pop Indirect mem[ac] <- mem[sp]; sp <- sp+1;
1111001000000000 PUSH Push on stack sp <- sp-1; mem[sp] <- ac
1111010000000000 POP Pop off stack ac <- mem[sp]; sp <- sp+1;
1111100000000000 RET Return from subroutine pc <- mem[sp]; sp <- sp+1;
1111101000000000 SWAP Swap ac and sp tmp <- ac; ac <- sp; sp <- tmp
11111100yyyyyyyy INCSP Increment sp sp <- sp + y
11111110yyyyyyyy DECSP Decrement sp sp <- sp - y

• The goal of the decoding process is to map each each assembler instruction to a sequence of micro-instructions that performs the indicated operation.

Example 1:

```  If assembler instruction read in is:     0000000000001111

According to the encoding in the table above, this assembler
instruction means:

the data from memory address 000000001111
into the AC (accumulator) register

We have seen how the CPU can instruct the datapath to load
data from memory using the following micro-instructions

1. mar = 0000000000001111; rd;  // Send out addr and read request
2. rd;                          // Use 0 of more of this instr to wait
3. rd; mbr;			    // When data is read on databus, read into MBR
4. ac := mbr;		    // Transfer data from MBR to destination
```
The webpage at (click here) contains picture that shows the dataflow in these instruction.

Example 2:

```  If assembler instruction read in is:     0001000000001111

According to the encoding in the table above, this assembler
instruction means:

Write (the first bits are 0001 which means "Store")
the data from the AC register to memory address
000000001111

We have also seen how the CPU can instruct the datapath to write
data from memory using the following micro-instructions

1. mar = 0000000000001111; mbr = ac; wr;
// Send out addr in MAR, the data in MBR and a write request.
2. wr;    // Use 0 of more of this instr to wait for the memory
// to finish
```
The webpage at (click here) contains picture that shows the dataflow in these instruction.

• As you see from the examples above, the instruction decode phase depends on the assembler instruction encoding and for our encoding, the decode procedure can be captured into the following high level program:

```START:

// Fetch next assembler instruction from memory at address "PC"
// (has been discussed)

// Now we decode the assembler instruction:

if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // This program segment decodes 00??.....

if ( 3rd left most bit in assembler code == 0 )
{ // This program segment decodes 000?.....

if ( 4th left most bit in assembler code == 0 )
{ // Jackpot: 0000xxxxxxxxxxxx is a load operation

mar = addr "xxxxxxxxxxxx" in assemler instruction; rd;
rd; mbr;	              // Read databus into MBR
ac := mbr; goto START; // Transfer data from MBR to destination
// and loop back (fetch next assm instr)
}
else
{ // Jackpot: 0001xxxxxxxxxxxx is a store operation

mar = addr "xxxxxxxxxxxx"; mbr = ac; wr;
// Send out addr in MAR, the data in MBR
// and a write request.
wr; goto START;  // Wait for memory to finish and then
// loop back (fetch next assm instr)
}
else
{ // This program segment decodes 001?.....
...
}
}
else
{  // This program segment decodes 01??.....
...
}
}
else
{  // This program segment decodes assembler instructions 1???.....
...
... (similar construction as above)
}
```

• Maybe you can/have already detected this program structure in the micro-program:
```ADDR   Micro Assembler Instruction                      Comment
===========================================================================
0:    mar := pc; rd;
1:    pc := pc + 1; rd; mbr;                 // Fetch assembler instruction

2:    ir := mbr; if n then goto 31;              // Test left most bit
3:    tir := lshift(ir + ir); if n then goto 22; // Test 2nd left most bit
4:    tir := lshift(tir); if n then goto 13;     // Test 3rd left most bit
5:    alu := tir; if n then goto 9;              // Test 4th left most bit

6:    mar := ir; rd;         	 // Micro-program instructions that read
7:    rd; mbr;			 // data at address given in the assembler instr
8:    ac := mbr; goto 0;	 // into AC register (and loop back to START)

9:    ir := ir and r8;          // Micro-program instructions that write
10:    mar := ir; mbr := ac; wr; // data from AC register to memory at address
11:    wr; goto 0;		 // given in the assembler instr & loop back

12:    alu := tir; if n then goto 17;                   {0010 or 0011?}
....
```

• Let me illustrate the decoding process with 2 concrete examples...

Decoding example 1: 0000000000001111
• Suppose the instruction fetch phase of the CPU fetched the assembler instruction code "0000000000001111" from memory.

As you have seen, this is the code for the assembler instruction move the word at memory location 15 to the AC register

Note: if you were to program in assembler, you may have written something like "move 15, AC" and the assembler will translate this "text" representation into the assembler code 0000000000001111

So after the micro-program instructions

```
0:    mar := pc; rd;
1:    pc := pc + 1; rd; mbr;
```
The MBR contains 0000000000001111.

• The next instruction in the micro-program is:

```     2:    ir := mbr; if n then goto 31;
```

This micro-instruction forms the following if-construct:

```
if ( left most bit in assembler code == 0 )
{ // Address 3: program segment decodes assembler instructions 0???.....
}
else
{ // Address 31: program segment decodes assembler instructions 1???.....
}
```

Pictorially:

• The assembler instruction 0000000000001111 is copied into the IR register
• The CPU tests and finds the left most bit of the assembler instruction is equal to 0 and will not branch.
• Since the first bit of the assembler instruction is 0 and the next MPC value is 3.

• The next instruction in the micro-program is:
```     3:    tir := lshift(ir + ir); if n then goto 22;
```

This micro-instruction forms the following if-construct:

```  if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // Address 4: program segment decodes 00??.....
}
else
{  // Address 22: program segment decodes 01??.....
}
```

Pictorially:

Therefore:

• if instruction code begins with 00... the next micro-program instruction address (MPC) is 4
• if instruction code begins with 01... the next micro-program instruction address (MPC) is 22
• Note: we already know the first bit in the assembler instruction is 0 because micro-instruction 3 is only executed when the left most bit in the assembler instruction is 0 (if it was 1, the micro-program would have branched to micro-instruction 31)

• The next instruction in the micro-program is:
```     4:    tir := lshift(tir); if n then goto 13;
```

This micro-instruction forms the following if-construct:

```  if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // Address 4: program segment decodes 00??.....
}

if ( 3rd left most bit in assembler code == 0 )
{  // Address 5: program segment decodes 000??.....
}
else
{  // Address 13: program segment decodes 001??.....
}
....
```

Pictorially:

Therefore:

• if instruction code begins with 000... the next micro-program instruction address (MPC) is 5
• if instruction code begins with 001... the next micro-program instruction address (MPC) is 13
• In this case, we go to micro-instruction 5.

• The next instruction in the micro-program is:
```     5:    alu := tir; if n then goto 9;
```

This micro-instruction forms the following if-construct:

```  if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // Address 4: program segment decodes 00??.....
}

if ( 3rd left most bit in assembler code == 0 )
{  // Address 5: program segment decodes 000??.....

if ( 3rd left most bit in assembler code == 0 )
{  // Address 6: program segment handles 0000xxxxx...
}
else
{  // Address 9: program segment handles 0001xxxxx...
}
}
....
```

Pictorially:

Therefore:

• if instruction code begins with 0000... the next micro-program instruction address (MPC) is 6
• if instruction code begins with 0001... the next micro-program instruction address (MPC) is 9
• In this case, we go to micro-instruction 6.

Hooray... the decode process is over.

The only way that the micro-program reaches the micro-instruction at MPC=6 is when the first 4 bits of the assembler code is 0000.... We know that the assembler instruction is a "load" (read) instruction !

We now enter the next phases of the instruction execution cycle: (3) fetch operand and (4) execute the assembler instruction.

The program segment that starts at address 6 will instruct the datapath to perform the "load" (read) operation. Let's look at it more carefully next...

• The next instruction in the micro-program is:
```     6:    mar := ir; rd;
```

Pictorially:

Therefore:

• The CPU sends out a READ indication to the memory
• The read operation has begun !
• The branch code = 00, so the next MPC = 7 (6+1)

• The next instruction in the micro-program is:
```     7:    rd; mbr;
```

Pictorially:

Result:

• The data from memory loction 15 is copied into the MBR
• The branch code = 00, so the next MPC = 8 (7+1)

• The next instruction in the micro-program is:
```     8:    ac := mbr; goto 0;
```

Pictorially:

Result:

• The data from memory loction 15 (in MBR) is copied into the AC register
• The branch code = 11, so the next MPC = 0

Notice that MPC = 0 now, and you have seen the micro-instruction at address 0 before: it fetches an assembler code from memory location at address given by the PC register. Since PC has been updated to point to the next assembler instruction, the CPU will now fetch and execute the next assembler instruction and the instruction execution cycle is complete (indeed, the CPU has just read the data from memory location 15 into the AC register as specified by the assembler instruction 0000000000001111.... and it moves on to fetch the next assembler instruction (and then decode it and execute it...)

• DEMO: (Demo instruction fetch)

• Run: /home/cs355000/bin/cs355-demo-computer

Do the following:

1. Press I, then press r
2. Maximize the window

3. Toggle key 1 TWICE - this resets the computer

4. Toggle key 1 REPEATED and you will see this:

• CPU sends address 0 to memory
• Memory returns the instruction at address 0 (which is: 0000000000001010) and it will be stored in IR (R3 - the 4th register)

• This instruction is a LOAD instruction

• Keep on toggling key 0 until the CPU fetched the value 15 (0000000000001111) from memory and stored in ACCU.

Decoding example 2: 0001000000001111
• Suppose the instruction fetch phase of the CPU fetched the assembler instruction code "0001000000001111" from memory.

As you know, this is the code for the assembler instruction that moves the word in the AC register to memory location 15.

Note: if you were to program in assembler, you may have written something like "move AC, 15" and the assembler will translate this "text" representation into the assembler code 0001000000001111

So we consider the case that this assembler instruction is fetched by phase 1 of the instruction execution cycle. After:

```
0:    mar := pc; rd;
1:    pc := pc + 1; rd; mbr;
```
the MBR contains 0001000000001111.

• Consider the next instruction in the micro-program:

```     2:    ir := mbr; if n then goto 31;
```

This micro-instruction forms the following if-construct:

```
if ( left most bit in assembler code == 0 )
{ // Address 3: program segment decodes assembler instructions 0???.....
}
else
{ // Address 31: program segment decodes assembler instructions 1???.....
}
```

Pictorially:

• The assembler instruction 0001000000001111 is copied into the IR register
• The CPU tests and finds the left most bit of the assembler instruction is equal to 0 and will not branch.
• Since the first bit of the assembler instruction is 0 and the next MPC value is 3.

• The next instruction in the micro-program is:
```     3:    tir := lshift(ir + ir); if n then goto 22;
```

This micro-instruction forms the following if-construct:

```  if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // Address 4: program segment decodes 00??.....
}
else
{  // Address 22: program segment decodes 01??.....
}
```

Pictorially:

Therefore:

• if instruction code begins with 00... the next micro-program instruction address (MPC) is 4
• if instruction code begins with 01... the next micro-program instruction address (MPC) is 22
• Note: we already know the first bit in the assembler instruction is 0 because micro-instruction 3 is only executed when the left most bit in the assembler instruction is 0 (if it was 1, the micro-program would have branched to micro-instruction 31)

• The next instruction in the micro-program is:
```     4:    tir := lshift(tir); if n then goto 13;
```

This micro-instruction forms the following if-construct:

```  if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // Address 4: program segment decodes 00??.....
}

if ( 3rd left most bit in assembler code == 0 )
{  // Address 5: program segment decodes 000??.....
}
else
{  // Address 13: program segment decodes 001??.....
}
....
```

Pictorially:

Therefore:

• if instruction code begins with 000... the next micro-program instruction address (MPC) is 5
• if instruction code begins with 001... the next micro-program instruction address (MPC) is 13
• In this case, we go to micro-instruction 5.

• The next instruction in the micro-program is:
```     5:    alu := tir; if n then goto 9;
```

This micro-instruction forms the following if-construct:

```  if ( left most bit in assembler code == 0 )
{  // This program segment decodes assembler instructions 0???.....

if ( 2nd left most bit in assembler code == 0 )
{  // Address 4: program segment decodes 00??.....
}

if ( 3rd left most bit in assembler code == 0 )
{  // Address 5: program segment decodes 000??.....

if ( 3rd left most bit in assembler code == 0 )
{  // Address 6: program segment handles 0000xxxxx...
}
else
{  // Address 9: program segment handles 0001xxxxx...
}
}
....
```

Pictorially:

Therefore:

• if instruction code begins with 0000... the next micro-program instruction address (MPC) is 6
• if instruction code begins with 0001... the next micro-program instruction address (MPC) is 9
• In this case, we go to micro-instruction 9 !!!

Hooray... the decode process is over.

The only way that the micro-program reaches the micro-instruction at MPC=9 is when the first 4 bits of the assembler code is 0001.... We know that the assembler instruction is a "store" (write) instruction !

We now enter the next phases of the instruction execution cycle: (3) fetch operand and (4) execute the assembler instruction.

The program segment that starts at address 9 will instruct the datapath to perform the "store" (write) operation. Let's look at it more carefully next...

• The next instruction in the micro-program is:
```     9:   ir := ir and r8;
```

Pictorially:

Therefore:

• This AND operation is also know as "masking".
• It "extracts" the address portion from the whole assembler instruction
• Now the IR register contains the address (15) and we are ready to perform the write operation...
• The branch code = 00, so the next MPC = 10 (9+1)

• The next instruction in the micro-program is:
```     10:    mar := ir; mbr := ac; wr;
```

Pictorially:

Result:

• MAR is written with the value 15, which is the address that the assembler instruction 0001000000001111 wants to update.
• MBR is written with the value in register AC, which is the value that the assembler instruction 0001000000001111 uses in the write operation.
• The CPU also sends out a WRITE indication.
• So the write instruct has started....
• The branch code = 00, so the next MPC = 11 (10+1)

• The next instruction in the micro-program is:
```     11:    wr; goto 0;
```

Pictorially:

Result:

• The write operation completes...
• The MBR data (= AC) is given more time to get written to memory location 15 (in MAR).
• The branch code = 11, so the next MPC = 0

Again, notice that MPC = 0 now, and you have seen the micro-instruction at address 0 before: it fetches an assembler code from memory location at address given by the PC register. Since PC has been updated to point to the next assembler instruction, the CPU will now fetch and execute the next assembler instruction and the instruction execution cycle is complete (indeed, the CPU has just written AC to memory location 15 as specified by the assembler instruction 0001000000001111....

• DEMO: (Demo instruction fetch)

• Run: /home/cs355000/bin/cs355-demo-computer

Do the following:

1. Press I, then press r
2. Maximize the window

3. Toggle key 1 TWICE - this resets the computer

4. Toggle key 1 REPEATED and you will see this:

• CPU sends address 0 to memory
• Memory returns the instruction at address 0 (which is: 0000000000001010) and it will be stored in IR (R3 - the 4th register)

• This instruction is a LOAD instruction

• Keep on toggling key 0 until the CPU fetched the value 15 (0000000000001111) from memory and stored in ACCU.

• After this, the CPU will fetch the second instruction (in memory addres 1).

• This instruction is a STORE instruction (STORE 72), which will store ACCU into memory location 72.