2 (** This module translates a [LIN] program into a [ASM] program. *)
5 let error_prefix = "LIN to ASM"
6 let error s = Error.global_error error_prefix s
9 (* Translation environment *)
12 { externals : AST.ident list ;
14 fresh : unit -> string }
16 let make_env externals exit_lbl fresh =
17 { externals = externals ;
22 (* Fetch the labels found in a LIN program. *)
24 let statement_labels = function
28 | LIN.St_condacc lbl -> Label.Set.singleton lbl
29 | _ -> Label.Set.empty
31 let funct_labels (_, fun_def) = match fun_def with
33 let f labels stmt = Label.Set.union labels (statement_labels stmt) in
34 List.fold_left f Label.Set.empty stmts
35 | _ -> Label.Set.empty
38 let f labels funct = Label.Set.union labels (funct_labels funct) in
39 List.fold_left f Label.Set.empty p.LIN.functs
42 let size_of_vect_size = function
49 let vect_of_int i size =
51 if i < 0 then (MiscPottier.pow 2 (size_of_vect_size size)) + i else i in
52 try BitVectors.vect_of_int i' size
53 with Invalid_argument _ (* "BitVectors.vect_of_int: size not big enough" *) ->
55 (Printf.sprintf "integer %d is too big to convert using %d bits. Maybe the stack frame of a function is too big."
56 i (size_of_vect_size size))
58 let byte_of_int i = vect_of_int i `Eight
59 let data_of_int i = `DATA (byte_of_int i)
60 let data16_of_int i = `DATA16 (vect_of_int i `Sixteen)
61 let acc_addr = I8051.reg_addr I8051.a
62 let dpl_addr = I8051.reg_addr I8051.dpl
63 let dph_addr = I8051.reg_addr I8051.dph
64 let st0_addr = I8051.reg_addr I8051.st0
65 let st1_addr = I8051.reg_addr I8051.st1
68 let translate_statement env = function
69 | LIN.St_goto lbl -> [`Jmp lbl]
70 | LIN.St_label lbl -> [`Label lbl]
71 | LIN.St_comment _ -> []
73 (* TODO: hack! Need to make the difference between cost labels and regular
76 | LIN.St_int (r, i) ->
77 [`MOV (`U3 (I8051.reg_addr r, data_of_int i))]
82 | LIN.St_addr x when List.mem x env.externals ->
83 (* HACK! for Lustre support: externals appears in the code but are not
85 [`MOV (`U4 (`DPTR, data16_of_int 0))]
86 (* error ("Primitive or external " ^ x ^ " is not supported.") *)
89 | LIN.St_from_acc r ->
90 [`MOV (`U3 (I8051.reg_addr r, `A))]
92 [`MOV (`U1 (`A, I8051.reg_addr r))]
93 | LIN.St_opaccs I8051.Mul ->
95 | LIN.St_opaccs I8051.DivuModu ->
97 | LIN.St_op1 I8051.Cmpl ->
99 | LIN.St_op1 I8051.Inc ->
101 | LIN.St_op2 (I8051.Add, r) ->
102 [`ADD (`A, I8051.reg_addr r)]
103 | LIN.St_op2 (I8051.Addc, r) ->
104 [`ADDC (`A, I8051.reg_addr r)]
105 | LIN.St_op2 (I8051.Sub, r) ->
106 [`SUBB (`A, I8051.reg_addr r)]
107 | LIN.St_op2 (I8051.And, r) ->
108 [`ANL (`U1 (`A, I8051.reg_addr r))]
109 | LIN.St_op2 (I8051.Or, r) ->
110 [`ORL (`U1 (`A, I8051.reg_addr r))]
111 | LIN.St_op2 (I8051.Xor, r) ->
112 [`XRL (`U1 (`A, I8051.reg_addr r))]
113 | LIN.St_clear_carry ->
115 | LIN.St_set_carry ->
118 [`MOVX (`U1 (`A, `EXT_IND_DPTR))]
120 [`MOVX (`U2 (`EXT_IND_DPTR, `A))]
121 | LIN.St_call_id x when List.mem x env.externals ->
122 (* HACK! for Lustre support: externals appears in the code but are not
125 (* error ("Primitive or external " ^ x ^ " is not supported.") *)
126 | LIN.St_call_id f ->
129 let lbl = env.fresh () in
130 [`MOV (`U3 (st0_addr, dpl_addr)) ; (* save DPL *)
131 `MOV (`U3 (st1_addr, dph_addr)) ; (* save DPH *)
132 `Mov (`DPTR, lbl) ; (* DPTR <- return address *)
133 `PUSH dpl_addr ; (* push DPL *)
134 `PUSH dph_addr ; (* push DPH *)
135 `MOV (`U3 (dpl_addr, st0_addr)) ; (* restore DPL *)
136 `MOV (`U3 (dph_addr, st1_addr)) ; (* restore DPH *)
137 `MOV (`U1 (`A, data_of_int 0)) ; (* A <- 0 *)
138 `JMP `IND_DPTR ; (* jump to A+DPTR *)
139 `Label lbl] (* return address *)
140 | LIN.St_condacc lbl ->
141 [`WithLabel (`JNZ (`Label lbl))]
145 let translate_code env code =
146 List.flatten (List.map (translate_statement env) code)
149 let translate_fun_def env (id, def) =
150 let code = match def with
151 | LIN.F_int code -> translate_code env code
152 | LIN.F_ext ext -> [`NOP] in
153 ((`Label id) :: code)
155 let translate_functs env main functs =
156 let preamble = match main with
159 [`MOV (`U3 (`DIRECT (byte_of_int I8051.isp_addr),
160 data_of_int I8051.isp_init)) ;
161 `MOV (`U3 (`DIRECT (byte_of_int I8051.spl_addr),
162 data_of_int I8051.spl_init)) ;
163 `MOV (`U3 (`DIRECT (byte_of_int I8051.sph_addr),
164 data_of_int I8051.sph_init)) ;
166 `Label env.exit_lbl ; `Jmp env.exit_lbl] in
167 preamble @ (List.flatten (List.map (translate_fun_def env) functs))
171 let f_externals (id, def) = match def with LIN.F_ext _ -> [id] | _ -> [] in
173 List.fold_left (fun res def -> res @ (f_externals def)) [] p.LIN.functs in
174 let prog_lbls = prog_labels p in
175 let exit_lbl = Label.Gen.fresh_prefix prog_lbls "_exit" in
176 let fresh = Label.make_fresh prog_lbls "_call_ret" in
177 make_env externals exit_lbl fresh
180 (* Translating programs.
182 Global variables are associated an offset from the base of the external
186 let env = init_env p in
188 { ASM.ppreamble = p.LIN.vars ;
189 ASM.pexit_label = env.exit_lbl ;
190 ASM.pcode = translate_functs env p.LIN.main p.LIN.functs ;
191 ASM.phas_main = p.LIN.main <> None } in
192 ASMInterpret.assembly p