00001
00006 #include "../dllkit/dllkit.h"
00007 #include "../usrmsgs.h"
00008 #include "resource.h"
00009 #include "instructions.h"
00010 #include <windows.h>
00011 #include <commctrl.h>
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014
00015 #define ADR(X, Y) (((Y) << 8) + (X))
00016
00017 #define FN 0x80
00018 #define FV 0x40
00019 #define FB 0x10
00020 #define FD 0x08
00021 #define FI 0x04
00022 #define FZ 0x02
00023 #define FC 0x01
00026 typedef struct {
00027 UINT PC;
00028 unsigned char X;
00029 unsigned char Y;
00030 unsigned char A;
00031 unsigned char P;
00032 UINT S;
00033 } Regs;
00034
00035 HANDLE hThisModule;
00036 MSGLIST Msgs;
00037 INITDLLSTRUCT info;
00038
00040 HMENU hMenu;
00042 HMENU hDebugMenu;
00043
00044
00045
00052 void StartDebug();
00053
00063 void DisAsm(int lower, int upper, HANDLE fil, int act);
00064
00065
00074 void DumpMemHex(HANDLE fil, UINT adr1, UINT adr2);
00075
00084 void DumpMem(HANDLE fil, UINT adr1, UINT adr2);
00085
00087 void printhelp();
00088
00096 HANDLE ofile();
00097
00105 HANDLE orfile();
00106
00115 void SetReg(Regs* regs, char* buf);
00116
00118 void printregs(Regs* regs);
00119
00128 void printfil(HANDLE fil, char* str);
00129
00131 void rinterval(UINT* adr1, UINT* adr2);
00132
00134 UINT rhex(char* msg);
00135
00137 void mklpstr(char* str);
00138
00140 void print(char* str);
00141
00143 void rline(char* str);
00144
00146 void printact(Regs* regs);
00147
00148
00149 BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
00150 LPVOID lpReserved)
00151 {
00152 hThisModule = hModule;
00153 switch (ul_reason_for_call) {
00154 case DLL_PROCESS_ATTACH:
00155 CreateMsgList(&Msgs, 1);
00156 break;
00157 case DLL_PROCESS_DETACH:
00158 FreeMsgList(Msgs);
00159 break;
00160 }
00161 return TRUE;
00162 }
00163
00164 DLLEXPORT void __cdecl InitDll(INITDLLSTRUCT* ids, INITDLLINFO* idi)
00165 {
00166 TBADDBITMAP tbab;
00167 TBBUTTON tbt;
00168 int index;
00169
00170
00171 AddMessage(Msgs, WM_COMMAND);
00172
00173
00174 info.CSMemory = ids->CSMemory;
00175 info.hInst = ids->hInst;
00176 info.hWnd = ids->hWnd;
00177 info.memory = ids->memory;
00178 info.memgetb = ids->memgetb;
00179 info.memsetb = ids->memsetb;
00180 info.optional = ids->optional;
00181 info.hTb = ids->hTb;
00182
00183 hMenu = GetMenu(info.hWnd);
00184 hDebugMenu = LoadMenu(hThisModule, MAKEINTRESOURCE(IDR_DEBUG));
00185 AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT) hDebugMenu, "&Debug");
00186 DrawMenuBar(info.hWnd);
00187
00188 tbab.hInst = hThisModule;
00189 tbab.nID = IDR_TB;
00190 index = SendMessage(info.hTb, TB_ADDBITMAP, (WPARAM) 1,
00191 (WPARAM) &tbab);
00192 ZeroMemory(&tbt, sizeof(TBBUTTON));
00193 tbt.iBitmap = index;
00194 tbt.idCommand = ID_DEBUG_STARTDEBUG;
00195 tbt.fsState = TBSTATE_ENABLED;
00196 tbt.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE;
00197
00198 SendMessage(info.hTb, TB_ADDBUTTONS, (WPARAM) 1,
00199 (LPARAM) &tbt);
00200 SendMessage(info.hTb, TB_AUTOSIZE, 0, 0);
00201
00202
00203
00204 idi->iolo = 0;
00205 idi->iohi = 0;
00206 idi->msglist = Msgs;
00207 }
00208
00209
00210 DLLEXPORT void __cdecl OnMessage(MESSAGEDLLSTRUCT* mds)
00211 {
00212 int wmId, wmEvent;
00213
00214 switch (mds->message) {
00215 case WM_COMMAND:
00216 wmId = LOWORD(mds->wParam);
00217 wmEvent = HIWORD(mds->wParam);
00218 switch (wmId) {
00219 case ID_DEBUG_STARTDEBUG:
00220 ShowWindow(info.hWnd, SW_MINIMIZE);
00221
00222 SendMessage(info.hWnd, PAUSECPU, 0, 0);
00223 SendMessage(info.hWnd, WAITEND, 0, 0);
00224 AllocConsole();
00225 StartDebug();
00226 FreeConsole();
00227 ShowWindow(info.hWnd, SW_RESTORE);
00228 break;
00229 case ID_DEBUG_ABOUT:
00230 MessageBox(info.hWnd, "Debug plugin\nAdds some debugging & disassembling features to emu6502\n(c)2002 Petr Cermak", "About", MB_OK);
00231 break;
00232 }
00233 break;
00234 }
00235
00236 }
00237
00238 DLLEXPORT void __cdecl IOFunc(UINT adr, unsigned char* data,
00239 iomode mode)
00240 {
00241 }
00242
00243 void StartDebug()
00244 {
00245 char buf[256];
00246 UINT adr1, adr2, val;
00247 DWORD tmp;
00248 Regs* regs = NULL;
00249 HANDLE fil = NULL;
00250
00251 print("Emu6502 debugger & disassembler\n");
00252 print("To retrieve list of commands, type 'h' and press enter.\n");
00253
00254
00255 SendMessage(info.hWnd, GETREGS, 0, (LPARAM) ®s);
00256
00257 if (regs == NULL) {
00258 print("Cpu plugin not running!\nDebugging not available.\nPress Enter key to return.\n");
00259 rline(buf);
00260 return;
00261 }
00262
00263 do {
00264 print("\n");
00265 print("> ");
00266 rline(buf);
00267 switch (buf[0]) {
00268 case 'H':
00269 case 'h':
00270 printhelp();
00271 break;
00272 case 'D':
00273 case 'd':
00274 print("Disassemble\n");
00275 fil = NULL;
00276 rinterval(&adr1, &adr2);
00277 if (buf[1] == 'f') {
00278 fil = ofile();
00279 if (fil == NULL) {
00280 break;
00281 }
00282 }
00283 DisAsm(adr1, adr2, fil, -1);
00284 if (fil != NULL) {
00285 CloseHandle(fil);
00286 }
00287 break;
00288 case 'M':
00289 case 'm':
00290 fil = NULL;
00291 if (buf[1] == 'f' || buf[1] == 'F') {
00292 rinterval(&adr1, &adr2);
00293 if (buf[2] == 'h' || buf[2] == 'H') {
00294 fil = ofile();
00295 if (fil == NULL) {
00296 break;
00297 }
00298 DumpMemHex(fil, adr1, adr2);
00299 }
00300 else {
00301 fil = ofile();
00302 if (fil == NULL) {
00303 break;
00304 }
00305 DumpMem(fil, adr1, adr2);
00306 }
00307 CloseHandle(fil);
00308 }
00309 else if (buf[1] == 's' || buf[1] == 'S'){
00310 if(buf[2] == 'f' || buf[2] == 'F'){
00311 do {
00312 adr1 = rhex("From addr.: ");
00313 } while (adr1 > 0xFFFF);
00314 fil = orfile();
00315 if (fil == NULL) {
00316 break;
00317 }
00318 adr2 = GetFileSize(fil, NULL);
00319 if (adr1 + adr2 - 1 > 0xFFFF) {
00320 print("Given address and size overreach the $ffff boundary\n");
00321 CloseHandle(fil);
00322 break;
00323 }
00324 if (!ReadFile(fil, info.memory + adr1, adr2, &tmp, NULL)) {
00325 print("Error reading file\n");
00326 break;
00327 }
00328 }
00329 else {
00330 rinterval(&adr1, &adr2);
00331 do {
00332 val = rhex("Value: ");
00333 } while (val > 0xFF);
00334 for (tmp = adr1; tmp <= adr2; tmp++) {
00335 (*info.memsetb)(tmp, (unsigned char) val);
00336 }
00337 }
00338 }
00339 else {
00340 rinterval(&adr1, &adr2);
00341 DumpMemHex(fil, adr1, adr2);
00342 }
00343 break;
00344 case 'R':
00345 case 'r':
00346 printregs(regs);
00347 break;
00348 case 'A':
00349 case 'a':
00350 printact(regs);
00351 break;
00352 case 'N':
00353 case 'n':
00354 SendMessage(info.hWnd, ISTEP, 0, (LPARAM) &adr1);
00355 printact(regs);
00356 sprintf(buf, "Instruction took %d cycles\n", adr1);
00357 print(buf);
00358 break;
00359 case 'I':
00360 case 'i':
00361 switch(buf[1]) {
00362 case 'I':
00363 case 'i':
00364 print("IRQ\n");
00365 (*info.memsetb)(IRQID, 254);
00366 SendMessage(info.hWnd, IRQD, 0, 0);
00367 printact(regs);
00368 break;
00369 case 'N':
00370 case 'n':
00371 print("NMI\n");
00372 (*info.memsetb)(NMIID, 254);
00373 SendMessage(info.hWnd, NMID, 0, 0);
00374 printact(regs);
00375 break;
00376 case 'R':
00377 case 'r':
00378 print("RESET\n");
00379 (*info.memsetb)(RESETID, 254);
00380 SendMessage(info.hWnd, RESETD, 0, 0);
00381 printact(regs);
00382 break;
00383 default:
00384 print("Unknown interrupt name\n");
00385 break;
00386 }
00387 break;
00388 case 'S':
00389 case 's':
00390 SetReg(regs, buf);
00391 break;
00392 case 'Q':
00393 case 'q':
00394 break;
00395 default:
00396 print("Unknown command, type 'h' for help\n");
00397 break;
00398 }
00399 } while (buf[0] != 'q');
00400 }
00401
00402 void SetReg(Regs* regs, char* buf)
00403 {
00404 UINT adr1;
00405 BOOL ok = FALSE;
00406
00407 if (buf[1] != 'f' && buf[1] != 'F') {
00408 printregs(regs);
00409 }
00410
00411 do {
00412 ok = FALSE;
00413 switch(buf[1]) {
00414 case 'A':
00415 case 'a':
00416 adr1 = rhex("A: ");
00417 if (adr1 <= 255) {
00418 ok = TRUE;
00419 regs->A = adr1;
00420 }
00421 break;
00422 case 'X':
00423 case 'x':
00424 adr1 = rhex("X: ");
00425 if (adr1 <= 255) {
00426 ok = TRUE;
00427 regs->X = adr1;
00428 }
00429 break;
00430 case 'Y':
00431 case 'y':
00432 adr1 = rhex("Y: ");
00433 if (adr1 <= 255) {
00434 ok = TRUE;
00435 regs->Y = adr1;
00436 }
00437 break;
00438 case 'S':
00439 case 's':
00440 adr1 = rhex("S: ");
00441 if (adr1 >= 256 && adr1 <511) {
00442 ok = TRUE;
00443 regs->A = adr1;
00444 }
00445 break;
00446 case 'P':
00447 case 'p':
00448 if (buf[2] == 'c' || buf[2] == 'C') {
00449 adr1 = rhex("PC: ");
00450 if (adr1 <= 65535) {
00451 ok = TRUE;
00452 regs->PC = adr1;
00453 }
00454 }
00455 else {
00456 adr1 = rhex("P: ");
00457 if (adr1 <= 255) {
00458 ok = TRUE;
00459 regs->P = adr1;
00460 }
00461 }
00462 break;
00463 case 'F':
00464 case 'f':
00465 ok = TRUE;
00466 switch(buf[2]) {
00467 case 'N':
00468 case 'n':
00469 regs->P = regs->P ^ FN;
00470 break;
00471 case 'V':
00472 case 'v':
00473 regs->P = regs->P ^ FV;
00474 break;
00475 case 'B':
00476 case 'b':
00477 regs->P = regs->P ^ FB;
00478 break;
00479 case 'D':
00480 case 'd':
00481 regs->P = regs->P ^ FD;
00482 break;
00483 case 'I':
00484 case 'i':
00485 regs->P = regs->P ^ FI;
00486 break;
00487 case 'Z':
00488 case 'z':
00489 regs->P = regs->P ^ FZ;
00490 break;
00491 case 'C':
00492 case 'c':
00493 regs->P = regs->P ^ FC;
00494 break;
00495 default:
00496 print("Wrong name of flag\n");
00497 break;
00498 }
00499 break;
00500 default:
00501 print("Wrong name of register\n");
00502 ok = TRUE;
00503 break;
00504 }
00505 } while (ok == FALSE);
00506 printregs(regs);
00507 }
00508
00509
00510 void DisAsm(int lower, int upper, HANDLE fil, int act)
00511 {
00512 int adr = lower;
00513 int tmp;
00514 unsigned char instr, op1, op2;
00515 char buf[20];
00516
00517 while (adr <= upper) {
00518 instr = (*info.memgetb)(adr);
00519 if (act == adr) {
00520 printfil(fil, ">>> ");
00521 }
00522 sprintf(buf, "%04x\t", adr);
00523 printfil(fil, buf);
00524 printfil(fil, INSTRUCTIONS[instr].name);
00525
00526 switch (INSTRUCTIONS[instr].aType) {
00527 case IMPL:
00528 break;
00529 case ACC:
00530 printfil(fil, " A");
00531 break;
00532 case IMM:
00533 printfil(fil, " #$");
00534 op1 = (*info.memgetb)(adr + 1);
00535 sprintf(buf, "%02x", op1);
00536 printfil(fil, buf);
00537 break;
00538 case ABS:
00539 printfil(fil, " $");
00540 op1 = (*info.memgetb)(adr + 1);
00541 op2 = (*info.memgetb)(adr + 2);
00542 sprintf(buf, "%04x", ADR(op1, op2));
00543 printfil(fil, buf);
00544 break;
00545 case ABSX:
00546 printfil(fil, " $");
00547 op1 = (*info.memgetb)(adr + 1);
00548 op2 = (*info.memgetb)(adr + 2);
00549 sprintf(buf, "%04x, X", ADR(op1, op2));
00550 printfil(fil, buf);
00551 break;
00552 case ABSY:
00553 printfil(fil, " $");
00554 op1 = (*info.memgetb)(adr + 1);
00555 op2 = (*info.memgetb)(adr + 2);
00556 sprintf(buf, "%04x, Y", ADR(op1, op2));
00557 printfil(fil, buf);
00558 break;
00559 case ZP:
00560 printfil(fil, " $");
00561 op1 = (*info.memgetb)(adr + 1);
00562 sprintf(buf, "%02x", op1);
00563 printfil(fil, buf);
00564 break;
00565 case ZPX:
00566 printfil(fil, " $");
00567 op1 = (*info.memgetb)(adr + 1);
00568 sprintf(buf, "%02x, X", op1);
00569 printfil(fil, buf);
00570 break;
00571 case ZPY:
00572 printfil(fil, " $");
00573 op1 = (*info.memgetb)(adr + 1);
00574 sprintf(buf, "%02x, Y", op1);
00575 printfil(fil, buf);
00576 break;
00577 case REL:
00578 op1 = (*info.memgetb)(adr + 1);
00579 printfil(fil, " $");
00580 if (op1 > 0x7F) {
00581 tmp = adr + 2 - 0x100 + op1;
00582 }
00583 else {
00584 tmp = adr + 2 + op1;
00585 }
00586 sprintf(buf, "%04x", tmp);
00587 printfil(fil, buf);
00588 break;
00589 case IND:
00590 printfil(fil, " (");
00591 op1 = (*info.memgetb)(adr + 1);
00592 op2 = (*info.memgetb)(adr + 2);
00593 sprintf(buf, "%04x)", ADR(op1, op2));
00594 printfil(fil, buf);
00595 break;
00596 case INDX:
00597 printfil(fil, " (");
00598 op1 = (*info.memgetb)(adr + 1);
00599 sprintf(buf, "%02x, X)", op1);
00600 printfil(fil, buf);
00601 break;
00602 case INDY:
00603 printfil(fil, " (");
00604 op1 = (*info.memgetb)(adr + 1);
00605 sprintf(buf, "%02x), Y", op1);
00606 printfil(fil, buf);
00607 break;
00608 }
00609 printfil(fil, "\r\n");
00610 adr += INSTRUCTIONS[instr].len;
00611 }
00612 }
00613
00614 void printhelp()
00615 {
00616 print("(a)ctual state -- prints actual state of emulator (registers and disassembled position in memory)\n");
00617 print("(d)isassemble -- disassembles given range of memory\n");
00618 print("(d)isassemble into (f)ile\n");
00619 print("(i)nterrupt (i)rq -- raises interrupt request\n");
00620 print("(i)nterrupt (n)mi -- raises nonmaskable interrupt\n");
00621 print("(i)nterrupt(r)eset -- raises reset interrupt\n");
00622 print("(h)elp -- this message\n");
00623 print("(m)emory dump -- prints memory dump in hex format onto screen\n");
00624 print("(m)emory dump into (f)ile -- dumps given range of memory into file (binary)\n");
00625 print("(m)emory dump into (f)ile in (h)ex format\n");
00626 print("(m)emory (s)et -- set given range of memory to specified value\n");
00627 print("(m)emory (s)et from (f)ile -- load block of memory from file\n");
00628 print("(n)ext instruction -- executes one instruction\n");
00629 print("(q)uit debugger\n");
00630 print("(r)egisters -- prints actual state of registers\n");
00631 print("(s)et ([A, X, Y, P, PC, S]) register to given value\n");
00632 print("(s)et (f)lag ([N, V, B, D, I, Z, C]) -- negates given flag\n");
00633 print("Creating commands - example:\n");
00634 print("(m)emory dump\tinto (f)ile in (h)ex format\n");
00635 print("means: > mfh <enter>\n");
00636 print("All values must be in hex format!\n");
00637 }
00638
00639 void DumpMem(HANDLE fil, UINT adr1, UINT adr2)
00640 {
00641 DWORD tmp;
00642 WriteFile(fil, info.memory + adr1, adr2 - adr1 + 1, &tmp, NULL);
00643 }
00644
00645
00646 void DumpMemHex(HANDLE fil, UINT adr1, UINT adr2)
00647 {
00648 UINT i;
00649 char buf[10];
00650 for (i = adr1; i <= adr2; i++) {
00651 if ((i - adr1) % 20 == 0) {
00652 sprintf(buf, "\r\n%04x ", i);
00653 printfil(fil, buf);
00654 }
00655 sprintf(buf, "%02x ", (*info.memgetb)(i));
00656 printfil(fil, buf);
00657 }
00658 }
00659
00660 HANDLE orfile()
00661 {
00662 OPENFILENAME ofn;
00663 TCHAR FileName[1024];
00664 HANDLE hFile;
00665
00666 lstrcpy(FileName, "");
00667 ZeroMemory(&ofn, sizeof(OPENFILENAME));
00668
00669 ofn.lStructSize = sizeof(OPENFILENAME);
00670 ofn.lpstrFile = FileName;
00671 ofn.hwndOwner = info.hWnd;
00672 ofn.nMaxFile = sizeof(FileName);
00673 ofn.lpstrFilter =
00674 TEXT("Pratial memory image files (*.bin;*.img)\0*.bin;*.img\0All Files (*.*)\0*.*\0");
00675 ofn.nFilterIndex = 1;
00676 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
00677
00678 ShowWindow(info.hWnd, SW_RESTORE);
00679 if (!GetOpenFileName(&ofn))
00680 return NULL;
00681 ShowWindow(info.hWnd, SW_MINIMIZE);
00682
00683 hFile=CreateFile((LPCSTR) FileName, GENERIC_READ, 0,NULL, OPEN_EXISTING, 0, NULL);
00684 if (hFile==INVALID_HANDLE_VALUE) {
00685 print("Cannot open file\n");
00686 return NULL;
00687 }
00688 return hFile;
00689 }
00690
00691
00692
00693 HANDLE ofile()
00694 {
00695 OPENFILENAME ofn;
00696 TCHAR FileName[1024];
00697 HANDLE hFile;
00698
00699 lstrcpy(FileName, "");
00700 ZeroMemory(&ofn, sizeof(OPENFILENAME));
00701
00702 ofn.lStructSize = sizeof(OPENFILENAME);
00703 ofn.lpstrFile = FileName;
00704 ofn.hwndOwner = info.hWnd;
00705 ofn.nMaxFile = sizeof(FileName);
00706 ofn.lpstrFilter =
00707 TEXT("All Files (*.*)\0*.*\0");
00708 ofn.nFilterIndex = 1;
00709 ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
00710
00711 ShowWindow(info.hWnd, SW_RESTORE);
00712 if (!GetSaveFileName(&ofn)) {
00713 ShowWindow(info.hWnd, SW_MINIMIZE);
00714 return NULL;
00715 }
00716 ShowWindow(info.hWnd, SW_MINIMIZE);
00717
00718 hFile=CreateFile((LPCSTR) FileName, GENERIC_WRITE, 0,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
00719 if (hFile==INVALID_HANDLE_VALUE) {
00720 print("Error creating file\n");
00721 return FALSE;
00722 }
00723 return hFile;
00724 }
00725
00726
00727 void printact(Regs* regs)
00728 {
00729 printregs(regs);
00730 print("\n");
00731 DisAsm(regs->PC,
00732 ((regs->PC + 10) > 0xffff) ? 0xffff : (regs->PC + 10), NULL, regs->PC);
00733 }
00734
00735 #define GETFLAG(FL) \
00736 ((regs->P & (FL)) == 0) ? 0 : 1
00737
00738 void printregs(Regs* regs)
00739 {
00740 char buf[255];
00741 sprintf(buf, "PC = %04x, S = %04x\nA = %02x, X = %02x, Y = %02x\n",
00742 regs->PC, regs->S, regs->A, regs->X, regs->Y);
00743 print(buf);
00744 sprintf(buf, "P = %02x: N = %d, V = %d, B = %d, D = %d, I = %d, Z = %d, C = %d\n",
00745 regs->P, GETFLAG(FN), GETFLAG(FV), GETFLAG(FB), GETFLAG(FD), GETFLAG(FI), GETFLAG(FZ), GETFLAG(FC));
00746 print(buf);
00747 }
00748
00749 void rinterval(UINT* adr1, UINT* adr2)
00750 {
00751 do {
00752 *adr1 = rhex("From addr.: ");
00753 *adr2 = rhex("To addr.: ");
00754 } while (!(adr1 <= adr2 <= 0xFFFF));
00755 }
00756
00757 UINT rhex(char* msg)
00758 {
00759 char str[255];
00760 long num;
00761 str[0] = '0';
00762 str[1] = 'x';
00763 do {
00764 print(msg);
00765 rline(str + 2);
00766 print("\n");
00767 if (str[3] == 13 && str[2] == '0') {
00768 num = 0;
00769 break;
00770 }
00771 } while (!(num = strtoul(str, NULL, 16)));
00772 return (UINT) num;
00773 }
00774
00775 void mklpstr(char* str)
00776 {
00777 for(; *str != 13; str++)
00778 ;
00779 *str = '\0';
00780 }
00781
00782 void printfil(HANDLE fil, char* str)
00783 {
00784 DWORD tmp;
00785 if (fil == NULL) {
00786 print(str);
00787 }
00788 else {
00789 WriteFile(fil, str, lstrlen(str), &tmp, NULL);
00790 }
00791 }
00792
00793 void print(char* str)
00794 {
00795 DWORD tmp;
00796 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, lstrlen(str), &tmp, NULL);
00797 }
00798
00799 void rline(char* str)
00800 {
00801 DWORD tmp;
00802 ReadFile(GetStdHandle(STD_INPUT_HANDLE), str, 255, &tmp, NULL);
00803 }