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}