The 68000 presents eight 32-bit data registers and eight address-register names. Byte, word, and long operations share those registers; a 16-bit operation word selects their size and addressing modes. The active stack pointer is A7, backed by separate user and supervisor storage. Logical addresses retain 32 bits while the physical address bus exposes 24.
This specification is the sole maintained implementation and model contract for the original Motorola 68000. Its executable definitions generate the public class, stored state, views, instruction encodings and behavior, reset, execution, and exception/interrupt entry. Shared TypeScript services implement the declared mechanics. The language guide explains the notation; reference comparisons record independent cross-checks and their limits.
Historical setting
Introduced in 1979, the 68000 opened Motorola's 16/32-bit processor family. Its designers describe aiming beyond the 8-bit market toward systems previously built around minicomputers. Their oral history connects that ambition to the earlier 6800 business and the decision to invest in a new architecture. It later powered the original Macintosh; the specification models the processor, while a Macintosh needs its own memory map and devices. See the Macintosh processor history.
The physical processor and this model
The 68000 combines 32-bit registers with a 16-bit external data bus and a 16 MiB byte-address space. Address pins A23–A1 identify a word; upper/lower data strobes select its byte lanes. Even-addressed bytes occupy the upper lane. A long therefore requires more than one bus transfer. In an asynchronous bus cycle, the selected memory or peripheral acknowledges completion with DTACK; external logic can report failure with BERR. Function-code outputs distinguish access spaces. Motorola's user's manual, chapters 2, 3, and 5 explains these signals and transfers.
Here the connection transfers individual bytes and records successful calls. The model preserves logical addresses, byte order, and declared commit points, but does not simulate clock edges, strobes, wait states, bus arbitration, or prefetch. In particular, a modeled bus error can occur between the two bytes of a hardware word transfer. Fault recovery below describes this abstraction, not a promise of identical partial execution on silicon. Later 680x0 extensions, caches, and virtual-memory machinery are outside this original-chip model.
Stored state
D0–D7 and A0–A6 are independent 32-bit registers. USP and SSP store the two stack pointers; there is no additional stored A7. PC retains its full logical address, IR the current operation word, and the interrupt mask three bits. The entry group records exception-frame bookkeeping, separate from architectural flags. HALTED, FAULTED, and TRACEPENDING support the execution boundary.
cpu "68000" boundary word
state {
register D0: 32
register D1: 32
register D2: 32
register D3: 32
register D4: 32
register D5: 32
register D6: 32
register D7: 32
register A0: 32
register A1: 32
register A2: 32
register A3: 32
register A4: 32
register A5: 32
register A6: 32
register USP: 32
register SSP: 32
register PC: 32
register IR: 16
register INTERRUPTMASK: 3 = interruptMask
latch HALTED
latch FAULTED
latch TRACEPENDING = tracePending
group ENTRY {
choice KIND: "none", "reset", "fault", "exception", "trap"
register VECTOR: 8
}
flag X
flag N
flag Z
flag V
flag C
flag T
flag S
}
Construction and inspection
new Cpu68000(memory, initialState, connections?) requires a 16 MiB address
space and all these stored fields:
| Fields | Constraint |
|---|---|
d0–d7 |
Unsigned 32-bit data registers |
a0–a6 |
Unsigned 32-bit address registers |
usp, ssp |
Unsigned 32-bit user and supervisor stack pointers |
pc |
Unsigned 32-bit program counter |
ir |
Unsigned 16-bit last completely fetched operation word |
interruptMask |
Integer from 0 through 7 |
halted |
Boolean STOP latch; required in initial state |
faulted |
Boolean terminal double-fault latch; only external reset releases it |
tracePending |
Boolean owed-trace latch; required independently of T and STOP |
entry.kind |
none, reset, fault, exception, or trap: phase awaiting its first opcode fetch |
entry.vector |
Unsigned byte identifying that exception vector; ignored for none and reset |
flags.x/n/z/v/c |
Boolean extend, negative, zero, overflow, and carry |
flags.t/s |
Boolean trace and supervisor bits |
The original status register has X/N/Z/V/C at bits 4–0, interrupt mask at
10–8, S at 13, and T at 15. There is no master-mode bit or second trace bit.
Instructions pack and unpack SR/CCR from these fields; snapshots keep no duplicate
packed register. STOP sets halted; completed instructions that began with T
set owe a trace through tracePending. All three latches are stored in snapshots. faulted takes priority over STOP,
trace, and interrupt recognition. ir changes as soon as both opcode bytes
have been read; extension fetches, trace, and interrupt entry preserve it.
An odd instruction PC therefore stacks the supplied or previously fetched IR.
Synchronous exceptions and trace ignore the interrupt mask; external requests
use the level rules below. Entry clears T and selects SSP.
The exported cpu68000StateDescription is generated from the state block above.
It supplies field names and constraints to construction and machine parsing.
Construction reads each declared field once, validates it, and owns a copy.
Numeric and named-choice errors throw RangeError; missing or invalid flag groups and Boolean
fields throw TypeError. Extra metadata and derived views are ignored.
Construction does not read RAM, reset, or execute.
snapshot() owns a detached copy with readonly TypeScript types. It adds:
a7:sspwhen S is set, otherwiseusp. The active pointer is a view, so switching modes cannot leave a duplicate A7 value out of sync.physicalPc: the low 24 bits ofpc.
Snapshots can initialize another CPU. Neither inspection nor snapshot copying accesses RAM. Mutating caller state or an earlier snapshot cannot alter the CPU.
entry preserves the context of the next initial opcode fetch across snapshots.
Ordinary initial state uses { kind: "none", vector: 0 }. Successful reset
sets reset; bus/address-error entry sets fault; group-1 exceptions, trace,
and interrupts set exception; group-2 instruction traps set trap.
The vector distinguishes, for example, TRAP #0 from TRAP #1. A complete opcode
fetch clears the context to none, vector 0; a partial fetch preserves it.
This records entry sequencing without storing a prefetch queue. The existing
trace/interrupt boundary priority still applies before that fetch.
Memory connection
MemoryConnection describes
size, read(address), and write(address, value). Addresses reaching it are
physical 24-bit addresses. A successful read returns an integer byte; a
successful write returns nothing. Either operation can return "bus-error"
to report a failed transfer. The connection must report failure without
completing that byte, including any device side effect. size describes
the address space, so unmapped regions need not allocate RAM.
For example, a machine can expose a small RAM region on the full address bus:
const memory: MemoryConnection = {
size: 0x1000000,
read: address => address < ram.size ? ram.read(address) : "bus-error",
write: (address, value) => address < ram.size ? ram.write(address, value) : "bus-error",
};
Only this explicit result signals an emulated bus error. Thrown host values,
even the string "bus-error", propagate unchanged. Invalid successful read
values throw RangeError; a write returning another value throws TypeError.
The shared recorder logs a byte only after its transfer succeeds. The failed
byte appears in fault metadata, while earlier successful bytes remain in order.
Logical and physical addresses
Registers retain all 32 bits, including PC and both stack pointers. Sequential
instruction fetching advances PC modulo 2³². RAM access uses the low 24 bits
of an address, matching the original processor's physical address space.
For example, PC AB001000 reads its first byte at physical 001000.
Words and long words are big-endian. A long word contains its most significant
word first, and each word contains its most significant byte first. Data
accesses continue across the physical FFFFFF boundary at 000000.
Instruction words, word operands, and long operands require even addresses.
A long word at an address ending in 2 is valid. Byte accesses have no alignment restriction.
The shared runner compares snapshot().pc, retaining all 32 bits. Accordingly,
a machine file's end uses the full PC while its memory blocks use physical
addresses. Machine images must fit RAM; loading an image never wraps.
A7 and physical addresses
S selects the stack bank at each operand's turn: clear means USP, set means SSP. Reading A7 reads only that selected register. Capturing the choice separately lets an exchange resolve both register identities before reading either value, and retain those identities through writeback. The bank view returns zero for user storage and one for supervisor storage.
view STACKBANK "active stack bank" : 8 {
supervisor = flag S
return select(supervisor, u8(1), u8(0))
}
view A7 "active stack pointer" : 32 {
bank = source STACKBANK
pointer = choose not(zero(bank)) : 32 {
then {
stack = register SSP
return stack
}
else {
stack = register USP
return stack
}
}
return pointer
}
view PHYSICALPC "physical program address" : 32 {
logical = register PC
return and(logical, u32($FFFFFF))
}
The three-bit address code names A0–A7. Selecting A7 captures its current bank; internal codes seven and eight then identify USP and SSP respectively. This selection reads S only for A7 and does not read either stack pointer yet.
codes addressRegisters {
000 "A0"
001 "A1"
010 "A2"
011 "A3"
100 "A4"
101 "A5"
110 "A6"
111 "A7"
}
source selectAddressRegister "select address-register storage" (code: 3) : 8 {
selected = choose equal(code, u3(7)) : 8 {
then {
bank = source STACKBANK
return add(u8(7), bank)
}
else {
return extend(code, 8)
}
}
return selected
}
operands addressStorage {
000 "A0" = register A0
001 "A1" = register A1
010 "A2" = register A2
011 "A3" = register A3
100 "A4" = register A4
101 "A5" = register A5
110 "A6" = register A6
111 "USP" = register USP
}
source readAddressRegister "read selected address register" (selected: 8) : 32 {
contents = match selected : 32 {
case "00000rrr" for r in addressStorage {
original = operand r
return original
}
case "00001000" {
original = register SSP
return original
}
otherwise unsupported
}
return contents
}
action writeAddressRegister "write selected address register" (selected: 8, contents: 32) {
match selected {
case "00000rrr" for r in addressStorage {
operand r <- contents
}
case "00001000" {
SSP <- contents
}
otherwise unsupported
}
}
Condition codes and status
CCR packs X, N, Z, V, C into bits 4 through 0. SR additionally holds T in bit 15, S in bit 13, and the interrupt mask in bits 10–8; reserved bits read as zero. Capture SR in the established order: T, S, interrupt mask, then X/N/Z/V/C. CCR writes update those five flags in place. Full SR writes then update T/S and finally the interrupt mask, preserving the existing flag object.
view CCR "condition code register" : 16 {
x = flag X
n = flag N
z = flag Z
v = flag V
c = flag C
return extend(pack<8>(0, 0, 0, x, n, z, v, c), 16)
}
view SR "status register" : 16 {
trace = flag T
supervisor = flag S
mask = register INTERRUPTMASK
condition = source CCR
high = pack<8>(trace, 0, supervisor, 0, 0, bit(mask, 2), bit(mask, 1), bit(mask, 0))
return concat(high, lowByte(condition))
}
policy conditionCode "restore condition codes" (contents: 16) {
X = bit(contents, 4)
N = bit(contents, 3)
Z = bit(contents, 2)
V = bit(contents, 1)
C = bit(contents, 0)
}
policy systemFlags "restore system flags" (contents: 16) {
T = bit(contents, 15)
S = bit(contents, 13)
}
action writeCCR "write condition code register" (contents: 16) {
apply conditionCode(contents)
}
action writeSR "write status register" (contents: 16) {
perform writeCCR(contents)
apply systemFlags(contents)
INTERRUPTMASK <- bits(contents, 10, 8)
}
Data-register results
A byte or word write preserves the live upper part of its data register. The three result policies set N from the size's sign bit, set Z for zero, and clear V/C. They preserve X/T/S and serve the specification’s arithmetic families.
operands dataRegisters {
000 "D0" = register D0
001 "D1" = register D1
010 "D2" = register D2
011 "D3" = register D3
100 "D4" = register D4
101 "D5" = register D5
110 "D6" = register D6
111 "D7" = register D7
}
policy resultFlags<bits: 8, 16, 32> "68000 result" (result: bits) {
N = negative(result)
Z = zero(result)
V = 0
C = 0
}
Register transfers
MOVE uses 00 zz ddd mmm sss rrr: zz=01 is byte, 10 long, 11 word.
The destination occupies ddd/mmm; the source sss/rrr. Mode 000 names Dn,
mode 001 An. Byte forms exclude address registers. Destination mode 001
selects MOVEA, which sign-extends a word and preserves every flag.
Capture the source before selecting the destination. Write the destination before applying the result flags; preserve its live upper bits for a byte or word.
family move8DataData "0001 ddd 000 000 rrr" for d in dataRegisters, r in dataRegisters named "MOVE.B {r},{d}" {
originalSource = operand r
result = truncate(originalSource, 8)
preserved = operand d
operand d <- withBits(preserved, 7, 0, result)
apply resultFlags<8>(result)
}
Capture the source before selecting the destination. Write the destination before applying the result flags; preserve its live upper bits for a byte or word.
family registerCopy "0011 ddd 000 000 rrr" for d in dataRegisters, r in dataRegisters named "MOVE.W {r},{d}" {
originalSource = operand r
result = truncate(originalSource, 16)
preserved = operand d
operand d <- withBits(preserved, 15, 0, result)
apply resultFlags<16>(result)
}
Capture the source before selecting the destination. Write the destination before applying the result flags; preserve its live upper bits for a byte or word.
family move16AddressData "0011 ddd 000 001 rrr" for d in dataRegisters, r in addressRegisters named "MOVE.W {r},{d}" {
sourceCode = operand r
sourceRegister = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceRegister)
result = truncate(originalSource, 16)
preserved = operand d
operand d <- withBits(preserved, 15, 0, result)
apply resultFlags<16>(result)
}
Capture the source before selecting the destination. Replace the complete address register and preserve every flag.
family move16DataAddress "0011 ddd 001 000 rrr" for d in addressRegisters, r in dataRegisters named "MOVEA.W {r},{d}" {
originalSource = operand r
result = truncate(originalSource, 16)
destinationCode = operand d
destinationRegister = source selectAddressRegister(destinationCode)
perform writeAddressRegister(destinationRegister, signExtend(result, 32))
}
Capture the source before selecting the destination. Replace the complete address register and preserve every flag.
family move16AddressAddress "0011 ddd 001 001 rrr" for d in addressRegisters, r in addressRegisters named "MOVEA.W {r},{d}" {
sourceCode = operand r
sourceRegister = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceRegister)
result = truncate(originalSource, 16)
destinationCode = operand d
destinationRegister = source selectAddressRegister(destinationCode)
perform writeAddressRegister(destinationRegister, signExtend(result, 32))
}
Capture the source before selecting the destination. Write the destination before applying the result flags; preserve its live upper bits for a byte or word.
family move32DataData "0010 ddd 000 000 rrr" for d in dataRegisters, r in dataRegisters named "MOVE.L {r},{d}" {
originalSource = operand r
result = originalSource
operand d <- result
apply resultFlags<32>(result)
}
Capture the source before selecting the destination. Write the destination before applying the result flags; preserve its live upper bits for a byte or word.
family move32AddressData "0010 ddd 000 001 rrr" for d in dataRegisters, r in addressRegisters named "MOVE.L {r},{d}" {
sourceCode = operand r
sourceRegister = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceRegister)
result = originalSource
operand d <- result
apply resultFlags<32>(result)
}
Capture the source before selecting the destination. Replace the complete address register and preserve every flag.
family move32DataAddress "0010 ddd 001 000 rrr" for d in addressRegisters, r in dataRegisters named "MOVEA.L {r},{d}" {
originalSource = operand r
result = originalSource
destinationCode = operand d
destinationRegister = source selectAddressRegister(destinationCode)
perform writeAddressRegister(destinationRegister, result)
}
Capture the source before selecting the destination. Replace the complete address register and preserve every flag.
family move32AddressAddress "0010 ddd 001 001 rrr" for d in addressRegisters, r in addressRegisters named "MOVEA.L {r},{d}" {
sourceCode = operand r
sourceRegister = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceRegister)
result = originalSource
destinationCode = operand d
destinationRegister = source selectAddressRegister(destinationCode)
perform writeAddressRegister(destinationRegister, result)
}
Small constants, extension, and word exchange
MOVEQ encodes 0111 ddd 0 iiiiiiii. Its signed eight-bit constant becomes a
complete long in Dn. The execution contract below selects the low byte as its
input; the specification owns the encoding inventory, extraction, and body.
Sign-extend the immediate byte, replace Dn, then set N/Z and clear V/C. Preserve X/T/S.
family moveQuick (immediate: 8) "0111 ddd 0 xxxxxxxx" for d in dataRegisters named "MOVEQ #n,{d}" {
result = signExtend(immediate, 32)
operand d <- result
apply resultFlags<32>(result)
}
EXT occupies 0100 1000 1 s 000 rrr, with s=0 for byte-to-word and s=1
for word-to-long. EXT.W preserves the upper word from the same single read;
there is no live reread of Dn between calculation and writeback.
Read Dn once, sign-extend its byte to a word, preserve the captured upper word, and write Dn before applying word-result flags.
family extendWord "0100 1000 10 000 rrr" for r in dataRegisters named "EXT.W {r}" {
original = operand r
result = signExtend(truncate(original, 8), 16)
operand r <- withBits(original, 15, 0, result)
apply resultFlags<16>(result)
}
Read Dn once, sign-extend its word to a long, and write Dn before applying long-result flags.
family extendLong "0100 1000 11 000 rrr" for r in dataRegisters named "EXT.L {r}" {
original = operand r
result = signExtend(truncate(original, 16), 32)
operand r <- result
apply resultFlags<32>(result)
}
SWAP uses 0100 1000 01 000 rrr, beside the EXT slots. Read Dn once and
exchange its high and low words. Apply long-result flags before writing Dn,
preserving the established execution order.
family swap "0100 1000 01 000 rrr" for r in dataRegisters named "SWAP {r}" {
original = operand r
result = or(shiftBits(original, left, 16), shiftBits(original, right, 16))
apply resultFlags<32>(result)
operand r <- result
}
Register exchange
EXG uses 1100 ddd 1 ooooo rrr. Operation 01000 exchanges Dn/Dn,
01001 An/An, and 10001 Dn/An. Both identities must be selected before
either value is read, especially when A7 participates. Capture both originals,
write left then right, and preserve every flag, even for self-exchanges.
Resolve both register identities before reading either original. Capture both values before writing left then right; preserve every flag.
family exchangeDataData "1100 ddd 1 01000 rrr" for d in dataRegisters, r in dataRegisters named "EXG {d},{r}" {
left = operand d
right = operand r
operand d <- right
operand r <- left
}
Resolve both register identities before reading either original. Capture both values before writing left then right; preserve every flag.
family exchangeAddressAddress "1100 ddd 1 01001 rrr" for d in addressRegisters, r in addressRegisters named "EXG {d},{r}" {
leftCode = operand d
leftRegister = source selectAddressRegister(leftCode)
rightCode = operand r
rightRegister = source selectAddressRegister(rightCode)
left = source readAddressRegister(leftRegister)
right = source readAddressRegister(rightRegister)
perform writeAddressRegister(leftRegister, right)
perform writeAddressRegister(rightRegister, left)
}
Resolve both register identities before reading either original. Capture both values before writing left then right; preserve every flag.
family exchangeDataAddress "1100 ddd 1 10001 rrr" for d in dataRegisters, r in addressRegisters named "EXG {d},{r}" {
rightCode = operand r
rightRegister = source selectAddressRegister(rightCode)
left = operand d
right = source readAddressRegister(rightRegister)
operand d <- right
perform writeAddressRegister(rightRegister, left)
}
Effective-address decoding
An effective address is a 32-bit logical address. The memory connection projects
it onto the physical 24-bit bus later. The six-bit mmm rrr field selects a
mode and a register (or a submode when mmm=111). Instruction families already
exclude illegal combinations before any extension or operand access.
mmm |
Operand | Extensions |
|---|---|---|
000, 001 |
Dn or An directly; handled by instruction families | None |
010 |
(An) |
None |
011 |
(An)+ |
None |
100 |
-(An) |
None |
101 |
(d16,An) |
Signed word displacement |
110 |
(d8,An,Xn) |
Brief index word |
111 |
Absolute, PC-relative, or immediate | Selected by rrr |
For mode 111, codes 000 and 001 select sign-extended absolute word and
absolute long addresses. Codes 010 and 011 select PC-relative displacement
and indexed forms. Immediate operands (100) belong to the instruction's fetch
sequence, not this address source.
Stored registers and pending updates
Operand decoding can stage a new address-register value before the instruction commits it. Later operands and index calculations see that pending value; a normal register read still sees stored state. Unstaged reads consult live state at their own turn. Each selected A7 bank is retained independently of later S changes. Byte auto-updates use two bytes for A7 and one for every other An; word and long updates use two and four bytes.
pending register and stage operate on instruction-local bookkeeping, not
extra CPU state. Commit writes the latest value of each selected register in
first-stage order. Repeated commits retain that order and those pending values.
An alignment or extension-fetch failure before commit leaves stored registers
unchanged; failures after commit retain the completed writes. The instruction
families choose those commit points explicitly with commit addresses.
The ordinary data reader captures the whole Dn. The address reader below first checks pending storage and reads the live register only when it has no staged value.
source readDataRegister "read selected data register" (code: 3) : 32 {
contents = match extend(code, 8) : 32 {
case "00000rrr" for r in dataRegisters {
original = operand r
return original
}
otherwise unsupported
}
return contents
}
source readPendingAddressRegister "read pending or stored address register" (selected: 8) : 32 {
contents = match selected : 32 {
case "00000rrr" for r in addressStorage {
original = pending operand r
return original
}
case "00001000" {
original = pending register SSP
return original
}
otherwise unsupported
}
return contents
}
action stageAddressRegister "stage selected address register" (selected: 8, contents: 32) using staging {
match selected {
case "00000rrr" for r in addressStorage {
stage operand r <- contents
}
case "00001000" {
stage SSP <- contents
}
otherwise unsupported
}
}
Brief index extensions
The extension word is t rrr w 000 dddddddd: t=0 selects Dn, t=1 selects
An, and w=0/1 selects signed word/full long index values. The low byte is a
signed displacement. This original-68000 model ignores bits 10–8; it implements
neither scaling nor the later full extension format. Decode after fetching the
whole word, so register reads observe completed fetch callbacks. Address-index
reads also observe pending updates. Capture the address-bank selection before
choosing Dn versus An, retaining the existing model's read order.
source indexOffset "brief index and signed displacement" (extension: 16) : 32 {
code = bits(extension, 14, 12)
bank = source selectAddressRegister(code)
index = choose bit(extension, 15) : 32 {
then {
contents = source readPendingAddressRegister(bank)
return contents
}
else {
contents = source readDataRegister(code)
return contents
}
}
wide = select(bit(extension, 11), index, signExtend(truncate(index, 16), 32))
return add(wide, signExtend(lowByte(extension), 32))
}
Resolving a memory operand
Capture the selected address bank and its pending/live base before fetching any extensions, including for the absolute and PC-relative submodes. Displacement and index additions wrap at 32 bits. A PC-relative base is the extension word's address, captured before that word is fetched. Predecrement returns the staged new address; postincrement returns the captured old address.
The size input is the operand's width in bits: 8, 16, or 32, supplied by the
checked resolve instruction statement. This source returns an address and
stages updates; alignment checks and commit timing remain in the instruction.
Unsupported mode selections return unsupported without inventing an address.
source effectiveAddress "resolve a logical memory address" (size: 8, mode: 3, code: 3) : 32 {
bank = source selectAddressRegister(code)
base = source readPendingAddressRegister(bank)
bytes = shiftBits(size, right, 3)
step = select(and(equal(size, u8(8)), equal(code, u3(7))), u32(2), extend(bytes, 32))
address = match extend(mode, 8) : 32 {
case "00000010" {
return base
}
case "00000011" {
perform stageAddressRegister(bank, add(base, step))
return base
}
case "00000100" {
decremented = subtract(base, step)
perform stageAddressRegister(bank, decremented)
return decremented
}
case "00000101" {
displacement = fetch word
return add(base, signExtend(displacement, 32))
}
case "00000110" {
extension = fetch word
offset = source indexOffset(extension)
return add(base, offset)
}
case "00000111" {
absoluteOrRelative = match extend(code, 8) : 32 {
case "00000000" {
absolute = fetch word
return signExtend(absolute, 32)
}
case "00000001" {
high = fetch word
low = fetch word
return concat(high, low)
}
case "00000010" {
basePc = next address
displacement = fetch word
return add(basePc, signExtend(displacement, 32))
}
case "00000011" {
basePc = next address
extension = fetch word
offset = source indexOffset(extension)
return add(basePc, offset)
}
otherwise unsupported
}
return absoluteOrRelative
}
otherwise unsupported
}
return address
}
Memory transfers and immediate operands
MOVE uses the same 00 zz ddd mmm sss rrr layout for every addressing form.
The source is sss/rrr; the destination fields occur in the opposite order,
ddd/mmm. The following table describes the effective-address fields:
| Mode | Register/code | Operand |
|---|---|---|
000 |
000–111 |
D0–D7 |
001 |
000–111 |
A0–A7; word/long only |
010 |
000–111 |
(An) |
011 |
000–111 |
(An)+ |
100 |
000–111 |
-(An) |
101 |
000–111 |
(d16,An) |
110 |
000–111 |
(d8,An,Xn) |
111 |
000, 001 |
Absolute short, absolute long |
111 |
010, 011 |
PC-relative displacement, indexed PC-relative; source only |
111 |
100 |
Immediate; source only |
111 |
101–111 |
Undefined |
Byte transfers exclude An on both sides. MOVEA is selected by destination mode
001; it replaces the whole address register, sign-extends a word, and preserves
all flags. PC-relative source reads use program space; other memory operands use
data space. The effective-address resolver still owns extension decoding,
index calculation, A7 byte strides, and staged predecrement/postincrement.
Ordered byte access
The resolver returns a full 32-bit logical address. Each memory callback applies the 24-bit physical projection, retaining the logical address and access space for fault reporting. Words and longs require even addresses. Alignment checks remain at the instruction level, before the first rejected access; these sources and actions express only the ordered transfers. Address addition wraps at 32 bits. A long reads or writes its most significant byte first, through its least significant byte. A failed access retains earlier bytes and prevents later ones.
source readMemoryByte "read 8-bit data memory" (address: 32) : 8 {
byte0 = memory(address)
return byte0
}
source readProgramByte "read 8-bit program memory" (address: 32) : 8 {
byte0 = program memory(address)
return byte0
}
action writeMemoryByte "write 8-bit data memory" (address: 32, contents: 8) using memory {
memory(address) <- contents
}
source readMemoryWord "read 16-bit data memory" (address: 32) : 16 {
byte0 = memory(address)
byte1 = memory(add(address, u32(1)))
return concat(byte0, byte1)
}
source readProgramWord "read 16-bit program memory" (address: 32) : 16 {
byte0 = program memory(address)
byte1 = program memory(add(address, u32(1)))
return concat(byte0, byte1)
}
action writeMemoryWord "write 16-bit data memory" (address: 32, contents: 16) using memory {
memory(address) <- bits(contents, 15, 8)
memory(add(address, u32(1))) <- truncate(contents, 8)
}
source readMemoryLong "read 32-bit data memory" (address: 32) : 32 {
byte0 = memory(address)
byte1 = memory(add(address, u32(1)))
byte2 = memory(add(address, u32(2)))
byte3 = memory(add(address, u32(3)))
return concat(concat(byte0, byte1), concat(byte2, byte3))
}
source readProgramLong "read 32-bit program memory" (address: 32) : 32 {
byte0 = program memory(address)
byte1 = program memory(add(address, u32(1)))
byte2 = program memory(add(address, u32(2)))
byte3 = program memory(add(address, u32(3)))
return concat(concat(byte0, byte1), concat(byte2, byte3))
}
action writeMemoryLong "write 32-bit data memory" (address: 32, contents: 32) using memory {
memory(address) <- bits(contents, 31, 24)
memory(add(address, u32(1))) <- bits(contents, 23, 16)
memory(add(address, u32(2))) <- bits(contents, 15, 8)
memory(add(address, u32(3))) <- truncate(contents, 8)
}
Immediate byte operands occupy the low byte of one extension word. A word fetch supplies all sixteen bits; a long fetches the high word before the low word. The fetch boundary owns cursor advancement and partial-fetch reporting.
source immediateByte "8-bit immediate operand" : 8 {
high = fetch word
return truncate(high, 8)
}
source immediateWord "16-bit immediate operand" : 16 {
high = fetch word
return high
}
source immediateLong "32-bit immediate operand" : 32 {
high = fetch word
low = fetch word
return concat(high, low)
}
Data-register writeback
A byte or word write preserves the destination's live upper bits. Read those bits at writeback, after any source reads, destination extension fetches, and pending address-register commits. Long writes replace all thirty-two bits. The three-bit data code selects D0–D7; selection itself performs no state access.
codes dataRegisterCodes {
000 "D0"
001 "D1"
010 "D2"
011 "D3"
100 "D4"
101 "D5"
110 "D6"
111 "D7"
}
action writeDataByte "write 8-bit data register" (code: 3, contents: 8) {
match extend(code, 8) {
case "00000rrr" for r in dataRegisters {
preserved = operand r
operand r <- withBits(preserved, 7, 0, contents)
}
otherwise unsupported
}
}
action writeDataWord "write 16-bit data register" (code: 3, contents: 16) {
match extend(code, 8) {
case "00000rrr" for r in dataRegisters {
preserved = operand r
operand r <- withBits(preserved, 15, 0, contents)
}
otherwise unsupported
}
}
action writeDataLong "write 32-bit data register" (code: 3, contents: 32) {
match extend(code, 8) {
case "00000rrr" for r in dataRegisters {
operand r <- contents
}
otherwise unsupported
}
}
MOVE and MOVEA families
The patterns below enumerate every remaining legal pair. x positions still
belong to the operation word, but do not select a different instruction body.
The declared input masks extract sourceMode/sourceCode from sss/rrr and
destinationMode/destinationCode from mmm/ddd. Thus modes with the same
register, memory, and access-space roles share their formal body. The preceding
register families already own the forms where both operands are registers.
Resolve and read the entire source before resolving the destination or fetching its extensions. Later address calculations observe pending updates. Select a destination A7 bank before committing those updates, and retain that selection through writeback. Check alignment before committing: a failed source or destination extension discards pending updates. Commit before a destination write; a failed write retains those updates and earlier bytes, with flags unchanged. Only a complete MOVE sets N/Z and clears V/C; MOVEA preserves every flag.
Capture the source byte from Dn before resolving the destination. Commit pending address updates before writeback. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove8DataMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 xxx 01x 000 rrr" for r in dataRegisters named "MOVE.B {r},MEMORY"
encoding "00 01 xxx 10x 000 rrr" for r in dataRegisters named "MOVE.B {r},MEMORY"
encoding "00 01 xxx 110 000 rrr" for r in dataRegisters named "MOVE.B {r},MEMORY"
encoding "00 01 00x 111 000 rrr" for r in dataRegisters named "MOVE.B {r},MEMORY"
originalSource = operand r
result = truncate(originalSource, 8)
destinationAddress = resolve(8, destinationMode, destinationCode)
commit addresses
perform writeMemoryByte(destinationAddress, result)
apply resultFlags<8>(result)
}
Resolve and read the complete byte in data space before selecting the destination. Commit pending address updates before writeback. Preserve the destination's live upper 24 bits. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove8MemoryData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 ddd 000 01x xxx" for d in dataRegisterCodes named "MOVE.B MEMORY,{d}"
encoding "00 01 ddd 000 10x xxx" for d in dataRegisterCodes named "MOVE.B MEMORY,{d}"
encoding "00 01 ddd 000 110 xxx" for d in dataRegisterCodes named "MOVE.B MEMORY,{d}"
encoding "00 01 ddd 000 111 00x" for d in dataRegisterCodes named "MOVE.B MEMORY,{d}"
sourceAddress = resolve(8, sourceMode, sourceCode)
result = source readMemoryByte(sourceAddress)
registerCode = operand d
commit addresses
perform writeDataByte(registerCode, result)
apply resultFlags<8>(result)
}
Resolve and read the complete byte in data space before resolving the destination. Commit pending address updates before writeback. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove8MemoryMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 xxx 01x 01x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 01x 10x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 01x 110 xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 01x 111 00x" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 10x 01x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 10x 10x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 10x 110 xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 10x 111 00x" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 110 01x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 110 10x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 110 110 xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 xxx 110 111 00x" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 00x 111 01x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 00x 111 10x xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 00x 111 110 xxx" named "MOVE.B MEMORY,MEMORY"
encoding "00 01 00x 111 111 00x" named "MOVE.B MEMORY,MEMORY"
sourceAddress = resolve(8, sourceMode, sourceCode)
result = source readMemoryByte(sourceAddress)
destinationAddress = resolve(8, destinationMode, destinationCode)
commit addresses
perform writeMemoryByte(destinationAddress, result)
apply resultFlags<8>(result)
}
Resolve and read the complete byte in program space before selecting the destination. Commit pending address updates before writeback. Preserve the destination's live upper 24 bits. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove8ProgramData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 ddd 000 111 01x" for d in dataRegisterCodes named "MOVE.B PROGRAM,{d}"
sourceAddress = resolve(8, sourceMode, sourceCode)
result = source readProgramByte(sourceAddress)
registerCode = operand d
commit addresses
perform writeDataByte(registerCode, result)
apply resultFlags<8>(result)
}
Resolve and read the complete byte in program space before resolving the destination. Commit pending address updates before writeback. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove8ProgramMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 xxx 01x 111 01x" named "MOVE.B PROGRAM,MEMORY"
encoding "00 01 xxx 10x 111 01x" named "MOVE.B PROGRAM,MEMORY"
encoding "00 01 xxx 110 111 01x" named "MOVE.B PROGRAM,MEMORY"
encoding "00 01 00x 111 111 01x" named "MOVE.B PROGRAM,MEMORY"
sourceAddress = resolve(8, sourceMode, sourceCode)
result = source readProgramByte(sourceAddress)
destinationAddress = resolve(8, destinationMode, destinationCode)
commit addresses
perform writeMemoryByte(destinationAddress, result)
apply resultFlags<8>(result)
}
Fetch one extension word; retain its low byte before selecting the destination. Preserve the destination's live upper 24 bits. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove8ImmediateData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 ddd 000 111 100" for d in dataRegisterCodes named "MOVE.B IMMEDIATE,{d}"
result = source immediateByte
registerCode = operand d
perform writeDataByte(registerCode, result)
apply resultFlags<8>(result)
}
Fetch one extension word; retain its low byte before resolving the destination. Commit pending address updates before writeback. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove8ImmediateMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 01 xxx 01x 111 100" named "MOVE.B IMMEDIATE,MEMORY"
encoding "00 01 xxx 10x 111 100" named "MOVE.B IMMEDIATE,MEMORY"
encoding "00 01 xxx 110 111 100" named "MOVE.B IMMEDIATE,MEMORY"
encoding "00 01 00x 111 111 100" named "MOVE.B IMMEDIATE,MEMORY"
result = source immediateByte
destinationAddress = resolve(8, destinationMode, destinationCode)
commit addresses
perform writeMemoryByte(destinationAddress, result)
apply resultFlags<8>(result)
}
Capture the source word from Dn before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove16DataMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 xxx 01x 000 rrr" for r in dataRegisters named "MOVE.W {r},MEMORY"
encoding "00 11 xxx 10x 000 rrr" for r in dataRegisters named "MOVE.W {r},MEMORY"
encoding "00 11 xxx 110 000 rrr" for r in dataRegisters named "MOVE.W {r},MEMORY"
encoding "00 11 00x 111 000 rrr" for r in dataRegisters named "MOVE.W {r},MEMORY"
originalSource = operand r
result = truncate(originalSource, 16)
destinationAddress = resolve(16, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryWord(destinationAddress, result)
apply resultFlags<16>(result)
}
Select the source An bank and capture its word before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove16AddressMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 xxx 01x 001 rrr" for r in addressRegisters named "MOVE.W {r},MEMORY"
encoding "00 11 xxx 10x 001 rrr" for r in addressRegisters named "MOVE.W {r},MEMORY"
encoding "00 11 xxx 110 001 rrr" for r in addressRegisters named "MOVE.W {r},MEMORY"
encoding "00 11 00x 111 001 rrr" for r in addressRegisters named "MOVE.W {r},MEMORY"
registerCode = operand r
sourceRegister = source selectAddressRegister(registerCode)
originalSource = source readAddressRegister(sourceRegister)
result = truncate(originalSource, 16)
destinationAddress = resolve(16, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryWord(destinationAddress, result)
apply resultFlags<16>(result)
}
Resolve and read the complete word in data space before selecting the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Preserve the destination's live upper word. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove16MemoryData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 ddd 000 01x xxx" for d in dataRegisterCodes named "MOVE.W MEMORY,{d}"
encoding "00 11 ddd 000 10x xxx" for d in dataRegisterCodes named "MOVE.W MEMORY,{d}"
encoding "00 11 ddd 000 110 xxx" for d in dataRegisterCodes named "MOVE.W MEMORY,{d}"
encoding "00 11 ddd 000 111 00x" for d in dataRegisterCodes named "MOVE.W MEMORY,{d}"
sourceAddress = resolve(16, sourceMode, sourceCode)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
result = source readMemoryWord(sourceAddress)
registerCode = operand d
commit addresses
perform writeDataWord(registerCode, result)
apply resultFlags<16>(result)
}
Resolve and read the complete word in data space before selecting the destination. Reject odd memory addresses before their first byte access. Select the destination A7 bank before any pending-update commit. Commit pending address updates before writeback. Sign-extend the word into the complete address register; preserve every flag.
family operandMove16MemoryAddress (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 ddd 001 01x xxx" for d in addressRegisters named "MOVEA.W MEMORY,{d}"
encoding "00 11 ddd 001 10x xxx" for d in addressRegisters named "MOVEA.W MEMORY,{d}"
encoding "00 11 ddd 001 110 xxx" for d in addressRegisters named "MOVEA.W MEMORY,{d}"
encoding "00 11 ddd 001 111 00x" for d in addressRegisters named "MOVEA.W MEMORY,{d}"
sourceAddress = resolve(16, sourceMode, sourceCode)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
result = source readMemoryWord(sourceAddress)
registerCode = operand d
destinationRegister = source selectAddressRegister(registerCode)
commit addresses
perform writeAddressRegister(destinationRegister, signExtend(result, 32))
}
Resolve and read the complete word in data space before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove16MemoryMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 xxx 01x 01x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 01x 10x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 01x 110 xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 01x 111 00x" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 10x 01x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 10x 10x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 10x 110 xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 10x 111 00x" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 110 01x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 110 10x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 110 110 xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 xxx 110 111 00x" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 00x 111 01x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 00x 111 10x xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 00x 111 110 xxx" named "MOVE.W MEMORY,MEMORY"
encoding "00 11 00x 111 111 00x" named "MOVE.W MEMORY,MEMORY"
sourceAddress = resolve(16, sourceMode, sourceCode)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
result = source readMemoryWord(sourceAddress)
destinationAddress = resolve(16, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryWord(destinationAddress, result)
apply resultFlags<16>(result)
}
Resolve and read the complete word in program space before selecting the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Preserve the destination's live upper word. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove16ProgramData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 ddd 000 111 01x" for d in dataRegisterCodes named "MOVE.W PROGRAM,{d}"
sourceAddress = resolve(16, sourceMode, sourceCode)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
result = source readProgramWord(sourceAddress)
registerCode = operand d
commit addresses
perform writeDataWord(registerCode, result)
apply resultFlags<16>(result)
}
Resolve and read the complete word in program space before selecting the destination. Reject odd memory addresses before their first byte access. Select the destination A7 bank before any pending-update commit. Commit pending address updates before writeback. Sign-extend the word into the complete address register; preserve every flag.
family operandMove16ProgramAddress (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 ddd 001 111 01x" for d in addressRegisters named "MOVEA.W PROGRAM,{d}"
sourceAddress = resolve(16, sourceMode, sourceCode)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
result = source readProgramWord(sourceAddress)
registerCode = operand d
destinationRegister = source selectAddressRegister(registerCode)
commit addresses
perform writeAddressRegister(destinationRegister, signExtend(result, 32))
}
Resolve and read the complete word in program space before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove16ProgramMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 xxx 01x 111 01x" named "MOVE.W PROGRAM,MEMORY"
encoding "00 11 xxx 10x 111 01x" named "MOVE.W PROGRAM,MEMORY"
encoding "00 11 xxx 110 111 01x" named "MOVE.W PROGRAM,MEMORY"
encoding "00 11 00x 111 111 01x" named "MOVE.W PROGRAM,MEMORY"
sourceAddress = resolve(16, sourceMode, sourceCode)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
result = source readProgramWord(sourceAddress)
destinationAddress = resolve(16, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryWord(destinationAddress, result)
apply resultFlags<16>(result)
}
Fetch one extension word before selecting the destination. Preserve the destination's live upper word. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove16ImmediateData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 ddd 000 111 100" for d in dataRegisterCodes named "MOVE.W IMMEDIATE,{d}"
result = source immediateWord
registerCode = operand d
perform writeDataWord(registerCode, result)
apply resultFlags<16>(result)
}
Fetch one extension word before selecting the destination. Select the destination A7 bank before any pending-update commit. Sign-extend the word into the complete address register; preserve every flag.
family operandMove16ImmediateAddress (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 ddd 001 111 100" for d in addressRegisters named "MOVEA.W IMMEDIATE,{d}"
result = source immediateWord
registerCode = operand d
destinationRegister = source selectAddressRegister(registerCode)
perform writeAddressRegister(destinationRegister, signExtend(result, 32))
}
Fetch one extension word before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove16ImmediateMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 11 xxx 01x 111 100" named "MOVE.W IMMEDIATE,MEMORY"
encoding "00 11 xxx 10x 111 100" named "MOVE.W IMMEDIATE,MEMORY"
encoding "00 11 xxx 110 111 100" named "MOVE.W IMMEDIATE,MEMORY"
encoding "00 11 00x 111 111 100" named "MOVE.W IMMEDIATE,MEMORY"
result = source immediateWord
destinationAddress = resolve(16, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryWord(destinationAddress, result)
apply resultFlags<16>(result)
}
Capture the source long from Dn before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove32DataMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 xxx 01x 000 rrr" for r in dataRegisters named "MOVE.L {r},MEMORY"
encoding "00 10 xxx 10x 000 rrr" for r in dataRegisters named "MOVE.L {r},MEMORY"
encoding "00 10 xxx 110 000 rrr" for r in dataRegisters named "MOVE.L {r},MEMORY"
encoding "00 10 00x 111 000 rrr" for r in dataRegisters named "MOVE.L {r},MEMORY"
originalSource = operand r
result = originalSource
destinationAddress = resolve(32, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryLong(destinationAddress, result)
apply resultFlags<32>(result)
}
Select the source An bank and capture its long before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove32AddressMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 xxx 01x 001 rrr" for r in addressRegisters named "MOVE.L {r},MEMORY"
encoding "00 10 xxx 10x 001 rrr" for r in addressRegisters named "MOVE.L {r},MEMORY"
encoding "00 10 xxx 110 001 rrr" for r in addressRegisters named "MOVE.L {r},MEMORY"
encoding "00 10 00x 111 001 rrr" for r in addressRegisters named "MOVE.L {r},MEMORY"
registerCode = operand r
sourceRegister = source selectAddressRegister(registerCode)
originalSource = source readAddressRegister(sourceRegister)
result = originalSource
destinationAddress = resolve(32, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryLong(destinationAddress, result)
apply resultFlags<32>(result)
}
Resolve and read the complete long in data space before selecting the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove32MemoryData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 ddd 000 01x xxx" for d in dataRegisterCodes named "MOVE.L MEMORY,{d}"
encoding "00 10 ddd 000 10x xxx" for d in dataRegisterCodes named "MOVE.L MEMORY,{d}"
encoding "00 10 ddd 000 110 xxx" for d in dataRegisterCodes named "MOVE.L MEMORY,{d}"
encoding "00 10 ddd 000 111 00x" for d in dataRegisterCodes named "MOVE.L MEMORY,{d}"
sourceAddress = resolve(32, sourceMode, sourceCode)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
result = source readMemoryLong(sourceAddress)
registerCode = operand d
commit addresses
perform writeDataLong(registerCode, result)
apply resultFlags<32>(result)
}
Resolve and read the complete long in data space before selecting the destination. Reject odd memory addresses before their first byte access. Select the destination A7 bank before any pending-update commit. Commit pending address updates before writeback. Replace the complete address register; preserve every flag.
family operandMove32MemoryAddress (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 ddd 001 01x xxx" for d in addressRegisters named "MOVEA.L MEMORY,{d}"
encoding "00 10 ddd 001 10x xxx" for d in addressRegisters named "MOVEA.L MEMORY,{d}"
encoding "00 10 ddd 001 110 xxx" for d in addressRegisters named "MOVEA.L MEMORY,{d}"
encoding "00 10 ddd 001 111 00x" for d in addressRegisters named "MOVEA.L MEMORY,{d}"
sourceAddress = resolve(32, sourceMode, sourceCode)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
result = source readMemoryLong(sourceAddress)
registerCode = operand d
destinationRegister = source selectAddressRegister(registerCode)
commit addresses
perform writeAddressRegister(destinationRegister, result)
}
Resolve and read the complete long in data space before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove32MemoryMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 xxx 01x 01x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 01x 10x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 01x 110 xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 01x 111 00x" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 10x 01x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 10x 10x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 10x 110 xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 10x 111 00x" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 110 01x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 110 10x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 110 110 xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 xxx 110 111 00x" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 00x 111 01x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 00x 111 10x xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 00x 111 110 xxx" named "MOVE.L MEMORY,MEMORY"
encoding "00 10 00x 111 111 00x" named "MOVE.L MEMORY,MEMORY"
sourceAddress = resolve(32, sourceMode, sourceCode)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
result = source readMemoryLong(sourceAddress)
destinationAddress = resolve(32, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryLong(destinationAddress, result)
apply resultFlags<32>(result)
}
Resolve and read the complete long in program space before selecting the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove32ProgramData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 ddd 000 111 01x" for d in dataRegisterCodes named "MOVE.L PROGRAM,{d}"
sourceAddress = resolve(32, sourceMode, sourceCode)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
result = source readProgramLong(sourceAddress)
registerCode = operand d
commit addresses
perform writeDataLong(registerCode, result)
apply resultFlags<32>(result)
}
Resolve and read the complete long in program space before selecting the destination. Reject odd memory addresses before their first byte access. Select the destination A7 bank before any pending-update commit. Commit pending address updates before writeback. Replace the complete address register; preserve every flag.
family operandMove32ProgramAddress (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 ddd 001 111 01x" for d in addressRegisters named "MOVEA.L PROGRAM,{d}"
sourceAddress = resolve(32, sourceMode, sourceCode)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
result = source readProgramLong(sourceAddress)
registerCode = operand d
destinationRegister = source selectAddressRegister(registerCode)
commit addresses
perform writeAddressRegister(destinationRegister, result)
}
Resolve and read the complete long in program space before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove32ProgramMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 xxx 01x 111 01x" named "MOVE.L PROGRAM,MEMORY"
encoding "00 10 xxx 10x 111 01x" named "MOVE.L PROGRAM,MEMORY"
encoding "00 10 xxx 110 111 01x" named "MOVE.L PROGRAM,MEMORY"
encoding "00 10 00x 111 111 01x" named "MOVE.L PROGRAM,MEMORY"
sourceAddress = resolve(32, sourceMode, sourceCode)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
result = source readProgramLong(sourceAddress)
destinationAddress = resolve(32, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryLong(destinationAddress, result)
apply resultFlags<32>(result)
}
Fetch two extension words, high word first before selecting the destination. Only completed writeback sets N/Z and clears V/C; preserve X/T/S.
family operandMove32ImmediateData (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 ddd 000 111 100" for d in dataRegisterCodes named "MOVE.L IMMEDIATE,{d}"
result = source immediateLong
registerCode = operand d
perform writeDataLong(registerCode, result)
apply resultFlags<32>(result)
}
Fetch two extension words, high word first before selecting the destination. Select the destination A7 bank before any pending-update commit. Replace the complete address register; preserve every flag.
family operandMove32ImmediateAddress (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 ddd 001 111 100" for d in addressRegisters named "MOVEA.L IMMEDIATE,{d}"
result = source immediateLong
registerCode = operand d
destinationRegister = source selectAddressRegister(registerCode)
perform writeAddressRegister(destinationRegister, result)
}
Fetch two extension words, high word first before resolving the destination. Reject odd memory addresses before their first byte access. Commit pending address updates before writeback. Write high byte first. Only completed writeback sets N/Z and clears V/C; preserve X/T/S. Failed writes retain committed updates and earlier bytes with flags unchanged.
family operandMove32ImmediateMemory (sourceMode: 3, sourceCode: 3, destinationMode: 3, destinationCode: 3) {
encoding "00 10 xxx 01x 111 100" named "MOVE.L IMMEDIATE,MEMORY"
encoding "00 10 xxx 10x 111 100" named "MOVE.L IMMEDIATE,MEMORY"
encoding "00 10 xxx 110 111 100" named "MOVE.L IMMEDIATE,MEMORY"
encoding "00 10 00x 111 111 100" named "MOVE.L IMMEDIATE,MEMORY"
result = source immediateLong
destinationAddress = resolve(32, destinationMode, destinationCode)
fault alignment write(destinationAddress) if lowBit(destinationAddress)
commit addresses
perform writeMemoryLong(destinationAddress, result)
apply resultFlags<32>(result)
}
Logical operations and read/modify/write
AND keeps bits set in both operands, OR keeps bits set in either, and EOR keeps bits set in exactly one. NOT complements each bit; CLR produces zero; TST sets condition codes from the original operand without writing a result. All use the byte/word/long result policies above: N/Z describe the result, V/C clear, and X/T/S are preserved. Address registers are not legal operands for these families.
Encodings and operand order
The binary layout is oooo rrr d ss mmm eee. oooo=1000 selects OR,
1100 AND, and 1011 EOR with d=1. ss=00/01/10 selects byte/word/long;
ss=11 belongs to other instructions. rrr selects a data register, while
mmm/eee selects an effective address using the preceding table.
| Direction | Source | Destination | Legal effective addresses |
|---|---|---|---|
AND/OR, d=0 |
EA | Dn | Data register, data memory, PC-relative, immediate |
AND/OR, d=1 |
Dn | EA | Alterable data memory |
EOR, d=1 |
Dn | EA | Data register or alterable data memory |
Immediate logic uses 0000 ooo 0 ss mmm eee: ooo=000/001/101 selects
ORI/ANDI/EORI. Its destination must be a data register or alterable data memory.
AND/OR with an immediate source EA has the same operand effects as ANDI/ORI to
Dn; those encodings select the same formal body below. CCR/SR immediate forms
are separate system instructions and remain outside these families.
Unary logic uses 0100 oooo ss mmm eee: oooo=0010/0110/1010 selects
CLR/NOT/TST. Even TST is restricted to data-alterable operands on the original
68000: PC-relative and immediate operands are excluded.
Every family below takes the encoded mmm/eee as mode/code. Other register
selectors and the chosen calculation are bound by the specification. Pattern x
positions share a body while still determining those runtime EA fields.
No second TypeScript catalogue determines which operation words are legal.
MOVE commits pending address updates after completing the source read and before writing the destination. Logical operations instead commit before reading the destination, and set flags before writing it. The sequence is:
- Read the complete source, when present, before resolving the destination.
- Resolve the destination once. Reject odd word/long addresses before any access to them or commitment of pending address updates.
- Commit pending address updates, then read the destination. CLR retains this read even though its result ignores the value.
- Calculate the result and apply N/Z/V/C. TST stops here.
- Write the result using the captured address or register code. byte/word Dn writes preserve the live upper bits, read after the flag updates.
Failed source accesses discard pending updates. Failed destination reads retain committed updates but leave result flags unchanged. Failed writes retain updated flags, committed address registers, and completed bytes. All memory transfers remain high byte first with 32-bit logical wrap; PC-relative source reads retain program-space identity in both bus and alignment faults.
Captured registers and pure calculations
The data-register reader selects only D0–D7 and captures the whole register at its own turn. Narrowing happens in the instruction before calculation. Its matching write actions above preserve live upper bits at writeback, so a memory or flag callback cannot make a captured upper part overwrite a later change.
The calculation sources receive already captured numbers; they perform no state
or memory access. An encoding's with calculation = ... chooses the expression
while the surrounding family keeps the same visible access and writeback order.
CLR's calculation receives the captured operand too, even though it returns zero.
source andValue<bits: 8, 16, 32> "AND result" (left: bits, right: bits) : bits {
return and(left, right)
}
source orValue<bits: 8, 16, 32> "OR result" (left: bits, right: bits) : bits {
return or(left, right)
}
source eorValue<bits: 8, 16, 32> "EOR result" (left: bits, right: bits) : bits {
return xor(left, right)
}
source clearValue<bits: 8, 16, 32> "clear result" (original: bits) : bits {
return u<bits>(0)
}
source complementByte "8-bit complement result" (original: 8) : 8 {
return xor(original, u8($FF))
}
source complementWord "16-bit complement result" (original: 16) : 16 {
return xor(original, u16($FFFF))
}
source complementLong "32-bit complement result" (original: 32) : 32 {
return xor(original, u32($FFFFFFFF))
}
Binary families
Capture the source byte before reading the destination, including when both select the same Dn. Calculate the result from those captures and apply N/Z/V/C before writeback; preserve X/T/S. Read the destination's live upper bits again at writeback.
family operandLogic8DataData (mode: 3, code: 3) {
encoding "1000 ddd 0 00 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = orValue<8> named "OR.B {r},{d}"
encoding "1100 ddd 0 00 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = andValue<8> named "AND.B {r},{d}"
encoding "1011 rrr 1 00 000 ddd" for d in dataRegisterCodes, r in dataRegisters with calculation = eorValue<8> named "EOR.B {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 8)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
apply resultFlags<8>(result)
perform writeDataByte(registerCode, result)
}
Read the complete byte in data space before committing pending address updates and reading Dn. A failed source discards pending updates. Calculate and set N/Z/V/C before writing Dn; preserve X/T/S. Preserve its live upper bits after the flag updates.
family operandLogic8MemoryData (mode: 3, code: 3) {
encoding "1000 ddd 0 00 01x xxx" for d in dataRegisterCodes with calculation = orValue<8> named "OR.B MEMORY,{d}"
encoding "1000 ddd 0 00 10x xxx" for d in dataRegisterCodes with calculation = orValue<8> named "OR.B MEMORY,{d}"
encoding "1000 ddd 0 00 110 xxx" for d in dataRegisterCodes with calculation = orValue<8> named "OR.B MEMORY,{d}"
encoding "1000 ddd 0 00 111 00x" for d in dataRegisterCodes with calculation = orValue<8> named "OR.B MEMORY,{d}"
encoding "1100 ddd 0 00 01x xxx" for d in dataRegisterCodes with calculation = andValue<8> named "AND.B MEMORY,{d}"
encoding "1100 ddd 0 00 10x xxx" for d in dataRegisterCodes with calculation = andValue<8> named "AND.B MEMORY,{d}"
encoding "1100 ddd 0 00 110 xxx" for d in dataRegisterCodes with calculation = andValue<8> named "AND.B MEMORY,{d}"
encoding "1100 ddd 0 00 111 00x" for d in dataRegisterCodes with calculation = andValue<8> named "AND.B MEMORY,{d}"
sourceAddress = resolve(8, mode, code)
sourceValue = source readMemoryByte(sourceAddress)
commit addresses
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
apply resultFlags<8>(result)
perform writeDataByte(registerCode, result)
}
Read the complete byte in program space before committing pending address updates and reading Dn. A failed source discards pending updates. Calculate and set N/Z/V/C before writing Dn; preserve X/T/S. Preserve its live upper bits after the flag updates.
family operandLogic8ProgramData (mode: 3, code: 3) {
encoding "1000 ddd 0 00 111 01x" for d in dataRegisterCodes with calculation = orValue<8> named "OR.B PROGRAM,{d}"
encoding "1100 ddd 0 00 111 01x" for d in dataRegisterCodes with calculation = andValue<8> named "AND.B PROGRAM,{d}"
sourceAddress = resolve(8, mode, code)
sourceValue = source readProgramByte(sourceAddress)
commit addresses
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
apply resultFlags<8>(result)
perform writeDataByte(registerCode, result)
}
Fetch the complete immediate byte before reading Dn. AND/OR source-EA immediates and their ANDI/ORI encodings share this sequence. Set N/Z/V/C before writeback, preserving X/T/S and any live upper destination bits. No address update or memory destination read is needed.
family operandLogic8ImmediateData (mode: 3, code: 3) {
encoding "0000 0000 00 000 ddd" for d in dataRegisterCodes with calculation = orValue<8> named "ORI.B IMMEDIATE,{d}"
encoding "1000 ddd 0 00 111 100" for d in dataRegisterCodes with calculation = orValue<8> named "ORI.B IMMEDIATE,{d}"
encoding "0000 0010 00 000 ddd" for d in dataRegisterCodes with calculation = andValue<8> named "ANDI.B IMMEDIATE,{d}"
encoding "1100 ddd 0 00 111 100" for d in dataRegisterCodes with calculation = andValue<8> named "ANDI.B IMMEDIATE,{d}"
encoding "0000 1010 00 000 ddd" for d in dataRegisterCodes with calculation = eorValue<8> named "EORI.B IMMEDIATE,{d}"
sourceValue = source immediateByte
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
apply resultFlags<8>(result)
perform writeDataByte(registerCode, result)
}
Capture the data-register byte before resolving the destination once. Commit pending updates before reading the old destination. Set N/Z/V/C before writing the result, preserving X/T/S. Failed reads retain committed updates; failed writes retain flags and completed bytes.
family operandLogic8DataMemory (mode: 3, code: 3) {
encoding "1000 rrr 1 00 01x xxx" for r in dataRegisters with calculation = orValue<8> named "OR.B {r},MEMORY"
encoding "1000 rrr 1 00 10x xxx" for r in dataRegisters with calculation = orValue<8> named "OR.B {r},MEMORY"
encoding "1000 rrr 1 00 110 xxx" for r in dataRegisters with calculation = orValue<8> named "OR.B {r},MEMORY"
encoding "1000 rrr 1 00 111 00x" for r in dataRegisters with calculation = orValue<8> named "OR.B {r},MEMORY"
encoding "1100 rrr 1 00 01x xxx" for r in dataRegisters with calculation = andValue<8> named "AND.B {r},MEMORY"
encoding "1100 rrr 1 00 10x xxx" for r in dataRegisters with calculation = andValue<8> named "AND.B {r},MEMORY"
encoding "1100 rrr 1 00 110 xxx" for r in dataRegisters with calculation = andValue<8> named "AND.B {r},MEMORY"
encoding "1100 rrr 1 00 111 00x" for r in dataRegisters with calculation = andValue<8> named "AND.B {r},MEMORY"
encoding "1011 rrr 1 00 01x xxx" for r in dataRegisters with calculation = eorValue<8> named "EOR.B {r},MEMORY"
encoding "1011 rrr 1 00 10x xxx" for r in dataRegisters with calculation = eorValue<8> named "EOR.B {r},MEMORY"
encoding "1011 rrr 1 00 110 xxx" for r in dataRegisters with calculation = eorValue<8> named "EOR.B {r},MEMORY"
encoding "1011 rrr 1 00 111 00x" for r in dataRegisters with calculation = eorValue<8> named "EOR.B {r},MEMORY"
originalSource = operand r
sourceValue = truncate(originalSource, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
apply resultFlags<8>(result)
perform writeMemoryByte(destinationAddress, result)
}
Fetch the complete immediate byte before resolving the destination once. Commit pending updates before reading the old destination. Set N/Z/V/C before writing the result, preserving X/T/S. Failed reads retain committed updates; failed writes retain flags and completed bytes.
family operandLogic8ImmediateMemory (mode: 3, code: 3) {
encoding "0000 0000 00 01x xxx" with calculation = orValue<8> named "ORI.B IMMEDIATE,MEMORY"
encoding "0000 0000 00 10x xxx" with calculation = orValue<8> named "ORI.B IMMEDIATE,MEMORY"
encoding "0000 0000 00 110 xxx" with calculation = orValue<8> named "ORI.B IMMEDIATE,MEMORY"
encoding "0000 0000 00 111 00x" with calculation = orValue<8> named "ORI.B IMMEDIATE,MEMORY"
encoding "0000 0010 00 01x xxx" with calculation = andValue<8> named "ANDI.B IMMEDIATE,MEMORY"
encoding "0000 0010 00 10x xxx" with calculation = andValue<8> named "ANDI.B IMMEDIATE,MEMORY"
encoding "0000 0010 00 110 xxx" with calculation = andValue<8> named "ANDI.B IMMEDIATE,MEMORY"
encoding "0000 0010 00 111 00x" with calculation = andValue<8> named "ANDI.B IMMEDIATE,MEMORY"
encoding "0000 1010 00 01x xxx" with calculation = eorValue<8> named "EORI.B IMMEDIATE,MEMORY"
encoding "0000 1010 00 10x xxx" with calculation = eorValue<8> named "EORI.B IMMEDIATE,MEMORY"
encoding "0000 1010 00 110 xxx" with calculation = eorValue<8> named "EORI.B IMMEDIATE,MEMORY"
encoding "0000 1010 00 111 00x" with calculation = eorValue<8> named "EORI.B IMMEDIATE,MEMORY"
sourceValue = source immediateByte
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
apply resultFlags<8>(result)
perform writeMemoryByte(destinationAddress, result)
}
Capture the source word before reading the destination, including when both select the same Dn. Calculate the result from those captures and apply N/Z/V/C before writeback; preserve X/T/S. Read the destination's live upper bits again at writeback.
family operandLogic16DataData (mode: 3, code: 3) {
encoding "1000 ddd 0 01 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = orValue<16> named "OR.W {r},{d}"
encoding "1100 ddd 0 01 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = andValue<16> named "AND.W {r},{d}"
encoding "1011 rrr 1 01 000 ddd" for d in dataRegisterCodes, r in dataRegisters with calculation = eorValue<16> named "EOR.W {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
apply resultFlags<16>(result)
perform writeDataWord(registerCode, result)
}
Read the complete word in data space before committing pending address updates and reading Dn. Reject an odd source address before its first byte access. A failed source discards pending updates. Calculate and set N/Z/V/C before writing Dn; preserve X/T/S. Preserve its live upper bits after the flag updates.
family operandLogic16MemoryData (mode: 3, code: 3) {
encoding "1000 ddd 0 01 01x xxx" for d in dataRegisterCodes with calculation = orValue<16> named "OR.W MEMORY,{d}"
encoding "1000 ddd 0 01 10x xxx" for d in dataRegisterCodes with calculation = orValue<16> named "OR.W MEMORY,{d}"
encoding "1000 ddd 0 01 110 xxx" for d in dataRegisterCodes with calculation = orValue<16> named "OR.W MEMORY,{d}"
encoding "1000 ddd 0 01 111 00x" for d in dataRegisterCodes with calculation = orValue<16> named "OR.W MEMORY,{d}"
encoding "1100 ddd 0 01 01x xxx" for d in dataRegisterCodes with calculation = andValue<16> named "AND.W MEMORY,{d}"
encoding "1100 ddd 0 01 10x xxx" for d in dataRegisterCodes with calculation = andValue<16> named "AND.W MEMORY,{d}"
encoding "1100 ddd 0 01 110 xxx" for d in dataRegisterCodes with calculation = andValue<16> named "AND.W MEMORY,{d}"
encoding "1100 ddd 0 01 111 00x" for d in dataRegisterCodes with calculation = andValue<16> named "AND.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
commit addresses
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
apply resultFlags<16>(result)
perform writeDataWord(registerCode, result)
}
Read the complete word in program space before committing pending address updates and reading Dn. Reject an odd source address before its first byte access. A failed source discards pending updates. Calculate and set N/Z/V/C before writing Dn; preserve X/T/S. Preserve its live upper bits after the flag updates.
family operandLogic16ProgramData (mode: 3, code: 3) {
encoding "1000 ddd 0 01 111 01x" for d in dataRegisterCodes with calculation = orValue<16> named "OR.W PROGRAM,{d}"
encoding "1100 ddd 0 01 111 01x" for d in dataRegisterCodes with calculation = andValue<16> named "AND.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramWord(sourceAddress)
commit addresses
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
apply resultFlags<16>(result)
perform writeDataWord(registerCode, result)
}
Fetch the complete immediate word before reading Dn. AND/OR source-EA immediates and their ANDI/ORI encodings share this sequence. Set N/Z/V/C before writeback, preserving X/T/S and any live upper destination bits. No address update or memory destination read is needed.
family operandLogic16ImmediateData (mode: 3, code: 3) {
encoding "0000 0000 01 000 ddd" for d in dataRegisterCodes with calculation = orValue<16> named "ORI.W IMMEDIATE,{d}"
encoding "1000 ddd 0 01 111 100" for d in dataRegisterCodes with calculation = orValue<16> named "ORI.W IMMEDIATE,{d}"
encoding "0000 0010 01 000 ddd" for d in dataRegisterCodes with calculation = andValue<16> named "ANDI.W IMMEDIATE,{d}"
encoding "1100 ddd 0 01 111 100" for d in dataRegisterCodes with calculation = andValue<16> named "ANDI.W IMMEDIATE,{d}"
encoding "0000 1010 01 000 ddd" for d in dataRegisterCodes with calculation = eorValue<16> named "EORI.W IMMEDIATE,{d}"
sourceValue = source immediateWord
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
apply resultFlags<16>(result)
perform writeDataWord(registerCode, result)
}
Capture the data-register word before resolving the destination once. Reject an odd destination before committing updates or reading it. Commit pending updates before reading the old destination. Set N/Z/V/C before writing the result, preserving X/T/S. Failed reads retain committed updates; failed writes retain flags and completed bytes.
family operandLogic16DataMemory (mode: 3, code: 3) {
encoding "1000 rrr 1 01 01x xxx" for r in dataRegisters with calculation = orValue<16> named "OR.W {r},MEMORY"
encoding "1000 rrr 1 01 10x xxx" for r in dataRegisters with calculation = orValue<16> named "OR.W {r},MEMORY"
encoding "1000 rrr 1 01 110 xxx" for r in dataRegisters with calculation = orValue<16> named "OR.W {r},MEMORY"
encoding "1000 rrr 1 01 111 00x" for r in dataRegisters with calculation = orValue<16> named "OR.W {r},MEMORY"
encoding "1100 rrr 1 01 01x xxx" for r in dataRegisters with calculation = andValue<16> named "AND.W {r},MEMORY"
encoding "1100 rrr 1 01 10x xxx" for r in dataRegisters with calculation = andValue<16> named "AND.W {r},MEMORY"
encoding "1100 rrr 1 01 110 xxx" for r in dataRegisters with calculation = andValue<16> named "AND.W {r},MEMORY"
encoding "1100 rrr 1 01 111 00x" for r in dataRegisters with calculation = andValue<16> named "AND.W {r},MEMORY"
encoding "1011 rrr 1 01 01x xxx" for r in dataRegisters with calculation = eorValue<16> named "EOR.W {r},MEMORY"
encoding "1011 rrr 1 01 10x xxx" for r in dataRegisters with calculation = eorValue<16> named "EOR.W {r},MEMORY"
encoding "1011 rrr 1 01 110 xxx" for r in dataRegisters with calculation = eorValue<16> named "EOR.W {r},MEMORY"
encoding "1011 rrr 1 01 111 00x" for r in dataRegisters with calculation = eorValue<16> named "EOR.W {r},MEMORY"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
apply resultFlags<16>(result)
perform writeMemoryWord(destinationAddress, result)
}
Fetch the complete immediate word before resolving the destination once. Reject an odd destination before committing updates or reading it. Commit pending updates before reading the old destination. Set N/Z/V/C before writing the result, preserving X/T/S. Failed reads retain committed updates; failed writes retain flags and completed bytes.
family operandLogic16ImmediateMemory (mode: 3, code: 3) {
encoding "0000 0000 01 01x xxx" with calculation = orValue<16> named "ORI.W IMMEDIATE,MEMORY"
encoding "0000 0000 01 10x xxx" with calculation = orValue<16> named "ORI.W IMMEDIATE,MEMORY"
encoding "0000 0000 01 110 xxx" with calculation = orValue<16> named "ORI.W IMMEDIATE,MEMORY"
encoding "0000 0000 01 111 00x" with calculation = orValue<16> named "ORI.W IMMEDIATE,MEMORY"
encoding "0000 0010 01 01x xxx" with calculation = andValue<16> named "ANDI.W IMMEDIATE,MEMORY"
encoding "0000 0010 01 10x xxx" with calculation = andValue<16> named "ANDI.W IMMEDIATE,MEMORY"
encoding "0000 0010 01 110 xxx" with calculation = andValue<16> named "ANDI.W IMMEDIATE,MEMORY"
encoding "0000 0010 01 111 00x" with calculation = andValue<16> named "ANDI.W IMMEDIATE,MEMORY"
encoding "0000 1010 01 01x xxx" with calculation = eorValue<16> named "EORI.W IMMEDIATE,MEMORY"
encoding "0000 1010 01 10x xxx" with calculation = eorValue<16> named "EORI.W IMMEDIATE,MEMORY"
encoding "0000 1010 01 110 xxx" with calculation = eorValue<16> named "EORI.W IMMEDIATE,MEMORY"
encoding "0000 1010 01 111 00x" with calculation = eorValue<16> named "EORI.W IMMEDIATE,MEMORY"
sourceValue = source immediateWord
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
apply resultFlags<16>(result)
perform writeMemoryWord(destinationAddress, result)
}
Capture the source long before reading the destination, including when both select the same Dn. Calculate the result from those captures and apply N/Z/V/C before writeback; preserve X/T/S. Replace the complete destination register after flags.
family operandLogic32DataData (mode: 3, code: 3) {
encoding "1000 ddd 0 10 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = orValue<32> named "OR.L {r},{d}"
encoding "1100 ddd 0 10 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = andValue<32> named "AND.L {r},{d}"
encoding "1011 rrr 1 10 000 ddd" for d in dataRegisterCodes, r in dataRegisters with calculation = eorValue<32> named "EOR.L {r},{d}"
originalSource = operand r
sourceValue = originalSource
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
apply resultFlags<32>(result)
perform writeDataLong(registerCode, result)
}
Read the complete long in data space before committing pending address updates and reading Dn. Reject an odd source address before its first byte access. A failed source discards pending updates. Calculate and set N/Z/V/C before writing Dn; preserve X/T/S. Write the complete long after the flag updates.
family operandLogic32MemoryData (mode: 3, code: 3) {
encoding "1000 ddd 0 10 01x xxx" for d in dataRegisterCodes with calculation = orValue<32> named "OR.L MEMORY,{d}"
encoding "1000 ddd 0 10 10x xxx" for d in dataRegisterCodes with calculation = orValue<32> named "OR.L MEMORY,{d}"
encoding "1000 ddd 0 10 110 xxx" for d in dataRegisterCodes with calculation = orValue<32> named "OR.L MEMORY,{d}"
encoding "1000 ddd 0 10 111 00x" for d in dataRegisterCodes with calculation = orValue<32> named "OR.L MEMORY,{d}"
encoding "1100 ddd 0 10 01x xxx" for d in dataRegisterCodes with calculation = andValue<32> named "AND.L MEMORY,{d}"
encoding "1100 ddd 0 10 10x xxx" for d in dataRegisterCodes with calculation = andValue<32> named "AND.L MEMORY,{d}"
encoding "1100 ddd 0 10 110 xxx" for d in dataRegisterCodes with calculation = andValue<32> named "AND.L MEMORY,{d}"
encoding "1100 ddd 0 10 111 00x" for d in dataRegisterCodes with calculation = andValue<32> named "AND.L MEMORY,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
commit addresses
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
apply resultFlags<32>(result)
perform writeDataLong(registerCode, result)
}
Read the complete long in program space before committing pending address updates and reading Dn. Reject an odd source address before its first byte access. A failed source discards pending updates. Calculate and set N/Z/V/C before writing Dn; preserve X/T/S. Write the complete long after the flag updates.
family operandLogic32ProgramData (mode: 3, code: 3) {
encoding "1000 ddd 0 10 111 01x" for d in dataRegisterCodes with calculation = orValue<32> named "OR.L PROGRAM,{d}"
encoding "1100 ddd 0 10 111 01x" for d in dataRegisterCodes with calculation = andValue<32> named "AND.L PROGRAM,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramLong(sourceAddress)
commit addresses
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
apply resultFlags<32>(result)
perform writeDataLong(registerCode, result)
}
Fetch the complete immediate long before reading Dn. AND/OR source-EA immediates and their ANDI/ORI encodings share this sequence. Set N/Z/V/C before writeback, preserving X/T/S and any live upper destination bits. No address update or memory destination read is needed.
family operandLogic32ImmediateData (mode: 3, code: 3) {
encoding "0000 0000 10 000 ddd" for d in dataRegisterCodes with calculation = orValue<32> named "ORI.L IMMEDIATE,{d}"
encoding "1000 ddd 0 10 111 100" for d in dataRegisterCodes with calculation = orValue<32> named "ORI.L IMMEDIATE,{d}"
encoding "0000 0010 10 000 ddd" for d in dataRegisterCodes with calculation = andValue<32> named "ANDI.L IMMEDIATE,{d}"
encoding "1100 ddd 0 10 111 100" for d in dataRegisterCodes with calculation = andValue<32> named "ANDI.L IMMEDIATE,{d}"
encoding "0000 1010 10 000 ddd" for d in dataRegisterCodes with calculation = eorValue<32> named "EORI.L IMMEDIATE,{d}"
sourceValue = source immediateLong
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
apply resultFlags<32>(result)
perform writeDataLong(registerCode, result)
}
Capture the data-register long before resolving the destination once. Reject an odd destination before committing updates or reading it. Commit pending updates before reading the old destination. Set N/Z/V/C before writing the result, preserving X/T/S. Failed reads retain committed updates; failed writes retain flags and completed bytes.
family operandLogic32DataMemory (mode: 3, code: 3) {
encoding "1000 rrr 1 10 01x xxx" for r in dataRegisters with calculation = orValue<32> named "OR.L {r},MEMORY"
encoding "1000 rrr 1 10 10x xxx" for r in dataRegisters with calculation = orValue<32> named "OR.L {r},MEMORY"
encoding "1000 rrr 1 10 110 xxx" for r in dataRegisters with calculation = orValue<32> named "OR.L {r},MEMORY"
encoding "1000 rrr 1 10 111 00x" for r in dataRegisters with calculation = orValue<32> named "OR.L {r},MEMORY"
encoding "1100 rrr 1 10 01x xxx" for r in dataRegisters with calculation = andValue<32> named "AND.L {r},MEMORY"
encoding "1100 rrr 1 10 10x xxx" for r in dataRegisters with calculation = andValue<32> named "AND.L {r},MEMORY"
encoding "1100 rrr 1 10 110 xxx" for r in dataRegisters with calculation = andValue<32> named "AND.L {r},MEMORY"
encoding "1100 rrr 1 10 111 00x" for r in dataRegisters with calculation = andValue<32> named "AND.L {r},MEMORY"
encoding "1011 rrr 1 10 01x xxx" for r in dataRegisters with calculation = eorValue<32> named "EOR.L {r},MEMORY"
encoding "1011 rrr 1 10 10x xxx" for r in dataRegisters with calculation = eorValue<32> named "EOR.L {r},MEMORY"
encoding "1011 rrr 1 10 110 xxx" for r in dataRegisters with calculation = eorValue<32> named "EOR.L {r},MEMORY"
encoding "1011 rrr 1 10 111 00x" for r in dataRegisters with calculation = eorValue<32> named "EOR.L {r},MEMORY"
originalSource = operand r
sourceValue = originalSource
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
apply resultFlags<32>(result)
perform writeMemoryLong(destinationAddress, result)
}
Fetch the complete immediate long before resolving the destination once. Reject an odd destination before committing updates or reading it. Commit pending updates before reading the old destination. Set N/Z/V/C before writing the result, preserving X/T/S. Failed reads retain committed updates; failed writes retain flags and completed bytes.
family operandLogic32ImmediateMemory (mode: 3, code: 3) {
encoding "0000 0000 10 01x xxx" with calculation = orValue<32> named "ORI.L IMMEDIATE,MEMORY"
encoding "0000 0000 10 10x xxx" with calculation = orValue<32> named "ORI.L IMMEDIATE,MEMORY"
encoding "0000 0000 10 110 xxx" with calculation = orValue<32> named "ORI.L IMMEDIATE,MEMORY"
encoding "0000 0000 10 111 00x" with calculation = orValue<32> named "ORI.L IMMEDIATE,MEMORY"
encoding "0000 0010 10 01x xxx" with calculation = andValue<32> named "ANDI.L IMMEDIATE,MEMORY"
encoding "0000 0010 10 10x xxx" with calculation = andValue<32> named "ANDI.L IMMEDIATE,MEMORY"
encoding "0000 0010 10 110 xxx" with calculation = andValue<32> named "ANDI.L IMMEDIATE,MEMORY"
encoding "0000 0010 10 111 00x" with calculation = andValue<32> named "ANDI.L IMMEDIATE,MEMORY"
encoding "0000 1010 10 01x xxx" with calculation = eorValue<32> named "EORI.L IMMEDIATE,MEMORY"
encoding "0000 1010 10 10x xxx" with calculation = eorValue<32> named "EORI.L IMMEDIATE,MEMORY"
encoding "0000 1010 10 110 xxx" with calculation = eorValue<32> named "EORI.L IMMEDIATE,MEMORY"
encoding "0000 1010 10 111 00x" with calculation = eorValue<32> named "EORI.L IMMEDIATE,MEMORY"
sourceValue = source immediateLong
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
apply resultFlags<32>(result)
perform writeMemoryLong(destinationAddress, result)
}
Unary families
Capture the original byte in Dn. CLR retains the original read even though its result is zero; NOT complements every bit. Set N/Z/V/C before writeback and preserve X/T/S. Byte/word writes read and preserve live upper bits after the flag updates.
family operandLogic8UnaryData (mode: 3, code: 3) {
encoding "0100 0010 00 000 ddd" for d in dataRegisterCodes with calculation = clearValue<8> named "CLR.B {d}"
encoding "0100 0110 00 000 ddd" for d in dataRegisterCodes with calculation = complementByte named "NOT.B {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination)
apply resultFlags<8>(result)
perform writeDataByte(registerCode, result)
}
Capture the original byte in Dn. TST sets N/Z from that value and clears V/C, preserving X/T/S. It does not write a result.
family operandLogic8TestData (mode: 3, code: 3) {
encoding "0100 1010 00 000 ddd" for d in dataRegisterCodes named "TST.B {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = destination
apply resultFlags<8>(result)
}
Resolve the byte destination once. Commit pending updates before reading the complete original value. CLR retains the original read even though its result is zero; NOT complements every bit. Set N/Z/V/C before writeback and preserve X/T/S. Failed writes retain updated flags, committed address updates, and completed bytes.
family operandLogic8UnaryMemory (mode: 3, code: 3) {
encoding "0100 0010 00 01x xxx" with calculation = clearValue<8> named "CLR.B MEMORY"
encoding "0100 0010 00 10x xxx" with calculation = clearValue<8> named "CLR.B MEMORY"
encoding "0100 0010 00 110 xxx" with calculation = clearValue<8> named "CLR.B MEMORY"
encoding "0100 0010 00 111 00x" with calculation = clearValue<8> named "CLR.B MEMORY"
encoding "0100 0110 00 01x xxx" with calculation = complementByte named "NOT.B MEMORY"
encoding "0100 0110 00 10x xxx" with calculation = complementByte named "NOT.B MEMORY"
encoding "0100 0110 00 110 xxx" with calculation = complementByte named "NOT.B MEMORY"
encoding "0100 0110 00 111 00x" with calculation = complementByte named "NOT.B MEMORY"
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination)
apply resultFlags<8>(result)
perform writeMemoryByte(destinationAddress, result)
}
Resolve the byte destination once. Commit pending updates before reading the complete original value. TST sets N/Z from that value and clears V/C, preserving X/T/S. It does not write a result.
family operandLogic8TestMemory (mode: 3, code: 3) {
encoding "0100 1010 00 01x xxx" named "TST.B MEMORY"
encoding "0100 1010 00 10x xxx" named "TST.B MEMORY"
encoding "0100 1010 00 110 xxx" named "TST.B MEMORY"
encoding "0100 1010 00 111 00x" named "TST.B MEMORY"
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = destination
apply resultFlags<8>(result)
}
Capture the original word in Dn. CLR retains the original read even though its result is zero; NOT complements every bit. Set N/Z/V/C before writeback and preserve X/T/S. Byte/word writes read and preserve live upper bits after the flag updates.
family operandLogic16UnaryData (mode: 3, code: 3) {
encoding "0100 0010 01 000 ddd" for d in dataRegisterCodes with calculation = clearValue<16> named "CLR.W {d}"
encoding "0100 0110 01 000 ddd" for d in dataRegisterCodes with calculation = complementWord named "NOT.W {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination)
apply resultFlags<16>(result)
perform writeDataWord(registerCode, result)
}
Capture the original word in Dn. TST sets N/Z from that value and clears V/C, preserving X/T/S. It does not write a result.
family operandLogic16TestData (mode: 3, code: 3) {
encoding "0100 1010 01 000 ddd" for d in dataRegisterCodes named "TST.W {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = destination
apply resultFlags<16>(result)
}
Resolve the word destination once. Reject odd addresses before committing updates. Commit pending updates before reading the complete original value. CLR retains the original read even though its result is zero; NOT complements every bit. Set N/Z/V/C before writeback and preserve X/T/S. Failed writes retain updated flags, committed address updates, and completed bytes.
family operandLogic16UnaryMemory (mode: 3, code: 3) {
encoding "0100 0010 01 01x xxx" with calculation = clearValue<16> named "CLR.W MEMORY"
encoding "0100 0010 01 10x xxx" with calculation = clearValue<16> named "CLR.W MEMORY"
encoding "0100 0010 01 110 xxx" with calculation = clearValue<16> named "CLR.W MEMORY"
encoding "0100 0010 01 111 00x" with calculation = clearValue<16> named "CLR.W MEMORY"
encoding "0100 0110 01 01x xxx" with calculation = complementWord named "NOT.W MEMORY"
encoding "0100 0110 01 10x xxx" with calculation = complementWord named "NOT.W MEMORY"
encoding "0100 0110 01 110 xxx" with calculation = complementWord named "NOT.W MEMORY"
encoding "0100 0110 01 111 00x" with calculation = complementWord named "NOT.W MEMORY"
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination)
apply resultFlags<16>(result)
perform writeMemoryWord(destinationAddress, result)
}
Resolve the word destination once. Reject odd addresses before committing updates. Commit pending updates before reading the complete original value. TST sets N/Z from that value and clears V/C, preserving X/T/S. It does not write a result.
family operandLogic16TestMemory (mode: 3, code: 3) {
encoding "0100 1010 01 01x xxx" named "TST.W MEMORY"
encoding "0100 1010 01 10x xxx" named "TST.W MEMORY"
encoding "0100 1010 01 110 xxx" named "TST.W MEMORY"
encoding "0100 1010 01 111 00x" named "TST.W MEMORY"
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = destination
apply resultFlags<16>(result)
}
Capture the original long in Dn. CLR retains the original read even though its result is zero; NOT complements every bit. Set N/Z/V/C before writeback and preserve X/T/S. Write the complete long after the flag updates.
family operandLogic32UnaryData (mode: 3, code: 3) {
encoding "0100 0010 10 000 ddd" for d in dataRegisterCodes with calculation = clearValue<32> named "CLR.L {d}"
encoding "0100 0110 10 000 ddd" for d in dataRegisterCodes with calculation = complementLong named "NOT.L {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination)
apply resultFlags<32>(result)
perform writeDataLong(registerCode, result)
}
Capture the original long in Dn. TST sets N/Z from that value and clears V/C, preserving X/T/S. It does not write a result.
family operandLogic32TestData (mode: 3, code: 3) {
encoding "0100 1010 10 000 ddd" for d in dataRegisterCodes named "TST.L {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = destination
apply resultFlags<32>(result)
}
Resolve the long destination once. Reject odd addresses before committing updates. Commit pending updates before reading the complete original value. CLR retains the original read even though its result is zero; NOT complements every bit. Set N/Z/V/C before writeback and preserve X/T/S. Failed writes retain updated flags, committed address updates, and completed bytes.
family operandLogic32UnaryMemory (mode: 3, code: 3) {
encoding "0100 0010 10 01x xxx" with calculation = clearValue<32> named "CLR.L MEMORY"
encoding "0100 0010 10 10x xxx" with calculation = clearValue<32> named "CLR.L MEMORY"
encoding "0100 0010 10 110 xxx" with calculation = clearValue<32> named "CLR.L MEMORY"
encoding "0100 0010 10 111 00x" with calculation = clearValue<32> named "CLR.L MEMORY"
encoding "0100 0110 10 01x xxx" with calculation = complementLong named "NOT.L MEMORY"
encoding "0100 0110 10 10x xxx" with calculation = complementLong named "NOT.L MEMORY"
encoding "0100 0110 10 110 xxx" with calculation = complementLong named "NOT.L MEMORY"
encoding "0100 0110 10 111 00x" with calculation = complementLong named "NOT.L MEMORY"
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination)
apply resultFlags<32>(result)
perform writeMemoryLong(destinationAddress, result)
}
Resolve the long destination once. Reject odd addresses before committing updates. Commit pending updates before reading the complete original value. TST sets N/Z from that value and clears V/C, preserving X/T/S. It does not write a result.
family operandLogic32TestMemory (mode: 3, code: 3) {
encoding "0100 1010 10 01x xxx" named "TST.L MEMORY"
encoding "0100 1010 10 10x xxx" named "TST.L MEMORY"
encoding "0100 1010 10 110 xxx" named "TST.L MEMORY"
encoding "0100 1010 10 111 00x" named "TST.L MEMORY"
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = destination
apply resultFlags<32>(result)
}
Addition, subtraction, and comparison
The arithmetic unit works at byte, word, or long width. ADD and SUB replace the destination; CMP performs the same subtraction solely to set N/Z/V/C. Data arithmetic copies carry or borrow into X, while comparisons preserve X. ADDX, SUBX, and NEGX consume X and accumulate Z across successive pieces of a multi-precision number. Address arithmetic has a separate rule: ADDA/SUBA and ADDQ/SUBQ to An operate on all 32 bits without changing any flag. CMPA compares all 32 bits and sets N/Z/V/C, preserving X.
Arithmetic encodings
The main layout is oooo rrr d ss mmm eee. oooo=1001/1011/1101 selects
SUB/CMP/ADD, and ss=00/01/10 selects byte/word/long. With d=0, the EA is
the source and Dn is the destination. An direct sources are legal for word and
long operations only. With d=1, ADD/SUB use Dn as source and alterable memory
as destination. CMP's d=1 encodings instead contain EOR and CMPM.
| Pattern | Meaning |
|---|---|
oooo rrr s11 mmm eee |
SUBA/CMPA/ADDA; s=0/1 selects a word/long source, with every source EA legal. |
0000 ooo 0 ss mmm eee |
SUBI/ADDI/CMPI for ooo=010/011/110; data-alterable destinations only. |
0101 qqq d ss mmm eee |
ADDQ/SUBQ for d=0/1; qqq=000 means eight, otherwise one through seven. An accepts word/long only. |
oooo ddd 1 ss 00 m rrr |
SUBX/ADDX for oooo=1001/1101; m=0 selects Dn pairs, m=1 selects predecrement An pairs. |
1011 ddd 1 ss 001 rrr |
CMPM compares two postincrement memory operands. |
0100 0n00 ss mmm eee |
NEGX/NEG for n=0/1; data-alterable destinations only. |
Every family receives the raw low mode/code fields and upperCode, the
three bits at 11–9. The specification binds ordinary register operands and explicitly
assigns the paired-memory modes; upperCode supplies a quick amount or the
second address register in a memory pair. Wildcard x bits share a body rather
than generating one per literal or memory address mode. ADD/SUB/CMP immediate
source-EA encodings share bodies with their equivalent ADDI/SUBI/CMPI encodings.
Arithmetic results and flags
The result sources below calculate from captured numbers and publish their
flags before returning the result for writeback. They perform no operand reads.
Ordinary operations do not read any old flag. Extended operations read Z then X
only after both operands have arrived. They first publish N/Z/V/C/X, then set Z
again to old Z AND result-is-zero; both stages remain explicit for partial
failure observation. T/S are preserved throughout.
The carry/borrow and overflow predicates use the original inputs and incoming
X, not a prematurely wrapped intermediate. Thus subtracting $FF plus X from
a byte can borrow even though the combined subtrahend would wrap to zero.
Negation uses subtraction from zero and the same result policies. The width
parameter shares these rules across bytes, words, and longs; each caller selects
its operand width explicitly.
policy addFlags<bits: 8, 16, 32> "68000 addition flags" (left: bits, right: bits, result: bits, incoming: flag) {
N = negative(result)
Z = zero(result)
V = addOverflow(left, right, incoming)
C = carry(left, right, incoming)
X = carry(left, right, incoming)
}
source addValue<bits: 8, 16, 32> "add and flags" (left: bits, right: bits) : bits {
result = add(left, right)
apply addFlags<bits>(left, right, result, 0)
return result
}
policy subtractFlags<bits: 8, 16, 32> "68000 subtraction flags" (left: bits, right: bits, result: bits, incoming: flag) {
N = negative(result)
Z = zero(result)
V = overflow(left, right, incoming)
C = borrow(left, right, incoming)
X = borrow(left, right, incoming)
}
source subtractValue<bits: 8, 16, 32> "subtract and flags" (left: bits, right: bits) : bits {
result = subtract(left, right)
apply subtractFlags<bits>(left, right, result, 0)
return result
}
policy compareFlags<bits: 8, 16, 32> "68000 comparison flags" (left: bits, right: bits, result: bits, incoming: flag) {
N = negative(result)
Z = zero(result)
V = overflow(left, right, incoming)
C = borrow(left, right, incoming)
}
source compareValue<bits: 8, 16, 32> "compare and flags" (left: bits, right: bits) : bits {
result = subtract(left, right)
apply compareFlags<bits>(left, right, result, 0)
return result
}
policy cumulativeZero<bits: 8, 16, 32> "68000 cumulative zero" (previous: flag, result: bits) {
Z = and(previous, zero(result))
}
source addExtended<bits: 8, 16, 32> "add with X and cumulative Z" (left: bits, right: bits) : bits {
previousZero = flag Z
incoming = flag X
result = add(left, right, incoming)
apply addFlags<bits>(left, right, result, incoming)
apply cumulativeZero<bits>(previousZero, result)
return result
}
source subtractExtended<bits: 8, 16, 32> "subtract with X and cumulative Z" (left: bits, right: bits) : bits {
previousZero = flag Z
incoming = flag X
result = subtract(left, right, incoming)
apply subtractFlags<bits>(left, right, result, incoming)
apply cumulativeZero<bits>(previousZero, result)
return result
}
source negateValue<bits: 8, 16, 32> "negate" (original: bits) : bits {
result = source subtractValue<bits>(u<bits>(0), original)
return result
}
source negateExtended<bits: 8, 16, 32> "negateExtended" (original: bits) : bits {
result = source subtractExtended<bits>(u<bits>(0), original)
return result
}
Address addition and subtraction are pure 32-bit calculations. The family sign-extends a word EA before calling them; quick constants stay positive. CMPA instead uses the long comparison source and its N/Z/V/C policy.
source addAddress "32-bit address add without flags" (left: 32, right: 32) : 32 {
return add(left, right)
}
source subtractAddress "32-bit address subtract without flags" (left: 32, right: 32) : 32 {
return subtract(left, right)
}
Operand access and writeback
Read the complete source before selecting or resolving the destination. An A7 destination captures its bank before pending address updates commit and retains that identity through writeback. Read its value after the commit, so an aliased source's auto-update is visible to the arithmetic. Word address sources are sign-extended; word and long quick operations on An both keep the full pointer.
Reject odd word/long addresses before committing either operand's pending updates. Commit before reading the destination. Source failures discard pending updates; destination-read failures retain them. Apply result flags before any writeback, preserving the destination's live upper Dn bits for byte/word writes. A failed write retains flags, committed updates, and earlier bytes. Comparisons never write a destination. Memory remains high byte first, with 32-bit logical wrap and separate PC-relative program-space accesses.
The paired forms resolve the source first and the destination second, using literal predecrement or postincrement modes. The specification decoder makes the first pending value available to the second resolution, including when both name the same An; the families commit only after both alignment checks succeed.
Byte arithmetic families
Capture the source Dn. Read the destination after the source. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic8ModifyDataData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 00 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = addValue<8> named "ADD.B {r},{d}"
encoding "1101 ddd 1 00 00 0 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = addExtended<8> named "ADDX.B {r},{d}"
encoding "1001 ddd 0 00 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = subtractValue<8> named "SUB.B {r},{d}"
encoding "1001 ddd 1 00 00 0 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = subtractExtended<8> named "SUBX.B {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 8)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
perform writeDataByte(registerCode, result)
}
Read the complete data-space source. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic8ModifyMemoryData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 00 01x xxx" for d in dataRegisterCodes with calculation = addValue<8> named "ADD.B MEMORY,{d}"
encoding "1101 ddd 0 00 10x xxx" for d in dataRegisterCodes with calculation = addValue<8> named "ADD.B MEMORY,{d}"
encoding "1101 ddd 0 00 110 xxx" for d in dataRegisterCodes with calculation = addValue<8> named "ADD.B MEMORY,{d}"
encoding "1101 ddd 0 00 111 00x" for d in dataRegisterCodes with calculation = addValue<8> named "ADD.B MEMORY,{d}"
encoding "1001 ddd 0 00 01x xxx" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUB.B MEMORY,{d}"
encoding "1001 ddd 0 00 10x xxx" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUB.B MEMORY,{d}"
encoding "1001 ddd 0 00 110 xxx" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUB.B MEMORY,{d}"
encoding "1001 ddd 0 00 111 00x" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUB.B MEMORY,{d}"
sourceAddress = resolve(8, mode, code)
sourceValue = source readMemoryByte(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
perform writeDataByte(registerCode, result)
}
Read the complete program-space source. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic8ModifyProgramData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 00 111 01x" for d in dataRegisterCodes with calculation = addValue<8> named "ADD.B PROGRAM,{d}"
encoding "1001 ddd 0 00 111 01x" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUB.B PROGRAM,{d}"
sourceAddress = resolve(8, mode, code)
sourceValue = source readProgramByte(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
perform writeDataByte(registerCode, result)
}
Fetch the complete immediate. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic8ModifyImmediateData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 00 111 100" for d in dataRegisterCodes with calculation = addValue<8> named "ADDI.B IMMEDIATE,{d}"
encoding "0000 011 0 00 000 ddd" for d in dataRegisterCodes with calculation = addValue<8> named "ADDI.B IMMEDIATE,{d}"
encoding "1001 ddd 0 00 111 100" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUBI.B IMMEDIATE,{d}"
encoding "0000 010 0 00 000 ddd" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUBI.B IMMEDIATE,{d}"
sourceValue = source immediateByte
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
perform writeDataByte(registerCode, result)
}
Fetch the complete immediate. Resolve the destination. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic8ModifyImmediateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 011 0 00 01x xxx" with calculation = addValue<8> named "ADDI.B IMMEDIATE,MEMORY"
encoding "0000 011 0 00 10x xxx" with calculation = addValue<8> named "ADDI.B IMMEDIATE,MEMORY"
encoding "0000 011 0 00 110 xxx" with calculation = addValue<8> named "ADDI.B IMMEDIATE,MEMORY"
encoding "0000 011 0 00 111 00x" with calculation = addValue<8> named "ADDI.B IMMEDIATE,MEMORY"
encoding "0000 010 0 00 01x xxx" with calculation = subtractValue<8> named "SUBI.B IMMEDIATE,MEMORY"
encoding "0000 010 0 00 10x xxx" with calculation = subtractValue<8> named "SUBI.B IMMEDIATE,MEMORY"
encoding "0000 010 0 00 110 xxx" with calculation = subtractValue<8> named "SUBI.B IMMEDIATE,MEMORY"
encoding "0000 010 0 00 111 00x" with calculation = subtractValue<8> named "SUBI.B IMMEDIATE,MEMORY"
sourceValue = source immediateByte
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryByte(destinationAddress, result)
}
Capture the source Dn. Resolve the destination. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic8ModifyDataMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1101 rrr 1 00 01x xxx" for r in dataRegisters with calculation = addValue<8> named "ADD.B {r},MEMORY"
encoding "1101 rrr 1 00 10x xxx" for r in dataRegisters with calculation = addValue<8> named "ADD.B {r},MEMORY"
encoding "1101 rrr 1 00 110 xxx" for r in dataRegisters with calculation = addValue<8> named "ADD.B {r},MEMORY"
encoding "1101 rrr 1 00 111 00x" for r in dataRegisters with calculation = addValue<8> named "ADD.B {r},MEMORY"
encoding "1001 rrr 1 00 01x xxx" for r in dataRegisters with calculation = subtractValue<8> named "SUB.B {r},MEMORY"
encoding "1001 rrr 1 00 10x xxx" for r in dataRegisters with calculation = subtractValue<8> named "SUB.B {r},MEMORY"
encoding "1001 rrr 1 00 110 xxx" for r in dataRegisters with calculation = subtractValue<8> named "SUB.B {r},MEMORY"
encoding "1001 rrr 1 00 111 00x" for r in dataRegisters with calculation = subtractValue<8> named "SUB.B {r},MEMORY"
originalSource = operand r
sourceValue = truncate(originalSource, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryByte(destinationAddress, result)
}
Decode the positive quick amount. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic8ModifyQuickData (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 00 000 ddd" for d in dataRegisterCodes with calculation = addValue<8> named "ADDQ.B QUICK,{d}"
encoding "0101 xxx 1 00 000 ddd" for d in dataRegisterCodes with calculation = subtractValue<8> named "SUBQ.B QUICK,{d}"
sourceValue = select(zero(upperCode), u8(8), extend(upperCode, 8))
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
perform writeDataByte(registerCode, result)
}
Decode the positive quick amount. Resolve the destination. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic8ModifyQuickMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 00 01x xxx" with calculation = addValue<8> named "ADDQ.B QUICK,MEMORY"
encoding "0101 xxx 0 00 10x xxx" with calculation = addValue<8> named "ADDQ.B QUICK,MEMORY"
encoding "0101 xxx 0 00 110 xxx" with calculation = addValue<8> named "ADDQ.B QUICK,MEMORY"
encoding "0101 xxx 0 00 111 00x" with calculation = addValue<8> named "ADDQ.B QUICK,MEMORY"
encoding "0101 xxx 1 00 01x xxx" with calculation = subtractValue<8> named "SUBQ.B QUICK,MEMORY"
encoding "0101 xxx 1 00 10x xxx" with calculation = subtractValue<8> named "SUBQ.B QUICK,MEMORY"
encoding "0101 xxx 1 00 110 xxx" with calculation = subtractValue<8> named "SUBQ.B QUICK,MEMORY"
encoding "0101 xxx 1 00 111 00x" with calculation = subtractValue<8> named "SUBQ.B QUICK,MEMORY"
sourceValue = select(zero(upperCode), u8(8), extend(upperCode, 8))
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryByte(destinationAddress, result)
}
Resolve and read the first predecrement operand. Resolve the second operand. Commit pending addresses before reading the destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic8ModifyPredecrementPair (mode: 3, code: 3, upperCode: 3) {
encoding "1101 xxx 1 00 00 1 xxx" with calculation = addExtended<8> named "ADDX.B MEMORY,MEMORY"
encoding "1001 xxx 1 00 00 1 xxx" with calculation = subtractExtended<8> named "SUBX.B MEMORY,MEMORY"
sourceAddress = resolve(8, u3(4), code)
sourceValue = source readMemoryByte(sourceAddress)
destinationAddress = resolve(8, u3(4), upperCode)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryByte(destinationAddress, result)
}
Capture the source Dn. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic8CompareDataData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 00 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = compareValue<8> named "CMP.B {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 8)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
}
Read the complete data-space source. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic8CompareMemoryData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 00 01x xxx" for d in dataRegisterCodes with calculation = compareValue<8> named "CMP.B MEMORY,{d}"
encoding "1011 ddd 0 00 10x xxx" for d in dataRegisterCodes with calculation = compareValue<8> named "CMP.B MEMORY,{d}"
encoding "1011 ddd 0 00 110 xxx" for d in dataRegisterCodes with calculation = compareValue<8> named "CMP.B MEMORY,{d}"
encoding "1011 ddd 0 00 111 00x" for d in dataRegisterCodes with calculation = compareValue<8> named "CMP.B MEMORY,{d}"
sourceAddress = resolve(8, mode, code)
sourceValue = source readMemoryByte(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
}
Read the complete program-space source. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic8CompareProgramData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 00 111 01x" for d in dataRegisterCodes with calculation = compareValue<8> named "CMP.B PROGRAM,{d}"
sourceAddress = resolve(8, mode, code)
sourceValue = source readProgramByte(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic8CompareImmediateData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 00 111 100" for d in dataRegisterCodes with calculation = compareValue<8> named "CMPI.B IMMEDIATE,{d}"
encoding "0000 110 0 00 000 ddd" for d in dataRegisterCodes with calculation = compareValue<8> named "CMPI.B IMMEDIATE,{d}"
sourceValue = source immediateByte
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Resolve the destination. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic8CompareImmediateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 110 0 00 01x xxx" with calculation = compareValue<8> named "CMPI.B IMMEDIATE,MEMORY"
encoding "0000 110 0 00 10x xxx" with calculation = compareValue<8> named "CMPI.B IMMEDIATE,MEMORY"
encoding "0000 110 0 00 110 xxx" with calculation = compareValue<8> named "CMPI.B IMMEDIATE,MEMORY"
encoding "0000 110 0 00 111 00x" with calculation = compareValue<8> named "CMPI.B IMMEDIATE,MEMORY"
sourceValue = source immediateByte
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
}
Resolve and read the first postincrement operand. Resolve the second operand. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic8ComparePostincrementPair (mode: 3, code: 3, upperCode: 3) {
encoding "1011 xxx 1 00 001 xxx" with calculation = compareValue<8> named "CMPM.B MEMORY,MEMORY"
sourceAddress = resolve(8, u3(3), code)
sourceValue = source readMemoryByte(sourceAddress)
destinationAddress = resolve(8, u3(3), upperCode)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
}
Read the original destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic8ModifyUnaryData (mode: 3, code: 3, upperCode: 3) {
encoding "0100 0100 00 000 ddd" for d in dataRegisterCodes with calculation = negateValue<8> named "NEG.B {d}"
encoding "0100 0000 00 000 ddd" for d in dataRegisterCodes with calculation = negateExtended<8> named "NEGX.B {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 8)
result = source calculation(destination)
perform writeDataByte(registerCode, result)
}
Resolve the destination. Commit pending addresses before reading the destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic8ModifyUnaryMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0100 0100 00 01x xxx" with calculation = negateValue<8> named "NEG.B MEMORY"
encoding "0100 0100 00 10x xxx" with calculation = negateValue<8> named "NEG.B MEMORY"
encoding "0100 0100 00 110 xxx" with calculation = negateValue<8> named "NEG.B MEMORY"
encoding "0100 0100 00 111 00x" with calculation = negateValue<8> named "NEG.B MEMORY"
encoding "0100 0000 00 01x xxx" with calculation = negateExtended<8> named "NEGX.B MEMORY"
encoding "0100 0000 00 10x xxx" with calculation = negateExtended<8> named "NEGX.B MEMORY"
encoding "0100 0000 00 110 xxx" with calculation = negateExtended<8> named "NEGX.B MEMORY"
encoding "0100 0000 00 111 00x" with calculation = negateExtended<8> named "NEGX.B MEMORY"
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination)
perform writeMemoryByte(destinationAddress, result)
}
Word arithmetic families
Capture the source Dn. Read the destination after the source. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyDataData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 01 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = addValue<16> named "ADD.W {r},{d}"
encoding "1101 ddd 1 01 00 0 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = addExtended<16> named "ADDX.W {r},{d}"
encoding "1001 ddd 0 01 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = subtractValue<16> named "SUB.W {r},{d}"
encoding "1001 ddd 1 01 00 0 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = subtractExtended<16> named "SUBX.W {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
perform writeDataWord(registerCode, result)
}
Select and read the source An bank. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyAddressData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 01 001 rrr" for d in dataRegisterCodes, r in addressRegisters with calculation = addValue<16> named "ADD.W {r},{d}"
encoding "1001 ddd 0 01 001 rrr" for d in dataRegisterCodes, r in addressRegisters with calculation = subtractValue<16> named "SUB.W {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = truncate(originalSource, 16)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
perform writeDataWord(registerCode, result)
}
Read the complete data-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyMemoryData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 01 01x xxx" for d in dataRegisterCodes with calculation = addValue<16> named "ADD.W MEMORY,{d}"
encoding "1101 ddd 0 01 10x xxx" for d in dataRegisterCodes with calculation = addValue<16> named "ADD.W MEMORY,{d}"
encoding "1101 ddd 0 01 110 xxx" for d in dataRegisterCodes with calculation = addValue<16> named "ADD.W MEMORY,{d}"
encoding "1101 ddd 0 01 111 00x" for d in dataRegisterCodes with calculation = addValue<16> named "ADD.W MEMORY,{d}"
encoding "1001 ddd 0 01 01x xxx" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUB.W MEMORY,{d}"
encoding "1001 ddd 0 01 10x xxx" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUB.W MEMORY,{d}"
encoding "1001 ddd 0 01 110 xxx" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUB.W MEMORY,{d}"
encoding "1001 ddd 0 01 111 00x" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUB.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
perform writeDataWord(registerCode, result)
}
Read the complete program-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyProgramData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 01 111 01x" for d in dataRegisterCodes with calculation = addValue<16> named "ADD.W PROGRAM,{d}"
encoding "1001 ddd 0 01 111 01x" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUB.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramWord(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
perform writeDataWord(registerCode, result)
}
Fetch the complete immediate. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyImmediateData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 01 111 100" for d in dataRegisterCodes with calculation = addValue<16> named "ADDI.W IMMEDIATE,{d}"
encoding "0000 011 0 01 000 ddd" for d in dataRegisterCodes with calculation = addValue<16> named "ADDI.W IMMEDIATE,{d}"
encoding "1001 ddd 0 01 111 100" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUBI.W IMMEDIATE,{d}"
encoding "0000 010 0 01 000 ddd" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUBI.W IMMEDIATE,{d}"
sourceValue = source immediateWord
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
perform writeDataWord(registerCode, result)
}
Fetch the complete immediate. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic16ModifyImmediateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 011 0 01 01x xxx" with calculation = addValue<16> named "ADDI.W IMMEDIATE,MEMORY"
encoding "0000 011 0 01 10x xxx" with calculation = addValue<16> named "ADDI.W IMMEDIATE,MEMORY"
encoding "0000 011 0 01 110 xxx" with calculation = addValue<16> named "ADDI.W IMMEDIATE,MEMORY"
encoding "0000 011 0 01 111 00x" with calculation = addValue<16> named "ADDI.W IMMEDIATE,MEMORY"
encoding "0000 010 0 01 01x xxx" with calculation = subtractValue<16> named "SUBI.W IMMEDIATE,MEMORY"
encoding "0000 010 0 01 10x xxx" with calculation = subtractValue<16> named "SUBI.W IMMEDIATE,MEMORY"
encoding "0000 010 0 01 110 xxx" with calculation = subtractValue<16> named "SUBI.W IMMEDIATE,MEMORY"
encoding "0000 010 0 01 111 00x" with calculation = subtractValue<16> named "SUBI.W IMMEDIATE,MEMORY"
sourceValue = source immediateWord
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryWord(destinationAddress, result)
}
Capture the source Dn. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic16ModifyDataMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1101 rrr 1 01 01x xxx" for r in dataRegisters with calculation = addValue<16> named "ADD.W {r},MEMORY"
encoding "1101 rrr 1 01 10x xxx" for r in dataRegisters with calculation = addValue<16> named "ADD.W {r},MEMORY"
encoding "1101 rrr 1 01 110 xxx" for r in dataRegisters with calculation = addValue<16> named "ADD.W {r},MEMORY"
encoding "1101 rrr 1 01 111 00x" for r in dataRegisters with calculation = addValue<16> named "ADD.W {r},MEMORY"
encoding "1001 rrr 1 01 01x xxx" for r in dataRegisters with calculation = subtractValue<16> named "SUB.W {r},MEMORY"
encoding "1001 rrr 1 01 10x xxx" for r in dataRegisters with calculation = subtractValue<16> named "SUB.W {r},MEMORY"
encoding "1001 rrr 1 01 110 xxx" for r in dataRegisters with calculation = subtractValue<16> named "SUB.W {r},MEMORY"
encoding "1001 rrr 1 01 111 00x" for r in dataRegisters with calculation = subtractValue<16> named "SUB.W {r},MEMORY"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryWord(destinationAddress, result)
}
Capture the source Dn. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic16ModifyDataAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 011 000 rrr" for d in addressRegisters, r in dataRegisters with calculation = addAddress named "ADDA.W {r},{d}"
encoding "1001 ddd 011 000 rrr" for d in addressRegisters, r in dataRegisters with calculation = subtractAddress named "SUBA.W {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
perform writeAddressRegister(destinationBank, result)
}
Select and read the source An bank. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic16ModifyAddressAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 011 001 rrr" for d in addressRegisters, r in addressRegisters with calculation = addAddress named "ADDA.W {r},{d}"
encoding "1001 ddd 011 001 rrr" for d in addressRegisters, r in addressRegisters with calculation = subtractAddress named "SUBA.W {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = truncate(originalSource, 16)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
perform writeAddressRegister(destinationBank, result)
}
Read the complete data-space source. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Preserve all flags and replace all 32 destination bits.
family operandArithmetic16ModifyMemoryAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 011 01x xxx" for d in addressRegisters with calculation = addAddress named "ADDA.W MEMORY,{d}"
encoding "1101 ddd 011 10x xxx" for d in addressRegisters with calculation = addAddress named "ADDA.W MEMORY,{d}"
encoding "1101 ddd 011 110 xxx" for d in addressRegisters with calculation = addAddress named "ADDA.W MEMORY,{d}"
encoding "1101 ddd 011 111 00x" for d in addressRegisters with calculation = addAddress named "ADDA.W MEMORY,{d}"
encoding "1001 ddd 011 01x xxx" for d in addressRegisters with calculation = subtractAddress named "SUBA.W MEMORY,{d}"
encoding "1001 ddd 011 10x xxx" for d in addressRegisters with calculation = subtractAddress named "SUBA.W MEMORY,{d}"
encoding "1001 ddd 011 110 xxx" for d in addressRegisters with calculation = subtractAddress named "SUBA.W MEMORY,{d}"
encoding "1001 ddd 011 111 00x" for d in addressRegisters with calculation = subtractAddress named "SUBA.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
perform writeAddressRegister(destinationBank, result)
}
Read the complete program-space source. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Preserve all flags and replace all 32 destination bits.
family operandArithmetic16ModifyProgramAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 011 111 01x" for d in addressRegisters with calculation = addAddress named "ADDA.W PROGRAM,{d}"
encoding "1001 ddd 011 111 01x" for d in addressRegisters with calculation = subtractAddress named "SUBA.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramWord(sourceAddress)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
perform writeAddressRegister(destinationBank, result)
}
Fetch the complete immediate. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic16ModifyImmediateAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 011 111 100" for d in addressRegisters with calculation = addAddress named "ADDA.W IMMEDIATE,{d}"
encoding "1001 ddd 011 111 100" for d in addressRegisters with calculation = subtractAddress named "SUBA.W IMMEDIATE,{d}"
sourceValue = source immediateWord
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
perform writeAddressRegister(destinationBank, result)
}
Decode the positive quick amount. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyQuickData (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 01 000 ddd" for d in dataRegisterCodes with calculation = addValue<16> named "ADDQ.W QUICK,{d}"
encoding "0101 xxx 1 01 000 ddd" for d in dataRegisterCodes with calculation = subtractValue<16> named "SUBQ.W QUICK,{d}"
sourceValue = select(zero(upperCode), u16(8), extend(upperCode, 16))
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
perform writeDataWord(registerCode, result)
}
Decode the positive quick amount. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic16ModifyQuickAddress (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 01 001 ddd" for d in addressRegisters with calculation = addAddress named "ADDQ.W QUICK,{d}"
encoding "0101 xxx 1 01 001 ddd" for d in addressRegisters with calculation = subtractAddress named "SUBQ.W QUICK,{d}"
sourceValue = select(zero(upperCode), u32(8), extend(upperCode, 32))
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Decode the positive quick amount. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic16ModifyQuickMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 01 01x xxx" with calculation = addValue<16> named "ADDQ.W QUICK,MEMORY"
encoding "0101 xxx 0 01 10x xxx" with calculation = addValue<16> named "ADDQ.W QUICK,MEMORY"
encoding "0101 xxx 0 01 110 xxx" with calculation = addValue<16> named "ADDQ.W QUICK,MEMORY"
encoding "0101 xxx 0 01 111 00x" with calculation = addValue<16> named "ADDQ.W QUICK,MEMORY"
encoding "0101 xxx 1 01 01x xxx" with calculation = subtractValue<16> named "SUBQ.W QUICK,MEMORY"
encoding "0101 xxx 1 01 10x xxx" with calculation = subtractValue<16> named "SUBQ.W QUICK,MEMORY"
encoding "0101 xxx 1 01 110 xxx" with calculation = subtractValue<16> named "SUBQ.W QUICK,MEMORY"
encoding "0101 xxx 1 01 111 00x" with calculation = subtractValue<16> named "SUBQ.W QUICK,MEMORY"
sourceValue = select(zero(upperCode), u16(8), extend(upperCode, 16))
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryWord(destinationAddress, result)
}
Resolve and read the first predecrement operand. Resolve the second operand. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic16ModifyPredecrementPair (mode: 3, code: 3, upperCode: 3) {
encoding "1101 xxx 1 01 00 1 xxx" with calculation = addExtended<16> named "ADDX.W MEMORY,MEMORY"
encoding "1001 xxx 1 01 00 1 xxx" with calculation = subtractExtended<16> named "SUBX.W MEMORY,MEMORY"
sourceAddress = resolve(16, u3(4), code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
destinationAddress = resolve(16, u3(4), upperCode)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryWord(destinationAddress, result)
}
Capture the source Dn. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareDataData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 01 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = compareValue<16> named "CMP.W {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
}
Select and read the source An bank. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareAddressData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 01 001 rrr" for d in dataRegisterCodes, r in addressRegisters with calculation = compareValue<16> named "CMP.W {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = truncate(originalSource, 16)
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
}
Read the complete data-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareMemoryData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 01 01x xxx" for d in dataRegisterCodes with calculation = compareValue<16> named "CMP.W MEMORY,{d}"
encoding "1011 ddd 0 01 10x xxx" for d in dataRegisterCodes with calculation = compareValue<16> named "CMP.W MEMORY,{d}"
encoding "1011 ddd 0 01 110 xxx" for d in dataRegisterCodes with calculation = compareValue<16> named "CMP.W MEMORY,{d}"
encoding "1011 ddd 0 01 111 00x" for d in dataRegisterCodes with calculation = compareValue<16> named "CMP.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
}
Read the complete program-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareProgramData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 01 111 01x" for d in dataRegisterCodes with calculation = compareValue<16> named "CMP.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramWord(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareImmediateData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 01 111 100" for d in dataRegisterCodes with calculation = compareValue<16> named "CMPI.W IMMEDIATE,{d}"
encoding "0000 110 0 01 000 ddd" for d in dataRegisterCodes with calculation = compareValue<16> named "CMPI.W IMMEDIATE,{d}"
sourceValue = source immediateWord
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareImmediateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 110 0 01 01x xxx" with calculation = compareValue<16> named "CMPI.W IMMEDIATE,MEMORY"
encoding "0000 110 0 01 10x xxx" with calculation = compareValue<16> named "CMPI.W IMMEDIATE,MEMORY"
encoding "0000 110 0 01 110 xxx" with calculation = compareValue<16> named "CMPI.W IMMEDIATE,MEMORY"
encoding "0000 110 0 01 111 00x" with calculation = compareValue<16> named "CMPI.W IMMEDIATE,MEMORY"
sourceValue = source immediateWord
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
}
Capture the source Dn. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareDataAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 011 000 rrr" for d in addressRegisters, r in dataRegisters with calculation = compareValue<32> named "CMPA.W {r},{d}"
originalSource = operand r
sourceValue = truncate(originalSource, 16)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
}
Select and read the source An bank. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareAddressAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 011 001 rrr" for d in addressRegisters, r in addressRegisters with calculation = compareValue<32> named "CMPA.W {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = truncate(originalSource, 16)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
}
Read the complete data-space source. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareMemoryAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 011 01x xxx" for d in addressRegisters with calculation = compareValue<32> named "CMPA.W MEMORY,{d}"
encoding "1011 ddd 011 10x xxx" for d in addressRegisters with calculation = compareValue<32> named "CMPA.W MEMORY,{d}"
encoding "1011 ddd 011 110 xxx" for d in addressRegisters with calculation = compareValue<32> named "CMPA.W MEMORY,{d}"
encoding "1011 ddd 011 111 00x" for d in addressRegisters with calculation = compareValue<32> named "CMPA.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
}
Read the complete program-space source. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareProgramAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 011 111 01x" for d in addressRegisters with calculation = compareValue<32> named "CMPA.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramWord(sourceAddress)
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
}
Fetch the complete immediate. Sign-extend the word source to 32 bits. Select the destination bank, retaining it through the instruction. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16CompareImmediateAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 011 111 100" for d in addressRegisters with calculation = compareValue<32> named "CMPA.W IMMEDIATE,{d}"
sourceValue = source immediateWord
converted = signExtend(sourceValue, 32)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, converted)
}
Resolve and read the first postincrement operand. Resolve the second operand. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic16ComparePostincrementPair (mode: 3, code: 3, upperCode: 3) {
encoding "1011 xxx 1 01 001 xxx" with calculation = compareValue<16> named "CMPM.W MEMORY,MEMORY"
sourceAddress = resolve(16, u3(3), code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryWord(sourceAddress)
destinationAddress = resolve(16, u3(3), upperCode)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination, sourceValue)
}
Read the original destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S and the live upper Dn bits.
family operandArithmetic16ModifyUnaryData (mode: 3, code: 3, upperCode: 3) {
encoding "0100 0100 01 000 ddd" for d in dataRegisterCodes with calculation = negateValue<16> named "NEG.W {d}"
encoding "0100 0000 01 000 ddd" for d in dataRegisterCodes with calculation = negateExtended<16> named "NEGX.W {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = truncate(originalDestination, 16)
result = source calculation(destination)
perform writeDataWord(registerCode, result)
}
Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic16ModifyUnaryMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0100 0100 01 01x xxx" with calculation = negateValue<16> named "NEG.W MEMORY"
encoding "0100 0100 01 10x xxx" with calculation = negateValue<16> named "NEG.W MEMORY"
encoding "0100 0100 01 110 xxx" with calculation = negateValue<16> named "NEG.W MEMORY"
encoding "0100 0100 01 111 00x" with calculation = negateValue<16> named "NEG.W MEMORY"
encoding "0100 0000 01 01x xxx" with calculation = negateExtended<16> named "NEGX.W MEMORY"
encoding "0100 0000 01 10x xxx" with calculation = negateExtended<16> named "NEGX.W MEMORY"
encoding "0100 0000 01 110 xxx" with calculation = negateExtended<16> named "NEGX.W MEMORY"
encoding "0100 0000 01 111 00x" with calculation = negateExtended<16> named "NEGX.W MEMORY"
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryWord(destinationAddress)
result = source calculation(destination)
perform writeMemoryWord(destinationAddress, result)
}
Long arithmetic families
Capture the source Dn. Read the destination after the source. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyDataData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 10 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = addValue<32> named "ADD.L {r},{d}"
encoding "1101 ddd 1 10 00 0 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = addExtended<32> named "ADDX.L {r},{d}"
encoding "1001 ddd 0 10 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = subtractValue<32> named "SUB.L {r},{d}"
encoding "1001 ddd 1 10 00 0 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = subtractExtended<32> named "SUBX.L {r},{d}"
originalSource = operand r
sourceValue = originalSource
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
perform writeDataLong(registerCode, result)
}
Select and read the source An bank. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyAddressData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 10 001 rrr" for d in dataRegisterCodes, r in addressRegisters with calculation = addValue<32> named "ADD.L {r},{d}"
encoding "1001 ddd 0 10 001 rrr" for d in dataRegisterCodes, r in addressRegisters with calculation = subtractValue<32> named "SUB.L {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = originalSource
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
perform writeDataLong(registerCode, result)
}
Read the complete data-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyMemoryData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 10 01x xxx" for d in dataRegisterCodes with calculation = addValue<32> named "ADD.L MEMORY,{d}"
encoding "1101 ddd 0 10 10x xxx" for d in dataRegisterCodes with calculation = addValue<32> named "ADD.L MEMORY,{d}"
encoding "1101 ddd 0 10 110 xxx" for d in dataRegisterCodes with calculation = addValue<32> named "ADD.L MEMORY,{d}"
encoding "1101 ddd 0 10 111 00x" for d in dataRegisterCodes with calculation = addValue<32> named "ADD.L MEMORY,{d}"
encoding "1001 ddd 0 10 01x xxx" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUB.L MEMORY,{d}"
encoding "1001 ddd 0 10 10x xxx" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUB.L MEMORY,{d}"
encoding "1001 ddd 0 10 110 xxx" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUB.L MEMORY,{d}"
encoding "1001 ddd 0 10 111 00x" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUB.L MEMORY,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
perform writeDataLong(registerCode, result)
}
Read the complete program-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyProgramData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 10 111 01x" for d in dataRegisterCodes with calculation = addValue<32> named "ADD.L PROGRAM,{d}"
encoding "1001 ddd 0 10 111 01x" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUB.L PROGRAM,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramLong(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
perform writeDataLong(registerCode, result)
}
Fetch the complete immediate. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyImmediateData (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 0 10 111 100" for d in dataRegisterCodes with calculation = addValue<32> named "ADDI.L IMMEDIATE,{d}"
encoding "0000 011 0 10 000 ddd" for d in dataRegisterCodes with calculation = addValue<32> named "ADDI.L IMMEDIATE,{d}"
encoding "1001 ddd 0 10 111 100" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUBI.L IMMEDIATE,{d}"
encoding "0000 010 0 10 000 ddd" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUBI.L IMMEDIATE,{d}"
sourceValue = source immediateLong
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
perform writeDataLong(registerCode, result)
}
Fetch the complete immediate. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyImmediateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 011 0 10 01x xxx" with calculation = addValue<32> named "ADDI.L IMMEDIATE,MEMORY"
encoding "0000 011 0 10 10x xxx" with calculation = addValue<32> named "ADDI.L IMMEDIATE,MEMORY"
encoding "0000 011 0 10 110 xxx" with calculation = addValue<32> named "ADDI.L IMMEDIATE,MEMORY"
encoding "0000 011 0 10 111 00x" with calculation = addValue<32> named "ADDI.L IMMEDIATE,MEMORY"
encoding "0000 010 0 10 01x xxx" with calculation = subtractValue<32> named "SUBI.L IMMEDIATE,MEMORY"
encoding "0000 010 0 10 10x xxx" with calculation = subtractValue<32> named "SUBI.L IMMEDIATE,MEMORY"
encoding "0000 010 0 10 110 xxx" with calculation = subtractValue<32> named "SUBI.L IMMEDIATE,MEMORY"
encoding "0000 010 0 10 111 00x" with calculation = subtractValue<32> named "SUBI.L IMMEDIATE,MEMORY"
sourceValue = source immediateLong
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryLong(destinationAddress, result)
}
Capture the source Dn. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyDataMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1101 rrr 1 10 01x xxx" for r in dataRegisters with calculation = addValue<32> named "ADD.L {r},MEMORY"
encoding "1101 rrr 1 10 10x xxx" for r in dataRegisters with calculation = addValue<32> named "ADD.L {r},MEMORY"
encoding "1101 rrr 1 10 110 xxx" for r in dataRegisters with calculation = addValue<32> named "ADD.L {r},MEMORY"
encoding "1101 rrr 1 10 111 00x" for r in dataRegisters with calculation = addValue<32> named "ADD.L {r},MEMORY"
encoding "1001 rrr 1 10 01x xxx" for r in dataRegisters with calculation = subtractValue<32> named "SUB.L {r},MEMORY"
encoding "1001 rrr 1 10 10x xxx" for r in dataRegisters with calculation = subtractValue<32> named "SUB.L {r},MEMORY"
encoding "1001 rrr 1 10 110 xxx" for r in dataRegisters with calculation = subtractValue<32> named "SUB.L {r},MEMORY"
encoding "1001 rrr 1 10 111 00x" for r in dataRegisters with calculation = subtractValue<32> named "SUB.L {r},MEMORY"
originalSource = operand r
sourceValue = originalSource
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryLong(destinationAddress, result)
}
Capture the source Dn. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic32ModifyDataAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 111 000 rrr" for d in addressRegisters, r in dataRegisters with calculation = addAddress named "ADDA.L {r},{d}"
encoding "1001 ddd 111 000 rrr" for d in addressRegisters, r in dataRegisters with calculation = subtractAddress named "SUBA.L {r},{d}"
originalSource = operand r
sourceValue = originalSource
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Select and read the source An bank. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic32ModifyAddressAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 111 001 rrr" for d in addressRegisters, r in addressRegisters with calculation = addAddress named "ADDA.L {r},{d}"
encoding "1001 ddd 111 001 rrr" for d in addressRegisters, r in addressRegisters with calculation = subtractAddress named "SUBA.L {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = originalSource
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Read the complete data-space source. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Preserve all flags and replace all 32 destination bits.
family operandArithmetic32ModifyMemoryAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 111 01x xxx" for d in addressRegisters with calculation = addAddress named "ADDA.L MEMORY,{d}"
encoding "1101 ddd 111 10x xxx" for d in addressRegisters with calculation = addAddress named "ADDA.L MEMORY,{d}"
encoding "1101 ddd 111 110 xxx" for d in addressRegisters with calculation = addAddress named "ADDA.L MEMORY,{d}"
encoding "1101 ddd 111 111 00x" for d in addressRegisters with calculation = addAddress named "ADDA.L MEMORY,{d}"
encoding "1001 ddd 111 01x xxx" for d in addressRegisters with calculation = subtractAddress named "SUBA.L MEMORY,{d}"
encoding "1001 ddd 111 10x xxx" for d in addressRegisters with calculation = subtractAddress named "SUBA.L MEMORY,{d}"
encoding "1001 ddd 111 110 xxx" for d in addressRegisters with calculation = subtractAddress named "SUBA.L MEMORY,{d}"
encoding "1001 ddd 111 111 00x" for d in addressRegisters with calculation = subtractAddress named "SUBA.L MEMORY,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Read the complete program-space source. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Preserve all flags and replace all 32 destination bits.
family operandArithmetic32ModifyProgramAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 111 111 01x" for d in addressRegisters with calculation = addAddress named "ADDA.L PROGRAM,{d}"
encoding "1001 ddd 111 111 01x" for d in addressRegisters with calculation = subtractAddress named "SUBA.L PROGRAM,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramLong(sourceAddress)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Fetch the complete immediate. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic32ModifyImmediateAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1101 ddd 111 111 100" for d in addressRegisters with calculation = addAddress named "ADDA.L IMMEDIATE,{d}"
encoding "1001 ddd 111 111 100" for d in addressRegisters with calculation = subtractAddress named "SUBA.L IMMEDIATE,{d}"
sourceValue = source immediateLong
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Decode the positive quick amount. Read the destination after the source. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyQuickData (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 10 000 ddd" for d in dataRegisterCodes with calculation = addValue<32> named "ADDQ.L QUICK,{d}"
encoding "0101 xxx 1 10 000 ddd" for d in dataRegisterCodes with calculation = subtractValue<32> named "SUBQ.L QUICK,{d}"
sourceValue = select(zero(upperCode), u32(8), extend(upperCode, 32))
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
perform writeDataLong(registerCode, result)
}
Decode the positive quick amount. Select the destination bank, retaining it through the instruction. Read the destination after the source. Preserve all flags and replace all 32 destination bits.
family operandArithmetic32ModifyQuickAddress (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 10 001 ddd" for d in addressRegisters with calculation = addAddress named "ADDQ.L QUICK,{d}"
encoding "0101 xxx 1 10 001 ddd" for d in addressRegisters with calculation = subtractAddress named "SUBQ.L QUICK,{d}"
sourceValue = select(zero(upperCode), u32(8), extend(upperCode, 32))
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
perform writeAddressRegister(destinationBank, result)
}
Decode the positive quick amount. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyQuickMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0101 xxx 0 10 01x xxx" with calculation = addValue<32> named "ADDQ.L QUICK,MEMORY"
encoding "0101 xxx 0 10 10x xxx" with calculation = addValue<32> named "ADDQ.L QUICK,MEMORY"
encoding "0101 xxx 0 10 110 xxx" with calculation = addValue<32> named "ADDQ.L QUICK,MEMORY"
encoding "0101 xxx 0 10 111 00x" with calculation = addValue<32> named "ADDQ.L QUICK,MEMORY"
encoding "0101 xxx 1 10 01x xxx" with calculation = subtractValue<32> named "SUBQ.L QUICK,MEMORY"
encoding "0101 xxx 1 10 10x xxx" with calculation = subtractValue<32> named "SUBQ.L QUICK,MEMORY"
encoding "0101 xxx 1 10 110 xxx" with calculation = subtractValue<32> named "SUBQ.L QUICK,MEMORY"
encoding "0101 xxx 1 10 111 00x" with calculation = subtractValue<32> named "SUBQ.L QUICK,MEMORY"
sourceValue = select(zero(upperCode), u32(8), extend(upperCode, 32))
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryLong(destinationAddress, result)
}
Resolve and read the first predecrement operand. Resolve the second operand. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyPredecrementPair (mode: 3, code: 3, upperCode: 3) {
encoding "1101 xxx 1 10 00 1 xxx" with calculation = addExtended<32> named "ADDX.L MEMORY,MEMORY"
encoding "1001 xxx 1 10 00 1 xxx" with calculation = subtractExtended<32> named "SUBX.L MEMORY,MEMORY"
sourceAddress = resolve(32, u3(4), code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
destinationAddress = resolve(32, u3(4), upperCode)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryLong(destinationAddress, result)
}
Capture the source Dn. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareDataData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 10 000 rrr" for d in dataRegisterCodes, r in dataRegisters with calculation = compareValue<32> named "CMP.L {r},{d}"
originalSource = operand r
sourceValue = originalSource
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
}
Select and read the source An bank. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareAddressData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 10 001 rrr" for d in dataRegisterCodes, r in addressRegisters with calculation = compareValue<32> named "CMP.L {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = originalSource
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
}
Read the complete data-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareMemoryData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 10 01x xxx" for d in dataRegisterCodes with calculation = compareValue<32> named "CMP.L MEMORY,{d}"
encoding "1011 ddd 0 10 10x xxx" for d in dataRegisterCodes with calculation = compareValue<32> named "CMP.L MEMORY,{d}"
encoding "1011 ddd 0 10 110 xxx" for d in dataRegisterCodes with calculation = compareValue<32> named "CMP.L MEMORY,{d}"
encoding "1011 ddd 0 10 111 00x" for d in dataRegisterCodes with calculation = compareValue<32> named "CMP.L MEMORY,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
}
Read the complete program-space source. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareProgramData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 10 111 01x" for d in dataRegisterCodes with calculation = compareValue<32> named "CMP.L PROGRAM,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramLong(sourceAddress)
registerCode = operand d
commit addresses
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareImmediateData (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 0 10 111 100" for d in dataRegisterCodes with calculation = compareValue<32> named "CMPI.L IMMEDIATE,{d}"
encoding "0000 110 0 10 000 ddd" for d in dataRegisterCodes with calculation = compareValue<32> named "CMPI.L IMMEDIATE,{d}"
sourceValue = source immediateLong
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareImmediateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 110 0 10 01x xxx" with calculation = compareValue<32> named "CMPI.L IMMEDIATE,MEMORY"
encoding "0000 110 0 10 10x xxx" with calculation = compareValue<32> named "CMPI.L IMMEDIATE,MEMORY"
encoding "0000 110 0 10 110 xxx" with calculation = compareValue<32> named "CMPI.L IMMEDIATE,MEMORY"
encoding "0000 110 0 10 111 00x" with calculation = compareValue<32> named "CMPI.L IMMEDIATE,MEMORY"
sourceValue = source immediateLong
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
}
Capture the source Dn. Select the destination bank, retaining it through the instruction. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareDataAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 111 000 rrr" for d in addressRegisters, r in dataRegisters with calculation = compareValue<32> named "CMPA.L {r},{d}"
originalSource = operand r
sourceValue = originalSource
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
}
Select and read the source An bank. Select the destination bank, retaining it through the instruction. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareAddressAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 111 001 rrr" for d in addressRegisters, r in addressRegisters with calculation = compareValue<32> named "CMPA.L {r},{d}"
sourceCode = operand r
sourceBank = source selectAddressRegister(sourceCode)
originalSource = source readAddressRegister(sourceBank)
sourceValue = originalSource
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
}
Read the complete data-space source. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareMemoryAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 111 01x xxx" for d in addressRegisters with calculation = compareValue<32> named "CMPA.L MEMORY,{d}"
encoding "1011 ddd 111 10x xxx" for d in addressRegisters with calculation = compareValue<32> named "CMPA.L MEMORY,{d}"
encoding "1011 ddd 111 110 xxx" for d in addressRegisters with calculation = compareValue<32> named "CMPA.L MEMORY,{d}"
encoding "1011 ddd 111 111 00x" for d in addressRegisters with calculation = compareValue<32> named "CMPA.L MEMORY,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
}
Read the complete program-space source. Select the destination bank, retaining it through the instruction. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareProgramAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 111 111 01x" for d in addressRegisters with calculation = compareValue<32> named "CMPA.L PROGRAM,{d}"
sourceAddress = resolve(32, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readProgramLong(sourceAddress)
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
commit addresses
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
}
Fetch the complete immediate. Select the destination bank, retaining it through the instruction. Read the destination after the source. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32CompareImmediateAddress (mode: 3, code: 3, upperCode: 3) {
encoding "1011 ddd 111 111 100" for d in addressRegisters with calculation = compareValue<32> named "CMPA.L IMMEDIATE,{d}"
sourceValue = source immediateLong
registerCode = operand d
destinationBank = source selectAddressRegister(registerCode)
destination = source readAddressRegister(destinationBank)
result = source calculation(destination, sourceValue)
}
Resolve and read the first postincrement operand. Resolve the second operand. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Apply N/Z/V/C, preserve X/T/S, and omit writeback.
family operandArithmetic32ComparePostincrementPair (mode: 3, code: 3, upperCode: 3) {
encoding "1011 xxx 1 10 001 xxx" with calculation = compareValue<32> named "CMPM.L MEMORY,MEMORY"
sourceAddress = resolve(32, u3(3), code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceValue = source readMemoryLong(sourceAddress)
destinationAddress = resolve(32, u3(3), upperCode)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination, sourceValue)
}
Read the original destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyUnaryData (mode: 3, code: 3, upperCode: 3) {
encoding "0100 0100 10 000 ddd" for d in dataRegisterCodes with calculation = negateValue<32> named "NEG.L {d}"
encoding "0100 0000 10 000 ddd" for d in dataRegisterCodes with calculation = negateExtended<32> named "NEGX.L {d}"
registerCode = operand d
originalDestination = source readDataRegister(registerCode)
destination = originalDestination
result = source calculation(destination)
perform writeDataLong(registerCode, result)
}
Resolve the destination. Reject odd word/long addresses before committing updates. Commit pending addresses before reading the destination. Extended calculations capture Z then X and accumulate zero. Apply N/Z/V/C and copy carry/borrow to X before writeback. Preserve T/S.
family operandArithmetic32ModifyUnaryMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0100 0100 10 01x xxx" with calculation = negateValue<32> named "NEG.L MEMORY"
encoding "0100 0100 10 10x xxx" with calculation = negateValue<32> named "NEG.L MEMORY"
encoding "0100 0100 10 110 xxx" with calculation = negateValue<32> named "NEG.L MEMORY"
encoding "0100 0100 10 111 00x" with calculation = negateValue<32> named "NEG.L MEMORY"
encoding "0100 0000 10 01x xxx" with calculation = negateExtended<32> named "NEGX.L MEMORY"
encoding "0100 0000 10 10x xxx" with calculation = negateExtended<32> named "NEGX.L MEMORY"
encoding "0100 0000 10 110 xxx" with calculation = negateExtended<32> named "NEGX.L MEMORY"
encoding "0100 0000 10 111 00x" with calculation = negateExtended<32> named "NEGX.L MEMORY"
destinationAddress = resolve(32, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
destination = source readMemoryLong(destinationAddress)
result = source calculation(destination)
perform writeMemoryLong(destinationAddress, result)
}
Bits, shifts, and rotates
Bit operations test or change one bit, shifts move a fixed-width value, and TAS combines a byte test with setting its top bit. Their encodings keep the operation, count source, width, and destination roles visible:
| Pattern | Meaning |
|---|---|
0000 bbb 1 oo mmm rrr |
Dynamic bit number in Dbbb; oo=00/01/10/11 selects BTST/BCHG/BCLR/BSET. |
0000 1000 oo mmm rrr |
Immediate bit number in an extension word, fetched before destination extensions. |
1110 ccc d ss i tt rrr |
Register shift/rotate: d=0/1 right/left, ss=00/01/10 byte/word/long, tt=00/01/10/11 AS/LS/ROX/RO. |
1110 0 tt d 11 mmm rrr |
Shift or rotate an alterable memory word once; bit 11 remains zero on the original 68000. |
0100 1010 11 mmm rrr |
TAS on a data-alterable byte; the excluded immediate slot is ILLEGAL. |
A register shift's i=0 takes its count from ccc, with zero encoding eight;
i=1 reads Dccc and keeps its low six bits, permitting zero through 63. Capture
that register before reading the destination, even when both names are the same.
Bit numbers wrap modulo 32 for a data-register destination and modulo 8 for all
other operands. Mode 001 belongs to MOVEP, not to these bit operations.
BTST alone admits PC-relative operands. Dynamic BTST also admits an immediate
byte destination; the static form does not. Modifying bit operations and TAS
require a data register or alterable memory. All families below receive raw
mode/code/upperCode fields, as arithmetic does. The specification binds register
roles and uses the declared upperCode input for quick counts.
Testing and changing a bit
The mask sources reduce the captured bit number before shifting a single one. The result sources update only Z from the original operand and mask, then return the tested or changed value. BTST families omit writeback altogether. No bit operation reads X or changes N/V/C/X/T/S.
source bitMaskByte "one selected bit in 8 bits" (bitNumber: 8) : 8 {
mask = iterate(and(bitNumber, u8(7)), u8(1)) {
return shiftLeft(mask, 0)
}
return mask
}
policy testedBit<bits: 8, 32> "68000 tested bit" (original: bits, mask: bits) {
Z = zero(and(original, mask))
}
source testBitByte "test a selected bit and set Z" (original: 8, bitNumber: 8) : 8 {
mask = source bitMaskByte(bitNumber)
apply testedBit<8>(original, mask)
return original
}
source changeBitByte "change a selected bit and set Z" (original: 8, bitNumber: 8) : 8 {
mask = source bitMaskByte(bitNumber)
apply testedBit<8>(original, mask)
return xor(original, mask)
}
source clearBitByte "clear a selected bit and set Z" (original: 8, bitNumber: 8) : 8 {
mask = source bitMaskByte(bitNumber)
apply testedBit<8>(original, mask)
return and(original, xor(mask, u8($FF)))
}
source setBitByte "set a selected bit and set Z" (original: 8, bitNumber: 8) : 8 {
mask = source bitMaskByte(bitNumber)
apply testedBit<8>(original, mask)
return or(original, mask)
}
source bitMaskLong "one selected bit in 32 bits" (bitNumber: 8) : 32 {
mask = iterate(and(bitNumber, u8(31)), u32(1)) {
return shiftLeft(mask, 0)
}
return mask
}
source testBitLong "test a selected bit and set Z" (original: 32, bitNumber: 8) : 32 {
mask = source bitMaskLong(bitNumber)
apply testedBit<32>(original, mask)
return original
}
source changeBitLong "change a selected bit and set Z" (original: 32, bitNumber: 8) : 32 {
mask = source bitMaskLong(bitNumber)
apply testedBit<32>(original, mask)
return xor(original, mask)
}
source clearBitLong "clear a selected bit and set Z" (original: 32, bitNumber: 8) : 32 {
mask = source bitMaskLong(bitNumber)
apply testedBit<32>(original, mask)
return and(original, xor(mask, u32($FFFFFFFF)))
}
source setBitLong "set a selected bit and set Z" (original: 32, bitNumber: 8) : 32 {
mask = source bitMaskLong(bitNumber)
apply testedBit<32>(original, mask)
return or(original, mask)
}
TAS sets N/Z and clears V/C from the old byte before setting bit 7. It preserves X/T/S. The instruction-level model retains the ordered read and write; it does not model a bus arbitration lock or cycle timing.
source testAndSetByte "test the old byte then set its top bit" (original: 8) : 8 {
apply resultFlags<8>(original)
return or(original, u8($80))
}
Local shift state
Each iteration moves one bit. shifted, extendBit, carryBit, and overflowBit
are typed local values, not CPU registers or flags. Every next expression sees
the same old locals; all four updates become visible together for the next step.
Zero iterations retain the initial values. Only the final policy publishes
N/Z/V/C/X, before writeback. Capture X after the operand read, even for ordinary
rotates whose final X retains that captured value.
| Operation | Incoming bit | Outgoing bit and flag behavior |
|---|---|---|
| ASL/LSL | Zero | Old sign bit goes to C/X; ASL accumulates every sign change in V. |
| ASR | Old sign | Old low bit goes to C/X, preserving the sign through each step. |
| LSR | Zero | Old low bit goes to C/X. |
| ROXL/ROXR | Previous local X | Outgoing bit becomes both C and the next local X. |
| ROL/ROR | Outgoing bit | Outgoing bit becomes C; local X is unchanged. |
One definition per shift or rotate covers byte, word, and long operands. The shifted value follows the width parameter; the captured count remains a byte. All shifts set N/Z from the final value. Only ASL can set V; every other form clears it. At count zero, ROX copies captured X to C, the other families clear C, and all retain X and leave the numeric result unchanged. Register writeback still occurs, preserving live upper Dn bits for byte/word widths.
policy shiftFlags<bits: 8, 16, 32> "68000 shift result" (result: bits, extendBit: flag, carryBit: flag, overflowBit: flag) {
N = negative(result)
Z = zero(result)
V = overflowBit
C = carryBit
X = extendBit
}
source asr<bits: 8, 16, 32> "ASR with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = 0
overflowBit: flag = 0
step {
result = shiftRight(shifted, negative(shifted))
next shifted = result
next extendBit = lowBit(shifted)
next carryBit = lowBit(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source asl<bits: 8, 16, 32> "ASL with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = 0
overflowBit: flag = 0
step {
result = shiftLeft(shifted, 0)
next shifted = result
next extendBit = negative(shifted)
next carryBit = negative(shifted)
next overflowBit = or(overflowBit, xor(negative(shifted), negative(result)))
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source lsr<bits: 8, 16, 32> "LSR with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = 0
overflowBit: flag = 0
step {
result = shiftRight(shifted, 0)
next shifted = result
next extendBit = lowBit(shifted)
next carryBit = lowBit(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source lsl<bits: 8, 16, 32> "LSL with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = 0
overflowBit: flag = 0
step {
result = shiftLeft(shifted, 0)
next shifted = result
next extendBit = negative(shifted)
next carryBit = negative(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source roxr<bits: 8, 16, 32> "ROXR with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = initialExtend
overflowBit: flag = 0
step {
result = shiftRight(shifted, extendBit)
next shifted = result
next extendBit = lowBit(shifted)
next carryBit = lowBit(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source roxl<bits: 8, 16, 32> "ROXL with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = initialExtend
overflowBit: flag = 0
step {
result = shiftLeft(shifted, extendBit)
next shifted = result
next extendBit = negative(shifted)
next carryBit = negative(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source ror<bits: 8, 16, 32> "ROR with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = 0
overflowBit: flag = 0
step {
result = shiftRight(shifted, lowBit(shifted))
next shifted = result
next extendBit = extendBit
next carryBit = lowBit(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
source rol<bits: 8, 16, 32> "ROL with local carry, X, and overflow" (original: bits, count: 8) : bits {
initialExtend = flag X
iterate(count) {
shifted: bits = original
extendBit: flag = initialExtend
carryBit: flag = 0
overflowBit: flag = 0
step {
result = shiftLeft(shifted, negative(shifted))
next shifted = result
next extendBit = extendBit
next carryBit = negative(shifted)
next overflowBit = 0
}
}
apply shiftFlags<bits>(shifted, extendBit, carryBit, overflowBit)
return shifted
}
Bit-operation families
Capture the bit-number register or immediate extension before resolving and reading the tested operand. Memory forms commit pending address updates before the read, including PC-relative BTST. Byte operands allow odd addresses. Only Z changes; modifying forms write afterward. A failed read retains committed updates and old flags; a failed write retains Z and any completed bytes.
Capture the bit-number Dn before reading the full destination Dn. Set only Z from the original bit; omit writeback.
family operandBitsDynamicTestData (mode: 3, code: 3, upperCode: 3) {
encoding "0000 bbb 1 00 000 ddd" for b in dataRegisters, d in dataRegisterCodes with calculation = testBitLong named "BTST.L {b},{d}"
numberRegister = operand b
bitNumber = truncate(numberRegister, 8)
registerCode = operand d
original = source readDataRegister(registerCode)
result = source calculation(original, bitNumber)
}
Capture the bit-number Dn before resolving, committing updates, and reading the data byte. Set only Z from the original bit; omit writeback.
family operandBitsDynamicTestMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 bbb 1 00 01x xxx" for b in dataRegisters with calculation = testBitByte named "BTST.B {b},MEMORY"
encoding "0000 bbb 1 00 10x xxx" for b in dataRegisters with calculation = testBitByte named "BTST.B {b},MEMORY"
encoding "0000 bbb 1 00 110 xxx" for b in dataRegisters with calculation = testBitByte named "BTST.B {b},MEMORY"
encoding "0000 bbb 1 00 111 00x" for b in dataRegisters with calculation = testBitByte named "BTST.B {b},MEMORY"
numberRegister = operand b
bitNumber = truncate(numberRegister, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readMemoryByte(destinationAddress)
result = source calculation(original, bitNumber)
}
Capture the bit-number Dn before resolving, committing updates, and reading the program-space byte. Set only Z from the original bit; omit writeback.
family operandBitsDynamicTestProgram (mode: 3, code: 3, upperCode: 3) {
encoding "0000 bbb 1 00 111 01x" for b in dataRegisters with calculation = testBitByte named "BTST.B {b},PROGRAM"
numberRegister = operand b
bitNumber = truncate(numberRegister, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readProgramByte(destinationAddress)
result = source calculation(original, bitNumber)
}
Capture the bit-number Dn before fetching the tested immediate byte from a full extension word. Set only Z from the original bit; omit writeback.
family operandBitsDynamicTestImmediate (mode: 3, code: 3, upperCode: 3) {
encoding "0000 bbb 1 00 111 100" for b in dataRegisters with calculation = testBitByte named "BTST.B {b},IMMEDIATE"
numberRegister = operand b
bitNumber = truncate(numberRegister, 8)
original = source immediateByte
result = source calculation(original, bitNumber)
}
Capture the bit-number Dn before reading the full destination Dn. Set only Z from the original bit, then write the changed value.
family operandBitsDynamicModifyData (mode: 3, code: 3, upperCode: 3) {
encoding "0000 bbb 1 01 000 ddd" for b in dataRegisters, d in dataRegisterCodes with calculation = changeBitLong named "BCHG.L {b},{d}"
encoding "0000 bbb 1 10 000 ddd" for b in dataRegisters, d in dataRegisterCodes with calculation = clearBitLong named "BCLR.L {b},{d}"
encoding "0000 bbb 1 11 000 ddd" for b in dataRegisters, d in dataRegisterCodes with calculation = setBitLong named "BSET.L {b},{d}"
numberRegister = operand b
bitNumber = truncate(numberRegister, 8)
registerCode = operand d
original = source readDataRegister(registerCode)
result = source calculation(original, bitNumber)
perform writeDataLong(registerCode, result)
}
Capture the bit-number Dn before resolving, committing updates, and reading the data byte. Set only Z from the original bit, then write the changed value.
family operandBitsDynamicModifyMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 bbb 1 01 01x xxx" for b in dataRegisters with calculation = changeBitByte named "BCHG.B {b},MEMORY"
encoding "0000 bbb 1 01 10x xxx" for b in dataRegisters with calculation = changeBitByte named "BCHG.B {b},MEMORY"
encoding "0000 bbb 1 01 110 xxx" for b in dataRegisters with calculation = changeBitByte named "BCHG.B {b},MEMORY"
encoding "0000 bbb 1 01 111 00x" for b in dataRegisters with calculation = changeBitByte named "BCHG.B {b},MEMORY"
encoding "0000 bbb 1 10 01x xxx" for b in dataRegisters with calculation = clearBitByte named "BCLR.B {b},MEMORY"
encoding "0000 bbb 1 10 10x xxx" for b in dataRegisters with calculation = clearBitByte named "BCLR.B {b},MEMORY"
encoding "0000 bbb 1 10 110 xxx" for b in dataRegisters with calculation = clearBitByte named "BCLR.B {b},MEMORY"
encoding "0000 bbb 1 10 111 00x" for b in dataRegisters with calculation = clearBitByte named "BCLR.B {b},MEMORY"
encoding "0000 bbb 1 11 01x xxx" for b in dataRegisters with calculation = setBitByte named "BSET.B {b},MEMORY"
encoding "0000 bbb 1 11 10x xxx" for b in dataRegisters with calculation = setBitByte named "BSET.B {b},MEMORY"
encoding "0000 bbb 1 11 110 xxx" for b in dataRegisters with calculation = setBitByte named "BSET.B {b},MEMORY"
encoding "0000 bbb 1 11 111 00x" for b in dataRegisters with calculation = setBitByte named "BSET.B {b},MEMORY"
numberRegister = operand b
bitNumber = truncate(numberRegister, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readMemoryByte(destinationAddress)
result = source calculation(original, bitNumber)
perform writeMemoryByte(destinationAddress, result)
}
Fetch the bit-number word before reading the full destination Dn. Set only Z from the original bit; omit writeback.
family operandBitsStaticTestData (mode: 3, code: 3, upperCode: 3) {
encoding "0000 1000 00 000 ddd" for d in dataRegisterCodes with calculation = testBitLong named "BTST.L IMMEDIATE,{d}"
numberWord = fetch word
bitNumber = truncate(numberWord, 8)
registerCode = operand d
original = source readDataRegister(registerCode)
result = source calculation(original, bitNumber)
}
Fetch the bit-number word before resolving, committing updates, and reading the data byte. Set only Z from the original bit; omit writeback.
family operandBitsStaticTestMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 1000 00 01x xxx" with calculation = testBitByte named "BTST.B IMMEDIATE,MEMORY"
encoding "0000 1000 00 10x xxx" with calculation = testBitByte named "BTST.B IMMEDIATE,MEMORY"
encoding "0000 1000 00 110 xxx" with calculation = testBitByte named "BTST.B IMMEDIATE,MEMORY"
encoding "0000 1000 00 111 00x" with calculation = testBitByte named "BTST.B IMMEDIATE,MEMORY"
numberWord = fetch word
bitNumber = truncate(numberWord, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readMemoryByte(destinationAddress)
result = source calculation(original, bitNumber)
}
Fetch the bit-number word before resolving, committing updates, and reading the program-space byte. Set only Z from the original bit; omit writeback.
family operandBitsStaticTestProgram (mode: 3, code: 3, upperCode: 3) {
encoding "0000 1000 00 111 01x" with calculation = testBitByte named "BTST.B IMMEDIATE,PROGRAM"
numberWord = fetch word
bitNumber = truncate(numberWord, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readProgramByte(destinationAddress)
result = source calculation(original, bitNumber)
}
Fetch the bit-number word before reading the full destination Dn. Set only Z from the original bit, then write the changed value.
family operandBitsStaticModifyData (mode: 3, code: 3, upperCode: 3) {
encoding "0000 1000 01 000 ddd" for d in dataRegisterCodes with calculation = changeBitLong named "BCHG.L IMMEDIATE,{d}"
encoding "0000 1000 10 000 ddd" for d in dataRegisterCodes with calculation = clearBitLong named "BCLR.L IMMEDIATE,{d}"
encoding "0000 1000 11 000 ddd" for d in dataRegisterCodes with calculation = setBitLong named "BSET.L IMMEDIATE,{d}"
numberWord = fetch word
bitNumber = truncate(numberWord, 8)
registerCode = operand d
original = source readDataRegister(registerCode)
result = source calculation(original, bitNumber)
perform writeDataLong(registerCode, result)
}
Fetch the bit-number word before resolving, committing updates, and reading the data byte. Set only Z from the original bit, then write the changed value.
family operandBitsStaticModifyMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0000 1000 01 01x xxx" with calculation = changeBitByte named "BCHG.B IMMEDIATE,MEMORY"
encoding "0000 1000 01 10x xxx" with calculation = changeBitByte named "BCHG.B IMMEDIATE,MEMORY"
encoding "0000 1000 01 110 xxx" with calculation = changeBitByte named "BCHG.B IMMEDIATE,MEMORY"
encoding "0000 1000 01 111 00x" with calculation = changeBitByte named "BCHG.B IMMEDIATE,MEMORY"
encoding "0000 1000 10 01x xxx" with calculation = clearBitByte named "BCLR.B IMMEDIATE,MEMORY"
encoding "0000 1000 10 10x xxx" with calculation = clearBitByte named "BCLR.B IMMEDIATE,MEMORY"
encoding "0000 1000 10 110 xxx" with calculation = clearBitByte named "BCLR.B IMMEDIATE,MEMORY"
encoding "0000 1000 10 111 00x" with calculation = clearBitByte named "BCLR.B IMMEDIATE,MEMORY"
encoding "0000 1000 11 01x xxx" with calculation = setBitByte named "BSET.B IMMEDIATE,MEMORY"
encoding "0000 1000 11 10x xxx" with calculation = setBitByte named "BSET.B IMMEDIATE,MEMORY"
encoding "0000 1000 11 110 xxx" with calculation = setBitByte named "BSET.B IMMEDIATE,MEMORY"
encoding "0000 1000 11 111 00x" with calculation = setBitByte named "BSET.B IMMEDIATE,MEMORY"
numberWord = fetch word
bitNumber = truncate(numberWord, 8)
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readMemoryByte(destinationAddress)
result = source calculation(original, bitNumber)
perform writeMemoryByte(destinationAddress, result)
}
Shift and rotate families
All register forms capture the count before the destination. Immediate count bits are runtime parameters shared by the eight encodings of one body. Memory forms resolve a word address, reject odd alignment before committing updates, then read the old word. Both bytes must arrive before X is captured or any flag changes. Shift once and write the high byte before the low byte; a failed write retains final flags, committed updates, and completed bytes.
Decode the positive quick count before reading the 8-bit destination. Capture X, calculate using local iteration values, then apply final N/Z/V/C/X before register writeback. Preserve the live upper Dn bits.
family operandBitsShift8Quick (mode: 3, code: 3, upperCode: 3) {
encoding "1110 xxx 0 00 0 00 ddd" for d in dataRegisterCodes with calculation = asr<8> named "ASR.B QUICK,{d}"
encoding "1110 xxx 1 00 0 00 ddd" for d in dataRegisterCodes with calculation = asl<8> named "ASL.B QUICK,{d}"
encoding "1110 xxx 0 00 0 01 ddd" for d in dataRegisterCodes with calculation = lsr<8> named "LSR.B QUICK,{d}"
encoding "1110 xxx 1 00 0 01 ddd" for d in dataRegisterCodes with calculation = lsl<8> named "LSL.B QUICK,{d}"
encoding "1110 xxx 0 00 0 10 ddd" for d in dataRegisterCodes with calculation = roxr<8> named "ROXR.B QUICK,{d}"
encoding "1110 xxx 1 00 0 10 ddd" for d in dataRegisterCodes with calculation = roxl<8> named "ROXL.B QUICK,{d}"
encoding "1110 xxx 0 00 0 11 ddd" for d in dataRegisterCodes with calculation = ror<8> named "ROR.B QUICK,{d}"
encoding "1110 xxx 1 00 0 11 ddd" for d in dataRegisterCodes with calculation = rol<8> named "ROL.B QUICK,{d}"
count = select(zero(upperCode), u8(8), extend(upperCode, 8))
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = truncate(originalRegister, 8)
result = source calculation(original, count)
perform writeDataByte(registerCode, result)
}
Capture the count register and mask to six bits before reading the 8-bit destination. Capture X, calculate using local iteration values, then apply final N/Z/V/C/X before register writeback. Preserve the live upper Dn bits.
family operandBitsShift8Register (mode: 3, code: 3, upperCode: 3) {
encoding "1110 ccc 0 00 1 00 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = asr<8> named "ASR.B {c},{d}"
encoding "1110 ccc 1 00 1 00 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = asl<8> named "ASL.B {c},{d}"
encoding "1110 ccc 0 00 1 01 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = lsr<8> named "LSR.B {c},{d}"
encoding "1110 ccc 1 00 1 01 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = lsl<8> named "LSL.B {c},{d}"
encoding "1110 ccc 0 00 1 10 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = roxr<8> named "ROXR.B {c},{d}"
encoding "1110 ccc 1 00 1 10 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = roxl<8> named "ROXL.B {c},{d}"
encoding "1110 ccc 0 00 1 11 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = ror<8> named "ROR.B {c},{d}"
encoding "1110 ccc 1 00 1 11 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = rol<8> named "ROL.B {c},{d}"
countRegister = operand c
count = and(truncate(countRegister, 8), u8(63))
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = truncate(originalRegister, 8)
result = source calculation(original, count)
perform writeDataByte(registerCode, result)
}
Decode the positive quick count before reading the 16-bit destination. Capture X, calculate using local iteration values, then apply final N/Z/V/C/X before register writeback. Preserve the live upper Dn bits.
family operandBitsShift16Quick (mode: 3, code: 3, upperCode: 3) {
encoding "1110 xxx 0 01 0 00 ddd" for d in dataRegisterCodes with calculation = asr<16> named "ASR.W QUICK,{d}"
encoding "1110 xxx 1 01 0 00 ddd" for d in dataRegisterCodes with calculation = asl<16> named "ASL.W QUICK,{d}"
encoding "1110 xxx 0 01 0 01 ddd" for d in dataRegisterCodes with calculation = lsr<16> named "LSR.W QUICK,{d}"
encoding "1110 xxx 1 01 0 01 ddd" for d in dataRegisterCodes with calculation = lsl<16> named "LSL.W QUICK,{d}"
encoding "1110 xxx 0 01 0 10 ddd" for d in dataRegisterCodes with calculation = roxr<16> named "ROXR.W QUICK,{d}"
encoding "1110 xxx 1 01 0 10 ddd" for d in dataRegisterCodes with calculation = roxl<16> named "ROXL.W QUICK,{d}"
encoding "1110 xxx 0 01 0 11 ddd" for d in dataRegisterCodes with calculation = ror<16> named "ROR.W QUICK,{d}"
encoding "1110 xxx 1 01 0 11 ddd" for d in dataRegisterCodes with calculation = rol<16> named "ROL.W QUICK,{d}"
count = select(zero(upperCode), u8(8), extend(upperCode, 8))
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = truncate(originalRegister, 16)
result = source calculation(original, count)
perform writeDataWord(registerCode, result)
}
Capture the count register and mask to six bits before reading the 16-bit destination. Capture X, calculate using local iteration values, then apply final N/Z/V/C/X before register writeback. Preserve the live upper Dn bits.
family operandBitsShift16Register (mode: 3, code: 3, upperCode: 3) {
encoding "1110 ccc 0 01 1 00 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = asr<16> named "ASR.W {c},{d}"
encoding "1110 ccc 1 01 1 00 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = asl<16> named "ASL.W {c},{d}"
encoding "1110 ccc 0 01 1 01 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = lsr<16> named "LSR.W {c},{d}"
encoding "1110 ccc 1 01 1 01 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = lsl<16> named "LSL.W {c},{d}"
encoding "1110 ccc 0 01 1 10 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = roxr<16> named "ROXR.W {c},{d}"
encoding "1110 ccc 1 01 1 10 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = roxl<16> named "ROXL.W {c},{d}"
encoding "1110 ccc 0 01 1 11 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = ror<16> named "ROR.W {c},{d}"
encoding "1110 ccc 1 01 1 11 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = rol<16> named "ROL.W {c},{d}"
countRegister = operand c
count = and(truncate(countRegister, 8), u8(63))
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = truncate(originalRegister, 16)
result = source calculation(original, count)
perform writeDataWord(registerCode, result)
}
Decode the positive quick count before reading the 32-bit destination. Capture X, calculate using local iteration values, then apply final N/Z/V/C/X before register writeback.
family operandBitsShift32Quick (mode: 3, code: 3, upperCode: 3) {
encoding "1110 xxx 0 10 0 00 ddd" for d in dataRegisterCodes with calculation = asr<32> named "ASR.L QUICK,{d}"
encoding "1110 xxx 1 10 0 00 ddd" for d in dataRegisterCodes with calculation = asl<32> named "ASL.L QUICK,{d}"
encoding "1110 xxx 0 10 0 01 ddd" for d in dataRegisterCodes with calculation = lsr<32> named "LSR.L QUICK,{d}"
encoding "1110 xxx 1 10 0 01 ddd" for d in dataRegisterCodes with calculation = lsl<32> named "LSL.L QUICK,{d}"
encoding "1110 xxx 0 10 0 10 ddd" for d in dataRegisterCodes with calculation = roxr<32> named "ROXR.L QUICK,{d}"
encoding "1110 xxx 1 10 0 10 ddd" for d in dataRegisterCodes with calculation = roxl<32> named "ROXL.L QUICK,{d}"
encoding "1110 xxx 0 10 0 11 ddd" for d in dataRegisterCodes with calculation = ror<32> named "ROR.L QUICK,{d}"
encoding "1110 xxx 1 10 0 11 ddd" for d in dataRegisterCodes with calculation = rol<32> named "ROL.L QUICK,{d}"
count = select(zero(upperCode), u8(8), extend(upperCode, 8))
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = originalRegister
result = source calculation(original, count)
perform writeDataLong(registerCode, result)
}
Capture the count register and mask to six bits before reading the 32-bit destination. Capture X, calculate using local iteration values, then apply final N/Z/V/C/X before register writeback.
family operandBitsShift32Register (mode: 3, code: 3, upperCode: 3) {
encoding "1110 ccc 0 10 1 00 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = asr<32> named "ASR.L {c},{d}"
encoding "1110 ccc 1 10 1 00 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = asl<32> named "ASL.L {c},{d}"
encoding "1110 ccc 0 10 1 01 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = lsr<32> named "LSR.L {c},{d}"
encoding "1110 ccc 1 10 1 01 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = lsl<32> named "LSL.L {c},{d}"
encoding "1110 ccc 0 10 1 10 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = roxr<32> named "ROXR.L {c},{d}"
encoding "1110 ccc 1 10 1 10 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = roxl<32> named "ROXL.L {c},{d}"
encoding "1110 ccc 0 10 1 11 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = ror<32> named "ROR.L {c},{d}"
encoding "1110 ccc 1 10 1 11 ddd" for d in dataRegisterCodes, c in dataRegisters with calculation = rol<32> named "ROL.L {c},{d}"
countRegister = operand c
count = and(truncate(countRegister, 8), u8(63))
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = originalRegister
result = source calculation(original, count)
perform writeDataLong(registerCode, result)
}
Resolve the word destination and check alignment before committing updates. Read both bytes before capturing X; shift once with local flags, apply final N/Z/V/C/X, and write the high byte before the low byte. Preserve T/S.
family operandBitsShiftMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1110 0 00 0 11 01x xxx" with calculation = asr<16> named "ASR.W MEMORY"
encoding "1110 0 00 0 11 10x xxx" with calculation = asr<16> named "ASR.W MEMORY"
encoding "1110 0 00 0 11 110 xxx" with calculation = asr<16> named "ASR.W MEMORY"
encoding "1110 0 00 0 11 111 00x" with calculation = asr<16> named "ASR.W MEMORY"
encoding "1110 0 00 1 11 01x xxx" with calculation = asl<16> named "ASL.W MEMORY"
encoding "1110 0 00 1 11 10x xxx" with calculation = asl<16> named "ASL.W MEMORY"
encoding "1110 0 00 1 11 110 xxx" with calculation = asl<16> named "ASL.W MEMORY"
encoding "1110 0 00 1 11 111 00x" with calculation = asl<16> named "ASL.W MEMORY"
encoding "1110 0 01 0 11 01x xxx" with calculation = lsr<16> named "LSR.W MEMORY"
encoding "1110 0 01 0 11 10x xxx" with calculation = lsr<16> named "LSR.W MEMORY"
encoding "1110 0 01 0 11 110 xxx" with calculation = lsr<16> named "LSR.W MEMORY"
encoding "1110 0 01 0 11 111 00x" with calculation = lsr<16> named "LSR.W MEMORY"
encoding "1110 0 01 1 11 01x xxx" with calculation = lsl<16> named "LSL.W MEMORY"
encoding "1110 0 01 1 11 10x xxx" with calculation = lsl<16> named "LSL.W MEMORY"
encoding "1110 0 01 1 11 110 xxx" with calculation = lsl<16> named "LSL.W MEMORY"
encoding "1110 0 01 1 11 111 00x" with calculation = lsl<16> named "LSL.W MEMORY"
encoding "1110 0 10 0 11 01x xxx" with calculation = roxr<16> named "ROXR.W MEMORY"
encoding "1110 0 10 0 11 10x xxx" with calculation = roxr<16> named "ROXR.W MEMORY"
encoding "1110 0 10 0 11 110 xxx" with calculation = roxr<16> named "ROXR.W MEMORY"
encoding "1110 0 10 0 11 111 00x" with calculation = roxr<16> named "ROXR.W MEMORY"
encoding "1110 0 10 1 11 01x xxx" with calculation = roxl<16> named "ROXL.W MEMORY"
encoding "1110 0 10 1 11 10x xxx" with calculation = roxl<16> named "ROXL.W MEMORY"
encoding "1110 0 10 1 11 110 xxx" with calculation = roxl<16> named "ROXL.W MEMORY"
encoding "1110 0 10 1 11 111 00x" with calculation = roxl<16> named "ROXL.W MEMORY"
encoding "1110 0 11 0 11 01x xxx" with calculation = ror<16> named "ROR.W MEMORY"
encoding "1110 0 11 0 11 10x xxx" with calculation = ror<16> named "ROR.W MEMORY"
encoding "1110 0 11 0 11 110 xxx" with calculation = ror<16> named "ROR.W MEMORY"
encoding "1110 0 11 0 11 111 00x" with calculation = ror<16> named "ROR.W MEMORY"
encoding "1110 0 11 1 11 01x xxx" with calculation = rol<16> named "ROL.W MEMORY"
encoding "1110 0 11 1 11 10x xxx" with calculation = rol<16> named "ROL.W MEMORY"
encoding "1110 0 11 1 11 110 xxx" with calculation = rol<16> named "ROL.W MEMORY"
encoding "1110 0 11 1 11 111 00x" with calculation = rol<16> named "ROL.W MEMORY"
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
original = source readMemoryWord(destinationAddress)
result = source calculation(original, u8(1))
perform writeMemoryWord(destinationAddress, result)
}
Test and set families
Read the old byte, apply N/Z/V/C, then set bit 7 and write back. Dn writeback preserves its live upper bits; memory forms commit pending updates before the read. Preserve X/T/S. Failed writes retain the flags derived from the old byte.
family operandBitsTasData (mode: 3, code: 3, upperCode: 3) "0100 1010 11 000 ddd" for d in dataRegisterCodes named "TAS.B {d}" {
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
original = truncate(originalRegister, 8)
result = source testAndSetByte(original)
perform writeDataByte(registerCode, result)
}
Resolve and commit pending address updates before reading the old byte. Apply N/Z/V/C from that byte, set bit 7, and write; preserve X/T/S.
family operandBitsTasMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0100 1010 11 01x xxx" named "TAS.B MEMORY"
encoding "0100 1010 11 10x xxx" named "TAS.B MEMORY"
encoding "0100 1010 11 110 xxx" named "TAS.B MEMORY"
encoding "0100 1010 11 111 00x" named "TAS.B MEMORY"
destinationAddress = resolve(8, mode, code)
commit addresses
original = source readMemoryByte(destinationAddress)
result = source testAndSetByte(original)
perform writeMemoryByte(destinationAddress, result)
}
Word products, division, and bounds
These instructions read a word source but use Dn differently: multiplication replaces the entire register, division packs a word remainder above a word quotient, and CHK tests only its low signed word.
| Pattern | Operation | Source and destination |
|---|---|---|
1100 ddd s11 mmm rrr |
MULU/MULS | EA.W times Dddd.W gives Dddd.L; s=0/1 unsigned/signed. |
1000 ddd s11 mmm rrr |
DIVU/DIVS | Dddd.L divided by EA.W; s=0/1 unsigned/signed. |
0100 ddd 110 mmm rrr |
CHK | Test signed Dddd.W against the signed EA.W bound. |
Address-register direct sources are excluded. Data-register, memory, PC-relative program-space, and immediate sources are distinct families below. The whole source arrives before Dn is read. Odd word addresses fail before reading data, changing flags, or committing staged address updates.
Unlike read/modify/write arithmetic, these families commit source auto-updates after their result and flag effects. A zero-divisor or failed bound commits those updates before returning its named exception request. A failed source read discards pending updates. The specification event contract delivers exceptions.
Products
Multiplication uses the low destination word, retains the complete 32-bit product, and writes Dn before applying N/Z and clearing V/C. X is preserved. The signed calculation interprets both words as two's-complement integers; the resulting stored long retains the product's 32-bit representation.
source unsignedWordProduct "unsigned word product" (left: 16, right: 16) : 32 {
return multiply(left, right, unsigned)
}
source signedWordProduct "signed word product" (left: 16, right: 16) : 32 {
return multiply(left, right, signed)
}
Read the complete source register word, then the destination. Write the full product before N/Z/V/C; preserve X.
family operandWordProductData (mode: 3, code: 3, upperCode: 3) {
encoding "1100 ddd 011 000 sss" for d in dataRegisters, s in dataRegisters with calculation = unsignedWordProduct named "MULU.W {s},{d}"
encoding "1100 ddd 111 000 sss" for d in dataRegisters, s in dataRegisters with calculation = signedWordProduct named "MULS.W {s},{d}"
sourceRegister = operand s
sourceWord = truncate(sourceRegister, 16)
destinationRegister = operand d
result = source calculation(truncate(destinationRegister, 16), sourceWord)
operand d <- result
apply resultFlags<32>(result)
}
Read the complete data-memory word after checking alignment, then the destination. Write the full product before N/Z/V/C; preserve X. Commit source updates last.
family operandWordProductMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1100 ddd 011 01x xxx" for d in dataRegisters with calculation = unsignedWordProduct named "MULU.W MEMORY,{d}"
encoding "1100 ddd 011 10x xxx" for d in dataRegisters with calculation = unsignedWordProduct named "MULU.W MEMORY,{d}"
encoding "1100 ddd 011 110 xxx" for d in dataRegisters with calculation = unsignedWordProduct named "MULU.W MEMORY,{d}"
encoding "1100 ddd 011 111 00x" for d in dataRegisters with calculation = unsignedWordProduct named "MULU.W MEMORY,{d}"
encoding "1100 ddd 111 01x xxx" for d in dataRegisters with calculation = signedWordProduct named "MULS.W MEMORY,{d}"
encoding "1100 ddd 111 10x xxx" for d in dataRegisters with calculation = signedWordProduct named "MULS.W MEMORY,{d}"
encoding "1100 ddd 111 110 xxx" for d in dataRegisters with calculation = signedWordProduct named "MULS.W MEMORY,{d}"
encoding "1100 ddd 111 111 00x" for d in dataRegisters with calculation = signedWordProduct named "MULS.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readMemoryWord(sourceAddress)
destinationRegister = operand d
result = source calculation(truncate(destinationRegister, 16), sourceWord)
operand d <- result
apply resultFlags<32>(result)
commit addresses
}
Read the complete program-space word after checking alignment, then the destination. Write the full product before N/Z/V/C; preserve X. Commit source updates last.
family operandWordProductProgram (mode: 3, code: 3, upperCode: 3) {
encoding "1100 ddd 011 111 01x" for d in dataRegisters with calculation = unsignedWordProduct named "MULU.W PROGRAM,{d}"
encoding "1100 ddd 111 111 01x" for d in dataRegisters with calculation = signedWordProduct named "MULS.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readProgramWord(sourceAddress)
destinationRegister = operand d
result = source calculation(truncate(destinationRegister, 16), sourceWord)
operand d <- result
apply resultFlags<32>(result)
commit addresses
}
Read the complete immediate extension word, then the destination. Write the full product before N/Z/V/C; preserve X.
family operandWordProductImmediate (mode: 3, code: 3, upperCode: 3) {
encoding "1100 ddd 011 111 100" for d in dataRegisters with calculation = unsignedWordProduct named "MULU.W IMMEDIATE,{d}"
encoding "1100 ddd 111 111 100" for d in dataRegisters with calculation = signedWordProduct named "MULS.W IMMEDIATE,{d}"
sourceWord = fetch word
destinationRegister = operand d
result = source calculation(truncate(destinationRegister, 16), sourceWord)
operand d <- result
apply resultFlags<32>(result)
}
Quotients and remainders
Clear C before examining the captured divisor. Zero requests divide-by-zero
without reading Dn, preserving N/Z/V/X. Otherwise, signed division truncates
toward zero and the remainder has the dividend's sign.
The third division result is a local Boolean, not an architectural flag.
quotientOverflow separates a nonzero divisor's oversized quotient from the
zero-divisor outcome. Overflow sets V and preserves Dn/N/Z/X. Success writes
remainder:quotient, then derives N/Z from the quotient and clears V/C.
The full signed range −32768 through 32767 is accepted. Both completed paths
commit source updates after their result/flag effects.
policy divisionCarry "68000 division carry" () {
C = 0
}
policy divisionOverflow "68000 division overflow" () {
V = 1
}
Read the data source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. An unsigned quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X.
family operandWordDivuData (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 011 000 sss" for d in dataRegisters, s in dataRegisters named "DIVU.W {s},{d}"
sourceRegister = operand s
sourceWord = truncate(sourceRegister, 16)
apply divisionCarry()
when zero(sourceWord) {
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, unsigned) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
}
Read the memory source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. An unsigned quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X. Commit source updates before a zero-divisor request, or after all successful/overflow effects.
family operandWordDivuMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 011 01x xxx" for d in dataRegisters named "DIVU.W MEMORY,{d}"
encoding "1000 ddd 011 10x xxx" for d in dataRegisters named "DIVU.W MEMORY,{d}"
encoding "1000 ddd 011 110 xxx" for d in dataRegisters named "DIVU.W MEMORY,{d}"
encoding "1000 ddd 011 111 00x" for d in dataRegisters named "DIVU.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readMemoryWord(sourceAddress)
apply divisionCarry()
when zero(sourceWord) {
commit addresses
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, unsigned) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
commit addresses
}
Read the program source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. An unsigned quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X. Commit source updates before a zero-divisor request, or after all successful/overflow effects.
family operandWordDivuProgram (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 011 111 01x" for d in dataRegisters named "DIVU.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readProgramWord(sourceAddress)
apply divisionCarry()
when zero(sourceWord) {
commit addresses
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, unsigned) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
commit addresses
}
Read the immediate source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. An unsigned quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X.
family operandWordDivuImmediate (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 011 111 100" for d in dataRegisters named "DIVU.W IMMEDIATE,{d}"
sourceWord = fetch word
apply divisionCarry()
when zero(sourceWord) {
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, unsigned) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
}
Read the data source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. A signed quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X.
family operandWordDivsData (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 111 000 sss" for d in dataRegisters, s in dataRegisters named "DIVS.W {s},{d}"
sourceRegister = operand s
sourceWord = truncate(sourceRegister, 16)
apply divisionCarry()
when zero(sourceWord) {
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, signed) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
}
Read the memory source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. A signed quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X. Commit source updates before a zero-divisor request, or after all successful/overflow effects.
family operandWordDivsMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 111 01x xxx" for d in dataRegisters named "DIVS.W MEMORY,{d}"
encoding "1000 ddd 111 10x xxx" for d in dataRegisters named "DIVS.W MEMORY,{d}"
encoding "1000 ddd 111 110 xxx" for d in dataRegisters named "DIVS.W MEMORY,{d}"
encoding "1000 ddd 111 111 00x" for d in dataRegisters named "DIVS.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readMemoryWord(sourceAddress)
apply divisionCarry()
when zero(sourceWord) {
commit addresses
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, signed) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
commit addresses
}
Read the program source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. A signed quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X. Commit source updates before a zero-divisor request, or after all successful/overflow effects.
family operandWordDivsProgram (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 111 111 01x" for d in dataRegisters named "DIVS.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readProgramWord(sourceAddress)
apply divisionCarry()
when zero(sourceWord) {
commit addresses
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, signed) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
commit addresses
}
Read the immediate source word. Clear C before testing for zero, which requests divide-by-zero without reading Dn. A signed quotient overflow sets only V; success writes remainder:quotient before N/Z/V/C. Preserve X.
family operandWordDivsImmediate (mode: 3, code: 3, upperCode: 3) {
encoding "1000 ddd 111 111 100" for d in dataRegisters named "DIVS.W IMMEDIATE,{d}"
sourceWord = fetch word
apply divisionCarry()
when zero(sourceWord) {
reject "divide-by-zero"
}
dividend = operand d
quotient, remainder, quotientOverflow = divide(dividend, sourceWord, signed) otherwise "divide-by-zero"
when quotientOverflow {
apply divisionOverflow()
}
when not(quotientOverflow) {
operand d <- concat(remainder, quotient)
apply resultFlags<16>(quotient)
}
}
Signed bounds
CHK accepts a tested word from zero through the signed bound, inclusive, and
preserves all flags on success. A negative tested word fails with N set; a
nonnegative word above the bound fails with N clear. A negative bound accepts
nothing. On failure, preserve Z/V/C/X and request bounds-check after committing
any staged source updates. The explicit sign tests keep the unsigned borrow
comparison meaningful for the remaining nonnegative words.
policy failedBound "68000 failed bound" (tested: 16) {
N = negative(tested)
}
Read the data bound word before the destination. Accept a nonnegative tested word no greater than the signed bound without flag changes. Otherwise set N from the tested sign, preserve Z/V/C/X, and request bounds-check.
family operandWordBoundsData (mode: 3, code: 3, upperCode: 3) {
encoding "0100 ddd 110 000 sss" for d in dataRegisters, s in dataRegisters named "CHK.W {s},{d}"
sourceRegister = operand s
sourceWord = truncate(sourceRegister, 16)
original = operand d
tested = truncate(original, 16)
when or(negative(tested), lessThan(sourceWord, tested, signed)) {
apply failedBound(tested)
reject "bounds-check"
}
}
Read the memory bound word before the destination. Accept a nonnegative tested word no greater than the signed bound without flag changes. Otherwise set N from the tested sign, preserve Z/V/C/X, and request bounds-check. Commit source updates on either completed path, before requesting an exception.
family operandWordBoundsMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0100 ddd 110 01x xxx" for d in dataRegisters named "CHK.W MEMORY,{d}"
encoding "0100 ddd 110 10x xxx" for d in dataRegisters named "CHK.W MEMORY,{d}"
encoding "0100 ddd 110 110 xxx" for d in dataRegisters named "CHK.W MEMORY,{d}"
encoding "0100 ddd 110 111 00x" for d in dataRegisters named "CHK.W MEMORY,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readMemoryWord(sourceAddress)
original = operand d
tested = truncate(original, 16)
when or(negative(tested), lessThan(sourceWord, tested, signed)) {
apply failedBound(tested)
commit addresses
reject "bounds-check"
}
commit addresses
}
Read the program bound word before the destination. Accept a nonnegative tested word no greater than the signed bound without flag changes. Otherwise set N from the tested sign, preserve Z/V/C/X, and request bounds-check. Commit source updates on either completed path, before requesting an exception.
family operandWordBoundsProgram (mode: 3, code: 3, upperCode: 3) {
encoding "0100 ddd 110 111 01x" for d in dataRegisters named "CHK.W PROGRAM,{d}"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
sourceWord = source readProgramWord(sourceAddress)
original = operand d
tested = truncate(original, 16)
when or(negative(tested), lessThan(sourceWord, tested, signed)) {
apply failedBound(tested)
commit addresses
reject "bounds-check"
}
commit addresses
}
Read the immediate bound word before the destination. Accept a nonnegative tested word no greater than the signed bound without flag changes. Otherwise set N from the tested sign, preserve Z/V/C/X, and request bounds-check.
family operandWordBoundsImmediate (mode: 3, code: 3, upperCode: 3) {
encoding "0100 ddd 110 111 100" for d in dataRegisters named "CHK.W IMMEDIATE,{d}"
sourceWord = fetch word
original = operand d
tested = truncate(original, 16)
when or(negative(tested), lessThan(sourceWord, tested, signed)) {
apply failedBound(tested)
reject "bounds-check"
}
}
Packed decimal arithmetic
ABCD and SBCD add or subtract two packed decimal bytes with X as incoming carry/borrow. NBCD subtracts one byte and X from zero. Each nibble represents one decimal digit. Correct the low digit first, carry its carry/borrow into the high digit, and combine the corrected nibbles.
| Pattern | Operation and operands |
|---|---|
1100 ddd 10000 m rrr |
ABCD; m=0 Drrr,Dddd, m=1 −(Arrr),−(Addd). |
1000 ddd 10000 m rrr |
SBCD, with the same register or paired-predecrement selection. |
0100 1000 00 mmm rrr |
NBCD on a data register or alterable memory byte. |
Capture X after reading both operands. Set C then X from the high digit's carry/borrow. Only then read the previous Z and retain it if this result is zero, allowing a multi-byte calculation to accumulate zero. Preserve N/V/T/S. Flags precede destination writeback, even when the numeric result is unchanged. The model applies the same deterministic correction to non-decimal nibbles; these invalid-digit results are a model choice, not a portable software contract.
Digit correction and flags
policy decimalCarry "68000 decimal carry" (carry: flag) {
C = carry
X = carry
}
policy decimalZero "68000 decimal zero" (previous: flag, result: 8) {
Z = and(previous, zero(result))
}
Add six to a digit sum above nine. Retain four corrected bits, feed the low carry/borrow into the high calculation, and publish final C/X before reading cumulative Z.
source addDecimal "add packed decimal digits" (left: 8, right: 8) : 8 {
incoming = flag X
leftLow = and(left, u8(15))
rightLow = and(right, u8(15))
rawLow = add(leftLow, rightLow, incoming)
digitLow = and(select(not(lessThan(rawLow, u8(10), unsigned)), add(rawLow, u8(6)), rawLow), u8(15))
leftHigh = and(shiftBits(left, right, 4), u8(15))
rightHigh = and(shiftBits(right, right, 4), u8(15))
rawHigh = add(leftHigh, rightHigh, not(lessThan(rawLow, u8(10), unsigned)))
digitHigh = and(select(not(lessThan(rawHigh, u8(10), unsigned)), add(rawHigh, u8(6)), rawHigh), u8(15))
result = or(shiftBits(digitHigh, left, 4), digitLow)
apply decimalCarry(not(lessThan(rawHigh, u8(10), unsigned)))
previousZero = flag Z
apply decimalZero(previousZero, result)
return result
}
Subtract six when a digit subtraction borrows. Retain four corrected bits, feed the low carry/borrow into the high calculation, and publish final C/X before reading cumulative Z.
source subtractDecimal "subtract packed decimal digits" (left: 8, right: 8) : 8 {
incoming = flag X
leftLow = and(left, u8(15))
rightLow = and(right, u8(15))
rawLow = subtract(leftLow, rightLow, incoming)
digitLow = and(select(borrow(leftLow, rightLow, incoming), subtract(rawLow, u8(6)), rawLow), u8(15))
leftHigh = and(shiftBits(left, right, 4), u8(15))
rightHigh = and(shiftBits(right, right, 4), u8(15))
rawHigh = subtract(leftHigh, rightHigh, borrow(leftLow, rightLow, incoming))
digitHigh = and(select(borrow(leftHigh, rightHigh, borrow(leftLow, rightLow, incoming)), subtract(rawHigh, u8(6)), rawHigh), u8(15))
result = or(shiftBits(digitHigh, left, 4), digitLow)
apply decimalCarry(borrow(leftHigh, rightHigh, borrow(leftLow, rightLow, incoming)))
previousZero = flag Z
apply decimalZero(previousZero, result)
return result
}
Decimal operand families
Paired memory forms resolve and read the source before resolving the destination.
Both predecrements use mode 100, irrespective of the single encoded m bit.
Two uses of the same An therefore decrement twice; A7 steps by two per byte in
its selected stack bank. Commit all pending updates before reading the destination.
A failed source read discards updates. A failed destination read retains committed
updates, and a failed write also retains the new flags.
Read the source byte before the destination byte. Capture X, correct both digits, publish C/X and cumulative Z, then write the result while preserving live upper Dn bits.
family operandDecimalPairData (mode: 3, code: 3, upperCode: 3) {
encoding "1100 ddd 10000 0 sss" for d in dataRegisterCodes, s in dataRegisters with calculation = addDecimal named "ABCD {s},{d}"
encoding "1000 ddd 10000 0 sss" for d in dataRegisterCodes, s in dataRegisters with calculation = subtractDecimal named "SBCD {s},{d}"
sourceRegister = operand s
sourceValue = truncate(sourceRegister, 8)
registerCode = operand d
destinationRegister = source readDataRegister(registerCode)
destination = truncate(destinationRegister, 8)
result = source calculation(destination, sourceValue)
perform writeDataByte(registerCode, result)
}
Resolve and read the source predecrement byte, then resolve the destination predecrement. Commit pending updates before reading the destination. Capture X, correct both digits, publish C/X and cumulative Z, then write the byte; preserve N/V/T/S.
family operandDecimalPairMemory (mode: 3, code: 3, upperCode: 3) {
encoding "1100 xxx 10000 1 xxx" with calculation = addDecimal named "ABCD MEMORY,MEMORY"
encoding "1000 xxx 10000 1 xxx" with calculation = subtractDecimal named "SBCD MEMORY,MEMORY"
sourceAddress = resolve(8, u3(4), code)
sourceValue = source readMemoryByte(sourceAddress)
destinationAddress = resolve(8, u3(4), upperCode)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source calculation(destination, sourceValue)
perform writeMemoryByte(destinationAddress, result)
}
Read the original byte, then subtract it and X from zero using decimal correction. Publish C/X and cumulative Z before writeback; preserve N/V/T/S and live upper Dn bits.
family operandDecimalNegateData (mode: 3, code: 3, upperCode: 3) {
encoding "0100 1000 00 000 ddd" for d in dataRegisterCodes named "NBCD {d}"
registerCode = operand d
originalRegister = source readDataRegister(registerCode)
destination = truncate(originalRegister, 8)
result = source subtractDecimal(u8(0), destination)
perform writeDataByte(registerCode, result)
}
Resolve the byte destination and commit updates before its read. Subtract that byte and X from zero using decimal correction. Publish C/X and cumulative Z before writing the byte; preserve N/V/T/S.
family operandDecimalNegateMemory (mode: 3, code: 3, upperCode: 3) {
encoding "0100 1000 00 01x xxx" named "NBCD MEMORY"
encoding "0100 1000 00 10x xxx" named "NBCD MEMORY"
encoding "0100 1000 00 110 xxx" named "NBCD MEMORY"
encoding "0100 1000 00 111 00x" named "NBCD MEMORY"
destinationAddress = resolve(8, mode, code)
commit addresses
destination = source readMemoryByte(destinationAddress)
result = source subtractDecimal(u8(0), destination)
perform writeMemoryByte(destinationAddress, result)
}
Conditions and control flow
The control instructions distinguish three addresses: the stored PC, the sequential fetch cursor, and a selected target for retirement. Reading the cursor neither fetches memory nor changes the target. Selecting a target does not move the cursor. The core commits a selected target only when the instruction completes; the specification decides when to validate it and when to stack a return address. All address arithmetic wraps at 32 bits.
| Pattern | Meaning |
|---|---|
0101 cccc 11 mmm rrr |
Scc on a data-alterable byte; mmm=001 instead selects DBcc Drrr. |
0110 cccc dddddddd |
BRA for cccc=0000, BSR for 0001, otherwise Bcc. A zero displacement byte fetches a signed word; $FF means −1. |
0100 aaa 111 mmm rrr |
LEA of a control address into Aaaa. |
0100 1000 01 mmm rrr |
PEA, stacking the control address itself. |
0100 1110 10 mmm rrr / 0100 1110 11 mmm rrr |
JSR / JMP to a control address. |
0100 1110 0101 u rrr |
LINK for u=0, UNLK for u=1. |
0100 1110 0111 0101 |
RTS. |
Control addresses allow (An), displacement, index, absolute, and PC-relative
forms. They calculate an address without reading its contents. LEA and PEA
can therefore carry odd addresses; taken jumps and returns require even
targets.
Condition evaluation
In cccc=tttp, ttt chooses T, HI, CC, NE, VC, PL, GE, or GT, and p=1
inverts that test. T/F read no flags. Compound conditions capture C then Z,
N then V, or N then V then Z, including when an earlier flag already determines
the answer. These sources return Boolean decisions while preserving every flag.
source conditionT "68000 T condition" : flag {
return 1
}
source conditionF "68000 F condition" : flag {
return 0
}
source conditionHI "68000 HI condition" : flag {
c = flag C
z = flag Z
return not(or(c, z))
}
source conditionLS "68000 LS condition" : flag {
c = flag C
z = flag Z
return or(c, z)
}
source conditionCC "68000 CC condition" : flag {
c = flag C
return not(c)
}
source conditionCS "68000 CS condition" : flag {
c = flag C
return c
}
source conditionNE "68000 NE condition" : flag {
z = flag Z
return not(z)
}
source conditionEQ "68000 EQ condition" : flag {
z = flag Z
return z
}
source conditionVC "68000 VC condition" : flag {
v = flag V
return not(v)
}
source conditionVS "68000 VS condition" : flag {
v = flag V
return v
}
source conditionPL "68000 PL condition" : flag {
n = flag N
return not(n)
}
source conditionMI "68000 MI condition" : flag {
n = flag N
return n
}
source conditionGE "68000 GE condition" : flag {
n = flag N
v = flag V
return not(xor(n, v))
}
source conditionLT "68000 LT condition" : flag {
n = flag N
v = flag V
return xor(n, v)
}
source conditionGT "68000 GT condition" : flag {
n = flag N
v = flag V
z = flag Z
return and(not(z), not(xor(n, v)))
}
source conditionLE "68000 LE condition" : flag {
n = flag N
v = flag V
z = flag Z
return or(z, xor(n, v))
}
Setting a byte and decrementing a counter
Scc resolves and reads its destination before capturing the condition. Memory
auto-updates commit before that read. It writes $FF for true and zero for
false,
even if unchanged; register writes preserve the live upper 24 bits. DBcc
instead
captures the condition before its displacement word. A true condition leaves Dn
untouched. Otherwise decrement its low word; $FFFF falls through. A taken
DBcc
checks and selects its target before writing the counter, preserving live upper
bits. Both instructions preserve all flags.
Read Dn before testing the condition, then write the result byte while preserving its live upper bits. Preserve every flag.
family operandControlSetData (mode: 3, code: 3, displacement: 8) {
encoding "0101 0000 11 000 ddd" for d in dataRegisterCodes with condition = conditionT named "ST {d}"
encoding "0101 0001 11 000 ddd" for d in dataRegisterCodes with condition = conditionF named "SF {d}"
encoding "0101 0010 11 000 ddd" for d in dataRegisterCodes with condition = conditionHI named "SHI {d}"
encoding "0101 0011 11 000 ddd" for d in dataRegisterCodes with condition = conditionLS named "SLS {d}"
encoding "0101 0100 11 000 ddd" for d in dataRegisterCodes with condition = conditionCC named "SCC {d}"
encoding "0101 0101 11 000 ddd" for d in dataRegisterCodes with condition = conditionCS named "SCS {d}"
encoding "0101 0110 11 000 ddd" for d in dataRegisterCodes with condition = conditionNE named "SNE {d}"
encoding "0101 0111 11 000 ddd" for d in dataRegisterCodes with condition = conditionEQ named "SEQ {d}"
encoding "0101 1000 11 000 ddd" for d in dataRegisterCodes with condition = conditionVC named "SVC {d}"
encoding "0101 1001 11 000 ddd" for d in dataRegisterCodes with condition = conditionVS named "SVS {d}"
encoding "0101 1010 11 000 ddd" for d in dataRegisterCodes with condition = conditionPL named "SPL {d}"
encoding "0101 1011 11 000 ddd" for d in dataRegisterCodes with condition = conditionMI named "SMI {d}"
encoding "0101 1100 11 000 ddd" for d in dataRegisterCodes with condition = conditionGE named "SGE {d}"
encoding "0101 1101 11 000 ddd" for d in dataRegisterCodes with condition = conditionLT named "SLT {d}"
encoding "0101 1110 11 000 ddd" for d in dataRegisterCodes with condition = conditionGT named "SGT {d}"
encoding "0101 1111 11 000 ddd" for d in dataRegisterCodes with condition = conditionLE named "SLE {d}"
registerCode = operand d
previous = source readDataRegister(registerCode)
tested = source condition
result = select(tested, u8($FF), u8(0))
perform writeDataByte(registerCode, result)
}
Resolve the byte destination, commit updates, and read its old byte before testing the condition. Always write the resulting byte, preserving every flag.
family operandControlSetMemory (mode: 3, code: 3, displacement: 8) {
encoding "0101 0000 11 01x xxx" with condition = conditionT named "ST MEMORY"
encoding "0101 0000 11 10x xxx" with condition = conditionT named "ST MEMORY"
encoding "0101 0000 11 110 xxx" with condition = conditionT named "ST MEMORY"
encoding "0101 0000 11 111 00x" with condition = conditionT named "ST MEMORY"
encoding "0101 0001 11 01x xxx" with condition = conditionF named "SF MEMORY"
encoding "0101 0001 11 10x xxx" with condition = conditionF named "SF MEMORY"
encoding "0101 0001 11 110 xxx" with condition = conditionF named "SF MEMORY"
encoding "0101 0001 11 111 00x" with condition = conditionF named "SF MEMORY"
encoding "0101 0010 11 01x xxx" with condition = conditionHI named "SHI MEMORY"
encoding "0101 0010 11 10x xxx" with condition = conditionHI named "SHI MEMORY"
encoding "0101 0010 11 110 xxx" with condition = conditionHI named "SHI MEMORY"
encoding "0101 0010 11 111 00x" with condition = conditionHI named "SHI MEMORY"
encoding "0101 0011 11 01x xxx" with condition = conditionLS named "SLS MEMORY"
encoding "0101 0011 11 10x xxx" with condition = conditionLS named "SLS MEMORY"
encoding "0101 0011 11 110 xxx" with condition = conditionLS named "SLS MEMORY"
encoding "0101 0011 11 111 00x" with condition = conditionLS named "SLS MEMORY"
encoding "0101 0100 11 01x xxx" with condition = conditionCC named "SCC MEMORY"
encoding "0101 0100 11 10x xxx" with condition = conditionCC named "SCC MEMORY"
encoding "0101 0100 11 110 xxx" with condition = conditionCC named "SCC MEMORY"
encoding "0101 0100 11 111 00x" with condition = conditionCC named "SCC MEMORY"
encoding "0101 0101 11 01x xxx" with condition = conditionCS named "SCS MEMORY"
encoding "0101 0101 11 10x xxx" with condition = conditionCS named "SCS MEMORY"
encoding "0101 0101 11 110 xxx" with condition = conditionCS named "SCS MEMORY"
encoding "0101 0101 11 111 00x" with condition = conditionCS named "SCS MEMORY"
encoding "0101 0110 11 01x xxx" with condition = conditionNE named "SNE MEMORY"
encoding "0101 0110 11 10x xxx" with condition = conditionNE named "SNE MEMORY"
encoding "0101 0110 11 110 xxx" with condition = conditionNE named "SNE MEMORY"
encoding "0101 0110 11 111 00x" with condition = conditionNE named "SNE MEMORY"
encoding "0101 0111 11 01x xxx" with condition = conditionEQ named "SEQ MEMORY"
encoding "0101 0111 11 10x xxx" with condition = conditionEQ named "SEQ MEMORY"
encoding "0101 0111 11 110 xxx" with condition = conditionEQ named "SEQ MEMORY"
encoding "0101 0111 11 111 00x" with condition = conditionEQ named "SEQ MEMORY"
encoding "0101 1000 11 01x xxx" with condition = conditionVC named "SVC MEMORY"
encoding "0101 1000 11 10x xxx" with condition = conditionVC named "SVC MEMORY"
encoding "0101 1000 11 110 xxx" with condition = conditionVC named "SVC MEMORY"
encoding "0101 1000 11 111 00x" with condition = conditionVC named "SVC MEMORY"
encoding "0101 1001 11 01x xxx" with condition = conditionVS named "SVS MEMORY"
encoding "0101 1001 11 10x xxx" with condition = conditionVS named "SVS MEMORY"
encoding "0101 1001 11 110 xxx" with condition = conditionVS named "SVS MEMORY"
encoding "0101 1001 11 111 00x" with condition = conditionVS named "SVS MEMORY"
encoding "0101 1010 11 01x xxx" with condition = conditionPL named "SPL MEMORY"
encoding "0101 1010 11 10x xxx" with condition = conditionPL named "SPL MEMORY"
encoding "0101 1010 11 110 xxx" with condition = conditionPL named "SPL MEMORY"
encoding "0101 1010 11 111 00x" with condition = conditionPL named "SPL MEMORY"
encoding "0101 1011 11 01x xxx" with condition = conditionMI named "SMI MEMORY"
encoding "0101 1011 11 10x xxx" with condition = conditionMI named "SMI MEMORY"
encoding "0101 1011 11 110 xxx" with condition = conditionMI named "SMI MEMORY"
encoding "0101 1011 11 111 00x" with condition = conditionMI named "SMI MEMORY"
encoding "0101 1100 11 01x xxx" with condition = conditionGE named "SGE MEMORY"
encoding "0101 1100 11 10x xxx" with condition = conditionGE named "SGE MEMORY"
encoding "0101 1100 11 110 xxx" with condition = conditionGE named "SGE MEMORY"
encoding "0101 1100 11 111 00x" with condition = conditionGE named "SGE MEMORY"
encoding "0101 1101 11 01x xxx" with condition = conditionLT named "SLT MEMORY"
encoding "0101 1101 11 10x xxx" with condition = conditionLT named "SLT MEMORY"
encoding "0101 1101 11 110 xxx" with condition = conditionLT named "SLT MEMORY"
encoding "0101 1101 11 111 00x" with condition = conditionLT named "SLT MEMORY"
encoding "0101 1110 11 01x xxx" with condition = conditionGT named "SGT MEMORY"
encoding "0101 1110 11 10x xxx" with condition = conditionGT named "SGT MEMORY"
encoding "0101 1110 11 110 xxx" with condition = conditionGT named "SGT MEMORY"
encoding "0101 1110 11 111 00x" with condition = conditionGT named "SGT MEMORY"
encoding "0101 1111 11 01x xxx" with condition = conditionLE named "SLE MEMORY"
encoding "0101 1111 11 10x xxx" with condition = conditionLE named "SLE MEMORY"
encoding "0101 1111 11 110 xxx" with condition = conditionLE named "SLE MEMORY"
encoding "0101 1111 11 111 00x" with condition = conditionLE named "SLE MEMORY"
destinationAddress = resolve(8, mode, code)
commit addresses
previous = source readMemoryByte(destinationAddress)
tested = source condition
result = select(tested, u8($FF), u8(0))
perform writeMemoryByte(destinationAddress, result)
}
Capture the condition before fetching the displacement. On a false condition, decrement only the low word; validate a taken target before changing Dn.
family operandControlDecrement (mode: 3, code: 3, displacement: 8) {
encoding "0101 0000 11 001 ddd" for d in dataRegisterCodes with condition = conditionT named "DBT {d},label"
encoding "0101 0001 11 001 ddd" for d in dataRegisterCodes with condition = conditionF named "DBF {d},label"
encoding "0101 0010 11 001 ddd" for d in dataRegisterCodes with condition = conditionHI named "DBHI {d},label"
encoding "0101 0011 11 001 ddd" for d in dataRegisterCodes with condition = conditionLS named "DBLS {d},label"
encoding "0101 0100 11 001 ddd" for d in dataRegisterCodes with condition = conditionCC named "DBCC {d},label"
encoding "0101 0101 11 001 ddd" for d in dataRegisterCodes with condition = conditionCS named "DBCS {d},label"
encoding "0101 0110 11 001 ddd" for d in dataRegisterCodes with condition = conditionNE named "DBNE {d},label"
encoding "0101 0111 11 001 ddd" for d in dataRegisterCodes with condition = conditionEQ named "DBEQ {d},label"
encoding "0101 1000 11 001 ddd" for d in dataRegisterCodes with condition = conditionVC named "DBVC {d},label"
encoding "0101 1001 11 001 ddd" for d in dataRegisterCodes with condition = conditionVS named "DBVS {d},label"
encoding "0101 1010 11 001 ddd" for d in dataRegisterCodes with condition = conditionPL named "DBPL {d},label"
encoding "0101 1011 11 001 ddd" for d in dataRegisterCodes with condition = conditionMI named "DBMI {d},label"
encoding "0101 1100 11 001 ddd" for d in dataRegisterCodes with condition = conditionGE named "DBGE {d},label"
encoding "0101 1101 11 001 ddd" for d in dataRegisterCodes with condition = conditionLT named "DBLT {d},label"
encoding "0101 1110 11 001 ddd" for d in dataRegisterCodes with condition = conditionGT named "DBGT {d},label"
encoding "0101 1111 11 001 ddd" for d in dataRegisterCodes with condition = conditionLE named "DBLE {d},label"
tested = source condition
base = next address
offset = fetch word
target = add(base, signExtend(offset, 32))
when not(tested) {
registerCode = operand d
counter = source readDataRegister(registerCode)
result = subtract(truncate(counter, 16), u16(1))
when not(equal(result, u16($FFFF))) {
fault alignment fetch(target) if lowBit(target)
select target(target)
}
perform writeDataWord(registerCode, result)
}
}
Branches and subroutine calls
Branches capture their condition before reading the sequential cursor or an extension word. The displacement is relative to the cursor before that extension, not the cursor after it. An untaken branch never validates its target. BSR always calls: capture the return cursor after any extension, then select the active stack bank. Check the decremented stack address before the target, select the target before writing the return long, and commit the original stack bank only after all four writes succeed. Callback changes to S cannot redirect that commit.
Capture the condition and pre-extension cursor. Sign-extend the nonzero displacement byte. Only a taken branch validates and selects its target; preserve all flags and registers.
family operandControlBranchByte (mode: 3, code: 3, displacement: 8) {
encoding "0110 0000 xxxxxxxx" with condition = conditionT named "BRA.B label" except "0110 0000 00000000"
encoding "0110 0010 xxxxxxxx" with condition = conditionHI named "BHI.B label" except "0110 0010 00000000"
encoding "0110 0011 xxxxxxxx" with condition = conditionLS named "BLS.B label" except "0110 0011 00000000"
encoding "0110 0100 xxxxxxxx" with condition = conditionCC named "BCC.B label" except "0110 0100 00000000"
encoding "0110 0101 xxxxxxxx" with condition = conditionCS named "BCS.B label" except "0110 0101 00000000"
encoding "0110 0110 xxxxxxxx" with condition = conditionNE named "BNE.B label" except "0110 0110 00000000"
encoding "0110 0111 xxxxxxxx" with condition = conditionEQ named "BEQ.B label" except "0110 0111 00000000"
encoding "0110 1000 xxxxxxxx" with condition = conditionVC named "BVC.B label" except "0110 1000 00000000"
encoding "0110 1001 xxxxxxxx" with condition = conditionVS named "BVS.B label" except "0110 1001 00000000"
encoding "0110 1010 xxxxxxxx" with condition = conditionPL named "BPL.B label" except "0110 1010 00000000"
encoding "0110 1011 xxxxxxxx" with condition = conditionMI named "BMI.B label" except "0110 1011 00000000"
encoding "0110 1100 xxxxxxxx" with condition = conditionGE named "BGE.B label" except "0110 1100 00000000"
encoding "0110 1101 xxxxxxxx" with condition = conditionLT named "BLT.B label" except "0110 1101 00000000"
encoding "0110 1110 xxxxxxxx" with condition = conditionGT named "BGT.B label" except "0110 1110 00000000"
encoding "0110 1111 xxxxxxxx" with condition = conditionLE named "BLE.B label" except "0110 1111 00000000"
tested = source condition
base = next address
target = add(base, signExtend(displacement, 32))
when tested {
fault alignment fetch(target) if lowBit(target)
select target(target)
}
}
Sign-extend the nonzero displacement byte from the captured cursor. Capture the return cursor, check the stack before the target, select the target, push the return long, and commit the captured stack bank.
family operandControlCallByte (mode: 3, code: 3, displacement: 8) {
encoding "0110 0001 xxxxxxxx" named "BSR.B label" except "0110 0001 00000000"
base = next address
target = add(base, signExtend(displacement, 32))
returnAddress = next address
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
stackAddress = subtract(stack, u32(4))
fault alignment write(stackAddress) if lowBit(stackAddress)
fault alignment fetch(target) if lowBit(target)
select target(target)
perform writeMemoryLong(stackAddress, returnAddress)
perform writeAddressRegister(stackBank, stackAddress)
}
Capture the condition and pre-extension cursor. Fetch and sign-extend the displacement word. Only a taken branch validates and selects its target; preserve all flags and registers.
family operandControlBranchWord (mode: 3, code: 3, displacement: 8) {
encoding "0110 0000 00000000" with condition = conditionT named "BRA.W label"
encoding "0110 0010 00000000" with condition = conditionHI named "BHI.W label"
encoding "0110 0011 00000000" with condition = conditionLS named "BLS.W label"
encoding "0110 0100 00000000" with condition = conditionCC named "BCC.W label"
encoding "0110 0101 00000000" with condition = conditionCS named "BCS.W label"
encoding "0110 0110 00000000" with condition = conditionNE named "BNE.W label"
encoding "0110 0111 00000000" with condition = conditionEQ named "BEQ.W label"
encoding "0110 1000 00000000" with condition = conditionVC named "BVC.W label"
encoding "0110 1001 00000000" with condition = conditionVS named "BVS.W label"
encoding "0110 1010 00000000" with condition = conditionPL named "BPL.W label"
encoding "0110 1011 00000000" with condition = conditionMI named "BMI.W label"
encoding "0110 1100 00000000" with condition = conditionGE named "BGE.W label"
encoding "0110 1101 00000000" with condition = conditionLT named "BLT.W label"
encoding "0110 1110 00000000" with condition = conditionGT named "BGT.W label"
encoding "0110 1111 00000000" with condition = conditionLE named "BLE.W label"
tested = source condition
base = next address
offset = fetch word
target = add(base, signExtend(offset, 32))
when tested {
fault alignment fetch(target) if lowBit(target)
select target(target)
}
}
Fetch the displacement word after capturing its base cursor. Capture the return cursor, check the stack before the target, select the target, push the return long, and commit the captured stack bank.
family operandControlCallWord (mode: 3, code: 3, displacement: 8) {
encoding "0110 0001 00000000" named "BSR.W label"
base = next address
offset = fetch word
target = add(base, signExtend(offset, 32))
returnAddress = next address
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
stackAddress = subtract(stack, u32(4))
fault alignment write(stackAddress) if lowBit(stackAddress)
fault alignment fetch(target) if lowBit(target)
select target(target)
perform writeMemoryLong(stackAddress, returnAddress)
perform writeAddressRegister(stackBank, stackAddress)
}
Control addresses and frames
LEA selects its destination register bank before resolving the source. PEA selects the active stack after resolving the source, checks stack alignment, and pushes the address without validating it as a target. JSR captures the return cursor after all EA extensions and follows BSR's stack-before-target validation and delayed stack commit. JMP validates and selects the resolved target directly.
Select the destination register bank before resolving the control address. Write that complete address without a data read or alignment check.
family operandControlLea (mode: 3, code: 3, displacement: 8) {
encoding "0100 aaa 111 010 xxx" for a in addressRegisters named "LEA control EA,{a}"
encoding "0100 aaa 111 101 xxx" for a in addressRegisters named "LEA control EA,{a}"
encoding "0100 aaa 111 110 xxx" for a in addressRegisters named "LEA control EA,{a}"
encoding "0100 aaa 111 111 0xx" for a in addressRegisters named "LEA control EA,{a}"
registerCode = operand a
destinationBank = source selectAddressRegister(registerCode)
target = resolve(32, mode, code)
perform writeAddressRegister(destinationBank, target)
}
Resolve the control address before selecting the stack bank. Check the decremented stack, push the address high byte first, then commit the captured pointer.
family operandControlPea (mode: 3, code: 3, displacement: 8) {
encoding "0100 1000 01 010 xxx" named "PEA control EA"
encoding "0100 1000 01 101 xxx" named "PEA control EA"
encoding "0100 1000 01 110 xxx" named "PEA control EA"
encoding "0100 1000 01 111 0xx" named "PEA control EA"
target = resolve(32, mode, code)
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
stackAddress = subtract(stack, u32(4))
fault alignment write(stackAddress) if lowBit(stackAddress)
perform writeMemoryLong(stackAddress, target)
perform writeAddressRegister(stackBank, stackAddress)
}
Resolve the address and capture the return cursor. Check stack alignment before target alignment; select the target before stacking and commit the original stack bank after all writes.
family operandControlJsr (mode: 3, code: 3, displacement: 8) {
encoding "0100 1110 10 010 xxx" named "JSR control EA"
encoding "0100 1110 10 101 xxx" named "JSR control EA"
encoding "0100 1110 10 110 xxx" named "JSR control EA"
encoding "0100 1110 10 111 0xx" named "JSR control EA"
target = resolve(32, mode, code)
returnAddress = next address
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
stackAddress = subtract(stack, u32(4))
fault alignment write(stackAddress) if lowBit(stackAddress)
fault alignment fetch(target) if lowBit(target)
select target(target)
perform writeMemoryLong(stackAddress, returnAddress)
perform writeAddressRegister(stackBank, stackAddress)
}
Resolve the control address, validate its alignment, and select it as the target. Do not read target memory or change the sequential cursor.
family operandControlJmp (mode: 3, code: 3, displacement: 8) {
encoding "0100 1110 11 010 xxx" named "JMP control EA"
encoding "0100 1110 11 101 xxx" named "JMP control EA"
encoding "0100 1110 11 110 xxx" named "JMP control EA"
encoding "0100 1110 11 111 0xx" named "JMP control EA"
target = resolve(32, mode, code)
fault alignment fetch(target) if lowBit(target)
select target(target)
}
LINK fetches its signed allocation word first, selects the frame register's identity, and then selects the active stack bank. Check stack alignment before reading the saved register. LINK A7 saves the decremented stack address itself. After all writes succeed, set the frame register, then apply the allocation to the captured stack address. UNLK reads the saved long through the frame register before updating either register: advance the captured stack bank, then restore the frame register. Consequently UNLK A7 leaves the popped value in SP.
RTS captures the active stack, reads the complete return long, and validates and selects its target before advancing that captured stack by four. Failed reads or an odd target preserve the pointer. All these operations preserve every flag.
Fetch the allocation before selecting either register identity. After checking stack alignment, save the frame value, write the new frame pointer, and allocate from the captured stack address. LINK A7 saves the decremented pointer.
family operandControlLink (mode: 3, code: 3, displacement: 8) {
encoding "0100 1110 0101 0 rrr" for r in addressRegisters named "LINK {r},#allocation"
allocation = fetch word
frameCode = operand r
frameBank = source selectAddressRegister(frameCode)
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
stackAddress = subtract(stack, u32(4))
fault alignment write(stackAddress) if lowBit(stackAddress)
saved = choose equal(frameCode, u3(7)) : 32 {
then {
return stackAddress
}
else {
original = source readAddressRegister(frameBank)
return original
}
}
perform writeMemoryLong(stackAddress, saved)
perform writeAddressRegister(frameBank, stackAddress)
perform writeAddressRegister(stackBank, add(stackAddress, signExtend(allocation, 32)))
}
Select the frame register before the stack bank. Read the complete saved long before advancing the captured stack and restoring the frame register; preserve flags.
family operandControlUnlink (mode: 3, code: 3, displacement: 8) {
encoding "0100 1110 0101 1 rrr" for r in addressRegisters named "UNLK {r}"
frameCode = operand r
frameBank = source selectAddressRegister(frameCode)
stackBank = source selectAddressRegister(u3(7))
frameAddress = source readAddressRegister(frameBank)
fault alignment read(frameAddress) if lowBit(frameAddress)
saved = source readMemoryLong(frameAddress)
perform writeAddressRegister(stackBank, add(frameAddress, u32(4)))
perform writeAddressRegister(frameBank, saved)
}
Capture the active stack and read the complete return long. Validate and select the target before advancing the captured pointer; preserve flags.
family operandControlReturn (mode: 3, code: 3, displacement: 8) {
encoding "0100 1110 0111 0101" named "RTS"
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
fault alignment read(stack) if lowBit(stack)
target = source readMemoryLong(stack)
fault alignment fetch(target) if lowBit(target)
select target(target)
perform writeAddressRegister(stackBank, add(stack, u32(4)))
}
Peripheral and multiple-register transfers
MOVEP and MOVEM both preserve every flag, but describe different bus sequences. MOVEP moves a word or long through alternate byte addresses; MOVEM traverses a register mask and transfers complete registers consecutively. Neither performs an ALU destination read before a store.
MOVEP: alternate byte addresses
0000 ddd 1 t s 001 aaa selects Dddd, Aaaa, direction t (zero loads Dn),
and size s (zero word, one long). Capture An before fetching the signed
16-bit displacement. Read or write high byte first at alternate addresses,
wrapping each logical address at 32 bits. Odd addresses are legal. Stores read
Dn after fetching the displacement; loads replace Dn only after every byte
arrives. A word load preserves its live upper word.
source readPeripheralWord "read alternate bytes of a 16-bit value" (address: 32) : 16 {
byte0 = memory(address)
byte1 = memory(add(address, u32(2)))
return concat(byte0, byte1)
}
action writePeripheralWord "write alternate bytes of a 16-bit value" (address: 32, contents: 16) using memory {
memory(address) <- bits(contents, 15, 8)
memory(add(address, u32(2))) <- truncate(contents, 8)
}
Capture the address register before fetching the displacement. Transfer high byte first at alternate addresses; odd addresses are legal. Read every byte before writing Dn, preserving its live upper word for a word load. Preserve every flag.
family operandTransferPeripheralWordLoad (mode: 3, code: 3) {
encoding "0000 ddd 1 0 0 001 aaa" for d in dataRegisterCodes, a in addressRegisters named "MOVEP.W (d,{a}),{d}"
registerCode = operand d
baseCode = operand a
baseBank = source selectAddressRegister(baseCode)
base = source readAddressRegister(baseBank)
displacementWord = fetch word
address = add(base, signExtend(displacementWord, 32))
result = source readPeripheralWord(address)
perform writeDataWord(registerCode, result)
}
Capture the address register before fetching the displacement. Transfer high byte first at alternate addresses; odd addresses are legal. Read Dn after the fetch, then write the bytes without destination reads. Preserve every flag.
family operandTransferPeripheralWordStore (mode: 3, code: 3) {
encoding "0000 ddd 1 1 0 001 aaa" for d in dataRegisterCodes, a in addressRegisters named "MOVEP.W {d},(d,{a})"
registerCode = operand d
baseCode = operand a
baseBank = source selectAddressRegister(baseCode)
base = source readAddressRegister(baseBank)
displacementWord = fetch word
address = add(base, signExtend(displacementWord, 32))
original = source readDataRegister(registerCode)
perform writePeripheralWord(address, truncate(original, 16))
}
source readPeripheralLong "read alternate bytes of a 32-bit value" (address: 32) : 32 {
byte0 = memory(address)
byte1 = memory(add(address, u32(2)))
byte2 = memory(add(address, u32(4)))
byte3 = memory(add(address, u32(6)))
return concat(concat(byte0, byte1), concat(byte2, byte3))
}
action writePeripheralLong "write alternate bytes of a 32-bit value" (address: 32, contents: 32) using memory {
memory(address) <- bits(contents, 31, 24)
memory(add(address, u32(2))) <- bits(contents, 23, 16)
memory(add(address, u32(4))) <- bits(contents, 15, 8)
memory(add(address, u32(6))) <- truncate(contents, 8)
}
Capture the address register before fetching the displacement. Transfer high byte first at alternate addresses; odd addresses are legal. Read every byte before writing Dn, preserving its live upper word for a word load. Preserve every flag.
family operandTransferPeripheralLongLoad (mode: 3, code: 3) {
encoding "0000 ddd 1 0 1 001 aaa" for d in dataRegisterCodes, a in addressRegisters named "MOVEP.L (d,{a}),{d}"
registerCode = operand d
baseCode = operand a
baseBank = source selectAddressRegister(baseCode)
base = source readAddressRegister(baseBank)
displacementWord = fetch word
address = add(base, signExtend(displacementWord, 32))
result = source readPeripheralLong(address)
perform writeDataLong(registerCode, result)
}
Capture the address register before fetching the displacement. Transfer high byte first at alternate addresses; odd addresses are legal. Read Dn after the fetch, then write the bytes without destination reads. Preserve every flag.
family operandTransferPeripheralLongStore (mode: 3, code: 3) {
encoding "0000 ddd 1 1 1 001 aaa" for d in dataRegisterCodes, a in addressRegisters named "MOVEP.L {d},(d,{a})"
registerCode = operand d
baseCode = operand a
baseBank = source selectAddressRegister(baseCode)
base = source readAddressRegister(baseBank)
displacementWord = fetch word
address = add(base, signExtend(displacementWord, 32))
original = source readDataRegister(registerCode)
perform writePeripheralLong(address, original)
}
MOVEM: register mask and order
0100 1 d 00 1 s mmm rrr selects direction, size, and effective address.
d=0 stores; d=1 loads. Fetch the register mask before any EA extensions.
Normal order is D0 through D7, then A0 through A7. Predecrement stores reverse
both register order and mask interpretation: bit zero selects A7 and bit
fifteen
selects D0. An empty list still resolves EA extensions, but checks no alignment
and updates no base. Otherwise check the first transfer's alignment before
accessing any listed register or memory byte.
Capture each source and select each A7 bank at its own turn. Loads select that register identity before reading its bytes and write it only when the complete value arrives. Word loads sign-extend to all 32 bits. PC-relative loads use program space. Stores read the live register at its turn; storing the base register sees its original value. Earlier successful transfers survive failures.
The following internal storage number extends D0–D7 with A0–A6, USP, and SSP. Selecting A7 reads S at the selected register's turn. This number is a local binding, not another hardware register.
source selectTransferRegister "select a MOVEM register's storage" (index: 8) : 8 {
selected = choose lessThan(index, u8(8), unsigned) : 8 {
then {
return index
}
else {
addressCode = truncate(subtract(index, u8(8)), 3)
bank = source selectAddressRegister(addressCode)
return add(u8(8), bank)
}
}
return selected
}
source readTransferRegister "read selected MOVEM storage" (selected: 8) : 32 {
contents = match selected : 32 {
case "00000rrr" for r in dataRegisters {
original = operand r
return original
}
case "00001rrr" for r in addressStorage {
original = operand r
return original
}
case "00010000" {
original = register SSP
return original
}
otherwise unsupported
}
return contents
}
action writeTransferRegister "write selected MOVEM storage" (selected: 8, contents: 32) {
match selected {
case "00000rrr" for r in dataRegisters {
operand r <- contents
}
case "00001rrr" for r in addressStorage {
operand r <- contents
}
case "00010000" {
SSP <- contents
}
otherwise unsupported
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Resolve the control EA once, including for an empty list. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleWordStoreMemory (mode: 3, code: 3) {
encoding "0100 1 0 00 1 0 010 xxx" named "MOVEM.W list,MEMORY"
encoding "0100 1 0 00 1 0 101 xxx" named "MOVEM.W list,MEMORY"
encoding "0100 1 0 00 1 0 110 xxx" named "MOVEM.W list,MEMORY"
encoding "0100 1 0 00 1 0 111 00x" named "MOVEM.W list,MEMORY"
mask = fetch word
initialAddress = resolve(32, mode, code)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment write(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(2)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
original = source readTransferRegister(storage)
perform writeMemoryWord(address, truncate(original, 16))
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
}
}
Predecrement stores use reversed register order and subtract before each selected transfer. Commit the captured base bank after the whole list succeeds; a postincrement update wins over a loaded base. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleWordStorePredecrement (mode: 3, code: 3) {
encoding "0100 1 0 00 1 0 100 rrr" for r in addressRegisters named "MOVEM.W list,-({r})"
mask = fetch word
baseCode = operand r
baseBank = source selectAddressRegister(baseCode)
initialAddress = source readAddressRegister(baseBank)
when not(zero(mask)) {
firstAddress = subtract(initialAddress, u32(2))
fault alignment write(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), subtract(address, u32(2)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(subtract(u8(15), registerIndex))
original = source readTransferRegister(storage)
perform writeMemoryWord(followingAddress, truncate(original, 16))
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
perform writeAddressRegister(baseBank, address)
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Resolve the control EA once, including for an empty list. Word loads sign-extend into the complete register. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleWordLoadMemory (mode: 3, code: 3) {
encoding "0100 1 1 00 1 0 010 xxx" named "MOVEM.W MEMORY,list"
encoding "0100 1 1 00 1 0 101 xxx" named "MOVEM.W MEMORY,list"
encoding "0100 1 1 00 1 0 110 xxx" named "MOVEM.W MEMORY,list"
encoding "0100 1 1 00 1 0 111 00x" named "MOVEM.W MEMORY,list"
mask = fetch word
initialAddress = resolve(32, mode, code)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment read(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(2)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
result = source readMemoryWord(address)
perform writeTransferRegister(storage, signExtend(result, 32))
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Commit the captured base bank after the whole list succeeds; a postincrement update wins over a loaded base. Word loads sign-extend into the complete register. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleWordLoadPostincrement (mode: 3, code: 3) {
encoding "0100 1 1 00 1 0 011 rrr" for r in addressRegisters named "MOVEM.W ({r})+,list"
mask = fetch word
baseCode = operand r
baseBank = source selectAddressRegister(baseCode)
initialAddress = source readAddressRegister(baseBank)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment read(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(2)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
result = source readMemoryWord(address)
perform writeTransferRegister(storage, signExtend(result, 32))
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
perform writeAddressRegister(baseBank, address)
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Resolve the control EA once, including for an empty list. Word loads sign-extend into the complete register. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleWordLoadProgram (mode: 3, code: 3) {
encoding "0100 1 1 00 1 0 111 01x" named "MOVEM.W PROGRAM,list"
mask = fetch word
initialAddress = resolve(32, mode, code)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment program read(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(2)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
result = source readProgramWord(address)
perform writeTransferRegister(storage, signExtend(result, 32))
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Resolve the control EA once, including for an empty list. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleLongStoreMemory (mode: 3, code: 3) {
encoding "0100 1 0 00 1 1 010 xxx" named "MOVEM.L list,MEMORY"
encoding "0100 1 0 00 1 1 101 xxx" named "MOVEM.L list,MEMORY"
encoding "0100 1 0 00 1 1 110 xxx" named "MOVEM.L list,MEMORY"
encoding "0100 1 0 00 1 1 111 00x" named "MOVEM.L list,MEMORY"
mask = fetch word
initialAddress = resolve(32, mode, code)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment write(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(4)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
original = source readTransferRegister(storage)
perform writeMemoryLong(address, original)
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
}
}
Predecrement stores use reversed register order and subtract before each selected transfer. Commit the captured base bank after the whole list succeeds; a postincrement update wins over a loaded base. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleLongStorePredecrement (mode: 3, code: 3) {
encoding "0100 1 0 00 1 1 100 rrr" for r in addressRegisters named "MOVEM.L list,-({r})"
mask = fetch word
baseCode = operand r
baseBank = source selectAddressRegister(baseCode)
initialAddress = source readAddressRegister(baseBank)
when not(zero(mask)) {
firstAddress = subtract(initialAddress, u32(4))
fault alignment write(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), subtract(address, u32(4)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(subtract(u8(15), registerIndex))
original = source readTransferRegister(storage)
perform writeMemoryLong(followingAddress, original)
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
perform writeAddressRegister(baseBank, address)
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Resolve the control EA once, including for an empty list. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleLongLoadMemory (mode: 3, code: 3) {
encoding "0100 1 1 00 1 1 010 xxx" named "MOVEM.L MEMORY,list"
encoding "0100 1 1 00 1 1 101 xxx" named "MOVEM.L MEMORY,list"
encoding "0100 1 1 00 1 1 110 xxx" named "MOVEM.L MEMORY,list"
encoding "0100 1 1 00 1 1 111 00x" named "MOVEM.L MEMORY,list"
mask = fetch word
initialAddress = resolve(32, mode, code)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment read(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(4)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
result = source readMemoryLong(address)
perform writeTransferRegister(storage, result)
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Commit the captured base bank after the whole list succeeds; a postincrement update wins over a loaded base. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleLongLoadPostincrement (mode: 3, code: 3) {
encoding "0100 1 1 00 1 1 011 rrr" for r in addressRegisters named "MOVEM.L ({r})+,list"
mask = fetch word
baseCode = operand r
baseBank = source selectAddressRegister(baseCode)
initialAddress = source readAddressRegister(baseBank)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment read(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(4)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
result = source readMemoryLong(address)
perform writeTransferRegister(storage, result)
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
perform writeAddressRegister(baseBank, address)
}
}
Visit selected registers in normal order, advancing only for a selected transfer. Resolve the control EA once, including for an empty list. An empty list captures its address but performs no alignment check or transfer. Preserve every flag; failed transfers retain earlier complete registers and written bytes.
family operandTransferMultipleLongLoadProgram (mode: 3, code: 3) {
encoding "0100 1 1 00 1 1 111 01x" named "MOVEM.L PROGRAM,list"
mask = fetch word
initialAddress = resolve(32, mode, code)
when not(zero(mask)) {
firstAddress = initialAddress
fault alignment program read(firstAddress) if lowBit(firstAddress)
iterate(u8(16)) {
remaining: 16 = mask
registerIndex: 8 = u8(0)
address: 32 = initialAddress
step {
selected = and(remaining, u16(1))
followingAddress = select(not(zero(selected)), add(address, u32(4)), address)
when not(zero(selected)) {
storage = source selectTransferRegister(registerIndex)
result = source readProgramLong(address)
perform writeTransferRegister(storage, result)
}
next remaining = shiftBits(remaining, right, 1)
next registerIndex = add(registerIndex, u8(1))
next address = followingAddress
}
}
}
}
Status and system instructions
These instructions separate instruction effects from exception delivery. A privilege check reads S before any operand access. A rejected instruction returns a named reason: the execution contract chooses its vector, saved PC, and tracing policy; generated entry constructs the frame and handles nested faults. The instruction itself does not silently perform that delivery.
| Pattern | Meaning |
|---|---|
0000 ooo0 0 f 111100 |
Immediate CCR/SR logic; ooo=000/001/101 means OR/AND/XOR, f=1 selects privileged SR. |
0100 0 ff0 11 mmm rrr |
ff=00 SR to data-alterable EA, 10 EA to CCR, 11 EA to privileged SR; 01 is absent on the original chip. |
0100 1110 0110 d rrr |
An to USP for d=0, USP to An for d=1; both privileged. |
0100 1110 0111 0xxx |
RESET, NOP, STOP, RTE, reserved, RTS, TRAPV, RTR. |
0100 1110 0100 vvvv |
TRAP; the exception declaration adds the low nibble to vector 32. |
0100 1010 1111 1100 |
ILLEGAL. |
1010 xxxx xxxx xxxx / 1111 xxxx xxxx xxxx |
Software emulator lines A and F. |
Immediate status logic
Capture old packed SR before fetching the complete immediate word, even for CCR. Apply the chosen operation to that capture, ignoring reserved bits on restoration. CCR preserves T, S, and the live interrupt mask. SR restores X/N/Z/V/C first, then T/S and the interrupt mask. Check SR privilege before both status capture and operand fetch.
Capture packed SR before fetching the immediate word. Restore the calculated condition codes while preserving live system flags and the interrupt mask.
family operandSystemImmediateCCR (mode: 3, code: 3) {
encoding "0000 0000 0 0 111100" with calculation = orValue<16> named "ORI #n,CCR"
encoding "0000 0010 0 0 111100" with calculation = andValue<16> named "ANDI #n,CCR"
encoding "0000 1010 0 0 111100" with calculation = eorValue<16> named "EORI #n,CCR"
status = source SR
immediate = fetch word
result = source calculation(status, immediate)
perform writeCCR(result)
}
Check privilege and capture old SR before fetching the immediate word. Restore the calculated status, including system flags and the interrupt mask.
family operandSystemImmediateSR (mode: 3, code: 3) {
encoding "0000 0000 0 1 111100" with calculation = orValue<16> named "ORI #n,SR"
encoding "0000 0010 0 1 111100" with calculation = andValue<16> named "ANDI #n,SR"
encoding "0000 1010 0 1 111100" with calculation = eorValue<16> named "EORI #n,SR"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
status = source SR
immediate = fetch word
result = source calculation(status, immediate)
perform writeSR(result)
}
Moving status and USP
MOVE from SR is unprivileged on the original 68000. Resolve and align a memory destination, commit its auto-updates, and read its old word before capturing SR. Write the captured status word, preserving live upper Dn bits. Source-to-status moves instead read the complete word and restore status before committing staged address updates. Those updates retain their original stack bank even if S changes. A failed source leaves both status and pending updates untouched.
Read the destination register before capturing SR. Write the status word while preserving its live upper word; this instruction is unprivileged on the original chip.
family operandSystemFromStatusData (mode: 3, code: 3) {
encoding "0100 0000 11 000 ddd" for d in dataRegisterCodes named "MOVE SR,{d}"
registerCode = operand d
previous = source readDataRegister(registerCode)
status = source SR
perform writeDataWord(registerCode, status)
}
Resolve and align the destination, commit updates, and read its old word before capturing SR. Write the status high byte first, retaining completed effects on failure.
family operandSystemFromStatusMemory (mode: 3, code: 3) {
encoding "0100 0000 11 01x xxx" named "MOVE SR,MEMORY"
encoding "0100 0000 11 10x xxx" named "MOVE SR,MEMORY"
encoding "0100 0000 11 110 xxx" named "MOVE SR,MEMORY"
encoding "0100 0000 11 111 00x" named "MOVE SR,MEMORY"
destinationAddress = resolve(16, mode, code)
fault alignment read(destinationAddress) if lowBit(destinationAddress)
commit addresses
previous = source readMemoryWord(destinationAddress)
status = source SR
perform writeMemoryWord(destinationAddress, status)
}
Read the complete source word without a privilege check. Restore only the condition codes before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToCCRData (mode: 3, code: 3) {
encoding "0100 0100 11 000 rrr" for r in dataRegisters named "MOVE {r},CCR"
original = operand r
status = truncate(original, 16)
perform writeCCR(status)
}
Read the complete source word without a privilege check. Restore only the condition codes before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToCCRMemory (mode: 3, code: 3) {
encoding "0100 0100 11 01x xxx" named "MOVE MEMORY,CCR"
encoding "0100 0100 11 10x xxx" named "MOVE MEMORY,CCR"
encoding "0100 0100 11 110 xxx" named "MOVE MEMORY,CCR"
encoding "0100 0100 11 111 00x" named "MOVE MEMORY,CCR"
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
status = source readMemoryWord(sourceAddress)
perform writeCCR(status)
commit addresses
}
Read the complete source word without a privilege check. Restore only the condition codes before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToCCRProgram (mode: 3, code: 3) {
encoding "0100 0100 11 111 01x" named "MOVE PROGRAM,CCR"
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
status = source readProgramWord(sourceAddress)
perform writeCCR(status)
commit addresses
}
Read the complete source word without a privilege check. Restore only the condition codes before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToCCRImmediate (mode: 3, code: 3) {
encoding "0100 0100 11 111 100" named "MOVE IMMEDIATE,CCR"
status = fetch word
perform writeCCR(status)
}
Check privilege before reading the source word. Restore full SR before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToSRData (mode: 3, code: 3) {
encoding "0100 0110 11 000 rrr" for r in dataRegisters named "MOVE {r},SR"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
original = operand r
status = truncate(original, 16)
perform writeSR(status)
}
Check privilege before reading the source word. Restore full SR before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToSRMemory (mode: 3, code: 3) {
encoding "0100 0110 11 01x xxx" named "MOVE MEMORY,SR"
encoding "0100 0110 11 10x xxx" named "MOVE MEMORY,SR"
encoding "0100 0110 11 110 xxx" named "MOVE MEMORY,SR"
encoding "0100 0110 11 111 00x" named "MOVE MEMORY,SR"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
sourceAddress = resolve(16, mode, code)
fault alignment read(sourceAddress) if lowBit(sourceAddress)
status = source readMemoryWord(sourceAddress)
perform writeSR(status)
commit addresses
}
Check privilege before reading the source word. Restore full SR before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToSRProgram (mode: 3, code: 3) {
encoding "0100 0110 11 111 01x" named "MOVE PROGRAM,SR"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
sourceAddress = resolve(16, mode, code)
fault alignment program read(sourceAddress) if lowBit(sourceAddress)
status = source readProgramWord(sourceAddress)
perform writeSR(status)
commit addresses
}
Check privilege before reading the source word. Restore full SR before committing any staged source-address updates, retaining their original stack bank. A failed source leaves status unchanged.
family operandSystemToSRImmediate (mode: 3, code: 3) {
encoding "0100 0110 11 111 100" named "MOVE IMMEDIATE,SR"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
status = fetch word
perform writeSR(status)
}
USP transfers check privilege before selecting An's identity. Capture the complete source before writing the destination; A7 selects the current stack bank, normally SSP after the privilege check. Preserve every flag.
Check privilege, select and read the address register, then write USP. Preserve every flag.
family operandSystemToUserStack (mode: 3, code: 3) {
encoding "0100 1110 0110 0 rrr" for r in addressRegisters named "MOVE {r},USP"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
registerCode = operand r
addressBank = source selectAddressRegister(registerCode)
contents = source readAddressRegister(addressBank)
USP <- contents
}
Check privilege, select the address-register identity, then read USP and write the captured destination. Preserve every flag.
family operandSystemFromUserStack (mode: 3, code: 3) {
encoding "0100 1110 0110 1 rrr" for r in addressRegisters named "MOVE USP,{r}"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
registerCode = operand r
addressBank = source selectAddressRegister(registerCode)
contents = register USP
perform writeAddressRegister(addressBank, contents)
}
Returns, stopping, and device reset
RTE checks privilege, captures SSP, and reads PC high, SR, then PC low from that original supervisor stack. RTR captures the active stack and reads CCR before the complete PC long. Both reject odd stack addresses before reading, then validate and select the target before advancing the captured pointer by six and restoring status. Neither a failed read nor an odd target changes the pointer or status. Restoring S never redirects reads already in progress.
STOP checks privilege, fetches a complete status word, restores SR, then halts. RESET checks privilege before asserting the device reset connection; the core records a successful signal, while callback failure stops retirement. NOP has no effects after opcode fetching. TRAPV requests delivery only when V is set.
Check privilege and capture SSP. Read PC high, SR, then PC low. Validate and select the target before advancing SSP and restoring the captured status.
family operandSystemReturnException (mode: 3, code: 3) {
encoding "0100 1110 0111 0011" named "RTE"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
stack = register SSP
fault alignment read(stack) if lowBit(stack)
high = source readMemoryWord(add(stack, u32(2)))
status = source readMemoryWord(stack)
low = source readMemoryWord(add(stack, u32(4)))
target = concat(high, low)
fault alignment fetch(target) if lowBit(target)
select target(target)
SSP <- add(stack, u32(6))
perform writeSR(status)
}
Capture the active stack, read CCR then the PC long, and validate the target. Advance the original stack bank before restoring condition codes; preserve system status.
family operandSystemReturnCondition (mode: 3, code: 3) {
encoding "0100 1110 0111 0111" named "RTR"
stackBank = source selectAddressRegister(u3(7))
stack = source readAddressRegister(stackBank)
fault alignment read(stack) if lowBit(stack)
status = source readMemoryWord(stack)
target = source readMemoryLong(add(stack, u32(2)))
fault alignment fetch(target) if lowBit(target)
select target(target)
perform writeAddressRegister(stackBank, add(stack, u32(6)))
perform writeCCR(status)
}
Check privilege before signaling device reset. A failed callback prevents later effects and successful-reset recording; preserve CPU state.
family operandSystemReset (mode: 3, code: 3) {
encoding "0100 1110 0111 0000" named "RESET"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
reset devices
}
Complete without effects after opcode fetching.
family operandSystemNop (mode: 3, code: 3) {
encoding "0100 1110 0111 0001" named "NOP"
}
Check privilege before fetching status. Restore SR completely before entering the halted state.
family operandSystemStop (mode: 3, code: 3) {
encoding "0100 1110 0111 0010" named "STOP"
supervisor = flag S
reject "privilege-violation" if not(supervisor)
status = fetch word
perform writeSR(status)
HALTED <- 1
}
Read V and request overflow-trap delivery only when set, preserving every register and flag.
family operandSystemTrapv (mode: 3, code: 3) {
encoding "0100 1110 0111 0110" named "TRAPV"
overflow = flag V
reject "overflow-trap" if overflow
}
TRAP, ILLEGAL, and the two software emulator lines return their named reason without changing state in the body. The execution contract below owns vector selection and saved-PC rules; the generated boundary delivers the requested frame. All sixteen TRAP literals and every low-bit pattern on lines A/F share those rules; these literals do not add documented instruction forms to the coverage denominator.
Request illegal-instruction delivery; vector selection and frame entry belong to the CPU boundary.
family operandSystemIllegal (mode: 3, code: 3) {
encoding "0100 1010 1111 1100" named "ILLEGAL"
reject "illegal-instruction"
}
Request trap delivery; the CPU boundary uses the opcode literal to select the vector and owns frame entry.
family operandSystemTrap (mode: 3, code: 3) {
encoding "0100 1110 0100 xxxx" named "TRAP #n"
reject "trap"
}
Request line-A software-emulator delivery without instruction-body state changes.
family operandSystemLineA (mode: 3, code: 3) {
encoding "1010 xxxx xxxx xxxx" named "LINE_A"
reject "line-a"
}
Request line-F software-emulator delivery without instruction-body state changes.
family operandSystemLineF (mode: 3, code: 3) {
encoding "1111 xxxx xxxx xxxx" named "LINE_F"
reject "line-f"
}
Exception frames and external events
Synchronous exception entry and return
step() includes the triggering instruction and its synchronous exception in
one transition. It reports outcome: "executed" on successful delivery and
adds exception: { source, vector, returnPc } to the record. This lets the
runner continue through a handler. No handler opcode is fetched during entry.
Restarting exceptions save the full faulting address; RTE with an unchanged frame retries that word. Software handlers must adjust the saved PC to skip it.
TRAPV with V=0 advances PC without entering an exception. TRAP, TRAPV, ILLEGAL, other illegal encodings, emulator lines, and privilege violations preserve all condition codes. CHK and division apply the flag and completed-source effects described above before saving SR.
RTE requires supervisor mode. It reads PC high at SSP+2, SR at SSP, then PC low
at SSP+4, all through the original supervisor stack. It validates the restored
PC, advances SSP by six, and restores PC plus the defined SR bits (A71F).
An S=0 return then exposes USP as A7; it cannot redirect the frame reads.
Nested exceptions consume separate frames, and snapshots taken inside handlers
can initialize another CPU. RTE samples incoming T like other executed
instructions; restoring T=1 enables tracing of the following instruction,
without retroactively tracing an RTE that began with T=0.
Delivery failures and callbacks
An odd exception SSP starts address-error delivery and faults again on the same odd stack, producing a terminal halt. Completed instruction effects remain visible. The address-error contract defines frame reservation, metadata, handler-fetch failures, and reset recovery.
An odd RTE stack faults before frame reads; an odd restored PC faults after all six reads. The return's register/SR updates remain staged in either case, then vector-3 entry applies its own state and memory effects.
step(), reset(), and interrupt() share a per-instance execution guard.
RAM and device callbacks may inspect snapshot(); nested mutations throw
before any nested CPU changes.
The guard clears on success or failure. A host memory exception propagates without
a record or fabricated bus-error delivery. Completed writes are not rolled back.
During entry S/T and reserved SSP are visible before the first frame write;
PC changes only after all vector bytes arrive. During RTE the stack/PC/SR
return state changes only after all frame reads and target validation; IR
already holds 4E73. During reset, SSP commits after four vector bytes;
PC follows the remaining four. Reset control flags are applied after the vectors
succeed or explicitly report a bus fault; a thrown host error preserves the
control flags it interrupted. These are instruction-level commit points.
The original 68000 has two frame shapes and no format word. Ordinary exceptions, trace, and interrupts reserve six bytes on SSP. Bus and address errors reserve fourteen. Capture the old supervisor stack and SR before selecting supervisor mode, clearing tracing and STOP, and reserving the frame. An odd old stack fails at its first word address after those state changes, before any memory call.
view EXCEPTIONSTACK "supervisor stack before entry" : 32 {
stack = register SSP
return stack
}
view INSTRUCTIONREGISTER "last complete operation word" : 16 {
instruction = register IR
return instruction
}
policy exceptionFlags "enter supervisor mode without tracing" () {
S = 1
T = 0
}
action prepareException "reserve an exception frame" (stack: 32, bytes: 8) {
apply exceptionFlags()
HALTED <- 0
TRACEPENDING <- 0
SSP <- subtract(stack, extend(bytes, 32))
}
action checkExceptionStack "check the first stacked word" (stack: 32) using alignment {
fault alignment write(subtract(stack, u32(2))) if lowBit(stack)
}
The six-byte frame ends with SR at new SSP followed by the saved PC. Its bus order differs from its final layout: write PC low, SR, then PC high, each word high byte first. Only then read the vector long. A frame overlapping a vector therefore changes the handler actually loaded. Commit PC only after all four vector bytes succeed; an odd target reports a fetch alignment fault after that commit. Vector reads use data-space calls in this instruction-level model.
action writeExceptionFrame "write the six-byte exception frame" (stack: 32, status: 16, returnPc: 32) using memory {
perform writeMemoryWord(subtract(stack, u32(2)), truncate(returnPc, 16))
perform writeMemoryWord(subtract(stack, u32(6)), status)
perform writeMemoryWord(subtract(stack, u32(4)), bits(returnPc, 31, 16))
}
source exceptionVectorAddress "vector table byte address" (vector: 8) : 32 {
return shiftBits(extend(vector, 32), left, 2)
}
action loadExceptionVector "load and check the handler address" (vector: 8) using memory, alignment {
address = source exceptionVectorAddress(vector)
target = source readMemoryLong(address)
PC <- target
fault alignment fetch(target) if lowBit(target)
}
action finishException "remember the handler-entry group" (processing: flag, vector: 8) {
when not(processing) {
ENTRY.KIND <- "exception"
}
when processing {
ENTRY.KIND <- "trap"
}
ENTRY.VECTOR <- vector
}
source exceptionFaultReturn "save the interrupted entry position" (returnPc: 32, vector: 8, vectorPhase: flag) : 32 {
address = source exceptionVectorAddress(vector)
return select(vectorPhase, address, returnPc)
}
A failure while writing this frame saves its requested return PC. A failure reading the vector, or its odd handler target, instead saves the vector's byte address. Completed-instruction exceptions (DIV, CHK, TRAPV, TRAP) retain the instruction-processing classification from the exception table below; restarted exceptions, trace, and interrupts do not. This classification is independent of program/data space.
Address errors
Odd instruction fetches and word/long operand accesses enter vector 3 in
the detecting boundary. The odd access itself makes no RAM call. Byte operands
and MOVEP's separate byte transfers remain valid at odd addresses. Entry selects
SSP, clears T, STOP, and owed trace, preserves the interrupt mask, and reserves
14 bytes. It writes seven words from the old SSP downwards, high byte first
within each word, then reads the vector at physical 00000C–00000F.
| Offset from new SSP | Contents |
|---|---|
| +0 | Special status word (SSW) |
| +2 | Full 32-bit fault address |
| +6 | Instruction register |
| +8 | Saved SR |
| +10 | Saved 32-bit PC |
SSW bit 4 is 1 for read/fetch and 0 for write. Bit 3 is 0 during instruction processing (including group-2 traps) and 1 during group-0/group-1 exceptions, trace, or interrupts. Bits 2–0 are the faulting access's function code: user data/program = 1/2; supervisor data/program = 5/6. PC-relative data operands use program space. Other bits are zero by model policy. Function codes appear in the fault metadata and SSW, not on the ordinary byte-access records.
The saved PC is the local fetch cursor: the instruction start for a rejected
initial opcode fetch, or the address following the completely fetched opcode
and extensions for an operand or taken-target fault. For example, an odd
MOVE.W (A0),D0 operand saves start+2; an odd absolute-long source saves
start+6. A failed branch saves its sequential cursor, with the attempted target
recorded separately as the fault address. A fault on an exception handler's
initial fetch saves that exception's vector address.
This is an instruction-level recovery contract. Hardware prefetch can advance the saved PC differently and can expose different partial register effects. Pending An updates, result writes, condition-code changes, return frame consumption, and call pushes still wait for their existing alignment checks. Already completed source reads remain in the record. Completed DIV/CHK source updates and flags remain visible if their exception entry fails. There is no rollback of completed RAM calls or earlier exception work. Handlers must choose a recovery PC; this core does not restart arbitrary faulting instructions automatically.
The original 68000 has no frame-format word. RTE consumes only the ordinary
six-byte SR/PC frame. A bus/address-error handler must remove the first eight
bytes itself (for example, ADDQ.L #8,A7) before RTE. It can edit the saved PC
first to retry or skip the faulting instruction.
A successful entry returns outcome: "executed" and exception.source:
"address-error"; the shared runner can execute the handler next. Exception
metadata contains vector 3, returnPc, and a fault with operation, full
address, instruction register, function code, and processingInstruction.
instruction is null for an initial odd-PC fault or failed trace entry.
A bus or address error during either vector-2 or vector-3 entry
sets faulted. The record returns outcome: "halted" and adds entryFault.
No recursive frame is attempted. Frame reservation precedes the first write;
thus an odd SSP reserves 14 bytes without writing, or 20 bytes in total when
a six-byte exception entry failed first. Completed writes/vector reads stay
visible. Subsequent step() calls return halted with no accesses; all interrupt
offers return ignored with reason "faulted", including level 7. Snapshots
preserve this latch. External reset can release it; a reset vector with an odd
PC leaves it set. An odd SSP alone is harmless until a stack access needs it.
Bus errors
A connection's "bus-error" result enters vector 2, read from physical
000008–00000B. Bus and address errors share the seven-word frame and
function-code rules above. This applies to instruction fetches, operands,
call/return stacks, ordinary exception frames, and vector reads. The fault
address identifies the exact failed byte, retaining its full logical address.
exception.source is "bus-error"; the remaining metadata matches address errors.
The saved PC follows the sequential fetch cursor after the last completely
fetched word. A failed opcode fetch leaves instruction: null and the old IR;
a failed extension leaves the completed opcode/extension words in
instruction.bytes. A successfully read first byte of an incomplete word
still appears in accesses. Failed calls save the sequential cursor even
when their target was already selected. Failures during vector reads or the
first handler fetch instead save the interrupted exception's vector address.
Completed effects are retained according to the existing instruction helpers:
| Interrupted work | Effects retained before vector-2 entry |
|---|---|
| MOVE source read | Earlier bytes read; pending An updates and destination remain unchanged |
| MOVE destination write | Pending source/destination An updates and earlier written bytes; MOVE flags wait for the whole write |
| ALU destination read/write | An updates precede the read; result flags precede the write |
| MOVEM | Completed register loads/stores; its final base update waits for the entire list |
| BSR/JSR, PEA, LINK | Earlier stack bytes written; the stack-pointer update waits for the complete push |
| RTS/RTR/RTE | Earlier frame reads; return PC, flags, and stack consumption remain staged |
| Ordinary exception entry | Reserved six-byte frame, supervisor/trace changes, completed bytes, and any acknowledged interrupt/mask update |
These commit points deliberately describe this instruction-level model. They do not reproduce the original processor's internal partial execution or prefetch advancement. Hardware bus transactions are word-sized; this connection can stop between their two modeled bytes. Recovery software must choose the saved PC and account for retained effects; automatic instruction restart is not provided.
Any bus/address error during bus/address-error entry terminally halts, including
its first opcode fetch. A failed transfer while writing the frame or reading
the vector appears as exception.entryFault, with source: "bus-error" for a
bus failure. A failed initial handler fetch happens in the next step():
it returns outcome: "halted", a top-level fault, and no new exception or
frame. Reset's first opcode fetch follows the same terminal-halt rule. The
stored entry context makes these decisions reproducible after restoration.
A successful complete handler opcode clears that context; subsequent operand
or extension faults belong to the handler instruction itself.
Host exceptions return no record and retain completed effects, as described under delivery failures. They never set the terminal-halt latch merely because a callback threw.
The function code captures the faulting access's space and the current S flag before switching to supervisor mode. Fetches and PC-relative reads use program space. Codes 1/2 describe user data/program; 5/6 describe supervisor data/program. The special status word adds R/W at bit 4 (one for a read) and I/N at bit 3 (one when not processing an instruction); reserved bits stay zero.
source faultFunctionCode "capture the failing access space" (program: flag) : 8 {
supervisor = flag S
return or(select(supervisor, u8(4), u8(0)), select(program, u8(2), u8(1)))
}
action beginMemoryError "mark memory-error entry before transfers" (vector: 8) {
ENTRY.KIND <- "fault"
ENTRY.VECTOR <- vector
}
action haltMemoryError "stop after a second entry fault" {
FAULTED <- 1
}
action writeMemoryErrorFrame "write the fourteen-byte memory-error frame" (stack: 32, status: 16, returnPc: 32, address: 32, write: flag, processing: flag, code: 8) using memory {
instruction = register IR
special = or(or(select(not(write), u8($10), u8(0)), select(not(processing), u8(8), u8(0))), code)
perform writeMemoryWord(subtract(stack, u32(2)), truncate(returnPc, 16))
perform writeMemoryWord(subtract(stack, u32(4)), bits(returnPc, 31, 16))
perform writeMemoryWord(subtract(stack, u32(6)), status)
perform writeMemoryWord(subtract(stack, u32(8)), instruction)
perform writeMemoryWord(subtract(stack, u32(10)), truncate(address, 16))
perform writeMemoryWord(subtract(stack, u32(12)), bits(address, 31, 16))
perform writeMemoryWord(subtract(stack, u32(14)), extend(special, 16))
}
Push the seven words downwards in that order. At new SSP the final layout is SSW, fault address (long), IR, SR, saved PC (long). Entry then loads vector 2 for a bus error or vector 3 for an address error. A second modeled fault while checking/writing this frame or loading its vector halts without a third frame. The failure record retains the original access metadata and the second fault; earlier state changes and completed memory accesses remain visible.
First handler fetch
The next instruction's initial fetch remembers how its handler was entered.
After reset or memory-error entry, a failed first fetch halts immediately without
another frame. After an ordinary exception or trap, it saves that entry's vector
address; after normal execution it saves PC. A completed operation-word fetch
clears this entry phase in beginInstruction below.
source terminalInitialFetch "whether another frame is forbidden" : flag {
reset = choice ENTRY.KIND = "reset"
memoryError = choice ENTRY.KIND = "fault"
return or(reset, memoryError)
}
source initialFaultReturn "saved PC for an initial fetch failure" : 32 {
ordinary = choice ENTRY.KIND = "none"
pc = register PC
vector = register ENTRY.VECTOR
address = source exceptionVectorAddress(vector)
return select(ordinary, pc, address)
}
source initialFaultProcessing "instruction-processing state at the first fetch" : flag {
ordinary = choice ENTRY.KIND = "none"
trap = choice ENTRY.KIND = "trap"
return or(ordinary, trap)
}
External interrupt delivery
interrupt(level, acknowledge) offers one selected request at an instruction
boundary. level is 1..7. The caller owns pending requests, priority selection,
and physical level transitions; there is no internal signal queue or scheduler.
Levels 1..6 are accepted only when greater than interruptMask. A level-7
offer represents a newly detected transition from a lower level to 7, or a
held level 7 when the current mask is below 7. It is accepted even at mask 7.
Do not repeatedly offer a held level 7 at mask 7; each such call would
represent another selected edge. Ignored requests remain caller-owned.
A terminal halt returns outcome: "ignored", reason: "faulted". Otherwise an
owed trace returns outcome: "ignored", reason: "trace-pending" before
masking or acknowledgement. Deliver that trace with step() and reoffer the
selected interrupt before executing handler code. Otherwise a masked request
returns outcome: "ignored", reason: "masked". Neither calls the device,
reads RAM, changes state, nor wakes STOP. Invalid levels throw before mutation;
an acknowledgement callback is required only for an eligible request.
Accepted delivery captures the old SR, selects
supervisor mode, clears T/STOP, reserves six frame bytes, and sets the mask to
the selected level. It then calls acknowledge() once:
| Result | Vector |
|---|---|
| Integer byte 0..255 | The supplied vector number |
"autovector" |
24 + level (25..31) |
"spurious" |
24 |
An uninitialized peripheral may supply vector 15. A zero handler address is
valid and is not implicitly redirected to vector 15. A host exception is not a
spurious hardware acknowledgement; use the explicit "spurious" response.
Invalid results throw after entry preparation, without frame/vector accesses.
The reserved SSP, changed mask, cleared T, and released STOP remain visible;
completed host/device effects are not rolled back.
Following acknowledgement, the common entry path writes PC low, the saved
pre-interrupt SR, and PC high, then reads the vector. The return PC is the
full address of the instruction that would otherwise execute. Frame/vector
overlap and address wrapping follow the synchronous entry contract. An odd
SSP starts address-error delivery before acknowledgement and terminally halts
on the same odd stack. An odd loaded handler PC instead enters vector 3 after
acknowledgement and frame writes. Such records use outcome: "executed" or
"halted" and carry address-error metadata.
The separate interrupt record contains level, a null instruction, detached
snapshots, and ordered accesses. Accepted records add vector and returnPc.
Their first access is { kind: "acknowledge", level, value }, followed by six
frame writes and four vector reads. RTE restores the previous mask, flags,
stack selection, and return PC; the caller can then reoffer an eligible held
request. Snapshots preserve all CPU-owned recognition state; device state and
pending external requests stay with the caller.
An offer selects one level from 1 through 7. Terminal halt rejects first, then owed trace, then the current mask. Level 7 bypasses the mask: an offer represents a new edge or an eligible held request, not a pin-transition detector. The gate returns zero to admit an offer, or the declared reason's one-based selector.
source interruptGate "recognize an eligible interrupt offer" (level: 8) : 8 {
faulted = latch FAULTED
trace = latch TRACEPENDING
mask = register INTERRUPTMASK
masked: flag = and(not(equal(level, u8(7))), not(lessThan(extend(mask, 8), level, unsigned)))
return select(faulted, u8(1), select(trace, u8(2), select(masked, u8(3), u8(0))))
}
action acceptInterrupt "raise the interrupt mask before acknowledgement" (level: 8) {
INTERRUPTMASK <- truncate(level, 3)
}
source autovector "select the level's autovector" (level: 8) : 8 {
return add(u8(24), level)
}
An admitted offer checks that acknowledgement is callable, captures PC and the
old SR/SSP, reserves six bytes, and checks stack alignment before raising the
mask or calling the host. An odd stack thus receives no acknowledgement. The
callback observes supervisor mode, the reserved stack, cleared STOP/trace, and
the new mask. Its response is a vector byte, "autovector" (24 + level), or
"spurious" (24). Validate before recording acknowledgement, then write the
captured frame and load the handler. Failed short entry follows the same
memory-error recovery as synchronous exceptions, with processing set to zero.
Host throws and invalid responses retain completed effects and escape unchanged.
Trace recognition
Delivery uses a separate six-byte entry to vector 9 with
instruction: null and { source: "trace", vector: 9, returnPc }.
The saved PC and SR are the current post-instruction state, including a taken
branch or exception handler target. No instruction is fetched. Trace entry
clears STOP, T, and tracePending.
An odd trace stack terminally halts through failed address-error entry, with
no RAM accesses, cleared STOP/trace latches, and 20 reserved stack bytes.
Host callback failures retain cleared latches and reserved SSP, as for other entries. External reset
clears an owed trace after reading both reset vectors. T and tracePending
are intentionally independent: setting T during an instruction or restoring a
snapshot with T=1 does not itself request an immediate trace entry.
RESET device connection
The optional third constructor argument is a Cpu68000Connections object with
resetDevices(): void. The privileged RESET instruction (4E70) calls that
method once after fetching its opcode, then records { kind: "reset" } and
advances PC by two. It preserves registers, flags, and the interrupt mask;
normal trace retirement still applies. The connection owns device state and
is supplied again when constructing a CPU from a snapshot.
An absent connection throws only when a supervisor-mode RESET uses it. A
user-mode attempt enters the privilege vector without calling the device.
A throwing callback leaves PC at the instruction boundary and IR at 4E70,
returns no record, and does not undo device effects. The execution guard still
clears. No synthetic memory transfer or cycle count represents RESET's output.
The physical chip's 124-clock reset pulse is not timed here.
Fetching, dispatch, and retirement
Execution starts with boundary arbitration: terminal halt prevents all work; an owed trace is delivered before STOP is considered; otherwise STOP prevents fetching. T is sampled before the first memory callback. Changing T during an instruction affects the following instruction, including when STOP loads SR or RTE restores it. This is an instruction-level model; it does not emulate the hardware prefetch queue or bus-cycle timing.
The operation word and each extension word are fetched high byte first. Both bytes must succeed before the sequential cursor advances or either byte joins the instruction's byte list. The access log still contains a successful first byte if its partner fails. The cursor wraps at 32 bits; the bus adapter projects physical addresses separately. An odd starting PC rejects fetching before any memory call. Only a complete operation word updates IR and clears the prior entry phase; unknown words then request illegal-instruction delivery without fetching extensions.
view FETCHPC "logical instruction address" : 32 {
contents = register PC
return contents
}
action beginInstruction "commit a complete operation word" (opcode: 16) {
IR <- opcode
ENTRY.KIND <- "none"
ENTRY.VECTOR <- u8(0)
}
action scheduleTrace "retain the trace sampled before execution" (sampled: flag) {
TRACEPENDING <- sampled
}
action finishInstruction "retire to the selected target or sequential cursor" (next: 32, sampled: flag) {
PC <- next
perform scheduleTrace(sampled)
}
The input masks below select numeric fields from the operation word. A repeated
letter marks the captured bits; x marks ignored bits. They do not determine
legality: the instruction families above enumerate the accepted words and give
each field its meaning. MOVE has separate source and destination mode/register
fields; the other operand families use mode, code, and where needed the
upper register/quick field. Branch displacements and MOVEQ immediates retain all
eight encoded bits for the instruction body to interpret.
execution word {
memory 24
counter FETCHPC
fetch big advance after word
alignment 2
terminal FAULTED
stopped HALTED
trace T pending TRACEPENDING exception "trace" action scheduleTrace
fetched action beginInstruction
retire action finishInstruction
address source effectiveAddress
unknown "illegal-instruction"
unsupported "illegal-instruction"
inputs {
sourceMode = "xxxx xxxx xxmmm xxx"
sourceCode = "xxxx xxxx xxxx xrrr"
destinationMode = "xxxx xxxm mmxx xxxx"
destinationCode = "xxxx rrrx xxxx xxxx"
mode = "xxxx xxxx xxmmm xxx"
code = "xxxx xxxx xxxx xrrr"
upperCode = "xxxx rrrx xxxx xxxx"
displacement = "xxxx xxxx dddd dddd"
immediate = "xxxx xxxx iiii iiii"
}
exceptions {
"illegal-instruction" vector 4 restart
"divide-by-zero" vector 5 complete
"bounds-check" vector 6 complete
"overflow-trap" vector 7 complete
"privilege-violation" vector 8 restart
"trace" vector 9 restart
"line-a" vector 10 restart
"line-f" vector 11 restart
"trap" vector 32 plus "xxxx xxxx xxxx vvvv" complete
}
interrupt events
events {
capture view EXCEPTIONSTACK view SR view INSTRUCTIONREGISTER
prepare action prepareException
stack check action checkExceptionStack
short frame action writeExceptionFrame bytes 6
vector action loadExceptionVector
complete action finishException
entry return source exceptionFaultReturn
fault frame action writeMemoryErrorFrame bytes 14
fault vectors address 3 bus 2
function code source faultFunctionCode values 1, 2, 5, 6
fault begin action beginMemoryError
halt action haltMemoryError
initial fetch terminal source terminalInitialFetch return source initialFaultReturn processing source initialFaultProcessing
levels 1 7
gate source interruptGate reasons "faulted", "trace-pending", "masked"
accept action acceptInterrupt
acknowledge autovector source autovector spurious 24 maximum 255
interrupt return view FETCHPC processing 0
}
}
Selecting a branch target never moves the sequential fetch cursor. Successful
retirement stores the target if one was selected, otherwise the cursor. STOP
reports halted only when no trace is owed. A synchronous exception marked
restart saves the operation-word address; one marked complete saves the
cursor after its operands and can owe a trace after successful exception entry.
TRAP adds its four-bit literal to vector 32. Failed exception entry does not
schedule this trace. Memory faults during an instruction use the sequential
cursor, even if the instruction already selected a target.
Each dispatched instruction gets its own pending-register update set. The address source above calculates addresses using that set, and instruction bodies choose the commit points. The shared executor supplies ordered word fetches, dispatch, and retirement; generated bindings connect these mechanics to the declared actions. The shared bus adapter classifies explicit bus failures. The generated event binding constructs specification-defined frames and handles failed first fetches through the declared recovery sources. Arbitrary host throws escape unchanged, leaving all earlier completed effects visible.
An ordinary successful step returns outcome: "executed", a full logical
instruction.address, and the operation/extension bytes in fetch order. Its
before and after snapshots are detached. accesses records completed
physical byte reads and writes, plus a successful device-reset event for RESET.
A failure in the first word has instruction: null; a later failure retains
only complete fetched words in instruction.bytes. Successful synchronous
exception entry adds { source, vector, returnPc } and still reports executed,
without fetching a handler instruction. Terminal halt or stopped execution
returns halted; owed trace entry has no instruction. No unsupported-opcode
outcome is exposed. Calls share the reset/interrupt reentrancy guard; callbacks
may inspect snapshots but cannot begin another boundary.
Operand accesses in records
An instruction fetches its source extensions before reading the source, and
its destination extensions before writing the destination. Ordinary words and
longs transfer high byte first at ascending addresses, including predecrement
stores; MOVEP advances by two. Exception frames and RTE use their explicitly
declared word order. Control-flow instructions fetch no byte at their target.
Each record reflects completed calls rather than reconstructed bus cycles.
Zero-filled memory is executable (0000 is ORI.B), so callers use an endpoint
or a step budget to stop execution.
External reset
External reset starts execution by loading an initial supervisor stack pointer
and program counter from the first eight bytes of memory. It differs from the
privileged RESET instruction, which signals external devices without resetting
the processor. This model's reset() never calls the device-reset connection,
fetches an instruction, or constructs an exception frame.
The vector reads use supervisor program space, high byte first. Each long commits only after all four bytes succeed: failure while reading PC retains the new SSP and the old PC. Both vectors retain all 32 bits; only physical memory accesses discard the high eight bits. The PC is checked for even alignment after it is stored. An odd PC remains visible and reports a rejected fetch without calling memory at that address.
action loadResetVectors "load the external-reset vectors" using memory, alignment {
stack = source readProgramLong(u32(0))
SSP <- stack
start = source readProgramLong(u32(4))
PC <- start
fault alignment fetch(start) if lowBit(start)
}
After successful reads or a modeled bus/alignment fault, reset sets S, clears T, masks all ordinary interrupt levels, clears STOP and owed trace, and records the reset phase. The Boolean failure input is set only for a modeled fault. Only a successful reset clears terminal halt. D0–D7, A0–A6, USP, IR, X/N/Z/V/C, and memory are preserved. Retaining registers and condition codes whose reset values are unspecified is a deterministic model policy, not a hardware guarantee.
policy resetFlags "select supervisor mode and clear tracing" () {
S = 1
T = 0
}
action finishReset "complete external reset" (failed: flag) {
apply resetFlags()
INTERRUPTMASK <- u3(7)
TRACEPENDING <- 0
HALTED <- 0
FAULTED <- failed
ENTRY.KIND <- "reset"
ENTRY.VECTOR <- u8(0)
}
reset {
attempt action loadResetVectors
complete action finishReset with failure
}
The reset contract runs the attempt, then passes its success or modeled failure
to the completion action. Only an explicit "bus-error" result from the memory
connection becomes a bus fault. Host-thrown values, including the string
"bus-error" or an object resembling a fault, escape unchanged and skip
completion. Invalid byte results likewise throw. Earlier completed vector
writes remain visible in all cases; no failed transfer is logged.
A returned reset record has detached before and after snapshots and a list
of completed physical byte reads. Success produces exactly eight accesses and
no fault property. An explicit bus failure adds
{ source: "bus-error", operation: "read", address }; an odd PC adds
{ operation: "fetch", address }. Neither record includes an instruction or
step outcome. Calls share the step/interrupt reentrancy guard; callbacks may
inspect the current snapshot but cannot start another CPU boundary. Restarting
an example instead creates fresh state and memory.
Public interface
The class, connection types, detached snapshots, and execution records are created from these declarations and the execution and event contracts above. Returned records own their snapshots, bytes, accesses, and fault/exception metadata; the CPU retains no record history. Memory size, logical PC width, interrupt levels, fault vectors, and function codes come from this specification. The machine catalogue discovers this interface.
interface Cpu68000 "Instruction-level Motorola 68000 with 32-bit registers and a 24-bit memory connection." {
snapshot a7 = A7
snapshot physicalPc = PHYSICALPC
}
Checks and limits
The register tests independently enumerate operation words and check widths, aliases, both stack banks, live upper bits, and failure after every register/flag access. They also cover every MOVEQ immediate byte and incoming flag combination. The specification tests check schema and encoding ownership, memory order, alignment faults, physical projection, status packing/restoration, and formal edits that change execution. The MOVE tests independently enumerate all 9,150 non-register MOVE forms and compare every access, state change, and injected failure. The logical tests cover all 6,660 logical/unary encodings, independent bit truth tables, callback mutations, and partial failures. Logical specification tests verify encoding ownership, shared aliases, and edits to calculations and fields. The arithmetic tests independently scan all 13,510 arithmetic operation words and verify signed and unsigned results, X and cumulative Z, active stack banks, live callback changes, and every partial-failure boundary. Arithmetic specification tests change calculations, flag policies, quick amounts, and paired-register selection to prove those rules control generated execution. The bit/shift tests independently scan all 5,284 operation words, compare against a bit-array oracle for every six-bit count and sign boundary, and inject failures after each effect. Bit/shift specification tests change loop initials, overflow accumulation, count masks, and bit-number reduction; typed-loop tests check simultaneous updates and their scopes, effects, and outcomes. The word/decimal tests independently enumerate all 2,426 encodings, compare every effect and injected failure, check quotient limits with BigInt, and exhaust packed bytes with separate digit and valid-decimal oracles. Word/decimal specification tests change product signedness, overflow flags, signed bounds, decimal correction, cumulative zero, and paired selectors to prove the specification controls execution. The control, transfer, and system probes independently enumerate all remaining encodings, compare every observable effect and failed access, and cover displacement/counter limits, every condition, register masks, status words, both stack banks, and live callback mutations. Specification mutation tests change conditions, cursor placement, alternate-byte spacing, mask order and iteration count, sign extension, privilege and commit order, return-frame reads, and the RESET encoding/signal. Boundary-language tests check distinct cursor/target effects, callback failures, widths, capabilities, and document-located errors. Address-decoder tests compare every mode with an independent imperative reference, inject failures after each observable effect, and exhaust all 65,536 brief index extensions in both stack banks. Specification edits change bank selection, byte increments, extension signedness, PC-relative capture order, and staging itself. Shared staging tests check lazy reads, commit order, repeated commits, and partial failures; language tests exercise another CPU and reject hidden staging effects. Reset tests check complete records, callback-visible vector commits, every failed byte, host exceptions, invalid values, and reentrancy. Reset specification tests change vectors, alignment, masks, completion, and commit timing through the public CPU. Word-execution tests check partial words, arbitration, cursor/target separation, trace samples, and host throws. Word-contract tests exercise an unrelated model and change input fields, IR commits, retirement, trace sampling, vector literals, completion, unknown words, and byte order through the public CPU. Event-contract tests change frame reservation, transfer addresses, vector geometry, interrupt gates, callback-visible masks, initial-fetch recovery, and special-status bits. Public-interface tests rename the CPU and class, change bus widths and snapshot views, and reject missing contracts. Memory-adapter tests check other address widths and distinguish explicit failures from host throws. Entry-sequence tests exercise different frame sizes, vectors, levels, and reason names, including partial entry and host exceptions. Source and family inputs are captured numeric values, not additional hardware registers.
The specification now resolves effective addresses, selects storage, and stages register updates. A shared instruction-local helper retains pending values and commits their generated writes at the specification's explicit commit points. Exception frames, interrupt recognition and acknowledgement, and nested-fault recovery now come from the specification. The specification also owns the public class and record types, snapshot assembly, memory width, and integration metadata. There is no handwritten 68000 core, state adapter, context adapter, or instruction-family registry. The generator groups bodies by their declared input signatures and binds the encoded fields. Shared runtimes provide memory recording, guarding, and the declared word-entry sequence; they contain no 68000-name branches.
Reference comparisons
The pinned dromaios-mac CPU and instruction definitions
at 9fa2068 supplied implementation comparisons. Motorola's manuals below
remain the hardware authority. Local tests derive expected results independently;
matching an earlier emulator is supplementary evidence, not a correctness oracle.
Source comparisons
The Mac reference includes later-family status fields and masks PC while fetching. This model retains the original chip's single T bit, no M/T0, a 32-bit logical PC, and separate USP/SSP storage. Reset preserves unspecified state under the policy above. Macintosh mapping, ROM hooks, and device wiring belong to machine components.
Pinned Musashi instruction handlers and exception helpers provide additional comparisons. Important differences and corroborating cases are retained here:
| Area | Comparison and chosen rule |
|---|---|
| Legal effective addresses | The Mac decoders admit extra MOVE, CMPI, EOR, control, TST, and bit-operation forms. The chapter follows the original-chip sets in Motorola's instruction tables. |
| Source updates and address arithmetic | Both references read the source before the destination in ADDA/SUBA/CMPA. Pending source updates can affect the destination value. |
| MOVEM base aliases | Musashi corroborates original-base stores on predecrement and the final postincrement base. Later-processor base rules are excluded. |
| LINK/UNLK A7 | Musashi corroborates saving the decremented SP for LINK A7 and leaving the popped value in SP for UNLK A7. The Mac reference increments the popped value for UNLK A7. |
| CLR and Scc memory reads | Both references omit the read in these paths; Motorola's original-68000 notes require it. Dromaios performs it, as it does for MOVE from SR to memory. |
| ASL overflow | The Mac reference clears V. Motorola requires any intermediate sign change: ASL.B of 40 by two yields 00 with V=1. |
| Decimal predecrement | The Mac decimal path decrements byte A7 by one; the original stack-byte step here is two. Undefined N/V follow the declared preservation policy. |
| Divide by zero | The Mac reference sets V instead of delivering vector 5. Musashi delivers the exception but does not clear C; this model follows the manual's C rule and following-PC return address. |
| External interrupts | Musashi fetches the vector before stacking and redirects a zero handler to vector 15. This model follows the manual's stacking-before-vector rule; vector 15 is a peripheral response, and zero remains a valid handler address. |
MOVEM retains this model's ascending, high-first byte records, even for predecrement long stores. Musashi models low-word-first hardware ordering there. Its source comparison does not establish bus timing for this model. Likewise, Musashi's seven-word bus/address-error frame is a layout cross-check, not hardware evidence for partial instruction execution or restartability.
External fixture comparisons
Recorded comparisons used SingleStepTests/680x0 68000 V1 at e0d5ece.
These are emulator-generated cases, not hardware traces. Downloaded fixtures
are supplementary evidence; the routine regression suite uses local expectations.
| Scope | Passing cases | Observations |
|---|---|---|
| TRAP, TRAPV, RTE, CHK | 25,089 | 8,065 TRAP, 8,065 TRAPV, 4,011 RTE, and 4,948 CHK; full registers, defined SR, final RAM, and ordered data accesses |
| RESET instruction | 8,065 | Registers, defined SR, PC, RAM, and exactly one connected device callback; no reset-pin pulse-duration claim |
The comparison materialized the fixtures' two prefetched instruction words for direct fetching, excluded instruction-prefetch transactions, and masked undefined CHK flags in both SR and the saved frame. It corroborated the modeled short-frame order: entry writes PC low, SR, PC high; RTE reads PC high, SR, PC low. Timing and physical function-code signaling were not compared.
The RTE file's 4,054 and CHK file's 3,117 address-error cases were excluded.
After excluding address errors and ordinary division, the DIVU/DIVS corpus
contained only one zero-divisor case: 80ef [DIVU (d16, A7), D0] 5745.
It saves the instruction-start PC, unlike the following PC required by the
user's manual §6.3.5 and used by Musashi. Other defined state, frame, and data
accesses agreed after undefined flags were masked. This discrepancy is not
counted as a pass; local tests cover signed and unsigned zero divisors across
every source form using the manual's following-PC rule.
These corpus comparisons do not cover external IRQs, traced instructions, address errors, or bus errors. Those paths use manual-derived local checks, including every failed transfer, nested faults, frame cleanup, and snapshot restoration. The address-error and bus-error contracts describe the model's limits: byte callbacks, staged register updates, and a completed-word fetch cursor cannot establish exact hardware fault timing or restartability.
Hardware references
Motorola's MC68000 User's Manual, ninth edition defines the programmer's model and data organization in chapter 2, external reset in §6.3.1, and address errors in §6.3.10. The M68000 Family Programmer's Reference Manual supplies ADDI (4-9–4-10), ANDI (4-18–4-19), CMPI (4-79–4-80), EORI (4-102–4-103), ORI (4-153–4-154), SUBI (4-179–4-180), MOVE (4-116–4-118), and MOVEA (4-119–4-120) encodings and flags. Control-flow references are Bcc (4-25–4-26), BRA (4-55), BSR (4-59–4-60), DBcc (4-90–4-91), RTS (4-169), and condition table 3-19. Address, register-list, and frame references are JMP (4-108), JSR (4-109), LEA (4-110), LINK (4-111–4-112), MOVEM (4-128–4-130), PEA (4-159), and UNLK (4-194). The reference comparisons record the source cross-checks for base-register and A7 aliases. Register/address arithmetic uses ADD (4-4–4-6), ADDA (4-7–4-8), CMP (4-75–4-76), CMPA (4-77–4-78), SUB (4-174–4-176), and SUBA (4-177–4-178). Register/memory logic uses AND (4-15–4-17), OR (4-150–4-152), and EOR (4-100–4-101). Quick/unary references are ADDQ (4-11–4-12), SUBQ (4-181–4-182), CLR (4-73–4-74), NEG (4-143–4-144), NEGX (4-145–4-146), NOT (4-148–4-149), TST (4-192–4-193), and Scc (4-172–4-173). CLR and Scc's final notes specify their original-68000 memory reads. The reference comparisons distinguish those accesses from the existing emulators' behavior. Addressing is defined in §§2.2.1–2.2.7 and §§2.2.11–2.2.18; §2.4 distinguishes the original brief extension from later chips. Later-family additions are excluded.
Shift/rotate references are ASL/ASR (4-21–4-24), LSL/LSR (4-113–4-115), ROL/ROR (4-160–4-162), and ROXL/ROXR (4-163–4-165). Bit operations use BCHG (4-27–4-29), BCLR (4-30–4-32), BSET (4-56–4-58), and BTST (4-61–4-63). Extended arithmetic uses ADDX (4-13–4-14), CMPM (4-81), and SUBX (4-183–4-184). Decimal, word, and transfer references include ABCD (4-2–4-3), CHK (4-69–4-70), DIVS (4-92), DIVU (4-96), EXG (4-105), EXT (4-106), MOVE to CCR (4-123–4-124), MOVE from SR (4-125), MOVEP (4-131–4-133), NBCD (4-141–4-142), RTR (4-168), and TAS (4-186–4-187).
The user's manual §§6.2.3–6.2.4 and 6.3.5–6.3.8 establish short frames, saved-PC selection, privilege checks, and trace ordering. Sections 6.3.2–6.3.4 cover interrupt levels and acknowledgement responses; §§6.3.9–6.3.10 and figure 6-7 define bus/address-error frames and terminal faults. Section 6.1.3 places reset vectors in supervisor program space; other exception vectors use supervisor data space. RESET and STOP use the original-chip instruction entries, without importing later-family trace fields.