1
0

asm.inc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  1. // Copyright (C) 2012 Zeex
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a
  4. // copy of this software and associated documentation files (the "Software"),
  5. // to deal in the Software without restriction, including without limitation
  6. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7. // and/or sell copies of the Software, and to permit persons to whom the
  8. // Software is furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  14. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19. // DEALINGS IN THE SOFTWARE.
  20. #if defined ASM_INC
  21. #endinput
  22. #endif
  23. #define ASM_INC
  24. #include <core>
  25. #include "amx_base"
  26. #include "amx_header"
  27. #include "amx_memory"
  28. #include "asm_macros"
  29. #include "dynamic_call"
  30. #include "opcode"
  31. #if !defined ASM_MAX_LABELS
  32. #define ASM_MAX_LABELS (8)
  33. #endif
  34. enum AsmError {
  35. ASM_ERROR_NONE,
  36. ASM_ERROR_OPCODE,
  37. ASM_ERROR_OPERAND,
  38. ASM_ERROR_SPACE,
  39. ASM_ERROR_LABEL_OVERFLOW,
  40. ASM_ERROR_LABEL_DUPLICATE,
  41. };
  42. enum AsmContext {
  43. AsmContext_buffer,
  44. AsmContext_buffer_size,
  45. AsmContext_buffer_offset,
  46. AsmContext_error,
  47. AsmContext_error_handler, // ErrorHandler(ctx[AsmContext])
  48. AsmContext_label_names[ASM_MAX_LABELS],
  49. // All labels in PAWN should be 4-byte-aligned (1 cell in 32-bit). This
  50. // means the bottom two bits are always `0b00`. We re-use this data to
  51. // store two bits of information - is this label resolved (i.e. do we know
  52. // the true address yet), and is this use of the label relative or absolute?
  53. //
  54. // If the label is NOT resolved, the current value is the start pointer of a
  55. // linked list of jump-ahead uses of the label (relative to DAT), i.e. jumps
  56. // waiting to know the label's address when it is eventually defined. If
  57. // the label IS resolved, it is just the absolute address of the label
  58. // (relative to COD) so that any new uses can be resolved instantly. The
  59. // lowest bit determines which.
  60. //
  61. // If a jump to an unknown label is emitted, the value is the next item in
  62. // the linked list (potentially NULL), and the bottom bit is instead used to
  63. // determine which jump type this is - relative (1) or absolute (0).
  64. AsmContext_labels[ASM_MAX_LABELS],
  65. };
  66. stock const ASM_ARGUMENTS_OFFSET = 0x0C;
  67. stock const ASM_LOCALS_OFFSET = -0x04;
  68. stock const ASM_CALLER_FRAME_OFFSET = 0x00;
  69. stock const ASM_RETURN_ADDR_OFFSET = 0x04;
  70. stock const ASM_CTRL_COD = 0;
  71. stock const ASM_CTRL_DAT = 1;
  72. stock const ASM_CTRL_HEA = 2;
  73. stock const ASM_CTRL_STP = 3;
  74. stock const ASM_CTRL_STK = 4;
  75. stock const ASM_CTRL_FRM = 5;
  76. stock const ASM_CTRL_CIP = 6;
  77. stock const ASM_CTRL_JIT = 7;
  78. stock const ASM_CTRL_JMP = 8;
  79. static gPreviousWriteOffset = cellmin;
  80. // Internal functions:
  81. static stock AsmError:AsmRaiseError(ctx[AsmContext], AsmError:error) {
  82. if (error != ASM_ERROR_NONE) {
  83. AsmSetError(ctx, error);
  84. if (ctx[AsmContext_error_handler] != 0) {
  85. CallFunction(ctx[AsmContext_error_handler], ref(ctx));
  86. }
  87. }
  88. return error;
  89. }
  90. static stock AsmError:AsmEmitCell(ctx[AsmContext], value) {
  91. if (ctx[AsmContext_buffer_offset] >= ctx[AsmContext_buffer_size]) {
  92. return AsmRaiseError(ctx, ASM_ERROR_SPACE);
  93. }
  94. WriteAmxMemory(ctx[AsmContext_buffer] + ctx[AsmContext_buffer_offset], value);
  95. ctx[AsmContext_buffer_offset] += 4;
  96. return ASM_ERROR_NONE;
  97. }
  98. // Label functions:
  99. #define AsmIsLabelResolved(%2,%0) (%2[AsmContext_labels][(%0)] & 1)
  100. #define AsmIsJumpRelative(%0) ((%0) & 1)
  101. #define AsmSetJumpRelative(%2,%0,%1) (%2[AsmContext_labels][(%0)] & (%1))
  102. #define AsmGetLabel(%2,%0) (%2[AsmContext_labels][(%0)] & ~1)
  103. #define AsmSetLabel(%2,%0,%1) (%2[AsmContext_labels][(%0)] = (%1) | 1)
  104. static stock AsmHashLabel(const label[]) {
  105. // Return the Bernstein hash of this label. This is NOT a cryptographically
  106. // secure hash, but is sufficient for our uses.
  107. new hash = -1;
  108. new i = -1;
  109. new ch;
  110. while ((ch = label[++i])) {
  111. hash = hash * 33 + ch;
  112. }
  113. return hash;
  114. }
  115. static stock AsmFindLabelIndex(ctx[AsmContext], hash) {
  116. for (new i = 0; i != ASM_MAX_LABELS; ++i) {
  117. if (ctx[AsmContext_label_names][i] == hash) {
  118. return i;
  119. }
  120. }
  121. return -1;
  122. }
  123. stock AsmError:AsmEmitLabelStringize(ctx[AsmContext], const label[]) {
  124. // Everything works on the hashes - it saves storing the strings.
  125. new hash = AsmHashLabel(label);
  126. // See if this label already exists.
  127. new idx = AsmFindLabelIndex(ctx, hash);
  128. // Get the true address. Use an offset of -8 because
  129. // `AsmGetJumpAddressFromOffset` assumes the jump is from the start of the
  130. // next instruction (8 bytes later), while we want it from right here, so
  131. // shift back accordingly.
  132. new datAddr = ctx[AsmContext_buffer] + ctx[AsmContext_buffer_offset];
  133. new codAddr = AsmGetJumpAddressFromOffset(ctx, -8);
  134. if (idx == -1) {
  135. // Doesn't exist. Get a free slot.
  136. idx = AsmFindLabelIndex(ctx, 0);
  137. if (idx == -1) {
  138. return AsmRaiseError(ctx, ASM_ERROR_LABEL_OVERFLOW);
  139. }
  140. ctx[AsmContext_label_names][idx] = hash;
  141. }
  142. if (AsmIsLabelResolved(ctx, idx)) {
  143. // Check that no other labels have the same name.
  144. return AsmRaiseError(ctx, ASM_ERROR_LABEL_DUPLICATE);
  145. } else {
  146. // Loop over all the pending items in the linked list.
  147. new cur = AsmGetLabel(ctx, idx);
  148. while (cur) {
  149. new next = ReadAmxMemory(cur);
  150. if (AsmIsJumpRelative(next)) {
  151. WriteAmxMemory(cur, datAddr - cur - 4);
  152. } else {
  153. WriteAmxMemory(cur, codAddr);
  154. }
  155. cur = next & ~1;
  156. }
  157. }
  158. // Store the label's absolute address, along with a flag to mark that it is
  159. // resolved.
  160. AsmSetLabel(ctx, idx, codAddr);
  161. return ASM_ERROR_NONE;
  162. }
  163. stock AsmError:AsmEmitJumpStringize(ctx[AsmContext], const label[], bool:relative) {
  164. new hash = AsmHashLabel(label);
  165. new idx = AsmFindLabelIndex(ctx, hash);
  166. new datAddr = ctx[AsmContext_buffer] + ctx[AsmContext_buffer_offset];
  167. new AsmError:error = ASM_ERROR_NONE;
  168. if (idx == -1) {
  169. // Doesn't exist. Get a free slot.
  170. idx = AsmFindLabelIndex(ctx, 0);
  171. if (idx == -1) {
  172. return AsmRaiseError(ctx, ASM_ERROR_LABEL_OVERFLOW);
  173. }
  174. ctx[AsmContext_label_names][idx] = hash;
  175. }
  176. if (AsmIsLabelResolved(ctx, idx)) {
  177. // The label was in the past, jump to that.
  178. new cur = AsmGetLabel(ctx, idx);
  179. if (relative) {
  180. error = AsmEmitCell(ctx, cur - datAddr - 4);
  181. } else {
  182. error = AsmEmitCell(ctx, cur);
  183. }
  184. } else {
  185. // The label is not yet known, store this use in the list.
  186. new cur = AsmGetLabel(ctx, idx);
  187. if (relative) {
  188. error = AsmEmitCell(ctx, cur | 1);
  189. } else {
  190. error = AsmEmitCell(ctx, cur);
  191. }
  192. if (error == ASM_ERROR_NONE) {
  193. // Store to the list only if the output was successful.
  194. ctx[AsmContext_labels][idx] = datAddr;
  195. }
  196. }
  197. return error;
  198. }
  199. // Core functions:
  200. stock AsmError:AsmEmitOpcode(ctx[AsmContext], Opcode:opcode) {
  201. if (opcode <= OP_NONE || _:opcode >= NUM_OPCODES) {
  202. return AsmRaiseError(ctx, ASM_ERROR_OPCODE);
  203. }
  204. return AsmEmitCell(ctx, _:RelocateOpcode(opcode));
  205. }
  206. stock AsmError:AsmEmitOperand(ctx[AsmContext], value) {
  207. return AsmEmitCell(ctx, value);
  208. }
  209. stock AsmError:AsmEmitInstruction(ctx[AsmContext], Opcode:opcode, ...) {
  210. // if there's an error while writing then backtracking is useful
  211. gPreviousWriteOffset = ctx[AsmContext_buffer_offset];
  212. new AsmError:error = ASM_ERROR_NONE;
  213. error = AsmEmitOpcode(ctx, opcode);
  214. if (error != ASM_ERROR_NONE) {
  215. return error;
  216. }
  217. static const STATIC_ARGS = 2;
  218. new num_opers = numargs() - STATIC_ARGS;
  219. for (new i = 0; i < num_opers; i++) {
  220. error = AsmEmitOperand(ctx, getarg(STATIC_ARGS + i));
  221. if (error != ASM_ERROR_NONE) {
  222. return error;
  223. }
  224. }
  225. return ASM_ERROR_NONE;
  226. }
  227. stock AsmGetJumpAddressFromOffset(ctx[AsmContext], offset) {
  228. new amxhdr[AMX_HDR];
  229. GetAmxHeader(amxhdr);
  230. new next_offset = 2 * 4; // offset to the next instruction
  231. new base = GetAmxBaseAddress() + amxhdr[AMX_HDR_DAT];
  232. new dest = ctx[AsmContext_buffer] + ctx[AsmContext_buffer_offset] + next_offset + offset;
  233. return base + dest;
  234. }
  235. stock AsmError:AsmEmitJumpInstruction(ctx[AsmContext], Opcode:opcode, offset) {
  236. return AsmEmitInstruction(ctx, opcode, AsmGetJumpAddressFromOffset(ctx, offset));
  237. }
  238. stock AsmError:AsmEmitJumpLabelInstruction(ctx[AsmContext], Opcode:opcode, const label[], bool:relative = false) {
  239. // if there's an error while writing then backtracking is useful
  240. gPreviousWriteOffset = ctx[AsmContext_buffer_offset];
  241. new AsmError:error = ASM_ERROR_NONE;
  242. error = AsmEmitOpcode(ctx, opcode);
  243. if (error != ASM_ERROR_NONE) {
  244. return error;
  245. }
  246. return AsmEmitJumpStringize(ctx, label, relative);
  247. }
  248. stock AsmError:AsmInitPtr(ctx[AsmContext], buffer, size) {
  249. ctx[AsmContext_buffer] = buffer;
  250. ctx[AsmContext_buffer_size] = size;
  251. ctx[AsmContext_buffer_offset] = 0;
  252. ctx[AsmContext_error_handler] = 0;
  253. for (new i = 0; i != ASM_MAX_LABELS; ++i) {
  254. ctx[AsmContext_label_names][i] = 0;
  255. ctx[AsmContext_labels][i] = 0;
  256. }
  257. return ASM_ERROR_NONE;
  258. }
  259. stock AsmGetPreviousWriteOffset() {
  260. return gPreviousWriteOffset;
  261. }
  262. stock AsmGetBufferSize(ctx[AsmContext]) {
  263. return ctx[AsmContext_buffer_size] - ctx[AsmContext_buffer_offset];
  264. }
  265. stock AsmError:AsmInit(ctx[AsmContext], buffer[], size = sizeof(buffer)) {
  266. AsmInitPtr(ctx, ref(buffer), size * 4);
  267. }
  268. stock AsmGetCode(const ctx[AsmContext]) {
  269. new amxhdr[AMX_HDR];
  270. GetAmxHeader(amxhdr);
  271. return ctx[AsmContext_buffer] + amxhdr[AMX_HDR_DAT] - amxhdr[AMX_HDR_COD];
  272. }
  273. stock AsmGetCodeSize(const ctx[AsmContext]) {
  274. return ctx[AsmContext_buffer_offset];
  275. }
  276. stock AsmError:AsmGetError(ctx[AsmContext]) {
  277. return AsmError:ctx[AsmContext_error];
  278. }
  279. stock AsmSetError(ctx[AsmContext], AsmError:error) {
  280. ctx[AsmContext_error] = _:error;
  281. }
  282. stock AsmClearError(ctx[AsmContext]) {
  283. AsmSetError(ctx, ASM_ERROR_NONE);
  284. }
  285. stock AsmGetErrorHandler(const ctx[AsmContext]) {
  286. return ctx[AsmContext_error_handler];
  287. }
  288. stock AsmError:AsmSetErrorHandler(ctx[AsmContext], error_handler) {
  289. ctx[AsmContext_error_handler] = error_handler;
  290. return ASM_ERROR_NONE;
  291. }
  292. stock AsmError:AsmSetErrorHandlerName(ctx[AsmContext], error_handler[]) {
  293. ctx[AsmContext_error_handler] = GetPublicAddressFromName(error_handler);
  294. return ASM_ERROR_NONE;
  295. }
  296. stock AsmEmitPadding(ctx[AsmContext], Opcode:op = OP_NOP) {
  297. // Must not have parameters, to make the padding valid.
  298. if (!IsOpcodeValid(op) || GetOpcodeInstructionParameters(op)) {
  299. op = OP_NOP;
  300. }
  301. // Resolve it for speed.
  302. op = RelocateOpcode(op);
  303. new
  304. cur = ctx[AsmContext_buffer] + ctx[AsmContext_buffer_offset],
  305. end = ctx[AsmContext_buffer] + ctx[AsmContext_buffer_size];
  306. while (cur < end) {
  307. WriteAmxMemory(cur, _:op);
  308. cur += 4;
  309. }
  310. ctx[AsmContext_buffer_offset] = ctx[AsmContext_buffer_size];
  311. }
  312. // Low level functions:
  313. stock AsmError:AsmEmitAdd(ctx[AsmContext]) {
  314. return AsmEmitInstruction(ctx, OP_ADD);
  315. }
  316. stock AsmError:AsmEmitAddC(ctx[AsmContext], value) {
  317. return AsmEmitInstruction(ctx, OP_ADD_C, value);
  318. }
  319. stock AsmError:AsmEmitAddrAlt(ctx[AsmContext], offset) {
  320. return AsmEmitInstruction(ctx, OP_ADDR_ALT, offset);
  321. }
  322. stock AsmError:AsmEmitAddrPri(ctx[AsmContext], offset) {
  323. return AsmEmitInstruction(ctx, OP_ADDR_PRI, offset);
  324. }
  325. stock AsmError:AsmEmitAlignAlt(ctx[AsmContext], number) {
  326. return AsmEmitInstruction(ctx, OP_ALIGN_ALT, number);
  327. }
  328. stock AsmError:AsmEmitAlignPri(ctx[AsmContext], number) {
  329. return AsmEmitInstruction(ctx, OP_ALIGN_PRI, number);
  330. }
  331. stock AsmError:AsmEmitAnd(ctx[AsmContext]) {
  332. return AsmEmitInstruction(ctx, OP_AND);
  333. }
  334. stock AsmError:AsmEmitBounds(ctx[AsmContext], bound) {
  335. return AsmEmitInstruction(ctx, OP_BOUNDS, bound);
  336. }
  337. stock AsmError:AsmEmitBreak(ctx[AsmContext]) {
  338. return AsmEmitInstruction(ctx, OP_BREAK);
  339. }
  340. stock AsmError:AsmEmitCall(ctx[AsmContext], address) {
  341. return AsmEmitInstruction(ctx, OP_CALL, address);
  342. }
  343. stock AsmError:AsmEmitCallAbs(ctx[AsmContext], address) {
  344. new hdr[AMX_HDR];
  345. GetAmxHeader(hdr);
  346. return AsmEmitInstruction(ctx, OP_CALL, address + GetAmxBaseAddress() + hdr[AMX_HDR_COD]);
  347. }
  348. stock AsmError:AsmEmitCallLabelStringize(ctx[AsmContext], const label[]) {
  349. return AsmEmitJumpLabelInstruction(ctx, OP_CALL, label);
  350. }
  351. stock AsmError:AsmEmitCmps(ctx[AsmContext], nbytes) {
  352. return AsmEmitInstruction(ctx, OP_CMPS, nbytes);
  353. }
  354. stock AsmError:AsmEmitConstAlt(ctx[AsmContext], value) {
  355. return AsmEmitInstruction(ctx, OP_CONST_ALT, value);
  356. }
  357. stock AsmError:AsmEmitConstPri(ctx[AsmContext], value) {
  358. return AsmEmitInstruction(ctx, OP_CONST_PRI, value);
  359. }
  360. stock AsmError:AsmEmitDec(ctx[AsmContext], address) {
  361. return AsmEmitInstruction(ctx, OP_DEC, address);
  362. }
  363. stock AsmError:AsmEmitDecAlt(ctx[AsmContext]) {
  364. return AsmEmitInstruction(ctx, OP_DEC_ALT);
  365. }
  366. stock AsmError:AsmEmitDecI(ctx[AsmContext]) {
  367. return AsmEmitInstruction(ctx, OP_DEC_I);
  368. }
  369. stock AsmError:AsmEmitDecPri(ctx[AsmContext]) {
  370. return AsmEmitInstruction(ctx, OP_DEC_PRI);
  371. }
  372. stock AsmError:AsmEmitDecS(ctx[AsmContext], offset) {
  373. return AsmEmitInstruction(ctx, OP_DEC_S, offset);
  374. }
  375. stock AsmError:AsmEmitEq(ctx[AsmContext]) {
  376. return AsmEmitInstruction(ctx, OP_EQ);
  377. }
  378. stock AsmError:AsmEmitEqCAlt(ctx[AsmContext], value) {
  379. return AsmEmitInstruction(ctx, OP_EQ_C_ALT, value);
  380. }
  381. stock AsmError:AsmEmitEqCPri(ctx[AsmContext], value) {
  382. return AsmEmitInstruction(ctx, OP_EQ_C_PRI, value);
  383. }
  384. stock AsmError:AsmEmitFill(ctx[AsmContext], nbytes) {
  385. return AsmEmitInstruction(ctx, OP_FILL, nbytes);
  386. }
  387. stock AsmError:AsmEmitGeq(ctx[AsmContext]) {
  388. return AsmEmitInstruction(ctx, OP_GEQ);
  389. }
  390. stock AsmError:AsmEmitGrtr(ctx[AsmContext]) {
  391. return AsmEmitInstruction(ctx, OP_GRTR);
  392. }
  393. stock AsmError:AsmEmitHalt(ctx[AsmContext], code) {
  394. return AsmEmitInstruction(ctx, OP_HALT, code);
  395. }
  396. stock AsmError:AsmEmitHeap(ctx[AsmContext], nbytes) {
  397. return AsmEmitInstruction(ctx, OP_HEAP, nbytes);
  398. }
  399. stock AsmError:AsmEmitIdxaddr(ctx[AsmContext]) {
  400. return AsmEmitInstruction(ctx, OP_IDXADDR);
  401. }
  402. stock AsmError:AsmEmitIdxaddrB(ctx[AsmContext], shift) {
  403. return AsmEmitInstruction(ctx, OP_IDXADDR_B, shift);
  404. }
  405. stock AsmError:AsmEmitInc(ctx[AsmContext], address) {
  406. return AsmEmitInstruction(ctx, OP_INC, address);
  407. }
  408. stock AsmError:AsmEmitIncAlt(ctx[AsmContext]) {
  409. return AsmEmitInstruction(ctx, OP_INC_ALT);
  410. }
  411. stock AsmError:AsmEmitIncI(ctx[AsmContext]) {
  412. return AsmEmitInstruction(ctx, OP_INC_I);
  413. }
  414. stock AsmError:AsmEmitIncPri(ctx[AsmContext]) {
  415. return AsmEmitInstruction(ctx, OP_INC_PRI);
  416. }
  417. stock AsmError:AsmEmitIncS(ctx[AsmContext], offset) {
  418. return AsmEmitInstruction(ctx, OP_INC_S, offset);
  419. }
  420. stock AsmError:AsmEmitInvert(ctx[AsmContext]) {
  421. return AsmEmitInstruction(ctx, OP_INVERT);
  422. }
  423. stock AsmError:AsmEmitJeq(ctx[AsmContext], address) {
  424. return AsmEmitInstruction(ctx, OP_JEQ, address);
  425. }
  426. stock AsmError:AsmEmitJeqRel(ctx[AsmContext], offset) {
  427. return AsmEmitJumpInstruction(ctx, OP_JEQ, offset);
  428. }
  429. stock AsmError:AsmEmitJgeq(ctx[AsmContext], address) {
  430. return AsmEmitInstruction(ctx, OP_JGEQ, address);
  431. }
  432. stock AsmError:AsmEmitJgeqRel(ctx[AsmContext], offset) {
  433. return AsmEmitJumpInstruction(ctx, OP_JGEQ, offset);
  434. }
  435. stock AsmError:AsmEmitJgrtr(ctx[AsmContext], address) {
  436. return AsmEmitInstruction(ctx, OP_JGRTR, address);
  437. }
  438. stock AsmError:AsmEmitJgrtrRel(ctx[AsmContext], offset) {
  439. return AsmEmitJumpInstruction(ctx, OP_JGRTR, offset);
  440. }
  441. stock AsmError:AsmEmitJleq(ctx[AsmContext], address) {
  442. return AsmEmitInstruction(ctx, OP_JLEQ, address);
  443. }
  444. stock AsmError:AsmEmitJleqRel(ctx[AsmContext], offset) {
  445. return AsmEmitJumpInstruction(ctx, OP_JLEQ, offset);
  446. }
  447. stock AsmError:AsmEmitJless(ctx[AsmContext], address) {
  448. return AsmEmitInstruction(ctx, OP_JLESS, address);
  449. }
  450. stock AsmError:AsmEmitJlessRel(ctx[AsmContext], offset) {
  451. return AsmEmitJumpInstruction(ctx, OP_JLESS, offset);
  452. }
  453. stock AsmError:AsmEmitJneq(ctx[AsmContext], address) {
  454. return AsmEmitInstruction(ctx, OP_JNEQ, address);
  455. }
  456. stock AsmError:AsmEmitJneqRel(ctx[AsmContext], offset) {
  457. return AsmEmitJumpInstruction(ctx, OP_JNEQ, offset);
  458. }
  459. stock AsmError:AsmEmitJnz(ctx[AsmContext], address) {
  460. return AsmEmitInstruction(ctx, OP_JNZ, address);
  461. }
  462. stock AsmError:AsmEmitJnzRel(ctx[AsmContext], offset) {
  463. return AsmEmitJumpInstruction(ctx, OP_JNZ, offset);
  464. }
  465. stock AsmError:AsmEmitJsgeq(ctx[AsmContext], address) {
  466. return AsmEmitInstruction(ctx, OP_JSGEQ, address);
  467. }
  468. stock AsmError:AsmEmitJsgeqRel(ctx[AsmContext], offset) {
  469. return AsmEmitJumpInstruction(ctx, OP_JSGEQ, offset);
  470. }
  471. stock AsmError:AsmEmitJsgrtr(ctx[AsmContext], address) {
  472. return AsmEmitInstruction(ctx, OP_JSGRTR, address);
  473. }
  474. stock AsmError:AsmEmitJsgrtrRel(ctx[AsmContext], offset) {
  475. return AsmEmitJumpInstruction(ctx, OP_JSGRTR, offset);
  476. }
  477. stock AsmError:AsmEmitJsleq(ctx[AsmContext], address) {
  478. return AsmEmitInstruction(ctx, OP_JSLEQ, address);
  479. }
  480. stock AsmError:AsmEmitJsleqRel(ctx[AsmContext], offset) {
  481. return AsmEmitJumpInstruction(ctx, OP_JSLEQ, offset);
  482. }
  483. stock AsmError:AsmEmitJsless(ctx[AsmContext], address) {
  484. return AsmEmitInstruction(ctx, OP_JSLESS, address);
  485. }
  486. stock AsmError:AsmEmitJslessRel(ctx[AsmContext], offset) {
  487. return AsmEmitJumpInstruction(ctx, OP_JSLESS, offset);
  488. }
  489. stock AsmError:AsmEmitJump(ctx[AsmContext], address) {
  490. return AsmEmitInstruction(ctx, OP_JUMP, address);
  491. }
  492. stock AsmError:AsmEmitJumpRel(ctx[AsmContext], offset) {
  493. return AsmEmitJumpInstruction(ctx, OP_JUMP, offset);
  494. }
  495. stock AsmError:AsmEmitJzer(ctx[AsmContext], address) {
  496. return AsmEmitInstruction(ctx, OP_JZER, address);
  497. }
  498. stock AsmError:AsmEmitJzerRel(ctx[AsmContext], offset) {
  499. return AsmEmitJumpInstruction(ctx, OP_JZER, offset);
  500. }
  501. stock AsmError:AsmEmitJrel(ctx[AsmContext], offset) {
  502. return AsmEmitJumpInstruction(ctx, OP_JREL, offset);
  503. }
  504. stock AsmError:AsmEmitJeqLabelStringize(ctx[AsmContext], const label[]) {
  505. return AsmEmitJumpLabelInstruction(ctx, OP_JEQ, label);
  506. }
  507. stock AsmError:AsmEmitJgeqLabelStringize(ctx[AsmContext], const label[]) {
  508. return AsmEmitJumpLabelInstruction(ctx, OP_JGEQ, label);
  509. }
  510. stock AsmError:AsmEmitJgrtrLabelStringize(ctx[AsmContext], const label[]) {
  511. return AsmEmitJumpLabelInstruction(ctx, OP_JGRTR, label);
  512. }
  513. stock AsmError:AsmEmitJleqLabelStringize(ctx[AsmContext], const label[]) {
  514. return AsmEmitJumpLabelInstruction(ctx, OP_JLEQ, label);
  515. }
  516. stock AsmError:AsmEmitJlessLabelStringize(ctx[AsmContext], const label[]) {
  517. return AsmEmitJumpLabelInstruction(ctx, OP_JLESS, label);
  518. }
  519. stock AsmError:AsmEmitJneqLabelStringize(ctx[AsmContext], const label[]) {
  520. return AsmEmitJumpLabelInstruction(ctx, OP_JNEQ, label);
  521. }
  522. stock AsmError:AsmEmitJnzLabelStringize(ctx[AsmContext], const label[]) {
  523. return AsmEmitJumpLabelInstruction(ctx, OP_JNZ, label);
  524. }
  525. stock AsmError:AsmEmitJsgeqLabelStringize(ctx[AsmContext], const label[]) {
  526. return AsmEmitJumpLabelInstruction(ctx, OP_JSGEQ, label);
  527. }
  528. stock AsmError:AsmEmitJsgrtrLabelStringize(ctx[AsmContext], const label[]) {
  529. return AsmEmitJumpLabelInstruction(ctx, OP_JSGRTR, label);
  530. }
  531. stock AsmError:AsmEmitJsleqLabelStringize(ctx[AsmContext], const label[]) {
  532. return AsmEmitJumpLabelInstruction(ctx, OP_JSLEQ, label);
  533. }
  534. stock AsmError:AsmEmitJslessLabelStringize(ctx[AsmContext], const label[]) {
  535. return AsmEmitJumpLabelInstruction(ctx, OP_JSLESS, label);
  536. }
  537. stock AsmError:AsmEmitJumpLabelStringize(ctx[AsmContext], const label[]) {
  538. return AsmEmitJumpLabelInstruction(ctx, OP_JUMP, label);
  539. }
  540. stock AsmError:AsmEmitJzerLabelStringize(ctx[AsmContext], const label[]) {
  541. return AsmEmitJumpLabelInstruction(ctx, OP_JZER, label);
  542. }
  543. stock AsmError:AsmEmitJrelLabelStringize(ctx[AsmContext], const label[]) {
  544. return AsmEmitJumpLabelInstruction(ctx, OP_JREL, label, true);
  545. }
  546. stock AsmError:AsmEmitLctrl(ctx[AsmContext], index) {
  547. assert(index >= 0 && index <= 8);
  548. return AsmEmitInstruction(ctx, OP_LCTRL, index);
  549. }
  550. stock AsmError:AsmEmitLeq(ctx[AsmContext]) {
  551. return AsmEmitInstruction(ctx, OP_LEQ);
  552. }
  553. stock AsmError:AsmEmitLess(ctx[AsmContext]) {
  554. return AsmEmitInstruction(ctx, OP_LESS);
  555. }
  556. stock AsmError:AsmEmitLidx(ctx[AsmContext]) {
  557. return AsmEmitInstruction(ctx, OP_LIDX);
  558. }
  559. stock AsmError:AsmEmitLidxB(ctx[AsmContext], shift) {
  560. return AsmEmitInstruction(ctx, OP_LIDX_B, shift);
  561. }
  562. stock AsmError:AsmEmitLoadAlt(ctx[AsmContext], address) {
  563. return AsmEmitInstruction(ctx, OP_LOAD_ALT, address);
  564. }
  565. stock AsmError:AsmEmitLoadPri(ctx[AsmContext], address) {
  566. return AsmEmitInstruction(ctx, OP_LOAD_PRI, address);
  567. }
  568. stock AsmError:AsmEmitLoad(ctx[AsmContext], address) {
  569. return AsmEmitInstruction(ctx, OP_LOAD_ALT, address);
  570. }
  571. stock AsmError:AsmEmitLoadI(ctx[AsmContext]) {
  572. return AsmEmitInstruction(ctx, OP_LOAD_I);
  573. }
  574. stock AsmError:AsmEmitLoadSAlt(ctx[AsmContext], offset) {
  575. return AsmEmitInstruction(ctx, OP_LOAD_S_ALT, offset);
  576. }
  577. stock AsmError:AsmEmitLoadSPri(ctx[AsmContext], offset) {
  578. return AsmEmitInstruction(ctx, OP_LOAD_S_PRI, offset);
  579. }
  580. stock AsmError:AsmEmitLodbI(ctx[AsmContext], nbytes) {
  581. assert(nbytes == 1 || nbytes == 2 || nbytes == 4);
  582. return AsmEmitInstruction(ctx, OP_LODB_I, nbytes);
  583. }
  584. stock AsmError:AsmEmitLrefAlt(ctx[AsmContext], address) {
  585. return AsmEmitInstruction(ctx, OP_LREF_ALT, address);
  586. }
  587. stock AsmError:AsmEmitLrefPri(ctx[AsmContext], address) {
  588. return AsmEmitInstruction(ctx, OP_LREF_PRI, address);
  589. }
  590. stock AsmError:AsmEmitLrefSAlt(ctx[AsmContext], offset) {
  591. return AsmEmitInstruction(ctx, OP_LREF_S_ALT, offset);
  592. }
  593. stock AsmError:AsmEmitLrefSPri(ctx[AsmContext], offset) {
  594. return AsmEmitInstruction(ctx, OP_LREF_S_PRI, offset);
  595. }
  596. stock AsmError:AsmEmitMoveAlt(ctx[AsmContext]) {
  597. return AsmEmitInstruction(ctx, OP_MOVE_ALT);
  598. }
  599. stock AsmError:AsmEmitMovePri(ctx[AsmContext]) {
  600. return AsmEmitInstruction(ctx, OP_MOVE_PRI);
  601. }
  602. stock AsmError:AsmEmitMovs(ctx[AsmContext], nbytes) {
  603. return AsmEmitInstruction(ctx, OP_MOVS, nbytes);
  604. }
  605. stock AsmError:AsmEmitNeg(ctx[AsmContext]) {
  606. return AsmEmitInstruction(ctx, OP_NEG);
  607. }
  608. stock AsmError:AsmEmitNeq(ctx[AsmContext]) {
  609. return AsmEmitInstruction(ctx, OP_NEQ);
  610. }
  611. stock AsmError:AsmEmitNop(ctx[AsmContext]) {
  612. return AsmEmitInstruction(ctx, OP_NOP);
  613. }
  614. stock AsmError:AsmEmitNot(ctx[AsmContext]) {
  615. return AsmEmitInstruction(ctx, OP_NOT);
  616. }
  617. stock AsmError:AsmEmitOr(ctx[AsmContext]) {
  618. return AsmEmitInstruction(ctx, OP_OR);
  619. }
  620. stock AsmError:AsmEmitPopAlt(ctx[AsmContext]) {
  621. return AsmEmitInstruction(ctx, OP_POP_ALT);
  622. }
  623. stock AsmError:AsmEmitPopPri(ctx[AsmContext]) {
  624. return AsmEmitInstruction(ctx, OP_POP_PRI);
  625. }
  626. stock AsmError:AsmEmitProc(ctx[AsmContext]) {
  627. return AsmEmitInstruction(ctx, OP_PROC);
  628. }
  629. stock AsmError:AsmEmitPushAdr(ctx[AsmContext], offset) {
  630. return AsmEmitInstruction(ctx, OP_PUSH_ADR, offset);
  631. }
  632. stock AsmError:AsmEmitPushAlt(ctx[AsmContext]) {
  633. return AsmEmitInstruction(ctx, OP_PUSH_ALT);
  634. }
  635. stock AsmError:AsmEmitPushC(ctx[AsmContext], value) {
  636. return AsmEmitInstruction(ctx, OP_PUSH_C, value);
  637. }
  638. stock AsmError:AsmEmitPushPri(ctx[AsmContext]) {
  639. return AsmEmitInstruction(ctx, OP_PUSH_PRI);
  640. }
  641. stock AsmError:AsmEmitPush(ctx[AsmContext], address) {
  642. return AsmEmitInstruction(ctx, OP_PUSH, address);
  643. }
  644. stock AsmError:AsmEmitPushS(ctx[AsmContext], offset) {
  645. return AsmEmitInstruction(ctx, OP_PUSH_S, offset);
  646. }
  647. stock AsmError:AsmEmitRet(ctx[AsmContext]) {
  648. return AsmEmitInstruction(ctx, OP_RET);
  649. }
  650. stock AsmError:AsmEmitRetn(ctx[AsmContext]) {
  651. return AsmEmitInstruction(ctx, OP_RETN);
  652. }
  653. stock AsmError:AsmEmitSctrl(ctx[AsmContext], index) {
  654. assert(index == 2 || 4 <= index <= 6 || index == 8);
  655. return AsmEmitInstruction(ctx, OP_SCTRL, index);
  656. }
  657. stock AsmError:AsmEmitSdiv(ctx[AsmContext]) {
  658. return AsmEmitInstruction(ctx, OP_SDIV);
  659. }
  660. stock AsmError:AsmEmitSdivAlt(ctx[AsmContext]) {
  661. return AsmEmitInstruction(ctx, OP_SDIV_ALT);
  662. }
  663. stock AsmError:AsmEmitSgeq(ctx[AsmContext]) {
  664. return AsmEmitInstruction(ctx, OP_SGEQ);
  665. }
  666. stock AsmError:AsmEmitSgrtr(ctx[AsmContext]) {
  667. return AsmEmitInstruction(ctx, OP_SGRTR);
  668. }
  669. stock AsmError:AsmEmitShl(ctx[AsmContext]) {
  670. return AsmEmitInstruction(ctx, OP_SHL);
  671. }
  672. stock AsmError:AsmEmitShlCAlt(ctx[AsmContext], shift) {
  673. return AsmEmitInstruction(ctx, OP_SHL_C_ALT, shift);
  674. }
  675. stock AsmError:AsmEmitShlCPri(ctx[AsmContext], shift) {
  676. return AsmEmitInstruction(ctx, OP_SHL_C_PRI, shift);
  677. }
  678. stock AsmError:AsmEmitShrCAlt(ctx[AsmContext], shift) {
  679. return AsmEmitInstruction(ctx, OP_SHR_C_ALT, shift);
  680. }
  681. stock AsmError:AsmEmitShrCPri(ctx[AsmContext], shift) {
  682. return AsmEmitInstruction(ctx, OP_SHR_C_PRI, shift);
  683. }
  684. stock AsmError:AsmEmitShr(ctx[AsmContext]) {
  685. return AsmEmitInstruction(ctx, OP_SHR);
  686. }
  687. stock AsmError:AsmEmitSignAlt(ctx[AsmContext]) {
  688. return AsmEmitInstruction(ctx, OP_SIGN_ALT);
  689. }
  690. stock AsmError:AsmEmitSignPri(ctx[AsmContext]) {
  691. return AsmEmitInstruction(ctx, OP_SIGN_PRI);
  692. }
  693. stock AsmError:AsmEmitSleq(ctx[AsmContext]) {
  694. return AsmEmitInstruction(ctx, OP_SLEQ);
  695. }
  696. stock AsmError:AsmEmitSless(ctx[AsmContext]) {
  697. return AsmEmitInstruction(ctx, OP_SLESS);
  698. }
  699. stock AsmError:AsmEmitSmul(ctx[AsmContext]) {
  700. return AsmEmitInstruction(ctx, OP_SMUL);
  701. }
  702. stock AsmError:AsmEmitSmulC(ctx[AsmContext], value) {
  703. return AsmEmitInstruction(ctx, OP_SMUL_C, value);
  704. }
  705. stock AsmError:AsmEmitSshr(ctx[AsmContext]) {
  706. return AsmEmitInstruction(ctx, OP_SSHR);
  707. }
  708. stock AsmError:AsmEmitSrefAlt(ctx[AsmContext], address) {
  709. return AsmEmitInstruction(ctx, OP_SREF_ALT, address);
  710. }
  711. stock AsmError:AsmEmitSrefPri(ctx[AsmContext], address) {
  712. return AsmEmitInstruction(ctx, OP_SREF_PRI, address);
  713. }
  714. stock AsmError:AsmEmitSrefSAlt(ctx[AsmContext], offset) {
  715. return AsmEmitInstruction(ctx, OP_SREF_S_ALT, offset);
  716. }
  717. stock AsmError:AsmEmitSrefSPri(ctx[AsmContext], offset) {
  718. return AsmEmitInstruction(ctx, OP_SREF_S_PRI, offset);
  719. }
  720. stock AsmError:AsmEmitStack(ctx[AsmContext], nbytes) {
  721. return AsmEmitInstruction(ctx, OP_STACK, nbytes);
  722. }
  723. stock AsmError:AsmEmitStorAlt(ctx[AsmContext], address) {
  724. return AsmEmitInstruction(ctx, OP_STOR_ALT, address);
  725. }
  726. stock AsmError:AsmEmitStorPri(ctx[AsmContext], address) {
  727. return AsmEmitInstruction(ctx, OP_STOR_PRI, address);
  728. }
  729. stock AsmError:AsmEmitStorI(ctx[AsmContext]) {
  730. return AsmEmitInstruction(ctx, OP_STOR_I);
  731. }
  732. stock AsmError:AsmEmitStorSAlt(ctx[AsmContext], offset) {
  733. return AsmEmitInstruction(ctx, OP_STOR_S_ALT, offset);
  734. }
  735. stock AsmError:AsmEmitStorSPri(ctx[AsmContext], offset) {
  736. return AsmEmitInstruction(ctx, OP_STOR_S_PRI, offset);
  737. }
  738. stock AsmError:AsmEmitStrbI(ctx[AsmContext], nbytes) {
  739. assert(nbytes == 1 || nbytes == 2 || nbytes == 4);
  740. return AsmEmitInstruction(ctx, OP_STRB_I, nbytes);
  741. }
  742. stock AsmError:AsmEmitSub(ctx[AsmContext]) {
  743. return AsmEmitInstruction(ctx, OP_SUB);
  744. }
  745. stock AsmError:AsmEmitSubAlt(ctx[AsmContext]) {
  746. return AsmEmitInstruction(ctx, OP_SUB_ALT);
  747. }
  748. stock AsmError:AsmEmitSwapAlt(ctx[AsmContext]) {
  749. return AsmEmitInstruction(ctx, OP_SWAP_ALT);
  750. }
  751. stock AsmError:AsmEmitSwapPri(ctx[AsmContext]) {
  752. return AsmEmitInstruction(ctx, OP_SWAP_PRI);
  753. }
  754. stock AsmError:AsmEmitSysreqC(ctx[AsmContext], index) {
  755. return AsmEmitInstruction(ctx, OP_SYSREQ_C, index);
  756. }
  757. stock AsmError:AsmEmitSysreqD(ctx[AsmContext], address) {
  758. return AsmEmitInstruction(ctx, OP_SYSREQ_D, address);
  759. }
  760. stock AsmError:AsmEmitSysreqPri(ctx[AsmContext]) {
  761. return AsmEmitInstruction(ctx, OP_SYSREQ_PRI);
  762. }
  763. stock AsmError:AsmEmitUdiv(ctx[AsmContext]) {
  764. return AsmEmitInstruction(ctx, OP_UDIV);
  765. }
  766. stock AsmError:AsmEmitUdivAlt(ctx[AsmContext]) {
  767. return AsmEmitInstruction(ctx, OP_UDIV_ALT);
  768. }
  769. stock AsmError:AsmEmitUmul(ctx[AsmContext]) {
  770. return AsmEmitInstruction(ctx, OP_UMUL);
  771. }
  772. stock AsmError:AsmEmitXchg(ctx[AsmContext]) {
  773. return AsmEmitInstruction(ctx, OP_XCHG);
  774. }
  775. stock AsmError:AsmEmitXor(ctx[AsmContext]) {
  776. return AsmEmitInstruction(ctx, OP_XOR);
  777. }
  778. stock AsmError:AsmEmitZero(ctx[AsmContext], address) {
  779. return AsmEmitInstruction(ctx, OP_ZERO, address);
  780. }
  781. stock AsmError:AsmEmitZeroAlt(ctx[AsmContext]) {
  782. return AsmEmitInstruction(ctx, OP_ZERO_ALT);
  783. }
  784. stock AsmError:AsmEmitZeroPri(ctx[AsmContext]) {
  785. return AsmEmitInstruction(ctx, OP_ZERO_PRI);
  786. }
  787. stock AsmError:AsmEmitZeroS(ctx[AsmContext], offset) {
  788. return AsmEmitInstruction(ctx, OP_ZERO_S, offset);
  789. }
  790. // Higher level functions:
  791. stock AsmError:AsmEmitSysreq(ctx[AsmContext], const name[]) {
  792. return AsmEmitSysreqC(ctx, GetNativeIndexFromName(name));
  793. }
  794. stock AsmError:AsmEmitPopArgs(ctx[AsmContext], n) {
  795. return AsmEmitStack(ctx, (n + 1) * 4);
  796. }
  797. stock AsmError:AsmEmitPushArg(ctx[AsmContext], n) {
  798. return AsmEmitPushS(ctx, AsmGetArgOffset(n));
  799. }
  800. stock AsmError:AsmEmitPushNumArgs(ctx[AsmContext], n) {
  801. return AsmEmitPushC(ctx, 4 * n);
  802. }
  803. // Helpers:
  804. stock AsmGetArgOffset(n) {
  805. return ASM_ARGUMENTS_OFFSET + 4 * n;
  806. }