summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/ami_dsk.c
blob: 127c2c1c3483635fbfc4db436405853b79a802bd (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
/*********************************************************************

    formats/ami_dsk.c

    Amiga disk images

*********************************************************************/

#include "formats/ami_dsk.h"

adf_format::adf_format() : floppy_image_format_t()
{
}

const char *adf_format::name() const
{
	return "adf";
}

const char *adf_format::description() const
{
	return "Amiga ADF floppy disk image";
}

const char *adf_format::extensions() const
{
	return "adf";
}

bool adf_format::supports_save() const
{
	return true;
}

int adf_format::identify(io_generic *io)
{
	UINT64 size = io_generic_size(io);
	if ((size == 901120) || (size == 1802240))
	{
		return 50;
	}
	return 0;
}

bool adf_format::load(io_generic *io, floppy_image *image)
{
	desc_s sectors[11];
	UINT8 sectdata[512*11];
	for(int i=0; i<11; i++) {
		sectors[i].data = sectdata + 512*i;
		sectors[i].size = 512;
		sectors[i].sector_id = i;
	}

	for(int track=0; track < 80; track++) {
		for(int side=0; side < 2; side++) {
			io_generic_read(io, sectdata, (track*2 + side)*512*11, 512*11);
			generate_track(amiga_11, track, side, sectors, 11, 100000, image);
		}
	}

	return true;
}

UINT32 adf_format::g32(const UINT8 *trackbuf, int track_size, int pos)
{
	if(pos >= 0 && track_size-pos >= 40) {
		int pp = pos >> 3;
		int dp = pos & 7;
		return
			(trackbuf[pp] << (24+dp)) |
			(trackbuf[pp+1] << (16+dp)) |
			(trackbuf[pp+2] << (8+dp)) |
			(trackbuf[pp+3] << dp) |
			(trackbuf[pp+4] >> (8-dp));
	} else {
		UINT32 res = 0;
		for(int i=0; i<32; i++) {
			int pp = (pos+i) % track_size;
			if(trackbuf[pp>>3] & (0x80 >> (pp & 7)))
				res |= 0x80000000 >> i;
		}
		return res;
	}
}

UINT32 adf_format::checksum(const UINT8 *trackbuf, int track_size, int pos, int long_count)
{
	UINT32 check = 0;
	for(int i=0; i<long_count; i++)
		check ^= g32(trackbuf, track_size, pos+32*i);
	return check & 0x55555555;
}

bool adf_format::save(io_generic *io, floppy_image *image)
{
	// TODO: HD support
	UINT8 sectdata[512*11];
	UINT8 trackbuf[150000/8];
	for(int track=0; track < 80; track++) {
		for(int side=0; side < 2; side++) {
			int track_size;
			generate_bitstream_from_track(track, side, 2000, trackbuf, track_size, image);

			for(int i=0; i<track_size; i++)
				if(g32(trackbuf, track_size, i) == 0x44894489 &&
				   (g32(trackbuf, track_size, i+384) & 0x55555555) == checksum(trackbuf, track_size, i+32, 10) &&
				   (g32(trackbuf, track_size, i+448) & 0x55555555) == checksum(trackbuf, track_size, i+480, 256)) {

					UINT32 head = ((g32(trackbuf, track_size, i+32) & 0x55555555) << 1) | (g32(trackbuf, track_size, i+64) & 0x55555555);
					int sect = (head >> 8) & 0xff;
					if(sect > 11)
						continue;

					UINT8 *dest = sectdata + 512*sect;
					for(int j=0; j<128; j++) {
						UINT32 val = ((g32(trackbuf, track_size, i+480+32*j) & 0x55555555) << 1) | (g32(trackbuf, track_size, i+4576+32*j) & 0x55555555);
						*dest++ = val >> 24;
						*dest++ = val >> 16;
						*dest++ = val >> 8;
						*dest++ = val;
					}

					io_generic_write(io, sectdata, (track*2 + side)*512*11, 512*11);
				}
		}
	}
	return true;
}

const floppy_format_type FLOPPY_ADF_FORMAT = &floppy_image_format_creator<adf_format>;