feat: working assembler! second pass implemenation. mnemonic parsing and binary construction and writing
This commit is contained in:
@@ -3,11 +3,9 @@
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
|
||||
// Computes R0 = 2 + 3 (R0 refers to RAM[0])
|
||||
(lab)
|
||||
@2
|
||||
D=A
|
||||
@3
|
||||
D=D+A
|
||||
(test)
|
||||
@0
|
||||
M=D
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
// Assembled from Add.asm
|
||||
// 12 lines processed
|
||||
0000000000000010
|
||||
1110110000010000
|
||||
0000000000000011
|
||||
1110000010010000
|
||||
0000000000000000
|
||||
1110001100001000
|
||||
@@ -6,12 +6,10 @@
|
||||
// Computes R2 = max(R0, R1) (R0,R1,R2 refer to RAM[0],RAM[1],RAM[2])
|
||||
// Usage: Before executing, put two values in R0 and R1.
|
||||
|
||||
// R0 = 10
|
||||
// R1 = 15
|
||||
// d = 10
|
||||
// d = 10 - 15
|
||||
|
||||
// D = R0 - R1
|
||||
|
||||
/*
|
||||
@R0
|
||||
D=M
|
||||
@R1
|
||||
@@ -33,3 +31,36 @@
|
||||
(END)
|
||||
@END
|
||||
0;JMP
|
||||
|
||||
*/
|
||||
|
||||
// Max
|
||||
// Takes two numbers and saves the highest of them
|
||||
// Get the sum of R0 & R1
|
||||
// Save it in R2
|
||||
// Get Value of R0
|
||||
// Compare it value of R1
|
||||
// Remember that the conditional can only be compared to zero.
|
||||
// GT. LS, EQ etc.. All to zero
|
||||
// Create a label and jump to it
|
||||
|
||||
@R0
|
||||
D=M // Value of R0
|
||||
@R1
|
||||
D=D-M // New D(playground) is Old D(Value of R0) Minus Value of R1. Basically R0 - R1
|
||||
@ITSR0
|
||||
D;JGT // If D (R0 - R1) is greater than 0, then R0 is biger. Otherwise R1 or equal.
|
||||
// Else it R1
|
||||
|
||||
|
||||
|
||||
// The end Statements
|
||||
(ITSR0) // Jump here if R0
|
||||
@R0
|
||||
D=M // Set value of R0 to the playground variable.
|
||||
(OUTPUT_D) // End up here either way. Depending on value.
|
||||
@R2
|
||||
M=D // Set R2 to D either way. Just with or without the ITSR0 iteration
|
||||
(END) // The end final loop. Necessary to preven stack overflows.
|
||||
@END
|
||||
0;JMP // Infinite Jumping to end the program
|
||||
|
||||
16
project-6-assembler/assembler/provided-asm-files/Max.hack
Normal file
16
project-6-assembler/assembler/provided-asm-files/Max.hack
Normal file
@@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
1111110000010000
|
||||
0000000000000001
|
||||
1111010011010000
|
||||
0000000000001010
|
||||
1110001100000001
|
||||
0000000000000001
|
||||
1111110000010000
|
||||
0000000000001100
|
||||
1110101010000111
|
||||
0000000000000000
|
||||
1111110000010000
|
||||
0000000000000010
|
||||
1110001100001000
|
||||
0000000000001110
|
||||
1110101010000111
|
||||
27483
project-6-assembler/assembler/provided-asm-files/Pong.hack
Normal file
27483
project-6-assembler/assembler/provided-asm-files/Pong.hack
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
from assembler.code import Code
|
||||
from assembler.constants.command_types import CommandType
|
||||
from assembler.parser import Parser
|
||||
|
||||
@@ -49,11 +50,14 @@ class Assembler:
|
||||
"""
|
||||
print("[ ] - Starting First Pass..")
|
||||
self._first_pass()
|
||||
print("Symbol Table After First Pass")
|
||||
print(self.symbol_table.symbols)
|
||||
print("[x] - First Pass Done..")
|
||||
print("[ ] - Starting Second Pass..")
|
||||
self._second_pass()
|
||||
print("[x] - Second pass done..")
|
||||
print("[ ] - Writing output file..")
|
||||
self._write_output()
|
||||
print("[x] - Output file written..")
|
||||
self._assembled_success()
|
||||
|
||||
def _trim_comments_and_whitespace(self, lines: list[str]) -> list[str]:
|
||||
"""
|
||||
@@ -88,7 +92,6 @@ class Assembler:
|
||||
|
||||
while self.parser.has_more_commands():
|
||||
self.parser.advance() # Move to next command
|
||||
print(self.parser.command_type())
|
||||
cmd_type = self.parser.command_type()
|
||||
if cmd_type == CommandType.L_COMMAND:
|
||||
label = self.parser.symbol() # Extract label name
|
||||
@@ -105,43 +108,59 @@ class Assembler:
|
||||
Second pass: Translate instructions to binary.
|
||||
Handles A-commands, C-commands, and resolves symbols.
|
||||
"""
|
||||
print(self.cleaned_lines)
|
||||
|
||||
while self.parser.has_more_commands():
|
||||
self.parser.advance() # Move to next command
|
||||
print(self.parser.command_type())
|
||||
|
||||
# cmd cmd_type
|
||||
cmd_type = self.parser.command_type()
|
||||
if cmd_type == CommandType.L_COMMAND:
|
||||
continue
|
||||
elif cmd_type == CommandType.A_COMMAND:
|
||||
print("....")
|
||||
binary = self._translate_a_command(self.parser.symbol())
|
||||
self.binary_instructions.append(binary) # Store resultp
|
||||
# Do A command things
|
||||
elif cmd_type == CommandType.C_COMMAND:
|
||||
print("..")
|
||||
binary = self._translate_c_command()
|
||||
self.binary_instructions.append(binary) # Store resultp
|
||||
|
||||
# Do C command Things
|
||||
|
||||
def _translate_a_command(self, symbol: str) -> str:
|
||||
"""
|
||||
Translate A-command to 16-bit binary.
|
||||
Handles: numeric constants, predefined symbols, variables.
|
||||
"""
|
||||
raise NotImplementedError("Not implemented")
|
||||
# Case 1: Check if symbol is a numeric constant (e.g., "2", "100")
|
||||
if symbol.isdigit():
|
||||
address = int(symbol)
|
||||
|
||||
# Case 2: Check if symbol exists in symbol table (predefined or label)
|
||||
elif self.symbol_table.contains(symbol):
|
||||
address = self.symbol_table.get_address(symbol)
|
||||
|
||||
# Case 3: It's a new variable - allocate next available address
|
||||
else:
|
||||
address = self.next_variable_address
|
||||
self.symbol_table.add_entry(symbol, address)
|
||||
self.next_variable_address += 1
|
||||
|
||||
# Convert address to 16-bit binary string (format: 0xxxxxxxxxxxxxxx)
|
||||
return format(address, "016b")
|
||||
|
||||
def _translate_c_command(self) -> str:
|
||||
"""
|
||||
Translate C-command to 16-bit binary.
|
||||
Format: 111 a c1c2c3c4c5c6 d1d2d3 j1j2j3
|
||||
"""
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
comp = Code.comp(self.parser.comp())
|
||||
dest = Code.dest(self.parser.dest())
|
||||
jump = Code.jump(self.parser.jump())
|
||||
|
||||
binary = f"111{comp}{dest}{jump}"
|
||||
return binary
|
||||
|
||||
def _write_output(self) -> None:
|
||||
"""Write binary instructions to output file."""
|
||||
with open(self.output_file, "w") as f:
|
||||
f.write(f"// Assembled from {self.input_file.name}\n")
|
||||
f.write(f"// {len(self.cleaned_lines)} lines processed\n")
|
||||
raise NotImplementedError("Not implemented")
|
||||
f.write("\n".join(self.binary_instructions))
|
||||
|
||||
def _assembled_success(self) -> None:
|
||||
"""Success Message"""
|
||||
|
||||
@@ -28,7 +28,6 @@ def main():
|
||||
try:
|
||||
assembler = Assembler(input_path, output_path)
|
||||
assembler.assemble()
|
||||
print(f"Successfully assembled {input_path} -> {output_path}")
|
||||
except ValueError as e:
|
||||
# Handle validation errors (empty labels, invalid syntax, etc.)
|
||||
print(f"Assembly Error: {e}", file=sys.stderr)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .code_tables import DEST_TABLE, COMP_TABLE, JUMP_TABLE
|
||||
from .code_tables import COMP_TABLE, DEST_TABLE, JUMP_TABLE
|
||||
|
||||
|
||||
class Code:
|
||||
|
||||
Reference in New Issue
Block a user