//============================================================================= // eTape::ParseCSW //----------------------------------------------------------------------------- bool eTape::ParseCSW(const void* data, size_t data_size) { const byte* buf = (const byte*)data; const dword Z80FQ = 3500000; CloseTape(); NamedCell("CSW tape image"); if(buf[0x1B] != 1) return false; // unknown compression type dword rate = Z80FQ / Word(buf + 0x19); // usually 3.5mhz / 44khz if(!rate) return false; Reserve(data_size - 0x18); if(!(buf[0x1C] & 1)) tape_image[tape_imagesize++] = FindPulse(1); for(const byte* ptr = (const byte*)data + 0x20; ptr < (const byte*)data + data_size;) { dword len = *ptr++ * rate; if(!len) { len = Dword(ptr) / rate; ptr += 4; } tape_image[tape_imagesize++] = FindPulse(len); } tape_image[tape_imagesize++] = FindPulse(Z80FQ / 10); FindTapeSizes(); return true; }
/* * Subroutine to do actual fixing after state initialization. */ static void Dfix2(Char **v) { ginit(); /* Initialize glob's area pointers */ Dvp = v; Dcp = STRNULL; /* Setup input vector for Dreadc */ unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */ dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */ while (Dword()) continue; }
/* ============= CheckSizeToWrite ============= */ void MemoryWriter::CheckSizeToWrite( Dword sizeToWrite ) { if( this->pos + sizeToWrite > this->buffer.getLength() ) { Dword toAdd = Dword( Math::Ceil( float( sizeToWrite - ( this->buffer.getLength() - this->pos ) ) / float( this->blockSize ) ) ) * this->blockSize; if( this->buffer.getLength() ) { memory temp( this->buffer ); this->buffer.realloc( this->buffer.getLength() + toAdd ); memcpy( this->buffer.getData(), temp.getData(), temp.getLength() ); } else this->buffer.alloc( toAdd ); } }//CheckSizeToWrite
/* * Subroutine to do actual fixing after state initialization. */ void Dfix2(tchar **v) { tchar *agargv[GAVSIZ]; #ifdef TRACE tprintf("TRACE- Dfix2()\n"); #endif ginit(agargv); /* Initialize glob's area pointers */ Dvp = v; Dcp = S_ /* "" */; /* Setup input vector for Dreadc */ unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */ dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */ while (Dword()) continue; gargv = copyblk(gargv); }
//============================================================================= // eFdd::ReadFdi //----------------------------------------------------------------------------- bool eFdd::ReadFdi(const void* _data, size_t data_size) { const byte* buf = (const byte*)_data; SAFE_DELETE(disk); disk = new eUdi(buf[4], buf[6]); const byte* trk = buf + 0x0E + Word(buf + 0x0C); const byte* dat = buf + Word(buf + 0x0A); for(int i = 0; i < disk->Cyls(); ++i) { for(int j = 0; j < disk->Sides(); ++j) { Seek(i, j); int id_len = Track().data_len / 8 + ((Track().data_len & 7) ? 1 : 0); memset(Track().data, 0, Track().data_len + id_len); int pos = 0; WriteBlock(pos, 0x4e, 80); //gap4a WriteBlock(pos, 0, 12); //sync WriteBlock(pos, 0xc2, 3, true); //iam Write(pos++, 0xfc); const byte* t0 = dat + Dword(trk); int ns = trk[6]; Track().sectors_amount = ns; trk += 7; for(int i = 0; i < ns; ++i) { WriteBlock(pos, 0x4e, 40); //gap1 50 fixme: recalculate gap1 only for non standard formats WriteBlock(pos, 0, 12); //sync WriteBlock(pos, 0xa1, 3, true); //id am Write(pos++, 0xfe); eUdi::eTrack::eSector& sec = Sector(i); sec.id = Track().data + pos; Write(pos++, trk[0]); Write(pos++, trk[1]); Write(pos++, trk[2]); Write(pos++, trk[3]); word crc = Crc(Track().data + pos - 5, 5); Write(pos++, crc >> 8); Write(pos++, (byte)crc); if(trk[4] & 0x40) { sec.data = NULL; } else { const byte* data = t0 + Word(trk+5); if(data + 128 > buf + data_size) return false; WriteBlock(pos, 0x4e, 22); //gap2 WriteBlock(pos, 0, 12); //sync WriteBlock(pos, 0xa1, 3, true); //data am Write(pos++, 0xfb); sec.data = Track().data + pos; int len = sec.Len(); memcpy(sec.data, data, len); crc = Crc(Track().data + pos - 1, len + 1); if(!(trk[4] & (1<<(trk[3] & 3)))) crc ^= 0xffff; pos += len; Write(pos++, crc >> 8); Write(pos++, (byte)crc); } trk += 7; } if(pos > Track().data_len) { assert(0); //track too long } WriteBlock(pos, 0x4e, Track().data_len - pos - 1); //gap3 } } return true; }
bool eZ80AccessorSZX::SetState(xIo::eStreamMemory& is) { ZXSTHEADER header; if(is.Read(&header, sizeof(header)) != sizeof(header)) return false; if(header.dwMagic != FOURCC('Z', 'X', 'S', 'T')) return false; bool model48k = false; switch(header.chMachineId) { case ZXSTMID_16K: case ZXSTMID_48K: case ZXSTMID_NTSC48K: model48k = true; break; case ZXSTMID_128K: case ZXSTMID_PENTAGON128: break; default: return false; } SetupDevices(model48k); ZXSTBLOCK block; while(is.Read(&block, sizeof(block)) == sizeof(block)) { switch(block.dwId) { case FOURCC('Z', '8', '0', 'R'): { ZXSTZ80REGS regs; if(!ReadBlock(is, ®s, block)) return false; af = SwapWord(regs.AF); bc = SwapWord(regs.BC); de = SwapWord(regs.DE); hl = SwapWord(regs.HL); alt.af = SwapWord(regs.AF1); alt.bc = SwapWord(regs.BC1); alt.de = SwapWord(regs.DE1); alt.hl = SwapWord(regs.HL1); ix = SwapWord(regs.IX); iy = SwapWord(regs.IY); sp = SwapWord(regs.SP); pc = SwapWord(regs.PC); i = regs.I; r_low = regs.R; r_hi = regs.R & 0x80; im = regs.IM; iff1 = regs.IFF1; iff2 = regs.IFF2; t = Dword((const byte*)®s.dwCyclesStart) % frame_tacts; if(regs.wMemPtr) memptr = SwapWord(regs.wMemPtr); } break; case FOURCC('S', 'P', 'C', 'R'): { ZXSTSPECREGS regs; if(!ReadBlock(is, ®s, block)) return false; devices->IoWrite(0xfe, (regs.chFe&0x18) | regs.chBorder, t); devices->IoWrite(0x7ffd, model48k ? 0x30 : regs.ch7ffd, t); if(model48k) devices->Get<eMemory>()->SetRomPage(eMemory::P_ROM_48); else devices->Get<eMemory>()->SetRomPage((regs.ch7ffd & 0x10) ? eMemory::P_ROM_128_0 : eMemory::P_ROM_128_1); } break; case FOURCC('R', 'A', 'M', 'P'): { ZXSTRAMPAGE ram_page; if(!ReadBlock(is, &ram_page, block, sizeof(ZXSTRAMPAGE) - sizeof(ZXSTBLOCK) - 1)) return false; byte* buf = new byte[eMemory::PAGE_SIZE]; bool ok = false; if(SwapWord(ram_page.wFlags)&ZXSTRF_COMPRESSED) { #ifdef USE_ZIP size_t size = ram_page.blk.dwSize - (sizeof(ZXSTRAMPAGE) - sizeof(ZXSTBLOCK) - 1); byte* buf_compr = new byte[size]; ok = is.Read(buf_compr, size) == size; if(ok) { z_stream zs; memset(&zs, 0, sizeof(zs)); zs.next_in = buf_compr; zs.avail_in = size; zs.next_out = buf; zs.avail_out = eMemory::PAGE_SIZE; ok = inflateInit2(&zs, 15) == Z_OK; if(ok) ok = inflate(&zs, Z_NO_FLUSH) == Z_STREAM_END; inflateEnd(&zs); } SAFE_DELETE_ARRAY(buf_compr); #endif//USE_ZIP } else { size_t size = ram_page.blk.dwSize - (sizeof(ZXSTRAMPAGE) - sizeof(ZXSTBLOCK) - 1); ok = size == eMemory::PAGE_SIZE; if(ok) { ok = is.Read(buf, size) == size; } } if(ok && ram_page.chPageNo <= 7) { memcpy(memory->Get(eMemory::P_RAM0 + ram_page.chPageNo), buf, eMemory::PAGE_SIZE); } SAFE_DELETE(buf); if(!ok) return false; } break; case FOURCC('A', 'Y', '\0', '\0'): { ZXSTAYBLOCK ay_state; if(!ReadBlock(is, &ay_state, block)) return false; devices->Get<eAY>()->SetRegs(ay_state.chAyRegs); devices->Get<eAY>()->Select(ay_state.chCurrentRegister); } break; default: if(is.Seek(block.dwSize, xIo::eStreamMemory::S_CUR) != 0) return false; } if(is.Pos() == is.Size()) return true; } return false; }
//============================================================================= // eTape::ParseTZX //----------------------------------------------------------------------------- bool eTape::ParseTZX(const void* data, size_t data_size) { byte* ptr = (byte*)data; CloseTape(); dword size, pause, i, j, n, t, t0; byte pl, last, *end; byte* p; dword loop_n = 0, loop_p = 0; char nm[512]; while(ptr < (const byte*)data + data_size) { switch(*ptr++) { case 0x10: // normal block AllocInfocell(); size = Word(ptr + 2); pause = Word(ptr); ptr += 4; Desc(ptr, size, tapeinfo[tape_infosize].desc); tape_infosize++; MakeBlock(ptr, size, 2168, 667, 735, 855, 1710, (*ptr < 4) ? 8064 : 3220, pause); ptr += size; break; case 0x11: // turbo block AllocInfocell(); size = 0xFFFFFF & Dword(ptr + 0x0F); Desc(ptr + 0x12, size, tapeinfo[tape_infosize].desc); tape_infosize++; MakeBlock(ptr + 0x12, size, Word(ptr), Word(ptr + 2), Word(ptr + 4), Word(ptr + 6), Word(ptr + 8), Word(ptr + 10), Word(ptr + 13), ptr[12]); // todo: test used bits - ptr+12 ptr += size + 0x12; break; case 0x12: // pure tone CreateAppendableBlock(); pl = FindPulse(Word(ptr)); n = Word(ptr + 2); Reserve(n); for(i = 0; i < n; i++) tape_image[tape_imagesize++] = pl; ptr += 4; break; case 0x13: // sequence of pulses of different lengths CreateAppendableBlock(); n = *ptr++; Reserve(n); for(i = 0; i < n; i++, ptr += 2) tape_image[tape_imagesize++] = FindPulse(Word(ptr)); break; case 0x14: // pure data block CreateAppendableBlock(); size = 0xFFFFFF & Dword(ptr + 7); MakeBlock(ptr + 0x0A, size, 0, 0, 0, Word(ptr), Word(ptr + 2), -1, Word(ptr + 5), ptr[4]); ptr += size + 0x0A; break; case 0x15: // direct recording size = 0xFFFFFF & Dword(ptr + 5); t0 = Word(ptr); pause = Word(ptr + 2); last = ptr[4]; NamedCell("direct recording"); ptr += 8; pl = 0; n = 0; for(i = 0; i < size; i++) // count number of pulses for(j = 0x80; j; j >>= 1) if((ptr[i] ^ pl) & j) n++, pl ^= -1; t = 0; pl = 0; Reserve(n + 2); for(i = 1; i < size; i++, ptr++) // find pulses for(j = 0x80; j; j >>= 1) { t += t0; if((*ptr ^ pl) & j) { tape_image[tape_imagesize++] = FindPulse(t); pl ^= -1; t = 0; } } // find pulses - last byte for(j = 0x80; j != (byte)(0x80 >> last); j >>= 1) { t += t0; if((*ptr ^ pl) & j) { tape_image[tape_imagesize++] = FindPulse(t); pl ^= -1; t = 0; } } ptr++; tape_image[tape_imagesize++] = FindPulse(t); // last pulse ??? if(pause) tape_image[tape_imagesize++] = FindPulse(pause * 3500); break; case 0x20: // pause (silence) or 'stop the tape' command pause = Word(ptr); sprintf(nm, pause ? "pause %d ms" : "stop the tape", pause); NamedCell(nm); Reserve(2); ptr += 2; if(!pause) { // at least 1ms pulse as specified in TZX 1.13 tape_image[tape_imagesize++] = FindPulse(3500); pause = -1; } else pause *= 3500; tape_image[tape_imagesize++] = FindPulse(pause); break; case 0x21: // group start n = *ptr++; NamedCell(ptr, n); ptr += n; appendable = 1; break; case 0x22: // group end break; case 0x23: // jump to block NamedCell("* jump"); ptr += 2; break; case 0x24: // loop start loop_n = Word(ptr); loop_p = tape_imagesize; ptr += 2; break; case 0x25: // loop end if(!loop_n) break; size = tape_imagesize - loop_p; Reserve((loop_n - 1) * size); for(i = 1; i < loop_n; i++) memcpy(tape_image + loop_p + i * size, tape_image + loop_p, size); tape_imagesize += (loop_n - 1) * size; loop_n = 0; break; case 0x26: // call NamedCell("* call"); ptr += 2 + 2 * Word(ptr); break; case 0x27: // ret NamedCell("* return"); break; case 0x28: // select block sprintf(nm, "* choice: "); n = ptr[2]; p = ptr + 3; for(i = 0; i < n; i++) { if(i) strcat(nm, " / "); char *q = nm + strlen(nm); size = *(p + 2); memcpy(q, p + 3, size); q[size] = 0; p += size + 3; } NamedCell(nm); ptr += 2 + Word(ptr); break; case 0x2A: // stop if 48k NamedCell("* stop if 48K"); ptr += 4 + Dword(ptr); break; case 0x30: // text description n = *ptr++; NamedCell(ptr, n); ptr += n; appendable = 1; break; case 0x31: // message block NamedCell("- MESSAGE BLOCK "); end = ptr + 2 + ptr[1]; pl = *end; *end = 0; for(p = ptr + 2; p < end; p++) if(*p == 0x0D) *p = 0; for(p = ptr + 2; p < end; p += strlen((char*)p) + 1) NamedCell(p); *end = pl; ptr = end; NamedCell("-"); break; case 0x32: // archive info NamedCell("- ARCHIVE INFO "); p = ptr + 3; for(i = 0; i < ptr[2]; i++) { const char *info; switch(*p++) { case 0: info = "Title"; break; case 1: info = "Publisher"; break; case 2: info = "Author"; break; case 3: info = "Year"; break; case 4: info = "Language"; break; case 5: info = "Type"; break; case 6: info = "Price"; break; case 7: info = "Protection"; break; case 8: info = "Origin"; break; case 0xFF: info = "Comment"; break; default: info = "info"; break; } dword size = *p + 1; char tmp = p[size]; p[size] = 0; sprintf(nm, "%s: %s", info, p + 1); p[size] = tmp; p += size; NamedCell(nm); } NamedCell("-"); ptr += 2 + Word(ptr); break; case 0x33: // hardware type ParseHardware(ptr); ptr += 1 + 3 * *ptr; break; case 0x34: // emulation info NamedCell("* emulation info"); ptr += 8; break; case 0x35: // custom info if(!memcmp(ptr, "POKEs ", 16)) { NamedCell("- POKEs block "); NamedCell(ptr + 0x15, ptr[0x14]); p = ptr + 0x15 + ptr[0x14]; n = *p++; for(i = 0; i < n; i++) { NamedCell(p + 1, *p); p += *p + 1; t = *p++; strcpy(nm, "POKE "); for(j = 0; j < t; j++) { sprintf(nm + strlen(nm), "%d,", Word(p + 1)); sprintf(nm + strlen(nm), *p & 0x10 ? "nn" : "%d", *(byte*)(p + 3)); if(!(*p & 0x08)) sprintf(nm + strlen(nm), "(page %d)", *p & 7); strcat(nm, "; "); p += 5; } NamedCell(nm); } nm[0] = '-'; nm[1] = 0; nm[2] = 0; nm[3] = 0; } else sprintf(nm, "* custom info: %s", ptr), nm[15 + 16] = 0; NamedCell(nm); ptr += 0x14 + Dword(ptr + 0x10); break; case 0x40: // snapshot NamedCell("* snapshot"); ptr += 4 + (0xFFFFFF & Dword(ptr + 1)); break; case 0x5A: // 'Z' ptr += 9; break; default: ptr += data_size; } } for(i = 0; i < tape_infosize; i++) { if(tapeinfo[i].desc[0] == '*' && tapeinfo[i].desc[1] == ' ') strcat(tapeinfo[i].desc, " [UNSUPPORTED]"); if(*tapeinfo[i].desc == '-') while(strlen(tapeinfo[i].desc) < sizeof(tapeinfo[i].desc) - 1) strcat(tapeinfo[i].desc, "-"); } if(tape_imagesize && tape_pulse[tape_image[tape_imagesize - 1]] < 350000) Reserve(1), tape_image[tape_imagesize++] = FindPulse(350000); // small pause [rqd for 3ddeathchase] FindTapeSizes(); return (ptr == (const byte*)data + data_size); }