semihost server example program

Dependencies:   SWD mbed USBLocalFileSystem BaseDAP USBDAP

/media/uploads/va009039/kl46z-lpc800-360x480.jpg

LPCXpresso
LPC11U68
LPCXpresso
LPC1549
FRDM-KL46ZEA LPC4088 QSB
app-board
LPC1768
app-board
LPC810LPC1114FN28
serverserverserverserverserverclientclient
SWDIOD12D12D12p25p21p4(P0_2)p12
SWCLKD10D10D10p26p22p3(P0_3)p3
nRESET
*option
D6D6D6p34p30p1(P0_5)p23
GNDGNDGNDGNDp1p1p7p22
3.3VP3V3P3V3P3V3p44p40p6p21
flash writeSW2(P0_1)SW3(P1_9)SW1p14
joystick
center
p14
joystick
center

client example:

Import programlpc810-semihost_helloworld

semihost client example program

Files at this revision

API Documentation at this revision

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

Semihost.cpp Show annotated file Show diff for this revision Revisions of this file
Semihost.h Show annotated file Show diff for this revision Revisions of this file
Target2.cpp Show annotated file Show diff for this revision Revisions of this file
Target2.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
tests/mytest.h Show annotated file Show diff for this revision Revisions of this file
tests/test_Semihost.cpp Show annotated file Show diff for this revision Revisions of this file
--- /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
+
+
+