SLOOP ISA Last revision: $Id: sloop-spec.txt,v 1.4 2001/02/01 23:20:24 dugan Exp $ ------------------------------------------------------------------------- Introduction: The SLOOP ISA specifies a simple RISC-like architecture. While the SLOOP machine could be used in isolation, its primary goal is to provide an easy-to-pipeline CPU core for the 6502 architecture. Each 6502 instruction has a simple translation into a small sequence (usually no more than 2 or 3) of SLOOP instructions, which can then be executed efficiently in a pipelined processor. Because of the need to support the 6502 ISA, SLOOP contains a few non-RISC-like features, such as a status register. ------------------------------------------------------------------------- Registers: Number Name Notes ----------------------------------- 0 R0 Zero register (NoOp on write) 1 RT Temp register 2 RS Stack pointer 3 RA Accumulator register 4 RX X index register 5 RY Y index register 6 RP Status register 7 RPC Program Counter Note: Most of the above registers map to the 6502 registers, with the exception of R0 and RT. The registers are all "general purpose" in that there are no restrictions on the kind of data they may contain. Two exceptions to this quality are the zero register and the status register. A sequence of SLOOP instructions that translates a 6502 instruction should use the registers in a way that the machine state can be easily mapped back into the 6502 world. Note: We could define more registers (and would probably want to for pure SLOOP programs). However, the above set is sufficient to implement any 6502 program (almost). Note: We may need to make the PC a general purpose register, for reasons described below. Size: SLOOP registers are 32 bits in size. ------------------------------------------------------------------------- Encoding: Every SLOOP instruction is 32 bits in length. There are 4 instruction formats. The following notation applies to the encoding rules below: op opcode sm status mode rd destination register rs source register rt target register (can be read or write) mask an 8 bit mask func an ALU function imm a 16-bit immediate value offset a 16-bit immediate value xxx an unused field R-type: The assembly format of an R-type instruction is: op sm, rd, rs, rt It is encoded as follows: 31 27 23 19 15 11 +----+----+----+----+----+----+----+-----+ | op | sm | rt | rs | rd | func | +----+----+----+----+----+----+----+-----+ Note: the opcode is 4 bits, but R-type opcodes are "extended", in that they rely on the value in the func field to tell the ALU what operation to perform. The status mode is used to determine which status bits should be set by this operation. I-type: The assembly format of an I-type instruction is: op sm, rt, rs, imm It is encoded as follows: 31 27 23 19 15 +----+----+----+----+----+----+----+-----+ | op | sm | rt | rs | immediate | +----+----+----+----+----+----+----+-----+ B-type: B-type is used to encode branch instructions. To support 6502-style branching (which is based on the state of the status register) we encode a mask in our branch instructions. This mask is logically ANDed to the status register, and then branches are taken or not taken based on the "zero-ness" of the result. The assembly format of a B-type instruction is: op mask It is encoded as follows: 31 27 23 19 15 +----+----+----+----+----+----+----+-----+ | op | 0 | mask | offset | +----+----+----+----+----+----+----+-----+ Note: in order to support more RISC-like branches, we could make the mask field to double-duty as a register descriptor, and employ the currently unused bits 27 through 24 to define the type of comparison. As this is not required to support the 6502 it is not currently defined by this spec. J-type: J-type is used to encode jump instructions. The 6502 supports 16 bit addressing. The assembly format of a J-type instruction is: op imm It is encoded as follows: 31 27 15 +----+----+----+----+----+----+----+-----+ | op | 0 | xxx | imm | +----+----+----+----+----+----+----+-----+ Note: The imm field could be expanded to fill 28 bits to support larger address spaces. Again, this is not necessary for the 6502. ------------------------------------------------------------------------- Instructions: The SLOOP defines a very small set of instructions: Mnemonic Opcode Func Encoding Notes ---------------------------------------------------------------------- NOP 0 n/a All zero Do nothing ADD 1 2 R-type RD <- RS + RT ADDI 2 n/a I-type RT <- RS + imm SUB 1 3 R-type RD <- RS - RT SUBI 3 n/a I-type RT <- RS - imm AND 1 4 R-type RD <- RS & RT ANDI 4 n/a I-type RT <- RS & imm OR 1 5 R-type RD <- RS | RT ORI 5 n/a I-type RT <- RS | imm XOR 1 6 R-type RD <- RS ^ RT XORI 6 n/a I-type RT <- RS ^ imm SLL 1 7 R-type RD <- RS << 1 SRL 1 8 R-type RD <- RS >> 1 (unsigned) ROL 1 9 R-type RD <- rotate_left(RS) ROR 1 10 R-type RD <- rotate_right(RS) CMP 1 11 R-type RD <- compare(RT, RS) BEQZ 7 n/a B-type Branch iff StatusRegister & mask == 0 BNEZ 8 n/a B-type Branch iff StatusRegister & mask != 0 J 9 n/a J-type Jump unconditionally JR 10 n/a I-type Jump to the address in RT LD 11 n/a I-type RT <- mem[RS + imm] (byte transfer) ST 12 n/a I-type mem[RS + imm] <- RT (byte transfer) LDW 13 n/a I-type RT <- mem[RS + imm] (2 byte transfer) STW 14 n/a I-type mem[RS + imm] <- RT (2 byte transfer) Notes/Issues: ------------------------------------------------------------------------- Status Modes: We define a set of status modes, which are "algorithms" for setting the status bits appropriately. This dirties up the organization of the machine somewhat, but it is a reasonable way to support the 6502 instruction set. Pure SLOOP programs should be able to be written without using the status register. The 6502 status register (which lives in the low 8 bits of RS on the SLOOP machine): bit -> 7 0 +---+---+---+---+---+---+---+---+ | N | V | | B | D | I | Z | C | <-- flag, 0/1 = reset/set +---+---+---+---+---+---+---+---+ N = NEGATIVE. Set if bit 7 of the accumulator is set. V = OVERFLOW. Set if the addition of two like-signed numbers or the subtraction of two unlike-signed numbers produces a result greater than +127 or less than -128. B = BRK COMMAND. Set if an interrupt caused by a BRK, reset if caused by an external interrupt. D = DECIMAL MODE. Set if decimal mode active. I = IRQ DISABLE. Set if maskable interrupts are disabled. Z = ZERO. Set if the result of the last operation (load/inc/dec/ add/sub) was zero. C = CARRY. Set if the add produced a carry, or if the subtraction produced a borrow. Also holds bits after a logical shift. (NOTE: Bit 5 is always 1) We define the following status modes: ModeNumber Actions -------------------------------------------------------------- 0 Do not touch the status register. 1 C <- (result > 0xFF) N <- (result & 0x80) V <- (result > 127 || result < -128) Z <- (result == 0) 2 N <- (result & 0x80) Z <- (result == 0) 3 C <- (result & 0x0100) N <- (result & 0x80) Z <- (result == 0) 4 C <- (operand & 0x01) N <- (result & 0x80) Z <- (result == 0) 5 C <- (result > 0xFF) N <- (result & 0x80) Z <- (result == 0) 6 V <- (operand & 0x40) N <- (operand & 0x80) Z <- (result == 0) Note: If you think these combinations look really arbitrary, you're right. They reflect combinations commonly used by classes of 6502 instructions. Here is a quick summary: ADC/SBC use mode 1; AND/OR/EOR use mode 2; ASL/ROL use mode 3; LSR/ROR use mode 4; CMP/CPX/CPY use mode 5; INC/DEC/INX/DEX/INY/DEY use mode 2; LDA uses mode 2; TAX/TAY/TXA/TAX/TSX/TXS use mode 2; BIT uses mode 6. Detail: Implementing these means possibly first inspecting the operand and setting some bits, then doing the operation, and finally inspecting the result and setting some more bits.