FoxAMD64Assembler.Mod 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732
  1. MODULE FoxAMD64Assembler; (** AUTHOR "fn & fof"; PURPOSE "Oberon Compiler:AMD 64 Assembler"; **)
  2. (* (c) fof ETH Zürich, 2008 *)
  3. (*
  4. this module has in great portions been taken over from Florian Negele's PCAAMD64.Mod
  5. *)
  6. IMPORT
  7. Basic := FoxBasic, Scanner := FoxScanner, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, InstructionSet := FoxAMD64InstructionSet, Sections := FoxSections,
  8. BinaryCode := FoxBinaryCode, SYSTEM, Streams, Strings, Commands, KernelLog, Diagnostics, IntermediateCode := FoxIntermediateCode, ObjectFile
  9. ;
  10. CONST
  11. Trace= FALSE;
  12. none* = InstructionSet.none;
  13. (* rex prefix bit positions *)
  14. rexB = 0;
  15. rexX = 1;
  16. rexR = 2;
  17. rexW= 3;
  18. rex = 4;
  19. (* register indices, the numbers have a meaning in instruction encoding, do not modify *)
  20. RAX* = 0; EAX*=0; AX*=0; AL*=0;
  21. RCX* = 1; ECX*=1; CX*=1; CL*=1;
  22. RDX* = 2;EDX*=2; DX*=2; DL*=2;
  23. RBX* = 3;EBX*=3; BX*=3; BL*=3;
  24. RSP* = 4; ESP*=4; SP*=5; SPL*=4; AH*=4;
  25. RBP* = 5; EBP*=5; BP*=5; BPL*=5; CH*=5;
  26. RSI* = 6; ESI*=6; SI*=6; SIL*=6; DH*=6;
  27. RDI* = 7;EDI*=7; DI*=7; DIL*=7; BH*=7;
  28. R8*= 8; R8D*=8; R8W*=8; R8B*=8;
  29. R9* = 9;R9D*=9; R9W*=9; R9B*=9;
  30. R10* = 10;R10D*=10; R10W*=10; R10B*=10;
  31. R11* = 11;R11D*=11; R11W*=11; R11B*=11;
  32. R12* = 12;R12D*=12; R12W*=12; R12B*=12;
  33. R13* = 13;R13D*=13; R13W*=13; R13B*=13;
  34. R14* = 14;R14D*=14; R14W*=14; R14B*=14;
  35. R15* = 15;R15D*=15; R15W*=15; R15B*=15;
  36. RIP* = 16;
  37. (* segment registers *)
  38. segES = 0;
  39. segCS = 1;
  40. segSS = 2;
  41. segDS = 3;
  42. segFS = 4;
  43. segGS = 5;
  44. (* sizes *)
  45. bitsDefault* = 0;
  46. bits8* = 1;
  47. bits16* = 2;
  48. bits32* = 4;
  49. bits64* = 8;
  50. bits128* = 16;
  51. (** constants from InstructionSet **)
  52. (* instruction encoding *)
  53. opCode = InstructionSet.opCode;
  54. modRMExtension= InstructionSet.modRMExtension; modRMBoth= InstructionSet.modRMBoth;
  55. cb= InstructionSet.cb; cw= InstructionSet.cw; cd= InstructionSet.cd; cp= InstructionSet.cp;
  56. ib= InstructionSet.ib; iw= InstructionSet.iw; id= InstructionSet.id; iq= InstructionSet.iq;
  57. rb= InstructionSet.rb; rw= InstructionSet.rw; rd= InstructionSet.rd; rq= InstructionSet.rq;
  58. mem64Operand= InstructionSet.mem64Operand; mem128Operand= InstructionSet.mem128Operand;
  59. fpStackOperand= InstructionSet.fpStackOperand; directMemoryOffset= InstructionSet.directMemoryOffset;
  60. (* limits *)
  61. maxNumberOperands = InstructionSet.maxNumberOperands;
  62. (* operand types, values have no meaning but do coincide with symbols in the instruction set module *)
  63. reg8*= InstructionSet.reg8;
  64. reg16*= InstructionSet.reg16;
  65. reg32*= InstructionSet.reg32;
  66. reg64*= InstructionSet.reg64;
  67. CRn*= InstructionSet.CRn;
  68. DRn*= InstructionSet.DRn;
  69. segReg*= InstructionSet.segReg;
  70. mmx*= InstructionSet.mmx;
  71. xmm*= InstructionSet.xmm;
  72. mem*=InstructionSet.mem;
  73. sti*= InstructionSet.sti;
  74. imm*= InstructionSet.imm;
  75. ioffset*=InstructionSet.ioffset;
  76. pntr1616*= InstructionSet.pntr1616;
  77. pntr1632*=InstructionSet.pntr1632;
  78. (* scanner codes *)
  79. TAB = 09X;
  80. LF = 0AX;
  81. CR = 0DX;
  82. SPACE = 20X;
  83. (* symbol values *)
  84. symNone = 0;
  85. symIdent = 1;
  86. symLabel = 2;
  87. symNumber = 3;
  88. symSemicolon = 4;
  89. symColon = 5;
  90. symLn = 6;
  91. symComma = 7;
  92. symString = 8;
  93. symPlus = 9;
  94. symMinus = 10;
  95. symTimes = 11;
  96. symDiv = 12;
  97. symLParen = 13;
  98. symRParen = 14;
  99. symLBrace = 15;
  100. symRBrace = 16;
  101. symLBraket = 17;
  102. symRBraket = 18;
  103. symPC = 19;
  104. symPCOffset = 20;
  105. symNegate = 21;
  106. symMod = 22;
  107. symPeriod = 23;
  108. symAt = 24;
  109. symEnd = 25;
  110. TYPE
  111. Name = Scanner.IdentifierString;
  112. Size = SHORTINT;
  113. Register* = LONGINT; (* index for InstructionSet.registers *)
  114. (*
  115. an implementation of Operands as objects is very elegant but unfortunately also very costly in terms of number of allocations
  116. *)
  117. Operand* = RECORD
  118. type-: SHORTINT; (* reg8..reg64, CRn,DRn, segReg, sti, mmx, xmm, mem, imm, moffset, pntr1616, pntr1632 *)
  119. (* assembler examples:
  120. reg8: AL => register = InstructionSet.regAL
  121. reg16: CX => register = InstructionSet.regCX
  122. reg32: EBX => register = InstructionSet.regEBX
  123. reg64: RCX => register = InstructionSet.regRCX
  124. mem: BYTE [EAX+EBX*4+16] => register = EAX, index = EBX, scale = 4, displacement = 16, size = 8
  125. imm: DWORD 256 => val = 256, size = 32
  126. *)
  127. register-: Register; (* for registers and mem *)
  128. sizeInBytes-: Size; (* for mem and imm and moffset *)
  129. segment-,index-: Register; (* registers for mem *)
  130. scale-, displacement-: LONGINT; (* for mem *)
  131. symbol- : ObjectFile.Identifier; (* for imm and mem *)
  132. symbolOffset-: LONGINT; (* offset in immediate code (source) for a fixup *)
  133. val-: HUGEINT; (* for imm and moffset *)
  134. pc-: LONGINT;
  135. selector-, offset-: LONGINT; (* for pntr1616 / pntr1632 *)
  136. END;
  137. Code* = BinaryCode.Section;
  138. NamedLabel*= OBJECT
  139. VAR
  140. offset: LONGINT;
  141. name-: SyntaxTree.IdentifierString;
  142. nextNamedLabel-: NamedLabel;
  143. index-: LONGINT;
  144. PROCEDURE &InitNamedLabel(offset: LONGINT; CONST name: ARRAY OF CHAR);
  145. BEGIN
  146. SELF.offset := offset;
  147. COPY(name,SELF.name);
  148. nextNamedLabel := NIL;
  149. END InitNamedLabel;
  150. PROCEDURE SetOffset*(ofs: LONGINT);
  151. BEGIN SELF.offset := ofs;
  152. END SetOffset;
  153. END NamedLabel;
  154. NamedLabelList*=OBJECT
  155. VAR first-,last-: NamedLabel; number-: LONGINT;
  156. PROCEDURE & InitNamedLabelList;
  157. BEGIN first := NIL; last := NIL; number := 0;
  158. END InitNamedLabelList;
  159. PROCEDURE Add*(n: NamedLabel);
  160. BEGIN
  161. IF first = NIL THEN first := n ELSE last.nextNamedLabel := n; last.nextNamedLabel := n; END; last := n; INC(number);
  162. n.index := number;
  163. END Add;
  164. PROCEDURE Find*(CONST name: ARRAY OF CHAR): NamedLabel;
  165. VAR label: NamedLabel;
  166. BEGIN
  167. label := first;
  168. WHILE (label # NIL) & (label.name # name) DO
  169. label := label.nextNamedLabel;
  170. END;
  171. RETURN label
  172. END Find;
  173. END NamedLabelList;
  174. Emitter*=OBJECT
  175. VAR
  176. code-: Code;
  177. error-: BOOLEAN;
  178. diagnostics: Diagnostics.Diagnostics;
  179. assembly: Assembly; (* for error position *)
  180. (* overal state *)
  181. cpuBits: Size; (* supported bit width for this cpu / target *)
  182. cpuOptions: InstructionSet.CPUOptions;
  183. dump: Streams.Writer;
  184. PROCEDURE & InitEmitter*(diagnostics: Diagnostics.Diagnostics);
  185. BEGIN
  186. SELF.diagnostics := diagnostics;
  187. cpuBits := bits32; cpuOptions := {0..31};
  188. error := FALSE;
  189. END InitEmitter;
  190. PROCEDURE SetCode*(code: BinaryCode.Section);
  191. BEGIN SELF.code := code;
  192. dump := code.comments
  193. END SetCode;
  194. PROCEDURE SetBits* (numberBits: LONGINT): BOOLEAN;
  195. BEGIN
  196. CASE numberBits OF
  197. 16: cpuBits := bits16;
  198. | 32: cpuBits := bits32;
  199. | 64: cpuBits := bits64;
  200. ELSE
  201. Error("number bits not supported");
  202. RETURN FALSE;
  203. END;
  204. RETURN TRUE;
  205. END SetBits;
  206. PROCEDURE Error(CONST message: ARRAY OF CHAR);
  207. VAR msg,name: ARRAY 256 OF CHAR; errPos: Basic.Position;
  208. BEGIN
  209. COPY(message,msg);
  210. Strings.Append(msg," in ");
  211. ObjectFile.SegmentedNameToString(code.os.identifier.name,name);
  212. Strings.Append(msg, name);
  213. IF assembly # NIL THEN errPos := assembly.errPos ELSE errPos := Basic.invalidPosition END;
  214. Basic.Error(diagnostics,"",errPos,msg);
  215. error := TRUE;
  216. IF dump # NIL THEN dump.Update; END;
  217. END Error;
  218. PROCEDURE ErrorSS(CONST msg1,msg2: ARRAY OF CHAR);
  219. VAR message: ARRAY 256 OF CHAR;
  220. BEGIN
  221. COPY(msg1,message);
  222. Strings.Append(message," : ");
  223. Strings.Append(message, msg2);
  224. Error(message);
  225. END ErrorSS;
  226. PROCEDURE ErrorSI(CONST msg1: ARRAY OF CHAR; mnemonic: LONGINT; CONST operands: ARRAY OF Operand);
  227. VAR s: Streams.StringWriter; msg: Basic.MessageString;
  228. BEGIN
  229. NEW(s,LEN(msg));
  230. DumpInstruction(s,mnemonic,operands);
  231. s.String(" @");
  232. s.Int(code.pc,1);
  233. s.Get(msg);
  234. ErrorSS(msg1,msg);
  235. END ErrorSI;
  236. PROCEDURE AddFixup (mode: SHORTINT; size: SHORTINT; pc: LONGINT; symbol: ObjectFile.Identifier; symbolOffset, displacement: LONGINT);
  237. VAR fixup: BinaryCode.Fixup; format: BinaryCode.FixupPatterns; id: ObjectFile.Identifier;
  238. BEGIN
  239. NEW(format,1);
  240. format[0].bits:= size*8;
  241. format[0].offset := 0;
  242. fixup := BinaryCode.NewFixup(mode,pc,symbol,symbolOffset,displacement,0,format);
  243. code.fixupList.AddFixup(fixup);
  244. END AddFixup;
  245. PROCEDURE EmitInstruction (mnem: LONGINT; VAR operands: ARRAY OF Operand; lastPass: BOOLEAN): BOOLEAN;
  246. VAR instr, i, oppos, op: LONGINT;
  247. val: LONGINT;
  248. regOperand: LONGINT;
  249. addressOperand: LONGINT;
  250. regField, modField, rmField: LONGINT;
  251. scaleField, indexField, baseField: LONGINT;
  252. free: ARRAY maxNumberOperands OF BOOLEAN;
  253. byte: LONGINT;
  254. offset: LONGINT;
  255. opPrefix, adrPrefix: BOOLEAN;
  256. segPrefix: LONGINT; rexPrefix: SET;
  257. bitwidthOptions: SET;
  258. opcode: ARRAY InstructionSet.maxCodeLength OF InstructionSet.Code;
  259. pc0: LONGINT;
  260. debug,temp: LONGINT;
  261. PROCEDURE FindInstruction(mnem: LONGINT; CONST operands: ARRAY OF Operand): LONGINT;
  262. VAR instr: LONGINT;
  263. PROCEDURE MatchesInstruction (): BOOLEAN;
  264. VAR i: LONGINT;
  265. BEGIN
  266. FOR i := 0 TO maxNumberOperands - 1 DO
  267. IF (i>=LEN(operands)) OR (operands[i].type = none) THEN (* no operand -> check if instruction has no operand here *)
  268. IF InstructionSet.instructions[instr].operands[i] # none THEN
  269. RETURN FALSE
  270. END;
  271. ELSIF ~Matches(operands[i],InstructionSet.instructions[instr].operands[i]) THEN (* instruction operand type and this operand do not match *)
  272. RETURN FALSE
  273. ELSIF (cpuBits = bits64) & (InstructionSet.optNot64 IN InstructionSet.instructions[instr].bitwidthOptions) THEN (* instruction is invalid in 64 bit mode *)
  274. RETURN FALSE;
  275. END;
  276. END;
  277. RETURN TRUE;
  278. END MatchesInstruction;
  279. BEGIN
  280. instr := InstructionSet.mnemonics[mnem].firstInstruction;
  281. WHILE (instr <= InstructionSet.mnemonics[mnem].lastInstruction) & (~MatchesInstruction ()) DO
  282. INC (instr);
  283. END;
  284. IF instr > InstructionSet.mnemonics[mnem].lastInstruction THEN
  285. ErrorSI("invalid combination of opcode and operands", mnem,operands); RETURN none;
  286. ELSIF InstructionSet.instructions[instr].cpuOptions * cpuOptions # InstructionSet.instructions[instr].cpuOptions THEN
  287. ErrorSI("invalid instruction for current target", mnem,operands); RETURN none;
  288. END;
  289. RETURN instr
  290. END FindInstruction;
  291. PROCEDURE GetRegOperand (): LONGINT;
  292. VAR i: LONGINT;
  293. BEGIN
  294. FOR i := 0 TO maxNumberOperands -1 DO
  295. CASE InstructionSet.instructions[instr].operands[i] OF
  296. InstructionSet.reg8, InstructionSet.reg16, InstructionSet.reg32, InstructionSet.reg64, InstructionSet.xmm, InstructionSet.mmx: RETURN i;
  297. ELSE
  298. END;
  299. END;
  300. RETURN none;
  301. END GetRegOperand;
  302. PROCEDURE GetAddressOperand (): LONGINT;
  303. VAR i: LONGINT;
  304. BEGIN
  305. FOR i := 0 TO maxNumberOperands -1 DO
  306. CASE InstructionSet.instructions[instr].operands[i] OF
  307. InstructionSet.mem,
  308. InstructionSet.mem8, InstructionSet.mem16, InstructionSet.mem32, InstructionSet.mem64, InstructionSet.mem128,
  309. InstructionSet.regmem8, InstructionSet.regmem16, InstructionSet.regmem32, InstructionSet.regmem64,
  310. InstructionSet.mmxmem32, InstructionSet.mmxmem64,
  311. InstructionSet.xmmmem32, InstructionSet.xmmmem64, InstructionSet.xmmmem128:
  312. RETURN i;
  313. ELSE
  314. END;
  315. END;
  316. RETURN none;
  317. END GetAddressOperand;
  318. PROCEDURE GetSpecialOperand (): LONGINT;
  319. VAR i: LONGINT;
  320. BEGIN
  321. FOR i := 0 TO maxNumberOperands -1 DO
  322. CASE InstructionSet.instructions[instr].operands[i] OF
  323. InstructionSet.segReg, InstructionSet.mmx, InstructionSet.xmm, InstructionSet.CRn, InstructionSet.DRn:
  324. RETURN i;
  325. ELSE
  326. END;
  327. END;
  328. RETURN none;
  329. END GetSpecialOperand;
  330. PROCEDURE ModRM (mod, reg, rm: LONGINT);
  331. BEGIN
  332. IF Trace THEN KernelLog.String("ModRM"); KernelLog.Int(mod,1); KernelLog.String(","); KernelLog.Int(reg,1);
  333. KernelLog.String(","); KernelLog.Int(rm,1); KernelLog.Ln;
  334. END;
  335. code.PutByte (mod MOD 4 * 40H + reg MOD 8 * 8H + rm MOD 8);
  336. END ModRM;
  337. PROCEDURE SIB (scale, index, base: LONGINT);
  338. BEGIN code.PutByte (scale MOD 4 * 40H + index MOD 8 * 8H + base MOD 8);
  339. END SIB;
  340. PROCEDURE FPOrSSEOperation(instr: LONGINT): BOOLEAN;
  341. BEGIN
  342. RETURN {InstructionSet.cpuFPU, InstructionSet.cpuSSE, InstructionSet.cpuSSE2, InstructionSet.cpuSSE3} * InstructionSet.instructions[instr].cpuOptions # {}
  343. END FPOrSSEOperation;
  344. BEGIN
  345. IF (dump # NIL) & (lastPass) THEN
  346. pc0 := code.pc;
  347. DumpInstruction(dump,mnem,operands);
  348. dump.Update;
  349. END;
  350. IF Trace THEN
  351. DumpInstruction(kernelWriter,mnem,operands);
  352. kernelWriter.Update;
  353. END;
  354. instr := FindInstruction(mnem,operands);
  355. IF instr = none THEN RETURN FALSE END;
  356. bitwidthOptions := InstructionSet.instructions[instr].bitwidthOptions;
  357. FOR i := 0 TO InstructionSet.maxCodeLength-1 DO opcode[i] := InstructionSet.instructions[instr].code[i] END;
  358. opPrefix := FALSE;
  359. adrPrefix := FALSE;
  360. segPrefix := none;
  361. rexPrefix := {};
  362. IF (InstructionSet.optO16 IN bitwidthOptions) & (cpuBits # bits16) THEN
  363. IF Trace THEN KernelLog.String(" optO16 "); KernelLog.Ln; END;
  364. opPrefix := TRUE;
  365. END;
  366. IF (InstructionSet.optO32 IN bitwidthOptions) & (cpuBits = bits16) THEN
  367. IF Trace THEN KernelLog.String(" optO32 "); KernelLog.Ln; END;
  368. opPrefix := TRUE;
  369. END;
  370. IF (InstructionSet.optO64 IN bitwidthOptions) & (cpuBits = bits64) THEN
  371. IF Trace THEN KernelLog.String(" optO64 "); KernelLog.Ln; END;
  372. INCL (rexPrefix, rexW)
  373. END;
  374. IF InstructionSet.optPOP IN bitwidthOptions THEN
  375. IF Trace THEN KernelLog.String(" optPOP "); KernelLog.Ln; END;
  376. opPrefix := TRUE;
  377. END;
  378. regOperand := GetSpecialOperand ();
  379. addressOperand := GetAddressOperand ();
  380. IF regOperand = none THEN
  381. regOperand := GetRegOperand ();
  382. END;
  383. IF addressOperand = none THEN
  384. addressOperand := GetRegOperand ();
  385. IF regOperand # none THEN
  386. temp := InstructionSet.instructions[instr].operands[regOperand];
  387. IF (temp = xmm) OR (temp = mmx) THEN (* patch case such as PEXTRW EDX, XMM3, 0 *)
  388. temp := addressOperand; addressOperand := regOperand; regOperand := temp;
  389. END;
  390. ELSE
  391. END;
  392. END;
  393. IF mnem = InstructionSet.opMOVQ2DQ THEN (* patch *)
  394. regOperand := 0; addressOperand :=1;
  395. END;
  396. (* KernelLog.String (InstructionSet.mnemonics[mnem].name); KernelLog.Int (regOperand, 10); KernelLog.Int (addressOperand, 10); KernelLog.Ln; *)
  397. FOR i := 0 TO maxNumberOperands - 1 DO
  398. IF operands[i].type # none THEN
  399. IF operands[i].type = mem THEN
  400. IF Trace THEN KernelLog.String("mem"); KernelLog.Ln; END;
  401. IF operands[i].segment# none THEN
  402. IF Trace THEN KernelLog.String(" segment "); KernelLog.Ln; END;
  403. segPrefix := InstructionSet.RegisterIndex(operands[i].segment);
  404. END;
  405. IF operands[i].register# none THEN
  406. IF Trace THEN KernelLog.String(" register "); KernelLog.Int(operands[i].register,1); KernelLog.Ln; END;
  407. IF (InstructionSet.RegisterIndex(operands[i].register) >= 8) THEN
  408. IF Trace THEN KernelLog.String(" rexprefix "); KernelLog.Ln; END;
  409. INCL (rexPrefix, rexB)
  410. END;
  411. IF (InstructionSet.RegisterType(operands[i].register) = reg32) & (cpuBits # bits32) THEN
  412. IF Trace THEN KernelLog.String(" adr prefix "); KernelLog.Ln; END;
  413. adrPrefix := TRUE;
  414. END;
  415. IF InstructionSet.RegisterType(operands[i].register)=reg16 THEN
  416. IF cpuBits = bits64 THEN
  417. ErrorSI("invalid effective address (1)", mnem,operands);
  418. RETURN FALSE;
  419. ELSIF cpuBits = bits32 THEN
  420. IF Trace THEN KernelLog.String(" adr prefix (2) "); KernelLog.Ln; END;
  421. adrPrefix := TRUE;
  422. END;
  423. END;
  424. END;
  425. IF operands[i].index # none THEN
  426. IF Trace THEN KernelLog.String(" mem index "); KernelLog.Int(operands[i].index,1); KernelLog.Ln; END;
  427. IF (InstructionSet.RegisterType(operands[i].index)=reg64) & (InstructionSet.RegisterIndex(operands[i].index) >= 8) THEN
  428. INCL (rexPrefix, rexX)
  429. END
  430. END;
  431. IF (operands[i].sizeInBytes = bits64) & ~(InstructionSet.optD64 IN bitwidthOptions) & ~FPOrSSEOperation(instr) THEN
  432. IF Trace THEN KernelLog.String(" bits64 "); KernelLog.Ln; END;
  433. INCL (rexPrefix, rexW)
  434. END;
  435. IF InstructionSet.instructions[instr].operands[i] = InstructionSet.moffset64 THEN
  436. IF Trace THEN KernelLog.String(" moffset64 "); KernelLog.Ln; END;
  437. adrPrefix := TRUE;
  438. END;
  439. ELSIF IsRegisterOperand(operands[i]) (* is register *) THEN
  440. IF Trace THEN KernelLog.String("register"); KernelLog.Ln; END;
  441. IF (operands[i].type = reg64) & ~(InstructionSet.optD64 IN bitwidthOptions) THEN
  442. IF Trace THEN KernelLog.String(" reg64 "); KernelLog.Ln; END;
  443. INCL (rexPrefix, rexW)
  444. END;
  445. IF InstructionSet.RegisterIndex(operands[i].register) >= 8 THEN
  446. IF i = addressOperand THEN
  447. INCL (rexPrefix, rexB)
  448. ELSIF i = regOperand THEN
  449. INCL (rexPrefix, rexR)
  450. END;
  451. ELSIF (cpuBits = bits64) & (operands[i].type = reg8) & (InstructionSet.RegisterIndex(operands[i].register) >= 4) THEN
  452. INCL (rexPrefix, rex);
  453. END;
  454. END;
  455. END;
  456. free[i] := operands[i].type # none;
  457. END;
  458. CASE segPrefix OF
  459. none:
  460. | segES: code.PutByte (InstructionSet.prfES);
  461. | segCS: code.PutByte (InstructionSet.prfCS);
  462. | segSS: code.PutByte (InstructionSet.prfSS);
  463. | segDS: code.PutByte (InstructionSet.prfDS);
  464. | segFS: code.PutByte (InstructionSet.prfFS);
  465. | segGS: code.PutByte (InstructionSet.prfGS);
  466. END;
  467. IF opPrefix THEN code.PutByte (InstructionSet.prfOP) END;
  468. IF adrPrefix THEN code.PutByte (InstructionSet.prfADR) END;
  469. IF InstructionSet.optPLOCK IN bitwidthOptions THEN code.PutByte (InstructionSet.prfLOCK) END;
  470. IF InstructionSet.optPREP IN bitwidthOptions THEN code.PutByte (InstructionSet.prfREP) END;
  471. IF InstructionSet.optPREPN IN bitwidthOptions THEN code.PutByte (InstructionSet.prfREPNE) END;
  472. IF rexPrefix # {} THEN
  473. ASSERT(cpuBits = bits64);
  474. byte := 40H;
  475. IF rexB IN rexPrefix THEN byte := byte + 1H END;
  476. IF rexX IN rexPrefix THEN byte := byte + 2H END;
  477. IF rexR IN rexPrefix THEN byte := byte + 4H END;
  478. IF rexW IN rexPrefix THEN byte := byte + 8H END;
  479. code.PutByte (byte);
  480. END;
  481. op := 0;
  482. oppos := 0;
  483. val := -1;
  484. WHILE (oppos < LEN(opcode)) & (opcode[oppos] # CHR(none)) DO
  485. IF opcode[oppos] = CHR(opCode) THEN
  486. IF Trace THEN KernelLog.String("opcode "); KernelLog.Hex(ORD(opcode[oppos+1]),-2); END;
  487. IF val # -1 THEN code.PutByte (val) END;
  488. INC(oppos);
  489. val := ORD(opcode[oppos]);
  490. ELSE
  491. CASE ORD(opcode[oppos]) OF
  492. | modRMExtension, modRMBoth:
  493. IF Trace THEN KernelLog.String(" modRMExtension/Both "); END;
  494. IF val # -1 THEN code.PutByte (val); val := -1 END;
  495. IF opcode[oppos] = CHR(modRMBoth) (* /r *) THEN
  496. regField := InstructionSet.RegisterIndex(operands[regOperand].register) MOD 8;
  497. ELSE (* /digit *)
  498. INC(oppos);
  499. regField := ORD(opcode[oppos]);
  500. IF Trace THEN KernelLog.String(" digit: "); KernelLog.Int(regField,1); KernelLog.Ln; END;
  501. END;
  502. IF IsRegisterOperand(operands[addressOperand]) THEN
  503. IF Trace THEN KernelLog.String(" isRegisterOperand "); END;
  504. ModRM (3, regField, InstructionSet.RegisterIndex(operands[addressOperand].register) MOD 8);
  505. ELSIF (cpuBits = bits16) & (InstructionSet.RegisterType(operands[addressOperand].register) # reg32) THEN
  506. IF Trace THEN KernelLog.String(" cpuBits=16 "); END;
  507. IF (operands[addressOperand].scale # 1) OR (operands[addressOperand].symbol.name # "") THEN
  508. ErrorSI("invalid effective address (2)", mnem,operands);
  509. RETURN FALSE;
  510. ELSIF operands[addressOperand].register= none THEN
  511. IF operands[addressOperand].index =none THEN
  512. ErrorSI("invalid effective address (3)", mnem,operands);
  513. RETURN FALSE;
  514. END;
  515. ModRM (0, regField, 6);
  516. code.PutWord (operands[addressOperand].displacement);
  517. ELSIF InstructionSet.RegisterType(operands[addressOperand].register) = reg16 THEN
  518. IF operands[addressOperand].displacement = 0 THEN
  519. modField := 0;
  520. ELSIF (operands[addressOperand].displacement >= -80H) & (operands[addressOperand].displacement < 80H) THEN
  521. modField := 1;
  522. ELSIF (operands[addressOperand].displacement >= -8000H) & (operands[addressOperand].displacement < 8000H) THEN
  523. modField := 2;
  524. ELSE
  525. Error("value exceeds bounds");
  526. RETURN FALSE;
  527. END;
  528. CASE InstructionSet.RegisterIndex(operands[addressOperand].register) OF
  529. | RBX:
  530. IF operands[addressOperand].index = none THEN
  531. rmField := 7;
  532. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RSI THEN
  533. rmField := 0;
  534. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RDI THEN
  535. rmField := 1;
  536. ELSE
  537. ErrorSI("invalid effective address (4)", mnem,operands); RETURN FALSE;
  538. END
  539. | RBP:
  540. IF operands[addressOperand].index = none THEN
  541. rmField := 6;
  542. IF modField = 0 THEN modField := 1 END;
  543. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RSI THEN
  544. rmField := 2;
  545. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RDI THEN
  546. rmField := 3;
  547. ELSE
  548. ErrorSI("invalid effective address (5)", mnem,operands); RETURN FALSE;
  549. END
  550. | RSI:
  551. IF operands[addressOperand].index = none THEN
  552. rmField := 4;
  553. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RBX THEN
  554. rmField := 0;
  555. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RBP THEN
  556. rmField := 2;
  557. ELSE
  558. ErrorSI("invalid effective address (6)", mnem,operands); RETURN FALSE;
  559. END;
  560. | RDI:
  561. IF operands[addressOperand].index = none THEN
  562. rmField := 5;
  563. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RBX THEN
  564. rmField := 1;
  565. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].index) = RBP THEN
  566. rmField := 3;
  567. ELSE
  568. ErrorSI("invalid effective address (7)", mnem,operands); RETURN FALSE;
  569. END;
  570. ELSE
  571. ErrorSI("invalid effective address (8)", mnem,operands); RETURN FALSE;
  572. END;
  573. ModRM (modField, regField, rmField);
  574. IF modField = 1 THEN
  575. code.PutByte (operands[addressOperand].displacement);
  576. ELSIF modField = 2 THEN
  577. code.PutWord (operands[addressOperand].displacement);
  578. END;
  579. END;
  580. ELSE (* cpuBits # 16 *)
  581. ASSERT(operands[addressOperand].type = mem);
  582. IF Trace THEN KernelLog.String(" cpuBits # 16 "); END;
  583. IF (operands[addressOperand].register= none) & (operands[addressOperand].index = none) THEN
  584. IF Trace THEN KernelLog.String(" no register, no index "); END;
  585. IF operands[addressOperand].scale # 1 THEN
  586. ErrorSI("invalid effective address (9)", mnem,operands); RETURN FALSE;
  587. END;
  588. IF cpuBits = bits64 THEN
  589. ModRM (0, regField, 4);
  590. SIB (0, 4, 5);
  591. ELSE
  592. ModRM (0, regField, 5);
  593. END;
  594. (* fixup must be 8bit wide for linker!
  595. IF lastPass & (operands[addressOperand].fixup # NIL) THEN
  596. AddFixup (operands[addressOperand].fixup, pc);
  597. END;
  598. *)
  599. IF lastPass & (operands[addressOperand].symbol.name # "") THEN
  600. AddFixup(BinaryCode.Absolute,4,code.pc,operands[addressOperand].symbol, operands[addressOperand].symbolOffset,operands[addressOperand].displacement)
  601. END;
  602. code.PutDWord (operands[addressOperand].displacement);
  603. ELSE
  604. IF (operands[addressOperand].index # none) THEN
  605. (* index register available: must use SIB memory reference *)
  606. IF Trace THEN KernelLog.String(" index "); END;
  607. IF (InstructionSet.RegisterIndex(operands[addressOperand].index) = RSP) OR (InstructionSet.RegisterIndex(operands[addressOperand].index) = RIP) THEN
  608. ErrorSI("invalid effective address: unsupported stack / instruction pointer index", mnem,operands); RETURN FALSE;
  609. END;
  610. IF (operands[addressOperand].register# none) & (InstructionSet.RegisterIndex(operands[addressOperand].register) = RIP) THEN
  611. ErrorSI("invalid effective address: unsupported instruction base pointer with index", mnem,operands); RETURN FALSE;
  612. END;
  613. CASE operands[addressOperand].scale OF
  614. 1: scaleField := 0;
  615. | 2: scaleField := 1;
  616. | 4: scaleField := 2;
  617. | 8: scaleField := 3;
  618. ELSE
  619. ErrorSI("invalid effective address (12)", mnem,operands); RETURN FALSE;
  620. END;
  621. rmField := 4; (* indicates usage of SIB byte *)
  622. ELSE
  623. (* no index register available *)
  624. IF Trace THEN KernelLog.String(" no index ") END;
  625. IF (operands[addressOperand].scale # 1) THEN
  626. ErrorSI("invalid effective address: scale without index register", mnem,operands); RETURN FALSE;
  627. END;
  628. IF operands[addressOperand].register = none THEN (* no index, no base *)
  629. rmField := 4; (* indicates usage of SIB byte *)
  630. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].register) = RIP THEN
  631. rmField := 5; (* indicates usage of instruction pointer, must be followed by 32 bit displacement, modField must be 0 *)
  632. ELSIF InstructionSet.RegisterIndex(operands[addressOperand].register) MOD 8 = RSP THEN
  633. rmField := 4; (* indicates usage of SIB byte => stack pointer must be referenced in SIB byte *)
  634. ELSE
  635. rmField := InstructionSet.RegisterIndex(operands[addressOperand].register) MOD 8; (* any other register can be encoded via modRM field *)
  636. END;
  637. END;
  638. (* IF operands[addressOperand].fixup # NIL THEN
  639. modField := 2;
  640. mem fixups only for local variables and parameters
  641. *)
  642. IF operands[addressOperand].displacement = 0 THEN
  643. (* no displacement => modRM = 0 except for base pointer, which must be encoded with (zero) displacement *)
  644. IF Trace THEN KernelLog.String(" no displacement "); END;
  645. IF (operands[addressOperand].register # none) & (InstructionSet.RegisterIndex(operands[addressOperand].register) = RBP) THEN
  646. modField := 1;
  647. ELSIF (operands[addressOperand].register # none) & (InstructionSet.RegisterIndex(operands[addressOperand].register) = R13) THEN
  648. modField := 1;
  649. ELSE
  650. modField := 0;
  651. END;
  652. ELSIF (operands[addressOperand].register = none) & (operands[addressOperand].index # none) THEN
  653. modField := 0; (* 32 bit displacement without base register encoded via SIB byte *)
  654. ELSIF (operands[addressOperand].register # none) & (InstructionSet.RegisterIndex(operands[addressOperand].register) = RIP) THEN
  655. (* if there is displacement on RIP, we still have to use the modRM = 0 case *)
  656. IF cpuBits = 64 THEN
  657. modField := 0;
  658. ELSE
  659. Error("invalid effective address: instruction pointer relative addressing only in 64 bit mode")
  660. END;
  661. ELSIF (operands[addressOperand].displacement >= -80H) & (operands[addressOperand].displacement < 80H) THEN
  662. (* 8 bit displacement *)
  663. modField := 1;
  664. ELSE
  665. (* 32 bit displacement *)
  666. modField := 2;
  667. END;
  668. ModRM (modField, regField, rmField);
  669. IF (rmField = 4) THEN (* must emit SIB encoding scale, index and base (operand.register --> base) *)
  670. IF operands[addressOperand].index # none THEN
  671. (* index register present *)
  672. indexField := InstructionSet.RegisterIndex(operands[addressOperand].index) MOD 8;
  673. ELSE
  674. (* no index register *)
  675. indexField := 4;
  676. END;
  677. IF operands[addressOperand].register# none THEN
  678. (* base register present, can also be the base pointer (5) *)
  679. baseField := InstructionSet.RegisterIndex(operands[addressOperand].register) MOD 8;
  680. ELSE
  681. (* no register present *)
  682. debug := operands[addressOperand].register;
  683. ASSERT(modField = 0);
  684. baseField := 5;
  685. END;
  686. SIB (scaleField, indexField, baseField);
  687. END;
  688. IF modField = 0 THEN
  689. IF rmField = 5 THEN
  690. IF lastPass & (operands[addressOperand].symbol.name # "") THEN AddFixup(BinaryCode.Absolute,4,code.pc,operands[addressOperand].symbol,operands[addressOperand].symbolOffset,operands[addressOperand].displacement) END;
  691. code.PutDWord(operands[addressOperand].displacement);
  692. ELSIF (rmField = 4) & (baseField = 5) THEN (* special case: SIB without base register: mandatory displacement *)
  693. IF lastPass & (operands[addressOperand].symbol.name # "") THEN AddFixup(BinaryCode.Absolute,4,code.pc,operands[addressOperand].symbol,operands[addressOperand].symbolOffset,operands[addressOperand].displacement) END;
  694. code.PutDWord(operands[addressOperand].displacement);
  695. END;
  696. ELSIF modField = 1 THEN
  697. IF lastPass & (operands[addressOperand].symbol.name # "") THEN AddFixup(BinaryCode.Absolute,1,code.pc,operands[addressOperand].symbol,operands[addressOperand].symbolOffset,operands[addressOperand].displacement) END;
  698. code.PutByte(operands[addressOperand].displacement);
  699. ELSIF modField = 2 THEN
  700. IF lastPass & (operands[addressOperand].symbol.name # "") THEN AddFixup(BinaryCode.Absolute,4,code.pc,operands[addressOperand].symbol,operands[addressOperand].symbolOffset,operands[addressOperand].displacement) END;
  701. code.PutDWord (operands[addressOperand].displacement);
  702. END;
  703. END;
  704. END;
  705. | cb:
  706. IF Trace THEN KernelLog.String(" cb "); END;
  707. IF val # -1 THEN code.PutByte (val); val := -1 END;
  708. FOR i := 0 TO maxNumberOperands - 1 DO
  709. IF (free[i]) & (operands[i].type = ioffset) THEN
  710. IF Trace THEN KernelLog.String(" ioffset "); END;
  711. offset := SHORT(operands[i].val - code.pc - 1);
  712. IF lastPass & ~ValueInByteRange (offset) THEN
  713. Error( "value exceeds bounds");
  714. RETURN FALSE;
  715. END;
  716. operands[i].pc := code.pc;
  717. code.PutByte (offset);
  718. free[i] := FALSE; i:= maxNumberOperands;
  719. ELSIF (free[i]) & (operands[i].type = imm) THEN
  720. IF Trace THEN KernelLog.String(" imm "); END;
  721. offset := SHORT (operands[i].val);
  722. IF lastPass & ~ValueInByteRange (offset) THEN
  723. Error( "value exceeds bounds");
  724. RETURN FALSE;
  725. END;
  726. operands[i].pc := code.pc;
  727. code.PutByte (offset);
  728. free[i] := FALSE; i:= maxNumberOperands;
  729. END
  730. END;
  731. | cw:
  732. IF Trace THEN KernelLog.String(" cw "); END;
  733. IF val # -1 THEN code.PutByte (val); val := -1 END;
  734. FOR i := 0 TO maxNumberOperands - 1 DO
  735. IF (free[i]) & (InstructionSet.instructions[instr].operands[i] = InstructionSet.rel16off) THEN
  736. offset := SHORT(operands[i].val - code.pc - 2);
  737. IF lastPass & ~ValueInWordRange (offset) THEN
  738. Error( "value exceeds bounds");
  739. END;
  740. operands[i].pc := code.pc;
  741. code.PutWord (offset);
  742. free[i] := FALSE; i:= maxNumberOperands;
  743. ELSIF (free[i]) & InstructionSet.IsImmediate16(InstructionSet.instructions[instr].operands[i]) THEN
  744. offset := SHORT (operands[i].val);
  745. IF lastPass & ~ValueInWordRange (offset) THEN
  746. Error( "value exceeds bounds");
  747. RETURN FALSE;
  748. END;
  749. operands[i].pc := code.pc;
  750. code.PutWord (offset);
  751. free[i] := FALSE; i:= maxNumberOperands;
  752. END
  753. END;
  754. | cd:
  755. IF Trace THEN KernelLog.String(" cd "); END;
  756. IF val # -1 THEN code.PutByte (val); val := -1 END;
  757. FOR i := 0 TO maxNumberOperands - 1 DO
  758. IF (free[i]) & (InstructionSet.instructions[instr].operands[i] = InstructionSet.rel32off) THEN
  759. operands[i].pc := code.pc;
  760. IF lastPass & (operands[i].symbol.name # "") THEN
  761. AddFixup(BinaryCode.Relative,4,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement-4);
  762. code.PutDWord(SHORT(operands[i].val));
  763. ELSE
  764. code.PutDWord (SHORT (operands[i].val - code.pc - 4));
  765. END;
  766. free[i] := FALSE; i:= maxNumberOperands;
  767. ELSIF (free[i]) & InstructionSet.IsImmediate32(InstructionSet.instructions[instr].operands[i]) THEN
  768. operands[i].pc := code.pc;
  769. IF lastPass & (operands[i].symbol.name # "") THEN
  770. AddFixup(BinaryCode.Absolute,4,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement);
  771. END;
  772. code.PutDWord (SHORT (operands[i].val));
  773. free[i] := FALSE; i:= maxNumberOperands;
  774. END
  775. END;
  776. | cp:
  777. IF Trace THEN KernelLog.String(" cp "); END;
  778. IF val # -1 THEN code.PutByte (val); val := -1 END;
  779. | ib:
  780. IF Trace THEN KernelLog.String(" ib "); END;
  781. IF val # -1 THEN code.PutByte (val); val := -1 END;
  782. FOR i := 0 TO maxNumberOperands - 1 DO
  783. IF (free[i]) & (operands[i].type = imm) OR (operands[i].type = ioffset) THEN
  784. offset := SHORT (operands[i].val);
  785. IF FALSE & lastPass & ~ValueInByteRange (offset) THEN
  786. Error( "value exceeds bounds");
  787. RETURN FALSE;
  788. END;
  789. operands[i].pc := code.pc;
  790. IF lastPass & (operands[i].symbol.name # "") THEN AddFixup(BinaryCode.Absolute,1,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement) END;
  791. code.PutByte (SHORT (operands[i].val));
  792. free[i] := FALSE; i:= maxNumberOperands;
  793. END
  794. END;
  795. | iw:
  796. IF Trace THEN KernelLog.String(" iw "); END;
  797. IF val # -1 THEN code.PutByte (val); val := -1 END;
  798. FOR i := 0 TO maxNumberOperands - 1 DO
  799. IF (free[i]) & (operands[i].type = imm) OR (operands[i].type = ioffset) THEN
  800. operands[i].pc := code.pc;
  801. code.PutWord (SHORT (operands[i].val));
  802. free[i] := FALSE; i:= maxNumberOperands;
  803. END
  804. END;
  805. | id:
  806. IF Trace THEN KernelLog.String(" id "); END;
  807. IF val # -1 THEN code.PutByte (val); val := -1 END;
  808. FOR i := 0 TO maxNumberOperands - 1 DO
  809. IF (free[i]) & (InstructionSet.instructions[instr].operands[i] = InstructionSet.rel32off) THEN
  810. operands[i].pc := code.pc;
  811. IF lastPass & (operands[i].symbol.name # "") THEN AddFixup(BinaryCode.Relative,4,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement-4) END;
  812. code.PutDWord (SHORT (operands[i].val - code.pc - 4));
  813. free[i] := FALSE; i:= maxNumberOperands;
  814. ELSIF (free[i]) & InstructionSet.IsImmediate32(InstructionSet.instructions[instr].operands[i]) THEN
  815. operands[i].pc := code.pc;
  816. IF lastPass & (operands[i].symbol.name # "") THEN AddFixup(BinaryCode.Absolute,4,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement) END;
  817. code.PutDWord (SHORT (operands[i].val));
  818. free[i] := FALSE; i:= maxNumberOperands;
  819. END
  820. END;
  821. | iq:
  822. IF Trace THEN KernelLog.String(" iq "); END;
  823. IF val # -1 THEN code.PutByte (val); val := -1 END;
  824. FOR i := 0 TO maxNumberOperands - 1 DO
  825. IF (free[i]) & InstructionSet.IsImmediate64(InstructionSet.instructions[instr].operands[i]) THEN
  826. operands[i].pc := code.pc;
  827. IF lastPass & (operands[i].symbol.name # "") THEN
  828. AddFixup(BinaryCode.Absolute,8,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement)
  829. END;
  830. code.PutQWord (operands[i].val);
  831. free[i] := FALSE; i:= maxNumberOperands;
  832. END
  833. END;
  834. | rb, rw, rd, rq:
  835. IF Trace THEN KernelLog.String(" r* "); END;
  836. regOperand := GetRegOperand ();
  837. val := val + InstructionSet.RegisterIndex(operands[regOperand].register) MOD 8;
  838. code.PutByte (val); val := -1;
  839. free[regOperand] := FALSE;
  840. | fpStackOperand:
  841. IF Trace THEN KernelLog.String(" fp "); END;
  842. FOR i := 0 TO maxNumberOperands - 1 DO
  843. IF (free[i]) & (operands[i].type = sti) & (InstructionSet.instructions[instr].operands[i] # InstructionSet.st0) THEN
  844. val := val + InstructionSet.RegisterIndex(operands[i].register);
  845. code.PutByte (val); val := -1;
  846. free[i] := FALSE; i:= maxNumberOperands;
  847. END;
  848. END;
  849. | directMemoryOffset:
  850. IF Trace THEN KernelLog.String(" memoffset "); END;
  851. IF val # -1 THEN code.PutByte (val); val := -1 END;
  852. FOR i := 0 TO maxNumberOperands - 1 DO
  853. IF (free[i]) & (operands[i].type = mem) THEN
  854. IF cpuBits = bits16 THEN
  855. code.PutWord (operands[i].displacement);
  856. ELSE
  857. IF lastPass & (operands[i].symbol.name # "") THEN
  858. AddFixup(BinaryCode.Absolute,4,code.pc,operands[i].symbol,operands[i].symbolOffset,operands[i].displacement)
  859. END;
  860. code.PutDWord (operands[i].displacement);
  861. END;
  862. free[i] := FALSE; i:= maxNumberOperands;
  863. END;
  864. END;
  865. | mem64Operand, mem128Operand: (* ignored *)
  866. IF Trace THEN KernelLog.String(" mem64/mem128 "); END;
  867. ELSE HALT(100) (* decoding error *)
  868. END;
  869. END;
  870. INC(oppos);
  871. IF Trace THEN KernelLog.Ln; END;
  872. END;
  873. IF val # -1 THEN code.PutByte (val) END;
  874. ASSERT(oppos < LEN(opcode)); (* decoding or representation error otherwise *)
  875. RETURN TRUE;
  876. END EmitInstruction;
  877. PROCEDURE EmitPrefix* (prefix: LONGINT);
  878. BEGIN code.PutByte (prefix);
  879. END EmitPrefix;
  880. PROCEDURE Emit*(mnem: LONGINT; VAR op1,op2,op3: Operand);
  881. VAR operands: ARRAY maxNumberOperands OF Operand; res: BOOLEAN; i: LONGINT; noOperand: Operand;
  882. BEGIN
  883. operands[0] := op1;
  884. operands[1] := op2;
  885. operands[2] := op3;
  886. noOperand.type := none;
  887. FOR i := 3 TO maxNumberOperands-1 DO
  888. operands[i] := noOperand;
  889. END;
  890. res := EmitInstruction(mnem,operands,TRUE);
  891. op1 := operands[0];
  892. op2 := operands[1];
  893. op3 := operands[2];
  894. END Emit;
  895. PROCEDURE EmitAt*(pc: LONGINT;mnem: LONGINT; VAR op1,op2,op3: Operand);
  896. VAR prevPC: LONGINT; prevDump: Streams.Writer;
  897. BEGIN
  898. prevDump := dump;
  899. dump := NIL;
  900. prevPC := code.pc;
  901. code.SetPC(pc);
  902. Emit(mnem,op1,op2,op3);
  903. code.SetPC(prevPC);
  904. dump := prevDump;
  905. END EmitAt;
  906. PROCEDURE StartEmitAt*(VAR pc: LONGINT): LONGINT;
  907. VAR prevPC: LONGINT;
  908. BEGIN
  909. prevPC := code.pc;
  910. dump := NIL;
  911. code.SetPC(pc);
  912. RETURN prevPC;
  913. END StartEmitAt;
  914. PROCEDURE EndEmitAt*(pc: LONGINT);
  915. BEGIN
  916. code.SetPC(pc);
  917. SELF.dump := code.comments;
  918. END EndEmitAt;
  919. PROCEDURE Emit0* (mnem: LONGINT);
  920. VAR noOperand: Operand;
  921. BEGIN
  922. noOperand.type := none;
  923. Emit(mnem,noOperand,noOperand,noOperand);
  924. END Emit0;
  925. PROCEDURE Emit1* (mnem: LONGINT; VAR op1: Operand);
  926. VAR noOperand: Operand;
  927. BEGIN
  928. noOperand.type := none;
  929. Emit(mnem,op1,noOperand,noOperand);
  930. END Emit1;
  931. PROCEDURE Emit2* (mnem: LONGINT; VAR op1, op2: Operand);
  932. VAR noOperand: Operand;
  933. BEGIN
  934. noOperand.type := none;
  935. Emit(mnem,op1,op2,noOperand);
  936. END Emit2;
  937. PROCEDURE Emit3* (mnem: LONGINT; VAR op1, op2, op3: Operand);
  938. BEGIN
  939. Emit(mnem,op1,op2,op3);
  940. END Emit3;
  941. END Emitter;
  942. RegisterMapEntry*= POINTER TO RECORD
  943. name-: Strings.String;
  944. register-: LONGINT;
  945. next: RegisterMapEntry;
  946. END;
  947. RegisterMap*= OBJECT
  948. VAR first: RegisterMapEntry;
  949. PROCEDURE & Init *;
  950. BEGIN
  951. first := NIL
  952. END Init;
  953. PROCEDURE Find*(CONST name: ARRAY OF CHAR): LONGINT;
  954. VAR map: RegisterMapEntry;
  955. BEGIN
  956. map := first;
  957. WHILE (map # NIL) & (map.name^#name) DO map := map.next END;
  958. IF map = NIL THEN RETURN InstructionSet.none ELSE RETURN map.register END;
  959. END Find;
  960. PROCEDURE Add*(name: Strings.String; register: LONGINT);
  961. VAR map: RegisterMapEntry;
  962. BEGIN
  963. NEW(map); map.name := name; map.register := register;
  964. map.next := first; first := map;
  965. END Add;
  966. END RegisterMap;
  967. Assembly* = OBJECT
  968. VAR
  969. (* output *)
  970. errPos: Basic.Position;
  971. error-: BOOLEAN;
  972. useLineNumbers*: BOOLEAN;
  973. emitter: Emitter;
  974. (* overal state *)
  975. diagnostics: Diagnostics.Diagnostics;
  976. dump: Streams.Writer;
  977. (* temporaries *)
  978. fixup: BinaryCode.Fixup;
  979. type: SHORTINT;
  980. currentFixup: Sections.SectionName;
  981. currentLabel: NamedLabel;
  982. sourceName: Basic.FileName;
  983. PROCEDURE & InitAssembly*(diagnostics: Diagnostics.Diagnostics; emit: Emitter);
  984. BEGIN
  985. SELF.diagnostics := diagnostics;
  986. errPos := Basic.invalidPosition;
  987. error := FALSE;
  988. SELF.emitter := emit;
  989. sourceName := "";
  990. END InitAssembly;
  991. PROCEDURE Error( CONST message: ARRAY OF CHAR);
  992. VAR pos: Basic.Position; msg,name: ARRAY 256 OF CHAR;
  993. BEGIN
  994. pos := errPos;
  995. COPY(message,msg);
  996. IF (pos.start = Diagnostics.Invalid) OR (sourceName = "") THEN
  997. Strings.Append(msg," in ");
  998. ObjectFile.SegmentedNameToString(emitter.code.os.identifier.name, name);
  999. Strings.Append(msg, name);
  1000. Basic.Error(diagnostics, sourceName,errPos,msg);
  1001. ELSE
  1002. Basic.Error(diagnostics, sourceName,errPos,msg);
  1003. END;
  1004. error := TRUE;
  1005. IF dump # NIL THEN dump.Update; END;
  1006. END Error;
  1007. PROCEDURE ErrorSS(CONST msg1,msg2: ARRAY OF CHAR);
  1008. VAR message: ARRAY 256 OF CHAR;
  1009. BEGIN
  1010. COPY(msg1,message);
  1011. Strings.Append(message," : ");
  1012. Strings.Append(message, msg2);
  1013. Error(message);
  1014. END ErrorSS;
  1015. PROCEDURE Assemble* (reader: Streams.Reader; orgPos: Basic.Position; scope: SyntaxTree.Scope; in: IntermediateCode.Section; out: IntermediateCode.Section; module: Sections.Module; exported, inlined: BOOLEAN;
  1016. map: RegisterMap
  1017. );
  1018. CONST maxPasses = 2;
  1019. VAR
  1020. symbol, reg: LONGINT;
  1021. ident, idents: Name;
  1022. val, times, val2, val3: LONGINT;
  1023. currentLabel: NamedLabel;
  1024. labels: NamedLabelList;
  1025. prevPC: LONGINT;
  1026. pass: LONGINT;
  1027. absoluteMode: BOOLEAN;
  1028. absoluteOffset: LONGINT;
  1029. alignment: LONGINT;
  1030. orgOffset: LONGINT;
  1031. char: CHAR;
  1032. orgReaderPos: LONGINT;
  1033. orgCodePos: LONGINT;
  1034. prevSourceName: Basic.FileName;
  1035. position: Basic.Position;
  1036. prevCpuBits: Size;
  1037. prevCpuOptions: InstructionSet.CPUOptions;
  1038. prevAssembly: Assembly;
  1039. PROCEDURE NextChar;
  1040. BEGIN
  1041. (*
  1042. IF (dump # NIL) & (pass = maxPasses) THEN dump.Char (char) END;
  1043. *)
  1044. reader.Char(char); INC(position.start);
  1045. END NextChar;
  1046. PROCEDURE SkipBlanks;
  1047. BEGIN
  1048. (* tf returns 01X when an embedded object is encountered *)
  1049. WHILE (char = SPACE) OR (char = TAB) OR (char = 01X) DO NextChar END;
  1050. IF char = ";" THEN
  1051. WHILE (char # CR) & (char # LF) & (char # 0X) DO NextChar END (* Skip comments *)
  1052. END;
  1053. END SkipBlanks;
  1054. PROCEDURE GetNumber (VAR intval: LONGINT);
  1055. VAR i, m, n: INTEGER; dig: ARRAY 24 OF CHAR;
  1056. BEGIN
  1057. i := 0; m := 0; n := 0;
  1058. WHILE ('0' <= char) & (char <= '9') OR ('A' <= CAP (char)) & (CAP (char) <= 'F') DO
  1059. IF (m > 0) OR (char # "0") THEN (* ignore leading zeros *)
  1060. IF n < LEN(dig) THEN dig[n] := char; INC(n) END;
  1061. INC(m)
  1062. END;
  1063. NextChar; INC(i)
  1064. END;
  1065. IF n = m THEN intval := 0; i := 0;
  1066. IF (CAP (char) = "H") OR (char = "X") THEN NextChar;
  1067. IF (n = Scanner.MaxHexDigits) & (dig[0] > "7") THEN (* prevent overflow *) intval := -1 END;
  1068. WHILE i < n DO intval := intval * 10H + HexOrd (dig[i]); INC(i) END;
  1069. ELSE
  1070. IF (n = Scanner.MaxHugeHexDigits) & (dig[0] > "7") THEN (* prevent overflow *) intval := -1 END;
  1071. WHILE i < n DO intval := intval * 10 + Ord (dig[i]); INC(i) END
  1072. END
  1073. END;
  1074. END GetNumber;
  1075. PROCEDURE GetIdentifier;
  1076. VAR i: LONGINT;
  1077. BEGIN
  1078. i := 0;
  1079. REPEAT
  1080. IF i < Scanner.MaxIdentifierLength - 1 THEN
  1081. IF ('0' <= char) & (char <= '9') THEN
  1082. ident[i] := char; idents[i] := char;
  1083. ELSE
  1084. ident[i] := (* CAP *) (char); idents[i] := char; END;
  1085. INC (i);
  1086. END;
  1087. NextChar
  1088. UNTIL ~( ('A' <= CAP(char)) & (CAP(char) <= 'Z') OR ('0' <= char) & (char <= '9') OR (char = '_') );
  1089. ident[i] := 0X; idents[i] := 0X;
  1090. END GetIdentifier;
  1091. PROCEDURE GetString;
  1092. VAR i: LONGINT;
  1093. BEGIN
  1094. i := 0;
  1095. NextChar;
  1096. WHILE (char # "'") & (i < Scanner.MaxIdentifierLength - 1) DO
  1097. ident[i] := char; INC (i);
  1098. NextChar;
  1099. END;
  1100. ident[i] := 0X;
  1101. NextChar;
  1102. END GetString;
  1103. PROCEDURE NextSymbol;
  1104. BEGIN
  1105. SkipBlanks;
  1106. errPos := position;
  1107. CASE char OF
  1108. 'A' .. 'Z', 'a' .. 'z', '_' :
  1109. GetIdentifier;
  1110. SkipBlanks;
  1111. IF char = ':' THEN
  1112. NextChar; symbol := symLabel;
  1113. ELSE
  1114. symbol := symIdent;
  1115. END;
  1116. | '0' .. '9':
  1117. GetNumber (val);
  1118. symbol := symNumber;
  1119. | "'": GetString;
  1120. symbol := symString;
  1121. | '.': symbol := symPeriod;
  1122. NextChar;
  1123. | ';': symbol := symSemicolon;
  1124. NextChar;
  1125. | ':': symbol := symColon;
  1126. NextChar;
  1127. | CR: symbol := symLn;
  1128. NextChar; INC(position.line);
  1129. position.linepos := position.start;
  1130. IF char = LF THEN NextChar END;
  1131. | LF: symbol := symLn;
  1132. NextChar;INC(position.line);
  1133. position.linepos := position.start;
  1134. IF char = CR THEN NextChar END;
  1135. | ',': symbol := symComma;
  1136. NextChar;
  1137. | '+': symbol := symPlus;
  1138. NextChar;
  1139. | '-': symbol := symMinus;
  1140. NextChar;
  1141. | '*': symbol := symTimes;
  1142. NextChar;
  1143. | '/': symbol := symDiv;
  1144. NextChar;
  1145. | '%': symbol := symMod;
  1146. NextChar;
  1147. | '~': symbol := symNegate;
  1148. NextChar;
  1149. | '(': symbol := symLParen;
  1150. NextChar;
  1151. | ')': symbol := symRParen;
  1152. NextChar;
  1153. | '[': symbol := symLBraket;
  1154. NextChar;
  1155. | ']': symbol := symRBraket;
  1156. NextChar;
  1157. | '{': symbol := symLBrace;
  1158. NextChar;
  1159. | '}': symbol := symRBrace;
  1160. NextChar;
  1161. | '@': symbol := symAt;
  1162. NextChar;
  1163. | '$': NextChar;
  1164. IF char = '$' THEN
  1165. symbol := symPCOffset; NextChar;
  1166. ELSE
  1167. symbol := symPC;
  1168. END
  1169. | 0X: symbol := symEnd;
  1170. ELSE
  1171. symbol := symNone;
  1172. NextChar;
  1173. END;
  1174. END NextSymbol;
  1175. PROCEDURE SkipLine;
  1176. BEGIN
  1177. WHILE (symbol # symLn) & (symbol # symNone) DO
  1178. NextSymbol;
  1179. END;
  1180. END SkipLine;
  1181. PROCEDURE Ensure (desiredSymbol, errNumber : LONGINT) : BOOLEAN;
  1182. VAR temp: LONGINT;
  1183. BEGIN
  1184. temp := symbol;
  1185. IF symbol = desiredSymbol THEN
  1186. NextSymbol;
  1187. RETURN TRUE;
  1188. ELSE
  1189. Error("other symbol expected");
  1190. RETURN FALSE;
  1191. END;
  1192. END Ensure;
  1193. PROCEDURE GetCPU (cumulateOptions: BOOLEAN): BOOLEAN;
  1194. VAR i: LONGINT;
  1195. BEGIN
  1196. SkipBlanks;
  1197. GetIdentifier;
  1198. Strings.UpperCase(ident);
  1199. i := InstructionSet.FindCPU (ident);
  1200. IF i # InstructionSet.none THEN
  1201. IF cumulateOptions THEN
  1202. emitter.cpuOptions := emitter.cpuOptions + InstructionSet.cpus[i].cpuOptions;
  1203. ELSE
  1204. emitter.cpuOptions := InstructionSet.cpus[i].cpuOptions + InstructionSet.cpuOptions;
  1205. END;
  1206. NextSymbol;
  1207. RETURN TRUE;
  1208. ELSE
  1209. ErrorSS ("cpu unknown",ident);
  1210. emitter.cpuOptions := prevCpuOptions;
  1211. RETURN FALSE;
  1212. END;
  1213. END GetCPU;
  1214. PROCEDURE Factor (VAR x: LONGINT; critical: BOOLEAN; VAR type: SHORTINT): BOOLEAN;
  1215. VAR label: NamedLabel; l: LONGINT;
  1216. BEGIN
  1217. IF symbol = symNumber THEN
  1218. x := val; NextSymbol; RETURN TRUE;
  1219. ELSIF symbol = symPC THEN
  1220. x := (orgOffset + emitter.code.pc ); NextSymbol; RETURN TRUE;
  1221. ELSIF symbol = symPCOffset THEN
  1222. x := orgOffset; NextSymbol; RETURN TRUE;
  1223. ELSIF symbol = symString THEN
  1224. x := 0; l := Strings.Length (ident);
  1225. IF l > 0 THEN INC (x, ORD (ident [0])) END;
  1226. IF l > 1 THEN INC (x, ORD (ident [1])*100H) END;
  1227. IF l > 2 THEN INC (x, ORD (ident [2])*10000H) END;
  1228. IF l > 3 THEN INC (x, ORD (ident [3])*1000000H) END;
  1229. NextSymbol; RETURN TRUE;
  1230. ELSIF symbol = symIdent THEN
  1231. label := labels.Find (idents);
  1232. NextSymbol;
  1233. IF label # NIL THEN
  1234. x := (label.offset );
  1235. type := ioffset;
  1236. currentLabel := label;
  1237. (*
  1238. IF x = MAX(LONGINT) THEN
  1239. x := -label.index;
  1240. currentFixup := in;
  1241. END;
  1242. *)
  1243. RETURN TRUE;
  1244. ELSIF scope # NIL THEN
  1245. IF ~GetValue(idents,x) THEN
  1246. IF (pass = maxPasses) THEN
  1247. Error("constant expected");
  1248. END;
  1249. RETURN FALSE;
  1250. ELSE
  1251. RETURN TRUE;
  1252. END
  1253. END;
  1254. IF (~critical) & (pass # maxPasses) THEN
  1255. x := 0;
  1256. RETURN TRUE
  1257. END;
  1258. Error("undefined symbol");
  1259. RETURN FALSE;
  1260. ELSIF symbol = symLParen THEN
  1261. NextSymbol;
  1262. RETURN Expression (x, critical,type) & Ensure (symRParen, 555);
  1263. END;
  1264. Error("parse error in expression");
  1265. RETURN FALSE
  1266. END Factor;
  1267. PROCEDURE Term (VAR x: LONGINT; critical: BOOLEAN; VAR type: SHORTINT): BOOLEAN;
  1268. VAR y, op : LONGINT;
  1269. BEGIN
  1270. IF Factor (x, critical,type) THEN
  1271. WHILE (symbol = symTimes) OR (symbol = symDiv) OR (symbol = symMod) DO
  1272. op := symbol; NextSymbol;
  1273. IF Factor (y, critical,type) THEN
  1274. IF op = symTimes THEN x := x * y
  1275. ELSIF op = symDiv THEN x := x DIV y
  1276. ELSE x := x MOD y
  1277. END;
  1278. ELSE
  1279. RETURN FALSE;
  1280. END;
  1281. END;
  1282. RETURN TRUE;
  1283. ELSE
  1284. RETURN FALSE;
  1285. END;
  1286. END Term;
  1287. PROCEDURE Expression (VAR x: LONGINT; critical: BOOLEAN; VAR type: SHORTINT): BOOLEAN;
  1288. VAR y, op : LONGINT;
  1289. BEGIN
  1290. IF symbol = symMinus THEN
  1291. op := symbol; NextSymbol;
  1292. IF Term (x, critical,type) THEN
  1293. x := -x
  1294. ELSE
  1295. RETURN FALSE;
  1296. END;
  1297. ELSIF symbol = symPlus THEN
  1298. op := symbol; NextSymbol;
  1299. IF ~Term (x, critical,type) THEN
  1300. RETURN FALSE;
  1301. END;
  1302. ELSIF symbol = symNegate THEN
  1303. op := symbol; NextSymbol;
  1304. IF Term (x, critical,type) THEN
  1305. x := -x - 1
  1306. ELSE
  1307. RETURN FALSE;
  1308. END;
  1309. ELSIF ~Term (x, critical,type) THEN
  1310. RETURN FALSE;
  1311. END;
  1312. WHILE (symbol = symPlus) OR (symbol = symMinus) DO
  1313. op := symbol; NextSymbol;
  1314. IF Term (y, critical,type) THEN
  1315. IF op = symPlus THEN x := x + y ELSE x := x - y END;
  1316. ELSE
  1317. RETURN FALSE;
  1318. END;
  1319. END;
  1320. RETURN TRUE;
  1321. END Expression;
  1322. PROCEDURE Align(size: LONGINT);
  1323. VAR pc: LONGINT;
  1324. BEGIN
  1325. IF size <= 0 THEN Error("invalid alignment size"); RETURN END;
  1326. pc := emitter.code.pc DIV 8; (* bytes *)
  1327. WHILE pc MOD size # 0 DO
  1328. emitter.code.PutByte(0);
  1329. INC(pc);
  1330. END;
  1331. END Align;
  1332. PROCEDURE PutData (size: Size): BOOLEAN;
  1333. VAR i: LONGINT; type:SHORTINT; ofs: Operand;
  1334. BEGIN
  1335. NextSymbol;
  1336. WHILE symbol # symLn DO
  1337. IF symbol = symString THEN
  1338. i := 0;
  1339. WHILE ident[i] # 0X DO
  1340. emitter.code.PutByte (ORD (ident[i]));
  1341. INC (i);
  1342. END;
  1343. IF size # bits8 THEN
  1344. i := (size ) - i MOD (size );
  1345. WHILE i # 0 DO emitter.code.PutByte (0); DEC (i) END;
  1346. END;
  1347. NextSymbol;
  1348. ELSIF (scope # NIL) & (symbol = symAt) THEN
  1349. NextSymbol;
  1350. IF symbol # symIdent THEN Error("identifier missing") END;
  1351. GetOffsetFixup (idents, ofs);
  1352. NextSymbol;
  1353. IF symbol = symPlus THEN
  1354. NextSymbol;
  1355. IF Expression(i, FALSE, type) THEN
  1356. ofs.displacement := i
  1357. END;
  1358. ELSIF symbol = symMinus THEN
  1359. NextSymbol;
  1360. IF Expression(i, FALSE, type) THEN
  1361. ofs.displacement := - i
  1362. END;
  1363. END;
  1364. IF pass = maxPasses THEN
  1365. emitter.AddFixup(BinaryCode.Absolute, ofs.sizeInBytes, emitter.code.pc, ofs.symbol, ofs.symbolOffset,ofs.displacement);
  1366. END;
  1367. emitter.code.PutBytes (0, size );
  1368. ELSIF Expression (i, FALSE,type) THEN
  1369. emitter.code.PutBytes (i, size );
  1370. ELSE
  1371. RETURN FALSE;
  1372. END;
  1373. IF symbol = symComma THEN
  1374. NextSymbol;
  1375. ELSIF symbol # symLn THEN
  1376. Error("operand missing");
  1377. END
  1378. END;
  1379. Duplicate ((emitter.code.pc - prevPC) , NIL);
  1380. RETURN TRUE;
  1381. END PutData;
  1382. PROCEDURE Duplicate (size: LONGINT; fixup: BinaryCode.Fixup);
  1383. VAR i: LONGINT; buffer: ARRAY 100 OF CHAR; pc: LONGINT;
  1384. BEGIN
  1385. IF times = 1 THEN RETURN END;
  1386. pc := (prevPC );
  1387. IF (dump # NIL) & (pass = maxPasses) THEN dump.Hex (emitter.code.pc, 1); dump.Char (' ') END;
  1388. FOR i := 0 TO size - 1 DO
  1389. buffer[i] := emitter.code.GetByte (pc); INC(pc);
  1390. IF (dump # NIL) & (pass = maxPasses) THEN dump.Hex (ORD (buffer[i]), -2); END;
  1391. END;
  1392. pc := (prevPC );
  1393. IF times > 1 THEN
  1394. WHILE times # 1 DO
  1395. IF fixup # NIL THEN
  1396. HALT(200);
  1397. (*!!
  1398. AddFixup (fixup.adr, pc + fixup.offset - prevPC);
  1399. *)
  1400. END;
  1401. FOR i := 0 TO size - 1 DO
  1402. emitter.code.PutByteAt (pc, ORD (buffer[i])); INC(pc);
  1403. IF (dump # NIL) & (pass = maxPasses) THEN dump.Hex (ORD (buffer[i]), -2); END;
  1404. END;
  1405. DEC (times);
  1406. END;
  1407. ELSE
  1408. times := 1;
  1409. END;
  1410. IF (dump # NIL) & (pass = maxPasses) THEN dump.Ln END;
  1411. END Duplicate;
  1412. PROCEDURE Reserve (size: Size) : BOOLEAN;
  1413. VAR type : SHORTINT;
  1414. BEGIN
  1415. IF Expression (val2, TRUE, type) THEN
  1416. absoluteOffset := absoluteOffset + val2 * size;
  1417. RETURN TRUE;
  1418. ELSE
  1419. RETURN FALSE;
  1420. END;
  1421. END Reserve;
  1422. PROCEDURE GetScopeSymbol (CONST ident: ARRAY OF CHAR): SyntaxTree.Symbol;
  1423. VAR sym: SyntaxTree.Symbol; localScope: SyntaxTree.Scope; identifier: SyntaxTree.Identifier;
  1424. BEGIN
  1425. localScope := scope;
  1426. identifier := SyntaxTree.NewIdentifier(ident);
  1427. IF Trace THEN KernelLog.String("GetScopeSymbol:"); KernelLog.String(ident); KernelLog.Ln; END;
  1428. WHILE (sym = NIL) & (localScope # NIL) DO
  1429. sym := localScope.FindSymbol(identifier);
  1430. localScope := localScope.outerScope
  1431. END;
  1432. IF (sym # NIL) & (sym IS SyntaxTree.Import) THEN
  1433. NextSymbol;
  1434. IF Ensure(symPeriod,0) & (symbol = symIdent) THEN
  1435. identifier := SyntaxTree.NewIdentifier(idents);
  1436. IF Trace THEN KernelLog.String("GetScopeSymbol :"); KernelLog.String(idents); KernelLog.Ln; END;
  1437. localScope := sym(SyntaxTree.Import).module.moduleScope;
  1438. sym := NIL;
  1439. WHILE (sym = NIL) & (localScope # NIL) DO
  1440. sym := localScope.FindSymbol(identifier);
  1441. localScope := localScope.outerScope
  1442. END;
  1443. END;
  1444. END;
  1445. IF Trace THEN IF sym = NIL THEN KernelLog.String("not found") ELSE KernelLog.String("found"); END; KernelLog.Ln; END;
  1446. RETURN sym
  1447. END GetScopeSymbol;
  1448. PROCEDURE GetValue(CONST ident: ARRAY OF CHAR; VAR x: LONGINT): BOOLEAN;
  1449. VAR scopeSymbol:SyntaxTree.Symbol;
  1450. BEGIN
  1451. scopeSymbol := GetScopeSymbol (ident);
  1452. IF scopeSymbol = NIL THEN RETURN FALSE
  1453. ELSIF ~(scopeSymbol IS SyntaxTree.Constant) THEN RETURN FALSE
  1454. ELSE
  1455. IF (scopeSymbol.type.resolved IS SyntaxTree.CharacterType) & (scopeSymbol.type.resolved.sizeInBits=8) THEN
  1456. x := ORD(scopeSymbol(SyntaxTree.Constant).value.resolved(SyntaxTree.CharacterValue).value)
  1457. ELSIF scopeSymbol.type.resolved IS SyntaxTree.IntegerType THEN
  1458. x := scopeSymbol(SyntaxTree.Constant).value.resolved(SyntaxTree.IntegerValue).value
  1459. ELSE
  1460. Error("number expected");
  1461. RETURN FALSE;
  1462. END;
  1463. RETURN TRUE;
  1464. END;
  1465. END GetValue;
  1466. PROCEDURE GetMemFixup (CONST ident: ARRAY OF CHAR; VAR operand: Operand);
  1467. VAR scopeSymbol:SyntaxTree.Symbol;
  1468. BEGIN
  1469. scopeSymbol := GetScopeSymbol (ident);
  1470. IF scopeSymbol = NIL THEN RETURN END;
  1471. IF scopeSymbol IS SyntaxTree.Constant THEN
  1472. RETURN
  1473. END;
  1474. IF inlined & exported THEN
  1475. Error("no symbols may be accessed in exported and inlined procedures");
  1476. END;
  1477. IF (scopeSymbol IS SyntaxTree.Variable) & (scopeSymbol.scope = module.module.moduleScope) THEN (* global variable. offset not supported *)
  1478. Error("global variables cannot be accessed as memory operands");
  1479. ELSIF (scopeSymbol IS SyntaxTree.Variable) THEN (* local variable *)
  1480. operand.displacement := (scopeSymbol.offsetInBits DIV 8)
  1481. ELSIF (scopeSymbol IS SyntaxTree.Parameter) THEN (* local parameter *)
  1482. operand.displacement := (scopeSymbol.offsetInBits DIV 8)
  1483. ELSE
  1484. RETURN (* ? *)
  1485. END;
  1486. (*! mem.fixup := scopeSymbol.adr; *)
  1487. NextSymbol;
  1488. END GetMemFixup;
  1489. PROCEDURE GetOffsetFixup (CONST ident: ARRAY OF CHAR; VAR operand: Operand);
  1490. VAR scopeSymbol: SyntaxTree.Symbol;name: Basic.SegmentedName; symbol: IntermediateCode.Section;
  1491. BEGIN
  1492. IF labels.Find(ident) # NIL THEN RETURN END;
  1493. scopeSymbol := GetScopeSymbol (ident);
  1494. IF (scopeSymbol = NIL) OR (scopeSymbol IS SyntaxTree.Constant) THEN RETURN END;
  1495. IF inlined & exported THEN
  1496. Error("no symbols may be accessed in exported and inlined procedures");
  1497. END;
  1498. Global.GetSymbolSegmentedName(scopeSymbol,name);
  1499. IF scopeSymbol.scope IS SyntaxTree.ModuleScope THEN
  1500. IF (scopeSymbol IS SyntaxTree.Variable) THEN
  1501. InitMem(operand,IntermediateCode.Bits32,none,0); (* or immediate ?? *)
  1502. ELSIF (scopeSymbol IS SyntaxTree.Procedure) & (scopeSymbol.scope = module.module.moduleScope) THEN
  1503. IF scopeSymbol(SyntaxTree.Procedure).isInline THEN
  1504. Error("fobidden reference to inline call");
  1505. ELSE
  1506. InitOffset32(operand,0); (* or immediate ?? *)
  1507. END;
  1508. ELSIF (scopeSymbol IS SyntaxTree.Procedure) THEN
  1509. InitOffset32(operand,0); (* or immediate ?? *)
  1510. END;
  1511. SetSymbol(operand,name,0,0,0);
  1512. ELSE
  1513. Error("direct access to local variable offset forbidden");
  1514. END;
  1515. operand.sizeInBytes := emitter.cpuBits;
  1516. END GetOffsetFixup;
  1517. (* the following procedure is used to adapt sizes for relative jumps *)
  1518. PROCEDURE AdaptOperandSizes(VAR operands: ARRAY OF Operand);
  1519. VAR i: LONGINT;
  1520. PROCEDURE OffsetSize(val: HUGEINT): SHORTINT;
  1521. BEGIN
  1522. DEC(val,emitter.code.pc);
  1523. IF (val > MIN(SHORTINT)+2) & (val < MAX(SHORTINT)) THEN
  1524. RETURN bits8
  1525. (* We do not support word (16-bit) displacement jumps
  1526. (i.e. prefixing the jump instruction with the `addr16' opcode prefix),
  1527. since the 80386 insists upon masking `%eip' to 16 bits after the word
  1528. displacement is added. *)
  1529. ELSIF (val > MIN(LONGINT)+2) & (val < MAX(LONGINT)-2) THEN
  1530. RETURN bits32
  1531. ELSE
  1532. RETURN bits64
  1533. END;
  1534. END OffsetSize;
  1535. BEGIN
  1536. i := 0;
  1537. WHILE (i< LEN(operands)) & (operands[i].type # none) DO
  1538. IF (operands[i].type = ioffset) & (operands[i].sizeInBytes = bitsDefault)
  1539. THEN
  1540. IF operands[i].symbol.name = "" THEN
  1541. operands[i].sizeInBytes := OffsetSize(operands[i].val);
  1542. ELSE
  1543. operands[i].sizeInBytes := bits32
  1544. END;
  1545. END;
  1546. INC(i)
  1547. END;
  1548. END AdaptOperandSizes;
  1549. PROCEDURE GetInstruction (): BOOLEAN;
  1550. VAR
  1551. position: Basic.Position;
  1552. mnem, opCount: LONGINT;
  1553. size: Size;
  1554. operands: ARRAY InstructionSet.maxNumberOperands OF Operand;
  1555. prevFixup: BinaryCode.Fixup;
  1556. mem: Operand;
  1557. offset: Operand;
  1558. i: LONGINT;
  1559. type: SHORTINT;
  1560. BEGIN
  1561. position := errPos;
  1562. mnem := InstructionSet.FindMnemonic (ident);
  1563. IF mnem = InstructionSet.none THEN
  1564. ErrorSS("unkown instruction",idents);
  1565. RETURN FALSE;
  1566. END;
  1567. opCount := 0;
  1568. NextSymbol;
  1569. FOR i := 0 TO LEN(operands)-1 DO
  1570. InitOperand(operands[i]);
  1571. END;
  1572. WHILE (symbol # symLn) & (symbol # symNone) & (symbol # symEnd) DO
  1573. IF symbol = symIdent THEN
  1574. IF (ident = "BYTE") OR (ident = "SHORT") THEN
  1575. size := bits8; NextSymbol;
  1576. ELSIF (ident = "WORD") OR (ident = "NEAR") THEN
  1577. size := bits16; NextSymbol;
  1578. ELSIF ident = "DWORD" THEN
  1579. size := bits32; NextSymbol;
  1580. ELSIF ident = "QWORD" THEN
  1581. size := bits64; NextSymbol;
  1582. ELSIF ident = "TWORD" THEN
  1583. size := bits128; NextSymbol;
  1584. ELSE
  1585. size := bitsDefault;
  1586. END;
  1587. ELSE
  1588. size := bitsDefault;
  1589. END;
  1590. IF symbol = symIdent THEN (* register ?, for example EAX *)
  1591. reg := InstructionSet.FindRegister (ident);
  1592. IF reg = InstructionSet.none THEN
  1593. reg := map.Find(ident)
  1594. END;
  1595. IF reg # InstructionSet.none THEN
  1596. IF size # bitsDefault THEN
  1597. Error ("invalid register size specification"); RETURN FALSE;
  1598. END;
  1599. InitRegister(operands[opCount], reg);
  1600. INC (opCount);
  1601. NextSymbol;
  1602. END;
  1603. ELSE
  1604. reg := InstructionSet.none;
  1605. END;
  1606. IF reg = InstructionSet.none THEN
  1607. IF symbol = symLBraket THEN
  1608. (* mem, written as [....] *)
  1609. NextSymbol;
  1610. InitMem(mem, size, InstructionSet.none,0); (*! ??? *)
  1611. IF symbol = symLabel THEN (* register segment as in [ES:...] *)
  1612. reg := InstructionSet.FindRegister (ident);
  1613. IF reg = InstructionSet.none THEN
  1614. ErrorSS("undefined symbol",idents);
  1615. RETURN FALSE;
  1616. END;
  1617. mem.segment := reg;
  1618. NextSymbol;
  1619. END;
  1620. IF symbol = symIdent THEN (* register, for example [EAX] or [ES:EAX] *)
  1621. reg := InstructionSet.FindRegister (ident);
  1622. IF reg # InstructionSet.none THEN
  1623. mem.register := reg;
  1624. NextSymbol;
  1625. IF symbol = symTimes THEN (* register multiply as in [EAX*4] *)
  1626. NextSymbol;
  1627. IF ~Factor (mem.scale, FALSE,type) THEN
  1628. RETURN FALSE;
  1629. END;
  1630. mem.index := mem.register;
  1631. mem.register := InstructionSet.none;
  1632. END;
  1633. IF symbol = symPlus THEN (* register add as in [EAX + EBX] *)
  1634. NextSymbol;
  1635. IF symbol = symIdent THEN
  1636. reg := InstructionSet.FindRegister (ident);
  1637. IF reg # InstructionSet.none THEN (* maybe it is this: [EAX + EBX * 4] *)
  1638. NextSymbol;
  1639. IF mem.index = InstructionSet.none THEN
  1640. mem.index := reg;
  1641. IF symbol = symTimes THEN
  1642. NextSymbol;
  1643. IF ~Factor (mem.scale, FALSE,type) THEN
  1644. RETURN FALSE;
  1645. END;
  1646. END;
  1647. ELSE
  1648. mem.register := reg;
  1649. END;
  1650. END;
  1651. END;
  1652. END;
  1653. END;
  1654. END;
  1655. IF symbol = symPlus THEN
  1656. NextSymbol;
  1657. END;
  1658. IF (scope # NIL) & (symbol = symIdent) THEN
  1659. GetMemFixup (idents, mem);
  1660. END;
  1661. IF (symbol # symRBraket) & (symbol # symNegate) THEN
  1662. val2 := 0;
  1663. IF ~Expression (val2, FALSE ,type) THEN
  1664. RETURN FALSE;
  1665. END;
  1666. INC (mem.displacement, val2);
  1667. ELSIF (mem.register = InstructionSet.none) & (mem.index = InstructionSet.none) THEN
  1668. Error("operand missing: no register provided");
  1669. RETURN FALSE;
  1670. END;
  1671. operands[opCount] := mem;
  1672. INC (opCount);
  1673. IF ~Ensure (symRBraket, 556) THEN
  1674. RETURN FALSE;
  1675. END;
  1676. ELSE
  1677. (* number or identifier (symbol) *)
  1678. InitImm(offset,size,0);
  1679. IF (scope # NIL) & (symbol = symIdent) THEN (* identifier: must be a symbol *)
  1680. GetOffsetFixup (idents, offset);
  1681. END;
  1682. IF offset.symbol.name = "" THEN (* nothing could be fixuped, must be a number / constant *)
  1683. type := offset.type; currentFixup := ""; currentLabel := NIL;
  1684. IF ~Expression (val2, FALSE,type) THEN
  1685. RETURN FALSE;
  1686. ELSE
  1687. offset.type := type;
  1688. IF currentFixup # "" THEN
  1689. offset.symbol.name := currentFixup; offset.symbolOffset := val2;
  1690. ELSIF currentLabel # NIL THEN
  1691. IF (offset.sizeInBytes = bitsDefault ) & (val2 > emitter.code.pc) THEN (* forward jump *)
  1692. offset.sizeInBytes := bits32
  1693. END;
  1694. (*
  1695. IF offset.sizeInBytes = bitsDefault THEN
  1696. offset.sizeInBytes := bits32;
  1697. END;
  1698. *)
  1699. END;
  1700. END;
  1701. offset.val := val2;
  1702. IF symbol = symColon THEN (* additional prefixed operand separated by ":", segmentation register *)
  1703. NextSymbol;
  1704. IF ~Expression (val3, FALSE, type) THEN
  1705. RETURN FALSE;
  1706. END;
  1707. InitOffset(operands[opCount],bitsDefault,val3);
  1708. INC (opCount);
  1709. END;
  1710. ELSE
  1711. NextSymbol;
  1712. END;
  1713. operands[opCount] := offset;
  1714. INC (opCount);
  1715. END;
  1716. END;
  1717. IF symbol = symComma THEN
  1718. NextSymbol;
  1719. ELSIF (symbol # symLn) & (symbol # symEnd) THEN
  1720. Error("operand missing");
  1721. END
  1722. END;
  1723. prevFixup := fixup;
  1724. AdaptOperandSizes(operands);
  1725. errPos := position;
  1726. IF ~emitter.EmitInstruction (mnem, operands, pass = maxPasses) THEN
  1727. RETURN FALSE;
  1728. END;
  1729. IF fixup = prevFixup THEN
  1730. Duplicate ((emitter.code.pc - prevPC) , NIL);
  1731. ELSE
  1732. Duplicate ((emitter.code.pc - prevPC) , fixup);
  1733. END;
  1734. RETURN TRUE;
  1735. END GetInstruction;
  1736. PROCEDURE Reset;
  1737. BEGIN
  1738. reader.SetPos(orgReaderPos);
  1739. emitter.code.SetPC(orgCodePos);
  1740. NextChar;
  1741. position := orgPos;
  1742. END Reset;
  1743. PROCEDURE FindLabels;
  1744. VAR firstInLine : BOOLEAN; label: NamedLabel;
  1745. BEGIN
  1746. IF Trace THEN KernelLog.String("find labels"); KernelLog.Ln; END;
  1747. LOOP
  1748. NextSymbol;
  1749. IF symbol = symLn THEN
  1750. firstInLine := TRUE;
  1751. ELSIF symbol = symLabel THEN
  1752. IF firstInLine THEN
  1753. IF labels.Find(idents) # NIL THEN
  1754. Error("multiply declared identifier")
  1755. ELSE
  1756. NEW(label,MAX(LONGINT),idents);
  1757. labels.Add(label);
  1758. IF Trace THEN KernelLog.String("found label"); KernelLog.String(idents); KernelLog.Ln; END;
  1759. END
  1760. END;
  1761. ELSIF symbol = symEnd THEN
  1762. EXIT
  1763. ELSE
  1764. firstInLine := FALSE;
  1765. END;
  1766. END;
  1767. END FindLabels;
  1768. PROCEDURE FixupLabels;
  1769. VAR label: NamedLabel;
  1770. BEGIN
  1771. IF Trace THEN KernelLog.String("patch fixups "); KernelLog.Ln; END;
  1772. fixup := emitter.code.fixupList.firstFixup;
  1773. WHILE fixup # NIL DO
  1774. IF (fixup.symbol.name = in.name) & (fixup.symbolOffset < 0) THEN
  1775. label := labels.first;
  1776. WHILE (label # NIL) & (label.index # -fixup.symbolOffset) DO label := label.nextNamedLabel END;
  1777. (*
  1778. fixup.SetSymbolOffset(label.offset);
  1779. *)
  1780. fixup.SetSymbol(out.name,0,0,label.offset+fixup.displacement);
  1781. IF Trace THEN
  1782. KernelLog.String("patch fixup: ");
  1783. KernelLog.Hex(fixup.offset,1); KernelLog.String(" "); KernelLog.Hex(-fixup.displacement, 1);
  1784. KernelLog.String(" "); KernelLog.Hex(label.offset, 1); KernelLog.Ln;
  1785. END;
  1786. END;
  1787. fixup := fixup.nextFixup;
  1788. END;
  1789. END FixupLabels;
  1790. BEGIN
  1791. prevAssembly := emitter.assembly;
  1792. prevSourceName := sourceName;
  1793. prevCpuBits := emitter.cpuBits;
  1794. prevCpuOptions := emitter.cpuOptions;
  1795. emitter.assembly := SELF;
  1796. IF scope # NIL THEN
  1797. sourceName := scope.ownerModule.sourceName;
  1798. END;
  1799. NEW(labels);
  1800. orgReaderPos := reader.Pos();
  1801. orgCodePos := emitter.code.pc;
  1802. NextChar;
  1803. position := orgPos;
  1804. (* first we have to find all labels as their names might collide with symbol names *)
  1805. FindLabels;
  1806. FOR pass := 1 TO maxPasses DO (*! currently maxPasses = 1 *)
  1807. Reset;
  1808. times := 1;
  1809. prevPC := emitter.code.pc;
  1810. currentLabel := NIL;
  1811. absoluteMode := FALSE;
  1812. orgOffset := 0;
  1813. NextSymbol;
  1814. IF (scope # NIL) THEN
  1815. IF symbol # symLBrace THEN
  1816. (* treat CPU options as an optional limitation and not vice versa *)
  1817. ELSE
  1818. emitter.cpuOptions := {};
  1819. NextSymbol;
  1820. (* parse code flags such as {SYSTEM.i386 .... } *)
  1821. LOOP
  1822. IF ~Ensure (symIdent, 551) THEN
  1823. RETURN
  1824. END;
  1825. IF ident # "SYSTEM" THEN
  1826. Error("unsupportorted target identifier");
  1827. RETURN
  1828. END;
  1829. IF symbol # symPeriod THEN
  1830. Error("identifier expected");
  1831. RETURN;
  1832. END;
  1833. IF ~GetCPU (TRUE) THEN
  1834. RETURN;
  1835. END;
  1836. IF symbol = symRBrace THEN
  1837. EXIT
  1838. ELSIF symbol = symComma THEN
  1839. NextSymbol
  1840. ELSE
  1841. Error("target specifier expected");
  1842. RETURN;
  1843. END;
  1844. END;
  1845. NextSymbol;
  1846. END
  1847. END;
  1848. LOOP
  1849. IF symbol = symLn THEN
  1850. NextSymbol;
  1851. ELSIF symbol = symLabel THEN
  1852. currentLabel := labels.Find(idents);
  1853. ASSERT(currentLabel # NIL);
  1854. IF absoluteMode THEN
  1855. currentLabel.SetOffset(absoluteOffset);
  1856. ELSE
  1857. currentLabel.SetOffset(emitter.code.pc)
  1858. END;
  1859. NextSymbol;
  1860. ELSIF symbol = symIdent THEN
  1861. IF ident = "END" THEN
  1862. symbol := symNone;
  1863. ELSIF ident = "BITS" THEN
  1864. NextSymbol;
  1865. IF ~Ensure (symNumber, 553) OR ~emitter.SetBits (val) THEN
  1866. SkipLine;
  1867. ELSE
  1868. NextSymbol;
  1869. END;
  1870. ELSIF ident = "ALIGN" THEN
  1871. NextSymbol;
  1872. IF Expression(alignment, TRUE, type) THEN
  1873. Align(alignment);
  1874. END;
  1875. ELSIF ~(scope # NIL) & (ident = "CPU") THEN
  1876. IF ~GetCPU (FALSE) THEN
  1877. SkipLine;
  1878. END;
  1879. ELSIF ~(scope # NIL) & (ident = "ABSOLUTE") THEN
  1880. absoluteMode := TRUE;
  1881. NextSymbol;
  1882. IF ~Expression (absoluteOffset, TRUE,type) THEN
  1883. SkipLine;
  1884. END;
  1885. ELSIF ~(scope # NIL) & (ident = "ORG") THEN
  1886. NextSymbol;
  1887. IF (orgOffset # 0) OR ~Expression (orgOffset, TRUE,type) THEN
  1888. SkipLine;
  1889. END;
  1890. ELSIF ~(scope # NIL) & (ident = "RESB") THEN
  1891. NextSymbol;
  1892. IF ~Reserve (1) THEN SkipLine END;
  1893. ELSIF ~(scope # NIL) & (ident = "RESW") THEN
  1894. NextSymbol;
  1895. IF ~Reserve (2) THEN SkipLine END;
  1896. ELSIF ~(scope # NIL) & (ident = "RESD") THEN
  1897. NextSymbol;
  1898. IF ~Reserve (4) THEN SkipLine END;
  1899. (*
  1900. ELSIF ident = "EQU" THEN
  1901. IF currentLabel # NIL THEN
  1902. NextSymbol;
  1903. IF Expression (val2, FALSE) THEN
  1904. currentLabel.pc := val2;
  1905. currentLabel.equ := TRUE;
  1906. ELSE
  1907. SkipLine;
  1908. END;
  1909. ELSE
  1910. Error("???");
  1911. RETURN;
  1912. END;
  1913. *)
  1914. ELSIF ident = "TIMES" THEN
  1915. NextSymbol;
  1916. IF ~Expression (times, TRUE,type) THEN
  1917. SkipLine;
  1918. ELSIF times < 0 THEN
  1919. Error("unsupported negative value"); RETURN;
  1920. ELSE
  1921. prevPC := emitter.code.pc;
  1922. END;
  1923. ELSIF ident = "DB" THEN
  1924. IF ~PutData (bits8) THEN SkipLine END;
  1925. ELSIF ident = "DW" THEN
  1926. IF ~PutData (bits16) THEN SkipLine END;
  1927. ELSIF ident = "DD" THEN
  1928. IF ~PutData (bits32) THEN SkipLine END;
  1929. ELSIF ident = "DQ" THEN
  1930. IF ~PutData (bits64) THEN SkipLine END;
  1931. ELSIF ident = "REP" THEN
  1932. NextSymbol;
  1933. emitter.code.PutByte (InstructionSet.prfREP);
  1934. ELSIF ident = "LOCK" THEN
  1935. NextSymbol;
  1936. emitter.code.PutByte (InstructionSet.prfLOCK);
  1937. ELSIF ident = "REPE" THEN
  1938. NextSymbol;
  1939. emitter.code.PutByte (InstructionSet.prfREPE);
  1940. ELSIF ident = "REPZ" THEN
  1941. NextSymbol;
  1942. emitter.code.PutByte (InstructionSet.prfREPZ);
  1943. ELSIF ident = "REPNE" THEN
  1944. NextSymbol;
  1945. emitter.code.PutByte (InstructionSet.prfREPNE);
  1946. ELSIF ident = "REPNZ" THEN
  1947. NextSymbol;
  1948. emitter.code.PutByte (InstructionSet.prfREPNZ);
  1949. ELSIF ~GetInstruction () THEN
  1950. SkipLine
  1951. END;
  1952. currentLabel := NIL;
  1953. ELSIF (symbol = symNone) OR (symbol = symEnd) THEN
  1954. EXIT
  1955. ELSE
  1956. Error("identifier expected");
  1957. RETURN;
  1958. END;
  1959. END;
  1960. END;
  1961. (*
  1962. FixupLabels();
  1963. *)
  1964. (*! FixupLabels(labels.first,code) *)
  1965. sourceName := prevSourceName;
  1966. emitter.cpuBits := prevCpuBits;
  1967. emitter.cpuOptions := prevCpuOptions;
  1968. emitter.assembly := prevAssembly;
  1969. END Assemble;
  1970. END Assembly;
  1971. VAR kernelWriter: Streams.Writer;
  1972. PROCEDURE Ord (ch: CHAR): INTEGER;
  1973. BEGIN RETURN ORD (ch) - ORD ("0")
  1974. END Ord;
  1975. PROCEDURE HexOrd (ch: CHAR): INTEGER;
  1976. BEGIN
  1977. IF ch <= "9" THEN RETURN ORD (ch) - ORD ("0")
  1978. ELSE RETURN ORD (CAP (ch)) - ORD ("A") + 10
  1979. END
  1980. END HexOrd;
  1981. PROCEDURE IsRegisterOperand*(CONST op: Operand): BOOLEAN;
  1982. BEGIN
  1983. RETURN op.type IN {reg8, reg16, reg32, reg64, CRn, DRn, segReg, sti, mmx, xmm}
  1984. END IsRegisterOperand;
  1985. PROCEDURE IsMemoryOperand*(CONST op: Operand): BOOLEAN;
  1986. BEGIN RETURN op.type = mem
  1987. END IsMemoryOperand;
  1988. PROCEDURE IsImmediateOperand*(CONST op: Operand): BOOLEAN;
  1989. BEGIN RETURN op.type = imm
  1990. END IsImmediateOperand;
  1991. PROCEDURE DumpType*(w: Streams.Writer; type: LONGINT);
  1992. BEGIN
  1993. CASE type OF
  1994. reg8: w.String("reg8")
  1995. |reg16: w.String("reg16");
  1996. |reg32: w.String("reg32");
  1997. |reg64: w.String("reg64");
  1998. |CRn: w.String("CRn");
  1999. |DRn: w.String("DRn");
  2000. |segReg: w.String("segReg");
  2001. |mmx: w.String("mmx");
  2002. |xmm: w.String("xmm");
  2003. |mem: w.String("mem");
  2004. |sti: w.String("sti");
  2005. |imm: w.String("imm");
  2006. |ioffset: w.String("ioffset");
  2007. |pntr1616: w.String("pntr1616");
  2008. |pntr1632: w.String("pntr1632");
  2009. ELSE
  2010. w.String("?"); w.Int(type,1); w.String("?");
  2011. END;
  2012. END DumpType;
  2013. PROCEDURE DumpOperand*(w: Streams.Writer; CONST operand: Operand);
  2014. BEGIN
  2015. CASE operand.type OF
  2016. |reg8, reg16, reg32, reg64, CRn, DRn, segReg, sti, mmx, xmm:
  2017. w.String(InstructionSet.registers[operand.register].name);
  2018. |mem:
  2019. IF operand.sizeInBytes = 1 THEN w.String("BYTE ")
  2020. ELSIF operand.sizeInBytes= 2 THEN w.String("WORD ")
  2021. ELSIF operand.sizeInBytes = 4 THEN w.String("DWORD ")
  2022. ELSIF operand.sizeInBytes = 8 THEN w.String("QWORD ")
  2023. END;
  2024. w.String("[");
  2025. IF operand.register # none THEN
  2026. w.String(InstructionSet.registers[operand.register].name);
  2027. IF operand.index # none THEN w.String("+") END;
  2028. END;
  2029. IF operand.index # none THEN
  2030. w.String(InstructionSet.registers[operand.index].name);
  2031. IF operand.scale # 1 THEN
  2032. w.String("*"); w.Int(operand.scale,1);
  2033. END;
  2034. END;
  2035. IF operand.symbol.name # "" THEN
  2036. Basic.WriteSegmentedName(w, operand.symbol.name); w.String(":"); w.Int(operand.displacement,1);
  2037. IF operand.symbolOffset # 0 THEN w.String("(@"); w.Int(operand.symbolOffset,1); w.String(")") END;
  2038. ELSIF operand.displacement # 0 THEN
  2039. IF (operand.displacement > 0) & ((operand.register # none) OR (operand.index # none)) THEN w.String("+");END;
  2040. w.Int(operand.displacement,1);
  2041. END;
  2042. w.String("]");
  2043. |imm,ioffset:
  2044. IF operand.symbol.name # "" THEN
  2045. Basic.WriteSegmentedName(w, operand.symbol.name); w.String(":"); w.Int(operand.displacement,1);
  2046. IF operand.symbolOffset # 0 THEN w.String("(@"); w.Int(operand.symbolOffset,1); w.String(")") END;
  2047. ELSE
  2048. IF (operand.val > MAX(LONGINT)) OR (operand.val < MIN(LONGINT)) THEN
  2049. w.Hex(operand.val,1); w.String("H");
  2050. ELSE
  2051. w.Int(SHORT(operand.val),1);
  2052. END;
  2053. END;
  2054. |pntr1616:
  2055. |pntr1632:
  2056. ELSE
  2057. HALT(100)
  2058. END;
  2059. END DumpOperand;
  2060. PROCEDURE DumpInstruction(w: Streams.Writer; mnemonic: LONGINT; CONST operands: ARRAY OF Operand);
  2061. VAR i: LONGINT;
  2062. CONST DebugSize = FALSE;
  2063. BEGIN
  2064. IF mnemonic # none THEN
  2065. w.String(InstructionSet.mnemonics[mnemonic].name);
  2066. i := 0;
  2067. WHILE(i<maxNumberOperands) & (operands[i].type # none) DO
  2068. IF i = 0 THEN w.Char(09X) ELSE w.String(", ") END;
  2069. DumpOperand(w,operands[i]);
  2070. IF DebugSize THEN
  2071. w.String("(*"); DumpType(w,operands[i].type); w.String(":"); w.Int(operands[i].sizeInBytes,1); w.String("*)");
  2072. END;
  2073. INC(i);
  2074. END;
  2075. w.String("; ");
  2076. END;
  2077. END DumpInstruction;
  2078. PROCEDURE Matches(CONST operand: Operand; type: InstructionSet.OperandType): BOOLEAN;
  2079. PROCEDURE IsMemReg(regIndex: LONGINT): BOOLEAN;
  2080. BEGIN
  2081. RETURN InstructionSet.RegisterType(regIndex) IN {reg16, reg32, reg64}
  2082. END IsMemReg;
  2083. BEGIN
  2084. CASE operand.type OF
  2085. |reg8:
  2086. CASE type OF
  2087. InstructionSet.reg8, InstructionSet.regmem8:
  2088. RETURN TRUE;
  2089. | InstructionSet.AL, InstructionSet.rAX:
  2090. RETURN InstructionSet.RegisterIndex(operand.register) = RAX;
  2091. | InstructionSet.CL:
  2092. RETURN InstructionSet.RegisterIndex(operand.register) = RCX;
  2093. ELSE
  2094. RETURN FALSE;
  2095. END;
  2096. |reg16:
  2097. CASE type OF
  2098. InstructionSet.reg16, InstructionSet.regmem16:
  2099. RETURN TRUE;
  2100. | InstructionSet.AX, InstructionSet.rAX:
  2101. RETURN InstructionSet.RegisterIndex(operand.register) = RAX;
  2102. | InstructionSet.DX:
  2103. RETURN InstructionSet.RegisterIndex(operand.register) = RDX;
  2104. ELSE
  2105. RETURN FALSE;
  2106. END;
  2107. |reg32:
  2108. CASE type OF
  2109. InstructionSet.reg32, InstructionSet.regmem32:
  2110. RETURN TRUE;
  2111. | InstructionSet.EAX, InstructionSet.rAX:
  2112. RETURN InstructionSet.RegisterIndex(operand.register) = RAX;
  2113. ELSE
  2114. RETURN FALSE;
  2115. END;
  2116. |reg64:
  2117. CASE type OF
  2118. InstructionSet.reg64, InstructionSet.regmem64:
  2119. RETURN TRUE;
  2120. | InstructionSet.RAX, InstructionSet.rAX:
  2121. RETURN InstructionSet.RegisterIndex(operand.register) = RAX;
  2122. ELSE
  2123. RETURN FALSE;
  2124. END;
  2125. |CRn:
  2126. CASE type OF
  2127. InstructionSet.CRn:
  2128. RETURN TRUE;
  2129. | InstructionSet.CR8:
  2130. RETURN InstructionSet.RegisterIndex(operand.register) = 8;
  2131. ELSE
  2132. RETURN FALSE;
  2133. END;
  2134. |DRn:
  2135. RETURN type = InstructionSet.DRn;
  2136. |segReg:
  2137. CASE type OF
  2138. InstructionSet.segReg:
  2139. RETURN TRUE;
  2140. | InstructionSet.ES:
  2141. RETURN InstructionSet.RegisterIndex(operand.register) = segES;
  2142. | InstructionSet.CS:
  2143. RETURN InstructionSet.RegisterIndex(operand.register) = segCS;
  2144. | InstructionSet.SS:
  2145. RETURN InstructionSet.RegisterIndex(operand.register) = segSS;
  2146. | InstructionSet.DS:
  2147. RETURN InstructionSet.RegisterIndex(operand.register) = segDS;
  2148. | InstructionSet.FS:
  2149. RETURN InstructionSet.RegisterIndex(operand.register) = segFS;
  2150. | InstructionSet.GS:
  2151. RETURN InstructionSet.RegisterIndex(operand.register) = segGS;
  2152. ELSE
  2153. RETURN FALSE;
  2154. END
  2155. |sti:
  2156. CASE type OF
  2157. InstructionSet.sti:
  2158. RETURN TRUE;
  2159. | InstructionSet.st0:
  2160. RETURN InstructionSet.RegisterIndex(operand.register) = 0;
  2161. ELSE
  2162. RETURN FALSE;
  2163. END
  2164. |mmx:
  2165. CASE type OF
  2166. InstructionSet.mmx, InstructionSet.mmxmem32, InstructionSet.mmxmem64:
  2167. RETURN TRUE;
  2168. ELSE
  2169. RETURN FALSE;
  2170. END
  2171. |xmm:
  2172. CASE type OF
  2173. InstructionSet.xmm, InstructionSet.xmmmem32, InstructionSet.xmmmem64, InstructionSet.xmmmem128:
  2174. RETURN TRUE;
  2175. ELSE
  2176. RETURN FALSE;
  2177. END
  2178. |mem:
  2179. CASE type OF
  2180. | InstructionSet.mem:
  2181. RETURN TRUE;
  2182. | InstructionSet.mem8:
  2183. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8);
  2184. | InstructionSet.regmem8:
  2185. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8)) & ((operand.register= none) OR (IsMemReg(operand.register)));
  2186. | InstructionSet.mem16:
  2187. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16);
  2188. | InstructionSet.regmem16:
  2189. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16)) & ((operand.register= none) OR (IsMemReg(operand.register)));
  2190. | InstructionSet.mem32:
  2191. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32);
  2192. | InstructionSet.regmem32, InstructionSet.mmxmem32, InstructionSet.xmmmem32:
  2193. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32)) & ((operand.register= none) OR (IsMemReg(operand.register)));
  2194. | InstructionSet.mem64:
  2195. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits64);
  2196. | InstructionSet.regmem64, InstructionSet.mmxmem64, InstructionSet.xmmmem64:
  2197. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits64)) & ((operand.register= none) OR (IsMemReg(operand.register)));
  2198. | InstructionSet.mem128:
  2199. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits128);
  2200. | InstructionSet.xmmmem128:
  2201. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits128)) & ((operand.register= none) OR (IsMemReg(operand.register)));
  2202. | InstructionSet.moffset8:
  2203. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8)) & (operand.register= none);
  2204. | InstructionSet.moffset16:
  2205. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16)) & (operand.register= none);
  2206. | InstructionSet.moffset32:
  2207. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32)) & (operand.register= none);
  2208. | InstructionSet.moffset64:
  2209. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits64)) & (operand.register= none);
  2210. ELSE
  2211. RETURN FALSE;
  2212. END;
  2213. |imm,ioffset:
  2214. CASE type OF
  2215. InstructionSet.one:
  2216. RETURN operand.val = 1
  2217. | InstructionSet.three:
  2218. RETURN operand.val = 3
  2219. | InstructionSet.rel8off:
  2220. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8)
  2221. | InstructionSet.imm8:
  2222. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8)) & (operand.val >= -80H) & (operand.val < 100H)
  2223. | InstructionSet.simm8:
  2224. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8)) & (operand.val >= -80H) & (operand.val < 80H)
  2225. | InstructionSet.uimm8:
  2226. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits8)) & (operand.val >= 0H) & (operand.val < 100H)
  2227. | InstructionSet.rel16off:
  2228. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16) & FALSE (* do not allow 16 bit jumps *)
  2229. | InstructionSet.imm16:
  2230. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16)) & (operand.val >= -8000H) & (operand.val < 10000H)
  2231. | InstructionSet.simm16:
  2232. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16)) & (operand.val >= -8000H) & (operand.val < 8000H)
  2233. | InstructionSet.uimm16:
  2234. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits16)) & (operand.val >= 0H) & (operand.val < 10000H)
  2235. | InstructionSet.rel32off:
  2236. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32) (* & & (operand.val >= -80000000H) & (operand.val < 100000000H) PACO confused? *)
  2237. | InstructionSet.imm32:
  2238. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32)) (* & & (operand.val >= -80000000H) & (operand.val < 100000000H) PACO confused? *)
  2239. | InstructionSet.simm32:
  2240. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32)) (* & & (operand.val >= -80000000H) & (operand.val < 80000000H) PACO confused? *)
  2241. | InstructionSet.uimm32:
  2242. RETURN ((operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits32)) & (operand.val >= 0H) (* & (operand.val < 100000000H) PACO confused? *)
  2243. | InstructionSet.imm64:
  2244. RETURN (operand.sizeInBytes = bitsDefault) OR (operand.sizeInBytes = bits64)
  2245. ELSE
  2246. RETURN FALSE
  2247. END
  2248. |pntr1616:
  2249. RETURN type = InstructionSet.pntr1616;
  2250. |pntr1632:
  2251. RETURN type = InstructionSet.pntr1632;
  2252. ELSE
  2253. HALT(100)
  2254. END;
  2255. END Matches;
  2256. PROCEDURE ValueInByteRange (value: HUGEINT): BOOLEAN;
  2257. BEGIN RETURN SYSTEM.VAL (SHORTINT, value) = value
  2258. END ValueInByteRange;
  2259. PROCEDURE ValueInWordRange (value: HUGEINT): BOOLEAN;
  2260. BEGIN RETURN SYSTEM.VAL (INTEGER, value) = value
  2261. END ValueInWordRange;
  2262. PROCEDURE InitOperand*(VAR operand: Operand);
  2263. BEGIN
  2264. operand.type := none;
  2265. operand.index := none;
  2266. operand.register:= none;
  2267. operand.segment:= none;
  2268. operand.sizeInBytes := none;
  2269. operand.scale := 1;
  2270. operand.displacement := 0;
  2271. operand.val := 0;
  2272. operand.pc := none;
  2273. operand.symbol.name := "";
  2274. operand.symbol.fingerprint := 0;
  2275. operand.selector := none;
  2276. operand.offset := 0;
  2277. END InitOperand;
  2278. PROCEDURE InitRegister* (VAR operand: Operand; register: Register);
  2279. BEGIN
  2280. InitOperand(operand);
  2281. operand.type := InstructionSet.RegisterType(register);
  2282. operand.register :=register;
  2283. CASE operand.type OF
  2284. reg8,reg16,reg32,reg64,segReg,CRn,DRn,sti,xmm,mmx: (* ok *)
  2285. |InstructionSet.st0: operand.type := InstructionSet.sti;
  2286. ELSE
  2287. HALT(100);
  2288. END;
  2289. operand.sizeInBytes := InstructionSet.registers[register].sizeInBytes
  2290. END InitRegister;
  2291. PROCEDURE NewRegister*(register: Register): Operand;
  2292. VAR operand: Operand;
  2293. BEGIN InitRegister(operand,register); RETURN operand
  2294. END NewRegister;
  2295. PROCEDURE InitMem*(VAR operand: Operand; size: Size; reg: Register; displacement: LONGINT);
  2296. BEGIN
  2297. InitOperand(operand);
  2298. operand.type := mem;
  2299. operand.sizeInBytes := size;
  2300. operand.register:= reg;
  2301. operand.displacement := displacement;
  2302. operand.scale := 1;
  2303. END InitMem;
  2304. PROCEDURE SetIndexScale*(VAR operand: Operand; index: Register; scale: LONGINT);
  2305. BEGIN
  2306. operand.index := index;
  2307. operand.scale := scale
  2308. END SetIndexScale;
  2309. PROCEDURE NewMem*(size: Size; reg: Register; displacement: LONGINT): Operand;
  2310. VAR operand: Operand;
  2311. BEGIN
  2312. InitMem(operand,size,reg,displacement); RETURN operand
  2313. END NewMem;
  2314. PROCEDURE InitMem8* (VAR operand: Operand; reg: Register; displacement: LONGINT);
  2315. BEGIN InitMem (operand, bits8, reg, displacement);
  2316. END InitMem8;
  2317. PROCEDURE NewMem8* (reg: Register; displacement: LONGINT): Operand;
  2318. VAR operand: Operand;
  2319. BEGIN InitMem8 (operand,reg, displacement); RETURN operand
  2320. END NewMem8;
  2321. PROCEDURE InitMem16* (VAR operand: Operand; reg: Register; displacement: LONGINT);
  2322. BEGIN InitMem (operand,bits16, reg, displacement);
  2323. END InitMem16;
  2324. PROCEDURE NewMem16* (reg: Register; displacement: LONGINT): Operand;
  2325. VAR operand: Operand;
  2326. BEGIN InitMem16 (operand,reg, displacement); RETURN operand
  2327. END NewMem16;
  2328. PROCEDURE InitMem32* (VAR operand: Operand; reg: Register; displacement: LONGINT);
  2329. BEGIN InitMem (operand,bits32, reg, displacement);
  2330. END InitMem32;
  2331. PROCEDURE NewMem32* (reg: Register; displacement: LONGINT): Operand;
  2332. VAR operand: Operand;
  2333. BEGIN InitMem32 (operand,reg, displacement); RETURN operand
  2334. END NewMem32;
  2335. PROCEDURE InitMem64* (VAR operand: Operand; reg: Register; displacement: LONGINT);
  2336. BEGIN InitMem (operand,bits64, reg, displacement);
  2337. END InitMem64;
  2338. PROCEDURE NewMem64* (reg: Register; displacement: LONGINT): Operand;
  2339. VAR operand: Operand;
  2340. BEGIN InitMem64 (operand,reg, displacement); RETURN operand
  2341. END NewMem64;
  2342. PROCEDURE InitMem128* (VAR operand: Operand; reg: Register; displacement: LONGINT);
  2343. BEGIN InitMem (operand,bits128, reg, displacement);
  2344. END InitMem128;
  2345. PROCEDURE NewMem128* (reg: Register; displacement: LONGINT): Operand;
  2346. VAR operand: Operand;
  2347. BEGIN InitMem128 (operand,reg, displacement); RETURN operand
  2348. END NewMem128;
  2349. PROCEDURE SetSymbol*(VAR operand: Operand; symbol: Sections.SectionName; fingerprint: LONGINT; symbolOffset, displacement: LONGINT);
  2350. BEGIN
  2351. operand.symbol.name := symbol;
  2352. operand.symbol.fingerprint := fingerprint;
  2353. operand.symbolOffset := symbolOffset; operand.displacement := displacement;
  2354. END SetSymbol;
  2355. PROCEDURE InitImm* (VAR operand: Operand; size: SHORTINT; val: HUGEINT);
  2356. BEGIN InitOperand(operand); operand.type := imm; operand.sizeInBytes := size; operand.val := val;
  2357. END InitImm;
  2358. PROCEDURE InitImm8* (VAR operand: Operand; val: HUGEINT);
  2359. BEGIN InitImm (operand, bits8, val);
  2360. END InitImm8;
  2361. PROCEDURE NewImm8*(val: HUGEINT): Operand;
  2362. VAR operand: Operand;
  2363. BEGIN InitImm8(operand,val); RETURN operand
  2364. END NewImm8;
  2365. PROCEDURE InitImm16* (VAR operand: Operand; val: HUGEINT);
  2366. BEGIN InitImm (operand, bits16, val);
  2367. END InitImm16;
  2368. PROCEDURE NewImm16*(val: HUGEINT): Operand;
  2369. VAR operand:Operand;
  2370. BEGIN InitImm16(operand,val); RETURN operand
  2371. END NewImm16;
  2372. PROCEDURE InitImm32* (VAR operand: Operand; val: HUGEINT);
  2373. BEGIN InitImm (operand, bits32, val);
  2374. END InitImm32;
  2375. PROCEDURE NewImm32*(val: HUGEINT): Operand;
  2376. VAR operand: Operand;
  2377. BEGIN InitImm32(operand,val); RETURN operand
  2378. END NewImm32;
  2379. PROCEDURE InitImm64* (VAR operand: Operand; val: HUGEINT);
  2380. BEGIN InitImm (operand, bits64, val);
  2381. END InitImm64;
  2382. PROCEDURE NewImm64*(val: HUGEINT): Operand;
  2383. VAR operand: Operand;
  2384. BEGIN InitImm64(operand,val); RETURN operand
  2385. END NewImm64;
  2386. PROCEDURE InitOffset* (VAR operand: Operand; size: SHORTINT; val: HUGEINT);
  2387. BEGIN InitOperand(operand); operand.type := ioffset; operand.sizeInBytes := size; operand.val := val;
  2388. END InitOffset;
  2389. PROCEDURE InitOffset8* (VAR operand: Operand; val: HUGEINT);
  2390. BEGIN InitOffset (operand, bits8, val);
  2391. END InitOffset8;
  2392. PROCEDURE NewOffset8*(val: HUGEINT): Operand;
  2393. VAR operand: Operand;
  2394. BEGIN InitOffset8(operand,val); RETURN operand
  2395. END NewOffset8;
  2396. PROCEDURE InitOffset16* (VAR operand: Operand; val: HUGEINT);
  2397. BEGIN InitOffset (operand, bits16, val);
  2398. END InitOffset16;
  2399. PROCEDURE NewOffset16*(val: HUGEINT): Operand;
  2400. VAR operand: Operand;
  2401. BEGIN InitOffset16(operand,val); RETURN operand
  2402. END NewOffset16;
  2403. PROCEDURE InitOffset32* (VAR operand: Operand; val: HUGEINT);
  2404. BEGIN InitOffset (operand, bits32, val);
  2405. END InitOffset32;
  2406. PROCEDURE NewOffset32*(val: HUGEINT): Operand;
  2407. VAR operand: Operand;
  2408. BEGIN InitOffset32(operand,val); RETURN operand
  2409. END NewOffset32;
  2410. PROCEDURE InitOffset64* (VAR operand: Operand; val: HUGEINT);
  2411. BEGIN InitOffset (operand, bits64, val);
  2412. END InitOffset64;
  2413. PROCEDURE NewOffset64*(val: HUGEINT): Operand;
  2414. VAR operand: Operand;
  2415. BEGIN InitOffset64(operand,val); RETURN operand
  2416. END NewOffset64;
  2417. PROCEDURE InitPntr1616* (VAR operand: Operand; s, o: LONGINT);
  2418. BEGIN InitOperand(operand); operand.type := pntr1616; operand.selector := s; operand.offset := o;
  2419. END InitPntr1616;
  2420. PROCEDURE InitPntr1632* (VAR operand: Operand; s, o: LONGINT);
  2421. BEGIN InitOperand(operand); operand.type := pntr1632; operand.selector := s; operand.offset := o;
  2422. END InitPntr1632;
  2423. PROCEDURE SetSize*(VAR operand: Operand;sizeInBytes: Size);
  2424. BEGIN operand.sizeInBytes := sizeInBytes
  2425. END SetSize;
  2426. PROCEDURE SameOperand*(CONST left,right: Operand): BOOLEAN;
  2427. BEGIN
  2428. IF (left.type # right.type) OR (left.sizeInBytes # right.sizeInBytes) OR (left.symbol # right.symbol) THEN RETURN FALSE END;
  2429. CASE left.type OF
  2430. reg8,reg16,reg32,reg64,segReg,CRn,DRn,sti,xmm,mmx: RETURN left.register = right.register
  2431. | imm,ioffset: RETURN (left.val = right.val) & ((left.symbol.name="") OR (left.displacement = right.displacement))
  2432. | mem:RETURN (left.register = right.register) & (left.displacement = right.displacement) & (left.index = right.index) & (left.scale = right.scale)
  2433. | pntr1616,pntr1632: RETURN (left.selector=right.selector) & (left.offset=right.offset)
  2434. END;
  2435. RETURN FALSE
  2436. END SameOperand;
  2437. PROCEDURE Test*(context: Commands.Context);
  2438. VAR assembly: Emitter;
  2439. (*errorHandler: ErrorHandler; *)
  2440. op1,op2,op3: Operand;
  2441. diagnostics: Diagnostics.StreamDiagnostics;
  2442. code: Code;
  2443. pooledName: Basic.SegmentedName;
  2444. PROCEDURE Op(CONST name: ARRAY OF CHAR): LONGINT;
  2445. BEGIN
  2446. RETURN InstructionSet.FindMnemonic(name)
  2447. END Op;
  2448. BEGIN
  2449. InitOperand(op1); InitOperand(op2); InitOperand(op3);
  2450. NEW(diagnostics,context.error);
  2451. Basic.ToSegmentedName("test", pooledName);
  2452. NEW(code,Sections.CodeSection,8,0,pooledName,TRUE,TRUE);
  2453. NEW(assembly,diagnostics);
  2454. assembly.SetCode(code);
  2455. InitRegister(op1,InstructionSet.regEAX);
  2456. InitImm32(op2,10);
  2457. assembly.Emit2(Op("MOV"),op1,op2);
  2458. context.out.Update;
  2459. code.Dump(context.out);
  2460. END Test;
  2461. BEGIN
  2462. IF Trace THEN
  2463. NEW(kernelWriter,KernelLog.Send,1000);
  2464. END;
  2465. END FoxAMD64Assembler.
  2466. OCAMD64Assembler.Test ~