Main navigation | Main content
The standard Y86-64 instruction set provides the OPq
instruction family (addq, subq, andq, and
xorq) for doing arithmetic or bitwise operations on two
numbers. These instructions require that both operands be in
registers, which helps keep things simple. But you may have noticed
that this requirement is somewhat inconvenient in programming, since
you need to devote a separate instruction and register for a constant
to do even simple operations like adding 1.
For this lab, you're a hardware designer at the company designing
the next version of the Y86-64 processor, part of the team extending
the processor with new instructions. Specifically you're part of the
team implementing a new family of instructions, called
iOPq
for short, which do arithmetic or bitwise
instructions with a constant (immediate) operand. This new instruction
will take the place of the combination of an irmovq and an
OPq instruction, and also will save on the use of registers.
Other engineers on the team have already implemented support for the
new instruction in the assembler and simulator and created a couple of
test programs. Your job is to implement support for the new
instruction in the HCL control logic of the sequential Y86-64
processor implementation.
The iaddq
instruction has the effect of adding a
constant to a register, with the new value stored in the same
register, and there are also isubq
, iandq
,
and ixorq
instructions that do the same with the other
ALU operations. The operation of these instructions is summarized as
follows:
iaddq V, rA rA <- V + rA
isubq V, rA rA <- V - rA
iandq V, rA rA <- V & rA
ixorq V, rA rA <- V ^ rA
Notice that the order of the two operands is significant in the case of isubq. The designers chose this order so that isubq can be useful for other things besides what could be done with iaddq with a negative constant. For instance, isubq with a 0 constant is like a negation instruction.
The encoding of the new instructions is somewhat similar to the encoding of the existing OPq instructions. The instruction code is 0xc, and the function code uses the same encoding as for OPq: 0 for add, 1 for subtract, 2 for AND, and 3 for XOR. The register rA is encoded by the first hex digit of the register IDs byte, while the second hex digit of that byte is 0xf signifying no second register. The remaining 8 bytes of the instruction are a 64-bit little endian constant. For instance, since %rdi is register 7, the encoding of iaddq $8,%rdi is c07f0800000000000000.
Extract the lab files with this command:
tar xvf /web/classes/Spring-2020/csci2021/labs/0x9/lab0x9.tar
This will create a directory named lab0x9 with the files you'll
need for the lab. Because the hardware design is expressed in the HCL
language, you may want to review the description of that language in
the slides or textbook as you go. The file you'll be modifying is
seq.hcl
. See how each stage in the processor (Fetch,
Decode, etc.), control signals, and the program counter are all
described in HCL. This is a programmatic representation of the logic
of SEQ (a sequential version of a Y86-64 processor).
In this CPU description, the different instructions are named with constant values that start with an extra I. The existing OPq is referred to as IOPQ, and we've already given you a declaration of a new instruction type IIOPQ for the new iOPq. You'll need to modify several different parts of the processor so that they do the right thing when given the new instruction. Sometimes the new instruction will be similar to the old OPq, while other times it will need to be different.
Fetch
Recall that HCL expressions like
var in {list}
evaluate to true
if var
is found in the
list and false
if not. In the Fetch section we see this
in action where IOPQ
is listed under the
instr_valid
control signal. Add IIOPQ
to this list
since you want it to be read as a valid instruction.
Look at the other control
signals generated during Fetch. Which of these will IIOPQ
need?
Decode
Now recall HCL switch statements
[
boolExpr1: value1;
boolExpr2: value2;
...
boolExprN: valueN;
]
return the value corresponding to the first boolean expression that
evaluates as true
. The list-containment expression from
Fetch is used as a boolean expression.
In IOPQ
,
registers rA
and rB
are identified as the
sources for the ALU. IIOPQ
also has a register input to
the ALU, but how will you encode the logic for the constant value?
Execute, Memory Stage, PC Update
Once you've identified IIOPQ
's input sources in
Decode, you are ready to plug them into the ALU. We've covered all the
HCL syntax you need to continue. Use IIOPQ
's similarity to
IOPQ
to decide how to finish the Execute and Memory
Stages.
We've given you two sample test cases named negate.ys and asumi.ys. When you give the command make, it will assemble the test cases into Y86-64 object files using yas, and compile the HCL processor description seq.hcl together with some supporting C code into a simulator named ssim. We've also given you a version of the ISA-level simulator yis which has already been updated with the new instruction. In other words, yis will show you the expected behavior of the instruction. But if you try to run the examples before you have implemented the new instruction, you will see that they won't have the correct behavior. Instead ssim will stop with the status INS, meaning illegal instruction.
Once you have finished modifying the seq.hcl
file, you
will need to compile a new instance of the SEQ simulator
(ssim
) based on your HCL file, and then test it:
Building a new simulator.
You can use make
to build a new SEQ simulator:
make
This builds a version of ssim
that uses the control logic you
specified in seq.hcl
.
Testing your solution on a simple Y86-64 program. You can run the SEQ simulator on an object file with a command like ./ssim negate.yo. This will execute the program on the simulator until it halts, and print the final status. You can also have the simulator automatically check its results against the ISA model (like yis) using the option -t. The program negate.yo uses isubq to compute the negation of 10, so the final value in %rax should be 0xfffffffffffffff6. The program asumi.yo computes the sum of an array of long integers, so its final result should be 0x0000abcdabcdabcd.
For more information on the SEQ simulator refer to the handout CS:APP3e Guide to Y86-64 Processor Simulators. Note however that the version of the simulator you build in this lab doesn't include the GUI features.