ptr->member
instead of (*ptr).member
.<stdint.h>
, <stddef.h>
, <stdlib.h>
, <stdio.h>
, and <string.h>
.A
Implement a RISC-V function called sum_of_squares
that, given an integer n
, calculates the following sum:
If is not a positive integer (n ≤ 0
), the function should return the value of .
This task requires a recursive algorithm that uses the a1
register to keep track of the accumulated sum. You will implement the following function:
sum_of_squares
a0
: A 32-bit integer representing n
. You can assume that n ≤ 10000
.a1
: A 32-bit integer representing m
.a0
the result of:n ≤ 0
, return the value of m
.You have access to a helper function square
that computes the square of an integer.
square
a0
: An integer n
.a0
will hold the value of .To implement the recursive logic, consider updating the value of m
at each step. Specifically, let:
Then, the original sum:
can be rewritten as:
This transformation allows you to reduce the problem size by decrementing and updating with the new accumulated sum (). Use this approach to implement the recursive function and follow the RISC-V calling convention.
You are required to complete the RISC-V assembly code above, ensuring that no pseudo-instructions are used.
Fill in A01, A02, …, A11.
From the perspective of the callee, is it necessary to save any registers in the prologue and epilogue of the function? If so, which registers need to be saved, and where should the prologue and epilogue be placed? If not, provide a brief explanation as to why. __ A12 __
Answer A12 with appropriate explanation.
Next, we will implement the square
function, which calculates the square of an integer (a0 = n
) and returns the result in a0
. This function adheres to the RISC-V calling convention and avoids using RV32M instructions, ensuring compatibility with the RV32I base ISA.
You are required to complete the RISC-V assembly code above, ensuring that no pseudo-instructions are used.
Fill in A13, A02, …, A19.
B
Similar to logic gates, registers also experience a delay before their output reflects the sampled input. This delay is called the clock-to-Q (clk-to-q) delay, where "Q" typically denotes the output. The clk-to-q delay is the time between the rising edge of the clock signal and when the register's output updates to match the input.
In the circuit below:
Determine:
Answer B01, B02, and B03
C
Consider a left-complete binary search tree represented as an array. For example:
The corresponding binary tree structure is:
To find the position of elements in sorted order, we perform an in-order traversal (left-root-right) on this tree. The sorted order is:
Let's go through two specific examples:
nodes
), 3 is at index 8 (0-based).nodes
), 7 is at index 10 (0-based).This example demonstrates how elements in a left-complete, array-based binary search tree can be efficiently accessed and positioned based on their sorted order.
Sorted Order | Element | 0-Based Index | 1-Based Position |
---|---|---|---|
3rd | 3 | 8 | 9 |
7th | 7 | 10 | 11 |
Now let's generalize the problem. Suppose we want to find the position of the -th element in sorted order for a subtree rooted at position with a given height .
Define the function:
For example:
The typical method involves traversing the tree using a loop, utilizing the fact that the left and right child positions can be calculated as and , respectively. This approach has a time complexity of , where is the number of bits in the integer representation (commonly 32 bits).
We can achieve a more efficient solution with a time complexity of using a direct bitwise calculation:
C01 is a valid C expression; write it as concisely as possible.
- : Shifts the position left by bits, effectively scaling the root position to the height of the subtree.
- : Shifts right by 1 bit, halving it and adjusting for 0-based indexing.
The proposed approach avoids iterative traversal, greatly speeding up the computation, and you should complete the above. Explain whether the division (/
) operation could become a performance bottleneck in this solution. __ C02 __
Answer C02 with appropriate explanation.
D
We have several addressing modes for accessing memory (excluding the immediate mode):
lw
, lb
, sw
, and sb
).jalr
, jr
, and ret
, where jr
and ret
are pseudoinstructions translated into jalr
).What is the maximum range of 32-bit instructions that can be reached from the current PC using a jump instruction?
The range covers addresses within instructions from the current PC.
Answer D01 and D02.
Assume we are implementing a minimal RISC-V RV32I disassembler, which operates as follows:
You need to complete the program by filling in the specified placeholders.
D03, D04, …, D20 are valid C expressions; write them as concisely as possible.
Answer D03, D04, …, D20.
E
The critical path is the longest delay path between state elements in a circuit. The circuit’s clock speed cannot exceed this limit, as a faster clock would not allow sufficient time for the correct value to propagate to the state elements. By placing additional registers along the critical path, we can reduce the clock period by decreasing the amount of logic between registers.
The delay times for each circuit element are as follows:
For a single-cycle CPU, how long does it take to execute each instruction? Disregard the clock cycle duration based on the critical path, and assume that the setup times for both the register file (RegFile) and the program counter (PC) are identical.
sw
: __ E01 __ nslw
: __ E02 __ nsjal
: __ E03 __ nsAnswer E01, E02, and E03.
The top diagram shows the standard single-cycle datapath, while the second diagram illustrates a modified version. Referring to the modified single-cycle datapath, consider the information that must be carried forward from one stage to the next. Which pipeline registers are necessary at the end of each stage?
Answer E04, E05, E06, …, E11.
F
For all questions, assume there is no branch prediction or double-pumping (i.e., no write-then-read in a single cycle for the RegFile). Most data hazards can be resolved through forwarding, where the result from the EX or MEM stage is sent directly to the EX stage for use by a subsequent instruction.
Note: How is forwarding (EX to EX or MEM to EX) implemented in hardware? We add two wires: one from the start of the MEM stage carrying the ALU output, and another from the start of the WB stage. Both wires connect to the A/B multiplexers in the EX stage.
Identify data hazards in the code below and determine how forwarding could be used to resolve them.
There are two data hazards: one between instructions __ F01 __ and __ F02 __ , and another between instructions __ F03 __ and 3. The first hazard can be resolved by forwarding the ALU output from the __ F04 __ stage in cycle C3 to the start of the __ F05 __ stage in cycle C4. The second hazard can be resolved by forwarding the ALU output from the __ F06 __ stage in cycle C4 to the start of the __ F07 __ stage in cycle C5.
Answer F01, F02, and F03; all are numbers.
Answer F04 … F07; all are names of stages.
There are two data hazards present in the code:
t0
.t1
.The hazard between instructions __ F12 __ and __ F13 __ can be resolved using forwarding. However, the hazard between instructions __ F14 __ and __ F15 __ cannot be resolved with forwarding. This is because instruction __ F16 __ requires the result of instruction __ F17 __ at the beginning of cycle C6, but the result is not available until the end of cycle C6.
To resolve this, we can introduce a stall by inserting a nop
(no-operation) instruction between instructions __ F18 __ and __ F19 __ .
Answer F08, F09, … F19; all are numbers.
Imagine you are the compiler and can reorder instructions to minimize data hazards while still producing the same output. How would you modify the code? Reorder the instructions as __ F20 __ , since instruction 1 has no dependencies and can be moved without affecting the result.
Answer F20; It is the sequence of numbers.
For the RISC-V code provided below and a pipelined CPU without forwarding, how many data hazards would occur? __ F21 __
How many stalls would be required to resolve the data hazard(s) if the RegFile supports double-pumping (i.e., write-then-read capability)? __ F22 __
Answer F21 and F22; Both are numbers.
G
In Chisel, hardware components are referred to as modules. Each module extends the Module
class and includes a field named io
for defining its interface. The interface is specified using a Bundle
, which is wrapped with a call to IO()
. The Bundle
contains fields representing the input and output ports of the module. The direction of these ports is specified using Input()
or Output()
, based on the perspective of the component itself.
We will demonstrate this with a simple design where a counter is constructed using two components: an adder and a register. Next, we create a counter using these two components that counts from 0 to 9 and then resets. The schematic of the counter is depicted below.
An adder is used to increment the current counter value by 1. A multiplexer selects between the incremented value and 0. The result of this selection, referred to as next
, is used as the input to the register component. The output of the register represents the current count value and also serves as the output of the Count10
module (dout
).
The following shows the Chisel code for the Count10
module. The two components are instantiated using new
, wrapped with Module()
, and assigned the names add
and reg
. The register's output (reg.io.q
) is given the name count
.
We connect 1.U
and count
to the inputs of the adder component. The adder's output is named result
. The multiplexer selects between 0.U
and result
based on the current counter value (count
). The output of the multiplexer, named next
, is connected to the input of the register component. Finally, we connect the counter value (count
) to the output of the Count10
module (io.dout
).
Complete the above to make the design work.
Answer G01, G02, and G03.
A key component in circuits that perform computation, such as a microprocessor, is the Arithmetic Logic Unit (ALU). The figure below depicts the symbol of an ALU.
The ALU has two data inputs, labeled a
and b
, one function input labeled fn
, and an output labeled y
. The ALU processes inputs a
and b
and produces the result at the output y
. The fn
input determines which operation is applied to a
and b
. Typical operations include arithmetic functions like addition and subtraction, as well as logical functions like AND, OR, and XOR, hence the name ALU
.
The ALU is typically a combinational circuit with no state elements. It may also include additional outputs to indicate specific properties of the result, such as whether the result is zero or its sign.
The following code defines an ALU with 16-bit inputs and outputs, supporting addition, subtraction, OR, and AND operations, selected by a 2-bit fn
signal.
Answer G04 and G05.
H
Examine the following RISC-V assembly code for the floating-point addition function (fadd
), designed for single-precision floating-point addition using custom bitwise operations. Your task is to complete the code so that it functions as intended. This version includes simplified rounding logic, which may need enhancements for full IEEE 754 compliance.
Answer H01, H02, … H07.
Consider the following implementation of converting a signed 32-bit integer to a single-precision floating-point number (IEEE 754 format) using the RISC-V RV32I assembly. The focus is on understanding the low-level operations required to perform this conversion without relying on pseudo-instructions or extended instruction sets.
Answer H08, H09, and H10.