1use std::collections::HashMap;
10
11pub const UXN_OPCODE_TABLE: &[(u8, &str)] = &[
22 (0x00, "BRK"),
24 (0x01, "INC"),
25 (0x02, "POP"),
26 (0x03, "NIP"),
27 (0x04, "SWP"),
28 (0x05, "ROT"),
29 (0x06, "DUP"),
30 (0x07, "OVR"),
31 (0x08, "EQU"),
32 (0x09, "NEQ"),
33 (0x0A, "GTH"),
34 (0x0B, "LTH"),
35 (0x0C, "JMP"),
36 (0x0D, "JCN"),
37 (0x0E, "JSR"),
38 (0x0F, "STH"),
39 (0x10, "LDZ"),
41 (0x11, "STZ"),
42 (0x12, "LDR"),
43 (0x13, "STR"),
44 (0x14, "LDA"),
45 (0x15, "STA"),
46 (0x16, "DEI"),
47 (0x17, "DEO"),
48 (0x18, "ADD"),
49 (0x19, "SUB"),
50 (0x1A, "MUL"),
51 (0x1B, "DIV"),
52 (0x1C, "AND"),
53 (0x1D, "ORA"),
54 (0x1E, "EOR"),
55 (0x1F, "SFT"),
56 (0x20, "JCI"),
58 (0x21, "INC2"),
59 (0x22, "POP2"),
60 (0x23, "NIP2"),
61 (0x24, "SWP2"),
62 (0x25, "ROT2"),
63 (0x26, "DUP2"),
64 (0x27, "OVR2"),
65 (0x28, "EQU2"),
66 (0x29, "NEQ2"),
67 (0x2A, "GTH2"),
68 (0x2B, "LTH2"),
69 (0x2C, "JMP2"),
70 (0x2D, "JCN2"),
71 (0x2E, "JSR2"),
72 (0x2F, "STH2"),
73 (0x30, "LDZ2"),
75 (0x31, "STZ2"),
76 (0x32, "LDR2"),
77 (0x33, "STR2"),
78 (0x34, "LDA2"),
79 (0x35, "STA2"),
80 (0x36, "DEI2"),
81 (0x37, "DEO2"),
82 (0x38, "ADD2"),
83 (0x39, "SUB2"),
84 (0x3A, "MUL2"),
85 (0x3B, "DIV2"),
86 (0x3C, "AND2"),
87 (0x3D, "ORA2"),
88 (0x3E, "EOR2"),
89 (0x3F, "SFT2"),
90 (0x40, "JMI"),
92 (0x41, "INCr"),
93 (0x42, "POPr"),
94 (0x43, "NIPr"),
95 (0x44, "SWPr"),
96 (0x45, "ROTr"),
97 (0x46, "DUPr"),
98 (0x47, "OVRr"),
99 (0x48, "EQUr"),
100 (0x49, "NEQr"),
101 (0x4A, "GTHr"),
102 (0x4B, "LTHr"),
103 (0x4C, "JMPr"),
104 (0x4D, "JCNr"),
105 (0x4E, "JSRr"),
106 (0x4F, "STHr"),
107 (0x50, "LDZr"),
109 (0x51, "STZr"),
110 (0x52, "LDRr"),
111 (0x53, "STRr"),
112 (0x54, "LDAr"),
113 (0x55, "STAr"),
114 (0x56, "DEIr"),
115 (0x57, "DEOr"),
116 (0x58, "ADDr"),
117 (0x59, "SUBr"),
118 (0x5A, "MULr"),
119 (0x5B, "DIVr"),
120 (0x5C, "ANDr"),
121 (0x5D, "ORAr"),
122 (0x5E, "EORr"),
123 (0x5F, "SFTr"),
124 (0x60, "JSI"),
126 (0x61, "INC2r"),
127 (0x62, "POP2r"),
128 (0x63, "NIP2r"),
129 (0x64, "SWP2r"),
130 (0x65, "ROT2r"),
131 (0x66, "DUP2r"),
132 (0x67, "OVR2r"),
133 (0x68, "EQU2r"),
134 (0x69, "NEQ2r"),
135 (0x6A, "GTH2r"),
136 (0x6B, "LTH2r"),
137 (0x6C, "JMP2r"),
138 (0x6D, "JCN2r"),
139 (0x6E, "JSR2r"),
140 (0x6F, "STH2r"),
141 (0x70, "LDZ2r"),
143 (0x71, "STZ2r"),
144 (0x72, "LDR2r"),
145 (0x73, "STR2r"),
146 (0x74, "LDA2r"),
147 (0x75, "STA2r"),
148 (0x76, "DEI2r"),
149 (0x77, "DEO2r"),
150 (0x78, "ADD2r"),
151 (0x79, "SUB2r"),
152 (0x7A, "MUL2r"),
153 (0x7B, "DIV2r"),
154 (0x7C, "AND2r"),
155 (0x7D, "ORA2r"),
156 (0x7E, "EOR2r"),
157 (0x7F, "SFT2r"),
158 (0x80, "LIT"),
160 (0x81, "INCk"),
161 (0x82, "POPk"),
162 (0x83, "NIPk"),
163 (0x84, "SWPk"),
164 (0x85, "ROTk"),
165 (0x86, "DUPk"),
166 (0x87, "OVRk"),
167 (0x88, "EQUk"),
168 (0x89, "NEQk"),
169 (0x8A, "GTHk"),
170 (0x8B, "LTHk"),
171 (0x8C, "JMPk"),
172 (0x8D, "JCNk"),
173 (0x8E, "JSRk"),
174 (0x8F, "STHk"),
175 (0x90, "LDZk"),
177 (0x91, "STZk"),
178 (0x92, "LDRk"),
179 (0x93, "STRk"),
180 (0x94, "LDAk"),
181 (0x95, "STAk"),
182 (0x96, "DEIk"),
183 (0x97, "DEOk"),
184 (0x98, "ADDk"),
185 (0x99, "SUBk"),
186 (0x9A, "MULk"),
187 (0x9B, "DIVk"),
188 (0x9C, "ANDk"),
189 (0x9D, "ORAk"),
190 (0x9E, "EORk"),
191 (0x9F, "SFTk"),
192 (0xA0, "LIT2"),
194 (0xA1, "INC2k"),
195 (0xA2, "POP2k"),
196 (0xA3, "NIP2k"),
197 (0xA4, "SWP2k"),
198 (0xA5, "ROT2k"),
199 (0xA6, "DUP2k"),
200 (0xA7, "OVR2k"),
201 (0xA8, "EQU2k"),
202 (0xA9, "NEQ2k"),
203 (0xAA, "GTH2k"),
204 (0xAB, "LTH2k"),
205 (0xAC, "JMP2k"),
206 (0xAD, "JCN2k"),
207 (0xAE, "JSR2k"),
208 (0xAF, "STH2k"),
209 (0xB0, "LDZ2k"),
211 (0xB1, "STZ2k"),
212 (0xB2, "LDR2k"),
213 (0xB3, "STR2k"),
214 (0xB4, "LDA2k"),
215 (0xB5, "STA2k"),
216 (0xB6, "DEI2k"),
217 (0xB7, "DEO2k"),
218 (0xB8, "ADD2k"),
219 (0xB9, "SUB2k"),
220 (0xBA, "MUL2k"),
221 (0xBB, "DIV2k"),
222 (0xBC, "AND2k"),
223 (0xBD, "ORA2k"),
224 (0xBE, "EOR2k"),
225 (0xBF, "SFT2k"),
226 (0xC0, "LITr"),
228 (0xC1, "INCkr"),
229 (0xC2, "POPkr"),
230 (0xC3, "NIPkr"),
231 (0xC4, "SWPkr"),
232 (0xC5, "ROTkr"),
233 (0xC6, "DUPkr"),
234 (0xC7, "OVRkr"),
235 (0xC8, "EQUkr"),
236 (0xC9, "NEQkr"),
237 (0xCA, "GTHkr"),
238 (0xCB, "LTHkr"),
239 (0xCC, "JMPkr"),
240 (0xCD, "JCNkr"),
241 (0xCE, "JSRkr"),
242 (0xCF, "STHkr"),
243 (0xD0, "LDZkr"),
245 (0xD1, "STZkr"),
246 (0xD2, "LDRkr"),
247 (0xD3, "STRkr"),
248 (0xD4, "LDAkr"),
249 (0xD5, "STAkr"),
250 (0xD6, "DEIkr"),
251 (0xD7, "DEOkr"),
252 (0xD8, "ADDkr"),
253 (0xD9, "SUBkr"),
254 (0xDA, "MULkr"),
255 (0xDB, "DIVkr"),
256 (0xDC, "ANDkr"),
257 (0xDD, "ORAkr"),
258 (0xDE, "EORkr"),
259 (0xDF, "SFTkr"),
260 (0xE0, "LIT2r"),
262 (0xE1, "INC2kr"),
263 (0xE2, "POP2kr"),
264 (0xE3, "NIP2kr"),
265 (0xE4, "SWP2kr"),
266 (0xE5, "ROT2kr"),
267 (0xE6, "DUP2kr"),
268 (0xE7, "OVR2kr"),
269 (0xE8, "EQU2kr"),
270 (0xE9, "NEQ2kr"),
271 (0xEA, "GTH2kr"),
272 (0xEB, "LTH2kr"),
273 (0xEC, "JMP2kr"),
274 (0xED, "JCN2kr"),
275 (0xEE, "JSR2kr"),
276 (0xEF, "STH2kr"),
277 (0xF0, "LDZ2kr"),
279 (0xF1, "STZ2kr"),
280 (0xF2, "LDR2kr"),
281 (0xF3, "STR2kr"),
282 (0xF4, "LDA2kr"),
283 (0xF5, "STA2kr"),
284 (0xF6, "DEI2kr"),
285 (0xF7, "DEO2kr"),
286 (0xF8, "ADD2kr"),
287 (0xF9, "SUB2kr"),
288 (0xFA, "MUL2kr"),
289 (0xFB, "DIV2kr"),
290 (0xFC, "AND2kr"),
291 (0xFD, "ORA2kr"),
292 (0xFE, "EOR2kr"),
293 (0xFF, "SFT2kr"),
294];
295
296pub const BASE_INSTRUCTIONS: &[&str] = &[
298 "BRK", "INC", "POP", "NIP", "SWP", "ROT", "DUP", "OVR", "EQU", "NEQ", "GTH", "LTH", "JMP", "JCN", "JSR", "STH", "LDZ", "STZ", "LDR", "STR", "LDA", "STA", "DEI", "DEO", "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT", ];
303
304pub fn create_instruction_map() -> HashMap<String, u8> {
306 let mut map = HashMap::new();
307 for (index, &instruction) in BASE_INSTRUCTIONS.iter().enumerate() {
308 map.insert(instruction.to_string(), index as u8);
309 map.insert(instruction.to_ascii_lowercase(), index as u8);
310 }
311 map
312}
313
314pub fn get_opcode_name(opcode: u8) -> &'static str {
316 UXN_OPCODE_TABLE[opcode as usize].1
317}
318
319pub fn decode_opcode(opcode: u8) -> (u8, bool, bool, bool) {
321 let base = opcode & 0x1F; let short_mode = (opcode & 0x20) != 0; let return_mode = (opcode & 0x40) != 0; let keep_mode = (opcode & 0x80) != 0; (base, short_mode, return_mode, keep_mode)
327}
328
329pub fn encode_opcode(base: u8, short_mode: bool, return_mode: bool, keep_mode: bool) -> u8 {
331 let mut opcode = base & 0x1F;
332 if short_mode {
333 opcode |= 0x20;
334 }
335 if return_mode {
336 opcode |= 0x40;
337 }
338 if keep_mode {
339 opcode |= 0x80;
340 }
341 opcode
342}
343
344pub fn verify_opcode_table() -> Result<(), String> {
346 if UXN_OPCODE_TABLE.len() != 256 {
348 return Err(format!(
349 "Expected 256 opcodes, found {}",
350 UXN_OPCODE_TABLE.len()
351 ));
352 }
353
354 for (i, &(opcode, _)) in UXN_OPCODE_TABLE.iter().enumerate() {
356 if opcode != i as u8 {
357 return Err(format!(
358 "Opcode at index {} should be 0x{:02x}, found 0x{:02x}",
359 i, i, opcode
360 ));
361 }
362 }
363
364 let special_checks = [
366 (0x00, "BRK"),
367 (0x80, "LIT"),
368 (0xA0, "LIT2"),
369 (0x17, "DEO"),
370 (0x20, "JCI"),
371 (0x40, "JMI"),
372 (0x60, "JSI"),
373 ];
374
375 for &(opcode, expected_name) in &special_checks {
376 let actual_name = get_opcode_name(opcode);
377 if actual_name != expected_name {
378 return Err(format!(
379 "Opcode 0x{:02x} should be '{}', found '{}'",
380 opcode, expected_name, actual_name
381 ));
382 }
383 }
384
385 println!("✓ UXN opcode table verification passed");
386 Ok(())
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn test_opcode_table_verification() {
395 verify_opcode_table().unwrap();
396 }
397
398 #[test]
399 fn test_opcode_encoding() {
400 assert_eq!(encode_opcode(0x00, false, false, true), 0x80);
402
403 assert_eq!(encode_opcode(0x00, true, false, true), 0xA0);
405
406 assert_eq!(encode_opcode(0x17, false, false, false), 0x17);
408
409 assert_eq!(encode_opcode(0x18, true, false, true), 0xB8);
411 }
412
413 #[test]
414 fn test_opcode_decoding() {
415 let (base, short, ret, keep) = decode_opcode(0x80);
417 assert_eq!(base, 0x00);
418 assert!(!short);
419 assert!(!ret);
420 assert!(keep);
421
422 let (base, short, ret, keep) = decode_opcode(0xF8);
424 assert_eq!(base, 0x18);
425 assert!(short);
426 assert!(ret);
427 assert!(keep);
428 }
429
430 #[test]
431 fn test_instruction_names() {
432 assert_eq!(get_opcode_name(0x00), "BRK");
433 assert_eq!(get_opcode_name(0x80), "LIT");
434 assert_eq!(get_opcode_name(0x17), "DEO");
435 assert_eq!(get_opcode_name(0xB8), "ADD2k");
436 assert_eq!(get_opcode_name(0xFF), "SFT2kr");
437 }
438}