Rev 798 | Details | Compare with Previous | 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]; |
||
796 | DimkaM | 77 | t.hdr[sn].n = u8(s); t.hdr[sn].l = 1; |
78 | t.hdr[sn].c = u8(c); t.hdr[sn].s = 0; |
||
716 | lvd | 79 | t.hdr[sn].c1 = t.hdr[sn].c2 = 0; |
80 | t.hdr[sn].data = (unsigned char*)1; |
||
800 | DimkaM | 81 | t.hdr[sn].datlen = 0; |
716 | lvd | 82 | } |
83 | t.format(); |
||
84 | } |
||
85 | } |
||
86 | } |
||
87 | |||
88 | void FDD::emptydisk(unsigned FreeSecCnt) |
||
89 | { |
||
90 | unsigned SecCnt = FreeSecCnt + 16; |
||
91 | unsigned CylCnt = SecCnt / (16 * 2) + ((SecCnt % (16 * 2)) ? 1 : 0); |
||
92 | format_trd(CylCnt); |
||
93 | t.seek(this, 0, 0, LOAD_SECTORS); |
||
800 | DimkaM | 94 | const SECHDR *Sec9Hdr = t.get_sector(9, 1); |
716 | lvd | 95 | if(!Sec9Hdr) |
96 | return; |
||
97 | |||
98 | TTrdSec9 *Sec9 = (TTrdSec9 *)Sec9Hdr->data; |
||
99 | Sec9->FirstFreeTrk = 1; // first free track |
||
100 | Sec9->DiskType = DS_80; // 80T,DS |
||
796 | DimkaM | 101 | Sec9->FreeSecCnt = u16(FreeSecCnt); // free sec |
716 | lvd | 102 | Sec9->TrDosSig = TRD_SIG; // trdos flag |
103 | memset(Sec9->Label, ' ', 8); // label |
||
104 | memset(Sec9->Res2, ' ', 9); // reserved |
||
800 | DimkaM | 105 | t.write_sector(9, 1, Sec9Hdr->data); // update sector CRC |
716 | lvd | 106 | } |
107 | |||
108 | int FDD::addfile(unsigned char *hdr, unsigned char *data) |
||
109 | { |
||
110 | t.seek(this, 0, 0, LOAD_SECTORS); |
||
800 | DimkaM | 111 | const SECHDR *Sec9Hdr = t.get_sector(9, 1); |
716 | lvd | 112 | if (!Sec9Hdr) |
113 | return 0; |
||
114 | |||
115 | TTrdSec9 *Sec9 = (TTrdSec9 *)Sec9Hdr->data; |
||
116 | if(!Sec9) |
||
117 | return 0; |
||
118 | |||
119 | if(Sec9->FileCnt >= 128) // ������� �������� ��������� |
||
120 | return 0; |
||
121 | |||
122 | unsigned len = ((TTrdDirEntry *)hdr)->SecCnt; |
||
123 | unsigned pos = Sec9->FileCnt * sizeof(TTrdDirEntry); |
||
800 | DimkaM | 124 | const SECHDR *dir = t.get_sector(1 + pos / 0x100, 1); |
716 | lvd | 125 | |
126 | if (!dir) |
||
127 | return 0; |
||
128 | |||
129 | if (Sec9->FreeSecCnt < len) |
||
130 | return 0; // �� ����� ��� ����� |
||
131 | |||
132 | TTrdDirEntry *TrdDirEntry = (TTrdDirEntry *)(dir->data + (pos & 0xFF)); |
||
133 | memcpy(TrdDirEntry, hdr, 14); |
||
134 | TrdDirEntry->Sec = Sec9->FirstFreeSec; |
||
135 | TrdDirEntry->Trk = Sec9->FirstFreeTrk; |
||
800 | DimkaM | 136 | t.write_sector(1 + pos / 0x100, 1, dir->data); |
716 | lvd | 137 | |
138 | pos = Sec9->FirstFreeSec + 16*Sec9->FirstFreeTrk; |
||
139 | Sec9->FirstFreeSec = (pos+len) & 0x0F; |
||
796 | DimkaM | 140 | Sec9->FirstFreeTrk = u8((pos+len) >> 4); |
716 | lvd | 141 | Sec9->FileCnt++; |
142 | Sec9->FreeSecCnt -= len; |
||
800 | DimkaM | 143 | t.write_sector(9, 1, Sec9Hdr->data); |
716 | lvd | 144 | |
145 | // goto next track. s8 become invalid |
||
146 | for (unsigned i = 0; i < len; i++, pos++) |
||
147 | { |
||
148 | t.seek(this, pos/32, (pos/16) & 1, LOAD_SECTORS); |
||
149 | if (!t.trkd) |
||
150 | return 0; |
||
800 | DimkaM | 151 | if (!t.write_sector((pos & 0x0F) + 1, 1, data + i * 0x100)) |
716 | lvd | 152 | return 0; |
153 | } |
||
154 | return 1; |
||
155 | } |
||
156 | |||
157 | static bool FillCheck(const void *buf, char fill, size_t size) |
||
158 | { |
||
159 | const char *p = (const char *)buf; |
||
160 | while(size--) |
||
161 | { |
||
162 | if(*p++ != fill) |
||
163 | return false; |
||
164 | } |
||
165 | return true; |
||
166 | } |
||
167 | |||
168 | // destroys snbuf - use after loading all files |
||
169 | void FDD::addboot() |
||
170 | { |
||
171 | t.seek(this, 0, 0, LOAD_SECTORS); |
||
172 | |||
173 | // �������� �� �� ��� ���� ����� tr-dos ������ |
||
800 | DimkaM | 174 | const SECHDR *Hdr = t.get_sector(9, 1); |
716 | lvd | 175 | if(!Hdr) |
176 | return; |
||
177 | |||
178 | if((Hdr->l & 3) != 1) // �������� ���� ������� ������� (1 - 256 ����) |
||
179 | return; |
||
180 | |||
181 | const TTrdSec9 *Sec9 = (const TTrdSec9 *)Hdr->data; |
||
182 | if(!Sec9) |
||
183 | return; |
||
184 | |||
185 | if(Sec9->Zero != 0) |
||
186 | return; |
||
187 | |||
188 | if(Sec9->TrDosSig != TRD_SIG) |
||
189 | return; |
||
190 | |||
191 | if(!(FillCheck(Sec9->Res2, ' ', 9) || FillCheck(Sec9->Res2, 0, 9))) |
||
192 | return; |
||
193 | |||
194 | if(!(Sec9->DiskType == DS_80 || Sec9->DiskType == DS_40 || |
||
195 | Sec9->DiskType == SS_80 || Sec9->DiskType == SS_40)) |
||
196 | return; |
||
197 | |||
198 | for (unsigned s = 0; s < 8; s++) |
||
199 | { |
||
800 | DimkaM | 200 | const SECHDR *sc = t.get_sector(1 + s, 1); |
716 | lvd | 201 | if (!sc) |
202 | return; |
||
203 | TTrdDirEntry *TrdDirEntry = (TTrdDirEntry *)sc->data; |
||
204 | for (unsigned i = 0; i < 16; i++) |
||
205 | { |
||
206 | if (memcmp(TrdDirEntry[i].Name, "boot B", 9) == 0) |
||
207 | return; |
||
208 | } |
||
209 | } |
||
210 | |||
211 | FILE *f = fopen(conf.appendboot, "rb"); |
||
212 | if (!f) |
||
213 | return; |
||
214 | fread(snbuf, 1, sizeof snbuf, f); |
||
215 | fclose(f); |
||
216 | snbuf[13] = snbuf[14]; // copy length |
||
217 | addfile(snbuf, snbuf+0x11); |
||
218 | } |
||
219 | |||
220 | int FDD::read_scl() |
||
221 | { |
||
222 | unsigned size = 0, i; |
||
223 | TSclHdr *SclHdr = (TSclHdr *)snbuf; |
||
224 | for (i = 0; i < SclHdr->FileCnt; i++) |
||
225 | size += SclHdr->Files[i].SecCnt; |
||
226 | |||
227 | emptydisk(max(size, 2544U)); |
||
228 | |||
229 | unsigned char *data = snbuf + sizeof(TSclHdr) + SclHdr->FileCnt * sizeof(TTrdDirEntryBase); |
||
230 | for (i = 0; i < SclHdr->FileCnt; i++) |
||
231 | { |
||
232 | if (!addfile((u8 *)&SclHdr->Files[i], data)) |
||
233 | return 0; |
||
234 | data += SclHdr->Files[i].SecCnt * 0x100; |
||
235 | } |
||
236 | |||
237 | return 1; |
||
238 | } |
||
239 | |||
240 | int FDD::read_hob() |
||
241 | { |
||
242 | if(!rawdata) |
||
243 | { |
||
244 | emptydisk(2544); |
||
245 | } |
||
246 | snbuf[13] = snbuf[14]; |
||
247 | int r = addfile(snbuf, snbuf+0x11); |
||
248 | return r; |
||
249 | } |
||
250 | |||
251 | int FDD::read_trd() |
||
252 | { |
||
253 | unsigned CylCnt = snapsize / (256 * 16 * 2) + ((snapsize % (256 * 16 * 2)) ? 1 : 0); |
||
254 | |||
255 | if(CylCnt > MAX_CYLS) |
||
256 | { |
||
257 | err_printf("cylinders (%u) > MAX_CYLS(%d)", CylCnt, MAX_CYLS); |
||
258 | return 0; |
||
259 | } |
||
260 | |||
261 | format_trd(CylCnt); |
||
262 | |||
263 | for (unsigned i = 0; i < snapsize; i += 0x100) |
||
264 | { |
||
265 | t.seek(this, i>>13, (i>>12) & 1, LOAD_SECTORS); |
||
800 | DimkaM | 266 | t.write_sector(((i>>8) & 0x0F)+1, 1, snbuf+i); |
716 | lvd | 267 | } |
268 | return 1; |
||
269 | } |
||
270 | |||
271 | int FDD::write_trd(FILE *ff) |
||
272 | { |
||
273 | static unsigned char zerosec[256] = { 0 }; |
||
274 | |||
275 | for (unsigned i = 0; i < cyls * sides * 16; i++) |
||
276 | { |
||
277 | t.seek(this, i>>5, (i>>4) & 1, LOAD_SECTORS); |
||
800 | DimkaM | 278 | const SECHDR *hdr = t.get_sector((i & 0x0F)+1, 1); |
716 | lvd | 279 | unsigned char *ptr = zerosec; |
280 | if (hdr && hdr->data) |
||
281 | ptr = hdr->data; |
||
282 | if (fwrite(ptr, 1, 256, ff) != 256) |
||
283 | return 0; |
||
284 | } |
||
285 | return 1; |
||
286 | } |