formatII.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. MSP430 Emulator
  3. Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
  4. "MSP430 Emulator" is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. "MSP430 Emulator" is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. //##########+++ Decode Format II Instructions +++#########
  16. //# Format II are single operand of the form:
  17. //# [0001][00CC][CBAA][SSSS]
  18. //#
  19. //# Where C = Opcode, B = Byte/Word flag,
  20. //# A = Addressing mode for source
  21. //# S = Source
  22. //########################################################
  23. #include "formatII.h"
  24. #include "decoder.h"
  25. #include "../utilities.h"
  26. void decode_formatII(Emulator *emu, uint16_t instruction, bool disassemble)
  27. {
  28. Cpu *cpu = emu->cpu;
  29. Debugger *debugger = emu->debugger;
  30. uint8_t opcode = (instruction & 0x0380) >> 7;
  31. uint8_t bw_flag = (instruction & 0x0040) >> 6;
  32. uint8_t as_flag = (instruction & 0x0030) >> 4;
  33. uint8_t source = (instruction & 0x000F);
  34. char reg_name[10];
  35. reg_num_to_name(source, reg_name);
  36. uint16_t *reg = (uint16_t * )get_reg_ptr(emu, source);
  37. uint16_t bogus_reg; /* For immediate values to be operated on */
  38. uint8_t constant_generator_active = 0; /* Specifies if CG1/CG2 active */
  39. int16_t immediate_constant = 0; /* Generated Constant */
  40. char mnemonic[100] = {0};
  41. /* String to show hex value of instruction */
  42. char hex_str[100] = {0};
  43. char hex_str_part[10] = {0};
  44. sprintf(hex_str, "%04X", instruction);
  45. /*
  46. printf("Opcode: 0x%01X Source bits: 0x%01X\nAS_Flag: 0x%01X "\
  47. "BW_Flag: 0x%01X\n",
  48. opcode, source, as_flag, bw_flag);
  49. */
  50. /* Spot CG1 and CG2 Constant generator instructions */
  51. if ( (source == 2 && as_flag > 1) || source == 3 ) {
  52. constant_generator_active = 1;
  53. immediate_constant = run_constant_generator(source, as_flag);
  54. }
  55. else {
  56. constant_generator_active = 0;
  57. }
  58. /* Identify the nature of instruction operand addressing modes */
  59. int16_t source_value, source_offset;
  60. uint16_t *source_address;
  61. char asm_operand[50] = {0};
  62. /* Register; Ex: PUSH Rd */
  63. /* Constant Gen; Ex: PUSH #C */ /* 0 */
  64. if (as_flag == 0) {
  65. if (constant_generator_active) { /* Source Constant */
  66. source_value = bogus_reg = immediate_constant;
  67. source_address = &bogus_reg;
  68. sprintf(asm_operand, "#0x%04X", (uint16_t) source_value);
  69. }
  70. else { /* Source Register */
  71. source_value = *reg;
  72. source_address = reg;
  73. sprintf(asm_operand, "%s", reg_name);
  74. }
  75. bw_flag == EMU_BYTE ? *reg &= 0x00FF : 0;
  76. }
  77. /* Indexed; Ex: PUSH 0x0(Rs) */
  78. /* Symbolic; Ex: PUSH 0xS */
  79. /* Absolute: Ex: PUSH &0xS */
  80. /* Constant Gen; Ex: PUSH #C */ /* 1 */
  81. else if (as_flag == 1) {
  82. if (constant_generator_active) { /* Source Constant */
  83. source_value = bogus_reg = immediate_constant;
  84. source_address = &bogus_reg;
  85. sprintf(asm_operand, "#0x%04X", source_value);
  86. }
  87. else if (source == 0) { /* Source Symbolic */
  88. source_offset = fetch(emu);
  89. uint16_t virtual_addr = cpu->pc + source_offset;
  90. sprintf(hex_str_part, "%04X", (uint16_t) source_offset);
  91. strncat(hex_str, hex_str_part, sizeof hex_str);
  92. source_address = get_addr_ptr(virtual_addr);
  93. sprintf(asm_operand, "0x%04X", virtual_addr);
  94. }
  95. else if (source == 2) { /* Source Absolute */
  96. source_offset = fetch(emu);
  97. source_address = get_addr_ptr(source_offset);
  98. source_value = *source_address;
  99. sprintf(hex_str_part, "%04X", (uint16_t) source_value);
  100. strncat(hex_str, hex_str_part, sizeof hex_str);
  101. sprintf(asm_operand, "&0x%04X", (uint16_t) source_offset);
  102. }
  103. else { /* Source Indexed */
  104. source_offset = fetch(emu);
  105. source_address = get_addr_ptr(*reg + source_offset);
  106. source_value = *source_address;
  107. sprintf(hex_str_part, "%04X", (uint16_t) source_offset);
  108. strncat(hex_str, hex_str_part, sizeof hex_str);
  109. sprintf(asm_operand, "0x%04X(%s)", (uint16_t) source_offset, reg_name);
  110. }
  111. }
  112. /* Indirect; Ex: PUSH @Rs */
  113. /* Constant Gen; Ex: PUSH #C */ /* 2, 4 */
  114. else if (as_flag == 2) {
  115. if (constant_generator_active) { /* Source Constant */
  116. source_value = bogus_reg = immediate_constant;
  117. source_address = &bogus_reg;
  118. sprintf(asm_operand, "#0x%04X", immediate_constant);
  119. }
  120. else { /* Source Indirect */
  121. source_address = get_addr_ptr(*reg);
  122. source_value = *source_address;
  123. sprintf(asm_operand, "@%s", reg_name);
  124. }
  125. }
  126. /* Indirect AutoIncrement; Ex: PUSH @Rs+ */
  127. /* Immediate; Ex: PUSH #S */
  128. /* Constant Gen; Ex: PUSH #C */ /* -1, 8 */
  129. else if (as_flag == 3) {
  130. if (constant_generator_active) { /* Source Constant */
  131. source_value = bogus_reg = immediate_constant;
  132. source_address = &bogus_reg;
  133. sprintf(asm_operand, "#0x%04X", (uint16_t) source_value);
  134. }
  135. else if (source == 0) { /* Source Immediate */
  136. source_value = bogus_reg = fetch(emu);
  137. source_address = &bogus_reg;
  138. sprintf(hex_str_part, "%04X", (uint16_t) source_value);
  139. strncat(hex_str, hex_str_part, sizeof hex_str);
  140. if (bw_flag == EMU_WORD) {
  141. sprintf(asm_operand, "#0x%04X", (uint16_t) source_value);
  142. }
  143. else if (bw_flag == EMU_BYTE) {
  144. sprintf(asm_operand, "#0x%04X", (uint8_t) source_value);
  145. }
  146. }
  147. else { /* Source Indirect AutoIncrement */
  148. source_address = get_addr_ptr(*reg);
  149. source_value = *source_address;
  150. sprintf(asm_operand, "@%s+", reg_name);
  151. bw_flag == EMU_WORD ? *reg += 2 : (*reg += 1);
  152. }
  153. }
  154. if (!disassemble) {
  155. switch (opcode) {
  156. /* RRC Rotate right through carry
  157. * C → MSB → MSB-1 .... LSB+1 → LSB → C
  158. *
  159. * Description The destination operand is shifted right one position
  160. * as shown in Figure 3-18. The carry bit (C) is shifted into the MSB,
  161. * the LSB is shifted into the carry bit (C).
  162. *
  163. * N: Set if result is negative, reset if positive
  164. * Z: Set if result is zero, reset otherwise
  165. * C: Loaded from the LSB
  166. * V: Reset
  167. * TODO: UNDEFINED BEHAVIOR DURRING CONSTANT MANIPULATION, BROKEN
  168. */
  169. case 0x0:{
  170. bool CF = cpu->sr.carry;
  171. if (bw_flag == EMU_WORD) {
  172. cpu->sr.carry = *source_address & 0x0001; /* Set CF from LSB */
  173. *source_address >>= 1; /* Shift one right */
  174. CF ? *source_address |= 0x8000 : 0; /* Set MSB from prev CF */
  175. }
  176. else if (bw_flag == EMU_BYTE){
  177. cpu->sr.carry = *(uint8_t *) source_address & 0x01;
  178. *(uint8_t *) source_address >>= 1;
  179. CF ? *(uint8_t *) source_address |= 0x80 : 0;
  180. }
  181. cpu->sr.zero = is_zero(source_address, bw_flag);
  182. cpu->sr.negative = is_negative((int16_t*)source_address, bw_flag);
  183. cpu->sr.overflow = false;
  184. break;
  185. }
  186. /* SWPB Swap bytes
  187. * bw flag always 0 (word)
  188. * Bits 15 to 8 ↔ bits 7 to 0
  189. */
  190. case 0x1:{
  191. uint8_t upper_nibble, lower_nibble;
  192. upper_nibble = (*source_address & 0xFF00) >> 8;
  193. lower_nibble = *source_address & 0x00FF;
  194. *source_address = ((uint16_t)0|(lower_nibble << 8)) | upper_nibble;
  195. break;
  196. }
  197. /* RRA Rotate right arithmetic
  198. * MSB → MSB, MSB → MSB-1, ... LSB+1 → LSB, LSB → C
  199. *
  200. * N: Set if result is negative, reset if positive
  201. * Z: Set if result is zero, reset otherwise
  202. * C: Loaded from the LSB
  203. * V: Reset
  204. */
  205. case 0x2:{
  206. if (bw_flag == EMU_WORD) {
  207. cpu->sr.carry = *source_address & 0x0001;
  208. bool msb = *source_address >> 15;
  209. *source_address >>= 1;
  210. msb ? *source_address |= 0x8000 : 0; /* Extend Sign */
  211. }
  212. else if (bw_flag == EMU_BYTE) {
  213. cpu->sr.carry = *source_address & 0x0001;
  214. bool msb = *source_address >> 7;
  215. *source_address >>= 1;
  216. msb ? *source_address |= 0x0080 : 0;
  217. }
  218. cpu->sr.zero = is_zero(source_address, bw_flag);
  219. cpu->sr.negative = is_negative((int16_t*)source_address, bw_flag);
  220. cpu->sr.overflow = false;
  221. break;
  222. }
  223. /* SXT Sign extend byte to word
  224. * bw flag always 0 (word)
  225. *
  226. * Bit 7 → Bit 8 ......... Bit 15
  227. *
  228. * N: Set if result is negative, reset if positive
  229. * Z: Set if result is zero, reset otherwise
  230. * C: Set if result is not zero, reset otherwise (.NOT. Zero)
  231. * V: Reset
  232. */
  233. case 0x3:{
  234. if (*source_address & 0x0080) {
  235. *source_address |= 0xFF00;
  236. }
  237. else {
  238. *source_address &= 0x00FF;
  239. }
  240. cpu->sr.negative = is_negative((int16_t*)source_address, EMU_WORD);
  241. cpu->sr.zero = is_zero(source_address, EMU_WORD);
  242. cpu->sr.carry = ! cpu->sr.zero;
  243. cpu->sr.overflow = false;
  244. break;
  245. }
  246. /* PUSH push value on to the stack
  247. *
  248. * SP - 2 → SP
  249. * src → @SP
  250. *
  251. */
  252. case 0x4:{
  253. cpu->sp -= 2; /* Yes, even for BYTE Instructions */
  254. uint16_t *stack_address = get_stack_ptr(emu);
  255. if (bw_flag == EMU_WORD) {
  256. *stack_address = source_value;
  257. }
  258. else if (bw_flag == EMU_BYTE) {
  259. *stack_address &= 0xFF00; /* Zero out bottom half for pushed byte */
  260. *stack_address |= (uint8_t) source_value;
  261. }
  262. break;
  263. }
  264. /* CALL SUBROUTINE:
  265. * PUSH PC and PC = SRC
  266. *
  267. * This is always a word instruction. Supporting all addressing modes
  268. */
  269. case 0x5:{
  270. cpu->sp -= 2;
  271. uint16_t *stack_address = get_stack_ptr(emu);
  272. *stack_address = cpu->pc;
  273. cpu->pc = *source_address;
  274. break;
  275. }
  276. //# RETI Return from interrupt: Pop SR then pop PC
  277. case 0x6:{
  278. set_sr_value(emu, *get_stack_ptr(emu));
  279. cpu->sp += 2;
  280. cpu->pc = *get_stack_ptr(emu);
  281. cpu->sp += 2;
  282. // printf("RETI 0x%04X 0x%04X\n", cpu->pc, sr_to_value(emu));
  283. break;
  284. }
  285. default:{
  286. printf("Unknown Single operand instruction.\n");
  287. }
  288. } //# End of Switch
  289. } //# end if
  290. else {
  291. switch (opcode) {
  292. case 0x0: {
  293. bw_flag == EMU_WORD ?
  294. strncpy(mnemonic, "RRC", sizeof mnemonic) :
  295. strncpy(mnemonic, "RRC.B", sizeof mnemonic);
  296. break;
  297. }
  298. case 0x1: {
  299. strncpy(mnemonic, "SWPB", sizeof mnemonic);
  300. break;
  301. }
  302. case 0x2: {
  303. bw_flag == EMU_WORD ?
  304. strncpy(mnemonic, "RRA", sizeof mnemonic) :
  305. strncpy(mnemonic, "RRA.B", sizeof mnemonic);
  306. break;
  307. }
  308. case 0x3: {
  309. strncpy(mnemonic, "SXT", sizeof mnemonic);
  310. break;
  311. }
  312. case 0x4: {
  313. bw_flag == EMU_WORD ?
  314. strncpy(mnemonic, "PUSH", sizeof mnemonic) :
  315. strncpy(mnemonic, "PUSH.B", sizeof mnemonic);
  316. break;
  317. }
  318. case 0x5: {
  319. strncpy(mnemonic, "CALL", sizeof mnemonic);
  320. break;
  321. }
  322. case 0x6: {
  323. strncpy(mnemonic, "RETI", sizeof mnemonic);
  324. break;
  325. }
  326. default: {
  327. printf("Unknown Single operand instruction.\n");
  328. }
  329. } //# End of Switch
  330. strncat(mnemonic, "\t", sizeof mnemonic);
  331. strncat(mnemonic, asm_operand, sizeof mnemonic);
  332. strncat(mnemonic, "\n", sizeof mnemonic);
  333. if (disassemble && emu->debugger->debug_mode) {
  334. int i;
  335. char one = 0, two = 0;
  336. // Make little endian big endian
  337. for (i = 0;i < strlen(hex_str);i += 4) {
  338. one = hex_str[i];
  339. two = hex_str[i + 1];
  340. hex_str[i] = hex_str[i + 2];
  341. hex_str[i + 1] = hex_str[i + 3];
  342. hex_str[i + 2] = one;
  343. hex_str[i + 3] = two;
  344. }
  345. printf("%s", hex_str);
  346. print_console(emu, hex_str);
  347. for (i = strlen(hex_str);i < 12;i++) {
  348. printf(" ");
  349. print_console(emu, " ");
  350. }
  351. printf("\t%s", mnemonic);
  352. print_console(emu, "\t");
  353. print_console(emu, mnemonic);
  354. }
  355. } //# end else
  356. }