Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

787 lines
18 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Assembe Alpha machine implementation.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include "alpha_dis.h"
  10. #include "alpha_optable.h"
  11. #include "alpha_strings.h"
  12. #define OPSIZE 16
  13. BOOL TestCharacter (PSTR inString, PSTR *outString, CHAR ch);
  14. ULONG GetIntReg(PSTR, PSTR *);
  15. ULONG GetFltReg(PSTR, PSTR *);
  16. LONG
  17. GetValue (
  18. PSTR inString,
  19. PSTR *outString,
  20. BOOL fSigned,
  21. ULONG bitsize
  22. );
  23. PSTR SkipWhite(PSTR *);
  24. ULONG GetToken(PSTR, PSTR *, PSTR, ULONG);
  25. ULONG ParseIntMemory(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  26. ULONG ParseFltMemory(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  27. ULONG ParseMemSpec(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  28. ULONG ParseJump(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  29. ULONG ParseIntBranch(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  30. ULONG ParseFltBranch(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  31. ULONG ParseIntOp(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  32. ULONG ParsePal(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  33. ULONG ParseUnknown(PSTR, PSTR *, POPTBLENTRY, PULONG64);
  34. /*** assem - assemble instruction
  35. *
  36. * Purpose:
  37. * To assemble the instruction pointed by *poffset.
  38. *
  39. * Input:
  40. * pchInput - pointer to string to assemble
  41. *
  42. * Output:
  43. * *poffset - pointer to ADDR at which to assemble
  44. *
  45. * Exceptions:
  46. * error exit:
  47. * BADOPCODE - unknown or bad opcode
  48. * OPERAND - bad operand
  49. * ALIGNMENT - bad byte alignment in operand
  50. * DISPLACEMENT - overflow in displacement computation
  51. * BADREG - bad register name
  52. * EXTRACHARS - extra characters after legal instruction
  53. * MEMORY - write failure on assembled instruction
  54. *
  55. * Notes:
  56. * errors are handled by the calling program by outputting
  57. * the error string and reprompting the user for the same
  58. * instruction.
  59. *
  60. *************************************************************************/
  61. void
  62. AlphaMachineInfo::Assemble (PADDR poffset, PSTR pchInput)
  63. {
  64. CHAR szOpcode[OPSIZE];
  65. ULONG instruction;
  66. POPTBLENTRY pEntry;
  67. //
  68. // Using the mnemonic token, find the entry in the assembler's
  69. // table for the associated instruction.
  70. //
  71. if (GetToken(pchInput, &pchInput, szOpcode, OPSIZE) == 0)
  72. error(BADOPCODE);
  73. if ((pEntry = findStringEntry(szOpcode)) == (POPTBLENTRY) -1)
  74. error(BADOPCODE);
  75. if (pEntry->eType == INVALID_ETYPE) {
  76. error(BADOPCODE);
  77. }
  78. //
  79. // Use the instruction format specific parser to encode the
  80. // instruction plus its operands.
  81. //
  82. instruction = (*pEntry->parsFunc)
  83. (pchInput, &pchInput, pEntry, &(Flat(*poffset)));
  84. //
  85. // Store the instruction into the target memory location and
  86. // increment the instruction pointer.
  87. //
  88. if (SetMemString(poffset, &instruction, 4) != 4) {
  89. error(MEMORY);
  90. }
  91. Flat(*poffset) += sizeof(ULONG);
  92. Off(*poffset) += sizeof(ULONG);
  93. }
  94. BOOL
  95. TestCharacter (PSTR inString, PSTR *outString, CHAR ch)
  96. {
  97. inString = SkipWhite(&inString);
  98. if (ch == *inString) {
  99. *outString = inString+1;
  100. return TRUE;
  101. }
  102. else {
  103. *outString = inString;
  104. return FALSE;
  105. }
  106. }
  107. /*** GetIntReg - get integer register number
  108. *** GetFltReg - get floating register number
  109. *
  110. * Purpose:
  111. * From reading the input stream, return the register number.
  112. *
  113. * Input:
  114. * inString - pointer to input string
  115. *
  116. * Output:
  117. * *outString - pointer to character after register token in input stream
  118. *
  119. * Returns:
  120. * register number
  121. *
  122. * Exceptions:
  123. * error(BADREG) - bad register name
  124. *
  125. *************************************************************************/
  126. PCHAR regNums[] = {
  127. "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
  128. "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
  129. "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
  130. "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
  131. };
  132. PCHAR intRegNames[] = {
  133. g_R0, g_R1, g_R2, g_R3, g_R4, g_R5, g_R6, g_R7,
  134. g_R8, g_R9, g_R10, g_R11, g_R12, g_R13, g_R14, g_R15,
  135. g_R16, g_R17, g_R18, g_R19, g_R20, g_R21, g_R22, g_R23,
  136. g_R24, g_R25, g_R26, g_R27, g_R28, g_R29, g_R30, g_R31
  137. };
  138. PCHAR fltRegNames[] = {
  139. g_F0, g_F1, g_F2, g_F3, g_F4, g_F5, g_F6, g_F7,
  140. g_F8, g_F9, g_F10, g_F11, g_F12, g_F13, g_F14, g_F15,
  141. g_F16, g_F17, g_F18, g_F19, g_F20, g_F21, g_F22, g_F23,
  142. g_F24, g_F25, g_F26, g_F27, g_F28, g_F29, g_F30, g_F31
  143. };
  144. ULONG
  145. GetIntReg (PSTR inString, PSTR *outString)
  146. {
  147. CHAR szRegOp[5];
  148. ULONG index;
  149. if (!GetToken(inString, outString, szRegOp, sizeof(szRegOp)))
  150. error(BADREG);
  151. if (szRegOp[0] == '$') {
  152. //
  153. // use numbers
  154. //
  155. for (index = 0; index < 32; index++) {
  156. if (!strcmp(szRegOp, regNums[index]))
  157. return index;
  158. }
  159. } else {
  160. //
  161. // use names
  162. //
  163. for (index = 0; index < 32; index++) {
  164. if (!strcmp(szRegOp, intRegNames[index]))
  165. return index;
  166. }
  167. }
  168. error(BADREG);
  169. return 0;
  170. }
  171. ULONG
  172. GetFltReg (PSTR inString, PSTR *outString)
  173. {
  174. CHAR szRegOp[5];
  175. ULONG index;
  176. if (!GetToken(inString, outString, szRegOp, sizeof(szRegOp)))
  177. error(BADREG);
  178. if (szRegOp[0] == '$') {
  179. //
  180. // use numbers
  181. //
  182. for (index = 0; index < 32; index++) {
  183. if (!strcmp(szRegOp, regNums[index]))
  184. return index;
  185. }
  186. } else {
  187. //
  188. // use names
  189. //
  190. for (index = 0; index < 32; index++) {
  191. if (!strcmp(szRegOp, fltRegNames[index]))
  192. return index;
  193. }
  194. }
  195. error(BADREG);
  196. return 0;
  197. }
  198. /*** GetValue - get value from command line
  199. *
  200. * Purpose:
  201. * Use GetExpression to evaluate the next expression in the input
  202. * stream.
  203. *
  204. * Input:
  205. * inString - pointer to input stream
  206. * fSigned - TRUE if signed value
  207. * FALSE if unsigned value
  208. * bitsize - size of value allowed
  209. *
  210. * Output:
  211. * outString - character after the last character of the expression
  212. *
  213. * Returns:
  214. * value computed from input stream
  215. *
  216. * Exceptions:
  217. * error exit: OVERFLOW - value too large for bitsize
  218. *
  219. *************************************************************************/
  220. LONG
  221. GetValue (
  222. PSTR inString,
  223. PSTR *outString,
  224. BOOL fSigned,
  225. ULONG bitsize
  226. )
  227. {
  228. ULONGLONG value;
  229. inString = SkipWhite(&inString);
  230. g_CurCmd = inString;
  231. value = GetExpression();
  232. *outString = g_CurCmd;
  233. if ((value > (ULONG)(1L << bitsize) - 1) &&
  234. (!fSigned || (value < (ULONG)(-1L << (bitsize - 1))))) {
  235. error(OVERFLOW);
  236. }
  237. return (LONG)value;
  238. }
  239. /*** SkipWhite - skip white-space
  240. *
  241. * Purpose:
  242. * To advance g_CurCmd over any spaces or tabs.
  243. *
  244. * Input:
  245. * *g_CurCmd - present command line position
  246. *
  247. *************************************************************************/
  248. PSTR
  249. SkipWhite (PSTR * string)
  250. {
  251. while (**string == ' ' || **string == '\t')
  252. (*string)++;
  253. return(*string);
  254. }
  255. /*** GetToken - get token from command line
  256. *
  257. * Purpose:
  258. * Build a lower-case mapped token of maximum size maxcnt
  259. * at the string pointed by *psz. Token consist of the
  260. * set of characters a-z, A-Z, 0-9, $, and underscore.
  261. *
  262. * Input:
  263. * *inString - present command line position
  264. * maxcnt - maximum size of token allowed
  265. *
  266. * Output:
  267. * *outToken - token in lower case
  268. * *outString - pointer to first character beyond token in input
  269. *
  270. * Returns:
  271. * size of token if under maximum else 0
  272. *
  273. * Notes:
  274. * if string exceeds maximum size, the extra characters
  275. * are still processed, but ignored.
  276. *
  277. *************************************************************************/
  278. ULONG
  279. GetToken (PSTR inString, PSTR *outString, PSTR outToken, ULONG maxcnt)
  280. {
  281. CHAR ch;
  282. ULONG count = 0;
  283. inString = SkipWhite(&inString);
  284. while (count < maxcnt) {
  285. ch = (CHAR)tolower(*inString);
  286. if (!((ch >= '0' && ch <= '9') ||
  287. (ch >= 'a' && ch <= 'z') ||
  288. (ch == '$') ||
  289. (ch == '_') ||
  290. (ch == '#')))
  291. break;
  292. count++;
  293. *outToken++ = ch;
  294. inString++;
  295. }
  296. *outToken = '\0';
  297. *outString = inString;
  298. return (count >= maxcnt ? 0 : count);
  299. }
  300. /*** ParseIntMemory - parse integer memory instruction
  301. *
  302. * Purpose:
  303. * Given the users input, create the memory instruction.
  304. *
  305. * Input:
  306. * *inString - present input position
  307. * pEntry - pointer into the asmTable for this instr type
  308. *
  309. * Output:
  310. * *outstring - update input position
  311. *
  312. * Returns:
  313. * the instruction.
  314. *
  315. * Format:
  316. * op Ra, disp(Rb)
  317. *
  318. *************************************************************************/
  319. ULONG
  320. ParseIntMemory(
  321. PSTR inString,
  322. PSTR *outString,
  323. POPTBLENTRY pEntry,
  324. PULONG64 poffset
  325. )
  326. {
  327. ULONG instruction;
  328. ULONG Ra;
  329. ULONG Rb;
  330. ULONG disp;
  331. Ra = GetIntReg(inString, &inString);
  332. if (!TestCharacter(inString, &inString, ','))
  333. error(OPERAND);
  334. disp = GetValue(inString, &inString, TRUE, WIDTH_MEM_DISP);
  335. if (!TestCharacter(inString, &inString, '('))
  336. error(OPERAND);
  337. Rb = GetIntReg(inString, &inString);
  338. if (!TestCharacter(inString, &inString, ')'))
  339. error(OPERAND);
  340. if (!TestCharacter(inString, &inString, '\0'))
  341. error(EXTRACHARS);
  342. instruction = OPCODE(pEntry->opCode) +
  343. REG_A(Ra) +
  344. REG_B(Rb) +
  345. MEM_DISP(disp);
  346. return(instruction);
  347. }
  348. /*** ParseFltMemory - parse floating point memory instruction
  349. *
  350. * Purpose:
  351. * Given the users input, create the memory instruction.
  352. *
  353. * Input:
  354. * *inString - present input position
  355. * pEntry - pointer into the asmTable for this instr type
  356. *
  357. * Output:
  358. * *outstring - update input position
  359. *
  360. * Returns:
  361. * the instruction.
  362. *
  363. * Format:
  364. * op Fa, disp(Rb)
  365. *
  366. *************************************************************************/
  367. ULONG
  368. ParseFltMemory(PSTR inString,
  369. PSTR *outString,
  370. POPTBLENTRY pEntry,
  371. PULONG64 poffset)
  372. {
  373. ULONG instruction;
  374. ULONG Fa;
  375. ULONG Rb;
  376. ULONG disp;
  377. Fa = GetFltReg(inString, &inString);
  378. if (!TestCharacter(inString, &inString, ','))
  379. error(OPERAND);
  380. disp = (ULONG)GetValue(inString, &inString, TRUE, WIDTH_MEM_DISP);
  381. if (!TestCharacter(inString, &inString, '('))
  382. error(OPERAND);
  383. Rb = GetIntReg(inString, &inString);
  384. if (!TestCharacter(inString, &inString, ')'))
  385. error(OPERAND);
  386. if (!TestCharacter(inString, &inString, '\0'))
  387. error(EXTRACHARS);
  388. instruction = OPCODE(pEntry->opCode) +
  389. REG_A(Fa) +
  390. REG_B(Rb) +
  391. MEM_DISP(disp);
  392. return(instruction);
  393. }
  394. /*** ParseMemSpec - parse special memory instruction
  395. *
  396. * Purpose:
  397. * Given the users input, create the memory instruction.
  398. *
  399. * Input:
  400. * *inString - present input position
  401. * pEntry - pointer into the asmTable for this instr type
  402. *
  403. * Output:
  404. * *outstring - update input position
  405. *
  406. * Returns:
  407. * the instruction.
  408. *
  409. * Format:
  410. * op
  411. *
  412. *************************************************************************/
  413. ULONG ParseMemSpec(PSTR inString,
  414. PSTR *outString,
  415. POPTBLENTRY pEntry,
  416. PULONG64 poffset)
  417. {
  418. return(OPCODE(pEntry->opCode) +
  419. MEM_FUNC(pEntry->funcCode));
  420. }
  421. /*** ParseJump - parse jump instruction
  422. *
  423. * Purpose:
  424. * Given the users input, create the memory instruction.
  425. *
  426. * Input:
  427. * *inString - present input position
  428. * pEntry - pointer into the asmTable for this instr type
  429. *
  430. * Output:
  431. * *outstring - update input position
  432. *
  433. * Returns:
  434. * the instruction.
  435. *
  436. * Format:
  437. * op Ra,(Rb),hint
  438. * op Ra,(Rb) - not really - we just support it in ntsd
  439. *
  440. *************************************************************************/
  441. ULONG ParseJump(PSTR inString,
  442. PSTR *outString,
  443. POPTBLENTRY pEntry,
  444. PULONG64 poffset)
  445. {
  446. ULONG instruction;
  447. ULONG Ra;
  448. ULONG Rb;
  449. ULONG hint;
  450. Ra = GetIntReg(inString, &inString);
  451. if (!TestCharacter(inString, &inString, ','))
  452. error(OPERAND);
  453. if (!TestCharacter(inString, &inString, '('))
  454. error(OPERAND);
  455. Rb = GetIntReg(inString, &inString);
  456. if (!TestCharacter(inString, &inString, ')'))
  457. error(OPERAND);
  458. if (TestCharacter(inString, &inString, ',')) {
  459. //
  460. // User is giving us a hint
  461. //
  462. hint = GetValue(inString, &inString, TRUE, WIDTH_HINT);
  463. } else {
  464. hint = 0;
  465. }
  466. if (!TestCharacter(inString, &inString, '\0'))
  467. error(EXTRACHARS);
  468. instruction = OPCODE(pEntry->opCode) +
  469. JMP_FNC(pEntry->funcCode) +
  470. REG_A(Ra) +
  471. REG_B(Rb) +
  472. HINT(hint);
  473. return(instruction);
  474. }
  475. /*** ParseIntBranch - parse integer branch instruction
  476. *
  477. * Purpose:
  478. * Given the users input, create the memory instruction.
  479. *
  480. * Input:
  481. * *inString - present input position
  482. * pEntry - pointer into the asmTable for this instr type
  483. *
  484. * Output:
  485. * *outstring - update input position
  486. *
  487. * Returns:
  488. * the instruction.
  489. *
  490. * Format:
  491. * op Ra,disp
  492. *
  493. *************************************************************************/
  494. ULONG ParseIntBranch(PSTR inString,
  495. PSTR *outString,
  496. POPTBLENTRY pEntry,
  497. PULONG64 poffset)
  498. {
  499. ULONG instruction;
  500. ULONG Ra;
  501. LONG disp;
  502. Ra = GetIntReg(inString, &inString);
  503. if (!TestCharacter(inString, &inString, ','))
  504. error(OPERAND);
  505. //
  506. // the user gives an absolute address; we convert
  507. // that to a displacement, which is computed as a
  508. // difference off of (pc+1)
  509. // GetValue handles both numerics and symbolics
  510. //
  511. disp = GetValue(inString, &inString, TRUE, 32);
  512. // get the relative displacement from the updated pc
  513. disp = disp - (LONG)((*poffset)+4);
  514. // divide by four
  515. disp = disp >> 2;
  516. if (!TestCharacter(inString, &inString, '\0'))
  517. error(EXTRACHARS);
  518. instruction = OPCODE(pEntry->opCode) +
  519. REG_A(Ra) +
  520. BR_DISP(disp);
  521. return(instruction);
  522. }
  523. /*** ParseFltBranch - parse floating point branch instruction
  524. *
  525. * Purpose:
  526. * Given the users input, create the memory instruction.
  527. *
  528. * Input:
  529. * *inString - present input position
  530. * pEntry - pointer into the asmTable for this instr type
  531. *
  532. * Output:
  533. * *outstring - update input position
  534. *
  535. * Returns:
  536. * the instruction.
  537. *
  538. * Format:
  539. * op Fa,disp
  540. *
  541. *************************************************************************/
  542. ULONG ParseFltBranch(PSTR inString,
  543. PSTR *outString,
  544. POPTBLENTRY pEntry,
  545. PULONG64 poffset)
  546. {
  547. ULONG instruction;
  548. ULONG Ra;
  549. LONG disp;
  550. Ra = GetFltReg(inString, &inString);
  551. if (!TestCharacter(inString, &inString, ','))
  552. error(OPERAND);
  553. //
  554. // the user gives an absolute address; we convert
  555. // that to a displacement, which is computed as a
  556. // difference off of (pc+1)
  557. // GetValue handles both numerics and symbolics
  558. //
  559. disp = GetValue(inString, &inString, TRUE, 32);
  560. // get the relative displacement from the updated pc
  561. disp = disp - (LONG)((*poffset)+4);
  562. // divide by four
  563. disp = disp >> 2;
  564. if (!TestCharacter(inString, &inString, '\0'))
  565. error(EXTRACHARS);
  566. instruction = OPCODE(pEntry->opCode) +
  567. REG_A(Ra) +
  568. BR_DISP(disp);
  569. return(instruction);
  570. }
  571. /*** ParseIntOp - parse integer operation
  572. *
  573. * Purpose:
  574. * Given the users input, create the memory instruction.
  575. *
  576. * Input:
  577. * *inString - present input position
  578. * pEntry - pointer into the asmTable for this instr type
  579. *
  580. * Output:
  581. * *outstring - update input position
  582. *
  583. * Returns:
  584. * the instruction.
  585. *
  586. * Format:
  587. * op Ra, Rb, Rc
  588. * op Ra, #lit, Rc
  589. *
  590. *************************************************************************/
  591. ULONG ParseIntOp(PSTR inString,
  592. PSTR *outString,
  593. POPTBLENTRY pEntry,
  594. PULONG64 poffset)
  595. {
  596. ULONG instruction;
  597. ULONG Ra, Rb, Rc;
  598. ULONG lit;
  599. ULONG Format; // Whether there is a literal or 3rd reg
  600. instruction = OPCODE(pEntry->opCode) +
  601. OP_FNC(pEntry->funcCode);
  602. if (pEntry->opCode != SEXT_OP) {
  603. Ra = GetIntReg(inString, &inString);
  604. if (!TestCharacter(inString, &inString, ','))
  605. error(OPERAND);
  606. } else {
  607. Ra = 31;
  608. }
  609. if (TestCharacter(inString, &inString, '#')) {
  610. //
  611. // User is giving us a literal value
  612. lit = GetValue(inString, &inString, TRUE, WIDTH_LIT);
  613. Format = RBV_LITERAL_FORMAT;
  614. } else {
  615. //
  616. // using a third register value
  617. Rb = GetIntReg(inString, &inString);
  618. Format = RBV_REGISTER_FORMAT;
  619. }
  620. if (!TestCharacter(inString, &inString, ','))
  621. error(OPERAND);
  622. Rc = GetIntReg(inString, &inString);
  623. if (!TestCharacter(inString, &inString, '\0'))
  624. error(EXTRACHARS);
  625. instruction = instruction +
  626. REG_A(Ra) +
  627. RBV_TYPE(Format) +
  628. REG_C(Rc);
  629. if (Format == RBV_REGISTER_FORMAT) {
  630. instruction = instruction + REG_B(Rb);
  631. } else {
  632. instruction = instruction + LIT(lit);
  633. }
  634. return(instruction);
  635. }
  636. ULONG ParsePal(PSTR inString,
  637. PSTR *outString,
  638. POPTBLENTRY pEntry,
  639. PULONG64 poffset)
  640. {
  641. if (!TestCharacter(inString, &inString, '\0'))
  642. error(EXTRACHARS);
  643. return(OPCODE(pEntry->opCode) +
  644. PAL_FNC(pEntry->funcCode));
  645. }
  646. ULONG ParseUnknown(PSTR inString,
  647. PSTR *outString,
  648. POPTBLENTRY pEntry,
  649. PULONG64 poffset)
  650. {
  651. dprintf("Unable to assemble %s\n", inString);
  652. error(BADOPCODE);
  653. return(0);
  654. }