IPS(Interpreter for Process Structures) for mbed
Dependencies: ConfigFile FATFileSystem mbed
IPS port from linux/unix version.
mbed_blinky.ips
0 VAR led1 " LED1 " DigitalOut led1 ! : main ANFANG 1 JA? 1 led1 @ write 200 wait_ms 0 led1 @ write 200 wait_ms DANN/NOCHMAL ; main
- ips-02.tgz - ips for linux/unix
- ipsdoc.zip - document
- https://bitbucket.org/va009039/ips/
Revision 1:e74530ad6b9e, committed 2015-05-13
- Comitter:
- va009039
- Date:
- Wed May 13 18:39:01 2015 +0900
- Parent:
- 0:25fe9b2fe195
- Child:
- 2:908338b1151a
- Commit message:
- add L152RE.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BaseIPS.cpp Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,743 @@ +// BaseIPS.cpp 2015/5/6 +#include "mbed.h" +#include "BaseIPS.h" + +#include <math.h> +#define Round(x) ( (x>=0) ? (int)(x+0.5) : (int)(x-0.5) ) + +BaseIPS::BaseIPS() { + PS = 0xfff8; + RS = 0x4f8; + depth=0; + idle=0; + input_ptr = 512; + cycle = 0; + inputfile = NULL; +} + +u16 BaseIPS::peek(u16 a) { + return peekB(a) | peekB(a + 1)<<8; +} + +void BaseIPS::poke(u16 a, u16 w) { + pokeB(a, w & 0xff); + pokeB(a + 1, w>>8); +} + +u32 BaseIPS::peek32(u16 a) { + return peekB(a) | peekB(a + 1)<<8 | peekB(a + 2)<<16 | peekB(a + 3)<<24; +} + + +void BaseIPS::push_ps(u16 w) { + PS -= 2; + poke(PS, w); +} + +u16 BaseIPS::pull_ps() { + PS += 2; + return peek(PS - 2); +} + +void BaseIPS::push_rs(u16 w) { + RS -= 2; + poke(RS, w); +} + +u16 BaseIPS::pull_rs() { + RS += 2; + return peek(RS - 2); +} + +void BaseIPS::c_rumpelstilzchen(void) { // 0 +} + +void BaseIPS::c_defex(void) { // 1 + push_rs(PPC); + PPC = HP; + depth++; +} + +void BaseIPS::c_consex(void) { // 2 + push_ps(peek(HP)); +} + +void BaseIPS::c_varex(void) { // 3 + push_ps(HP); +} + +void BaseIPS::c_retex(void) { // 4 + depth--; + PPC = pull_rs(); +} + +void BaseIPS::c_get(void) { // 5 + poke(PS, peek(peek(PS))); +} + +void BaseIPS::c_getB(void) { // 6 + poke(PS, peekB(peek(PS))); +} + +void BaseIPS::c_put(void) { // 7 + u16 a = pull_ps(); + u16 v = pull_ps(); + if (peek(a) != v) idle=0; + poke(a, v); +} + +void BaseIPS::c_putB(void) { // 8 + u16 a = pull_ps(); + u16 v = pull_ps(); + if (peekB(a) != v) idle=0; + pokeB(a, v); + idle=0; +} + +void BaseIPS::c_1bliteral(void) { // 9 + push_ps(peekB(PPC)); + PPC++; +} + +void BaseIPS::c_2bliteral(void) { // 10 + push_ps(peek(PPC)); + PPC += 2; +} + +void BaseIPS::c_bronz(void) { // 11 + if ((pull_ps() & 1) == 0) PPC=peek(PPC); + else PPC += 2; +} + +void BaseIPS::c_jump(void) { // 12 + PPC = peek(PPC); +} + +void BaseIPS::c_weg(void) { // 13 + PS += 2; +} + +void BaseIPS::c_pweg(void) { // 14 + PS += 4; +} + +void BaseIPS::c_plus(void) { // 15 + s16 v = pull_ps(); + poke(PS, peek(PS) + v); +} + +void BaseIPS::c_minus(void) { // 16 + s16 v = pull_ps(); + poke(PS, peek(PS) - v); +} + +void BaseIPS::c_dup(void) { // 17 + push_ps(peek(PS)); +} + +void BaseIPS::c_pdup(void) { // 18 + push_ps(peek(PS + 2)); + push_ps(peek(PS + 2)); +} + +void BaseIPS::c_vert(void) { // 19 + s16 h=peek(PS); + poke(PS, peek(PS + 2)); + poke(PS + 2, h); +} + +void BaseIPS::c_zwo(void) { // 20 + push_ps(peek(PS+2)); +} + +void BaseIPS::c_rdu(void) { // 21 + s16 h=peek(PS); + poke(PS, peek(PS+2)); + poke(PS+2, peek(PS+4)); + poke(PS+4, h); +} + +void BaseIPS::c_rdo(void) { // 22 + s16 h=peek(PS+4); + poke(PS+4, peek(PS+2)); + poke(PS+2, peek(PS)); + poke(PS, h); +} + +void BaseIPS::c_index(void) { // 23 + push_ps(peek(RS)); +} + +void BaseIPS::c_s_to_r(void) { // 24 + push_rs(pull_ps()); +} + +void BaseIPS::c_r_to_s(void) { // 25 + push_ps(pull_rs()); +} + +void BaseIPS::c_eqz(void) { // 26 + poke(PS,(peek(PS)==0)); +} + +void BaseIPS::c_gz(void) { // 27 + poke(PS,((s16)peek(PS)>0)); +} + +void BaseIPS::c_lz(void) { // 28 + poke(PS,((s16)peek(PS)<0)); +} + +void BaseIPS::c_geu(void) { // 29 + u16 a,b; + b=pull_ps(); + a=peek(PS); + poke(PS,a>=b); +} + +void BaseIPS::c_f_vergl(void) { // 30 + int t; + u16 n,a1,a2; + n=pull_ps(); + a2=pull_ps(); + a1=peek(PS); + t=1; + do { + int b; + b=(s16)peekB(a1++)-(s16)peekB(a2++); + if (b>0) t=2; + else if (b<0) t=0; + n=(n-1)&0xff; + } while (n); + poke(PS,t); +} + +void BaseIPS::c_nicht(void) { // 31 + poke(PS, 0xffff^peek(PS)); +} + +void BaseIPS::c_und(void) { // 32 + u16 v = pull_ps(); + poke(PS, v & peek(PS)); +} + +void BaseIPS::c_oder(void) { // 33 + u16 v = pull_ps(); + poke(PS, v | peek(PS)); +} + +void BaseIPS::c_exo(void) { // 34 + u16 v = pull_ps(); + poke(PS, v ^ peek(PS)); +} + +void BaseIPS::c_bit(void) { // 35 + poke(PS, 1<<peek(PS)); +} + +void BaseIPS::c_cbit(void) { // 36 + int a = pull_ps(); + int b = (pull_ps())&0x07; + pokeB(a, peekB(a)&~(1<<b) ); +} + +void BaseIPS::c_sbit(void) { // 37 + int a,b; + a=pull_ps(); + b=(pull_ps())&0x07; + pokeB(a, peekB(a)|(1<<b) ); +} + +void BaseIPS::c_tbit(void) { // 38 + int a,b; + a=pull_ps(); + b=(peek(PS))&0x07; + if (peekB(a)&(1<<b)) poke(PS,1); + else poke(PS,0); +} + +void BaseIPS::loop_sharedcode(int i) { + int l; + l=(s16)peek(RS); + if (i<=l) { + push_rs(i); + PPC=peek(PPC); + } else { + pull_rs(); + PPC+=2; + } +} + +void BaseIPS::c_jeex(void) { // 39 + PPC=peek(PPC); + push_rs(pull_ps()); + loop_sharedcode((s16)pull_ps()); +} + +void BaseIPS::c_loopex(void) { // 40 + loop_sharedcode((s16)(pull_rs()+1)); +} + +void BaseIPS::c_plusloopex(void) { // 41 + int i; + i=(s16)(pull_rs()); + loop_sharedcode(i+(s16)pull_rs()); +} + +void BaseIPS::c_fieldtrans(void) { // 42 + /* note: cannot call memcpy() here, because memcpy()'s behaviour is not defined when source and destination areas overlap */ + /* memmove() cannot be used either, because its behaviour for overlap is different from what IPS expects */ + int n,d,s,b; + n=pull_ps(); + d=pull_ps(); + s=pull_ps(); + do { + b=peekB(s++); + pokeB(d++,b); + n=(n-1)&0xff; + } while (n); + if (d<=0x400) redraw=1; + idle=0; +} + +void BaseIPS::c_pmul(void) { // 43 + u32 c = pull_ps() * pull_ps(); + push_ps((s16)(c&0xffff)); + push_ps(c>>16); +} + +void BaseIPS::c_pdiv(void) { // 44 + u32 q,n; + u16 d,nh,nl,r; + d=pull_ps(); + nh=pull_ps(); + nl=pull_ps(); + n=(nh<<16)+nl; + if (d==0) { q=0xffff; r=0; } + else { + q=n/d; + r=n%d; + if (q>=0x10000) { q=0xffff; r=0; } + } + push_ps(q); + push_ps(r); +} + +void BaseIPS::c_tue(void) { // 45 + HP = pull_ps(); +} + +void BaseIPS::c_polyname(void) { // 46 + u32 x,p,d; + d=pull_ps(); + x=pull_ps(); + p=pull_ps(); + x= x | (p&0xff00) | ((p&0xff)<<16); + p = d ^ x ^ (x>>1) ^ (x>>2) ^ (x>>7); + x = x ^ ((p&0xff)<<24); + x >>= 7; + push_ps( (x&0xff00) | ((x>>16)&0xff) ); + push_ps( (x&0xff) ); +} + +void BaseIPS::c_scode(void) { // 47 + int i; + u32 nd; + int offs=peek(a_Os); + i=peek(a_NDptr); + nd=peek32(i); + i=peek(a_P3); + while (i) { + i+=offs; + if ( ( (peek32(i) ^ nd) & 0xffffff3f) ==0) { + push_ps(i+6); + return; + } + i=peek(i+4); + } + push_ps(0); +} + +void BaseIPS::c_cscan(void) { // 48 + int a; + int pi,pe; + int comment=0; + pi=peek(a_PI); + pe=peek(a_PE); + + a=pull_ps(); + if (a==1) { + while (pi<=pe) { + if (comment) { + if (peekB(pi)==')') comment=0; + } else { + if (peekB(pi)=='(') comment=1; + else if (peekB(pi)!=' ') { + poke(a_PI,pi); + push_ps(1); + return; + } + } + pi++; + } + push_ps(0); + poke(a_P2,1); + return; + } else { + while (pi<=pe) { + if (peekB(pi)==' ') { + break; + } + pi++; + } + poke(a_PI,pi); + push_ps(0); + } +} + +void BaseIPS::c_chs(void) { // 49 + poke(PS,-(s16)peek(PS)); +} + +void BaseIPS::c_cyc2(void) { // 50 + u32 ch,a,crcc; + int i; + + ch=pull_ps(); + a=pull_ps(); + crcc=(a>>8)|((a&0xff)<<8); + + ch<<=8; + for (i=0;i<=7;i++) { + //int test; + //test=(ch^crcc)&0x8000; + crcc<<=1; + ch<<=1; + if ((ch^crcc)&0x10000) crcc^=0x1021; + } + + push_ps( ((crcc&0xff)<<8) | ((crcc>>8)&0xff) ); +} + +void BaseIPS::c_close(void) { // 51 + if (inputfile) { + file_close(inputfile); + inputfile = NULL; + } +} + +void BaseIPS::c_open(void) { // 52 + if (inputfile) { + file_close(inputfile); + } + int namelen = pull_ps(); + int namestart = pull_ps(); + char filename[256]; + if (namelen > sizeof(filename)-1) { + namelen = sizeof(filename) - 1; + } + for(int i = 0; i < namelen; i++) { + filename[i] = peekB(namestart + i); + } + filename[namelen] = '\0'; + inputfile = file_open(filename); + push_ps(inputfile != NULL ? 1 : 0); +} + +void BaseIPS::c_oscli(void) { // 53 + error("OSCLI not implemented!"); +} + +void BaseIPS::c_load(void) { // 54 + error("LOAD not implemented!"); +} + +void BaseIPS::c_save(void) { // 55 + int namelen = pull_ps(); + int namestart = pull_ps(); + int end = pull_ps(); + int start = pull_ps(); + + char filename[256]; + if (namelen > 255) namelen = 255; + for(int i = 0; i < namelen; i++) { + filename[i] = peekB(namestart + i); + } + filename[namelen] = 0; + + void* fh = file_open(filename, "wb"); + if (fh == NULL) { + push_ps(0); + return; + } + for(int i = start; i < end; i++) { + file_putc(peekB(i), fh); + } + file_close(fh); + push_ps(1); +} + +void BaseIPS::c_setkbptr(void) { // 56 + input_ptr = pull_ps() & 0x3ff; +} + +void BaseIPS::c_getPS(void) { // 57 + push_ps(PS); +} + +void BaseIPS::c_setPS(void) { // 58 + PS=pull_ps(); +} + +void BaseIPS::c_rp_code(void) { // 59 + double theta,x,y,r; + pull_ps(); + y=(s16)pull_ps(); + x=(s16)pull_ps(); + theta=((s16)pull_ps())/10430.38; /* convert to radians */ + theta+=atan2(y,x); + r=sqrt(x*x+y*y)*1.6468; + push_ps(Round(theta*10430.38)); + push_ps((int)(r+0.5)); + push_ps(0); +} + +void BaseIPS::c_tr_code(void) { // 60 + double theta,x,y,r; + pull_ps(); + y=(s16)pull_ps(); + x=(s16)pull_ps(); + theta=((s16)pull_ps())/10430.38; /* convert to radians */ + theta+=atan2(y,x); + r=sqrt(x*x+y*y)*1.6468; + push_ps(0); + push_ps(Round(r*cos(theta))); + push_ps(Round(r*sin(theta))); +} + +void BaseIPS::c_swap3(void) { // 61 + u16 h; + h=peek(PS+6); poke(PS+6,peek(PS)); poke(PS,h); + h=peek(PS+8); poke(PS+8,peek(PS+2)); poke(PS+2,h); + h=peek(PS+10); poke(PS+10,peek(PS+4)); poke(PS+4,h); +} + +void BaseIPS::c_defchar(void) { // 62 + error("DEFCHAR not implemented!\n"); +} + +void BaseIPS::c_pplus(void) { // 63 + u32 h=pull_ps(); + u32 b=(h<<16)+pull_ps(); + h=pull_ps(); + u32 a=(h<<16)+pull_ps(); + u32 c=a+b; + push_ps(c&0xffff); + push_ps(c>>16); +} + +void BaseIPS::c_pminus(void) { // 64 + u32 h = pull_ps(); + u32 b = (h<<16)+pull_ps(); + h = pull_ps(); + u32 a = (h<<16)+pull_ps(); + u32 c = a - b; + push_ps(c&0xffff); + push_ps(c>>16); +} + +void BaseIPS::c_sleepifidle(void) { // 80 +/* extension for IPS-Mu, i.e., the linux/unix version */ + if (idle) { + //do_sleep(); + //leaveloop=0; + } + idle=1; +} + +void BaseIPS::do_20ms(void) { + pokeB(UHR, peekB(UHR) + 2); // 20ms + if (peekB(UHR) == 100) { + pokeB(UHR, 0); + pokeB(UHR+1, peekB(UHR+1) + 1); + if (peekB(UHR+1) == 60) { + pokeB(UHR+1, 0); + pokeB(UHR+2, peekB(UHR+2) + 1); + if (peekB(UHR+2) == 60) { + pokeB(UHR+2, 0); + pokeB(UHR+3, peekB(UHR+3) + 1); + if (peekB(UHR+3) == 24) { + pokeB(UHR+3, 0); + poke(UHR+4, peek(UHR+4) + 1); + } + } + } + } + + const int sus[4]={SU0,SU1,SU2,SU3}; + for (int i = 0; i < 4; i++) { + int su=sus[i]; + if ((peekB(su)&1) == 0) { + if (peekB(su) != 0) { + pokeB(su, peekB(su) - 2); + } else { + if (peekB(su+1) != 0) { + pokeB(su, 98); + pokeB(su+1, peekB(su+1) - 1); + } else { + if (peekB(su+2) != 0) { + pokeB(su+1, 59); + pokeB(su+2, peekB(su+2) - 1); + } else { + if (peekB(su+3) != 0) { + pokeB(su+2, 255); + pokeB(su+3, peekB(su+3) - 1); + } else { + pokeB(su, 1); + } + } + } + } + } + } +} + +void BaseIPS::read_inputfile(void) { + for(int i = 0x200; i < 0x400; i++) { + pokeB(i, ' '); + } + + do { + int ch = file_getc(inputfile); + if (ch<1) { + if (input_ptr == peek(a_PI)) { + file_close(inputfile); + inputfile = NULL; + pokeB(LOADFLAG, 0); + input_ptr = 0x200; + } + break; + } + if (ch=='\r') { + /* ignore \r, we expect at least also a \n as end-of-line */ + } else if (ch=='\n') { + input_ptr=(input_ptr&0xffc0)+64; + } else { + pokeB(input_ptr++,ch); + } + } while (input_ptr<1024 && inputfile); /* 1024 = TVE */ + + if (input_ptr!=peek(a_PI)) { + pokeB(READYFLAG,1); + poke(a_PE,input_ptr-1); + idle=0; + } +} + +void BaseIPS::emulator() { + PPC = 0x0400; + input_ptr = peek(a_PI); + while(1) { + HP = peek(PPC); + PPC += 2; +exec: u16 CPC = peek(HP); + HP += 2; + trace(cycle++, PPC-2, HP-2, CPC, PS, RS); + switch(CPC) { + case 1: c_defex(); break; + case 2: c_consex(); break; + case 3: c_varex(); break; + case 4: c_retex(); break; + case 5: c_get(); break; + case 6: c_getB(); break; + case 7: c_put(); break; + case 8: c_putB(); break; + case 9: c_1bliteral(); break; + case 10: c_2bliteral(); break; + case 11: c_bronz(); break; + case 12: c_jump(); break; + case 13: c_weg(); break; + case 14: c_pweg(); break; + case 15: c_plus(); break; + case 16: c_minus(); break; + case 17: c_dup(); break; + case 18: c_pdup(); break; + case 19: c_vert(); break; + case 20: c_zwo(); break; + case 21: c_rdu(); break; + case 22: c_rdo(); break; + case 23: c_index(); break; + case 24: c_s_to_r(); break; + case 25: c_r_to_s(); break; + case 26: c_eqz(); break; + case 27: c_gz(); break; + case 28: c_lz(); break; + case 29: c_geu(); break; + case 30: c_f_vergl(); break; + case 31: c_nicht(); break; + case 32: c_und(); break; + case 33: c_oder(); break; + case 34: c_exo(); break; + case 35: c_bit(); break; + case 36: c_cbit(); break; + case 37: c_sbit(); break; + case 38: c_tbit(); break; + case 39: c_jeex(); break; + case 40: c_loopex(); break; + case 41: c_plusloopex(); break; + case 42: c_fieldtrans(); break; + case 43: c_pmul(); break; + case 44: c_pdiv(); break; + case 45: c_tue(); goto exec; + case 46: c_polyname(); break; + case 47: c_scode(); break; + case 48: c_cscan(); break; + case 49: c_chs(); break; + case 50: c_cyc2(); break; + case 51: c_close(); break; + case 52: c_open(); break; + case 53: c_oscli(); break; + case 54: c_load(); break; + case 55: c_save(); break; + case 56: c_setkbptr(); break; + case 57: c_getPS(); break; + case 58: c_setPS(); break; + case 59: c_rp_code(); break; + case 60: c_tr_code(); break; + case 61: c_swap3(); break; + case 62: c_defchar(); break; + case 63: c_pplus(); break; + case 64: c_pminus(); break; + case 80: c_sleepifidle(); break; + default: c_rumpelstilzchen(); break; + } + do_io(); + if (test_20ms()) { + do_20ms(); + } + if (inputfile) { + if (!(peekB(READYFLAG)&1) && (peekB(LOADFLAG)&1)) { + read_inputfile(); + } + } + } +} + +void BaseIPS::load_image(const u8* image, int size) { + for(int i = 0; i < size; i++) { + pokeB(i, *image++); + } +} + +void BaseIPS::command(const char* s) { + if (s) { + int cmd_len = strlen(s); + for(int i = 0; i < cmd_len; i++) { + pokeB(i + 64*8, *s++); + } + poke(a_PE, 0x200 + cmd_len); + pokeB(READYFLAG, 1); + } +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BaseIPS.h Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,134 @@ +// BaseIPS.h 2015/5/6 +#pragma once + +/* data types */ +typedef unsigned char u8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned long u32; +typedef unsigned char byte; + +/* some variables of IPS also need to be accessed by the emulator; here are their addresses: */ +#define READYFLAG 0x42e +#define LOADFLAG 0x43b +#define UHR 0x418 +#define SU0 0x41e +#define SU1 0x422 +#define SU2 0x426 +#define SU3 0x42a +#define a_PE 0x42f +#define a_PI 0x431 +#define a_P1 0x433 +#define a_P2 0x435 +#define a_P3 0x437 +#define a_NDptr 0x43e +#define a_Os 0x43c + +#define TVE 1023 + +class BaseIPS { +public: + BaseIPS(); + void emulator(); + void load_image(const u8* image, int size); + void command(const char* s); + +protected: + virtual u8 peekB(u16 a) = 0; + virtual void pokeB(u16 a, u8 b) = 0; + void poke(u16 a, u16 w); + u16 peek(u16 a); + virtual void do_io() = 0; + virtual bool test_20ms() { return false; } + virtual void* file_open(const char* filename, const char* mode = "rb") { return NULL; } + virtual int file_getc(void* handle) { return -1; } + virtual void file_putc(int c, void* handle) {} + virtual bool file_close(void* handle) { return false; } + virtual void trace(u32 cycle, u16 ppc, u16 hp, u16 cpc, u16 ps, u16 rs) {} + int input_ptr; + +private: + u32 peek32(u16 a); + u16 PPC, HP, PS, RS; + u32 cycle; + int depth; + int redraw; + int idle; + void push_ps(u16 w); + u16 pull_ps(); + void push_rs(u16 w); + u16 pull_rs(); + void* inputfile; + void do_20ms(); + void read_inputfile(void); + + void c_rumpelstilzchen(void); // 0 + void c_defex(void); // 1 + void c_consex(void); // 2 + void c_varex(void); // 3 + void c_retex(void); // 4 + void c_get(void); // 5 + void c_getB(void); // 6 + void c_put(void); // 7 + void c_putB(void); // 8 + void c_1bliteral(void); // 9 + void c_2bliteral(void); // 10 + void c_bronz(void); // 11 + void c_jump(void); // 12 + void c_weg(void); // 13 + void c_pweg(void); // 14 + void c_plus(void); // 15 + void c_minus(void); // 16 + void c_dup(void); // 17 + void c_pdup(void); // 18 + void c_vert(void); // 19 + void c_zwo(void); // 20 + void c_rdu(void); // 21 + void c_rdo(void); // 22 + void c_index(void); // 23 + void c_s_to_r(void); // 24 + void c_r_to_s(void); // 25 + void c_eqz(void); // 26 + void c_gz(void); // 27 + void c_lz(void); // 28 + void c_geu(void); // 29 + void c_f_vergl(void); // 30 + void c_nicht(void); // 31 + void c_und(void); // 32 + void c_oder(void); // 33 + void c_exo(void); // 34 + void c_bit(void); // 35 + void c_cbit(void); // 36 + void c_sbit(void); // 37 + void c_tbit(void); // 38 + void loop_sharedcode(int i); + void c_jeex(void); // 39 + void c_loopex(void); // 40 + void c_plusloopex(void); // 41 + void c_fieldtrans(void); // 42 + void c_pmul(void); // 43 + void c_pdiv(void); // 44 + void c_tue(void); // 45 + void c_polyname(void); // 46 + void c_scode(void); // 47 + void c_cscan(void); // 48 + void c_chs(void); // 49 + void c_cyc2(void); // 50 + void c_close(void); // 51 + void c_open(void); // 52 + void c_oscli(void); // 53 + void c_load(void); // 54 + void c_save(void); // 55 + void c_setkbptr(void); // 56 + void c_getPS(void); // 57 + void c_setPS(void); // 58 + void c_rp_code(void); // 59 + void c_tr_code(void); // 60 + void c_swap3(void); // 61 + void c_defchar(void); // 62 + void c_pplus(void); // 63 + void c_pminus(void); // 64 + void c_sleepifidle(void); // 80 +}; + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem/SDFileSystem.cpp Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,498 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* Introduction + * ------------ + * SD and MMC cards support a number of interfaces, but common to them all + * is one based on SPI. This is the one I'm implmenting because it means + * it is much more portable even though not so performant, and we already + * have the mbed SPI Interface! + * + * The main reference I'm using is Chapter 7, "SPI Mode" of: + * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf + * + * SPI Startup + * ----------- + * The SD card powers up in SD mode. The SPI interface mode is selected by + * asserting CS low and sending the reset command (CMD0). The card will + * respond with a (R1) response. + * + * CMD8 is optionally sent to determine the voltage range supported, and + * indirectly determine whether it is a version 1.x SD/non-SD card or + * version 2.x. I'll just ignore this for now. + * + * ACMD41 is repeatedly issued to initialise the card, until "in idle" + * (bit 0) of the R1 response goes to '0', indicating it is initialised. + * + * You should also indicate whether the host supports High Capicity cards, + * and check whether the card is high capacity - i'll also ignore this + * + * SPI Protocol + * ------------ + * The SD SPI protocol is based on transactions made up of 8-bit words, with + * the host starting every bus transaction by asserting the CS signal low. The + * card always responds to commands, data blocks and errors. + * + * The protocol supports a CRC, but by default it is off (except for the + * first reset CMD0, where the CRC can just be pre-calculated, and CMD8) + * I'll leave the CRC off I think! + * + * Standard capacity cards have variable data block sizes, whereas High + * Capacity cards fix the size of data block to 512 bytes. I'll therefore + * just always use the Standard Capacity cards with a block size of 512 bytes. + * This is set with CMD16. + * + * You can read and write single blocks (CMD17, CMD25) or multiple blocks + * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When + * the card gets a read command, it responds with a response token, and then + * a data token or an error. + * + * SPI Command Format + * ------------------ + * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC. + * + * +---------------+------------+------------+-----------+----------+--------------+ + * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 | + * +---------------+------------+------------+-----------+----------+--------------+ + * + * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95) + * + * All Application Specific commands shall be preceded with APP_CMD (CMD55). + * + * SPI Response Format + * ------------------- + * The main response format (R1) is a status byte (normally zero). Key flags: + * idle - 1 if the card is in an idle state/initialising + * cmd - 1 if an illegal command code was detected + * + * +-------------------------------------------------+ + * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle | + * +-------------------------------------------------+ + * + * R1b is the same, except it is followed by a busy signal (zeros) until + * the first non-zero byte when it is ready again. + * + * Data Response Token + * ------------------- + * Every data block written to the card is acknowledged by a byte + * response token + * + * +----------------------+ + * | xxx | 0 | status | 1 | + * +----------------------+ + * 010 - OK! + * 101 - CRC Error + * 110 - Write Error + * + * Single Block Read and Write + * --------------------------- + * + * Block transfers have a byte header, followed by the data, followed + * by a 16-bit CRC. In our case, the data will always be 512 bytes. + * + * +------+---------+---------+- - - -+---------+-----------+----------+ + * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] | + * +------+---------+---------+- - - -+---------+-----------+----------+ + */ +#include "SDFileSystem.h" +#include "mbed_debug.h" + +#define SD_COMMAND_TIMEOUT 5000 + +#define SD_DBG 0 + +SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) : + FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0) { + _cs = 1; + + // Set default to 100kHz for initialisation and 1MHz for data transfer + _init_sck = 100000; + _transfer_sck = 1000000; +} + +#define R1_IDLE_STATE (1 << 0) +#define R1_ERASE_RESET (1 << 1) +#define R1_ILLEGAL_COMMAND (1 << 2) +#define R1_COM_CRC_ERROR (1 << 3) +#define R1_ERASE_SEQUENCE_ERROR (1 << 4) +#define R1_ADDRESS_ERROR (1 << 5) +#define R1_PARAMETER_ERROR (1 << 6) + +// Types +// - v1.x Standard Capacity +// - v2.x Standard Capacity +// - v2.x High Capacity +// - Not recognised as an SD Card +#define SDCARD_FAIL 0 +#define SDCARD_V1 1 +#define SDCARD_V2 2 +#define SDCARD_V2HC 3 + +int SDFileSystem::initialise_card() { + // Set to SCK for initialisation, and clock card with cs = 1 + _spi.frequency(_init_sck); + _cs = 1; + for (int i = 0; i < 16; i++) { + _spi.write(0xFF); + } + + // send CMD0, should return with all zeros except IDLE STATE set (bit 0) + if (_cmd(0, 0) != R1_IDLE_STATE) { + debug("No disk, or could not put SD card in to SPI idle state\n"); + return SDCARD_FAIL; + } + + // send CMD8 to determine whther it is ver 2.x + int r = _cmd8(); + if (r == R1_IDLE_STATE) { + return initialise_card_v2(); + } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) { + return initialise_card_v1(); + } else { + debug("Not in idle state after sending CMD8 (not an SD card?)\n"); + return SDCARD_FAIL; + } +} + +int SDFileSystem::initialise_card_v1() { + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + _cmd(55, 0); + if (_cmd(41, 0) == 0) { + cdv = 512; + debug_if(SD_DBG, "\n\rInit: SEDCARD_V1\n\r"); + return SDCARD_V1; + } + } + + debug("Timeout waiting for v1.x card\n"); + return SDCARD_FAIL; +} + +int SDFileSystem::initialise_card_v2() { + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + wait_ms(50); + _cmd58(); + _cmd(55, 0); + if (_cmd(41, 0x40000000) == 0) { + _cmd58(); + debug_if(SD_DBG, "\n\rInit: SDCARD_V2\n\r"); + cdv = 1; + return SDCARD_V2; + } + } + + debug("Timeout waiting for v2.x card\n"); + return SDCARD_FAIL; +} + +int SDFileSystem::disk_initialize() { + _is_initialized = initialise_card(); + if (_is_initialized == 0) { + debug("Fail to initialize card\n"); + return 1; + } + debug_if(SD_DBG, "init card = %d\n", _is_initialized); + _sectors = _sd_sectors(); + + // Set block length to 512 (CMD16) + if (_cmd(16, 512) != 0) { + debug("Set 512-byte block timed out\n"); + return 1; + } + + // Set SCK for data transfer + _spi.frequency(_transfer_sck); + return 0; +} + +int SDFileSystem::disk_write(const uint8_t* buffer, uint64_t block_number, uint8_t count) { + if (!_is_initialized) { + return -1; + } + + for (uint64_t b = block_number; b < block_number + count; b++) { + // set write address for single block (CMD24) + if (_cmd(24, b * cdv) != 0) { + return 1; + } + + // send the data block + _write(buffer, 512); + buffer += 512; + } + + return 0; +} + +int SDFileSystem::disk_read(uint8_t* buffer, uint64_t block_number, uint8_t count) { + if (!_is_initialized) { + return -1; + } + + for (uint64_t b = block_number; b < block_number + count; b++) { + // set read address for single block (CMD17) + if (_cmd(17, b * cdv) != 0) { + return 1; + } + + // receive the data + _read(buffer, 512); + buffer += 512; + } + + return 0; +} + +int SDFileSystem::disk_status() { + // FATFileSystem::disk_status() returns 0 when initialized + if (_is_initialized) { + return 0; + } else { + return 1; + } +} + +int SDFileSystem::disk_sync() { return 0; } +uint64_t SDFileSystem::disk_sectors() { return _sectors; } + + +// PRIVATE FUNCTIONS +int SDFileSystem::_cmd(int cmd, int arg) { + _cs = 0; + + // send a command + _spi.write(0x40 | cmd); + _spi.write(arg >> 24); + _spi.write(arg >> 16); + _spi.write(arg >> 8); + _spi.write(arg >> 0); + _spi.write(0x95); + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = _spi.write(0xFF); + if (!(response & 0x80)) { + _cs = 1; + _spi.write(0xFF); + return response; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} +int SDFileSystem::_cmdx(int cmd, int arg) { + _cs = 0; + + // send a command + _spi.write(0x40 | cmd); + _spi.write(arg >> 24); + _spi.write(arg >> 16); + _spi.write(arg >> 8); + _spi.write(arg >> 0); + _spi.write(0x95); + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = _spi.write(0xFF); + if (!(response & 0x80)) { + return response; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} + + +int SDFileSystem::_cmd58() { + _cs = 0; + int arg = 0; + + // send a command + _spi.write(0x40 | 58); + _spi.write(arg >> 24); + _spi.write(arg >> 16); + _spi.write(arg >> 8); + _spi.write(arg >> 0); + _spi.write(0x95); + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = _spi.write(0xFF); + if (!(response & 0x80)) { + int ocr = _spi.write(0xFF) << 24; + ocr |= _spi.write(0xFF) << 16; + ocr |= _spi.write(0xFF) << 8; + ocr |= _spi.write(0xFF) << 0; + _cs = 1; + _spi.write(0xFF); + return response; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} + +int SDFileSystem::_cmd8() { + _cs = 0; + + // send a command + _spi.write(0x40 | 8); // CMD8 + _spi.write(0x00); // reserved + _spi.write(0x00); // reserved + _spi.write(0x01); // 3.3v + _spi.write(0xAA); // check pattern + _spi.write(0x87); // crc + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) { + char response[5]; + response[0] = _spi.write(0xFF); + if (!(response[0] & 0x80)) { + for (int j = 1; j < 5; j++) { + response[i] = _spi.write(0xFF); + } + _cs = 1; + _spi.write(0xFF); + return response[0]; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} + +int SDFileSystem::_read(uint8_t *buffer, uint32_t length) { + _cs = 0; + + // read until start byte (0xFF) + while (_spi.write(0xFF) != 0xFE); + + // read data + for (uint32_t i = 0; i < length; i++) { + buffer[i] = _spi.write(0xFF); + } + _spi.write(0xFF); // checksum + _spi.write(0xFF); + + _cs = 1; + _spi.write(0xFF); + return 0; +} + +int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) { + _cs = 0; + + // indicate start of block + _spi.write(0xFE); + + // write the data + for (uint32_t i = 0; i < length; i++) { + _spi.write(buffer[i]); + } + + // write the checksum + _spi.write(0xFF); + _spi.write(0xFF); + + // check the response token + if ((_spi.write(0xFF) & 0x1F) != 0x05) { + _cs = 1; + _spi.write(0xFF); + return 1; + } + + // wait for write to finish + while (_spi.write(0xFF) == 0); + + _cs = 1; + _spi.write(0xFF); + return 0; +} + +static uint32_t ext_bits(unsigned char *data, int msb, int lsb) { + uint32_t bits = 0; + uint32_t size = 1 + msb - lsb; + for (uint32_t i = 0; i < size; i++) { + uint32_t position = lsb + i; + uint32_t byte = 15 - (position >> 3); + uint32_t bit = position & 0x7; + uint32_t value = (data[byte] >> bit) & 1; + bits |= value << i; + } + return bits; +} + +uint64_t SDFileSystem::_sd_sectors() { + uint32_t c_size, c_size_mult, read_bl_len; + uint32_t block_len, mult, blocknr, capacity; + uint32_t hc_c_size; + uint64_t blocks; + + // CMD9, Response R2 (R1 byte + 16-byte block read) + if (_cmdx(9, 0) != 0) { + debug("Didn't get a response from the disk\n"); + return 0; + } + + uint8_t csd[16]; + if (_read(csd, 16) != 0) { + debug("Couldn't read csd response from disk\n"); + return 0; + } + + // csd_structure : csd[127:126] + // c_size : csd[73:62] + // c_size_mult : csd[49:47] + // read_bl_len : csd[83:80] - the *maximum* read block length + + int csd_structure = ext_bits(csd, 127, 126); + + switch (csd_structure) { + case 0: + cdv = 512; + c_size = ext_bits(csd, 73, 62); + c_size_mult = ext_bits(csd, 49, 47); + read_bl_len = ext_bits(csd, 83, 80); + + block_len = 1 << read_bl_len; + mult = 1 << (c_size_mult + 2); + blocknr = (c_size + 1) * mult; + capacity = blocknr * block_len; + blocks = capacity / 512; + debug_if(SD_DBG, "\n\rSDCard\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks); + break; + + case 1: + cdv = 1; + hc_c_size = ext_bits(csd, 63, 48); + blocks = (hc_c_size+1)*1024; + debug_if(SD_DBG, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks); + break; + + default: + debug("CSD struct unsupported\r\n"); + return 0; + }; + return blocks; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem/SDFileSystem.h Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,89 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef MBED_SDFILESYSTEM_H +#define MBED_SDFILESYSTEM_H + +#include "mbed.h" +#include "FATFileSystem.h" +#include <stdint.h> + +/** Access the filesystem on an SD Card using SPI + * + * @code + * #include "mbed.h" + * #include "SDFileSystem.h" + * + * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs + * + * int main() { + * FILE *fp = fopen("/sd/myfile.txt", "w"); + * fprintf(fp, "Hello World!\n"); + * fclose(fp); + * } + */ +class SDFileSystem : public FATFileSystem { +public: + + /** Create the File System for accessing an SD Card using SPI + * + * @param mosi SPI mosi pin connected to SD Card + * @param miso SPI miso pin conencted to SD Card + * @param sclk SPI sclk pin connected to SD Card + * @param cs DigitalOut pin used as SD Card chip select + * @param name The name used to access the virtual filesystem + */ + SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name); + virtual int disk_initialize(); + virtual int disk_status(); + virtual int disk_read(uint8_t* buffer, uint64_t block_number, uint8_t count); + virtual int disk_write(const uint8_t* buffer, uint64_t block_number, uint8_t count); + virtual int disk_sync(); + virtual uint64_t disk_sectors(); + +protected: + + int _cmd(int cmd, int arg); + int _cmdx(int cmd, int arg); + int _cmd8(); + int _cmd58(); + int initialise_card(); + int initialise_card_v1(); + int initialise_card_v2(); + + int _read(uint8_t * buffer, uint32_t length); + int _write(const uint8_t *buffer, uint32_t length); + uint64_t _sd_sectors(); + uint64_t _sectors; + + void set_init_sck(uint32_t sck) { _init_sck = sck; } + // Note: The highest SPI clock rate is 20 MHz for MMC and 25 MHz for SD + void set_transfer_sck(uint32_t sck) { _transfer_sck = sck; } + uint32_t _init_sck; + uint32_t _transfer_sck; + + SPI _spi; + DigitalOut _cs; + int cdv; + int _is_initialized; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VideoRAM.h Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,34 @@ +#pragma once + +class VideoRAM { +public: + VideoRAM(RawSerial& pc):_pc(pc),x(0),y(0) { + _puts("\x1b[2J"); // erase + } + void vpoke(uint16_t i, uint8_t b) { + if (i < 1024) { + if (x != i%64 || y != i/64) { + x = i%64; + y = i/64; + char buf[16]; + snprintf(buf, sizeof(buf), "\x1b[%d;%dH", y+1, x+1) ; // locate + _puts(buf); + } + _putc(b & 0x7f); + x++; + } + } + +private: + void _puts(const char* s) { + while(*s) { + _putc(*s++); + } + } + void _putc(int c) { + _pc.putc(c); + } + RawSerial& _pc; + uint16_t x, y; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VirtualRAM.h Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,37 @@ +// VirtualRAM.h 2015/4/29 +#pragma once +#define PAGE_CHUNK_SIZE 1024 +class VirtualRAM { +public: + int used_size; + VirtualRAM(): used_size(0) { + memset(mem_ptr, 0x00, sizeof(mem_ptr)); // NULL + } + uint8_t peek(uint16_t a) { + uint8_t* mem = ptr(a); + if (mem == NULL) { + return 0x00; + } + return mem[a % PAGE_CHUNK_SIZE]; + } + void poke(uint16_t a, uint8_t b) { + uint8_t* mem = ptr(a); + if (mem == NULL) { + mem = reinterpret_cast<uint8_t*>(malloc(PAGE_CHUNK_SIZE)); + MBED_ASSERT(mem != NULL); + mem_ptr[idx(a)] = mem; + used_size += PAGE_CHUNK_SIZE; + } + mem[a % PAGE_CHUNK_SIZE] = b; + } + +private: + uint8_t* ptr(uint16_t addr) { + return mem_ptr[idx(addr)]; + } + int idx(uint16_t addr) { + return addr / PAGE_CHUNK_SIZE; + } + uint8_t* mem_ptr[65536 / PAGE_CHUNK_SIZE]; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed May 13 18:39:01 2015 +0900 @@ -0,0 +1,124 @@ +// main.cpp 2015/5/13 +#include "mbed.h" +#include "BaseIPS.h" +#include "VideoRAM.h" +#include "VirtualRAM.h" +#include "SDFileSystem.h" +#include "ConfigFile.h" +#include <string> + +#define CFG_FILE "/local/ips.cfg" + +#ifndef MBED_SPI0 +#define MBED_SPI0 D11, D12, D13, D4 +#endif +SDFileSystem local(MBED_SPI0, "local"); // mosi, miso, sclk, cs, name + +RawSerial pc(USBTX,USBRX); + +class myips : public BaseIPS { + VideoRAM vram; + VirtualRAM mem; + RawSerial& _pc; + Timer t20ms; +public: + myips(RawSerial& pc): vram(pc),_pc(pc) { + t20ms.reset(); + t20ms.start(); + } + virtual u8 peekB(u16 a) { + return mem.peek(a); + } + virtual void pokeB(u16 a, u8 b) { + mem.poke(a, b); + vram.vpoke(a, b); + } + virtual void* file_open(const char* filename, const char* mode) { + string path = string("/local/") + filename; + return fopen(path.c_str(), mode); + } + virtual int file_getc(void* handle) { + MBED_ASSERT(handle); + int c = fgetc((FILE*)handle); + return c == EOF ? (-1) : c; + } + virtual void file_putc(int c, void* handle) { + MBED_ASSERT(handle); + fputc(c, (FILE*)handle); + } + virtual bool file_close(void* handle) { + MBED_ASSERT(handle); + if (fclose((FILE*)handle) == 0) { + return true; + } + return false; + } + + virtual bool test_20ms() { + if (t20ms.read_ms() >= 20) { + t20ms.reset(); + return true; + } + return false; + } + + virtual void do_io() { + if (_pc.readable()) { + int c = _pc.getc(); + if (c == '\n' || c == '\r') { + if (input_ptr != peek(a_PI)) { + pokeB(READYFLAG, 1); + poke(a_PE, input_ptr - 1); + } + else if (c == 0x08) // BS + if (input_ptr > 0) { + input_ptr--; + } + } else { + if (input_ptr <= TVE) { + pokeB(input_ptr++, c); + } + } + } + } +}; + +int main() { + string image = "IPS-Mu.bin"; + string file; + string cmd; + ConfigFile cfg; + if(cfg.read(CFG_FILE)) { + char buf[128]; + if (cfg.getValue("image", buf, sizeof(buf))) { + image = buf; + } + if (cfg.getValue("file", buf, sizeof(buf))) { + file = buf; + cmd = string("\" ") + file + string(" \" READ"); + } + if (cfg.getValue("cmd", buf, sizeof(buf))) { + cmd = buf; + } + } + + myips* ips = new myips(pc); + void* fh = ips->file_open(image.c_str(), "rb"); + MBED_ASSERT(fh); + if (fh) { + for(int i = 0; i <= 65535; i++) { + int c = ips->file_getc(fh); + if (c == (-1)) { + break; + } + ips->pokeB(i, c); + } + ips->file_close(fh); + } + if (cmd != "") { + ips->command(cmd.c_str()); + } + ips->emulator(); + /* NOTREACHED */ +} +