aasmcpu.pas 32 KB

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