OSU8 began as a student project in 1994 to create a simple but functional 8bit microprocessor, starting with a definition of the architecture to implementation in a Xilinx FPGA chip, and fullcustom CMOS implementation.
OSU-8 "Instructional" Microprocessor Specification User Registers: A = accumulator (8 bits) B = secondary data register (8 bits) P1 = memory pointer #1 (16 bits) P2 = memory pointer #2 (16 bits) SP = stack pointer (16 bits) Status Bits: C = Carry bit N = Negative/overflow bit Z = Zero/equal bit P = Pointers equal bit Other Registers: PC = Program counter (16 bits) MAR = Memory Address bus register (16 bits) MDR = Memory Data bus register (8 bits) IR = Instruction register (8 bits) Some syntax used below: t = top nibble of a byte, bits 7-4 b = bottom nibble of a byte, bits 3-0 H = high half of a memory pointer, bits 15-8 L = low half of a memory pointer, bits 7-0 Instruction Set Summary: Arithmatic Operations: Inst: Source: Destination: Description: CPL <A | B> <A | B> Complement A or B, store in A or B C Complement the carry bit. ADD A+B <A | B> Add A to B with Carry, store in A or B SUB A-B <A | B> Subtract B from A w/C, store in A or B AND A&B <A | B> Logical AND A with B, store in A or B OR A|B <A | B> Logical OR A with B, store in A or B RR A <A | B> Rotate A to right, store in A or B RL A <A | B> Rotate A to right, store in A or B RRC A <A | B> Rotate A right by carry, store in A or B RLC A <A | B> Rotate A left by carry, store in A or B INC <A | B> <A | B> Increment A or B, store in A or B INC <P1 | P2> Increment P1 or P2 (store in itself) DEC <A | B> <A | B> Decrement A or B, store in A or B DEC <P1 | P2> Decrement P1 or P2 (store in itself) SET C Set carry bit CLR C Clear carry bit Data Transfer: Inst: Source: Destination: Description: MOVE <A | B> <A | B> Move A or B into A or B <A | B> <P1H | P1L> Move A or B into P1H or P1L <P1H | P1L> <A | B> Move P1H or P1L into A or B P1 <P2 | SP> Move P1 into P2 or SP <P2 | SP> P1 Move P2 or SP into P1 #data4 <A(tb) | B(tb)> Move 4 bit data into A or B. #data4 P1(HL)(tb) Move 4 bit data into P1 C OUT(0,1,2,3) Move C to output pin 0 to 3 <N | Z | P> C Move N, Z or P bit to carry <IN0 | IN1> C Move input pin 0 or 1 to carry LOAD <@P1 | @P2> <A | B> Load from memory @P1 or @P2 into A or B STORE <A | B> <@P1 | @P2> Store A or B into memory @P1 or @P2 PUSH <A | B | P1(HL) | P2(HL)> Push A, B, P1H, P1L, P2H, or P2L onto stack in memory POP <A | B | P1(HL) | P2(HL)> Pop A, B, P1H, P1L, P2H, or P2L from stack in memory Program Branching: JUMP @P1 Jump to routine @P1 CALL @P1 Call to routine @P1, save return address onto stack in memory RET Return from subroutine (pop address from stack in memory and jump to it) JCU relative, see below Jump upward if carry set JCD relative, see below Jump downward if carry set NOP No operation (used with JCU/JDU, see relative address encoding below) Assembler Macro Instructions: The osu8asm assembler provides many built in macros to make programming the OSU-8 processor less painful. These are largely undocumented, but here is an incomplete list: MOVE #data8 <A | B> Move a byte into A or B MOVE #data16 P1 Move an address into P1 JC address Jump on carry, either direction JNC address Jump on complement carry, either direction CJNE A, B, address Jump to address if A and B are not equal CJNE A, #data, address Jump to address is A is not equal to a byte These macros are expanded to a fixed group of instructions. These macros should be used with care, since the group of instructions which they are expanded to can perform somewhat differently than expected, particularily with respect to the status bits. For example, JNC must complement the carry using a "CPL C" instruction before making the JCD or JDU. If the carry bit is to be used in the following code, for whatever reason, it will have been complemented, which is not what one would expect from a JNC instruction implemented in hardware. Unlike the hardware instructions, the exact behavior of the assembler macros with respect to the status bits is not specified the object code listing should be examined to see what instructions the assembler actually substitutes if this is important. The substituted instructions never overwrite registers unexpectedly. For example, the "CJNE A, #data, address" macro must execute a "PUSH B" and use B, then execute a "POP B", since it is not allowed to destroy the contents of B. While "CJNE" is a very handy instruction, the resulting object code is inefficient if the value current in B is not used by the subsequent code, compared to manually entering the group of instructions which perform the operation without saving the value of B. Despite these potential problems, the assembler macro instructions make programming the OSU-8 processor much easier. In fact, it's quite difficult to call a subroutine (whose memory location is specified by a label) without code such as: .org 0 ;start at memory location zero. begin: move #0 -> p1lb ;this is the hard way to do it. move #0 -> p1lt ;just using "move #0x0100 -> P1" move #1 -> p1hb ;is about four times easier move #0 -> p1ht move p1 -> p2 loop: move #routine -> p1 ;this is a macro, will become 4 MOVE's. call @p1 set c ;an infinite loop jc loop ;another macro, will expand to JCU. ;Note: Three NOP's will be inserted after the "move p1 -> p2" line to ; to align "loop" on a 4-byte boundry. This has nothing to do with ; the macro on that line. The JCU instruction can only jump to ; exact four byte boundries, in this case 0008. routine:inc a ;it would have been hard to call to store a -> @p2 ;here without being able to move the inc p2 ;16 bit value "routine" directly into push a ;p1. The macro will obviously use four move #1 -> a ;MOVE #data4 -> P1(LH)(tb) instructions. move p2 -> p1 move a -> p1h move p1 -> p2 pop a ret Most of the osu8asm macro instructions either add addressing modes to existing OSU-8 instructions or attempt to duplicate instructions found in the 8051 microcontroller. Instruction Word Format: All instructions are 1 byte long, requiring a single byte fetch. bits 7-4: opcode bits 3-0: operand or additional opcode information Opcode Instruction(s) 0000 ALU A . B -> A (only ALU instructions affect C, N, Z bits) 0001 ALU A . B -> B (only ALU instructions affect C, N, Z bits) 0010 JCU (jump upward if carry set) 0011 JCD (jump downward if carry clear) 0100 PUSH, POP, JUMP, CALL, RET 0101 LOAD, STORE (8 undefined instructions) 0110 Misc Carry bit instructions (2 undefined instructions) 0111 MOVE (memory pointers) (only these instructions effect P bit) 1000 MOVE #data4 -> Ab 1001 MOVE #data4 -> At 1010 MOVE #data4 -> Bb 1011 MOVE #data4 -> Bt 1100 MOVE #data4 -> P1Lb 1101 MOVE #data4 -> P1Lt 1110 MOVE #data4 -> P1Hb 1111 MOVE #data4 -> P1Ht Opcodes 0000 and 0001 specify ALU operation. The 4 bit operand specifies that operation the ALU will perform. During other instructions, the ALU is typically driven with 0000 or 0010 to pass only A or B, so they can be tranfered to other registers. The alu function for each instruction is shown in the table below. The destination of the result is A of the opcode is 0000 or B if the opcode is 0001. All three ALU status bits, C, N, and Z, are update during all 32 of these instructions, even though most of these don't actually produce meaningful results. These bits are never changed by other instructions, except for eight of the 0110 opcodes, which move a new value into the carry bit. Updating all three bits for every ALU operation simplifies the decoding logic required to produce the clock signals for these bits. The P bit is updated during all 16 of the 0111 opcode instructions. Opcodes 0010 (JCU) and 0011 (JCD) use the 4 bit operand to specify the jump location. The destination address is: trunc(PC + 1) - (operand * 4) <- for JDU trunc(PC + 1) + (operand * 4) <- for JDC The trunc() function simple sets the lowest two bits to zeros. The operand is multiplied by four (simply input to bits [5:2] of an adder when added to the program counter). This allows the four bit operand to specify a jump destination as far as 60 bytes away using only four bits, but the only possible jump addresses are spaced four bytes apart from each other. Because the lower two bits of the address are forced to zero, the possible jump addresses are always aligned on even four byte boundries (e.g. 0, 4, 8, 12, etc) regardless of the address of the JCD/JCD instruction. The osu8asm assembler identifies all of these branch targets and inserts NOP instructions if necessary to align them onto the valid four byte boundries. Opcodes 1000 to 1111 (MOVE #data) load the four operand bits into four bits of the A, B, or P1 registers, without changing the other bits in the register, of course. Opcodes 0100, 0101, 0110, and 0111 perform several differnet instructions, as shown in the table below: Opcode: 0000/0001 0100 0101 0110 0111 Operand 0000 MOVE A, PUSH A LOAD @P1, A MOVE IN0, C INC P1 0001 CPL A, POP A LOAD @P2, A MOVE IN1, C INC P2 0010 MOVE B, PUSH B LOAD @P1, B MOVE N, C DEC P1 0011 CPL B, POP B LOAD @P2, B MOVE Z, C DEC P2 0100 ADD A+B, PUSH P1L MOVE P, C MOVE P2 -> P1 0101 SUB A-B, POP P1L CLR C MOVE P1 -> P2 0110 AND A B, PUSH P1H SET C MOVE SP -> P1 0111 OR A B, POP P1H CPL C MOVE P1 -> SP 1000 RR A, PUSH P2L STORE A, @P1 MOVE C, OUT0 MOVE P1L -> A 1001 RL A, POP P2L STORE A, @P2 MOVE C, OUT1 MOVE P1H -> A 1010 RRC A, PUSH P2H STORE B, @P1 MOVE C, OUT2 MOVE P1L -> B 1011 RLC A, POP P2H STORE B, @P2 MOVE C, OUT3 MOVE P1H -> B 1100 INC A, CALL @P1 MOVE A -> P1L 1101 DEC A, JUMP @P1 MOVE A -> P1H 1110 INC B, RET NOP MOVE B -> P1L 1111 DEC B, RETI * MOVE C, IE * MOVE B -> P1H * Note: Interrupt support is not required, but the RETI instruction is allocated the 01001111 opcode, in the event that hardware is added to provide interrupt support. If interrupt support is not provided, the RETI instruction should execute as the ordinary RET instruction. Similarily, the MOVB C, IE instruction would allow interrupts to be enabled and disabled by moving the carry bit into an interrupt enable bit. Supporting interrupts requires a second set of status bits and an interrupt status bits. See discussion in RETI instruction for details. The empty spaces in the table are unassigned opcodes. They may duplicate the functions of other instructions, execute as NOP's, or be used to add custom instructions or support for custom built-in I/O hardware. The osu8asm will not produce these opcodes in its output, except with the .db directive, which can be used to insert any bytes into the code. These 10 unassigned opcodes MUST NOT cause the processor to halt or execute subsequent instructions incorrectly. If interrupts are not implemented, RETI should execute as RET, and MOVE C -> IE should excute as NOP. Detailed Instruction Summary: (not finished, but probably useful) ADD A+B -> A Add A + B with carry, store in A Encoding: 0000 0100 Description: Register Operations: (PC) <- (PC) + 1 (A) <- (A) + (B) + (C) Example Code: ADD A+B -> B Add A + B with carry, store in B Encoding: 0001 0100 Description: Register Operations: (PC) <- (PC) + 1 (B) <- (A) + (B) + (C) Example Code: AND A&B -> A Logical AND A with B, store in A Encoding: 0000 0110 Description: Register Operations: (PC) <- (PC) + 1 (A) <- (A) AND (B) Example Code: AND A|B -> B Logical AND A with B, store in B Encoding: 0001 0110 Description: Register Operations: (PC) <- (PC) + 1 (B) <- (A) AND (B) Example Code: CALL @P1 Call to subroutine @P1, save return address on stack Encoding: 0100 1100 Description: Register Operations: (PC) <- (PC) + 1 ((SP)) <- (PC[15:8]) (SP) <- (SP) + 1 ((SP)) <- (PC[7:0]) (SP) <- (SP) + 1 (PC) <- (P1) Example Code: CLR C Clear Carry bit Encoding: Description: Register Operations: (PC) <- (PC) + 1 (C) <- 0 Example Code: CPL A Complement A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- NOT (A) Example Code: CPL A -> B Complement A, store in B Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- NOT (A) Example Code: CPL B -> A Complement B, store in A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- NOT (B) Example Code: CPL B Complement B Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- NOT (B) Example Code: CPL C Complement Carry bit Encoding: Description: Register Operations: (PC) <- (PC) + 1 (C) <- NOT (C) Example Code: DEC A Decrement A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- (A) - 1 Example Code: DEC A -> B Decrement A, store in B Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- (A) - 1 Example Code: DEC B -> A Decrement B, store in A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- (B) - 1 Example Code: DEC B Decrement B Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- (B) - 1 Example Code: DEC P1 Decrement P1 Encoding: Description: Register Operations: (PC) <- (PC) + 1 (P1) <- (P1) - 1 Example Code: DEC P2 Decrement P2 Encoding: Description: Register Operations: (PC) <- (PC) + 1 (P2) <- (P2) - 1 Example Code: INC A Increment A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- (A) + 1 Example Code: INC A -> B Increment A, store in B Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- (A) + 1 Example Code: INC B -> A Increment B, store in A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- (B) + 1 Example Code: INC B Increment B Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- (B) + 1 Example Code: INC P1 Increment A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (P1) <- (P1) + 1 Example Code: INC P2 Increment A Encoding: Description: Register Operations: (PC) <- (PC) + 1 (P2) <- (P2) + 1 Example Code: JCD rel4 Jump (down) if Carry set Encoding: 0011 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 if C == 1 (PC) <- (PC) + 4 * d[3:0] (PC[1:0]) <- 0 Example Code: JCU rel4 Jump (up) if Carry set Encoding: 0010 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 if C == 1 (PC) <- (PC) - 4 * d[3:0] (PC[1:0]) <- 0 Example Code: JUMP @P1 Jump to code @P1 (unconditional) Encoding: Description: Register Operations: (PC) <- (P1) Example Code: LOAD @P1 -> A Load A from memory @P1 Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- ((P1)) Example Code: LOAD @P1 -> B Load B from memory @P1 Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- ((P1)) Example Code: LOAD @P2 -> A Load A from memory @P2 Encoding: Description: Register Operations: (PC) <- (PC) + 1 (A) <- ((P2)) Example Code: LOAD @P2 -> B Load B from memory @P2 Encoding: Description: Register Operations: (PC) <- (PC) + 1 (B) <- ((P2)) Example Code: MOVE C -> OUTn Move Carry bit to Output pin #n Encoding: 0110 10 n1 n0 Description: Register Operations: (PC) <- (PC) + 1 (OUTn) <- (C) Example Code: MOVE INn -> C Read input pin #n, store in Carry Encoding: 0110 000 n Description: Register Operations: (PC) <- (PC) + 1 (C) <- (INn) Example Code: MOVE N -> C Move N (negative/overflow) bit to Carry Encoding: Description: Register Operations: (PC) <- (PC) + 1 (C) <- (N) Example Code: MOVE P -> C Move P (P1 == P2) bit to Carry Encoding: Description: Register Operations: (PC) <- (PC) + 1 (C) <- (P) Example Code: MOVE Z -> C Move Z (zero/equal) bit to Carry Encoding: Description: Register Operations: (PC) <- (PC) + 1 (C) <- (Z) Example Code: MOVE #data4 -> Ab Initialize Ab with 4 bit immediate data Encoding: 1000 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 (A[3:0]) <- d[3:0] Example Code: MOVE #data4 -> At Initialize At with 4 bit immediate data Encoding: 1001 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 (A[7:4]) <- d[3:0] Example Code: MOVE #data4 -> Bb Initialize Bb with 4 bit immediate data Encoding: 1010 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 (B[3:0]) <- d[3:0] Example Code: MOVE #data4 -> Bt Initialize Bt with 4 bit immediate data Encoding: 1011 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 (B[7:4]) <- d[3:0] Example Code: MOVE #data4 -> P1Lb Initialize P1Lb with 4 bit immediate data Encoding: 1100 d3 d2 d1 d0 Description: Register Operations: (PC) <- (PC) + 1 (P1[3:0]) <- d[3:0] Example Code: [...]... isrcinsol promteodnr RT hs ntuto hud efr h riay E T spotitrut,amcooesqec smlr o upr nerps ircd eune iia t teoefrCL cetd adbtenisrcin, o h n o AL rae, n ewe ntutos i teITbti asre,ti sqec i eeue, f h N i s setd hs eune s xctd isedo tenx isrcin nta f h et ntuto Rgse Oeain:(o fgr i ot eitr prtos yu iue t u) R A- A L > Rtt Alf oae et Ecdn: noig Dsrpin ecito: Rgse Oeain:(C < (C +1 eitr prtos P) - P) EapeCd: . status bits. For example, JNC must complement the carry using a "CPL C" instruction before making the JCD or JDU. If the carry bit is to be used in the following code, for whatever. modes to existing OSU-8 instructions or attempt to duplicate instructions found in the 8051 microcontroller. Instruction Word Format: All instructions are 1 byte long, requiring a single byte fetch. . operand or additional opcode information Opcode Instruction( s) 0000 ALU A . B -> A (only ALU instructions affect C, N, Z bits) 0001 ALU A . B -> B (only ALU instructions affect C, N, Z