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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [peripheral/] [atahost.c] - Rev 1712

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

/*
    atahost.c -- ATA Host code simulation
    Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
 
    This file is part of OpenRISC 1000 Architectural Simulator
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
 
#include <string.h>
 
#include "config.h"
 
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
 
#include "port.h"
#include "arch.h"
/* get a prototype for 'reg_mem_area()', and 'adjust_rw_delay()' */
#include "abstract.h"
#include "sim-config.h"
#include "sched.h"
 
#include "atahost.h"
 
/* default timing reset values */
#define PIO_MODE0_T1 6
#define PIO_MODE0_T2 28
#define PIO_MODE0_T4 2
#define PIO_MODE0_TEOC 23
 
#define DMA_MODE0_TM 4
#define DMA_MODE0_TD 21
#define DMA_MODE0_TEOC 21
 
/* reset and initialize ATA host core(s) */
static void ata_reset(void *dat)
{
   ata_host *ata = dat;
 
   // reset the core registers
   ata->regs.ctrl  = 0x0001;
   ata->regs.stat  = (ata->dev_id << 28) | (ata->rev << 24);
   ata->regs.pctr  = (ata->pio_mode0_teoc << ATA_TEOC) |
                     (ata->pio_mode0_t4 << ATA_T4) |
                     (ata->pio_mode0_t2 << ATA_T2) |
                     (ata->pio_mode0_t1 << ATA_T1);
   ata->regs.pftr0 = ata->regs.pctr;
   ata->regs.pftr1 = ata->regs.pctr;
   ata->regs.dtr0  = (ata->dma_mode0_teoc << ATA_TEOC) |
                     (ata->dma_mode0_td << ATA_TD) |
                     (ata->dma_mode0_tm << ATA_TM);
   ata->regs.dtr1  = ata->regs.dtr0;
   ata->regs.txb   = 0;
 
   // inform simulator about new read/write delay timings
   adjust_rw_delay( ata->mem, ata_pio_delay(ata->regs.pctr), ata_pio_delay(ata->regs.pctr) );
 
   /* the reset bit in the control register 'ctrl' is set, reset connect ata-devices */
   ata_devices_hw_reset(&ata->devices, 1);
}
/* ========================================================================= */
 
 
/*
  Read a register
*/
static uint32_t ata_read32( oraddr_t addr, void *dat )
{
    ata_host *ata = dat;
 
    /* determine if ata_host or ata_device addressed */
    if (is_ata_hostadr(addr))
    {
        // Accesses to internal register take 2cycles
        adjust_rw_delay( ata->mem, 2, 2 );
 
        switch( addr ) {
            case ATA_CTRL :
	        return ata -> regs.ctrl;
 
	    case ATA_STAT :
	        return ata -> regs.stat;
 
	    case ATA_PCTR :
	        return ata -> regs.pctr;
 
	    case ATA_PFTR0:
	        return ata->dev_id > 1 ? ata->regs.pftr0 : 0;
 
	    case ATA_PFTR1:
	        return ata->dev_id > 1 ? ata->regs.pftr1 : 0;
 
	    case ATA_DTR0 :
	        return ata->dev_id > 2 ? ata->regs.dtr0 : 0;
 
	    case ATA_DTR1 :
	        return ata->dev_id > 2 ? ata->regs.dtr1 : 0;
 
	    case ATA_RXB  :
	        return ata->dev_id > 2 ? ata->regs.rxb : 0;
 
	    default:
		return 0;
        }
    }
 
    /* check if the controller is enabled */
    if(ata->regs.ctrl & ATA_IDE_EN) {
        // make sure simulator uses correct read/write delay timings
        if(((addr & 0x7f) == ATA_DR) && ata->dev_id > 1) {
	  if(ata->dev_sel)
	      adjust_rw_delay(ata->mem, ata_pio_delay(ata->regs.pftr1), ata_pio_delay(ata->regs.pftr1));
	  else
	      adjust_rw_delay(ata->mem, ata_pio_delay(ata->regs.pftr0), ata_pio_delay(ata->regs.pftr0));
	}
	else
          adjust_rw_delay(ata->mem, ata_pio_delay(ata->regs.pctr), ata_pio_delay(ata->regs.pctr));
 
        return ata_devices_read(&ata->devices, addr & 0x7f);
    }
    return 0;
}
/* ========================================================================= */
 
 
/*
  Write a register
*/
static void ata_write32( oraddr_t addr, uint32_t value, void *dat )
{
    ata_host *ata = dat;
 
    /* determine if ata_host or ata_device addressed */
    if (is_ata_hostadr(addr))
    {
       // Accesses to internal register take 2cycles
       adjust_rw_delay( ata->mem, 2, 2 );
 
        switch( addr ) {
            case ATA_CTRL :
	        ata -> regs.ctrl =  value;
 
		/* check if reset bit set, if so reset ata-devices    */
		if (value & ATA_RST)
		  ata_devices_hw_reset(&ata->devices, 1);
		else
		  ata_devices_hw_reset(&ata->devices, 0);
		break;
 
            case ATA_STAT :
		ata -> regs.stat = (ata -> regs.stat & ~ATA_IDEIS) | (ata -> regs.stat & ATA_IDEIS & value);
		break;
 
	    case ATA_PCTR :
	        ata -> regs.pctr = value;
		break;
 
	    case ATA_PFTR0:
	        ata -> regs.pftr0 = value;
		break;
 
	    case ATA_PFTR1:
	        ata -> regs.pftr1 = value;
		break;
 
	    case ATA_DTR0 :
	        ata -> regs.dtr0  = value;
		break;
 
	    case ATA_DTR1 :
	        ata -> regs.dtr1  = value;
		break;
 
	    case ATA_TXB  :
	        ata -> regs.txb   = value;
		break;
 
            default:
	        /* ERROR-macro currently only supports simple strings. */
		/*
	          fprintf(stderr, "ERROR  : Unknown register for OCIDEC(%1d).\n", DEV_ID );
 
		  Tried to show some useful info here.
		  But when using 'DM'-simulator-command, the screen gets filled with these messages.
		  Thereby eradicating the usefulness of the message
		*/
		break;
        }
        return;
    }
 
    /* check if the controller is enabled */
    if(ata->regs.ctrl & ATA_IDE_EN) {
        // make sure simulator uses correct read/write delay timings
        if(((addr & 0x7f) == ATA_DR) && (ata->dev_id > 1)) {
	  if(ata->dev_sel)
	    adjust_rw_delay(ata->mem, ata_pio_delay(ata->regs.pftr1), ata_pio_delay(ata->regs.pftr1));
	  else
	    adjust_rw_delay(ata->mem, ata_pio_delay(ata->regs.pftr0), ata_pio_delay(ata->regs.pftr0));
	} else
          adjust_rw_delay( ata->mem, ata_pio_delay(ata->regs.pctr), ata_pio_delay(ata->regs.pctr) );
 
        if((addr & 0x7f) == ATA_DHR)
          ata->dev_sel = value & ATA_DHR_DEV;
 
        ata_devices_write(&ata->devices, addr & 0x7f, value);
    }
}
/* ========================================================================= */
 
 
/* Dump status */
static void ata_status( void *dat )
{
  ata_host *ata = dat;
 
  if ( ata->baseaddr == 0 )
    return;
 
  PRINTF( "\nOCIDEC-%1d at: 0x%"PRIxADDR"\n", ata->dev_id, ata->baseaddr );
  PRINTF( "ATA CTRL     : 0x%08X\n", ata->regs.ctrl  );
  PRINTF( "ATA STAT     : 0x%08x\n", ata->regs.stat  );
  PRINTF( "ATA PCTR     : 0x%08x\n", ata->regs.pctr  );
 
  if(ata->dev_id > 1) {
    PRINTF( "ATA FCTR0    : 0x%08x\n", ata->regs.pftr0 );
    PRINTF( "ATA FCTR1    : 0x%08x\n", ata->regs.pftr1 );
  }
 
  if(ata->dev_id > 2) {
    PRINTF( "ATA DTR0     : 0x%08x\n", ata->regs.dtr0  );
    PRINTF( "ATA DTR1     : 0x%08x\n", ata->regs.dtr1  );
    PRINTF( "ATA TXD      : 0x%08x\n", ata->regs.txb   );
    PRINTF( "ATA RXD      : 0x%08x\n", ata->regs.rxb   );
  }
}
/* ========================================================================= */
 
/*----------------------------------------------------[ ATA Configuration ]---*/
static unsigned int conf_dev;
 
static void ata_baseaddr(union param_val val, void *dat)
{
  ata_host *ata = dat;
  ata->baseaddr = val.addr_val;
}
 
static void ata_irq(union param_val val, void *dat)
{
  ata_host *ata = dat;
  ata->irq = val.int_val;
}
 
static void ata_dev_id(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(val.int_val < 1 || val.int_val > 3) {
    fprintf(stderr, "Peripheral ATA: Unknown device id %d, useing 1\n",
            val.int_val);
    ata->dev_id = 1;
    return;
  }
 
  ata->dev_id = val.int_val;
}
 
static void ata_rev(union param_val val, void *dat)
{
  ata_host *ata = dat;
  ata->rev = val.int_val;
}
 
static void ata_pio_mode0_t1(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid pio_mode0_t1: %d\n", val.int_val);
    return;
  }
 
  ata->pio_mode0_t1 = val.int_val;
}
 
static void ata_pio_mode0_t2(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid pio_mode0_t2: %d\n", val.int_val);
    return;
  }
 
  ata->pio_mode0_t2 = val.int_val;
}
 
static void ata_pio_mode0_t4(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid pio_mode0_t4: %d\n", val.int_val);
    return;
  }
 
  ata->pio_mode0_t4 = val.int_val;
}
 
static void ata_pio_mode0_teoc(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid pio_mode0_teoc: %d\n", val.int_val);
    return;
  }
 
  ata->pio_mode0_teoc = val.int_val;
}
 
static void ata_dma_mode0_tm(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid dma_mode0_tm: %d\n", val.int_val);
    return;
  }
 
  ata->dma_mode0_tm = val.int_val;
}
 
static void ata_dma_mode0_td(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid dma_mode0_td: %d\n", val.int_val);
    return;
  }
 
  ata->dma_mode0_td = val.int_val;
}
 
static void ata_dma_mode0_teoc(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(val.int_val < 0 || val.int_val > 255) {
    fprintf(stderr, "Peripheral ATA: Invalid dma_mode0_teoc: %d\n", val.int_val);
    return;
  }
 
  ata->dma_mode0_teoc = val.int_val;
}
 
static void ata_type(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.type = val.int_val;
}
 
static void ata_file(union param_val val, void *dat)
{
  ata_host *ata = dat;
 
  if(conf_dev <= 1)
    if(!(ata->devices.device[conf_dev].conf.file = strdup(val.str_val))) {
      fprintf(stderr, "Peripheral ATA: Run out of memory\n");
      exit(-1);
    }
}
 
static void ata_size(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.size = val.int_val << 20;
}
 
static void ata_packet(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.packet = val.int_val;
}
 
static void ata_enabled(union param_val val, void *dat)
{
  ata_host *ata = dat;
  ata->enabled = val.int_val;
}
 
static void ata_heads(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.heads = val.int_val;
}
 
static void ata_sectors(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.sectors = val.int_val;
}
 
static void ata_firmware(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    if(!(ata->devices.device[conf_dev].conf.firmware = strdup(val.str_val))) {
      fprintf(stderr, "Peripheral ATA: Run out of memory\n");
      exit(-1);
    }
}
 
static void ata_mwdma(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.mwdma = val.int_val;
}
 
static void ata_pio(union param_val val, void *dat)
{
  ata_host *ata = dat;
  if(conf_dev <= 1)
    ata->devices.device[conf_dev].conf.pio = val.int_val;
}
 
 
static void ata_start_device(union param_val val, void *dat)
{
  conf_dev = val.int_val;
 
  if(conf_dev > 1)
    fprintf(stderr, "Device %d out-of-range\n", conf_dev);
}
 
static void ata_enddevice(union param_val val, void *dat)
{
  conf_dev = 2;
}
 
static void *ata_sec_start(void)
{
  ata_host *new = malloc(sizeof(ata_host));
 
  if(!new) {
    fprintf(stderr, "Peripheral ATA: Run out of memory\n");
    exit(-1);
  }
 
  memset(new, 0, sizeof(ata_host));
  new->enabled = 1;
  new->dev_id = 1;
 
  new->pio_mode0_t1 = PIO_MODE0_T1;
  new->pio_mode0_t2 = PIO_MODE0_T2;
  new->pio_mode0_t4 = PIO_MODE0_T4;
  new->pio_mode0_teoc = PIO_MODE0_TEOC;
 
  new->dma_mode0_tm = DMA_MODE0_TM;
  new->dma_mode0_td = DMA_MODE0_TD;
  new->dma_mode0_teoc = DMA_MODE0_TEOC;
 
  new->devices.device[0].conf.heads = 7;
  new->devices.device[0].conf.sectors = 32;
  new->devices.device[0].conf.firmware = "02207031";
  new->devices.device[0].conf.mwdma = 2;
  new->devices.device[0].conf.pio = 4;
 
  new->devices.device[1].conf.heads = 7;
  new->devices.device[1].conf.sectors = 32;
  new->devices.device[1].conf.firmware = "02207031";
  new->devices.device[1].conf.mwdma = 2;
  new->devices.device[1].conf.pio = 4;
 
  return new;
}
 
static void ata_sec_end(void *dat)
{
  ata_host *ata = dat;
  struct mem_ops ops;
 
  if(!ata->enabled) {
    free(dat);
    return;
  }
 
  /* Connect ata_devices.                                            */
  ata_devices_init(&ata->devices);
 
  memset(&ops, 0, sizeof(struct mem_ops));
 
  ops.readfunc32 = ata_read32;
  ops.read_dat32 = dat;
  ops.writefunc32 = ata_write32;
  ops.write_dat32 = dat;
 
  /* Delays will be readjusted later */
  ops.delayr = 2;
  ops.delayw = 2;
 
  ata->mem = reg_mem_area(ata->baseaddr, ATA_ADDR_SPACE, 0, &ops);
 
  reg_sim_reset(ata_reset, dat);
  reg_sim_stat(ata_status, dat);
}
 
void reg_ata_sec(void)
{
  struct config_section *sec = reg_config_sec("ata", ata_sec_start, ata_sec_end);
 
  reg_config_param(sec, "enabled", paramt_int, ata_enabled);
  reg_config_param(sec, "baseaddr", paramt_addr, ata_baseaddr);
  reg_config_param(sec, "irq", paramt_int, ata_irq);
  reg_config_param(sec, "dev_id", paramt_int, ata_dev_id);
  reg_config_param(sec, "rev", paramt_int, ata_rev);
 
  reg_config_param(sec, "pio_mode0_t1", paramt_int, ata_pio_mode0_t1);
  reg_config_param(sec, "pio_mode0_t2", paramt_int, ata_pio_mode0_t2);
  reg_config_param(sec, "pio_mode0_t4", paramt_int, ata_pio_mode0_t4);
  reg_config_param(sec, "pio_mode0_teoc", paramt_int, ata_pio_mode0_teoc);
 
  reg_config_param(sec, "dma_mode0_tm", paramt_int, ata_dma_mode0_tm);
  reg_config_param(sec, "dma_mode0_td", paramt_int, ata_dma_mode0_td);
  reg_config_param(sec, "dma_mode0_teoc", paramt_int, ata_dma_mode0_teoc);
 
  reg_config_param(sec, "device", paramt_int, ata_start_device);
  reg_config_param(sec, "enddevice", paramt_int, ata_enddevice);
 
  reg_config_param(sec, "type", paramt_int, ata_type);
  reg_config_param(sec, "file", paramt_str, ata_file);
  reg_config_param(sec, "size", paramt_int, ata_size);
  reg_config_param(sec, "packet", paramt_int, ata_packet);
  reg_config_param(sec, "heads", paramt_int, ata_heads);
  reg_config_param(sec, "sectors", paramt_int, ata_sectors);
  reg_config_param(sec, "firmware", paramt_int, ata_firmware);
  reg_config_param(sec, "mwdma", paramt_int, ata_mwdma);
  reg_config_param(sec, "pio", paramt_int, ata_pio);
}
 

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

powered by: WebSVN 2.1.0

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