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

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/tags/rel-0-3-0-rc1/or1ksim/peripheral
    from Rev 1749 to Rev 1765
    Reverse comparison

Rev 1749 → Rev 1765

/gpio.c
0,0 → 1,465
/* gpio.h -- GPIO code simulation
 
Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org
Copyright (C) 2008 Embecosm Limited
 
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
This file is part of Or1ksim, the 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 3 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, see <http://www.gnu.org/licenses/>. */
 
/* This program is commented throughout in a fashion suitable for processing
with Doxygen. */
 
 
/* Autoconf and/or portability configuration */
#include "config.h"
#include "port.h"
 
/* System includes */
#include <stdlib.h>
 
/* Package includes */
#include "sim-config.h"
#include "arch.h"
#include "debug.h"
#include "vapi.h"
#include "sched.h"
#include "pic.h"
#include "abstract.h"
#include "toplevel-support.h"
#include "sim-cmd.h"
 
 
/* Address space required by one GPIO */
#define GPIO_ADDR_SPACE 0x20
 
/* Relative Register Addresses */
#define RGPIO_IN 0x00
#define RGPIO_OUT 0x04
#define RGPIO_OE 0x08
#define RGPIO_INTE 0x0C
#define RGPIO_PTRIG 0x10
#define RGPIO_AUX 0x14
#define RGPIO_CTRL 0x18
#define RGPIO_INTS 0x1C
 
/* Fields inside RGPIO_CTRL */
#define RGPIO_CTRL_ECLK 0x00000001
#define RGPIO_CTRL_NEC 0x00000002
#define RGPIO_CTRL_INTE 0x00000004
#define RGPIO_CTRL_INTS 0x00000008
 
DEFAULT_DEBUG_CHANNEL (gpio);
 
 
/*
* The various VAPI IDs each GPIO device has
*/
enum
{ GPIO_VAPI_DATA = 0,
GPIO_VAPI_AUX,
GPIO_VAPI_CLOCK,
GPIO_VAPI_RGPIO_OE,
GPIO_VAPI_RGPIO_INTE,
GPIO_VAPI_RGPIO_PTRIG,
GPIO_VAPI_RGPIO_AUX,
GPIO_VAPI_RGPIO_CTRL,
GPIO_NUM_VAPI_IDS
};
 
/*
* Implementatino of GPIO Code Registers and State
*/
struct gpio_device
{
/* Is peripheral enabled */
int enabled;
 
/* Base address in memory */
oraddr_t baseaddr;
 
/* Which IRQ to generate */
int irq;
 
/* Which GPIO is this? */
unsigned gpio_number;
 
/* VAPI IDs */
unsigned long base_vapi_id;
 
/* Auxiliary inputs */
unsigned long auxiliary_inputs;
 
/* Visible registers */
struct
{
unsigned long in;
unsigned long out;
unsigned long oe;
unsigned long inte;
unsigned long ptrig;
unsigned long aux;
unsigned long ctrl;
unsigned long ints;
 
int external_clock;
} curr, next;
};
 
static void gpio_vapi_read (unsigned long id, unsigned long data, void *dat);
static void gpio_external_clock (unsigned long value,
struct gpio_device *gpio);
static void gpio_device_clock (struct gpio_device *gpio);
static void gpio_clock (void *dat);
 
/* Initialize all parameters and state */
static void
gpio_reset (void *dat)
{
struct gpio_device *gpio = dat;
 
if (gpio->baseaddr != 0)
{
/* Possibly connect to VAPI */
if (gpio->base_vapi_id)
{
vapi_install_multi_handler (gpio->base_vapi_id, GPIO_NUM_VAPI_IDS,
gpio_vapi_read, dat);
}
}
SCHED_ADD (gpio_clock, dat, 1);
}
 
 
/* Dump status */
static void
gpio_status (void *dat)
{
struct gpio_device *gpio = dat;
 
if (gpio->baseaddr == 0)
return;
 
PRINTF ("\nGPIO at 0x%" PRIxADDR ":\n", gpio->baseaddr);
PRINTF ("RGPIO_IN : 0x%08lX\n", gpio->curr.in);
PRINTF ("RGPIO_OUT : 0x%08lX\n", gpio->curr.out);
PRINTF ("RGPIO_OE : 0x%08lX\n", gpio->curr.oe);
PRINTF ("RGPIO_INTE : 0x%08lX\n", gpio->curr.inte);
PRINTF ("RGPIO_PTRIG : 0x%08lX\n", gpio->curr.ptrig);
PRINTF ("RGPIO_AUX : 0x%08lX\n", gpio->curr.aux);
PRINTF ("RGPIO_CTRL : 0x%08lX\n", gpio->curr.ctrl);
PRINTF ("RGPIO_INTS : 0x%08lX\n", gpio->curr.ints);
}
 
 
/* Wishbone read */
static uint32_t
gpio_read32 (oraddr_t addr, void *dat)
{
struct gpio_device *gpio = dat;
 
switch (addr)
{
case RGPIO_IN:
return gpio->curr.in | gpio->curr.out;
case RGPIO_OUT:
return gpio->curr.out;
case RGPIO_OE:
return gpio->curr.oe;
case RGPIO_INTE:
return gpio->curr.inte;
case RGPIO_PTRIG:
return gpio->curr.ptrig;
case RGPIO_AUX:
return gpio->curr.aux;
case RGPIO_CTRL:
return gpio->curr.ctrl;
case RGPIO_INTS:
return gpio->curr.ints;
}
 
return 0;
}
 
 
/* Wishbone write */
static void
gpio_write32 (oraddr_t addr, uint32_t value, void *dat)
{
struct gpio_device *gpio = dat;
 
switch (addr)
{
case RGPIO_IN:
TRACE ("GPIO: Cannot write to RGPIO_IN\n");
break;
case RGPIO_OUT:
gpio->next.out = value;
break;
case RGPIO_OE:
gpio->next.oe = value;
break;
case RGPIO_INTE:
gpio->next.inte = value;
break;
case RGPIO_PTRIG:
gpio->next.ptrig = value;
break;
case RGPIO_AUX:
gpio->next.aux = value;
break;
case RGPIO_CTRL:
gpio->next.ctrl = value;
break;
case RGPIO_INTS:
if (gpio->next.ints && !value)
clear_interrupt (gpio->irq);
gpio->next.ints = value;
break;
}
}
 
 
/* Input from "outside world" */
static void
gpio_vapi_read (unsigned long id, unsigned long data, void *dat)
{
unsigned which;
struct gpio_device *gpio = dat;
 
TRACE ("GPIO: id %08lx, data %08lx\n", id, data);
 
which = id - gpio->base_vapi_id;
 
switch (which)
{
case GPIO_VAPI_DATA:
TRACE ("GPIO: Next input from VAPI = 0x%08lx (RGPIO_OE = 0x%08lx)\n",
data, gpio->next.oe);
gpio->next.in = data;
break;
case GPIO_VAPI_AUX:
gpio->auxiliary_inputs = data;
break;
case GPIO_VAPI_RGPIO_OE:
gpio->next.oe = data;
break;
case GPIO_VAPI_RGPIO_INTE:
gpio->next.inte = data;
break;
case GPIO_VAPI_RGPIO_PTRIG:
gpio->next.ptrig = data;
break;
case GPIO_VAPI_RGPIO_AUX:
gpio->next.aux = data;
break;
case GPIO_VAPI_RGPIO_CTRL:
gpio->next.ctrl = data;
break;
case GPIO_VAPI_CLOCK:
gpio_external_clock (data, gpio);
break;
}
}
 
/* System Clock. */
static void
gpio_clock (void *dat)
{
struct gpio_device *gpio = dat;
 
/* Clock the device */
if (!(gpio->curr.ctrl & RGPIO_CTRL_ECLK))
gpio_device_clock (gpio);
SCHED_ADD (gpio_clock, dat, 1);
}
 
/* External Clock. */
static void
gpio_external_clock (unsigned long value, struct gpio_device *gpio)
{
int use_external_clock =
((gpio->curr.ctrl & RGPIO_CTRL_ECLK) == RGPIO_CTRL_ECLK);
int negative_edge = ((gpio->curr.ctrl & RGPIO_CTRL_NEC) == RGPIO_CTRL_NEC);
 
/* "Normalize" clock value */
value = (value != 0);
 
gpio->next.external_clock = value;
 
if (use_external_clock
&& (gpio->next.external_clock != gpio->curr.external_clock)
&& (value != negative_edge))
/* Make sure that in vapi_read, we don't clock the device */
if (gpio->curr.ctrl & RGPIO_CTRL_ECLK)
gpio_device_clock (gpio);
}
 
/* Report an interrupt to the sim */
static void
gpio_do_int (void *dat)
{
struct gpio_device *gpio = dat;
 
report_interrupt (gpio->irq);
}
 
/* Clock as handld by one device. */
static void
gpio_device_clock (struct gpio_device *gpio)
{
/* Calculate new inputs and outputs */
gpio->next.in &= ~gpio->next.oe; /* Only input bits */
/* Replace requested output bits with aux input */
gpio->next.out =
(gpio->next.out & ~gpio->next.aux) | (gpio->auxiliary_inputs & gpio->next.
aux);
gpio->next.out &= gpio->next.oe; /* Only output-enabled bits */
 
/* If any outputs changed, notify the world (i.e. vapi) */
if (gpio->next.out != gpio->curr.out)
{
TRACE ("GPIO: New output 0x%08lx, RGPIO_OE = 0x%08lx\n", gpio->next.out,
gpio->next.oe);
if (gpio->base_vapi_id)
vapi_send (gpio->base_vapi_id + GPIO_VAPI_DATA, gpio->next.out);
}
 
/* If any inputs changed and interrupt enabled, generate interrupt */
if (gpio->next.in != gpio->curr.in)
{
TRACE ("GPIO: New input 0x%08lx\n", gpio->next.in);
 
if (gpio->next.ctrl & RGPIO_CTRL_INTE)
{
unsigned changed_bits = gpio->next.in ^ gpio->curr.in; /* inputs that have changed */
unsigned set_bits = changed_bits & gpio->next.in; /* inputs that have been set */
unsigned cleared_bits = changed_bits & gpio->curr.in; /* inputs that have been cleared */
unsigned relevant_bits =
(gpio->next.ptrig & set_bits) | (~gpio->next.
ptrig & cleared_bits);
 
if (relevant_bits & gpio->next.inte)
{
TRACE ("GPIO: Reporting interrupt %d\n", gpio->irq);
gpio->next.ctrl |= RGPIO_CTRL_INTS;
gpio->next.ints |= relevant_bits & gpio->next.inte;
/* Since we can't report an interrupt during a readmem/writemem
* schedule the scheduler to do it. Read the comment above
* report_interrupt in pic/pic.c */
SCHED_ADD (gpio_do_int, gpio, 1);
}
}
}
 
/* Switch to values for next clock */
memcpy (&(gpio->curr), &(gpio->next), sizeof (gpio->curr));
}
 
/*---------------------------------------------------[ GPIO configuration ]---*/
static void
gpio_baseaddr (union param_val val, void *dat)
{
struct gpio_device *gpio = dat;
gpio->baseaddr = val.addr_val;
}
 
static void
gpio_irq (union param_val val, void *dat)
{
struct gpio_device *gpio = dat;
gpio->irq = val.int_val;
}
 
static void
gpio_base_vapi_id (union param_val val, void *dat)
{
struct gpio_device *gpio = dat;
gpio->base_vapi_id = val.int_val;
}
 
static void
gpio_enabled (union param_val val, void *dat)
{
struct gpio_device *gpio = dat;
gpio->enabled = val.int_val;
}
 
static void *
gpio_sec_start (void)
{
struct gpio_device *new = malloc (sizeof (struct gpio_device));
 
if (!new)
{
fprintf (stderr, "Peripheral gpio: Run out of memory\n");
exit (-1);
}
 
new->auxiliary_inputs = 0;
memset (&new->curr, 0, sizeof (new->curr));
memset (&new->next, 0, sizeof (new->next));
 
new->enabled = 1;
new->baseaddr = 0;
new->irq = 0;
new->base_vapi_id = 0;
 
return new;
}
 
static void
gpio_sec_end (void *dat)
{
struct gpio_device *gpio = dat;
struct mem_ops ops;
 
if (!gpio->enabled)
{
free (dat);
return;
}
 
memset (&ops, 0, sizeof (struct mem_ops));
 
ops.readfunc32 = gpio_read32;
ops.writefunc32 = gpio_write32;
ops.write_dat32 = dat;
ops.read_dat32 = dat;
 
/* FIXME: Correct delays? */
ops.delayr = 2;
ops.delayw = 2;
 
/* Register memory range */
reg_mem_area (gpio->baseaddr, GPIO_ADDR_SPACE, 0, &ops);
 
reg_sim_reset (gpio_reset, dat);
reg_sim_stat (gpio_status, dat);
}
 
void
reg_gpio_sec (void)
{
struct config_section *sec =
reg_config_sec ("gpio", gpio_sec_start, gpio_sec_end);
 
reg_config_param (sec, "enabled", paramt_int, gpio_enabled);
reg_config_param (sec, "baseaddr", paramt_addr, gpio_baseaddr);
reg_config_param (sec, "irq", paramt_int, gpio_irq);
reg_config_param (sec, "vapi_id", paramt_int, gpio_base_vapi_id);
reg_config_param (sec, "base_vapi_id", paramt_int, gpio_base_vapi_id);
}
/mc.c
0,0 → 1,547
/* mc.c -- Simulation of Memory Controller
 
Copyright (C) 2001 by Marko Mlinar, markom@opencores.org
Copyright (C) 2008 Embecosm Limited
 
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
This file is part of Or1ksim, the 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 3 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, see <http://www.gnu.org/licenses/>. */
 
/* This program is commented throughout in a fashion suitable for processing
with Doxygen. */
 
 
/* Enable memory controller, via:
section mc
enable = 1
POC = 0x13243545
end
 
Limitations:
- memory refresh is not simulated
*/
 
 
/* Autoconf and/or portability configuration */
#include "config.h"
#include "port.h"
 
/* System includes */
#include <stdlib.h>
 
/* Package includes */
#include "arch.h"
#include "abstract.h"
#include "sim-config.h"
#include "debug.h"
#include "toplevel-support.h"
#include "sim-cmd.h"
 
 
#define N_CE 8
 
#define MC_CSR 0x00
#define MC_POC 0x04
#define MC_BA_MASK 0x08
#define MC_CSC(i) (0x10 + (i) * 8)
#define MC_TMS(i) (0x14 + (i) * 8)
 
#define MC_ADDR_SPACE (MC_CSC(N_CE))
 
/* POC register field definition */
#define MC_POC_EN_BW_OFFSET 0
#define MC_POC_EN_BW_WIDTH 2
#define MC_POC_EN_MEMTYPE_OFFSET 2
#define MC_POC_EN_MEMTYPE_WIDTH 2
 
/* CSC register field definition */
#define MC_CSC_EN_OFFSET 0
#define MC_CSC_MEMTYPE_OFFSET 1
#define MC_CSC_MEMTYPE_WIDTH 2
#define MC_CSC_BW_OFFSET 4
#define MC_CSC_BW_WIDTH 2
#define MC_CSC_MS_OFFSET 6
#define MC_CSC_MS_WIDTH 2
#define MC_CSC_WP_OFFSET 8
#define MC_CSC_BAS_OFFSET 9
#define MC_CSC_KRO_OFFSET 10
#define MC_CSC_PEN_OFFSET 11
#define MC_CSC_SEL_OFFSET 16
#define MC_CSC_SEL_WIDTH 8
 
#define MC_CSC_MEMTYPE_SDRAM 0
#define MC_CSC_MEMTYPE_SSRAM 1
#define MC_CSC_MEMTYPE_ASYNC 2
#define MC_CSC_MEMTYPE_SYNC 3
 
#define MC_CSR_VALID 0xFF000703LU
#define MC_POC_VALID 0x0000000FLU
#define MC_BA_MASK_VALID 0x000003FFLU
#define MC_CSC_VALID 0x00FF0FFFLU
#define MC_TMS_SDRAM_VALID 0x0FFF83FFLU
#define MC_TMS_SSRAM_VALID 0x00000000LU
#define MC_TMS_ASYNC_VALID 0x03FFFFFFLU
#define MC_TMS_SYNC_VALID 0x01FFFFFFLU
#define MC_TMS_VALID 0xFFFFFFFFLU /* reg test compat. */
 
/* TMS register field definition SDRAM */
#define MC_TMS_SDRAM_TRFC_OFFSET 24
#define MC_TMS_SDRAM_TRFC_WIDTH 4
#define MC_TMS_SDRAM_TRP_OFFSET 20
#define MC_TMS_SDRAM_TRP_WIDTH 4
#define MC_TMS_SDRAM_TRCD_OFFSET 17
#define MC_TMS_SDRAM_TRCD_WIDTH 4
#define MC_TMS_SDRAM_TWR_OFFSET 15
#define MC_TMS_SDRAM_TWR_WIDTH 2
#define MC_TMS_SDRAM_WBL_OFFSET 9
#define MC_TMS_SDRAM_OM_OFFSET 7
#define MC_TMS_SDRAM_OM_WIDTH 2
#define MC_TMS_SDRAM_CL_OFFSET 4
#define MC_TMS_SDRAM_CL_WIDTH 3
#define MC_TMS_SDRAM_BT_OFFSET 3
#define MC_TMS_SDRAM_BL_OFFSET 0
#define MC_TMS_SDRAM_BL_WIDTH 3
 
/* TMS register field definition ASYNC */
#define MC_TMS_ASYNC_TWWD_OFFSET 20
#define MC_TMS_ASYNC_TWWD_WIDTH 6
#define MC_TMS_ASYNC_TWD_OFFSET 16
#define MC_TMS_ASYNC_TWD_WIDTH 4
#define MC_TMS_ASYNC_TWPW_OFFSET 12
#define MC_TMS_ASYNC_TWPW_WIDTH 4
#define MC_TMS_ASYNC_TRDZ_OFFSET 8
#define MC_TMS_ASYNC_TRDZ_WIDTH 4
#define MC_TMS_ASYNC_TRDV_OFFSET 0
#define MC_TMS_ASYNC_TRDV_WIDTH 8
/* TMS register field definition SYNC */
#define MC_TMS_SYNC_TTO_OFFSET 16
#define MC_TMS_SYNC_TTO_WIDTH 9
#define MC_TMS_SYNC_TWR_OFFSET 12
#define MC_TMS_SYNC_TWR_WIDTH 4
#define MC_TMS_SYNC_TRDZ_OFFSET 8
#define MC_TMS_SYNC_TRDZ_WIDTH 4
#define MC_TMS_SYNC_TRDV_OFFSET 0
#define MC_TMS_SYNC_TRDV_WIDTH 8
 
DEFAULT_DEBUG_CHANNEL (mc);
 
struct mc_area
{
struct dev_memarea *mem;
unsigned int cs;
int mc;
struct mc_area *next;
};
 
struct mc
{
uint32_t csr;
uint32_t poc;
uint32_t ba_mask;
uint32_t csc[N_CE];
uint32_t tms[N_CE];
oraddr_t baseaddr;
int enabled;
 
/* Index of this memory controler amongst all the memory controlers */
int index;
/* List of memory devices under this mc's control */
struct mc_area *mc_areas;
 
struct mc *next;
};
 
static struct mc *mcs = NULL;
 
/* List used to temporarily hold memory areas registered with the mc, while the
* mc configureation has not been loaded */
static struct mc_area *mc_areas = NULL;
 
void
set_csc_tms (int cs, uint32_t csc, uint32_t tms, struct mc *mc)
{
struct mc_area *cur = mc->mc_areas;
 
while (cur)
{
if (cur->cs == cs)
{
/* FIXME: No peripheral should _ever_ acess a dev_memarea structure
* directly */
TRACE ("Remapping %" PRIxADDR "-%" PRIxADDR " to %" PRIxADDR "-%"
PRIxADDR "\n", cur->mem->addr_compare,
cur->mem->addr_compare | cur->mem->size_mask,
(csc >> MC_CSC_SEL_OFFSET) << 22,
((csc >> MC_CSC_SEL_OFFSET) << 22) | cur->mem->size_mask);
 
cur->mem->addr_mask = mc->ba_mask << 22;
cur->mem->addr_compare =
((csc >> MC_CSC_SEL_OFFSET) /* & 0xff */ ) << 22;
set_mem_valid (cur->mem, (csc >> MC_CSC_EN_OFFSET) & 0x01);
 
if ((csc >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_ASYNC)
{
adjust_rw_delay (cur->mem, (tms & 0xff) + ((tms >> 8) & 0x0f),
((tms >> 12) & 0x0f) + ((tms >> 16) & 0x0f) +
((tms >> 20) & 0x3f));
}
else if ((csc >> MC_CSC_MEMTYPE_OFFSET)
&& 0x07 == MC_CSC_MEMTYPE_SDRAM)
{
adjust_rw_delay (cur->mem, 3 + ((tms >> 4) & 0x03),
3 + ((tms >> 4) & 0x03));
}
else if ((csc >> MC_CSC_MEMTYPE_OFFSET)
&& 0x07 == MC_CSC_MEMTYPE_SSRAM)
{
adjust_rw_delay (cur->mem, 2, 2);
}
else if ((csc >> MC_CSC_MEMTYPE_OFFSET)
&& 0x07 == MC_CSC_MEMTYPE_SYNC)
{
adjust_rw_delay (cur->mem, 2, 2);
}
return;
}
cur = cur->next;
}
}
 
/* Set a specific MC register with value. */
void
mc_write_word (oraddr_t addr, uint32_t value, void *dat)
{
struct mc *mc = dat;
int chipsel;
 
TRACE ("mc_write_word(%" PRIxADDR ",%08" PRIx32 ")\n", addr, value);
 
switch (addr)
{
case MC_CSR:
mc->csr = value;
break;
case MC_POC:
WARN ("warning: write to MC's POC register!");
break;
case MC_BA_MASK:
mc->ba_mask = value & MC_BA_MASK_VALID;
for (chipsel = 0; chipsel < N_CE; chipsel++)
set_csc_tms (chipsel, mc->csc[chipsel], mc->tms[chipsel], mc);
break;
default:
if (addr >= MC_CSC (0) && addr <= MC_TMS (N_CE - 1))
{
addr -= MC_CSC (0);
if ((addr >> 2) & 1)
mc->tms[addr >> 3] = value;
else
mc->csc[addr >> 3] = value;
 
set_csc_tms (addr >> 3, mc->csc[addr >> 3], mc->tms[addr >> 3], mc);
break;
}
else
TRACE ("write out of range (addr %" PRIxADDR ")\n",
addr + mc->baseaddr);
}
}
 
/* Read a specific MC register. */
uint32_t
mc_read_word (oraddr_t addr, void *dat)
{
struct mc *mc = dat;
uint32_t value = 0;
 
TRACE ("mc_read_word(%" PRIxADDR ")", addr);
 
switch (addr)
{
case MC_CSR:
value = mc->csr;
break;
case MC_POC:
value = mc->poc;
break;
case MC_BA_MASK:
value = mc->ba_mask;
break;
default:
if (addr >= MC_CSC (0) && addr <= MC_TMS (N_CE - 1))
{
addr -= MC_CSC (0);
if ((addr >> 2) & 1)
value = mc->tms[addr >> 3];
else
value = mc->csc[addr >> 3];
}
else
TRACE (" read out of range (addr %" PRIxADDR ")\n",
addr + mc->baseaddr);
break;
}
TRACE (" value(%" PRIx32 ")\n", value);
return value;
}
 
/* Read POC register and init memory controler regs. */
void
mc_reset (void *dat)
{
struct mc *mc = dat;
struct mc_area *cur, *prev, *tmp;
 
PRINTF ("Resetting memory controller.\n");
 
memset (mc->csc, 0, sizeof (mc->csc));
memset (mc->tms, 0, sizeof (mc->tms));
 
mc->csr = 0;
mc->ba_mask = 0;
 
/* Set CS0 */
mc->csc[0] =
(((mc->poc & 0x0c) >> 2) << MC_CSC_MEMTYPE_OFFSET) | ((mc->
poc & 0x03) <<
MC_CSC_BW_OFFSET) |
1;
 
if ((mc->csc[0] >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_ASYNC)
{
mc->tms[0] = MC_TMS_ASYNC_VALID;
}
else if ((mc->csc[0] >> MC_CSC_MEMTYPE_OFFSET)
&& 0x07 == MC_CSC_MEMTYPE_SDRAM)
{
mc->tms[0] = MC_TMS_SDRAM_VALID;
}
else if ((mc->csc[0] >> MC_CSC_MEMTYPE_OFFSET)
&& 0x07 == MC_CSC_MEMTYPE_SSRAM)
{
mc->tms[0] = MC_TMS_SSRAM_VALID;
}
else if ((mc->csc[0] >> MC_CSC_MEMTYPE_OFFSET)
&& 0x07 == MC_CSC_MEMTYPE_SYNC)
{
mc->tms[0] = MC_TMS_SYNC_VALID;
}
 
/* Grab control over all the devices we are destined to control */
cur = mc_areas;
prev = NULL;
while (cur)
{
if (cur->mc == mc->index)
{
if (prev)
prev->next = cur->next;
else
mc_areas = cur->next;
prev = cur;
tmp = cur->next;
cur->next = mc->mc_areas;
mc->mc_areas = cur;
cur = tmp;
}
else
{
prev = cur;
cur = cur->next;
}
}
 
for (cur = mc->mc_areas; cur; cur = cur->next)
set_mem_valid (cur->mem, 0);
 
set_csc_tms (0, mc->csc[0], mc->tms[0], mc);
}
 
/*---------------------------------------------------------------------------*/
/*!Free all allocated memory */
/*---------------------------------------------------------------------------*/
void
mc_done ()
{
while (NULL != mc_areas)
{
struct mc_area *next = mc_areas->next;
 
free (mc_areas);
mc_areas = next;
}
} /* mc_done () */
 
 
void
mc_status (void *dat)
{
struct mc *mc = dat;
int i;
 
PRINTF ("\nMemory Controller at 0x%" PRIxADDR ":\n", mc->baseaddr);
PRINTF ("POC: 0x%" PRIx32 "\n", mc->poc);
PRINTF ("BAS: 0x%" PRIx32 "\n", mc->ba_mask);
PRINTF ("CSR: 0x%" PRIx32 "\n", mc->csr);
 
for (i = 0; i < N_CE; i++)
{
PRINTF ("CE %02d - CSC: 0x%" PRIx32 " TMS: 0x%" PRIx32 "\n", i,
mc->csc[i], mc->tms[i]);
}
}
 
/*--------------------------------------------[ Peripheral<->MC interface ]---*/
/* Registers some memory to be under the memory controllers control */
void
mc_reg_mem_area (struct dev_memarea *mem, unsigned int cs, int mc)
{
struct mc_area *new = malloc (sizeof (struct mc_area));
 
if (NULL == new)
{
fprintf (stderr, "Out-of-memory\n");
exit (-1);
}
 
new->cs = cs;
new->mem = mem;
new->mc = mc;
 
new->next = mc_areas;
 
mc_areas = new;
}
 
/*-----------------------------------------------------[ MC configuration ]---*/
static void
mc_enabled (union param_val val, void *dat)
{
struct mc *mc = dat;
mc->enabled = val.int_val;
}
 
static void
mc_baseaddr (union param_val val, void *dat)
{
struct mc *mc = dat;
mc->baseaddr = val.addr_val;
}
 
 
/*---------------------------------------------------------------------------*/
/*!Set the power on configuration state
 
Only the bottom 4 bits are signficant. Other bits are truncated with a
warning.
 
@param[in] val The value to use
@param[in] dat The config data structure */
/*---------------------------------------------------------------------------*/
static void
mc_poc (union param_val val,
void *dat)
{
struct mc *mc = dat;
 
if (val.int_val > 0xf)
{
fprintf (stderr, "Warning: memory controller PoC > 4 bits: truncated\n");
}
 
mc->poc = val.int_val & 0xf;
 
} /* mc_poc() */
 
 
static void
mc_index (union param_val val, void *dat)
{
struct mc *mc = dat;
mc->index = val.int_val;
}
 
/*---------------------------------------------------------------------------*/
/*!Initialize a new memory controller configuration
 
ALL parameters are set explicitly to default values. */
/*---------------------------------------------------------------------------*/
static void *
mc_sec_start ()
{
struct mc *new = malloc (sizeof (struct mc));
 
if (!new)
{
fprintf (stderr, "Peripheral MC: Run out of memory\n");
exit (-1);
}
 
new->enabled = 1;
new->baseaddr = 0;
new->poc = 0;
new->index = 0;
 
new->mc_areas = NULL;
 
return new;
}
 
static void
mc_sec_end (void *dat)
{
struct mc *mc = dat;
struct mem_ops ops;
 
if (!mc->enabled)
{
free (dat);
return;
}
 
/* FIXME: Check to see that the index given to this mc is unique */
 
mc->next = mcs;
mcs = mc;
 
memset (&ops, 0, sizeof (struct mem_ops));
 
ops.readfunc32 = mc_read_word;
ops.writefunc32 = mc_write_word;
ops.write_dat32 = dat;
ops.read_dat32 = dat;
 
/* FIXME: Correct delays? */
ops.delayr = 2;
ops.delayw = 2;
 
reg_mem_area (mc->baseaddr, MC_ADDR_SPACE, 1, &ops);
reg_sim_reset (mc_reset, dat);
reg_sim_stat (mc_status, dat);
}
 
void
reg_mc_sec (void)
{
struct config_section *sec =
reg_config_sec ("mc", mc_sec_start, mc_sec_end);
 
reg_config_param (sec, "enabled", paramt_int, mc_enabled);
reg_config_param (sec, "baseaddr", paramt_addr, mc_baseaddr);
reg_config_param (sec, "POC", paramt_int, mc_poc);
reg_config_param (sec, "index", paramt_int, mc_index);
}
mc.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: atadevice-cmdi.c =================================================================== --- atadevice-cmdi.c (nonexistent) +++ atadevice-cmdi.c (revision 1765) @@ -0,0 +1,1163 @@ +/* atadevice_cmdi.c -- ATA Device simulation + Command interpreter for the simulated harddisk. + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* For fun, count the number of FIXMEs :-( */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" + +/* Package includes */ +#include "atadevice-cmdi.h" +#include "atahost.h" +#include "atacmd.h" +#include "debug.h" +#include "sched.h" + + +DEFAULT_DEBUG_CHANNEL (ata); + +/* FIXME: If device0 is not selected and then an interrupt occurs and + * then it is selected, the interrupt should be delivered, but I just drop it + * (same goes for device 1). */ +static void +ata_cmd_complete (void *dat) +{ + struct ata_device *dev = dat; + + TRACE ("Cmd completed intrq: %i, dev: %i\n", dev->sigs.intrq, + dev->internals.dev ? 1 : 0); + + dev->regs.status &= ~ATA_SR_BSY; + + if (dev->regs.device_control & ATA_DCR_IEN) + return; + + if ((dev->regs.device_head & ATA_DHR_DEV) != dev->internals.dev) + return; + + if (dev->sigs.intrq) + return; + + dev->sigs.intrq = 1; + ata_int (dev->internals.host); +} + +static void +ata_set_sect (struct ata_device *dev, uint32_t sect) +{ + uint16_t cyl; + + dev->regs.device_head &= ~ATA_DHR_H; + if (dev->regs.device_head & ATA_DHR_LBA) + { + dev->regs.sector_number = sect & 0xff; + dev->regs.cylinder_low = (sect >> 8) & 0xff; + dev->regs.cylinder_high = (sect >> 16) & 0xff; + dev->regs.device_head |= (sect >> 24) & 0xf; + } + else + { + cyl = sect / (dev->conf.heads * dev->conf.sectors); + dev->regs.cylinder_low = cyl & 0xff; + dev->regs.cylinder_high = (cyl >> 8) & 0xff; + + cyl = sect % (dev->conf.heads * dev->conf.sectors); + dev->regs.sector_number = (cyl % dev->conf.sectors) + 1; + dev->regs.device_head |= (cyl / dev->conf.sectors) & 0xf; + } +} + +/* Returns the concatenated lba address from the values in the addr regs */ +static uint32_t +ata_calc_lba (struct ata_device *dev) +{ + uint32_t lba; + + /* check if we are using CHS or LBA translation, fill in the bits */ + if (dev->regs.device_head & ATA_DHR_LBA) + { + /* we are using LBA translation */ + lba = (dev->regs.device_head & ATA_DHR_H) << 24 | + (dev->regs.cylinder_high) << 16 | + (dev->regs.cylinder_low) << 8 | dev->regs.sector_number; + } + else + { + /* we are using CHS translation, calculate lba address */ + lba = (dev->regs.cylinder_high << 16) | dev->regs.cylinder_low; + lba *= dev->internals.heads_per_cylinder; + lba += dev->regs.device_head & ATA_DHR_H; + lba *= dev->internals.sectors_per_track; + lba += dev->regs.sector_number; + lba -= 1; + } + return lba; +} + +/* Reads a sector from the device */ +static void +ata_read_sect (struct ata_device *dev) +{ + if (!dev->internals.nr_sect) + return; + + TRACE ("Reading sector from %" PRId32 "\n", dev->internals.lba); + + /* set the file-positon pointer to the start of the sector */ + fseek (dev->conf.stream, dev->internals.lba, SEEK_SET); + + /* get the bytes from the stream */ + fread (dev->internals.dbuf, BYTES_PER_SECTOR, 1, dev->conf.stream); + + /* set status register bits */ + dev->regs.status = ATA_SR_DRDY | ATA_SR_DRQ; + + /* reset the databuffer */ + dev->internals.dbuf_cnt = BYTES_PER_SECTOR / 2; //Words, not bytes + dev->internals.dbuf_ptr = dev->internals.dbuf; + + dev->internals.lba += BYTES_PER_SECTOR; + dev->internals.nr_sect--; + + SCHED_ADD (ata_cmd_complete, dev, 400000); +} + +/* Writes a sector to the device */ +static void +ata_write_sect (struct ata_device *dev) +{ + if (!dev->internals.nr_sect) + { + dev->regs.status = ATA_SR_DRDY; + return; + } + + TRACE ("Writeing sector to %" PRId32 "\n", dev->internals.lba); + + /* set the file-positon pointer to the start of the sector */ + fseek (dev->conf.stream, dev->internals.lba, SEEK_SET); + + /* get the bytes from the stream */ + fwrite (dev->internals.dbuf, BYTES_PER_SECTOR, 1, dev->conf.stream); + + /* set status register bits */ + dev->regs.status = ATA_SR_DRDY | ATA_SR_DRQ | ATA_SR_DSC | ATA_SR_BSY; + + /* reset the databuffer */ + dev->internals.dbuf_cnt = BYTES_PER_SECTOR / 2; //Words, not bytes + dev->internals.dbuf_ptr = dev->internals.dbuf; + + dev->internals.lba += BYTES_PER_SECTOR; + if (!--dev->internals.nr_sect) + dev->regs.status = ATA_SR_DRDY | ATA_SR_DSC | ATA_SR_BSY; + + SCHED_ADD (ata_cmd_complete, dev, 40000); +} + + +/* + A T A _ S E T _ D E V I C E _ S I G N A T U R E + + called whenever a command needs to signal the device type (packet, non-packet) +*/ +static void +ata_set_device_signature (struct ata_device *device, int packet) +{ + if (packet) + { + /* place PACKET Command feature set signature in register block */ + device->regs.sector_count = 0x01; + device->regs.sector_number = 0x01; + device->regs.cylinder_low = 0x14; + device->regs.cylinder_high = 0xEB; + } + else + { + /* place NON_PACKET Command feature set signature in register block */ + device->regs.sector_count = 0x01; + device->regs.sector_number = 0x01; + device->regs.cylinder_low = 0x00; + device->regs.cylinder_high = 0x00; + device->regs.device_head = 0x00; + } +} + + +/* + A T A _ E X E C U T E _ D E V I C E _ D I A G N O S T I C S +*/ +void +ata_execute_device_diagnostics_cmd (struct ata_device *device) +{ + /* print debug information */ + TRACE ("executing command 'execute_device_diagnostics'\n"); + + /* clear SRST bit, if set */ + device->regs.device_control &= ~ATA_DCR_RST; + + /* content of features register is undefined */ + + /* + set device error register + Device0: 0x01 = Device0 passed & Device1 passed/not present + Device1: 0x01 = Device1 passed + */ + device->regs.error = 0x01; + /* something about DASP- and error_register_bit7 */ + /* if device1 is not present or if device1 is present and passed */ + /* diagnostics, than bit7 should be cleared. */ + /* This means we always clear bit7 */ + + + /* check if device implements packet protocol */ + if (device->conf.packet) + { + /* place PACKET command feature set signature in register block */ + ata_set_device_signature (device, 1); + + device->regs.status &= 0xf8; + + if (device->regs.command == DEVICE_RESET) + device->regs.device_head = device->regs.device_head & ATA_DHR_LBA; + else + device->regs.device_head = 0x00; + } + else + { + /* place NON_PACKET Command feature set signature in register block */ + ata_set_device_signature (device, 0); + + device->regs.status &= 0x82; + } + + + /* we passed diagnostics, so set the PDIAG-line */ + device->sigs.pdiago = 1; +} + + +/* + A T A _ D E V I C E _ R E S E T +*/ +static void +ata_device_reset_cmd (struct ata_device *device) +{ + /* print debug information */ + TRACE ("executing command 'device reset'\n"); + + if (!device->conf.packet) + WARN ("executing DEVICE_RESET on non-packet device."); + + ata_execute_device_diagnostics_cmd (device); +} + + +/* + A T A _ I D E N T I F Y _ D E V I C E +*/ +static void +ata_identify_device_cmd (struct ata_device *device) +{ + unsigned char *chksum_buf, chksum; + unsigned short *buf; + int n; + unsigned int tmp; + + /* print debug information */ + TRACE ("ata_device executing command 'identify device'\n"); + + /* reset databuffer */ + device->internals.dbuf_cnt = 256; + device->internals.dbuf_ptr = device->internals.dbuf; + device->internals.end_t_func = NULL; + + buf = device->internals.dbuf; + chksum_buf = (unsigned char *) buf; + + /* + if number_of_available_sectors (==device->size / BYTES_PER_SECTOR) < 16,514,064 then + support CHS translation where: + LBA = ( ((cylinder_number*heads_per_cylinder) +head_number) *sectors_per_track ) +sector_number -1; + + Cylinders : 1-255 (or max.cylinders) + Heads : 0-15 (or max.heads ) + Sectors : 0-65535 (or max.sectors ) + */ + + /* + 1) Word 1 shall contain the number of user-addressable logical cylinders in the default CHS + translation. If the content of words (61:60) is less than 16,514,064 then the content of word 1 + shall be greater than or equal to one and less than or equal to 65,535. If the content of words + (61:60) is greater than or equal to 16,514,064 then the content of + word 1 shall be equal to 16,383. + 2) Word 3 shall contain the number of user-addressable logical heads in the default CHS + translation. The content of word 3 shall be greater than or equal to one and less than or equal to + 16. For compatibility with some BIOSs, the content of word 3 may be equal to 15 if the content of + word 1 is greater than 8192. + 3) Word 6 shall contain the number of user-addressable logical sectors in the default CHS + translation. The content of word 6 shall be greater than or equal to one and less than or equal to + 63. + 4) [(The content of word 1) * (the content of word 3) * (the content of word 6)] shall be less than or + equal to 16,514,064 + 5) Word 54 shall contain the number of user-addressable logical cylinders in the current CHS + translation. The content of word 54 shall be greater than or equal to one and less than or + equal to 65,535. After power-on of after a hardware reset the content of word 54 shall be equal to + the content of word 1. + 6) Word 55 shall contain the number of user-addressable logical heads in the current CHS + translation. The content of word 55 shall be greater than or equal to one and less than or equal + to 16. After power-on or after a hardware reset the content of word 55 shall equal the content of + word 3. + 7) Word 56 shall contain the user-addressable logical sectors in the current CHS + translation. The content of word 56 should be equal to 63 for compatibility with all BIOSs. + However, the content of word 56 may be greater than or equal to one and less than or equal to + 255. At power-on or after a hardware reset the content of word 56 shall equal the content of + word 6. + 8) Words (58:57) shall contain the user-addressable capacity in sectors for the current CHS + translation. The content of words (58:57) shall equal [(the content of word 54) * (the content of + word 55) * (the content of word 56)] The content of words (58:57) shall be less than or equal to + 16,514,064. The content of words (58:57) shall be less than or equal to the content of words + (61:60). + 9) The content of words 54, 55, 56, and (58:57) may be affected by the host issuing an INITIALIZE + DEVICE PARAMETERS command. + 10)If the content of words (61:60) is greater than 16,514,064 and if the device does not support CHS + addressing, then the content of words 1, 3, 6, 54, 55, 56, and (58:57) shall equal zero. If the + content of word 1, word 3, or word 6 equals zero, then the content of words 1, 3, 6, 54, 55, 56, + and (58:57) shall equal zero. + 11)Words (61:60) shall contain the total number of user-addressable sectors. The content of words + (61:60) shall be greater than or equal to one and less than or equal to 268,435,456. + 12)The content of words 1, 54, (58:57), and (61:60) may be affected by the host issuing a SET MAX + ADDRESS command. + */ + + + /* check if this is a NON-PACKET device */ + if (device->conf.packet) + { + /* + This is a PACKET device. + Respond by placing PACKET Command feature set signature in block registers. + Abort command. + */ + TRACE ("'identify_device' command: This is a PACKET device\n"); + + ata_set_device_signature (device, 1); + device->regs.status = ATA_SR_ERR; + device->regs.error = ATA_ERR_ABT; + } + else + { + /* start filling buffer */ + + /* + word 0: General configuration + 15 : 0 = ATA device + 14-8: retired + 7 : 1 = removable media device (not set) + 6 : 1 = not-removable controller and/or device (set) + 5-0 : retired and/or always set to zero + */ + *buf++ = 0x0040; + + /* + word 1: Number of logical cylinders + + >=1, <= 65535 + */ + if ((tmp = device->conf.size_sect) >= 16514064) + *buf++ = 16383; + else + if ((tmp /= (device->conf.heads + 1) * device->conf.sectors) > 65535) + *buf++ = 65535; + else + *buf++ = tmp; + + /* + word 2: Specific configuration + + 0x37c8: Device requires SET_FEATURES subcommand to spinup after power-on + and IDENTIFY_DEVICE response is incomplete + 0x738c: Device requires SET_FEATURES subcommand to spinup after power-on + and IDENTIFY_DEVICE response is complete + 0x8c73: Device does not require SET_FEATURES subcommand to spinup after power-on + and IDENTIFY_DEVICE response is incomplete + 0xc837: Device does not require SET_FEATURES subcommand to spinup after power-on + and IDENTIFY_DEVICE response is complete + + pick-one + */ + *buf++ = 0xc837; + + /* + word 3: Number of logical heads + + >= 1, <= 16 + + set to 15 if word1 > 8192 (BIOS compatibility) + */ + *buf++ = device->conf.heads; + + /* + word 5-4: retired + */ + buf += 2; + + /* + word 6: Number of logical sectors per logical track + + >= 1, <= 63 + */ + *buf++ = device->conf.sectors; + + /* + word 8-7: Reserved by the CompactFLASH association + */ + buf += 2; + + /* + word 9: retired + */ + buf++; + + /* + word 19-10: Serial number (ASCII) + */ + /* " www.opencores.org " */ + *buf++ = (' ' << 8) | 'w'; + *buf++ = ('w' << 8) | 'w'; + *buf++ = ('.' << 8) | 'o'; + *buf++ = ('p' << 8) | 'e'; + *buf++ = ('n' << 8) | 'c'; + *buf++ = ('o' << 8) | 'r'; + *buf++ = ('e' << 8) | 's'; + *buf++ = ('.' << 8) | 'o'; + *buf++ = ('r' << 8) | 'g'; + *buf++ = (' ' << 8) | ' '; + + /* + word 22 : obsolete + word 21-20: retired + */ + buf += 3; + + /* + word 26-23: Firmware revision + */ + strncpy ((char *) buf, device->conf.firmware, 8); + buf += 4; + + /* + word 46-27: Model number + */ + /* " ata device model (C)Richard Herveille " */ + *buf++ = (' ' << 8) | 'a'; + *buf++ = ('t' << 8) | 'a'; + *buf++ = (' ' << 8) | 'd'; + *buf++ = ('e' << 8) | 'v'; + *buf++ = ('i' << 8) | 'c'; + *buf++ = ('e' << 8) | ' '; + *buf++ = ('m' << 8) | 'o'; + *buf++ = ('d' << 8) | 'e'; + *buf++ = ('l' << 8) | ' '; + *buf++ = (' ' << 8) | '('; + *buf++ = ('C' << 8) | ')'; + *buf++ = ('R' << 8) | 'i'; + *buf++ = ('c' << 8) | 'h'; + *buf++ = ('a' << 8) | 'r'; + *buf++ = ('d' << 8) | ' '; + *buf++ = ('H' << 8) | 'e'; + *buf++ = ('r' << 8) | 'v'; + *buf++ = ('e' << 8) | 'i'; + *buf++ = ('l' << 8) | 'l'; + *buf++ = ('e' << 8) | ' '; + + /* + word 47: + 15-8: 0x80 + 7-0: 0x00 reserved + 0x01-0xff maximum number of sectors to be transfered + per interrupt on a READ/WRITE MULTIPLE command + */ + *buf++ = 0x8001; + + /* + word 48: reserved + */ + buf++; + + /* + word 49: Capabilities + 15-14: reserved for IDENTIFY PACKET DEVICE + 13 : 1=standby timers are supported + 0=standby timers are handled by the device FIXME + 12 : reserved for IDENTIFY PACKET DEVICE + 11 : 1=IORDY supported + 0=IORDY may be supported + 10 : 1=IORDY may be disabled + 9 : set to one + 8 : set to one + 7-0 : retired + */ + *buf++ = 0x0f00; + + /* + word 50: Capabilities + 15 : always cleared to zero + 14 : always set to one + 13-1: reserved + 0 : 1=Device specific standby timer minimum value FIXME + */ + *buf++ = 0x4000; + + /* + word 52-51: obsolete + */ + buf += 2; + + /* + word 53: + 15-3: Reserved + 2 : 1=value in word 88 is valid + 0=value in word 88 is not valid + 1 : 1=value in word 64-70 is valid + 0=value in word 64-70 is not valid + 0 : 1=value in word 54-58 is valid + 0=value in word 54-58 is not valid + */ + *buf++ = 0x0007; + + + /* + word 54: number of current logical cylinders (0-65535) + */ + if ((tmp = device->conf.size_sect) > 16514064) + tmp = 16514064; + + tmp /= (device->internals.heads_per_cylinder + + 1) * (device->internals.sectors_per_track); + if (tmp > 65535) + *buf++ = 65535; + else + *buf++ = tmp; + + /* + word 55: number of current logical heads, (0-15) + */ + *buf++ = device->internals.heads_per_cylinder + 1; + + /* + word 56: number of current logical sectors per track (1-255) + */ + *buf++ = device->internals.sectors_per_track; + + /* + word 58-57: current capacity in sectors + */ + tmp = *(buf - 3) * *(buf - 2) * *(buf - 1); + *buf++ = tmp >> 16; + *buf++ = tmp & 0xffff; + + /* + word 59: + 15-9: reserved + 8 : 1=multiple sector setting is valid + 7-0 : current setting for number of sectors to be transfered + per interrupt on a READ/WRITE MULTIPLE command + */ + *buf++ = 0x0001; // not really a FIXME + + /* + word 60-61: Total number of user addressable sectors (LBA only) + */ + *buf++ = device->conf.size_sect; + *buf++ = device->conf.size_sect >> 16; + + /* + word 62: obsolete + */ + buf++; + + /* FIXME + word 63: DMA settings + 15-11: Reserved + 10 : 1=Multiword DMA Mode 2 is selected + 0=Multiword DMA Mode 2 is not selected + 9 : 1=Multiword DMA Mode 1 is selected + 0=Multiword DMA Mode 1 is not selected + 8 : 1=Multiword DMA Mode 0 is selected + 0=Multiword DMA Mode 0 is not selected + 7-3 : Reserved + 2 : Multiword DMA Mode 2 and below are supported + 1 : Multiword DMA Mode 1 and below are supported + 0 : Multiword DMA Mode 0 is supported + */ + *buf = 0; + if (device->conf.mwdma >= 0) + *buf |= 0x1; + if (device->conf.mwdma >= 1) + *buf |= 0x2; + if (device->conf.mwdma >= 2) + *buf |= 0x4; + + buf++; + + /* + word 64: + 15-8: reserved + 7-0: Advanced PIO modes supported + + 7-2: reserved + 1 : PIO mode4 supported + 0 : PIO mode3 supported + */ + *buf = 0; + if (device->conf.pio >= 3) + *buf |= 0x1; + if (device->conf.pio >= 4) + *buf |= 0x2; + buf++; + + /* + word 65: Minimum Multiword DMA transfer cycle time per word (nsec) + */ + *buf++ = MIN_MWDMA_CYCLE_TIME; + + /* + word 66: Manufacturer's recommended Multiword DMA transfer cycle time per word (nsec) + */ + *buf++ = RECOMMENDED_MWDMA_CYCLE_TIME; + + + /* + word 67: Minimum PIO transfer cycle time per word (nsec), without IORDY flow control + */ + *buf++ = MIN_PIO_CYCLE_TIME_NO_IORDY; + + /* + word 68: Minimum PIO transfer cycle time per word (nsec), with IORDY flow control + */ + *buf++ = MIN_PIO_CYCLE_TIME_IORDY; + + /* + word 69-70: reserved for future command overlap and queueing + 71-74: reserved for IDENTIFY PACKET DEVICE command + */ + buf += 6; + + /* + word 75: Queue depth + 15-5: reserved + 4-0: queue depth -1 + */ + *buf++ = SUPPORT_READ_WRITE_DMA_QUEUED ? QUEUE_DEPTH : 0x0000; + + /* + word 76-79: reserved + */ + buf += 4; + + /* + word 80: MAJOR ATA version + We simply report that we do not report a version + + You can also set bits 5-2 to indicate compliancy to + ATA revisions 5-2 (1 & 0 are obsolete) + */ + *buf++ = 0x0000; + + /* + word 81: MINOR ATA version + We report ATA/ATAPI-5 T13 1321D revision 3 (0x13) + */ + *buf++ = 0x0013; + + /* + word 82: Command set supported + */ + *buf++ = 0 << 15 | /* obsolete */ + SUPPORT_NOP_CMD << 14 | SUPPORT_READ_BUFFER_CMD << 13 | SUPPORT_WRITE_BUFFER_CMD << 12 | 0 << 11 | /* obsolete */ + SUPPORT_HOST_PROTECTED_AREA << 10 | SUPPORT_DEVICE_RESET_CMD << 9 | SUPPORT_SERVICE_INTERRUPT << 8 | SUPPORT_RELEASE_INTERRUPT << 7 | SUPPORT_LOOKAHEAD << 6 | SUPPORT_WRITE_CACHE << 5 | 0 << 4 | /* cleared to zero */ + SUPPORT_POWER_MANAGEMENT << 3 | + SUPPORT_REMOVABLE_MEDIA << 2 | + SUPPORT_SECURITY_MODE << 1 | SUPPORT_SMART << 0; + + /* + word 83: Command set supported + */ + *buf++ = 0 << 15 | /* cleared to zero */ + 1 << 14 | /* set to one */ + 0 << 9 | /* reserved */ + SUPPORT_SET_MAX << 8 | 0 << 7 | /* reserved for */ + /* project 1407DT */ + SET_FEATURES_REQUIRED_AFTER_POWER_UP << 6 | + SUPPORT_POWER_UP_IN_STANDBY_MODE << 5 | + SUPPORT_REMOVABLE_MEDIA_NOTIFICATION << 4 | + SUPPORT_APM << 3 | + SUPPORT_CFA << 2 | + SUPPORT_READ_WRITE_DMA_QUEUED << 1 | SUPPORT_DOWNLOAD_MICROCODE << 0; + + /* + word 84: Command set/feature supported + */ + *buf++ = 0 << 15 | /* cleared to zero */ + 1 << 14 /* set to one */ + ; /* 0-13 reserved */ + + /* + word 85: Command set enabled FIXME + */ + *buf++ = 0 << 15 | /* obsolete */ + SUPPORT_NOP_CMD << 14 | SUPPORT_READ_BUFFER_CMD << 13 | SUPPORT_WRITE_BUFFER_CMD << 12 | 0 << 11 | /* obsolete */ + SUPPORT_HOST_PROTECTED_AREA << 10 | SUPPORT_DEVICE_RESET_CMD << 9 | SUPPORT_SERVICE_INTERRUPT << 8 | SUPPORT_RELEASE_INTERRUPT << 7 | SUPPORT_LOOKAHEAD << 6 | SUPPORT_WRITE_CACHE << 5 | 0 << 4 | /* cleared to zero */ + SUPPORT_POWER_MANAGEMENT << 3 | + SUPPORT_REMOVABLE_MEDIA << 2 | + SUPPORT_SECURITY_MODE << 1 | SUPPORT_SMART << 0; + + /* + word 86: Command set enables + */ + *buf++ = 0 << 9 | /* 15-9 reserved */ + SUPPORT_SET_MAX << 8 | 0 << 7 | /* reserved for */ + /* project 1407DT */ + SET_FEATURES_REQUIRED_AFTER_POWER_UP << 6 | + SUPPORT_POWER_UP_IN_STANDBY_MODE << 5 | + SUPPORT_REMOVABLE_MEDIA_NOTIFICATION << 4 | + SUPPORT_APM << 3 | + SUPPORT_CFA << 2 | + SUPPORT_READ_WRITE_DMA_QUEUED << 1 | SUPPORT_DOWNLOAD_MICROCODE << 0; + + /* + word 87: Command set/feature supported + */ + *buf++ = 0 << 15 | /* cleared to zero */ + 1 << 14 /* set to one */ + ; /* 0-13 reserved */ + + /* + word 88: UltraDMA section + 15-13: reserved + 12 : 1=UltraDMA Mode 4 is selected + 0=UltraDMA Mode 4 is not selected + 10 : 1=UltraDMA Mode 3 is selected + 0=UltraDMA Mode 3 is not selected + 10 : 1=UltraDMA Mode 2 is selected + 0=UltraDMA Mode 2 is not selected + 9 : 1=UltraDMA Mode 1 is selected + 0=UltraDMA Mode 1 is not selected + 8 : 1=UltraDMA Mode 0 is selected + 0=UltraDMA Mode 0 is not selected + 7-5 : Reserved + 4 : UltraDMA Mode 4 and below are supported + 3 : UltraDMA Mode 3 and below are supported + 2 : UltraDMA Mode 2 and below are supported + 1 : UltraDMA Mode 1 and below are supported + 0 : UltraDMA Mode 0 is supported + + Because the OCIDEC cores currently do not support + UltraDMA we set all bits to zero + */ + *buf++ = 0; + + /* + word 89: Security sector erase unit completion time + + For now we report a 'value not specified'. + */ + *buf++ = 0x0000; // not really a FIXME + + /* + word 90: Enhanced security erase completion time + + For now we report a 'value not specified'. + */ + *buf++ = 0x0000; // not really a FIXME + + /* + word 91: Current advanced power management value + + For now set it to zero. + */ + *buf++ = 0x0000; // FIXME + + /* + word 92: Master Password Revision Code. + We simply report that we do not support this. + */ + *buf++ = 0x0000; + + /* + word 93: Hardware reset result + */ + if (device->internals.dev) + { + /* this is device1, clear device0 bits */ + *buf++ = 0 << 15 | 1 << 14 | 0 << 13 | /* CBLIBD level (1=Vih, 0=Vil) */ + /* 12-8 Device 1 hardware reset result */ + 0 << 12 | /* reserved */ + device->sigs.pdiago << 11 | /* 1: Device1 did assert PDIAG */ + /* 0: Device1 did not assert PDIAG */ + 3 << 9 | /* Device1 determined device number by */ + /* 00: reserved */ + /* 01: a jumper was used */ + /* 10: the CSEL signal was used */ + /* 11: some other or unknown method was used */ + 1 << 8 /* set to one */ + ; + } + else + { /* FIXME bit 6 */ + /* this is device0, clear device1 bits */ + *buf++ = 0 << 7 | /* reserved */ + 0 << 6 | /* 1: Device0 responds for device 1 */ + /* 0: Device0 does not respond for device1 */ + device->sigs.daspi << 5 | /* 1: Device0 did detected DASP assertion */ + /* 0: Device0 did not detect DASP assertion */ + device->sigs.pdiagi << 4 | /* Device0 did detect PDIAG assertion */ + /* Device0 did not detect PDIAG assertion */ + 1 << 3 | /* Device0 did pass diagnostics */ + 3 << 1 | /* Device0 determined device number by */ + /* 00: reserved */ + /* 01: a jumper was used */ + /* 10: the CSEL signal was used */ + /* 11: some other or unknown method was used */ + 1 << 0 /* set to one */ + ; + } + + /* + word 94-126: Reserved + */ + buf += 33; + + /* + word 127: Removable Media Status Notification feature set support + 15-2: reserved + 1-0: 00 Removable media Status Notification not supported + 01 Removable media Status Notification supported + 10 reserved + 11 reserved + */ + *buf++ = SUPPORT_REMOVABLE_MEDIA_NOTIFICATION; + + /* + word 128: Security status + 15-9: reserved + 8 : Security level, 0=high, 1=maximum + 7-6 : reserved + 5 : 1=enhanced security erase supported + 4 : 1=security count expired + 3 : 1=security frozen + 2 : 1=security locked + 1 : 1=security enabled + 0 : security supported + + for now we do not support security, set is to zero + */ + *buf++ = 0; + + /* + word 129-159: Vendor specific + */ + buf += 31; + + /* + word 160: CFA power mode 1 + 15 : Word 160 supported + 14 : reserved + 13 : CFA power mode 1 is required for one or more commands + 12 : CFA power mode 1 disabled + 11-0: Maximum current in mA + */ + *buf++ = 0; + + /* + word 161-175: Reserved for the CompactFLASH Association + */ + buf += 15; + + /* + word 176-254: reserved + */ + buf += 79; + + /* + word 255: Integrity word + 15-8: Checksum + 7-0 : Signature + */ + // set signature to indicate valid checksum + *buf = 0x00a5; + + // calculate checksum + chksum = 0; + for (n = 0; n < 511; n++) + chksum += *chksum_buf++; + + *buf = ((0 - chksum) << 8) | 0x00a5; + + /* set status register bits */ + device->regs.status = ATA_SR_DRDY | ATA_SR_DRQ; + } +} + + +/* + A T A _ I N I T I A L I Z E _ D E V I C E _ P A R A M E T E R S +*/ +static void +ata_initialize_device_parameters_cmd (struct ata_device *device) +{ + /* print debug information */ + TRACE ("executing command 'initialize device parameters'\n"); + + device->internals.sectors_per_track = device->regs.sector_count; + device->internals.heads_per_cylinder = device->regs.device_head & ATA_DHR_H; + + /* set status register bits */ + device->regs.status = ATA_SR_BSY | ATA_SR_DRDY; +} + + +/* + A T A _ R E A D _ S E C T O R S +*/ +static void +ata_read_sectors_cmd (struct ata_device *device) +{ + size_t sector_count; + uint32_t lba; + + /* print debug information */ + TRACE ("executing command 'read sectors'\n"); + + /* check if this is a NON-PACKET device */ + if (device->conf.packet) + { + /* + This is a PACKET device. + Respond by placing PACKET Command feature set signature in block registers. + Abort command. + */ + TRACE ("'identify_device' command: This is a PACKET device\n"); + + ata_set_device_signature (device, 1); + device->regs.status = ATA_SR_ERR | ATA_SR_DRDY; + device->regs.error = ATA_ERR_ABT; + return; + } + + /* get the sector count */ + if (device->regs.sector_count == 0) + sector_count = 256; + else + sector_count = device->regs.sector_count; + + lba = ata_calc_lba (device); + + TRACE ("Reading from lba %i, %i sectors\n", lba, sector_count); + + /* check if sector within bounds */ + if (lba >= device->conf.size_sect) + { + /* invalid sector address */ + /* set the status & error registers */ + TRACE ("Sector read out-of-bounds: %i >= %i\n", lba, + device->conf.size_sect); + device->regs.status = ATA_SR_DRDY | ATA_SR_ERR; + device->regs.error = ATA_ERR_IDNF; + return; + } + + /* go ahead, read the bytestream */ + lba *= BYTES_PER_SECTOR; + + device->internals.lba = lba; + device->internals.nr_sect = sector_count; + device->internals.end_t_func = ata_read_sect; + + ata_read_sect (device); +} + + + +/* + A T A _ R E A D _ N A T I V E _ M A X _ A D D R +*/ +static void +ata_read_native_max_addr (struct ata_device *dev) +{ + TRACE ("executing command 'read native max addr'\n"); + // FIXME: Left shift???? + ata_set_sect (dev, dev->conf.size << 11); + + dev->regs.status = ATA_SR_DRDY | ATA_SR_BSY; +} + +/* + A T A _ W R I T E _ S E C T O R S +*/ +static void +ata_write_sectors (struct ata_device *dev) +{ + size_t sector_count; + uint32_t lba; + + TRACE ("executing command 'write sectors'\n"); + + if (dev->conf.packet) + { + ata_set_device_signature (dev, 1); + dev->regs.status = ATA_SR_ERR | ATA_SR_DRDY; + dev->regs.error = ATA_ERR_ABT; + return; + } + + /* get the sector count */ + if (dev->regs.sector_count == 0) + sector_count = 256; + else + sector_count = dev->regs.sector_count; + + lba = ata_calc_lba (dev); + + TRACE ("Writeing to lba %i, %i sectors\n", lba, sector_count); + + /* check if sector within bounds */ + if (lba >= dev->conf.size_sect) + { + /* invalid sector address */ + /* set the status & error registers */ + TRACE ("Sector read out-of-bounds: %i >= %i\n", lba, + dev->conf.size_sect); + dev->regs.status = ATA_SR_DRDY | ATA_SR_ERR; + dev->regs.error = ATA_ERR_IDNF; + return; + } + + dev->internals.lba = lba * BYTES_PER_SECTOR; + dev->internals.nr_sect = sector_count; + + dev->internals.dbuf_cnt = BYTES_PER_SECTOR / 2; //Words, not bytes + dev->internals.dbuf_ptr = dev->internals.dbuf; + + dev->regs.status = ATA_SR_BSY | ATA_SR_DRDY | ATA_SR_DRQ; + dev->internals.end_t_func = ata_write_sect; +} + +/* + A T A _ S E T _ F E A T U R E S +*/ +static void +ata_set_features (struct ata_device *dev) +{ + switch (dev->regs.features) + { + case SET_TRANSFER_MODE_SECTOR_COUNT_REG: + /* FIXME: I don't have a clue as to what to do with this... */ + switch (dev->regs.sector_count >> 3) + { + case 0: /* Set default */ + break; + case 1: /* Set PIO mode */ + TRACE ("Setting device pio mode %d\n", + dev->regs.sector_count & 0x7); + break; + case 4: /* Set DMA mode */ + FIXME ("Set DMA mode to %d\n", dev->regs.sector_count & 0x7); + break; + case 8: /* Set UDMA mode */ + FIXME ("Set UDMA mode to %d\n", dev->regs.sector_count & 0x7); + break; + } + dev->regs.status = ATA_SR_DSC | ATA_SR_DRDY | ATA_SR_BSY; + break; + default: + dev->regs.error = ATA_ERR_ABT; + dev->regs.status = ATA_SR_ERR | ATA_SR_BSY | ATA_SR_DRDY; + FIXME ("Unknown set features sub-command %x\n", dev->regs.features); + } +} + + +int +ata_device_execute_cmd (struct ata_device *device) +{ + /*display debug information */ + TRACE ("command: 0x%02X\n", device->regs.command); + + /* execute the commands */ + switch (device->regs.command) + { + case DEVICE_RESET: + ata_device_reset_cmd (device); + SCHED_ADD (ata_cmd_complete, device, 4000000); + return 0; + + case EXECUTE_DEVICE_DIAGNOSTICS: + ata_execute_device_diagnostics_cmd (device); + SCHED_ADD (ata_cmd_complete, device, 4000000); + return 0; + + case IDENTIFY_DEVICE: + ata_identify_device_cmd (device); + /* FIXME: This should generate an interrupt, but linux is abit broken so + * it doesn't happen */ + //SCHED_ADD(ata_cmd_complete, device, 40000); + return 0; + + case INITIALIZE_DEVICE_PARAMETERS: + ata_initialize_device_parameters_cmd (device); + SCHED_ADD (ata_cmd_complete, device, 400000); + return 0; + + case READ_SECTORS: + ata_read_sectors_cmd (device); + /* PIO-in command -- Doesn't interrupt on completion */ + return 0; + + case READ_NATIVE_MAX_ADDRESS: + ata_read_native_max_addr (device); + SCHED_ADD (ata_cmd_complete, device, 40000); + return 0; + + case WRITE_SECTORS: + ata_write_sectors (device); + SCHED_ADD (ata_cmd_complete, device, 40000); + return 0; + + case SET_FEATURES: + ata_set_features (device); + SCHED_ADD (ata_cmd_complete, device, 4000); + return 0; + + default: + device->regs.error = ATA_ERR_ABT; + device->regs.status = ATA_SR_ERR | ATA_SR_BSY | ATA_SR_DRDY; + FIXME ("Unknown command %x\n", device->regs.command); + SCHED_ADD (ata_cmd_complete, device, 40000); + return -1; + } +} Index: Makefile.in =================================================================== --- Makefile.in (nonexistent) +++ Makefile.in (revision 1765) @@ -0,0 +1,630 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile -- Makefile for peripherals simulation +# +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# Copyright (C) 2008 Embecosm Limited +# +# Contributor Jeremy Bennett +# +# 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 3 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, see . + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = peripheral +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libperipheral_la_LIBADD = +am_libperipheral_la_OBJECTS = generic.lo 16450.lo dma.lo mc.lo eth.lo \ + crc32.lo gpio.lo vga.lo fb.lo ps2kbd.lo atahost.lo \ + atadevice.lo atadevice-cmdi.lo memory.lo +libperipheral_la_OBJECTS = $(am_libperipheral_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libperipheral_la_SOURCES) +DIST_SOURCES = $(libperipheral_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_DIR = @BUILD_DIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPU_ARCH = @CPU_ARCH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUGFLAGS = @DEBUGFLAGS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INCLUDES = @INCLUDES@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +LOCAL_DEFS = @LOCAL_DEFS@ +LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MAKE_SHELL = @MAKE_SHELL@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SUMVERSION = @SUMVERSION@ +TERMCAP_LIB = @TERMCAP_LIB@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = channels +noinst_LTLIBRARIES = libperipheral.la +libperipheral_la_SOURCES = generic.c \ + 16450.c \ + dma.c \ + mc.c \ + eth.c \ + crc32.c \ + gpio.c \ + vga.c \ + fb.c \ + ps2kbd.c \ + atahost.c \ + atadevice.c \ + atadevice-cmdi.c \ + memory.c \ + 16450.h \ + atacmd.h \ + generic.h \ + atadevice-cmdi.h \ + atadevice.h \ + atahost.h \ + crc32.h \ + dma-defs.h \ + dma.h \ + eth.h \ + fb.h \ + fields.h \ + gpio.h \ + mc.h \ + memory.h \ + ps2kbd.h \ + vga.h + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu peripheral/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu peripheral/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libperipheral.la: $(libperipheral_la_OBJECTS) $(libperipheral_la_DEPENDENCIES) + $(LINK) $(libperipheral_la_OBJECTS) $(libperipheral_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/16450.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atadevice-cmdi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atadevice.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atahost.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dma.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ps2kbd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + clean-noinstLTLIBRARIES ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: gpio.h =================================================================== --- gpio.h (nonexistent) +++ gpio.h (revision 1765) @@ -0,0 +1,33 @@ +/* gpio.h -- Definition of types and structures for the GPIO code + + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef GPIO__H +#define GPIO__H + +/* Function prototypes for external use */ +extern void reg_gpio_sec (); + +#endif /* GPIO__H */ Index: mc.h =================================================================== --- mc.h (nonexistent) +++ mc.h (revision 1765) @@ -0,0 +1,41 @@ +/* mc.h -- Simulation of Memory Controller + + Copyright (C) 2001 by Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef MC__H +#define MC__H + +/* Package includes */ +#include "abstract.h" + + +/* Prototypes for external use */ +extern void mc_done (); +extern void reg_mc_sec (); +extern void mc_reg_mem_area (struct dev_memarea *mem, + unsigned int cs, + int mc); + +#endif /* MC__H */
mc.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: atadevice-cmdi.h =================================================================== --- atadevice-cmdi.h (nonexistent) +++ atadevice-cmdi.h (revision 1765) @@ -0,0 +1,101 @@ +/* atadevice-cmdi.h -- ATA Device command interpreter + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef ATADEVICE_CMDI__H +#define ATADEVICE_CMDI__H + +/* Package includes */ +#include "atadevice.h" + + +/**********************************************************************/ +/* Define default CHS translation parameters */ +/* bytes per sector */ +#define BYTES_PER_SECTOR 512 + + +/**********************************************************************/ +/* Define DMA and PIO cycle times */ +/* define the minimum Multiword DMA cycle time per word (in nsec) */ +#define MIN_MWDMA_CYCLE_TIME 100 + +/* define the manufacturer's recommended Multiword DMA cycle time */ +#define RECOMMENDED_MWDMA_CYCLE_TIME 100 + +/* define the minimum PIO cycle time per word (in nsec), no IORDY */ +#define MIN_PIO_CYCLE_TIME_NO_IORDY 100 + +/* define the minimum PIO cycle time per word (in nsec), with IORDY */ +#define MIN_PIO_CYCLE_TIME_IORDY 100 + + +/**********************************************************************/ +/* Define supported command sets */ +/* 1=command is supported */ +/* 0=command is not (yet) supported */ +#define SUPPORT_NOP_CMD 0 +#define SUPPORT_READ_BUFFER_CMD 0 +#define SUPPORT_WRITE_BUFFER_CMD 0 +#define SUPPORT_HOST_PROTECTED_AREA 0 +#define SUPPORT_DEVICE_RESET_CMD 1 +#define SUPPORT_SERVICE_INTERRUPT 0 +#define SUPPORT_RELEASE_INTERRUPT 0 +#define SUPPORT_LOOKAHEAD 0 +#define SUPPORT_WRITE_CACHE 0 +#define SUPPORT_POWER_MANAGEMENT 0 +#define SUPPORT_REMOVABLE_MEDIA 0 +#define SUPPORT_SECURITY_MODE 0 +#define SUPPORT_SMART 0 +#define SUPPORT_SET_MAX 0 +#define SET_FEATURES_REQUIRED_AFTER_POWER_UP 0 +#define SUPPORT_POWER_UP_IN_STANDBY_MODE 0 +#define SUPPORT_REMOVABLE_MEDIA_NOTIFICATION 0 +#define SUPPORT_APM 0 +#define SUPPORT_CFA 0 +#define SUPPORT_READ_WRITE_DMA_QUEUED 0 +#define SUPPORT_DOWNLOAD_MICROCODE 0 + +/* +Queue depth defines the maximum queue depth supported by the device. +This includes all commands for which the command acceptance has occured +and command completion has not occured. This value is used for the DMA +READ/WRITE QUEUE command. + +QUEUE_DEPTH = actual_queue_depth -1 +*/ +#define QUEUE_DEPTH 0 + + +/* + ---------------- + -- Prototypes -- + ---------------- +*/ +int ata_device_execute_cmd(struct ata_device *device); + +void ata_execute_device_diagnostics_cmd(struct ata_device *device); + +#endif /* ATADEVICE_CMDI__H */ Index: channels/fd.h =================================================================== --- channels/fd.h (nonexistent) +++ channels/fd.h (revision 1765) @@ -0,0 +1,50 @@ +/* fd.h -- Declaration of functions for peripheral to + * communicate with host through file descriptors + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef FD__H +#define FD__H + +/*! Data structure to represent a channel through file descriptors */ +struct fd_channel +{ + int fdin; + int fdout; +}; + +/* Global data structures */ +extern struct channel_ops fd_channel_ops; + +/* Function prototypes for external use */ +extern int fd_read (void *data, + char *buffer, + int size); +extern int fd_write (void *data, + const char *buffer, + int size); + +#endif /* FD__H */ + Index: channels/xterm.c =================================================================== --- channels/xterm.c (nonexistent) +++ channels/xterm.c (revision 1765) @@ -0,0 +1,285 @@ +/* xterm.c -- Definition of functions and structures for + peripheral to communicate with host through an xterm. + Inspired from SWI-Prolog by Jan Wielemaker (GPL too) + even if there is really few in common. + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + 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 3 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, see . */ + + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_SYS_STROPTS_H +#include /* I_PUSH ioctl */ +#endif + +#if HAVE_BASENAME +#include /* basename() */ +#endif + +/* Package includes */ +#include "channel.h" +#include "generic.h" +#include "fd.h" + +/*! Data structure to represent the connection to the xterm */ +struct xterm_channel +{ + struct fd_channel fds; + int pid; + char **argv; +}; + +/* Forward declaration of static functions */ +static void xterm_close (void *data); +static void *xterm_init (const char *input); +static int xterm_open (void *data); + +/*! Global data structure with the xterm interface functions */ +struct channel_ops xterm_channel_ops = { + .init = xterm_init, + .open = xterm_open, + .close = xterm_close, + .read = fd_read, + .write = fd_write, + .free = generic_free, +}; + + +#if !(HAVE_BASENAME) +static char * +basename (const char *filename) +{ + char *p = strrchr (filename, '/'); + + return p ? p + 1 : (char *) filename; +} +#endif /* HAVE_BASENAME */ + +static void +xterm_close (void *data) +{ + struct xterm_channel *xt = data; + + if (!xt) + return; + + if (xt->fds.fdin != -1) + close (xt->fds.fdin); + + if (xt->pid != -1) + { + kill (xt->pid, SIGKILL); + waitpid (xt->pid, NULL, 0); + } + + if (xt->argv) + free (xt->argv); + + xt->fds.fdin = -1; + xt->fds.fdout = -1; + xt->pid = -1; + xt->argv = NULL; + +} + +#if defined(HAVE_ON_EXIT) +static void +xterm_exit (int i, void *data) +{ + xterm_close (data); +} +#endif + +#define MAX_XTERM_ARGS 100 +static void * +xterm_init (const char *input) +{ + struct xterm_channel *retval = malloc (sizeof (struct xterm_channel)); + if (retval) + { + int i; + char *arglist; + + retval->fds.fdin = -1; + retval->fds.fdout = -1; + retval->pid = -1; + +#if defined(HAVE_ON_EXIT) + /* reset cause exit(1), leaving an xterm opened */ + on_exit (xterm_exit, retval); +#endif + + i = 2; + arglist = (char *) input; + retval->argv = malloc (sizeof (char *) * MAX_XTERM_ARGS); + if (!retval->argv) + { + free (retval); + return NULL; + } + /* Assume xterm arguments are separated by whitespace */ + while ((retval->argv[i++] = strtok (arglist, " \t\n"))) + { + arglist = NULL; + if (i == MAX_XTERM_ARGS - 1) + { + free (retval); + return NULL; + } + } + + } + return (void *) retval; +} + + + +static int +xterm_open (void *data) +{ +#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME) + struct xterm_channel *xt = data; + int master, retval; + char *slavename; + struct termios termio; + char arg[64], *fin; + + if (!data) + { + errno = ENODEV; + return -1; + } + + master = open ("/dev/ptmx", O_RDWR); + + if (master < 0) + return -1; + + grantpt (master); + unlockpt (master); + slavename = (char *) ptsname (master); + + if (!slavename) + { + errno = ENOTTY; + goto closemastererror; + } + + xt->fds.fdout = xt->fds.fdin = open (slavename, O_RDWR); + if (xt->fds.fdout < 0) + goto closemastererror; + +#if HAVE_SYS_STROPTS_H + /* These modules must be pushed onto the stream for some non-Linux and + non-Cygwin operating systems. */ + retval = ioctl (xt->fds.fdin, I_PUSH, "ptem"); + if (retval < 0) + goto closeslaveerror; + + retval = ioctl (xt->fds.fdin, I_PUSH, "ldterm"); + if (retval < 0) + goto closeslaveerror; +#endif + + retval = tcgetattr (xt->fds.fdin, &termio); + if (retval < 0) + goto closeslaveerror; + termio.c_lflag &= ~ECHO; + retval = tcsetattr (xt->fds.fdin, TCSADRAIN, &termio); + if (retval < 0) + goto closeslaveerror; + + xt->pid = fork (); + + if (xt->pid == -1) + goto closeslaveerror; + + if (xt->pid == 0) + { + /* Ctrl-C on sim still kill the xterm, grrr */ + signal (SIGINT, SIG_IGN); + + fin = slavename + strlen (slavename) - 2; + if (strchr (fin, '/')) + { + sprintf (arg, "-S%s/%d", basename (slavename), master); + } + else + { + sprintf (arg, "-S%c%c%d", fin[0], fin[1], master); + } + xt->argv[0] = "xterm"; + xt->argv[1] = arg; + execvp ("xterm", xt->argv); + write (master, "\n", 1); + exit (1); + } + + do + retval = read (xt->fds.fdin, &arg, 1); + while (retval >= 0 && arg[0] != '\n'); + if (retval < 0) + goto closeslaveerror; + + termio.c_lflag |= ECHO; + retval = tcsetattr (xt->fds.fdin, TCSADRAIN, &termio); + + if (retval < 0) + goto closeslaveerror; + + return 0; + +closeslaveerror: + close (xt->fds.fdin); + +closemastererror: + close (master); + xt->pid = xt->fds.fdin = xt->fds.fdout = -1; + return -1; + +#else + /* I don't see how this stuff should be working on a system that doesn't know + grantpt(), unlockpt(), ptsname(). Mac OS X also does not have /dev/ptmx. + -hpanther + */ + return -1; +#endif +} Index: channels/Makefile.in =================================================================== --- channels/Makefile.in (nonexistent) +++ channels/Makefile.in (revision 1765) @@ -0,0 +1,490 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile -- Makefile for peripherals channels to host +# +# Copyright (C) 2002 Richard Prescott +# Copyright (C) 2008 Embecosm Limited +# +# Contributor Jeremy Bennett +# +# 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 3 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, see . + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = peripheral/channels +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libchannels_la_LIBADD = +am_libchannels_la_OBJECTS = channel.lo fd.lo file.lo generic.lo tcp.lo \ + tty.lo xterm.lo +libchannels_la_OBJECTS = $(am_libchannels_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libchannels_la_SOURCES) +DIST_SOURCES = $(libchannels_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_DIR = @BUILD_DIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPU_ARCH = @CPU_ARCH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUGFLAGS = @DEBUGFLAGS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INCLUDES = @INCLUDES@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +LOCAL_DEFS = @LOCAL_DEFS@ +LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MAKE_SHELL = @MAKE_SHELL@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SUMVERSION = @SUMVERSION@ +TERMCAP_LIB = @TERMCAP_LIB@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libchannels.la +libchannels_la_SOURCES = channel.c \ + fd.c \ + file.c \ + generic.c \ + tcp.c \ + tty.c \ + xterm.c \ + channel.h \ + fd.h \ + file.h \ + generic.h \ + tcp.h \ + tty.h \ + xterm.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu peripheral/channels/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu peripheral/channels/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libchannels.la: $(libchannels_la_OBJECTS) $(libchannels_la_DEPENDENCIES) + $(LINK) $(libchannels_la_OBJECTS) $(libchannels_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xterm.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: channels/xterm.h =================================================================== --- channels/xterm.h (nonexistent) +++ channels/xterm.h (revision 1765) @@ -0,0 +1,31 @@ +/* xterm.h -- peripheral communication with host through an xterm header + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef XTERM__H +#define XTERM__H + +extern struct channel_ops xterm_channel_ops; + +#endif /* XTERM__H */ Index: channels/channel.c =================================================================== --- channels/channel.c (nonexistent) +++ channels/channel.c (revision 1765) @@ -0,0 +1,194 @@ +/* channel.c -- Definition of types and structures for + peripherals to communicate with host. Adapted from UML. + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include + +/* Package includes */ +#include "channel.h" +#include "fd.h" +#include "file.h" +#include "tcp.h" +#include "tty.h" +#include "xterm.h" + +struct channel_factory +{ + const char *name; + const struct channel_ops *ops; + struct channel_factory *next; +}; + +static struct channel_factory preloaded[] = { + {"fd", &fd_channel_ops, &preloaded[1]}, + {"file", &file_channel_ops, &preloaded[2]}, + {"xterm", &xterm_channel_ops, &preloaded[3]}, + {"tcp", &tcp_channel_ops, &preloaded[4]}, + {"tty", &tty_channel_ops, NULL} +}; + +static struct channel_factory *head = &preloaded[0]; + +/* Forward declaration of static functions */ +static struct channel_factory *find_channel_factory (const char *name); + +struct channel * +channel_init (const char *descriptor) +{ + struct channel *retval; + struct channel_factory *current; + char *args, *name; + int count; + + if (!descriptor) + { + return NULL; + } + + retval = (struct channel *) calloc (1, sizeof (struct channel)); + + if (!retval) + { + perror (descriptor); + exit (1); + } + + args = strchr (descriptor, ':'); + + if (args) + { + count = args - descriptor; + args++; + } + else + { + count = strlen (descriptor); + } + + name = (char *) strndup (descriptor, count); + + if (!name) + { + perror (name); + exit (1); + } + + current = find_channel_factory (name); + + if (!current) + { + errno = ENODEV; + perror (descriptor); + exit (1); + } + + retval->ops = current->ops; + + free (name); + + if (!retval->ops) + { + errno = ENODEV; + perror (descriptor); + exit (1); + } + + if (retval->ops->init) + { + retval->data = (retval->ops->init) (args); + + if (!retval->data) + { + perror (descriptor); + exit (1); + } + } + + return retval; +} + +int +channel_open (struct channel *channel) +{ + if (channel && channel->ops && channel->ops->open) + { + return (channel->ops->open) (channel->data); + } + errno = ENOSYS; + return -1; +} + +int +channel_read (struct channel *channel, char *buffer, int size) +{ + if (channel && channel->ops && channel->ops->read) + { + return (channel->ops->read) (channel->data, buffer, size); + } + errno = ENOSYS; + return -1; +} + +int +channel_write (struct channel *channel, const char *buffer, int size) +{ + if (channel && channel->ops && channel->ops->write) + { + return (channel->ops->write) (channel->data, buffer, size); + } + errno = ENOSYS; + return -1; +} + +void +channel_close (struct channel *channel) +{ + if (channel && channel->ops && channel->ops->close) + { + (channel->ops->close) (channel->data); + } +} + +static struct channel_factory * +find_channel_factory (const char *name) +{ + struct channel_factory *current = head; + + current = head; + while (current && strcmp (current->name, name)) + { + current = current->next; + } + + return current; +} Index: channels/generic.c =================================================================== --- channels/generic.c (nonexistent) +++ channels/generic.c (revision 1765) @@ -0,0 +1,62 @@ +/* generic.c -- Definition of generic functions for peripheral to + * communicate with host + + Copyright (C) 2002 Richard Prescott + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" + +/* System includes */ +#include +#include + + +int +generic_open (void *data) +{ + if (data) + { + return 0; + } + errno = ENODEV; + return -1; +} + + +void +generic_close (void *data) +{ + return; +} + + +void +generic_free (void *data) +{ + if (data) + { + free (data); + } +} Index: channels/channel.h =================================================================== --- channels/channel.h (nonexistent) +++ channels/channel.h (revision 1765) @@ -0,0 +1,63 @@ +/* channel.h -- Definition of types and structures for + peripheral to communicate with host. Addapted from UML. + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef CHANNEL__H +#define CHANNEL__H + +/*! A data structure representing all the functions required on a channel */ +struct channel_ops +{ + void *(*init) (const char *); + int (*open) (void *); + void (*close) (void *); + int (*read) (void *, char *, int); + int (*write) (void *, const char *, int); + void (*free) (void *); + int (*isok) (void *); + char *(*status) (void *); +}; + +/*! A data structure representing a channel. Its operations and data */ +struct channel +{ + const struct channel_ops *ops; + void *data; +}; + + +/* Function prototypes for external use */ +extern struct channel *channel_init (const char *descriptor); +extern int channel_open (struct channel *channel); +extern int channel_read (struct channel *channel, + char *buffer, + int size); +extern int channel_write (struct channel *channel, + const char *buffer, + int size); +extern void channel_close (struct channel *channel); + +#endif /* CHANNEL__H */ Index: channels/file.c =================================================================== --- channels/file.c (nonexistent) +++ channels/file.c (revision 1765) @@ -0,0 +1,172 @@ +/* file.c -- Definition of functions and structures for + peripheral to communicate with host through files + + Copyright (C) 2002 Richard Prescott + Copyright (C) 1999 Damjan Lampret, lampret@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include +#include + +/* Package includes */ +#include "channel.h" +#include "fd.h" + +/*! Data structure representing a channel to/from a file */ +struct file_channel +{ + struct fd_channel fds; + char *namein; + char *nameout; +}; + + +/* Forward declarations of static routines */ +static void *file_init (const char *args); +static int file_open (void *data); +static void file_close (void *data); +static void file_free (void *data); + +/*! Data structure with all the operations for communicating with a file + channel */ +struct channel_ops file_channel_ops = { + .init = file_init, + .open = file_open, + .close = file_close, + .read = fd_read, + .write = fd_write, + .free = file_free, +}; + + +static void * +file_init (const char *args) +{ + struct file_channel *retval; + char *nameout; + + if (!args) + { + errno = EINVAL; + return NULL; + } + + retval = (struct file_channel *) calloc (1, sizeof (struct file_channel)); + + if (!retval) + { + return NULL; + } + + retval->fds.fdin = -1; + retval->fds.fdout = -1; + + nameout = strchr (args, ','); + + if (nameout) + { + retval->namein = strndup (args, nameout - args); + retval->nameout = strdup (nameout + 1); + } + else + { + retval->nameout = retval->namein = strdup (args); + } + + return (void *) retval; +} + +static int +file_open (void *data) +{ + struct file_channel *files = (struct file_channel *) data; + + if (!files) + { + errno = ENODEV; + return -1; + } + + if (files->namein == files->nameout) + { + /* if we have the same name in and out + * it cannot (logically) be a regular files. + * so we wont create one + */ + files->fds.fdin = files->fds.fdout = open (files->namein, O_RDWR); + + return files->fds.fdin < 0 ? -1 : 0; + } + + + files->fds.fdin = open (files->namein, O_RDONLY | O_CREAT, 0664); + + if (files->fds.fdin < 0) + return -1; + + files->fds.fdout = open (files->nameout, O_WRONLY | O_CREAT, 0664); + + if (files->fds.fdout < 0) + { + close (files->fds.fdout); + files->fds.fdout = -1; + return -1; + } + + return 0; +} + +static void +file_close (void *data) +{ + struct file_channel *files = (struct file_channel *) data; + + if (files->fds.fdin != files->fds.fdout) + close (files->fds.fdin); + + close (files->fds.fdout); + + files->fds.fdin = -1; + files->fds.fdout = -1; +} + +static void +file_free (void *data) +{ + struct file_channel *files = (struct file_channel *) data; + + if (files->namein != files->nameout) + free (files->namein); + + free (files->nameout); + + free (files); +} Index: channels/tty.c =================================================================== --- channels/tty.c (nonexistent) +++ channels/tty.c (revision 1765) @@ -0,0 +1,222 @@ +/* tty.c -- Definition of functions for peripheral to + * communicate with host via a tty. + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include +#include +#include + +/* Package includes */ +#include "channel.h" +#include "generic.h" +#include "fd.h" + +/* Default parameters if not specified in config file */ +#define DEFAULT_BAUD B19200 +#define DEFAULT_TTY_DEVICE "/dev/ttyS0" + +/*! Data structure representing a TTY channel */ +struct tty_channel +{ + struct fd_channel fds; +}; + +/*! Table of Baud rates */ +static const struct +{ + char *name; + int value; +} baud_table[] = +{ + { + "50", B50}, + { + "2400", B2400}, + { + "4800", B4800}, + { + "9600", B9600}, + { + "19200", B19200}, + { + "38400", B38400}, + { + "115200", B115200}, + { + "230400", B230400}, + { + 0, 0} +}; + +/* Forward declaration of static functions */ +static void *tty_init (const char *input); +static int tty_open (void *data); + +/*! Global data structure representing the operations on a TTY channel */ +struct channel_ops tty_channel_ops = { + .init = tty_init, + .open = tty_open, + .close = generic_close, + .read = fd_read, + .write = fd_write, + .free = generic_free, +}; + + +/* Convert baud rate string to termio baud rate constant */ +static int +parse_baud (char *baud_string) +{ + int i; + for (i = 0; baud_table[i].name; i++) + { + if (!strcmp (baud_table[i].name, baud_string)) + return baud_table[i].value; + } + + fprintf (stderr, "Error: unknown baud rate: %s\n", baud_string); + fprintf (stderr, " Known baud rates: "); + + for (i = 0; baud_table[i].name; i++) + { + fprintf (stderr, "%s%s", baud_table[i].name, + baud_table[i + 1].name ? ", " : "\n"); + } + return B0; +} + +static void * +tty_init (const char *input) +{ + int fd = 0, baud; + char *param_name, *param_value, *device; + struct termios options; + struct tty_channel *channel; + + channel = (struct tty_channel *) malloc (sizeof (struct tty_channel)); + if (!channel) + return NULL; + + /* Make a copy of config string, because we're about to mutate it */ + input = strdup (input); + if (!input) + goto error; + + baud = DEFAULT_BAUD; + device = DEFAULT_TTY_DEVICE; + + /* Parse command-line parameters + Command line looks like name1=value1,name2,name3=value3,... */ + while ((param_name = strtok ((char *) input, ","))) + { + + input = NULL; + + /* Parse a parameter's name and value */ + param_value = strchr (param_name, '='); + if (param_value != NULL) + { + *param_value = '\0'; + param_value++; /* Advance past '=' character */ + } + + if (!strcmp (param_name, "baud") && param_value) + { + baud = parse_baud (param_value); + if (baud == B0) + { + goto error; + } + } + else if (!strcmp (param_name, "device")) + { + device = param_value; + } + else + { + fprintf (stderr, "error: unknown tty channel parameter \"%s\"\n", + param_name); + goto error; + } + } + + fd = open (device, O_RDWR); + if (fd < 0) + goto error; + + /* Get the current options for the port... */ + if (tcgetattr (fd, &options) < 0) + goto error; + + /* Set the serial baud rate */ + cfsetispeed (&options, baud); + cfsetospeed (&options, baud); + + /* Enable the receiver and set local mode... */ + + /* cfmakeraw(&options); + * + * cygwin lacks cfmakeraw(), just do it explicitly + */ + options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + options.c_oflag &= ~OPOST; + options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + options.c_cflag &= ~(CSIZE | PARENB); + options.c_cflag |= CS8; + + options.c_cflag |= (CLOCAL | CREAD); + + + /* Set the new options for the port... */ + if (tcsetattr (fd, TCSANOW, &options) < 0) + goto error; + + channel->fds.fdin = channel->fds.fdout = fd; + free ((void *) input); + return channel; + +error: + if (fd > 0) + close (fd); + free (channel); + if (input) + free ((void *) input); + return NULL; +} + +static int +tty_open (void *data) +{ + return 0; +} Index: channels/generic.h =================================================================== --- channels/generic.h (nonexistent) +++ channels/generic.h (revision 1765) @@ -0,0 +1,35 @@ +/* generic.h -- Declaration of generic functions for peripheral to + communicate with host + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +#ifndef GENERIC__H +#define GENERIC__H + +/* Function prototypes for external use */ +extern int generic_open (void *data); +extern void generic_close (void *data); +extern void generic_free (void *data); + +#endif /* GENERIC__H */ Index: channels/file.h =================================================================== --- channels/file.h (nonexistent) +++ channels/file.h (revision 1765) @@ -0,0 +1,32 @@ +/* file.h -- Header for functions and structures for + peripheral to communicate with host through files + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +#ifndef FILE__H +#define FILE__H + +/* Global data structures for external use */ +extern struct channel_ops file_channel_ops; + +#endif /* FILE__H */ Index: channels/tty.h =================================================================== --- channels/tty.h (nonexistent) +++ channels/tty.h (revision 1765) @@ -0,0 +1,33 @@ +/* tty.h -- Header for functions for peripheral to + * communicate with host via a tty. + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef TTY__H +#define TTY__H + +/* Global data structures for external use */ +extern struct channel_ops tty_channel_ops; + +#endif /* TTY__H */ Index: channels/tcp.c =================================================================== --- channels/tcp.c (nonexistent) +++ channels/tcp.c (revision 1765) @@ -0,0 +1,211 @@ +/* tcp.c -- Definition of functions for peripheral to + * communicate with host via a tcp socket. + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Package includes */ +#include "channel.h" +#include "generic.h" +#include "fd.h" + +/*! Structure to represent a TCP/IP channel */ +struct tcp_channel +{ + struct fd_channel fds; + int socket_fd; /* Socket to listen to */ + int port_number; /* TCP port number */ + int connected; /* If 0, no remote endpoint yet */ + int nonblocking; /* If 0, read/write will block until + remote client connects */ +}; + +/* Forward declarations of static functions */ +static void *tcp_init (const char *input); +static int tcp_open (void *data); +static int tcp_read (void *data, + char *buffer, + int size); +static int tcp_write (void *data, + const char *buffer, + int size); + +/*! Data structure holding all the operations for a TCP/IP channel */ +struct channel_ops tcp_channel_ops = { + .init = tcp_init, + .open = tcp_open, + .close = generic_close, + .read = tcp_read, + .write = tcp_write, + .free = generic_free, +}; + +static void * +tcp_init (const char *input) +{ + int port_number, fd, flags; + struct sockaddr_in local_ip; + struct tcp_channel *channel = + (struct tcp_channel *) malloc (sizeof (struct tcp_channel)); + if (!channel) + return NULL; + + fd = 0; + channel->nonblocking = 1; + channel->fds.fdin = -1; + channel->fds.fdout = -1; + channel->socket_fd = -1; + channel->port_number = -1; + + port_number = atoi (input); + if (port_number == 0) + goto error; + + fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd < 0) + goto error; + + flags = 1; + if (setsockopt + (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &flags, sizeof (int)) < 0) + { + perror ("Can not set SO_REUSEADDR option on channel socket"); + goto error; + } + + memset (&local_ip, 0, sizeof (local_ip)); + local_ip.sin_family = AF_INET; + local_ip.sin_addr.s_addr = htonl (INADDR_ANY); + local_ip.sin_port = htons (port_number); + if (bind (fd, (struct sockaddr *) &local_ip, sizeof (local_ip)) < 0) + { + perror ("Can't bind local address"); + goto error; + } + + if (channel->nonblocking) + { + if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) + { + perror ("Can not make channel socket non-blocking"); + goto error; + } + } + + if (listen (fd, 1) < 0) + goto error; + + channel->socket_fd = fd; + channel->port_number = port_number; + channel->connected = 0; + return (void *) channel; + +error: + if (fd) + close (fd); + free (channel); + return NULL; +} + +static int +tcp_open (void *data) +{ + /* Socket is opened lazily, upon first read or write, so do nothing here */ + return 0; +} + + +static int +wait_for_tcp_connect (struct tcp_channel *channel) +{ + int fd; + socklen_t sizeof_remote_ip; + struct sockaddr_in remote_ip; + + sizeof_remote_ip = sizeof (remote_ip); + fd = + accept (channel->socket_fd, (struct sockaddr *) &remote_ip, + &sizeof_remote_ip); + if (fd < 0) + { + if (channel->nonblocking) + { + /* Not an error if there is not yet a remote connection - try again later */ + if (errno == EAGAIN) + return 0; + } + perror ("Couldn't accept connection"); + return -1; + } + + channel->fds.fdin = channel->fds.fdout = fd; + close (channel->socket_fd); + channel->socket_fd = -1; + channel->connected = 1; + return 1; +} + +static int +tcp_read (void *data, char *buffer, int size) +{ + struct tcp_channel *channel = data; + + /* Lazily connect to tcp partner on read/write */ + if (!channel->connected) + { + int retval = wait_for_tcp_connect (data); + if (retval <= 0) + return retval; + } + return fd_read (data, buffer, size); +} + +static int +tcp_write (void *data, const char *buffer, int size) +{ + struct tcp_channel *channel = data; + + /* Lazily connect to tcp partner on read/write */ + if (!channel->connected) + { + int retval = wait_for_tcp_connect (data); + if (retval < 0) + return retval; + } + return fd_write (data, buffer, size); +} Index: channels/Makefile.am =================================================================== --- channels/Makefile.am (nonexistent) +++ channels/Makefile.am (revision 1765) @@ -0,0 +1,38 @@ +# Makefile -- Makefile for peripherals channels to host +# +# Copyright (C) 2002 Richard Prescott +# Copyright (C) 2008 Embecosm Limited +# +# Contributor Jeremy Bennett +# +# 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 3 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, see . + + +noinst_LTLIBRARIES = libchannels.la +libchannels_la_SOURCES = channel.c \ + fd.c \ + file.c \ + generic.c \ + tcp.c \ + tty.c \ + xterm.c \ + channel.h \ + fd.h \ + file.h \ + generic.h \ + tcp.h \ + tty.h \ + xterm.h Index: channels/fd.c =================================================================== --- channels/fd.c (nonexistent) +++ channels/fd.c (revision 1765) @@ -0,0 +1,173 @@ +/* fd.c -- Definition of functions and structures for + peripheral to communicate with host through file descriptors + + Copyright (C) 2002 Richard Prescott + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include +#include + +/* Package includes */ +#include "fd.h" +#include "channel.h" +#include "generic.h" + + +/* Forward declarations of static functions */ +static void *fd_init (const char *args); +static int fd_isok (void *data); +static char *fd_status (void *data); + +/*! Global data structure representing the operations for communicating + through a file descriptor channel */ +struct channel_ops fd_channel_ops = { + .init = fd_init, + .open = generic_open, + .close = generic_close, + .read = fd_read, + .write = fd_write, + .free = generic_free, + .isok = fd_isok, + .status = fd_status, +}; + + +static void * +fd_init (const char *args) +{ + struct fd_channel *retval; + + retval = (struct fd_channel *) calloc (1, sizeof (struct fd_channel)); + + if (!retval) + { + return NULL; + } + + + retval->fdin = atoi (args); /* so 0 if garbage */ + /* TODO: strtoul */ + + args = strchr (args, ','); + + if (args) + { + retval->fdout = atoi (args + 1); + } + else + { + retval->fdout = retval->fdin; + } + + return (void *) retval; +} + +int +fd_read (void *data, char *buffer, int size) +{ + struct fd_channel *fds = (struct fd_channel *) data; + struct timeval timeout = { 0, 0 }; + fd_set rfds; + int retval; + + if (!fds) + { + errno = ENODEV; + return -1; + } + + FD_ZERO (&rfds); + FD_SET (fds->fdin, &rfds); + + retval = select (fds->fdin + 1, &rfds, NULL, NULL, &timeout); + + if (retval <= 0) + return retval; + + return read (fds->fdin, buffer, size); +} + +int +fd_write (void *data, const char *buffer, int size) +{ + struct fd_channel *fds = (struct fd_channel *) data; + if (fds) + { + return write (fds->fdout, buffer, size); + } + errno = ENODEV; + return -1; +} + +static int +fd_isok (void *data) +{ + struct fd_channel *fds = (struct fd_channel *) data; + if (fds) + { + return fds->fdout != -1 && fds->fdin != -1; + } + return 0; +} + +static int +fd_status_fd (int fd, char *str, int size) +{ + if (fd == -1) + return snprintf (str, size, "closed"); + + return snprintf (str, size, "opened(fd=%d)", fd); +} + +static char * +fd_status (void *data) +{ + static char retval[256]; + int index = 0; + + struct fd_channel *fds = (struct fd_channel *) data; + if (fds) + { + index += snprintf (retval + index, sizeof (retval) - index, "in "); + index += + fd_status_fd (fds->fdin, retval + index, sizeof (retval) - index); + + index += snprintf (retval + index, sizeof (retval) - index, "out "); + index += + fd_status_fd (fds->fdout, retval + index, sizeof (retval) - index); + } + else + { + snprintf (retval, sizeof (retval), "(null)"); + } + return retval; +} + Index: channels/tcp.h =================================================================== --- channels/tcp.h (nonexistent) +++ channels/tcp.h (revision 1765) @@ -0,0 +1,33 @@ +/* tcp.h -- Header for functions for peripheral to + communicate with host via a TCP/IP socket. + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef TCP__H +#define TCP__H + +/* Global data structures for external use */ +extern struct channel_ops tcp_channel_ops; + +#endif /* TCP__H */ Index: channels =================================================================== --- channels (nonexistent) +++ channels (revision 1765)
channels Property changes : Added: svn:ignore ## -0,0 +1,2 ## +Makefile +.deps Index: generic.c =================================================================== --- generic.c (nonexistent) +++ generic.c (revision 1765) @@ -0,0 +1,541 @@ +/* generic.c -- Generic external peripheral + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* This is functional simulation of any external peripheral. It's job is to + * trap accesses in a specific range, so that the simulator can drive an + * external device. + */ + +/* Autoconf and/or portability configuration */ +#include "config.h" + +/* System includes */ +#include +#include + +/* Package includes */ +#include "arch.h" +#include "sim-config.h" +#include "abstract.h" +#include "toplevel-support.h" +#include "sim-cmd.h" + + +/*! State associated with the generic device. */ +struct dev_generic +{ + + /* Info about a particular transaction */ + + enum + { /* Direction of the access */ + GENERIC_READ, + GENERIC_WRITE + } trans_direction; + + enum + { /* Size of the access */ + GENERIC_BYTE, + GENERIC_HW, + GENERIC_WORD + } trans_size; + + uint32_t value; /* The value to read/write */ + + /* Configuration */ + + int enabled; /* Device enabled */ + int byte_enabled; /* Byte R/W allowed */ + int hw_enabled; /* Half word R/W allowed */ + int word_enabled; /* Full word R/W allowed */ + char *name; /* Name of the device */ + oraddr_t baseaddr; /* Base address of device */ + uint32_t size; /* Address space size (bytes) */ + +}; + + +/* Generic read and write upcall routines. Note the address here is absolute, + not relative to the device. */ + +static unsigned long int +ext_read (unsigned long int addr, unsigned long int mask) +{ + return config.ext.read_up (config.ext.class_ptr, addr, mask); + +} /* ext_callback() */ + + +/* Generic read and write upcall routines. Note the address here is absolute, + not relative to the device. */ + +static void +ext_write (unsigned long int addr, + unsigned long int mask, unsigned long int value) +{ + config.ext.write_up (config.ext.class_ptr, addr, mask, value); + +} /* ext_callback() */ + + +/* I/O routines. Note that address is relative to start of address space. */ + +static uint8_t +generic_read_byte (oraddr_t addr, void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + if (!config.ext.class_ptr) + { + fprintf (stderr, "Byte read from disabled generic device\n"); + return 0; + } + else if (addr >= dev->size) + { + fprintf (stderr, "Byte read out of range for generic device %s " + "(addr %" PRIxADDR ")\n", dev->name, addr); + return 0; + } + else + { + unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr); + unsigned long wordaddr = fulladdr & 0xfffffffc; + unsigned long bitoff = (fulladdr & 0x00000003) << 3; + +#ifdef WORDS_BIGENDIAN + unsigned long mask = 0x000000ff << (24 - bitoff); + unsigned long res = ext_read (wordaddr, mask); + + return (uint8_t) ((res >> (24 - bitoff)) & 0x000000ff); +#else + unsigned long mask = 0x000000ff << bitoff; + unsigned long res = ext_read (wordaddr, mask); + + return (uint8_t) ((res >> bitoff) & 0x00000ff); +#endif + } +} /* generic_read_byte() */ + + +static void +generic_write_byte (oraddr_t addr, uint8_t value, void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + if (!config.ext.class_ptr) + { + fprintf (stderr, "Byte write to disabled generic device\n"); + } + else if (addr >= dev->size) + { + fprintf (stderr, "Byte written out of range for generic device %s " + "(addr %" PRIxADDR ")\n", dev->name, addr); + } + else + { + unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr); + unsigned long wordaddr = fulladdr & 0xfffffffc; + unsigned long bitoff = (fulladdr & 0x00000003) << 3; + +#ifdef WORDS_BIGENDIAN + unsigned long mask = 0x000000ff << (24 - bitoff); + unsigned long wordval = ((unsigned long int) value) << (24 - bitoff); +#else + unsigned long mask = 0x000000ff << bitoff; + unsigned long wordval = ((unsigned long int) value) << bitoff; +#endif + + ext_write (wordaddr, mask, wordval); + } +} /* generic_write_byte() */ + + +static uint16_t +generic_read_hw (oraddr_t addr, void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + if (!config.ext.class_ptr) + { + fprintf (stderr, "Half word read from disabled generic device\n"); + return 0; + } + else if (addr >= dev->size) + { + fprintf (stderr, "Half-word read out of range for generic device %s " + "(addr %" PRIxADDR ")\n", dev->name, addr); + return 0; + } + else if (addr & 0x1) + { + fprintf (stderr, + "Unaligned half word read from 0x%" PRIxADDR " ignored\n", + addr); + return 0; + } + else + { + unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr); + unsigned long wordaddr = fulladdr & 0xfffffffc; + unsigned long bitoff = (fulladdr & 0x00000003) << 3; + +#ifdef WORDS_BIGENDIAN + unsigned long mask = 0x0000ffff << (16 - bitoff); + unsigned long res = ext_read (wordaddr, mask); + + return (uint16_t) ((res >> (16 - bitoff)) & 0x0000ffff); +#else + unsigned long mask = 0x0000ffff << bitoff; + unsigned long res = ext_read (wordaddr, mask); + + return (uint16_t) ((res >> bitoff) & 0x0000ffff); +#endif + } +} /* generic_read_hw() */ + + +static void +generic_write_hw (oraddr_t addr, uint16_t value, void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + if (!config.ext.class_ptr) + { + fprintf (stderr, "Half word write to disabled generic device\n"); + } + else if (addr >= dev->size) + { + fprintf (stderr, "Half-word written out of range for generic device %s " + "(addr %" PRIxADDR ")\n", dev->name, addr); + } + else if (addr & 0x1) + { + fprintf (stderr, + "Unaligned half word write to 0x%" PRIxADDR " ignored\n", addr); + } + else + { + unsigned long fulladdr = (unsigned long int) (addr + dev->baseaddr); + unsigned long wordaddr = fulladdr & 0xfffffffc; + unsigned long bitoff = (fulladdr & 0x00000003) << 3; + +#ifdef WORDS_BIGENDIAN + unsigned long mask = 0x0000ffff << (16 - bitoff); + unsigned long wordval = ((unsigned long int) value) << (16 - bitoff); +#else + unsigned long mask = 0x0000ffff << bitoff; + unsigned long wordval = ((unsigned long int) value) << bitoff; +#endif + + ext_write (wordaddr, mask, wordval); + } +} /* generic_write_hw() */ + + +static uint32_t +generic_read_word (oraddr_t addr, void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + if (!config.ext.class_ptr) + { + fprintf (stderr, "Full word read from disabled generic device\n"); + return 0; + } + else if (addr >= dev->size) + { + fprintf (stderr, "Full word read out of range for generic device %s " + "(addr %" PRIxADDR ")\n", dev->name, addr); + return 0; + } + else if (0 != (addr & 0x3)) + { + fprintf (stderr, + "Unaligned full word read from 0x%" PRIxADDR " ignored\n", + addr); + return 0; + } + else + { + unsigned long wordaddr = (unsigned long int) (addr + dev->baseaddr); + + return (uint32_t) ext_read (wordaddr, 0xffffffff); + } +} /* generic_read_word() */ + + +static void +generic_write_word (oraddr_t addr, uint32_t value, void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + if (!config.ext.class_ptr) + { + fprintf (stderr, "Full word write to disabled generic device\n"); + } + else if (addr >= dev->size) + { + fprintf (stderr, "Full word written out of range for generic device %s " + "(addr %" PRIxADDR ")\n", dev->name, addr); + } + else if (0 != (addr & 0x3)) + { + fprintf (stderr, + "Unaligned full word write to 0x%" PRIxADDR " ignored\n", addr); + } + else + { + unsigned long wordaddr = (unsigned long int) (addr + dev->baseaddr); + + ext_write (wordaddr, 0xffffffff, value); + } +} /* generic_write_word() */ + + +/* Reset is a null operation */ + +static void +generic_reset (void *dat) +{ + return; + +} /* generic_reset() */ + + +/* Status report can only advise of configuration. */ + +static void +generic_status (void *dat) +{ + struct dev_generic *dev = (struct dev_generic *) dat; + + PRINTF ("\nGeneric device \"%s\" at 0x%" PRIxADDR ":\n", dev->name, + dev->baseaddr); + PRINTF (" Size 0x%" PRIx32 "\n", dev->size); + + if (dev->byte_enabled) + { + PRINTF (" Byte R/W enabled\n"); + } + + if (dev->hw_enabled) + { + PRINTF (" Half word R/W enabled\n"); + } + + if (dev->word_enabled) + { + PRINTF (" Full word R/W enabled\n"); + } + + PRINTF ("\n"); + +} /* generic_status() */ + + +/* Functions to set configuration */ + +static void +generic_enabled (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->enabled = val.int_val; + +} /* generic_enabled() */ + + +static void +generic_byte_enabled (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->byte_enabled = val.int_val; + +} /* generic_byte_enabled() */ + + +static void +generic_hw_enabled (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->hw_enabled = val.int_val; + +} /* generic_hw_enabled() */ + + +static void +generic_word_enabled (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->word_enabled = val.int_val; + +} /* generic_word_enabled() */ + + +static void +generic_name (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->name = strdup (val.str_val); + + if (!((struct dev_generic *) dat)->name) + { + fprintf (stderr, "Peripheral 16450: name \"%s\": Run out of memory\n", + val.str_val); + exit (-1); + } +} /* generic_name() */ + + +static void +generic_baseaddr (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->baseaddr = val.addr_val; + +} /* generic_baseaddr() */ + + +static void +generic_size (union param_val val, void *dat) +{ + ((struct dev_generic *) dat)->size = val.int_val; + +} /* generic_size() */ + + +/* Start of new generic section */ + +static void * +generic_sec_start () +{ + struct dev_generic *new = + (struct dev_generic *) malloc (sizeof (struct dev_generic)); + + if (0 == new) + { + fprintf (stderr, "Generic peripheral: Run out of memory\n"); + exit (-1); + } + + /* Default names */ + + new->enabled = 1; + new->byte_enabled = 1; + new->hw_enabled = 1; + new->word_enabled = 1; + new->name = "anonymous external peripheral"; + new->baseaddr = 0; + new->size = 0; + + return new; + +} /* generic_sec_start() */ + + +/* End of new generic section */ + +static void +generic_sec_end (void *dat) +{ + struct dev_generic *generic = (struct dev_generic *) dat; + struct mem_ops ops; + + /* Give up if not enabled, or if size is zero, or if no access size is + enabled. */ + + if (!generic->enabled) + { + free (dat); + return; + } + + if (0 == generic->size) + { + fprintf (stderr, "Generic peripheral \"%s\" has size 0: ignoring", + generic->name); + free (dat); + return; + } + + if (!generic->byte_enabled && + !generic->hw_enabled && !generic->word_enabled) + { + fprintf (stderr, "Generic peripheral \"%s\" has no access: ignoring", + generic->name); + free (dat); + return; + } + + /* Zero all the ops, then set the ones we care about. Read/write delays will + * come from the peripheral if desired. + */ + + memset (&ops, 0, sizeof (struct mem_ops)); + + if (generic->byte_enabled) + { + ops.readfunc8 = generic_read_byte; + ops.writefunc8 = generic_write_byte; + ops.read_dat8 = dat; + ops.write_dat8 = dat; + } + + if (generic->hw_enabled) + { + ops.readfunc16 = generic_read_hw; + ops.writefunc16 = generic_write_hw; + ops.read_dat16 = dat; + ops.write_dat16 = dat; + } + + if (generic->word_enabled) + { + ops.readfunc32 = generic_read_word; + ops.writefunc32 = generic_write_word; + ops.read_dat32 = dat; + ops.write_dat32 = dat; + } + + /* Register everything */ + + reg_mem_area (generic->baseaddr, generic->size, 0, &ops); + + reg_sim_reset (generic_reset, dat); + reg_sim_stat (generic_status, dat); + +} /* generic_sec_end() */ + + +/* Register a generic section. */ + +void +reg_generic_sec (void) +{ + struct config_section *sec = reg_config_sec ("generic", + generic_sec_start, + generic_sec_end); + + reg_config_param (sec, "enabled", paramt_int, generic_enabled); + reg_config_param (sec, "byte_enabled", paramt_int, generic_byte_enabled); + reg_config_param (sec, "hw_enabled", paramt_int, generic_hw_enabled); + reg_config_param (sec, "word_enabled", paramt_int, generic_word_enabled); + reg_config_param (sec, "name", paramt_str, generic_name); + reg_config_param (sec, "baseaddr", paramt_addr, generic_baseaddr); + reg_config_param (sec, "size", paramt_int, generic_size); + +} /* reg_generic_sec */ Index: eth.c =================================================================== --- eth.c (nonexistent) +++ eth.c (revision 1765) @@ -0,0 +1,1619 @@ +/* ethernet.c -- Simulation of Ethernet MAC + + Copyright (C) 2001 by Erez Volk, erez@opencores.org + Ivan Guzvinec, ivang@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ETH_PHY +#include +#endif /* HAVE_ETH_PHY */ + +#ifdef HAVE_NET_ETHERNET_H +# include +#elif defined(HAVE_SYS_ETHERNET_H) +# include +#else /* !HAVE_NET_ETHERNET_H && !HAVE_SYS_ETHERNET_H - */ +#include +#endif + +/* Package includes */ +#include "arch.h" +#include "config.h" +#include "abstract.h" +#include "eth.h" +#include "dma.h" +#include "sim-config.h" +#include "fields.h" +#include "crc32.h" +#include "vapi.h" +#include "pic.h" +#include "sched.h" +#include "debug.h" +#include "toplevel-support.h" +#include "sim-cmd.h" + +/* Address space required by one Ethernet MAC */ +#define ETH_ADDR_SPACE 0x1000 + +/* Relative Register Addresses */ +#define ETH_MODER (4 * 0x00) +#define ETH_INT_SOURCE (4 * 0x01) +#define ETH_INT_MASK (4 * 0x02) +#define ETH_IPGT (4 * 0x03) +#define ETH_IPGR1 (4 * 0x04) +#define ETH_IPGR2 (4 * 0x05) +#define ETH_PACKETLEN (4 * 0x06) +#define ETH_COLLCONF (4 * 0x07) +#define ETH_TX_BD_NUM (4 * 0x08) +#define ETH_CTRLMODER (4 * 0x09) +#define ETH_MIIMODER (4 * 0x0A) +#define ETH_MIICOMMAND (4 * 0x0B) +#define ETH_MIIADDRESS (4 * 0x0C) +#define ETH_MIITX_DATA (4 * 0x0D) +#define ETH_MIIRX_DATA (4 * 0x0E) +#define ETH_MIISTATUS (4 * 0x0F) +#define ETH_MAC_ADDR0 (4 * 0x10) +#define ETH_MAC_ADDR1 (4 * 0x11) +#define ETH_HASH0 (4 * 0x12) +#define ETH_HASH1 (4 * 0x13) + +/* Where BD's are stored */ +#define ETH_BD_BASE 0x400 +#define ETH_BD_COUNT 0x100 +#define ETH_BD_SPACE (4 * ETH_BD_COUNT) + +/* Where to point DMA to transmit/receive */ +#define ETH_DMA_RX_TX 0x800 + +/* Field definitions for MODER */ +#define ETH_MODER_DMAEN_OFFSET 17 +#define ETH_MODER_RECSMALL_OFFSET 16 +#define ETH_MODER_PAD_OFFSET 15 +#define ETH_MODER_HUGEN_OFFSET 14 +#define ETH_MODER_CRCEN_OFFSET 13 +#define ETH_MODER_DLYCRCEN_OFFSET 12 +#define ETH_MODER_RST_OFFSET 11 +#define ETH_MODER_FULLD_OFFSET 10 +#define ETH_MODER_EXDFREN_OFFSET 9 +#define ETH_MODER_NOBCKOF_OFFSET 8 +#define ETH_MODER_LOOPBCK_OFFSET 7 +#define ETH_MODER_IFG_OFFSET 6 +#define ETH_MODER_PRO_OFFSET 5 +#define ETH_MODER_IAM_OFFSET 4 +#define ETH_MODER_BRO_OFFSET 3 +#define ETH_MODER_NOPRE_OFFSET 2 +#define ETH_MODER_TXEN_OFFSET 1 +#define ETH_MODER_RXEN_OFFSET 0 + +/* Field definitions for INT_SOURCE */ +#define ETH_INT_SOURCE_RXC_OFFSET 6 +#define ETH_INT_SOURCE_TXC_OFFSET 5 +#define ETH_INT_SOURCE_BUSY_OFFSET 4 +#define ETH_INT_SOURCE_RXE_OFFSET 3 +#define ETH_INT_SOURCE_RXB_OFFSET 2 +#define ETH_INT_SOURCE_TXE_OFFSET 1 +#define ETH_INT_SOURCE_TXB_OFFSET 0 + +/* Field definitions for INT_MASK */ +#define ETH_INT_MASK_RXC_M_OFFSET 6 +#define ETH_INT_MASK_TXC_M_OFFSET 5 +#define ETH_INT_MASK_BUSY_M_OFFSET 4 +#define ETH_INT_MASK_RXE_M_OFFSET 3 +#define ETH_INT_MASK_RXB_M_OFFSET 2 +#define ETH_INT_MASK_TXE_M_OFFSET 1 +#define ETH_INT_MASK_TXB_M_OFFSET 0 + +/* Field definitions for PACKETLEN */ +#define ETH_PACKETLEN_MINFL_OFFSET 16 +#define ETH_PACKETLEN_MINFL_WIDTH 16 +#define ETH_PACKETLEN_MAXFL_OFFSET 0 +#define ETH_PACKETLEN_MAXFL_WIDTH 16 + +/* Field definitions for COLLCONF */ +#define ETH_COLLCONF_MAXRET_OFFSET 16 +#define ETH_COLLCONF_MAXRET_WIDTH 4 +#define ETH_COLLCONF_COLLVALID_OFFSET 0 +#define ETH_COLLCONF_COLLVALID_WIDTH 6 + +/* Field definitions for CTRLMODER */ +#define ETH_CMODER_TXFLOW_OFFSET 2 +#define ETH_CMODER_RXFLOW_OFFSET 1 +#define ETH_CMODER_PASSALL_OFFSET 0 + +/* Field definitions for MIIMODER */ +#define ETH_MIIMODER_MRST_OFFSET 9 +#define ETH_MIIMODER_NOPRE_OFFSET 8 +#define ETH_MIIMODER_CLKDIV_OFFSET 0 +#define ETH_MIIMODER_CLKDIV_WIDTH 8 + +/* Field definitions for MIICOMMAND */ +#define ETH_MIICOMM_WCDATA_OFFSET 2 +#define ETH_MIICOMM_RSTAT_OFFSET 1 +#define ETH_MIICOMM_SCANS_OFFSET 0 + +/* Field definitions for MIIADDRESS */ +#define ETH_MIIADDR_RGAD_OFFSET 8 +#define ETH_MIIADDR_RGAD_WIDTH 5 +#define ETH_MIIADDR_FIAD_OFFSET 0 +#define ETH_MIIADDR_FIAD_WIDTH 5 + +/* Field definitions for MIISTATUS */ +#define ETH_MIISTAT_NVALID_OFFSET 1 +#define ETH_MIISTAT_BUSY_OFFSET 1 +#define ETH_MIISTAT_FAIL_OFFSET 0 + +/* Field definitions for TX buffer descriptors */ +#define ETH_TX_BD_LENGTH_OFFSET 16 +#define ETH_TX_BD_LENGTH_WIDTH 16 +#define ETH_TX_BD_READY_OFFSET 15 +#define ETH_TX_BD_IRQ_OFFSET 14 +#define ETH_TX_BD_WRAP_OFFSET 13 +#define ETH_TX_BD_PAD_OFFSET 12 +#define ETH_TX_BD_CRC_OFFSET 11 +#define ETH_TX_BD_LAST_OFFSET 10 +#define ETH_TX_BD_PAUSE_OFFSET 9 +#define ETH_TX_BD_UNDERRUN_OFFSET 8 +#define ETH_TX_BD_RETRY_OFFSET 4 +#define ETH_TX_BD_RETRY_WIDTH 4 +#define ETH_TX_BD_RETRANSMIT_OFFSET 3 +#define ETH_TX_BD_COLLISION_OFFSET 2 +#define ETH_TX_BD_DEFER_OFFSET 1 +#define ETH_TX_BD_NO_CARRIER_OFFSET 0 + + +/* Field definitions for RX buffer descriptors */ +#define ETH_RX_BD_LENGTH_OFFSET 16 +#define ETH_RX_BD_LENGTH_WIDTH 16 +#define ETH_RX_BD_READY_OFFSET 15 +#define ETH_RX_BD_IRQ_OFFSET 14 +#define ETH_RX_BD_WRAP_OFFSET 13 +#define ETH_RX_BD_MISS_OFFSET 7 +#define ETH_RX_BD_UVERRUN_OFFSET 6 +#define ETH_RX_BD_INVALID_OFFSET 5 +#define ETH_RX_BD_DRIBBLE_OFFSET 4 +#define ETH_RX_BD_TOOBIG_OFFSET 3 +#define ETH_RX_BD_TOOSHORT_OFFSET 2 +#define ETH_RX_BD_CRC_OFFSET 1 +#define ETH_RX_BD_COLLISION_OFFSET 0 + +/* + * Ethernet protocol definitions + */ +#ifdef HAVE_NET_ETHERNET_H +#elif defined(HAVE_SYS_ETHERNET_H) +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN ETHERADDRL +#endif +#ifndef ETHER_HDR_LEN +#define ETHER_HDR_LEN sizeof(struct ether_header) +#endif +#else /* !HAVE_NET_ETHERNET_H && !HAVE_SYS_ETHERNET_H - */ +#ifdef __CYGWIN__ +/* define some missing cygwin defines. + * + * NOTE! there is no nonblocking socket option implemented in cygwin.dll + * so defining MSG_DONTWAIT is just (temporary) workaround !!! + */ +#define MSG_DONTWAIT 0x40 +#define ETH_HLEN 14 +#endif /* __CYGWIN__ */ + +#define ETH_ALEN 6 + +struct ether_addr +{ + u_int8_t ether_addr_octet[ETH_ALEN]; +}; + +struct ether_header +{ + u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ + u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ + u_int16_t ether_type; /* packet type ID field */ +}; + +/* Ethernet protocol ID's */ +#define ETHERTYPE_PUP 0x0200 /* Xerox PUP */ +#define ETHERTYPE_IP 0x0800 /* IP */ +#define ETHERTYPE_ARP 0x0806 /* Address resolution */ +#define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ + +#define ETHER_ADDR_LEN ETH_ALEN /* size of ethernet addr */ +#define ETHER_TYPE_LEN 2 /* bytes in type field */ +#define ETHER_CRC_LEN 4 /* bytes in CRC field */ +#define ETHER_HDR_LEN ETH_HLEN /* total octets in header */ +#define ETHER_MIN_LEN (ETH_ZLEN + ETHER_CRC_LEN) /* min packet length */ +#define ETHER_MAX_LEN (ETH_FRAME_LEN + ETHER_CRC_LEN) /* max packet length */ + +/* make sure ethenet length is valid */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +/* + * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have + * (type-ETHERTYPE_TRAIL)*512 bytes of data followed + * by an ETHER type (as given above) and then the (variable-length) header. + */ +#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */ +#define ETHERTYPE_NTRAILER 16 + +#define ETHERMTU ETH_DATA_LEN +#define ETHERMIN (ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) + +#endif /* HAVE_NET_ETHERNET_H */ + +/* + * Implementatino of Ethernet MAC Registers and State + */ +#define ETH_TXSTATE_IDLE 0 +#define ETH_TXSTATE_WAIT4BD 10 +#define ETH_TXSTATE_READFIFO 20 +#define ETH_TXSTATE_TRANSMIT 30 + +#define ETH_RXSTATE_IDLE 0 +#define ETH_RXSTATE_WAIT4BD 10 +#define ETH_RXSTATE_RECV 20 +#define ETH_RXSTATE_WRITEFIFO 30 + +#define ETH_RTX_FILE 0 +#define ETH_RTX_SOCK 1 +#define ETH_RTX_VAPI 2 + +#define ETH_MAXPL 0x10000 + +enum +{ ETH_VAPI_DATA = 0, + ETH_VAPI_CTRL, + ETH_NUM_VAPI_IDS +}; + +struct eth_device +{ + /* Is peripheral enabled */ + int enabled; + + /* Base address in memory */ + oraddr_t baseaddr; + + /* Which DMA controller is this MAC connected to */ + unsigned dma; + unsigned tx_channel; + unsigned rx_channel; + + /* Our address */ + unsigned char mac_address[ETHER_ADDR_LEN]; + + /* interrupt line */ + unsigned long mac_int; + + /* VAPI ID */ + unsigned long base_vapi_id; + + /* RX and TX file names and handles */ + char *rxfile, *txfile; + int txfd; + int rxfd; + off_t loopback_offset; + + /* Socket interface name */ + char *sockif; + + int rtx_sock; + int rtx_type; + struct ifreq ifr; + fd_set rfds, wfds; + + /* Current TX state */ + struct + { + unsigned long state; + unsigned long bd_index; + unsigned long bd; + unsigned long bd_addr; + unsigned working, waiting_for_dma, error; + long packet_length; + unsigned minimum_length, maximum_length; + unsigned add_crc; + unsigned crc_dly; + unsigned long crc_value; + long bytes_left, bytes_sent; + } tx; + + /* Current RX state */ + struct + { + unsigned long state; + unsigned long bd_index; + unsigned long bd; + unsigned long bd_addr; + int fd; + off_t *offset; + unsigned working, error, waiting_for_dma; + long packet_length, bytes_read, bytes_left; + } rx; + + /* Visible registers */ + struct + { + unsigned long moder; + unsigned long int_source; + unsigned long int_mask; + unsigned long ipgt; + unsigned long ipgr1; + unsigned long ipgr2; + unsigned long packetlen; + unsigned long collconf; + unsigned long tx_bd_num; + unsigned long controlmoder; + unsigned long miimoder; + unsigned long miicommand; + unsigned long miiaddress; + unsigned long miitx_data; + unsigned long miirx_data; + unsigned long miistatus; + unsigned long hash0; + unsigned long hash1; + + /* Buffer descriptors */ + unsigned long bd_ram[ETH_BD_SPACE / 4]; + } regs; + + unsigned char rx_buff[ETH_MAXPL]; + unsigned char tx_buff[ETH_MAXPL]; + unsigned char lo_buff[ETH_MAXPL]; +}; + + +DEFAULT_DEBUG_CHANNEL (eth); + +/* simulator interface */ +static void eth_vapi_read (unsigned long id, unsigned long data, void *dat); +/* register interface */ +static void eth_write32 (oraddr_t addr, uint32_t value, void *dat); +static uint32_t eth_read32 (oraddr_t addr, void *dat); +/* clock */ +static void eth_controller_tx_clock (void *); +static void eth_controller_rx_clock (void *); +/* utility functions */ +static ssize_t eth_read_rx_file (struct eth_device *, void *, size_t); +static void eth_skip_rx_file (struct eth_device *, off_t); +static void eth_rx_next_packet (struct eth_device *); +static void eth_write_tx_bd_num (struct eth_device *, unsigned long value); +/* ========================================================================= */ +/* TX LOGIC */ +/*---------------------------------------------------------------------------*/ + +/* + * TX clock + * Responsible for starting and finishing TX + */ +static void +eth_controller_tx_clock (void *dat) +{ + struct eth_device *eth = dat; + int bAdvance = 1; +#if HAVE_ETH_PHY + struct sockaddr_ll sll; +#endif /* HAVE_ETH_PHY */ + long nwritten = 0; + unsigned long read_word; + + switch (eth->tx.state) + { + case ETH_TXSTATE_IDLE: + TRACE ("TX - entering state WAIT4BD (%ld)\n", eth->tx.bd_index); + eth->tx.state = ETH_TXSTATE_WAIT4BD; + break; + case ETH_TXSTATE_WAIT4BD: + /* Read buffer descriptor */ + eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index]; + eth->tx.bd_addr = eth->regs.bd_ram[eth->tx.bd_index + 1]; + + if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, READY)) + { + /*****************/ + /* initialize TX */ + eth->tx.bytes_left = eth->tx.packet_length = + GET_FIELD (eth->tx.bd, ETH_TX_BD, LENGTH); + eth->tx.bytes_sent = 0; + + /* Initialize error status bits */ + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, DEFER); + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, COLLISION); + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, RETRANSMIT); + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, UNDERRUN); + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, NO_CARRIER); + SET_FIELD (eth->tx.bd, ETH_TX_BD, RETRY, 0); + + /* Find out minimum length */ + if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, PAD) || + TEST_FLAG (eth->regs.moder, ETH_MODER, PAD)) + eth->tx.minimum_length = + GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MINFL); + else + eth->tx.minimum_length = eth->tx.packet_length; + + /* Find out maximum length */ + if (TEST_FLAG (eth->regs.moder, ETH_MODER, HUGEN)) + eth->tx.maximum_length = eth->tx.packet_length; + else + eth->tx.maximum_length = + GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MAXFL); + + /* Do we need CRC on this packet? */ + if (TEST_FLAG (eth->regs.moder, ETH_MODER, CRCEN) || + (TEST_FLAG (eth->tx.bd, ETH_TX_BD, CRC) && + TEST_FLAG (eth->tx.bd, ETH_TX_BD, LAST))) + eth->tx.add_crc = 1; + else + eth->tx.add_crc = 0; + + if (TEST_FLAG (eth->regs.moder, ETH_MODER, DLYCRCEN)) + eth->tx.crc_dly = 1; + else + eth->tx.crc_dly = 0; + /* XXX - For now we skip CRC calculation */ + + TRACE ("Ethernet: Starting TX of %lu bytes (min. %u, max. %u)\n", + eth->tx.packet_length, eth->tx.minimum_length, + eth->tx.maximum_length); + + if (eth->rtx_type == ETH_RTX_FILE) + { + /* write packet length to file */ + nwritten = + write (eth->txfd, &(eth->tx.packet_length), + sizeof (eth->tx.packet_length)); + } + + /************************************************/ + /* start transmit with reading packet into FIFO */ + TRACE ("TX - entering state READFIFO\n"); + eth->tx.state = ETH_TXSTATE_READFIFO; + } + + /* stay in this state if (TXEN && !READY) */ + break; + case ETH_TXSTATE_READFIFO: +#if 1 + if (eth->tx.bytes_sent < eth->tx.packet_length) + { + read_word = + eval_direct32 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0); + eth->tx_buff[eth->tx.bytes_sent] = + (unsigned char) (read_word >> 24); + eth->tx_buff[eth->tx.bytes_sent + 1] = + (unsigned char) (read_word >> 16); + eth->tx_buff[eth->tx.bytes_sent + 2] = + (unsigned char) (read_word >> 8); + eth->tx_buff[eth->tx.bytes_sent + 3] = (unsigned char) (read_word); + eth->tx.bytes_sent += 4; + } +#else + if (eth->tx.bytes_sent < eth->tx.packet_length) + { + eth->tx_buff[eth->tx.bytes_sent] = + eval_direct8 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0); + eth->tx.bytes_sent += 1; + } +#endif + else + { + TRACE ("TX - entering state TRANSMIT\n"); + eth->tx.state = ETH_TXSTATE_TRANSMIT; + } + break; + case ETH_TXSTATE_TRANSMIT: + /* send packet */ + switch (eth->rtx_type) + { + case ETH_RTX_FILE: + nwritten = write (eth->txfd, eth->tx_buff, eth->tx.packet_length); + break; +#if HAVE_ETH_PHY + case ETH_RTX_SOCK: + memset (&sll, 0, sizeof (sll)); + sll.sll_ifindex = eth->ifr.ifr_ifindex; + nwritten = + sendto (eth->rtx_sock, eth->tx_buff, eth->tx.packet_length, 0, + (struct sockaddr *) &sll, sizeof (sll)); +#endif /* HAVE_ETH_PHY */ + } + + /* set BD status */ + if (nwritten == eth->tx.packet_length) + { + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY); + SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB); + TRACE ("ETH_INT_SOURCE = %0lx\n", eth->regs.int_source); + + TRACE ("TX - entering state WAIT4BD\n"); + eth->tx.state = ETH_TXSTATE_WAIT4BD; + TRACE ("send (%ld)bytes OK\n", nwritten); + } + else + { + /* XXX - implement retry mechanism here! */ + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY); + CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, COLLISION); + SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE); + TRACE ("ETH_INT_SOURCE = %0lx\n", eth->regs.int_source); + + TRACE ("TX - entering state WAIT4BD\n"); + eth->tx.state = ETH_TXSTATE_WAIT4BD; + TRACE ("send FAILED!\n"); + } + + eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd; + + /* generate OK interrupt */ + if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXE_M) || + TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXB_M)) + { + if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, IRQ)) + report_interrupt (eth->mac_int); + } + + /* advance to next BD */ + if (bAdvance) + { + if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, WRAP) || + eth->tx.bd_index >= ETH_BD_COUNT) + eth->tx.bd_index = 0; + else + eth->tx.bd_index += 2; + } + + break; + } + + /* Reschedule */ + SCHED_ADD (eth_controller_tx_clock, dat, 1); +} + +/* ========================================================================= */ + + +/* ========================================================================= */ +/* RX LOGIC */ +/*---------------------------------------------------------------------------*/ + +/* + * RX clock + * Responsible for starting and finishing RX + */ +static void +eth_controller_rx_clock (void *dat) +{ + struct eth_device *eth = dat; + long nread; + unsigned long send_word; + + + switch (eth->rx.state) + { + case ETH_RXSTATE_IDLE: + TRACE ("RX - entering state WAIT4BD (%ld)\n", eth->rx.bd_index); + eth->rx.state = ETH_RXSTATE_WAIT4BD; + break; + + case ETH_RXSTATE_WAIT4BD: + eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index]; + eth->rx.bd_addr = eth->regs.bd_ram[eth->rx.bd_index + 1]; + + if (TEST_FLAG (eth->rx.bd, ETH_RX_BD, READY)) + { + /*****************/ + /* Initialize RX */ + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, MISS); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, INVALID); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, DRIBBLE); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, UVERRUN); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, COLLISION); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, TOOBIG); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, TOOSHORT); + + TRACE ("Ethernet: Starting RX\n"); + + /* Setup file to read from */ + if (TEST_FLAG (eth->regs.moder, ETH_MODER, LOOPBCK)) + { + eth->rx.fd = eth->txfd; + eth->rx.offset = &(eth->loopback_offset); + } + else + { + eth->rx.fd = eth->rxfd; + eth->rx.offset = 0; + } + TRACE ("RX - entering state RECV\n"); + eth->rx.state = ETH_RXSTATE_RECV; + } + else if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN)) + { + TRACE ("RX - entering state IDLE\n"); + eth->rx.state = ETH_RXSTATE_IDLE; + } + else + { + nread = + recv (eth->rtx_sock, eth->rx_buff, ETH_MAXPL, /*MSG_PEEK | */ + MSG_DONTWAIT); + if (nread > 0) + { + SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY); + if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, BUSY_M)) + report_interrupt (eth->mac_int); + } + } + break; + + case ETH_RXSTATE_RECV: + switch (eth->rtx_type) + { + case ETH_RTX_FILE: + /* Read packet length */ + if (eth_read_rx_file + (eth, &(eth->rx.packet_length), + sizeof (eth->rx.packet_length)) < + sizeof (eth->rx.packet_length)) + { + /* TODO: just do what real ethernet would do (some kind of error state) */ + TRACE + ("eth_start_rx(): File does not have a packet ready for RX (len = %ld)\n", + eth->rx.packet_length); + sim_done (); + break; + } + + /* Packet must be big enough to hold a header */ + if (eth->rx.packet_length < ETHER_HDR_LEN) + { + TRACE ("eth_start_rx(): Packet too small\n"); + eth_rx_next_packet (eth); + + TRACE ("RX - entering state WAIT4BD\n"); + eth->rx.state = ETH_RXSTATE_WAIT4BD; + break; + } + + eth->rx.bytes_read = 0; + eth->rx.bytes_left = eth->rx.packet_length; + + /* for now Read entire packet into memory */ + nread = eth_read_rx_file (eth, eth->rx_buff, eth->rx.bytes_left); + if (nread < eth->rx.bytes_left) + { + TRACE ("Read %ld from %ld. Error!\n", nread, + eth->rx.bytes_left); + eth->rx.error = 1; + break; + } + + eth->rx.packet_length = nread; + eth->rx.bytes_left = nread; + eth->rx.bytes_read = 0; + + TRACE ("RX - entering state WRITEFIFO\n"); + eth->rx.state = ETH_RXSTATE_WRITEFIFO; + + break; + + case ETH_RTX_SOCK: + nread = recv (eth->rtx_sock, eth->rx_buff, ETH_MAXPL, MSG_DONTWAIT); + + if (nread == 0) + { + TRACE ("No data read\n"); + break; + } + else if (nread < 0) + { + if (errno != EAGAIN) + { + TRACE ("recv() FAILED!\n"); + break; + } + else + break; + } + /* If not promiscouos mode, check the destination address */ + if (!TEST_FLAG (eth->regs.moder, ETH_MODER, PRO)) + { + if (TEST_FLAG (eth->regs.moder, ETH_MODER, IAM) + && (eth->rx_buff[0] & 1)) + { + /* Nothing for now */ + } + + if (eth->mac_address[5] != eth->rx_buff[0] || + eth->mac_address[4] != eth->rx_buff[1] || + eth->mac_address[3] != eth->rx_buff[2] || + eth->mac_address[2] != eth->rx_buff[3] || + eth->mac_address[1] != eth->rx_buff[4] || + eth->mac_address[0] != eth->rx_buff[5]) + break; + } + + eth->rx.packet_length = nread; + eth->rx.bytes_left = nread; + eth->rx.bytes_read = 0; + + TRACE ("RX - entering state WRITEFIFO\n"); + eth->rx.state = ETH_RXSTATE_WRITEFIFO; + + break; + case ETH_RTX_VAPI: + break; + } + break; + + case ETH_RXSTATE_WRITEFIFO: +#if 1 + send_word = ((unsigned long) eth->rx_buff[eth->rx.bytes_read] << 24) | + ((unsigned long) eth->rx_buff[eth->rx.bytes_read + 1] << 16) | + ((unsigned long) eth->rx_buff[eth->rx.bytes_read + 2] << 8) | + ((unsigned long) eth->rx_buff[eth->rx.bytes_read + 3]); + set_direct32 (eth->rx.bd_addr + eth->rx.bytes_read, send_word, 0, 0); + /* update counters */ + TRACE ("Write %ld, left %ld - %08lXd\n", eth->rx.bytes_read, + eth->rx.bytes_left, send_word); + eth->rx.bytes_left -= 4; + eth->rx.bytes_read += 4; +#else + set_direct8 (eth->rx.bd_addr + eth->rx.bytes_read, + eth->rx_buff[eth->rx.bytes_read], 0, 0); + eth->rx.bytes_left -= 1; + eth->rx.bytes_read += 1; +#endif + + if (eth->rx.bytes_left <= 0) + { + /* Write result to bd */ + SET_FIELD (eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length); + CLEAR_FLAG (eth->rx.bd, ETH_RX_BD, READY); + SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, RXB); + TRACE ("ETH_INT_SOURCE = %0lx\n", eth->regs.int_source); + + if (eth->rx.packet_length < + (GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MINFL) - 4)) + SET_FLAG (eth->rx.bd, ETH_RX_BD, TOOSHORT); + if (eth->rx.packet_length > + GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MAXFL)) + SET_FLAG (eth->rx.bd, ETH_RX_BD, TOOBIG); + + eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd; + + /* advance to next BD */ + if (TEST_FLAG (eth->rx.bd, ETH_RX_BD, WRAP) + || eth->rx.bd_index >= ETH_BD_COUNT) + eth->rx.bd_index = eth->regs.tx_bd_num << 1; + else + eth->rx.bd_index += 2; + + if ((TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, RXB_M)) && + (TEST_FLAG (eth->rx.bd, ETH_RX_BD, IRQ))) + { + report_interrupt (eth->mac_int); + } + + /* ready to receive next packet */ + TRACE ("RX - entering state IDLE\n"); + eth->rx.state = ETH_RXSTATE_IDLE; + } + break; + } + + /* Reschedule */ + SCHED_ADD (eth_controller_rx_clock, dat, 1); +} + +/* ========================================================================= */ +/* Move to next RX BD */ +static void +eth_rx_next_packet (struct eth_device *eth) +{ + /* Skip any possible leftovers */ + if (eth->rx.bytes_left) + eth_skip_rx_file (eth, eth->rx.bytes_left); +} + +/* "Skip" bytes in RX file */ +static void +eth_skip_rx_file (struct eth_device *eth, off_t count) +{ + eth->rx.offset += count; +} + +/* + * Utility function to read from the ethernet RX file + * This function moves the file pointer to the current place in the packet before reading + */ +static ssize_t +eth_read_rx_file (struct eth_device *eth, void *buf, size_t count) +{ + ssize_t result; + + if (eth->rx.fd <= 0) + { + TRACE ("Ethernet: No RX file\n"); + return 0; + } + + if (eth->rx.offset) + if (lseek (eth->rx.fd, *(eth->rx.offset), SEEK_SET) == (off_t) - 1) + { + TRACE ("Ethernet: Error seeking RX file\n"); + return 0; + } + + result = read (eth->rx.fd, buf, count); + TRACE ("Ethernet: read result = %d \n", result); + if (eth->rx.offset && result >= 0) + *(eth->rx.offset) += result; + + return result; +} + +/* ========================================================================= */ + +/* + Reset. Initializes all registers to default and places devices in + memory address space. +*/ +static void +eth_reset (void *dat) +{ + struct eth_device *eth = dat; +#if HAVE_ETH_PHY + int j; + struct sockaddr_ll sll; +#endif /* HAVE_ETH_PHY */ + + if (eth->baseaddr != 0) + { + switch (eth->rtx_type) + { + case ETH_RTX_FILE: + /* (Re-)open TX/RX files */ + if (eth->rxfd > 0) + close (eth->rxfd); + if (eth->txfd > 0) + close (eth->txfd); + eth->rxfd = eth->txfd = -1; + + if ((eth->rxfd = open (eth->rxfile, O_RDONLY)) < 0) + fprintf (stderr, "Cannot open Ethernet RX file \"%s\"\n", + eth->rxfile); + if ((eth->txfd = open (eth->txfile, O_RDWR | O_CREAT | O_APPEND +#if defined(O_SYNC) /* BSD / Mac OS X manual doesn't know about O_SYNC */ + | O_SYNC +#endif + , + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) + fprintf (stderr, "Cannot open Ethernet TX file \"%s\"\n", + eth->txfile); + eth->loopback_offset = lseek (eth->txfd, 0, SEEK_END); + + break; +#if HAVE_ETH_PHY + case ETH_RTX_SOCK: + /* (Re-)open TX/RX sockets */ + if (eth->rtx_sock != 0) + break; + + TRACE ("RTX opening socket...\n"); + eth->rtx_sock = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)); + if (eth->rtx_sock == -1) + { + fprintf (stderr, "Cannot open rtx_sock.\n"); + return; + } + + /* get interface index number */ + TRACE ("RTX getting interface...\n"); + memset (&(eth->ifr), 0, sizeof (eth->ifr)); + strncpy (eth->ifr.ifr_name, eth->sockif, IFNAMSIZ); + if (ioctl (eth->rtx_sock, SIOCGIFINDEX, &(eth->ifr)) == -1) + { + fprintf (stderr, "SIOCGIFINDEX failed!\n"); + return; + } + TRACE ("RTX Socket Interface : %d\n", eth->ifr.ifr_ifindex); + + /* Bind to interface... */ + TRACE ("Binding to the interface ifindex=%d\n", + eth->ifr.ifr_ifindex); + memset (&sll, 0xff, sizeof (sll)); + sll.sll_family = AF_PACKET; /* allways AF_PACKET */ + sll.sll_protocol = htons (ETH_P_ALL); + sll.sll_ifindex = eth->ifr.ifr_ifindex; + if (bind (eth->rtx_sock, (struct sockaddr *) &sll, sizeof (sll)) == + -1) + { + fprintf (stderr, "Error bind().\n"); + return; + } + + /* first, flush all received packets. */ + TRACE ("Flush"); + do + { + fd_set fds; + struct timeval t; + + TRACE ("."); + FD_ZERO (&fds); + FD_SET (eth->rtx_sock, &fds); + memset (&t, 0, sizeof (t)); + j = select (FD_SETSIZE, &fds, NULL, NULL, &t); + if (j > 0) + recv (eth->rtx_sock, eth->rx_buff, j, 0); + } + while (j); + TRACE ("\n"); + + break; +#else /* HAVE_ETH_PHY */ + case ETH_RTX_SOCK: + fprintf (stderr, + "Ethernet phy not enabled in this configuration. Configure with --enable-ethphy.\n"); + exit (1); + break; +#endif /* HAVE_ETH_PHY */ + } + + /* Set registers to default values */ + memset (&(eth->regs), 0, sizeof (eth->regs)); + eth->regs.moder = 0x0000A000; + eth->regs.ipgt = 0x00000012; + eth->regs.ipgr1 = 0x0000000C; + eth->regs.ipgr2 = 0x00000012; + eth->regs.packetlen = 0x003C0600; + eth->regs.collconf = 0x000F003F; + eth->regs.miimoder = 0x00000064; + eth->regs.tx_bd_num = 0x00000040; + + /* Initialize TX/RX status */ + memset (&(eth->tx), 0, sizeof (eth->tx)); + memset (&(eth->rx), 0, sizeof (eth->rx)); + eth->rx.bd_index = eth->regs.tx_bd_num << 1; + + /* Initialize VAPI */ + if (eth->base_vapi_id) + { + vapi_install_multi_handler (eth->base_vapi_id, ETH_NUM_VAPI_IDS, + eth_vapi_read, dat); + } + } +} + +/* ========================================================================= */ + + +/* + Print register values on stdout +*/ +static void +eth_status (void *dat) +{ + struct eth_device *eth = dat; + + PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", eth->baseaddr); + PRINTF ("MODER : 0x%08lX\n", eth->regs.moder); + PRINTF ("INT_SOURCE : 0x%08lX\n", eth->regs.int_source); + PRINTF ("INT_MASK : 0x%08lX\n", eth->regs.int_mask); + PRINTF ("IPGT : 0x%08lX\n", eth->regs.ipgt); + PRINTF ("IPGR1 : 0x%08lX\n", eth->regs.ipgr1); + PRINTF ("IPGR2 : 0x%08lX\n", eth->regs.ipgr2); + PRINTF ("PACKETLEN : 0x%08lX\n", eth->regs.packetlen); + PRINTF ("COLLCONF : 0x%08lX\n", eth->regs.collconf); + PRINTF ("TX_BD_NUM : 0x%08lX\n", eth->regs.tx_bd_num); + PRINTF ("CTRLMODER : 0x%08lX\n", eth->regs.controlmoder); + PRINTF ("MIIMODER : 0x%08lX\n", eth->regs.miimoder); + PRINTF ("MIICOMMAND : 0x%08lX\n", eth->regs.miicommand); + PRINTF ("MIIADDRESS : 0x%08lX\n", eth->regs.miiaddress); + PRINTF ("MIITX_DATA : 0x%08lX\n", eth->regs.miitx_data); + PRINTF ("MIIRX_DATA : 0x%08lX\n", eth->regs.miirx_data); + PRINTF ("MIISTATUS : 0x%08lX\n", eth->regs.miistatus); + PRINTF ("MAC Address : %02X:%02X:%02X:%02X:%02X:%02X\n", + eth->mac_address[0], eth->mac_address[1], eth->mac_address[2], + eth->mac_address[3], eth->mac_address[4], eth->mac_address[5]); + PRINTF ("HASH0 : 0x%08lX\n", eth->regs.hash0); + PRINTF ("HASH1 : 0x%08lX\n", eth->regs.hash1); +} + +/* ========================================================================= */ + + +/* + Read a register +*/ +static uint32_t +eth_read32 (oraddr_t addr, void *dat) +{ + struct eth_device *eth = dat; + + switch (addr) + { + case ETH_MODER: + return eth->regs.moder; + case ETH_INT_SOURCE: + return eth->regs.int_source; + case ETH_INT_MASK: + return eth->regs.int_mask; + case ETH_IPGT: + return eth->regs.ipgt; + case ETH_IPGR1: + return eth->regs.ipgr1; + case ETH_IPGR2: + return eth->regs.ipgr2; + case ETH_PACKETLEN: + return eth->regs.packetlen; + case ETH_COLLCONF: + return eth->regs.collconf; + case ETH_TX_BD_NUM: + return eth->regs.tx_bd_num; + case ETH_CTRLMODER: + return eth->regs.controlmoder; + case ETH_MIIMODER: + return eth->regs.miimoder; + case ETH_MIICOMMAND: + return eth->regs.miicommand; + case ETH_MIIADDRESS: + return eth->regs.miiaddress; + case ETH_MIITX_DATA: + return eth->regs.miitx_data; + case ETH_MIIRX_DATA: + return eth->regs.miirx_data; + case ETH_MIISTATUS: + return eth->regs.miistatus; + case ETH_MAC_ADDR0: + return (((unsigned long) eth->mac_address[3]) << 24) | + (((unsigned long) eth->mac_address[2]) << 16) | + (((unsigned long) eth->mac_address[1]) << 8) | + (unsigned long) eth->mac_address[0]; + case ETH_MAC_ADDR1: + return (((unsigned long) eth->mac_address[5]) << 8) | + (unsigned long) eth->mac_address[4]; + case ETH_HASH0: + return eth->regs.hash0; + case ETH_HASH1: + return eth->regs.hash1; + /*case ETH_DMA_RX_TX: return eth_rx( eth ); */ + } + + if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE)) + return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4]; + + PRINTF ("eth_read32( 0x%" PRIxADDR " ): Illegal address\n", + addr + eth->baseaddr); + return 0; +} + +/* ========================================================================= */ + + +/* + Write a register +*/ +static void +eth_write32 (oraddr_t addr, uint32_t value, void *dat) +{ + struct eth_device *eth = dat; + + switch (addr) + { + case ETH_MODER: + + if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN) && + TEST_FLAG (value, ETH_MODER, RXEN)) + SCHED_ADD (eth_controller_rx_clock, dat, 1); + else if (!TEST_FLAG (value, ETH_MODER, RXEN)) + SCHED_FIND_REMOVE (eth_controller_rx_clock, dat); + + if (!TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN) && + TEST_FLAG (value, ETH_MODER, TXEN)) + SCHED_ADD (eth_controller_tx_clock, dat, 1); + else if (!TEST_FLAG (value, ETH_MODER, TXEN)) + SCHED_FIND_REMOVE (eth_controller_tx_clock, dat); + + eth->regs.moder = value; + + if (TEST_FLAG (value, ETH_MODER, RST)) + eth_reset (dat); + return; + case ETH_INT_SOURCE: + if (!(eth->regs.int_source & ~value) && eth->regs.int_source) + clear_interrupt (eth->mac_int); + eth->regs.int_source &= ~value; + return; + case ETH_INT_MASK: + eth->regs.int_mask = value; + return; + case ETH_IPGT: + eth->regs.ipgt = value; + return; + case ETH_IPGR1: + eth->regs.ipgr1 = value; + return; + case ETH_IPGR2: + eth->regs.ipgr2 = value; + return; + case ETH_PACKETLEN: + eth->regs.packetlen = value; + return; + case ETH_COLLCONF: + eth->regs.collconf = value; + return; + case ETH_TX_BD_NUM: + eth_write_tx_bd_num (eth, value); + return; + case ETH_CTRLMODER: + eth->regs.controlmoder = value; + return; + case ETH_MIIMODER: + eth->regs.miimoder = value; + return; + case ETH_MIICOMMAND: + eth->regs.miicommand = value; + return; + case ETH_MIIADDRESS: + eth->regs.miiaddress = value; + return; + case ETH_MIITX_DATA: + eth->regs.miitx_data = value; + return; + case ETH_MIIRX_DATA: + eth->regs.miirx_data = value; + return; + case ETH_MIISTATUS: + eth->regs.miistatus = value; + return; + case ETH_MAC_ADDR0: + eth->mac_address[0] = value & 0xFF; + eth->mac_address[1] = (value >> 8) & 0xFF; + eth->mac_address[2] = (value >> 16) & 0xFF; + eth->mac_address[3] = (value >> 24) & 0xFF; + return; + case ETH_MAC_ADDR1: + eth->mac_address[4] = value & 0xFF; + eth->mac_address[5] = (value >> 8) & 0xFF; + return; + case ETH_HASH0: + eth->regs.hash0 = value; + return; + case ETH_HASH1: + eth->regs.hash1 = value; + return; + + /*case ETH_DMA_RX_TX: eth_tx( eth, value ); return; */ + } + + if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE)) + { + eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value; + return; + } + + PRINTF ("eth_write32( 0x%" PRIxADDR " ): Illegal address\n", + addr + eth->baseaddr); + return; +} + +/* ========================================================================= */ + + +/* + * VAPI connection to outside + */ +static void +eth_vapi_read (unsigned long id, unsigned long data, void *dat) +{ + unsigned long which; + struct eth_device *eth = dat; + + which = id - eth->base_vapi_id; + + TRACE ("ETH: id %08lx, data %08lx\n", id, data); + + if (!eth) + { + TRACE ("ETH: VAPI ID %08lx is not ours!\n", id); + return; + } + + switch (which) + { + case ETH_VAPI_DATA: + break; + case ETH_VAPI_CTRL: + break; + } +} + +/* ========================================================================= */ + + +/* When TX_BD_NUM is written, also reset current RX BD index */ +static void +eth_write_tx_bd_num (struct eth_device *eth, unsigned long value) +{ + eth->regs.tx_bd_num = value & 0xFF; + eth->rx.bd_index = eth->regs.tx_bd_num << 1; +} + +/* ========================================================================= */ + +/*-----------------------------------------------[ Ethernet configuration ]---*/ + + +/*---------------------------------------------------------------------------*/ +/*!Enable or disable the Ethernet interface + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_enabled (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + eth->enabled = val.int_val; + +} /* eth_enabled() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet interface base address + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_baseaddr (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + eth->baseaddr = val.addr_val; + +} /* eth_baseaddr() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet DMA port + + This is not currently supported, so a warning message is printed. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_dma (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + fprintf (stderr, "Warning: External Ethernet DMA not currently supported\n"); + eth->dma = val.addr_val; + +} /* eth_dma() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet IRQ + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_irq (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + eth->mac_int = val.int_val; + +} /* eth_irq() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet interface type + + Currently two types are supported, file and socket. Use of the socket + requires a compile time option. + + @param[in] val The value to use. 0 for file, 1 for socket. + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_rtx_type (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + if (val.int_val) + { +#ifndef HAVE_ETH_PHY + fprintf (stderr, "Warning: Ethernet PHY socket not enabled in this " + "configuration (configure with --enable-ethphy): ignored\n"); + return; +#endif + } + + eth->rtx_type = val.int_val; + +} /* eth_rtx_type() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet DMA Rx channel + + External DMA is not currently supported, so a warning message is printed. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_rx_channel (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + fprintf (stderr, "Warning: External Ethernet DMA not currently supported: " + "Rx channel ignored\n"); + eth->rx_channel = val.int_val; + +} /* eth_rx_channel() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet DMA Tx channel + + External DMA is not currently supported, so a warning message is printed. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_tx_channel (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + fprintf (stderr, "Warning: External Ethernet DMA not currently supported: " + "Tx channel ignored\n"); + eth->tx_channel = val.int_val; + +} /* eth_tx_channel() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet DMA Rx file + + Free any previously allocated value. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_rxfile (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + if (NULL != eth->rxfile) + { + free (eth->rxfile); + eth->rxfile = NULL; + } + + if (!(eth->rxfile = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral Ethernet: Run out of memory\n"); + exit (-1); + } +} /* eth_rxfile() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet DMA Tx file + + Free any previously allocated value. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_txfile (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + + if (NULL != eth->txfile) + { + free (eth->txfile); + eth->txfile = NULL; + } + + if (!(eth->txfile = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral Ethernet: Run out of memory\n"); + exit (-1); + } +} /* eth_txfile() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the Ethernet socket interface + + Free any previously allocated value. This is only meaningful if the socket + interface is configured. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +eth_sockif (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + +#ifndef HAVE_ETH_PHY + fprintf (stderr, "Warning: Ethernet PHY socket not enabled in this " + "configuration (configure with --enable-ethphy): " + "sockif ignored\n"); + return; +#endif + + if (NULL != eth->sockif) + { + free (eth->sockif); + eth->sockif = NULL; + } + + if (!(eth->sockif = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral Ethernet: Run out of memory\n"); + exit (-1); + } +} /* eth_sockif() */ + + +static void +eth_vapi_id (union param_val val, + void *dat) +{ + struct eth_device *eth = dat; + eth->base_vapi_id = val.int_val; +} + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new Ethernet configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +eth_sec_start (void) +{ + struct eth_device *new = malloc (sizeof (struct eth_device)); + + if (!new) + { + fprintf (stderr, "Peripheral Eth: Run out of memory\n"); + exit (-1); + } + + memset (new, 0, sizeof (struct eth_device)); + + new->enabled = 1; + new->baseaddr = 0; + new->dma = 0; + new->mac_int = 0; + new->rtx_type = 0; + new->rx_channel = 0; + new->tx_channel = 0; + new->rxfile = strdup ("eth_rx"); + new->txfile = strdup ("eth_tx"); + new->sockif = strdup ("or1ksim_eth"); + new->base_vapi_id = 0; + + return new; +} + +static void +eth_sec_end (void *dat) +{ + struct eth_device *eth = dat; + struct mem_ops ops; + + if (!eth->enabled) + { + free (eth->rxfile); + free (eth->txfile); + free (eth->sockif); + free (eth); + return; + } + + memset (&ops, 0, sizeof (struct mem_ops)); + + ops.readfunc32 = eth_read32; + ops.writefunc32 = eth_write32; + ops.read_dat32 = dat; + ops.write_dat32 = dat; + + /* FIXME: Correct delay? */ + ops.delayr = 2; + ops.delayw = 2; + reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops); + reg_sim_stat (eth_status, dat); + reg_sim_reset (eth_reset, dat); +} + + +/*---------------------------------------------------------------------------*/ +/*!Register a new Ethernet configuration */ +/*---------------------------------------------------------------------------*/ +void +reg_ethernet_sec () +{ + struct config_section *sec = + reg_config_sec ("ethernet", eth_sec_start, eth_sec_end); + + reg_config_param (sec, "enabled", paramt_int, eth_enabled); + reg_config_param (sec, "baseaddr", paramt_addr, eth_baseaddr); + reg_config_param (sec, "dma", paramt_int, eth_dma); + reg_config_param (sec, "irq", paramt_int, eth_irq); + reg_config_param (sec, "rtx_type", paramt_int, eth_rtx_type); + reg_config_param (sec, "rx_channel", paramt_int, eth_rx_channel); + reg_config_param (sec, "tx_channel", paramt_int, eth_tx_channel); + reg_config_param (sec, "rxfile", paramt_str, eth_rxfile); + reg_config_param (sec, "txfile", paramt_str, eth_txfile); + reg_config_param (sec, "sockif", paramt_str, eth_sockif); + reg_config_param (sec, "vapi_id", paramt_int, eth_vapi_id); + +} /* reg_ethernet_sec() */ + Index: generic.h =================================================================== --- generic.h (nonexistent) +++ generic.h (revision 1765) @@ -0,0 +1,32 @@ +/* generic.h -- Generic external peripheral + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef GENERIC__H +#define GENERIC__H + +/* Prototype for external use */ +extern void reg_generic_sec (); + +#endif /* GENERIC__H */ Index: ps2kbd.c =================================================================== --- ps2kbd.c (nonexistent) +++ ps2kbd.c (revision 1765) @@ -0,0 +1,762 @@ +/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation + + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include + +/* Package includes */ +#include "arch.h" +#include "pic.h" +#include "sim-config.h" +#include "abstract.h" +#include "sched.h" +#include "toplevel-support.h" +#include "sim-cmd.h" + + +/* Device registers */ +#define KBD_CTRL 4 +#define KBD_DATA 0 +#define KBD_SPACE 8 + +/* Keyboard commands */ +#define KBD_KCMD_RST 0xFF +#define KBD_KCMD_DK 0xF5 +#define KBD_KCMD_EK 0xF4 +#define KBD_KCMD_ECHO 0xFF +#define KBD_KCMD_SRL 0xED + +/* Keyboard responses */ +#define KBD_KRESP_RSTOK 0xAA +#define KBD_KRESP_ECHO 0xEE +#define KBD_KRESP_ACK 0xFA + +/* Controller commands */ +#define KBD_CCMD_RCB 0x20 +#define KBD_CCMD_WCB 0x60 +#define KBD_CCMD_ST1 0xAA +#define KBD_CCMD_ST2 0xAB +#define KBD_CCMD_DKI 0xAD +#define KBD_CCMD_EKI 0xAE + +/* Status register bits */ +#define KBD_STATUS_OBF 0x01 +#define KBD_STATUS_IBF 0x02 +#define KBD_STATUS_SYS 0x04 +#define KBD_STATUS_A2 0x08 +#define KBD_STATUS_INH 0x10 +#define KBD_STATUS_MOBF 0x20 +#define KBD_STATUS_TO 0x40 +#define KBD_STATUS_PERR 0x80 + +/* Command byte register bits */ +#define KBD_CCMDBYTE_INT 0x01 +#define KBD_CCMDBYTE_INT2 0x02 +#define KBD_CCMDBYTE_SYS 0x04 +#define KBD_CCMDBYTE_EN 0x10 +#define KBD_CCMDBYTE_EN2 0x20 +#define KBD_CCMDBYTE_XLAT 0x40 + +/* Length of internal scan code fifo */ +#define KBD_MAX_BUF 0x100 + +/* Keyboard is checked every KBD_SLOWDOWN cycle */ +#define KBD_BAUD_RATE 1200 + +/* ASCII to scan code conversion table */ +const static struct +{ + /* Whether shift must be pressed */ + unsigned char shift; + /* Scan code to be generated */ + unsigned char code; +} scan_table[128] = +{ +/* 0 - 15 */ + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x0E}, + { + 0, 0x0F}, + { + 0, 0x1C}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, +/* 16 - 31 */ + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x01}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, + { + 0, 0x00}, +/* 32 - 47 */ + { + 0, 0x39}, + { + 1, 0x02}, + { + 1, 0x28}, + { + 1, 0x04}, + { + 1, 0x05}, + { + 1, 0x06}, + { + 1, 0x08}, + { + 0, 0x28}, + { + 1, 0x0A}, + { + 1, 0x0B}, + { + 1, 0x09}, + { + 1, 0x0D}, + { + 0, 0x33}, + { + 0, 0x0C}, + { + 0, 0x34}, + { + 0, 0x35}, +/* 48 - 63 */ + { + 0, 0x0B}, + { + 0, 0x02}, + { + 0, 0x03}, + { + 0, 0x04}, + { + 0, 0x05}, + { + 0, 0x06}, + { + 0, 0x07}, + { + 0, 0x08}, + { + 0, 0x09}, + { + 0, 0x0A}, + { + 1, 0x27}, + { + 0, 0x27}, + { + 1, 0x33}, + { + 0, 0x0D}, + { + 1, 0x34}, + { + 1, 0x35}, +/* 64 - 79 */ + { + 1, 0x03}, + { + 1, 0x1E}, + { + 1, 0x30}, + { + 1, 0x2E}, + { + 1, 0x20}, + { + 1, 0x12}, + { + 1, 0x21}, + { + 1, 0x22}, + { + 1, 0x23}, + { + 1, 0x17}, + { + 1, 0x24}, + { + 1, 0x25}, + { + 1, 0x26}, + { + 1, 0x32}, + { + 1, 0x31}, + { + 1, 0x18}, +/* 80 - 95 */ + { + 1, 0x19}, + { + 1, 0x10}, + { + 1, 0x13}, + { + 1, 0x1F}, + { + 1, 0x14}, + { + 1, 0x16}, + { + 1, 0x2F}, + { + 1, 0x11}, + { + 1, 0x2D}, + { + 1, 0x15}, + { + 1, 0x2C}, + { + 0, 0x1A}, + { + 0, 0x2B}, + { + 0, 0x1B}, + { + 1, 0x07}, + { + 1, 0x0C}, +/* 96 - 111 */ + { + 0, 0x29}, + { + 0, 0x1E}, + { + 0, 0x30}, + { + 0, 0x2E}, + { + 0, 0x20}, + { + 0, 0x12}, + { + 0, 0x21}, + { + 0, 0x22}, + { + 0, 0x23}, + { + 0, 0x17}, + { + 0, 0x24}, + { + 0, 0x25}, + { + 0, 0x26}, + { + 0, 0x32}, + { + 0, 0x31}, + { + 0, 0x18}, +/* 112 - 127 */ + { + 0, 0x19}, + { + 0, 0x10}, + { + 0, 0x13}, + { + 0, 0x1F}, + { + 0, 0x14}, + { + 0, 0x16}, + { + 0, 0x2F}, + { + 0, 0x11}, + { + 0, 0x2D}, + { + 0, 0x15}, + { + 0, 0x2C}, + { + 1, 0x1A}, + { + 1, 0x2B}, + { + 1, 0x1B}, + { + 1, 0x29}, + { + 0, 0x00} +}; + +struct kbd_state +{ + /* Temporary buffer to store incoming scan codes */ + uint8_t buf[KBD_MAX_BUF]; + + /* Number of scan codes in buffer */ + unsigned long buf_count; + unsigned long buf_head; + unsigned long buf_tail; + + /* Input stream */ + FILE *rxfs; + + /* Controller Command (write into 0x64) */ + int ccmd; + + /* Keyboard Command (write into 0x60) */ + uint8_t kcmd; + + /* Controller Command Byte */ + uint8_t ccmdbyte; + + /* Keyboard response pending */ + unsigned long kresp; + + /* Keyboard slowdown factor */ + long slowdown; + + /* Cofiguration */ + int enabled; + int irq; + oraddr_t baseaddr; + char *rxfile; +}; + +static void +kbd_put (struct kbd_state *kbd, unsigned char c) +{ + if (kbd->buf_count >= KBD_MAX_BUF) + { + fprintf (stderr, "WARNING: Keyboard buffer overflow.\n"); + } + else + { + kbd->buf[kbd->buf_head] = c; + kbd->buf_head = (kbd->buf_head + 1) % KBD_MAX_BUF; + kbd->buf_count++; + } +} + +/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */ +static void +scan_decode (struct kbd_state *kbd, unsigned char c) +{ + /* Do not handle special characters and extended ascii */ + if (c >= 128 || !scan_table[c].code) + return; + + /* Make shift? */ + if (scan_table[c].shift) + kbd_put (kbd, 0x2a); + /* Make char */ + kbd_put (kbd, scan_table[c].code); + /* Break char */ + kbd_put (kbd, scan_table[c].code | 0x80); + /* Break shift? */ + if (scan_table[c].shift) + kbd_put (kbd, 0xaa); +} + +/* Write a register */ +static void +kbd_write8 (oraddr_t addr, uint8_t value, void *dat) +{ + struct kbd_state *kbd = dat; + switch (addr) + { + case KBD_CTRL: + kbd->ccmd = value & 0xff; + if (kbd->ccmd == KBD_CCMD_RCB) + kbd->kresp = 0x1; + if (kbd->ccmd == KBD_CCMD_ST1) + kbd->kresp = 0x1; + if (kbd->ccmd == KBD_CCMD_ST2) + kbd->kresp = 0x1; + if (kbd->ccmd == KBD_CCMD_DKI) + { + clear_interrupt (kbd->irq); + kbd->ccmdbyte |= KBD_CCMDBYTE_EN; + } + if (kbd->ccmd == KBD_CCMD_EKI) + kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN; + if (config.sim.verbose) + PRINTF ("kbd_write8(%" PRIxADDR ") %" PRIx32 "\n", addr, value); + break; + case KBD_DATA: + if (kbd->ccmd == KBD_CCMD_WCB) + { + kbd->ccmdbyte = value & 0xff; + kbd->ccmd = 0x00; + } + else + kbd->kcmd = value & 0xff; + if (kbd->kcmd == KBD_KCMD_DK) + kbd->ccmdbyte |= KBD_CCMDBYTE_EN; + if (kbd->kcmd == KBD_KCMD_EK) + kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN; + kbd->kresp = 0x1; + kbd->ccmd = 0x00; + if (config.sim.verbose) + PRINTF ("kbd_write8(%" PRIxADDR ") %" PRIx32 "\n", addr, value); + break; + default: + fprintf (stderr, "Write out of keyboard space (0x%" PRIxADDR ")!\n", + addr); + break; + } +} + +/* Read a register */ +static uint8_t +kbd_read8 (oraddr_t addr, void *dat) +{ + struct kbd_state *kbd = dat; + switch (addr) + { + case KBD_CTRL: + { + unsigned long c = 0x0; + if (kbd->kresp || kbd->buf_count) + c |= KBD_STATUS_OBF; + c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS; + c |= KBD_STATUS_INH; + if (config.sim.verbose) + PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, c); + return c; + } + case KBD_DATA: + clear_interrupt (kbd->irq); + if (kbd->ccmd) + { + unsigned long rc = 0; + if (kbd->ccmd == KBD_CCMD_RCB) + rc = kbd->ccmdbyte; + if (kbd->ccmd == KBD_CCMD_ST1) + rc = 0x55; + if (kbd->ccmd == KBD_CCMD_ST2) + rc = 0x00; + kbd->ccmd = 0x00; + kbd->kresp = 0x0; + if (config.sim.verbose) + PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, rc); + return rc; + } + else if (kbd->kresp) + { + unsigned long rc; + if (kbd->kresp == 0x2) + { + kbd->kresp = 0x0; + rc = KBD_KRESP_RSTOK; + } + else if (kbd->kcmd == KBD_KCMD_RST) + { + kbd->kresp = 0x2; + rc = KBD_KRESP_ACK; + } + else if (kbd->kcmd == KBD_KCMD_ECHO) + { + kbd->kresp = 0x0; + rc = KBD_KRESP_ECHO; + } + else + { + kbd->kresp = 0x0; + rc = KBD_KRESP_ACK; + } + kbd->kcmd = 0x00; + if (config.sim.verbose) + PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, rc); + return rc; + } + else if (kbd->buf_count) + { + unsigned long c = kbd->buf[kbd->buf_tail]; + kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF; + kbd->buf_count--; + kbd->kresp = 0x0; + if (config.sim.verbose) + PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, c); + return c; + } + kbd->kresp = 0x0; + if (config.sim.verbose) + PRINTF ("kbd_read8(%" PRIxADDR ") fifo empty\n", addr); + return 0; + default: + fprintf (stderr, "Read out of keyboard space (0x%" PRIxADDR ")!\n", + addr); + return 0; + } +} + + +/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */ +static void +kbd_job (void *dat) +{ + struct kbd_state *kbd = dat; + int c; + int kbd_int = 0; + + /* Check if there is something waiting, and decode it into kdb_buf */ + if ((c = fgetc (kbd->rxfs)) != EOF) + { + scan_decode (kbd, c); + } + kbd_int = kbd->kresp + || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0; +/* + if (config.sim.verbose && kbd_int) + PRINTF("Keyboard Interrupt.... kbd_kresp %lx kbd_buf_count %lx \n", + kbd->kresp, kbd->buf_count); +*/ + if (kbd_int) + report_interrupt (kbd->irq); + SCHED_ADD (kbd_job, dat, kbd->slowdown); +} + +/* Reset all (simulated) ps2 controlers/keyboards */ +static void +kbd_reset (void *dat) +{ + struct kbd_state *kbd = dat; + long int system_kfreq = + (long) ((1000000000.0 / (double) config.sim.clkcycle_ps)); + + system_kfreq = (system_kfreq < 1) ? 1 : system_kfreq; + + kbd->buf_count = 0; + kbd->buf_head = 0; + kbd->buf_tail = 0; + kbd->kresp = 0x0; + kbd->ccmdbyte = 0x65; /* We reset into default normal operation. */ + + if (!(kbd->rxfs = fopen (kbd->rxfile, "r")) + && !(kbd->rxfs = fopen (kbd->rxfile, "r+"))) + { + fprintf (stderr, "WARNING: Unable to open RX file stream.\n"); + return; + } + kbd->slowdown = (long) ((system_kfreq * 1000.0) / KBD_BAUD_RATE); + if (kbd->slowdown <= 0) + kbd->slowdown = 1; + SCHED_ADD (kbd_job, dat, kbd->slowdown); +} + + +static void +kbd_info (void *dat) +{ + struct kbd_state *kbd = dat; + PRINTF ("kbd_kcmd: %x\n", kbd->kcmd); + PRINTF ("kbd_ccmd: %x\n", kbd->ccmd); + PRINTF ("kbd_ccmdbyte: %x\n", kbd->ccmdbyte); + PRINTF ("kbd_kresp: %lx\n", kbd->kresp); + PRINTF ("kbd_buf_count: %lx\n", kbd->buf_count); +} + +/*----------------------------------------------------[ KBD Configuration ]---*/ + + +static void +kbd_enabled (union param_val val, void *dat) +{ + struct kbd_state *kbd = dat; + kbd->enabled = val.int_val; +} + + +static void +kbd_baseaddr (union param_val val, void *dat) +{ + struct kbd_state *kbd = dat; + kbd->baseaddr = val.addr_val; +} + + +static void +kbd_irq (union param_val val, void *dat) +{ + struct kbd_state *kbd = dat; + kbd->irq = val.int_val; +} + + +/*---------------------------------------------------------------------------*/ +/*!Set the keyboard input file + + Free any previously allocated value. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +kbd_rxfile (union param_val val, void *dat) +{ + struct kbd_state *kbd = dat; + + if (NULL != kbd->rxfile) + { + free (kbd->rxfile); + kbd->rxfile = NULL; + } + + if (!(kbd->rxfile = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral KBD: Run out of memory\n"); + exit (-1); + } +} /* kbd_rxfile() */ + + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new keyboard configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +kbd_sec_start () +{ + struct kbd_state *new = malloc (sizeof (struct kbd_state)); + + if (!new) + { + fprintf (stderr, "Peripheral KBD: Run out of memory\n"); + exit (-1); + } + + new->enabled = 1; + new->baseaddr = 0; + new->irq = 0; + new->rxfile = strdup ("kbd_in"); + + new->buf_count = 0; + new->buf_head = 0; + new->buf_tail = 0; + new->rxfs = NULL; + + return new; + +} /* kbd_sec_start() */ + + +static void +kbd_sec_end (void *dat) +{ + struct kbd_state *kbd = dat; + struct mem_ops ops; + + if (!kbd->enabled) + { + free (kbd->rxfile); + free (kbd); + return; + } + + memset (&ops, 0, sizeof (struct mem_ops)); + + ops.readfunc8 = kbd_read8; + ops.writefunc8 = kbd_write8; + ops.read_dat8 = dat; + ops.write_dat8 = dat; + + /* FIXME: Correct delay? */ + ops.delayr = 2; + ops.delayw = 2; + + reg_mem_area (kbd->baseaddr, KBD_SPACE, 0, &ops); + reg_sim_reset (kbd_reset, dat); + reg_sim_stat (kbd_info, dat); +} + +void +reg_kbd_sec () +{ + struct config_section *sec = + reg_config_sec ("kbd", kbd_sec_start, kbd_sec_end); + + reg_config_param (sec, "baseaddr", paramt_addr, kbd_baseaddr); + reg_config_param (sec, "enabled", paramt_int, kbd_enabled); + reg_config_param (sec, "irq", paramt_int, kbd_irq); + reg_config_param (sec, "rxfile", paramt_str, kbd_rxfile); +}
ps2kbd.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: atadevice.c =================================================================== --- atadevice.c (nonexistent) +++ atadevice.c (revision 1765) @@ -0,0 +1,613 @@ +/* atadevice.c -- ATA Device simulation. Simulates a harddisk, using a local + streams. + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include + +/* Package includes */ +#include "atadevice.h" +#include "atadevice-cmdi.h" +#include "atacmd.h" +#include "debug.h" +#include "abstract.h" + + +DEFAULT_DEBUG_CHANNEL (ata); + +/* + mandatory commands: + - execute device diagnostics (done) + - flush cache + - identify device (done) + - initialize device parameters (done) + - read dma + - read multiple + - read sector(s) (done) + - read verify sector(s) + - seek + - set features + - set multiple mode + - write dma + - write multiple + - write sector(s) + + + optional commands: + - download microcode + - nop + - read buffer + - write buffer + + + prohibited commands: + - device reset +*/ + + +/* Use a file to simulate a hard-disk */ +static FILE * +open_file (uint32_t * size, const char *filename) +{ + FILE *fp; + unsigned long n; + + // TODO: + + /* check if a file with name 'filename' already exists */ + if (!(fp = fopen (filename, "rb+"))) + if (!(fp = fopen (filename, "wb+"))) + { + ERR ("ata_open_file, cannot open hd-file %s\n", filename); + return NULL; + } + else + { + /* TODO create a file 'size' large */ + /* create a file 'size' large */ + TRACE ("ata_device; generating a new hard disk file.\n"); + TRACE ("This may take a while, depending on the requested size.\n"); + for (n = 0; n < *size; n++) + fputc (0, fp); + } + else /* file already exist */ + fprintf (stderr, "file %s already exists. Using existing file.\n", + filename); + + TRACE ("requested filesize was: %d (MBytes).\n", *size); + + /* get the size of the file. This is also the size of the harddisk */ + fseek (fp, 0, SEEK_END); + *size = ftell (fp); + + TRACE ("actual filesize is: %d (MBytes).\n", *size >> 20); + + return fp; +} + + +/* Use a the local filesystem as a hard-disk */ +static FILE * +open_local (void) +{ + // TODO: + FIXME + ("Device type LOCAL is not yet supported. Defaulting to device type NO_CONNECT."); + return NULL; +} + +static void +ata_device_init (struct ata_device * device, int dev) +{ + /* set DeviceID */ + device->internals.dev = dev; + + /* generate stream for hd_simulation */ + switch (device->conf.type) + { + case TYPE_NO_CONNECT: + TRACE ("ata_device, using type NO_CONNECT.\n"); + device->conf.stream = NULL; + break; + + case TYPE_FILE: + TRACE ("ata_device, using device type FILE.\n"); + device->conf.stream = open_file (&device->conf.size, device->conf.file); + break; + + case TYPE_LOCAL: + TRACE ("ata_device, using device type LOCAL.\n"); + device->conf.stream = open_local (); + break; + + default: + ERR ("Illegal device-type. Defaulting to type NO_CONNECT.\n"); + device->conf.stream = NULL; + break; + } + + device->conf.size_sect = device->conf.size / BYTES_PER_SECTOR; +} + +/* + D E V I C E S _ I N I T +*/ +void +ata_devices_init (struct ata_devices * devices) +{ + ata_device_init (&devices->device[0], 0); + + if (devices->device[0].conf.type) + ata_device_init (&devices->device[1], ATA_DHR_DEV); + else + ata_device_init (&devices->device[1], 0); +} + +/* + D E V I C E S _ H W _ R E S E T +*/ +static void +ata_device_hw_reset (struct ata_device * device, int reset_signal, + int daspo, int pdiagi, int daspi) +{ + /* check ata-device state */ + if (device->internals.state == ATA_STATE_HW_RST) + { + if (!reset_signal) + { + /* hardware reset finished */ + + /* set sectors_per_track & heads_per_cylinders */ + device->internals.sectors_per_track = device->conf.sectors; + device->internals.heads_per_cylinder = device->conf.heads; + + /* set device1 input signals */ + device->sigs.pdiagi = pdiagi; + device->sigs.daspi = daspi; + + ata_execute_device_diagnostics_cmd (device); + + /* clear busy bit */ + device->regs.status &= ~ATA_SR_BSY; + + /* set DRDY bit, when not a PACKET device */ + if (!device->conf.packet) + device->regs.status |= ATA_SR_DRDY; + + /* set new state */ + device->internals.state = ATA_STATE_IDLE; + } + } + else if (reset_signal) + { + /* hardware reset signal asserted, stop what we are doing */ + + /* negate bus signals */ + device->sigs.iordy = 0; + device->sigs.intrq = 0; + device->sigs.dmarq = 0; + device->sigs.pdiago = 0; + device->sigs.daspo = daspo; + + /* set busy bit */ + device->regs.status |= ATA_SR_BSY; + + /* set new state */ + device->internals.state = ATA_STATE_HW_RST; + } +} + +/* power-on and hardware reset */ +void +ata_devices_hw_reset (struct ata_devices * devices, int reset_signal) +{ + /* display debug information */ + TRACE (reset_signal ? "Starting reset\n" : "Finishing reset\n"); + + /* find device 0 */ + if ((devices->device[0].conf.stream) && (devices->device[1].conf.stream)) + { + /* this one is simple, device0 is device0 */ + + /* 1) handle device1 first */ + ata_device_hw_reset (&devices->device[1], reset_signal, 1, /* assert dasp, this is device1 */ + 0, /* negate pdiag input, no more devices */ + 0); /* negate dasp input, no more devices */ + + /* 2) Then handle device0 */ + ata_device_hw_reset (&devices->device[0], reset_signal, + 0, + devices->device[1].sigs.pdiago, + devices->device[1].sigs.daspo); + } + else if (devices->device[0].conf.stream) + { + /* device0 is device0, there's no device1 */ + ata_device_hw_reset (&devices->device[0], reset_signal, 0, /* negate dasp, this is device0 */ + 0, /* negate pdiag input, there's no device1 */ + 0); /* negate dasp input, there's no device1 */ + } + else if (devices->device[1].conf.stream) + { + /* device1 is (logical) device0, there's no (physical) device0 */ + ata_device_hw_reset (&devices->device[1], reset_signal, 0, /* negate dasp, this is device0 */ + 0, /* negate pdiag input, there's no device1 */ + 0); /* negate dasp input, there's no device1 */ + } + else + { + /* no devices connected */ + TRACE ("ata_device_hw_reset, no devices connected.\n"); + } +} + + +/* + D E V I C E S _ D O _ C O N T R O L _ R E G I S T E R + + Handles - software reset + - Interrupt enable bit +*/ +static void +ata_device_do_control_register (struct ata_device * device) +{ + /* TODO respond to new values of nIEN */ + /* if device not selected, respond to new values of nIEN & SRST */ + + /* check if SRST bit is set */ + if (device->regs.device_control & ATA_DCR_RST) + { + if (device->internals.state == ATA_STATE_IDLE) + { /* start software reset */ + /* negate bus signals */ + device->sigs.pdiago = 0; + device->sigs.intrq = 0; + device->sigs.iordy = 0; + device->sigs.dmarq = 0; + + /* set busy bit */ + device->regs.status |= ATA_SR_BSY; + + /* set new state */ + device->internals.state = ATA_STATE_SW_RST; + + /* display debug information */ + TRACE ("ata_device_sw_reset initiated.\n"); + } + } + else if (device->internals.state == ATA_STATE_SW_RST) + { /* are we doing a software reset ?? */ + /* SRST bit cleared, end of software reset */ + + /*execute device diagnostics */ + ata_execute_device_diagnostics_cmd (device); + + /* clear busy bit */ + device->regs.status &= ~ATA_SR_BSY; + + /* set DRDY bit, when not a PACKET device */ + if (!device->conf.packet) + device->regs.status |= ATA_SR_DRDY; + + /* set new state */ + device->internals.state = ATA_STATE_IDLE; + + /* display debug information */ + TRACE ("ata_device_sw_reset done.\n"); + } + /* + We are doing a hardware reset (or similar) + ignore command + */ +} + + +/* + D E V I C E S _ D O _ C O M M A N D _ R E G I S T E R +*/ +static void +ata_device_do_command_register (struct ata_device * device) +{ + /* check BSY & DRQ */ + if ((device->regs.status & ATA_SR_BSY) + || (device->regs.status & ATA_SR_DRQ)) + if (device->regs.command != DEVICE_RESET) + WARN + ("ata_device_write, writing a command while BSY or DRQ asserted.\n"); + + /* check if device selected */ + if ((device->regs.device_head & ATA_DHR_DEV) == device->internals.dev) + ata_device_execute_cmd (device); + else + { + /* if not selected, only respond to EXECUTE DEVICE DIAGNOSTICS */ + if (device->regs.command == EXECUTE_DEVICE_DIAGNOSTICS) + ata_device_execute_cmd (device); + } +} + + +/* Return contents of status register in pretty for */ +static const char * +ata_pretty_status (uint8_t status) +{ + static char str[50]; + + str[0] = '\0'; + if (status & ATA_SR_BSY) + strcat (str, "BUSY"); + if (status & ATA_SR_DRDY) + strcat (str, "| READY"); + if (status & ATA_SR_DF) + strcat (str, "| FAULT"); + if (status & ATA_SR_DSC) + strcat (str, "| SEEKC"); + if (status & ATA_SR_DRQ) + strcat (str, "| DRQ"); + if (status & ATA_SR_COR) + strcat (str, "| COR"); + if (status & ATA_SR_IDX) + strcat (str, "| IDX"); + if (status & ATA_SR_ERR) + strcat (str, "| ERROR"); + return str; +} + +/* + D E V I C E S _ R E A D +*/ +/* Read from devices */ +short +ata_devices_read (struct ata_devices * devices, char adr) +{ + struct ata_device *device; + + /* check for no connected devices */ + if ((!devices->device[0].conf.stream) && (!devices->device[1].conf.stream)) + ERR ("ata_devices_read, no ata devices connected.\n"); + else + { + /* check if both device0 and device1 are connected */ + if ((devices->device[0].conf.stream) + && (devices->device[1].conf.stream)) + { + /* get the current active device */ + if (devices->device[1].regs.device_head & ATA_DHR_DEV) + device = &devices->device[1]; + else + device = &devices->device[0]; + } + else + { + /* only one device connected */ + if (devices->device[1].conf.stream) + device = &devices->device[1]; + else + device = &devices->device[0]; + } + + /* return data provided by selected device */ + switch (adr) + { + case ATA_ASR: + TRACE ("read alternate status register: %s\n", + ata_pretty_status (device->regs.status)); + if ((device->regs.device_head & ATA_DHR_DEV) == + device->internals.dev) + return device->regs.status; + else + { + TRACE ("device0 responds for device1, asr = 0x00\n"); + return 0; // return 0 when device0 responds for device1 + } + + case ATA_CHR: + TRACE ("cylinder_high register read, value = 0x%02X\n", + device->regs.cylinder_high); + return device->regs.cylinder_high; + + case ATA_CLR: + TRACE ("cylinder_low register read, value = 0x%02X\n", + device->regs.cylinder_low); + return device->regs.cylinder_low; + + case ATA_DR: + if (!device->regs.status & ATA_SR_DRQ) + { + TRACE ("data register read, while DRQ bit negated\n"); + return 0; + } + else + { + uint16_t val = LE16 (*device->internals.dbuf_ptr++); + TRACE ("data register read, value = 0x%04X, cnt = %3d\n", val, + device->internals.dbuf_cnt); + if (!--device->internals.dbuf_cnt) + { + device->regs.status &= ~ATA_SR_DRQ; + if (device->internals.end_t_func) + device->internals.end_t_func (device); + } + return val; + } + + case ATA_DHR: + TRACE ("device_head register read, value = 0x%02X\n", + device->regs.device_head); + return device->regs.device_head; + + case ATA_ERR: + TRACE ("error register read, value = 0x%02X\n", device->regs.error); + return device->regs.error; + + case ATA_SCR: + TRACE ("sectorcount register read, value = 0x%02X\n", + device->regs.sector_count); + return device->regs.sector_count; + + case ATA_SNR: + TRACE ("sectornumber register read, value = 0x%02X\n", + device->regs.sector_number); + return device->regs.sector_number; + + case ATA_SR: + TRACE ("read status register: %s\n", + ata_pretty_status (device->regs.status)); + if ((device->regs.device_head & ATA_DHR_DEV) == + device->internals.dev) + { + device->sigs.intrq = 0; + return device->regs.status; + } + + TRACE ("device0 responds for device1, sr = 0x00\n"); + return 0; // return 0 when device0 responds for device1 + +// case ATA_DA : +// return device -> regs.status; + } + } + return 0; +} + + +/* + D E V I C E S _ W R I T E +*/ +/* write to a single device */ +static void +ata_device_write (struct ata_device * device, char adr, short value) +{ + switch (adr) + { + case ATA_CR: + /*display debug information */ + TRACE ("command register written, value = 0x%02X\n", value); + + device->regs.command = value; + + /* check command register settings and execute command */ + ata_device_do_command_register (device); + break; + + + case ATA_CHR: + /*display debug information */ + TRACE ("cylinder high register written, value = 0x%02X\n", value); + + device->regs.cylinder_high = value; + break; + + case ATA_CLR: + /*display debug information */ + TRACE ("cylinder low register written, value = 0x%02X\n", value); + + device->regs.cylinder_low = value; + break; + + case ATA_DR: + /*display debug information */ + if (!device->regs.status & ATA_SR_DRQ) + { + TRACE ("data register write, while DRQ bit negated\n"); + break; + } + else + { + TRACE ("data register write, value = 0x%04X, cnt = %3d\n", + value, device->internals.dbuf_cnt); + *device->internals.dbuf_ptr++ = LE16 (value); + if (!--device->internals.dbuf_cnt) + { + device->regs.status &= ~ATA_SR_DRQ; + if (device->internals.end_t_func) + device->internals.end_t_func (device); + } + } + device->regs.dataport_i = value; + break; + + case ATA_DCR: + /*display debug information */ + TRACE ("device control register written, value = 0x%02X\n", value); + + device->regs.device_control = value; + ata_device_do_control_register (device); + break; + + case ATA_DHR: + /*display debug information */ + TRACE ("device head register written, value = 0x%02X\n", value); + + device->regs.device_head = value; + break; + + case ATA_FR: + /*display debug information */ + TRACE ("features register written, value = 0x%02X\n", value); + + device->regs.features = value; + break; + + case ATA_SCR: + /*display debug information */ + TRACE ("sectorcount register written, value = 0x%02X\n", value); + + device->regs.sector_count = value; + break; + + case ATA_SNR: + /*display debug information */ + TRACE ("sectornumber register written, value = 0x%02X\n", value); + + device->regs.sector_number = value; + break; + + } //endcase +} + +/* Write to devices */ +void +ata_devices_write (struct ata_devices * devices, char adr, short value) +{ + /* check for no connected devices */ + if (!devices->device[0].conf.stream && !devices->device[1].conf.stream) + ERR ("ata_devices_write, no ata devices connected.\n"); + else + { + /* first device */ + if (devices->device[0].conf.stream) + ata_device_write (&devices->device[0], adr, value); + + /* second device */ + if (devices->device[1].conf.stream) + ata_device_write (&devices->device[1], adr, value); + } +} Index: eth.h =================================================================== --- eth.h (nonexistent) +++ eth.h (revision 1765) @@ -0,0 +1,33 @@ +/* eth.h -- Simulation of Ethernet MAC header + + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef ETH__H +#define ETH__H + +/* Prototypes for external use */ +extern void reg_ethernet_sec (); + +#endif /* ETH__H */ Index: fb.c =================================================================== --- fb.c (nonexistent) +++ fb.c (revision 1765) @@ -0,0 +1,555 @@ +/* fb.c -- Simple frame buffer + + Copyright (C) 2001 Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include + +/* Package includes */ +#include "arch.h" +#include "sim-config.h" +#include "abstract.h" +#include "sched.h" +#include "toplevel-support.h" + + +#define FB_SIZEX 640 +#define FB_SIZEY 480 + +#define CAM_SIZEX 352 +#define CAM_SIZEY 288 + +/*! Relative amount of time spent in refresh */ +#define REFRESH_DIVIDER 20 + +#define FB_CTRL 0x0000 +#define FB_BUFADDR 0x0004 +#define FB_CAMBUFADDR 0x0008 +#define FB_CAMPOSADDR 0x000c +#define FB_PAL 0x0400 + +#define FB_WRAP (512*1024) + +struct fb_state +{ + int enabled; + unsigned long pal[256]; + int ctrl; + int pic; + int in_refresh; + int refresh_count; + oraddr_t addr; + oraddr_t cam_addr; + int camerax; + int cameray; + int camera_pos; + oraddr_t baseaddr; + int refresh; + int refresh_rate; + char *filename; +}; + +static void +change_buf_addr (struct fb_state *fb, oraddr_t addr) +{ + fb->addr = addr; +} + +/* Write a register */ +static void +fb_write32 (oraddr_t addr, uint32_t value, void *dat) +{ + struct fb_state *fb = dat; + + switch (addr) + { + case FB_CTRL: + fb->ctrl = value; + break; + case FB_BUFADDR: + change_buf_addr (fb, value); + break; + case FB_CAMBUFADDR: + fb->cam_addr = value; + break; + case FB_CAMPOSADDR: + fb->camera_pos = value; + fb->camerax = value % FB_SIZEX; + fb->cameray = value / FB_SIZEX; + break; + default: + addr -= FB_PAL; + addr /= 4; + if (addr < 0 || addr >= 256) + { + fprintf (stderr, "Write out of palette buffer (0x%" PRIxADDR ")!\n", + addr); + } + else + fb->pal[addr] = value; + break; + } +} + +/* Read a register */ +static oraddr_t +fb_read32 (oraddr_t addr, void *dat) +{ + struct fb_state *fb = dat; + + switch (addr) + { + case FB_CTRL: + return (fb->ctrl & ~0xff000000) | (fb-> + in_refresh ? 0x80000000 : 0) | + ((unsigned long) (fb->refresh_count & 0x7f) << 24); + break; + case FB_BUFADDR: + return fb->addr; + break; + case FB_CAMBUFADDR: + return fb->cam_addr; + break; + case FB_CAMPOSADDR: + return fb->camera_pos; + break; + default: + addr -= FB_PAL; + addr /= 4; + if (addr < 0 || addr >= 256) + { + fprintf (stderr, "Read out of palette buffer (0x%" PRIxADDR ")!\n", + addr); + return 0; + } + else + return fb->pal[addr]; + } +} + +/* define these also for big endian */ +#if __BIG_ENDIAN__ +#define CNV32(x) (\ + ((((x) >> 24) & 0xff) << 0)\ + | ((((x) >> 16) & 0xff) << 8)\ + | ((((x) >> 8) & 0xff) << 16)\ + | ((((x) >> 0) & 0xff) << 24)) +#define CNV16(x) (\ + ((((x) >> 8) & 0xff) << 0)\ + | ((((x) >> 0) & 0xff) << 8)) +#else +#define CNV16(x) (x) +#define CNV32(x) (x) +#endif + +/* Dumps a bmp file, based on current image */ +static int +fb_dump_image8 (struct fb_state *fb, char *filename) +{ + int sx = FB_SIZEX; + int sy = FB_SIZEY; + int i, x = 0, y = 0; + FILE *fo; + + unsigned short int u16; + unsigned long int u32; + + if (config.sim.verbose) + PRINTF ("Creating %s...", filename); + fo = fopen (filename, "wb+"); + u16 = CNV16 (19778); /* BM */ + if (!fwrite (&u16, 2, 1, fo)) + return 1; + u32 = CNV32 (14 + 40 + sx * sy + 1024); /* size */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (0); /* reserved */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = 14 + 40 + 1024; /* offset */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + + u32 = CNV32 (40); /* header size */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (sx); /* width */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (sy); /* height */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u16 = CNV16 (1); /* planes */ + if (!fwrite (&u16, 2, 1, fo)) + return 1; + u16 = CNV16 (8); /* bits */ + if (!fwrite (&u16, 2, 1, fo)) + return 1; + u32 = CNV32 (0); /* compression */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (x * y); /* image size */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (2835); /* x resolution */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (2835); /* y resolution */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (0); /* ncolours = 0; should be generated */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (0); /* important colours; all are important */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + + for (i = 0; i < 256; i++) + { + unsigned long val, d; + d = fb->pal[i]; +#if 1 + val = ((d >> 0) & 0x1f) << 3; /* Blue */ + val |= ((d >> 5) & 0x3f) << 10; /* Green */ + val |= ((d >> 11) & 0x1f) << 19; /* Red */ +#else + val = CNV32 (pal[i]); +#endif + if (!fwrite (&val, 4, 1, fo)) + return 1; + } + + if (config.sim.verbose) + PRINTF ("(%i,%i)", sx, sy); + /* Data is stored upside down */ + for (y = sy - 1; y >= 0; y--) + { + int align = (4 - sx) % 4; + int zero = CNV32 (0); + int add; + while (align < 0) + align += 4; + for (x = 0; x < sx; x++) + { + add = + (fb-> + addr & ~(FB_WRAP - 1)) | ((fb->addr + y * sx + x) & (FB_WRAP - + 1)); + fputc (eval_direct8 (add, 0, 0), fo); + } + if (align && !fwrite (&zero, align, 1, fo)) + return 1; + } + + if (config.sim.verbose) + PRINTF ("DONE\n"); + fclose (fo); + return 0; +} + +/* Dumps a bmp file, based on current image */ +static int +fb_dump_image24 (struct fb_state *fb, char *filename) +{ + int sx = FB_SIZEX; + int sy = FB_SIZEY; + int x = 0, y = 0; + FILE *fo; + + unsigned short int u16; + unsigned long int u32; + + if (config.sim.verbose) + PRINTF ("Creating %s...", filename); + fo = fopen (filename, "wb+"); + u16 = CNV16 (19778); /* BM */ + if (!fwrite (&u16, 2, 1, fo)) + return 1; + u32 = CNV32 (14 + 40 + sx * sy * 3); /* size */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (0); /* reserved */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = 14 + 40; /* offset */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + + u32 = CNV32 (40); /* header size */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (sx); /* width */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (sy); /* height */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u16 = CNV16 (1); /* planes */ + if (!fwrite (&u16, 2, 1, fo)) + return 1; + u16 = CNV16 (24); /* bits */ + if (!fwrite (&u16, 2, 1, fo)) + return 1; + u32 = CNV32 (0); /* compression */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (x * y * 3); /* image size */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (2835); /* x resolution */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (2835); /* y resolution */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (0); /* ncolours = 0; should be generated */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + u32 = CNV32 (0); /* important colours; all are important */ + if (!fwrite (&u32, 4, 1, fo)) + return 1; + + if (config.sim.verbose) + PRINTF ("(%i,%i)", sx, sy); + /* Data is stored upside down */ + for (y = sy - 1; y >= 0; y--) + { + unsigned char line[FB_SIZEX][3]; + for (x = 0; x < sx; x++) + if (y >= fb->cameray && x >= fb->camerax + && y < fb->cameray + CAM_SIZEY && x < fb->camerax + CAM_SIZEX) + { + int add = + (fb->cam_addr + + (x - fb->camerax + (y - fb->cameray) * CAM_SIZEX) * 2) ^ 2; + unsigned short d = eval_direct16 (add, 0, 0); + line[x][0] = ((d >> 0) & 0x1f) << 3; /* Blue */ + line[x][1] = ((d >> 5) & 0x3f) << 2; /* Green */ + line[x][2] = ((d >> 11) & 0x1f) << 3; /* Red */ + } + else + { + int add = + (fb-> + addr & ~(FB_WRAP - 1)) | ((fb->addr + y * sx + x) & (FB_WRAP - + 1)); + unsigned short d = fb->pal[eval_direct8 (add, 0, 0)]; + line[x][0] = ((d >> 0) & 0x1f) << 3; /* Blue */ + line[x][1] = ((d >> 5) & 0x3f) << 2; /* Green */ + line[x][2] = ((d >> 11) & 0x1f) << 3; /* Red */ + } + if (!fwrite (line, sizeof (line), 1, fo)) + return 1; + } + + if (config.sim.verbose) + PRINTF ("DONE\n"); + fclose (fo); + return 0; +} + +static void +fb_job (void *dat) +{ + struct fb_state *fb = dat; + + if (fb->refresh) + { + /* dump the image? */ + if (fb->ctrl & 1) + { + char temp[STR_SIZE]; + sprintf (temp, "%s%04i.bmp", fb->filename, fb->pic); + if (fb->ctrl & 2) + fb_dump_image24 (fb, temp); + else + fb_dump_image8 (fb, temp); + fb->pic++; + } + SCHED_ADD (fb_job, dat, fb->refresh_rate / REFRESH_DIVIDER); + fb->in_refresh = 0; + fb->refresh = 0; + } + else + { + fb->refresh_count++; + fb->refresh = 1; + SCHED_ADD (fb_job, dat, fb->refresh_rate / REFRESH_DIVIDER); + } +} + +/* Reset all FBs */ +static void +fb_reset (void *dat) +{ + struct fb_state *fb = dat; + int i; + + fb->pic = 0; + fb->addr = 0; + fb->ctrl = 0; + + for (i = 0; i < 256; i++) + fb->pal[i] = (i << 16) | (i << 8) | (i << 0); + + SCHED_ADD (fb_job, dat, fb->refresh_rate); + fb->refresh = 0; +} + +/*-----------------------------------------------------[ FB configuration ]---*/ +static void +fb_enabled (union param_val val, void *dat) +{ + struct fb_state *fb = dat; + fb->enabled = val.int_val; +} + + +static void +fb_baseaddr (union param_val val, void *dat) +{ + struct fb_state *fb = dat; + fb->baseaddr = val.addr_val; +} + + +static void +fb_refresh_rate (union param_val val, void *dat) +{ + struct fb_state *fb = dat; + fb->refresh_rate = val.int_val; +} + + +/*---------------------------------------------------------------------------*/ +/*!Set the frame buffer output file + + Free any previously allocated value. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +fb_filename (union param_val val, + void *dat) +{ + struct fb_state *fb = dat; + + if (NULL != fb->filename) + { + free (fb->filename); + fb->filename = NULL; + } + + if (!(fb->filename = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral FB: Run out of memory\n"); + exit (-1); + } +} /* fb_filename() */ + + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new frame buffer configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +fb_sec_start () +{ + struct fb_state *new = malloc (sizeof (struct fb_state)); + + if (!new) + { + fprintf (stderr, "Peripheral FB: Run out of memory\n"); + exit (-1); + } + + new->enabled = 1; + new->baseaddr = 0; + new->refresh_rate = 1000000000000ULL / 50ULL / config.sim.clkcycle_ps; + new->filename = strdup ("fb_out"); + + new->ctrl = 0; + new->pic = 0; + new->in_refresh = 1; + new->refresh_count = 0; + new->addr = 0; + new->cam_addr = 0; + new->camerax = 0; + new->cameray = 0; + new->camera_pos = 0; + + return new; + +} /* fb_sec_start() */ + + +static void +fb_sec_end (void *dat) +{ + struct fb_state *fb = dat; + struct mem_ops ops; + + if (!fb->enabled) + { + free (fb->filename); + free (fb); + return; + } + + memset (&ops, 0, sizeof (struct mem_ops)); + + ops.readfunc32 = fb_read32; + ops.writefunc32 = fb_write32; + ops.write_dat32 = dat; + ops.read_dat32 = dat; + + /* FIXME: Correct delay? */ + ops.delayr = 2; + ops.delayw = 2; + + reg_mem_area (fb->baseaddr, FB_PAL + 256 * 4, 0, &ops); + + reg_sim_reset (fb_reset, dat); +} + +void +reg_fb_sec () +{ + struct config_section *sec = + reg_config_sec ("fb", fb_sec_start, fb_sec_end); + + reg_config_param (sec, "baseaddr", paramt_addr, fb_baseaddr); + reg_config_param (sec, "enabled", paramt_int, fb_enabled); + reg_config_param (sec, "refresh_rate", paramt_int, fb_refresh_rate); + reg_config_param (sec, "txfile", paramt_str, fb_filename); + reg_config_param (sec, "filename", paramt_str, fb_filename); +}
fb.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: atadevice.h =================================================================== --- atadevice.h (nonexistent) +++ atadevice.h (revision 1765) @@ -0,0 +1,218 @@ +/* atadevice.h -- ATA Device code simulation + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* + * Definitions for the Opencores ATA Controller Core, Device model + */ + +#ifndef ATADEVICE__H +#define ATADEVICE__H + +/* Autoconf and/or portability configuration */ +#include "port.h" + +/* System includes */ +#include + +/* --- Register definitions --- */ +/* ----- ATA Registers */ +/* These are actually the memory locations where the ATA registers */ +/* can be found in the host system; i.e. as seen from the CPU. */ +/* However, this doesn't matter for the simulator. */ +#define ATA_ASR 0x78 /* Alternate Status Register (R) */ +#define ATA_CR 0x5c /* Command Register (W) */ +#define ATA_CHR 0x54 /* Cylinder High Register (R/W) */ +#define ATA_CLR 0x50 /* Cylinder Low Register (R/W) */ +#define ATA_DR 0x40 /* Data Register */ +#define ATA_DCR 0x78 /* Device Control Register (W) */ +#define ATA_DHR 0x58 /* Device/Head Register (R/W) */ +#define ATA_ERR 0x44 /* Error Register (R) */ +#define ATA_FR 0x44 /* Features Register (W) */ +#define ATA_SCR 0x48 /* Sector Count Register (R/W) */ +#define ATA_SNR 0x4c /* Sector Number Register (R/W) */ +#define ATA_SR 0x5c /* Status Register (R) */ +#define ATA_DA 0x7c /* Device Address Register (R) */ + /* ATA/ATAPI-5 does not describe Device Status Register */ + +/* -------------------------------------- */ +/* ----- ATA Device bit defenitions ----- */ +/* -------------------------------------- */ + +/* ----- ATA (Alternate) Status Register */ +#define ATA_SR_BSY 0x80 /* Busy */ +#define ATA_SR_DRDY 0x40 /* Device Ready */ +#define ATA_SR_DF 0x20 /* Device Fault */ +#define ATA_SR_DSC 0x10 /* Device Seek Complete */ +#define ATA_SR_DRQ 0x08 /* Data Request */ +#define ATA_SR_COR 0x04 /* Corrected data (obsolete) */ +#define ATA_SR_IDX 0x02 /* (obsolete) */ +#define ATA_SR_ERR 0x01 /* Error */ + +/* ----- ATA Device Control Register */ + /* bits 7-3 are reserved */ +#define ATA_DCR_RST 0x04 /* Software reset (RST=1, reset) */ +#define ATA_DCR_IEN 0x02 /* Interrupt Enable (IEN=0, enabled) */ + /* always write a '0' to bit0 */ + +/* ----- ATA Device Address Register */ +/* All values in this register are one's complement (i.e. inverted) */ +#define ATA_DAR_WTG 0x40 /* Write Gate */ +#define ATA_DAR_H 0x3c /* Head Select */ +#define ATA_DAR_DS1 0x02 /* Drive select 1 */ +#define ATA_DAR_DS0 0x01 /* Drive select 0 */ + +/* ----- Device/Head Register */ +#define ATA_DHR_LBA 0x40 /* LBA/CHS mode ('1'=LBA mode) */ +#define ATA_DHR_DEV 0x10 /* Device ('0'=dev0, '1'=dev1) */ +#define ATA_DHR_H 0x0f /* Head Select */ + +/* ----- Error Register */ +#define ATA_ERR_BBK 0x80 /* Bad Block */ +#define ATA_ERR_UNC 0x40 /* Uncorrectable Data Error */ +#define ATA_ERR_IDNF 0x10 /* ID Not Found */ +#define ATA_ERR_ABT 0x04 /* Aborted Command */ +#define ATA_ERR_TON 0x02 /* Track0 Not Found */ +#define ATA_ERR_AMN 0x01 /* Address Mark Not Found */ + +/* -------------------------- */ +/* ----- Device Defines ----- */ +/* -------------------------- */ + +/* types for hard disk simulation */ +#define TYPE_NO_CONNECT 0 +#define TYPE_FILE 1 +#define TYPE_LOCAL 2 + + +/* ----------------------------- */ +/* ----- Statemachine defines -- */ +/* ----------------------------- */ +#define ATA_STATE_IDLE 0x00 +#define ATA_STATE_SW_RST 0x01 +#define ATA_STATE_HW_RST 0x02 + + +/* ---------------------------- */ +/* ----- Structs ----- */ +/* ---------------------------- */ +struct ata_device +{ + + /******* Housekeeping *****************************************/ + struct + { + /* Pointer to host that device is attached to */ + void *host; + /* device number */ + int dev; + + /* current PIO mode */ + int pio_mode; + + /* current DMA mode */ + int dma_mode; + + /* databuffer */ + uint16_t dbuf[4096]; + uint16_t *dbuf_ptr; + uint16_t dbuf_cnt; + + /* current statemachine state */ + int state; + + /* current CHS translation settings */ + unsigned int heads_per_cylinder; + unsigned int sectors_per_track; + + /* Current byte being read */ + uint32_t lba; + /* Number of sectors still needing to be read */ + int nr_sect; + /* function to call when block of data has been transfered */ + void (*end_t_func) (struct ata_device *); + } internals; + + + /******* ATA Device Registers *********************************/ + struct + { + uint8_t command; + uint8_t cylinder_low; + uint8_t cylinder_high; + uint8_t device_control; + uint8_t device_head; + uint8_t error; + uint8_t features; + uint8_t sector_count; + uint8_t sector_number; + uint8_t status; + + uint16_t dataport_i; + } regs; + + /******** ata device output signals **************************/ + struct + { + int iordy; + int intrq; + int dmarq; + int pdiagi, pdiago; + int daspi, daspo; + } sigs; + + /******** simulator settings **********************************/ + struct + { + char *file; /* Filename (if type == FILE) */ + FILE *stream; /* stream where the simulated device connects to */ + int type; /* Simulate device using */ + /* NO_CONNECT: no device connected (dummy) */ + /* FILE : a file */ + /* LOCAL : a local stream, e.g./dev/hda1 */ + uint32_t size; /* size in bytes of the simulated device */ + uint32_t size_sect; /* size in sectors of the simulated device */ + int packet; /* device implements PACKET command set */ + + unsigned int heads; + unsigned int sectors; + + char *firmware; + unsigned int mwdma; + unsigned int pio; + } conf; +}; + +struct ata_devices +{ + struct ata_device device[2]; +}; + +/* all devices */ +void ata_devices_init (struct ata_devices *devices); +void ata_devices_hw_reset (struct ata_devices *devices, int reset_signal); +short ata_devices_read (struct ata_devices *devices, char adr); +void ata_devices_write (struct ata_devices *devices, char adr, short value); + +#endif /* ATADEVICE__H */
atadevice.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ps2kbd.h =================================================================== --- ps2kbd.h (nonexistent) +++ ps2kbd.h (revision 1765) @@ -0,0 +1,33 @@ +/* ps2kbd.h -- Very simple PS/2 keyboard simulation header file + + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef PS2KBD__H +#define PS2KBD__H + +/* Prototypes for external use */ +void reg_kbd_sec (); + +#endif /* PS2KBD__H */
ps2kbd.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: fb.h =================================================================== --- fb.h (nonexistent) +++ fb.h (revision 1765) @@ -0,0 +1,33 @@ +/* fb.h -- Definition of types and structures for simple frame buffer. + + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef FB__H +#define FB__H + +/* Function prototypes for external use. */ +extern void reg_fb_sec (); + +#endif /* FB__H */
fb.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: atacmd.h =================================================================== --- atacmd.h (nonexistent) +++ atacmd.h (revision 1765) @@ -0,0 +1,130 @@ +/* atacommon.h -- ATA Host code simulation. Common defines for ATA Host and + ATA Device + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* Definitions for the Opencores ATA Controller Core */ + +#ifndef ATACMD__H +#define ATACMD__H + +/* ---------------------------- */ +/* ----- ATA commands ----- */ +/* ---------------------------- */ +#define CFA_ERASE_SECTORS 0xC0 +#define CFA_REQUEST_EXTENDED_ERROR_CODE 0x03 +#define CFA_TRANSLATE_SECTOR 0x87 +#define CFA_WRITE_MULTIPLE_WITHOUT_ERASE 0xCD +#define CFA_WRITE_SECTORS_WITHOUT_ERASE 0x38 +#define CHECK_POWER_MODE 0xE5 +#define DEVICE_RESET 0x08 +#define DOWNLOAD_MICROCODE 0x92 +#define EXECUTE_DEVICE_DIAGNOSTICS 0x90 +#define FLUSH_CACHE 0xE7 +#define GET_MEDIA_STATUS 0xDA +#define IDENTIFY_DEVICE 0xEC +#define IDENTIFY_PACKET_DEVICE 0xA1 +#define IDLE 0xE3 +#define IDLE_IMMEDIATE 0xE1 +#define INITIALIZE_DEVICE_PARAMETERS 0x91 +#define MEDIA_EJECT 0xED +#define MEDIA_LOCK 0xDE +#define MEDIA_UNLOCK 0xDF +#define NOP 0x00 +#define PACKET 0xA0 +#define READ_BUFFER 0xE4 +#define READ_DMA 0xC8 +#define READ_DMA_QUEUED 0xC7 +#define READ_MULTIPLE 0xC4 +#define READ_NATIVE_MAX_ADDRESS 0xF8 +#define READ_SECTOR 0x20 +#define READ_SECTORS 0x20 +#define READ_VERIFY_SECTOR 0x40 +#define READ_VERIFY_SECTORS 0x40 +#define SECURITY_DISABLE_PASSWORD 0xF6 +#define SECURITY_ERASE_PREPARE 0xF3 +#define SECURITY_ERASE_UNIT 0xF4 +#define SECURITY_FREEZE_LOCK 0xF5 +#define SECURITY_SET_PASSWORD 0xF1 +#define SECURITY_UNLOCK 0xF2 +#define SEEK 0x70 +#define SERVICE 0xA2 +#define SET_FEATURES 0xEF +#define SET_MAX 0xF9 +#define SET_MULTIPLE_MODE 0xC6 +#define SLEEP 0xE6 +#define SMART 0xB0 +#define STANDBY 0xE2 +#define STANDBY_IMMEDIATE 0xE0 +#define WRITE_BUFFER 0xE8 +#define WRITE_DMA 0xCA +#define WRITE_DMA_QUEUED 0xCC +#define WRITE_MULTIPLE 0xC5 +#define WRITE_SECTOR 0x30 +#define WRITE_SECTORS 0x30 + + +/* SET_FEATURES has a number of sub-commands (in Features Register) */ +#define CFA_ENABLE_8BIT_PIO_TRANSFER_MODE 0x01 +#define ENABLE_WRITE_CACHE 0x02 +#define SET_TRANSFER_MODE_SECTOR_COUNT_REG 0x03 +#define ENABLE_ADVANCED_POWER_MANAGEMENT 0x05 +#define ENABLE_POWERUP_IN_STANDBY_FEATURE_SET 0x06 +#define POWERUP_IN_STANDBY_FEATURE_SET_SPINUP 0x07 +#define CFA_ENABLE_POWER_MODE1 0x0A +#define DISABLE_MEDIA_STATUS_NOTIFICATION 0x31 +#define DISABLE_READ_LOOKAHEAD 0x55 +#define ENABLE_RELEASE_INTERRUPT 0x5D +#define ENABLE_SERVICE_INTERRUPT 0x5E +#define DISABLE_REVERTING_TO_POWERON_DEFAULTS 0x66 +#define CFA_DISABLE_8BIT_PIO_TRANSFER_MODE 0x81 +#define DISABLE_WRITE_CACHE 0x82 +#define DISABLE_ADVANCED_POWER_MANAGEMENT 0x85 +#define DISABLE_POWERUP_IN_STANDBY_FEATURE_SET 0x86 +#define CFA_DISABLE_POWER_MODE1 0x8A +#define ENABLE_MEDIA_STATUS_NOTIFICATION 0x95 +#define ENABLE_READ_LOOKAHEAD_FEATURE 0xAA +#define ENABLE_REVERTING_TO_POWERON_DEFAULTS 0xCC +#define DISABLE_RELEASE_INTERRUPT 0xDD +#define DISABLE_SERVICE_INTERRUPT 0xDE + +/* SET_MAX has a number of sub-commands (in Features Register) */ +#define SET_MAX_ADDRESS 0x00 +#define SET_MAX_SET_PASSWORD 0x01 +#define SET_MAX_LOCK 0x02 +#define SET_MAX_UNLOCK 0x03 +#define SET_MAX_FREEZE_LOCK 0x04 + +/* SET_MAX has a number of sub-commands (in Features Register) */ +#define SMART_READ_DATA 0xD0 +#define SMART_ATTRIBITE_AUTOSAVE 0xD1 +#define SMART_SAVE_ATTRIBUTE_VALUES 0xD3 +#define SMART_EXECUTE_OFFLINE_IMMEDIATE 0xD4 +#define SMART_READ_LOG 0xD5 +#define SMART_WRITE_LOG 0xD6 +#define SMART_ENABLE_OPERATIONS 0xD8 +#define SMART_DISABLE_OPERATIONS 0xD9 +#define SMART_RETURN_STATUS 0xDA + +#endif /* ATACMD__H */ Index: dma.c =================================================================== --- dma.c (nonexistent) +++ dma.c (revision 1765) @@ -0,0 +1,669 @@ +/* dma.c -- Simulation of DMA + + Copyright (C) 2001 by Erez Volk, erez@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* This simulation of the DMA core is not meant to be full. It is written + only to allow simulating the Ethernet core. Of course, if anyone feels + like perfecting it, feel free... */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include + +/* Package includes */ +#include "dma.h" +#include "debug.h" +#include "fields.h" +#include "abstract.h" +#include "sched.h" +#include "pic.h" +#include "toplevel-support.h" +#include "sim-cmd.h" + +DEFAULT_DEBUG_CHANNEL (dma); + +/* We keep a copy of all our controllers because we have to export an interface + * to other peripherals eg. ethernet */ +static struct dma_controller *dmas = NULL; + +static unsigned long dma_read_ch_csr (struct dma_channel *channel); +static void dma_write_ch_csr (struct dma_channel *channel, + unsigned long value); +static void dma_load_descriptor (struct dma_channel *channel); +static void dma_init_transfer (struct dma_channel *channel); +static void dma_channel_terminate_transfer (struct dma_channel *channel, + int generate_interrupt); + +static void dma_channel_clock (void *dat); + +static void masked_increase (oraddr_t * value, unsigned long mask); + +#define CHANNEL_ND_I(ch) (TEST_FLAG(ch->regs.csr,DMA_CH_CSR,MODE) && TEST_FLAG(ch->regs.csr,DMA_CH_CSR,USE_ED) && ch->dma_nd_i) + + +/* Reset. Initializes all registers to default and places devices in memory address space. */ +static void +dma_reset (void *dat) +{ + struct dma_controller *dma = dat; + unsigned channel_number; + + memset (dma->ch, 0, sizeof (dma->ch)); + + dma->regs.csr = 0; + dma->regs.int_msk_a = 0; + dma->regs.int_msk_b = 0; + dma->regs.int_src_a = 0; + dma->regs.int_src_b = 0; + + for (channel_number = 0; channel_number < DMA_NUM_CHANNELS; + ++channel_number) + { + dma->ch[channel_number].controller = dma; + dma->ch[channel_number].channel_number = channel_number; + dma->ch[channel_number].channel_mask = 1LU << channel_number; + dma->ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = + 0xFFFFFFFC; + } +} + +/* Print register values on stdout */ +static void +dma_status (void *dat) +{ + unsigned j; + struct dma_controller *dma = dat; + + if (dma->baseaddr == 0) + return; + + PRINTF ("\nDMA controller at 0x%" PRIxADDR ":\n", dma->baseaddr); + PRINTF ("CSR : 0x%08lX\n", dma->regs.csr); + PRINTF ("INT_MSK_A : 0x%08lX\n", dma->regs.int_msk_a); + PRINTF ("INT_MSK_B : 0x%08lX\n", dma->regs.int_msk_b); + PRINTF ("INT_SRC_A : 0x%08lX\n", dma->regs.int_src_a); + PRINTF ("INT_SRC_B : 0x%08lX\n", dma->regs.int_src_b); + + for (j = 0; j < DMA_NUM_CHANNELS; ++j) + { + struct dma_channel *channel = &(dma->ch[j]); + if (!channel->referenced) + continue; + PRINTF ("CH%u_CSR : 0x%08lX\n", j, channel->regs.csr); + PRINTF ("CH%u_SZ : 0x%08lX\n", j, channel->regs.sz); + PRINTF ("CH%u_A0 : 0x%08lX\n", j, channel->regs.a0); + PRINTF ("CH%u_AM0 : 0x%08lX\n", j, channel->regs.am0); + PRINTF ("CH%u_A1 : 0x%08lX\n", j, channel->regs.a1); + PRINTF ("CH%u_AM1 : 0x%08lX\n", j, channel->regs.am1); + PRINTF ("CH%u_DESC : 0x%08lX\n", j, channel->regs.desc); + PRINTF ("CH%u_SWPTR : 0x%08lX\n", j, channel->regs.swptr); + } +} + + +/* Read a register */ +static uint32_t +dma_read32 (oraddr_t addr, void *dat) +{ + struct dma_controller *dma = dat; + uint32_t ret; + + if (addr < DMA_CH_BASE) + { + /* case of global (not per-channel) registers */ + switch (addr) + { + case DMA_CSR: + return dma->regs.csr; + case DMA_INT_MSK_A: + return dma->regs.int_msk_a; + case DMA_INT_MSK_B: + return dma->regs.int_msk_b; + case DMA_INT_SRC_A: + if (dma->regs.int_src_a) + clear_interrupt (dma->irq); + ret = dma->regs.int_src_a; + dma->regs.int_src_a = 0; + return ret; + case DMA_INT_SRC_B: + return dma->regs.int_src_b; + default: + fprintf (stderr, + "dma_read32( 0x%" PRIxADDR " ): Illegal register\n", + addr + dma->baseaddr); + return 0; + } + } + else + { + /* case of per-channel registers */ + unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; + addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; + switch (addr) + { + case DMA_CH_CSR: + return dma_read_ch_csr (&(dma->ch[chno])); + case DMA_CH_SZ: + return dma->ch[chno].regs.sz; + case DMA_CH_A0: + return dma->ch[chno].regs.a0; + case DMA_CH_AM0: + return dma->ch[chno].regs.am0; + case DMA_CH_A1: + return dma->ch[chno].regs.a1; + case DMA_CH_AM1: + return dma->ch[chno].regs.am1; + case DMA_CH_DESC: + return dma->ch[chno].regs.desc; + case DMA_CH_SWPTR: + return dma->ch[chno].regs.swptr; + } + } + return 0; +} + + +/* Handle read from a channel CSR */ +static unsigned long +dma_read_ch_csr (struct dma_channel *channel) +{ + unsigned long result = channel->regs.csr; + + /* before returning, clear all relevant bits */ + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, INT_CHUNK_DONE); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, INT_DONE); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, INT_ERR); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, ERR); + + return result; +} + + + +/* Write a register */ +static void +dma_write32 (oraddr_t addr, uint32_t value, void *dat) +{ + struct dma_controller *dma = dat; + + /* case of global (not per-channel) registers */ + if (addr < DMA_CH_BASE) + { + switch (addr) + { + case DMA_CSR: + if (TEST_FLAG (value, DMA_CSR, PAUSE)) + fprintf (stderr, "dma: PAUSE not implemented\n"); + break; + + case DMA_INT_MSK_A: + dma->regs.int_msk_a = value; + break; + case DMA_INT_MSK_B: + dma->regs.int_msk_b = value; + break; + case DMA_INT_SRC_A: + dma->regs.int_src_a = value; + break; + case DMA_INT_SRC_B: + dma->regs.int_src_b = value; + break; + default: + fprintf (stderr, + "dma_write32( 0x%" PRIxADDR " ): Illegal register\n", + addr + dma->baseaddr); + return; + } + } + else + { + /* case of per-channel registers */ + unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; + struct dma_channel *channel = &(dma->ch[chno]); + channel->referenced = 1; + addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; + switch (addr) + { + case DMA_CSR: + dma_write_ch_csr (&(dma->ch[chno]), value); + break; + case DMA_CH_SZ: + channel->regs.sz = value; + break; + case DMA_CH_A0: + channel->regs.a0 = value; + break; + case DMA_CH_AM0: + channel->regs.am0 = value; + break; + case DMA_CH_A1: + channel->regs.a1 = value; + break; + case DMA_CH_AM1: + channel->regs.am1 = value; + break; + case DMA_CH_DESC: + channel->regs.desc = value; + break; + case DMA_CH_SWPTR: + channel->regs.swptr = value; + break; + } + } +} + + +/* Write a channel CSR + * This ensures only the writable bits are modified. + */ +static void +dma_write_ch_csr (struct dma_channel *channel, unsigned long value) +{ + /* Check if we should *start* a transfer */ + if (!TEST_FLAG (channel->regs.csr, DMA_CH_CSR, CH_EN) && + TEST_FLAG (value, DMA_CH_CSR, CH_EN)) + SCHED_ADD (dma_channel_clock, channel, 1); + else if (!TEST_FLAG (value, DMA_CH_CSR, CH_EN)) + /* The CH_EN flag is clear, check if we have a transfer in progress and + * clear it */ + SCHED_FIND_REMOVE (dma_channel_clock, channel); + + /* Copy the writable bits to the channel CSR */ + channel->regs.csr &= ~DMA_CH_CSR_WRITE_MASK; + channel->regs.csr |= value & DMA_CH_CSR_WRITE_MASK; +} + + + +/* Clock tick for one channel on one DMA controller. + * This does the actual "DMA" operation. + * One chunk is transferred per clock. + */ +static void +dma_channel_clock (void *dat) +{ + struct dma_channel *channel = dat; + + /* Do we need to abort? */ + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, STOP)) + { + TRACE ("DMA: STOP requested\n"); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, CH_EN); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, BUSY); + SET_FLAG (channel->regs.csr, DMA_CH_CSR, ERR); + + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, INE_ERR) && + (channel->controller->regs.int_msk_a & channel->channel_mask)) + { + SET_FLAG (channel->regs.csr, DMA_CH_CSR, INT_ERR); + channel->controller->regs.int_src_a = channel->channel_mask; + report_interrupt (channel->controller->irq); + } + + return; + } + + /* In HW Handshake mode, only work when dma_req_i asserted */ + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, MODE) && !channel->dma_req_i) + { + /* Reschedule */ + SCHED_ADD (dma_channel_clock, dat, 1); + return; + } + + /* If this is the first cycle of the transfer, initialize our state */ + if (!TEST_FLAG (channel->regs.csr, DMA_CH_CSR, BUSY)) + { + TRACE ("DMA: Starting new transfer\n"); + + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, DONE); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, ERR); + SET_FLAG (channel->regs.csr, DMA_CH_CSR, BUSY); + + /* If using linked lists, copy the appropriate fields to our registers */ + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, USE_ED)) + dma_load_descriptor (channel); + else + channel->load_next_descriptor_when_done = 0; + + /* Set our internal status */ + dma_init_transfer (channel); + + /* Might need to skip descriptor */ + if (CHANNEL_ND_I (channel)) + { + TRACE + ("DMA: dma_nd_i asserted before dma_req_i, skipping descriptor\n"); + dma_channel_terminate_transfer (channel, 0); + return; + } + } + + /* Transfer one word */ + set_direct32 (channel->destination, eval_direct32 (channel->source, 0, 0), + 0, 0); + + /* Advance the source and destionation pointers */ + masked_increase (&(channel->source), channel->source_mask); + masked_increase (&(channel->destination), channel->destination_mask); + ++channel->words_transferred; + + /* Have we finished a whole chunk? */ + channel->dma_ack_o = + (channel->words_transferred % channel->chunk_size == 0); + + /* When done with a chunk, check for dma_nd_i */ + if (CHANNEL_ND_I (channel)) + { + TRACE ("DMA: dma_nd_i asserted\n"); + dma_channel_terminate_transfer (channel, 0); + return; + } + + /* Are we done? */ + if (channel->words_transferred >= channel->total_size) + { + dma_channel_terminate_transfer (channel, 1); + return; + } + + /* Reschedule to transfer the next chunk */ + SCHED_ADD (dma_channel_clock, dat, 1); +} + + +/* Copy relevant valued from linked list descriptor to channel registers */ +static void +dma_load_descriptor (struct dma_channel *channel) +{ + unsigned long desc_csr = + eval_direct32 (channel->regs.desc + DMA_DESC_CSR, 0, 0); + + channel->load_next_descriptor_when_done = + !TEST_FLAG (desc_csr, DMA_DESC_CSR, EOL); + + ASSIGN_FLAG (channel->regs.csr, DMA_CH_CSR, INC_SRC, + TEST_FLAG (desc_csr, DMA_DESC_CSR, INC_SRC)); + ASSIGN_FLAG (channel->regs.csr, DMA_CH_CSR, INC_DST, + TEST_FLAG (desc_csr, DMA_DESC_CSR, INC_DST)); + ASSIGN_FLAG (channel->regs.csr, DMA_CH_CSR, SRC_SEL, + TEST_FLAG (desc_csr, DMA_DESC_CSR, SRC_SEL)); + ASSIGN_FLAG (channel->regs.csr, DMA_CH_CSR, DST_SEL, + TEST_FLAG (desc_csr, DMA_DESC_CSR, DST_SEL)); + + SET_FIELD (channel->regs.sz, DMA_CH_SZ, TOT_SZ, + GET_FIELD (desc_csr, DMA_DESC_CSR, TOT_SZ)); + + channel->regs.a0 = eval_direct32 (channel->regs.desc + DMA_DESC_ADR0, 0, 0); + channel->regs.a1 = eval_direct32 (channel->regs.desc + DMA_DESC_ADR1, 0, 0); + + channel->current_descriptor = channel->regs.desc; + channel->regs.desc = + eval_direct32 (channel->regs.desc + DMA_DESC_NEXT, 0, 0); +} + + +/* Initialize internal parameters used to implement transfers */ +static void +dma_init_transfer (struct dma_channel *channel) +{ + channel->source = channel->regs.a0; + channel->destination = channel->regs.a1; + channel->source_mask = + TEST_FLAG (channel->regs.csr, DMA_CH_CSR, + INC_SRC) ? channel->regs.am0 : 0; + channel->destination_mask = + TEST_FLAG (channel->regs.csr, DMA_CH_CSR, + INC_DST) ? channel->regs.am1 : 0; + channel->total_size = GET_FIELD (channel->regs.sz, DMA_CH_SZ, TOT_SZ); + channel->chunk_size = GET_FIELD (channel->regs.sz, DMA_CH_SZ, CHK_SZ); + if (!channel->chunk_size || (channel->chunk_size > channel->total_size)) + channel->chunk_size = channel->total_size; + channel->words_transferred = 0; +} + + +/* Take care of transfer termination */ +static void +dma_channel_terminate_transfer (struct dma_channel *channel, + int generate_interrupt) +{ + TRACE ("DMA: Terminating transfer\n"); + + /* Might be working in a linked list */ + if (channel->load_next_descriptor_when_done) + { + dma_load_descriptor (channel); + dma_init_transfer (channel); + /* Reschedule */ + SCHED_ADD (dma_channel_clock, channel, 1); + return; + } + + /* Might be in auto-restart mode */ + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, ARS)) + { + dma_init_transfer (channel); + return; + } + + /* If needed, write amount of data transferred back to memory */ + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, SZ_WB) && + TEST_FLAG (channel->regs.csr, DMA_CH_CSR, USE_ED)) + { + /* TODO: What should we write back? Doc says "total number of remaining bytes" !? */ + unsigned long remaining_words = + channel->total_size - channel->words_transferred; + SET_FIELD (channel->regs.sz, DMA_DESC_CSR, TOT_SZ, remaining_words); + } + + /* Mark end of transfer */ + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, CH_EN); + SET_FLAG (channel->regs.csr, DMA_CH_CSR, DONE); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, ERR); + CLEAR_FLAG (channel->regs.csr, DMA_CH_CSR, BUSY); + + /* If needed, generate interrupt */ + if (generate_interrupt) + { + /* TODO: Which channel should we interrupt? */ + if (TEST_FLAG (channel->regs.csr, DMA_CH_CSR, INE_DONE) && + (channel->controller->regs.int_msk_a & channel->channel_mask)) + { + SET_FLAG (channel->regs.csr, DMA_CH_CSR, INT_DONE); + channel->controller->regs.int_src_a = channel->channel_mask; + report_interrupt (channel->controller->irq); + } + } +} + +/* Utility function: Add 4 to a value with a mask */ +static void +masked_increase (oraddr_t * value, unsigned long mask) +{ + *value = (*value & ~mask) | ((*value + 4) & mask); +} + +/*-------------------------------------------[ DMA<->Peripheral interface ]---*/ +/* + * Simulation of control signals + * To be used by simulations for other devices, e.g. ethernet + */ + +void +set_dma_req_i (struct dma_channel *channel) +{ + channel->dma_req_i = 1; +} + +void +clear_dma_req_i (struct dma_channel *channel) +{ + channel->dma_req_i = 0; +} + +void +set_dma_nd_i (struct dma_channel *channel) +{ + channel->dma_nd_i = 1; +} + +void +clear_dma_nd_i (struct dma_channel *channel) +{ + channel->dma_nd_i = 0; +} + +unsigned +check_dma_ack_o (struct dma_channel *channel) +{ + return channel->dma_ack_o; +} + +struct dma_channel * +find_dma_controller_ch (unsigned controller, unsigned channel) +{ + struct dma_controller *cur = dmas; + + while (cur && controller) + { + cur = cur->next; + controller--; + } + + if (!cur) + return NULL; + + return &(cur->ch[channel]); +} + + +/*----------------------------------------------------[ DMA configuration ]---*/ +static void +dma_baseaddr (union param_val val, void *dat) +{ + struct dma_controller *dma = dat; + dma->baseaddr = val.addr_val; +} + +static void +dma_irq (union param_val val, void *dat) +{ + struct dma_controller *dma = dat; + dma->irq = val.int_val; +} + +static void +dma_vapi_id (union param_val val, void *dat) +{ + struct dma_controller *dma = dat; + dma->vapi_id = val.int_val; +} + +static void +dma_enabled (union param_val val, void *dat) +{ + struct dma_controller *dma = dat; + dma->enabled = val.int_val; +} + + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new DMA configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +dma_sec_start () +{ + struct dma_controller *new = malloc (sizeof (struct dma_controller)); + + if (!new) + { + fprintf (stderr, "Peripheral DMA: Run out of memory\n"); + exit (-1); + } + + new->next = NULL; + new->enabled = 1; + new->baseaddr = 0; + new->irq = 0; + new->vapi_id = 0; + + return new; + +} /* dma_sec_start() */ + +static void +dma_sec_end (void *dat) +{ + struct dma_controller *dma = dat; + struct dma_controller *cur; + struct mem_ops ops; + + if (!dma->enabled) + { + free (dat); + return; + } + + memset (&ops, 0, sizeof (struct mem_ops)); + + ops.readfunc32 = dma_read32; + ops.writefunc32 = dma_write32; + ops.read_dat32 = dat; + ops.write_dat32 = dat; + + /* FIXME: Correct delay?? */ + ops.delayr = 2; + ops.delayw = 2; + + reg_mem_area (dma->baseaddr, DMA_ADDR_SPACE, 0, &ops); + reg_sim_reset (dma_reset, dat); + reg_sim_stat (dma_status, dat); + + if (dmas) + { + for (cur = dmas; cur->next; cur = cur->next); + cur->next = dma; + } + else + dmas = dma; +} + +void +reg_dma_sec (void) +{ + struct config_section *sec = + reg_config_sec ("dma", dma_sec_start, dma_sec_end); + + reg_config_param (sec, "enabled", paramt_int, dma_enabled); + reg_config_param (sec, "baseaddr", paramt_addr, dma_baseaddr); + reg_config_param (sec, "irq", paramt_int, dma_irq); + reg_config_param (sec, "vapi_id", paramt_addr, dma_vapi_id); +} Index: atahost.c =================================================================== --- atahost.c (nonexistent) +++ atahost.c (revision 1765) @@ -0,0 +1,753 @@ +/* atahost.c -- ATA Host code simulation + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include + +/* Package includes */ +#include "atahost.h" +#include "sim-config.h" +#include "debug.h" +#include "abstract.h" +#include "pic.h" +#include "toplevel-support.h" +#include "sim-cmd.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 + +DEFAULT_DEBUG_CHANNEL (ata); + +/* reset and initialize ATA host core(s) */ +static void +ata_reset (void *dat) +{ + struct 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); +} + +/* ========================================================================= */ + + +/* Assert interrupt */ +void +ata_int (void *dat) +{ + struct ata_host *ata = dat; + if (!(ata->regs.stat & ATA_IDEIS)) + { + ata->regs.stat |= ATA_IDEIS; + report_interrupt (ata->irq); + } +} + +/* ========================================================================= */ + + +/* + Read a register +*/ +static uint32_t +ata_read32 (oraddr_t addr, void *dat) +{ + struct 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: + TRACE ("Read control register: %" PRIx32 "\n", ata->regs.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) +{ + struct 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: + TRACE ("Writting control register: %" PRIx32 "\n", value); + 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: + if (!(value & ATA_IDEIS) && (ata->regs.stat & ATA_IDEIS)) + { + clear_interrupt (ata->irq); + ata->regs.stat &= ~ATA_IDEIS; + } + break; + + case ATA_PCTR: + TRACE ("PCTR: Toec = %d, t4 = %d, t2 = %d, t1 = %d\n", + value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, + value & 0xff); + ata->regs.pctr = value; + break; + + case ATA_PFTR0: + TRACE ("PFTR0: Toec = %d, t4 = %d, t2 = %d, t1 = %d\n", + value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, + value & 0xff); + ata->regs.pftr0 = value; + break; + + case ATA_PFTR1: + TRACE ("PFTR1: Toec = %d, t4 = %d, t2 = %d, t1 = %d\n", + value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, + value & 0xff); + 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) +{ + struct 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) +{ + struct ata_host *ata = dat; + ata->baseaddr = val.addr_val; +} + +static void +ata_irq (union param_val val, void *dat) +{ + struct ata_host *ata = dat; + ata->irq = val.int_val; +} + +static void +ata_dev_id (union param_val val, void *dat) +{ + struct 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; +} + + +/*---------------------------------------------------------------------------*/ +/*!Set the ATA revision + + This must be in the range 0-15, to fit in the relevant field. Anything + larger is truncated with a warning. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +ata_rev (union param_val val, void *dat) +{ + struct ata_host *ata = dat; + + if (val.int_val > 0xf) + { + fprintf (stderr, "Warning: ATA rev > 4 bits: truncated\n"); + } + + ata->rev = val.int_val & 0xf; +} + +static void +ata_pio_mode0_t1 (union param_val val, void *dat) +{ + struct 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) +{ + struct 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) +{ + struct 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) +{ + struct 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) +{ + struct 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) +{ + struct 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) +{ + struct 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) +{ + struct ata_host *ata = dat; + if (conf_dev <= 1) + ata->devices.device[conf_dev].conf.type = val.int_val; +} + + +/*---------------------------------------------------------------------------*/ +/*!Set the ATA file + + Free any previously allocated value. Only used if device type is 1. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +ata_file (union param_val val, void *dat) +{ + struct ata_host *ata = dat; + + if (conf_dev <= 1) + { + if (NULL != ata->devices.device[conf_dev].conf.file) + { + free (ata->devices.device[conf_dev].conf.file); + ata->devices.device[conf_dev].conf.file = NULL; + } + + if (!(ata->devices.device[conf_dev].conf.file = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral ATA: Run out of memory\n"); + exit (-1); + } + } +} /* ata_file() */ + + +static void +ata_size (union param_val val, void *dat) +{ + struct 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) +{ + struct 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) +{ + struct ata_host *ata = dat; + ata->enabled = val.int_val; +} + +static void +ata_heads (union param_val val, void *dat) +{ + struct 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) +{ + struct 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) +{ + struct 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); + } +} + + +/*---------------------------------------------------------------------------*/ +/*!Set the ATA multi-word DMA mode + + Must be -1, 0, 1 or 2. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +ata_mwdma (union param_val val, + void *dat) +{ + struct ata_host *ata = dat; + + if ((val.int_val >= -1) && (val.int_val <= 2)) + { + ata->devices.device[conf_dev].conf.mwdma = val.int_val; + } + else + { + fprintf (stderr, "Warning: invalid ATA multi-word DMA mode: ignored\n"); + } +} /* ata_mwdma() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the ATA programmed I/O mode + + Must be 0, 1, 2, 3 or 4. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +ata_pio (union param_val val, + void *dat) +{ + struct ata_host *ata = dat; + + if ((val.int_val >= 0) && (val.int_val <= 4)) + { + ata->devices.device[conf_dev].conf.pio = val.int_val; + } + else + { + fprintf (stderr, "Warning: invalid ATA programmed I/O mode: ignored\n"); + } +} /* ata_pio() */ + + +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; +} + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new ATA configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +ata_sec_start (void) +{ + struct ata_host *new = malloc (sizeof (struct ata_host)); + + if (!new) + { + fprintf (stderr, "Peripheral ATA: Run out of memory\n"); + exit (-1); + } + + memset (new, 0, sizeof (struct ata_host)); + + new->enabled = 1; + new->baseaddr = 0; + new->irq = 0; + new->dev_id = 1; + new->rev = 0; + + 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.type = 0; + new->devices.device[0].conf.file = strdup ("ata_file0"); + new->devices.device[0].conf.size = 0; + new->devices.device[0].conf.packet = 0; + 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.type = 0; + new->devices.device[1].conf.file = strdup ("ata_file1"); + new->devices.device[1].conf.size = 0; + new->devices.device[1].conf.packet = 0; + 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; + +} /* ata_sec_start() */ + + +static void +ata_sec_end (void *dat) +{ + struct ata_host *ata = dat; + struct mem_ops ops; + + if (!ata->enabled) + { + free (dat); + return; + } + + /* Connect ata_devices. */ + ata_devices_init (&ata->devices); + ata->devices.device[0].internals.host = ata; + ata->devices.device[1].internals.host = ata; + + 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 () +{ + 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_str, ata_firmware); + reg_config_param (sec, "mwdma", paramt_int, ata_mwdma); + reg_config_param (sec, "pio", paramt_int, ata_pio); +} Index: dma.h =================================================================== --- dma.h (nonexistent) +++ dma.h (revision 1765) @@ -0,0 +1,114 @@ +/* dma.h -- Definition of DMA<->peripheral interface + + Copyright (C) 2001 by Erez Volk, erez@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +#ifndef DMA__H +#define DMA__H + +/* Package includes */ +#include "dma-defs.h" +#include "sim-config.h" + +/* Implementation of DMA Channel Registers and State */ +struct dma_channel +{ + /* The controller we belong to */ + struct dma_controller *controller; + + /* Our channel number and bit mask */ + unsigned channel_number; + unsigned long channel_mask; + + /* Used for dump, to save dumping all 32 channels */ + unsigned referenced; + + /* Inner state of transfer etc. */ + unsigned load_next_descriptor_when_done; + unsigned long current_descriptor; + oraddr_t source, destination, source_mask, destination_mask; + unsigned long chunk_size, total_size, words_transferred; + + /* The interface registers */ + struct + { + unsigned long csr; + unsigned long sz; + unsigned long a0; + unsigned long am0; + unsigned long a1; + unsigned long am1; + unsigned long desc; + unsigned long swptr; + } regs; + + /* Some control signals */ + unsigned dma_req_i; + unsigned dma_ack_o; + unsigned dma_nd_i; +}; + + +/* Implementation of DMA Controller Registers and State */ +struct dma_controller +{ + /* Is peripheral enabled */ + int enabled; + + /* Base address in memory */ + oraddr_t baseaddr; + + /* Which interrupt number we generate */ + unsigned irq; + + /* VAPI id */ + int vapi_id; + + /* Controller Registers */ + struct + { + unsigned long csr; + unsigned long int_msk_a; + unsigned long int_msk_b; + unsigned long int_src_a; + unsigned long int_src_b; + } regs; + + /* Channels */ + struct dma_channel ch[DMA_NUM_CHANNELS]; + + struct dma_controller *next; +}; + +void set_dma_req_i (struct dma_channel *channel); +void clear_dma_req_i (struct dma_channel *channel); +void set_dma_nd_i (struct dma_channel *channel); +void clear_dma_nd_i (struct dma_channel *channel); +unsigned check_dma_ack_o (struct dma_channel *channel); +struct dma_channel *find_dma_controller_ch (unsigned controller, + unsigned channel); + +/* Prototype for external use */ +extern void reg_dma_sec (); + +#endif /* DMA__H */ Index: memory.c =================================================================== --- memory.c (nonexistent) +++ memory.c (revision 1765) @@ -0,0 +1,485 @@ +/* memory.c -- Generic memory model + + Copyright (C) 1999 Damjan Lampret, lampret@opencores.org + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include +#include + +/* Package includes */ +#include "arch.h" +#include "sim-config.h" +#include "abstract.h" +#include "mc.h" +#include "toplevel-support.h" + + +struct mem_config +{ + int ce; /* Which ce this memory is associated with */ + int mc; /* Which mc this memory is connected to */ + oraddr_t baseaddr; /* Start address of the memory */ + unsigned int size; /* Memory size */ + char *name; /* Memory type string */ + char *log; /* Memory log filename */ + int delayr; /* Read cycles */ + int delayw; /* Write cycles */ + + void *mem; /* malloced memory for this memory */ + + int pattern; /* A user specified memory initialization + * pattern */ + int random_seed; /* Initialize the memory with random values, + * starting with seed */ + enum + { + MT_UNKNOWN, + MT_PATTERN, + MT_RANDOM + } type; +}; + +static uint32_t +simmem_read32 (oraddr_t addr, void *dat) +{ + return *(uint32_t *) (dat + addr); +} + +static uint16_t +simmem_read16 (oraddr_t addr, void *dat) +{ +#ifdef WORDS_BIGENDIAN + return *(uint16_t *) (dat + addr); +#else + return *(uint16_t *) (dat + (addr ^ 2)); +#endif +} + +static uint8_t +simmem_read8 (oraddr_t addr, void *dat) +{ +#ifdef WORDS_BIGENDIAN + return *(uint8_t *) (dat + addr); +#else + return *(uint8_t *) (dat + ((addr & ~ADDR_C (3)) | (3 - (addr & 3)))); +#endif +} + +static void +simmem_write32 (oraddr_t addr, uint32_t value, void *dat) +{ + *(uint32_t *) (dat + addr) = value; +} + +static void +simmem_write16 (oraddr_t addr, uint16_t value, void *dat) +{ +#ifdef WORDS_BIGENDIAN + *(uint16_t *) (dat + addr) = value; +#else + *(uint16_t *) (dat + (addr ^ 2)) = value; +#endif +} + +static void +simmem_write8 (oraddr_t addr, uint8_t value, void *dat) +{ +#ifdef WORDS_BIGENDIAN + *(uint8_t *) (dat + addr) = value; +#else + *(uint8_t *) (dat + ((addr & ~ADDR_C (3)) | (3 - (addr & 3)))) = value; +#endif +} + +static uint32_t +simmem_read_zero32 (oraddr_t addr, void *dat) +{ + if (config.sim.verbose) + fprintf (stderr, + "WARNING: 32-bit memory read from non-read memory area 0x%" + PRIxADDR ".\n", addr); + return 0; +} + +static uint16_t +simmem_read_zero16 (oraddr_t addr, void *dat) +{ + if (config.sim.verbose) + fprintf (stderr, + "WARNING: 16-bit memory read from non-read memory area 0x%" + PRIxADDR ".\n", addr); + return 0; +} + +static uint8_t +simmem_read_zero8 (oraddr_t addr, void *dat) +{ + if (config.sim.verbose) + fprintf (stderr, + "WARNING: 8-bit memory read from non-read memory area 0x%" + PRIxADDR ".\n", addr); + return 0; +} + +static void +simmem_write_null32 (oraddr_t addr, uint32_t value, void *dat) +{ + if (config.sim.verbose) + fprintf (stderr, + "WARNING: 32-bit memory write to 0x%" PRIxADDR ", non-write " + "memory area (value 0x%08" PRIx32 ").\n", addr, value); +} + +static void +simmem_write_null16 (oraddr_t addr, uint16_t value, void *dat) +{ + if (config.sim.verbose) + fprintf (stderr, + "WARNING: 16-bit memory write to 0x%" PRIxADDR ", non-write " + "memory area (value 0x%08" PRIx32 ").\n", addr, value); +} + +static void +simmem_write_null8 (oraddr_t addr, uint8_t value, void *dat) +{ + if (config.sim.verbose) + fprintf (stderr, + "WARNING: 8-bit memory write to 0x%" PRIxADDR ", non-write " + "memory area (value 0x%08" PRIx32 ").\n", addr, value); +} + +static void +mem_reset (void *dat) +{ + struct mem_config *mem = dat; + int seed; + int i; + uint8_t *mem_area = mem->mem; + + /* Initialize memory */ + switch (mem->type) + { + case MT_RANDOM: + if (mem->random_seed == -1) + { + seed = time (NULL); + /* Print out the seed just in case we ever need to debug */ + PRINTF ("Seeding random generator with value %d\n", seed); + } + else + seed = mem->random_seed; + srandom (seed); + + for (i = 0; i < mem->size; i++, mem_area++) + *mem_area = random () & 0xFF; + break; + case MT_PATTERN: + for (i = 0; i < mem->size; i++, mem_area++) + *mem_area = mem->pattern; + break; + case MT_UNKNOWN: + break; + default: + fprintf (stderr, "Invalid memory configuration type.\n"); + exit (1); + } +} + +/*-------------------------------------------------[ Memory configuration ]---*/ +static void +memory_random_seed (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->random_seed = val.int_val; +} + +/*---------------------------------------------------------------------------*/ +/*!Set the memory pattern + + Value must be up to 8 bits. Larger values are truncated with a warning. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +memory_pattern (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + + if (val.int_val > 0xff) + { + fprintf (stderr, "Warning: memory pattern exceeds 8-bits: truncated\n"); + } + + mem->pattern = val.int_val & 0xff; + +} /* memory_pattern() */ + + +/*---------------------------------------------------------------------------*/ +/*!Set the memory type + + Value must be one of unknown, random, pattern or zero (case + insensitive). Unrecognized values are ignored with a warning. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +memory_type (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + + if (0 == strcasecmp (val.str_val, "unknown")) + { + mem->type = MT_UNKNOWN; + } + else if (0 == strcasecmp (val.str_val, "random")) + { + mem->type = MT_RANDOM; + } + else if (0 == strcasecmp (val.str_val, "pattern")) + { + mem->type = MT_PATTERN; + } + else if (0 == strcasecmp (val.str_val, "zero")) + { + mem->type = MT_PATTERN; + mem->pattern = 0; + } + else + { + fprintf (stderr, "Warning: memory type invalid. Ignored"); + } +} /* memory_type() */ + + +static void +memory_ce (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->ce = val.int_val; +} + +static void +memory_mc (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->mc = val.int_val; +} + +static void +memory_baseaddr (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->baseaddr = val.addr_val; +} + +static void +memory_size (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->size = val.int_val; +} + +/* FIXME: Check use */ +static void +memory_name (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + + if (NULL != mem->name) + { + free (mem->name); + } + + mem->name = strdup (val.str_val); +} + +static void +memory_log (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->log = strdup (val.str_val); +} + +static void +memory_delayr (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->delayr = val.int_val; +} + +static void +memory_delayw (union param_val val, void *dat) +{ + struct mem_config *mem = dat; + mem->delayw = val.int_val; +} + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new block of memory configuration + + ALL parameters are set explicitly to default values. + + @return The new memory configuration data structure */ +/*---------------------------------------------------------------------------*/ +static void * +memory_sec_start () +{ + struct mem_config *mem = malloc (sizeof (struct mem_config)); + + if (!mem) + { + fprintf (stderr, "Memory Peripheral: Run out of memory\n"); + exit (-1); + } + + mem->type = MT_UNKNOWN; + mem->random_seed = -1; + mem->pattern = 0; + mem->baseaddr = 0; + mem->size = 1024; + mem->name = strdup ("anonymous memory block"); + mem->ce = -1; + mem->mc = 0; + mem->delayr = 1; + mem->delayw = 1; + mem->log = NULL; + + return mem; + +} /* memory_sec_start() */ + + +static void +memory_sec_end (void *dat) +{ + struct mem_config *mem = dat; + struct dev_memarea *mema; + + struct mem_ops ops; + + if (!mem->size) + { + free (dat); + return; + } + + /* Round up to the next 32-bit boundry */ + if (mem->size & 3) + { + mem->size &= ~3; + mem->size += 4; + } + + if (!(mem->mem = malloc (mem->size))) + { + fprintf (stderr, + "Unable to allocate memory at %" PRIxADDR ", length %i\n", + mem->baseaddr, mem->size); + exit (-1); + } + + if (mem->delayr > 0) + { + ops.readfunc32 = simmem_read32; + ops.readfunc16 = simmem_read16; + ops.readfunc8 = simmem_read8; + } + else + { + ops.readfunc32 = simmem_read_zero32; + ops.readfunc16 = simmem_read_zero16; + ops.readfunc8 = simmem_read_zero8; + } + + if (mem->delayw > 0) + { + ops.writefunc32 = simmem_write32; + ops.writefunc16 = simmem_write16; + ops.writefunc8 = simmem_write8; + } + else + { + ops.writefunc32 = simmem_write_null32; + ops.writefunc16 = simmem_write_null16; + ops.writefunc8 = simmem_write_null8; + } + + ops.writeprog8 = simmem_write8; + ops.writeprog32 = simmem_write32; + ops.writeprog8_dat = mem->mem; + ops.writeprog32_dat = mem->mem; + + ops.read_dat32 = mem->mem; + ops.read_dat16 = mem->mem; + ops.read_dat8 = mem->mem; + + ops.write_dat32 = mem->mem; + ops.write_dat16 = mem->mem; + ops.write_dat8 = mem->mem; + + ops.delayr = mem->delayr; + ops.delayw = mem->delayw; + + ops.log = mem->log; + + mema = reg_mem_area (mem->baseaddr, mem->size, 0, &ops); + + /* Set valid */ + /* FIXME: Should this be done during reset? */ + set_mem_valid (mema, 1); + + if (mem->ce >= 0) + mc_reg_mem_area (mema, mem->ce, mem->mc); + + reg_sim_reset (mem_reset, dat); +} + +void +reg_memory_sec (void) +{ + struct config_section *sec = reg_config_sec ("memory", memory_sec_start, + memory_sec_end); + + reg_config_param (sec, "type", paramt_word, memory_type); + reg_config_param (sec, "random_seed", paramt_int, memory_random_seed); + reg_config_param (sec, "pattern", paramt_int, memory_pattern); + reg_config_param (sec, "baseaddr", paramt_addr, memory_baseaddr); + reg_config_param (sec, "size", paramt_int, memory_size); + reg_config_param (sec, "name", paramt_str, memory_name); + reg_config_param (sec, "ce", paramt_int, memory_ce); + reg_config_param (sec, "mc", paramt_int, memory_mc); + reg_config_param (sec, "delayr", paramt_int, memory_delayr); + reg_config_param (sec, "delayw", paramt_int, memory_delayw); + reg_config_param (sec, "log", paramt_str, memory_log); +} Index: atahost.h =================================================================== --- atahost.h (nonexistent) +++ atahost.h (revision 1765) @@ -0,0 +1,188 @@ +/* atahost.h -- ATA Host code simulation + + Copyright (C) 2002 Richard Herveille, rherveille@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* Definitions for the Opencores ATA Host Controller Core */ + + +#ifndef ATAHOST__H +#define ATAHOST__H + +#include "arch.h" +#include "atadevice.h" + +/* --- Register definitions --- */ + +/* ----- Core Registers */ +#define ATA_CTRL 0x00 /* Control register */ +#define ATA_STAT 0x04 /* Status register */ +#define ATA_PCTR 0x08 /* PIO command timing register */ +#define ATA_PFTR0 0x0c /* PIO Fast Timing register Device0 */ +#define ATA_PFTR1 0x10 /* PIO Fast Timing register Device1 */ +#define ATA_DTR0 0x14 /* DMA Timing register Device2 */ +#define ATA_DTR1 0x18 /* DMA Timing register Device1 */ +#define ATA_TXB 0x3c /* DMA Transmit buffer */ +#define ATA_RXB 0x3c /* DMA Receive buffer */ + + +/* ---------------------------- */ +/* ----- Bits definitions ----- */ +/* ---------------------------- */ + +/* ----- Core Control register */ + /* bits 31-16 are reserved */ +#define ATA_DMA_EN (0<<15) /* DMAen, DMA enable bit */ + /* bit 14 is reserved */ +#define ATA_DMA_WR (1<<14) /* DMA Write transaction */ +#define ATA_DMA_RD (0<<14) /* DMA Read transaction */ + /* bits 13-10 are reserved */ +#define ATA_BELEC1 (1<< 9) /* Big-Little endian conversion */ + /* enable bit for Device1 */ +#define ATA_BELEC0 (1<< 8) /* Big-Little endian conversion */ + /* enable bit for Device0 */ +#define ATA_IDE_EN (1<< 7) /* IDE core enable bit */ +#define ATA_FTE1 (1<< 6) /* Device1 Fast PIO Timing Enable bit */ +#define ATA_FTE0 (1<< 5) /* Device0 Fast PIO Timing Enable bit */ +#define ATA_PWPP (1<< 4) /* PIO Write Ping-Pong Enable bit */ +#define ATA_IORDY_FTE1 (1<< 3) /* Device1 Fast PIO Timing IORDY */ + /* enable bit */ +#define ATA_IORDY_FTE0 (1<< 2) /* Device0 Fast PIO Timing IORDY */ + /* enable bit */ +#define ATA_IORDY (1<< 1) /* PIO Command Timing IORDY enable bit */ +#define ATA_RST (1<< 0) /* ATA Reset bit */ + +/* ----- Core Status register */ +#define ATA_DEVID 0xf0000000 /* bits 31-28 Device-ID */ +#define ATA_REVNO 0x0f000000 /* bits 27-24 Revision number */ + /* bits 23-16 are reserved */ +#define ATA_DMA_TIP (1<<15) /* DMA Transfer in progress */ + /* bits 14-10 are reserved */ +#define ATA_DRBE (1<<10) /* DMA Receive buffer empty */ +#define ATA_DTBF (1<< 9) /* DMA Transmit buffer full */ +#define ATA_DMARQ (1<< 8) /* DMARQ Line status */ +#define ATA_PIO_TIP (1<< 7 /* PIO Transfer in progress */ +#define ATA_PWPPF (1<< 6) /* PIO write ping-pong full */ + /* bits 5-1 are reserved */ +#define ATA_IDEIS (1<< 0) /* IDE Interrupt status */ + + +/* ----- Core Timing registers */ +#define ATA_TEOC 24 /* End of cycle time DMA/PIO */ +#define ATA_T4 16 /* DIOW- data hold time PIO */ +#define ATA_T2 8 /* DIOR-/DIOW- pulse width PIO */ +#define ATA_TD 8 /* DIOR-/DIOW- pulse width DMA */ +#define ATA_T1 0 /* Address valid to DIOR-/DIOW- PIO */ +#define ATA_TM 0 /* CS[1:0]valid to DIOR-/DIOW- DMA */ + + +/* ----------------------------- */ +/* ----- Simulator defines ----- */ +/* ----------------------------- */ +#define ATA_ADDR_SPACE 0x80 + + +/* ---------------------------- */ +/* ----- Structs ----- */ +/* ---------------------------- */ +struct ata_host +{ + /* Is peripheral enabled? */ + int enabled; + + /* Base address in memory */ + oraddr_t baseaddr; + + /* Registered memory area */ + struct dev_memarea *mem; + + /* Which IRQ to generate */ + int irq; + + /* Which ocidec version is implemented */ + int dev_id; + + /* OCIDEC revision */ + int rev; + + /* Current selected device */ + int dev_sel; + + /* PIO T1 reset value */ + uint8_t pio_mode0_t1; + + /* PIO T2 reset value */ + uint8_t pio_mode0_t2; + + /* PIO T4 reset value */ + uint8_t pio_mode0_t4; + + /* PIO Teoc reset value */ + uint8_t pio_mode0_teoc; + + /* DMA Tm reset value */ + uint8_t dma_mode0_tm; + + /* DMA Td reset value */ + uint8_t dma_mode0_td; + + /* DMA Teoc reset value */ + uint8_t dma_mode0_teoc; + + /* ata host registers */ + struct + { + uint32_t ctrl; + uint32_t stat; + uint32_t pctr; + uint32_t pftr0; + uint32_t pftr1; + uint32_t dtr0; + uint32_t dtr1; + uint32_t txb; + uint32_t rxb; + } regs; + + /* connected ATA devices (slaves) */ + struct ata_devices devices; +}; + +/* ---------------------------- */ +/* ----- Prototypes ----- */ +/* ---------------------------- */ +void ata_int (void *dat); + + +/* ---------------------------- */ +/* ----- Macros ----- */ +/* ---------------------------- */ +#define is_ata_hostadr(adr) (!(adr & 0x40)) + +// FIXME +#define ata_pio_delay(pioreg) ( (((pioreg >> ATA_T1) & 0xff) +1) + (((pioreg >> ATA_T2) & 0xff) +1) + (((pioreg >> ATA_T4) & 0xff) +1) +1 ) +#define ata_dma_delay(dmareg) ( (((dmareg >> ATA_TD) & 0xff) +1) + (((pioreg >> ATA_TM) & 0xff) +1) +1 ) + +/* Prototypes for external use */ +void reg_ata_sec (); + +#endif /* ATAHOST__H */
atahost.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: fields.h =================================================================== --- fields.h (nonexistent) +++ fields.h (revision 1765) @@ -0,0 +1,64 @@ +/* fields.h -- Some macros to help with bit field definitions + + Copyright (C) 2001 by Erez Volk, erez@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef FIELDS__H +#define FIELDS__H + + +/* Macros to get/set a field in a register + * Example: + * unsigned long done, priority, channel_csr; + * + * priority = GET_FIELD( channel_csr, DMA_CH_CSR, PRIORITY ); + * SET_FIELD( channel_csr, DMA_CH_CSR, PRIORITY, priority ); + * + * done = TEST_FLAG( channel_csr, DMA_CH_CSR, DONE ); + * SET_FLAG( channel_csr, DMA_CH_CSR, DONE ); + * CLEAR_FLAG( channel_csr, DMA_CH_CSR, DONE ); + * ASSIGN_FLAG( channel_csr, DMA_CH_CSR, done ); + * + * For each field, we then define e.g. + * #define DMA_CH_CSR_PRIORITY_OFFSET 13 + * #define DMA_CH_CSR_PRIORITY_WIDTH 3 // not needed for flags, which always have width = 1 + */ + +#define FLAG_SHIFT(reg_name,flag_name) (reg_name##_##flag_name##_OFFSET) +#define FLAG_MASK(reg_name,flag_name) (1LU << reg_name##_##flag_name##_OFFSET) + +#define TEST_FLAG(reg_value,reg_name,flag_name) (((reg_value ) >> reg_name##_##flag_name##_OFFSET) & 1LU) +#define SET_FLAG(reg_value,reg_name,flag_name) { (reg_value) |= 1LU << reg_name##_##flag_name##_OFFSET; } +#define CLEAR_FLAG(reg_value,reg_name,flag_name) { (reg_value) &= ~(1LU << reg_name##_##flag_name##_OFFSET); } +#define ASSIGN_FLAG(reg_value,reg_name,flag_name,flag_value) { \ + (reg_value) = flag_value ? ((reg_value) | (1LU << reg_name##_##flag_name##_OFFSET)) : ((reg_value) & ~(1LU << reg_name##_##flag_name##_OFFSET)); } + +#define FIELD_SHIFT(reg_name,field_name) (reg_name##_##field_name##_OFFSET) +#define FIELD_MASK(reg_name,field_name) ((~(~0LU << reg_name##_##field_name##_WIDTH)) << reg_name##_##field_name##_OFFSET) + +#define GET_FIELD(reg_value,reg_name,field_name) (((reg_value) >> reg_name##_##field_name##_OFFSET) & (~(~0LU << reg_name##_##field_name##_WIDTH))) +#define SET_FIELD(reg_value,reg_name,field_name,field_value) { \ + (reg_value) = ((reg_value) & ~((~(~0LU << reg_name##_##field_name##_WIDTH)) << reg_name##_##field_name##_OFFSET)) | ((field_value) << reg_name##_##field_name##_OFFSET); } + +#endif /* FIELDS__H */ Index: vga.c =================================================================== --- vga.c (nonexistent) +++ vga.c (revision 1765) @@ -0,0 +1,461 @@ +/* vga.c -- Definition of types and structures for VGA/LCD + + Copyright (C) 2001 Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include +#include + +/* Package includes */ +#include "arch.h" +#include "sim-config.h" +#include "abstract.h" +#include "sched.h" +#include "toplevel-support.h" + + +#define VGA_CTRL 0x00 /* Control Register */ +#define VGA_STAT 0x04 /* Status Register */ +#define VGA_HTIM 0x08 /* Horizontal Timing Register */ +#define VGA_VTIM 0x0c /* Vertical Timing Register */ +#define VGA_HVLEN 0x10 /* Horizontal and Vertical Length Register */ +#define VGA_VBARA 0x14 /* Video Memory Base Address Register A */ +#define VGA_VBARB 0x18 /* Video Memory Base Address Register B */ +#define VGA_CLUTA 0x800 +#define VGA_CLUTB 0xc00 +#define VGA_MASK 0xfff +#define VGA_ADDR_SPACE 1024 + + +/* List of implemented registers; all other are ignored. */ + +/* Control Register */ +#define VGA_CTRL_VEN 0x00000001 /* Video Enable */ +#define VGA_CTRL_CD 0x00000300 /* Color Depth */ +#define VGA_CTRL_PC 0x00000400 /* Pseudo Color */ + +/* Status Register */ +/* Horiz. Timing Register */ +/* Vert. Timing Register */ +/* Horiz. and Vert. Length Register */ + +/* When this counter reaches config.vgas[].refresh_rate, a screenshot is taken and outputted */ +struct vga_state +{ + int enabled; + int pics; + unsigned long ctrl, stat, htim, vtim; + int vbindex; + unsigned long vbar[2]; + unsigned hlen, vlen; + int pindex; + unsigned long palette[2][256]; + oraddr_t baseaddr; + int refresh_rate; + int irq; + char *filename; +}; + + +/* Write a register */ +void +vga_write32 (oraddr_t addr, uint32_t value, void *dat) +{ + struct vga_state *vga = dat; + + switch (addr) + { + case VGA_CTRL: + vga->ctrl = value; + break; + case VGA_STAT: + vga->stat = value; + break; + case VGA_HTIM: + vga->htim = value; + break; + case VGA_VTIM: + vga->vtim = value; + break; + case VGA_HVLEN: + vga->hlen = (value >> 16) + 2; + vga->hlen = (value & 0xffff) + 2; + break; + case VGA_VBARA: + vga->vbar[0] = value; + break; + case VGA_VBARB: + vga->vbar[1] = value; + break; + default: + if (addr >= VGA_CLUTA && addr < VGA_CLUTB) + { + vga->palette[0][addr - VGA_CLUTA] = value & 0x00ffffff; + } + else if (addr >= VGA_CLUTB) + { + vga->palette[1][addr - VGA_CLUTB] = value & 0x00ffffff; + } + else + { + fprintf (stderr, + "vga_write32( 0x%" PRIxADDR ", 0x%08" PRIx32 + " ): Out of range\n", addr + vga->baseaddr, value); + return; + } + break; + } +} + +/* Read a register */ +uint32_t +vga_read32 (oraddr_t addr, void *dat) +{ + struct vga_state *vga = dat; + + switch (addr) + { + case VGA_CTRL: + return vga->ctrl; + case VGA_STAT: + return vga->stat; + case VGA_HTIM: + return vga->htim; + case VGA_VTIM: + return vga->vtim; + case VGA_HVLEN: + return ((vga->hlen - 2) << 16) | (vga->vlen - 2); + case VGA_VBARA: + return vga->vbar[0]; + case VGA_VBARB: + return vga->vbar[1]; + default: + if (addr >= VGA_CLUTA && addr < VGA_CLUTB) + { + return vga->palette[0][addr - VGA_CLUTA]; + } + else if (addr >= VGA_CLUTB) + { + return vga->palette[1][addr - VGA_CLUTB]; + } + else + { + fprintf (stderr, "vga_read32( 0x%" PRIxADDR " ): Out of range\n", + addr); + return 0; + } + break; + } + return 0; +} + +/* This code will only work on little endian machines */ +#ifdef __BIG_ENDIAN__ +#warning Image dump not supported on big endian machines + +static int +vga_dump_image (char *filename, struct vga_start *vga) +{ + return 1; +} + +#else + +typedef struct +{ + unsigned short int type; /* Magic identifier */ + unsigned int size; /* File size in bytes */ + unsigned short int reserved1, reserved2; + unsigned int offset; /* Offset to image data, bytes */ +} BMP_HEADER; + +typedef struct +{ + unsigned int size; /* Header size in bytes */ + int width, height; /* Width and height of image */ + unsigned short int planes; /* Number of colour planes */ + unsigned short int bits; /* Bits per pixel */ + unsigned int compression; /* Compression type */ + unsigned int imagesize; /* Image size in bytes */ + int xresolution, yresolution; /* Pixels per meter */ + unsigned int ncolours; /* Number of colours */ + unsigned int importantcolours; /* Important colours */ +} INFOHEADER; + + +/* Dumps a bmp file, based on current image */ +static int +vga_dump_image (char *filename, struct vga_state *vga) +{ + int sx = vga->hlen; + int sy = vga->vlen; + int i, x = 0, y = 0; + int pc = vga->ctrl & VGA_CTRL_PC; + int rbpp = vga->ctrl & VGA_CTRL_CD; + int bpp = rbpp >> 8; + + BMP_HEADER bh; + INFOHEADER ih; + FILE *fo; + + if (!sx || !sy) + return 1; + + /* 16bpp and 32 bpp will be converted to 24bpp */ + if (bpp == 1 || bpp == 3) + bpp = 2; + + bh.type = 19778; /* BM */ + bh.size = + sizeof (BMP_HEADER) + sizeof (INFOHEADER) + sx * sy * (bpp * 4 + 4) + + (pc ? 1024 : 0); + bh.reserved1 = bh.reserved2 = 0; + bh.offset = sizeof (BMP_HEADER) + sizeof (INFOHEADER) + (pc ? 1024 : 0); + + ih.size = sizeof (INFOHEADER); + ih.width = sx; + ih.height = sy; + ih.planes = 1; + ih.bits = bpp * 4 + 4; + ih.compression = 0; + ih.imagesize = x * y * (bpp * 4 + 4); + ih.xresolution = ih.yresolution = 0; + ih.ncolours = 0; /* should be generated */ + ih.importantcolours = 0; /* all are important */ + + fo = fopen (filename, "wb+"); + if (!fwrite (&bh, sizeof (BMP_HEADER), 1, fo)) + return 1; + if (!fwrite (&ih, sizeof (INFOHEADER), 1, fo)) + return 1; + + if (pc) + { /* Write palette? */ + for (i = 0; i < 256; i++) + { + unsigned long val, d; + d = vga->palette[vga->pindex][i]; + val = (d >> 0) & 0xff; /* Blue */ + val |= (d >> 8) & 0xff; /* Green */ + val |= (d >> 16) & 0xff; /* Red */ + if (!fwrite (&val, sizeof (val), 1, fo)) + return 1; + } + } + + /* Data is stored upside down */ + for (y = sy - 1; y >= 0; y--) + { + int align = 4 - ((bpp + 1) * sx) % 4; + int zero = 0; + for (x = 0; x < sx; x++) + { + unsigned long pixel = + eval_direct32 (vga->vbar[vga->vbindex] + (y * sx + x) * (bpp + 1), + 0, 0); + if (!fwrite (&pixel, sizeof (pixel), 1, fo)) + return 1; + } + if (!fwrite (&zero, align, 1, fo)) + return 1; + } + + fclose (fo); + return 0; +} +#endif /* !__BIG_ENDIAN__ */ + +void +vga_job (void *dat) +{ + struct vga_state *vga = dat; + /* dump the image? */ + char temp[STR_SIZE]; + sprintf (temp, "%s%04i.bmp", vga->filename, vga->pics++); + vga_dump_image (temp, vga); + + SCHED_ADD (vga_job, dat, vga->refresh_rate); +} + +/* Reset all VGAs */ +void +vga_reset (void *dat) +{ + struct vga_state *vga = dat; + + int i; + + /* Init palette */ + for (i = 0; i < 256; i++) + vga->palette[0][i] = vga->palette[1][i] = 0; + + vga->ctrl = vga->stat = vga->htim = vga->vtim = 0; + vga->hlen = vga->vlen = 0; + vga->vbar[0] = vga->vbar[1] = 0; + + /* Init screen dumping machine */ + vga->pics = 0; + + vga->pindex = 0; + vga->vbindex = 0; + + SCHED_ADD (vga_job, dat, vga->refresh_rate); +} + +/*----------------------------------------------------[ VGA Configuration ]---*/ +static void +vga_enabled (union param_val val, void *dat) +{ + struct vga_state *vga = dat; + vga->enabled = val.int_val; +} + +static void +vga_baseaddr (union param_val val, void *dat) +{ + struct vga_state *vga = dat; + vga->baseaddr = val.addr_val; +} + +static void +vga_irq (union param_val val, void *dat) +{ + struct vga_state *vga = dat; + vga->irq = val.int_val; +} + +static void +vga_refresh_rate (union param_val val, void *dat) +{ + struct vga_state *vga = dat; + vga->refresh_rate = val.int_val; +} + +/*---------------------------------------------------------------------------*/ +/*!Set the VGA output file + + Free any previously allocated value. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +vga_filename (union param_val val, + void *dat) +{ + struct vga_state *vga = dat; + + if (NULL != vga->filename) + { + free (vga->filename); + vga->filename = NULL; + } + + if (NULL == (vga->filename = strdup (val.str_val))) + { + fprintf (stderr, "ERROR: Out of memory\n"); + exit (-1); + } + +} /* vga_filename() */ + + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new VGA configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +vga_sec_start () +{ + struct vga_state *new = malloc (sizeof (struct vga_state)); + + if (!new) + { + fprintf (stderr, "Peripheral VGA: Run out of memory\n"); + exit (-1); + } + + new->enabled = 1; + new->baseaddr = 0; + new->irq = 0; + new->refresh_rate = 1000000000000ULL / 50ULL / config.sim.clkcycle_ps; + new->filename = strdup ("vga_out"); + + return new; + +} /* vga_sec_start() */ + + +static void +vga_sec_end (void *dat) +{ + struct vga_state *vga = dat; + struct mem_ops ops; + if (!vga->enabled) + { + free (vga->filename); + free (vga); + return; + } + + memset (&ops, 0, sizeof (struct mem_ops)); + ops.readfunc32 = vga_read32; + ops.writefunc32 = vga_write32; + ops.write_dat32 = dat; + ops.read_dat32 = dat; + /* FIXME: Correct delay? */ + ops.delayr = 2; + ops.delayw = 2; + reg_mem_area (vga->baseaddr, VGA_ADDR_SPACE, 0, &ops); + reg_sim_reset (vga_reset, dat); +} + + +/*---------------------------------------------------------------------------*/ +/*!Create a new VGA configuration + + ALL parameters are set explicitly to default values. Alternative naming for + file parameter supported. */ +/*---------------------------------------------------------------------------*/ +void +reg_vga_sec () +{ + struct config_section *sec = + reg_config_sec ("vga", vga_sec_start, vga_sec_end); + + reg_config_param (sec, "baseaddr", paramt_addr, vga_baseaddr); + reg_config_param (sec, "enabled", paramt_int, vga_enabled); + reg_config_param (sec, "irq", paramt_int, vga_irq); + reg_config_param (sec, "refresh_rate", paramt_int, vga_refresh_rate); + reg_config_param (sec, "txfile", paramt_str, vga_filename); + reg_config_param (sec, "filename", paramt_str, vga_filename); + +} /* reg_vga_sec() */ +
vga.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: memory.h =================================================================== --- memory.h (nonexistent) +++ memory.h (revision 1765) @@ -0,0 +1,31 @@ +/* memory.h -- Generic memory model header + + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef MEMORY__H +#define MEMORY__H + +extern void reg_memory_sec (); + +#endif /* MEMORY__H */ Index: 16450.c =================================================================== --- 16450.c (nonexistent) +++ 16450.c (revision 1765) @@ -0,0 +1,1425 @@ +/* 16450.c -- Simulation of 8250/16450 serial UART + + Copyright (C) 1999 Damjan Lampret, lampret@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* This is functional simulation of 8250/16450/16550 UARTs. Since we RX/TX + data via file streams, we can't simulate modem control lines coming from + the DCE and similar details of communication with the DCE. + + This simulated UART device is intended for basic UART device driver + verification. From device driver perspective this device looks like a + regular UART but never reports any modem control lines changes (the + only DCE responses are incoming characters from the file stream). */ + + +/* Autoconf and/or portability configuration */ +#include "config.h" +#include "port.h" + +/* System includes */ +#include + +/* Package includes */ +#include "sim-config.h" +#include "debug.h" +#include "arch.h" +#include "pic.h" +#include "sched.h" +#include "vapi.h" +#include "channel.h" +#include "abstract.h" +#include "toplevel-support.h" +#include "sim-cmd.h" + + +DEFAULT_DEBUG_CHANNEL (uart); + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +/* Definitions */ +#define UART_ADDR_SPACE 8 /*!< UART addr space size in bytes */ +#define UART_MAX_FIFO_LEN 16 /*!< rx FIFO for uart 16550 */ +#define MAX_SKEW 1 /*!< max. clock skew in subclocks */ +#define UART_VAPI_BUF_LEN 128 /*!< Size of VAPI command buffer */ +#define UART_CLOCK_DIVIDER 16 /*!< UART clock divider */ +#define UART_FGETC_SLOWDOWN 100 /*!< fgetc() slowdown factor */ + +/* + * Addresses of visible registers + * + */ +#define UART_RXBUF 0 /* R: Rx buffer, DLAB=0 */ +#define UART_TXBUF 0 /* W: Tx buffer, DLAB=0 */ +#define UART_DLL 0 /* R/W: Divisor Latch Low, DLAB=1 */ +#define UART_DLH 1 /* R/W: Divisor Latch High, DLAB=1 */ +#define UART_IER 1 /* R/W: Interrupt Enable Register */ +#define UART_IIR 2 /* R: Interrupt ID Register */ +#define UART_FCR 2 /* W: FIFO Control Register */ +#define UART_LCR 3 /* R/W: Line Control Register */ +#define UART_MCR 4 /* W: Modem Control Register */ +#define UART_LSR 5 /* R: Line Status Register */ +#define UART_MSR 6 /* R: Modem Status Register */ +#define UART_SCR 7 /* R/W: Scratch Register */ + +/* + * R/W masks for valid bits in 8250/16450 (mask out 16550 and later bits) + * + */ +#define UART_VALID_LCR 0xff +#define UART_VALID_LSR 0xff +#define UART_VALID_IIR 0x0f +#define UART_VALID_FCR 0xc0 +#define UART_VALID_IER 0x0f +#define UART_VALID_MCR 0x1f +#define UART_VALID_MSR 0xff + +/* + * Bit definitions for the Line Control Register + * + */ +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ +#define UART_LCR_SBC 0x40 /* Set break control */ +#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ +#define UART_LCR_EPAR 0x10 /* Even parity select */ +#define UART_LCR_PARITY 0x08 /* Parity Enable */ +#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */ +#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ +#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ +#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ +#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ +#define UART_LCR_RESET 0x03 +/* + * Bit definitions for the Line Status Register + */ +#define UART_LSR_RXERR 0x80 /* Error in rx fifo */ +#define UART_LSR_TXSERE 0x40 /* Transmitter serial register empty */ +#define UART_LSR_TXBUFE 0x20 /* Transmitter buffer register empty */ +#define UART_LSR_BREAK 0x10 /* Break interrupt indicator */ +#define UART_LSR_FRAME 0x08 /* Frame error indicator */ +#define UART_LSR_PARITY 0x04 /* Parity error indicator */ +#define UART_LSR_OVRRUN 0x02 /* Overrun error indicator */ +#define UART_LSR_RDRDY 0x01 /* Receiver data ready */ + +/* + * Bit definitions for the Interrupt Identification Register + */ +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt (Low priority) */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt (High p.) */ +#define UART_IIR_CTI 0x0c /* Character timeout */ + +/* + * Bit Definitions for the FIFO Control Register + */ +#define UART_FCR_FIE 0x01 /* FIFO enable */ +#define UART_FCR_RRXFI 0x02 /* Reset rx FIFO */ +#define UART_FCR_RTXFI 0x04 /* Reset tx FIFO */ +#define UART_FIFO_TRIGGER(x) /* Trigger values for indexes 0..3 */\ + ((x) == 0 ? 1\ + :(x) == 1 ? 4\ + :(x) == 2 ? 8\ + :(x) == 3 ? 14 : 0) + +/* + * Bit definitions for the Interrupt Enable Register + */ +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ + +/* + * Bit definitions for the Modem Control Register + */ +#define UART_MCR_LOOP 0x10 /* Enable loopback mode */ +#define UART_MCR_AUX2 0x08 /* Auxilary 2 */ +#define UART_MCR_AUX1 0x04 /* Auxilary 1 */ +#define UART_MCR_RTS 0x02 /* Force RTS */ +#define UART_MCR_DTR 0x01 /* Force DTR */ + +/* + * Bit definitions for the Modem Status Register + */ +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ +#define UART_MSR_RI 0x40 /* Ring Indicator */ +#define UART_MSR_DSR 0x20 /* Data Set Ready */ +#define UART_MSR_CTS 0x10 /* Clear to Send */ +#define UART_MSR_DDCD 0x08 /* Delta DCD */ +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ +#define UART_MSR_DDSR 0x02 /* Delta DSR */ +#define UART_MSR_DCTS 0x01 /* Delta CTS */ + +/* + * Various definitions + */ +#define UART_BREAK_COUNT 1 /* # of chars to count when doing break */ +#define UART_CHAR_TIMEOUT 4 /* # of chars to count when doing timeout int */ + + +/* Registers */ + +struct dev_16450 +{ + struct + { + uint8_t txbuf[UART_MAX_FIFO_LEN]; + uint16_t rxbuf[UART_MAX_FIFO_LEN]; /* Upper 8-bits is the LCR modifier */ + uint8_t dll; + uint8_t dlh; + uint8_t ier; + uint8_t iir; + uint8_t fcr; + uint8_t lcr; + uint8_t mcr; + uint8_t lsr; + uint8_t msr; + uint8_t scr; + } regs; /* Visible registers */ + struct + { + uint8_t txser; /* Character just sending */ + uint16_t rxser; /* Character just receiving */ + uint8_t loopback; + } iregs; /* Internal registers */ + struct + { + int txbuf_head; + int txbuf_tail; + int rxbuf_head; + int rxbuf_tail; + unsigned int txbuf_full; + unsigned int rxbuf_full; + int receiveing; /* Receiving a char */ + int recv_break; /* Receiving a break */ + int ints; /* Which interrupts are pending */ + } istat; /* Internal status */ + + /* Clocks per char */ + unsigned long char_clks; + + /* VAPI internal registers */ + struct + { + unsigned long char_clks; + uint8_t dll; + uint8_t dlh; + uint8_t lcr; + int skew; + } vapi; + + /* Required by VAPI - circular buffer to store incoming chars, since we + cannothandle them so fast - we are serial. */ + unsigned long vapi_buf[UART_VAPI_BUF_LEN]; /* Buffer */ + int vapi_buf_head_ptr; /* Where we write to */ + int vapi_buf_tail_ptr; /* Where we read from */ + + /* Length of FIFO, 16 for 16550, 1 for 16450 */ + int fifo_len; + + struct channel *channel; + + /* Configuration */ + int enabled; + int jitter; + oraddr_t baseaddr; + int irq; + unsigned long vapi_id; + int uart16550; + char *channel_str; +}; + +/* Forward declarations of static functions */ +static void uart_recv_break (void *dat); +static void uart_recv_char (void *dat); +static void uart_check_char (void *dat); +static void uart_sched_recv_check (struct dev_16450 *uart); +static void uart_vapi_cmd (void *dat); +static void uart_clear_int (struct dev_16450 *uart, int intr); +static void uart_tx_send (void *dat); + + +/* Number of clock cycles (one clock cycle is when UART_CLOCK_DIVIDER simulator + * cycles have elapsed) before a single character is transmitted or received. */ +static unsigned long +char_clks (int dll, int dlh, int lcr) +{ + unsigned int bauds_per_char = 2; + unsigned long char_clks = ((dlh << 8) + dll); + + if (lcr & UART_LCR_PARITY) + bauds_per_char += 2; + + /* stop bits 1 or two */ + if (lcr & UART_LCR_STOP) + bauds_per_char += 4; + else if ((lcr & 0x3) != 0) + bauds_per_char += 2; + else + bauds_per_char += 3; + + bauds_per_char += 10 + ((lcr & 0x3) << 1); + + return (char_clks * bauds_per_char) >> 1; +} + +/*---------------------------------------------------[ Interrupt handling ]---*/ +/* Signals the specified interrupt. If a higher priority interrupt is already + * pending, do nothing */ +static void +uart_int_msi (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.ints |= 1 << UART_IIR_MSI; + + if (!(uart->regs.ier & UART_IER_MSI)) + return; + + if ((uart->regs.iir & UART_IIR_NO_INT) || (uart->regs.iir == UART_IIR_MSI)) + { + TRACE ("Raiseing modem status interrupt\n"); + + uart->regs.iir = UART_IIR_MSI; + report_interrupt (uart->irq); + } +} + +static void +uart_int_thri (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.ints |= 1 << UART_IIR_THRI; + + if (!(uart->regs.ier & UART_IER_THRI)) + return; + + if ((uart->regs.iir & UART_IIR_NO_INT) || (uart->regs.iir == UART_IIR_MSI) + || (uart->regs.iir == UART_IIR_THRI)) + { + TRACE ("Raiseing transmitter holding register interrupt\n"); + + uart->regs.iir = UART_IIR_THRI; + report_interrupt (uart->irq); + } +} + +static void +uart_int_cti (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.ints |= 1 << UART_IIR_CTI; + + if (!(uart->regs.ier & UART_IER_RDI)) + return; + + if ((uart->regs.iir != UART_IIR_RLSI) && (uart->regs.iir != UART_IIR_RDI)) + { + TRACE ("Raiseing character timeout interrupt\n"); + + uart->regs.iir = UART_IIR_CTI; + report_interrupt (uart->irq); + } +} + +static void +uart_int_rdi (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.ints |= 1 << UART_IIR_RDI; + + if (!(uart->regs.ier & UART_IER_RDI)) + return; + + if (uart->regs.iir != UART_IIR_RLSI) + { + TRACE ("Raiseing receiver data interrupt\n"); + + uart->regs.iir = UART_IIR_RDI; + report_interrupt (uart->irq); + } +} + +static void +uart_int_rlsi (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.ints |= 1 << UART_IIR_RLSI; + + if (!(uart->regs.ier & UART_IER_RLSI)) + return; + + TRACE ("Raiseing receiver line status interrupt\n"); + + /* Highest priority interrupt */ + uart->regs.iir = UART_IIR_RLSI; + report_interrupt (uart->irq); +} + +/* Checks to see if an RLSI interrupt is due and schedules one if need be */ +static void +uart_check_rlsi (void *dat) +{ + struct dev_16450 *uart = dat; + + if (uart->regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY | UART_LSR_FRAME | + UART_LSR_BREAK)) + uart_int_rlsi (uart); +} + +/* Checks to see if an RDI interrupt is due and schedules one if need be */ +static void +uart_check_rdi (void *dat) +{ + struct dev_16450 *uart = dat; + + if (uart->istat.rxbuf_full >= UART_FIFO_TRIGGER (uart->regs.fcr >> 6)) + { + TRACE ("FIFO trigger level reached %i\n", + UART_FIFO_TRIGGER (uart->regs.fcr >> 6)); + uart_int_rdi (uart); + } +} + +/* Raises the next highest priority interrupt */ +static void +uart_next_int (struct dev_16450 *uart) +{ + /* Interrupt detection in proper priority order. */ + if ((uart->istat.ints & (1 << UART_IIR_RLSI)) && + (uart->regs.ier & UART_IER_RLSI)) + uart_int_rlsi (uart); + else if ((uart->istat.ints & (1 << UART_IIR_RDI)) && + (uart->regs.ier & UART_IER_RDI)) + uart_int_rdi (uart); + else if ((uart->istat.ints & (1 << UART_IIR_CTI)) && + (uart->regs.ier & UART_IER_RDI)) + uart_int_cti (uart); + else if ((uart->istat.ints & (1 << UART_IIR_THRI)) && + (uart->regs.ier & UART_IER_THRI)) + uart_int_thri (uart); + else if ((uart->istat.ints & (1 << UART_IIR_MSI)) && + (uart->regs.ier & UART_IER_MSI)) + uart_int_msi (uart); + else + { + clear_interrupt (uart->irq); + uart->regs.iir = UART_IIR_NO_INT; + } +} + +/* Clears potentially pending interrupts */ +static void +uart_clear_int (struct dev_16450 *uart, int intr) +{ + uart->istat.ints &= ~(1 << intr); + + TRACE ("Interrupt pending was %x\n", uart->regs.iir); + + /* Some stuff schedule uart_int_cti, therefore remove it here */ + if (intr == UART_IIR_CTI) + SCHED_FIND_REMOVE (uart_int_cti, uart); + + if (intr != uart->regs.iir) + return; + + TRACE ("Clearing interrupt 0x%x\n", intr); + + uart_next_int (uart); +} + +/*----------------------------------------------------[ Loopback handling ]---*/ +static void +uart_loopback (struct dev_16450 *uart) +{ + if (!(uart->regs.mcr & UART_MCR_LOOP)) + return; + + if ((uart->regs.mcr & UART_MCR_AUX2) != + ((uart->regs.msr & UART_MSR_DCD) >> 4)) + uart->regs.msr |= UART_MSR_DDCD; + + if ((uart->regs.mcr & UART_MCR_AUX1) < + ((uart->regs.msr & UART_MSR_RI) >> 4)) + uart->regs.msr |= UART_MSR_TERI; + + if ((uart->regs.mcr & UART_MCR_RTS) != + ((uart->regs.msr & UART_MSR_CTS) >> 3)) + uart->regs.msr |= UART_MSR_DCTS; + + if ((uart->regs.mcr & UART_MCR_DTR) != + ((uart->regs.msr & UART_MSR_DSR) >> 5)) + uart->regs.msr |= UART_MSR_DDSR; + + uart->regs.msr &= + ~(UART_MSR_DCD | UART_MSR_RI | UART_MSR_DSR | UART_MSR_CTS); + uart->regs.msr |= ((uart->regs.mcr & UART_MCR_AUX2) << 4); + uart->regs.msr |= ((uart->regs.mcr & UART_MCR_AUX1) << 4); + uart->regs.msr |= ((uart->regs.mcr & UART_MCR_RTS) << 3); + uart->regs.msr |= ((uart->regs.mcr & UART_MCR_DTR) << 5); + + if (uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR | UART_MSR_TERI | + UART_MSR_DDCD)) + uart_int_msi (uart); +} + +/*----------------------------------------------------[ Transmitter logic ]---*/ +/* Sends the data in the shift register to the outside world */ +static void +send_char (struct dev_16450 *uart, int bits_send) +{ + PRINTF ("%c", (char) uart->iregs.txser); + TRACE ("TX \'%c\' via UART at %" PRIxADDR "\n", (char) uart->iregs.txser, + uart->baseaddr); + if (uart->regs.mcr & UART_MCR_LOOP) + uart->iregs.loopback = uart->iregs.txser; + else + { + /* Send to either VAPI or to file */ + if (uart->vapi_id) + { + int par, pe, fe, nbits; + int j, data; + unsigned long packet = 0; + + nbits = MIN (bits_send, (uart->regs.lcr & UART_LCR_WLEN8) + 5); + /* Encode a packet */ + packet = uart->iregs.txser & ((1 << nbits) - 1); + + /* Calculate parity */ + for (j = 0, par = 0; j < nbits; j++) + par ^= (packet >> j) & 1; + + if (uart->regs.lcr & UART_LCR_PARITY) + { + if (uart->regs.lcr & UART_LCR_SPAR) + { + packet |= 1 << nbits; + } + else + { + if (uart->regs.lcr & UART_LCR_EPAR) + packet |= par << nbits; + else + packet |= (par ^ 1) << nbits; + } + nbits++; + } + packet |= 1 << (nbits++); + if (uart->regs.lcr & UART_LCR_STOP) + packet |= 1 << (nbits++); + + /* Decode a packet */ + nbits = (uart->vapi.lcr & UART_LCR_WLEN8) + 5; + data = packet & ((1 << nbits) - 1); + + /* Calculate parity, including parity bit */ + for (j = 0, par = 0; j < nbits + 1; j++) + par ^= (packet >> j) & 1; + + if (uart->vapi.lcr & UART_LCR_PARITY) + { + if (uart->vapi.lcr & UART_LCR_SPAR) + { + pe = !((packet >> nbits) & 1); + } + else + { + if (uart->vapi.lcr & UART_LCR_EPAR) + pe = par != 0; + else + pe = par != 1; + } + nbits++; + } + else + pe = 0; + + fe = ((packet >> (nbits++)) & 1) ^ 1; + if (uart->vapi.lcr & UART_LCR_STOP) + fe |= ((packet >> (nbits++)) & 1) ^ 1; + + TRACE ("lcr vapi %02x, uart %02x\n", uart->vapi.lcr, + uart->regs.lcr); + data |= + (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi. + lcr << 8); + TRACE ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data); + vapi_send (uart->vapi_id, data); + } + else + { + char buffer[1] = { uart->iregs.txser & 0xFF }; + channel_write (uart->channel, buffer, 1); + } + } +} + +/* Called when all the bits have been shifted out of the shift register */ +void +uart_char_clock (void *dat) +{ + struct dev_16450 *uart = dat; + + TRACE ("Sending data in shift reg: 0x%02" PRIx8 "\n", uart->iregs.txser); + /* We've sent all bits */ + send_char (uart, (uart->regs.lcr & UART_LCR_WLEN8) + 5); + + if (!uart->istat.txbuf_full) + uart->regs.lsr |= UART_LSR_TXSERE; + else + uart_tx_send (uart); +} + +/* Called when a break has been shifted out of the shift register */ +void +uart_send_break (void *dat) +{ + struct dev_16450 *uart = dat; + + TRACE ("Sending break\n"); +#if 0 + /* Send broken frame */ + int nbits_sent = + ((uart->regs.lcr & UART_LCR_WLEN8) + 5) * (uart->istat.txser_clks - + 1) / uart->char_clks; + send_char (i, nbits_sent); +#endif + /* Send one break signal */ + vapi_send (uart->vapi_id, UART_LCR_SBC << 8); + + /* Send the next char (if there is one) */ + if (!uart->istat.txbuf_full) + uart->regs.lsr |= UART_LSR_TXSERE; + else + uart_tx_send (uart); +} + +/* Scheduled whenever the TX buffer has characters in it and we aren't sending + * a character. */ +void +uart_tx_send (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail]; + uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len; + uart->istat.txbuf_full--; + uart->regs.lsr &= ~UART_LSR_TXSERE; + + TRACE ("Moveing head of TX fifo (fill: %i) to shift reg 0x%02" PRIx8 "\n", + uart->istat.txbuf_full, uart->iregs.txser); + + /* Schedules a char_clock to run in the correct amount of time */ + if (!(uart->regs.lcr & UART_LCR_SBC)) + { + SCHED_ADD (uart_char_clock, uart, uart->char_clks * UART_CLOCK_DIVIDER); + } + else + { + TRACE ("Sending break not char\n"); + SCHED_ADD (uart_send_break, uart, 0); + } + + /* When UART is in either character mode, i.e. 16450 emulation mode, or FIFO + * mode, the THRE interrupt is raised when THR transitions from full to empty. + */ + if (!uart->istat.txbuf_full) + { + uart->regs.lsr |= UART_LSR_TXBUFE; + uart_int_thri (uart); + } +} + +/*-------------------------------------------------------[ Receiver logic ]---*/ +/* Adds a character to the RX FIFO */ +static void +uart_add_char (struct dev_16450 *uart, int ch) +{ + uart->regs.lsr |= UART_LSR_RDRDY; + uart_clear_int (uart, UART_IIR_CTI); + SCHED_ADD (uart_int_cti, uart, + uart->char_clks * UART_CHAR_TIMEOUT * UART_CLOCK_DIVIDER); + + if (uart->istat.rxbuf_full + 1 > uart->fifo_len) + { + uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR; + uart_int_rlsi (uart); + } + else + { + TRACE ("add %02x\n", ch); + uart->regs.rxbuf[uart->istat.rxbuf_head] = ch; + uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len; + if (!uart->istat.rxbuf_full++) + { + uart->regs.lsr |= ch >> 8; + uart_check_rlsi (uart); + } + } + uart_check_rdi (uart); +} + +/* Called when a break sequence is about to start. It stops receiveing + * characters and schedules the uart_recv_break to send the break */ +static void +uart_recv_break_start (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.receiveing = 0; + uart->istat.recv_break = 1; + + SCHED_FIND_REMOVE (uart_recv_char, uart); + + if (uart->vapi_id && (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr)) + uart_vapi_cmd (uart); + + SCHED_ADD (uart_recv_break, uart, + UART_BREAK_COUNT * uart->vapi.char_clks * UART_CLOCK_DIVIDER); +} + +/* Stops sending breaks and starts receiveing characters */ +static void +uart_recv_break_stop (void *dat) +{ + struct dev_16450 *uart = dat; + + uart->istat.recv_break = 0; + SCHED_FIND_REMOVE (uart_recv_break, dat); +} + +/* Receives a break */ +static void +uart_recv_break (void *dat) +{ + struct dev_16450 *uart = dat; + unsigned lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY; + + uart_add_char (uart, lsr << 8); +} + +/* Moves a character from the serial register to the RX FIFO */ +static void +uart_recv_char (void *dat) +{ + struct dev_16450 *uart = dat; + uint16_t char_to_add; + + /* Set unused character bits to zero and allow lsr register in fifo */ + char_to_add = + uart->iregs.rxser & (((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00); + + TRACE ("Receiving 0x%02" PRIx16 "'%c' via UART at %" PRIxADDR "\n", + char_to_add, (char) char_to_add, uart->baseaddr); + PRINTF ("%c", (char) char_to_add); + + if (uart->regs.mcr & UART_MCR_LOOP) + { + uart->iregs.rxser = uart->iregs.loopback; + uart->istat.receiveing = 1; + SCHED_ADD (uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER); + } + else + { + uart->istat.receiveing = 0; + uart_sched_recv_check (uart); + if (uart->vapi_id + && (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr)) + SCHED_ADD (uart_vapi_cmd, uart, 0); + } + + uart_add_char (uart, char_to_add); +} + +/* Checks if there is a character waiting to be received */ +static void +uart_check_char (void *dat) +{ + struct dev_16450 *uart = dat; + uint8_t buffer; + int retval; + + /* Check if there is something waiting, and put it into rxser */ + retval = channel_read (uart->channel, (char *) &buffer, 1); + if (retval > 0) + { + TRACE ("Shifting 0x%02" PRIx8 " (`%c') into shift reg\n", buffer, + buffer); + uart->iregs.rxser = buffer; + uart->istat.receiveing = 1; + SCHED_ADD (uart_recv_char, uart, uart->char_clks * UART_CLOCK_DIVIDER); + return; + } + + if (!retval) + { + SCHED_ADD (uart_check_char, uart, + UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER); + return; + } + + if (retval < 0) + perror (uart->channel_str); +} + +static void +uart_sched_recv_check (struct dev_16450 *uart) +{ + if (!uart->vapi_id) + SCHED_ADD (uart_check_char, uart, + UART_FGETC_SLOWDOWN * UART_CLOCK_DIVIDER); +} + +/*----------------------------------------------------[ UART I/O handling ]---*/ +/* Set a specific UART register with value. */ +static void +uart_write_byte (oraddr_t addr, uint8_t value, void *dat) +{ + struct dev_16450 *uart = dat; + + if (uart->regs.lcr & UART_LCR_DLAB) + { + switch (addr) + { + case UART_DLL: + uart->regs.dll = value; + uart->char_clks = + char_clks (uart->regs.dll, uart->regs.dlh, uart->regs.lcr); + TRACE ("\tSetting char_clks to %li (%02x, %02x, %02x)\n", + uart->char_clks, uart->regs.dll, uart->regs.dlh, + uart->regs.lcr); + return; + case UART_DLH: + TRACE ("Setting dlh with %" PRIx8 "\n", value); + uart->regs.dlh = value; + return; + } + } + + switch (addr) + { + case UART_TXBUF: + TRACE ("Adding %" PRIx8 " to TX FIFO (fill %i)\n", value, + uart->istat.txbuf_full); + uart->regs.lsr &= ~UART_LSR_TXBUFE; + if (uart->istat.txbuf_full < uart->fifo_len) + { + uart->regs.txbuf[uart->istat.txbuf_head] = value; + uart->istat.txbuf_head = + (uart->istat.txbuf_head + 1) % uart->fifo_len; + if (!uart->istat.txbuf_full++ && (uart->regs.lsr & UART_LSR_TXSERE)) + SCHED_ADD (uart_tx_send, uart, 0); + } + else + uart->regs.txbuf[uart->istat.txbuf_head] = value; + + uart_clear_int (uart, UART_IIR_THRI); + break; + case UART_FCR: + TRACE ("Setting FCR reg with %" PRIx8 "\n", value); + uart->regs.fcr = value & UART_VALID_FCR; + if ((uart->fifo_len == 1 && (value & UART_FCR_FIE)) + || (uart->fifo_len != 1 && !(value & UART_FCR_FIE))) + value |= UART_FCR_RRXFI | UART_FCR_RTXFI; + uart->fifo_len = (value & UART_FCR_FIE) ? 16 : 1; + if (value & UART_FCR_RTXFI) + { + uart->istat.txbuf_head = uart->istat.txbuf_tail = 0; + uart->istat.txbuf_full = 0; + uart->regs.lsr |= UART_LSR_TXBUFE; + + /* For FIFO-mode only, THRE interrupt is set when THR and FIFO are empty + */ + if (uart->fifo_len == 16) + uart_int_thri (uart); + + SCHED_FIND_REMOVE (uart_tx_send, uart); + } + if (value & UART_FCR_RRXFI) + { + uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0; + uart->istat.rxbuf_full = 0; + uart->regs.lsr &= ~UART_LSR_RDRDY; + uart_clear_int (uart, UART_IIR_RDI); + uart_clear_int (uart, UART_IIR_CTI); + } + break; + case UART_IER: + uart->regs.ier = value & UART_VALID_IER; + TRACE ("Enabling 0x%02x interrupts with 0x%x interrupts pending\n", + value, uart->istat.ints); + uart_next_int (uart); + break; + case UART_LCR: + TRACE ("Setting LCR reg with %" PRIx8 "\n", value); + if ((uart->regs.lcr & UART_LCR_SBC) != (value & UART_LCR_SBC)) + { + if ((value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) + { + /* Schedule a job to send the break char */ + SCHED_FIND_REMOVE (uart_char_clock, uart); + SCHED_ADD (uart_send_break, uart, 0); + } + if (!(value & UART_LCR_SBC) && !(uart->regs.lsr & UART_LSR_TXSERE)) + { + /* Schedule a job to start sending characters */ + SCHED_ADD (uart_tx_send, uart, 0); + /* Remove the uart_send_break job just in case it has not run yet */ + SCHED_FIND_REMOVE (uart_char_clock, uart); + } + } + uart->regs.lcr = value & UART_VALID_LCR; + uart->char_clks = + char_clks (uart->regs.dll, uart->regs.dlh, uart->regs.lcr); + break; + case UART_MCR: + TRACE ("Setting MCR reg with %" PRIx8 "\n", value); + uart->regs.mcr = value & UART_VALID_MCR; + uart_loopback (uart); + break; + case UART_SCR: + TRACE ("Setting SCR reg with %" PRIx8 "\n", value); + uart->regs.scr = value; + break; + default: + TRACE ("write out of range (addr %" PRIxADDR ")\n", addr); + } +} + +/* Read a specific UART register. */ +static uint8_t +uart_read_byte (oraddr_t addr, void *dat) +{ + struct dev_16450 *uart = dat; + uint8_t value = 0; + + if (uart->regs.lcr & UART_LCR_DLAB) + { + switch (addr) + { + case UART_DLL: + value = uart->regs.dll; + TRACE ("reading DLL = %" PRIx8 "\n", value); + return value; + case UART_DLH: + value = uart->regs.dlh; + TRACE ("reading DLH = %" PRIx8 "\n", value); + return value; + } + } + + switch (addr) + { + case UART_RXBUF: + { /* Print out FIFO for debugging */ + int i; + TRACE ("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len, + uart->istat.rxbuf_head, uart->istat.rxbuf_tail); + for (i = 0; i < uart->istat.rxbuf_full; i++) + TRACE ("%02x ", + uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % + uart->fifo_len]); + TRACE (")\n"); + } + if (uart->istat.rxbuf_full) + { + value = uart->regs.rxbuf[uart->istat.rxbuf_tail]; + uart->istat.rxbuf_tail = + (uart->istat.rxbuf_tail + 1) % uart->fifo_len; + uart->istat.rxbuf_full--; + TRACE ("Reading %" PRIx8 " out of RX FIFO\n", value); + } + else + TRACE ("Trying to read out of RX FIFO but it's empty!\n"); + + uart_clear_int (uart, UART_IIR_RDI); + uart_clear_int (uart, UART_IIR_CTI); + + if (uart->istat.rxbuf_full) + { + uart->regs.lsr |= + UART_LSR_RDRDY | uart->regs.rxbuf[uart->istat.rxbuf_tail] >> 8; + SCHED_ADD (uart_int_cti, uart, + uart->char_clks * UART_CHAR_TIMEOUT * + UART_CLOCK_DIVIDER); + uart_check_rlsi (uart); + uart_check_rdi (uart); + } + else + { + uart->regs.lsr &= ~UART_LSR_RDRDY; + } + break; + case UART_IER: + value = uart->regs.ier & UART_VALID_IER; + TRACE ("reading IER = %" PRIx8 "\n", value); + break; + case UART_IIR: + value = (uart->regs.iir & UART_VALID_IIR) | 0xc0; + /* Only clear the thri interrupt if it is the one we are repporting */ + if (uart->regs.iir == UART_IIR_THRI) + uart_clear_int (uart, UART_IIR_THRI); + TRACE ("reading IIR = %" PRIx8 "\n", value); + break; + case UART_LCR: + value = uart->regs.lcr & UART_VALID_LCR; + TRACE ("reading LCR = %" PRIx8 "\n", value); + break; + case UART_MCR: + value = 0; + TRACE ("reading MCR = %" PRIx8 "\n", value); + break; + case UART_LSR: + value = uart->regs.lsr & UART_VALID_LSR; + uart->regs.lsr &= + ~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY + | UART_LSR_FRAME | UART_LSR_RXERR); + /* Clear potentially pending RLSI interrupt */ + uart_clear_int (uart, UART_IIR_RLSI); + TRACE ("reading LSR = %" PRIx8 "\n", value); + break; + case UART_MSR: + value = uart->regs.msr & UART_VALID_MSR; + uart->regs.msr = 0; + uart_clear_int (uart, UART_IIR_MSI); + uart_loopback (uart); + TRACE ("reading MSR = %" PRIx8 "\n", value); + break; + case UART_SCR: + value = uart->regs.scr; + TRACE ("reading SCR = %" PRIx8 "\n", value); + break; + default: + TRACE ("read out of range (addr %" PRIxADDR ")\n", addr); + } + return value; +} + +/*--------------------------------------------------------[ VAPI handling ]---*/ +/* Decodes the read vapi command */ +static void +uart_vapi_cmd (void *dat) +{ + struct dev_16450 *uart = dat; + int received = 0; + + while (!received) + { + if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) + { + unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr]; + TRACE ("\tHandling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr, + uart->vapi_buf_tail_ptr); + uart->vapi_buf_tail_ptr = + (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN; + switch (data >> 24) + { + case 0x00: + uart->vapi.lcr = (data >> 8) & 0xff; + /* Put data into rx fifo */ + uart->iregs.rxser = data & 0xff; + uart->vapi.char_clks = + char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr); + if ((uart->vapi.lcr & ~UART_LCR_SBC) != + (uart->regs.lcr & ~UART_LCR_SBC) + || uart->vapi.char_clks != uart->char_clks + || uart->vapi.skew < -MAX_SKEW + || uart->vapi.skew > MAX_SKEW) + { + if ((uart->vapi.lcr & ~UART_LCR_SBC) != + (uart->regs.lcr & ~UART_LCR_SBC)) + WARN ("unmatched VAPI (%02" PRIx8 ") and uart (%02" PRIx8 + ") modes.\n", uart->vapi.lcr & ~UART_LCR_SBC, + uart->regs.lcr & ~UART_LCR_SBC); + if (uart->vapi.char_clks != uart->char_clks) + { + WARN + ("unmatched VAPI (%li) and uart (%li) char clocks.\n", + uart->vapi.char_clks, uart->char_clks); + WARN ("VAPI: lcr: %02" PRIx8 ", dll: %02" PRIx8 + ", dlh: %02" PRIx8 "\n", uart->vapi.lcr, + uart->vapi.dll, uart->vapi.dlh); + WARN ("UART: lcr: %02" PRIx8 ", dll: %02" PRIx8 + ", dlh: %02" PRIx8 "\n", uart->regs.lcr, + uart->regs.dll, uart->vapi.dlh); + } + if (uart->vapi.skew < -MAX_SKEW + || uart->vapi.skew > MAX_SKEW) + WARN ("VAPI skew is beyond max: %i\n", uart->vapi.skew); + /* Set error bits */ + uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8; + if (uart->regs.lcr & UART_LCR_PARITY) + uart->iregs.rxser |= UART_LSR_PARITY << 8; + } + if (!uart->istat.recv_break) + { + uart->istat.receiveing = 1; + SCHED_ADD (uart_recv_char, uart, + uart->char_clks * UART_CLOCK_DIVIDER); + } + received = 1; + break; + case 0x01: + uart->vapi.dll = (data >> 0) & 0xff; + uart->vapi.dlh = (data >> 8) & 0xff; + break; + case 0x02: + uart->vapi.lcr = (data >> 8) & 0xff; + break; + case 0x03: + uart->vapi.skew = (signed short) (data & 0xffff); + break; + case 0x04: + if ((data >> 16) & 1) + { + /* If data & 0xffff is 0 then set the break imediatly and handle the + * following commands as appropriate */ + if (!(data & 0xffff)) + uart_recv_break_start (uart); + else + /* Schedule a job to start sending breaks */ + SCHED_ADD (uart_recv_break_start, uart, + (data & 0xffff) * UART_CLOCK_DIVIDER); + } + else + { + /* If data & 0xffff is 0 then release the break imediatly and handle + * the following commands as appropriate */ + if (!(data & 0xffff)) + uart_recv_break_stop (uart); + else + /* Schedule a job to stop sending breaks */ + SCHED_ADD (uart_recv_break_stop, uart, + (data & 0xffff) * UART_CLOCK_DIVIDER); + } + break; + default: + WARN ("WARNING: Invalid vapi command %02lx\n", data >> 24); + break; + } + } + else + break; + } +} + +/* Function that handles incoming VAPI data. */ +static void +uart_vapi_read (unsigned long id, unsigned long data, void *dat) +{ + struct dev_16450 *uart = dat; + TRACE ("UART: id %08lx, data %08lx\n", id, data); + uart->vapi_buf[uart->vapi_buf_head_ptr] = data; + uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN; + if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) + { + fprintf (stderr, "FATAL: uart VAPI buffer to small.\n"); + exit (1); + } + if (!uart->istat.receiveing) + uart_vapi_cmd (uart); +} + +/*--------------------------------------------------------[ Sim callbacks ]---*/ +/* Reset. It initializes all registers of all UART devices to zero values, + * (re)opens all RX/TX file streams and places devices in memory address + * space. */ +void +uart_reset (void *dat) +{ + struct dev_16450 *uart = dat; + + if (uart->vapi_id) + { + vapi_install_handler (uart->vapi_id, uart_vapi_read, dat); + } + else if (uart->channel_str && uart->channel_str[0]) + { /* Try to create stream. */ + if (uart->channel) + channel_close (uart->channel); + else + uart->channel = channel_init (uart->channel_str); + if (channel_open (uart->channel) < 0) + { + WARN ("WARNING: problem with channel \"%s\" detected.\n", + uart->channel_str); + } + else if (config.sim.verbose) + PRINTF ("UART at 0x%" PRIxADDR "\n", uart->baseaddr); + } + else + { + WARN ("WARNING: UART at %" PRIxADDR + " has no vapi nor channel specified\n", uart->baseaddr); + } + + if (uart->uart16550) + uart->fifo_len = 16; + else + uart->fifo_len = 1; + + uart->istat.rxbuf_head = uart->istat.rxbuf_tail = 0; + uart->istat.txbuf_head = uart->istat.txbuf_tail = 0; + + uart->istat.txbuf_full = uart->istat.rxbuf_full = 0; + + uart->char_clks = 0; + + uart->iregs.txser = 0; + uart->iregs.rxser = 0; + uart->iregs.loopback = 0; + uart->istat.receiveing = 0; + uart->istat.recv_break = 0; + uart->istat.ints = 0; + + memset (uart->regs.txbuf, 0, sizeof (uart->regs.txbuf)); + memset (uart->regs.rxbuf, 0, sizeof (uart->regs.rxbuf)); + + uart->regs.dll = 0; + uart->regs.dlh = 0; + uart->regs.ier = 0; + uart->regs.iir = UART_IIR_NO_INT; + uart->regs.fcr = 0; + uart->regs.lcr = UART_LCR_RESET; + uart->regs.mcr = 0; + uart->regs.lsr = UART_LSR_TXBUFE | UART_LSR_TXSERE; + uart->regs.msr = 0; + uart->regs.scr = 0; + + uart->vapi.skew = 0; + uart->vapi.lcr = 0; + uart->vapi.dll = 0; + uart->vapi.char_clks = 0; + + uart->vapi_buf_head_ptr = 0; + uart->vapi_buf_tail_ptr = 0; + memset (uart->vapi_buf, 0, sizeof (uart->vapi_buf)); + + uart_sched_recv_check (uart); +} + +/* Print register values on stdout. */ +void +uart_status (void *dat) +{ + struct dev_16450 *uart = dat; + int i; + + PRINTF ("\nUART visible registers at 0x%" PRIxADDR ":\n", uart->baseaddr); + PRINTF ("RXBUF: "); + for (i = uart->istat.rxbuf_head; i != uart->istat.rxbuf_tail; + i = (i + 1) % uart->fifo_len) + PRINTF (" %.2x", uart->regs.rxbuf[i]); + PRINTF ("TXBUF: "); + for (i = uart->istat.txbuf_head; i != uart->istat.txbuf_tail; + i = (i + 1) % uart->fifo_len) + PRINTF (" %.2x", uart->regs.txbuf[i]); + PRINTF ("\n"); + PRINTF ("DLL : %.2x DLH : %.2x\n", uart->regs.dll, uart->regs.dlh); + PRINTF ("IER : %.2x IIR : %.2x\n", uart->regs.ier, uart->regs.iir); + PRINTF ("LCR : %.2x MCR : %.2x\n", uart->regs.lcr, uart->regs.mcr); + PRINTF ("LSR : %.2x MSR : %.2x\n", uart->regs.lsr, uart->regs.msr); + PRINTF ("SCR : %.2x\n", uart->regs.scr); + + PRINTF ("\nInternal registers (sim debug):\n"); + PRINTF ("RXSER: %.2" PRIx16 " TXSER: %.2" PRIx8 "\n", uart->iregs.rxser, + uart->iregs.txser); + + PRINTF ("\nInternal status (sim debug):\n"); + PRINTF ("char_clks: %ld\n", uart->char_clks); + PRINTF ("rxbuf_full: %d txbuf_full: %d\n", uart->istat.rxbuf_full, + uart->istat.txbuf_full); + PRINTF ("Using IRQ%i\n", uart->irq); + if (uart->vapi_id) + PRINTF ("Connected to vapi ID=%lx\n\n", uart->vapi_id); + /* TODO: replace by a channel_status + else + PRINTF("RX fs: %p TX fs: %p\n\n", uart->rxfs, uart->txfs); + */ +} + +/*---------------------------------------------------[ UART configuration ]---*/ +static void +uart_baseaddr (union param_val val, void *dat) +{ + struct dev_16450 *uart = dat; + uart->baseaddr = val.addr_val; +} + +static void +uart_jitter (union param_val val, void *dat) +{ + struct dev_16450 *uart = dat; + uart->jitter = val.int_val; +} + +static void +uart_irq (union param_val val, void *dat) +{ + struct dev_16450 *uart = dat; + uart->irq = val.int_val; +} + +static void +uart_16550 (union param_val val, void *dat) +{ + struct dev_16450 *uart = dat; + uart->uart16550 = val.int_val; +} + +/*---------------------------------------------------------------------------*/ +/*!Set the channel description + + Free any existing string. + + @param[in] val The value to use + @param[in] dat The config data structure */ +/*---------------------------------------------------------------------------*/ +static void +uart_channel (union param_val val, + void *dat) +{ + struct dev_16450 *uart = dat; + + if (NULL != uart->channel_str) + { + free (uart->channel_str); + uart->channel_str = NULL; + } + + if (!(uart->channel_str = strdup (val.str_val))) + { + fprintf (stderr, "Peripheral 16450: Run out of memory\n"); + exit (-1); + } + +} /* uart_channel() */ + + +static void +uart_newway (union param_val val, void *dat) +{ + CONFIG_ERROR + (" txfile and rxfile and now obsolete.\n\tUse 'channel = \"file:rxfile,txfile\"' instead."); + exit (1); +} + +static void +uart_vapi_id (union param_val val, void *dat) +{ + struct dev_16450 *uart = dat; + uart->vapi_id = val.int_val; +} + +static void +uart_enabled (union param_val val, void *dat) +{ + struct dev_16450 *uart = dat; + uart->enabled = val.int_val; +} + + +/*---------------------------------------------------------------------------*/ +/*!Initialize a new UART configuration + + ALL parameters are set explicitly to default values. */ +/*---------------------------------------------------------------------------*/ +static void * +uart_sec_start () +{ + struct dev_16450 *new = malloc (sizeof (struct dev_16450)); + + if (!new) + { + fprintf (stderr, "Peripheral 16450: Run out of memory\n"); + exit (-1); + } + + new->enabled = 1; + new->baseaddr = 0; + new->irq = 0; + new->uart16550 = 0; + new->jitter = 0; + new->channel_str = strdup ("xterm:"); + new->vapi_id = 0; + + new->channel = NULL; + + return new; + +} /* uart_sec_start() */ + + +static void +uart_sec_end (void *dat) +{ + struct dev_16450 *uart = dat; + struct mem_ops ops; + + if (!uart->enabled) + { + free (dat); + return; + } + + memset (&ops, 0, sizeof (struct mem_ops)); + + ops.readfunc8 = uart_read_byte; + ops.writefunc8 = uart_write_byte; + ops.read_dat8 = dat; + ops.write_dat8 = dat; + + /* FIXME: What should these be? */ + ops.delayr = 2; + ops.delayw = 2; + + reg_mem_area (uart->baseaddr, UART_ADDR_SPACE, 0, &ops); + + reg_sim_reset (uart_reset, dat); + reg_sim_stat (uart_status, dat); +} + +void +reg_uart_sec (void) +{ + struct config_section *sec = reg_config_sec ("uart", uart_sec_start, + uart_sec_end); + + reg_config_param (sec, "enabled", paramt_int, uart_enabled); + reg_config_param (sec, "baseaddr", paramt_addr, uart_baseaddr); + reg_config_param (sec, "irq", paramt_int, uart_irq); + reg_config_param (sec, "16550", paramt_int, uart_16550); + reg_config_param (sec, "jitter", paramt_int, uart_jitter); + reg_config_param (sec, "channel", paramt_str, uart_channel); + reg_config_param (sec, "txfile", paramt_str, uart_newway); + reg_config_param (sec, "rxfile", paramt_str, uart_newway); + reg_config_param (sec, "vapi_id", paramt_int, uart_vapi_id); +} Index: vga.h =================================================================== --- vga.h (nonexistent) +++ vga.h (revision 1765) @@ -0,0 +1,35 @@ +/* vga.h -- Definition of types and structures for Richard's VGA/LCD controler. + + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + +/* NOTE: device is only partially implemented! */ + + +#ifndef VGA__H +#define VGA__H + +/* Prototypes for external void */ +extern void reg_vga_sec (); + +#endif /* VGA__H */
vga.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: 16450.h =================================================================== --- 16450.h (nonexistent) +++ 16450.h (revision 1765) @@ -0,0 +1,35 @@ +/* 16450.h -- Definition of types and structures for 8250/16450 serial UART + + Copyright (C) 2000 Damjan Lampret, lampret@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef UART_16450__H +#define UART_16450__H + +/* Prototypes for external use*/ +extern void uart_reset (); +extern void uart_status (); +extern void reg_uart_sec (); + +#endif /* UART_16450__H */ Index: dma-defs.h =================================================================== --- dma-defs.h (nonexistent) +++ dma-defs.h (revision 1765) @@ -0,0 +1,132 @@ +/* dma-defs.h -- Definition of relative addresses/register bits for DMA + + Copyright (C) 2001 by Erez Volk, erez@opencores.org + Copyright (C) 2008 Embecosm Limited + + Contributor Jeremy Bennett + + This file is part of Or1ksim, the 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 3 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, see . */ + +/* This program is commented throughout in a fashion suitable for processing + with Doxygen. */ + + +#ifndef DMA_DEFS__H +#define DMA_DEFS__H + +/* Number of channel per DMA controller */ +#define DMA_NUM_CHANNELS 31 + +/* Address space required by one DMA controller */ +#define DMA_ADDR_SPACE 0x400 + +/* Relative Register Addresses */ +#define DMA_CSR 0x00 +#define DMA_INT_MSK_A 0x04 +#define DMA_INT_MSK_B 0x08 +#define DMA_INT_SRC_A 0x0C +#define DMA_INT_SRC_B 0x10 + +/* Channel registers definitions */ +#define DMA_CH_BASE 0x20 /*!< Offset of first channel registers */ +#define DMA_CH_SIZE 0x20 /*!< Per-channel address space */ + +/* Per-channel Register Addresses, relative to channel start */ +#define DMA_CH_CSR 0x00 +#define DMA_CH_SZ 0x04 +#define DMA_CH_A0 0x08 +#define DMA_CH_AM0 0x0C +#define DMA_CH_A1 0x10 +#define DMA_CH_AM1 0x14 +#define DMA_CH_DESC 0x18 +#define DMA_CH_SWPTR 0x1C + +/* Field Definitions for the Main CSR */ +#define DMA_CSR_PAUSE_OFFSET 0 + +/* Field Definitions for the Channel CSR(s) */ +#define DMA_CH_CSR_CH_EN_OFFSET 0 +#define DMA_CH_CSR_DST_SEL_OFFSET 1 +#define DMA_CH_CSR_SRC_SEL_OFFSET 2 +#define DMA_CH_CSR_INC_DST_OFFSET 3 +#define DMA_CH_CSR_INC_SRC_OFFSET 4 +#define DMA_CH_CSR_MODE_OFFSET 5 +#define DMA_CH_CSR_ARS_OFFSET 6 +#define DMA_CH_CSR_USE_ED_OFFSET 7 +#define DMA_CH_CSR_SZ_WB_OFFSET 8 +#define DMA_CH_CSR_STOP_OFFSET 9 +#define DMA_CH_CSR_BUSY_OFFSET 10 +#define DMA_CH_CSR_DONE_OFFSET 11 +#define DMA_CH_CSR_ERR_OFFSET 12 +#define DMA_CH_CSR_PRIORITY_OFFSET 13 +#define DMA_CH_CSR_PRIORITY_WIDTH 3 +#define DMA_CH_CSR_REST_EN_OFFSET 16 +#define DMA_CH_CSR_INE_ERR_OFFSET 17 +#define DMA_CH_CSR_INE_DONE_OFFSET 18 +#define DMA_CH_CSR_INE_CHK_DONE_OFFSET 19 +#define DMA_CH_CSR_INT_ERR_OFFSET 20 +#define DMA_CH_CSR_INT_DONE_OFFSET 21 +#define DMA_CH_CSR_INT_CHUNK_DONE_OFFSET 22 +#define DMA_CH_CSR_RESERVED_OFFSET 23 +#define DMA_CH_CSR_RESERVED_WIDTH 9 + +/* Masks -- Writable and readonly parts of the register */ +#define DMA_CH_CSR_WRITE_MASK 0x000FE3FF + +/* Field definitions for Channel Size Registers */ +#define DMA_CH_SZ_TOT_SZ_OFFSET 0 +#define DMA_CH_SZ_TOT_SZ_WIDTH 12 +#define DMA_CH_SZ_CHK_SZ_OFFSET 16 +#define DMA_CH_SZ_CHK_SZ_WIDTH 9 + +/* Field definitions for Channel Address Registers CHn_Am */ +#define DMA_CH_A0_ADDR_OFFSET 2 +#define DMA_CH_A0_ADDR_WIDTH 30 +#define DMA_CH_A1_ADDR_OFFSET 2 +#define DMA_CH_A1_ADDR_WIDTH 30 + +/* Field definitions for Channel Address Mask Registers CHn_AMm */ +#define DMA_CH_AM0_MASK_OFFSET 4 +#define DMA_CH_AM0_MASK_WIDTH 28 +#define DMA_CH_AM1_MASK_OFFSET 4 +#define DMA_CH_AM1_MASK_WIDTH 28 + +/* Field definitions for Channel Linked List descriptor Pointer CHn_DESC */ +#define DMA_CH_DESC_ADDR_OFFSET 2 +#define DMA_CH_DESC_ADDR_WIDTH 30 + +/* Field definitions for Channel Software Pointer */ +#define DMA_CH_SWPTR_PTR_OFFSET 2 +#define DMA_CH_SWPTR_PTR_WIDTH 29 +#define DMA_CH_SWPTR_EN_OFFSET 31 + + +/* Structure of linked list descriptors (offsets of elements) */ +#define DMA_DESC_CSR 0x00 +#define DMA_DESC_ADR0 0x04 +#define DMA_DESC_ADR1 0x08 +#define DMA_DESC_NEXT 0x0C + +/* Field definitions for linked list descriptor DESC_CSR */ +#define DMA_DESC_CSR_EOL_OFFSET 20 +#define DMA_DESC_CSR_INC_SRC_OFFSET 19 +#define DMA_DESC_CSR_INC_DST_OFFSET 18 +#define DMA_DESC_CSR_SRC_SEL_OFFSET 17 +#define DMA_DESC_CSR_DST_SEL_OFFSET 16 +#define DMA_DESC_CSR_TOT_SZ_OFFSET 0 +#define DMA_DESC_CSR_TOT_SZ_WIDTH 12 + +#endif /* DMA_DEFS__H */ Index: Makefile.am =================================================================== --- Makefile.am (nonexistent) +++ Makefile.am (revision 1765) @@ -0,0 +1,57 @@ +# Makefile -- Makefile for peripherals simulation +# +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# Copyright (C) 2008 Embecosm Limited +# +# Contributor Jeremy Bennett +# +# 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 3 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, see . + + +SUBDIRS = channels + +noinst_LTLIBRARIES = libperipheral.la +libperipheral_la_SOURCES = generic.c \ + 16450.c \ + dma.c \ + mc.c \ + eth.c \ + crc32.c \ + gpio.c \ + vga.c \ + fb.c \ + ps2kbd.c \ + atahost.c \ + atadevice.c \ + atadevice-cmdi.c \ + memory.c \ + 16450.h \ + atacmd.h \ + generic.h \ + atadevice-cmdi.h \ + atadevice.h \ + atahost.h \ + crc32.h \ + dma-defs.h \ + dma.h \ + eth.h \ + fb.h \ + fields.h \ + gpio.h \ + mc.h \ + memory.h \ + ps2kbd.h \ + vga.h Index: crc32.c =================================================================== --- crc32.c (nonexistent) +++ crc32.c (revision 1765) @@ -0,0 +1,67 @@ +#include "crc32.h" + +static unsigned long crc32_table[256] = +{ + 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, + 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, + 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, + 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, + 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, + 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, + 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, + 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, + 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, + 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, + 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, + 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, + 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, + 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, + 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, + 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, + 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, + 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, + 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, + 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, + 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, + 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, + 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, + 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, + 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, + 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, + 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, + 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, + 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, + 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, + 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, + 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL +}; + + +unsigned long crc32( const void *buf, unsigned len ) +{ + unsigned long crc; + + crc32_init( &crc ); + crc32_feed_bytes( &crc, buf, len ); + crc32_close( &crc ); + return crc; +} + + +void crc32_init( unsigned long *value ) +{ + *value = 0xFFFFFFFF; +} + +void crc32_feed_bytes( unsigned long *value, const void *buf, unsigned len ) +{ + const unsigned char *p; + + for ( p = (const unsigned char *)buf; len > 0; ++ p, -- len ) + *value = (*value >> 8) ^ crc32_table[(*value ^ *p) & 0xFF]; +} + +void crc32_close( unsigned long *value ) +{ + *value = ~*value; +} Index: crc32.h =================================================================== --- crc32.h (nonexistent) +++ crc32.h (revision 1765) @@ -0,0 +1,13 @@ +#ifndef __CRC32_H +#define __CRC32_H + + +/* Calculate CRC of buffer in one go */ +unsigned long crc32( const void *buf, unsigned len ); + +/* Calculate incrementally */ +void crc32_init( unsigned long *value ); +void crc32_feed_bytes( unsigned long *value, const void *buf, unsigned len ); +void crc32_close( unsigned long *value ); + +#endif /* ___CRC32_H */ Index: . =================================================================== --- . (nonexistent) +++ . (revision 1765)
. Property changes : Added: svn:ignore ## -0,0 +1,2 ## +Makefile +.deps

powered by: WebSVN 2.1.0

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