hex2_word.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /* -*- c-file-style: "linux";indent-tabs-mode:t -*- */
  2. /* Copyright (C) 2017 Jeremiah Orians
  3. * Copyright (C) 2017 Jan Nieuwenhuizen <janneke@gnu.org>
  4. * This file is part of mescc-tools
  5. *
  6. * mescc-tools is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * mescc-tools is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with mescc-tools. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "hex2_globals.h"
  20. unsigned shiftregister;
  21. unsigned tempword;
  22. int updates;
  23. void outOfRange(char* s, int value)
  24. {
  25. line_error();
  26. fputs("error: value ", stderr);
  27. fputs(int2str(value, 10, TRUE), stderr);
  28. fputs(" out of range for field type ", stderr);
  29. fputs(s, stderr);
  30. fputs("\n", stderr);
  31. exit(EXIT_FAILURE);
  32. }
  33. void UpdateShiftRegister(char ch, int value)
  34. {
  35. if ('.' == ch)
  36. {
  37. unsigned swap;
  38. /* Assume the user knows what they are doing */
  39. if(!BigEndian)
  40. {
  41. /* Swap from big-endian to little endian order */
  42. swap = (((value >> 24) & 0xFF) |
  43. ((value << 8) & 0xFF0000) |
  44. ((value >> 8) & 0xFF00) |
  45. ((value & 0xFF) << 24));
  46. }
  47. else
  48. {
  49. /* Big endian needs no change */
  50. swap = value;
  51. }
  52. /* we just take the 4 bytes after the . and shove in the shift register */
  53. swap = swap & ((0xFFFF << 16) | 0xFFFF);
  54. shiftregister = shiftregister ^ swap;
  55. }
  56. else if ('!' == ch)
  57. {
  58. /* Corresponds to RISC-V I format */
  59. /* Will need architecture specific logic if more architectures go this route */
  60. /* no range check because it needs to work with labels for lui/addi + AUIPC combos */
  61. /* !label is used in the second instruction of AUIPC combo but we want an offset from */
  62. /* the first instruction */
  63. value = value + 4;
  64. tempword = (value & 0xFFF) << 20;
  65. /* Update shift register */
  66. tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
  67. shiftregister = shiftregister ^ tempword;
  68. }
  69. else if ('@' == ch)
  70. {
  71. /* Corresponds to RISC-V B format (formerly known as SB) */
  72. /* Will need architecture specific logic if more architectures go this route */
  73. if ((value < -0x1000 || value > 0xFFF) || (value & 1)) outOfRange("B", value);
  74. /* Prepare the immediate's word */
  75. tempword = ((value & 0x1E) << 7)
  76. | ((value & 0x7E0) << (31 - 11))
  77. | ((value & 0x800) >> 4)
  78. | ((value & 0x1000) << (31 - 12));
  79. tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
  80. /* Update shift register */
  81. shiftregister = shiftregister ^ tempword;
  82. }
  83. else if ('$' == ch)
  84. {
  85. /* Corresponds with RISC-V J format (formerly known as UJ) */
  86. /* Will need architecture specific logic if more architectures go this route */
  87. if ((value < -0x100000 || value > 0xFFFFF) || (value & 1)) outOfRange("J", value);
  88. tempword = ((value & 0x7FE) << (30 - 10))
  89. | ((value & 0x800) << (20 - 11))
  90. | ((value & 0xFF000))
  91. | ((value & 0x100000) << (31 - 20));
  92. tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
  93. shiftregister = shiftregister ^ tempword;
  94. }
  95. else if ('~' == ch)
  96. {
  97. /* Corresponds with RISC-V U format */
  98. /* Will need architecture specific logic if more architectures go this route */
  99. if ((value & 0xFFF) < 0x800) tempword = value & (0xFFFFF << 12);
  100. else tempword = (value & (0xFFFFF << 12)) + 0x1000;
  101. tempword = tempword & ((0xFFFF << 16) | 0xFFFF);
  102. shiftregister = shiftregister ^ tempword;
  103. }
  104. else
  105. {
  106. line_error();
  107. fputs("error: UpdateShiftRegister reached impossible case: ch=", stderr);
  108. fputc(ch, stderr);
  109. fputs("\n", stderr);
  110. exit(EXIT_FAILURE);
  111. }
  112. }
  113. void WordStorePointer(char ch, FILE* source_file)
  114. {
  115. /* Get string of pointer */
  116. ip = ip + 4;
  117. Clear_Scratch(scratch);
  118. int base_sep_p = consume_token(source_file);
  119. /* Lookup token */
  120. int target = GetTarget(scratch);
  121. int displacement;
  122. int base = ip;
  123. /* Change relative base address to :<base> */
  124. if ('>' == base_sep_p)
  125. {
  126. Clear_Scratch(scratch);
  127. consume_token (source_file);
  128. base = GetTarget (scratch);
  129. /* Force universality of behavior */
  130. displacement = (target - base);
  131. }
  132. else
  133. {
  134. displacement = Architectural_displacement(target, base);
  135. }
  136. /* output calculated difference */
  137. if('&' == ch) outputPointer(target, 4, TRUE); /* Deal with & */
  138. else if('%' == ch) outputPointer(displacement, 4, FALSE); /* Deal with % */
  139. else
  140. {
  141. line_error();
  142. fputs("error: WordStorePointer reached impossible case: ch=", stderr);
  143. fputc(ch, stderr);
  144. fputs("\n", stderr);
  145. exit(EXIT_FAILURE);
  146. }
  147. }
  148. unsigned sr_nextb()
  149. {
  150. unsigned rv = shiftregister & 0xff;
  151. shiftregister = shiftregister >> 8;
  152. return rv;
  153. }
  154. void DoByte(char c, FILE* source_file, int write, int update)
  155. {
  156. if(HEX == ByteMode)
  157. {
  158. if(0 <= hex(c, source_file))
  159. {
  160. if(toggle)
  161. {
  162. if(write) fputc(((hold * 16)) + hex(c, source_file) ^ sr_nextb(), output);
  163. ip = ip + 1;
  164. if(update)
  165. {
  166. hold = (hold * 16) + hex(c, source_file);
  167. tempword = (tempword << 8) ^ hold;
  168. updates = updates + 1;
  169. }
  170. hold = 0;
  171. }
  172. else
  173. {
  174. hold = hex(c, source_file);
  175. }
  176. toggle = !toggle;
  177. }
  178. }
  179. else if(OCTAL ==ByteMode)
  180. {
  181. if(0 <= octal(c, source_file))
  182. {
  183. if(2 == toggle)
  184. {
  185. if(write) fputc(((hold * 8)) + octal(c, source_file) ^ sr_nextb(), output);
  186. ip = ip + 1;
  187. if(update)
  188. {
  189. hold = ((hold * 8) + octal(c, source_file));
  190. tempword = (tempword << 8) ^ hold;
  191. updates = updates + 1;
  192. }
  193. hold = 0;
  194. toggle = 0;
  195. }
  196. else if(1 == toggle)
  197. {
  198. hold = ((hold * 8) + octal(c, source_file));
  199. toggle = 2;
  200. }
  201. else
  202. {
  203. hold = octal(c, source_file);
  204. toggle = 1;
  205. }
  206. }
  207. }
  208. else if(BINARY == ByteMode)
  209. {
  210. if(0 <= binary(c, source_file))
  211. {
  212. if(7 == toggle)
  213. {
  214. if(write) fputc((hold * 2) + binary(c, source_file) ^ sr_nextb(), output);
  215. ip = ip + 1;
  216. if(update)
  217. {
  218. hold = ((hold * 2) + binary(c, source_file));
  219. tempword = (tempword << 8) ^ hold;
  220. updates = updates + 1;
  221. }
  222. hold = 0;
  223. toggle = 0;
  224. }
  225. else
  226. {
  227. hold = ((hold * 2) + binary(c, source_file));
  228. toggle = toggle + 1;
  229. }
  230. }
  231. }
  232. }
  233. void WordFirstPass(struct input_files* input)
  234. {
  235. if(NULL == input) return;
  236. WordFirstPass(input->next);
  237. filename = input->filename;
  238. linenumber = 1;
  239. FILE* source_file = fopen(filename, "r");
  240. if(NULL == source_file)
  241. {
  242. fputs("The file: ", stderr);
  243. fputs(input->filename, stderr);
  244. fputs(" can not be opened!\n", stderr);
  245. exit(EXIT_FAILURE);
  246. }
  247. toggle = FALSE;
  248. int c;
  249. for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
  250. {
  251. /* Check for and deal with label */
  252. if(':' == c)
  253. {
  254. c = storeLabel(source_file, ip);
  255. }
  256. /* check for and deal with relative/absolute pointers to labels */
  257. if('.' == c)
  258. {
  259. /* Read architecture specific number of bytes for what is defined as a word */
  260. /* 4bytes in RISC-V's case */
  261. updates = 0;
  262. tempword = 0;
  263. while (updates < 4)
  264. {
  265. c = fgetc(source_file);
  266. DoByte(c, source_file, FALSE, TRUE);
  267. }
  268. ip = ip - 4;
  269. }
  270. else if(in_set(c, "!@$~"))
  271. {
  272. /* Don't update IP */
  273. c = Throwaway_token(source_file);
  274. }
  275. else if(in_set(c, "%&"))
  276. {
  277. ip = ip + 4;
  278. c = Throwaway_token(source_file);
  279. if ('>' == c)
  280. { /* deal with label>base */
  281. c = Throwaway_token(source_file);
  282. }
  283. }
  284. else if('<' == c)
  285. {
  286. pad_to_align(FALSE);
  287. }
  288. else if('^' == c)
  289. {
  290. /* Just ignore */
  291. continue;
  292. }
  293. else DoByte(c, source_file, FALSE, FALSE);
  294. }
  295. fclose(source_file);
  296. }
  297. void WordSecondPass(struct input_files* input)
  298. {
  299. shiftregister = 0;
  300. tempword = 0;
  301. if(NULL == input) return;
  302. WordSecondPass(input->next);
  303. filename = input->filename;
  304. linenumber = 1;
  305. FILE* source_file = fopen(filename, "r");
  306. /* Something that should never happen */
  307. if(NULL == source_file)
  308. {
  309. fputs("The file: ", stderr);
  310. fputs(input->filename, stderr);
  311. fputs(" can not be opened!\nWTF-pass2\n", stderr);
  312. exit(EXIT_FAILURE);
  313. }
  314. toggle = FALSE;
  315. hold = 0;
  316. int c;
  317. for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
  318. {
  319. if(':' == c) c = Throwaway_token(source_file); /* Deal with : */
  320. else if('.' == c)
  321. {
  322. /* Read architecture specific number of bytes for what is defined as a word */
  323. /* 4bytes in RISC-V's case */
  324. updates = 0;
  325. tempword = 0;
  326. while (updates < 4)
  327. {
  328. c = fgetc(source_file);
  329. DoByte(c, source_file, FALSE, TRUE);
  330. }
  331. UpdateShiftRegister('.', tempword);
  332. ip = ip - 4;
  333. }
  334. else if(in_set(c, "%&")) WordStorePointer(c, source_file); /* Deal with % and & */
  335. else if(in_set(c, "!@$~"))
  336. {
  337. Clear_Scratch(scratch);
  338. consume_token(source_file);
  339. UpdateShiftRegister(c, Architectural_displacement(GetTarget(scratch), ip)); /* Play with shift register */
  340. }
  341. else if('<' == c) pad_to_align(TRUE);
  342. else if('^' == c) ALIGNED = TRUE;
  343. else DoByte(c, source_file, TRUE, FALSE);
  344. }
  345. fclose(source_file);
  346. }