lc3_vm/hardware/instructions/trap.rs
1//! `trap` :
2//! The LC-3 provides a few predefined routines for performing common tasks and interacting with I/O devices.
3//! For example, there are routines for getting input from the keyboard and for displaying strings to the console.
4//! These are called trap routines which you can think of as the operating system or API for the LC-3.
5//! Each trap routine is assigned a trap code which identifies it (similar to an opcode).
6//! To execute one, the TRAP instruction is called with the trap code of the desired routine.
7use crate::hardware::register::Registers;
8use crate::hardware::Memory;
9use crate::sys::getchar;
10use crate::sys::terminal;
11use std::io;
12use std::io::Write;
13use std::process;
14
15// TRAP Codes
16pub enum TrapCode {
17 /// get character from keyboard
18 Getc = 0x20, /* get character from keyboard */
19 /// output a character
20 Out = 0x21, /* output a character */
21 /// output a word string
22 Puts = 0x22, /* output a word string */
23 /// input a string
24 In = 0x23, /* input a string */
25 /// output a byte string
26 Putsp = 0x24, /* output a byte string */
27 /// halt the program
28 Halt = 0x25, /* halt the program */
29}
30
31/// `trap` fn allows interacting with I/O devices
32/// First R7 is loaded with the incremented PC.
33// (This enables a return to the instruction physically following the TRAP instruction in the original program
34/// after the service routine has completed execution.)
35/// Then the PC is loaded with the starting address of the system call specified by trapvector8.
36/// The starting address is contained in the memory location whose address is obtained by zero-extending trapvector8 to 16 bits.
37pub fn trap(instr: u16, registers: &mut Registers, memory: &mut Memory) {
38 terminal::turn_off_canonical_and_echo_modes();
39 match instr & 0xFF {
40 0x20 => {
41 registers.update(0, getchar::get_char() as u16);
42 }
43 0x21 => {
44 print!("{}", (registers.r_00 as u8) as char);
45 io::stdout().flush().expect("Flushed.");
46 }
47 0x22 => {
48 // /* one char per word */
49 let mut index = registers.r_00 as usize;
50 let mut c = memory.cells[index];
51 while c != 0x0000 {
52 print!("{}", (c as u8) as char);
53 index += 1;
54 c = memory.cells[index];
55 }
56 io::stdout().flush().expect("Flushed.");
57 }
58 0x23 => {
59 print!("Enter a character : ");
60 io::stdout().flush().expect("Flushed.");
61 registers.update(0, getchar::get_char() as u16);
62 }
63 0x24 => {
64 let mut index = registers.r_00 as usize;
65 let mut c = memory.cells[index];
66 while c != 0x0000 {
67 let c1 = ((c & 0xFF) as u8) as char;
68 print!("{}", c1);
69 let c2 = ((c >> 8) as u8) as char;
70 if c2 != '\0' {
71 print!("{}", c2);
72 }
73 index += 1;
74 c = memory.cells[index];
75 }
76 io::stdout().flush().expect("Flushed.");
77 }
78 0x25 => {
79 /* TRAP HALT */
80 print!("HALT");
81 io::stdout().flush().expect("Flushed.");
82 terminal::restore_terminal_settings();
83 process::exit(1);
84 }
85 _ => {
86 terminal::restore_terminal_settings();
87 process::exit(1);
88 }
89 }
90 terminal::restore_terminal_settings();
91}