X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=dev%2Fide_disk.hh;h=f9a413e1ea2a011d925f03df75cfffa793645e11;hb=8bbaaa7478bdddcd098c4da97f4ac1ba5a97ee67;hp=29ddd4be7d7d13aa26def21f68efbac3381b68c4;hpb=f4168a708c15c219a968d9cd665b571705467875;p=gem5.git diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh index 29ddd4be7..f9a413e1e 100644 --- a/dev/ide_disk.hh +++ b/dev/ide_disk.hh @@ -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 @@ -33,53 +33,315 @@ #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 *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 *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; + EventWrapper dmaTransferEvent; + + void doDmaRead(); + friend class EventWrapper; + EventWrapper dmaReadWaitEvent; + + void doDmaWrite(); + friend class EventWrapper; + EventWrapper dmaWriteWaitEvent; + + void dmaPrdReadDone(); + friend class EventWrapper; + EventWrapper dmaPrdReadEvent; + + void dmaReadDone(); + friend class EventWrapper; + EventWrapper dmaReadEvent; + + void dmaWriteDone(); + friend class EventWrapper; + EventWrapper 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.