Case Statements and Enumerated Types

Enumerated types provide a way of giving meaningful representations to symbolic values. Case statements provide a convenient tabular way of structuring conditional code. The following example illustrates how both of these can be used in an instruction decoding situation.

	alu_op:type=scalar.
	alu_mov:val(alu_op).
	alu_add:val(alu_op).
	alu_sub:var(alu_op).

	alu(op:val(alu_op),x:val(int),y:val(int)):expr(int)=(
	  case op
	    when alu_mov => x
	    when alu_add => x+y
	    when alu_sub => x-y
	).

	result:=alu(case opcode when 0 => alu_mov
	                        when 1 => alu_add
	                        when 2 => alu_sub, op1, op2)
The power of case statements can be increased by using them in conjunction with vector or record constructors. The following example illustrates how an AND function can be described in this way:

	AND(x:val(int),y:val(int)):expr(int)=(
	  case [x,y]
	    when [0,0] => 0
	    when [0,1] => 0
	    when [1,0] => 0
	    when [1,1] => 1
	).
It can also be useful to put vector and record constructors on the right hand side of the =>, but note that these constructors cannot be used as the left hand side of an assignment.

Here is a further example of case statements, in this case for instruction decoding, that uses a record constructor:

	decoded_instr:type=record(alu_op::alu_op_type,
	                          mem_op::mem_op_type,
	                          prefetch_op::prefetch_op_type).

	decode(instr:val(opcode)):expr(decoded_instr)=(
	  cast(decoded_instr,
	    case instr
	      when op_add    => { alu_add, mem_none,  prefetch_next }
	      when op_sub    => { alu_sub, mem_none,  prefetch_next }
	      when op_load   => { alu_add, mem_load,  prefetch_next }
	      when op_store  => { alu_add, mem_store, prefetch_next }
	      when op_branch => { alu_add, mem_none,  prefetch_branch }
	  )
	).