Fix doxgyen comments
[gem5.git] / dev / ide_disk.hh
index 29ddd4be7d7d13aa26def21f68efbac3381b68c4..f9a413e1ea2a011d925f03df75cfffa793645e11 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2004 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef __IDE_DISK_HH__
 #define __IDE_DISK_HH__
 
+#include "dev/disk_image.hh"
+#include "dev/ide_atareg.h"
+#include "dev/ide_wdcreg.h"
 #include "dev/io_device.hh"
+#include "sim/eventq.hh"
 
-class DiskImage;
+#define DMA_BACKOFF_PERIOD 200
+
+#define MAX_DMA_SIZE    (65536)  // 64K
+#define MAX_MULTSECT    (128)
+
+#define PRD_BASE_MASK  0xfffffffe
+#define PRD_COUNT_MASK 0xfffe
+#define PRD_EOT_MASK   0x8000
+
+typedef struct PrdEntry {
+    uint32_t baseAddr;
+    uint16_t byteCount;
+    uint16_t endOfTable;
+} PrdEntry_t;
+
+class PrdTableEntry {
+  public:
+    PrdEntry_t entry;
+
+    uint32_t getBaseAddr()
+    {
+        return (entry.baseAddr & PRD_BASE_MASK);
+    }
+
+    uint32_t getByteCount()
+    {
+        return ((entry.byteCount == 0) ? MAX_DMA_SIZE :
+                (entry.byteCount & PRD_COUNT_MASK));
+    }
+
+    uint16_t getEOT()
+    {
+        return (entry.endOfTable & PRD_EOT_MASK);
+    }
+};
+
+#define DATA_OFFSET     (0)
+#define ERROR_OFFSET    (1)
+#define FEATURES_OFFSET (1)
+#define NSECTOR_OFFSET  (2)
+#define SECTOR_OFFSET   (3)
+#define LCYL_OFFSET     (4)
+#define HCYL_OFFSET     (5)
+#define SELECT_OFFSET   (6)
+#define STATUS_OFFSET   (7)
+#define COMMAND_OFFSET  (7)
+
+#define CONTROL_OFFSET  (2)
+#define ALTSTAT_OFFSET  (2)
+
+#define SELECT_DEV_BIT  0x10
+#define CONTROL_RST_BIT 0x04
+#define CONTROL_IEN_BIT 0x02
+#define STATUS_BSY_BIT  0x80
+#define STATUS_DRDY_BIT 0x40
+#define STATUS_DRQ_BIT  0x08
+#define STATUS_SEEK_BIT 0x10
+#define STATUS_DF_BIT   0x20
+#define DRIVE_LBA_BIT   0x40
+
+#define DEV0 (0)
+#define DEV1 (1)
+
+typedef struct CommandReg {
+    uint8_t data0;
+    union {
+        uint8_t data1;
+        uint8_t error;
+        uint8_t features;
+    };
+    uint8_t sec_count;
+    uint8_t sec_num;
+    uint8_t cyl_low;
+    uint8_t cyl_high;
+    union {
+        uint8_t drive;
+        uint8_t head;
+    };
+    uint8_t command;
+} CommandReg_t;
+
+typedef enum Events {
+    None = 0,
+    Transfer,
+    ReadWait,
+    WriteWait,
+    PrdRead,
+    DmaRead,
+    DmaWrite
+} Events_t;
+
+typedef enum DevAction {
+    ACT_NONE = 0,
+    ACT_CMD_WRITE,
+    ACT_CMD_COMPLETE,
+    ACT_CMD_ERROR,
+    ACT_SELECT_WRITE,
+    ACT_STAT_READ,
+    ACT_DATA_READY,
+    ACT_DATA_READ_BYTE,
+    ACT_DATA_READ_SHORT,
+    ACT_DATA_WRITE_BYTE,
+    ACT_DATA_WRITE_SHORT,
+    ACT_DMA_READY,
+    ACT_DMA_DONE,
+    ACT_SRST_SET,
+    ACT_SRST_CLEAR
+} DevAction_t;
+
+typedef enum DevState {
+    // Device idle
+    Device_Idle_S = 0,
+    Device_Idle_SI,
+    Device_Idle_NS,
+
+    // Software reset
+    Device_Srst,
+
+    // Non-data commands
+    Command_Execution,
+
+    // PIO data-in (data to host)
+    Prepare_Data_In,
+    Data_Ready_INTRQ_In,
+    Transfer_Data_In,
+
+    // PIO data-out (data from host)
+    Prepare_Data_Out,
+    Data_Ready_INTRQ_Out,
+    Transfer_Data_Out,
+
+    // DMA protocol
+    Prepare_Data_Dma,
+    Transfer_Data_Dma
+} DevState_t;
+
+typedef enum DmaState {
+    Dma_Idle = 0,
+    Dma_Start,
+    Dma_Transfer
+} DmaState_t;
+
+class PhysicalMemory;
 class IdeController;
 
 /**
- * SCSI Disk device model
+ * IDE Disk device model
  */
 class IdeDisk : public SimObject
 {
   protected:
     /** The IDE controller for this disk. */
     IdeController *ctrl;
+    /** The DMA interface to use for transfers */
+    DMAInterface<Bus> *dmaInterface;
     /** The image that contains the data of this disk. */
     DiskImage *image;
+    /** Pointer to physical memory for DMA transfers */
+    PhysicalMemory *physmem;
 
   protected:
-    /** The disk delay in milliseconds. */
+    /** The disk delay in microseconds. */
     int diskDelay;
 
+  private:
+    /** Drive identification structure for this disk */
+    struct ataparams driveID;
+    /** Data buffer for transfers */
+    uint8_t *dataBuffer;
+    /** Number of bytes in command data transfer */
+    uint32_t cmdBytes;
+    /** Number of bytes left in command data transfer */
+    uint32_t cmdBytesLeft;
+    /** Number of bytes left in DRQ block */
+    uint32_t drqBytesLeft;
+    /** Current sector in access */
+    uint32_t curSector;
+    /** Command block registers */
+    CommandReg_t cmdReg;
+    /** Status register */
+    uint8_t status;
+    /** Interrupt enable bit */
+    bool nIENBit;
+    /** Device state */
+    DevState_t devState;
+    /** Dma state */
+    DmaState_t dmaState;
+    /** Dma transaction is a read */
+    bool dmaRead;
+    /** PRD table base address */
+    uint32_t curPrdAddr;
+    /** PRD entry */
+    PrdTableEntry curPrd;
+    /** Number of bytes transfered by DMA interface for current transfer */
+    uint32_t dmaInterfaceBytes;
+    /** Device ID (master=0/slave=1) */
+    int devID;
+    /** Interrupt pending */
+    bool intrPending;
+
   public:
     /**
      * Create and initialize this Disk.
      * @param name The name of this disk.
      * @param img The disk image of this disk.
+     * @param phys Pointer to physical memory
+     * @param id The disk ID (master=0/slave=1)
      * @param disk_delay The disk delay in milliseconds
      */
-    IdeDisk(const std::string &name, DiskImage *img, int disk_delay);
+    IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys,
+            int id, Tick disk_delay);
 
     /**
      * Delete the data buffer.
      */
     ~IdeDisk();
 
+    /**
+     * Reset the device state
+     */
+    void reset(int id);
+
     /**
      * Set the controller for this device
      * @param c The IDE controller
      */
-    void setController(IdeController *c) {
+    void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) {
         if (ctrl) panic("Cannot change the controller once set!\n");
         ctrl = c;
+        dmaInterface = dmaIntr;
+    }
+
+    // Device register read/write
+    void read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data);
+    void write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data);
+
+    // Start/abort functions
+    void startDma(const uint32_t &prdTableBase);
+    void abortDma();
+
+  private:
+    void startCommand();
+
+    // Interrupt management
+    void intrPost();
+    void intrClear();
+
+    // DMA stuff
+    void doDmaTransfer();
+    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
+    EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
+
+    void doDmaRead();
+    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
+    EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
+
+    void doDmaWrite();
+    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
+    EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
+
+    void dmaPrdReadDone();
+    friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
+    EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
+
+    void dmaReadDone();
+    friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
+    EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
+
+    void dmaWriteDone();
+    friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
+    EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
+
+    // Disk image read/write
+    void readDisk(uint32_t sector, uint8_t *data);
+    void writeDisk(uint32_t sector, uint8_t *data);
+
+    // State machine management
+    void updateState(DevAction_t action);
+
+    // Utility functions
+    bool isBSYSet() { return (status & STATUS_BSY_BIT); }
+    bool isIENSet() { return nIENBit; }
+    bool isDEVSelect();
+
+    void setComplete()
+    {
+        // clear out the status byte
+        status = 0;
+        // set the DRDY bit
+        status |= STATUS_DRDY_BIT;
+        // set the SEEK bit
+        status |= STATUS_SEEK_BIT;
+    }
+
+    uint32_t getLBABase()
+    {
+        return  (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
+                       (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
     }
 
-    void startIO(uint8_t *cmdBlk, uint8_t *prdPtr) {};
+    inline Addr pciToDma(Addr pciAddr);
 
-    void dmaStart() {};
-    void dmaStop() {};
+    uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft);
 
     /**
      * Serialize this object to the given output stream.