~maddie/STT-implementation

ref: 0498f90e33c864784a80996a9a1494e763041029 STT-implementation/src/lib.rs -rw-r--r-- 5.1 KiB
0498f90e — kn0000 Added helper function for keyboard input 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
const STACK_SIZE: usize = 1024;
pub const MEMORY_SIZE: usize = 1<<20;
pub const SCREEN_WIDTH: usize = 512;
pub const SCREEN_HEIGHT: usize = 512;
pub const SCREEN_UPDATE_ADDRESS: usize = 0x7FFFF;

use minifb::Key;

#[derive(Debug)]
pub struct Stack {
    buffer: [u16;STACK_SIZE],
    index: usize
}

impl Stack {
    fn push(&mut self, value: u16) {
        self.buffer[self.index] = value;
        self.index = (self.index + 1) % STACK_SIZE;
    }

    fn pop(&mut self) -> u16 {
        self.index = (self.index + STACK_SIZE - 1) % STACK_SIZE;
        self.buffer[self.index]
    }
}

pub fn new_stack() -> Stack {
    Stack{
        buffer: [0u16;STACK_SIZE],
        index: 0
    }
}

pub struct Processor {
    pub stack_a: Stack,
    pub stack_b: Stack,
    pub memory: [u16;MEMORY_SIZE],
    pub carry: bool,
    pub pc: usize
}

impl Processor {
    pub fn run(&mut self) -> bool {
        let instruction = self.memory[self.pc] & 0x3FF;
        let (mut stack, off_stack)  = {
            if (instruction & 0x200) == 0 {
                (&mut self.stack_a, &mut self.stack_b)
            }
            else {(&mut self.stack_b, &mut self.stack_a)}
        };
        let mut is_jump = false;

        if instruction & 0x100 == 0 { //calculation
            self.carry = calc(&mut stack, instruction, self.carry);
        }
        else if instruction & 0x80 == 0 { //jump
            let push_pc = (instruction & 0x40) != 0;
            let conditional = (instruction & 0x20) != 0;
            if !conditional || self.carry {
                let address = (stack.pop() as usize) | ((stack.pop() as usize) << 10);
                is_jump = true;
                if push_pc {
                    let a = self.pc + 1;
                    let upper = a & 0b11111111110000000000 >> 10;
                    let lower = a & 0b1111111111;
                    stack.push(upper as u16);
                    stack.push(lower as u16);
                }
                self.pc = address;
            }
        }
        else {
            match instruction & 0x7F {
                0 => { //immediate value
                    self.pc += 1;
                    stack.push(self.memory[self.pc] & 0x3FF);
                }
                1 => { //push pc
                    let upper = self.pc & 0b11111111110000000000 >> 10;
                    let lower = self.pc & 0b1111111111;
                    stack.push(upper as u16);
                    stack.push(lower as u16);
                }
                2 => { //swap
                    let a = stack.pop();
                    let b = stack.pop();
                    stack.push(a);
                    stack.push(b);
                }
                3 => off_stack.push(stack.pop()), //move between stacks
                4 => { //push from memory
                    let address = (stack.pop() as usize) | ((stack.pop() as usize) << 10);
                    stack.push(self.memory[address]);
                }
                5 => { //pop to memory
                    let address = (stack.pop() as usize) | ((stack.pop() as usize) << 10);
                    self.memory[address] = stack.pop();
                }
                6 => { //dup
                    let a = stack.pop();
                    stack.push(a);
                    stack.push(a);
                }
                7 => { //over
                    let a = stack.pop();
                    let b = stack.pop();
                    stack.push(b);
                    stack.push(a);
                    stack.push(b);
                }
                8 => self.carry = false, //clear/set carry
                9 => self.carry = true,
                10 => _ = stack.pop(), //drop value
                0x7F => return false,
                _ => ()
            }
        }
        if !is_jump {self.pc += 1};
        true
    }
}

fn calc(stack: &mut Stack, instruction: u16, carry_in: bool) -> bool {
    let operand_a = stack.pop();
    let operand_b = stack.pop();
    let mut carry = carry_in;
    let mut result = 0;
    for i in 0..10 {
        let count = ((operand_a >> i) & 1) + ((operand_b >> i) & 1) + (carry as u16);
        result += ((instruction >> (count+4)) & 1) << i;
        carry = ((instruction >> count) & 1) != 0;
    }
    stack.push(result);
    carry
}

pub fn mem_to_buf(memory: &[u16]) -> Vec<u32> {
    let mut result = Vec::new();
    for byte in &memory[(MEMORY_SIZE-SCREEN_WIDTH*SCREEN_HEIGHT)..MEMORY_SIZE] {
        result.push((((byte & 0b111000000) as u32) << 15) | (((byte & 0b111000) as u32) << 10) | (((byte & 0b111) as u32) << 5)); //shifts 3 bits of each 10 bit value into the rgb channels of the buffer, from the last region of memory
    }
    result
}

pub fn keys_to_state(keys: Vec<Key>) -> Vec<u16> { //output is using only 10 bits each to match with
    let mut result = 0u128;                        //rest of system
    for key in keys {                              //see minifb docs for what number each key is
        result &= 1 << (key as usize);
    }
    let mut output = Vec::new();
    for i in 0..11 {
        let slice = ((result>>(10*i))&0x3FF) as u16;
        output.push(slice);
    }
    output
}