-
16 bit architecture
- All pointers/addresses are word addresses
- No concept of bytes / double-words / ... If required, it must be handled purely in software
-
Harvard architecture
- Program space
- Data space
- IO space
- Default configuration:
- 1 SPRAM + small ROM for Program space giving 16k words
- 1 EBR for Data giving 256 words
-
32 General-Purpose Registers
- In fact just windowed accesses into RAM
- 2 banks of 16 registers
- 'R' bank (
R0
->RF
) : can only be either at the bottom or top of RAM - 'S' bank (
S0
->SF
) : base address can be moved by increment of 4 words - Special opcode
WIN
is used to control the windows
-
Special registers
A
accumulator, used for transfer, ALU operations, ...X
index register: used for indexed access into Program / Data / IO space.- Also used as a link register for function calls
Y
index register: used for indexed access into Data / IO space- Indexed accesses can also include a 4 bit immediate offset and post-increment/decrement
MCSR
provides read access to flags and control over register window
-
Processor flags:
Z
: ZeroC
: CarryN
: NegativeV
: Overflow
-
Control flow
- Jumps / Calls have a delay slot right after them (i.e. the next instruction is executed even if the branch is taken)
- Only testing the Z flag is supported in conditional control flow. To support other conditions, a special op code can test other flags and assign the result to Z
-
Load / Store to Program memory
- Instructions allow to freely load and store to the program memory
- Those accesses are subject to several limitations and must be done very carefully
- All accesses will result in a lost execution cycle hapenning 2 cycles after the access opcode.
- If the opcode following the program memory access is a branch instruction,
the opcode in the delay slot will not be executed if the branch is taken
- Better avoid branches after those accesses all together
- Load access won't have the result available directly. The next instruction can't
use the
A
register as its value is undefined - Two accesses can't be done right after the other
- All in all, unless being very careful, it's better to use a
NOP
right after any program memory load / store.
-
Load / Store to Data memory (including GPR accesses)
- Reading a memory location that was written in the previous cycle will yield undefined results
-
Other 'gotchas':
- Post-increment / Post-decrement are done in the 'Execute' stage, while operand value are fetched in the 'Decode' stage and so the updated value of the register will be availble 1 cycle late. If you don't use the same index register in two consecutive instructions, this is not an issue.
- A special
IMM
instructions allows to extend any I-format op code to use 16 bit immediate. (use the 'IMM' instruction right before). It can also be used twice to add support for immediate operands to some opcode that would otherwise not support and immediate argument.
Beause this CPU uses SPRAM as the main program memory and SPRAM cannot be initialized, the boot process is a bit special.
General idea is :
- In addition to the SPRAM, a small 16 word ROM is mapped to the boot address.
- This ROM will execute the FSBL (First Stage Boot Loader) that will copy the content of data RAM (which can be initialized) to address 0 of program memory and jump to it.
- This program can either be the final application if it's small enough. or this can be a SSBL (Second Stage Boot Loader) that will load the real application from another medium like SPI flash
,---------------------------------------------------------------,
| f | e | d | c | b | a | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---------------------------------------------------------------|
| opcode | 1 | s | imm8 |
'---------------------------------------------------------------'
This format contains an 8 bit immediate field and a sign specifier.
Depending on the actual instruction and if there was a special imm
instruction executed before, the implicit I
immediate register
will either be a sign-extended version of the 9 bits value formed by
s
+ imm8
, or a combination of the two imm8
fields.
,---------------------------------------------------------------,
| f | e | d | c | b | a | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---------------------------------------------------------------|
| opcode | 0 | 0 | d | src | reg |
'---------------------------------------------------------------'
This instruction format is used when accessing General Purpose Registers.
-
reg
: 5 bits used to indicate which register is to be accessed- The MSB selected the bank (
0
= R bank,1
= S bank) - The 4 LSBs select the actual register within the bank
- The MSB selected the bank (
-
src
: Selects the operands for the operation to be performed00
=A
, GPR01
=A
, Immediate10
= GPR,A
11
= GPR, Immediate- For operations with only 1 operand, only the first is
applicable and only
01
and11
are valid.
-
d
: Selects the destination (if applicable)0
=A
1
= GPR
,---------------------------------------------------------------,
| f | e | d | c | b | a | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---------------------------------------------------------------|
| opcode | 0 | 1 | mod | sel | imm 4 |
'---------------------------------------------------------------'
-
mod
: Post operation to be applied to the special register.00
: None01
: Reserved10
: Post-Increment11
: Post-Decrement- This is only valid for
X
andY
registers and should be set to00
for all other cases
-
sel
: Select special register00
:X
01
:Y
10
:MCSR
(read-only) /WIN
(write-only)11
:BSWAP(A)
(byte swapped version ofA
, read-only)
-
imm4
: 4 bit immediate field. Meaning is dependent on opcode
Op Code | Instruction class |
---|---|
00xxxx |
ALU 2 operands |
01xxxx |
ALU 1 operand |
10000x |
Program Memory access |
10001x |
Data Memory access |
1001xx |
IO access |
101xxx |
Special |
11xxxx |
Control Flow |
Sub Op | Mnemonic | Description |
---|---|---|
0010 |
CMP |
Same as SUB but without writing result |
0100 |
TEST |
Same as AND but without writing result |
1000 |
ADD |
dst ← OpA + OpB |
1001 |
ADDCY |
dst ← OpA + OpB + C |
1010 |
SUB |
dst ← ~OpA + OpB + 1 |
1011 |
SUBCY |
dst ← ~OpA + OpB + C |
1100 |
AND |
dst ← OpA & OpB |
1101 |
ANDN |
dst ← ~OpA & OpB |
1110 |
OR |
dst ← OpA | OpB |
1111 |
XOR |
dst ← OpA ^ OpB |
Note that the MSB is in fact a write enable and so any operation can be used to update the flag without writing the result if need-be.
The valid instruction formats are :
- I-fmt: In this case dst and OpA is always
A
and OpB is always the immediate - G-fmt: In this case the OpA,OpB couple is specified by the
src
field anddst
by thed
field.
Sub Op | Mnemonic | Description |
---|---|---|
0000 |
INC |
dst ← OpA + 1 |
0001 |
DEC |
dst ← OpA - 1 |
1000 |
ROL |
dst ← RotateLeft(OpA) |
1001 |
SL0 |
dst ← OpA << 1 |
1010 |
SL1 |
dst ← OpA << 1|1 |
1011 |
SLC |
dst ← OpA << 1|C |
1100 |
ROR |
dst ← RotateRight(OpA) |
1101 |
SR0 |
dst ← OpA >> 1 |
1110 |
SRA |
dst ← (OpA >> 1)|(OpA & (1 << 15)) |
1111 |
SRC |
dst ← (OpA >> 1)|(C << 15) |
The valid instruction formats are :
- G-fmt:
dst
selected by thed
fieldOpA
is the first operand from thesrc
field with only01
and11
being valid- This means you can have
A
as both source and destination the the GPR is actually ignored.
- S-fmt:
- FIXME ... this should actually be possible to use
[X]
/[Y]
as operand with minimal changes to the decode logic. dst
would always be the same asOpA
for this combination
- FIXME ... this should actually be possible to use
Store / Load between accumulator and program memory
Sub Op | Mnemonic | Description |
---|---|---|
0 |
LDP |
Load Program memory |
1 |
STP |
Store Program memory |
The valid instruction formats are :
- I-fmt: Absolute address access.
- S-fmt: Only
X
special register without offset is supported for indexed access
Store / Load between accumulator and data memory
Sub Op | Mnemonic | Description |
---|---|---|
0 |
LDD / MOV |
Load Data memory |
1 |
STD / MOV |
Store Data memory |
The valid instruction formats are :
- I-fmt: Absolute address access.
- S-fmt: Only
X
/Y
special register supported for indexed access - G-fmt: In this case the mnemonic used is
MOV
and the order of operand is what selected between Store / Load
Read/Write between IO and accumulator
Sub Op | Mnemonic | Description |
---|---|---|
00 |
IORR |
IO Read Request |
01 |
IORD |
IO Read Data |
10 |
IOWR |
IO Write Request |
The valid instruction formats are :
- I-fmt: Absolute address access.
- S-fmt: Only
X
/Y
special register supported for indexed access
For S-fmt:
The a
and b
bit control which is read/written.
a
== 1 :A
is written with the SPR valueb
== 1 : SPR is written withA
value- Both can be set at once to allow for atomic swaps
For I-fmt:
This is used to load constant in A
register. ab
must be 10
.
This instruction essentially a move from A
to MCSR
and is encoded as such.
But the value of A
is not simply written to the window, instead the imm4
field is used as an operation to apply:
Bit | Name | Description |
---|---|---|
3 |
win_R_ce |
Enable update of R window |
2 |
win_R_rel |
Apply relative change to R window |
1 |
win_S_ce |
Enable update of S window |
0 |
win_S_rel |
Apply relative change to S window |
Each window can either be left unaffected, or be updated with a new value.
The new value can either be the value of A
directly, or the old value added
to the value of A
.
Only I-fmt is supported (obviously ...)
Only the I-fmt is supported with the LSB of the immediate indicating which extended condition code to use.
imm[2:0] |
Code | Condition | Description |
---|---|---|---|
000 |
mi |
Z = N |
Negative |
001 |
vs |
Z = V |
Signed Overflow |
010 |
ior |
Z = IO Req ready |
Is IO ready for a new request ? |
011 |
iod |
Z = IO Read ready |
Is IO ready for read ? |
100 |
cs /hs |
Z = C |
Carry Set |
101 |
ge |
Z = (N == V) |
Signed greater than or equal |
110 |
hi |
Z = (Z==0) && (C==1) |
Unsigned higher |
111 |
gt |
Z = (Z==0) && (N==V) |
Signed greater than |
,---------------,
| d | c | b | a |
|---------------|
| l | r | cc |
'---------------'
l
= Link. If set,X
will be set to the return address.- Note that
X
is set regardless if the jump is executed or not !
- Note that
r
= Relativecc
= Condition Code00
- Never01
- Always10
-Z == 0
11
-Z == 1
The mnemonic for the combinations are :
Sub Op | Mnemonic | Description |
---|---|---|
00xx |
BA / BAX |
Branch Absolute |
01xx |
BR / BRX |
Branch Relative |
10xx |
BAL / BALX |
Branch Absolute and Link |
11xx |
BRL / BRLX |
Branch Relative and Link |
The condition code are marked with a suffix. If no suffix is set, then the 'Always' condition code is assumed.
Code | cc |
Description |
---|---|---|
nv |
00 |
Never |
al |
01 |
Always (normally omitted) |
z |
10 |
Zero |
nz |
11 |
Non-Zero |
The valid instruction formats are :
- I-fmt: Immediate field is used for the jump target
- S-fmt: Only
mod
=00
, 'sel'=00
andimm4
=0000
is supported.- Mnemonics are the ones with an
X
suffix - Uses the
X
register instead of immediate target
- Mnemonics are the ones with an