How the CMP Instruction Works in NanoCore: Flag Effects and Implementation
The CMP instruction in NanoCore compares two registers, stores a result code (0, 1, or 2) in the destination register, and updates the Zero (Z) and Negative (N) status flags to enable conditional branching.
The CMP (compare) instruction is a fundamental register-to-register operation in the NanoCore educational CPU emulator written in Rust. Understanding how this instruction manipulates the processor status flags is essential for writing correct conditional logic in NanoCore assembly programs.
CMP Instruction Opcode Definition and Decoding
The CMP opcode is formally defined in the Op enum located in src/lib.rs. The source code documents its purpose with the comment: "Comparison: CMP Rx Ry (Set zero flag if Rx = Ry, otherwise reset)" at lines 55–56.
During the instruction fetch and decode cycle, the fetch_decode method in src/nanocore.rs (lines 81–82) identifies the CMP opcode and parses the operands as Operands::RegReg(rd, rs). This encoding treats the first operand as the destination register (rd) and the second as the source register (rs).
Execution Logic and Comparison Algorithm
The core execution logic resides in the execute method within src/nanocore.rs (lines 25–66). CMP shares an execution arm with bitwise operations (AND, OR, XOR), but implements distinct comparison semantics:
let v1 = self.cpu.registers[rs as usize];
let v2 = self.cpu.registers[rd as usize];
let result = if v1 == v2 { 0 } else if v1 > v2 { 1 } else { 2 };
self.cpu.registers[rd as usize] = result;
self.cpu.update_zn_flags(result);
The algorithm performs the following steps:
- Read values:
v1loads the value from the source register (rs), whilev2loads from the destination register (rd) - Compare: The instruction evaluates the relationship between the two values
- Store result: The destination register
rdreceives the comparison outcome (0 for equal, 1 for greater-than, 2 for less-than) - Update flags: The CPU updates status flags based on the result value
Flag Updates and Status Register Effects
After computing the comparison result, the instruction calls self.cpu.update_zn_flags(result) defined in src/cpu.rs (lines 69–79). This helper function modifies the processor status register according to the result value.
Zero Flag (Z) Behavior
The Zero flag (Z) is set if and only if the two compared registers contain identical values. When v1 == v2, the result is 0, causing update_zn_flags to set FLAG_Z. For any non-zero result (1 or 2), the Zero flag is cleared. Conditional jump instructions JZ and JNZ query this flag via the CPU::FLAG_Z constant defined in src/cpu.rs (lines 49–52) to control program flow.
Negative Flag (N) Behavior
The Negative flag (N) is updated according to the most significant bit (MSB) of the result. However, since CMP can only produce results of 0, 1, or 2, the Negative flag is effectively always cleared after a comparison operation. The flag update logic still executes for consistency, but no CMP operation can yield a negative result.
Unaffected Flags
The CMP instruction leaves the Carry (C) and Overflow (Y) flags unchanged. No logic in the CMP execution path modifies these status bits.
Practical Assembly Examples
Equality Test with Conditional Jump
This example demonstrates detecting equal values and branching based on the Zero flag:
LDI R0 0x05 ; R0 = 5
LDI R1 0x05 ; R1 = 5
CMP R0 R1 ; R0 = 0 (equal), Z flag set
JZ label ; Branch taken because Z is set
After execution, register R0 contains 0 and the program counter jumps to label.
Greater-Than Comparison
Detecting when one register exceeds another:
LDI R2 0x09 ; R2 = 9
LDI R3 0x03 ; R3 = 3
CMP R2 R3 ; R2 = 1 (greater than), Z flag cleared
JZ equal ; Not taken (Z is 0)
JNZ not_equal ; Taken because Z is cleared
The result 1 in R2 indicates the first operand was larger than the second.
Less-Than Detection
Identifying when the destination is smaller than the source:
LDI R4 0x01 ; R4 = 1
LDI R5 0x04 ; R5 = 4
CMP R4 R5 ; R4 = 2 (less than), Z flag cleared
Register R4 receives the value 2, signaling that the original R4 value was less than R5.
Summary
- Opcode location: Defined in
src/lib.rsasOp::CMPwith explicit documentation about zero flag behavior - Decode logic: Parsed in
src/nanocore.rsasOperands::RegReg(rd, rs)whererdis the destination andrsis the source - Result encoding: Stores
0for equal,1for greater-than, and2for less-than in the destination register - Flag effects: Sets Z (zero) flag only on equality; updates N (negative) flag but always clears it; leaves C and Y unchanged
- Branch dependency: Conditional jumps JZ and JNZ read
FLAG_Zto determine branching decisions
Frequently Asked Questions
What flags does the CMP instruction affect in NanoCore?
The CMP instruction affects only the Zero (Z) and Negative (N) flags. The Zero flag is set when the compared registers are equal and cleared otherwise. The Negative flag is updated by the update_zn_flags function but remains cleared because CMP results (0, 1, or 2) never have the most significant bit set. The Carry (C) and Overflow (Y) flags remain unchanged.
Where is the CMP instruction implemented in the NanoCore source code?
The implementation spans three files: the opcode definition exists in src/lib.rs (lines 55–56), the decoding logic resides in src/nanocore.rs within the fetch_decode method (lines 81–82), and the execution engine lives in the same file's execute method (lines 25–66). The flag update helper function is located in src/cpu.rs (lines 69–79).
How does CMP handle register comparison results?
CMP performs a three-way comparison. It subtracts the conceptual values and stores an integer code in the destination register: 0 if the registers are equal, 1 if the destination register was greater than the source, and 2 if the destination was less than the source. This result overwrites the original value in the destination register rd.
Can CMP trigger a negative flag in NanoCore?
No, CMP cannot set the Negative flag because the possible result values (0, 1, and 2) are all non-negative integers with the most significant bit equal to zero. While the update_zn_flags function checks the MSB of the result, the comparison algorithm guarantees the Negative flag will always be cleared after executing CMP.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →