aasmcpu.pas 28 KB

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