aasmcpu.pas 29 KB

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