Skip to content

Instantly share code, notes, and snippets.

@valtron
Created September 2, 2017 07:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save valtron/bf1d3ac3be58e4fa7d75355d863f0cc0 to your computer and use it in GitHub Desktop.
Save valtron/bf1d3ac3be58e4fa7d75355d863f0cc0 to your computer and use it in GitHub Desktop.
Hack machine language assembler
import re
from pathlib import Path
def main():
dir = Path('.')
for pi in dir.glob('**/*.asm'):
po = Path(str(pi).replace('.asm', '.hack'))
assemble(pi, po)
def assemble(pi, po):
labels = {
'SP': 0, 'LCL': 1, 'ARG': 2, 'THIS': 3, 'THAT': 4,
'SCREEN': 16384, 'KBD': 24576,
}
for i in range(16):
labels['R{}'.format(i)] = i
VAR = 1024
i = 0
with pi.open() as fi:
for l in fi:
l = re.sub(r'//.*', '', l).strip()
if not l: continue
if l[0] == '(':
labels[l[1:-1]] = i
continue
i += 1
with po.open('w') as fo:
with pi.open() as fi:
i = 0
for l in fi:
l = re.sub(r'//.*', '', l).strip()
if not l: continue
if l[0] == '(': continue
if l[0] == '@':
sym = l[1:]
try:
sym = int(sym)
except ValueError:
if sym not in labels:
labels[sym] = VAR
VAR += 1
sym = labels[sym]
fo.write('{:016b}\n'.format(int(sym)))
else:
if ';' not in l:
l += ';'
if '=' not in l:
l = '=' + l
l = l.replace('=', ';')
(dst, clc, jmp) = l.split(';')
dst = DSTMAP[''.join(sorted(dst)).lower()]
clc = clc.lower()
jmp = JMPMAP[jmp.lower()]
A = (1 if 'm' in clc else 0)
clc = CLCMAP[clc.replace('m', 'a')]
fo.write('111{}{}{}{}\n'.format(A, clc, dst, jmp))
JMPMAP = {
'': '000', 'jmp': '111', 'jlt': '100',
'jle': '110', 'jeq': '010', 'jge': '011',
'jgt': '001', 'jne': '101',
}
DSTMAP = {
'': '000', 'a': '100', 'd': '010',
'm': '001', 'ad': '110', 'am': '101',
'dm': '011', 'adm': '111',
}
CLCMAP = {
'0': '101010',
'1': '111111',
'-1': '111010',
'd': '001100',
'a': '110000',
'!d': '001101',
'!a': '110001',
'-d': '001111',
'-a': '110011',
'd+1': '011111',
'a+1': '110111',
'd-1': '001110',
'a-1': '110010',
'd+a': '000010',
'd-a': '010011',
'a-d': '000111',
'd&a': '000000',
'd|a': '010101',
}
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment