differentiate numerical imm and label imm,

implement assembler,
add binary file outputs to gitignore,
add development container for assembler
This commit is contained in:
Arthur Lu 2022-08-10 05:44:32 +00:00
parent 216d118967
commit 5d8ea74edc
8 changed files with 211 additions and 33 deletions

6
.devcontainer/Dockerfile Normal file
View File

@ -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

View File

@ -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": ""
}

View File

@ -0,0 +1 @@
tqdm

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
**/*.bin

138
assembler.py Normal file
View File

@ -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'))

View File

@ -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

View File

@ -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

View File

@ -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