QNICE - an Elegant 16 Bit Processor
| ||
QNICE is a rather simple, yet powerful 16 bit processor architecture which is a result of some research done in the late 1990s and the following years. The goal was to create a processor architectur which is as orthogonal as possible without complicating a hardware implementation unnecessarily. Since the design borrows heavily from the NICE processor which featured a 32 bit architecture, the resulting architecture was called QNICE for "Quite NICE". The architecture is very well suited for teaching the basics of computer architecture and hardware implementation. Furthermore programming the QNICE processor is really easy and thus the architecture already served as a training device for some lectures about programming as well as computer architecture. This introductory presentation contains valuable insights. |
||
QNICE at a Glance
| ||
|
||
Examples
| ||
Summing |
||
|
The QNICE assembler program shown on the left sums all values from 0x0000 to 0x1000. This example is really simple - the main idea is to count backwards from 0x1000 to 0x0000 and using the Z (zero) flag of the status register R14 as a control condition for the central loop. Due to the possibility of making all branches and subroutine calls conditional by prefixing them with the name of one of the eight status register status bits the loop effectively consists of only two instructions, a subtraction and an absolute branch (ABRA). Prefixing the flag controlling the instruction with an exclamation mark inverts the flag (without modifying the status register's contents) prior to testing thus the instruction ABRA LOOP, !Z will perform an absolute branch to the location labeled LOOP if the zero flag is not set. |
|
Subroutine Calls |
||
The code example below is a bit more complex and shows a subroutine which performs a string comparison (like the C standard library function strcmp). This function expects two pointers to the strings to be compared in the registers R9 and R10 and will return the result of the comparison in R8. Since the routine needs some registers for temporary storage of data is has to make sure that the contents of these registers are somehow saved at the entry of the subroutine and restored just before jumping back to the calling program. In traditional architectures this would involve pushing the registers to a stack (either explicitly, register by register, or controlled by a bit mask). Since QNICE features a register bank for its registers R0 to R7 saving and restoring the contents of these eight registers just makes it necessary to increment the register bank pointer which is made up by the eight upper bits of the status register R14 thus giving the routine access to its "own" set of registers R0 to R7. Before returning to the calling program the register bank pointer will be decremented making sure that the original register contents will be accessible again. Incrementing the register bank pointer is done by performing the instruction ADD 0x0100, R14, decrementing it by one is done at the label STR$_STRCMP_EXIT using the subtraction SUB 0x0100, R14.
A typical call to this routine would look like this:
|
||
Contents of the Distribution Kit
| ||
The historical QNICE distribution kit is available here and currently contains the following items (the most recent distribution kit is available here):
|
||
Current state of the project
| ||
The project is currently in a solid working state. We moved to GitHub and merged the repository with the QNICE-FPGA implementation. You find the repository here: https://github.com/sy2002/QNICE-FPGA. The following features are available:
Currently our main goal is to interest people in the QNICE architecture in general and in the implementation of the processor in hardware. If you are interested in joining the project, please contact Bernd Ulmann at ulmann@vaxman.de . |