[−][src]Enum pir_8_emu::isa::instruction::Instruction
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 Mask | Name | Count | Description |
---|---|---|---|
000X XXXX | LOAD | 32 | Load, see section below |
0010 0XXX | JUMP | 8 | Jump, see section below |
0010 1RRR | SAVE | 8 | Store value in register RRR in address indicated by ADR |
0011 XXXX | ALU | 16 | ALU based operations, see section below |
01QQ QRRR | MOVE | 64 | Move a value from register QQQ to register RRR |
10XX XXXX | 64 | Reserved | |
1100 XXXX | 16 | Reserved | |
1101 0XXX | 8 | Reserved | |
1101 10XX | MADR | 4 | Move a value to/from the ADR register, see section below |
1101 11XX | 4 | Reserved | |
1110 XXXX | PORT | 16 | Perform I/O, see section below |
1111 0RRR | COMP | 8 | Compare register S with register RRR , see section below |
1111 10XX | STCK | 4 | Stack manipulation, see section below |
1111 110X | 2 | Reserved | |
1111 1110 | CLRF | 1 | Clear the F register, by setting it to 0000 0000 |
1111 1111 | HALT | 1 | Stop 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 Mask | Load Type | Description |
---|---|---|
0 0RRR | Byte immediate | Load the the next byte into register RRR |
0 1RRR | From memory | Load the byte address by ADR into register RRR |
1 00XX | Wide immediate | Load the the next two bytes into a register pair |
1 01XX | Reserved | |
1 1XXX | Reserved |
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.
RR | Registers |
---|---|
00 | A and B |
01 | C and D |
10 | X and Y |
11 | ADR |
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
Load the the next byte into register RRR
(PC will be incremented a second time), see section above
Fields of LoadImmediateByte
rrr: u8
Load the the next two byte into register pair RR
(PC will be incremented two more times), see section above
Fields of LoadImmediateWide
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
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 a value from register QQQ
to register RRR
Manipulate ADR, see section above
Fields of Madr
Perform I/O, see section above
Fields of Port
d: InstructionPortDirection
rrr: u8
Compare register S with register RRR
, see section above
Fields of Comp
rrr: u8
Stack manipulation, see member doc
Fields of Stck
Clear the F register, by setting it to 0000 0000
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]
&'s self,
registers: &'r GeneralPurposeRegisterBank
) -> DisplayInstruction<'r>
Get proxy object implementing Display
for printing instructions in assembly format
Examples
assert_eq!(Instruction::Clrf.display(®isters).to_string(), "CLRF"); assert_eq!(Instruction::Alu(AluOperation::Or).display(®isters).to_string(), "ALU OR"); assert_eq!(Instruction::Stck { d: InstructionStckDirection::Push, r: InstructionRegisterPair::Cd, }.display(®isters).to_string(), "STCK PUSH C&D"); assert_eq!(Instruction::Reserved(0b1111_0000).display(®isters).to_string(), "0b1111_0000");
pub fn from_str(
s: &str,
registers: &GeneralPurposeRegisterBank
) -> Result<Instruction, ParseInstructionError>
[src]
s: &str,
registers: &GeneralPurposeRegisterBank
) -> Result<Instruction, ParseInstructionError>
Parse assembly instruction format
The input string must be ASCII and contain no vertical whitespace
Examples
assert_eq!(Instruction::from_str("JMPL", ®isters), Ok(Instruction::Jump(InstructionJumpCondition::Jmpl))); assert_eq!(Instruction::from_str("LOAD IND B", ®isters), Ok(Instruction::LoadIndirect { rrr: 0b101 })); assert_eq!(Instruction::from_str("ALU SOR RIGHT ASF", ®isters), Ok(Instruction::Alu(AluOperation::ShiftOrRotate { d: AluOperationShiftOrRotateDirection::Right, tt: AluOperationShiftOrRotateType::Asf, })));
Trait Implementations
impl Clone for Instruction
[src]
fn clone(&self) -> Instruction
[src]
fn clone_from(&mut self, source: &Self)
1.0.0[src]
impl Copy for Instruction
[src]
impl Debug for Instruction
[src]
impl Eq for Instruction
[src]
impl From<u8> for Instruction
[src]
fn from(raw: u8) -> Instruction
[src]
impl Hash for Instruction
[src]
fn hash<__H: Hasher>(&self, state: &mut __H)
[src]
fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl Into<u8> for Instruction
[src]
impl Ord for Instruction
[src]
fn cmp(&self, other: &Instruction) -> Ordering
[src]
fn max(self, other: Self) -> Self
1.21.0[src]
fn min(self, other: Self) -> Self
1.21.0[src]
fn clamp(self, min: Self, max: Self) -> Self
[src]
impl PartialEq<Instruction> for Instruction
[src]
fn eq(&self, other: &Instruction) -> bool
[src]
fn ne(&self, other: &Instruction) -> bool
[src]
impl PartialOrd<Instruction> for Instruction
[src]
fn partial_cmp(&self, other: &Instruction) -> Option<Ordering>
[src]
fn lt(&self, other: &Instruction) -> bool
[src]
fn le(&self, other: &Instruction) -> bool
[src]
fn gt(&self, other: &Instruction) -> bool
[src]
fn ge(&self, other: &Instruction) -> bool
[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]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> Downcast for T where
T: Any,
[src]
T: Any,
fn into_any(self: Box<T>) -> Box<dyn Any + 'static>
[src]
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
[src]
fn as_any(&self) -> &(dyn Any + 'static)
[src]
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
[src]
impl<T> DowncastSync for T where
T: Send + Sync + Any,
[src]
T: Send + Sync + Any,
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
fn to_owned(&self) -> T
[src]
fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,