aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2021-10-22 07:50:50 -0400
committerClyne Sullivan <clyne@bitgloo.com>2021-10-22 07:50:50 -0400
commit67f3a6c9896a5651e00eb22ee6e036c536aa0587 (patch)
tree76d66c0442ad64b51ea606647ce98380d494bfba /src
parent6a62488e1599ddfb3981dcf22e01024d5619af0f (diff)
first draft; needs tests
Diffstat (limited to 'src')
-rw-r--r--src/core.c258
-rw-r--r--src/core.h15
-rw-r--r--src/do_cycle_byte.c214
-rw-r--r--src/do_cycle_word.c246
4 files changed, 733 insertions, 0 deletions
diff --git a/src/core.c b/src/core.c
new file mode 100644
index 0000000..c29fe96
--- /dev/null
+++ b/src/core.c
@@ -0,0 +1,258 @@
+#include "core.h"
+
+#include <stdint.h>
+
+#define MSP430_SR_C (1 << 0)
+#define MSP430_SR_Z (1 << 1)
+#define MSP430_SR_N (1 << 2)
+#define MSP430_SR_V (1 << 8)
+
+// r0 = pc
+// r1 = sp
+// r2 = sr
+
+static int msp430_do_cycle_jump(msp430_t *state, uint16_t opcode);
+int msp430_do_cycle_single_operand(msp430_t *state, uint16_t opcode);
+int msp430_do_cycle_dual_operand(msp430_t *state, uint16_t opcode);
+int msp430_do_cycle_single_operand_byte(msp430_t *state, uint16_t opcode);
+int msp430_do_cycle_dual_operand_byte(msp430_t *state, uint16_t opcode);
+
+uint16_t *msp430_do_cycle_get_single_operand(msp430_t *state, uint16_t opcode);
+uint16_t *msp430_do_cycle_get_source_operand(msp430_t *state, uint16_t opcode);
+uint16_t *msp430_do_cycle_get_dest_operand(msp430_t *state, uint16_t opcode);
+
+static inline int msp430_get_opcode_bw(uint16_t opcode);
+
+void msp430_init_state(msp430_t *state, void *mem)
+{
+ for (int i = 0; i < 16; ++i)
+ state->reg[i] = 0;
+ state->mem = mem;
+}
+
+int msp430_do_cycle(msp430_t *state)
+{
+ uint16_t pc = state->reg[0];
+ uint16_t opcode = *((uint16_t *)(state->mem + pc));
+
+ // Check for program end...
+ if (opcode == 0x4130 && state->reg[1] == 0)
+ return 1;
+
+ state->reg[0] = pc + 2;
+
+ int ret;
+ if ((opcode & 0xE000) == 0x2000) {
+ ret = msp430_do_cycle_jump(state, opcode);
+ } else {
+ int bw = msp430_get_opcode_bw(opcode);
+ if (bw == 0) {
+ if ((opcode & 0xFC00) == 0x1000)
+ ret = msp430_do_cycle_single_operand(state, opcode);
+ else
+ ret = msp430_do_cycle_dual_operand(state, opcode);
+ } else {
+ if ((opcode & 0xFC00) == 0x1000)
+ ret = msp430_do_cycle_single_operand_byte(state, opcode);
+ else
+ ret = msp430_do_cycle_dual_operand_byte(state, opcode);
+ }
+ }
+
+ return ret;
+}
+
+static void msp430_jump_to_offset(msp430_t *state, uint16_t opcode)
+{
+ uint16_t addr = opcode & 0x3FF;
+ if (addr & (1 << 9))
+ addr |= 0xFC00;
+ int16_t saddr = (int16_t)addr * 2;
+ state->reg[0] += saddr;
+}
+
+int msp430_do_cycle_jump(msp430_t *state, uint16_t opcode)
+{
+ // PC to become PC + ((opcode & 0x3FF) << 1)
+ switch ((opcode & 0x01C0) >> 10) {
+ case 0:
+ // JNE/JZ
+ if ((state->reg[2] & MSP430_SR_Z) == 0)
+ msp430_jump_to_offset(state, opcode);
+ break;
+ case 1:
+ // JEQ/JZ
+ if ((state->reg[2] & MSP430_SR_Z) == MSP430_SR_Z)
+ msp430_jump_to_offset(state, opcode);
+ break;
+ case 2:
+ // JNC/JLO
+ if ((state->reg[2] & MSP430_SR_C) == 0)
+ msp430_jump_to_offset(state, opcode);
+ break;
+ case 3:
+ // JC/JHS
+ if ((state->reg[2] & MSP430_SR_C) == MSP430_SR_C)
+ msp430_jump_to_offset(state, opcode);
+ break;
+ case 4:
+ // JN
+ if ((state->reg[2] & MSP430_SR_N) == MSP430_SR_N)
+ msp430_jump_to_offset(state, opcode);
+ break;
+ case 5: {
+ // JGE
+ uint16_t flags = state->reg[2] & (MSP430_SR_N | MSP430_SR_V);
+ if (flags == 0 || flags == (MSP430_SR_N | MSP430_SR_V))
+ msp430_jump_to_offset(state, opcode);
+ break; }
+ case 6: {
+ // JL
+ uint16_t flags = state->reg[2] & (MSP430_SR_N | MSP430_SR_V);
+ if (flags == MSP430_SR_N || flags == MSP430_SR_V)
+ msp430_jump_to_offset(state, opcode);
+ break; }
+ case 7:
+ // JMP
+ msp430_jump_to_offset(state, opcode);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+uint16_t *msp430_do_cycle_get_operand(msp430_t *state, int AS, int BW, int SOURCE)
+{
+ static uint16_t constants[6] = {
+ 0, 1, 2, -1, 4, 8
+ };
+
+ if (SOURCE == 0) {
+ if (AS == 1) {
+ // Operand at PC + X
+ // X = word after PC
+ uint16_t offset = *((uint16_t *)(state->mem + state->reg[0]));
+ uint16_t *ret = (uint16_t *)(state->mem + state->reg[0] + offset);
+ state->reg[0] += 2;
+ return ret;
+ } else if (AS == 3) {
+ // Operand is X
+ uint16_t *ret = (uint16_t *)(state->mem + state->reg[0]);
+ state->reg[0] += 2;
+ return ret;
+ }
+ }
+
+ if (SOURCE == 2) {
+ switch (AS) {
+ case 0:
+ // R2
+ return &state->reg[2];
+ break;
+ case 1: {
+ // Operand at X
+ uint16_t offset = *((uint16_t *)(state->mem + state->reg[0]));
+ uint16_t *ret = (uint16_t *)(state->mem + offset);
+ state->reg[0] += 2;
+ return ret;
+ break; }
+ case 2:
+ return &constants[4];
+ break;
+ case 3:
+ return &constants[5];
+ break;
+ }
+ } else if (SOURCE == 3) {
+ // Constants
+ return &constants[AS];
+ } else {
+ switch (AS) {
+ case 0:
+ // Register
+ return &state->reg[SOURCE];
+ break;
+ case 1: {
+ // Operand at Rn + X
+ uint16_t offset = *((uint16_t *)(state->mem + state->reg[0]));
+ uint16_t *ret = (uint16_t *)(state->mem + state->reg[SOURCE] + offset);
+ state->reg[0] += 2;
+ return ret;
+ break; }
+ case 2:
+ // Operand at Rn
+ return (uint16_t *)(state->mem + state->reg[SOURCE]);
+ break;
+ case 3: {
+ // Operand at Rn, increment Rn
+ uint16_t *ret = (uint16_t *)(state->mem + state->reg[SOURCE]);
+ state->reg[SOURCE] += BW ? 1 : 2;
+ return ret;
+ break; }
+ }
+ }
+
+ return 0; // Failed...
+}
+
+inline int msp430_get_opcode_bw(uint16_t opcode)
+{
+ return opcode & (1 << 6);
+}
+
+uint16_t *msp430_do_cycle_get_single_operand(msp430_t *state, uint16_t opcode)
+{
+ return msp430_do_cycle_get_operand(state,
+ /* AS */ (opcode & 0x30) >> 4,
+ /* BW */ msp430_get_opcode_bw(opcode),
+ /* SOURCE */ (opcode & 0xF));
+}
+
+uint16_t *msp430_do_cycle_get_source_operand(msp430_t *state, uint16_t opcode)
+{
+ return msp430_do_cycle_get_operand(state,
+ /* AS */ (opcode & 0x30) >> 4,
+ /* BW */ msp430_get_opcode_bw(opcode),
+ /* SOURCE */ (opcode & 0xF00) >> 8);
+}
+uint16_t *msp430_do_cycle_get_dest_operand(msp430_t *state, uint16_t opcode)
+{
+ int AD = opcode & 0x80;
+ int DEST = opcode & 0xF;
+
+ if (AD == 0) {
+ // Byte operation? Clear MSB.
+ if (msp430_get_opcode_bw(opcode) == 0) {
+ return &state->reg[DEST];
+ } else {
+ uint16_t *ret = &state->reg[DEST];
+ *ret &= 0xFF;
+ return ret;
+ }
+ } else {
+ if (DEST == 0) {
+ // dest at PC + X
+ uint16_t offset = *((uint16_t *)(state->mem + state->reg[0]));
+ uint16_t *ret = (uint16_t *)(state->mem + state->reg[0] + offset);
+ state->reg[0] += 2;
+ return ret;
+ } else if (DEST == 2) {
+ // dest at X
+ uint16_t offset = *((uint16_t *)(state->mem + state->reg[0]));
+ uint16_t *ret = (uint16_t *)(state->mem + offset);
+ state->reg[0] += 2;
+ return ret;
+ } else {
+ // dest at Rn + X
+ uint16_t offset = *((uint16_t *)(state->mem + state->reg[0]));
+ uint16_t *ret = (uint16_t *)(state->mem + state->reg[DEST] + offset);
+ state->reg[0] += 2;
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/core.h b/src/core.h
new file mode 100644
index 0000000..2a320a1
--- /dev/null
+++ b/src/core.h
@@ -0,0 +1,15 @@
+#ifndef CORE_H
+#define CORE_H
+
+#include <stdint.h>
+
+typedef struct {
+ uint16_t reg[16];
+ uint8_t *mem;
+} msp430_t;
+
+void msp430_init_state(msp430_t *state, void *mem);
+int msp430_do_cycle(msp430_t *state);
+
+#endif // CORE_H
+
diff --git a/src/do_cycle_byte.c b/src/do_cycle_byte.c
new file mode 100644
index 0000000..247d3b4
--- /dev/null
+++ b/src/do_cycle_byte.c
@@ -0,0 +1,214 @@
+#include <stdint.h>
+
+#define MSP430_SR_C (1 << 0)
+#define MSP430_SR_Z (1 << 1)
+#define MSP430_SR_N (1 << 2)
+#define MSP430_SR_V (1 << 8)
+
+// r0 = pc
+// r1 = sp
+// r2 = sr
+typedef struct {
+ uint16_t reg[16];
+ uint8_t *mem;
+} msp430_t;
+
+extern uint16_t *msp430_do_cycle_get_single_operand(msp430_t *state, uint16_t opcode);
+extern uint16_t *msp430_do_cycle_get_source_operand(msp430_t *state, uint16_t opcode);
+extern uint16_t *msp430_do_cycle_get_dest_operand(msp430_t *state, uint16_t opcode);
+
+int msp430_do_cycle_single_operand_byte(msp430_t *state, uint16_t opcode)
+{
+ uint8_t *operand = (uint8_t *)msp430_do_cycle_get_single_operand(state, opcode);
+ if (operand == 0)
+ return -1;
+
+ switch ((opcode & 0x0380) >> 7) {
+ case 0: {
+ // RRC
+ uint8_t res = *operand;
+ uint16_t sr = 0;
+ if (res & 1)
+ sr |= MSP430_SR_C;
+ res >>= 1;
+ if (state->reg[2] & MSP430_SR_C)
+ res |= 0x80;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ *operand = res;
+ state->reg[2] = sr;
+ break; }
+ case 2: {
+ // RRA
+ uint8_t res = *operand;
+ uint16_t sr = 0;
+ if (res & 1)
+ sr |= MSP430_SR_C;
+ res >>= 1;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ *operand = res;
+ state->reg[2] = sr;
+ break; }
+ case 4: {
+ // PUSH
+ uint16_t sp = state->reg[1] - 2;
+ *((uint16_t *)(state->mem + sp)) = *operand;
+ state->reg[1] = sp;
+ break; }
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+int msp430_do_cycle_dual_operand_byte(msp430_t *state, uint16_t opcode)
+{
+ uint8_t *src = (uint8_t *)msp430_do_cycle_get_source_operand(state, opcode);
+ uint8_t *dst = (uint8_t *)msp430_do_cycle_get_dest_operand(state, opcode);
+ if (src == 0 || dst == 0)
+ return -1;
+
+ switch ((opcode & 0xF000) >> 12) {
+ case 4:
+ // MOV
+ *dst = *src;
+ break;
+ case 5: {
+ // ADD
+ uint16_t res = *src + *dst;
+ uint16_t sr = 0;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFF00) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x80) ^ (*src & 0x80)) == 0 && (*src & 0x80) != (res & 0x80))
+ sr |= MSP430_SR_V;
+ *dst = res & 0xFF;
+ state->reg[2] = sr;
+ break; }
+ case 6: {
+ // ADDC
+ uint16_t res = *src + *dst + (state->reg[2] & MSP430_SR_C);
+ uint16_t sr = 0;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFF00) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x80) ^ (*src & 0x80)) == 0 && (*src & 0x80) != (res & 0x80))
+ sr |= MSP430_SR_V;
+ *dst = res & 0xFF;
+ state->reg[2] = sr;
+ break; }
+ case 7: {
+ // SUBC
+ uint16_t res = *dst + ~(*src) + (state->reg[2] & MSP430_SR_C);
+ uint16_t sr = 0;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFF00) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x80) ^ (*src & 0x80)) == 0 && (*src & 0x80) != (res & 0x80))
+ sr |= MSP430_SR_V;
+ *dst = res & 0xFF;
+ state->reg[2] = sr;
+ break; }
+ case 8: {
+ // SUB
+ uint16_t res = *dst + ~(*src) + 1;
+ uint16_t sr = 0;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFF00) != 0) // TODO confirm
+ sr |= MSP430_SR_C;
+ if (((*src & 0x80) ^ (*src & 0x80)) == 0 && (*src & 0x80) != (res & 0x80))
+ sr |= MSP430_SR_V;
+ *dst = res & 0xFF;
+ state->reg[2] = sr;
+ break; }
+ case 9: {
+ // CMP
+ uint16_t res = *dst + ~(*src) + 1;
+ uint16_t sr = 0;
+ if ((int8_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFF00) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x80) ^ (*src & 0x80)) == 0 && (*src & 0x80) != (res & 0x80))
+ sr |= MSP430_SR_V;
+ state->reg[2] = sr;
+ break; }
+ case 10:
+ // DADD TODO
+ break;
+ case 11: {
+ // BIT
+ uint8_t res = *dst & *src;
+ uint16_t sr = 0;
+ if (res & 0x80)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ state->reg[2] = sr;
+ break; }
+ case 12:
+ // BIC
+ *dst &= ~(*src);
+ break;
+ case 13:
+ // BIS
+ *dst |= *src;
+ break;
+ case 14: {
+ // XOR
+ uint8_t res = *dst ^ *src;
+ uint16_t sr = 0;
+ if (res & 0x80)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ if ((*dst & 0x80) && (*src & 0x80))
+ sr |= MSP430_SR_V;
+ *dst = res;
+ state->reg[2] = sr;
+ break; }
+ case 15: {
+ // AND
+ uint8_t res = *dst & *src;
+ uint16_t sr = 0;
+ if (res & 0x80)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ *dst = res;
+ state->reg[2] = sr;
+ break; }
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/src/do_cycle_word.c b/src/do_cycle_word.c
new file mode 100644
index 0000000..2599d13
--- /dev/null
+++ b/src/do_cycle_word.c
@@ -0,0 +1,246 @@
+#include <stdint.h>
+
+#define MSP430_SR_C (1 << 0)
+#define MSP430_SR_Z (1 << 1)
+#define MSP430_SR_N (1 << 2)
+#define MSP430_SR_V (1 << 8)
+
+// r0 = pc
+// r1 = sp
+// r2 = sr
+typedef struct {
+ uint16_t reg[16];
+ uint8_t *mem;
+} msp430_t;
+
+extern uint16_t *msp430_do_cycle_get_single_operand(msp430_t *state, uint16_t opcode);
+extern uint16_t *msp430_do_cycle_get_source_operand(msp430_t *state, uint16_t opcode);
+extern uint16_t *msp430_do_cycle_get_dest_operand(msp430_t *state, uint16_t opcode);
+
+int msp430_do_cycle_single_operand(msp430_t *state, uint16_t opcode)
+{
+ uint16_t *operand = msp430_do_cycle_get_single_operand(state, opcode);
+ if (operand == 0)
+ return -1;
+
+ switch ((opcode & 0x0380) >> 7) {
+ case 0: {
+ // RRC
+ uint16_t res = *operand;
+ uint16_t sr = 0;
+ if (res & 1)
+ sr |= MSP430_SR_C;
+ res >>= 1;
+ if (state->reg[2] & MSP430_SR_C)
+ res |= 0x8000;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ *operand = res;
+ state->reg[2] = sr;
+ break; }
+ case 1: {
+ // SWPB
+ uint16_t swapped = ((*operand & 0xFF00) >> 8) | ((*operand & 0x00FF) << 8);
+ *operand = swapped;
+ break; }
+ case 2: {
+ // RRA
+ uint16_t res = *operand;
+ uint16_t sr = 0;
+ if (res & 1)
+ sr |= MSP430_SR_C;
+ res >>= 1;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ *operand = res;
+ state->reg[2] = sr;
+ break; }
+ case 3: {
+ // SXT
+ uint16_t sr = 0;
+ uint16_t res = (*operand & 0x80) ? (*operand | 0xFF00) : *operand;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ *operand = res;
+ state->reg[2] = sr;
+ break; }
+ case 4: {
+ // PUSH
+ uint16_t sp = state->reg[1] - 2;
+ *((uint16_t *)(state->mem + sp)) = *operand;
+ state->reg[1] = sp;
+ break; }
+ case 5: {
+ // CALL
+ uint16_t sp = state->reg[1] - 2;
+ *((uint16_t *)(state->mem + sp)) = state->reg[0];
+ state->reg[0] = *operand;
+ state->reg[1] = sp;
+ break; }
+ case 6: {
+ // RETI
+ uint16_t sp = state->reg[1];
+ state->reg[2] = *((uint16_t *)(state->mem + sp));
+ state->reg[0] = *((uint16_t *)(state->mem + sp + 2));
+ state->reg[1] = sp + 4;
+ break; }
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+int msp430_do_cycle_dual_operand(msp430_t *state, uint16_t opcode)
+{
+ uint16_t *src = msp430_do_cycle_get_source_operand(state, opcode);
+ uint16_t *dst = msp430_do_cycle_get_dest_operand(state, opcode);
+ if (src == 0 || dst == 0)
+ return -1;
+
+ switch ((opcode & 0xF000) >> 12) {
+ case 4:
+ // MOV
+ *dst = *src;
+ break;
+ case 5: {
+ // ADD
+ uint32_t res = *src + *dst;
+ uint16_t sr = 0;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFFFF0000) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x8000) ^ (*src & 0x8000)) == 0 && (*src & 0x8000) != (res & 0x8000))
+ sr |= MSP430_SR_V;
+ *dst = (uint16_t)res;
+ state->reg[2] = sr;
+ break; }
+ case 6: {
+ // ADDC
+ uint32_t res = *src + *dst + (state->reg[2] & MSP430_SR_C);
+ uint16_t sr = 0;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFFFF0000) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x8000) ^ (*src & 0x8000)) == 0 && (*src & 0x8000) != (res & 0x8000))
+ sr |= MSP430_SR_V;
+ *dst = (uint16_t)res;
+ state->reg[2] = sr;
+ break; }
+ case 7: {
+ // SUBC
+ uint32_t res = *dst + ~(*src) + (state->reg[2] & MSP430_SR_C);
+ uint16_t sr = 0;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFFFF0000) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x8000) ^ (*src & 0x8000)) == 0 && (*src & 0x8000) != (res & 0x8000))
+ sr |= MSP430_SR_V;
+ *dst = (uint16_t)res;
+ state->reg[2] = sr;
+ break; }
+ case 8: {
+ // SUB
+ uint32_t res = *dst + ~(*src) + 1;
+ uint16_t sr = 0;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFFFF0000) != 0) // TODO confirm
+ sr |= MSP430_SR_C;
+ if (((*src & 0x8000) ^ (*src & 0x8000)) == 0 && (*src & 0x8000) != (res & 0x8000))
+ sr |= MSP430_SR_V;
+ *dst = (uint16_t)res;
+ state->reg[2] = sr;
+ break; }
+ case 9: {
+ // CMP
+ uint32_t res = *dst + ~(*src) + 1;
+ uint16_t sr = 0;
+ if ((int16_t)res < 0)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if ((res & 0xFFFF0000) != 0)
+ sr |= MSP430_SR_C;
+ if (((*src & 0x8000) ^ (*src & 0x8000)) == 0 && (*src & 0x8000) != (res & 0x8000))
+ sr |= MSP430_SR_V;
+ state->reg[2] = sr;
+ break; }
+ case 10:
+ // DADD TODO
+ break;
+ case 11: {
+ // BIT
+ uint16_t res = *dst & *src;
+ uint16_t sr = 0;
+ if (res & 0x8000)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ state->reg[2] = sr;
+ break; }
+ case 12:
+ // BIC
+ *dst &= ~(*src);
+ break;
+ case 13:
+ // BIS
+ *dst |= *src;
+ break;
+ case 14: {
+ // XOR
+ uint16_t res = *dst ^ *src;
+ uint16_t sr = 0;
+ if (res & 0x8000)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ if ((*dst & 0x8000) && (*src & 0x8000))
+ sr |= MSP430_SR_V;
+ *dst = res;
+ state->reg[2] = sr;
+ break; }
+ case 15: {
+ // AND
+ uint16_t res = *dst & *src;
+ uint16_t sr = 0;
+ if (res & 0x8000)
+ sr |= MSP430_SR_N;
+ if (res == 0)
+ sr |= MSP430_SR_Z;
+ if (res != 0)
+ sr |= MSP430_SR_C;
+ *dst = res;
+ state->reg[2] = sr;
+ break; }
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+