(*naloga instruction modula je ustvarjanje instructionLista, torej vsebine T zapisa*) (*sem spada izbira nacina naslavljanja, dolocanje ali je operand simbol itd..*) open SemanticAnalyzer open Simtab open OpcodeTable (*podatki o base naslavljanju*) type base_info = { is_base : bool; valueB : int } type operand = | R of register | RR of register * register | RN of register * int (*register in število*) | N of int (*številski operand*) | S of string (*simbol*) | None let string_is_symbol (s : string) : bool * operand = try let n = int_of_string s in false, N n with Failure _ -> true, S s (*preveri ali je operand iz mnemonic_type simbol ali stevilo*) let operand_is_symbol (x : lineSemantic) : (bool * operand * int) option = (*vrne isSymbol, operand in dolzino ukaza, ali none, če ukaza/direktive ne bomo zapisali v T file*) match x.mnem with | MnemonicD -> None | MnemonicDn s -> let (issym, operand) = string_is_symbol s in Some (issym, operand, x.len) | MnemonicF1 -> Some (false, None, x.len) | MnemonicF2n n -> Some (false, N n, x.len) | MnemonicF2r r1 -> Some (false, R r1, x.len) | MnemonicF2rn (r1, n) -> Some (false, RN (r1, n), x.len) | MnemonicF2rr (r1, r2) -> Some (false, RR (r1, r2), x.len) | MnemonicF3 -> Some (false, None, x.len) | MnemonicF3m s -> let (issym, operand) = string_is_symbol s in Some (issym, operand, x.len) | MnemonicF4m s -> let (issym, operand) = string_is_symbol s in Some (issym, operand, x.len) | MnemonicSd s -> let (issym, operand) = string_is_symbol s in Some (issym, operand, x.len) | MnemonicSn _ -> None(*RESW in RESB že drugje obdelamo*) | COMMENT -> None (*Comment ze obdelamo drugje*) (*helper funkcija za registre*) let int_of_reg (reg : register) : int = match reg with | A -> 0 | X -> 1 | L -> 2 | B -> 3 | S -> 4 | T -> 5 | F -> 6 | PC -> 8 | SW -> 9 (*helper funkcija*) let int_to_hex_width (width : int) (n : int) : string = let s = Printf.sprintf "%X" n in let len = String.length s in if len >= width then (String.sub s (len - width) width) else String.make (width - len) '0' ^ s let char_to_hex c = Printf.sprintf "%02X" (Char.code c) (*preveri ali laho pc relativno nasljavljas in vrni disp*) let is_pc_relative (loc : int) (target : int) : bool * int = let pc = loc + 3 in let disp = target - pc in if disp >= -2048 && disp <= 2047 then (true, disp) else (false, 0) (*preveri ali lahko bazno naslavljamo*) let is_base_relative (target : int) (valueB : int) : bool * int = let disp = valueB - target in if disp >= 0 && disp <= 4095 then (true, disp) else (false, 0) (*preveri ali gre v direktno naslavljanje 0 <= addr <= 4095*) let is_direct (target: int) : bool * int = if target >= 0 && target <= 4095 then true, target else false, 0 (*vrne xbpe in disp*) let get_xbpe_disp (x : bool) (loc : int option) (target : int) (base_info : base_info) : int * int = let location = match loc with | None -> failwith "location of instructin in None" | Some i -> i in (*probamo pc relativno*) let p, disp = is_pc_relative location target in if p then let x_int = if x then 8 else 0 in let p_int = 2 in let xbpe = x_int + p_int in xbpe, disp (*ce je bazno omogoceno in deluje*) else let b, disp = is_base_relative base_info.valueB target in if base_info.is_base && b then let x_int = if x then 8 else 0 in let b_int = 4 in let xbpe = x_int + b_int in xbpe, disp (*če gre direktno*) else let direct, disp = is_direct target in if direct then let x_int = if x then 8 else 0 in let xbpe = x_int in xbpe, disp else failwith (Printf.sprintf "No adressing mode is appropriate for target %d" target) (*naredi binaren zapis F1 oz string nibblov celotnega ukaza*) let get_bin_instruction_F1 (opcode : int) : string = int_to_hex_width 2 opcode (*naredi binaren zapis F2 oz string nibblov celotnega ukaza*) let get_bin_instruction_F2 (opcode : int) (operand : operand) : string = match operand with | RR (r1, r2) -> (int_to_hex_width 2 opcode) ^ (int_to_hex_width 1 (int_of_reg r1)) ^ (int_to_hex_width 1 (int_of_reg r2)) | RN (r1, n) -> (int_to_hex_width 2 opcode) ^ (int_to_hex_width 1 (int_of_reg r1)) ^ (int_to_hex_width 1 n) | R r1 -> (int_to_hex_width 2 opcode) ^ (int_to_hex_width 1 (int_of_reg r1)) ^ (int_to_hex_width 1 0) (*r2 -> 0*) | N n -> (int_to_hex_width 2 opcode) ^ (int_to_hex_width 1 n) ^ (int_to_hex_width 1 0) | _ -> failwith "invalid operand type for F2 instruction" let get_bin_instruction_F3 (opcode : int) (simtab : symtab) (operand : operand) (loc : int option) (x : bool) (n : bool) (i : bool) (base_info : base_info) : string = let oppcode_with_ni = match (n, i) with | (false, false) -> opcode + 0 | (false, true) -> opcode + 1 | (true, false) -> opcode + 2 | (true, true ) -> opcode + 3 in match operand with | None -> (int_to_hex_width 2 oppcode_with_ni) ^ (int_to_hex_width 4 0) (*RSUB damo z disp = 0*) | N n -> let xbpe = if x then 8 else 0 in (*ce imamo stevilsko vrednost uporabimo direktno naslavljanje*) (int_to_hex_width 2 oppcode_with_ni) ^ (int_to_hex_width 1 xbpe) ^ (int_to_hex_width 3 n) | S s -> (*poiscemo naslov simbola, dolocimo xbpe in disp*) let operand = Hashtbl.find simtab s in let xbpe, disp = get_xbpe_disp x loc operand base_info in (int_to_hex_width 2 oppcode_with_ni) ^ (int_to_hex_width 1 xbpe) ^ (int_to_hex_width 3 disp) | _ -> "" let get_bin_instruction_F4 (opcode : int) (simtab : symtab) (operand : operand) (x : bool) (n : bool) (i : bool) : string = let oppcode_with_ni = match (n, i) with | (false, false) -> opcode + 0 | (false, true) -> opcode + 1 | (true, false) -> opcode + 2 | (true, true ) -> opcode + 3 in let xbpe = if x then 9 else 1 in (*pri F4 imamo le direktno, zato je p = 0, b = 0, e=1*) match operand with | None -> (int_to_hex_width 2 oppcode_with_ni) ^ (int_to_hex_width 6 0) (*RSUB damo z disp = 0*) | N n -> (int_to_hex_width 2 oppcode_with_ni) ^ (int_to_hex_width 1 xbpe) ^ (int_to_hex_width 5 n) | S s -> let operand = Hashtbl.find simtab s in (int_to_hex_width 2 oppcode_with_ni) ^ (int_to_hex_width 1 xbpe) ^ (int_to_hex_width 5 operand) | _ -> "" (*vrni bin zapis instrukcij tipa F1, F2, F3, F4*) let create_opcode (simtab : symtab) (opcodeTab : opcodeTab) (opcode : mnemonic) (operand : operand) (formatLen : int) (loc : int option) (x : bool) (n : bool) (i : bool) (base_info: base_info): string = (*izberi nacin naslavljanja in naredi string ukaza*) match formatLen with | 1 -> get_bin_instruction_F1 (find_opcode opcodeTab opcode) | 2 -> get_bin_instruction_F2 (find_opcode opcodeTab opcode) operand | 3 -> get_bin_instruction_F3 (find_opcode opcodeTab opcode) simtab operand loc x n i base_info | 4 -> get_bin_instruction_F4 (find_opcode opcodeTab opcode) simtab operand x n i | _ -> "" (*opcode BYTE direktive*) let create_opcode_byte (operand : string) : string = if String.length operand < 3 then failwith "Invalid BYTE operand, use X'...' or C'...'!" else match operand.[0] with | 'C' -> (* e.g., C'EOF' *) let content = String.sub operand 2 (String.length operand - 3) in let len = String.length content in if len <> 1 then failwith "BYTE C'...' has to have a operand of length 1 inside hte '...' brackets!" else String.concat "" (List.init (String.length content) (fun i -> char_to_hex content.[i])) | 'X' -> (* e.g., X'F1' *) let hex = String.sub operand 2 (String.length operand - 3) in if String.length hex >= 6 then failwith "WORD X'...' has to have a operand of length <= 6 inside hte '...' brackets!" else String.make (2 - String.length hex) '0' ^ hex | _ -> let n = int_of_string operand in Printf.sprintf "%02X" n let create_opcode_word (operand : string) : string = if String.length operand = 0 then failwith "Invalid WORD operand use X'...' or C'...'!" else match operand.[0] with | 'C' -> (* WORD as C'...' *) let content = String.sub operand 2 (String.length operand - 3) in let len = String.length content in if len <> 3 then failwith "WORD C'...' has to have a operand of length 3 inside hte '...' brackets!" else let hex = String.concat "" (List.init len (fun i -> char_to_hex content.[i])) in (* pad to 6 hex digits for WORD *) if String.length hex >= 6 then hex else String.make (6 - String.length hex) '0' ^ hex | 'X' -> (* WORD as X'...' *) let hex = String.sub operand 2 (String.length operand - 3) in if String.length hex >= 6 then failwith "WORD X'...' has to have a operand of length <= 6 inside hte '...' brackets!" else String.make (6 - String.length hex) '0' ^ hex | _ -> (* numeric constant *) let n = int_of_string operand in Printf.sprintf "%06X" n let print_text_line_instruction (opcode : mnemonic) (mnem : mnemonic_type) (newTextLine : string) : unit = Printf.printf "zbirali %s, %s -> %s\n" (string_of_mnemonic opcode) (string_of_mnemonic_type mnem) newTextLine