aasmcpu.pas 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. {
  2. Copyright (c) 1998-2001 by Florian Klaempfl and Pierre Muller
  3. m68k family assembler instructions
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit aasmcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,aasmtai,aasmdata,aasmsym,
  22. aasmbase,globals,verbose,symtype,
  23. cpubase,cpuinfo,cgbase,cgutils,
  24. ogbase;
  25. const
  26. { "mov reg,reg" source operand number }
  27. O_MOV_SOURCE = 0;
  28. { "mov reg,reg" source operand number }
  29. O_MOV_DEST = 1;
  30. instabentries = {$i m68knop.inc}
  31. type
  32. TOperandType = (
  33. OT_DATA,
  34. OT_ADDR,
  35. OT_ADDR_INDIR,
  36. OT_ADDR_INDIR_POSTINC,
  37. OT_ADDR_INDIR_PREDEC,
  38. OT_ADDR_DISP16,
  39. OT_ADDR_IDX_DISP8,
  40. OT_ABS_SHORT,
  41. OT_ABS_LONG,
  42. OT_PC_DISP16,
  43. OT_PC_IDX_DISP8,
  44. OT_IMMEDIATE,
  45. OT_REG_LIST,
  46. OT_FPUREG_LIST,
  47. OT_FPUREG,
  48. OT_SPECIALREG
  49. );
  50. TOperandFlags = (
  51. OF_IMM_QUICK,
  52. OF_IMM_FLOAT,
  53. OF_IMM_64BIT,
  54. OF_SPECREG,
  55. OF_SPECREG_CCR,
  56. OF_SPECREG_SR,
  57. OF_SPECREG_USP,
  58. OF_SPECREG_FPIAR,
  59. OF_SPECREG_FPU,
  60. OF_BITFIELD,
  61. OF_BRANCH,
  62. OF_DOUBLE_REG,
  63. OF_KFACTOR,
  64. OF_NOSIZE
  65. );
  66. TOpSizeFlag = (
  67. OPS_UNSIZED,
  68. OPS_SHORT,
  69. OPS_BYTE,
  70. OPS_WORD,
  71. OPS_LONG,
  72. OPS_QUAD,
  73. OPS_SINGLE,
  74. OPS_DOUBLE,
  75. OPS_EXTENDED,
  76. OPS_PACKED,
  77. OPS_COLDFIRE
  78. );
  79. TOpSupported = (
  80. OS_M68000,
  81. OS_M68000UP,
  82. OS_M68010UP,
  83. OS_M68020,
  84. OS_M68020UP,
  85. OS_M68030,
  86. OS_M68040,
  87. OS_M68040UP,
  88. OS_M68060,
  89. OS_M68881,
  90. OS_M68851,
  91. OS_CPU32,
  92. OS_CF,
  93. OS_CF_ISA_A,
  94. OS_CF_ISA_APL,
  95. OS_CF_ISA_B,
  96. OS_CF_ISA_C,
  97. OS_CF_HWDIV,
  98. OS_CF_FPU,
  99. OS_CF_USP,
  100. OS_GNU_AS
  101. );
  102. const
  103. AM_Dn = 0;
  104. AM_An = 1;
  105. AM_An_Indir = 2;
  106. AM_An_PostInc = 3;
  107. AM_An_PreDec = 4;
  108. AM_An_Disp16 = 5;
  109. AM_An_Format8 = 6;
  110. AM_Extended = 7;
  111. AM_FPn = 8;
  112. AM_SpecReg = 9;
  113. REG_AbsShort = 0;
  114. REG_AbsLong = 1;
  115. REG_PC_Disp16 = 2;
  116. REG_PC_Format8 = 3;
  117. REG_Immediate = 4;
  118. REG_RegList = 5;
  119. REG_FPURegList = 6;
  120. type
  121. toperandtypeset = set of toperandtype;
  122. toperandflagset = set of toperandflags;
  123. type
  124. tinsentry = record
  125. opcode : tasmop;
  126. ops : byte;
  127. optypes : array[0..max_operands-1] of toperandtypeset;
  128. opflags : array[0..max_operands-1] of toperandflagset;
  129. codelen : byte;
  130. code : array[0..1] of word;
  131. support : set of topsupported;
  132. sizes : set of topsizeflag;
  133. end;
  134. pinsentry = ^tinsentry;
  135. type
  136. TInsTabCache=array[TasmOp] of longint;
  137. PInsTabCache=^TInsTabCache;
  138. var
  139. InsTabCache: PInsTabCache;
  140. const
  141. InsTab:array[0..instabentries-1] of TInsEntry = {$i m68ktab.inc}
  142. type
  143. taicpu = class(tai_cpu_abstract_sym)
  144. private
  145. { next fields are filled in pass1, so pass2 is faster }
  146. insentry : PInsEntry;
  147. inssize : shortint;
  148. insoffset : longint;
  149. LastInsOffset : longint;
  150. function CalcSize(p: PInsEntry):shortint;
  151. function Matches(p: PInsEntry; objdata: TObjData):boolean;
  152. function FindInsEntry(objdata: TObjData):boolean;
  153. procedure GenCode(objdata: TObjData);
  154. procedure init(_size : topsize); { this need to be called by all constructor }
  155. public
  156. opsize : topsize;
  157. procedure loadregset(opidx:longint; const dataregs,addrregs,fpuregs:tcpuregisterset);
  158. procedure loadregpair(opidx:longint; const _reghi,_reglo: tregister);
  159. procedure loadrealconst(opidx:longint; const value_real: bestreal);
  160. constructor op_none(op : tasmop);
  161. constructor op_none(op : tasmop;_size : topsize);
  162. constructor op_reg(op : tasmop;_size : topsize;_op1 : tregister);
  163. constructor op_const(op : tasmop;_size : topsize;_op1 : longint);
  164. constructor op_ref(op : tasmop;_size : topsize;_op1 : treference);
  165. constructor op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
  166. constructor op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;_op2 : treference);
  167. constructor op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: longint);
  168. constructor op_const_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister);
  169. constructor op_const_const(op : tasmop;_size : topsize;_op1,_op2 : longint);
  170. constructor op_const_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : treference);
  171. constructor op_realconst_reg(op : tasmop;_size : topsize;_op1: bestreal;_op2: tregister);
  172. constructor op_ref_reg(op : tasmop;_size : topsize;_op1 : treference;_op2 : tregister);
  173. { this is only allowed if _op1 is an int value (_op1^.isintvalue=true) }
  174. constructor op_ref_ref(op : tasmop;_size : topsize;_op1,_op2 : treference);
  175. { this is used for mulx/divx/remx regpair generation }
  176. constructor op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
  177. constructor op_const_reg_reg(op : tasmop;_size : topsize;_op1 : longint; _op2,_op3 : tregister);
  178. constructor op_ref_reg_reg(op : tasmop;_size : topsize;_op1 : treference; _op2,_op3 : tregister);
  179. constructor op_reg_regset(op: tasmop; _size : topsize; _op1: tregister;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
  180. constructor op_regset_reg(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: tregister);
  181. constructor op_ref_regset(op: tasmop; _size : topsize; _op1: treference;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
  182. constructor op_regset_ref(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: treference);
  183. { this is for Jmp instructions }
  184. constructor op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
  185. constructor op_sym(op : tasmop;_size : topsize;_op1 : tasmsymbol);
  186. { for DBxx opcodes }
  187. constructor op_reg_sym(op: tasmop; _size : topsize; _op1: tregister; _op2 :tasmsymbol);
  188. constructor op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;_op2 : tregister);
  189. constructor op_sym_ofs(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint);
  190. constructor op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
  191. function is_same_reg_move(regtype: Tregistertype):boolean;override;
  192. function spilling_get_operation_type(opnr: longint): topertype;override;
  193. function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override;
  194. procedure ResetPass1;override;
  195. procedure ResetPass2;override;
  196. function Pass1(objdata:TObjData):longint;override;
  197. procedure Pass2(objdata:TObjData);override;
  198. end;
  199. tai_align = class(tai_align_abstract)
  200. { nothing to add }
  201. end;
  202. procedure InitAsm;
  203. procedure DoneAsm;
  204. function spilling_create_load(const ref:treference;r:tregister):Taicpu;
  205. function spilling_create_store(r:tregister; const ref:treference):Taicpu;
  206. implementation
  207. uses
  208. globtype, itcpugas;
  209. {*****************************************************************************
  210. Taicpu Constructors
  211. *****************************************************************************}
  212. procedure taicpu.loadregset(opidx:longint; const dataregs,addrregs,fpuregs:tcpuregisterset);
  213. var
  214. i : byte;
  215. begin
  216. allocate_oper(opidx+1);
  217. with oper[opidx]^ do
  218. begin
  219. if typ<>top_regset then
  220. clearop(opidx);
  221. dataregset:=dataregs;
  222. addrregset:=addrregs;
  223. fpuregset:=fpuregs;
  224. typ:=top_regset;
  225. for i:=RS_D0 to RS_D7 do
  226. begin
  227. if assigned(add_reg_instruction_hook) and (i in dataregset) then
  228. add_reg_instruction_hook(self,newreg(R_INTREGISTER,i,R_SUBWHOLE));
  229. end;
  230. for i:=RS_A0 to RS_SP do
  231. begin
  232. if assigned(add_reg_instruction_hook) and (i in addrregset) then
  233. add_reg_instruction_hook(self,newreg(R_ADDRESSREGISTER,i,R_SUBWHOLE));
  234. end;
  235. for i:=RS_FP0 to RS_FP7 do
  236. begin
  237. if assigned(add_reg_instruction_hook) and (i in fpuregset) then
  238. add_reg_instruction_hook(self,newreg(R_FPUREGISTER,i,R_SUBWHOLE));
  239. end;
  240. end;
  241. end;
  242. procedure taicpu.loadregpair(opidx:longint; const _reghi,_reglo: tregister);
  243. begin
  244. allocate_oper(opidx+1);
  245. with oper[opidx]^ do
  246. begin
  247. if typ<>top_regpair then
  248. clearop(opidx);
  249. typ:=top_regpair;
  250. reghi:=_reghi;
  251. reglo:=_reglo;
  252. end;
  253. end;
  254. procedure taicpu.loadrealconst(opidx:longint; const value_real: bestreal);
  255. begin
  256. allocate_oper(opidx+1);
  257. with oper[opidx]^ do
  258. begin
  259. if typ<>top_realconst then
  260. clearop(opidx);
  261. val_real:=value_real;
  262. typ:=top_realconst;
  263. end;
  264. end;
  265. procedure taicpu.init(_size : topsize);
  266. begin
  267. typ:=ait_instruction;
  268. is_jmp:=false;
  269. opsize:=_size;
  270. ops:=0;
  271. end;
  272. constructor taicpu.op_none(op : tasmop);
  273. begin
  274. inherited create(op);
  275. init(S_NO);
  276. end;
  277. constructor taicpu.op_none(op : tasmop;_size : topsize);
  278. begin
  279. inherited create(op);
  280. init(_size);
  281. end;
  282. constructor taicpu.op_reg(op : tasmop;_size : topsize;_op1 : tregister);
  283. begin
  284. inherited create(op);
  285. init(_size);
  286. ops:=1;
  287. loadreg(0,_op1);
  288. end;
  289. constructor taicpu.op_const(op : tasmop;_size : topsize;_op1 : longint);
  290. begin
  291. inherited create(op);
  292. init(_size);
  293. ops:=1;
  294. loadconst(0,aword(_op1));
  295. end;
  296. constructor taicpu.op_ref(op : tasmop;_size : topsize;_op1 : treference);
  297. begin
  298. inherited create(op);
  299. init(_size);
  300. ops:=1;
  301. loadref(0,_op1);
  302. end;
  303. constructor taicpu.op_reg_reg(op : tasmop;_size : topsize;_op1,_op2 : tregister);
  304. begin
  305. inherited create(op);
  306. init(_size);
  307. ops:=2;
  308. loadreg(0,_op1);
  309. loadreg(1,_op2);
  310. end;
  311. constructor taicpu.op_reg_const(op:tasmop; _size: topsize; _op1: tregister; _op2: longint);
  312. begin
  313. inherited create(op);
  314. init(_size);
  315. ops:=2;
  316. loadreg(0,_op1);
  317. loadconst(1,aword(_op2));
  318. end;
  319. constructor taicpu.op_reg_ref(op : tasmop;_size : topsize;_op1 : tregister;_op2 : treference);
  320. begin
  321. inherited create(op);
  322. init(_size);
  323. ops:=2;
  324. loadreg(0,_op1);
  325. loadref(1,_op2);
  326. end;
  327. constructor taicpu.op_const_reg(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister);
  328. begin
  329. inherited create(op);
  330. init(_size);
  331. ops:=2;
  332. loadconst(0,aword(_op1));
  333. loadreg(1,_op2);
  334. end;
  335. constructor taicpu.op_const_const(op : tasmop;_size : topsize;_op1,_op2 : longint);
  336. begin
  337. inherited create(op);
  338. init(_size);
  339. ops:=2;
  340. loadconst(0,aword(_op1));
  341. loadconst(1,aword(_op2));
  342. end;
  343. constructor taicpu.op_const_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : treference);
  344. begin
  345. inherited create(op);
  346. init(_size);
  347. ops:=2;
  348. loadconst(0,aword(_op1));
  349. loadref(1,_op2);
  350. end;
  351. constructor taicpu.op_realconst_reg(op : tasmop;_size : topsize;_op1 : bestreal;_op2 : tregister);
  352. begin
  353. inherited create(op);
  354. init(_size);
  355. ops:=2;
  356. loadrealconst(0,_op1);
  357. loadreg(1,_op2);
  358. end;
  359. constructor taicpu.op_ref_reg(op : tasmop;_size : topsize;_op1 : treference;_op2 : tregister);
  360. begin
  361. inherited create(op);
  362. init(_size);
  363. ops:=2;
  364. loadref(0,_op1);
  365. loadreg(1,_op2);
  366. end;
  367. constructor taicpu.op_ref_ref(op : tasmop;_size : topsize;_op1,_op2 : treference);
  368. begin
  369. inherited create(op);
  370. init(_size);
  371. ops:=2;
  372. loadref(0,_op1);
  373. loadref(1,_op2);
  374. end;
  375. constructor taicpu.op_reg_reg_reg(op : tasmop;_size : topsize;_op1,_op2,_op3 : tregister);
  376. begin
  377. inherited create(op);
  378. init(_size);
  379. ops:=3;
  380. loadreg(0,_op1);
  381. loadreg(1,_op2);
  382. loadreg(2,_op3);
  383. end;
  384. constructor taicpu.op_const_reg_reg(op : tasmop;_size : topsize;_op1 : longint; _op2,_op3 : tregister);
  385. begin
  386. inherited create(op);
  387. init(_size);
  388. ops:=3;
  389. loadconst(0,aword(_op1));
  390. loadreg(1,_op2);
  391. loadreg(2,_op3);
  392. end;
  393. constructor taicpu.op_ref_reg_reg(op : tasmop;_size : topsize;_op1 : treference; _op2,_op3 : tregister);
  394. begin
  395. inherited create(op);
  396. init(_size);
  397. ops:=3;
  398. loadref(0,_op1);
  399. loadreg(1,_op2);
  400. loadreg(2,_op3);
  401. end;
  402. constructor taicpu.op_ref_regset(op: tasmop; _size : topsize; _op1: treference;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
  403. Begin
  404. inherited create(op);
  405. init(_size);
  406. ops:=2;
  407. loadref(0,_op1);
  408. loadregset(1,_op2data,_op2addr,_op2fpu);
  409. end;
  410. constructor taicpu.op_regset_ref(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: treference);
  411. Begin
  412. inherited create(op);
  413. init(_size);
  414. ops:=2;
  415. loadregset(0,_op1data,_op1addr,_op1fpu);
  416. loadref(1,_op2);
  417. End;
  418. constructor taicpu.op_reg_regset(op: tasmop; _size : topsize; _op1: tregister;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
  419. Begin
  420. inherited create(op);
  421. init(_size);
  422. ops:=2;
  423. loadreg(0,_op1);
  424. loadregset(1,_op2data,_op2addr,_op2fpu);
  425. end;
  426. constructor taicpu.op_regset_reg(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: tregister);
  427. Begin
  428. inherited create(op);
  429. init(_size);
  430. ops:=2;
  431. loadregset(0,_op1data,_op1addr,_op1fpu);
  432. loadreg(1,_op2);
  433. End;
  434. constructor taicpu.op_sym(op : tasmop;_size : topsize;_op1 : tasmsymbol);
  435. begin
  436. inherited create(op);
  437. init(_size);
  438. ops:=1;
  439. loadsymbol(0,_op1,0);
  440. end;
  441. constructor taicpu.op_reg_sym(op: tasmop; _size : topsize; _op1: tregister; _op2 :tasmsymbol);
  442. begin
  443. inherited create(op);
  444. init(_size);
  445. ops:=2;
  446. loadreg(0,_op1);
  447. loadsymbol(1,_op2,0);
  448. end;
  449. constructor taicpu.op_sym_ofs_ref(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
  450. begin
  451. inherited create(op);
  452. init(_size);
  453. ops:=2;
  454. loadsymbol(0,_op1,_op1ofs);
  455. loadref(1,_op2);
  456. end;
  457. constructor taicpu.op_sym_ofs(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint);
  458. begin
  459. inherited create(op);
  460. init(_size);
  461. ops:=1;
  462. loadsymbol(0,_op1,_op1ofs);
  463. end;
  464. constructor taicpu.op_sym_ofs_reg(op : tasmop;_size : topsize;_op1 : tasmsymbol;_op1ofs:longint;_op2 : tregister);
  465. begin
  466. inherited create(op);
  467. init(_size);
  468. ops:=2;
  469. if ((op >= A_DBCC) and (op <= A_DBF))
  470. or ((op >= A_FDBEQ) and (op <= A_FDBNGLE)) then
  471. begin
  472. loadreg(0,_op2);
  473. loadsymbol(1,_op1,_op1ofs);
  474. end
  475. else
  476. begin
  477. loadsymbol(0,_op1,_op1ofs);
  478. loadreg(1,_op2);
  479. end;
  480. end;
  481. constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
  482. begin
  483. inherited create(op);
  484. init(_size);
  485. condition:=cond;
  486. ops:=1;
  487. loadsymbol(0,_op1,0);
  488. end;
  489. function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
  490. begin
  491. result:=(((opcode=A_MOVE) or (opcode=A_EXG)) and
  492. (regtype = R_INTREGISTER) and
  493. (ops=2) and
  494. (oper[0]^.typ=top_reg) and
  495. (oper[1]^.typ=top_reg) and
  496. (isregoverlap(oper[0]^.reg,oper[1]^.reg))
  497. ) or
  498. (((opcode=A_MOVE) or (opcode=A_EXG) or (opcode=A_MOVEA)) and
  499. (regtype = R_ADDRESSREGISTER) and
  500. (ops=2) and
  501. (oper[0]^.typ=top_reg) and
  502. (oper[1]^.typ=top_reg) and
  503. (isregoverlap(oper[0]^.reg,oper[1]^.reg))
  504. ) or
  505. ((opcode=A_FMOVE) and
  506. (regtype = R_FPUREGISTER) and
  507. (ops=2) and
  508. (oper[0]^.typ=top_reg) and
  509. (oper[1]^.typ=top_reg) and
  510. (oper[0]^.reg=oper[1]^.reg)
  511. );
  512. end;
  513. function taicpu.spilling_get_operation_type(opnr: longint): topertype;
  514. begin
  515. result:=operand_read;
  516. case opcode of
  517. // CPU opcodes
  518. A_MOVE, A_MOVEQ, A_MOVEA, A_MVZ, A_MVS, A_MOV3Q, A_LEA:
  519. if opnr=1 then
  520. result:=operand_write;
  521. A_ADD, A_ADDQ, A_ADDX, A_SUB, A_SUBQ, A_SUBX,
  522. A_AND, A_LSR, A_LSL, A_ASR, A_ASL, A_EOR, A_EORI, A_OR,
  523. A_ROL, A_ROR, A_ROXL, A_ROXR,
  524. A_BSET, A_BCLR:
  525. if opnr=1 then
  526. result:=operand_readwrite;
  527. A_MULS, A_MULU, A_DIVS, A_DIVU, A_DIVSL, A_DIVUL, A_REMS, A_REMU:
  528. { FIXME: actually, one of the operand of the 3 op DIV/MUL is write only,
  529. but we can't handle it easily... }
  530. if opnr>0 then
  531. result:=operand_readwrite;
  532. A_DBRA:
  533. if opnr=0 then
  534. result:=operand_readwrite;
  535. A_CLR, A_SXX, A_SEQ, A_SNE, A_SLT, A_SLE, A_SGT, A_SGE, A_SCS, A_SCC,
  536. A_SMI, A_SPL, A_SF, A_ST, A_SVS, A_SVC, A_SHI, A_SLS:
  537. result:=operand_write;
  538. A_NEG, A_NEGX, A_EXT, A_EXTB, A_NOT, A_SWAP:
  539. result:=operand_readwrite;
  540. A_TST, A_CMP, A_CMPI, A_BTST:
  541. begin end; { Do nothing, default operand_read is fine here. }
  542. // FPU opcodes
  543. A_FSXX, A_FSEQ, A_FSNE, A_FSLT, A_FSLE, A_FSGT, A_FSGE:
  544. result:=operand_write;
  545. A_FABS, A_FSABS, A_FDABS,
  546. A_FSQRT, A_FSSQRT, A_FDSQRT,
  547. A_FNEG, A_FSNEG, A_FDNEG,
  548. A_FSIN, A_FCOS,
  549. A_FINT, A_FINTRZ:
  550. if ops = 1 then
  551. begin
  552. if opnr = 0 then
  553. result:=operand_readwrite;
  554. end
  555. else
  556. if opnr = 1 then
  557. result:=operand_write;
  558. A_FMOVE, A_FSMOVE, A_FDMOVE:
  559. if opnr=1 then
  560. result:=operand_write;
  561. A_FADD, A_FSADD, A_FDADD,
  562. A_FSUB, A_FSSUB, A_FDSUB,
  563. A_FMUL, A_FSMUL, A_FDMUL, A_FSGLMUL,
  564. A_FDIV, A_FSDIV, A_FDDIV, A_FSGLDIV:
  565. if opnr=1 then
  566. result:=operand_readwrite;
  567. A_FCMP, A_FTST:
  568. begin end; { operand_read }
  569. else begin
  570. internalerror(2004040903);
  571. end;
  572. end;
  573. end;
  574. function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;
  575. begin
  576. result := operand_read;
  577. if (oper[opnr]^.ref^.base = reg) and
  578. (oper[opnr]^.ref^.direction <> dir_none) then
  579. result := operand_readwrite;
  580. end;
  581. function taicpu.CalcSize(p: PInsEntry): shortint;
  582. begin
  583. result:=p^.codelen * 2;
  584. end;
  585. function taicpu.Matches(p: PInsEntry; objdata:TObjData): boolean;
  586. function OperandsMatch(const oper: toper; const ots: toperandtypeset): boolean;
  587. var
  588. ot: toperandtype;
  589. begin
  590. // fix me: this function could use some improvements, in particular checking
  591. // agains for example CF or 68000 limitations, etc
  592. result:=false;
  593. for ot in ots do
  594. begin
  595. case ot of
  596. OT_DATA:
  597. result:=(oper.typ=top_reg) and isintregister(oper.reg);
  598. OT_ADDR:
  599. result:=(oper.typ=top_reg) and isaddressregister(oper.reg);
  600. OT_ADDR_INDIR:
  601. result:=(oper.typ=top_ref) and isaddressregister(oper.ref^.base)
  602. and (oper.ref^.direction=dir_none) and (oper.ref^.index=NR_NO)
  603. and (oper.ref^.offset=0) and (oper.ref^.symbol=nil);
  604. OT_ADDR_INDIR_POSTINC:
  605. result:=(oper.typ=top_ref) and isaddressregister(oper.ref^.base)
  606. and (oper.ref^.direction=dir_inc) and (oper.ref^.index=NR_NO)
  607. and (oper.ref^.offset=0) and (oper.ref^.symbol=nil);
  608. OT_ADDR_INDIR_PREDEC:
  609. result:=(oper.typ=top_ref) and isaddressregister(oper.ref^.base)
  610. and (oper.ref^.direction=dir_dec) and (oper.ref^.index=NR_NO)
  611. and (oper.ref^.offset=0) and (oper.ref^.symbol=nil);
  612. OT_ADDR_DISP16:
  613. // fix me: also needs checking offset sizes, incl. 020+ base displacements!
  614. result:=(oper.typ=top_ref) and isaddressregister(oper.ref^.base)
  615. and (oper.ref^.direction=dir_none) and (oper.ref^.index=NR_NO)
  616. and (oper.ref^.symbol=nil);
  617. OT_ADDR_IDX_DISP8:
  618. // fix me: also needs checking offset sizes, incl. 020+ base displacements!
  619. result:=(oper.typ=top_ref) and isaddressregister(oper.ref^.base)
  620. and (isaddressregister(oper.ref^.index) or isintregister(oper.ref^.index))
  621. and (oper.ref^.direction=dir_none)
  622. and (oper.ref^.symbol=nil);
  623. OT_ABS_SHORT,
  624. // fix me: also needs checking sizes!
  625. OT_ABS_LONG:
  626. result:=((oper.typ=top_ref) and assigned(oper.ref^.symbol)
  627. and (oper.ref^.base=NR_NO) and (oper.ref^.index=NR_NO)
  628. and (oper.ref^.direction=dir_none)) or
  629. (oper.typ=top_const);
  630. OT_PC_DISP16:
  631. // fix me: also needs checking offset sizes, incl. 020+ base displacements!
  632. result:=(oper.typ=top_ref) and (oper.ref^.base=NR_PC)
  633. and (oper.ref^.direction=dir_none) and (oper.ref^.index=NR_NO)
  634. and (oper.ref^.symbol=nil);
  635. OT_PC_IDX_DISP8:
  636. // fix me: also needs checking offset sizes, incl. 020+ base displacements!
  637. result:=(oper.typ=top_ref) and (oper.ref^.base=NR_PC)
  638. and (isaddressregister(oper.ref^.index) or isintregister(oper.ref^.index))
  639. and (oper.ref^.direction=dir_none)
  640. and (oper.ref^.symbol=nil);
  641. OT_IMMEDIATE:
  642. // fix me: needs checking against OF_IMM_QUICK and others
  643. result:=(oper.typ=top_const);
  644. OT_REG_LIST:
  645. result:=(oper.typ=top_regset) and (oper.fpuregset=[]) and
  646. ((oper.dataregset<>[]) or (oper.addrregset<>[]));
  647. OT_FPUREG_LIST:
  648. result:=(oper.typ=top_regset) and (oper.fpuregset<>[]) and
  649. ((oper.dataregset=[]) or (oper.addrregset=[]));
  650. OT_FPUREG:
  651. result:=(oper.typ=top_reg) and isfpuregister(oper.reg);
  652. {OT_SPECIALREG}
  653. else
  654. internalerror(2023010101);
  655. end;
  656. if result then
  657. break;
  658. end;
  659. end;
  660. var
  661. i: Integer;
  662. begin
  663. result:=false;
  664. { Check the opcode and number of operands }
  665. if (p^.opcode<>opcode) or (p^.ops<>ops) then
  666. exit;
  667. { Check the operands }
  668. for i:=0 to p^.ops-1 do
  669. if not OperandsMatch(oper[i]^,p^.optypes[i]) then
  670. exit;
  671. result:=true;
  672. end;
  673. function taicpu.FindInsEntry(objdata: TObjData): boolean;
  674. var
  675. i : longint;
  676. begin
  677. result:=false;
  678. { Things which may only be done once, not when a second pass is done to
  679. optimize }
  680. if (InsEntry=nil) then
  681. begin
  682. { set the file postion }
  683. current_filepos:=fileinfo;
  684. end
  685. else
  686. begin
  687. { we've already an insentry so it's valid }
  688. result:=true;
  689. exit;
  690. end;
  691. { Lookup opcode in the table }
  692. InsSize:=-1;
  693. i:=InsTabCache^[opcode];
  694. if i=-1 then
  695. begin
  696. Message1(asmw_e_opcode_not_in_table,gas_op2str[opcode]);
  697. exit;
  698. end;
  699. InsEntry:=@instab[i];
  700. while (InsEntry^.opcode=opcode) do
  701. begin
  702. if Matches(insentry,objdata) then
  703. begin
  704. result:=true;
  705. exit;
  706. end;
  707. inc(insentry);
  708. end;
  709. Message1(asmw_e_invalid_opcode_and_operands,gas_op2str[opcode]{,GetString});
  710. { No instruction found, set insentry to nil and inssize to -1 }
  711. InsEntry:=nil;
  712. InsSize:=-1;
  713. end;
  714. procedure taicpu.GenCode(objdata: TObjData);
  715. procedure WriteWord(w: word);
  716. var
  717. bytes: array [0..1] of Byte;
  718. begin
  719. Word(bytes):=NToBE(w);
  720. objdata.writebytes(bytes,2);
  721. end;
  722. procedure OpcodeSetReg(opcode: word; regnum: byte);
  723. begin
  724. opcode:=(opcode and $fff8) or (regnum and $7);
  725. end;
  726. procedure OpcodeSetMode(opcode: word; mode: byte);
  727. begin
  728. opcode:=(opcode and $ffc7) or ((mode and $7) shl 3);
  729. end;
  730. procedure OpcodeSetEA(opcode: word; mode: byte; regnum: byte);
  731. begin
  732. opcode:=(opcode and $ffc0) or ((mode and $7) shl 3) or (regnum and $7);
  733. end;
  734. var
  735. i: longint;
  736. begin
  737. // writeln('GenCode: ',insentry^.opcode);
  738. for i:=0 to insentry^.codelen do
  739. WriteWord(insentry^.code[i]);
  740. end;
  741. procedure taicpu.ResetPass1;
  742. begin
  743. { we need to reset everything here, because the choosen insentry
  744. can be invalid for a new situation where the previously optimized
  745. insentry is not correct }
  746. InsEntry:=nil;
  747. InsSize:=0;
  748. LastInsOffset:=-1;
  749. end;
  750. procedure taicpu.ResetPass2;
  751. begin
  752. { we are here in a second pass, check if the instruction can be optimized }
  753. if assigned(InsEntry) then
  754. begin
  755. InsEntry:=nil;
  756. InsSize:=0;
  757. end;
  758. LastInsOffset:=-1;
  759. end;
  760. function taicpu.Pass1(objdata:TObjData):longint;
  761. begin
  762. Pass1:=0;
  763. { Save the old offset and set the new offset }
  764. InsOffset:=ObjData.CurrObjSec.Size;
  765. { Error? }
  766. if (InsEntry=nil) and (InsSize=-1) then
  767. exit;
  768. { set the file postion }
  769. current_filepos:=fileinfo;
  770. { Get InsEntry }
  771. if FindInsEntry(ObjData) then
  772. begin
  773. { Calculate instruction size }
  774. InsSize:=CalcSize(InsEntry);
  775. LastInsOffset:=InsOffset;
  776. Pass1:=InsSize;
  777. exit;
  778. end;
  779. LastInsOffset:=-1;
  780. end;
  781. procedure taicpu.Pass2(objdata: TObjData);
  782. begin
  783. { error in pass1 ? }
  784. if InsEntry=nil then
  785. exit;
  786. current_filepos:=fileinfo;
  787. { Generate the instruction }
  788. GenCode(ObjData);
  789. end;
  790. function spilling_create_load(const ref:treference;r:tregister):Taicpu;
  791. begin
  792. case getregtype(r) of
  793. R_INTREGISTER :
  794. result:=taicpu.op_ref_reg(A_MOVE,S_L,ref,r);
  795. R_ADDRESSREGISTER :
  796. result:=taicpu.op_ref_reg(A_MOVE,S_L,ref,r);
  797. R_FPUREGISTER :
  798. result:=taicpu.op_ref_reg(A_FMOVE,fpuregopsize,ref,r);
  799. else
  800. internalerror(200602011);
  801. end;
  802. end;
  803. function spilling_create_store(r:tregister; const ref:treference):Taicpu;
  804. begin
  805. case getregtype(r) of
  806. R_INTREGISTER :
  807. result:=taicpu.op_reg_ref(A_MOVE,S_L,r,ref);
  808. R_ADDRESSREGISTER :
  809. result:=taicpu.op_reg_ref(A_MOVE,S_L,r,ref);
  810. R_FPUREGISTER :
  811. result:=taicpu.op_reg_ref(A_FMOVE,fpuregopsize,r,ref);
  812. else
  813. internalerror(200602012);
  814. end;
  815. end;
  816. {****************************************************************************
  817. Instruction table
  818. *****************************************************************************}
  819. procedure BuildInsTabCache;
  820. var
  821. i : longint;
  822. begin
  823. new(InsTabCache);
  824. FillChar(InsTabCache^,sizeof(TInsTabCache),$ff);
  825. i:=0;
  826. while (i<InsTabEntries) do
  827. begin
  828. if InsTabCache^[InsTab[i].OPcode]=-1 then
  829. InsTabCache^[InsTab[i].OPcode]:=i;
  830. inc(i);
  831. end;
  832. end;
  833. procedure InitAsm;
  834. begin
  835. if not assigned(InsTabCache) then
  836. BuildInsTabCache;
  837. end;
  838. procedure DoneAsm;
  839. begin
  840. if assigned(InsTabCache) then
  841. begin
  842. dispose(InsTabCache);
  843. InsTabCache:=nil;
  844. end;
  845. end;
  846. begin
  847. cai_align:=tai_align;
  848. cai_cpu:=taicpu;
  849. end.