Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
716 | lvd | 1 | #include "std.h" |
2 | |||
3 | #include "emul.h" |
||
4 | #include "vars.h" |
||
5 | |||
6 | #include "util.h" |
||
7 | |||
8 | enum TDiskType |
||
9 | { |
||
10 | DS_80 = 0x16, |
||
11 | DS_40 = 0x17, |
||
12 | SS_80 = 0x18, |
||
13 | SS_40 = 0x19 |
||
14 | }; |
||
15 | |||
16 | enum { TRD_SIG = 0x10 }; |
||
17 | |||
18 | #pragma pack(push, 1) |
||
19 | struct TTrdDirEntryBase |
||
20 | { |
||
21 | char Name[8]; |
||
22 | u8 Type; |
||
23 | u16 Start; |
||
24 | u16 Length; |
||
25 | u8 SecCnt; // Длина файла в секторах |
||
26 | }; |
||
27 | |||
28 | struct TTrdDirEntry : public TTrdDirEntryBase |
||
29 | { |
||
30 | u8 Sec; // Начальный сектор |
||
31 | u8 Trk; // Начальная дорожка |
||
32 | }; |
||
33 | |||
34 | struct TTrdSec9 |
||
35 | { |
||
36 | u8 Zero; // 00 |
||
37 | u8 Reserved[224]; |
||
38 | u8 FirstFreeSec; // E1 |
||
39 | u8 FirstFreeTrk; // E2 |
||
40 | u8 DiskType; // E3 |
||
41 | u8 FileCnt; // E4 |
||
42 | u16 FreeSecCnt; // E5, E6 |
||
43 | u8 TrDosSig; // E7 |
||
44 | u8 Res1[2]; // | 0 |
||
45 | u8 Res2[9]; // | 32 |
||
46 | u8 Res3; // | 0 |
||
47 | u8 DelFileCnt; // F4 |
||
48 | char Label[8]; // F5-FC |
||
49 | u8 Res4[3]; // | 0 |
||
50 | }; |
||
51 | |||
52 | struct TSclHdr |
||
53 | { |
||
54 | u8 Sig[8]; // SINCLAIR |
||
55 | u8 FileCnt; |
||
56 | #pragma warning(push) |
||
57 | #pragma warning(disable: 4200) |
||
58 | TTrdDirEntryBase Files[]; |
||
59 | #pragma warning(pop) |
||
60 | }; |
||
61 | #pragma pack(pop) |
||
62 | |||
63 | void FDD::format_trd(unsigned CylCnt) |
||
64 | { |
||
65 | static const unsigned char lv[3][16] = |
||
66 | { { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }, |
||
67 | { 1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16 }, |
||
68 | { 1,12,7,2,13,8,3,14,9,4,15,10,5,16,11,6 } }; |
||
69 | |||
70 | newdisk(CylCnt, 2); |
||
71 | |||
72 | for (unsigned c = 0; c < cyls; c++) { |
||
73 | for (unsigned side = 0; side < 2; side++) { |
||
74 | t.seek(this, c, side, JUST_SEEK); t.s = 16; |
||
75 | for (unsigned sn = 0; sn < 16; sn++) { |
||
76 | unsigned s = lv[conf.trdos_interleave][sn]; |
||
77 | t.hdr[sn].n = s, t.hdr[sn].l = 1; |
||
78 | t.hdr[sn].c = c, t.hdr[sn].s = 0; |
||
79 | t.hdr[sn].c1 = t.hdr[sn].c2 = 0; |
||
80 | t.hdr[sn].data = (unsigned char*)1; |
||
81 | } |
||
82 | t.format(); |
||
83 | } |
||
84 | } |
||
85 | } |
||
86 | |||
87 | void FDD::emptydisk(unsigned FreeSecCnt) |
||
88 | { |
||
89 | unsigned SecCnt = FreeSecCnt + 16; |
||
90 | unsigned CylCnt = SecCnt / (16 * 2) + ((SecCnt % (16 * 2)) ? 1 : 0); |
||
91 | format_trd(CylCnt); |
||
92 | t.seek(this, 0, 0, LOAD_SECTORS); |
||
93 | const SECHDR *Sec9Hdr = t.get_sector(9); |
||
94 | if(!Sec9Hdr) |
||
95 | return; |
||
96 | |||
97 | TTrdSec9 *Sec9 = (TTrdSec9 *)Sec9Hdr->data; |
||
98 | Sec9->FirstFreeTrk = 1; // first free track |
||
99 | Sec9->DiskType = DS_80; // 80T,DS |
||
100 | Sec9->FreeSecCnt = FreeSecCnt; // free sec |
||
101 | Sec9->TrDosSig = TRD_SIG; // trdos flag |
||
102 | memset(Sec9->Label, ' ', 8); // label |
||
103 | memset(Sec9->Res2, ' ', 9); // reserved |
||
104 | t.write_sector(9, Sec9Hdr->data); // update sector CRC |
||
105 | } |
||
106 | |||
107 | int FDD::addfile(unsigned char *hdr, unsigned char *data) |
||
108 | { |
||
109 | t.seek(this, 0, 0, LOAD_SECTORS); |
||
110 | const SECHDR *Sec9Hdr = t.get_sector(9); |
||
111 | if (!Sec9Hdr) |
||
112 | return 0; |
||
113 | |||
114 | TTrdSec9 *Sec9 = (TTrdSec9 *)Sec9Hdr->data; |
||
115 | if(!Sec9) |
||
116 | return 0; |
||
117 | |||
118 | if(Sec9->FileCnt >= 128) // Каталог заполнен полностью |
||
119 | return 0; |
||
120 | |||
121 | unsigned len = ((TTrdDirEntry *)hdr)->SecCnt; |
||
122 | unsigned pos = Sec9->FileCnt * sizeof(TTrdDirEntry); |
||
123 | const SECHDR *dir = t.get_sector(1 + pos / 0x100); |
||
124 | |||
125 | if (!dir) |
||
126 | return 0; |
||
127 | |||
128 | if (Sec9->FreeSecCnt < len) |
||
129 | return 0; // На диске нет места |
||
130 | |||
131 | TTrdDirEntry *TrdDirEntry = (TTrdDirEntry *)(dir->data + (pos & 0xFF)); |
||
132 | memcpy(TrdDirEntry, hdr, 14); |
||
133 | TrdDirEntry->Sec = Sec9->FirstFreeSec; |
||
134 | TrdDirEntry->Trk = Sec9->FirstFreeTrk; |
||
135 | t.write_sector(1 + pos / 0x100, dir->data); |
||
136 | |||
137 | pos = Sec9->FirstFreeSec + 16*Sec9->FirstFreeTrk; |
||
138 | Sec9->FirstFreeSec = (pos+len) & 0x0F; |
||
139 | Sec9->FirstFreeTrk = (pos+len) >> 4; |
||
140 | Sec9->FileCnt++; |
||
141 | Sec9->FreeSecCnt -= len; |
||
142 | t.write_sector(9, Sec9Hdr->data); |
||
143 | |||
144 | // goto next track. s8 become invalid |
||
145 | for (unsigned i = 0; i < len; i++, pos++) |
||
146 | { |
||
147 | t.seek(this, pos/32, (pos/16) & 1, LOAD_SECTORS); |
||
148 | if (!t.trkd) |
||
149 | return 0; |
||
150 | if (!t.write_sector((pos & 0x0F) + 1, data + i * 0x100)) |
||
151 | return 0; |
||
152 | } |
||
153 | return 1; |
||
154 | } |
||
155 | |||
156 | static bool FillCheck(const void *buf, char fill, size_t size) |
||
157 | { |
||
158 | const char *p = (const char *)buf; |
||
159 | while(size--) |
||
160 | { |
||
161 | if(*p++ != fill) |
||
162 | return false; |
||
163 | } |
||
164 | return true; |
||
165 | } |
||
166 | |||
167 | // destroys snbuf - use after loading all files |
||
168 | void FDD::addboot() |
||
169 | { |
||
170 | t.seek(this, 0, 0, LOAD_SECTORS); |
||
171 | |||
172 | // Проверка на то что диск имеет tr-dos формат |
||
173 | const SECHDR *Hdr = t.get_sector(9); |
||
174 | if(!Hdr) |
||
175 | return; |
||
176 | |||
177 | if((Hdr->l & 3) != 1) // Проверка кода размера сектора (1 - 256 байт) |
||
178 | return; |
||
179 | |||
180 | const TTrdSec9 *Sec9 = (const TTrdSec9 *)Hdr->data; |
||
181 | if(!Sec9) |
||
182 | return; |
||
183 | |||
184 | if(Sec9->Zero != 0) |
||
185 | return; |
||
186 | |||
187 | if(Sec9->TrDosSig != TRD_SIG) |
||
188 | return; |
||
189 | |||
190 | if(!(FillCheck(Sec9->Res2, ' ', 9) || FillCheck(Sec9->Res2, 0, 9))) |
||
191 | return; |
||
192 | |||
193 | if(!(Sec9->DiskType == DS_80 || Sec9->DiskType == DS_40 || |
||
194 | Sec9->DiskType == SS_80 || Sec9->DiskType == SS_40)) |
||
195 | return; |
||
196 | |||
197 | for (unsigned s = 0; s < 8; s++) |
||
198 | { |
||
199 | const SECHDR *sc = t.get_sector(1 + s); |
||
200 | if (!sc) |
||
201 | return; |
||
202 | TTrdDirEntry *TrdDirEntry = (TTrdDirEntry *)sc->data; |
||
203 | for (unsigned i = 0; i < 16; i++) |
||
204 | { |
||
205 | if (memcmp(TrdDirEntry[i].Name, "boot B", 9) == 0) |
||
206 | return; |
||
207 | } |
||
208 | } |
||
209 | |||
210 | FILE *f = fopen(conf.appendboot, "rb"); |
||
211 | if (!f) |
||
212 | return; |
||
213 | fread(snbuf, 1, sizeof snbuf, f); |
||
214 | fclose(f); |
||
215 | snbuf[13] = snbuf[14]; // copy length |
||
216 | addfile(snbuf, snbuf+0x11); |
||
217 | } |
||
218 | |||
219 | int FDD::read_scl() |
||
220 | { |
||
221 | unsigned size = 0, i; |
||
222 | TSclHdr *SclHdr = (TSclHdr *)snbuf; |
||
223 | for (i = 0; i < SclHdr->FileCnt; i++) |
||
224 | size += SclHdr->Files[i].SecCnt; |
||
225 | |||
226 | emptydisk(max(size, 2544U)); |
||
227 | |||
228 | unsigned char *data = snbuf + sizeof(TSclHdr) + SclHdr->FileCnt * sizeof(TTrdDirEntryBase); |
||
229 | for (i = 0; i < SclHdr->FileCnt; i++) |
||
230 | { |
||
231 | if (!addfile((u8 *)&SclHdr->Files[i], data)) |
||
232 | return 0; |
||
233 | data += SclHdr->Files[i].SecCnt * 0x100; |
||
234 | } |
||
235 | |||
236 | return 1; |
||
237 | } |
||
238 | |||
239 | int FDD::read_hob() |
||
240 | { |
||
241 | if(!rawdata) |
||
242 | { |
||
243 | emptydisk(2544); |
||
244 | } |
||
245 | snbuf[13] = snbuf[14]; |
||
246 | int r = addfile(snbuf, snbuf+0x11); |
||
247 | return r; |
||
248 | } |
||
249 | |||
250 | int FDD::read_trd() |
||
251 | { |
||
252 | unsigned CylCnt = snapsize / (256 * 16 * 2) + ((snapsize % (256 * 16 * 2)) ? 1 : 0); |
||
253 | |||
254 | if(CylCnt > MAX_CYLS) |
||
255 | { |
||
256 | err_printf("cylinders (%u) > MAX_CYLS(%d)", CylCnt, MAX_CYLS); |
||
257 | return 0; |
||
258 | } |
||
259 | |||
260 | format_trd(CylCnt); |
||
261 | |||
262 | for (unsigned i = 0; i < snapsize; i += 0x100) |
||
263 | { |
||
264 | t.seek(this, i>>13, (i>>12) & 1, LOAD_SECTORS); |
||
265 | t.write_sector(((i>>8) & 0x0F)+1, snbuf+i); |
||
266 | } |
||
267 | return 1; |
||
268 | } |
||
269 | |||
270 | int FDD::write_trd(FILE *ff) |
||
271 | { |
||
272 | static unsigned char zerosec[256] = { 0 }; |
||
273 | |||
274 | for (unsigned i = 0; i < cyls * sides * 16; i++) |
||
275 | { |
||
276 | t.seek(this, i>>5, (i>>4) & 1, LOAD_SECTORS); |
||
277 | const SECHDR *hdr = t.get_sector((i & 0x0F)+1); |
||
278 | unsigned char *ptr = zerosec; |
||
279 | if (hdr && hdr->data) |
||
280 | ptr = hdr->data; |
||
281 | if (fwrite(ptr, 1, 256, ff) != 256) |
||
282 | return 0; |
||
283 | } |
||
284 | return 1; |
||
285 | } |