cga68k.pas 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl, Carl Eric Codere
  4. This unit generates 68000 (or better) assembler from the parse tree
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cga68k;
  19. interface
  20. uses
  21. cobjects,tree,m68k,aasm,symtable;
  22. procedure emitl(op : tasmop;var l : plabel);
  23. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  24. procedure emitcall(const routine:string;add_to_externals : boolean);
  25. procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
  26. destreg:Tregister;delloc:boolean);
  27. procedure emit_to_reg32(var hr:tregister);
  28. procedure loadsetelement(var p : ptree);
  29. { produces jumps to true respectively false labels using boolean expressions }
  30. procedure maketojumpbool(p : ptree);
  31. procedure emitoverflowcheck(p: ptree);
  32. procedure push_int(l : longint);
  33. function maybe_push(needed : byte;p : ptree) : boolean;
  34. procedure restore(p : ptree);
  35. procedure emit_push_mem(const ref : treference);
  36. procedure emitpushreferenceaddr(const ref : treference);
  37. procedure copystring(const dref,sref : treference;len : byte);
  38. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
  39. { see implementation }
  40. procedure maybe_loada5;
  41. procedure emit_bounds_check(hp: treference; index: tregister);
  42. procedure loadstring(p:ptree);
  43. procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
  44. { return a float op_size from a floatb type }
  45. { also does some error checking for problems }
  46. function getfloatsize(t: tfloattype): topsize;
  47. procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
  48. { procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  49. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize); }
  50. procedure firstcomplex(p : ptree);
  51. { generate stackframe for interrupt procedures }
  52. procedure generate_interrupt_stackframe_entry;
  53. procedure generate_interrupt_stackframe_exit;
  54. { generate entry code for a procedure.}
  55. procedure genentrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  56. stackframe:longint;
  57. var parasize:longint;var nostackframe:boolean;
  58. inlined : boolean);
  59. { generate the exit code for a procedure. }
  60. procedure genexitcode(list : paasmoutput;parasize:longint;
  61. nostackframe,inlined:boolean);
  62. {$ifdef test_dest_loc}
  63. const { used to avoid temporary assignments }
  64. dest_loc_known : boolean = false;
  65. in_dest_loc : boolean = false;
  66. dest_loc_tree : ptree = nil;
  67. var dest_loc : tlocation;
  68. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  69. {$endif test_dest_loc}
  70. implementation
  71. uses
  72. systems,globals,verbose,files,types,pbase,
  73. tgen68k,hcodegen,temp_gen,ppu
  74. {$ifdef GDB}
  75. ,gdb
  76. {$endif}
  77. ;
  78. {
  79. procedure genconstadd(size : topsize;l : longint;const str : string);
  80. begin
  81. if l=0 then
  82. else if l=1 then
  83. exprasmlist^.concat(new(pai68k,op_A_INC,size,str)
  84. else if l=-1 then
  85. exprasmlist^.concat(new(pai68k,op_A_INC,size,str)
  86. else
  87. exprasmlist^.concat(new(pai68k,op_ADD,size,'$'+tostr(l)+','+str);
  88. end;
  89. }
  90. procedure copystring(const dref,sref : treference;len : byte);
  91. var
  92. pushed : tpushed;
  93. begin
  94. pushusedregisters(pushed,$ffff);
  95. { emitpushreferenceaddr(dref); }
  96. { emitpushreferenceaddr(sref); }
  97. { push_int(len); }
  98. { This speeds up from 116 cycles to 24 cycles on the 68000 }
  99. { when passing register parameters! }
  100. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dref),R_A1)));
  101. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(sref),R_A0)));
  102. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,len,R_D0)));
  103. emitcall('FPC_STRCOPY',true);
  104. maybe_loada5;
  105. popusedregisters(pushed);
  106. end;
  107. procedure loadstring(p:ptree);
  108. begin
  109. case p^.right^.resulttype^.deftype of
  110. stringdef : begin
  111. { load a string ... }
  112. { here two possible choices: }
  113. { if it is a char, then simply }
  114. { load 0 length string }
  115. if (p^.right^.treetype=stringconstn) and
  116. (str_length(p^.right)=0) then
  117. exprasmlist^.concat(new(pai68k,op_const_ref(
  118. A_MOVE,S_B,0,newreference(p^.left^.location.reference))))
  119. else
  120. copystring(p^.left^.location.reference,p^.right^.location.reference,
  121. min(pstringdef(p^.right^.resulttype)^.len,pstringdef(p^.left^.resulttype)^.len));
  122. end;
  123. orddef : begin
  124. if p^.right^.treetype=ordconstn then
  125. begin
  126. { offset 0: length of string }
  127. { offset 1: character }
  128. exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_W,1*256+p^.right^.value,
  129. newreference(p^.left^.location.reference))))
  130. end
  131. else
  132. begin
  133. { not so elegant (goes better with extra register }
  134. if (p^.right^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  135. begin
  136. exprasmlist^.concat(new(pai68k,op_reg_reg(
  137. A_MOVE,S_B,p^.right^.location.register,R_D0)));
  138. ungetregister32(p^.right^.location.register);
  139. end
  140. else
  141. begin
  142. exprasmlist^.concat(new(pai68k,op_ref_reg(
  143. A_MOVE,S_B,newreference(p^.right^.location.reference),R_D0)));
  144. del_reference(p^.right^.location.reference);
  145. end;
  146. { alignment can cause problems }
  147. { add length of string to ref }
  148. exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_B,1,
  149. newreference(p^.left^.location.reference))));
  150. (* if abs(p^.left^.location.reference.offset) >= 1 then
  151. Begin *)
  152. { temporarily decrease offset }
  153. Inc(p^.left^.location.reference.offset);
  154. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,R_D0,
  155. newreference(p^.left^.location.reference))));
  156. Dec(p^.left^.location.reference.offset);
  157. { restore offset }
  158. (* end
  159. else
  160. Begin
  161. Comment(V_Debug,'SecondChar2String() internal error.');
  162. internalerror(34);
  163. end; *)
  164. end;
  165. end;
  166. else
  167. CGMessage(type_e_mismatch);
  168. end;
  169. end;
  170. procedure restore(p : ptree);
  171. var
  172. hregister : tregister;
  173. begin
  174. if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
  175. hregister:=getregister32
  176. else
  177. hregister:=getaddressreg;
  178. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SPPULL,hregister)));
  179. if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
  180. begin
  181. p^.location.register:=hregister;
  182. end
  183. else
  184. begin
  185. reset_reference(p^.location.reference);
  186. p^.location.reference.base:=hregister;
  187. set_location(p^.left^.location,p^.location);
  188. end;
  189. end;
  190. function maybe_push(needed : byte;p : ptree) : boolean;
  191. var
  192. pushed : boolean;
  193. begin
  194. if (needed>usablereg32) or (needed > usableaddress) then
  195. begin
  196. if (p^.location.loc=LOC_REGISTER) or
  197. (p^.location.loc=LOC_CREGISTER) then
  198. begin
  199. pushed:=true;
  200. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,p^.location.register,R_SPPUSH)));
  201. ungetregister32(p^.location.register);
  202. end
  203. else
  204. if ((p^.location.loc=LOC_MEM) or(p^.location.loc=LOC_REFERENCE)) and
  205. ((p^.location.reference.base<>R_NO) or
  206. (p^.location.reference.index<>R_NO)) then
  207. begin
  208. del_reference(p^.location.reference);
  209. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  210. R_A0)));
  211. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A0,R_SPPUSH)));
  212. pushed:=true;
  213. end
  214. else pushed:=false;
  215. end
  216. else pushed:=false;
  217. maybe_push:=pushed;
  218. end;
  219. { emit out of range check for arrays and sets}
  220. procedure emit_bounds_check(hp: treference; index: tregister);
  221. { index = index of array to check }
  222. { memory of range check information for array }
  223. var
  224. hl : plabel;
  225. begin
  226. if (aktoptprocessor = MC68020) then
  227. begin
  228. exprasmlist^.concat(new(pai68k, op_ref_reg(A_CMP2,S_L,newreference(hp),index)));
  229. getlabel(hl);
  230. emitl(A_BCC, hl);
  231. exprasmlist^.concat(new(pai68k, op_const_reg(A_MOVE,S_L,201,R_D0)));
  232. emitcall('FPC_HALT_ERROR',true);
  233. emitl(A_LABEL, hl);
  234. end
  235. else
  236. begin
  237. exprasmlist^.concat(new(pai68k, op_ref_reg(A_LEA,S_L,newreference(hp), R_A1)));
  238. exprasmlist^.concat(new(pai68k, op_reg_reg(A_MOVE, S_L, index, R_D0)));
  239. emitcall('FPC_RE_BOUNDS_CHECK',true);
  240. end;
  241. end;
  242. procedure emit_to_reg32(var hr:tregister);
  243. begin
  244. (* case hr of
  245. R_AX..R_DI : begin
  246. hr:=reg16toreg32(hr);
  247. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ffff,hr)));
  248. end;
  249. R_AL..R_DL : begin
  250. hr:=reg8toreg32(hr);
  251. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ff,hr)));
  252. end;
  253. R_AH..R_DH : begin
  254. hr:=reg8toreg32(hr);
  255. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ff00,hr)));
  256. end;
  257. end; *)
  258. end;
  259. function getfloatsize(t: tfloattype): topsize;
  260. begin
  261. case t of
  262. s32real: getfloatsize := S_FS;
  263. s64real: getfloatsize := S_FL;
  264. s80real: getfloatsize := S_FX;
  265. {$ifdef extdebug}
  266. else {else case }
  267. begin
  268. Comment(V_Debug,' getfloatsize() trying to get unknown size.');
  269. internalerror(12);
  270. end;
  271. {$endif}
  272. end;
  273. end;
  274. procedure emitl(op : tasmop;var l : plabel);
  275. begin
  276. if op=A_LABEL then
  277. exprasmlist^.concat(new(pai_label,init(l)))
  278. else
  279. exprasmlist^.concat(new(pai_labeled,init(op,l)))
  280. end;
  281. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  282. begin
  283. if (reg1 <> reg2) or (i <> A_MOVE) then
  284. exprasmlist^.concat(new(pai68k,op_reg_reg(i,s,reg1,reg2)));
  285. end;
  286. procedure emitcall(const routine:string;add_to_externals : boolean);
  287. begin
  288. exprasmlist^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol(routine,0))));
  289. if add_to_externals and
  290. not (cs_compilesystem in aktmoduleswitches) then
  291. concat_external(routine,EXT_NEAR);
  292. end;
  293. procedure maketojumpbool(p : ptree);
  294. begin
  295. if p^.error then
  296. exit;
  297. if (p^.resulttype^.deftype=orddef) and
  298. (porddef(p^.resulttype)^.typ=bool8bit) then
  299. begin
  300. if is_constboolnode(p) then
  301. begin
  302. if p^.value<>0 then
  303. emitl(A_JMP,truelabel)
  304. else emitl(A_JMP,falselabel);
  305. end
  306. else
  307. begin
  308. case p^.location.loc of
  309. LOC_CREGISTER,LOC_REGISTER : begin
  310. exprasmlist^.concat(new(pai68k,op_reg(A_TST,S_B,p^.location.register)));
  311. ungetregister32(p^.location.register);
  312. emitl(A_BNE,truelabel);
  313. emitl(A_JMP,falselabel);
  314. end;
  315. LOC_MEM,LOC_REFERENCE : begin
  316. exprasmlist^.concat(new(pai68k,op_ref(
  317. A_TST,S_B,newreference(p^.location.reference))));
  318. del_reference(p^.location.reference);
  319. emitl(A_BNE,truelabel);
  320. emitl(A_JMP,falselabel);
  321. end;
  322. LOC_FLAGS : begin
  323. emitl(flag_2_jmp[p^.location.resflags],truelabel);
  324. emitl(A_JMP,falselabel);
  325. end;
  326. end;
  327. end;
  328. end
  329. else
  330. CGMessage(type_e_mismatch);
  331. end;
  332. procedure emitoverflowcheck(p: ptree);
  333. var
  334. hl : plabel;
  335. begin
  336. if cs_check_overflow in aktlocalswitches then
  337. begin
  338. getlabel(hl);
  339. if not ((p^.resulttype^.deftype=pointerdef) or
  340. ((p^.resulttype^.deftype=orddef) and
  341. (porddef(p^.resulttype)^.typ in [u16bit,u32bit,u8bit,uchar,bool8bit]))) then
  342. emitl(A_BVC,hl)
  343. else
  344. emitl(A_BCC,hl);
  345. emitcall('FPC_OVERFLOW',true);
  346. emitl(A_LABEL,hl);
  347. end;
  348. end;
  349. procedure push_int(l : longint);
  350. begin
  351. if (l = 0) and (aktoptprocessor = MC68020) then
  352. begin
  353. exprasmlist^.concat(new(pai68k,op_reg(A_CLR,S_L,R_D6)));
  354. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  355. R_D6, R_SPPUSH)));
  356. end
  357. else
  358. if not(cs_littlesize in aktglobalswitches) and (l >= -128) and (l <= 127) then
  359. begin
  360. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVEQ,S_L,l,R_D6)));
  361. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_D6,R_SPPUSH)));
  362. end
  363. else
  364. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,l,R_SPPUSH)));
  365. end;
  366. procedure emit_push_mem(const ref : treference);
  367. { Push a value on to the stack }
  368. begin
  369. if ref.isintvalue then
  370. push_int(ref.offset)
  371. else
  372. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),R_SPPUSH)));
  373. end;
  374. { USES REGISTER R_A1 }
  375. procedure emitpushreferenceaddr(const ref : treference);
  376. { Push a pointer to a value on the stack }
  377. begin
  378. if ref.isintvalue then
  379. push_int(ref.offset)
  380. else
  381. begin
  382. if (ref.base=R_NO) and (ref.index=R_NO) then
  383. exprasmlist^.concat(new(pai68k,op_ref(A_PEA,S_L,
  384. newreference(ref))))
  385. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  386. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  387. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  388. ref.index,R_SPPUSH)))
  389. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  390. (ref.offset=0) and (ref.symbol=nil) then
  391. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,ref.base,R_SPPUSH)))
  392. else
  393. begin
  394. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(ref),R_A1)));
  395. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A1,R_SPPUSH)));
  396. end;
  397. end;
  398. end;
  399. { This routine needs to be further checked to see if it works correctly }
  400. { because contrary to the intel version, all large set elements are read }
  401. { as 32-bit value_str, and then decomposed to find the correct byte. }
  402. { CHECKED : Depending on the result size, if reference, a load may be }
  403. { required on word, long or byte. }
  404. procedure loadsetelement(var p : ptree);
  405. var
  406. hr : tregister;
  407. opsize : topsize;
  408. begin
  409. { copy the element in the d0.b register, slightly complicated }
  410. case p^.location.loc of
  411. LOC_REGISTER,
  412. LOC_CREGISTER : begin
  413. hr:=p^.location.register;
  414. emit_reg_reg(A_MOVE,S_L,hr,R_D0);
  415. ungetregister32(hr);
  416. end;
  417. else
  418. begin
  419. { This is quite complicated, because of the endian on }
  420. { the m68k! }
  421. opsize:=S_NO;
  422. case integer(p^.resulttype^.savesize) of
  423. 1 : opsize:=S_B;
  424. 2 : opsize:=S_W;
  425. 4 : opsize:=S_L;
  426. else
  427. internalerror(19);
  428. end;
  429. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,opsize,
  430. newreference(p^.location.reference),R_D0)));
  431. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
  432. 255,R_D0)));
  433. {
  434. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  435. newreference(p^.location.reference),R_D0))); }
  436. { exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
  437. $ff,R_D0))); }
  438. del_reference(p^.location.reference);
  439. end;
  440. end;
  441. end;
  442. procedure generate_interrupt_stackframe_entry;
  443. begin
  444. { save the registers of an interrupt procedure }
  445. { .... also the segment registers }
  446. end;
  447. procedure generate_interrupt_stackframe_exit;
  448. begin
  449. { restore the registers of an interrupt procedure }
  450. end;
  451. procedure genentrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  452. stackframe:longint;
  453. var parasize:longint;var nostackframe:boolean;
  454. inlined : boolean);
  455. {Generates the entry code for a procedure.}
  456. var hs:string;
  457. hp:Pused_unit;
  458. unitinits:taasmoutput;
  459. {$ifdef GDB}
  460. stab_function_name:Pai_stab_function_name;
  461. {$endif GDB}
  462. begin
  463. if (aktprocsym^.definition^.options and poproginit<>0) then
  464. begin
  465. {Init the stack checking.}
  466. if (cs_check_stack in aktlocalswitches) and
  467. (target_info.target=target_m68k_linux) then
  468. begin
  469. procinfo.aktentrycode^.insert(new(pai68k,
  470. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_INIT_STACK_CHECK',0))));
  471. end
  472. else
  473. { The main program has already allocated its stack - so we simply compare }
  474. { with a value of ZERO, and the comparison will directly check! }
  475. if (cs_check_stack in aktlocalswitches) then
  476. begin
  477. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  478. newcsymbol('FPC_STACKCHECK',0))));
  479. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
  480. 0,R_D0)));
  481. concat_external('FPC_STACKCHECK',EXT_NEAR);
  482. end;
  483. unitinits.init;
  484. {Call the unit init procedures.}
  485. hp:=pused_unit(usedunits.first);
  486. while assigned(hp) do
  487. begin
  488. { call the unit init code and make it external }
  489. if (hp^.u^.flags and uf_init)<>0 then
  490. begin
  491. unitinits.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('INIT$$'+hp^.u^.modulename^,0))));
  492. concat_external('INIT$$'+hp^.u^.modulename^,EXT_NEAR);
  493. end;
  494. hp:=pused_unit(hp^.next);
  495. end;
  496. procinfo.aktentrycode^.insertlist(@unitinits);
  497. unitinits.done;
  498. end;
  499. { a constructor needs a help procedure }
  500. if (aktprocsym^.definition^.options and poconstructor)<>0 then
  501. begin
  502. if procinfo._class^.isclass then
  503. begin
  504. procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
  505. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  506. newcsymbol('FPC_NEW_CLASS',0))));
  507. concat_external('FPC_NEW_CLASS',EXT_NEAR);
  508. end
  509. else
  510. begin
  511. procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
  512. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  513. newcsymbol('FPC_HELP_CONSTRUCTOR',0))));
  514. concat_external('FPC_HELP_CONSTRUCTOR',EXT_NEAR);
  515. end;
  516. end;
  517. { don't load ESI, does the caller }
  518. { omit stack frame ? }
  519. if procinfo.framepointer=stack_pointer then
  520. begin
  521. CGMessage(cg_d_stackframe_omited);
  522. nostackframe:=true;
  523. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  524. parasize:=0
  525. else
  526. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset;
  527. end
  528. else
  529. begin
  530. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  531. parasize:=0
  532. else
  533. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-8;
  534. nostackframe:=false;
  535. if stackframe<>0 then
  536. begin
  537. if cs_littlesize in aktglobalswitches then
  538. begin
  539. if (cs_check_stack in aktlocalswitches) and
  540. (target_info.target<>target_m68k_linux) then
  541. begin
  542. { If only not in main program, do we setup stack checking }
  543. if (aktprocsym^.definition^.options and poproginit=0) then
  544. Begin
  545. procinfo.aktentrycode^.insert(new(pai68k,
  546. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
  547. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,stackframe,R_D0)));
  548. concat_external('FPC_STACKCHECK',EXT_NEAR);
  549. end;
  550. end;
  551. { to allocate stack space }
  552. { here we allocate space using link signed 16-bit version }
  553. { -ve offset to allocate stack space! }
  554. if (stackframe > -32767) and (stackframe < 32769) then
  555. procinfo.aktentrycode^.insert(new(pai68k,op_reg_const(A_LINK,S_W,R_A6,-stackframe)))
  556. else
  557. CGMessage(cg_e_stacklimit_in_local_routine);
  558. end
  559. else
  560. begin
  561. { Not to complicate the code generator too much, and since some }
  562. { of the systems only support this format, the stackframe cannot }
  563. { exceed 32K in size. }
  564. if (stackframe > -32767) and (stackframe < 32769) then
  565. begin
  566. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_SUB,S_L,stackframe,R_SP)));
  567. { IF only NOT in main program do we check the stack normally }
  568. if (cs_check_stack in aktlocalswitches)
  569. and (aktprocsym^.definition^.options and poproginit=0) then
  570. begin
  571. procinfo.aktentrycode^.insert(new(pai68k,
  572. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
  573. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
  574. stackframe,R_D0)));
  575. concat_external('FPC_STACKCHECK',EXT_NEAR);
  576. end;
  577. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
  578. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
  579. end
  580. else
  581. CGMessage(cg_e_stacklimit_in_local_routine);
  582. end;
  583. end {endif stackframe<>0 }
  584. else
  585. begin
  586. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
  587. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
  588. end;
  589. end;
  590. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  591. generate_interrupt_stackframe_entry;
  592. {proc_names.insert(aktprocsym^.definition^.mangledname);}
  593. if (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  594. ((procinfo._class<>nil) and (procinfo._class^.owner^.
  595. symtabletype=globalsymtable)) then
  596. make_global:=true;
  597. hs:=proc_names.get;
  598. {$IfDef GDB}
  599. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  600. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  601. {$EndIf GDB}
  602. while hs<>'' do
  603. begin
  604. if make_global then
  605. procinfo.aktentrycode^.insert(new(pai_symbol,init_global(hs)))
  606. else
  607. procinfo.aktentrycode^.insert(new(pai_symbol,init(hs)));
  608. {$ifdef GDB}
  609. if (cs_debuginfo in aktmoduleswitches) then
  610. begin
  611. if target_os.use_function_relative_addresses then
  612. list^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  613. { This is not a nice solution to save the name, change it and restore when done }
  614. { not only not nice but also completely wrong !!! (PM) }
  615. { aktprocsym^.setname(hs);
  616. list^.insert(new(pai_stabs,init(aktprocsym^.stabstring))); }
  617. end;
  618. {$endif GDB}
  619. hs:=proc_names.get;
  620. end;
  621. {$ifdef GDB}
  622. if (cs_debuginfo in aktmoduleswitches) then
  623. begin
  624. if target_os.use_function_relative_addresses then
  625. procinfo.aktentrycode^.insert(stab_function_name);
  626. if make_global or ((procinfo.flags and pi_is_global) <> 0) then
  627. aktprocsym^.is_global := True;
  628. aktprocsym^.isstabwritten:=true;
  629. end;
  630. {$endif GDB}
  631. { Alignment required for Motorola }
  632. procinfo.aktentrycode^.insert(new(pai_align,init(2)));
  633. end;
  634. {Generate the exit code for a procedure.}
  635. procedure genexitcode(list : paasmoutput;parasize:longint; nostackframe,inlined:boolean);
  636. var hr:Preference; {This is for function results.}
  637. op:Tasmop;
  638. s:Topsize;
  639. begin
  640. { !!!! insert there automatic destructors }
  641. procinfo.aktexitcode^.insert(new(pai_label,init(aktexitlabel)));
  642. { call the destructor help procedure }
  643. if (aktprocsym^.definition^.options and podestructor)<>0 then
  644. begin
  645. if procinfo._class^.isclass then
  646. begin
  647. procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  648. newcsymbol('FPC_DISPOSE_CLASS',0))));
  649. concat_external('FPC_DISPOSE_CLASS',EXT_NEAR);
  650. end
  651. else
  652. begin
  653. procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  654. newcsymbol('FPC_HELP_DESTRUCTOR',0))));
  655. concat_external('FPC_HELP_DESTRUCTOR',EXT_NEAR);
  656. end;
  657. end;
  658. { call __EXIT for main program }
  659. { ????????? }
  660. if ((aktprocsym^.definition^.options and poproginit)<>0) and
  661. (target_info.target<>target_m68k_PalmOS) then
  662. begin
  663. procinfo.aktexitcode^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('FPC_DO_EXIT',0))));
  664. externals^.concat(new(pai_external,init('FPC_DO_EXIT',EXT_NEAR)));
  665. end;
  666. { handle return value }
  667. if (aktprocsym^.definition^.options and poassembler)=0 then
  668. if (aktprocsym^.definition^.options and poconstructor)=0 then
  669. begin
  670. if procinfo.retdef<>pdef(voiddef) then
  671. begin
  672. if not procinfo.funcret_is_valid then
  673. CGMessage(sym_w_function_result_not_set);
  674. new(hr);
  675. reset_reference(hr^);
  676. hr^.offset:=procinfo.retoffset;
  677. hr^.base:=procinfo.framepointer;
  678. if (procinfo.retdef^.deftype in [orddef,enumdef]) then
  679. begin
  680. case procinfo.retdef^.size of
  681. 4 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
  682. 2 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,hr,R_D0)));
  683. 1 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,hr,R_D0)));
  684. end;
  685. end
  686. else
  687. if (procinfo.retdef^.deftype in [pointerdef,enumdef,procvardef]) or
  688. ((procinfo.retdef^.deftype=setdef) and
  689. (psetdef(procinfo.retdef)^.settype=smallset)) then
  690. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)))
  691. else
  692. if (procinfo.retdef^.deftype=floatdef) then
  693. begin
  694. if pfloatdef(procinfo.retdef)^.typ=f32bit then
  695. begin
  696. { Isnt this missing ? }
  697. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
  698. end
  699. else
  700. begin
  701. { how the return value is handled }
  702. { if single value, then return in d0, otherwise return in }
  703. { TRUE FPU register (does not apply in emulation mode) }
  704. if (pfloatdef(procinfo.retdef)^.typ = s32real) then
  705. begin
  706. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
  707. S_L,hr,R_D0)))
  708. end
  709. else
  710. begin
  711. if cs_fp_emulation in aktmoduleswitches then
  712. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
  713. S_L,hr,R_D0)))
  714. else
  715. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_FMOVE,
  716. getfloatsize(pfloatdef(procinfo.retdef)^.typ),hr,R_FP0)));
  717. end;
  718. end;
  719. end
  720. else
  721. dispose(hr);
  722. end
  723. end
  724. else
  725. begin
  726. { successful constructor deletes the zero flag }
  727. { and returns self in accumulator }
  728. procinfo.aktexitcode^.concat(new(pai_label,init(quickexitlabel)));
  729. { eax must be set to zero if the allocation failed !!! }
  730. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_D0)));
  731. { faster then OR on mc68000/mc68020 }
  732. procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_TST,S_L,R_D0)));
  733. end;
  734. procinfo.aktexitcode^.concat(new(pai_label,init(aktexit2label)));
  735. if not(nostackframe) then
  736. procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_UNLK,S_NO,R_A6)));
  737. { at last, the return is generated }
  738. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  739. generate_interrupt_stackframe_exit
  740. else
  741. if (parasize=0) or ((aktprocsym^.definition^.options and poclearstack)<>0)
  742. then
  743. {Routines with the poclearstack flag set use only a ret.}
  744. { also routines with parasize=0 }
  745. procinfo.aktexitcode^.concat(new(pai68k,op_none(A_RTS,S_NO)))
  746. else
  747. { return with immediate size possible here }
  748. { signed! }
  749. if (aktoptprocessor = MC68020) and (parasize < $7FFF) then
  750. procinfo.aktexitcode^.concat(new(pai68k,op_const(
  751. A_RTD,S_NO,parasize)))
  752. { manually restore the stack }
  753. else
  754. begin
  755. { We must pull the PC Counter from the stack, before }
  756. { restoring the stack pointer, otherwise the PC would }
  757. { point to nowhere! }
  758. { save the PC counter (pop it from the stack) }
  759. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
  760. A_MOVE,S_L,R_SPPULL,R_A0)));
  761. { can we do a quick addition ... }
  762. if (parasize > 0) and (parasize < 9) then
  763. procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
  764. A_ADD,S_L,parasize,R_SP)))
  765. else { nope ... }
  766. procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
  767. A_ADD,S_L,parasize,R_SP)));
  768. { endif }
  769. { restore the PC counter (push it on the stack) }
  770. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
  771. A_MOVE,S_L,R_A0,R_SPPUSH)));
  772. procinfo.aktexitcode^.concat(new(pai68k,op_none(
  773. A_RTS,S_NO)))
  774. end;
  775. {$ifdef GDB}
  776. if cs_debuginfo in aktmoduleswitches then
  777. begin
  778. aktprocsym^.concatstabto(procinfo.aktexitcode);
  779. if assigned(procinfo._class) then
  780. procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
  781. '"$t:v'+procinfo._class^.numberstring+'",'+
  782. tostr(N_PSYM)+',0,0,'+tostr(procinfo.esi_offset)))));
  783. if (porddef(aktprocsym^.definition^.retdef) <> voiddef) then
  784. procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
  785. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  786. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))));
  787. procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  788. +aktprocsym^.definition^.mangledname))));
  789. procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('224,0,0,'
  790. +lab2str(aktexit2label)))));
  791. end;
  792. {$endif GDB}
  793. end;
  794. { USES REGISTERS R_A0 AND R_A1 }
  795. { maximum size of copy is 65535 bytes }
  796. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
  797. var
  798. ecxpushed : boolean;
  799. helpsize : longint;
  800. i : byte;
  801. reg8,reg32 : tregister;
  802. swap : boolean;
  803. hregister : tregister;
  804. iregister : tregister;
  805. jregister : tregister;
  806. hp1 : treference;
  807. hp2 : treference;
  808. hl : plabel;
  809. hl2: plabel;
  810. begin
  811. { this should never occur }
  812. if size > 65535 then
  813. internalerror(0);
  814. hregister := getregister32;
  815. if delsource then
  816. del_reference(source);
  817. { from 12 bytes movs is being used }
  818. if (size<=8) or (not(cs_littlesize in aktglobalswitches) and (size<=12)) then
  819. begin
  820. helpsize:=size div 4;
  821. { move a dword x times }
  822. for i:=1 to helpsize do
  823. begin
  824. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(source),hregister)));
  825. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,hregister,newreference(dest))));
  826. inc(source.offset,4);
  827. inc(dest.offset,4);
  828. dec(size,4);
  829. end;
  830. { move a word }
  831. if size>1 then
  832. begin
  833. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,newreference(source),hregister)));
  834. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_W,hregister,newreference(dest))));
  835. inc(source.offset,2);
  836. inc(dest.offset,2);
  837. dec(size,2);
  838. end;
  839. { move a single byte }
  840. if size>0 then
  841. begin
  842. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,newreference(source),hregister)));
  843. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,hregister,newreference(dest))));
  844. end
  845. end
  846. else
  847. begin
  848. if (usableaddress > 1) then
  849. begin
  850. iregister := getaddressreg;
  851. jregister := getaddressreg;
  852. end
  853. else
  854. if (usableaddress = 1) then
  855. begin
  856. iregister := getaddressreg;
  857. jregister := R_A1;
  858. end
  859. else
  860. begin
  861. iregister := R_A0;
  862. jregister := R_A1;
  863. end;
  864. { reference for move (An)+,(An)+ }
  865. reset_reference(hp1);
  866. hp1.base := iregister; { source register }
  867. hp1.direction := dir_inc;
  868. reset_reference(hp2);
  869. hp2.base := jregister;
  870. hp2.direction := dir_inc;
  871. { iregister = source }
  872. { jregister = destination }
  873. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(source),iregister)));
  874. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dest),jregister)));
  875. { double word move only on 68020+ machines }
  876. { because of possible alignment problems }
  877. { use fast loop mode }
  878. if (aktoptprocessor=MC68020) then
  879. begin
  880. helpsize := size - size mod 4;
  881. size := size mod 4;
  882. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize div 4,hregister)));
  883. getlabel(hl2);
  884. emitl(A_BRA,hl2);
  885. getlabel(hl);
  886. emitl(A_LABEL,hl);
  887. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_L,newreference(hp1),newreference(hp2))));
  888. emitl(A_LABEL,hl2);
  889. exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
  890. if size > 1 then
  891. begin
  892. dec(size,2);
  893. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_W,newreference(hp1), newreference(hp2))));
  894. end;
  895. if size = 1 then
  896. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1), newreference(hp2))));
  897. end
  898. else
  899. begin
  900. { Fast 68010 loop mode with no possible alignment problems }
  901. helpsize := size;
  902. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize,hregister)));
  903. getlabel(hl2);
  904. emitl(A_BRA,hl2);
  905. getlabel(hl);
  906. emitl(A_LABEL,hl);
  907. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1),newreference(hp2))));
  908. emitl(A_LABEL,hl2);
  909. exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
  910. end;
  911. { restore the registers that we have just used olny if they are used! }
  912. if jregister = R_A1 then
  913. hp2.base := R_NO;
  914. if iregister = R_A0 then
  915. hp1.base := R_NO;
  916. del_reference(hp1);
  917. del_reference(hp2);
  918. end;
  919. { loading SELF-reference again }
  920. maybe_loada5;
  921. if delsource then
  922. ungetiftemp(source);
  923. ungetregister32(hregister);
  924. end;
  925. procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
  926. destreg:Tregister;delloc:boolean);
  927. {A lot smaller and less bug sensitive than the original unfolded loads.}
  928. var tai:pai68k;
  929. r:Preference;
  930. begin
  931. case location.loc of
  932. LOC_REGISTER,LOC_CREGISTER:
  933. begin
  934. case orddef^.typ of
  935. u8bit: begin
  936. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
  937. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
  938. end;
  939. s8bit: begin
  940. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
  941. if (aktoptprocessor <> MC68020) then
  942. begin
  943. { byte to word }
  944. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
  945. { word to long }
  946. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  947. end
  948. else { 68020+ and later only }
  949. exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
  950. end;
  951. u16bit: begin
  952. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
  953. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FFFF,destreg)));
  954. end;
  955. s16bit: begin
  956. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
  957. { word to long }
  958. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  959. end;
  960. u32bit:
  961. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
  962. s32bit:
  963. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
  964. end;
  965. if delloc then
  966. ungetregister(location.register);
  967. end;
  968. LOC_REFERENCE:
  969. begin
  970. r:=newreference(location.reference);
  971. case orddef^.typ of
  972. u8bit: begin
  973. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
  974. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
  975. end;
  976. s8bit: begin
  977. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
  978. if (aktoptprocessor <> MC68020) then
  979. begin
  980. { byte to word }
  981. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
  982. { word to long }
  983. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  984. end
  985. else { 68020+ and later only }
  986. exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
  987. end;
  988. u16bit: begin
  989. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
  990. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$ffff,destreg)));
  991. end;
  992. s16bit: begin
  993. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
  994. { word to long }
  995. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  996. end;
  997. u32bit:
  998. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
  999. s32bit:
  1000. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
  1001. end;
  1002. if delloc then
  1003. del_reference(location.reference);
  1004. end
  1005. else
  1006. internalerror(6);
  1007. end;
  1008. end;
  1009. { if necessary A5 is reloaded after a call}
  1010. procedure maybe_loada5;
  1011. var
  1012. hp : preference;
  1013. p : pprocinfo;
  1014. i : longint;
  1015. begin
  1016. if assigned(procinfo._class) then
  1017. begin
  1018. if lexlevel>2 then
  1019. begin
  1020. new(hp);
  1021. reset_reference(hp^);
  1022. hp^.offset:=procinfo.framepointer_offset;
  1023. hp^.base:=procinfo.framepointer;
  1024. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1025. p:=procinfo.parent;
  1026. for i:=3 to lexlevel-1 do
  1027. begin
  1028. new(hp);
  1029. reset_reference(hp^);
  1030. hp^.offset:=p^.framepointer_offset;
  1031. hp^.base:=R_A5;
  1032. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1033. p:=p^.parent;
  1034. end;
  1035. new(hp);
  1036. reset_reference(hp^);
  1037. hp^.offset:=p^.ESI_offset;
  1038. hp^.base:=R_A5;
  1039. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1040. end
  1041. else
  1042. begin
  1043. new(hp);
  1044. reset_reference(hp^);
  1045. hp^.offset:=procinfo.ESI_offset;
  1046. hp^.base:=procinfo.framepointer;
  1047. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1048. end;
  1049. end;
  1050. end;
  1051. (***********************************************************************)
  1052. (* PROCEDURE FLOATLOAD *)
  1053. (* Description: This routine is to be called each time a location *)
  1054. (* must be set to LOC_FPU and a value loaded into a FPU register. *)
  1055. (* *)
  1056. (* Remark: The routine sets up the register field of LOC_FPU correctly*)
  1057. (***********************************************************************)
  1058. procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
  1059. var
  1060. op : tasmop;
  1061. s : topsize;
  1062. begin
  1063. { no emulation }
  1064. case t of
  1065. s32real : s := S_FS;
  1066. s64real : s := S_FL;
  1067. s80real : s := S_FX;
  1068. else
  1069. begin
  1070. CGMessage(cg_f_unknown_float_type);
  1071. end;
  1072. end; { end case }
  1073. location.loc := LOC_FPU;
  1074. if not ((cs_fp_emulation) in aktmoduleswitches) then
  1075. begin
  1076. location.fpureg := getfloatreg;
  1077. exprasmlist^.concat(new(pai68k,op_ref_reg(A_FMOVE,s,newreference(ref),location.fpureg)))
  1078. end
  1079. else
  1080. { handle emulation }
  1081. begin
  1082. if t = s32real then
  1083. begin
  1084. location.fpureg := getregister32;
  1085. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),location.fpureg)))
  1086. end
  1087. else
  1088. { other floating types are not supported in emulation mode }
  1089. CGMessage(sym_e_type_id_not_defined);
  1090. end;
  1091. end;
  1092. { procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1093. begin
  1094. case t of
  1095. s32real : begin
  1096. op:=A_FSTP;
  1097. s:=S_FS;
  1098. end;
  1099. s64real : begin
  1100. op:=A_FSTP;
  1101. s:=S_FL;
  1102. end;
  1103. s80real : begin
  1104. op:=A_FSTP;
  1105. s:=S_FX;
  1106. end;
  1107. s64bit : begin
  1108. op:=A_FISTP;
  1109. s:=S_IQ;
  1110. end;
  1111. else internalerror(17);
  1112. end;
  1113. end; }
  1114. { stores an FPU value to memory }
  1115. { location:tlocation used to free up FPU register }
  1116. { ref: destination of storage }
  1117. procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
  1118. var
  1119. op : tasmop;
  1120. s : topsize;
  1121. begin
  1122. if location.loc <> LOC_FPU then
  1123. InternalError(34);
  1124. { no emulation }
  1125. case t of
  1126. s32real : s := S_FS;
  1127. s64real : s := S_FL;
  1128. s80real : s := S_FX;
  1129. else
  1130. begin
  1131. CGMessage(cg_f_unknown_float_type);
  1132. end;
  1133. end; { end case }
  1134. if not ((cs_fp_emulation) in aktmoduleswitches) then
  1135. begin
  1136. { This permits the mixing of emulation and non-emulation routines }
  1137. { only possible for REAL = SINGLE value_str }
  1138. if not (location.fpureg in [R_FP0..R_FP7]) then
  1139. Begin
  1140. if s = S_FS then
  1141. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))))
  1142. else
  1143. internalerror(255);
  1144. end
  1145. else
  1146. exprasmlist^.concat(new(pai68k,op_reg_ref(A_FMOVE,s,location.fpureg,newreference(ref))));
  1147. ungetregister(location.fpureg);
  1148. end
  1149. else
  1150. { handle emulation }
  1151. begin
  1152. if t = s32real then
  1153. begin
  1154. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))));
  1155. ungetregister32(location.fpureg);
  1156. end
  1157. else
  1158. { other floating types are not supported in emulation mode }
  1159. CGMessage(sym_e_type_id_not_defined);
  1160. end;
  1161. location.fpureg:=R_NO; { no register in LOC_FPU now }
  1162. end;
  1163. procedure firstcomplex(p : ptree);
  1164. var
  1165. hp : ptree;
  1166. begin
  1167. { always calculate boolean AND and OR from left to right }
  1168. if ((p^.treetype=orn) or (p^.treetype=andn)) and
  1169. (p^.left^.resulttype^.deftype=orddef) and
  1170. (porddef(p^.left^.resulttype)^.typ=bool8bit) then
  1171. p^.swaped:=false
  1172. else if (p^.left^.registers32<p^.right^.registers32)
  1173. { the following check is appropriate, because all }
  1174. { 4 registers are rarely used and it is thereby }
  1175. { achieved that the extra code is being dropped }
  1176. { by exchanging not commutative operators }
  1177. and (p^.right^.registers32<=4) then
  1178. begin
  1179. hp:=p^.left;
  1180. p^.left:=p^.right;
  1181. p^.right:=hp;
  1182. p^.swaped:=true;
  1183. end
  1184. else p^.swaped:=false;
  1185. end;
  1186. {$ifdef test_dest_loc}
  1187. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  1188. begin
  1189. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  1190. begin
  1191. emit_reg_reg(A_MOVE,s,reg,dest_loc.register);
  1192. p^.location:=dest_loc;
  1193. in_dest_loc:=true;
  1194. end
  1195. else
  1196. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  1197. begin
  1198. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,s,reg,newreference(dest_loc.reference))));
  1199. p^.location:=dest_loc;
  1200. in_dest_loc:=true;
  1201. end
  1202. else
  1203. internalerror(20080);
  1204. end;
  1205. {$endif test_dest_loc}
  1206. end.
  1207. {
  1208. $Log$
  1209. Revision 1.22 1998-10-13 16:50:12 pierre
  1210. * undid some changes of Peter that made the compiler wrong
  1211. for m68k (I had to reinsert some ifdefs)
  1212. * removed several memory leaks under m68k
  1213. * removed the meory leaks for assembler readers
  1214. * cross compiling shoud work again better
  1215. ( crosscompiling sysamiga works
  1216. but as68k still complain about some code !)
  1217. Revision 1.21 1998/10/13 13:10:12 peter
  1218. * new style for m68k/i386 infos and enums
  1219. Revision 1.20 1998/10/13 08:19:29 pierre
  1220. + source_os is now set correctly for cross-processor compilers
  1221. (tos contains all target_infos and
  1222. we use CPU86 and CPU68 conditionnals to
  1223. get the source operating system
  1224. this only works if you do not undefine
  1225. the source target !!)
  1226. * several cg68k memory leaks fixed
  1227. + started to change the code so that it should be possible to have
  1228. a complete compiler (both for m68k and i386 !!)
  1229. Revision 1.19 1998/10/08 13:48:40 peter
  1230. * fixed memory leaks for do nothing source
  1231. * fixed unit interdependency
  1232. Revision 1.18 1998/09/28 16:57:17 pierre
  1233. * changed all length(p^.value_str^) into str_length(p)
  1234. to get it work with and without ansistrings
  1235. * changed sourcefiles field of tmodule to a pointer
  1236. Revision 1.17 1998/09/17 09:42:30 peter
  1237. + pass_2 for cg386
  1238. * Message() -> CGMessage() for pass_1/pass_2
  1239. Revision 1.16 1998/09/14 10:44:04 peter
  1240. * all internal RTL functions start with FPC_
  1241. Revision 1.15 1998/09/07 18:46:00 peter
  1242. * update smartlinking, uses getdatalabel
  1243. * renamed ptree.value vars to value_str,value_real,value_set
  1244. Revision 1.14 1998/09/04 08:41:50 peter
  1245. * updated some error CGMessages
  1246. Revision 1.13 1998/09/01 12:48:02 peter
  1247. * use pdef^.size instead of orddef^.typ
  1248. Revision 1.12 1998/09/01 09:07:09 peter
  1249. * m68k fixes, splitted cg68k like cgi386
  1250. Revision 1.11 1998/08/31 12:26:24 peter
  1251. * m68k and palmos updates from surebugfixes
  1252. Revision 1.10 1998/08/21 14:08:41 pierre
  1253. + TEST_FUNCRET now default (old code removed)
  1254. works also for m68k (at least compiles)
  1255. Revision 1.9 1998/08/17 10:10:04 peter
  1256. - removed OLDPPU
  1257. Revision 1.8 1998/08/10 14:43:16 peter
  1258. * string type st_ fixed
  1259. Revision 1.7 1998/07/10 10:51:01 peter
  1260. * m68k updates
  1261. Revision 1.6 1998/06/08 13:13:39 pierre
  1262. + temporary variables now in temp_gen.pas unit
  1263. because it is processor independent
  1264. * mppc68k.bat modified to undefine i386 and support_mmx
  1265. (which are defaults for i386)
  1266. Revision 1.5 1998/06/04 23:51:36 peter
  1267. * m68k compiles
  1268. + .def file creation moved to gendef.pas so it could also be used
  1269. for win32
  1270. Revision 1.4 1998/05/07 00:17:00 peter
  1271. * smartlinking for sets
  1272. + consts labels are now concated/generated in hcodegen
  1273. * moved some cpu code to cga and some none cpu depended code from cga
  1274. to tree and hcodegen and cleanup of hcodegen
  1275. * assembling .. output reduced for smartlinking ;)
  1276. Revision 1.3 1998/04/29 10:33:46 pierre
  1277. + added some code for ansistring (not complete nor working yet)
  1278. * corrected operator overloading
  1279. * corrected nasm output
  1280. + started inline procedures
  1281. + added starstarn : use ** for exponentiation (^ gave problems)
  1282. + started UseTokenInfo cond to get accurate positions
  1283. }