The
addi immediate operand is a byte-lane immediate: an unsigned eight-bit quantity shifted by or positions. ThusIt is not the sign extension of a 16-bit constant used by the MIPS instruction addi. For example, this design can add directly, but cannot add in a single immediate instruction. A field containing byte in the low lane adds 255, not .The
load and store memory address is exactly the content of . The arithmetic logic unit result is not connected to the memory-address input. ThereforeThere is no native base-plus-offset calculation during either memory instruction. The paper does not specify exception behavior for signed overflow, so the representable constants and address calculation are the justified differences; the datapath alone cannot establish MIPS-compatible overflow traps.Decompose the 32-bit pattern of into bytes:Let be its ten-bit encoding, so . The following custom-ISA assembly language sequence implements the requested sum:
addi t,s,x0
addi t,t,x1
addi t,t,x2
addi t,t,x3The symbols
x0 through x3 stand for the encoded ten-bit fields, not for the expanded 32-bit values. After line , the destination contains modulo . HenceIf , each instruction correctly uses the preceding partial sum. Zero-byte additions can be omitted except that, when , an initial instruction must still copy the original source if all earlier omitted bytes are zero. An assembler can initialize t with add t,s,0 instead and then emit only nonzero lanes. If , the intended register effect is discarded.For a MIPS instruction
lw t,k(s), first construct in a scratch processor register , using the four-lane sequence above with destination , and then issueload t,(u)For
sw t,k(s), construct the same address in and issuestore t,(u)Choose , or preserve a live scratch processor register according to the calling convention. In particular the store sequence must retain the original data in , even when . Both expansions need at most five custom instructions and have the same address and memory-word effects as the corresponding MIPS instructions, assuming aligned valid memory and 32-bit modular address arithmetic. When , the memory instruction alone suffices. These are listings for the examination's custom instruction set architecture, not native MIPS encodings; exact exception and pipeline behavior is outside the specified datapath.
Make the code a leaf procedure called
array_diff, copy the four argument processor registers into the temporaries used above, and replace the final label by a return. The copies are real addu instructions, avoiding an unexplained move pseudo-instruction:array_diff:
addu $t0,$a0,$zero
addu $t1,$a1,$zero
addu $t2,$a2,$zero
addu $t3,$a3,$zero
# insert the code of (i), including its initial zero-count test
# use the local label array_diff_done in place of done
array_diff_done:
jr $ra
sll $zero,$zero,0In the literal insertion, the
done: line from (i) is the array_diff_done: line displayed here; it is not a second return block. Under the usual calling convention, temporary processor registers are caller-saved. This procedure calls no other procedure and changes no saved processor registers, so it needs no stack frame or saved return address.For a 32-bit constant , define and using its unsigned binary representation. Load it with
lui followed by ori; both are single MIPS instructions. For base addresses and count , the main program is:main:
lui $a0,H_A
ori $a0,$a0,L_A
lui $a1,H_B
ori $a1,$a1,L_B
lui $a2,H_C
ori $a2,$a2,L_C
lui $a3,H_N
ori $a3,$a3,L_N
jal array_diff
sll $zero,$zero,0
main_after_call:
# c now contains the differences; continue the main program hereHere each
H_... and L_... is an assembler-time numeric constant, not an executed operation. lui places the high half and clears the low half; ori inserts the low half without sign extension. ThusThe jal instruction saves the return address after its branch delay slot in $ra; jr $ra resumes at main_after_call. A main routine that itself needs to return to a caller must save its incoming $ra before jal and restore it afterwards.Use byte addresses, so adjacent 32-bit array elements are four bytes apart. The following MIPS instructions include harmless
sll $zero,$zero,0 instructions in every branch delay slot; the second load is followed by another independent instruction before its value is consumed, also accommodating an early MIPS architecture with a load-use delay. All mnemonics here denote individual machine instructions. beq $t3,$zero,done # n=0: do not access any array
sll $zero,$zero,0
loop:
lw $t4,0($t0) # current a element
lw $t5,0($t1) # current b element
addiu $t0,$t0,4 # advance a; also separates lw from its use
subu $t6,$t4,$t5 # current difference, modulo 2^32
sw $t6,0($t2) # store current c element
addiu $t1,$t1,4
addiu $t2,$t2,4
addiu $t3,$t3,-1 # one fewer element remains
bne $t3,$zero,loop
sll $zero,$zero,0
done:A loop invariant at the head of the loop, after completed iterations, is that the three addresses point to elements , the count is , and every output element before equals the corresponding difference. One iteration reads element , stores its difference and advances to , preserving the loop invariant. The remaining count is a nonnegative loop variant decreasing by one, so the loop ends with .
The code uses
subu to avoid signed-overflow traps: the suffix does not restrict the operands to unsigned values. Its precise result isFor representable signed differences this is exactly . If trapping signed arithmetic is required instead, use sub and assume all differences are representable. The arrays must occupy valid word-aligned storage with no address wrap; the usual separate output array avoids overwriting unread inputs.Again use independent externally initialized MIPS instruction tests. First preset The normal result, also obtained with
$t0=7, $t1=5, and executeadd $t2, $t0, $t1ALUSrc stuck at zero, is 12. If the line is stuck at one, the second ALU operand is the sign-extended low 16 instruction bits. For this exact instruction they encode rd=10, shift amount zero and function , giving . The erroneous result is therefore .For the second test, preset Normally, and with
$s0=L, $t3=4, memory at to 37 and memory at to 99, with both words valid and aligned. Executelw $t3, 0($s0)ALUSrc stuck at one, the address is and the result is 37. With the line stuck at zero, the second ALU operand is the old $t3=4, so the load reads 99 from . ThusA writing MIPS instruction distinguishes a line stuck at zero. With A healthy line or a line stuck at one produces
$t0=7, $t1=5, $t2=99, executeadd $t2, $t0, $t1$t2=12; a line stuck at zero leaves $t2=99.To distinguish normal operation from stuck at one, execute a normally nonwriting MIPS instruction. The following functional test uses the usual concrete controller choice The ALU computes . Here
MemToReg=0 during sw, selecting the ALU result on the write-data bus. Prepare $t0=37 and $s0=L-16384, for an aligned writable address , then executesw $t0, 16384($s0)rt is register 8 ($t0), and immediate also puts 8 into bits . Thus either value of the otherwise irrelevant RegDst selects $t0. With a healthy RegWrite, $t0 remains 37. With RegWrite stuck at one and the specified write-data selection, the unwanted register file write changes $t0 to . Combining the two independent observations givesController qualification. The source diagram does not specify values of otherwise irrelevant control outputs during a store.
MemToReg is a don't-care condition when RegWrite=0; its chosen implementation matters when that enable line is faulty. The functional test above explicitly fixes this convention instead of assuming that all implementations resolve it identically. A manufacturing fixture can also observe the register file write-enable directly while executing add followed by sw: the expected pairs are normally, stuck at zero, and stuck at one. This second observation does not depend on unused write-data controls or on whether an unwanted write happens to repeat an old value.Run the following two MIPS instruction tests separately from externally prepared states, and inspect the register file after the indicated instruction. External preparation is useful in a manufacturing test: code that initializes processor registers through the very control line being tested need not work. Assume the one potentially faulty line is
RegDst; all other lines work normally.For the first test, preset The encoded
$t0=7, $t1=5, $t2=99, and executeadd $t2, $t0, $t1rt is $t1, while rd is $t2. A healthy line or a line stuck at one writes 12 into $t2. A line stuck at zero instead writes 12 into $t1, leaving $t2=99.For the second test, preset The zero immediate makes instruction bits zero. A healthy line or a line stuck at zero writes 37 into
$t3=4, $s0=L, and the aligned memory word at to 37, then executelw $t3, 0($s0)$t3; a line stuck at one attempts to write the MIPS zero register, leaving $t3=4. The MIPS zero register ignores attempted writes. Thus, recording the first test's $t2 and the second test's $t3,Execute this MIPS instruction fragment twice, once with equal operands and once with unequal operands, and observe whether its conditional branch is taken:Use
beq $t0, $t1, hit
sll $zero, $zero, 0
sll $zero, $zero, 0
hit:
sll $zero, $zero, 0$t0=7,$t1=7 for the first test and $t0=7,$t1=8 for the second. All padding instructions are explicit harmless MIPS instructions. In the pictured single-cycle model, the next program counter after beq is either hit or the sequential address. The branch target is deliberately different from the next sequential instruction. The extra padding also keeps a branch delay slot harmless if a test fixture uses an implementation with one, although the pictured model itself has none.A healthy
zero line reports the first subtraction as zero and the second as nonzero. A line stuck at zero prevents both branches, while a line stuck at one forces both branches. ThereforeObserve the branch decision or execution trace itself; an alleged unconditional beq used to skip result-recording code would also be affected by the fault.The register file in this datapath supplies both read ports combinationally for whatever read addresses the instruction fields present. Reading a processor register is harmless, and a result that the current MIPS instruction does not need can simply be ignored. Only writes require an explicit enable because writes change architectural state. There is consequently no functional need for
RegRead in this design.The data-memory read interface has an explicit
MemRead enable. Non-load MIPS instructions can present irrelevant or invalid addresses at the memory address input; an external memory transaction should not be initiated merely because those bits happen to be present. An explicit enable also permits interfaces with memory-mapped input-output, where a read can have a side effect. It can reduce unnecessary activity even for ordinary memory.This is a distinction in the supplied datapath, rather than a universal physical prohibition: other register files can have read enables, and an ideal side-effect-free memory can be modeled with continuous reads.The calling convention passes the integer argument in
$a0, returns the result in $v0, and uses jal with $ra for a call and its return address. The callee returns using jr $ra. Its stack frame grows downwards from $sp and must be removed before returning, restoring the caller's stack pointer.The
$s processor registers are callee-saved registers: a callee that uses $s0 or $s1 must restore their incoming values. The $a, $v, and $t processor registers are caller-saved registers; a caller must preserve any of their values that it needs after a call. Consequently foo keeps its own argument in $s0 and the first call's result in $s1, where nested calls preserve them. Because a nested jal overwrites $ra, foo also saves its incoming return address. Every recursive activation has its own stack frame.The supplied MIPS instructions use the paper's simplified convention: pseudoinstructions such as
subi are accepted, and control transfers have no branch delay slot. The completed code below follows that convention. A hardware implementation with delayed control transfers requires suitable scheduling or nop instructions throughout the supplied code as well.The missing MIPS instructions, in order, areThe comparison
bne $t0, $0, fooRet1
subi $a0, $s0, 3
add $v0, $s1, $v0slti $t0, $s0, 3 makes $t0 nonzero exactly when , so the first instruction selects the base case. The second forms from the saved argument, rather than relying on $a0 surviving the first call. After the second call, $s1 holds bar(y-2) and $v0 holds bar(y-3); the final addition puts their sum in $v0, as required by the calling convention.Fetch the MIPS instruction at the program counter, and compute . The opcode selects an MIPS R-type instruction; register-file read addresses and select the two operands. The function field selects ALU addition. The result returns through write-back multiplexer input zero to destination , and the next program counter is .
Zero extension 2026-10-31
Widen an -bit binary representation to bits by retaining the original low positions and filling every new high position with zero. This preserves the unsigned interpretation. A MIPS instruction such as
ori uses zero extension of its immediate operand, whereas addi uses sign extension.