summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2010-06-02 12:58:00 -0500
committerGabe Black <gblack@eecs.umich.edu>2010-06-02 12:58:00 -0500
commit96be7e16c15deecc167f99b0d6ba9fe81617197f (patch)
tree6551e060c640d456227b64ad028ca895c18730d0 /src
parentf49cdb4f5d8c9740e5f021ad5704a4586e88f6c3 (diff)
downloadgem5-96be7e16c15deecc167f99b0d6ba9fe81617197f.tar.xz
ARM: Make the predecoder handle Thumb instructions.
Diffstat (limited to 'src')
-rw-r--r--src/arch/arm/SConscript14
-rw-r--r--src/arch/arm/predecoder.hh98
-rw-r--r--src/cpu/simple/base.cc2
3 files changed, 99 insertions, 15 deletions
diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript
index 92a4193f1..c1a08aa49 100644
--- a/src/arch/arm/SConscript
+++ b/src/arch/arm/SConscript
@@ -1,9 +1,20 @@
# -*- mode:python -*-
-# Copyright (c) 2007-2008 The Florida State University
# Copyright (c) 2009 ARM Limited
# All rights reserved.
#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Copyright (c) 2007-2008 The Florida State University
+# All rights reserved.
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
@@ -52,6 +63,7 @@ if env['TARGET_ISA'] == 'arm':
TraceFlag('Arm')
TraceFlag('Faults', "Trace Exceptions, interrupts, svc/swi")
+ TraceFlag('Predecoder', "Instructions returned by the predecoder")
if env['FULL_SYSTEM']:
Source('interrupts.cc')
Source('stacktrace.cc')
diff --git a/src/arch/arm/predecoder.hh b/src/arch/arm/predecoder.hh
index b21b77320..2438f0378 100644
--- a/src/arch/arm/predecoder.hh
+++ b/src/arch/arm/predecoder.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* Copyright (c) 2007-2008 The Florida State University
* All rights reserved.
@@ -47,9 +59,13 @@ namespace ArmISA
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
+ MachInst data;
+ bool bigThumb;
+ int offset;
public:
- Predecoder(ThreadContext * _tc) : tc(_tc)
+ Predecoder(ThreadContext * _tc) :
+ tc(_tc), data(0), bigThumb(false), offset(0)
{}
ThreadContext * getTC()
@@ -62,20 +78,67 @@ namespace ArmISA
tc = _tc;
}
- void process()
- {}
-
void reset()
- {}
+ {
+ bigThumb = false;
+ offset = 0;
+ emi = 0;
+ }
+
+ void process()
+ {
+ if (!emi.thumb) {
+ emi.instBits = data;
+ emi.sevenAndFour = bits(data, 7) && bits(data, 4);
+ emi.isMisc = (bits(data, 24, 23) == 0x2 &&
+ bits(data, 20) == 0);
+ DPRINTF(Predecoder, "Arm inst.\n");
+ } else {
+ uint16_t word = (data >> (offset * 8));
+ if (bigThumb) {
+ // A 32 bit thumb inst is half collected.
+ emi.instBits = emi.instBits | word;
+ bigThumb = false;
+ offset += 2;
+ DPRINTF(Predecoder, "Second half of 32 bit Thumb.\n");
+ } else {
+ uint16_t highBits = word & 0xF800;
+ if (highBits == 0xE800 || highBits == 0xF000 ||
+ highBits == 0xF800) {
+ // The start of a 32 bit thumb inst.
+ emi.bigThumb = 1;
+ if (offset == 0) {
+ // We've got the whole thing.
+ DPRINTF(Predecoder,
+ "All of 32 bit Thumb.\n");
+ emi.instBits = (data >> 16) | (data << 16);
+ offset += 4;
+ } else {
+ // We only have the first half word.
+ DPRINTF(Predecoder,
+ "First half of 32 bit Thumb.\n");
+ emi.instBits = (uint32_t)word << 16;
+ bigThumb = true;
+ offset += 2;
+ }
+ } else {
+ // A 16 bit thumb inst.
+ DPRINTF(Predecoder, "16 bit Thumb.\n");
+ offset += 2;
+ emi.instBits = word;
+ }
+ }
+ }
+ }
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void moreBytes(Addr pc, Addr fetchPC, MachInst inst)
{
- emi = inst;
- emi.thumb = (pc & (ULL(1) << PcTBitShift));
- emi.sevenAndFour = bits(inst, 7) && bits(inst, 4);
- emi.isMisc = (bits(inst, 24, 23) == 0x2 && bits(inst, 20) == 0);
+ data = inst;
+ offset = (fetchPC >= pc) ? 0 : pc - fetchPC;
+ emi.thumb = (pc & (ULL(1) << PcTBitShift)) ? 1 : 0;
+ process();
}
//Use this to give data to the predecoder. This should be used
@@ -87,18 +150,27 @@ namespace ArmISA
bool needMoreBytes()
{
- return true;
+ return sizeof(MachInst) > offset;
}
bool extMachInstReady()
{
- return true;
+ // The only way an instruction wouldn't be ready is if this is a
+ // 32 bit ARM instruction that's not 32 bit aligned.
+ return !bigThumb;
+ }
+
+ int getInstSize()
+ {
+ return (!emi.thumb || emi.bigThumb) ? 4 : 2;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
- const ExtMachInst & getExtMachInst()
+ ExtMachInst getExtMachInst()
{
- return emi;
+ ExtMachInst thisEmi = emi;
+ emi = 0;
+ return thisEmi;
}
};
};
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
index 17ba6a10b..d15b84bd6 100644
--- a/src/cpu/simple/base.cc
+++ b/src/cpu/simple/base.cc
@@ -410,7 +410,7 @@ BaseSimpleCPU::preExecute()
//If an instruction is ready, decode it. Otherwise, we'll have to
//fetch beyond the MachInst at the current pc.
if (predecoder.extMachInstReady()) {
-#if THE_ISA == X86_ISA
+#if THE_ISA == X86_ISA || THE_ISA == ARM_ISA
thread->setNextPC(thread->readPC() + predecoder.getInstSize());
#endif // X86_ISA
stayAtPC = false;