diff options
author | 2021-05-26 15:19:45 +0200 | |
---|---|---|
committer | 2021-05-26 19:15:31 +0200 | |
commit | 9add8034d2b92fe8cd876ab16c63831ce460e7e2 (patch) | |
tree | 5012a1ec8f5df8389a99805d9443351cb9653141 | |
parent | ec2bec33c2e53dada0970411f3b897930516d284 (diff) |
vtech: Add floppy formats and fs
-rw-r--r-- | scripts/src/formats.lua | 24 | ||||
-rw-r--r-- | scripts/target/mame/mess.lua | 2 | ||||
-rw-r--r-- | src/devices/bus/vtech/memexp/floppy.cpp | 13 | ||||
-rw-r--r-- | src/devices/bus/vtech/memexp/floppy.h | 2 | ||||
-rw-r--r-- | src/devices/imagedev/floppy.cpp | 2 | ||||
-rw-r--r-- | src/lib/formats/all.cpp | 15 | ||||
-rw-r--r-- | src/lib/formats/fs_vtech.cpp | 366 | ||||
-rw-r--r-- | src/lib/formats/fs_vtech.h | 96 | ||||
-rw-r--r-- | src/lib/formats/fsmgr.cpp | 9 | ||||
-rw-r--r-- | src/lib/formats/fsmgr.h | 3 | ||||
-rw-r--r-- | src/lib/formats/mfi_dsk.cpp | 9 | ||||
-rw-r--r-- | src/lib/formats/vt_dsk.cpp | 396 | ||||
-rw-r--r-- | src/lib/formats/vt_dsk.h | 58 |
13 files changed, 990 insertions, 5 deletions
diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index 3448962fe70..5afef69d522 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -1991,6 +1991,30 @@ end -------------------------------------------------- -- +--@src/lib/formats/vt_dsk.h,FORMATS["VT_DSK"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "VT_DSK") then + files { + MAME_DIR.. "src/lib/formats/vt_dsk.cpp", + MAME_DIR.. "src/lib/formats/vt_dsk.h", + } +end + +-------------------------------------------------- +-- +--@src/lib/formats/fs_vtech.h,FORMATS["FS_VTECH"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "FS_VTECH") then + files { + MAME_DIR.. "src/lib/formats/fs_vtech.cpp", + MAME_DIR.. "src/lib/formats/fs_vtech.h", + } +end + +-------------------------------------------------- +-- --@src/lib/formats/wd177x_dsk.h,FORMATS["WD177X_DSK"] = true -------------------------------------------------- diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 312fac4b71e..52dc912def7 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -1154,6 +1154,8 @@ FORMATS["VECTOR06_DSK"] = true FORMATS["VG5K_CAS"] = true FORMATS["VICTOR9K_DSK"] = true FORMATS["VT_CAS"] = true +FORMATS["VT_DSK"] = true +FORMATS["FS_VTECH"] = true FORMATS["WD177X_DSK"] = true FORMATS["X07_CAS"] = true FORMATS["X1_TAP"] = true diff --git a/src/devices/bus/vtech/memexp/floppy.cpp b/src/devices/bus/vtech/memexp/floppy.cpp index e18cf7fd186..60e6a5166fc 100644 --- a/src/devices/bus/vtech/memexp/floppy.cpp +++ b/src/devices/bus/vtech/memexp/floppy.cpp @@ -11,6 +11,8 @@ #include "emu.h" #include "floppy.h" +#include "formats/vt_dsk.h" +#include "formats/fs_vtech.h" //************************************************************************** @@ -50,11 +52,18 @@ static void laser_floppies(device_slot_interface &device) device.option_add("525", FLOPPY_525_VTECH); } +void vtech_floppy_controller_device::floppy_formats(format_registration &fr) +{ + fr.add(FLOPPY_VTECH_BIN_FORMAT); + fr.add(FLOPPY_VTECH_DSK_FORMAT); + fr.add(FS_VTECH); +} + void vtech_floppy_controller_device::device_add_mconfig(machine_config &config) { VTECH_MEMEXP_SLOT(config, m_memexp); - FLOPPY_CONNECTOR(config, m_floppy0, laser_floppies, "525", floppy_image_device::default_mfm_floppy_formats); - FLOPPY_CONNECTOR(config, m_floppy1, laser_floppies, "525", floppy_image_device::default_mfm_floppy_formats); + FLOPPY_CONNECTOR(config, m_floppy0, laser_floppies, "525", floppy_formats); + FLOPPY_CONNECTOR(config, m_floppy1, laser_floppies, "525", floppy_formats); } diff --git a/src/devices/bus/vtech/memexp/floppy.h b/src/devices/bus/vtech/memexp/floppy.h index 56a926e17b1..78079cea461 100644 --- a/src/devices/bus/vtech/memexp/floppy.h +++ b/src/devices/bus/vtech/memexp/floppy.h @@ -48,6 +48,8 @@ private: void update_latching_inverter(); void flush_writes(bool keep_margin = false); + static void floppy_formats(format_registration &fr); + required_device<vtech_memexp_slot_device> m_memexp; required_device<floppy_connector> m_floppy0, m_floppy1; floppy_image_device *m_floppy; diff --git a/src/devices/imagedev/floppy.cpp b/src/devices/imagedev/floppy.cpp index 09f61ea17c9..faa6b5d30d6 100644 --- a/src/devices/imagedev/floppy.cpp +++ b/src/devices/imagedev/floppy.cpp @@ -39,7 +39,7 @@ #define PITCH_SEEK_SAMPLES 1 -#define FLUX_SCREEN 0 +#define FLUX_SCREEN 1 #define FLOPSND_TAG "floppysound" diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp index 0b50ddc9d69..7eaf27d4d91 100644 --- a/src/lib/formats/all.cpp +++ b/src/lib/formats/all.cpp @@ -653,6 +653,14 @@ #include "vt_cas.h" #endif +#ifdef HAS_FORMATS_VT_DSK +#include "vt_dsk.h" +#endif + +#ifdef HAS_FORMATS_FS_VTECH +#include "fs_vtech.h" +#endif + #ifdef HAS_FORMATS_WD177X_DSK #include "wd177x_dsk.h" #endif @@ -1379,6 +1387,13 @@ void mame_formats_full_list(mame_formats_enumerator &en) en.add(vtech1_cassette_formats); // vt_cas.h en.add(vtech2_cassette_formats); // vt_cas.h #endif +#ifdef HAS_FORMATS_VT_CAS + en.add(FLOPPY_VTECH_BIN_FORMAT); // vt_dsk.h + en.add(FLOPPY_VTECH_DSK_FORMAT); // vt_dsk.h +#endif +#ifdef HAS_FORMATS_FS_VTECH + en.add(FS_VTECH); // fs_vtech.h +#endif en.category("Canon"); #ifdef HAS_FORMATS_X07_CAS diff --git a/src/lib/formats/fs_vtech.cpp b/src/lib/formats/fs_vtech.cpp new file mode 100644 index 00000000000..cf432baa218 --- /dev/null +++ b/src/lib/formats/fs_vtech.cpp @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Management of VTech images + +#include "emu.h" +#include "fs_vtech.h" +#include "vt_dsk.h" + +const fs_vtech FS_VTECH; + +// Floppy only, format is 40 tracks, 1 head, 16 sectors numbered 0-15, 256 bytes/sector. +// Filesystem has no subdirectories. +// +// Track 0 sectors 0-14 have the file names. 16 bytes/entry +// offset 0 : File type 'T' (basic) or 'B' (binary) +// offset 1 : 0x3a +// offset 2-9: File name +// offset a : Track number of first file sector +// offset b : Sector number of first file sector +// offset c-d: Start address (little-endian) +// offset e-f: End address (little-endian) +// +// Files are stored with 126 bytes/sector, and bytes 126 and 127 are +// track/sector of the next file data sector. + +const char *fs_vtech::name() const +{ + return "vtech"; +} + +const char *fs_vtech::description() const +{ + return "VTech (Laser 200/300)"; +} + +void fs_vtech::enumerate_f(floppy_enumerator &fe, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + if(has(form_factor, variants, floppy_image::FF_525, floppy_image::SSSD)) + fe.add(FLOPPY_VTECH_BIN_FORMAT, 163840, "vtech", "VTech"); +} + +std::unique_ptr<filesystem_t> fs_vtech::mount(fsblk_t &blockdev) const +{ + return std::make_unique<impl>(blockdev); +} + +bool fs_vtech::can_format() const +{ + return true; +} + +bool fs_vtech::can_read() const +{ + return true; +} + +bool fs_vtech::can_write() const +{ + return true; +} + +bool fs_vtech::has_rsrc() const +{ + return false; +} + +std::vector<fs_meta_description> fs_vtech::volume_meta_description() const +{ + std::vector<fs_meta_description> res; + return res; +} + +fs_meta_data fs_vtech::impl::metadata() +{ + fs_meta_data res; + return res; +} + +std::vector<fs_meta_description> fs_vtech::file_meta_description() const +{ + std::vector<fs_meta_description> res; + res.emplace_back(fs_meta_description(fs_meta_name::name, fs_meta_type::string, "", false, [](const fs_meta &m) { return m.as_string().size() <= 8; }, "File name, 8 chars")); + res.emplace_back(fs_meta_description(fs_meta_name::loading_address, fs_meta_type::number, 0x7ae9, false, [](const fs_meta &m) { return m.as_number() < 0x10000; }, "Loading address of the file")); + res.emplace_back(fs_meta_description(fs_meta_name::length, fs_meta_type::number, 0, true, nullptr, "Size of the file in bytes")); + res.emplace_back(fs_meta_description(fs_meta_name::basic, fs_meta_type::flag, true, true, nullptr, "Basic file")); + return res; +} + + +void fs_vtech::impl::format(const fs_meta_data &meta) +{ + m_blockdev.fill(0); +} + +fs_vtech::impl::impl(fsblk_t &blockdev) : filesystem_t(blockdev, 128), m_root(true) +{ +} + +filesystem_t::dir_t fs_vtech::impl::root() +{ + if(!m_root) + m_root = new root_dir(*this); + return m_root.strong(); +} + +void fs_vtech::impl::drop_root_ref() +{ + m_root = nullptr; +} + +void fs_vtech::impl::root_dir::drop_weak_references() +{ + m_fs.drop_root_ref(); +} + +fs_meta_data fs_vtech::impl::root_dir::metadata() +{ + return fs_meta_data(); +} + +std::vector<fs_dir_entry> fs_vtech::impl::root_dir::contents() +{ + std::vector<fs_dir_entry> res; + + uint64_t id = 0; + for(int sect = 0; sect != 14; sect++) { + auto bdir = m_fs.m_blockdev.get(sect); + for(u32 i = 0; i != 8; i ++) { + u32 off = i*16; + u8 type = bdir.r8(off); + if(type != 'T' && type != 'B') + continue; + if(bdir.r8(off+1) != ':') + continue; + std::string fname = trim_end_spaces(bdir.rstr(off+2, 8)); + res.emplace_back(fs_dir_entry(fname, fs_dir_entry_type::file, id)); + id++; + } + } + return res; +} + +filesystem_t::file_t fs_vtech::impl::root_dir::file_get(uint64_t key) +{ + if(key >= 15*8) + fatalerror("Key out of range\n"); + + auto bdir = m_fs.m_blockdev.get(key >> 3); + int off = (key & 7) << 4; + return file_t(new file(m_fs, this, bdir.rodata() + off, key)); +} + +void fs_vtech::impl::root_dir::update_file(u16 key, const u8 *entry) +{ + auto bdir = m_fs.m_blockdev.get(key >> 3); + int off = (key & 7) << 4; + bdir.copy(off, entry, 16); +} + +filesystem_t::dir_t fs_vtech::impl::root_dir::dir_get(uint64_t key) +{ + fatalerror("Directories not supported\n"); +} + +fs_vtech::impl::file::file(impl &fs, root_dir *dir, const u8 *entry, u16 key) : m_fs(fs), m_dir(dir), m_key(key) +{ + memcpy(m_entry, entry, 16); +} + +void fs_vtech::impl::file::drop_weak_references() +{ +} + +fs_meta_data fs_vtech::impl::file::metadata() +{ + fs_meta_data res; + + res.set(fs_meta_name::name, trim_end_spaces(rstr(m_entry+2, 8))); + res.set(fs_meta_name::basic, m_entry[0] == 'T'); + res.set(fs_meta_name::loading_address, r16l(m_entry + 0xc)); + res.set(fs_meta_name::length, ((r16l(m_entry + 0xe) - r16l(m_entry + 0xc) + 1) & 0xffff)); + + return res; +} + +std::vector<u8> fs_vtech::impl::file::read_all() +{ + u8 track = m_entry[0xa]; + u8 sector = m_entry[0xb]; + int len = ((r16l(m_entry + 0xe) - r16l(m_entry + 0xc)) & 0xffff) + 1; + + std::vector<u8> data(len, 0); + int pos = 0; + while(pos < len) { + if(track >= 40 || sector >= 16) + break; + auto dblk = m_fs.m_blockdev.get(track*16 + sector); + int size = len - pos; + if(size > 126) + size = 126; + memcpy(data.data() + pos, dblk.data(), size); + pos += size; + track = dblk.r8(126); + sector = dblk.r8(127); + } + return data; +} + +fs_vtech::impl::file_t fs_vtech::impl::root_dir::file_create(const fs_meta_data &info) +{ + // Find the key for the next unused entry + for(int sect = 0; sect != 14; sect++) { + auto bdir = m_fs.m_blockdev.get(sect); + uint64_t id = 0; + for(u32 i = 0; i != 16; i ++) { + u32 off = i*16; + u8 type = bdir.r8(off); + if(type != 'T' && type != 'B') { + std::string fname = info.get_string(fs_meta_name::name, ""); + fname.resize(8, ' '); + + bdir.w8 (off+0x0, info.get_flag(fs_meta_name::basic, true) ? 'T' : 'B'); + bdir.w8 (off+0x1, ':'); + bdir.wstr(off+0x2, fname); + bdir.w8 (off+0xa, 0x00); + bdir.w8 (off+0xb, 0x00); + bdir.w16l(off+0xc, info.get_number(fs_meta_name::loading_address, 0x7ae9)); + bdir.w16l(off+0xe, bdir.r16l(off+0xc) - 1); // Size 0 initially + return file_t(new file(m_fs, this, bdir.rodata() + off, id)); + } + id++; + } + } + return nullptr; +} + +void fs_vtech::impl::root_dir::file_delete(uint64_t key) +{ +} + +void fs_vtech::impl::file::replace(const std::vector<u8> &data) +{ + u32 cur_len = ((r16l(m_entry + 0xe) - r16l(m_entry + 0xc) + 1) & 0xffff); + u32 new_len = data.size(); + if(new_len > 65535) + new_len = 65535; + u32 cur_ns = (cur_len + 125)/126; + u32 need_ns = (new_len + 125) / 126; + + // Enough space? + if(cur_ns < need_ns && m_fs.free_block_count() < need_ns - cur_ns) + return; + + u8 track = m_entry[0xa]; + u8 sector = m_entry[0xb]; + std::vector<std::pair<u8, u8>> tofree; + for(u32 i = 0; i != cur_ns; i++) { + tofree.emplace_back(std::make_pair(track, sector)); + auto dblk = m_fs.m_blockdev.get(track*16 + sector); + track = dblk.r8(126); + sector = dblk.r8(127); + } + + m_fs.free_blocks(tofree); + + std::vector<std::pair<u8, u8>> blocks = m_fs.allocate_blocks(need_ns); + for(u32 i=0; i != need_ns; i ++) { + auto dblk = m_fs.m_blockdev.get(blocks[i].first * 16 + blocks[i].second); + u32 len = new_len - i*126; + if(len > 126) + len = 126; + else if(len < 126) + dblk.fill(0x00); + memcpy(dblk.data(), data.data() + 126*i, len); + if(i < need_ns) { + dblk.w8(126, blocks[i+1].first); + dblk.w8(127, blocks[i+1].second); + } else + dblk.w16l(126, 0); + } + + u16 end_address = (r16l(m_entry + 0xc) + data.size() - 1) & 0xffff; + w16l(m_entry + 0xe, end_address); + if(need_ns) { + w8(m_entry + 0xa, blocks[0].first); + w8(m_entry + 0xb, blocks[0].second); + } else + w16l(m_entry + 0xa, 0); + + m_dir->update_file(m_key, m_entry); +} + +void fs_vtech::impl::root_dir::metadata_change(const fs_meta_data &info) +{ +} + +void fs_vtech::impl::metadata_change(const fs_meta_data &info) +{ +} + +void fs_vtech::impl::file::metadata_change(const fs_meta_data &info) +{ + if(info.has(fs_meta_name::basic)) + w8 (m_entry+0x0, info.get_flag(fs_meta_name::basic) ? 'T' : 'B'); + if(info.has(fs_meta_name::name)) { + std::string name = info.get_string(fs_meta_name::name); + name.resize(8, ' '); + wstr(m_entry+0x2, name); + } + if(info.has(fs_meta_name::loading_address)) { + u16 new_loading = info.get_number(fs_meta_name::loading_address); + u16 new_end = r16l(m_entry + 0xe) - r16l(m_entry + 0xc) + new_loading; + w16l(m_entry + 0xc, new_loading); + w16l(m_entry + 0xe, new_end); + } + m_dir->update_file(m_key, m_entry); +} + +std::vector<std::pair<u8, u8>> fs_vtech::impl::allocate_blocks(u32 count) +{ + std::vector<std::pair<u8, u8>> blocks; + if(free_block_count() < count) + return blocks; + + auto fmap = m_blockdev.get(15); + for(u8 track = 1; track != 40; track++) + for(u8 sector = 0; sector != 16; sector++) { + u32 off = (track-1)*2 + (sector / 8); + u32 bit = 1 << (sector & 7); + if(!(fmap.r8(off) & bit)) { + fmap.w8(off, fmap.r8(off) | bit); + blocks.emplace_back(std::make_pair(track, sector)); + if(blocks.size() == count) + return blocks; + } + } + abort(); +} + +void fs_vtech::impl::free_blocks(const std::vector<std::pair<u8, u8>> &blocks) +{ + auto fmap = m_blockdev.get(15); + for(auto ref : blocks) { + u8 track = ref.first; + u8 sector = ref.second; + u32 off = (track-1)*2 + (sector / 8); + u32 bit = 1 << (sector & 7); + fmap.w8(off, fmap.r8(off) & ~bit); + } +} + +u32 fs_vtech::impl::free_block_count() +{ + auto fmap = m_blockdev.get(15); + u32 nf = 0; + for(u32 off = 0; off != (40-1)*2; off++) { + u8 m = fmap.r8(off); + // Count 1 bits; + m = ((m & 0xaa) >> 1) | (m & 0x55); + m = ((m & 0xcc) >> 2) | (m & 0x33); + m = ((m & 0xf0) >> 4) | (m & 0x0f); + nf += 7-m; + } + return nf; +} diff --git a/src/lib/formats/fs_vtech.h b/src/lib/formats/fs_vtech.h new file mode 100644 index 00000000000..0a73c15778d --- /dev/null +++ b/src/lib/formats/fs_vtech.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// Management of VTech images + +#ifndef MAME_FORMATS_FS_VTECH_H +#define MAME_FORMATS_FS_VTECH_H + +#pragma once + +#include "fsmgr.h" + +class fs_vtech : public filesystem_manager_t { +public: + class impl : public filesystem_t { + public: + class root_dir : public idir_t { + public: + root_dir(impl &i) : m_fs(i) {} + virtual ~root_dir() = default; + + virtual void drop_weak_references() override; + + virtual fs_meta_data metadata() override; + virtual void metadata_change(const fs_meta_data &info) override; + virtual std::vector<fs_dir_entry> contents() override; + virtual file_t file_get(uint64_t key) override; + virtual dir_t dir_get(uint64_t key) override; + virtual file_t file_create(const fs_meta_data &info) override; + virtual void file_delete(uint64_t key) override; + + void update_file(u16 key, const u8 *entry); + + private: + impl &m_fs; + + std::pair<fsblk_t::block_t, u32> get_dir_block(uint64_t key); + }; + + class file : public ifile_t { + public: + file(impl &fs, root_dir *dir, const u8 *entry, u16 key); + virtual ~file() = default; + + virtual void drop_weak_references() override; + + virtual fs_meta_data metadata() override; + virtual void metadata_change(const fs_meta_data &info) override; + virtual std::vector<u8> read_all() override; + virtual void replace(const std::vector<u8> &data) override; + + private: + impl &m_fs; + root_dir *m_dir; + u16 m_key; + u8 m_entry[18]; + }; + + impl(fsblk_t &blockdev); + virtual ~impl() = default; + + virtual void format(const fs_meta_data &meta) override; + virtual fs_meta_data metadata() override; + virtual void metadata_change(const fs_meta_data &info) override; + virtual dir_t root() override; + + void drop_root_ref(); + + std::vector<std::pair<u8, u8>> allocate_blocks(u32 count); + void free_blocks(const std::vector<std::pair<u8, u8>> &blocks); + u32 free_block_count(); + + private: + dir_t m_root; + }; + + fs_vtech() : filesystem_manager_t() {} + + virtual const char *name() const override; + virtual const char *description() const override; + + virtual void enumerate_f(floppy_enumerator &fe, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + virtual std::unique_ptr<filesystem_t> mount(fsblk_t &blockdev) const override; + + virtual bool can_format() const override; + virtual bool can_read() const override; + virtual bool can_write() const override; + virtual bool has_rsrc() const override; + + virtual std::vector<fs_meta_description> volume_meta_description() const override; + virtual std::vector<fs_meta_description> file_meta_description() const override; +}; + +extern const fs_vtech FS_VTECH; + +#endif diff --git a/src/lib/formats/fsmgr.cpp b/src/lib/formats/fsmgr.cpp index 09234ebcaf4..cc18a942ed5 100644 --- a/src/lib/formats/fsmgr.cpp +++ b/src/lib/formats/fsmgr.cpp @@ -369,6 +369,14 @@ uint32_t filesystem_t::r32l(const uint8_t *p) return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); } +std::string filesystem_t::trim_end_spaces(const std::string &str) +{ + auto i = str.end(); + while(i != str.begin() && i[-1] == ' ') + i--; + return std::string(str.begin(), i); +} + filesystem_t::file_t filesystem_t::idir_t::file_create(const fs_meta_data &info) { fatalerror("file_create called on a filesystem not supporting write\n"); @@ -413,6 +421,7 @@ std::vector<u8> filesystem_t::ifile_t::rsrc_read_all() const char *fs_meta_data::entry_name(fs_meta_name name) { switch(name) { + case fs_meta_name::basic: return "basic"; case fs_meta_name::creation_date: return "creation_date"; case fs_meta_name::length: return "length"; case fs_meta_name::loading_address: return "loading_address"; diff --git a/src/lib/formats/fsmgr.h b/src/lib/formats/fsmgr.h index 8ae9ddeb452..d407a597c6e 100644 --- a/src/lib/formats/fsmgr.h +++ b/src/lib/formats/fsmgr.h @@ -16,6 +16,7 @@ #include <functional> enum class fs_meta_name { + basic, creation_date, length, loading_address, @@ -380,6 +381,8 @@ public: static uint32_t r24l(const uint8_t *p); static uint32_t r32l(const uint8_t *p); + static std::string trim_end_spaces(const std::string &str); + protected: fsblk_t &m_blockdev; }; diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp index 049660272a3..7670bf6bfb9 100644 --- a/src/lib/formats/mfi_dsk.cpp +++ b/src/lib/formats/mfi_dsk.cpp @@ -146,8 +146,10 @@ bool mfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui trackbuf.resize(cell_count); uLongf size = ent->uncompressed_size; - if(uncompress((Bytef *)&trackbuf[0], &size, &compressed[0], ent->compressed_size) != Z_OK) + if(uncompress((Bytef *)&trackbuf[0], &size, &compressed[0], ent->compressed_size) != Z_OK) { + fprintf(stderr, "fail1\n"); return false; + } uint32_t cur_time = 0; for(unsigned int i=0; i != cell_count; i++) { @@ -155,12 +157,15 @@ bool mfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui trackbuf[i] = (trackbuf[i] & MG_MASK) | cur_time; cur_time = next_cur_time; } - if(cur_time != 200000000) + if(cur_time != 200000000) { + fprintf(stderr, "fail2 %d\n", cur_time); return false; + } ent++; } + fprintf(stderr, "tick\n"); return true; } diff --git a/src/lib/formats/vt_dsk.cpp b/src/lib/formats/vt_dsk.cpp new file mode 100644 index 00000000000..5d42ee9a1e0 --- /dev/null +++ b/src/lib/formats/vt_dsk.cpp @@ -0,0 +1,396 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/********************************************************************* + + formats/vt_dsk.cpp + + VTech disk image formats + +*********************************************************************/ + +#include "formats/vt_dsk.h" + +// Zero = | 9187 | +// One = | 2237 | 6950 | +// 0.5us ~= 143 + +void vtech_common_format::wbit(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, bool bit) +{ + buffer.push_back(pos | mg); + mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; + if(bit) { + pos += 2237; + buffer.push_back(pos | mg); + mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; + pos += 6950; + } else + pos += 9187; +} + +void vtech_common_format::wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, uint8_t byte) +{ + for(int i = 7; i >= 0; i--) + wbit(buffer, pos, mg, (byte >> i) & 1); +} + +void vtech_common_format::image_to_flux(const std::vector<uint8_t> &bdata, floppy_image *image) +{ + static const uint8_t sector_map[16] = { + 0x0, 0xb, 0x6, 0x1, 0xc, 0x7, 0x2, 0xd, 0x8, 0x3, 0xe, 0x9, 0x4, 0xf, 0xa, 0x5 + }; + + for(int track = 0; track != 40; track ++) { + uint32_t pos = 0; + uint32_t mg = floppy_image::MG_A; + std::vector<uint32_t> &buffer = image->get_buffer(track, 0); + buffer.clear(); + image->set_write_splice_position(track, 0, 0); + // One window of pad at the start to avoid problems with the write splice + wbit(buffer, pos, mg, 0); + + for(int sector = 0; sector != 16; sector ++) { + uint8_t sid = sector_map[sector]; + for(int i=0; i != 7; i++) + wbyte(buffer, pos, mg, 0x80); + wbyte(buffer, pos, mg, 0x00); + wbyte(buffer, pos, mg, 0xfe); + wbyte(buffer, pos, mg, 0xe7); + wbyte(buffer, pos, mg, 0x18); + wbyte(buffer, pos, mg, 0xc3); + wbyte(buffer, pos, mg, track); + wbyte(buffer, pos, mg, sid); + wbyte(buffer, pos, mg, track+sid); + for(int i=0; i != 5; i++) + wbyte(buffer, pos, mg, 0x80); + wbyte(buffer, pos, mg, 0x00); + wbyte(buffer, pos, mg, 0xc3); + wbyte(buffer, pos, mg, 0x18); + wbyte(buffer, pos, mg, 0xe7); + wbyte(buffer, pos, mg, 0xfe); + uint16_t chk = 0; + const uint8_t *src = bdata.data() + 16*128*track + 128*sid; + for(int i=0; i != 128; i++) { + chk += src[i]; + wbyte(buffer, pos, mg, src[i]); + } + wbyte(buffer, pos, mg, chk); + wbyte(buffer, pos, mg, chk >> 8); + } + // Rest is just not formatted + buffer.push_back(pos | floppy_image::MG_N); + } +} + +std::vector<uint8_t> vtech_common_format::flux_to_image(floppy_image *image) +{ + std::vector<uint8_t> bdata(16*256*40, 0); + + for(int track = 0; track != 40; track++) { + auto buffer = image->get_buffer(track, 0); + int sz = buffer.size(); + if(sz < 128) + continue; + + std::vector<bool> bitstream; + int lpos = -1; + bool looped = !((buffer[sz-1] ^ buffer[0]) & floppy_image::MG_MASK); + int cpos = looped ? sz-1 : 0; + while(cpos != lpos) { + int dt = looped && cpos == sz-1 ? (200000000 - (buffer[cpos] & floppy_image::TIME_MASK)) + (buffer[1] & floppy_image::TIME_MASK) : + cpos == sz-1 ? 200000000 - (buffer[cpos] & floppy_image::TIME_MASK) : + (buffer[cpos+1] & floppy_image::TIME_MASK) - (buffer[cpos] & floppy_image::TIME_MASK); + int t = dt >= 9187 - 143 ? 0 : + dt >= 2237 - 143 && dt <= 2237 + 143 ? 1 : + 2; + if(t <= 1) { + if(lpos == -1) + lpos = cpos; + bitstream.push_back(t); + } + cpos += 1; + if(cpos == sz) + cpos = looped ? 1 : 0; + } + int mode = 0; + looped = false; + int pos = 0; + int count = 0; + uint8_t *dest = nullptr; + uint16_t checksum = 0; + uint64_t buf = 0; + sz = bitstream.size(); + if(sz < 128) + continue; + + for(int i=0; i != 63; i++) + buf = (buf << 1) | bitstream[sz-64+i]; + for(;;) { + buf = (buf << 1) | bitstream[pos]; + count ++; + switch(mode) { + case 0: // idle + if(buf == 0x80808000fee718c3) + mode = 1; + count = 0; + break; + + case 1: // sector header + if(count == 24) { + uint8_t trk = buf >> 16; + uint8_t sector = buf >> 8; + uint8_t chk = buf; + if(chk != sector + trk) { + mode = 0; + break; + } + checksum = 0; + dest = bdata.data() + 128 * 16 * trk + 128 * (sector & 0xf); + mode = 2; + } + break; + + case 2: // look for sector data + if(buf == 0x80808000fee718c3) + mode = 1; + else if(buf == 0x80808000c318e7fe) + mode = 3; + count = 0; + break; + + case 3: // sector data + if(count <= 128*8 && !(count & 7)) { + uint8_t byte = buf; + checksum += byte; + *dest++ = byte; + } else if(count == 128*8+16) { + // uint16_t disk_checksum = buf; + // printf("sector checksum %04x %04x\n", checksum, disk_checksum); + mode = 0; + } + break; + } + if(mode == 0 && looped) + break; + pos++; + if(pos == sz) { + pos = 0; + looped = true; + } + } + } + + return bdata; +} + + +const char *vtech_bin_format::name() const +{ + return "vtech_bin"; +} + +const char *vtech_bin_format::description() const +{ + return "VTech sector disk image"; +} + +const char *vtech_bin_format::extensions() const +{ + return "bin"; +} + +const char *vtech_dsk_format::name() const +{ + return "vtech_dsk"; +} + +const char *vtech_dsk_format::description() const +{ + return "VTech dsk image"; +} + +const char *vtech_dsk_format::extensions() const +{ + return "dsk"; +} + +int vtech_bin_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +{ + int size = io_generic_size(io); + + if(size == 40*16*256) + return 50; + + return 0; +} + +int vtech_dsk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +{ + int size = io_generic_size(io); + if(size < 256) + return 0; + + std::vector<uint8_t> bdata(size); + io_generic_read(io, bdata.data(), 0, size); + + // Structurally validate the presence of sector headers and data + int count_sh = 0, count_sd = 0; + uint64_t buf = 0; + for(uint8_t b : bdata) { + buf = (buf << 8) | b; + if(buf == 0x80808000fee718c3) + count_sh++; + else if(buf == 0x80808000c318e7fe) + count_sd++; + } + + return count_sh >= 30*16 && count_sd >= 30*16 ? 100 : 0; +} + +bool vtech_bin_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +{ + int size = io_generic_size(io); + if(size != 40*16*256) + return false; + + std::vector<uint8_t> bdata(size); + io_generic_read(io, bdata.data(), 0, size); + + image_to_flux(bdata, image); + image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + return true; +} + +bool vtech_dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +{ + int size = io_generic_size(io); + std::vector<uint8_t> bdata(size); + io_generic_read(io, bdata.data(), 0, size); + + std::vector<uint8_t> bdatax(128*16*40, 0); + + int mode = 0; + int count = 0; + uint16_t checksum = 0; + uint64_t buf = 0; + uint8_t *dest = nullptr; + + for(uint8_t b : bdata) { + buf = (buf << 8) | b; + count ++; + switch(mode) { + case 0: // idle + if(buf == 0x80808000fee718c3) + mode = 1; + count = 0; + break; + + case 1: // sector header + if(count == 3) { + uint8_t trk = buf >> 16; + uint8_t sector = buf >> 8; + uint8_t chk = buf; + if(chk != sector + trk) { + mode = 0; + break; + } + dest = bdatax.data() + 128*16*trk + sector*128; + checksum = 0; + mode = 2; + } + break; + + case 2: // look for sector data + if(buf == 0x80808000fee718c3) + mode = 1; + else if(buf == 0x80808000c318e7fe) + mode = 3; + count = 0; + break; + + case 3: // sector data + if(count <= 128) { + uint8_t byte = buf; + checksum += byte; + *dest++ = byte; + + } else if(count == 128+2) { + uint16_t disk_checksum = buf; + disk_checksum = (disk_checksum << 8) | (disk_checksum >> 8); + mode = 0; + } + break; + } + } + + image_to_flux(bdatax, image); + image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + return true; +} + +bool vtech_bin_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +{ + int tracks, heads; + image->get_maximal_geometry(tracks, heads); + if(tracks < 40) + return false; + + auto bdata = flux_to_image(image); + io_generic_write(io, bdata.data(), 0, bdata.size()); + return true; +} + +bool vtech_dsk_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +{ + int tracks, heads; + image->get_maximal_geometry(tracks, heads); + if(tracks < 40) + return false; + + auto bdata = flux_to_image(image); + std::vector<uint8_t> bdatax(0x9b*16*40); + + // Format is essentially an idealized version of what's written on the disk + + static const uint8_t sector_map[16] = { + 0x0, 0xb, 0x6, 0x1, 0xc, 0x7, 0x2, 0xd, 0x8, 0x3, 0xe, 0x9, 0x4, 0xf, 0xa, 0x5 + }; + + int pos = 0; + for(int track = 0; track != 40; track ++) { + for(int sector = 0; sector != 16; sector ++) { + uint8_t sid = sector_map[sector]; + for(int i=0; i != 7; i++) + bdatax[pos++] = 0x80; + bdatax[pos++] = 0x00; + bdatax[pos++] = 0xfe; + bdatax[pos++] = 0xe7; + bdatax[pos++] = 0x18; + bdatax[pos++] = 0xc3; + bdatax[pos++] = track; + bdatax[pos++] = sid; + bdatax[pos++] = track+sid; + for(int i=0; i != 5; i++) + bdatax[pos++] = 0x80; + bdatax[pos++] = 0x00; + bdatax[pos++] = 0xc3; + bdatax[pos++] = 0x18; + bdatax[pos++] = 0xe7; + bdatax[pos++] = 0xfe; + uint16_t chk = 0; + const uint8_t *src = bdata.data() + 16*128*track + 128*sid; + for(int i=0; i != 128; i++) { + chk += src[i]; + bdatax[pos++] = src[i]; + } + bdatax[pos++] = chk; + bdatax[pos++] = chk >> 8; + } + } + + io_generic_write(io, bdatax.data(), 0, bdatax.size()); + return true; +} + + +const floppy_format_type FLOPPY_VTECH_BIN_FORMAT = &floppy_image_format_creator<vtech_bin_format>; +const floppy_format_type FLOPPY_VTECH_DSK_FORMAT = &floppy_image_format_creator<vtech_dsk_format>; diff --git a/src/lib/formats/vt_dsk.h b/src/lib/formats/vt_dsk.h new file mode 100644 index 00000000000..739e5234a3f --- /dev/null +++ b/src/lib/formats/vt_dsk.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/********************************************************************* + + formats/vt_dsk.h + + VTech disk image formats + +*********************************************************************/ +#ifndef MAME_FORMATS_VT_DSK_H +#define MAME_FORMATS_VT_DSK_H + +#pragma once + +#include "flopimg.h" + +class vtech_common_format : public floppy_image_format_t { +public: + virtual bool supports_save() const override { return true; } + +protected: + static void image_to_flux(const std::vector<uint8_t> &bdata, floppy_image *image); + static std::vector<uint8_t> flux_to_image(floppy_image *image); + + static void wbit(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, bool bit); + static void wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, uint8_t byte); +}; + +class vtech_bin_format : public vtech_common_format { +public: + vtech_bin_format() = default; + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + + virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; +}; + +class vtech_dsk_format : public vtech_common_format { +public: + vtech_dsk_format() = default; + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + + virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; +}; + +extern const floppy_format_type FLOPPY_VTECH_BIN_FORMAT; +extern const floppy_format_type FLOPPY_VTECH_DSK_FORMAT; + +#endif // MAME_FORMATS_VT_DSK_H |