1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
/* Blackfin device support.
Copyright (C) 2010-2012 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of simulators.
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/>. */
#include "config.h"
#include "sim-main.h"
#include "sim-hw.h"
#include "hw-device.h"
#include "dv-bfin_cec.h"
#include "dv-bfin_mmu.h"
static void
bfin_mmr_invalid (struct hw *me, SIM_CPU *cpu, address_word addr,
unsigned nr_bytes, bool write)
{
if (!cpu)
cpu = hw_system_cpu (me);
/* Only throw a fit if the cpu is doing the access. DMA/GDB simply
go unnoticed. Not exactly hardware behavior, but close enough. */
if (!cpu)
{
sim_io_eprintf (hw_system (me), "%s: invalid MMR access @ %#x\n",
hw_path (me), addr);
return;
}
HW_TRACE ((me, "invalid MMR %s to 0x%08lx length %u",
write ? "write" : "read", (unsigned long) addr, nr_bytes));
/* XXX: is this what hardware does ? */
if (addr >= BFIN_CORE_MMR_BASE)
/* XXX: This should be setting up CPLB fault addrs ? */
mmu_process_fault (cpu, addr, write, false, false, true);
else
/* XXX: Newer parts set up an interrupt from EBIU and program
EBIU_ERRADDR with the address. */
cec_hwerr (cpu, HWERR_SYSTEM_MMR);
}
void
dv_bfin_mmr_invalid (struct hw *me, address_word addr, unsigned nr_bytes,
bool write)
{
bfin_mmr_invalid (me, NULL, addr, nr_bytes, write);
}
void
dv_bfin_mmr_require (struct hw *me, address_word addr, unsigned nr_bytes,
unsigned size, bool write)
{
if (nr_bytes != size)
dv_bfin_mmr_invalid (me, addr, nr_bytes, write);
}
static bool
bfin_mmr_check (struct hw *me, SIM_CPU *cpu, address_word addr,
unsigned nr_bytes, bool write)
{
if (addr >= BFIN_CORE_MMR_BASE)
{
/* All Core MMRs are aligned 32bits. */
if ((addr & 3) == 0 && nr_bytes == 4)
return true;
}
else if (addr >= BFIN_SYSTEM_MMR_BASE)
{
/* All System MMRs are 32bit aligned, but can be 16bits or 32bits. */
if ((addr & 0x3) == 0 && (nr_bytes == 2 || nr_bytes == 4))
return true;
}
else
return true;
/* Still here ? Must be crap. */
bfin_mmr_invalid (me, cpu, addr, nr_bytes, write);
return false;
}
bool
dv_bfin_mmr_check (struct hw *me, address_word addr, unsigned nr_bytes,
bool write)
{
return bfin_mmr_check (me, NULL, addr, nr_bytes, write);
}
int
device_io_read_buffer (device *me, void *source, int space,
address_word addr, unsigned nr_bytes,
SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
{
struct hw *dv_me = (struct hw *) me;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
return nr_bytes;
if (bfin_mmr_check (dv_me, cpu, addr, nr_bytes, false))
if (cpu)
{
sim_cpu_hw_io_read_buffer (cpu, cia, dv_me, source, space,
addr, nr_bytes);
return nr_bytes;
}
else
return sim_hw_io_read_buffer (sd, dv_me, source, space, addr, nr_bytes);
else
return 0;
}
int
device_io_write_buffer (device *me, const void *source, int space,
address_word addr, unsigned nr_bytes,
SIM_DESC sd, SIM_CPU *cpu, sim_cia cia)
{
struct hw *dv_me = (struct hw *) me;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
return nr_bytes;
if (bfin_mmr_check (dv_me, cpu, addr, nr_bytes, true))
if (cpu)
{
sim_cpu_hw_io_write_buffer (cpu, cia, dv_me, source, space,
addr, nr_bytes);
return nr_bytes;
}
else
return sim_hw_io_write_buffer (sd, dv_me, source, space, addr, nr_bytes);
else
return 0;
}
void device_error (device *me, const char *message, ...)
{
/* Don't bother doing anything here -- any place in common code that
calls device_error() follows it with sim_hw_abort(). Since the
device isn't bound to the system yet, we can't call any common
hardware error funcs on it or we'll hit a NULL pointer. */
}
unsigned int dv_get_bus_num (struct hw *me)
{
const hw_unit *unit = hw_unit_address (me);
return unit->cells[unit->nr_cells - 1];
}
|