aasmcpu.pas 29 KB

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