Overview
Memory Map
ROM Format
System Reset
About
Change Colors
System Components
CPU - NVC/V810 Family Microprocessor
Communication Port
Game Pad
Game Pak
Timer
Wait Controller
VIP - Virtual Image Processor
VSU - Virtual Sound Unit
The Virtual Boy memory bus is 27 bits wide and is organized by hardware component:
0x00000000 - 0x00FFFFFF |
VIP - Virtual Image Processor |
0x01000000 - 0x01FFFFFF |
VSU - Virtual Sound Unit |
0x02000000 - 0x02FFFFFF |
Miscellaneous Hardware |
0x03000000 - 0x03FFFFFF |
Unmapped |
0x04000000 - 0x04FFFFFF |
Game Pak Expansion |
0x05000000 - 0x05FFFFFF |
WRAM |
0x06000000 - 0x06FFFFFF |
Game Pak RAM |
0x07000000 - 0x07FFFFFF |
Game Pak ROM |
0x08000000 - 0xFFFFFFFF |
Mirroring of memory map |
The upper 5 bits of any address in the 0x08000000
-
0xFFFFFFFF
range are masked, making the maximum effective
address 0x07FFFFFF
and producing mirrors of the contents of
memory across the entire address range.
Writes to the unmapped address range 0x03000000
-
0x03FFFFFF
have no effect, and reads in that range will return
zero.
WRAM is 64 KiB in size: its effective address range is
0x05000000
- 0x0500FFFF
. Any addresses in the
0x05010000
- 0x05FFFFFF
range consequently have
bits 16-23 masked, producing mirrors of the contents of WRAM across the
entire address range.
For information on the Game Pak Expansion, Game Pak RAM and Game Pak ROM address ranges, see Game Pak.
WRAM is pseudostatic RAM that has specific initialization requirements:
• | Wait 200 µs before accessing. |
• | Perform 8 dummy read accesses before any other accesses. |
Virtual Boy software must account for this initialization before accessing WRAM, or else its behavior is undefined.
Registers for various hardware components occupy addresses
0x02000000
- 0x02FFFFFF
in the system memory map:
0x02000000 | CCR | Link | Communication Control Register |
0x02000004 | CCSR | Link | COMCNT Control Register |
0x02000008 | CDTR | Link | Transmitted Data Register |
0x0200000C | CDRR | Link | Received Data Register |
0x02000010 | SDLR | Game Pad | Serial Data Low Register |
0x02000014 | SDHR | Game Pad | Serial Data High Register |
0x02000018 | TLR | Timer | Timer Counter Low Register |
0x0200001C | THR | Timer | Timer Counter High Register |
0x02000020 | TCR | Timer | Timer Control Register |
0x02000024 | WCR | Game Pak | Wait Control Register |
0x02000028 | SCR | Game Pad | Serial Control Register |
0x02000040 - 0x02FFFFFF
|
Mirroring of hardware component memory map |
Hardware I/O registers are intended to be accessed as bytes. However, the registers are spaced 4 bytes apart, so any type of access can be used with them.
Writing to unmapped addresses has no apparent effect, and all bits in any byte not listed above will be undefined when read.
Memory addresses 0xFFFFFDE0
- 0xFFFFFFF
must
contain specific kinds of data. Due to the address mirroring behavior of the
memory map, these addresses correspond with
addresses 0x07FFFDE0
- 0x07FFFFFF
in the
game pak ROM address range. The
significance of these addresses is described below.
Due to the address mirroring behavior of the game pak ROM address range in
all commercial game paks, addresses starting at 0x07FFFDE0
are
traditionally located at the end of the ROM data, regardless of the size of
the ROM module.
Memory addresses 0xFFFFFDE0
- 0xFFFFFDFF
contain
the ROM header:
0xFFFFFDE0 - 0xFFFFFDF3 |
Title |
0xFFFFFDF4 - 0xFFFFFDF8 |
Reserved |
0xFFFFFDF9 - 0xFFFFFDFA |
Maker code |
0xFFFFFDFB - 0xFFFFFDFE |
Game code |
0xFFFFFDFF |
Version |
Title | The game's title in Shift JIS character encoding. |
Reserved | Reserved bytes and should be zeroes. |
Maker code | A 2-character ASCII identifier for the game's developer. |
Game code | A 4-character ASCII identifier for the game. |
Version | An unsigned byte representing the minor version number of the software. The major version number is always 1. |
Nintendo maintains a list of maker codes that is beyond the scope of this document.
The game codes for commercial software are printed on the packaging and game pak labels.
Memory addresses 0xFFFFFE00
- 0xFFFFFFFF
contain
the CPU
exception handlers:
0xFFFFFE00 - 0xFFFFFE0F |
Game pad interrupt |
0xFFFFFE10 - 0xFFFFFE1F |
Timer zero interrupt |
0xFFFFFE20 - 0xFFFFFE2F |
Game pak interrupt |
0xFFFFFE30 - 0xFFFFFE3F |
Communication interrupt |
0xFFFFFE40 - 0xFFFFFE4F |
VIP interrupt |
0xFFFFFE50 - 0xFFFFFEFF |
Unused |
0xFFFFFF00 - 0xFFFFFF5F |
Unused |
0xFFFFFF60 - 0xFFFFFF6F |
Floating-point exception |
0xFFFFFF70 - 0xFFFFFF7F |
Unused |
0xFFFFFF80 - 0xFFFFFF8F |
Zero division exception |
0xFFFFFF90 - 0xFFFFFF9F |
Illegal opcode exception |
0xFFFFFFA0 - 0xFFFFFFAF |
TRAP instruction (vector < 16) |
0xFFFFFFB0 - 0xFFFFFFBF |
TRAP instruction (vector ≥ 16) |
0xFFFFFFC0 - 0xFFFFFFCF |
Address trap |
0xFFFFFFD0 - 0xFFFFFFDF |
Duplexed exception |
0xFFFFFFE0 - 0xFFFFFFEF |
Unused |
0xFFFFFFF0 - 0xFFFFFFFF |
Reset |
The data at these addresses is CPU instructions for processing the exceptions. At 16 bytes each, there is enough room to construct an address and jump to it.
Overview
Specifications
Data Types
Register Set
Instruction Cache
Instruction Formats
Exceptions
Exceptions
Exception Processing
List of Exceptions
Instruction Set
Memory and Register
Arithmetic
Bitwise
CPU Control
Floating-Point
Bit Strings
Miscellaneous
Nintendo
Appendix
Assembly Notation
Condition Numbers
Opcode Map
System Register Numbers
Virtual Boy uses a modified NEC V810 CPU called NVC:
Name: | NVC |
Bus width: | 16 bits |
Clock speed: | 20.0 MHz |
General registers: | 32 |
Instruction cache: | 1 KiB |
Instruction set: | RISC |
Manufacturer: | Nintendo |
Word size: | 32 bits |
Year: | 1995 |
A handful of instructions were added by Nintendo, but otherwise the processor is the same as the stock V810.
The I/O bus is mapped to the memory bus: all read and write instructions access the same data.
Editor's Note: Three system registers are functional on NVC that are not mentioned in the V810 manual. It's possible Nintendo may have introduced them, but so far no record of where they came from can be found.
Operations on NVC registers can take place on five different types of data:
Byte | An 8-bit, two's complemement integer. |
Halfword | A 16-bit, two's complemement integer. |
Word | A 32-bit, two's complemement integer. |
Floating Short | A 32-bit floating-point value in the IEEE 754-1985 format. Only normal real numbers and zero are accepted by the CPU: indefinites, NaNs and non-zero denormal values are regarded as invalid operands and cannot be processed. |
Bit String | A sequence of contiguous bits, starting at a given offset (0 to 31) within a given word in memory and extending for a given number of bits in length. For more information, see Bit Strings. |
All multi-byte data types are accessed in memory with the lowest-order byte at the lowest address within the data type (little-endian).
Memory accesses are aligned: the address being accessed is divisible by the number of bytes in the corresponding data type. If an unaligned access is attempted, the lowest-order bits of the address are ignored and the effective address is rounded down to the next lower multiple of the size in bytes of the data type.
Dedicated instructions exist for converting between word and floating short data types.
All CPU registers are 32 bits wide.
The program counter (PC
) stores the address of the current
instruction being executed. After an instruction completes, the address in
PC
is updated in preparation of the next instruction. This is
done automatically, although a branch or jump instruction specifies the new
address directly.
If an instruction raises an exception,
PC
will generally not be changed. Accordingly, it is the
responsibility of the exception handler to modify the corresponding "PC"
status-saving register before
returning in order to prevent the exception from immediately being raised
again.
The lowest-order bit of PC
is always clear: instructions always
begin on a 16-bit boundary.
There are 32 general-purpose registers that can be used by programs for
whatever reason, called program registers. Program registers are named
r0
through r31
and they all behave the same way,
with the exception of r0
, which has a fixed value of zero.
While program registers can be used for whatever purpose by the program, specific registers are used by certain instructions as input or output targets. The following program registers have significance regarding the execution of CPU instructions:
r0 | Contains a fixed value of zero. | ||||||||
r26 | Bit string destination bit offset. | ||||||||
r27 | Bit string source bit offset. | ||||||||
r28 | Bit string length. | ||||||||
r29 |
Multiple uses:
|
||||||||
r30 |
Multiple uses:
|
||||||||
r31 | Stores the return address of the JAL instruction. |
Certain program registers have names according to their intended use by compilers and assemblers:
r0 | Zero Register | Contains a fixed value of zero. | |
r1 | Assembler Reserved | To be used for the construction 32-bit immediate data. | |
r2 | hp | Handler Stack Pointer | Stack pointer within exception handlers. [note] |
r3 | sp | Stack Pointer | Program stack pointer. Points to the value most recently added to the stack ("full stack" convention). |
r4 | gp | Global Pointer | References global memory. |
r5 | tp | Text Pointer | References the beginning of text data. [note] |
r31 | lp | Link Pointer | Return address of a function call. |
[note] | These registers have no designated purpose on Virtual Boy. |
Upon entering a function, the calling convention defines the following roles for program registers:
r6 | First argument, if applicable. |
r7 | Second argument, if applicable. |
r8 | Third argument, if applicable. |
r9 | Fourth argument, if applicable. |
r31 | Return address. |
When a function completes, any return value will be stored in
r10
.
If more than four arguments are passed to a function, additional arguments
will be located on the stack such that the fifth argument is pointed to by
r3 + 16
and subsequent arguments follow at consecutively higher
addresses. The callee is not responsible for cleaning up these arguments from
the stack before returning: the value of r3
will remain the same
when returning as it was upon entering the function.
The 16 bytes preceding the fifth argument on the stack are designated as spill space in the caller's stack frame and may be written by the callee.
Registers r1
and r6
through r31
are
not guaranteed to be preserved during a function call.
Editor's Note: Is it correct that the spill area is in the caller's stack frame? Is it absent when fewer than five arguments are present?
System registers are additional registers that can't be used by the program directly, but represent and configure CPU operating behavior. There are 13 system registers:
25 | ADTRE | Address Trap Register for Execution | Configures the execution address for the hardware breakpoint. |
24 | CHCW | Cache Control Word | Configures the instruction cache. |
4 | ECR | Exception Cause Register | Stores values indicating the source of exceptions or interrupts. |
0 | EIPC | Exception/Interrupt PC | Stores the value to restore to PC when an exception finishes processing. |
1 | EIPSW | Exception/Interrupt PSW | Stores the value to restore to PSW when an exception finishes processing. |
2 | FEPC | Fatal Error PC |
Stores the value to restore to PC when a duplexed exception finishes
processing.
|
3 | FEPSW | Fatal Error PSW |
Stores the value to restore to PSW when a duplexed exception
finishes processing.
|
6 | PIR | Processor ID Register | Indicates to the program what kind of processor it's being run on. |
5 | PSW | Program Status Word | Contains status flags and the interrupt masking level. |
7 | TKCW | Task Control Word | Specifies the behavior of floating-point instructions. |
29 | 29 [note] | This system register has unknown significance. | |
30 | 30 [note] | This system register has unknown significance. | |
31 | 31 [note] | Calculates the absolute value of the number written into it. |
[note] | The official names of these system registers are unknown. |
System registers can be accessed by the program through the LDSR and STSR instructions, which transfer values between system registers and program registers.
The format and functionality of each system register is described below.
ADTRE
- Address Trap Register for ExecutionConfigures the execution address of the address trap, which is a hardware breakpoint feature.
31 | 0 | ||||||||||||||||||||||||||||||
TA | |||||||||||||||||||||||||||||||
32 |
TA | Trap Address | R/W | The memory address to monitor for address traps. The lowest-order bit is always clear. |
CHCW
- Cache Control WordConfigures the instruction cache. The significance of the bits varies depending on the context in which the register is used:
31 | 20 | 19 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||||||||||||||||||||
CEN | CEC | RFU | ICR |
ICD |
RFU | ICE |
ICC |
||||||||||||||||||||||||
12 | 12 | 2 | 1 | 1 | 2 | 1 | 1 |
31 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||||||||||||||||||||||
SA | RFU | ICR |
ICD |
RFU | ICE |
ICC |
|||||||||||||||||||||||||
24 | 2 | 1 | 1 | 2 | 1 | 1 |
RFU | Reserved for Future Use | R | These bits have no function and are read as zeroes. |
CEN | Clear Entry Number | W | The index of the first cache entry to clear. Read as zeroes. |
CEC | Clear Entry Count | W | The number of cache entries to clear. Read as zeroes. |
SA | Spill-Out Base Address | W | The higher 24 bits of of the address to use for dump and restore operations. The lower 8 bits will be zero. Read as zeroes. |
ICR | Instruction Cache Restore | W | When set, a cache restore operation is performed. Read as zero. |
ICD | Instruction Cache Dump | W | When set, a cache dump operation is performed. Read as zero. |
ICE | Instruction Cache Enable | R/W | When set, the instruction cache is enabled. |
ICC | Instruction Cache Clear | W | When set, a cache clear operation is performed. Read as zero. |
If CEN
≥ 128, no dump or restore operation will be performed.
If CEC
> 128, the actual number of entries to clear becomes
128.
A clear operation will stop after it clears entry 127.
If more than one of ICR
, ICD
or ICC
are specified simultaneously, the operation is undefined.
ECR
- Exception Cause RegisterIndicates the source of an exception:
31 | 16 | 15 | 0 | ||||||||||||||||||||||||||||
FECC | EICC | ||||||||||||||||||||||||||||||
16 | 16 |
FECC | Fatal Error Cause Code | R | The exception code of the source of a duplexed exception. |
EICC | Exception/Interrupt Cause Code | R | The exception code of the source of a regular exception or interrupt. |
This register cannot be modified by the LDSR instruction.
EIPC
,
EIPSW
, FEPC
, FEPSW
-
Status-saving registersWhenever an exception occurs, the values of PC and PSW are copied into the corresponding status-saving registers prior to handling the exception:
• |
EIPC , EIPSW in case of a regular exception or
interrupt.
|
• |
FEPC , FEPSW in case of a duplexed exception.
|
EIPC
and FEPC
share the same format as
PC
: the lowest-order bit is always clear.
EIPSW
and FEPSW
share the same format as
PSW
: reserved bits in PSW
likewise cannot be
written in EIPSW
or FEPSW
.
PIR
- Processor ID RegisterContains the identification code of the processor:
31 | 16 | 15 | 0 | ||||||||||||||||||||||||||||
RFU | PT | ||||||||||||||||||||||||||||||
16 | 16 |
RFU | Reserved for Future Use | R | These bits have no function and are read as zeroes. |
PT | Processor Type | R | The numeric value 0x5346 . |
This register is read-only and contains a fixed value of
0x00005346
.
Editor's Note: The NVC format of PIR differs slightly from the V810 format.
PSW
- Program Status WordContains status flags and an interrupt masking level:
31 | 20 | 19 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||||||||||||
RFU | I | NP |
EP |
AE |
ID |
RFU | FRO |
FIV |
FZD |
FOV |
FUD |
FPR |
CY |
OV |
S | Z | |||||||||||||||
12 | 4 | 1 | 1 | 1 | 1 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
RFU | Reserved for Future Use | R | These bits have no function and are read as zeroes. |
I | Interrupt Level | R/W |
If an interrupt is requested and the interrupt's level is less than
I , the interrupt will be masked.
|
NP | NMI Pending | R/W | Set during processing of a duplexed exception or reset. |
EP | Exception Pending | R/W | Set during processing of an exception or interrupt. |
AE | Address Trap Enable | R/W | If set, the address trap feature will be enabled. |
ID | Interrupt Disable | R/W | If set, all interrupts will be masked. |
FRO | Floating Reserved Operand | R/W | Set when a floating-point operation is attempted with a reserved operand. |
FIV | Floating Invalid | R/W | Set when an invalid floating-point operation attempted. |
FZD | Floating Zero Divide | R/W | Set when the DIVF.S instruction is executed with a divisor of zero. |
FOV | Floating Overflow | R/W | Set when the result of a floating-point operation is too large to be represented by the floating short data type. |
FUD | Floating Underflow | R/W | Set when the result of a floating-point operation is too small to be represented as a normal floating short value. |
FPR | Floating Precision | R/W | Set when the result of a floating-point operation is subjected to rounding and suffers precision degradation. |
CY | Carry | R/W | Set when an operation produces a carry. |
OV | Overflow | R/W | Set when an operation results in integer overflow. |
S | Sign | R/W | Set when the result of an operation is negative. |
Z | Zero | R/W | Set when the result of an operation is zero. |
During the operation of the Bcond and
SETF instructions, certain flag state
combinations are checked in PSW
.
TKCW
- Task Control WordSpecifies how floating-point operations are to be processed:
31 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||||||||||||||||||||
RFU | OTM |
FIT |
FZT |
FVT |
FUT |
FPT |
RDI |
RD | |||||||||||||||||||||||
23 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 |
RFU | Reserved for Future Use | R | These bits have no function and are read as zeroes. | ||||||||
OTM | Operand Trap Mask | R | If set, floating-point invalid operand exceptions will be masked. | ||||||||
FIT | Floating Invalid Operation Trap Enable | R | If set, floating-point invalid operation exceptions will be enabled. | ||||||||
FZT | Floating-Zero Divide Trap Enable | R | If set, floating-point zero division exceptions will be enabled. | ||||||||
FVT | Floating-Overflow Trap Enable | R | If set, floating-point overflow exceptions will be enabled. | ||||||||
FUT | Floating-Underflow Trap Enable | R | If set, floating-point underflow exceptions will be enabled. | ||||||||
FPT | Floating-Precision Trap Enable | R | If set, floating-point precision degradation exceptions will be enabled. | ||||||||
RDI |
Floating Rounding Control Bit for Integer Conversion |
R |
Specifies the direction of floating-point rounding operations when
converting to integer:
|
||||||||
RD | Floating Rounding Control | R |
Specifies the direction of floating-point rounding operations:
|
This register is read-only and contains a fixed value of
0x000000E0
. This corresponds to the following configuration:
OTM | = 0 | Invalid operand exceptions will be raised. |
FIT | = 1 | Invalid operation exceptions will be raised. |
FZT | = 1 | Zero-division exceptions will be raised. |
FVT | = 1 | Overflow exceptions will be raised. |
FUT | = 0 | Underflow exceptions will not be raised. |
FPT | = 0 | Precision degradation exceptions will not be raised. |
RDI | = 0 | Rounding to integer uses nearest value. |
RD | = 0 | Rounding to floating short uses nearest value. |
Editor's Note: Since this register was never intended to be modifiable, the
effects of other values for RDI
and RD
were not
provided in the documentation for the V810 or V830 processors.
29
- System register 29This register has unknown significance:
31 | 0 | ||||||||||||||||||||||||||||||
??? | |||||||||||||||||||||||||||||||
32 |
??? | R/W | Unknown. All 32 bits of this field can be read and written. |
30
- System register 30This register has unknown significance:
31 | 0 | ||||||||||||||||||||||||||||||
??? | |||||||||||||||||||||||||||||||
32 |
??? | R | Unknown. |
This register is read-only and contains a fixed value of
0x00000004
.
31
- System register 31Calculates the absolute value of a signed word:
31 | 0 | ||||||||||||||||||||||||||||||
??? | |||||||||||||||||||||||||||||||
32 |
??? | R/W | Any signed word value. |
Reading from this register will give the absolute value of the most recent value written to it.
NVC provides 1 KiB of CPU instruction cache. There are 128 cache entries with a block size of 8 bytes each for a total of 1,024 bytes of cache memory. The benefit of using the instruction cache is to accelerate the execution of program code. This is accomplished by storing program code directly on the CPU so that it doesn't need to be read from the memory bus every time it is needed.
The instruction cache is managed through the CHCW system regster. Cache entries can be cleared directly, and the full contents of the cache can be dumped to and restored from main memory.
Associated with each cache entry is a tag representing the upper 22 bits of the memory address of the corresponding data, and a bit specifying whether the entry contains valid cached data. These fields are used in conjunction with the block memory to represent the cached data.
When an instruction fetch read is performed, the address to be accessed is parsed in the following way:
31 | 10 | 9 | 3 | 2 | 0 | ||||||||||||||||||||||||||
Tag | Index | Offset | |||||||||||||||||||||||||||||
22 | 7 | 3 |
Tag | The upper bits of the source address of the block data. |
Index | The index of the cache entry that may contain the requested data. |
Offset | The position within the block data being requested. |
The cache entry is selected by Index
. If the entry does not
contain valid data or if its tag does not match Tag
, the
corresponding data is read from memory and stored into the cache entry.
During dump and restore operations, both the block data and the tag data are
written to/read from main memory. At the memory location specified by
SA
in CHCW
, all 128 8-byte blocks are stored in
order, followed by all 128 4-byte tags for a total of 1,536 bytes.
The format of the tag data dumped or restored for one cache entry is as follows:
31 | 28 | 27 | 23 | 22 | 21 | 0 | |||||||||||||||||||||||||
- | NECRV | Valid |
TAG | ||||||||||||||||||||||||||||
4 | 5 | 1 | 22 |
- | Unused. Tag memory in the cache is only 27 bits wide. | |
NECRV | NEC Reserved | The significance of this field is not documented. |
Valid | Valid bit | Set if the entry contains actual cache data. |
TAG | Tag | The upper 22 bits of the corresponding memory address. |
Valid
can be explicitly reset by performing a clear operation
through CHCW
. This will immediately free the cache entry and the
next access whose Index
matches will be loaded into cache
memory.
Interrupts are postponed until the completion of dump and restore operations.
Instructions are fetched as halfword units from the bus and may be 16 or 32 bits in size. A common opcode field is present in the highest-order bits of the first halfword of every instruction, which is used to determine the instruction's binary format and whether an additional 16 bits need to be fetched.
If an instruction is 32 bits in size, a second halfword is fetched from the bus at the immediate next higher halfword address. The resulting word value is formed by taking the first halfword (bits 0-15) as the upper 16 bits and the second halfword (bits 16-31) as the lower 16 bits.
Every instruction is encoded into one of seven binary formats, referred to as Format I through Format VII. The structure of each of these instruction formats is described below.
16 bits. Used for register-to-register operations.
15 | 10 | 9 | 5 | 4 | 0 | ||||||||||
opcode | reg2 | reg1 | |||||||||||||
6 | 5 | 5 |
opcode | The instruction's opcode. |
reg2 | Destination register and left-hand operand. |
reg1 | Source register and right-hand operand. |
16 bits. Used for immediate-to-register operations.
15 | 10 | 9 | 5 | 4 | 0 | ||||||||||
opcode | reg2 | imm | |||||||||||||
6 | 5 | 5 |
15 | 10 | 9 | 5 | 4 | 3 | 0 | |||||||||
opcode | reg2 | - | cond | ||||||||||||
6 | 5 | 1 | 4 |
15 | 10 | 9 | 5 | 4 | 0 | ||||||||||
opcode | reg2 | regID | |||||||||||||
6 | 5 | 5 |
15 | 10 | 9 | 5 | 4 | 0 | ||||||||||
opcode | reg2 | vector | |||||||||||||
6 | 5 | 5 |
15 | 10 | 9 | 5 | 4 | 0 | ||||||||||
opcode | reg2 | sub-opcode | |||||||||||||
6 | 5 | 5 |
- | This bit has no significance. |
opcode | The instruction's opcode. |
reg2 | Destination register and left-hand operand. |
imm | Source value and right-hand operand. |
cond | Condition for the SETF instruction. |
regID | The zero-extended system register index for the LDSR and STSR instructions. |
vector | The zero-extended vector for the TRAP instruction. |
sub-opcode | Additional opcode bits for bit string instructions. |
Depending on the instruction, imm
may or may not be
sign-extended.
16 bits. Used by the Bcond instruction for short-distance branches.
15 | 13 | 12 | 9 | 8 | 0 | ||||||||||
opcode | cond | disp | |||||||||||||
3 | 4 | 9 |
opcode | The instruction's opcode. |
cond | Condition for branch to occur. |
disp | Sign-extended displacement offset. |
For the numeric codes of each condition, see Bcond.
The displacement offset is measured in bytes relative to the address of the first byte of the instruction.
This is the only format that does not have a 6-bit opcode field. The 3 bits
that represent the Bcond
instruction's opcode (100
)
are not shared as the upper 3 bits of any other instruction's opcode.
32 bits. Used for middle-distance jumps using a displacement offset.
15 | 10 | 9 | 0 | 31 | 16 | ||||||||||||||||||||||||||
opcode | disp | ||||||||||||||||||||||||||||||
6 | 26 |
opcode | The instruction's opcode. |
disp | Sign-extended displacement offset. |
The displacement offset is measured in bytes relative to the address of the first byte of the instruction.
32 bits. Used for operations that require three operands.
15 | 10 | 9 | 5 | 4 | 0 | 31 | 16 | ||||||||||||||||||||||||
opcode | reg2 | reg1 | imm | ||||||||||||||||||||||||||||
6 | 5 | 5 | 16 |
opcode | The instruction's opcode. |
reg2 | Destination register. |
reg1 | Source register and left-hand operand. |
imm | Source value and right-hand operand. |
Depending on the instruction, imm
may or may not be
sign-extended.
32 bits. Used for memory access operations.
15 | 10 | 9 | 5 | 4 | 0 | 31 | 16 | ||||||||||||||||||||||||
opcode | reg2 | reg1 | disp | ||||||||||||||||||||||||||||
6 | 5 | 5 | 16 |
opcode | The instruction's opcode. |
reg2 | Data register. |
reg1 | Base address register. |
disp | Sign-extended address displacement offset. |
The effective address of the memory access operation is determined by adding
disp
to the value in register reg1
.
For load and input operations, register reg2
receives the value
read. For store and output operations, it supplies the value to write.
32 bits. Functions similarly to Format I, but with additional opcodes.
15 | 10 | 9 | 5 | 4 | 0 | 31 | 26 | 25 | 16 | ||||||||||||||||||||||
opcode | reg2 | reg1 | sub-opcode | RFU | |||||||||||||||||||||||||||
6 | 5 | 5 | 6 | 10 |
opcode | The instruction's opcode. |
reg2 | Destination register and left-hand operand. |
reg1 | Source register and right-hand operand. |
sub-opcode | Additional opcode bits. |
RFU | Reserved for Future Use. These bits are ignored. |
Certain events can cause the CPU to break its current execution, save its status and begin execution somewhere else according to what happened. The general term for such an occurrence is exception, and exceptions come in three froms:
Exception | The processing of an instruction resulted in a error condition. |
Interrupt | A hardware component requested a program break. |
Address Trap | A hardware execute breakpoint was triggered. |
Every exception has an associated 16-bit code and a 32-bit handler address. When an exception is raised, the code is stored into ECR and the handler address into PC. For a list of codes and handler addresses, see List of Exceptions.
Processing of CPU instructions can raise exceptions on their own. This can happen in the following situations:
• | The opcode or sub-opcode of the instruction being decoded does not correspond with any valid instruction. |
• | The operation cannot be performed with the given operands. |
• | The TRAP instruction was executed. |
Hardware components other than the CPU are allowed to request interrupts. This provides a mechanism to synchronize all system operations as well as a way for a hardware component to signal the program when certain conditions are met.
Interrupts can be disabled by setting the ID
flag in PSW. The CLI and SEI
instructions manipulate this flag directly, and the LDSR instruction can also be used to configure it.
Each hardware component that can request an interrupt is assigned a numeric
level. Interrupts with greater levels are given priority over and are
accepted before interrupts with lesser levels. If the interrupt's level is
less than the value of the I
field in PSW
, the
interrupt request will be ignored.
When an interrupt is requested, it will not be accepted until after the current CPU instruction or cache dump or restore operation has finished processing.
Interrupts are ignored during exception processing: when either of the
EP
or NP
flags is set in PSW
.
The HALT instruction will stop all CPU activity until an interrupt request is accepted, at which point it will resume with exception processing.
A hardware breakpoint can be configured to raise an exception when the CPU is about to execute an instruction at the configured address.
The ADTRE system register can be
configured with the breakpoint address, and the address trap function can be
enabled by setting the AE
flag in PSW. Under these conditions, if the value of PC matches ADTRE
prior to fetching the instruction at that address, an address trap exception
will be raised.
If an exception is raised during the processing of another exception, a duplexed exception occurs. The return status of both exceptions is held in ECR and the status-saving registers, and a special handler specifically for duplexed exceptions is run.
If an exception is raised during the processing of a duplexed exception, a fatal exception occurs. Debugging information is written to the memory bus and the CPU enters a permanent halt state until reset. For more information, see Exception Processing.
PC
When exception handling begins, the contents of
PC and PSW are transferred into the appropriate status-saving
registers. The value used for PC
in this case is known as the
restore PC
, and is determined relative to the address of
the current instruction being executed.
The following exceptions will use the address of the current instruction,
known as current PC
, as the restore PC
:
• | Any regular exception not raised by the TRAP instruction. |
• | Any interrupt that is accepted during the processing of a bit string instruction. |
• | An address trap. |
The following exceptions will use the address of the following instruction,
known as next PC
, as the restore PC
:
• | The TRAP instruction. |
• | Any interrupt that does not occur during the processing of a bit string instruction. |
An interrupt that is requested will only be accepted if all of the following conditions are met:
• | ID = 0 in PSW. |
• | EP = 0 in PSW . |
• | NP = 0 in PSW . |
• |
I in PSW is less than or equal to the
interrupt's level.
|
When an exception is raised, the following algorithm is carried out:
♦ |
If the NP flag in PSW is
set, a fatal exception occurs:
|
||||||||||
♦ |
If the EP flag in PSW is set, a
duplexed exception occurs:
|
||||||||||
◊ |
Else, a regular exception occurs:
|
||||||||||
♦ |
If the exception was an interrupt:
|
||||||||||
▪ | The ID flag in PSW is set. |
||||||||||
▪ | The AE flag in PSW is cleared. |
[note] |
If an interrupt's level is 15, 15 will be stored into the I
field of PSW . This will never occur on an unmodified Virtual
Boy because no interrupt is assigned level 15.
|
Editor's Note: Research is needed to determine the number of cycles taken by this process.
When handling of an exception is completed, control is returned to the program with the RETI instruction.
According to the NP
flag of PSW, RETI
will restore PC and PSW
from the appropriate
status-saving registers.
Name | Type | Code | Level | Handler Address |
Restore PC
|
Note |
---|---|---|---|---|---|---|
Reset | Interrupt | 0xFFF0 | - | 0xFFFFFFF0 | - | Occurs at system power-on |
Duplexed exception | Exception | - | - | 0xFFFFFFD0 | Current PC | Exception during exception processing |
VIP | Interrupt | 0xFE40 | 4 | 0xFFFFFE40 | [note] | Various video conditions |
Communication | Interrupt | 0xFE30 | 3 | 0xFFFFFE30 | [note] | Completion of communication port transfer |
Game Pak | Interrupt | 0xFE20 | 2 | 0xFFFFFE20 | [note] | Initiated by the game pak |
Timer Zero | Interrupt | 0xFE10 | 1 | 0xFFFFFE10 | [note] | The timer counter reached zero |
Game Pad | Interrupt | 0xFE00 | 0 | 0xFFFFFE00 | [note] | Controller button press |
Address trap | Address trap | 0xFFC0 | - | 0xFFFFFFC0 | Current PC | Hardware breakpoint |
TRAP instruction
(vector < 16)
|
Exception | 0xFFA0 + vector |
- | 0xFFFFFFA0 | Next PC | Instruction operation |
TRAP instruction (vector ≥ 16)
|
Exception | 0xFFA0 + vector |
- | 0xFFFFFFB0 | Next PC | Instruction operation |
Illegal opcode | Exception | 0xFF90 | - | 0xFFFFFF90 | Current PC | Invalid opcode or sub-opcode |
Zero division | Exception | 0xFF80 | - | 0xFFFFFF80 | Current PC | Integer division by zero |
Floating-point reserved operand | Exception | 0xFF60 | - | 0xFFFFFF60 | Current PC | Indefinites, NaNs or non-zero denormals |
Floating-point invalid operation | Exception | 0xFF70 | - | 0xFFFFFF60 | Current PC | Undefined operation |
Floating-point zero division | Exception | 0xFF68 | - | 0xFFFFFF60 | Current PC | Division by zero |
Floating-point overflow | Exception | 0xFF64 | - | 0xFFFFFF60 | Current PC | Result is too large for data type |
[note] |
If an interrupt occurs during the processing of a bit string instruction, current
PC is used. Otherwise, next PC is used.
|
This list is ordered such that items that appear earlier in the list have higher priority than items that appear later in the list. If any two exceptions should coincide, the one with the highest priority is the one that will be processed.
Although interrupts are given high priority, they cannot occur simultaneously
with instruction exceptions because the CPU checks for interrupt requests in
between executing instructions. Bit string instructions are not actually
interrupted during processing, but rather they are executed repeatedly and
only update PC
once they fully complete.
The reset interrupt is automatically acknowledged when the CPU is
initialized. PSW
is initialized in such a way that the
I
field is zero, so reset has no meaningful interrupt level.
If a floating-point instruction satisfies multiple error conditions (such as
dividing NaN by zero), only the one with the highest priority will be
processed and have its status flag set in PSW
.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
MOV | 010000 | II | - | - | - | - | 1 | Move Immediate | reg2 = (sign extend) imm |
MOV | 000000 | I | - | - | - | - | 1 | Move Register | reg2 = reg1 |
MOVEA | 101000 | V | - | - | - | - | 1 | Add |
reg2 = reg1 + (sign extend) imm
|
MOVHI | 101111 | V | - | - | - | - | 1 | Add |
reg2 = reg1 + (imm << 16)
|
The purpose of the MOVEA
and MOVHI
instructions is
to provide a means for populating a register with 32 bits of immediate data
without modifying the status flags in
PSW.
Since MOVEA
sign-extends its immediate value, care needs to be
taken to ensure that the appropriate value is stored in the upper halfword of
the register via MOVHI
.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
IN.B | 111000 | VI | - | - | - | - | * | Input Byte from Port |
reg2 = (zero extend) (byte ptr) [reg1 +
disp ]
|
IN.H | 111001 | VI | - | - | - | - | * | Input Halfword from Port |
reg2 = (zero extend) (halfword ptr) [reg1 +
disp ]
|
IN.W | 111011 | VI | - | - | - | - | * | Input Word from Port |
reg2 = (word ptr) [reg1 + disp ]
|
LD.B | 110000 | VI | - | - | - | - | * | Load Byte |
reg2 = (sign extend) (byte ptr) [reg1 +
disp ]
|
LD.H | 110001 | VI | - | - | - | - | * | Load Halfword |
reg2 = (sign extend) (halfword ptr) [reg1 +
disp ]
|
LD.W | 110011 | VI | - | - | - | - | * | Load Word |
reg2 = (word ptr) [reg1 + disp ]
|
Halfword operations will mask the lowest bit of the effective address to 0, and word operations will mask the two lowest bits to 0. This ensures that data in memory is accessed on a boundary the same size as the data type.
Since Virtual Boy maps the I/O bus to the memory bus, the input instructions access the same data as the load instructions. They're nearly identical in function, except the input instructions zero-extend the data being read whereas the load instructions sign-extend it.
The number of cycles taken by load instructions depends on prior bus activity:
1 cycle | When used immediately after an instruction that takes many cycles [note] and which does not conflict with the operation of the load instruction. |
4 cycles | When immediately following another load instruction. |
5 cycles | When used in an isolated context. |
[note] Editor's Note: The V810 documentation uses the phrase "many cycles" with regards to a one-cycle load operation, but it doesn't explicitly define exactly how many is "many". Logic suggests that the instruction needs only take long enough for the pipeline to ready the load operation with its effective address, then can immediately execute it when the long instruction finishes. Either way, this needs some research.
Editor's Note: The cycle counts for input instructions needs to be researched, as they may be identical to the load instructions' counts.
Editor's Note: While the number of CPU cycles taken for an input or load instruction may be small, the actual amount of time taken depends on the speed of whatever is being accessed on the bus (video memory, WRAM, etc.). The exact latencies for reads needs to be researched.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
OUT.B | 111100 | VI | - | - | - | - | * | Output Byte to Port |
(byte ptr) [reg1 + disp ] = reg2
AND 0xFF
|
OUT.H | 111101 | VI | - | - | - | - | * | Output Halfword to Port |
(halfword ptr) [reg1 + disp ] = reg2
AND 0xFFFF
|
OUT.W | 111111 | VI | - | - | - | - | * | Output Word to Port |
(word ptr) [reg1 + disp ] = reg2
|
ST.B | 110100 | VI | - | - | - | - | * | Store Byte |
(byte ptr) [reg1 + disp ] = reg2
AND 0xFF
|
ST.H | 110101 | VI | - | - | - | - | * | Store Halfword |
(halfword ptr) [reg1 + disp ] = reg2
AND 0xFFFF
|
ST.W | 110111 | VI | - | - | - | - | * | Store Word |
(word ptr) [reg1 + disp ] = reg2
|
Halfword operations will mask the lowest bit of the effective address to 0, and word operations will mask the two lowest bits to 0. This ensures that data in memory is accessed on a boundary the same size as the data type.
Since Virtual Boy maps the I/O bus to the memory bus, the output instructions access the same data as the store instructions. They're identical in function.
The number of cycles taken by store instructions depends on prior bus activity:
1 cycle | The first two consecutive executions of store instructions. |
4 cycles | Subsequent consecutive executions. |
Editor's Note: The cycle counts for output instructions needs to be researched, as they may be identical to the store instructions' counts.
Editor's Note: While the number of CPU cycles taken for an output or store instruction may be small, the actual amount of time taken depends on the speed of whatever is being accessed on the bus (video memory, WRAM, etc.). The exact latencies for writes needs to be researched.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
ADD | 010001 | II | ✓ | ✓ | ✓ | ✓ | 1 | Add Immediate |
reg2 = reg2 + (sign extend) imm
|
ADD | 000001 | I | ✓ | ✓ | ✓ | ✓ | 1 | Add Register |
reg2 = reg2 + reg1
|
ADDI | 101001 | V | ✓ | ✓ | ✓ | ✓ | 1 | Add Immediate |
reg2 = reg1 + (sign extend) imm
|
CMP | 010011 | II | ✓ | ✓ | ✓ | ✓ | 1 | Compare Immediate |
(discard) = reg2 - (sign extend) imm
|
CMP | 000011 | I | ✓ | ✓ | ✓ | ✓ | 1 | Compare Register |
(discard) = reg2 - reg1
|
DIV | 001001 | I | ✓ | ✓ | ✓ | - | 38 | Divide |
r30 = reg2 MOD reg1 ,
reg2 = reg2 / reg1
|
DIVU | 001011 | I | ✓ | ✓ | 0 | - | 36 | Divide Unsigned |
r30 = reg2 MOD reg1 ,
reg2 = reg2 / reg1
|
MUL | 001000 | I | ✓ | ✓ | ✓ | - | 13 | Multiply |
(result) = reg2 * reg1 , r30 =
(result) >> 32, reg2 = (result)
|
MULU | 001010 | I | ✓ | ✓ | ✓ | - | 13 | Multiply Unsigned |
(result) = reg2 * reg1 , r30 =
(result) >> 32, reg2 = (result)
|
SUB | 000010 | I | ✓ | ✓ | ✓ | ✓ | 1 | Subtract |
reg2 = reg2 - reg1
|
Compare operations perform subtraction and update the status flags accordingly, but discard the result.
Division operations produce the arithmetic quotient without any fractional
part (round towards zero), and the remainder, which shares the same sign as
the dividend. The remainder is first stored into r30
, then the
result is stored into reg2
. If a division is attempted with a
divisor of zero, a Zero Division exception will
be raised with a code of 0xFF80
and a restore PC
of current
PC
.
The result of multiplication operations is 64 bits in size. The upper 32 bits
are first stored into r30
, then the lower 32 bits are stored
into reg2
.
The zero flag (Z
) is set when the result of any operation is
zero, or is cleared otherwise. For multiply operations, only the lower 32
bits of the result are considered.
The sign flag (S
) is a copy of the highest-order bit of the
result of any operation. For multiply operations, only the lower 32 bits of
the result are considered.
The overflow flag (OV
) is set in the following situations, or is
cleared otherwise:
• | The operands of an addition have the same sign and the result has the opposite sign. |
• | The operands of a subtraction have opposite signs and the left operand and result have opposite signs. |
• |
The DIV instruction is performed dividing
0x80000000 by -1. In this situation, the result is
0x80000000 and the remainder is zero.
|
• | The full 64-bit result of a multiplication is not equivalent to the 64-bit value produced by sign-extending (signed) or zero-filling (unsigned) the lower 32 bits of the product. |
The carry flag (CY
) is set when addition or subtraction results
in unsigned wrap-around, or is cleared otherwise. For example, carry will be
set when subtracting an unsigned value from a lesser value.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
AND | 001101 | I | ✓ | ✓ | 0 | - | 1 | And |
reg2 = reg2 AND reg1
|
ANDI | 101101 | V | ✓ | 0 | 0 | - | 1 | And Immediate |
reg2 = reg1 AND (zero extend) imm
|
NOT | 001111 | I | ✓ | ✓ | 0 | - | 1 | Not |
reg2 = NOT reg1
|
OR | 001100 | I | ✓ | ✓ | 0 | - | 1 | Or |
reg2 = reg2 OR reg1
|
ORI | 101100 | V | ✓ | ✓ | 0 | - | 1 | Or Immediate |
reg2 = reg1 OR (zero extend) imm
|
SAR | 010111 | II | ✓ | ✓ | 0 | ✓ | 1 | Shift Arithmetic Right by Immediate |
reg2 = reg2 >> (zero extend)
imm (sign-propagating)
|
SAR | 000111 | I | ✓ | ✓ | 0 | ✓ | 1 | Shift Arithmetic Right by Register |
reg2 = reg2 >> (reg1 AND
0x1F ) (sign-propagating)
|
SHL | 010100 | II | ✓ | ✓ | 0 | ✓ | 1 | Shift Logical Left by Immediate |
reg2 = reg2 << (zero extend)
imm
|
SHL | 000100 | I | ✓ | ✓ | 0 | ✓ | 1 | Shift Logical Left by Register |
reg2 = reg2 << (reg1 AND
0x1F )
|
SHR | 010101 | II | ✓ | ✓ | 0 | ✓ | 1 | Shift Logical Right by Immediate |
reg2 = reg2 >> (zero extend)
imm (zero-filling)
|
SHR | 000101 | I | ✓ | ✓ | 0 | ✓ | 1 | Shift Logical Right by Register |
reg2 = reg2 >> (reg1 AND
0x1F ) (zero-filling)
|
XOR | 001110 | I | ✓ | ✓ | 0 | - | 1 | Exclusive Or |
reg2 = reg2 XOR reg1
|
XORI | 101110 | V | ✓ | ✓ | 0 | - | 1 | Exclusive Or Immediate |
reg2 = reg1 XOR (zero extend) imm
|
Arithmetic right shift will produce copies of the highest-order bit when filling from the left. Logical right shift will fill with zeroes.
The zero flag (Z
) is set when the result of any operation is
zero, or is cleared otherwise.
The sign flag (S
) is a copy of the highest-order bit of the
result of any operation.
The carry flag (CY
) is a copy of the last bit shifted out of the
register during a shift operation, or cleared if the shift amount was zero.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
Bcond | 100 [note] |
III | - | - | - | - | * | Branch on Condition |
if cond = true then PC = PC +
disp
|
HALT | 011010 | II | - | - | - | - | - | Halt | Wait for interrupt |
JAL | 101011 | IV | - | - | - | - | 3 | Jump and Link |
r31 = PC + 4, PC = PC
+ disp
|
JMP | 000110 | I | - | - | - | - | 3 | Jump Register | PC = reg1 |
JR | 101010 | IV | - | - | - | - | 3 | Jump Relative | PC = PC + disp |
LDSR | 011100 | II | * | * | * | * | 8 | Load to System Register | SystemRegister[regID ] = reg2 |
RETI | 011001 | II | * | * | * | * | 10 | Return from Trap or Interrupt |
if NP = 1 then PC = FEPC ,
PSW = FEPSW else PC =
EIPC , PSW = EIPSW
|
STSR | 011101 | II | - | - | - | - | 8 | Store Contents of System Register | reg2 = SystemRegister[regID ] |
TRAP | 011000 | II | - | - | - | - | 15 | Trap | Raise exception (0xFFA0 + vector ) |
[note] |
Format III has a 3-bit opcode field. No
other instruction contains an opcode whose highest 3 bits match the
opcode of Bcond .
|
If the Bcond
instruction's condition as specified by
cond
in PSW is true, then
PC is updated directly.
Otherwise, PC
advances to the next instruction as usual.
The HALT
instruction will cause the CPU to stop all processing
until an interrupt is accepted. If all
interrupts are masked or disabled, HALT
cannot finish and the
CPU will be stopped until reset.
Because the lowest-order bit of PC is always clear, the effective addresses of branch and jump instructions will have their lowest bit masked to a 16-bit boundary.
Status flags in PSW will only be modified
by the LDSR
instruction if PSW
itself is the system register being loaded into. Their
states are determined directly by the value being loaded.
The resulting exception raised by the
TRAP
instruction will have a code of (0xFFA0
+
vector
) and a restore
PC
of next PC
.
The number of cycles taken by Bcond
varies depending on whether
the branch is taken:
1 cycle | The branch is not taken. |
3 cycles | The branch is taken. |
All conditional branch instructions are permutations of the
Bcond
instruction, just with different values for
cond
. Each permutation is given its own mnemonic. The following
conditions and mnemonics can be checked by the Bcond
instruction:
Value | Mnemonic | Condition | Test | Note |
---|---|---|---|---|
0 | BV | Overflow | if OV = 1 |
|
1 | BC , BL |
Carry, Lower | if CY = 1 |
Unsigned |
2 | BE , BZ |
Equal, Zero | if Z = 1 |
|
3 | BNH | Not higher | if (CY OR Z ) = 1 |
Unsigned |
4 | BN | Negative | if S = 1 |
|
5 | BR | Always | if true | |
6 | BLT | Less than | if (OV XOR S ) = 1 |
Signed |
7 | BLE | Less than or equal |
if ((OV XOR S ) OR Z ) = 1
|
Signed |
8 | BNV | Not overflow | if OV = 0 |
|
9 | BNC , BNL |
Not carry, Not lower | if CY = 0 |
Unsigned |
10 | BNE , BNZ |
Not equal, Not zero | if Z = 0 |
|
11 | BH | Higher | if (CY OR Z ) = 0 |
Unsigned |
12 | BP | Positive | if S = 0 |
|
13 | NOP | Not always | if false | Never branches |
14 | BGE | Greater than or equal | if (OV XOR S ) = 0 |
Signed |
15 | BGT | Greater than |
if ((OV XOR S ) OR Z ) = 0
|
Signed |
Certain conditions have more than one mnemonic. In these situations, either mnemonic can be used and the two are interchangeable.
The Bcond
instruction's cond
field uses the same
numeric values for each condition as the
SETF instruction.
The following numeric codes for system registers are used by the
LDSR
and STSR
instructions:
0 | EIPC |
1 | EIPSW |
2 | FEPC |
3 | FEPSW |
4 | ECR [note] |
5 | PSW |
6 | PIR [note] |
7 | TKCW [note] |
⋯ | Reserved |
24 | CHCW |
25 | ADTRE |
⋯ | Reserved |
29 | 29 |
30 | 30 [note] |
31 | 31 |
[note] |
Attempting to load to these system registers with the LDSR
instruction will have no effect.
|
Attempting to load to a reserved system register will have no effect, and they are all read as zero.
Editor's Note: Research is needed to determine whether a conditional branch with a displacement to the following instruction still take 3 cycles, even though it's equivalent to a non-branch.
All of the floating-point instructions are stored in Format VII and share a common opcode of
111110
. They are identified by their sub-opcode
field.
Mnemonic | Sub-Opcode | Z | S | OV | CY | FRO | FIV | FZD | FOV | FUD | FPR | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ADDF.S | 000100 | ✓ | ✓ | 0 | ✓ | ✓ | - | - | ✓ | ✓ | ✓ | 9-28 | Add Floating Short | reg2 = reg2 + reg1 |
CMPF.S | 000000 | ✓ | ✓ | 0 | ✓ | ✓ | - | - | - | - | - | 7-10 | Compare Floating Short | (discard) = reg2 - reg1 |
CVT.SW | 000011 | ✓ | ✓ | 0 | - | ✓ | ✓ | - | - | - | ✓ | 9-14 | Convert Short Floating to Word Integer | reg2 = (word) round(reg1 ) |
CVT.WS | 000010 | ✓ | ✓ | 0 | ✓ | - | - | - | - | - | ✓ | 5-16 | Convert Word Integer to Short Floating | reg2 = (float) reg1 |
DIVF.S | 000111 | ✓ | ✓ | 0 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 44 | Divide Floating Short | reg2 = reg2 / reg1 |
MULF.S | 000110 | ✓ | ✓ | 0 | ✓ | ✓ | - | - | ✓ | ✓ | ✓ | 8-30 | Multiply Floating Short | reg2 = reg2 * reg1 |
SUBF.S | 000101 | ✓ | ✓ | 0 | ✓ | ✓ | - | - | ✓ | ✓ | ✓ | 12-28 | Subtract Floating Short | reg2 = reg2 - reg1 |
TRNC.SW | 001011 | ✓ | ✓ | 0 | - | ✓ | ✓ | - | - | - | ✓ | 9-14 | Truncate Short Floating to Word Integer | reg2 = (word) truncate(reg1 ) |
The CVT.SW
and TRNC.SW
instructions produce an
approximate word value from a floating short value. CVT.SW
will
round to the nearest integer value, wheras TRNC.SW
will round
toward zero.
The zero flag (Z
) is set when the result of any operation is
zero, or is cleared otherwise.
The carry flag (CY
) and sign flag (S
) are both
copies of the highest-order bit of the result of any operation.
PSW contains status flags that pertain
only to floating-point operations. When a floating-point status condition is
met, the corresponding flag is set in PSW
, but otherwise will
not be modified. The floating-point status conditions are as follows:
Flag | Code | Name | Condition | ||||
---|---|---|---|---|---|---|---|
FRO | 0xFF60 | Reserved operand | Either operand is a NaN, an indefinite, or a non-zero denormal value. | ||||
FIV | 0xFF70 | Invalid operation |
Multiple conditions:
|
||||
FZD | 0xFF68 | Zero division | DIVF.S was attempted to divide non-zero by zero. |
||||
FOV | 0xFF64 | Overflow | The result was beyond the maximum normal range of the floating short data type. | ||||
FUD | - | Underflow | The result was beyond the minimum normal range of the floating short data type. Zero is used as the result. | ||||
FPR | - | Precision degradation | Underflow did not occur, and the result was subjected to rounding and suffered a loss of precision. |
Status conditions in the list with an associated code will raise an
exception with that code if they are met. They
are ordered in the list such that items that appear earlier in the list have
higher priority than items that appear later in the list. In the event an
instruction satisfies more than one such condition, only the one with the
highest priority will be processed and have its corresponding flag set in
PSW. Flags are set in PSW
prior to raising an exception.
Editor's Note: The overflow condition appears to process the result as usual,
updating FPR
and reg2
as appropriate, then raises
the overflow exception when writing the exponent field. Research is needed to
determine exactly which values are produced in this situation.
Editor's Note: While the V810 documentation gives ranges for the number of cycles taken for each floating-point instruction, it does not give specifics about which situations result in which cycle counts. Research is needed to determine how long any given operation will take.
Bit strings are contiguous sequences of bits in memory. Operations can be performed on one or two bit strings.
Bit strings are defined with three parameters:
Word address | The address in memory of the word containing the first bit of the bit string. |
Bit offset | The binary position within the word where the first bit of the bit string is located, with 0 representing the least-significant bit. |
Length | The number of bits in the bit string. Bit strings of length zero are valid. |
Data storage for bit strings follows the order of least-significant to
most-significant for bits within words, and by memory address for words. If a
bit string extends higher than bit 31 of word address 0xFFFFFFFC
or lower than bit 0 of word address 0x00000000
, the following
bit will wrap around to the other end of the address space.
Registers r26
through r30
are used to define bit
strings:
r30 | Source string word address. The lowest 2 bits are cleared prior to operation. | ||||
r29 |
Multiple meanings:
|
||||
r28 | String length. All 32 bits are regarded as an unsigned integer. | ||||
r27 | Source string bit offset. The highest 27 bits are cleared prior to operation. | ||||
r26 | Destination string bit offset. The highest 27 bits are cleared prior to operation. |
Search operations use the registers designated for the "source" bit string.
Bit string operations are carried out in either an "upward" or "downward" direction. In an upwards operation, the offset of bits within a word increases and the words in memory increase in address. Conversely, a downward operation observes decreased bit offsets and word addresses.
All of the bit string instructions are stored in Format II and share a common opcode of
011111
. They are identified by their sub-opcode field.
Mnemonic | Sub-Opcode | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|
ANDBSU | 01001 | - | - | - | - | * | And Bit String Upward | dest = dest AND src |
ANDNBSU | 01101 | - | - | - | - | * | And Not Bit String Upward | dest = dest AND (NOT src ) |
MOVBSU | 01011 | - | - | - | - | * | Move Bit String Upward | dest = src |
NOTBSU | 01111 | - | - | - | - | * | Not Bit String Upward | dest = NOT src |
ORBSU | 01000 | - | - | - | - | * | Or Bit String Upward | dest = dest OR src |
ORNBSU | 01100 | - | - | - | - | * | Or Not Bit String Upward | dest = dest OR (NOT src ) |
XORBSU | 01010 | - | - | - | - | * | Exclusive Or Bit String Upward | dest = dest XOR src |
XORNBSU | 01110 | - | - | - | - | * | Exclusive Or Not Bit String Upward | dest = dest XOR (NOT src ) |
These operations read from the source bit string and store new bits into the
destination bit string, performing the specified operation on the
corresponding bits from both strings to produce the final output bits. All of
these instructions will clear the 2 lowest-order bits in r30
and
r29
, and clear the 27 highest-order bits in r27
and
r26
.
When a bit string instruction is invoked, it will process one word of output
and complete. Only after the entire bit string has been processed will PC be advanced to the next
instruction. During each invocation, the values in registers r26
through r30
are updated to reflect the current state. This
implementation facilitates the handling of interrupts even in the midst of time-consuming bit
string operations.
After a bit string instruction fully completes, the source and destination
bit strings as specified by registers r30
/r27
and
r29
/r26
respectively will represent the next higher
bit in memory. r28
will be zero, as there are no bits remaining
to be processed.
During each invocation of a bit string instruction, all of the bits for the
current destination word are processed, leaving the following destination
word to begin at bit offset zero (as specified by r26
). In this
way, the destination bit string is processed in full word units across the
minimum number of write accesses.
If the source and destination bit strings overlap and the destination bit string begins later than the source bit string, then the source bit string may become corrupted by overwriting data as output before reading it as input. Due to read buffering in the CPU, this will only occur during an invocation of a bit string instruction when the destination bit string begins 64 or more bits after the source bit string.
Editor's Note: The V810 manual provides a table of cycle timings for various configurations of these operations that needs to be incorporated into this document.
Mnemonic | Sub-Opcode | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|
SCH0BSD | 00001 | ✓ | - | - | - | * | Search Bit 0 Downward | Search downward for 0 |
SCH0BSU | 00000 | ✓ | - | - | - | * | Search Bit 0 Upward | Search upward for 0 |
SCH1BSD | 00011 | ✓ | - | - | - | * | Search Bit 1 Downward | Search downward for 1 |
SCH1BSU | 00010 | ✓ | - | - | - | * | Search Bit 1 Upward | Search upward for 1 |
These operations scan through the source bit string in the specified
direction for a bit with the specified state. At the start of processing, the
zero flag (Z
) is set and is only cleared if the specified bit
was found. All of these instructions will clear the 2 lowest-order bits in
r30
and clear the 27 highest-order bits in r27
.
When a search instruction is invoked, it will process one word of input and
complete. Only after the entire bit string has been processed will PC be advanced to the next
instruction. During each invocation, the values in registers r27
through r30
are updated to reflect the current state. This
implementation facilitates the handling of interrupts even in the midst of time-consuming
search operations.
During each invocation of a search instruction, all of the bits for the
current source word are processed, leaving the following source word to begin
at bit offset zero (if upward) or 31 (if downward), specified by
r27
. In this way, the source bit string is processed in full
word units across the minimum number of read accesses.
r29
is incremented for each bit processed during a search that
does not match the specified bit. It is not modified prior to operation.
After a search instruction fully completes, the source bit string specified
by registers r30
and r27
will point to the next bit
in memory in the specified direction that follows the matched bit (if a match
is found) or the entire string (if no match is found). Register
r28
will contain the number of remaining bits in the bit string
including the one pointed to by r30
and r27
.
Editor's Note: The V810 manual provides a table of cycle timings for various configurations of these operations that needs to be incorporated into this document.
CAXI
- Compare and Exchange InterlockedMnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
CAXI | 111010 | VI | ✓ | ✓ | ✓ | ✓ | 26 | Compare and Exchange Interlocked | See below. |
This instruction facilitates synchronization between multiple processors. It has four operands:
reg1 | Base address of lock word. |
disp | Lock word address displacement offset. |
reg2 | Compare value. |
r30 | Exchange value. |
When executing this instruction, the following algorithm is carried out:
▪ | The bus is locked, causing other CPUs to block when accessing it. | ||
▪ |
A value is loaded, as though with LD.W, from reg1 + disp .
|
||
▪ |
A comparison is performed, as though with CMP, using reg2 -
value.
|
||
♦ |
If the result is equal (Z = 1):
|
||
◊ |
Otherwise:
|
||
▪ | value is stored into reg2 .
| ||
▪ | The lock on the bus is released. |
The program can check the zero flag (Z
) to determine what action
was taken.
Virtual Boy only has one processor, so the CAXI
instruction has
limited utility.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
SETF | 010010 | II | - | - | - | - | 1 | Set Flag Condition |
if cond then reg2 = 1 else reg2 =
0
|
Tests a condition in PSW. If the
condition is true, stores 0x00000001
into reg2
;
otherwise, stores 0x00000000
into reg2
.
The purpose of SETF
is to provide a means for evaluating simple
conditional operations without performing a branch via Bcond
.
Branching disrupts the pipeline flow and takes more cycles than the
corresponding SETF
implementations for such operations. For
example, either-or assignments such as absolute value and sign benefit from
the use of SETF
.
The cond
field is 4 bits in size. The following conditions can
be checked:
Value | Mnemonic | Condition | Test | Note |
---|---|---|---|---|
0 | V | Overflow | if OV = 1 |
|
1 | C , L |
Carry, Lower | if CY = 1 |
Unsigned |
2 | E , Z |
Equal, Zero | if Z = 1 |
|
3 | NH | Not higher | if (CY OR Z ) = 1 |
Unsigned |
4 | N | Negative | if S = 1 |
|
5 | T | Always | if true | Always 1 |
6 | LT | Less than | if (OV XOR S ) = 1 |
Signed |
7 | LE | Less than or equal |
if ((OV XOR S ) OR Z ) = 1
|
Signed |
8 | NV | Not overflow | if OV = 0 |
|
9 | NC , NL |
Not carry, Not lower | if CY = 0 |
Unsigned |
10 | NE , NZ |
Not equal, Not zero | if Z = 0 |
|
11 | H | Higher | if (CY OR Z ) = 0 |
Unsigned |
12 | P | Positive | if S = 0 |
|
13 | F | Not always | if false | Always 0 |
14 | GE | Greater than or equal | if (OV XOR S ) = 0 |
Signed |
15 | GT | Greater than |
if ((OV XOR S ) OR Z ) = 0
|
Signed |
Certain conditions have more than one mnemonic. In these situations, either mnemonic can be used and the two are interchangeable.
The cond
field uses the same numeric values for each condition
as the Bcond instruction.
These instructions have unique opcodes.
Mnemonic | Opcode | Format | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|---|
CLI | 010110 | II | - | - | - | - | 12 | Clear Interrupt Disable Flag | ID = 0 |
SEI | 011110 | II | - | - | - | - | 12 | Set Interrupt Disable Flag | ID = 1 |
These instructions facilitate manipulation of the ID
flag in PSW through a mechanism that is simpler than
using the LDSR and STSR instructions.
Editor's Note: These instructions were borrowed from the 6502/65816
instruction set used by the NES and SNES. When NEC developed the V830 in
1997, they introduced the EI
and DI
instructions
(Enable Maskable Interrupt and Disable Maskable Interrupt, respectively),
which use the same opcodes and perform the same operations as NVC's
CLI
and SEI
instructions. However, EI
and DI
only take 2 cycles to complete.
These instructions are stored in Format VII and
share a common opcode of 111110
. They are identified by their
sub-opcode
field.
Mnemonic | Sub-Opcode | Z | S | OV | CY | Cycles | Name | Operation |
---|---|---|---|---|---|---|---|---|
MPYHW | 001100 | - | - | - | - | 9 | Multiply Halfword |
reg2 = reg2 * (reg1 << 15
>> 15 (sign-propagating))
|
REV | 001010 | - | - | - | - | 22 | Reverse Bits in Word | reg2 = ReverseBits(reg1 ) |
XB | 001000 | - | - | - | - | 6 | Exchange Byte |
reg2 = (reg2 AND 0xFFFF0000 ) OR
((reg2 << 8) AND 0xFF00 ) OR
((reg2 >> 8) AND 0x00FF )
|
XH | 001001 | - | - | - | - | 1 | Exchange Halfword |
reg2 = (reg2 >> 16 (zero-filling)) OR
(reg2 << 16)
|
The MPYHW
instruction performs a 32-bit signed multiplication.
The right-hand operand is produced by sign-extending the lower 17 bits of
reg1
.
The REV
instruction reverses the order of the bits in
reg2
: the highest-order bit of the input becomes the
lowest-order bit of the output and so-on.
Editor's Note: One source suggests that XB
and XH
must supply r0
in the binary encoding of the reg1
field, or else the behavior is undefined. This could use further testing, as
no misbehavior has been observed regardless of the value of
reg1
.
The following conventions, except as described below, apply to all instructions in the official V810 assembly notation:
• | When multiple operands are present, the destination is on the right. |
• | When three operands are present, the immediate value is on the left. |
• | The target address of reads and writes is the displacement offset followed by the base address register in [square brackets]. If the displacement offset is zero, it may be omitted. |
• | The target address of jumps and branches is the absolute address, not the relative displacement. |
The following instructions have additional conventions:
Bcond |
Multiple notations:
|
||||||
JMP | Although the operation does not perform an indirection, the operand is enclosed in [square brackets]. | ||||||
LDSR, STSR | May use the symbolic name of the system register or its numeric index. | ||||||
SETF |
Multiple notations: [note]
|
[note] | • | The "V810" notation is used by official NEC V810 documents, the GNU assembler, Nintendo's own Virtual Boy development tools, and NEC/Renesas-produced development tools. In the final draft of the V810 specification, this was the notation that was intended to be used. |
• | The "IAR" notation has been known to be used by NEC in V810 presentations during development, the IAR Systems V850 assembler, and Hudson Soft's development tools for PC-FX. |
The notation for each instruction is as follows:
Mnemonic | Name | Notation | |
---|---|---|---|
ADD | Add Immediate | ADD | imm , reg2 |
ADD | Add Register | ADD | reg1 , reg2 |
ADDF.S | Add Floating Short | ADDF.S | reg1 , reg2 |
ADDI | Add Immediate | ADDI | imm , reg1 , reg2 |
AND | And | AND | reg1 , reg2 |
ANDBSU | And Bit String Upward | ANDBSU | |
ANDI | And Immediate | ANDI | imm , reg1 , reg2 |
ANDNBSU | And Not Bit String Upward | ANDNBSU | |
Bcond | Branch on Condition | BNZ | address |
NOP | |||
CAXI | Compare and Exchange Interlocked | CAXI | disp [reg1 ], reg2 |
CLI | Clear Interrupt Disable Flag | CLI | |
CMP | Compare Immediate | CMP | imm , reg2 |
CMP | Compare Register | CMP | reg1 , reg2 |
CMPF.S | Compare Floating Short | CMPF.S | reg1 , reg2 |
CVT.SW | Convert Short Floating to Word Integer | CVT.SW | reg1 , reg2 |
CVT.WS | Convert Word Integer to Short Floating | CVT.WS | reg1 , reg2 |
DIV | Divide | DIV | reg1 , reg2 |
DIVF.S | Divide Floating Short | DIVF.S | reg1 , reg2 |
DIVU | Divide Unsigned | DIVU | reg1 , reg2 |
HALT | Halt | HALT | |
IN.B | Input Byte from Port | IN.B | disp [reg1 ], reg2 |
IN.H | Input Halfword from Port | IN.H | disp [reg1 ], reg2 |
IN.W | Input Word from Port | IN.W | disp [reg1 ], reg2 |
JAL | Jump and Link | JAL | address |
JMP | Jump Register | JMP | [reg1 ] |
JR | Jump Relative | JR | address |
LD.B | Load Byte | LD.B | disp [reg1 ], reg2 |
LD.H | Load Halfword | LD.H | disp [reg1 ], reg2 |
LD.W | Load Word | LD.W | disp [reg1 ], reg2 |
LDSR | Load to System Register | LDSR | reg2 , regID |
MOV | Move Immediate | MOV | imm , reg2 |
MOV | Move Register | MOV | reg1 , reg2 |
MOVBSU | Move Bit String Upward | MOVBSU | |
MOVEA | Add | MOVEA | imm , reg1 , reg2 |
MOVHI | Add | MOVHI | imm , reg1 , reg2 |
MPYHW | Multiply Halfword | MPYHW | reg1 , reg2 |
MUL | Multiply | MUL | reg1 , reg2 |
MULF.S | Multiply Floating Short | MULF.S | reg1 , reg2 |
MULU | Multiply Unsigned | MULU | reg1 , reg2 |
NOT | Not | NOT | reg1 , reg2 |
NOTBSU | Not Bit String Upward | NOTBSU | |
OR | Or | OR | reg1 , reg2 |
ORBSU | Or Bit String Upward | ORBSU | |
ORI | Or Immediate | ORI | imm , reg1 , reg2 |
ORNBSU | Or Not Bit String Upward | ORNBSU | |
OUT.B | Output Byte to Port | OUT.B | reg2 , disp [reg1 ] |
OUT.H | Output Halfword to Port | OUT.H | reg2 , disp [reg1 ] |
OUT.W | Output Word to Port | OUT.W | reg2 , disp [reg1 ] |
RETI | Return from Trap or Interrupt | RETI | |
REV | Reverse Bits in Word | REV | reg1 , reg2 |
SAR | Shift Arithmetic Right by Immediate | SAR | imm , reg2 |
SAR | Shift Arithmetic Right by Register | SAR | reg1 , reg2 |
SCH0BSD | Search Bit 0 Downward | SCH0BSD | |
SCH0BSU | Search Bit 0 Upward | SCH0BSU | |
SCH1BSD | Search Bit 1 Downward | SCH1BSD | |
SCH1BSU | Search Bit 1 Upward | SCH1BSU | |
SEI | Set Interrupt Disable Flag | SEI | |
SETF | Set Flag Condition | SETF | cond , reg2 |
SETFNZ | reg2 |
||
SHL | Shift Logical Left by Immediate | SHL | imm , reg2 |
SHL | Shift Logical Left by Register | SHL | reg1 , reg2 |
SHR | Shift Logical Right by Immediate | SHR | imm , reg2 |
SHR | Shift Logical Right by Register | SHR | reg1 , reg2 |
ST.B | Store Byte | ST.B | reg2 , disp [reg1 ] |
ST.H | Store Halfword | ST.H | reg2 , disp [reg1 ] |
ST.W | Store Word | ST.W | reg2 , disp [reg1 ] |
STSR | Store Contents of System Register | STSR | regID , reg2 |
SUB | Subtract | SUB | reg1 , reg2 |
SUBF.S | Subtract Floating Short | SUBF.S | reg1 , reg2 |
TRAP | Trap | TRAP | vector |
TRNC.SW | Truncate Short Floating to Word Integer | TRNC.SW | reg1 , reg2 |
XB | Exchange Byte | XB | reg2 |
XH | Exchange Halfword | XH | reg2 |
XOR | Exclusive Or | XOR | reg1 , reg2 |
XORBSU | Exclusive Or Bit String Upward | XORBSU | |
XORI | Exclusive Or Immediate | XORI | imm , reg1 , reg2 |
XORNBSU | Exclusive Or Not Bit String Upward | XORNBSU |
Attempting to execute any invalid opcode or sub-opcode will raise an
exception with code 0xFF90
and a
restore PC
of current
PC
.
Opcode | Format | Mnemonic | Operation |
---|---|---|---|
000000 | I | MOV | reg2 = reg1 |
000001 | I | ADD | reg2 = reg2 + reg1 |
000010 | I | SUB | reg2 = reg2 - reg1 |
000011 | I | CMP | (discard) = reg2 - reg1 |
000100 | I | SHL |
reg2 = reg2 << (reg1 AND
0x1F )
|
000101 | I | SHR |
reg2 = reg2 >> (reg1 AND
0x1F ) (zero-filling)
|
000110 | I | JMP | PC = reg1 |
000111 | I | SAR |
reg2 = reg2 >> (reg1 AND
0x1F ) (sign-propagating)
|
001000 | I | MUL |
(result) = reg2 * reg1 , r30 =
(result) >> 32, reg2 = (result)
|
001001 | I | DIV |
r30 = reg2 MOD reg1 ,
reg2 = reg2 / reg1
|
001010 | I | MULU |
(result) = reg2 * reg1 , r30 =
(result) >> 32, reg2 = (result)
|
001011 | I | DIVU |
r30 = reg2 MOD reg1 ,
reg2 = reg2 / reg1
|
001100 | I | OR | reg2 = reg2 OR reg1 |
001101 | I | AND | reg2 = reg2 AND reg1 |
001110 | I | XOR | reg2 = reg2 XOR reg1 |
001111 | I | NOT | reg2 = NOT reg1 |
010000 | II | MOV | reg2 = (sign extend) imm |
010001 | II | ADD |
reg2 = reg2 + (sign extend)
imm
|
010010 | II | SETF |
if cond then reg2 = 1 else reg2 =
0
|
010011 | II | CMP | (discard) = reg2 - (sign extend) imm |
010100 | II | SHL |
reg2 = reg2 << (zero extend)
imm
|
010101 | II | SHR |
reg2 = reg2 >> (zero extend)
imm (zero-filling)
|
010110 | II | CLI | ID = 0 |
010111 | II | SAR |
reg2 = reg2 >> (zero extend)
imm (sign-propagating)
|
011000 | II | TRAP | Raise exception (0xFFA0 + vector ) |
011001 | II | RETI |
if NP then PC = FEPC ,
PSW = FEPSW else PC =
EIPC , PSW = EIPSW
|
011010 | II | HALT | Wait for interrupt |
011011 | - | Invalid | |
011100 | II | LDSR | SystemRegister[regID ] = reg2 |
011101 | II | STSR | reg2 = SystemRegister[regID ] |
011110 | II | SEI | ID = 1 |
011111 | II | * | Bit string: see below |
100 | III | Bcond |
if cond = true then PC = PC +
disp
|
101000 | V | MOVEA |
reg2 = reg1 + (sign extend) imm
|
101001 | V | ADDI |
reg2 = reg1 + (sign extend)
imm
|
101010 | IV | JR | PC = PC + disp |
101011 | IV | JAL |
r31 = PC + 4, PC = PC
+ disp
|
101100 | V | ORI |
reg2 = reg1 OR (zero extend) imm
|
101101 | V | ANDI |
reg2 = reg1 AND (zero extend) imm
|
101110 | V | XORI |
reg2 = reg1 XOR (zero extend) imm
|
101111 | V | MOVHI |
reg2 = reg1 + (imm << 16)
|
110000 | VI | LD.B |
reg2 = (sign extend) (byte ptr) [reg1 +
disp ]
|
110001 | VI | LD.H |
reg2 = (sign extend) (halfword ptr) [reg1 +
disp ]
|
110010 | - | Invalid | |
110011 | VI | LD.W |
reg2 = (word ptr) [reg1 +
disp ]
|
110100 | VI | ST.B |
(byte ptr) [reg1 + disp ] = reg2
AND 0xFF
|
110101 | VI | ST.H |
(halfword ptr) [reg1 + disp ] =
reg2 AND 0xFFFF
|
110110 | - | Invalid | |
110111 | VI | ST.W |
(word ptr) [reg1 + disp ] = reg2
|
111000 | VI | IN.B |
reg2 = (zero extend) (byte ptr) [reg1 +
disp ]
|
111001 | VI | IN.H |
reg2 = (zero extend) (halfword ptr) [reg1 +
disp ]
|
111010 | VI | CAXI | See instruction section. |
111011 | VI | IN.W |
reg2 = (word ptr) [reg1 +
disp ]
|
111100 | VI | OUT.B |
(byte ptr) [reg1 + disp ] = reg2
AND 0xFF
|
111101 | VI | OUT.H |
(halfword ptr) [reg1 + disp ] =
reg2 AND 0xFFFF
|
111110 | VII | * | Floating-point and Nintendo: see below |
111111 | VI | OUT.W |
(word ptr) [reg1 + disp ] = reg2
|
Bit string instructions are stored in Format II and share a common opcode of
011111
. They are identified by their sub-opcode
field.
Sub-Opcode | Mnemonic | Operation |
---|---|---|
00000 | SCH0BSU | Search upward for 0 |
00001 | SCH0BSD | Search downward for 0 |
00010 | SCH1BSU | Search upward for 1 |
00011 | SCH1BSD | Search downward for 1 |
⋯ | Invalid | |
01000 | ORBSU | dest = dest OR src |
01001 | ANDBSU | dest = dest AND src |
01010 | XORBSU | dest = dest XOR src |
01011 | MOVBSU | dest = src |
01100 | ORNBSU | dest = dest OR (NOT src ) |
01101 | ANDNBSU | dest = dest AND (NOT src ) |
01110 | XORNBSU | dest = dest XOR (NOT src ) |
01111 | NOTBSU | dest = NOT src |
⋯ | Invalid |
Floating-point and Nintendo instructions are stored in Format VII and share a common opcode of
111110
. They are identified by their sub-opcode
field.
Sub-Opcode | Mnemonic | Operation |
---|---|---|
000000 | CMPF.S | (discard) = reg2 - reg1 |
000001 | Invalid | |
000010 | CVT.WS | reg2 = (float) reg1 |
000011 | CVT.SW | reg2 = (word) round(reg1 ) |
000100 | ADDF.S | reg2 = reg2 + reg1 |
000101 | SUBF.S | reg2 = reg2 - reg1 |
000110 | MULF.S | reg2 = reg2 * reg1 |
000111 | DIVF.S | reg2 = reg2 / reg1 |
001000 | XB |
reg2 = (reg2 AND 0xFFFF0000 ) OR
((reg2 << 8) AND 0xFF00 ) OR
((reg2 >> 8) AND 0x00FF )
|
001001 | XH |
reg2 = (reg2 >> 16 (zero-filling)) OR
(reg2 << 16)
|
001010 | REV | reg2 = ReverseBits(reg1 ) |
001011 | TRNC.SW | reg2 = (word) truncate(reg1 ) |
001100 | MPYHW |
reg2 = reg2 * (reg1 << 15
>> 15 (sign-propagating))
|
⋯ | Invalid |
Contents
Overview
Pinout
Communication Control
Signal Control
Data Registers
Communication Interrupt
On the underside of the Virtual Boy unit, next to the controller port, is a port labeled "EXT." that can be used for communication between two linked Virtual Boys. Although a link cable was developed for use with the system, no commercial games made use of it and the cable itself was never made available to consumers.
Communication exchanges 8 bits at a time between Virtual Boy units. Bits come from dedicated data registers for transmitted and received data.
The hardware controls the entire communication operation, exchanging bits at a rate of 50 KHz per bit for a total of 160 µs. When the operation completes, a communication interrupt can be configured to be raised.
An additional auxiliary signal can be used for negotiating communication status independently from the actual bits sent and received.
The following diagram depicts the pin configuration of the communication port when looking into it from the bottom of the Virtual Boy unit:
The pins have the following significance:
1. | COMCNT |
2. | +5V DC |
3. | Communication clock |
4. | Data receive |
5. | Sync in |
6. | Sync out |
7. | Ground |
8. | Data transmit |
Within a link cable, pins are connected to each end in the following way:
COMCNT | 1 | ⟷ | 1 | COMCNT |
+5V DC | 2 | ⨂ | 2 | +5V DC |
Communication clock | 3 | ⟷ | 3 | Communication clock |
Data receive | 4 | ← | 8 | Data transmit |
Sync in | 5 | ← | 6 | Sync out |
Sync out | 6 | ⨂ | 5 | Sync in |
Ground | 7 | ⟷ | 7 | Ground |
Data transmit | 8 | → | 4 | Data receive |
⨂ | +5V DC is not connected because it is not used in link communications. It can be used to power some external device. |
⨂ | Sync in and Sync out do not form a round-trip connection in a link cable because doing so would result in clock feedback. |
The primary communication operation is performed through the data registers and a single control register:
0x02000000 | CCR | Communication Control Register |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
C-Int-Inh |
- | C-Clk-Sel |
- | C-Start |
C-Stat |
- | |
1 | 2 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are set when read. | |
C-Int-Inh | R/W | When clear, the communication interrupt is enabled for communications. When set, it is acknowledged and disabled. |
C-Clk-Sel | R/W | When clear, the unit uses its internal communication clock signal. When set, it relies on the signal from an external unit. |
C-Start | W | When set, a communication operation begins. Always set when read. |
C-Stat | R | Set while a communication is underway, or cleared otherwise. |
The primary function of the communication port is to exchange 8 bits of data between two Virtual Boy units. The hardware performs the operation when requested, sending the data in CDTR and receiving data into CDRR.
If C-Int-Inh
is clear when the communication operation
completes, a communication interrupt is raised.
C-Clk-Sel
determines the communication clock signal to use for
synchronizing communication operations:
0 | Internal | Uses own clock. |
1 | External | Uses another unit's clock. |
When C-Start
is set, a communication operation is initiated. If
the external clock is selected, the unit will wait for a communication signal
from a linked unit before performing the operation. If the internal clock is
selected, the operation begins immediately. When the operation completes, the
bits received from the other unit will be loaded into CDRR
.
If the internal clock is selected and C-Start
is set without
another unit waiting for an external clock, a peerless communication will be
performed immediately and the bits in CDRR
will be undefined.
C-Stat
is set as soon as C-Start
is set, and will
remain set until the communication operation completes. If
C-Start
is set while C-Stat
is already set, nothing
happens.
Changing the clock selection while C-Stat
is set will not abort
the communication operation, but will merely change the clock signal source.
If both units are waiting for an external clock and one changes to the
internal clock (with or without writing to C-Start
) the
communication will be carried out normally.
A communication operation cannot be canceled once initiated. The only way
C-Stat
will be cleared is when the operation completes.
An auxiliary signal channel is present on the communication port intended for use in negotiations between peers. It is managed through a single register:
0x02000004 | CCSR | COMCNT Control Register |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
CC-Int-Inh |
- | CC-Int-Lev |
CC-Sig |
CC-Smp |
CC-Wr |
CC-Rd |
|
1 | 2 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are set when read. | |
CC-Int-Inh | R/W | When clear, the communication interrupt is enabled for signals. When set, it is acknowledged and disabled. |
CC-Int-Lev | R/W |
When CC-Smp becomes equal to CC-Int-Lev , the
interrupt condition is satisfied.
|
CC-Sig | R/W | The automatic signal status to be used after a communication operation completes. |
CC-Smp | R | Automatically sampled from the signal after a communication operation completes. |
CC-Wr | R/W | The manual signal status to be used on write. |
CC-Rd | R | The current manual signal status on read. |
There are two bits in CCSR
that are managed by the hardware:
CC-Rd |
Manually configured by software writes to CCSR . The value of
this bit on both connected units is the bitwise AND of the
CC-Wr bits on both units.
|
CC-Smp |
Automatically configured when communication operations via CCR complete. The value of this bit on
both connected units is the bitwise AND of the CC-Sig bits
on both units as well as another bitwise AND with the value of
CC-Rd .
|
If there is no second unit connected, the values of CC-Rd
and
CC-Smp
are processed as though a connected unit had the same
CCSR
configuration.
When a communication operation completes and CC-Smp
is updated,
its value is compared with CC-Int-Lev
. If the two bits match,
the interrupt condition is satisfied and will be raised if
CC-Int-Inh
is clear.
When performing communication operations via CCR, the data transmitted and received is loaded/stored in dedicated registers:
0x02000008 | CDTR | Transmitted Data Register |
0x0200000C | CDRR | Received Data Register |
Both of these registers are 8 bits of software-assigned data.
CDTR
is read/write and CDRR
is read-only.
When a communication operation via CCR completes, two interrupts can be optionally raised:
Communication |
Configured in CCR and occurs any time a communication
operation completes.
|
COMCNT Input |
Configured in CCSR and occurs when
a communication operation completes and the CC-Int-Lev and
CC-Smp bits match.
|
Under either situation, an interrupt will be requested on the CPU with a code
of 0xFE30
. Each situation is capable of independently requesting
an interrupt, and must be acknowledged individually. To acknowlege each type
of communication iterrupt:
Communication | Set C-Int-Inh in CCR . |
COMCNT Input | Set CC-Int-Inh in CCSR .
|
Contents
Layout
Pinout
Game Pad Control
Data Registers
The game pad is an 8-direction, 6-buton controller that also supplies power to the system. It was manufactured with a battery pack that accepted 6 AA batteries, and an A/C adapter was sold separately. The button state can be read from the controller either through software or through a hardware function, and an interrupt can be configured to raise when a button is pressed.
The game pad has the following input configuration:
The game pad is responsible for supplying power to the system. On the back of the game pad is a bracket that can hold a power source, which could be either a pack of 6 AA batteries or an A/C wall adapter.
The following diagram depicts the pin configuration of the game pad port when looking into it from the bottom of the Virtual Boy unit:
The pins have the following significance:
1. | Data |
2. | +5V DC |
3. | Reset |
4. | Clock |
5. | Ground |
6. | Power (VCC) |
Button state information is read from the game pad one bit at a time over a serial port. There are two signals that control this operation: one to reset the entire process and one to clock the bits being sent back to the console. This process of reading button state information can be handled either by the program or by a hardware function.
All game pad operations are managed through a single register:
0x02000028 | SCR | Serial Control Register |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
K-Int-Inh |
- | Para/Si |
Soft-Ck |
- | HW-SI |
SI-Stat |
S-Abt/Dis |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are set when read. | |
K-Int-Inh | R/W | When clear, the key input interrupt is enabled. When set, it is acknowledged and disabled. |
Para/Si | R/W | When set, a latch signal resets the game pad's read operation. |
Soft-Ck | R/W | Sends the inverse read bit to the game pad. (See below) |
HW-SI | W | Set to initiate a hardware button state read. (See below) |
SI-Stat | R | Set while a hardware button state read is in progress. |
S-Abt/Dis | R/W | When set, any active hardware button state read is aborted. |
Setting Para/Si
sends a latch signal to the game pad that resets
the button read operation. This bit should be cleared when subsequently using
Soft-Ck
, or else the operation will be repeatedly reset.
To perform a software read, set Para/Si
once to reset the
operation, then write alternating states for Soft-Ck
16 times.
After the 16th bit has been clocked, the data registers will contain the button
state bits. Before the 16th bit has been clocked, the contents of the data
registers will be undefined.
Writing to Soft-Ck
sends the inverse bit to the game pad (0
becomes 1 and vice-versa). In order to properly read the button state, the
game pad must receive a 0 followed by a 1 for each button for a total of 33
writes to Soft-Ck
.
Editor's Note: If the ambient humidity is high enough, an assembly-optimized software read routine will attempt to process game pad bits so fast that the game pad will respond with unstable data. A dummy MUL instruction between bits seems to add enough latency to address this problem, but may or may not be sufficient in all cases.
Setting HW-SI
will initiate a hardware read operation, which
will handle the latch and clock signals automatically. When the operation
completes, the data registers will
contain the button state bits. Setting HW-SI
while a hardware
read operation is already underway will have no effect.
HW-SI
is always set when read.
While a hardware read operation is underway, SI-Stat
will be
set. When the operation completes, SI-Stat
will be clear.
Setting S-Abt/Dis
during a hardware read operation will cancel
it immediately.
The hardware read operation clocks buttons at a rate of 31.25 KHz per button for a total of 512 µs. This is significantly slower than the speeds that can be achieved through a software read.
When a hardware read operation completes and K-Int-Inh
is clear,
an interrupt will be raised if any bit in the
data registers from 15 through 4 is
set, but will not be raised if any bit from 3 through 1 is set. Since the
standard Virtual Boy controller always sets bit 1, it is impossible for it to
raise a key input interrupt.
The key input interrupt has a code of 0xFE00
.
After reading button state information from the game pad, a 16-bit value is loaded into two read-only registers, one for the lower 8 bits and one for the higher 8 bits:
0x02000010 | SDLR | Serial Data Low Register |
0x02000014 | SDHR | Serial Data High Register |
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
RD |
RL |
SEL |
STA |
LU |
LD |
LL |
LR |
RR |
RU |
LT |
RT |
B | A | SGN |
PWR |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
RD | Right D-pad down |
RL | Right D-pad left |
SEL | Select button |
STA | Start button |
LU | Left D-pad up |
LD | Left D-pad down |
LL | Left D-pad left |
LR | Left D-pad right |
RR | Right D-pad right |
RU | Right D-pad up |
LT | L button |
RT | R button |
B | B button |
A | A button |
SGN | Signature (see below) |
PWR | Low battery |
When using the standard Virtual Boy controller, SGN
is always
set. This prevents the key input interrupt
from ever being raised.
A game pak is a cartridge containing a ROM module and optionally a RAM module, battery and/or other circuitry. It is inserted into the Virtual Boy unit and supplies the software.
The game pak is able to request an interrupt
with a code of 0xFE20
. No commercial game paks make use of this.
The following address ranges in the memory map are allocated to the game pak:
0x04000000 - 0x04FFFFFF
|
Game Pak Expansion |
0x06000000 - 0x06FFFFFF |
Game Pak RAM |
0x07000000 - 0x07FFFFFF |
Game Pak ROM |
The game pak expansion range is provided for game pak-specific use, but was not used in any commercial game pak.
Game paks may or may not contain RAM modules. Commercial game paks that contained RAM modules were battery-backed, retaining RAM contents while the power is off (SRAM).
Every game pak must supply program data, typically provided by a ROM module.
In all commercial game paks, the sizes in bytes of the ROM and RAM (if present) data are powers of 2. Addresses into game pak memory that exceed the size of the corresponding data simply have their upper bits masked, producing mirrors of the data across the entire respective address range.
The following diagram depicts the pin configuration of the game pak as seen looking at the bottom of the cartridge. Pins follow a zig-zag pattern with odd-numbered pins on one row and even-numbered pins on the other:
The pins have the following significance:
1. | Ground | 21. | Address 5 | 41. | Data 1 |
2. | Ground | 22. | Address 11 | 42. | Data 14 |
3. | RAM write enable | 23. | Address 4 | 43. | Data 9 |
4. | Expansion select | 24. | Address 12 | 44. | Data 6 |
5. | Expansion write enable | 25. | Address 3 | 45. | Data 2 |
6. | RAM select | 26. | Address 13 | 46. | Data 13 |
7. | Reset | 27. | Address 2 | 47. | Data 10 |
8. | +5V DC | 28. | Address 14 | 48. | Data 5 |
9. | Interrupt request | 29. | Address 1 | 49. | Data 3 |
10. | Address 23 | 30. | Address 15 | 50. | Data 12 |
11. | Address 19 | 31. | ROM select | 51. | Data 11 |
12. | Address 22 | 32. | Address 16 | 52. | Data 4 |
13. | Address 18 | 33. | Ground | 53. | +5V DC |
14. | Address 21 | 34. | Address 17 | 54. | +5V DC |
15. | Address 8 | 35. | Output enable | 55. | Right audio in |
16. | Address 20 | 36. | +5V DC | 56. | Left audio in |
17. | Address 7 | 37. | Data 0 | 57. | Right audio out |
18. | Address 9 | 38. | Data 15 | 58. | Left audio out |
19. | Address 6 | 39. | Data 8 | 59. | Ground |
20. | Address 10 | 40. | Data 7 | 60. | Ground |
The expansion, ROM and RAM memory addresses activate the corresponding "select" pins when accessing the game pak. Only one such pin should be active at a time.
There is no Address 0 pin because there are 16 data lines: all accesses are 16-bit aligned.
The direction of the audio lines in the chart above is relative to the game pak itself: "in" lines enter the game pak, and "out" lines exit it.
Contents
Counter and Reload
Timer Control
Timer Zero Interrupt
The timer component contains a 16-bit counter that is decremented at a specified interval. An interrupt can be configured to raise whenever the counter reaches zero. After the counter reaches zero, it is reinitialized with a supplied reload value and counting continues.
The timer contains a 16-bit counter that is decremented by one at the configured interval. After the counter reaches zero, a preset reload value is loaded into the counter and counting continues.
The counter and reload values can be accessed 8 bits at a time through the following registers:
0x02000018 | TLR | Timer Counter Low Register |
0x0200001C | THR | Timer Counter High Register |
These registers represent both the counter and the reload value. The "High" register represents the upper 8 bits of the corresponding 16-bit value, and the "Low" register represents the lower 8 bits.
When reading from these registers, the bits returned will be the current value of the counter. Since the timer continues to count independently from program activity, it should be stopped before accessing the counter value.
When writing to these registers, a new reload value is specified for the corresponding 8 bits. When either register is written, the entire 16-bit value will be loaded into the counter and reset the current timer tick to the beginning of its wait interval.
All timer operations are managed through a single register:
0x02000020 | TCR | Timer Control Register |
7 | 5 | 4 | 3 | 2 | 1 | 0 | |
- | T-Clk-Sel |
Tim-Z-Int |
Z-Stat-Clr |
Z-Stat |
T-Enb |
||
3 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are set when read. | |
T-Clk-Sel | R/W | Specifies the timer interval. (See below) |
Tim-Z-Int | R/W | When set, the timer zero interrupt is enabled. |
Z-Stat-Clr | W | Clears Z-Stat and acknowledges interrupt. (See below) |
Z-Stat | R | Set when the timer counter becomes zero. |
T-Enb | R/W | When set, the timer is enabled. |
The value of T-Clk-Sel
determines the frequency at which the
timer will count:
0 | 100 µs |
1 | 20 µs |
Z-Stat-Clr
will clear Z-Stat
and acknowledge a timer zero interrupt if the counter is
non-zero or, if the counter is zero, if the timer is disabled. This bit is
always set when read.
Z-Stat
becomes set whenever the counter is zero while the timer
is enabled. This bit will remain set until Z-Stat-Clr
performs
an action as specified above.
If both T-Enb
is cleared and Z-Stat-Clr
is set
while the timer is enabled, then the timer is disabled, but zero status is
not cleared (nor is an interrupt acknowledged).
If enabled in TCR, a timer zero interrupt will be raised whenever the counter value changes from a non-zero value to zero. This can occur either by timer activity or by writing to the reload value registers. The timer loading a reload value of zero into the counter does not satisfy the interrupt condition.
Timer zero interrupts have a code of 0xFE10
and can be
acknowledged in two ways via writes to TCR
:
• | Disabling the interrupt by clearing Tim-Z-Int |
• |
Clearing zero status by setting Z-Stat-Clr under the
conditions outlined in Timer Control.
|
The wait controller component generates wait signals for the game pak expansion and ROM address ranges. The wait controller is managed through the following register:
0x02000024 | WCR | Wait Control Register |
7 | 2 | 1 | 0 | ||||
- | EXP1W |
ROM1W |
|||||
6 | 1 | 1 |
- | These bits have no function and are set when read. | |
EXP1W | R/W | Controls the wait count in the game pak expansion address range. |
ROM1W | R/W | Controls the wait count in the game pak ROM address range. |
For both EXP1W
and ROM1W
, 2 waits are generated for
accesses in the respective address range if clear, and 1 wait is generated if
set.
Overview
Overview
Memory Map
Drawing and Display
Procedures
Memory
Characters
Objects
Background Maps
Worlds
Column Table
Frame Buffer
Registers
Display
Drawing
Brightness
Palettes
Interrupts
Miscellaneous
The displays used in the Virtual Boy were invented by Reflection Technology, Inc. and pitched to Nintendo, who accepted the proposal and initiated the Virtual Boy project. Each display consists of a single column of red LEDs and creates the illusion of a two-dimensional image by precicely projecting light onto an oscillating mirror. The two mirrors oscillate opposite one another to maintain balance and optimize power consumption.
A double-buffered, stereoscopic frame buffer is read from video memory to transmit to the eyes. Typically, this frame buffer is manipulated by the VIP during its drawing procedure. Alternately, the drawing functionality can be disabled and the frame buffer can be accessed directly by the CPU, facilitating software rendering.
Images on Virtual Boy are 384×224 pixels per eye and are transmitted at a rate of 50.0 Hz.
Image Elements
The atomic unit of graphics on Virtual Boy is the character, also known as a "tile". Characters are 8×8 pixel graphics with 2 bits per pixel. They can be used on their own in a scene or as part of a larger mosaic. There is memory for 2,048 characters.
Individual characters can be displayed anywhere on the screen by using them in an object, often called a "sprite". There is memory for 1,024 objects.
Background maps are 64×64-character mosaics that themselves are arranged into larger mosaics called backgrounds. There is memory for 14 full background maps.
The top-level unit of graphics on Virtual Boy is the world, also known as a "window". A world specifies a rectangular region in the scene where a background can be drawn. The portion of a background that appears within a world can be determined in a number of ways, from simple scrolling to affine transformations. There is memory for 32 worlds.
Other Features
The VIP is capable of raising an interrupt for a number of different conditions. This is the primary means by which a program is synchronized with the video hardware.
Three levels of brightness can be configured before a frame is displayed. Used in conjunction with a black value, there can be four base shades of red in a given image.
A column table exists that is used by the physical display unit to maintain pixel proportions as the mirror oscillates, since the mirror's angle relative to the LEDs is constantly changing. The column table can also be used to indirectly influence the absolute brightness of columns of pixels in the output independently from the brightness settings.
The drawing feature can be configured to swap the front and back frame buffers after some number of display cycles rather than every cycle, thereby tuning the frame rate of the program.
The VIP occupies addresses 0x00000000
- 0x00FFFFFF
in the system memory map.
0x00000000 - 0x00005FFF
|
Left frame buffer 0 |
0x00006000 - 0x00007FFF |
Character table 0 |
0x00008000 - 0x0000DFFF |
Left frame buffer 1 |
0x0000E000 - 0x0000FFFF |
Character table 1 |
0x00010000 - 0x00015FFF |
Right frame buffer 0 |
0x00016000 - 0x00017FFF |
Character table 2 |
0x00018000 - 0x0001DFFF |
Right frame buffer 1 |
0x0001E000 - 0x0001FFFF |
Character table 3 |
0x00020000 - 0x0003D7FF |
Background maps and world parameters |
0x0003D800 - 0x0003DBFF |
World attributes |
0x0003DC00 - 0x0003DDFF |
Left column table |
0x0003DE00 - 0x0003DFFF |
Right column table |
0x0003E000 - 0x0003FFFF |
Object attributes |
0x00040000 - 0x0005DFFF |
Unmapped |
0x0005E000 - 0x0005FFFF |
I/O Registers (see below) |
0x00060000 - 0x00077FFF |
Unmapped |
0x00078000 - 0x00079FFF |
Mirror of character table 0 |
0x0007A000 - 0x0007BFFF |
Mirror of character table 1 |
0x0007C000 - 0x0007DFFF |
Mirror of character table 2 |
0x0007E000 - 0x0007FFFF |
Mirror of character table 3 |
0x00080000 - 0x00FFFFFF |
Mirroring of VIP memory map |
Writing to unmapped addresses has no apparent effect, and their values are undefined when read.
0x0005F800 | INTPND | Interrupt Pending |
0x0005F802 | INTENB | Interrupt Enable |
0x0005F804 | INTCLR | Interrupt Clear |
0x0005F820 | DPSTTS | Display Control Read Register |
0x0005F822 | DPCTRL | Display Control Write Register |
0x0005F824 | BRTA | Brightness Control Register A |
0x0005F826 | BRTB | Brightness Control Register B |
0x0005F828 | BRTC | Brightness Control Register C |
0x0005F82A | REST | Rest Control Register |
0x0005F82E | FRMCYC | Game Frame Control Register |
0x0005F830 | CTA | Column Table Read Start Address |
0x0005F840 | XPSTTS | Drawing Control Read Register |
0x0005F842 | XPCTRL | Drawing Control Write Register |
0x0005F844 | VER | VIP Version Register |
0x0005F848 | SPT0 | OBJ Control Register 0 |
0x0005F84A | SPT1 | OBJ Control Register 1 |
0x0005F84C | SPT2 | OBJ Control Register 2 |
0x0005F84E | SPT3 | OBJ Control Register 3 |
0x0005F860 | GPLT0 | BG Palette Control Register 0 |
0x0005F862 | GPLT1 | BG Palette Control Register 1 |
0x0005F864 | GPLT2 | BG Palette Control Register 2 |
0x0005F866 | GPLT3 | BG Palette Control Register 3 |
0x0005F868 | JPLT0 | OBJ Palette Control Register 0 |
0x0005F86A | JPLT1 | OBJ Palette Control Register 1 |
0x0005F86C | JPLT2 | OBJ Palette Control Register 2 |
0x0005F86E | JPLT3 | OBJ Palette Control Register 3 |
0x0005F870 | BKCOL | BG Color Palette Control Register |
VIP I/O registers are intended to be accessed as halfwords. All reads, halfword writes and word writes function normally, but byte writes behave anomalously:
• | If a byte write is attempted on an even address, a halfword write is performed using the lowest 16 bits of the source register. |
• | If a byte write is attempted on an odd address, a halfword write is performed using a value produced by taking the lowest 8 bits of the source regsiter and shifting them left 8 bits. |
Any address in the 0x0005E000
- 0x0005FFFF
range
that does not correspond with one of the above I/O registers is unused.
Writing to these addresses has no apparent effect, and their values are
undefined when read.
A frame is an image presented to the user. The image may be produced by the VIP itself through its drawing procedure, the drawing feature can be disabled and the image produced through software, or a mixture of both. In all cases, the image to be displayed is stored in the frame buffer.
The primary clock signal used to produce and display images is the display frame, which drives the physical display unit. Display frames occur at a fixed interval of 20 ms, or 50 Hz. During each display frame, the contents of the frame buffer are transmitted to the LEDs for display to the user.
Drawing, if enabled, produces a new image in the frame buffer. The interval at which this occurs is a game frame. The timing of game frames is relative to display frames: the FRMCYC register can be used to configure how many display frames to wait between game frames.
If enabled, the VIP will draw a new image into the frame buffer every game frame using settings from VIP memory such as characters, worlds and palettes.
When appropriate, the drawing procedure begins when the FCLK
flag gets set in DPSTTS. The value in
FRMCYC is loaded into a counter that
is decremented with each display frame to determine when to begin the next
drawing task. If the previous drawing task is still ongoing when this occurs,
the OVERTIME
flag in DPSTTS
is set.
Because the VIP memory bus is 16 bits wide and frame buffer memory is 2 bits per pixel stored in column-major order, a halfword access into frame buffer memory corresponds to a 1×8 pixel unit of data. The VIP only writes each location in frame buffer memory once per frame, performing all graphical processing necessary for the current halfword internally.
Halfwords are processed into the frame buffer in left-to-right order, thereby processing 8 rows of pixels at a time. Groups of 8 rows of pixels are procesed in top-to-bottom order. When all 28 groups of 8 rows of pixels have been processed, the drawing procedure completes.
For each 1×8 halfword unit of frame buffer data, the following algorithm is carried out:
▪ | All pixels in the halfword are initialized to the value specified by BKCOL. | ||||||||||||||||||
▪ | A temporary object group counter is initialized to 3. | ||||||||||||||||||
▪ |
For each world from 31 to 0:
|
||||||||||||||||||
▪ | Store the halfword into the frame buffer. |
Drawing is performed on frame buffer 0 or 1, alternating each time the drawing procedure is carried out. This enables drawing to one frame buffer while the other is being displayed.
Editor's Note: The amount of time taken by the drawing procedure depends on the complexity of the image being drawn. Affine worlds in particular are computationally expensive and cannot fill the screen without reducing the frame rate. Research is needed to determine exactly how long each type of graphic takes to draw. When no image is being drawn whatsoever (such that the frame buffer's contents are merely erased), the drawing procedure takes approximately 2.8 ms.
Editor's Note: Research is needed to determine exactly when the active frame
buffer is toggled. It may occur when FCLK
goes high.
If enabled, then each display frame, the frame buffer is transmitted to the LEDs for display to the user.
Each display frame, the following sequence of events takes place:
▪ | 0 ms |
FCLK in DPSTTS goes
high.
|
▪ | 3 ms | The appropriate left frame buffer begins to display. |
▪ | 8 ms | The left frame buffer finishes displaying. |
▪ | 10 ms |
FCLK goes low.
|
▪ | 13 ms | The appropriate right frame buffer begins to display. |
▪ | 18 ms | The right frame buffer finishes displaying. |
▪ | 20 ms | Start of next display frame. |
When displaying a frame buffer for one eye, the following algorithm is carred out:
▪ | An internal column table pointer is initialized using the corresponding value from CTA. | ||||||||
▪ |
The corresponding DPBSY flag is set in DPSTTS .
|
||||||||
▪ |
For every group of 4 columns of pixels from left to right:
|
||||||||
▪ |
The corresponding DPBSY flag is cleared in
DPSTTS .
|
Editor's Note: There doesn't appear to be any way to select in software the frame buffer to be displayed. The only known way to leverage double buffering is to use the hardware drawing feature.
Editor's Note: Research is needed to determine whether frame buffer 0 is
necessarily used as the default after reset. The drawing function can be used
for one frame and DPSTTS
monitored to determine which frame
buffer it used.
The fundamental graphical element on Virtual Boy is the character, or "tile", which is an 8×8 pixel image with 2 bits per pixel. There is memory for 2,048 characters broken up into four blocks of 512 characters each:
0x00006000 - 0x00007FFF
|
Character table 0 |
0x0000E000 - 0x0000FFFF |
Character table 1 |
0x00016000 - 0x00017FFF |
Character table 2 |
0x0001E000 - 0x0001FFFF |
Character table 3 |
These address ranges exist in between frame buffer memory and are not contiguous. In ordrer to facilitate fully linear access, virtual addresses are provided that map to character memory in such a way that all addresses are consecutive:
0x00078000 - 0x00079FFF
|
Mirror of character table 0 |
0x0007A000 - 0x0007BFFF |
Mirror of character table 1 |
0x0007C000 - 0x0007DFFF |
Mirror of character table 2 |
0x0007E000 - 0x0007FFFF |
Mirror of character table 3 |
A character is an 8×8 pixel graphic represented by 16 bytes. Bytes are stored in the character data consecutively by address.
Each halfword contains 8 pixels at 2 bits per pixel in the following format:
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
p7 | p6 | p5 | p4 | p3 | p2 | p1 | p0 | ||||||||
2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
Each halfword represents one row of pixels in the character. Pixels at lower-order positions are displayed to the left of pixels at higher-order positions. Rows within the character are ordered top-to-bottom for a total of 8 halfwords.
Individual characters can appear anywhere in the scene by using them as objects, or "sprites". There is memory (OAM) for 1,024 objects:
0x0003E000 - 0x0003FFFF
|
Object attributes |
Object elements are 8 bytes in size, organized into 4 halfwords with the following format:
0 |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 |
|
- | Unused | These bits are not used by the VIP, but are functional memory. |
JX | Display Pointer X | The signed horizontal coordinate of the left edge of the object from the left edge of the image. |
JLON | Left Display On | If set, the object will be drawn to the left image. |
JRON | Right Display On | If set, the object will be drawn to the right image. |
JP | Parallax | The signed parallax offset applied to the horizontal coordinate. (See below) |
JY | Display Pointer Y | The vertical coordinate of the top edge of the object from the top edge of the image. (See below) |
JPLTS | Palette Selector | Specifies the palette index to use for this object. |
JHFLP | Horizontal Flip | If set, the character graphic will be reversed horizontally. |
JVFLP | Vertical Flip | If set, the character graphic will be reversed vertically. |
JCA | Character Number | The index of the character to draw. |
The JP
field is used to specify the apparent depth of the object
in the frame. This is achieved by modifying its horizontal position
differently for each eye. The final horizontal position for each of the left
and right images is calculated as follows:
Left: | JX - JP |
Right: | JX + JP |
The palette index specified by JPLTS
selects one of the object
("OBJ") palettes.
JY
is not formally two's complement, but is effectively the
lower 8 bits of a signed halfword value. It can express values in the range
of -8 to +224. Values 0xE0
through 0xF8
are beyond
the bounds of the image, so the exact range of the field is unknown.
JCA
indexes characters consecutively across all four character
tables. The virtual mirroring address of the character in question can be
calculated as 0x00078000 + JCA * 16
.
A background map is a mosaic of 64×64 characters. Background maps are stored in a region of memory that is shared with world parameters:
0x00020000 - 0x0003D7FF
|
Background maps and world parameters |
There is enough memory in this address range for 14 full background maps, plus a few more bytes. When accessing background maps, a full 16 indexes are allowed, but indexes 14 and 15 will access memory not intended for background maps.
Background maps are each 8,192 bytes in size and appear consecutively in memory by address.
Background maps contain 64×64 = 4,096 cells. Cell elements are halfwords with the following format:
15 | 14 | 13 | 12 | 11 | 10 | 0 | |||||||||
GPLTS |
BHFLP |
BVFLP |
- | Character | |||||||||||
2 | 1 | 1 | 1 | 11 |
- | Unused | These bits are not used by the VIP, but are functional memory. |
GPLTS | Palette Selector | Specifies the palette index to use for this cell. |
BHFLP | Horizontal Flip | If set, the character graphic will be reversed horizontally. |
BVFLP | Vertical Flip | If set, the character graphic will be reversed vertically. |
Character | Character Number | The index of the character to draw. |
The palette index specified by GPLTS
selects one of the
background ("BG") palettes.
Character
indexes characters consecutively across all four
character tables. The virtual mirroring address of the character in question
can be calculated as 0x00078000
+ Character
.
The order of cells in a background map is first left-to-right for each row, then top-to-bottom row order.
Overview
Overview
Backgrounds
World Attributes
Types
Normal Worlds
H-Bias Worlds
Affine Worlds
Object Worlds
All scenes drawn by the VIP are defined in worlds. Worlds can specify either backgrounds or objects to be drawn, both of which use pixel data stored in characters.
Worlds containing backgrounds define a rectangular region of pixels in the image, with position and dimension attributes. The contents of this area involve the world's background, which can be manipulated in various ways.
Worlds containing objects do not specify a windowed region. When an object world is processed, all of its child objects are drawn to the image at the locations specified in their own attributes.
There is memory for 32 worlds, and they
are processed in reverse order: beginning with world 31 and working backwards
to world 0. Worlds with higher indexes will appear behind, and be obscured
by, worlds of lesser indexes. If at any time a control world is
encountered (its END
flag is set), that world and all subsequent
worlds are skipped and the drawing procedure immediately completes.
Worlds come in six varieties:
Normal | The world's background is drawn normally, without any special modifications. |
H-Bias | Contains all of the features of Normal, but also allows each row of pixels within the background to be shifted horizontally, independently from one another. |
Affine | Each row of pixels is processed with a source coordinate within the background, and a vector, allowing for affine transformations of the background such as rotation and scaling, and can even be used to achieve perspective. |
Object | Draws a group of objects. |
Dummy |
Configured to produce no output. This occurs when both the
LON and RON flags are clear in the world's
attributes.
|
Control |
Signals early termination of the drawing procedure. This is specified by
setting the END flag in the world's attributes.
|
For more information regarding world configuration, see World Attributes.
Every world mode except object selects pixels from a background to draw into the image. The background is composed of 1 to 8 background maps arranged in some number of rows and columns within the world.
Backgrounds specify one background map as a base, and any additional
background maps are selected sequentially from memory. The background map to
use as the base is specified by the BG Map Base
field of the
world's attributes. For example, if a
background consisting of four background maps uses 8 as its base map, the
background will consist of maps 8, 9, 10 and 11.
The dimensions of the world's background are specified in units of background map, which are each 512×512 pixels in size. The number of background maps wide or tall a background can be is any power of 2 from 1 BG map to 8 BG maps. However, no more than 8 BG maps total are intended to be used in a single background, restricting which combinations of width and height are intended to be used.
For backgrounds consisting of 8 or fewer background maps, the arrangement of maps regardless of dimension is left-to-right for each row, then top-to-bottom row order. For example, a background that is 4 maps wide and 2 maps tall with a base map of 0 will be arranged as follows:
0 1 2 3
4 5 6 7
For backgrounds consisting of more than 8 background maps, the behavior of the VIP is unintended but nonetheless well-defined. Initially, the background is treated as the largest 8-map background that can be expressed with the specified height. This vertical arrangement is then repeated horizontally as many times as is necessary to fill in the entire background. For example, a 4×4 Background with a base map of 0 will be arranged as follows:
0 1 0 1
2 3 2 3
4 5 4 5
6 7 6 7
The actual index of the background map to use as the base depends on the
number of maps in the background. Generally speaking, the value written to
BG Map Base
in the world's attributes will automatically be
rounded down to the next multiple of the total number of background maps.
For example, if a background consists of 4 maps and the base map index is 11,
the actual map used as the base will be rounded down to 8. For the purposes
of determining which map to use as the base, backgrounds consisting of more
than 8 maps are treated as though they contain only 8, making their effective
base map indexes either 0 or 8.
There is memory for 32 worlds:
0x0003D800 - 0x0003DBFF
|
World attributes |
World elements are 32 bytes in size, organized into 16 halfwords with the following format:
0 |
|
4 |
|
8 |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
|
5 |
|
9 |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 |
|
6 |
|
10 |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 |
|
7 |
|
11 - 15 |
|
- | Work memory | These bits do not specify world attributes, but are used by the VIP as work memory. |
LON | Left Display On | If set, the world will be drawn to the left image. |
RON | Right Display On | If set, the world will be drawn to the right image. |
BGM | BG Modification | Indicates the world's contents. (See below) |
SCX | Screen X Size | Raise 2 to this power for the width of the world's background in background maps. |
SCY | Screen Y Size | Raise 2 to this power for the height of the world's background in background maps. |
OVER | Overplane |
If clear, the world's background will repeat indefinitely. If set, characters beyond the background's bounds will
use the character specified by Overplane Character .
|
END | End World Specification Flag | If set, this world and all worlds of lesser index will not be drawn to the frame buffer. |
BG Map Base | The index of the first background map in the world's background. | |
GX | BG X Destination | The signed horizontal coordinate of the left edge of the world from the left edge of the image. |
GP | BG Parallax Destination | The signed parallax offset applied to the world's horizontal coordinate. (See below) |
GY | BG Y Destination | The signed vertical coordinate of the top edge of the world from the top edge of the image. |
MX | BG X Source | The signed horizontal source coordinate of the pixel within the world's background, relative to the top-left corner of the background, to be displayed in the top-left corner of the world. |
MP | BG Parallax Source | The signed parallax offset applied to the background's horizontal source coordinate. (See below) |
MY | BG Y Source | The signed vertical source coordinate of the pixel within the world's background, relative to the top-left corner of the background, to be displayed in the top-left corner of the world. |
W | Window Width |
Add 1 to this figure to yield the width in pixels of the world. This
field's format depends on BGM . (See below)
|
H | Window Height | Add 1 to this figure to yield the height in pixels of the world. This value is signed. (See below) |
Param Base | Specifies the location in world parameter memory where this world's parameters can be found. (See below) | |
Overplane Character |
When OVER is set, characters beyond the background's bounds will
use the cell in background map memory at the index given by this
field.The corresponding address is 0x00020000
+ Overplane_Character × 2
|
BGM
determines the type of content displayed in the world:
0 | Normal BG |
1 | H-Bias BG |
2 | Affine BG |
3 | OBJ |
The GP
field is used to specify the apparent depth of the world
in the image. This is achieved by modifying its horizontal position
differently for each eye. The final horizontal destination position for each
of the left and right images is calculated as follows:
Left: | GX - GP |
Right: | GX + GP |
The MP
field is used to specify the apparent depth of the
background within the world. This is achieved by modifying its horizontal
background source position differently for each eye. The final horizontal
background source position for each of the left and right images is
calculated as follows:
Left: | MX - MP |
Right: | MX + MP |
For normal and H-bias worlds, W
is a 13-bit signed value. For
affine worlds, it is a 10-bit unsigned value.
The minimum height of normal and H-bias worlds is 8 pixels, even if
H
is in the range of 0 to 6. Affine worlds can be any height.
The Param Base
field specifies where in world attribute memory
the parameters for this world are located. The corresponding CPU address is
as follows:
0x00020000
+ Param_Base
× 2
Parameter elements are stored sequentially for each row of pixels in the
world at the address given by Param Base
. The first element is
for the top row of pixels, and each subsequent element is for each subsequent
row of pixels down.
World parameter elements are always located in the 0x00020000
-
0x0003FFFF
range of VIP memory, which is contains all of the background maps, worlds, world parameters,
the column table and objects. Care must be taken to prevent accessing data
used for other purposes. If the address for the parameters of a given row of
pixels would exceed 0x0003FFFF
, it will wrap back around to
0x00020000
and continue counting up from there.
Editor's Note: One case suggests that Overplane Character
may
have restrictions regarding the range of characters it is able to access.
Some experimentation is in order.
Editor's Note: Extensive research is required in order to determine the exact behavior of the VIP when drawing worlds with unintended attributes, such as negative or large dimensions, excessive parallax, etc. Research is also needed to determine which bits of world attribute memory are used by the VIP as work memory and in what ways.
A normal world is defined entirely with an entry in world attribute
memory. All attributes except Param Base
apply to normal worlds,
and BGM
must be 0.
An H-bias world inherits all of the features of normal worlds and introduces the ability to
manipulate the horizontal scrolling of each row of pixels independently. All
fields in world attribute memory apply
to H-bias worlds, and BGM
must be 1.
The Param Base
attribute points to the location in world
parameter memory where H-bias parameters can be found. The number of H-bias
elements required for a world is equal to the height in pixels of the world,
as there is one element for each row of pixels starting with the top row.
H-bias elements are 4 bytes in size, organized into 2 halfwords with the following format:
0 |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
|
- | Unused | These bits are not used by the VIP, but are functional memory. |
HOFSTL | Left | The signed horizontal offset to apply to the row of pixels for the left eye. |
HOFSTR | Right | The signed horizontal offset to apply to the row of pixels for the right eye. |
H-bias offsets function by adjusting the horizontal source position within the world's background for each row of pixels. The final horizontal background source position for each of the left and right images is calculated as follows:
Left: | MX - MP + HOFSTL |
Right: | MX + MP + HOFSTR |
The VIP appears to determine the address of HOFSTR
by OR'ing the
address of HOFSTL
with 2. If the Param Base
attribute in the world is not divisibe by 4, this will result in
HOFSTL
being used for both the left and right images, and
HOFSTR
will not be accessed.
An affine world inherits some basic features of normal worlds, but replaces the specifics of
how each row of pixels is drawn. All fields in world attribute memory except
MX
, MP
and MY
apply to affine worlds,
and BGM
must be 2.
The Param Base
attribute points to the location in world
parameter memory where affine parameters can be found. The number of affine
elements required for a world is equal to the height of the world in pixels,
as there is one element for each row of pixels starting with the top row.
Affine elements are 16 bytes in size, organized into 8 halfwords with the following format:
0 |
|
3 |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
|
4 |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 |
|
5 - 7 |
|
- | Work memory | These bits do not specify affine parameters, but are used by the VIP as work memory. |
MX | BG X Source | 13.3 fixed-point signed horizontal source coordinate of the pixel within the world's background, relative to the top-left corner of the background, to be displayed in the left-most column of the current row of pixels. |
MP | BG Parallax Source | The 16-bit signed parallax offset applied to the background's source coordinates. (See below) |
MY | BG Y Source | 13.3 fixed-point signed vertical source coordinate of the pixel within the world's background, relative to the top-left corner of the background, to be displayed in the left-most column of the current row of pixels. |
DX | BG X Direction | 7.9 fixed-point signed horizontal source offset added to the coordinate of the previous source pixel in the current row of pixels for each column of pixels in the world. |
DY | BG Y Direction | 7.9 fixed-point signed vertical source offset added to the coordinate of the previous source pixel in the current row of pixels for each column of pixels in the world. |
The affine parameters MX
and MY
are analogous to
the world attributes of the same names, but specify source coordinates with
sub-pixel precision. They will be used as the source background coordinates
of the left-most column in the corresponding row of output pixels in the
world. The source background coordinates for each subsequent column are
produced by adding DX
and DY
to the source
background coordinates of the pixel in the previous column.
The affine parameter MP
is analogous to the world attribute of
the same name. It is processed as though producing output for pixels in the
world that are shifted horizontally. For instance, a value of 1 in
MP
will produce output pixels as though they were 1 world
column to the right of their actual position.
If MP
is negative, it only applies to the left-eye image.
Otherwise, it only applies to the right-eye image.
The final background source positions for each of the left and right images, for each column of pixels i where i = 0 is the left-most column, are calculated as follows:
If MP < 0:
|
||||||||
If MP ≥ 0:
|
Editor's Note: Research is needed to determine which bits of affine parameter memory are used by the VIP as work memory and in what ways.
Editor's Note: IMPORTANT - Affine parameters should always be
configured to begin on a 16-byte boundary (lowest 3 bits of Param
Base
are clear). The VIP appears to determine field addresses with a
bitwise OR rather than addition, but writes to halfwords 5, 6 and 7 with
addition. Unaligned parameter elements will result in corruption of
subsequent elements.
An object world is used only to display objects and therefore ignores all attributes in world attribute memory except
BGM
, which must be 3.
The LON
and RON
world attributes do not influence
which eyes objects get drawn to: object visibility is determined entirely by
object attributes. However, if both flags are clear, the world will be
interpreted as a dummy world and will be skipped. In this situation, the
world does not count as an object world.
Objects are organized into one of four object groups, which are managed through global object group registers:
0x0005F848 | SPT0 | OBJ Control Register 0 |
0x0005F84A | SPT1 | OBJ Control Register 1 |
0x0005F84C | SPT2 | OBJ Control Register 2 |
0x0005F84E | SPT3 | OBJ Control Register 3 |
The format of all object group registers is the same:
15 | 10 | 9 | 0 | ||||||||||||
- | OBJ End Number | ||||||||||||||
6 | 10 |
- | These bits have no function and are undefined when read. | |
OBJ End Number | R/W | The ending index of objects in the group. |
An object group defines a range of objects with a start index and an end index. The end index is given by the corresponding object group register. The start index is 1 greater than the register of the next lower group. The start index of group 0 is always 0.
An internal object world counter is initialized to 3 at the start of image processing. Each time an object world is processed, the object group with the same index as the counter is drawn, then the counter is decremented by 1. The counter will reset to 3 every time it is decremented from 0, allowing each object group to be processed multiple times in one frame.
Objects within an object group are drawn in reverse order, beginning with the end index of the group and counting down until the start index of the group has been processed. If the end index is less than the start index, the process is still carried out as usual, continuing with processing of object index 1,023 after object index 0.
While the LEDs are emitting light during the display procedure, the angles between the mirrors and the user's eyes are constantly changing. If LED emissions were of constant duration for each column of pixels, then pixels on one side of the image would appear wider than pixels on the other side of the image. In order to correct for this, the column table was implemented.
0x0003DC00 - 0x0003DDFF
|
Left column table |
0x0003DE00 - 0x0003DFFF |
Right column table |
An entry in the column table is loaded during the display of every 4 columns of pixels. Column table entries are stored in column table memory consecutively by address, with lower addresses representing columns that are more to the right. There are 512 column table entries total, 256 for each eye. Column table entries are halfwords with the following format:
15 | 8 | 7 | 0 | ||||||||||||
Repeat | Column Length | ||||||||||||||
8 | 8 |
Repeat | R/W | Add 1 to this figure for the number of times to produce LED pulses for each column of pixels. |
Column Length | R/W | Add 1 to this figure for the amount of time to spend emitting light for each column of pixels, in units of 200 nanoseconds. |
The exact column table entries used during LED operation are determined by the servo and may change from one frame to the next. The VIP prefers to use the middle 96 entries, with the others providing room for adjustments to compensate for the physical behavior of the mirrors. The starting addresses for each eye's column table entries are made available via CTA.
CTA
- Column Table Read Start AddressAs the image is being displayed, a column table entry is loaded every 4 columns of pixels from left to right. The addresses of the left-most 4 columns can be queried with the following register:
0x0005F830 | CTA | Column Table Read Start Address |
15 | 8 | 7 | 0 | ||||||||||||
CTA_R | CTA_L | ||||||||||||||
8 | 8 |
CTA_R | R |
Index into the right column table. The corresponding address is 0x0003DE00 + (CTA_R ×
2)
|
CTA_L | R |
Index into the left column table. The corresponding address is 0x0003DC00 + (CTA_L ×
2)
|
The VIP has an internal pointer that is initialized with the corresponding
value from CTA
when displaying a
frame buffer. After each 4 columns of pixels
are displayed, the pointer is decremented, causing it to point to the next 4
columns of pixels to the right. This decrement operation can be prevented by
setting the LOCK
flag in
DPCTRL.
The LEDs in the display unit cannot actually emit light of varying intensity, so brightness is instead achieved by adjusting how long each pixel emits light. The less light that reaches the eye when displaying a pixel, the dimmer that pixel will appear to be. For the configuration of the base durations of LED emission for each level of brightness, see Brightness.
In addition to the LED emission interval per brightness level, there is also an idle interval register:
0x0005F82A | REST | Rest Control Register |
15 | 8 | 7 | 0 | ||||||||||||
- | Duration | ||||||||||||||
8 | 8 |
- | These bits have no function and are undefined when read. | |
Duration | R/W | Specifies the duration in units of 5 nanoseconds. |
When a pixel is displayed, its value is loaded from the frame buffer. The LED will pulse for the
appropriate brightness duration, then idle for the REST
duration. The number of times this occurs for each column of pixels is given
by the Repeat
field in the column table. Since more light
reaching the eye produces a brighter pixel, Repeat
serves as a
sort of brightness multiplier for the column.
If the total configured brightness + idle duration exceeds the time allotted for the corresponding column of pixels, the display will stop emitting and move onto the next column.
After a certain amount of time spent emitting light, the full intensity of the LEDs can be perceived by the human eye, and longer emissions will not appear to get any brighter.
The measurable brightness of a pixel is given by the duration of its brightness level multiplied by the
Repeat
field in the column table. If this measurement reaches
about 128, then any longer durations will not appear brighter to the user.
Nintendo provides a recommended column table configuration that is used by
all commercial software. The following data is to be loaded to addresses
0x0003DC00
and 0x0003DE00
:
+000 +010 +020 +030 +040 +050 +060 +070 +080 +090 +0A0 +0B0 +0C0 +0D0 +0E0 +0F0 +100 +110 +120 +130 +140 +150 +160 +170 +180 +190 +1A0 +1B0 +1C0 +1D0 +1E0 +1F0 |
FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 E0 00 BC 00 A6 00 96 00 8A 00 82 00 7A 00 74 00 6E 00 6A 00 66 00 62 00 60 00 5C 00 5A 00 58 00 56 00 54 00 52 00 50 00 50 00 4E 00 4C 00 4C 00 4A 00 4A 00 48 00 48 00 46 00 46 00 46 00 44 00 44 00 44 00 42 00 42 00 42 00 40 00 40 00 40 00 40 00 40 00 3E 00 3E 00 3E 00 3E 00 3E 00 3E 00 3E 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3C 00 3E 00 3E 00 3E 00 3E 00 3E 00 3E 00 3E 00 40 00 40 00 40 00 40 00 40 00 42 00 42 00 42 00 44 00 44 00 44 00 46 00 46 00 46 00 48 00 48 00 4A 00 4A 00 4C 00 4C 00 4E 00 50 00 50 00 52 00 54 00 56 00 58 00 5A 00 5C 00 60 00 62 00 66 00 6A 00 6E 00 74 00 7A 00 82 00 8A 00 96 00 A6 00 BC 00 E0 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 FE 00 |
The exact association between entries in the column table and physical columns of pixels is dynamic and can change without notice during system operation. The starting position in the column table during the display procedure each frame can be inspected using CTA.
Virtual Boy processes images in a double-buffered, stereoscopic frame buffer. The drawing procedure automatically alternates between buffers 0 and 1 for each eye, allowing one frame to be drawn while the previous frame is being displayed.
0x00000000 - 0x00005FFF
|
Left frame buffer 0 |
0x00008000 - 0x0000DFFF |
Left frame buffer 1 |
0x00010000 - 0x00015FFF |
Right frame buffer 0 |
0x00018000 - 0x0001DFFF |
Right frame buffer 1 |
A frame buffer is a 384×256 pixel image represented by 24,576 bytes. Bytes are stored in the frame buffer data consecutively by address.
Each halfword contains 8 pixels at 2 bits per pixel in the following format:
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
p7 | p6 | p5 | p4 | p3 | p2 | p1 | p0 | ||||||||
2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
Pixels at lower-order positions are displayed above pixels at higher-order positions.
Pixels are stored in column-major order in the frame buffer in order to transfer them more efficiently when displayed by the scanner. The order of pixels in the frame buffer is first top-to-bottom for each column, then left-to-right column order.
The VIP will only draw and display the top 224 rows of pixels in the frame buffer. In the interest of simplifying design and manufacture, additional memory is present for 32 rows below the bottom of the image within each frame buffer. This memory is never modified by the VIP but is fully functional.
The display unit in the VIP processes two images: one for each eye. A vertical column of LEDs is reflected off of oscillating mirrors in order to produce the illusion of a two-dimensional image.
The display is configured through two registers:
0x0005F820 | DPSTTS | Display Control Read Register |
0x0005F822 | DPCTRL | Display Control Write Register |
Both display registers have the same format:
15 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
- | LOCK |
SYNCE |
RE |
FCLK |
SCANRDY |
R1BSY |
L1BSY |
R0BSY |
L0BSY |
DISP |
DPRST |
||||
5 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are undefined when read. | |
LOCK | R/W | When set, CTA is prevented from updating. |
SYNCE | R/W | When clear, display sync signals are not sent to the display servo, preventing images from being displayed. |
RE | R/W | When clear, memory refresh signals will not be issued on VIP memory. |
FCLK | R | The display frame clock signal is high. |
SCANRDY | R | When set, the mirrors are stable. |
R1BSY [note] |
R | Right frame buffer 1 is being displayed. |
L1BSY [note] |
R | Left frame buffer 1 is being displayed. |
R0BSY [note] |
R | Right frame buffer 0 is being displayed. |
L0BSY [note] |
R | Left frame buffer 0 is being displayed. |
DISP | R/W | When set, the display is enabled. |
DPRST | W | When set, display functions are reset. When clear, no action occurs. |
[note] |
These fields are formally sub-fields of a 4-bit field called
DPBSY .
|
DPSTTS
is read-only and writes have no effect.
DPCTRL
is write-only and undefined when read. As such, fields
marked "R" above apply to DPSTTS
and fields marked "W" apply to
DPCTRL
.
SYNCE
and DISP
must both be set in order for images
to be displayed. With precise timing, SYNCE
might be used to
enable only one image at a time, but its function is effectively the same as
DISP
.
While RE
is clear, any VIP memory not used by the drawing procedure
will degrade after several seconds.
Setting the DPRST
flag will cause the following flags in
DPSTTS
to be undefined: LOCK
, FCLK
,
SCANRDY
and all four DPBSY
flags.
Setting the DPRST
flag will clear the following flags in
INTENB and
INTPND: TIMEERR
,
FRAMESTART
, GAMESTART
, RFBEND
,
LFBEND
and SCANERR
.
For more informaiton on the display frame clock signal, see Drawing and Display Procedures.
The VIP has a drawing feature built in that can produce images for display using graphics data supplied by the software. This drawing feature can be disabled, allowing software rendering through direct access to the frame buffer.
Drawing is configured through two registers:
0x0005F840 | XPSTTS | Drawing Control Read Register |
0x0005F842 | XPCTRL | Drawing Control Write Register |
Both drawing registers have the same format:
15 | 14 | 13 | 12 | 8 | 7 | 5 | 4 | 3 | 2 | 1 | 0 | ||||
SBOUT |
- |
SBCOUNT /
SBCMP |
- | OVERTIME |
F1BSY |
F0BSY |
XPEN |
XPRST |
|||||||
1 | 2 | 5 | 3 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are undefined when read. | |
SBOUT | R | Set when a group of 8 rows of pixels begins to draw. (See below) |
SBCOUNT | R | The current group of 8 rows of pixels, relative to the top of the image, currently being drawn. |
SBCMP | W | The group of 8 rows of pixels, relative to the top of the image, to compare with while drawing. |
OVERTIME | R | The drawing procedure has taken longer than the allotted time. |
F1BSY [note] |
R | Frame buffer 1 is being drawn to. |
F0BSY [note] |
R | Frame buffer 0 is being drawn to. |
XPEN | R/W | When set, drawing is enabled. |
XPRST | W | When set, drawing functions are reset. When clear, no action occurs. |
[note] |
These fields are formally sub-fields of a 2-bit field called
XPBSY .
|
XPSTTS
is read-only and writes have no effect.
XPCTRL
is write-only and undefined when read. As such, fields
marked "R" above apply to XPSTTS
and fields marked "W" apply to
XPCTRL
.
The VIP will draw to the frame buffer in
units of 1×8 pixels, from left to right. This corresponds to a
halfword write into frame buffer memory. For this reason, the vertical
position of drawing into the frame buffer is tracked in units of 8 rows of
pixels relative to the top of the image. SBCOUNT
is the current
group of 8 rows of pixels being processed during the drawing procedure.
SBOUT
is set each time SBCOUNT
is incremented, at
the start of processing for each group of 8 rows of pixels.
SBOUT
will automatically clear itself shortly thereafter.
[note]
[note] |
The formal specification states that SBOUT will be cleared
after 56 µs, but testing has shown it to persist for as long as
120 µs and overrun into the following group of 8 rows of pixels.
SBOUT is not a reliable way to detect changes to
SBCOUNT .
|
Setting the XPRST
flag will clear the XPEN
flag in
XPSTTS
.
Setting the XPRST
flag will clear the following flags in
INTENB and
INTPND: TIMEERR
,
XPEND
and SBHIT
.
For more informaiton on drawing processing, see Drawing and Display Procedures.
The displays in the Virtual Boy are only capable of emitting red light, but the intensity of that light can be adjusted in order to produce four shades of red per image, one of which is always black. The intensity of the other three can be controlled with global brightness settings:
0x0005F824 | BRTA | Brightness Control Register A |
0x0005F826 | BRTB | Brightness Control Register B |
0x0005F828 | BRTC | Brightness Control Register C |
The format of all brightness registers is the same:
15 | 8 | 7 | 0 | ||||||||||||
- | Duration | ||||||||||||||
8 | 8 |
- | These bits have no function and are undefined when read. | |
Duration | R/W | Specifies the duration in units of 5 nanoseconds. |
The LEDs in the display unit cannot actually emit light of varying intensity, so brightness is instead achieved by adjusting how long each pixel emits light. The less light that reaches the eye when displaying a pixel, the dimmer that pixel will appear to be. For additional information regarding LED emission periods and apparent brightness, see Column Table.
The brightness of each pixel in the frame buffer is determined by the pixel's value. Since pixels are 2 bits in size, there are four possible brightness levels:
0 | Black |
1 | Brightness level A |
2 | Brightness level B |
3 | Brightness level C |
Brightness levels A and B are configured directly, with zero representing no intensity and larger durations appearing brighter.
The actual duration of brightness level C is the sum of the durations in all three brightness registers: A + B + C.
When a character is drawn by the VIP, a palette is applied to each pixel before storing the result into the frame buffer. The palette used depends on the context in which the character is used: there are distinct palettes for background maps and objects.
The format of all palette registers is the same:
15 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||||||
- | c3 | c2 | c1 | - | |||||||||||
8 | 2 | 2 | 2 | 2 |
- | These bits have no function and are undefined when read. | |
c3 | R/W | The frame buffer pixel value for character pixel value 3. |
c2 | R/W | The frame buffer pixel value for character pixel value 2. |
c1 | R/W | The frame buffer pixel value for character pixel value 1. |
A pixel value of 0 in a character is interpreted as a transparent pixel and will not modify the contents of the frame buffer when drawn. Accordingly, there is no palette entry for character pixel value 0.
One of four palettes can be selected for each character, which is applied to every pixel within the character. The "BG" palettes are selected when the character is used in a background map, and the "OBJ" palettes are selected when the character is used in an object.
If any given pixel in the frame buffer is never drawn to by a character, its color will be determined by a global background color:
0x0005F870 | BKCOL | R/W | BG Color Palette Control Register |
15 | 2 | 1 | 0 | ||||||||||||
- | value |
||||||||||||||
14 | 2 |
- | These bits have no function and are undefined when read. | |
value | R/W | The initial frame buffer pixel value. |
After BKCOL
is written, the new background color will not be
applied until after the first 8 rows of pixels are drawn to the frame buffer
the next time a frame is drawn.
The VIP is capable of raising an interrupt for a
number of different conditions. Regardless of the cause, all VIP interrupts
have a code of 0xFE40
.
VIP interrupts are configured through three registers:
0x0005F800 | INTPND | Interrupt Pending |
0x0005F802 | INTENB | Interrupt Enable |
0x0005F804 | INTCLR | Interrupt Clear |
All interrupt registers have the same format:
15 | 14 | 13 | 12 | 5 | 4 | 3 | 2 | 1 | 0 | ||||||
TIMEERR |
XPEND |
SBHIT |
- | FRAMESTART |
GAMESTART |
RFBEND |
LFBEND |
SCANERR |
|||||||
1 | 1 | 1 | 8 | 1 | 1 | 1 | 1 | 1 |
- | These bits have no function and are undefined when read. |
TIMEERR |
Drawing is still in progress when the drawing procedure should begin.
Detects the OVERTIME flag in
XPSTTS.
|
XPEND | The drawing procedure has finished. |
SBHIT |
Drawing has begun on the group of 8 rows of pixels specified in the
SBCMP field of XPCTRL.
|
FRAMESTART | The display procedure has begun. |
GAMESTART | The drawing procedure has begun. |
RFBEND | The display procedure has completed for the right eye. |
LFBEND | The display procedure has completed for the left eye. |
SCANERR | The mirrors are not stable. |
INTPND
is read-only and writes have no effect.
INTCLR
is write-only and is undefined when read.
Interrupt conditions are enabled or disabled by writing to
INTENB
. If the corresponding flag is set, the interrupt
condition will be enabled, and if it is clear, the interrupt condition will
be disabled.
When an interrupt condition is satisfied, regardless of whether or not the
condition is enabled, the corresponding flag in INTPND
will be
set. If any flag is set in both INTENB
and INTPND
,
the VIP will issue an interrupt request signal to the CPU.
Interrupt conditions are acknowledged by writing to INTCLR
,
which will clear the corresponding flags in INTPND
.
Setting the DPRST
flag in DPCTRL will clear the following flags in
INTENB
and INTPND
: TIMEERR
,
FRAMESTART
, GAMESTART
, RFBEND
,
LFBEND
and SCANERR
.
Setting the XPRST
flag in XPCTRL will clear the following flags in
INTENB
and INTPND
: TIMEERR
,
XPEND
and SBHIT
.
For more information on the SBHIT
interrupt condition, see
Display.
FRMCYC
- Game Frame Control RegisterA game frame is the interval between invocations of the VIP drawing procedure. One game frame can be synchronized with a particular number of display frames:
0x0005F82E | FRMCYC | Game Frame Control Register |
15 | 4 | 3 | 0 | ||||||||||||
- | FRMCYC | ||||||||||||||
12 | 4 |
- | These bits have no function and are undefined when read. | |
FRMCYC | R/W | Add 1 to this figure for the number of display frames for each game frame. |
For more information regarding the synchronization of game frame and display frame, see Drawing and Display Procedures.
Editor's Note: If FRMCYC
is set to a value lower than the
internal frame counter in between game frames, what happens? Will the next
frame be a game frame? Will it wrap around at 15 and keep counting?
VER
- VIP Version RegisterThe version of the current VIP hardware can be queried with the following register:
0x0005F844 | VER | VIP Version Register |
15 | 5 | 4 | 0 | ||||||||||||
- | VER | ||||||||||||||
11 | 5 |
- | These bits have no function and are undefined when read. | |
VER | R | The version number of the current VIP hardware. |
Only one model of Virtual Boy was ever produced. Its VIP version is 2.
Overview
Overview
Memory Map
Output Procedure
Channels
PCM Waveforms
Channel Control
Stereo Levels
Frequency
Envelope
Sweep & Modulation
Noise
Master Control
Virtual Boy's sound unit has 6 channels, five of which produce tones by sampling from PCM memory and one of which produces binary noise.
Channels are named 1 through 6 and have the following features:
• |
All channels
|
||||||||
• |
Channels 1 through 4
|
||||||||
• |
Channel 5
|
||||||||
• |
Channel 6
|
Audio output from the mixer is 10-bit digital stereo at 41,700 Hz. Peripherals include two built-in stereo speakers, a volume wheel and a 3.5 mm headphone jack.
The VSU occupies addresses 0x01000000
- 0x01FFFFFF
in the system memory map.
All VSU addresses must be accessed with 8-bit writes. 16- and 32-bit writes have undefined behavior. All reads are undefined.
0x01000000 - 0x0100007F
|
Waveform 1 RAM |
0x01000080 - 0x010000FF |
Waveform 2 RAM |
0x01000100 - 0x0100017F |
Waveform 3 RAM |
0x01000180 - 0x010001FF |
Waveform 4 RAM |
0x01000200 - 0x0100027F |
Waveform 5 RAM |
0x01000280 - 0x010002FF |
Modulation RAM |
0x01000300 - 0x010003FF |
Unmapped |
0x01000400 - 0x010007FF |
I/O Registers (see below) |
0x01000800 - 0x01FFFFFF |
Mirroring of VSU memory map |
Writing to unmapped addresses has no apparent effect.
0x01000400 | S1INT | Channel 1 Sound Interval Specification Register |
0x01000404 | S1LRV | Channel 1 Level Setting Register |
0x01000408 | S1FQL | Channel 1 Frequency Setting Low Register |
0x0100040C | S1FQH | Channel 1 Frequency Setting High Register |
0x01000410 | S1EV0 | Channel 1 Envelope Specification Register 0 |
0x01000414 | S1EV1 | Channel 1 Envelope Specification Register 1 |
0x01000418 | S1RAM | Channel 1 Base Address Setting Register |
0x01000440 | S2INT | Channel 2 Sound Interval Specification Register |
0x01000444 | S2LRV | Channel 2 Level Setting Register |
0x01000448 | S2FQL | Channel 2 Frequency Setting Low Register |
0x0100044C | S2FQH | Channel 2 Frequency Setting High Register |
0x01000450 | S2EV0 | Channel 2 Envelope Specification Register 0 |
0x01000454 | S2EV1 | Channel 2 Envelope Specification Register 1 |
0x01000458 | S2RAM | Channel 2 Base Address Setting Register |
0x01000480 | S3INT | Channel 3 Sound Interval Specification Register |
0x01000484 | S3LRV | Channel 3 Level Setting Register |
0x01000488 | S3FQL | Channel 3 Frequency Setting Low Register |
0x0100048C | S3FQH | Channel 3 Frequency Setting High Register |
0x01000490 | S3EV0 | Channel 3 Envelope Specification Register 0 |
0x01000494 | S3EV1 | Channel 3 Envelope Specification Register 1 |
0x01000498 | S3RAM | Channel 3 Base Address Setting Register |
0x010004C0 | S4INT | Channel 4 Sound Interval Specification Register |
0x010004C4 | S4LRV | Channel 4 Level Setting Register |
0x010004C8 | S4FQL | Channel 4 Frequency Setting Low Register |
0x010004CC | S4FQH | Channel 4 Frequency Setting High Register |
0x010004D0 | S4EV0 | Channel 4 Envelope Specification Register 0 |
0x010004D4 | S4EV1 | Channel 4 Envelope Specification Register 1 |
0x010004D8 | S4RAM | Channel 4 Base Address Setting Register |
0x01000500 | S5INT | Channel 5 Sound Interval Specification Register |
0x01000504 | S5LRV | Channel 5 Level Setting Register |
0x01000508 | S5FQL | Channel 5 Frequency Setting Low Register |
0x0100050C | S5FQH | Channel 5 Frequency Setting High Register |
0x01000510 | S5EV0 | Channel 5 Envelope Specification Register 0 |
0x01000514 | S5EV1 | Channel 5 Envelope Specification Register 1 |
0x01000518 | S5RAM | Channel 5 Base Address Setting Register |
0x0100051C | S5SWP | Sweep/Modulation Register |
0x01000540 | S6INT | Channel 6 Sound Interval Specification Register |
0x01000544 | S6LRV | Channel 6 Level Setting Register |
0x01000548 | S6FQL | Channel 6 Frequency Setting Low Register |
0x0100054C | S6FQH | Channel 6 Frequency Setting High Register |
0x01000550 | S6EV0 | Channel 6 Envelope Specification Register 0 |
0x01000554 | S6EV1 | Channel 6 Envelope Specification Register 1 |
0x01000580 | SSTOP | Stop All Sound Output Register |
An unsigned, 6-bit input sample is produced for each of the 6 audio channels. Wave channel samples come directly from wave memory, and the noise channel's sample is generated according to the noise generation algorithm. If a channel is not active, 0 is used for its input sample.
Each channel has a master output level determined by its current envelope value, even if the envelope is not doing anything, and the left/right levels as determined by the channel's stereo levels configuration. This section refers to the left and right channel output streams in singular, but this algorithm applies to each stream independently.
For each channel:
▪ | The 4-bit stereo level is multiplied with the 4-bit envelope level. |
▪ | Of the resulting 8 bits, only the highest 5 are used as the amplitude value. |
▪ | If neither level was zero, 1 is added to the amplitude value. |
• | The 6-bit input sample is multiplied with the 5-bit amplitude value to produce the 11-bit channel output value. |
Once all channels have been processed:
▪ | The 11-bit channel output values for all channels are added together. |
▪ | Of the resulting 14 bits, only the highest 10 are used as the final output. |
Output is sampled at 41,700 Hz. The maximum output value is 685.
When converting to analog, the VSU implements an RC circuit to block the DC bias, effectively producing a first-order high-pass filter with a very low cutoff frequency. This prevents the output voltage from being exclusively non-negative without affecting the audible significance of the stream.
The RC circuit is implemented with a 100 Ω resistor and a 220 µF capacitor, resulting in a cutoff frequency of 1 / (2π × 100 × 0.000220) ≈ 7.234 Hz. It can be discretized with an arbitrary sampling rate using the following formulas:
RC | = | 100 × 0.000220 = 0.022 |
α | = | RC / (RC + 1 / SamplingRateHz) |
Then, for each sample:
Output[n] = α × ( Output[n - 1] + Input[n] - Input[n - 1] )
If no output line is plugged into the 3.5 mm headphone jack, the output will be sent to the internal stereo speakers. Otherwise, the output will be sent through the connected line and not to the speakers.
Wave generation on the VSU is performed by reading samples from PCM wave memory. There are five wave tables, each with 32 samples:
0x01000000 - 0x0100007F
|
Waveform 1 RAM |
0x01000080 - 0x010000FF |
Waveform 2 RAM |
0x01000100 - 0x0100017F |
Waveform 3 RAM |
0x01000180 - 0x010001FF |
Waveform 4 RAM |
0x01000200 - 0x0100027F |
Waveform 5 RAM |
Samples are 6-bit, unsigned integers. They are accessed on word boundaries (4 bytes apart, lowest address), but must be written using 8-bit store or output instructions. The upper 2 bits of the 8-bit value are ignored. 16- and 32-bit writes have undefined behavior.
PCM wave memory can only be written while all sound channels are inactive, including the noise channel. Attempts to write to it during sound generation will have no effect.
When a channel's SxINT register is written, the channel's current sampling position within wave memory will be reset to the first sample.
PCM waveforms are associated with audio channels through dedicated registers:
7 | 3 | 2 | 0 | ||||
- | Wave | ||||||
5 | 3 |
- | These bits have no function and are undefined when read. | |
Wave | W | The index of the waveform. |
Wave
specifies which PCM wave table to use on the sound channel,
such that a value of zero corresponds with waveform 1.
If a value greater than 4 (PCM wave 5) is specified for Wave
,
the channel will still play, but will not produce any sound. PCM wave memory
still cannot be written while any channel is active in this manner.
Channels are enabled and disabled through designated registers:
7 | 6 | 5 | 4 | 0 | |||
Enb |
- | Auto |
Interval | ||||
1 | 1 | 1 | 5 |
- | This bit has no function and is undefined when read. | |
Enb | W | Set to enable sound generation. |
Auto | W | Set to schedule automatic channel deactivation. |
Interval | W | The time to wait before deactivating the channel. |
When Enable
is set, the channel will begin generating sound.
Otherwise, the channel will be disabled and cease sound generation.
When Auto
is set, the channel will play for the amount of time
specified by Interval
and then automatically disable itself.
Otherwise, the channel will play until the software disables it.
Interval
specifies how long the channel should generate sound
before automatically shutting itself off as described above. The value plus
1 represents time in units of ≈ 3.84 ms (= 260.4 Hz).
Various state settings within the sound channel will be reset when its
SxINT
register is written:
• | The frequency delay counter will be reset to the beginning of its current sample. |
• | The current position in PCM wave memory will be reset to the first sample. |
• | The envelope step timer will be reset to the start of its step interval. |
• | The frequency modification timer will be reset to the start of its modification interval. |
• | The current position in modulation memory will be reset to the first value. |
• | The noise generator's shift register will be reset to all zeroes. |
The left and right stereo levels of a channel are configured through designated registers:
7 | 4 | 3 | 0 | ||||
Left | Right | ||||||
4 | 4 |
Left | W | The left volume. |
Right | W | The right volume. |
Each field controls the output level of the corresponding stereo stream. The level scales linearly with 0 being silence and 15 being maximum amplitude.
A channel's frequency specifies the interval at which it produces new samples.
All channels define a sampling rate with a base clock and a configurable delay. The base clock depends on the channel and cannot be changed, while the delay setting is used to configure how many base clocks to wait before moving on to the next sample.
A channel's base clock frequency depends on the channel:
5,000,000 Hz | Channels 1-5 |
500,000 Hz | Channel 6 |
The channel's delay setting specifies how many base clocks to wait between changing the sample value on the channel. To wait zero clocks is to update samples at the base clock frequency, and longer delays will update at slower intervals. This document refers to the delay setting as the "frequency value".
The number of base clocks to wait is calculated by subtracting the frequency value from 2,048 (1 greater than the 11-bit maximum value). In this way, higher frequency values correspond with higher frequencies.
Channels maintain two frequency values internally: the most recent value written to the frequency registers (see below) and the current value used as the delay counter during sound generation. Both values are unsigned 11-bit, with one byte representing the lower 8 bits and a second byte representing the upper 3 bits (the upper 5 bits of this byte are ignored).
Writing an 8-bit value to one of the frequency registers will update the corresponding bits of both the most recent value and the current value. Frequency modifications that occur during sound generation will only update the current value. Since frequency modifications can alter all 11 bits of the current value, programs should use both frequency registers to ensure the entire value is updated.
Since the VSU samples output from channels at 41,700 Hz, any frequency value that specifies a higher sampling rate will be subject to aliasing.
When a channel's SxINT register is written, its sampling delay counter is reset to the beginning of the current sample.
11-bit frequency values are configured through two registers per channel, one for the lower 8 bits of the value and the other for the upper 3 bits:
7 | 0 | ||||||
Low | |||||||
8 |
Low | W | The lower 8 bits of the frequency value. |
7 | 3 | 2 | 0 | ||||
- | High | ||||||
5 | 3 |
- | These bits have no function and are undefined when read. | |
High | W | The upper 3 bits of the frequency value. |
Frequency values are 11-bit, but must be written as two individual bytes
because the VSU bus is only 8 bits wide. The lower 8 bits come from the
SxFQL
register and the upper 3 bits come from the
SxFQH
register.
These registers will update the corresponding bits in both the channel's most recent and current frequency values. The bits from the register not written will remain unaffected.
The envelope feature maintains a channel envelope level that acts like a master volume setting independent from the stereo levels. The envelope can be configured to grow or decay automatically over time, and optionally reload a pre-configured value and repeat the grow/decay process. Even if automatic modifications are disabled, the envelope level must be initialized to some non-zero value in order for audible sound to be produced on the channel.
The envelope is controlled through two registers:
7 | 4 | 3 | 1 | 0 | |||
Value | Dir |
Interval | |||||
4 | 1 | 3 |
Value | W | The initial and reload value of the envelope. |
Dir | W | Specifies the direction in which the envelope is modified. (See below) |
Interval | W | Specifies the time between envelope modifications. (See below) |
7 | 6 | 4 | 3 | 2 | 1 | 0 | |
- | (Ext) | - | Rep |
Enb |
|||
1 | 3 | 2 | 1 | 1 |
- | These bits have no function and are undefined when read. | |
(Ext) | * | These bits have significance with regards to the frequency modification and noise features. |
Rep | W | Specifies whether envelope modification loops. (See below) |
Enb | W | When set, envelope modification is enabled. |
Writing to Value
changes the current envelope level and stores a
new reload value.
When Dir
is set, automatic envelope modifications will add 1 to
the current envelope level (grow). When clear, modifications will subtract 1
from the current level (decay).
Interval
specifies how long each envelope level lasts before
being automatically modified. The value plus 1 represents time in units of
≈ 15.36 ms (65.1 Hz).
If Enb
is set, the envelope level is automatically modified by 1
in the direction specified by Dir
at the interval specified by
Interval
. The envelope level can grow until it reaches 15 or
decay until it reaches 0. If Enb
is clear, automatic envelope
modifications will not occur.
If Rep
is set while Enb
is set, then after the
envelope is processed at its maximum (if Dir
is set) or minimum
(if Dir
is clear) level for one interval, the most recent value
written to Value
is reloaded as the envelope level for one
interval and automatic modifications will resume. If Rep
is not
set while Enb
is set, then the envelope level will remain at its
maximum or minimum value depending on Dir
.
Writing to S6EV1
will reset the noise
generator's shift register to all zeroes.
The following procedure takes place for each envelope frame as specified by
Interval
:
▪ | Sound is generated for Interval time. |
||
♦ |
If Enb is clear:
|
||
◊ |
Otherwise, if Dir is clear and the current envelope level is
not 0:
|
||
◊ |
Otherwise, if Dir is set and the current envelope level is
not 15:
|
||
◊ |
Otherwise, if Rep is set:
|
When the channel's SxINT register is written, the current
envelope frame is reset (needs to wait for the entire Interval
again).
Editor's Note: When the channel is enabled while the envelope's
Enb
is set, it will generate samples of value 0 for the first
5-10 milliseconds but otherwise function normally. It is not clear exactly
why this happens or whether it's consistent, so it could bear some further
investigation.
Channel 5 has, in addition to all of the features of Channels 1-4, support for frequency sweep and modulation functions. These functions will modify the current frequency value, but not the frequency value most recently written to the frequency registers.
Regardless of the frequency modification function used, a new frequency value is calculated at the beginning of the current frequency modification frame. After audio is generated for the current frame, the current frequency value is replaced by the calculated new value.
The sweep function produces a new frequency value relative to the current frequency value. The new frequency value is calculated by shifting the current frequency value right by a specified number of bits, then adding or subtracting the result to or from the current frequency value. This results in a sliding pitch on the logarithmic scale, as though along octaves.
If the calculated new frequency value is greater than 2,047, channel 5 will immediately be stopped without generating any further sound. A bug in the hardware implementation of the sweep function allows this to occur even if the sweep function is disabled (if either modifications are disabled or the modification interval is zero).
Because automatic channel shutoff occurs at the beginning of the current frequency modification frame (inspecting the calculated new frequency value), it will prevent the highest valid frequency value from being used in audio generation.
The modulation function produces a new frequency value by reading modulation values from VSU memory. Each frequency modification frame, a new frequency value is calculated by reading a modulation value and adding it to the most recent frequency value written to the frequency registers, retaining only the lowest 11 bits of the result.
After processing all 32 modulation values, frequency modification processing can either stop or continue from the first modulation value.
Writing to S5INT will reset the current modulation position to the first value in modulation memory.
There are 32 values in modulation memory:
0x01000280 - 0x010002FF
|
Modulation Data RAM |
Modulation values are 8-bit, two's complement signed integers. They are accessed on word boundaries (4 bytes apart, lowest address), but must be written using 8-bit store or output instructions. 16- and 32-bit writes have undefined behavior.
Modulation memory can only be written while sound channel 5 is inactive. Attempts to write to it while the channel is generating sound will have no effect.
Frequency modifications are controlled through two registers. Frequency modification bits exist in S5EV1 that do not pertain to envelope functionality:
0x01000514 | S5EV1 | Channel 5 Envelope Specification Register 1 |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | Enb |
Rep |
Func |
- | (Env) | ||
1 | 1 | 1 | 1 | 2 | 2 |
- | These bits have no function and are undefined when read. | |
Enb | W | When set, frequency modification is enabled. |
Rep | W | Specifies whether modulation loops. (See below) |
Func | W | Specifies the frequency modification function. (See below) |
(Env) | * | These bits have significance with regards to the envelope feature. |
0x0100051C | S5SWP | Sweep/Modulation Register |
7 | 6 | 4 | 3 | 2 | 0 | ||
Clk |
Interval | Dir |
Shift | ||||
1 | 3 | 1 | 3 |
Clk | W | Specifies the base modification clock. (See below) |
Interval | W | Specifies the modification interval. (See below) |
Dir | W | Specifies the sweep direction. (See below) |
Shift | W | Specifies the sweep shift amount. (See below) |
If Enb
is set and Interval
is not zero, frequency
modifications will be performed. Otherwise, the frequency will not be
modified.
Func
specifies which type of frequency modification is to take
place:
0 | Sweep |
1 | Modulation |
If Rep
is clear while the modulation function is selected, then
the 32 values in modulation memory will only be
processed once, leaving the frequency at the final value. Otherwise, if
Repeat
is set, modulation memory will continue to be processed
by wrapping back to the first value and continuing from there.
Clk
specifies the base clock for the frequency modification
interval:
0 | ≈ 0.96 ms (1041.6 Hz) |
1 | ≈ 7.68 ms (130.2 Hz) |
Interval
specifies how long each frequency lasts before being
automatically modified. The value exactly represents time in the unit
specified by Clk
. If Interval
is zero, the
frequency modification feature is disabled.
If Dir
is set while the sweep function is selected, the shifted
result is added to the current frequency value. Otherwise, if
Dir
is clear, the shifted result is subtracted from the current
frequency value.
When the sweep function is selected, Shift
specifies the number
of bits to shift the current frequency value to the right when calculating a
new frequency value.
For either frequency modification function, the following procedure takes
place for each frequency modification frame as specified by Clk
and Interval
:
▪ | A new frequency value is calculated, but is not yet applied. | ||
♦ |
If the new frequency value is greater than 2,047:
|
||
▪ | Sound is generated for the modification interval. | ||
♦ |
If Enb is set and Interval is not zero:
|
When S5INT is written, the current
frequency modification frame is reset to the beginning of its interval. The
current frequency value itself will not be changed by S5INT
,
meaning the most recent current frequency value will be used for one
frequency modification frame after re-enabling the channel.
If S5SWP is written specifying a new frequency modification interval, and the amount of time since the start of the current frequency modification frame is already greater than the new interval being set, the current frame will continue to be processed using the previous interval. However, if the new interval specifies a time that hasn't been fully processed yet during the current frame, the new interval will take effect immediately.
Channel 6 produces sound by generating pseudorandom noise. The noise generator is a 15-bit linear feedback shift register with a configurable tap location. Output is binary: noise is only either high or low.
Noise generation bits exist in S6EV1 that do not pertain to envelope functionality:
0x01000554 | S6EV1 | Channel 6 Envelope Specification Register 1 |
7 | 6 | 4 | 3 | 2 | 0 | ||
- | Tap | - | (Env) | ||||
1 | 3 | 2 | 2 |
- | These bits have no function and are undefined when read. | |
Tap | W | Specifies the bit to use in noise generation. (See below) |
(Env) | * | These bits have significance with regards to the envelope feature. |
Tap
specifies the bit within the shift register to use as the
feedback source in noise generation. Different bits will produce pseudorandom bit
sequences of different lengths before the sequences repeat:
0 | Bit 14 | Sequence length of 32,767 |
1 | Bit 10 | Sequence length of 1,953 |
2 | Bit 13 | Sequence length of 254 |
3 | Bit 4 | Sequence length of 217 |
4 | Bit 8 | Sequence length of 73 |
5 | Bit 6 | Sequence length of 63 |
6 | Bit 9 | Sequence length of 42 |
7 | Bit 11 | Sequence length of 28 |
Bit positions listed above are zero-based. That is, bit 0 is the bit at
position 0x0001
and bit 14 is the bit at position
0x4000
.
At the interval specified by the current frequency value, a single bit is produced by the noise generator. The bit is then scaled to 6 bits to be the same size as the samples of the other sound channels. That is to say, if a 0 is generated, the sample is 0; and if a 1 is generated, the sample is 63.
Noise generation begins by initializing the 15-bit shift register to all zeroes. This happens when either S6INT or S6EV1 is written.
For each pseudorandom sample, the following algorithm takes place:
▪ |
From the shift register, bit 7 (0x0080 ) is XORed with the bit
at Tap and the result inverted to produce a pseudorandom bit.
|
▪ | The value in the register is shifted left one bit. |
▪ | The pseudorandom bit is used as the new bit 0 of the shift register. |
▪ | The pseudorandom bit is scaled to 63 to produce the output sample. |
All channels can be globally controlled through a master control register:
0x01000580 | SSTOP | Stop All Sound Output Register |
7 | 1 | 0 | |||||
- | Stop |
||||||
7 | 1 |
- | These bits have no function and are undefined when read. | |
Stop | W | When set, stops all active channels. |
If Stop
is set, all active channels will be disabled. Clearing
Stop
has no effect.
This register will not prevent sounds from being generated: it only stops
active channels. Channels can be restarted without writing a 0 to
Stop
.
System components are initialized in the following ways when the Virtual Boy is powered on.
The following system registers are initialized on reset:
ECR | 0x0000FFF0 |
PC | 0xFFFFFFF0 |
PSW | 0x00008000 [note] |
[note] |
The only bit set in PSW on reset is the NP
flag.
|
All other system registers and all program
registers (except r0
) are undefined on reset.
Editor's Note: Research is needed to determine whether the cache is initialized during reset.
CCR | All fields zero |
CCSR | All fields set |
CDRR | 0x00 |
CDTR | 0x00 |
SCR | All fields zero |
SDHR | 0x00 |
SDLR | 0x00 |
Counter | 0xFFFF |
Reload | 0x0000 |
TCR | All fields zero |
Because the reload value is loaded into the counter when either of the reload registers is written, reset is the only time when the two figures can have different values.
WCR | All fields zero |
The contents of VIP memory is undefined on reset.
The following fields in I/O registers are initialized on reset:
DPSTTS | SYNCE | = 0 |
RE | = 0 | |
DISP | = 0 | |
INTENB | All fields zero | |
XPSTTS | XPEN | = 0 |
All other registers (including INTPND) and other fields within the above registers are undefined on reset.
Editor's note: The VSU appears to be initialized to all zeroes/disabled on reset, but this hasn't been definitively verified. If nothing else, SSTOP should probably be used on boot.
The contents of WRAM are undefined on reset.
Virtual Boy - Sacred Tech Scroll
October 20, 2024
Written by Guy Perfect
Produced for Planet Virtual Boy.
https://www.virtual-boy.com/
Special thanks to the following individuals:
V810 Family™ 32-bit Microprocessor User's Manual
October 1995
Document No. U10082EJ1V0UM00 (1st edition)
Written by Renesas Technology Corporation
Download
Project: Virtual Boy
Website by DogP
Link
The Unofficial Virtual Boy Home Page
Website by David Tucker
Link
IAR Assembler Reference Guide for V850
October 2010
Document No. AV850-4 (fourth edition)
Written by IAR Systems
Download
V830 Family™ 32-bit Microprocessor User's Manual
December 1997
Document No. U12496EJ2V0UM00 (2nd edition)
Written by Renesas Technology Corporation
Download
Unraveling The Enigma Of Nintendo's Virtual Boy, 20 Years Later
August 21, 2015
Article detailing the history of the Virtual Boy's development
Written by Benj Edwards.
Link
And countless hours of original research.