Computer Architecture Lab/Winter2006/LechnerWalterStadlerTrinkl/Workplace

Design decisions
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'.

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):

Status Register

Pipeline stages

 * 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)
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 */

The conditional flags
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
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 Immediate
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.

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
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.

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
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.

Format of Load Indirect with Displacement and Mode Switch

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

Load Indirect {with Mode Switch}
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
The Load Register with Register instruction, abbr. ld rX, rY stores the value of rY in rX.

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 Indirect
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
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.

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
All other instructions are of the format shown below.

General instruction for Register-Register Operation

or

General instruction for Register-Immediate Operation

Arithmetic
All arithmetic instructions work on 16-bit signed values.

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
Logical Instructions

Program Control
Subroutine instructions

Other
Other Instructions

Tool Chain
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)
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)
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
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

 * 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
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 : 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 : 12:   10 3e           ld R7,R6

00000014 : 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
The following files have been modified for this port to work:

BFD specific parts
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
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

 * 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.
 * gas/config/tc-rise.h: Defines for our target.

GNU ld

 * 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

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