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