[][src]Enum pir_8_emu::isa::instruction::Instruction

pub enum Instruction {
    Reserved(u8),
    LoadImmediateByte {
        rrr: u8,
    },
    LoadImmediateWide {
        rr: InstructionLoadImmediateWideRegisterPair,
    },
    LoadIndirect {
        rrr: u8,
    },
    Jump(InstructionJumpCondition),
    Save {
        rrr: u8,
    },
    Alu(AluOperation),
    Move {
        qqq: u8,
        rrr: u8,
    },
    Madr {
        d: InstructionMadrDirection,
        r: InstructionRegisterPair,
    },
    Port {
        d: InstructionPortDirection,
        rrr: u8,
    },
    Comp {
        rrr: u8,
    },
    Stck {
        d: InstructionStckDirection,
        r: InstructionRegisterPair,
    },
    Clrf,
    Halt,
}

Instructions will increase the PC by one, unless otherwise stated.

The PC is incremented as the instruction is loaded from RAM.

An instruction is a single byte, and can include some following immediate values purely for data.

It is possible that the PC will overflow and wrap around as you load an instruction, there is no hardware level protection or detection if this happens.

An example of how this can happen is if you perform a jump to 0xFFFF, as the instruction at 0xFFFF is loaded, the PC would be incremented to 0x10000, but as it's only 16 bits wide, it becomes just 0x0000.

The 'Bit Mask' shows a pattern which denotes an instruction or group of instructions, the letters denoting where any value can be used and still be considered part of the same instruction.

The 'name' is for either a group or single instruction.

'Count' is how many of the 256 possible instructions are used by that bit pattern; HALT for example is exactly one instruction, whilst MOVE is effectively 64 possible combinations [this was added to help me keep track of how many operations I've defined, it should add up to 256].

Bit MaskNameCountDescription
000X XXXXLOAD32Load, see section below
0010 0XXXJUMP8Jump, see section below
0010 1RRRSAVE8Store value in register RRR in address indicated by ADR
0011 XXXXALU16ALU based operations, see section below
01QQ QRRRMOVE64Move a value from register QQQ to register RRR
10XX XXXX64Reserved
1100 XXXX16Reserved
1101 0XXX8Reserved
1101 10XXMADR4Move a value to/from the ADR register, see section below
1101 11XX4Reserved
1110 XXXXPORT16Perform I/O, see section below
1111 0RRRCOMP8Compare register S with register RRR, see section below
1111 10XXSTCK4Stack manipulation, see section below
1111 110X2Reserved
1111 1110CLRF1Clear the F register, by setting it to 0000 0000
1111 1111HALT1Stop the CPU from doing any more execution

LOAD

There are various types of load instruction, all under the same 000X XXXX pattern. They may further increment the PC, as described in their relevant sub-sections. Some of the potential instruction patterns are simply reserved.

The following table is a break down of possible LOAD instructions. If you consider load instruction pattern as 000M XXXX, the M bit is 0 for single byte loads and 1 for multi-byte loads.

Bit MaskLoad TypeDescription
0 0RRRByte immediateLoad the the next byte into register RRR
0 1RRRFrom memoryLoad the byte address by ADR into register RRR
1 00XXWide immediateLoad the the next two bytes into a register pair
1 01XXReserved
1 1XXXReserved

Wide Immediate

When performing a wide immediate load, two bytes are read from memory into a pair of registers, as indicated by the two bits RR.

The first byte read (after the actual LOAD instruction itself) is loaded as the high byte, the second is the low byte; registers A, C and X are considered the 'high byte' for this purpose; if loading into ADR, the high/low bytes are loaded as the high/low byte of the address for ADR.

RRRegisters
00A and B
01C and D
10X and Y
11ADR

The PC is incremented twice more.

Byte Immediate

When performing a byte immediate load, the next byte (after this instruction) is read from memory into a register, as indicated by the bits RRR.

The PC is incremented once more.

From memory

For loading from memory, the memory address to load from should have already been set in the ADR register and the instruction says what register to load into.

The PC is not incremented any further.

PORT - I/O

The PORT instruction in the form 1110 DRRR will perform I/O on the port specified in register A.

The D bit specifies the direction; 1 for reading in from the port (PORT IN) and 0 for writing out to the port (PORT OUT). The RRR bits specify the register to write to (IN from the selected device) or read from (OUT to the selected device).

It is possible to read a value form a selected device to the A register, via 1110 1100, which then changes the selected device. This will be stable though, and would require a further such operation in order to for the device selection to change once more. The value is latched on the clock edge.

NB: It is currently planned the data is be latched on the rising edge. The clock signal will also be exposed out for I/O device, though it may only be done so when the CPU is expecting to read/write. The control line to signify to I/O devices that they should read/write would also be exposed, but under what timings is not yet determined.

COMP - Compare

The compare instruction will compare the S register with a register selected by bits RRR.

It will set the Zero and Parity flag based on the value of the S register; the Zero flag if all the bits are zero, Parity if the number of set bits is even. Parity if the number of set bits is even.

Compare will set the Equal flag if the two registers have the same bit pattern.

The Greater than flag is set if S is greater than the second register.

Note that when doing a compare signed/unsigned is not taken into account, the two registers are treated as if they contain two unsigned values.

NB: This might change to instead compare just the X and Y register.

STCK - Stack Manipulation

When dealing with the stack, a pair of registers will be moved to or from 'the stack' and the SP updated to reflect the changed address.

The registers A and B are paired, as are the registers C and D.

Effectively, the stack works on 16-bit values, but due to the 8-bit data bus it requires two transfers, though this is handled via the hardware/microcode.

The Stack manipulation operations are of pattern 1111 10DR.

The D bit indicates the direction; 0 for PUSH and 1 for POP.

The R bit indicates the register pair; 0 for A & B and 1 for C & D.

When PUSHing B/D will go to the address one less than the current SP, whilst A/C will go to address two less than the SP.

After PUSHing, the SP will have been decremented by two, with the SP containing the address of A/C (now in memory).

When POPing, the same respective pairs of memory locations will be read to the same pair of registers, and the SP increased by two.

Care must be taken, especially when POPing the stack, as there is no under/overflow protection or detection, just like with the PC incrementing during instruction execution.

In fact, by design, POPing the final value from the stack will result in an overflow bringing the SP back to 0x0000.

In terms of pseudo-code, a PUSH followed by a POP can view as the following microcode, where SP is a pointer to the memory address:

// PUSH
SP -= 1
*SP = B
SP -= 1
*SP = A

// POP
A = *SP
SP += 1
B = *SP
SP += 1

NB: I Think I might update this to allow pushing/popping the PC, this would make it very easy (hardware wise) to handle calling and returning functions

MADR - ADR Register Manipulation

The ADR register is a 16-bit register, it's value can be set/read to the general purpose registers.

The registers A and B are paired, as are the registers C and D.

Although still two distinct bytes, the A and C registers should be considered the more significant byte whilst B and D registers the lesser; the more significant byte will be stored at the lower address in the stack, the pair of registers are big-endian.

These ADR manipulation operations are of pattern 0000 10DR.

The D bit indicates the direction; 0 for write-to and 1 for read-from the ADR register.

The R bit indicates the register pair; 0 for A & B and 1 for C & D.

Variants

Reserved(u8)

Reserved instruction, contains the entire byte

LoadImmediateByte

Load the the next byte into register RRR (PC will be incremented a second time), see section above

Fields of LoadImmediateByte

rrr: u8
LoadImmediateWide

Load the the next two byte into register pair RR (PC will be incremented two more times), see section above

Fields of LoadImmediateWide

rr: InstructionLoadImmediateWideRegisterPair
LoadIndirect

Load the byte at the address specified by ADR into register RRR, see section above

Fields of LoadIndirect

rrr: u8
Jump(InstructionJumpCondition)

Jump, see member doc

Save

Store value in register RRR in address indicated by the next two bytes (PC will be incremented two more times)

Fields of Save

rrr: u8
Alu(AluOperation)

ALU based operations, see member doc

Move

Move a value from register QQQ to register RRR

Fields of Move

qqq: u8rrr: u8
Madr

Manipulate ADR, see section above

Fields of Madr

d: InstructionMadrDirectionr: InstructionRegisterPair
Port

Perform I/O, see section above

Fields of Port

d: InstructionPortDirectionrrr: u8
Comp

Compare register S with register RRR, see section above

Fields of Comp

rrr: u8
Stck

Stack manipulation, see member doc

Fields of Stck

d: InstructionStckDirectionr: InstructionRegisterPair
Clrf

Clear the F register, by setting it to 0000 0000

Halt

Stop the CPU from doing any more execution

Methods

impl Instruction[src]

pub fn is_valid(self) -> bool[src]

Check if this instruction doesn't use reserved space

Examples

assert!(Instruction::Clrf.is_valid());
assert!(Instruction::Alu(AluOperation::Or).is_valid());

assert!(!Instruction::Reserved(0).is_valid());

pub fn data_length(self) -> usize[src]

Get the amount of data bytes following this instruction

Examples

assert_eq!(Instruction::Clrf.data_length(), 0);
assert_eq!(Instruction::Alu(AluOperation::Or).data_length(), 0);

assert_eq!(Instruction::LoadImmediateByte { rrr: 0 }.data_length(), 1);
assert_eq!(Instruction::LoadImmediateWide { rr: InstructionLoadImmediateWideRegisterPair::Ab }.data_length(), 2);

pub fn display<'r, 's: 'r>(
    &'s self,
    registers: &'r GeneralPurposeRegisterBank
) -> DisplayInstruction<'r>
[src]

Get proxy object implementing Display for printing instructions in assembly format

Examples

assert_eq!(Instruction::Clrf.display(&registers).to_string(),
           "CLRF");
assert_eq!(Instruction::Alu(AluOperation::Or).display(&registers).to_string(),
           "ALU OR");
assert_eq!(Instruction::Stck {
               d: InstructionStckDirection::Push,
               r: InstructionRegisterPair::Cd,
           }.display(&registers).to_string(),
           "STCK PUSH C&D");

assert_eq!(Instruction::Reserved(0b1111_0000).display(&registers).to_string(),
           "0b1111_0000");

pub fn from_str(
    s: &str,
    registers: &GeneralPurposeRegisterBank
) -> Result<Instruction, ParseInstructionError>
[src]

Parse assembly instruction format

The input string must be ASCII and contain no vertical whitespace

Examples

assert_eq!(Instruction::from_str("JMPL", &registers),
           Ok(Instruction::Jump(InstructionJumpCondition::Jmpl)));

assert_eq!(Instruction::from_str("LOAD IND B", &registers),
           Ok(Instruction::LoadIndirect { rrr: 0b101 }));

assert_eq!(Instruction::from_str("ALU SOR RIGHT ASF", &registers),
           Ok(Instruction::Alu(AluOperation::ShiftOrRotate {
               d: AluOperationShiftOrRotateDirection::Right,
               tt: AluOperationShiftOrRotateType::Asf,
           })));

Trait Implementations

impl Clone for Instruction[src]

impl Copy for Instruction[src]

impl Debug for Instruction[src]

impl Eq for Instruction[src]

impl From<u8> for Instruction[src]

impl Hash for Instruction[src]

impl Into<u8> for Instruction[src]

impl Ord for Instruction[src]

impl PartialEq<Instruction> for Instruction[src]

impl PartialOrd<Instruction> for Instruction[src]

impl StructuralEq for Instruction[src]

impl StructuralPartialEq for Instruction[src]

Auto Trait Implementations

impl RefUnwindSafe for Instruction

impl Send for Instruction

impl Sync for Instruction

impl Unpin for Instruction

impl UnwindSafe for Instruction

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> Downcast for T where
    T: Any
[src]

impl<T> DowncastSync for T where
    T: Send + Sync + Any
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.