Simple 16

Simple 16 is a toy 16-bit video game console designed with simplicity of implementation in mind. While it is technically a 16-bit system, it's capabilites are in many ways closer to an 8-bit system. Ultimately, the hope is that Simple 16 is simple enough to provide an easy introduction for the novice emudev while still containing all the essential features of an older game console.

Table of Contents

CPU

Overview

The Simple 16 CPU is a 16-bit RISC design. It has a main register file of 16 16-bit registers. Additionally, there are five special purpose registers dedicated to exception processing. It has a flag 16-bit addres space. Instructions are a fixed size and are also 16-bits.

Registers

The first 14 registers in the main file have no fixed function and are named r0 through r13. r14 serves as the program counter and points to the next instruction to be fetched. More information about instruction fetch and execution can be found in Execution Details. r15 serves as the status register. The status register contains bits corresponding to the result of the last arithmetic instruction and the interrupt mask. The layout of the status register is given below.

Bit Use Notes
15-5 Unused Should be set to zero.
4 Negative Flag Indicates the last result was negative.
3 Carry Flag Generally indicates a carry out of bit 15. Last bit shifted out for shift instructions.
2 Zero fFag Indicates the last result was zero.
1 Interrupt 1 enable Interrupt 1 can be taken when this bit is set.
0 Interrupt 0 enable Interrupt 0 can be taken when this bit is set.

Instructions

ldim IM, rD

ldim sign extends an 8-bit immediate value to 16-bits and assigns it to the designated register.

Flags: No change

Encoding:

15-12 11-4 3-0
Destination register 8-bit immediate value $0

lidmh IM, rD

ldimh assigns an 8-bit immediate value to the upper 8-bits of rD.

Flags: No change

Encoding:

15-12 11-4 3-0
Destination register 8-bit immediate value $1

ld8 rA, rB, rD

Reads a byte from the address indicated by the sum of rA and rB and loads it into rD

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $2

ld16 rA, rB, rD

Reads a word from the address indicated by the sum of rA and rB and loads it into rD

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $3

str8 rA, rB, rD

Writes the byte stored in rD to the address indicated by the sum of rA and rB.

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Register containing value to write (aka rD) Source A register Source B register $4

str16 rA, rB, rD

Writes the word stored in rD to the address indicated by the sum of rA and rB.

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Register containing value to write (aka rD) Source A register Source B register $5

add rA, rB, rD

Adds rA and rB. The result is stored in rD.

Flags: C = carry out of bit 15, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $6

adc rA, rB, rD

Adds rA, rB and the carry flag. The result is stored in rD.

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $7

Flags: C = carry out of bit 15, N = result is negative, Z = result is zero

and rA, rB, rD

Bitwise and of rA and rB is stored in rD.

Flags: C = unmodified, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $8

or rA, rB, rD

Bitwise or of rA and rB is stored in rD.

Flags: C = unmodified, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $9

xor rA, rB, rD

Bitwise exclusive or of rA and rB is stored in rD.

Flags: C = unmodified, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $A

lsl rA, rB, rD

The value in rA is shifted left by rB bits and stored in rD

Flags: C = last bit shifted out of rA, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $B

lsr rA, rB, rD

The value in rA is shifted right by rB bits and stored in rD

Flags: C = last bit shifted out of rA, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $C

asr rA, rB, rD

The value in rA is arithmetically shifted right by rB bits and stored in rD. The most significant bit of rA is copied into the newly shifted bits. This allows asr to be used for signed division by powers of 2 as the sign is preserved.

Flags: C = last bit shifted out of rA, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register Source B register $D

bCC LABEL

bCC performs a relative branch if the condition indicated by CC is true. It has a range of 131 instructions forward or 124 instructions backwards. CC must be one of the following values

CC Mnemonic Name Description
0 ra bRanch Always Unconditionall branch
1 rf bRanch False Effectively a nop
2 eq EQual Branch if zero flag is 1
3 ne Not Equal Branch if zero flag is 0
4 mi MInus Branch if negative flag is 1
5 pl PLus Branch if negative flag is 0
6 cs Carry Set Branch if carry flag is 1. Unsigned "less than" when used with cmp
7 cc Carry Clear Branch if carry flag is 1. Unsigned "greater or equal" when used with cmp
8 gr Greater Branch if carry flag is 0 and the zero flag is zero. Unsigned "greater" when used with cmp
9 le Less or Equal Branch if carry flag is 1 or the zero flag is 1. Unsigned "lesser or equal" when used with cmp
Use of CC values greater than 9 will result in an invalid instruction exception.

Flags: No change

Encoding:

15-12 11-4 3-0
CC Signed 8-bit offset. Offset is multiplied by two before being added to PC $E

mov rA, rD

Stores the value of rA in rD. This can be used as a return or jump instruction if rD is PC.

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register $0 $F

neg rA, rD

Calculates the 2s complement of rA and stores it in rD. This can be used in combination with add to implement subtraction.

Flags: C = carry out of bit 15, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register $1 $F

not rA, rD

Calculates the 1s complement of rA and stores it in rD.

Flags: C = unmodified, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register $2 $F

cmp rA, rD

Subtracts rA from rD and discards the result, but still updates flags.

Flags: C = carry out of bit 15, N = result is negative, Z = result is zero

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register $3 $F

call rA, rD

Stores the address of the next instruction in rD and sets PC to the value in rA. Used for calling subroutines.

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register $4 $F

swap rA, rD

Swaps the values in rA and rD.

Flags: No change

Encoding:

15-12 11-8 7-4 3-0
Destination register Source A register $5 $F

in rA, rD

Reads a word from the IO port indicated by rA and stores it in rD.

Flags: No change

out rA, rD

Writes the word stored in rD to the IO port indicated by rA.

Flags: No change

ini IM, rD

Reads a word from the IO port indicated by IM and stores it in rD. IM can range from 0 to 15.

Flags: No change

outi

Writes the word stored in rD to the IO port indicated by IM. IM can range from 0 to 15.

Flags: No change

addi IM, rD

Adds IM to the value in rD and stores the result in rD. IM range from -8 to -1 or 1 to 8. A value of 0 is used to indicate 8.

Flags: C = carry out of bit 15, N = result is negative, Z = result is zero

andi IM, rD

Performs a logical and of IM and the value in rD and stores the result in rD. IM can range from -8 to -1 or 1 to 8. A value of 0 is used to indicate 8.

Flags: C = unmodified, N = result is negative, Z = result is zero

ori IM, rD

Performs a logical or of IM and the value in rD and stores the result in rD. IM can range from-8 to -1 or 1 to 8. A value of 0 is used to indicate 8.

Flags: C = unmodified, N = result is negative, Z = result is zero

lsli IM, rD

Shifts the value in rD IM bits to the left. IM can range from 1 to 8.

Flags: C = last bit shifted out of rA, N = result is negative, Z = result is zero

lsri IM, rD

Shifts the value in rD IM bits to the right. IM can range from 1 to 8.

Flags: C = last bit shifted out of rA, N = result is negative, Z = result is zero

cmpi IM, rd

Subtracts IM from rD and discards the result, but updates flags. IM can range from -8 to 7.

Flags: C = carry out of bit 15, N = result is negative, Z = result is zero

reti rD

Sets rD to the value storeed in EUR, SR to the value stored in ESR and PC to the value stored in EPC. This instruction is used for returning from an exception or interrupt.

Flags: Updated corresponding to the value in ESR.

trap rD

Causes an exception to be taken to the vector indicated by rD.

Flags: Condition code flags unchanged, interrupt enable bits cleared.

trapi IM

Causes an exception to be taken to the vector indicated by IM

Flags: Condition code flags unchanged, interrupt enable bits cleared.

getepc rD

Stores the value of EPC in rD.

Flags: No change

setepc rD

Stores the vaule of rD in EPC.

Flags: No change

getesr rD

Stores the value of ESR in rD.

Flags: No change

setesr rD

Stores the value of rD in ESR.

Flags: No change

geteur rD

Stores the value of EUR in rD.

Flags: No change

seteur rD

Stores the value of rd in EUR.

Flags: No change

getenum rD

Stores the value of ENUM in rD.

Flags: No change

setenum rD

Stores the value of rd in ENUM.

Flags: No change

getvbr rD

Stores the value of VBR in rD.

Flags: No change

setvbr rD

Stores the valueof rD in VBR.

Flags: No change

Video

Overview

Simple 16 features a tile-based video processor using 8x8 pixel tiles. It supports a single background plane with a fixed width of 64 tiles and configurable height. 64 sprites can be displayed simultaneously and 20 can be displayed on each line. Each sprite can either be 8x8 or 16x16 pixels and can use either of the first two 16 color palettes. The background plane can make use of all 4 palettes.

Audio

Overview

Simple 16 has four square-wave tone generators with a 16-bit period and an 8-bit volume. The special value of 0 for the period causes the volume to be output constantly allowing the volume register to be used as a simple 8-bit DAC.

Timer

Overview

Simple 16 has a single timer with a 16-bit period. Interrupt 0 is triggered on timer expiration.

Controllers

Overview

Simple 16 supports 2 controllers, each with a D-pad and 8 buttons configured in either an SNES (4 action buttons on the face + 2 shoulder buttons + Start and Select) or Genesis 6-button controller (6 action buttons on the face + Start and Mode) arrangement. In this document, the buttons are given using the Genesis naming scheme. For a controller following the SNES layout, the right trigger is 'C', the left trigger is 'Z' and 'Select' is 'Mode'.

Serial Port

Overview

This port can be thought of a simple UART for debugging purposes. In an emulator, a write should result in a byte being written to stdout and a read should return a byte read from stdin. This peripheral can be omitted in which case writes should be ignored and reads should return $FFFF. The primary purpose of this port is to enable easy debugging of the CPU core before other, more complicated, peripherals are working.

Cartridge

Overview

Simple 16 allows for 48KB of flat mapped cartridge ROM. Future revisions may allow banking.