diff --git a/chapter/cpu/instruction-set.typ b/chapter/cpu/instruction-set.typ index f02979f..41b49fd 100644 --- a/chapter/cpu/instruction-set.typ +++ b/chapter/cpu/instruction-set.typ @@ -3,22 +3,56 @@ #let ops = toml("../../opcodes.toml") -#let instruction-block(body, ..grid-args) = block(breakable: false)[ +#let instruction-block(body, ..grid-args) = [ #body #grid( - columns: (6em, auto), - gutter: 8pt, + columns: 1, + gutter: 6pt, ..grid-args ) + #pagebreak() ] -#let instruction-timing(mnemonic: str, duration: int, mem_rw: array, mem_addr: array, next_addr: content) = timing.diagram(w_scale: 0.75, ..{ +#let simple-instruction-timing(mnemonic: str, timing_data: dictionary) = timing.diagram(w_scale: 0.9, ..{ import timing: * + let duration = timing_data.duration ( (label: "M-cycle", wave: ( x(1), - ..range(1 + duration).map((cycle) => { - let m_cycle = cycle + 1 + ..range(duration).map((idx) => { + let m_cycle = idx + 1 + d(8, "M" + str(m_cycle)) + }), + x(1), + )), + (label: "Mem R/W", wave: ( + x(1), + timing.d(8, [R: opcode]), + ..timing_data.mem_rw.enumerate().map(((idx, label)) => { + let m_cycle = idx + 2 + if label == "U" { timing.u(8) } else { timing.d(8, label) } + }), + x(1, opacity: 40%), + )), + ) +}) + +#let instruction-timing(mnemonic: str, timing_data: dictionary) = timing.diagram(w_scale: 0.9, ..{ + import timing: * + let duration = timing_data.duration + let map_cycle_labels(data) = data.enumerate().map(((idx, label)) => { + let m_cycle = idx + 2 + if label == "U" { + timing.u(8) + } else { + timing.d(8, label) + } + }) + ( + (label: "M-cycle", wave: ( + x(1), + ..range(1 + duration).map((idx) => { + let m_cycle = idx + 1 if m_cycle == duration + 1 { d(8, "M" + str(m_cycle) + "/M1") } else { @@ -27,36 +61,91 @@ }), x(1), )), - (label: "Instruction", wave: ( - d(9, [Previous], opacity: 40%), - d(duration * 8, mnemonic), + (label: "Addr bus", wave: ( + x(1), + timing.d(8, [Previous], opacity: 40%), + ..map_cycle_labels(timing_data.addr), x(1, opacity: 40%), )), - (label: "Mem R/W", wave: ( + (label: "Data bus", wave: ( x(1), - timing.d(8, [R: opcode]), - ..mem_rw.map((label) => if label == "U" { timing.u(8) } else { timing.d(8, label) }), - timing.d(8, [R: next op], opacity: 40%), + timing.d(8, [IR ← mem], opacity: 40%), + ..map_cycle_labels(timing_data.data), + x(1, opacity: 40%), + )), + (label: "IDU op", wave: ( + x(1), + timing.d(8, [Previous], opacity: 40%), + ..map_cycle_labels(timing_data.idu_op), + x(1, opacity: 40%), + )), + (label: "ALU op", wave: ( + x(1), + timing.d(8, [Previous], opacity: 40%), + ..map_cycle_labels(timing_data.alu_op), x(1, opacity: 40%), )), - (label: "Mem addr", wave: ( + (label: "Misc op", wave: ( x(1), - timing.d(8, [PC#sub[0]]), - ..mem_addr.map((label) => if label == "U" { timing.u(8) } else { timing.d(8, label) }), - timing.d(8, next_addr, opacity: 40%), + timing.d(8, [Previous], opacity: 40%), + ..map_cycle_labels(timing_data.misc_op), x(1, opacity: 40%), )), ) }) -#let instruction = (body, mnemonic: str, length: int, duration: int, opcode: content, flags: [-], mem_rw: array, mem_addr: array, next_addr: [], pseudocode: content) => instruction-block( +#let instruction = (body, mnemonic: str, opcode: content, operand_bytes: array, flags: [-], timing: dictionary, simple-pseudocode: [], pseudocode: content) => instruction-block( body, - [*Opcode*], opcode, - [*Length*], if length > 1 { str(length) + " bytes" } else { "1 byte" }, - [*Duration*], if duration > 1 { str(duration) + " machine cycles" } else { "1 machine cycle" }, - [*Flags*], flags, - [*Timing*], instruction-timing(mnemonic: mnemonic, duration: duration, mem_rw: mem_rw, mem_addr: mem_addr, next_addr: if next_addr == [] { [PC#sub[0]+#length] } else { next_addr }), - [*Pseudocode*], pseudocode, + grid(columns: (auto, 1fr, auto, 1fr), gutter: 6pt, + [*Opcode*], opcode, + [*Duration*], if "cc_false" in timing [ + #let cc_false = if timing.cc_false.duration > 1 { str(timing.cc_false.duration) + " machine cycles" } else { "1 machine cycle" } + #let cc_true = if timing.cc_true.duration > 1 { str(timing.cc_true.duration) + " machine cycles" } else { "1 machine cycle" } + #cc_true (cc=true)\ + #cc_false (cc=false) + ] else [ + #let duration = timing.duration + #if duration > 1 [ #duration machine cycles ] else [ 1 machine cycle ] + ], + [*Length*], { + let length = 1 + operand_bytes.len() + if length > 1 { str(length) + " bytes: opcode + " + operand_bytes.join(" + ") } else { "1 byte: opcode" } + }, + [*Flags*], flags, + ), + if "cc_false" in timing { + [ + #block(breakable: false)[ + *Simple timing and pseudocode* + #grid(columns: (auto, 1fr), gutter: 12pt, + align(horizon, [_cc=true_]), simple-instruction-timing(mnemonic: mnemonic, timing_data: timing.cc_true), + align(horizon, [_cc=false_]), simple-instruction-timing(mnemonic: mnemonic, timing_data: timing.cc_false), + ) + #simple-pseudocode + ] + #block(breakable: false)[ + *Detailed timing and pseudocode* + #grid(columns: (auto, 1fr), gutter: 12pt, + align(horizon, [_cc=true_]), instruction-timing(mnemonic: mnemonic, timing_data: timing.cc_true), + align(horizon, [_cc=false_]), instruction-timing(mnemonic: mnemonic, timing_data: timing.cc_false), + ) + #pseudocode + ] + ] + } else { + [ + #block(breakable: false)[ + *Simple timing and pseudocode* + #simple-instruction-timing(mnemonic: mnemonic, timing_data: timing) + #simple-pseudocode + ] + #block(breakable: false)[ + *Detailed timing and pseudocode* + #instruction-timing(mnemonic: mnemonic, timing_data: timing) + #pseudocode + ] + ] + } ) #let flag-update = awesome[\u{f005}] @@ -68,6 +157,8 @@ ==== CB opcode prefix ==== Undefined opcodes +#pagebreak() + === 8-bit load instructions #instruction( @@ -77,17 +168,27 @@ Load to the 8-bit register `r`, data from the 8-bit register `r'`. ], mnemonic: "LD r, r'", - length: 1, - duration: 1, opcode: [#bin("01xxxyyy")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([`r` ← `r'`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: LD B, C -if opcode == 0x41: +if opcode == 0x41: # example: LD B, C B = C - ``` +```, + pseudocode: ```python +# M2/M1 +if IR == 0x41: # example: LD B, C + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; B = C +``` ) #instruction( @@ -97,17 +198,29 @@ if opcode == 0x41: Load to the 8-bit register `r`, the immediate data `n`. ], mnemonic: "LD r, n", - length: 2, - duration: 2, - opcode: [#bin("00xxx110")/various + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("00xxx110")/various], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [`r` ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: LD B, n -if opcode == 0x06: +if opcode == 0x06: # example: LD B, n B = read_memory(addr=PC); PC = PC + 1 - ``` +```, + pseudocode: ```python +# M2 +if IR == 0x06: # example: LD B, n + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; B = Z +``` ) #instruction( @@ -117,16 +230,28 @@ if opcode == 0x06: Load to the 8-bit register `r`, data from the absolute address specified by the 16-bit register HL. ], mnemonic: "LD r, (HL)", - length: 1, - duration: 2, opcode: [#bin("01xxx110")/various], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [`r` ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: LD B, (HL) -if opcode == 0x46: +if opcode == 0x46: # example: LD B, (HL) B = read_memory(addr=HL) + ```, + pseudocode: ```python +# M2 +if IR == 0x46: # example: LD B, (HL) + Z = read_memory(addr=HL) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; B = Z ``` ) @@ -137,16 +262,28 @@ if opcode == 0x46: Load to the absolute address specified by the 16-bit register HL, data from the 8-bit register `r`. ], mnemonic: "LD (HL), r", - length: 1, - duration: 2, opcode: [#bin("01110xxx")/various], - mem_rw: ([W: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([W: data],), + addr: ([HL], [PC],), + data: ([mem ← `r`], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: LD (HL), B -if opcode == 0x70: +if opcode == 0x70: # example: LD (HL), B + write_memory(addr=HL, data=B) + ```, + pseudocode: ```python +# M2 +if IR == 0x70: # example: LD (HL), B write_memory(addr=HL, data=B) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -157,16 +294,31 @@ if opcode == 0x70: Load to the absolute address specified by the 16-bit register HL, the immediate data `n`. ], mnemonic: "LD (HL), n", - length: 2, - duration: 3, - opcode: [#bin("00110110")/#hex("36") + `n`], - mem_rw: ([R: `n`], [W: `n`],), - mem_addr: ([PC#sub[0]+1], [HL],), - pseudocode: ```python + opcode: [#bin("00110110")/#hex("36")], + operand_bytes: ([`n`],), + timing: ( + duration: 3, + mem_rw: ([R: `n`], [W: `n`],), + addr: ([PC], [HL], [PC],), + data: ([Z ← mem], [mem ← Z], [IR ← mem],), + idu_op: ([PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U",), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x36: n = read_memory(addr=PC); PC = PC + 1 write_memory(addr=HL, data=n) + ```, + pseudocode: ```python +# M2 +if IR == 0x36: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + write_memory(addr=HL, data=Z) + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -177,15 +329,28 @@ if opcode == 0x36: Load to the 8-bit A register, data from the absolute address specified by the 16-bit register BC. ], mnemonic: "LD A, (BC)", - length: 1, - duration: 2, opcode: [#bin("00001010")/#hex("0A")], - mem_rw: ([R: data],), - mem_addr: ([BC],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([BC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x0A: A = read_memory(addr=BC) + ```, + pseudocode: ```python +# M2 +if IR == 0x0A: + Z = read_memory(addr=BC) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -196,15 +361,28 @@ if opcode == 0x0A: Load to the 8-bit A register, data from the absolute address specified by the 16-bit register DE. ], mnemonic: "LD A, (DE)", - length: 1, - duration: 2, opcode: [#bin("00011010")/#hex("1A")], - mem_rw: ([R: data],), - mem_addr: ([DE],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([DE], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x1A: A = read_memory(addr=DE) + ```, + pseudocode: ```python +# M2 +if IR == 0x1A: + Z = read_memory(addr=DE) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -215,15 +393,28 @@ if opcode == 0x1A: Load to the absolute address specified by the 16-bit register BC, data from the 8-bit A register. ], mnemonic: "LD (BC), A", - length: 1, - duration: 2, opcode: [#bin("00000010")/#hex("02")], - mem_rw: ([W: data],), - mem_addr: ([BC],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([W: data],), + addr: ([BC], [PC],), + data: ([mem ← A], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x02: write_memory(addr=BC, data=A) + ```, + pseudocode: ```python +# M2 +if IR == 0x02: + write_memory(addr=BC, data=A) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -234,15 +425,28 @@ if opcode == 0x02: Load to the absolute address specified by the 16-bit register DE, data from the 8-bit A register. ], mnemonic: "LD (DE), A", - length: 1, - duration: 2, opcode: [#bin("00010010")/#hex("12")], - mem_rw: ([W: data],), - mem_addr: ([DE],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([W: data],), + addr: ([DE], [PC],), + data: ([mem ← A], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x12: write_memory(addr=DE, data=A) + ```, + pseudocode: ```python +# M2 +if IR == 0x12: + write_memory(addr=DE, data=A) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -253,18 +457,35 @@ if opcode == 0x12: Load to the 8-bit A register, data from the absolute address specified by the 16-bit operand `nn`. ], mnemonic: "LD A, (nn)", - length: 3, - duration: 4, - opcode: [#bin("11111010")/#hex("FA") + LSB of `n` + MSB of `n`], - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], [R: data],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], [`nn`]), - pseudocode: ```python + opcode: [#bin("11111010")/#hex("FA")], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + duration: 4, + mem_rw: ([R: lsb `nn`], [R: msb `nn`], [R: data],), + addr: ([PC], [PC], [WZ], [PC],), + data: ([Z ← mem], [W ← mem], [Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", [A ← Z],), + misc_op: ("U", "U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xFA: nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) A = read_memory(addr=nn) + ```, + pseudocode: ```python +# M2 +if IR == 0xFA: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + # M4 + Z = read_memory(addr=WZ) + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -275,18 +496,35 @@ if opcode == 0xFA: Load to the absolute address specified by the 16-bit operand `nn`, data from the 8-bit A register. ], mnemonic: "LD (nn), A", - length: 3, - duration: 4, - opcode: [#bin("11101010")/#hex("EA") + LSB of `n` + MSB of `n`], - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], [W: data],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], [`nn`]), - pseudocode: ```python + opcode: [#bin("11101010")/#hex("EA")], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + duration: 4, + mem_rw: ([R: lsb `nn`], [R: msb `nn`], [W: data],), + addr: ([PC], [PC], [WZ], [PC],), + data: ([Z ← mem], [W ← mem], [mem ← A], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", "U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xEA: nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) write_memory(addr=nn, data=A) + ```, + pseudocode: ```python +# M2 +if IR == 0xEA: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + # M4 + write_memory(addr=WZ, data=A) + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -297,15 +535,28 @@ if opcode == 0xEA: Load to the 8-bit A register, data from the address specified by the 8-bit C register. The full 16-bit absolute address is obtained by setting the most significant byte to #hex("FF") and the least significant byte to the value of C, so the possible range is #hex-range("FF00", "FFFF"). ], mnemonic: "LDH A, (C)", - length: 1, - duration: 2, opcode: [#bin("11110010")/#hex("F2")], - mem_rw: ([R: A],), - mem_addr: ([#hex("FF00")+C],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([#hex("FF00")+C], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xF2: A = read_memory(addr=unsigned_16(lsb=C, msb=0xFF)) + ```, + pseudocode: ```python +# M2 +if IR == 0xF2: + Z = read_memory(addr=unsigned_16(lsb=C, msb=0xFF)) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -316,15 +567,28 @@ if opcode == 0xF2: Load to the address specified by the 8-bit C register, data from the 8-bit A register. The full 16-bit absolute address is obtained by setting the most significant byte to #hex("FF") and the least significant byte to the value of C, so the possible range is #hex-range("FF00", "FFFF"). ], mnemonic: "LDH (C), A", - length: 1, - duration: 2, opcode: [#bin("11100010")/#hex("E2")], - mem_rw: ([W: A],), - mem_addr: ([#hex("FF00")+C],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([W: data],), + addr: ([#hex("FF00")+C], [PC],), + data: ([mem ← A], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xE2: - write_memory(addr=unsigned_16(lsb=C, data=msb=0xFF), A) + write_memory(addr=unsigned_16(lsb=C, data=msb=0xFF), data=A) + ```, + pseudocode: ```python +# M2 +if IR == 0xE2: + write_memory(addr=unsigned_16(lsb=C, data=msb=0xFF), data=A) + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -335,16 +599,31 @@ if opcode == 0xE2: Load to the 8-bit A register, data from the address specified by the 8-bit immediate data `n`. The full 16-bit absolute address is obtained by setting the most significant byte to #hex("FF") and the least significant byte to the value of `n`, so the possible range is #hex-range("FF00", "FFFF"). ], mnemonic: "LDH A, (n)", - length: 2, - duration: 3, opcode: [#bin("11110000")/#hex("F0")], - mem_rw: ([R: `n`], [R: A],), - mem_addr: ([PC#sub[0]+1], [#hex("FF00")+`n`],), - pseudocode: ```python + operand_bytes: ([`n`],), + timing: ( + duration: 3, + mem_rw: ([R: `n`], [R: data],), + addr: ([PC], [#hex("FF00")+Z], [PC],), + data: ([Z ← mem], [Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", [A ← Z],), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xF0: n = read_memory(addr=PC); PC = PC + 1 A = read_memory(addr=unsigned_16(lsb=n, msb=0xFF)) + ```, + pseudocode: ```python +# M2 +if IR == 0xF0: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + Z = read_memory(addr=unsigned_16(lsb=Z, msb=0xFF)) + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -355,16 +634,31 @@ if opcode == 0xF0: Load to the address specified by the 8-bit immediate data `n`, data from the 8-bit A register. The full 16-bit absolute address is obtained by setting the most significant byte to #hex("FF") and the least significant byte to the value of `n`, so the possible range is #hex-range("FF00", "FFFF"). ], mnemonic: "LDH (n), A", - length: 2, - duration: 3, opcode: [#bin("11100000")/#hex("E0")], - mem_rw: ([R: `n`], [W: A],), - mem_addr: ([PC#sub[0]+1], [#hex("FF00")+C],), - pseudocode: ```python + operand_bytes: ([`n`],), + timing: ( + duration: 3, + mem_rw: ([R: `n`], [W: data],), + addr: ([PC], [#hex("FF00")+Z], [PC],), + data: ([Z ← mem], [mem ← A], [IR ← mem],), + idu_op: ([PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U",), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xE0: n = read_memory(addr=PC); PC = PC + 1 - write_memory(addr=unsigned_16(lsb=n, data=msb=0xFF), A) + write_memory(addr=unsigned_16(lsb=n, msb=0xFF), data=A) + ```, + pseudocode: ```python +# M2 +if IR == 0xE0: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + write_memory(addr=unsigned_16(lsb=Z, msb=0xFF), data=A) + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -375,15 +669,28 @@ if opcode == 0xE0: Load to the 8-bit A register, data from the absolute address specified by the 16-bit register HL. The value of HL is decremented after the memory read. ], mnemonic: "LD A, (HL-)", - length: 1, - duration: 2, opcode: [#bin("00111010")/#hex("3A")], - mem_rw: ([R: A],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([HL ← HL - 1], [PC ← PC + 1],), + alu_op: ("U", [A ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x3A: A = read_memory(addr=HL); HL = HL - 1 + ```, + pseudocode: ```python +# M2 +if IR == 0x3A: + Z = read_memory(addr=HL); HL = HL - 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -394,15 +701,28 @@ if opcode == 0x3A: Load to the absolute address specified by the 16-bit register HL, data from the 8-bit A register. The value of HL is decremented after the memory write. ], mnemonic: "LD (HL-), A", - length: 1, - duration: 2, opcode: [#bin("00110010")/#hex("32")], - mem_rw: ([W: A],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([W: data],), + addr: ([HL], [PC],), + data: ([mem ← A], [IR ← mem],), + idu_op: ([HL ← HL - 1], [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x32: write_memory(addr=HL, data=A); HL = HL - 1 + ```, + pseudocode: ```python +# M2 +if IR == 0x32: + write_memory(addr=HL, data=A); HL = HL - 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -413,15 +733,28 @@ if opcode == 0x32: Load to the 8-bit A register, data from the absolute address specified by the 16-bit register HL. The value of HL is incremented after the memory read. ], mnemonic: "LD A, (HL+)", - length: 1, - duration: 2, opcode: [#bin("00101010")/#hex("2A")], - mem_rw: ([R: A],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([HL ← HL + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x2A: A = read_memory(addr=HL); HL = HL + 1 + ```, + pseudocode: ```python +# M2 +if IR == 0x2A: + Z = read_memory(addr=HL); HL = HL + 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z ``` ) @@ -432,15 +765,28 @@ if opcode == 0x2A: Load to the absolute address specified by the 16-bit register HL, data from the 8-bit A register. The value of HL is decremented after the memory write. ], mnemonic: "LD (HL+), A", - length: 1, - duration: 2, opcode: [#bin("00100010")/#hex("22")], - mem_rw: ([W: A],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([W: data],), + addr: ([HL], [PC],), + data: ([mem ← A], [IR ← mem],), + idu_op: ([HL ← HL + 1], [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode == 0x32: +if opcode == 0x22: + write_memory(addr=HL, data=A); HL = HL + 1 + ```, + pseudocode: ```python +# M2 +if IR == 0x22: write_memory(addr=HL, data=A); HL = HL + 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -453,19 +799,33 @@ if opcode == 0x32: Load to the 16-bit register `rr`, the immediate 16-bit data `nn`. ], mnemonic: "LD rr, nn", - length: 3, - duration: 3, - opcode: [#bin("00xx0001")/various + LSB of `nn` + MSB of `nn`], - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2],), - pseudocode: ```python + opcode: [#bin("00xx0001")/various], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + duration: 3, + mem_rw: ([R: lsb `nn`], [R: msb `nn`],), + addr: ([PC], [PC], [PC],), + data: ([Z ← mem], [W ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", "U", "U",), + misc_op: ("U", "U", [`rr` ← WZ],), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: LD BC, nn -if opcode == 0x01: +if opcode == 0x01: # example: LD BC, nn nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) BC = nn + ```, + pseudocode: ```python +# M2 +if IR == 0x01: # example: LD BC, nn + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; BC = WZ ``` ) @@ -476,19 +836,38 @@ if opcode == 0x01: Load to the absolute address specified by the 16-bit operand `nn`, data from the 16-bit SP register. ], mnemonic: "LD (nn), SP", - length: 3, - duration: 5, - opcode: [#bin("00001000")/#hex("08") + LSB of `nn` + MSB of `nn`], - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], [W: lsb(SP)], [W: msb(SP)],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], [`nn`], [`nn`+1]), - pseudocode: ```python + opcode: [#bin("00001000")/#hex("08")], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + duration: 5, + mem_rw: ([R: Z], [R: W], [W: SPH], [W: SPL],), + addr: ([PC], [PC], [WZ], [WZ], [PC],), + data: ([Z ← mem], [W ← mem], [mem ← SPL], [mem ← SPH], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], [WZ ← WZ + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U", "U",), + misc_op: ("U", "U", "U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x08: nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) - write_memory(addr=nn, data=lsb(SP)) - write_memory(addr=nn+1, data=msb(SP)) + write_memory(addr=nn, data=lsb(SP)); nn = nn + 1 + write_memory(addr=nn, data=msb(SP)) + ```, + pseudocode: ```python +# M2 +if IR == 0x08: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + # M4 + write_memory(addr=WZ, data=lsb(SP)); WZ = WZ + 1 + # M5 + write_memory(addr=WZ, data=msb(SP)) + # M6/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -499,15 +878,28 @@ if opcode == 0x08: Load to the 16-bit SP register, data from the 16-bit HL register. ], mnemonic: "LD SP, HL", - length: 1, - duration: 2, opcode: [#bin("11111001")/#hex("F9")], - mem_rw: ("U",), - mem_addr: ("U",), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ("U",), + addr: ([HL], [PC],), + data: ("U", [IR ← mem],), + idu_op: ([SP ← HL], [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xF9: SP = HL + ```, + pseudocode: ```python +# M2 +if IR == 0xF9: + SP = HL + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -518,18 +910,34 @@ if opcode == 0xF9: Push to the stack memory, data from the 16-bit register `rr`. ], mnemonic: "PUSH rr", - length: 1, - duration: 4, opcode: [#bin("11xx0101")/various], - mem_rw: ("U", [W: msb(`rr`)], [W: lsb(`rr`)],), - mem_addr: ([SP#sub[0]], [SP#sub[0]-1], [SP#sub[0]-2],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 4, + mem_rw: ("U", [W: msb `rr`], [W: lsb `rr`],), + addr: ([SP], [SP], [SP], [PC],), + data: ("U", [mem ← msb `rr`], [mem ← lsb `rr`], [IR ← mem],), + idu_op: ([SP ← SP - 1], [SP ← SP - 1], [SP ← SP], [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", "U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: PUSH BC -if opcode == 0xC5: +if opcode == 0xC5: # example: PUSH BC SP = SP - 1 write_memory(addr=SP, data=msb(BC)); SP = SP - 1 write_memory(addr=SP, data=lsb(BC)) + ```, + pseudocode: ```python +# M2 +if IR == 0xC5: # example: PUSH BC + SP = SP - 1 + # M3 + write_memory(addr=SP, data=msb(BC)); SP = SP - 1 + # M4 + write_memory(addr=SP, data=lsb(BC)) + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -542,25 +950,85 @@ if opcode == 0xC5: This instruction does not do calculations that affect flags, but POP AF completely replaces the F register value, so all flags are changed based on the 8-bit data that is read from memory. ], mnemonic: "POP rr", - length: 1, - duration: 3, flags: [See the instruction description], opcode: [#bin("11xx0001")/various], - mem_rw: ([R: lsb(`rr`)], [R: msb(`rr`)],), - mem_addr: ([SP#sub[0]], [SP#sub[0]-1], [SP#sub[0]-2],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 3, + mem_rw: ([R: lsb `rr`], [R: msb `rr`],), + addr: ([SP], [SP], [PC],), + data: ([Z ← mem], [W ← mem], [IR ← mem],), + idu_op: ([SP ← SP + 1], [SP ← SP + 1], [PC ← PC + 1],), + alu_op: ("U", "U", "U",), + misc_op: ("U", "U", [`rr` ← WZ],), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: POP BC -if opcode == 0xC1: +if opcode == 0xC1: # example: POP BC lsb = read_memory(addr=SP); SP = SP + 1 msb = read_memory(addr=SP); SP = SP + 1 BC = unsigned_16(lsb=lsb, msb=msb) + ```, + pseudocode: ```python +# M2 +if IR == 0xC1: # example: POP BC + Z = read_memory(addr=SP); SP = SP + 1 + # M3 + W = read_memory(addr=SP); SP = SP + 1 + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; BC = WZ ``` ) -==== LD HL,SP+e +#instruction( + [ + ==== LD HL, SP+e: Load HL from adjusted stack pointer -TODO + Load to the HL register, 16-bit data calculated by adding the signed 8-bit operand `e` to the 16-bit value of the SP register. + ], + mnemonic: "LD HL, SP+e", + flags: [Z = 0, N = 0, H = #flag-update, C = #flag-update], + opcode: [#bin("11111000")/#hex("F8")], + operand_bytes: ([`e`],), + timing: ( + duration: 3, + mem_rw: ([R: `e`], "U",), + addr: ([PC], [#hex("0000")], [PC],), + data: ([Z ← mem], "U", [IR ← mem],), + idu_op: ([PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", [L ← SPL + Z], [H ← SPH +#sub[c] adj],), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python +opcode = read_memory(addr=PC); PC = PC + 1 +if opcode == 0xF8: + e = signed_8(read_memory(addr=PC)); PC = PC + 1 + result, carry_per_bit = SP + e + HL = result + flags.Z = 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xF8: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + result, carry_per_bit = lsb(SP) + Z + L = result + flags.Z = 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + Z_sign = bit(7, Z) + # M4/M1 + adj = 0xFF if Z_sign else 0x00 + result = msb(SP) + adj + flags.C + H = result + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` +) === 8-bit arithmetic and logical instructions @@ -571,22 +1039,38 @@ TODO Adds to the 8-bit A register, the 8-bit register `r`, and stores the result back into the A register. ], mnemonic: "ADD r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 0, H = #flag-update, C = #flag-update], opcode: [#bin("10000xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A + `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: ADD B -if opcode == 0x80: +if opcode == 0x80: # example: ADD B + result, carry_per_bit = A + B + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x80: # example: ADD B result, carry_per_bit = A + B A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -597,13 +1081,19 @@ if opcode == 0x80: Adds to the 8-bit A register, data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "ADD (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = #flag-update, C = #flag-update], opcode: [#bin("10000110")/#hex("86")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A + Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x86: data = read_memory(addr=HL) @@ -613,6 +1103,19 @@ if opcode == 0x86: flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x86: + Z = read_memory(addr=HL) + # M3/M1 + result, carry_per_bit = A + Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -623,13 +1126,19 @@ if opcode == 0x86: Adds to the 8-bit A register, the immediate data `n`, and stores the result back into the A register. ], mnemonic: "ADD n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = #flag-update, C = #flag-update], opcode: [#bin("11000110")/#hex("C6")], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A + Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xC6: n = read_memory(addr=PC); PC = PC + 1 @@ -639,6 +1148,19 @@ if opcode == 0xC6: flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xC6: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result, carry_per_bit = A + Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -650,22 +1172,38 @@ if opcode == 0xC6: ], mnemonic: "ADC r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 0, H = #flag-update, C = #flag-update], opcode: [#bin("10001xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A +#sub[c] `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: ADC B -if opcode == 0x88: - result, carry_per_bit = A + flags.C + B +if opcode == 0x88: # example: ADC B + result, carry_per_bit = A + B + flags.C + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x88: # example: ADC B + result, carry_per_bit = A + B + flags.C A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -676,22 +1214,41 @@ if opcode == 0x88: Adds to the 8-bit A register, the carry flag and data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "ADC (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = #flag-update, C = #flag-update], opcode: [#bin("10001110")/#hex("8E")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A +#sub[c] Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x8E: data = read_memory(addr=HL) - result, carry_per_bit = A + flags.C + data + result, carry_per_bit = A + data + flags.C + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x8E: + Z = read_memory(addr=HL) + # M3/M1 + result, carry_per_bit = A + Z + flags.C A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -702,22 +1259,41 @@ if opcode == 0x8E: Adds to the 8-bit A register, the carry flag and the immediate data `n`, and stores the result back into the A register. ], mnemonic: "ADC n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = #flag-update, C = #flag-update], - opcode: [#bin("11001110")/#hex("CE") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("11001110")/#hex("CE")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A +#sub[c] Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xCE: n = read_memory(addr=PC); PC = PC + 1 - result, carry_per_bit = A + flags.C + n + result, carry_per_bit = A + n + flags.C + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xCE: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result, carry_per_bit = A + Z + flags.C A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -728,22 +1304,38 @@ if opcode == 0xCE: Subtracts from the 8-bit A register, the 8-bit register `r`, and stores the result back into the A register. ], mnemonic: "SUB r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], opcode: [#bin("10010xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A - `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: SUB B -if opcode == 0x90: +if opcode == 0x90: # example: SUB B + result, carry_per_bit = A - B + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x90: # example: SUB B result, carry_per_bit = A - B A = result flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -754,13 +1346,19 @@ if opcode == 0x90: Subtracts from the 8-bit A register, data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "SUB (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], opcode: [#bin("10010110")/#hex("96")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A - Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x96: data = read_memory(addr=HL) @@ -770,6 +1368,19 @@ if opcode == 0x96: flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x96: + Z = read_memory(addr=HL) + # M3/M1 + result, carry_per_bit = A - Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -780,13 +1391,19 @@ if opcode == 0x96: Subtracts from the 8-bit A register, the immediate data `n`, and stores the result back into the A register. ], mnemonic: "SUB n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], - opcode: [#bin("11010110")/#hex("D6") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("11010110")/#hex("D6")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A - Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xD6: n = read_memory(addr=PC); PC = PC + 1 @@ -796,6 +1413,19 @@ if opcode == 0xD6: flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xD6: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result, carry_per_bit = A - Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -806,22 +1436,38 @@ if opcode == 0xD6: Subtracts from the 8-bit A register, the carry flag and the 8-bit register `r`, and stores the result back into the A register. ], mnemonic: "SBC r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], opcode: [#bin("10011xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A -#sub[c] `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: SBC B -if opcode == 0x98: - result, carry_per_bit = A - flags.C - B +if opcode == 0x98: # example: SBC B + result, carry_per_bit = A - B - flags.C + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x98: # example: SBC B + result, carry_per_bit = A - B - flags.C A = result flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -832,22 +1478,41 @@ if opcode == 0x98: Subtracts from the 8-bit A register, the carry flag and data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "SBC (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], opcode: [#bin("10011110")/#hex("9E")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A -#sub[c] Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x9E: data = read_memory(addr=HL) - result, carry_per_bit = A - flags.C - data + result, carry_per_bit = A - data - flags.C + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x9E: + Z = read_memory(addr=HL) + # M3/M1 + result, carry_per_bit = A - Z - flags.C A = result flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -858,22 +1523,41 @@ if opcode == 0x9E: Subtracts from the 8-bit A register, the carry flag and the immediate data `n`, and stores the result back into the A register. ], mnemonic: "SBC n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], - opcode: [#bin("11011110")/#hex("DE") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([HL],), - pseudocode: ```python + opcode: [#bin("11011110")/#hex("DE")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A -#sub[c] Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xDE: n = read_memory(addr=PC); PC = PC + 1 - result, carry_per_bit = A - flags.C - n + result, carry_per_bit = A - n - flags.C A = result flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xDE: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result, carry_per_bit = A - Z - flags.C + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -884,21 +1568,36 @@ if opcode == 0xDE: Subtracts from the 8-bit A register, the 8-bit register `r`, and updates flags based on the result. This instruction is basically identical to #link()[SUB r], but does not update the A register. ], mnemonic: "CP r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], opcode: [#bin("10111xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A - `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: CP B -if opcode == 0xB8: +if opcode == 0xB8: # example: CP B result, carry_per_bit = A - B flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0xB8: # example: CP B + result, carry_per_bit = A - B + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -909,13 +1608,19 @@ if opcode == 0xB8: Subtracts from the 8-bit A register, data from the absolute address specified by the 16-bit register HL, and updates flags based on the result. This instruction is basically identical to #link()[SUB (HL)], but does not update the A register. ], mnemonic: "CP (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], opcode: [#bin("10011110")/#hex("9E")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A - Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xBE: data = read_memory(addr=HL) @@ -924,6 +1629,18 @@ if opcode == 0xBE: flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xBE: + Z = read_memory(addr=HL) + # M3/M1 + result, carry_per_bit = A - Z + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -934,13 +1651,19 @@ if opcode == 0xBE: Subtracts from the 8-bit A register, the immediate data `n`, and updates flags based on the result. This instruction is basically identical to #link()[SUB n], but does not update the A register. ], mnemonic: "CP n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 1, H = #flag-update, C = #flag-update], - opcode: [#bin("11111110")/#hex("FE") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("11111110")/#hex("FE")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A - Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xFE: n = read_memory(addr=PC); PC = PC + 1 @@ -949,6 +1672,17 @@ if opcode == 0xFE: flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xFE: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result, carry_per_bit = A - Z + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 ``` ) @@ -959,21 +1693,36 @@ if opcode == 0xFE: Increments data in the 8-bit register `r`. ], mnemonic: "INC r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 0, H = #flag-update], opcode: [#bin("00xxx100")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([`r` ← `r` + 1],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: INC B -if opcode == 0x04: +if opcode == 0x04: # example: INC B + result, carry_per_bit = B + 1 + B = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + ```, + pseudocode: ```python +if opcode == 0x04: # example: INC B + # M2/M1 result, carry_per_bit = B + 1 B = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -984,13 +1733,19 @@ if opcode == 0x04: Increments data at the absolute address specified by the 16-bit register HL. ], mnemonic: "INC (HL)", - length: 1, - duration: 3, flags: [Z = #flag-update, N = 0, H = #flag-update], opcode: [#bin("00110100")/#hex("34")], - mem_rw: ([R: data], [W: data],), - mem_addr: ([HL], [HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 3, + mem_rw: ([R: data], [W: data],), + addr: ([HL], [HL], [PC],), + data: ([Z ← mem], [mem ← ALU], [IR ← mem],), + idu_op: ("U", "U", [PC ← PC + 1],), + alu_op: ("U", [mem ← Z + 1], "U",), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x34: data = read_memory(addr=HL) @@ -999,6 +1754,19 @@ if opcode == 0x34: flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 if carry_per_bit[3] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x34: + Z = read_memory(addr=HL) + # M3 + result, carry_per_bit = Z + 1 + write_memory(addr=HL, data=result) + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1009,13 +1777,19 @@ if opcode == 0x34: Increments data in the 8-bit register `r`. ], mnemonic: "DEC r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 1, H = #flag-update], opcode: [#bin("00xxx101")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([`r` ← `r` - 1],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 # example: DEC B if opcode == 0x05: @@ -1024,6 +1798,16 @@ if opcode == 0x05: flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x05: # example: DEC B + result, carry_per_bit = B - 1 + B = result + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1034,13 +1818,19 @@ if opcode == 0x05: Decrements data at the absolute address specified by the 16-bit register HL. ], mnemonic: "DEC (HL)", - length: 1, - duration: 3, flags: [Z = #flag-update, N = 1, H = #flag-update], opcode: [#bin("00110101")/#hex("35")], - mem_rw: ([R: data], [W: data],), - mem_addr: ([HL], [HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 3, + mem_rw: ([R: data], [W: data],), + addr: ([HL], [HL], [PC],), + data: ([Z ← mem], [mem ← ALU], [IR ← mem],), + idu_op: ("U", "U", [PC ← PC + 1],), + alu_op: ("U", [mem ← Z - 1], "U",), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x35: data = read_memory(addr=HL) @@ -1049,6 +1839,19 @@ if opcode == 0x35: flags.Z = 1 if result == 0 else 0 flags.N = 1 flags.H = 1 if carry_per_bit[3] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x35: + Z = read_memory(addr=HL) + # M3 + result, carry_per_bit = Z - 1 + write_memory(addr=HL, data=result) + flags.Z = 1 if result == 0 else 0 + flags.N = 1 + flags.H = 1 if carry_per_bit[3] else 0 + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1059,22 +1862,38 @@ if opcode == 0x35: Performs a bitwise AND operation between the 8-bit A register and the 8-bit register `r`, and stores the result back into the A register. ], mnemonic: "AND r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 0, H = 1, C = 0], opcode: [#bin("10100xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A and `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: AND B -if opcode == 0xA0: +if opcode == 0xA0: # example: AND B + result = A & B + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 + flags.C = 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0xA0: # example: AND B result = A & B A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 1 flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1085,13 +1904,19 @@ if opcode == 0xA0: Performs a bitwise AND operation between the 8-bit A register and data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "AND (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = 1, C = 0], opcode: [#bin("10100110")/#hex("A6")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A and Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xA6: data = read_memory(addr=HL) @@ -1101,6 +1926,19 @@ if opcode == 0xA6: flags.N = 0 flags.H = 1 flags.C = 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xA6: + Z = read_memory(addr=HL) + # M3/M1 + result = A & Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1111,13 +1949,19 @@ if opcode == 0xA6: Performs a bitwise AND operation between the 8-bit A register and immediate data `n`, and stores the result back into the A register. ], mnemonic: "AND n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = 1, C = 0], - opcode: [#bin("11100110")/#hex("E6") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("11100110")/#hex("E6")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A and Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xE6: n = read_memory(addr=PC); PC = PC + 1 @@ -1127,6 +1971,19 @@ if opcode == 0xE6: flags.N = 0 flags.H = 1 flags.C = 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xE6: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result = A & Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 1 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1137,22 +1994,38 @@ if opcode == 0xE6: Performs a bitwise OR operation between the 8-bit A register and the 8-bit register `r`, and stores the result back into the A register. ], mnemonic: "OR r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 0, H = 0, C = 0], opcode: [#bin("10110xxx")/various], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A or `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: OR B -if opcode == 0xB0: +if opcode == 0xB0: # example: OR B result = A | B A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 0 flags.C = 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0xB0: # example: OR B + result = A | B + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 0 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1163,13 +2036,19 @@ if opcode == 0xB0: Performs a bitwise OR operation between the 8-bit A register and data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "OR (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = 0, C = 0], opcode: [#bin("10110110")/#hex("B6")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A or Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xB6: data = read_memory(addr=HL) @@ -1179,6 +2058,19 @@ if opcode == 0xB6: flags.N = 0 flags.H = 0 flags.C = 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xB6: + Z = read_memory(addr=HL) + # M3/M1 + result = A | Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 0 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1189,13 +2081,19 @@ if opcode == 0xB6: Performs a bitwise OR operation between the 8-bit A register and immediate data `n`, and stores the result back into the A register. ], mnemonic: "OR n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = 0, C = 0], - opcode: [#bin("11110110")/#hex("F6") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("11110110")/#hex("F6")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A or Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xF6: n = read_memory(addr=PC); PC = PC + 1 @@ -1205,6 +2103,19 @@ if opcode == 0xF6: flags.N = 0 flags.H = 0 flags.C = 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xF6: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result = A | Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 0 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1215,22 +2126,39 @@ if opcode == 0xF6: Performs a bitwise XOR operation between the 8-bit A register and the 8-bit register `r`, and stores the result back into the A register. ], mnemonic: "XOR r", - length: 1, - duration: 1, flags: [Z = #flag-update, N = 0, H = 0, C = 0], opcode: [#bin("10101xxx")/various], - mem_rw: (), - mem_addr: (), + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A xor `r`],), + misc_op: ("U",), + ), + simple-pseudocode: ```python +opcode = read_memory(addr=PC); PC = PC + 1 +if opcode == 0xA8: # example: XOR B + result = A ^ B + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 0 + flags.C = 0 + ```, pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -# example: XOR B -if opcode == 0xB8: +if opcode == 0xA8: # example: XOR B + # M2/M1 result = A ^ B A = result flags.Z = 1 if result == 0 else 0 flags.N = 0 flags.H = 0 flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1241,15 +2169,21 @@ if opcode == 0xB8: Performs a bitwise XOR operation between the 8-bit A register and data from the absolute address specified by the 16-bit register HL, and stores the result back into the A register. ], mnemonic: "XOR (HL)", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = 0, C = 0], opcode: [#bin("10101110")/#hex("AE")], - mem_rw: ([R: data],), - mem_addr: ([HL],), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ([R: data],), + addr: ([HL], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", [A ← A xor Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode == 0xBE: +if opcode == 0xAE: data = read_memory(addr=HL) result = A ^ data A = result @@ -1257,6 +2191,19 @@ if opcode == 0xBE: flags.N = 0 flags.H = 0 flags.C = 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xAE: + Z = read_memory(addr=HL) + # M3/M1 + result = A ^ Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 0 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1267,13 +2214,19 @@ if opcode == 0xBE: Performs a bitwise XOR operation between the 8-bit A register and immediate data `n`, and stores the result back into the A register. ], mnemonic: "XOR n", - length: 1, - duration: 2, flags: [Z = #flag-update, N = 0, H = 0, C = 0], - opcode: [#bin("11101110")/#hex("EE") + `n`], - mem_rw: ([R: `n`],), - mem_addr: ([PC#sub[0]+1],), - pseudocode: ```python + opcode: [#bin("11101110")/#hex("EE")], + operand_bytes: ([`n`],), + timing: ( + duration: 2, + mem_rw: ([R: `n`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", [A ← A xor Z],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xEE: n = read_memory(addr=PC); PC = PC + 1 @@ -1283,6 +2236,19 @@ if opcode == 0xEE: flags.N = 0 flags.H = 0 flags.C = 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xEE: + Z = read_memory(addr=PC); PC = PC + 1 + # M3/M1 + result = A ^ Z + A = result + flags.Z = 1 if result == 0 else 0 + flags.N = 0 + flags.H = 0 + flags.C = 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1293,18 +2259,32 @@ if opcode == 0xEE: Flips the carry flag, and clears the N and H flags. ], mnemonic: "CCF", - length: 1, - duration: 1, flags: [N = 0, H = 0, C = #flag-update], opcode: [#bin("00111111")/#hex("3F")], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([cf ← not cf],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x3F: flags.N = 0 flags.H = 0 flags.C = ~flags.C + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x3F: + flags.N = 0 + flags.H = 0 + flags.C = ~flags.C + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1315,18 +2295,32 @@ if opcode == 0x3F: Sets the carry flag, and clears the N and H flags. ], mnemonic: "SCF", - length: 1, - duration: 1, flags: [N = 0, H = 0, C = 1], opcode: [#bin("00110111")/#hex("37")], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([cf ← 1],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x37: flags.N = 0 flags.H = 0 flags.C = 1 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x37: + flags.N = 0 + flags.H = 0 + flags.C = 1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1337,12 +2331,18 @@ if opcode == 0x37: TODO ], mnemonic: "DAA", - length: 1, - duration: 1, flags: [Z = #flag-update, H = 0, C = #flag-update], opcode: [#bin("00100111")/#hex("27")], - mem_rw: (), - mem_addr: (), + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← A + adj],), + misc_op: ("U",), + ), pseudocode: ```python TODO ``` @@ -1355,38 +2355,197 @@ TODO Flips all the bits in the 8-bit A register, and sets the N and H flags. ], mnemonic: "CPL", - length: 1, - duration: 1, flags: [N = 1, H = 1], opcode: [#bin("00101111")/#hex("2F")], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ([A ← not A],), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x2F: A = ~A flags.N = 1 flags.H = 1 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x2F: + A = ~A + flags.N = 1 + flags.H = 1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) === 16-bit arithmetic instructions -==== INC rr +#instruction( + [ + ==== INC rr: Increment 16-bit register -TODO + Increments data in the 16-bit register `rr`. + ], + mnemonic: "INC rr", + opcode: [#bin("00xx0011")/various], + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ("U",), + addr: ([`rr`], [PC],), + data: ("U", [IR ← mem],), + idu_op: ([`rr` ← `rr` + 1], [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python +opcode = read_memory(addr=PC); PC = PC + 1 +if opcode == 0x03: # example: INC BC + BC = BC + 1 + ```, + pseudocode: ```python +# M2 +if IR == 0x03: # example: INC BC + BC = BC + 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` +) -==== DEC rr +#instruction( + [ + ==== DEC rr: Decrement 16-bit register -TODO + Decrements data in the 16-bit register `rr`. + ], + mnemonic: "DEC rr", + opcode: [#bin("00xx1011")/various], + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ("U",), + addr: ([`rr`], [PC],), + data: ("U", [IR ← mem],), + idu_op: ([`rr` ← `rr` - 1], [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python +opcode = read_memory(addr=PC); PC = PC + 1 +if opcode == 0x0B: # example: DEC BC + BC = BC - 1 + ```, + pseudocode: ```python +# M2 +if IR == 0x0B: # example: DEC BC + BC = BC - 1 + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` +) -==== ADD HL,rr +#instruction( + [ + ==== ADD HL, rr: Add (16-bit register) -TODO + Adds to the 16-bit HL register pair, the 16-bit register `rr`, and stores the result back into the HL register pair. + ], + mnemonic: "ADD HL, rr", + flags: [N = 0, H = #flag-update, C = #flag-update], + opcode: [#bin("00xx1001")/various], + operand_bytes: (), + timing: ( + duration: 2, + mem_rw: ("U",), + addr: ([#hex("0000")], [PC],), + data: ("U", [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ([L ← L + lsb `rr`], [H ← H +#sub[c] msb `rr`],), + misc_op: ("U", "U",), + ), + simple-pseudocode: ```python +opcode = read_memory(addr=PC); PC = PC + 1 +if opcode == 0x09: # example: ADD HL, BC + result, carry_per_bit = HL + BC + HL = result + flags.N = 0 + flags.H = 1 if carry_per_bit[11] else 0 + flags.C = 1 if carry_per_bit[15] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0x09: # example: ADD HL, BC + result, carry_per_bit = L + C + L = result + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + # M3/M1 + result, carry_per_bit = H + B + flags.C + H = result + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` +) -==== ADD SP, e +#instruction( + [ + ==== ADD SP, e: Add to stack pointer (relative) -TODO + Loads to the 16-bit SP register, 16-bit data calculated by adding the signed 8-bit operand `e` to the 16-bit value of the SP register. + ], + mnemonic: "ADD SP, e", + flags: [Z = 0, N = 0, H = #flag-update, C = #flag-update], + opcode: [#bin("11101000")/#hex("E8")], + operand_bytes: ([`e`],), + timing: ( + duration: 4, + mem_rw: ([R: `e`], "U", "U",), + addr: ([PC], [#hex("0000")], [#hex("0000")], [PC],), + data: ([Z ← mem], [ALU], [ALU], [IR ← mem],), + idu_op: ([PC ← PC + 1], "U", "U", [PC ← PC + 1],), + alu_op: ("U", [Z ← SPL + Z], [W ← SPH +#sub[c] adj], "U",), + misc_op: ("U", "U", "U", [SP ← WZ],), + ), + simple-pseudocode: ```python +opcode = read_memory(addr=PC); PC = PC + 1 +if opcode == 0xE8: + e = signed_8(read_memory(addr=PC)); PC = PC + 1 + result, carry_per_bit = SP + e + SP = result + flags.Z = 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + ```, + pseudocode: ```python +# M2 +if IR == 0xE8: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + result, carry_per_bit = lsb(SP) + Z + Z = result + flags.Z = 0 + flags.N = 0 + flags.H = 1 if carry_per_bit[3] else 0 + flags.C = 1 if carry_per_bit[7] else 0 + # M4 + result = msb(SP) + adj + flags.C + W = result + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; SP = WZ + ``` +) + +#pagebreak() === Rotate, shift, and bit operation instructions @@ -1494,6 +2653,8 @@ TODO TODO +#pagebreak() + === Control flow instructions #instruction( @@ -1503,19 +2664,35 @@ TODO Unconditional jump to the absolute address specified by the 16-bit immediate operand `nn`. ], mnemonic: "JP nn", - length: 3, - duration: 4, - opcode: [#bin("11000011")/#hex("C3") + LSB of `nn` + MSB of `nn`], - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U",), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], "U",), - next_addr: [`nn`], - pseudocode: ```python + opcode: [#bin("11000011")/#hex("C3")], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + duration: 4, + mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U",), + addr: ([PC], [PC], [#hex("0000")], [PC],), + data: ([Z ← mem], [W ← mem], "U", [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", "U", [PC ← WZ], "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xC3: nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) PC = nn + ```, + pseudocode: ```python +# M2 +if IR == 0xC3: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + # M4 + PC = WZ + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1526,16 +2703,26 @@ if opcode == 0xC3: Unconditional jump to the absolute address specified by the 16-bit register HL. ], mnemonic: "JP HL", - length: 1, - duration: 1, opcode: [#bin("11101001")/#hex("E9")], - mem_rw: (), - mem_addr: (), - next_addr: [HL], - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([HL],), + data: ([IR ← mem],), + idu_op: ([PC ← HL + 1],), + alu_op: ("U",), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xE9: PC = HL + ```, + pseudocode: ```python +# M2/M1 +if IR == 0xE9: + IR, intr = fetch_cycle(addr=HL); PC = HL + 1 ``` ) @@ -1543,7 +2730,7 @@ if opcode == 0xE9: In some documentation this instruction is written as `JP [HL]`. This is very misleading, since brackets are usually used to indicate a memory read, and this instruction simply copies the value of HL to PC. ] -#instruction-block( +#instruction( [ ==== JP cc, nn: Jump (conditional) @@ -1551,33 +2738,53 @@ if opcode == 0xE9: Note that the operand (absolute address) is read even when the condition is false! ], - [*Opcode*], [#bin("110xx010")/various + LSB of `n` + MSB of `n`], - [*Length*], [3 bytes], - [*Duration*], [3 machine cycles (cc=false), or 4 machine cycles (cc=true)], - [*Flags*], [-], - [*Timing\ _cc=false_*], instruction-timing( - mnemonic: "JP cc, nn", - duration: 3, - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)]), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2],), - next_addr: [PC#sub[0]+3], - ), - [*Timing\ _cc=true_*], instruction-timing( - mnemonic: "JP cc, nn", - duration: 4, - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U",), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], "U",), - next_addr: [`nn`], + mnemonic: "JP cc, nn", + opcode: [#bin("110xx010")/various], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + cc_true: ( + duration: 4, + mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U",), + addr: ([PC], [PC], [#hex("0000")], [PC],), + data: ([Z ← mem], [W ← mem], "U", [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", [cc check], [PC ← WZ], "U",), + ), + cc_false: ( + duration: 3, + mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)],), + addr: ([PC], [PC], [PC],), + data: ([Z ← mem], [W ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", "U", "U",), + misc_op: ("U", [cc check], "U",), + ) ), - [*Pseudocode*], ```python + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode in [0xC2, 0xD2, 0xCA, 0xDA]: +if opcode == 0xC2: # example: JP NZ, nn nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) - if F.check_condition(cc): + if !flags.Z: # cc=true PC = nn ```, + pseudocode: ```python +# M2 +if IR == 0xC2: # example: JP NZ, nn + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + if !flags.Z: # cc=true + # M4 + PC = WZ + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + else: # cc=false + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` ) #instruction( @@ -1587,21 +2794,41 @@ if opcode in [0xC2, 0xD2, 0xCA, 0xDA]: Unconditional jump to the relative address specified by the signed 8-bit operand `e`. ], mnemonic: "JR e", - length: 2, - duration: 3, - opcode: [#bin("00011000")/#hex("18") + offset `e`], - mem_rw: ([R: `e`], "U",), - mem_addr: ([PC#sub[0]+1], "U",), - next_addr: [PC#sub[0]+2+`e`], - pseudocode: ```python + opcode: [#bin("00011000")/#hex("18")], + operand_bytes: ([`e`],), + timing: ( + duration: 3, + mem_rw: ([R: `e`], "U",), + addr: ([PC], [PCH], [WZ],), + data: ([Z ← mem], [ALU], [IR ← mem],), + idu_op: ([PC ← PC + 1], [W ← adj PCH], [PC ← WZ + 1],), + alu_op: ("U", [Z ← PCL + Z], "U",), + misc_op: ("U", "U", "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x18: - e = signed_8(read_memory(addr=PC); PC = PC + 1) + e = signed_8(read_memory(addr=PC)); PC = PC + 1 PC = PC + e + ```, + pseudocode: ```python +# M2 +if IR == 0x18: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + Z_sign = bit(7, Z) + result, carry_per_bit = Z + lsb(PC) + Z = result + adj = 1 if carry_per_bit[7] and not Z_sign else + -1 if not carry_per_bit[7] and Z_sign else + 0 + W = msb(PC) + adj + # M4/M1 + IR, intr = fetch_cycle(addr=WZ); PC = WZ + 1 ``` ) -#instruction-block( +#instruction( [ ==== JR cc, e: Relative jump (conditional) @@ -1609,31 +2836,55 @@ if opcode == 0x18: Note that the operand (relative address offset) is read even when the condition is false! ], - [*Opcode*], [#bin("001xx000")/various + offset `e`], - [*Length*], [2 bytes], - [*Duration*], [2 machine cycles (cc=false), or 3 machine cycles (cc=true)], - [*Flags*], [-], - [*Timing\ _cc=false_*], instruction-timing( - mnemonic: "JR cc, e", - duration: 2, - mem_rw: ([R: `e`],), - mem_addr: ([PC#sub[0]+1],), - next_addr: [PC#sub[0]+2], - ), - [*Timing\ _cc=true_*], instruction-timing( - mnemonic: "JR cc, e", - duration: 3, - mem_rw: ([R: `e`], "U",), - mem_addr: ([PC#sub[0]+1], "U",), - next_addr: [PC#sub[0]+2+`e`], + mnemonic: "JR cc, e", + opcode: [#bin("001xx000")/various], + operand_bytes: ([`e`],), + timing: ( + cc_true: ( + duration: 3, + mem_rw: ([R: `e`], "U",), + addr: ([PC], [PCH], [WZ],), + data: ([Z ← mem], [ALU], [IR ← mem],), + idu_op: ([PC ← PC + 1], [W ← adj PCH], [PC ← WZ + 1],), + alu_op: ("U", [Z ← PCL + Z], "U",), + misc_op: ([cc check], "U", "U",), + ), + cc_false: ( + duration: 2, + mem_rw: ([R: `e`],), + addr: ([PC], [PC],), + data: ([Z ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ([cc check], "U",), + ) ), - [*Pseudocode*], ```python + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode in [0x20, 0x30, 0x28, 0x38]: - e = signed_8(read_memory(addr=PC); PC = PC + 1) - if F.check_condition(cc): +if opcode == 0x20: + e = signed_8(read_memory(addr=PC)); PC = PC + 1 + if !flags.Z: # cc=true PC = PC + e ```, + pseudocode: ```python +# M2 +if IR == 0x20: + Z = read_memory(addr=PC); PC = PC + 1 + if !flags.Z: # cc=true + # M3 + Z_sign = bit(7, Z) + result, carry_per_bit = Z + lsb(PC) + Z = result + adj = 1 if carry_per_bit[7] and not Z_sign else + -1 if not carry_per_bit[7] and Z_sign else + 0 + W = msb(PC) + adj + # M4/M1 + IR, intr = fetch_cycle(addr=WZ); PC = WZ + 1 + else: # cc=false + # M3/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` ) #instruction( @@ -1643,13 +2894,18 @@ if opcode in [0x20, 0x30, 0x28, 0x38]: Unconditional function call to the absolute address specified by the 16-bit operand `nn`. ], mnemonic: "CALL nn", - length: 3, - duration: 6, - opcode: [#bin("11001101")/#hex("CD") + LSB of `nn` + MSB of `nn`], - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U", [W: msb(PC#sub[0]+3)], [W: lsb(PC#sub[0]+3)],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], [SP#sub[0]], [SP#sub[0]-1], [SP#sub[0]-2],), - next_addr: [`nn`], - pseudocode: ```python + opcode: [#bin("11001101")/#hex("CD")], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + duration: 6, + mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U", [W: msb(PC#sub[0]+3)], [W: lsb(PC#sub[0]+3)],), + addr: ([PC], [PC], [SP], [SP], [SP], [PC],), + data: ([Z ← mem], [W ← mem], "U", [mem ← PCH], [mem ← PCL], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], [SP ← SP - 1], [SP ← SP - 1], [SP ← SP], [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U", "U", "U",), + misc_op: ("U", "U", "U", "U", [PC ← WZ], "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xCD: nn_lsb = read_memory(addr=PC); PC = PC + 1 @@ -1659,10 +2915,25 @@ if opcode == 0xCD: write_memory(addr=SP, data=msb(PC)); SP = SP - 1 write_memory(addr=SP, data=lsb(PC)) PC = nn + ```, + pseudocode: ```python +# M2 +if IR == 0xCD: + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + # M4 + SP = SP - 1 + # M5 + write_memory(addr=SP, data=msb(PC)); SP = SP - 1 + # M6 + write_memory(addr=SP, data=lsb(PC)); PC = WZ + # M7/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) -#instruction-block( +#instruction( [ ==== CALL cc, nn: Call function (conditional) @@ -1670,36 +2941,60 @@ if opcode == 0xCD: Note that the operand (absolute address) is read even when the condition is false! ], - [*Opcode*], [#bin("110xx100")/various + LSB of `nn` + MSB of `nn`], - [*Length*], [3 bytes], - [*Duration*], [3 machine cycles (cc=false), or 6 machine cycles (cc=true)], - [*Flags*], [-], - [*Timing\ _cc=false_*], instruction-timing( - mnemonic: "CALL cc, nn", - duration: 3, - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2],), - next_addr: [PC#sub[0]+3], - ), - [*Timing\ _cc=true_*], instruction-timing( - mnemonic: "CALL cc, nn", - duration: 6, - mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U", [W: msb(PC#sub[0]+3)], [W: lsb(PC#sub[0]+3)],), - mem_addr: ([PC#sub[0]+1], [PC#sub[0]+2], [SP#sub[0]], [SP#sub[0]-1], [SP#sub[0]-2],), - next_addr: [`nn`], + mnemonic: "CALL cc, nn", + opcode: [#bin("110xx100")/various], + operand_bytes: ([LSB(`nn`)], [MSB(`nn`)]), + timing: ( + cc_true: ( + duration: 6, + mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)], "U", [W: msb(PC#sub[0]+3)], [W: lsb(PC#sub[0]+3)],), + addr: ([PC], [PC], [SP], [SP], [SP], [PC],), + data: ([Z ← mem], [W ← mem], "U", [mem ← PCH], [mem ← PCL], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], [SP ← SP - 1], [SP ← SP - 1], [SP ← SP], [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U", "U", "U",), + misc_op: ("U", [cc check], "U", "U", [PC ← WZ], "U",), + ), + cc_false: ( + duration: 3, + mem_rw: ([R: lsb(`nn`)], [R: msb(`nn`)]), + addr: ([PC], [PC], [PC],), + data: ([Z ← mem], [W ← mem], [IR ← mem],), + idu_op: ([PC ← PC + 1], [PC ← PC + 1], [PC ← PC + 1],), + alu_op: ("U", "U", "U",), + misc_op: ("U", [cc check], "U",), + ) ), - [*Pseudocode*], ```python + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode in [0xC4, 0xD4, 0xCC, 0xDC]: +if opcode == 0xC4: # example: CALL NZ, nn nn_lsb = read_memory(addr=PC); PC = PC + 1 nn_msb = read_memory(addr=PC); PC = PC + 1 nn = unsigned_16(lsb=nn_lsb, msb=nn_msb) - if F.check_condition(cc): + if !flags.Z: # cc=true SP = SP - 1 write_memory(addr=SP, data=msb(PC)); SP = SP - 1 write_memory(addr=SP, data=lsb(PC)) PC = nn ```, + pseudocode: ```python +# M2 +if IR == 0xC4: # example: CALL NZ, nn + Z = read_memory(addr=PC); PC = PC + 1 + # M3 + W = read_memory(addr=PC); PC = PC + 1 + if !flags.Z: # cc=true + # M4 + SP = SP - 1 + # M5 + write_memory(addr=SP, data=msb(PC)); SP = SP - 1 + # M6 + write_memory(addr=SP, data=lsb(PC)); PC = WZ + # M7/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + else: # cc=false + # M4/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` ) #instruction( @@ -1709,53 +3004,89 @@ if opcode in [0xC4, 0xD4, 0xCC, 0xDC]: Unconditional return from a function. ], mnemonic: "RET", - length: 1, - duration: 4, opcode: [#bin("11001001")/#hex("C9")], - mem_rw: ([R: lsb(PC)], [R: msb(PC)], "U",), - mem_addr: ([SP#sub[0]], [SP#sub[0]+1], "U",), - next_addr: [PC from stack], - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 4, + mem_rw: ([R: lsb(PC)], [R: msb(PC)], "U",), + addr: ([SP], [SP], [#hex("0000")], [PC],), + data: ([Z ← mem], [W ← mem], "U", [IR ← mem],), + idu_op: ([SP ← SP + 1], [SP ← SP + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", "U", [PC ← WZ], "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xC9: lsb = read_memory(addr=SP); SP = SP + 1 msb = read_memory(addr=SP); SP = SP + 1 PC = unsigned_16(lsb=lsb, msb=msb) + ```, + pseudocode: ```python +# M2 +if IR == 0xC9: + Z = read_memory(addr=SP); SP = SP + 1 + # M3 + W = read_memory(addr=SP); SP = SP + 1 + # M4 + PC = WZ + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) -#instruction-block( +#instruction( [ ==== RET cc: Return from function (conditional) Conditional return from a function, depending on the condition `cc`. ], - [*Opcode*], [#bin("110xx000")/various], - [*Length*], [1 byte], - [*Duration*], [2 machine cycles (cc=false), or 5 machine cycles (cc=true)], - [*Flags*], [-], - [*Timing\ _cc=false_*], instruction-timing( - mnemonic: "RET cc", - duration: 2, - mem_rw: ("U",), - mem_addr: ("U",), - next_addr: [PC#sub[0]+1], - ), - [*Timing\ _cc=true_*], instruction-timing( - mnemonic: "RET cc", - duration: 5, - mem_rw: ("U", [R: lsb(PC)], [R: msb(PC)], "U",), - mem_addr: ("U", [SP#sub[0]], [SP#sub[0]+1], "U",), - next_addr: [PC from stack], + mnemonic: "RET cc", + opcode: [#bin("110xx000")/various], + operand_bytes: (), + timing: ( + cc_true: ( + duration: 4, + mem_rw: ([R: lsb(PC)], [R: msb(PC)], "U",), + addr: ([SP], [SP], [#hex("0000")], [PC],), + data: ([Z ← mem], [W ← mem], "U", [IR ← mem],), + idu_op: ([SP ← SP + 1], [SP ← SP + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ([cc check], "U", [PC ← WZ], "U",), + ), + cc_false: ( + duration: 2, + mem_rw: ("U",), + addr: ([#hex("0000")], [PC],), + data: ("U", [IR ← mem],), + idu_op: ("U", [PC ← PC + 1],), + alu_op: ("U", "U",), + misc_op: ([cc check], "U",), + ) ), - [*Pseudocode*], ```python + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode in [0xC0, 0xD0, 0xC8, 0xD8]: - if F.check_condition(cc): +if opcode == 0xC0: # example: RET NZ + if !flags.Z: # cc=true lsb = read_memory(addr=SP); SP = SP + 1 msb = read_memory(addr=SP); SP = SP + 1 PC = unsigned_16(lsb=lsb, msb=msb) ```, + pseudocode: ```python +# M2 +if IR == 0xC0: # example: RET NZ + if !flags.Z: # cc=true + Z = read_memory(addr=SP); SP = SP + 1 + # M3 + W = read_memory(addr=SP); SP = SP + 1 + # M4 + PC = WZ + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + else: # cc=false + # M3 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 + ``` ) #instruction( @@ -1765,19 +3096,35 @@ if opcode in [0xC0, 0xD0, 0xC8, 0xD8]: Unconditional return from a function. Also enables interrupts by setting IME=1. ], mnemonic: "RETI", - length: 1, - duration: 4, opcode: [#bin("11011001")/#hex("D9")], - mem_rw: ([R: lsb(PC)], [R: msb(PC)], "U",), - mem_addr: ([SP#sub[0]], [SP#sub[0]+1], "U",), - next_addr: [PC from stack], - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 4, + mem_rw: ([R: lsb(PC)], [R: msb(PC)], "U",), + addr: ([SP], [SP], [#hex("0000")], [PC],), + data: ([Z ← mem], [W ← mem], "U", [IR ← mem],), + idu_op: ([SP ← SP + 1], [SP ← SP + 1], "U", [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", "U", [PC ← WZ, IME ← 1], "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xD9: lsb = read_memory(addr=SP); SP = SP + 1 msb = read_memory(addr=SP); SP = SP + 1 PC = unsigned_16(lsb=lsb, msb=msb) IME = 1 + ```, + pseudocode: ```python +# M2 +if IR == 0xD9: + Z = read_memory(addr=SP); SP = SP + 1 + # M3 + W = read_memory(addr=SP); SP = SP + 1 + # M4 + PC = WZ; IME = 1 + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1788,21 +3135,36 @@ if opcode == 0xD9: Unconditional function call to the absolute fixed address defined by the opcode. ], mnemonic: "RST n", - length: 1, - duration: 4, opcode: [#bin("11xxx111")/various], - mem_rw: ("U", [W: msb(PC#sub[0]+1)], [W: lsb(PC#sub[0]+1)],), - mem_addr: ([SP#sub[0]], [SP#sub[0]-1], [SP#sub[0]-2],), - next_addr: [`n`], - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 4, + mem_rw: ("U", [W: msb PC], [W: lsb PC],), + addr: ([SP], [SP], [SP], [PC],), + data: ("U", [mem ← PCH], [mem ← PCL], [IR ← mem],), + idu_op: ([SP ← SP - 1], [SP ← SP - 1], [SP ← SP], [PC ← PC + 1],), + alu_op: ("U", "U", "U", "U",), + misc_op: ("U", "U", [PC ← addr], "U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 -if opcode in [0xC7, 0xCF, 0xD7, 0xDF, 0xE7, 0xEF, 0xF7, 0xFF]: - # address 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38 - n = rst_address(opcode) +if opcode == 0xDF: # example: RST 0x18 + n = 0x18 SP = SP - 1 write_memory(addr=SP, data=msb(PC)); SP = SP - 1 write_memory(addr=SP, data=lsb(PC)) PC = unsigned_16(lsb=n, msb=0x00) + ```, + pseudocode: ```python +# M2 +if IR == 0xDF: # example: RST 0x18 + SP = SP - 1 + # M3 + write_memory(addr=SP, data=msb(PC)); SP = SP - 1 + # M4 + write_memory(addr=SP, data=lsb(PC)); PC = 0x0018 + # M5/M1 + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` ) @@ -1823,40 +3185,58 @@ TODO Disables interrupt handling by setting IME=0 and cancelling any scheduled effects of the EI instruction if any. ], mnemonic: "DI", - length: 1, - duration: 1, opcode: [#bin("11110011")/#hex("F3")], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ("U",), + misc_op: ("IME ← 0",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xF3: IME = 0 + ```, + pseudocode: ```python +# M2/M1 +if IR == 0xF3: + # interrupt checking is suppressed so fetch_cycle(..) is not used + IR = read_memory(addr=PC); PC = PC + 1; IME = 0 ``` ) -#instruction-block( +#instruction( [ ==== EI: Enable interrupts Schedules interrupt handling to be enabled after the next machine cycle. ], - [*Opcode*], [#bin("11111011")/#hex("FB")], - [*Length*], [1 byte], - [*Duration*], [2 machine cycles (cc=false), or 5 machine cycles (cc=true)], - [*Flags*], [-], - [*Timing*], instruction-timing( - mnemonic: "EI", + mnemonic: "EI", + opcode: [#bin("11111011")/#hex("FB")], + operand_bytes: (), + timing: ( duration: 1, mem_rw: (), - mem_addr: (), - next_addr: [PC#sub[0]+1], + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ("U",), + misc_op: ("IME ← 1",), ), - [*Pseudocode*], ```python + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0xFB: - IME_scheduled = true + IME_next = 1 ```, + pseudocode: ```python +# M2/M1 +if IR == 0xFB: + IR, intr = fetch_cycle(addr=PC); PC = PC + 1; IME = 1 + ``` ) #instruction( @@ -1866,14 +3246,25 @@ if opcode == 0xFB: No operation. This instruction doesn't do anything, but can be used to add a delay of one machine cycle and increment PC by one. ], mnemonic: "NOP", - length: 1, - duration: 1, opcode: [#bin("00000000")/#hex("00")], - mem_rw: (), - mem_addr: (), - pseudocode: ```python + operand_bytes: (), + timing: ( + duration: 1, + mem_rw: (), + addr: ([PC],), + data: ([IR ← mem],), + idu_op: ([PC ← PC + 1],), + alu_op: ("U",), + misc_op: ("U",), + ), + simple-pseudocode: ```python opcode = read_memory(addr=PC); PC = PC + 1 if opcode == 0x00: - // nothing + # nothing + ```, + pseudocode: ```python +# M2/M1 +if IR == 0x00: + IR, intr = fetch_cycle(addr=PC); PC = PC + 1 ``` )