next up previous contents
Next: SALTO User Interface Specification Up: SALTO Target Description Specifications Previous: Target-Specific Functionalities

Putting It All Together

To illustrate the specification given above, let us take a closer look at several excerpts from a preliminary SALTO description of the Philips TriMedia TM1000 architecture. The full description is given in appendix A.

Defining the Resources

The minimal description of the resources available on the TM1000 is quite compact. It can be extended with special-purpose registers such as PCSW, but in the first place, it consists of the general registers and the memory:

;; SECTION I: REGISTERS
;; ====================
;;
;; * there are 128 general registers named r0 through r127
(def_ress
  (base_name "r" 0 127)
  [(type "reg") (width 32)])

;; memory: "memI is a reserved name, but the resource corresponding
;; to the name must be explicitly defined
(def_ress (name "mem")
  [(type "memory")
   (width 32)])

Defining the Functional Units

The definition of functional units contains directly the replication level of each unit, i.e., the number of distinct operations on that functional unit type that can be issued within a single cycle. Here, the number of issue units is thus limited to five, corresponding to the five issue slots available on the TM1000:

;; Subsection II.1: ISSUE UNITS
;; ----------------------------
;;
(def_ress (name "issue")
  [(type "functional_unit")
    (limit 5)])				     ; five issue slots

#define ISSUE (ress (name "issue") USE_AT_1)

;; Subsection II.2: COMPUTATION AND MEMORY ACCESS UNITS
;; ----------------------------------------------------

;; CPP macro - all functional unit declarations follow the same format
#define FU_DECL(fu_name,replication) \
  (def_ress (name fu_name) \
    [(type "functional_unit") \
     (width 32) \
     (limit replication) \
     ])

;; dummy memory access unit for exclusions between DMEM and DMEMSPEC FUs
;; They will BOTH have to use this resource at cycle 1, but while DMEM
;; operations take just one token, DMEMSPEC ops squat both :-)
FU_DECL("mem_dummy_fu", 2)

;; integer ALU units: basic integer operations; replication level: 5
FU_DECL("alu", 5)

;; BRANCH units: branch and jump operations; replication level: 2
FU_DECL("branch", 2)

;; FCOMP unit: floating-point comparisons, status info (including clock);
;; replication level: 1
FU_DECL("fcomp", 1)

The case of a limited number of write-back buses is handled by requiring the use of a ``writeback_bus'' resource by all instructions that perform a register write, and by limiting the replication level of that resource to the required value:

;; the number of write-back buses is limited to 5 (as of TM1000) while
;; instruction latencies are variable (1, 2, 3 or 17)
;; Therefore, we need a model of that limitation... 
FU_DECL("writeback_bus", 5)

;; Each register write must be represented by the reservation of a
;; write-back bus at the last cycle of the instruction.
#define WRITEBACK_BUS_AT(N) (ress (name "writeback_bus") USE_AT_CYCLE(N))

Defining the Reservation Tables

In their simplest form, reservation tables on the TM1000 depend on the format of the instruction (number and kind of its operands) and on the functional unit type for that instruction.

Therefore, the reservation tables can be first defined as cpp macros, then instantiated with values appropriate for each category of instructions. The following are definitions of the two most frequently used reservation table forms; information on issue slot access, functional unit type and the latency of the instruction is provided when the macros are instantiated.

;; there''s a couple common defs for reservation tables...

;;   ...at cycle 1
#define USE_AT_1          [(use)   (at_cycle 1)]
#define READ_AT_1         [(read)  (at_cycle 1)]

;;   ...we also need reservations at cycle n
#define USE_AT_CYCLE(N)   [(use)   (at_cycle N)]
#define WRITE_AT_CYCLE(N) [(write) (at_cycle N)]

;; Default reservation table: guard, no modifier, three addresses, and use
;; everything at cycle 1 except result register and write-back bus
;; in other words,  "IF rguard OP rsrc1 rsrc2 -> rdest"
#define THREE_ADDR_TABLE(ISSUE_INFO,FU,N) \
(reser_table \
	     [ \
	       ISSUE_INFO \
	       (ress (name FU) USE_AT_1) \
	       (ress (match_arg 0) READ_AT_1) \
	       (ress (match_arg 1) READ_AT_1) \
	       (ress (match_arg 2) READ_AT_1) \
	       (ress (match_arg 3) WRITE_AT_CYCLE(N)) \
	       WRITEBACK_BUS_AT(N) \
	       ])

;; operations of the form  "IF rguard OP(modifier) rsrc1 -> rdest": guard,
;; modifier, one source and one destination register
#define MOD_SRC1_DEST_TABLE(ISSUE_INFO,FU,N) \
(reser_table \
	     [ \
	       ISSUE_INFO \
	       (ress (name FU) USE_AT_1) \
	       (ress (match_arg 0) READ_AT_1) \
	       (ress (match_arg 2) READ_AT_1) \
	       (ress (match_arg 3) WRITE_AT_CYCLE(N)) \
	       WRITEBACK_BUS_AT(N) \
	       ])

Instruction Semantics

The modeling of instruction semantics for the TM1000 is currently restricted to the delay slots and the information on the branch target location, which is known for immediate jumps, but not for indirect ones:

;; Right now, there is only one type of constraints: delay slots, common to
;; all branch instructions.

;; conditional _branch_ information: 
#define BRANCH_SEM_INFO \
(sem [ \
       (delay_slot 3) \
       (branch -1) \
       ])

;; unconditional _jump_ information: well, it is still a branch if the guard
;; is given
#define JUMP_SEM_INFO \
(sem [ \
       (delay_slot 3) \
       (jump 1) \
       ])

;; _return_ information - the instruction terminates a procedure/function
#define RETURN_SEM_INFO \
(sem [ \
       (delay_slot 3) \
       (noreorder) \
       (return) \
       ])

Instruction Definitions

Instruction definitions associate instruction names with input format information and reservation tables. Therefore, they rely on a previous definition of operand representations. Here's the definition of input tokens for an instruction format nearly matching the actual input format of the TM1000 assembler (except for the guard which has to be placed after the opcode together with instruction operands):

;; Section II.1: COMMENTS AND SEPARATORS
;; =====================================

(comment_chars "!")

;; parentheses, dash, "greater" sign (right chevron), 'I' and 'F' as
;; separators
(def_exact "()IF->")

;; Section II.2: META-VARIABLE TOKENS
;; ==================================
;;
;; register tokens are quite nice:
#define REGISTER_REGEXP "r12[0-7]\\|r1[0-1][0-9]\\|r[1-9][0-9]\\|r[0-9]"
(def_token "g" [(regex REGISTER_REGEXP)]) ; guard register
(def_token "s" [(regex REGISTER_REGEXP)]) ; first source register
(def_token "t" [(regex REGISTER_REGEXP)]) ; second source register
(def_token "d" [(regex REGISTER_REGEXP)]) ; destination register

;; sometimes r0 must be explicitly given
(def_token "0" [(regex "r0")])

;; modifier tokens: integer expressions, possibly containing identifiers
(def_token "m" [(read_exp)])

Finally, the instructions are defined using all the above components:

;; Section III: INSTRUCTION SET SPECIFICATION
;; ==========================================
;;
;; Section III.1: VLIW INSTRUCTION WIDTH
;; =====================================
;;
;; five issue slots per cycle
(inst_width 5)

;; Section III.2: NATIVE INSTRUCTIONS
;; ==================================
;;
;; Instructions are assumed to complete at cycle following the latency cycle
;; - there''s an EXPLICIT decode/read cycle at t=1 (0 is insn fetch...)
;; Latencies given as parameters of reservation tables take this already
;; into account.
;;
;; BTW, spaces are not significant in the format string and ARE IGNORED
;; during unparsing - this needs post-processing :-)
#define INPUT_THREE_ADDR input "IF g s t -> d"
#define INPUT_DEST input "IF g -> d"
#define INPUT_MOD input "IF g (m)"
#define INPUT_MOD_DEST input "IF g (m) -> d"
#define INPUT_MOD_SRC1 input "IF g (m) s"
#define INPUT_MOD_SRC1_DEST input "IF g (m) s -> d"
#define INPUT_MOD_SRC1_SRC2 input "IF g (m) s t"
#define INPUT_SRC1 input "IF g s"
#define INPUT_SRC1_DEST input "IF g s -> d"
#define INPUT_SRC1_SRC2 input "IF g s t"
#define INPUT_NOP input "IF g"

;; Section III.2.1: ALU OPERATIONS
;; ===============================
;;
;; most "alu" operations are three-address ops completed in one cycle;
;; the write takes place at the next cycle (t=2)
#define ALU_THREE_ADDR_OP(op) \
(def_asm op \
  [(INPUT_THREE_ADDR) \
   THREE_ADDR_TABLE(ISSUE,"alu",2) \
   ])

ALU_THREE_ADDR_OP("iadd")		; signed integer addition
ALU_THREE_ADDR_OP("isub")		; signed integer subtraction
;; etc. etc.

;; "alu" ops that use an immediate value, source1 and dest register
#define ALU_MOD_SRC1_DEST_OP(op) \
(def_asm op \
  [(INPUT_MOD_SRC1_DEST) \
   MOD_SRC1_DEST_TABLE(ISSUE,"alu",2) \
   ])

ALU_MOD_SRC1_DEST_OP("ileqi")		; signed less or equal than imm    
ALU_MOD_SRC1_DEST_OP("igtri")		; signed greater than immediate  
;; etc. etc.


next up previous contents
Next: SALTO User Interface Specification Up: SALTO Target Description Specifications Previous: Target-Specific Functionalities

Erven Rohou
Fri Oct 17 09:15:29 MET DST 1997