2 (** This module provides an interpreter for the LTL language. *)
5 let error_prefix = "LTL interpret"
6 let error s = Error.global_error error_prefix s
9 module Mem = Driver.LTLMemory
10 module Val = Mem.Value
11 let chunk = Driver.LTLMemory.int_size
12 module Eval = I8051.Eval (Val)
17 type memory = LTL.function_def Mem.memory
19 (* Hardware registers environments. They associate a value to the each hardware
22 type hdw_reg_env = Val.t I8051.RegisterMap.t
24 (* Execution states. *)
33 trace : CostLabel.t list }
38 let change_pc st pc = { st with pc = pc }
39 let change_isp st isp = { st with isp = isp }
40 let change_exit st exit = { st with exit = exit }
41 let change_carry st carry = { st with carry = carry }
42 let change_renv st renv = { st with renv = renv }
43 let change_mem st mem = { st with mem = mem }
44 let change_trace st trace = { st with trace = trace }
45 let add_trace st cost_lbl = change_trace st (cost_lbl :: st.trace)
52 renv = I8051.RegisterMap.empty ;
57 (* Each label of each function is associated a pointer. The base of this pointer
58 is the base of the function in memory. Inside a function, offsets are
59 bijectively associated to labels. *)
61 module Labels_Offsets = Bijection.Make (Label) (Val.Offset)
63 let labels_offsets_internal int_fun =
64 let f lbl _ (lbls_offs, i) =
65 (Labels_Offsets.add1 lbl i lbls_offs, Val.Offset.succ i) in
66 Label.Map.fold f int_fun.LTL.f_graph
68 (* [labels_offsets p] builds a bijection between the labels found in the
69 functions of [p] and some offsets. *)
71 let labels_offsets p =
72 let f (lbls_offs, i) (_, def) = match def with
73 | LTL.F_int int_fun -> labels_offsets_internal int_fun (lbls_offs, i)
74 | _ -> (lbls_offs, i) in
75 fst (List.fold_left f (Labels_Offsets.empty, Val.Offset.zero) p.LTL.functs)
77 let fun_def_of_ptr mem ptr = match Mem.find_fun_def mem ptr with
78 | LTL.F_int def -> def
79 | _ -> error "Trying to fetch the definition of an external function."
81 let fetch_stmt lbls_offs st =
83 Printf.sprintf "%s does not point to a statement."
84 (Val.string_of_address st.pc) in
85 if Val.is_mem_address st.pc then
86 let off = Val.offset_of_address st.pc in
87 let def = fun_def_of_ptr st.mem st.pc in
88 let lbl = Labels_Offsets.find2 off lbls_offs in
89 Label.Map.find lbl def.LTL.f_graph
92 let entry_pc lbls_offs ptr def =
93 Val.change_address_offset ptr (Labels_Offsets.find1 def.LTL.f_entry lbls_offs)
95 let init_fun_call lbls_offs st ptr def =
96 let pc = entry_pc lbls_offs ptr def in
99 let next_pc lbls_offs st lbl =
100 let off = Labels_Offsets.find1 lbl lbls_offs in
101 change_pc st (Val.change_address_offset st.pc off)
104 if Val.is_mem_address st.pc then
105 let def = fun_def_of_ptr st.mem st.pc in
107 else error "Trying to load the stack size of an external function."
110 let renv = I8051.RegisterMap.add r v st.renv in
114 if I8051.RegisterMap.mem r st.renv then I8051.RegisterMap.find r st.renv
115 else error ("Unknown hardware register " ^ (I8051.print_register r) ^ ".")
118 let mem = Mem.store st.mem chunk st.isp v in
119 let isp = Val.add_address st.isp (Val.Offset.of_int chunk) in
120 change_mem (change_isp st isp) mem
123 let isp = Val.add_address st.isp (Val.Offset.of_int (-chunk)) in
124 let st = change_isp st isp in
125 let v = Mem.load st.mem chunk st.isp in
128 let save_ra lbls_offs st lbl =
130 Val.change_address_offset st.pc (Labels_Offsets.find1 lbl lbls_offs) in
131 let st = push st (List.nth ra 0) in
132 let st = push st (List.nth ra 1) in
135 let label_of_pointer lbls_offs ptr =
137 Printf.printf "Retrieving label of %s\n%!" (Val.to_string ptr) ;
139 let off = Val.offset_of_address ptr in
140 Labels_Offsets.find2 off lbls_offs
142 let pointer_of_label lbls_offs ptr lbl =
143 Val.change_address_offset ptr (Labels_Offsets.find1 lbl lbls_offs)
146 let (st, pch) = pop st in
147 let (st, pcl) = pop st in
150 let dptr st = List.map (fun r -> get_reg r st) [I8051.dpl ; I8051.dph]
153 (* State pretty-printing *)
155 let current_label lbls_offs st =
156 Labels_Offsets.find2 (Val.offset_of_address st.pc) lbls_offs
158 let print_renv renv =
160 if not (Val.eq v Val.undef) then
161 Printf.printf "\n%s = %s%!" (I8051.print_register r) (Val.to_string v) in
162 I8051.RegisterMap.iter f renv
164 let print_state lbls_offs st =
165 Printf.printf "PC: %s (%s)\n%!"
166 (Val.string_of_address st.pc) (current_label lbls_offs st) ;
167 Printf.printf "SP: %s\n%!"
168 (Val.string_of_address [get_reg I8051.spl st ; get_reg I8051.sph st]) ;
169 Printf.printf "ISP: %s%!" (Val.string_of_address st.isp) ;
171 Printf.printf "\nC = %s%!" (Val.to_string st.carry) ;
176 module InterpretExternal = Primitive.Interpret (Mem)
178 let interpret_external mem f args = match InterpretExternal.t mem f args with
179 | (mem', InterpretExternal.V vs) -> (mem', vs)
180 | (mem', InterpretExternal.A addr) -> (mem', addr)
182 let fetch_external_args f st =
183 let size = Mem.size_of_quantity (Primitive.args_byte_size f) in
184 let params = MiscPottier.prefix size I8051.parameters in
185 List.map (fun r -> get_reg r st) params
187 let set_result st vs =
188 let f st (r, v) = add_reg r v st in
189 List.fold_left f st (MiscPottier.combine I8051.rets vs)
191 let interpret_external_call st f next_pc =
192 let args = fetch_external_args f st in
193 let (mem, vs) = interpret_external st.mem f args in
194 let st = change_mem st mem in
195 let st = set_result st vs in
198 let interpret_call lbls_offs st ptr ra =
199 match Mem.find_fun_def st.mem ptr with
201 let st = save_ra lbls_offs st ra in
202 init_fun_call lbls_offs st ptr def
205 Val.change_address_offset st.pc (Labels_Offsets.find1 ra lbls_offs) in
206 interpret_external_call st def.AST.ef_tag next_pc
208 let interpret_return lbls_offs st =
209 let (st, pc) = return_pc st in
213 (* Interpret statements. *)
215 let interpret_stmt lbls_offs st stmt =
216 let next_pc = next_pc lbls_offs in
222 | LTL.St_comment (s, lbl) ->
224 Printf.printf "*** %s ***\n\n%!" s ;
228 | LTL.St_cost (cost_lbl, lbl) ->
229 let st = add_trace st cost_lbl in
232 | LTL.St_int (r, i, lbl) ->
233 let st = add_reg r (Val.of_int i) st in
237 let (st, v) = pop st in
238 let st = add_reg I8051.a v st in
242 let v = get_reg I8051.a st in
243 let st = push st v in
246 | LTL.St_addr (x, lbl) ->
247 let vs = Mem.find_global st.mem x in
248 let st = add_reg I8051.dpl (List.nth vs 0) st in
249 let st = add_reg I8051.dph (List.nth vs 1) st in
252 | LTL.St_from_acc (destr, lbl) ->
253 let st = add_reg destr (get_reg (I8051.a) st) st in
256 | LTL.St_to_acc (srcr, lbl) ->
257 let st = add_reg I8051.a (get_reg srcr st) st in
260 | LTL.St_opaccs (opaccs, lbl) ->
264 (get_reg I8051.b st) in
265 let st = add_reg I8051.a a st in
266 let st = add_reg I8051.b b st in
269 | LTL.St_op1 (op1, lbl) ->
270 let v = Eval.op1 op1 (get_reg I8051.a st) in
271 let st = add_reg I8051.a v st in
274 | LTL.St_op2 (op2, srcr, lbl) ->
276 Eval.op2 st.carry op2
279 let st = change_carry st carry in
280 let st = add_reg I8051.a v st in
283 | LTL.St_clear_carry lbl ->
284 let st = change_carry st Val.zero in
287 | LTL.St_set_carry lbl ->
288 let st = change_carry st (Val.of_int 1) in
292 let addr = dptr st in
293 let v = Mem.load st.mem chunk addr in
294 let st = add_reg I8051.a v st in
297 | LTL.St_store lbl ->
298 let addr = dptr st in
299 let mem = Mem.store st.mem chunk addr (get_reg I8051.a st) in
300 let st = change_mem st mem in
303 | LTL.St_call_id (f, lbl) ->
304 interpret_call lbls_offs st (Mem.find_global st.mem f) lbl
306 | LTL.St_call_ptr lbl ->
307 interpret_call lbls_offs st (dptr st) lbl
309 | LTL.St_condacc (lbl_true, lbl_false) ->
310 let v = get_reg I8051.a st in
312 if Val.is_true v then lbl_true
314 if Val.is_false v then lbl_false
315 else error "Undecidable branchment." in
319 interpret_return lbls_offs st
322 let compute_result st =
323 let vs = List.map (fun r -> get_reg r st) I8051.rets in
324 let f res v = res && (Val.is_int v) in
325 let is_int vs = (List.length vs > 0) && (List.fold_left f true vs) in
328 List.map (fun v -> IntValue.Int32.cast (Val.to_int_repr v)) vs in
329 IntValue.Int32.merge chunks
330 else IntValue.Int32.zero
332 let rec iter_small_step debug lbls_offs st =
333 let print_and_return_result (res, cost_labels) =
334 if debug then Printf.printf "Result = %s\n%!"
335 (IntValue.Int32.to_string res) ;
336 (res, cost_labels) in
337 if debug then print_state lbls_offs st ;
338 match fetch_stmt lbls_offs st with
339 | LTL.St_return when Val.eq_address (snd (return_pc st)) st.exit ->
340 print_and_return_result (compute_result st, List.rev st.trace)
342 let st' = interpret_stmt lbls_offs st stmt in
343 iter_small_step debug lbls_offs st'
346 let add_global_vars =
348 (fun mem (id, size) -> Mem.add_var mem id (AST.SQ (AST.QInt size)) None)
351 List.fold_left (fun mem (f_id, f_def) -> Mem.add_fun_def mem f_id f_def)
353 let init_prog (st : state) (p : LTL.program) : state =
354 let mem = add_global_vars (add_fun_defs st.mem p.LTL.functs) p.LTL.vars in
358 let (mem, sp) = Mem.alloc st.mem I8051.ext_ram_size in
360 Val.change_address_offset sp (Val.Offset.of_int I8051.ext_ram_size) in
361 let st = change_mem st mem in
365 let (mem, isp) = Mem.alloc st.mem I8051.int_ram_size in
366 let st = change_mem (change_isp st isp) mem in
367 let (mem, exit) = Mem.alloc st.mem 1 in
368 let st = change_exit st exit in
369 let st = push st (List.nth exit 0) in
370 let st = push st (List.nth exit 1) in
373 let init_renv st sp =
374 let f r st = add_reg r Val.undef st in
375 let st = I8051.RegisterSet.fold f I8051.registers st in
376 let spl = List.nth sp 0 in
377 let sph = List.nth sp 1 in
378 let st = add_reg I8051.spl spl st in
379 let st = add_reg I8051.sph sph st in
382 let init_main_call lbls_offs st main =
383 let ptr = Mem.find_global st.mem main in
384 match Mem.find_fun_def st.mem ptr with
386 init_fun_call lbls_offs st ptr def
387 | _ -> error ("Cannot execute the main (\"" ^ main ^ "\"): it is external.")
390 (* Before interpreting, the environment is initialized:
391 - Build a bijection between the labels in the program and some values (taken
392 amongst the offsets).
393 - Add function definitions to the memory and reserve space for the globals.
394 - Allocate memory to emulate the external stack and initialize the external
396 - Allocate memory to emulate the internal stack and initialize the internal
398 - Initialiaze the physical register environment. All are set to 0, except for
399 the stack pointer registers that take the high and low bits of the external
401 - Initialize a call to the main (set the current program counter to the
402 beginning of the function).
403 - Initialize the carry flag to 0. *)
405 let interpret debug p =
406 Printf.printf "*** LTL interpret ***\n%!" ;
407 match p.LTL.main with
408 | None -> (IntValue.Int8.zero, [])
410 let lbls_offs = labels_offsets p in
411 let st = empty_state in
412 let st = init_prog st p in
413 let (st, sp) = init_sp st in
414 let st = init_isp st in
415 let st = init_renv st sp in
416 let st = init_main_call lbls_offs st main in
417 let st = change_carry st Val.zero in
418 iter_small_step debug lbls_offs st