From 5d8ea74edca7baa83f823a045b4772bed8a8bb89 Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Wed, 10 Aug 2022 05:44:32 +0000 Subject: [PATCH] differentiate numerical imm and label imm, implement assembler, add binary file outputs to gitignore, add development container for assembler --- .devcontainer/Dockerfile | 6 ++ .devcontainer/devcontainer.json | 30 +++++++ .devcontainer/requirements.txt | 1 + .gitignore | 1 + assembler.py | 138 ++++++++++++++++++++++++++++++++ program1.asm | 14 ++-- program2.asm | 25 +++--- program3.asm | 29 +++---- 8 files changed, 211 insertions(+), 33 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/requirements.txt create mode 100644 .gitignore create mode 100644 assembler.py diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..9992aaa --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,6 @@ +FROM python:slim +WORKDIR / +RUN apt-get -y update; apt-get -y upgrade +RUN apt-get -y install git binutils +COPY requirements.txt . +RUN pip install -r requirements.txt \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..c750a50 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +{ + "name": "cse141L development container", + "build": { + "dockerfile": "Dockerfile", + }, + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "python.pythonPath": "/usr/local/bin/python", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", + "python.formatting.blackPath": "/usr/local/py-utils/bin/black", + "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", + "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", + "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", + "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", + "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", + "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", + "python.linting.pylintPath": "/usr/local/bin/pylint", + "python.testing.pytestPath": "/usr/local/py-utils/bin/pytest", + "editor.tabSize": 4, + "editor.insertSpaces": false + }, + "extensions": [ + "mhutchie.git-graph", + "ms-python.python", + "waderyan.gitblame" + ], + "postCreateCommand": "" + } diff --git a/.devcontainer/requirements.txt b/.devcontainer/requirements.txt new file mode 100644 index 0000000..fa9cf06 --- /dev/null +++ b/.devcontainer/requirements.txt @@ -0,0 +1 @@ +tqdm \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8e2b01 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/*.bin \ No newline at end of file diff --git a/assembler.py b/assembler.py new file mode 100644 index 0000000..95442da --- /dev/null +++ b/assembler.py @@ -0,0 +1,138 @@ +from re import M +import sys +from tqdm import tqdm + +reg_map = { + 'r0': 0, + 'r1': 1, + 'r2': 2, + 'r3': 3, + 'r4': 4, + 'r5': 5, + 'r6': 6, + 'r7': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15 +} + +op_type = { + 'LDI': 'I', + 'PUT': 'A', + 'GET': 'A', + 'LDW': 'S', + 'STW': 'S', + 'NXT': 'S', + 'CLB': 'G', + 'ADD': 'A', + 'SUB': 'A', + 'ORR': 'A', + 'AND': 'A', + 'LSH': 'T', + 'PTY': 'G', + 'CHK': 'A', + 'XOR': 'A', + 'JNZ': 'G', + 'JEZ': 'G', + 'JMP': 'G', + 'JAL': 'G' +} + +op_codes = { + 'LDI': 0b1_0000_0000, + 'PUT': 0b0_0000_0000, + 'GET': 0b0_0001_0000, + 'LDW': 0b0_0010_0000, + 'STW': 0b0_0010_1000, + 'NXT': 0b0_0011_0000, + 'CLB': 0b0_0011_1000, + 'ADD': 0b0_0100_0000, + 'SUB': 0b0_0101_0000, + 'ORR': 0b0_0110_0000, + 'AND': 0b0_0111_0000, + 'LSH': 0b0_1000_0000, + 'PTY': 0b0_1000_1000, + 'CHK': 0b0_1001_0000, + 'XOR': 0b0_1010_0000, + 'JNZ': 0b0_1110_0000, + 'JEZ': 0b0_1110_1000, + 'JMP': 0b0_1111_0000, + 'JAL': 0b0_1111_1000 +} + +def get_reg(type, opcode): + if type == 'S': + return reg_map[opcode] - 8 + elif type == 'G': + return reg_map[opcode] + elif type == 'A': + return reg_map[opcode] + else: + print('invalid opcode detected: ' + opcode) + exit(1) + +def get_immediate(operand, labels): + if operand.startswith("#b"): + operand = operand.strip("#b") + return int(operand, 2) + elif operand.startswith("#x"): + operand = operand.strip("#x") + return int(operand, 16) + elif operand.startswith("#d"): + operand = operand.strip("#d") + return int(operand, 10) + elif operand in labels: + return labels[operand] + else: + print('invalid immediate detected: ' + operand) + exit(1) + +output = sys.argv[1] +targets = sys.argv[2:] +print('detected targets: ' + str(targets)) +for file in targets: + print('assembing: ' + file) + no_comments = [] + instructions = [] + labels = {} + index = 0 + raw_lines = [] + instructions = [] + f = open(file, 'r') + for line in f: + raw_lines.append(line) + for line in tqdm(raw_lines, desc='Preprocessing', unit=' lines'): + line = line.split('//')[0] # remove comments + if line != '': + line = line.replace('\t', '') # remove leading tabs + line = line.replace('\n', '') # remove trailing newline + if ': ' in line: + labels[line.split(': ')[0]] = index # ': ' must be used to end a label + no_comments.append(line.split(': ')[1]) + else: + no_comments.append(line) + index += 1 + index = 0 + for line in tqdm(no_comments, desc='Operand', unit=' operands'): + line = line.split(' ') + opcode = line[0] + operand = line[1] + if op_type[opcode] == "I" or op_type[opcode] == "T": + operand = get_immediate(operand, labels) + else: + operand = get_reg(op_type[opcode], operand) + instructions.append((opcode, operand)) + #print(str(index+1) + " " + str(opcode) + " " + str(operand)) + index += 1 + out = open(output, "wb") + for inst in tqdm(instructions, desc='Assembly', unit=' instructions'): + opcode = op_codes[inst[0]] + operand = inst[1] + #print(str(opcode) + " " + str(operand)) + #print(str(opcode | operand)) + out.write((opcode| operand).to_bytes(length=2, byteorder='big')) diff --git a/program1.asm b/program1.asm index 0e31162..bb4cb9d 100644 --- a/program1.asm +++ b/program1.asm @@ -28,34 +28,34 @@ preamble_loop: LDI #d32 // get space character decimal 32 XOR r7 // bitwise XOR the current state with plaintext space to generate ciphertext CLB r0 // clear the leading bit of the ciphertext as in requirements STW r12 // store ciphertext to write pointer - LDI #lfsr_routine // load address for the lfsr_routine label + LDI lfsr_routine // load address for the lfsr_routine label JAL r0 // jump to the lfsr_routine label NXT r12 // increment write pointer NXT r9 // decrement number of remaining ciphertext characters - LDI #main_loop // load the address of label main_loop + LDI main_loop // load the address of label main_loop NXT r8 // decrement preamble counter JEZ r0 // exit preamble loop if the preamble counter has just reached 0 - LDI #preamble_loop // load the address of label preamble_loop + LDI preamble_loop // load the address of label preamble_loop JMP r0 // jump to preamble_loop if there are more space characters to encode main_loop: LDW r11 // load the next plaintext byte XOR r7 // bitwise XOR the current state with plaintext space to generate ciphertext CLB r0 // clear the leading bit of the ciphertext as in requirements STW r12 // store ciphertext to write pointer - LDI #lfsr_routine // load address for the lfsr_routine label + LDI lfsr_routine // load address for the lfsr_routine label JAL r0 // jump to the lfsr_routine label NXT r11 // increment read pointer NXT r12 // increment write pointer - LDI #done // load address of label done + LDI done // load address of label done NXT r9 // decrement number of remaining ciphertext chars JEZ r0 // jump to end of program if all ciphertext chars have been processed - LDI #main_loop // load address of main_loop + LDI main_loop // load address of main_loop JMP r0 // jump to main_loop if there is still space for message characters lfsr_routine: GET r7 // get previous state AND r6 // and state with taps to get feedback pattern PTY r0 // get feedback parity bit PUT r1 // store feedback bit to r1 temporarily GET r7 // get previous state again - LSH #1 // left shift previous state by 1 + LSH #d1 // left shift previous state by 1 ORR r1 // or with parity bit to get next state PUT r7 // put next state to r7 GET r14 // load link register diff --git a/program2.asm b/program2.asm index 4e81314..8596f3b 100644 --- a/program2.asm +++ b/program2.asm @@ -10,7 +10,7 @@ // r12 is the write pointer init: LDI #d10 PUT r10 // set the tap counter to 10, which will choose tap pattern 9 to start after subtracting by 1 -tap_lut: LDI #tap_init +tap_lut: LDI tap_init JMP r0 // goto tap_init, skipping the LUT LDI #x60 // load tap pattern 1 JMP r5 // jump back to tap loop @@ -38,11 +38,12 @@ tap_init: LDI #d64 PUT r8 // load 10 into preamble counter LDI #d64 PUT r9 // load 64 (total encryption length) to r9 + LDI done NXT r10 // decrement tap selection by 1, starts at 9 for the first iteration - JEZ #done // if no more taps left that didn't work, raise the done flag - LDI #tap_init + JEZ r0 // if no more taps left that didn't work, raise the done flag + LDI tap_init PUT r5 // put the tap_loop address in r5 - LDI #tap_lut + LDI tap_lut ADD r10 ADD r10 // add 2*tap select to tap_lut location, results in location of selected tap pattern JMP r0 // jump to LUT, which loads the tap pattern into r0 @@ -56,13 +57,13 @@ tap_init: LDI #d64 NXT r11 // increment read pointer NXT r12 // increment write pointer NXT r9 // decrement total encryption chars remaining - tap_loop: LDI #lfsr_routine + tap_loop: LDI lfsr_routine JAL r0 // jump to lfsr routine which calculates next state in r7 LDI #d32 // load space char expected plaintext XOR r7 CLB r0 // clear leading bit in the expected ciphertext PUT r1 // store expected cipher text in r1 - LDI #tap_init + LDI tap_init PUT r2 // load the outer loop top into r2 LDW r11 // load actual ciphertext SUB r1 // subtract actual from expected, result of 0 means matching @@ -72,30 +73,30 @@ tap_init: LDI #d64 NXT r11 // increment read pointer NXT r12 // increment write pointer NXT r9 // decrement total encryption chars remaining - LDI #main_loop // load main_loop location into r0 + LDI main_loop // load main_loop location into r0 NXT r8 // decrement preamble counter JEZ r0 // if r8 (preamble counter) is zero, then all preamble have matched and current tap pattern is correct, jump to main loop - LDI #tap_loop + LDI tap_loop JMP r0 // jump to tap_loop if characters matched but preamble is not over main_loop: LDW r11 // load the next ciphertext byte XOR r7 // bitwise XOR the current state with ciphertext space to generate plaintext CLB r0 // clear the leading bit of the plaintext as in requirements STW r12 // store plaintext to write pointer - LDI #lfsr_routine // load address for the lfsr_routine label + LDI lfsr_routine // load address for the lfsr_routine label JAL r0 // jump to the lfsr_routine label NXT r11 // increment read pointer NXT r12 // increment write pointer - LDI #done // load address of label done + LDI done // load address of label done NXT r9 // decrement number of remaining plaintext chars JEZ r0 // jump to end of program if all plaintext chars have been processed - LDI #main_loop // load address of main_loop + LDI main_loop // load address of main_loop JMP r0 // jump to main_loop if there is still space for message characters lfsr_routine: GET r7 // get previous state AND r6 // and state with taps to get feedback pattern PTY r0 // get feedback parity bit PUT r1 // store feedback bit to r1 temporarily GET r7 // get previous state again - LSH #1 // left shift previous state by 1 + LSH #d1 // left shift previous state by 1 ORR r1 // or with parity bit to get next state PUT r7 // put next state to r7 GET r14 // load link register diff --git a/program3.asm b/program3.asm index 3d9b60a..fe5e894 100644 --- a/program3.asm +++ b/program3.asm @@ -10,7 +10,7 @@ // r12 is the write pointer init: LDI #d10 PUT r10 // set the tap counter to 10, which will choose tap pattern 9 to start after subtracting by 1 -tap_lut: LDI #tap_init +tap_lut: LDI tap_init JMP r0 // goto tap_init, skipping the LUT LDI #x60 // load tap pattern 1 JMP r5 // jump back to tap loop @@ -38,11 +38,12 @@ tap_init: LDI #d64 PUT r8 // load 10 into preamble counter LDI #d64 PUT r9 // load 64 (total encryption length) to r9 + LDI done NXT r10 // decrement tap selection by 1, starts at 9 for the first iteration - JEZ #done // if no more taps left that didn't work, raise the done flag - LDI #tap_init + JEZ r0 // if no more taps left that didn't work, raise the done flag + LDI tap_init PUT r5 // put the tap_loop address in r5 - LDI #tap_lut + LDI tap_lut ADD r10 ADD r10 // add 2*tap select to tap_lut location, results in location of selected tap pattern JMP r0 // jump to LUT, which loads the tap pattern into r0 @@ -56,13 +57,13 @@ tap_init: LDI #d64 NXT r11 // increment read pointer NXT r12 // increment write pointer NXT r9 // decrement total encryption chars remaining - tap_loop: LDI #lfsr_routine + tap_loop: LDI lfsr_routine JAL r0 // jump to lfsr routine which calculates next state in r7 LDI #d32 // load space char expected plaintext XOR r7 CLB r0 // clear leading bit in the expected ciphertext PUT r1 // store expected cipher text in r1 - LDI #tap_init + LDI tap_init PUT r2 // load the outer loop top into r2 LDW r11 // load actual ciphertext SUB r1 // subtract actual from expected, result of 0 means matching @@ -72,38 +73,38 @@ tap_init: LDI #d64 NXT r11 // increment read pointer NXT r12 // increment write pointer NXT r9 // decrement total encryption chars remaining - LDI #main_loop // load main_loop location into r0 + LDI main_loop // load main_loop location into r0 NXT r8 // decrement preamble counter JEZ r0 // if r8 (preamble counter) is zero, then all preamble have matched and current tap pattern is correct, jump to main loop - LDI #tap_loop + LDI tap_loop JMP r0 // jump to tap_loop if characters matched but preamble is not over -main_loop: LDI #correct +main_loop: LDI correct PUT r1 // put correct handle address in r1 LDW r11 // load the next ciphertext byte CHK r0 // check ciphertext for error JEZ r1 // if no error, jump to correct, otherwise continue to error handling error: LDI #x80 // load error flag character into r0 STW r12 // store error flag to write pointer - LDI #common + LDI common JMP r0 // jump out of error handling, to common operations after writing correct: XOR r7 // bitwise XOR the current state with ciphertext space to generate plaintext CLB r0 // clear the leading bit of the plaintext as in requirements STW r12 // store plaintext to write pointer - common: LDI #lfsr_routine // load address for the lfsr_routine label + common: LDI lfsr_routine // load address for the lfsr_routine label JAL r0 // jump to the lfsr_routine label NXT r11 // increment read pointer NXT r12 // increment write pointer - LDI #done // load address of label done + LDI done // load address of label done NXT r9 // decrement number of remaining plaintext chars JEZ r0 // jump to end of program if all plaintext chars have been processed - LDI #main_loop // load address of main_loop + LDI main_loop // load address of main_loop JMP r0 // jump to main_loop if there is still space for message characters lfsr_routine: GET r7 // get previous state AND r6 // and state with taps to get feedback pattern PTY r0 // get feedback parity bit PUT r1 // store feedback bit to r1 temporarily GET r7 // get previous state again - LSH #1 // left shift previous state by 1 + LSH #d1 // left shift previous state by 1 ORR r1 // or with parity bit to get next state PUT r7 // put next state to r7 GET r14 // load link register