0% found this document useful (0 votes)
23 views8 pages

Lab A

Uploaded by

pahe in
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views8 pages

Lab A

Uploaded by

pahe in
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

LabA: Integers and Binary Data

A1. Integer arithmetic (add, addi, sub)

We will begin with explaining how to instruct the RISC-V CPU to do some simple arithmetic,
e.g. to calculate the sum of 2+3.
(add)
The add instruction that uses 3 registers (x5, x6, and x7 in the following example) does just
that- it sums the 2 integer values in the registers x6 and x7 and stores the result in register
x5:
add x5, x6, x7
(addi)
But how to store the values of 2 and 3 in the registers x6 and x7 respectively? The following
form of the addi (add immediate) instruction stores the immediate value of 2, provided as part
of the instruction code, into the x6 register:
addi x6, x0, 2
More precisely, the above addi instruction sums the value stored in the register specified as
its second argument (in this case it is x0 which always contains the value of 0) with the
immediate value specified as its third argument (2 in this case) and stores the result (2 in this
case) in the register x6.
The assembly code using 3 registers (x5, x6, and x7) to calculate the sum of 2+3 could,
therefore, be as follows:
addi x6, x0, 2
addi x7, x0, 3
add x5, x6, x7
Save the above example as a file named a1a05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000000005 5
x6 t1 0x0000000000000002 2
x7 t2 0x0000000000000003 3
Note that the values are shown both in a hexadecimal format (the third column) and in a
decimal format (the fourth column).
An even shorter version using only 2 registers (x5 and x6) could be as follows:
addi x6, x0, 2
addi x5, x6, 3
Save the above example as a file named a1b05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000000005 5
x6 t1 0x0000000000000002 2
Now let us instruct the RISC-V CPU to calculate the difference 2-3. One can easily obtain the
correct result by calculating the sum 2+(-3) as follows:
addi x6, x0, 2
addi x7, x0, -3
add x5, x6, x7
Save the above example as a file named a1c05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0xFFFFFFFFFFFFFFFF -1

1
x6 t1 0x0000000000000002 2
x7 t2 0xFFFFFFFFFFFFFFFD -3
Make sure you understand why the hexadecimal value for x7 is 0xFFFFFFFFFFFFFFFD.
(sub)
The above approach, however, works only for subtracting constants that are known at compile
time. When subtracting values that are obtained at run time, e.g. input values and results of
intermediate calculations, etc., the sub (subtract) instruction must be used:
addi x6, x0, 2
addi x7, x0, 3
sub x5, x6, x7
Save the above example as a file named a1d05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0xFFFFFFFFFFFFFFFF -1
x6 t1 0x0000000000000002 2
x7 t2 0x0000000000000003 3

A2. Binary shifts (slli, srli, srai)

Now let us instruct the RISC-V CPU to use shifting to accomplish multiplication by a power of 2,
e.g.:
17 × 4
(slli)
The instruction slli (shift left logical immediate) takes the value in register x6 and shifts its
bits to the left while feeding zeros in the LSB (Least Significant Bit). The number of shifts is
provided as an immediate value (the shift amount is encoded in the lower 5 bits of the
immediate field; the immediate value of 0 produces no shift). The immediate value of 2 in our
case produces 2 shifts which effectively multiplies the integer in x6 by 4 (each 1-bit shift to the
left multiplies the number by another factor of 2) and stores the result in x5.
slli x5, x6, 2
The assembly code to load the value of 17 in x6, and then to multiply it by 4 and store the
result (68=17*4) in x5 could, therefore, be as follows:
addi x6, x0, 17
slli x5, x6, 2
Save the above example as a file named a2a05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000000044 68
x6 t1 0x0000000000000011 17
(srli)
In a similar way the instruction srli (shift right logical immediate) can be used for division by a
power of 2, to calculate for example the following:
88 / 8
The corresponding assembly source code to calculate the result (11=88/8) could be as
follows:
addi x6, x0, 88
srli x5, x6, 3
Save the above example as a file named a2b05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:

2
x5 t0 0x000000000000000B 11
x6 t1 0x0000000000000058 88
Now let us see what happens when we try to divide a negative value in a similar way:
-88 / 8
The corresponding assembly source code to calculate the result (-11=-88/8) could be as
follows:
addi x6, x0, -88
srli x5, x6, 3
Save the above example as a file named a2c05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x1FFFFFFFFFFFFFF5 2305843009213693941
x6 t1 0xFFFFFFFFFFFFFFA8 -88
(srai)
The obtained result in the x5 register shown above is obviously wrong. The problem is created
by the 0 bits fed into the MSB (Most Significant Bit) part of the number during the shift. Indeed,
the expected result is -11, which is a negative number that must have 1 as its most significant
bit. However, the result in x5 begins with 0x1 which represents the four bit sequence of 0001.
Fortunately, this problem is easily solved by using the srai (shift right arithmetic immediate)
instruction as follows:
addi x6, x0, -88
srai x5, x6, 3
The srai instruction treats the value in x6 as a signed number and a sign extension is carried
out. Since -88 is a negative number, 1-bits are fed into the register during the shift (in
contrast to 0-bits when the value is positive).
Save the above example as a file named a2d05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0xFFFFFFFFFFFFFFF5 -11
x6 t1 0xFFFFFFFFFFFFFFA8 -88
So far we have specified constants in a decimal format which is suitable for illustrating
arithmetic operations, including shifts when they are used for integer multiplication and division.
In some cases, however, we need to work with sequences of bit and manipulate them
irrespectively of the integer values they may map to. In such cases it is more convenient to
specify the constants in a hexadecimal format which allows direct mapping of hexadecimal
digits to sequences of 4 bits. A hexadecimal constant is specified as a sequence of
hexadecimal digits (the decimal digits and the first six letters of the English alphabet) preceded
by 0x, e.g. 0x1AB.
Shift instructions are often used for extracting subsequences of bits. We denote a
subsequence of bits by enclosing in square brackets the number of its starting bit and the
number of its ending bit separated by a column, e.g. [3:0] which denotes a 4-bit sequence
containing bits 3,2,1, and 0. Remember that the bits are numbered from 0 to 63 starting with
the rightmost one.
The following source code will move bits [7:4] of the value in x6 to the 4 least significant bits
[3:0] of x5 nullifying all its other bits:
addi x6, x0, 0x123
slli x7, x6, 56
srli x5, x7, 60
The above code uses slli to move the 4 bits of interest to the MSB part of the register (bits
[63:60]) followed by a srli to move the 4 bits of interest to the LSB part of the register

3
(bits [3:0]), taking advantage of the fact that srli feeds 0 bits in the MSB during the shift to
clear the bits [63:4] on the left.
Save the above example as a file named a2e05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000000002 2
x6 t1 0x0000000000000123 291
x7 t2 0x2300000000000000 2522015791327477760

A3. Logical operations (andi, or, xori)

(andi)
The following source code will extract bits [7:4] of the value in x6 by directly masking out all
other bits using the andi (and immediate) instruction. It will then move the bits to the LSB part
by a srli instruction:
addi x6, x0, 0x123
andi x7, x6, 0x0f0
srli x5, x7, 4
Save the above example as a file named a3a05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000000002 2
x6 t1 0x0000000000000123 291
x7 t2 0x0000000000000020 32
(or)
Another bitwise instruction, often used to combine subsequences of bits, is the or instruction:
addi x6, x0, 0x123
andi x6, x6, 0x0f0
addi x7, x0, 0x456
andi x7, x7, 0xf0f
or x5, x6, x7
In the above example we combine the middle hexadecimal digit of the value 0x123 with the
1st and the 3rd hexadecimal digits of the value 0x456 and obtain in result 0x426 in x5.
Save the above example as a file named a3b05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000000426 1062
x6 t1 0x0000000000000020 32
x7 t2 0x0000000000000406 1030
(xori)
The xori (exclusive or immediate) instruction calculates an exclusive or of its operands and
can be used, for example, to invert sequences of bits. The following assembly source inverts
(changes 0 to 1 and vice versa) all the bits of the value in x6 and stores the result in x5:
addi x6, x0, 0x123
xori x5, x6, -1
Save the above example as a file named a3c05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0xFFFFFFFFFFFFFEDC -292
x6 t1 0x0000000000000123 291

4
A4. Loading larger values (lui, EQU)

Let us try to use the approach described in the previous sections for calculating the sum of
4098+3.
Type the following instruction in the Source window and press the Compile button:
addi x6, x0, 4098
The following error message is shown in the Listing window:
0x0000000000000000 ERROR: imm OUT OF RANGE [-2048,4095] addi
rd,rs1,imm addi x6,x0,4098 addi x6, x0, 4098
It indicates that the immediate value we supplied as a third argument (4098 in our case) is out
of the allowed range. Indeed, as in the addi instruction there are only 12 bits for encoding the
immediate values (see the bit allocation of the I-type instructions on the “Green Card”) only
unsigned integers in the range of [0,4095] or signed integers in the range of [-2048,2047]
could be represented.
Note that the ALU itself does the addition using 64-bit registers, so all we have to do is to find a
way for putting the right values in the registers. One possible approach is to use more bits of
the instruction for encoding larger immediate values. Since some bits are still needed for
encoding the rd and the opcode, only immediate values represented by up to 20 bits can be
encoded in this way (see the U-type instruction format in the “Green Card”).
(lui)
This lui&addi method can be employed to store in a register a value represented by up to 32
bits. This method uses a sequence of 2 instructions, namely the lui (load upper immediate)
instruction (stores the most-significant 20 bits) and the addi instruction (stores the least-
significant 12 bits) as follows:
lui x6, 1
addi x6, x6, 2
Save the above example as a file named a4a05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x6 t1 0x0000000000001002 4098
Here is how we derived the constants 1 and 2 in the above lui and addi instructions. For the
decimal value of 4098 we have
4098 = 4096+2 = (4096×1) +(256×0) + (16×0) + (1×2) = 0x1002
The 32 bit binary representation of the above hexadecimal value is, therefore, as follows
0000 0000 0000 0000 0001 0000 0000 0010
The most-significant 20 bits of the above value are its first 20 bits from the left (shaded green)
which represent the value of 1 used in the above lui instruction as an immediate value:
0000 0000 0000 0000 0001
The least-significant 12 bits of the above value are its last 12 bits on the right (shaded yellow)
which represent the value of 2 used in the above addi instruction as an immediate value:
0000 0000 0010
The assembly code to calculate the sum of 4098+3 could, therefore, be as follows:
lui x6, 1
addi x6, x6, 2
addi x7, x0, 3
add x5, x6, x7
Save the above example as a file named a4b05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000001005 4101

5
x6 t1 0x0000000000001002 4098
x7 t2 0x0000000000000003 3
An even shorter version that uses only 2 registers could be as follows:
lui x6, 1
addi x6, x6, 2
addi x5, x6, 3
Save the above example as a file named a4c05.asm for possible future use and submit it.
Compile and run the above example. Check the resulting values in the Regs window:
x5 t0 0x0000000000001005 4101
x6 t1 0x0000000000001002 4098

A5. Assembly Language and Machine Instruction and Formats

Throughout the first half of this course you are expected to develop a comprehensive
understanding of the employed assembly language and the way it is compiled and mapped to
the RISC-V machine instructions. You should also fully understand how to analyze machine
instructions specified in binary, hexadecimal and other formats, extract and decode their fields,
and convert them to assembly language instructions. Mastering these techniques is also
indispensable for the second part of the course where a fully functional CPU will be
implemented in Verilog.
The RISC-V Green Card, a two-page reference sheet that comes as an insert in the course
textbook, will help you in this process.
The reference data in the RISC-V Green Card is organized in four sections denoted by
encircled numbers. Section provides descriptions of the RISC-V integer instructions (RV64I
BASE INTEGER INSTRUCTIONS) in alphabetical order organized in five columns:

The MNEMONIC (or the short name) of the instruction, e.g. add, addi, is specified in the first
column. The format of the instruction is specified in the second (FMT) column. In the above
example add is denoted as a register (R) type instruction while addi is denoted as an
immediate (I) type instruction. The table with the RISC-V CORE INSTRUCTION FORMATS is
provided in the end of Section .
The third column (NAME) provides a short description of the instruction while the fourth column
(DESCRIPTION) provides a formal description of the instruction functionality. For the add
instruction, the denotation R[rd] = R[rs1] + R[rs2] means that the value stored in the
first source register (rs1) is added to the value stored in the second source register (rs2) and
the obtained result is stored in the destination register (rd). Note that the register denotations
refer to bit sequences within the instruction code as shown in the RISC-V CORE

6
INSTRUCTION FORMATS table. For example, rs2 refers to a sequence of 5 bits starting at
bit 20 and ending at bit 24, often denoted as [24:20].
The DESCRIPTION of the addi instruction is different, namely R[rd] = R[rs1] + imm. In
this case imm denotes an immediate value that is stored in bits [31:20] of the instruction
code as per the RISC-V CORE INSTRUCTION FORMATS table.
The last column contains references to the notes listed in the end of Section .
It is important to learn how to employ the information provided on the Green Card as the
coverage of the different instructions in the course textbook, the lectures, and the labs may
vary. The RISC-V Green Card and the RISC-V Instruction Set Manual will provide you with the
necessary detail for a comprehensive understanding of the RISC-V instructions set. This will
also help you understand how the tools that we use function.
The RVS system compiles RISC-V assembly language instructions essentially converting them
to sequences of bits. Enter the following assembly language instruction in the Source window
of the RVS system and compile it:
add x5,x6,x7
Save the above example as a file named a5a05.asm for possible future use and submit it.
After the compilation, the resulting sequence of bits shown in the Listing window will be as
follows:
0000000 00111 00110 000 00101 0110011
The above sequence of bits can be mapped to the line corresponding to the R (register) format
in the RISC-V CORE INSTRUCTION FORMATS table to identify the values stored in the
corresponding instruction fields. The rd field [11:7] for example will map to the 5-bit
sequence of 00101 (the second from the right in the sequence shown above) which is the
binary representation of the decimal value 5. This matches the number of the destination
register (x5) specified in the original assembly language instruction shown above.
Details about the different instruction fields are provided in Section of the RISC-V Green
Card under the title OPCODES IN NUMERICAL ORDER BY OPCODE. Using this table you
can manually compile selected assembly language instructions and use the results to verify, for
example, the functionality of the RVS system. For illustration we will compile manually the
following assembly language instruction:
addi x6,x0,2
We begin by finding addi in the MNEMONIC column:

The I in the second column of the addi row indicates that we should use the immediate (I)
instruction format as shown in the second row of the RISC-V CORE INSTRUCTION
FORMATS table:

7
So, we have to fill the five fields (imm, rs1, funct3, rd, and Opcode) with the
appropriate values.
We take the Opcode from the third column (OPCODE) in the addi row of the OPCODES IN
NUMERICAL ORDER BY OPCODE table, namely 0010011. In a similar way we take the
funct3 value from the FUCT3 column, namely 000. And finally, we convert the numbers of
the employed registers and the immediate value to binary format. Note that the number of bits
used to represent the binary value is determined by the length of its corresponding field (5 bits
for the registers and 12 bits for the immediate.) The resulting manually compiled machine
instruction will be:
000000000010 00000 000 00110 0010011
The assembly code of the above machine instruction is as follows:
addi x6,x0,2
Enter the above assembly language instruction in the Source window of the RVS system and
compile it. Compare and make sure that the resulting binary code shown in the Listing window
matches the manually compiled machine instruction.
Save the above example as a file named a5b05.asm for possible future use and submit it.
The compiled machine code is essentially a sequence of 32 bits organized in five groups
corresponding to the fields in the I instruction format row in the RISC-V CORE INSTRUCTION
FORMATS table. In the computer memory, however, such sequences of bits are continuous so
our example bit sequence could also be denoted as follows:
00000000001000000000001100010011
For more concise writing we will often use hexadecimal representations where every four bits
of the sequences are denoted by a single hexadecimal digit as shown below (note that
hexadecimal values are preceded by 0x):
0x00200313
To obtain the above hexadecimal representation we could rewrite the bit sequence separating
its bits in groups of length four and then replace each group with the hexadecimal digit
corresponding to the value represented by its bits as shown below:
0000 0000 0010 0000 0000 0011 0001 0011
0 0 2 0 0 3 1 3
The complete Binary to/from Hexadecimal Conversion table is shown below:
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
0 1 2 3 4 5 6 7 8 9 A B C D E F

You might also like