Merge master into threading to add support for VFP

This commit is contained in:
bunnei 2014-05-16 22:24:34 -04:00
commit 0b1ba2f37a
33 changed files with 14281 additions and 189 deletions

View file

@ -7,6 +7,7 @@ set(SRCS core.cpp
arm/disassembler/arm_disasm.cpp
arm/disassembler/load_symbol_map.cpp
arm/interpreter/arm_interpreter.cpp
arm/interpreter/armcopro.cpp
arm/interpreter/armemu.cpp
arm/interpreter/arminit.cpp
arm/interpreter/armmmu.cpp
@ -14,7 +15,18 @@ set(SRCS core.cpp
arm/interpreter/armsupp.cpp
arm/interpreter/armvirt.cpp
arm/interpreter/thumbemu.cpp
arm/mmu/arm1176jzf_s_mmu.cpp
arm/interpreter/vfp/vfp.cpp
arm/interpreter/vfp/vfpdouble.cpp
arm/interpreter/vfp/vfpinstr.cpp
arm/interpreter/vfp/vfpsingle.cpp
arm/interpreter/mmu/arm1176jzf_s_mmu.cpp
arm/interpreter/mmu/cache.cpp
arm/interpreter/mmu/maverick.cpp
arm/interpreter/mmu/rb.cpp
arm/interpreter/mmu/sa_mmu.cpp
arm/interpreter/mmu/tlb.cpp
arm/interpreter/mmu/wb.cpp
arm/interpreter/mmu/xscale_copro.cpp
elf/elf_reader.cpp
file_sys/directory_file_system.cpp
file_sys/meta_file_system.cpp

View file

@ -2,7 +2,7 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "arm_interpreter.h"
#include "core/arm/interpreter/arm_interpreter.h"
const static cpu_config_t s_arm11_cpu_info = {
"armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE

View file

@ -0,0 +1,842 @@
/* armcopro.c -- co-processor interface: ARM6 Instruction Emulator.
Copyright (C) 1994, 2000 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "core/arm/interpreter/armdefs.h"
#include "core/arm/interpreter/armos.h"
#include "core/arm/interpreter/armemu.h"
#include "core/arm/interpreter/vfp/vfp.h"
//chy 2005-07-08
//#include "ansidecl.h"
//chy -------
//#include "iwmmxt.h"
//chy 2005-09-19 add CP6 MRC support (for get irq number and base)
extern unsigned xscale_cp6_mrc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
//chy 2005-09-19---------------
extern unsigned xscale_cp13_init (ARMul_State * state);
extern unsigned xscale_cp13_exit (ARMul_State * state);
extern unsigned xscale_cp13_ldc (ARMul_State * state, unsigned type,
ARMword instr, ARMword data);
extern unsigned xscale_cp13_stc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
extern unsigned xscale_cp13_mrc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
extern unsigned xscale_cp13_mcr (ARMul_State * state, unsigned type,
ARMword instr, ARMword data);
extern unsigned xscale_cp13_cdp (ARMul_State * state, unsigned type,
ARMword instr);
extern unsigned xscale_cp13_read_reg (ARMul_State * state, unsigned reg,
ARMword * data);
extern unsigned xscale_cp13_write_reg (ARMul_State * state, unsigned reg,
ARMword data);
extern unsigned xscale_cp14_init (ARMul_State * state);
extern unsigned xscale_cp14_exit (ARMul_State * state);
extern unsigned xscale_cp14_ldc (ARMul_State * state, unsigned type,
ARMword instr, ARMword data);
extern unsigned xscale_cp14_stc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
extern unsigned xscale_cp14_mrc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
extern unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type,
ARMword instr, ARMword data);
extern unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type,
ARMword instr);
extern unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg,
ARMword * data);
extern unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg,
ARMword data);
extern unsigned xscale_cp15_init (ARMul_State * state);
extern unsigned xscale_cp15_exit (ARMul_State * state);
extern unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type,
ARMword instr, ARMword data);
extern unsigned xscale_cp15_stc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
extern unsigned xscale_cp15_mrc (ARMul_State * state, unsigned type,
ARMword instr, ARMword * data);
extern unsigned xscale_cp15_mcr (ARMul_State * state, unsigned type,
ARMword instr, ARMword data);
extern unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type,
ARMword instr);
extern unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg,
ARMword * data);
extern unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg,
ARMword data);
extern unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
unsigned cpnum);
/* Dummy Co-processors. */
static unsigned
NoCoPro3R (ARMul_State * state,
unsigned a, ARMword b)
{
return ARMul_CANT;
}
static unsigned
NoCoPro4R (ARMul_State * state,
unsigned a,
ARMword b, ARMword c)
{
return ARMul_CANT;
}
static unsigned
NoCoPro4W (ARMul_State * state,
unsigned a,
ARMword b, ARMword * c)
{
return ARMul_CANT;
}
static unsigned
NoCoPro5R (ARMul_State * state,
unsigned a,
ARMword b,
ARMword c, ARMword d)
{
return ARMul_CANT;
}
static unsigned
NoCoPro5W (ARMul_State * state,
unsigned a,
ARMword b,
ARMword * c, ARMword * d )
{
return ARMul_CANT;
}
/* The XScale Co-processors. */
/* Coprocessor 15: System Control. */
static void write_cp14_reg (unsigned, ARMword);
static ARMword read_cp14_reg (unsigned);
/* There are two sets of registers for copro 15.
One set is available when opcode_2 is 0 and
the other set when opcode_2 >= 1. */
static ARMword XScale_cp15_opcode_2_is_0_Regs[16];
static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16];
/* There are also a set of breakpoint registers
which are accessed via CRm instead of opcode_2. */
static ARMword XScale_cp15_DBR1;
static ARMword XScale_cp15_DBCON;
static ARMword XScale_cp15_IBCR0;
static ARMword XScale_cp15_IBCR1;
static unsigned
XScale_cp15_init (ARMul_State * state)
{
int i;
for (i = 16; i--;) {
XScale_cp15_opcode_2_is_0_Regs[i] = 0;
XScale_cp15_opcode_2_is_not_0_Regs[i] = 0;
}
/* Initialise the processor ID. */
//chy 2003-03-24, is same as cpu id in skyeye_options.c
//XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000;
XScale_cp15_opcode_2_is_0_Regs[0] = 0x69050000;
/* Initialise the cache type. */
XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA;
/* Initialise the ARM Control Register. */
XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078;
return No_exp;
}
/* Check an access to a register. */
static unsigned
check_cp15_access (ARMul_State * state,
unsigned reg,
unsigned CRm, unsigned opcode_1, unsigned opcode_2)
{
/* Do not allow access to these register in USER mode. */
//chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
if (state->Mode == USER26MODE || state->Mode == USER32MODE )
return ARMul_CANT;
/* Opcode_1should be zero. */
if (opcode_1 != 0)
return ARMul_CANT;
/* Different register have different access requirements. */
switch (reg) {
case 0:
case 1:
/* CRm must be 0. Opcode_2 can be anything. */
if (CRm != 0)
return ARMul_CANT;
break;
case 2:
case 3:
/* CRm must be 0. Opcode_2 must be zero. */
if ((CRm != 0) || (opcode_2 != 0))
return ARMul_CANT;
break;
case 4:
/* Access not allowed. */
return ARMul_CANT;
case 5:
case 6:
/* Opcode_2 must be zero. CRm must be 0. */
if ((CRm != 0) || (opcode_2 != 0))
return ARMul_CANT;
break;
case 7:
/* Permissable combinations:
Opcode_2 CRm
0 5
0 6
0 7
1 5
1 6
1 10
4 10
5 2
6 5 */
switch (opcode_2) {
default:
return ARMul_CANT;
case 6:
if (CRm != 5)
return ARMul_CANT;
break;
case 5:
if (CRm != 2)
return ARMul_CANT;
break;
case 4:
if (CRm != 10)
return ARMul_CANT;
break;
case 1:
if ((CRm != 5) && (CRm != 6) && (CRm != 10))
return ARMul_CANT;
break;
case 0:
if ((CRm < 5) || (CRm > 7))
return ARMul_CANT;
break;
}
break;
case 8:
/* Permissable combinations:
Opcode_2 CRm
0 5
0 6
0 7
1 5
1 6 */
if (opcode_2 > 1)
return ARMul_CANT;
if ((CRm < 5) || (CRm > 7))
return ARMul_CANT;
if (opcode_2 == 1 && CRm == 7)
return ARMul_CANT;
break;
case 9:
/* Opcode_2 must be zero or one. CRm must be 1 or 2. */
if (((CRm != 0) && (CRm != 1))
|| ((opcode_2 != 1) && (opcode_2 != 2)))
return ARMul_CANT;
break;
case 10:
/* Opcode_2 must be zero or one. CRm must be 4 or 8. */
if (((CRm != 0) && (CRm != 1))
|| ((opcode_2 != 4) && (opcode_2 != 8)))
return ARMul_CANT;
break;
case 11:
/* Access not allowed. */
return ARMul_CANT;
case 12:
/* Access not allowed. */
return ARMul_CANT;
case 13:
/* Opcode_2 must be zero. CRm must be 0. */
if ((CRm != 0) || (opcode_2 != 0))
return ARMul_CANT;
break;
case 14:
/* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */
if (opcode_2 != 0)
return ARMul_CANT;
if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8)
&& (CRm != 9))
return ARMul_CANT;
break;
case 15:
/* Opcode_2 must be zero. CRm must be 1. */
if ((CRm != 1) || (opcode_2 != 0))
return ARMul_CANT;
break;
default:
/* Should never happen. */
return ARMul_CANT;
}
return ARMul_DONE;
}
/* Coprocessor 13: Interrupt Controller and Bus Controller. */
/* There are two sets of registers for copro 13.
One set (of three registers) is available when CRm is 0
and the other set (of six registers) when CRm is 1. */
static ARMword XScale_cp13_CR0_Regs[16];
static ARMword XScale_cp13_CR1_Regs[16];
static unsigned
XScale_cp13_init (ARMul_State * state)
{
int i;
for (i = 16; i--;) {
XScale_cp13_CR0_Regs[i] = 0;
XScale_cp13_CR1_Regs[i] = 0;
}
return No_exp;
}
/* Check an access to a register. */
static unsigned
check_cp13_access (ARMul_State * state,
unsigned reg,
unsigned CRm, unsigned opcode_1, unsigned opcode_2)
{
/* Do not allow access to these registers in USER mode. */
//chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
if (state->Mode == USER26MODE || state->Mode == USER32MODE )
return ARMul_CANT;
/* The opcodes should be zero. */
if ((opcode_1 != 0) || (opcode_2 != 0))
return ARMul_CANT;
/* Do not allow access to these register if bit
13 of coprocessor 15's register 15 is zero. */
if (!CP_ACCESS_ALLOWED (state, 13))
return ARMul_CANT;
/* Registers 0, 4 and 8 are defined when CRm == 0.
Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1.
For all other CRm values undefined behaviour results. */
if (CRm == 0) {
if (reg == 0 || reg == 4 || reg == 8)
return ARMul_DONE;
}
else if (CRm == 1) {
if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8))
return ARMul_DONE;
}
return ARMul_CANT;
}
/* Coprocessor 14: Performance Monitoring, Clock and Power management,
Software Debug. */
static ARMword XScale_cp14_Regs[16];
static unsigned
XScale_cp14_init (ARMul_State * state)
{
int i;
for (i = 16; i--;)
XScale_cp14_Regs[i] = 0;
return No_exp;
}
/* Check an access to a register. */
static unsigned
check_cp14_access (ARMul_State * state,
unsigned reg,
unsigned CRm, unsigned opcode1, unsigned opcode2)
{
/* Not allowed to access these register in USER mode. */
//chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
if (state->Mode == USER26MODE || state->Mode == USER32MODE )
return ARMul_CANT;
/* CRm should be zero. */
if (CRm != 0)
return ARMul_CANT;
/* OPcodes should be zero. */
if (opcode1 != 0 || opcode2 != 0)
return ARMul_CANT;
/* Accessing registers 4 or 5 has unpredicatable results. */
if (reg >= 4 && reg <= 5)
return ARMul_CANT;
return ARMul_DONE;
}
/* Here's ARMulator's MMU definition. A few things to note:
1) It has eight registers, but only two are defined.
2) You can only access its registers with MCR and MRC.
3) MMU Register 0 (ID) returns 0x41440110
4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4
controls 32/26 bit program space, bit 5 controls 32/26 bit data space,
bit 6 controls late abort timimg and bit 7 controls big/little endian. */
static ARMword MMUReg[8];
static unsigned
MMUInit (ARMul_State * state)
{
/* 2004-05-09 chy
-------------------------------------------------------------
read ARM Architecture Reference Manual
2.6.5 Data Abort
There are three Abort Model in ARM arch.
Early Abort Model: used in some ARMv3 and earlier implementations. In this
model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and
the base register was unchanged for all other instructions. (oldest)
Base Restored Abort Model: If a Data Abort occurs in an instruction which
specifies base register writeback, the value in the base register is
unchanged. (strongarm, xscale)
Base Updated Abort Model: If a Data Abort occurs in an instruction which
specifies base register writeback, the base register writeback still occurs.
(arm720T)
read PART B
chap2 The System Control Coprocessor CP15
2.4 Register1:control register
L(bit 6): in some ARMv3 and earlier implementations, the abort model of the
processor could be configured:
0=early Abort Model Selected(now obsolete)
1=Late Abort Model selceted(same as Base Updated Abort Model)
on later processors, this bit reads as 1 and ignores writes.
-------------------------------------------------------------
So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
if lateabtSig=0, then it means Base Restored Abort Model
because the ARMs which skyeye simulates are all belonged to ARMv4,
so I think MMUReg[1]'s bit 6 should always be 1
*/
MMUReg[1] = state->prog32Sig << 4 |
state->data32Sig << 5 | 1 << 6 | state->bigendSig << 7;
//state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7;
NOTICE_LOG(ARM11, "ARMul_ConsolePrint: MMU present");
return TRUE;
}
static unsigned
MMUMRC (ARMul_State * state, unsigned type,
ARMword instr, ARMword * value)
{
mmu_mrc (state, instr, value);
return (ARMul_DONE);
}
static unsigned
MMUMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
{
mmu_mcr (state, instr, value);
return (ARMul_DONE);
}
/* What follows is the Validation Suite Coprocessor. It uses two
co-processor numbers (4 and 5) and has the follwing functionality.
Sixteen registers. Both co-processor nuimbers can be used in an MCR
and MRC to access these registers. CP 4 can LDC and STC to and from
the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of
cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a
number of cycles (specified in a CP register), CDP 2 issues an IRQW
in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5
stores a 32 bit time value in a CP register (actually it's the total
number of N, S, I, C and F cyles). */
static ARMword ValReg[16];
static unsigned
ValLDC (ARMul_State * state,
unsigned type, ARMword instr, ARMword data)
{
static unsigned words;
if (type != ARMul_DATA)
words = 0;
else {
ValReg[BITS (12, 15)] = data;
if (BIT (22))
/* It's a long access, get two words. */
if (words++ != 4)
return ARMul_INC;
}
return ARMul_DONE;
}
static unsigned
ValSTC (ARMul_State * state,
unsigned type, ARMword instr, ARMword * data)
{
static unsigned words;
if (type != ARMul_DATA)
words = 0;
else {
*data = ValReg[BITS (12, 15)];
if (BIT (22))
/* It's a long access, get two words. */
if (words++ != 4)
return ARMul_INC;
}
return ARMul_DONE;
}
static unsigned
ValMRC (ARMul_State * state,
unsigned type, ARMword instr, ARMword * value)
{
*value = ValReg[BITS (16, 19)];
return ARMul_DONE;
}
static unsigned
ValMCR (ARMul_State * state,
unsigned type, ARMword instr, ARMword value)
{
ValReg[BITS (16, 19)] = value;
return ARMul_DONE;
}
static unsigned
ValCDP (ARMul_State * state, unsigned type, ARMword instr)
{
static unsigned int finish = 0;
if (BITS (20, 23) != 0)
return ARMul_CANT;
if (type == ARMul_FIRST) {
ARMword howlong;
howlong = ValReg[BITS (0, 3)];
/* First cycle of a busy wait. */
finish = ARMul_Time (state) + howlong;
return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
}
else if (type == ARMul_BUSY) {
if (ARMul_Time (state) >= finish)
return ARMul_DONE;
else
return ARMul_BUSY;
}
return ARMul_CANT;
}
static unsigned
DoAFIQ (ARMul_State * state)
{
state->NfiqSig = LOW;
return 0;
}
static unsigned
DoAIRQ (ARMul_State * state)
{
state->NirqSig = LOW;
return 0;
}
static unsigned
IntCDP (ARMul_State * state, unsigned type, ARMword instr)
{
static unsigned int finish;
ARMword howlong;
howlong = ValReg[BITS (0, 3)];
switch ((int) BITS (20, 23)) {
case 0:
if (type == ARMul_FIRST) {
/* First cycle of a busy wait. */
finish = ARMul_Time (state) + howlong;
return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
}
else if (type == ARMul_BUSY) {
if (ARMul_Time (state) >= finish)
return ARMul_DONE;
else
return ARMul_BUSY;
}
return ARMul_DONE;
case 1:
if (howlong == 0)
ARMul_Abort (state, ARMul_FIQV);
else
ARMul_ScheduleEvent (state, howlong, DoAFIQ);
return ARMul_DONE;
case 2:
if (howlong == 0)
ARMul_Abort (state, ARMul_IRQV);
else
ARMul_ScheduleEvent (state, howlong, DoAIRQ);
return ARMul_DONE;
case 3:
state->NfiqSig = HIGH;
return ARMul_DONE;
case 4:
state->NirqSig = HIGH;
return ARMul_DONE;
case 5:
ValReg[BITS (0, 3)] = ARMul_Time (state);
return ARMul_DONE;
}
return ARMul_CANT;
}
/* Install co-processor instruction handlers in this routine. */
unsigned
ARMul_CoProInit (ARMul_State * state)
{
unsigned int i;
/* Initialise tham all first. */
for (i = 0; i < 16; i++)
ARMul_CoProDetach (state, i);
/* Install CoPro Instruction handlers here.
The format is:
ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
LDC routine, STC routine, MRC routine, MCR routine,
CDP routine, Read Reg routine, Write Reg routine). */
if (state->is_ep9312) {
ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4,
DSPMRC4, DSPMCR4, NULL, NULL, DSPCDP4, NULL, NULL);
ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5,
DSPMRC5, DSPMCR5, NULL, NULL, DSPCDP5, NULL, NULL);
ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL,
DSPMRC6, DSPMCR6, NULL, NULL, DSPCDP6, NULL, NULL);
}
else {
ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC,
ValMRC, ValMCR, NULL, NULL, ValCDP, NULL, NULL);
ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL,
ValMRC, ValMCR, NULL, NULL, IntCDP, NULL, NULL);
}
if (state->is_XScale) {
//chy 2005-09-19, for PXA27x's CP6
if (state->is_pxa27x) {
ARMul_CoProAttach (state, 6, NULL, NULL,
NULL, NULL, xscale_cp6_mrc,
NULL, NULL, NULL, NULL, NULL, NULL);
}
//chy 2005-09-19 end-------------
ARMul_CoProAttach (state, 13, xscale_cp13_init,
xscale_cp13_exit, xscale_cp13_ldc,
xscale_cp13_stc, xscale_cp13_mrc,
xscale_cp13_mcr, NULL, NULL, xscale_cp13_cdp,
xscale_cp13_read_reg,
xscale_cp13_write_reg);
ARMul_CoProAttach (state, 14, xscale_cp14_init,
xscale_cp14_exit, xscale_cp14_ldc,
xscale_cp14_stc, xscale_cp14_mrc,
xscale_cp14_mcr, NULL, NULL, xscale_cp14_cdp,
xscale_cp14_read_reg,
xscale_cp14_write_reg);
//chy: 2003-08-24.
ARMul_CoProAttach (state, 15, xscale_cp15_init,
xscale_cp15_exit, xscale_cp15_ldc,
xscale_cp15_stc, xscale_cp15_mrc,
xscale_cp15_mcr, NULL, NULL, xscale_cp15_cdp,
xscale_cp15_read_reg,
xscale_cp15_write_reg);
}
else if (state->is_v6) {
ARMul_CoProAttach (state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
ARMul_CoProAttach (state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);
}
else { //all except xscale
ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
// MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);
}
//chy 2003-09-03 do it in future!!!!????
#if 0
if (state->is_iWMMXt) {
ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC,
NULL, NULL, IwmmxtCDP, NULL, NULL);
ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL,
IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL,
NULL);
}
#endif
//-----------------------------------------------------------------------------
//chy 2004-05-25, found the user/system code visit CP 1,2, so I add below code.
ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL,
ValMRC, ValMCR, NULL, NULL, NULL, NULL, NULL);
ARMul_CoProAttach (state, 2, NULL, NULL, ValLDC, ValSTC,
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
//------------------------------------------------------------------------------
/* No handlers below here. */
/* Call all the initialisation routines. */
for (i = 0; i < 16; i++)
if (state->CPInit[i])
(state->CPInit[i]) (state);
return TRUE;
}
/* Install co-processor finalisation routines in this routine. */
void
ARMul_CoProExit (ARMul_State * state)
{
register unsigned i;
for (i = 0; i < 16; i++)
if (state->CPExit[i])
(state->CPExit[i]) (state);
for (i = 0; i < 16; i++) /* Detach all handlers. */
ARMul_CoProDetach (state, i);
}
/* Routines to hook Co-processors into ARMulator. */
void
ARMul_CoProAttach (ARMul_State * state,
unsigned number,
ARMul_CPInits * init,
ARMul_CPExits * exit,
ARMul_LDCs * ldc,
ARMul_STCs * stc,
ARMul_MRCs * mrc,
ARMul_MCRs * mcr,
ARMul_MRRCs * mrrc,
ARMul_MCRRs * mcrr,
ARMul_CDPs * cdp,
ARMul_CPReads * read, ARMul_CPWrites * write)
{
if (init != NULL)
state->CPInit[number] = init;
if (exit != NULL)
state->CPExit[number] = exit;
if (ldc != NULL)
state->LDC[number] = ldc;
if (stc != NULL)
state->STC[number] = stc;
if (mrc != NULL)
state->MRC[number] = mrc;
if (mcr != NULL)
state->MCR[number] = mcr;
if (mrrc != NULL)
state->MRRC[number] = mrrc;
if (mcrr != NULL)
state->MCRR[number] = mcrr;
if (cdp != NULL)
state->CDP[number] = cdp;
if (read != NULL)
state->CPRead[number] = read;
if (write != NULL)
state->CPWrite[number] = write;
}
void
ARMul_CoProDetach (ARMul_State * state, unsigned number)
{
ARMul_CoProAttach (state, number, NULL, NULL,
NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL);
state->CPInit[number] = NULL;
state->CPExit[number] = NULL;
state->CPRead[number] = NULL;
state->CPWrite[number] = NULL;
}
//chy 2003-09-03:below funs just replace the old ones
/* Set the XScale FSR and FAR registers. */
void
XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far)
{
//if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0)
if (!state->is_XScale)
return;
//assume opcode2=0 crm =0
xscale_cp15_write_reg (state, 5, fsr);
xscale_cp15_write_reg (state, 6, _far);
}
//chy 2003-09-03 seems 0 is CANT, 1 is DONE ????
int
XScale_debug_moe (ARMul_State * state, int moe)
{
//chy 2003-09-03 , W/R CP14 reg, now it's no use ????
printf ("SKYEYE: XScale_debug_moe called !!!!\n");
return 1;
}

View file

@ -23,17 +23,6 @@
#include "armemu.h"
#include "armos.h"
void
XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword _far)
{
_dbg_assert_msg_(ARM11, false, "ImplementMe: XScale_set_fsr_far!");
//if (!state->is_XScale || (read_cp14_reg(10) & (1UL << 31)) == 0)
// return;
//
//write_cp15_reg(state, 5, 0, 0, fsr);
//write_cp15_reg(state, 6, 0, 0, _far);
}
#define ARMul_Debug(x,y,z) 0 // Disabling this /bunnei
//#include "skyeye_callback.h"

View file

@ -17,9 +17,9 @@
#ifndef __ARMEMU_H__
#define __ARMEMU_H__
#include "common/common.h"
#include "armdefs.h"
//#include "skyeye.h"
#include "core/arm/interpreter/skyeye_defs.h"
#include "core/arm/interpreter/armdefs.h"
extern ARMword isize;
@ -73,9 +73,7 @@ extern ARMword isize;
#define ASSIGNT(res) state->TFlag = res
#define INSN_SIZE (TFLAG ? 2 : 4)
#else
#define TBIT (1L << 5)
#define INSN_SIZE 4
#define TFLAG 0
#endif
/*add armv6 CPSR feature*/
@ -166,6 +164,7 @@ extern ARMword isize;
#define PCWRAP(pc) ((pc) & R15PCBITS)
#endif
#define PC (state->Reg[15] & PCMASK)
#define R15CCINTMODE (state->Reg[15] & (CCBITS | R15INTBITS | R15MODEBITS))
#define R15INT (state->Reg[15] & R15INTBITS)
#define R15INTPC (state->Reg[15] & (R15INTBITS | R15PCBITS))
@ -180,11 +179,11 @@ extern ARMword isize;
#define ER15INT (IFFLAGS << 26)
#define EMODE (state->Mode)
//#ifdef MODET
//#define CPSR (ECC | EINT | EMODE | (TFLAG << 5))
//#else
//#define CPSR (ECC | EINT | EMODE)
//#endif
#ifdef MODET
#define CPSR (ECC | EINT | EMODE | (TFLAG << 5))
#else
#define CPSR (ECC | EINT | EMODE)
#endif
#ifdef MODE32
#define PATCHR15
@ -240,12 +239,12 @@ extern ARMword isize;
} \
while (0)
//#ifndef MODE32
#ifndef MODE32
#define VECTORS 0x20
#define LEGALADDR 0x03ffffff
#define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig)
#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig)
//#endif
#endif
#define INTERNALABORT(address) \
do \
@ -420,12 +419,10 @@ extern ARMword isize;
|| (! (STATE)->is_XScale) \
|| (read_cp15_reg (15, 0, 1) & (1 << (CP))))
*/
//#define CP_ACCESS_ALLOWED(STATE, CP) \
// (((CP) >= 14) \
// || (!(STATE)->is_XScale) \
// || (xscale_cp15_cp_access_allowed(STATE, 15, CP)))
#define CP_ACCESS_ALLOWED(STATE, CP) false // Disabled coprocessor shit /bunnei
#define CP_ACCESS_ALLOWED(STATE, CP) \
( ((CP) >= 14) \
|| (! (STATE)->is_XScale) \
|| (xscale_cp15_cp_access_allowed(STATE,15,CP)))
/* Macro to rotate n right by b bits. */
#define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b))))
@ -517,7 +514,7 @@ tdstate;
* out-of-updated with the newer ISA.
* -- Michael.Kang
********************************************************************************/
#define UNDEF_WARNING ERROR_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n");
#define UNDEF_WARNING WARN_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n");
/* Macros to scrutinize instructions. */
#define UNDEF_Test UNDEF_WARNING

View file

@ -23,8 +23,8 @@
#include <math.h>
#include "armdefs.h"
#include "armemu.h"
#include "core/arm/interpreter/armdefs.h"
#include "core/arm/interpreter/armemu.h"
/***************************************************************************\
* Definitions for the emulator architecture *
@ -271,7 +271,7 @@ below line sould be in skyeye_mach_XXX.c 's XXX_mach_init function
/* Only initialse the coprocessor support once we
know what kind of chip we are dealing with. */
//ARMul_CoProInit (state); Commented out /bunnei
ARMul_CoProInit (state);
}
@ -318,7 +318,7 @@ ARMul_Reset (ARMul_State * state)
state->NumFcycles = 0;
//fprintf(stderr,"armul_reset 3: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode);
//mmu_reset (state); Commented out /bunnei
mmu_reset (state);
//fprintf(stderr,"armul_reset 4: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode);
//mem_reset (state); /* move to memory/ram.c */

View file

@ -172,18 +172,18 @@ typedef struct mmu_ops_s
} mmu_ops_t;
#include "core/arm/mmu/tlb.h"
#include "core/arm/mmu/rb.h"
#include "core/arm/mmu/wb.h"
#include "core/arm/mmu/cache.h"
#include "core/arm/interpreter/mmu/tlb.h"
#include "core/arm/interpreter/mmu/rb.h"
#include "core/arm/interpreter/mmu/wb.h"
#include "core/arm/interpreter/mmu/cache.h"
/*special process mmu.h*/
//#include "core/arm/mmu/sa_mmu.h"
//#include "core/arm/mmu/arm7100_mmu.h"
//#include "core/arm/mmu/arm920t_mmu.h"
//#include "core/arm/mmu/arm926ejs_mmu.h"
#include "core/arm/mmu/arm1176jzf_s_mmu.h"
//#include "core/arm/mmu/cortex_a9_mmu.h"
#include "core/arm/interpreter/mmu/sa_mmu.h"
//#include "core/arm/interpreter/mmu/arm7100_mmu.h"
//#include "core/arm/interpreter/mmu/arm920t_mmu.h"
//#include "core/arm/interpreter/mmu/arm926ejs_mmu.h"
#include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h"
//#include "core/arm/interpreter/mmu/cortex_a9_mmu.h"
typedef struct mmu_state_t
{
@ -213,13 +213,13 @@ typedef struct mmu_state_t
ARMword copro_access; // 15
mmu_ops_t ops;
//union
//{
//sa_mmu_t sa_mmu;
union
{
sa_mmu_t sa_mmu;
//arm7100_mmu_t arm7100_mmu;
//arm920t_mmu_t arm920t_mmu;
//arm926ejs_mmu_t arm926ejs_mmu;
//} u;
} u;
} mmu_state_t;
int mmu_init (ARMul_State * state);

View file

@ -15,11 +15,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "armdefs.h"
#include "armemu.h"
//#include "ansidecl.h"
#include "skyeye_defs.h"
#include "core/arm/interpreter/armdefs.h"
#include "core/arm/interpreter/armemu.h"
#include "core/arm/interpreter/skyeye_defs.h"
#include "core/hle/coprocessor.h"
#include "core/arm/disassembler/arm_disasm.h"
@ -127,8 +125,7 @@ ARMul_GetCPSR (ARMul_State * state)
{
//chy 2003-08-20: below is from gdb20030716, maybe isn't suitable for system simulator
//return (CPSR | state->Cpsr); for gdb20030716
// NOTE(bunnei): Changed this from [now] commented out macro "CPSR"
return ((ECC | EINT | EMODE | (TFLAG << 5))); //had be tested in old skyeye with gdb5.0-5.3
return (CPSR); //had be tested in old skyeye with gdb5.0-5.3
}
/* This routine sets the value of the CPSR. */
@ -145,7 +142,7 @@ ARMul_SetCPSR (ARMul_State * state, ARMword value)
void
ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
{
{
state->Cpsr = ARMul_GetCPSR (state);
//chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
if (state->Mode != USER26MODE && state->Mode != USER32MODE ) {
@ -500,8 +497,8 @@ ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
return;
}
if (ADDREXCEPT (address))
INTERNALABORT (address);
//if (ADDREXCEPT (address))
// INTERNALABORT (address);
cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
while (cpab == ARMul_BUSY) {
@ -594,8 +591,8 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
return;
}
if (ADDREXCEPT (address) || VECTORACCESS (address))
INTERNALABORT (address);
//if (ADDREXCEPT (address) || VECTORACCESS (address))
// INTERNALABORT (address);
cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
while (cpab == ARMul_BUSY) {
@ -661,40 +658,39 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
void
ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
{
HLE::CallMCR(instr, source);
//unsigned cpab;
unsigned cpab;
////printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source);
//if (!CP_ACCESS_ALLOWED (state, CPNum)) {
// //chy 2004-07-19 should fix in the future ????!!!!
// //printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source);
// ARMul_UndefInstr (state, instr);
// return;
//}
//printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source);
if (!CP_ACCESS_ALLOWED (state, CPNum)) {
//chy 2004-07-19 should fix in the future ????!!!!
//printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source);
ARMul_UndefInstr (state, instr);
return;
}
//cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
//while (cpab == ARMul_BUSY) {
// ARMul_Icycles (state, 1, 0);
while (cpab == ARMul_BUSY) {
ARMul_Icycles (state, 1, 0);
// if (IntPending (state)) {
// cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT,
// instr, 0);
// return;
// }
// else
// cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr,
// source);
//}
if (IntPending (state)) {
cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT,
instr, 0);
return;
}
else
cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr,
source);
}
//if (cpab == ARMul_CANT) {
// printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source);
// ARMul_Abort (state, ARMul_UndefinedInstrV);
//}
//else {
// BUSUSEDINCPCN;
// ARMul_Ccycles (state, 1, 0);
//}
if (cpab == ARMul_CANT) {
printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source);
ARMul_Abort (state, ARMul_UndefinedInstrV);
}
else {
BUSUSEDINCPCN;
ARMul_Ccycles (state, 1, 0);
}
}
/* This function does the Busy-Waiting for an MCRR instruction. */
@ -742,37 +738,41 @@ ARMul_MRC (ARMul_State * state, ARMword instr)
ARMword result = HLE::CallMRC(instr);
////printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr);
//if (!CP_ACCESS_ALLOWED (state, CPNum)) {
// //chy 2004-07-19 should fix in the future????!!!!
// //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr);
// ARMul_UndefInstr (state, instr);
// return -1;
//}
if (result != -1) {
return result;
}
//cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
//while (cpab == ARMul_BUSY) {
// ARMul_Icycles (state, 1, 0);
// if (IntPending (state)) {
// cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT,
// instr, 0);
// return (0);
// }
// else
// cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr,
// &result);
//}
//if (cpab == ARMul_CANT) {
// printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr);
// ARMul_Abort (state, ARMul_UndefinedInstrV);
// /* Parent will destroy the flags otherwise. */
// result = ECC;
//}
//else {
// BUSUSEDINCPCN;
// ARMul_Ccycles (state, 1, 0);
// ARMul_Icycles (state, 1, 0);
//}
//printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr);
if (!CP_ACCESS_ALLOWED (state, CPNum)) {
//chy 2004-07-19 should fix in the future????!!!!
//printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr);
ARMul_UndefInstr (state, instr);
return -1;
}
cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
while (cpab == ARMul_BUSY) {
ARMul_Icycles (state, 1, 0);
if (IntPending (state)) {
cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT,
instr, 0);
return (0);
}
else
cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr,
&result);
}
if (cpab == ARMul_CANT) {
printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr);
ARMul_Abort (state, ARMul_UndefinedInstrV);
/* Parent will destroy the flags otherwise. */
result = ECC;
}
else {
BUSUSEDINCPCN;
ARMul_Ccycles (state, 1, 0);
ARMul_Icycles (state, 1, 0);
}
return result;
}
@ -907,9 +907,7 @@ ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay,
state->Now = ARMul_Time (state);
when = (state->Now + delay) % EVENTLISTSIZE;
event = (struct EventNode *) malloc (sizeof (struct EventNode));
_dbg_assert_msg_(ARM11, event, "SKYEYE:ARMul_ScheduleEvent: malloc event error\n");
event->func = what;
event->next = *(state->EventPtr + when);
*(state->EventPtr + when) = event;

View file

@ -0,0 +1,370 @@
#include "core/arm/interpreter/armdefs.h"
/* mmu cache init
*
* @cache_t :cache_t to init
* @width :cache line width in byte
* @way :way of each cache set
* @set :cache set num
*
* $ -1: error
* 0: sucess
*/
int
mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode)
{
int i, j;
cache_set_t *sets;
cache_line_t *lines;
/*alloc cache set */
sets = NULL;
lines = NULL;
//fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets);
//exit(-1);
sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set);
if (sets == NULL) {
ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set);
goto sets_error;
}
//fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets);
cache_t->sets = sets;
/*init cache set */
for (i = 0; i < set; i++) {
/*alloc cache line */
lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way);
if (lines == NULL) {
ERROR_LOG(ARM11, "line malloc size %d\n",
sizeof (cache_line_t) * way);
goto lines_error;
}
/*init cache line */
for (j = 0; j < way; j++) {
lines[j].tag = 0; //invalid
lines[j].data = (ARMword *) malloc (width);
if (lines[j].data == NULL) {
ERROR_LOG(ARM11, "data alloc size %d\n", width);
goto data_error;
}
}
sets[i].lines = lines;
sets[i].cycle = 0;
}
cache_t->width = width;
cache_t->set = set;
cache_t->way = way;
cache_t->w_mode = w_mode;
return 0;
data_error:
/*free data */
while (j-- > 0)
free (lines[j].data);
/*free data error line */
free (lines);
lines_error:
/*free lines already alloced */
while (i-- > 0) {
for (j = 0; j < way; j++)
free (sets[i].lines[j].data);
free (sets[i].lines);
}
/*free sets */
free (sets);
sets_error:
return -1;
};
/* free a cache_t's inner data, the ptr self is not freed,
* when needed do like below:
* mmu_cache_exit(cache);
* free(cache_t);
*
* @cache_t : the cache_t to free
*/
void
mmu_cache_exit (cache_s * cache_t)
{
int i, j;
cache_set_t *sets, *set;
cache_line_t *lines, *line;
/*free all set */
sets = cache_t->sets;
for (set = sets, i = 0; i < cache_t->set; i++, set++) {
/*free all line */
lines = set->lines;
for (line = lines, j = 0; j < cache_t->way; j++, line++)
free (line->data);
free (lines);
}
free (sets);
}
/* mmu cache search
*
* @state :ARMul_State
* @cache_t :cache_t to search
* @va :virtual address
*
* $ NULL: no cache match
* cache :cache matched
*/
cache_line_t *
mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va)
{
int i;
int set = va_cache_set (va, cache_t);
ARMword tag = va_cache_align (va, cache_t);
cache_line_t *cache;
cache_set_t *cache_set = cache_t->sets + set;
for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) {
if ((cache->tag & TAG_VALID_FLAG)
&& (tag == va_cache_align (cache->tag, cache_t)))
return cache;
}
return NULL;
}
/* mmu cache search by set/index
*
* @state :ARMul_State
* @cache_t :cache_t to search
* @index :set/index value.
*
* $ NULL: no cache match
* cache :cache matched
*/
cache_line_t *
mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t,
ARMword index)
{
int way = cache_t->way;
int set_v = index_cache_set (index, cache_t);
int i = 0, index_v = 0;
cache_set_t *set;
while ((way >>= 1) >= 1)
i++;
index_v = index >> (32 - i);
set = cache_t->sets + set_v;
return set->lines + index_v;
}
/* mmu cache alloc
*
* @state :ARMul_State
* @cache_t :cache_t to alloc from
* @va :virtual address that require cache alloc, need not cache aligned
* @pa :physical address of va
*
* $ cache_alloced, always alloc OK
*/
cache_line_t *
mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va,
ARMword pa)
{
cache_line_t *cache;
cache_set_t *set;
int i;
va = va_cache_align (va, cache_t);
pa = va_cache_align (pa, cache_t);
set = &cache_t->sets[va_cache_set (va, cache_t)];
/*robin-round */
cache = &set->lines[set->cycle++];
if (set->cycle == cache_t->way)
set->cycle = 0;
if (cache_t->w_mode == CACHE_WRITE_BACK) {
ARMword t;
/*if cache valid, try to write back */
if (cache->tag & TAG_VALID_FLAG) {
mmu_cache_write_back (state, cache_t, cache);
}
/*read in cache_line */
t = pa;
for (i = 0; i < (cache_t->width >> WORD_SHT);
i++, t += WORD_SIZE) {
//cache->data[i] = mem_read_word (state, t);
bus_read(32, t, &cache->data[i]);
}
}
/*store tag and pa */
cache->tag = va | TAG_VALID_FLAG;
cache->pa = pa;
return cache;
};
/* mmu_cache_write_back write cache data to memory
* @state
* @cache_t :cache_t of the cache line
* @cache : cache line
*/
void
mmu_cache_write_back (ARMul_State * state, cache_s * cache_t,
cache_line_t * cache)
{
ARMword pa = cache->pa;
int nw = cache_t->width >> WORD_SHT;
ARMword *data = cache->data;
int i;
int t0, t1, t2;
if ((cache->tag & 1) == 0)
return;
switch (cache->
tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) {
case 0:
return;
case TAG_FIRST_HALF_DIRTY:
nw /= 2;
break;
case TAG_LAST_HALF_DIRTY:
nw /= 2;
pa += nw << WORD_SHT;
data += nw;
break;
case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY:
break;
}
for (i = 0; i < nw; i++, data++, pa += WORD_SIZE)
//mem_write_word (state, pa, *data);
bus_write(32, pa, *data);
cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY);
};
/* mmu_cache_clean: clean a cache of va in cache_t
*
* @state :ARMul_State
* @cache_t :cache_t to clean
* @va :virtaul address
*/
void
mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va)
{
cache_line_t *cache;
cache = mmu_cache_search (state, cache_t, va);
if (cache)
mmu_cache_write_back (state, cache_t, cache);
}
/* mmu_cache_clean_by_index: clean a cache by set/index format value
*
* @state :ARMul_State
* @cache_t :cache_t to clean
* @va :set/index format value
*/
void
mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t,
ARMword index)
{
cache_line_t *cache;
cache = mmu_cache_search_by_index (state, cache_t, index);
if (cache)
mmu_cache_write_back (state, cache_t, cache);
}
/* mmu_cache_invalidate : invalidate a cache of va
*
* @state :ARMul_State
* @cache_t :cache_t to invalid
* @va :virt_addr to invalid
*/
void
mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va)
{
cache_line_t *cache;
cache = mmu_cache_search (state, cache_t, va);
if (cache) {
mmu_cache_write_back (state, cache_t, cache);
cache->tag = 0;
}
}
/* mmu_cache_invalidate_by_index : invalidate a cache by index format
*
* @state :ARMul_State
* @cache_t :cache_t to invalid
* @index :set/index data
*/
void
mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t,
ARMword index)
{
cache_line_t *cache;
cache = mmu_cache_search_by_index (state, cache_t, index);
if (cache) {
mmu_cache_write_back (state, cache_t, cache);
cache->tag = 0;
}
}
/* mmu_cache_invalidate_all
*
* @state:
* @cache_t
* */
void
mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t)
{
int i, j;
cache_set_t *set;
cache_line_t *cache;
set = cache_t->sets;
for (i = 0; i < cache_t->set; i++, set++) {
cache = set->lines;
for (j = 0; j < cache_t->way; j++, cache++) {
mmu_cache_write_back (state, cache_t, cache);
cache->tag = 0;
}
}
};
void
mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa)
{
ARMword set, way;
cache_line_t *cache;
pa = (pa / cache_t->width);
way = pa & (cache_t->way - 1);
set = (pa / cache_t->way) & (cache_t->set - 1);
cache = &cache_t->sets[set].lines[way];
mmu_cache_write_back (state, cache_t, cache);
cache->tag = 0;
}
cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){
int i;
int j;
cache_line_t *cache_line = NULL;
cache_set_t *cache_set = cache->sets;
int sets = cache->set;
for (i = 0; i < sets; i++){
for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){
if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY))
return cache_line;
}
}
return NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,126 @@
#include "core/arm/interpreter/armdefs.h"
/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/
ARMword rb_masks[] = {
0x0, //RB_INVALID
4, //RB_1
16, //RB_4
32, //RB_8
};
/*mmu_rb_init
* @rb_t :rb_t to init
* @num :number of entry
* */
int
mmu_rb_init (rb_s * rb_t, int num)
{
int i;
rb_entry_t *entrys;
entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num);
if (entrys == NULL) {
printf ("SKYEYE:mmu_rb_init malloc error\n");
return -1;
}
for (i = 0; i < num; i++) {
entrys[i].type = RB_INVALID;
entrys[i].fault = NO_FAULT;
}
rb_t->entrys = entrys;
rb_t->num = num;
return 0;
}
/*mmu_rb_exit*/
void
mmu_rb_exit (rb_s * rb_t)
{
free (rb_t->entrys);
};
/*mmu_rb_search
* @rb_t :rb_t to serach
* @va :va address to math
*
* $ NULL :not match
* NO-NULL:
* */
rb_entry_t *
mmu_rb_search (rb_s * rb_t, ARMword va)
{
int i;
rb_entry_t *rb = rb_t->entrys;
DEBUG_LOG(ARM11, "va = %x\n", va);
for (i = 0; i < rb_t->num; i++, rb++) {
//2004-06-06 lyh bug from wenye@cs.ucsb.edu
if (rb->type) {
if ((va >= rb->va)
&& (va < (rb->va + rb_masks[rb->type])))
return rb;
}
}
return NULL;
};
void
mmu_rb_invalidate_entry (rb_s * rb_t, int i)
{
rb_t->entrys[i].type = RB_INVALID;
}
void
mmu_rb_invalidate_all (rb_s * rb_t)
{
int i;
for (i = 0; i < rb_t->num; i++)
mmu_rb_invalidate_entry (rb_t, i);
};
void
mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va)
{
rb_entry_t *rb;
int i;
ARMword max_start, min_end;
fault_t fault;
tlb_entry_t *tlb;
/*align va according to type */
va &= ~(rb_masks[type] - 1);
/*invalidate all RB match [va, va + rb_masks[type]] */
for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) {
if (rb->type) {
max_start = max (va, rb->va);
min_end =
min (va + rb_masks[type],
rb->va + rb_masks[rb->type]);
if (max_start < min_end)
rb->type = RB_INVALID;
}
}
/*load word */
rb = &rb_t->entrys[i_rb];
rb->type = type;
fault = translate (state, va, D_TLB (), &tlb);
if (fault) {
rb->fault = fault;
return;
}
fault = check_access (state, va, tlb, 1);
if (fault) {
rb->fault = fault;
return;
}
rb->fault = NO_FAULT;
va = tlb_va_to_pa (tlb, va);
//2004-06-06 lyh bug from wenye@cs.ucsb.edu
for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) {
//rb->data[i] = mem_read_word (state, va);
bus_read(32, va, &rb->data[i]);
};
}

View file

@ -0,0 +1,864 @@
/*
armmmu.c - Memory Management Unit emulation.
ARMulator extensions for the ARM7100 family.
Copyright (C) 1999 Ben Williamson
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <assert.h>
#include <string.h>
#include "core/arm/interpreter/armdefs.h"
/**
* The interface of read data from bus
*/
int bus_read(short size, int addr, uint32_t * value) {
ERROR_LOG(ARM11, "unimplemented bus_read");
return 0;
}
/**
* The interface of write data from bus
*/
int bus_write(short size, int addr, uint32_t value) {
ERROR_LOG(ARM11, "unimplemented bus_write");
return 0;
}
typedef struct sa_mmu_desc_s
{
int i_tlb;
cache_desc_t i_cache;
int d_tlb;
cache_desc_t main_d_cache;
cache_desc_t mini_d_cache;
int rb;
wb_desc_t wb;
} sa_mmu_desc_t;
static sa_mmu_desc_t sa11xx_mmu_desc = {
32,
{32, 32, 16, CACHE_WRITE_BACK},
32,
{32, 32, 8, CACHE_WRITE_BACK},
{32, 2, 8, CACHE_WRITE_BACK},
4,
//{8, 4}, for word size
{8, 16}, //for byte size, chy 2003-07-11
};
static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data,
ARMword datatype);
static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
ARMword datatype);
static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data,
ARMword datatype, cache_line_t * cache,
cache_s * cache_t, ARMword real_va);
void
mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
ARMbyte * data, int n);
int
sa_mmu_init (ARMul_State * state)
{
sa_mmu_desc_t *desc;
cache_desc_t *c_desc;
state->mmu.control = 0x70;
state->mmu.translation_table_base = 0xDEADC0DE;
state->mmu.domain_access_control = 0xDEADC0DE;
state->mmu.fault_status = 0;
state->mmu.fault_address = 0;
state->mmu.process_id = 0;
desc = &sa11xx_mmu_desc;
if (mmu_tlb_init (I_TLB (), desc->i_tlb)) {
ERROR_LOG(ARM11, "i_tlb init %d\n", -1);
goto i_tlb_init_error;
}
c_desc = &desc->i_cache;
if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way,
c_desc->set, c_desc->w_mode)) {
ERROR_LOG(ARM11, "i_cache init %d\n", -1);
goto i_cache_init_error;
}
if (mmu_tlb_init (D_TLB (), desc->d_tlb)) {
ERROR_LOG(ARM11, "d_tlb init %d\n", -1);
goto d_tlb_init_error;
}
c_desc = &desc->main_d_cache;
if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way,
c_desc->set, c_desc->w_mode)) {
ERROR_LOG(ARM11, "main_d_cache init %d\n", -1);
goto main_d_cache_init_error;
}
c_desc = &desc->mini_d_cache;
if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way,
c_desc->set, c_desc->w_mode)) {
ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1);
goto mini_d_cache_init_error;
}
if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) {
ERROR_LOG(ARM11, "wb init %d\n", -1);
goto wb_init_error;
}
if (mmu_rb_init (RB (), desc->rb)) {
ERROR_LOG(ARM11, "rb init %d\n", -1);
goto rb_init_error;
}
return 0;
rb_init_error:
mmu_wb_exit (WB ());
wb_init_error:
mmu_cache_exit (MINI_D_CACHE ());
mini_d_cache_init_error:
mmu_cache_exit (MAIN_D_CACHE ());
main_d_cache_init_error:
mmu_tlb_exit (D_TLB ());
d_tlb_init_error:
mmu_cache_exit (I_CACHE ());
i_cache_init_error:
mmu_tlb_exit (I_TLB ());
i_tlb_init_error:
return -1;
}
void
sa_mmu_exit (ARMul_State * state)
{
mmu_rb_exit (RB ());
mmu_wb_exit (WB ());
mmu_cache_exit (MINI_D_CACHE ());
mmu_cache_exit (MAIN_D_CACHE ());
mmu_tlb_exit (D_TLB ());
mmu_cache_exit (I_CACHE ());
mmu_tlb_exit (I_TLB ());
};
static fault_t
sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr)
{
fault_t fault;
tlb_entry_t *tlb;
cache_line_t *cache;
int c; //cache bit
ARMword pa; //physical addr
static int debug_count = 0; //used for debug
DEBUG_LOG(ARM11, "va = %x\n", va);
va = mmu_pid_va_map (va);
if (MMU_Enabled) {
/*align check */
if ((va & (WORD_SIZE - 1)) && MMU_Aligned) {
DEBUG_LOG(ARM11, "align\n");
return ALIGNMENT_FAULT;
}
else
va &= ~(WORD_SIZE - 1);
/*translate tlb */
fault = translate (state, va, I_TLB (), &tlb);
if (fault) {
DEBUG_LOG(ARM11, "translate\n");
return fault;
}
/*check access */
fault = check_access (state, va, tlb, 1);
if (fault) {
DEBUG_LOG(ARM11, "check_fault\n");
return fault;
}
}
/*search cache no matter MMU enabled/disabled */
cache = mmu_cache_search (state, I_CACHE (), va);
if (cache) {
*instr = cache->data[va_cache_index (va, I_CACHE ())];
return NO_FAULT;
}
/*if MMU disabled or C flag is set alloc cache */
if (MMU_Disabled) {
c = 1;
pa = va;
}
else {
c = tlb_c_flag (tlb);
pa = tlb_va_to_pa (tlb, va);
}
if (c) {
int index;
debug_count++;
cache = mmu_cache_alloc (state, I_CACHE (), va, pa);
index = va_cache_index (va, I_CACHE ());
*instr = cache->data[va_cache_index (va, I_CACHE ())];
}
else
//*instr = mem_read_word (state, pa);
bus_read(32, pa, instr);
return NO_FAULT;
};
static fault_t
sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data)
{
//ARMword temp,offset;
fault_t fault;
fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
return fault;
}
static fault_t
sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data)
{
//ARMword temp,offset;
fault_t fault;
fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
return fault;
}
static fault_t
sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data)
{
return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
}
static fault_t
sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
ARMword datatype)
{
fault_t fault;
rb_entry_t *rb;
tlb_entry_t *tlb;
cache_line_t *cache;
ARMword pa, real_va, temp, offset;
DEBUG_LOG(ARM11, "va = %x\n", va);
va = mmu_pid_va_map (va);
real_va = va;
/*if MMU disabled, memory_read */
if (MMU_Disabled) {
//*data = mem_read_word(state, va);
if (datatype == ARM_BYTE_TYPE)
//*data = mem_read_byte (state, va);
bus_read(8, va, data);
else if (datatype == ARM_HALFWORD_TYPE)
//*data = mem_read_halfword (state, va);
bus_read(16, va, data);
else if (datatype == ARM_WORD_TYPE)
//*data = mem_read_word (state, va);
bus_read(32, va, data);
else {
printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype);
// skyeye_exit (-1);
}
return NO_FAULT;
}
/*align check */
if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
DEBUG_LOG(ARM11, "align\n");
return ALIGNMENT_FAULT;
} // else
va &= ~(WORD_SIZE - 1);
/*translate va to tlb */
fault = translate (state, va, D_TLB (), &tlb);
if (fault) {
DEBUG_LOG(ARM11, "translate\n");
return fault;
}
/*check access permission */
fault = check_access (state, va, tlb, 1);
if (fault)
return fault;
/*search in read buffer */
rb = mmu_rb_search (RB (), va);
if (rb) {
if (rb->fault)
return rb->fault;
*data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT];
goto datatrans;
//return 0;
};
/*search main cache */
cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
if (cache) {
*data = cache->data[va_cache_index (va, MAIN_D_CACHE ())];
goto datatrans;
//return 0;
}
/*search mini cache */
cache = mmu_cache_search (state, MINI_D_CACHE (), va);
if (cache) {
*data = cache->data[va_cache_index (va, MINI_D_CACHE ())];
goto datatrans;
//return 0;
}
/*get phy_addr */
pa = tlb_va_to_pa (tlb, va);
if ((pa >= 0xe0000000) && (pa < 0xe8000000)) {
if (tlb_c_flag (tlb)) {
if (tlb_b_flag (tlb)) {
mmu_cache_soft_flush (state, MAIN_D_CACHE (),
pa);
}
else {
mmu_cache_soft_flush (state, MINI_D_CACHE (),
pa);
}
}
return NO_FAULT;
}
/*if Buffer, drain Write Buffer first */
if (tlb_b_flag (tlb))
mmu_wb_drain_all (state, WB ());
/*alloc cache or mem_read */
if (tlb_c_flag (tlb) && MMU_DCacheEnabled) {
cache_s *cache_t;
if (tlb_b_flag (tlb))
cache_t = MAIN_D_CACHE ();
else
cache_t = MINI_D_CACHE ();
cache = mmu_cache_alloc (state, cache_t, va, pa);
*data = cache->data[va_cache_index (va, cache_t)];
}
else {
//*data = mem_read_word(state, pa);
if (datatype == ARM_BYTE_TYPE)
//*data = mem_read_byte (state, pa | (real_va & 3));
bus_read(8, pa | (real_va & 3), data);
else if (datatype == ARM_HALFWORD_TYPE)
//*data = mem_read_halfword (state, pa | (real_va & 2));
bus_read(16, pa | (real_va & 2), data);
else if (datatype == ARM_WORD_TYPE)
//*data = mem_read_word (state, pa);
bus_read(32, pa, data);
else {
printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype);
// skyeye_exit (-1);
}
return NO_FAULT;
}
datatrans:
if (datatype == ARM_HALFWORD_TYPE) {
temp = *data;
offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
*data = (temp >> offset) & 0xffff;
}
else if (datatype == ARM_BYTE_TYPE) {
temp = *data;
offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
*data = (temp >> offset & 0xffL);
}
end:
return NO_FAULT;
}
static fault_t
sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data)
{
return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
}
static fault_t
sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data)
{
return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
}
static fault_t
sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data)
{
return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
}
static fault_t
sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype)
{
tlb_entry_t *tlb;
cache_line_t *cache;
int b;
ARMword pa, real_va;
fault_t fault;
DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
va = mmu_pid_va_map (va);
real_va = va;
/*search instruction cache */
cache = mmu_cache_search (state, I_CACHE (), va);
if (cache) {
update_cache (state, va, data, datatype, cache, I_CACHE (),
real_va);
}
if (MMU_Disabled) {
//mem_write_word(state, va, data);
if (datatype == ARM_BYTE_TYPE)
//mem_write_byte (state, va, data);
bus_write(8, va, data);
else if (datatype == ARM_HALFWORD_TYPE)
//mem_write_halfword (state, va, data);
bus_write(16, va, data);
else if (datatype == ARM_WORD_TYPE)
//mem_write_word (state, va, data);
bus_write(32, va, data);
else {
printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype);
// skyeye_exit (-1);
}
return NO_FAULT;
}
/*align check */
//if ((va & (WORD_SIZE - 1)) && MMU_Aligned){
if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
DEBUG_LOG(ARM11, "align\n");
return ALIGNMENT_FAULT;
} //else
va &= ~(WORD_SIZE - 1);
/*tlb translate */
fault = translate (state, va, D_TLB (), &tlb);
if (fault) {
DEBUG_LOG(ARM11, "translate\n");
return fault;
}
/*tlb check access */
fault = check_access (state, va, tlb, 0);
if (fault) {
DEBUG_LOG(ARM11, "check_access\n");
return fault;
}
/*search main cache */
cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
if (cache) {
update_cache (state, va, data, datatype, cache,
MAIN_D_CACHE (), real_va);
}
else {
/*search mini cache */
cache = mmu_cache_search (state, MINI_D_CACHE (), va);
if (cache) {
update_cache (state, va, data, datatype, cache,
MINI_D_CACHE (), real_va);
}
}
if (!cache) {
b = tlb_b_flag (tlb);
pa = tlb_va_to_pa (tlb, va);
if (b) {
if (MMU_WBEnabled) {
if (datatype == ARM_WORD_TYPE)
mmu_wb_write_bytes (state, WB (), pa,
(ARMbyte*)&data, 4);
else if (datatype == ARM_HALFWORD_TYPE)
mmu_wb_write_bytes (state, WB (),
(pa |
(real_va & 2)),
(ARMbyte*)&data, 2);
else if (datatype == ARM_BYTE_TYPE)
mmu_wb_write_bytes (state, WB (),
(pa |
(real_va & 3)),
(ARMbyte*)&data, 1);
}
else {
if (datatype == ARM_WORD_TYPE)
//mem_write_word (state, pa, data);
bus_write(32, pa, data);
else if (datatype == ARM_HALFWORD_TYPE)
/*
mem_write_halfword (state,
(pa |
(real_va & 2)),
data);
*/
bus_write(16, pa | (real_va & 2), data);
else if (datatype == ARM_BYTE_TYPE)
/*
mem_write_byte (state,
(pa | (real_va & 3)),
data);
*/
bus_write(8, pa | (real_va & 3), data);
}
}
else {
mmu_wb_drain_all (state, WB ());
if (datatype == ARM_WORD_TYPE)
//mem_write_word (state, pa, data);
bus_write(32, pa, data);
else if (datatype == ARM_HALFWORD_TYPE)
/*
mem_write_halfword (state,
(pa | (real_va & 2)),
data);
*/
bus_write(16, pa | (real_va & 2), data);
else if (datatype == ARM_BYTE_TYPE)
/*
mem_write_byte (state, (pa | (real_va & 3)),
data);
*/
bus_write(8, pa | (real_va & 3), data);
}
}
return NO_FAULT;
}
static fault_t
update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype,
cache_line_t * cache, cache_s * cache_t, ARMword real_va)
{
ARMword temp, offset;
ARMword index = va_cache_index (va, cache_t);
//cache->data[index] = data;
if (datatype == ARM_WORD_TYPE)
cache->data[index] = data;
else if (datatype == ARM_HALFWORD_TYPE) {
temp = cache->data[index];
offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
cache->data[index] =
(temp & ~(0xffffL << offset)) | ((data & 0xffffL) <<
offset);
}
else if (datatype == ARM_BYTE_TYPE) {
temp = cache->data[index];
offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
cache->data[index] =
(temp & ~(0xffL << offset)) | ((data & 0xffL) <<
offset);
}
if (index < (cache_t->width >> (WORD_SHT + 1)))
cache->tag |= TAG_FIRST_HALF_DIRTY;
else
cache->tag |= TAG_LAST_HALF_DIRTY;
return NO_FAULT;
}
ARMword
sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
{
mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15);
ARMword data;
switch (creg) {
case MMU_ID:
// printf("mmu_mrc read ID ");
data = 0x41007100; /* v3 */
data = state->cpu->cpu_val;
break;
case MMU_CONTROL:
// printf("mmu_mrc read CONTROL");
data = state->mmu.control;
break;
case MMU_TRANSLATION_TABLE_BASE:
// printf("mmu_mrc read TTB ");
data = state->mmu.translation_table_base;
break;
case MMU_DOMAIN_ACCESS_CONTROL:
// printf("mmu_mrc read DACR ");
data = state->mmu.domain_access_control;
break;
case MMU_FAULT_STATUS:
// printf("mmu_mrc read FSR ");
data = state->mmu.fault_status;
break;
case MMU_FAULT_ADDRESS:
// printf("mmu_mrc read FAR ");
data = state->mmu.fault_address;
break;
case MMU_PID:
data = state->mmu.process_id;
default:
printf ("mmu_mrc read UNKNOWN - reg %d\n", creg);
data = 0;
break;
}
// printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]);
*value = data;
return data;
}
void
sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value)
{
int CRm, OPC_2;
CRm = BITS (0, 3);
OPC_2 = BITS (5, 7);
if (OPC_2 == 0 && CRm == 7) {
mmu_cache_invalidate_all (state, I_CACHE ());
mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
mmu_cache_invalidate_all (state, MINI_D_CACHE ());
return;
}
if (OPC_2 == 0 && CRm == 5) {
mmu_cache_invalidate_all (state, I_CACHE ());
return;
}
if (OPC_2 == 0 && CRm == 6) {
mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
mmu_cache_invalidate_all (state, MINI_D_CACHE ());
return;
}
if (OPC_2 == 1 && CRm == 6) {
mmu_cache_invalidate (state, MAIN_D_CACHE (), value);
mmu_cache_invalidate (state, MINI_D_CACHE (), value);
return;
}
if (OPC_2 == 1 && CRm == 0xa) {
mmu_cache_clean (state, MAIN_D_CACHE (), value);
mmu_cache_clean (state, MINI_D_CACHE (), value);
return;
}
if (OPC_2 == 4 && CRm == 0xa) {
mmu_wb_drain_all (state, WB ());
return;
}
ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
}
static void
sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value)
{
int CRm, OPC_2;
CRm = BITS (0, 3);
OPC_2 = BITS (5, 7);
if (OPC_2 == 0 && CRm == 0x7) {
mmu_tlb_invalidate_all (state, I_TLB ());
mmu_tlb_invalidate_all (state, D_TLB ());
return;
}
if (OPC_2 == 0 && CRm == 0x5) {
mmu_tlb_invalidate_all (state, I_TLB ());
return;
}
if (OPC_2 == 0 && CRm == 0x6) {
mmu_tlb_invalidate_all (state, D_TLB ());
return;
}
if (OPC_2 == 1 && CRm == 0x6) {
mmu_tlb_invalidate_entry (state, D_TLB (), value);
return;
}
ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
}
static void
sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value)
{
int CRm, OPC_2;
CRm = BITS (0, 3);
OPC_2 = BITS (5, 7);
if (OPC_2 == 0x0 && CRm == 0x0) {
mmu_rb_invalidate_all (RB ());
return;
}
if (OPC_2 == 0x2) {
int idx = CRm & 0x3;
int type = ((CRm >> 2) & 0x3) + 1;
if ((idx < 4) && (type < 4))
mmu_rb_load (state, RB (), idx, type, value);
return;
}
if ((OPC_2 == 1) && (CRm < 4)) {
mmu_rb_invalidate_entry (RB (), CRm);
return;
}
ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
}
static ARMword
sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
{
mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15);
if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) {
switch (creg) {
case MMU_CONTROL:
// printf("mmu_mcr wrote CONTROL ");
state->mmu.control = (value | 0x70) & 0xFFFD;
break;
case MMU_TRANSLATION_TABLE_BASE:
// printf("mmu_mcr wrote TTB ");
state->mmu.translation_table_base =
value & 0xFFFFC000;
break;
case MMU_DOMAIN_ACCESS_CONTROL:
// printf("mmu_mcr wrote DACR ");
state->mmu.domain_access_control = value;
break;
case MMU_FAULT_STATUS:
state->mmu.fault_status = value & 0xFF;
break;
case MMU_FAULT_ADDRESS:
state->mmu.fault_address = value;
break;
case MMU_CACHE_OPS:
sa_mmu_cache_ops (state, instr, value);
break;
case MMU_TLB_OPS:
sa_mmu_tlb_ops (state, instr, value);
break;
case MMU_SA_RB_OPS:
sa_mmu_rb_ops (state, instr, value);
break;
case MMU_SA_DEBUG:
break;
case MMU_SA_CP15_R15:
break;
case MMU_PID:
//2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu
state->mmu.process_id = value & 0x7e000000;
break;
default:
printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
break;
}
}
return 0;
}
//teawater add for arm2x86 2005.06.24-------------------------------------------
static int
sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr)
{
fault_t fault;
tlb_entry_t *tlb;
virt_addr = mmu_pid_va_map (virt_addr);
if (MMU_Enabled) {
/*align check */
if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
DEBUG_LOG(ARM11, "align\n");
return ALIGNMENT_FAULT;
}
else
virt_addr &= ~(WORD_SIZE - 1);
/*translate tlb */
fault = translate (state, virt_addr, I_TLB (), &tlb);
if (fault) {
DEBUG_LOG(ARM11, "translate\n");
return fault;
}
/*check access */
fault = check_access (state, virt_addr, tlb, 1);
if (fault) {
DEBUG_LOG(ARM11, "check_fault\n");
return fault;
}
}
if (MMU_Disabled) {
*phys_addr = virt_addr;
}
else {
*phys_addr = tlb_va_to_pa (tlb, virt_addr);
}
return (0);
}
//AJ2D--------------------------------------------------------------------------
/*sa mmu_ops_t*/
mmu_ops_t sa_mmu_ops = {
sa_mmu_init,
sa_mmu_exit,
sa_mmu_read_byte,
sa_mmu_write_byte,
sa_mmu_read_halfword,
sa_mmu_write_halfword,
sa_mmu_read_word,
sa_mmu_write_word,
sa_mmu_load_instr,
sa_mmu_mcr,
sa_mmu_mrc,
//teawater add for arm2x86 2005.06.24-------------------------------------------
sa_mmu_v2p_dbct,
//AJ2D--------------------------------------------------------------------------
};

View file

@ -0,0 +1,58 @@
/*
sa_mmu.h - StrongARM Memory Management Unit emulation.
ARMulator extensions for SkyEye.
<lyhost@263.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SA_MMU_H_
#define _SA_MMU_H_
/**
* The interface of read data from bus
*/
int bus_read(short size, int addr, uint32_t * value);
/**
* The interface of write data from bus
*/
int bus_write(short size, int addr, uint32_t value);
typedef struct sa_mmu_s
{
tlb_s i_tlb;
cache_s i_cache;
tlb_s d_tlb;
cache_s main_d_cache;
cache_s mini_d_cache;
rb_s rb_t;
wb_s wb_t;
} sa_mmu_t;
#define I_TLB() (&state->mmu.u.sa_mmu.i_tlb)
#define I_CACHE() (&state->mmu.u.sa_mmu.i_cache)
#define D_TLB() (&state->mmu.u.sa_mmu.d_tlb)
#define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache)
#define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache)
#define WB() (&state->mmu.u.sa_mmu.wb_t)
#define RB() (&state->mmu.u.sa_mmu.rb_t)
extern mmu_ops_t sa_mmu_ops;
#endif /*_SA_MMU_H_*/

View file

@ -0,0 +1,307 @@
#include <assert.h>
#include "core/arm/interpreter/armdefs.h"
ARMword tlb_masks[] = {
0x00000000, /* TLB_INVALID */
0xFFFFF000, /* TLB_SMALLPAGE */
0xFFFF0000, /* TLB_LARGEPAGE */
0xFFF00000, /* TLB_SECTION */
0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */
0xFFFFFC00 /* TLB_TINYPAGE */
};
/* This function encodes table 8-2 Interpreting AP bits,
returning non-zero if access is allowed. */
static int
check_perms (ARMul_State * state, int ap, int read)
{
int s, r, user;
s = state->mmu.control & CONTROL_SYSTEM;
r = state->mmu.control & CONTROL_ROM;
//chy 2006-02-15 , should consider system mode, don't conside 26bit mode
user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE);
switch (ap) {
case 0:
return read && ((s && !user) || r);
case 1:
return !user;
case 2:
return read || !user;
case 3:
return 1;
}
return 0;
}
fault_t
check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
int read)
{
int access;
state->mmu.last_domain = tlb->domain;
access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3;
if ((access == 0) || (access == 2)) {
/* It's unclear from the documentation whether this
should always raise a section domain fault, or if
it should be a page domain fault in the case of an
L1 that describes a page table. In the ARM710T
datasheets, "Figure 8-9: Sequence for checking faults"
seems to indicate the former, while "Table 8-4: Priority
encoding of fault status" gives a value for FS[3210] in
the event of a domain fault for a page. Hmm. */
return SECTION_DOMAIN_FAULT;
}
if (access == 1) {
/* client access - check perms */
int subpage, ap;
switch (tlb->mapping) {
/*ks 2004-05-09
* only for XScale
* Extend Small Page(ESP) Format
* 31-12 bits the base addr of ESP
* 11-10 bits SBZ
* 9-6 bits TEX
* 5-4 bits AP
* 3 bit C
* 2 bit B
* 1-0 bits 11
* */
case TLB_ESMALLPAGE: //xj
subpage = 0;
//printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr );
break;
case TLB_TINYPAGE:
subpage = 0;
//printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr );
break;
case TLB_SMALLPAGE:
subpage = (virt_addr >> 10) & 3;
break;
case TLB_LARGEPAGE:
subpage = (virt_addr >> 14) & 3;
break;
case TLB_SECTION:
subpage = 3;
break;
default:
assert (0);
subpage = 0; /* cleans a warning */
}
ap = (tlb->perms >> (subpage * 2 + 4)) & 3;
if (!check_perms (state, ap, read)) {
if (tlb->mapping == TLB_SECTION) {
return SECTION_PERMISSION_FAULT;
}
else {
return SUBPAGE_PERMISSION_FAULT;
}
}
}
else { /* access == 3 */
/* manager access - don't check perms */
}
return NO_FAULT;
}
fault_t
translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t,
tlb_entry_t ** tlb)
{
*tlb = mmu_tlb_search (state, tlb_t, virt_addr);
if (!*tlb) {
/* walk the translation tables */
ARMword l1addr, l1desc;
tlb_entry_t entry;
l1addr = state->mmu.translation_table_base & 0xFFFFC000;
l1addr = (l1addr | (virt_addr >> 18)) & ~3;
//l1desc = mem_read_word (state, l1addr);
bus_read(32, l1addr, &l1desc);
switch (l1desc & 3) {
case 0:
/*
* according to Figure 3-9 Sequence for checking faults in arm manual,
* section translation fault should be returned here.
*/
{
return SECTION_TRANSLATION_FAULT;
}
case 3:
/* fine page table */
// dcl 2006-01-08
{
ARMword l2addr, l2desc;
l2addr = l1desc & 0xFFFFF000;
l2addr = (l2addr |
((virt_addr & 0x000FFC00) >> 8)) &
~3;
//l2desc = mem_read_word (state, l2addr);
bus_read(32, l2addr, &l2desc);
entry.virt_addr = virt_addr;
entry.phys_addr = l2desc;
entry.perms = l2desc & 0x00000FFC;
entry.domain = (l1desc >> 5) & 0x0000000F;
switch (l2desc & 3) {
case 0:
state->mmu.last_domain = entry.domain;
return PAGE_TRANSLATION_FAULT;
case 3:
entry.mapping = TLB_TINYPAGE;
break;
case 1:
// this is untested
entry.mapping = TLB_LARGEPAGE;
break;
case 2:
// this is untested
entry.mapping = TLB_SMALLPAGE;
break;
}
}
break;
case 1:
/* coarse page table */
{
ARMword l2addr, l2desc;
l2addr = l1desc & 0xFFFFFC00;
l2addr = (l2addr |
((virt_addr & 0x000FF000) >> 10)) &
~3;
//l2desc = mem_read_word (state, l2addr);
bus_read(32, l2addr, &l2desc);
entry.virt_addr = virt_addr;
entry.phys_addr = l2desc;
entry.perms = l2desc & 0x00000FFC;
entry.domain = (l1desc >> 5) & 0x0000000F;
//printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr);
//chy 2003-09-02 for xscale
switch (l2desc & 3) {
case 0:
state->mmu.last_domain = entry.domain;
return PAGE_TRANSLATION_FAULT;
case 3:
if (!state->is_XScale) {
state->mmu.last_domain =
entry.domain;
return PAGE_TRANSLATION_FAULT;
};
//ks 2004-05-09 xscale shold use Extend Small Page
//entry.mapping = TLB_SMALLPAGE;
entry.mapping = TLB_ESMALLPAGE; //xj
break;
case 1:
entry.mapping = TLB_LARGEPAGE;
break;
case 2:
entry.mapping = TLB_SMALLPAGE;
break;
}
}
break;
case 2:
/* section */
//printf("SKYEYE:WARNING: not implement section mapping incompletely\n");
//printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc);
//return SECTION_DOMAIN_FAULT;
//#if 0
entry.virt_addr = virt_addr;
entry.phys_addr = l1desc;
entry.perms = l1desc & 0x00000C0C;
entry.domain = (l1desc >> 5) & 0x0000000F;
entry.mapping = TLB_SECTION;
break;
//#endif
}
entry.virt_addr &= tlb_masks[entry.mapping];
entry.phys_addr &= tlb_masks[entry.mapping];
/* place entry in the tlb */
*tlb = &tlb_t->entrys[tlb_t->cycle];
tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num;
**tlb = entry;
}
state->mmu.last_domain = (*tlb)->domain;
return NO_FAULT;
}
int
mmu_tlb_init (tlb_s * tlb_t, int num)
{
tlb_entry_t *e;
int i;
e = (tlb_entry_t *) malloc (sizeof (*e) * num);
if (e == NULL) {
ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num);
goto tlb_malloc_error;
}
tlb_t->entrys = e;
for (i = 0; i < num; i++, e++)
e->mapping = TLB_INVALID;
tlb_t->cycle = 0;
tlb_t->num = num;
return 0;
tlb_malloc_error:
return -1;
}
void
mmu_tlb_exit (tlb_s * tlb_t)
{
free (tlb_t->entrys);
};
void
mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t)
{
int entry;
for (entry = 0; entry < tlb_t->num; entry++) {
tlb_t->entrys[entry].mapping = TLB_INVALID;
}
tlb_t->cycle = 0;
}
void
mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr)
{
tlb_entry_t *tlb;
tlb = mmu_tlb_search (state, tlb_t, addr);
if (tlb) {
tlb->mapping = TLB_INVALID;
}
}
tlb_entry_t *
mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr)
{
int entry;
for (entry = 0; entry < tlb_t->num; entry++) {
tlb_entry_t *tlb;
ARMword mask;
tlb = &(tlb_t->entrys[entry]);
if (tlb->mapping == TLB_INVALID) {
continue;
}
mask = tlb_masks[tlb->mapping];
if ((virt_addr & mask) == (tlb->virt_addr & mask)) {
return tlb;
}
}
return NULL;
}

View file

@ -63,14 +63,7 @@ typedef struct tlb_s
#define tlb_b_flag(tlb) \
((tlb)->perms & 0x4)
#define tlb_va_to_pa(tlb, va) \
(\
{\
ARMword mask = tlb_masks[tlb->mapping]; \
(tlb->phys_addr & mask) | (va & ~mask);\
}\
)
#define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping]))
fault_t
check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
int read);

View file

@ -0,0 +1,149 @@
#include "core/arm/interpreter/armdefs.h"
/* wb_init
* @wb_t :wb_t to init
* @num :num of entrys
* @nb :num of byte of each entry
*
* $ -1:error
* 0:ok
* */
int
mmu_wb_init (wb_s * wb_t, int num, int nb)
{
int i;
wb_entry_t *entrys, *wb;
entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num);
if (entrys == NULL) {
ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num);
goto entrys_malloc_error;
}
for (wb = entrys, i = 0; i < num; i++, wb++) {
/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */
//wb->data = (ARMword *)malloc(sizeof(ARMword) * nb);
wb->data = (ARMbyte *) malloc (nb);
if (wb->data == NULL) {
ERROR_LOG(ARM11, "malloc size of %d\n", nb);
goto data_malloc_error;
}
};
wb_t->first = wb_t->last = wb_t->used = 0;
wb_t->num = num;
wb_t->nb = nb;
wb_t->entrys = entrys;
return 0;
data_malloc_error:
while (--i >= 0)
free (entrys[i].data);
free (entrys);
entrys_malloc_error:
return -1;
};
/* wb_exit
* @wb_t :wb_t to exit
* */
void
mmu_wb_exit (wb_s * wb_t)
{
int i;
wb_entry_t *wb;
wb = wb_t->entrys;
for (i = 0; i < wb_t->num; i++, wb++) {
free (wb->data);
}
free (wb_t->entrys);
};
/* wb_write_words :put words in Write Buffer
* @state: ARMul_State
* @wb_t: write buffer
* @pa: physical address
* @data: data ptr
* @n number of word to write
*
* Note: write buffer merge is not implemented, can be done late
* */
void
mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
ARMbyte * data, int n)
{
int i;
wb_entry_t *wb;
while (n) {
if (wb_t->num == wb_t->used) {
/*clean the last wb entry */
ARMword t;
wb = &wb_t->entrys[wb_t->last];
t = wb->pa;
for (i = 0; i < wb->nb; i++) {
//mem_write_byte (state, t, wb->data[i]);
bus_write(8, t, wb->data[i]);
//t += WORD_SIZE;
t++;
}
wb_t->last++;
if (wb_t->last == wb_t->num)
wb_t->last = 0;
wb_t->used--;
}
wb = &wb_t->entrys[wb_t->first];
i = (n < wb_t->nb) ? n : wb_t->nb;
wb->pa = pa;
//pa += i << WORD_SHT;
pa += i;
wb->nb = i;
//memcpy(wb->data, data, i << WORD_SHT);
memcpy (wb->data, data, i);
data += i;
n -= i;
wb_t->first++;
if (wb_t->first == wb_t->num)
wb_t->first = 0;
wb_t->used++;
};
//teawater add for set_dirty fflash cache function 2005.07.18-------------------
#ifdef DBCT
if (!skyeye_config.no_dbct) {
tb_setdirty (state, pa, NULL);
}
#endif
//AJ2D--------------------------------------------------------------------------
}
/* wb_drain_all
* @wb_t wb_t to drain
* */
void
mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t)
{
ARMword pa;
wb_entry_t *wb;
int i;
while (wb_t->used) {
wb = &wb_t->entrys[wb_t->last];
pa = wb->pa;
for (i = 0; i < wb->nb; i++) {
//mem_write_byte (state, pa, wb->data[i]);
bus_write(8, pa, wb->data[i]);
//pa += WORD_SIZE;
pa++;
}
wb_t->last++;
if (wb_t->last == wb_t->num)
wb_t->last = 0;
wb_t->used--;
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
/*
* arch/arm/include/asm/vfp.h
*
* VFP register definitions.
* First, the standard VFP set.
*/
#define FPSID cr0
#define FPSCR cr1
#define MVFR1 cr6
#define MVFR0 cr7
#define FPEXC cr8
#define FPINST cr9
#define FPINST2 cr10
/* FPSID bits */
#define FPSID_IMPLEMENTER_BIT (24)
#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT)
#define FPSID_SOFTWARE (1<<23)
#define FPSID_FORMAT_BIT (21)
#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT)
#define FPSID_NODOUBLE (1<<20)
#define FPSID_ARCH_BIT (16)
#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT)
#define FPSID_PART_BIT (8)
#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT)
#define FPSID_VARIANT_BIT (4)
#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT)
#define FPSID_REV_BIT (0)
#define FPSID_REV_MASK (0xF << FPSID_REV_BIT)
/* FPEXC bits */
#define FPEXC_EX (1 << 31)
#define FPEXC_EN (1 << 30)
#define FPEXC_DEX (1 << 29)
#define FPEXC_FP2V (1 << 28)
#define FPEXC_VV (1 << 27)
#define FPEXC_TFV (1 << 26)
#define FPEXC_LENGTH_BIT (8)
#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT)
#define FPEXC_IDF (1 << 7)
#define FPEXC_IXF (1 << 4)
#define FPEXC_UFF (1 << 3)
#define FPEXC_OFF (1 << 2)
#define FPEXC_DZF (1 << 1)
#define FPEXC_IOF (1 << 0)
#define FPEXC_TRAP_MASK (FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF)
/* FPSCR bits */
#define FPSCR_DEFAULT_NAN (1<<25)
#define FPSCR_FLUSHTOZERO (1<<24)
#define FPSCR_ROUND_NEAREST (0<<22)
#define FPSCR_ROUND_PLUSINF (1<<22)
#define FPSCR_ROUND_MINUSINF (2<<22)
#define FPSCR_ROUND_TOZERO (3<<22)
#define FPSCR_RMODE_BIT (22)
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
#define FPSCR_STRIDE_BIT (20)
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
#define FPSCR_LENGTH_BIT (16)
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
#define FPSCR_IOE (1<<8)
#define FPSCR_DZE (1<<9)
#define FPSCR_OFE (1<<10)
#define FPSCR_UFE (1<<11)
#define FPSCR_IXE (1<<12)
#define FPSCR_IDE (1<<15)
#define FPSCR_IOC (1<<0)
#define FPSCR_DZC (1<<1)
#define FPSCR_OFC (1<<2)
#define FPSCR_UFC (1<<3)
#define FPSCR_IXC (1<<4)
#define FPSCR_IDC (1<<7)
/* MVFR0 bits */
#define MVFR0_A_SIMD_BIT (0)
#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT)
/* Bit patterns for decoding the packaged operation descriptors */
#define VFPOPDESC_LENGTH_BIT (9)
#define VFPOPDESC_LENGTH_MASK (0x07 << VFPOPDESC_LENGTH_BIT)
#define VFPOPDESC_UNUSED_BIT (24)
#define VFPOPDESC_UNUSED_MASK (0xFF << VFPOPDESC_UNUSED_BIT)
#define VFPOPDESC_OPDESC_MASK (~(VFPOPDESC_LENGTH_MASK | VFPOPDESC_UNUSED_MASK))

View file

@ -0,0 +1,357 @@
/*
armvfp.c - ARM VFPv3 emulation unit
Copyright (C) 2003 Skyeye Develop Group
for help please send mail to <skyeye-developer@lists.gro.clinux.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Note: this file handles interface with arm core and vfp registers */
/* Opens debug for classic interpreter only */
//#define DEBUG
#include "common/common.h"
#include "core/arm/interpreter/armdefs.h"
#include "core/arm/interpreter/vfp/vfp.h"
//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
unsigned
VFPInit (ARMul_State *state)
{
state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
//persistent_state = state;
/* Reset only specify VFP_FPEXC_EN = '0' */
return No_exp;
}
unsigned
VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
{
/* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
int CoProc = BITS (8, 11); /* 10 or 11 */
int OPC_1 = BITS (21, 23);
int Rt = BITS (12, 15);
int CRn = BITS (16, 19);
int CRm = BITS (0, 3);
int OPC_2 = BITS (5, 7);
/* TODO check access permission */
/* CRn/opc1 CRm/opc2 */
if (CoProc == 10 || CoProc == 11)
{
#define VFP_MRC_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MRC_TRANS
}
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
return ARMul_CANT;
}
unsigned
VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
{
/* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
int CoProc = BITS (8, 11); /* 10 or 11 */
int OPC_1 = BITS (21, 23);
int Rt = BITS (12, 15);
int CRn = BITS (16, 19);
int CRm = BITS (0, 3);
int OPC_2 = BITS (5, 7);
/* TODO check access permission */
/* CRn/opc1 CRm/opc2 */
if (CoProc == 10 || CoProc == 11)
{
#define VFP_MCR_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MCR_TRANS
}
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
return ARMul_CANT;
}
unsigned
VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
{
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
int CoProc = BITS (8, 11); /* 10 or 11 */
int OPC_1 = BITS (4, 7);
int Rt = BITS (12, 15);
int Rt2 = BITS (16, 19);
int CRm = BITS (0, 3);
if (CoProc == 10 || CoProc == 11)
{
#define VFP_MRRC_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MRRC_TRANS
}
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
instr, CoProc, OPC_1, Rt, Rt2, CRm);
return ARMul_CANT;
}
unsigned
VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
{
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
int CoProc = BITS (8, 11); /* 10 or 11 */
int OPC_1 = BITS (4, 7);
int Rt = BITS (12, 15);
int Rt2 = BITS (16, 19);
int CRm = BITS (0, 3);
/* TODO check access permission */
/* CRn/opc1 CRm/opc2 */
if (CoProc == 11 || CoProc == 10)
{
#define VFP_MCRR_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MCRR_TRANS
}
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
instr, CoProc, OPC_1, Rt, Rt2, CRm);
return ARMul_CANT;
}
unsigned
VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
{
/* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
int CoProc = BITS (8, 11); /* 10 or 11 */
int CRd = BITS (12, 15);
int Rn = BITS (16, 19);
int imm8 = BITS (0, 7);
int P = BIT(24);
int U = BIT(23);
int D = BIT(22);
int W = BIT(21);
/* TODO check access permission */
/* VSTM */
if ( (P|U|D|W) == 0 )
{
DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
}
if (CoProc == 10 || CoProc == 11)
{
#if 1
if (P == 0 && U == 0 && W == 0)
{
DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
}
if (P == U && W == 1)
{
DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
}
#endif
#define VFP_STC_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_STC_TRANS
}
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
instr, CoProc, CRd, Rn, imm8, P, U, D, W);
return ARMul_CANT;
}
unsigned
VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
{
/* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
int CoProc = BITS (8, 11); /* 10 or 11 */
int CRd = BITS (12, 15);
int Rn = BITS (16, 19);
int imm8 = BITS (0, 7);
int P = BIT(24);
int U = BIT(23);
int D = BIT(22);
int W = BIT(21);
/* TODO check access permission */
if ( (P|U|D|W) == 0 )
{
DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
}
if (CoProc == 10 || CoProc == 11)
{
#define VFP_LDC_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_LDC_TRANS
}
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
instr, CoProc, CRd, Rn, imm8, P, U, D, W);
return ARMul_CANT;
}
unsigned
VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
{
/* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
int CoProc = BITS (8, 11); /* 10 or 11 */
int OPC_1 = BITS (20, 23);
int CRd = BITS (12, 15);
int CRn = BITS (16, 19);
int CRm = BITS (0, 3);
int OPC_2 = BITS (5, 7);
/* TODO check access permission */
/* CRn/opc1 CRm/opc2 */
if (CoProc == 10 || CoProc == 11)
{
#define VFP_CDP_TRANS
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_CDP_TRANS
int exceptions = 0;
if (CoProc == 10)
exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
else
exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
return ARMul_DONE;
}
DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
return ARMul_CANT;
}
/* ----------- MRC ------------ */
#define VFP_MRC_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MRC_IMPL
#define VFP_MRRC_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MRRC_IMPL
/* ----------- MCR ------------ */
#define VFP_MCR_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MCR_IMPL
#define VFP_MCRR_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_MCRR_IMPL
/* Memory operation are not inlined, as old Interpreter and Fast interpreter
don't have the same memory operation interface.
Old interpreter framework does one access to coprocessor per data, and
handles already data write, as well as address computation,
which is not the case for Fast interpreter. Therefore, implementation
of vfp instructions in old interpreter and fast interpreter are separate. */
/* ----------- STC ------------ */
#define VFP_STC_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_STC_IMPL
/* ----------- LDC ------------ */
#define VFP_LDC_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_LDC_IMPL
/* ----------- CDP ------------ */
#define VFP_CDP_IMPL
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
#undef VFP_CDP_IMPL
/* Miscellaneous functions */
int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
{
DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
return state->ExtReg[reg];
}
void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
{
DBG("VFP put float: s%d <= [%08x]\n", reg, val);
state->ExtReg[reg] = val;
}
uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
{
uint64_t result;
result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
return result;
}
void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
{
DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
}
/*
* Process bitmask of exception conditions. (from vfpmodule.c)
*/
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
{
int si_code = 0;
vfpdebug("VFP: raising exceptions %08x\n", exceptions);
if (exceptions == VFP_EXCEPTION_ERROR) {
DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
exit(-1);
return;
}
/*
* If any of the status flags are set, update the FPSCR.
* Comparison instructions always return at least one of
* these flags set.
*/
if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
fpscr |= exceptions;
state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
}

View file

@ -0,0 +1,111 @@
/*
vfp/vfp.h - ARM VFPv3 emulation unit - vfp interface
Copyright (C) 2003 Skyeye Develop Group
for help please send mail to <skyeye-developer@lists.gro.clinux.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __VFP_H__
#define __VFP_H__
#define DBG(...) DEBUG_LOG(ARM11, __VA_ARGS__)
#define vfpdebug //printf
#include "core/arm/interpreter/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
unsigned VFPInit (ARMul_State *state);
unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value);
unsigned VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value);
unsigned VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2);
unsigned VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
unsigned VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value);
unsigned VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value);
unsigned VFPCDP (ARMul_State * state, unsigned type, ARMword instr);
/* FPSID Information */
#define VFP_FPSID_IMPLMEN 0 /* should be the same as cp15 0 c0 0*/
#define VFP_FPSID_SW 0
#define VFP_FPSID_SUBARCH 0x2 /* VFP version. Current is v3 (not strict) */
#define VFP_FPSID_PARTNUM 0x1
#define VFP_FPSID_VARIANT 0x1
#define VFP_FPSID_REVISION 0x1
/* FPEXC Flags */
#define VFP_FPEXC_EX 1<<31
#define VFP_FPEXC_EN 1<<30
/* FPSCR Flags */
#define VFP_FPSCR_NFLAG 1<<31
#define VFP_FPSCR_ZFLAG 1<<30
#define VFP_FPSCR_CFLAG 1<<29
#define VFP_FPSCR_VFLAG 1<<28
#define VFP_FPSCR_AHP 1<<26 /* Alternative Half Precision */
#define VFP_FPSCR_DN 1<<25 /* Default NaN */
#define VFP_FPSCR_FZ 1<<24 /* Flush-to-zero */
#define VFP_FPSCR_RMODE 3<<22 /* Rounding Mode */
#define VFP_FPSCR_STRIDE 3<<20 /* Stride (vector) */
#define VFP_FPSCR_LEN 7<<16 /* Stride (vector) */
#define VFP_FPSCR_IDE 1<<15 /* Input Denormal exc */
#define VFP_FPSCR_IXE 1<<12 /* Inexact exc */
#define VFP_FPSCR_UFE 1<<11 /* Undeflow exc */
#define VFP_FPSCR_OFE 1<<10 /* Overflow exc */
#define VFP_FPSCR_DZE 1<<9 /* Division by Zero exc */
#define VFP_FPSCR_IOE 1<<8 /* Invalid Operation exc */
#define VFP_FPSCR_IDC 1<<7 /* Input Denormal cum exc */
#define VFP_FPSCR_IXC 1<<4 /* Inexact cum exc */
#define VFP_FPSCR_UFC 1<<3 /* Undeflow cum exc */
#define VFP_FPSCR_OFC 1<<2 /* Overflow cum exc */
#define VFP_FPSCR_DZC 1<<1 /* Division by Zero cum exc */
#define VFP_FPSCR_IOC 1<<0 /* Invalid Operation cum exc */
/* Inline instructions. Note: Used in a cpp file as well */
#ifdef __cplusplus
extern "C" {
#endif
int32_t vfp_get_float(ARMul_State * state, unsigned int reg);
void vfp_put_float(ARMul_State * state, int32_t val, unsigned int reg);
uint64_t vfp_get_double(ARMul_State * state, unsigned int reg);
void vfp_put_double(ARMul_State * state, uint64_t val, unsigned int reg);
void vfp_raise_exceptions(ARMul_State * state, uint32_t exceptions, uint32_t inst, uint32_t fpscr);
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
/* MRC */
inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
/* MCR */
inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
/* STC */
inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
/* LDC */
inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,541 @@
/*
vfp/vfp.h - ARM VFPv3 emulation unit - SoftFloat lib helper
Copyright (C) 2003 Skyeye Develop Group
for help please send mail to <skyeye-developer@lists.gro.clinux.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* The following code is derivative from Linux Android kernel vfp
* floating point support.
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __VFP_HELPER_H__
#define __VFP_HELPER_H__
/* Custom edit */
#include <stdint.h>
#include <stdio.h>
#include "core/arm/interpreter/armdefs.h"
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define s16 int16_t
#define s32 int32_t
#define s64 int64_t
#define pr_info //printf
#define pr_debug //printf
static u32 fls(int x);
#define do_div(n, base) {n/=base;}
/* From vfpinstr.h */
#define INST_CPRTDO(inst) (((inst) & 0x0f000000) == 0x0e000000)
#define INST_CPRT(inst) ((inst) & (1 << 4))
#define INST_CPRT_L(inst) ((inst) & (1 << 20))
#define INST_CPRT_Rd(inst) (((inst) & (15 << 12)) >> 12)
#define INST_CPRT_OP(inst) (((inst) >> 21) & 7)
#define INST_CPNUM(inst) ((inst) & 0xf00)
#define CPNUM(cp) ((cp) << 8)
#define FOP_MASK (0x00b00040)
#define FOP_FMAC (0x00000000)
#define FOP_FNMAC (0x00000040)
#define FOP_FMSC (0x00100000)
#define FOP_FNMSC (0x00100040)
#define FOP_FMUL (0x00200000)
#define FOP_FNMUL (0x00200040)
#define FOP_FADD (0x00300000)
#define FOP_FSUB (0x00300040)
#define FOP_FDIV (0x00800000)
#define FOP_EXT (0x00b00040)
#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4)
#define FEXT_MASK (0x000f0080)
#define FEXT_FCPY (0x00000000)
#define FEXT_FABS (0x00000080)
#define FEXT_FNEG (0x00010000)
#define FEXT_FSQRT (0x00010080)
#define FEXT_FCMP (0x00040000)
#define FEXT_FCMPE (0x00040080)
#define FEXT_FCMPZ (0x00050000)
#define FEXT_FCMPEZ (0x00050080)
#define FEXT_FCVT (0x00070080)
#define FEXT_FUITO (0x00080000)
#define FEXT_FSITO (0x00080080)
#define FEXT_FTOUI (0x000c0000)
#define FEXT_FTOUIZ (0x000c0080)
#define FEXT_FTOSI (0x000d0000)
#define FEXT_FTOSIZ (0x000d0080)
#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
#define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00)
#define FPSCR_N (1 << 31)
#define FPSCR_Z (1 << 30)
#define FPSCR_C (1 << 29)
#define FPSCR_V (1 << 28)
/* -------------- */
/* From asm/include/vfp.h */
/* FPSCR bits */
#define FPSCR_DEFAULT_NAN (1<<25)
#define FPSCR_FLUSHTOZERO (1<<24)
#define FPSCR_ROUND_NEAREST (0<<22)
#define FPSCR_ROUND_PLUSINF (1<<22)
#define FPSCR_ROUND_MINUSINF (2<<22)
#define FPSCR_ROUND_TOZERO (3<<22)
#define FPSCR_RMODE_BIT (22)
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
#define FPSCR_STRIDE_BIT (20)
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
#define FPSCR_LENGTH_BIT (16)
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
#define FPSCR_IOE (1<<8)
#define FPSCR_DZE (1<<9)
#define FPSCR_OFE (1<<10)
#define FPSCR_UFE (1<<11)
#define FPSCR_IXE (1<<12)
#define FPSCR_IDE (1<<15)
#define FPSCR_IOC (1<<0)
#define FPSCR_DZC (1<<1)
#define FPSCR_OFC (1<<2)
#define FPSCR_UFC (1<<3)
#define FPSCR_IXC (1<<4)
#define FPSCR_IDC (1<<7)
/* ---------------- */
static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift)
{
if (shift) {
if (shift < 32)
val = val >> shift | ((val << (32 - shift)) != 0);
else
val = val != 0;
}
return val;
}
static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift)
{
if (shift) {
if (shift < 64)
val = val >> shift | ((val << (64 - shift)) != 0);
else
val = val != 0;
}
return val;
}
static inline u32 vfp_hi64to32jamming(u64 val)
{
u32 v;
u32 highval = val >> 32;
u32 lowval = val & 0xffffffff;
if (lowval >= 1)
v = highval | 1;
else
v = highval;
return v;
}
static inline void add128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml)
{
*resl = nl + ml;
*resh = nh + mh;
if (*resl < nl)
*resh += 1;
}
static inline void sub128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml)
{
*resl = nl - ml;
*resh = nh - mh;
if (*resl > nl)
*resh -= 1;
}
static inline void mul64to128(u64 *resh, u64 *resl, u64 n, u64 m)
{
u32 nh, nl, mh, ml;
u64 rh, rma, rmb, rl;
nl = n;
ml = m;
rl = (u64)nl * ml;
nh = n >> 32;
rma = (u64)nh * ml;
mh = m >> 32;
rmb = (u64)nl * mh;
rma += rmb;
rh = (u64)nh * mh;
rh += ((u64)(rma < rmb) << 32) + (rma >> 32);
rma <<= 32;
rl += rma;
rh += (rl < rma);
*resl = rl;
*resh = rh;
}
static inline void shift64left(u64 *resh, u64 *resl, u64 n)
{
*resh = n >> 63;
*resl = n << 1;
}
static inline u64 vfp_hi64multiply64(u64 n, u64 m)
{
u64 rh, rl;
mul64to128(&rh, &rl, n, m);
return rh | (rl != 0);
}
static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
{
u64 mh, ml, remh, reml, termh, terml, z;
if (nh >= m)
return ~0ULL;
mh = m >> 32;
if (mh << 32 <= nh) {
z = 0xffffffff00000000ULL;
} else {
z = nh;
do_div(z, mh);
z <<= 32;
}
mul64to128(&termh, &terml, m, z);
sub128(&remh, &reml, nh, nl, termh, terml);
ml = m << 32;
while ((s64)remh < 0) {
z -= 0x100000000ULL;
add128(&remh, &reml, remh, reml, mh, ml);
}
remh = (remh << 32) | (reml >> 32);
if (mh << 32 <= remh) {
z |= 0xffffffff;
} else {
do_div(remh, mh);
z |= remh;
}
return z;
}
/*
* Operations on unpacked elements
*/
#define vfp_sign_negate(sign) (sign ^ 0x8000)
/*
* Single-precision
*/
struct vfp_single {
s16 exponent;
u16 sign;
u32 significand;
};
#ifdef __cplusplus
extern "C" {
#endif
extern s32 vfp_get_float(ARMul_State * state, unsigned int reg);
extern void vfp_put_float(ARMul_State * state, s32 val, unsigned int reg);
#ifdef __cplusplus
}
#endif
/*
* VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa
* VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent
* VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand
* which are not propagated to the float upon packing.
*/
#define VFP_SINGLE_MANTISSA_BITS (23)
#define VFP_SINGLE_EXPONENT_BITS (8)
#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2)
#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1)
/*
* The bit in an unpacked float which indicates that it is a quiet NaN
*/
#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS))
/*
* Operations on packed single-precision numbers
*/
#define vfp_single_packed_sign(v) ((v) & 0x80000000)
#define vfp_single_packed_negate(v) ((v) ^ 0x80000000)
#define vfp_single_packed_abs(v) ((v) & ~0x80000000)
#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1))
/*
* Unpack a single-precision float. Note that this returns the magnitude
* of the single-precision float mantissa with the 1. if necessary,
* aligned to bit 30.
*/
static inline void vfp_single_unpack(struct vfp_single *s, s32 val)
{
u32 significand;
s->sign = vfp_single_packed_sign(val) >> 16,
s->exponent = vfp_single_packed_exponent(val);
significand = (u32) val;
significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
if (s->exponent && s->exponent != 255)
significand |= 0x40000000;
s->significand = significand;
}
/*
* Re-pack a single-precision float. This assumes that the float is
* already normalised such that the MSB is bit 30, _not_ bit 31.
*/
static inline s32 vfp_single_pack(struct vfp_single *s)
{
u32 val;
val = (s->sign << 16) +
(s->exponent << VFP_SINGLE_MANTISSA_BITS) +
(s->significand >> VFP_SINGLE_LOW_BITS);
return (s32)val;
}
#define VFP_NUMBER (1<<0)
#define VFP_ZERO (1<<1)
#define VFP_DENORMAL (1<<2)
#define VFP_INFINITY (1<<3)
#define VFP_NAN (1<<4)
#define VFP_NAN_SIGNAL (1<<5)
#define VFP_QNAN (VFP_NAN)
#define VFP_SNAN (VFP_NAN|VFP_NAN_SIGNAL)
static inline int vfp_single_type(struct vfp_single *s)
{
int type = VFP_NUMBER;
if (s->exponent == 255) {
if (s->significand == 0)
type = VFP_INFINITY;
else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN)
type = VFP_QNAN;
else
type = VFP_SNAN;
} else if (s->exponent == 0) {
if (s->significand == 0)
type |= VFP_ZERO;
else
type |= VFP_DENORMAL;
}
return type;
}
u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func);
/*
* Double-precision
*/
struct vfp_double {
s16 exponent;
u16 sign;
u64 significand;
};
/*
* VFP_REG_ZERO is a special register number for vfp_get_double
* which returns (double)0.0. This is useful for the compare with
* zero instructions.
*/
#ifdef CONFIG_VFPv3
#define VFP_REG_ZERO 32
#else
#define VFP_REG_ZERO 16
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern u64 vfp_get_double(ARMul_State * state, unsigned int reg);
extern void vfp_put_double(ARMul_State * state, u64 val, unsigned int reg);
#ifdef __cplusplus
}
#endif
#define VFP_DOUBLE_MANTISSA_BITS (52)
#define VFP_DOUBLE_EXPONENT_BITS (11)
#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2)
#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1)
/*
* The bit in an unpacked double which indicates that it is a quiet NaN
*/
#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS))
/*
* Operations on packed single-precision numbers
*/
#define vfp_double_packed_sign(v) ((v) & (1ULL << 63))
#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63))
#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63))
#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1))
/*
* Unpack a double-precision float. Note that this returns the magnitude
* of the double-precision float mantissa with the 1. if necessary,
* aligned to bit 62.
*/
static inline void vfp_double_unpack(struct vfp_double *s, s64 val)
{
u64 significand;
s->sign = vfp_double_packed_sign(val) >> 48;
s->exponent = vfp_double_packed_exponent(val);
significand = (u64) val;
significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
if (s->exponent && s->exponent != 2047)
significand |= (1ULL << 62);
s->significand = significand;
}
/*
* Re-pack a double-precision float. This assumes that the float is
* already normalised such that the MSB is bit 30, _not_ bit 31.
*/
static inline s64 vfp_double_pack(struct vfp_double *s)
{
u64 val;
val = ((u64)s->sign << 48) +
((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
(s->significand >> VFP_DOUBLE_LOW_BITS);
return (s64)val;
}
static inline int vfp_double_type(struct vfp_double *s)
{
int type = VFP_NUMBER;
if (s->exponent == 2047) {
if (s->significand == 0)
type = VFP_INFINITY;
else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN)
type = VFP_QNAN;
else
type = VFP_SNAN;
} else if (s->exponent == 0) {
if (s->significand == 0)
type |= VFP_ZERO;
else
type |= VFP_DENORMAL;
}
return type;
}
u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
/*
* A special flag to tell the normalisation code not to normalise.
*/
#define VFP_NAN_FLAG 0x100
/*
* A bit pattern used to indicate the initial (unset) value of the
* exception mask, in case nothing handles an instruction. This
* doesn't include the NAN flag, which get masked out before
* we check for an error.
*/
#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
/*
* A flag to tell vfp instruction type.
* OP_SCALAR - this operation always operates in scalar mode
* OP_SD - the instruction exceptionally writes to a single precision result.
* OP_DD - the instruction exceptionally writes to a double precision result.
* OP_SM - the instruction exceptionally reads from a single precision operand.
*/
#define OP_SCALAR (1 << 0)
#define OP_SD (1 << 1)
#define OP_DD (1 << 1)
#define OP_SM (1 << 2)
struct op {
u32 (* const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr);
u32 flags;
};
static inline u32 fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -139,6 +139,7 @@
<ItemGroup>
<ClCompile Include="arm\disassembler\arm_disasm.cpp" />
<ClCompile Include="arm\disassembler\load_symbol_map.cpp" />
<ClCompile Include="arm\interpreter\armcopro.cpp" />
<ClCompile Include="arm\interpreter\armemu.cpp" />
<ClCompile Include="arm\interpreter\arminit.cpp" />
<ClCompile Include="arm\interpreter\armmmu.cpp" />
@ -146,8 +147,19 @@
<ClCompile Include="arm\interpreter\armsupp.cpp" />
<ClCompile Include="arm\interpreter\armvirt.cpp" />
<ClCompile Include="arm\interpreter\arm_interpreter.cpp" />
<ClCompile Include="arm\interpreter\mmu\arm1176jzf_s_mmu.cpp" />
<ClCompile Include="arm\interpreter\mmu\cache.cpp" />
<ClCompile Include="arm\interpreter\mmu\maverick.cpp" />
<ClCompile Include="arm\interpreter\mmu\rb.cpp" />
<ClCompile Include="arm\interpreter\mmu\sa_mmu.cpp" />
<ClCompile Include="arm\interpreter\mmu\tlb.cpp" />
<ClCompile Include="arm\interpreter\mmu\wb.cpp" />
<ClCompile Include="arm\interpreter\mmu\xscale_copro.cpp" />
<ClCompile Include="arm\interpreter\thumbemu.cpp" />
<ClCompile Include="arm\mmu\arm1176jzf_s_mmu.cpp" />
<ClCompile Include="arm\interpreter\vfp\vfp.cpp" />
<ClCompile Include="arm\interpreter\vfp\vfpdouble.cpp" />
<ClCompile Include="arm\interpreter\vfp\vfpinstr.cpp" />
<ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" />
<ClCompile Include="core.cpp" />
<ClCompile Include="core_timing.cpp" />
<ClCompile Include="elf\elf_reader.cpp" />
@ -183,12 +195,16 @@
<ClInclude Include="arm\interpreter\armos.h" />
<ClInclude Include="arm\interpreter\arm_interpreter.h" />
<ClInclude Include="arm\interpreter\arm_regformat.h" />
<ClInclude Include="arm\interpreter\mmu\arm1176jzf_s_mmu.h" />
<ClInclude Include="arm\interpreter\mmu\cache.h" />
<ClInclude Include="arm\interpreter\mmu\rb.h" />
<ClInclude Include="arm\interpreter\mmu\sa_mmu.h" />
<ClInclude Include="arm\interpreter\mmu\tlb.h" />
<ClInclude Include="arm\interpreter\mmu\wb.h" />
<ClInclude Include="arm\interpreter\skyeye_defs.h" />
<ClInclude Include="arm\mmu\arm1176jzf_s_mmu.h" />
<ClInclude Include="arm\mmu\cache.h" />
<ClInclude Include="arm\mmu\rb.h" />
<ClInclude Include="arm\mmu\tlb.h" />
<ClInclude Include="arm\mmu\wb.h" />
<ClInclude Include="arm\interpreter\vfp\asm_vfp.h" />
<ClInclude Include="arm\interpreter\vfp\vfp.h" />
<ClInclude Include="arm\interpreter\vfp\vfp_helper.h" />
<ClInclude Include="core.h" />
<ClInclude Include="core_timing.h" />
<ClInclude Include="elf\elf_reader.h" />

View file

@ -7,9 +7,6 @@
<Filter Include="arm\disassembler">
<UniqueIdentifier>{61100188-a726-4024-ab16-95ee242b446e}</UniqueIdentifier>
</Filter>
<Filter Include="arm\mmu">
<UniqueIdentifier>{a64d3c8a-747a-491b-b782-6e2622bedf24}</UniqueIdentifier>
</Filter>
<Filter Include="file_sys">
<UniqueIdentifier>{7f618562-73d1-4f55-9628-887497c27654}</UniqueIdentifier>
</Filter>
@ -28,8 +25,11 @@
<Filter Include="hle\service">
<UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier>
</Filter>
<Filter Include="hle\kernel">
<UniqueIdentifier>{f2b132eb-caff-4b04-aaae-88d24393a711}</UniqueIdentifier>
<Filter Include="arm\interpreter\vfp">
<UniqueIdentifier>{de62238f-a28e-4a33-8495-23fed6784588}</UniqueIdentifier>
</Filter>
<Filter Include="arm\interpreter\mmu">
<UniqueIdentifier>{13ef9860-2ba0-47e9-a93d-b4052adab269}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@ -60,9 +60,6 @@
<ClCompile Include="arm\interpreter\thumbemu.cpp">
<Filter>arm\interpreter</Filter>
</ClCompile>
<ClCompile Include="arm\mmu\arm1176jzf_s_mmu.cpp">
<Filter>arm\mmu</Filter>
</ClCompile>
<ClCompile Include="file_sys\directory_file_system.cpp">
<Filter>file_sys</Filter>
</ClCompile>
@ -117,11 +114,44 @@
<ClCompile Include="hle\config_mem.cpp">
<Filter>hle</Filter>
</ClCompile>
<ClCompile Include="hle\kernel\thread.cpp">
<Filter>hle\kernel</Filter>
<ClCompile Include="arm\interpreter\vfp\vfp.cpp">
<Filter>arm\interpreter\vfp</Filter>
</ClCompile>
<ClCompile Include="hle\kernel\kernel.cpp">
<Filter>hle\kernel</Filter>
<ClCompile Include="arm\interpreter\vfp\vfpinstr.cpp">
<Filter>arm\interpreter\vfp</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\vfp\vfpdouble.cpp">
<Filter>arm\interpreter\vfp</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp">
<Filter>arm\interpreter\vfp</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\arm1176jzf_s_mmu.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\xscale_copro.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\sa_mmu.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\cache.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\rb.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\tlb.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\wb.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\armcopro.cpp">
<Filter>arm</Filter>
</ClCompile>
<ClCompile Include="arm\interpreter\mmu\maverick.cpp">
<Filter>arm\interpreter\mmu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -152,21 +182,6 @@
<ClInclude Include="arm\interpreter\skyeye_defs.h">
<Filter>arm\interpreter</Filter>
</ClInclude>
<ClInclude Include="arm\mmu\arm1176jzf_s_mmu.h">
<Filter>arm\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\mmu\cache.h">
<Filter>arm\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\mmu\rb.h">
<Filter>arm\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\mmu\tlb.h">
<Filter>arm\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\mmu\wb.h">
<Filter>arm\mmu</Filter>
</ClInclude>
<ClInclude Include="file_sys\directory_file_system.h">
<Filter>file_sys</Filter>
</ClInclude>
@ -232,11 +247,32 @@
<ClInclude Include="hle\config_mem.h">
<Filter>hle</Filter>
</ClInclude>
<ClInclude Include="hle\kernel\thread.h">
<Filter>hle\kernel</Filter>
<ClInclude Include="arm\interpreter\vfp\asm_vfp.h">
<Filter>arm\interpreter\vfp</Filter>
</ClInclude>
<ClInclude Include="hle\kernel\kernel.h">
<Filter>hle\kernel</Filter>
<ClInclude Include="arm\interpreter\vfp\vfp.h">
<Filter>arm\interpreter\vfp</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\vfp\vfp_helper.h">
<Filter>arm\interpreter\vfp</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\mmu\arm1176jzf_s_mmu.h">
<Filter>arm\interpreter\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\mmu\cache.h">
<Filter>arm\interpreter\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\mmu\rb.h">
<Filter>arm\interpreter\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\mmu\tlb.h">
<Filter>arm\interpreter\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\mmu\wb.h">
<Filter>arm\interpreter\mmu</Filter>
</ClInclude>
<ClInclude Include="arm\interpreter\mmu\sa_mmu.h">
<Filter>arm\interpreter\mmu</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>

View file

@ -9,42 +9,26 @@
namespace HLE {
/// Data synchronization barrier
u32 DataSynchronizationBarrier() {
return 0;
}
/// Returns the coprocessor (in this case, syscore) command buffer pointer
Addr GetThreadCommandBuffer() {
// Called on insruction: mrc p15, 0, r0, c13, c0, 3
return Memory::KERNEL_MEMORY_VADDR;
}
/// Call an MCR (move to coprocessor from ARM register) instruction in HLE
s32 CallMCR(u32 instruction, u32 value) {
CoprocessorOperation operation = (CoprocessorOperation)((instruction >> 20) & 0xFF);
ERROR_LOG(OSHLE, "unimplemented MCR instruction=0x%08X, operation=%02X, value=%08X",
instruction, operation, value);
return 0;
}
/// Call an MRC (move to ARM register from coprocessor) instruction in HLE
s32 CallMRC(u32 instruction) {
CoprocessorOperation operation = (CoprocessorOperation)((instruction >> 20) & 0xFF);
switch (operation) {
case DATA_SYNCHRONIZATION_BARRIER:
return DataSynchronizationBarrier();
case CALL_GET_THREAD_COMMAND_BUFFER:
return GetThreadCommandBuffer();
default:
ERROR_LOG(OSHLE, "unimplemented MRC instruction 0x%08X", instruction);
//DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction);
break;
}
return 0;
return -1;
}
} // namespace

View file

@ -14,9 +14,6 @@ enum CoprocessorOperation {
CALL_GET_THREAD_COMMAND_BUFFER = 0xE1,
};
/// Call an MCR (move to coprocessor from ARM register) instruction in HLE
s32 CallMCR(u32 instruction, u32 value);
/// Call an MRC (move to ARM register from coprocessor) instruction in HLE
s32 CallMRC(u32 instruction);