cga68k.pas 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  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. oldaktprocname : string;
  461. stab_function_name:Pai_stab_function_name;
  462. {$endif GDB}
  463. begin
  464. if (aktprocsym^.definition^.options and poproginit<>0) then
  465. begin
  466. {Init the stack checking.}
  467. if (cs_check_stack in aktlocalswitches) and
  468. (target_info.target=target_linux_m68k) then
  469. begin
  470. procinfo.aktentrycode^.insert(new(pai68k,
  471. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_INIT_STACK_CHECK',0))));
  472. end
  473. else
  474. { The main program has already allocated its stack - so we simply compare }
  475. { with a value of ZERO, and the comparison will directly check! }
  476. if (cs_check_stack in aktlocalswitches) then
  477. begin
  478. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  479. newcsymbol('FPC_STACKCHECK',0))));
  480. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
  481. 0,R_D0)));
  482. concat_external('FPC_STACKCHECK',EXT_NEAR);
  483. end;
  484. unitinits.init;
  485. {Call the unit init procedures.}
  486. hp:=pused_unit(usedunits.first);
  487. while assigned(hp) do
  488. begin
  489. { call the unit init code and make it external }
  490. if (hp^.u^.flags and uf_init)<>0 then
  491. begin
  492. unitinits.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('INIT$$'+hp^.u^.modulename^,0))));
  493. concat_external('INIT$$'+hp^.u^.modulename^,EXT_NEAR);
  494. end;
  495. hp:=pused_unit(hp^.next);
  496. end;
  497. procinfo.aktentrycode^.insertlist(@unitinits);
  498. unitinits.done;
  499. end;
  500. { a constructor needs a help procedure }
  501. if (aktprocsym^.definition^.options and poconstructor)<>0 then
  502. begin
  503. if procinfo._class^.isclass then
  504. begin
  505. procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
  506. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  507. newcsymbol('FPC_NEW_CLASS',0))));
  508. concat_external('FPC_NEW_CLASS',EXT_NEAR);
  509. end
  510. else
  511. begin
  512. procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
  513. procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  514. newcsymbol('FPC_HELP_CONSTRUCTOR',0))));
  515. concat_external('FPC_HELP_CONSTRUCTOR',EXT_NEAR);
  516. end;
  517. end;
  518. { don't load ESI, does the caller }
  519. { omit stack frame ? }
  520. if procinfo.framepointer=stack_pointer then
  521. begin
  522. CGMessage(cg_d_stackframe_omited);
  523. nostackframe:=true;
  524. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  525. parasize:=0
  526. else
  527. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset;
  528. end
  529. else
  530. begin
  531. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  532. parasize:=0
  533. else
  534. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-8;
  535. nostackframe:=false;
  536. if stackframe<>0 then
  537. begin
  538. if cs_littlesize in aktglobalswitches then
  539. begin
  540. if (cs_check_stack in aktlocalswitches) and
  541. (target_info.target<>target_linux_m68k) then
  542. begin
  543. { If only not in main program, do we setup stack checking }
  544. if (aktprocsym^.definition^.options and poproginit=0) then
  545. Begin
  546. procinfo.aktentrycode^.insert(new(pai68k,
  547. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
  548. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,stackframe,R_D0)));
  549. concat_external('FPC_STACKCHECK',EXT_NEAR);
  550. end;
  551. end;
  552. { to allocate stack space }
  553. { here we allocate space using link signed 16-bit version }
  554. { -ve offset to allocate stack space! }
  555. if (stackframe > -32767) and (stackframe < 32769) then
  556. procinfo.aktentrycode^.insert(new(pai68k,op_reg_const(A_LINK,S_W,R_A6,-stackframe)))
  557. else
  558. CGMessage(cg_e_stacklimit_in_local_routine);
  559. end
  560. else
  561. begin
  562. { Not to complicate the code generator too much, and since some }
  563. { of the systems only support this format, the stackframe cannot }
  564. { exceed 32K in size. }
  565. if (stackframe > -32767) and (stackframe < 32769) then
  566. begin
  567. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_SUB,S_L,stackframe,R_SP)));
  568. { IF only NOT in main program do we check the stack normally }
  569. if (cs_check_stack in aktlocalswitches)
  570. and (aktprocsym^.definition^.options and poproginit=0) then
  571. begin
  572. procinfo.aktentrycode^.insert(new(pai68k,
  573. op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
  574. procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
  575. stackframe,R_D0)));
  576. concat_external('FPC_STACKCHECK',EXT_NEAR);
  577. end;
  578. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
  579. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
  580. end
  581. else
  582. CGMessage(cg_e_stacklimit_in_local_routine);
  583. end;
  584. end {endif stackframe<>0 }
  585. else
  586. begin
  587. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
  588. procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
  589. end;
  590. end;
  591. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  592. generate_interrupt_stackframe_entry;
  593. {proc_names.insert(aktprocsym^.definition^.mangledname);}
  594. if (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  595. ((procinfo._class<>nil) and (procinfo._class^.owner^.
  596. symtabletype=globalsymtable)) then
  597. make_global:=true;
  598. hs:=proc_names.get;
  599. {$IfDef GDB}
  600. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  601. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  602. oldaktprocname:=aktprocsym^.name;
  603. {$EndIf GDB}
  604. while hs<>'' do
  605. begin
  606. if make_global then
  607. procinfo.aktentrycode^.insert(new(pai_symbol,init_global(hs)))
  608. else
  609. procinfo.aktentrycode^.insert(new(pai_symbol,init(hs)));
  610. {$ifdef GDB}
  611. if (cs_debuginfo in aktmoduleswitches) and
  612. target_os.use_function_relative_addresses then
  613. begin
  614. procinfo.aktentrycode^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  615. { This is not a nice solution to save the name, change it and restore when done }
  616. aktprocsym^.setname(hs);
  617. procinfo.aktentrycode^.insert(new(pai_stabs,init(aktprocsym^.stabstring)));
  618. end;
  619. {$endif GDB}
  620. hs:=proc_names.get;
  621. end;
  622. {$ifdef GDB}
  623. aktprocsym^.setname(oldaktprocname);
  624. if (cs_debuginfo in aktmoduleswitches) then
  625. begin
  626. if target_os.use_function_relative_addresses then
  627. procinfo.aktentrycode^.insert(stab_function_name);
  628. if make_global or ((procinfo.flags and pi_is_global) <> 0) then
  629. aktprocsym^.is_global := True;
  630. aktprocsym^.isstabwritten:=true;
  631. end;
  632. {$endif GDB}
  633. { Alignment required for Motorola }
  634. procinfo.aktentrycode^.insert(new(pai_align,init(2)));
  635. end;
  636. {Generate the exit code for a procedure.}
  637. procedure genexitcode(list : paasmoutput;parasize:longint; nostackframe,inlined:boolean);
  638. var hr:Preference; {This is for function results.}
  639. op:Tasmop;
  640. s:Topsize;
  641. begin
  642. { !!!! insert there automatic destructors }
  643. procinfo.aktexitcode^.insert(new(pai_label,init(aktexitlabel)));
  644. { call the destructor help procedure }
  645. if (aktprocsym^.definition^.options and podestructor)<>0 then
  646. begin
  647. if procinfo._class^.isclass then
  648. begin
  649. procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  650. newcsymbol('FPC_DISPOSE_CLASS',0))));
  651. concat_external('FPC_DISPOSE_CLASS',EXT_NEAR);
  652. end
  653. else
  654. begin
  655. procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
  656. newcsymbol('FPC_HELP_DESTRUCTOR',0))));
  657. concat_external('FPC_HELP_DESTRUCTOR',EXT_NEAR);
  658. end;
  659. end;
  660. { call __EXIT for main program }
  661. { ????????? }
  662. if ((aktprocsym^.definition^.options and poproginit)<>0) and
  663. (target_info.target<>target_PalmOS) then
  664. begin
  665. procinfo.aktexitcode^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('FPC_DO_EXIT',0))));
  666. externals^.concat(new(pai_external,init('FPC_DO_EXIT',EXT_NEAR)));
  667. end;
  668. { handle return value }
  669. if (aktprocsym^.definition^.options and poassembler)=0 then
  670. if (aktprocsym^.definition^.options and poconstructor)=0 then
  671. begin
  672. if procinfo.retdef<>pdef(voiddef) then
  673. begin
  674. if not procinfo.funcret_is_valid then
  675. CGMessage(sym_w_function_result_not_set);
  676. new(hr);
  677. reset_reference(hr^);
  678. hr^.offset:=procinfo.retoffset;
  679. hr^.base:=procinfo.framepointer;
  680. if (procinfo.retdef^.deftype in [orddef,enumdef]) then
  681. begin
  682. case procinfo.retdef^.size of
  683. 4 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
  684. 2 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,hr,R_D0)));
  685. 1 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,hr,R_D0)));
  686. end;
  687. end
  688. else
  689. if (procinfo.retdef^.deftype in [pointerdef,enumdef,procvardef]) or
  690. ((procinfo.retdef^.deftype=setdef) and
  691. (psetdef(procinfo.retdef)^.settype=smallset)) then
  692. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)))
  693. else
  694. if (procinfo.retdef^.deftype=floatdef) then
  695. begin
  696. if pfloatdef(procinfo.retdef)^.typ=f32bit then
  697. begin
  698. { Isnt this missing ? }
  699. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
  700. end
  701. else
  702. begin
  703. { how the return value is handled }
  704. { if single value, then return in d0, otherwise return in }
  705. { TRUE FPU register (does not apply in emulation mode) }
  706. if (pfloatdef(procinfo.retdef)^.typ = s32real) then
  707. begin
  708. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
  709. S_L,hr,R_D0)))
  710. end
  711. else
  712. begin
  713. if cs_fp_emulation in aktmoduleswitches then
  714. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
  715. S_L,hr,R_D0)))
  716. else
  717. procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_FMOVE,
  718. getfloatsize(pfloatdef(procinfo.retdef)^.typ),hr,R_FP0)));
  719. end;
  720. end;
  721. end
  722. else
  723. dispose(hr);
  724. end
  725. end
  726. else
  727. begin
  728. { successful constructor deletes the zero flag }
  729. { and returns self in accumulator }
  730. procinfo.aktexitcode^.concat(new(pai_label,init(quickexitlabel)));
  731. { eax must be set to zero if the allocation failed !!! }
  732. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_D0)));
  733. { faster then OR on mc68000/mc68020 }
  734. procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_TST,S_L,R_D0)));
  735. end;
  736. procinfo.aktexitcode^.concat(new(pai_label,init(aktexit2label)));
  737. if not(nostackframe) then
  738. procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_UNLK,S_NO,R_A6)));
  739. { at last, the return is generated }
  740. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  741. generate_interrupt_stackframe_exit
  742. else
  743. if (parasize=0) or ((aktprocsym^.definition^.options and poclearstack)<>0)
  744. then
  745. {Routines with the poclearstack flag set use only a ret.}
  746. { also routines with parasize=0 }
  747. procinfo.aktexitcode^.concat(new(pai68k,op_none(A_RTS,S_NO)))
  748. else
  749. { return with immediate size possible here }
  750. { signed! }
  751. if (aktoptprocessor = MC68020) and (parasize < $7FFF) then
  752. procinfo.aktexitcode^.concat(new(pai68k,op_const(
  753. A_RTD,S_NO,parasize)))
  754. { manually restore the stack }
  755. else
  756. begin
  757. { We must pull the PC Counter from the stack, before }
  758. { restoring the stack pointer, otherwise the PC would }
  759. { point to nowhere! }
  760. { save the PC counter (pop it from the stack) }
  761. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
  762. A_MOVE,S_L,R_SPPULL,R_A0)));
  763. { can we do a quick addition ... }
  764. if (parasize > 0) and (parasize < 9) then
  765. procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
  766. A_ADD,S_L,parasize,R_SP)))
  767. else { nope ... }
  768. procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
  769. A_ADD,S_L,parasize,R_SP)));
  770. { endif }
  771. { restore the PC counter (push it on the stack) }
  772. procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
  773. A_MOVE,S_L,R_A0,R_SPPUSH)));
  774. procinfo.aktexitcode^.concat(new(pai68k,op_none(
  775. A_RTS,S_NO)))
  776. end;
  777. {$ifdef GDB}
  778. if cs_debuginfo in aktmoduleswitches then
  779. begin
  780. aktprocsym^.concatstabto(procinfo.aktexitcode);
  781. if assigned(procinfo._class) then
  782. procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
  783. '"$t:v'+procinfo._class^.numberstring+'",'+
  784. tostr(N_PSYM)+',0,0,'+tostr(procinfo.esi_offset)))));
  785. if (porddef(aktprocsym^.definition^.retdef) <> voiddef) then
  786. procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
  787. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  788. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))));
  789. procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  790. +aktprocsym^.definition^.mangledname))));
  791. procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('224,0,0,'
  792. +lab2str(aktexit2label)))));
  793. end;
  794. {$endif GDB}
  795. end;
  796. { USES REGISTERS R_A0 AND R_A1 }
  797. { maximum size of copy is 65535 bytes }
  798. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
  799. var
  800. ecxpushed : boolean;
  801. helpsize : longint;
  802. i : byte;
  803. reg8,reg32 : tregister;
  804. swap : boolean;
  805. hregister : tregister;
  806. iregister : tregister;
  807. jregister : tregister;
  808. hp1 : treference;
  809. hp2 : treference;
  810. hl : plabel;
  811. hl2: plabel;
  812. begin
  813. { this should never occur }
  814. if size > 65535 then
  815. internalerror(0);
  816. hregister := getregister32;
  817. if delsource then
  818. del_reference(source);
  819. { from 12 bytes movs is being used }
  820. if (size<=8) or (not(cs_littlesize in aktglobalswitches) and (size<=12)) then
  821. begin
  822. helpsize:=size div 4;
  823. { move a dword x times }
  824. for i:=1 to helpsize do
  825. begin
  826. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(source),hregister)));
  827. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,hregister,newreference(dest))));
  828. inc(source.offset,4);
  829. inc(dest.offset,4);
  830. dec(size,4);
  831. end;
  832. { move a word }
  833. if size>1 then
  834. begin
  835. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,newreference(source),hregister)));
  836. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_W,hregister,newreference(dest))));
  837. inc(source.offset,2);
  838. inc(dest.offset,2);
  839. dec(size,2);
  840. end;
  841. { move a single byte }
  842. if size>0 then
  843. begin
  844. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,newreference(source),hregister)));
  845. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,hregister,newreference(dest))));
  846. end
  847. end
  848. else
  849. begin
  850. if (usableaddress > 1) then
  851. begin
  852. iregister := getaddressreg;
  853. jregister := getaddressreg;
  854. end
  855. else
  856. if (usableaddress = 1) then
  857. begin
  858. iregister := getaddressreg;
  859. jregister := R_A1;
  860. end
  861. else
  862. begin
  863. iregister := R_A0;
  864. jregister := R_A1;
  865. end;
  866. { reference for move (An)+,(An)+ }
  867. reset_reference(hp1);
  868. hp1.base := iregister; { source register }
  869. hp1.direction := dir_inc;
  870. reset_reference(hp2);
  871. hp2.base := jregister;
  872. hp2.direction := dir_inc;
  873. { iregister = source }
  874. { jregister = destination }
  875. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(source),iregister)));
  876. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dest),jregister)));
  877. { double word move only on 68020+ machines }
  878. { because of possible alignment problems }
  879. { use fast loop mode }
  880. if (aktoptprocessor=MC68020) then
  881. begin
  882. helpsize := size - size mod 4;
  883. size := size mod 4;
  884. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize div 4,hregister)));
  885. getlabel(hl2);
  886. emitl(A_BRA,hl2);
  887. getlabel(hl);
  888. emitl(A_LABEL,hl);
  889. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_L,newreference(hp1),newreference(hp2))));
  890. emitl(A_LABEL,hl2);
  891. exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
  892. if size > 1 then
  893. begin
  894. dec(size,2);
  895. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_W,newreference(hp1), newreference(hp2))));
  896. end;
  897. if size = 1 then
  898. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1), newreference(hp2))));
  899. end
  900. else
  901. begin
  902. { Fast 68010 loop mode with no possible alignment problems }
  903. helpsize := size;
  904. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize,hregister)));
  905. getlabel(hl2);
  906. emitl(A_BRA,hl2);
  907. getlabel(hl);
  908. emitl(A_LABEL,hl);
  909. exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1),newreference(hp2))));
  910. emitl(A_LABEL,hl2);
  911. exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
  912. end;
  913. { restore the registers that we have just used olny if they are used! }
  914. if jregister = R_A1 then
  915. hp2.base := R_NO;
  916. if iregister = R_A0 then
  917. hp1.base := R_NO;
  918. del_reference(hp1);
  919. del_reference(hp2);
  920. end;
  921. { loading SELF-reference again }
  922. maybe_loada5;
  923. if delsource then
  924. ungetiftemp(source);
  925. ungetregister32(hregister);
  926. end;
  927. procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
  928. destreg:Tregister;delloc:boolean);
  929. {A lot smaller and less bug sensitive than the original unfolded loads.}
  930. var tai:pai68k;
  931. r:Preference;
  932. begin
  933. case location.loc of
  934. LOC_REGISTER,LOC_CREGISTER:
  935. begin
  936. case orddef^.typ of
  937. u8bit: begin
  938. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
  939. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
  940. end;
  941. s8bit: begin
  942. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
  943. if (aktoptprocessor <> MC68020) then
  944. begin
  945. { byte to word }
  946. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
  947. { word to long }
  948. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  949. end
  950. else { 68020+ and later only }
  951. exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
  952. end;
  953. u16bit: begin
  954. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
  955. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FFFF,destreg)));
  956. end;
  957. s16bit: begin
  958. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
  959. { word to long }
  960. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  961. end;
  962. u32bit:
  963. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
  964. s32bit:
  965. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
  966. end;
  967. if delloc then
  968. ungetregister(location.register);
  969. end;
  970. LOC_REFERENCE:
  971. begin
  972. r:=newreference(location.reference);
  973. case orddef^.typ of
  974. u8bit: begin
  975. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
  976. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
  977. end;
  978. s8bit: begin
  979. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
  980. if (aktoptprocessor <> MC68020) then
  981. begin
  982. { byte to word }
  983. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
  984. { word to long }
  985. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  986. end
  987. else { 68020+ and later only }
  988. exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
  989. end;
  990. u16bit: begin
  991. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
  992. exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$ffff,destreg)));
  993. end;
  994. s16bit: begin
  995. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
  996. { word to long }
  997. exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
  998. end;
  999. u32bit:
  1000. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
  1001. s32bit:
  1002. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
  1003. end;
  1004. if delloc then
  1005. del_reference(location.reference);
  1006. end
  1007. else
  1008. internalerror(6);
  1009. end;
  1010. end;
  1011. { if necessary A5 is reloaded after a call}
  1012. procedure maybe_loada5;
  1013. var
  1014. hp : preference;
  1015. p : pprocinfo;
  1016. i : longint;
  1017. begin
  1018. if assigned(procinfo._class) then
  1019. begin
  1020. if lexlevel>2 then
  1021. begin
  1022. new(hp);
  1023. reset_reference(hp^);
  1024. hp^.offset:=procinfo.framepointer_offset;
  1025. hp^.base:=procinfo.framepointer;
  1026. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1027. p:=procinfo.parent;
  1028. for i:=3 to lexlevel-1 do
  1029. begin
  1030. new(hp);
  1031. reset_reference(hp^);
  1032. hp^.offset:=p^.framepointer_offset;
  1033. hp^.base:=R_A5;
  1034. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1035. p:=p^.parent;
  1036. end;
  1037. new(hp);
  1038. reset_reference(hp^);
  1039. hp^.offset:=p^.ESI_offset;
  1040. hp^.base:=R_A5;
  1041. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1042. end
  1043. else
  1044. begin
  1045. new(hp);
  1046. reset_reference(hp^);
  1047. hp^.offset:=procinfo.ESI_offset;
  1048. hp^.base:=procinfo.framepointer;
  1049. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
  1050. end;
  1051. end;
  1052. end;
  1053. (***********************************************************************)
  1054. (* PROCEDURE FLOATLOAD *)
  1055. (* Description: This routine is to be called each time a location *)
  1056. (* must be set to LOC_FPU and a value loaded into a FPU register. *)
  1057. (* *)
  1058. (* Remark: The routine sets up the register field of LOC_FPU correctly*)
  1059. (***********************************************************************)
  1060. procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
  1061. var
  1062. op : tasmop;
  1063. s : topsize;
  1064. begin
  1065. { no emulation }
  1066. case t of
  1067. s32real : s := S_FS;
  1068. s64real : s := S_FL;
  1069. s80real : s := S_FX;
  1070. else
  1071. begin
  1072. CGMessage(cg_f_unknown_float_type);
  1073. end;
  1074. end; { end case }
  1075. location.loc := LOC_FPU;
  1076. if not ((cs_fp_emulation) in aktmoduleswitches) then
  1077. begin
  1078. location.fpureg := getfloatreg;
  1079. exprasmlist^.concat(new(pai68k,op_ref_reg(A_FMOVE,s,newreference(ref),location.fpureg)))
  1080. end
  1081. else
  1082. { handle emulation }
  1083. begin
  1084. if t = s32real then
  1085. begin
  1086. location.fpureg := getregister32;
  1087. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),location.fpureg)))
  1088. end
  1089. else
  1090. { other floating types are not supported in emulation mode }
  1091. CGMessage(sym_e_type_id_not_defined);
  1092. end;
  1093. end;
  1094. { procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1095. begin
  1096. case t of
  1097. s32real : begin
  1098. op:=A_FSTP;
  1099. s:=S_FS;
  1100. end;
  1101. s64real : begin
  1102. op:=A_FSTP;
  1103. s:=S_FL;
  1104. end;
  1105. s80real : begin
  1106. op:=A_FSTP;
  1107. s:=S_FX;
  1108. end;
  1109. s64bit : begin
  1110. op:=A_FISTP;
  1111. s:=S_IQ;
  1112. end;
  1113. else internalerror(17);
  1114. end;
  1115. end; }
  1116. { stores an FPU value to memory }
  1117. { location:tlocation used to free up FPU register }
  1118. { ref: destination of storage }
  1119. procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
  1120. var
  1121. op : tasmop;
  1122. s : topsize;
  1123. begin
  1124. if location.loc <> LOC_FPU then
  1125. InternalError(34);
  1126. { no emulation }
  1127. case t of
  1128. s32real : s := S_FS;
  1129. s64real : s := S_FL;
  1130. s80real : s := S_FX;
  1131. else
  1132. begin
  1133. CGMessage(cg_f_unknown_float_type);
  1134. end;
  1135. end; { end case }
  1136. if not ((cs_fp_emulation) in aktmoduleswitches) then
  1137. begin
  1138. { This permits the mixing of emulation and non-emulation routines }
  1139. { only possible for REAL = SINGLE value_str }
  1140. if not (location.fpureg in [R_FP0..R_FP7]) then
  1141. Begin
  1142. if s = S_FS then
  1143. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))))
  1144. else
  1145. internalerror(255);
  1146. end
  1147. else
  1148. exprasmlist^.concat(new(pai68k,op_reg_ref(A_FMOVE,s,location.fpureg,newreference(ref))));
  1149. ungetregister(location.fpureg);
  1150. end
  1151. else
  1152. { handle emulation }
  1153. begin
  1154. if t = s32real then
  1155. begin
  1156. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))));
  1157. ungetregister32(location.fpureg);
  1158. end
  1159. else
  1160. { other floating types are not supported in emulation mode }
  1161. CGMessage(sym_e_type_id_not_defined);
  1162. end;
  1163. location.fpureg:=R_NO; { no register in LOC_FPU now }
  1164. end;
  1165. procedure firstcomplex(p : ptree);
  1166. var
  1167. hp : ptree;
  1168. begin
  1169. { always calculate boolean AND and OR from left to right }
  1170. if ((p^.treetype=orn) or (p^.treetype=andn)) and
  1171. (p^.left^.resulttype^.deftype=orddef) and
  1172. (porddef(p^.left^.resulttype)^.typ=bool8bit) then
  1173. p^.swaped:=false
  1174. else if (p^.left^.registers32<p^.right^.registers32)
  1175. { the following check is appropriate, because all }
  1176. { 4 registers are rarely used and it is thereby }
  1177. { achieved that the extra code is being dropped }
  1178. { by exchanging not commutative operators }
  1179. and (p^.right^.registers32<=4) then
  1180. begin
  1181. hp:=p^.left;
  1182. p^.left:=p^.right;
  1183. p^.right:=hp;
  1184. p^.swaped:=true;
  1185. end
  1186. else p^.swaped:=false;
  1187. end;
  1188. {$ifdef test_dest_loc}
  1189. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  1190. begin
  1191. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  1192. begin
  1193. emit_reg_reg(A_MOVE,s,reg,dest_loc.register);
  1194. p^.location:=dest_loc;
  1195. in_dest_loc:=true;
  1196. end
  1197. else
  1198. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  1199. begin
  1200. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,s,reg,newreference(dest_loc.reference))));
  1201. p^.location:=dest_loc;
  1202. in_dest_loc:=true;
  1203. end
  1204. else
  1205. internalerror(20080);
  1206. end;
  1207. {$endif test_dest_loc}
  1208. end.
  1209. {
  1210. $Log$
  1211. Revision 1.20 1998-10-13 08:19:29 pierre
  1212. + source_os is now set correctly for cross-processor compilers
  1213. (tos contains all target_infos and
  1214. we use CPU86 and CPU68 conditionnals to
  1215. get the source operating system
  1216. this only works if you do not undefine
  1217. the source target !!)
  1218. * several cg68k memory leaks fixed
  1219. + started to change the code so that it should be possible to have
  1220. a complete compiler (both for m68k and i386 !!)
  1221. Revision 1.19 1998/10/08 13:48:40 peter
  1222. * fixed memory leaks for do nothing source
  1223. * fixed unit interdependency
  1224. Revision 1.18 1998/09/28 16:57:17 pierre
  1225. * changed all length(p^.value_str^) into str_length(p)
  1226. to get it work with and without ansistrings
  1227. * changed sourcefiles field of tmodule to a pointer
  1228. Revision 1.17 1998/09/17 09:42:30 peter
  1229. + pass_2 for cg386
  1230. * Message() -> CGMessage() for pass_1/pass_2
  1231. Revision 1.16 1998/09/14 10:44:04 peter
  1232. * all internal RTL functions start with FPC_
  1233. Revision 1.15 1998/09/07 18:46:00 peter
  1234. * update smartlinking, uses getdatalabel
  1235. * renamed ptree.value vars to value_str,value_real,value_set
  1236. Revision 1.14 1998/09/04 08:41:50 peter
  1237. * updated some error CGMessages
  1238. Revision 1.13 1998/09/01 12:48:02 peter
  1239. * use pdef^.size instead of orddef^.typ
  1240. Revision 1.12 1998/09/01 09:07:09 peter
  1241. * m68k fixes, splitted cg68k like cgi386
  1242. Revision 1.11 1998/08/31 12:26:24 peter
  1243. * m68k and palmos updates from surebugfixes
  1244. Revision 1.10 1998/08/21 14:08:41 pierre
  1245. + TEST_FUNCRET now default (old code removed)
  1246. works also for m68k (at least compiles)
  1247. Revision 1.9 1998/08/17 10:10:04 peter
  1248. - removed OLDPPU
  1249. Revision 1.8 1998/08/10 14:43:16 peter
  1250. * string type st_ fixed
  1251. Revision 1.7 1998/07/10 10:51:01 peter
  1252. * m68k updates
  1253. Revision 1.6 1998/06/08 13:13:39 pierre
  1254. + temporary variables now in temp_gen.pas unit
  1255. because it is processor independent
  1256. * mppc68k.bat modified to undefine i386 and support_mmx
  1257. (which are defaults for i386)
  1258. Revision 1.5 1998/06/04 23:51:36 peter
  1259. * m68k compiles
  1260. + .def file creation moved to gendef.pas so it could also be used
  1261. for win32
  1262. Revision 1.4 1998/05/07 00:17:00 peter
  1263. * smartlinking for sets
  1264. + consts labels are now concated/generated in hcodegen
  1265. * moved some cpu code to cga and some none cpu depended code from cga
  1266. to tree and hcodegen and cleanup of hcodegen
  1267. * assembling .. output reduced for smartlinking ;)
  1268. Revision 1.3 1998/04/29 10:33:46 pierre
  1269. + added some code for ansistring (not complete nor working yet)
  1270. * corrected operator overloading
  1271. * corrected nasm output
  1272. + started inline procedures
  1273. + added starstarn : use ** for exponentiation (^ gave problems)
  1274. + started UseTokenInfo cond to get accurate positions
  1275. }