Left Shift cont.
A left shift (LSH) is a bitwise operation where the bits of a binary number are shifted to
the left by a specified number of positions. Each left shift moves the bits one place to the
left, and the rightmost positions are filled with zeros. This operation effectively multiplies
the number by powers of 2. The number of positions the bits are shifted determines the
factor by which the number is multiplied.
Following the explanation of how a 1-bit left shifter works using AND, OR, and inverters,
we can also implement the left shifter using multiplexers for a streamlined design.
In this method, we use four 2-to-1 multiplexers, each associated with one of the 4-bit
input’s positions. The multiplexers shift the bits left by one position when the enable signal
is active, filling the least significant bit with zero. This approach simplifies control over
shifting behavior by leveraging multiplexers to select between the original and shifted
bits.
The image below illustrates this circuit in Logisim.
2
In order to design the circuit, like always, we start by making a table with the rules applied
and analyzing it. From the table below we can conclude that the input can vary between 2
choices and the 2:1 multiplexer would be an excellent choice based on the given situation.
The same design can be achieved using one input element in Logisim for which the
attribute “Data bits” can be changed to 4.
We use the “Splitter” element in order to have the separated bits available for usage.
An example of that can be seen on the image below:
3
The shift amount for the diagrams that have been made is of fixed size 1 (shifting by one
bit to the left). The shift amount can also be changed and can vary. In order to implement
that, we need a couple of multiplexer levels (cascading multiplexers).
4
For the preceding Logisim circuit which is able to shift the input by 0, 1, 2 or 3 bits (Shift
amount input is 2 bits which can represent 4 different combinations i.e. 00, 01, 10, and 11)
we needed 2 sets of multiplexers. Why?
For the initial design, let’s start by making a rule table for it:
In order to make these 4 combinations work, we need two sets of multiplexers, each
defining the rule for a specific shift amount bit (because now we have 2 of those).
We start by making the first row (for the LSB-least significant bit or the right one in this
case) of shift amount with the first row of multiplexers. And then the second row (for
MSB-most significant bit or the left one in this case).
So, if we were to have a 5-bit input signal for the shift amount, we would need 5 rows of
cascading multiplexers.
LMS Assignment - Design a LeftShift16 in Logisim
Design a 16-bit left shifter circuit in Logisim.
The circuit should take a 16-bit input number and a 4-bit shift amount, allowing you to
shift the input by 0 to 15 positions to the left.
Use the provided template which is in the assignment files on this link.
After you finish and test out your circuit, submit the .circ file.
5
Register File
The Register file in a processor is a small but crucial component that stores a limited
number of digital data storage units known as registers. These registers hold data
temporarily during computation, acting as high-speed memory locations that can be
quickly accessed by the processor’s control logic and arithmetic logic units. Simply, the
purpose of the register file is to store output values generated by the ALU and to supply
the ALU’s inputs with operands.
Registers are temporary storage locations inside the CPU that hold data and addresses.
The register file is the component that contains all the general purpose registers of the
microprocessor. A few CPUs also place special registers such as the PC and the status
register in the register file. Other CPUs keep them separate.
A simple register file is a set of registers and a decoder. The register file requires an
address and a data input.
However, this simple register file isn't useful in a modern processor design, because there
are some occasions when we don't want to write a new value to a register. Also, we
typically want to read two values at once and write one value back in a single cycle.
Consider the following equation:
C=A+B
To perform this operation, we want to read two values from the register file, A and B. We
also have one result that we want to write back to the register file when the operation has
completed. For cases where we do not want to write any value to the register file, we add a
6
control signal called Read/Write. When the control signal is high, the data is written to a
register, and when the control signal is low, no new values are written.
Register File Design in Logisim - 8-Bit
Also, the internal structure of 8-bit register file would look like this:
7
Program Counter
The Program Counter (PC) is a critical CPU component responsible for holding the
address of the next instruction to be executed in the processor’s instruction memory.
In every cycle, the PC is updated to point to the location of the subsequent instruction,
ensuring that the program executes sequentially unless a jump or branch instruction is
modifying this flow.
By directing the processor to the next instruction, the PC enables efficient, predictable
instruction execution which is a fundamental aspect of a Reduced Instruction Set
Computer (RISC) architecture, like the RISC-V.
8
PC Design in Logisim
While designing the PC we need to take into consideration the key points that a Program
Counter must have. Those are: register to which we can write and read from, an adder
component which will be able to increase the memory location, and a clock signal where
we define that we will write to the register (the new increased value) on the rising edge of
the clock.
9
ALU
An Arithmetic Logic Unit (ALU) is a key component of a CPU, responsible for executing
arithmetic and logic operations.
The ALU that we are going to design is an 8-bit ALU which means that all operations are
performed on 8-bit values (it can process values from 0 to 255).
This simplified version of ALU is designed to perform four fundamental operations:
addition, subtraction, AND, and OR.
These operations are often core functions in processors, enabling basic computations and
logical decision-making in digital circuits.
ALU Design in Logisim
10
LMS Assignment - Design a 32-bit ALU in Logisim
Design a 32-bit Arithmetic Logic Unit (ALU) in Logisim.
The circuit should take two 32-bit inputs and a 3-bit operation input, which allows for
23=8 different operations to be performed.
Those operations are the following:
opcode 000 - Addition
opcode 001 - Subtraction
opcode 010 - Bitwise AND
opcode 011 - Bitwise OR
opcode 100 - Bitwise XOR
opcode 101 - Bitwise NOT (for the first input)
opcode 110 - Bitwise NOT (for the second input)
opcode 111 - Left Shift (shift the bits of the first input one position to the left)
Use the provided template which is in the assignment files on this link.
After you finish and test out your circuit, submit the .circ file.
11
RARS
RARS, or RISC-V Assembler and Runtime Simulator, is a tool used to simulate and run
RISC-V assembly language programs. It provides an environment where users can write,
assemble, and execute RISC-V code, making it particularly useful for students and
professionals learning RISC-V architecture.
Setting up RARS Simulator
In order to use the RARS simulator, your PC must have the Java Development Kit (JDK)
installed on your Windows. In order to install it, you can download it by clicking on the
link. After installing JDK, you can check whether the installation succeeded by opening
the Microsoft PowerShell in Windows, and simply writing the command “java”.
In case you see the output as on the image above, this means that JDK was successfully
installed on your PC. Now, after JDK is ready to run, you can move on to downloading the
RARS simulator. The simulator can be downloaded by clicking on the link.
This will download the .jar file. Now, you should use the JDK in order to run the simulator.
12
By using the cd command, navigate to the folder where the .jar file has been downloaded.
Launch the simulator by using the following command
java -jar rars1_6.jar
After a few seconds, you will see the following screen which means that your simulator is
ready for execution.
Writing Your First Assembly Program in RARS
Assembly language programming introduces you to the fundamentals of how a CPU
executes instructions. In this example, we’ll look at a simple RISC-V assembly program in
RARS that uses basic commands to perform arithmetic operations and demonstrates an
infinite loop.
13
In order to write a program in assembly language, you need to use instructions. In RISC-V
assembly, there are various instruction types, each tailored for different tasks such as
arithmetic, data storage, conditional branching, and jumps. These include R-type, I-type,
S-type, B-type, U-type, and J-type instructions. However, for this lab session, we'll focus
on three essential types to get started:
● R-Type: Used for arithmetic and logical operations between two registers. It
includes instructions like add, sub, and, and or.
● I-Type: Primarily for operations that involve an immediate (constant) value, such as
addi (add immediate) and load instructions like lb (load byte). It’s also used for
certain control instructions, like conditional branches (e.g., beq).
● J-Type: For jump instructions, allowing for unconditional jumps within the code.
The main example is jal (jump and link), which is used for function calls as it also
stores the return address.
In programming we work with variables as a utility for storing information. In RARS that
would be a register. On the right side of the RARS simulator, you can see all of the
registers that exist. Important ones for us are the named “zero” and “pc”.
● Zero register (x0) is the one which always holds the value zero.
● PC is the program counter which we mentioned before. It holds the address of the
next instruction to be executed.
●
Let’s write the code in which we will store two immediate values 5 and 6 into registers and
then sum the value from those registers.
In order to do that, click on the file icon in the navigation bar.
This will open a new file in which we can write assembly code.
14
The code that we will put inside the that file would look something like this:
.text #1 Start of the code section
main:
addi x12, x0, 6 # Load immediate value 6 into register x12
addi x13, x0, 4 # Load immediate value 4 into register x13
add x23, x12, x13 # Add values in x12 and x13, store result in x23
j main # Jump back to main label (creates an infinite loop)
If we want to run this, we need to “assemble” this code. We do that by click on “Run” in the
top bar and select the “Assemble” (or just press F3).
This will open the “Execute” pane in which we can see the instructions we wrote.
1
Comments in assembly start with ‘#’.
15
If you look right now on the right in the registers pane, you will see that the program
counter register (PC), like we explained, holds the address of the instruction that will be
executed next.
In order to go one instruction at a time, we select the “Run one step at a time” once.
This will now run the first instruction in which we sum the immediate value 6 with the zero
register x0 (meaning the output of that operation will result in 6 because 0+6=6).
We the first parameter of the addi instruction as x12 which is the register we want to
store the output of the operation. If we check the x12 register, we can notice that the
value changed from 0 to 6.
Also, program counter increased by 4 which matches with the address of the following
instruction.
16
The second instruction will sum the immediate value 4 with zero register, resulting in 4,
and save the output in x13 register.
The add instruction that is the next one in the line is the r-type instruction which means it
does arithmetic and logical operations between registers, or to be more exact, between
the values that the specified registers store.
The first parameter is the register to store the output and the second and the third are the
registers which values we want to sum.
We set the output register as x23. If we check that register after we go step further, you
will se that it increased to “a” (hexadecimal for 10).
The last instruction is the j-type and is the “jump” command. We set the jump to be to
“main”. This means that after finishing the given commands before, the program will start
again from the “main:” annotation (which means that we end up in an infinite loop).
17