DLX Architecture - ``0 low'' variant

Introduction

This is an RTL description of the DLX architecture as described in Computer Architecture, A Quantitative Approach, Second Edition, Hennessy & Patterson, Morgan Kaufman, 1996. This specific document uses the bit numbering found in Appendix C of the text; specifically, bit 31 is the high-order bit of the word. (This configuration is required in order to use the Arch library to simulate the DLX architecture.)

Bus Structure

The DLX machine has 3 buses: s1, s2, and dest.

Having two s buses allows us to have a separate bus for each input arm of the ALU.

The dest bus is used to move output from the ALU.

A convention of the DLX is that the s# buses are used to get values from the registers, and the dest bus is used to put values on to the registers. Thus, to move data from reg[1] to reg[2] you would perform the following steps:

  1. s1 <- reg[1]
  2. alu.out <- s1 (using OP1 passthrough operation of the ALU)
  3. dest <- alu.out
  4. reg[2] <- dest bus

(This isn't completely correct, but we'll get to that in a minute.)

Registers

The DLX has 32 general purpose registers in what is called a register file, labeled reg[#]. In addition, it has the following special purpose registers:

PC:the program counter
IR:The instruction register
MAR:the memory address register
MDR:the memory data register
IAR:interupt address register
TEMP:a temporary register

plus three registers used to make working with the register more orthogonal:

A:a buffer between the register file and the s1 bus
B:a buffer between the register file and the s2 bus
C:a buffer between the dest bus and the register file

The intent of these registers is to make all the ALU operations work identically once the data from the source registers has been loaded into A and B registers. For example, to perform reg[3] <- reg[1] + reg[2] you would perform the following steps:

1:
A <- reg[1]
2:
B <- reg[2]
3:
s1 <- A
4:
s2 <- B
5:
add A to B
5a:
OP1 <- s1
5b:
OP2 <- s2
5c:
alu.out <- OP1 + OP2
5d:
dest <- alu.out
6:
C <- dest
7:
reg[3] <- C

Note that only steps 1, 2 and 7 use actual register numbers; everything else only works with A, B, and C. Also note that this use of A, B, and C would affect the transfer described in the first section, so to do a transfer from reg[1] to reg[2] you would actually need to perform to following steps:

1a:
A <- reg[1]
1b:
s1 <- A
2:
alu.out <- s1 (using OP1 passthrough operation of the alu)
3:
dest <- alu.out
4a:
C <- dest bus
4b:
reg[2] <- C

Memory

The DLX uses 32-bit addressing.

ALU Operation

The following operations are available to the alu:

s1 + s2add
s1 - s1subtraction
s1 & s2logical AND
s1 | s2logical OR
s1 ^ s2logical XOR
s1 << s2logically shift s1 left by s2 bit locations
s1 >> s2logically shift s1 right by s2 bit locations
s1 >> as2 arithmatic shift s1 right by s2 bit locations
s1pass through value of s1
s2pass through value of s2
0constant 0
1constant 1

Instruction Formats

All instructions are 32 bits long. Bit 31 is the high-order bit of the word; for instructions, this is the beginning of the opcode. There are three instruction formats:

I-type instruction format:

opcode 6 bits
rs15 bits
rd5 bits
immediate16 bits
used for all load, store, immediate ALU, conditional branch (rs1 is register, rd not used) jump register, jump & link register (rd=0, rs is destination, immediate=0)

R-type instruction format:

opcode6 bits
rs15 bits
rs25 bits
rd5 bits
func11 bits
used for register-register ALU operations: reg[rd] <- reg[rs1] func reg[rs2] (func encodes the ALU operation, e.g. add, sub...)

also used for read/write special registers and moves

J-type instruction format:

opcode6 bits
offset for PC26 bits
used for jump, jump and link, trap, and return from exeception

RTL Notation

We will use [#] and [#,#] to represent bit locations within a register, and ## to indicate concatenation of values (e.g., "hi"##"_there" gives you "hi_there"); ^ to represent duplication on a bit (e.g. 1^16 says to duplicate the bit '1' 16 times giving the value 1111111111111111 or the hex value FFFF).

Top level (instruction fetch):

     MAR <- PC
     IR <- mem[MAR]
     PC <- PC + 4
     A <- reg[rs1]
     B <- reg[rs2]

Following the fetch, we will execute one of the following six instruction subgroups:

0:
special register
1:
data transfer
2:
alu
3:
set
4:
jump
5:
branch

Note that floating point operations are not dealt with here.

Group 0: special register

     if movi2s then IAR <- A
     if movs2i then A <- IAR

Group 1: memory instructions

Note that these RTL descriptions assume that memory can be read and written in one-, two-, or four-byte units (e.g., LB reads a single byte from memory into the low-order bits of MDR). If memory can only be read and written in multiples of four bytes, the load operations must select the appropriate byte from the resulting contents of MDR, and the store operations must read the relevant word from memory, replace the appropriate byte(s), and then write the modified word back into memory.

     MAR <- A + ((IR[15])^16 ## IR[15,0]
     if load then
       MDR <- mem[MAR]
       if LB then
         C <- (MDR[7])^24##MDR[7,0]
       else if LBU then
         C <- 0^24##MDR[7,0]
       else if LH then
         C <- (MDR[15])^16##MDR[15,0]
       else if LHU then
         C <- 0^16##MDR[15,0]
       else if LW then
         C <- MDR
       else if LHI then
         C <- (IR[15,0]<<16)##0^16
       reg[rd] <- C
     
     else if store then
       MDR <- B
       mem[MAR] <- MDR

Group 2: alu

     if register-register
       TEMP <- B
     
     if register-immediate
       if unsigned
          TEMP <- 0^16##IR[15,0]
       else
          TEMP <- (IR[15])^16##IR[15,0]

All ALU operations will use the two source values A and TEMP, so for all operations,

       C <- A func TEMP

where func is defined by the operation being performed. A special note for shift right arithmetic:

     if SRA then
       C <- (A[31])^TEMP##(A>>TEMP)
Once register C has been set,
     reg[rd] <- C

Group 3: set

     if register-register
       TEMP <- B
     
     if register-immediate
       if unsigned
          TEMP <- 0^16##IR[15,0]
       else
          TEMP <- (IR[15])^16##IR[15,0]

All set operations will compare the two values A and TEMP, so to look at a single example,

if SNEQ then A != TEMP if yes then true so C <- 1 else false C <- 0

(Side note: code for the set instructions can be simplified by using subtraction to determine the relationship between the numbers; e.g.,

     result = A - TEMP

     if A = TEMP then
       result is 0
     if A > TEMP then
       result is > 0
     if A < TEMP then
       result is < 0
and so on.) Again, once register C has been set,
     reg[rd] <- C

Group 4: jump

     if JR then
       PC <- A
     else if J then
       PC <- PC + (IR[25])^6##IR[25,0]
     else if JAL then
       C <- PC
       PC <- PC + (IR[25])^6##IR[25,0]
       reg[31] <- C
     else if JALR then
       C <- PC
       PC <- A
       reg[31] <- C
     else if TRAP then
       IAR <- PC
       PC <- (IR[25])^6##IR[25,0]

Group 5: branch

     if BEQZ then
       if A == 0 then
         PC <- PC + (IR[15])^16##IR[15,0]
       else
         do nothing
     else if BNEZ then
       if A != 0 then
         PC <- PC + (IR[15])^16##IR[15,0]
       else
         do nothing

Last updated 2001/10/17 09:40:15
Back to Course Home Page
Back to My Home Page