12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427 |
- /* 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 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
- #include "armdefs.h"
- #include "armos.h"
- #include "armemu.h"
- #include "ansidecl.h"
- #include "iwmmxt.h"
- /* Dummy Co-processors. */
- static unsigned
- NoCoPro3R (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned a ATTRIBUTE_UNUSED,
- ARMword b ATTRIBUTE_UNUSED)
- {
- return ARMul_CANT;
- }
- static unsigned
- NoCoPro4R (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned a ATTRIBUTE_UNUSED,
- ARMword b ATTRIBUTE_UNUSED,
- ARMword c ATTRIBUTE_UNUSED)
- {
- return ARMul_CANT;
- }
- static unsigned
- NoCoPro4W (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned a ATTRIBUTE_UNUSED,
- ARMword b ATTRIBUTE_UNUSED,
- ARMword * c ATTRIBUTE_UNUSED)
- {
- 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 ATTRIBUTE_UNUSED)
- {
- 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. */
- XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000;
- /* 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 TRUE;
- }
- /* 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. */
- 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;
- }
- /* Store a value into one of coprocessor 15's registers. */
- static void
- write_cp15_reg (ARMul_State * state,
- unsigned reg,
- unsigned opcode_2,
- unsigned CRm,
- ARMword value)
- {
- if (opcode_2)
- {
- switch (reg)
- {
- case 0: /* Cache Type. */
- /* Writes are not allowed. */
- return;
- case 1: /* Auxillary Control. */
- /* Only BITS (5, 4) and BITS (1, 0) can be written. */
- value &= 0x33;
- break;
- default:
- return;
- }
- XScale_cp15_opcode_2_is_not_0_Regs [reg] = value;
- }
- else
- {
- switch (reg)
- {
- case 0: /* ID. */
- /* Writes are not allowed. */
- return;
- case 1: /* ARM Control. */
- /* Only BITS (13, 11), BITS (9, 7) and BITS (2, 0) can be written.
- BITS (31, 14) and BIT (10) write as zero, BITS (6, 3) write as one. */
- value &= 0x00003b87;
- value |= 0x00000078;
- /* Change the endianness if necessary. */
- if ((value & ARMul_CP15_R1_ENDIAN) !=
- (XScale_cp15_opcode_2_is_0_Regs [reg] & ARMul_CP15_R1_ENDIAN))
- {
- state->bigendSig = value & ARMul_CP15_R1_ENDIAN;
- /* Force ARMulator to notice these now. */
- state->Emulate = CHANGEMODE;
- }
- break;
- case 2: /* Translation Table Base. */
- /* Only BITS (31, 14) can be written. */
- value &= 0xffffc000;
- break;
- case 3: /* Domain Access Control. */
- /* All bits writable. */
- break;
- case 5: /* Fault Status Register. */
- /* BITS (10, 9) and BITS (7, 0) can be written. */
- value &= 0x000006ff;
- break;
- case 6: /* Fault Address Register. */
- /* All bits writable. */
- break;
- case 7: /* Cache Functions. */
- case 8: /* TLB Operations. */
- case 10: /* TLB Lock Down. */
- /* Ignore writes. */
- return;
- case 9: /* Data Cache Lock. */
- /* Only BIT (0) can be written. */
- value &= 0x1;
- break;
- case 13: /* Process ID. */
- /* Only BITS (31, 25) are writable. */
- value &= 0xfe000000;
- break;
- case 14: /* DBR0, DBR1, DBCON, IBCR0, IBCR1 */
- /* All bits can be written. Which register is accessed is
- dependent upon CRm. */
- switch (CRm)
- {
- case 0: /* DBR0 */
- break;
- case 3: /* DBR1 */
- XScale_cp15_DBR1 = value;
- break;
- case 4: /* DBCON */
- XScale_cp15_DBCON = value;
- break;
- case 8: /* IBCR0 */
- XScale_cp15_IBCR0 = value;
- break;
- case 9: /* IBCR1 */
- XScale_cp15_IBCR1 = value;
- break;
- default:
- return;
- }
- break;
- case 15: /* Coprpcessor Access Register. */
- /* Access is only valid if CRm == 1. */
- if (CRm != 1)
- return;
- /* Only BITS (13, 0) may be written. */
- value &= 0x00003fff;
- break;
- default:
- return;
- }
- XScale_cp15_opcode_2_is_0_Regs [reg] = value;
- }
- return;
- }
- /* Return the value in a cp15 register. */
- ARMword
- read_cp15_reg (unsigned reg, unsigned opcode_2, unsigned CRm)
- {
- if (opcode_2 == 0)
- {
- if (reg == 15 && CRm != 1)
- return 0;
- if (reg == 14)
- {
- switch (CRm)
- {
- case 3: return XScale_cp15_DBR1;
- case 4: return XScale_cp15_DBCON;
- case 8: return XScale_cp15_IBCR0;
- case 9: return XScale_cp15_IBCR1;
- default:
- break;
- }
- }
- return XScale_cp15_opcode_2_is_0_Regs [reg];
- }
- else
- return XScale_cp15_opcode_2_is_not_0_Regs [reg];
- return 0;
- }
- static unsigned
- XScale_cp15_MRC (ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword * value)
- {
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
- result = check_cp15_access (state, reg, CRm, BITS (21, 23), opcode_2);
- if (result == ARMul_DONE)
- * value = read_cp15_reg (reg, opcode_2, CRm);
- return result;
- }
- static unsigned
- XScale_cp15_MCR (ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword value)
- {
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
- result = check_cp15_access (state, reg, CRm, BITS (21, 23), opcode_2);
- if (result == ARMul_DONE)
- write_cp15_reg (state, reg, opcode_2, CRm, value);
- return result;
- }
- static unsigned
- XScale_cp15_read_reg (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned reg,
- ARMword * value)
- {
- /* FIXME: Not sure what to do about the alternative register set
- here. For now default to just accessing CRm == 0 registers. */
- * value = read_cp15_reg (reg, 0, 0);
- return TRUE;
- }
- static unsigned
- XScale_cp15_write_reg (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned reg,
- ARMword value)
- {
- /* FIXME: Not sure what to do about the alternative register set
- here. For now default to just accessing CRm == 0 registers. */
- write_cp15_reg (state, reg, 0, 0, value);
- return TRUE;
- }
- /* Check for special XScale memory access features. */
- void
- XScale_check_memacc (ARMul_State * state, ARMword * address, int store)
- {
- ARMword dbcon, r0, r1;
- int e1, e0;
- if (!state->is_XScale)
- return;
- /* Check for PID-ification.
- XXX BTB access support will require this test failing. */
- r0 = (read_cp15_reg (13, 0, 0) & 0xfe000000);
- if (r0 && (* address & 0xfe000000) == 0)
- * address |= r0;
- /* Check alignment fault enable/disable. */
- if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN) && (* address & 3))
- {
- /* Set the FSR and FAR.
- Do not use XScale_set_fsr_far as this checks the DCSR register. */
- write_cp15_reg (state, 5, 0, 0, ARMul_CP15_R5_MMU_EXCPT);
- write_cp15_reg (state, 6, 0, 0, * address);
- ARMul_Abort (state, ARMul_DataAbortV);
- }
- if (XScale_debug_moe (state, -1))
- return;
- /* Check the data breakpoint registers. */
- dbcon = read_cp15_reg (14, 0, 4);
- r0 = read_cp15_reg (14, 0, 0);
- r1 = read_cp15_reg (14, 0, 3);
- e0 = dbcon & ARMul_CP15_DBCON_E0;
- if (dbcon & ARMul_CP15_DBCON_M)
- {
- /* r1 is a inverse mask. */
- if (e0 != 0 && ((store && e0 != 3) || (!store && e0 != 1))
- && ((* address & ~r1) == (r0 & ~r1)))
- {
- XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB);
- ARMul_OSHandleSWI (state, SWI_Breakpoint);
- }
- }
- else
- {
- if (e0 != 0 && ((store && e0 != 3) || (!store && e0 != 1))
- && ((* address & ~3) == (r0 & ~3)))
- {
- XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB);
- ARMul_OSHandleSWI (state, SWI_Breakpoint);
- }
- e1 = (dbcon & ARMul_CP15_DBCON_E1) >> 2;
- if (e1 != 0 && ((store && e1 != 3) || (!store && e1 != 1))
- && ((* address & ~3) == (r1 & ~3)))
- {
- XScale_debug_moe (state, ARMul_CP14_R10_MOE_DB);
- ARMul_OSHandleSWI (state, SWI_Breakpoint);
- }
- }
- }
- /* 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)
- return;
- write_cp15_reg (state, 5, 0, 0, fsr);
- write_cp15_reg (state, 6, 0, 0, far);
- }
- /* Set the XScale debug `method of entry' if it is enabled. */
- int
- XScale_debug_moe (ARMul_State * state, int moe)
- {
- ARMword value;
- if (!state->is_XScale)
- return 1;
- value = read_cp14_reg (10);
- if (value & (1UL << 31))
- {
- if (moe != -1)
- {
- value &= ~0x1c;
- value |= moe;
-
- write_cp14_reg (10, value);
- }
- return 1;
- }
- return 0;
- }
- /* 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 ATTRIBUTE_UNUSED)
- {
- int i;
- for (i = 16; i--;)
- {
- XScale_cp13_CR0_Regs[i] = 0;
- XScale_cp13_CR1_Regs[i] = 0;
- }
- return TRUE;
- }
- /* 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. */
- 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;
- }
- /* Store a value into one of coprocessor 13's registers. */
- static void
- write_cp13_reg (unsigned reg, unsigned CRm, ARMword value)
- {
- switch (CRm)
- {
- case 0:
- switch (reg)
- {
- case 0: /* INTCTL */
- /* Only BITS (3:0) can be written. */
- value &= 0xf;
- break;
- case 4: /* INTSRC */
- /* No bits may be written. */
- return;
- case 8: /* INTSTR */
- /* Only BITS (1:0) can be written. */
- value &= 0x3;
- break;
- default:
- /* Should not happen. Ignore any writes to unimplemented registers. */
- return;
- }
- XScale_cp13_CR0_Regs [reg] = value;
- break;
- case 1:
- switch (reg)
- {
- case 0: /* BCUCTL */
- /* Only BITS (30:28) and BITS (3:0) can be written.
- BIT(31) is write ignored. */
- value &= 0x7000000f;
- value |= XScale_cp13_CR1_Regs[0] & (1UL << 31);
- break;
- case 1: /* BCUMOD */
- /* Only bit 0 is accecssible. */
- value &= 1;
- value |= XScale_cp13_CR1_Regs[1] & ~ 1;
- break;
- case 4: /* ELOG0 */
- case 5: /* ELOG1 */
- case 6: /* ECAR0 */
- case 7: /* ECAR1 */
- /* No bits can be written. */
- return;
- case 8: /* ECTST */
- /* Only BITS (7:0) can be written. */
- value &= 0xff;
- break;
- default:
- /* Should not happen. Ignore any writes to unimplemented registers. */
- return;
- }
- XScale_cp13_CR1_Regs [reg] = value;
- break;
- default:
- /* Should not happen. */
- break;
- }
- return;
- }
- /* Return the value in a cp13 register. */
- static ARMword
- read_cp13_reg (unsigned reg, unsigned CRm)
- {
- if (CRm == 0)
- return XScale_cp13_CR0_Regs [reg];
- else if (CRm == 1)
- return XScale_cp13_CR1_Regs [reg];
- return 0;
- }
- static unsigned
- XScale_cp13_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data)
- {
- unsigned reg = BITS (12, 15);
- unsigned result;
- result = check_cp13_access (state, reg, 0, 0, 0);
- if (result == ARMul_DONE && type == ARMul_DATA)
- write_cp13_reg (reg, 0, data);
- return result;
- }
- static unsigned
- XScale_cp13_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * data)
- {
- unsigned reg = BITS (12, 15);
- unsigned result;
- result = check_cp13_access (state, reg, 0, 0, 0);
- if (result == ARMul_DONE && type == ARMul_DATA)
- * data = read_cp13_reg (reg, 0);
- return result;
- }
- static unsigned
- XScale_cp13_MRC (ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword * value)
- {
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
- result = check_cp13_access (state, reg, CRm, BITS (21, 23), BITS (5, 7));
- if (result == ARMul_DONE)
- * value = read_cp13_reg (reg, CRm);
- return result;
- }
- static unsigned
- XScale_cp13_MCR (ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword value)
- {
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
- result = check_cp13_access (state, reg, CRm, BITS (21, 23), BITS (5, 7));
- if (result == ARMul_DONE)
- write_cp13_reg (reg, CRm, value);
- return result;
- }
- static unsigned
- XScale_cp13_read_reg (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned reg,
- ARMword * value)
- {
- /* FIXME: Not sure what to do about the alternative register set
- here. For now default to just accessing CRm == 0 registers. */
- * value = read_cp13_reg (reg, 0);
- return TRUE;
- }
- static unsigned
- XScale_cp13_write_reg (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned reg,
- ARMword value)
- {
- /* FIXME: Not sure what to do about the alternative register set
- here. For now default to just accessing CRm == 0 registers. */
- write_cp13_reg (reg, 0, value);
- return TRUE;
- }
- /* Coprocessor 14: Performance Monitoring, Clock and Power management,
- Software Debug. */
- static ARMword XScale_cp14_Regs[16];
- static unsigned
- XScale_cp14_init (ARMul_State * state ATTRIBUTE_UNUSED)
- {
- int i;
- for (i = 16; i--;)
- XScale_cp14_Regs[i] = 0;
- return TRUE;
- }
- /* 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. */
- 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;
- }
- /* Store a value into one of coprocessor 14's registers. */
- static void
- write_cp14_reg (unsigned reg, ARMword value)
- {
- switch (reg)
- {
- case 0: /* PMNC */
- /* Only BITS (27:12), BITS (10:8) and BITS (6:0) can be written. */
- value &= 0x0ffff77f;
- /* Reset the clock counter if necessary. */
- if (value & ARMul_CP14_R0_CLKRST)
- XScale_cp14_Regs [1] = 0;
- break;
- case 4:
- case 5:
- /* We should not normally reach this code. The debugger interface
- can bypass the normal checks though, so it could happen. */
- value = 0;
- break;
- case 6: /* CCLKCFG */
- /* Only BITS (3:0) can be written. */
- value &= 0xf;
- break;
- case 7: /* PWRMODE */
- /* Although BITS (1:0) can be written with non-zero values, this would
- have the side effect of putting the processor to sleep. Thus in
- order for the register to be read again, it would have to go into
- ACTIVE mode, which means that any read will see these bits as zero.
- Rather than trying to implement complex reset-to-zero-upon-read logic
- we just override the write value with zero. */
- value = 0;
- break;
- case 10: /* DCSR */
- /* Only BITS (31:30), BITS (23:22), BITS (20:16) and BITS (5:0) can
- be written. */
- value &= 0xc0df003f;
- break;
- case 11: /* TBREG */
- /* No writes are permitted. */
- value = 0;
- break;
- case 14: /* TXRXCTRL */
- /* Only BITS (31:30) can be written. */
- value &= 0xc0000000;
- break;
- default:
- /* All bits can be written. */
- break;
- }
- XScale_cp14_Regs [reg] = value;
- }
- /* Return the value in a cp14 register. Not a static function since
- it is used by the code to emulate the BKPT instruction in armemu.c. */
- ARMword
- read_cp14_reg (unsigned reg)
- {
- return XScale_cp14_Regs [reg];
- }
- static unsigned
- XScale_cp14_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data)
- {
- unsigned reg = BITS (12, 15);
- unsigned result;
- result = check_cp14_access (state, reg, 0, 0, 0);
- if (result == ARMul_DONE && type == ARMul_DATA)
- write_cp14_reg (reg, data);
- return result;
- }
- static unsigned
- XScale_cp14_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * data)
- {
- unsigned reg = BITS (12, 15);
- unsigned result;
- result = check_cp14_access (state, reg, 0, 0, 0);
- if (result == ARMul_DONE && type == ARMul_DATA)
- * data = read_cp14_reg (reg);
- return result;
- }
- static unsigned
- XScale_cp14_MRC
- (
- ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword * value
- )
- {
- unsigned reg = BITS (16, 19);
- unsigned result;
- result = check_cp14_access (state, reg, BITS (0, 3), BITS (21, 23), BITS (5, 7));
- if (result == ARMul_DONE)
- * value = read_cp14_reg (reg);
- return result;
- }
- static unsigned
- XScale_cp14_MCR
- (
- ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword value
- )
- {
- unsigned reg = BITS (16, 19);
- unsigned result;
- result = check_cp14_access (state, reg, BITS (0, 3), BITS (21, 23), BITS (5, 7));
- if (result == ARMul_DONE)
- write_cp14_reg (reg, value);
- return result;
- }
- static unsigned
- XScale_cp14_read_reg
- (
- ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned reg,
- ARMword * value
- )
- {
- * value = read_cp14_reg (reg);
- return TRUE;
- }
- static unsigned
- XScale_cp14_write_reg
- (
- ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned reg,
- ARMword value
- )
- {
- write_cp14_reg (reg, value);
- return TRUE;
- }
- /* 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)
- {
- MMUReg[1] = state->prog32Sig << 4 |
- state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7;
- ARMul_ConsolePrint (state, ", MMU present");
- return TRUE;
- }
- static unsigned
- MMUMRC (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword * value)
- {
- int reg = BITS (16, 19) & 7;
- if (reg == 0)
- *value = 0x41440110;
- else
- *value = MMUReg[reg];
- return ARMul_DONE;
- }
- static unsigned
- MMUMCR (ARMul_State * state,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword value)
- {
- int reg = BITS (16, 19) & 7;
- MMUReg[reg] = value;
- if (reg == 1)
- {
- ARMword p,d,l,b;
- p = state->prog32Sig;
- d = state->data32Sig;
- l = state->lateabtSig;
- b = state->bigendSig;
- state->prog32Sig = value >> 4 & 1;
- state->data32Sig = value >> 5 & 1;
- state->lateabtSig = value >> 6 & 1;
- state->bigendSig = value >> 7 & 1;
- if ( p != state->prog32Sig
- || d != state->data32Sig
- || l != state->lateabtSig
- || b != state->bigendSig)
- /* Force ARMulator to notice these now. */
- state->Emulate = CHANGEMODE;
- }
- return ARMul_DONE;
- }
- static unsigned
- MMURead (ARMul_State * state ATTRIBUTE_UNUSED, unsigned reg, ARMword * value)
- {
- if (reg == 0)
- *value = 0x41440110;
- else if (reg < 8)
- *value = MMUReg[reg];
- return TRUE;
- }
- static unsigned
- MMUWrite (ARMul_State * state, unsigned reg, ARMword value)
- {
- if (reg < 8)
- MMUReg[reg] = value;
- if (reg == 1)
- {
- ARMword p,d,l,b;
- p = state->prog32Sig;
- d = state->data32Sig;
- l = state->lateabtSig;
- b = state->bigendSig;
- state->prog32Sig = value >> 4 & 1;
- state->data32Sig = value >> 5 & 1;
- state->lateabtSig = value >> 6 & 1;
- state->bigendSig = value >> 7 & 1;
- if ( p != state->prog32Sig
- || d != state->data32Sig
- || l != state->lateabtSig
- || b != state->bigendSig)
- /* Force ARMulator to notice these now. */
- state->Emulate = CHANGEMODE;
- }
- return TRUE;
- }
- /* 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 ATTRIBUTE_UNUSED,
- 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 ATTRIBUTE_UNUSED,
- 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 ATTRIBUTE_UNUSED,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword * value)
- {
- *value = ValReg[BITS (16, 19)];
- return ARMul_DONE;
- }
- static unsigned
- ValMCR (ARMul_State * state ATTRIBUTE_UNUSED,
- unsigned type ATTRIBUTE_UNUSED,
- ARMword instr,
- ARMword value)
- {
- ValReg[BITS (16, 19)] = value;
- return ARMul_DONE;
- }
- static unsigned
- ValCDP (ARMul_State * state, unsigned type, ARMword instr)
- {
- static unsigned long 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;
- state->Exception++;
- return 0;
- }
- static unsigned
- DoAIRQ (ARMul_State * state)
- {
- state->NirqSig = LOW;
- state->Exception++;
- return 0;
- }
- static unsigned
- IntCDP (ARMul_State * state, unsigned type, ARMword instr)
- {
- static unsigned long 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;
- state->Exception--;
- return ARMul_DONE;
- case 4:
- state->NirqSig = HIGH;
- state->Exception--;
- 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, DSPCDP4, NULL, NULL);
- ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5,
- DSPMRC5, DSPMCR5, DSPCDP5, NULL, NULL);
- ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL,
- DSPMRC6, DSPMCR6, DSPCDP6, NULL, NULL);
- }
- else
- {
- ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC,
- ValMRC, ValMCR, ValCDP, NULL, NULL);
- ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL,
- ValMRC, ValMCR, IntCDP, NULL, NULL);
- }
- if (state->is_XScale)
- {
- ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL,
- XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC,
- XScale_cp13_MCR, NULL, XScale_cp13_read_reg,
- XScale_cp13_write_reg);
- ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL,
- XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC,
- XScale_cp14_MCR, NULL, XScale_cp14_read_reg,
- XScale_cp14_write_reg);
- ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL,
- NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR,
- NULL, XScale_cp15_read_reg, XScale_cp15_write_reg);
- }
- else
- {
- ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
- MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
- }
- 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);
- }
- /* 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_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 (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,
- NoCoPro3R, NULL, NULL);
- state->CPInit[number] = NULL;
- state->CPExit[number] = NULL;
- state->CPRead[number] = NULL;
- state->CPWrite[number] = NULL;
- }
|