diff --git a/ass3/zbirnik/src/zbirnik/EmitCtx.py b/ass3/zbirnik/src/zbirnik/EmitCtx.py index ba171d3..8a29781 100644 --- a/ass3/zbirnik/src/zbirnik/EmitCtx.py +++ b/ass3/zbirnik/src/zbirnik/EmitCtx.py @@ -1,9 +1,8 @@ from zbirnik.opcodes import OPCODES + class EmitContext: - REGISTERS = { - 'A': 0, 'X': 1, 'L': 2, - 'B': 3, 'S': 4, 'T': 5, 'F': 6 - } + + REGISTERS = {'A': 0, 'X': 1, 'L': 2,'B': 3, 'S': 4, 'T': 5, 'F': 6} def __init__(self, symtab): self.opcodes = OPCODES diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc index 9063204..990566a 100644 Binary files a/ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc index a67d407..1ca25d9 100644 Binary files a/ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/code.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/code.cpython-310.pyc index c7f9fc4..674f57b 100644 Binary files a/ass3/zbirnik/src/zbirnik/__pycache__/code.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/__pycache__/code.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/gen_obj.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/gen_obj.cpython-310.pyc new file mode 100644 index 0000000..47d535c Binary files /dev/null and b/ass3/zbirnik/src/zbirnik/__pycache__/gen_obj.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/parser.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/parser.cpython-310.pyc index 1f6d182..1a565f9 100644 Binary files a/ass3/zbirnik/src/zbirnik/__pycache__/parser.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/__pycache__/parser.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/parserctx.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/parserctx.cpython-310.pyc index 0e4c047..991c1b5 100644 Binary files a/ass3/zbirnik/src/zbirnik/__pycache__/parserctx.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/__pycache__/parserctx.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/adressing.py b/ass3/zbirnik/src/zbirnik/adressing.py index cf00b06..bd3107a 100644 --- a/ass3/zbirnik/src/zbirnik/adressing.py +++ b/ass3/zbirnik/src/zbirnik/adressing.py @@ -5,3 +5,4 @@ class AddrMode(Enum): SIMPLE = auto() IMMEDIATE = auto() INDIRECT = auto() + EXTENDED = auto() diff --git a/ass3/zbirnik/src/zbirnik/gen_obj.py b/ass3/zbirnik/src/zbirnik/gen_obj.py new file mode 100644 index 0000000..d875d03 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/gen_obj.py @@ -0,0 +1,89 @@ +from zbirnik.code import Code +from zbirnik.EmitCtx import EmitContext + +class Generate_obj: + + def __init__(self, code: Code, emit_ctx: EmitContext): + self.code = code + self.records = [] + self.emit_ctx = emit_ctx + + def generate(self) -> str: + h_record = self.generate_h_record() + t_records = self.generate_t_records() + #m_records = self.generate_m_records() nimam podpore za EXTREF tako da ne bo M recordou + e_record = self.generate_e_record() + + return '\n'.join([h_record] + t_records + [e_record]) + + def generate_h_record(self) -> str: + ime = (self.code.name).ljust(6) + start = f"{self.code.start_address:06X}" + dolzina= f"{self.code.program_length:06X}" + return f"H^{ime}^{start}^{dolzina}" + + + def generate_t_records(self) -> list[str]: + t_records = [] + current_start_addr = None + current_bytes = bytearray() + + for node in self.code.nodes: + chunk = node.emit(self.emit_ctx) + # If node generates no code (like RESB, RESW, START, END) + if not chunk: + # Flush current T record if we have accumulated bytes + if current_bytes: + t_record = self._make_t_record(current_start_addr, current_bytes) + t_records.append(t_record) + current_bytes = bytearray() + current_start_addr = None + continue + + # If this is the first byte in a new T record, set starting address + if current_start_addr is None: + current_start_addr = node.address + + # Add this node's bytes to current accumulation + current_bytes.extend(chunk) + + # If we've accumulated 30 or more bytes, flush a T record + while len(current_bytes) >= 30: + # Take first 30 bytes + record_bytes = current_bytes[:30] + t_record = self._make_t_record(current_start_addr, record_bytes) + t_records.append(t_record) + + # Remove those bytes and update start address + current_bytes = current_bytes[30:] + current_start_addr += 30 + + # Flush any remaining bytes + if current_bytes: + t_record = self._make_t_record(current_start_addr, current_bytes) + t_records.append(t_record) + + return t_records + + def _make_t_record(self, start_address: int, bytes_data: bytearray) -> str: + start = f"{start_address:06X}" + length = f"{len(bytes_data):02X}" + hex_code = bytes_data.hex().upper() + + return f"T^{start}^{length}^{hex_code}" + + + + def generate_m_records(self) -> list[str]: + pass + + def generate_e_record(self) -> str: + entry = self.code.entry_point + + if isinstance(entry, str): + entry = self.code.symtab.get(entry, self.code.start_address) + + if entry is None: + entry = self.code.start_address + + return f"E^{entry:06X}" \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/main.py b/ass3/zbirnik/src/zbirnik/main.py index bc79da3..f90f042 100644 --- a/ass3/zbirnik/src/zbirnik/main.py +++ b/ass3/zbirnik/src/zbirnik/main.py @@ -3,17 +3,18 @@ from zbirnik.code import Code from zbirnik.EmitCtx import EmitContext from zbirnik.mnemoniki.mnemoniki_tabela import MNEMONICS from zbirnik.parserctx import ParserContext +from zbirnik.gen_obj import Generate_obj import os ime = input("Vnesite ime programa (.asm): ") -ime = os.path.join(os.path.dirname(__file__), ime) +ime1 = os.path.join(os.path.dirname(__file__), ime) -if not ime.endswith(".asm"): +if not ime1.endswith(".asm"): raise ValueError("Ime programa ni v pravi obliki, mora biti: ime.asm") code = Code() -with open(ime) as f: +with open(ime1) as f: for line in f: print("LINE:", line.rstrip()) @@ -35,8 +36,19 @@ with open(ime) as f: code.pass1() - ctx_emit = EmitContext(symtab=code.symtab) - binary = code.pass2(ctx_emit) -print(binary.hex()) + +print("Rezultat pass2: " + binary.hex()) +print("-"*40) +obj_generator = Generate_obj(code=code, emit_ctx=ctx_emit) + +obj_data = obj_generator.generate() + +izhod = "output/"+ ime.replace(".asm", ".obj") +izhod = os.path.join(os.path.dirname(__file__), izhod) + +with open(izhod, "w") as obj: + obj.write(obj_data) + +print(obj_data) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/__pycache__/mnemoniki_tabela.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/mnemoniki/__pycache__/mnemoniki_tabela.cpython-310.pyc index 921ac79..19b674b 100644 Binary files a/ass3/zbirnik/src/zbirnik/mnemoniki/__pycache__/mnemoniki_tabela.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/mnemoniki/__pycache__/mnemoniki_tabela.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py index 80bfbb7..5580101 100644 --- a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py @@ -63,6 +63,7 @@ MNEMONICS = { 'TD': MnemonicF3m('TD', opcode=0xE0), 'RD': MnemonicF3m('RD', opcode=0xD8), 'WD': MnemonicF3m('WD', opcode=0xDC), + 'TIX': MnemonicF3m('TIX', opcode=0x2C), # Format 4 (razširjeni) '+LDA': MnemonicF4m('+LDA', opcode=0x00), '+JSUB': MnemonicF4m('+JSUB', opcode=0x48), diff --git a/ass3/zbirnik/src/zbirnik/output/test1.obj b/ass3/zbirnik/src/zbirnik/output/test1.obj new file mode 100644 index 0000000..0a677ba --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/output/test1.obj @@ -0,0 +1,3 @@ +H^TEST ^000000^00000C +T^000000^09^0320030F2003000005 +E^000000 \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/output/test2.obj b/ass3/zbirnik/src/zbirnik/output/test2.obj new file mode 100644 index 0000000..f5b4ec1 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/output/test2.obj @@ -0,0 +1,6 @@ +H^COPY ^0003E8^00005A +T^0003E8^1E^0320271B20270F202707202703A02A192C070FA0242F201E3B2FF1022039 +T^000406^12^292C5B3320033F2FE54F000000000A000014 +T^00041B^06^000000000005 +T^00043F^03^000418 +E^0003E8 \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/parser.py b/ass3/zbirnik/src/zbirnik/parser.py index 9987e09..f976579 100644 --- a/ass3/zbirnik/src/zbirnik/parser.py +++ b/ass3/zbirnik/src/zbirnik/parser.py @@ -1,6 +1,5 @@ import ply.lex import ply.yacc -#import sys global at_line_start, seen_mnemonic_or_directive # Lexer @@ -179,13 +178,3 @@ def p_error(p): print('Syntax error at EOF') parser = ply.yacc.yacc() - - -#if __name__ == '__main__': -# for line in sys.stdin: -# line = line.rstrip('\n\r') -# if line and not line.lstrip().startswith('.'): -# at_line_start = True -# seen_mnemonic_or_directive = False -# result = parser.parse(line, lexer=lexer) -# print(result) \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/parserctx.py b/ass3/zbirnik/src/zbirnik/parserctx.py index fbfcb83..ff134cc 100644 --- a/ass3/zbirnik/src/zbirnik/parserctx.py +++ b/ass3/zbirnik/src/zbirnik/parserctx.py @@ -1,6 +1,6 @@ class ParserContext: def __init__(self, parsed): - # Handle COMMENT special case (if you still need it) + #Comment if isinstance(parsed, tuple) and parsed[0] == 'COMMENT': self.label = None self.mnemonic = 'COMMENT' @@ -8,13 +8,13 @@ class ParserContext: self.comment = parsed[1] return - # New parser format: (label, mnemonic, *operands) + #parsed=(label, mnemonic, *operands) if not isinstance(parsed, tuple) or len(parsed) < 2: raise ValueError(f"Invalid parsed format: {parsed}") - self.label = parsed[0] # Can be None + self.label = parsed[0] self.mnemonic = parsed[1] - # All remaining elements are operands + #Ostali so operandi self.operands = list(parsed[2:]) if len(parsed) > 2 else [] self.comment = None @@ -29,12 +29,10 @@ class ParserContext: def read_reg(self) -> str: """Read a register operand (e.g., 'A', 'X', 'L')""" op = self.next_op() - # If it's a plain string, return it + if isinstance(op, str): return op - # If it's a tuple (shouldn't happen for registers), take first element - if isinstance(op, tuple): - return op[0] + return str(op) def read_num_sym(self): @@ -59,25 +57,22 @@ class ParserContext: addr_mode = AddrMode.SIMPLE op = self.next_op() - # Check if operand has a prefix (immediate/indirect/indexed) + # Check for prefix (immediate/indirect/indexed) if isinstance(op, tuple) and len(op) == 2: prefix, value = op if prefix == '#': addr_mode = AddrMode.IMMEDIATE elif prefix == '@': addr_mode = AddrMode.INDIRECT - elif prefix == '+': - # Extended format (SIC/XE) + elif prefix == '+': addr_mode = AddrMode.EXTENDED else: - # Unknown prefix, treat as simple value = op else: - # Simple operand (no prefix) + # Simple value = op # Check for indexed addressing (X register) - # In new parser, indexed would be a second operand that's just 'X' if self.operands and self.operands[0] == 'X': self.operands.pop(0) indexed = True diff --git a/ass3/zbirnik/src/zbirnik/program.obj b/ass3/zbirnik/src/zbirnik/program.obj new file mode 100644 index 0000000..0a677ba --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/program.obj @@ -0,0 +1,3 @@ +H^TEST ^000000^00000C +T^000000^09^0320030F2003000005 +E^000000 \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/program.asm b/ass3/zbirnik/src/zbirnik/test1.asm similarity index 100% rename from ass3/zbirnik/src/zbirnik/program.asm rename to ass3/zbirnik/src/zbirnik/test1.asm diff --git a/ass3/zbirnik/src/zbirnik/test2.asm b/ass3/zbirnik/src/zbirnik/test2.asm new file mode 100644 index 0000000..2adeec3 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/test2.asm @@ -0,0 +1,23 @@ +COPY START 1000 + LDA ALPHA + ADD BETA + STA GAMMA + LDX ZERO +LOOP LDA BUFFER,X + ADD #1 + STA BUFFER,X + TIX COUNT + JLT LOOP + LDA @PTR + COMP #100 + JEQ DONE + J LOOP +DONE RSUB +ALPHA WORD 10 +BETA WORD 20 +GAMMA RESW 1 +ZERO WORD 0 +COUNT WORD 5 +BUFFER RESW 10 +PTR WORD GAMMA + END COPY \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/test_emit.py b/ass3/zbirnik/src/zbirnik/test_emit.py index f81e021..69bf254 100644 --- a/ass3/zbirnik/src/zbirnik/test_emit.py +++ b/ass3/zbirnik/src/zbirnik/test_emit.py @@ -1,25 +1,7 @@ -OPCODES = { - "FIX": 0xC4, - "ADDR": 0x90, - "LDA": 0x00, - "STA": 0x0C, - "JSUB": 0x48, -} - -REGISTERS = { - "A": 0, - "X": 1, - "L": 2, - "B": 3, - "S": 4, - "T": 5, - "F": 6, -} - from zbirnik.ukazi.f1 import f1 from zbirnik.EmitCtx import EmitContext -ctx = EmitContext(OPCODES, REGISTERS, {}) +ctx = EmitContext({}) node = f1("FIX", None) result = node.emit(ctx) diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/directive.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/directive.cpython-310.pyc index fb43c3b..6c528a4 100644 Binary files a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/directive.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/directive.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc index 23c9532..ec95518 100644 Binary files a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f3.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f3.cpython-310.pyc index 00a2e7f..35ea5ff 100644 Binary files a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f3.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f3.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f4.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f4.cpython-310.pyc index 19b6a58..2b16771 100644 Binary files a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f4.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f4.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/storage.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/storage.cpython-310.pyc index e155d04..da4a2e0 100644 Binary files a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/storage.cpython-310.pyc and b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/storage.cpython-310.pyc differ diff --git a/ass3/zbirnik/src/zbirnik/ukazi/directive.py b/ass3/zbirnik/src/zbirnik/ukazi/directive.py index 61908ed..48e1337 100644 --- a/ass3/zbirnik/src/zbirnik/ukazi/directive.py +++ b/ass3/zbirnik/src/zbirnik/ukazi/directive.py @@ -10,7 +10,7 @@ class directive(Node): return 0 def emit(self, ctx): - # BASE directive + # BASE if self.name == "BASE": if isinstance(self.operand, str): ctx.base = ctx.symtab[self.operand] @@ -20,7 +20,7 @@ class directive(Node): raise ValueError("Invalid BASE operand") return None - # NOBASE directive + # NOBASE if self.name == "NOBASE": ctx.base = None return None diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f2.py b/ass3/zbirnik/src/zbirnik/ukazi/f2.py index f686434..a7bddf1 100644 --- a/ass3/zbirnik/src/zbirnik/ukazi/f2.py +++ b/ass3/zbirnik/src/zbirnik/ukazi/f2.py @@ -13,15 +13,20 @@ class f2(Node): def emit(self, ctx): opcode = ctx.opcodes[self.mnemonic] + #f2r,f2rr,f2rn if isinstance(self.r1, str): r1_val = ctx.REGISTERS[self.r1] + #f2n else: r1_val = self.r1 + #f2r if self.r2 is None: r2_val = 0 + #f2rr elif isinstance(self.r2, str): r2_val = ctx.REGISTERS[self.r2] + #f2rn else: r2_val = self.r2 diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f3.py b/ass3/zbirnik/src/zbirnik/ukazi/f3.py index 8da7f9f..90c0923 100644 --- a/ass3/zbirnik/src/zbirnik/ukazi/f3.py +++ b/ass3/zbirnik/src/zbirnik/ukazi/f3.py @@ -14,6 +14,16 @@ class f3(Node): def emit(self, ctx): opcode = ctx.opcodes[self.mnemonic] + + # RSUB + if self.mnemonic == "RSUB": + base_opcode = opcode & 0b11111100 + n, i = 1, 1 + byte1 = base_opcode | (n << 1) | i + byte2 = 0x00 + byte3 = 0x00 + return bytes([byte1, byte2, byte3]) + base_opcode = opcode & 0b11111100 if self.adr_mode == AddrMode.SIMPLE: @@ -38,6 +48,7 @@ class f3(Node): disp = target - pc b = 0 p = 1 + #PC relativno if -2048 <= disp <= 2047: b = 0 diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f4.py b/ass3/zbirnik/src/zbirnik/ukazi/f4.py index 4acc767..cb8cb10 100644 --- a/ass3/zbirnik/src/zbirnik/ukazi/f4.py +++ b/ass3/zbirnik/src/zbirnik/ukazi/f4.py @@ -34,6 +34,7 @@ class f4(Node): raise ValueError("Invalid addressing mode") byte1 = base_opcode | (n << 1) | i + x = 1 if self.index else 0 b = 0 p = 0 diff --git a/ass3/zbirnik/src/zbirnik/ukazi/storage.py b/ass3/zbirnik/src/zbirnik/ukazi/storage.py index 1e1ca8a..a21ca5a 100644 --- a/ass3/zbirnik/src/zbirnik/ukazi/storage.py +++ b/ass3/zbirnik/src/zbirnik/ukazi/storage.py @@ -37,7 +37,7 @@ class storage(Node): if s.startswith("C'") and s.endswith("'"): chars = s[2:-1] return bytes(ord(c) for c in chars) - # X'F1A3' + # X'FA3' if s.startswith("X'") and s.endswith("'"): hexstr = s[2:-1] return bytes.fromhex(hexstr)