--- M6502/M6502.xs 2007/08/01 22:01:15 84 +++ M6502/M6502.xs 2007/08/02 12:37:06 91 @@ -7,14 +7,159 @@ #include "M6502.h" #include "config.h" -M6502 *R; +M6502 *R = NULL; +int debug = 0; -void -run (void) { - debugf(("M6502::run")); - run_forever(); +void update_C_R(void) { + R->A = SvIV( get_sv("M6502::A", FALSE) ); + R->P = SvIV( get_sv("M6502::P", FALSE) ); + R->X = SvIV( get_sv("M6502::X", FALSE) ); + R->Y = SvIV( get_sv("M6502::Y", FALSE) ); + R->S = SvIV( get_sv("M6502::S", FALSE) ); + R->PC.W = SvIV( get_sv("M6502::PC", FALSE) ); + R->IPeriod = SvIV( get_sv("M6502::IPeriod", FALSE) ); + R->IRequest = SvIV( get_sv("M6502::IRequest", FALSE) ); + R->IAutoReset = SvIV( get_sv("M6502::IAutoReset", FALSE) ); + R->TrapBadOps = SvIV( get_sv("M6502::TrapBadOps", FALSE) ); + R->Trap = SvIV( get_sv("M6502::Trap", FALSE) ); + R->Trace = SvIV( get_sv("M6502::Trace", FALSE) ); + debugf(("pull_R finished")); + dump_R; +} + +void update_perl_R(void) { + debugf(("update_perl_R")); + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs( sv_2mortal( newSViv( R->A ) ) ); + XPUSHs( sv_2mortal( newSViv( R->P ) ) ); + XPUSHs( sv_2mortal( newSViv( R->X ) ) ); + XPUSHs( sv_2mortal( newSViv( R->Y ) ) ); + XPUSHs( sv_2mortal( newSViv( R->S ) ) ); + XPUSHs( sv_2mortal( newSViv( R->PC.W ) ) ); + XPUSHs( sv_2mortal( newSViv( R->IPeriod ) ) ); + XPUSHs( sv_2mortal( newSViv( R->ICount ) ) ); + XPUSHs( sv_2mortal( newSViv( R->IRequest ) ) ); + XPUSHs( sv_2mortal( newSViv( R->IAutoReset ) ) ); + XPUSHs( sv_2mortal( newSViv( R->TrapBadOps ) ) ); + XPUSHs( sv_2mortal( newSViv( R->Trap ) ) ); + XPUSHs( sv_2mortal( newSViv( R->Trace ) ) ); + PUTBACK; + call_pv("M6502::_update_perl_R", G_DISCARD ); + debugf(("_update_perl_R returned to C")); + dump_R; + FREETMPS; + LEAVE; +} + +/** Debug6502() **********************************************/ + +byte Debug6502(M6502 *R) { + dump_R; + return 1; // continue emulation +} + +/** Rd6502()/Wr6502/Op6502() *********************************/ +/** These functions are called when access to RAM occurs. **/ +/** They allow to control memory access. Op6502 is the same **/ +/** as Rd6502, but used to read *opcodes* only, when many **/ +/** checks can be skipped to make it fast. It is only **/ +/** required if there is a #define FAST_RDOP. **/ +/************************************ TO BE WRITTEN BY USER **/ + +byte mem(word Addr) { + byte byte; + int count; + debugf(("mem(%04x)", Addr)); + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs( sv_2mortal( newSViv( Addr ) ) ); + PUTBACK; + count = call_pv("M6502::_read", G_ARRAY | G_EVAL ); + debugf(("got %d values", count)); + SPAGAIN; + if (SvTRUE(ERRSV)) { + printf("ERROR: %s", SvPV_nolen( ERRSV ) ); + exit(1); + } + if ( count != 1 ) { + printf("expect 1 return value, got %d", count); + exit(1); + } + SV *sv; + sv = POPs; + byte = SvIV(sv); + FREETMPS; + LEAVE; + debugf(("mem(%04x) = %02x", Addr, byte)); + return byte; +} + +byte Rd6502(register word Addr) { + byte Value; + Value = mem(Addr); +// Value = 0x42; + debugf(("Rd6502(%04x) = %02x", Addr, Value)); + return Value; +} + +void Wr6502(register word Addr,register byte Value) { + debugf(("Wr6502(%04x,%02x)", Addr, Value)); + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs( sv_2mortal( newSViv( Addr ) ) ); + XPUSHs( sv_2mortal( newSViv( Value ) ) ); + PUTBACK; + call_pv("M6502::_write", G_DISCARD ); + FREETMPS; + LEAVE; +} + +byte Op6502(register word Addr) { + byte Op; + Op = mem(Addr); + debugf(("Op6502(%04x,%02x) PC:%04x", Addr, Op, R->PC.W)); + return Op; +} + +/** Loop6502() ***********************************************/ +/** 6502 emulation calls this function periodically to **/ +/** check if the system hardware requires any interrupts. **/ +/** This function must return one of following values: **/ +/** INT_NONE, INT_IRQ, INT_NMI, or INT_QUIT to exit the **/ +/** emulation loop. **/ +/************************************ TO BE WRITTEN BY USER **/ + +int hw_int = INT_NONE; + +byte Loop6502(register M6502 *R) { + debugf(("Loop6502")); + dump_R; + return hw_int; +} + +/** Patch6502() **********************************************/ +/** Emulation calls this function when it encounters an **/ +/** unknown opcode. This can be used to patch the code to **/ +/** emulate BIOS calls, such as disk and tape access. The **/ +/** function should return 1 if the exception was handled, **/ +/** or 0 if the opcode was truly illegal. **/ +/************************************ TO BE WRITTEN BY USER **/ +byte Patch6502(register byte Op,register M6502 *R) { + debugf(("Patch6502(%02x)", Op)); + dump_R; + hw_int = INT_QUIT; + return 0; } +/*************************************************************/ + int reset (void) { debugf(("M6502::reset called")); @@ -22,22 +167,55 @@ debugf(("allocating space for R")); R = malloc(sizeof(M6502)); if (!R) { - printf("can't alloc %d bytes for M6502", sizeof(M6502)); + PerlIO_stdoutf("can't alloc %d bytes for M6502", sizeof(M6502)); exit(1); } } Reset6502(R); debugf(("Reset6502 over")); + update_perl_R(); dump_R; return 1; } +int exec(int cycles) { + debugf(("exec for %d cycles", cycles)); + + if (!R) reset(); + + update_C_R(); + Exec6502(R, cycles); + update_perl_R(); + debugf(("end of %d cycles CPU run\n", cycles)); +} + +int set_debug(int state) { + debug = state; + return debug; +} + +int get_debug(void) { + return debug; +} + MODULE = M6502 PACKAGE = M6502 PROTOTYPES: DISABLE -void -run() +int +set_debug(int state) + +int +get_debug() int reset() + +void +update_C_R() + +void +update_perl_R() + +int +exec(int cycles)