semihost server example program
Dependencies: SWD mbed USBLocalFileSystem BaseDAP USBDAP
LPCXpresso LPC11U68 | LPCXpresso LPC1549 | FRDM-KL46Z | EA LPC4088 QSB app-board | LPC1768 app-board | LPC810 | LPC1114FN28 | |
---|---|---|---|---|---|---|---|
server | server | server | server | server | client | client | |
SWDIO | D12 | D12 | D12 | p25 | p21 | p4(P0_2) | p12 |
SWCLK | D10 | D10 | D10 | p26 | p22 | p3(P0_3) | p3 |
nRESET *option | D6 | D6 | D6 | p34 | p30 | p1(P0_5) | p23 |
GND | GND | GND | GND | p1 | p1 | p7 | p22 |
3.3V | P3V3 | P3V3 | P3V3 | p44 | p40 | p6 | p21 |
flash write | SW2(P0_1) | SW3(P1_9) | SW1 | p14 joystick center | p14 joystick center |
client example:
Import programlpc810-semihost_helloworld
semihost client example program
Revision 1:eb30547ba84d, committed 2013-09-02
- Comitter:
- va009039
- Date:
- Mon Sep 02 17:33:08 2013 +0000
- Parent:
- 0:27d35fa263b5
- Child:
- 2:32e9437348ad
- Commit message:
- add semihost
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Semihost.cpp Mon Sep 02 17:33:08 2013 +0000 @@ -0,0 +1,246 @@ +// Semihost.cpp 2013/9/3 +#include "Semihost.h" +#include "mydebug.h" + +Semihost::Semihost(Target2* target, Serial* usbpc) : _target(target),_pc(usbpc) +{ + _dirpath = "/local"; +} + +void Semihost::mount(const char* dirpath) +{ + _dirpath = (char*)dirpath; +} + +int Semihost::poll() +{ + if (_target->getStatus() != TARGET_HALTED) { + return 0; + } + uint32_t pc = _target->pc; + if (pc & 1) { + return 0; + } + if (rd<uint16_t>(pc) != 0xbeab) { // BKPT #171 + return 0; + } + _target->r0 = exec(_target->r0, _target->r1); + _target->pc = pc + 3; // skip bkpt #171 + _target->resume(); + return 0; +} + +int Semihost::exec(uint32_t reason, uint32_t arg) +{ + int result = 0; + switch(reason) { + case 0x01: result = sys_open(arg); break; + case 0x02: result = sys_close(arg); break; + case 0x03: result = sys_writec(arg); break; + case 0x04: result = sys_write0(arg); break; + case 0x05: result = sys_write(arg); break; + case 0x06: result = sys_read(arg); break; + case 0x07: result = sys_readc(arg); break; + case 0x09: result = sys_istty(arg); break; + case 0x0a: result = sys_fseek(arg); break; + case 0x0b: result = sys_ensure(arg); break; + case 0x0c: result = sys_flen(arg); break; + case 0x0e: result = sys_remove(arg); break; + case 0x0f: result = sys_rename(arg); break; + case 0x18: result = sys_exit(arg); break; + + case 0x100: result = usr_xffind(arg); break; + case 0x101: result = usr_uid(arg); break; + case 0x102: result = usr_reset(arg); break; + case 0x103: result = usr_vbus(arg); break; + case 0x104: result = usr_powerdown(arg); break; + case 0x105: result = usr_disabledebug(arg); break; + + default: + _pc->printf("[semihost]error reason=%08x arg=%08x\n", reason, arg); + result = -1; + } + return result; +} + +int Semihost::sys_open(uint32_t arg) // 0x01 +{ + char name[64]; + _build_name(name, sizeof(name), arg, arg+8); + const char* mode[] = {"r", "rb", "r+", "r+b", "w", "wb", "w+", "w+b", "a", "ab", "a+", "a+b"}; + uint32_t mode_index = rd<uint32_t>(arg+4); + FILE* fp = fopen(name, mode[mode_index]); + if (fp) { + return (uint32_t)fp; + } + _pc->printf("\n[semihost]file open error [%s]\n", name); + return -1; +} + +int Semihost::sys_close(uint32_t arg) // 0x02 +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + int r = fclose(fp); + if (r == 0) { + return 0; + } + return -1; +} + +int Semihost::sys_writec(uint32_t arg) // 0x03 +{ + uint32_t p = rd<uint32_t>(arg); + _pc->putc(rd<uint8_t>(p) & 0xff); + return 0; +} + +int Semihost::sys_write0(uint32_t arg) // 0x04 +{ + uint32_t p = rd<uint32_t>(arg); + while(1) { + uint8_t c = rd<uint8_t>(p++); + if (c == '\0') { + break; + } + _pc->putc(c & 0xff); + } + return 0; +} + +int Semihost::sys_write(uint32_t arg) // 0x05 +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + uint32_t p = rd<uint32_t>(arg+4); + int count = rd<uint32_t>(arg+8); + while(count > 0) { + uint8_t c = rd<uint8_t>(p++); + if (fputc(c, fp) == EOF) { + return count; + } + count--; + } + return 0; +} + +int Semihost::sys_read(uint32_t arg) // 0x06 +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + uint32_t p = rd<uint32_t>(arg+4); + int count = rd<uint32_t>(arg+8); + while(count > 0) { + int c = fgetc(fp); + if (c == EOF) { + return count; + } + wr<uint8_t>(p++, c); + count--; + } + return 0; +} + +int Semihost::sys_readc(uint32_t arg) // 0x07 +{ + return _pc->getc() & 0xff; +} + +int Semihost::sys_istty(uint32_t arg) // 0x09 +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + return 0; +} + +int Semihost::sys_fseek(uint32_t arg) // 0x0a +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + int offset = rd<uint32_t>(arg+4); + return fseek(fp, offset, SEEK_SET); +} + +int Semihost::sys_ensure(uint32_t arg) // 0x0b +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + return -1; +} + +int Semihost::sys_flen(uint32_t arg) // 0x0c +{ + FILE* fp = reinterpret_cast<FILE*>(rd<uint32_t>(arg)); + return ftell(fp); +} + +int Semihost::sys_remove(uint32_t arg) // 0x0e +{ + + char name[64]; + _build_name(name, sizeof(name), arg, arg+4); + return remove(name); +} + +int Semihost::sys_rename(uint32_t arg) // 0x0f +{ + char oldname[64]; + char newname[64]; + _build_name(oldname, sizeof(oldname), arg, arg+4); + _build_name(newname, sizeof(newname), arg+8, arg+12); + return rename(oldname, newname); +} + +int Semihost::sys_exit(uint32_t arg) // 0x18 +{ + _pc->printf("\n[semihost]EXIT!!!\n"); + return -1; +} + +void Semihost::_build_name(char* buf, int size, uint32_t arg1, uint32_t arg2) +{ + strcpy(buf, _dirpath); + uint32_t p = rd<uint32_t>(arg1); + int len = rd<uint32_t>(arg2); + int pos = strlen(buf); + if (buf[pos-1] != '/') { + buf[pos++] = '/'; + buf[pos] = '\0'; + } + for(int i = 0; i < len && pos < size-1; i++) { + buf[pos++] = rd<uint8_t>(p++); + } + buf[pos] = '\0'; +} + +int Semihost::usr_xffind(uint32_t arg) // 0x100 +{ + return -1; +} + +int Semihost::usr_uid(uint32_t arg) // 0x101 +{ + uint32_t uid = rd<uint32_t>(arg); + uint32_t len = rd<uint32_t>(arg+4); + const uint8_t mac[] = {0x00, 0x02, 0xf7, 0xf0, 0x00, 0x00}; + for(int i = 0; i < sizeof(mac) && i < len; i++) { + wr<uint8_t>(uid+i, mac[i]); + } + return 0; +} + +int Semihost::usr_reset(uint32_t arg) // 0x102 +{ + _target->Reset(); + _target->setup(); + return 0; +} + +int Semihost::usr_vbus(uint32_t arg) // 0x103 +{ + return -1; +} + +int Semihost::usr_powerdown(uint32_t arg) // 0x104 +{ + return -1; +} + +int Semihost::usr_disabledebug(uint32_t arg) // 0x105 +{ + return -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Semihost.h Mon Sep 02 17:33:08 2013 +0000 @@ -0,0 +1,62 @@ +// Semihost.h 2013/9/3 +#pragma once +#include "Target2.h" +#include "mydebug.h" + +class Semihost { +public: + Semihost(Target2* target, Serial* usbpc); + void mount(const char* dirpath); + int poll(); +private: + int exec(uint32_t reason, uint32_t arg); + + int sys_open(uint32_t arg); // 0x01 + int sys_close(uint32_t arg); // 0x02 + int sys_writec(uint32_t arg); // 0x03 + int sys_write0(uint32_t arg); // 0x04 + int sys_write(uint32_t arg); // 0x05 + int sys_read(uint32_t arg); // 0x06 + int sys_readc(uint32_t arg); // 0x07 + int sys_istty(uint32_t arg); // 0x09 + int sys_fseek(uint32_t arg); // 0x0a + int sys_ensure(uint32_t arg); // 0x0b + int sys_flen(uint32_t arg); // 0x0c + int sys_remove(uint32_t arg); // 0x0e + int sys_rename(uint32_t arg); // 0x0f + int sys_exit(uint32_t arg); // 0x18 + + int usr_xffind(uint32_t arg); // 0x100 + int usr_uid(uint32_t arg); // 0x101 + int usr_reset(uint32_t arg); // 0x102 + int usr_vbus(uint32_t arg); // 0x103 + int usr_powerdown(uint32_t arg); // 0x104 + int usr_disabledebug(uint32_t arg);// 0x105 + + void _build_name(char* buf, int size, uint32_t arg1, uint32_t arg2); + + template<typename T> + void wr(uint32_t addr, T data) { + TEST_ASSERT(addr <= 0x10001fff); + uint8_t buf[sizeof(T)]; + *reinterpret_cast<T*>(buf) = data; + for(int i = 0; i < sizeof(T); i++) { + _target->writeMemory8(addr+i, buf[i]); + } + } + + template<typename T> + T rd(uint32_t addr) { + TEST_ASSERT(addr <= 0x10001fff); + uint8_t buf[sizeof(T)]; + for(int i = 0; i < sizeof(T); i++) { + buf[i] = _target->readMemory8(addr+i); + } + return *reinterpret_cast<T*>(buf); + } + +protected: + Target2* _target; + Serial* _pc; + char* _dirpath; +};
--- a/Target2.cpp Sun Sep 01 08:25:28 2013 +0000 +++ b/Target2.cpp Mon Sep 02 17:33:08 2013 +0000 @@ -1,4 +1,4 @@ -// Target2.cpp 2013/9/1 +// Target2.cpp 2013/9/2 #include "Target2.h" #include "mydebug.h" @@ -160,6 +160,29 @@ } } +uint8_t Target2::readMemory8(uint32_t addr) +{ + _setaddr8(addr); + + uint32_t data32; + uint8_t ack = _swd.Transfer(AP_DRW_R, &data32); // dummy read + TEST_ASSERT(ack == SWD_OK); + + ack = _swd.Transfer(DP_RDBUFF, &data32); + TEST_ASSERT(ack == SWD_OK); + return (data32 >> ((addr & 0x03) << 3)) & 0xff; +} + +void Target2::writeMemory8(uint32_t addr, uint8_t data) +{ + _setaddr8(addr); + + uint32_t data32 = data; + data32 <<= ((addr & 0x03) << 3); + uint8_t ack = _swd.Transfer(AP_DRW_W, &data32); + TEST_ASSERT(ack == SWD_OK); +} + void Target2::_setaddr(uint32_t addr) { uint32_t ctl = CSW_VALUE|CSW_SIZE32; @@ -177,6 +200,23 @@ TEST_ASSERT(ack == SWD_OK); } +void Target2::_setaddr8(uint32_t addr) +{ + uint32_t ctl = CSW_VALUE|CSW_SIZE8; + TEST_ASSERT(ctl == 0x23000050); + uint8_t ack = _swd.Transfer(AP_CSW, &ctl); + TEST_ASSERT(ack == SWD_OK); + + ack = _swd.Transfer(DP_RDBUFF, NULL); + TEST_ASSERT(ack == SWD_OK); + + ack = _swd.Transfer(AP_TAR, &addr); + TEST_ASSERT(ack == SWD_OK); + + ack = _swd.Transfer(DP_RDBUFF, NULL); + TEST_ASSERT(ack == SWD_OK); +} + void Target2::Abort() { uint32_t data = 0x1e; @@ -212,6 +252,11 @@ writeMemory(DHCSR, 0xa05f0001); } +void Target2::step() +{ + writeMemory(DHCSR, 0xa05f0005); +} + uint32_t CoreReg::read() { _target->writeMemory(DCRSR, _reg);
--- a/Target2.h Sun Sep 01 08:25:28 2013 +0000 +++ b/Target2.h Mon Sep 02 17:33:08 2013 +0000 @@ -1,4 +1,4 @@ -// Target2.h 2013/9/1 +// Target2.h 2013/9/2 #pragma once #include "mbed.h" #include "SWD.h" @@ -39,8 +39,11 @@ void readMemory(uint32_t addr, uint32_t* data, int count); void writeMemory(uint32_t addr, uint32_t data); void writeMemory(uint32_t addr, uint32_t* data, int count); + uint8_t readMemory8(uint32_t addr); + void writeMemory8(uint32_t addr, uint8_t data); void halt(); void resume(); + void step(); void Abort(); void Reset(); int getStatus(); @@ -64,6 +67,7 @@ CoreReg xpsr; private: void _setaddr(uint32_t addr); + void _setaddr8(uint32_t addr); protected: SWD _swd; Serial* _pc;
--- a/main.cpp Sun Sep 01 08:25:28 2013 +0000 +++ b/main.cpp Mon Sep 02 17:33:08 2013 +0000 @@ -1,8 +1,8 @@ -// main.cpp 2013/9/1 +// main.cpp 2013/9/3 #if 1 -#include "mbed.h" #include "Target2.h" #include "Flash.h" +#include "Semihost.h" LocalFileSystem local("local"); Serial pc(USBTX, USBRX); @@ -11,7 +11,9 @@ void Terminal(Target2* target) { target->setup(); - bool halt = false; + Semihost semihost(target, &pc); + semihost.mount("/local"); + pc.printf("*** dumb-terminal ***\n\n"); while(1) { if (target_uart.readable()) { @@ -21,10 +23,7 @@ int c = pc.getc(); target_uart.putc(c); } - if (!halt && target->getStatus() == TARGET_HALTED) { - pc.printf("\n*** BKPT at pc=%08x sp=%08x\n", target->pc.read(), target->sp.read()); - halt = true; - } + semihost.poll(); } }
--- a/tests/mytest.h Sun Sep 01 08:25:28 2013 +0000 +++ b/tests/mytest.h Mon Sep 02 17:33:08 2013 +0000 @@ -76,5 +76,7 @@ #define RUN_ALL_TESTS(A) reg::inst()->run_all_tests(#A) #define ASSERT_TRUE(A) if(A){}else{debug("\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#ifndef DBG #define DBG(FMT, ...) do{debug("[%s:%d]"FMT"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);}while(0); +#endif #define TEST_PRINT(FMT, ...) do{debug("[TEST: %d]"FMT"\r\n", __LINE__, ##__VA_ARGS__);}while(0);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_Semihost.cpp Mon Sep 02 17:33:08 2013 +0000 @@ -0,0 +1,111 @@ +// test_Semihost.cpp 2013/9/3 +#if 0 +#include "Semihost.h" +#include "Flash.h" +#include "mytest.h" + +LocalFileSystem local("local"); +Serial pc(USBTX, USBRX); +Target2 target(p21,p22,p17,&pc); // SWDIO(dp12),SWCLK(dp3),nReset(dp23) +Serial target_uart(p9,p10); // RXD(dp15),TXD(dp16) + +Semihost* sh; + +TEST(Target2,setup) { + ASSERT_TRUE(target.setup()); + target.halt(); + target.wait_status(TARGET_HALTED); +} + +#define RAM 0x10000000 + +TEST(Target2,readMemory8_1) { + target.writeMemory(RAM, 0x12345678); + ASSERT_TRUE(0x12345678 == target.readMemory(RAM)); + + ASSERT_TRUE(0x78 == target.readMemory8(RAM)); + ASSERT_TRUE(0x56 == target.readMemory8(RAM+1)); + ASSERT_TRUE(0x34 == target.readMemory8(RAM+2)); + ASSERT_TRUE(0x12 == target.readMemory8(RAM+3)); +} + +TEST(Target2,writeMemory8_1) { + target.writeMemory(RAM, 0xfefefefe); + ASSERT_TRUE(0xfefefefe == target.readMemory(RAM)); + + target.writeMemory8(RAM, 0x78); + ASSERT_TRUE(0xfefefe78 == target.readMemory(RAM)); + + target.writeMemory8(RAM+1, 0x56); + ASSERT_TRUE(0xfefe5678 == target.readMemory(RAM)); + + target.writeMemory8(RAM+2, 0x34); + ASSERT_TRUE(0xfe345678 == target.readMemory(RAM)); + + target.writeMemory8(RAM+3, 0x12); + ASSERT_TRUE(0x12345678 == target.readMemory(RAM)); +} + +#if 1 +TEST(Flash1,flash1) { + Flash flash(&target, &pc); + bool r = flash.eraseAll(); + ASSERT_TRUE(r); + r = flash.write("/local/SEMIHOST.LPC"); + ASSERT_TRUE(r); +} +#endif + +#if 0 +TEST(Semihost1,local1) { + FILE* fp = fopen("/local/test2.txt", "w"); + if (fp) { + fprintf(fp, "hello world test2.txt\n"); + fclose(fp); + } + ASSERT_TRUE(fp); + + fp = fopen("/local/TEST3.TXT", "w"); + if (fp) { + fprintf(fp, "hello world TEXT3.TXT \n"); + fclose(fp); + } + ASSERT_TRUE(fp); + + fp = fopen("/local/MBED.HTM", "r"); + if (fp) { + fclose(fp); + } + ASSERT_TRUE(fp); +} +#endif + +TEST(Semihost1,poll) { + target.Reset(); + target.setup(); + sh = new Semihost(&target, &pc); + sh->mount("/local"); + Timer t; + t.reset(); + t.start(); + while(t.read_ms() < 1000*15) { + if (target_uart.readable()) { + pc.putc(target_uart.getc()); + } + if (sh->poll()) { + break; + } + } +} + +int main() { + pc.baud(921600); + DBG("%s", __FILE__); + + RUN_ALL_TESTS(); + exit(0); +} +#endif + + +