├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── examples ├── 2048.obj ├── bootstrap.asm ├── hello-world.obj ├── hello-world.obj.asm └── rogue.obj └── src ├── hardware ├── instruction │ └── mod.rs ├── mod.rs ├── register │ └── mod.rs └── vm │ └── mod.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "LC-3" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "byteorder", 10 | "structopt", 11 | "termios", 12 | ] 13 | 14 | [[package]] 15 | name = "ansi_term" 16 | version = "0.11.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 19 | dependencies = [ 20 | "winapi", 21 | ] 22 | 23 | [[package]] 24 | name = "atty" 25 | version = "0.2.14" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 28 | dependencies = [ 29 | "hermit-abi", 30 | "libc", 31 | "winapi", 32 | ] 33 | 34 | [[package]] 35 | name = "bitflags" 36 | version = "1.2.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 39 | 40 | [[package]] 41 | name = "byteorder" 42 | version = "1.4.3" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 45 | 46 | [[package]] 47 | name = "clap" 48 | version = "2.33.3" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 51 | dependencies = [ 52 | "ansi_term", 53 | "atty", 54 | "bitflags", 55 | "strsim", 56 | "textwrap", 57 | "unicode-width", 58 | "vec_map", 59 | ] 60 | 61 | [[package]] 62 | name = "heck" 63 | version = "0.3.3" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 66 | dependencies = [ 67 | "unicode-segmentation", 68 | ] 69 | 70 | [[package]] 71 | name = "hermit-abi" 72 | version = "0.1.19" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 75 | dependencies = [ 76 | "libc", 77 | ] 78 | 79 | [[package]] 80 | name = "lazy_static" 81 | version = "1.4.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 84 | 85 | [[package]] 86 | name = "libc" 87 | version = "0.2.97" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" 90 | 91 | [[package]] 92 | name = "proc-macro-error" 93 | version = "1.0.4" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 96 | dependencies = [ 97 | "proc-macro-error-attr", 98 | "proc-macro2", 99 | "quote", 100 | "syn", 101 | "version_check", 102 | ] 103 | 104 | [[package]] 105 | name = "proc-macro-error-attr" 106 | version = "1.0.4" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 109 | dependencies = [ 110 | "proc-macro2", 111 | "quote", 112 | "version_check", 113 | ] 114 | 115 | [[package]] 116 | name = "proc-macro2" 117 | version = "1.0.28" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" 120 | dependencies = [ 121 | "unicode-xid", 122 | ] 123 | 124 | [[package]] 125 | name = "quote" 126 | version = "1.0.9" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 129 | dependencies = [ 130 | "proc-macro2", 131 | ] 132 | 133 | [[package]] 134 | name = "strsim" 135 | version = "0.8.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 138 | 139 | [[package]] 140 | name = "structopt" 141 | version = "0.3.22" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" 144 | dependencies = [ 145 | "clap", 146 | "lazy_static", 147 | "structopt-derive", 148 | ] 149 | 150 | [[package]] 151 | name = "structopt-derive" 152 | version = "0.4.15" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" 155 | dependencies = [ 156 | "heck", 157 | "proc-macro-error", 158 | "proc-macro2", 159 | "quote", 160 | "syn", 161 | ] 162 | 163 | [[package]] 164 | name = "syn" 165 | version = "1.0.74" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" 168 | dependencies = [ 169 | "proc-macro2", 170 | "quote", 171 | "unicode-xid", 172 | ] 173 | 174 | [[package]] 175 | name = "termios" 176 | version = "0.3.3" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" 179 | dependencies = [ 180 | "libc", 181 | ] 182 | 183 | [[package]] 184 | name = "textwrap" 185 | version = "0.11.0" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 188 | dependencies = [ 189 | "unicode-width", 190 | ] 191 | 192 | [[package]] 193 | name = "unicode-segmentation" 194 | version = "1.8.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 197 | 198 | [[package]] 199 | name = "unicode-width" 200 | version = "0.1.8" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 203 | 204 | [[package]] 205 | name = "unicode-xid" 206 | version = "0.2.2" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 209 | 210 | [[package]] 211 | name = "vec_map" 212 | version = "0.8.2" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 215 | 216 | [[package]] 217 | name = "version_check" 218 | version = "0.9.3" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 221 | 222 | [[package]] 223 | name = "winapi" 224 | version = "0.3.9" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 227 | dependencies = [ 228 | "winapi-i686-pc-windows-gnu", 229 | "winapi-x86_64-pc-windows-gnu", 230 | ] 231 | 232 | [[package]] 233 | name = "winapi-i686-pc-windows-gnu" 234 | version = "0.4.0" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 237 | 238 | [[package]] 239 | name = "winapi-x86_64-pc-windows-gnu" 240 | version = "0.4.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 243 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "LC-3" 3 | version = "0.1.0" 4 | authors = ["Rodrigo Araujo "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | byteorder = "1.4.3" 11 | termios = "0.3.1" 12 | structopt = "0.3.22" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LC-3 written in Rust 2 | 3 | An LC-3 virtual machine written in Rust for learning purposes. 4 | 5 | Write-up/guide can be found here: www.rodrigoaraujo.me/posts/lets-build-an-lc-3-virtual-machine/ 6 | 7 | To run an LC-3 program: `cargo run -- examples/.obj` 8 | -------------------------------------------------------------------------------- /examples/2048.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digorithm/LC-3-Rust/61c93c60c3088ba8bfb4fe0ea92f38a8136ca5d5/examples/2048.obj -------------------------------------------------------------------------------- /examples/bootstrap.asm: -------------------------------------------------------------------------------- 1 | .orig x6000 2 | ;; JUMP TABLE: 3 | .fill x3076 ; COND_222_0_ln_21 4 | .fill x3091 ; COND_959_2_ln_28 5 | .fill x30e7 ; COND_410_3_ln_28 6 | .fill x3136 ; COND_601_5_ln_49 7 | .fill x31b2 ; COND_84_6_ln_49 8 | .fill x31b4 ; COND_24_4_ln_37 9 | .fill x31b7 ; END_COND_24_4_ln_37 10 | .fill x31b9 ; COND_179_1_ln_21 11 | .fill x31bb ; F_eval 12 | .fill x31e9 ; COND_563_8_ln_80 13 | .fill x322a ; COND_94_11_ln_87 14 | .fill x327d ; COND_375_12_ln_87 15 | .fill x328d ; COND_168_10_ln_81 16 | .fill x32b8 ; COND_994_14_ln_98 17 | .fill x32e3 ; COND_493_15_ln_102 18 | .fill x330e ; COND_19_16_ln_106 19 | .fill x3314 ; END_COND_168_10_ln_81 20 | .fill x331e ; COND_935_9_ln_80 21 | .fill x3324 ; COND_574_16_ln_124 22 | .fill x3359 ; COND_573_19_ln_133 23 | .fill x33d7 ; COND_155_21_ln_143 24 | .fill x33e7 ; END_COND_155_21_ln_143 25 | .fill x33e9 ; COND_561_20_ln_133 26 | .fill x33f7 ; END_COND_850_18_ln_127 27 | .fill x33ff ; COND_118_17_ln_124 28 | ;; END OF JUMP TABLE 29 | .end 30 | 31 | 32 | .orig x6800 33 | ;; STR TABLE: 34 | .stringz "Type in an expression with only '+' and '*'.\nMake sure it is valid\n" 35 | .stringz "\n>>\t" 36 | .stringz "\nThe result is: " 37 | ;; END OF STR TABLE 38 | .end 39 | 40 | .orig x3000 41 | ;; CODE: 42 | 43 | brnzp #2 ; The code effectively starts at x3003 44 | STACK .fill xF000 45 | TABLE .fill x6000 46 | 47 | 48 | ;; i: 0, j: 0, IR: (None, '__setup_main__') 49 | ld R6, STACK ; 0 50 | add R5, R6, #-1 ; 1 51 | and R3, R3, #0 ; 2 52 | ld R4, TABLE ; 3 53 | add R6, R6, #-9 ; 4 54 | ;; i: 1, j: 5, IR: ([(4, "Type in an expression with only '+' and '*'.\nMake sure it is valid\n"), (3, 'msg')], '__array_assign__') 55 | add R6, R6, #-16 ; 5 56 | add R6, R6, #-16 ; 6 57 | add R6, R6, #-16 ; 7 58 | add R6, R6, #-16 ; 8 59 | add R6, R6, #-5 ; 9 60 | add R2, R3, #8 ; 10 61 | add R2, R2, R2 ; 11 62 | add R2, R2, R2 ; 12 63 | add R2, R2, R2 ; 13 64 | add R2, R2, #4 ; 14 65 | str R2, R6, #0 ; 15 66 | add R0, R5, #0 ; 16 67 | add R1, R6, #1 ; 17 68 | str R1, R0, #0 ; 18 69 | add R0, R3, #15 ; 19 70 | add R0, R0, #1 ; 20 71 | add R0, R0, R0 ; 21 72 | add R0, R0, R0 ; 22 73 | add R0, R0, R0 ; 23 74 | add R0, R0, R0 ; 24 75 | add R0, R0, R0 ; 25 76 | add R0, R0, R0 ; 26 77 | add R0, R0, R0 ; 27 78 | add R0, R0, #0 ; 28 79 | add R0, R4, R0 ; 29 80 | ldr R3, R0, #0 ; 30 81 | str R3, R1, #0 ; 31 82 | add R0, R0, #1 ; 32 83 | add R1, R1, #1 ; 33 84 | add R2, R2, #-1 ; 34 85 | brp #-6 ; 35 86 | and R3, R3, #0 ; 36 87 | ;; i: 2, j: 37, IR: ([(4, '\n>>\t'), (3, 'prompt')], '__array_assign__') 88 | add R6, R6, #-6 ; 37 89 | add R2, R3, #5 ; 38 90 | str R2, R6, #0 ; 39 91 | add R0, R5, #-1 ; 40 92 | add R1, R6, #1 ; 41 93 | str R1, R0, #0 ; 42 94 | add R0, R3, #15 ; 43 95 | add R0, R0, #1 ; 44 96 | add R0, R0, R0 ; 45 97 | add R0, R0, R0 ; 46 98 | add R0, R0, R0 ; 47 99 | add R0, R0, R0 ; 48 100 | add R0, R0, R0 ; 49 101 | add R0, R0, R0 ; 50 102 | add R0, R0, R0 ; 51 103 | add R0, R0, #15 ; 52 104 | add R0, R0, #15 ; 53 105 | add R0, R0, #15 ; 54 106 | add R0, R0, #15 ; 55 107 | add R0, R0, #8 ; 56 108 | add R0, R4, R0 ; 57 109 | ldr R3, R0, #0 ; 58 110 | str R3, R1, #0 ; 59 111 | add R0, R0, #1 ; 60 112 | add R1, R1, #1 ; 61 113 | add R2, R2, #-1 ; 62 114 | brp #-6 ; 63 115 | and R3, R3, #0 ; 64 116 | ;; i: 3, j: 65, IR: ([(4, '\nThe result is: '), (3, 'output')], '__array_assign__') 117 | add R6, R6, #-16 ; 65 118 | add R6, R6, #-2 ; 66 119 | add R2, R3, #8 ; 67 120 | add R2, R2, R2 ; 68 121 | add R2, R2, #1 ; 69 122 | str R2, R6, #0 ; 70 123 | add R0, R5, #-2 ; 71 124 | add R1, R6, #1 ; 72 125 | str R1, R0, #0 ; 73 126 | add R0, R3, #15 ; 74 127 | add R0, R0, #1 ; 75 128 | add R0, R0, R0 ; 76 129 | add R0, R0, R0 ; 77 130 | add R0, R0, R0 ; 78 131 | add R0, R0, R0 ; 79 132 | add R0, R0, R0 ; 80 133 | add R0, R0, R0 ; 81 134 | add R0, R0, R0 ; 82 135 | add R0, R0, #15 ; 83 136 | add R0, R0, #15 ; 84 137 | add R0, R0, #15 ; 85 138 | add R0, R0, #15 ; 86 139 | add R0, R0, #13 ; 87 140 | add R0, R4, R0 ; 88 141 | ldr R3, R0, #0 ; 89 142 | str R3, R1, #0 ; 90 143 | add R0, R0, #1 ; 91 144 | add R1, R1, #1 ; 92 145 | add R2, R2, #-1 ; 93 146 | brp #-6 ; 94 147 | and R3, R3, #0 ; 95 148 | ;; i: 4, j: 96, IR: ((3, 'msg'), 'print') 149 | add R2, R0, #0 ; 96 150 | add R0, R5, #0 ; 97 151 | ldr R0, R0, #0 ; 98 152 | puts ; 99 153 | add R0, R2, #0 ; 100 154 | ;; i: 5, j: 101, IR: ([(0, 92), (3, 'str')], '__array_assign__') 155 | add R0, R3, #11 ; 101 156 | add R0, R0, R0 ; 102 157 | add R0, R0, R0 ; 103 158 | add R0, R0, R0 ; 104 159 | add R0, R0, #4 ; 105 160 | not R1, R0 ; 106 161 | add R6, R6, R1 ; 107 162 | str R0, R6, #0 ; 108 163 | add R0, R5, #-3 ; 109 164 | add R1, R6, #1 ; 110 165 | str R1, R0, #0 ; 111 166 | ;; i: 6, j: 112, IR: ([(0, 0), (3, 'done')], '=') 167 | add R0, R3, #0 ; 112 168 | add R1, R5, #-4 ; 113 169 | str R0, R1, #0 ; 114 170 | ;; i: 7, j: 115, IR: ([(3, 'done')], 'not') 171 | add R0, R5, #-4 ; 115 172 | ldr R0, R0, #0 ; 116 173 | add R0, R0, #0 ; 117 174 | brz #2 ; 118 175 | add R0, R3, #0 ; 119 176 | brnzp #1 ; 120 177 | add R0, R3, #1 ; 121 178 | ;; i: 8, j: 122, IR: ((8, '$'), '__load_cc__') 179 | add R0, R0, #0 ; 122 180 | ;; i: 9, j: 123, IR: ('COND_179_1_ln_21', '__cond_branch__') 181 | brnp #2 ; 123 182 | ldr R0, R4, #7 ; 124 183 | jmp R0 ; 125 184 | ;; i: 10, j: 126, IR: ((3, 'prompt'), 'print') 185 | add R2, R0, #0 ; 126 186 | add R0, R5, #-1 ; 127 187 | ldr R0, R0, #0 ; 128 188 | puts ; 129 189 | add R0, R2, #0 ; 130 190 | ;; i: 11, j: 131, IR: ([(0, 0), (3, 'i')], '=') 191 | add R0, R3, #0 ; 131 192 | add R1, R5, #-5 ; 132 193 | str R0, R1, #0 ; 133 194 | ;; i: 12, j: 134, IR: (None, 'getc') 195 | getc ; 134 196 | ;; i: 13, j: 135, IR: ([(8, '$'), (3, 'c')], '=') 197 | add R1, R5, #-6 ; 135 198 | str R0, R1, #0 ; 136 199 | ;; i: 14, j: 137, IR: ((3, 'c'), 'outc') 200 | add R2, R0, #0 ; 137 201 | add R0, R5, #-6 ; 138 202 | ldr R0, R0, #0 ; 139 203 | out ; 140 204 | add R0, R2, #0 ; 141 205 | ;; i: 15, j: 142, IR: ([(0, 59), (3, 'c')], '==') 206 | add R0, R5, #-6 ; 142 207 | ldr R0, R0, #0 ; 143 208 | add R1, R3, #14 ; 144 209 | add R1, R1, R1 ; 145 210 | add R1, R1, R1 ; 146 211 | add R1, R1, #3 ; 147 212 | not R1, R1 ; 148 213 | add R1, R1, #1 ; 149 214 | add R0, R0, R1 ; 150 215 | brnp #2 ; 151 216 | add R0, R3, #1 ; 152 217 | brnzp #1 ; 153 218 | add R0, R3, #0 ; 154 219 | ;; i: 16, j: 155, IR: ([(0, 113), (3, 'c')], '==') 220 | add R6, R6, #-1 ; 155 221 | str R0, R6, #0 ; 156 222 | add R0, R5, #-6 ; 157 223 | ldr R0, R0, #0 ; 158 224 | add R1, R3, #14 ; 159 225 | add R1, R1, R1 ; 160 226 | add R1, R1, R1 ; 161 227 | add R1, R1, R1 ; 162 228 | add R1, R1, #1 ; 163 229 | not R1, R1 ; 164 230 | add R1, R1, #1 ; 165 231 | add R0, R0, R1 ; 166 232 | brnp #2 ; 167 233 | add R0, R3, #1 ; 168 234 | brnzp #1 ; 169 235 | add R0, R3, #0 ; 170 236 | ;; i: 17, j: 171, IR: ([(8, '$'), (8, '$')], 'or') 237 | ldr R1, R6, #0 ; 171 238 | add R6, R6, #1 ; 172 239 | add R0, R0, #0 ; 173 240 | brnp #1 ; 174 241 | add R0, R1, #0 ; 175 242 | ;; i: 18, j: 176, IR: ([(8, '$')], 'not') 243 | add R0, R0, #0 ; 176 244 | brz #2 ; 177 245 | add R0, R3, #0 ; 178 246 | brnzp #1 ; 179 247 | add R0, R3, #1 ; 180 248 | ;; i: 19, j: 181, IR: ([(0, 90), (3, 'i')], '<') 249 | add R6, R6, #-1 ; 181 250 | str R0, R6, #0 ; 182 251 | add R0, R5, #-5 ; 183 252 | ldr R0, R0, #0 ; 184 253 | add R1, R3, #11 ; 185 254 | add R1, R1, R1 ; 186 255 | add R1, R1, R1 ; 187 256 | add R1, R1, R1 ; 188 257 | add R1, R1, #2 ; 189 258 | not R1, R1 ; 190 259 | add R1, R1, #1 ; 191 260 | add R0, R0, R1 ; 192 261 | brn #1 ; 193 262 | add R0, R3, #0 ; 194 263 | ;; i: 20, j: 195, IR: ([(8, '$'), (8, '$')], 'and') 264 | ldr R1, R6, #0 ; 195 265 | add R6, R6, #1 ; 196 266 | add R0, R0, #0 ; 197 267 | brz #1 ; 198 268 | add R0, R1, #0 ; 199 269 | ;; i: 21, j: 200, IR: ((8, '$'), '__load_cc__') 270 | add R0, R0, #0 ; 200 271 | ;; i: 22, j: 201, IR: ('COND_410_3_ln_28', '__cond_branch__') 272 | brnp #2 ; 201 273 | ldr R0, R4, #2 ; 202 274 | jmp R0 ; 203 275 | ;; i: 23, j: 204, IR: ([(3, 'i'), (3, 'str')], '+') 276 | add R0, R5, #-3 ; 204 277 | ldr R0, R0, #0 ; 205 278 | add R1, R5, #-5 ; 206 279 | ldr R1, R1, #0 ; 207 280 | add R0, R0, R1 ; 208 281 | ;; i: 24, j: 209, IR: ([(3, 'c'), (8, '$')], '__mem_assign__') 282 | add R1, R5, #-6 ; 209 283 | ldr R1, R1, #0 ; 210 284 | str R1, R0, #0 ; 211 285 | ;; i: 25, j: 212, IR: ([(0, 1), (3, 'i')], '+') 286 | add R0, R5, #-5 ; 212 287 | ldr R0, R0, #0 ; 213 288 | add R1, R3, #1 ; 214 289 | add R0, R0, R1 ; 215 290 | ;; i: 26, j: 216, IR: ([(8, '$'), (3, 'i')], '=') 291 | add R1, R5, #-5 ; 216 292 | str R0, R1, #0 ; 217 293 | ;; i: 27, j: 218, IR: (None, 'getc') 294 | getc ; 218 295 | ;; i: 28, j: 219, IR: ([(8, '$'), (3, 'c')], '=') 296 | add R1, R5, #-6 ; 219 297 | str R0, R1, #0 ; 220 298 | ;; i: 29, j: 221, IR: ((3, 'c'), 'outc') 299 | add R2, R0, #0 ; 221 300 | add R0, R5, #-6 ; 222 301 | ldr R0, R0, #0 ; 223 302 | out ; 224 303 | add R0, R2, #0 ; 225 304 | ;; i: 30, j: 226, IR: ('COND_959_2_ln_28', '__branch__') 305 | ldr R0, R4, #1 ; 226 306 | jmp R0 ; 227 307 | ;; i: 31, j: 228, IR: ((0, 10), 'outc') 308 | add R2, R0, #0 ; 228 309 | add R0, R3, #10 ; 229 310 | out ; 230 311 | add R0, R2, #0 ; 231 312 | ;; i: 32, j: 232, IR: ([(0, 113), (3, 'c')], '==') 313 | add R0, R5, #-6 ; 232 314 | ldr R0, R0, #0 ; 233 315 | add R1, R3, #14 ; 234 316 | add R1, R1, R1 ; 235 317 | add R1, R1, R1 ; 236 318 | add R1, R1, R1 ; 237 319 | add R1, R1, #1 ; 238 320 | not R1, R1 ; 239 321 | add R1, R1, #1 ; 240 322 | add R0, R0, R1 ; 241 323 | brnp #2 ; 242 324 | add R0, R3, #1 ; 243 325 | brnzp #1 ; 244 326 | add R0, R3, #0 ; 245 327 | ;; i: 33, j: 246, IR: ([(8, '$')], 'not') 328 | add R0, R0, #0 ; 246 329 | brz #2 ; 247 330 | add R0, R3, #0 ; 248 331 | brnzp #1 ; 249 332 | add R0, R3, #1 ; 250 333 | ;; i: 34, j: 251, IR: ((8, '$'), '__load_cc__') 334 | add R0, R0, #0 ; 251 335 | ;; i: 35, j: 252, IR: ('COND_24_4_ln_37', '__cond_branch__') 336 | brnp #2 ; 252 337 | ldr R0, R4, #5 ; 253 338 | jmp R0 ; 254 339 | ;; i: 36, j: 255, IR: ([(3, 'i'), (3, 'str')], '+') 340 | add R0, R5, #-3 ; 255 341 | ldr R0, R0, #0 ; 256 342 | add R1, R5, #-5 ; 257 343 | ldr R1, R1, #0 ; 258 344 | add R0, R0, R1 ; 259 345 | ;; i: 37, j: 260, IR: ([(0, 59), (8, '$')], '__mem_assign__') 346 | add R1, R3, #14 ; 260 347 | add R1, R1, R1 ; 261 348 | add R1, R1, R1 ; 262 349 | add R1, R1, #3 ; 263 350 | str R1, R0, #0 ; 264 351 | ;; i: 38, j: 265, IR: ([(3, 'i'), (3, 'str')], '+') 352 | add R0, R5, #-3 ; 265 353 | ldr R0, R0, #0 ; 266 354 | add R1, R5, #-5 ; 267 355 | ldr R1, R1, #0 ; 268 356 | add R0, R0, R1 ; 269 357 | ;; i: 39, j: 270, IR: ([(0, 1), (8, '$')], '+') 358 | add R1, R3, #1 ; 270 359 | add R0, R0, R1 ; 271 360 | ;; i: 40, j: 272, IR: ([(0, 0), (8, '$')], '__mem_assign__') 361 | add R1, R3, #0 ; 272 362 | str R1, R0, #0 ; 273 363 | ;; i: 41, j: 274, IR: ([(3, 'str')], '__push__') 364 | add R6, R6, #-1 ; 274 365 | add R0, R5, #-3 ; 275 366 | ldr R0, R0, #0 ; 276 367 | str R0, R6, #0 ; 277 368 | ;; i: 42, j: 278, IR: ('F_eval', '__jump_to_routine___') 369 | ldr R0, R4, #8 ; 278 370 | jsrr R0 ; 279 371 | ;; i: 43, j: 280, IR: ([(3, 'str')], '__fetch_return_value__') 372 | ldr R0, R6, #0 ; 280 373 | add R6, R6, #2 ; 281 374 | ;; i: 44, j: 282, IR: ([(8, '$'), (3, 'a')], '=') 375 | add R1, R5, #-7 ; 282 376 | str R0, R1, #0 ; 283 377 | ;; i: 45, j: 284, IR: ((3, 'output'), 'print') 378 | add R2, R0, #0 ; 284 379 | add R0, R5, #-2 ; 285 380 | ldr R0, R0, #0 ; 286 381 | puts ; 287 382 | add R0, R2, #0 ; 288 383 | ;; i: 46, j: 289, IR: ([(0, 10000), (3, 'i')], '=') 384 | add R0, R3, #9 ; 289 385 | add R0, R0, R0 ; 290 386 | add R0, R0, R0 ; 291 387 | add R0, R0, R0 ; 292 388 | add R0, R0, R0 ; 293 389 | add R0, R0, #12 ; 294 390 | add R0, R0, R0 ; 295 391 | add R0, R0, R0 ; 296 392 | add R0, R0, R0 ; 297 393 | add R0, R0, R0 ; 298 394 | add R0, R0, R0 ; 299 395 | add R0, R0, #8 ; 300 396 | add R0, R0, R0 ; 301 397 | add R1, R5, #-5 ; 302 398 | str R0, R1, #0 ; 303 399 | ;; i: 47, j: 304, IR: ([(0, 0), (3, 'div')], '=') 400 | add R0, R3, #0 ; 304 401 | add R1, R5, #-8 ; 305 402 | str R0, R1, #0 ; 306 403 | ;; i: 48, j: 307, IR: ((3, 'i'), '__load_cc__') 404 | add R0, R5, #-5 ; 307 405 | ldr R0, R0, #0 ; 308 406 | ;; i: 49, j: 309, IR: ('COND_84_6_ln_49', '__cond_branch__') 407 | brnp #2 ; 309 408 | ldr R0, R4, #4 ; 310 409 | jmp R0 ; 311 410 | ;; i: 50, j: 312, IR: ([(3, 'i'), (3, 'a')], '/') 411 | add R0, R5, #-7 ; 312 412 | ldr R0, R0, #0 ; 313 413 | add R1, R5, #-5 ; 314 414 | ldr R1, R1, #0 ; 315 415 | add R1, R1, #0 ; 316 416 | brz #34 ; 317 417 | brn #3 ; 318 418 | add R0, R0, #0 ; 319 419 | brn #17 ; 320 420 | brnzp #6 ; 321 421 | add R0, R0, #0 ; 322 422 | brzp #14 ; 323 423 | not R0, R0 ; 324 424 | add R0, R0, #1 ; 325 425 | not R1, R1 ; 326 426 | add R1, R1, #1 ; 327 427 | add R2, R3, #0 ; 328 428 | not R1, R1 ; 329 429 | add R1, R1, #1 ; 330 430 | add R0, R0, #0 ; 331 431 | brn #3 ; 332 432 | add R2, R2, #1 ; 333 433 | add R0, R0, R1 ; 334 434 | brzp #-3 ; 335 435 | add R0, R2, #-1 ; 336 436 | brnzp #14 ; 337 437 | add R1, R1, #0 ; 338 438 | brn #4 ; 339 439 | not R0, R0 ; 340 440 | add R0, R0, #1 ; 341 441 | not R1, R1 ; 342 442 | add R1, R1, #1 ; 343 443 | add R2, R3, #0 ; 344 444 | add R0, R0, #0 ; 345 445 | brn #3 ; 346 446 | add R2, R2, #1 ; 347 447 | add R0, R0, R1 ; 348 448 | brzp #-3 ; 349 449 | not R2, R2 ; 350 450 | add R0, R2, #2 ; 351 451 | ;; i: 51, j: 352, IR: ([(8, '$'), (3, 'div')], '=') 452 | add R1, R5, #-8 ; 352 453 | str R0, R1, #0 ; 353 454 | ;; i: 52, j: 354, IR: ([(0, 48), (3, 'div')], '+') 455 | add R0, R5, #-8 ; 354 456 | ldr R0, R0, #0 ; 355 457 | add R1, R3, #12 ; 356 458 | add R1, R1, R1 ; 357 459 | add R1, R1, R1 ; 358 460 | add R0, R0, R1 ; 359 461 | ;; i: 53, j: 360, IR: ((8, '$'), 'outc') 462 | add R2, R0, #0 ; 360 463 | out ; 361 464 | add R0, R2, #0 ; 362 465 | ;; i: 54, j: 363, IR: (None, '__pop__') 466 | ;; i: 55, j: 363, IR: ([(3, 'i'), (3, 'div')], '*') 467 | add R0, R5, #-8 ; 363 468 | ldr R0, R0, #0 ; 364 469 | add R1, R5, #-5 ; 365 470 | ldr R1, R1, #0 ; 366 471 | add R1, R1, #0 ; 367 472 | brzp #4 ; 368 473 | not R1, R1 ; 369 474 | add R1, R1, #1 ; 370 475 | not R0, R0 ; 371 476 | add R0, R0, #1 ; 372 477 | and R2, R3, #0 ; 373 478 | add R1, R1, #0 ; 374 479 | brnz #3 ; 375 480 | add R2, R2, R0 ; 376 481 | add R1, R1, #-1 ; 377 482 | brp #-3 ; 378 483 | add R0, R2, #0 ; 379 484 | ;; i: 56, j: 380, IR: ([(8, '$'), (3, 'a')], '-') 485 | add R1, R0, #0 ; 380 486 | add R0, R5, #-7 ; 381 487 | ldr R0, R0, #0 ; 382 488 | not R1, R1 ; 383 489 | add R1, R1, #1 ; 384 490 | add R0, R0, R1 ; 385 491 | ;; i: 57, j: 386, IR: ([(8, '$'), (3, 'a')], '=') 492 | add R1, R5, #-7 ; 386 493 | str R0, R1, #0 ; 387 494 | ;; i: 58, j: 388, IR: ([(0, 10), (3, 'i')], '/') 495 | add R0, R5, #-5 ; 388 496 | ldr R0, R0, #0 ; 389 497 | add R1, R3, #10 ; 390 498 | add R1, R1, #0 ; 391 499 | brz #34 ; 392 500 | brn #3 ; 393 501 | add R0, R0, #0 ; 394 502 | brn #17 ; 395 503 | brnzp #6 ; 396 504 | add R0, R0, #0 ; 397 505 | brzp #14 ; 398 506 | not R0, R0 ; 399 507 | add R0, R0, #1 ; 400 508 | not R1, R1 ; 401 509 | add R1, R1, #1 ; 402 510 | add R2, R3, #0 ; 403 511 | not R1, R1 ; 404 512 | add R1, R1, #1 ; 405 513 | add R0, R0, #0 ; 406 514 | brn #3 ; 407 515 | add R2, R2, #1 ; 408 516 | add R0, R0, R1 ; 409 517 | brzp #-3 ; 410 518 | add R0, R2, #-1 ; 411 519 | brnzp #14 ; 412 520 | add R1, R1, #0 ; 413 521 | brn #4 ; 414 522 | not R0, R0 ; 415 523 | add R0, R0, #1 ; 416 524 | not R1, R1 ; 417 525 | add R1, R1, #1 ; 418 526 | add R2, R3, #0 ; 419 527 | add R0, R0, #0 ; 420 528 | brn #3 ; 421 529 | add R2, R2, #1 ; 422 530 | add R0, R0, R1 ; 423 531 | brzp #-3 ; 424 532 | not R2, R2 ; 425 533 | add R0, R2, #2 ; 426 534 | ;; i: 59, j: 427, IR: ([(8, '$'), (3, 'i')], '=') 535 | add R1, R5, #-5 ; 427 536 | str R0, R1, #0 ; 428 537 | ;; i: 60, j: 429, IR: ('COND_601_5_ln_49', '__branch__') 538 | ldr R0, R4, #3 ; 429 539 | jmp R0 ; 430 540 | ;; i: 61, j: 431, IR: ('END_COND_24_4_ln_37', '__branch__') 541 | ldr R0, R4, #6 ; 431 542 | jmp R0 ; 432 543 | ;; i: 62, j: 433, IR: ([(0, 1), (3, 'done')], '=') 544 | add R0, R3, #1 ; 433 545 | add R1, R5, #-4 ; 434 546 | str R0, R1, #0 ; 435 547 | ;; i: 63, j: 436, IR: ('COND_222_0_ln_21', '__branch__') 548 | ldr R0, R4, #0 ; 436 549 | jmp R0 ; 437 550 | ;; i: 64, j: 438, IR: (['msg', 'prompt', 'output', 'str', 'done', 'i', 'c', 'a', 'div'], '__clean_main__') 551 | add R6, R5, #1 ; 438 552 | ;; i: 65, j: 439, IR: (None, '__halt__') 553 | halt ; 439 554 | ;; i: 66, j: 440, IR: (('eval', ['str']), '__setup_func__') 555 | add R6, R6, #-3 ; 440 556 | str R5, R6, #0 ; 441 557 | str R7, R6, #1 ; 442 558 | add R5, R6, #-1 ; 443 559 | add R6, R6, #-14 ; 444 560 | ;; i: 67, j: 445, IR: ([(0, 10), (3, 'num_stack')], '__array_assign__') 561 | add R0, R3, #10 ; 445 562 | not R1, R0 ; 446 563 | add R6, R6, R1 ; 447 564 | str R0, R6, #0 ; 448 565 | add R0, R5, #0 ; 449 566 | add R1, R6, #1 ; 450 567 | str R1, R0, #0 ; 451 568 | ;; i: 68, j: 452, IR: ([(0, 10), (3, 'op_stack')], '__array_assign__') 569 | add R0, R3, #10 ; 452 570 | not R1, R0 ; 453 571 | add R6, R6, R1 ; 454 572 | str R0, R6, #0 ; 455 573 | add R0, R5, #-1 ; 456 574 | add R1, R6, #1 ; 457 575 | str R1, R0, #0 ; 458 576 | ;; i: 69, j: 459, IR: ([(0, 1)], 'um') 577 | add R0, R3, #-1 ; 459 578 | ;; i: 70, j: 460, IR: ([(8, '$'), (3, 'ntop')], '=') 579 | add R1, R5, #-2 ; 460 580 | str R0, R1, #0 ; 461 581 | ;; i: 71, j: 462, IR: ([(0, 1)], 'um') 582 | add R0, R3, #-1 ; 462 583 | ;; i: 72, j: 463, IR: ([(8, '$'), (3, 'otop')], '=') 584 | add R1, R5, #-3 ; 463 585 | str R0, R1, #0 ; 464 586 | ;; i: 73, j: 465, IR: ([(0, 1)], 'um') 587 | add R0, R3, #-1 ; 465 588 | ;; i: 74, j: 466, IR: ([(8, '$'), (3, 'sl')], '=') 589 | add R1, R5, #-4 ; 466 590 | str R0, R1, #0 ; 467 591 | ;; i: 75, j: 468, IR: ([(0, 15), (3, 'tokens')], '__array_assign__') 592 | add R0, R3, #15 ; 468 593 | not R1, R0 ; 469 594 | add R6, R6, R1 ; 470 595 | str R0, R6, #0 ; 471 596 | add R0, R5, #-5 ; 472 597 | add R1, R6, #1 ; 473 598 | str R1, R0, #0 ; 474 599 | ;; i: 76, j: 475, IR: ([(0, 0), (3, 'i')], '=') 600 | add R0, R3, #0 ; 475 601 | add R1, R5, #-6 ; 476 602 | str R0, R1, #0 ; 477 603 | ;; i: 77, j: 478, IR: ([(3, 'i'), (3, 'str')], '+') 604 | add R0, R5, #4 ; 478 605 | ldr R0, R0, #0 ; 479 606 | add R1, R5, #-6 ; 480 607 | ldr R1, R1, #0 ; 481 608 | add R0, R0, R1 ; 482 609 | ;; i: 78, j: 483, IR: ((8, '$'), 'mem') 610 | ldr R0, R0, #0 ; 483 611 | ;; i: 79, j: 484, IR: ([(8, '$'), (3, 'c')], '=') 612 | add R1, R5, #-7 ; 484 613 | str R0, R1, #0 ; 485 614 | ;; i: 80, j: 486, IR: ((3, 'c'), '__load_cc__') 615 | add R0, R5, #-7 ; 486 616 | ldr R0, R0, #0 ; 487 617 | ;; i: 81, j: 488, IR: ('COND_935_9_ln_80', '__cond_branch__') 618 | brnp #2 ; 488 619 | ldr R0, R4, #17 ; 489 620 | jmp R0 ; 490 621 | ;; i: 82, j: 491, IR: ([(0, 48), (3, 'c')], '>=') 622 | add R0, R5, #-7 ; 491 623 | ldr R0, R0, #0 ; 492 624 | add R1, R3, #12 ; 493 625 | add R1, R1, R1 ; 494 626 | add R1, R1, R1 ; 495 627 | not R1, R1 ; 496 628 | add R1, R1, #1 ; 497 629 | add R0, R0, R1 ; 498 630 | brzp #2 ; 499 631 | add R0, R3, #0 ; 500 632 | brnzp #1 ; 501 633 | add R0, R3, #1 ; 502 634 | ;; i: 83, j: 503, IR: ([(0, 57), (3, 'c')], '<=') 635 | add R6, R6, #-1 ; 503 636 | str R0, R6, #0 ; 504 637 | add R0, R5, #-7 ; 505 638 | ldr R0, R0, #0 ; 506 639 | add R1, R3, #14 ; 507 640 | add R1, R1, R1 ; 508 641 | add R1, R1, R1 ; 509 642 | add R1, R1, #1 ; 510 643 | not R1, R1 ; 511 644 | add R1, R1, #1 ; 512 645 | add R0, R0, R1 ; 513 646 | brnz #2 ; 514 647 | add R0, R3, #0 ; 515 648 | brnzp #1 ; 516 649 | add R0, R3, #1 ; 517 650 | ;; i: 84, j: 518, IR: ([(8, '$'), (8, '$')], 'and') 651 | ldr R1, R6, #0 ; 518 652 | add R6, R6, #1 ; 519 653 | add R0, R0, #0 ; 520 654 | brz #1 ; 521 655 | add R0, R1, #0 ; 522 656 | ;; i: 85, j: 523, IR: ((8, '$'), '__load_cc__') 657 | add R0, R0, #0 ; 523 658 | ;; i: 86, j: 524, IR: ('COND_168_10_ln_81', '__cond_branch__') 659 | brnp #2 ; 524 660 | ldr R0, R4, #12 ; 525 661 | jmp R0 ; 526 662 | ;; i: 87, j: 527, IR: ([(0, 48), (3, 'c')], '-') 663 | add R0, R5, #-7 ; 527 664 | ldr R0, R0, #0 ; 528 665 | add R1, R3, #12 ; 529 666 | add R1, R1, R1 ; 530 667 | add R1, R1, R1 ; 531 668 | not R1, R1 ; 532 669 | add R1, R1, #1 ; 533 670 | add R0, R0, R1 ; 534 671 | ;; i: 88, j: 535, IR: ([(8, '$'), (3, 'num')], '=') 672 | add R1, R5, #-8 ; 535 673 | str R0, R1, #0 ; 536 674 | ;; i: 89, j: 537, IR: ([(0, 1), (3, 'i')], '+') 675 | add R0, R5, #-6 ; 537 676 | ldr R0, R0, #0 ; 538 677 | add R1, R3, #1 ; 539 678 | add R0, R0, R1 ; 540 679 | ;; i: 90, j: 541, IR: ([(8, '$'), (3, 'i')], '=') 680 | add R1, R5, #-6 ; 541 681 | str R0, R1, #0 ; 542 682 | ;; i: 91, j: 543, IR: ([(3, 'i'), (3, 'str')], '+') 683 | add R0, R5, #4 ; 543 684 | ldr R0, R0, #0 ; 544 685 | add R1, R5, #-6 ; 545 686 | ldr R1, R1, #0 ; 546 687 | add R0, R0, R1 ; 547 688 | ;; i: 92, j: 548, IR: ((8, '$'), 'mem') 689 | ldr R0, R0, #0 ; 548 690 | ;; i: 93, j: 549, IR: ([(8, '$'), (3, 'c')], '=') 691 | add R1, R5, #-7 ; 549 692 | str R0, R1, #0 ; 550 693 | ;; i: 94, j: 551, IR: ([(0, 48), (3, 'c')], '>=') 694 | add R0, R5, #-7 ; 551 695 | ldr R0, R0, #0 ; 552 696 | add R1, R3, #12 ; 553 697 | add R1, R1, R1 ; 554 698 | add R1, R1, R1 ; 555 699 | not R1, R1 ; 556 700 | add R1, R1, #1 ; 557 701 | add R0, R0, R1 ; 558 702 | brzp #2 ; 559 703 | add R0, R3, #0 ; 560 704 | brnzp #1 ; 561 705 | add R0, R3, #1 ; 562 706 | ;; i: 95, j: 563, IR: ([(0, 57), (3, 'c')], '<=') 707 | add R6, R6, #-1 ; 563 708 | str R0, R6, #0 ; 564 709 | add R0, R5, #-7 ; 565 710 | ldr R0, R0, #0 ; 566 711 | add R1, R3, #14 ; 567 712 | add R1, R1, R1 ; 568 713 | add R1, R1, R1 ; 569 714 | add R1, R1, #1 ; 570 715 | not R1, R1 ; 571 716 | add R1, R1, #1 ; 572 717 | add R0, R0, R1 ; 573 718 | brnz #2 ; 574 719 | add R0, R3, #0 ; 575 720 | brnzp #1 ; 576 721 | add R0, R3, #1 ; 577 722 | ;; i: 96, j: 578, IR: ([(8, '$'), (8, '$')], 'and') 723 | ldr R1, R6, #0 ; 578 724 | add R6, R6, #1 ; 579 725 | add R0, R0, #0 ; 580 726 | brz #1 ; 581 727 | add R0, R1, #0 ; 582 728 | ;; i: 97, j: 583, IR: ((8, '$'), '__load_cc__') 729 | add R0, R0, #0 ; 583 730 | ;; i: 98, j: 584, IR: ('COND_375_12_ln_87', '__cond_branch__') 731 | brnp #2 ; 584 732 | ldr R0, R4, #11 ; 585 733 | jmp R0 ; 586 734 | ;; i: 99, j: 587, IR: ([(0, 10), (3, 'num')], '*') 735 | add R0, R5, #-8 ; 587 736 | ldr R0, R0, #0 ; 588 737 | add R1, R3, #10 ; 589 738 | add R1, R1, #0 ; 590 739 | brzp #4 ; 591 740 | not R1, R1 ; 592 741 | add R1, R1, #1 ; 593 742 | not R0, R0 ; 594 743 | add R0, R0, #1 ; 595 744 | and R2, R3, #0 ; 596 745 | add R1, R1, #0 ; 597 746 | brnz #3 ; 598 747 | add R2, R2, R0 ; 599 748 | add R1, R1, #-1 ; 600 749 | brp #-3 ; 601 750 | add R0, R2, #0 ; 602 751 | ;; i: 100, j: 603, IR: ([(0, 48), (3, 'c')], '-') 752 | add R6, R6, #-1 ; 603 753 | str R0, R6, #0 ; 604 754 | add R0, R5, #-7 ; 605 755 | ldr R0, R0, #0 ; 606 756 | add R1, R3, #12 ; 607 757 | add R1, R1, R1 ; 608 758 | add R1, R1, R1 ; 609 759 | not R1, R1 ; 610 760 | add R1, R1, #1 ; 611 761 | add R0, R0, R1 ; 612 762 | ;; i: 101, j: 613, IR: ([(8, '$'), (8, '$')], '+') 763 | ldr R1, R6, #0 ; 613 764 | add R6, R6, #1 ; 614 765 | add R0, R0, R1 ; 615 766 | ;; i: 102, j: 616, IR: ([(8, '$'), (3, 'num')], '=') 767 | add R1, R5, #-8 ; 616 768 | str R0, R1, #0 ; 617 769 | ;; i: 103, j: 618, IR: ([(0, 1), (3, 'i')], '+') 770 | add R0, R5, #-6 ; 618 771 | ldr R0, R0, #0 ; 619 772 | add R1, R3, #1 ; 620 773 | add R0, R0, R1 ; 621 774 | ;; i: 104, j: 622, IR: ([(8, '$'), (3, 'i')], '=') 775 | add R1, R5, #-6 ; 622 776 | str R0, R1, #0 ; 623 777 | ;; i: 105, j: 624, IR: ([(3, 'i'), (3, 'str')], '+') 778 | add R0, R5, #4 ; 624 779 | ldr R0, R0, #0 ; 625 780 | add R1, R5, #-6 ; 626 781 | ldr R1, R1, #0 ; 627 782 | add R0, R0, R1 ; 628 783 | ;; i: 106, j: 629, IR: ((8, '$'), 'mem') 784 | ldr R0, R0, #0 ; 629 785 | ;; i: 107, j: 630, IR: ([(8, '$'), (3, 'c')], '=') 786 | add R1, R5, #-7 ; 630 787 | str R0, R1, #0 ; 631 788 | ;; i: 108, j: 632, IR: ('COND_94_11_ln_87', '__branch__') 789 | ldr R0, R4, #10 ; 632 790 | jmp R0 ; 633 791 | ;; i: 109, j: 634, IR: ([(0, 1), (3, 'sl')], '+') 792 | add R0, R5, #-4 ; 634 793 | ldr R0, R0, #0 ; 635 794 | add R1, R3, #1 ; 636 795 | add R0, R0, R1 ; 637 796 | ;; i: 110, j: 638, IR: ([(8, '$'), (3, 'sl')], '=') 797 | add R1, R5, #-4 ; 638 798 | str R0, R1, #0 ; 639 799 | ;; i: 111, j: 640, IR: ([(3, 'sl'), (3, 'tokens')], '+') 800 | add R0, R5, #-5 ; 640 801 | ldr R0, R0, #0 ; 641 802 | add R1, R5, #-4 ; 642 803 | ldr R1, R1, #0 ; 643 804 | add R0, R0, R1 ; 644 805 | ;; i: 112, j: 645, IR: ([(3, 'num'), (8, '$')], '__mem_assign__') 806 | add R1, R5, #-8 ; 645 807 | ldr R1, R1, #0 ; 646 808 | str R1, R0, #0 ; 647 809 | ;; i: 113, j: 648, IR: ('END_COND_168_10_ln_81', '__branch__') 810 | ldr R0, R4, #16 ; 648 811 | jmp R0 ; 649 812 | ;; i: 114, j: 650, IR: ([(0, 43), (3, 'c')], '==') 813 | add R0, R5, #-7 ; 650 814 | ldr R0, R0, #0 ; 651 815 | add R1, R3, #10 ; 652 816 | add R1, R1, R1 ; 653 817 | add R1, R1, R1 ; 654 818 | add R1, R1, #3 ; 655 819 | not R1, R1 ; 656 820 | add R1, R1, #1 ; 657 821 | add R0, R0, R1 ; 658 822 | brnp #2 ; 659 823 | add R0, R3, #1 ; 660 824 | brnzp #1 ; 661 825 | add R0, R3, #0 ; 662 826 | ;; i: 115, j: 663, IR: ((8, '$'), '__load_cc__') 827 | add R0, R0, #0 ; 663 828 | ;; i: 116, j: 664, IR: ('COND_994_14_ln_98', '__cond_branch__') 829 | brnp #2 ; 664 830 | ldr R0, R4, #13 ; 665 831 | jmp R0 ; 666 832 | ;; i: 117, j: 667, IR: ([(0, 1), (3, 'sl')], '+') 833 | add R0, R5, #-4 ; 667 834 | ldr R0, R0, #0 ; 668 835 | add R1, R3, #1 ; 669 836 | add R0, R0, R1 ; 670 837 | ;; i: 118, j: 671, IR: ([(8, '$'), (3, 'sl')], '=') 838 | add R1, R5, #-4 ; 671 839 | str R0, R1, #0 ; 672 840 | ;; i: 119, j: 673, IR: ([(3, 'sl'), (3, 'tokens')], '+') 841 | add R0, R5, #-5 ; 673 842 | ldr R0, R0, #0 ; 674 843 | add R1, R5, #-4 ; 675 844 | ldr R1, R1, #0 ; 676 845 | add R0, R0, R1 ; 677 846 | ;; i: 120, j: 678, IR: ([(0, 2)], 'um') 847 | add R6, R6, #-1 ; 678 848 | str R0, R6, #0 ; 679 849 | add R0, R3, #-2 ; 680 850 | ;; i: 121, j: 681, IR: ([(8, '$'), (8, '$')], '__mem_assign__') 851 | add R1, R0, #0 ; 681 852 | ldr R0, R6, #0 ; 682 853 | add R6, R6, #1 ; 683 854 | str R1, R0, #0 ; 684 855 | ;; i: 122, j: 685, IR: ([(0, 1), (3, 'i')], '+') 856 | add R0, R5, #-6 ; 685 857 | ldr R0, R0, #0 ; 686 858 | add R1, R3, #1 ; 687 859 | add R0, R0, R1 ; 688 860 | ;; i: 123, j: 689, IR: ([(8, '$'), (3, 'i')], '=') 861 | add R1, R5, #-6 ; 689 862 | str R0, R1, #0 ; 690 863 | ;; i: 124, j: 691, IR: ('END_COND_168_10_ln_81', '__branch__') 864 | ldr R0, R4, #16 ; 691 865 | jmp R0 ; 692 866 | ;; i: 125, j: 693, IR: ([(0, 42), (3, 'c')], '==') 867 | add R0, R5, #-7 ; 693 868 | ldr R0, R0, #0 ; 694 869 | add R1, R3, #10 ; 695 870 | add R1, R1, R1 ; 696 871 | add R1, R1, R1 ; 697 872 | add R1, R1, #2 ; 698 873 | not R1, R1 ; 699 874 | add R1, R1, #1 ; 700 875 | add R0, R0, R1 ; 701 876 | brnp #2 ; 702 877 | add R0, R3, #1 ; 703 878 | brnzp #1 ; 704 879 | add R0, R3, #0 ; 705 880 | ;; i: 126, j: 706, IR: ((8, '$'), '__load_cc__') 881 | add R0, R0, #0 ; 706 882 | ;; i: 127, j: 707, IR: ('COND_493_15_ln_102', '__cond_branch__') 883 | brnp #2 ; 707 884 | ldr R0, R4, #14 ; 708 885 | jmp R0 ; 709 886 | ;; i: 128, j: 710, IR: ([(0, 1), (3, 'sl')], '+') 887 | add R0, R5, #-4 ; 710 888 | ldr R0, R0, #0 ; 711 889 | add R1, R3, #1 ; 712 890 | add R0, R0, R1 ; 713 891 | ;; i: 129, j: 714, IR: ([(8, '$'), (3, 'sl')], '=') 892 | add R1, R5, #-4 ; 714 893 | str R0, R1, #0 ; 715 894 | ;; i: 130, j: 716, IR: ([(3, 'sl'), (3, 'tokens')], '+') 895 | add R0, R5, #-5 ; 716 896 | ldr R0, R0, #0 ; 717 897 | add R1, R5, #-4 ; 718 898 | ldr R1, R1, #0 ; 719 899 | add R0, R0, R1 ; 720 900 | ;; i: 131, j: 721, IR: ([(0, 1)], 'um') 901 | add R6, R6, #-1 ; 721 902 | str R0, R6, #0 ; 722 903 | add R0, R3, #-1 ; 723 904 | ;; i: 132, j: 724, IR: ([(8, '$'), (8, '$')], '__mem_assign__') 905 | add R1, R0, #0 ; 724 906 | ldr R0, R6, #0 ; 725 907 | add R6, R6, #1 ; 726 908 | str R1, R0, #0 ; 727 909 | ;; i: 133, j: 728, IR: ([(0, 1), (3, 'i')], '+') 910 | add R0, R5, #-6 ; 728 911 | ldr R0, R0, #0 ; 729 912 | add R1, R3, #1 ; 730 913 | add R0, R0, R1 ; 731 914 | ;; i: 134, j: 732, IR: ([(8, '$'), (3, 'i')], '=') 915 | add R1, R5, #-6 ; 732 916 | str R0, R1, #0 ; 733 917 | ;; i: 135, j: 734, IR: ('END_COND_168_10_ln_81', '__branch__') 918 | ldr R0, R4, #16 ; 734 919 | jmp R0 ; 735 920 | ;; i: 136, j: 736, IR: ([(0, 59), (3, 'c')], '==') 921 | add R0, R5, #-7 ; 736 922 | ldr R0, R0, #0 ; 737 923 | add R1, R3, #14 ; 738 924 | add R1, R1, R1 ; 739 925 | add R1, R1, R1 ; 740 926 | add R1, R1, #3 ; 741 927 | not R1, R1 ; 742 928 | add R1, R1, #1 ; 743 929 | add R0, R0, R1 ; 744 930 | brnp #2 ; 745 931 | add R0, R3, #1 ; 746 932 | brnzp #1 ; 747 933 | add R0, R3, #0 ; 748 934 | ;; i: 137, j: 749, IR: ((8, '$'), '__load_cc__') 935 | add R0, R0, #0 ; 749 936 | ;; i: 138, j: 750, IR: ('COND_19_16_ln_106', '__cond_branch__') 937 | brnp #2 ; 750 938 | ldr R0, R4, #15 ; 751 939 | jmp R0 ; 752 940 | ;; i: 139, j: 753, IR: ([(0, 1), (3, 'sl')], '+') 941 | add R0, R5, #-4 ; 753 942 | ldr R0, R0, #0 ; 754 943 | add R1, R3, #1 ; 755 944 | add R0, R0, R1 ; 756 945 | ;; i: 140, j: 757, IR: ([(8, '$'), (3, 'sl')], '=') 946 | add R1, R5, #-4 ; 757 947 | str R0, R1, #0 ; 758 948 | ;; i: 141, j: 759, IR: ([(3, 'sl'), (3, 'tokens')], '+') 949 | add R0, R5, #-5 ; 759 950 | ldr R0, R0, #0 ; 760 951 | add R1, R5, #-4 ; 761 952 | ldr R1, R1, #0 ; 762 953 | add R0, R0, R1 ; 763 954 | ;; i: 142, j: 764, IR: ([(0, 3)], 'um') 955 | add R6, R6, #-1 ; 764 956 | str R0, R6, #0 ; 765 957 | add R0, R3, #-3 ; 766 958 | ;; i: 143, j: 767, IR: ([(8, '$'), (8, '$')], '__mem_assign__') 959 | add R1, R0, #0 ; 767 960 | ldr R0, R6, #0 ; 768 961 | add R6, R6, #1 ; 769 962 | str R1, R0, #0 ; 770 963 | ;; i: 144, j: 771, IR: ([(0, 1), (3, 'i')], '+') 964 | add R0, R5, #-6 ; 771 965 | ldr R0, R0, #0 ; 772 966 | add R1, R3, #1 ; 773 967 | add R0, R0, R1 ; 774 968 | ;; i: 145, j: 775, IR: ([(8, '$'), (3, 'i')], '=') 969 | add R1, R5, #-6 ; 775 970 | str R0, R1, #0 ; 776 971 | ;; i: 146, j: 777, IR: ('END_COND_168_10_ln_81', '__branch__') 972 | ldr R0, R4, #16 ; 777 973 | jmp R0 ; 778 974 | ;; i: 147, j: 779, IR: ([(0, 1), (3, 'i')], '+') 975 | add R0, R5, #-6 ; 779 976 | ldr R0, R0, #0 ; 780 977 | add R1, R3, #1 ; 781 978 | add R0, R0, R1 ; 782 979 | ;; i: 148, j: 783, IR: ([(8, '$'), (3, 'i')], '=') 980 | add R1, R5, #-6 ; 783 981 | str R0, R1, #0 ; 784 982 | ;; i: 149, j: 785, IR: ([(3, 'i'), (3, 'str')], '+') 983 | add R0, R5, #4 ; 785 984 | ldr R0, R0, #0 ; 786 985 | add R1, R5, #-6 ; 787 986 | ldr R1, R1, #0 ; 788 987 | add R0, R0, R1 ; 789 988 | ;; i: 150, j: 790, IR: ((8, '$'), 'mem') 989 | ldr R0, R0, #0 ; 790 990 | ;; i: 151, j: 791, IR: ([(8, '$'), (3, 'c')], '=') 991 | add R1, R5, #-7 ; 791 992 | str R0, R1, #0 ; 792 993 | ;; i: 152, j: 793, IR: ('COND_563_8_ln_80', '__branch__') 994 | ldr R0, R4, #9 ; 793 995 | jmp R0 ; 794 996 | ;; i: 153, j: 795, IR: ([(0, 0), (3, 'i')], '=') 997 | add R0, R3, #0 ; 795 998 | add R1, R5, #-6 ; 796 999 | str R0, R1, #0 ; 797 1000 | ;; i: 154, j: 798, IR: ([(0, 0), (3, 'res')], '=') 1001 | add R0, R3, #0 ; 798 1002 | add R1, R5, #-9 ; 799 1003 | str R0, R1, #0 ; 800 1004 | ;; i: 155, j: 801, IR: ([(3, 'sl'), (3, 'i')], '<=') 1005 | add R0, R5, #-6 ; 801 1006 | ldr R0, R0, #0 ; 802 1007 | add R1, R5, #-4 ; 803 1008 | ldr R1, R1, #0 ; 804 1009 | not R1, R1 ; 805 1010 | add R1, R1, #1 ; 806 1011 | add R0, R0, R1 ; 807 1012 | brnz #2 ; 808 1013 | add R0, R3, #0 ; 809 1014 | brnzp #1 ; 810 1015 | add R0, R3, #1 ; 811 1016 | ;; i: 156, j: 812, IR: ((8, '$'), '__load_cc__') 1017 | add R0, R0, #0 ; 812 1018 | ;; i: 157, j: 813, IR: ('COND_118_17_ln_124', '__cond_branch__') 1019 | brnp #2 ; 813 1020 | ldr R0, R4, #24 ; 814 1021 | jmp R0 ; 815 1022 | ;; i: 158, j: 816, IR: ([(3, 'i'), (3, 'tokens')], '+') 1023 | add R0, R5, #-5 ; 816 1024 | ldr R0, R0, #0 ; 817 1025 | add R1, R5, #-6 ; 818 1026 | ldr R1, R1, #0 ; 819 1027 | add R0, R0, R1 ; 820 1028 | ;; i: 159, j: 821, IR: ((8, '$'), 'mem') 1029 | ldr R0, R0, #0 ; 821 1030 | ;; i: 160, j: 822, IR: ([(8, '$'), (3, 'curr')], '=') 1031 | add R1, R5, #-10 ; 822 1032 | str R0, R1, #0 ; 823 1033 | ;; i: 161, j: 824, IR: ([(0, 0), (3, 'curr')], '>=') 1034 | add R0, R5, #-10 ; 824 1035 | ldr R0, R0, #0 ; 825 1036 | add R1, R3, #0 ; 826 1037 | not R1, R1 ; 827 1038 | add R1, R1, #1 ; 828 1039 | add R0, R0, R1 ; 829 1040 | brzp #2 ; 830 1041 | add R0, R3, #0 ; 831 1042 | brnzp #1 ; 832 1043 | add R0, R3, #1 ; 833 1044 | ;; i: 162, j: 834, IR: ((8, '$'), '__load_cc__') 1045 | add R0, R0, #0 ; 834 1046 | ;; i: 163, j: 835, IR: ('COND_850_18_ln_127', '__cond_branch__') 1047 | brnp #2 ; 835 1048 | ldr R0, R4, #19 ; 836 1049 | jmp R0 ; 837 1050 | ;; i: 164, j: 838, IR: ([(0, 1), (3, 'ntop')], '+') 1051 | add R0, R5, #-2 ; 838 1052 | ldr R0, R0, #0 ; 839 1053 | add R1, R3, #1 ; 840 1054 | add R0, R0, R1 ; 841 1055 | ;; i: 165, j: 842, IR: ([(8, '$'), (3, 'ntop')], '=') 1056 | add R1, R5, #-2 ; 842 1057 | str R0, R1, #0 ; 843 1058 | ;; i: 166, j: 844, IR: ([(3, 'ntop'), (3, 'num_stack')], '+') 1059 | add R0, R5, #0 ; 844 1060 | ldr R0, R0, #0 ; 845 1061 | add R1, R5, #-2 ; 846 1062 | ldr R1, R1, #0 ; 847 1063 | add R0, R0, R1 ; 848 1064 | ;; i: 167, j: 849, IR: ([(3, 'curr'), (8, '$')], '__mem_assign__') 1065 | add R1, R5, #-10 ; 849 1066 | ldr R1, R1, #0 ; 850 1067 | str R1, R0, #0 ; 851 1068 | ;; i: 168, j: 852, IR: ('END_COND_850_18_ln_127', '__branch__') 1069 | ldr R0, R4, #23 ; 852 1070 | jmp R0 ; 853 1071 | ;; i: 169, j: 854, IR: ([(0, 0), (3, 'otop')], '>=') 1072 | add R0, R5, #-3 ; 854 1073 | ldr R0, R0, #0 ; 855 1074 | add R1, R3, #0 ; 856 1075 | not R1, R1 ; 857 1076 | add R1, R1, #1 ; 858 1077 | add R0, R0, R1 ; 859 1078 | brzp #2 ; 860 1079 | add R0, R3, #0 ; 861 1080 | brnzp #1 ; 862 1081 | add R0, R3, #1 ; 863 1082 | ;; i: 170, j: 864, IR: ([(3, 'otop'), (3, 'op_stack')], '+') 1083 | add R6, R6, #-1 ; 864 1084 | str R0, R6, #0 ; 865 1085 | add R0, R5, #-1 ; 866 1086 | ldr R0, R0, #0 ; 867 1087 | add R1, R5, #-3 ; 868 1088 | ldr R1, R1, #0 ; 869 1089 | add R0, R0, R1 ; 870 1090 | ;; i: 171, j: 871, IR: ((8, '$'), 'mem') 1091 | ldr R0, R0, #0 ; 871 1092 | ;; i: 172, j: 872, IR: ([(8, '$'), (3, 'curr')], '<=') 1093 | add R1, R0, #0 ; 872 1094 | add R0, R5, #-10 ; 873 1095 | ldr R0, R0, #0 ; 874 1096 | not R1, R1 ; 875 1097 | add R1, R1, #1 ; 876 1098 | add R0, R0, R1 ; 877 1099 | brnz #2 ; 878 1100 | add R0, R3, #0 ; 879 1101 | brnzp #1 ; 880 1102 | add R0, R3, #1 ; 881 1103 | ;; i: 173, j: 882, IR: ([(8, '$'), (8, '$')], 'and') 1104 | ldr R1, R6, #0 ; 882 1105 | add R6, R6, #1 ; 883 1106 | add R0, R0, #0 ; 884 1107 | brz #1 ; 885 1108 | add R0, R1, #0 ; 886 1109 | ;; i: 174, j: 887, IR: ((8, '$'), '__load_cc__') 1110 | add R0, R0, #0 ; 887 1111 | ;; i: 175, j: 888, IR: ('COND_561_20_ln_133', '__cond_branch__') 1112 | brnp #2 ; 888 1113 | ldr R0, R4, #22 ; 889 1114 | jmp R0 ; 890 1115 | ;; i: 176, j: 891, IR: ([(3, 'otop'), (3, 'op_stack')], '+') 1116 | add R0, R5, #-1 ; 891 1117 | ldr R0, R0, #0 ; 892 1118 | add R1, R5, #-3 ; 893 1119 | ldr R1, R1, #0 ; 894 1120 | add R0, R0, R1 ; 895 1121 | ;; i: 177, j: 896, IR: ((8, '$'), 'mem') 1122 | ldr R0, R0, #0 ; 896 1123 | ;; i: 178, j: 897, IR: ([(8, '$'), (3, 'operation')], '=') 1124 | add R1, R5, #-11 ; 897 1125 | str R0, R1, #0 ; 898 1126 | ;; i: 179, j: 899, IR: ([(0, 1), (3, 'otop')], '-') 1127 | add R0, R5, #-3 ; 899 1128 | ldr R0, R0, #0 ; 900 1129 | add R1, R3, #1 ; 901 1130 | not R1, R1 ; 902 1131 | add R1, R1, #1 ; 903 1132 | add R0, R0, R1 ; 904 1133 | ;; i: 180, j: 905, IR: ([(8, '$'), (3, 'otop')], '=') 1134 | add R1, R5, #-3 ; 905 1135 | str R0, R1, #0 ; 906 1136 | ;; i: 181, j: 907, IR: ([(3, 'ntop'), (3, 'num_stack')], '+') 1137 | add R0, R5, #0 ; 907 1138 | ldr R0, R0, #0 ; 908 1139 | add R1, R5, #-2 ; 909 1140 | ldr R1, R1, #0 ; 910 1141 | add R0, R0, R1 ; 911 1142 | ;; i: 182, j: 912, IR: ((8, '$'), 'mem') 1143 | ldr R0, R0, #0 ; 912 1144 | ;; i: 183, j: 913, IR: ([(8, '$'), (3, 'num1')], '=') 1145 | add R1, R5, #-12 ; 913 1146 | str R0, R1, #0 ; 914 1147 | ;; i: 184, j: 915, IR: ([(3, 'ntop'), (3, 'num_stack')], '+') 1148 | add R0, R5, #0 ; 915 1149 | ldr R0, R0, #0 ; 916 1150 | add R1, R5, #-2 ; 917 1151 | ldr R1, R1, #0 ; 918 1152 | add R0, R0, R1 ; 919 1153 | ;; i: 185, j: 920, IR: ([(0, 1), (8, '$')], '-') 1154 | add R1, R3, #1 ; 920 1155 | not R1, R1 ; 921 1156 | add R1, R1, #1 ; 922 1157 | add R0, R0, R1 ; 923 1158 | ;; i: 186, j: 924, IR: ((8, '$'), 'mem') 1159 | ldr R0, R0, #0 ; 924 1160 | ;; i: 187, j: 925, IR: ([(8, '$'), (3, 'num2')], '=') 1161 | add R1, R5, #-13 ; 925 1162 | str R0, R1, #0 ; 926 1163 | ;; i: 188, j: 927, IR: ([(0, 1), (3, 'ntop')], '-') 1164 | add R0, R5, #-2 ; 927 1165 | ldr R0, R0, #0 ; 928 1166 | add R1, R3, #1 ; 929 1167 | not R1, R1 ; 930 1168 | add R1, R1, #1 ; 931 1169 | add R0, R0, R1 ; 932 1170 | ;; i: 189, j: 933, IR: ([(8, '$'), (3, 'ntop')], '=') 1171 | add R1, R5, #-2 ; 933 1172 | str R0, R1, #0 ; 934 1173 | ;; i: 190, j: 935, IR: ([(0, 1)], 'um') 1174 | add R0, R3, #-1 ; 935 1175 | ;; i: 191, j: 936, IR: ([(8, '$'), (3, 'operation')], '==') 1176 | add R1, R0, #0 ; 936 1177 | add R0, R5, #-11 ; 937 1178 | ldr R0, R0, #0 ; 938 1179 | not R1, R1 ; 939 1180 | add R1, R1, #1 ; 940 1181 | add R0, R0, R1 ; 941 1182 | brnp #2 ; 942 1183 | add R0, R3, #1 ; 943 1184 | brnzp #1 ; 944 1185 | add R0, R3, #0 ; 945 1186 | ;; i: 192, j: 946, IR: ((8, '$'), '__load_cc__') 1187 | add R0, R0, #0 ; 946 1188 | ;; i: 193, j: 947, IR: ('COND_155_21_ln_143', '__cond_branch__') 1189 | brnp #2 ; 947 1190 | ldr R0, R4, #20 ; 948 1191 | jmp R0 ; 949 1192 | ;; i: 194, j: 950, IR: ([(3, 'ntop'), (3, 'num_stack')], '+') 1193 | add R0, R5, #0 ; 950 1194 | ldr R0, R0, #0 ; 951 1195 | add R1, R5, #-2 ; 952 1196 | ldr R1, R1, #0 ; 953 1197 | add R0, R0, R1 ; 954 1198 | ;; i: 195, j: 955, IR: ([(3, 'num2'), (3, 'num1')], '*') 1199 | add R6, R6, #-1 ; 955 1200 | str R0, R6, #0 ; 956 1201 | add R0, R5, #-12 ; 957 1202 | ldr R0, R0, #0 ; 958 1203 | add R1, R5, #-13 ; 959 1204 | ldr R1, R1, #0 ; 960 1205 | add R1, R1, #0 ; 961 1206 | brzp #4 ; 962 1207 | not R1, R1 ; 963 1208 | add R1, R1, #1 ; 964 1209 | not R0, R0 ; 965 1210 | add R0, R0, #1 ; 966 1211 | and R2, R3, #0 ; 967 1212 | add R1, R1, #0 ; 968 1213 | brnz #3 ; 969 1214 | add R2, R2, R0 ; 970 1215 | add R1, R1, #-1 ; 971 1216 | brp #-3 ; 972 1217 | add R0, R2, #0 ; 973 1218 | ;; i: 196, j: 974, IR: ([(8, '$'), (8, '$')], '__mem_assign__') 1219 | add R1, R0, #0 ; 974 1220 | ldr R0, R6, #0 ; 975 1221 | add R6, R6, #1 ; 976 1222 | str R1, R0, #0 ; 977 1223 | ;; i: 197, j: 978, IR: ('END_COND_155_21_ln_143', '__branch__') 1224 | ldr R0, R4, #21 ; 978 1225 | jmp R0 ; 979 1226 | ;; i: 198, j: 980, IR: ([(3, 'ntop'), (3, 'num_stack')], '+') 1227 | add R0, R5, #0 ; 980 1228 | ldr R0, R0, #0 ; 981 1229 | add R1, R5, #-2 ; 982 1230 | ldr R1, R1, #0 ; 983 1231 | add R0, R0, R1 ; 984 1232 | ;; i: 199, j: 985, IR: ([(3, 'num2'), (3, 'num1')], '+') 1233 | add R6, R6, #-1 ; 985 1234 | str R0, R6, #0 ; 986 1235 | add R0, R5, #-12 ; 987 1236 | ldr R0, R0, #0 ; 988 1237 | add R1, R5, #-13 ; 989 1238 | ldr R1, R1, #0 ; 990 1239 | add R0, R0, R1 ; 991 1240 | ;; i: 200, j: 992, IR: ([(8, '$'), (8, '$')], '__mem_assign__') 1241 | add R1, R0, #0 ; 992 1242 | ldr R0, R6, #0 ; 993 1243 | add R6, R6, #1 ; 994 1244 | str R1, R0, #0 ; 995 1245 | ;; i: 201, j: 996, IR: ('COND_573_19_ln_133', '__branch__') 1246 | ldr R0, R4, #19 ; 996 1247 | jmp R0 ; 997 1248 | ;; i: 202, j: 998, IR: ([(0, 1), (3, 'otop')], '+') 1249 | add R0, R5, #-3 ; 998 1250 | ldr R0, R0, #0 ; 999 1251 | add R1, R3, #1 ; 1000 1252 | add R0, R0, R1 ; 1001 1253 | ;; i: 203, j: 1002, IR: ([(8, '$'), (3, 'otop')], '=') 1254 | add R1, R5, #-3 ; 1002 1255 | str R0, R1, #0 ; 1003 1256 | ;; i: 204, j: 1004, IR: ([(3, 'otop'), (3, 'op_stack')], '+') 1257 | add R0, R5, #-1 ; 1004 1258 | ldr R0, R0, #0 ; 1005 1259 | add R1, R5, #-3 ; 1006 1260 | ldr R1, R1, #0 ; 1007 1261 | add R0, R0, R1 ; 1008 1262 | ;; i: 205, j: 1009, IR: ([(3, 'curr'), (8, '$')], '__mem_assign__') 1263 | add R1, R5, #-10 ; 1009 1264 | ldr R1, R1, #0 ; 1010 1265 | str R1, R0, #0 ; 1011 1266 | ;; i: 206, j: 1012, IR: ([(0, 1), (3, 'i')], '+') 1267 | add R0, R5, #-6 ; 1012 1268 | ldr R0, R0, #0 ; 1013 1269 | add R1, R3, #1 ; 1014 1270 | add R0, R0, R1 ; 1015 1271 | ;; i: 207, j: 1016, IR: ([(8, '$'), (3, 'i')], '=') 1272 | add R1, R5, #-6 ; 1016 1273 | str R0, R1, #0 ; 1017 1274 | ;; i: 208, j: 1018, IR: ('COND_574_16_ln_124', '__branch__') 1275 | ldr R0, R4, #18 ; 1018 1276 | jmp R0 ; 1019 1277 | ;; i: 209, j: 1020, IR: ([(3, 'ntop'), (3, 'num_stack')], '+') 1278 | add R0, R5, #0 ; 1020 1279 | ldr R0, R0, #0 ; 1021 1280 | add R1, R5, #-2 ; 1022 1281 | ldr R1, R1, #0 ; 1023 1282 | add R0, R0, R1 ; 1024 1283 | ;; i: 210, j: 1025, IR: ((8, '$'), 'mem') 1284 | ldr R0, R0, #0 ; 1025 1285 | ;; i: 211, j: 1026, IR: ([(8, '$')], 'return') 1286 | str R0, R5, #3 ; 1026 1287 | add R6, R5, #1 ; 1027 1288 | ldr R5, R6, #0 ; 1028 1289 | ldr R7, R6, #1 ; 1029 1290 | add R6, R6, #2 ; 1030 1291 | ret ; 1031 1292 | ;; i: 212, j: 1032, IR: (None, '__return_to_caller__') 1293 | add R6, R5, #1 ; 1032 1294 | ldr R5, R6, #0 ; 1033 1295 | ldr R7, R6, #1 ; 1034 1296 | add R6, R6, #2 ; 1035 1297 | ret ; 1036 1298 | 1299 | .end -------------------------------------------------------------------------------- /examples/hello-world.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digorithm/LC-3-Rust/61c93c60c3088ba8bfb4fe0ea92f38a8136ca5d5/examples/hello-world.obj -------------------------------------------------------------------------------- /examples/hello-world.obj.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digorithm/LC-3-Rust/61c93c60c3088ba8bfb4fe0ea92f38a8136ca5d5/examples/hello-world.obj.asm -------------------------------------------------------------------------------- /examples/rogue.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digorithm/LC-3-Rust/61c93c60c3088ba8bfb4fe0ea92f38a8136ca5d5/examples/rogue.obj -------------------------------------------------------------------------------- /src/hardware/instruction/mod.rs: -------------------------------------------------------------------------------- 1 | // Opcodes are fundamental operations to the CPU, LC-3 only has 16 opcodes. 2 | // Each instruction is 16 bits long, with first 4 bits storing the Opcode, 3 | // the rest is reserved for the parameter. 4 | use super::vm::VM; 5 | 6 | use std::io; 7 | use std::io::Read; 8 | use std::io::Write; 9 | use std::process; 10 | 11 | #[derive(Debug)] 12 | pub enum OpCode { 13 | BR = 0, // branch 14 | ADD, // add 15 | LD, // load 16 | ST, // store 17 | JSR, // jump register 18 | AND, // bitwise and 19 | LDR, // load register 20 | STR, // store register 21 | RTI, // unused 22 | NOT, // bitwise not 23 | LDI, // load indirect 24 | STI, // store indirect 25 | JMP, // jump 26 | RES, // reserved (unused) 27 | LEA, // load effective address 28 | TRAP, // execute trap 29 | } 30 | 31 | // TRAP Codes 32 | pub enum TrapCode { 33 | /// get character from keyboard 34 | Getc = 0x20, 35 | /// output a character 36 | Out = 0x21, 37 | /// output a word string 38 | Puts = 0x22, 39 | /// input a string 40 | In = 0x23, 41 | /// output a byte string 42 | Putsp = 0x24, 43 | /// halt the program 44 | Halt = 0x25, 45 | } 46 | 47 | pub fn execute_instruction(instr: u16, vm: &mut VM) { 48 | // Extract OPCode from the instruction 49 | let op_code = get_op_code(&instr); 50 | 51 | // Match OPCode and execute instruction 52 | match op_code { 53 | Some(OpCode::ADD) => add(instr, vm), 54 | Some(OpCode::AND) => and(instr, vm), 55 | Some(OpCode::NOT) => not(instr, vm), 56 | Some(OpCode::BR) => br(instr, vm), 57 | Some(OpCode::JMP) => jmp(instr, vm), 58 | Some(OpCode::JSR) => jsr(instr, vm), 59 | Some(OpCode::LD) => ld(instr, vm), 60 | Some(OpCode::LDI) => ldi(instr, vm), 61 | Some(OpCode::LDR) => ldr(instr, vm), 62 | Some(OpCode::LEA) => lea(instr, vm), 63 | Some(OpCode::ST) => st(instr, vm), 64 | Some(OpCode::STI) => sti(instr, vm), 65 | Some(OpCode::STR) => str(instr, vm), 66 | Some(OpCode::TRAP) => trap(instr, vm), 67 | _ => {} 68 | } 69 | } 70 | 71 | // Each instruction is 16 bits long, with the left 4 bits storing the opcode. 72 | // The rest of the bits are used to store the parameters. 73 | // To extract left 4 bits out of the instruction, we'll use a right bit shift `>>` 74 | // operator and shift to the right the first 4 bits 12 positions. 75 | pub fn get_op_code(instruction: &u16) -> Option { 76 | match instruction >> 12 { 77 | 0 => Some(OpCode::BR), 78 | 1 => Some(OpCode::ADD), 79 | 2 => Some(OpCode::LD), 80 | 3 => Some(OpCode::ST), 81 | 4 => Some(OpCode::JSR), 82 | 5 => Some(OpCode::AND), 83 | 6 => Some(OpCode::LDR), 84 | 7 => Some(OpCode::STR), 85 | 8 => Some(OpCode::RTI), 86 | 9 => Some(OpCode::NOT), 87 | 10 => Some(OpCode::LDI), 88 | 11 => Some(OpCode::STI), 89 | 12 => Some(OpCode::JMP), 90 | 13 => Some(OpCode::RES), 91 | 14 => Some(OpCode::LEA), 92 | 15 => Some(OpCode::TRAP), 93 | _ => None, 94 | } 95 | } 96 | 97 | /// ADD takes two values and stores them in a register. 98 | /// In register mode, the second value to add is found in a register. 99 | /// In immediate mode, the second value is embedded in the right-most 5 bits of the instruction. 100 | /// Values which are shorter than 16 bits need to be sign extended. 101 | /// Any time an instruction modifies a register, the condition flags need to be updated 102 | /// If bit [5] is 0, the second source operand is obtained from SR2. 103 | /// If bit [5] is 1, the second source operand is obtained by sign-extending the imm5 field to 16 bits. 104 | /// In both cases, the second source operand is added to the contents of SR1 and the result stored in DR. 105 | /// The condition codes are set, based on whether the result is negative, zero, or positive. 106 | /// Encoding: 107 | /// 108 | /// 15 12 │11 9│8 6│ 5 │4 3│2 0 109 | /// ┌───────────────┼───────────┼───────────┼───┼───────┼───────────┐ 110 | /// │ 0001 │ DR │ SR1 │ 0 │ 00 │ SR2 │ 111 | /// └───────────────┴───────────┴───────────┴───┴───────┴───────────┘ 112 | /// 113 | /// 15 12│11 9│8 6│ 5 │4 0 114 | /// ┌───────────────┼───────────┼───────────┼───┼───────────────────┐ 115 | /// │ 0001 │ DR │ SR1 │ 1 │ IMM5 │ 116 | /// └───────────────┴───────────┴───────────┴───┴───────────────────┘ 117 | pub fn add(instruction: u16, vm: &mut VM) { 118 | // Get destination address using bitwise operation tricks. 119 | // `instruction >> 9` will shift the binary from instruction it 9 times to the right 120 | // That means the last bit will be the end of the DR portion of the instruction 121 | // And the bitwise-and (`&`) `0x7` will grab only the length of `111` out of the 122 | // instruction, i.e the last 3 bits, which is exactly the length of the DR. 123 | let dr = (instruction >> 9) & 0x7; 124 | 125 | // First operand -- Same things as described above, but we move only 6 times to grab the sr1. 126 | let sr1 = (instruction >> 6) & 0x7; 127 | 128 | // Check if we're in immediate mode or register mode. Grab just the imm_flag portion of the 129 | // instruction 130 | let imm_flag = (instruction >> 5) & 0x1; 131 | 132 | if imm_flag == 1 { 133 | let imm5 = sign_extend(instruction & 0x1F, 5); 134 | 135 | // This is declared as u32 to prevent from overflow. 136 | let val: u32 = imm5 as u32 + vm.registers.get(sr1) as u32; 137 | 138 | // Set the result of the sum to the target register 139 | vm.registers.update(dr, val as u16); 140 | } else { 141 | // If not immediate mode, we need to extract the second register. 142 | let sr2 = instruction & 0x7; 143 | 144 | // Proceed as usual 145 | let val: u32 = vm.registers.get(sr1) as u32 + vm.registers.get(sr2) as u32; 146 | 147 | // Set the result of the sum to the target register 148 | vm.registers.update(dr, val as u16); 149 | } 150 | 151 | // Update the cond register. We pass `dr` here because this is the register that 152 | // has the result of the last operation. Remember that the cond register's idea 153 | // is to set positive/negative/zero based on the result of the last operation, 154 | // which in this case live in `dr`. 155 | vm.registers.update_r_cond_register(dr); 156 | } 157 | 158 | /// Load indirect 159 | /// An address is computed by sign-extending bits [8:0] to 16 bits and adding this 160 | /// value to the incremented PC. What is stored in memory at this address is the address 161 | /// of the data to be loaded into DR. The condition codes are set, based on whether the 162 | // value loaded is negative, zero, or positive. 163 | /// 164 | /// Encoding: 165 | /// 166 | /// 15 12 11 9 8 0 167 | /// ┌───────────────┬───────────┬───────────────────────────────────┐ 168 | /// │ 1010 │ DR │ PCOffset9 │ 169 | /// └───────────────┴───────────┴───────────────────────────────────┘ 170 | pub fn ldi(instruction: u16, vm: &mut VM) { 171 | // Get the direct register encoded in the instruction (see `add` fn for more in-depth details) 172 | let dr = (instruction >> 9) & 0x7; 173 | 174 | // Get the PC offset and sign extend it to be 16 bits 175 | let pc_offset = sign_extend(instruction & 0x1ff, 9); 176 | 177 | // This sum is an address to a location in memory, and that address contains 178 | // another value which is the address of the value to load. That's why it's called "indirect". 179 | let first_read = vm.read_memory(vm.registers.pc + pc_offset); 180 | 181 | // Read the resulting address and update the DR. 182 | let resulting_address = vm.read_memory(first_read); 183 | vm.registers.update(dr, resulting_address); 184 | vm.registers.update_r_cond_register(dr); 185 | } 186 | 187 | /// Your good old logical `and` function. Two operation modes, immediate or passing a register. 188 | /// 189 | /// 15 12 │11 9│8 6│ 5 │4 3│2 0 190 | /// ┌───────────────┼───────────┼───────────┼───┼───────┼───────────┐ 191 | /// │ 0101 │ DR │ SR1 │ 0 │ 00 │ SR2 │ 192 | /// └───────────────┴───────────┴───────────┴───┴───────┴───────────┘ 193 | 194 | /// 15 12│11 9│8 6│ 5 │4 0 195 | /// ┌───────────────┼───────────┼───────────┼───┼───────────────────┐ 196 | /// │ 0101 │ DR │ SR1 │ 1 │ IMM5 │ 197 | /// └───────────────┴───────────┴───────────┴───┴───────────────────┘ 198 | pub fn and(instruction: u16, vm: &mut VM) { 199 | // Get the direct register encoded in the instruction (see `add` fn for more in-depth details) 200 | let dr = (instruction >> 9) & 0x7; 201 | 202 | // As seen in `add` fn, same tricks. 203 | let sr1 = (instruction >> 6) & 0x7; 204 | let imm_flag = (instruction >> 5) & 0x1; 205 | 206 | if imm_flag == 1 { 207 | let imm5 = sign_extend(instruction & 0x1F, 5); 208 | // Perform the bitwise and (`&`) and store its value in the DR. 209 | vm.registers.update(dr, vm.registers.get(sr1) & imm5); 210 | } else { 211 | let sr2 = instruction & 0x7; 212 | // Perform the bitwise and (`&`) and store its value in the DR. 213 | vm.registers 214 | .update(dr, vm.registers.get(sr1) & vm.registers.get(sr2)); 215 | } 216 | 217 | vm.registers.update_r_cond_register(dr); 218 | } 219 | 220 | /// Simple binary negation. 221 | /// 15 12 │11 9│8 6│ 5 │4 0 222 | /// ┌───────────────┼───────────┼───────────┼───┼───────────────────┐ 223 | /// │ 1001 │ DR │ SR │ 1 │ 1111 │ 224 | /// └───────────────┴───────────┴───────────┴───┴───────────────────┘ 225 | pub fn not(instruction: u16, vm: &mut VM) { 226 | // Get the direct register encoded in the instruction (see `add` fn for more in-depth details) 227 | let dr = (instruction >> 9) & 0x7; 228 | let sr1 = (instruction >> 6) & 0x7; 229 | vm.registers.update(dr, !vm.registers.get(sr1)); 230 | 231 | vm.registers.update_r_cond_register(dr); 232 | } 233 | 234 | /// The branching operation; means to go somewhere else in the assembly code 235 | /// depending on whether some conditions are met. 236 | /// The condition codes specified by the state of bits [11:9] are tested. 237 | /// If bit [11] is set, N is tested; if bit [11] is clear, N is not tested. 238 | /// If bit [10] is set, Z is tested. If any of the condition codes tested is set, 239 | /// the program branches to the location specified by 240 | /// adding the sign-extended PCOffset9 field to the incremented PC. 241 | /// 242 | /// 15 12 │11 │10 │ 9 │8 0 243 | /// ┌───────────────┼───┼───┼───┼───────────────────────────────────┐ 244 | /// │ 0000 │ N │ Z │ P │ PCOffset9 │ 245 | /// └───────────────┴───┴───┴───┴───────────────────────────────────┘ 246 | pub fn br(instruction: u16, vm: &mut VM) { 247 | // Grab the PCOffset of the instruction and sign extend it 248 | // You can read more sign extension inside the `sign_extend` fn. 249 | let pc_offset = sign_extend((instruction) & 0x1ff, 9); 250 | 251 | // Shift 9 and grab 3 bits (& 0x7 is doing that) 252 | // You can read more about this trick inside `lea` fn. 253 | let cond_flag = (instruction >> 9) & 0x7; 254 | 255 | // so we're taking the `001`, xor `010`, xor `100` that's stored in the condition register 256 | // and `&`ing it to the `001`, or `010`, or `100` coming from the instruction, 257 | // note that it can be `110`, `111` or any combination. 258 | if cond_flag & vm.registers.cond != 0 { 259 | let val: u32 = vm.registers.pc as u32 + pc_offset as u32; 260 | vm.registers.pc = val as u16; 261 | } 262 | 263 | // If the branch isn't taken (no condition met), PC isn't changed 264 | // and PC will just point to the next sequential instruction. 265 | } 266 | 267 | /// The program unconditionally jumps to the location specified by the contents of the base register. 268 | /// Bits [8:6] identify the base register. `RET` is listed as a separate instruction 269 | /// in the specification, since it is a different keyword in assembly. 270 | /// However, it is actually a special case of JMP. RET happens whenever R1 is 7. 271 | /// 272 | /// 15 12│11 9│8 6│ 5 0 273 | /// ┌───────────────┼───────────┼───────────┼───────────────────────┐ 274 | /// │ 1100 │ 000 │ BaseR │ 00000 │ 275 | /// └───────────────┴───────────┴───────────┴───────────────────────┘ 276 | /// 15 12│11 9│8 6│ 5 0 277 | /// ┌───────────────┼───────────┼───────────┼───────────────────────┐ 278 | /// │ 1100 │ 000 │ 111 │ 00000 │ 279 | /// └───────────────┴───────────┴───────────┴───────────────────────┘ 280 | pub fn jmp(instruction: u16, vm: &mut VM) { 281 | // base_reg will either be an arbitrary register or the register 7 (`111`) which in this 282 | // case it would be the `RET` operation. 283 | let base_reg = (instruction >> 6) & 0x7; 284 | vm.registers.pc = vm.registers.get(base_reg); 285 | } 286 | 287 | /// First, the incremented PC is saved in R7. 288 | /// This is the linkage back to the calling routine. 289 | /// Then the PC is loaded with the address of the first instruction of the subroutine, 290 | /// causing an unconditional jump to that address. 291 | /// The address of the subroutine is obtained from the base register (if bit [11] is 0), 292 | /// or the address is computed by sign-extending bits [10:0] and adding this value to the incremented PC (if bit [11] is 1). 293 | 294 | /// 15 12│11 │10 295 | /// ┌───────────────┼───┼───────────────────────────────────────────┐ 296 | /// │ 0100 │ 1 │ PCOffset11 │ 297 | /// └───────────────┴───┴───────────────────────────────────────────┘ 298 | /// 15 12│11 │10 9│8 6│5 0 299 | /// ┌───────────────┼───┼───────┼───────┼───────────────────────────┐ 300 | /// │ 0100 │ 0 │ 00 │ BaseR │ 00000 │ 301 | /// └───────────────┴───┴───────┴───────┴───────────────────────────┘ 302 | pub fn jsr(instruction: u16, vm: &mut VM) { 303 | // Grab the base register 304 | let base_reg = (instruction >> 6) & 0x7; 305 | 306 | // 0x7ff == 11111111111 (11 ones, exactly the length of PCOffset11) 307 | // Grab it and extend it to 16 bits. 308 | let long_pc_offset = sign_extend(instruction & 0x7ff, 11); 309 | 310 | // Grab the flag bit at [11] and test it 311 | let long_flag = (instruction >> 11) & 1; 312 | 313 | // Save the incremented PC in R7 314 | vm.registers.r7 = vm.registers.pc; 315 | 316 | if long_flag != 0 { 317 | // JSR case, the address to jump is computed from PCOffset11 318 | let val: u32 = vm.registers.pc as u32 + long_pc_offset as u32; 319 | vm.registers.pc = val as u16; 320 | } else { 321 | // JSRR case, address to jump to lives in the base register 322 | vm.registers.pc = vm.registers.get(base_reg); 323 | } 324 | } 325 | 326 | /// An address is computed by sign-extending bits [8:0] to 16 bits and 327 | /// adding this value to the incremented PC. 328 | /// The contents of memory at this address are loaded into DR. 329 | /// The condition codes are set, based on whether the value loaded is negative, zero, or positive. 330 | /// 331 | /// 15 12│11 9│8 0 332 | /// ┌───────────────┼───────────┼───────────────────────────────────┐ 333 | /// │ 0010 │ DR │ PCOffset9 │ 334 | /// └───────────────┴───────────┴───────────────────────────────────┘ 335 | pub fn ld(instruction: u16, vm: &mut VM) { 336 | // Get the direct register encoded in the instruction (see `add` fn for more in-depth details) 337 | let dr = (instruction >> 9) & 0x7; 338 | 339 | // Grab the PCOffset and sign extend it 340 | let pc_offset = sign_extend(instruction & 0x1ff, 9); 341 | 342 | let mem: u32 = pc_offset as u32 + vm.registers.pc as u32; 343 | 344 | // Read the value from the place where the memory above was computed 345 | let value = vm.read_memory(mem as u16); 346 | 347 | // Save that value to the direct register and update the condition register 348 | vm.registers.update(dr, value); 349 | vm.registers.update_r_cond_register(dr); 350 | } 351 | 352 | /// Load base + offset 353 | /// An address is computed by sign-extending bits [5:0] to 16 bits 354 | /// and adding this value to the contents of the register specified by bits [8:6]. 355 | /// The contents of memory at this address are loaded into DR. 356 | /// The condition codes are set, based on whether the value loaded is negative, zero, or positive. 357 | /// 358 | /// 15 12│11 9│8 6│5 0 359 | /// ┌───────────────┼───────────┼───────────────┼───────────────────┐ 360 | /// │ 1010 │ DR │ BaseR │ PCOffset6 │ 361 | /// └───────────────┴───────────┴───────────────┴───────────────────┘ 362 | pub fn ldr(instruction: u16, vm: &mut VM) { 363 | // Get the direct register encoded in the instruction (see `add` fn for more in-depth details) 364 | let dr = (instruction >> 9) & 0x7; 365 | 366 | // Grab the base register 367 | let base_reg = (instruction >> 6) & 0x7; 368 | 369 | // Grab the offset6 and sign extend it 370 | let offset = sign_extend(instruction & 0x3F, 6); 371 | 372 | // Compute the memory location to be loaded 373 | let val: u32 = vm.registers.get(base_reg) as u32 + offset as u32; 374 | 375 | // Read the value at that memory location 376 | let mem_value = vm.read_memory(val as u16).clone(); 377 | 378 | // Update the register with the loaded value and update the condition register 379 | vm.registers.update(dr, mem_value); 380 | vm.registers.update_r_cond_register(dr); 381 | } 382 | 383 | /// An address is computed by sign-extending bits [8:0] to 16 bits and adding 384 | /// this value to the incremented PC. 385 | /// This address is loaded into DR. The condition codes are set, based on whether the 386 | /// value loaded is negative, zero, or positive. 387 | /// 388 | /// 15 12│11 9│8 0 389 | /// ┌───────────────┼───────────┼───────────────────────────────────┐ 390 | /// │ 1110 │ DR │ PCOffset9 │ 391 | /// └───────────────┴───────────┴───────────────────────────────────┘ 392 | pub fn lea(instruction: u16, vm: &mut VM) { 393 | // This (instruction >> 9) & 0x7 is trying to say: shift it so that the last three bits 394 | // are the direct register we're looking for, mask it with 0x7 (`0b0000000000000111`) so that 395 | // we clear _everything_ up to the last three bits, which is what we want. 396 | // The resulting 16 bits value will be _exactly_ the direct register! 397 | let dr = (instruction >> 9) & 0x7; 398 | 399 | // 0x1ff is `111111111`, 9 consecutive ones. 400 | let pc_offset = sign_extend(instruction & 0x1ff, 9); 401 | 402 | // Value that we want to store in the register (`dr`) 403 | // Which is the current program counter + the 404 | // calculated offset. 405 | let val: u32 = vm.registers.pc as u32 + pc_offset as u32; 406 | 407 | vm.registers.update(dr, val as u16); 408 | 409 | vm.registers.update_r_cond_register(dr); 410 | } 411 | 412 | /// The contents of the register specified by SR are stored in the memory location 413 | /// whose address is computed by sign-extending bits [8:0] to 16 bits and adding 414 | /// this value to the incremented PC. 415 | /// 416 | /// 15 12│11 9│8 0 417 | /// ┌───────────────┼───────────┼───────────────────────────────────┐ 418 | /// │ 0011 │ SR │ PCOffset9 │ 419 | /// └───────────────┴───────────┴───────────────────────────────────┘ 420 | pub fn st(instruction: u16, vm: &mut VM) { 421 | // Get the direct register encoded in the instruction (see `add` fn for more in-depth details) 422 | let sr = (instruction >> 9) & 0x7; 423 | 424 | // Grab the PC offset and sign extend it 425 | let pc_offset = sign_extend(instruction & 0x1ff, 9); 426 | 427 | // Add the current PC to the PC offset 428 | // We're doing these conversions to avoid overflow 429 | let val: u32 = vm.registers.pc as u32 + pc_offset as u32; 430 | let val: u16 = val as u16; 431 | 432 | // Store the value in the register being passed in the instruction at 433 | // the address computed above 434 | vm.write_memory(val as usize, vm.registers.get(sr)); 435 | } 436 | 437 | /// The contents of the register specified by SR are stored in the memory location 438 | /// whose address is obtained as follows: Bits [8:0] are sign-extended to 16 bits and added to the incremented PC. 439 | /// What is in memory at this address is the address of the location to which the data in SR is stored. 440 | /// 441 | /// 15 12│11 9│8 0 442 | /// ┌───────────────┼───────────┼───────────────────────────────────┐ 443 | /// │ 1011 │ SR │ PCOffset9 │ 444 | /// └───────────────┴───────────┴───────────────────────────────────┘ 445 | pub fn sti(instruction: u16, vm: &mut VM) { 446 | // Get the register encoded in the instruction (see `add` fn for more in-depth details) 447 | let sr = (instruction >> 9) & 0x7; 448 | 449 | // Grab the PC offset and sign extend it 450 | let pc_offset = sign_extend(instruction & 0x1ff, 9); 451 | 452 | // Add the current PC to the PC offset 453 | // We're doing these conversions to avoid overflow 454 | let val: u32 = vm.registers.pc as u32 + pc_offset as u32; 455 | let val: u16 = val as u16; 456 | 457 | // This is the difference between STI and ST 458 | let address = vm.read_memory(val) as usize; 459 | 460 | vm.write_memory(address, vm.registers.get(sr)); 461 | } 462 | 463 | /// The contents of the register specified by SR are stored in the memory location 464 | /// whose address is computed by sign-extending bits [5:0] to 16 bits 465 | /// and adding this value to the contents of the register specified by bits [8:6]. 466 | /// 467 | /// 15 12│11 9│8 6│ 0 468 | /// ┌───────────────┼───────────┼───────────┼───────────────────────┐ 469 | /// │ 0111 │ SR │ BaseR │ PCOffset6 │ 470 | /// └───────────────┴───────────┴───────────┴───────────────────────┘ 471 | pub fn str(instruction: u16, vm: &mut VM) { 472 | // Get the register encoded in the instruction (see `add` fn for more in-depth details) 473 | let dr = (instruction >> 9) & 0x7; 474 | 475 | // Grab the base register 476 | let base_reg = (instruction >> 6) & 0x7; 477 | 478 | // Grab the offset and sign extend it 479 | let offset = sign_extend(instruction & 0x3F, 6); 480 | 481 | // Get the value in the base_register and sum it to the offset encoded in the instruction 482 | // Note that we're doing some conversions here to prevent overflow. 483 | let val: u32 = vm.registers.get(base_reg) as u32 + offset as u32; 484 | let val: u16 = val as u16; 485 | vm.write_memory(val as usize, vm.registers.get(dr)); 486 | } 487 | 488 | /// `trap` fn allows interacting with I/O devices 489 | /// First R7 is loaded with the incremented PC. 490 | // (This enables a return to the instruction physically following the TRAP instruction in the original program 491 | /// after the service routine has completed execution.) 492 | /// Then the PC is loaded with the starting address of the system call specified by trap vector8. 493 | /// The starting address is contained in the memory location whose address is obtained by zero-extending trap vector8 to 16 bits. 494 | pub fn trap(instruction: u16, vm: &mut VM) { 495 | match instruction & 0xFF { 496 | 0x20 => { 497 | // Get character 498 | let mut buffer = [0; 1]; 499 | std::io::stdin().read_exact(&mut buffer).unwrap(); 500 | vm.registers.r0 = buffer[0] as u16; 501 | } 502 | 0x21 => { 503 | // Write out character 504 | let c = vm.registers.r0 as u8; 505 | print!("{}", c as char); 506 | // println!("[*] OUT"); 507 | } 508 | 0x22 => { 509 | // Puts 510 | let mut index = vm.registers.r0; 511 | let mut c = vm.read_memory(index); 512 | while c != 0x0000 { 513 | print!("{}", (c as u8) as char); 514 | index += 1; 515 | c = vm.read_memory(index); 516 | } 517 | io::stdout().flush().expect("failed to flush"); 518 | } 519 | 0x23 => { 520 | // In, Print a prompt on the screen and read a single character from the keyboard. The character is echoed onto the console monitor, and its ASCII code is copied into R0.The high eight bits of R0 are cleared. 521 | print!("Enter a character : "); 522 | io::stdout().flush().expect("failed to flush"); 523 | let char = std::io::stdin() 524 | .bytes() 525 | .next() 526 | .and_then(|result| result.ok()) 527 | .map(|byte| byte as u16) 528 | .unwrap(); 529 | vm.registers.update(0, char); 530 | } 531 | 0x24 => { 532 | // Putsp 533 | let mut index = vm.registers.r0; 534 | let mut c = vm.read_memory(index); 535 | while c != 0x0000 { 536 | let c1 = ((c & 0xFF) as u8) as char; 537 | print!("{}", c1); 538 | let c2 = ((c >> 8) as u8) as char; 539 | if c2 != '\0' { 540 | print!("{}", c2); 541 | } 542 | index += 1; 543 | c = vm.read_memory(index); 544 | } 545 | io::stdout().flush().expect("failed to flush"); 546 | } 547 | 0x25 => { 548 | println!("HALT detected"); 549 | io::stdout().flush().expect("failed to flush"); 550 | process::exit(1); 551 | } 552 | _ => { 553 | process::exit(1); 554 | } 555 | } 556 | } 557 | 558 | pub fn sign_extend(mut x: u16, bit_count: u8) -> u16 { 559 | // bit_count is the original number of bits 560 | // that this binary value has. We want to take that 561 | // and transform it into a 16 bits value 562 | 563 | // This if clause is testing the sign of the value. 564 | // We're moving `x` to the right up until 565 | // the sign bit (`bit_count - 1`). 566 | // Then check if it's different than zero, 567 | // if it is, it's signed as 1 (negative) 568 | // Meaning we have to pad with ones instead of zeroes 569 | if (x >> (bit_count - 1)) & 1 != 0 { 570 | x |= 0xFFFF << bit_count; 571 | } 572 | // If it's positive, return as is, it will be padded 573 | // with zeroes. 574 | x 575 | } 576 | -------------------------------------------------------------------------------- /src/hardware/mod.rs: -------------------------------------------------------------------------------- 1 | //pub mod instruction; 2 | //pub mod memory; 3 | pub mod instruction; 4 | pub mod register; 5 | pub mod vm; 6 | 7 | use vm::VM; 8 | 9 | pub const MEMORY_SIZE: usize = std::u16::MAX as usize; 10 | 11 | pub fn execute_program(vm: &mut VM) { 12 | //initialize Registers 13 | while vm.registers.pc < MEMORY_SIZE as u16 { 14 | //read instruction 15 | let instruction = vm.read_memory(vm.registers.pc); 16 | 17 | //increment program counter 18 | vm.registers.pc += 1; 19 | 20 | //extract op_code and execute operation... 21 | instruction::execute_instruction(instruction, vm) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/hardware/register/mod.rs: -------------------------------------------------------------------------------- 1 | const PC_START: u16 = 0x3000; 2 | 3 | // LC-3 has 10 registers -- 8 general purpose registers, 4 | // 1 program counter, and one condition flag. 5 | // The program counter stores an uint that is the memory 6 | // address of the next instruction to be executed. 7 | pub struct Registers { 8 | pub r0: u16, 9 | pub r1: u16, 10 | pub r2: u16, 11 | pub r3: u16, 12 | pub r4: u16, 13 | pub r5: u16, 14 | pub r6: u16, 15 | pub r7: u16, 16 | pub pc: u16, 17 | pub cond: u16, 18 | } 19 | 20 | impl Registers { 21 | pub fn new() -> Registers { 22 | Registers { 23 | r0: 0, // general purpose register 24 | r1: 0, // general purpose register 25 | r2: 0, // general purpose register 26 | r3: 0, // general purpose register 27 | r4: 0, // general purpose register 28 | r5: 0, // general purpose register 29 | r6: 0, // general purpose register 30 | r7: 0, // general purpose register 31 | pc: PC_START, // program counter 32 | cond: 0, // condition flag 33 | } 34 | } 35 | 36 | pub fn update(&mut self, index: u16, value: u16) { 37 | match index { 38 | 0 => self.r0 = value, 39 | 1 => self.r1 = value, 40 | 2 => self.r2 = value, 41 | 3 => self.r3 = value, 42 | 4 => self.r4 = value, 43 | 5 => self.r5 = value, 44 | 6 => self.r6 = value, 45 | 7 => self.r7 = value, 46 | 8 => self.pc = value, 47 | 9 => self.cond = value, 48 | _ => panic!("Index out of bound"), 49 | } 50 | } 51 | 52 | pub fn get(&self, index: u16) -> u16 { 53 | match index { 54 | 0 => self.r0, 55 | 1 => self.r1, 56 | 2 => self.r2, 57 | 3 => self.r3, 58 | 4 => self.r4, 59 | 5 => self.r5, 60 | 6 => self.r6, 61 | 7 => self.r7, 62 | 8 => self.pc, 63 | 9 => self.cond, 64 | _ => panic!("Index out of bound. "), 65 | } 66 | } 67 | 68 | // Update the condition register based on the value that's inside the register `r`. 69 | pub fn update_r_cond_register(&mut self, r: u16) { 70 | if self.get(r) == 0 { 71 | self.update(9, ConditionFlag::ZRO as u16); 72 | } else if (self.get(r) >> 15) != 0 { 73 | // a 1 in the left-most bit indicates negative 74 | self.update(9, ConditionFlag::NEG as u16); 75 | } else { 76 | self.update(9, ConditionFlag::POS as u16); 77 | } 78 | } 79 | } 80 | 81 | // The RCOND register stores condition flags that represents information about 82 | // the most recent computation. It's used for checking logical conditions. 83 | // The LC-3 uses only 3 condition flags which indicate the sign of the previous calculation. 84 | enum ConditionFlag { 85 | // The `<<` operator is a left bit shift operator. 86 | // It's simpler than it looks: `n << k` means we're moving (or shifting) 87 | // the bits in the binary representation of the number `n` by `k`. 88 | // for instance, 1 in binary representation is 0000000000000001 89 | // 1 << 2 means we're shifting the bits twice to the left, so that 90 | // `1` at the end will effectively move to left, twice. It ends up being 91 | // 0000000000000100, which in decimal representation is 4. 92 | // Thus, 1 << 2 == 4. 93 | 94 | // So why are we storing 1, 2, 4 here? Glad you asked. 95 | // In binary, with 3 bits only: 96 | // 1 == 001 97 | // 2 == 010 98 | // 4 == 100 99 | // So we're playing with the possible conditional flags settings! 100 | // Because the condition instruction will be `nzp` (neg, zero, pos) 101 | // and only one can be set at a time, it will either be 102 | // 001 (positive set `nz1`) 103 | // 010 (zero set, `n1p`) 104 | // 100 (negative set, `1zp`) 105 | // And these three binary values are 1, 2, and 4 in decimal base! 106 | POS = 1 << 0, // Positive 107 | ZRO = 1 << 1, // Zero 108 | NEG = 1 << 2, // Negative 109 | } 110 | -------------------------------------------------------------------------------- /src/hardware/vm/mod.rs: -------------------------------------------------------------------------------- 1 | // The LC-3 has 65_536 memory locations, which is the max addressable by u16, 2^16. 2 | const MEMORY_SIZE: usize = u16::MAX as usize; 3 | 4 | use super::register::Registers; 5 | 6 | use std::io::Read; 7 | 8 | pub struct VM { 9 | pub memory: [u16; MEMORY_SIZE], 10 | pub registers: Registers, 11 | } 12 | 13 | impl VM { 14 | pub fn new() -> VM { 15 | VM { 16 | memory: [0; MEMORY_SIZE], 17 | registers: Registers::new(), 18 | } 19 | } 20 | 21 | pub fn read_memory(&mut self, address: u16) -> u16 { 22 | if address == MemoryMappedReg::Kbsr as u16 { 23 | self.handle_keyboard(); 24 | } 25 | self.memory[address as usize] 26 | } 27 | 28 | fn handle_keyboard(&mut self) { 29 | let mut buffer = [0; 1]; 30 | std::io::stdin().read_exact(&mut buffer).unwrap(); 31 | if buffer[0] != 0 { 32 | self.write_memory(MemoryMappedReg::Kbsr as usize, 1 << 15); 33 | self.write_memory(MemoryMappedReg::Kbdr as usize, buffer[0] as u16); 34 | } else { 35 | self.write_memory(MemoryMappedReg::Kbsr as usize, 0) 36 | } 37 | } 38 | 39 | pub fn write_memory(&mut self, address: usize, value: u16) { 40 | self.memory[address] = value; 41 | } 42 | } 43 | 44 | pub enum MemoryMappedReg { 45 | // Keyboard status: The KBSR indicates whether a key has been pressed 46 | Kbsr = 0xFE00, 47 | 48 | // Keyboard data: The KBDR identifies which key was pressed 49 | Kbdr = 0xFE02, 50 | } 51 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate termios; 2 | 3 | pub mod hardware; 4 | use hardware::vm::VM; 5 | 6 | use termios::*; 7 | 8 | use byteorder::{BigEndian, ReadBytesExt}; 9 | 10 | use std::{fs::File, io::BufReader}; 11 | use structopt::StructOpt; 12 | 13 | #[derive(StructOpt)] 14 | struct Cli { 15 | /// The path to the file to read 16 | #[structopt(parse(from_os_str))] 17 | path: std::path::PathBuf, 18 | 19 | #[structopt(long)] 20 | print_asm: bool, // Future feature 21 | } 22 | 23 | fn main() { 24 | // Some tricks to make the VM's terminal be interactive 25 | let stdin = 0; 26 | let termios = termios::Termios::from_fd(stdin).unwrap(); 27 | 28 | // make a mutable copy of termios 29 | // that we will modify 30 | let mut new_termios = termios.clone(); 31 | new_termios.c_iflag &= IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON; 32 | new_termios.c_lflag &= !(ICANON | ECHO); // no echo and canonical mode 33 | 34 | tcsetattr(stdin, TCSANOW, &mut new_termios).unwrap(); 35 | 36 | // Actual VM logic code 37 | let mut vm = VM::new(); 38 | 39 | let cli = Cli::from_args(); 40 | 41 | let f = File::open(cli.path).expect("couldn't open file"); 42 | let mut f = BufReader::new(f); 43 | 44 | // Note how we're using `read_u16` _and_ BigEndian to read the binary file. 45 | let base_address = f.read_u16::().expect("error"); 46 | 47 | // Here we're loading the program in memory 48 | let mut address = base_address as usize; 49 | loop { 50 | match f.read_u16::() { 51 | Ok(instruction) => { 52 | vm.write_memory(address, instruction); 53 | address += 1; 54 | } 55 | Err(e) => { 56 | if e.kind() == std::io::ErrorKind::UnexpectedEof { 57 | println!("OK") 58 | } else { 59 | println!("failed: {}", e); 60 | } 61 | break; 62 | } 63 | } 64 | } 65 | 66 | hardware::execute_program(&mut vm); 67 | 68 | // reset the stdin to 69 | // original termios data 70 | tcsetattr(stdin, TCSANOW, &termios).unwrap(); 71 | } 72 | --------------------------------------------------------------------------------