summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/hpi_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/hpi_dsk.cpp')
-rw-r--r--src/lib/formats/hpi_dsk.cpp96
1 files changed, 78 insertions, 18 deletions
diff --git a/src/lib/formats/hpi_dsk.cpp b/src/lib/formats/hpi_dsk.cpp
index 8d23f151862..50d2653280d 100644
--- a/src/lib/formats/hpi_dsk.cpp
+++ b/src/lib/formats/hpi_dsk.cpp
@@ -4,9 +4,10 @@
hpi_dsk.cpp
- HP9895A "HPI" disk images
+ HP9885/HP9895A "HPI" disk images
- CHS = 77/2/30
+ CHS = 67/1/30 (SSDD)
+ CHS = 77/2/30 (DSDD)
Sector size 256 bytes
Cell size 2 µs
Gap1 = 16 x 0x00
@@ -40,7 +41,7 @@
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.
+ that it can be loaded into HP9885/HP9895 emulator.
*********************************************************************/
@@ -65,11 +66,14 @@ constexpr int ID_DATA_OFFSET = 30 * 16; // Nominal distance (in cells) between I
// 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
+constexpr unsigned HPI_9885_TRACKS = 67; // Tracks visible to HP9885 drives
// 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()
{
+ (void)HPI_IMAGE_SIZE;
+ (void)HPI_RED_IMAGE_SIZE;
}
int hpi_format::identify(io_generic *io, uint32_t form_factor)
@@ -79,27 +83,79 @@ int hpi_format::identify(io_generic *io, uint32_t form_factor)
// 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...
+ unsigned dummy_heads;
+ unsigned dummy_tracks;
if (((form_factor == floppy_image::FF_8) || (form_factor == floppy_image::FF_UNKNOWN)) &&
- ((size == HPI_RED_IMAGE_SIZE) || (size == HPI_IMAGE_SIZE))) {
+ geometry_from_size(size , dummy_heads , dummy_tracks)) {
return 50;
} else {
return 0;
}
}
+bool hpi_format::geometry_from_size(uint64_t image_size , unsigned& heads , unsigned& tracks)
+{
+ if ((image_size % HPI_SECTOR_SIZE) != 0) {
+ // Not a whole number of sectors
+ return false;
+ }
+ unsigned sectors = unsigned(image_size / HPI_SECTOR_SIZE);
+ if ((sectors % HPI_SECTORS) != 0) {
+ // Not a whole number of tracks
+ return false;
+ }
+ unsigned tot_tracks = sectors / HPI_SECTORS;
+ // Possible combinations
+ //
+ // | Tot tracks | Heads | Tracks | Format |
+ // |------------+-------+--------+--------|
+ // | 67 | 1 | 67 | SSDD |
+ // | 77 | 1 | 77 | SSDD |
+ // | 150 | 2 | 75 | DSDD |
+ // | 154 | 2 | 77 | DSDD |
+ //
+ switch (tot_tracks) {
+ case HPI_9885_TRACKS:
+ heads = 1;
+ tracks = HPI_9885_TRACKS;
+ return true;
+
+ case HPI_TRACKS:
+ heads = 1;
+ tracks = HPI_TRACKS;
+ return true;
+
+ case HPI_RED_TRACKS * 2:
+ heads = 2;
+ tracks = HPI_RED_TRACKS;
+ return true;
+
+ case HPI_TRACKS * 2:
+ heads = 2;
+ tracks = HPI_TRACKS;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
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
+ unsigned heads;
+ unsigned cylinders;
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 {
+ if (!geometry_from_size(size, heads, cylinders)) {
+ return false;
+ }
+ int max_tracks;
+ int max_heads;
+ image->get_maximal_geometry(max_tracks , max_heads);
+ if (cylinders > max_tracks || heads > max_heads) {
return false;
}
+ image->set_variant(heads == 2 ? floppy_image::DSDD : floppy_image::SSDD);
// Suck in the whole image
std::vector<uint8_t> image_data(size);
@@ -118,11 +174,11 @@ bool hpi_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
unsigned list_offset = 0;
for (unsigned cyl = 0; cyl < cylinders; cyl++) {
- for (unsigned head = 0; head < HPI_HEADS; head++) {
+ for (unsigned head = 0; head < 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;
+ unsigned offset_in_image = chs_to_lba(cyl, head, real_sector, heads) * HPI_SECTOR_SIZE;
write_sector(track_data , cyl , real_sector + (head << 7) , &image_data[ offset_in_image ]);
}
fill_with_gap3(track_data);
@@ -135,8 +191,12 @@ bool hpi_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
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++) {
+ int tracks;
+ int heads;
+ image->get_actual_geometry(tracks, heads);
+
+ for (int cyl = 0; cyl < tracks; cyl++) {
+ for (int head = 0; head < heads; head++) {
uint8_t bitstream[ 21000 ];
int bitstream_size;
generate_bitstream_from_track(cyl , head , CELL_SIZE , bitstream , bitstream_size , image , 0);
@@ -145,7 +205,7 @@ bool hpi_format::save(io_generic *io, floppy_image *image)
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;
+ unsigned offset_in_image = chs_to_lba(cyl, head, sector_no, heads) * HPI_SECTOR_SIZE;
io_generic_write(io, sector_data, offset_in_image, HPI_SECTOR_SIZE);
}
}
@@ -300,9 +360,9 @@ void hpi_format::fill_with_gap3(std::vector<uint32_t> &buffer)
}
}
-unsigned hpi_format::chs_to_lba(unsigned cylinder , unsigned head , unsigned sector)
+unsigned hpi_format::chs_to_lba(unsigned cylinder , unsigned head , unsigned sector , unsigned heads)
{
- return sector + (head + cylinder * HPI_HEADS) * HPI_SECTORS;
+ return sector + (head + cylinder * 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)