diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9eca6c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.a +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d9c168c --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +CROSS := +CC := $(CROSS)gcc +CFLAGS := -Os -ggdb -g3 \ + -Wall -Wextra -pedantic -Werror + +CSRC := $(wildcard src/*.c) +COBJ := $(patsubst %.c,%.o,$(CSRC)) + +all: lib430core.a + +clean: + @echo " CLEAN" + @rm -f lib430core.a $(COBJ) + +lib430core.a: $(COBJ) + @echo " AR " $@ + @$(CROSS)ar rc $@ $(COBJ) + @$(CROSS)size -t $@ + +.c.o: + @echo " CC " $< + @$(CC) $(CFLAGS) -c $< -o $@ + diff --git a/link.ld b/link.ld new file mode 100644 index 0000000..582fb5f --- /dev/null +++ b/link.ld @@ -0,0 +1,15 @@ +SECTIONS { + . = 0x0000; + .text : { + * (.text); + . = ALIGN(8); + * (.rodata); + } + . = ALIGN(8); + .data : { + * (.data); + . = ALIGN(8); + * (.bss); + } +} + 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 + +#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 + +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 + +#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 + +#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; +} + diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..43d4134 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,24 @@ +DEBUG := #-DDEBUG + +LIB430COREDIR = .. + +TEST_CSRC = test.c +TEST_OUT = $(patsubst %.c,%.o,$(TEST_CSRC)) + +all: $(LIB430COREDIR)/lib430core.a $(TEST_OUT) + +$(LIB430COREDIR)/lib430core.a: + @$(MAKE) -C .. + +.c.o: + @echo "Testing" $< "..." + @msp430-elf32-gcc -T../link.ld $< -o tmp.elf -nostdlib -lgcc -lc + @msp430-elf32-objcopy -Obinary tmp.elf tmp.bin + @echo "#define TESTBIN \\" > test.h + @od -t x1 tmp.bin | awk '{for (i=2; i<=NF; i++) printf "0x" $$i ", "}' >> test.h + @printf "\n#define TESTSIZE %u \n" $$(msp430-elf32-objdump tmp.elf -Dj .text | grep -E "^\s+[0-9a-fA-F]+:" | wc -l) >> test.h + @echo >> test.h + @gcc -Os -ggdb -g3 -Wall -W -pedantic $(DEBUG) -I../src -o tmp \ + core_test.c -L$(LIB430COREDIR) -l430core + @./tmp > log + @rm log tmp.elf tmp.bin tmp test.h diff --git a/tests/core_test.c b/tests/core_test.c new file mode 100644 index 0000000..08e2650 --- /dev/null +++ b/tests/core_test.c @@ -0,0 +1,52 @@ +#include "core.h" +#include "test.h" + +#include + +//#define DEBUG + +#ifdef DEBUG +static void dump_state(msp430_t *state) +{ + puts("MSP430 dump state:"); + printf("R0/PC: 0x%04x R1/SP: 0x%04x R2/SR: 0x%04x R3: 0x%04x\n", + state->reg[0], state->reg[1], state->reg[2], state->reg[3]); + printf("R4: 0x%04x R5: 0x%04x R6: 0x%04x R7: 0x%04x\n", + state->reg[4], state->reg[5], state->reg[6], state->reg[7]); + printf("R8: 0x%04x R9: 0x%04x R10: 0x%04x R11: 0x%04x\n", + state->reg[8], state->reg[9], state->reg[10], state->reg[11]); + printf("R12: 0x%04x R13: 0x%04x R14: 0x%04x R15: 0x%04x\n\n", + state->reg[12], state->reg[13], state->reg[14], state->reg[15]); +} +#endif // DEBUG + +static uint8_t mem[0x10000] = { + TESTBIN +}; + +int main() +{ + msp430_t state; + + msp430_init_state(&state, mem); + +#ifdef DEBUG + dump_state(&state); +#endif // DEBUG + int r; + do { + r = msp430_do_cycle(&state); + if (r < 0) { + printf("Failed to execute near PC=0x%04x!\n", state.reg[0]); + return 1; + //break; + } + +#ifdef DEBUG + dump_state(&state); +#endif // DEBUG + } while (r != 1); + + return 0; +} + diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 0000000..8eb344a --- /dev/null +++ b/tests/test.c @@ -0,0 +1,8 @@ +int main() +{ + volatile int *mem = (int *)0x200; + *mem = 24; + for (int i = 0; i < 8; ++i) + *mem += 2; + return *mem; +}