lc3_zkvm/opcode.rs
1//! LC3 Opcode Module
2//!
3//! This module defines the opcodes for the LC3 (Little Computer 3) Zero-Knowledge Virtual Machine.
4//! It includes enumerations for the opcodes and their associated functions.
5
6/// Represents the LC3 opcodes
7#[allow(non_camel_case_types)]
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Opcode {
10 /// Branch
11 /// Conditional branch based on condition codes (N, Z, P)
12 /// Format: 0000 NZP PCoffset9
13 OP_BR = 0x0,
14
15 /// Add
16 /// Add two values and store the result
17 /// Format: 0001 DR SR1 000 SR2 (register mode)
18 /// 0001 DR SR1 1 imm5 (immediate mode)
19 OP_ADD = 0x1,
20
21 /// Load
22 /// Load a value from memory into a register
23 /// Format: 0010 DR PCoffset9
24 OP_LD = 0x2,
25
26 /// Store
27 /// Store a value from a register into memory
28 /// Format: 0011 SR PCoffset9
29 OP_ST = 0x3,
30
31 /// Jump to Subroutine
32 /// Jump to a subroutine and save the return address
33 /// Format: 0100 1 PCoffset11 (JSR)
34 /// 0100 000 BaseR 000000 (JSRR)
35 OP_JSR = 0x4,
36
37 /// Bitwise AND
38 /// Perform bitwise AND operation
39 /// Format: 0101 DR SR1 000 SR2 (register mode)
40 /// 0101 DR SR1 1 imm5 (immediate mode)
41 OP_AND = 0x5,
42
43 /// Load Register
44 /// Load a value from memory using a base register and offset
45 /// Format: 0110 DR BaseR offset6
46 OP_LDR = 0x6,
47
48 /// Store Register
49 /// Store a value to memory using a base register and offset
50 /// Format: 0111 SR BaseR offset6
51 OP_STR = 0x7,
52
53 /// Return from Interrupt
54 /// Unused in LC3
55 /// Format: 1000 000000000000
56 OP_RTI = 0x8,
57
58 /// Bitwise NOT
59 /// Perform bitwise NOT operation
60 /// Format: 1001 DR SR 111111
61 OP_NOT = 0x9,
62
63 /// Load Indirect
64 /// Load a value from memory using an address stored in memory
65 /// Format: 1010 DR PCoffset9
66 OP_LDI = 0xA,
67
68 /// Store Indirect
69 /// Store a value to memory using an address stored in memory
70 /// Format: 1011 SR PCoffset9
71 OP_STI = 0xB,
72
73 /// Jump
74 /// Jump to an address specified by a register
75 /// Format: 1100 000 BaseR 000000
76 OP_JMP = 0xC,
77
78 /// Reserved
79 /// Unused opcode
80 /// Format: 1101 000000000000
81 OP_RES = 0xD,
82
83 /// Load Effective Address
84 /// Load a memory address into a register
85 /// Format: 1110 DR PCoffset9
86 OP_LEA = 0xE,
87
88 /// Execute Trap
89 /// Execute a system call
90 /// Format: 1111 0000 trapvect8
91 OP_TRAP = 0xF,
92}
93
94impl Opcode {
95 /// Convert a u16 to an Opcode
96 pub fn from_u16(value: u16) -> Option<Self> {
97 match value {
98 0 => Some(Opcode::OP_BR),
99 1 => Some(Opcode::OP_ADD),
100 2 => Some(Opcode::OP_LD),
101 3 => Some(Opcode::OP_ST),
102 4 => Some(Opcode::OP_JSR),
103 5 => Some(Opcode::OP_AND),
104 6 => Some(Opcode::OP_LDR),
105 7 => Some(Opcode::OP_STR),
106 8 => Some(Opcode::OP_RTI),
107 9 => Some(Opcode::OP_NOT),
108 10 => Some(Opcode::OP_LDI),
109 11 => Some(Opcode::OP_STI),
110 12 => Some(Opcode::OP_JMP),
111 13 => Some(Opcode::OP_RES),
112 14 => Some(Opcode::OP_LEA),
113 15 => Some(Opcode::OP_TRAP),
114 _ => None,
115 }
116 }
117
118 /// Convert an Opcode to a u16
119 pub fn to_u16(self) -> u16 {
120 self as u16
121 }
122}
123
124/// Extract the opcode from a 16-bit instruction
125pub fn extract_opcode(instruction: u16) -> Option<Opcode> {
126 Opcode::from_u16(instruction >> 12)
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn test_opcode_conversion() {
135 assert_eq!(Opcode::from_u16(0), Some(Opcode::OP_BR));
136 assert_eq!(Opcode::from_u16(15), Some(Opcode::OP_TRAP));
137 assert_eq!(Opcode::from_u16(16), None);
138
139 assert_eq!(Opcode::OP_BR.to_u16(), 0);
140 assert_eq!(Opcode::OP_TRAP.to_u16(), 15);
141 }
142
143 #[test]
144 fn test_extract_opcode() {
145 assert_eq!(extract_opcode(0b0001_000_000_000_000), Some(Opcode::OP_ADD));
146 assert_eq!(
147 extract_opcode(0b1111_000_000_000_000),
148 Some(Opcode::OP_TRAP)
149 );
150 assert_eq!(
151 extract_opcode(0b1111_111_111_111_111),
152 Some(Opcode::OP_TRAP)
153 );
154 }
155}