How the STR Instruction Stores Register Data to Memory in NanoCore
The STR (Store Register) instruction moves data from a source register into a memory location addressed by another register, implementing register-indirect storage within the 256-byte address space.
The STR instruction is a fundamental operation in the NanoCore virtual CPU, enabling programs to persist register values into main memory. In the afaanbilal/nanocore repository, this instruction is implemented through a three-stage pipeline involving opcode definition in src/lib.rs, operand decoding in src/nanocore.rs, and direct memory writing with flag updates.
Opcode Definition and Instruction Format
The STR opcode is defined in src/lib.rs as part of the core instruction enum with the explicit documentation: “Store register to address in register: STR Rd Rs (Store Rd to [Rs])”【/cache/repos/github.com/afaanbilal/nanocore/master/src/lib.rs#L37-L39】. This declaration establishes the instruction length as 2 bytes—one byte for the opcode and one byte for the packed register operands【/cache/repos/github.com/afaanbilal/nanocore/master/src/lib.rs#L104-L105】.
The instruction uses register-indirect addressing, where Rd specifies the data register (source) and Rs specifies the address register (destination pointer).
Operand Decoding in the Fetch Stage
During the instruction fetch cycle, the emulator parses the second byte to extract two 4-bit register indices. For STR, the decoder creates an Operands::RegReg(rd, rs) variant, where rd holds the value to be stored and rs contains the target memory address【/cache/repos/github.com/afaanbilal/nanocore/master/src/nanocore.rs#L281-L283】.
This decoding scheme allows the instruction to reference any of the 16 general-purpose registers for both the data source and the memory pointer.
Execution Logic and Memory Writing
The execute method in src/nanocore.rs handles the Op::STR variant through a precise sequence of operations【/cache/repos/github.com/afaanbilal/nanocore/master/src/nanocore.rs#L357-L372】:
- Address retrieval: Reads the memory address from
cpu.registers[rs] - Value retrieval: Fetches the stored value from
cpu.registers[rd] - Memory write: Writes the value into
cpu.memory[address] - Flag update: Modifies the Z (zero) and N (negative) flags based on the stored value
- Trace generation: Formats the operation as
STR R{rd} [R{rs}]| (value) -> [address]for debugging
Register-Indirect Addressing
This implementation enables writing to any location within the 256-byte memory space by first loading the target address into a register. The separation of address and data registers allows flexible memory operations without hardcoding addresses into the instruction stream.
Practical Assembly Example
The following Rust code demonstrates assembling and executing an STR instruction that stores 0x42 from R0 into the memory address contained in R1:
// Assemble a simple program that stores 0x42 from R0 into the memory address in R1
let mut asm = nanocore::assembler::Assembler::default();
asm.assemble("
LDI R0 0x42 // R0 = 0x42
LDI R1 0x10 // R1 = 0x10 (target address)
STR R0 R1 // memory[0x10] = 0x42
").unwrap();
let mut core = nanocore::nanocore::NanoCore::new();
core.load_program(&asm.program, 0x00).unwrap();
core.run().unwrap(); // runs until HLT or cycle limit
assert_eq!(core.cpu.memory[0x10 as usize], 0x42);
The assembler encodes STR R0 R1 as the opcode byte followed by the packed register byte 0x01, where the high nibble represents Rd (R0) and the low nibble represents Rs (R1)【/cache/repos/github.com/afaanbilal/nanocore/master/src/assembler.rs#L15-L19】.
Summary
- The
STRinstruction is defined insrc/lib.rsas a 2-byte opcode using theRegRegoperand pattern. - Operand decoding in
src/nanocore.rsextracts two 4-bit register indices to identify the source data and target address. - Execution writes the source register's value into
cpu.memoryat the address specified by the second register. - The operation updates the Z and N status flags based on the value being stored.
- The assembler packs the register indices into a single byte following the opcode, enabling compact binary encoding.
Frequently Asked Questions
What is the binary encoding of the STR instruction?
The binary format consists of two bytes: the first byte contains the STR opcode, and the second byte packs the two register operands where the high 4 bits specify the data register (Rd) and the low 4 bits specify the address register (Rs). For example, STR R0 R1 encodes the register byte as 0x01【/cache/repos/github.com/afaanbilal/nanocore/master/src/assembler.rs#L15-L19】.
Which flags are affected by the STR operation?
The instruction updates the Z (zero) flag and N (negative) flag based on the value being stored to memory. These flags reflect whether the stored value equals zero or has its most significant bit set, respectively【/cache/repos/github.com/afaanbilal/nanocore/master/src/nanocore.rs#L357-L372】.
How does the NanoCore assembler handle STR instructions?
The assembler parses the mnemonic STR followed by two register identifiers, validates the register names, and emits the opcode byte plus a packed operand byte containing the 4-bit indices for the source and address registers【/cache/repos/github.com/afaanbilal/nanocore/master/src/assembler.rs#L15-L19】.
What is the maximum memory address accessible by STR?
The instruction can target any address within the NanoCore's 256-byte memory space (addresses 0x00 to 0xFF), provided the address register contains a valid 8-bit unsigned value. The emulator performs direct indexing into the cpu.memory array using the value retrieved from the address register.
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 →