From 3cd0bc3f20a2b6c3ab7b8f454220f462eebf5844 Mon Sep 17 00:00:00 2001 From: Marek Karcz Date: Sun, 21 Aug 2016 01:41:38 -0400 Subject: [PATCH] Performance optimizations. Performance optimizations. Emulation speed measurement. Bug fixes. --- MKCpu.cpp | 140 ++- MKCpu.h | 25 +- MemMapDev.cpp | 20 +- MemMapDev.h | 2 +- Memory.cpp | 259 +++-- Memory.h | 10 +- ReadMe.txt | 156 ++- VMachine.cpp | 100 +- VMachine.h | 22 +- ehbas_grdemo_loop.snap | Bin 0 -> 65673 bytes ehbas_nogrdev.dat | 2074 ++++++++++++++++++++++++++++++++++++++++ main.cpp | 407 +++++--- 12 files changed, 2914 insertions(+), 301 deletions(-) create mode 100644 ehbas_grdemo_loop.snap create mode 100644 ehbas_nogrdev.dat diff --git a/MKCpu.cpp b/MKCpu.cpp index 7d35f92..823b488 100644 --- a/MKCpu.cpp +++ b/MKCpu.cpp @@ -351,6 +351,7 @@ void MKCpu::InitCpu() mReg.PageBoundary = false; mLocalMem = false; mExitAtLastRTS = true; + mEnableHistory = false; // performance decrease when enabled if (NULL == mpMem) { mpMem = new Memory(); if (NULL == mpMem) { @@ -359,15 +360,15 @@ void MKCpu::InitCpu() mLocalMem = true; } // Set default BRK vector ($FFFE -> $FFF0) - mpMem->Poke8bit(0xFFFE,0xF0); // LSB - mpMem->Poke8bit(0xFFFF,0xFF); // MSB + mpMem->Poke8bitImg(0xFFFE,0xF0); // LSB + mpMem->Poke8bitImg(0xFFFF,0xFF); // MSB // Put RTI opcode at BRK procedure address. - mpMem->Poke8bit(0xFFF0, OPCODE_RTI); + mpMem->Poke8bitImg(0xFFF0, OPCODE_RTI); // Set default RESET vector ($FFFC -> $0200) - mpMem->Poke8bit(0xFFFC,0x00); // LSB - mpMem->Poke8bit(0xFFFD,0x02); // MSB + mpMem->Poke8bitImg(0xFFFC,0x00); // LSB + mpMem->Poke8bitImg(0xFFFD,0x02); // MSB // Set BRK code at the RESET procedure address. - mpMem->Poke8bit(0x0200,OPCODE_BRK); + mpMem->Poke8bitImg(0x0200,OPCODE_BRK); } /* @@ -922,24 +923,24 @@ unsigned short MKCpu::GetArgWithMode(unsigned short addr, int mode) /* *-------------------------------------------------------------------- * Method: Disassemble() - * Purpose: Disassemble instruction and argument per addressing mode - * Arguments: n/a - internal + * Purpose: Disassemble op-code exec. history item. + * Arguments: histit - pointer to OpCodeHistItem type * Returns: 0 *-------------------------------------------------------------------- */ -unsigned short MKCpu::Disassemble() +unsigned short MKCpu::Disassemble(OpCodeHistItem *histit) { char sArg[40]; char sFmt[20]; strcpy(sFmt, "%s "); - strcat(sFmt, mArgFmtTbl[mReg.LastAddrMode].c_str()); + strcat(sFmt, mArgFmtTbl[histit->LastAddrMode].c_str()); sprintf(sArg, sFmt, - ((mOpCodesMap[(eOpCodes)mReg.LastOpCode]).amf.length() > 0 - ? (mOpCodesMap[(eOpCodes)mReg.LastOpCode]).amf.c_str() : "???"), - mReg.LastArg); + ((mOpCodesMap[(eOpCodes)histit->LastOpCode]).amf.length() > 0 + ? (mOpCodesMap[(eOpCodes)histit->LastOpCode]).amf.c_str() : "???"), + histit->LastArg); for (unsigned int i=0; iLastInstr = sArg; return 0; } @@ -963,7 +964,7 @@ unsigned short MKCpu::Disassemble(unsigned short opcaddr, char *instrbuf) int opcode = -1; int addrmode = -1; - opcode = mpMem->Peek8bit(addr++); + opcode = mpMem->Peek8bitImg(addr++); addrmode = (mOpCodesMap[(eOpCodes)opcode]).amf.length() > 0 ? (mOpCodesMap[(eOpCodes)opcode]).addrmode : -1; @@ -971,12 +972,12 @@ unsigned short MKCpu::Disassemble(unsigned short opcaddr, char *instrbuf) switch (mAddrModesLen[addrmode]) { case 2: - sprintf(sBuf, "$%02x ", mpMem->Peek8bit(addr)); + sprintf(sBuf, "$%02x ", mpMem->Peek8bitImg(addr)); break; case 3: - sprintf(sBuf, "$%02x $%02x", mpMem->Peek8bit(addr), - mpMem->Peek8bit(addr+1)); + sprintf(sBuf, "$%02x $%02x", mpMem->Peek8bitImg(addr), + mpMem->Peek8bitImg(addr+1)); break; default: @@ -985,7 +986,7 @@ unsigned short MKCpu::Disassemble(unsigned short opcaddr, char *instrbuf) } strcpy(sFmt, "$%04x: $%02x %s %s "); strcat(sFmt, mArgFmtTbl[addrmode].c_str()); - sprintf(sArg, sFmt, opcaddr, mpMem->Peek8bit(opcaddr), sBuf, + sprintf(sArg, sFmt, opcaddr, mpMem->Peek8bitImg(opcaddr), sBuf, ((mOpCodesMap[(eOpCodes)opcode]).amf.length() > 0 ? (mOpCodesMap[(eOpCodes)opcode]).amf.c_str() : "???"), GetArgWithMode(addr,addrmode)); @@ -3821,19 +3822,22 @@ Regs *MKCpu::ExecOpcode(unsigned short memaddr) mReg.LastAddr = memaddr; unsigned char opcode = OPCODE_BRK; - // skip until all the cycles were completed + // The op-code action was executed already once. + // Now skip if the clock cycles for this op-code are not yet completed. if (mReg.CyclesLeft > 0) { mReg.CyclesLeft--; return &mReg; } - // if no IRQ waiting, get the next opcode and advance PC + // If no IRQ waiting, get the next opcode and advance PC. + // Otherwise the opcode is OPCODE_BRK and with IrqPending + // flag set the IRQ sequence will be executed. if (!mReg.IrqPending) { opcode = mpMem->Peek8bit(mReg.PtrAddr++); } // load CPU instruction details from map - OpCode instrdet = mOpCodesMap[(eOpCodes)opcode]; + OpCode *instrdet = &mOpCodesMap[(eOpCodes)opcode]; SetFlag(false, FLAGS_BRK); // reset BRK flag - we want to detect mReg.SoftIrq = false; // software interrupt each time it @@ -3843,27 +3847,34 @@ Regs *MKCpu::ExecOpcode(unsigned short memaddr) mReg.LastAddrMode = ADDRMODE_UND; mReg.LastArg = 0; - string s = (instrdet.amf.length() > 0 - ? instrdet.amf.c_str() : "???"); + string s = (instrdet->amf.length() > 0 + ? instrdet->amf.c_str() : "???"); if (s.compare("ILL") == 0) { // trap any illegal opcode mReg.SoftIrq = true; } else { - // execute legal opcode - mReg.CyclesLeft = instrdet.time - 1; - OpCodeHdlrFn pfun = instrdet.pfun; + // reset remaining cycles counter and execute legal opcode + mReg.CyclesLeft = instrdet->time - 1; + OpCodeHdlrFn pfun = instrdet->pfun; if (NULL != pfun) (this->*pfun)(); } - - Disassemble(); - char histentry[80]; - sprintf(histentry, - "$%04x: %-16s \t$%02x | $%02x | $%02x | $%02x | $%02x", - mReg.LastAddr, mReg.LastInstr.c_str(), mReg.Acc, mReg.IndX, - mReg.IndY, mReg.Flags, mReg.PtrStack); - Add2History(histentry); + // Update history/log of recently executed op-codes/instructions. + if (mEnableHistory) { + + OpCodeHistItem histentry; + histentry.LastAddr = mReg.LastAddr; + histentry.Acc = mReg.Acc; + histentry.IndX = mReg.IndX; + histentry.IndY = mReg.IndY; + histentry.Flags = mReg.Flags; + histentry.PtrStack = mReg.PtrStack; + histentry.LastOpCode = mReg.LastOpCode; + histentry.LastAddrMode = mReg.LastAddrMode; + histentry.LastArg = mReg.LastArg; + Add2History(histentry); + } return &mReg; } @@ -3884,28 +3895,75 @@ Regs *MKCpu::GetRegs() /* *-------------------------------------------------------------------- * Method: Add2History() - * Purpose: Add entry to execute history. + * Purpose: Add entry with last executed op-code, arguments and + * CPU status to execute history. * Arguments: s - string (entry) * Returns: n/a *-------------------------------------------------------------------- */ -void MKCpu::Add2History(string s) +void MKCpu::Add2History(OpCodeHistItem histitem) { - mExecHistory.push(s); - while (mExecHistory.size() > 20) mExecHistory.pop(); + mExecHistory.push(histitem); + while (mExecHistory.size() > OPCO_HIS_SIZE) mExecHistory.pop(); } /* *-------------------------------------------------------------------- * Method: GetExecHistory() - * Purpose: Return queue with execute history. + * Purpose: Disassemble op-codes execute history stored in + * mExecHistory and create/return queue of strings with + * execute history in symbolic form (assembly mnemonics, + * properly converted arguments in corresponding addressing + * mode notation that adheres to MOS-6502 industry + * standard.) * Arguments: n/a * Returns: queue *-------------------------------------------------------------------- */ queue MKCpu::GetExecHistory() { - return mExecHistory; + queue ret; + queue exechist(mExecHistory); + + while (exechist.size()) { + OpCodeHistItem item = exechist.front(); + Disassemble(&item); + char histentry[80]; + sprintf(histentry, + "$%04x: %-16s \t$%02x | $%02x | $%02x | $%02x | $%02x", + item.LastAddr, item.LastInstr.c_str(), item.Acc, item.IndX, + item.IndY, item.Flags, item.PtrStack); + ret.push(histentry); + exechist.pop(); + } + + return ret; +} + +/* + *-------------------------------------------------------------------- + * Method: EnableExecHistory() + * Purpose: Enable/disable recording of op-codes execute history. + * Arguments: bool - true = enable / false = disable + * Returns: n/a + *-------------------------------------------------------------------- + */ +void MKCpu::EnableExecHistory(bool enexehist) +{ + mEnableHistory = enexehist; +} + +/* + *-------------------------------------------------------------------- + * Method: IsExecHistoryEnabled() + * Purpose: Check if op-code execute history is enabled. + * Arguments: n/a + * Returns: bool - true = enabled / false = disabled + *-------------------------------------------------------------------- + */ +bool MKCpu::IsExecHistoryEnabled() +{ + return mEnableHistory; } /* diff --git a/MKCpu.h b/MKCpu.h index df2fd6f..75f7eb8 100644 --- a/MKCpu.h +++ b/MKCpu.h @@ -12,6 +12,7 @@ using namespace std; namespace MKBasic { #define DISS_BUF_SIZE 60 // disassembled instruction buffer size +#define OPCO_HIS_SIZE 20 // size of op-code execute history queue struct Regs { unsigned char Acc; // 8-bit accumulator @@ -427,6 +428,8 @@ class MKCpu Regs *GetRegs(); void SetRegs(Regs r); queue GetExecHistory(); + void EnableExecHistory(bool enexehist); + bool IsExecHistoryEnabled(); unsigned short Disassemble(unsigned short addr, char *instrbuf); // Disassemble instruction in memory, return next instruction addr. void Reset(); // reset CPU @@ -435,6 +438,20 @@ class MKCpu protected: private: + + // keeps all needed data to disassemble op-codes in execute history queue + struct OpCodeHistItem { + unsigned char Acc; // 8-bit accumulator + unsigned char IndX; // 8-bit index register X + unsigned char IndY; // 8-bit index register Y + unsigned char Flags; // CPU flags + unsigned char PtrStack; // 8-bit stack pointer (0-255). + unsigned short LastAddr; // PC at the time of previous op-code + string LastInstr; // instruction and argument executed in previous step + int LastOpCode; // op-code of last instruction + unsigned short LastArg; // argument to the last instruction + int LastAddrMode; // addressing mode of last instruction + }; struct Regs mReg; // CPU registers Memory *mpMem; // pointer to memory object @@ -442,7 +459,8 @@ class MKCpu OpCodesMap mOpCodesMap; // hash table of all opcodes int mAddrModesLen[ADDRMODE_LENGTH]; // array of instructions lengths per addressing mode string mArgFmtTbl[ADDRMODE_LENGTH]; // array of instructions assembly formats per addressing mode - queue mExecHistory; // history of last 20 op-codes with arguments and registers statuses + queue mExecHistory; // keep the op-codes execute history + bool mEnableHistory; // enable/disable execute history void InitCpu(); @@ -466,8 +484,9 @@ class MKCpu unsigned short GetAddrWithMode(int mode); // Get address of the byte argument with specified addr. mode unsigned short GetArgWithMode(unsigned short opcaddr, int mode); // Get argument from address with specified addr. mode - unsigned short Disassemble(); // Disassemble instruction and argument per addressing mode - void Add2History(string s); // add entry to op-codes execute history + unsigned short Disassemble(OpCodeHistItem *histit); // Disassemble op-code exec history item + //void Add2History(string s); // add entry to op-codes execute history + void Add2History(OpCodeHistItem histitem); // add entry to op-codes execute history bool PageBoundary(unsigned short startaddr, unsigned short endaddr); // detect if page boundary was crossed diff --git a/MemMapDev.cpp b/MemMapDev.cpp index 6c546fd..3479d34 100644 --- a/MemMapDev.cpp +++ b/MemMapDev.cpp @@ -130,9 +130,8 @@ Device MemMapDev::GetDevice(int devnum) ++devit ) { - Device dev = *devit; - if (dev.num == devnum) { - ret = dev; + if (devit->num == devnum) { + ret = *devit; break; } } @@ -287,6 +286,7 @@ int MemMapDev::getch() return c; } } + #endif /* @@ -307,9 +307,17 @@ unsigned char MemMapDev::ReadCharKb(bool nonblock) static int c = ' '; if (mIOEcho && isprint(c)) putchar(c); fflush(stdout); - if (!nonblock) while(!kbhit()); - else c = 0; - c = getch(); + + if (nonblock) { + // get a keystroke only if character is already in buffer + if (kbhit()) c = getch(); + else c = 0; + + } else { + // wait for a keystroke, then get the character from buffer + while(!kbhit()); + c = getch(); + } #if defined(LINUX) if (c == 3) { // capture CTRL-C in CONIO mode reset_terminal_mode(); diff --git a/MemMapDev.h b/MemMapDev.h index b51b513..698d3d2 100644 --- a/MemMapDev.h +++ b/MemMapDev.h @@ -225,7 +225,7 @@ class MemMapDev { void set_conio_terminal_mode(); int kbhit(); - int getch(); + int getch(); #endif diff --git a/Memory.cpp b/Memory.cpp index 0f569da..4221a3f 100644 --- a/Memory.cpp +++ b/Memory.cpp @@ -1,5 +1,6 @@ #include "Memory.h" +#include "MKGenException.h" //#define DBG 1 #if defined (DBG) @@ -58,6 +59,9 @@ void Memory::Initialize() for (int i=0; i < 0xFFFF; i++) { m8bitMem[addr++] = 0; } + for (int i=0; i < MEM_PAGE_SIZE; i++) { + mMemPageDev[i] = -1; + } mCharIOAddr = CHARIO_ADDR; mCharIOActive = false; mIOEcho = false; @@ -138,37 +142,32 @@ unsigned char Memory::Peek8bit(unsigned short addr) { // if memory address is in range of any active memory mapped // devices, call corresponding device handling function - bool cont_loop = true; - for (vector::iterator it = mActiveDevNumVec.begin(); - it != mActiveDevNumVec.end() && cont_loop; - ++it - ) { + int mempg = addr / MEM_PAGE_SIZE; + if (mMemPageDev[mempg] >= 0) { + bool cont_loop = true; + for (vector::iterator devit = mActiveDeviceVec.begin(); + devit != mActiveDeviceVec.end() && cont_loop; + ++devit + ) { - Device dev = mpMemMapDev->GetDevice(*it); - if (dev.num >= 0) { - for (MemAddrRanges::iterator memrangeit = dev.addr_ranges.begin(); - memrangeit != dev.addr_ranges.end(); - ++memrangeit - ) { - AddrRange addr_range = *memrangeit; - if (addr >= addr_range.start_addr && addr <= addr_range.end_addr) { - ReadFunPtr pfun = dev.read_fun_ptr; - if (pfun != NULL) { - cont_loop = false; - (mpMemMapDev->*pfun)((int)addr); - break; + if (devit->num >= 0) { + for (MemAddrRanges::iterator memrangeit = devit->addr_ranges.begin(); + memrangeit != devit->addr_ranges.end(); + ++memrangeit + ) { + if (addr >= memrangeit->start_addr && addr <= memrangeit->end_addr) { + ReadFunPtr pfun = devit->read_fun_ptr; + if (pfun != NULL) { + cont_loop = false; + (mpMemMapDev->*pfun)((int)addr); + break; + } } } + mDispOp = (DEVNUM_GRDISP == devit->num); } } - mDispOp = (DEVNUM_GRDISP == dev.num); } - /* - if (mCharIOActive && addr == mCharIOAddr) { - m8bitMem[addr] = ReadCharKb(false); // blocking mode input - } else if (mCharIOActive && addr == mCharIOAddr+1) { - m8bitMem[addr] = ReadCharKb(true); // non-blocking mode input - }*/ return m8bitMem[addr]; } @@ -204,38 +203,32 @@ unsigned short Memory::Peek16bit(unsigned short addr) // if memory address is in range of any active memory mapped // devices, call corresponding device handling function - bool cont_loop = true; - for (vector::iterator it = mActiveDevNumVec.begin(); - it != mActiveDevNumVec.end() && cont_loop; - ++it - ) { - Device dev = mpMemMapDev->GetDevice(*it); - if (dev.num >= 0) { - for (MemAddrRanges::iterator memrangeit = dev.addr_ranges.begin(); - memrangeit != dev.addr_ranges.end(); - ++memrangeit - ) { - AddrRange addr_range = *memrangeit; - if (addr >= addr_range.start_addr && addr <= addr_range.end_addr) { - ReadFunPtr pfun = dev.read_fun_ptr; - if (pfun != NULL) { - cont_loop = false; - (mpMemMapDev->*pfun)((int)addr); - break; + int mempg = addr / MEM_PAGE_SIZE; + if (mMemPageDev[mempg] >= 0) { + bool cont_loop = true; + for (vector::iterator devit = mActiveDeviceVec.begin(); + devit != mActiveDeviceVec.end() && cont_loop; + ++devit + ) { + if (devit->num >= 0) { + for (MemAddrRanges::iterator memrangeit = devit->addr_ranges.begin(); + memrangeit != devit->addr_ranges.end(); + ++memrangeit + ) { + if (addr >= memrangeit->start_addr && addr <= memrangeit->end_addr) { + ReadFunPtr pfun = devit->read_fun_ptr; + if (pfun != NULL) { + cont_loop = false; + (mpMemMapDev->*pfun)((int)addr); + break; + } } } + mDispOp = (DEVNUM_GRDISP == devit->num); } } - mDispOp = (DEVNUM_GRDISP == dev.num); } - /* - if (mCharIOActive && addr == mCharIOAddr) { - m8bitMem[addr] = ReadCharKb(false); // blocking mode input - } else if (mCharIOActive && addr == mCharIOAddr+1) { - m8bitMem[addr] = ReadCharKb(true); // non-blocking mode input - }*/ - ret = m8bitMem[addr++]; ret += m8bitMem[addr] * 256; @@ -259,35 +252,32 @@ void Memory::Poke8bit(unsigned short addr, unsigned char val) { // if memory address is in range of any active memory mapped // devices, call corresponding device handling function - bool cont_loop = true; - for (vector::iterator it = mActiveDevNumVec.begin(); - it != mActiveDevNumVec.end() && cont_loop; - ++it - ) { - Device dev = mpMemMapDev->GetDevice(*it); - if (dev.num >= 0) { - for (MemAddrRanges::iterator memrangeit = dev.addr_ranges.begin(); - memrangeit != dev.addr_ranges.end(); - ++memrangeit - ) { - AddrRange addr_range = *memrangeit; - if (addr >= addr_range.start_addr && addr <= addr_range.end_addr) { - WriteFunPtr pfun = dev.write_fun_ptr; - if (pfun != NULL) { - cont_loop = false; - (mpMemMapDev->*pfun)((int)addr,(int)val); - m8bitMem[addr] = val; - break; + int mempg = addr / MEM_PAGE_SIZE; + if (mMemPageDev[mempg] >= 0) { + bool cont_loop = true; + for (vector::iterator devit = mActiveDeviceVec.begin(); + devit != mActiveDeviceVec.end() && cont_loop; + ++devit + ) { + if (devit->num >= 0) { + for (MemAddrRanges::iterator memrangeit = devit->addr_ranges.begin(); + memrangeit != devit->addr_ranges.end(); + ++memrangeit + ) { + if (addr >= memrangeit->start_addr && addr <= memrangeit->end_addr) { + WriteFunPtr pfun = devit->write_fun_ptr; + if (pfun != NULL) { + cont_loop = false; + (mpMemMapDev->*pfun)((int)addr,(int)val); + break; + } } } + mDispOp = (DEVNUM_GRDISP == devit->num); } } - mDispOp = (DEVNUM_GRDISP == dev.num); } - /* - if (mCharIOActive && addr == mCharIOAddr) - PutCharIO(val); - */ + if (!mROMActive || (addr < mROMBegin || addr > mROMEnd)) { m8bitMem[addr] = val; } @@ -319,7 +309,6 @@ void Memory::Poke8bitImg(unsigned short addr, unsigned char val) void Memory::SetCharIO(unsigned short addr, bool echo) { mCharIOAddr = addr; - //mCharIOActive = true; mIOEcho = echo; AddrRange addr_range(addr, addr+1); @@ -330,9 +319,9 @@ void Memory::SetCharIO(unsigned short addr, bool echo) dev_params.push_back(dev_par); memaddr_ranges.push_back(addr_range); - if (false == mCharIOActive) AddDevice(DEVNUM_CHARIO); - mCharIOActive = true; SetupDevice(DEVNUM_CHARIO, memaddr_ranges, dev_params); + if (false == mCharIOActive) AddDevice(DEVNUM_CHARIO); + mCharIOActive = true; } /* @@ -380,9 +369,9 @@ void Memory::SetGraphDisp(unsigned short addr) dev_params.push_back(dev_par); memaddr_ranges.push_back(addr_range); - if (false == mGraphDispActive) AddDevice(DEVNUM_GRDISP); - mGraphDispActive = true; SetupDevice(DEVNUM_GRDISP, memaddr_ranges, dev_params); + if (false == mGraphDispActive) AddDevice(DEVNUM_GRDISP); + mGraphDispActive = true; mpMemMapDev->ActivateGraphDisp(); } @@ -458,14 +447,49 @@ bool Memory::IsROMEnabled() * Method: AddDevice() * Purpose: Add device number to active devices list. * Arguments: devnum - device number - * Returns: 0 + * Returns: -1 if device is not supported OR already cached + * devnum - device number if it was found *-------------------------------------------------------------------- */ int Memory::AddDevice(int devnum) { - mActiveDevNumVec.push_back(devnum); + int ret = -1; + bool found = false; + Device dev = mpMemMapDev->GetDevice(devnum); + if (dev.num >= 0) { + for (vector::iterator devit = mActiveDeviceVec.begin(); + devit != mActiveDeviceVec.end(); + ++devit + ) { - return 0; + if (devit->num == devnum) { + found = true; + break; + } + } + // if device not found in local cache, add it + if (!found) { + mActiveDeviceVec.push_back(dev); + ret = devnum; + + // update the device usage flag in memory pages devices array mMemPageDev + for (MemAddrRanges::iterator memrangeit = dev.addr_ranges.begin(); + memrangeit != dev.addr_ranges.end(); + ++memrangeit + ) { + + int pgnum = memrangeit->start_addr / MEM_PAGE_SIZE; + while (pgnum < MEM_PAGE_SIZE) { + mMemPageDev[pgnum] = devnum; + pgnum++; + if (pgnum * MEM_PAGE_SIZE > memrangeit->end_addr) break; + } + } + } + } // END if (dev.num >= 0) + // else device with wuch number is not supported + + return ret; } /* @@ -473,25 +497,56 @@ int Memory::AddDevice(int devnum) * Method: DeleteDevice() * Purpose: Delete device number from active devices list. * Arguments: devnum - device number - * Returns: 0 + * Returns: >=0 if device was found in local cache and deleted + * -1 if device was not found *-------------------------------------------------------------------- */ int Memory::DeleteDevice(int devnum) { - vector active_new; + vector actdev_new; + int ret = -1; - for (vector::iterator it = mActiveDevNumVec.begin(); - it != mActiveDevNumVec.end(); - ++it - ) { - if (*it != devnum) { - active_new.push_back(*it); - } + for (int i=0; i < MEM_PAGE_SIZE; i++) { + mMemPageDev[i] = -1; } - mActiveDevNumVec.clear(); - mActiveDevNumVec = active_new; + // device is deleted by refreshing local active devices cache + // the device to be deleted is skipped and not re-added to refreshed + // cache vector + for (vector::iterator devit = mActiveDeviceVec.begin(); + devit != mActiveDeviceVec.end(); + ++devit + ) { - return 0; + if (devit->num != devnum) { + + Device dev = mpMemMapDev->GetDevice(devit->num); + + if (dev.num < 0) + throw MKGenException("Unsupported device in local cache"); + + actdev_new.push_back(mpMemMapDev->GetDevice(devit->num)); + + // update the device number in memory pages devices array mMemPageDev + for (MemAddrRanges::iterator memrangeit = devit->addr_ranges.begin(); + memrangeit != devit->addr_ranges.end(); + ++memrangeit + ) { + + int pgnum = memrangeit->start_addr / MEM_PAGE_SIZE; + while (pgnum < MEM_PAGE_SIZE) { + mMemPageDev[pgnum] = devit->num; + pgnum++; + if (pgnum * MEM_PAGE_SIZE > memrangeit->end_addr) break; + } + } + + } else ret++; // indicating that the device was found in cache + } + // refresh local active devices cache + mActiveDeviceVec.clear(); + mActiveDeviceVec = actdev_new; + + return ret; } /* @@ -508,14 +563,12 @@ void Memory::SetupDevice(int devnum, MemAddrRanges memranges, DevParams params) { - for (vector::iterator it = mActiveDevNumVec.begin(); - it != mActiveDevNumVec.end(); - ++it - ) { - if (devnum == *it) { - mpMemMapDev->SetupDevice(devnum, memranges, params); - break; - } + Device dev = mpMemMapDev->GetDevice(devnum); + if (dev.num >= 0) { + mpMemMapDev->SetupDevice(devnum, memranges, params); + // reload device to local vector because its setup has changed + // but only if device was cached locally already (active) + if (0 <= DeleteDevice(devnum)) AddDevice(devnum); } if (DEVNUM_CHARIO == devnum) { mCharIOAddr = mpMemMapDev->GetCharIOAddr(); diff --git a/Memory.h b/Memory.h index 6216001..2a48132 100644 --- a/Memory.h +++ b/Memory.h @@ -5,6 +5,7 @@ #include "MemMapDev.h" #define MAX_8BIT_ADDR 0xFFFF +#define MEM_PAGE_SIZE 0x100 #define ROM_BEGIN 0xD000 #define ROM_END 0xDFFF #define MIN_ROM_BEGIN 0x0200 @@ -54,14 +55,19 @@ class Memory private: unsigned char m8bitMem[MAX_8BIT_ADDR+1]; + // array of device usage for each memory page + // this is performance optimization array that keeps values >= 0 under the + // indexes of memory pages where the memory mapped device is active or -1 + // if there is no active device on given memory page + int mMemPageDev[MEM_PAGE_SIZE]; unsigned short mCharIOAddr; bool mCharIOActive; bool mIOEcho; unsigned short mROMBegin; unsigned short mROMEnd; bool mROMActive; - vector mActiveDevNumVec; // active devices numbers - MemMapDev *mpMemMapDev; // pointer to MemMapDev object + vector mActiveDeviceVec; // active devices + MemMapDev *mpMemMapDev; // pointer to MemMapDev object bool mGraphDispActive; bool mDispOp; diff --git a/ReadMe.txt b/ReadMe.txt index db257cd..48da66e 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -281,10 +281,23 @@ code and also emulated CPU Acc register contains the same code. Reading from IOADDR+1 inside 6502 code invokes a non-blocking character input function from user's DOS/shell session. -This function is different than blocking one in one respect. -This function will return value 0 in the memory location and Acc register -if there was no key pressed by the user (no character waiting in buffer). -If there was a key typed, the function will act as the blocking counterpart. + +The difference between blocking and non-blocking character input from 6502 +code perspective: + + - blocking + + Just read from the address. Emulated device will wait for the character + input. The 6502 code does not need to be polling the address for + a keystroke. + + - non-blocking + + If there is no character/keystroke in the keyboard buffer, the function + will move on returning the value of 0. If implementing waiting character + input in 6502 code with this function, the 6502 code needs to be polling + the value returned from this address in a loop until it is different + than 0. Note that there is no clearly distinguished prompt generated by emulator when there is character input operation performed. It is designed like that @@ -308,7 +321,7 @@ It is only written to the emulated display's text memory. When VM is running in non-debug code execution mode (X - execute from new address), the character is also output to the native DOS/shell console -(user's screen). +(user's screen, a.k.a. standard output). The character output history is therefore always kept in the memory of the emulated text display device and can be recalled to the screen in debug console with command 'T'. @@ -316,6 +329,7 @@ console with command 'T'. There are 2 reasons for this: * Performance. + In previous version only the emulated text display device approach was used. That meant that each time there was a new character in the emulated display buffer, the entire emulated text output device screen had to be refreshed on @@ -323,12 +337,16 @@ the DOS/shell console. That was slow and caused screen flicker when characters were output at high rate of speed. * Record of character I/O operation. + During step-by-step debugging or multiple-step animated registers mode, any characters output is immediately replaced by the registers and stack status -on the screen and is not visible on the screen. However user must be able to -debug applications that perform character I/O operations and recall the -history of the characters output to the emulated text display device. This is -when shadow copy of character I/O comes handy. +on the screen and is not visible on the screen. However user, while debugging +must be able to recall the history of the characters output to the emulated +text display device if user's program uses character I/O, for normal operation +or diagnostic purposes. This is when shadow copy of character I/O comes handy. +In real life, text output devices like text terminals, serial terminals, +especially the software emulated ones also offer the facilities to buffer the +output to memory for later review (history). 4. ROM (read-only memory) emulation. @@ -356,6 +374,13 @@ ROMEND address ENROM +For more sophisticated memory mapping schemes including multiple ROM ranges +and/or MMU-s that allow to read from ROM, write to RAM in the same range etc. +I suggest to write your ROM device emulating code and use it to expand the +functionality of this emulator using memory Mapped Devices framework, +explained later in this document and in the programmer's reference manual +document included with this project. + 5. Additional comments and remarks. IOADDR is permitted to be located in the emulated ROM memory range. @@ -380,7 +405,8 @@ The VMachine class calls the ExecOpcode() method as fast as possible, so it is not real-time accurate, as already mentioned. To implement real-time accurate emulation, the MKCpu::ExecOpcode() method calls would have to be synchronized to some fairly accurate time scale (some kind of timer thread or a different -solution). +solution) to emulate the timing on the bus signals level. This emulator does +not implement such level of accuracy. 6. Debugger Console Command Reference. @@ -432,7 +458,7 @@ V - toggle graphics display (video) emulation When enabled, window with graphics screen will open and several registers are available to control the device starting at provided base address. Read programmers reference for detailed documentation - regarding the available registers and their functions. + regarding the available registers and their functions. R - show registers Displays CPU registers, flags and stack. Y - snapshot @@ -468,7 +494,7 @@ K - toggle ROM emulation (read-only memory) will be mapped. Default range: $D000-$DFFF. L - load memory image Usage: L [image_type] [image_name] - Where: + Where: image_type - A - (auto), B (binary), H (Intel HEX) OR D (definition), image_name - name of the image file. This function allows to load new memory image from either binary @@ -478,7 +504,7 @@ L - load memory image The binary image is always loaded from address 0x0000 and can be up to 64kB long. The definition file format is a plain text file that can contain following keywords and data: - + ADDR This keyword defines the run address of the executable code. It is optional, but if exists, it must be the 1-st keyword in the definition file. @@ -523,11 +549,32 @@ L - load memory image in decimal or hexadecimal format. RESET Enables auto-reset of the CPU. After loading the memory - definition file, the CPU reset sequence will be initiated. + definition file, the CPU reset sequence will be initiated. + + ENGRAPH Enables raster graphics device emulation. + + GRAPHADDR Defines the base address of raster graphics device. The next + line that follows sets the address in decimal or hexadecimal + format. + + NOTE: The binary image file can contain a header which contains + definitions corresponding to the above parameters at fixed + positions. This header is created when user saves the snapshot of + current emulator memory image and status. Example use scenario: + * User loads the image definition file. + * User adjusts various parameters of the emulator + (enables/disables devices, sets addresses, changes memory + contents). + * User saves the snapshot with 'Y' command. + * Next time user loads the snapshot image, all the parameters + and memory contents stick. This way game status can be saved + or a BASIC interpreter with BASIC program in it. + See command 'Y' for details. O - display op-codes history Show the history of last executed op-codes/instructions, full with - disassembled mnemonic and argument. + disassembled mnemonic, argument and CPU registers and status. + NOTE: op-codes execute history must be enabled, see command 'U'. D - diassemble code in memory Usage: D [startaddr] [endaddr] Where: startaddr,endaddr - hexadecimal address [0000..FFFF]. @@ -543,6 +590,11 @@ D - diassemble code in memory jumping to main loop. The reset routine disables trapping last RTS opcode if stack is empty, so the VM will never return from opcodes execution loop unless user interrupts with CTRL-C or CTRL-Break. +? - display commands menu + Display the menu of all available in Debug Console commands. +U - enable/disable exec. history + Toggle enable/disable of op-codes execute history. + Disabling this feature improves performance. NOTE: 1. If no arguments provided, each command will prompt user to enter @@ -551,7 +603,7 @@ NOTE: by pressing CTRL-C or CTRL-Pause/Break, which will generate a "Operator Interrupt". However in the character input mode use CTRL-Y combination or CTRL-Break (DOS), CTRL-C (Linux). - You may need to press ENTER after that in input mode (DOS) + You may need to press ENTER after that in input mode (DOS). 7. Command line usage. @@ -628,8 +680,8 @@ Programming API responsible for modeling this functionality is implemented in Memory and MemMapDev classes. The Memory class implements access to specific memory locations and maintains the memory image. The MemMapDev class implements specific device address spaces and handling -methods that are triggered when addresses of the device are accessed by the -microprocessor. +methods that are triggered when addresses that belong to the device are +accessed by the microprocessor. Programmers can expand the functionality of this emulator by adding necessary code emulating specific devices in MemMapDev and Memory classes implementation and header files. In current version, two basic devices are implemented: @@ -640,7 +692,7 @@ E.g.: Character I/O device uses just 2 memory locations, one for non-blocking I/O and one for blocking I/O. Writing to location causes character output, while reading from location waits for character input (blocking mode) or reads the -character from keyboard buffer if available (non-blocking mode). +character from keyboard buffer if available (non-blocking mode) or returns 0. The graphics display can be accessed by writing to multiple memory locations. If we assume that GRDEVBASE is the base address of the Graphics Device, there @@ -685,7 +737,7 @@ Reading from registers has no effect (returns 0). Above method of interfacing GD requires no dedicated graphics memory space in VM's RAM. It is also simple to implement. -The downside - slow performance (multiple memory writes to select/unselect +The downside - slower performance (multiple memory writes to select/unselect a pixel or set color). I plan to add graphics frame buffer in the VM's RAM address space in future release. @@ -693,7 +745,67 @@ release. Simple demo program written in EhBasic that shows how to drive the graphics screen is included: grdevdemo.bas. -10. Problems, issues, bugs. +10. Performance considerations. + +Program measures the emulation performance and displays it in the Debug +Console. It uses a 1 MHz CPU as a reference to return % of speed compared to +assumed 1,000,000 CPU cycles or clock ticks per second - which is considered +a 100 % speed. +Performance is measured during the whole execution cycle and calculated at the +end of the run. Captured speed is summed with previous result and divided by 2 +to produce average emulation speed during single session. + +This emulator has been optimized for performance. I had issues with +emulation speed in previous version, but I took a good look at all the +critical parts of code and fixed the problems. I am sure there is still +space for improvement, but now the emulation speed leaves good margin +for expansion with new emulated peripherals and still should compare +well to the model 1 MHz CPU. +Emulating of pure 6502 machine code with all peripherals (memory mapped +devices, I/O etc.) emulation disabled and time critical debugging facility, +the op-codes execute history also disabled, returns performance in range of +646 % (PC1) and 468 % (PC2) (* see annotation below). +Enabling the op-code execute history drops the performance. +With all peripherals disabled and op-code history enabled we are down to +411 % on PC1 and 312 % on PC2. + +Enabling and adding the emulated memory mapped devices to the pool may cause +the emulation speed to drop as well. Hovever even with currently implemented +peripherals (char I/O, graphics raster device) enabled and actively used and +op-codes execute history enabled the performance is still well above 300 % +on both PC1 and on PC2 (* see annotations for PC configurations/specs). +The same case but with op-code execute history disabled - performance exceeds +400 % on both PC configurations. + +Currently the main emulation loop is not synchronized to an accurate +clock tick or raster synchronization signal but just runs as fast as it can. +Therefore emulation speed may vary per PC and per current load on the system. + +If this code is to be used as a template to implement emulator of a real-world +machine, like C-64 or Apple I, it may need some work to improve performance, +but I think is leaves a pretty good margin for expansion as it is. +On a fast PC (* see annotation) the emulation speed above 600 % with +basically nothing but CPU emulated and op-codes execute history disabled +(which should be disabled by default as it is needed for debugging purposes +only) is IMO decent if we don't want to emulate MOS 6502 machine with clock +much faster than 1 MHz. + +Annotations to 'Performance considerations': +*) + +PC1 stats: +Type: Desktop +CPU: 2.49 GHz (64-bit Quad-core Q8300) +RAM: 4,060 MB +OS: Windows 10 Pro (no SP) [6.2.9200] + +PC2 stats: +Type: Laptop +CPU: 2.3 GHz (64-bit Quad-core i5-6300HQ) +RAM: 15.9 GB +OS: Win 10 Home. + +11. Problems, issues, bugs. * Regaining focus of the graphics window when it is not being written to by the 6502 code is somewhat flakey. Since the window has no title bar, user can @@ -702,7 +814,7 @@ screen is included: grdevdemo.bas. of emulator while in emulation mode should bring the graphics window back to front. -11. Warranty and License Agreement. +12. Warranty and License Agreement. This software is provided with No Warranty. I (The Author) will not be held responsible for any damage to computer diff --git a/VMachine.cpp b/VMachine.cpp index 991ab9b..592b734 100644 --- a/VMachine.cpp +++ b/VMachine.cpp @@ -81,6 +81,11 @@ void VMachine::InitVM() mOpInterrupt = false; mpRAM = new Memory(); + mPerfStats.cycles = 0; + mPerfStats.micro_secs = 0; + mPerfStats.perf_onemhz = 0; + mPerfStats.prev_cycles = 0; + mPerfStats.prev_usec = 0; mOldStyleHeader = false; mError = VMERR_OK; mAutoExec = false; @@ -225,6 +230,39 @@ void VMachine::ShowDisp() } } + +/* + *-------------------------------------------------------------------- + * Method: + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +int VMachine::CalcCurrPerf() +{ + auto lap = high_resolution_clock::now(); + auto beg = mPerfStats.begin_time; + mPerfStats.micro_secs = duration_cast(lap-beg).count(); + + if (mPerfStats.micro_secs > 0) { + int currperf = (int) + (((double)mPerfStats.cycles / (double)mPerfStats.micro_secs) * 100.0); + if (mPerfStats.perf_onemhz == 0) + mPerfStats.perf_onemhz = currperf; + else + mPerfStats.perf_onemhz = (mPerfStats.perf_onemhz + currperf) / 2; + + mPerfStats.prev_cycles = mPerfStats.cycles; + mPerfStats.prev_usec = mPerfStats.micro_secs; + mPerfStats.cycles = 0; + mPerfStats.micro_secs = 0; + mPerfStats.begin_time = high_resolution_clock::now(); + } + + return mPerfStats.perf_onemhz; +} + /* *-------------------------------------------------------------------- * Method: Run() @@ -240,14 +278,17 @@ Regs *VMachine::Run() mOpInterrupt = false; ClearScreen(); ShowDisp(); + mPerfStats.cycles = 0; + mPerfStats.micro_secs = 0; + mPerfStats.begin_time = high_resolution_clock::now(); while (true) { + mPerfStats.cycles++; cpureg = Step(); - if (cpureg->CyclesLeft == 0 && mCharIO) { - ShowDisp(); - } - if (cpureg->SoftIrq || mOpInterrupt) - break; + if (cpureg->CyclesLeft == 0 && mCharIO) ShowDisp(); + if (cpureg->SoftIrq || mOpInterrupt) break; + //if (mPerfStats.cycles == PERFSTAT_INTERVAL) CalcCurrPerf(); } + CalcCurrPerf(); ShowDisp(); @@ -285,20 +326,39 @@ Regs *VMachine::Exec() mOpInterrupt = false; ClearScreen(); ShowDisp(); + mPerfStats.cycles = 0; + mPerfStats.micro_secs = 0; + mPerfStats.begin_time = high_resolution_clock::now(); while (true) { + mPerfStats.cycles++; cpureg = Step(); if (cpureg->CyclesLeft == 0 && mCharIO) { cout << mpDisp->GetLastChar(); cout << flush; } if (cpureg->LastRTS || mOpInterrupt) break; + //if (mPerfStats.cycles == PERFSTAT_INTERVAL) CalcCurrPerf(); } + CalcCurrPerf(); ShowDisp(); return cpureg; } +/* + *-------------------------------------------------------------------- + * Method: + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +PerfStats VMachine::GetPerfStats() +{ + return mPerfStats; +} + /* *-------------------------------------------------------------------- * Method: Exec() @@ -327,7 +387,9 @@ Regs *VMachine::Step() Regs *cpureg = NULL; cpureg = mpCPU->ExecOpcode(addr); - if (mGraphDispActive) mpRAM->GraphDisp_ReadEvents(); + if (mGraphDispActive && cpureg->CyclesLeft == 0) { + mpRAM->GraphDisp_ReadEvents(); + } addr = cpureg->PtrAddr; mRunAddr = addr; @@ -1619,4 +1681,30 @@ int VMachine::GetLastError() return ret; } +/* + *-------------------------------------------------------------------- + * Method: + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +void VMachine::EnableExecHistory(bool enexehist) +{ + mpCPU->EnableExecHistory(enexehist); +} + +/* + *-------------------------------------------------------------------- + * Method: + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +bool VMachine::IsExecHistoryActive() +{ + return mpCPU->IsExecHistoryEnabled(); +} + } // namespace MKBasic diff --git a/VMachine.h b/VMachine.h index 0411dc7..8feeb22 100644 --- a/VMachine.h +++ b/VMachine.h @@ -3,6 +3,7 @@ #include #include +#include #include "system.h" #include "MKCpu.h" #include "Memory.h" @@ -20,8 +21,10 @@ #define HDRDATALEN 128 #define HDRDATALEN_OLD 15 #define HEXEOF ":00000001FF" +//#define PERFSTAT_INTERVAL 30000000 using namespace std; +using namespace chrono; namespace MKBasic { @@ -63,6 +66,16 @@ enum eVMErrors { VMERR_UNKNOWN // unknown error }; +struct PerfStats { + time_point + begin_time; // the moment of time count start + long cycles; // performance stats + long micro_secs; // performance stats + long prev_cycles; // previously measured stats + long prev_usec; // previously measured stats + int perf_onemhz; // avg. % perf. based on 1MHz CPU. +}; + class VMachine { public: @@ -113,7 +126,12 @@ class VMachine int GetLastError(); void SetGraphDisp(unsigned short addr); void DisableGraphDisp(); - unsigned short GetGraphDispAddr(); + unsigned short GetGraphDispAddr(); + PerfStats GetPerfStats(); // returns performance stats based on 1 million + // cycles per second (1 MHz CPU). + void EnableExecHistory(bool enexehist); + bool IsExecHistoryActive(); + protected: @@ -133,6 +151,7 @@ class VMachine int mError; // last error code bool mGraphDispActive; bool mOldStyleHeader; + PerfStats mPerfStats; int LoadMEM(string memfname, Memory *pmem); void ShowDisp(); @@ -141,6 +160,7 @@ class VMachine bool LoadHdrData(FILE *fp); void SaveHdrData(FILE *fp); eMemoryImageTypes GetMemoryImageType(string ramfname); + int CalcCurrPerf(); }; } // namespace MKBasic diff --git a/ehbas_grdemo_loop.snap b/ehbas_grdemo_loop.snap new file mode 100644 index 0000000000000000000000000000000000000000..10c445e43da370cbd19311f2c42f86e441f879b9 GIT binary patch literal 65673 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 literal 0 HcmV?d00001 diff --git a/ehbas_nogrdev.dat b/ehbas_nogrdev.dat new file mode 100644 index 0000000..a272dbd --- /dev/null +++ b/ehbas_nogrdev.dat @@ -0,0 +1,2074 @@ +; Program disassembly from $C000 to $FFDF 3/4/2016 +; EhBasic image for MKBASIC 6502 simulator. +; +ORG +$C000 +; Char IO +IOADDR +$FFE0 +; ROM +ROMBEGIN +$FFC0 +ROMEND +$FFFF +;$FFDF +; Enable char IO and ROM +ENIO +ENROM +; Enable generic graphics display +; and set its base address. +; ENGRAPH +;GRAPHADDR +;$FFE2 +; Auto-execute +;EXEC +;$C000 +RESET +; Data/Code +$D8, $A0, $08, $B9, $FB, $E0, $99, $00 +$02, $88, $10, $F7, $A2, $FF, $8E, $21 +$02, $86, $88, $9A, $A9, $4C, $85, $A1 +$A2, $1C, $BD, $03, $E1, $95, $BB, $CA +$D0, $F8, $A2, $12, $BD, $20, $E1, $95 +$00, $CA, $10, $F8, $A9, $00, $85, $DC +$85, $DF, $85, $B2, $85, $67, $A9, $0E +$85, $64, $A9, $03, $85, $A0, $A2, $68 +$86, $65, $20, $97, $C8, $A9, $33, $A0 +$E1, $20, $D8, $C8, $20, $45, $C2, $86 +$C3, $84, $C4, $20, $C2, $00, $D0, $1F +$A0, $00, $E6, $11, $D0, $08, $E6, $12 +$A5, $12, $C9, $C0, $F0, $1D, $A9, $55 +$91, $11, $D1, $11, $D0, $15, $0A, $91 +$11, $D1, $11, $F0, $E5, $D0, $0C, $20 +$AB, $D9, $A5, $AC, $C9, $98, $B0, $A2 +$20, $FC, $D4, $A5, $11, $A4, $12, $C0 +$01, $90, $97, $85, $85, $84, $86, $85 +$81, $84, $82, $A0, $00, $A2, $03, $84 +$79, $86, $7A, $98, $91, $79, $E6, $79 +$20, $97, $C8, $20, $55, $C3, $A5, $85 +$38, $E5, $79, $AA, $A5, $86, $E5, $7A +$20, $87, $DA, $A9, $42, $A0, $E1, $20 +$D8, $C8, $A9, $5E, $A0, $C1, $85, $01 +$84, $02, $6C, $01, $00, $20, $0F, $C1 +$85, $7F, $84, $80, $38, $A5, $A6, $E5 +$AA, $A8, $A5, $A7, $E5, $AB, $AA, $E8 +$98, $F0, $24, $38, $49, $FF, $65, $A6 +$85, $A6, $B0, $03, $C6, $A7, $38, $98 +$49, $FF, $65, $A4, $85, $A4, $B0, $08 +$C6, $A5, $90, $04, $B1, $A6, $91, $A4 +$88, $D0, $F9, $B1, $A6, $91, $A4, $C6 +$A7, $C6, $A5, $CA, $D0, $F2, $60, $85 +$78, $BA, $E4, $78, $90, $30, $60, $C4 +$82, $90, $2A, $D0, $04, $C5, $81, $90 +$24, $48, $A2, $08, $98, $48, $B5, $A3 +$CA, $10, $FA, $20, $E4, $D1, $A2, $00 +$68, $95, $A4, $E8, $E0, $08, $30, $F8 +$68, $A8, $68, $C4, $82, $90, $06, $D0 +$05, $C5, $81, $B0, $01, $60, $A2, $0C +$20, $97, $C8, $BD, $B2, $E6, $BC, $B3 +$E6, $20, $D8, $C8, $20, $8E, $C3, $A9 +$EF, $A0, $E7, $20, $D8, $C8, $A4, $88 +$C8, $F0, $03, $20, $7C, $DA, $A9, $00 +$85, $DF, $85, $DC, $A9, $00, $A0, $E8 +$20, $D8, $C8, $18, $20, $52, $C2, $86 +$C3, $84, $C4, $20, $C2, $00, $F0, $F4 +$A2, $FF, $86, $88, $90, $06, $20, $83 +$C2, $4C, $F8, $C4, $20, $5A, $C7, $20 +$83, $C2, $84, $5D, $20, $29, $C3, $90 +$44, $A0, $01, $B1, $AA, $85, $72, $A5 +$7B, $85, $71, $A5, $AB, $85, $74, $A5 +$AA, $88, $F1, $AA, $18, $65, $7B, $85 +$7B, $85, $73, $A5, $7C, $69, $FF, $85 +$7C, $E5, $AB, $AA, $38, $A5, $AA, $E5 +$7B, $A8, $B0, $03, $E8, $C6, $74, $18 +$65, $71, $90, $03, $C6, $72, $18, $B1 +$71, $91, $73, $C8, $D0, $F9, $E6, $72 +$E6, $74, $CA, $D0, $F2, $AD, $21, $02 +$F0, $3F, $A5, $85, $A4, $86, $85, $81 +$84, $82, $A5, $7B, $85, $A6, $A4, $7C +$84, $A7, $65, $5D, $90, $01, $C8, $85 +$A4, $84, $A5, $20, $C5, $C0, $A5, $7F +$A4, $80, $85, $7B, $84, $7C, $A4, $5D +$88, $B9, $1D, $02, $91, $AA, $88, $C0 +$03, $D0, $F6, $A5, $12, $91, $AA, $88 +$A5, $11, $91, $AA, $88, $A9, $FF, $91 +$AA, $20, $6A, $C3, $A6, $79, $A5, $7A +$A0, $01, $86, $71, $85, $72, $B1, $71 +$F0, $18, $A0, $04, $C8, $B1, $71, $D0 +$FB, $38, $98, $65, $71, $AA, $A0, $00 +$91, $71, $98, $65, $72, $C8, $91, $71 +$90, $E0, $4C, $6C, $C1, $20, $F0, $C8 +$20, $ED, $C8, $D0, $05, $20, $F2, $C8 +$CA, $2C, $A2, $00, $20, $EF, $E0, $90 +$FB, $F0, $F9, $C9, $07, $F0, $10, $C9 +$0D, $F0, $19, $E0, $00, $D0, $04, $C9 +$21, $90, $E9, $C9, $08, $F0, $DE, $E0 +$47, $B0, $0C, $9D, $21, $02, $E8, $20 +$F2, $C8, $D0, $D8, $4C, $8E, $C8, $A9 +$07, $D0, $F4, $A0, $FF, $38, $A5, $C3 +$E9, $21, $AA, $86, $60, $BD, $21, $02 +$F0, $51, $C9, $5F, $B0, $4D, $C9, $3C +$B0, $0E, $C9, $30, $B0, $45, $85, $5C +$C9, $22, $F0, $61, $C9, $2A, $90, $3B +$24, $60, $70, $37, $86, $78, $84, $BA +$A0, $19, $84, $73, $A0, $E3, $84, $74 +$A0, $00, $D1, $73, $F0, $05, $90, $21 +$C8, $D0, $F7, $98, $0A, $AA, $BD, $37 +$E3, $85, $73, $BD, $38, $E3, $85, $74 +$A0, $FF, $A6, $78, $C8, $B1, $73, $30 +$08, $E8, $DD, $21, $02, $F0, $F5, $D0 +$2B, $A4, $BA, $E8, $C8, $99, $21, $02 +$C9, $00, $F0, $32, $E9, $3A, $F0, $04 +$C9, $49, $D0, $02, $85, $60, $49, $57 +$D0, $93, $85, $5C, $BD, $21, $02, $F0 +$E2, $C5, $5C, $F0, $DE, $C8, $99, $21 +$02, $E8, $D0, $F0, $A6, $78, $B1, $73 +$08, $C8, $28, $10, $F9, $B1, $73, $D0 +$BE, $BD, $21, $02, $10, $C3, $C8, $C8 +$99, $21, $02, $C8, $C8, $C8, $C6, $C3 +$60, $A5, $79, $A6, $7A, $A0, $01, $85 +$AA, $86, $AB, $B1, $AA, $F0, $1A, $A0 +$03, $B1, $AA, $88, $C5, $12, $D0, $04 +$B1, $AA, $C5, $11, $B0, $09, $88, $B1 +$AA, $AA, $88, $B1, $AA, $90, $DE, $F0 +$01, $18, $60, $D0, $FD, $A9, $00, $A8 +$91, $79, $C8, $91, $79, $18, $A5, $79 +$69, $02, $85, $7B, $A5, $7A, $69, $00 +$85, $7C, $18, $A5, $79, $69, $FF, $85 +$C3, $A5, $7A, $69, $FF, $85, $C4, $A5 +$85, $A4, $86, $85, $81, $84, $82, $A5 +$7B, $A4, $7C, $85, $7D, $84, $7E, $85 +$7F, $84, $80, $20, $49, $C5, $A2, $68 +$86, $65, $68, $AA, $68, $8E, $FE, $01 +$8D, $FF, $01, $A2, $FD, $9A, $A9, $00 +$85, $8C, $85, $61, $60, $F0, $D0, $60 +$90, $06, $F0, $04, $C9, $B7, $D0, $F4 +$20, $5A, $C7, $20, $29, $C3, $20, $C2 +$00, $F0, $0C, $C9, $B7, $D0, $93, $20 +$BC, $00, $20, $5A, $C7, $D0, $8B, $A5 +$11, $05, $12, $D0, $06, $A9, $FF, $85 +$11, $85, $12, $A0, $01, $84, $60, $20 +$97, $C8, $B1, $AA, $F0, $3E, $20, $19 +$C5, $C8, $B1, $AA, $AA, $C8, $B1, $AA +$C5, $12, $D0, $04, $E4, $11, $F0, $02 +$B0, $2A, $84, $97, $20, $87, $DA, $A9 +$20, $A4, $97, $29, $7F, $20, $F2, $C8 +$C9, $22, $D0, $06, $A5, $60, $49, $FF +$85, $60, $C8, $B1, $AA, $D0, $0E, $A8 +$B1, $AA, $AA, $C8, $B1, $AA, $86, $AA +$85, $AB, $D0, $B7, $60, $10, $DE, $24 +$60, $30, $DA, $A2, $E5, $0A, $0A, $90 +$02, $E8, $18, $69, $1A, $90, $01, $E8 +$85, $73, $86, $74, $84, $97, $A0, $00 +$B1, $73, $AA, $C8, $B1, $73, $CA, $F0 +$B8, $20, $F2, $C8, $C8, $B1, $73, $48 +$C8, $B1, $73, $A0, $00, $85, $74, $68 +$85, $73, $B1, $73, $CA, $F0, $A2, $20 +$F2, $C8, $C8, $D0, $F5, $A9, $80, $85 +$61, $20, $B9, $C7, $68, $68, $A9, $10 +$20, $07, $C1, $20, $A2, $C6, $18, $98 +$65, $C3, $48, $A5, $C4, $69, $00, $48 +$A5, $88, $48, $A5, $87, $48, $A9, $AD +$20, $F6, $CB, $20, $D5, $CA, $20, $D2 +$CA, $A5, $B0, $09, $7F, $25, $AD, $85 +$AD, $A9, $9C, $A0, $C4, $85, $71, $84 +$72, $4C, $89, $CB, $A9, $E9, $A0, $E1 +$20, $82, $D8, $20, $C2, $00, $C9, $B2 +$D0, $06, $20, $BC, $00, $20, $D2, $CA +$20, $EE, $D8, $85, $B0, $20, $7E, $CB +$A5, $98, $48, $A5, $97, $48, $A9, $81 +$48, $20, $19, $C5, $A5, $C3, $A4, $C4 +$A6, $88, $E8, $F0, $04, $85, $8B, $84 +$8C, $A0, $00, $B1, $C3, $F0, $07, $C9 +$3A, $F0, $1D, $4C, $07, $CC, $A0, $02 +$B1, $C3, $18, $F0, $56, $C8, $B1, $C3 +$85, $87, $C8, $B1, $C3, $85, $88, $98 +$65, $C3, $85, $C3, $90, $02, $E6, $C4 +$20, $BC, $00, $20, $01, $C5, $4C, $C1 +$C4, $F0, $54, $0A, $B0, $03, $4C, $B9 +$C7, $C9, $56, $B0, $CE, $A8, $B9, $11 +$E2, $48, $B9, $10, $E2, $48, $4C, $BC +$00, $6C, $03, $02, $C9, $03, $B0, $01 +$18, $D0, $67, $A5, $C4, $49, $02, $F0 +$10, $49, $02, $A4, $C3, $84, $8B, $85 +$8C, $A5, $87, $A4, $88, $85, $89, $84 +$8A, $68, $68, $90, $07, $A9, $E7, $A0 +$E7, $4C, $53, $C1, $4C, $5E, $C1, $D0 +$0F, $38, $A5, $79, $E9, $01, $A4, $7A +$B0, $01, $88, $85, $8F, $84, $90, $60 +$20, $5A, $C7, $20, $A5, $C6, $A5, $88 +$C5, $12, $B0, $0B, $98, $38, $65, $C3 +$A6, $C4, $90, $07, $E8, $B0, $04, $A5 +$79, $A6, $7A, $20, $2D, $C3, $B0, $03 +$4C, $77, $C6, $A5, $AA, $E9, $01, $A4 +$AB, $B0, $D0, $90, $CD, $20, $91, $D4 +$86, $0D, $60, $D0, $FD, $A4, $8C, $D0 +$05, $A2, $1E, $4C, $40, $C1, $A9, $93 +$20, $19, $DF, $A9, $93, $20, $1C, $DF +$84, $C4, $A5, $8B, $85, $C3, $A5, $89 +$A4, $8A, $85, $87, $84, $88, $60, $D0 +$03, $4C, $6A, $C3, $20, $77, $C3, $F0 +$2E, $A9, $05, $20, $07, $C1, $A5, $C4 +$48, $A5, $C3, $48, $A5, $88, $48, $A5 +$87, $48, $A9, $9D, $48, $20, $C2, $00 +$4C, $C1, $C4, $A9, $05, $20, $07, $C1 +$A5, $C4, $48, $A5, $C3, $48, $A5, $88 +$48, $A5, $87, $48, $A9, $8D, $48, $20 +$C2, $00, $20, $F0, $C5, $4C, $C1, $C4 +$20, $5A, $C7, $20, $A5, $C6, $A5, $88 +$C5, $12, $B0, $0B, $98, $38, $65, $C3 +$A6, $C4, $90, $07, $E8, $B0, $04, $A5 +$79, $A6, $7A, $20, $2D, $C3, $90, $67 +$A5, $AA, $E9, $01, $85, $C3, $A5, $AB +$E9, $00, $85, $C4, $60, $A2, $22, $4C +$40, $C1, $A8, $BA, $BD, $03, $01, $C9 +$9D, $D0, $F2, $E8, $E8, $9A, $98, $F0 +$20, $C9, $3A, $F0, $1C, $E9, $B3, $AA +$F0, $04, $CA, $D0, $62, $CA, $86, $98 +$20, $BC, $00, $20, $E6, $CA, $A5, $AC +$F0, $02, $A9, $FF, $BA, $45, $98, $D0 +$1A, $BD, $02, $01, $85, $87, $BD, $03 +$01, $85, $88, $BD, $04, $01, $85, $C3 +$BD, $05, $01, $85, $C4, $20, $C2, $00 +$4C, $C1, $C4, $E8, $E8, $E8, $E8, $E8 +$9A, $4C, $91, $C6, $A2, $04, $2C, $A2 +$0E, $4C, $40, $C1, $D0, $9E, $68, $68 +$68, $C9, $8D, $D0, $EF, $68, $85, $87 +$68, $85, $88, $68, $85, $C3, $68, $85 +$C4, $20, $A2, $C6, $98, $18, $65, $C3 +$85, $C3, $90, $02, $E6, $C4, $60, $4C +$07, $CC, $A2, $3A, $2C, $A2, $00, $A0 +$00, $84, $5C, $8A, $45, $5C, $85, $5C +$B1, $C3, $F0, $EA, $C5, $5C, $F0, $E6 +$C8, $C9, $22, $D0, $F3, $F0, $EC, $20 +$E6, $CA, $20, $C2, $00, $C9, $B0, $F0 +$11, $C9, $89, $D0, $D2, $A6, $C3, $A4 +$C4, $20, $BC, $00, $B0, $C9, $86, $C3 +$84, $C4, $A5, $AC, $F0, $1B, $20, $BC +$00, $B0, $03, $4C, $F0, $C5, $C9, $90 +$D0, $03, $4C, $03, $C5, $20, $01, $C5 +$A0, $00, $B1, $C3, $C9, $AC, $F0, $99 +$60, $A0, $00, $A2, $01, $C8, $B1, $C3 +$F0, $0F, $C9, $8B, $D0, $03, $E8, $D0 +$F4, $C9, $AC, $D0, $F0, $CA, $D0, $ED +$C8, $98, $18, $65, $C3, $85, $C3, $90 +$02, $E6, $C4, $20, $C2, $00, $90, $C3 +$4C, $01, $C5, $20, $A5, $C6, $4C, $94 +$C6, $4C, $07, $CC, $C9, $A9, $D0, $03 +$4C, $3D, $DF, $C9, $AA, $D0, $03, $4C +$41, $DF, $20, $91, $D4, $48, $C9, $8D +$F0, $04, $C9, $89, $D0, $E3, $C6, $AF +$D0, $04, $68, $4C, $03, $C5, $20, $BC +$00, $20, $5A, $C7, $C9, $2C, $F0, $EE +$68, $60, $A2, $00, $86, $11, $86, $12 +$B0, $F7, $E0, $19, $A8, $B0, $DD, $E9 +$2F, $A8, $A5, $11, $0A, $26, $12, $0A +$26, $12, $65, $11, $85, $11, $8A, $65 +$12, $06, $11, $2A, $AA, $98, $65, $11 +$85, $11, $90, $01, $E8, $20, $BC, $00 +$4C, $5E, $C7, $A9, $ED, $2C, $A9, $E9 +$48, $20, $AF, $CD, $A6, $5F, $30, $1E +$85, $97, $84, $98, $20, $82, $D8, $68 +$48, $A0, $E1, $20, $C3, $D5, $20, $A8 +$D8, $20, $C2, $00, $C9, $2C, $D0, $A8 +$20, $BC, $00, $4C, $91, $C7, $4C, $E1 +$CA, $20, $AF, $CD, $85, $97, $84, $98 +$A9, $C1, $20, $F6, $CB, $A5, $5F, $48 +$20, $E6, $CA, $68, $2A, $20, $D8, $CA +$D0, $03, $4C, $A8, $D8, $A0, $02, $B1 +$AE, $C5, $82, $90, $17, $D0, $07, $88 +$B1, $AE, $C5, $81, $90, $0E, $A4, $AF +$C4, $7C, $90, $08, $D0, $0D, $A5, $AE +$C5, $7B, $B0, $07, $A5, $AE, $A4, $AF +$4C, $11, $C8, $A0, $00, $B1, $AE, $20 +$37, $D1, $A5, $9E, $A4, $9F, $85, $B8 +$84, $B9, $20, $16, $D3, $A9, $AC, $A0 +$00, $85, $9E, $84, $9F, $20, $78, $D3 +$A0, $00, $B1, $9E, $91, $97, $C8, $B1 +$9E, $91, $97, $C8, $B1, $9E, $91, $97 +$60, $20, $AF, $CD, $85, $97, $84, $98 +$20, $05, $DF, $A6, $5F, $30, $07, $A8 +$20, $6B, $D0, $4C, $A8, $D8, $48, $A9 +$01, $B0, $01, $68, $20, $3F, $D1, $F0 +$05, $68, $A0, $00, $91, $AD, $20, $8A +$D1, $4C, $D5, $C7, $20, $DB, $C8, $20 +$C2, $00, $F0, $3B, $C9, $AB, $F0, $56 +$C9, $AF, $F0, $52, $C9, $2C, $F0, $38 +$C9, $3B, $F0, $66, $20, $E6, $CA, $24 +$5F, $30, $E1, $20, $9A, $DA, $20, $49 +$D1, $A0, $00, $A5, $0F, $F0, $0A, $38 +$E5, $0E, $F1, $AE, $B0, $03, $20, $97 +$C8, $20, $DB, $C8, $F0, $C9, $A9, $00 +$9D, $21, $02, $A2, $21, $A0, $02, $A9 +$0D, $20, $F2, $C8, $A9, $0A, $D0, $52 +$A5, $0E, $C5, $10, $90, $05, $20, $97 +$C8, $D0, $27, $38, $E5, $64, $B0, $FC +$49, $FF, $69, $01, $D0, $12, $48, $20 +$8E, $D4, $C9, $29, $D0, $7B, $68, $C9 +$AB, $D0, $06, $8A, $E5, $0E, $90, $0A +$AA, $8A, $F0, $06, $20, $ED, $C8, $CA +$D0, $FA, $20, $BC, $00, $D0, $85, $60 +$20, $49, $D1, $20, $43, $D3, $A0, $00 +$AA, $F0, $49, $B1, $71, $20, $F2, $C8 +$C8, $CA, $D0, $F7, $60, $A9, $20, $2C +$A9, $3F, $C9, $20, $90, $19, $48, $A5 +$0F, $D0, $0A, $A5, $0E, $E5, $64, $D0 +$0B, $85, $0E, $F0, $07, $C5, $0E, $D0 +$03, $20, $97, $C8, $E6, $0E, $68, $20 +$F2, $E0, $C9, $0D, $D0, $14, $86, $78 +$A6, $0D, $F0, $0A, $A9, $00, $20, $F2 +$C8, $CA, $D0, $FA, $A9, $0D, $86, $0E +$A6, $78, $29, $FF, $60, $A5, $62, $10 +$0B, $A5, $8D, $A4, $8E, $85, $87, $84 +$88, $4C, $07, $CC, $A9, $1B, $A0, $E8 +$20, $D8, $C8, $A5, $8B, $A4, $8C, $85 +$C3, $84, $C4, $60, $C9, $22, $D0, $0B +$20, $C3, $CB, $A9, $3B, $20, $F6, $CB +$20, $DB, $C8, $20, $6F, $D0, $20, $45 +$C2, $A9, $00, $CD, $21, $02, $D0, $0A +$18, $4C, $31, $C5, $A6, $8F, $A4, $90 +$A9, $80, $85, $62, $86, $91, $84, $92 +$20, $AF, $CD, $85, $97, $84, $98, $A5 +$C3, $A4, $C4, $85, $11, $84, $12, $A6 +$91, $A4, $92, $86, $C3, $84, $C4, $20 +$C2, $00, $D0, $11, $24, $62, $30, $65 +$20, $F0, $C8, $20, $45, $C2, $86, $C3 +$84, $C4, $20, $C2, $00, $24, $5F, $10 +$24, $85, $5B, $C9, $22, $F0, $07, $A9 +$3A, $85, $5B, $A9, $2C, $18, $85, $5C +$A5, $C3, $A4, $C4, $69, $00, $90, $01 +$C8, $20, $4F, $D1, $20, $D4, $D4, $20 +$D5, $C7, $4C, $D3, $C9, $20, $AB, $D9 +$20, $A8, $D8, $20, $C2, $00, $F0, $0A +$C9, $2C, $F0, $03, $4C, $2D, $C9, $20 +$BC, $00, $A5, $C3, $A4, $C4, $85, $91 +$84, $92, $A5, $11, $A4, $12, $85, $C3 +$84, $C4, $20, $C2, $00, $F0, $2C, $20 +$03, $CC, $4C, $78, $C9, $20, $A2, $C6 +$C8, $AA, $D0, $12, $A2, $06, $C8, $B1 +$C3, $F0, $73, $C8, $B1, $C3, $85, $8D +$C8, $B1, $C3, $C8, $85, $8E, $B1, $C3 +$C8, $AA, $20, $94, $C6, $E0, $83, $F0 +$81, $D0, $DA, $A5, $91, $A4, $92, $A6 +$62, $10, $03, $4C, $53, $C5, $A0, $00 +$B1, $91, $D0, $01, $60, $A9, $0A, $A0 +$E8, $4C, $D8, $C8, $BA, $E8, $E8, $E8 +$E8, $BD, $01, $01, $C9, $81, $D0, $21 +$A5, $98, $D0, $0A, $BD, $02, $01, $85 +$97, $BD, $03, $01, $85, $98, $DD, $03 +$01, $D0, $07, $A5, $97, $DD, $02, $01 +$F0, $07, $8A, $18, $69, $10, $AA, $D0 +$D8, $60, $D0, $04, $A0, $00, $F0, $03 +$20, $AF, $CD, $85, $97, $84, $98, $20 +$3C, $CA, $F0, $04, $A2, $00, $F0, $63 +$9A, $8A, $38, $E9, $F7, $85, $73, $69 +$FB, $A0, $01, $20, $82, $D8, $BA, $BD +$08, $01, $85, $B0, $A5, $97, $A4, $98 +$20, $C3, $D5, $20, $A8, $D8, $A0, $01 +$20, $1E, $D9, $BA, $DD, $08, $01, $F0 +$17, $BD, $0D, $01, $85, $87, $BD, $0E +$01, $85, $88, $BD, $10, $01, $85, $C3 +$BD, $0F, $01, $85, $C4, $4C, $C1, $C4 +$8A, $69, $0F, $AA, $9A, $20, $C2, $00 +$C9, $2C, $D0, $F1, $20, $BC, $00, $20 +$70, $CA, $20, $E6, $CA, $18, $24, $38 +$24, $5F, $30, $03, $B0, $03, $60, $B0 +$FD, $A2, $18, $4C, $40, $C1, $A6, $C3 +$D0, $02, $C6, $C4, $C6, $C3, $A9, $00 +$48, $A9, $02, $20, $07, $C1, $20, $D2 +$CB, $A9, $00, $85, $9B, $20, $C2, $00 +$38, $E9, $C0, $90, $17, $C9, $03, $B0 +$13, $C9, $01, $2A, $49, $01, $45, $9B +$C5, $9B, $90, $67, $85, $9B, $20, $BC +$00, $4C, $00, $CB, $A6, $9B, $D0, $2C +$B0, $79, $69, $0A, $90, $75, $D0, $07 +$24, $5F, $10, $03, $4C, $D9, $D2, $85 +$71, $0A, $65, $71, $A8, $68, $D9, $F2 +$E2, $B0, $65, $20, $D5, $CA, $48, $20 +$67, $CB, $68, $A4, $99, $10, $19, $AA +$F0, $76, $D0, $5D, $26, $5F, $8A, $85 +$5F, $2A, $A6, $C3, $D0, $02, $C6, $C4 +$C6, $C3, $A0, $24, $85, $9B, $D0, $D5 +$D9, $F2, $E2, $B0, $44, $90, $D7, $B9 +$F4, $E2, $48, $B9, $F3, $E2, $48, $20 +$7E, $CB, $A5, $9B, $48, $B9, $F2, $E2 +$4C, $F0, $CA, $4C, $07, $CC, $68, $85 +$71, $E6, $71, $68, $85, $72, $A5, $B0 +$48, $20, $DE, $D8, $A5, $AF, $48, $A5 +$AE, $48, $A5, $AD, $48, $A5, $AC, $48 +$6C, $71, $00, $A0, $FF, $68, $F0, $20 +$C9, $64, $F0, $03, $20, $D5, $CA, $84 +$99, $68, $4A, $85, $63, $68, $85, $B3 +$68, $85, $B4, $68, $85, $B5, $68, $85 +$B6, $68, $85, $B7, $45, $B0, $85, $B8 +$A5, $AC, $60, $A5, $C3, $A4, $C4, $69 +$00, $90, $01, $C8, $20, $49, $D1, $4C +$D4, $D4, $20, $BC, $00, $B0, $03, $4C +$AB, $D9, $AA, $30, $2F, $C9, $24, $F0 +$F6, $C9, $25, $F0, $F2, $C9, $2E, $F0 +$EE, $C9, $22, $F0, $D6, $C9, $28, $D0 +$4F, $20, $EE, $CA, $A9, $29, $A0, $00 +$D1, $C3, $D0, $0B, $4C, $BC, $00, $A9 +$28, $D0, $F3, $A9, $2C, $D0, $EF, $A2 +$02, $4C, $40, $C1, $C9, $B7, $F0, $29 +$C9, $B6, $F0, $BE, $C9, $B1, $D0, $13 +$A0, $21, $D0, $1F, $20, $AB, $CE, $A5 +$AF, $49, $FF, $A8, $A5, $AE, $49, $FF +$4C, $5E, $D0, $C9, $AE, $D0, $03, $4C +$B9, $D0, $E9, $C3, $B0, $19, $4C, $07 +$CC, $A0, $1E, $68, $68, $4C, $3F, $CB +$20, $AF, $CD, $85, $AE, $84, $AF, $A6 +$5F, $30, $03, $4C, $82, $D8, $60, $0A +$A8, $B9, $AD, $E2, $48, $B9, $AC, $E2 +$48, $B9, $67, $E2, $F0, $05, $48, $B9 +$66, $E2, $48, $60, $20, $F1, $CB, $4C +$D7, $CA, $20, $F1, $CB, $4C, $D5, $CA +$46, $5F, $4C, $BC, $00, $20, $EE, $CA +$20, $03, $CC, $20, $D7, $CA, $68, $AA +$68, $A8, $A5, $AF, $48, $A5, $AE, $48 +$98, $48, $8A, $48, $20, $91, $D4, $8A +$60, $20, $EE, $CA, $20, $D5, $CA, $A5 +$AC, $C9, $98, $B0, $20, $20, $55, $D9 +$A2, $02, $B5, $AD, $95, $11, $CA, $10 +$F9, $20, $C2, $00, $A2, $00, $C9, $29 +$F0, $0A, $20, $E3, $D4, $20, $C2, $00 +$C9, $29, $D0, $01, $60, $4C, $2E, $CF +$20, $E7, $CC, $45, $5B, $A8, $A5, $AE +$45, $5C, $4C, $5E, $D0, $20, $E7, $CC +$05, $5B, $A8, $A5, $AE, $05, $5C, $4C +$5E, $D0, $20, $E7, $CC, $25, $5B, $A8 +$A5, $AE, $25, $5C, $4C, $5E, $D0, $20 +$AB, $CE, $A5, $AE, $85, $5C, $A5, $AF +$85, $5B, $20, $C8, $D5, $20, $AB, $CE +$A5, $AF, $60, $20, $D8, $CA, $B0, $13 +$A5, $B7, $09, $7F, $25, $B4, $85, $B4 +$A9, $B3, $A0, $00, $20, $1C, $D9, $AA +$4C, $44, $CD, $46, $5F, $C6, $9B, $20 +$43, $D3, $85, $AC, $86, $AD, $84, $AE +$A5, $B5, $A4, $B6, $20, $47, $D3, $86 +$B5, $84, $B6, $AA, $38, $E5, $AC, $F0 +$08, $A9, $01, $90, $04, $A6, $AC, $A9 +$FF, $85, $B0, $A0, $FF, $E8, $C8, $CA +$D0, $07, $A6, $B0, $30, $0F, $18, $90 +$0C, $B1, $B5, $D1, $AD, $F0, $EF, $A2 +$FF, $B0, $02, $A2, $01, $E8, $8A, $2A +$25, $63, $F0, $02, $A9, $FF, $4C, $FF +$D8, $20, $03, $CC, $AA, $20, $B4, $CD +$20, $C2, $00, $D0, $F4, $60, $20, $A4 +$CD, $A5, $AE, $A6, $78, $F0, $22, $E0 +$10, $B0, $23, $06, $AF, $2A, $CA, $D0 +$FA, $A4, $AF, $4C, $5E, $D0, $20, $A4 +$CD, $A5, $AE, $A6, $78, $F0, $0A, $E0 +$10, $B0, $0B, $4A, $66, $AF, $CA, $D0 +$FA, $A4, $AF, $4C, $5E, $D0, $A9, $00 +$A8, $4C, $5E, $D0, $20, $94, $D4, $86 +$78, $20, $C8, $D5, $4C, $AB, $CE, $A2 +$00, $20, $C2, $00, $86, $5E, $85, $93 +$29, $7F, $20, $23, $CE, $B0, $03, $4C +$07, $CC, $A2, $00, $86, $5F, $20, $BC +$00, $90, $05, $20, $23, $CE, $90, $0B +$AA, $20, $BC, $00, $90, $FB, $20, $23 +$CE, $B0, $F6, $C9, $24, $D0, $0B, $A9 +$FF, $85, $5F, $8A, $09, $80, $AA, $20 +$BC, $00, $86, $94, $05, $61, $C9, $28 +$D0, $03, $4C, $BD, $CE, $A9, $00, $85 +$61, $A5, $7B, $A6, $7C, $A0, $00, $86 +$AB, $85, $AA, $E4, $7E, $D0, $04, $C5 +$7D, $F0, $2C, $A5, $93, $D1, $AA, $D0 +$08, $A5, $94, $C8, $D1, $AA, $F0, $69 +$88, $18, $A5, $AA, $69, $06, $90, $E1 +$E8, $D0, $DC, $C9, $61, $B0, $0A, $C9 +$41, $90, $05, $E9, $5B, $38, $E9, $A5 +$60, $E9, $7B, $38, $E9, $85, $60, $68 +$48, $C9, $42, $D0, $05, $A9, $EA, $A0 +$E1, $60, $A5, $7D, $A4, $7E, $85, $AA +$84, $AB, $A5, $7F, $A4, $80, $85, $A6 +$84, $A7, $18, $69, $06, $90, $01, $C8 +$85, $A4, $84, $A5, $20, $C5, $C0, $A5 +$A4, $A4, $A5, $C8, $85, $7D, $84, $7E +$A0, $00, $A5, $93, $91, $AA, $C8, $A5 +$94, $91, $AA, $A9, $00, $C8, $91, $AA +$C8, $91, $AA, $C8, $91, $AA, $C8, $91 +$AA, $A5, $AA, $18, $69, $02, $A4, $AB +$90, $01, $C8, $85, $95, $84, $96, $60 +$A5, $5D, $0A, $69, $05, $65, $AA, $A4 +$AB, $90, $01, $C8, $85, $A4, $84, $A5 +$60, $20, $BC, $00, $20, $D2, $CA, $A5 +$B0, $30, $0D, $A5, $AC, $C9, $90, $90 +$09, $A9, $F1, $A0, $E1, $20, $1C, $D9 +$D0, $74, $4C, $55, $D9, $A5, $5E, $48 +$A5, $5F, $48, $A0, $00, $98, $48, $A5 +$94, $48, $A5, $93, $48, $20, $A1, $CE +$68, $85, $93, $68, $85, $94, $68, $A8 +$BA, $BD, $02, $01, $48, $BD, $01, $01 +$48, $A5, $AE, $9D, $02, $01, $A5, $AF +$9D, $01, $01, $C8, $20, $C2, $00, $C9 +$2C, $F0, $D2, $84, $5D, $20, $F4, $CB +$68, $85, $5F, $68, $85, $5E, $A6, $7D +$A5, $7E, $86, $AA, $85, $AB, $C5, $80 +$D0, $04, $E4, $7F, $F0, $39, $A0, $00 +$B1, $AA, $C8, $C5, $93, $D0, $06, $A5 +$94, $D1, $AA, $F0, $16, $C8, $B1, $AA +$18, $65, $AA, $AA, $C8, $B1, $AA, $65 +$AB, $90, $D7, $A2, $10, $2C, $A2, $08 +$4C, $40, $C1, $A2, $12, $A5, $5E, $D0 +$F7, $20, $90, $CE, $A5, $5D, $A0, $04 +$D1, $AA, $D0, $E7, $4C, $CA, $CF, $20 +$90, $CE, $20, $0F, $C1, $A0, $00, $84 +$BB, $A5, $93, $91, $AA, $C8, $A5, $94 +$91, $AA, $A5, $5D, $A0, $04, $84, $BA +$91, $AA, $18, $A2, $0B, $A9, $00, $24 +$5E, $50, $07, $68, $69, $01, $AA, $68 +$69, $00, $C8, $91, $AA, $C8, $8A, $91 +$AA, $20, $19, $D0, $86, $BA, $85, $BB +$A4, $71, $C6, $5D, $D0, $DD, $65, $A5 +$B0, $5D, $85, $A5, $A8, $8A, $65, $A4 +$90, $03, $C8, $F0, $52, $20, $0F, $C1 +$85, $7F, $84, $80, $A9, $00, $E6, $BB +$A4, $BA, $F0, $05, $88, $91, $A4, $D0 +$FB, $C6, $A5, $C6, $BB, $D0, $F5, $E6 +$A5, $38, $A0, $02, $A5, $7F, $E5, $AA +$91, $AA, $C8, $A5, $80, $E5, $AB, $91 +$AA, $A5, $5E, $D0, $53, $C8, $B1, $AA +$85, $5D, $A9, $00, $85, $BA, $85, $BB +$C8, $68, $AA, $85, $AE, $68, $85, $AF +$D1, $AA, $90, $0E, $D0, $06, $C8, $8A +$D1, $AA, $90, $07, $4C, $2B, $CF, $4C +$3E, $C1, $C8, $A5, $BB, $05, $BA, $F0 +$0A, $20, $19, $D0, $8A, $65, $AE, $AA +$98, $A4, $71, $65, $AF, $86, $BA, $C6 +$5D, $D0, $CB, $06, $BA, $2A, $06, $BA +$2A, $A8, $A5, $BA, $65, $A4, $85, $95 +$98, $65, $A5, $85, $96, $A8, $A5, $95 +$60, $84, $71, $B1, $AA, $85, $76, $88 +$B1, $AA, $85, $77, $A9, $10, $85, $A8 +$A2, $00, $A0, $00, $8A, $0A, $AA, $98 +$2A, $A8, $B0, $B3, $06, $BA, $26, $BB +$90, $0B, $18, $8A, $65, $76, $AA, $98 +$65, $77, $A8, $B0, $A2, $C6, $A8, $D0 +$E3, $60, $A5, $5F, $10, $03, $20, $43 +$D3, $20, $E4, $D1, $38, $A5, $81, $E5 +$7F, $A8, $A5, $82, $E5, $80, $46, $5F +$85, $AD, $84, $AE, $A2, $90, $4C, $07 +$D9, $A4, $0E, $A9, $00, $F0, $EF, $A6 +$88, $E8, $D0, $A4, $A2, $16, $4C, $40 +$C1, $20, $AA, $D0, $85, $9C, $84, $9D +$20, $6F, $D0, $20, $FF, $CB, $A9, $80 +$85, $61, $20, $AF, $CD, $20, $D5, $CA +$20, $F4, $CB, $A9, $C1, $20, $F6, $CB +$A5, $96, $48, $A5, $95, $48, $A5, $C4 +$48, $A5, $C3, $48, $20, $91, $C6, $4C +$19, $D1, $A9, $AE, $20, $F6, $CB, $09 +$80, $85, $61, $20, $B6, $CD, $4C, $D5 +$CA, $20, $AA, $D0, $48, $98, $48, $20 +$FF, $CB, $20, $E6, $CA, $20, $F4, $CB +$20, $D5, $CA, $68, $85, $9D, $68, $85 +$9C, $A2, $20, $A0, $03, $B1, $9C, $F0 +$9D, $85, $96, $88, $B1, $9C, $85, $95 +$AA, $C8, $B1, $95, $48, $88, $10, $FA +$A4, $96, $20, $AC, $D8, $A5, $C4, $48 +$A5, $C3, $48, $B1, $9C, $85, $C3, $C8 +$B1, $9C, $85, $C4, $A5, $96, $48, $A5 +$95, $48, $20, $D2, $CA, $68, $85, $9C +$68, $85, $9D, $20, $C2, $00, $F0, $03 +$4C, $07, $CC, $68, $85, $C3, $68, $85 +$C4, $A0, $00, $68, $91, $9C, $C8, $68 +$91, $9C, $C8, $68, $91, $9C, $C8, $68 +$91, $9C, $60, $20, $D5, $CA, $20, $9A +$DA, $A9, $F0, $A0, $00, $F0, $12, $A6 +$AE, $A4, $AF, $86, $9E, $84, $9F, $20 +$B2, $D1, $86, $AD, $84, $AE, $85, $AC +$60, $A2, $22, $86, $5B, $86, $5C, $85 +$B8, $84, $B9, $85, $AD, $84, $AE, $A0 +$FF, $C8, $B1, $B8, $F0, $0C, $C5, $5B +$F0, $04, $C5, $5C, $D0, $F3, $C9, $22 +$F0, $01, $18, $84, $AC, $98, $65, $B8 +$85, $BA, $A6, $B9, $90, $01, $E8, $86 +$BB, $A5, $B9, $C9, $03, $B0, $0B, $98 +$20, $37, $D1, $A6, $B8, $A4, $B9, $20 +$24, $D3, $A6, $65, $E0, $71, $D0, $05 +$A2, $1C, $4C, $40, $C1, $A5, $AC, $95 +$00, $A5, $AD, $95, $01, $A5, $AE, $95 +$02, $A0, $00, $86, $AE, $84, $AF, $88 +$84, $5F, $86, $66, $E8, $E8, $E8, $86 +$65, $60, $46, $60, $48, $49, $FF, $38 +$65, $81, $A4, $82, $B0, $01, $88, $C4 +$80, $90, $11, $D0, $04, $C5, $7F, $90 +$0B, $85, $81, $84, $82, $85, $83, $84 +$84, $AA, $68, $60, $A2, $0C, $A5, $60 +$30, $B8, $20, $E4, $D1, $A9, $80, $85 +$60, $68, $D0, $D0, $A6, $85, $A5, $86 +$86, $81, $85, $82, $A0, $00, $84, $9D +$A5, $7F, $A6, $80, $85, $AA, $86, $AB +$A9, $68, $85, $71, $84, $72, $C5, $65 +$F0, $05, $20, $68, $D2, $F0, $F7, $06 +$A0, $A5, $7B, $A6, $7C, $85, $71, $86 +$72, $E4, $7E, $D0, $04, $C5, $7D, $F0 +$05, $20, $62, $D2, $F0, $F3, $85, $A4 +$86, $A5, $A9, $04, $85, $A0, $A5, $A4 +$A6, $A5, $E4, $80, $D0, $04, $C5, $7F +$F0, $75, $85, $71, $86, $72, $A0, $02 +$B1, $71, $65, $A4, $85, $A4, $C8, $B1 +$71, $65, $A5, $85, $A5, $A0, $01, $B1 +$71, $10, $DB, $A0, $04, $B1, $71, $0A +$69, $05, $20, $9A, $D2, $E4, $A5, $D0 +$04, $C5, $A4, $F0, $CD, $20, $68, $D2 +$F0, $F3, $C8, $B1, $71, $10, $30, $C8 +$B1, $71, $F0, $2B, $C8, $B1, $71, $AA +$C8, $B1, $71, $C5, $82, $90, $06, $D0 +$1E, $E4, $81, $B0, $1A, $C5, $AB, $90 +$17, $D0, $04, $E4, $AA, $90, $11, $86 +$AA, $85, $AB, $A5, $71, $A6, $72, $85 +$9C, $86, $9D, $88, $88, $84, $A2, $18 +$A5, $A0, $65, $71, $85, $71, $90, $02 +$E6, $72, $A6, $72, $A0, $00, $60, $C6 +$A0, $A6, $9D, $F0, $F5, $A4, $A2, $18 +$B1, $9C, $65, $AA, $85, $A6, $A5, $AB +$69, $00, $85, $A7, $A5, $81, $A6, $82 +$85, $A4, $86, $A5, $20, $CC, $C0, $A4 +$A2, $C8, $A5, $A4, $91, $9C, $AA, $E6 +$A5, $A5, $A5, $C8, $91, $9C, $4C, $E8 +$D1, $A5, $AF, $48, $A5, $AE, $48, $20 +$D2, $CB, $20, $D7, $CA, $68, $85, $B8 +$68, $85, $B9, $A0, $00, $B1, $B8, $18 +$71, $AE, $90, $05, $A2, $1A, $4C, $40 +$C1, $20, $37, $D1, $20, $16, $D3, $A5 +$9E, $A4, $9F, $20, $47, $D3, $20, $28 +$D3, $A5, $B8, $A4, $B9, $20, $47, $D3 +$20, $8A, $D1, $4C, $FD, $CA, $A0, $00 +$B1, $B8, $48, $C8, $B1, $B8, $AA, $C8 +$B1, $B8, $A8, $68, $86, $71, $84, $72 +$AA, $F0, $14, $A0, $00, $B1, $71, $91 +$83, $C8, $CA, $D0, $F8, $98, $18, $65 +$83, $85, $83, $90, $02, $E6, $84, $60 +$20, $D7, $CA, $A5, $AE, $A4, $AF, $85 +$71, $84, $72, $20, $78, $D3, $08, $A0 +$00, $B1, $71, $48, $C8, $B1, $71, $AA +$C8, $B1, $71, $A8, $68, $28, $D0, $13 +$C4, $82, $D0, $0F, $E4, $81, $D0, $0B +$48, $18, $65, $81, $85, $81, $90, $02 +$E6, $82, $68, $86, $71, $84, $72, $60 +$C4, $67, $D0, $0C, $C5, $66, $D0, $08 +$85, $65, $E9, $03, $85, $66, $A0, $00 +$60, $20, $94, $D4, $8A, $48, $A9, $01 +$20, $3F, $D1, $68, $A0, $00, $91, $AD +$4C, $8A, $D1, $48, $20, $FC, $D3, $D1 +$9E, $98, $F0, $09, $48, $20, $FC, $D3 +$18, $F1, $9E, $49, $FF, $90, $04, $B1 +$9E, $AA, $98, $48, $8A, $48, $20, $3F +$D1, $A5, $9E, $A4, $9F, $20, $47, $D3 +$68, $A8, $68, $18, $65, $71, $85, $71 +$90, $02, $E6, $72, $98, $20, $28, $D3 +$4C, $8A, $D1, $48, $A9, $FF, $85, $AF +$20, $C2, $00, $C9, $29, $F0, $06, $20 +$03, $CC, $20, $91, $D4, $20, $FC, $D3 +$CA, $8A, $48, $18, $A2, $00, $F1, $9E +$B0, $C2, $49, $FF, $C5, $AF, $90, $BD +$A5, $AF, $B0, $B9, $20, $F4, $CB, $68 +$85, $A2, $68, $85, $A3, $68, $AA, $68 +$85, $9E, $68, $85, $9F, $A0, $00, $8A +$F0, $79, $E6, $A2, $6C, $A2, $00, $20 +$40, $D3, $85, $AC, $A8, $F0, $38, $20 +$3F, $D1, $86, $AD, $84, $AE, $A8, $88 +$B1, $71, $20, $27, $CE, $90, $02, $09 +$20, $91, $83, $98, $D0, $F1, $F0, $1F +$20, $40, $D3, $85, $AC, $A8, $F0, $17 +$20, $3F, $D1, $86, $AD, $84, $AE, $A8 +$88, $B1, $71, $20, $23, $CE, $90, $02 +$29, $DF, $91, $83, $98, $D0, $F1, $4C +$8A, $D1, $20, $BC, $00, $20, $AF, $CD +$20, $F4, $CB, $20, $D7, $CA, $A0, $02 +$B1, $95, $AA, $88, $B1, $95, $A8, $8A +$4C, $5E, $D0, $20, $79, $D4, $4C, $6B +$D0, $20, $40, $D3, $A8, $60, $20, $79 +$D4, $F0, $08, $A0, $00, $B1, $71, $A8 +$4C, $6B, $D0, $4C, $2E, $CF, $20, $BC +$00, $20, $D2, $CA, $20, $A7, $CE, $A4 +$AE, $D0, $F0, $A6, $AF, $4C, $C2, $00 +$20, $79, $D4, $D0, $03, $4C, $55, $D6 +$A6, $C3, $A4, $C4, $86, $BA, $84, $BB +$A6, $71, $86, $C3, $18, $65, $71, $85 +$73, $A5, $72, $85, $C4, $69, $00, $85 +$74, $A0, $00, $B1, $73, $48, $98, $91 +$73, $20, $C2, $00, $20, $AB, $D9, $68 +$A0, $00, $91, $73, $A6, $BA, $A4, $BB +$86, $C3, $84, $C4, $60, $20, $D2, $CA +$20, $F6, $D4, $20, $03, $CC, $A5, $12 +$48, $A5, $11, $48, $20, $91, $D4, $68 +$85, $11, $68, $85, $12, $60, $A5, $AC +$C9, $98, $B0, $8F, $20, $55, $D9, $A5 +$AE, $A4, $AF, $84, $11, $85, $12, $60 +$20, $F6, $D4, $A2, $00, $A1, $11, $A8 +$4C, $6B, $D0, $20, $DD, $D4, $8A, $A2 +$00, $81, $11, $60, $20, $F6, $D4, $A2 +$00, $A1, $11, $A8, $E6, $11, $D0, $02 +$E6, $12, $A1, $11, $4C, $5E, $D0, $20 +$D2, $CA, $20, $F6, $D4, $84, $97, $85 +$98, $20, $03, $CC, $20, $D2, $CA, $20 +$F6, $D4, $98, $A2, $00, $81, $97, $E6 +$97, $D0, $02, $E6, $98, $A5, $12, $81 +$97, $4C, $C2, $00, $20, $AF, $CD, $85 +$97, $84, $98, $A5, $5F, $48, $20, $03 +$CC, $20, $AF, $CD, $68, $45, $5F, $10 +$10, $A0, $03, $B1, $97, $AA, $B1, $95 +$91, $97, $8A, $91, $95, $88, $10, $F3 +$60, $4C, $E1, $CA, $20, $D2, $CA, $20 +$F6, $D4, $A9, $D5, $48, $A9, $8A, $48 +$6C, $11, $00, $4C, $C2, $00, $20, $DD +$D4, $86, $97, $A2, $00, $20, $C2, $00 +$F0, $03, $20, $E3, $D4, $86, $98, $B1 +$11, $45, $98, $25, $97, $F0, $F8, $60 +$20, $90, $D7, $A5, $B0, $49, $FF, $85 +$B0, $45, $B7, $85, $B8, $A5, $AC, $4C +$C6, $D5, $20, $DF, $D6, $90, $4D, $A9 +$F2, $A0, $E1, $20, $90, $D7, $D0, $10 +$A5, $B7, $85, $B0, $A2, $04, $B5, $B2 +$95, $AB, $CA, $D0, $F9, $86, $B9, $60 +$A6, $B9, $86, $A3, $A2, $B3, $A5, $B3 +$A8, $F0, $C4, $38, $E5, $AC, $F0, $24 +$90, $12, $84, $AC, $A4, $B7, $84, $B0 +$49, $FF, $69, $00, $A0, $00, $84, $A3 +$A2, $AC, $D0, $04, $A0, $00, $84, $B9 +$C9, $F9, $30, $B6, $A8, $A5, $B9, $56 +$01, $20, $F6, $D6, $24, $B8, $10, $4C +$A0, $AC, $E0, $B3, $F0, $02, $A0, $B3 +$38, $49, $FF, $65, $A3, $85, $B9, $B9 +$03, $00, $F5, $03, $85, $AF, $B9, $02 +$00, $F5, $02, $85, $AE, $B9, $01, $00 +$F5, $01, $85, $AD, $B0, $03, $20, $9B +$D6, $A0, $00, $98, $18, $A6, $AD, $D0 +$3E, $A6, $AE, $86, $AD, $A6, $AF, $86 +$AE, $A6, $B9, $86, $AF, $84, $B9, $69 +$08, $C9, $18, $D0, $E8, $A9, $00, $85 +$AC, $85, $B0, $60, $65, $A3, $85, $B9 +$A5, $AF, $65, $B6, $85, $AF, $A5, $AE +$65, $B5, $85, $AE, $A5, $AD, $65, $B4 +$85, $AD, $B0, $1A, $60, $69, $01, $06 +$B9, $26, $AF, $26, $AE, $26, $AD, $10 +$F4, $38, $E5, $AC, $B0, $CF, $49, $FF +$69, $01, $85, $AC, $90, $0C, $E6, $AC +$F0, $36, $66, $AD, $66, $AE, $66, $AF +$66, $B9, $60, $A5, $B0, $49, $FF, $85 +$B0, $A5, $AD, $49, $FF, $85, $AD, $A5 +$AE, $49, $FF, $85, $AE, $A5, $AF, $49 +$FF, $85, $AF, $A5, $B9, $49, $FF, $85 +$B9, $E6, $B9, $D0, $0A, $E6, $AF, $D0 +$06, $E6, $AE, $D0, $02, $E6, $AD, $60 +$A2, $0A, $4C, $40, $C1, $A2, $74, $B4 +$03, $84, $B9, $B4, $02, $94, $03, $B4 +$01, $94, $02, $A4, $B2, $94, $01, $69 +$08, $30, $EC, $F0, $EA, $E9, $08, $A8 +$A5, $B9, $B0, $12, $16, $01, $90, $02 +$F6, $01, $76, $01, $76, $01, $76, $02 +$76, $03, $6A, $C8, $D0, $EE, $18, $60 +$20, $EE, $D8, $F0, $02, $10, $03, $4C +$2E, $CF, $A5, $AC, $E9, $7F, $48, $A9 +$80, $85, $AC, $A9, $72, $A0, $E1, $20 +$C3, $D5, $A9, $76, $A0, $E1, $20, $06 +$D8, $A9, $E9, $A0, $E1, $20, $A8, $D5 +$A9, $65, $A0, $E1, $20, $56, $DC, $A9 +$7A, $A0, $E1, $20, $C3, $D5, $68, $20 +$4A, $DA, $A9, $7E, $A0, $E1, $20, $90 +$D7, $F0, $4C, $20, $B6, $D7, $A9, $00 +$85, $75, $85, $76, $85, $77, $A5, $B9 +$20, $65, $D7, $A5, $AF, $20, $65, $D7 +$A5, $AE, $20, $65, $D7, $A5, $AD, $20 +$6A, $D7, $4C, $73, $D8, $D0, $03, $4C +$CD, $D6, $4A, $09, $80, $A8, $90, $13 +$18, $A5, $77, $65, $B6, $85, $77, $A5 +$76, $65, $B5, $85, $76, $A5, $75, $65 +$B4, $85, $75, $66, $75, $66, $76, $66 +$77, $66, $B9, $98, $4A, $D0, $DE, $60 +$85, $71, $84, $72, $A0, $03, $B1, $71 +$85, $B6, $88, $B1, $71, $85, $B5, $88 +$B1, $71, $85, $B7, $45, $B0, $85, $B8 +$A5, $B7, $09, $80, $85, $B4, $88, $B1 +$71, $85, $B3, $A5, $AC, $60, $A5, $B3 +$F0, $1D, $18, $65, $AC, $90, $04, $30 +$31, $18, $2C, $10, $12, $69, $80, $85 +$AC, $D0, $03, $4C, $59, $D6, $A5, $B8 +$85, $B0, $60, $A5, $B0, $10, $1B, $68 +$68, $4C, $55, $D6, $20, $CF, $D8, $AA +$F0, $F0, $18, $69, $02, $B0, $0B, $A2 +$00, $86, $B8, $20, $E0, $D5, $E6, $AC +$D0, $E0, $4C, $C8, $D6, $20, $CF, $D8 +$A9, $FA, $A0, $E1, $A2, $00, $86, $B8 +$20, $82, $D8, $4C, $09, $D8, $20, $90 +$D7, $F0, $63, $20, $DE, $D8, $A9, $00 +$38, $E5, $AC, $85, $AC, $20, $B6, $D7 +$E6, $AC, $F0, $D6, $A2, $FF, $A9, $01 +$A4, $B4, $C4, $AD, $D0, $0A, $A4, $B5 +$C4, $AE, $D0, $04, $A4, $B6, $C4, $AF +$08, $2A, $90, $0E, $A0, $01, $E8, $E0 +$02, $30, $04, $D0, $28, $A0, $40, $95 +$75, $98, $28, $90, $14, $A8, $A5, $B6 +$E5, $AF, $85, $B6, $A5, $B5, $E5, $AE +$85, $B5, $A5, $B4, $E5, $AD, $85, $B4 +$98, $06, $B6, $26, $B5, $26, $B4, $B0 +$CF, $30, $BD, $10, $CB, $4A, $6A, $6A +$85, $B9, $28, $4C, $73, $D8, $A2, $14 +$4C, $40, $C1, $A5, $75, $85, $AD, $A5 +$76, $85, $AE, $A5, $77, $85, $AF, $4C +$39, $D6, $85, $71, $84, $72, $A0, $03 +$B1, $71, $85, $AF, $88, $B1, $71, $85 +$AE, $88, $B1, $71, $85, $B0, $09, $80 +$85, $AD, $88, $B1, $71, $85, $AC, $84 +$B9, $60, $A2, $A4, $A0, $00, $F0, $04 +$A6, $97, $A4, $98, $20, $DE, $D8, $86 +$71, $84, $72, $A0, $03, $A5, $AF, $91 +$71, $88, $A5, $AE, $91, $71, $88, $A5 +$B0, $09, $7F, $25, $AD, $91, $71, $88 +$A5, $AC, $91, $71, $84, $B9, $60, $20 +$DE, $D8, $A2, $05, $B5, $AB, $95, $B2 +$CA, $D0, $F9, $86, $B9, $60, $A5, $AC +$F0, $FB, $06, $B9, $90, $F7, $20, $BD +$D6, $D0, $F2, $4C, $8E, $D6, $A5, $AC +$F0, $09, $A5, $B0, $2A, $A9, $FF, $B0 +$02, $A9, $01, $60, $20, $EE, $D8, $85 +$AD, $A9, $00, $85, $AE, $A2, $88, $A5 +$AD, $49, $FF, $2A, $A9, $00, $85, $AF +$86, $AC, $85, $B9, $85, $B0, $4C, $34 +$D6, $46, $B0, $60, $85, $73, $84, $74 +$A0, $00, $B1, $73, $C8, $AA, $F0, $C6 +$B1, $73, $45, $B0, $30, $C4, $E4, $AC +$D0, $1A, $B1, $73, $09, $80, $C5, $AD +$D0, $12, $C8, $B1, $73, $C5, $AE, $D0 +$0B, $C8, $A9, $7F, $C5, $B9, $B1, $73 +$E5, $AF, $F0, $28, $A5, $B0, $90, $02 +$49, $FF, $4C, $F4, $D8, $A5, $AC, $F0 +$4A, $38, $E9, $98, $24, $B0, $10, $09 +$AA, $A9, $FF, $85, $B2, $20, $A1, $D6 +$8A, $A2, $AC, $C9, $F9, $10, $06, $20 +$DF, $D6, $84, $B2, $60, $A8, $A5, $B0 +$29, $80, $46, $AD, $05, $AD, $85, $AD +$20, $F6, $D6, $84, $B2, $60, $A5, $AC +$C9, $98, $B0, $1E, $20, $55, $D9, $84 +$B9, $A5, $B0, $84, $B0, $49, $80, $2A +$A9, $98, $85, $AC, $A5, $AF, $85, $5B +$4C, $34, $D6, $85, $AD, $85, $AE, $85 +$AF, $A8, $60, $A0, $00, $84, $5F, $A2 +$09, $94, $A8, $CA, $10, $FB, $90, $7F +$C9, $2D, $D0, $04, $86, $B1, $F0, $04 +$C9, $2B, $D0, $05, $20, $BC, $00, $90 +$6E, $C9, $24, $D0, $03, $4C, $73, $DE +$C9, $25, $D0, $08, $4C, $A1, $DE, $20 +$BC, $00, $90, $5B, $C9, $2E, $F0, $2E +$C9, $45, $D0, $30, $20, $BC, $00, $90 +$17, $C9, $B7, $F0, $0E, $C9, $2D, $F0 +$0A, $C9, $B6, $F0, $08, $C9, $2B, $F0 +$04, $D0, $07, $66, $AB, $20, $BC, $00 +$90, $5B, $24, $AB, $10, $0E, $A9, $00 +$38, $E5, $A9, $4C, $16, $DA, $66, $AA +$24, $AA, $50, $C3, $A5, $A9, $38, $E5 +$A8, $85, $A9, $F0, $12, $10, $09, $20 +$F5, $D7, $E6, $A9, $D0, $F9, $F0, $07 +$20, $DC, $D7, $C6, $A9, $D0, $F9, $A5 +$B1, $30, $01, $60, $4C, $F9, $DB, $48 +$24, $AA, $10, $02, $E6, $A8, $20, $DC +$D7, $68, $29, $0F, $20, $4A, $DA, $4C +$D7, $D9, $48, $20, $CF, $D8, $68, $20 +$FF, $D8, $A5, $B7, $45, $B0, $85, $B8 +$A6, $AC, $4C, $C6, $D5, $A5, $A9, $C9 +$0A, $90, $09, $A9, $64, $24, $AB, $30 +$0E, $4C, $C8, $D6, $0A, $0A, $65, $A9 +$0A, $A0, $00, $71, $C3, $E9, $2F, $85 +$A9, $4C, $FD, $D9, $A9, $F6, $A0, $E7 +$20, $D8, $C8, $A5, $88, $A6, $87, $85 +$AD, $86, $AE, $A2, $90, $38, $20, $0C +$D9, $A0, $00, $98, $20, $A7, $DA, $4C +$D8, $C8, $A0, $01, $A9, $20, $24, $B0 +$10, $02, $A9, $2D, $99, $EF, $00, $85 +$B0, $84, $BA, $C8, $A6, $AC, $D0, $05 +$A9, $30, $4C, $B3, $DB, $A9, $00, $E0 +$81, $B0, $09, $A9, $8A, $A0, $E1, $20 +$3E, $D7, $A9, $FA, $85, $A8, $A9, $86 +$A0, $E1, $20, $1C, $D9, $F0, $1E, $10 +$12, $A9, $82, $A0, $E1, $20, $1C, $D9 +$F0, $02, $10, $0E, $20, $DC, $D7, $C6 +$A8, $D0, $EE, $20, $F5, $D7, $E6, $A8 +$D0, $DC, $20, $BF, $D5, $20, $55, $D9 +$A2, $01, $A5, $A8, $18, $69, $07, $30 +$09, $C9, $08, $B0, $06, $69, $FF, $AA +$A9, $02, $38, $E9, $02, $85, $A9, $86 +$A8, $8A, $F0, $02, $10, $13, $A4, $BA +$A9, $2E, $C8, $99, $EF, $00, $8A, $F0 +$06, $A9, $30, $C8, $99, $EF, $00, $84 +$BA, $A0, $00, $A2, $80, $A5, $AF, $18 +$79, $00, $E2, $85, $AF, $A5, $AE, $79 +$FF, $E1, $85, $AE, $A5, $AD, $79, $FE +$E1, $85, $AD, $E8, $B0, $04, $10, $E5 +$30, $02, $30, $E1, $8A, $90, $04, $49 +$FF, $69, $0A, $69, $2F, $C8, $C8, $C8 +$84, $95, $A4, $BA, $C8, $AA, $29, $7F +$99, $EF, $00, $C6, $A8, $D0, $06, $A9 +$2E, $C8, $99, $EF, $00, $84, $BA, $A4 +$95, $8A, $49, $FF, $29, $80, $AA, $C0 +$12, $D0, $B2, $A4, $BA, $B9, $EF, $00 +$88, $C9, $30, $F0, $F8, $C9, $2E, $F0 +$01, $C8, $A9, $2B, $A6, $A9, $F0, $2E +$10, $08, $A9, $00, $38, $E5, $A9, $AA +$A9, $2D, $99, $F1, $00, $A9, $45, $99 +$F0, $00, $8A, $A2, $2F, $38, $E8, $E9 +$0A, $B0, $FB, $69, $3A, $99, $F3, $00 +$8A, $99, $F2, $00, $A9, $00, $99, $F4 +$00, $F0, $08, $99, $EF, $00, $A9, $00 +$99, $F0, $00, $A9, $F0, $A0, $00, $60 +$F0, $42, $A5, $B3, $D0, $03, $4C, $57 +$D6, $A2, $9C, $A0, $00, $20, $AC, $D8 +$A5, $B7, $10, $0F, $20, $86, $D9, $A9 +$9C, $A0, $00, $20, $1C, $D9, $D0, $03 +$98, $A4, $5B, $20, $CA, $D5, $98, $48 +$20, $00, $D7, $A9, $9C, $A0, $00, $20 +$3E, $D7, $20, $04, $DC, $68, $4A, $90 +$0A, $A5, $AC, $F0, $06, $A5, $B0, $49 +$FF, $85, $B0, $60, $A9, $8E, $A0, $E1 +$20, $3E, $D7, $A5, $B9, $69, $50, $90 +$03, $20, $E6, $D8, $85, $A3, $20, $D2 +$D8, $A5, $AC, $C9, $88, $90, $03, $20 +$D3, $D7, $20, $86, $D9, $A5, $5B, $18 +$69, $81, $F0, $F3, $38, $E9, $01, $48 +$A2, $04, $B5, $B3, $B4, $AC, $95, $AC +$94, $B3, $CA, $10, $F5, $A5, $A3, $85 +$B9, $20, $AB, $D5, $20, $F9, $DB, $A9 +$92, $A0, $E1, $20, $6C, $DC, $A9, $00 +$85, $B8, $68, $4C, $B8, $D7, $85, $BA +$84, $BB, $20, $A2, $D8, $A9, $A4, $20 +$3E, $D7, $20, $70, $DC, $A9, $A4, $A0 +$00, $4C, $3E, $D7, $85, $BA, $84, $BB +$A2, $A8, $20, $A4, $D8, $B1, $BA, $85 +$B1, $A4, $BA, $C8, $98, $D0, $02, $E6 +$BB, $85, $BA, $A4, $BB, $20, $3E, $D7 +$A5, $BA, $A4, $BB, $18, $69, $04, $90 +$01, $C8, $85, $BA, $84, $BB, $20, $C3 +$D5, $A9, $A8, $A0, $00, $C6, $B1, $D0 +$E4, $60, $A5, $AC, $F0, $07, $A2, $D8 +$A0, $00, $20, $AC, $D8, $A2, $AF, $A0 +$13, $06, $D9, $26, $DA, $26, $DB, $26 +$D8, $90, $05, $8A, $45, $D9, $85, $D9 +$88, $D0, $EE, $A2, $02, $B5, $D9, $95 +$AD, $CA, $10, $F9, $A9, $80, $85, $AC +$0A, $85, $B0, $4C, $39, $D6, $A9, $AF +$A0, $E1, $20, $C3, $D5, $20, $CF, $D8 +$A9, $C4, $A0, $E1, $A6, $B7, $20, $FE +$D7, $20, $CF, $D8, $20, $86, $D9, $A9 +$00, $85, $B8, $20, $AB, $D5, $A9, $F6 +$A0, $E1, $20, $A8, $D5, $A5, $B0, $48 +$10, $0D, $20, $BF, $D5, $A5, $B0, $30 +$09, $A5, $63, $49, $FF, $85, $63, $20 +$F9, $DB, $A9, $F6, $A0, $E1, $20, $C3 +$D5, $68, $10, $03, $20, $F9, $DB, $A9 +$B3, $A0, $E1, $4C, $56, $DC, $20, $A2 +$D8, $A9, $00, $85, $63, $20, $DD, $DC +$A2, $9C, $A0, $00, $20, $AC, $D8, $A9 +$A4, $A0, $00, $20, $82, $D8, $A9, $00 +$85, $B0, $A5, $63, $20, $4E, $DD, $A9 +$9C, $A0, $00, $4C, $06, $D8, $48, $4C +$0F, $DD, $20, $0A, $00, $4C, $F4, $CB +$A5, $B0, $48, $10, $03, $20, $F9, $DB +$A5, $AC, $48, $C9, $81, $90, $07, $A9 +$E9, $A0, $E1, $20, $06, $D8, $A9, $C8 +$A0, $E1, $20, $56, $DC, $68, $C9, $81 +$90, $07, $A9, $AF, $A0, $E1, $20, $A8 +$D5, $68, $10, $16, $4C, $F9, $DB, $20 +$DD, $D4, $E0, $08, $B0, $20, $A9, $00 +$38, $2A, $CA, $10, $FC, $E8, $01, $11 +$81, $11, $60, $20, $DD, $D4, $E0, $08 +$B0, $0C, $A9, $FF, $2A, $CA, $10, $FC +$E8, $21, $11, $81, $11, $60, $4C, $2E +$CF, $20, $BC, $00, $20, $DD, $D4, $E0 +$08, $B0, $F3, $20, $C2, $00, $C9, $29 +$F0, $03, $4C, $07, $CC, $20, $BC, $00 +$A9, $00, $38, $2A, $CA, $10, $FC, $E8 +$21, $11, $F0, $02, $A9, $FF, $4C, $FF +$D8, $E0, $19, $B0, $48, $86, $78, $A9 +$18, $20, $3F, $D1, $A0, $17, $A2, $18 +$46, $11, $66, $12, $66, $13, $8A, $2A +$91, $AD, $88, $10, $F3, $A5, $78, $F0 +$0A, $AA, $38, $49, $FF, $69, $18, $F0 +$1C, $D0, $0F, $A8, $B1, $AD, $C9, $30 +$D0, $07, $CA, $F0, $03, $C8, $10, $F4 +$E8, $98, $18, $65, $AD, $85, $AD, $A9 +$00, $65, $AE, $85, $AE, $86, $AC, $20 +$BC, $00, $4C, $8A, $D1, $4C, $2E, $CF +$E0, $07, $B0, $F9, $86, $78, $A9, $06 +$20, $3F, $D1, $A0, $05, $F8, $A5, $13 +$20, $56, $DE, $A5, $12, $20, $56, $DE +$A5, $11, $20, $56, $DE, $D8, $A2, $06 +$A5, $78, $F0, $B7, $AA, $38, $49, $FF +$69, $06, $F0, $C9, $D0, $BC, $AA, $29 +$0F, $20, $61, $DE, $8A, $4A, $4A, $4A +$4A, $C9, $0A, $69, $30, $91, $AD, $88 +$60, $85, $AC, $A9, $00, $85, $B8, $8A +$20, $4A, $DA, $20, $BC, $00, $90, $0A +$09, $20, $E9, $61, $C9, $06, $B0, $2A +$69, $0A, $29, $0F, $AA, $A5, $AC, $F0 +$E4, $69, $04, $90, $DC, $4C, $C8, $D6 +$AA, $A5, $AC, $F0, $06, $E6, $AC, $F0 +$F4, $A9, $00, $85, $B8, $8A, $20, $4A +$DA, $20, $BC, $00, $49, $30, $C9, $02 +$90, $E6, $4C, $2F, $DA, $AD, $00, $02 +$D0, $18, $20, $EF, $E0, $90, $0B, $8D +$01, $02, $A2, $20, $8E, $02, $02, $4C +$1C, $C5, $AE, $02, $02, $F0, $03, $CE +$02, $02, $A2, $DC, $20, $D5, $DE, $A2 +$DF, $20, $D5, $DE, $60, $B5, $00, $10 +$FB, $0A, $29, $40, $F0, $F6, $95, $00 +$8A, $A8, $68, $68, $A9, $05, $20, $07 +$C1, $A5, $C4, $48, $A5, $C3, $48, $A5 +$88, $48, $A5, $87, $48, $A9, $8D, $48 +$B9, $01, $00, $85, $C3, $B9, $02, $00 +$85, $C4, $4C, $C1, $C4, $20, $EF, $E0 +$B0, $09, $AD, $02, $02, $F0, $09, $AD +$01, $02, $38, $A2, $00, $8E, $02, $02 +$60, $A2, $DF, $2C, $A2, $DC, $C9, $93 +$F0, $11, $C9, $B5, $F0, $07, $49, $A2 +$F0, $0E, $4C, $07, $CC, $A9, $7F, $35 +$00, $10, $05, $B5, $00, $0A, $15, $00 +$95, $00, $4C, $BC, $00, $58, $A2, $DF +$2C, $A2, $DC, $86, $78, $20, $BC, $00 +$20, $5A, $C7, $A5, $79, $A6, $7A, $20 +$2D, $C3, $B0, $03, $4C, $77, $C6, $A6 +$78, $A5, $AA, $E9, $01, $95, $01, $A5 +$AB, $E9, $00, $95, $02, $A9, $C0, $95 +$00, $60, $D0, $FD, $A5, $DF, $0A, $05 +$DF, $85, $DF, $4C, $7E, $C6, $D0, $F1 +$A5, $DC, $0A, $05, $DC, $85, $DC, $4C +$7E, $C6, $20, $EE, $CA, $4C, $D5, $CA +$20, $B6, $DF, $10, $FB, $A5, $B4, $09 +$80, $85, $B4, $20, $C8, $D5, $F0, $F0 +$20, $B6, $DF, $30, $FB, $F0, $F9, $A5 +$B4, $09, $80, $85, $B4, $20, $C8, $D5 +$F0, $EE, $C9, $29, $D0, $05, $68, $68 +$4C, $BC, $00, $4C, $07, $CC, $20, $C2 +$00, $C9, $2C, $D0, $ED, $20, $DE, $D8 +$A5, $B0, $09, $7F, $25, $AD, $48, $A5 +$AE, $48, $A5, $AF, $48, $A5, $AC, $48 +$20, $BC, $00, $20, $D2, $CA, $68, $85 +$B3, $68, $85, $B6, $68, $85, $B5, $68 +$85, $B4, $85, $B7, $A9, $B3, $A0, $00 +$4C, $1C, $D9, $C9, $2C, $F0, $1B, $20 +$91, $D4, $8A, $F0, $0A, $E0, $10, $90 +$45, $E4, $64, $B0, $02, $86, $64, $86 +$0F, $20, $C2, $00, $F0, $1A, $C9, $2C +$D0, $A9, $20, $8E, $D4, $8A, $30, $2E +$E0, $01, $90, $2A, $A5, $0F, $F0, $06 +$E4, $0F, $F0, $02, $B0, $20, $86, $64 +$A5, $0F, $F0, $06, $C5, $64, $B0, $03 +$85, $64, $38, $E5, $64, $B0, $FC, $65 +$64, $18, $65, $64, $85, $10, $A5, $0F +$38, $E5, $10, $85, $10, $60, $4C, $2E +$CF, $A5, $B0, $30, $F9, $A5, $AC, $F0 +$F4, $20, $CF, $D8, $A9, $00, $85, $77 +$85, $76, $85, $75, $85, $78, $85, $AF +$85, $AE, $85, $AD, $A2, $18, $A5, $B3 +$4A, $B0, $0E, $06, $B6, $26, $B5, $26 +$B4, $26, $77, $26, $76, $26, $75, $26 +$78, $06, $B6, $26, $B5, $26, $B4, $26 +$77, $26, $76, $26, $75, $26, $78, $06 +$AF, $26, $AE, $26, $AD, $A5, $AF, $2A +$85, $5B, $A5, $AE, $2A, $85, $5C, $A5 +$AD, $2A, $85, $5D, $A9, $00, $2A, $85 +$5E, $A5, $77, $E5, $5B, $85, $5B, $A5 +$76, $E5, $5C, $85, $5C, $A5, $75, $E5 +$5D, $A8, $A5, $78, $E5, $5E, $90, $0E +$85, $78, $84, $75, $A5, $5C, $85, $76 +$A5, $5B, $85, $77, $E6, $AF, $CA, $D0 +$A2, $38, $A5, $B3, $E9, $80, $6A, $69 +$00, $85, $AC, $4C, $39, $D6, $20, $BC +$00, $20, $AF, $CD, $20, $F4, $CB, $A4 +$95, $A5, $96, $4C, $5E, $D0, $A9, $C4 +$A0, $E1, $20, $82, $D8, $C6, $AC, $60 +$A9, $C4, $A0, $E1, $4C, $82, $D8, $6C +$05, $02, $6C, $07, $02, $6C, $09, $02 +$6C, $0B, $02, $FF, $00, $00, $AD, $DE +$C0, $FF, $D3, $FF, $E6, $C3, $D0, $02 +$E6, $C4, $AD, $FF, $FF, $C9, $AC, $F0 +$0E, $C9, $3A, $B0, $0A, $C9, $20, $F0 +$EB, $38, $E9, $30, $38, $E9, $D0, $60 +$4C, $00, $C0, $00, $00, $00, $00, $00 +$00, $00, $4C, $2E, $CF, $00, $00, $00 +$F2, $00, $03, $0D, $0A, $4D, $65, $6D +$6F, $72, $79, $20, $73, $69, $7A, $65 +$20, $00, $20, $42, $79, $74, $65, $73 +$20, $66, $72, $65, $65, $0D, $0A, $0A +$45, $6E, $68, $61, $6E, $63, $65, $64 +$20, $42, $41, $53, $49, $43, $20, $32 +$2E, $32, $32, $0A, $00, $02, $80, $19 +$56, $62, $80, $76, $22, $F3, $82, $38 +$AA, $40, $80, $35, $04, $F3, $81, $35 +$04, $F3, $80, $80, $00, $00, $80, $31 +$72, $18, $91, $43, $4F, $F8, $94, $74 +$23, $F7, $94, $74, $24, $00, $81, $38 +$AA, $3B, $06, $74, $63, $90, $8C, $77 +$23, $0C, $AB, $7A, $1E, $94, $00, $7C +$63, $42, $80, $7E, $75, $FE, $D0, $80 +$31, $72, $15, $81, $00, $00, $00, $81 +$49, $0F, $DB, $04, $86, $1E, $D7, $FB +$87, $99, $26, $65, $87, $23, $34, $58 +$86, $A5, $5D, $E1, $83, $49, $0F, $DB +$08, $78, $3A, $C5, $37, $7B, $83, $A2 +$5C, $7C, $2E, $DD, $4D, $7D, $99, $B0 +$1E, $7D, $59, $ED, $24, $7E, $91, $72 +$00, $7E, $4C, $B9, $73, $7F, $AA, $AA +$53, $81, $00, $00, $00, $81, $80, $00 +$00, $90, $80, $00, $00, $00, $7F, $00 +$00, $00, $84, $20, $00, $00, $FE, $79 +$60, $00, $27, $10, $FF, $FC, $18, $00 +$00, $64, $FF, $FF, $F6, $00, $00, $01 +$1F, $C5, $5C, $C4, $69, $CA, $90, $C6 +$4B, $C9, $63, $CD, $6B, $C9, $B8, $C7 +$8A, $C7, $EF, $C5, $AE, $C5, $BE, $C6 +$46, $C5, $D2, $C5, $69, $DF, $75, $DF +$7B, $C6, $22, $C7, $1D, $C5, $2B, $C7 +$84, $C5, $8D, $C7, $8D, $D5, $F4, $E0 +$F7, $E0, $78, $D0, $12, $D5, $2E, $D5 +$7B, $D5, $B8, $C5, $21, $C6, $59, $C8 +$8A, $C5, $A7, $C3, $A4, $C3, $52, $C3 +$EA, $DF, $28, $C8, $53, $D5, $86, $DD +$9A, $DD, $18, $DF, $1B, $DF, $69, $CC +$69, $CC, $69, $CC, $ED, $CA, $F0, $CB +$F0, $CB, $69, $CC, $69, $CC, $69, $CC +$69, $CC, $69, $CC, $69, $CC, $69, $CC +$69, $CC, $69, $CC, $69, $CC, $00, $00 +$63, $CC, $69, $CC, $63, $CC, $63, $CC +$63, $CC, $63, $CC, $69, $CC, $90, $CC +$90, $CC, $00, $00, $81, $DF, $81, $DF +$6F, $CC, $6F, $CC, $00, $00, $74, $CC +$74, $CC, $74, $CC, $FB, $D8, $85, $D9 +$18, $D9, $51, $DD, $49, $D0, $68, $D0 +$40, $E0, $A1, $DC, $FF, $D6, $03, $DC +$D5, $DC, $DC, $DC, $25, $DD, $57, $DD +$07, $D5, $1B, $D5, $59, $D4, $72, $D4 +$2A, $D1, $9F, $D4, $7D, $D4, $37, $D4 +$16, $D4, $88, $D3, $27, $DE, $D8, $DD +$B0, $DD, $87, $DF, $97, $DF, $DD, $E0 +$E7, $E0, $CD, $E0, $9A, $D3, $A3, $D3 +$D2, $D3, $79, $C5, $D5, $79, $AA, $D5 +$7B, $40, $D7, $7B, $08, $D8, $7F, $BF +$DB, $50, $D9, $CC, $46, $BF, $CC, $46 +$CC, $CC, $56, $85, $CD, $56, $6D, $CD +$7D, $F8, $DB, $5A, $1B, $CC, $64, $FA +$CC, $2A, $2B, $2D, $2F, $3C, $3D, $3E +$3F, $41, $42, $43, $44, $45, $46, $47 +$48, $49, $4C, $4D, $4E, $4F, $50, $52 +$53, $54, $55, $56, $57, $5E, $00, $71 +$E3, $73, $E3, $75, $E3, $77, $E3, $79 +$E3, $7D, $E3, $7F, $E3, $83, $E3, $85 +$E3, $95, $E3, $AE, $E3, $C5, $E3, $DE +$E3, $ED, $E3, $F7, $E3, $04, $E4, $0A +$E4, $1C, $E4, $41, $E4, $4F, $E4, $61 +$E4, $69, $E4, $7E, $E4, $AD, $E4, $D8 +$E4, $EC, $E4, $FD, $E4, $09, $E5, $18 +$E5, $B8, $00, $B6, $00, $B7, $00, $B9 +$00, $3C, $BF, $C2, $00, $C1, $00, $3E +$BE, $C0, $00, $9F, $00, $42, $53, $28 +$C5, $4E, $44, $BB, $53, $43, $28, $D7 +$54, $4E, $28, $D0, $00, $49, $4E, $24 +$28, $DC, $49, $54, $43, $4C, $52, $A8 +$49, $54, $53, $45, $54, $A7, $49, $54 +$54, $53, $54, $28, $DD, $00, $41, $4C +$4C, $9C, $48, $52, $24, $28, $DA, $4C +$45, $41, $52, $A2, $4F, $4E, $54, $A0 +$4F, $53, $28, $CD, $00, $41, $54, $41 +$83, $45, $43, $88, $45, $45, $4B, $28 +$D2, $45, $46, $99, $49, $4D, $85, $4F +$4B, $45, $9B, $4F, $9D, $00, $4C, $53 +$45, $AC, $4E, $44, $80, $4F, $52, $BC +$58, $50, $28, $CC, $00, $4E, $AE, $4F +$52, $81, $52, $45, $28, $C7, $00, $45 +$54, $A5, $4F, $53, $55, $42, $8D, $4F +$54, $4F, $89, $00, $45, $58, $24, $28 +$DB, $00, $46, $8B, $4E, $43, $95, $4E +$50, $55, $54, $84, $4E, $54, $28, $C4 +$52, $51, $A9, $00, $43, $41, $53, $45 +$24, $28, $D9, $45, $46, $54, $24, $28 +$E3, $45, $4E, $28, $D4, $45, $54, $87 +$49, $53, $54, $A1, $4F, $41, $44, $97 +$4F, $47, $28, $CB, $4F, $4F, $50, $9E +$00, $41, $58, $28, $DE, $49, $44, $24 +$28, $E5, $49, $4E, $28, $DF, $00, $45 +$57, $A3, $45, $58, $54, $82, $4D, $49 +$AA, $4F, $54, $B1, $55, $4C, $4C, $94 +$00, $46, $46, $B5, $4E, $93, $52, $BD +$00, $45, $45, $4B, $28, $D1, $49, $E0 +$4F, $4B, $45, $9A, $4F, $53, $28, $C8 +$52, $49, $4E, $54, $9F, $00, $45, $41 +$44, $86, $45, $4D, $91, $45, $53, $54 +$4F, $52, $45, $8C, $45, $54, $49, $52 +$51, $8E, $45, $54, $4E, $4D, $49, $8F +$45, $54, $55, $52, $4E, $90, $49, $47 +$48, $54, $24, $28, $E4, $4E, $44, $28 +$CA, $55, $4E, $8A, $00, $41, $44, $44 +$28, $D3, $41, $56, $45, $98, $47, $4E +$28, $C3, $49, $4E, $28, $CE, $50, $43 +$28, $AF, $51, $52, $28, $C9, $54, $45 +$50, $B2, $54, $4F, $50, $92, $54, $52 +$24, $28, $D5, $57, $41, $50, $A6, $00 +$41, $42, $28, $AB, $41, $4E, $28, $CF +$48, $45, $4E, $B0, $4F, $AD, $57, $4F +$50, $49, $E1, $00, $43, $41, $53, $45 +$24, $28, $D8, $4E, $54, $49, $4C, $B3 +$53, $52, $28, $C6, $00, $41, $4C, $28 +$D6, $41, $52, $50, $54, $52, $28, $E2 +$00, $41, $49, $54, $96, $48, $49, $4C +$45, $B4, $49, $44, $54, $48, $A4, $00 +$BA, $00, $03, $45, $E2, $E3, $03, $46 +$EF, $E3, $04, $4E, $52, $E4, $04, $44 +$C5, $E3, $05, $49, $0F, $E4, $03, $44 +$D4, $E3, $04, $52, $7E, $E4, $03, $4C +$2D, $E4, $03, $44, $C9, $E3, $04, $47 +$FF, $E3, $03, $52, $A9, $E4, $02, $49 +$0A, $E4, $07, $52, $85, $E4, $05, $47 +$FA, $E3, $06, $52, $8C, $E4, $06, $52 +$92, $E4, $06, $52, $98, $E4, $03, $52 +$82, $E4, $04, $53, $CA, $E4, $02, $4F +$64, $E4, $04, $4E, $5C, $E4, $03, $49 +$0C, $E4, $04, $57, $09, $E5, $04, $4C +$34, $E4, $04, $53, $B2, $E4, $03, $44 +$D1, $E3, $04, $50, $70, $E4, $04, $44 +$D7, $E3, $04, $43, $AE, $E3, $02, $44 +$DB, $E3, $04, $4C, $3C, $E4, $05, $50 +$78, $E4, $04, $43, $BC, $E3, $04, $4C +$30, $E4, $05, $43, $B7, $E3, $03, $4E +$4F, $E4, $05, $57, $12, $E5, $03, $47 +$F7, $E3, $04, $53, $D3, $E4, $06, $42 +$A0, $E3, $06, $42, $9A, $E3, $03, $49 +$18, $E4, $03, $4E, $56, $E4, $04, $54 +$D8, $E4, $04, $45, $DE, $E3, $02, $54 +$E4, $E4, $02, $46, $ED, $E3, $04, $53 +$BE, $E4, $04, $54, $E0, $E4, $03, $4E +$59, $E4, $04, $53, $C6, $E4, $05, $55 +$F3, $E4, $05, $57, $0D, $E5, $03, $4F +$61, $E4, $01, $2B, $00, $00, $01, $2D +$00, $00, $01, $2A, $00, $00, $01, $2F +$00, $00, $01, $5E, $00, $00, $03, $41 +$89, $E3, $03, $45, $E5, $E3, $02, $4F +$66, $E4, $02, $3E, $7F, $E3, $02, $3C +$79, $E3, $01, $3E, $00, $00, $01, $3D +$00, $00, $01, $3C, $00, $00, $04, $53 +$B6, $E4, $04, $49, $14, $E4, $04, $41 +$85, $E3, $04, $55, $F8, $E4, $04, $46 +$F2, $E3, $04, $50, $74, $E4, $04, $53 +$C2, $E4, $04, $52, $A5, $E4, $04, $4C +$38, $E4, $04, $45, $E8, $E3, $04, $43 +$C0, $E3, $04, $53, $BA, $E4, $04, $54 +$DC, $E4, $04, $41, $90, $E3, $05, $50 +$69, $E4, $05, $44, $CC, $E3, $05, $53 +$AD, $E4, $04, $4C, $29, $E4, $05, $53 +$CE, $E4, $04, $56, $FD, $E4, $04, $41 +$8C, $E3, $07, $55, $EC, $E4, $07, $4C +$1C, $E4, $05, $43, $B2, $E3, $05, $48 +$04, $E4, $05, $42, $95, $E3, $07, $42 +$A6, $E3, $04, $4D, $41, $E4, $04, $4D +$4A, $E4, $02, $50, $6E, $E4, $05, $54 +$E6, $E4, $07, $56, $01, $E5, $06, $4C +$23, $E4, $07, $52, $9E, $E4, $05, $4D +$45, $E4, $D6, $E6, $E7, $E6, $EE, $E6 +$03, $E7, $0F, $E7, $1D, $E7, $26, $E7 +$34, $E7, $48, $E7, $55, $E7, $66, $E7 +$75, $E7, $84, $E7, $92, $E7, $A2, $E7 +$B5, $E7, $C4, $E7, $D7, $E7, $4E, $45 +$58, $54, $20, $77, $69, $74, $68, $6F +$75, $74, $20, $46, $4F, $52, $00, $53 +$79, $6E, $74, $61, $78, $00, $52, $45 +$54, $55, $52, $4E, $20, $77, $69, $74 +$68, $6F, $75, $74, $20, $47, $4F, $53 +$55, $42, $00, $4F, $75, $74, $20, $6F +$66, $20, $44, $41, $54, $41, $00, $46 +$75, $6E, $63, $74, $69, $6F, $6E, $20 +$63, $61, $6C, $6C, $00, $4F, $76, $65 +$72, $66, $6C, $6F, $77, $00, $4F, $75 +$74, $20, $6F, $66, $20, $6D, $65, $6D +$6F, $72, $79, $00, $55, $6E, $64, $65 +$66, $69, $6E, $65, $64, $20, $73, $74 +$61, $74, $65, $6D, $65, $6E, $74, $00 +$41, $72, $72, $61, $79, $20, $62, $6F +$75, $6E, $64, $73, $00, $44, $6F, $75 +$62, $6C, $65, $20, $64, $69, $6D, $65 +$6E, $73, $69, $6F, $6E, $00, $44, $69 +$76, $69, $64, $65, $20, $62, $79, $20 +$7A, $65, $72, $6F, $00, $49, $6C, $6C +$65, $67, $61, $6C, $20, $64, $69, $72 +$65, $63, $74, $00, $54, $79, $70, $65 +$20, $6D, $69, $73, $6D, $61, $74, $63 +$68, $00, $53, $74, $72, $69, $6E, $67 +$20, $74, $6F, $6F, $20, $6C, $6F, $6E +$67, $00, $53, $74, $72, $69, $6E, $67 +$20, $74, $6F, $6F, $20, $63, $6F, $6D +$70, $6C, $65, $78, $00, $43, $61, $6E +$27, $74, $20, $63, $6F, $6E, $74, $69 +$6E, $75, $65, $00, $55, $6E, $64, $65 +$66, $69, $6E, $65, $64, $20, $66, $75 +$6E, $63, $74, $69, $6F, $6E, $00, $4C +$4F, $4F, $50, $20, $77, $69, $74, $68 +$6F, $75, $74, $20, $44, $4F, $00, $0D +$0A, $42, $72, $65, $61, $6B, $00, $20 +$45, $72, $72, $6F, $72, $00, $20, $69 +$6E, $20, $6C, $69, $6E, $65, $20, $00 +$0D, $0A, $52, $65, $61, $64, $79, $0D +$0A, $00, $20, $45, $78, $74, $72, $61 +$20, $69, $67, $6E, $6F, $72, $65, $64 +$0D, $0A, $00, $20, $52, $65, $64, $6F +$20, $66, $72, $6F, $6D, $20, $73, $74 +$61, $72, $74, $0D, $0A, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$00, $00, $00, $00, $00, $00, $00, $00 +$AD, $E1, $FF, $F0, $0C, $C9, $61, $90 +$06, $C9, $7B, $B0, $02, $29, $5F, $38 +$60, $18, $60, $8D, $E0, $FF, $29, $FF +$60, $00, $00, $00, $00, $00, $00, $00 +ORG +$FFFC +$00 $C0 diff --git a/main.cpp b/main.cpp index a5239f7..76d54e1 100644 --- a/main.cpp +++ b/main.cpp @@ -317,6 +317,8 @@ bool ShowRegs(Regs *preg, VMachine *pvm, bool ioecho, bool showiostat) cout << " at: $" << hex << pvm->GetGraphDispAddr() << endl; cout << "ROM: " << ((pvm->IsROMEnabled()) ? "enabled." : "disabled.") << " "; cout << "Range: $" << hex << pvm->GetROMBegin() << " - $" << hex << pvm->GetROMEnd() << "." << endl; + cout << "Op-code execute history: " << (pvm->IsExecHistoryActive() ? "enabled" : "disabled"); + cout << "." << endl; } cout << " \r"; @@ -341,9 +343,9 @@ void ShowMenu() cout << " E - toggle I/O local echo | F - toggle registers animation" << endl; cout << " J - set animation delay | M - dump memory, W - write memory" << endl; cout << " K - toggle ROM emulation | R - show registers, Y - snapshot" << endl; - cout << " L - load memory image | O - display op-codes history" << endl; + cout << " L - load memory image | O - display op-code exec. history" << endl; cout << " D - disassemble code in memory | Q - quit, 0 - reset, H - help" << endl; - cout << " V - toggle graphics emulation |" << endl; + cout << " V - toggle graphics emulation | U - enable/disable exec. history" << endl; cout << "------------------------------------+----------------------------------------" << endl; } @@ -392,6 +394,227 @@ void ShowMenu() } \ } +/* + *-------------------------------------------------------------------- + * Method: ShowSpeedStats() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +void ShowSpeedStats() +{ + cout << endl; + cout << dec; + cout << "CPU emulation speed stats: " << endl; + cout << "|-> Average speed based on 1MHz CPU: " << pvm->GetPerfStats().perf_onemhz << " %" << endl; + cout << "|-> Last measured # of cycles exec.: " << pvm->GetPerfStats().prev_cycles << endl; + cout << "|-> Last measured time of execution: " << pvm->GetPerfStats().prev_usec << " usec" << endl; + cout << endl; +} + +/* + *-------------------------------------------------------------------- + * Method: ExecHistory() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +void ExecHistory() +{ + if (pvm->IsExecHistoryActive()) { + queue exechist(pvm->GetExecHistory()); + cout << "PC : INSTR ACC | X | Y | PS | SP" << endl; + cout << "------------------------------------+-----+-----+-----+-----" << endl; + while (exechist.size()) { + cout << exechist.front() << endl; + exechist.pop(); + } + } else { + cout << "Sorry. Op-code execute history is currently disabled." << endl; + } +} + +/* + *-------------------------------------------------------------------- + * Method: LoadImage() + * Purpose: Load memory image from file. Set new execute address. + * Arguments: newaddr - current execute address + * Returns: unsigned int - new execute address + *-------------------------------------------------------------------- + */ +unsigned int LoadImage(unsigned int newaddr) +{ + char typ = 0; + for (char c = tolower(typ); + c != 'a' && c != 'b' && c != 'h' && c != 'd'; + c = tolower(typ)) { + cout << "Type (A - auto/B - binary/H - Intel HEX/D - definition): "; + cin >> typ; + } + cout << " ["; + switch (tolower(typ)) { + case 'a': cout << "auto"; break; + case 'b': cout << "binary"; break; + case 'h': cout << "Intel HEX"; break; + case 'd': cout << "definition"; break; + default: break; // should never happen + } + cout << "]" << endl; + string name; + cout << "Memory Image File Name: "; + cin >> name; + cout << " [" << name << "]" << endl; + if (typ == 'b') PrintVMErr (pvm->LoadRAMBin(name)); + else if (typ == 'h') PrintVMErr (pvm->LoadRAMHex(name)); + else if (typ == 'd') { + PrintVMErr (pvm->LoadRAMDef(name)); + if (pvm->IsAutoExec()) execvm = true; + if (newaddr == 0) newaddr = 0x10000; + } + else { // automatic file format detection + pvm->LoadRAM(name); + if (pvm->IsAutoExec()) execvm = true; + if (newaddr == 0) newaddr = 0x10000; + } + + return newaddr; +} + +/* + *-------------------------------------------------------------------- + * Method: ToggleIO() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +unsigned int ToggleIO(unsigned int ioaddr) +{ + if (pvm->GetCharIOActive()) { + pvm->DisableCharIO(); + cout << "I/O deactivated." << endl; + } else { + ioaddr = PromptNewAddress("Address (0..FFFF): "); + cout << " [" << hex << ioaddr << "]" << endl; + pvm->SetCharIO(ioaddr, ioecho); + cout << "I/O activated." << endl; + } + + return ioaddr; +} + +/* + *-------------------------------------------------------------------- + * Method: ToggleGrDisp() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +unsigned int ToggleGrDisp(unsigned int graddr) +{ + if (pvm->GetGraphDispActive()) { + pvm->DisableGraphDisp(); + cout << "Graphics display deactivated." << endl; + } else { + graddr = PromptNewAddress("Address (0..FFFF): "); + cout << " [" << hex << graddr << "]" << endl; + pvm->SetGraphDisp(graddr); + cout << "Graphics display activated." << endl; + } + + return graddr; +} + +/* + *-------------------------------------------------------------------- + * Method: WriteToMemory() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +void WriteToMemory() +{ + unsigned int tmpaddr = PromptNewAddress("Address (0..FFFF): "); + cout << " [" << hex << tmpaddr << "]" << endl; + cout << "Enter hex bytes [00..FF] values separated with NL or spaces, end with [100]:" << endl; + unsigned short v = 0; + while (true) { + cin >> hex >> v; + cout << " " << hex << v; + if (v > 0xFF) break; + pvm->MemPoke8bit(tmpaddr++, v & 0xFF); + }; + cout << endl; +} + +/* + *-------------------------------------------------------------------- + * Method: DisassembleMemory() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +void DisassembleMemory() +{ + unsigned int addrbeg = 0x10000, addrend = 0x10000; + cout << "Enter address range (0..0xFFFF)..." << endl; + addrbeg = PromptNewAddress("Start address (0..FFFF): "); + cout << " [" << hex << addrbeg << "]" << endl; + addrend = PromptNewAddress("End address (0..FFFF): "); + cout << " [" << hex << addrend << "]" << endl; + cout << endl; + for (unsigned int addr = addrbeg; addr <= addrend;) { + char instrbuf[DISS_BUF_SIZE]; + addr = pvm->Disassemble((unsigned short)addr, instrbuf); + cout << instrbuf << endl; + } +} + +/* + *-------------------------------------------------------------------- + * Method: DumpMemory() + * Purpose: + * Arguments: + * Returns: + *-------------------------------------------------------------------- + */ +void DumpMemory() +{ + unsigned int addrbeg = 0x10000, addrend = 0x10000; + cout << "Enter address range (0..0xFFFF)..." << endl; + addrbeg = PromptNewAddress("Start address (0..FFFF): "); + cout << " [" << hex << addrbeg << "]" << endl; + addrend = PromptNewAddress("End address (0..FFFF): "); + cout << " [" << hex << addrend << "]" << endl; + cout << endl; + for (unsigned int addr = addrbeg; addr <= addrend; addr+=16) { + cout << "\t|"; + for (unsigned int j=0; j < 16; j++) { + unsigned int hv = (unsigned int)pvm->MemPeek8bit(addr+j); + if (hv < 16) { + cout << 0; + } + cout << hex << hv << " "; + } + cout << "|"; + for (int j=0; j < 16; j++) { + char cc = (char)pvm->MemPeek8bit(addr+j); + if (isprint(cc)) + cout << cc; + else + cout << "?"; + } + cout << '\r'; + cout << hex << addr; + cout << endl; + } +} + /* *-------------------------------------------------------------------- * Method: LoadArgs() @@ -478,8 +701,8 @@ int main(int argc, char *argv[]) { CopyrightBanner(); string cmd; bool runvm = false, step = false, brk = false, execaddr = false, stop = true; - bool lrts = false, anim = false, enrom = pvm->IsROMEnabled(); - unsigned int newaddr = pvm->GetRunAddr(), ioaddr = pvm->GetCharIOAddr(), tmpaddr = 0x0000; + bool lrts = false, anim = false, enrom = pvm->IsROMEnabled(), show_menu = true; + unsigned int newaddr = pvm->GetRunAddr(), ioaddr = pvm->GetCharIOAddr(); unsigned int graddr = pvm->GetGraphDispAddr(); unsigned int rombegin = pvm->GetROMBegin(), romend = pvm->GetROMEnd(), delay = ANIM_DELAY; int nsteps = 0; @@ -532,19 +755,36 @@ int main(int argc, char *argv[]) { } else if (stop) { cout << "STOPPED at " << hex << ((newaddr > 0xFFFF) ? preg->PtrAddr : newaddr) << endl; } + ShowSpeedStats(); opbrk = brk = stop = lrts = false; pvm->SetOpInterrupt(false); ShowRegs(preg,pvm,ioecho,true); + show_menu = true; + } + if (show_menu) { + + ShowMenu(); + show_menu = false; + + } else { + + cout << endl; + cout << "Type '?' and press ENTER for Menu ..." << endl; + cout << endl; + } - ShowMenu(); cout << "> "; cin >> cmd; char c = tolower(cmd.c_str()[0]); - if (c == 'h') { // display help + if (c == '?') { + show_menu = true; + } + else if (c == 'h') { // display help ShowHelp(); } else if (c == 'p') { // Interrupt ReQuest pvm->Interrupt(); cout << "OK" << endl; + show_menu = true; } else if (c == 'y') { // save snapshot of current CPU and memory in binary image string name; cout << "Enter file name: "; @@ -560,47 +800,11 @@ int main(int argc, char *argv[]) { reset = true; execvm = true; runvm = false; + show_menu = true; } else if (c == 'o') { - queue exechist(pvm->GetExecHistory()); - cout << "PC : INSTR ACC | X | Y | PS | SP" << endl; - cout << "------------------------------------+-----+-----+-----+-----" << endl; - while (exechist.size()) { - cout << exechist.front() << endl; - exechist.pop(); - } + ExecHistory(); } else if (c == 'l') { // load memory image - char typ = 0; - for (char c = tolower(typ); - c != 'a' && c != 'b' && c != 'h' && c != 'd'; - c = tolower(typ)) { - cout << "Type (A - auto/B - binary/H - Intel HEX/D - definition): "; - cin >> typ; - } - cout << " ["; - switch (tolower(typ)) { - case 'a': cout << "auto"; break; - case 'b': cout << "binary"; break; - case 'h': cout << "Intel HEX"; break; - case 'd': cout << "definition"; break; - default: break; // should never happen - } - cout << "]" << endl; - string name; - cout << "Memory Image File Name: "; - cin >> name; - cout << " [" << name << "]" << endl; - if (typ == 'b') PrintVMErr (pvm->LoadRAMBin(name)); - else if (typ == 'h') PrintVMErr (pvm->LoadRAMHex(name)); - else if (typ == 'd') { - PrintVMErr (pvm->LoadRAMDef(name)); - if (pvm->IsAutoExec()) execvm = true; - if (newaddr == 0) newaddr = 0x10000; - } - else { // automatic file format detection - pvm->LoadRAM(name); - if (pvm->IsAutoExec()) execvm = true; - if (newaddr == 0) newaddr = 0x10000; - } + newaddr = LoadImage(newaddr); } else if (c == 'k') { // toggle ROM emulation if (!enrom) { enrom = true; @@ -645,37 +849,11 @@ int main(int argc, char *argv[]) { cout << "ERROR: I/O is deactivated." << endl; } } else if (c == 'i') { // toggle I/O - if (pvm->GetCharIOActive()) { - pvm->DisableCharIO(); - cout << "I/O deactivated." << endl; - } else { - ioaddr = PromptNewAddress("Address (0..FFFF): "); - cout << " [" << hex << ioaddr << "]" << endl; - pvm->SetCharIO(ioaddr, ioecho); - cout << "I/O activated." << endl; - } + ioaddr = ToggleIO(ioaddr); } else if (c == 'v') { // toggle graphics display - if (pvm->GetGraphDispActive()) { - pvm->DisableGraphDisp(); - cout << "Graphics display deactivated." << endl; - } else { - graddr = PromptNewAddress("Address (0..FFFF): "); - cout << " [" << hex << graddr << "]" << endl; - pvm->SetGraphDisp(graddr); - cout << "Graphics display activated." << endl; - } + graddr = ToggleGrDisp(graddr); } else if (c == 'w') { // write to memory - tmpaddr = PromptNewAddress("Address (0..FFFF): "); - cout << " [" << hex << tmpaddr << "]" << endl; - cout << "Enter hex bytes [00..FF] values separated with NL or spaces, end with [100]:" << endl; - unsigned short v = 0; - while (true) { - cin >> hex >> v; - cout << " " << hex << v; - if (v > 0xFF) break; - pvm->MemPoke8bit(tmpaddr++, v & 0xFF); - }; - cout << endl; + WriteToMemory(); } else if (c == 'a') { // change run address execaddr = stop = true; newaddr = PromptNewAddress("Address (0..FFFF): "); @@ -690,62 +868,33 @@ int main(int argc, char *argv[]) { } cout << " [" << dec << nsteps << "]" << endl; runvm = step = stop = true; + show_menu = true; } else if (c == 'c') { // continue running code runvm = true; + show_menu = true; } else if (c == 'g') { // run from new address until BRK runvm = true; execaddr = true; newaddr = PromptNewAddress("Address (0..FFFF): "); cout << " [" << hex << newaddr << "]" << endl; + show_menu = true; } else if (c == 'x') { // execute code at address execvm = true; execaddr = true; newaddr = PromptNewAddress("Address (0..FFFF): "); - cout << " [" << hex << newaddr << "]" << endl; + cout << " [" << hex << newaddr << "]" << endl; + show_menu = true; } else if (c == 'q') { // quit break; } else if (c == 'd') { // disassemble code in memory - unsigned int addrbeg = 0x10000, addrend = 0x10000; - cout << "Enter address range (0..0xFFFF)..." << endl; - addrbeg = PromptNewAddress("Start address (0..FFFF): "); - cout << " [" << hex << addrbeg << "]" << endl; - addrend = PromptNewAddress("End address (0..FFFF): "); - cout << " [" << hex << addrend << "]" << endl; - cout << endl; - for (unsigned int addr = addrbeg; addr <= addrend;) { - char instrbuf[DISS_BUF_SIZE]; - addr = pvm->Disassemble((unsigned short)addr, instrbuf); - cout << instrbuf << endl; - } + DisassembleMemory(); } else if (c == 'm') { // dump memory - unsigned int addrbeg = 0x10000, addrend = 0x10000; - cout << "Enter address range (0..0xFFFF)..." << endl; - addrbeg = PromptNewAddress("Start address (0..FFFF): "); - cout << " [" << hex << addrbeg << "]" << endl; - addrend = PromptNewAddress("End address (0..FFFF): "); - cout << " [" << hex << addrend << "]" << endl; + DumpMemory(); + } else if (c == 'u') { // toggle enable/disable op-code exec. history + pvm->EnableExecHistory(!pvm->IsExecHistoryActive()); + cout << "Op-code execute history has been "; + cout << (pvm->IsExecHistoryActive() ? "enabled" : "disabled") << "."; cout << endl; - for (unsigned int addr = addrbeg; addr <= addrend; addr+=16) { - cout << "\t|"; - for (unsigned int j=0; j < 16; j++) { - unsigned int hv = (unsigned int)pvm->MemPeek8bit(addr+j); - if (hv < 16) { - cout << 0; - } - cout << hex << hv << " "; - } - cout << "|"; - for (int j=0; j < 16; j++) { - char cc = (char)pvm->MemPeek8bit(addr+j); - if (isprint(cc)) - cout << cc; - else - cout << "?"; - } - cout << '\r'; - cout << hex << addr; - cout << endl; - } } } } @@ -963,11 +1112,32 @@ L - load memory image in decimal or hexadecimal format. RESET Enables auto-reset of the CPU. After loading the memory - definition file, the CPU reset sequence will be initiated. + definition file, the CPU reset sequence will be initiated. + + ENGRAPH Enables raster graphics device emulation. + + GRAPHADDR Defines the base address of raster graphics device. The next + line that follows sets the address in decimal or hexadecimal + format. + + NOTE: The binary image file can contain a header which contains + definitions corresponding to the above parameters at fixed + positions. This header is created when user saves the snapshot of + current emulator memory image and status. Example use scenario: + * User loads the image definition file. + * User adjusts various parameters of the emulator + (enables/disables devices, sets addresses, changes memory + contents). + * User saves the snapshot with 'Y' command. + * Next time user loads the snapshot image, all the parameters + and memory contents stick. This way game status can be saved + or a BASIC interpreter with BASIC program in it. + See command 'Y' for details. O - display op-codes history Show the history of last executed op-codes/instructions, full with - disassembled mnemonic and argument. + disassembled mnemonic, argument and CPU registers and status. + NOTE: op-codes execute history must be enabled, see command 'U'. D - diassemble code in memory Usage: D [startaddr] [endaddr] Where: startaddr,endaddr - hexadecimal address [0000..FFFF]. @@ -983,6 +1153,11 @@ D - diassemble code in memory jumping to main loop. The reset routine disables trapping last RTS opcode if stack is empty, so the VM will never return from opcodes execution loop unless user interrupts with CTRL-C or CTRL-Break. +? - display commands menu + Display the menu of all available in Debug Console commands. +U - enable/disable exec. history + Toggle enable/disable of op-codes execute history. + Disabling this feature improves performance. NOTE: 1. If no arguments provided, each command will prompt user to enter