# How the STR Instruction Stores Register Data to Memory in NanoCore

> Learn how the STR instruction in NanoCore stores register data to memory. Explore register-indirect storage and its 256-byte address space functionality for efficient data management.

- Repository: [Afaan Bilal/nanocore](https://github.com/afaanbilal/nanocore)
- Tags: internals
- Published: 2026-02-23

---

**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`](https://github.com/afaanbilal/nanocore/blob/main/src/lib.rs), operand decoding in [`src/nanocore.rs`](https://github.com/afaanbilal/nanocore/blob/main/src/nanocore.rs), and direct memory writing with flag updates.

## Opcode Definition and Instruction Format

The `STR` opcode is defined in [`src/lib.rs`](https://github.com/afaanbilal/nanocore/blob/main/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`](https://github.com/afaanbilal/nanocore/blob/main/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】:

1. **Address retrieval**: Reads the memory address from `cpu.registers[rs]`
2. **Value retrieval**: Fetches the stored value from `cpu.registers[rd]`
3. **Memory write**: Writes the value into `cpu.memory[address]`
4. **Flag update**: Modifies the **Z** (zero) and **N** (negative) flags based on the stored value
5. **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**:

```rust
// 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 `STR` instruction is defined in [`src/lib.rs`](https://github.com/afaanbilal/nanocore/blob/main/src/lib.rs) as a 2-byte opcode using the `RegReg` operand pattern.
- Operand decoding in [`src/nanocore.rs`](https://github.com/afaanbilal/nanocore/blob/main/src/nanocore.rs) extracts two 4-bit register indices to identify the source data and target address.
- Execution writes the source register's value into `cpu.memory` at 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.