aasmcpu.pas 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. {******************************************************************************
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl and Peter Vreman
  4. * This code was inspired by the NASM sources
  5. The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  6. Julian Hall. All rights reserved.
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************}
  19. unit aasmcpu;
  20. {$INCLUDE fpcdefs.inc}
  21. interface
  22. uses
  23. cclasses,globals,verbose,
  24. cpuinfo,cpubase,
  25. symppu,
  26. aasmbase,aasmtai;
  27. const
  28. MaxPrefixes=4;
  29. type
  30. { alignment for operator }
  31. tai_align=class(tai_align_abstract)
  32. reg:tregister;
  33. constructor create(b:byte);
  34. constructor create_op(b:byte; _op:byte);
  35. end;
  36. taicpu = class(taicpu_abstract)
  37. opsize:topsize;
  38. constructor op_none(op:tasmop);
  39. constructor op_reg(op:tasmop;reg:tregister);
  40. constructor op_const(op:tasmop;_op1:aword);
  41. constructor op_ref(op:tasmop;const _op1:treference);
  42. constructor op_reg_reg(op:tasmop;_op1,_op2:tregister);
  43. constructor op_reg_ref(Op:TAsmOp;Reg:TRegister;const Ref:TReference);
  44. constructor op_reg_const(op:tasmop;_op1:tregister;_op2:aword);
  45. constructor op_const_reg(op:tasmop;_op1:aword;_op2:tregister);
  46. constructor op_ref_reg(Op:TAsmOp;const Ref:TReference;Reg:TRegister);
  47. constructor op_ref_ref(op:tasmop;_size:topsize;const _op1,_op2:treference);
  48. constructor op_reg_reg_reg(op:tasmop;_op1,_op2,_op3:tregister);
  49. constructor op_reg_const_reg(Op:TAsmOp;SrcReg:TRegister;value:aWord;DstReg:TRegister);
  50. constructor op_const_ref_reg(op:tasmop;_size:topsize;_op1:aword;const _op2:treference;_op3:tregister);
  51. constructor op_const_reg_ref(op:tasmop;_size:topsize;_op1:aword;_op2:tregister;const _op3:treference);
  52. { this is for Jmp instructions }
  53. constructor op_cond_sym(op:tasmop;cond:TAsmCond;_size:topsize;_op1:tasmsymbol);
  54. constructor op_sym(op:tasmop;_size:topsize;_op1:tasmsymbol);
  55. constructor op_sym_ofs(op:tasmop;_size:topsize;_op1:tasmsymbol;_op1ofs:longint);
  56. constructor op_sym_ofs_reg(op:tasmop;_size:topsize;_op1:tasmsymbol;_op1ofs:longint;_op2:tregister);
  57. constructor op_sym_ofs_ref(op:tasmop;_size:topsize;_op1:tasmsymbol;_op1ofs:longint;const _op2:treference);
  58. constructor op_caddr_reg(op:TAsmOp;rgb:TRegister;cnst:Integer;reg:TRegister);
  59. constructor op_raddr_reg(op:TAsmOp;rg1,rg2:TRegister;reg:TRegister);
  60. procedure changeopsize(siz:topsize);
  61. function GetString:string;
  62. procedure CheckNonCommutativeOpcodes;
  63. procedure loadcaddr(opidx:longint;aReg:TRegister;cnst:Integer);
  64. procedure loadraddr(opidx:longint;rg1,rg2:TRegister);
  65. private
  66. procedure init(_size:topsize);{this need to be called by all constructor}
  67. public
  68. { the next will reset all instructions that can change in pass 2 }
  69. procedure ResetPass1;
  70. procedure ResetPass2;
  71. function CheckIfValid:boolean;
  72. function Pass1(offset:longint):longint;virtual;
  73. private
  74. { next fields are filled in pass1, so pass2 is faster }
  75. insentry : PInsEntry;
  76. insoffset,
  77. inssize : longint;
  78. LastInsOffset : longint; { need to be public to be reset }
  79. function InsEnd:longint;
  80. procedure create_ot;
  81. function Matches(p:PInsEntry):longint;
  82. function calcsize(p:PInsEntry):longint;
  83. function NeedAddrPrefix(opidx:byte):boolean;
  84. procedure Swatoperands;
  85. end;
  86. PROCEDURE DoneAsm;
  87. PROCEDURE InitAsm;
  88. implementation
  89. uses
  90. cutils,
  91. CpuGas;
  92. const
  93. _size=S_SW;{To be removed soon}
  94. {****************************************************************************
  95. TAI_ALIGN
  96. ****************************************************************************}
  97. constructor tai_align.create(b:byte);
  98. begin
  99. inherited create(b);
  100. reg:= R_NONE;
  101. end;
  102. constructor tai_align.create_op(b:byte; _op:byte);
  103. begin
  104. inherited create_op(b,_op);
  105. reg:= R_NONE;
  106. end;
  107. {*****************************************************************************
  108. Taicpu Constructors
  109. *****************************************************************************}
  110. procedure taicpu.changeopsize(siz:topsize);
  111. begin
  112. opsize:=siz;
  113. end;
  114. procedure taicpu.init(_size:topsize);
  115. begin
  116. opsize:=_size;
  117. end;
  118. constructor taicpu.op_none(op:tasmop);
  119. begin
  120. inherited create(op);
  121. init(_size);
  122. end;
  123. constructor taicpu.op_reg(op:tasmop;reg:tregister);
  124. begin
  125. inherited create(op);
  126. init(_size);
  127. ops:=1;
  128. loadreg(0,reg);
  129. end;
  130. constructor taicpu.op_const(op:tasmop;_op1:aword);
  131. begin
  132. inherited create(op);
  133. init(_size);
  134. ops:=1;
  135. loadconst(0,aword(_op1));
  136. end;
  137. constructor taicpu.op_ref(op:tasmop;const _op1:treference);
  138. begin
  139. inherited create(op);
  140. init(_size);
  141. ops:=1;
  142. loadref(0,_op1);
  143. end;
  144. constructor taicpu.op_reg_reg(op:tasmop;_op1,_op2:tregister);
  145. begin
  146. inherited create(op);
  147. init(_size);
  148. ops:=2;
  149. loadreg(0,_op1);
  150. loadreg(1,_op2);
  151. end;
  152. constructor taicpu.op_reg_const(op:tasmop;_op1:tregister; _op2:aword);
  153. begin
  154. inherited create(op);
  155. init(_size);
  156. ops:=2;
  157. loadreg(0,_op1);
  158. loadconst(1,aword(_op2));
  159. end;
  160. constructor taicpu.op_reg_ref(Op:TAsmOp;Reg:TRegister;const Ref:TReference);
  161. begin
  162. if not(Op in [A_STB..A_STDFQ])
  163. then
  164. fail;
  165. inherited Create(Op);
  166. init(_size);
  167. ops:=2;
  168. LoadReg(0,Reg);
  169. LoadRef(1,Ref);
  170. end;
  171. constructor taicpu.op_const_reg(op:tasmop;_op1:aword;_op2:tregister);
  172. begin
  173. inherited create(op);
  174. init(_size);
  175. ops:=2;
  176. loadconst(0,aword(_op1));
  177. loadreg(1,_op2);
  178. end;
  179. constructor TAiCpu.op_ref_reg(Op:TAsmOp;const Ref:TReference;Reg:TRegister);
  180. begin
  181. if not(Op in [A_JMPL,A_FLUSH,A_LDSB..A_LDDC,A_RETT,A_SWAP])
  182. then
  183. fail;
  184. inherited Create(Op);
  185. Init(S_SW);
  186. Ops:=2;
  187. LoadRef(0,Ref);
  188. LoadReg(1,Reg);
  189. end;
  190. constructor taicpu.op_ref_ref(op:tasmop;_size:topsize;const _op1,_op2:treference);
  191. begin
  192. inherited create(op);
  193. init(_size);
  194. ops:=2;
  195. loadref(0,_op1);
  196. loadref(1,_op2);
  197. end;
  198. constructor taicpu.op_reg_reg_reg(op:tasmop;_op1,_op2,_op3:tregister);
  199. begin
  200. inherited create(op);
  201. init(_size);
  202. ops:=3;
  203. loadreg(0,_op1);
  204. loadreg(1,_op2);
  205. loadreg(2,_op3);
  206. end;
  207. constructor taicpu.op_reg_const_reg(op:TAsmOp;SrcReg:TRegister;Value:aWord;DstReg:TRegister);
  208. begin
  209. inherited Create(Op);
  210. Init(S_W);
  211. ops:=3;
  212. LoadReg(0,SrcReg);
  213. LoadConst(1,Value);
  214. LoadReg(2,DstReg);
  215. end;
  216. constructor taicpu.op_const_ref_reg(op:tasmop;_size:topsize;_op1:aword;const _op2:treference;_op3:tregister);
  217. begin
  218. inherited create(op);
  219. init(_size);
  220. ops:=3;
  221. loadconst(0,aword(_op1));
  222. loadref(1,_op2);
  223. loadreg(2,_op3);
  224. end;
  225. constructor taicpu.op_const_reg_ref(op:tasmop;_size:topsize;_op1:aword;_op2:tregister;const _op3:treference);
  226. begin
  227. inherited create(op);
  228. init(_size);
  229. ops:=3;
  230. loadconst(0,aword(_op1));
  231. loadreg(1,_op2);
  232. loadref(2,_op3);
  233. end;
  234. constructor taicpu.op_cond_sym(op:tasmop;cond:TAsmCond;_size:topsize;_op1:tasmsymbol);
  235. begin
  236. inherited create(op);
  237. init(_size);
  238. condition:=cond;
  239. ops:=1;
  240. loadsymbol(0,_op1,0);
  241. end;
  242. constructor taicpu.op_sym(op:tasmop;_size:topsize;_op1:tasmsymbol);
  243. begin
  244. inherited create(op);
  245. init(_size);
  246. ops:=1;
  247. loadsymbol(0,_op1,0);
  248. end;
  249. constructor taicpu.op_sym_ofs(op:tasmop;_size:topsize;_op1:tasmsymbol;_op1ofs:longint);
  250. begin
  251. inherited create(op);
  252. init(_size);
  253. ops:=1;
  254. loadsymbol(0,_op1,_op1ofs);
  255. end;
  256. constructor taicpu.op_sym_ofs_reg(op:tasmop;_size:topsize;_op1:tasmsymbol;_op1ofs:longint;_op2:tregister);
  257. begin
  258. inherited create(op);
  259. init(_size);
  260. ops:=2;
  261. loadsymbol(0,_op1,_op1ofs);
  262. loadreg(1,_op2);
  263. end;
  264. constructor taicpu.op_sym_ofs_ref(op:tasmop;_size:topsize;_op1:tasmsymbol;_op1ofs:longint;const _op2:treference);
  265. begin
  266. inherited create(op);
  267. init(_size);
  268. ops:=2;
  269. loadsymbol(0,_op1,_op1ofs);
  270. loadref(1,_op2);
  271. end;
  272. constructor taicpu.op_caddr_reg(op:TAsmOp;rgb:TRegister;cnst:Integer;reg:TRegister);
  273. begin
  274. inherited create(op);
  275. init(S_SW);
  276. ops:=2;
  277. WriteLn(1,std_reg2str[rgb]);
  278. loadcaddr(0,rgb,cnst);
  279. WriteLn(2,std_reg2str[rgb]);
  280. loadreg(1,reg);
  281. end;
  282. constructor taicpu.op_raddr_reg(op:TAsmOp;rg1,rg2,reg:TRegister);
  283. begin
  284. inherited create(op);
  285. init(S_SW);
  286. ops:=2;
  287. loadraddr(0,rg1,rg2);
  288. loadreg(1,reg);
  289. end;
  290. function taicpu.GetString:string;
  291. var
  292. i:longint;
  293. s:string;
  294. addsize:boolean;
  295. begin
  296. s:='['+std_op2str[opcode];
  297. for i:=1to ops do
  298. begin
  299. if i=1 then
  300. s:=s+' '
  301. else
  302. s:=s+',';
  303. { type }
  304. addsize:=false;
  305. if (oper[i-1].ot and OT_XMMREG)=OT_XMMREG then
  306. s:=s+'xmmreg'
  307. else
  308. if (oper[i-1].ot and OT_MMXREG)=OT_MMXREG then
  309. s:=s+'mmxreg'
  310. else
  311. if (oper[i-1].ot and OT_FPUREG)=OT_FPUREG then
  312. s:=s+'fpureg'
  313. else
  314. if (oper[i-1].ot and OT_REGISTER)=OT_REGISTER then
  315. begin
  316. s:=s+'reg';
  317. addsize:=true;
  318. end
  319. else
  320. if (oper[i-1].ot and OT_IMMEDIATE)=OT_IMMEDIATE then
  321. begin
  322. s:=s+'imm';
  323. addsize:=true;
  324. end
  325. else
  326. if (oper[i-1].ot and OT_MEMORY)=OT_MEMORY then
  327. begin
  328. s:=s+'mem';
  329. addsize:=true;
  330. end
  331. else
  332. s:=s+'???';
  333. { size }
  334. if addsize then
  335. begin
  336. if (oper[i-1].ot and OT_BITS8)<>0 then
  337. s:=s+'8'
  338. else
  339. if (oper[i-1].ot and OT_BITS16)<>0 then
  340. s:=s+'16'
  341. else
  342. if (oper[i-1].ot and OT_BITS32)<>0 then
  343. s:=s+'32'
  344. else
  345. s:=s+'??';
  346. { signed }
  347. if (oper[i-1].ot and OT_SIGNED)<>0 then
  348. s:=s+'s';
  349. end;
  350. end;
  351. GetString:=s+']';
  352. end;
  353. procedure taicpu.Swatoperands;
  354. var
  355. p:TOper;
  356. begin
  357. { Fix the operands which are in AT&T style and we need them in Intel style }
  358. case ops of
  359. 2:begin
  360. { 0,1 -> 1,0 }
  361. p:=oper[0];
  362. oper[0]:=oper[1];
  363. oper[1]:=p;
  364. end;
  365. 3:begin
  366. { 0,1,2 -> 2,1,0 }
  367. p:=oper[0];
  368. oper[0]:=oper[2];
  369. oper[2]:=p;
  370. end;
  371. end;
  372. end;
  373. { This check must be done with the operand in ATT order
  374. i.e.after swapping in the intel reader
  375. but before swapping in the NASM and TASM writers PM }
  376. procedure taicpu.CheckNonCommutativeOpcodes;
  377. begin
  378. { if ((ops=2) and
  379. (oper[0].typ=top_reg) and
  380. (oper[1].typ=top_reg) and
  381. (oper[0].reg IN [R_F0..RF31])) or
  382. (ops=0) then
  383. if opcode=A_FSUBR then
  384. opcode:=A_FSUB
  385. else if opcode=A_FSUB then
  386. opcode:=A_FSUBR
  387. else if opcode=A_FDIVR then
  388. opcode:=A_FDIV
  389. else if opcode=A_FDIV then
  390. opcode:=A_FDIVR
  391. else if opcode=A_FSUBRP then
  392. opcode:=A_FSUBP
  393. else if opcode=A_FSUBP then
  394. opcode:=A_FSUBRP
  395. else if opcode=A_FDIVRP then
  396. opcode:=A_FDIVP
  397. else if opcode=A_FDIVP then
  398. opcode:=A_FDIVRP;
  399. if ((ops=1) and
  400. (oper[0].typ=top_reg) and
  401. (oper[0].reg in [R_ST1..R_ST7])) then
  402. if opcode=A_FSUBRP then
  403. opcode:=A_FSUBP
  404. else if opcode=A_FSUBP then
  405. opcode:=A_FSUBRP
  406. else if opcode=A_FDIVRP then
  407. opcode:=A_FDIVP
  408. else if opcode=A_FDIVP then
  409. opcode:=A_FDIVRP;}
  410. end;
  411. {*****************************************************************************
  412. Assembler
  413. *****************************************************************************}
  414. type
  415. ea=packed record
  416. sib_present:boolean;
  417. bytes:byte;
  418. size:byte;
  419. modrm:byte;
  420. sib:byte;
  421. end;
  422. procedure taicpu.create_ot;
  423. {
  424. this function will also fix some other fields which only needs to be once
  425. }
  426. var
  427. i,l,relsize:longint;
  428. begin
  429. if ops=0 then
  430. exit;
  431. { update oper[].ot field }
  432. for i:=0 to ops-1 do
  433. with oper[i] do
  434. begin
  435. case typ of
  436. top_reg:
  437. {ot:=reg2type[reg]};
  438. top_ref:
  439. begin
  440. { create ot field }
  441. {if (ot and OT_SIZE_MASK)=0 then
  442. ot:=OT_MEMORY or opsize_2_type[i,opsize]
  443. else
  444. ot:=OT_MEMORY or (ot and OT_SIZE_MASK);
  445. if (ref^.base=R_NONE) and (ref^.index=R_NONE) then
  446. ot:=ot or OT_MEM_OFFS;}
  447. { fix scalefactor }
  448. if (ref^.index=R_NONE) then
  449. ref^.scalefactor:=0
  450. else
  451. if (ref^.scalefactor=0) then
  452. ref^.scalefactor:=1;
  453. end;
  454. top_const:
  455. begin
  456. if (opsize<>S_W) and (longint(val)>=-128) and (val<=127) then
  457. ot:=OT_IMM8 or OT_SIGNED
  458. else
  459. ot:=OT_IMMEDIATE {or opsize_2_type[i,opsize];}
  460. end;
  461. top_symbol:
  462. begin
  463. if LastInsOffset=-1 then
  464. l:=0
  465. else
  466. l:=InsOffset-LastInsOffset;
  467. inc(l,symofs);
  468. if assigned(sym) then
  469. inc(l,sym.address);
  470. { instruction size will then always become 2 (PFV) }
  471. relsize:=(InsOffset+2)-l;
  472. if (not assigned(sym) or
  473. ((sym.currbind<>AB_EXTERNAL) and (sym.address<>0))) and
  474. (relsize>=-128) and (relsize<=127) then
  475. ot:=OT_IMM32 or OT_SHORT
  476. else
  477. ot:=OT_IMM32 or OT_NEAR;
  478. end;
  479. end;
  480. end;
  481. end;
  482. function taicpu.InsEnd:longint;
  483. begin
  484. InsEnd:=InsOffset+InsSize;
  485. end;
  486. function taicpu.Matches(p:PInsEntry):longint;
  487. { * IF_SM stands for Size Match:any operand whose size is not
  488. * explicitly specified by the template is `really' intended to be
  489. * the same size as the first size-specified operand.
  490. * Non-specification is tolerated in the input instruction, but
  491. * _wrong_ specification is not.
  492. *
  493. * IF_SM2 invokes Size Match on only the first _two_ operands, for
  494. * three-operand instructions such as SHLD:it implies that the
  495. * first two operands must match in size, but that the third is
  496. * required to be _unspecified_.
  497. *
  498. * IF_SB invokes Size Byte:operands with unspecified size in the
  499. * template are really bytes, and so no non-byte specification in
  500. * the input instruction will be tolerated. IF_SW similarly invokes
  501. * Size Word, and IF_SD invokes Size Doubleword.
  502. *
  503. * (The default state if neither IF_SM nor IF_SM2 is specified is
  504. * that any operand with unspecified size in the template is
  505. * required to have unspecified size in the instruction too...)
  506. }
  507. var
  508. i,j,asize,oprs:longint;
  509. siz:array[0..2] of longint;
  510. begin
  511. Matches:=100;
  512. { Check the opcode and operands }
  513. if (p^.opcode<>opcode) or (p^.ops<>ops) then
  514. begin
  515. Matches:=0;
  516. exit;
  517. end;
  518. { Check that no spurious colons or TOs are present }
  519. for i:=0 to p^.ops-1 do
  520. if (oper[i].ot and (not p^.optypes[i]) and (OT_COLON or OT_TO))<>0 then
  521. begin
  522. Matches:=0;
  523. exit;
  524. end;
  525. { Check that the operand flags all match up }
  526. for i:=0 to p^.ops-1 do
  527. begin
  528. if ((p^.optypes[i] and (not oper[i].ot)) or
  529. ((p^.optypes[i] and OT_SIZE_MASK) and
  530. ((p^.optypes[i] xor oper[i].ot) and OT_SIZE_MASK)))<>0 then
  531. begin
  532. if ((p^.optypes[i] and (not oper[i].ot) and OT_NON_SIZE) or
  533. (oper[i].ot and OT_SIZE_MASK))<>0 then
  534. begin
  535. Matches:=0;
  536. exit;
  537. end
  538. else
  539. Matches:=1;
  540. end;
  541. end;
  542. { Check operand sizes }
  543. { as default an untyped size can get all the sizes, this is different
  544. from nasm, but else we need to do a lot checking which opcodes want
  545. size or not with the automatic size generation }
  546. asize:=longint($ffffffff);
  547. if (p^.flags and IF_SB)<>0 then
  548. asize:=OT_BITS8
  549. else if (p^.flags and IF_SW)<>0 then
  550. asize:=OT_BITS16
  551. else if (p^.flags and IF_SD)<>0 then
  552. asize:=OT_BITS32;
  553. if (p^.flags and IF_ARMASK)<>0 then
  554. begin
  555. siz[0]:=0;
  556. siz[1]:=0;
  557. siz[2]:=0;
  558. if (p^.flags and IF_AR0)<>0 then
  559. siz[0]:=asize
  560. else if (p^.flags and IF_AR1)<>0 then
  561. siz[1]:=asize
  562. else if (p^.flags and IF_AR2)<>0 then
  563. siz[2]:=asize;
  564. end
  565. else
  566. begin
  567. { we can leave because the size for all operands is forced to be
  568. the same
  569. but not if IF_SB IF_SW or IF_SD is set PM }
  570. if asize=-1 then
  571. exit;
  572. siz[0]:=asize;
  573. siz[1]:=asize;
  574. siz[2]:=asize;
  575. end;
  576. if (p^.flags and (IF_SM or IF_SM2))<>0 then
  577. begin
  578. if (p^.flags and IF_SM2)<>0 then
  579. oprs:=2
  580. else
  581. oprs:=p^.ops;
  582. for i:=0 to oprs-1 do
  583. if ((p^.optypes[i] and OT_SIZE_MASK) <> 0) then
  584. begin
  585. for j:=0 to oprs-1 do
  586. siz[j]:=p^.optypes[i] and OT_SIZE_MASK;
  587. break;
  588. end;
  589. end
  590. else
  591. oprs:=2;
  592. { Check operand sizes }
  593. for i:=0 to p^.ops-1 do
  594. begin
  595. if ((p^.optypes[i] and OT_SIZE_MASK)=0) and
  596. ((oper[i].ot and OT_SIZE_MASK and (not siz[i]))<>0) and
  597. { Immediates can always include smaller size }
  598. ((oper[i].ot and OT_IMMEDIATE)=0) and
  599. (((p^.optypes[i] and OT_SIZE_MASK) or siz[i])<(oper[i].ot and OT_SIZE_MASK)) then
  600. Matches:=2;
  601. end;
  602. end;
  603. procedure taicpu.ResetPass1;
  604. begin
  605. { we need to reset everything here, because the choosen insentry
  606. can be invalid for a new situation where the previously optimized
  607. insentry is not correct }
  608. InsEntry:=nil;
  609. InsSize:=0;
  610. LastInsOffset:=-1;
  611. end;
  612. procedure taicpu.ResetPass2;
  613. begin
  614. { we are here in a second pass, check if the instruction can be optimized }
  615. if assigned(InsEntry) and
  616. ((InsEntry^.flags and IF_PASS2)<>0) then
  617. begin
  618. InsEntry:=nil;
  619. InsSize:=0;
  620. end;
  621. LastInsOffset:=-1;
  622. end;
  623. function taicpu.CheckIfValid:boolean;
  624. var
  625. m,i:longint;
  626. begin
  627. CheckIfValid:=false;
  628. { Things which may only be done once, not when a second pass is done to
  629. optimize }
  630. if (Insentry=nil) or ((InsEntry^.flags and IF_PASS2)<>0) then
  631. begin
  632. { create the .ot fields }
  633. create_ot;
  634. { set the file postion }
  635. aktfilepos:=fileinfo;
  636. end
  637. else
  638. begin
  639. { we've already an insentry so it's valid }
  640. CheckIfValid:=true;
  641. exit;
  642. end;
  643. { Lookup opcode in the table }
  644. InsSize:=-1;
  645. i:=instabcache^[opcode];
  646. if i=-1 then
  647. begin
  648. {$ifdef TP}
  649. Message1(asmw_e_opcode_not_in_table,'');
  650. {$else}
  651. Message1(asmw_e_opcode_not_in_table,std_op2str[opcode]);
  652. {$endif}
  653. exit;
  654. end;
  655. // insentry:=@instab[i];
  656. while (insentry^.opcode=opcode) do
  657. begin
  658. m:=matches(insentry);
  659. if m=100 then
  660. begin
  661. InsSize:=calcsize(insentry);
  662. {if (segprefix<>R_NONE) then
  663. inc(InsSize);}{No segprefix!}
  664. { For opsize if size if forced }
  665. if (insentry^.flags and (IF_SB or IF_SW or IF_SD))<>0 then
  666. begin
  667. if (insentry^.flags and IF_ARMASK)=0 then
  668. begin
  669. if (insentry^.flags and IF_SB)<>0 then
  670. begin
  671. if opsize=S_NO then
  672. opsize:=S_B;
  673. end
  674. else if (insentry^.flags and IF_SW)<>0 then
  675. begin
  676. if opsize=S_NO then
  677. opsize:=S_W;
  678. end
  679. else if (insentry^.flags and IF_SD)<>0 then
  680. begin
  681. if opsize=S_NO then
  682. opsize:=S_SW;
  683. end;
  684. end;
  685. end;
  686. CheckIfValid:=true;
  687. exit;
  688. end;
  689. inc(i);
  690. // insentry:=@instab[i];
  691. end;
  692. if insentry^.opcode<>opcode then
  693. Message1(asmw_e_invalid_opcode_and_operands,GetString);
  694. { No instruction found, set insentry to nil and inssize to -1 }
  695. insentry:=nil;
  696. inssize:=-1;
  697. end;
  698. function taicpu.Pass1(offset:longint):longint;
  699. begin
  700. Pass1:=0;
  701. { Save the old offset and set the new offset }
  702. InsOffset:=Offset;
  703. { Things which may only be done once, not when a second pass is done to
  704. optimize }
  705. if Insentry=nil then
  706. begin
  707. { Check if error last time then InsSize=-1 }
  708. if InsSize=-1 then
  709. exit;
  710. { set the file postion }
  711. aktfilepos:=fileinfo;
  712. end
  713. else
  714. begin
  715. {$ifdef PASS2FLAG}
  716. { we are here in a second pass, check if the instruction can be optimized }
  717. if (InsEntry^.flags and IF_PASS2)=0 then
  718. begin
  719. Pass1:=InsSize;
  720. exit;
  721. end;
  722. { update the .ot fields, some top_const can be updated }
  723. create_ot;
  724. {$endif}
  725. end;
  726. { Check if it's a valid instruction }
  727. if CheckIfValid then
  728. begin
  729. LastInsOffset:=InsOffset;
  730. Pass1:=InsSize;
  731. exit;
  732. end;
  733. LastInsOffset:=-1;
  734. end;
  735. function taicpu.NeedAddrPrefix(opidx:byte):boolean;
  736. var
  737. i,b:tregister;
  738. begin
  739. { if (OT_MEMORY and (not oper[opidx].ot))=0 then
  740. begin
  741. i:=oper[opidx].ref^.index;
  742. b:=oper[opidx].ref^.base;
  743. if not(i in [R_NONE,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) or
  744. not(b in [R_NONE,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) then
  745. begin
  746. NeedAddrPrefix:=true;
  747. exit;
  748. end;
  749. end;}
  750. NeedAddrPrefix:=false;
  751. end;
  752. function regval(r:tregister):byte;
  753. begin
  754. {case r of
  755. R_EAX,R_AX,R_AL,R_ES,R_CR0,R_DR0,R_ST,R_ST0,R_MM0,R_XMM0:
  756. regval:=0;
  757. R_ECX,R_CX,R_CL,R_CS,R_DR1,R_ST1,R_MM1,R_XMM1:
  758. regval:=1;
  759. R_EDX,R_DX,R_DL,R_SS,R_CR2,R_DR2,R_ST2,R_MM2,R_XMM2:
  760. regval:=2;
  761. R_EBX,R_BX,R_BL,R_DS,R_CR3,R_DR3,R_TR3,R_ST3,R_MM3,R_XMM3:
  762. regval:=3;
  763. R_ESP,R_SP,R_AH,R_FS,R_CR4,R_TR4,R_ST4,R_MM4,R_XMM4:
  764. regval:=4;
  765. R_EBP,R_BP,R_CH,R_GS,R_TR5,R_ST5,R_MM5,R_XMM5:
  766. regval:=5;
  767. R_ESI,R_SI,R_DH,R_DR6,R_TR6,R_ST6,R_MM6,R_XMM6:
  768. regval:=6;
  769. R_EDI,R_DI,R_BH,R_DR7,R_TR7,R_ST7,R_MM7,R_XMM7:
  770. regval:=7;
  771. else}
  772. begin
  773. internalerror(777001);
  774. regval:=0;
  775. end;
  776. { end;}
  777. end;
  778. function process_ea(const input:toper;var output:ea;rfield:longint):boolean;
  779. {const
  780. regs:array[0..63] of tregister=(
  781. R_MM0, R_EAX, R_AX, R_AL, R_XMM0, R_NONE, R_NONE, R_NONE,
  782. R_MM1, R_ECX, R_CX, R_CL, R_XMM1, R_NONE, R_NONE, R_NONE,
  783. R_MM2, R_EDX, R_DX, R_DL, R_XMM2, R_NONE, R_NONE, R_NONE,
  784. R_MM3, R_EBX, R_BX, R_BL, R_XMM3, R_NONE, R_NONE, R_NONE,
  785. R_MM4, R_ESP, R_SP, R_AH, R_XMM4, R_NONE, R_NONE, R_NONE,
  786. R_MM5, R_EBP, R_BP, R_CH, R_XMM5, R_NONE, R_NONE, R_NONE,
  787. R_MM6, R_ESI, R_SI, R_DH, R_XMM6, R_NONE, R_NONE, R_NONE,
  788. R_MM7, R_EDI, R_DI, R_BH, R_XMM7, R_NONE, R_NONE, R_NONE
  789. );}
  790. var
  791. j:longint;
  792. i,b:tregister;
  793. sym:tasmsymbol;
  794. md,s:byte;
  795. base,index,scalefactor,
  796. o:longint;
  797. begin
  798. process_ea:=false;
  799. { register ? }
  800. { if (input.typ=top_reg) then
  801. begin
  802. j:=0;
  803. while (j<=high(regs)) do
  804. begin
  805. if input.reg=regs[j] then
  806. break;
  807. inc(j);
  808. end;
  809. if j<=high(regs) then
  810. begin
  811. output.sib_present:=false;
  812. output.bytes:=0;
  813. output.modrm:=$c0 or (rfield shl 3) or (j shr 3);
  814. output.size:=1;
  815. process_ea:=true;
  816. end;
  817. exit;
  818. end;}
  819. { memory reference }
  820. i:=input.ref^.index;
  821. b:=input.ref^.base;
  822. s:=input.ref^.scalefactor;
  823. o:=input.ref^.offset+input.ref^.offsetfixup;
  824. sym:=input.ref^.symbol;
  825. { it's direct address }
  826. if (b=R_NONE) and (i=R_NONE) then
  827. begin
  828. { it's a pure offset }
  829. output.sib_present:=false;
  830. output.bytes:=4;
  831. output.modrm:=5 or (rfield shl 3);
  832. end
  833. else
  834. { it's an indirection }
  835. begin
  836. { 16 bit address? }
  837. { if not((i in [R_NONE,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI]) and
  838. (b in [R_NONE,R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESP,R_ESI,R_EDI])) then
  839. Message(asmw_e_16bit_not_supported);}
  840. {$ifdef OPTEA}
  841. { make single reg base }
  842. if (b=R_NONE) and (s=1) then
  843. begin
  844. b:=i;
  845. i:=R_NONE;
  846. end;
  847. { convert [3,5,9]*EAX to EAX+[2,4,8]*EAX }
  848. { if (b=R_NONE) and
  849. (((s=2) and (i<>R_ESP)) or
  850. (s=3) or (s=5) or (s=9)) then
  851. begin
  852. b:=i;
  853. dec(s);
  854. end;}
  855. { swap ESP into base if scalefactor is 1 }
  856. { if (s=1) and (i=R_ESP) then
  857. begin
  858. i:=b;
  859. b:=R_ESP;
  860. end;}
  861. {$endif}
  862. { wrong, for various reasons }
  863. { if (i=R_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (i<>R_NONE)) then
  864. exit;}
  865. { base }
  866. { case b of
  867. R_EAX:base:=0;
  868. R_ECX:base:=1;
  869. R_EDX:base:=2;
  870. R_EBX:base:=3;
  871. R_ESP:base:=4;
  872. R_NONE,
  873. R_EBP:base:=5;
  874. R_ESI:base:=6;
  875. R_EDI:base:=7;
  876. else
  877. exit;
  878. end;}
  879. { index }
  880. { case i of
  881. R_EAX:index:=0;
  882. R_ECX:index:=1;
  883. R_EDX:index:=2;
  884. R_EBX:index:=3;
  885. R_NONE:index:=4;
  886. R_EBP:index:=5;
  887. R_ESI:index:=6;
  888. R_EDI:index:=7;
  889. else
  890. exit;
  891. end;
  892. case s of
  893. 0,
  894. 1:scalefactor:=0;
  895. 2:scalefactor:=1;
  896. 4:scalefactor:=2;
  897. 8:scalefactor:=3;
  898. else
  899. exit;
  900. end;
  901. if (b=R_NONE) or
  902. ((b<>R_EBP) and (o=0) and (sym=nil)) then
  903. md:=0
  904. else
  905. if ((o>=-128) and (o<=127) and (sym=nil)) then
  906. md:=1
  907. else
  908. md:=2;
  909. if (b=R_NONE) or (md=2) then
  910. output.bytes:=4
  911. else
  912. output.bytes:=md;}
  913. { SIB needed ? }
  914. { if (i=R_NONE) and (b<>R_ESP) then
  915. begin
  916. output.sib_present:=false;
  917. output.modrm:=(md shl 6) or (rfield shl 3) or base;
  918. end
  919. else
  920. begin
  921. output.sib_present:=true;
  922. output.modrm:=(md shl 6) or (rfield shl 3) or 4;
  923. output.sib:=(scalefactor shl 6) or (index shl 3) or base;
  924. end;}
  925. end;
  926. if output.sib_present then
  927. output.size:=2+output.bytes
  928. else
  929. output.size:=1+output.bytes;
  930. process_ea:=true;
  931. end;
  932. function taicpu.calcsize(p:PInsEntry):longint;
  933. var
  934. codes:pchar;
  935. c:byte;
  936. len:longint;
  937. ea_data:ea;
  938. begin
  939. len:=0;
  940. codes:=@p^.code;
  941. repeat
  942. c:=ord(codes^);
  943. inc(codes);
  944. case c of
  945. 0:
  946. break;
  947. 1,2,3:
  948. begin
  949. inc(codes,c);
  950. inc(len,c);
  951. end;
  952. 8,9,10:
  953. begin
  954. inc(codes);
  955. inc(len);
  956. end;
  957. 4,5,6,7:
  958. begin
  959. if opsize=S_W then
  960. inc(len,2)
  961. else
  962. inc(len);
  963. end;
  964. 15,
  965. 12,13,14,
  966. 16,17,18,
  967. 20,21,22,
  968. 40,41,42:
  969. inc(len);
  970. 24,25,26,
  971. 31,
  972. 48,49,50:
  973. inc(len,2);
  974. 28,29,30, { we don't have 16 bit immediates code }
  975. 32,33,34,
  976. 52,53,54,
  977. 56,57,58:
  978. inc(len,4);
  979. 192,193,194:
  980. if NeedAddrPrefix(c-192) then
  981. inc(len);
  982. 208:
  983. inc(len);
  984. 200,
  985. 201,
  986. 202,
  987. 209,
  988. 210,
  989. 217,218,219:;
  990. 216:
  991. begin
  992. inc(codes);
  993. inc(len);
  994. end;
  995. 224,225,226:
  996. begin
  997. InternalError(777002);
  998. end;
  999. else
  1000. begin
  1001. if (c>=64) and (c<=191) then
  1002. begin
  1003. if not process_ea(oper[(c shr 3) and 7], ea_data, 0) then
  1004. Message(asmw_e_invalid_effective_address)
  1005. else
  1006. inc(len,ea_data.size);
  1007. end
  1008. else
  1009. InternalError(777003);
  1010. end;
  1011. end;
  1012. until false;
  1013. calcsize:=len;
  1014. end;
  1015. procedure taicpu.loadcaddr(opidx:longint;aReg:TRegister;cnst:Integer);
  1016. begin
  1017. if opidx>=ops
  1018. then
  1019. ops:=opidx+1;
  1020. with oper[opidx] do
  1021. begin
  1022. typ:=top_caddr;
  1023. regb:=aReg;
  1024. const13:=cnst;
  1025. end;
  1026. end;
  1027. procedure taicpu.loadraddr(opidx:longint;rg1,rg2:TRegister);
  1028. begin
  1029. if opidx>=ops
  1030. then
  1031. ops:=opidx+1;
  1032. with oper[opidx] do
  1033. begin
  1034. typ:=top_caddr;
  1035. reg1:=rg1;
  1036. reg2:=rg2;
  1037. end;
  1038. end;
  1039. procedure DoneAsm;
  1040. begin
  1041. end;
  1042. procedure InitAsm;
  1043. begin
  1044. end;
  1045. end.
  1046. {
  1047. $Log$
  1048. Revision 1.14 2002-12-14 15:02:03 carl
  1049. * maxoperands -> max_operands (for portability in rautils.pas)
  1050. * fix some range-check errors with loadconst
  1051. + add ncgadd unit to m68k
  1052. * some bugfix of a_param_reg with LOC_CREFERENCE
  1053. Revision 1.13 2002/11/17 16:32:04 carl
  1054. * memory optimization (3-4%) : cleanup of tai fields,
  1055. cleanup of tdef and tsym fields.
  1056. * make it work for m68k
  1057. Revision 1.12 2002/11/10 19:07:46 mazen
  1058. * SPARC calling mechanism almost OK (as in GCC./mppcsparc )
  1059. Revision 1.11 2002/11/06 11:31:24 mazen
  1060. * op_reg_reg_reg don't need any more a TOpSize parameter
  1061. Revision 1.10 2002/11/05 16:15:00 mazen
  1062. *** empty log message ***
  1063. Revision 1.9 2002/10/28 20:59:17 mazen
  1064. * TOpSize values changed S_L --> S_SW
  1065. Revision 1.8 2002/10/22 13:43:01 mazen
  1066. - cga.pas redueced to an empty unit
  1067. Revision 1.7 2002/10/20 19:01:38 mazen
  1068. + op_raddr_reg and op_caddr_reg added to fix functions prologue
  1069. Revision 1.6 2002/10/19 20:35:07 mazen
  1070. * carl's patch applied
  1071. Revision 1.5 2002/10/15 09:00:28 mazen
  1072. * sone coding style modified
  1073. Revision 1.4 2002/10/13 21:46:07 mazen
  1074. * assembler output format fixed
  1075. }