├── CPU.pptx ├── programs_for_testing ├── tests │ ├── segfault.c │ ├── a.out │ ├── functionrefs.c │ ├── arithmetic.c │ └── blackjackmodified.c ├── games │ ├── a.out │ └── blackjack.c ├── simple │ ├── a.out │ ├── d6.c │ ├── helloworld.c │ ├── twoplustwo.c │ ├── fibonacci.c │ ├── factorial.c │ ├── greeting.c │ ├── gcd.c │ └── primes.c ├── pptlib.h └── pptlibimpl.h ├── README.md ├── LICENSE ├── pptcc.py ├── pptvm_tests.py ├── pptutils.py ├── autoclicker.py ├── pptvm.py └── pptasm.py /CPU.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomWildenhain/pptcc/HEAD/CPU.pptx -------------------------------------------------------------------------------- /programs_for_testing/tests/segfault.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | int main() { 4 | char *c; 5 | *c = 3; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /programs_for_testing/games/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomWildenhain/pptcc/HEAD/programs_for_testing/games/a.out -------------------------------------------------------------------------------- /programs_for_testing/simple/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomWildenhain/pptcc/HEAD/programs_for_testing/simple/a.out -------------------------------------------------------------------------------- /programs_for_testing/tests/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomWildenhain/pptcc/HEAD/programs_for_testing/tests/a.out -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pptcc 2 | ![image representing the process](https://user-images.githubusercontent.com/13198444/78660768-f444cd80-78cd-11ea-97ad-a15cff51ca23.png) 3 | -------------------------------------------------------------------------------- /programs_for_testing/simple/d6.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int main() { 4 | ppt_putint(ppt_rand() % 6 + 1); 5 | ppt_putc('\n'); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /programs_for_testing/simple/helloworld.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int main() { 4 | ppt_puts("Hello "); 5 | ppt_puts("World!"); 6 | ppt_putc('\n'); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /programs_for_testing/pptlib.h: -------------------------------------------------------------------------------- 1 | void ppt_puts(char* s); 2 | 3 | void ppt_putint(int i); 4 | 5 | void ppt_putc(char c); 6 | 7 | void ppt_gets(char *buf); 8 | 9 | int ppt_getint(); 10 | 11 | int ppt_rand(); -------------------------------------------------------------------------------- /programs_for_testing/simple/twoplustwo.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int i = 2; 4 | 5 | int main() { 6 | int j = 2; 7 | if (i + j == 4) { 8 | return 0; 9 | } 10 | return 1; 11 | } -------------------------------------------------------------------------------- /programs_for_testing/simple/fibonacci.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int fib(int x) { 4 | if (x <= 1) return 1; 5 | return fib(x-1) + fib(x-2); 6 | } 7 | 8 | int main() { 9 | ppt_putint(fib(7)); 10 | ppt_putc('\n'); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /programs_for_testing/simple/factorial.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int factorial(int i) { 4 | if (i == 0) return 1; 5 | return i * factorial(i-1); 6 | } 7 | 8 | int main() { 9 | ppt_putint(factorial(4)); 10 | ppt_putc('\n'); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /programs_for_testing/simple/greeting.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int main() { 4 | char buf[20]; 5 | ppt_puts("What is your name?\n"); 6 | ppt_gets(buf); 7 | ppt_puts("Hello "); 8 | ppt_puts(buf); 9 | ppt_puts("!\n"); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /programs_for_testing/simple/gcd.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int gcd(int x, int y) { 4 | if (x == 0) return y; 5 | if (y == 0) return x; 6 | return gcd(y, x % y); 7 | } 8 | 9 | int main() { 10 | int x; 11 | int y; 12 | int g; 13 | ppt_puts("x = ?\n"); 14 | x = ppt_getint(); 15 | ppt_puts("y = ?\n"); 16 | y = ppt_getint(); 17 | g = gcd(x, y); 18 | ppt_puts("gcd(x, y) = "); 19 | ppt_putint(g); 20 | ppt_puts("\n"); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /programs_for_testing/simple/primes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../pptlib.h" 3 | 4 | bool isprime(int p) { 5 | int i; 6 | if (p < 2) return false; 7 | for (i = 2; i*i <= p; i++) { 8 | if (p % i == 0) return false; 9 | } 10 | return true; 11 | } 12 | 13 | int main() { 14 | int i = 0; 15 | while (true) { 16 | if (isprime(i)) { 17 | ppt_putint(i); 18 | ppt_puts(" is prime!\n"); 19 | } 20 | i++; 21 | } 22 | return 0; 23 | } -------------------------------------------------------------------------------- /programs_for_testing/tests/functionrefs.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | typedef int (*intfnptr)(int x); 4 | 5 | int fn1(int x) { 6 | return x / 4; 7 | } 8 | 9 | int fn2(int x) { 10 | return x * 50; 11 | } 12 | 13 | int fn3(int x) { 14 | return x + 1; 15 | } 16 | 17 | int main() { 18 | intfnptr fns[3] = { &fn3, &fn2, &fn1 }; 19 | int res = 20; 20 | unsigned int i = 0; 21 | for (i = 0; i < 3; i++) { 22 | res = (*fns[3-i-1])(res); 23 | } 24 | ppt_putint(res); 25 | ppt_putc('\n'); 26 | } -------------------------------------------------------------------------------- /programs_for_testing/tests/arithmetic.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | 3 | int a = 7; 4 | 5 | int main() { 6 | int b; 7 | 8 | ppt_puts("A=\n"); 9 | a = ppt_getint(); 10 | ppt_puts("B=\n"); 11 | b = ppt_getint(); 12 | ppt_puts("A+B="); 13 | ppt_putint(a+b); 14 | ppt_putc('\n'); 15 | ppt_puts("A-B="); 16 | ppt_putint(a-b); 17 | ppt_putc('\n'); 18 | ppt_puts("A/B="); 19 | ppt_putint(a/b); 20 | ppt_putc('\n'); 21 | ppt_puts("A%B="); 22 | ppt_putint(a%b); 23 | ppt_putc('\n'); 24 | ppt_puts("A*B="); 25 | ppt_putint(a*b); 26 | ppt_putc('\n'); 27 | ppt_puts("A 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void ppt_puts(char* s) { 8 | printf("%s", s); 9 | } 10 | 11 | void ppt_putint(int i) { 12 | printf("%d", i); 13 | } 14 | 15 | void ppt_putc(char c) { 16 | putc(c, stdout); 17 | } 18 | 19 | void ppt_gets(char *buf) { 20 | fgets(buf, INT_MAX, stdin); 21 | char *c = buf; 22 | while (*c != '\0') { 23 | c++; 24 | } 25 | c[-1] = '\0'; 26 | } 27 | 28 | int ppt_getint() { 29 | int i; 30 | scanf("%d", &i); 31 | return i; 32 | } 33 | 34 | int seeded = false; 35 | 36 | int ppt_rand() { 37 | if (!seeded) { 38 | srand(time(0)); 39 | seeded = true; 40 | } 41 | return rand(); 42 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Thomas Wildenhain 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pptcc.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import subprocess 3 | 4 | parser = argparse.ArgumentParser(description='Compile C to PPT CPU microcode.') 5 | parser.add_argument('file', help='.c files to compile', type=str) 6 | parser.add_argument('-o', help='output obj from wasm', action='store_true') 7 | parser.add_argument('-l', help='output listing file from wdis', action='store_true') 8 | parser.add_argument('-a', help='output pptasm file runnable on pptvm', action='store_true') 9 | 10 | args = parser.parse_args() 11 | print(args.file) 12 | 13 | # -0 -s 14 | 15 | WATCOM_PATH = 'C:\\WATCOM\\binnt\\%s.exe' 16 | 17 | def watcom_compile(source_file, output_path): 18 | subprocess.check_call([WATCOM_PATH % 'wcc', '-0', '-s', '-fo=' + output_path, source_file]) 19 | 20 | def watcom_dis(obj_file, output_masm_path, output_gas_path): 21 | subprocess.check_call([WATCOM_PATH % 'wdis', '-a', '-l=' + output_masm_path, obj_file]) 22 | subprocess.check_call([WATCOM_PATH % 'wdis', '-au', '-l=' + output_gas_path, obj_file]) 23 | 24 | def ppt_compile(ppt_asm_file, output_path): 25 | pass 26 | 27 | def main(): 28 | print('*** Compiling c code ***') 29 | watcom_compile(args.file, 'test.myout') 30 | print('*** Disassembling obj file ***') 31 | watcom_dis('test.myout', 'mytest.masm', 'mytest.gas') 32 | print('*** Compiling pptasm ***') 33 | ppt_asm('mytest.lst', 'sometest.pptasm') 34 | 35 | def ppt_asm(listing_file, output_path): 36 | pass 37 | 38 | 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /pptvm_tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import pptvm 3 | import copy 4 | 5 | class TestBitConversions(unittest.TestCase): 6 | def test_byte_v_uint(self): 7 | cases = [ 8 | ('00000000', 0), 9 | ('10000001', 2**7+1), 10 | ('11111111', 2**8-1), 11 | ('00000101', 5) 12 | ] 13 | for b, i in cases: 14 | self.assertEqual(pptvm.byte_to_uint(b), i) 15 | self.assertEqual(pptvm.uint_to_byte(i), b) 16 | 17 | def test_byte_v_int(self): 18 | cases = [ 19 | ('00000000', 0), 20 | ('10000000', -2**7), 21 | ('11111111', -1), 22 | ('00000101', 5), 23 | ('11111011', -5) 24 | ] 25 | for b, i in cases: 26 | self.assertEqual(pptvm.byte_to_int(b), i) 27 | self.assertEqual(pptvm.int_to_byte(i), b) 28 | 29 | def test_dword_v_int(self): 30 | cases = [ 31 | ('00000000', '00000000', '00000000', '00000000', 0), 32 | ('00000000', '00000000', '00000000', '00000101', 5), 33 | ('11111111', '11111111', '11111111', '11111111', -1), 34 | ('00000000', '00000001', '00000000', '00000000', 2**16), 35 | ] 36 | for b1, b2, b3, b4, i in cases: 37 | self.assertEqual(pptvm.dword_to_int(b1+b2+b3+b4), i) 38 | h, l = pptvm.int_to_dword(i) 39 | self.assertEqual(h + l, b1+b2+b3+b4) 40 | 41 | class TestMachineInstructions(unittest.TestCase): 42 | def setUp(self): 43 | const_dict = {pptvm.uint_to_word(i+2**15): pptvm.uint_to_word(i*10) for i in range(20)} 44 | data_dict = {pptvm.uint_to_word(i): pptvm.uint_to_word(i*20) for i in range(20)} 45 | pptasm_dict = { 46 | 'code': {}, 47 | 'const': const_dict, 48 | 'data': data_dict, 49 | } 50 | self.machine_state = pptvm.MachineState(pptasm_dict) 51 | 52 | 53 | if __name__ == '__main__': 54 | unittest.main() -------------------------------------------------------------------------------- /pptutils.py: -------------------------------------------------------------------------------- 1 | def hex_to_int(hex): 2 | assert hex.startswith('0x') 3 | hex = hex[2:] 4 | total = 0 5 | for h in hex: 6 | total *= 16 7 | total += '0123456789abcdef'.index(h) 8 | return total 9 | 10 | def byte_to_uint(byte): 11 | total = 0 12 | for c in byte: 13 | total *= 2 14 | if c == '1': 15 | total += 1 16 | return total 17 | 18 | def byte_to_int(byte): 19 | total = 0 20 | for c in byte: 21 | total *= 2 22 | if c == '1': 23 | total += 1 24 | return total if byte[0] == '0' else total - 2**8 25 | 26 | def word_to_int(word): 27 | total = 0 28 | for c in word: 29 | total *= 2 30 | if c == '1': 31 | total += 1 32 | return total if word[0] == '0' else total - 2**16 33 | 34 | def dword_to_int(dword): 35 | total = 0 36 | for c in dword: 37 | total *= 2 38 | if c == '1': 39 | total += 1 40 | return total if dword[0] == '0' else total - 2**32 41 | 42 | def word_to_uint(word): 43 | total = 0 44 | for c in word: 45 | total *= 2 46 | if c == '1': 47 | total += 1 48 | return total 49 | 50 | def dword_to_uint(dword): 51 | total = 0 52 | for c in dword: 53 | total *= 2 54 | if c == '1': 55 | total += 1 56 | return total 57 | 58 | def int_to_byte(x): 59 | if x < 0: 60 | x += 2**8 61 | res = '' 62 | for i in range(8): 63 | if x % 2 == 1: 64 | res = '1' + res 65 | else: 66 | res = '0' + res 67 | x = x // 2 68 | return res 69 | 70 | def int_to_word(x): 71 | if x < 0: 72 | x += 2**16 73 | res = '' 74 | for i in range(16): 75 | if x % 2 == 1: 76 | res = '1' + res 77 | else: 78 | res = '0' + res 79 | x = x // 2 80 | return res 81 | 82 | def uint_to_word(x): 83 | res = '' 84 | for i in range(16): 85 | if x % 2 == 1: 86 | res = '1' + res 87 | else: 88 | res = '0' + res 89 | x = x // 2 90 | return res 91 | 92 | def uint_to_dword(x): 93 | res = '' 94 | for i in range(32): 95 | if x % 2 == 1: 96 | res = '1' + res 97 | else: 98 | res = '0' + res 99 | x = x // 2 100 | return res[:16], res[16:] 101 | 102 | def int_to_dword(x): 103 | if x < 0: 104 | x += 2**32 105 | res = '' 106 | for i in range(32): 107 | if x % 2 == 1: 108 | res = '1' + res 109 | else: 110 | res = '0' + res 111 | x = x // 2 112 | return res[:16], res[16:] 113 | 114 | def uint_to_byte(x): 115 | res = '' 116 | for i in range(8): 117 | if x % 2 == 1: 118 | res = '1' + res 119 | else: 120 | res = '0' + res 121 | x = x // 2 122 | return res 123 | 124 | def split_on_spaces(s): 125 | parts = s.replace('\t', ' ').split(' ') 126 | parts = [p.strip() for p in parts if p.strip()] 127 | return parts 128 | 129 | def condense_spaces(s): 130 | return ' '.join(split_on_spaces(s)) 131 | 132 | def pad_to_length(s, l): 133 | assert l >= len(s) 134 | return s + ' ' * (l - len(s)) -------------------------------------------------------------------------------- /autoclicker.py: -------------------------------------------------------------------------------- 1 | import pyautogui 2 | import win32gui 3 | import time 4 | import random 5 | 6 | # While background middle pixel is active color: 7 | # Find click colors 8 | 9 | ACTIVE_COLOR = (0, 94, 172) 10 | WALL_COLOR = (255, 28, 228) 11 | CLICK_COLORS = [(209, 69, 38), (232, 122, 0)] 12 | WAIT_COLOR = (255, 255, 255) 13 | pyautogui.PAUSE = 0.025 14 | (width, height) = pyautogui.size() 15 | screenshot = None 16 | last_screenshot_time = None 17 | 18 | def get_pixel_at(x, y, refresh=False): 19 | if not (0 <= x < width and 0 <= y < height): 20 | return None 21 | global last_screenshot_time 22 | global screenshot 23 | if refresh or screenshot is None or time.time() - last_screenshot_time > 0.2: 24 | screenshot = pyautogui.screenshot() 25 | last_screenshot_time = time.time() 26 | return screenshot.getpixel((x, y)) 27 | 28 | def pixel_matches_color(x, y, color): 29 | return get_pixel_at(x, y) == color 30 | 31 | def main(): 32 | while True: 33 | if is_active() and not mouse_is_spinner(): 34 | mx, my = pyautogui.position() 35 | if not (can_click_new(mx, my) or can_click(mx, my)): 36 | x = random.randint(0, width-1) 37 | y = random.randint(0, height-1) 38 | if can_click_new(x, y) or can_click(x, y): 39 | pyautogui.moveTo(x, y) 40 | if mouse_is_hand(): 41 | color = get_pixel_at(x, y) 42 | pyautogui.click() 43 | if 0.3 <= x/width <= 0.7 and 0.44 <= y/height <= 0.91: 44 | timeout = time.time() + 0.2 45 | while pixel_matches_color(x, y, color) and time.time() < timeout: 46 | pass 47 | else: 48 | timeout = time.time() + 0.2 49 | while not mouse_is_spinner() and time.time() < timeout: 50 | pass 51 | while mouse_is_spinner(): 52 | pass 53 | 54 | 55 | def is_active(): 56 | return pixel_matches_color(0, height//2, ACTIVE_COLOR) 57 | 58 | def can_click_new(x, y): 59 | if not get_pixel_at(x, y) in CLICK_COLORS: 60 | return False 61 | mx, my = pyautogui.position() 62 | while my > 0: 63 | if pixel_matches_color(mx, my, WALL_COLOR): 64 | return False 65 | my -= 1 66 | 67 | dx = 1 if x > mx else -1 68 | 69 | while mx != x: 70 | if pixel_matches_color(mx, my, WALL_COLOR): 71 | return False 72 | mx += dx 73 | 74 | while my < y: 75 | if pixel_matches_color(mx, my, WALL_COLOR): 76 | return False 77 | my += 1 78 | 79 | return True 80 | 81 | def can_click(x, y): 82 | if not get_pixel_at(x, y) in CLICK_COLORS: 83 | return False 84 | mx, my = pyautogui.position() 85 | dx = x - mx 86 | dy = y - my 87 | scale = max(abs(dx), abs(dy)) 88 | if scale == 0: 89 | return True 90 | if dx == 0: 91 | dx = 1 92 | if dy == 0: 93 | dy = 1 94 | dx *= 2 / scale 95 | dy *= 2 / scale 96 | xpositive = dx > 0 97 | ypositive = dy > 0 98 | while (mx < x) == xpositive or (my < y) == ypositive: 99 | mx += dx 100 | my += dy 101 | if pixel_matches_color(mx, my, WALL_COLOR): 102 | return False 103 | return True 104 | 105 | def mouse_is_hand(): 106 | return win32gui.GetCursorInfo()[1] == 65567 107 | 108 | def mouse_is_spinner(): 109 | return win32gui.GetCursorInfo()[1] == 65543 110 | 111 | main() 112 | -------------------------------------------------------------------------------- /programs_for_testing/games/blackjack.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | bool high_ace; 7 | int total; 8 | } score; 9 | 10 | void update_score(score *p, int c) { 11 | int v = (c % 13) + 1; 12 | if (v == 1) { 13 | p->high_ace = true; 14 | p->total += 11; 15 | } 16 | else { 17 | p->total += v < 10 ? v : 10; 18 | } 19 | if (p->total > 21 && p->high_ace) { 20 | p->high_ace = false; 21 | p->total -= 10; 22 | } 23 | } 24 | 25 | void put_card(int c) { 26 | int v = (c % 13) + 1; 27 | if (v == 1) { 28 | ppt_putc('A'); 29 | } 30 | else if (v > 10) { 31 | ppt_putc("JQK"[v-11]); 32 | } 33 | else { 34 | ppt_putint(v); 35 | } 36 | } 37 | 38 | int main() { 39 | int deck[52]; 40 | int i; 41 | int j; 42 | int top; 43 | int dealer1; 44 | int dealer2; 45 | int player1; 46 | int player2; 47 | char move[2]; 48 | int c; 49 | score dealer_score = {false, 0}; 50 | score player_score = {false, 0}; 51 | 52 | deck[0] = 0; 53 | for (i = 1; i < 52; i++) { 54 | j = ppt_rand() % i; 55 | deck[i] = deck[j]; 56 | deck[j] = i; 57 | } 58 | top = 0; 59 | 60 | ppt_puts("D: "); 61 | dealer1 = deck[top++]; 62 | update_score(&dealer_score, dealer1); 63 | put_card(dealer1); 64 | ppt_putc(','); 65 | dealer2 = deck[top++]; 66 | update_score(&dealer_score, dealer2); 67 | if (dealer_score.total == 21) { 68 | put_card(dealer2); 69 | ppt_puts("\n=>21\n"); 70 | } 71 | else { 72 | ppt_puts("?\n"); 73 | } 74 | 75 | ppt_puts("P: "); 76 | player1 = deck[top++]; 77 | update_score(&player_score, player1); 78 | put_card(player1); 79 | ppt_putc(','); 80 | player2 = deck[top++]; 81 | update_score(&player_score, player2); 82 | put_card(player2); 83 | 84 | if (player_score.total == 21) { 85 | ppt_puts("\n=>21\n"); 86 | if (dealer_score.total == 21) { 87 | ppt_puts("Tie!\n"); 88 | return 0; 89 | } 90 | else { 91 | ppt_puts("Player wins!\n"); 92 | return 0; 93 | } 94 | } 95 | 96 | if (dealer_score.total == 21) { 97 | ppt_puts("\nDealer wins!\n"); 98 | return 0; 99 | } 100 | 101 | ppt_puts("\nH/S?\n"); 102 | ppt_gets(move); 103 | while (move[0] == 'H' || move[0] == 'h') { 104 | c = deck[top++]; 105 | put_card(c); 106 | ppt_putc('\n'); 107 | update_score(&player_score, c); 108 | if (player_score.total > 21) { 109 | ppt_puts("=>bust\nDealer wins!\n"); 110 | return 0; 111 | } 112 | else if (player_score.total == 21) { 113 | break; 114 | } 115 | ppt_gets(move); 116 | } 117 | ppt_puts("=>"); 118 | ppt_putint(player_score.total); 119 | 120 | ppt_puts("\nD: "); 121 | put_card(dealer1); 122 | ppt_putc(','); 123 | put_card(dealer2); 124 | while (dealer_score.total < 17) { 125 | c = deck[top++]; 126 | ppt_putc(','); 127 | put_card(c); 128 | update_score(&dealer_score, c); 129 | } 130 | if (dealer_score.total > 21) { 131 | ppt_puts("\n=>bust\nPlayer wins!\n"); 132 | return 0; 133 | } 134 | else { 135 | ppt_puts("\n=>"); 136 | ppt_putint(dealer_score.total); 137 | } 138 | 139 | if (dealer_score.total > player_score.total) { 140 | ppt_puts("\nDealer wins!\n"); 141 | } 142 | else if (dealer_score.total == player_score.total) { 143 | ppt_puts("\nTie!\n"); 144 | } 145 | else { 146 | ppt_puts("\nPlayer wins!\n"); 147 | } 148 | return 0; 149 | } -------------------------------------------------------------------------------- /programs_for_testing/tests/blackjackmodified.c: -------------------------------------------------------------------------------- 1 | #include "../pptlib.h" 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | bool high_ace; 7 | int total; 8 | } score; 9 | 10 | int test_const[] = {1, 2, 3, 'H', "Hello", "World"}; 11 | 12 | char s2[4] = { 'a','a',3, 'b' }; 13 | 14 | void update_score(score *p, int c) { 15 | int v = (c % 13) + 1; 16 | if (v == 1) { 17 | p->high_ace = true; 18 | p->total += 11; 19 | } 20 | else { 21 | p->total += v < 10 ? v : 10; 22 | } 23 | if (p->total > 21 && p->high_ace) { 24 | p->high_ace = false; 25 | p->total -= 10; 26 | } 27 | } 28 | 29 | int test_ptr = &test_const[-1]; 30 | 31 | void put_card(int c) { 32 | int v = (c % 13) + 1; 33 | if (v == 1) { 34 | ppt_putc('A'); 35 | } 36 | if (v == 0) { 37 | ppt_putc('X'); 38 | v += 3000; 39 | v = v >> 3; 40 | if (v == 2000) { 41 | ppt_putc('X'); 42 | } 43 | } 44 | else if (v > 10) { 45 | ppt_putc("JQK"[v-11]); 46 | } 47 | else { 48 | ppt_putint(v); 49 | } 50 | } 51 | 52 | int main() { 53 | int deck[52]; 54 | int i; 55 | int j; 56 | int top; 57 | int dealer1; 58 | int dealer2; 59 | int player1; 60 | int player2; 61 | char move[2]; 62 | int c; 63 | score dealer_score = {false, 0}; 64 | score player_score = {false, 0}; 65 | 66 | deck[0] = 0; 67 | for (i = 1; i < 52; i++) { 68 | j = ppt_rand(i); 69 | deck[i] = deck[j]; 70 | deck[j] = i; 71 | } 72 | top = 0; 73 | 74 | ppt_puts("D: "); 75 | dealer1 = deck[top++]; 76 | update_score(&dealer_score, dealer1); 77 | put_card(dealer1); 78 | ppt_putc(','); 79 | dealer2 = deck[top++]; 80 | update_score(&dealer_score, dealer2); 81 | if (dealer_score.total == 21) { 82 | put_card(dealer2); 83 | ppt_puts("\n=>21\n"); 84 | } 85 | else { 86 | ppt_puts("?\n"); 87 | } 88 | 89 | ppt_puts("P: "); 90 | player1 = deck[top++]; 91 | update_score(&player_score, player1); 92 | put_card(player1); 93 | ppt_putc(','); 94 | player2 = deck[top++]; 95 | update_score(&player_score, player2); 96 | put_card(player2); 97 | 98 | if (player_score.total == 21) { 99 | ppt_puts("\n=>21\n"); 100 | if (dealer_score.total == 21) { 101 | ppt_puts("Tie!\n"); 102 | return 0; 103 | } 104 | else { 105 | ppt_puts("Player wins!\n"); 106 | return 0; 107 | } 108 | } 109 | 110 | if (dealer_score.total == 21) { 111 | ppt_puts("\nDealer wins!\n"); 112 | return 0; 113 | } 114 | 115 | ppt_puts("\nH/S?\n"); 116 | ppt_gets(move); 117 | while (move[0] == 'H' || move[0] == 'h') { 118 | c = deck[top++]; 119 | put_card(c); 120 | ppt_putc('\n'); 121 | update_score(&player_score, c); 122 | if (player_score.total > 21) { 123 | ppt_puts("=>bust\nDealer wins!\n"); 124 | return 0; 125 | } 126 | else if (player_score.total == 21) { 127 | break; 128 | } 129 | ppt_gets(move); 130 | } 131 | ppt_puts("=>"); 132 | ppt_putint(player_score.total); 133 | 134 | ppt_puts("\nD: "); 135 | put_card(dealer1); 136 | ppt_putc(','); 137 | put_card(dealer2); 138 | while (dealer_score.total < 17) { 139 | c = deck[top++]; 140 | ppt_putc(','); 141 | put_card(c); 142 | update_score(&dealer_score, c); 143 | } 144 | if (dealer_score.total > 21) { 145 | ppt_puts("\n=>bust\nPlayer wins!\n"); 146 | return 0; 147 | } 148 | else { 149 | ppt_puts("\n=>"); 150 | ppt_putint(dealer_score.total); 151 | } 152 | 153 | if (dealer_score.total > player_score.total) { 154 | ppt_puts("\nDealer wins!\n"); 155 | } 156 | else if (dealer_score.total == player_score.total) { 157 | ppt_puts("\nTie!\n"); 158 | } 159 | else { 160 | ppt_puts("\nPlayer wins!\n"); 161 | } 162 | return 0; 163 | } 164 | 165 | int cool_sum(a, b, c, d, e, f, g) { 166 | return a + b + c+d+e+f+g; 167 | } 168 | 169 | int (*global_fn_ref)() = &cool_sum; 170 | 171 | int test_sum() { 172 | int (*x)() = &cool_sum; 173 | if (x > 0) { 174 | global_fn_ref(); 175 | } 176 | return cool_sum(1, 2, 3, 4, 5, test_const[3], 7); 177 | } -------------------------------------------------------------------------------- /pptvm.py: -------------------------------------------------------------------------------- 1 | import random 2 | import argparse 3 | from pptutils import * 4 | 5 | class Instruction: 6 | def __init__(self, cmd, args): 7 | self.cmd = cmd 8 | self.args = args 9 | 10 | class ByteRegister: 11 | def __init__(self, name): 12 | self.name = name 13 | self.value = '0' * 8 14 | 15 | class MemRegister: 16 | def __init__(self, name): 17 | self.name = name 18 | self.low = '0' * 8 19 | self.high = '0' * 8 20 | 21 | def read(self): 22 | return self.high + self.low 23 | 24 | def assign(self, bits): 25 | self.high = bits[:8] 26 | self.low = bits[8:] 27 | 28 | class Flags: 29 | def __init__(self): 30 | self.verdict = False 31 | self.carry = False 32 | self.zero = False 33 | self.sign = False 34 | self.overflow = False 35 | 36 | def inc_bits(w): 37 | if w == '': 38 | return '' 39 | if w[-1] == '0': 40 | return w[:-1] + '1' 41 | else: 42 | return inc_bits(w[:-1]) + '0' 43 | 44 | def dec_bits(w): 45 | if w == '': 46 | return '' 47 | if w[-1] == '1': 48 | return w[:-1] + '0' 49 | else: 50 | return dec_bits(w[:-1]) + '1' 51 | 52 | def and_bits(x, y): 53 | if x == '0': 54 | return '0' 55 | else: 56 | return y 57 | 58 | def or_bits(x, y): 59 | if x == '1': 60 | return '1' 61 | else: 62 | return y 63 | 64 | def xor_bits(x, y): 65 | if x == y: 66 | return '0' 67 | else: 68 | return '1' 69 | 70 | class MachineState: 71 | def __init__(self, text_dict, data_dict, const_dict): 72 | self.instructions = text_dict 73 | self.const = const_dict 74 | self.data = data_dict 75 | reg_names = [ 76 | 'AH', 'AL', 'BH', 'BL', 'CH', 'CL', 'DH', 'DL', 77 | 'M4H', 'M4L', 'M5H', 'M5L', 78 | 'DIH', 'DIL', 'SIH', 'SIL', 'BPH', 'BPL', 'SPH', 'SPL'] 79 | self.regs = { r: ByteRegister(r) for r in reg_names } 80 | self.flags = Flags() 81 | self.m1 = MemRegister('M1') 82 | self.m2 = MemRegister('M2') 83 | self.m3 = MemRegister('M3') 84 | self.ip = '0' * 16 85 | self.mp = '0' * 16 86 | 87 | def step(self): 88 | if self.ip not in self.instructions: 89 | raise Exception('ip out of range') 90 | assert self._read_reg('SP')[-1] == '0' 91 | assert len(self.m2.low) == 8 92 | assert len(self.m3.low) == 8 93 | inst = self.instructions[self.ip] 94 | self.ip = inc_bits(self.ip) 95 | if inst.cmd == 'LOAD1L': 96 | if inst.args[0] == 'M3H': 97 | self.m1.low = self.m3.high 98 | elif inst.args[0] == 'M3L': 99 | self.m1.low = self.m3.low 100 | else: 101 | self.m1.low = self.regs[inst.args[0]].value 102 | elif inst.cmd == 'LOAD1H': 103 | if inst.args[0] == 'M3H': 104 | self.m1.high = self.m3.high 105 | elif inst.args[0] == 'M3L': 106 | self.m1.high = self.m3.low 107 | else: 108 | self.m1.high = self.regs[inst.args[0]].value 109 | elif inst.cmd == 'LOAD2L': 110 | if inst.args[0] == 'M3H': 111 | self.m2.low = self.m3.high 112 | elif inst.args[0] == 'M3L': 113 | self.m2.low = self.m3.low 114 | else: 115 | self.m2.low = self.regs[inst.args[0]].value 116 | elif inst.cmd == 'LOAD2H': 117 | if inst.args[0] == 'M3H': 118 | self.m2.high = self.m3.high 119 | elif inst.args[0] == 'M3L': 120 | self.m2.high = self.m3.low 121 | else: 122 | self.m2.high = self.regs[inst.args[0]].value 123 | elif inst.cmd == 'COPYL': 124 | self.m3.low = self.m1.low 125 | elif inst.cmd == 'COPYH': 126 | self.m3.high = self.m1.high 127 | elif inst.cmd == 'STOREL': 128 | self.regs[inst.args[0]].value = self.m3.low 129 | elif inst.cmd == 'STOREH': 130 | self.regs[inst.args[0]].value = self.m3.high 131 | elif inst.cmd == 'CLEARL1': 132 | self.m1.low = '0' * 8 133 | elif inst.cmd == 'CLEARH1': 134 | self.m1.high = '0' * 8 135 | elif inst.cmd == 'CLEARL2': 136 | self.m2.low = '0' * 8 137 | elif inst.cmd == 'CLEARH2': 138 | self.m2.high = '0' * 8 139 | elif inst.cmd == 'CLEARL3': 140 | self.m3.low = '0' * 8 141 | elif inst.cmd == 'CLEARH3': 142 | self.m3.high = '0' * 8 143 | elif inst.cmd == 'CONSTL': 144 | self.m3.low = inst.args[0] 145 | elif inst.cmd == 'CONSTH': 146 | self.m3.high = inst.args[0] 147 | elif inst.cmd == 'EXEC': 148 | name = inst.args[0] 149 | assert name == name.upper() 150 | getattr(self, 'exec_' + name.lower())() 151 | 152 | def _assign_reg(self, letter, value): 153 | assert len(value) == 16 154 | self.regs[letter + 'H'].value = value[:8] 155 | self.regs[letter + 'L'].value = value[8:] 156 | 157 | def _read_reg(self, letter): 158 | return self.regs[letter + 'H'].value + self.regs[letter + 'L'].value 159 | 160 | def _addb(self, with_carry=False): 161 | res = ['0'] * 8 162 | carry = False 163 | if with_carry: 164 | carry = self.flags.carry 165 | for i in range(7, -1, -1): 166 | if i == 7: 167 | self.flags.overflow = carry 168 | total = 1 if self.m1.low[i] == '1' else 0 169 | total += 1 if self.m2.low[i] == '1' else 0 170 | if carry: 171 | total += 1 172 | if total == 0: 173 | carry = False 174 | elif total == 1: 175 | carry = False 176 | res[i] = '1' 177 | elif total == 2: 178 | carry = True 179 | elif total == 3: 180 | carry = True 181 | res[i] = '1' 182 | else: 183 | assert False 184 | self.flags.carry = carry 185 | self.flags.sign = res[0] == '1' 186 | self.m3.low = ''.join(res) 187 | self.flags.zero = self.m3.low == '0' * 8 188 | 189 | def exec_adcb(self): 190 | self._addb(with_carry=True) 191 | 192 | def _addw(self, with_carry=False): 193 | res = ['0'] * 16 194 | carry = False 195 | if with_carry: 196 | carry = self.flags.carry 197 | for i in range(15, -1, -1): 198 | if i == 15: 199 | self.flags.overflow = carry 200 | total = 1 if self.m1.read()[i] == '1' else 0 201 | total += 1 if self.m2.read()[i] == '1' else 0 202 | if carry: 203 | total += 1 204 | if total == 0: 205 | carry = False 206 | elif total == 1: 207 | carry = False 208 | res[i] = '1' 209 | elif total == 2: 210 | carry = True 211 | elif total == 3: 212 | carry = True 213 | res[i] = '1' 214 | else: 215 | assert False 216 | self.flags.carry = carry 217 | self.flags.sign = res[0] == '1' 218 | self.m3.assign(''.join(res)) 219 | self.flags.zero = self.m3.read() == '0' * 16 220 | 221 | def exec_adcw(self): 222 | self._addw(with_carry=True) 223 | 224 | def exec_addb(self): # Used 225 | self._addb(with_carry=False) 226 | 227 | def exec_addw(self): # Used 228 | self._addw(with_carry=False) 229 | 230 | def _shiftaddr(self, n=1): 231 | addr = self.m1.read() 232 | addr = addr[n:] + '0' * n 233 | self.m3.assign(addr) 234 | 235 | def exec_shiftaddr1(self): 236 | self._shiftaddr(1) 237 | 238 | def exec_shiftaddr2(self): 239 | self._shiftaddr(2) 240 | 241 | def exec_shiftaddr3(self): 242 | self._shiftaddr(3) 243 | 244 | def exec_addaddr(self): 245 | res = ['0'] * 16 246 | carry = False 247 | for i in range(15, -1, -1): 248 | total = 1 if self.m1.read()[i] == '1' else 0 249 | total += 1 if self.m2.read()[i] == '1' else 0 250 | if carry: 251 | total += 1 252 | if total == 0: 253 | carry = False 254 | elif total == 1: 255 | carry = False 256 | res[i] = '1' 257 | elif total == 2: 258 | carry = True 259 | elif total == 3: 260 | carry = True 261 | res[i] = '1' 262 | self.m3.assign(''.join(res)) 263 | 264 | def _bitwiseb(self, fn): 265 | res = ['0'] * 8 266 | for i in range(8): 267 | res[i] = fn(self.m1.low[i], self.m2.low[i]) 268 | self.m3.low = ''.join(res) 269 | self.flags.zero = self.m3.low == '0' * 8 270 | self.flags.sign = self.m3.low[0] == '1' 271 | 272 | def _bitwisew(self, fn): 273 | res = ['0'] * 16 274 | for i in range(16): 275 | res[i] = fn(self.m1.read()[i], self.m2.read()[i]) 276 | self.m3.assign(''.join(res)) 277 | self.flags.zero = self.m3.read() == '0' * 16 278 | self.flags.sign = self.m3.high[0] == '1' 279 | 280 | def exec_andb(self): 281 | self._bitwiseb(and_bits) 282 | 283 | def exec_andw(self): 284 | self._bitwisew(and_bits) 285 | 286 | def exec_cbw(self): 287 | if self.regs['AL'].value[0] == '1': 288 | self.regs['AH'].value = '1' * 8 289 | else: 290 | self.regs['AH'].value = '0' * 8 291 | 292 | def exec_clc(self): 293 | self.flags.carry = False 294 | 295 | def exec_cmc(self): 296 | self.flags.carry = not self.flags.carry 297 | 298 | def exec_cmpb(self): 299 | m3 = self.m3.low 300 | self.exec_subb() 301 | self.m3.low = m3 302 | 303 | def exec_cmpw(self): 304 | m3 = self.m3.read() 305 | self.exec_subw() 306 | self.m3.assign(m3) 307 | 308 | def exec_decb(self): 309 | res = ['0'] * 8 310 | borrow = True 311 | for i in range(7, -1, -1): 312 | if i == 7: 313 | self.flags.overflow = borrow 314 | if borrow: 315 | if self.m1.low[i] == '1': 316 | res[i] = '0' 317 | borrow = False 318 | else: 319 | res[i] = '1' 320 | else: 321 | res[i] = self.m1.low[i] 322 | self.m3.low = ''.join(res) 323 | self.flags.sign = self.m3.low[0] 324 | self.flags.carry = borrow 325 | self.flags.zero = self.m3.low == '0' * 8 326 | 327 | def exec_decw(self): 328 | res = ['0'] * 16 329 | borrow = True 330 | for i in range(15, -1, -1): 331 | if i == 15: 332 | self.flags.overflow = borrow 333 | if borrow: 334 | if self.m1.read()[i] == '1': 335 | res[i] = '0' 336 | borrow = False 337 | else: 338 | res[i] = '1' 339 | else: 340 | res[i] = self.m1.read()[i] 341 | self.m3.assign(''.join(res)) 342 | self.flags.sign = self.m3.high[0] 343 | self.flags.carry = borrow 344 | self.flags.zero = self.m3.read() == '0' * 16 345 | 346 | def exec_dec2w(self): 347 | x = word_to_uint(self.m1.read()) - 2 348 | self.m3.assign(uint_to_word(x)) 349 | 350 | def exec_inc2w(self): 351 | x = word_to_uint(self.m1.read()) + 2 352 | self.m3.assign(uint_to_word(x)) 353 | 354 | def exec_cwd(self): 355 | if self.regs['AH'].value[0] == '1': 356 | self.regs['DH'].value = '1' * 8 357 | self.regs['DL'].value = '1' * 8 358 | else: 359 | self.regs['DH'].value = '0' * 8 360 | self.regs['DL'].value = '0' * 8 361 | 362 | # TODO: Division 363 | 364 | def exec_divb(self): 365 | x = word_to_uint(self._read_reg('A')) 366 | y = byte_to_uint(self.m1.low) 367 | z = x // y 368 | w = x % y 369 | self.regs['AL'].value = uint_to_byte(z) 370 | self.regs['AH'].value = uint_to_byte(w) 371 | 372 | def exec_divw(self): 373 | xdw = self._read_reg('D') + self._read_reg('A') 374 | x = dword_to_uint(xdw) 375 | y = word_to_uint(self.m1.read()) 376 | z = x // y 377 | w = x % y 378 | self._assign_reg('A', uint_to_word(z)) 379 | self._assign_reg('D', uint_to_word(w)) 380 | 381 | def exec_idivb(self): 382 | x = word_to_int(self._read_reg('A')) 383 | y = byte_to_int(self.m1.low) 384 | if x < 0: 385 | x = -x 386 | y = -y 387 | if y >= 0: 388 | z = x // y 389 | w = x % y 390 | else: 391 | z = (x + y + 1) // y 392 | w = x - z * y 393 | self.regs['AL'].value = int_to_byte(z) 394 | self.regs['AH'].value = int_to_byte(w) 395 | 396 | def exec_idivw(self): 397 | xdw = self._read_reg('D') + self._read_reg('A') 398 | x = dword_to_int(xdw) 399 | y = word_to_int(self.m1.read()) 400 | if x < 0: 401 | x = -x 402 | y = -y 403 | if y >= 0: 404 | z = x // y 405 | w = x % y 406 | else: 407 | z = (x + y + 1) // y 408 | w = x - z * y 409 | self._assign_reg('A', int_to_word(z)) 410 | self._assign_reg('D', int_to_word(w)) 411 | 412 | def exec_imulb(self): 413 | x = byte_to_int(self.regs['AL'].value) 414 | y = byte_to_int(self.m1.low) 415 | z = x * y 416 | res = int_to_word(z) 417 | self._assign_reg('A', res) 418 | if byte_to_int(self.regs['AL'].value) == z: 419 | self.flags.carry = False 420 | self.flags.overflow = False 421 | else: 422 | self.flags.carry = True 423 | self.flags.overflow = True 424 | 425 | def exec_imulw(self): 426 | x = word_to_int(self._read_reg('A')) 427 | y = word_to_int(self.m1.read()) 428 | z = x * y 429 | zh, zl = int_to_dword(z) 430 | self._assign_reg('D', zh) 431 | self._assign_reg('A', zl) 432 | if word_to_int(self._read_reg('A')) == z: 433 | self.flags.carry = False 434 | self.flags.overflow = False 435 | else: 436 | self.flags.carry = True 437 | self.flags.overflow = True 438 | 439 | def exec_mulb(self): 440 | x = byte_to_uint(self.regs['AL'].value) 441 | y = byte_to_uint(self.m1.low) 442 | z = x * y 443 | res = uint_to_word(z) 444 | self._assign_reg('A', res) 445 | if self.regs['AH'].value == '0' * 8: 446 | self.flags.carry = False 447 | self.flags.overflow = False 448 | else: 449 | self.flags.carry = True 450 | self.flags.overflow = True 451 | 452 | def exec_mulw(self): 453 | x = word_to_uint(self._read_reg('A')) 454 | y = word_to_uint(self.m1.read()) 455 | z = x * y 456 | zh, zl = uint_to_dword(z) 457 | self._assign_reg('D', zh) 458 | self._assign_reg('A', zl) 459 | if self._read_reg('D') == '0' * 16: 460 | self.flags.carry = False 461 | self.flags.overflow = False 462 | else: 463 | self.flags.carry = True 464 | self.flags.overflow = True 465 | 466 | def exec_incb(self): 467 | res = ['0'] * 8 468 | carry = True 469 | for i in range(7, -1, -1): 470 | if i == 7: 471 | self.flags.overflow = carry 472 | if carry: 473 | if self.m1.low[i] == '0': 474 | res[i] = '1' 475 | carry = False 476 | else: 477 | res[i] = '0' 478 | carry = True 479 | else: 480 | res[i] = self.m1.low[i] 481 | self.m3.low = ''.join(res) 482 | self.flags.sign = self.m3.low[0] 483 | self.flags.carry = carry 484 | self.flags.zero = self.m3.low == '0' * 8 485 | 486 | def exec_incw(self): 487 | res = ['0'] * 16 488 | carry = True 489 | for i in range(15, -1, -1): 490 | if i == 15: 491 | self.flags.overflow = carry 492 | if carry: 493 | if self.m1.read()[i] == '0': 494 | res[i] = '1' 495 | carry = False 496 | else: 497 | res[i] = '0' 498 | else: 499 | res[i] = self.m1.read()[i] 500 | 501 | self.m3.assign(''.join(res)) 502 | self.flags.sign = self.m3.high[0] 503 | self.flags.carry = carry 504 | self.flags.zero = self.m3.read() == '0' * 16 505 | 506 | # TODO: IRET 507 | 508 | def exec_va(self): 509 | self.flags.verdict = not self.flags.carry and not self.flags.zero 510 | 511 | def exec_vc(self): 512 | self.flags.verdict = self.flags.carry 513 | 514 | def exec_vz(self): 515 | self.flags.verdict = self.flags.zero 516 | 517 | def exec_vo(self): 518 | self.flags.verdict = self.flags.overflow 519 | 520 | def exec_vs(self): 521 | self.flags.verdict = self.flags.sign 522 | 523 | def exec_vg(self): 524 | self.flags.verdict = not self.flags.zero and (self.flags.sign == self.flags.overflow) 525 | 526 | def exec_vl(self): 527 | self.flags.verdict = self.flags.sign != self.flags.overflow 528 | 529 | def exec_nv(self): 530 | self.flags.verdict = not self.flags.verdict 531 | 532 | def exec_jmp(self): # Used 533 | assert(self.regs['SPH'].value[0] == '1') 534 | self.ip = self.m1.read() 535 | 536 | def exec_jv(self): # Used 537 | if self.flags.verdict: 538 | self.ip = self.m1.read() 539 | 540 | def exec_rmem(self): # Used 541 | if self.mp[0] == '1': 542 | self.m3.low = self.data[self.mp] 543 | else: 544 | self.m3.low = self.const[self.mp] 545 | 546 | def exec_wmem(self): 547 | assert self.mp[0] == '1' 548 | # assert self.mp in self.data 549 | self.data[self.mp] = self.m2.low 550 | 551 | def exec_smp(self): 552 | self.mp = self.m1.read() 553 | 554 | def exec_imp(self): 555 | self.mp = inc_bits(self.mp) 556 | 557 | def exec_dmp(self): 558 | self.mp = dec_bits(self.mp) 559 | 560 | def exec_negb(self): 561 | res = ['0'] * 8 562 | for i in range(8): 563 | res[i] = '0' if self.m1.low[i] == '1' else '1' 564 | m1 = self.m1.low 565 | self.m1.low = ''.join(res) 566 | self.exec_incb() 567 | self.m3.low = self.m1.low 568 | self.m1.low = m1 569 | 570 | def exec_negw(self): 571 | res = ['0'] * 16 572 | for i in range(16): 573 | res[i] = '0' if self.m1.read()[i] == '1' else '1' 574 | m1 = self.m1.read() 575 | self.m1.assign(''.join(res)) 576 | self.exec_incw() 577 | self.m3.assign(self.m1.read()) 578 | self.m1.assign(m1) 579 | 580 | def exec_notb(self): 581 | res = ['0'] * 8 582 | for i in range(8): 583 | res[i] = '0' if self.m1.low[i] == '1' else '1' 584 | self.m3.low = ''.join(res) 585 | 586 | def exec_notw(self): 587 | res = ['0'] * 16 588 | for i in range(16): 589 | res[i] = '0' if self.m1.read()[i] == '1' else '1' 590 | self.m3.assign(''.join(res)) 591 | 592 | def exec_orb(self): 593 | self._bitwiseb(or_bits) 594 | 595 | def exec_orw(self): 596 | self._bitwisew(or_bits) 597 | 598 | def exec_sarb(self): 599 | carry = self.m1.low[0] == '1' 600 | res = ['0'] * 8 601 | for i in range(8): 602 | if carry: 603 | res[i] = '1' 604 | carry = self.m1.low[i] == '1' 605 | self.flags.carry = carry 606 | self.flags.overflow = res[0] != self.m1.low[0] 607 | self.m3.low = ''.join(res) 608 | 609 | def exec_sarw(self): 610 | carry = self.m1.low[0] == '1' 611 | res = ['0'] * 16 612 | for i in range(16): 613 | if carry: 614 | res[i] = '1' 615 | carry = self.m1.read()[i] == '1' 616 | self.flags.carry = carry 617 | self.flags.overflow = res[0] != self.m1.high[0] 618 | self.m3.assign(''.join(res)) 619 | 620 | def exec_shlb(self): # Used 621 | carry = False 622 | res = ['0'] * 8 623 | for i in range(7, -1, -1): 624 | if carry: 625 | res[i] = '1' 626 | carry = self.m1.low[i] == '1' 627 | self.flags.carry = carry 628 | self.flags.overflow = res[0] != self.m1.low[0] 629 | self.m3.low = ''.join(res) 630 | 631 | def exec_shlw(self): # Used 632 | carry = False 633 | res = ['0'] * 16 634 | for i in range(15, -1, -1): 635 | if carry: 636 | res[i] = '1' 637 | carry = self.m1.read()[i] == '1' 638 | self.flags.carry = carry 639 | self.flags.overflow = res[0] != self.m1.high[0] 640 | self.m3.assign(''.join(res)) 641 | 642 | def exec_shrb(self): 643 | carry = False 644 | res = ['0'] * 8 645 | for i in range(8): 646 | if carry: 647 | res[i] = '1' 648 | carry = self.m1.low[i] == '1' 649 | self.flags.carry = carry 650 | self.flags.overflow = res[0] != self.m1.low[0] 651 | self.m3.low = ''.join(res) 652 | 653 | def exec_shrw(self): 654 | carry = False 655 | res = ['0'] * 16 656 | for i in range(16): 657 | if carry: 658 | res[i] = '1' 659 | carry = self.m1.read()[i] == '1' 660 | self.flags.carry = carry 661 | self.flags.overflow = res[0] != self.m1.high[0] 662 | self.m3.assign(''.join(res)) 663 | 664 | def exec_stc(self): 665 | self.flags.carry = True 666 | 667 | def _subb(self, with_borrow=False): 668 | res = ['0'] * 8 669 | borrow = False 670 | if with_borrow: 671 | borrow = self.flags.carry 672 | for i in range(7, -1, -1): 673 | if i == 7: 674 | self.flags.overflow = borrow 675 | total = 1 if self.m1.low[i] == '1' else 0 676 | total -= 1 if self.m2.low[i] == '1' else 0 677 | if borrow: 678 | total -= 1 679 | if total == 0: 680 | borrow = False 681 | elif total == 1: 682 | borrow = False 683 | res[i] = '1' 684 | elif total == -1: 685 | borrow = True 686 | res[i] = '1' 687 | elif total == -2: 688 | borrow = True 689 | else: 690 | assert False 691 | self.flags.carry = borrow 692 | self.flags.sign = res[0] == '1' 693 | self.m3.low = ''.join(res) 694 | self.flags.zero = self.m3.low == '0' * 8 695 | 696 | def _subw(self, with_borrow=False): 697 | res = ['0'] * 16 698 | borrow = False 699 | if with_borrow: 700 | borrow = self.flags.carry 701 | for i in range(15, -1, -1): 702 | if i == 15: 703 | self.flags.overflow = borrow 704 | total = 1 if self.m1.read()[i] == '1' else 0 705 | total -= 1 if self.m2.read()[i] == '1' else 0 706 | if borrow: 707 | total -= 1 708 | if total == 0: 709 | borrow = False 710 | elif total == 1: 711 | borrow = False 712 | res[i] = '1' 713 | elif total == -1: 714 | borrow = True 715 | res[i] = '1' 716 | elif total == -2: 717 | borrow = True 718 | else: 719 | assert False 720 | self.flags.carry = borrow 721 | self.flags.sign = res[0] == '1' 722 | self.m3.assign(''.join(res)) 723 | self.flags.zero = self.m3.read() == '0' * 16 724 | 725 | def exec_sbbb(self): 726 | self._subb(with_borrow=True) 727 | 728 | def exec_sbbw(self): 729 | self._subw(with_borrow=True) 730 | 731 | def exec_subb(self): 732 | self._subb(with_borrow=False) 733 | 734 | def exec_subw(self): 735 | self._subw(with_borrow=False) 736 | 737 | def exec_testb(self): 738 | m3 = self.m3.low 739 | self.exec_andb() 740 | self.m3.low = m3 741 | 742 | def exec_testw(self): 743 | m3 = self.m3.read() 744 | self.exec_andw() 745 | self.m3.assign(m3) 746 | 747 | def exec_xorb(self): 748 | self._bitwiseb(xor_bits) 749 | 750 | def exec_xorw(self): 751 | self._bitwisew(xor_bits) 752 | 753 | def exec_puts(self): 754 | m3 = self.m3.low 755 | self.m1.assign(self._read_reg('A')) 756 | self.exec_smp() 757 | self.exec_rmem() 758 | while self.m3.low != '0' * 8: 759 | print(chr(byte_to_uint(self.m3.low)), end='') 760 | self.exec_imp() 761 | self.exec_rmem() 762 | self.m3.low = m3 763 | 764 | def exec_putint(self): 765 | print(str(word_to_int(self._read_reg('A'))), end='') 766 | 767 | def exec_putc(self): 768 | print(chr(byte_to_uint(self.regs['AL'].value)), end='') 769 | 770 | def exec_gets(self): 771 | m2 = self.m2.low 772 | s = input() 773 | self.m1.assign(self._read_reg('A')) 774 | self.exec_smp() 775 | for c in s: 776 | self.m2.low = uint_to_byte(ord(c)) 777 | self.exec_wmem() 778 | self.exec_imp() 779 | self.m2.low = '0' * 8 780 | self.exec_wmem() 781 | self.m2.low = m2 782 | 783 | def exec_getint(self): 784 | self._assign_reg('A', int_to_word(int(input()))) 785 | 786 | def exec_rand(self): 787 | r = random.randint(0, 2 ** 15 - 1) 788 | self._assign_reg('A', int_to_word(r)) 789 | 790 | def exec_hlt(self): 791 | exit(0) 792 | 793 | 794 | def run(pptasm_dict): 795 | vm = MachineState(pptasm_dict) 796 | while True: 797 | vm.step() 798 | 799 | def test_verdict(cmd1, cmd2): 800 | print('Testing ' + cmd1 + ' and ' + cmd2) 801 | class Dummy: 802 | def __init__(self, flags): 803 | self.flags = flags 804 | d = Dummy(Flags()) 805 | from copy import deepcopy 806 | for i in range(100): 807 | d.flags.carry = random.choice([True, False]) 808 | d.flags.overflow = random.choice([True, False]) 809 | d.flags.sign = random.choice([True, False]) 810 | d.flags.zero = random.choice([True, False]) 811 | d.flags.verdict = False 812 | d2 = deepcopy(d) 813 | MachineState.__dict__[cmd1](d) 814 | MachineState.__dict__[cmd2](d2) 815 | if d.flags.verdict == d2.flags.verdict: 816 | print('*** No match ***') 817 | return 818 | print('(match)') 819 | 820 | def test(): 821 | print('Hello') 822 | names = [k for k in MachineState.__dict__.keys() if k.startswith('exec_v')] 823 | for k in names: 824 | cmd = k[6:] 825 | if cmd[0] != 'n': 826 | test_verdict(k, 'exec_vn' + cmd) 827 | 828 | print(names) 829 | 830 | def parse_file(file_path): 831 | with open(file_path, mode='rt') as file: 832 | lines = file.readlines() 833 | lines = [line.strip() for line in lines] 834 | lines = [line for line in lines if line] 835 | text = {} 836 | data = {} 837 | const = {} 838 | i = 0 839 | assert lines[i] == 'text:' 840 | i += 1 841 | while lines[i] != 'data:': 842 | parts = split_on_spaces(lines[i]) 843 | text[parts[0]] = Instruction(parts[1], parts[2:]) 844 | i += 1 845 | i += 1 846 | while lines[i] != 'const:': 847 | parts = split_on_spaces(lines[i]) 848 | data[parts[0]] = parts[1] 849 | i += 1 850 | i += 1 851 | while i < len(lines): 852 | parts = split_on_spaces(lines[i]) 853 | const[parts[0]] = parts[1] 854 | i += 1 855 | return MachineState(text, data, const) 856 | 857 | if __name__ == '__main__': 858 | parser = argparse.ArgumentParser(description='Run .pptasm files') 859 | parser.add_argument('file', help='.pptasm file to run', type=str) 860 | args = parser.parse_args() 861 | vm = parse_file(args.file) 862 | while True: 863 | try: 864 | vm.step() 865 | except SystemExit: 866 | exit(0) 867 | except: 868 | raise Exception('Error while running line %s' % vm.ip) 869 | -------------------------------------------------------------------------------- /pptasm.py: -------------------------------------------------------------------------------- 1 | from pptutils import * 2 | import json 3 | import argparse 4 | 5 | def find_line(lines, target): 6 | if target not in lines: 7 | raise Exception('Could not find line "%s" in file' % target) 8 | return lines.index(target) 9 | 10 | def parse_line(line): 11 | line = line.strip() 12 | if ' ' not in line: 13 | return line, [] 14 | i = line.find(' ') 15 | inst = line[:i] 16 | arg_str = line[i:].strip() 17 | args = [a.strip() for a in arg_str.split(',')] 18 | args2 = [] 19 | for a in args: 20 | if len(args2) > 0 and '(' in args2[-1] and ')' not in args2[-1]: 21 | args2[-1] = args2[-1] + ',' + a 22 | else: 23 | args2.append(a) 24 | return inst, args2 25 | 26 | class X86LabeledRegion: 27 | def __init__(self, label, lines): 28 | self.label = label 29 | self.lines = lines 30 | 31 | def __repr__(self): 32 | return 'X86LabeledRegion(%s, <%d lines>)' % (repr(self.label), len(self.lines)) 33 | 34 | def parse_section_labels(section_name, lines): 35 | labeled_regions = [X86LabeledRegion(section_name, [])] 36 | for l in lines: 37 | if l.startswith(' '): 38 | labeled_regions[-1].lines.append(l) 39 | else: 40 | assert l.endswith(':') 41 | labeled_regions.append(X86LabeledRegion(l[:-1], [])) 42 | return labeled_regions 43 | 44 | def assemble_gas(file_path, output_path): 45 | with open(file_path, mode='rt') as file: 46 | lines = file.readlines() 47 | lines = [line.replace('\t', ' ').rstrip() for line in lines] 48 | lines = [line for line in lines if line] 49 | section_map = {} 50 | section = [] 51 | section_map['INITIAL'] = section 52 | for l in lines: 53 | if l.startswith('.new_section'): 54 | section = [] 55 | inst, args = parse_line(l) 56 | section_map[args[0]] = section 57 | else: 58 | section.append(l) 59 | if '_TEXT' not in section_map: 60 | raise Exception('No _TEXT section in assembly code') 61 | text_section = section_map['_TEXT'] 62 | const_section = section_map.get('CONST', []) 63 | data_section = section_map.get('_DATA', []) 64 | labeled_text = parse_section_labels('_TEXT', text_section) 65 | labeled_const = parse_section_labels('CONST', const_section) 66 | labeled_data = parse_section_labels('_DATA', data_section) 67 | labels_to_offsets = get_label_offsets(labeled_data, 2**15) 68 | labels_to_offsets.update(get_label_offsets(labeled_const, 0)) 69 | 70 | code = [ 71 | PptInstruction('CONSTH', '11111111'), 72 | PptInstruction('CONSTL', '11111100'), 73 | PptInstruction('STOREH', 'SPH'), 74 | PptInstruction('STOREL', 'SPL'), 75 | PptInstruction('LOAD1H', 'M3H'), 76 | PptInstruction('LOAD1L', 'M3L'), 77 | PptInstruction('EXEC', 'SMP'), 78 | PptInstruction('CONSTL', Immediate(0, 'w', 'X$0')), 79 | PptInstruction('LOAD2L', 'M3L'), 80 | PptInstruction('EXEC', 'WMEM'), 81 | PptInstruction('EXEC', 'IMP'), 82 | PptInstruction('CONSTH', Immediate(0, 'w', 'X$0')), 83 | PptInstruction('LOAD2L', 'M3H'), 84 | PptInstruction('EXEC', 'WMEM'), 85 | PptInstruction('CONSTH', Immediate(0, 'w', 'main_')), 86 | PptInstruction('CONSTL', Immediate(0, 'w', 'main_')), 87 | PptInstruction('LOAD1H', 'M3H'), 88 | PptInstruction('LOAD1L', 'M3L'), 89 | PptInstruction('EXEC', 'JMP'), 90 | ] 91 | labels_to_offsets['X$0'] = len(code) 92 | code += [PptInstruction('EXEC', 'HLT')] 93 | for region in labeled_text: 94 | labels_to_offsets[region.label] = len(code) 95 | for line in region.lines: 96 | try: 97 | new_code = code_for_line(line, len(code)) 98 | except SegmentRegisterException as e: 99 | print('Warning: skipping line containing segment register "%s"' % e.message) 100 | continue 101 | new_code[0].comment = condense_spaces(line) 102 | code += new_code 103 | 104 | for inst in code: 105 | if inst.cmd == 'CONSTL': 106 | assert inst.arg is not None 107 | if isinstance(inst.arg, Immediate): 108 | h = inst.arg.to_binary(labels_to_offsets) 109 | if inst.cmd == 'CONSTH': 110 | h = h[:8] 111 | elif inst.cmd == 'CONSTL': 112 | h = h[-8:] 113 | assert len(h) == 8 114 | inst.arg = h 115 | data = read_data_section(labeled_data, labels_to_offsets) 116 | const = read_data_section(labeled_const, labels_to_offsets) 117 | 118 | lines = [] 119 | lines.append('text:') 120 | for i in range(len(code)): 121 | lines.append(' ' + int_to_word(i) + ' ' + str(code[i])) 122 | lines.append('') 123 | lines.append('data:') 124 | for i in range(len(data)): 125 | lines.append(' ' + int_to_word(i+2**15) + ' ' + data[i]) 126 | lines.append('') 127 | lines.append('const:') 128 | for i in range(len(const)): 129 | lines.append(' ' + int_to_word(i) + ' ' + const[i]) 130 | 131 | with open(output_path, mode='wt') as file: 132 | file.write('\n'.join(lines)) 133 | 134 | 135 | def get_label_offsets(labeled_const_or_data, initial_byte_offset): 136 | byte_offset = initial_byte_offset 137 | labels_to_offsets = {} 138 | for region in labeled_const_or_data: 139 | labels_to_offsets[region.label] = byte_offset 140 | for l in region.lines: 141 | inst, args = parse_line(l) 142 | if inst == '.byte': 143 | byte_offset += len(args) 144 | elif inst == '.word': 145 | byte_offset += 2 * len(args) 146 | elif inst == '.ascii': 147 | byte_offset += sum(data_string_len(a) for a in args) 148 | elif inst in ['.asciiz', '.string']: 149 | byte_offset += sum(1+data_string_len(a) for a in args) 150 | else: 151 | raise Exception('Unidentified line "%s"' % l) 152 | return labels_to_offsets 153 | 154 | def read_byte_data(arg, offsets): 155 | if arg.startswith('0x'): 156 | return [int_to_byte(hex_to_int(arg))] 157 | else: 158 | return [Immediate.parse(arg, 'b').to_binary(offsets)] 159 | 160 | def read_word_data(arg, offsets): 161 | if arg.startswith('0x'): 162 | w = int_to_word(hex_to_int(arg)) 163 | else: 164 | w = Immediate.parse(arg, 'w').to_binary(offsets) 165 | return [w[8:], w[:8]] 166 | 167 | def read_asciiz_data(arg): 168 | assert arg[0] == '"' 169 | assert arg[-1] == '"' 170 | s = json.loads(arg) 171 | return [int_to_byte(ord(a)) for a in s] + ['0' * 8] 172 | 173 | def read_ascii_data(arg): 174 | assert arg[0] == '"' 175 | assert arg[-1] == '"' 176 | s = json.loads(arg) 177 | return [int_to_byte(ord(a)) for a in s] 178 | 179 | 180 | def read_data_section(labeled_const_or_data, labels_to_offsets): 181 | data = [] 182 | for region in labeled_const_or_data: 183 | for l in region.lines: 184 | inst, args = parse_line(l) 185 | if inst == '.byte': 186 | for a in args: 187 | data += read_byte_data(a.strip(), labels_to_offsets) 188 | elif inst == '.word': 189 | for a in args: 190 | data += read_word_data(a.strip(), labels_to_offsets) 191 | elif inst == '.ascii': 192 | for a in args: 193 | data += read_ascii_data(a.strip()) 194 | elif inst in ['.asciiz', '.string']: 195 | for a in args: 196 | data += read_asciiz_data(a.strip()) 197 | else: 198 | raise Exception('Unidentified line "%s"' % l) 199 | return data 200 | 201 | def data_string_len(string): 202 | assert string[0] == '"' 203 | assert string[-1] == '"' 204 | return len(json.loads(string)) 205 | 206 | class SegmentRegisterException(Exception): 207 | def __init__(self, message): 208 | self.message = message 209 | 210 | def code_for_line(line, offset): 211 | inst, args = parse_line(line) 212 | cmd = inst.upper() 213 | size = 'b' if inst[-1] == 'b' else 'w' 214 | def parse_args(is_branch_operand=False): 215 | parsed_args = [] 216 | for a in args: 217 | try: 218 | parsed_args.append(X86InstructionOperand(a, size, is_branch_operand)) 219 | except: 220 | if a in ['%ds', '%es', '%ss', '%cs']: 221 | raise SegmentRegisterException(line) 222 | else: 223 | raise Exception('Failure parsing operand "%s" for line "%s"' % (a, line)) 224 | return parsed_args 225 | if cmd in unary_commands_w: 226 | return code_for_unary_cmd_w(parse_args(), cmd) 227 | if cmd in unary_commands_b: 228 | return code_for_unary_cmd_b(parse_args(), cmd) 229 | if cmd in binary_commands_w: 230 | return code_for_binary_cmd_w(parse_args(), cmd) 231 | if cmd in binary_commands_b: 232 | return code_for_binary_cmd_b(parse_args(), cmd) 233 | if cmd in nullary_commands: 234 | return [PptInstruction('EXEC', cmd)] 235 | if cmd.startswith('J') and cmd[1:] in cond_jmp_suffixes: 236 | return code_for_cond_jmp(parse_args(True), cmd) 237 | if cmd.startswith('J') and cmd[1:] in cond_jump_suffix_map: 238 | suffix = cond_jump_suffix_map[cmd[1:]] 239 | return code_for_cond_jmp(parse_args(True), 'J' + suffix) 240 | if cmd.startswith('JN') and cmd[2:] in cond_jmp_suffixes: 241 | return code_for_cond_jmp(parse_args(True), cmd) 242 | if cmd.startswith('JN') and cmd[2:] in cond_jump_suffix_map: 243 | suffix = cond_jump_suffix_map[cmd[2:]] 244 | if suffix.startswith('N'): 245 | return code_for_cond_jmp(parse_args(True), 'J' + suffix[1:]) 246 | else: 247 | return code_for_cond_jmp(parse_args(True), 'JN' + suffix) 248 | if cmd == 'CALL': 249 | return code_for_cmd_call(parse_args(True), offset) 250 | key = 'code_for_cmd_' + inst 251 | if key not in globals(): 252 | raise Exception('Unrecognized command "%s"' % inst) 253 | return globals()[key](parse_args(cmd in cmds_with_branch_ops)) 254 | 255 | cmds_with_branch_ops = ['JMP', 'CALL'] 256 | 257 | class Immediate: 258 | def __init__(self, offset, size, label=None): 259 | self.offset = offset 260 | self.label = label 261 | self.size = size 262 | 263 | def __repr__(self): 264 | if self.label is None: 265 | return str(self.offset) 266 | elif self.offset < 0: 267 | return self.label + str(self.offset) 268 | else: 269 | return self.label + '+' + str(self.offset) 270 | 271 | def __str__(self): 272 | return self.__repr__() 273 | 274 | def is_zero(self): 275 | return self.offset == 0 and self.label is None 276 | 277 | def to_binary(self, label_dict): 278 | i = self.offset 279 | if self.label is not None: 280 | if self.label not in label_dict: 281 | raise Exception('Unidentified label "%s"' % self.label) 282 | i += label_dict[self.label] 283 | if self.size == 'w': 284 | return int_to_word(i) 285 | else: 286 | return int_to_byte(i) 287 | 288 | @staticmethod 289 | def parse(asm_str, size): 290 | asm_str = asm_str.strip() 291 | def parse_num(string): 292 | if string.startswith('0x'): 293 | return hex_to_int(string) 294 | else: 295 | return int(string) 296 | if '-' in asm_str: 297 | label, offset = asm_str.split('-') 298 | if len(label) > 0: 299 | return Immediate(-parse_num(offset), size, label) 300 | else: 301 | return Immediate(-parse_num(offset), size) 302 | elif '+' in asm_str: 303 | label, offset = asm_str.split('+') 304 | assert len(label) > 0 305 | return Immediate(parse_num(offset), size, label) 306 | elif asm_str[0] in '0123456789': 307 | return Immediate(parse_num(asm_str), size) 308 | else: 309 | return Immediate(0, size, asm_str) 310 | 311 | class X86InstructionOperand: 312 | def __init__(self, arg, size, is_branch_operand=False): 313 | self.immediate = Immediate(0, size) 314 | self.reg1 = None 315 | self.reg2 = None 316 | self.scale = 1 317 | if arg.startswith('*'): 318 | assert is_branch_operand 319 | arg = arg[1:] 320 | is_branch_operand = False 321 | if arg.startswith('$'): 322 | self.type = 'IMM' 323 | self.immediate = Immediate.parse(arg[1:], size) 324 | elif arg.startswith('%'): 325 | self.type = 'REG' 326 | self.reg1 = get_reg_prefix(arg[1:]) 327 | elif '(' in arg: 328 | self.type = 'MEM' 329 | assert '(' in arg 330 | i = arg.find('(') 331 | j = arg.find(')') 332 | contents = arg[i+1:j] 333 | arg = arg[:i] 334 | parts = contents.split(',') 335 | if parts[0] != '': 336 | self.reg1 = get_reg_prefix(parts[0][1:]) 337 | if len(parts) >= 2: 338 | assert parts[1].startswith('%') 339 | self.reg2 = get_reg_prefix(parts[1][1:]) 340 | if len(parts) >= 3: 341 | assert parts[2] in ['1', '2', '4', '8'] 342 | self.scale = int(parts[2]) 343 | if arg != '': 344 | self.immediate = Immediate.parse(arg, size='w') 345 | else: 346 | if is_branch_operand: 347 | self.type = 'IMM' 348 | self.immediate = Immediate.parse(arg, size) 349 | else: 350 | self.type = 'MEM' 351 | self.immediate = Immediate.parse(arg, size='w') 352 | 353 | 354 | 355 | def __repr__(self): 356 | if self.type == 'IMM': 357 | return repr(self.immediate) 358 | elif self.type == 'REG': 359 | return self.reg1 360 | else: 361 | return repr(self.immediate) + '(' + repr(self.reg1) + ',' + repr(self.reg2) + ',' + repr(self.scale) + ')' 362 | 363 | def requires_calculation(self, for_write=False): 364 | if self.type != 'MEM': 365 | return False 366 | if self.reg2 is not None: 367 | return True 368 | if not self.immediate.is_zero() and self.reg1 is not None: 369 | return True 370 | if not self.immediate.is_zero() and for_write: 371 | return True 372 | return False 373 | 374 | class PptInstruction: 375 | def __init__(self, cmd, arg=None): 376 | self.cmd = cmd 377 | self.arg = arg 378 | self.comment = None 379 | def __str__(self): 380 | res = pad_to_length(self.cmd, 8) 381 | if self.arg is not None: 382 | res += pad_to_length(str(self.arg), 10) 383 | if self.comment is not None: 384 | res += '# ' + self.comment 385 | return res 386 | 387 | def get_reg_prefix(x86reg): 388 | x86reg = x86reg.lower() 389 | if len(x86reg) == 2 and x86reg[0] in ['a', 'b', 'c', 'd'] and x86reg[1] in ['l', 'h']: 390 | return x86reg.upper() 391 | return { 392 | 'ax': 'A', 393 | 'bx': 'B', 394 | 'cx': 'C', 395 | 'dx': 'D', 396 | 'di': 'DI', 397 | 'si': 'SI', 398 | 'bp': 'BP', 399 | 'sp': 'SP', 400 | }[x86reg] 401 | 402 | def get_low_byte(x86reg): 403 | pass 404 | 405 | def code_for_calc_address(operand, dst_reg='M4'): 406 | assert operand.type == 'MEM' 407 | code = [] 408 | if operand.reg2 is not None: 409 | code += [ 410 | PptInstruction('LOAD1H', operand.reg2 + 'H'), 411 | PptInstruction('LOAD1L', operand.reg2 + 'L'), 412 | ] 413 | if operand.scale > 1: 414 | if operand.scale == 2: 415 | cmd = 'SHIFTADDR1' 416 | elif operand.scale == 4: 417 | cmd = 'SHIFTADDR2' 418 | elif operand.scale == 8: 419 | cmd = 'SHIFTADDR3' 420 | else: 421 | assert False 422 | code += [ 423 | PptInstruction('EXEC', cmd), 424 | ] 425 | if operand.reg1 is None and operand.immediate.is_zero(): 426 | code += [ 427 | PptInstruction('STOREH', dst_reg + 'H'), 428 | PptInstruction('STOREL', dst_reg + 'L'), 429 | ] 430 | else: 431 | code += [ 432 | PptInstruction('LOAD1H', 'M3H'), 433 | PptInstruction('LOAD1L', 'M3L'), 434 | ] 435 | if operand.reg1 is not None: 436 | if operand.reg2 is None: 437 | code += [ 438 | PptInstruction('LOAD1H', operand.reg1 + 'H'), 439 | PptInstruction('LOAD1L', operand.reg1 + 'L'), 440 | ] 441 | if operand.immediate.is_zero(): 442 | code += [ 443 | PptInstruction('COPYH'), 444 | PptInstruction('COPYL'), 445 | PptInstruction('STOREH', dst_reg + 'H'), 446 | PptInstruction('STOREL', dst_reg + 'L'), 447 | ] 448 | else: 449 | code += [ 450 | PptInstruction('LOAD2H', operand.reg1 + 'H'), 451 | PptInstruction('LOAD2L', operand.reg1 + 'L'), 452 | PptInstruction('EXEC', 'ADDADDR'), 453 | ] 454 | if not operand.immediate.is_zero(): 455 | code += [ 456 | PptInstruction('LOAD1H', 'M3H'), 457 | PptInstruction('LOAD1L', 'M3L'), 458 | ] 459 | else: 460 | code += [ 461 | PptInstruction('STOREH', dst_reg + 'H'), 462 | PptInstruction('STOREL', dst_reg + 'L'), 463 | ] 464 | if not operand.immediate.is_zero(): 465 | if operand.reg1 is not None or operand.reg2 is not None: 466 | code += [ 467 | PptInstruction('CONSTH', operand.immediate), 468 | PptInstruction('CONSTL', operand.immediate), 469 | PptInstruction('LOAD2H', 'M3H'), 470 | PptInstruction('LOAD2L', 'M3L'), 471 | PptInstruction('EXEC', 'ADDADDR'), 472 | PptInstruction('STOREH', dst_reg + 'H'), 473 | PptInstruction('STOREL', dst_reg + 'L'), 474 | ] 475 | else: 476 | code += [ 477 | PptInstruction('CONSTH', operand.immediate), 478 | PptInstruction('CONSTL', operand.immediate), 479 | PptInstruction('STOREH', dst_reg + 'H'), 480 | PptInstruction('STOREL', dst_reg + 'L'), 481 | ] 482 | return code 483 | 484 | def code_for_read_w(op, reg='1'): 485 | code = [] 486 | if op.type == 'MEM': 487 | if op.requires_calculation(): 488 | code += [ 489 | PptInstruction('LOAD1H', 'M4H'), 490 | PptInstruction('LOAD1L', 'M4L'), 491 | ] 492 | elif op.reg1 is not None: 493 | code += [ 494 | PptInstruction('LOAD1H', op.reg1 + 'H'), 495 | PptInstruction('LOAD1L', op.reg1 + 'L'), 496 | ] 497 | else: 498 | assert not op.immediate.is_zero() 499 | code += [ 500 | PptInstruction('CONSTH', op.immediate), 501 | PptInstruction('CONSTL', op.immediate), 502 | PptInstruction('LOAD1H', 'M3H'), 503 | PptInstruction('LOAD1L', 'M3L'), 504 | ] 505 | code += [ 506 | PptInstruction('EXEC', 'SMP'), 507 | PptInstruction('EXEC', 'RMEM'), 508 | PptInstruction('STOREL', 'M5L'), 509 | PptInstruction('EXEC', 'IMP'), 510 | PptInstruction('EXEC', 'RMEM'), 511 | ] 512 | if reg == '3': 513 | code += [ 514 | PptInstruction('STOREL', 'M5H'), 515 | PptInstruction('LOAD1H', 'M5H'), 516 | PptInstruction('LOAD1L', 'M5L'), 517 | PptInstruction('COPYH'), 518 | PptInstruction('COPYL'), 519 | ] 520 | else: 521 | code += [ 522 | PptInstruction('LOAD' + reg + 'H', 'M3L'), 523 | PptInstruction('LOAD' + reg + 'L', 'M5L'), 524 | ] 525 | return code 526 | elif op.type == 'REG': 527 | if reg == '3': 528 | return [ 529 | PptInstruction('LOAD1H', op.reg1 + 'H'), 530 | PptInstruction('LOAD1L', op.reg1 + 'L'), 531 | PptInstruction('COPYH'), 532 | PptInstruction('COPYL'), 533 | ] 534 | else: 535 | return [ 536 | PptInstruction('LOAD' + reg + 'H', op.reg1 + 'H'), 537 | PptInstruction('LOAD' + reg + 'L', op.reg1 + 'L'), 538 | ] 539 | elif op.type == 'IMM': 540 | if reg == '3': 541 | return [ 542 | PptInstruction('CONSTH', op.immediate), 543 | PptInstruction('CONSTL', op.immediate), 544 | ] 545 | else: 546 | return [ 547 | PptInstruction('CONSTH', op.immediate), 548 | PptInstruction('CONSTL', op.immediate), 549 | PptInstruction('LOAD' + reg + 'H', 'M3H'), 550 | PptInstruction('LOAD' + reg + 'L', 'M3L'), 551 | ] 552 | assert False 553 | 554 | 555 | def code_for_read_b(op, reg='1'): 556 | code = [] 557 | if op.type == 'MEM': 558 | if op.requires_calculation(): 559 | code += [ 560 | PptInstruction('LOAD1H', 'M4H'), 561 | PptInstruction('LOAD1L', 'M4L'), 562 | ] 563 | elif op.reg1 is not None: 564 | code += [ 565 | PptInstruction('LOAD1H', op.reg1 + 'H'), 566 | PptInstruction('LOAD1L', op.reg1 + 'L'), 567 | ] 568 | else: 569 | assert not op.immediate.is_zero() 570 | code += [ 571 | PptInstruction('CONSTH', op.immediate), 572 | PptInstruction('CONSTL', op.immediate), 573 | PptInstruction('LOAD1H', 'M3H'), 574 | PptInstruction('LOAD1L', 'M3L'), 575 | ] 576 | code += [ 577 | PptInstruction('EXEC', 'SMP'), 578 | PptInstruction('EXEC', 'RMEM'), 579 | ] 580 | if reg != '3': 581 | code += [ 582 | PptInstruction('LOAD' + reg + 'L', 'M3L'), 583 | ] 584 | return code 585 | elif op.type == 'REG': 586 | if reg == '3': 587 | return [ 588 | PptInstruction('LOAD1L', op.reg1), 589 | PptInstruction('COPYL'), 590 | ] 591 | else: 592 | return [ 593 | PptInstruction('LOAD' + reg + 'L', op.reg1), 594 | ] 595 | elif op.type == 'IMM': 596 | if reg == '3': 597 | return [PptInstruction('CONSTL', op.immediate)] 598 | else: 599 | return [ 600 | PptInstruction('CONSTL', op.immediate), 601 | PptInstruction('LOAD' + reg + 'L', 'M3L'), 602 | ] 603 | assert False 604 | 605 | def code_for_write_w(op): 606 | if op.type == 'MEM': 607 | code = [] 608 | if op.requires_calculation(for_write=True): 609 | code += [ 610 | PptInstruction('LOAD1H', 'M4H'), 611 | PptInstruction('LOAD1L', 'M4L'), 612 | ] 613 | else: 614 | code += [ 615 | PptInstruction('LOAD1H', op.reg1 + 'H'), 616 | PptInstruction('LOAD1L', op.reg1 + 'L'), 617 | ] 618 | code += [ 619 | PptInstruction('LOAD2L', 'M3L'), 620 | PptInstruction('EXEC', 'SMP'), 621 | PptInstruction('EXEC', 'WMEM'), 622 | PptInstruction('EXEC', 'IMP'), 623 | PptInstruction('LOAD2L', 'M3H'), 624 | PptInstruction('EXEC', 'WMEM'), 625 | ] 626 | return code 627 | elif op.type == 'REG': 628 | return [ 629 | PptInstruction('STOREH', op.reg1 + 'H'), 630 | PptInstruction('STOREL', op.reg1 + 'L'), 631 | ] 632 | assert False 633 | 634 | def code_for_write_b(op): 635 | if op.type == 'MEM': 636 | code = [] 637 | if op.requires_calculation(for_write=True): 638 | code += [ 639 | PptInstruction('LOAD1H', 'M4H'), 640 | PptInstruction('LOAD1L', 'M4L'), 641 | ] 642 | else: 643 | code += [ 644 | PptInstruction('LOAD1H', op.reg1 + 'H'), 645 | PptInstruction('LOAD1L', op.reg1 + 'L'), 646 | ] 647 | code += [ 648 | PptInstruction('LOAD2L', 'M3L'), 649 | PptInstruction('EXEC', 'SMP'), 650 | PptInstruction('EXEC', 'WMEM'), 651 | ] 652 | return code 653 | elif op.type == 'REG': 654 | return [ 655 | PptInstruction('STOREL', op.reg1), 656 | ] 657 | assert False 658 | 659 | def code_to_calc_address_if_needed(ops, write_to_dst=True): 660 | code = None 661 | for i in range(len(ops)): 662 | op = ops[i] 663 | last = i == len(ops) - 1 664 | if op.requires_calculation(for_write=(write_to_dst and last)): 665 | assert code is None 666 | code = code_for_calc_address(op) 667 | return code or [] 668 | 669 | def code_for_cmd_movw(inst_operands): 670 | src, dst = inst_operands 671 | code = code_to_calc_address_if_needed(inst_operands) 672 | code += code_for_read_w(src, reg='3') 673 | code += code_for_write_w(dst) 674 | return code 675 | 676 | def code_for_cmd_movb(inst_operands): 677 | src, dst = inst_operands 678 | code = code_to_calc_address_if_needed(inst_operands) 679 | code += code_for_read_b(src, reg='3') 680 | code += code_for_write_b(dst) 681 | return code 682 | 683 | def code_for_cmd_ctwd(_): 684 | return [PptInstruction('EXEC', 'CWD')] 685 | 686 | def code_for_binary_cmd_b(inst_operands, cmd, write_to_dst=True): 687 | src, dst = inst_operands 688 | code = code_to_calc_address_if_needed(inst_operands) 689 | if src.type == 'MEM': 690 | code += code_for_read_b(src, reg='2') 691 | if dst.type == 'MEM': 692 | code += code_for_read_b(dst, reg='1') 693 | if src.type != 'MEM': 694 | code += code_for_read_b(src, reg='2') 695 | if dst.type != 'MEM': 696 | code += code_for_read_b(dst, reg='1') 697 | code += [PptInstruction('EXEC', cmd)] 698 | if write_to_dst: 699 | code += code_for_write_b(dst) 700 | return code 701 | 702 | def code_for_binary_cmd_w(inst_operands, cmd, write_to_dst=True): 703 | src, dst = inst_operands 704 | code = code_to_calc_address_if_needed(inst_operands, write_to_dst) 705 | if src.type == 'MEM': 706 | code += code_for_read_w(src, reg='2') 707 | if dst.type == 'MEM': 708 | code += code_for_read_w(dst, reg='1') 709 | if src.type != 'MEM': 710 | code += code_for_read_w(src, reg='2') 711 | if dst.type != 'MEM': 712 | code += code_for_read_w(dst, reg='1') 713 | code += [PptInstruction('EXEC', cmd)] 714 | if write_to_dst: 715 | code += code_for_write_w(dst) 716 | return code 717 | 718 | def code_for_unary_cmd_b(inst_operands, cmd): 719 | dst = inst_operands[0] 720 | code = code_to_calc_address_if_needed(inst_operands) 721 | code += code_for_read_b(dst, reg='1') 722 | code += [PptInstruction('EXEC', cmd)] 723 | code += code_for_write_b(dst) 724 | return code 725 | 726 | def code_for_unary_cmd_w(inst_operands, cmd): 727 | dst = inst_operands[0] 728 | code = code_to_calc_address_if_needed(inst_operands) 729 | code += code_for_read_w(dst, reg='1') 730 | code += [PptInstruction('EXEC', cmd)] 731 | code += code_for_write_w(dst) 732 | return code 733 | 734 | binary_commands_w = [ 735 | 'ADDW', 'ADCW', 'ANDW', 'ORW', 'XORW', 'SUBW', 'SBBW', 736 | 'SARW', 'SHLW', 'SHRW' 737 | ] 738 | binary_commands_b = [ 739 | 'ADDB', 'ADCB', 'ANDB', 'ORB', 'XORB', 'SUBB', 'SBBB', 740 | 'SARB', 'SHLB', 'SHRB' 741 | ] 742 | unary_commands_w = [ 743 | 'INCW', 'DECW', 'NOTW', 'NEGW', 744 | ] 745 | unary_commands_b = [ 746 | 'INCB', 'DECB', 'NOTB', 'NEGB', 747 | ] 748 | 749 | def code_for_cmd_nop(inst_operands): 750 | return [] 751 | 752 | def code_for_cmd_cmpw(inst_operands): 753 | return code_for_binary_cmd_w(inst_operands, 'CMPW', write_to_dst=False) 754 | 755 | def code_for_cmd_cmpb(inst_operands): 756 | return code_for_binary_cmd_b(inst_operands, 'CMPB', write_to_dst=False) 757 | 758 | def code_for_cmd_testw(inst_operands): 759 | return code_for_binary_cmd_w(inst_operands, 'TESTW', write_to_dst=False) 760 | 761 | def code_for_cmd_testb(inst_operands): 762 | return code_for_binary_cmd_b(inst_operands, 'TESTB', write_to_dst=False) 763 | 764 | def code_for_cmd_idivw(inst_operands): 765 | code = code_to_calc_address_if_needed(inst_operands) 766 | code += code_for_read_w(inst_operands[0], reg='1') 767 | code += [PptInstruction('EXEC', 'IDIVW')] 768 | return code 769 | 770 | def code_for_cmd_idivb(inst_operands): 771 | code = code_to_calc_address_if_needed(inst_operands) 772 | code += code_for_read_b(inst_operands[0], reg='1') 773 | code += [PptInstruction('EXEC', 'IDIVB')] 774 | return code 775 | 776 | def code_for_cmd_divw(inst_operands): 777 | code = code_to_calc_address_if_needed(inst_operands) 778 | code += code_for_read_w(inst_operands[0], reg='1') 779 | code += [PptInstruction('EXEC', 'DIVW')] 780 | return code 781 | 782 | def code_for_cmd_divb(inst_operands): 783 | code = code_to_calc_address_if_needed(inst_operands) 784 | code += code_for_read_b(inst_operands[0], reg='1') 785 | code += [PptInstruction('EXEC', 'DIVB')] 786 | return code 787 | 788 | def code_for_cmd_imulw(inst_operands): 789 | code = code_to_calc_address_if_needed(inst_operands) 790 | code += code_for_read_w(inst_operands[0], reg='1') 791 | code += [PptInstruction('EXEC', 'IMULW')] 792 | return code 793 | 794 | def code_for_cmd_imulb(inst_operands): 795 | code = code_to_calc_address_if_needed(inst_operands) 796 | code += code_for_read_b(inst_operands[0], reg='1') 797 | code += [PptInstruction('EXEC', 'IMULB')] 798 | return code 799 | 800 | def code_for_cmd_mulw(inst_operands): 801 | code = code_to_calc_address_if_needed(inst_operands) 802 | code += code_for_read_w(inst_operands[0], reg='1') 803 | code += [PptInstruction('EXEC', 'MULW')] 804 | return code 805 | 806 | def code_for_cmd_mulb(inst_operands): 807 | code = code_to_calc_address_if_needed(inst_operands) 808 | code += code_for_read_b(inst_operands[0], reg='1') 809 | code += [PptInstruction('EXEC', 'MULB')] 810 | return code 811 | 812 | def code_for_cmd_leaw(inst_operands): 813 | addr, dst = inst_operands 814 | assert dst.type == 'REG' 815 | return code_for_calc_address(addr, dst.reg1) 816 | 817 | def code_for_cmd_jmp(inst_operands): 818 | assert not inst_operands[0].requires_calculation() 819 | code = code_for_read_w(inst_operands[0], reg='1') 820 | code += [PptInstruction('EXEC', 'JMP')] 821 | return code 822 | 823 | def code_for_cond_jmp(inst_operands, cmd='JNE'): 824 | suffix = cmd[1:] 825 | negate = suffix.startswith('N') 826 | if negate: 827 | suffix = suffix[1:] 828 | code = [PptInstruction('EXEC', 'V' + suffix)] 829 | if negate: 830 | code += [PptInstruction('EXEC', 'NV')] 831 | code += code_for_read_w(inst_operands[0], reg='1') 832 | code += [PptInstruction('EXEC', 'JV')] 833 | return code 834 | 835 | cond_jmp_suffixes = ['A', 'C', 'Z', 'O', 'S', 'G', 'L'] 836 | 837 | cond_jump_suffix_map = { 838 | 'AE': 'NC', 839 | 'B': 'C', 840 | 'BE': 'NA', 841 | 'E': 'Z', 842 | 'GE': 'NL', 843 | 'LE': 'NG', 844 | } 845 | 846 | nullary_commands = [ 847 | 'CBW', 'CLC', 'CMC', 'STC', 'HLT' 848 | ] 849 | 850 | def code_for_cmd_pushw(inst_operands): 851 | src = inst_operands[0] 852 | code = [] 853 | if src.type == 'REG': 854 | return [ 855 | PptInstruction('LOAD1H', 'SPH'), 856 | PptInstruction('LOAD1L', 'SPL'), 857 | PptInstruction('EXEC', 'DEC2W'), 858 | PptInstruction('STOREH', 'SPH'), 859 | PptInstruction('STOREL', 'SPL'), 860 | PptInstruction('LOAD1H', 'SPH'), 861 | PptInstruction('LOAD1L', 'SPL'), 862 | PptInstruction('EXEC', 'SMP'), 863 | PptInstruction('LOAD2L', src.reg1 + 'L'), 864 | PptInstruction('EXEC', 'WMEM'), 865 | PptInstruction('EXEC', 'IMP'), 866 | PptInstruction('LOAD2L', src.reg1 + 'H'), 867 | PptInstruction('EXEC', 'WMEM'), 868 | ] 869 | else: 870 | code += code_to_calc_address_if_needed(inst_operands, write_to_dst=False) 871 | code += code_for_read_w(src, reg='3') 872 | code += [ 873 | PptInstruction('STOREH', 'M4H'), 874 | PptInstruction('STOREL', 'M4L'), 875 | PptInstruction('LOAD1H', 'SPH'), 876 | PptInstruction('LOAD1L', 'SPL'), 877 | PptInstruction('EXEC', 'DEC2W'), 878 | PptInstruction('STOREH', 'SPH'), 879 | PptInstruction('STOREL', 'SPL'), 880 | PptInstruction('LOAD1H', 'SPH'), 881 | PptInstruction('LOAD1L', 'SPL'), 882 | PptInstruction('EXEC', 'SMP'), 883 | PptInstruction('LOAD2L', 'M4L'), 884 | PptInstruction('EXEC', 'WMEM'), 885 | PptInstruction('EXEC', 'IMP'), 886 | PptInstruction('LOAD2L', 'M4H'), 887 | PptInstruction('EXEC', 'WMEM'), 888 | ] 889 | return code 890 | 891 | def code_for_cmd_popw(inst_operands): 892 | dst = inst_operands[0] 893 | code = [] 894 | if dst.type == 'REG': 895 | return [ 896 | PptInstruction('LOAD1H', 'SPH'), 897 | PptInstruction('LOAD1L', 'SPL'), 898 | PptInstruction('EXEC', 'INC2W'), 899 | PptInstruction('STOREH', 'SPH'), 900 | PptInstruction('STOREL', 'SPL'), 901 | PptInstruction('EXEC', 'SMP'), 902 | PptInstruction('EXEC', 'RMEM'), 903 | PptInstruction('STOREL', dst.reg1 + 'L'), 904 | PptInstruction('EXEC', 'IMP'), 905 | PptInstruction('EXEC', 'RMEM'), 906 | PptInstruction('STOREL', dst.reg1 + 'H'), 907 | ] 908 | else: 909 | code += code_for_calc_address(dst) 910 | code += [ 911 | PptInstruction('LOAD1H', 'SPH'), 912 | PptInstruction('LOAD1L', 'SPL'), 913 | PptInstruction('EXEC', 'INC2W'), 914 | PptInstruction('STOREH', 'SPH'), 915 | PptInstruction('STOREL', 'SPL'), 916 | PptInstruction('EXEC', 'SMP'), 917 | PptInstruction('EXEC', 'RMEM'), 918 | PptInstruction('STOREL', 'M5L'), 919 | PptInstruction('EXEC', 'IMP'), 920 | PptInstruction('EXEC', 'RMEM'), 921 | PptInstruction('STOREL', 'M5H'), 922 | 923 | PptInstruction('LOAD1H', 'M4H'), 924 | PptInstruction('LOAD1L', 'M4L'), 925 | PptInstruction('EXEC', 'SMP'), 926 | PptInstruction('LOAD2L', 'M5L'), 927 | PptInstruction('EXEC', 'WMEM'), 928 | PptInstruction('EXEC', 'IMP'), 929 | PptInstruction('LOAD2L', 'M5H'), 930 | PptInstruction('EXEC', 'WMEM'), 931 | ] 932 | return code 933 | 934 | def code_for_cmd_call(inst_operands, offset=0): 935 | dst = inst_operands[0] 936 | if dst.type == 'IMM' and dst.immediate.label in builtin_commands_map: 937 | return [ 938 | PptInstruction('EXEC', builtin_commands_map[dst.immediate.label]) 939 | ] 940 | 941 | code = [] 942 | i = Immediate(offset, size='w') 943 | if dst.type == 'MEM': 944 | code += code_to_calc_address_if_needed(inst_operands, write_to_dst=False) 945 | code += code_for_read_w(dst, reg='3') 946 | code += [ 947 | PptInstruction('STOREH', 'M5H'), 948 | PptInstruction('STOREL', 'M5L'), 949 | ] 950 | code += [ 951 | PptInstruction('LOAD1H', 'SPH'), 952 | PptInstruction('LOAD1L', 'SPL'), 953 | PptInstruction('EXEC', 'DEC2W'), 954 | PptInstruction('STOREH', 'SPH'), 955 | PptInstruction('STOREL', 'SPL'), 956 | PptInstruction('LOAD1H', 'SPH'), 957 | PptInstruction('LOAD1L', 'SPL'), 958 | PptInstruction('EXEC', 'SMP'), 959 | PptInstruction('CONSTH', i), 960 | PptInstruction('CONSTL', i), 961 | PptInstruction('LOAD2L', 'M3L'), 962 | PptInstruction('EXEC', 'WMEM'), 963 | PptInstruction('EXEC', 'IMP'), 964 | PptInstruction('LOAD2L', 'M3H'), 965 | PptInstruction('EXEC', 'WMEM'), 966 | ] 967 | if dst.type == 'MEM': 968 | code += [ 969 | PptInstruction('LOAD1H', 'M5H'), 970 | PptInstruction('LOAD1L', 'M5L'), 971 | ] 972 | else: 973 | code += code_for_read_w(dst, reg='1') 974 | code += [ 975 | PptInstruction('EXEC', 'JMP'), 976 | ] 977 | i.offset += len(code) 978 | return code 979 | 980 | def code_for_cmd_ret(inst_operands): 981 | if len(inst_operands) > 0: 982 | op = inst_operands[0] 983 | assert op.type == 'IMM' 984 | op.immediate.offset += 2 985 | else: 986 | op = None 987 | code = [] 988 | code += [ 989 | PptInstruction('LOAD1H', 'SPH'), 990 | PptInstruction('LOAD1L', 'SPL'), 991 | ] 992 | if op is None: 993 | code += [ 994 | PptInstruction('EXEC', 'INC2W'), 995 | PptInstruction('STOREH', 'SPH'), 996 | PptInstruction('STOREL', 'SPL'), 997 | ] 998 | else: 999 | code += [ 1000 | PptInstruction('CONSTH', op.immediate), 1001 | PptInstruction('CONSTL', op.immediate), 1002 | PptInstruction('EXEC', 'ADDADDR'), 1003 | PptInstruction('STOREH', 'SPH'), 1004 | PptInstruction('STOREL', 'SPL'), 1005 | ] 1006 | code += [ 1007 | PptInstruction('EXEC', 'SMP'), 1008 | PptInstruction('EXEC', 'RMEM'), 1009 | PptInstruction('LOAD1L', 'M3L'), 1010 | PptInstruction('EXEC', 'IMP'), 1011 | PptInstruction('EXEC', 'RMEM'), 1012 | PptInstruction('LOAD1H', 'M3L'), 1013 | PptInstruction('EXEC', 'JMP'), 1014 | ] 1015 | return code 1016 | 1017 | builtin_commands_map = { 1018 | 'ppt_puts_': 'PUTS', 1019 | 'ppt_putint_': 'PUTINT', 1020 | 'ppt_putc_': 'PUTC', 1021 | 'ppt_gets_': 'GETS', 1022 | 'ppt_getint_': 'GETINT', 1023 | 'ppt_rand_': 'RAND', 1024 | } 1025 | 1026 | # TODO: Optimize moving 0s 1027 | # TODO: Optimize moving between two addresses 1028 | # TODO: jumps, 1029 | # PUSH, POP, CALL, RET 1030 | 1031 | #parse_masm('mytest.masm') 1032 | assemble_gas('mytest.gas', 'mytest2.pptasm') 1033 | #testline = 'cmpb $0x48,%al' 1034 | #code = code_for_line(testline, 0) 1035 | #print(code[0].arg.to_binary({})) 1036 | #print('\n'.join(str(c) for c in code)) 1037 | 1038 | 1039 | if __name__ == '__main__': 1040 | exit(0) 1041 | parser = argparse.ArgumentParser(description='Convert .gas to .pptasm files') 1042 | parser.add_argument('file', help='.gas file to assemble', type=str) 1043 | args = parser.parse_args() 1044 | args.file 1045 | assemble_gas(args.file, 'mytest3.pptasm') 1046 | --------------------------------------------------------------------------------