aasmcpu.pas 28 KB

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