Computer Architecture Lab/Winter2006/PoettschacherRosenblattlWolf/iMISC

iMISC - invertable Minimized Instruction Set Computer

edit

The basic idea is to design a microprocessor that is able to perform all mandatory operations while reducing the usually rather rich RISC instruction set to a minimum.

Features

edit
  • CPU Architecture: RISC
  • Memory Architecture: Harvard
  • Number of Opcodes: 14
  • Number of Commands: 21
  • Pipeline Stages: 4 + Writeback
  • Branch Delay: 1 Cycle
  • Command execution: 1 Tick
  • Data Width: 16 bit
  • Registers: 32 16-bit Registers (29 for general purpose)
  • Addressable object size: 16-bit word
  • Ram address width: 16 bit
  • Ram size: up to 128 kb
  • Rom address width: 16 bit
  • Rom size: up to 128 kb

Specifications on Target (Altera Cyclone EP1C12Q240C8):

  • Logic Cells: about 1100 (with UART, depending on ROM size)
  • Total Memory Bits: 8704 + Rom
  • f_max: about 84 MHz (with most optimizations, depending on ROM size)

Design Decisions

edit

To minimize the instruction set we decided to use only three bits for the opcode, limiting them to eight different opcodes. To keep the overall design simple, we have chosen to implement a load/store harvard architecture. Currently, the design specifies a 16 bit cpu with 16 bit address space and 32 16 bit registers, 29 of them are general purpose. Another simplification is the lack of a program status word which normally holds some flags like the carry flag or an overflow flag. Also, there is no dedicated stack pointer. Jumps are performed by writing to the program counter which is a special register.

Registers

edit

The registers are numbered consecutively with a leading R character. The first register is R00. The three special registers are:

  • R29 ... Zero register (ZERO)
  • R30 ... Instruction Pointer (IP)
  • R31 ... Previous Instruction Pointer (PIP)

They have the mnemonics ZERO, IP and PIP.

Instruction Set

edit

For the given design, the following instructions are mandatory:

  • MV ... copys the value of one register to another register
  • LD ... loads a value from the given address to the given register
  • ST ... stores a value from a given register to the given address
  • AND, OR, NAND or NOR ... performs a logical (N)AND/(N)OR operation on the two given registers and store the value to a given register
  • ADD or SUB ... adds/subtracts the value of the second register to/from the first register
  • LSL ... performs a left shift on a register
  • LSR ... performs a right shift on a register

also, some form of conditional operation is needed, like

  • SKIP ... skips next operation

Although this are just 7 different instructions, we need some more instructions by several reasons. First, we use a harvard architecture, thus we want to separate access to the program memory (FLASH) from access to the data memory (SRAM). To simplify the load/store instructions, we limit them to the data memory, thus we need some way to get constants into a register as the data memory is not initialized. Therefore, we also need an instruction as

  • LDI ... loads a constant to a given register.

Another design decision is that we want to fit every instruction into 16 bit. As three bit are taken by the opcode, 13 bits are left for the parameters. We use 32 registers, thus we need 5 bits per register. This limits the number of parameters to 2, if both parameters of an instruction are register numbers. So instruction like NAND write the result to one of the given source registers. Additionally the LDI instructions cant load a 16 bit constant, so we decided to limit the size of the constant parameter to 8 bit and added a high byte/low byte flag. This leaves only 4 bits left for the register number, so constants can only be loaded into the lower 16 registers. To speed up execution, the AND, OR and NOR instructions are a good idea, although they could be done by software using NAND operations.

Memory-mapped I/O

edit

We implemented access to peripherals as the LED or the UART memory-mapped in the address range from 0x0200 to 0x0203, with the following special addresses:

  • 0x0200: The LED. If the bit 0 of this word is set, the LED goes on, otherwise, it goes off. A read has no effect.
  • 0x0201: UART read. If a byte is received by the UART hardware, it is read at this address in the low byte, with the high byte set to 0x01. If no byte is available, this is always read as 0x0000. A write has no effect.
  • 0x0202: UART write. If the UART write queue is not full, the lower byte of the word written here is transmitted. A read has no effect.
  • 0x0203: UART status. Bit 0 signals the possiblity to write to the UART, bit 1 signals if a byte is ready to be received.

invertability

edit

Finally, and not just to do something different than other designs, we enabled to invert instructions. This just means that by setting the inverted flag (by the SINV instruction), an opposite operation to the next instructions is performed, if possible. This enables to reduce the number of opcodes and enables further optimization within the pipeline. For example, the opposite operation of the LD instruction is the ST instruction. If the inverted flag is not set, only LD is possible, therefore no write back interferance within the pipeline is possible. If the iverted flag is set by the SINV instruction, all following LD instructions become ST instructions, therefore only write back operations may be possible.

Instruction Set of the iMISC architecture

edit
Instruction Set
Normal Inverted Bitfield Description
iNOP iNOP 0000 000000000000 Incontrovertible NOP
SKIP NOP 0001 000000000000 Skips the next Instruction or is ignored when inverted
LDI LDI 001H/L CCCCCCCC RdRdRdRd Loads C into the High/Low byte of Rd. Only the lower 16 Registers can be addressed by this.
LD ST 0100 0 RsRsRsRsRs 0 RdRdRdRdRd Loads the contents of the address given in Rs into Rd. When inverted, Rd is stored to the address given in Rs
MV MV 0110 0 RsRsRsRsRs0 RdRdRdRdRd Moves Rs to Rd
LSL LSR 1000 0 RsRsRsRsRs 0 RdRdRdRdRd Performs a logical left or right shift of Rs bits on Rd
CMP CMP 1001 0 RsRsRsRsRs 0 RdRdRdRdRd Compares Rs and Rd. Rs < Rd leads to Rd := -1, Rs = Rd to Rd := 0 and Rs > Rd to Rd := 1
NAND AND 1010 0 RsRsRsRsRs 0 RdRdRdRdRd Performs a logical NAND or AND of Rs and Rd and stores the result in Rd
NOR OR 1011 0 RsRsRsRsRs 0 RdRdRdRdRd Performs a logical NAND or AND of Rs and Rd and stores the result in Rd
ADD SUB 1100 0 RsRsRsRsRs 0 RdRdRdRdRd Adds the value in Rs to Rd or subtracts Rs from Rd
ADD (C) SUB (C) 1101 CCCCCCC RdRdRdRdRd Adds C to Rd or subtracts C from Rd
SINV SINV 1110 0 RsRsRsRsRs 000000 Sets the invert flag when Rs is nonzero, cleares it otherwise
SINV (C) SINV (C) 1111 00000000000 C Sets the invert flag to the value of C

As the mnemonics are used as the following:

  • 0 ... one bit with value zero
  • 1 ... one bit with value one
  • C ... one bit of constant
  • Rs ... one bit of the number of the source register
  • Rd ... one bit of the number of the destination register
  • H/L ... one bit signaling if high or low byte, H is equivalent to 1 and L to 0

Diagram

edit

The following Diagram shows the actual architecture: imisc_architecture.gif

Assembler

edit

The Assembler is the basic instrument to feed the iMISC architecture with machinecode. It is able to output text, binary or vhdl rom code. Also, it performs basic checks on the code. When using a C-Precompiler, assembler code becomes more readable as the iMISC-Assembler was not made to make code looking nice...

Language

edit

The assembler language is mostly comparable to the structure of the binary code, although there are some differences. Mainly, the assembler uses what it gets from the input file and converts it to the binary codeword which is written to the output. As the semantic of a codeword depends on the state of the InvertedFlag, it does not depend which of its representations is used. The basic syntax of an assembler command is as follows:

CMD SRC, DST

Here, CMD is the command name, SRC is the source may be a register or constant, depending on the command and DST is the destination and therefore again a register. Constants may be in decimal or hexadecimal format (either with leading 0x or h). The registers are named R00 to R31. The use of the special registers may be restricted depending on their meaning. R29 (ZERO) and R31 (PIP) must not be the destination register. R30, the instruction pointer register, may only be written through a move command where the source register is R00. Labels can be placed at the begin of a line and are delimited by a colon. They can be treated like constants (they are converted to 16-bit-addresses). The commands are as follows:

Commands
Normal Inverted SRC DST Description
iNOP iNOP none none Incontrovertible NOP
SKIP NOP none none Skips the next Instruction or is ignored when inverted flag is set
LDI LDI 8-bit-Constant Register (R00-R15) Loads C into the Low byte of Rd. Only the lower 16 Registers can be addressed by this.
LDI HIGH LDI HIGH (8-bit-Constant) Register (R00-R15) Loads C into the High byte of Rd. Only the lower 16 Registers can be addressed by this.
LD ST Register Register Loads the contents of the address given in SRC into DST. When inverted, SRC is stored to the address given in DST
MV MV Register Register Moves Rs to Rd
LSL LSR Register Register Performs a logical left or right shift on DEST by the number of bits given in SRC
CMP CMP Register Register Compares SRC and DEST similar to strcmp. DEST := -1 iff SRC<DEST or 0 iff SRC=DEST or 1 iff SRC>DEST
NAND AND Register Register Performs a logical NAND or AND of SRC and DST and stores the result in DST
NOR OR Register Register Performs a logical NAND or AND of SRC and DST and stores the result in DST
ADD SUB Register Register Adds the value in SRC to DST or subtracts SRC from DST
ADD SUB 7-Bit-Constant Register Adds a 7-bit-Constant to DST or subtracts the constant from DST
SINV SINV Register none Sets the invert flag when SRC is nonzero, cleares it otherwise
SINV SINV 1-Bit-Constant none Sets the invert flag to the value of the constant

File Structure

edit

A very basic assembler file may look like that:

final: LDI HIGH(final), R00
       LDI LOW(final), R00
       MV R00,R30

This is a simple endless loop which should be placed at the end of every assembler file to prevent the processor to execute unwanted code.

As usual, semicolon can be used for comments. When using a C-Precompiler, some defines may be useful:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Convenience defines

#define ZERO r29
#define JMP MV R00,R30

final: LDI HIGH(final), R00
       LDI LOW(final), R00
       JMP

Usage

edit
$ ./as-iMISC.exe --help
iMISC assembler, reads from stdin, writes to stdout
switches: -t --text   ... create human readable assembler output from input
          -b --binary ... create binary text from input
          -v --vhdl   ... create VHDL output from input (default)
To run the C preprocessor before assembling (recommended):
gcc -x c -E -C -P <infile> | ./as-iMISC <switch>

Files

edit

All files related to this project are available at http://stud4.tuwien.ac.at/~e0325880/iMISC/. As there are: