Subversion Repositories pentevo

Rev

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
}