CS 3330: HCL2D part 3: SEQ lab

This page is for a prior offering of CS 3330. It is not up-to-date.

Note: a minor bug in HCL2D which could cause register file or memory values to sometimes be written before the end of a cycle was fixed on 2017-03-03 12:18. We think it is very unlikely that this bug will cause your processor to operate incorrectly, but we’d encourage you to re-download HCL2D.

In this lab we’ll write a program that correctly executes irmovq, OPq, rrmovq/cmovXX, jmp, and rmmovq

We suggest you start with your hcl2 homework solution that implements irmovq and then add one instruction at a time.


1 More Stat, and nop

Stat should be

Difference from the book and the yis tool: we treat all addresses as valid, while the book gives the STAT_ADR error for addresses > 0xfff.

For nop, all you need to do is update the pc.


2 rrmovq

The textbook’s Figure 4.18 (page 387) notes the following semantics for rrmovq:

Stage rrmovq rA, rB
Fetch icode:ifun ← M1[PC]
rA:rB ← M1[PC + 1]
valP ← PC + 2
Decode valA ← R[rA]
Execute valE ← 0 + valA
Memory
Writeback R[rB] ← valE
PC Update PC ← valP

2.1 Comments

There’s more to fetch, particularly rA = i10bytes[12..16].

As with irmovq, 0 + valA is unneeded in our variant of HCL; we can use reg_outputA directly to set the register. You’ll need to add some muxes for things that are different between irmovq and rrmovq, like what goes into reg_inputE.

You’ll also need a new stage, decode: built-in signal reg_srcA determines what register is the source for the register move. If you set reg_srcA to something other than REG_NONE, reg_outputA will be set by the register file as the contents of that register.

2.2 Test cases

The following is in y86/rrmovq.ys:

irmovq $5678, %rax
irmovq $34, %rcx
rrmovq %rax, %rdx
rrmovq %rcx, %rax
 

If you run y86/rrmovq.yo you should see registers end as follows:

| RAX:               22   RCX:               22   RDX:             162e |

You should also now be able to get the same results using your simulator as you get from tools/yis when running y86/prog8.yo.


3 OPq

The textbook’s Figure 4.18 (page 387) notes the following semantics for OPq:

Stage OPq rA, rB
Fetch icode:ifun ← M1[PC]
rA:rB ← M1[PC + 1]
valP ← PC + 2
Decode valA ← R[rA]
valB ← R[rB]
Execute valE ← valB OP valA
Set CC
Memory
Writeback R[rB] ← valE
PC Update PC ← valP

3.1 Execute

There are two things to do in the Execute phase.

The simple part is the operation itself, the ALU, which is essentially a mux based on ifun with lines inside it like icode == OPQ && ifun == XORQ : reg_outputA ^ reg_outputB;.

The other part is setting condition codes. We’ll use a simpler set than the textbook: instead of trying to track overflow and so on, we’ll simply check zero and negative directly.

We’ll need a register to store those three flags inside of:

register cC {
    SF:1 = 0;
    ZF:1 = 1;
}

(ZF defaulting to 1 is consistent with yis, but we won’t test what you choose as the initial value o fthe condition codes.)

Register banks like cC have a special input stall_C which, if 1, causes the registers to ignore inputs and keep their current value. Thus, we want to stall C unless there was an OPq:

stall_C = (icode != OPq);

Once we have done that, we record if the (signed) value of valE is <, =, or > 0 (using unsigned comparison operators):

c_ZF = (valE == 0);
c_SF = (valE >= 0x8000000000000000);

3.2 Test cases

If you run your simulator on y86/opq.yo, which is an assembled version of

irmovq   $7, %rdx
irmovq   $3, %rcx
addq %rcx, %rbx # b = 3
subq %rdx, %rcx # c = -3  11..1101
andq %rdx, %rbx # b = 2
xorq %rcx, %rdx # d = -6  11..11010
andq %rdx, %rsi
 

you should see (without the -q flag, shown with some lines remove for brevity)

+------------------- between cycles    0 and    1 ----------------------+
| register cC(N) { SF=0 ZF=0 }                                          |
+------------------- between cycles    1 and    2 ----------------------+
| RAX:                0   RCX:                0   RDX:                7 |
| register cC(S) { SF=0 ZF=0 }                                          |
+------------------- between cycles    2 and    3 ----------------------+
| RAX:                0   RCX:                3   RDX:                7 |
| register cC(S) { SF=0 ZF=0 }                                          |
+------------------- between cycles    3 and    4 ----------------------+
| RAX:                0   RCX:                3   RDX:                7 |
| RBX:                3   RSP:                0   RBP:                0 |
| register cC(N) { SF=0 ZF=0 }                                          |
+------------------- between cycles    4 and    5 ----------------------+
| RAX:                0   RCX: fffffffffffffffc   RDX:                7 |
| RBX:                3   RSP:                0   RBP:                0 |
| register cC(N) { SF=1 ZF=0 }                                          |
+------------------- between cycles    5 and    6 ----------------------+
| RAX:                0   RCX: fffffffffffffffc   RDX:                7 |
| RBX:                3   RSP:                0   RBP:                0 |
| register cC(N) { SF=0 ZF=0 }                                          |
+------------------- between cycles    6 and    7 ----------------------+
| RAX:                0   RCX: fffffffffffffffc   RDX: fffffffffffffffb |
| RBX:                3   RSP:                0   RBP:                0 |
| register cC(N) { SF=1 ZF=0 }                                          |
+------------------- between cycles    7 and    8 ----------------------+
| RAX:                0   RCX: fffffffffffffffc   RDX: fffffffffffffffb |
| RBX:                3   RSP:                0   RBP:                0 |
| register cC(N) { SF=0 ZF=1 }                                          |
+----------------------- halted in state: ------------------------------+
| RAX:                0   RCX: fffffffffffffffc   RDX: fffffffffffffffb |
| RBX:                3   RSP:                0   RBP:                0 |
| register cC(S) { SF=0 ZF=1 }                                          |

You should also now be able to get the same results using your simulator as you get from tools/yis when running y86/prog1.yo through y86/prog4.yo (and y86/prog8.yo should still work too).


4 cmovXX

The cmovXX family of instructions have the same icode as rrmovq but non-zero ifuns.

The simplest way to implement cmovXX is to create a wire conditionsMet:1; and set it using a mux with entries like ifun == LE : C_SF || C_ZF;; then in the writeback stage of rrmovq make the reg_dstE (or reg_dstM if that’s what you used) REG_NONE if conditionsMet is false.

Recall that muxes execute only the first true case, so adding something like !conditionsMet && icode == CMOVXX : REG_NONE; before other cases when setting the dst_ should suffice. Remember that CMOVXX == RRMOVQ, so that line would need to be before a line with an expression like icode == RRMOVQ.

4.1 Test case

If you run your simulator on y86/cmovXX.yo, which is an assembled version of

irmovq $2766, %rbx  # 0xace → b
irmovq    $1, %rax  # 1 → a
andq    %rax, %rax  # set flags based on a (>)
cmovg   %rbx, %rcx  # move if g  (which it is): b → c  (c now 0xace)
cmovne  %rbx, %rdx  # move if ne (which it is): b → d  (d now 0xace)
irmovq   $-1, %rax  # -1 → a
andq    %rax, %rax  # set flags based on a (<)
cmovl   %rbx, %rsp  # move if l  (which it is): b → sp  (sp now 0xace)
cmovle  %rbx, %rbp  # move if le (which it is): b → bp  (bp now 0xace)
xorq    %rax, %rax  # a ^= a means 0 → a, and sets flags (=)
cmove   %rbx, %rsi  # move if e  (which it is): b → si  (si now 0xace)
cmovge  %rbx, %rdi  # move if ge (which it is): b → di  (di now 0xace)
irmovq $2989, %rbx  # 0xbad → b
irmovq    $1, %rax  # 1 → a
andq    %rax, %rax  # set flags based on a (>)
cmovl   %rbx, %rcx  # move if l  (which it is not): b → c  (not moved)
cmove   %rbx, %rdx  # move if e  (which it is not): b → d  (not moved)
irmovq   $-1, %rax  # -1 → a
andq    %rax, %rax  # set flags based on a (<)
cmovge  %rbx, %rsp  # move if ge (which it is not): b → sp  (not moved)
cmovg   %rbx, %rbp  # move if g  (which it is not): b → bp  (not moved)
xorq    %rax, %rax  # a ^= a means 0 → a, and sets flags (=)
cmovl   %rbx, %rsi  # move if l  (which it is not): b → si  (not moved)
cmovne  %rbx, %rdi  # move if ne (which it is not): b → di  (not moved)
irmovq    $0, %rbx  # 0 → b

you should end with registers

| RAX:                0   RCX:              ace   RDX:              ace |
| RBX:                0   RSP:              ace   RBP:              ace |
| RSI:              ace   RDI:              ace   R8:                 0 |

5 jXX

Note that the for jXX the immediate value is in bits [8, 72) not [16, 80). You’ll thus need a mux for valC.

Nothing to do in decode, execute, memory, or writeback; simply update the next PC (x_pc) to by valC instead of the offset PC (meaning another mux).

You’ll add conditional handling to jXX as part of your homework, but not part of this lab.

5.1 Tests

If you run your simulator on the following code

    irmovq 0xbad, %rax
    jmp A
    irmovq 0xbad, %rbx
    halt
A:
    irmovq 0xace, %rax
    halt
     

you should end up with ace, not bad, in rax and nothing in rbx.

(The .yo file is not in the y86/ folder already; to make it follow steps 1–4 of activity 4 in hcl1 lab.)


6 rmmovq

The textbook’s Figure 4.19 (page 389) notes the following semantics for rmmovq:

Stage rmmovq rA, D(rB)
Fetch icode:ifun ← M1[PC]
rA:rB ← M1[PC + 1]
valC ← M8[PC+2]
valP ← PC + 10
Decode valA ← R[rA]
valB ← R[rB]
Execute valE ← valB + valC
Memory M8[valE] ← valA
Writeback
PC Update PC ← valP

6.1 Comments

Memory is accessed by setting mem_addr to the memory address in question and either

You will also need to compute the memory address as reg_outputB + valC (the book suggests you do this in the ALU, meaning the same mux you used for OPq’s adding and subtracting).

6.2 Test Case

If both rmmovq is implemented correctly, the following should result in address 0xa2 containing byte 0x08.

irmovq $2, %rax
irmovq $8, %rbx
rmmovq %rbx, 160(%rax)
 

(The .yo file is not in the y86/ folder already; to make it follow steps 1–4 of activity 4 in hcl1 lab.)

7 Submit

Submit a file named seqlab.hcl on the submission page.

Copyright © 2016–2017 by Samira Khan, Luther Tychonievich, and Charles Reiss.
Last updated 2017-03-27 13:55:21