flashing, test program

This commit is contained in:
Triss 2021-10-03 17:39:32 +02:00
parent ad046185d3
commit d4e34bb742
9 changed files with 835 additions and 19 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
build/ build/
dat/

View File

@ -9,10 +9,20 @@
#include "tap.h" #include "tap.h"
#include "msp430dbg.h" #include "msp430dbg.h"
void printbuf(const uint8_t* buf, size_t size) { static uint16_t DATA_text[0x24] = {
for (size_t i = 0; i < size; ++i) 0xc232,0x43c2,0x0000,0x4031,0x02fe,0x40f2,0x00ff,0x002a,0x40b2,0x5a10,0x0120,
printf("%02x%c", buf[i], i % 16 == 15 ? '\n' : ' '); 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() { int main() {
gpio_init(PINOUT_SBW_TCK); gpio_init(PINOUT_SBW_TCK);
@ -83,5 +93,63 @@ int main() {
uint32_t initv = msp430_device_get(200e3); uint32_t initv = msp430_device_get(200e3);
printf("init -> %08lx\n", initv); 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; return 0;
} }

View File

@ -274,7 +274,8 @@ uint32_t msp430_device_get(float freq) {
if (jtagid != MSP430_JTAG_TAP_ID) return 0<<24; if (jtagid != MSP430_JTAG_TAP_ID) return 0<<24;
if (msp430_check_fuse_blown()) return 1<<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); sbw_tap_shift_ir(msp430_ir_ctrl_sig_16bit);
uint16_t dr = sbw_tap_shift_dr(0x2401); // JTAG mode, read 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; 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();
}

View File

@ -5,43 +5,103 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
// also seen: 8D 91 95 99
#define MSP430_JTAG_TAP_ID 0x89 #define MSP430_JTAG_TAP_ID 0x89
enum msp430_ir { enum msp430_ir {
// lsb-first transfer //!all these // EMEX == EEM
// DR: msb-first transfer... msp430_ir_emex_data_exchange = 0x09,
msp430_ir_addr_16bit = 0x83, msp430_ir_emex_read_trigger = 0x0a, // unused? / unknown
msp430_ir_addr_capture = 0x84, 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, // overlaps with EMEX!
msp430_ir_data_16bit = 0x41, msp430_ir_bp_cntl_16bit = 0x09, // unused? / unknown // == data_exchange
msp430_ir_data_quick = 0x43, 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_high_byte = 0x11,
msp430_ir_ctrl_sig_low_byte = 0x12,
msp430_ir_ctrl_sig_16bit = 0x13, msp430_ir_ctrl_sig_16bit = 0x13,
msp430_ir_ctrl_sig_capture = 0x14, // 0010 1000 <=> 0x28 msp430_ir_ctrl_sig_capture = 0x14,
msp430_ir_ctrl_sig_release = 0x15, 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_flash_16bit_update = 0x19, // "disable flash test mode"?
msp430_ir_shift_out_psa = 0x46, 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_prepare_blow = 0x22,
msp430_ir_fuse_ex_blow = 0x24, 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_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 msp430_ir_bypass = 0xff
}; };
enum msp430_ctrl { enum msp430_ctrl {
msp430_ctrl_RnW = 1<< 0, 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_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_instr_load = 1<< 7,
msp430_ctrl_tmode = 1<< 8,
msp430_ctrl_tce0 = 1<< 9, msp430_ctrl_tce0 = 1<< 9,
msp430_ctrl_tce1 = 1<<10, msp430_ctrl_tce1 = 1<<10,
msp430_ctrl_por = 1<<11, msp430_ctrl_por = 1<<11,
msp430_release_lbyte0 = 1<<12, msp430_release_lbyte0 = 1<<12,
msp430_tagfuncsat = 1<<13, msp430_tagfuncsat = 1<<13,
msp430_switch = 1<<14, msp430_switch = 1<<14,
msp430_ctrl_stop_sel = 1<<15,
}; };
bool msp430_check_fuse_blown(void); 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); uint8_t msp430_memory_read8 (uint16_t addr);
void msp430_memory_write16(uint16_t addr, uint16_t value); void msp430_memory_write16(uint16_t addr, uint16_t value);
void msp430_memory_write8 (uint16_t addr, uint8_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_read_block(uint16_t srcaddr, uint16_t numwords, uint16_t* dest);
void msp430_memory_write_block(uint16_t dstaddr, uint16_t num, const uint16_t* src); 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); 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_read(bits, addr) (msp430_memory_read##bits (addr))
#define msp430_memory_write(bit, a, v) (msp430_memory_write##bit (a, v)) #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);// 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_seg(uint16_t startaddr, bool is_infosegA);//
void msp430_flash_erase_mass(bool withinfomem); // false: only main flash void msp430_flash_erase_mass(bool withinfomem); // false: only main flash
uint32_t msp430_device_get(float freq); 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 #endif

6
test/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
trace.log
*.bin
*.h
*.elf
*.map
*.o

20
test/Makefile Normal file
View File

@ -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

112
test/bin2h.py Executable file
View File

@ -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_<datafile>"
# (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()

167
test/link.ld Normal file
View File

@ -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) ;
}

144
test/test.S Normal file
View File

@ -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