Introduction
The 2650 addresses 32 KB (15 bits) but its data instructions only have room for 13 address bits. The address space is therefore four pages of 8 KB ($0000, $2000, $4000, $6000), and a
data instruction can reach only the page it is in; the 15-bit form exists only for branches. This is the rule that most often surprises a reader of a 2650 listing: LODA,R0 $1800 in the page at $2000 loads from $3800, not from $1800.
All the rules on this page are those of the core read for the checks (FBNeo’s MAME-derived 2650 core), which the decoder agrees with in every run, and of the MAME disassembler; no manufacturer document was read.
The 8 KB pages
An address is page (2 bits) and offset (13 bits). The page of an instruction is bits 14 and 13 of its address. Everything below is computed inside that page unless it says otherwise. The instruction address register counts inside the page too: after the last byte of a page, the next instruction byte is the first byte of the same page, not of the next one. A program that runs off the end of a page does not continue into the next.
Relative (the R instructions and the relative branches)
Two bytes: the opcode and one byte whose bit 7 is the indirect flag and whose bits 6 to 0 are a signed displacement, -64 to +63. The effective address is the address of the next instruction plus the displacement, taken
modulo 8 KB inside the page of the instruction. BCTR,EQ $0407 at $0400 has the displacement byte $05 (next instruction $0402, plus 5). At the end of a page the sum wraps: 18 04 at $1FFE branches to $0004, in the same page.
| Bytes at | Instruction | Effective address |
|---|---|---|
$0400: 18 05 | BCTR,EQ $0407 | $0402 + 5 = $0407 |
$0400: 18 7E | BCTR,EQ $0400 | $0402 - 2: a branch to itself |
$1FFE: 18 04 | BCTR,EQ $0004 | the next instruction wraps to $0000 inside the page; + 4 |
$0400: 08 85 | LODR,R0 *$0407 | bit 7 set: indirect, with the displacement +5 (see below) |
The two emulator sources read disagree here: the MAME-derived core adds the displacement to the address of the next instruction (above); the Arcadia 2001 emulator of emulators.org and its debugger decoder add it to the address of the displacement byte, one less. The decoder follows the first, which agrees with MAME’s disassembler; the checks list the difference.
Absolute (the A instructions)
Three bytes: the opcode, then a byte holding the indirect flag (bit 7), the two index control bits (bits 6 and 5) and the high five bits of a 13-bit address, then the low eight bits. The effective address is the 13-bit address inside the page of the instruction:
0C 18 00 is LODA,R0 $1800 at $0400 and LODA,R0 $3800 at $2400.
| Index control | Written | What happens |
|---|---|---|
| 00 | LODA,R1 $1800 | no indexing: the register in the opcode is the data register |
| 01 | LODA,R0 $1810,R2+ | auto-increment: R2 is increased by one, then added to the address; the data register is R0 |
| 10 | LODA,R0 $1810,R2- | auto-decrement: R2 is decreased by one, then added |
| 11 | LODA,R0 $1810,R2 | plain indexing: R2 is added unchanged |
With indexing the register in the opcode becomes the index register and the data register is always R0 (the viewer writes the data register after the mnemonic and the index register after the address). The sum is taken modulo 8 KB inside the page, so an index cannot carry into the page bits. The index is an unsigned byte. If both indirection and indexing are used, the pointer is read first and the index is added to the address the pointer gives. The index register may be R0, in which case R0 is both index and data register (the increment happens first). The first-byte value is that of the table: an operand byte of $38 is index control 01, address high bits $18; of $98, indirect with no index.
Absolute branches (15 bits)
The branch forms BCTA, BCFA, BSTA, BSFA, BRNA, BSNA, BIRA and BDRA also have three bytes, but the byte after the opcode is only the indirect flag (bit 7) and the high seven bits of a
full 15-bit address: there are no index control bits, and the target may be in any page. 1C 61 23 at $0400 is BCTA,EQ $6123; 1F 00 00 is BCTA,UN $0000, the usual jump to the reset address.
A branch to a different page works only with this form; relative branches cannot leave the page.
Zero-page relative (ZBRR, ZBSR)
ZBRR (opcode $9B) and ZBSR ($BB) use the relative byte (indirect flag and 7-bit displacement) but add the displacement to address 0 instead of the instruction’s address, modulo 8 KB, in page 0: the reachable addresses are $0000 to $003F and $1FC0 to $1FFF.
9B 05 is ZBRR $0005 from anywhere; 9B 7E is ZBRR $1FFE. They are the cheap two-byte jump or call to the start of the program, and an interrupt takes its vector the same way (BB 83 is ZBSR *$0003: a call through the pointer at $0003).
Indirect operands
Bit 7 of the first operand byte (of the relative byte, or of the high address byte) makes the address indirect: the effective address names two bytes in memory, high byte first, and the 15-bit pointer they hold (bit 7 of the high byte is ignored) is the real address. The pointer is a full 15-bit address: an indirect data access can reach another page.
The second pointer byte is read from the next address inside the page (the address after $1FFF is $0000). An indirect operand costs two machine cycles more. The viewer shows *$addr and cannot show the target, which is in memory.
BXA and BSXA
BXA ($9F) and BSXA ($BF) are absolute branches whose target is the 15-bit address plus R3: a jump table. There is no other index register and no auto-increment. The viewer writes BXA $1000,R3; the target is not known without the value of R3.
The same two opcodes would be the “false-condition” branches with condition 3, which do not exist.
Not described
Known, not yet covered
- Reference: a larger set of worked listings (a vector table, a screen loop) from Arcadia and VC4000 programs.
Unknown
- Reference: the base of the relative displacement is stated as two cores and a disassembler have it; the manufacturer’s manual was not read. Likewise whether an indexed address can cross a page boundary in the hardware: the core read keeps it inside the page.
- Reference: whether a conditional branch that is not taken still reads its indirect pointer (the core read does not; a real chip’s timing may differ).
Links
Reference
- 2650 processor – Wikibook: addressing modes, indexing and indirection
- AS2650 instruction set architecture – Avalon Semiconductors: relative, absolute, branch absolute, indexed and indirect
- 2650dasm.cpp – MAME’s 2650 disassembler