OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [atadevice.c] - Blame information for rev 60

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 19 jeremybenn
/* atadevice.c -- ATA Device simulation. Simulates a harddisk, using a local
2
   streams.
3
 
4
   Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
5
   Copyright (C) 2008 Embecosm Limited
6
 
7
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8
 
9
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
10
 
11
   This program is free software; you can redistribute it and/or modify it
12
   under the terms of the GNU General Public License as published by the Free
13
   Software Foundation; either version 3 of the License, or (at your option)
14
   any later version.
15
 
16
   This program is distributed in the hope that it will be useful, but WITHOUT
17
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19
   more details.
20
 
21
   You should have received a copy of the GNU General Public License along
22
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
23
 
24
/* This program is commented throughout in a fashion suitable for processing
25
   with Doxygen. */
26
 
27
 
28
/* Autoconf and/or portability configuration */
29
#include "config.h"
30
#include "port.h"
31
 
32
/* System includes */
33 60 jeremybenn
#ifdef __APPLE__
34
#include <libkern/OSByteOrder.h>
35
#define bswap_16(x) OSSwapInt16(x)
36
#define bswap_32(x) OSSwapInt32(x)
37
#define bswap_64(x) OSSwapInt64(x)
38
#else
39 19 jeremybenn
#include <byteswap.h>
40 60 jeremybenn
#endif
41 19 jeremybenn
 
42
/* Package includes */
43
#include "atadevice.h"
44
#include "atadevice-cmdi.h"
45
#include "atacmd.h"
46
#include "abstract.h"
47
 
48
 
49
/*
50
 mandatory commands:
51
 - execute device diagnostics       (done)
52
 - flush cache
53
 - identify device                  (done)
54
 - initialize device parameters     (done)
55
 - read dma
56
 - read multiple
57
 - read sector(s)                   (done)
58
 - read verify sector(s)
59
 - seek
60
 - set features
61
 - set multiple mode
62
 - write dma
63
 - write multiple
64
 - write sector(s)
65
 
66
 
67
 optional commands:
68
 - download microcode
69
 - nop
70
 - read buffer
71
 - write buffer
72
 
73
 
74
 prohibited commands:
75
 - device reset
76
*/
77
 
78
 
79
/* Use a file to simulate a hard-disk                                 */
80
static FILE *
81
open_file (uint32_t * size, const char *filename)
82
{
83
  FILE *fp;
84
  unsigned long n;
85
 
86
  // TODO:
87
 
88
  /* check if a file with name 'filename' already exists             */
89
  if (!(fp = fopen (filename, "rb+")))
90
    if (!(fp = fopen (filename, "wb+")))
91
      {
92
        fprintf (stderr, "Warning: ata_open_file, cannot open hd-file %s\n",
93
                 filename);
94
        return NULL;
95
      }
96
    else
97
      {
98
        /* TODO create a file 'size' large */
99
        /* create a file 'size' large                                  */
100
        for (n = 0; n < *size; n++)
101
          fputc (0, fp);
102
      }
103
  else                          /* file already exist                                         */
104
    fprintf (stderr, "file %s already exists. Using existing file.\n",
105
             filename);
106
 
107
  /* get the size of the file. This is also the size of the harddisk */
108
  fseek (fp, 0, SEEK_END);
109
  *size = ftell (fp);
110
 
111
  return fp;
112
}
113
 
114
 
115
/* Use a the local filesystem as a hard-disk                          */
116
static FILE *
117
open_local (void)
118
{
119
  // TODO:
120
  fprintf (stderr, "Warning: Device type LOCAL is not yet supported: "
121
           "Defaulting to device type NO_CONNECT.");
122
  return NULL;
123
}
124
 
125
static void
126
ata_device_init (struct ata_device * device, int dev)
127
{
128
  /* set DeviceID                                                     */
129
  device->internals.dev = dev;
130
 
131
  /* generate stream for hd_simulation                                */
132
  switch (device->conf.type)
133
    {
134
    case TYPE_NO_CONNECT:
135
      device->conf.stream = NULL;
136
      break;
137
 
138
    case TYPE_FILE:
139
      device->conf.stream = open_file (&device->conf.size, device->conf.file);
140
      break;
141
 
142
    case TYPE_LOCAL:
143
      device->conf.stream = open_local ();
144
      break;
145
 
146
    default:
147
      fprintf (stderr, "Warning: Illegal device-type %d: "
148
               "Defaulting to type NO_CONNECT.\n", device->conf.type);
149
      device->conf.stream = NULL;
150
      break;
151
    }
152
 
153
  device->conf.size_sect = device->conf.size / BYTES_PER_SECTOR;
154
}
155
 
156
/*
157
  D E V I C E S _ I N I T
158
*/
159
void
160
ata_devices_init (struct ata_devices * devices)
161
{
162
  ata_device_init (&devices->device[0], 0);
163
 
164
  if (devices->device[0].conf.type)
165
    ata_device_init (&devices->device[1], ATA_DHR_DEV);
166
  else
167
    ata_device_init (&devices->device[1], 0);
168
}
169
 
170
/*
171
  D E V I C E S _ H W _ R E S E T
172
*/
173
static void
174
ata_device_hw_reset (struct ata_device * device, int reset_signal,
175
                     int daspo, int pdiagi, int daspi)
176
{
177
  /* check ata-device state                                         */
178
  if (device->internals.state == ATA_STATE_HW_RST)
179
    {
180
      if (!reset_signal)
181
        {
182
          /* hardware reset finished                                    */
183
 
184
          /* set sectors_per_track & heads_per_cylinders                */
185
          device->internals.sectors_per_track = device->conf.sectors;
186
          device->internals.heads_per_cylinder = device->conf.heads;
187
 
188
          /* set device1 input signals                                  */
189
          device->sigs.pdiagi = pdiagi;
190
          device->sigs.daspi = daspi;
191
 
192
          ata_execute_device_diagnostics_cmd (device);
193
 
194
          /* clear busy bit                                             */
195
          device->regs.status &= ~ATA_SR_BSY;
196
 
197
          /* set DRDY bit, when not a PACKET device                     */
198
          if (!device->conf.packet)
199
            device->regs.status |= ATA_SR_DRDY;
200
 
201
          /* set new state                                              */
202
          device->internals.state = ATA_STATE_IDLE;
203
        }
204
    }
205
  else if (reset_signal)
206
    {
207
      /* hardware reset signal asserted, stop what we are doing     */
208
 
209
      /* negate bus signals                                         */
210
      device->sigs.iordy = 0;
211
      device->sigs.intrq = 0;
212
      device->sigs.dmarq = 0;
213
      device->sigs.pdiago = 0;
214
      device->sigs.daspo = daspo;
215
 
216
      /* set busy bit                                               */
217
      device->regs.status |= ATA_SR_BSY;
218
 
219
      /* set new state                                              */
220
      device->internals.state = ATA_STATE_HW_RST;
221
    }
222
}
223
 
224
/* power-on and hardware reset                                        */
225
void
226
ata_devices_hw_reset (struct ata_devices * devices, int reset_signal)
227
{
228
  /* find device 0                                                    */
229
  if ((devices->device[0].conf.stream) && (devices->device[1].conf.stream))
230
    {
231
      /* this one is simple, device0 is device0                         */
232
 
233
      /* 1) handle device1 first                                        */
234
      ata_device_hw_reset (&devices->device[1], reset_signal, 1,        /* assert dasp, this is device1          */
235
                           0,    /* negate pdiag input, no more devices   */
236
                           0);   /* negate dasp input, no more devices    */
237
 
238
      /* 2) Then handle device0                                         */
239
      ata_device_hw_reset (&devices->device[0], reset_signal,
240
                           0,
241
                           devices->device[1].sigs.pdiago,
242
                           devices->device[1].sigs.daspo);
243
    }
244
  else if (devices->device[0].conf.stream)
245
    {
246
      /* device0 is device0, there's no device1                         */
247
      ata_device_hw_reset (&devices->device[0], reset_signal, 0,  /* negate dasp, this is device0          */
248
                           0,    /* negate pdiag input, there's no device1 */
249
                           0);   /* negate dasp input, there's no device1 */
250
    }
251
  else if (devices->device[1].conf.stream)
252
    {
253
      /* device1 is (logical) device0, there's no (physical) device0    */
254
      ata_device_hw_reset (&devices->device[1], reset_signal, 0, /* negate dasp, this is device0          */
255
                           0,    /* negate pdiag input, there's no device1 */
256
                           0);   /* negate dasp input, there's no device1 */
257
    }
258
}
259
 
260
 
261
/*
262
  D E V I C E S _ D O _ C O N T R O L _ R E G I S T E R
263
 
264
  Handles - software reset
265
          - Interrupt enable bit
266
*/
267
static void
268
ata_device_do_control_register (struct ata_device * device)
269
{
270
  /* TODO respond to new values of nIEN */
271
  /* if device not selected, respond to new values of nIEN & SRST */
272
 
273
  /* check if SRST bit is set                                         */
274
  if (device->regs.device_control & ATA_DCR_RST)
275
    {
276
      if (device->internals.state == ATA_STATE_IDLE)
277
        {                       /* start software reset                                       */
278
          /* negate bus signals                                         */
279
          device->sigs.pdiago = 0;
280
          device->sigs.intrq = 0;
281
          device->sigs.iordy = 0;
282
          device->sigs.dmarq = 0;
283
 
284
          /* set busy bit                                               */
285
          device->regs.status |= ATA_SR_BSY;
286
 
287
          /* set new state                                              */
288
          device->internals.state = ATA_STATE_SW_RST;
289
        }
290
    }
291
  else if (device->internals.state == ATA_STATE_SW_RST)
292
    {                           /* are we doing a software reset ??                             */
293
      /* SRST bit cleared, end of software reset                      */
294
 
295
      /*execute device diagnostics                                    */
296
      ata_execute_device_diagnostics_cmd (device);
297
 
298
      /* clear busy bit                                               */
299
      device->regs.status &= ~ATA_SR_BSY;
300
 
301
      /* set DRDY bit, when not a PACKET device                       */
302
      if (!device->conf.packet)
303
        device->regs.status |= ATA_SR_DRDY;
304
 
305
      /* set new state                                                */
306
      device->internals.state = ATA_STATE_IDLE;
307
    }
308
  /*
309
     <else> We are doing a hardware reset (or similar)
310
     ignore command
311
   */
312
}
313
 
314
 
315
/*
316
  D E V I C E S _ D O _ C O M M A N D _ R E G I S T E R
317
*/
318
static void
319
ata_device_do_command_register (struct ata_device * device)
320
{
321
  /* check BSY & DRQ                                                  */
322
  if ((device->regs.status & ATA_SR_BSY)
323
      || (device->regs.status & ATA_SR_DRQ))
324
    {
325
      if (device->regs.command != DEVICE_RESET)
326
        {
327
          fprintf (stderr, "Warning: ata_device_write, writing a command "
328
                   "while BSY or DRQ asserted.\n");
329
        }
330
    }
331
 
332
  /* check if device selected                                         */
333
  if ((device->regs.device_head & ATA_DHR_DEV) == device->internals.dev)
334
    ata_device_execute_cmd (device);
335
  else
336
    {
337
      /* if not selected, only respond to EXECUTE DEVICE DIAGNOSTICS  */
338
      if (device->regs.command == EXECUTE_DEVICE_DIAGNOSTICS)
339
        ata_device_execute_cmd (device);
340
    }
341
}
342
 
343
 
344
/*
345
  D E V I C E S _ R E A D
346
*/
347
/* Read from devices                                                  */
348
short
349
ata_devices_read (struct ata_devices * devices, char adr)
350
{
351
  struct ata_device *device;
352
 
353
  /* check for no connected devices                                 */
354
  if ((!devices->device[0].conf.stream) && (!devices->device[1].conf.stream))
355
    {
356
      fprintf (stderr, "Warning: ata_devices_read, no ata devices "
357
               "connected.\n");
358
    }
359
  else
360
    {
361
      /* check if both device0 and device1 are connected              */
362
      if ((devices->device[0].conf.stream)
363
          && (devices->device[1].conf.stream))
364
        {
365
          /* get the current active device                            */
366
          if (devices->device[1].regs.device_head & ATA_DHR_DEV)
367
            device = &devices->device[1];
368
          else
369
            device = &devices->device[0];
370
        }
371
      else
372
        {
373
          /* only one device connected                                */
374
          if (devices->device[1].conf.stream)
375
            device = &devices->device[1];
376
          else
377
            device = &devices->device[0];
378
        }
379
 
380
      /* return data provided by selected device                      */
381
      switch (adr)
382
        {
383
        case ATA_ASR:
384
          if ((device->regs.device_head & ATA_DHR_DEV) ==
385
              device->internals.dev)
386
            return device->regs.status;
387
          else
388
            {
389
              return 0;          // return 0 when device0 responds for device1
390
            }
391
 
392
        case ATA_CHR:
393
          return device->regs.cylinder_high;
394
 
395
        case ATA_CLR:
396
          return device->regs.cylinder_low;
397
 
398
        case ATA_DR:
399
          if (!device->regs.status & ATA_SR_DRQ)
400
            {
401
              return 0;
402
            }
403
          else
404
            {
405
              uint16_t val = LE16 (*device->internals.dbuf_ptr++);
406
              if (!--device->internals.dbuf_cnt)
407
                {
408
                  device->regs.status &= ~ATA_SR_DRQ;
409
                  if (device->internals.end_t_func)
410
                    device->internals.end_t_func (device);
411
                }
412
              return val;
413
            }
414
 
415
        case ATA_DHR:
416
          return device->regs.device_head;
417
 
418
        case ATA_ERR:
419
          return device->regs.error;
420
 
421
        case ATA_SCR:
422
          return device->regs.sector_count;
423
 
424
        case ATA_SNR:
425
          return device->regs.sector_number;
426
 
427
        case ATA_SR:
428
          if ((device->regs.device_head & ATA_DHR_DEV) ==
429
              device->internals.dev)
430
            {
431
              device->sigs.intrq = 0;
432
              return device->regs.status;
433
            }
434
 
435
          return 0;              // return 0 when device0 responds for device1
436
 
437
//        case ATA_DA   :
438
//          return device -> regs.status;
439
        }
440
    }
441
  return 0;
442
}
443
 
444
 
445
/*
446
  D E V I C E S _ W R I T E
447
*/
448
/* write to a single device                                           */
449
static void
450
ata_device_write (struct ata_device * device, char adr, short value)
451
{
452
  switch (adr)
453
    {
454
    case ATA_CR:
455
      device->regs.command = value;
456
 
457
      /* check command register settings and execute command    */
458
      ata_device_do_command_register (device);
459
      break;
460
 
461
 
462
    case ATA_CHR:
463
      device->regs.cylinder_high = value;
464
      break;
465
 
466
    case ATA_CLR:
467
      device->regs.cylinder_low = value;
468
      break;
469
 
470
    case ATA_DR:
471
      if (!device->regs.status & ATA_SR_DRQ)
472
        {
473
          break;
474
        }
475
      else
476
        {
477
          *device->internals.dbuf_ptr++ = LE16 (value);
478
          if (!--device->internals.dbuf_cnt)
479
            {
480
              device->regs.status &= ~ATA_SR_DRQ;
481
              if (device->internals.end_t_func)
482
                device->internals.end_t_func (device);
483
            }
484
        }
485
      device->regs.dataport_i = value;
486
      break;
487
 
488
    case ATA_DCR:
489
      device->regs.device_control = value;
490
      ata_device_do_control_register (device);
491
      break;
492
 
493
    case ATA_DHR:
494
      device->regs.device_head = value;
495
      break;
496
 
497
    case ATA_FR:
498
      device->regs.features = value;
499
      break;
500
 
501
    case ATA_SCR:
502
      device->regs.sector_count = value;
503
      break;
504
 
505
    case ATA_SNR:
506
      device->regs.sector_number = value;
507
      break;
508
 
509
    }                           //endcase
510
}
511
 
512
/* Write to devices                                                   */
513
void
514
ata_devices_write (struct ata_devices * devices, char adr, short value)
515
{
516
  /* check for no connected devices                                 */
517
  if (!devices->device[0].conf.stream && !devices->device[1].conf.stream)
518
    {
519
      fprintf (stderr, "Warning: ata_devices_write, no ata devices "
520
               "connected.\n");
521
    }
522
  else
523
    {
524
      /* first device                                                 */
525
      if (devices->device[0].conf.stream)
526
        ata_device_write (&devices->device[0], adr, value);
527
 
528
      /* second device                                                */
529
      if (devices->device[1].conf.stream)
530
        ata_device_write (&devices->device[1], adr, value);
531
    }
532
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.