2
0

FoxARMAssembler.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. MODULE FoxARMAssembler; (** AUTHOR ""; PURPOSE ""; *)
  2. IMPORT InstructionSet := FoxARMInstructionSet, FoxAssembler, (*D := Debugging,*) Scanner := FoxScanner, Diagnostics, Strings, Basic := FoxBasic;
  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 token.symbol = Scanner.Identifier THEN
  18. registerNumber := InstructionSet.RegisterNumberFromName(token.identifierString);
  19. IF registerNumber # InstructionSet.None THEN
  20. result := TRUE;
  21. NextToken
  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 token.symbol = Scanner.LeftBrace THEN
  31. REPEAT
  32. NextToken;
  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 token.symbol # Scanner.Comma;
  40. IF token.symbol # Scanner.RightBrace THEN
  41. Error(errorPosition, "'}' expected.")
  42. ELSE
  43. NextToken;
  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 token.symbol = Scanner.Identifier THEN
  60. strings := Strings.Split(token.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. NextToken
  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 token.symbol = Scanner.Identifier THEN
  92. shiftModeNumber := InstructionSet.ShiftModeNumberFromName(token.identifierString);
  93. IF shiftModeNumber # InstructionSet.None THEN
  94. result := TRUE;
  95. NextToken
  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 token.symbol = Scanner.Identifier THEN
  108. coprocessorNumber := InstructionSet.CoprocessorNumberFromName(token.identifierString);
  109. IF coprocessorNumber # InstructionSet.None THEN
  110. result := TRUE;
  111. NextToken
  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 (token.symbol = Scanner.Number) & (token.numberType = Scanner.Integer) & (token.integer >= 0) & (token.integer <= 7) THEN
  122. coprocessorOpcode := token.integer;
  123. result := TRUE;
  124. NextToken
  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 := LONGINT(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 ThisSymbol(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: Basic.Position;
  157. opCode, condition, i, operandNumber: LONGINT;
  158. flags: SET;
  159. newOperandExpected: BOOLEAN;
  160. result: FoxAssembler.Result;
  161. (** parse an operand
  162. - note that a subsequent comma is consumed as well
  163. - 'newOperandExpected' indicates if any more operands are expected
  164. **)
  165. PROCEDURE ParseOperand;
  166. VAR
  167. operand: InstructionSet.Operand;
  168. indexingMode, fields: SET;
  169. registerNumber, offsetRegisterNumber, shiftModeNumber, shiftRegisterNumber, shiftImmediateValue, offsetImmediateValue, value: LONGINT;
  170. position: Basic.Position;
  171. isImmediateOffset, bracketIsOpen: BOOLEAN;
  172. registerList: SET;
  173. BEGIN
  174. newOperandExpected := FALSE;
  175. position := errorPosition;
  176. IF operandNumber >= InstructionSet.MaxOperands THEN
  177. Error(position, "too many operands")
  178. ELSE
  179. InstructionSet.InitOperand(operand);
  180. IF ThisSymbol(Scanner.LeftBracket) THEN
  181. bracketIsOpen := TRUE;
  182. (* memory operand *)
  183. indexingMode := {};
  184. IF GetRegister(registerNumber) THEN
  185. IF ThisSymbol(Scanner.RightBracket) THEN
  186. bracketIsOpen := FALSE;
  187. (* post indexing *)
  188. INCL(indexingMode, InstructionSet.PostIndexed)
  189. END;
  190. IF ExpectSymbol(Scanner.Comma) THEN
  191. IF GetImmediateValue(offsetImmediateValue) THEN
  192. (* immediate offset memory operand *)
  193. isImmediateOffset := TRUE;
  194. IF ABS(offsetImmediateValue) < InstructionSet.Bits12 THEN
  195. IF offsetImmediateValue >= 0 THEN
  196. INCL(indexingMode, InstructionSet.Increment)
  197. ELSE
  198. INCL(indexingMode, InstructionSet.Decrement)
  199. END;
  200. offsetImmediateValue := ABS(offsetImmediateValue)
  201. ELSE
  202. Error(errorPosition, "immediate offset is out of range")
  203. END
  204. ELSE
  205. (* register offset memory operand *)
  206. isImmediateOffset := FALSE;
  207. (* parse sign *)
  208. IF ThisSymbol(Scanner.Plus) THEN
  209. INCL(indexingMode, InstructionSet.Increment)
  210. ELSIF ThisSymbol(Scanner.Minus) THEN
  211. INCL(indexingMode, InstructionSet.Decrement)
  212. ELSE
  213. Error(errorPosition, "plus or minus sign expected")
  214. END;
  215. IF ~error THEN
  216. (* parse offset register *)
  217. IF GetRegister(offsetRegisterNumber) THEN
  218. shiftModeNumber := InstructionSet.None;
  219. shiftImmediateValue := 0;
  220. (* parse optional shift *)
  221. IF GetShiftMode(shiftModeNumber) THEN
  222. IF GetImmediateValue(shiftImmediateValue) THEN
  223. IF shiftImmediateValue >= InstructionSet.Bits5 THEN
  224. Error(errorPosition, "immediate shift amount is out of range")
  225. END
  226. ELSE
  227. Error(errorPosition, "immediate shift amount expected")
  228. END
  229. END
  230. ELSE
  231. Error(errorPosition, "register expected")
  232. END
  233. END
  234. END
  235. END;
  236. IF bracketIsOpen THEN
  237. IF ExpectSymbol(Scanner.RightBracket) THEN
  238. IF ThisSymbol(Scanner.ExclamationMark) THEN
  239. (* preindexing *)
  240. INCL(indexingMode, InstructionSet.PreIndexed)
  241. END
  242. END
  243. END
  244. ELSIF GetPlainValue(offsetImmediateValue) THEN
  245. (* pc label of the form [labelName], translated to [PC, #labelName - $ - 8] *)
  246. registerNumber := InstructionSet.PC;
  247. isImmediateOffset := TRUE;
  248. DEC(offsetImmediateValue, 8);
  249. DEC(offsetImmediateValue, code.pc);
  250. IF ABS(offsetImmediateValue) < InstructionSet.Bits12 THEN
  251. IF offsetImmediateValue >= 0 THEN
  252. INCL(indexingMode, InstructionSet.Increment)
  253. ELSE
  254. INCL(indexingMode, InstructionSet.Decrement)
  255. END;
  256. offsetImmediateValue := ABS(offsetImmediateValue)
  257. ELSE
  258. Error(errorPosition, "immediate offset is out of range")
  259. END;
  260. IF ExpectSymbol(Scanner.RightBracket) THEN
  261. END;
  262. ELSE
  263. Error(errorPosition, "register expected")
  264. END;
  265. IF ~error THEN
  266. IF isImmediateOffset THEN
  267. InstructionSet.InitImmediateOffsetMemory(operand, registerNumber, offsetImmediateValue, indexingMode)
  268. ELSE
  269. InstructionSet.InitRegisterOffsetMemory(operand, registerNumber, offsetRegisterNumber, shiftModeNumber, shiftImmediateValue, indexingMode);
  270. END
  271. END
  272. ELSIF GetSpecialRegisterWithFields(registerNumber, fields) THEN
  273. ASSERT((registerNumber = InstructionSet.CPSR) OR (registerNumber = InstructionSet.SPSR));
  274. InstructionSet.InitRegisterWithFields(operand, registerNumber, fields);
  275. ELSIF GetRegister(registerNumber) THEN
  276. (* register *)
  277. shiftModeNumber := InstructionSet.None; (* defaults *)
  278. shiftRegisterNumber := InstructionSet.None;
  279. shiftImmediateValue := 0;
  280. IF ThisSymbol(Scanner.ExclamationMark) THEN
  281. INCL(flags, InstructionSet.flagBaseRegisterUpdate);
  282. END;
  283. IF ThisSymbol(Scanner.Comma) THEN
  284. (* parse shift mode *)
  285. IF GetShiftMode(shiftModeNumber) THEN
  286. IF shiftModeNumber # InstructionSet.shiftRRX THEN (* RRX shift amount is always 1 *)
  287. (* parse shift amount *)
  288. IF ~GetRegister(shiftRegisterNumber) & ~GetImmediateValue(shiftImmediateValue) THEN
  289. Error(position, "invalid shift amount")
  290. END
  291. END
  292. ELSE
  293. newOperandExpected := TRUE
  294. END
  295. END;
  296. IF ~error THEN
  297. InstructionSet.InitRegister(operand, registerNumber, shiftModeNumber, shiftRegisterNumber, shiftImmediateValue)
  298. END
  299. ELSIF GetRegisterList(registerList) THEN
  300. InstructionSet.InitRegisterList(operand, InstructionSet.R0, registerList);
  301. IF ThisSymbol(Scanner.Arrow) THEN
  302. INCL(flags, InstructionSet.flagUserMode);
  303. END;
  304. ELSIF GetCoprocessor(value) THEN
  305. (* coprocessor name *)
  306. InstructionSet.InitCoprocessor(operand, value)
  307. ELSIF GetCoprocessorOpcode(value) THEN (* integer constant in the range 0 .. 7 *)
  308. (* coprocessor opcode *)
  309. InstructionSet.InitOpcode(operand, value)
  310. ELSIF GetImmediateValue(value) THEN (* expression that evaluates to constant value starting with '#' *)
  311. (* ARM immediate value *)
  312. InstructionSet.InitImmediate(operand, value)
  313. ELSIF GetNonConstant(errorPosition,token.identifierString, result) THEN
  314. InstructionSet.InitImmediate(operand,LONGINT(result.value));
  315. IF result.fixup # NIL THEN
  316. InstructionSet.AddFixup(operand,result.fixup);
  317. END;
  318. NextToken;
  319. ELSIF GetPlainValue(value) THEN (* expression that evaluates to constant value *)
  320. (* resolved label name *)
  321. InstructionSet.InitImmediate(operand, value)
  322. ELSE
  323. Error(position, "invalid operand")
  324. END;
  325. IF ThisSymbol(Scanner.ExclamationMark) THEN
  326. INCL(flags, InstructionSet.flagBaseRegisterUpdate);
  327. END;
  328. IF ~newOperandExpected THEN newOperandExpected := ThisSymbol(Scanner.Comma) END; (* a comma means that there is one more operand *)
  329. operands[operandNumber] := operand;
  330. END
  331. END ParseOperand;
  332. BEGIN
  333. (*
  334. IF Trace THEN D.String("Instruction: "); D.String(mnemonic); D.String(" "); D.Ln END;
  335. *)
  336. position := errorPosition;
  337. IF InstructionSet.FindMnemonic(mnemonic, opCode, condition, flags) THEN
  338. (*IF Trace THEN
  339. D.String(" opCode="); D.Int(opCode, 0); D.Ln;
  340. D.String(" condition="); D.Int(condition, 0); D.Ln;
  341. D.String(" flags="); D.Set(flags); D.Ln;
  342. END;*)
  343. FOR i := 0 TO InstructionSet.MaxOperands - 1 DO
  344. InstructionSet.InitOperand(operands[i])
  345. END;
  346. operandNumber := 0;
  347. IF token.symbol # Scanner.Ln THEN
  348. REPEAT
  349. ParseOperand;
  350. INC(operandNumber);
  351. UNTIL error OR ~newOperandExpected;
  352. END;
  353. IF ~error THEN
  354. IF ~InstructionSet.MakeInstruction(instruction, opCode, condition, flags, operands) THEN
  355. ErrorSS(position, "wrong instruction format: ", mnemonic);
  356. ELSE
  357. IF pass < FoxAssembler.MaxPasses THEN
  358. (* not last pass: only increment the current PC by 4 units *)
  359. section.resolved.SetPC(section.resolved.pc + 4)
  360. ELSE
  361. (* last pass: emit the instruction *)
  362. IF ~InstructionSet.EmitInstruction(instruction, section.resolved) THEN
  363. ErrorSS(position, "wrong instruction format (encoding failed): ", mnemonic);
  364. END;
  365. END
  366. END
  367. END
  368. ELSE
  369. ErrorSS(position, "unknown mnemonic: ", mnemonic)
  370. END
  371. END Instruction;
  372. END Assembler;
  373. END FoxARMAssembler.
  374. System.FreeDownTo FoxARMInstructionSet ~
  375. Alwazs