mirror of
https://github.com/holub/mame
synced 2025-06-04 20:06:28 +03:00
Hp9845: Support for HPI floppy format (#2310)
hp9845: Support for HPI floppy format [F. Ulivi, A.Kückes]
This commit is contained in:
parent
dc1dcd260b
commit
e2b9e11da0
@ -893,6 +893,18 @@ if (FORMATS["HECT_TAP"]~=null or _OPTIONS["with-tools"]) then
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
--
|
||||
--@src/lib/formats/hpi_dsk.h,FORMATS["HPI_DSK"] = true
|
||||
--------------------------------------------------
|
||||
|
||||
if (FORMATS["HPI_DSK"]~=null or _OPTIONS["with-tools"]) then
|
||||
files {
|
||||
MAME_DIR.. "src/lib/formats/hpi_dsk.cpp",
|
||||
MAME_DIR.. "src/lib/formats/hpi_dsk.h",
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
--
|
||||
--@src/lib/formats/hp_ipc_dsk.h,FORMATS["HP_IPC_DSK"] = true
|
||||
|
@ -800,6 +800,7 @@ FORMATS["GTP_CAS"] = true
|
||||
FORMATS["HECTOR_MINIDISC"] = true
|
||||
FORMATS["HECT_DSK"] = true
|
||||
FORMATS["HECT_TAP"] = true
|
||||
FORMATS["HPI_DSK"] = true
|
||||
FORMATS["HP_IPC_DSK"] = true
|
||||
FORMATS["IQ151_DSK"] = true
|
||||
FORMATS["ITT3030_DSK"] = true
|
||||
|
@ -133,9 +133,12 @@ READ16_MEMBER(hp98034_io_card_device::reg_r)
|
||||
m_force_flg = true;
|
||||
|
||||
update_flg();
|
||||
// PPU yields to let NP see FLG=0 immediately
|
||||
// (horrible race conditions lurking...)
|
||||
space.device().execute().yield();
|
||||
// PPU pauses for an instant to let NP see FLG=0 immediately
|
||||
// There's a bug in Mass Memory opt. ROM because the PPU
|
||||
// doesn't wait for FLG from 98034 in a few (common) cases.
|
||||
// A magic combination of relative speeds between PPU and
|
||||
// NP always hides this bug in the real hw.
|
||||
space.device().execute().spin_until_time(attotime::from_usec(5));
|
||||
|
||||
LOG("read R%u=%04x\n" , offset + 4 , res);
|
||||
return res;
|
||||
@ -156,9 +159,9 @@ WRITE16_MEMBER(hp98034_io_card_device::reg_w)
|
||||
m_force_flg = true;
|
||||
|
||||
update_flg();
|
||||
// PPU yields to let NP see FLG=0 immediately
|
||||
// (horrible race conditions lurking...)
|
||||
space.device().execute().yield();
|
||||
// PPU pauses for an instant to let NP see FLG=0 immediately
|
||||
// (see above)
|
||||
space.device().execute().spin_until_time(attotime::from_usec(5));
|
||||
LOG("write R%u=%04x\n" , offset + 4 , data);
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "hp9895.h"
|
||||
#include "formats/hpi_dsk.h"
|
||||
|
||||
// Debugging
|
||||
#define VERBOSE 1
|
||||
@ -866,6 +867,12 @@ static SLOT_INTERFACE_START(hp9895_floppies)
|
||||
SLOT_INTERFACE("8dsdd" , FLOPPY_8_DSDD)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
static const floppy_format_type hp9895_floppy_formats[] = {
|
||||
FLOPPY_MFI_FORMAT,
|
||||
FLOPPY_HPI_FORMAT,
|
||||
nullptr
|
||||
};
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT(hp9895)
|
||||
MCFG_CPU_ADD("cpu" , Z80 , 4000000)
|
||||
MCFG_CPU_PROGRAM_MAP(z80_program_map)
|
||||
@ -884,9 +891,9 @@ static MACHINE_CONFIG_FRAGMENT(hp9895)
|
||||
MCFG_PHI_DIO_READWRITE_CB(READ8(hp9895_device , phi_dio_r) , WRITE8(hp9895_device , phi_dio_w))
|
||||
MCFG_PHI_INT_WRITE_CB(WRITELINE(hp9895_device , phi_int_w))
|
||||
|
||||
MCFG_FLOPPY_DRIVE_ADD("floppy0" , hp9895_floppies , "8dsdd" , floppy_image_device::default_floppy_formats)
|
||||
MCFG_FLOPPY_DRIVE_ADD("floppy0" , hp9895_floppies , "8dsdd" , hp9895_floppy_formats)
|
||||
MCFG_SLOT_FIXED(true)
|
||||
MCFG_FLOPPY_DRIVE_ADD("floppy1" , hp9895_floppies , "8dsdd" , floppy_image_device::default_floppy_formats)
|
||||
MCFG_FLOPPY_DRIVE_ADD("floppy1" , hp9895_floppies , "8dsdd" , hp9895_floppy_formats)
|
||||
MCFG_SLOT_FIXED(true)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
430
src/lib/formats/hpi_dsk.cpp
Normal file
430
src/lib/formats/hpi_dsk.cpp
Normal file
@ -0,0 +1,430 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: Ansgar Kückes, F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hpi_dsk.cpp
|
||||
|
||||
HP9895A "HPI" disk images
|
||||
|
||||
CHS = 77/2/30
|
||||
Sector size 256 bytes
|
||||
Cell size 2 µs
|
||||
Gap1 = 16 x 0x00
|
||||
Gap2 = 34 x 0x00
|
||||
Gap3 = ~490 x 0x00 (depends on actual rotation speed)
|
||||
Sync = 4 x 0x00 + 4 x 0xff
|
||||
ID AM = 0x0e clock + 0x70 data
|
||||
Data AM = 0x0e clock + 0x50 data
|
||||
DefectTrack AM = 0x0e clock + 0xf0 data
|
||||
CRC-16 excludes address markers
|
||||
MMFM/M2FM encoding (LS bit first)
|
||||
|
||||
The order of sectors in a track depends on the interleave factor
|
||||
which is the distance (in number of sectors) between two consecutively
|
||||
numbered sectors. Interleave factor is specified at formatting time.
|
||||
The default factor is 7. The order of sectors for this factor is:
|
||||
0, 13, 26, 9, 22, 5, 18, 1, 14, 27, 10, 23, 6, 19, 2,
|
||||
15, 28, 11, 24, 7, 20, 3, 16, 29, 12, 25, 8, 21, 4, 17
|
||||
|
||||
<Track> := [Index hole]|Sector0|Gap2|Sector1|Gap2|...|Sector29|Gap3|
|
||||
|
||||
<Sector> := ID field|Gap1|Data field
|
||||
|
||||
<ID field> := Sync|ID AM|Track no.|Sector no.|CRC-16|0x00
|
||||
|
||||
<Data field> := Sync|Data AM|Data|CRC-16|0x00
|
||||
|
||||
This format is just a raw image of every sector on a HP-formatted
|
||||
8" floppy disk. Files with this format have no header/trailer and
|
||||
are exactly 1182720 bytes in size (30 sectors, 2 heads, 77 tracks,
|
||||
256 bytes per sector). There's also a "reduced" version holding
|
||||
just 75 cylinders.
|
||||
When loading, the disk image is translated to MMFM encoding so
|
||||
that it can be loaded into HP9895 emulator.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "hpi_dsk.h"
|
||||
|
||||
// Debugging
|
||||
#define VERBOSE 0
|
||||
#define LOG(...) do { if (VERBOSE) printf(__VA_ARGS__); } while (false)
|
||||
|
||||
constexpr unsigned IL_OFFSET = 0x12; // Position of interleave factor in HPI image (2 bytes, big-endian)
|
||||
constexpr unsigned DEFAULT_IL = 7; // Default interleaving factor
|
||||
constexpr unsigned CELL_SIZE = 1200; // Bit cell size (1 µs)
|
||||
constexpr uint8_t ID_AM = 0x70; // ID address mark
|
||||
constexpr uint8_t DATA_AM = 0x50; // Data address mark
|
||||
constexpr uint8_t AM_CLOCK = 0x0e; // Clock pattern of AM
|
||||
constexpr uint32_t ID_CD_PATTERN= 0x55552a54; // C/D pattern of 0xff + ID_AM
|
||||
constexpr uint32_t DATA_CD_PATTERN = 0x55552a44; // C/D pattern of 0xff + DATA_AM
|
||||
constexpr unsigned GAP1_SIZE = 17; // Size of gap 1 (+1)
|
||||
constexpr unsigned GAP2_SIZE = 35; // Size of gap 2 (+1)
|
||||
constexpr unsigned ID_DATA_OFFSET = 30 * 16; // Nominal distance (in cells) between ID & DATA AM
|
||||
// Size of image file (holding 77 cylinders)
|
||||
constexpr unsigned HPI_IMAGE_SIZE = HPI_TRACKS * HPI_HEADS * HPI_SECTORS * HPI_SECTOR_SIZE;
|
||||
constexpr unsigned HPI_RED_TRACKS = 75; // Reduced number of tracks
|
||||
// Size of reduced image file (holding 75 cylinders)
|
||||
constexpr unsigned HPI_RED_IMAGE_SIZE = HPI_RED_TRACKS * HPI_HEADS * HPI_SECTORS * HPI_SECTOR_SIZE;
|
||||
|
||||
hpi_format::hpi_format()
|
||||
{
|
||||
}
|
||||
|
||||
int hpi_format::identify(io_generic *io, uint32_t form_factor)
|
||||
{
|
||||
uint64_t size = io_generic_size(io);
|
||||
|
||||
// we try to stay back and give only 50 points, since another image
|
||||
// format may also have images of the same size (there is no header and no
|
||||
// magic number for HPI format...
|
||||
if (((form_factor == floppy_image::FF_8) || (form_factor == floppy_image::FF_UNKNOWN)) &&
|
||||
((size == HPI_RED_IMAGE_SIZE) || (size == HPI_IMAGE_SIZE))) {
|
||||
return 50;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool hpi_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
|
||||
{
|
||||
image->set_variant(floppy_image::DSDD); // We actually need to derive the variant from the image size depending on the form factor
|
||||
|
||||
uint64_t size = io_generic_size(io);
|
||||
unsigned cylinders;
|
||||
if (size == HPI_RED_IMAGE_SIZE) {
|
||||
cylinders = HPI_RED_TRACKS;
|
||||
} else if (size == HPI_IMAGE_SIZE) {
|
||||
cylinders = HPI_TRACKS;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suck in the whole image
|
||||
std::vector<uint8_t> image_data(size);
|
||||
io_generic_read(io, (void *)image_data.data(), 0, size);
|
||||
|
||||
// Get interleave factor from image
|
||||
unsigned il = (unsigned)image_data[ IL_OFFSET ] * 256 + image_data[ IL_OFFSET + 1 ];
|
||||
LOG("I/L from image: %u\n" , il);
|
||||
if (il < 1 || il >= HPI_SECTORS) {
|
||||
il = DEFAULT_IL;
|
||||
}
|
||||
LOG("Actual I/L: %u\n" , il);
|
||||
|
||||
sector_list_t sector_list;
|
||||
interleaved_sectors(il, sector_list);
|
||||
|
||||
unsigned list_offset = 0;
|
||||
for (unsigned cyl = 0; cyl < cylinders; cyl++) {
|
||||
for (unsigned head = 0; head < HPI_HEADS; head++) {
|
||||
std::vector<uint32_t> track_data;
|
||||
for (unsigned sector = 0; sector < HPI_SECTORS; sector++) {
|
||||
unsigned real_sector = sector_list[ (sector + list_offset) % HPI_SECTORS ];
|
||||
unsigned offset_in_image = chs_to_lba(cyl, head, real_sector) * HPI_SECTOR_SIZE;
|
||||
write_sector(track_data , cyl , real_sector + (head << 7) , &image_data[ offset_in_image ]);
|
||||
}
|
||||
fill_with_gap3(track_data);
|
||||
generate_track_from_levels(cyl , head , track_data , 0 , image);
|
||||
list_offset = (list_offset + m_track_skew[ il - 1 ][ head ]) % HPI_SECTORS;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hpi_format::save(io_generic *io, floppy_image *image)
|
||||
{
|
||||
for (unsigned cyl = 0; cyl < HPI_TRACKS; cyl++) {
|
||||
for (unsigned head = 0; head < HPI_HEADS; head++) {
|
||||
uint8_t bitstream[ 21000 ];
|
||||
int bitstream_size;
|
||||
generate_bitstream_from_track(cyl , head , CELL_SIZE , bitstream , bitstream_size , image , 0);
|
||||
int pos = 0;
|
||||
unsigned track_no , head_no , sector_no;
|
||||
uint8_t sector_data[ HPI_SECTOR_SIZE ];
|
||||
while (get_next_sector(bitstream , bitstream_size , pos , track_no , head_no , sector_no , sector_data)) {
|
||||
if (track_no == cyl && head_no == head && sector_no < HPI_SECTORS) {
|
||||
unsigned offset_in_image = chs_to_lba(cyl, head, sector_no) * HPI_SECTOR_SIZE;
|
||||
io_generic_write(io, sector_data, offset_in_image, HPI_SECTOR_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *hpi_format::name() const
|
||||
{
|
||||
return "hpi";
|
||||
}
|
||||
|
||||
const char *hpi_format::description() const
|
||||
{
|
||||
return "HP9895A floppy disk image";
|
||||
}
|
||||
|
||||
const char *hpi_format::extensions() const
|
||||
{
|
||||
return "hpi";
|
||||
}
|
||||
|
||||
bool hpi_format::supports_save() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void hpi_format::interleaved_sectors(unsigned il_factor , sector_list_t& sector_list)
|
||||
{
|
||||
sector_list.fill(0xff);
|
||||
|
||||
unsigned idx = HPI_SECTORS - il_factor;
|
||||
for (unsigned sect = 0; sect < HPI_SECTORS; sect++) {
|
||||
idx = (idx + il_factor) % HPI_SECTORS;
|
||||
while (sector_list[ idx ] != 0xff) {
|
||||
idx = (idx + 1) % HPI_SECTORS;
|
||||
}
|
||||
LOG("[%u]=%u\n" , idx , sect);
|
||||
sector_list[ idx ] = sect;
|
||||
}
|
||||
}
|
||||
|
||||
void hpi_format::write_mmfm_bit(std::vector<uint32_t> &buffer , bool data_bit , bool clock_bit)
|
||||
{
|
||||
bool had_transition = buffer.size() < 2 ? false : bit_r(buffer, buffer.size() - 1) || bit_r(buffer , buffer.size() - 2);
|
||||
clock_bit = !data_bit && (clock_bit || !had_transition);
|
||||
bit_w(buffer , clock_bit , CELL_SIZE);
|
||||
bit_w(buffer , data_bit , CELL_SIZE);
|
||||
}
|
||||
|
||||
void hpi_format::write_mmfm_byte(std::vector<uint32_t> &buffer , uint8_t data , uint8_t clock)
|
||||
{
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
write_mmfm_bit(buffer , BIT(data , i) , BIT(clock , i));
|
||||
}
|
||||
}
|
||||
|
||||
void hpi_format::write_sync(std::vector<uint32_t> &buffer)
|
||||
{
|
||||
// Sync
|
||||
// 4x 00
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
write_mmfm_byte(buffer , 0);
|
||||
}
|
||||
// 4x ff
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
write_mmfm_byte(buffer , 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
void hpi_format::write_crc(std::vector<uint32_t> &buffer , uint16_t crc)
|
||||
{
|
||||
// Note that CRC is stored with MSB (x^15) first
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
write_mmfm_bit(buffer , BIT(crc , 15 - i) , 0);
|
||||
}
|
||||
}
|
||||
|
||||
void hpi_format::write_sector(std::vector<uint32_t> &buffer , uint8_t track_no , uint8_t sect_head_no , const uint8_t *sect_data)
|
||||
{
|
||||
// **** On-disk format of a sector ****
|
||||
//
|
||||
// | Offset | Size | Value | Content |
|
||||
// |--------+------+-------+----------------------|
|
||||
// | 0 | 4 | 00 | Sync |
|
||||
// | 4 | 4 | ff | Sync |
|
||||
// | 8 | 1 | 70 | ID AM (clock = 0e) |
|
||||
// | 9 | 1 | xx | Track no. |
|
||||
// | 10 | 1 | xx | Sector and head no. |
|
||||
// | 11 | 2 | xx | ID CRC |
|
||||
// | 13 | 1 | 00 | ID tail |
|
||||
// | 14 | 16 | 00 | Gap 1 |
|
||||
// | 30 | 4 | 00 | Sync |
|
||||
// | 34 | 4 | ff | Sync |
|
||||
// | 38 | 1 | 50 | Data AM (clock = 0e) |
|
||||
// | 39 | 256 | xx | Sector data |
|
||||
// | 295 | 2 | xx | Data CRC |
|
||||
// | 297 | 1 | 00 | Data tail |
|
||||
// | 298 | 34 | 00 | Gap 2 |
|
||||
// | 332 | | | |
|
||||
|
||||
// Sync
|
||||
write_sync(buffer);
|
||||
// ID AM
|
||||
write_mmfm_byte(buffer , ID_AM , AM_CLOCK);
|
||||
auto crc_start = buffer.size();
|
||||
// Track #
|
||||
write_mmfm_byte(buffer , track_no);
|
||||
// Sector/head #
|
||||
write_mmfm_byte(buffer , sect_head_no);
|
||||
uint16_t crc = calc_crc_ccitt(buffer , crc_start , buffer.size());
|
||||
// ID CRC
|
||||
write_crc(buffer , crc);
|
||||
// Gap 1
|
||||
for (unsigned i = 0; i < GAP1_SIZE; i++) {
|
||||
write_mmfm_byte(buffer , 0);
|
||||
}
|
||||
// Sync
|
||||
write_sync(buffer);
|
||||
// Data AM
|
||||
write_mmfm_byte(buffer , DATA_AM , AM_CLOCK);
|
||||
crc_start = buffer.size();
|
||||
for (unsigned i = 0; i < HPI_SECTOR_SIZE; i += 2) {
|
||||
// Data: bytes are swapped in pairs
|
||||
write_mmfm_byte(buffer , sect_data[ i + 1 ]);
|
||||
write_mmfm_byte(buffer , sect_data[ i ]);
|
||||
}
|
||||
crc = calc_crc_ccitt(buffer , crc_start , buffer.size());
|
||||
// Data CRC
|
||||
write_crc(buffer , crc);
|
||||
// Gap 2
|
||||
for (unsigned i = 0; i < GAP2_SIZE; i++) {
|
||||
write_mmfm_byte(buffer , 0);
|
||||
}
|
||||
}
|
||||
|
||||
void hpi_format::fill_with_gap3(std::vector<uint32_t> &buffer)
|
||||
{
|
||||
// Cell count in a track (1 µs cells in a 1/6 s track)
|
||||
unsigned cell_count = (500000 * 120) / 360;
|
||||
unsigned cells_in_buffer = buffer.size();
|
||||
// Size of gap 3
|
||||
unsigned gap_3 = (cell_count - cells_in_buffer) / 16;
|
||||
// Gap 3
|
||||
for (unsigned i = 0; i < gap_3; i++) {
|
||||
write_mmfm_byte(buffer , 0);
|
||||
}
|
||||
// Last cell to round everything up to 2E+8
|
||||
if (buffer.size() * CELL_SIZE < 200000000) {
|
||||
bit_w(buffer , false , 200000000 - buffer.size() * CELL_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned hpi_format::chs_to_lba(unsigned cylinder , unsigned head , unsigned sector)
|
||||
{
|
||||
return sector + (head + cylinder * HPI_HEADS) * HPI_SECTORS;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> hpi_format::get_next_id_n_block(const uint8_t *bitstream , int bitstream_size , int& pos , int& start_pos)
|
||||
{
|
||||
std::vector<uint8_t> res;
|
||||
uint32_t sr = 0;
|
||||
// Look for either sync + ID AM or sync + DATA AM
|
||||
while (pos < bitstream_size && sr != ID_CD_PATTERN && sr != DATA_CD_PATTERN) {
|
||||
bool bit = BIT(bitstream[ pos >> 3 ] , 7 - (pos & 7));
|
||||
pos++;
|
||||
sr = (sr << 1) | bit;
|
||||
}
|
||||
if (pos == bitstream_size) {
|
||||
// End of track reached
|
||||
return res;
|
||||
}
|
||||
start_pos = pos;
|
||||
// ID blocks: Track no. + sector/head no. + CRC
|
||||
// Data blocks: Sector data + CRC
|
||||
unsigned to_dump;
|
||||
if (sr == ID_CD_PATTERN) {
|
||||
to_dump = 4;
|
||||
res.push_back(ID_AM);
|
||||
} else {
|
||||
to_dump = HPI_SECTOR_SIZE + 2;
|
||||
res.push_back(DATA_AM);
|
||||
}
|
||||
// Align to data cells
|
||||
pos++;
|
||||
for (unsigned i = 0; i < to_dump && pos < bitstream_size; i++) {
|
||||
uint8_t byte = 0;
|
||||
unsigned j;
|
||||
for (j = 0; j < 8 && pos < bitstream_size; j++) {
|
||||
bool bit = BIT(bitstream[ pos >> 3 ] , 7 - (pos & 7));
|
||||
pos += 2;
|
||||
byte >>= 1;
|
||||
if (bit) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
}
|
||||
if (j == 8) {
|
||||
res.push_back(byte);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool hpi_format::get_next_sector(const uint8_t *bitstream , int bitstream_size , int& pos , unsigned& track , unsigned& head , unsigned& sector , uint8_t *sector_data)
|
||||
{
|
||||
std::vector<uint8_t> block;
|
||||
while (true) {
|
||||
// Scan for ID block first
|
||||
int id_pos;
|
||||
while (true) {
|
||||
if (block.size() == 0) {
|
||||
block = get_next_id_n_block(bitstream , bitstream_size , pos , id_pos);
|
||||
if (block.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (block[ 0 ] == ID_AM && block.size() >= 3) {
|
||||
track = block[ 1 ];
|
||||
head = block[ 2 ] >> 7;
|
||||
sector = block[ 2 ] & 0x7f;
|
||||
break;
|
||||
} else {
|
||||
block.clear();
|
||||
}
|
||||
}
|
||||
// Then for DATA block
|
||||
int data_pos;
|
||||
block = get_next_id_n_block(bitstream , bitstream_size , pos , data_pos);
|
||||
if (block.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (block[ 0 ] == DATA_AM && block.size() >= (HPI_SECTOR_SIZE + 1) && abs((data_pos - id_pos) - ID_DATA_OFFSET) <= 16) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < HPI_SECTOR_SIZE; i += 2) {
|
||||
sector_data[ i ] = block[ i + 2 ];
|
||||
sector_data[ i + 1 ] = block[ i + 1 ];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This table comes straight from hp9895 firmware (it's @ 0x0f90)
|
||||
// For each interleave factor in [1..29] it stores the number of positions
|
||||
// to move forward in the interleaved sector list when beginning a new track.
|
||||
// There are different offsets for tracks on head 0 and tracks on head 1.
|
||||
const uint8_t hpi_format::m_track_skew[ HPI_SECTORS - 1 ][ HPI_HEADS ] = {
|
||||
{ 0x1c , 0x18 }, // Interleave = 1
|
||||
{ 0x1c , 0x18 }, // Interleave = 2
|
||||
{ 0x1c , 0x18 }, // Interleave = 3
|
||||
{ 0x1d , 0x1a }, // Interleave = 4
|
||||
{ 0x1a , 0x18 }, // Interleave = 5
|
||||
{ 0x19 , 0x18 }, // Interleave = 6
|
||||
{ 0x00 , 0x00 }, // Interleave = 7
|
||||
{ 0x1d , 0x1d }, // Interleave = 8
|
||||
{ 0x1c , 0x1c }, // Interleave = 9
|
||||
{ 0x15 , 0x15 }, // Interleave = 10
|
||||
{ 0x00 , 0x00 }, // Interleave = 11
|
||||
{ 0x19 , 0x19 }, // Interleave = 12
|
||||
{ 0x00 , 0x00 }, // Interleave = 13
|
||||
{ 0x1d , 0x1d }, // Interleave = 14
|
||||
{ 0x10 , 0x10 }, // Interleave = 15
|
||||
{ 0x1d , 0x1d }, // Interleave = 16
|
||||
{ 0x00 , 0x00 }, // Interleave = 17
|
||||
{ 0x19 , 0x19 }, // Interleave = 18
|
||||
{ 0x00 , 0x00 }, // Interleave = 19
|
||||
{ 0x15 , 0x15 }, // Interleave = 20
|
||||
{ 0x1c , 0x1c }, // Interleave = 21
|
||||
{ 0x1d , 0x1d }, // Interleave = 22
|
||||
{ 0x00 , 0x00 }, // Interleave = 23
|
||||
{ 0x19 , 0x19 }, // Interleave = 24
|
||||
{ 0x1a , 0x1a }, // Interleave = 25
|
||||
{ 0x1d , 0x1d }, // Interleave = 26
|
||||
{ 0x1c , 0x1c }, // Interleave = 27
|
||||
{ 0x1d , 0x1d }, // Interleave = 28
|
||||
{ 0x00 , 0x00 } // Interleave = 29
|
||||
};
|
||||
|
||||
const floppy_format_type FLOPPY_HPI_FORMAT = &floppy_image_format_creator<hpi_format>;
|
55
src/lib/formats/hpi_dsk.h
Normal file
55
src/lib/formats/hpi_dsk.h
Normal file
@ -0,0 +1,55 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: Ansgar Kückes, F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hpi_dsk.h
|
||||
|
||||
"HPI" disk format
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _HPI_DSK_H_
|
||||
#define _HPI_DSK_H_
|
||||
|
||||
#include "flopimg.h"
|
||||
|
||||
// Geometry constants
|
||||
constexpr unsigned HPI_TRACKS = 77;
|
||||
constexpr unsigned HPI_HEADS = 2;
|
||||
constexpr unsigned HPI_SECTORS = 30;
|
||||
constexpr unsigned HPI_SECTOR_SIZE = 256;
|
||||
|
||||
class hpi_format : public floppy_image_format_t
|
||||
{
|
||||
public:
|
||||
hpi_format();
|
||||
|
||||
virtual int identify(io_generic *io, uint32_t form_factor) override;
|
||||
virtual bool load(io_generic *io, uint32_t form_factor, floppy_image *image) override;
|
||||
virtual bool save(io_generic *io, floppy_image *image) override;
|
||||
virtual const char *name() const override;
|
||||
virtual const char *description() const override;
|
||||
virtual const char *extensions() const override;
|
||||
virtual bool supports_save() const override;
|
||||
|
||||
private:
|
||||
typedef std::array<uint8_t , HPI_SECTORS> sector_list_t;
|
||||
static void interleaved_sectors(unsigned il_factor , sector_list_t& sector_list);
|
||||
void write_mmfm_bit(std::vector<uint32_t> &buffer , bool data_bit , bool clock_bit);
|
||||
void write_mmfm_byte(std::vector<uint32_t> &buffer , uint8_t data , uint8_t clock = 0);
|
||||
void write_sync(std::vector<uint32_t> &buffer);
|
||||
void write_crc(std::vector<uint32_t> &buffer , uint16_t crc);
|
||||
void write_sector(std::vector<uint32_t> &buffer , uint8_t track_no , uint8_t sect_head_no , const uint8_t *sect_data);
|
||||
void fill_with_gap3(std::vector<uint32_t> &buffer);
|
||||
static unsigned chs_to_lba(unsigned cylinder , unsigned head , unsigned sector);
|
||||
std::vector<uint8_t> get_next_id_n_block(const uint8_t *bitstream , int bitstream_size , int& pos , int& start_pos);
|
||||
bool get_next_sector(const uint8_t *bitstream , int bitstream_size , int& pos , unsigned& track , unsigned& head , unsigned& sector , uint8_t *sector_data);
|
||||
|
||||
static const uint8_t m_track_skew[ HPI_SECTORS - 1 ][ HPI_HEADS ];
|
||||
};
|
||||
|
||||
extern const floppy_format_type FLOPPY_HPI_FORMAT;
|
||||
|
||||
#endif /* _HPI_DSK_H_ */
|
@ -46,6 +46,8 @@
|
||||
|
||||
#include "formats/applix_dsk.h"
|
||||
|
||||
#include "formats/hpi_dsk.h"
|
||||
|
||||
static floppy_format_type floppy_formats[] = {
|
||||
FLOPPY_MFI_FORMAT,
|
||||
FLOPPY_DFI_FORMAT,
|
||||
@ -75,6 +77,8 @@ static floppy_format_type floppy_formats[] = {
|
||||
FLOPPY_ORIC_DSK_FORMAT,
|
||||
|
||||
FLOPPY_APPLIX_FORMAT,
|
||||
|
||||
FLOPPY_HPI_FORMAT
|
||||
};
|
||||
|
||||
void CLIB_DECL ATTR_PRINTF(1,2) logerror(const char *format, ...)
|
||||
|
Loading…
Reference in New Issue
Block a user