Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - Arkaeriit/reflet: A processor with a custom ISA · GitHub
Skip to content

Latest commit

History

452 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

REFLET

A RISC ISA. Reflet stands for RISC Elementary FLExible Thinking machine. To see a Reflet processor in action, see my implementation of a Reflet processor in a microcontroller here: https://github.com/Arkaeriit/Reflet-microcontroller.

This repository

This repository contains a simulator for a Reflet processor, an assembler to create Reflet machine code, and a Verilog implementation of a Reflet processor.

The architecture

Reflet is a RISC ISA. Each instruction is coded on a single byte and composed of a 4 or 8-bit opcode, followed by an optional 4-bit register. This ISA can be used with a processor with words of any size superior which is 8 bits times a power of two. When the processor has a word size above 8 bits, it is little-endian.

Most operations are made between one of the 12 general-purpose registers and an implicit working register.

Registers

A Reflet processor got 16 registers.

The working register

R0 or WR is the working register. This is the most important register, most operations will either copy its value into another register modify its content. Its use is never explicitly mentioned in the instructions as it is assumed that it is used most of the time. Its reset value is 0. This is very similar to the accumulator in other ISA with the exception than any register (including the working register) can be used as operand in the same way.

General purpose registers

R1 to R12 are the 12 general-purpose registers. They are meant to store values used to interact with the working register. Their reset values are 0.

Status register

R13 or SR is the status register.

  • The first bit is the comparison bit. It is set to 1 when a comparison instruction is realized and 0 otherwise. The comparison bit is used for conditional jumps.
  • The bits 1 to 4 are the flags to enable interrupts. Bit 1 enables interrupt 0, bit 2 enables interrupt 1, up to bit 4 which enables interrupt 3.
  • When bit 5 is set to 1, interrupt 0 is raised when invalid memory access is made.
  • The bits 8 to 15 are the reduced behaviors bits. When they are all set to 0, the processor behaves normally. When they are set to b00000001, if the word size of the processor is above 8 bits, the processor will act as a 8-bit processor when interfacing with memory. When they are set to b00000010, if the word size of the processor is above 16 bits, the processor will act as a 16-bit processor when interfacing with memory. To summarize, The processor will act as a 8 * (2 ^ (reduced-behavior - 1)) bits processor when interacting with memory. Those bits are not taken into account when interacting with the stack such as with pop and push instructions.

Its reset value is 0.

Program counter

R14 or PC is the program counter. It contains the address of the current address. It can also be used to jump to a specific code address when forcefully modified by the user. Its reset value is 4.

Stack pointer

R15 or SP is the stack pointer. It is updated when doing pop or push instructions and it points toward an address in RAM. Its reset value is 0 but it should be initialized if you intend to use the stack.

Instructions

Here is a list of the instruction of Reflet processor.

MnemonicOpcodeOperandEffect
read0x0A registerCopies the value in the argument register into the working register
cpy0x1A registerCopies the value of the working register into the argument register
set0x2A 4 bits numberPut the number in the working register
add0x3A registerAdd the value in the working register to the value in the argument register and put the result in the working register
and0x4A registerDo a bit-wise and between the working register and the argument register
or0x5A registerDo a bit-wise or between the working register and the argument register
xor0x6A registerDo a bitwise xor between the working register and the argument register
not0x7A registerPut in the working register the bit-wise not of the argument register
lsl0x8A registerShit the bits in working register to the left n times, where n is the content of the argument register
lsr0x9A registerShit the bits in working register to the right n times, where n is the content of the argument register
eq0xAA registerIf the content of the working register is the same as the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
les0xBA registerIf the content of the working register is less than the one in the argument registers, sets the comparison bit of the status register to 1. Otherwise, sets it to 0
str0xCA register with an addressStore the value in the working register to the address given in the argument register
load0xDA register with an addressPut in the working register the value at the address given in the argument register
jif0xE0NothingJump to the address in the working register if the comparison register is not equal to 0, does not affect the stack
call0xE1NothingPut the current address in the stack and jump to the address in the working register.
ret0xE2NothingJump to the address just after the address on top of the stack.
pop0xE3NothingPut the content of the working register on the stack and updates the stack pointer.
push0xE4NothingPut the value on top of the stack in the working register and updates the stack pointer.
cc20xE5NothingPut in the working register the opposite in two-complement of the working register.
cmpnot0xE6NothingFlip the comparison bit of the status register.
tbm0xE7NothingToggle byte mode. Toggle the memory accesses from the size specified by the status register to 8 bit and back.
quit0xE8NothingReset the processor or stop it.
debug0xE9NothingDoes not modify any registers but the processor sends a signal to tell it is executing a debug instruction.
atom0xEANothingSet the content of the address in the working register to 1 and set the status bit to whether or not the content of this address was 0.
retint0xEBNothingReturn from an interruption context.
setintb111011A two-bit numberSet the routine of the interruption of the given number to the address in the working register.
getintb111100A two-bit numberGet the routine of the interruption of the given number and put it in the working register.
getintstackb111101A two-bit numberGet the address at the given place in the interrupt stack.
setintstackb111110A two-bit numberGet the address at the given place in the interrupt stack.
softintb111111A two-bit numberTriggers the interrupt of the given number.

There is no no-op instructions, but a few instructions have no effects such as read WR, cpy WR, or and WR. As read WR is encoded as 0x00, it makes for a fine no-op instruction.

Connection to memory

Word size

To be able to work, a Reflet processor needs a connection to some RAM (or RAM and ROM) where values can be stored and machine code can be read. This document describes no word size for a Reflet processor. The Reflet processor word size should be 8 bits times a power of two. The memory should have a data bus the same size as the processor word size. As the instruction size is always 8 bits regardless of the CPU's word size, Reflet machine code could work with Reflet processor of any word size.

Alignment

To ease the utilization of memory, the memory access should be aligned to the size of the word. For example, when trying to manipulate 8-bit values, any address is valid. But when trying to manipulate 32-bit values, access should be aligned on 32 bits.

The access to data smaller than the word size, a module of the CPU handles this assuming that the memory output data from an address aligned to the word size. The address outputed by the CPU should be masked before addressing the memory. For example, in the case of a 16-bit CPU.

  • The CPU wants to read 8 bytes at address 0x3.
  • The CPU output 0x3 as the address.
  • Outside the CPU, the address is masked to 0x2 to be aligned to 16 bits.
  • The memory output 0xABCD, the data at address 0x2.
  • Inside of the CPU, the data is masked and shifted to be 0xAB, the data at address 0x3.

When an invalid memory access is made (for example, trying to read 16 bits from address 0x3), it is possible to raise an interrupt signal to trap it. Be careful, when exiting this interruption, the program will jump back to the instruction that raised the interruption. You should disable traping or editing the working register in this case to prevent an infinite loop.

Starting address

Any byte is a valid Reflet instruction. To enable a minimal value of error-correcting, the 4 first bytes of a machine code file can be reserved for the "ASRM" magic word. To allow the existence of the magic word, the program starts at the 5th byte, at address 4.

Interruptions

A Reflet processor can react to external interruptions and do special routines. There are 4 different interruptions going from 0 (the highest priority) to 3, (the lowest priority).

To use interrupts, you must first tell the processor what is its interrupt routine. To do so, you must use the setint instruction with the number of the instruction as an argument while the address of the interruption routine is in the working register. Then, you must enable the interruption by setting to 1 the correct bit on the status register. The interruption is now set and enabled.

If the instruction is set, when the processor will receive an interrupt signal, the content of the program counter will be stored. The address of the interruption routine will be then put in the program counter. All the other registers will stay unchanged so they must be protected inside the interruption routine. To finish the interruption routine, use the retint instruction which will restore the program counter to its state before rentering the interruption. Be careful, in order not to loop back in the interruption, you must make sure that the peripheral responsible for the interruption stopped sending it.

As there are different interruptions with different levels of priority, it is possible to nest interruptions. For example, if you are in the context of interruption 2 and that interruption 1 is raised, you will shift to the context of interruption 1. When doing retint you will shift back to the context of interrupt 2. On the other hand, if you are in the context of interrupt 2 and interrupt 3 is raised, you will fall into the context of interrupt 3 only when you use retint from the context of interrupt 2.

Except for the program counter, the registers are not banked when entering an interrupt context. Thus some care should be given to preserve them.

The only noticeable impact of being in interrupt context is that the byte mode is ignored. The number of byte used during memory access is influenced by the reduced behavior bits of the status register but the setup made with the tbm instruction are not taken into account. Once leaving the interrupt context, the byte mode is left as it was before entering the interrupt context.

About

A processor with a custom ISA

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages