diff --git a/.gitignore b/.gitignore index 567609b..242c142 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ build/ +dat/ diff --git a/src/main.c b/src/main.c index 9561d8f..b468e31 100644 --- a/src/main.c +++ b/src/main.c @@ -9,10 +9,20 @@ #include "tap.h" #include "msp430dbg.h" -void printbuf(const uint8_t* buf, size_t size) { - for (size_t i = 0; i < size; ++i) - printf("%02x%c", buf[i], i % 16 == 15 ? '\n' : ' '); -} +static uint16_t DATA_text[0x24] = { + 0xc232,0x43c2,0x0000,0x4031,0x02fe,0x40f2,0x00ff,0x002a,0x40b2,0x5a10,0x0120, + 0x43d2,0x0000,0xd232,0xd032,0x0018,0x3ffd,0xc3d2,0x0002,0xd3d2,0x0000,0xe3d2, + 0x0029,0x4130,0x1300,0x1300,0x1300,0x1300,0x1300,0x1300,0x12b0,0xf822,0x1300, + 0x1300,0x1300,0x3fdc +}; +static uint16_t DATA_vectors[0x10] = { + 0xf830,0xf830,0xf832,0xf834,0xf836,0xf830,0xf830,0xf830, + 0xf838,0xf83a,0xf83c,0xf842,0xf830,0xf830,0xf844,0xf846 +}; + +// 2k/8k flash, 256b RAM +static uint16_t dumpmem_ram[256>>1]; +static uint16_t dumpmem_flash[8192>>1]; int main() { gpio_init(PINOUT_SBW_TCK); @@ -83,5 +93,63 @@ int main() { uint32_t initv = msp430_device_get(200e3); printf("init -> %08lx\n", initv); + /*msp430_memory_read_block(0x0f00, 16>>1, dumpmem_ram); + printf("info dump:\n"); + for (size_t i = 0; i < ( 16>>1); i += 4) { + printf("%04zx: %04x %04x %04x %04x\n", + 0x0f00+(i<<1), dumpmem_ram[i+0], dumpmem_ram[i+1], + dumpmem_ram[i+2], dumpmem_ram[i+3] + ); + } + + msp430_memory_read_block(0x0200, 256>>1, dumpmem_ram); + + printf("RAM dump:\n"); + for (size_t i = 0; i < (256>>1); i += 4) { + printf("%04zx: %04x %04x %04x %04x\n", + 0x0200+(i<<1), dumpmem_ram[i+0], dumpmem_ram[i+1], + dumpmem_ram[i+2], dumpmem_ram[i+3] + ); + } + + msp430_memory_read_block(0xe000, 8192>>1, dumpmem_flash); + + printf("flash dump:\n"); + for (size_t i = 0; i < (8192>>1); i += 4) { + printf("%04zx: %04x %04x %04x %04x\n", + 0xe000+(i<<1), dumpmem_flash[i+0], dumpmem_flash[i+1], + dumpmem_flash[i+2], dumpmem_flash[i+3] + ); + }*/ + + /*printf("flashing text...\n"); + for (size_t i = 0; i < 0x24; ++i) { + printf("%zu : %04x\n", DATA_text[i]); + msp430_flash_write(0xf800 + (i*2), 1, &DATA_text[i]); + } + printf("flashing vectors...\n"); + for (size_t i = 0; i < 0x10; ++i) { + msp430_flash_write(0xffe0 + (i*2), 1, &DATA_vectors[i]); + }*/ + + /*printf("dumping for check...\n"); + msp430_memory_read_block(0xf800, 0x0800>>1, dumpmem_flash); + + printf("flash dump:\n"); + for (size_t i = 0; i < (2048>>1); i += 4) { + printf("%04zx: %04x %04x %04x %04x\n", + 0xf800+(i<<1), dumpmem_flash[i+0], dumpmem_flash[i+1], + dumpmem_flash[i+2], dumpmem_flash[i+3] + ); + }*/ + + /*msp430_memory_write8(0x0024, 0x00); // P2IE =0x00 (no irq) + msp430_memory_write8(0x002e, 0x00); // P2SEL=0x00 (gpio) + msp430_memory_write8(0x0042, 0x00); // P2SEL2=0 (gpio) + msp430_memory_write8(0x002a, 0xff); // P2DIR=0xff (all out) + msp430_memory_write8(0x0029, 0x01); // P2OUT=0x01 (P2.0 hi)*/ + + msp430_device_release(0xfffe/*0xf800*/); + return 0; } diff --git a/src/msp430dbg.c b/src/msp430dbg.c index 74950ec..71b4f2c 100644 --- a/src/msp430dbg.c +++ b/src/msp430dbg.c @@ -274,7 +274,8 @@ uint32_t msp430_device_get(float freq) { if (jtagid != MSP430_JTAG_TAP_ID) return 0<<24; if (msp430_check_fuse_blown()) return 1<<24; - sbw_set_freq(false, freq); // TODO: store freq? for programming stuff (needs different baudrate for tclk) + //sbw_set_freq(false, freq); // TODO: store freq? for programming stuff (needs different baudrate for tclk) + sbw_set_freq(true, 350e3); sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); uint16_t dr = sbw_tap_shift_dr(0x2401); // JTAG mode, read @@ -301,5 +302,200 @@ uint32_t msp430_device_get(float freq) { return ((uint32_t)jtagid << 24) | devid; } +// TODO +void msp430_flash_write(uint16_t startaddr, uint16_t num, const uint16_t* src) { + msp430_cpu_halt(); + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2408); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x0128); // FCTL1 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa540); // enable flash write + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x012a); // FCTL2 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa540); // MCLK source, DIV=1 + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x012c); // FCTL3 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa540); // unlock + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + + //sbw_set_freq(true, 350e3); + + for (uint16_t i = 0, addr = startaddr; i < num; ++i, addr += 2) { + sbw_tap_shift_dr(0x2408); + + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(addr); + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(src[i]); + + sbw_set_tclk(); + sbw_clr_tclk(); + + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2409); + + sbw_tclk_burst(35*4); + printf("%04x gets %04x\n", addr, src[i]); + } + + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2408); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x0128); // FCTL1 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa500); // disable flash write + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x012c); // FCTL3 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa550); // set lock + sbw_set_tclk(); + + msp430_cpu_release(); +} +void msp430_flash_erase_seg(uint16_t startaddr, bool is_infosegA) { + (void)is_infosegA; + + msp430_cpu_halt(); + + sbw_clr_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2408); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x0128); // FCTL1 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa502); // enable flash erase, single segment + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x012a); // FCTL2 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa540); // MCLK source, DIV=1 + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x012c); // FCTL3 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa500); // unlock + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(startaddr); + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0x55aa); + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2409); + + sbw_tclk_burst(4820); + + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2408); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x0128); // FCTL1 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa500); // lock flash + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_addr_16bit); + sbw_tap_shift_dr(0x012c); // FCTL3 + sbw_tap_shift_ir(msp430_ir_data_to_addr); + sbw_tap_shift_dr(0xa510); // set lock + sbw_set_tclk(); + + msp430_cpu_release(); +} +void msp430_flash_erase_mass(bool withinfomem) { + uint16_t addr = withinfomem ? 0x1002 : 0xfffe; + uint16_t mode = withinfomem ? 0xa506 : 0xa504; + + (void)addr; (void)mode; // nah, not yet +} + +// mwhahahah + +// TODO +/*uint16_t msp430_read_jmb(void) { + return 0; +} +void msp430_write_jmb(uint16_t v) { + +}*/ + +uint16_t msp430_cpureg_read(short regid) { + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x3401); + + sbw_tap_shift_ir(msp430_ir_data_16bit); + sbw_tap_shift_dr((regid & 0xf) << 8 | 0x4082); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_data_capture); + sbw_set_tclk(); + sbw_tap_shift_ir(msp430_ir_data_16bit); + sbw_tap_shift_dr(0x00fe); + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_data_capture); + sbw_set_tclk(); + sbw_clr_tclk(); + sbw_set_tclk(); + uint16_t reg = sbw_tap_read_dr(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2401); + sbw_set_tclk(); + + return reg; +} +void msp430_cpureg_write(short regid, uint16_t value) { + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x3401); + + sbw_tap_shift_ir(msp430_ir_data_16bit); + sbw_tap_shift_dr((regid & 0xf) | 0x4030); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_data_capture); + sbw_set_tclk(); + sbw_tap_shift_ir(msp430_ir_data_16bit); + sbw_tap_shift_dr(value); + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_data_capture); + sbw_set_tclk(); + sbw_tap_shift_ir(msp430_ir_data_16bit); + sbw_tap_shift_dr(0x3ffd); + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_data_capture); + sbw_set_tclk(); + + sbw_clr_tclk(); + sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit); + sbw_tap_shift_dr(0x2401); + sbw_set_tclk(); +} diff --git a/src/msp430dbg.h b/src/msp430dbg.h index 3231084..e6bdb9f 100644 --- a/src/msp430dbg.h +++ b/src/msp430dbg.h @@ -5,43 +5,103 @@ #include #include +// also seen: 8D 91 95 99 #define MSP430_JTAG_TAP_ID 0x89 enum msp430_ir { - // lsb-first transfer - // DR: msb-first transfer... - msp430_ir_addr_16bit = 0x83, - msp430_ir_addr_capture = 0x84, + //!all these // EMEX == EEM + msp430_ir_emex_data_exchange = 0x09, + msp430_ir_emex_read_trigger = 0x0a, // unused? / unknown + msp430_ir_emex_read_control = 0x0b, + msp430_ir_emex_write_control = 0x0c, + msp430_ir_emex_data_exchange32 = 0x0d, // 430X/Xv2-only - msp430_ir_data_to_addr = 0x85, - msp430_ir_data_16bit = 0x41, - msp430_ir_data_quick = 0x43, + // overlaps with EMEX! + msp430_ir_bp_cntl_16bit = 0x09, // unused? / unknown // == data_exchange + msp430_ir_bp_cntl_capture = 0x0a, // unused? / unknown + msp430_ir_bp1_16bit = 0x0b, // unused? / unknown + msp430_ir_bp1_capture = 0x0c, // unused? / unknown + msp430_ir_bp2_16bit = 0x0d, // unused? / unknown + msp430_ir_bp2_capture = 0x0e, // unused? / unknown - msp430_ir_ctrl_sig_16bit = 0x13, - msp430_ir_ctrl_sig_capture = 0x14, // 0010 1000 <=> 0x28 - msp430_ir_ctrl_sig_release = 0x15, + msp430_ir_ctrl_sig_high_byte = 0x11, + msp430_ir_ctrl_sig_low_byte = 0x12, + msp430_ir_ctrl_sig_16bit = 0x13, + msp430_ir_ctrl_sig_capture = 0x14, + msp430_ir_ctrl_sig_release = 0x15, + msp430_ir_coreip_id = 0x17, // pointer to more data on non-0x89 JTAG IDs? + msp430_ir_jstate_id = 0x18, // JState is Xv2 stuff so eh // NOTE: 64-bit DRshift! - msp430_ir_data_psa = 0x44, - msp430_ir_shift_out_psa = 0x46, + msp430_ir_flash_16bit_update = 0x19, // "disable flash test mode"? + msp430_ir_flash_capture = 0x1a, // unused? / unknown + msp430_ir_flash_16bit_in = 0x1b, // unused? / unknown + msp430_ir_flash_update = 0x1c, // unused? / unknown + // sesel = 0x0080, tmr = 0x0800 + msp430_ir_cntrl = 0x21, // unused? / unknown msp430_ir_fuse_prepare_blow = 0x22, msp430_ir_fuse_ex_blow = 0x24, + msp430_ir_config_fuses = 0x29, // get fuse state? uses 8-bit DRshift! + + msp43_ir_test_reg = 0x2a, // Xv2-only + msp43_ir_test_v3_reg = 0x2f, + // TODO: what is LPM? something with power? related to LPMx.5 + + // "embedded signal processing cell" control + msp430_ir_dual_8bit = 0x31, + msp430_ir_dual_capture = 0x32, + msp430_ir_select_main = 0x33, + msp430_ir_select_esp = 0x34, + + msp430_ir_tclk_toggle_inst = 0x39, // unused? / unknown + msp430_ir_tclk_0_inst = 0x3a, // unused? / unknown + msp430_ir_tclk_1_inst = 0x3b, // unused? / unknown + + msp430_ir_data_16bit = 0x41, + msp430_ir_data_capture = 0x42,//! // reads from data bus? + msp430_ir_data_quick = 0x43, + msp430_ir_data_psa = 0x44, + msp430_ir_data_16bit_opt = 0x45, // unused? / unknown + msp430_ir_shift_out_psa = 0x46, + msp430_ir_dta = 0x47, // unused? / unknown + + msp430_ir_accept_key = 0x59, // unused? / unknown msp430_ir_jmb_exchange = 0x61, + msp430_ir_tdo_event = 0x64, // unused? / unknown + msp430_ir_tdo_event_ctl = 0x65, // unused? / unknown + + msp430_ir_addr_high_byte = 0x81, + msp430_ir_addr_low_byte = 0x82, + msp430_ir_addr_16bit = 0x83, + msp430_ir_addr_capture = 0x84, + msp430_ir_data_to_addr = 0x85, + msp430_ir_capture_cpu_reg = 0x86, // unused? / unknown + msp430_ir_device_id = 0x87, // "device ip pointer" for non-0x89 JTAG IDs + + msp430_ir_jmb_write_32bit_mode = 0x88,//! + msp430_ir_bypass = 0xff }; enum msp430_ctrl { msp430_ctrl_RnW = 1<< 0, + msp430_ctrl_cpu_halt = 1<< 1, + msp430_ctrl_intr_req = 1<< 2, msp430_ctrl_halt_jtag = 1<< 3, + msp430_ctrl_byte = 1<< 4, + msp430_ctrl_cpu_off = 1<< 5, + msp430_ctrl_mclk_on = 1<< 6, msp430_ctrl_instr_load = 1<< 7, + msp430_ctrl_tmode = 1<< 8, msp430_ctrl_tce0 = 1<< 9, msp430_ctrl_tce1 = 1<<10, msp430_ctrl_por = 1<<11, msp430_release_lbyte0 = 1<<12, msp430_tagfuncsat = 1<<13, msp430_switch = 1<<14, + msp430_ctrl_stop_sel = 1<<15, }; bool msp430_check_fuse_blown(void); @@ -57,18 +117,60 @@ uint16_t msp430_memory_read16(uint16_t addr); uint8_t msp430_memory_read8 (uint16_t addr); void msp430_memory_write16(uint16_t addr, uint16_t value); void msp430_memory_write8 (uint16_t addr, uint8_t value); -void msp430_memory_read_block(uint16_t srcaddr, uint16_t num, uint16_t* dest); -void msp430_memory_write_block(uint16_t dstaddr, uint16_t num, const uint16_t* src); +void msp430_memory_read_block(uint16_t srcaddr, uint16_t numwords, uint16_t* dest); +void msp430_memory_write_block(uint16_t dstaddr, uint16_t numwords, const uint16_t* src); bool msp430_memory_verify(uint16_t startaddr, uint16_t length, const uint16_t* copy); #define msp430_memory_read(bits, addr) (msp430_memory_read##bits (addr)) #define msp430_memory_write(bit, a, v) (msp430_memory_write##bit (a, v)) void msp430_flash_write(uint16_t startaddr, uint16_t num, const uint16_t* src);// + +// TODO: erase routine needs to be redone void msp430_flash_erase_seg(uint16_t startaddr, bool is_infosegA);// void msp430_flash_erase_mass(bool withinfomem); // false: only main flash uint32_t msp430_device_get(float freq); +// TODO: from non-slau320aj src +uint16_t msp430_read_jmb(void); +void msp430_write_jmb(uint16_t v); + +uint16_t msp430_cpureg_read(short regno); +void msp430_cpureg_write(short regno, uint16_t value); + +// TODO: +// 430X and Xv2 versions of the above routines +// +// EnableLpmx5 +// DisableLpmx5 +// what do these do? it's something about power mode, it's disabled when +// starting JTAG, and reenabled when releasing JTAG +// only MSP430Xv2, though, so we're not going to care for now. (I don't +// have such chips, only an MSP430G2212 and a G2452) +// uses test_reg and test_reg_3V +// +// jstate_read +// what is this for? (Xv2-only -> let's not care for this either now) +// uses 64-bit DRshift! +// -> PollJStateReg, HilCommand, SingleStepJState +// +// eem_write_control +// used in save & restore context stuff / jtag start & release +// eem_read_control +// used where write_control is used, but also "wait for eem" and single-step +// eem_data_exchange +// used in a lot of places: write_control places, single-step, wait for storage, "eemdataexchange", execute funclet +// +// what is EEM? what is its sub-command stuff? +// +// wait for EEM +// JTAG release with context restore +// JTAG start with context save +// single-step +// wait for storage(?) +// execute funclet +// get dco frequency // annoying + #endif diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..89c6812 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,6 @@ +trace.log +*.bin +*.h +*.elf +*.map +*.o diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..d62cb45 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,20 @@ + +AS := msp430-gcc +CC := msp430-gcc +LD := msp430-gcc +OBJCOPY := msp430-objcopy + +all: test.bin + +test.S.o: test.S + $(AS) -c -o "$@" "$<" + +test.elf test.elf.map: test.S.o link.ld + $(LD) -o "$@" "$<" -T link.ld -Wl,-Map="$@.map" -nostdlib -nostartfiles + +test.bin: test.elf + $(OBJCOPY) -O binary "$<" "$@" + +clean: + @$(RM) -v test.bin test.bin.h test.elf test.elf.map test.S.o + diff --git a/test/bin2h.py b/test/bin2h.py new file mode 100755 index 0000000..2943041 --- /dev/null +++ b/test/bin2h.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 + +import argparse +import os, re, sys, struct +import textwrap +import traceback + + +def sanitize_name(name): + # replace special characters with underscores + name = re.sub('[^a-zA-Z0-9_]', '_', name) + # clean up + name = name.strip('_') + + # not needed: 'DATA_' prefix + #if name[0] in "0123456789": name = '_' + name + + return name + + +def main(): + parser = argparse.ArgumentParser( + description="Convert data files into byte arrays in a C header") + + parser.add_argument('input', nargs='*', action='append', + help="Input data file to convert to a header file. If " + +"none are specified, data is read from standard input.") + parser.add_argument('--output', type=str, default=None, + help="Output header file path, standard output if none specified") + + args = parser.parse_args() + + #print(repr(args), file=sys.stderr) + + inputfiles = args.input[0] + datafiles = {} + + if len(inputfiles) == 0: + # need to read from stdio + datafiles['data'] = sys.stdin.buffer.read() + else: + for path in inputfiles: + # cannot use os.access, POSIX-only + if not os.path.exists(path) or os.path.isdir(path): + print("ERROR: input path '%s' does not exist, or is not a file" % path) + sys.exit(1) + + # get base name of the path (no folder names, no extension) + name = os.path.splitext(os.path.split(path)[1])[0] + # make it usable for C code names + name = sanitize_name(name) + + # now read the data + data = None + try: + with open(path, 'rb') as f: + data = f.read() + except IOError: + print("ERROR: input file '%s' not readable" % path) + traceback.print_exc() + sys.exit(1) + + data = struct.unpack('<'+('H'*(len(data)//2)), data) + + # add it to the list + datafiles[name] = data + + #print(repr(datafiles), file=sys.stderr) + + outname = "hardcoded_data" + if args.output is not None: + outname = os.path.splitext(os.path.split(args.output)[1])[0] + outname = sanitize_name(outname) + + # generate the C source code: one uint8_t array for each data file + # variable name is "DATA_" + # (width=84 is the equivalent of 16 bytes/line) + headersrc = '\n\n'.join( + "static uint16_t DATA_%s[%d] = {\n%s\n};" % (name, len(data), \ + textwrap.fill(','.join("0x%04x" % b for b in data), width=81, + initial_indent=" ", subsequent_indent=" ") + ) for name, data in datafiles.items() + ) + + # a C header needs include guards + headersrc = """ +#ifndef AUTOGEN_{0}_H_ +#define AUTOGEN_{0}_H_ + +{1} + +#endif +""".format(outname.upper(), headersrc) + + #print(headersrc, file=sys.stderr) + + if args.output is None: + # no output specified -> output to stdout + sys.stdout.write(headersrc) + else: + try: + with open(args.output, 'w') as f: + f.write(headersrc) + except IOError: + print("ERROR: output file '%s' not writable" % args.output) + traceback.print_exc() + sys.exit(1) + + +if __name__ == '__main__': + main() + diff --git a/test/link.ld b/test/link.ld new file mode 100644 index 0000000..e183db6 --- /dev/null +++ b/test/link.ld @@ -0,0 +1,167 @@ +OUTPUT_FORMAT("elf32-msp430","elf32-msp430","elf32-msp430") +OUTPUT_ARCH(msp:14) +ENTRY(_start) + +MEMORY +{ + data (rwx) : ORIGIN = 0x0200, LENGTH = 0x100 + text (rx) : ORIGIN = 0xf800, LENGTH = 0x800 - 0x20 + vectors (rw) : ORIGIN = 0xffe0, LENGTH = 0x20 +} + +SECTIONS { + /* Internal text space. */ + .text : + { + . = ALIGN(2); + *(SORT_NONE(.init)) + *(SORT_NONE(.init0)) /* Start here after reset. */ + *(SORT_NONE(.init1)) + *(SORT_NONE(.init2)) /* Copy data loop */ + *(SORT_NONE(.init3)) + *(SORT_NONE(.init4)) /* Clear bss */ + *(SORT_NONE(.init5)) + *(SORT_NONE(.init6)) /* C++ constructors. */ + *(SORT_NONE(.init7)) + *(SORT_NONE(.init8)) + *(SORT_NONE(.init9)) /* Call main(). */ + __ctors_start = . ; + *(.ctors) + __ctors_end = . ; + __dtors_start = . ; + *(.dtors) + __dtors_end = . ; + . = ALIGN(2); + *(.lower.text.* .lower.text) + . = ALIGN(2); + *(.text) + . = ALIGN(2); + *(.text.*) + . = ALIGN(2); + *(.text:*) + . = ALIGN(2); + *(SORT_NONE(.fini9)) + *(SORT_NONE(.fini8)) + *(SORT_NONE(.fini7)) + *(SORT_NONE(.fini6)) /* C++ destructors. */ + *(SORT_NONE(.fini5)) + *(SORT_NONE(.fini4)) + *(SORT_NONE(.fini3)) + *(SORT_NONE(.fini2)) + *(SORT_NONE(.fini1)) + *(SORT_NONE(.fini0)) /* Infinite loop after program termination. */ + *(SORT_NONE(.fini)) + _etext = .; + } > text =0xff + + .rodata : + { + . = ALIGN(2); + *(.lower.rodata.* .lower.rodata) + . = ALIGN(2); + *(.plt) + *(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*) + *(.rodata1) + *(.eh_frame_hdr) + KEEP (*(.eh_frame)) + KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + LONG(0); /* Sentinel. */ + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from from the + crtend.o file until after the sorted ctors. The .ctor section + from the crtend file contains the end of ctors marker and it + must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } > text =0xff + + .vectors : + { + PROVIDE (__vectors_start = .) ; + *(.vectors*) + _vectors_end = . ; + } > vectors =0xff + + .data : + { + PROVIDE (__data_start = .) ; + PROVIDE (__datastart = .) ; + . = ALIGN(2); + KEEP (*(.jcr)) + *(.data.rel.ro.local) *(.data.rel.ro*) + *(.dynamic) + . = ALIGN(2); + *(.lower.data.* .lower.data) + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + KEEP (*(.gnu.linkonce.d.*personality*)) + *(.data1) + *(.got.plt) *(.got) + . = ALIGN(2); + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(2); + _edata = . ; + } > data AT> text + .bss SIZEOF(.data) + ADDR(.data) : + { + . = ALIGN(2); + PROVIDE (__bss_start = .) ; + *(.lower.bss.* .lower.bss) + . = ALIGN(2); + *(.bss) + *(COMMON) + PROVIDE (__bss_end = .) ; + _end = . ; + } > data + .noinit SIZEOF(.bss) + ADDR(.bss) : + { + PROVIDE (__noinit_start = .) ; + *(.noinit) + *(COMMON) + PROVIDE (__noinit_end = .) ; + _end = . ; + } > data + + + .fill : + { + FILL(0xffffffff); + . = ORIGIN(vectors); + } > text + + .MP430.attributes 0 : + { + KEEP (*(.MSP430.attributes)) + KEEP (*(.gnu.attributes)) + KEEP (*(__TI_build_attributes)) + } + PROVIDE (__stack = 0x2fe) ; + PROVIDE (__data_start_rom = _etext) ; + PROVIDE (__data_end_rom = _etext + SIZEOF (.data)) ; + PROVIDE (__noinit_start_rom = _etext + SIZEOF (.data)) ; + PROVIDE (__noinit_end_rom = _etext + SIZEOF (.data) + SIZEOF (.noinit)) ; + PROVIDE (__subdevice_has_heap = 0) ; +} diff --git a/test/test.S b/test/test.S new file mode 100644 index 0000000..b01c4a8 --- /dev/null +++ b/test/test.S @@ -0,0 +1,144 @@ +; vim: set ft=gas: + +#define CPUOFF (1<<4) +#define GIE (1<<3) + +#define IE1 0x0000 +#define IFG1 0x0002 + +#define WDTCTL 0x0120 + +#define USICTL0 0x0078 +#define USICTL1 0x0079 +#define USICKCTL 0x007a +#define USICNT 0x007b +#define USISR 0x007c + +#define BCSCTL3 0x0053 +#define BCSCTL2 0x0058 +#define BCSCTL1 0x0057 +#define DCOCTL 0x0056 + +#define P2SEL2 0x0042 +#define P2REN 0x002f +#define P2SEL 0x002e +#define P2IE 0x002d +#define P2IES 0x002c +#define P2IFG 0x002b +#define P2DIR 0x002a +#define P2OUT 0x0029 +#define P2IN 0x0028 + +#define P1SEL2 0x0041 +#define P1REN 0x0027 +#define P1SEL 0x0026 +#define P1IE 0x0024 +#define P1IES 0x0024 +#define P1IFG 0x0023 +#define P1DIR 0x0022 +#define P1OUT 0x0021 +#define P1IN 0x0020 + +.section ".text.startup._start", "ax", %progbits + +.global _start +_start: + dint + + mov.b #0, &IE1 + + mov.w #__stack, sp + + mov.b #0, &P2IE + mov.b #0, &P2SEL + mov.b #0, &P2SEL2 + mov.b #0xff, &P2DIR + + ; TODO: configure wdt + mov.w #((0x5a<<8)|(1<<4)), &WDTCTL + + mov.b #1, &IE1 + + eint + +lockup: + + ; enter LPM0 for power save stuff + bis #(GIE|CPUOFF), sr + + jmp lockup + + +.section ".text.callback", "ax", %progbits + +wdt_callback: + bic.b #1, &IFG1 + bis.b #1, &IE1 + + xor.b #1, &P2OUT + + ret + + +.section ".vectors", "ax", %progbits + +_VECTORS: + + .2byte ISR_unk ; ffe0 + .2byte ISR_unk ; ffe2 + .2byte ISR_port1 ; ffe4 + .2byte ISR_port2 ; ffe6 + .2byte ISR_USI ; ffe8 + .2byte ISR_unk ; ffea ; (ADC10, not on this chip) + .2byte ISR_unk ; ffec + .2byte ISR_unk ; ffee + .2byte ISR_timer0 ; fff0 + .2byte ISR_timer1 ; fff2 + .2byte ISR_wdt ; fff4 + .2byte ISR_cmpA ; fff6 + .2byte ISR_unk ; fff8 + .2byte ISR_unk ; fffa + .2byte ISR_NMI ; fffc + .2byte ISR_RST ; fffe + +.section ".text.isr.unk", "ax", %progbits +ISR_unk: + reti + +.section ".text.isr.port1", "ax", %progbits +ISR_port1: + reti + +.section ".text.isr.port2", "ax", %progbits +ISR_port2: + reti + +.section ".text.isr.usi", "ax", %progbits +ISR_USI: + reti + +.section ".text.isr.timer0", "ax", %progbits +ISR_timer0: + reti + +.section ".text.isr.timer1", "ax", %progbits +ISR_timer1: + reti + +.section ".text.isr.wdt", "ax", %progbits +ISR_wdt: + call #wdt_callback + reti + +.section ".text.isr.cmpA", "ax", %progbits +ISR_cmpA: + reti + +.section ".text.isr.nmi", "ax", %progbits +ISR_NMI: + reti + +.section ".text.isr.rst", "ax", %progbits +ISR_RST: + jmp _start +