cgcpu.pas 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by the FPC team
  4. This unit implements the code generator for the 680x0
  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 cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cginfo,cgbase,cgobj,
  23. aasmbase,aasmtai,aasmcpu,
  24. cpubase,cpuinfo,cpupara,
  25. node,symconst;
  26. type
  27. tcg68k = class(tcg)
  28. procedure a_call_name(list : taasmoutput;const s : string);override;
  29. procedure a_call_ref(list : taasmoutput;const ref : treference);override;
  30. procedure a_load_const_reg(list : taasmoutput;size : tcgsize;a : aword;register : tregister);override;
  31. procedure a_load_reg_ref(list : taasmoutput;size : tcgsize;register : tregister;const ref : treference);override;
  32. procedure a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);override;
  33. procedure a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref : treference;register : tregister);override;
  34. procedure a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister);override;
  35. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  36. procedure a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  37. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  38. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  39. procedure a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
  40. procedure a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister); override;
  41. procedure a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference); override;
  42. procedure a_parammm_reg(list: taasmoutput; reg: tregister); override;
  43. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister); override;
  44. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; reg1, reg2: TRegister); override;
  45. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  46. l : tasmlabel);override;
  47. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  48. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  49. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  50. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister); override;
  51. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword;delsource,loadref : boolean);override;
  52. { generates overflow checking code for a node }
  53. procedure g_overflowcheck(list: taasmoutput; const p: tnode); override;
  54. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer); override;
  55. {
  56. This routine should setup the stack frame and allocate @var(localsize) bytes on
  57. the local stack (for local variables). It should also setup the frame pointer,
  58. so that all variables are now accessed via the frame pointer register.
  59. }
  60. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  61. { restores the previous frame pointer at procedure exit }
  62. procedure g_restore_frame_pointer(list : taasmoutput);override;
  63. { This routine should update the stack pointer so that parasize are freed
  64. from the stack. It should also emit the return instruction
  65. }
  66. procedure g_return_from_proc(list : taasmoutput;parasize : aword);override;
  67. procedure g_save_standard_registers(list : taasmoutput);override;
  68. procedure g_restore_standard_registers(list : taasmoutput);override;
  69. procedure g_save_all_registers(list : taasmoutput);override;
  70. procedure g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);override;
  71. private
  72. { # Sign or zero extend the register to a full 32-bit value.
  73. The new value is left in the same register.
  74. }
  75. procedure sign_extend(list: taasmoutput;_oldsize : tcgsize; reg: tregister);
  76. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  77. end;
  78. Implementation
  79. uses
  80. globtype,globals,verbose,systems,cutils,
  81. symdef,symsym,defbase,paramgr,
  82. rgobj,tgobj,rgcpu;
  83. const
  84. TCGSize2OpSize: Array[tcgsize] of topsize =
  85. (S_NO,S_B,S_W,S_L,S_L,S_B,S_W,S_L,S_L,
  86. S_FS,S_FD,S_FX,S_NO,
  87. S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
  88. { opcode table lookup }
  89. topcg2tasmop: Array[topcg] of tasmop =
  90. (
  91. A_NONE,
  92. A_ADD,
  93. A_AND,
  94. A_DIVU,
  95. A_DIVS,
  96. A_MULS,
  97. A_MULU,
  98. A_NEG,
  99. A_NOT,
  100. A_OR,
  101. A_ASR,
  102. A_LSL,
  103. A_LSR,
  104. A_SUB,
  105. A_EOR
  106. );
  107. TOpCmp2AsmCond: Array[topcmp] of TAsmCond =
  108. (
  109. C_NONE,
  110. C_EQ,
  111. C_GT,
  112. C_LT,
  113. C_GE,
  114. C_LE,
  115. C_NE,
  116. C_LS,
  117. C_CS,
  118. C_CC,
  119. C_HI
  120. );
  121. procedure tcg68k.a_call_name(list : taasmoutput;const s : string);
  122. begin
  123. list.concat(taicpu.op_sym(A_JSR,S_NO,objectlibrary.newasmsymbol(s)));
  124. end;
  125. procedure tcg68k.a_call_ref(list : taasmoutput;const ref : treference);
  126. begin
  127. list.concat(taicpu.op_ref(A_JSR,S_NO,ref));
  128. end;
  129. procedure tcg68k.a_load_const_reg(list : taasmoutput;size : tcgsize;a : aword;register : tregister);
  130. begin
  131. if (rg.isaddressregister(register)) then
  132. begin
  133. list.concat(taicpu.op_const_reg(A_MOVE,S_L,a,register))
  134. end
  135. else
  136. if a = 0 then
  137. list.concat(taicpu.op_reg(A_CLR,S_L,register))
  138. else
  139. begin
  140. if (longint(a) >= -128) and (longint(a) <= 127) then
  141. list.concat(taicpu.op_const_reg(A_MOVEQ,S_L,a,register))
  142. else
  143. list.concat(taicpu.op_const_reg(A_MOVE,S_L,a,register))
  144. end;
  145. end;
  146. procedure tcg68k.a_load_reg_ref(list : taasmoutput;size : tcgsize;register : tregister;const ref : treference);
  147. begin
  148. { move to destination reference }
  149. list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[size],register,ref));
  150. end;
  151. procedure tcg68k.a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);
  152. begin
  153. { move to destination register }
  154. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg1,reg2));
  155. { zero/sign extend register to 32-bit }
  156. sign_extend(list, size, reg2);
  157. end;
  158. procedure tcg68k.a_load_ref_reg(list : taasmoutput;size : tcgsize;const ref : treference;register : tregister);
  159. begin
  160. list.concat(taicpu.op_ref_reg(A_MOVE,TCGSize2OpSize[size],ref,register));
  161. { extend the value in the register }
  162. sign_extend(list, size, register);
  163. end;
  164. procedure tcg68k.a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister);
  165. begin
  166. {$warning To complete this section}
  167. end;
  168. procedure tcg68k.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  169. begin
  170. if (not rg.isaddressregister(r)) then
  171. begin
  172. internalerror(2002072901);
  173. end;
  174. list.concat(taicpu.op_ref_reg(A_LEA,S_L,ref,r));
  175. end;
  176. procedure tcg68k.a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  177. begin
  178. list.concat(taicpu.op_reg_reg(A_FMOVE,S_FD,reg1,reg2));
  179. end;
  180. procedure tcg68k.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  181. var
  182. opsize : topsize;
  183. begin
  184. opsize := tcgsize2opsize[size];
  185. { extended is not supported, since it is not available on Coldfire }
  186. if opsize = S_FX then
  187. internalerror(20020729);
  188. list.concat(taicpu.op_ref_reg(A_FMOVE,opsize,ref,reg));
  189. end;
  190. procedure tcg68k.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  191. var
  192. opsize : topsize;
  193. begin
  194. opsize := tcgsize2opsize[size];
  195. { extended is not supported, since it is not available on Coldfire }
  196. if opsize = S_FX then
  197. internalerror(20020729);
  198. list.concat(taicpu.op_reg_ref(A_FMOVE,opsize,reg, ref));
  199. end;
  200. procedure tcg68k.a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister);
  201. begin
  202. internalerror(20020729);
  203. end;
  204. procedure tcg68k.a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister);
  205. begin
  206. internalerror(20020729);
  207. end;
  208. procedure tcg68k.a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference);
  209. begin
  210. internalerror(20020729);
  211. end;
  212. procedure tcg68k.a_parammm_reg(list: taasmoutput; reg: tregister);
  213. begin
  214. internalerror(20020729);
  215. end;
  216. procedure tcg68k.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
  217. var
  218. scratch_reg : tregister;
  219. scratch_reg2: tregister;
  220. opcode : tasmop;
  221. begin
  222. opcode := topcg2tasmop[op];
  223. case op of
  224. OP_ADD :
  225. Begin
  226. if (a >= 1) and (a <= 8) then
  227. list.concat(taicpu.op_const_reg(A_ADDQ,S_L,a, reg))
  228. else
  229. begin
  230. { all others, including coldfire }
  231. list.concat(taicpu.op_const_reg(A_ADD,S_L,a, reg));
  232. end;
  233. end;
  234. OP_AND,
  235. OP_OR:
  236. Begin
  237. list.concat(taicpu.op_const_reg(topcg2tasmop[op],S_L,a, reg));
  238. end;
  239. OP_DIV :
  240. Begin
  241. {$warning To complete DIV opcode}
  242. end;
  243. OP_IDIV :
  244. Begin
  245. {$warning To complete IDIV opcode}
  246. end;
  247. OP_IMUL :
  248. Begin
  249. if aktoptprocessor = MC68000 then
  250. begin
  251. rg.getexplicitregisterint(list,R_D0);
  252. rg.getexplicitregisterint(list,R_D1);
  253. list.concat(taicpu.op_const_reg(A_MOVE,S_L,a, R_D0));
  254. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg, R_D1));
  255. cg.a_call_name(list,'FPC_MUL_LONGINT');
  256. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,R_D0, reg));
  257. rg.ungetregisterint(list,R_D0);
  258. rg.ungetregisterint(list,R_D1);
  259. end
  260. else
  261. begin
  262. if (rg.isaddressregister(reg)) then
  263. begin
  264. scratch_reg := cg.get_scratch_reg_int(list);
  265. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg, scratch_reg));
  266. list.concat(taicpu.op_const_reg(A_MULS,S_L,a,scratch_reg));
  267. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,scratch_reg,reg));
  268. cg.free_scratch_reg(list,scratch_reg);
  269. end
  270. else
  271. list.concat(taicpu.op_const_reg(A_MULS,S_L,a,reg));
  272. end;
  273. end;
  274. OP_MUL :
  275. Begin
  276. if aktoptprocessor = MC68000 then
  277. begin
  278. rg.getexplicitregisterint(list,R_D0);
  279. rg.getexplicitregisterint(list,R_D1);
  280. list.concat(taicpu.op_const_reg(A_MOVE,S_L,a, R_D0));
  281. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg, R_D1));
  282. cg.a_call_name(list,'FPC_MUL_CARDINAL');
  283. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,R_D0, reg));
  284. rg.ungetregisterint(list,R_D0);
  285. rg.ungetregisterint(list,R_D1);
  286. end
  287. else
  288. begin
  289. if (rg.isaddressregister(reg)) then
  290. begin
  291. scratch_reg := cg.get_scratch_reg_int(list);
  292. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg, scratch_reg));
  293. list.concat(taicpu.op_const_reg(A_MULU,S_L,a,scratch_reg));
  294. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,scratch_reg,reg));
  295. cg.free_scratch_reg(list,scratch_reg);
  296. end
  297. else
  298. list.concat(taicpu.op_const_reg(A_MULU,S_L,a,reg));
  299. end;
  300. end;
  301. OP_SAR,
  302. OP_SHL,
  303. OP_SHR :
  304. Begin
  305. if (a >= 1) and (a <= 8) then
  306. begin
  307. { now allowed to shift an address register }
  308. if (rg.isaddressregister(reg)) then
  309. begin
  310. scratch_reg := cg.get_scratch_reg_int(list);
  311. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg, scratch_reg));
  312. list.concat(taicpu.op_const_reg(opcode,S_L,a, scratch_reg));
  313. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,scratch_reg,reg));
  314. cg.free_scratch_reg(list,scratch_reg);
  315. end
  316. else
  317. list.concat(taicpu.op_const_reg(opcode,S_L,a, reg));
  318. end
  319. else
  320. begin
  321. { we must load the data into a register ... :() }
  322. scratch_reg := cg.get_scratch_reg_int(list);
  323. list.concat(taicpu.op_const_reg(A_MOVE,S_L,a, scratch_reg));
  324. { again... since shifting with address register is not allowed }
  325. if (rg.isaddressregister(reg)) then
  326. begin
  327. scratch_reg2 := cg.get_scratch_reg_int(list);
  328. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg, scratch_reg2));
  329. list.concat(taicpu.op_reg_reg(opcode,S_L,scratch_reg, scratch_reg2));
  330. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,scratch_reg2,reg));
  331. cg.free_scratch_reg(list,scratch_reg2);
  332. end
  333. else
  334. list.concat(taicpu.op_reg_reg(opcode,S_L,scratch_reg, reg));
  335. cg.free_scratch_reg(list,scratch_reg);
  336. end;
  337. end;
  338. OP_SUB :
  339. Begin
  340. if (a >= 1) and (a <= 8) then
  341. list.concat(taicpu.op_const_reg(A_SUBQ,S_L,a,reg))
  342. else
  343. begin
  344. { all others, including coldfire }
  345. list.concat(taicpu.op_const_reg(A_SUB,S_L,a, reg));
  346. end;
  347. end;
  348. OP_XOR :
  349. Begin
  350. list.concat(taicpu.op_const_reg(A_EORI,S_L,a, reg));
  351. end;
  352. else
  353. internalerror(20020729);
  354. end;
  355. end;
  356. procedure tcg68k.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; reg1, reg2: TRegister);
  357. var
  358. hreg1,hreg2: tregister;
  359. begin
  360. case op of
  361. OP_ADD :
  362. Begin
  363. if aktoptprocessor = ColdFire then
  364. begin
  365. { operation only allowed only a longword }
  366. sign_extend(list, size, reg1);
  367. sign_extend(list, size, reg2);
  368. list.concat(taicpu.op_reg_reg(A_ADD,S_L,reg1, reg2));
  369. end
  370. else
  371. begin
  372. list.concat(taicpu.op_reg_reg(A_ADD,TCGSize2OpSize[size],reg1, reg2));
  373. end;
  374. end;
  375. OP_AND,OP_OR,
  376. OP_SAR,OP_SHL,
  377. OP_SHR,OP_SUB,OP_XOR :
  378. Begin
  379. { load to data registers }
  380. if (rg.isaddressregister(reg1)) then
  381. begin
  382. hreg1 := cg.get_scratch_reg_int(list);
  383. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg1,hreg1));
  384. end
  385. else
  386. hreg1 := reg1;
  387. if (rg.isaddressregister(reg2)) then
  388. begin
  389. hreg2:= cg.get_scratch_reg_int(list);
  390. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg2,hreg2));
  391. end
  392. else
  393. hreg2 := reg2;
  394. if aktoptprocessor = ColdFire then
  395. begin
  396. { operation only allowed only a longword }
  397. {!***************************************
  398. in the case of shifts, the value to
  399. shift by, should already be valid, so
  400. no need to sign extend the value
  401. !
  402. }
  403. if op in [OP_AND,OP_OR,OP_SUB,OP_XOR] then
  404. sign_extend(list, size, hreg1);
  405. sign_extend(list, size, hreg2);
  406. list.concat(taicpu.op_reg_reg(topcg2tasmop[op],S_L,hreg1, hreg2));
  407. end
  408. else
  409. begin
  410. list.concat(taicpu.op_reg_reg(topcg2tasmop[op],TCGSize2OpSize[size],hreg1, hreg2));
  411. end;
  412. if reg1 <> hreg1 then
  413. cg.free_scratch_reg(list,hreg1);
  414. { move back result into destination register }
  415. if reg2 <> hreg2 then
  416. begin
  417. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,hreg2,reg2));
  418. cg.free_scratch_reg(list,hreg2);
  419. end;
  420. end;
  421. OP_DIV :
  422. Begin
  423. {$warning DIV to complete}
  424. end;
  425. OP_IDIV :
  426. Begin
  427. {$warning IDIV to complete}
  428. end;
  429. OP_IMUL :
  430. Begin
  431. sign_extend(list, size,reg1);
  432. sign_extend(list, size,reg2);
  433. if aktoptprocessor = MC68000 then
  434. begin
  435. rg.getexplicitregisterint(list,R_D0);
  436. rg.getexplicitregisterint(list,R_D1);
  437. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg1, R_D0));
  438. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg2, R_D1));
  439. cg.a_call_name(list,'FPC_MUL_LONGINT');
  440. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,R_D0, reg2));
  441. rg.ungetregisterint(list,R_D0);
  442. rg.ungetregisterint(list,R_D1);
  443. end
  444. else
  445. begin
  446. if (rg.isaddressregister(reg1)) then
  447. hreg1 := cg.get_scratch_reg_int(list)
  448. else
  449. hreg1 := reg1;
  450. if (rg.isaddressregister(reg2)) then
  451. hreg2:= cg.get_scratch_reg_int(list)
  452. else
  453. hreg2 := reg2;
  454. if reg1 <> hreg1 then
  455. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg1,hreg1));
  456. if reg2 <> hreg2 then
  457. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg2,hreg2));
  458. list.concat(taicpu.op_reg_reg(A_MULS,S_L,reg1,reg2));
  459. if reg1 <> hreg1 then
  460. cg.free_scratch_reg(list,hreg1);
  461. { move back result into destination register }
  462. if reg2 <> hreg2 then
  463. begin
  464. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,hreg2,reg2));
  465. cg.free_scratch_reg(list,hreg2);
  466. end;
  467. end;
  468. end;
  469. OP_MUL :
  470. Begin
  471. sign_extend(list, size,reg1);
  472. sign_extend(list, size,reg2);
  473. if aktoptprocessor = MC68000 then
  474. begin
  475. rg.getexplicitregisterint(list,R_D0);
  476. rg.getexplicitregisterint(list,R_D1);
  477. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg1, R_D0));
  478. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg2, R_D1));
  479. cg.a_call_name(list,'FPC_MUL_CARDINAL');
  480. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,R_D0, reg2));
  481. rg.ungetregisterint(list,R_D0);
  482. rg.ungetregisterint(list,R_D1);
  483. end
  484. else
  485. begin
  486. if (rg.isaddressregister(reg1)) then
  487. begin
  488. hreg1 := cg.get_scratch_reg_int(list);
  489. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg1,hreg1));
  490. end
  491. else
  492. hreg1 := reg1;
  493. if (rg.isaddressregister(reg2)) then
  494. begin
  495. hreg2:= cg.get_scratch_reg_int(list);
  496. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg2,hreg2));
  497. end
  498. else
  499. hreg2 := reg2;
  500. list.concat(taicpu.op_reg_reg(A_MULU,S_L,reg1,reg2));
  501. if reg1 <> hreg1 then
  502. cg.free_scratch_reg(list,hreg1);
  503. { move back result into destination register }
  504. if reg2 <> hreg2 then
  505. begin
  506. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,hreg2,reg2));
  507. cg.free_scratch_reg(list,hreg2);
  508. end;
  509. end;
  510. end;
  511. OP_NEG,
  512. OP_NOT :
  513. Begin
  514. if reg1 <> R_NO then
  515. internalerror(200112291);
  516. if (rg.isaddressregister(reg2)) then
  517. begin
  518. hreg2 := cg.get_scratch_reg_int(list);
  519. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg2,hreg2));
  520. end
  521. else
  522. hreg2 := reg2;
  523. { coldfire only supports long version }
  524. if aktoptprocessor = ColdFire then
  525. begin
  526. sign_extend(list, size,hreg2);
  527. list.concat(taicpu.op_reg(topcg2tasmop[op],S_L,hreg2));
  528. end
  529. else
  530. begin
  531. list.concat(taicpu.op_reg(topcg2tasmop[op],TCGSize2OpSize[size],hreg2));
  532. end;
  533. if reg2 <> hreg2 then
  534. begin
  535. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,hreg2,reg2));
  536. cg.free_scratch_reg(list,hreg2);
  537. end;
  538. end;
  539. else
  540. internalerror(20020729);
  541. end;
  542. end;
  543. procedure tcg68k.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  544. l : tasmlabel);
  545. var
  546. hregister : tregister;
  547. begin
  548. if a = 0 then
  549. begin
  550. list.concat(taicpu.op_reg(A_TST,TCGSize2OpSize[size],reg));
  551. end
  552. else
  553. begin
  554. if (aktoptprocessor = ColdFire) then
  555. begin
  556. {
  557. only longword comparison is supported,
  558. and only on data registers.
  559. }
  560. hregister := cg.get_scratch_reg_int(list);
  561. { always move to a data register }
  562. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,reg,hregister));
  563. { sign/zero extend the register }
  564. sign_extend(list, size,hregister);
  565. list.concat(taicpu.op_const_reg(A_CMPI,S_L,a,hregister));
  566. cg.free_scratch_reg(list,hregister);
  567. end
  568. else
  569. begin
  570. list.concat(taicpu.op_const_reg(A_CMPI,TCGSize2OpSize[size],a,reg));
  571. end;
  572. end;
  573. { emit the actual jump to the label }
  574. a_jmp_cond(list,cmp_op,l);
  575. end;
  576. procedure tcg68k.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  577. begin
  578. list.concat(taicpu.op_reg_reg(A_CMP,tcgsize2opsize[size],reg1,reg2));
  579. { emit the actual jump to the label }
  580. a_jmp_cond(list,cmp_op,l);
  581. end;
  582. procedure tcg68k.a_jmp_always(list : taasmoutput;l: tasmlabel);
  583. var
  584. ai: taicpu;
  585. begin
  586. ai := Taicpu.op_sym(A_JMP,S_NO,l);
  587. ai.is_jmp := true;
  588. list.concat(ai);
  589. end;
  590. procedure tcg68k.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  591. var
  592. ai : taicpu;
  593. begin
  594. ai := Taicpu.op_sym(A_BXX,S_NO,l);
  595. ai.SetCondition(flags_to_cond(f));
  596. ai.is_jmp := true;
  597. list.concat(ai);
  598. end;
  599. procedure tcg68k.g_flags2reg(list: taasmoutput; size: TCgSize; const f: tresflags; reg: TRegister);
  600. var
  601. ai : taicpu;
  602. hreg : tregister;
  603. begin
  604. { move to a Dx register? }
  605. if (rg.isaddressregister(reg)) then
  606. begin
  607. hreg := get_scratch_reg_int(list);
  608. a_load_const_reg(list,size,0,hreg);
  609. ai:=Taicpu.Op_reg(A_Sxx,S_B,hreg);
  610. ai.SetCondition(flags_to_cond(f));
  611. list.concat(ai);
  612. if (aktoptprocessor = ColdFire) then
  613. begin
  614. { neg.b does not exist on the Coldfire
  615. so we need to sign extend the value
  616. before doing a neg.l
  617. }
  618. list.concat(taicpu.op_reg(A_EXTB,S_L,hreg));
  619. list.concat(taicpu.op_reg(A_NEG,S_L,hreg));
  620. end
  621. else
  622. begin
  623. list.concat(taicpu.op_reg(A_NEG,S_B,hreg));
  624. end;
  625. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,hreg,reg));
  626. free_scratch_reg(list,hreg);
  627. end
  628. else
  629. begin
  630. a_load_const_reg(list,size,0,reg);
  631. ai:=Taicpu.Op_reg(A_Sxx,S_B,reg);
  632. ai.SetCondition(flags_to_cond(f));
  633. list.concat(ai);
  634. if (aktoptprocessor = ColdFire) then
  635. begin
  636. { neg.b does not exist on the Coldfire
  637. so we need to sign extend the value
  638. before doing a neg.l
  639. }
  640. list.concat(taicpu.op_reg(A_EXTB,S_L,reg));
  641. list.concat(taicpu.op_reg(A_NEG,S_L,reg));
  642. end
  643. else
  644. begin
  645. list.concat(taicpu.op_reg(A_NEG,S_B,reg));
  646. end;
  647. end;
  648. end;
  649. procedure tcg68k.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword;delsource,loadref : boolean);
  650. var
  651. helpsize : longint;
  652. i : byte;
  653. reg8,reg32 : tregister;
  654. swap : boolean;
  655. hregister : tregister;
  656. iregister : tregister;
  657. jregister : tregister;
  658. hp1 : treference;
  659. hp2 : treference;
  660. hl : tasmlabel;
  661. hl2: tasmlabel;
  662. popaddress : boolean;
  663. srcref,dstref : treference;
  664. begin
  665. popaddress := false;
  666. { this should never occur }
  667. if len > 65535 then
  668. internalerror(0);
  669. hregister := get_scratch_reg_int(list);
  670. if delsource then
  671. reference_release(list,source);
  672. { from 12 bytes movs is being used }
  673. if (not loadref) and ((len<=8) or (not(cs_littlesize in aktglobalswitches) and (len<=12))) then
  674. begin
  675. srcref := source;
  676. dstref := dest;
  677. helpsize:=len div 4;
  678. { move a dword x times }
  679. for i:=1 to helpsize do
  680. begin
  681. list.concat(taicpu.op_ref_reg(A_MOVE,S_L,srcref,hregister));
  682. list.concat(taicpu.op_reg_ref(A_MOVE,S_L,hregister,dstref));
  683. inc(srcref.offset,4);
  684. inc(dstref.offset,4);
  685. dec(len,4);
  686. end;
  687. { move a word }
  688. if len>1 then
  689. begin
  690. list.concat(taicpu.op_ref_reg(A_MOVE,S_W,srcref,hregister));
  691. list.concat(taicpu.op_reg_ref(A_MOVE,S_W,hregister,dstref));
  692. inc(srcref.offset,2);
  693. inc(dstref.offset,2);
  694. dec(len,2);
  695. end;
  696. { move a single byte }
  697. if len>0 then
  698. begin
  699. list.concat(taicpu.op_ref_reg(A_MOVE,S_B,srcref,hregister));
  700. list.concat(taicpu.op_reg_ref(A_MOVE,S_B,hregister,dstref));
  701. end
  702. end
  703. else
  704. begin
  705. iregister := get_scratch_reg_address(list);
  706. jregister := get_scratch_reg_address(list);
  707. { reference for move (An)+,(An)+ }
  708. reference_reset(hp1);
  709. hp1.base := iregister; { source register }
  710. hp1.direction := dir_inc;
  711. reference_reset(hp2);
  712. hp2.base := jregister;
  713. hp2.direction := dir_inc;
  714. { iregister = source }
  715. { jregister = destination }
  716. if loadref then
  717. list.concat(taicpu.op_ref_reg(A_MOVE,S_L,source,iregister))
  718. else
  719. list.concat(taicpu.op_ref_reg(A_LEA,S_L,source,iregister));
  720. list.concat(taicpu.op_ref_reg(A_LEA,S_L,dest,jregister));
  721. { double word move only on 68020+ machines }
  722. { because of possible alignment problems }
  723. { use fast loop mode }
  724. if (aktoptprocessor=MC68020) then
  725. begin
  726. helpsize := len - len mod 4;
  727. len := len mod 4;
  728. list.concat(taicpu.op_const_reg(A_MOVE,S_L,helpsize div 4,hregister));
  729. objectlibrary.getlabel(hl2);
  730. a_jmp_always(list,hl2);
  731. objectlibrary.getlabel(hl);
  732. a_label(list,hl);
  733. list.concat(taicpu.op_ref_ref(A_MOVE,S_L,hp1,hp2));
  734. cg.a_label(list,hl2);
  735. list.concat(taicpu.op_reg_sym(A_DBRA,S_L,hregister,hl));
  736. if len > 1 then
  737. begin
  738. dec(len,2);
  739. list.concat(taicpu.op_ref_ref(A_MOVE,S_W,hp1,hp2));
  740. end;
  741. if len = 1 then
  742. list.concat(taicpu.op_ref_ref(A_MOVE,S_B,hp1,hp2));
  743. end
  744. else
  745. begin
  746. { Fast 68010 loop mode with no possible alignment problems }
  747. helpsize := len;
  748. list.concat(taicpu.op_const_reg(A_MOVE,S_L,helpsize,hregister));
  749. objectlibrary.getlabel(hl2);
  750. a_jmp_always(list,hl2);
  751. objectlibrary.getlabel(hl);
  752. a_label(list,hl);
  753. list.concat(taicpu.op_ref_ref(A_MOVE,S_B,hp1,hp2));
  754. a_label(list,hl2);
  755. list.concat(taicpu.op_reg_sym(A_DBRA,S_L,hregister,hl));
  756. end;
  757. { restore the registers that we have just used olny if they are used! }
  758. if jregister = R_A1 then
  759. hp2.base := R_NO;
  760. if iregister = R_A0 then
  761. hp1.base := R_NO;
  762. reference_release(list,hp1);
  763. reference_release(list,hp2);
  764. end;
  765. { loading SELF-reference again }
  766. g_maybe_loadself(list);
  767. if delsource then
  768. tg.ungetiftemp(list,source);
  769. free_scratch_reg(list,hregister);
  770. end;
  771. procedure tcg68k.g_overflowcheck(list: taasmoutput; const p: tnode);
  772. begin
  773. end;
  774. procedure tcg68k.g_copyvaluepara_openarray(list : taasmoutput;const ref:treference;elesize:integer);
  775. begin
  776. end;
  777. procedure tcg68k.g_stackframe_entry(list : taasmoutput;localsize : longint);
  778. begin
  779. if localsize<>0 then
  780. begin
  781. { Not to complicate the code generator too much, and since some }
  782. { of the systems only support this format, the localsize cannot }
  783. { exceed 32K in size. }
  784. if (localsize < -32767) or (localsize > 32768) then
  785. CGMessage(cg_e_stacklimit_in_local_routine);
  786. list.concat(taicpu.op_reg_const(A_LINK,S_W,frame_pointer_reg,-localsize));
  787. end { endif localsize <> 0 }
  788. else
  789. begin
  790. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,frame_pointer_reg,R_SPPUSH));
  791. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,stack_pointer_reg,frame_pointer_reg));
  792. end;
  793. end;
  794. procedure tcg68k.g_restore_frame_pointer(list : taasmoutput);
  795. begin
  796. list.concat(taicpu.op_reg(A_UNLK,S_NO,frame_pointer_reg));
  797. end;
  798. procedure tcg68k.g_return_from_proc(list : taasmoutput;parasize : aword);
  799. var
  800. hregister : tregister;
  801. begin
  802. {Routines with the poclearstack flag set use only a ret.}
  803. { also routines with parasize=0 }
  804. if (po_clearstack in aktprocdef.procoptions) then
  805. begin
  806. { complex return values are removed from stack in C code PM }
  807. if paramanager.ret_in_param(aktprocdef.rettype.def) then
  808. list.concat(taicpu.op_const(A_RTD,S_NO,4))
  809. else
  810. list.concat(taicpu.op_none(A_RTS,S_NO));
  811. end
  812. else if (parasize=0) then
  813. begin
  814. list.concat(taicpu.op_none(A_RTS,S_NO));
  815. end
  816. else
  817. begin
  818. { return with immediate size possible here }
  819. { signed! }
  820. { RTD is not supported on the coldfire }
  821. if (aktoptprocessor = MC68020) and (parasize < $7FFF) then
  822. list.concat(taicpu.op_const(A_RTD,S_NO,parasize))
  823. { manually restore the stack }
  824. else
  825. begin
  826. { We must pull the PC Counter from the stack, before }
  827. { restoring the stack pointer, otherwise the PC would }
  828. { point to nowhere! }
  829. { save the PC counter (pop it from the stack) }
  830. hregister := get_scratch_reg_address(list);
  831. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,R_SPPULL,hregister));
  832. { can we do a quick addition ... }
  833. if (parasize > 0) and (parasize < 9) then
  834. list.concat(taicpu.op_const_reg(A_ADDQ,S_L,parasize,R_SP))
  835. else { nope ... }
  836. list.concat(taicpu.op_const_reg(A_ADD,S_L,parasize,R_SP));
  837. { restore the PC counter (push it on the stack) }
  838. list.concat(taicpu.op_reg_reg(A_MOVE,S_L,hregister,R_SPPUSH));
  839. list.concat(taicpu.op_none(A_RTS,S_NO));
  840. free_scratch_reg(list,hregister);
  841. end;
  842. end;
  843. end;
  844. procedure tcg68k.g_save_standard_registers(list : taasmoutput);
  845. begin
  846. end;
  847. procedure tcg68k.g_restore_standard_registers(list : taasmoutput);
  848. begin
  849. end;
  850. procedure tcg68k.g_save_all_registers(list : taasmoutput);
  851. begin
  852. end;
  853. procedure tcg68k.g_restore_all_registers(list : taasmoutput;selfused,accused,acchiused:boolean);
  854. begin
  855. end;
  856. procedure tcg68k.sign_extend(list: taasmoutput;_oldsize : tcgsize; reg: tregister);
  857. begin
  858. case _oldsize of
  859. { sign extend }
  860. OS_S8:
  861. begin
  862. if (rg.isaddressregister(reg)) then
  863. internalerror(20020729);
  864. if (aktoptprocessor = MC68000) then
  865. begin
  866. list.concat(taicpu.op_reg(A_EXT,S_W,reg));
  867. list.concat(taicpu.op_reg(A_EXT,S_L,reg));
  868. end
  869. else
  870. begin
  871. list.concat(taicpu.op_reg(A_EXTB,S_L,reg));
  872. end;
  873. end;
  874. OS_S16:
  875. begin
  876. if (rg.isaddressregister(reg)) then
  877. internalerror(20020729);
  878. list.concat(taicpu.op_reg(A_EXT,S_L,reg));
  879. end;
  880. { zero extend }
  881. OS_8:
  882. begin
  883. if (rg.isaddressregister(reg)) then
  884. internalerror(20020729);
  885. list.concat(taicpu.op_const_reg(A_AND,S_L,$FF,reg));
  886. end;
  887. OS_16:
  888. begin
  889. if (rg.isaddressregister(reg)) then
  890. internalerror(20020729);
  891. list.concat(taicpu.op_const_reg(A_AND,S_L,$FFFF,reg));
  892. end;
  893. end; { otherwise the size is already correct }
  894. end;
  895. procedure tcg68k.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  896. var
  897. ai : taicpu;
  898. begin
  899. if cond=OC_None then
  900. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  901. else
  902. begin
  903. ai:=Taicpu.Op_sym(A_Bxx,S_NO,l);
  904. ai.SetCondition(TOpCmp2AsmCond[cond]);
  905. end;
  906. ai.is_jmp:=true;
  907. list.concat(ai);
  908. end;
  909. begin
  910. cg := tcg68k.create;
  911. { cg64 :=tcg64fppc.create;}
  912. end.
  913. {
  914. $Log$
  915. Revision 1.1 2002-08-13 18:30:22 carl
  916. * rename swatoperands to swapoperands
  917. + m68k first compilable version (still needs a lot of testing):
  918. assembler generator, system information , inline
  919. assembler reader.
  920. Revision 1.5 2002/08/12 15:08:43 carl
  921. + stab register indexes for powerpc (moved from gdb to cpubase)
  922. + tprocessor enumeration moved to cpuinfo
  923. + linker in target_info is now a class
  924. * many many updates for m68k (will soon start to compile)
  925. - removed some ifdef or correct them for correct cpu
  926. Revision 1.2 2002/08/05 17:27:52 carl
  927. + updated m68k
  928. Revision 1.1 2002/07/29 17:51:32 carl
  929. + restart m68k support
  930. }