FoxARMAssembler.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. MODULE FoxARMAssembler; (** AUTHOR ""; PURPOSE ""; *)
  2. IMPORT InstructionSet := FoxARMInstructionSet, FoxAssembler, (*D := Debugging,*) Scanner := FoxScanner, Diagnostics, Strings;
  3. CONST Trace = FoxAssembler.Trace;
  4. TYPE
  5. Assembler* = OBJECT(FoxAssembler.Assembler)
  6. VAR
  7. PROCEDURE & Init2*(diagnostics: Diagnostics.Diagnostics);
  8. BEGIN Init(diagnostics)
  9. END Init2;
  10. (** parse a register name **)
  11. PROCEDURE GetRegister*(VAR registerNumber: LONGINT): BOOLEAN;
  12. VAR
  13. result: BOOLEAN;
  14. BEGIN
  15. registerNumber := InstructionSet.None;
  16. result := FALSE;
  17. IF symbol.token = Scanner.Identifier THEN
  18. registerNumber := InstructionSet.RegisterNumberFromName(symbol.identifierString);
  19. IF registerNumber # InstructionSet.None THEN
  20. result := TRUE;
  21. NextSymbol
  22. END
  23. END;
  24. RETURN result
  25. END GetRegister;
  26. PROCEDURE GetRegisterList(VAR registerList: SET): BOOLEAN;
  27. VAR num: LONGINT;
  28. BEGIN
  29. registerList := {};
  30. IF symbol.token = Scanner.LeftBrace THEN
  31. REPEAT
  32. NextSymbol;
  33. IF GetRegister(num) THEN
  34. IF (num > 16) THEN
  35. Error(errorPosition, "invalid register in list (not yet implemented)")
  36. END;
  37. INCL(registerList, num);
  38. END;
  39. UNTIL symbol.token # Scanner.Comma;
  40. IF symbol.token # Scanner.RightBrace THEN
  41. Error(errorPosition, "'}' expected.")
  42. ELSE
  43. NextSymbol;
  44. RETURN TRUE
  45. END;
  46. END;
  47. RETURN FALSE;
  48. END GetRegisterList;
  49. (** parse a special register name, along with fields **)
  50. PROCEDURE GetSpecialRegisterWithFields(VAR registerNumber: LONGINT; VAR fields: SET): BOOLEAN;
  51. VAR
  52. result: BOOLEAN;
  53. i: LONGINT;
  54. strings: Strings.StringArray;
  55. BEGIN
  56. result := FALSE;
  57. registerNumber := InstructionSet.None;
  58. fields := {};
  59. IF symbol.token = Scanner.Identifier THEN
  60. strings := Strings.Split(symbol.identifierString, '_'); (* split the identifier at the underscore symbol *)
  61. IF LEN(strings) = 2 THEN
  62. IF (strings[0]^ = "CPSR") OR (strings[0]^ = "SPSR") THEN
  63. IF strings[0]^ = "CPSR" THEN registerNumber := InstructionSet.CPSR
  64. ELSE registerNumber := InstructionSet.SPSR
  65. END;
  66. IF strings[1]^ # "" THEN
  67. FOR i := 0 TO LEN(strings[1]) - 1 DO
  68. CASE strings[1][i] OF
  69. | 'f': INCL(fields, InstructionSet.fieldF)
  70. | 's': INCL(fields, InstructionSet.fieldS)
  71. | 'x': INCL(fields, InstructionSet.fieldX)
  72. | 'c': INCL(fields, InstructionSet.fieldC)
  73. ELSE
  74. END
  75. END;
  76. result := TRUE;
  77. NextSymbol
  78. END
  79. END
  80. END
  81. END;
  82. RETURN result
  83. END GetSpecialRegisterWithFields;
  84. (** parse a shift mode name **)
  85. PROCEDURE GetShiftMode*(VAR shiftModeNumber: LONGINT): BOOLEAN;
  86. VAR
  87. result: BOOLEAN;
  88. BEGIN
  89. shiftModeNumber := InstructionSet.None;
  90. result := FALSE;
  91. IF symbol.token = Scanner.Identifier THEN
  92. shiftModeNumber := InstructionSet.ShiftModeNumberFromName(symbol.identifierString);
  93. IF shiftModeNumber # InstructionSet.None THEN
  94. result := TRUE;
  95. NextSymbol
  96. END
  97. END;
  98. RETURN result
  99. END GetShiftMode;
  100. (** parse a coprocessor name **)
  101. PROCEDURE GetCoprocessor*(VAR coprocessorNumber: LONGINT): BOOLEAN;
  102. VAR
  103. result: BOOLEAN;
  104. BEGIN
  105. coprocessorNumber := InstructionSet.None;
  106. result := FALSE;
  107. IF symbol.token = Scanner.Identifier THEN
  108. coprocessorNumber := InstructionSet.CoprocessorNumberFromName(symbol.identifierString);
  109. IF coprocessorNumber # InstructionSet.None THEN
  110. result := TRUE;
  111. NextSymbol
  112. END
  113. END;
  114. RETURN result
  115. END GetCoprocessor;
  116. (* parse coprocessor opcode *)
  117. PROCEDURE GetCoprocessorOpcode*(VAR coprocessorOpcode: LONGINT): BOOLEAN;
  118. VAR
  119. result: BOOLEAN;
  120. BEGIN
  121. IF (symbol.token = Scanner.Number) & (symbol.numberType = Scanner.Integer) & (symbol.integer >= 0) & (symbol.integer <= 7) THEN
  122. coprocessorOpcode := symbol.integer;
  123. result := TRUE;
  124. NextSymbol
  125. ELSE
  126. coprocessorOpcode := InstructionSet.None;
  127. result := FALSE
  128. END;
  129. RETURN result
  130. END GetCoprocessorOpcode;
  131. (** parse any expression that evaluates to a constant value **)
  132. PROCEDURE GetPlainValue*(VAR value: LONGINT): BOOLEAN;
  133. VAR
  134. assemblerResult: FoxAssembler.Result;
  135. result: BOOLEAN;
  136. BEGIN
  137. IF Expression(assemblerResult, FALSE) & ((assemblerResult.type = FoxAssembler.ConstantInteger) OR (assemblerResult.type = FoxAssembler.Offset)) THEN
  138. value := assemblerResult.value;
  139. result := TRUE
  140. ELSE
  141. value := 0;
  142. result := FALSE
  143. END;
  144. RETURN result
  145. END GetPlainValue;
  146. (** parse an ARM immediate value
  147. i.e., the '#'-sign followed by any expression that evaluates to a constant value
  148. **)
  149. PROCEDURE GetImmediateValue*(VAR immediateValue: LONGINT): BOOLEAN;
  150. BEGIN RETURN ThisToken(Scanner.Unequal) & GetPlainValue(immediateValue)
  151. END GetImmediateValue;
  152. PROCEDURE Instruction*(CONST mnemonic: ARRAY OF CHAR);
  153. VAR
  154. instruction: InstructionSet.Instruction;
  155. operands: ARRAY InstructionSet.MaxOperands OF InstructionSet.Operand;
  156. position, opCode, condition, i, operandNumber: LONGINT;
  157. flags: SET;
  158. newOperandExpected: BOOLEAN;
  159. result: FoxAssembler.Result;
  160. (** parse an operand
  161. - note that a subsequent comma is consumed as well
  162. - 'newOperandExpected' indicates if any more operands are expected
  163. **)
  164. PROCEDURE ParseOperand;
  165. VAR
  166. operand: InstructionSet.Operand;
  167. indexingMode, fields: SET;
  168. registerNumber, offsetRegisterNumber, shiftModeNumber, shiftRegisterNumber, shiftImmediateValue, position, offsetImmediateValue, value: LONGINT;
  169. isImmediateOffset, bracketIsOpen: BOOLEAN;
  170. registerList: SET;
  171. BEGIN
  172. newOperandExpected := FALSE;
  173. position := errorPosition;
  174. IF operandNumber >= InstructionSet.MaxOperands THEN
  175. Error(position, "too many operands")
  176. ELSE
  177. InstructionSet.InitOperand(operand);
  178. IF ThisToken(Scanner.LeftBracket) THEN
  179. bracketIsOpen := TRUE;
  180. (* memory operand *)
  181. indexingMode := {};
  182. IF GetRegister(registerNumber) THEN
  183. IF ThisToken(Scanner.RightBracket) THEN
  184. bracketIsOpen := FALSE;
  185. (* post indexing *)
  186. INCL(indexingMode, InstructionSet.PostIndexed)
  187. END;
  188. IF ExpectToken(Scanner.Comma) THEN
  189. IF GetImmediateValue(offsetImmediateValue) THEN
  190. (* immediate offset memory operand *)
  191. isImmediateOffset := TRUE;
  192. IF ABS(offsetImmediateValue) < InstructionSet.Bits12 THEN
  193. IF offsetImmediateValue >= 0 THEN
  194. INCL(indexingMode, InstructionSet.Increment)
  195. ELSE
  196. INCL(indexingMode, InstructionSet.Decrement)
  197. END;
  198. offsetImmediateValue := ABS(offsetImmediateValue)
  199. ELSE
  200. Error(errorPosition, "immediate offset is out of range")
  201. END
  202. ELSE
  203. (* register offset memory operand *)
  204. isImmediateOffset := FALSE;
  205. (* parse sign *)
  206. IF ThisToken(Scanner.Plus) THEN
  207. INCL(indexingMode, InstructionSet.Increment)
  208. ELSIF ThisToken(Scanner.Minus) THEN
  209. INCL(indexingMode, InstructionSet.Decrement)
  210. ELSE
  211. Error(errorPosition, "plus or minus sign expected")
  212. END;
  213. IF ~error THEN
  214. (* parse offset register *)
  215. IF GetRegister(offsetRegisterNumber) THEN
  216. shiftModeNumber := InstructionSet.None;
  217. shiftImmediateValue := 0;
  218. (* parse optional shift *)
  219. IF GetShiftMode(shiftModeNumber) THEN
  220. IF GetImmediateValue(shiftImmediateValue) THEN
  221. IF shiftImmediateValue >= InstructionSet.Bits5 THEN
  222. Error(errorPosition, "immediate shift amount is out of range")
  223. END
  224. ELSE
  225. Error(errorPosition, "immediate shift amount expected")
  226. END
  227. END
  228. ELSE
  229. Error(errorPosition, "register expected")
  230. END
  231. END
  232. END
  233. END;
  234. IF bracketIsOpen THEN
  235. IF ExpectToken(Scanner.RightBracket) THEN
  236. IF ThisToken(Scanner.ExclamationMark) THEN
  237. (* preindexing *)
  238. INCL(indexingMode, InstructionSet.PreIndexed)
  239. END
  240. END
  241. END
  242. ELSE
  243. Error(errorPosition, "register expected")
  244. END;
  245. IF ~error THEN
  246. IF isImmediateOffset THEN
  247. InstructionSet.InitImmediateOffsetMemory(operand, registerNumber, offsetImmediateValue, indexingMode)
  248. ELSE
  249. InstructionSet.InitRegisterOffsetMemory(operand, registerNumber, offsetRegisterNumber, shiftModeNumber, shiftImmediateValue, indexingMode);
  250. END
  251. END
  252. ELSIF GetSpecialRegisterWithFields(registerNumber, fields) THEN
  253. ASSERT((registerNumber = InstructionSet.CPSR) OR (registerNumber = InstructionSet.SPSR));
  254. InstructionSet.InitRegisterWithFields(operand, registerNumber, fields);
  255. ELSIF GetRegister(registerNumber) THEN
  256. (* register *)
  257. shiftModeNumber := InstructionSet.None; (* defaults *)
  258. shiftRegisterNumber := InstructionSet.None;
  259. shiftImmediateValue := 0;
  260. IF ThisToken(Scanner.ExclamationMark) THEN
  261. INCL(flags, InstructionSet.flagBaseRegisterUpdate);
  262. END;
  263. IF ThisToken(Scanner.Comma) THEN
  264. (* parse shift mode *)
  265. IF GetShiftMode(shiftModeNumber) THEN
  266. IF shiftModeNumber # InstructionSet.shiftRRX THEN (* RRX shift amount is always 1 *)
  267. (* parse shift amount *)
  268. IF ~GetRegister(shiftRegisterNumber) & ~GetImmediateValue(shiftImmediateValue) THEN
  269. Error(position, "invalid shift amount")
  270. END
  271. END
  272. ELSE
  273. newOperandExpected := TRUE
  274. END
  275. END;
  276. IF ~error THEN
  277. InstructionSet.InitRegister(operand, registerNumber, shiftModeNumber, shiftRegisterNumber, shiftImmediateValue)
  278. END
  279. ELSIF GetRegisterList(registerList) THEN
  280. InstructionSet.InitRegisterList(operand, InstructionSet.R0, registerList);
  281. IF ThisToken(Scanner.Arrow) THEN
  282. INCL(flags, InstructionSet.flagUserMode);
  283. END;
  284. ELSIF GetCoprocessor(value) THEN
  285. (* coprocessor name *)
  286. InstructionSet.InitCoprocessor(operand, value)
  287. ELSIF GetCoprocessorOpcode(value) THEN (* integer constant in the range 0 .. 7 *)
  288. (* coprocessor opcode *)
  289. InstructionSet.InitOpcode(operand, value)
  290. ELSIF GetImmediateValue(value) THEN (* expression that evaluates to constant value starting with '#' *)
  291. (* ARM immediate value *)
  292. InstructionSet.InitImmediate(operand, value)
  293. ELSIF GetNonConstant(errorPosition,symbol.identifierString, result) THEN
  294. InstructionSet.InitImmediate(operand,result.value);
  295. IF result.fixup # NIL THEN
  296. InstructionSet.AddFixup(operand,result.fixup);
  297. END;
  298. NextSymbol;
  299. ELSIF GetPlainValue(value) THEN (* expression that evaluates to constant value *)
  300. (* resolved label name *)
  301. InstructionSet.InitImmediate(operand, value)
  302. ELSE
  303. Error(position, "invalid operand")
  304. END;
  305. IF ThisToken(Scanner.ExclamationMark) THEN
  306. INCL(flags, InstructionSet.flagBaseRegisterUpdate);
  307. END;
  308. IF ~newOperandExpected THEN newOperandExpected := ThisToken(Scanner.Comma) END; (* a comma means that there is one more operand *)
  309. operands[operandNumber] := operand;
  310. END
  311. END ParseOperand;
  312. BEGIN
  313. (*
  314. IF Trace THEN D.String("Instruction: "); D.String(mnemonic); D.String(" "); D.Ln END;
  315. *)
  316. position := errorPosition;
  317. IF InstructionSet.FindMnemonic(mnemonic, opCode, condition, flags) THEN
  318. (*IF Trace THEN
  319. D.String(" opCode="); D.Int(opCode, 0); D.Ln;
  320. D.String(" condition="); D.Int(condition, 0); D.Ln;
  321. D.String(" flags="); D.Set(flags); D.Ln;
  322. END;*)
  323. FOR i := 0 TO InstructionSet.MaxOperands - 1 DO
  324. InstructionSet.InitOperand(operands[i])
  325. END;
  326. operandNumber := 0;
  327. IF symbol.token # Scanner.Ln THEN
  328. REPEAT
  329. ParseOperand;
  330. INC(operandNumber);
  331. UNTIL error OR ~newOperandExpected;
  332. END;
  333. IF ~error THEN
  334. IF ~InstructionSet.MakeInstruction(instruction, opCode, condition, flags, operands) THEN
  335. ErrorSS(position, "wrong instruction format: ", mnemonic);
  336. ELSE
  337. IF pass < FoxAssembler.MaxPasses THEN
  338. (* not last pass: only increment the current PC by 4 units *)
  339. section.resolved.SetPC(section.resolved.pc + 4)
  340. ELSE
  341. (* last pass: emit the instruction *)
  342. IF ~InstructionSet.EmitInstruction(instruction, section.resolved) THEN
  343. ErrorSS(position, "wrong instruction format (encoding failed): ", mnemonic);
  344. END;
  345. END
  346. END
  347. END
  348. ELSE
  349. ErrorSS(position, "unknown mnemonic: ", mnemonic)
  350. END
  351. END Instruction;
  352. END Assembler;
  353. END FoxARMAssembler.
  354. SystemTools.Free FoxARMAssembler FoxARMInstructionSet ~
  355. Alwazs