aasmcpu.pas 31 KB

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