Computer Architecture Lab/Winter2006/LechnerWalterStadlerTrinkl/Workplace

RISE

edit

Design decisions

edit

We have choose to do a RISC processor featuring a typical load/store architecture. The only powerful instructions are the load (LD) and store instructions (ST) where we focused on a single-cycle implementation. Some parts of the instructions has been inspired by the ARM architecture which has similar load/store operations. All operations can be conditional. We have chosen to use only general purpose registers where we have given the register R13 to R15 special meanings. Please not that all registers share the same location with the exception of the register R15'.

User Mode Interrupt Mode
R0 16 Bit Zero Register R0 16 Bit Zero Register
R1 16 Bit General Purpose Register R1 16 Bit General Purpose Register
R2 16 Bit General Purpose Register R2 16 Bit General Purpose Register
R3 16 Bit General Purpose Register R3 16 Bit General Purpose Register
R4 16 Bit General Purpose Register R4 16 Bit General Purpose Register
R5 16 Bit General Purpose Register R5 16 Bit General Purpose Register
R6 16 Bit General Purpose Register R6 16 Bit General Purpose Register
R7 16 Bit General Purpose Register R7 16 Bit General Purpose Register
R8 16 Bit General Purpose Register R8 16 Bit General Purpose Register
R9 16 Bit General Purpose Register R9 16 Bit General Purpose Register
R10 16 Bit General Purpose Register R10 16 Bit General Purpose Register
R11 16 Bit General Purpose Register R11 16 Bit General Purpose Register
R12 16 Bit General Purpose Register R12 16 Bit General Purpose Register
R13 16 Bit Link Register (Special - See Notes) R13 16 Bit Link Register (Special - See Notes)
R14 16 Bit Program Counter (Special - See Notes) R14 16 Bit Program Counter (Special - See Notes)
R15 Status Register R15 Status Register
R15' Backup Status Register

Register file of RISE processor

Notes: The Link Register R13 is updated with the value of the program counter PC + 2 if the Jump Subroutine instruction is executed. This effectively places the return address in the link register.
Notes SR: The Status Register is special because is contains a lot of flags. The lower byte is used to store conditionals and the high byte is used for interrupt handling (Not implemented):

Bit15 Bit14:12 Bit11:8 Bit 7:4 Bit 3 Bit 2 Bit 1 Bit 0
Disable Interrupts Interrupt Priority Mask - - Overflow Negative Carry Zero

Status Register

Pipeline stages

edit
  • Instruction fetch: Fetches instructions from program memory.
  • Instruction decode and Register fetch
  • Execution
  • Memory Access
  • Write back

Instruction decode and Argument fetch stages could probably be combined in one single stage.

Interrupt Handling (Feature)

edit

The processor supports eight external interrupt sources INT0 to INT7. If an external interrupt pin is high the value of the interrupt source is compared with the priority level in the status register. If it is greater than or equal to the level and the global Disable Interrupt bit in the status registers is cleared an interrupt is generated.

Interrupt are only handled at the end of the currently executing instruction. If an interrupt is handled the return address is placed in the link register (LR) and the current value of the status register (SR) is copied into the backup status register (R15'). In the next step the processor loads the address stored at 0x0000 + 2*IRQ_NR into its program counter. In addition the interrupt disable flag in the status register (Bit 15) is set which disables any further interrupts.

IRQ_HANDLE:
  st  sr, [sp]
  add sp, #1
  st  r1, [sp]
  add sp, #1

  /* do something here touching only r1*/
  sub sp, #1
  ld  r1, [sp]
  sub sp, #1
  ld  sr, [sp]    /* Restore status register from stack. */
  ldm pc, lr      /* Return from ISR with mode switch (copies backup SR (R15') to SR */

Instruction set

edit

The conditional flags

edit

Almost all instructions support the usage of conditonals. Conditionals specify if the instruction should be executed depending on the current value of the status registers. The following conditionals are supported:

  • 000b: Uncoditional:
  • 001b: NZ ( Not Equal != 0 )
  • 010b: Z ( Equal = 0)
  • 011b: C ( Carry )
  • 100b: N ( Negative < 0)
  • 101b: O ( Overflow )
  • 110b: Z, N (Zero or Negative)

Open Questions

edit

These Questions are open and must be worked out:

  • What about interrupt support in the feature. If an interrupt occurs it must be possible to save the processor status register and the other registers on something like a stack without corrupting the other registers.

Load Instructions

edit
Load Immediate
edit

The load immediate instruction loads a 8-Bit constant into the destination register. Depending upon the value of lhb (Load High Byte) the value is either stored in the high or low byte of the register. If the low byte is accessed the high byte is set to zero. Otherwise loading of small constants, which is very frequent, couldn't be done in one instruction. If the high byte is written the low byte remains unchanged.

Bit 15:13 Bit 12 Bit 11:8 Bit 7:0
100 (Opcode) lhb (Load High Byte) rX (Destination Register) imm8 (Immediate 8-Bit value)

Format of Load Immediate instruction

Semantics: If lhb(Load High Byte) is zero the value is stored in the low byte of rX. If lhb is set the value is stored in the high byte of rX. This functions does not affect the status register. For example to load ANY 16-Bit constant the following assembler code is sufficient:

  ld   rX, #LO8(IMM16) ; Load low byte of IMM16 into rX.
  ldhb rX, #HI8(IMM16) ; Load high byte of IMM16 into rX.

Syntax: ld rX, #IMM8 to load an 8-Bit immediate into rX. ldhb rX, #IMM8 to load an 8-Bit immediate into the high byte of rX.

Load Indirect with Displacement
edit

The Load Indirect with Displacement instruction, abbr. ld rX, rZ[rY] adds the value of rZ to the value of the register rY. The resulting address is then used to fetch the operand from memory with the result beeing stored in rX.

Bit 15:13 Bit 12:10 Bit 9:8 Bit 7:4 Bit 3:0
101 (Opcode) cond (Conditional flags) rZ (See Notes) rX (Destination register) rY (Base Address Register)

Format of Load Indirect with Displacement

Notes: Only the lower 2bits of rZ are encoded in the instruction. On instruction decode the value is constructed by using the value rZ prefixed by 00b. That is valid registers value for rZ are r0:r3 = 00XX.
Semantics: The value of rZ is added to the value of rY. The resulting address is then used to fetch an operand from memory and the result is stored in rX. Depending upon cond the function is either conditional or not.
Syntax: ld{COND} rX, rZ[rY]

Load Indirect with Displacement and Mode Switch
edit

The Load Indirect with Displacement and Mode Switch instruction works equally to the Load Indirect with Displacement instruction. But additionally this instruction copies the backup SR (R15') into the real SR. This is needed i.e. when leaving an interrupt service routine.

Bit 15:13 Bit 12:10 Bit 9:8 Bit 7:4 Bit 3:0
110 (Opcode) cond (Conditional flags) rZ (See Notes) rX (Destination register) rY (Base Address Register)

Format of Load Indirect with Displacement and Mode Switch

Syntax: ldm{COND} rX, rZ[rY]

Load Indirect {with Mode Switch}
edit

This Load Indirect function, abbr. ld{m} rX, [rY] is implemented by the Load Indirect with Displacement function by using r0 as displacement register. This functionallity is implemented into the assembler which generates a instruction for ld{m} rX, r0[rY].

Load Register Register
edit

The Load Register with Register instruction, abbr. ld rX, rY stores the value of rY in rX.

Bit 15:11 Bit 10:8 Bit 7:4 Bit 3:0
00001 (Opcode) cond (Conditional flags) rX (Destination register) rY (Source register)

Format of Load Register with Register

Semantics: The value of rY is copied into rX. Depending upon cond the instruction is either conditional or not.
Syntax: ld{COND} rX, rY Note: Please note that the instruction format is the same as for the general instructions but because it is a load instruction is has been placed here.

Store instructions

edit
Store Indirect
edit

This Store Indirect function, abbr. st rX, [rY] is implemented by the Store Indirect with Displacement function by using r0 as displacement register. This functionallity is implemented into the assembler which generates a instruction for st rX, r0[rY].

Store Indirect with Displacement
edit

The Store Indirect with Displacement instruction, abbr. st rX, rZ[rY] adds the value of rZ to the value of the register rZ. The resulting address is then used to store the value of rX.

Bit 15:13 Bit 12:10 Bit 9:8 Bit 7:4 Bit 3:0
111 (Opcode) cond (Conditional flags) rZ (See Notes) rX (Source register) rY (Base Address Register)

Format of Store Indirect with Displacement

Notes: Only the lower 2bits of rZ are encoded in the instruction. On instruction decode the value is constructed by using the value rZ prefixed by 10b. That is valid registers value for rZ are r11:r8 = 10XX.
Semantics: The value of rZ is added to the value of rY. The resulting address is then used to store the value of rX to. Depending upon cond the function is either conditional or not.
Syntax: st{COND} rX, rZ[rY]

Other instructions

edit

All other instructions are of the format shown below.

Bit 15:11 Bit 10:8 Bit 7:4 Bit 3:0
0xxxx (Opcode) cond (Conditional flags) rX (Destination register) rY (Source register)

General instruction for Register-Register Operation

or

Bit 15:11 Bit 10:8 Bit 7:4 Bit 3:0
0xxxx (Opcode) cond (Conditional flags) rX (Destination register) imm4 (4 Bit Immediate)

General instruction for Register-Immediate Operation

Arithmetic
edit

All arithmetic instructions work on 16-bit signed values.

Assembler Syntax Opcode Description
ADD{COND} rX, rY 00010 Add value of rY to rX, and store result in rX.
ADD{{COND} rX, #imm4 00011 Add unsigned 4-Bit value to rX.
SUB{COND} rX, rY 00100 Substract value of rY from rX and store result in rX.
SUB{COND} rX, #imm4 00101 Substract unsigned 4-Bit value from in rX.
NEG{COND} rX, rY 00110 Build two's complement of rY and store result in rX.
ARS{COND} rX, rY 00111 Arithmetically shift right by value of rY.
ALS{COND} rX, rY 01000 Arithmetically shift left by value of rY.

Arithmetic Instructions

Notes: Arithmetic left shift instruction seems to be redundant since the produced result doesn't differ from a logical left shift. Though we think a arithmetic left shift make sense because a logical left shift wouldn't update the overflow bit in the status register.

Logical
edit
Assembler Syntax Opcode Description
AND{COND} rX, rY 01001 Logically and value of rY with rX and store result in rX.
NOT{COND} rX, rY 01010 Negate the value of rY and store result in rX.
EOR{COND} rX, rY 01011 Logically exclusive or of rY with rX and store result in rX.
LS{COND} rX, rY 01100 Shift value of rX left by rY bits.
RS{COND} rX, rY 01101 Shift value of rX right by rY bits.

Logical Instructions

Program Control
edit
Assembler Syntax Opcode Description
JMP{COND} [rX] 01110 Jump to subroutine starting at the address provided in register rX. Return address is stored in link register.

Subroutine instructions

Other
edit
Assembler Syntax Opcode Description
TST{COND} rX 01111 Test value of register rX.
NOP 00000 Nop instruction

Other Instructions

Tool Chain

edit

We have ported the GNU binutils which include assembler, linker and other tools for our processor. You can get download our patch from here (patch-rise-1.5.gz). In addition some assembler source are available my here.

Installing the port (Users)

edit

Download binutils 2.17 and unpack it into a directory. Switch to this directory and apply our patch and build the toolchain.

$ tar -jxf binutils-2.17.tar.bz2
$ cd binutils-2.17
$ patch -p1 < ../patch-rise-1.3
...
$ ./configure --prefix=/opt/gcc-rise --target=rise
$ make && make install

Installing the port (Developers)

edit

The port uses CGEN as a framework for building the assembler, disassembler. Non CGEN specific parts include BFD/ELF support and Autoconf/Automake stuff but changeing them is rarely necessary. First download cgen and unpack it into a directory. Then copy the subdirectory 'cgen' into the binutils directory. Finally configure must be called with --enable-cgen-main to support updating the processor description.

$ tar -jxf ../sources/cgen-20061014.tar.bz2
$ cp -Rpf src/cgen binutils-2.17
$ ./configure --prefix=/opt/gcc-rise --target=rise --enable-cgen-maint
$ make && make install

Now build the toolchain to test if everything worked out okay.

Adding new opcodes

edit

In this example we are going to add a new opcode for loading an immediate value into a register to the processor. Open the file 'cpu/rise.cpu' in an editor and add the following piece of code at the end:

(dni ldid "Load Indirect with Displacement"
   ()
   "ld${cond1} $dr,$dr2[$sr]"
   (+ OPC_3_LD_IN_DISP cond1 dr2 dr sr )
   (nop)
   ()
)

The second line is the assembler syntax and the third list is the actual encoding of the instruction. cond1, $dr, %dr2 and $sr are defined as operands in rise.cpu. OPC_3 is defined as an enum type. If you have finished updating the CPU file change to the opcode directory and call 'make stamp-rise'. This calls CGEN and rebuilds the input source files for the GNU assembler.

$ make stamp-rise
...
Generating rise desc.h ...
Generating rise desc.c ...
Generating rise-opc.h ...
Generating rise-opc.c ...
Generating rise-ibld.in ...
Generating rise-asm.in ...
Generating rise-dis.in ...
Generating rise-opinst.c ...
touch stamp-rise
make[1]: Leaving directory `binutils-2.17/opcodes'
$

Now switch to the top-level directory and rebuild the tools. You can test the new tools without installing them by calling 'gas/as-new' and 'binutils/objdump'.

Common problems

edit
  • Changes in the BFD (e.g. archures.c) subdirectory require calling 'make headers' within this directory.
  • If you get an error like .././opcodes/cgen.sh: line 96: guile: command not found during make stamp-rise you have to install guile.

Using it

edit

You can test the port with the following assembler source code.

    .text
    ld      r5,addrlo(stack)
    ldhb    r5,addrhi(stack)

    /* an absolute call. */
    ld      r2,addrlo(func1)
    ldhb    r2,addrhi(func1)
    ld      pc, r2

    /* a PC relative call. */
    ld      r2, #( ( 1f - func2 ) & 0xFF )
    ldhb    r2, #( ( ( 1f - func2 ) >> 8 ) & 0xFF )
    /* store return address in link register */
    ld      lr, #(1f + 0x02)
1:
    ld      pc, r2[pc]

    nop

func1:
    ld      pc, lr

func2:
    ld      pc, lr

The source file must then be compiled by the assembler rise-as and liked with rise-ld to resolve the symbols. This is done with the following steps:

$ rise-as simple.s -o simple.o
$ rise-ld simple.o -o simple

The result can then be disassembling again by calling rise-objdump.

$ ./binutils/objdump -d demo.o

demo.o:     file format elf32-rise

Disassembly of section .text:

00000000 <func1-0x12>:
   0:   85 00           ld R5,#0x0
   2:   8d 00           ldhb R5,#0x0
   4:   80 12           ld R0,#0x12
   6:   88 00           ldhb R0,#0x0
   8:   10 38           ld R7,R0
   a:   80 fa           ld R0,#0xfa
   c:   88 ff           ldhb R0,#0xff
   e:   a1 c7           ld R7,R0[R7]
        ...

00000012 <func1>:
  12:   10 3e           ld R7,R6

00000014 <func2>:
  14:   10 3e           ld R7,R6
$


Another demo program for testing the compiler:

    .text
    /* an absolute call. */
    ld      r2,addrlo(func1)
    ldhb    r2,addrhi(func1)
    jmp     r2

    nop
    nop

    /* a PC relative call. */
    ld      r2, #( ( func2 - 1f ) & 0xFF )
    ldhb    r2, #( ( ( func2 - 1f ) >> 8 ) & 0xFF )

    /* store return address in link register */
    ld      lr, #(1f + 0x02)
1:
    ld      pc, r2[pc]

    nop

    /* arithmetic test block */ 
func1:
    /* add r1 with Immediate 0x03 */    
    add     r1,#03
    ars	    r2,r1
    neg	    r3,r2
    /* add if r3 negative */ 
    addn    r3,r2
    ars     r4,r3
    /* sub if r4 not zero */     
    subnz   r4,#01
    neg     r4,r4
    sub     r2,r4
    
    ld      pc, lr


    /* logical test block */ 
func2:
    and     r1,r2
    /* not if overflow */ 
    noto    r2,r1
    ld      r3,#03
    tst     r2
    /* right shift if zero or negative */ 
    rszn    r2,r3
    eor     r3,r2	    
    ld      r4,#64
    tst     r3
    eorz    r3,r4
    ld      r5,#01
    ls      r3,r5
    
    ld      pc, lr

Port Details

edit

The following files have been modified for this port to work:

BFD specific parts

edit

A BFD ELF backend is required for storing object files on the disc. In additions it handles all the low levels stuff like relocations, ...

  • bfd/aclocal.m4, bfd/configure, bfd/doc/Makefile.in, bfd/Makefile.in, bfd/po/Makefile.in, bfd/config.h, bfd/targmatch.h, bfd/elf32-target.h: Autogenerated
  • bfd/configure.in: Add support for or --target=rise.
  • bfd/config.bfd: Add target vector
  • bfd/cpu-rise.c: CPU architecture and name
  • bfd/elf32-rise.c: ELF specific stuff for the architecture.
  • bfd/targets.c: Architecture vector.
  • bfd/Makefile.am: Add sources and dependencies for compilation.
  • bfd/reloc.c: Add support for relocations (Used by high/low bytes of 16-bit addresses).
  • bfd/archures.c: Architecture declaration
  • bfd/bfd.h bfd/bfd-in2.h bfd/bfd-in3.h bfd/bfdver.h: autogenerated by calling make headers in BFD.
  • include/elf/common.h
  • include/elf/rise.h

CGEN/CPU specific parts

edit

This defines the types of instructions and how they are encoded.

  • opcodes/aclocal.m4, opcodes/configure, opcodes/configure.in, opcodes/Makefile.in, opcodes/po/Makefile.in: Autogenerated
  • opcodes/Makefile.am: Add support for our target.
  • opcodes/disassemble.c: Call disassemble function for our target.
  • cpu/rise.cpu: CPU description - Most important file. Add new instructions here.
  • cpu/rise.opc: Special handling/parsing for opcodes.
  • include/dis-asm.h: Prototype for disassemble function.
  • opcodes/rise-asm.c opcodes/rise-desc.c opcodes/rise-desc.h opcodes/rise-dis.c opcodes/rise-ibld.c opcodes/rise-opc.c opcodes/rise-opc.h opcodes/rise-opinst.c: Auto generated by CGEN from rise.cpu and rise.opc for our CPU.

GNU assembler specific parts

edit
  • gas/aclocal.m4, gas/configure: Autogenerated
  • gas/configure.in: Add support for or --target=rise.
  • gas/configure.tgt: Add the cpu and the generic target. Define the endianness and the BFD format.
  • gas/Makefile.am: Add sources.
  • gas/config/tc-rise.c: Special assembler handling for our target and CGEN setup.
  • gas/config/tc-rise.h: Defines for our target.

GNU ld

edit
  • ld/aclocal.m4, ld/Makefile.in
  • ld/configure.tgt
  • ld/Makefile.am
  • ld/emulparams/riseelf.sh: Generates a linker script for our target.

Other parts

edit
  • binutils/readelf.c: Support for disassembling ELF objects for our target.
  • bootstrap.sh
  • config.sub, configure