From 82501d0dad335ee5320d7a2f40fe03d181eecb3f Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 22:18:16 +0300 Subject: [PATCH 1/7] add disassamble func --- lc3vm/2048.asm | 1141 +++++++++++++++++++++++++++++++++++++++++ lc3vm/include/lc3.hpp | 15 +- lc3vm/src/ls3.cpp | 145 +++++- lc3vm/src/main.cpp | 32 +- 4 files changed, 1322 insertions(+), 11 deletions(-) create mode 100644 lc3vm/2048.asm diff --git a/lc3vm/2048.asm b/lc3vm/2048.asm new file mode 100644 index 0000000..cf4d9bf --- /dev/null +++ b/lc3vm/2048.asm @@ -0,0 +1,1141 @@ +Loading image: ../obj/2048.obj +Disassembling memory... + +Disassembling segment from 0x3000 to 0x3470: +0x3000: LD R6, 0x3018 +0x3001: LEA R5, 0x301a +0x3002: LEA R0, 0x3085 +0x3003: TRAP x22 +0x3004: LEA R0, 0x302d +0x3005: JSR 0x3283 +0x3006: BRp 0x300b +0x3007: STI R0, 0x302a +0x3008: LD R1, 0x302b +0x3009: LD R2, 0x302c +0x300a: STR R2, R1, #0 +0x300b: JSR 0x30a8 +0x300c: JSR 0x31ea +0x300d: JSR 0x30b7 +0x300e: LD R0, 0x3019 +0x300f: BRp 0x3011 +0x3010: BRnzp 0x300c +0x3011: JSR 0x31ea +0x3012: LEA R0, 0x3076 +0x3013: TRAP x22 +0x3014: LEA R0, 0x3051 +0x3015: JSR 0x3283 +0x3016: BRp 0x300b +0x3017: TRAP x25 +0x3018: JSR R0 +0x3019: BR 0x301a +0x301a: BR 0x301c +0x301b: BR 0x3023 +0x301c: BR 0x3025 +0x301d: BR 0x302d +0x301e: BR 0x3020 +0x301f: BR 0x3026 +0x3020: BR 0x302a +0x3021: BR 0x3030 +0x3022: BR 0x3025 +0x3023: BR 0x3029 +0x3024: BR 0x302f +0x3025: BR 0x3033 +0x3026: BR 0x302a +0x3027: BR 0x302c +0x3028: BR 0x3034 +0x3029: BR 0x3036 +0x302a: ST R1, 0x3047 +0x302b: ST R1, 0x3097 +0x302c: ST R1, 0x312a +0x302d: BR 0x306f +0x302e: BR 0x30a1 +0x302f: BR 0x3095 +0x3030: BR 0x3051 +0x3031: BR 0x30ab +0x3032: BR 0x30a2 +0x3033: BR 0x30a9 +0x3034: BR 0x3055 +0x3035: BR 0x30a5 +0x3036: BR 0x30a5 +0x3037: BR 0x3058 +0x3038: BR 0x309a +0x3039: BR 0x30a8 +0x303a: BR 0x305b +0x303b: BR 0x307d +0x303c: BR 0x308b +0x303d: BR 0x3091 +0x303e: BR 0x3088 +0x303f: BR 0x3060 +0x3040: BR 0x30b5 +0x3041: BR 0x30a7 +0x3042: BR 0x30b5 +0x3043: BR 0x30b1 +0x3044: BR 0x30ae +0x3045: BR 0x30b4 +0x3046: BR 0x30a8 +0x3047: BR 0x30b4 +0x3048: BR 0x3069 +0x3049: BR 0x3072 +0x304a: BR 0x30c4 +0x304b: BR 0x307b +0x304c: BR 0x30bb +0x304d: BR 0x3077 +0x304e: BR 0x308e +0x304f: BR 0x3070 +0x3050: BR 0x3051 +0x3051: BR 0x30a9 +0x3052: BR 0x30c2 +0x3053: BR 0x30c9 +0x3054: BR 0x30c1 +0x3055: BR 0x30ba +0x3056: BR 0x3077 +0x3057: BR 0x30d1 +0x3058: BR 0x30c8 +0x3059: BR 0x30cf +0x305a: BR 0x307b +0x305b: BR 0x30c8 +0x305c: BR 0x30c6 +0x305d: BR 0x30c9 +0x305e: BR 0x30c4 +0x305f: BR 0x3080 +0x3060: BR 0x30d5 +0x3061: BR 0x30d1 +0x3062: BR 0x3083 +0x3063: BR 0x30d4 +0x3064: BR 0x30d1 +0x3065: BR 0x30c7 +0x3066: BR 0x30e0 +0x3067: BR 0x3088 +0x3068: BR 0x30ca +0x3069: BR 0x30d1 +0x306a: BR 0x30cc +0x306b: BR 0x30d5 +0x306c: BR 0x30db +0x306d: BR 0x308e +0x306e: BR 0x3097 +0x306f: BR 0x30e9 +0x3070: BR 0x30a0 +0x3071: BR 0x30e0 +0x3072: BR 0x309c +0x3073: BR 0x30b3 +0x3074: BR 0x3095 +0x3075: BR 0x3076 +0x3076: BR 0x3081 +0x3077: BR 0x30d1 +0x3078: BR 0x30e8 +0x3079: BR 0x30ef +0x307a: BR 0x309b +0x307b: BR 0x30e8 +0x307c: BR 0x30ec +0x307d: BR 0x30f1 +0x307e: BR 0x30f3 +0x307f: BR 0x30a0 +0x3080: BR 0x30bb +0x3081: BR 0x30aa +0x3082: BR 0x308d +0x3083: BR 0x308e +0x3084: BR 0x3085 +0x3085: BR 0x30c9 +0x3086: BR 0x30f6 +0x3087: BR 0x30f6 +0x3088: BR 0x30fd +0x3089: BR 0x30fc +0x308a: BR 0x30fa +0x308b: BR 0x30f8 +0x308c: BR 0x30ad +0x308d: BR 0x3102 +0x308e: BR 0x30f7 +0x308f: BR 0x30f5 +0x3090: BR 0x30b1 +0x3091: BR 0x30f9 +0x3092: BR 0x30f4 +0x3093: BR 0x3101 +0x3094: BR 0x30fa +0x3095: BR 0x30b6 +0x3096: BR 0x310c +0x3097: BR 0x310b +0x3098: BR 0x3102 +0x3099: BR 0x3108 +0x309a: BR 0x3102 +0x309b: BR 0x30bc +0x309c: BR 0x30f4 +0x309d: BR 0x30df +0x309e: BR 0x30f2 +0x309f: BR 0x30e4 +0x30a0: BR 0x30c1 +0x30a1: BR 0x310d +0x30a2: BR 0x3108 +0x30a3: BR 0x311d +0x30a4: BR 0x3118 +0x30a5: BR 0x30d4 +0x30a6: BR 0x30b1 +0x30a7: BR 0x30a8 +0x30a8: STR R7, R6, #-1 +0x30a9: ADD R6, R6, #-1 +0x30aa: AND R0, R0, #0 +0x30ab: AND R1, R1, #0 +0x30ac: ST R0, 0x3019 +0x30ad: ADD R2, R1, R5 +0x30ae: STR R0, R2, #0 +0x30af: ADD R1, R1, #1 +0x30b0: ADD R2, R1, #-16 +0x30b1: BRn 0x30ad +0x30b2: JSR 0x319b +0x30b3: JSR 0x319b +0x30b4: LDR R7, R6, #0 +0x30b5: ADD R6, R6, #1 +0x30b6: RET +0x30b7: STR R7, R6, #-1 +0x30b8: ADD R6, R6, #-1 +0x30b9: TRAP x20 +0x30ba: LD R1, 0x30e4 +0x30bb: ADD R1, R0, R1 +0x30bc: BRz 0x30cf +0x30bd: LD R1, 0x30e5 +0x30be: ADD R1, R0, R1 +0x30bf: BRz 0x30c7 +0x30c0: LD R1, 0x30e6 +0x30c1: ADD R1, R0, R1 +0x30c2: BRz 0x30d5 +0x30c3: LD R1, 0x30e7 +0x30c4: ADD R1, R0, R1 +0x30c5: BRz 0x30c9 +0x30c6: BRnzp 0x30b9 +0x30c7: JSR 0x3119 +0x30c8: BRnzp 0x30da +0x30c9: JSR 0x30e8 +0x30ca: JSR 0x30e8 +0x30cb: JSR 0x3119 +0x30cc: JSR 0x30e8 +0x30cd: JSR 0x30e8 +0x30ce: BRnzp 0x30da +0x30cf: JSR 0x30e8 +0x30d0: JSR 0x30e8 +0x30d1: JSR 0x30e8 +0x30d2: JSR 0x3119 +0x30d3: JSR 0x30e8 +0x30d4: BRnzp 0x30da +0x30d5: JSR 0x30e8 +0x30d6: JSR 0x3119 +0x30d7: JSR 0x30e8 +0x30d8: JSR 0x30e8 +0x30d9: JSR 0x30e8 +0x30da: ADD R0, R0, #0 +0x30db: BRnz 0x30b9 +0x30dc: JSR 0x319b +0x30dd: ADD R0, R0, #0 +0x30de: BRp 0x30e1 +0x30df: JSR 0x31bc +0x30e0: ST R0, 0x3019 +0x30e1: LDR R7, R6, #0 +0x30e2: ADD R6, R6, #1 +0x30e3: RET +0x30e4: TRAP x89 +0x30e5: TRAP x9f +0x30e6: TRAP x8d +0x30e7: TRAP x9c +0x30e8: STR R0, R6, #-1 +0x30e9: ADD R6, R6, #-1 +0x30ea: LDR R0, R5, #1 +0x30eb: STR R0, R6, #-1 +0x30ec: LDR R0, R5, #2 +0x30ed: STR R0, R6, #-2 +0x30ee: LDR R0, R5, #3 +0x30ef: STR R0, R6, #-3 +0x30f0: ADD R6, R6, #-3 +0x30f1: LDR R0, R5, #0 +0x30f2: STR R0, R5, #3 +0x30f3: LDR R0, R5, #4 +0x30f4: STR R0, R5, #2 +0x30f5: LDR R0, R5, #8 +0x30f6: STR R0, R5, #1 +0x30f7: LDR R0, R5, #12 +0x30f8: STR R0, R5, #0 +0x30f9: LDR R0, R5, #13 +0x30fa: STR R0, R5, #4 +0x30fb: LDR R0, R5, #14 +0x30fc: STR R0, R5, #8 +0x30fd: LDR R0, R5, #15 +0x30fe: STR R0, R5, #12 +0x30ff: LDR R0, R5, #11 +0x3100: STR R0, R5, #13 +0x3101: LDR R0, R5, #7 +0x3102: STR R0, R5, #14 +0x3103: LDR R0, R6, #0 +0x3104: STR R0, R5, #15 +0x3105: LDR R0, R6, #1 +0x3106: STR R0, R5, #11 +0x3107: LDR R0, R6, #2 +0x3108: STR R0, R5, #7 +0x3109: ADD R6, R6, #3 +0x310a: LDR R0, R5, #6 +0x310b: STR R0, R6, #-1 +0x310c: ADD R6, R6, #-1 +0x310d: LDR R0, R5, #5 +0x310e: STR R0, R5, #6 +0x310f: LDR R0, R5, #9 +0x3110: STR R0, R5, #5 +0x3111: LDR R0, R5, #10 +0x3112: STR R0, R5, #9 +0x3113: LDR R0, R6, #0 +0x3114: STR R0, R5, #10 +0x3115: ADD R6, R6, #1 +0x3116: LDR R0, R6, #0 +0x3117: ADD R6, R6, #1 +0x3118: RET +0x3119: STR R7, R6, #-1 +0x311a: STR R1, R6, #-2 +0x311b: ADD R6, R6, #-2 +0x311c: AND R1, R1, #0 +0x311d: ADD R0, R5, #0 +0x311e: JSR 0x312d +0x311f: ADD R1, R0, R1 +0x3120: ADD R0, R5, #4 +0x3121: JSR 0x312d +0x3122: ADD R1, R0, R1 +0x3123: ADD R0, R5, #8 +0x3124: JSR 0x312d +0x3125: ADD R1, R0, R1 +0x3126: ADD R0, R5, #12 +0x3127: JSR 0x312d +0x3128: ADD R0, R0, R1 +0x3129: LDR R1, R6, #0 +0x312a: LDR R7, R6, #1 +0x312b: ADD R6, R6, #2 +0x312c: RET +0x312d: STR R1, R6, #-1 +0x312e: ADD R6, R6, #-1 +0x312f: AND R1, R1, #0 +0x3130: AND R2, R2, #0 +0x3131: LDR R4, R0, #0 +0x3132: ADD R3, R4, R4 +0x3133: ADD R3, R3, R3 +0x3134: ADD R3, R3, R3 +0x3135: ADD R3, R3, R3 +0x3136: LDR R4, R0, #1 +0x3137: ADD R3, R3, R4 +0x3138: ADD R3, R3, R3 +0x3139: ADD R3, R3, R3 +0x313a: ADD R3, R3, R3 +0x313b: ADD R3, R3, R3 +0x313c: LDR R4, R0, #2 +0x313d: ADD R3, R3, R4 +0x313e: ADD R3, R3, R3 +0x313f: ADD R3, R3, R3 +0x3140: ADD R3, R3, R3 +0x3141: ADD R3, R3, R3 +0x3142: LDR R4, R0, #3 +0x3143: ADD R3, R3, R4 +0x3144: STR R3, R6, #-1 +0x3145: ADD R6, R6, #-1 +0x3146: ADD R4, R0, R1 +0x3147: LDR R4, R4, #0 +0x3148: BRnz 0x314c +0x3149: ADD R3, R0, R2 +0x314a: ADD R2, R2, #1 +0x314b: STR R4, R3, #0 +0x314c: ADD R1, R1, #1 +0x314d: ADD R4, R1, #-4 +0x314e: BRn 0x3146 +0x314f: AND R1, R1, #0 +0x3150: ADD R4, R2, #-4 +0x3151: BRz 0x3156 +0x3152: ADD R3, R0, R2 +0x3153: ADD R2, R2, #1 +0x3154: STR R1, R3, #0 +0x3155: BRnzp 0x3150 +0x3156: LDR R1, R0, #0 +0x3157: LDR R3, R0, #1 +0x3158: BRz 0x317e +0x3159: NOT R3, R3 +0x315a: ADD R3, R3, #1 +0x315b: ADD R3, R1, R3 +0x315c: BRnp 0x3165 +0x315d: ADD R1, R1, #1 +0x315e: STR R1, R0, #0 +0x315f: LDR R1, R0, #2 +0x3160: STR R1, R0, #1 +0x3161: LDR R1, R0, #3 +0x3162: STR R1, R0, #2 +0x3163: AND R1, R1, #0 +0x3164: STR R1, R0, #3 +0x3165: LDR R1, R0, #1 +0x3166: LDR R3, R0, #2 +0x3167: BRz 0x317e +0x3168: NOT R3, R3 +0x3169: ADD R3, R3, #1 +0x316a: ADD R3, R1, R3 +0x316b: BRnp 0x3173 +0x316c: ADD R1, R1, #1 +0x316d: STR R1, R0, #1 +0x316e: LDR R1, R0, #3 +0x316f: STR R1, R0, #2 +0x3170: AND R1, R1, #0 +0x3171: STR R1, R0, #3 +0x3172: BRnzp 0x317e +0x3173: LDR R1, R0, #2 +0x3174: LDR R3, R0, #3 +0x3175: BRz 0x317e +0x3176: NOT R3, R3 +0x3177: ADD R3, R3, #1 +0x3178: ADD R3, R1, R3 +0x3179: BRnp 0x317e +0x317a: ADD R1, R1, #1 +0x317b: STR R1, R0, #2 +0x317c: AND R1, R1, #0 +0x317d: STR R1, R0, #3 +0x317e: LDR R4, R0, #0 +0x317f: ADD R3, R4, R4 +0x3180: ADD R3, R3, R3 +0x3181: ADD R3, R3, R3 +0x3182: ADD R3, R3, R3 +0x3183: LDR R4, R0, #1 +0x3184: ADD R3, R3, R4 +0x3185: ADD R3, R3, R3 +0x3186: ADD R3, R3, R3 +0x3187: ADD R3, R3, R3 +0x3188: ADD R3, R3, R3 +0x3189: LDR R4, R0, #2 +0x318a: ADD R3, R3, R4 +0x318b: ADD R3, R3, R3 +0x318c: ADD R3, R3, R3 +0x318d: ADD R3, R3, R3 +0x318e: ADD R3, R3, R3 +0x318f: LDR R4, R0, #3 +0x3190: ADD R3, R3, R4 +0x3191: NOT R3, R3 +0x3192: ADD R3, R3, #1 +0x3193: LDR R4, R6, #0 +0x3194: AND R0, R0, #0 +0x3195: ADD R3, R3, R4 +0x3196: BRz 0x3198 +0x3197: ADD R0, R0, #1 +0x3198: LDR R1, R6, #1 +0x3199: ADD R6, R6, #2 +0x319a: RET +0x319b: STR R7, R6, #-1 +0x319c: ADD R6, R6, #-1 +0x319d: AND R1, R1, #0 +0x319e: AND R2, R2, #0 +0x319f: ADD R0, R2, R5 +0x31a0: ADD R2, R2, #1 +0x31a1: STR R0, R6, #-1 +0x31a2: LDR R0, R0, #0 +0x31a3: BRp 0x31a6 +0x31a4: ADD R1, R1, #1 +0x31a5: ADD R6, R6, #-1 +0x31a6: ADD R0, R2, #-16 +0x31a7: BRn 0x319f +0x31a8: ADD R0, R1, #0 +0x31a9: BRz 0x31b7 +0x31aa: JSR 0x326c +0x31ab: ADD R2, R0, R6 +0x31ac: LD R0, 0x31bb +0x31ad: JSR 0x326c +0x31ae: ADD R0, R0, #0 +0x31af: BRz 0x31b3 +0x31b0: AND R0, R0, #0 +0x31b1: ADD R0, R0, #1 +0x31b2: BRnzp 0x31b4 +0x31b3: ADD R0, R0, #2 +0x31b4: LDR R2, R2, #0 +0x31b5: STR R0, R2, #0 +0x31b6: ADD R0, R1, #-1 +0x31b7: ADD R6, R6, R1 +0x31b8: LDR R7, R6, #0 +0x31b9: ADD R6, R6, #1 +0x31ba: RET +0x31bb: BR 0x31c7 +0x31bc: STR R7, R6, #-1 +0x31bd: ADD R6, R6, #-1 +0x31be: AND R4, R4, #0 +0x31bf: ADD R4, R4, #1 +0x31c0: ADD R0, R5, #0 +0x31c1: JSR 0x31d9 +0x31c2: BRz 0x31d0 +0x31c3: ADD R0, R5, #4 +0x31c4: JSR 0x31d9 +0x31c5: BRz 0x31d0 +0x31c6: ADD R0, R5, #8 +0x31c7: JSR 0x31d9 +0x31c8: BRz 0x31d0 +0x31c9: ADD R0, R5, #12 +0x31ca: JSR 0x31d9 +0x31cb: BRz 0x31d0 +0x31cc: ADD R4, R4, #-1 +0x31cd: BRn 0x31d0 +0x31ce: JSR 0x30e8 +0x31cf: BRnzp 0x31c0 +0x31d0: ADD R4, R4, #0 +0x31d1: BRp 0x31d5 +0x31d2: JSR 0x30e8 +0x31d3: JSR 0x30e8 +0x31d4: JSR 0x30e8 +0x31d5: LDR R7, R6, #0 +0x31d6: ADD R6, R6, #1 +0x31d7: ADD R0, R1, #0 +0x31d8: RET +0x31d9: LDR R2, R0, #0 +0x31da: LDR R3, R0, #1 +0x31db: NOT R3, R3 +0x31dc: ADD R3, R3, #1 +0x31dd: ADD R1, R2, R3 +0x31de: BRz 0x31e9 +0x31df: LDR R2, R0, #2 +0x31e0: ADD R1, R2, R3 +0x31e1: BRz 0x31e9 +0x31e2: LDR R3, R0, #3 +0x31e3: NOT R3, R3 +0x31e4: ADD R3, R3, #1 +0x31e5: ADD R1, R2, R3 +0x31e6: BRz 0x31e9 +0x31e7: AND R1, R1, #0 +0x31e8: ADD R1, R1, #1 +0x31e9: RET +0x31ea: STR R7, R6, #-1 +0x31eb: ADD R6, R6, #-1 +0x31ec: LEA R0, 0x321c +0x31ed: TRAP x22 +0x31ee: LD R1, 0x326b +0x31ef: AND R2, R2, #0 +0x31f0: LEA R0, 0x3228 +0x31f1: TRAP x22 +0x31f2: LD R0, 0x326a +0x31f3: TRAP x21 +0x31f4: LEA R0, 0x3245 +0x31f5: TRAP x22 +0x31f6: LD R0, 0x326a +0x31f7: TRAP x21 +0x31f8: LEA R0, 0x3262 +0x31f9: TRAP x22 +0x31fa: LD R0, 0x3269 +0x31fb: TRAP x21 +0x31fc: ADD R3, R5, R2 +0x31fd: LDR R3, R3, #0 +0x31fe: ADD R2, R2, #1 +0x31ff: ADD R0, R1, R3 +0x3200: LDR R0, R0, #0 +0x3201: TRAP x22 +0x3202: LD R0, 0x3269 +0x3203: TRAP x21 +0x3204: ADD R0, R2, #-4 +0x3205: BRz 0x320d +0x3206: ADD R0, R2, #-8 +0x3207: BRz 0x320d +0x3208: ADD R0, R2, #-12 +0x3209: BRz 0x320d +0x320a: ADD R0, R2, #-16 +0x320b: BRz 0x320d +0x320c: BRnp 0x31fa +0x320d: LEA R0, 0x3265 +0x320e: TRAP x22 +0x320f: ADD R0, R2, #-16 +0x3210: BRnp 0x31f4 +0x3211: LEA R0, 0x3245 +0x3212: TRAP x22 +0x3213: LD R0, 0x326a +0x3214: TRAP x21 +0x3215: LEA R0, 0x3228 +0x3216: TRAP x22 +0x3217: LD R0, 0x326a +0x3218: TRAP x21 +0x3219: LDR R7, R6, #0 +0x321a: ADD R6, R6, #1 +0x321b: RET +0x321c: BR 0x3238 +0x321d: BR 0x3279 +0x321e: BR 0x3251 +0x321f: BR 0x326a +0x3220: BR 0x323c +0x3221: BR 0x327d +0x3222: BR 0x326b +0x3223: BR 0x323f +0x3224: BR 0x3280 +0x3225: BR 0x3259 +0x3226: BR 0x3271 +0x3227: BR 0x3228 +0x3228: BR 0x3254 +0x3229: BR 0x3257 +0x322a: BR 0x3258 +0x322b: BR 0x3259 +0x322c: BR 0x325a +0x322d: BR 0x325b +0x322e: BR 0x325c +0x322f: BR 0x325d +0x3230: BR 0x325e +0x3231: BR 0x325f +0x3232: BR 0x3260 +0x3233: BR 0x3261 +0x3234: BR 0x3262 +0x3235: BR 0x3263 +0x3236: BR 0x3264 +0x3237: BR 0x3265 +0x3238: BR 0x3266 +0x3239: BR 0x3267 +0x323a: BR 0x3268 +0x323b: BR 0x3269 +0x323c: BR 0x326a +0x323d: BR 0x326b +0x323e: BR 0x326c +0x323f: BR 0x326d +0x3240: BR 0x326e +0x3241: BR 0x326f +0x3242: BR 0x3270 +0x3243: BR 0x326f +0x3244: BR 0x3245 +0x3245: BR 0x32c2 +0x3246: BR 0x3267 +0x3247: BR 0x3268 +0x3248: BR 0x3269 +0x3249: BR 0x326a +0x324a: BR 0x326b +0x324b: BR 0x326c +0x324c: BR 0x326d +0x324d: BR 0x326e +0x324e: BR 0x326f +0x324f: BR 0x3270 +0x3250: BR 0x3271 +0x3251: BR 0x3272 +0x3252: BR 0x3273 +0x3253: BR 0x3274 +0x3254: BR 0x3275 +0x3255: BR 0x3276 +0x3256: BR 0x3277 +0x3257: BR 0x3278 +0x3258: BR 0x3279 +0x3259: BR 0x327a +0x325a: BR 0x327b +0x325b: BR 0x327c +0x325c: BR 0x327d +0x325d: BR 0x327e +0x325e: BR 0x327f +0x325f: BR 0x3280 +0x3260: BR 0x32dd +0x3261: BR 0x3262 +0x3262: BR 0x32df +0x3263: BR 0x3284 +0x3264: BR 0x3265 +0x3265: BR 0x3286 +0x3266: BR 0x32e3 +0x3267: BR 0x3272 +0x3268: BR 0x3269 +0x3269: BR 0x328a +0x326a: BR 0x3275 +0x326b: ST R1, 0x317a +0x326c: STR R0, R6, #-1 +0x326d: STR R1, R6, #-2 +0x326e: STR R2, R6, #-3 +0x326f: STR R7, R6, #-4 +0x3270: ADD R6, R6, #-4 +0x3271: LD R0, 0x327f +0x3272: LD R1, 0x3282 +0x3273: JSR 0x32cf +0x3274: LD R1, 0x3280 +0x3275: JSR 0x32e3 +0x3276: ST R0, 0x327f +0x3277: LDR R1, R6, #3 +0x3278: JSR 0x32cf +0x3279: LDR R7, R6, #0 +0x327a: LDR R2, R6, #1 +0x327b: LDR R1, R6, #2 +0x327c: ADD R6, R6, #4 +0x327d: RET +0x327e: BR 0x327f +0x327f: JMP R0 +0x3280: BR 0x3288 +0x3281: STR R7, R7, #-1 +0x3282: ADD R1, R1, R1 +0x3283: STR R0, R6, #-1 +0x3284: STR R1, R6, #-2 +0x3285: STR R7, R6, #-3 +0x3286: ADD R6, R6, #-3 +0x3287: LDR R0, R6, #2 +0x3288: TRAP x22 +0x3289: JSR 0x32be +0x328a: TRAP x21 +0x328b: ADD R1, R0, #0 +0x328c: LD R0, 0x32bd +0x328d: TRAP x21 +0x328e: LD R0, 0x32bb +0x328f: ADD R0, R0, R1 +0x3290: BRz 0x329b +0x3291: LD R0, 0x32bc +0x3292: ADD R0, R0, R1 +0x3293: BRz 0x3299 +0x3294: ADD R0, R1, #0 +0x3295: TRAP x21 +0x3296: LEA R0, 0x32a2 +0x3297: TRAP x22 +0x3298: BRnzp 0x3287 +0x3299: AND R0, R0, #0 +0x329a: BRnzp 0x329d +0x329b: AND R0, R0, #0 +0x329c: ADD R0, R0, #1 +0x329d: LDR R7, R6, #0 +0x329e: LDR R1, R6, #1 +0x329f: ADD R6, R6, #3 +0x32a0: ADD R0, R0, #0 +0x32a1: RET +0x32a2: BR 0x32c3 +0x32a3: BR 0x330d +0x32a4: BR 0x3318 +0x32a5: BR 0x32c6 +0x32a6: BR 0x3315 +0x32a7: BR 0x3317 +0x32a8: BR 0x331d +0x32a9: BR 0x32ca +0x32aa: BR 0x330c +0x32ab: BR 0x32cc +0x32ac: BR 0x3323 +0x32ad: BR 0x330f +0x32ae: BR 0x331b +0x32af: BR 0x3319 +0x32b0: BR 0x3315 +0x32b1: BR 0x32d2 +0x32b2: BR 0x331c +0x32b3: BR 0x3322 +0x32b4: BR 0x3325 +0x32b5: BR 0x332b +0x32b6: BR 0x332b +0x32b7: BR 0x32e6 +0x32b8: BR 0x32c3 +0x32b9: BR 0x32c4 +0x32ba: BR 0x32bb +0x32bb: TRAP x87 +0x32bc: TRAP x92 +0x32bd: BR 0x32c8 +0x32be: STR R1, R6, #-1 +0x32bf: ADD R6, R6, #-1 +0x32c0: AND R1, R1, #0 +0x32c1: ADD R1, R1, #1 +0x32c2: LDI R0, 0x32cc +0x32c3: BRzp 0x32c1 +0x32c4: LD R0, 0x32ce +0x32c5: AND R1, R1, R0 +0x32c6: LDI R0, 0x32cd +0x32c7: ST R1, 0x327f +0x32c8: ST R1, 0x327e +0x32c9: LDR R1, R6, #0 +0x32ca: ADD R6, R6, #1 +0x32cb: RET +0x32cc: TRAP x00 +0x32cd: TRAP x02 +0x32ce: STR R7, R7, #-1 +0x32cf: STR R1, R6, #-1 +0x32d0: STR R2, R6, #-2 +0x32d1: STR R3, R6, #-3 +0x32d2: ADD R6, R6, #-3 +0x32d3: NOT R2, R1 +0x32d4: ADD R2, R2, #1 +0x32d5: BRz 0x32e2 +0x32d6: AND R1, R1, #0 +0x32d7: ADD R1, R1, #1 +0x32d8: ADD R0, R0, R2 +0x32d9: BRp 0x32d7 +0x32da: BRz 0x32de +0x32db: LDR R2, R6, #2 +0x32dc: ADD R1, R1, #-1 +0x32dd: ADD R0, R0, R2 +0x32de: LDR R3, R6, #0 +0x32df: LDR R2, R6, #1 +0x32e0: ADD R6, R6, #3 +0x32e1: RET +0x32e2: TRAP x25 +0x32e3: ADD R0, R0, #0 +0x32e4: BRz 0x32fb +0x32e5: ADD R1, R1, #0 +0x32e6: BRz 0x32fb +0x32e7: STR R1, R6, #-1 +0x32e8: STR R2, R6, #-2 +0x32e9: STR R3, R6, #-3 +0x32ea: STR R4, R6, #-4 +0x32eb: ADD R6, R6, #-4 +0x32ec: AND R2, R2, #0 +0x32ed: ADD R3, R2, #1 +0x32ee: AND R4, R0, R3 +0x32ef: BRnz 0x32f1 +0x32f0: ADD R2, R2, R1 +0x32f1: ADD R1, R1, R1 +0x32f2: ADD R3, R3, R3 +0x32f3: BRp 0x32ee +0x32f4: ADD R0, R2, #0 +0x32f5: LDR R4, R6, #0 +0x32f6: LDR R3, R6, #1 +0x32f7: LDR R2, R6, #2 +0x32f8: LDR R1, R6, #3 +0x32f9: ADD R6, R6, #4 +0x32fa: RET +0x32fb: AND R0, R0, #0 +0x32fc: RET +0x32fd: ST R1, 0x321d +0x32fe: ST R1, 0x3223 +0x32ff: ST R1, 0x3229 +0x3300: ST R1, 0x322f +0x3301: ST R1, 0x3235 +0x3302: ST R1, 0x323b +0x3303: ST R1, 0x3241 +0x3304: ST R1, 0x3247 +0x3305: ST R1, 0x324d +0x3306: ST R1, 0x3253 +0x3307: ST R1, 0x3259 +0x3308: ST R1, 0x325f +0x3309: ST R1, 0x3265 +0x330a: ST R1, 0x326b +0x330b: ST R1, 0x3271 +0x330c: ST R1, 0x3277 +0x330d: ST R1, 0x327d +0x330e: ST R1, 0x3283 +0x330f: ST R1, 0x3289 +0x3310: ST R1, 0x3298 +0x3311: ST R1, 0x32a9 +0x3312: ST R1, 0x32b8 +0x3313: ST R1, 0x32c7 +0x3314: ST R1, 0x32d8 +0x3315: ST R1, 0x32e9 +0x3316: ST R1, 0x32f8 +0x3317: ST R1, 0x3307 +0x3318: ST R1, 0x3316 +0x3319: ST R2, 0x3327 +0x331a: ST R2, 0x3338 +0x331b: ST R2, 0x3349 +0x331c: ST R2, 0x335b +0x331d: ST R2, 0x336d +0x331e: ST R2, 0x337f +0x331f: BR 0x3340 +0x3320: BR 0x3341 +0x3321: BR 0x3342 +0x3322: BR 0x3343 +0x3323: BR 0x3324 +0x3324: BR 0x3345 +0x3325: BR 0x3358 +0x3326: BR 0x3347 +0x3327: BR 0x3348 +0x3328: BR 0x3329 +0x3329: BR 0x334a +0x332a: BR 0x335f +0x332b: BR 0x334c +0x332c: BR 0x334d +0x332d: BR 0x332e +0x332e: BR 0x334f +0x332f: BR 0x3368 +0x3330: BR 0x3351 +0x3331: BR 0x3352 +0x3332: BR 0x3333 +0x3333: BR 0x3354 +0x3334: BR 0x3366 +0x3335: BR 0x336c +0x3336: BR 0x3357 +0x3337: BR 0x3338 +0x3338: BR 0x3359 +0x3339: BR 0x336d +0x333a: BR 0x336d +0x333b: BR 0x335c +0x333c: BR 0x333d +0x333d: BR 0x335e +0x333e: BR 0x3375 +0x333f: BR 0x3374 +0x3340: BR 0x3361 +0x3341: BR 0x3342 +0x3342: BR 0x3374 +0x3343: BR 0x3376 +0x3344: BR 0x337d +0x3345: BR 0x3366 +0x3346: BR 0x3347 +0x3347: BR 0x337a +0x3348: BR 0x337e +0x3349: BR 0x3380 +0x334a: BR 0x336b +0x334b: BR 0x334c +0x334c: BR 0x3382 +0x334d: BR 0x337f +0x334e: BR 0x3381 +0x334f: BR 0x3370 +0x3350: BR 0x3351 +0x3351: BR 0x3383 +0x3352: BR 0x3383 +0x3353: BR 0x3386 +0x3354: BR 0x3389 +0x3355: BR 0x3356 +0x3356: BR 0x3389 +0x3357: BR 0x3388 +0x3358: BR 0x338d +0x3359: BR 0x3392 +0x335a: BR 0x335b +0x335b: BR 0x3390 +0x335c: BR 0x338d +0x335d: BR 0x3397 +0x335e: BR 0x3395 +0x335f: BR 0x3360 +0x3360: BR 0x3399 +0x3361: BR 0x3393 +0x3362: BR 0x339c +0x3363: BR 0x3396 +0x3364: BR 0x3365 +0x3365: BR 0x3398 +0x3366: BR 0x33c5 +0x3367: BR 0x3399 +0x3368: BR 0x339d +0x3369: BR 0x336a +0x336a: BR 0x339d +0x336b: BR 0x33ca +0x336c: BR 0x339e +0x336d: BR 0x33a3 +0x336e: BR 0x336f +0x336f: BR 0x33a2 +0x3370: BR 0x33cf +0x3371: BR 0x33a3 +0x3372: BR 0x33a9 +0x3373: BR 0x3374 +0x3374: BR 0x3395 +0x3375: BR 0x3396 +0x3376: BR 0x3397 +0x3377: BR 0x3398 +0x3378: BR 0x3379 +0x3379: BR 0x3395 +0x337a: BR 0x33d6 +0x337b: BR 0x33af +0x337c: BR 0x33b4 +0x337d: BR 0x33eb +0x337e: BR 0x339f +0x337f: BR 0x33b2 +0x3380: BR 0x33a1 +0x3381: BR 0x33a2 +0x3382: BR 0x339e +0x3383: BR 0x33df +0x3384: BR 0x33b5 +0x3385: BR 0x33f3 +0x3386: BR 0x3387 +0x3387: BR 0x33a3 +0x3388: BR 0x33e4 +0x3389: BR 0x33bb +0x338a: BR 0x33c6 +0x338b: BR 0x33bf +0x338c: BR 0x33c4 +0x338d: BR 0x33fb +0x338e: BR 0x33af +0x338f: BR 0x33c4 +0x3390: BR 0x33b1 +0x3391: BR 0x33b2 +0x3392: BR 0x33ae +0x3393: BR 0x33ef +0x3394: BR 0x33c5 +0x3395: BR 0x3403 +0x3396: BR 0x3397 +0x3397: BR 0x33b3 +0x3398: BR 0x33f4 +0x3399: BR 0x33cd +0x339a: BR 0x33cc +0x339b: BR 0x3409 +0x339c: BR 0x33bd +0x339d: BR 0x33d6 +0x339e: BR 0x33bf +0x339f: BR 0x33c0 +0x33a0: BR 0x33bc +0x33a1: BR 0x33fd +0x33a2: BR 0x33d3 +0x33a3: BR 0x3411 +0x33a4: BR 0x33a5 +0x33a5: BR 0x33c1 +0x33a6: BR 0x3402 +0x33a7: BR 0x33db +0x33a8: BR 0x33da +0x33a9: BR 0x3417 +0x33aa: BR 0x33cb +0x33ab: BR 0x33dd +0x33ac: BR 0x33e3 +0x33ad: BR 0x33ce +0x33ae: BR 0x33ca +0x33af: BR 0x340b +0x33b0: BR 0x33e1 +0x33b1: BR 0x341f +0x33b2: BR 0x33b3 +0x33b3: BR 0x33cf +0x33b4: BR 0x3410 +0x33b5: BR 0x33e7 +0x33b6: BR 0x33f2 +0x33b7: BR 0x33eb +0x33b8: BR 0x33ea +0x33b9: BR 0x3427 +0x33ba: BR 0x33db +0x33bb: BR 0x33ef +0x33bc: BR 0x33ef +0x33bd: BR 0x33de +0x33be: BR 0x33da +0x33bf: BR 0x341b +0x33c0: BR 0x33f1 +0x33c1: BR 0x342f +0x33c2: BR 0x33c3 +0x33c3: BR 0x33df +0x33c4: BR 0x3420 +0x33c5: BR 0x33f7 +0x33c6: BR 0x3402 +0x33c7: BR 0x33fb +0x33c8: BR 0x33fa +0x33c9: BR 0x3437 +0x33ca: BR 0x33eb +0x33cb: BR 0x3402 +0x33cc: BR 0x3401 +0x33cd: BR 0x33ee +0x33ce: BR 0x33ea +0x33cf: BR 0x342b +0x33d0: BR 0x3401 +0x33d1: BR 0x343f +0x33d2: BR 0x33d3 +0x33d3: BR 0x33ef +0x33d4: BR 0x3430 +0x33d5: BR 0x3409 +0x33d6: BR 0x340a +0x33d7: BR 0x3445 +0x33d8: BR 0x340a +0x33d9: BR 0x340c +0x33da: BR 0x3413 +0x33db: BR 0x33fc +0x33dc: BR 0x33f8 +0x33dd: BR 0x3439 +0x33de: BR 0x340f +0x33df: BR 0x344d +0x33e0: BR 0x33e1 +0x33e1: BR 0x33fd +0x33e2: BR 0x343e +0x33e3: BR 0x3417 +0x33e4: BR 0x3418 +0x33e5: BR 0x3453 +0x33e6: BR 0x3419 +0x33e7: BR 0x341d +0x33e8: BR 0x341f +0x33e9: BR 0x340a +0x33ea: BR 0x3406 +0x33eb: BR 0x3447 +0x33ec: BR 0x341d +0x33ed: BR 0x345b +0x33ee: BR 0x33ef +0x33ef: BR 0x340b +0x33f0: BR 0x344c +0x33f1: BR 0x3425 +0x33f2: BR 0x3426 +0x33f3: BR 0x3461 +0x33f4: BR 0x342a +0x33f5: BR 0x3427 +0x33f6: BR 0x3429 +0x33f7: BR 0x3418 +0x33f8: BR 0x3414 +0x33f9: BR 0x3455 +0x33fa: BR 0x342b +0x33fb: BR 0x3469 +0x33fc: BR 0x33fd +0x33fd: BR 0x3419 +0x33fe: BR 0x345a +0x33ff: BR 0x3431 +0x3400: BR 0x343c +0x3401: BR 0x3435 +0x3402: BR 0x3436 +0x3403: BR 0x3471 +0x3404: BR 0x3436 +0x3405: BR 0x3436 +0x3406: BR 0x3439 +0x3407: BR 0x343c +0x3408: BR 0x3424 +0x3409: BR 0x3465 +0x340a: BR 0x343b +0x340b: BR 0x3479 +0x340c: BR 0x340d +0x340d: BR 0x3429 +0x340e: BR 0x346a +0x340f: BR 0x3441 +0x3410: BR 0x344c +0x3411: BR 0x3445 +0x3412: BR 0x3446 +0x3413: BR 0x3481 +0x3414: BR 0x3447 +0x3415: BR 0x3446 +0x3416: BR 0x344b +0x3417: BR 0x3450 +0x3418: BR 0x3434 +0x3419: BR 0x3475 +0x341a: BR 0x344b +0x341b: BR 0x3489 +0x341c: BR 0x341d +0x341d: BR 0x3439 +0x341e: BR 0x347a +0x341f: BR 0x3451 +0x3420: BR 0x345c +0x3421: BR 0x3455 +0x3422: BR 0x3456 +0x3423: BR 0x3491 +0x3424: BR 0x3459 +0x3425: BR 0x3456 +0x3426: BR 0x3460 +0x3427: BR 0x345e +0x3428: BR 0x3444 +0x3429: BR 0x3485 +0x342a: BR 0x345b +0x342b: BR 0x3499 +0x342c: BR 0x342d +0x342d: BR 0x3449 +0x342e: BR 0x348a +0x342f: BR 0x3463 +0x3430: BR 0x3468 +0x3431: BR 0x346d +0x3432: BR 0x3467 +0x3433: BR 0x3464 +0x3434: BR 0x34a2 +0x3435: BR 0x346e +0x3436: BR 0x3468 +0x3437: BR 0x3471 +0x3438: BR 0x346b +0x3439: BR 0x3455 +0x343a: BR 0x3496 +0x343b: BR 0x346c +0x343c: BR 0x34aa +0x343d: BR 0x343e +0x343e: BR 0x345a +0x343f: BR 0x349b +0x3440: BR 0x3474 +0x3441: BR 0x3479 +0x3442: BR 0x347e +0x3443: BR 0x3478 +0x3444: BR 0x3475 +0x3445: BR 0x34b3 +0x3446: BR 0x3479 +0x3447: BR 0x34a6 +0x3448: BR 0x347a +0x3449: BR 0x347e +0x344a: BR 0x3466 +0x344b: BR 0x34a7 +0x344c: BR 0x347d +0x344d: BR 0x34bb +0x344e: BR 0x344f +0x344f: BR 0x346b +0x3450: BR 0x34ac +0x3451: BR 0x3485 +0x3452: BR 0x348a +0x3453: BR 0x348f +0x3454: BR 0x3489 +0x3455: BR 0x3486 +0x3456: BR 0x34c4 +0x3457: BR 0x348a +0x3458: BR 0x34b7 +0x3459: BR 0x348b +0x345a: BR 0x3490 +0x345b: BR 0x3477 +0x345c: BR 0x34b8 +0x345d: BR 0x348e +0x345e: BR 0x34cc +0x345f: BR 0x3460 +0x3460: BR 0x347c +0x3461: BR 0x34bd +0x3462: BR 0x3496 +0x3463: BR 0x349b +0x3464: BR 0x34a0 +0x3465: BR 0x349a +0x3466: BR 0x3497 +0x3467: BR 0x34d5 +0x3468: BR 0x349b +0x3469: BR 0x34c8 +0x346a: BR 0x349c +0x346b: BR 0x34a2 +0x346c: BR 0x3488 +0x346d: BR 0x34c9 +0x346e: BR 0x349f +0x346f: BR 0x34dd +0x3470: BR 0x3471 diff --git a/lc3vm/include/lc3.hpp b/lc3vm/include/lc3.hpp index 2efe353..d97ff95 100644 --- a/lc3vm/include/lc3.hpp +++ b/lc3vm/include/lc3.hpp @@ -14,6 +14,15 @@ #include "opcodes.hpp" #include #include +#include + +/** + * @brief Represents a loaded code/data segment in memory. + */ +struct CodeSegment { + std::uint16_t start_address; ///< The starting memory address of the segment. + std::uint16_t size; ///< The size of the segment in words. +}; /** * @brief Represents the state of an LC-3 virtual machine. @@ -40,6 +49,7 @@ class LC3State { void update_flags(std::uint16_t r); bool running; ///< Flag indicating whether the LC-3 VM is currently running. + std::vector loaded_code_segments; ///< Stores info about loaded program segments. /** * @brief Table of function pointers for dispatching LC-3 opcodes. @@ -88,10 +98,11 @@ class LC3State { * @brief Disassembles the instruction at a given memory address. * (Currently not implemented) * @param address The memory address of the instruction to disassemble. + * @return A string representation of the disassembled instruction. */ - void disassemble(std::uint16_t address); + std::string disassemble(std::uint16_t address); /** - * @brief Disassembles all instructions in memory. + * @brief Disassembles all instructions in loaded memory segments. * (Currently not implemented) */ void disassemble_all(); diff --git a/lc3vm/src/ls3.cpp b/lc3vm/src/ls3.cpp index 0f7a820..1bc2645 100644 --- a/lc3vm/src/ls3.cpp +++ b/lc3vm/src/ls3.cpp @@ -18,6 +18,8 @@ #include #include "traps.hpp" #include "flags.hpp" +#include +#include /** * @brief Swaps the endianness of a 16-bit unsigned integer. @@ -235,6 +237,9 @@ void LC3State::load_image(const std::string &filename) { throw std::runtime_error("Image too large for memory at specified origin."); } } + if (words_actually_read > 0) { + loaded_code_segments.push_back({origin, static_cast(words_actually_read)}); + } } LC3State::LC3State() : memory(), reg{}, running(true) { @@ -279,11 +284,143 @@ void LC3State::update_flags(std::uint16_t r_idx) { } } -void LC3State::disassemble(std::uint16_t address) { - (void)address; - std::cout << "Disassembly not yet implemented." << std::endl; +std::string LC3State::disassemble(std::uint16_t address) { + std::uint16_t instr = memory.read(address); + std::uint16_t opcode = instr >> 12; + std::ostringstream oss; + + oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << address << ": "; + + switch (opcode) { + case OP_ADD: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::uint16_t sr1 = (instr >> 6) & 0x7; + oss << "ADD R" << dr << ", R" << sr1 << ", "; + if ((instr >> 5) & 0x1) { // ADD imm + std::int16_t imm5 = static_cast(sign_extend(instr & 0x1F, 5)); + oss << "#" << std::dec << imm5; + } else { // ADD reg + std::uint16_t sr2 = instr & 0x7; + oss << "R" << sr2; + } + break; + } + case OP_AND: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::uint16_t sr1 = (instr >> 6) & 0x7; + oss << "AND R" << dr << ", R" << sr1 << ", "; + if ((instr >> 5) & 0x1) { // AND imm + std::int16_t imm5 = static_cast(sign_extend(instr & 0x1F, 5)); + oss << "#" << std::dec << imm5; + } else { // AND reg + std::uint16_t sr2 = instr & 0x7; + oss << "R" << sr2; + } + break; + } + case OP_NOT: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::uint16_t sr = (instr >> 6) & 0x7; + oss << "NOT R" << dr << ", R" << sr; + break; + } + case OP_BR: { + std::uint16_t n = (instr >> 11) & 0x1; + std::uint16_t z = (instr >> 10) & 0x1; + std::uint16_t p = (instr >> 9) & 0x1; + std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); + oss << "BR" << (n ? "n" : "") << (z ? "z" : "") << (p ? "p" : "") << " 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + break; + } + case OP_JMP: { // Also handles RET + std::uint16_t base_r = (instr >> 6) & 0x7; + if (base_r == 7) { // RET + oss << "RET"; + } else { + oss << "JMP R" << base_r; + } + break; + } + case OP_JSR: { + oss << "JSR "; + if ((instr >> 11) & 1) { // JSR + std::int16_t pc_offset11 = static_cast(sign_extend(instr & 0x7FF, 11)); + oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset11); + } else { // JSRR + std::uint16_t base_r = (instr >> 6) & 0x7; + oss << "R" << base_r; + } + break; + } + case OP_LD: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); + oss << "LD R" << dr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + break; + } + case OP_LDI: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); + oss << "LDI R" << dr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + break; + } + case OP_LDR: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::uint16_t base_r = (instr >> 6) & 0x7; + std::int16_t offset6 = static_cast(sign_extend(instr & 0x3F, 6)); + oss << "LDR R" << dr << ", R" << base_r << ", #" << std::dec << offset6; + break; + } + case OP_LEA: { + std::uint16_t dr = (instr >> 9) & 0x7; + std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); + oss << "LEA R" << dr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + break; + } + case OP_ST: { + std::uint16_t sr = (instr >> 9) & 0x7; + std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); + oss << "ST R" << sr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + break; + } + case OP_STI: { + std::uint16_t sr = (instr >> 9) & 0x7; + std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); + oss << "STI R" << sr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + break; + } + case OP_STR: { + std::uint16_t sr = (instr >> 9) & 0x7; + std::uint16_t base_r = (instr >> 6) & 0x7; + std::int16_t offset6 = static_cast(sign_extend(instr & 0x3F, 6)); + oss << "STR R" << sr << ", R" << base_r << ", #" << std::dec << offset6; + break; + } + case OP_TRAP: { + oss << "TRAP x" << std::hex << std::setfill('0') << std::setw(2) << (instr & 0xFF); + break; + } + case OP_RES: + case OP_RTI: + default: + oss << "BAD OPCODE"; + break; + } + return oss.str(); } void LC3State::disassemble_all() { - std::cout << "Disassembly not yet implemented." << std::endl; + if (loaded_code_segments.empty()) { + std::cout << "No program images loaded. Nothing to disassemble." << std::endl; + return; + } + + for (const auto& segment : loaded_code_segments) { + std::cout << "\nDisassembling segment from 0x" << std::hex << std::setfill('0') << std::setw(4) << segment.start_address + << " to 0x" << std::hex << std::setfill('0') << std::setw(4) << (segment.start_address + segment.size -1) << std::dec << ":\n"; + for (std::uint16_t i = 0; i < segment.size; ++i) { + std::uint16_t current_address = segment.start_address + i; + std::cout << disassemble(current_address) << std::endl; + } + } } \ No newline at end of file diff --git a/lc3vm/src/main.cpp b/lc3vm/src/main.cpp index 109be78..de5a0d5 100644 --- a/lc3vm/src/main.cpp +++ b/lc3vm/src/main.cpp @@ -45,7 +45,7 @@ void handle_sigint(int sig) { */ int main(int argc, const char* argv[]) { if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " [image_file2] ..." << std::endl; + std::cerr << "Usage: " << argv[0] << " [-d|--disassemble] [image_file2] ..." << std::endl; return 1; } @@ -62,16 +62,38 @@ int main(int argc, const char* argv[]) { return 1; } + bool disassemble_mode = false; + int first_image_arg_index = 1; + + if (argc > 1) { + std::string first_arg = argv[1]; + if (first_arg == "-d" || first_arg == "--disassemble") { + disassemble_mode = true; + first_image_arg_index = 2; + if (argc < 3) { + std::cerr << "Usage: " << argv[0] << " [-d|--disassemble] [image_file2] ..." << std::endl; + std::cerr << "Error: At least one image file is required for disassembly." << std::endl; + g_vm_ptr = nullptr; + return 1; + } + } + } + try { - for (int i = 1; i < argc; ++i) { + for (int i = first_image_arg_index; i < argc; ++i) { std::string filename = argv[i]; std::cout << "Loading image: " << filename << std::endl; vm.load_image(filename); } - std::cout << "Starting LC-3 VM..." << std::endl; - vm.run(); - std::cout << "LC-3 VM halted." << std::endl; + if (disassemble_mode) { + std::cout << "Disassembling memory..." << std::endl; + vm.disassemble_all(); + } else { + std::cout << "Starting LC-3 VM..." << std::endl; + vm.run(); + std::cout << "LC-3 VM halted." << std::endl; + } } catch (const std::exception& e) { std::cerr << "VM Runtime Error: " << e.what() << std::endl; From adbc2bd03b41638dda142e375fa90ad86fb7731f Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 22:32:50 +0300 Subject: [PATCH 2/7] fix terminal handle --- lc3vm/Makefile | 7 ++++--- lc3vm/src/ls3.cpp | 18 +++++++++++------- lc3vm/src/main.cpp | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/lc3vm/Makefile b/lc3vm/Makefile index 166af19..12f8b62 100644 --- a/lc3vm/Makefile +++ b/lc3vm/Makefile @@ -6,7 +6,8 @@ BUILD_DIR = build TEST_DIR = tests GTEST_FLAGS = -lgtest -lgtest_main -pthread -VM_TEST_SRCS = src/ls3.cpp src/memory.cpp +VM_SRCS = src/ls3.cpp src/memory.cpp src/terminal_input.cpp +VM_TEST_SRCS = $(VM_SRCS) # Test sources now also include terminal_input.cpp for completeness, though not directly tested by test_basic TEST_MAIN_SRC = src/main.cpp @@ -14,9 +15,9 @@ TEST_MAIN_SRC = src/main.cpp all: $(BUILD_DIR)/lc3vm -$(BUILD_DIR)/lc3vm: $(VM_TEST_SRCS) src/main.cpp +$(BUILD_DIR)/lc3vm: $(VM_SRCS) src/main.cpp mkdir -p $(BUILD_DIR) - $(CC) $(CFLAGS) $(VM_TEST_SRCS) src/main.cpp -o $(BUILD_DIR)/lc3vm + $(CC) $(CFLAGS) $(VM_SRCS) src/main.cpp -o $(BUILD_DIR)/lc3vm test: $(BUILD_DIR)/test_runner $(BUILD_DIR)/test_runner diff --git a/lc3vm/src/ls3.cpp b/lc3vm/src/ls3.cpp index 1bc2645..e7e2ebd 100644 --- a/lc3vm/src/ls3.cpp +++ b/lc3vm/src/ls3.cpp @@ -18,6 +18,7 @@ #include #include "traps.hpp" #include "flags.hpp" +#include // For read() in TRAP_GETC/TRAP_IN #include #include @@ -134,9 +135,10 @@ void LC3State::ins(LC3State& state, std::uint16_t instr) { switch (instr & 0xFF) { case TRAP_GETC: { - char c_in; - std::cin.get(c_in); - state.reg[R_R0] = static_cast(c_in); + char c_in = 0; + if (read(STDIN_FILENO, &c_in, 1) == 1) { + state.reg[R_R0] = static_cast(c_in); + } } state.update_flags(R_R0); break; @@ -157,11 +159,13 @@ void LC3State::ins(LC3State& state, std::uint16_t instr) { } case TRAP_IN: { std::cout << "Enter a character: "; - char c_in_trap; - std::cin.get(c_in_trap); - std::cout.put(c_in_trap); std::cout.flush(); - state.reg[R_R0] = static_cast(c_in_trap); + char c_in_trap = 0; + if (read(STDIN_FILENO, &c_in_trap, 1) == 1) { + std::cout.put(c_in_trap); + std::cout.flush(); + state.reg[R_R0] = static_cast(c_in_trap); + } state.update_flags(R_R0); break; } diff --git a/lc3vm/src/main.cpp b/lc3vm/src/main.cpp index de5a0d5..43fab59 100644 --- a/lc3vm/src/main.cpp +++ b/lc3vm/src/main.cpp @@ -10,6 +10,8 @@ #include #include #include "lc3.hpp" +#include "terminal_input.hpp" // For raw terminal mode +#include // For std::atexit /** * @brief Global pointer to the LC3State instance. @@ -29,6 +31,10 @@ void handle_sigint(int sig) { if (g_vm_ptr) { g_vm_ptr->request_halt(); } + disable_raw_mode(); // Restore terminal settings on SIGINT + // Re-raise signal for default termination (optional, but good practice) + std::signal(sig, SIG_DFL); + std::raise(sig); } } @@ -52,6 +58,16 @@ int main(int argc, const char* argv[]) { LC3State vm; g_vm_ptr = &vm; + // Attempt to enable raw mode right after VM is created + try { + enable_raw_mode(); + std::atexit(disable_raw_mode); // Ensure raw mode is disabled on normal exit + } catch (const std::exception& e) { + std::cerr << "Terminal Setup Error: " << e.what() << std::endl; + // Not setting g_vm_ptr to nullptr here, as sigaction setup hasn't happened yet + return 1; // Exit if raw mode cannot be enabled + } + struct sigaction sa; sa.sa_handler = handle_sigint; sigemptyset(&sa.sa_mask); @@ -97,10 +113,12 @@ int main(int argc, const char* argv[]) { } catch (const std::exception& e) { std::cerr << "VM Runtime Error: " << e.what() << std::endl; + // disable_raw_mode(); // Already handled by atexit for most cases g_vm_ptr = nullptr; return 1; } + // disable_raw_mode(); // Already handled by atexit g_vm_ptr = nullptr; return 0; } From 43f87d9777dbaf59f5998b6c58268b4a082cff99 Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 22:32:52 +0300 Subject: [PATCH 3/7] fixing terminal --- lc3vm/2048.asm | 1141 ------------------------------ lc3vm/include/terminal_input.hpp | 28 + lc3vm/src/ls3.cpp | 2 +- lc3vm/src/main.cpp | 11 +- lc3vm/src/terminal_input.cpp | 41 ++ 5 files changed, 73 insertions(+), 1150 deletions(-) delete mode 100644 lc3vm/2048.asm create mode 100644 lc3vm/include/terminal_input.hpp create mode 100644 lc3vm/src/terminal_input.cpp diff --git a/lc3vm/2048.asm b/lc3vm/2048.asm deleted file mode 100644 index cf4d9bf..0000000 --- a/lc3vm/2048.asm +++ /dev/null @@ -1,1141 +0,0 @@ -Loading image: ../obj/2048.obj -Disassembling memory... - -Disassembling segment from 0x3000 to 0x3470: -0x3000: LD R6, 0x3018 -0x3001: LEA R5, 0x301a -0x3002: LEA R0, 0x3085 -0x3003: TRAP x22 -0x3004: LEA R0, 0x302d -0x3005: JSR 0x3283 -0x3006: BRp 0x300b -0x3007: STI R0, 0x302a -0x3008: LD R1, 0x302b -0x3009: LD R2, 0x302c -0x300a: STR R2, R1, #0 -0x300b: JSR 0x30a8 -0x300c: JSR 0x31ea -0x300d: JSR 0x30b7 -0x300e: LD R0, 0x3019 -0x300f: BRp 0x3011 -0x3010: BRnzp 0x300c -0x3011: JSR 0x31ea -0x3012: LEA R0, 0x3076 -0x3013: TRAP x22 -0x3014: LEA R0, 0x3051 -0x3015: JSR 0x3283 -0x3016: BRp 0x300b -0x3017: TRAP x25 -0x3018: JSR R0 -0x3019: BR 0x301a -0x301a: BR 0x301c -0x301b: BR 0x3023 -0x301c: BR 0x3025 -0x301d: BR 0x302d -0x301e: BR 0x3020 -0x301f: BR 0x3026 -0x3020: BR 0x302a -0x3021: BR 0x3030 -0x3022: BR 0x3025 -0x3023: BR 0x3029 -0x3024: BR 0x302f -0x3025: BR 0x3033 -0x3026: BR 0x302a -0x3027: BR 0x302c -0x3028: BR 0x3034 -0x3029: BR 0x3036 -0x302a: ST R1, 0x3047 -0x302b: ST R1, 0x3097 -0x302c: ST R1, 0x312a -0x302d: BR 0x306f -0x302e: BR 0x30a1 -0x302f: BR 0x3095 -0x3030: BR 0x3051 -0x3031: BR 0x30ab -0x3032: BR 0x30a2 -0x3033: BR 0x30a9 -0x3034: BR 0x3055 -0x3035: BR 0x30a5 -0x3036: BR 0x30a5 -0x3037: BR 0x3058 -0x3038: BR 0x309a -0x3039: BR 0x30a8 -0x303a: BR 0x305b -0x303b: BR 0x307d -0x303c: BR 0x308b -0x303d: BR 0x3091 -0x303e: BR 0x3088 -0x303f: BR 0x3060 -0x3040: BR 0x30b5 -0x3041: BR 0x30a7 -0x3042: BR 0x30b5 -0x3043: BR 0x30b1 -0x3044: BR 0x30ae -0x3045: BR 0x30b4 -0x3046: BR 0x30a8 -0x3047: BR 0x30b4 -0x3048: BR 0x3069 -0x3049: BR 0x3072 -0x304a: BR 0x30c4 -0x304b: BR 0x307b -0x304c: BR 0x30bb -0x304d: BR 0x3077 -0x304e: BR 0x308e -0x304f: BR 0x3070 -0x3050: BR 0x3051 -0x3051: BR 0x30a9 -0x3052: BR 0x30c2 -0x3053: BR 0x30c9 -0x3054: BR 0x30c1 -0x3055: BR 0x30ba -0x3056: BR 0x3077 -0x3057: BR 0x30d1 -0x3058: BR 0x30c8 -0x3059: BR 0x30cf -0x305a: BR 0x307b -0x305b: BR 0x30c8 -0x305c: BR 0x30c6 -0x305d: BR 0x30c9 -0x305e: BR 0x30c4 -0x305f: BR 0x3080 -0x3060: BR 0x30d5 -0x3061: BR 0x30d1 -0x3062: BR 0x3083 -0x3063: BR 0x30d4 -0x3064: BR 0x30d1 -0x3065: BR 0x30c7 -0x3066: BR 0x30e0 -0x3067: BR 0x3088 -0x3068: BR 0x30ca -0x3069: BR 0x30d1 -0x306a: BR 0x30cc -0x306b: BR 0x30d5 -0x306c: BR 0x30db -0x306d: BR 0x308e -0x306e: BR 0x3097 -0x306f: BR 0x30e9 -0x3070: BR 0x30a0 -0x3071: BR 0x30e0 -0x3072: BR 0x309c -0x3073: BR 0x30b3 -0x3074: BR 0x3095 -0x3075: BR 0x3076 -0x3076: BR 0x3081 -0x3077: BR 0x30d1 -0x3078: BR 0x30e8 -0x3079: BR 0x30ef -0x307a: BR 0x309b -0x307b: BR 0x30e8 -0x307c: BR 0x30ec -0x307d: BR 0x30f1 -0x307e: BR 0x30f3 -0x307f: BR 0x30a0 -0x3080: BR 0x30bb -0x3081: BR 0x30aa -0x3082: BR 0x308d -0x3083: BR 0x308e -0x3084: BR 0x3085 -0x3085: BR 0x30c9 -0x3086: BR 0x30f6 -0x3087: BR 0x30f6 -0x3088: BR 0x30fd -0x3089: BR 0x30fc -0x308a: BR 0x30fa -0x308b: BR 0x30f8 -0x308c: BR 0x30ad -0x308d: BR 0x3102 -0x308e: BR 0x30f7 -0x308f: BR 0x30f5 -0x3090: BR 0x30b1 -0x3091: BR 0x30f9 -0x3092: BR 0x30f4 -0x3093: BR 0x3101 -0x3094: BR 0x30fa -0x3095: BR 0x30b6 -0x3096: BR 0x310c -0x3097: BR 0x310b -0x3098: BR 0x3102 -0x3099: BR 0x3108 -0x309a: BR 0x3102 -0x309b: BR 0x30bc -0x309c: BR 0x30f4 -0x309d: BR 0x30df -0x309e: BR 0x30f2 -0x309f: BR 0x30e4 -0x30a0: BR 0x30c1 -0x30a1: BR 0x310d -0x30a2: BR 0x3108 -0x30a3: BR 0x311d -0x30a4: BR 0x3118 -0x30a5: BR 0x30d4 -0x30a6: BR 0x30b1 -0x30a7: BR 0x30a8 -0x30a8: STR R7, R6, #-1 -0x30a9: ADD R6, R6, #-1 -0x30aa: AND R0, R0, #0 -0x30ab: AND R1, R1, #0 -0x30ac: ST R0, 0x3019 -0x30ad: ADD R2, R1, R5 -0x30ae: STR R0, R2, #0 -0x30af: ADD R1, R1, #1 -0x30b0: ADD R2, R1, #-16 -0x30b1: BRn 0x30ad -0x30b2: JSR 0x319b -0x30b3: JSR 0x319b -0x30b4: LDR R7, R6, #0 -0x30b5: ADD R6, R6, #1 -0x30b6: RET -0x30b7: STR R7, R6, #-1 -0x30b8: ADD R6, R6, #-1 -0x30b9: TRAP x20 -0x30ba: LD R1, 0x30e4 -0x30bb: ADD R1, R0, R1 -0x30bc: BRz 0x30cf -0x30bd: LD R1, 0x30e5 -0x30be: ADD R1, R0, R1 -0x30bf: BRz 0x30c7 -0x30c0: LD R1, 0x30e6 -0x30c1: ADD R1, R0, R1 -0x30c2: BRz 0x30d5 -0x30c3: LD R1, 0x30e7 -0x30c4: ADD R1, R0, R1 -0x30c5: BRz 0x30c9 -0x30c6: BRnzp 0x30b9 -0x30c7: JSR 0x3119 -0x30c8: BRnzp 0x30da -0x30c9: JSR 0x30e8 -0x30ca: JSR 0x30e8 -0x30cb: JSR 0x3119 -0x30cc: JSR 0x30e8 -0x30cd: JSR 0x30e8 -0x30ce: BRnzp 0x30da -0x30cf: JSR 0x30e8 -0x30d0: JSR 0x30e8 -0x30d1: JSR 0x30e8 -0x30d2: JSR 0x3119 -0x30d3: JSR 0x30e8 -0x30d4: BRnzp 0x30da -0x30d5: JSR 0x30e8 -0x30d6: JSR 0x3119 -0x30d7: JSR 0x30e8 -0x30d8: JSR 0x30e8 -0x30d9: JSR 0x30e8 -0x30da: ADD R0, R0, #0 -0x30db: BRnz 0x30b9 -0x30dc: JSR 0x319b -0x30dd: ADD R0, R0, #0 -0x30de: BRp 0x30e1 -0x30df: JSR 0x31bc -0x30e0: ST R0, 0x3019 -0x30e1: LDR R7, R6, #0 -0x30e2: ADD R6, R6, #1 -0x30e3: RET -0x30e4: TRAP x89 -0x30e5: TRAP x9f -0x30e6: TRAP x8d -0x30e7: TRAP x9c -0x30e8: STR R0, R6, #-1 -0x30e9: ADD R6, R6, #-1 -0x30ea: LDR R0, R5, #1 -0x30eb: STR R0, R6, #-1 -0x30ec: LDR R0, R5, #2 -0x30ed: STR R0, R6, #-2 -0x30ee: LDR R0, R5, #3 -0x30ef: STR R0, R6, #-3 -0x30f0: ADD R6, R6, #-3 -0x30f1: LDR R0, R5, #0 -0x30f2: STR R0, R5, #3 -0x30f3: LDR R0, R5, #4 -0x30f4: STR R0, R5, #2 -0x30f5: LDR R0, R5, #8 -0x30f6: STR R0, R5, #1 -0x30f7: LDR R0, R5, #12 -0x30f8: STR R0, R5, #0 -0x30f9: LDR R0, R5, #13 -0x30fa: STR R0, R5, #4 -0x30fb: LDR R0, R5, #14 -0x30fc: STR R0, R5, #8 -0x30fd: LDR R0, R5, #15 -0x30fe: STR R0, R5, #12 -0x30ff: LDR R0, R5, #11 -0x3100: STR R0, R5, #13 -0x3101: LDR R0, R5, #7 -0x3102: STR R0, R5, #14 -0x3103: LDR R0, R6, #0 -0x3104: STR R0, R5, #15 -0x3105: LDR R0, R6, #1 -0x3106: STR R0, R5, #11 -0x3107: LDR R0, R6, #2 -0x3108: STR R0, R5, #7 -0x3109: ADD R6, R6, #3 -0x310a: LDR R0, R5, #6 -0x310b: STR R0, R6, #-1 -0x310c: ADD R6, R6, #-1 -0x310d: LDR R0, R5, #5 -0x310e: STR R0, R5, #6 -0x310f: LDR R0, R5, #9 -0x3110: STR R0, R5, #5 -0x3111: LDR R0, R5, #10 -0x3112: STR R0, R5, #9 -0x3113: LDR R0, R6, #0 -0x3114: STR R0, R5, #10 -0x3115: ADD R6, R6, #1 -0x3116: LDR R0, R6, #0 -0x3117: ADD R6, R6, #1 -0x3118: RET -0x3119: STR R7, R6, #-1 -0x311a: STR R1, R6, #-2 -0x311b: ADD R6, R6, #-2 -0x311c: AND R1, R1, #0 -0x311d: ADD R0, R5, #0 -0x311e: JSR 0x312d -0x311f: ADD R1, R0, R1 -0x3120: ADD R0, R5, #4 -0x3121: JSR 0x312d -0x3122: ADD R1, R0, R1 -0x3123: ADD R0, R5, #8 -0x3124: JSR 0x312d -0x3125: ADD R1, R0, R1 -0x3126: ADD R0, R5, #12 -0x3127: JSR 0x312d -0x3128: ADD R0, R0, R1 -0x3129: LDR R1, R6, #0 -0x312a: LDR R7, R6, #1 -0x312b: ADD R6, R6, #2 -0x312c: RET -0x312d: STR R1, R6, #-1 -0x312e: ADD R6, R6, #-1 -0x312f: AND R1, R1, #0 -0x3130: AND R2, R2, #0 -0x3131: LDR R4, R0, #0 -0x3132: ADD R3, R4, R4 -0x3133: ADD R3, R3, R3 -0x3134: ADD R3, R3, R3 -0x3135: ADD R3, R3, R3 -0x3136: LDR R4, R0, #1 -0x3137: ADD R3, R3, R4 -0x3138: ADD R3, R3, R3 -0x3139: ADD R3, R3, R3 -0x313a: ADD R3, R3, R3 -0x313b: ADD R3, R3, R3 -0x313c: LDR R4, R0, #2 -0x313d: ADD R3, R3, R4 -0x313e: ADD R3, R3, R3 -0x313f: ADD R3, R3, R3 -0x3140: ADD R3, R3, R3 -0x3141: ADD R3, R3, R3 -0x3142: LDR R4, R0, #3 -0x3143: ADD R3, R3, R4 -0x3144: STR R3, R6, #-1 -0x3145: ADD R6, R6, #-1 -0x3146: ADD R4, R0, R1 -0x3147: LDR R4, R4, #0 -0x3148: BRnz 0x314c -0x3149: ADD R3, R0, R2 -0x314a: ADD R2, R2, #1 -0x314b: STR R4, R3, #0 -0x314c: ADD R1, R1, #1 -0x314d: ADD R4, R1, #-4 -0x314e: BRn 0x3146 -0x314f: AND R1, R1, #0 -0x3150: ADD R4, R2, #-4 -0x3151: BRz 0x3156 -0x3152: ADD R3, R0, R2 -0x3153: ADD R2, R2, #1 -0x3154: STR R1, R3, #0 -0x3155: BRnzp 0x3150 -0x3156: LDR R1, R0, #0 -0x3157: LDR R3, R0, #1 -0x3158: BRz 0x317e -0x3159: NOT R3, R3 -0x315a: ADD R3, R3, #1 -0x315b: ADD R3, R1, R3 -0x315c: BRnp 0x3165 -0x315d: ADD R1, R1, #1 -0x315e: STR R1, R0, #0 -0x315f: LDR R1, R0, #2 -0x3160: STR R1, R0, #1 -0x3161: LDR R1, R0, #3 -0x3162: STR R1, R0, #2 -0x3163: AND R1, R1, #0 -0x3164: STR R1, R0, #3 -0x3165: LDR R1, R0, #1 -0x3166: LDR R3, R0, #2 -0x3167: BRz 0x317e -0x3168: NOT R3, R3 -0x3169: ADD R3, R3, #1 -0x316a: ADD R3, R1, R3 -0x316b: BRnp 0x3173 -0x316c: ADD R1, R1, #1 -0x316d: STR R1, R0, #1 -0x316e: LDR R1, R0, #3 -0x316f: STR R1, R0, #2 -0x3170: AND R1, R1, #0 -0x3171: STR R1, R0, #3 -0x3172: BRnzp 0x317e -0x3173: LDR R1, R0, #2 -0x3174: LDR R3, R0, #3 -0x3175: BRz 0x317e -0x3176: NOT R3, R3 -0x3177: ADD R3, R3, #1 -0x3178: ADD R3, R1, R3 -0x3179: BRnp 0x317e -0x317a: ADD R1, R1, #1 -0x317b: STR R1, R0, #2 -0x317c: AND R1, R1, #0 -0x317d: STR R1, R0, #3 -0x317e: LDR R4, R0, #0 -0x317f: ADD R3, R4, R4 -0x3180: ADD R3, R3, R3 -0x3181: ADD R3, R3, R3 -0x3182: ADD R3, R3, R3 -0x3183: LDR R4, R0, #1 -0x3184: ADD R3, R3, R4 -0x3185: ADD R3, R3, R3 -0x3186: ADD R3, R3, R3 -0x3187: ADD R3, R3, R3 -0x3188: ADD R3, R3, R3 -0x3189: LDR R4, R0, #2 -0x318a: ADD R3, R3, R4 -0x318b: ADD R3, R3, R3 -0x318c: ADD R3, R3, R3 -0x318d: ADD R3, R3, R3 -0x318e: ADD R3, R3, R3 -0x318f: LDR R4, R0, #3 -0x3190: ADD R3, R3, R4 -0x3191: NOT R3, R3 -0x3192: ADD R3, R3, #1 -0x3193: LDR R4, R6, #0 -0x3194: AND R0, R0, #0 -0x3195: ADD R3, R3, R4 -0x3196: BRz 0x3198 -0x3197: ADD R0, R0, #1 -0x3198: LDR R1, R6, #1 -0x3199: ADD R6, R6, #2 -0x319a: RET -0x319b: STR R7, R6, #-1 -0x319c: ADD R6, R6, #-1 -0x319d: AND R1, R1, #0 -0x319e: AND R2, R2, #0 -0x319f: ADD R0, R2, R5 -0x31a0: ADD R2, R2, #1 -0x31a1: STR R0, R6, #-1 -0x31a2: LDR R0, R0, #0 -0x31a3: BRp 0x31a6 -0x31a4: ADD R1, R1, #1 -0x31a5: ADD R6, R6, #-1 -0x31a6: ADD R0, R2, #-16 -0x31a7: BRn 0x319f -0x31a8: ADD R0, R1, #0 -0x31a9: BRz 0x31b7 -0x31aa: JSR 0x326c -0x31ab: ADD R2, R0, R6 -0x31ac: LD R0, 0x31bb -0x31ad: JSR 0x326c -0x31ae: ADD R0, R0, #0 -0x31af: BRz 0x31b3 -0x31b0: AND R0, R0, #0 -0x31b1: ADD R0, R0, #1 -0x31b2: BRnzp 0x31b4 -0x31b3: ADD R0, R0, #2 -0x31b4: LDR R2, R2, #0 -0x31b5: STR R0, R2, #0 -0x31b6: ADD R0, R1, #-1 -0x31b7: ADD R6, R6, R1 -0x31b8: LDR R7, R6, #0 -0x31b9: ADD R6, R6, #1 -0x31ba: RET -0x31bb: BR 0x31c7 -0x31bc: STR R7, R6, #-1 -0x31bd: ADD R6, R6, #-1 -0x31be: AND R4, R4, #0 -0x31bf: ADD R4, R4, #1 -0x31c0: ADD R0, R5, #0 -0x31c1: JSR 0x31d9 -0x31c2: BRz 0x31d0 -0x31c3: ADD R0, R5, #4 -0x31c4: JSR 0x31d9 -0x31c5: BRz 0x31d0 -0x31c6: ADD R0, R5, #8 -0x31c7: JSR 0x31d9 -0x31c8: BRz 0x31d0 -0x31c9: ADD R0, R5, #12 -0x31ca: JSR 0x31d9 -0x31cb: BRz 0x31d0 -0x31cc: ADD R4, R4, #-1 -0x31cd: BRn 0x31d0 -0x31ce: JSR 0x30e8 -0x31cf: BRnzp 0x31c0 -0x31d0: ADD R4, R4, #0 -0x31d1: BRp 0x31d5 -0x31d2: JSR 0x30e8 -0x31d3: JSR 0x30e8 -0x31d4: JSR 0x30e8 -0x31d5: LDR R7, R6, #0 -0x31d6: ADD R6, R6, #1 -0x31d7: ADD R0, R1, #0 -0x31d8: RET -0x31d9: LDR R2, R0, #0 -0x31da: LDR R3, R0, #1 -0x31db: NOT R3, R3 -0x31dc: ADD R3, R3, #1 -0x31dd: ADD R1, R2, R3 -0x31de: BRz 0x31e9 -0x31df: LDR R2, R0, #2 -0x31e0: ADD R1, R2, R3 -0x31e1: BRz 0x31e9 -0x31e2: LDR R3, R0, #3 -0x31e3: NOT R3, R3 -0x31e4: ADD R3, R3, #1 -0x31e5: ADD R1, R2, R3 -0x31e6: BRz 0x31e9 -0x31e7: AND R1, R1, #0 -0x31e8: ADD R1, R1, #1 -0x31e9: RET -0x31ea: STR R7, R6, #-1 -0x31eb: ADD R6, R6, #-1 -0x31ec: LEA R0, 0x321c -0x31ed: TRAP x22 -0x31ee: LD R1, 0x326b -0x31ef: AND R2, R2, #0 -0x31f0: LEA R0, 0x3228 -0x31f1: TRAP x22 -0x31f2: LD R0, 0x326a -0x31f3: TRAP x21 -0x31f4: LEA R0, 0x3245 -0x31f5: TRAP x22 -0x31f6: LD R0, 0x326a -0x31f7: TRAP x21 -0x31f8: LEA R0, 0x3262 -0x31f9: TRAP x22 -0x31fa: LD R0, 0x3269 -0x31fb: TRAP x21 -0x31fc: ADD R3, R5, R2 -0x31fd: LDR R3, R3, #0 -0x31fe: ADD R2, R2, #1 -0x31ff: ADD R0, R1, R3 -0x3200: LDR R0, R0, #0 -0x3201: TRAP x22 -0x3202: LD R0, 0x3269 -0x3203: TRAP x21 -0x3204: ADD R0, R2, #-4 -0x3205: BRz 0x320d -0x3206: ADD R0, R2, #-8 -0x3207: BRz 0x320d -0x3208: ADD R0, R2, #-12 -0x3209: BRz 0x320d -0x320a: ADD R0, R2, #-16 -0x320b: BRz 0x320d -0x320c: BRnp 0x31fa -0x320d: LEA R0, 0x3265 -0x320e: TRAP x22 -0x320f: ADD R0, R2, #-16 -0x3210: BRnp 0x31f4 -0x3211: LEA R0, 0x3245 -0x3212: TRAP x22 -0x3213: LD R0, 0x326a -0x3214: TRAP x21 -0x3215: LEA R0, 0x3228 -0x3216: TRAP x22 -0x3217: LD R0, 0x326a -0x3218: TRAP x21 -0x3219: LDR R7, R6, #0 -0x321a: ADD R6, R6, #1 -0x321b: RET -0x321c: BR 0x3238 -0x321d: BR 0x3279 -0x321e: BR 0x3251 -0x321f: BR 0x326a -0x3220: BR 0x323c -0x3221: BR 0x327d -0x3222: BR 0x326b -0x3223: BR 0x323f -0x3224: BR 0x3280 -0x3225: BR 0x3259 -0x3226: BR 0x3271 -0x3227: BR 0x3228 -0x3228: BR 0x3254 -0x3229: BR 0x3257 -0x322a: BR 0x3258 -0x322b: BR 0x3259 -0x322c: BR 0x325a -0x322d: BR 0x325b -0x322e: BR 0x325c -0x322f: BR 0x325d -0x3230: BR 0x325e -0x3231: BR 0x325f -0x3232: BR 0x3260 -0x3233: BR 0x3261 -0x3234: BR 0x3262 -0x3235: BR 0x3263 -0x3236: BR 0x3264 -0x3237: BR 0x3265 -0x3238: BR 0x3266 -0x3239: BR 0x3267 -0x323a: BR 0x3268 -0x323b: BR 0x3269 -0x323c: BR 0x326a -0x323d: BR 0x326b -0x323e: BR 0x326c -0x323f: BR 0x326d -0x3240: BR 0x326e -0x3241: BR 0x326f -0x3242: BR 0x3270 -0x3243: BR 0x326f -0x3244: BR 0x3245 -0x3245: BR 0x32c2 -0x3246: BR 0x3267 -0x3247: BR 0x3268 -0x3248: BR 0x3269 -0x3249: BR 0x326a -0x324a: BR 0x326b -0x324b: BR 0x326c -0x324c: BR 0x326d -0x324d: BR 0x326e -0x324e: BR 0x326f -0x324f: BR 0x3270 -0x3250: BR 0x3271 -0x3251: BR 0x3272 -0x3252: BR 0x3273 -0x3253: BR 0x3274 -0x3254: BR 0x3275 -0x3255: BR 0x3276 -0x3256: BR 0x3277 -0x3257: BR 0x3278 -0x3258: BR 0x3279 -0x3259: BR 0x327a -0x325a: BR 0x327b -0x325b: BR 0x327c -0x325c: BR 0x327d -0x325d: BR 0x327e -0x325e: BR 0x327f -0x325f: BR 0x3280 -0x3260: BR 0x32dd -0x3261: BR 0x3262 -0x3262: BR 0x32df -0x3263: BR 0x3284 -0x3264: BR 0x3265 -0x3265: BR 0x3286 -0x3266: BR 0x32e3 -0x3267: BR 0x3272 -0x3268: BR 0x3269 -0x3269: BR 0x328a -0x326a: BR 0x3275 -0x326b: ST R1, 0x317a -0x326c: STR R0, R6, #-1 -0x326d: STR R1, R6, #-2 -0x326e: STR R2, R6, #-3 -0x326f: STR R7, R6, #-4 -0x3270: ADD R6, R6, #-4 -0x3271: LD R0, 0x327f -0x3272: LD R1, 0x3282 -0x3273: JSR 0x32cf -0x3274: LD R1, 0x3280 -0x3275: JSR 0x32e3 -0x3276: ST R0, 0x327f -0x3277: LDR R1, R6, #3 -0x3278: JSR 0x32cf -0x3279: LDR R7, R6, #0 -0x327a: LDR R2, R6, #1 -0x327b: LDR R1, R6, #2 -0x327c: ADD R6, R6, #4 -0x327d: RET -0x327e: BR 0x327f -0x327f: JMP R0 -0x3280: BR 0x3288 -0x3281: STR R7, R7, #-1 -0x3282: ADD R1, R1, R1 -0x3283: STR R0, R6, #-1 -0x3284: STR R1, R6, #-2 -0x3285: STR R7, R6, #-3 -0x3286: ADD R6, R6, #-3 -0x3287: LDR R0, R6, #2 -0x3288: TRAP x22 -0x3289: JSR 0x32be -0x328a: TRAP x21 -0x328b: ADD R1, R0, #0 -0x328c: LD R0, 0x32bd -0x328d: TRAP x21 -0x328e: LD R0, 0x32bb -0x328f: ADD R0, R0, R1 -0x3290: BRz 0x329b -0x3291: LD R0, 0x32bc -0x3292: ADD R0, R0, R1 -0x3293: BRz 0x3299 -0x3294: ADD R0, R1, #0 -0x3295: TRAP x21 -0x3296: LEA R0, 0x32a2 -0x3297: TRAP x22 -0x3298: BRnzp 0x3287 -0x3299: AND R0, R0, #0 -0x329a: BRnzp 0x329d -0x329b: AND R0, R0, #0 -0x329c: ADD R0, R0, #1 -0x329d: LDR R7, R6, #0 -0x329e: LDR R1, R6, #1 -0x329f: ADD R6, R6, #3 -0x32a0: ADD R0, R0, #0 -0x32a1: RET -0x32a2: BR 0x32c3 -0x32a3: BR 0x330d -0x32a4: BR 0x3318 -0x32a5: BR 0x32c6 -0x32a6: BR 0x3315 -0x32a7: BR 0x3317 -0x32a8: BR 0x331d -0x32a9: BR 0x32ca -0x32aa: BR 0x330c -0x32ab: BR 0x32cc -0x32ac: BR 0x3323 -0x32ad: BR 0x330f -0x32ae: BR 0x331b -0x32af: BR 0x3319 -0x32b0: BR 0x3315 -0x32b1: BR 0x32d2 -0x32b2: BR 0x331c -0x32b3: BR 0x3322 -0x32b4: BR 0x3325 -0x32b5: BR 0x332b -0x32b6: BR 0x332b -0x32b7: BR 0x32e6 -0x32b8: BR 0x32c3 -0x32b9: BR 0x32c4 -0x32ba: BR 0x32bb -0x32bb: TRAP x87 -0x32bc: TRAP x92 -0x32bd: BR 0x32c8 -0x32be: STR R1, R6, #-1 -0x32bf: ADD R6, R6, #-1 -0x32c0: AND R1, R1, #0 -0x32c1: ADD R1, R1, #1 -0x32c2: LDI R0, 0x32cc -0x32c3: BRzp 0x32c1 -0x32c4: LD R0, 0x32ce -0x32c5: AND R1, R1, R0 -0x32c6: LDI R0, 0x32cd -0x32c7: ST R1, 0x327f -0x32c8: ST R1, 0x327e -0x32c9: LDR R1, R6, #0 -0x32ca: ADD R6, R6, #1 -0x32cb: RET -0x32cc: TRAP x00 -0x32cd: TRAP x02 -0x32ce: STR R7, R7, #-1 -0x32cf: STR R1, R6, #-1 -0x32d0: STR R2, R6, #-2 -0x32d1: STR R3, R6, #-3 -0x32d2: ADD R6, R6, #-3 -0x32d3: NOT R2, R1 -0x32d4: ADD R2, R2, #1 -0x32d5: BRz 0x32e2 -0x32d6: AND R1, R1, #0 -0x32d7: ADD R1, R1, #1 -0x32d8: ADD R0, R0, R2 -0x32d9: BRp 0x32d7 -0x32da: BRz 0x32de -0x32db: LDR R2, R6, #2 -0x32dc: ADD R1, R1, #-1 -0x32dd: ADD R0, R0, R2 -0x32de: LDR R3, R6, #0 -0x32df: LDR R2, R6, #1 -0x32e0: ADD R6, R6, #3 -0x32e1: RET -0x32e2: TRAP x25 -0x32e3: ADD R0, R0, #0 -0x32e4: BRz 0x32fb -0x32e5: ADD R1, R1, #0 -0x32e6: BRz 0x32fb -0x32e7: STR R1, R6, #-1 -0x32e8: STR R2, R6, #-2 -0x32e9: STR R3, R6, #-3 -0x32ea: STR R4, R6, #-4 -0x32eb: ADD R6, R6, #-4 -0x32ec: AND R2, R2, #0 -0x32ed: ADD R3, R2, #1 -0x32ee: AND R4, R0, R3 -0x32ef: BRnz 0x32f1 -0x32f0: ADD R2, R2, R1 -0x32f1: ADD R1, R1, R1 -0x32f2: ADD R3, R3, R3 -0x32f3: BRp 0x32ee -0x32f4: ADD R0, R2, #0 -0x32f5: LDR R4, R6, #0 -0x32f6: LDR R3, R6, #1 -0x32f7: LDR R2, R6, #2 -0x32f8: LDR R1, R6, #3 -0x32f9: ADD R6, R6, #4 -0x32fa: RET -0x32fb: AND R0, R0, #0 -0x32fc: RET -0x32fd: ST R1, 0x321d -0x32fe: ST R1, 0x3223 -0x32ff: ST R1, 0x3229 -0x3300: ST R1, 0x322f -0x3301: ST R1, 0x3235 -0x3302: ST R1, 0x323b -0x3303: ST R1, 0x3241 -0x3304: ST R1, 0x3247 -0x3305: ST R1, 0x324d -0x3306: ST R1, 0x3253 -0x3307: ST R1, 0x3259 -0x3308: ST R1, 0x325f -0x3309: ST R1, 0x3265 -0x330a: ST R1, 0x326b -0x330b: ST R1, 0x3271 -0x330c: ST R1, 0x3277 -0x330d: ST R1, 0x327d -0x330e: ST R1, 0x3283 -0x330f: ST R1, 0x3289 -0x3310: ST R1, 0x3298 -0x3311: ST R1, 0x32a9 -0x3312: ST R1, 0x32b8 -0x3313: ST R1, 0x32c7 -0x3314: ST R1, 0x32d8 -0x3315: ST R1, 0x32e9 -0x3316: ST R1, 0x32f8 -0x3317: ST R1, 0x3307 -0x3318: ST R1, 0x3316 -0x3319: ST R2, 0x3327 -0x331a: ST R2, 0x3338 -0x331b: ST R2, 0x3349 -0x331c: ST R2, 0x335b -0x331d: ST R2, 0x336d -0x331e: ST R2, 0x337f -0x331f: BR 0x3340 -0x3320: BR 0x3341 -0x3321: BR 0x3342 -0x3322: BR 0x3343 -0x3323: BR 0x3324 -0x3324: BR 0x3345 -0x3325: BR 0x3358 -0x3326: BR 0x3347 -0x3327: BR 0x3348 -0x3328: BR 0x3329 -0x3329: BR 0x334a -0x332a: BR 0x335f -0x332b: BR 0x334c -0x332c: BR 0x334d -0x332d: BR 0x332e -0x332e: BR 0x334f -0x332f: BR 0x3368 -0x3330: BR 0x3351 -0x3331: BR 0x3352 -0x3332: BR 0x3333 -0x3333: BR 0x3354 -0x3334: BR 0x3366 -0x3335: BR 0x336c -0x3336: BR 0x3357 -0x3337: BR 0x3338 -0x3338: BR 0x3359 -0x3339: BR 0x336d -0x333a: BR 0x336d -0x333b: BR 0x335c -0x333c: BR 0x333d -0x333d: BR 0x335e -0x333e: BR 0x3375 -0x333f: BR 0x3374 -0x3340: BR 0x3361 -0x3341: BR 0x3342 -0x3342: BR 0x3374 -0x3343: BR 0x3376 -0x3344: BR 0x337d -0x3345: BR 0x3366 -0x3346: BR 0x3347 -0x3347: BR 0x337a -0x3348: BR 0x337e -0x3349: BR 0x3380 -0x334a: BR 0x336b -0x334b: BR 0x334c -0x334c: BR 0x3382 -0x334d: BR 0x337f -0x334e: BR 0x3381 -0x334f: BR 0x3370 -0x3350: BR 0x3351 -0x3351: BR 0x3383 -0x3352: BR 0x3383 -0x3353: BR 0x3386 -0x3354: BR 0x3389 -0x3355: BR 0x3356 -0x3356: BR 0x3389 -0x3357: BR 0x3388 -0x3358: BR 0x338d -0x3359: BR 0x3392 -0x335a: BR 0x335b -0x335b: BR 0x3390 -0x335c: BR 0x338d -0x335d: BR 0x3397 -0x335e: BR 0x3395 -0x335f: BR 0x3360 -0x3360: BR 0x3399 -0x3361: BR 0x3393 -0x3362: BR 0x339c -0x3363: BR 0x3396 -0x3364: BR 0x3365 -0x3365: BR 0x3398 -0x3366: BR 0x33c5 -0x3367: BR 0x3399 -0x3368: BR 0x339d -0x3369: BR 0x336a -0x336a: BR 0x339d -0x336b: BR 0x33ca -0x336c: BR 0x339e -0x336d: BR 0x33a3 -0x336e: BR 0x336f -0x336f: BR 0x33a2 -0x3370: BR 0x33cf -0x3371: BR 0x33a3 -0x3372: BR 0x33a9 -0x3373: BR 0x3374 -0x3374: BR 0x3395 -0x3375: BR 0x3396 -0x3376: BR 0x3397 -0x3377: BR 0x3398 -0x3378: BR 0x3379 -0x3379: BR 0x3395 -0x337a: BR 0x33d6 -0x337b: BR 0x33af -0x337c: BR 0x33b4 -0x337d: BR 0x33eb -0x337e: BR 0x339f -0x337f: BR 0x33b2 -0x3380: BR 0x33a1 -0x3381: BR 0x33a2 -0x3382: BR 0x339e -0x3383: BR 0x33df -0x3384: BR 0x33b5 -0x3385: BR 0x33f3 -0x3386: BR 0x3387 -0x3387: BR 0x33a3 -0x3388: BR 0x33e4 -0x3389: BR 0x33bb -0x338a: BR 0x33c6 -0x338b: BR 0x33bf -0x338c: BR 0x33c4 -0x338d: BR 0x33fb -0x338e: BR 0x33af -0x338f: BR 0x33c4 -0x3390: BR 0x33b1 -0x3391: BR 0x33b2 -0x3392: BR 0x33ae -0x3393: BR 0x33ef -0x3394: BR 0x33c5 -0x3395: BR 0x3403 -0x3396: BR 0x3397 -0x3397: BR 0x33b3 -0x3398: BR 0x33f4 -0x3399: BR 0x33cd -0x339a: BR 0x33cc -0x339b: BR 0x3409 -0x339c: BR 0x33bd -0x339d: BR 0x33d6 -0x339e: BR 0x33bf -0x339f: BR 0x33c0 -0x33a0: BR 0x33bc -0x33a1: BR 0x33fd -0x33a2: BR 0x33d3 -0x33a3: BR 0x3411 -0x33a4: BR 0x33a5 -0x33a5: BR 0x33c1 -0x33a6: BR 0x3402 -0x33a7: BR 0x33db -0x33a8: BR 0x33da -0x33a9: BR 0x3417 -0x33aa: BR 0x33cb -0x33ab: BR 0x33dd -0x33ac: BR 0x33e3 -0x33ad: BR 0x33ce -0x33ae: BR 0x33ca -0x33af: BR 0x340b -0x33b0: BR 0x33e1 -0x33b1: BR 0x341f -0x33b2: BR 0x33b3 -0x33b3: BR 0x33cf -0x33b4: BR 0x3410 -0x33b5: BR 0x33e7 -0x33b6: BR 0x33f2 -0x33b7: BR 0x33eb -0x33b8: BR 0x33ea -0x33b9: BR 0x3427 -0x33ba: BR 0x33db -0x33bb: BR 0x33ef -0x33bc: BR 0x33ef -0x33bd: BR 0x33de -0x33be: BR 0x33da -0x33bf: BR 0x341b -0x33c0: BR 0x33f1 -0x33c1: BR 0x342f -0x33c2: BR 0x33c3 -0x33c3: BR 0x33df -0x33c4: BR 0x3420 -0x33c5: BR 0x33f7 -0x33c6: BR 0x3402 -0x33c7: BR 0x33fb -0x33c8: BR 0x33fa -0x33c9: BR 0x3437 -0x33ca: BR 0x33eb -0x33cb: BR 0x3402 -0x33cc: BR 0x3401 -0x33cd: BR 0x33ee -0x33ce: BR 0x33ea -0x33cf: BR 0x342b -0x33d0: BR 0x3401 -0x33d1: BR 0x343f -0x33d2: BR 0x33d3 -0x33d3: BR 0x33ef -0x33d4: BR 0x3430 -0x33d5: BR 0x3409 -0x33d6: BR 0x340a -0x33d7: BR 0x3445 -0x33d8: BR 0x340a -0x33d9: BR 0x340c -0x33da: BR 0x3413 -0x33db: BR 0x33fc -0x33dc: BR 0x33f8 -0x33dd: BR 0x3439 -0x33de: BR 0x340f -0x33df: BR 0x344d -0x33e0: BR 0x33e1 -0x33e1: BR 0x33fd -0x33e2: BR 0x343e -0x33e3: BR 0x3417 -0x33e4: BR 0x3418 -0x33e5: BR 0x3453 -0x33e6: BR 0x3419 -0x33e7: BR 0x341d -0x33e8: BR 0x341f -0x33e9: BR 0x340a -0x33ea: BR 0x3406 -0x33eb: BR 0x3447 -0x33ec: BR 0x341d -0x33ed: BR 0x345b -0x33ee: BR 0x33ef -0x33ef: BR 0x340b -0x33f0: BR 0x344c -0x33f1: BR 0x3425 -0x33f2: BR 0x3426 -0x33f3: BR 0x3461 -0x33f4: BR 0x342a -0x33f5: BR 0x3427 -0x33f6: BR 0x3429 -0x33f7: BR 0x3418 -0x33f8: BR 0x3414 -0x33f9: BR 0x3455 -0x33fa: BR 0x342b -0x33fb: BR 0x3469 -0x33fc: BR 0x33fd -0x33fd: BR 0x3419 -0x33fe: BR 0x345a -0x33ff: BR 0x3431 -0x3400: BR 0x343c -0x3401: BR 0x3435 -0x3402: BR 0x3436 -0x3403: BR 0x3471 -0x3404: BR 0x3436 -0x3405: BR 0x3436 -0x3406: BR 0x3439 -0x3407: BR 0x343c -0x3408: BR 0x3424 -0x3409: BR 0x3465 -0x340a: BR 0x343b -0x340b: BR 0x3479 -0x340c: BR 0x340d -0x340d: BR 0x3429 -0x340e: BR 0x346a -0x340f: BR 0x3441 -0x3410: BR 0x344c -0x3411: BR 0x3445 -0x3412: BR 0x3446 -0x3413: BR 0x3481 -0x3414: BR 0x3447 -0x3415: BR 0x3446 -0x3416: BR 0x344b -0x3417: BR 0x3450 -0x3418: BR 0x3434 -0x3419: BR 0x3475 -0x341a: BR 0x344b -0x341b: BR 0x3489 -0x341c: BR 0x341d -0x341d: BR 0x3439 -0x341e: BR 0x347a -0x341f: BR 0x3451 -0x3420: BR 0x345c -0x3421: BR 0x3455 -0x3422: BR 0x3456 -0x3423: BR 0x3491 -0x3424: BR 0x3459 -0x3425: BR 0x3456 -0x3426: BR 0x3460 -0x3427: BR 0x345e -0x3428: BR 0x3444 -0x3429: BR 0x3485 -0x342a: BR 0x345b -0x342b: BR 0x3499 -0x342c: BR 0x342d -0x342d: BR 0x3449 -0x342e: BR 0x348a -0x342f: BR 0x3463 -0x3430: BR 0x3468 -0x3431: BR 0x346d -0x3432: BR 0x3467 -0x3433: BR 0x3464 -0x3434: BR 0x34a2 -0x3435: BR 0x346e -0x3436: BR 0x3468 -0x3437: BR 0x3471 -0x3438: BR 0x346b -0x3439: BR 0x3455 -0x343a: BR 0x3496 -0x343b: BR 0x346c -0x343c: BR 0x34aa -0x343d: BR 0x343e -0x343e: BR 0x345a -0x343f: BR 0x349b -0x3440: BR 0x3474 -0x3441: BR 0x3479 -0x3442: BR 0x347e -0x3443: BR 0x3478 -0x3444: BR 0x3475 -0x3445: BR 0x34b3 -0x3446: BR 0x3479 -0x3447: BR 0x34a6 -0x3448: BR 0x347a -0x3449: BR 0x347e -0x344a: BR 0x3466 -0x344b: BR 0x34a7 -0x344c: BR 0x347d -0x344d: BR 0x34bb -0x344e: BR 0x344f -0x344f: BR 0x346b -0x3450: BR 0x34ac -0x3451: BR 0x3485 -0x3452: BR 0x348a -0x3453: BR 0x348f -0x3454: BR 0x3489 -0x3455: BR 0x3486 -0x3456: BR 0x34c4 -0x3457: BR 0x348a -0x3458: BR 0x34b7 -0x3459: BR 0x348b -0x345a: BR 0x3490 -0x345b: BR 0x3477 -0x345c: BR 0x34b8 -0x345d: BR 0x348e -0x345e: BR 0x34cc -0x345f: BR 0x3460 -0x3460: BR 0x347c -0x3461: BR 0x34bd -0x3462: BR 0x3496 -0x3463: BR 0x349b -0x3464: BR 0x34a0 -0x3465: BR 0x349a -0x3466: BR 0x3497 -0x3467: BR 0x34d5 -0x3468: BR 0x349b -0x3469: BR 0x34c8 -0x346a: BR 0x349c -0x346b: BR 0x34a2 -0x346c: BR 0x3488 -0x346d: BR 0x34c9 -0x346e: BR 0x349f -0x346f: BR 0x34dd -0x3470: BR 0x3471 diff --git a/lc3vm/include/terminal_input.hpp b/lc3vm/include/terminal_input.hpp new file mode 100644 index 0000000..945f784 --- /dev/null +++ b/lc3vm/include/terminal_input.hpp @@ -0,0 +1,28 @@ +#ifndef LC3_TERMINAL_INPUT_H +#define LC3_TERMINAL_INPUT_H + +/** + * @file terminal_input.hpp + * @brief Provides functions to control terminal input mode (raw/canonical). + */ + +/** + * @brief Enables raw input mode for the terminal. + * + * In raw mode: + * - Input is unbuffered (character by character). + * - Input is not echoed to the screen. + * - Special character processing (like Ctrl+C for SIGINT) might be altered, + * so signal handling needs to be robust. + * @throw std::runtime_error if enabling raw mode fails. + */ +void enable_raw_mode(); + +/** + * @brief Disables raw input mode, restoring original terminal settings. + * This function should be called before the program exits to ensure the + * terminal is left in a usable state. + */ +void disable_raw_mode(); + +#endif // LC3_TERMINAL_INPUT_H \ No newline at end of file diff --git a/lc3vm/src/ls3.cpp b/lc3vm/src/ls3.cpp index e7e2ebd..72f134a 100644 --- a/lc3vm/src/ls3.cpp +++ b/lc3vm/src/ls3.cpp @@ -18,7 +18,7 @@ #include #include "traps.hpp" #include "flags.hpp" -#include // For read() in TRAP_GETC/TRAP_IN +#include #include #include diff --git a/lc3vm/src/main.cpp b/lc3vm/src/main.cpp index 43fab59..2c0ec52 100644 --- a/lc3vm/src/main.cpp +++ b/lc3vm/src/main.cpp @@ -31,8 +31,7 @@ void handle_sigint(int sig) { if (g_vm_ptr) { g_vm_ptr->request_halt(); } - disable_raw_mode(); // Restore terminal settings on SIGINT - // Re-raise signal for default termination (optional, but good practice) + disable_raw_mode(); std::signal(sig, SIG_DFL); std::raise(sig); } @@ -58,14 +57,12 @@ int main(int argc, const char* argv[]) { LC3State vm; g_vm_ptr = &vm; - // Attempt to enable raw mode right after VM is created try { enable_raw_mode(); - std::atexit(disable_raw_mode); // Ensure raw mode is disabled on normal exit + std::atexit(disable_raw_mode); } catch (const std::exception& e) { std::cerr << "Terminal Setup Error: " << e.what() << std::endl; - // Not setting g_vm_ptr to nullptr here, as sigaction setup hasn't happened yet - return 1; // Exit if raw mode cannot be enabled + return 1; } struct sigaction sa; @@ -113,12 +110,10 @@ int main(int argc, const char* argv[]) { } catch (const std::exception& e) { std::cerr << "VM Runtime Error: " << e.what() << std::endl; - // disable_raw_mode(); // Already handled by atexit for most cases g_vm_ptr = nullptr; return 1; } - // disable_raw_mode(); // Already handled by atexit g_vm_ptr = nullptr; return 0; } diff --git a/lc3vm/src/terminal_input.cpp b/lc3vm/src/terminal_input.cpp new file mode 100644 index 0000000..728b9c1 --- /dev/null +++ b/lc3vm/src/terminal_input.cpp @@ -0,0 +1,41 @@ +#include "terminal_input.hpp" +#include +#include +#include +#include + +static struct termios original_termios; +static bool raw_mode_enabled = false; + +void enable_raw_mode() { + if (tcgetattr(STDIN_FILENO, &original_termios) == -1) { + perror("tcgetattr"); + throw std::runtime_error("Failed to get terminal attributes."); + } + + struct termios raw = original_termios; + + raw.c_iflag &= ~(BRKINT | INPCK | ISTRIP | IXON); + + raw.c_cflag |= (CS8); + + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN); + + raw.c_cc[VMIN] = 1; + raw.c_cc[VTIME] = 0; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { + perror("tcsetattr"); + throw std::runtime_error("Failed to set terminal to raw mode."); + } + raw_mode_enabled = true; +} + +void disable_raw_mode() { + if (raw_mode_enabled) { + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &original_termios) == -1) { + perror("disable_raw_mode: tcsetattr"); + } + raw_mode_enabled = false; + } +} \ No newline at end of file From e0025ec802bcd1de0e09c8605bbdc71769de21ef Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 22:53:10 +0300 Subject: [PATCH 4/7] add tests --- lc3vm/Makefile | 19 +- lc3vm/src/ls3.cpp | 18 +- lc3vm/tests/test_basic.cpp | 308 -------------------------- lc3vm/tests/test_disassembly.cpp | 133 +++++++++++ lc3vm/tests/test_initialization.cpp | 17 ++ lc3vm/tests/test_main.cpp | 6 + lc3vm/tests/test_opcode_execution.cpp | 192 ++++++++++++++++ 7 files changed, 372 insertions(+), 321 deletions(-) delete mode 100644 lc3vm/tests/test_basic.cpp create mode 100644 lc3vm/tests/test_disassembly.cpp create mode 100644 lc3vm/tests/test_initialization.cpp create mode 100644 lc3vm/tests/test_main.cpp create mode 100644 lc3vm/tests/test_opcode_execution.cpp diff --git a/lc3vm/Makefile b/lc3vm/Makefile index 12f8b62..261084f 100644 --- a/lc3vm/Makefile +++ b/lc3vm/Makefile @@ -7,9 +7,11 @@ TEST_DIR = tests GTEST_FLAGS = -lgtest -lgtest_main -pthread VM_SRCS = src/ls3.cpp src/memory.cpp src/terminal_input.cpp -VM_TEST_SRCS = $(VM_SRCS) # Test sources now also include terminal_input.cpp for completeness, though not directly tested by test_basic +VM_TEST_SRCS = $(VM_SRCS) -TEST_MAIN_SRC = src/main.cpp +TEST_MAIN_OBJ = $(BUILD_DIR)/test_main.o +TEST_FILES = tests/test_initialization.cpp tests/test_opcode_execution.cpp tests/test_disassembly.cpp +TEST_OBJS = $(TEST_FILES:tests/%.cpp=$(BUILD_DIR)/tests/%.o) .PHONY: all clean test docs @@ -22,13 +24,22 @@ $(BUILD_DIR)/lc3vm: $(VM_SRCS) src/main.cpp test: $(BUILD_DIR)/test_runner $(BUILD_DIR)/test_runner -$(BUILD_DIR)/test_runner: $(TEST_DIR)/test_basic.cpp $(VM_TEST_SRCS) $(TEST_MAIN_SRC) +$(TEST_MAIN_OBJ): tests/test_main.cpp mkdir -p $(BUILD_DIR) - $(CC) $(CFLAGS) -Dmain=disabled_main $(TEST_DIR)/test_basic.cpp $(VM_TEST_SRCS) $(TEST_MAIN_SRC) -o $(BUILD_DIR)/test_runner $(GTEST_FLAGS) $(LDFLAGS_COVERAGE) + $(CC) $(CFLAGS) -c tests/test_main.cpp -o $(TEST_MAIN_OBJ) + +$(BUILD_DIR)/tests/%.o: tests/%.cpp + mkdir -p $(BUILD_DIR)/tests + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/test_runner: $(TEST_MAIN_OBJ) $(TEST_OBJS) $(VM_SRCS) + mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) $(TEST_MAIN_OBJ) $(TEST_OBJS) $(VM_SRCS) -o $(BUILD_DIR)/test_runner $(GTEST_FLAGS) $(LDFLAGS_COVERAGE) docs: @echo "Generating documentation with Doxygen..." @doxygen Doxyfile clean: + @echo "Cleaning build directory..." rm -rf $(BUILD_DIR) \ No newline at end of file diff --git a/lc3vm/src/ls3.cpp b/lc3vm/src/ls3.cpp index 72f134a..21be371 100644 --- a/lc3vm/src/ls3.cpp +++ b/lc3vm/src/ls3.cpp @@ -293,7 +293,7 @@ std::string LC3State::disassemble(std::uint16_t address) { std::uint16_t opcode = instr >> 12; std::ostringstream oss; - oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << address << ": "; + oss << "0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << address << ": "; switch (opcode) { case OP_ADD: { @@ -333,7 +333,7 @@ std::string LC3State::disassemble(std::uint16_t address) { std::uint16_t z = (instr >> 10) & 0x1; std::uint16_t p = (instr >> 9) & 0x1; std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); - oss << "BR" << (n ? "n" : "") << (z ? "z" : "") << (p ? "p" : "") << " 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + oss << "BR" << (n ? "n" : "") << (z ? "z" : "") << (p ? "p" : "") << " 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } case OP_JMP: { // Also handles RET @@ -349,7 +349,7 @@ std::string LC3State::disassemble(std::uint16_t address) { oss << "JSR "; if ((instr >> 11) & 1) { // JSR std::int16_t pc_offset11 = static_cast(sign_extend(instr & 0x7FF, 11)); - oss << "0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset11); + oss << "0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset11); } else { // JSRR std::uint16_t base_r = (instr >> 6) & 0x7; oss << "R" << base_r; @@ -359,13 +359,13 @@ std::string LC3State::disassemble(std::uint16_t address) { case OP_LD: { std::uint16_t dr = (instr >> 9) & 0x7; std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); - oss << "LD R" << dr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + oss << "LD R" << dr << ", 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } case OP_LDI: { std::uint16_t dr = (instr >> 9) & 0x7; std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); - oss << "LDI R" << dr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + oss << "LDI R" << dr << ", 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } case OP_LDR: { @@ -378,19 +378,19 @@ std::string LC3State::disassemble(std::uint16_t address) { case OP_LEA: { std::uint16_t dr = (instr >> 9) & 0x7; std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); - oss << "LEA R" << dr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + oss << "LEA R" << dr << ", 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } case OP_ST: { std::uint16_t sr = (instr >> 9) & 0x7; std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); - oss << "ST R" << sr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + oss << "ST R" << sr << ", 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } case OP_STI: { std::uint16_t sr = (instr >> 9) & 0x7; std::int16_t pc_offset9 = static_cast(sign_extend(instr & 0x1FF, 9)); - oss << "STI R" << sr << ", 0x" << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); + oss << "STI R" << sr << ", 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } case OP_STR: { @@ -401,7 +401,7 @@ std::string LC3State::disassemble(std::uint16_t address) { break; } case OP_TRAP: { - oss << "TRAP x" << std::hex << std::setfill('0') << std::setw(2) << (instr & 0xFF); + oss << "TRAP x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (instr & 0xFF); break; } case OP_RES: diff --git a/lc3vm/tests/test_basic.cpp b/lc3vm/tests/test_basic.cpp deleted file mode 100644 index c0447be..0000000 --- a/lc3vm/tests/test_basic.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include -#include "lc3.hpp" // Include the main VM header -#include "registers.hpp" // For R_PC, R_COND, R_R0 etc. -#include "flags.hpp" // For FL_ZRO - -// Helper to get register value if LC3State does not expose 'reg' directly publicly -// For now, assuming 'reg' is accessible for testing or we add a getter. -// Our LC3State.reg is private. We need a way to inspect registers for tests. -// Let's add a simple public getter in LC3State for tests for now. - -TEST(LC3VMTest, BasicInitialization) { - LC3State vm; - // PC should be initialized to 0x3000 - EXPECT_EQ(vm.get_register_value(R_PC), 0x3000); - // Condition code should be FL_ZRO - EXPECT_EQ(vm.get_register_value(R_COND), FL_ZRO); - - // General purpose registers R0-R7 should be 0 - for (int i = R_R0; i <= R_R7; ++i) { - EXPECT_EQ(vm.get_register_value(static_cast(i)), 0); - } -} - -// Placeholder for OP_ADD test - we'll need to write to memory -TEST(LC3VMTest, OP_ADD_Immediate) { - LC3State vm; - // Setup: R1 = 5, R2 will be destination - vm.set_register_value(R_R1, 5); - vm.set_register_value(R_R2, 0); // Clear destination - vm.set_register_value(R_PC, 0x3000); // Start PC - - // Instruction: ADD R2, R1, #10 (0001 010 001 10010 -> 0x14A2) - // R2 is DR (010), R1 is SR1 (001), imm_flag = 1, imm5 = 10 (01010) - // Opcode: 0001 (ADD) - // DR: 010 (R2) - // SR1: 001 (R1) - // Imm Flag: 1 - // Imm5: 01010 (10 decimal) - // instr = (OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | 10; - std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | 10; - vm.write_memory(0x3000, instr); - - vm.step(); // Execute the ADD instruction - - EXPECT_EQ(vm.get_register_value(R_R2), 15); // 5 + 10 = 15 - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Result is positive - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC should increment -} - -TEST(LC3VMTest, OP_ADD_Register) { - LC3State vm; - // Setup: R1 = 5, R3 = 7, R2 will be destination - vm.set_register_value(R_R1, 5); - vm.set_register_value(R_R3, 7); - vm.set_register_value(R_R2, 0); // Clear destination - vm.set_register_value(R_PC, 0x3000); // Start PC - - // Instruction: ADD R2, R1, R3 (0001 010 001 000 011 -> 0x14C3) - // R2 is DR (010), R1 is SR1 (001), imm_flag = 0, SR2 = R3 (011) - // Opcode: 0001 (ADD) - // DR: 010 (R2) - // SR1: 001 (R1) - // Imm Flag: 0 - // Reserved: 00 - // SR2: 011 (R3) - // instr = (OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (0 << 5) | R_R3; - std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | R_R3; - vm.write_memory(0x3000, instr); - - vm.step(); // Execute the ADD instruction - - EXPECT_EQ(vm.get_register_value(R_R2), 12); // 5 + 7 = 12 - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Result is positive - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC should increment -} - -TEST(LC3VMTest, OP_LD_LoadDirect) { - LC3State vm; - // Setup: PC = 0x3000. Memory[PC_after_fetch + offset(10)] = 123. R2 is destination. - // LD R2, LABEL_VAL (PCoffset9 = 10) - // PC_after_fetch = 0x3001. Effective Address = 0x3001 + 10 = 0x300B - vm.set_register_value(R_PC, 0x3000); - vm.write_memory(0x300B, 123); // Value to be loaded (Corrected address) - - // Instruction: LD R2, #10 (0010 010 000001010 -> 0x240A) - // R2 is DR (010), PCoffset9 = 10 - std::uint16_t instr = (Opcodes::OP_LD << 12) | (R_R2 << 9) | 10; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_R2), 123); - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // 123 is positive - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -TEST(LC3VMTest, OP_ST_StoreDirect) { - LC3State vm; - // Setup: PC = 0x3000. R2 = 456. Store R2 to Memory[PC_after_fetch + offset(5)] - // ST R2, LABEL_STORE (PCoffset9 = 5) - // PC_after_fetch = 0x3001. Effective Address = 0x3001 + 5 = 0x3006 - vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_R2, 456); - - // Instruction: ST R2, #5 (0011 010 000000101 -> 0x3405) - // R2 is SR (010), PCoffset9 = 5 - std::uint16_t instr = (Opcodes::OP_ST << 12) | (R_R2 << 9) | 5; - vm.write_memory(0x3000, instr); - - vm.step(); - - // Effective address calculated in OP_ST is state.reg[R_PC] (which is 0x3001) + offset (5) = 0x3006 - EXPECT_EQ(vm.read_memory(0x3001 + 5), 456); // Corrected expectation - - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC just increments - // ST does not change flags -} - -TEST(LC3VMTest, OP_AND_Register) { - LC3State vm; - // Setup: R1 = 0b1100, R3 = 0b1010. R2 is DR. - vm.set_register_value(R_R1, 0xC); // 12 - vm.set_register_value(R_R3, 0xA); // 10 - vm.set_register_value(R_PC, 0x3000); - - // Instruction: AND R2, R1, R3 (0101 010 001 000 011 -> 0x54C3) - std::uint16_t instr = (Opcodes::OP_AND << 12) | (R_R2 << 9) | (R_R1 << 6) | R_R3; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_R2), 0x8); // 0b1000 (12 & 10 = 8) - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -TEST(LC3VMTest, OP_NOT) { - LC3State vm; - // Setup: R1 = 0xFF00. R2 is DR. - vm.set_register_value(R_R1, 0xFF00); - vm.set_register_value(R_PC, 0x3000); - - // Instruction: NOT R2, R1 (1001 010 001 111111 -> 0x94BF) - std::uint16_t instr = (Opcodes::OP_NOT << 12) | (R_R2 << 9) | (R_R1 << 6) | 0x3F; // last 6 bits are 1s - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_R2), (std::uint16_t)~0xFF00); // 0x00FF - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -TEST(LC3VMTest, OP_JMP) { - LC3State vm; - // Setup: R3 contains target address 0x4000 - vm.set_register_value(R_R3, 0x4000); - vm.set_register_value(R_PC, 0x3000); - - // Instruction: JMP R3 (1100 000 011 000000 -> 0xC0C0) - std::uint16_t instr = (Opcodes::OP_JMP << 12) | (R_R3 << 6); - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_PC), 0x4000); -} - -TEST(LC3VMTest, OP_LDI_LoadIndirect) { - LC3State vm; - // Setup: PC = 0x3000. R2 is DR. - // LDI R2, ADDR_PTR (PCoffset9 = 10) - // ADDR_PTR is at 0x3001 (PC after fetch) + 10 = 0x300B - // Memory[0x300B] contains 0x4000 (the effective address) - // Memory[0x4000] contains 789 (the value to be loaded) - vm.set_register_value(R_PC, 0x3000); - vm.write_memory(0x300B, 0x4000); // Pointer to effective address - vm.write_memory(0x4000, 789); // Value at effective address - - // Instruction: LDI R2, #10 (1010 010 000001010 -> 0xA40A) - std::uint16_t instr = (Opcodes::OP_LDI << 12) | (R_R2 << 9) | 10; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_R2), 789); - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -TEST(LC3VMTest, OP_STI_StoreIndirect) { - LC3State vm; - // Setup: PC = 0x3000. R2 = 987 (value to store). - // STI R2, ADDR_PTR (PCoffset9 = 7) - // ADDR_PTR is at 0x3001 (PC after fetch) + 7 = 0x3008 - // Memory[0x3008] contains 0x5000 (the effective address where R2 will be stored) - vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_R2, 987); - vm.write_memory(0x3008, 0x5000); // Pointer to effective address - - // Instruction: STI R2, #7 (1011 010 000000111 -> 0xB407) - std::uint16_t instr = (Opcodes::OP_STI << 12) | (R_R2 << 9) | 7; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.read_memory(0x5000), 987); - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC just increments - // STI does not change flags -} - -TEST(LC3VMTest, OP_LDR_LoadBaseOffset) { - LC3State vm; - // Setup: PC = 0x3000. R1 (BaseR) = 0x4000. Memory[0x4000 + offset(5)] = 222. R2 is DR. - vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_R1, 0x4000); // Base register - vm.write_memory(0x4000 + 5, 222); // Value at BaseR + offset - - // Instruction: LDR R2, R1, #5 (0110 010 001 000101 -> 0x6445) - // R2 is DR (010), R1 is BaseR (001), offset6 = 5 - std::uint16_t instr = (Opcodes::OP_LDR << 12) | (R_R2 << 9) | (R_R1 << 6) | 5; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_R2), 222); - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -TEST(LC3VMTest, OP_STR_StoreBaseOffset) { - LC3State vm; - // Setup: PC = 0x3000. R1 (BaseR) = 0x5000. R2 (SR) = 333. - // Store R2 to Memory[R1 + offset(3)] - vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_R1, 0x5000); // Base register - vm.set_register_value(R_R2, 333); // Source register - - // Instruction: STR R2, R1, #3 (0111 010 001 000011 -> 0x7443) - // R2 is SR (010), R1 is BaseR (001), offset6 = 3 - std::uint16_t instr = (Opcodes::OP_STR << 12) | (R_R2 << 9) | (R_R1 << 6) | 3; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.read_memory(0x5000 + 3), 333); - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); - // STR does not change flags -} - -TEST(LC3VMTest, OP_LEA_LoadEffectiveAddress) { - LC3State vm; - // Setup: PC = 0x3000. R2 is DR. - // LEA R2, #7 (PCoffset9 = 7) - // Effective address = PC_after_fetch + 7 = 0x3001 + 7 = 0x3008 - vm.set_register_value(R_PC, 0x3000); - - // Instruction: LEA R2, #7 (1110 010 000000111 -> 0xE407) - std::uint16_t instr = (Opcodes::OP_LEA << 12) | (R_R2 << 9) | 7; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_R2), 0x3001 + 7); - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Address 0x3008 is positive - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -TEST(LC3VMTest, OP_BR_BranchIfPositive) { - LC3State vm; - // Setup: PC = 0x3000. R_COND = FL_POS (1). - // BRp #10 (PCoffset9 = 10) - // Target PC = PC_after_fetch + 10 = 0x3001 + 10 = 0x300B - vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_COND, FL_POS); - - // Instruction: BRp #10 (0000 001 000001010 -> 0x020A) - // nzp = 001 (Positive), PCoffset9 = 10 - std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_POS << 9) | 10; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001 + 10); - // BR does not change flags -} - -TEST(LC3VMTest, OP_BR_BranchNotTaken) { - LC3State vm; - // Setup: PC = 0x3000. R_COND = FL_ZRO (2). - // BRp #10 (PCoffset9 = 10) - // Condition (Positive) is not met, so PC should just increment. - vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_COND, FL_ZRO); - - // Instruction: BRp #10 (0000 001 000001010 -> 0x020A) - std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_POS << 9) | 10; - vm.write_memory(0x3000, instr); - - vm.step(); - - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file diff --git a/lc3vm/tests/test_disassembly.cpp b/lc3vm/tests/test_disassembly.cpp new file mode 100644 index 0000000..6e5780c --- /dev/null +++ b/lc3vm/tests/test_disassembly.cpp @@ -0,0 +1,133 @@ +#include +#include "lc3.hpp" +#include "opcodes.hpp" +#include "registers.hpp" +#include "flags.hpp" +#include +#include +#include + + +TEST(LC3DisassembleTest, ADD_Reg) { + LC3State vm; + std::uint16_t addr = 0x3000; + // ADD R1, R2, R3 (0001 001 010 000 011 => 0x1283) + vm.write_memory(addr, 0x1283); + EXPECT_EQ(vm.disassemble(addr), "0x3000: ADD R1, R2, R3"); +} + +TEST(LC3DisassembleTest, ADD_Imm) { + LC3State vm; + std::uint16_t addr = 0x3001; + // ADD R1, R2, #-1 (0001 001 010 1 11111 => 0x12BF) + vm.write_memory(addr, 0x12BF); + EXPECT_EQ(vm.disassemble(addr), "0x3001: ADD R1, R2, #-1"); + // ADD R3, R4, #5 (0001 011 100 1 00101 => 0x1725) + vm.write_memory(addr + 1, 0x1725); + EXPECT_EQ(vm.disassemble(addr + 1), "0x3002: ADD R3, R4, #5"); +} + +TEST(LC3DisassembleTest, AND_Reg) { + LC3State vm; + std::uint16_t addr = 0x3100; + // AND R5, R6, R7 (Op=0101 DR=101 SR1=110 Mode=0 MustBeZero=00 SR2=111 => 0101 101 110 000 111 => 0x5B87) + vm.write_memory(addr, 0x5B87); + EXPECT_EQ(vm.disassemble(addr), "0x3100: AND R5, R6, R7"); +} + +TEST(LC3DisassembleTest, AND_Imm) { + LC3State vm; + std::uint16_t addr = 0x3150; + // AND R0, R1, #0 (0101 000 001 1 00000 => 0x5060) + vm.write_memory(addr, 0x5060); + EXPECT_EQ(vm.disassemble(addr), "0x3150: AND R0, R1, #0"); + // AND R2, R3, #-16 (0101 010 011 1 10000 => 0x54F0) + vm.write_memory(addr + 1, 0x54F0); + EXPECT_EQ(vm.disassemble(addr + 1), "0x3151: AND R2, R3, #-16"); +} + +TEST(LC3DisassembleTest, NOT) { + LC3State vm; + std::uint16_t addr = 0x3200; + // NOT R3, R4 (1001 011 100 111111 => 0x973F) + vm.write_memory(addr, 0x973F); + EXPECT_EQ(vm.disassemble(addr), "0x3200: NOT R3, R4"); +} + +TEST(LC3DisassembleTest, BR) { + LC3State vm; + std::uint16_t addr = 0x3300; + // BRnzp 0x330A (PC = 0x3300, PCOffset9 = 9. Target = 0x3300+1+9 = 0x330A) + vm.write_memory(addr, 0x0E09); + EXPECT_EQ(vm.disassemble(addr), "0x3300: BRnzp 0x330a"); + // BRn (PC=0x3301, PCOffset9 = -10 Target = 0x3301+1-10 = 0x32F8) + vm.write_memory(addr + 1, 0x09F6); + EXPECT_EQ(vm.disassemble(addr+1), "0x3301: BRn 0x32f8"); +} + +TEST(LC3DisassembleTest, JMP_RET) { + LC3State vm; + std::uint16_t addr = 0x3400; + vm.write_memory(addr, 0xC0C0); // JMP R3 + EXPECT_EQ(vm.disassemble(addr), "0x3400: JMP R3"); + vm.write_memory(addr + 1, 0xC1C0); // RET (JMP R7) + EXPECT_EQ(vm.disassemble(addr + 1), "0x3401: RET"); +} + +TEST(LC3DisassembleTest, JSR_JSRR) { + LC3State vm; + std::uint16_t addr = 0x3500; + // JSR 0x358a. For PC=0x3500, Target=0x358a => PCOffset11 = 0x358a - 0x3500 - 1 = 0x89. + // Instruction: 0100 1 (JSR bit) 00010001001 (0x089) => 0x4889 + vm.write_memory(addr, 0x4889); + EXPECT_EQ(vm.disassemble(addr), "0x3500: JSR 0x358a"); + + // JSRR R5 (0100 0 00 101 000000 => 0x4140) + vm.write_memory(addr + 1, 0x4140); + EXPECT_EQ(vm.disassemble(addr + 1), "0x3501: JSR R5"); +} + +TEST(LC3DisassembleTest, LD_LDI_LDR_LEA) { + LC3State vm; + std::uint16_t addr = 0x3600; + vm.write_memory(addr, 0x200F); // LD R0, 0x3610 + EXPECT_EQ(vm.disassemble(addr), "0x3600: LD R0, 0x3610"); + vm.write_memory(addr + 1, 0xA206); // LDI R1, 0x3608 + EXPECT_EQ(vm.disassemble(addr + 1), "0x3601: LDI R1, 0x3608"); + vm.write_memory(addr + 2, 0x64C5); // LDR R2, R3, #5 + EXPECT_EQ(vm.disassemble(addr + 2), "0x3602: LDR R2, R3, #5"); + + // LEA R4, 0x35f0. For PC=0x3603, Target=0x35f0 => PCOffset9 = 0x35f0 - 0x3603 - 1 = -20 (0x1EC). + // Instruction: 1110 (LEA) 100 (R4) 111101100 (0x1EC) => 0xE9EC + vm.write_memory(addr + 3, 0xE9EC); + EXPECT_EQ(vm.disassemble(addr + 3), "0x3603: LEA R4, 0x35f0"); +} + +TEST(LC3DisassembleTest, ST_STI_STR) { + LC3State vm; + std::uint16_t addr = 0x3700; + vm.write_memory(addr, 0x3A1F); // ST R5, 0x3720 + EXPECT_EQ(vm.disassemble(addr), "0x3700: ST R5, 0x3720"); + vm.write_memory(addr + 1, 0xBDF0); // STI R6, 0x36f2 + EXPECT_EQ(vm.disassemble(addr + 1), "0x3701: STI R6, 0x36f2"); + vm.write_memory(addr + 2, 0x7E3E); // STR R7, R0, #-2 + EXPECT_EQ(vm.disassemble(addr + 2), "0x3702: STR R7, R0, #-2"); +} + +TEST(LC3DisassembleTest, TRAP) { + LC3State vm; + std::uint16_t addr = 0x3800; + vm.write_memory(addr, 0xF025); // TRAP x25 + EXPECT_EQ(vm.disassemble(addr), "0x3800: TRAP x25"); + vm.write_memory(addr+1, 0xF020); // TRAP x20 + EXPECT_EQ(vm.disassemble(addr+1), "0x3801: TRAP x20"); +} + +TEST(LC3DisassembleTest, BAD_OPCODE) { + LC3State vm; + std::uint16_t addr = 0x3900; + vm.write_memory(addr, 0x8000); // RTI (Opcode 8) + EXPECT_EQ(vm.disassemble(addr), "0x3900: BAD OPCODE"); + vm.write_memory(addr + 1, 0xD000); // RES (Opcode 13) + EXPECT_EQ(vm.disassemble(addr + 1), "0x3901: BAD OPCODE"); +} diff --git a/lc3vm/tests/test_initialization.cpp b/lc3vm/tests/test_initialization.cpp new file mode 100644 index 0000000..16b3ddc --- /dev/null +++ b/lc3vm/tests/test_initialization.cpp @@ -0,0 +1,17 @@ +#include +#include "lc3.hpp" +#include "registers.hpp" +#include "flags.hpp" + +TEST(LC3VMTest, BasicInitialization) { + LC3State vm; + // PC should be initialized to 0x3000 + EXPECT_EQ(vm.get_register_value(R_PC), 0x3000); + // Condition code should be FL_ZRO + EXPECT_EQ(vm.get_register_value(R_COND), FL_ZRO); + + // General purpose registers R0-R7 should be 0 + for (int i = R_R0; i <= R_R7; ++i) { + EXPECT_EQ(vm.get_register_value(static_cast(i)), 0); + } +} \ No newline at end of file diff --git a/lc3vm/tests/test_main.cpp b/lc3vm/tests/test_main.cpp new file mode 100644 index 0000000..9a1559a --- /dev/null +++ b/lc3vm/tests/test_main.cpp @@ -0,0 +1,6 @@ +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/lc3vm/tests/test_opcode_execution.cpp b/lc3vm/tests/test_opcode_execution.cpp new file mode 100644 index 0000000..45faf1e --- /dev/null +++ b/lc3vm/tests/test_opcode_execution.cpp @@ -0,0 +1,192 @@ +#include +#include "lc3.hpp" +#include "registers.hpp" +#include "flags.hpp" +#include "opcodes.hpp" + +TEST(LC3VMTest, OP_ADD_Immediate) { + LC3State vm; + // Setup: R1 = 5, R2 will be destination + vm.set_register_value(R_R1, 5); + vm.set_register_value(R_R2, 0); // Clear destination + vm.set_register_value(R_PC, 0x3000); // Start PC + + // Instruction: ADD R2, R1, #10 (0001 010 001 10010 -> 0x14A2) + std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | 10; + vm.write_memory(0x3000, instr); + + vm.step(); // Execute the ADD instruction + + EXPECT_EQ(vm.get_register_value(R_R2), 15); // 5 + 10 = 15 + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Result is positive + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC should increment +} + +TEST(LC3VMTest, OP_ADD_Register) { + LC3State vm; + // Setup: R1 = 5, R3 = 7, R2 will be destination + vm.set_register_value(R_R1, 5); + vm.set_register_value(R_R3, 7); + vm.set_register_value(R_R2, 0); // Clear destination + vm.set_register_value(R_PC, 0x3000); // Start PC + + // Instruction: ADD R2, R1, R3 (0001 010 001 000 011 -> 0x14C3) + std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | R_R3; + vm.write_memory(0x3000, instr); + + vm.step(); // Execute the ADD instruction + + EXPECT_EQ(vm.get_register_value(R_R2), 12); // 5 + 7 = 12 + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Result is positive + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC should increment +} + +TEST(LC3VMTest, OP_LD_LoadDirect) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.write_memory(0x300B, 123); + std::uint16_t instr = (Opcodes::OP_LD << 12) | (R_R2 << 9) | 10; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_R2), 123); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_ST_StoreDirect) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_R2, 456); + std::uint16_t instr = (Opcodes::OP_ST << 12) | (R_R2 << 9) | 5; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.read_memory(0x3001 + 5), 456); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_AND_Register) { + LC3State vm; + vm.set_register_value(R_R1, 0xC); + vm.set_register_value(R_R3, 0xA); + vm.set_register_value(R_PC, 0x3000); + std::uint16_t instr = (Opcodes::OP_AND << 12) | (R_R2 << 9) | (R_R1 << 6) | R_R3; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_R2), 0x8); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_NOT) { + LC3State vm; + vm.set_register_value(R_R1, 0xFF00); + vm.set_register_value(R_PC, 0x3000); + std::uint16_t instr = (Opcodes::OP_NOT << 12) | (R_R2 << 9) | (R_R1 << 6) | 0x3F; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_R2), (std::uint16_t)~0xFF00); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_JMP) { + LC3State vm; + vm.set_register_value(R_R3, 0x4000); + vm.set_register_value(R_PC, 0x3000); + std::uint16_t instr = (Opcodes::OP_JMP << 12) | (R_R3 << 6); + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_PC), 0x4000); +} + +TEST(LC3VMTest, OP_LDI_LoadIndirect) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.write_memory(0x300B, 0x4000); + vm.write_memory(0x4000, 789); + std::uint16_t instr = (Opcodes::OP_LDI << 12) | (R_R2 << 9) | 10; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_R2), 789); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_STI_StoreIndirect) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_R2, 987); + vm.write_memory(0x3008, 0x5000); + std::uint16_t instr = (Opcodes::OP_STI << 12) | (R_R2 << 9) | 7; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.read_memory(0x5000), 987); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_LDR_LoadBaseOffset) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_R1, 0x4000); + vm.write_memory(0x4000 + 5, 222); + std::uint16_t instr = (Opcodes::OP_LDR << 12) | (R_R2 << 9) | (R_R1 << 6) | 5; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_R2), 222); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_STR_StoreBaseOffset) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_R1, 0x5000); + vm.set_register_value(R_R2, 333); + std::uint16_t instr = (Opcodes::OP_STR << 12) | (R_R2 << 9) | (R_R1 << 6) | 3; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.read_memory(0x5000 + 3), 333); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_LEA_LoadEffectiveAddress) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + std::uint16_t instr = (Opcodes::OP_LEA << 12) | (R_R2 << 9) | 7; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_R2), 0x3001 + 7); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_BR_BranchIfPositive) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_COND, FL_POS); + std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_POS << 9) | 10; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001 + 10); +} + +TEST(LC3VMTest, OP_BR_BranchNotTaken) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_COND, FL_ZRO); + std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_POS << 9) | 10; + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +// Test for BR instruction offsets and conditions +TEST(LC3VMTest, OP_BR_BranchIfZero) { + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_COND, FL_ZRO); + std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_ZRO << 9) | 10; // BRz #10 + vm.write_memory(0x3000, instr); + vm.step(); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001 + 10); +} \ No newline at end of file From 0465beb6f7b4babdc4dc3d8001d0f3fcc82c32ef Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 23:00:33 +0300 Subject: [PATCH 5/7] clean --- lc3vm/src/ls3.cpp | 16 +++++++------- lc3vm/src/main.cpp | 4 ++-- lc3vm/tests/test_initialization.cpp | 3 --- lc3vm/tests/test_opcode_execution.cpp | 30 +++++++++++---------------- 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/lc3vm/src/ls3.cpp b/lc3vm/src/ls3.cpp index 21be371..fb13431 100644 --- a/lc3vm/src/ls3.cpp +++ b/lc3vm/src/ls3.cpp @@ -300,10 +300,10 @@ std::string LC3State::disassemble(std::uint16_t address) { std::uint16_t dr = (instr >> 9) & 0x7; std::uint16_t sr1 = (instr >> 6) & 0x7; oss << "ADD R" << dr << ", R" << sr1 << ", "; - if ((instr >> 5) & 0x1) { // ADD imm + if ((instr >> 5) & 0x1) { std::int16_t imm5 = static_cast(sign_extend(instr & 0x1F, 5)); oss << "#" << std::dec << imm5; - } else { // ADD reg + } else { std::uint16_t sr2 = instr & 0x7; oss << "R" << sr2; } @@ -313,10 +313,10 @@ std::string LC3State::disassemble(std::uint16_t address) { std::uint16_t dr = (instr >> 9) & 0x7; std::uint16_t sr1 = (instr >> 6) & 0x7; oss << "AND R" << dr << ", R" << sr1 << ", "; - if ((instr >> 5) & 0x1) { // AND imm + if ((instr >> 5) & 0x1) { std::int16_t imm5 = static_cast(sign_extend(instr & 0x1F, 5)); oss << "#" << std::dec << imm5; - } else { // AND reg + } else { std::uint16_t sr2 = instr & 0x7; oss << "R" << sr2; } @@ -336,9 +336,9 @@ std::string LC3State::disassemble(std::uint16_t address) { oss << "BR" << (n ? "n" : "") << (z ? "z" : "") << (p ? "p" : "") << " 0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset9); break; } - case OP_JMP: { // Also handles RET + case OP_JMP: { std::uint16_t base_r = (instr >> 6) & 0x7; - if (base_r == 7) { // RET + if (base_r == 7) { oss << "RET"; } else { oss << "JMP R" << base_r; @@ -347,10 +347,10 @@ std::string LC3State::disassemble(std::uint16_t address) { } case OP_JSR: { oss << "JSR "; - if ((instr >> 11) & 1) { // JSR + if ((instr >> 11) & 1) { std::int16_t pc_offset11 = static_cast(sign_extend(instr & 0x7FF, 11)); oss << "0x" << std::nouppercase << std::hex << std::setfill('0') << std::setw(4) << (address + 1 + pc_offset11); - } else { // JSRR + } else { std::uint16_t base_r = (instr >> 6) & 0x7; oss << "R" << base_r; } diff --git a/lc3vm/src/main.cpp b/lc3vm/src/main.cpp index 2c0ec52..6ea109b 100644 --- a/lc3vm/src/main.cpp +++ b/lc3vm/src/main.cpp @@ -10,8 +10,8 @@ #include #include #include "lc3.hpp" -#include "terminal_input.hpp" // For raw terminal mode -#include // For std::atexit +#include "terminal_input.hpp" +#include /** * @brief Global pointer to the LC3State instance. diff --git a/lc3vm/tests/test_initialization.cpp b/lc3vm/tests/test_initialization.cpp index 16b3ddc..2d6f8e3 100644 --- a/lc3vm/tests/test_initialization.cpp +++ b/lc3vm/tests/test_initialization.cpp @@ -5,12 +5,9 @@ TEST(LC3VMTest, BasicInitialization) { LC3State vm; - // PC should be initialized to 0x3000 EXPECT_EQ(vm.get_register_value(R_PC), 0x3000); - // Condition code should be FL_ZRO EXPECT_EQ(vm.get_register_value(R_COND), FL_ZRO); - // General purpose registers R0-R7 should be 0 for (int i = R_R0; i <= R_R7; ++i) { EXPECT_EQ(vm.get_register_value(static_cast(i)), 0); } diff --git a/lc3vm/tests/test_opcode_execution.cpp b/lc3vm/tests/test_opcode_execution.cpp index 45faf1e..7a7ddc4 100644 --- a/lc3vm/tests/test_opcode_execution.cpp +++ b/lc3vm/tests/test_opcode_execution.cpp @@ -6,39 +6,34 @@ TEST(LC3VMTest, OP_ADD_Immediate) { LC3State vm; - // Setup: R1 = 5, R2 will be destination vm.set_register_value(R_R1, 5); - vm.set_register_value(R_R2, 0); // Clear destination - vm.set_register_value(R_PC, 0x3000); // Start PC + vm.set_register_value(R_R2, 0); + vm.set_register_value(R_PC, 0x3000); - // Instruction: ADD R2, R1, #10 (0001 010 001 10010 -> 0x14A2) std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | 10; vm.write_memory(0x3000, instr); - vm.step(); // Execute the ADD instruction + vm.step(); - EXPECT_EQ(vm.get_register_value(R_R2), 15); // 5 + 10 = 15 - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Result is positive - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC should increment + EXPECT_EQ(vm.get_register_value(R_R2), 15); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } TEST(LC3VMTest, OP_ADD_Register) { LC3State vm; - // Setup: R1 = 5, R3 = 7, R2 will be destination vm.set_register_value(R_R1, 5); vm.set_register_value(R_R3, 7); - vm.set_register_value(R_R2, 0); // Clear destination - vm.set_register_value(R_PC, 0x3000); // Start PC + vm.set_register_value(R_R2, 0); - // Instruction: ADD R2, R1, R3 (0001 010 001 000 011 -> 0x14C3) std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | R_R3; vm.write_memory(0x3000, instr); - vm.step(); // Execute the ADD instruction + vm.step(); - EXPECT_EQ(vm.get_register_value(R_R2), 12); // 5 + 7 = 12 - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); // Result is positive - EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); // PC should increment + EXPECT_EQ(vm.get_register_value(R_R2), 12); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } TEST(LC3VMTest, OP_LD_LoadDirect) { @@ -180,12 +175,11 @@ TEST(LC3VMTest, OP_BR_BranchNotTaken) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -// Test for BR instruction offsets and conditions TEST(LC3VMTest, OP_BR_BranchIfZero) { LC3State vm; vm.set_register_value(R_PC, 0x3000); vm.set_register_value(R_COND, FL_ZRO); - std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_ZRO << 9) | 10; // BRz #10 + std::uint16_t instr = (Opcodes::OP_BR << 12) | (FL_ZRO << 9) | 10; vm.write_memory(0x3000, instr); vm.step(); EXPECT_EQ(vm.get_register_value(R_PC), 0x3001 + 10); From 051d23f0b7e9744f38631f45ea33fc5a83f59a9d Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 23:29:03 +0300 Subject: [PATCH 6/7] update readme --- README.md | 18 ++++++++++++++++++ lc3vm/src/ls3.cpp | 2 -- lc3vm/src/main.cpp | 2 -- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 891905e..222e91a 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,24 @@ To run an LC-3 object file: ./lc3vm/build/lc3vm path/to/your_program.obj [path/to/another_program.obj ...] ``` +## Disassembling Object Files + +The LC-3 VM can also disassemble `.obj` files, showing you the LC-3 assembly instructions corresponding to the machine code in the file. This is useful for inspecting programs or debugging. + +**How to use:** + +To disassemble one or more object files, use the `-d` or `--disassemble` flag followed by the path(s) to your `.obj` file(s): + +```bash +./lc3vm/build/lc3vm -d path/to/your_program.obj +``` + +Or for multiple files: + +```bash +./lc3vm/build/lc3vm --disassemble program1.obj program2.obj +``` + ## Running Tests To compile and run the unit tests (from within the `lc3vm` directory): diff --git a/lc3vm/src/ls3.cpp b/lc3vm/src/ls3.cpp index fb13431..d82f974 100644 --- a/lc3vm/src/ls3.cpp +++ b/lc3vm/src/ls3.cpp @@ -420,8 +420,6 @@ void LC3State::disassemble_all() { } for (const auto& segment : loaded_code_segments) { - std::cout << "\nDisassembling segment from 0x" << std::hex << std::setfill('0') << std::setw(4) << segment.start_address - << " to 0x" << std::hex << std::setfill('0') << std::setw(4) << (segment.start_address + segment.size -1) << std::dec << ":\n"; for (std::uint16_t i = 0; i < segment.size; ++i) { std::uint16_t current_address = segment.start_address + i; std::cout << disassemble(current_address) << std::endl; diff --git a/lc3vm/src/main.cpp b/lc3vm/src/main.cpp index 6ea109b..84f9606 100644 --- a/lc3vm/src/main.cpp +++ b/lc3vm/src/main.cpp @@ -95,12 +95,10 @@ int main(int argc, const char* argv[]) { try { for (int i = first_image_arg_index; i < argc; ++i) { std::string filename = argv[i]; - std::cout << "Loading image: " << filename << std::endl; vm.load_image(filename); } if (disassemble_mode) { - std::cout << "Disassembling memory..." << std::endl; vm.disassemble_all(); } else { std::cout << "Starting LC-3 VM..." << std::endl; From c41a536db1f3a60c2f14863aef480b42d6ef5b23 Mon Sep 17 00:00:00 2001 From: Morzan6 Date: Sun, 1 Jun 2025 23:50:43 +0300 Subject: [PATCH 7/7] add more tests --- lc3vm/tests/test_opcode_execution.cpp | 190 ++++++++++++++++++++++---- 1 file changed, 163 insertions(+), 27 deletions(-) diff --git a/lc3vm/tests/test_opcode_execution.cpp b/lc3vm/tests/test_opcode_execution.cpp index 7a7ddc4..4070ba8 100644 --- a/lc3vm/tests/test_opcode_execution.cpp +++ b/lc3vm/tests/test_opcode_execution.cpp @@ -4,7 +4,8 @@ #include "flags.hpp" #include "opcodes.hpp" -TEST(LC3VMTest, OP_ADD_Immediate) { +TEST(LC3VMTest, OP_ADD_Immediate) +{ LC3State vm; vm.set_register_value(R_R1, 5); vm.set_register_value(R_R2, 0); @@ -20,7 +21,8 @@ TEST(LC3VMTest, OP_ADD_Immediate) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_ADD_Register) { +TEST(LC3VMTest, OP_ADD_Register) +{ LC3State vm; vm.set_register_value(R_R1, 5); vm.set_register_value(R_R3, 7); @@ -36,10 +38,11 @@ TEST(LC3VMTest, OP_ADD_Register) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_LD_LoadDirect) { +TEST(LC3VMTest, OP_LD_LoadDirect) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); - vm.write_memory(0x300B, 123); + vm.write_memory(0x300B, 123); std::uint16_t instr = (Opcodes::OP_LD << 12) | (R_R2 << 9) | 10; vm.write_memory(0x3000, instr); vm.step(); @@ -48,7 +51,8 @@ TEST(LC3VMTest, OP_LD_LoadDirect) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_ST_StoreDirect) { +TEST(LC3VMTest, OP_ST_StoreDirect) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); vm.set_register_value(R_R2, 456); @@ -59,10 +63,11 @@ TEST(LC3VMTest, OP_ST_StoreDirect) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_AND_Register) { +TEST(LC3VMTest, OP_AND_Register) +{ LC3State vm; - vm.set_register_value(R_R1, 0xC); - vm.set_register_value(R_R3, 0xA); + vm.set_register_value(R_R1, 0xC); + vm.set_register_value(R_R3, 0xA); vm.set_register_value(R_PC, 0x3000); std::uint16_t instr = (Opcodes::OP_AND << 12) | (R_R2 << 9) | (R_R1 << 6) | R_R3; vm.write_memory(0x3000, instr); @@ -72,7 +77,8 @@ TEST(LC3VMTest, OP_AND_Register) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_NOT) { +TEST(LC3VMTest, OP_NOT) +{ LC3State vm; vm.set_register_value(R_R1, 0xFF00); vm.set_register_value(R_PC, 0x3000); @@ -84,7 +90,8 @@ TEST(LC3VMTest, OP_NOT) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_JMP) { +TEST(LC3VMTest, OP_JMP) +{ LC3State vm; vm.set_register_value(R_R3, 0x4000); vm.set_register_value(R_PC, 0x3000); @@ -94,11 +101,12 @@ TEST(LC3VMTest, OP_JMP) { EXPECT_EQ(vm.get_register_value(R_PC), 0x4000); } -TEST(LC3VMTest, OP_LDI_LoadIndirect) { +TEST(LC3VMTest, OP_LDI_LoadIndirect) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); - vm.write_memory(0x300B, 0x4000); - vm.write_memory(0x4000, 789); + vm.write_memory(0x300B, 0x4000); + vm.write_memory(0x4000, 789); std::uint16_t instr = (Opcodes::OP_LDI << 12) | (R_R2 << 9) | 10; vm.write_memory(0x3000, instr); vm.step(); @@ -107,11 +115,12 @@ TEST(LC3VMTest, OP_LDI_LoadIndirect) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_STI_StoreIndirect) { +TEST(LC3VMTest, OP_STI_StoreIndirect) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); vm.set_register_value(R_R2, 987); - vm.write_memory(0x3008, 0x5000); + vm.write_memory(0x3008, 0x5000); std::uint16_t instr = (Opcodes::OP_STI << 12) | (R_R2 << 9) | 7; vm.write_memory(0x3000, instr); vm.step(); @@ -119,11 +128,12 @@ TEST(LC3VMTest, OP_STI_StoreIndirect) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_LDR_LoadBaseOffset) { +TEST(LC3VMTest, OP_LDR_LoadBaseOffset) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_R1, 0x4000); - vm.write_memory(0x4000 + 5, 222); + vm.set_register_value(R_R1, 0x4000); + vm.write_memory(0x4000 + 5, 222); std::uint16_t instr = (Opcodes::OP_LDR << 12) | (R_R2 << 9) | (R_R1 << 6) | 5; vm.write_memory(0x3000, instr); vm.step(); @@ -132,11 +142,12 @@ TEST(LC3VMTest, OP_LDR_LoadBaseOffset) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_STR_StoreBaseOffset) { +TEST(LC3VMTest, OP_STR_StoreBaseOffset) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); - vm.set_register_value(R_R1, 0x5000); - vm.set_register_value(R_R2, 333); + vm.set_register_value(R_R1, 0x5000); + vm.set_register_value(R_R2, 333); std::uint16_t instr = (Opcodes::OP_STR << 12) | (R_R2 << 9) | (R_R1 << 6) | 3; vm.write_memory(0x3000, instr); vm.step(); @@ -144,18 +155,20 @@ TEST(LC3VMTest, OP_STR_StoreBaseOffset) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_LEA_LoadEffectiveAddress) { +TEST(LC3VMTest, OP_LEA_LoadEffectiveAddress) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); std::uint16_t instr = (Opcodes::OP_LEA << 12) | (R_R2 << 9) | 7; vm.write_memory(0x3000, instr); vm.step(); EXPECT_EQ(vm.get_register_value(R_R2), 0x3001 + 7); - EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_BR_BranchIfPositive) { +TEST(LC3VMTest, OP_BR_BranchIfPositive) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); vm.set_register_value(R_COND, FL_POS); @@ -165,7 +178,8 @@ TEST(LC3VMTest, OP_BR_BranchIfPositive) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001 + 10); } -TEST(LC3VMTest, OP_BR_BranchNotTaken) { +TEST(LC3VMTest, OP_BR_BranchNotTaken) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); vm.set_register_value(R_COND, FL_ZRO); @@ -175,7 +189,8 @@ TEST(LC3VMTest, OP_BR_BranchNotTaken) { EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); } -TEST(LC3VMTest, OP_BR_BranchIfZero) { +TEST(LC3VMTest, OP_BR_BranchIfZero) +{ LC3State vm; vm.set_register_value(R_PC, 0x3000); vm.set_register_value(R_COND, FL_ZRO); @@ -183,4 +198,125 @@ TEST(LC3VMTest, OP_BR_BranchIfZero) { vm.write_memory(0x3000, instr); vm.step(); EXPECT_EQ(vm.get_register_value(R_PC), 0x3001 + 10); -} \ No newline at end of file +} + +TEST(LC3VMTest, OP_ADD_Immediate_NegativeResult) +{ + LC3State vm; + vm.set_register_value(R_R1, 10); + vm.set_register_value(R_R2, 0); + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | (0b11111 & 0x1F); + std::uint16_t instr_neg = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | (0b11011 & 0x1F); + vm.write_memory(0x3000, instr_neg); + + vm.step(); + + EXPECT_EQ(vm.get_register_value(R_R2), 5); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_ADD_Immediate_NegativeResult_Corrected) +{ + LC3State vm; + vm.set_register_value(R_R1, 10); + vm.set_register_value(R_R2, 0); + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R2 << 9) | (R_R1 << 6) | (1 << 5) | (0b10100 & 0x1F); + vm.write_memory(0x3000, instr); + + vm.step(); + + EXPECT_EQ(vm.get_register_value(R_R2), 0xFFFE); + EXPECT_EQ(vm.get_register_value(R_COND), FL_NEG); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_ADD_Register_PositiveOverflow) +{ + LC3State vm; + vm.set_register_value(R_R1, 0x7000); + vm.set_register_value(R_R2, 0x7000); + vm.set_register_value(R_R3, 0); + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R3 << 9) | (R_R1 << 6) | R_R2; + vm.write_memory(0x3000, instr); + + vm.step(); + + EXPECT_EQ(vm.get_register_value(R_R3), 0xE000); + EXPECT_EQ(vm.get_register_value(R_COND), FL_NEG); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_ADD_Register_NegativeOverflow_WrapAround) +{ + LC3State vm; + vm.set_register_value(R_R1, 0xA000); + vm.set_register_value(R_R2, 0xA000); + vm.set_register_value(R_R3, 0); + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t instr = (Opcodes::OP_ADD << 12) | (R_R3 << 9) | (R_R1 << 6) | R_R2; + vm.write_memory(0x3000, instr); + + vm.step(); + + EXPECT_EQ(vm.get_register_value(R_R3), 0x4000); + EXPECT_EQ(vm.get_register_value(R_COND), FL_POS); + EXPECT_EQ(vm.get_register_value(R_PC), 0x3001); +} + +TEST(LC3VMTest, OP_LD_InvalidAddress) +{ + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + vm.set_register_value(R_PC, 0xFFFE); + std::uint16_t instr_wrap = (Opcodes::OP_LD << 12) | (R_R0 << 9) | (3 & 0x1FF); + vm.write_memory(0xFFFE, instr_wrap); + vm.write_memory(0x0002, 0xABCD); + + vm.step(); + + EXPECT_EQ(vm.get_register_value(R_R0), 0xABCD); + EXPECT_EQ(vm.get_register_value(R_PC), 0xFFFF); +} + +TEST(LC3VMTest, InvalidOpcodeExecution) +{ + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t invalid_instr = (Opcodes::OP_RTI << 12); + vm.write_memory(0x3000, invalid_instr); + std::uint16_t illegal_opcode = (0x8 << 12); + vm.write_memory(0x3000, illegal_opcode); + + std::uint16_t trap_undefined = (Opcodes::OP_TRAP << 12) | 0xFF; + vm.write_memory(0x3000, trap_undefined); +} +TEST(LC3VMTest, IllegalOpcodeExecution_DoesNotIncrementPC) +{ + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t illegal_opcode = (0x8 << 12); + vm.write_memory(0x3000, illegal_opcode); + + EXPECT_THROW(vm.step(), std::runtime_error); +} + +TEST(LC3VMTest, UndefinedTrapVector_DoesNotIncrementPC) +{ + LC3State vm; + vm.set_register_value(R_PC, 0x3000); + + std::uint16_t trap_undefined = (Opcodes::OP_TRAP << 12) | 0xFF; + vm.write_memory(0x3000, trap_undefined); + + EXPECT_THROW(vm.step(), std::runtime_error); +}