summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/uniflex_dsk.cpp
blob: 6b536aac3eb50e0844508ea92affb60f5f2f467a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// license:BSD-3-Clause
// copyright-holders:68bit
/*
 * uniflex_dsk.c  -  UniFLEX compatible disk images
 *
 * The UniFLEX floppy disk format is distinctily different to the FLEX format,
 * the sector size is 512 byte sectors versus 256 byte sectors and the format
 * of the disk information is different, and the file system format is
 * different.
 */

#include "uniflex_dsk.h"
#include "formats/imageutl.h"

uniflex_format::uniflex_format() : wd177x_format(formats)
{
}

const char *uniflex_format::name() const
{
	return "uniflex";
}

const char *uniflex_format::description() const
{
	return "UniFLEX compatible disk image";
}

const char *uniflex_format::extensions() const
{
	return "dsk";
}

int uniflex_format::identify(io_generic *io, uint32_t form_factor)
{
	int type = find_size(io, form_factor);

	if (type != -1)
		return 75;
	return 0;
}

int uniflex_format::find_size(io_generic *io, uint32_t form_factor)
{
	uint64_t size = io_generic_size(io);
	uint8_t sir[192];

	// Look at the SIR sector, the second sector.
	io_generic_read(io, sir, 1 * 512, sizeof(sir));

	uint16_t fdn_block_count = pick_integer_be(sir, 0x10, 2);
	uint32_t last_block_number = pick_integer_be(sir, 0x12, 3);
	uint32_t free_block_count = pick_integer_be(sir, 0x15, 3);
	uint16_t fdn_free_count = pick_integer_be(sir, 0x15, 2);

	uint16_t volume_number = pick_integer_be(sir, 0x36, 2);
	uint8_t disk_density = sir[0x3a];
	uint8_t disk_side_info = sir[0x3b];

	uint32_t volbc_start_addr = pick_integer_be(sir, 0x3c, 3);
	uint16_t swap_size = pick_integer_be(sir, 0x3f, 2);

	LOG_FORMATS("UniFLEX floppy dsk size %d\n", (uint32_t)size);
	LOG_FORMATS(" time = %u %u\n", (uint32_t) pick_integer_be(sir, 0x08, 4), (uint32_t) pick_integer_be(sir, 0x0c, 4));
	LOG_FORMATS(" fdn_block_count: %d\n", fdn_block_count);

	LOG_FORMATS(" file system name: ");
	for (int i = 0; i < 14; i++)
		LOG_FORMATS(" %02x", sir[0x1a + i]);
	LOG_FORMATS("\n");

	LOG_FORMATS(" volume name: ");
	for (int i = 0; i < 14; i++)
		LOG_FORMATS(" %02x", sir[0x28 + i]);
	LOG_FORMATS("\n");

	LOG_FORMATS(" last_block_number: %d\n", last_block_number);
	LOG_FORMATS(" free_block_count: %d\n", free_block_count);
	LOG_FORMATS(" fdn_free_count: %d\n", fdn_free_count);
	LOG_FORMATS(" volume_number: %d\n", volume_number);
	LOG_FORMATS(" disk density: %02x, side info %02x\n", disk_density, disk_side_info);
	LOG_FORMATS(" volbc_start_addr: %d\n", volbc_start_addr);
	LOG_FORMATS(" swap_size: %d\n", swap_size);

	// The first eight bytes appear to be zeros.
	if (pick_integer_be(sir, 0x00, 8) != 0)
		return -1;

	for(int i=0; formats[i].form_factor; i++) {
		const format &f = formats[i];
		if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor)
			continue;

		if(size != (uint64_t)compute_track_size(f) * f.track_count * f.head_count)
			continue;

		// Check consistency with the SIR sector.
		if(last_block_number + 1 + swap_size != f.sector_count * f.track_count * f.head_count)
			continue;
		if(f.head_count == 2 && disk_side_info == 0)
			continue;
		if(f.encoding == floppy_image::MFM && disk_density == 0)
			continue;
		if(f.encoding == floppy_image::FM && disk_density != 0)
			continue;

		return i;
	}
	return -1;
}

// UniFLEX numbers sectors on the second side of a track continuing from the
// first side which is a variation not handled by the generic code.
void uniflex_format::build_sector_description(const format &f, uint8_t *sectdata, desc_s *sectors, int track, int head) const
{
	if(f.sector_base_id == -1) {
		for(int i=0; i<f.sector_count; i++) {
			int cur_offset = 0;
			for(int j=0; j<f.sector_count; j++)
				if(f.per_sector_id[j] < f.per_sector_id[i])
					cur_offset += f.sector_base_size ? f.sector_base_size : f.per_sector_size[j];
			sectors[i].data = sectdata + cur_offset;
			sectors[i].size = f.sector_base_size ? f.sector_base_size : f.per_sector_size[i];
			sectors[i].sector_id = f.sector_count * head + f.per_sector_id[i];
		}
	} else {
		int cur_offset = 0;
		for(int i=0; i<f.sector_count; i++) {
			sectors[i].data = sectdata + cur_offset;
			sectors[i].size = f.sector_base_size ? f.sector_base_size : f.per_sector_size[i];
			cur_offset += sectors[i].size;
			sectors[i].sector_id = f.sector_count * head + i + f.sector_base_id;
		}
	}
}

const uniflex_format::format uniflex_format::formats[] = {
	{ // 616K 8 inch double density - gaps unverified
		floppy_image::FF_8, floppy_image::SSDD, floppy_image::MFM,
		1000, 16, 77, 1, 512, {}, 1, {}, 32, 22, 50
	},
	{ // 1232K 8 inch double density - gaps unverified
		floppy_image::FF_8, floppy_image::DSDD, floppy_image::MFM,
		1000, 16, 77, 2, 512, {}, 1, {}, 32, 22, 50
	},

	{}
};

const floppy_format_type FLOPPY_UNIFLEX_FORMAT = &floppy_image_format_creator<uniflex_format>;