## ADDED Requirements ### Requirement: AsmBuilder assembles x86 instruction text to byte array `AsmBuilder.Assemble(string source)` parses x86 assembly text and returns the corresponding `byte[]` machine code. #### Scenario: single instruction - **WHEN** `AsmBuilder.Assemble("nop")` is called - **THEN** the result is `[0x90]` #### Scenario: multiple instructions - **WHEN** `AsmBuilder.Assemble("pushad\npopad")` is called - **THEN** the result is `[0x60, 0x61]` #### Scenario: instruction with immediate operand - **WHEN** `AsmBuilder.Assemble("mov eax, 1")` is called - **THEN** the result is `[0xB8, 0x01, 0x00, 0x00, 0x00]` ### Requirement: AsmBuilder supports register operands Supported registers: `eax`, `ecx`, `edx`, `ebx`, `esp`, `ebp`, `esi`, `edi` (and 8-bit: `al`, `cl`, `dl`, `bl`, `ah`, `ch`, `dh`, `bh`). #### Scenario: register-to-register move - **WHEN** `AsmBuilder.Assemble("mov eax, ecx")` is called - **THEN** the result is `[0x89, 0xC8]` (mov eax, ecx encoding) #### Scenario: register encoding - **WHEN** registers are used in instructions - **THEN** each register maps to its correct 3-bit encoding (eax=0, ecx=1, edx=2, ebx=3, esp=4, ebp=5, esi=6, edi=7) ### Requirement: AsmBuilder supports labels and jumps Labels are defined with `@name:` and referenced with `jmp @name` or `je @name`. Forward and backward references are resolved in a second pass. #### Scenario: forward jump - **WHEN** `AsmBuilder.Assemble("jmp @skip\nnop\n@skip:\nret")` is called - **THEN** the jump skips exactly over the `nop` (2 bytes) and lands on `ret` #### Scenario: backward jump - **WHEN** `AsmBuilder.Assemble("@loop:\nnop\njmp @loop")` is called - **THEN** the jump targets the earlier label correctly #### Scenario: multiple labels - **WHEN** multiple labels are used in one source - **THEN** each label resolves to its correct byte offset ### Requirement: AsmBuilder SetPassLimit controls iteration `AsmBuilder.SetPassLimit(int limit)` sets the maximum number of assembly passes for label resolution. Default is 10. If the limit is exceeded before all labels resolve, `InvalidOperationException` is thrown. #### Scenario: default pass limit - **WHEN** no `SetPassLimit` is called - **THEN** the assembler uses 10 passes maximum #### Scenario: custom pass limit - **WHEN** `SetPassLimit(20)` is called - **THEN** the assembler uses 20 passes maximum #### Scenario: pass limit exceeded - **WHEN** forward references cannot resolve within the pass limit - **THEN** `InvalidOperationException` is thrown with label resolution details ### Requirement: AsmBuilder reports clear errors Unknown instructions, missing operands, and invalid register names produce `ArgumentException` with the line number and offending text. #### Scenario: unknown instruction - **WHEN** `AsmBuilder.Assemble("xyzw")` is called - **THEN** `ArgumentException` is thrown mentioning line 1 and "xyzw" #### Scenario: missing operand - **WHEN** `AsmBuilder.Assemble("mov")` is called (no operands) - **THEN** `ArgumentException` is thrown mentioning missing operand ### Requirement: AsmBuilder supported instruction set The following x86 instructions are supported: - **Data movement**: `mov`, `push`, `pop`, `pushad`, `popad`, `lea` - **Arithmetic**: `add`, `sub`, `inc`, `dec`, `xor`, `and`, `or`, `cmp`, `test` - **Control flow**: `jmp`, `je`, `jne`, `call`, `ret`, `nop`, `hlt` #### Scenario: all instructions produce valid bytes - **WHEN** each supported instruction is assembled individually - **THEN** it produces the correct x86 machine code encoding