* [Qemu-devel] [PATCH 01/48] arm-dis debug helper
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-04-08 19:03 ` Aurelien Jarno
2010-03-26 16:06 ` [Qemu-devel] [PATCH 04/48] audio: fix integer overflow expression Riku Voipio
` (43 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
modified the arm disassembler to include the opcode binary representation along
with the symbolic disassembly.
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
arm-dis.c | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/arm-dis.c b/arm-dis.c
index 4fb899e..2b37c24 100644
--- a/arm-dis.c
+++ b/arm-dis.c
@@ -4101,8 +4101,14 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
In such cases, we can ignore the pc when computing
addresses, since the addend is not currently pc-relative. */
pc = 0;
-
- printer (pc, info, given);
+ if (size == 2) {
+ info->fprintf_func(info->stream, "[%04lx] ",
+ ((unsigned long)given) & 0xffffffff);
+ } else {
+ info->fprintf_func(info->stream, "[%08lx] ",
+ ((unsigned long)given) & 0xffffffff);
+ }
+ printer (pc, info, given);
if (is_thumb)
{
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 01/48] arm-dis debug helper
2010-03-26 16:06 ` [Qemu-devel] [PATCH 01/48] arm-dis debug helper Riku Voipio
@ 2010-04-08 19:03 ` Aurelien Jarno
0 siblings, 0 replies; 55+ messages in thread
From: Aurelien Jarno @ 2010-04-08 19:03 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, Juha Riihimäki, qemu-devel
On Fri, Mar 26, 2010 at 04:06:24PM +0000, Riku Voipio wrote:
> From: Juha Riihimäki <juha.riihimaki@nokia.com>
>
> modified the arm disassembler to include the opcode binary representation along
> with the symbolic disassembly.
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
> Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
> ---
> arm-dis.c | 10 ++++++++--
> 1 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arm-dis.c b/arm-dis.c
> index 4fb899e..2b37c24 100644
> --- a/arm-dis.c
> +++ b/arm-dis.c
> @@ -4101,8 +4101,14 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
> In such cases, we can ignore the pc when computing
> addresses, since the addend is not currently pc-relative. */
> pc = 0;
> -
> - printer (pc, info, given);
> + if (size == 2) {
> + info->fprintf_func(info->stream, "[%04lx] ",
> + ((unsigned long)given) & 0xffffffff);
Is the mask here correct? As far as I understand, we only want to keep
16 bits here.
> + } else {
> + info->fprintf_func(info->stream, "[%08lx] ",
> + ((unsigned long)given) & 0xffffffff);
> + }
> + printer (pc, info, given);
>
> if (is_thumb)
> {
> --
> 1.6.5
>
>
>
>
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 04/48] audio: fix integer overflow expression
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 01/48] arm-dis debug helper Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 05/48] audio: fix coreaudio compilation Riku Voipio
` (42 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
audio/mixeng_template.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h
index 5617705..80af364 100644
--- a/audio/mixeng_template.h
+++ b/audio/mixeng_template.h
@@ -56,7 +56,7 @@ static mixeng_real inline glue (conv_, ET) (IN_T v)
#endif
#else /* !RECIPROCAL */
#ifdef SIGNED
- return nv / (mixeng_real) (IN_MAX - IN_MIN);
+ return nv / (mixeng_real) ((mixeng_real)IN_MAX - (mixeng_real)IN_MIN);
#else
return (nv - HALF) / (mixeng_real) IN_MAX;
#endif
@@ -73,7 +73,7 @@ static IN_T inline glue (clip_, ET) (mixeng_real v)
}
#ifdef SIGNED
- return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
+ return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real)IN_MAX - (mixeng_real)IN_MIN)));
#else
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
#endif
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 05/48] audio: fix coreaudio compilation
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 01/48] arm-dis debug helper Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 04/48] audio: fix integer overflow expression Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 06/48] Get rid of AREG1 and AREG2 Riku Voipio
` (41 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
audio: fix coreaudio compilation on OS X 10.6 and OS X 10.5
---
audio/coreaudio.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 0a26413..4fb6a01 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -47,6 +47,9 @@ typedef struct coreaudioVoiceOut {
pthread_mutex_t mutex;
int isAtexit;
AudioDeviceID outputDeviceID;
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+ AudioDeviceIOProcID ioProcID;
+#endif
UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
int live;
@@ -56,7 +59,7 @@ typedef struct coreaudioVoiceOut {
static void coreaudio_logstatus (OSStatus status)
{
- char *str = "BUG";
+ const char *str = "BUG";
switch(status) {
case kAudioHardwareNoError:
@@ -104,7 +107,7 @@ static void coreaudio_logstatus (OSStatus status)
break;
default:
- AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
+ AUD_log (AUDIO_CAP, "Reason: status code %d\n", status);
return;
}
@@ -148,10 +151,21 @@ static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
{
OSStatus status;
UInt32 result = 0;
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ AudioObjectPropertyAddress propertyAddress = {
+ .mSelector = kAudioDevicePropertyDeviceIsRunning,
+ .mScope = kAudioObjectPropertyScopeGlobal,
+ .mElement = kAudioObjectPropertyElementMaster,
+ };
+ UInt32 resultSize = sizeof(result);
+ status = AudioObjectGetPropertyData(outputDeviceID, &propertyAddress,
+ 0, NULL, &resultSize, &result);
+#else
UInt32 propertySize = sizeof(outputDeviceID);
status = AudioDeviceGetProperty(
outputDeviceID, 0, 0,
kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr(status,
"Could not determine whether Device is playing\n");
@@ -307,10 +321,21 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
/* open default output device */
propertySize = sizeof(core->outputDeviceID);
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ AudioObjectPropertyAddress propertyAddress = {
+ .mSelector = kAudioHardwarePropertyDefaultOutputDevice,
+ .mScope = kAudioObjectPropertyScopeGlobal,
+ .mElement = kAudioObjectPropertyElementMaster,
+ };
+ status = AudioObjectGetPropertyData(kAudioObjectSystemObject,
+ &propertyAddress, 0, NULL,
+ &propertySize, &core->outputDeviceID);
+#else
status = AudioHardwareGetProperty(
kAudioHardwarePropertyDefaultOutputDevice,
&propertySize,
&core->outputDeviceID);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get default output Device\n");
@@ -323,6 +348,11 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
/* get minimum and maximum buffer frame sizes */
propertySize = sizeof(frameRange);
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
+ status = AudioObjectGetPropertyData(core->outputDeviceID, &propertyAddress,
+ 0, NULL, &propertySize, &frameRange);
+#else
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
@@ -330,6 +360,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
kAudioDevicePropertyBufferFrameSizeRange,
&propertySize,
&frameRange);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame range\n");
@@ -350,6 +381,12 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
/* set Buffer Frame Size */
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
+ status = AudioObjectSetPropertyData(core->outputDeviceID, &propertyAddress,
+ 0, NULL, propertySize,
+ &core->audioDevicePropertyBufferFrameSize);
+#else
status = AudioDeviceSetProperty(
core->outputDeviceID,
NULL,
@@ -358,15 +395,22 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
kAudioDevicePropertyBufferFrameSize,
propertySize,
&core->audioDevicePropertyBufferFrameSize);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
- "Could not set device buffer frame size %ld\n",
+ "Could not set device buffer frame size %d\n",
core->audioDevicePropertyBufferFrameSize);
return -1;
}
/* get Buffer Frame Size */
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
+ status = AudioObjectGetPropertyData(core->outputDeviceID, &propertyAddress,
+ 0, NULL, &propertySize,
+ &core->audioDevicePropertyBufferFrameSize);
+#else
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
@@ -374,6 +418,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
kAudioDevicePropertyBufferFrameSize,
&propertySize,
&core->audioDevicePropertyBufferFrameSize);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame size\n");
@@ -383,6 +428,12 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
/* get StreamFormat */
propertySize = sizeof(core->outputStreamBasicDescription);
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
+ status = AudioObjectGetPropertyData(core->outputDeviceID, &propertyAddress,
+ 0, NULL, &propertySize,
+ &core->outputStreamBasicDescription);
+#else
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
@@ -390,6 +441,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
kAudioDevicePropertyStreamFormat,
&propertySize,
&core->outputStreamBasicDescription);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get Device Stream properties\n");
@@ -400,6 +452,12 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
/* set Samplerate */
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
propertySize = sizeof(core->outputStreamBasicDescription);
+#if MAC_OS_X_VERSION_MIN_REQUIRED>MAC_OS_X_VERSION_10_5
+ propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
+ status = AudioObjectSetPropertyData(core->outputDeviceID, &propertyAddress,
+ 0, NULL, propertySize,
+ &core->outputStreamBasicDescription);
+#else
status = AudioDeviceSetProperty(
core->outputDeviceID,
0,
@@ -408,6 +466,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
kAudioDevicePropertyStreamFormat,
propertySize,
&core->outputStreamBasicDescription);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
as->freq);
@@ -416,7 +475,14 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
}
/* set Callback */
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+ status = AudioDeviceCreateIOProcID(core->outputDeviceID,
+ audioDeviceIOProc,
+ hw,
+ &core->ioProcID);
+#else
status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
core->outputDeviceID = kAudioDeviceUnknown;
@@ -428,7 +494,11 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not start playback\n");
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+ AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioProcID);
+#else
AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
+#endif
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
@@ -453,8 +523,13 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
}
/* remove callback */
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+ status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
+ core->ioProcID);
+#else
status = AudioDeviceRemoveIOProc(core->outputDeviceID,
audioDeviceIOProc);
+#endif
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not remove IOProc\n");
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 06/48] Get rid of AREG1 and AREG2.
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (2 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 05/48] audio: fix coreaudio compilation Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 22:22 ` Aurelien Jarno
2010-03-26 16:06 ` [Qemu-devel] [PATCH 07/48] Shrink tb_jmp_offset to two entries, the other two are never used Riku Voipio
` (40 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Filip Navara, Riku Voipio
From: Filip Navara <filip.navara@gmail.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Filip Navara <filip.navara@gmail.com>
---
dyngen-exec.h | 26 --------------------------
tcg/arm/tcg-target.h | 2 --
tcg/hppa/tcg-target.h | 2 --
tcg/i386/tcg-target.h | 2 --
tcg/ppc/tcg-target.h | 2 --
tcg/ppc64/tcg-target.h | 2 --
tcg/sparc/tcg-target.h | 6 ------
tcg/x86_64/tcg-target.h | 2 --
8 files changed, 0 insertions(+), 44 deletions(-)
diff --git a/dyngen-exec.h b/dyngen-exec.h
index 0353f36..d04eda8 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -50,62 +50,36 @@ extern int printf(const char *, ...);
#if defined(__i386__)
#define AREG0 "ebp"
-#define AREG1 "ebx"
-#define AREG2 "esi"
#elif defined(__x86_64__)
#define AREG0 "r14"
-#define AREG1 "r15"
-#define AREG2 "r12"
#elif defined(_ARCH_PPC)
#define AREG0 "r27"
-#define AREG1 "r24"
-#define AREG2 "r25"
#elif defined(__arm__)
#define AREG0 "r7"
-#define AREG1 "r4"
-#define AREG2 "r5"
#elif defined(__hppa__)
#define AREG0 "r17"
-#define AREG1 "r14"
-#define AREG2 "r15"
#elif defined(__mips__)
#define AREG0 "fp"
-#define AREG1 "s0"
-#define AREG2 "s1"
#elif defined(__sparc__)
#ifdef CONFIG_SOLARIS
#define AREG0 "g2"
-#define AREG1 "g3"
-#define AREG2 "g4"
#else
#ifdef __sparc_v9__
#define AREG0 "g5"
-#define AREG1 "g6"
-#define AREG2 "g7"
#else
#define AREG0 "g6"
-#define AREG1 "g1"
-#define AREG2 "g2"
#endif
#endif
#elif defined(__s390__)
#define AREG0 "r10"
-#define AREG1 "r7"
-#define AREG2 "r8"
#elif defined(__alpha__)
/* Note $15 is the frame pointer, so anything in op-i386.c that would
require a frame pointer, like alloca, would probably loose. */
#define AREG0 "$15"
-#define AREG1 "$9"
-#define AREG2 "$10"
#elif defined(__mc68000)
#define AREG0 "%a5"
-#define AREG1 "%a4"
-#define AREG2 "%d7"
#elif defined(__ia64__)
#define AREG0 "r7"
-#define AREG1 "r4"
-#define AREG2 "r5"
#else
#error unsupported CPU
#endif
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 4cad967..7242be8 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -73,8 +73,6 @@ enum {
enum {
/* Note: must be synced with dyngen-exec.h */
TCG_AREG0 = TCG_REG_R7,
- TCG_AREG1 = TCG_REG_R4,
- TCG_AREG2 = TCG_REG_R5,
};
static inline void flush_icache_range(unsigned long start, unsigned long stop)
diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h
index fa39bfc..e956e71 100644
--- a/tcg/hppa/tcg-target.h
+++ b/tcg/hppa/tcg-target.h
@@ -83,8 +83,6 @@ enum {
/* Note: must be synced with dyngen-exec.h */
#define TCG_AREG0 TCG_REG_R17
-#define TCG_AREG1 TCG_REG_R14
-#define TCG_AREG2 TCG_REG_R15
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index e994fd5..7bb765e 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -62,8 +62,6 @@ enum {
/* Note: must be synced with dyngen-exec.h */
#define TCG_AREG0 TCG_REG_EBP
-#define TCG_AREG1 TCG_REG_EBX
-#define TCG_AREG2 TCG_REG_ESI
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 0c71a11..5cae81f 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -91,7 +91,5 @@ enum {
#define TCG_TARGET_HAS_orc_i32
#define TCG_AREG0 TCG_REG_R27
-#define TCG_AREG1 TCG_REG_R24
-#define TCG_AREG2 TCG_REG_R25
#define TCG_TARGET_HAS_GUEST_BASE
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index f5de642..e367751 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -98,7 +98,5 @@ enum {
/* #define TCG_TARGET_HAS_orc_i64 */
#define TCG_AREG0 TCG_REG_R27
-#define TCG_AREG1 TCG_REG_R24
-#define TCG_AREG2 TCG_REG_R25
#define TCG_TARGET_HAS_GUEST_BASE
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index dbc574d..6c818aa 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -122,16 +122,10 @@ enum {
/* Note: must be synced with dyngen-exec.h and Makefile.target */
#ifdef CONFIG_SOLARIS
#define TCG_AREG0 TCG_REG_G2
-#define TCG_AREG1 TCG_REG_G3
-#define TCG_AREG2 TCG_REG_G4
#elif defined(__sparc_v9__)
#define TCG_AREG0 TCG_REG_G5
-#define TCG_AREG1 TCG_REG_G6
-#define TCG_AREG2 TCG_REG_G7
#else
#define TCG_AREG0 TCG_REG_G6
-#define TCG_AREG1 TCG_REG_G1
-#define TCG_AREG2 TCG_REG_G2
#endif
static inline void flush_icache_range(unsigned long start, unsigned long stop)
diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
index d1e8b9e..02448b5 100644
--- a/tcg/x86_64/tcg-target.h
+++ b/tcg/x86_64/tcg-target.h
@@ -89,8 +89,6 @@ enum {
/* Note: must be synced with dyngen-exec.h */
#define TCG_AREG0 TCG_REG_R14
-#define TCG_AREG1 TCG_REG_R15
-#define TCG_AREG2 TCG_REG_R12
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 06/48] Get rid of AREG1 and AREG2.
2010-03-26 16:06 ` [Qemu-devel] [PATCH 06/48] Get rid of AREG1 and AREG2 Riku Voipio
@ 2010-03-26 22:22 ` Aurelien Jarno
0 siblings, 0 replies; 55+ messages in thread
From: Aurelien Jarno @ 2010-03-26 22:22 UTC (permalink / raw)
To: Riku Voipio; +Cc: Filip Navara, Riku Voipio, qemu-devel
On Fri, Mar 26, 2010 at 04:06:27PM +0000, Riku Voipio wrote:
> From: Filip Navara <filip.navara@gmail.com>
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
> Signed-off-by: Filip Navara <filip.navara@gmail.com>
> ---
> dyngen-exec.h | 26 --------------------------
> tcg/arm/tcg-target.h | 2 --
> tcg/hppa/tcg-target.h | 2 --
> tcg/i386/tcg-target.h | 2 --
> tcg/ppc/tcg-target.h | 2 --
> tcg/ppc64/tcg-target.h | 2 --
> tcg/sparc/tcg-target.h | 6 ------
> tcg/x86_64/tcg-target.h | 2 --
> 8 files changed, 0 insertions(+), 44 deletions(-)
I have just merged the patch from Paolo Bonzini posted a few weeks ago
doing exactly the same thing.
> diff --git a/dyngen-exec.h b/dyngen-exec.h
> index 0353f36..d04eda8 100644
> --- a/dyngen-exec.h
> +++ b/dyngen-exec.h
> @@ -50,62 +50,36 @@ extern int printf(const char *, ...);
>
> #if defined(__i386__)
> #define AREG0 "ebp"
> -#define AREG1 "ebx"
> -#define AREG2 "esi"
> #elif defined(__x86_64__)
> #define AREG0 "r14"
> -#define AREG1 "r15"
> -#define AREG2 "r12"
> #elif defined(_ARCH_PPC)
> #define AREG0 "r27"
> -#define AREG1 "r24"
> -#define AREG2 "r25"
> #elif defined(__arm__)
> #define AREG0 "r7"
> -#define AREG1 "r4"
> -#define AREG2 "r5"
> #elif defined(__hppa__)
> #define AREG0 "r17"
> -#define AREG1 "r14"
> -#define AREG2 "r15"
> #elif defined(__mips__)
> #define AREG0 "fp"
> -#define AREG1 "s0"
> -#define AREG2 "s1"
> #elif defined(__sparc__)
> #ifdef CONFIG_SOLARIS
> #define AREG0 "g2"
> -#define AREG1 "g3"
> -#define AREG2 "g4"
> #else
> #ifdef __sparc_v9__
> #define AREG0 "g5"
> -#define AREG1 "g6"
> -#define AREG2 "g7"
> #else
> #define AREG0 "g6"
> -#define AREG1 "g1"
> -#define AREG2 "g2"
> #endif
> #endif
> #elif defined(__s390__)
> #define AREG0 "r10"
> -#define AREG1 "r7"
> -#define AREG2 "r8"
> #elif defined(__alpha__)
> /* Note $15 is the frame pointer, so anything in op-i386.c that would
> require a frame pointer, like alloca, would probably loose. */
> #define AREG0 "$15"
> -#define AREG1 "$9"
> -#define AREG2 "$10"
> #elif defined(__mc68000)
> #define AREG0 "%a5"
> -#define AREG1 "%a4"
> -#define AREG2 "%d7"
> #elif defined(__ia64__)
> #define AREG0 "r7"
> -#define AREG1 "r4"
> -#define AREG2 "r5"
> #else
> #error unsupported CPU
> #endif
> diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
> index 4cad967..7242be8 100644
> --- a/tcg/arm/tcg-target.h
> +++ b/tcg/arm/tcg-target.h
> @@ -73,8 +73,6 @@ enum {
> enum {
> /* Note: must be synced with dyngen-exec.h */
> TCG_AREG0 = TCG_REG_R7,
> - TCG_AREG1 = TCG_REG_R4,
> - TCG_AREG2 = TCG_REG_R5,
> };
>
> static inline void flush_icache_range(unsigned long start, unsigned long stop)
> diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h
> index fa39bfc..e956e71 100644
> --- a/tcg/hppa/tcg-target.h
> +++ b/tcg/hppa/tcg-target.h
> @@ -83,8 +83,6 @@ enum {
>
> /* Note: must be synced with dyngen-exec.h */
> #define TCG_AREG0 TCG_REG_R17
> -#define TCG_AREG1 TCG_REG_R14
> -#define TCG_AREG2 TCG_REG_R15
>
> static inline void flush_icache_range(unsigned long start, unsigned long stop)
> {
> diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
> index e994fd5..7bb765e 100644
> --- a/tcg/i386/tcg-target.h
> +++ b/tcg/i386/tcg-target.h
> @@ -62,8 +62,6 @@ enum {
>
> /* Note: must be synced with dyngen-exec.h */
> #define TCG_AREG0 TCG_REG_EBP
> -#define TCG_AREG1 TCG_REG_EBX
> -#define TCG_AREG2 TCG_REG_ESI
>
> static inline void flush_icache_range(unsigned long start, unsigned long stop)
> {
> diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
> index 0c71a11..5cae81f 100644
> --- a/tcg/ppc/tcg-target.h
> +++ b/tcg/ppc/tcg-target.h
> @@ -91,7 +91,5 @@ enum {
> #define TCG_TARGET_HAS_orc_i32
>
> #define TCG_AREG0 TCG_REG_R27
> -#define TCG_AREG1 TCG_REG_R24
> -#define TCG_AREG2 TCG_REG_R25
>
> #define TCG_TARGET_HAS_GUEST_BASE
> diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
> index f5de642..e367751 100644
> --- a/tcg/ppc64/tcg-target.h
> +++ b/tcg/ppc64/tcg-target.h
> @@ -98,7 +98,5 @@ enum {
> /* #define TCG_TARGET_HAS_orc_i64 */
>
> #define TCG_AREG0 TCG_REG_R27
> -#define TCG_AREG1 TCG_REG_R24
> -#define TCG_AREG2 TCG_REG_R25
>
> #define TCG_TARGET_HAS_GUEST_BASE
> diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
> index dbc574d..6c818aa 100644
> --- a/tcg/sparc/tcg-target.h
> +++ b/tcg/sparc/tcg-target.h
> @@ -122,16 +122,10 @@ enum {
> /* Note: must be synced with dyngen-exec.h and Makefile.target */
> #ifdef CONFIG_SOLARIS
> #define TCG_AREG0 TCG_REG_G2
> -#define TCG_AREG1 TCG_REG_G3
> -#define TCG_AREG2 TCG_REG_G4
> #elif defined(__sparc_v9__)
> #define TCG_AREG0 TCG_REG_G5
> -#define TCG_AREG1 TCG_REG_G6
> -#define TCG_AREG2 TCG_REG_G7
> #else
> #define TCG_AREG0 TCG_REG_G6
> -#define TCG_AREG1 TCG_REG_G1
> -#define TCG_AREG2 TCG_REG_G2
> #endif
>
> static inline void flush_icache_range(unsigned long start, unsigned long stop)
> diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
> index d1e8b9e..02448b5 100644
> --- a/tcg/x86_64/tcg-target.h
> +++ b/tcg/x86_64/tcg-target.h
> @@ -89,8 +89,6 @@ enum {
>
> /* Note: must be synced with dyngen-exec.h */
> #define TCG_AREG0 TCG_REG_R14
> -#define TCG_AREG1 TCG_REG_R15
> -#define TCG_AREG2 TCG_REG_R12
>
> static inline void flush_icache_range(unsigned long start, unsigned long stop)
> {
> --
> 1.6.5
>
>
>
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 07/48] Shrink tb_jmp_offset to two entries, the other two are never used.
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (3 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 06/48] Get rid of AREG1 and AREG2 Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 08/48] Cortex-A8 R2 support and trustzone Riku Voipio
` (39 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Filip Navara, Riku Voipio
From: Filip Navara <filip.navara@gmail.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Filip Navara <filip.navara@gmail.com>
---
exec-all.h | 5 +----
translate-all.c | 4 ----
2 files changed, 1 insertions(+), 8 deletions(-)
diff --git a/exec-all.h b/exec-all.h
index 37da2f5..b9f0294 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -143,7 +143,7 @@ struct TranslationBlock {
the code of this one. */
uint16_t tb_next_offset[2]; /* offset of original jump target */
#ifdef USE_DIRECT_JUMP
- uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
+ uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
#else
unsigned long tb_next[2]; /* address of jump generated code */
#endif
@@ -234,9 +234,6 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
offset = tb->tb_jmp_offset[n];
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
- offset = tb->tb_jmp_offset[n + 2];
- if (offset != 0xffff)
- tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
}
#else
diff --git a/translate-all.c b/translate-all.c
index 8ef8a0b..8c3f666 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -103,10 +103,6 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
#ifdef USE_DIRECT_JUMP
s->tb_jmp_offset = tb->tb_jmp_offset;
s->tb_next = NULL;
- /* the following two entries are optional (only used for string ops) */
- /* XXX: not used ? */
- tb->tb_jmp_offset[2] = 0xffff;
- tb->tb_jmp_offset[3] = 0xffff;
#else
s->tb_jmp_offset = NULL;
s->tb_next = tb->tb_next;
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 08/48] Cortex-A8 R2 support and trustzone
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (4 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 07/48] Shrink tb_jmp_offset to two entries, the other two are never used Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 09/48] console change headers Riku Voipio
` (38 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/cpu.h | 7 +-
target-arm/helper.c | 330 +++++++++++++++++++++++++++++++++------------------
2 files changed, 220 insertions(+), 117 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 3892db4..3c5e181 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -110,6 +110,9 @@ typedef struct CPUARMState {
uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
+ uint32_t c1_secfg; /* Secure configuration register. */
+ uint32_t c1_sedbg; /* Secure debug enable register. */
+ uint32_t c1_nseac; /* Non-secure access control register. */
uint32_t c2_base0; /* MMU translation table base 0. */
uint32_t c2_base1; /* MMU translation table base 1. */
uint32_t c2_control; /* MMU translation table base control. */
@@ -345,7 +348,8 @@ enum arm_features {
ARM_FEATURE_DIV,
ARM_FEATURE_M, /* Microcontroller profile. */
ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
- ARM_FEATURE_THUMB2EE
+ ARM_FEATURE_THUMB2EE,
+ ARM_FEATURE_TRUSTZONE /* TrustZone Security Extensions. */
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -392,6 +396,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define ARM_CPUID_ARM1136_R2 0x4107b362
#define ARM_CPUID_ARM11MPCORE 0x410fb022
#define ARM_CPUID_CORTEXA8 0x410fc080
+#define ARM_CPUID_CORTEXA8_R2 0x412fc083
#define ARM_CPUID_CORTEXA9 0x410fc090
#define ARM_CPUID_CORTEXM3 0x410fc231
#define ARM_CPUID_ANY 0xffffffff
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 18e22b1..99c5b12 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -21,6 +21,9 @@ static uint32_t cortexa8_cp15_c0_c1[8] =
static uint32_t cortexa8_cp15_c0_c2[8] =
{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
+static uint32_t cortexa8r2_cp15_c0_c2[8] =
+{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00011142, 0, 0, 0 };
+
static uint32_t mpcore_cp15_c0_c1[8] =
{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
@@ -96,6 +99,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
set_feature(env, ARM_FEATURE_VFP3);
set_feature(env, ARM_FEATURE_NEON);
set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_TRUSTZONE);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
@@ -107,6 +111,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
break;
+ case ARM_CPUID_CORTEXA8_R2:
+ set_feature(env, ARM_FEATURE_V6);
+ set_feature(env, ARM_FEATURE_V6K);
+ set_feature(env, ARM_FEATURE_V7);
+ set_feature(env, ARM_FEATURE_AUXCR);
+ set_feature(env, ARM_FEATURE_THUMB2);
+ set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_VFP3);
+ set_feature(env, ARM_FEATURE_NEON);
+ set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_TRUSTZONE);
+ env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c2;
+ env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
+ env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011111;
+ memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
+ memcpy(env->cp15.c0_c2, cortexa8r2_cp15_c0_c2, 8 * sizeof(uint32_t));
+ env->cp15.c0_cachetype = 0x82048004;
+ env->cp15.c0_clid = (1 << 27) | (2 << 24) | (4 << 3) | 3;
+ env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+ env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+ env->cp15.c0_ccsid[2] = 0xf03fe03a; /* 256k L2 cache. */
+ break;
case ARM_CPUID_CORTEXA9:
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_V6K);
@@ -118,6 +144,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
set_feature(env, ARM_FEATURE_VFP_FP16);
set_feature(env, ARM_FEATURE_NEON);
set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_TRUSTZONE);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
@@ -314,6 +341,7 @@ static const struct arm_cpu_t arm_cpu_names[] = {
{ ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
{ ARM_CPUID_CORTEXM3, "cortex-m3"},
{ ARM_CPUID_CORTEXA8, "cortex-a8"},
+ { ARM_CPUID_CORTEXA8_R2, "cortex-a8-r2"},
{ ARM_CPUID_CORTEXA9, "cortex-a9"},
{ ARM_CPUID_TI925T, "ti925t" },
{ ARM_CPUID_PXA250, "pxa250" },
@@ -1003,7 +1031,7 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
table = get_level1_table_address(env, address);
desc = ldl_phys(table);
type = (desc & 3);
- if (type == 0) {
+ if (type == 0 || type == 3) {
/* Section translation fault. */
code = 5;
domain = 0;
@@ -1295,30 +1323,60 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
}
goto bad_reg;
case 1: /* System configuration. */
- if (arm_feature(env, ARM_FEATURE_OMAPCP))
- op2 = 0;
- switch (op2) {
+ switch (crm) {
case 0:
- if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
- env->cp15.c1_sys = val;
- /* ??? Lots of these bits are not implemented. */
- /* This may enable/disable the MMU, so do a TLB flush. */
- tlb_flush(env, 1);
- break;
- case 1: /* Auxiliary cotrol register. */
- if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- env->cp15.c1_xscaleauxcr = val;
+ if (arm_feature(env, ARM_FEATURE_OMAPCP))
+ op2 = 0;
+ switch (op2) {
+ case 0:
+ if (!arm_feature(env, ARM_FEATURE_XSCALE))
+ env->cp15.c1_sys = val;
+ /* ??? Lots of these bits are not implemented. */
+ /* This may enable/disable the MMU, so do a TLB flush. */
+ tlb_flush(env, 1);
+ break;
+ case 1: /* Auxiliary cotrol register. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ env->cp15.c1_xscaleauxcr = val;
+ break;
+ }
+ /* Not implemented. */
+ break;
+ case 2:
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ goto bad_reg;
+ if (env->cp15.c1_coproc != val) {
+ env->cp15.c1_coproc = val;
+ /* ??? Is this safe when called from within a TB? */
+ tb_flush(env);
+ }
break;
+ default:
+ goto bad_reg;
}
- /* Not implemented. */
break;
- case 2:
- if (arm_feature(env, ARM_FEATURE_XSCALE))
+ case 1:
+ if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)
+ || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+ goto bad_reg;
+ switch (op2) {
+ case 0: /* Secure configuration register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ env->cp15.c1_secfg = val;
+ break;
+ case 1: /* Secure debug enable register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ env->cp15.c1_sedbg = val;
+ break;
+ case 2: /* Nonsecure access control register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ env->cp15.c1_nseac = val;
+ break;
+ default:
goto bad_reg;
- if (env->cp15.c1_coproc != val) {
- env->cp15.c1_coproc = val;
- /* ??? Is this safe when called from within a TB? */
- tb_flush(env);
}
break;
default:
@@ -1338,22 +1396,22 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
goto bad_reg;
}
} else {
- switch (op2) {
- case 0:
- env->cp15.c2_base0 = val;
- break;
- case 1:
- env->cp15.c2_base1 = val;
- break;
- case 2:
+ switch (op2) {
+ case 0:
+ env->cp15.c2_base0 = val;
+ break;
+ case 1:
+ env->cp15.c2_base1 = val;
+ break;
+ case 2:
val &= 7;
env->cp15.c2_control = val;
- env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
+ env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val);
- break;
- default:
- goto bad_reg;
- }
+ break;
+ default:
+ goto bad_reg;
+ }
}
break;
case 3: /* MMU Domain access control / MPU write buffer control. */
@@ -1441,26 +1499,26 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
break;
switch (crm) {
case 0: /* Cache lockdown. */
- switch (op1) {
- case 0: /* L1 cache. */
- switch (op2) {
- case 0:
- env->cp15.c9_data = val;
- break;
- case 1:
- env->cp15.c9_insn = val;
- break;
- default:
- goto bad_reg;
- }
- break;
- case 1: /* L2 cache. */
- /* Ignore writes to L2 lockdown/auxiliary registers. */
- break;
- default:
- goto bad_reg;
- }
- break;
+ switch (op1) {
+ case 0: /* L1 cache. */
+ switch (op2) {
+ case 0:
+ env->cp15.c9_data = val;
+ break;
+ case 1:
+ env->cp15.c9_insn = val;
+ break;
+ default:
+ goto bad_reg;
+ }
+ break;
+ case 1: /* L2 cache. */
+ /* Ignore writes to L2 lockdown/auxiliary registers. */
+ break;
+ default:
+ goto bad_reg;
+ }
+ break;
case 1: /* TCM memory region registers. */
/* Not implemented. */
goto bad_reg;
@@ -1561,7 +1619,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
case 0: /* Device ID. */
return env->cp15.c0_cpuid;
case 1: /* Cache Type. */
- return env->cp15.c0_cachetype;
+ return env->cp15.c0_cachetype;
case 2: /* TCM status. */
return 0;
case 3: /* TLB type register. */
@@ -1588,6 +1646,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
default:
goto bad_reg;
}
+ break;
case 1:
/* These registers aren't documented on arm11 cores. However
Linux looks at them anyway. */
@@ -1614,39 +1673,68 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
default:
goto bad_reg;
}
+ break;
case 1: /* System configuration. */
- if (arm_feature(env, ARM_FEATURE_OMAPCP))
- op2 = 0;
- switch (op2) {
- case 0: /* Control register. */
- return env->cp15.c1_sys;
- case 1: /* Auxiliary control register. */
- if (arm_feature(env, ARM_FEATURE_XSCALE))
- return env->cp15.c1_xscaleauxcr;
- if (!arm_feature(env, ARM_FEATURE_AUXCR))
- goto bad_reg;
- switch (ARM_CPUID(env)) {
- case ARM_CPUID_ARM1026:
- return 1;
- case ARM_CPUID_ARM1136:
- case ARM_CPUID_ARM1136_R2:
- return 7;
- case ARM_CPUID_ARM11MPCORE:
- return 1;
- case ARM_CPUID_CORTEXA8:
- return 2;
- case ARM_CPUID_CORTEXA9:
- return 0;
+ switch (crm) {
+ case 0:
+ if (arm_feature(env, ARM_FEATURE_OMAPCP))
+ op2 = 0;
+ switch (op2) {
+ case 0: /* Control register. */
+ return env->cp15.c1_sys;
+ case 1: /* Auxiliary control register. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ return env->cp15.c1_xscaleauxcr;
+ if (!arm_feature(env, ARM_FEATURE_AUXCR))
+ goto bad_reg;
+ switch (ARM_CPUID(env)) {
+ case ARM_CPUID_ARM1026:
+ return 1;
+ case ARM_CPUID_ARM1136:
+ case ARM_CPUID_ARM1136_R2:
+ return 7;
+ case ARM_CPUID_ARM11MPCORE:
+ return 1;
+ case ARM_CPUID_CORTEXA8:
+ case ARM_CPUID_CORTEXA8_R2:
+ return 2;
+ case ARM_CPUID_CORTEXA9:
+ return 0;
+ default:
+ goto bad_reg;
+ }
+ break;
+ case 2: /* Coprocessor access register. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ goto bad_reg;
+ return env->cp15.c1_coproc;
default:
goto bad_reg;
}
- case 2: /* Coprocessor access register. */
- if (arm_feature(env, ARM_FEATURE_XSCALE))
+ break;
+ case 1:
+ if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)
+ || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
goto bad_reg;
- return env->cp15.c1_coproc;
+ switch (op2) {
+ case 0: /* Secure configuration register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ return env->cp15.c1_secfg;
+ case 1: /* Secure debug enable register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ return env->cp15.c1_sedbg;
+ case 2: /* Nonsecure access control register. */
+ return env->cp15.c1_nseac;
+ default:
+ goto bad_reg;
+ }
+ break;
default:
goto bad_reg;
}
+ break;
case 2: /* MMU Page table control / MPU cache control. */
if (arm_feature(env, ARM_FEATURE_MPU)) {
switch (op2) {
@@ -1660,17 +1748,17 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
goto bad_reg;
}
} else {
- switch (op2) {
- case 0:
- return env->cp15.c2_base0;
- case 1:
- return env->cp15.c2_base1;
- case 2:
+ switch (op2) {
+ case 0:
+ return env->cp15.c2_base0;
+ case 1:
+ return env->cp15.c2_base1;
+ case 2:
return env->cp15.c2_control;
- default:
- goto bad_reg;
- }
- }
+ default:
+ goto bad_reg;
+ }
+ }
case 3: /* MMU Domain access control / MPU write buffer control. */
return env->cp15.c3;
case 4: /* Reserved. */
@@ -1706,41 +1794,39 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
} else {
if (arm_feature(env, ARM_FEATURE_OMAPCP))
op2 = 0;
- switch (op2) {
- case 0:
- return env->cp15.c6_data;
- case 1:
- if (arm_feature(env, ARM_FEATURE_V6)) {
- /* Watchpoint Fault Adrress. */
- return 0; /* Not implemented. */
- } else {
- /* Instruction Fault Adrress. */
- /* Arm9 doesn't have an IFAR, but implementing it anyway
- shouldn't do any harm. */
- return env->cp15.c6_insn;
- }
- case 2:
- if (arm_feature(env, ARM_FEATURE_V6)) {
- /* Instruction Fault Adrress. */
- return env->cp15.c6_insn;
- } else {
- goto bad_reg;
- }
- default:
- goto bad_reg;
- }
+ switch (op2) {
+ case 0:
+ return env->cp15.c6_data;
+ case 1:
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ /* Watchpoint Fault Adrress. */
+ return 0; /* Not implemented. */
+ }
+ /* Instruction Fault Adrress. */
+ /* Arm9 doesn't have an IFAR, but implementing it anyway
+ shouldn't do any harm. */
+ return env->cp15.c6_insn;
+ case 2:
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ /* Instruction Fault Adrress. */
+ return env->cp15.c6_insn;
+ }
+ goto bad_reg;
+ default:
+ goto bad_reg;
+ }
}
case 7: /* Cache control. */
- /* FIXME: Should only clear Z flag if destination is r15. */
- env->ZF = 0;
+ if (((insn >> 12) & 0xf) == 0xf) /* clear ZF only if destination is r15 */
+ env->ZF = 0;
return 0;
case 8: /* MMU TLB control. */
goto bad_reg;
case 9: /* Cache lockdown. */
switch (op1) {
case 0: /* L1 cache. */
- if (arm_feature(env, ARM_FEATURE_OMAPCP))
- return 0;
+ if (arm_feature(env, ARM_FEATURE_OMAPCP))
+ return 0;
switch (op2) {
case 0:
return env->cp15.c9_data;
@@ -1762,6 +1848,18 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
return 0;
case 11: /* TCM DMA control. */
case 12: /* Reserved. */
+ if (!op1) {
+ switch (crm) {
+ case 0: /* secure or nonsecure vector base address */
+ if (arm_feature(env, ARM_FEATURE_TRUSTZONE)) {
+ /* FIXME: implement true vector base addressing */
+ return 0; /* reset value according to ARM Cortex-A8 TRM */
+ }
+ break;
+ default:
+ break;
+ }
+ }
goto bad_reg;
case 13: /* Process ID. */
switch (op2) {
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 09/48] console change headers
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (5 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 08/48] Cortex-A8 R2 support and trustzone Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 10/48] Lots of ARM TCG changes Riku Voipio
` (37 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
multitouch, multi-keyboard and window close hook support
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
console.h | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/console.h b/console.h
index 6def115..b1362ff 100644
--- a/console.h
+++ b/console.h
@@ -10,6 +10,7 @@
#define MOUSE_EVENT_LBUTTON 0x01
#define MOUSE_EVENT_RBUTTON 0x02
#define MOUSE_EVENT_MBUTTON 0x04
+extern int multitouch_enabled;
/* identical to the ps/2 keyboard bits */
#define QEMU_SCROLL_LOCK_LED (1 << 0)
@@ -19,6 +20,10 @@
/* in ms */
#define GUI_REFRESH_INTERVAL 30
+typedef int QEMUDisplayCloseCallback(void *opaque);
+void qemu_set_display_close_handler(QEMUDisplayCloseCallback *cb, void *opaque);
+int qemu_run_display_close_handler(void);
+
typedef void QEMUPutKBDEvent(void *opaque, int keycode);
typedef void QEMUPutLEDEvent(void *opaque, int ledstate);
typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
@@ -34,6 +39,13 @@ typedef struct QEMUPutMouseEntry {
/* used internally by qemu for handling mice */
QTAILQ_ENTRY(QEMUPutMouseEntry) node;
} QEMUPutMouseEntry;
+typedef struct QEMUPutKBDEntry {
+ QEMUPutKBDEvent *qemu_put_kbd_event;
+ void *qemu_put_kbd_event_opaque;
+
+ /* used internally by qemu for handling keyboards */
+ struct QEMUPutKBDEntry *next;
+} QEMUPutKBDEntry;
typedef struct QEMUPutLEDEntry {
QEMUPutLEDEvent *put_led;
@@ -42,6 +54,7 @@ typedef struct QEMUPutLEDEntry {
} QEMUPutLEDEntry;
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
+void qemu_remove_kbd_event_handler(QEMUPutKBDEvent *entry);
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
void *opaque, int absolute,
const char *name);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 10/48] Lots of ARM TCG changes
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (6 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 09/48] console change headers Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 12/48] cocoa frontend changes Riku Voipio
` (36 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
This patch is flattened set of dozens of patches. These
patches will be sent via another patch series once the commit messages
have been improved.
---
target-arm/helpers.h | 11 +
target-arm/machine.c | 6 +
target-arm/neon_helper.c | 269 ++++++++
target-arm/op_helper.c | 124 ++++
target-arm/translate.c | 1619 ++++++++++++++++++++++++----------------------
5 files changed, 1263 insertions(+), 766 deletions(-)
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index 0d1bc47..a5fd2e8 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -160,10 +160,14 @@ DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_s32, i32, env, i32, i32)
DEF_HELPER_2(neon_hadd_s8, i32, i32, i32)
DEF_HELPER_2(neon_hadd_u8, i32, i32, i32)
@@ -291,10 +295,13 @@ DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32)
DEF_HELPER_1(neon_narrow_u8, i32, i64)
DEF_HELPER_1(neon_narrow_u16, i32, i64)
+DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64)
+DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64)
+DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64)
DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
@@ -447,4 +454,8 @@ DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
DEF_HELPER_2(set_teecr, void, env, i32)
+DEF_HELPER_2(neon_unzip, void, env, i32)
+DEF_HELPER_2(neon_zip, void, env, i32)
+DEF_HELPER_2(neon_vldst_all, void, env, i32)
+
#include "def-helper.h"
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 3925d3a..8595549 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -26,6 +26,9 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, env->cp15.c1_sys);
qemu_put_be32(f, env->cp15.c1_coproc);
qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+ qemu_put_be32(f, env->cp15.c1_secfg);
+ qemu_put_be32(f, env->cp15.c1_sedbg);
+ qemu_put_be32(f, env->cp15.c1_nseac);
qemu_put_be32(f, env->cp15.c2_base0);
qemu_put_be32(f, env->cp15.c2_base1);
qemu_put_be32(f, env->cp15.c2_control);
@@ -133,6 +136,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->cp15.c1_sys = qemu_get_be32(f);
env->cp15.c1_coproc = qemu_get_be32(f);
env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+ env->cp15.c1_secfg = qemu_get_be32(f);
+ env->cp15.c1_sedbg = qemu_get_be32(f);
+ env->cp15.c1_nseac = qemu_get_be32(f);
env->cp15.c2_base0 = qemu_get_be32(f);
env->cp15.c2_base1 = qemu_get_be32(f);
env->cp15.c2_control = qemu_get_be32(f);
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 5e6452b..924bf40 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -198,6 +198,16 @@ NEON_VOP_ENV(qadd_u16, neon_u16, 2)
#undef NEON_FN
#undef NEON_USAT
+uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b)
+{
+ uint32_t res = a + b;
+ if (res < a) {
+ SET_QC();
+ res = ~0;
+ }
+ return res;
+}
+
#define NEON_SSAT(dest, src1, src2, type) do { \
int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \
if (tmp != (type)tmp) { \
@@ -218,6 +228,16 @@ NEON_VOP_ENV(qadd_s16, neon_s16, 2)
#undef NEON_FN
#undef NEON_SSAT
+uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b)
+{
+ uint32_t res = a + b;
+ if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
+ SET_QC();
+ res = ~(((int32_t)a >> 31) ^ SIGNBIT);
+ }
+ return res;
+}
+
#define NEON_USAT(dest, src1, src2, type) do { \
uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
if (tmp != (type)tmp) { \
@@ -234,6 +254,16 @@ NEON_VOP_ENV(qsub_u16, neon_u16, 2)
#undef NEON_FN
#undef NEON_USAT
+uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b)
+{
+ uint32_t res = a - b;
+ if (res > a) {
+ SET_QC();
+ res = 0;
+ }
+ return res;
+}
+
#define NEON_SSAT(dest, src1, src2, type) do { \
int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
if (tmp != (type)tmp) { \
@@ -254,6 +284,16 @@ NEON_VOP_ENV(qsub_s16, neon_s16, 2)
#undef NEON_FN
#undef NEON_SSAT
+uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b)
+{
+ uint32_t res = a - b;
+ if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
+ SET_QC();
+ res = ~(((int32_t)a >> 31) ^ SIGNBIT);
+ }
+ return res;
+}
+
#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1
NEON_VOP(hadd_s8, neon_s8, 4)
NEON_VOP(hadd_u8, neon_u8, 4)
@@ -909,6 +949,33 @@ uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x)
return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000);
}
+uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x)
+{
+ uint16_t s;
+ uint8_t d;
+ uint32_t res = 0;
+#define SAT8(n) \
+ s = x >> n; \
+ if (s & 0x8000) { \
+ SET_QC(); \
+ } else { \
+ if (s > 0xff) { \
+ d = 0xff; \
+ SET_QC(); \
+ } else { \
+ d = s; \
+ } \
+ res |= (uint32_t)d << (n / 2); \
+ }
+
+ SAT8(0);
+ SAT8(16);
+ SAT8(32);
+ SAT8(48);
+#undef SAT8
+ return res;
+}
+
uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x)
{
uint16_t s;
@@ -955,6 +1022,29 @@ uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x)
return res;
}
+uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x)
+{
+ uint32_t high;
+ uint32_t low;
+ low = x;
+ if (low & 0x80000000) {
+ low = 0;
+ SET_QC();
+ } else if (low > 0xffff) {
+ low = 0xffff;
+ SET_QC();
+ }
+ high = x >> 32;
+ if (high & 0x80000000) {
+ high = 0;
+ SET_QC();
+ } else if (high > 0xffff) {
+ high = 0xffff;
+ SET_QC();
+ }
+ return low | (high << 16);
+}
+
uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x)
{
uint32_t high;
@@ -989,6 +1079,19 @@ uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x)
return (uint16_t)low | (high << 16);
}
+uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x)
+{
+ if (x & 0x8000000000000000ull) {
+ SET_QC();
+ return 0;
+ }
+ if (x > 0xffffffffu) {
+ SET_QC();
+ return 0xffffffffu;
+ }
+ return x;
+}
+
uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
{
if (x > 0xffffffffu) {
@@ -1457,3 +1560,169 @@ uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b)
float32 f1 = float32_abs(vfp_itos(b));
return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0;
}
+
+#define ELEM(V, N, SIZE) (uint64_t)(((uint64_t)(V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
+
+void HELPER(neon_unzip)(CPUState *env, uint32_t insn)
+{
+ int rd = ((insn >> 18) & 0x10) | ((insn >> 12) & 0x0f);
+ int rm = ((insn >> 1) & 0x10) | (insn & 0x0f);
+ int size = (insn >> 18) & 3;
+ if (insn & 0x40) { /* Q */
+ uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+ uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+ uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+ uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+ uint64_t m0 = 0, m1 = 0, d0 = 0, d1 = 0;
+ switch (size) {
+ case 0:
+ d0 = ELEM(zd0, 0, 8) | (ELEM(zd0, 2, 8) << 8)
+ | (ELEM(zd0, 4, 8) << 16) | (ELEM(zd0, 6, 8) << 24)
+ | (ELEM(zd1, 0, 8) << 32) | (ELEM(zd1, 2, 8) << 40)
+ | (ELEM(zd1, 4, 8) << 48) | (ELEM(zd1, 6, 8) << 56);
+ d1 = ELEM(zm0, 0, 8) | (ELEM(zm0, 2, 8) << 8)
+ | (ELEM(zm0, 4, 8) << 16) | (ELEM(zm0, 6, 8) << 24)
+ | (ELEM(zm1, 0, 8) << 32) | (ELEM(zm1, 2, 8) << 40)
+ | (ELEM(zm1, 4, 8) << 48) | (ELEM(zm1, 6, 8) << 56);
+ m0 = ELEM(zd0, 1, 8) | (ELEM(zd0, 3, 8) << 8)
+ | (ELEM(zd0, 5, 8) << 16) | (ELEM(zd0, 7, 8) << 24)
+ | (ELEM(zd1, 1, 8) << 32) | (ELEM(zd1, 3, 8) << 40)
+ | (ELEM(zd1, 5, 8) << 48) | (ELEM(zd1, 7, 8) << 56);
+ m1 = ELEM(zm0, 1, 8) | (ELEM(zm0, 3, 8) << 8)
+ | (ELEM(zm0, 5, 8) << 16) | (ELEM(zm0, 7, 8) << 24)
+ | (ELEM(zm1, 1, 8) << 32) | (ELEM(zm1, 3, 8) << 40)
+ | (ELEM(zm1, 5, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
+ break;
+ case 1:
+ d0 = ELEM(zd0, 0, 16) | (ELEM(zd0, 2, 16) << 16)
+ | (ELEM(zd1, 0, 16) << 32) | (ELEM(zd1, 2, 16) << 48);
+ d1 = ELEM(zm0, 0, 16) | (ELEM(zm0, 2, 16) << 16)
+ | (ELEM(zm1, 0, 16) << 32) | (ELEM(zm1, 2, 16) << 48);
+ m0 = ELEM(zd0, 1, 16) | (ELEM(zd0, 3, 16) << 16)
+ | (ELEM(zd1, 1, 16) << 32) | (ELEM(zd1, 3, 16) << 48);
+ m1 = ELEM(zm0, 1, 16) | (ELEM(zm0, 3, 16) << 16)
+ | (ELEM(zm1, 1, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
+ break;
+ case 2:
+ d0 = ELEM(zd0, 0, 32) | (ELEM(zd1, 0, 32) << 32);
+ d1 = ELEM(zm0, 0, 32) | (ELEM(zm1, 0, 32) << 32);
+ m0 = ELEM(zd0, 1, 32) | (ELEM(zd1, 1, 32) << 32);
+ m1 = ELEM(zm0, 1, 32) | (ELEM(zm1, 1, 32) << 32);
+ break;
+ default:
+ break;
+ }
+ env->vfp.regs[rm] = make_float64(m0);
+ env->vfp.regs[rm + 1] = make_float64(m1);
+ env->vfp.regs[rd] = make_float64(d0);
+ env->vfp.regs[rd + 1] = make_float64(d1);
+ } else {
+ uint64_t zm = float64_val(env->vfp.regs[rm]);
+ uint64_t zd = float64_val(env->vfp.regs[rd]);
+ uint64_t m = 0, d = 0;
+ switch (size) {
+ case 0:
+ d = ELEM(zd, 0, 8) | (ELEM(zd, 2, 8) << 8)
+ | (ELEM(zd, 4, 8) << 16) | (ELEM(zd, 6, 8) << 24)
+ | (ELEM(zm, 0, 8) << 32) | (ELEM(zm, 2, 8) << 40)
+ | (ELEM(zm, 4, 8) << 48) | (ELEM(zm, 6, 8) << 56);
+ m = ELEM(zd, 1, 8) | (ELEM(zd, 3, 8) << 8)
+ | (ELEM(zd, 5, 8) << 16) | (ELEM(zd, 7, 8) << 24)
+ | (ELEM(zm, 1, 8) << 32) | (ELEM(zm, 3, 8) << 40)
+ | (ELEM(zm, 5, 8) << 48) | (ELEM(zm, 7, 8) << 56);
+ break;
+ case 1:
+ d = ELEM(zd, 0, 16) | (ELEM(zd, 2, 16) << 16)
+ | (ELEM(zm, 0, 16) << 32) | (ELEM(zm, 2, 16) << 48);
+ m = ELEM(zd, 1, 16) | (ELEM(zd, 3, 16) << 16)
+ | (ELEM(zm, 1, 16) << 32) | (ELEM(zm, 3, 16) << 48);
+ break;
+ default:
+ /* size == 2 is a no-op for doubleword vectors */
+ break;
+ }
+ env->vfp.regs[rm] = make_float64(m);
+ env->vfp.regs[rd] = make_float64(d);
+ }
+}
+
+void HELPER(neon_zip)(CPUState *env, uint32_t insn)
+{
+ int rd = ((insn >> 18) & 0x10) | ((insn >> 12) & 0x0f);
+ int rm = ((insn >> 1) & 0x10) | (insn & 0x0f);
+ int size = (insn >> 18) & 3;
+ if (insn & 0x40) { /* Q */
+ uint64_t zm0 = float64_val(env->vfp.regs[rm]);
+ uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]);
+ uint64_t zd0 = float64_val(env->vfp.regs[rd]);
+ uint64_t zd1 = float64_val(env->vfp.regs[rd + 1]);
+ uint64_t m0 = 0, m1 = 0, d0 = 0, d1 = 0;
+ switch (size) {
+ case 0:
+ d0 = ELEM(zd0, 0, 8) | (ELEM(zm0, 0, 8) << 8)
+ | (ELEM(zd0, 1, 8) << 16) | (ELEM(zm0, 1, 8) << 24)
+ | (ELEM(zd0, 2, 8) << 32) | (ELEM(zm0, 2, 8) << 40)
+ | (ELEM(zd0, 3, 8) << 48) | (ELEM(zm0, 3, 8) << 56);
+ d1 = ELEM(zd0, 4, 8) | (ELEM(zm0, 4, 8) << 8)
+ | (ELEM(zd0, 5, 8) << 16) | (ELEM(zm0, 5, 8) << 24)
+ | (ELEM(zd0, 6, 8) << 32) | (ELEM(zm0, 6, 8) << 40)
+ | (ELEM(zd0, 7, 8) << 48) | (ELEM(zm0, 7, 8) << 56);
+ m0 = ELEM(zd1, 0, 8) | (ELEM(zm1, 0, 8) << 8)
+ | (ELEM(zd1, 1, 8) << 16) | (ELEM(zm1, 1, 8) << 24)
+ | (ELEM(zd1, 2, 8) << 32) | (ELEM(zm1, 2, 8) << 40)
+ | (ELEM(zd1, 3, 8) << 48) | (ELEM(zm1, 3, 8) << 56);
+ m1 = ELEM(zd1, 4, 8) | (ELEM(zm1, 4, 8) << 8)
+ | (ELEM(zd1, 5, 8) << 16) | (ELEM(zm1, 5, 8) << 24)
+ | (ELEM(zd1, 6, 8) << 32) | (ELEM(zm1, 6, 8) << 40)
+ | (ELEM(zd1, 7, 8) << 48) | (ELEM(zm1, 7, 8) << 56);
+ break;
+ case 1:
+ d0 = ELEM(zd0, 0, 16) | (ELEM(zm0, 0, 16) << 16)
+ | (ELEM(zd0, 1, 16) << 32) | (ELEM(zm0, 1, 16) << 48);
+ d1 = ELEM(zd0, 2, 16) | (ELEM(zm0, 2, 16) << 16)
+ | (ELEM(zd0, 3, 16) << 32) | (ELEM(zm0, 3, 16) << 48);
+ m0 = ELEM(zd1, 0, 16) | (ELEM(zm1, 0, 16) << 16)
+ | (ELEM(zd1, 1, 16) << 32) | (ELEM(zm1, 1, 16) << 48);
+ m1 = ELEM(zd1, 2, 16) | (ELEM(zm1, 2, 16) << 16)
+ | (ELEM(zd1, 3, 16) << 32) | (ELEM(zm1, 3, 16) << 48);
+ break;
+ case 2:
+ d0 = ELEM(zd0, 0, 32) | (ELEM(zm0, 0, 32) << 32);
+ d1 = ELEM(zd0, 1, 32) | (ELEM(zm0, 1, 32) << 32);
+ m0 = ELEM(zd1, 0, 32) | (ELEM(zm1, 0, 32) << 32);
+ m1 = ELEM(zd1, 1, 32) | (ELEM(zm1, 1, 32) << 32);
+ break;
+ }
+ env->vfp.regs[rm] = make_float64(m0);
+ env->vfp.regs[rm + 1] = make_float64(m1);
+ env->vfp.regs[rd] = make_float64(d0);
+ env->vfp.regs[rd + 1] = make_float64(d1);
+ } else {
+ uint64_t zm = float64_val(env->vfp.regs[rm]);
+ uint64_t zd = float64_val(env->vfp.regs[rd]);
+ uint64_t m = 0, d = 0;
+ switch (size) {
+ case 0:
+ d = ELEM(zd, 0, 8) | (ELEM(zm, 0, 8) << 8)
+ | (ELEM(zd, 1, 8) << 16) | (ELEM(zm, 1, 8) << 24)
+ | (ELEM(zd, 2, 8) << 32) | (ELEM(zm, 2, 8) << 40)
+ | (ELEM(zd, 3, 8) << 48) | (ELEM(zm, 3, 8) << 56);
+ m = ELEM(zd, 4, 8) | (ELEM(zm, 4, 8) << 8)
+ | (ELEM(zd, 5, 8) << 16) | (ELEM(zm, 5, 8) << 24)
+ | (ELEM(zd, 6, 8) << 32) | (ELEM(zm, 6, 8) << 40)
+ | (ELEM(zd, 7, 8) << 48) | (ELEM(zm, 7, 8) << 56);
+ break;
+ case 1:
+ d = ELEM(zd, 0, 16) | (ELEM(zm, 0, 16) << 16)
+ | (ELEM(zd, 1, 16) << 32) | (ELEM(zm, 1, 16) << 48);
+ m = ELEM(zd, 2, 16) | (ELEM(zm, 2, 16) << 16)
+ | (ELEM(zd, 3, 16) << 32) | (ELEM(zm, 3, 16) << 48);
+ break;
+ default:
+ /* size == 2 is a no-op for doubleword vectors */
+ break;
+ }
+ env->vfp.regs[rm] = make_float64(m);
+ env->vfp.regs[rd] = make_float64(d);
+ }
+}
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 9b1a014..749c442 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -487,3 +487,127 @@ uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2)
}
return res;
}
+
+void HELPER(neon_vldst_all)(CPUState *env, uint32_t insn)
+{
+#if defined(CONFIG_USER_ONLY)
+#define LDB(addr) ldub(addr)
+#define LDW(addr) lduw(addr)
+#define LDL(addr) ldl(addr)
+#define LDQ(addr) ldq(addr)
+#define STB(addr, val) stb(addr, val)
+#define STW(addr, val) stw(addr, val)
+#define STL(addr, val) stl(addr, val)
+#define STQ(addr, val) stq(addr, val)
+#else
+ int user = cpu_mmu_index(env);
+#define LDB(addr) slow_ldb_mmu(addr, user, GETPC())
+#define LDW(addr) slow_ldw_mmu(addr, user, GETPC())
+#define LDL(addr) slow_ldl_mmu(addr, user, GETPC())
+#define LDQ(addr) slow_ldq_mmu(addr, user, GETPC())
+#define STB(addr, val) slow_stb_mmu(addr, val, user, GETPC())
+#define STW(addr, val) slow_stw_mmu(addr, val, user, GETPC())
+#define STL(addr, val) slow_stl_mmu(addr, val, user, GETPC())
+#define STQ(addr, val) slow_stq_mmu(addr, val, user, GETPC())
+#endif
+ static const struct {
+ int nregs;
+ int interleave;
+ int spacing;
+ } neon_ls_element_type[11] = {
+ {4, 4, 1},
+ {4, 4, 2},
+ {4, 1, 1},
+ {4, 2, 1},
+ {3, 3, 1},
+ {3, 3, 2},
+ {3, 1, 1},
+ {1, 1, 1},
+ {2, 2, 1},
+ {2, 2, 2},
+ {2, 1, 1}
+ };
+
+ const int op = (insn >> 8) & 0xf;
+ const int size = (insn >> 6) & 3;
+ int rd = ((insn >> 12) & 0x0f) | ((insn >> 18) & 0x10);
+ const int rn = (insn >> 16) & 0xf;
+ const int load = (insn & (1 << 21)) != 0;
+ const int nregs = neon_ls_element_type[op].nregs;
+ const int interleave = neon_ls_element_type[op].interleave;
+ const int spacing = neon_ls_element_type[op].spacing;
+ uint32_t addr = env->regs[rn];
+ const int stride = (1 << size) * interleave;
+ int i, reg;
+ uint64_t tmp64;
+
+ for (reg = 0; reg < nregs; reg++) {
+ if (interleave > 2 || (interleave == 2 && nregs == 2)) {
+ addr = env->regs[rn] + (1 << size) * reg;
+ } else if (interleave == 2 && nregs == 4 && reg == 2) {
+ addr = env->regs[rn] + (1 << size);
+ }
+ switch (size) {
+ case 3:
+ if (load) {
+ env->vfp.regs[rd] = make_float64(LDQ(addr));
+ } else {
+ STQ(addr, float64_val(env->vfp.regs[rd]));
+ }
+ addr += stride;
+ break;
+ case 2:
+ if (load) {
+ tmp64 = (uint32_t)LDL(addr);
+ addr += stride;
+ tmp64 |= (uint64_t)LDL(addr) << 32;
+ addr += stride;
+ env->vfp.regs[rd] = make_float64(tmp64);
+ } else {
+ tmp64 = float64_val(env->vfp.regs[rd]);
+ STL(addr, tmp64);
+ addr += stride;
+ STL(addr, tmp64 >> 32);
+ addr += stride;
+ }
+ break;
+ case 1:
+ if (load) {
+ tmp64 = 0ull;
+ for (i = 0; i < 4; i++, addr += stride) {
+ tmp64 |= (uint64_t)LDW(addr) << (i * 16);
+ }
+ env->vfp.regs[rd] = make_float64(tmp64);
+ } else {
+ tmp64 = float64_val(env->vfp.regs[rd]);
+ for (i = 0; i < 4; i++, addr += stride, tmp64 >>= 16) {
+ STW(addr, tmp64);
+ }
+ }
+ break;
+ case 0:
+ if (load) {
+ tmp64 = 0ull;
+ for (i = 0; i < 8; i++, addr += stride) {
+ tmp64 |= (uint64_t)LDB(addr) << (i * 8);
+ }
+ env->vfp.regs[rd] = make_float64(tmp64);
+ } else {
+ tmp64 = float64_val(env->vfp.regs[rd]);
+ for (i = 0; i < 8; i++, addr += stride, tmp64 >>= 8) {
+ STB(addr, tmp64);
+ }
+ }
+ break;
+ }
+ rd += spacing;
+ }
+#undef LDB
+#undef LDW
+#undef LDL
+#undef LDQ
+#undef STB
+#undef STW
+#undef STL
+#undef STQ
+}
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 3b84c1d..b214bff 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -34,6 +34,8 @@
#define GEN_HELPER 1
#include "helpers.h"
+//#define RESOURCE_LEAK_DEBUG
+
#define ENABLE_ARCH_5J 0
#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
@@ -123,22 +125,97 @@ void arm_translate_init(void)
#include "helpers.h"
}
+#ifdef RESOURCE_LEAK_DEBUG
static int num_temps;
/* Allocate a temporary variable. */
-static TCGv_i32 new_tmp(void)
+static inline TCGv_i32 new_tmp(void)
{
num_temps++;
return tcg_temp_new_i32();
}
+static inline TCGv_i32 new_tmplocal32(void)
+{
+ num_temps++;
+ return tcg_temp_local_new_i32();
+}
+
+static inline TCGv new_tmplocal(void)
+{
+ num_temps++;
+ return tcg_temp_local_new();
+}
+
+static inline TCGv_i64 new_tmp64(void)
+{
+ num_temps++;
+ return tcg_temp_new_i64();
+}
+
+static inline TCGv_ptr new_tmpptr(void)
+{
+ num_temps++;
+ return tcg_temp_new_ptr();
+}
+
+static inline TCGv_i32 new_const(uint32_t value)
+{
+ num_temps++;
+ return tcg_const_i32(value);
+}
+
+static inline TCGv_i64 new_const64(uint64_t value)
+{
+ num_temps++;
+ return tcg_const_i64(value);
+}
+
/* Release a temporary variable. */
-static void dead_tmp(TCGv tmp)
+static inline void dead_tmp(TCGv tmp)
+{
+ tcg_temp_free_i32(tmp);
+ num_temps--;
+}
+
+static inline void dead_tmp64(TCGv_i64 tmp)
+{
+ tcg_temp_free_i64(tmp);
+ num_temps--;
+}
+
+static inline void dead_tmp_(TCGv tmp)
{
tcg_temp_free(tmp);
num_temps--;
}
+static inline void dead_tmpptr(TCGv_ptr tmp)
+{
+ tcg_temp_free_ptr(tmp);
+ num_temps--;
+}
+
+#undef tcg_temp_local_new
+#undef tcg_temp_new_ptr
+#undef tcg_temp_free
+#undef tcg_temp_free_ptr
+#define tcg_temp_new_i32() new_tmp()
+#define tcg_temp_new_i64() new_tmp64()
+#define tcg_temp_local_new() new_tmplocal()
+#define tcg_temp_local_new_i32() new_tmplocal32()
+#define tcg_temp_new_ptr() new_tmpptr()
+#define tcg_const_i32(x) new_const(x)
+#define tcg_const_i64(x) new_const64(x)
+#define tcg_temp_free(x) dead_tmp_(x)
+#define tcg_temp_free_i32(x) dead_tmp(x)
+#define tcg_temp_free_i64(x) dead_tmp64(x)
+#define tcg_temp_free_ptr(x) dead_tmpptr(x)
+#else // RESOURCE_LEAK_DEBUG
+#define new_tmp() tcg_temp_new_i32()
+#define dead_tmp(x) tcg_temp_free_i32(x)
+#endif // RESOOURCE_LEAK_DEBUG
+
static inline TCGv load_cpu_offset(int offset)
{
TCGv tmp = new_tmp();
@@ -1691,8 +1768,8 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
TCGV_UNUSED(tmp3);
}
gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
- tcg_temp_free(tmp3);
- tcg_temp_free(tmp2);
+ tcg_temp_free_i32(tmp3);
+ tcg_temp_free_i32(tmp2);
dead_tmp(tmp);
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
@@ -2151,7 +2228,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
tmp = tcg_const_i32((insn >> 20) & 3);
iwmmxt_load_reg(cpu_V1, rd1);
gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
- tcg_temp_free(tmp);
+ tcg_temp_free_i32(tmp);
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
@@ -2207,7 +2284,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_M0_wRn(rd0);
tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
- tcg_temp_free(tmp);
+ tcg_temp_free_i32(tmp);
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
@@ -2420,7 +2497,7 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
tmp = new_tmp();
tmp2 = tcg_const_i32(insn);
gen_helper_get_cp(tmp, cpu_env, tmp2);
- tcg_temp_free(tmp2);
+ tcg_temp_free_i32(tmp2);
store_reg(s, rd, tmp);
} else {
if (!env->cp[cp].cp_write)
@@ -2429,7 +2506,7 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
tmp = load_reg(s, rd);
tmp2 = tcg_const_i32(insn);
gen_helper_set_cp(cpu_env, tmp2, tmp);
- tcg_temp_free(tmp2);
+ tcg_temp_free_i32(tmp2);
dead_tmp(tmp);
}
return 0;
@@ -3311,6 +3388,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
offset = 8;
else
offset = 4;
+ tmp = tcg_const_i32(offset);
for (i = 0; i < n; i++) {
if (insn & ARM_CP_RW_BIT) {
/* load */
@@ -3321,8 +3399,9 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
gen_mov_F0_vreg(dp, rd + i);
gen_vfp_st(s, dp, addr);
}
- tcg_gen_addi_i32(addr, addr, offset);
+ tcg_gen_add_i32(addr, addr, tmp);
}
+ tcg_temp_free_i32(tmp);
if (insn & (1 << 21)) {
/* writeback */
if (insn & (1 << 24))
@@ -3524,12 +3603,6 @@ static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32
#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32
-/* FIXME: This is wrong. They set the wrong overflow bit. */
-#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c)
-#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c)
-#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c)
-#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c)
-
#define GEN_NEON_INTEGER_OP_ENV(name) do { \
switch ((size << 1) | u) { \
case 0: \
@@ -3593,128 +3666,18 @@ static inline TCGv neon_get_scalar(int size, int reg)
{
TCGv tmp;
if (size == 1) {
- tmp = neon_load_reg(reg >> 1, reg & 1);
- } else {
- tmp = neon_load_reg(reg >> 2, (reg >> 1) & 1);
- if (reg & 1) {
- gen_neon_dup_low16(tmp);
- } else {
+ tmp = neon_load_reg(reg & 7, reg >> 4);
+ if (reg & 8) {
gen_neon_dup_high16(tmp);
+ } else {
+ gen_neon_dup_low16(tmp);
}
+ } else {
+ tmp = neon_load_reg(reg & 15, reg >> 4);
}
return tmp;
}
-static void gen_neon_unzip_u8(TCGv t0, TCGv t1)
-{
- TCGv rd, rm, tmp;
-
- rd = new_tmp();
- rm = new_tmp();
- tmp = new_tmp();
-
- tcg_gen_andi_i32(rd, t0, 0xff);
- tcg_gen_shri_i32(tmp, t0, 8);
- tcg_gen_andi_i32(tmp, tmp, 0xff00);
- tcg_gen_or_i32(rd, rd, tmp);
- tcg_gen_shli_i32(tmp, t1, 16);
- tcg_gen_andi_i32(tmp, tmp, 0xff0000);
- tcg_gen_or_i32(rd, rd, tmp);
- tcg_gen_shli_i32(tmp, t1, 8);
- tcg_gen_andi_i32(tmp, tmp, 0xff000000);
- tcg_gen_or_i32(rd, rd, tmp);
-
- tcg_gen_shri_i32(rm, t0, 8);
- tcg_gen_andi_i32(rm, rm, 0xff);
- tcg_gen_shri_i32(tmp, t0, 16);
- tcg_gen_andi_i32(tmp, tmp, 0xff00);
- tcg_gen_or_i32(rm, rm, tmp);
- tcg_gen_shli_i32(tmp, t1, 8);
- tcg_gen_andi_i32(tmp, tmp, 0xff0000);
- tcg_gen_or_i32(rm, rm, tmp);
- tcg_gen_andi_i32(tmp, t1, 0xff000000);
- tcg_gen_or_i32(t1, rm, tmp);
- tcg_gen_mov_i32(t0, rd);
-
- dead_tmp(tmp);
- dead_tmp(rm);
- dead_tmp(rd);
-}
-
-static void gen_neon_zip_u8(TCGv t0, TCGv t1)
-{
- TCGv rd, rm, tmp;
-
- rd = new_tmp();
- rm = new_tmp();
- tmp = new_tmp();
-
- tcg_gen_andi_i32(rd, t0, 0xff);
- tcg_gen_shli_i32(tmp, t1, 8);
- tcg_gen_andi_i32(tmp, tmp, 0xff00);
- tcg_gen_or_i32(rd, rd, tmp);
- tcg_gen_shli_i32(tmp, t0, 16);
- tcg_gen_andi_i32(tmp, tmp, 0xff0000);
- tcg_gen_or_i32(rd, rd, tmp);
- tcg_gen_shli_i32(tmp, t1, 24);
- tcg_gen_andi_i32(tmp, tmp, 0xff000000);
- tcg_gen_or_i32(rd, rd, tmp);
-
- tcg_gen_andi_i32(rm, t1, 0xff000000);
- tcg_gen_shri_i32(tmp, t0, 8);
- tcg_gen_andi_i32(tmp, tmp, 0xff0000);
- tcg_gen_or_i32(rm, rm, tmp);
- tcg_gen_shri_i32(tmp, t1, 8);
- tcg_gen_andi_i32(tmp, tmp, 0xff00);
- tcg_gen_or_i32(rm, rm, tmp);
- tcg_gen_shri_i32(tmp, t0, 16);
- tcg_gen_andi_i32(tmp, tmp, 0xff);
- tcg_gen_or_i32(t1, rm, tmp);
- tcg_gen_mov_i32(t0, rd);
-
- dead_tmp(tmp);
- dead_tmp(rm);
- dead_tmp(rd);
-}
-
-static void gen_neon_zip_u16(TCGv t0, TCGv t1)
-{
- TCGv tmp, tmp2;
-
- tmp = new_tmp();
- tmp2 = new_tmp();
-
- tcg_gen_andi_i32(tmp, t0, 0xffff);
- tcg_gen_shli_i32(tmp2, t1, 16);
- tcg_gen_or_i32(tmp, tmp, tmp2);
- tcg_gen_andi_i32(t1, t1, 0xffff0000);
- tcg_gen_shri_i32(tmp2, t0, 16);
- tcg_gen_or_i32(t1, t1, tmp2);
- tcg_gen_mov_i32(t0, tmp);
-
- dead_tmp(tmp2);
- dead_tmp(tmp);
-}
-
-static void gen_neon_unzip(int reg, int q, int tmp, int size)
-{
- int n;
- TCGv t0, t1;
-
- for (n = 0; n < q + 1; n += 2) {
- t0 = neon_load_reg(reg, n);
- t1 = neon_load_reg(reg, n + 1);
- switch (size) {
- case 0: gen_neon_unzip_u8(t0, t1); break;
- case 1: gen_neon_zip_u16(t0, t1); break; /* zip and unzip are the same. */
- case 2: /* no-op */; break;
- default: abort();
- }
- neon_store_scratch(tmp + n, t0);
- neon_store_scratch(tmp + n + 1, t1);
- }
-}
-
static void gen_neon_trn_u8(TCGv t0, TCGv t1)
{
TCGv rd, tmp;
@@ -3756,7 +3719,6 @@ static void gen_neon_trn_u16(TCGv t0, TCGv t1)
dead_tmp(rd);
}
-
static struct {
int nregs;
int interleave;
@@ -3790,11 +3752,9 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
int pass;
int load;
int shift;
- int n;
TCGv addr;
TCGv tmp;
TCGv tmp2;
- TCGv_i64 tmp64;
if (!vfp_enabled(env))
return 1;
@@ -3807,103 +3767,28 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
/* Load store all elements. */
op = (insn >> 8) & 0xf;
size = (insn >> 6) & 3;
- if (op > 10)
+ if (op > 10) {
+ dead_tmp(addr);
return 1;
+ }
nregs = neon_ls_element_type[op].nregs;
interleave = neon_ls_element_type[op].interleave;
spacing = neon_ls_element_type[op].spacing;
- if (size == 3 && (interleave | spacing) != 1)
+ if (size == 3 && (interleave | spacing) != 1) {
+ dead_tmp(addr);
return 1;
- load_reg_var(s, addr, rn);
- stride = (1 << size) * interleave;
- for (reg = 0; reg < nregs; reg++) {
- if (interleave > 2 || (interleave == 2 && nregs == 2)) {
- load_reg_var(s, addr, rn);
- tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
- } else if (interleave == 2 && nregs == 4 && reg == 2) {
- load_reg_var(s, addr, rn);
- tcg_gen_addi_i32(addr, addr, 1 << size);
- }
- if (size == 3) {
- if (load) {
- tmp64 = gen_ld64(addr, IS_USER(s));
- neon_store_reg64(tmp64, rd);
- tcg_temp_free_i64(tmp64);
- } else {
- tmp64 = tcg_temp_new_i64();
- neon_load_reg64(tmp64, rd);
- gen_st64(tmp64, addr, IS_USER(s));
- }
- tcg_gen_addi_i32(addr, addr, stride);
- } else {
- for (pass = 0; pass < 2; pass++) {
- if (size == 2) {
- if (load) {
- tmp = gen_ld32(addr, IS_USER(s));
- neon_store_reg(rd, pass, tmp);
- } else {
- tmp = neon_load_reg(rd, pass);
- gen_st32(tmp, addr, IS_USER(s));
- }
- tcg_gen_addi_i32(addr, addr, stride);
- } else if (size == 1) {
- if (load) {
- tmp = gen_ld16u(addr, IS_USER(s));
- tcg_gen_addi_i32(addr, addr, stride);
- tmp2 = gen_ld16u(addr, IS_USER(s));
- tcg_gen_addi_i32(addr, addr, stride);
- gen_bfi(tmp, tmp, tmp2, 16, 0xffff);
- dead_tmp(tmp2);
- neon_store_reg(rd, pass, tmp);
- } else {
- tmp = neon_load_reg(rd, pass);
- tmp2 = new_tmp();
- tcg_gen_shri_i32(tmp2, tmp, 16);
- gen_st16(tmp, addr, IS_USER(s));
- tcg_gen_addi_i32(addr, addr, stride);
- gen_st16(tmp2, addr, IS_USER(s));
- tcg_gen_addi_i32(addr, addr, stride);
- }
- } else /* size == 0 */ {
- if (load) {
- TCGV_UNUSED(tmp2);
- for (n = 0; n < 4; n++) {
- tmp = gen_ld8u(addr, IS_USER(s));
- tcg_gen_addi_i32(addr, addr, stride);
- if (n == 0) {
- tmp2 = tmp;
- } else {
- gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff);
- dead_tmp(tmp);
- }
- }
- neon_store_reg(rd, pass, tmp2);
- } else {
- tmp2 = neon_load_reg(rd, pass);
- for (n = 0; n < 4; n++) {
- tmp = new_tmp();
- if (n == 0) {
- tcg_gen_mov_i32(tmp, tmp2);
- } else {
- tcg_gen_shri_i32(tmp, tmp2, n * 8);
- }
- gen_st8(tmp, addr, IS_USER(s));
- tcg_gen_addi_i32(addr, addr, stride);
- }
- dead_tmp(tmp2);
- }
- }
- }
- }
- rd += spacing;
}
+ tcg_gen_movi_i32(addr, insn);
+ gen_helper_neon_vldst_all(cpu_env, addr);
stride = nregs * 8;
} else {
size = (insn >> 10) & 3;
if (size == 3) {
/* Load single element to all lanes. */
- if (!load)
+ if (!load) {
+ dead_tmp(addr);
return 1;
+ }
size = (insn >> 6) & 3;
nregs = ((insn >> 8) & 3) + 1;
stride = (insn & (1 << 5)) ? 2 : 1;
@@ -3922,6 +3807,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
tmp = gen_ld32(addr, IS_USER(s));
break;
case 3:
+ dead_tmp(addr);
return 1;
default: /* Avoid compiler warnings. */
abort();
@@ -4054,6 +3940,16 @@ static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
}
}
+static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src)
+{
+ switch(size) {
+ case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
+ case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
+ case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
+ default: abort();
+ }
+}
+
static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
int q, int u)
{
@@ -4074,8 +3970,8 @@ static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
} else {
if (u) {
switch (size) {
- case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
- case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
+ case 1: gen_helper_neon_shl_u16(var, var, shift); break;
+ case 2: gen_helper_neon_shl_u32(var, var, shift); break;
default: abort();
}
} else {
@@ -4189,8 +4085,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
TCGv tmp, tmp2, tmp3, tmp4, tmp5;
TCGv_i64 tmp64;
- if (!vfp_enabled(env))
- return 1;
+ if (!vfp_enabled(env)) {
+ return 1;
+ }
q = (insn & (1 << 6)) != 0;
u = (insn >> 24) & 1;
VFP_DREG_D(rd, insn);
@@ -4200,73 +4097,82 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if ((insn & (1 << 23)) == 0) {
/* Three register same length. */
op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
- if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
- || op == 10 || op == 11 || op == 16)) {
- /* 64-bit element instructions. */
- for (pass = 0; pass < (q ? 2 : 1); pass++) {
- neon_load_reg64(cpu_V0, rn + pass);
- neon_load_reg64(cpu_V1, rm + pass);
- switch (op) {
- case 1: /* VQADD */
- if (u) {
- gen_helper_neon_add_saturate_u64(CPU_V001);
- } else {
- gen_helper_neon_add_saturate_s64(CPU_V001);
- }
- break;
- case 5: /* VQSUB */
- if (u) {
- gen_helper_neon_sub_saturate_u64(CPU_V001);
- } else {
- gen_helper_neon_sub_saturate_s64(CPU_V001);
- }
- break;
- case 8: /* VSHL */
- if (u) {
- gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
- } else {
- gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
- }
- break;
- case 9: /* VQSHL */
- if (u) {
- gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
- cpu_V0, cpu_V0);
- } else {
- gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
- cpu_V1, cpu_V0);
- }
- break;
- case 10: /* VRSHL */
- if (u) {
- gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
- } else {
- gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
- }
- break;
- case 11: /* VQRSHL */
- if (u) {
- gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
- cpu_V1, cpu_V0);
- } else {
- gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
- cpu_V1, cpu_V0);
- }
- break;
- case 16:
- if (u) {
- tcg_gen_sub_i64(CPU_V001);
- } else {
- tcg_gen_add_i64(CPU_V001);
+ if (op == 24 || op == 25 || (q && ((rd | rn | rm) & 1))) {
+ return 1;
+ }
+ if (size == 3) {
+ if (op == 1 || op == 5 || op == 8 || op == 9 || op == 10
+ || op == 11 || op == 16) {
+ /* 64-bit element instructions. */
+ for (pass = 0; pass < (q ? 2 : 1); pass++) {
+ neon_load_reg64(cpu_V0, rn + pass);
+ neon_load_reg64(cpu_V1, rm + pass);
+ switch (op) {
+ case 1: /* VQADD */
+ if (u) {
+ gen_helper_neon_add_saturate_u64(CPU_V001);
+ } else {
+ gen_helper_neon_add_saturate_s64(CPU_V001);
+ }
+ break;
+ case 5: /* VQSUB */
+ if (u) {
+ gen_helper_neon_sub_saturate_u64(CPU_V001);
+ } else {
+ gen_helper_neon_sub_saturate_s64(CPU_V001);
+ }
+ break;
+ case 8: /* VSHL */
+ if (u) {
+ gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
+ } else {
+ gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
+ }
+ break;
+ case 9: /* VQSHL */
+ if (u) {
+ gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
+ cpu_V0, cpu_V0);
+ } else {
+ gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
+ cpu_V1, cpu_V0);
+ }
+ break;
+ case 10: /* VRSHL */
+ if (u) {
+ gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
+ } else {
+ gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
+ }
+ break;
+ case 11: /* VQRSHL */
+ if (u) {
+ gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
+ cpu_V1, cpu_V0);
+ } else {
+ gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
+ cpu_V1, cpu_V0);
+ }
+ break;
+ case 16: /* VADD, VSUB */
+ if (u) {
+ tcg_gen_sub_i64(CPU_V001);
+ } else {
+ tcg_gen_add_i64(CPU_V001);
+ }
+ break;
+ default:
+ abort();
}
- break;
- default:
- abort();
+ neon_store_reg64(cpu_V0, rd + pass);
}
- neon_store_reg64(cpu_V0, rd + pass);
+ return 0;
+ }
+ if (op != 3) {
+ return 1;
}
- return 0;
}
+ pairwise = 0;
switch (op) {
case 8: /* VSHL */
case 9: /* VQSHL */
@@ -4278,290 +4184,333 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
rtmp = rn;
rn = rm;
rm = rtmp;
- pairwise = 0;
}
break;
+ case 19: /* VMUL */
+ if (u && size) {
+ return 1;
+ }
+ break;
+ case 23: /* VPADD */
+ if (u) {
+ return 1;
+ }
+ /* fall through */
case 20: /* VPMAX */
case 21: /* VPMIN */
- case 23: /* VPADD */
pairwise = 1;
break;
- case 26: /* VPADD (float) */
+ case 22: /* VQDMULH/VQRDMULH */
+ if (!size) {
+ return 1;
+ }
+ break;
+ case 26: /* VADD/VSUB/VPADD/VABD (float) */
pairwise = (u && size < 2);
+ /* fall through */
+ case 27: /* VMLA/VMLS/VMUL (float) */
+ if (size & 1) {
+ return 1;
+ }
+ break;
+ case 28: /* VCEQ/VCGE/VCGT (float) */
+ if ((!u && size) || (size & 1)) {
+ return 1;
+ }
+ break;
+ case 29: /* VACGE/VACGT (float) */
+ if (!u || (size & 1)) {
+ return 1;
+ }
break;
case 30: /* VPMIN/VPMAX (float) */
pairwise = u;
+ if (size & 1) {
+ return 1;
+ }
+ break;
+ case 31: /* VRECPS/VRSQRTS */
+ if (u || (size & 1)) {
+ return 1;
+ }
break;
default:
- pairwise = 0;
break;
}
+ if (pairwise && q) {
+ return 1;
+ }
for (pass = 0; pass < (q ? 4 : 2); pass++) {
-
- if (pairwise) {
- /* Pairwise. */
- if (q)
- n = (pass & 1) * 2;
- else
- n = 0;
- if (pass < q + 1) {
- tmp = neon_load_reg(rn, n);
- tmp2 = neon_load_reg(rn, n + 1);
+ if (pairwise) {
+ /* Pairwise. */
+ if (!pass) {
+ tmp = neon_load_reg(rn, 0);
+ tmp2 = neon_load_reg(rn, 1);
+ } else {
+ tmp = neon_load_reg(rm, 0);
+ tmp2 = neon_load_reg(rm, 1);
+ }
} else {
- tmp = neon_load_reg(rm, n);
- tmp2 = neon_load_reg(rm, n + 1);
+ /* Elementwise. */
+ tmp = neon_load_reg(rn, pass);
+ tmp2 = neon_load_reg(rm, pass);
}
- } else {
- /* Elementwise. */
- tmp = neon_load_reg(rn, pass);
- tmp2 = neon_load_reg(rm, pass);
- }
- switch (op) {
- case 0: /* VHADD */
- GEN_NEON_INTEGER_OP(hadd);
- break;
- case 1: /* VQADD */
- GEN_NEON_INTEGER_OP_ENV(qadd);
- break;
- case 2: /* VRHADD */
- GEN_NEON_INTEGER_OP(rhadd);
- break;
- case 3: /* Logic ops. */
- switch ((u << 2) | size) {
- case 0: /* VAND */
- tcg_gen_and_i32(tmp, tmp, tmp2);
+ switch (op) {
+ case 0: /* VHADD */
+ GEN_NEON_INTEGER_OP(hadd);
break;
- case 1: /* BIC */
- tcg_gen_andc_i32(tmp, tmp, tmp2);
+ case 1: /* VQADD */
+ GEN_NEON_INTEGER_OP_ENV(qadd);
break;
- case 2: /* VORR */
- tcg_gen_or_i32(tmp, tmp, tmp2);
+ case 2: /* VRHADD */
+ GEN_NEON_INTEGER_OP(rhadd);
break;
- case 3: /* VORN */
- tcg_gen_orc_i32(tmp, tmp, tmp2);
+ case 3: /* Logic ops. */
+ switch ((u << 2) | size) {
+ case 0: /* VAND */
+ tcg_gen_and_i32(tmp, tmp, tmp2);
+ break;
+ case 1: /* VBIC */
+ tcg_gen_andc_i32(tmp, tmp, tmp2);
+ break;
+ case 2: /* VORR, VMOV */
+ tcg_gen_or_i32(tmp, tmp, tmp2);
+ break;
+ case 3: /* VORN */
+ tcg_gen_orc_i32(tmp, tmp, tmp2);
+ break;
+ case 4: /* VEOR */
+ tcg_gen_xor_i32(tmp, tmp, tmp2);
+ break;
+ case 5: /* VBSL */
+ tmp3 = neon_load_reg(rd, pass);
+ gen_neon_bsl(tmp, tmp, tmp2, tmp3);
+ dead_tmp(tmp3);
+ break;
+ case 6: /* VBIT */
+ tmp3 = neon_load_reg(rd, pass);
+ gen_neon_bsl(tmp, tmp, tmp3, tmp2);
+ dead_tmp(tmp3);
+ break;
+ case 7: /* VBIF */
+ tmp3 = neon_load_reg(rd, pass);
+ gen_neon_bsl(tmp, tmp3, tmp, tmp2);
+ dead_tmp(tmp3);
+ break;
+ }
break;
- case 4: /* VEOR */
- tcg_gen_xor_i32(tmp, tmp, tmp2);
+ case 4: /* VHSUB */
+ GEN_NEON_INTEGER_OP(hsub);
break;
- case 5: /* VBSL */
- tmp3 = neon_load_reg(rd, pass);
- gen_neon_bsl(tmp, tmp, tmp2, tmp3);
- dead_tmp(tmp3);
+ case 5: /* VQSUB */
+ GEN_NEON_INTEGER_OP_ENV(qsub);
break;
- case 6: /* VBIT */
- tmp3 = neon_load_reg(rd, pass);
- gen_neon_bsl(tmp, tmp, tmp3, tmp2);
- dead_tmp(tmp3);
+ case 6: /* VCGT */
+ GEN_NEON_INTEGER_OP(cgt);
break;
- case 7: /* VBIF */
- tmp3 = neon_load_reg(rd, pass);
- gen_neon_bsl(tmp, tmp3, tmp, tmp2);
- dead_tmp(tmp3);
+ case 7: /* VCGE */
+ GEN_NEON_INTEGER_OP(cge);
break;
- }
- break;
- case 4: /* VHSUB */
- GEN_NEON_INTEGER_OP(hsub);
- break;
- case 5: /* VQSUB */
- GEN_NEON_INTEGER_OP_ENV(qsub);
- break;
- case 6: /* VCGT */
- GEN_NEON_INTEGER_OP(cgt);
- break;
- case 7: /* VCGE */
- GEN_NEON_INTEGER_OP(cge);
- break;
- case 8: /* VSHL */
- GEN_NEON_INTEGER_OP(shl);
- break;
- case 9: /* VQSHL */
- GEN_NEON_INTEGER_OP_ENV(qshl);
- break;
- case 10: /* VRSHL */
- GEN_NEON_INTEGER_OP(rshl);
- break;
- case 11: /* VQRSHL */
- GEN_NEON_INTEGER_OP_ENV(qrshl);
- break;
- case 12: /* VMAX */
- GEN_NEON_INTEGER_OP(max);
- break;
- case 13: /* VMIN */
- GEN_NEON_INTEGER_OP(min);
- break;
- case 14: /* VABD */
- GEN_NEON_INTEGER_OP(abd);
- break;
- case 15: /* VABA */
- GEN_NEON_INTEGER_OP(abd);
- dead_tmp(tmp2);
- tmp2 = neon_load_reg(rd, pass);
- gen_neon_add(size, tmp, tmp2);
- break;
- case 16:
- if (!u) { /* VADD */
- if (gen_neon_add(size, tmp, tmp2))
- return 1;
- } else { /* VSUB */
- switch (size) {
- case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
- case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
- default: return 1;
- }
- }
- break;
- case 17:
- if (!u) { /* VTST */
- switch (size) {
- case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
- case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
- default: return 1;
+ case 8: /* VSHL */
+ GEN_NEON_INTEGER_OP(shl);
+ break;
+ case 9: /* VQSHL */
+ GEN_NEON_INTEGER_OP_ENV(qshl);
+ break;
+ case 10: /* VRSHL */
+ GEN_NEON_INTEGER_OP(rshl);
+ break;
+ case 11: /* VQRSHL */
+ GEN_NEON_INTEGER_OP_ENV(qrshl);
+ break;
+ case 12: /* VMAX */
+ GEN_NEON_INTEGER_OP(max);
+ break;
+ case 13: /* VMIN */
+ GEN_NEON_INTEGER_OP(min);
+ break;
+ case 14: /* VABD */
+ GEN_NEON_INTEGER_OP(abd);
+ break;
+ case 15: /* VABA */
+ GEN_NEON_INTEGER_OP(abd);
+ dead_tmp(tmp2);
+ tmp2 = neon_load_reg(rd, pass);
+ gen_neon_add(size, tmp, tmp2);
+ break;
+ case 16:
+ if (!u) { /* VADD */
+ if (gen_neon_add(size, tmp, tmp2)) {
+ abort(); /* size == 3 is handled earlier */
+ }
+ } else { /* VSUB */
+ switch (size) {
+ case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
+ case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
+ case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
+ default: abort(); /* size == 3 is handled earlier */
+ }
}
- } else { /* VCEQ */
- switch (size) {
- case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
- case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
- default: return 1;
+ break;
+ case 17:
+ if (!u) { /* VTST */
+ switch (size) {
+ case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
+ case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
+ case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
+ default: abort(); /* size == 3 is handled earlier */
+ }
+ } else { /* VCEQ */
+ switch (size) {
+ case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
+ case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
+ case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
+ default: abort(); /* size == 3 is handled earlier */
+ }
}
- }
- break;
- case 18: /* Multiply. */
- switch (size) {
- case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
- case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
- default: return 1;
- }
- dead_tmp(tmp2);
- tmp2 = neon_load_reg(rd, pass);
- if (u) { /* VMLS */
- gen_neon_rsb(size, tmp, tmp2);
- } else { /* VMLA */
- gen_neon_add(size, tmp, tmp2);
- }
- break;
- case 19: /* VMUL */
- if (u) { /* polynomial */
- gen_helper_neon_mul_p8(tmp, tmp, tmp2);
- } else { /* Integer */
+ break;
+ case 18: /* Multiply. */
switch (size) {
case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
- default: return 1;
+ default: abort(); /* size == 3 is handled earlier */
}
- }
- break;
- case 20: /* VPMAX */
- GEN_NEON_INTEGER_OP(pmax);
- break;
- case 21: /* VPMIN */
- GEN_NEON_INTEGER_OP(pmin);
- break;
- case 22: /* Hultiply high. */
- if (!u) { /* VQDMULH */
- switch (size) {
- case 1: gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); break;
- case 2: gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); break;
- default: return 1;
+ dead_tmp(tmp2);
+ tmp2 = neon_load_reg(rd, pass);
+ if (u) { /* VMLS */
+ gen_neon_rsb(size, tmp, tmp2);
+ } else { /* VMLA */
+ gen_neon_add(size, tmp, tmp2);
+ }
+ break;
+ case 19: /* VMUL */
+ if (u) { /* polynomial */
+ gen_helper_neon_mul_p8(tmp, tmp, tmp2);
+ } else { /* Integer */
+ switch (size) {
+ case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
+ case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
+ case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
+ default: abort(); /* size == 3 is handled earlier */
+ }
+ }
+ break;
+ case 20: /* VPMAX */
+ GEN_NEON_INTEGER_OP(pmax);
+ break;
+ case 21: /* VPMIN */
+ GEN_NEON_INTEGER_OP(pmin);
+ break;
+ case 22: /* Multiply high. */
+ if (!u) { /* VQDMULH */
+ switch (size) {
+ case 1:
+ gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
+ break;
+ case 2:
+ gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
+ break;
+ default:
+ abort(); /* size == 0,3 is handled earlier */
+ }
+ } else { /* VQRDHMUL */
+ switch (size) {
+ case 1:
+ gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
+ break;
+ case 2:
+ gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
+ break;
+ default:
+ abort(); /* size == 0,3 is handled earlier */
+ }
}
- } else { /* VQRDHMUL */
+ break;
+ case 23: /* VPADD */
switch (size) {
- case 1: gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); break;
- case 2: gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); break;
- default: return 1;
+ case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
+ case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
+ case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
+ default: abort(); /* size == 3 is handled earlier */
+ }
+ break;
+ case 26: /* Floating point arithmetic. */
+ switch ((u << 2) | size) {
+ case 0: /* VADD */
+ gen_helper_neon_add_f32(tmp, tmp, tmp2);
+ break;
+ case 2: /* VSUB */
+ gen_helper_neon_sub_f32(tmp, tmp, tmp2);
+ break;
+ case 4: /* VPADD */
+ gen_helper_neon_add_f32(tmp, tmp, tmp2);
+ break;
+ case 6: /* VABD */
+ gen_helper_neon_abd_f32(tmp, tmp, tmp2);
+ break;
+ default:
+ abort(); /* other values are handled earlier */
+ }
+ break;
+ case 27: /* Float multiply. */
+ gen_helper_neon_mul_f32(tmp, tmp, tmp2);
+ if (!u) {
+ dead_tmp(tmp2);
+ tmp2 = neon_load_reg(rd, pass);
+ if (size == 0) {
+ gen_helper_neon_add_f32(tmp, tmp, tmp2);
+ } else {
+ gen_helper_neon_sub_f32(tmp, tmp2, tmp);
+ }
}
- }
- break;
- case 23: /* VPADD */
- if (u)
- return 1;
- switch (size) {
- case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
- case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
- default: return 1;
- }
- break;
- case 26: /* Floating point arithnetic. */
- switch ((u << 2) | size) {
- case 0: /* VADD */
- gen_helper_neon_add_f32(tmp, tmp, tmp2);
break;
- case 2: /* VSUB */
- gen_helper_neon_sub_f32(tmp, tmp, tmp2);
+ case 28: /* Float compare. */
+ if (!u) {
+ gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
+ } else {
+ if (size == 0) {
+ gen_helper_neon_cge_f32(tmp, tmp, tmp2);
+ } else {
+ gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
+ }
+ }
break;
- case 4: /* VPADD */
- gen_helper_neon_add_f32(tmp, tmp, tmp2);
+ case 29: /* Float compare absolute. */
+ if (size == 0) {
+ gen_helper_neon_acge_f32(tmp, tmp, tmp2);
+ } else {
+ gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
+ }
break;
- case 6: /* VABD */
- gen_helper_neon_abd_f32(tmp, tmp, tmp2);
+ case 30: /* Float min/max. */
+ if (size == 0) {
+ gen_helper_neon_max_f32(tmp, tmp, tmp2);
+ } else {
+ gen_helper_neon_min_f32(tmp, tmp, tmp2);
+ }
break;
- default:
- return 1;
- }
- break;
- case 27: /* Float multiply. */
- gen_helper_neon_mul_f32(tmp, tmp, tmp2);
- if (!u) {
- dead_tmp(tmp2);
- tmp2 = neon_load_reg(rd, pass);
+ case 31:
if (size == 0) {
- gen_helper_neon_add_f32(tmp, tmp, tmp2);
+ gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
} else {
- gen_helper_neon_sub_f32(tmp, tmp2, tmp);
+ gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
}
+ break;
+ default:
+ abort();
}
- break;
- case 28: /* Float compare. */
- if (!u) {
- gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
+ dead_tmp(tmp2);
+
+ /* Save the result. For elementwise operations we can put it
+ straight into the destination register. For pairwise operations
+ we have to be careful to avoid clobbering the source operands.*/
+ if (pairwise && rd == rm) {
+ neon_store_scratch(pass, tmp);
} else {
- if (size == 0)
- gen_helper_neon_cge_f32(tmp, tmp, tmp2);
- else
- gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
+ neon_store_reg(rd, pass, tmp);
}
- break;
- case 29: /* Float compare absolute. */
- if (!u)
- return 1;
- if (size == 0)
- gen_helper_neon_acge_f32(tmp, tmp, tmp2);
- else
- gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
- break;
- case 30: /* Float min/max. */
- if (size == 0)
- gen_helper_neon_max_f32(tmp, tmp, tmp2);
- else
- gen_helper_neon_min_f32(tmp, tmp, tmp2);
- break;
- case 31:
- if (size == 0)
- gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
- else
- gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
- break;
- default:
- abort();
- }
- dead_tmp(tmp2);
-
- /* Save the result. For elementwise operations we can put it
- straight into the destination register. For pairwise operations
- we have to be careful to avoid clobbering the source operands. */
- if (pairwise && rd == rm) {
- neon_store_scratch(pass, tmp);
- } else {
- neon_store_reg(rd, pass, tmp);
- }
-
} /* for pass */
if (pairwise && rd == rm) {
for (pass = 0; pass < (q ? 4 : 2); pass++) {
@@ -4575,23 +4524,32 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
/* Two registers and shift. */
op = (insn >> 8) & 0xf;
if (insn & (1 << 7)) {
+ if (op & 8) {
+ return 1;
+ }
/* 64-bit shift. */
size = 3;
} else {
size = 2;
- while ((insn & (1 << (size + 19))) == 0)
+ while ((insn & (1 << (size + 19))) == 0) {
size--;
+ }
}
shift = (insn >> 16) & ((1 << (3 + size)) - 1);
/* To avoid excessive dumplication of ops we implement shift
by immediate using the variable shift operations. */
if (op < 8) {
/* Shift by immediate:
- VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */
+ VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VSLI, VQSHL, VQSHLU */
/* Right shifts are encoded as N - shift, where N is the
element size in bits. */
- if (op <= 4)
+ if ((q && ((rd | rm) & 1))
+ || (!u && (op == 4 || op == 6))) {
+ return 1;
+ }
+ if (op <= 4) {
shift = shift - (1 << (size + 3));
+ }
if (size == 3) {
count = q + 1;
} else {
@@ -4622,34 +4580,42 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
switch (op) {
case 0: /* VSHR */
case 1: /* VSRA */
- if (u)
- gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
- else
- gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
+ if (u) {
+ gen_helper_neon_shl_u64(cpu_V0, cpu_V0,
+ cpu_V1);
+ } else {
+ gen_helper_neon_shl_s64(cpu_V0, cpu_V0,
+ cpu_V1);
+ }
break;
case 2: /* VRSHR */
case 3: /* VRSRA */
- if (u)
- gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
- else
- gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
+ if (u) {
+ gen_helper_neon_rshl_u64(cpu_V0, cpu_V0,
+ cpu_V1);
+ } else {
+ gen_helper_neon_rshl_s64(cpu_V0, cpu_V0,
+ cpu_V1);
+ }
break;
case 4: /* VSRI */
- if (!u)
- return 1;
gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
break;
case 5: /* VSHL, VSLI */
gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
break;
- case 6: /* VQSHL */
- if (u)
- gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
- else
- gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
+ case 6: /* VQSHLU */
+ gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0,
+ cpu_V1);
break;
- case 7: /* VQSHLU */
- gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
+ case 7: /* VQSHL/VQSHLU */
+ if (u) {
+ gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
+ cpu_V0, cpu_V1);
+ } else {
+ gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
+ cpu_V0, cpu_V1);
+ }
break;
}
if (op == 1 || op == 3) {
@@ -4658,14 +4624,22 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
} else if (op == 4 || (op == 5 && u)) {
/* Insert */
- cpu_abort(env, "VS[LR]I.64 not implemented");
+ neon_load_reg64(cpu_V1, rd + pass);
+ uint64_t mask;
+ if (op == 4) {
+ mask = 0xffffffffffffffffull >> -shift;
+ } else {
+ mask = 0xffffffffffffffffull << shift;
+ }
+ tcg_gen_andi_i64(cpu_V0, cpu_V0, mask);
+ tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
+ tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
}
neon_store_reg64(cpu_V0, rd + pass);
} else { /* size < 3 */
/* Operands in T0 and T1. */
tmp = neon_load_reg(rm, pass);
- tmp2 = new_tmp();
- tcg_gen_movi_i32(tmp2, imm);
+ tmp2 = tcg_const_i32(imm);
switch (op) {
case 0: /* VSHR */
case 1: /* VSRA */
@@ -4676,31 +4650,44 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
GEN_NEON_INTEGER_OP(rshl);
break;
case 4: /* VSRI */
- if (!u)
- return 1;
- GEN_NEON_INTEGER_OP(shl);
- break;
case 5: /* VSHL, VSLI */
switch (size) {
- case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
- case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
- default: return 1;
+ case 0:
+ gen_helper_neon_shl_u8(tmp, tmp, tmp2);
+ break;
+ case 1:
+ gen_helper_neon_shl_u16(tmp, tmp, tmp2);
+ break;
+ case 2:
+ gen_helper_neon_shl_u32(tmp, tmp, tmp2);
+ break;
+ default:
+ abort(); /* size == 3 is handled earlier */
}
break;
- case 6: /* VQSHL */
+ case 6: /* VQSHLU */
GEN_NEON_INTEGER_OP_ENV(qshl);
break;
case 7: /* VQSHLU */
switch (size) {
- case 0: gen_helper_neon_qshl_u8(tmp, cpu_env, tmp, tmp2); break;
- case 1: gen_helper_neon_qshl_u16(tmp, cpu_env, tmp, tmp2); break;
- case 2: gen_helper_neon_qshl_u32(tmp, cpu_env, tmp, tmp2); break;
- default: return 1;
+ case 0:
+ gen_helper_neon_qshl_u8(tmp, cpu_env, tmp,
+ tmp2);
+ break;
+ case 1:
+ gen_helper_neon_qshl_u16(tmp, cpu_env, tmp,
+ tmp2);
+ break;
+ case 2:
+ gen_helper_neon_qshl_u32(tmp, cpu_env, tmp,
+ tmp2);
+ break;
+ default:
+ abort(); /* size == 3 is handled earlier */
}
break;
}
- dead_tmp(tmp2);
+ tcg_temp_free_i32(tmp2);
if (op == 1 || op == 3) {
/* Accumulate. */
@@ -4711,32 +4698,35 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
/* Insert */
switch (size) {
case 0:
- if (op == 4)
+ if (op == 4) {
mask = 0xff >> -shift;
- else
+ } else {
mask = (uint8_t)(0xff << shift);
+ }
mask |= mask << 8;
mask |= mask << 16;
break;
case 1:
- if (op == 4)
+ if (op == 4) {
mask = 0xffff >> -shift;
- else
+ } else {
mask = (uint16_t)(0xffff << shift);
+ }
mask |= mask << 16;
break;
case 2:
if (shift < -31 || shift > 31) {
mask = 0;
} else {
- if (op == 4)
+ if (op == 4) {
mask = 0xffffffffu >> -shift;
- else
+ } else {
mask = 0xffffffffu << shift;
+ }
}
break;
default:
- abort();
+ abort(); /* size == 3 is handled earlier */
}
tmp2 = neon_load_reg(rd, pass);
tcg_gen_andi_i32(tmp, tmp, mask);
@@ -4749,7 +4739,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
} /* for pass */
} else if (op < 10) {
/* Shift by immediate and narrow:
- VSHRN, VRSHRN, VQSHRN, VQRSHRN. */
+ VSHRN, VRSHRN, VQSHRN, VQSHRUN, VQRSHRN, VQRSHRUN */
+ if (rm & 1) {
+ return 1;
+ }
shift = shift - (1 << (size + 3));
size++;
switch (size) {
@@ -4776,51 +4769,61 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (size == 3) {
neon_load_reg64(cpu_V0, rm + pass);
if (q) {
- if (u)
- gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64);
- else
- gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64);
+ if ((op == 8 && !u) || (op == 9 && u)) {
+ gen_helper_neon_rshl_u64(cpu_V0, cpu_V0,
+ tmp64);
+ } else {
+ gen_helper_neon_rshl_s64(cpu_V0, cpu_V0,
+ tmp64);
+ }
} else {
- if (u)
- gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64);
- else
- gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64);
+ if ((op == 8 && !u) || (op == 9 && u)) {
+ gen_helper_neon_shl_u64(cpu_V0, cpu_V0,
+ tmp64);
+ } else {
+ gen_helper_neon_shl_s64(cpu_V0, cpu_V0,
+ tmp64);
+ }
}
} else {
tmp = neon_load_reg(rm + pass, 0);
- gen_neon_shift_narrow(size, tmp, tmp2, q, u);
+ gen_neon_shift_narrow(size, tmp, tmp2, q,
+ (op == 8) ? !u : u);
tmp3 = neon_load_reg(rm + pass, 1);
- gen_neon_shift_narrow(size, tmp3, tmp2, q, u);
+ gen_neon_shift_narrow(size, tmp3, tmp2, q,
+ (op == 8) ? !u : u);
tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
dead_tmp(tmp);
dead_tmp(tmp3);
}
tmp = new_tmp();
- if (op == 8 && !u) {
- gen_neon_narrow(size - 1, tmp, cpu_V0);
- } else {
- if (op == 8)
- gen_neon_narrow_sats(size - 1, tmp, cpu_V0);
- else
- gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
+ if (op == 8) {
+ if (u) { /* VQSHRUN / VQRSHRUN */
+ gen_neon_unarrow_sats(size - 1, tmp, cpu_V0);
+ } else { /* VSHRN / VRSHRN */
+ gen_neon_narrow(size - 1, tmp, cpu_V0);
+ }
+ } else { /* VQSHRN / VQRSHRN */
+ gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
}
neon_store_reg(rd, pass, tmp);
} /* for pass */
if (size == 3) {
tcg_temp_free_i64(tmp64);
} else {
- dead_tmp(tmp2);
+ tcg_temp_free_i32(tmp2);
}
} else if (op == 10) {
/* VSHLL */
- if (q || size == 3)
+ if (q) {
return 1;
+ }
tmp = neon_load_reg(rm, 0);
tmp2 = neon_load_reg(rm, 1);
for (pass = 0; pass < 2; pass++) {
- if (pass == 1)
+ if (pass == 1) {
tmp = tmp2;
-
+ }
gen_neon_widen(cpu_V0, tmp, size, u);
if (shift != 0) {
@@ -4841,22 +4844,29 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
neon_store_reg64(cpu_V0, rd + pass);
}
- } else if (op == 15 || op == 16) {
+ } else if (op == 14 || op == 15) {
/* VCVT fixed-point. */
+ if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
+ return 1;
+ }
for (pass = 0; pass < (q ? 4 : 2); pass++) {
- tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
+ tcg_gen_ld_f32(cpu_F0s, cpu_env,
+ neon_reg_offset(rm, pass));
if (op & 1) {
- if (u)
+ if (u) {
gen_vfp_ulto(0, shift);
- else
+ } else {
gen_vfp_slto(0, shift);
+ }
} else {
- if (u)
+ if (u) {
gen_vfp_toul(0, shift);
- else
+ } else {
gen_vfp_tosl(0, shift);
+ }
}
- tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
+ tcg_gen_st_f32(cpu_F0s, cpu_env,
+ neon_reg_offset(rd, pass));
}
} else {
return 1;
@@ -4895,10 +4905,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
break;
case 14:
imm |= (imm << 8) | (imm << 16) | (imm << 24);
- if (invert)
+ if (invert) {
imm = ~imm;
+ }
break;
case 15:
+ if (invert) {
+ return 1;
+ }
imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
| ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
break;
@@ -4937,36 +4951,22 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
} else { /* (insn & 0x00800010 == 0x00800000) */
if (size != 3) {
op = (insn >> 8) & 0xf;
- if ((insn & (1 << 6)) == 0) {
+ if (!q) {
/* Three registers of different lengths. */
- int src1_wide;
- int src2_wide;
- int prewiden;
- /* prewiden, src1_wide, src2_wide */
- static const int neon_3reg_wide[16][3] = {
- {1, 0, 0}, /* VADDL */
- {1, 1, 0}, /* VADDW */
- {1, 0, 0}, /* VSUBL */
- {1, 1, 0}, /* VSUBW */
- {0, 1, 1}, /* VADDHN */
- {0, 0, 0}, /* VABAL */
- {0, 1, 1}, /* VSUBHN */
- {0, 0, 0}, /* VABDL */
- {0, 0, 0}, /* VMLAL */
- {0, 0, 0}, /* VQDMLAL */
- {0, 0, 0}, /* VMLSL */
- {0, 0, 0}, /* VQDMLSL */
- {0, 0, 0}, /* Integer VMULL */
- {0, 0, 0}, /* VQDMULL */
- {0, 0, 0} /* Polynomial VMULL */
- };
-
- prewiden = neon_3reg_wide[op][0];
- src1_wide = neon_3reg_wide[op][1];
- src2_wide = neon_3reg_wide[op][2];
-
- if (size == 0 && (op == 9 || op == 11 || op == 13))
+
+ if (op == 15
+ || (op < 4 && ((rd & 1) || ((op & 1) && (rn & 1))))
+ || ((op == 4 || op == 6) && ((rn | rm) & 1))
+ || ((op == 5 || op >= 7) && (rd & 1))
+ || ((op == 9 || op == 11) && (u || size == 0))
+ || (op == 13 && size == 0)
+ || (op == 14 && (u || size))) {
return 1;
+ }
+
+ int src1_wide = (op == 1 || op == 3 || op == 4 || op == 6);
+ int src2_wide = (op == 4 || op == 6);
+ int prewiden = (op < 4);
/* Avoid overlapping operands. Wide source operands are
always aligned so will never overlap with wide
@@ -5033,7 +5033,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 5:
gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);
break;
- default: abort();
+ default: abort(); /* size == 3 is handled earlier */
}
dead_tmp(tmp2);
dead_tmp(tmp);
@@ -5048,7 +5048,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
cpu_abort(env, "Polynomial VMULL not implemented");
default: /* 15 is RESERVED. */
- return 1;
+ abort(); /* op == 15 is handled earlier */
}
if (op == 5 || op == 13 || (op >= 8 && op <= 11)) {
/* Accumulate. */
@@ -5091,7 +5091,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
tcg_gen_trunc_i64_i32(tmp, cpu_V0);
break;
- default: abort();
+ default: abort(); /* size == 3 is handled earlier */
}
} else {
switch (size) {
@@ -5106,7 +5106,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
tcg_gen_trunc_i64_i32(tmp, cpu_V0);
break;
- default: abort();
+ default: abort(); /* size == 3 is handled earlier */
}
}
if (pass == 0) {
@@ -5129,8 +5129,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 5: /* Floating point VMLS scalar */
case 8: /* Integer VMUL scalar */
case 9: /* Floating point VMUL scalar */
+ if (size <= (op & 1)) {
+ return 1;
+ }
+ /* fall through */
case 12: /* VQDMULH scalar */
case 13: /* VQRDMULH scalar */
+ if (u && ((rd | rn) & 1)) {
+ return 1;
+ }
tmp = neon_get_scalar(size, rm);
neon_store_scratch(0, tmp);
for (pass = 0; pass < (u ? 4 : 2); pass++) {
@@ -5138,24 +5145,35 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
tmp2 = neon_load_reg(rn, pass);
if (op == 12) {
if (size == 1) {
- gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
- } else {
- gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
+ gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp,
+ tmp2);
+ } else { /* TODO: what happens when size == 0? */
+ gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp,
+ tmp2);
}
} else if (op == 13) {
if (size == 1) {
- gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
- } else {
- gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
+ gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp,
+ tmp2);
+ } else { /* TODO: what happens when size == 0? */
+ gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp,
+ tmp2);
}
} else if (op & 1) {
gen_helper_neon_mul_f32(tmp, tmp, tmp2);
} else {
switch (size) {
- case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
- case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
- case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
- default: return 1;
+ case 0:
+ gen_helper_neon_mul_u8(tmp, tmp, tmp2);
+ break;
+ case 1:
+ gen_helper_neon_mul_u16(tmp, tmp, tmp2);
+ break;
+ case 2:
+ tcg_gen_mul_i32(tmp, tmp, tmp2);
+ break;
+ default:
+ abort(); /* size == 3 is handled earlier */
}
}
dead_tmp(tmp2);
@@ -5176,21 +5194,26 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
gen_helper_neon_sub_f32(tmp, tmp2, tmp);
break;
default:
- abort();
+ abort(); /* size == 3 is handled earlier */
}
dead_tmp(tmp2);
}
neon_store_reg(rd, pass, tmp);
}
break;
- case 2: /* VMLAL sclar */
case 3: /* VQDMLAL scalar */
- case 6: /* VMLSL scalar */
case 7: /* VQDMLSL scalar */
- case 10: /* VMULL scalar */
case 11: /* VQDMULL scalar */
- if (size == 0 && (op == 3 || op == 7 || op == 11))
+ if (u) {
+ return 1;
+ }
+ /* fall through */
+ case 2: /* VMLAL sclar */
+ case 6: /* VMLSL scalar */
+ case 10: /* VMULL scalar */
+ if (size == 0 || (rd & 1)) {
return 1;
+ }
tmp2 = neon_get_scalar(size, rm);
tmp3 = neon_load_reg(rn, 1);
@@ -5242,8 +5265,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
imm = (insn >> 8) & 0xf;
count = q + 1;
- if (imm > 7 && !q)
+ if ((imm > 7 && !q)
+ || (q && ((rd | rn | rm) & 1))) {
return 1;
+ }
if (imm == 0) {
neon_load_reg64(cpu_V0, rn);
@@ -5293,10 +5318,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
/* Two register misc. */
op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
size = (insn >> 18) & 3;
+ if ((q && (op < 36 || op > 46) && ((rd | rm) & 1))
+ || (op >= 56 && size != 2)) {
+ return 1;
+ }
switch (op) {
case 0: /* VREV64 */
- if (size == 3)
+ if (size == 3) {
return 1;
+ }
for (pass = 0; pass < (q ? 2 : 1); pass++) {
tmp = neon_load_reg(rm, pass * 2);
tmp2 = neon_load_reg(rm, pass * 2 + 1);
@@ -5321,8 +5351,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
break;
case 4: case 5: /* VPADDL */
case 12: case 13: /* VPADAL */
- if (size == 3)
+ if (size == 3) {
return 1;
+ }
for (pass = 0; pass < q + 1; pass++) {
tmp = neon_load_reg(rm, pass * 2);
gen_neon_widen(cpu_V0, tmp, size, op & 1);
@@ -5343,83 +5374,57 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
break;
case 33: /* VTRN */
- if (size == 2) {
+ switch (size) {
+ case 0: case 1:
+ goto elementwise;
+ case 2:
for (n = 0; n < (q ? 4 : 2); n += 2) {
tmp = neon_load_reg(rm, n);
tmp2 = neon_load_reg(rd, n + 1);
neon_store_reg(rm, n, tmp2);
neon_store_reg(rd, n + 1, tmp);
}
- } else {
- goto elementwise;
+ break;
+ default:
+ return 1;
}
break;
case 34: /* VUZP */
- /* Reg Before After
- Rd A3 A2 A1 A0 B2 B0 A2 A0
- Rm B3 B2 B1 B0 B3 B1 A3 A1
- */
- if (size == 3)
+ if (size == 3 || (!q && size == 2)) {
return 1;
- gen_neon_unzip(rd, q, 0, size);
- gen_neon_unzip(rm, q, 4, size);
- if (q) {
- static int unzip_order_q[8] =
- {0, 2, 4, 6, 1, 3, 5, 7};
- for (n = 0; n < 8; n++) {
- int reg = (n < 4) ? rd : rm;
- tmp = neon_load_scratch(unzip_order_q[n]);
- neon_store_reg(reg, n % 4, tmp);
- }
- } else {
- static int unzip_order[4] =
- {0, 4, 1, 5};
- for (n = 0; n < 4; n++) {
- int reg = (n < 2) ? rd : rm;
- tmp = neon_load_scratch(unzip_order[n]);
- neon_store_reg(reg, n % 2, tmp);
- }
}
+ tmp = tcg_const_i32(insn);
+ gen_helper_neon_unzip(cpu_env, tmp);
+ tcg_temp_free_i32(tmp);
break;
case 35: /* VZIP */
- /* Reg Before After
- Rd A3 A2 A1 A0 B1 A1 B0 A0
- Rm B3 B2 B1 B0 B3 A3 B2 A2
- */
- if (size == 3)
+ if (size == 3 || (!q && size == 2)) {
return 1;
- count = (q ? 4 : 2);
- for (n = 0; n < count; n++) {
- tmp = neon_load_reg(rd, n);
- tmp2 = neon_load_reg(rd, n);
- switch (size) {
- case 0: gen_neon_zip_u8(tmp, tmp2); break;
- case 1: gen_neon_zip_u16(tmp, tmp2); break;
- case 2: /* no-op */; break;
- default: abort();
- }
- neon_store_scratch(n * 2, tmp);
- neon_store_scratch(n * 2 + 1, tmp2);
- }
- for (n = 0; n < count * 2; n++) {
- int reg = (n < count) ? rd : rm;
- tmp = neon_load_scratch(n);
- neon_store_reg(reg, n % count, tmp);
}
+ tmp = tcg_const_i32(insn);
+ gen_helper_neon_zip(cpu_env, tmp);
+ tcg_temp_free_i32(tmp);
break;
case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
- if (size == 3)
+ if (size == 3 || (rm & 1)) {
return 1;
+ }
TCGV_UNUSED(tmp2);
for (pass = 0; pass < 2; pass++) {
neon_load_reg64(cpu_V0, rm + pass);
tmp = new_tmp();
- if (op == 36 && q == 0) {
- gen_neon_narrow(size, tmp, cpu_V0);
- } else if (q) {
- gen_neon_narrow_satu(size, tmp, cpu_V0);
- } else {
- gen_neon_narrow_sats(size, tmp, cpu_V0);
+ if (op == 36) {
+ if (q) { /* VQMOVUN */
+ gen_neon_unarrow_sats(size, tmp, cpu_V0);
+ } else { /* VMOVN */
+ gen_neon_narrow(size, tmp, cpu_V0);
+ }
+ } else { /* VQMOVN */
+ if (q) {
+ gen_neon_narrow_satu(size, tmp, cpu_V0);
+ } else {
+ gen_neon_narrow_sats(size, tmp, cpu_V0);
+ }
}
if (pass == 0) {
tmp2 = tmp;
@@ -5430,21 +5435,25 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
break;
case 38: /* VSHLL */
- if (q || size == 3)
+ if (q || size == 3 || (rd & 1)) {
return 1;
+ }
tmp = neon_load_reg(rm, 0);
tmp2 = neon_load_reg(rm, 1);
for (pass = 0; pass < 2; pass++) {
- if (pass == 1)
+ if (pass == 1) {
tmp = tmp2;
+ }
gen_neon_widen(cpu_V0, tmp, size, 1);
tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
neon_store_reg64(cpu_V0, rd + pass);
}
break;
case 44: /* VCVT.F16.F32 */
- if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
- return 1;
+ if (!arm_feature(env, ARM_FEATURE_VFP_FP16)
+ || q || size != 1 || (rm & 1)) {
+ return 1;
+ }
tmp = new_tmp();
tmp2 = new_tmp();
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
@@ -5465,8 +5474,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
dead_tmp(tmp);
break;
case 46: /* VCVT.F32.F16 */
- if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
- return 1;
+ if (!arm_feature(env, ARM_FEATURE_VFP_FP16)
+ || q || size != 1 || (rd & 1)) {
+ return 1;
+ }
tmp3 = new_tmp();
tmp = neon_load_reg(rm, 0);
tmp2 = neon_load_reg(rm, 1);
@@ -5501,38 +5512,44 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
switch (size) {
case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
case 1: gen_swap_half(tmp); break;
- default: return 1;
+ default: dead_tmp(tmp); return 1;
}
break;
case 2: /* VREV16 */
- if (size != 0)
+ if (size != 0) {
+ dead_tmp(tmp);
return 1;
+ }
gen_rev16(tmp);
break;
- case 8: /* CLS */
+ case 8: /* VCLS */
switch (size) {
case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
- default: return 1;
+ default: dead_tmp(tmp); return 1;
}
break;
- case 9: /* CLZ */
+ case 9: /* VCLZ */
switch (size) {
case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
case 2: gen_helper_clz(tmp, tmp); break;
- default: return 1;
+ default: dead_tmp(tmp); return 1;
}
break;
- case 10: /* CNT */
- if (size != 0)
+ case 10: /* VCNT */
+ if (size != 0) {
+ dead_tmp(tmp);
return 1;
+ }
gen_helper_neon_cnt_u8(tmp, tmp);
break;
- case 11: /* VNOT */
- if (size != 0)
+ case 11: /* VMVN */
+ if (size != 0) {
+ dead_tmp(tmp);
return 1;
+ }
tcg_gen_not_i32(tmp, tmp);
break;
case 14: /* VQABS */
@@ -5540,7 +5557,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 0: gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); break;
case 1: gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); break;
case 2: gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); break;
- default: return 1;
+ default: dead_tmp(tmp); return 1;
}
break;
case 15: /* VQNEG */
@@ -5548,84 +5565,112 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 0: gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); break;
case 1: gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); break;
case 2: gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); break;
- default: return 1;
+ default: dead_tmp(tmp); return 1;
}
break;
case 16: case 19: /* VCGT #0, VCLE #0 */
tmp2 = tcg_const_i32(0);
- switch(size) {
+ switch (size) {
case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
- default: return 1;
+ default: tcg_temp_free_i32(tmp2); dead_tmp(tmp); return 1;
}
- tcg_temp_free(tmp2);
- if (op == 19)
+ tcg_temp_free_i32(tmp2);
+ if (op == 19) {
tcg_gen_not_i32(tmp, tmp);
+ }
break;
case 17: case 20: /* VCGE #0, VCLT #0 */
tmp2 = tcg_const_i32(0);
- switch(size) {
+ switch (size) {
case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
- default: return 1;
+ default: tcg_temp_free_i32(tmp2); dead_tmp(tmp); return 1;
}
- tcg_temp_free(tmp2);
- if (op == 20)
+ tcg_temp_free_i32(tmp2);
+ if (op == 20) {
tcg_gen_not_i32(tmp, tmp);
+ }
break;
case 18: /* VCEQ #0 */
tmp2 = tcg_const_i32(0);
- switch(size) {
+ switch (size) {
case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
- default: return 1;
+ default: tcg_temp_free_i32(tmp2); dead_tmp(tmp); return 1;
}
- tcg_temp_free(tmp2);
+ tcg_temp_free_i32(tmp2);
break;
case 22: /* VABS */
- switch(size) {
+ switch (size) {
case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
case 2: tcg_gen_abs_i32(tmp, tmp); break;
- default: return 1;
+ default: dead_tmp(tmp); return 1;
}
break;
case 23: /* VNEG */
- if (size == 3)
+ if (size == 3) {
+ dead_tmp(tmp);
return 1;
+ }
tmp2 = tcg_const_i32(0);
gen_neon_rsb(size, tmp, tmp2);
- tcg_temp_free(tmp2);
+ tcg_temp_free_i32(tmp2);
break;
case 24: case 27: /* Float VCGT #0, Float VCLE #0 */
+ if (size != 2) {
+ dead_tmp(tmp);
+ return 1;
+ }
tmp2 = tcg_const_i32(0);
gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
- tcg_temp_free(tmp2);
- if (op == 27)
+ tcg_temp_free_i32(tmp2);
+ if (op == 27) {
tcg_gen_not_i32(tmp, tmp);
+ }
break;
case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
+ if (size != 2) {
+ dead_tmp(tmp);
+ return 1;
+ }
tmp2 = tcg_const_i32(0);
gen_helper_neon_cge_f32(tmp, tmp, tmp2);
- tcg_temp_free(tmp2);
- if (op == 28)
+ tcg_temp_free_i32(tmp2);
+ if (op == 28) {
tcg_gen_not_i32(tmp, tmp);
+ }
break;
case 26: /* Float VCEQ #0 */
+ if (size != 2) {
+ dead_tmp(tmp);
+ return 1;
+ }
tmp2 = tcg_const_i32(0);
gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
- tcg_temp_free(tmp2);
+ tcg_temp_free_i32(tmp2);
break;
case 30: /* Float VABS */
+ if (size != 2) {
+ return 1;
+ }
gen_vfp_abs(0);
break;
case 31: /* Float VNEG */
+ if (size != 2) {
+ return 1;
+ }
gen_vfp_neg(0);
break;
case 32: /* VSWP */
+ if (size != 0) {
+ dead_tmp(tmp);
+ return 1;
+ }
tmp2 = neon_load_reg(rd, pass);
neon_store_reg(rm, pass, tmp2);
break;
@@ -5634,8 +5679,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
switch (size) {
case 0: gen_neon_trn_u8(tmp, tmp2); break;
case 1: gen_neon_trn_u16(tmp, tmp2); break;
- case 2: abort();
- default: return 1;
+ default: abort(); /* size == 2,3 is handled earlier */
}
neon_store_reg(rm, pass, tmp2);
break;
@@ -5652,19 +5696,20 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
break;
case 60: /* VCVT.F32.S32 */
- gen_vfp_tosiz(0);
+ gen_vfp_sito(0);
break;
case 61: /* VCVT.F32.U32 */
- gen_vfp_touiz(0);
+ gen_vfp_uito(0);
break;
case 62: /* VCVT.S32.F32 */
- gen_vfp_sito(0);
+ gen_vfp_tosiz(0);
break;
case 63: /* VCVT.U32.F32 */
- gen_vfp_uito(0);
+ gen_vfp_touiz(0);
break;
default:
- /* Reserved: 21, 29, 39-56 */
+ /* Reserved: 3, 6, 7, 21, 29, 39-43, 45, 47-55 */
+ dead_tmp(tmp);
return 1;
}
if (op == 30 || op == 31 || op >= 58) {
@@ -5679,7 +5724,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
} else if ((insn & (1 << 10)) == 0) {
/* VTBL, VTBX. */
n = ((insn >> 5) & 0x18) + 8;
- if (insn & (1 << 6)) {
+ if (q) {
tmp = neon_load_reg(rd, 0);
} else {
tmp = new_tmp();
@@ -5690,7 +5735,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
tmp5 = tcg_const_i32(n);
gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5);
dead_tmp(tmp);
- if (insn & (1 << 6)) {
+ if (q) {
tmp = neon_load_reg(rd, 1);
} else {
tmp = new_tmp();
@@ -5705,6 +5750,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
dead_tmp(tmp);
} else if ((insn & 0x380) == 0) {
/* VDUP */
+ if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
+ return 1;
+ }
if (insn & (1 << 19)) {
tmp = neon_load_reg(rm, 1);
} else {
@@ -5713,10 +5761,11 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (insn & (1 << 16)) {
gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
} else if (insn & (1 << 17)) {
- if ((insn >> 18) & 1)
+ if ((insn >> 18) & 1) {
gen_neon_dup_high16(tmp);
- else
+ } else {
gen_neon_dup_low16(tmp);
+ }
}
for (pass = 0; pass < (q ? 4 : 2); pass++) {
tmp2 = new_tmp();
@@ -6343,11 +6392,22 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
dead_tmp(tmp2);
store_reg(s, rd, tmp);
break;
- case 7: /* bkpt */
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 4);
- gen_exception(EXCP_BKPT);
- s->is_jmp = DISAS_JUMP;
+ case 7:
+ if (op1 == 1) {
+ /* bkpt */
+ gen_set_condexec(s);
+ gen_set_pc_im(s->pc - 4);
+ gen_exception(EXCP_BKPT);
+ s->is_jmp = DISAS_JUMP;
+ } else if (op1 == 3) {
+ /* smi/smc */
+ if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s))
+ goto illegal_op;
+ /* TODO: real implementation; execute as NOP for now */
+ /*fprintf(stderr, "smc [0x%08x] pc=0x%08x\n", insn, s->pc);*/
+ } else {
+ goto illegal_op;
+ }
break;
case 0x8: /* signed multiply */
case 0xa:
@@ -6887,7 +6947,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 4: gen_uxtb16(tmp); break;
case 6: gen_uxtb(tmp); break;
case 7: gen_uxth(tmp); break;
- default: goto illegal_op;
+ default: dead_tmp(tmp); goto illegal_op;
}
if (rn != 15) {
tmp2 = load_reg(s, rn);
@@ -7097,7 +7157,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
}
rn = (insn >> 16) & 0xf;
addr = load_reg(s, rn);
-
+ tmp3 = tcg_const_i32(4);
+
/* compute total size */
loaded_base = 0;
TCGV_UNUSED(loaded_var);
@@ -7110,7 +7171,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
if (insn & (1 << 23)) {
if (insn & (1 << 24)) {
/* pre increment */
- tcg_gen_addi_i32(addr, addr, 4);
+ tcg_gen_add_i32(addr, addr, tmp3);
} else {
/* post increment */
}
@@ -7163,7 +7224,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
j++;
/* no need to add after the last transfer */
if (j != n)
- tcg_gen_addi_i32(addr, addr, 4);
+ tcg_gen_add_i32(addr, addr, tmp3);
}
}
if (insn & (1 << 21)) {
@@ -7173,7 +7234,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
/* pre increment */
} else {
/* post increment */
- tcg_gen_addi_i32(addr, addr, 4);
+ tcg_gen_add_i32(addr, addr, tmp3);
}
} else {
if (insn & (1 << 24)) {
@@ -7189,6 +7250,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
} else {
dead_tmp(addr);
}
+ tcg_temp_free_i32(tmp3);
if (loaded_base) {
store_reg(s, rn, loaded_var);
}
@@ -7565,6 +7627,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
tcg_gen_addi_i32(addr, addr, -offset);
}
+ tmp2 = tcg_const_i32(4);
for (i = 0; i < 16; i++) {
if ((insn & (1 << i)) == 0)
continue;
@@ -7581,8 +7644,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
tmp = load_reg(s, i);
gen_st32(tmp, addr, IS_USER(s));
}
- tcg_gen_addi_i32(addr, addr, 4);
+ tcg_gen_add_i32(addr, addr, tmp2);
}
+ tcg_temp_free_i32(tmp2);
if (insn & (1 << 21)) {
/* Base register writeback. */
if (insn & (1 << 24)) {
@@ -7882,7 +7946,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
/* Coprocessor. */
if (((insn >> 24) & 3) == 3) {
/* Translate into the equivalent ARM encoding. */
- insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4);
+ insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
if (disas_neon_data_insn(env, s, insn))
goto illegal_op;
} else {
@@ -8796,6 +8860,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
if ((insn & (1 << 11)) == 0) {
tcg_gen_addi_i32(addr, addr, -offset);
}
+ tmp2 = tcg_const_i32(4);
for (i = 0; i < 8; i++) {
if (insn & (1 << i)) {
if (insn & (1 << 11)) {
@@ -8808,7 +8873,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
gen_st32(tmp, addr, IS_USER(s));
}
/* advance to the next address. */
- tcg_gen_addi_i32(addr, addr, 4);
+ tcg_gen_add_i32(addr, addr, tmp2);
}
}
TCGV_UNUSED(tmp);
@@ -8823,8 +8888,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
tmp = load_reg(s, 14);
gen_st32(tmp, addr, IS_USER(s));
}
- tcg_gen_addi_i32(addr, addr, 4);
+ tcg_gen_add_i32(addr, addr, tmp2);
}
+ tcg_temp_free_i32(tmp2);
if ((insn & (1 << 11)) == 0) {
tcg_gen_addi_i32(addr, addr, -offset);
}
@@ -9017,9 +9083,12 @@ static inline void gen_intermediate_code_internal(CPUState *env,
uint32_t next_page_start;
int num_insns;
int max_insns;
+#ifdef RESOURCE_LEAK_DEBUG
+ int force_asmdump = 0;
/* generate intermediate code */
num_temps = 0;
+#endif
pc_start = tb->pc;
@@ -9049,6 +9118,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
cpu_V1 = cpu_F1d;
/* FIXME: cpu_M0 can probably be the same as cpu_V0. */
cpu_M0 = tcg_temp_new_i64();
+#ifdef RESOURCE_LEAK_DEBUG
+ num_temps = 0; /* to ignore above global temporaries from the count */
+#endif
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
lj = -1;
num_insns = 0;
@@ -9115,6 +9187,10 @@ static inline void gen_intermediate_code_internal(CPUState *env,
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+ tcg_gen_debug_insn_start(dc->pc);
+ }
+
if (env->thumb) {
disas_thumb_insn(env, dc);
if (dc->condexec_mask) {
@@ -9128,10 +9204,13 @@ static inline void gen_intermediate_code_internal(CPUState *env,
} else {
disas_arm_insn(env, dc);
}
+#ifdef RESOURCE_LEAK_DEBUG
if (num_temps) {
fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
+ force_asmdump = 1;
num_temps = 0;
}
+#endif
if (dc->condjmp && !dc->is_jmp) {
gen_set_label(dc->condlabel);
@@ -9225,6 +9304,14 @@ done_generating:
gen_icount_end(tb, num_insns);
*gen_opc_ptr = INDEX_op_end;
+#ifdef RESOURCE_LEAK_DEBUG
+ if (force_asmdump) {
+ fprintf(stderr, "----------------\n");
+ fprintf(stderr, "IN: %s\n", lookup_symbol(pc_start));
+ target_disas(stderr, pc_start, dc->pc - pc_start, env->thumb);
+ fprintf(stderr, "\n");
+ }
+#endif
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("----------------\n");
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 12/48] cocoa frontend changes
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (7 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 10/48] Lots of ARM TCG changes Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-27 13:28 ` Andreas Färber
2010-03-26 16:06 ` [Qemu-devel] [PATCH 13/48] multitouch and window close handler Riku Voipio
` (35 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
remove help menu, fix fullscreen mode mouse handling, add confirmation
dialog to quit menu command, add support for undocumented alt-grab and
ctrl-grab options, add qemu version printout in about panel.
- fix build on os x versions prior to 10.6
- cocoa window handling fixes
- show shutting down status in window caption
- add display close handler support
- add support for multitouch in cocoa frontend
- cocoa keymap changes
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
cocoa.m | 313 +++++++++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 217 insertions(+), 96 deletions(-)
diff --git a/cocoa.m b/cocoa.m
index 56c789a..524617f 100644
--- a/cocoa.m
+++ b/cocoa.m
@@ -47,10 +47,25 @@
#define cgrect(nsrect) (*(CGRect *)&(nsrect))
#define COCOA_MOUSE_EVENT \
if (isTabletEnabled) { \
- kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
+ if (isFullscreen) { \
+ NSSize fs = [[NSScreen mainScreen] frame].size; \
+ kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
+ (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
+ 0, buttons); \
+ } else { \
+ kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), \
+ (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), \
+ 0, buttons); \
+ } \
} else if (isMouseGrabed) { \
kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
} else { \
+ if (isFullscreen) { \
+ NSSize fs = [[NSScreen mainScreen] frame].size; \
+ kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
+ (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
+ 0, buttons); \
+ } \
[NSApp sendEvent:event]; \
}
@@ -65,6 +80,7 @@ int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
NSWindow *normalWindow;
id cocoaView;
static DisplayChangeListener *dcl;
+static int last_vm_running;
int gArgc;
char **gArgv;
@@ -83,7 +99,7 @@ int keymap[] =
45, // 7 0x07 0x2d X QZ_x
46, // 8 0x08 0x2e C QZ_c
47, // 9 0x09 0x2f V QZ_v
- 0, // 10 0x0A Undefined
+ 0, // 10 0x0A Undefined (paragraph)
48, // 11 0x0B 0x30 B QZ_b
16, // 12 0x0C 0x10 Q QZ_q
17, // 13 0x0D 0x11 W QZ_w
@@ -127,8 +143,8 @@ int keymap[] =
14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
0, // 52 0x34 Undefined
1, // 53 0x35 0x01 ESC QZ_ESCAPE
- 0, // 54 0x36 QZ_RMETA
- 0, // 55 0x37 QZ_LMETA
+ 220,// 54 0xdc e0,5c R GUI QZ_RMETA
+ 219,// 55 0xdb e0,5b L GUI QZ_LMETA
42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
56, // 58 0x3A 0x38 L ALT QZ_LALT
@@ -136,9 +152,9 @@ int keymap[] =
54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
- 0, // 63 0x3F Undefined
- 0, // 64 0x40 Undefined
- 0, // 65 0x41 Undefined
+ 0, // 63 0x3F Undefined (fn)
+ 0, // 64 0x40 Undefined (f17)
+ 83, // 65 0x53 0x53 KP .
0, // 66 0x42 Undefined
55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
0, // 68 0x44 Undefined
@@ -152,9 +168,9 @@ int keymap[] =
152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
0, // 77 0x4D undefined
74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
- 0, // 79 0x4F Undefined
- 0, // 80 0x50 Undefined
- 0, // 81 0x51 QZ_KP_EQUALS
+ 0, // 79 0x4F Undefined (f18)
+ 0, // 80 0x50 Undefined (f19)
+ 0, // 81 0x51 (kp =) QZ_KP_EQUALS
82, // 82 0x52 0x52 KP 0 QZ_KP0
79, // 83 0x53 0x4f KP 1 QZ_KP1
80, // 84 0x54 0x50 KP 2 QZ_KP2
@@ -178,15 +194,15 @@ int keymap[] =
0, // 102 0x66 Undefined
87, // 103 0x67 0x57 F11 QZ_F11
0, // 104 0x68 Undefined
- 183,// 105 0x69 0xb7 QZ_PRINT
+ 183,// 105 0x69 0xb7 (f13) QZ_PRINT
0, // 106 0x6A Undefined
- 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
+ 70, // 107 0x6B 0x46 SCROLL(f14) QZ_SCROLLOCK
0, // 108 0x6C Undefined
68, // 109 0x6D 0x44 F10 QZ_F10
0, // 110 0x6E Undefined
88, // 111 0x6F 0x58 F12 QZ_F12
0, // 112 0x70 Undefined
- 110,// 113 0x71 0x0 QZ_PAUSE
+ 110,// 113 0x71 0x0 (f15) QZ_PAUSE
210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
@@ -204,12 +220,9 @@ int keymap[] =
/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
/*
- 219 // 0xdb e0,5b L GUI
- 220 // 0xdc e0,5c R GUI
221 // 0xdd e0,5d APPS
// E0,2A,E0,37 PRNT SCRN
// E1,1D,45,E1,9D,C5 PAUSE
- 83 // 0x53 0x53 KP .
// ACPI Scan Codes
222 // 0xde E0, 5E Power
223 // 0xdf E0, 5F Sleep
@@ -259,23 +272,29 @@ static int cocoa_keycode_to_qemu(int keycode)
NSWindow *fullScreenWindow;
float cx,cy,cw,ch,cdx,cdy;
CGDataProviderRef dataProviderRef;
+ void *dataRawPtr;
+ int mouseX, mouseY;
int modifiers_state[256];
BOOL isMouseGrabed;
BOOL isFullscreen;
BOOL isAbsoluteEnabled;
BOOL isTabletEnabled;
+ BOOL isShuttingDownGuest;
}
- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
- (void) grabMouse;
- (void) ungrabMouse;
- (void) toggleFullScreen:(id)sender;
-- (void) handleEvent:(NSEvent *)event;
+- (void) qemuHandleEvent:(NSEvent *)event;
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
+- (void) setShuttingDownGuest;
- (BOOL) isMouseGrabed;
- (BOOL) isAbsoluteEnabled;
- (float) cdx;
- (float) cdy;
- (QEMUScreen) gscreen;
+- (void) updateCaption;
+- (void) checkAndDisplayAltCursor;
@end
@implementation QemuCocoaView
@@ -310,6 +329,34 @@ static int cocoa_keycode_to_qemu(int keycode)
return YES;
}
+- (void) checkAndDisplayAltCursor
+{
+ if (multitouch_enabled && !isMouseGrabed && !cursor_hide &&
+ dataRawPtr && modifiers_state[56]) {
+ unsigned char *p = (unsigned char *)dataRawPtr;
+ int altX = screen.width - mouseX;
+ int altY = mouseY;
+ int x, y;
+ int bytesperpixel = screen.bitsPerPixel / 8;
+ p += (altY * screen.width) * bytesperpixel;
+ for (y = 0; y < 8; y++) {
+ if (y + altY > 0 && y + altY < screen.height) {
+ unsigned char *q = p + altX * bytesperpixel;
+ for (x = 0; x < 8; x++) {
+ if (x + altX > 0 && x + altX < screen.width) {
+ int i;
+ for (i = 0; i < bytesperpixel; i++) {
+ q[i] ^= 0xff;
+ }
+ }
+ q += bytesperpixel;
+ }
+ }
+ p += screen.width * bytesperpixel;
+ }
+ }
+}
+
- (void) drawRect:(NSRect) rect
{
COCOA_DEBUG("QemuCocoaView: drawRect\n");
@@ -321,6 +368,7 @@ static int cocoa_keycode_to_qemu(int keycode)
// draw screen bitmap directly to Core Graphics context
if (dataProviderRef) {
+ [self checkAndDisplayAltCursor];
CGImageRef imageRef = CGImageCreate(
screen.width, //width
screen.height, //height
@@ -360,10 +408,10 @@ static int cocoa_keycode_to_qemu(int keycode)
[self getRectsBeingDrawn:&rectList count:&rectCount];
for (i = 0; i < rectCount; i++) {
- clipRect.origin.x = rectList[i].origin.x / cdx;
- clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
- clipRect.size.width = rectList[i].size.width / cdx;
- clipRect.size.height = rectList[i].size.height / cdy;
+ clipRect.origin.x = floorf(rectList[i].origin.x / cdx);
+ clipRect.origin.y = floorf((float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy);
+ clipRect.size.width = ceilf(rectList[i].size.width / cdx);
+ clipRect.size.height = ceilf(rectList[i].size.height / cdy);
clipImageRef = CGImageCreateWithImageInRect(
imageRef,
clipRect
@@ -410,6 +458,7 @@ static int cocoa_keycode_to_qemu(int keycode)
screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
+ dataRawPtr = is_graphic_console() ? ds_get_data(ds) : 0;
dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
// update windows
@@ -417,10 +466,9 @@ static int cocoa_keycode_to_qemu(int keycode)
[[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
[normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
} else {
- if (qemu_name)
- [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
[normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
}
+ [self updateCaption];
screen.width = w;
screen.height = h;
[normalWindow center];
@@ -434,7 +482,7 @@ static int cocoa_keycode_to_qemu(int keycode)
if (isFullscreen) { // switch from fullscreen to desktop
isFullscreen = FALSE;
- [self ungrabMouse];
+ if (isMouseGrabed) [self ungrabMouse];
[self setContentDimensions];
// test if host supports "exitFullScreenModeWithOptions" at compile time
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
@@ -444,29 +492,33 @@ static int cocoa_keycode_to_qemu(int keycode)
#endif
[fullScreenWindow close];
[normalWindow setContentView: self];
- [normalWindow makeKeyAndOrderFront: self];
[NSMenu setMenuBarVisible:YES];
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
}
#endif
+ [normalWindow makeKeyAndOrderFront:self];
} else { // switch from desktop to fullscreen
isFullscreen = TRUE;
- [self grabMouse];
+ if (cursor_allow_grab) [self grabMouse];
[self setContentDimensions];
+ [normalWindow orderOut:self];
// test if host supports "enterFullScreenMode:withOptions" at compile time
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
- [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
- [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
- nil]];
+ [self enterFullScreenMode:[NSScreen mainScreen]
+ withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:NO], kCGDisplayModeIsStretched,
+ nil], NSFullScreenModeSetting,
+ nil]];
} else {
#endif
[NSMenu setMenuBarVisible:NO];
fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
[fullScreenWindow setHasShadow:NO];
[fullScreenWindow setContentView:self];
[fullScreenWindow makeKeyAndOrderFront:self];
@@ -476,7 +528,7 @@ static int cocoa_keycode_to_qemu(int keycode)
}
}
-- (void) handleEvent:(NSEvent *)event
+- (void) qemuHandleEvent:(NSEvent *)event
{
COCOA_DEBUG("QemuCocoaView: handleEvent\n");
@@ -505,8 +557,13 @@ static int cocoa_keycode_to_qemu(int keycode)
}
// release Mouse grab when pressing ctrl+alt
- if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
- [self ungrabMouse];
+ if (!isFullscreen) {
+ if ((ctrl_grab && [event keyCode] == 0x3e)
+ || ((([event modifierFlags] & NSControlKeyMask) &&
+ ([event modifierFlags] & NSAlternateKeyMask))
+ && (!alt_grab || ([event modifierFlags] & NSShiftKeyMask)))) {
+ [self ungrabMouse];
+ }
}
break;
case NSKeyDown:
@@ -581,15 +638,17 @@ static int cocoa_keycode_to_qemu(int keycode)
}
break;
case NSMouseMoved:
+ mouseX = p.x;
+ mouseY = p.y;
if (isAbsoluteEnabled) {
if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
if (isTabletEnabled) { // if we leave the window, deactivate the tablet
- [NSCursor unhide];
+ if (cursor_hide) [NSCursor unhide];
isTabletEnabled = FALSE;
}
} else {
if (!isTabletEnabled) { // if we enter the window, activate the tablet
- [NSCursor hide];
+ if (cursor_hide) [NSCursor hide];
isTabletEnabled = TRUE;
}
}
@@ -602,6 +661,9 @@ static int cocoa_keycode_to_qemu(int keycode)
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
+ if ([event modifierFlags] & NSAlternateKeyMask) {
+ buttons |= MOUSE_EVENT_MBUTTON << 1;
+ }
COCOA_MOUSE_EVENT
break;
case NSRightMouseDown:
@@ -613,11 +675,16 @@ static int cocoa_keycode_to_qemu(int keycode)
COCOA_MOUSE_EVENT
break;
case NSLeftMouseDragged:
+ mouseX = p.x;
+ mouseY = p.y;
if ([event modifierFlags] & NSCommandKeyMask) {
buttons |= MOUSE_EVENT_RBUTTON;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
+ if ([event modifierFlags] & NSAlternateKeyMask) {
+ buttons |= MOUSE_EVENT_MBUTTON << 1;
+ }
COCOA_MOUSE_EVENT
break;
case NSRightMouseDragged:
@@ -633,7 +700,7 @@ static int cocoa_keycode_to_qemu(int keycode)
COCOA_MOUSE_EVENT
} else if (!isMouseGrabed) {
if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
- [self grabMouse];
+ if (cursor_allow_grab) [self grabMouse];
} else {
[NSApp sendEvent:event];
}
@@ -654,6 +721,25 @@ static int cocoa_keycode_to_qemu(int keycode)
[NSApp sendEvent:event];
}
break;
+ case NSAppKitDefined:
+ switch ([event subtype]) {
+ case NSApplicationActivatedEventType:
+ if (dcl) {
+ dcl->gui_timer_interval = 0;
+ dcl->idle = 0;
+ }
+ break;
+ case NSApplicationDeactivatedEventType:
+ if (dcl) {
+ dcl->gui_timer_interval = 500;
+ dcl->idle = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ [NSApp sendEvent:event];
+ break;
default:
[NSApp sendEvent:event];
}
@@ -662,34 +748,48 @@ static int cocoa_keycode_to_qemu(int keycode)
- (void) grabMouse
{
COCOA_DEBUG("QemuCocoaView: grabMouse\n");
-
- if (!isFullscreen) {
- if (qemu_name)
- [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
- else
- [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
- }
- [NSCursor hide];
+ if (cursor_hide) [NSCursor hide];
CGAssociateMouseAndMouseCursorPosition(FALSE);
isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
+ [self updateCaption];
}
- (void) ungrabMouse
{
COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
- if (!isFullscreen) {
- if (qemu_name)
- [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
- else
- [normalWindow setTitle:@"QEMU"];
- }
- [NSCursor unhide];
+ if (cursor_hide) [NSCursor unhide];
CGAssociateMouseAndMouseCursorPosition(TRUE);
isMouseGrabed = FALSE;
+ [self updateCaption];
+}
+
+- (void) updateCaption
+{
+ NSMutableString *caption = [NSMutableString stringWithCapacity:10];
+ [caption appendFormat:@"QEMU"];
+ if (isShuttingDownGuest) {
+ [caption appendString:@" [Shutting down]"];
+ }
+ if (qemu_name) {
+ [caption appendFormat:@" (%s)", qemu_name];
+ }
+ if (!vm_running) {
+ [caption appendString:@" [Stopped]"];
+ } else if (isMouseGrabed) {
+ if (ctrl_grab) {
+ [caption appendString:@" - Press Right-Ctrl to release mouse"];
+ } else if (alt_grab) {
+ [caption appendString:@" - Press Ctrl-Alt-Shift to release mouse"];
+ } else {
+ [caption appendString:@" - Press Ctrl-Alt to release mouse"];
+ }
+ }
+ [normalWindow setTitle:caption];
}
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
+- (void) setShuttingDownGuest { isShuttingDownGuest = YES; [self updateCaption]; }
- (BOOL) isMouseGrabed {return isMouseGrabed;}
- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
- (float) cdx {return cdx;}
@@ -704,14 +804,16 @@ static int cocoa_keycode_to_qemu(int keycode)
QemuCocoaAppController
------------------------------------------------------
*/
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
+@interface QemuCocoaAppController : NSObject <NSWindowDelegate>
+#else
@interface QemuCocoaAppController : NSObject
+#endif
{
}
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)toggleFullScreen:(id)sender;
-- (void)showQEMUDoc:(id)sender;
-- (void)showQEMUTec:(id)sender;
@end
@implementation QemuCocoaAppController
@@ -743,7 +845,8 @@ static int cocoa_keycode_to_qemu(int keycode)
[normalWindow useOptimizedDrawing:YES];
[normalWindow makeKeyAndOrderFront:self];
[normalWindow center];
-
+ [normalWindow setDelegate:self];
+ [cocoaView updateCaption];
}
return self;
}
@@ -781,7 +884,6 @@ static int cocoa_keycode_to_qemu(int keycode)
COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
qemu_system_shutdown_request();
- exit(0);
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
@@ -819,6 +921,7 @@ static int cocoa_keycode_to_qemu(int keycode)
[self startEmulationWithArgc:3 argv:(char**)argv];
}
}
+
- (void)toggleFullScreen:(id)sender
{
COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
@@ -826,41 +929,57 @@ static int cocoa_keycode_to_qemu(int keycode)
[cocoaView toggleFullScreen:sender];
}
-- (void)showQEMUDoc:(id)sender
+- (BOOL)windowShouldClose:(id)sender
{
- COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
-
- [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
- [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+ if (!no_quit) {
+ if (qemu_run_display_close_handler()) {
+ return YES;
+ }
+ [cocoaView setShuttingDownGuest];
+ }
+ return NO;
}
-- (void)showQEMUTec:(id)sender
+- (void)confirmQuit:(id)sender
{
- COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
+ NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to quit QEMU?"
+ defaultButton:@"No"
+ alternateButton:@"Yes"
+ otherButton:@"Shutdown"
+ informativeTextWithFormat:@"If you quit QEMU without shutting down the emulated machine properly you risk losing data and possibly corrupting the virtual machine contents."];
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ switch ([alert runModal]) {
+ case NSAlertDefaultReturn:
+ /* do nothing */
+ break;
+ case NSAlertAlternateReturn:
+ [NSApp terminate:sender];
+ break;
+ case NSAlertOtherReturn:
+ if (qemu_run_display_close_handler()) {
+ qemu_system_shutdown_request();
+ } else {
+ [cocoaView setShuttingDownGuest];
+ }
+ break;
+ default:
+ break;
+ }
+}
- [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
- [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+- (void)aboutQEMU:(id)sender
+{
+ [NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionaryWithObjectsAndKeys:
+ @ QEMU_VERSION QEMU_PKGVERSION, @"ApplicationVersion",
+ nil]];
}
@end
-
-// Dock Connection
-typedef struct CPSProcessSerNum
+int main (int argc, const char * argv[])
{
- UInt32 lo;
- UInt32 hi;
-} CPSProcessSerNum;
-
-extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
-extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
-extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
-
-int main (int argc, const char * argv[]) {
-
gArgc = argc;
gArgv = (char **)argv;
- CPSProcessSerNum PSN;
int i;
/* In case we don't need to display a window, let's not do that */
@@ -875,10 +994,11 @@ int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication];
- if (!CPSGetCurrentProcess(&PSN))
- if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
- if (!CPSSetFrontProcess(&PSN))
- [NSApplication sharedApplication];
+ ProcessSerialNumber PSN;
+ if (!GetCurrentProcess(&PSN) &&
+ !TransformProcessType(&PSN, kProcessTransformToForegroundApplication) &&
+ !SetFrontProcess(&PSN))
+ [NSApplication sharedApplication];
// Add menus
NSMenu *menu;
@@ -888,14 +1008,14 @@ int main (int argc, const char * argv[]) {
// Application menu
menu = [[NSMenu alloc] initWithTitle:@""];
- [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
+ [menu addItemWithTitle:@"About QEMU" action:@selector(aboutQEMU:) keyEquivalent:@""]; // About QEMU
[menu addItem:[NSMenuItem separatorItem]]; //Separator
[menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
[menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
[menu addItem:[NSMenuItem separatorItem]]; //Separator
- [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
+ [menu addItemWithTitle:@"Quit QEMU" action:@selector(confirmQuit:) keyEquivalent:@"q"];
menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
[menuItem setSubmenu:menu];
[[NSApp mainMenu] addItem:menuItem];
@@ -916,14 +1036,6 @@ int main (int argc, const char * argv[]) {
[[NSApp mainMenu] addItem:menuItem];
[NSApp setWindowsMenu:menu];
- // Help menu
- menu = [[NSMenu alloc] initWithTitle:@"Help"];
- [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
- [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
- menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
- [menuItem setSubmenu:menu];
- [[NSApp mainMenu] addItem:menuItem];
-
// Create an Application controller
QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
[NSApp setDelegate:appController];
@@ -968,6 +1080,11 @@ static void cocoa_refresh(DisplayState *ds)
{
COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
+ if (last_vm_running != vm_running) {
+ last_vm_running = vm_running;
+ [cocoaView updateCaption];
+ }
+
if (kbd_mouse_is_absolute()) {
if (![cocoaView isAbsoluteEnabled]) {
if ([cocoaView isMouseGrabed]) {
@@ -984,7 +1101,7 @@ static void cocoa_refresh(DisplayState *ds)
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
inMode: NSDefaultRunLoopMode dequeue:YES];
if (event != nil) {
- [cocoaView handleEvent:event];
+ [cocoaView qemuHandleEvent:event];
}
} while(event != nil);
vga_hw_update();
@@ -1012,3 +1129,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
// register cleanup function
atexit(cocoa_cleanup);
}
+
+#ifdef CONFIG_GLHW
+#include "hw/gl/opengl_host_cocoa.m"
+#endif
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 12/48] cocoa frontend changes
2010-03-26 16:06 ` [Qemu-devel] [PATCH 12/48] cocoa frontend changes Riku Voipio
@ 2010-03-27 13:28 ` Andreas Färber
0 siblings, 0 replies; 55+ messages in thread
From: Andreas Färber @ 2010-03-27 13:28 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, Juha Riihimäki, qemu-devel
Hello,
Am 26.03.2010 um 17:06 schrieb Riku Voipio:
> From: Juha Riihimäki <juha.riihimaki@nokia.com>
>
> remove help menu, fix fullscreen mode mouse handling, add confirmation
> dialog to quit menu command, add support for undocumented alt-grab and
> ctrl-grab options, add qemu version printout in about panel.
> - fix build on os x versions prior to 10.6
> - cocoa window handling fixes
> - show shutting down status in window caption
> - add display close handler support
> - add support for multitouch in cocoa frontend
> - cocoa keymap changes
I would appreciate if you could untangle these for review by splitting this patch up.
Last time I built on 10.5/ppc there were no build issues in Cocoa, for instance.
Further comment inline.
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
> Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
> ---
> cocoa.m | 313 +++++++++++++++++++++++++++++++++++++++++++-------------------
> 1 files changed, 217 insertions(+), 96 deletions(-)
>
> diff --git a/cocoa.m b/cocoa.m
> index 56c789a..524617f 100644
> --- a/cocoa.m
> +++ b/cocoa.m
> @@ -47,10 +47,25 @@
> #define cgrect(nsrect) (*(CGRect *)&(nsrect))
> #define COCOA_MOUSE_EVENT \
Since this macro is growing large, could you consider turning it into a static inline function please?
Regards,
Andreas
> if (isTabletEnabled) { \
> - kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
> + if (isFullscreen) { \
> + NSSize fs = [[NSScreen mainScreen] frame].size; \
> + kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
> + (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
> + 0, buttons); \
> + } else { \
> + kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), \
> + (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), \
> + 0, buttons); \
> + } \
> } else if (isMouseGrabed) { \
> kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
> } else { \
> + if (isFullscreen) { \
> + NSSize fs = [[NSScreen mainScreen] frame].size; \
> + kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
> + (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
> + 0, buttons); \
> + } \
> [NSApp sendEvent:event]; \
> }
>
> @@ -65,6 +80,7 @@ int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
> NSWindow *normalWindow;
> id cocoaView;
> static DisplayChangeListener *dcl;
> +static int last_vm_running;
>
> int gArgc;
> char **gArgv;
> @@ -83,7 +99,7 @@ int keymap[] =
> 45, // 7 0x07 0x2d X QZ_x
> 46, // 8 0x08 0x2e C QZ_c
> 47, // 9 0x09 0x2f V QZ_v
> - 0, // 10 0x0A Undefined
> + 0, // 10 0x0A Undefined (paragraph)
> 48, // 11 0x0B 0x30 B QZ_b
> 16, // 12 0x0C 0x10 Q QZ_q
> 17, // 13 0x0D 0x11 W QZ_w
> @@ -127,8 +143,8 @@ int keymap[] =
> 14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
> 0, // 52 0x34 Undefined
> 1, // 53 0x35 0x01 ESC QZ_ESCAPE
> - 0, // 54 0x36 QZ_RMETA
> - 0, // 55 0x37 QZ_LMETA
> + 220,// 54 0xdc e0,5c R GUI QZ_RMETA
> + 219,// 55 0xdb e0,5b L GUI QZ_LMETA
> 42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
> 58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
> 56, // 58 0x3A 0x38 L ALT QZ_LALT
> @@ -136,9 +152,9 @@ int keymap[] =
> 54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
> 184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
> 157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
> - 0, // 63 0x3F Undefined
> - 0, // 64 0x40 Undefined
> - 0, // 65 0x41 Undefined
> + 0, // 63 0x3F Undefined (fn)
> + 0, // 64 0x40 Undefined (f17)
> + 83, // 65 0x53 0x53 KP .
> 0, // 66 0x42 Undefined
> 55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
> 0, // 68 0x44 Undefined
> @@ -152,9 +168,9 @@ int keymap[] =
> 152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
> 0, // 77 0x4D undefined
> 74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
> - 0, // 79 0x4F Undefined
> - 0, // 80 0x50 Undefined
> - 0, // 81 0x51 QZ_KP_EQUALS
> + 0, // 79 0x4F Undefined (f18)
> + 0, // 80 0x50 Undefined (f19)
> + 0, // 81 0x51 (kp =) QZ_KP_EQUALS
> 82, // 82 0x52 0x52 KP 0 QZ_KP0
> 79, // 83 0x53 0x4f KP 1 QZ_KP1
> 80, // 84 0x54 0x50 KP 2 QZ_KP2
> @@ -178,15 +194,15 @@ int keymap[] =
> 0, // 102 0x66 Undefined
> 87, // 103 0x67 0x57 F11 QZ_F11
> 0, // 104 0x68 Undefined
> - 183,// 105 0x69 0xb7 QZ_PRINT
> + 183,// 105 0x69 0xb7 (f13) QZ_PRINT
> 0, // 106 0x6A Undefined
> - 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
> + 70, // 107 0x6B 0x46 SCROLL(f14) QZ_SCROLLOCK
> 0, // 108 0x6C Undefined
> 68, // 109 0x6D 0x44 F10 QZ_F10
> 0, // 110 0x6E Undefined
> 88, // 111 0x6F 0x58 F12 QZ_F12
> 0, // 112 0x70 Undefined
> - 110,// 113 0x71 0x0 QZ_PAUSE
> + 110,// 113 0x71 0x0 (f15) QZ_PAUSE
> 210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
> 199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
> 201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
> @@ -204,12 +220,9 @@ int keymap[] =
>
> /* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
> /*
> - 219 // 0xdb e0,5b L GUI
> - 220 // 0xdc e0,5c R GUI
> 221 // 0xdd e0,5d APPS
> // E0,2A,E0,37 PRNT SCRN
> // E1,1D,45,E1,9D,C5 PAUSE
> - 83 // 0x53 0x53 KP .
> // ACPI Scan Codes
> 222 // 0xde E0, 5E Power
> 223 // 0xdf E0, 5F Sleep
> @@ -259,23 +272,29 @@ static int cocoa_keycode_to_qemu(int keycode)
> NSWindow *fullScreenWindow;
> float cx,cy,cw,ch,cdx,cdy;
> CGDataProviderRef dataProviderRef;
> + void *dataRawPtr;
> + int mouseX, mouseY;
> int modifiers_state[256];
> BOOL isMouseGrabed;
> BOOL isFullscreen;
> BOOL isAbsoluteEnabled;
> BOOL isTabletEnabled;
> + BOOL isShuttingDownGuest;
> }
> - (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
> - (void) grabMouse;
> - (void) ungrabMouse;
> - (void) toggleFullScreen:(id)sender;
> -- (void) handleEvent:(NSEvent *)event;
> +- (void) qemuHandleEvent:(NSEvent *)event;
> - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
> +- (void) setShuttingDownGuest;
> - (BOOL) isMouseGrabed;
> - (BOOL) isAbsoluteEnabled;
> - (float) cdx;
> - (float) cdy;
> - (QEMUScreen) gscreen;
> +- (void) updateCaption;
> +- (void) checkAndDisplayAltCursor;
> @end
>
> @implementation QemuCocoaView
> @@ -310,6 +329,34 @@ static int cocoa_keycode_to_qemu(int keycode)
> return YES;
> }
>
> +- (void) checkAndDisplayAltCursor
> +{
> + if (multitouch_enabled && !isMouseGrabed && !cursor_hide &&
> + dataRawPtr && modifiers_state[56]) {
> + unsigned char *p = (unsigned char *)dataRawPtr;
> + int altX = screen.width - mouseX;
> + int altY = mouseY;
> + int x, y;
> + int bytesperpixel = screen.bitsPerPixel / 8;
> + p += (altY * screen.width) * bytesperpixel;
> + for (y = 0; y < 8; y++) {
> + if (y + altY > 0 && y + altY < screen.height) {
> + unsigned char *q = p + altX * bytesperpixel;
> + for (x = 0; x < 8; x++) {
> + if (x + altX > 0 && x + altX < screen.width) {
> + int i;
> + for (i = 0; i < bytesperpixel; i++) {
> + q[i] ^= 0xff;
> + }
> + }
> + q += bytesperpixel;
> + }
> + }
> + p += screen.width * bytesperpixel;
> + }
> + }
> +}
> +
> - (void) drawRect:(NSRect) rect
> {
> COCOA_DEBUG("QemuCocoaView: drawRect\n");
> @@ -321,6 +368,7 @@ static int cocoa_keycode_to_qemu(int keycode)
>
> // draw screen bitmap directly to Core Graphics context
> if (dataProviderRef) {
> + [self checkAndDisplayAltCursor];
> CGImageRef imageRef = CGImageCreate(
> screen.width, //width
> screen.height, //height
> @@ -360,10 +408,10 @@ static int cocoa_keycode_to_qemu(int keycode)
>
> [self getRectsBeingDrawn:&rectList count:&rectCount];
> for (i = 0; i < rectCount; i++) {
> - clipRect.origin.x = rectList[i].origin.x / cdx;
> - clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
> - clipRect.size.width = rectList[i].size.width / cdx;
> - clipRect.size.height = rectList[i].size.height / cdy;
> + clipRect.origin.x = floorf(rectList[i].origin.x / cdx);
> + clipRect.origin.y = floorf((float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy);
> + clipRect.size.width = ceilf(rectList[i].size.width / cdx);
> + clipRect.size.height = ceilf(rectList[i].size.height / cdy);
> clipImageRef = CGImageCreateWithImageInRect(
> imageRef,
> clipRect
> @@ -410,6 +458,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
> screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
>
> + dataRawPtr = is_graphic_console() ? ds_get_data(ds) : 0;
> dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
>
> // update windows
> @@ -417,10 +466,9 @@ static int cocoa_keycode_to_qemu(int keycode)
> [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
> [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
> } else {
> - if (qemu_name)
> - [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
> [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
> }
> + [self updateCaption];
> screen.width = w;
> screen.height = h;
> [normalWindow center];
> @@ -434,7 +482,7 @@ static int cocoa_keycode_to_qemu(int keycode)
>
> if (isFullscreen) { // switch from fullscreen to desktop
> isFullscreen = FALSE;
> - [self ungrabMouse];
> + if (isMouseGrabed) [self ungrabMouse];
> [self setContentDimensions];
> // test if host supports "exitFullScreenModeWithOptions" at compile time
> #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
> @@ -444,29 +492,33 @@ static int cocoa_keycode_to_qemu(int keycode)
> #endif
> [fullScreenWindow close];
> [normalWindow setContentView: self];
> - [normalWindow makeKeyAndOrderFront: self];
> [NSMenu setMenuBarVisible:YES];
> #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
> }
> #endif
> + [normalWindow makeKeyAndOrderFront:self];
> } else { // switch from desktop to fullscreen
> isFullscreen = TRUE;
> - [self grabMouse];
> + if (cursor_allow_grab) [self grabMouse];
> [self setContentDimensions];
> + [normalWindow orderOut:self];
> // test if host supports "enterFullScreenMode:withOptions" at compile time
> #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
> if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
> - [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
> - [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
> - [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
> - nil]];
> + [self enterFullScreenMode:[NSScreen mainScreen]
> + withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
> + [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
> + [NSDictionary dictionaryWithObjectsAndKeys:
> + [NSNumber numberWithBool:NO], kCGDisplayModeIsStretched,
> + nil], NSFullScreenModeSetting,
> + nil]];
> } else {
> #endif
> [NSMenu setMenuBarVisible:NO];
> fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
> - styleMask:NSBorderlessWindowMask
> - backing:NSBackingStoreBuffered
> - defer:NO];
> + styleMask:NSBorderlessWindowMask
> + backing:NSBackingStoreBuffered
> + defer:NO];
> [fullScreenWindow setHasShadow:NO];
> [fullScreenWindow setContentView:self];
> [fullScreenWindow makeKeyAndOrderFront:self];
> @@ -476,7 +528,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> }
> }
>
> -- (void) handleEvent:(NSEvent *)event
> +- (void) qemuHandleEvent:(NSEvent *)event
> {
> COCOA_DEBUG("QemuCocoaView: handleEvent\n");
>
> @@ -505,8 +557,13 @@ static int cocoa_keycode_to_qemu(int keycode)
> }
>
> // release Mouse grab when pressing ctrl+alt
> - if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
> - [self ungrabMouse];
> + if (!isFullscreen) {
> + if ((ctrl_grab && [event keyCode] == 0x3e)
> + || ((([event modifierFlags] & NSControlKeyMask) &&
> + ([event modifierFlags] & NSAlternateKeyMask))
> + && (!alt_grab || ([event modifierFlags] & NSShiftKeyMask)))) {
> + [self ungrabMouse];
> + }
> }
> break;
> case NSKeyDown:
> @@ -581,15 +638,17 @@ static int cocoa_keycode_to_qemu(int keycode)
> }
> break;
> case NSMouseMoved:
> + mouseX = p.x;
> + mouseY = p.y;
> if (isAbsoluteEnabled) {
> if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
> if (isTabletEnabled) { // if we leave the window, deactivate the tablet
> - [NSCursor unhide];
> + if (cursor_hide) [NSCursor unhide];
> isTabletEnabled = FALSE;
> }
> } else {
> if (!isTabletEnabled) { // if we enter the window, activate the tablet
> - [NSCursor hide];
> + if (cursor_hide) [NSCursor hide];
> isTabletEnabled = TRUE;
> }
> }
> @@ -602,6 +661,9 @@ static int cocoa_keycode_to_qemu(int keycode)
> } else {
> buttons |= MOUSE_EVENT_LBUTTON;
> }
> + if ([event modifierFlags] & NSAlternateKeyMask) {
> + buttons |= MOUSE_EVENT_MBUTTON << 1;
> + }
> COCOA_MOUSE_EVENT
> break;
> case NSRightMouseDown:
> @@ -613,11 +675,16 @@ static int cocoa_keycode_to_qemu(int keycode)
> COCOA_MOUSE_EVENT
> break;
> case NSLeftMouseDragged:
> + mouseX = p.x;
> + mouseY = p.y;
> if ([event modifierFlags] & NSCommandKeyMask) {
> buttons |= MOUSE_EVENT_RBUTTON;
> } else {
> buttons |= MOUSE_EVENT_LBUTTON;
> }
> + if ([event modifierFlags] & NSAlternateKeyMask) {
> + buttons |= MOUSE_EVENT_MBUTTON << 1;
> + }
> COCOA_MOUSE_EVENT
> break;
> case NSRightMouseDragged:
> @@ -633,7 +700,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> COCOA_MOUSE_EVENT
> } else if (!isMouseGrabed) {
> if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
> - [self grabMouse];
> + if (cursor_allow_grab) [self grabMouse];
> } else {
> [NSApp sendEvent:event];
> }
> @@ -654,6 +721,25 @@ static int cocoa_keycode_to_qemu(int keycode)
> [NSApp sendEvent:event];
> }
> break;
> + case NSAppKitDefined:
> + switch ([event subtype]) {
> + case NSApplicationActivatedEventType:
> + if (dcl) {
> + dcl->gui_timer_interval = 0;
> + dcl->idle = 0;
> + }
> + break;
> + case NSApplicationDeactivatedEventType:
> + if (dcl) {
> + dcl->gui_timer_interval = 500;
> + dcl->idle = 1;
> + }
> + break;
> + default:
> + break;
> + }
> + [NSApp sendEvent:event];
> + break;
> default:
> [NSApp sendEvent:event];
> }
> @@ -662,34 +748,48 @@ static int cocoa_keycode_to_qemu(int keycode)
> - (void) grabMouse
> {
> COCOA_DEBUG("QemuCocoaView: grabMouse\n");
> -
> - if (!isFullscreen) {
> - if (qemu_name)
> - [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
> - else
> - [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
> - }
> - [NSCursor hide];
> + if (cursor_hide) [NSCursor hide];
> CGAssociateMouseAndMouseCursorPosition(FALSE);
> isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
> + [self updateCaption];
> }
>
> - (void) ungrabMouse
> {
> COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
>
> - if (!isFullscreen) {
> - if (qemu_name)
> - [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
> - else
> - [normalWindow setTitle:@"QEMU"];
> - }
> - [NSCursor unhide];
> + if (cursor_hide) [NSCursor unhide];
> CGAssociateMouseAndMouseCursorPosition(TRUE);
> isMouseGrabed = FALSE;
> + [self updateCaption];
> +}
> +
> +- (void) updateCaption
> +{
> + NSMutableString *caption = [NSMutableString stringWithCapacity:10];
> + [caption appendFormat:@"QEMU"];
> + if (isShuttingDownGuest) {
> + [caption appendString:@" [Shutting down]"];
> + }
> + if (qemu_name) {
> + [caption appendFormat:@" (%s)", qemu_name];
> + }
> + if (!vm_running) {
> + [caption appendString:@" [Stopped]"];
> + } else if (isMouseGrabed) {
> + if (ctrl_grab) {
> + [caption appendString:@" - Press Right-Ctrl to release mouse"];
> + } else if (alt_grab) {
> + [caption appendString:@" - Press Ctrl-Alt-Shift to release mouse"];
> + } else {
> + [caption appendString:@" - Press Ctrl-Alt to release mouse"];
> + }
> + }
> + [normalWindow setTitle:caption];
> }
>
> - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
> +- (void) setShuttingDownGuest { isShuttingDownGuest = YES; [self updateCaption]; }
> - (BOOL) isMouseGrabed {return isMouseGrabed;}
> - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
> - (float) cdx {return cdx;}
> @@ -704,14 +804,16 @@ static int cocoa_keycode_to_qemu(int keycode)
> QemuCocoaAppController
> ------------------------------------------------------
> */
> +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
> +@interface QemuCocoaAppController : NSObject <NSWindowDelegate>
> +#else
> @interface QemuCocoaAppController : NSObject
> +#endif
> {
> }
> - (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
> - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
> - (void)toggleFullScreen:(id)sender;
> -- (void)showQEMUDoc:(id)sender;
> -- (void)showQEMUTec:(id)sender;
> @end
>
> @implementation QemuCocoaAppController
> @@ -743,7 +845,8 @@ static int cocoa_keycode_to_qemu(int keycode)
> [normalWindow useOptimizedDrawing:YES];
> [normalWindow makeKeyAndOrderFront:self];
> [normalWindow center];
> -
> + [normalWindow setDelegate:self];
> + [cocoaView updateCaption];
> }
> return self;
> }
> @@ -781,7 +884,6 @@ static int cocoa_keycode_to_qemu(int keycode)
> COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
>
> qemu_system_shutdown_request();
> - exit(0);
> }
>
> - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
> @@ -819,6 +921,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> [self startEmulationWithArgc:3 argv:(char**)argv];
> }
> }
> +
> - (void)toggleFullScreen:(id)sender
> {
> COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
> @@ -826,41 +929,57 @@ static int cocoa_keycode_to_qemu(int keycode)
> [cocoaView toggleFullScreen:sender];
> }
>
> -- (void)showQEMUDoc:(id)sender
> +- (BOOL)windowShouldClose:(id)sender
> {
> - COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
> -
> - [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
> - [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
> + if (!no_quit) {
> + if (qemu_run_display_close_handler()) {
> + return YES;
> + }
> + [cocoaView setShuttingDownGuest];
> + }
> + return NO;
> }
>
> -- (void)showQEMUTec:(id)sender
> +- (void)confirmQuit:(id)sender
> {
> - COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
> + NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to quit QEMU?"
> + defaultButton:@"No"
> + alternateButton:@"Yes"
> + otherButton:@"Shutdown"
> + informativeTextWithFormat:@"If you quit QEMU without shutting down the emulated machine properly you risk losing data and possibly corrupting the virtual machine contents."];
> + [alert setAlertStyle:NSCriticalAlertStyle];
> + switch ([alert runModal]) {
> + case NSAlertDefaultReturn:
> + /* do nothing */
> + break;
> + case NSAlertAlternateReturn:
> + [NSApp terminate:sender];
> + break;
> + case NSAlertOtherReturn:
> + if (qemu_run_display_close_handler()) {
> + qemu_system_shutdown_request();
> + } else {
> + [cocoaView setShuttingDownGuest];
> + }
> + break;
> + default:
> + break;
> + }
> +}
>
> - [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
> - [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
> +- (void)aboutQEMU:(id)sender
> +{
> + [NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionaryWithObjectsAndKeys:
> + @ QEMU_VERSION QEMU_PKGVERSION, @"ApplicationVersion",
> + nil]];
> }
> @end
>
>
> -
> -// Dock Connection
> -typedef struct CPSProcessSerNum
> +int main (int argc, const char * argv[])
> {
> - UInt32 lo;
> - UInt32 hi;
> -} CPSProcessSerNum;
> -
> -extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
> -extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
> -extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
> -
> -int main (int argc, const char * argv[]) {
> -
> gArgc = argc;
> gArgv = (char **)argv;
> - CPSProcessSerNum PSN;
> int i;
>
> /* In case we don't need to display a window, let's not do that */
> @@ -875,10 +994,11 @@ int main (int argc, const char * argv[]) {
> NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
> [NSApplication sharedApplication];
>
> - if (!CPSGetCurrentProcess(&PSN))
> - if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
> - if (!CPSSetFrontProcess(&PSN))
> - [NSApplication sharedApplication];
> + ProcessSerialNumber PSN;
> + if (!GetCurrentProcess(&PSN) &&
> + !TransformProcessType(&PSN, kProcessTransformToForegroundApplication) &&
> + !SetFrontProcess(&PSN))
> + [NSApplication sharedApplication];
>
> // Add menus
> NSMenu *menu;
> @@ -888,14 +1008,14 @@ int main (int argc, const char * argv[]) {
>
> // Application menu
> menu = [[NSMenu alloc] initWithTitle:@""];
> - [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
> + [menu addItemWithTitle:@"About QEMU" action:@selector(aboutQEMU:) keyEquivalent:@""]; // About QEMU
> [menu addItem:[NSMenuItem separatorItem]]; //Separator
> [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
> menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
> [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
> [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
> [menu addItem:[NSMenuItem separatorItem]]; //Separator
> - [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
> + [menu addItemWithTitle:@"Quit QEMU" action:@selector(confirmQuit:) keyEquivalent:@"q"];
> menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
> [menuItem setSubmenu:menu];
> [[NSApp mainMenu] addItem:menuItem];
> @@ -916,14 +1036,6 @@ int main (int argc, const char * argv[]) {
> [[NSApp mainMenu] addItem:menuItem];
> [NSApp setWindowsMenu:menu];
>
> - // Help menu
> - menu = [[NSMenu alloc] initWithTitle:@"Help"];
> - [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
> - [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
> - menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
> - [menuItem setSubmenu:menu];
> - [[NSApp mainMenu] addItem:menuItem];
> -
> // Create an Application controller
> QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
> [NSApp setDelegate:appController];
> @@ -968,6 +1080,11 @@ static void cocoa_refresh(DisplayState *ds)
> {
> COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
>
> + if (last_vm_running != vm_running) {
> + last_vm_running = vm_running;
> + [cocoaView updateCaption];
> + }
> +
> if (kbd_mouse_is_absolute()) {
> if (![cocoaView isAbsoluteEnabled]) {
> if ([cocoaView isMouseGrabed]) {
> @@ -984,7 +1101,7 @@ static void cocoa_refresh(DisplayState *ds)
> event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
> inMode: NSDefaultRunLoopMode dequeue:YES];
> if (event != nil) {
> - [cocoaView handleEvent:event];
> + [cocoaView qemuHandleEvent:event];
> }
> } while(event != nil);
> vga_hw_update();
> @@ -1012,3 +1129,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
> // register cleanup function
> atexit(cocoa_cleanup);
> }
> +
> +#ifdef CONFIG_GLHW
> +#include "hw/gl/opengl_host_cocoa.m"
> +#endif
> --
> 1.6.5
>
>
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 13/48] multitouch and window close handler
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (8 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 12/48] cocoa frontend changes Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 14/48] multikeyboard support merge Riku Voipio
` (34 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
console.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/console.c b/console.c
index 8bcd00b..8b24318 100644
--- a/console.c
+++ b/console.c
@@ -32,6 +32,24 @@
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
+int multitouch_enabled = 0;
+static QEMUDisplayCloseCallback *qemu_display_close_callback = NULL;
+static void *qemu_display_close_callback_opaque = NULL;
+
+void qemu_set_display_close_handler(QEMUDisplayCloseCallback *cb, void *opaque)
+{
+ qemu_display_close_callback = cb;
+ qemu_display_close_callback_opaque = opaque;
+}
+
+int qemu_run_display_close_handler(void)
+{
+ if (qemu_display_close_callback != NULL) {
+ return qemu_display_close_callback(qemu_display_close_callback_opaque);
+ }
+ return 1;
+}
+
typedef struct TextAttributes {
uint8_t fgcol:4;
uint8_t bgcol:4;
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 14/48] multikeyboard support merge
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (9 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 13/48] multitouch and window close handler Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 15/48] fix function signature of qemu_chr_open_pty on !linux Riku Voipio
` (33 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
On some systems (such as n900), multiple physical devices can create
keyboard events (gpio, lis302dl, twl4030, ..). Add hooks to make it
possible to recieve keyboard input from multiple devices.
merge our version with upstream multikb support
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
console.h | 8 ++++----
input.c | 21 +++++++++++++++------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/console.h b/console.h
index b1362ff..a894edf 100644
--- a/console.h
+++ b/console.h
@@ -39,12 +39,13 @@ typedef struct QEMUPutMouseEntry {
/* used internally by qemu for handling mice */
QTAILQ_ENTRY(QEMUPutMouseEntry) node;
} QEMUPutMouseEntry;
+
typedef struct QEMUPutKBDEntry {
- QEMUPutKBDEvent *qemu_put_kbd_event;
- void *qemu_put_kbd_event_opaque;
+ QEMUPutKBDEvent *put_kbd_event;
+ void *opaque;
/* used internally by qemu for handling keyboards */
- struct QEMUPutKBDEntry *next;
+ QTAILQ_ENTRY(QEMUPutKBDEntry) next;
} QEMUPutKBDEntry;
typedef struct QEMUPutLEDEntry {
@@ -54,7 +55,6 @@ typedef struct QEMUPutLEDEntry {
} QEMUPutLEDEntry;
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
-void qemu_remove_kbd_event_handler(QEMUPutKBDEvent *entry);
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
void *opaque, int absolute,
const char *name);
diff --git a/input.c b/input.c
index 8f0941e..2e860c6 100644
--- a/input.c
+++ b/input.c
@@ -28,8 +28,8 @@
#include "console.h"
#include "qjson.h"
-static QEMUPutKBDEvent *qemu_put_kbd_event;
-static void *qemu_put_kbd_event_opaque;
+static QTAILQ_HEAD(, QEMUPutKBDEntry) kbd_handlers =
+ QTAILQ_HEAD_INITIALIZER(kbd_handlers);
static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers);
static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
QTAILQ_HEAD_INITIALIZER(mouse_handlers);
@@ -38,8 +38,16 @@ static NotifierList mouse_mode_notifiers =
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
{
- qemu_put_kbd_event_opaque = opaque;
- qemu_put_kbd_event = func;
+ QEMUPutKBDEntry *s;
+
+ if (func != NULL) {
+ s = qemu_mallocz(sizeof(QEMUPutKBDEntry));
+
+ s->put_kbd_event = func;
+ s->opaque = opaque;
+
+ QTAILQ_INSERT_TAIL(&kbd_handlers, s, next);
+ }
}
static void check_mode_change(void)
@@ -123,8 +131,9 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
void kbd_put_keycode(int keycode)
{
- if (qemu_put_kbd_event) {
- qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
+ QEMUPutKBDEntry *cursor;
+ QTAILQ_FOREACH(cursor, &kbd_handlers, next) {
+ cursor->put_kbd_event(cursor->opaque, keycode);
}
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 15/48] fix function signature of qemu_chr_open_pty on !linux
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (10 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 14/48] multikeyboard support merge Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-04-08 19:08 ` Aurelien Jarno
2010-03-26 16:06 ` [Qemu-devel] [PATCH 16/48] sdl: multitouch and window close suppport Riku Voipio
` (32 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 617 bytes --]
From: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
qemu-char.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/qemu-char.c b/qemu-char.c
index a3d6e64..1e5b515 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1218,7 +1218,7 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
return chr;
}
#else /* ! __linux__ && ! __sun__ */
-static CharDriverState *qemu_chr_open_pty(void)
+static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
{
return NULL;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 15/48] fix function signature of qemu_chr_open_pty on !linux
2010-03-26 16:06 ` [Qemu-devel] [PATCH 15/48] fix function signature of qemu_chr_open_pty on !linux Riku Voipio
@ 2010-04-08 19:08 ` Aurelien Jarno
0 siblings, 0 replies; 55+ messages in thread
From: Aurelien Jarno @ 2010-04-08 19:08 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, Juha Riihimäki, qemu-devel
On Fri, Mar 26, 2010 at 04:06:35PM +0000, Riku Voipio wrote:
> From: Riku Voipio <riku.voipio@nokia.com>
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
> Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
Thanks, applied.
> ---
> qemu-char.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/qemu-char.c b/qemu-char.c
> index a3d6e64..1e5b515 100644
> --- a/qemu-char.c
> +++ b/qemu-char.c
> @@ -1218,7 +1218,7 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
> return chr;
> }
> #else /* ! __linux__ && ! __sun__ */
> -static CharDriverState *qemu_chr_open_pty(void)
> +static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
> {
> return NULL;
> }
> --
> 1.6.5
>
>
>
>
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 16/48] sdl: multitouch and window close suppport
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (11 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 15/48] fix function signature of qemu_chr_open_pty on !linux Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 17/48] add multi-sd support Riku Voipio
` (31 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
- show shutting down status in window caption
- add display close handler support
- add support for disabling input grabbing
- add ability to disable window grab:
currently if the qemu window is inactive and you click inside the
qemu window the input will be grabbed. with touchscreen devices
this might not be very feasible as there is no visible guest
cursor so this patch adds a global variable that can be used to
control the grabbing behavior. default behavior is not modified
but for n8x0, n900 and n00 devices the grabbing is disabled.
note that with sdl rendering you can still toggle grabbing by
pressing ctrl+alt when the qemu window is active.
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
sdl.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 54 insertions(+), 12 deletions(-)
diff --git a/sdl.c b/sdl.c
index 16a48e9..40e2ad1 100644
--- a/sdl.c
+++ b/sdl.c
@@ -57,6 +57,8 @@ static SDL_Cursor *guest_sprite = NULL;
static uint8_t allocator;
static SDL_PixelFormat host_format;
static int scaling_active = 0;
+static int mouseX = 0, mouseY = 0;
+static int shutting_down_guest = 0;
static Notifier mouse_mode_notifier;
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
@@ -78,6 +80,30 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
}
}
}
+ if (multitouch_enabled && !cursor_hide && !gui_grab &&
+ modifiers_state[56] && real_screen && real_screen->pixels) {
+ unsigned char *p = (unsigned char *)real_screen->pixels;
+ int altX = real_screen->w - mouseX;
+ int altY = real_screen->h - mouseY;
+ int x, y;
+ int bytesperpixel = real_screen->format->BytesPerPixel;
+ p += altY * real_screen->pitch;
+ for (y = 0; y < 8; y++) {
+ if (y + altY > 0 && y + altY < real_screen->h) {
+ unsigned char *q = p + altX * bytesperpixel;
+ for (x = 0; x < 8; x++) {
+ if (x + altX > 0 && x + altX < real_screen->w) {
+ int i;
+ for (i = 0; i < bytesperpixel; i++) {
+ q[i] ^= 0xff;
+ }
+ }
+ q += bytesperpixel;
+ }
+ }
+ p += real_screen->pitch;
+ }
+ }
SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
}
@@ -413,15 +439,19 @@ static void sdl_update_caption(void)
char icon_title[1024];
const char *status = "";
- if (!vm_running)
- status = " [Stopped]";
- else if (gui_grab) {
- if (alt_grab)
- status = " - Press Ctrl-Alt-Shift to exit mouse grab";
- else if (ctrl_grab)
- status = " - Press Right-Ctrl to exit mouse grab";
- else
- status = " - Press Ctrl-Alt to exit mouse grab";
+ if (shutting_down_guest) {
+ status = " [Shutting down]";
+ } else {
+ if (!vm_running)
+ status = " [Stopped]";
+ else if (gui_grab) {
+ if (alt_grab)
+ status = " - Press Ctrl-Alt-Shift to exit mouse grab";
+ else if (ctrl_grab)
+ status = " - Press Right-Ctrl to exit mouse grab";
+ else
+ status = " - Press Ctrl-Alt to exit mouse grab";
+ }
}
if (qemu_name) {
@@ -513,6 +543,9 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
buttons |= MOUSE_EVENT_RBUTTON;
if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
buttons |= MOUSE_EVENT_MBUTTON;
+ if (modifiers_state[56] &&
+ (buttons & (MOUSE_EVENT_LBUTTON | MOUSE_EVENT_RBUTTON)))
+ buttons |= MOUSE_EVENT_MBUTTON << 1;
if (kbd_mouse_is_absolute()) {
dx = x * 0x7FFF / (width - 1);
@@ -526,6 +559,9 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
dy = y;
}
+ mouseX = x;
+ mouseY = y;
+
kbd_mouse_event(dx, dy, dz, buttons);
}
@@ -678,8 +714,14 @@ static void sdl_refresh(DisplayState *ds)
sdl_process_key(&ev->key);
break;
case SDL_QUIT:
- if (!no_quit)
- qemu_system_shutdown_request();
+ if (!no_quit) {
+ if (qemu_run_display_close_handler()) {
+ qemu_system_shutdown_request();
+ } else {
+ shutting_down_guest = 1;
+ sdl_update_caption();
+ }
+ }
break;
case SDL_MOUSEMOTION:
if (gui_grab || kbd_mouse_is_absolute() ||
@@ -696,7 +738,7 @@ static void sdl_refresh(DisplayState *ds)
if (ev->type == SDL_MOUSEBUTTONDOWN &&
(bev->button == SDL_BUTTON_LEFT)) {
/* start grabbing all events */
- sdl_grab_start();
+ if (cursor_allow_grab) sdl_grab_start();
}
} else {
int dz;
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 17/48] add multi-sd support
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (12 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 16/48] sdl: multitouch and window close suppport Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 18/48] make cursor grab optional Riku Voipio
` (30 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio
From: Riku Voipio <riku.voipio@nokia.com>
N900 and other devices can have more than one sd/mmc card, and thus
the -sd command line option needs to be read multiple times.
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
---
vl.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/vl.c b/vl.c
index d69250c..b4dfb2e 100644
--- a/vl.c
+++ b/vl.c
@@ -752,7 +752,7 @@ static int bt_parse(const char *opt)
#define FD_ALIAS "index=%d,if=floppy"
#define PFLASH_ALIAS "if=pflash"
#define MTD_ALIAS "if=mtd"
-#define SD_ALIAS "index=0,if=sd"
+#define SD_ALIAS "index=%d,if=sd"
QemuOpts *drive_add(const char *file, const char *fmt, ...)
{
@@ -3738,6 +3738,7 @@ int main(int argc, char **argv, char **envp)
CPUState *env;
int show_vnc_port = 0;
int defconfig = 1;
+ int sd_device_index = 0;
error_set_progname(argv[0]);
@@ -3920,7 +3921,7 @@ int main(int argc, char **argv, char **envp)
drive_add(optarg, MTD_ALIAS);
break;
case QEMU_OPTION_sd:
- drive_add(optarg, SD_ALIAS);
+ drive_add(optarg, SD_ALIAS, sd_device_index++);
break;
case QEMU_OPTION_pflash:
drive_add(optarg, PFLASH_ALIAS);
@@ -4762,7 +4763,7 @@ int main(int argc, char **argv, char **envp)
if (default_sdcard) {
/* we always create one sd slot, even if no card is in it */
- drive_add(NULL, SD_ALIAS);
+ drive_add(NULL, SD_ALIAS, 0);
}
/* open the virtual block devices */
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 18/48] make cursor grab optional
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (13 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 17/48] add multi-sd support Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-04-08 19:10 ` Aurelien Jarno
2010-04-22 2:01 ` andrzej zaborowski
2010-03-26 16:06 ` [Qemu-devel] [PATCH 19/48] usb-ohci: add omap init support Riku Voipio
` (29 subsequent siblings)
44 siblings, 2 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio
From: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
---
sysemu.h | 1 +
vl.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/sysemu.h b/sysemu.h
index 525efd1..5b4ddd8 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -128,6 +128,7 @@ extern int usb_enabled;
extern int smp_cpus;
extern int max_cpus;
extern int cursor_hide;
+extern int cursor_allow_grab;
extern int graphic_rotate;
extern int no_quit;
extern int semihosting_enabled;
diff --git a/vl.c b/vl.c
index b4dfb2e..bc7635c 100644
--- a/vl.c
+++ b/vl.c
@@ -224,6 +224,7 @@ int fd_bootchk = 1;
int no_reboot = 0;
int no_shutdown = 0;
int cursor_hide = 1;
+int cursor_allow_grab = 1;
int graphic_rotate = 0;
uint8_t irq0override = 1;
#ifndef _WIN32
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 18/48] make cursor grab optional
2010-03-26 16:06 ` [Qemu-devel] [PATCH 18/48] make cursor grab optional Riku Voipio
@ 2010-04-08 19:10 ` Aurelien Jarno
2010-04-22 2:01 ` andrzej zaborowski
1 sibling, 0 replies; 55+ messages in thread
From: Aurelien Jarno @ 2010-04-08 19:10 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, qemu-devel
On Fri, Mar 26, 2010 at 04:06:38PM +0000, Riku Voipio wrote:
> From: Riku Voipio <riku.voipio@nokia.com>
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
>
> ---
> sysemu.h | 1 +
> vl.c | 1 +
> 2 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/sysemu.h b/sysemu.h
> index 525efd1..5b4ddd8 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -128,6 +128,7 @@ extern int usb_enabled;
> extern int smp_cpus;
> extern int max_cpus;
> extern int cursor_hide;
> +extern int cursor_allow_grab;
> extern int graphic_rotate;
> extern int no_quit;
> extern int semihosting_enabled;
> diff --git a/vl.c b/vl.c
> index b4dfb2e..bc7635c 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -224,6 +224,7 @@ int fd_bootchk = 1;
> int no_reboot = 0;
> int no_shutdown = 0;
> int cursor_hide = 1;
> +int cursor_allow_grab = 1;
> int graphic_rotate = 0;
> uint8_t irq0override = 1;
> #ifndef _WIN32
It looks like this patch is not complete. Adding a new variable won't
add the feature automatically ;-)
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 18/48] make cursor grab optional
2010-03-26 16:06 ` [Qemu-devel] [PATCH 18/48] make cursor grab optional Riku Voipio
2010-04-08 19:10 ` Aurelien Jarno
@ 2010-04-22 2:01 ` andrzej zaborowski
1 sibling, 0 replies; 55+ messages in thread
From: andrzej zaborowski @ 2010-04-22 2:01 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, qemu-devel
On 26 March 2010 18:06, Riku Voipio <riku.voipio@iki.fi> wrote:
> From: Riku Voipio <riku.voipio@nokia.com>
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
>
> ---
> sysemu.h | 1 +
> vl.c | 1 +
> 2 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/sysemu.h b/sysemu.h
> index 525efd1..5b4ddd8 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -128,6 +128,7 @@ extern int usb_enabled;
> extern int smp_cpus;
> extern int max_cpus;
> extern int cursor_hide;
> +extern int cursor_allow_grab;
> extern int graphic_rotate;
> extern int no_quit;
> extern int semihosting_enabled;
> diff --git a/vl.c b/vl.c
> index b4dfb2e..bc7635c 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -224,6 +224,7 @@ int fd_bootchk = 1;
> int no_reboot = 0;
> int no_shutdown = 0;
> int cursor_hide = 1;
> +int cursor_allow_grab = 1;
> int graphic_rotate = 0;
> uint8_t irq0override = 1;
> #ifndef _WIN32
> --
> 1.6.5
>
>
>
>
The n900 uses a touchscreen, right? For absolute pointer devices
there's no need to do the grab so unless something else is broken, you
shouldn't need to disallow it from command line.
Cheers
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 19/48] usb-ohci: add omap init support
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (14 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 18/48] make cursor grab optional Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 20/48] add reset support for musb Riku Voipio
` (28 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio
From: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
---
hw/usb-ohci.c | 12 ++++++++++++
hw/usb-ohci.h | 2 ++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 93f7d79..c9865f4 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -61,6 +61,7 @@ typedef struct OHCIPort {
enum ohci_type {
OHCI_TYPE_PCI,
OHCI_TYPE_PXA,
+ OHCI_TYPE_OMAP,
OHCI_TYPE_SM501,
};
@@ -1782,6 +1783,17 @@ void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
cpu_register_physical_memory(base, 0x1000, ohci->mem);
}
+void usb_ohci_init_omap(target_phys_addr_t base, uint32_t region_size,
+ int num_ports, qemu_irq irq, int be)
+{
+ OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
+
+ usb_ohci_init(ohci, NULL /* FIXME */, num_ports, -1, irq,
+ OHCI_TYPE_OMAP, "OHCI USB" ,0, be);
+
+ cpu_register_physical_memory(base, 0x1000, ohci->mem);
+}
+
void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
int num_ports, int devfn, qemu_irq irq, int be)
{
diff --git a/hw/usb-ohci.h b/hw/usb-ohci.h
index aadc365..741b6a1 100644
--- a/hw/usb-ohci.h
+++ b/hw/usb-ohci.h
@@ -6,5 +6,7 @@
void usb_ohci_init_pci(struct PCIBus *bus, int devfn, int be);
void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
qemu_irq irq, int be);
+void usb_ohci_init_omap(target_phys_addr_t base, uint32_t region_size,
+ int num_ports, qemu_irq irq, int be);
#endif
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 20/48] add reset support for musb
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (15 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 19/48] usb-ohci: add omap init support Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 21/48] NAND emulation overhaul Riku Voipio
` (27 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/usb-musb.c | 29 +++++++++++++++++++++++------
hw/usb.h | 1 +
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 7f15842..a83cd85 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -8,7 +8,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -307,7 +307,9 @@ struct MUSBState {
uint16_t rx_intr;
uint16_t rx_mask;
+#ifdef SETUPLEN_HACK
int setup_len;
+#endif
int session;
uint8_t buf[0x8000];
@@ -315,15 +317,16 @@ struct MUSBState {
/* Duplicating the world since 2008!... probably we should have 32
* logical, single endpoints instead. */
MUSBEndPoint ep[16];
-} *musb_init(qemu_irq *irqs)
+};
+
+void musb_reset(MUSBState *s)
{
- MUSBState *s = qemu_mallocz(sizeof(*s));
int i;
- s->irqs = irqs;
-
s->faddr = 0x00;
+ s->devctl = 0;
s->power = MGC_M_POWER_HSENAB;
+
s->tx_intr = 0x0000;
s->rx_intr = 0x0000;
s->tx_mask = 0xffff;
@@ -332,6 +335,12 @@ struct MUSBState {
s->mask = 0x06;
s->idx = 0;
+#ifdef SETUPLEN_HACK
+ s->setup_len = 0;
+#endif
+ s->session = 0;
+ memset(s->buf, 0, sizeof(s->buf));
+
/* TODO: _DW */
s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
for (i = 0; i < 16; i ++) {
@@ -341,6 +350,14 @@ struct MUSBState {
s->ep[i].musb = s;
s->ep[i].epnum = i;
}
+}
+
+struct MUSBState *musb_init(qemu_irq *irqs)
+{
+ MUSBState *s = qemu_mallocz(sizeof(*s));
+
+ s->irqs = irqs;
+ musb_reset(s);
usb_bus_new(&s->bus, NULL /* FIXME */);
usb_register_port(&s->bus, &s->port, s, 0, musb_attach);
@@ -1481,7 +1498,7 @@ static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
- break;
+ break;
default:
TRACE("unknown register 0x%02x", (int) addr);
break;
diff --git a/hw/usb.h b/hw/usb.h
index 106d174..71df75b 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -284,6 +284,7 @@ enum musb_irq_source_e {
typedef struct MUSBState MUSBState;
MUSBState *musb_init(qemu_irq *irqs);
+void musb_reset(MUSBState *s);
uint32_t musb_core_intr_get(MUSBState *s);
void musb_core_intr_clear(MUSBState *s, uint32_t mask);
void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 21/48] NAND emulation overhaul
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (16 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 20/48] add reset support for musb Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 22/48] License update Riku Voipio
` (26 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
- Enhanced existing NAND emulation to support other than 8-bit devices.
- Enhanced existing NAND emulation to support over 1Gb devices.
- Enhanced existing NAND emulation to support cache status bits and read cache commands.
- Fixed existing NAND emulation to correctly handle multiple IO reads after READ STATUS command.
- nand emulation fixes
- more NAND fixing & tidying
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/axis_dev88.c | 2 +-
hw/flash.h | 7 +-
hw/nand.c | 207 +++++++++++++++++++++++++++++++++++++------------------
hw/spitz.c | 4 +-
hw/tc6393xb.c | 3 +-
5 files changed, 148 insertions(+), 75 deletions(-)
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 5516e42..cb555c9 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -292,7 +292,7 @@ void axisdev88_init (ram_addr_t ram_size,
/* Attach a NAND flash to CS1. */
- nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
+ nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39, drive_get(IF_MTD, 0, 0));
nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state);
cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
diff --git a/hw/flash.h b/hw/flash.h
index 69aef8c..170a788 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -18,13 +18,14 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
/* nand.c */
typedef struct NANDFlashState NANDFlashState;
-NANDFlashState *nand_init(int manf_id, int chip_id);
+NANDFlashState *nand_init(int manf_id, int chip_id, DriveInfo *dinfo);
void nand_done(NANDFlashState *s);
void nand_setpins(NANDFlashState *s,
int cle, int ale, int ce, int wp, int gnd);
void nand_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint8_t value);
-uint8_t nand_getio(NANDFlashState *s);
+void nand_setio(NANDFlashState *s, uint32_t value);
+uint32_t nand_getio(NANDFlashState *s);
+uint32_t nand_getbuswidth(NANDFlashState *s);
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
diff --git a/hw/nand.c b/hw/nand.c
index 40d5a6a..c98fc66 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -6,6 +6,10 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
* This code is licensed under the GNU GPL v2.
*/
@@ -14,13 +18,14 @@
# include "hw.h"
# include "flash.h"
# include "block.h"
-/* FIXME: Pass block device as an argument. */
-# include "sysemu.h"
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
# define NAND_CMD_READ2 0x50
# define NAND_CMD_LPREAD2 0x30
+# define NAND_CMD_READCACHESTART 0x31
+# define NAND_CMD_READCACHEEXIT 0x34
+# define NAND_CMD_READCACHELAST 0x3f
# define NAND_CMD_NOSERIALREAD2 0x35
# define NAND_CMD_RANDOMREAD1 0x05
# define NAND_CMD_RANDOMREAD2 0xe0
@@ -39,7 +44,7 @@
# define NAND_IOSTATUS_PLANE1 (1 << 2)
# define NAND_IOSTATUS_PLANE2 (1 << 3)
# define NAND_IOSTATUS_PLANE3 (1 << 4)
-# define NAND_IOSTATUS_BUSY (1 << 6)
+# define NAND_IOSTATUS_READY (3 << 5)
# define NAND_IOSTATUS_UNPROTCT (1 << 7)
# define MAX_PAGE 0x800
@@ -47,6 +52,7 @@
struct NANDFlashState {
uint8_t manf_id, chip_id;
+ uint8_t buswidth; /* in BYTES */
int size, pages;
int page_shift, oob_shift, erase_shift, addr_shift;
uint8_t *storage;
@@ -59,14 +65,15 @@ struct NANDFlashState {
uint8_t *ioaddr;
int iolen;
- uint32_t cmd, addr;
+ uint32_t cmd;
+ uint64_t addr;
int addrlen;
int status;
int offset;
void (*blk_write)(NANDFlashState *s);
void (*blk_erase)(NANDFlashState *s);
- void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+ void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
};
# define NAND_NO_AUTOINCR 0x00000001
@@ -208,6 +215,14 @@ static void nand_reset(NANDFlashState *s)
s->iolen = 0;
s->offset = 0;
s->status &= NAND_IOSTATUS_UNPROTCT;
+ s->status |= NAND_IOSTATUS_READY;
+}
+
+static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
+{
+ s->ioaddr[s->iolen++] = value;
+ for (value = s->buswidth; --value;)
+ s->ioaddr[s->iolen++] = 0;
}
static void nand_command(NANDFlashState *s)
@@ -215,19 +230,20 @@ static void nand_command(NANDFlashState *s)
unsigned int offset;
switch (s->cmd) {
case NAND_CMD_READ0:
+ case NAND_CMD_READCACHEEXIT:
s->iolen = 0;
break;
case NAND_CMD_READID:
- s->io[0] = s->manf_id;
- s->io[1] = s->chip_id;
- s->io[2] = 'Q'; /* Don't-care byte (often 0xa5) */
+ s->ioaddr = s->io;
+ s->iolen = 0;
+ nand_pushio_byte(s, s->manf_id);
+ nand_pushio_byte(s, s->chip_id);
+ nand_pushio_byte(s, 'Q'); /* Don't-case byte (often 0xa5) */
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
- s->io[3] = 0x15; /* Page Size, Block Size, Spare Size.. */
+ nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
else
- s->io[3] = 0xc0; /* Multi-plane */
- s->ioaddr = s->io;
- s->iolen = 4;
+ nand_pushio_byte(s, 0xc0); /* Multi-plane */
break;
case NAND_CMD_RANDOMREAD2:
@@ -272,9 +288,9 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_READSTATUS:
- s->io[0] = s->status;
s->ioaddr = s->io;
- s->iolen = 1;
+ s->iolen = 0;
+ nand_pushio_byte(s, s->status);
break;
default:
@@ -295,7 +311,7 @@ static void nand_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->iolen);
qemu_put_be32s(f, &s->cmd);
- qemu_put_be32s(f, &s->addr);
+ qemu_put_be64s(f, &s->addr);
qemu_put_be32(f, s->addrlen);
qemu_put_be32(f, s->status);
qemu_put_be32(f, s->offset);
@@ -317,7 +333,7 @@ static int nand_load(QEMUFile *f, void *opaque, int version_id)
return -EINVAL;
qemu_get_be32s(f, &s->cmd);
- qemu_get_be32s(f, &s->addr);
+ qemu_get_be64s(f, &s->addr);
s->addrlen = qemu_get_be32(f);
s->status = qemu_get_be32(f);
s->offset = qemu_get_be32(f);
@@ -349,11 +365,16 @@ void nand_getpins(NANDFlashState *s, int *rb)
*rb = 1;
}
-void nand_setio(NANDFlashState *s, uint8_t value)
+void nand_setio(NANDFlashState *s, uint32_t value)
{
+ int i;
+
if (!s->ce && s->cle) {
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
+ if (s->cmd == NAND_CMD_READ0
+ && (value == NAND_CMD_LPREAD2
+ || value == NAND_CMD_READCACHESTART
+ || value == NAND_CMD_READCACHELAST))
return;
if (value == NAND_CMD_RANDOMREAD1) {
s->addr &= ~((1 << s->addr_shift) - 1);
@@ -380,7 +401,8 @@ void nand_setio(NANDFlashState *s, uint8_t value)
s->cmd == NAND_CMD_BLOCKERASE2 ||
s->cmd == NAND_CMD_NOSERIALREAD2 ||
s->cmd == NAND_CMD_RANDOMREAD2 ||
- s->cmd == NAND_CMD_RESET)
+ s->cmd == NAND_CMD_RESET ||
+ s->cmd == NAND_CMD_READCACHEEXIT)
nand_command(s);
if (s->cmd != NAND_CMD_RANDOMREAD2) {
@@ -396,40 +418,60 @@ void nand_setio(NANDFlashState *s, uint8_t value)
s->addr = (s->addr & mask) | v;
s->addrlen ++;
- if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
- nand_command(s);
-
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- s->addrlen == 3 && (
- s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1))
- nand_command(s);
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- s->addrlen == 4 && (
- s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1))
- nand_command(s);
+ switch (s->addrlen) {
+ case 1:
+ if (s->cmd == NAND_CMD_READID)
+ nand_command(s);
+ break;
+ case 2: /* fix cache address as a byte address */
+ s->addr <<= (s->buswidth - 1);
+ break;
+ case 3:
+ if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+ && (s->cmd == NAND_CMD_READ0
+ || s->cmd == NAND_CMD_PAGEPROGRAM1))
+ nand_command(s);
+ break;
+ case 4:
+ if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+ && nand_flash_ids[s->chip_id].size < 256 /* 1Gb or less */
+ && (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1))
+ nand_command(s);
+ break;
+ case 5:
+ if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+ && nand_flash_ids[s->chip_id].size >= 256 /* 2Gb or more */
+ && (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1))
+ nand_command(s);
+ break;
+ default:
+ break;
+ }
}
if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
- s->io[s->iolen ++] = value;
+ for (i = s->buswidth; i--; value >>= 8)
+ s->io[s->iolen++] = (uint8_t)(value & 0xff);
} else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
if ((s->addr & ((1 << s->addr_shift) - 1)) <
- (1 << s->page_shift) + (1 << s->oob_shift)) {
- s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
- s->addr ++;
- }
+ (1 << s->page_shift) + (1 << s->oob_shift))
+ for (i = s->buswidth; i--; s->addr++, value >>= 8)
+ s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+ (uint8_t)(value & 0xff);
}
}
-uint8_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(NANDFlashState *s)
{
int offset;
+ uint32_t x = 0;
/* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
- offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+ offset = (int)((s->addr & ((1 << s->addr_shift) - 1))) + s->offset;
s->offset = 0;
s->blk_load(s, s->addr, offset);
@@ -442,27 +484,40 @@ uint8_t nand_getio(NANDFlashState *s)
if (s->ce || s->iolen <= 0)
return 0;
- s->iolen --;
- s->addr++;
- return *(s->ioaddr ++);
+ for (offset = s->buswidth; offset--;)
+ x |= s->ioaddr[offset] << (offset << 3);
+ /* after receiving READ STATUS command all subsequent reads will
+ return the status register value until another command is issued */
+ if (s->cmd != NAND_CMD_READSTATUS) {
+ s->addr += s->buswidth;
+ s->ioaddr += s->buswidth;
+ s->iolen -= s->buswidth;
+ }
+ return x;
}
-NANDFlashState *nand_init(int manf_id, int chip_id)
+uint32_t nand_getbuswidth(NANDFlashState *s)
+{
+ if (!s)
+ return 0;
+ return (s->buswidth << 3);
+}
+
+NANDFlashState *nand_init(int manf_id, int chip_id, DriveInfo *dinfo)
{
int pagesize;
NANDFlashState *s;
- DriveInfo *dinfo;
if (nand_flash_ids[chip_id].size == 0) {
hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
}
s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
- dinfo = drive_get(IF_MTD, 0, 0);
if (dinfo)
s->bdrv = dinfo->bdrv;
s->manf_id = manf_id;
s->chip_id = chip_id;
+ s->buswidth = (uint8_t)(nand_flash_ids[s->chip_id].width >> 3);
s->size = nand_flash_ids[s->chip_id].size << 20;
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
s->page_shift = 11;
@@ -526,45 +581,61 @@ void nand_done(NANDFlashState *s)
/* Program a single page */
static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
{
- uint32_t off, page, sector, soff;
+ uint64_t off, page, sector, soff;
uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
if (PAGE(s->addr) >= s->pages)
return;
if (!s->bdrv) {
- memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
- s->offset, s->io, s->iolen);
+ uint8_t *p = s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+ s->offset;
+ int i;
+ for (i = 0; i < s->iolen; i++) {
+ p[i] &= s->io[i];
+ }
} else if (s->mem_oob) {
sector = SECTOR(s->addr);
off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr);
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
- printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: read error in sector %llu\n", __FUNCTION__, (long long unsigned)sector);
return;
}
- memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+ uint8_t *p = iobuf + (soff | off);
+ int i, count = MIN(s->iolen, PAGE_SIZE - off);
+ for (i = 0; i < count; i++) {
+ p[i] &= s->io[i];
+ }
if (off + s->iolen > PAGE_SIZE) {
page = PAGE(s->addr);
- memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
- MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
+ p = s->storage + (page << OOB_SHIFT);
+ uint8_t *q = s->io + PAGE_SIZE - off;
+ count = MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE);
+ for (i = 0; i < count; i++) {
+ p[i] &= q[i];
+ }
}
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: write error in sector %llu\n", __FUNCTION__, (long long unsigned)sector);
} else {
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
sector = off >> 9;
soff = off & 0x1ff;
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
- printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: read error in sector %llu\n", __FUNCTION__, (long long unsigned)sector);
return;
}
- memcpy(iobuf + soff, s->io, s->iolen);
+ uint8_t *p = iobuf + soff;
+ int i;
+ for (i = 0; i < s->iolen; i++) {
+ p[i] &= s->io[i];
+ }
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: write error in sector %llu\n", __FUNCTION__, (long long unsigned)sector);
}
s->offset = 0;
}
@@ -572,7 +643,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
/* Erase a single block */
static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
{
- uint32_t i, page, addr;
+ uint64_t i, page, addr;
uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
@@ -589,34 +660,34 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
for (; i < page; i ++)
if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, i);
+ printf("%s: write error in sector %llu\n", __FUNCTION__, (long long unsigned)i);
} else {
addr = PAGE_START(addr);
page = addr >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: read error in sector %i\n", __FUNCTION__, page);
+ printf("%s: read error in sector %llu\n", __FUNCTION__, (long long unsigned)page);
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, page);
+ printf("%s: write error in sector %llu\n", __FUNCTION__, (long long unsigned)page);
memset(iobuf, 0xff, 0x200);
i = (addr & ~0x1ff) + 0x200;
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200)
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+ printf("%s: write error in sector %llu\n", __FUNCTION__, (long long unsigned)i >> 9);
page = i >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: read error in sector %i\n", __FUNCTION__, page);
+ printf("%s: read error in sector %llu\n", __FUNCTION__, (long long unsigned)page);
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, page);
+ printf("%s: write error in sector %llu\n", __FUNCTION__, (long long unsigned)page);
}
}
static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
- uint32_t addr, int offset)
+ uint64_t addr, int offset)
{
if (PAGE(addr) >= s->pages)
return;
@@ -624,8 +695,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
if (s->bdrv) {
if (s->mem_oob) {
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
- printf("%s: read error in sector %i\n",
- __FUNCTION__, SECTOR(addr));
+ printf("%s: read error in sector %llu\n",
+ __FUNCTION__, (long long unsigned)SECTOR(addr));
memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
s->storage + (PAGE(s->addr) << OOB_SHIFT),
OOB_SIZE);
@@ -633,8 +704,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
} else {
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
s->io, (PAGE_SECTORS + 2)) == -1)
- printf("%s: read error in sector %i\n",
- __FUNCTION__, PAGE_START(addr) >> 9);
+ printf("%s: read error in sector %llu\n",
+ __FUNCTION__, (long long unsigned)PAGE_START(addr) >> 9);
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
}
} else {
diff --git a/hw/spitz.c b/hw/spitz.c
index 564519b..05b62e5 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -170,9 +170,9 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
s = (SLNANDState *) qemu_mallocz(sizeof(SLNANDState));
s->ctl = 0;
if (size == FLASH_128M)
- s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73);
+ s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73, drive_get(IF_MTD, 0, 0));
else if (size == FLASH_1024M)
- s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1);
+ s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1, drive_get(IF_MTD, 0, 0));
iomemtype = cpu_register_io_memory(sl_readfn,
sl_writefn, s);
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index e0c5e5f..c4e6807 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -13,6 +13,7 @@
#include "flash.h"
#include "console.h"
#include "pixel_ops.h"
+#include "sysemu.h"
#define IRQ_TC6393_NAND 0
#define IRQ_TC6393_MMC 1
@@ -587,7 +588,7 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
- s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
+ s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76, drive_get(IF_MTD, 0, 0));
iomemtype = cpu_register_io_memory(tc6393xb_readfn,
tc6393xb_writefn, s);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 22/48] License update
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (17 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 21/48] NAND emulation overhaul Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 19:03 ` Anthony Liguori
2010-03-26 16:06 ` [Qemu-devel] [PATCH 23/48] multi-mmc support in init call Riku Voipio
` (25 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 7607 bytes --]
From: Riku Voipio <riku.voipio@nokia.com>
Legal requested us to be open to future.
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/blizzard.c | 2 +-
hw/blizzard_template.h | 2 +-
hw/cbus.c | 2 +-
hw/lm832x.c | 2 +-
hw/nseries.c | 7 ++++---
hw/omap2.c | 4 ++--
hw/onenand.c | 4 ++--
hw/soc_dma.c | 2 +-
hw/tmp105.c | 2 +-
hw/tusb6010.c | 2 +-
hw/twl92230.c | 2 +-
11 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/hw/blizzard.c b/hw/blizzard.c
index 5f329ad..7cbb358 100644
--- a/hw/blizzard.c
+++ b/hw/blizzard.c
@@ -7,7 +7,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/blizzard_template.h b/hw/blizzard_template.h
index 42f4e90..e9f130f 100644
--- a/hw/blizzard_template.h
+++ b/hw/blizzard_template.h
@@ -7,7 +7,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/cbus.c b/hw/cbus.c
index 8ae24e0..61cfca6 100644
--- a/hw/cbus.c
+++ b/hw/cbus.c
@@ -9,7 +9,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/lm832x.c b/hw/lm832x.c
index ce7dcac..5d575ba 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -7,7 +7,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/nseries.c b/hw/nseries.c
index 0273eee..2013354 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1,13 +1,14 @@
/*
* Nokia N-series internet tablets.
*
- * Copyright (C) 2007 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ * Copyright (C) 2007-2009 Nokia Corporation
+ * N800/N810 support written by Andrzej Zaborowski <andrew@openedhand.com>
+ * N900 support written by Juha Riihimäki
*
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/omap2.c b/hw/omap2.c
index a3fa89d..69b6ea8 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -1,13 +1,13 @@
/*
* TI OMAP processors emulation.
*
- * Copyright (C) 2007-2008 Nokia Corporation
+ * Copyright (C) 2007-2009 Nokia Corporation
* Written by Andrzej Zaborowski <andrew@openedhand.com>
*
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/onenand.c b/hw/onenand.c
index c1e7e4d..b447726 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -1,13 +1,13 @@
/*
* OneNAND flash memories emulation.
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2008-2009 Nokia Corporation
* Written by Andrzej Zaborowski <andrew@openedhand.com>
*
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/soc_dma.c b/hw/soc_dma.c
index e116e63..8147ed5 100644
--- a/hw/soc_dma.c
+++ b/hw/soc_dma.c
@@ -7,7 +7,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/tmp105.c b/hw/tmp105.c
index 8343aff..9fae2e4 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -7,7 +7,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 3887233..284245b 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -8,7 +8,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/hw/twl92230.c b/hw/twl92230.c
index e61f17f..81f41e0 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -8,7 +8,7 @@
* 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 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 22/48] License update
2010-03-26 16:06 ` [Qemu-devel] [PATCH 22/48] License update Riku Voipio
@ 2010-03-26 19:03 ` Anthony Liguori
0 siblings, 0 replies; 55+ messages in thread
From: Anthony Liguori @ 2010-03-26 19:03 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, Juha Riihimäki, qemu-devel
On 03/26/2010 11:06 AM, Riku Voipio wrote:
> From: Riku Voipio<riku.voipio@nokia.com>
>
> Legal requested us to be open to future.
>
> Signed-Off-By: Riku Voipio<riku.voipio@nokia.com>
> Signed-Off-By: Juha Riihimäki<juha.riihimaki@nokia.com>
>
> ---
> hw/blizzard.c | 2 +-
> hw/blizzard_template.h | 2 +-
> hw/cbus.c | 2 +-
> hw/lm832x.c | 2 +-
> hw/nseries.c | 7 ++++---
> hw/omap2.c | 4 ++--
> hw/onenand.c | 4 ++--
> hw/soc_dma.c | 2 +-
> hw/tmp105.c | 2 +-
> hw/tusb6010.c | 2 +-
> hw/twl92230.c | 2 +-
> 11 files changed, 16 insertions(+), 15 deletions(-)
>
These files have been touched by multiple authors so the license cannot
be changed without permission from each author.
git log --format=pretty:"%an <%ae>"
Will give you a quick list for each file.
Regards,
Anthony Liguori
> diff --git a/hw/blizzard.c b/hw/blizzard.c
> index 5f329ad..7cbb358 100644
> --- a/hw/blizzard.c
> +++ b/hw/blizzard.c
> @@ -7,7 +7,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/blizzard_template.h b/hw/blizzard_template.h
> index 42f4e90..e9f130f 100644
> --- a/hw/blizzard_template.h
> +++ b/hw/blizzard_template.h
> @@ -7,7 +7,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/cbus.c b/hw/cbus.c
> index 8ae24e0..61cfca6 100644
> --- a/hw/cbus.c
> +++ b/hw/cbus.c
> @@ -9,7 +9,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/lm832x.c b/hw/lm832x.c
> index ce7dcac..5d575ba 100644
> --- a/hw/lm832x.c
> +++ b/hw/lm832x.c
> @@ -7,7 +7,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/nseries.c b/hw/nseries.c
> index 0273eee..2013354 100644
> --- a/hw/nseries.c
> +++ b/hw/nseries.c
> @@ -1,13 +1,14 @@
> /*
> * Nokia N-series internet tablets.
> *
> - * Copyright (C) 2007 Nokia Corporation
> - * Written by Andrzej Zaborowski<andrew@openedhand.com>
> + * Copyright (C) 2007-2009 Nokia Corporation
> + * N800/N810 support written by Andrzej Zaborowski<andrew@openedhand.com>
> + * N900 support written by Juha Riihimäki
> *
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/omap2.c b/hw/omap2.c
> index a3fa89d..69b6ea8 100644
> --- a/hw/omap2.c
> +++ b/hw/omap2.c
> @@ -1,13 +1,13 @@
> /*
> * TI OMAP processors emulation.
> *
> - * Copyright (C) 2007-2008 Nokia Corporation
> + * Copyright (C) 2007-2009 Nokia Corporation
> * Written by Andrzej Zaborowski<andrew@openedhand.com>
> *
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/onenand.c b/hw/onenand.c
> index c1e7e4d..b447726 100644
> --- a/hw/onenand.c
> +++ b/hw/onenand.c
> @@ -1,13 +1,13 @@
> /*
> * OneNAND flash memories emulation.
> *
> - * Copyright (C) 2008 Nokia Corporation
> + * Copyright (C) 2008-2009 Nokia Corporation
> * Written by Andrzej Zaborowski<andrew@openedhand.com>
> *
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/soc_dma.c b/hw/soc_dma.c
> index e116e63..8147ed5 100644
> --- a/hw/soc_dma.c
> +++ b/hw/soc_dma.c
> @@ -7,7 +7,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/tmp105.c b/hw/tmp105.c
> index 8343aff..9fae2e4 100644
> --- a/hw/tmp105.c
> +++ b/hw/tmp105.c
> @@ -7,7 +7,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/tusb6010.c b/hw/tusb6010.c
> index 3887233..284245b 100644
> --- a/hw/tusb6010.c
> +++ b/hw/tusb6010.c
> @@ -8,7 +8,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> diff --git a/hw/twl92230.c b/hw/twl92230.c
> index e61f17f..81f41e0 100644
> --- a/hw/twl92230.c
> +++ b/hw/twl92230.c
> @@ -8,7 +8,7 @@
> * 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 or
> - * (at your option) version 3 of the License.
> + * (at your option) any later version of the License.
> *
> * This program is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 23/48] multi-mmc support in init call
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (18 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 22/48] License update Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-28 19:19 ` Filip Navara
2010-03-26 16:06 ` [Qemu-devel] [PATCH 24/48] onenand overhaul Riku Voipio
` (24 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
change sd_init convention to allow multiple entries
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/omap_mmc.c | 4 ++--
hw/pl181.c | 2 +-
hw/pxa2xx_mmci.c | 2 +-
hw/sd.h | 4 +++-
hw/ssi-sd.c | 2 +-
5 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
index 15cbf06..7c94d91 100644
--- a/hw/omap_mmc.c
+++ b/hw/omap_mmc.c
@@ -590,7 +590,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
cpu_register_physical_memory(base, 0x800, iomemtype);
/* Instantiate the storage */
- s->card = sd_init(bd, 0);
+ s->card = sd_init(bd, 0, 0);
return s;
}
@@ -616,7 +616,7 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
omap_l4_attach(ta, 0, iomemtype);
/* Instantiate the storage */
- s->card = sd_init(bd, 0);
+ s->card = sd_init(bd, 0, 0);
s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
sd_set_cb(s->card, NULL, s->cdet);
diff --git a/hw/pl181.c b/hw/pl181.c
index 1924053..fd5ee81 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -458,7 +458,7 @@ static int pl181_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq[0]);
sysbus_init_irq(dev, &s->irq[1]);
bd = qdev_init_bdrv(&dev->qdev, IF_SD);
- s->card = sd_init(bd, 0);
+ s->card = sd_init(bd, 0, 0);
qemu_register_reset(pl181_reset, s);
pl181_reset(s);
/* ??? Save/restore. */
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
index a415349..01e7f1e 100644
--- a/hw/pxa2xx_mmci.c
+++ b/hw/pxa2xx_mmci.c
@@ -532,7 +532,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
cpu_register_physical_memory(base, 0x00100000, iomemtype);
/* Instantiate the actual storage */
- s->card = sd_init(bd, 0);
+ s->card = sd_init(bd, 0, 0);
register_savevm("pxa2xx_mmci", 0, 0,
pxa2xx_mmci_save, pxa2xx_mmci_load, s);
diff --git a/hw/sd.h b/hw/sd.h
index ac4b7c4..96450f2 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -67,7 +67,8 @@ typedef struct {
typedef struct SDState SDState;
-SDState *sd_init(BlockDriverState *bs, int is_spi);
+SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc);
+void sd_reset(SDState *sd);
int sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response);
void sd_write_data(SDState *sd, uint8_t value);
@@ -75,5 +76,6 @@ uint8_t sd_read_data(SDState *sd);
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
int sd_data_ready(SDState *sd);
void sd_enable(SDState *sd, int enable);
+int sd_is_mmc(SDState *sd);
#endif /* __hw_sd_h */
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 5e74e5d..a5d350d 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -236,7 +236,7 @@ static int ssi_sd_init(SSISlave *dev)
s->mode = SSI_SD_CMD;
bs = qdev_init_bdrv(&dev->qdev, IF_SD);
- s->sd = sd_init(bs, 1);
+ s->sd = sd_init(bs, 1, 0);
register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
return 0;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 23/48] multi-mmc support in init call
2010-03-26 16:06 ` [Qemu-devel] [PATCH 23/48] multi-mmc support in init call Riku Voipio
@ 2010-03-28 19:19 ` Filip Navara
0 siblings, 0 replies; 55+ messages in thread
From: Filip Navara @ 2010-03-28 19:19 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, Juha Riihimäki, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 3596 bytes --]
I see neither the change to sd_init implementation nor the implementation
of sd_is_mmc.
Best regards,
Filip Navara
On Fri, Mar 26, 2010 at 5:06 PM, Riku Voipio <riku.voipio@iki.fi> wrote:
> From: Juha Riihimäki <juha.riihimaki@nokia.com>
>
> change sd_init convention to allow multiple entries
>
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
> Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
>
> ---
> hw/omap_mmc.c | 4 ++--
> hw/pl181.c | 2 +-
> hw/pxa2xx_mmci.c | 2 +-
> hw/sd.h | 4 +++-
> hw/ssi-sd.c | 2 +-
> 5 files changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
> index 15cbf06..7c94d91 100644
> --- a/hw/omap_mmc.c
> +++ b/hw/omap_mmc.c
> @@ -590,7 +590,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t
> base,
> cpu_register_physical_memory(base, 0x800, iomemtype);
>
> /* Instantiate the storage */
> - s->card = sd_init(bd, 0);
> + s->card = sd_init(bd, 0, 0);
>
> return s;
> }
> @@ -616,7 +616,7 @@ struct omap_mmc_s *omap2_mmc_init(struct
> omap_target_agent_s *ta,
> omap_l4_attach(ta, 0, iomemtype);
>
> /* Instantiate the storage */
> - s->card = sd_init(bd, 0);
> + s->card = sd_init(bd, 0, 0);
>
> s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
> sd_set_cb(s->card, NULL, s->cdet);
> diff --git a/hw/pl181.c b/hw/pl181.c
> index 1924053..fd5ee81 100644
> --- a/hw/pl181.c
> +++ b/hw/pl181.c
> @@ -458,7 +458,7 @@ static int pl181_init(SysBusDevice *dev)
> sysbus_init_irq(dev, &s->irq[0]);
> sysbus_init_irq(dev, &s->irq[1]);
> bd = qdev_init_bdrv(&dev->qdev, IF_SD);
> - s->card = sd_init(bd, 0);
> + s->card = sd_init(bd, 0, 0);
> qemu_register_reset(pl181_reset, s);
> pl181_reset(s);
> /* ??? Save/restore. */
> diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
> index a415349..01e7f1e 100644
> --- a/hw/pxa2xx_mmci.c
> +++ b/hw/pxa2xx_mmci.c
> @@ -532,7 +532,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t
> base,
> cpu_register_physical_memory(base, 0x00100000, iomemtype);
>
> /* Instantiate the actual storage */
> - s->card = sd_init(bd, 0);
> + s->card = sd_init(bd, 0, 0);
>
> register_savevm("pxa2xx_mmci", 0, 0,
> pxa2xx_mmci_save, pxa2xx_mmci_load, s);
> diff --git a/hw/sd.h b/hw/sd.h
> index ac4b7c4..96450f2 100644
> --- a/hw/sd.h
> +++ b/hw/sd.h
> @@ -67,7 +67,8 @@ typedef struct {
>
> typedef struct SDState SDState;
>
> -SDState *sd_init(BlockDriverState *bs, int is_spi);
> +SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc);
> +void sd_reset(SDState *sd);
> int sd_do_command(SDState *sd, SDRequest *req,
> uint8_t *response);
> void sd_write_data(SDState *sd, uint8_t value);
> @@ -75,5 +76,6 @@ uint8_t sd_read_data(SDState *sd);
> void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
> int sd_data_ready(SDState *sd);
> void sd_enable(SDState *sd, int enable);
> +int sd_is_mmc(SDState *sd);
>
> #endif /* __hw_sd_h */
> diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
> index 5e74e5d..a5d350d 100644
> --- a/hw/ssi-sd.c
> +++ b/hw/ssi-sd.c
> @@ -236,7 +236,7 @@ static int ssi_sd_init(SSISlave *dev)
>
> s->mode = SSI_SD_CMD;
> bs = qdev_init_bdrv(&dev->qdev, IF_SD);
> - s->sd = sd_init(bs, 1);
> + s->sd = sd_init(bs, 1, 0);
> register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
> return 0;
> }
> --
> 1.6.5
>
>
>
>
[-- Attachment #2: Type: text/html, Size: 4482 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 24/48] onenand overhaul
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (19 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 23/48] multi-mmc support in init call Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 25/48] blizzard: fix for non-32bpp host displays Riku Voipio
` (23 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
- major onenand emulation changes
- add reset support
- onenand: ignore zero writes to boot command area
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/flash.h | 5 +-
hw/onenand.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 234 insertions(+), 46 deletions(-)
diff --git a/hw/flash.h b/hw/flash.h
index 170a788..74cfb37 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -1,3 +1,5 @@
+#include "sysemu.h"
+
/* NOR flash devices */
typedef struct pflash_t pflash_t;
@@ -39,7 +41,8 @@ uint32_t nand_getbuswidth(NANDFlashState *s);
/* onenand.c */
void onenand_base_update(void *opaque, target_phys_addr_t new);
void onenand_base_unmap(void *opaque);
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
+void *onenand_init(uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
+ int regshift, qemu_irq irq, DriveInfo *dinfo);
void *onenand_raw_otp(void *opaque);
/* ecc.c */
diff --git a/hw/onenand.c b/hw/onenand.c
index b447726..dc6dbee 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -23,6 +23,7 @@
#include "irq.h"
#include "sysemu.h"
#include "block.h"
+#include "hw.h"
/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
#define PAGE_SHIFT 11
@@ -31,7 +32,11 @@
#define BLOCK_SHIFT (PAGE_SHIFT + 6)
typedef struct {
- uint32_t id;
+ struct {
+ uint16_t man;
+ uint16_t dev;
+ uint16_t ver;
+ } id;
int shift;
target_phys_addr_t base;
qemu_irq intr;
@@ -128,6 +133,85 @@ static void onenand_intr_update(OneNANDState *s)
qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
}
+static void onenand_save_state(QEMUFile *f, void *opaque)
+{
+ OneNANDState *s = (OneNANDState *)opaque;
+ int i;
+
+ if (s->current == s->otp)
+ qemu_put_byte(f, 1);
+ else if (s->current == s->image)
+ qemu_put_byte(f, 2);
+ else
+ qemu_put_byte(f, 0);
+ qemu_put_sbe32(f, s->cycle);
+ qemu_put_sbe32(f, s->otpmode);
+ for (i = 0; i < 8; i++) {
+ qemu_put_be16(f, s->addr[i]);
+ qemu_put_be16(f, s->unladdr[i]);
+ }
+ qemu_put_sbe32(f, s->bufaddr);
+ qemu_put_sbe32(f, s->count);
+ qemu_put_be16(f, s->command);
+ qemu_put_be16(f, s->config[0]);
+ qemu_put_be16(f, s->config[1]);
+ qemu_put_be16(f, s->status);
+ qemu_put_be16(f, s->intstatus);
+ qemu_put_be16(f, s->wpstatus);
+ qemu_put_sbe32(f, s->secs_cur);
+ qemu_put_buffer(f, s->blockwp, s->blocks);
+ qemu_put_byte(f, s->ecc.cp);
+ qemu_put_be16(f, s->ecc.lp[0]);
+ qemu_put_be16(f, s->ecc.lp[1]);
+ qemu_put_be16(f, s->ecc.count);
+ qemu_put_buffer(f, s->otp, (64 + 2) << PAGE_SHIFT);
+}
+
+static int onenand_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ OneNANDState *s = (OneNANDState *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ switch (qemu_get_byte(f)) {
+ case 1:
+ s->current = s->otp;
+ break;
+ case 2:
+ s->current = s->image;
+ break;
+ default:
+ break;
+ }
+ s->cycle = qemu_get_sbe32(f);
+ s->otpmode = qemu_get_sbe32(f);
+ for (i = 0; i < 8; i++) {
+ s->addr[i] = qemu_get_be16(f);
+ s->unladdr[i] = qemu_get_be16(f);
+ }
+ s->bufaddr = qemu_get_sbe32(f);
+ s->count = qemu_get_sbe32(f);
+ s->command = qemu_get_be16(f);
+ s->config[0] = qemu_get_be16(f);
+ s->config[1] = qemu_get_be16(f);
+ s->status = qemu_get_be16(f);
+ s->intstatus = qemu_get_be16(f);
+ s->wpstatus = qemu_get_be16(f);
+ s->secs_cur = qemu_get_sbe32(f);
+ qemu_get_buffer(f, s->blockwp, s->blocks);
+ s->ecc.cp = qemu_get_byte(f);
+ s->ecc.lp[0] = qemu_get_be16(f);
+ s->ecc.lp[1] = qemu_get_be16(f);
+ s->ecc.count = qemu_get_be16(f);
+ qemu_get_buffer(f, s->otp, (64 + 2) << PAGE_SHIFT);
+
+ onenand_intr_update(s);
+
+ return 0;
+}
+
/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
static void onenand_reset(OneNANDState *s, int cold)
{
@@ -159,6 +243,11 @@ static void onenand_reset(OneNANDState *s, int cold)
}
}
+static void onenand_system_reset(void *opaque)
+{
+ onenand_reset(opaque, 1);
+}
+
static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
void *dest)
{
@@ -175,14 +264,39 @@ static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
void *src)
{
- if (s->bdrv_cur)
- return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
- else if (sec + secn > s->secs_cur)
- return 1;
-
- memcpy(s->current + (sec << 9), src, secn << 9);
+ int result = 0;
+
+ if (secn > 0) {
+ uint32_t size = (uint32_t)secn * 512;
+ const uint8_t *sp = (const uint8_t *)src;
+ uint8_t *dp = 0;
+ if (s->bdrv_cur) {
+ dp = qemu_malloc(size);
+ if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+ result = 1;
+ }
+ } else {
+ if (sec + secn > s->secs_cur) {
+ result = 1;
+ } else {
+ dp = (uint8_t *)s->current + (sec << 9);
+ }
+ }
+ if (!result) {
+ uint32_t i;
+ for (i = 0; i < size; i++) {
+ dp[i] &= sp[i];
+ }
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+ }
+ }
+ if (dp && s->bdrv_cur) {
+ qemu_free(dp);
+ }
+ }
- return 0;
+ return result;
}
static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
@@ -205,35 +319,87 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
void *src)
{
- uint8_t buf[512];
-
- if (s->bdrv_cur) {
- if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
- return 1;
- memcpy(buf + ((sec & 31) << 4), src, secn << 4);
- return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
- } else if (sec + secn > s->secs_cur)
- return 1;
-
- memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
-
- return 0;
+ int result = 0;
+ if (secn > 0) {
+ const uint8_t *sp = (const uint8_t *)src;
+ uint8_t *dp = 0, *dpp = 0;
+ if (s->bdrv_cur) {
+ dp = qemu_malloc(512);
+ if (!dp || bdrv_read(s->bdrv_cur,
+ s->secs_cur + (sec >> 5),
+ dp, 1) < 0) {
+ result = 1;
+ } else {
+ dpp = dp + ((sec & 31) << 4);
+ }
+ } else {
+ if (sec + secn > s->secs_cur) {
+ result = 1;
+ } else {
+ dpp = s->current + (s->secs_cur << 9) + (sec << 4);
+ }
+ }
+ if (!result) {
+ uint32_t i;
+ for (i = 0; i < (secn << 4); i++) {
+ dpp[i] &= sp[i];
+ }
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
+ dp, 1) < 0;
+ }
+ }
+ if (dp) {
+ qemu_free(dp);
+ }
+ }
+ return result;
}
static inline int onenand_erase(OneNANDState *s, int sec, int num)
{
- /* TODO: optimise */
- uint8_t buf[512];
-
- memset(buf, 0xff, sizeof(buf));
- for (; num > 0; num --, sec ++) {
- if (onenand_prog_main(s, sec, 1, buf))
- return 1;
- if (onenand_prog_spare(s, sec, 1, buf))
- return 1;
+ int result = 0;
+
+ uint8_t *buf, *buf2;
+ buf = qemu_malloc(512);
+ if (buf) {
+ buf2 = qemu_malloc(512);
+ if (buf2) {
+ memset(buf, 0xff, 512);
+ for (; !result && num > 0; num--, sec++) {
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, sec, buf, 1);
+ if (!result) {
+ result = bdrv_read(s->bdrv_cur,
+ s->secs_cur + (sec >> 5),
+ buf2, 1) < 0;
+ if (!result) {
+ memcpy(buf2 + ((sec & 31) << 4), buf, 1 << 4);
+ result = bdrv_write(s->bdrv_cur,
+ s->secs_cur + (sec >> 5),
+ buf2, 1) < 0;
+ }
+ }
+ } else {
+ if (sec + 1 > s->secs_cur) {
+ result = 1;
+ } else {
+ memcpy(s->current + (sec << 9), buf, 512);
+ memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
+ buf, 1 << 4);
+ }
+ }
+ }
+ qemu_free(buf2);
+ } else {
+ result = 1;
+ }
+ qemu_free(buf);
+ } else {
+ result = 1;
}
-
- return 0;
+
+ return result;
}
static void onenand_command(OneNANDState *s, int cmd)
@@ -293,6 +459,7 @@ static void onenand_command(OneNANDState *s, int cmd)
SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
SETBUF_M()
+
if (onenand_prog_main(s, sec, s->count, buf))
s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
@@ -453,12 +620,12 @@ static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
return lduw_le_p(s->boot[0] + addr);
case 0xf000: /* Manufacturer ID */
- return (s->id >> 16) & 0xff;
+ return s->id.man;
case 0xf001: /* Device ID */
- return (s->id >> 8) & 0xff;
- /* TODO: get the following values from a real chip! */
+ return s->id.dev;
case 0xf002: /* Version ID */
- return (s->id >> 0) & 0xff;
+ return s->id.ver;
+ /* TODO: get the following values from a real chip! */
case 0xf003: /* Data Buffer size */
return 1 << PAGE_SHIFT;
case 0xf004: /* Boot Buffer size */
@@ -541,11 +708,18 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
case 0x0090: /* Read Identification Data */
memset(s->boot[0], 0, 3 << s->shift);
- s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
- s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff;
+ s->boot[0][0 << s->shift] = s->id.man & 0xff;
+ s->boot[0][1 << s->shift] = s->id.dev & 0xff;
s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
break;
+ case 0x0000:
+ /* ignore zero writes without error messages,
+ * linux omap2/3 kernel will issue these upon
+ * powerdown/reset sequence.
+ */
+ break;
+
default:
fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
__FUNCTION__, value);
@@ -615,23 +789,25 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
onenand_write,
};
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
+void *onenand_init(uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
+ int regshift, qemu_irq irq, DriveInfo *dinfo)
{
OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
- DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
- uint32_t size = 1 << (24 + ((id >> 12) & 7));
+ uint32_t size = 1 << (24 + ((dev_id >> 4) & 7));
void *ram;
s->shift = regshift;
s->intr = irq;
s->rdy = NULL;
- s->id = id;
+ s->id.man = man_id;
+ s->id.dev = dev_id;
+ s->id.ver = ver_id;
s->blocks = size >> BLOCK_SHIFT;
s->secs = size >> 9;
s->blockwp = qemu_malloc(s->blocks);
- s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
+ s->density_mask = (dev_id & 0x08) ? (1 << (6 + ((dev_id >> 4) & 7))) : 0;
s->iomemtype = cpu_register_io_memory(onenand_readfn,
- onenand_writefn, s);
+ onenand_writefn, s);
if (!dinfo)
s->image = memset(qemu_malloc(size + (size >> 5)),
0xff, size + (size >> 5));
@@ -648,7 +824,16 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
- onenand_reset(s, 1);
+ onenand_system_reset(s);
+ qemu_register_reset(onenand_system_reset, s);
+
+ register_savevm("onenand",
+ ((regshift & 0x7f) << 24)
+ | ((man_id & 0xff) << 16)
+ | ((dev_id & 0xff) << 8)
+ | (ver_id & 0xff),
+ 0,
+ onenand_save_state, onenand_load_state, s);
return s;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 25/48] blizzard: fix for non-32bpp host displays
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (20 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 24/48] onenand overhaul Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 26/48] SD overhaul Riku Voipio
` (22 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 4993 bytes --]
From: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/blizzard.c | 102 +++++++++++++++++++++++++++++---------------------------
1 files changed, 53 insertions(+), 49 deletions(-)
diff --git a/hw/blizzard.c b/hw/blizzard.c
index 7cbb358..d110eec 100644
--- a/hw/blizzard.c
+++ b/hw/blizzard.c
@@ -71,7 +71,6 @@ typedef struct {
uint8_t iformat;
uint8_t source;
DisplayState *state;
- blizzard_fn_t *line_fn_tab[2];
void *fb;
uint8_t hssi_config[3];
@@ -117,7 +116,6 @@ typedef struct {
uint16_t *ptr;
int angle;
int pitch;
- blizzard_fn_t line_fn;
} data;
} BlizzardState;
@@ -135,6 +133,17 @@ static const int blizzard_iformat_bpp[0x10] = {
0, 0, 0, 0, 0, 0,
};
+#define DEPTH 8
+#include "blizzard_template.h"
+#define DEPTH 15
+#include "blizzard_template.h"
+#define DEPTH 16
+#include "blizzard_template.h"
+#define DEPTH 24
+#include "blizzard_template.h"
+#define DEPTH 32
+#include "blizzard_template.h"
+
static inline void blizzard_rgb2yuv(int r, int g, int b,
int *y, int *u, int *v)
{
@@ -149,8 +158,43 @@ static void blizzard_window(BlizzardState *s)
int bypp[2];
int bypl[3];
int y;
- blizzard_fn_t fn = s->data.line_fn;
-
+ blizzard_fn_t fn = 0;
+
+ /* FIXME: this is a hack - but nseries.c will use this function
+ * before correct DisplayState is initialized so we need a way to
+ * avoid drawing something when we actually have no clue about host bpp */
+ if (!s->state->listeners)
+ return;
+
+ switch (ds_get_bits_per_pixel(s->state)) {
+ case 8:
+ fn = s->data.angle
+ ? blizzard_draw_fn_r_8[s->iformat]
+ : blizzard_draw_fn_8[s->iformat];
+ break;
+ case 15:
+ fn = s->data.angle
+ ? blizzard_draw_fn_r_15[s->iformat]
+ : blizzard_draw_fn_15[s->iformat];
+ break;
+ case 16:
+ fn = s->data.angle
+ ? blizzard_draw_fn_r_16[s->iformat]
+ : blizzard_draw_fn_16[s->iformat];
+ break;
+ case 24:
+ fn = s->data.angle
+ ? blizzard_draw_fn_r_24[s->iformat]
+ : blizzard_draw_fn_24[s->iformat];
+ break;
+ case 32:
+ fn = s->data.angle
+ ? blizzard_draw_fn_r_32[s->iformat]
+ : blizzard_draw_fn_32[s->iformat];
+ break;
+ default:
+ break;
+ }
if (!fn)
return;
if (s->mx[0] > s->data.x)
@@ -181,7 +225,6 @@ static int blizzard_transfer_setup(BlizzardState *s)
return 0;
s->data.angle = s->effect & 3;
- s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
s->data.x = s->ix[0];
s->data.y = s->iy[0];
s->data.dx = s->ix[1] - s->ix[0] + 1;
@@ -941,58 +984,19 @@ static void blizzard_screen_dump(void *opaque, const char *filename) {
ppm_save(filename, s->state->surface);
}
-#define DEPTH 8
-#include "blizzard_template.h"
-#define DEPTH 15
-#include "blizzard_template.h"
-#define DEPTH 16
-#include "blizzard_template.h"
-#define DEPTH 24
-#include "blizzard_template.h"
-#define DEPTH 32
-#include "blizzard_template.h"
-
void *s1d13745_init(qemu_irq gpio_int)
{
BlizzardState *s = (BlizzardState *) qemu_mallocz(sizeof(*s));
s->fb = qemu_malloc(0x180000);
-
+ /* Fill the framebuffer with white color here because the corresponding
+ * code in nseries.c is broken since the DisplayState change in QEMU.
+ * This is supposedly ok since nseries.c is the only user of blizzard.c */
+ memset(s->fb, 0xff, 0x180000);
+
s->state = graphic_console_init(blizzard_update_display,
blizzard_invalidate_display,
blizzard_screen_dump, NULL, s);
-
- switch (ds_get_bits_per_pixel(s->state)) {
- case 0:
- s->line_fn_tab[0] = s->line_fn_tab[1] =
- qemu_mallocz(sizeof(blizzard_fn_t) * 0x10);
- break;
- case 8:
- s->line_fn_tab[0] = blizzard_draw_fn_8;
- s->line_fn_tab[1] = blizzard_draw_fn_r_8;
- break;
- case 15:
- s->line_fn_tab[0] = blizzard_draw_fn_15;
- s->line_fn_tab[1] = blizzard_draw_fn_r_15;
- break;
- case 16:
- s->line_fn_tab[0] = blizzard_draw_fn_16;
- s->line_fn_tab[1] = blizzard_draw_fn_r_16;
- break;
- case 24:
- s->line_fn_tab[0] = blizzard_draw_fn_24;
- s->line_fn_tab[1] = blizzard_draw_fn_r_24;
- break;
- case 32:
- s->line_fn_tab[0] = blizzard_draw_fn_32;
- s->line_fn_tab[1] = blizzard_draw_fn_r_32;
- break;
- default:
- fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
- exit(1);
- }
-
blizzard_reset(s);
-
return s;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 26/48] SD overhaul
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (21 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 25/48] blizzard: fix for non-32bpp host displays Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 27/48] tsc2005 overhaul Riku Voipio
` (21 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
- reset support
- add high capacity mmc support
- sd: improve mmc emulation
- make sd emulation work as mmc emulation as well
- handle SD CMD5 without error messages
- remove couple of unnecessary error messages
- Fix block count for OMAP3 MMC emulation
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/sd.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 334 insertions(+), 56 deletions(-)
diff --git a/hw/sd.c b/hw/sd.c
index cc2839d..3a395e7 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -4,6 +4,7 @@
*
* Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
* Copyright (c) 2007 CodeSourcery
+ * Copyright (c) 2009 Nokia Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -75,6 +76,7 @@ struct SDState {
uint8_t scr[8];
uint8_t cid[16];
uint8_t csd[16];
+ uint8_t ext_csd[512];
uint16_t rca;
uint32_t card_status;
uint8_t sd_status[64];
@@ -89,7 +91,7 @@ struct SDState {
int pwd_len;
int function_group[6];
- int spi;
+ int spi, mmc;
int current_cmd;
int blk_written;
uint64_t data_start;
@@ -101,6 +103,7 @@ struct SDState {
uint8_t *buf;
int enable;
+ int buswidth, highspeed;
};
static void sd_set_status(SDState *sd)
@@ -131,9 +134,9 @@ static void sd_set_status(SDState *sd)
}
static const sd_cmd_type_t sd_cmd_type[64] = {
- sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac,
+ sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_ac, sd_none, sd_ac,
sd_bcr, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac,
- sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_ac, sd_adtc, sd_adtc, sd_none, sd_adtc, sd_none, sd_none, sd_adtc,
sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none,
sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none,
sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none,
@@ -200,8 +203,8 @@ static void sd_set_ocr(SDState *sd)
static void sd_set_scr(SDState *sd)
{
- sd->scr[0] = 0x00; /* SCR Structure */
- sd->scr[1] = 0x2f; /* SD Security Support */
+ sd->scr[0] = 0x00; /* SCR v1.0, SD spec v1.0/1.01 */
+ sd->scr[1] = 0x25; /* erase=0, SD security v1.01, 1bit/4bit bus width */
sd->scr[2] = 0x00;
sd->scr[3] = 0x00;
sd->scr[4] = 0x00;
@@ -212,7 +215,7 @@ static void sd_set_scr(SDState *sd)
#define MID 0xaa
#define OID "XY"
-#define PNM "QEMU!"
+#define PNM "QEMU!!"
#define PRV 0x01
#define MDT_YR 2006
#define MDT_MON 2
@@ -227,14 +230,23 @@ static void sd_set_cid(SDState *sd)
sd->cid[5] = PNM[2];
sd->cid[6] = PNM[3];
sd->cid[7] = PNM[4];
- sd->cid[8] = PRV; /* Fake product revision (PRV) */
+ if (sd->mmc) {
+ sd->cid[8] = PNM[5];
+ } else {
+ sd->cid[8] = PRV; /* Fake product revision (PRV) */
+ }
sd->cid[9] = 0xde; /* Fake serial number (PSN) */
sd->cid[10] = 0xad;
sd->cid[11] = 0xbe;
sd->cid[12] = 0xef;
- sd->cid[13] = 0x00 | /* Manufacture date (MDT) */
- ((MDT_YR - 2000) / 10);
- sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
+ if (sd->mmc) {
+ sd->cid[13] = 0x55;
+ sd->cid[14] = ((MDT_MON) << 4) | (MDT_YR - 1997);
+ } else {
+ sd->cid[13] = 0x00 | /* Manufacture date (MDT) */
+ ((MDT_YR - 2000) / 10);
+ sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
+ }
sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
}
@@ -256,7 +268,12 @@ static void sd_set_csd(SDState *sd, uint64_t size)
uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
if (size <= 0x40000000) { /* Standard Capacity SD */
- sd->csd[0] = 0x00; /* CSD structure */
+ if (sd->mmc) {
+ sd->csd[0] = 0x80 | /* CSD structure: v1.2 */
+ 0x0c; /* MMC v3.x */
+ } else {
+ sd->csd[0] = 0x00; /* CSD structure: v0 */
+ }
sd->csd[1] = 0x26; /* Data read access-time-1 */
sd->csd[2] = 0x00; /* Data read access-time-2 */
sd->csd[3] = 0x5a; /* Max. data transfer rate */
@@ -282,25 +299,52 @@ static void sd_set_csd(SDState *sd, uint64_t size)
sd->csd[14] = 0x00; /* File format group */
sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
} else { /* SDHC */
- size /= 512 * 1024;
- size -= 1;
- sd->csd[0] = 0x40;
+ if (sd->mmc) {
+ sd->csd[0] = 0x90; /* CSD structure v1.2, MMC v4.0/4.1 */
+ } else {
+ sd->csd[0] = 0x40; /* CSD structure v1 */
+ }
sd->csd[1] = 0x0e;
sd->csd[2] = 0x00;
sd->csd[3] = 0x32;
sd->csd[4] = 0x5b;
sd->csd[5] = 0x59;
- sd->csd[6] = 0x00;
- sd->csd[7] = (size >> 16) & 0xff;
- sd->csd[8] = (size >> 8) & 0xff;
- sd->csd[9] = (size & 0xff);
- sd->csd[10] = 0x7f;
+ if (sd->mmc) {
+ sd->csd[6] = 0x03;
+ sd->csd[7] = 0xff;
+ sd->csd[8] = 0xff;
+ sd->csd[9] = 0xff;
+ sd->csd[10] = 0xff;
+ } else {
+ size /= 512 * 1024;
+ size -= 1;
+ sd->csd[6] = 0x00;
+ sd->csd[7] = (size >> 16) & 0xff;
+ sd->csd[8] = (size >> 8) & 0xff;
+ sd->csd[9] = (size & 0xff);
+ sd->csd[10] = 0x7f;
+ }
sd->csd[11] = 0x80;
sd->csd[12] = 0x0a;
sd->csd[13] = 0x40;
sd->csd[14] = 0x00;
sd->csd[15] = 0x00;
- sd->ocr |= 1 << 30; /* High Capacity SD Memort Card */
+ sd->ocr |= 1 << 30; /* High Capacity SD Memory Card */
+ if (sd->mmc) {
+ size /= 512;
+ sd->buswidth = 1; /* 4bit mode */
+ sd->highspeed = 0;
+ memset(sd->ext_csd, 0, 512);
+ sd->ext_csd[183] = sd->buswidth;
+ sd->ext_csd[185] = sd->highspeed;
+ sd->ext_csd[192] = 0x03; /* EXT_CSD v3 */
+ sd->ext_csd[196] = 0x03; /* supports 26MHz and 52MHz */
+ sd->ext_csd[212] = (size & 0xff);
+ sd->ext_csd[213] = (size >> 8) & 0xff;
+ sd->ext_csd[214] = (size >> 16) & 0xff;
+ sd->ext_csd[215] = (size >> 24) & 0xff;
+ sd->ext_csd[217] = 0x00; /* sleep/awake timeout */
+ }
}
}
@@ -382,13 +426,13 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response)
response[3] = (sd->vhs >> 0) & 0xff;
}
-static void sd_reset(SDState *sd, BlockDriverState *bdrv)
+void sd_reset(SDState *sd)
{
uint64_t size;
uint64_t sect;
- if (bdrv) {
- bdrv_get_geometry(bdrv, §);
+ if (sd->bdrv) {
+ bdrv_get_geometry(sd->bdrv, §);
} else {
sect = 0;
}
@@ -397,7 +441,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
size = sect + 1;
sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
-
+
sd->state = sd_idle_state;
sd->rca = 0x0000;
sd_set_ocr(sd);
@@ -407,11 +451,9 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
sd_set_cardstatus(sd);
sd_set_sdstatus(sd);
- sd->bdrv = bdrv;
-
if (sd->wp_groups)
qemu_free(sd->wp_groups);
- sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
+ sd->wp_switch = sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0;
sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
memset(sd->function_group, 0, sizeof(int) * 6);
sd->erase_start = 0;
@@ -426,27 +468,121 @@ static void sd_cardchange(void *opaque)
SDState *sd = opaque;
qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
if (bdrv_is_inserted(sd->bdrv)) {
- sd_reset(sd, sd->bdrv);
+ sd_reset(sd);
qemu_set_irq(sd->readonly_cb, sd->wp_switch);
}
}
+static void sd_save_state(QEMUFile *f, void *opaque)
+{
+ struct SDState *s = (struct SDState *)opaque;
+ int i;
+ uint32_t wpgc = (s->size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+ char *filename;
+
+ filename = qemu_mallocz(1024);
+ bdrv_get_backing_filename(s->bdrv, filename, 1024);
+ qemu_put_buffer(f, (uint8_t *)filename, 1024);
+ free(filename);
+
+ qemu_put_sbe32(f, s->mode);
+ qemu_put_sbe32(f, s->state);
+ qemu_put_be32(f, s->ocr);
+ qemu_put_buffer(f, s->scr, sizeof(s->scr));
+ qemu_put_buffer(f, s->cid, sizeof(s->cid));
+ qemu_put_buffer(f, s->csd, sizeof(s->csd));
+ qemu_put_be16(f, s->rca);
+ qemu_put_be32(f, s->card_status);
+ qemu_put_buffer(f, s->sd_status, sizeof(s->sd_status));
+ qemu_put_be32(f, s->vhs);
+ for (i = 0; i < wpgc; i++)
+ qemu_put_sbe32(f, s->wp_groups[i]);
+ qemu_put_sbe32(f, s->blk_len);
+ qemu_put_be32(f, s->erase_start);
+ qemu_put_be32(f, s->erase_end);
+ qemu_put_buffer(f, s->pwd, sizeof(s->pwd));
+ qemu_put_sbe32(f, s->pwd_len);
+ for (i = 0; i < 6; i++)
+ qemu_put_sbe32(f, s->function_group[i]);
+ qemu_put_sbe32(f, s->current_cmd);
+ qemu_put_sbe32(f, s->blk_written);
+ qemu_put_be32(f, s->data_start);
+ qemu_put_be32(f, s->data_offset);
+ qemu_put_buffer(f, s->data, sizeof(s->data));
+ qemu_put_buffer(f, s->buf, 512);
+ qemu_put_sbe32(f, s->enable);
+}
+
+static int sd_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct SDState *s = (struct SDState *)opaque;
+ int i;
+ uint32_t wpgc = (s->size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+ char *filename1, *filename2;
+ int result = 0;
+
+ if (version_id)
+ return -EINVAL;
+
+ filename1 = qemu_mallocz(1024);
+ filename2 = qemu_mallocz(1024);
+ bdrv_get_backing_filename(s->bdrv, filename1, 1024);
+ qemu_get_buffer(f, (uint8_t *)filename2, 1024);
+ if (!strcmp(filename1, filename2)) {
+ s->mode = qemu_get_sbe32(f);
+ s->state = qemu_get_sbe32(f);
+ s->ocr = qemu_get_be32(f);
+ qemu_get_buffer(f, s->scr, sizeof(s->scr));
+ qemu_get_buffer(f, s->cid, sizeof(s->cid));
+ qemu_get_buffer(f, s->csd, sizeof(s->csd));
+ s->rca = qemu_get_be16(f);
+ s->card_status = qemu_get_be32(f);
+ qemu_get_buffer(f, s->sd_status, sizeof(s->sd_status));
+ s->vhs = qemu_get_be32(f);
+ for (i = 0; i < wpgc; i++)
+ s->wp_groups[i] = qemu_get_sbe32(f);
+ s->blk_len = qemu_get_sbe32(f);
+ s->erase_start = qemu_get_be32(f);
+ s->erase_end = qemu_get_be32(f);
+ qemu_get_buffer(f, s->pwd, sizeof(s->pwd));
+ s->pwd_len = qemu_get_sbe32(f);
+ for (i = 0; i < 6; i++)
+ s->function_group[i] = qemu_get_sbe32(f);
+ s->current_cmd = qemu_get_sbe32(f);
+ s->blk_written = qemu_get_sbe32(f);
+ s->data_start = qemu_get_be32(f);
+ s->data_offset = qemu_get_be32(f);
+ qemu_get_buffer(f, s->data, sizeof(s->data));
+ qemu_get_buffer(f, s->buf, 512);
+ s->enable = qemu_get_sbe32(f);
+ } else
+ result = -EINVAL;
+ free(filename2);
+ free(filename1);
+ return result;
+}
+
/* We do not model the chip select pin, so allow the board to select
whether card should be in SSI or MMC/SD mode. It is also up to the
board to ensure that ssi transfers only occur when the chip select
is asserted. */
-SDState *sd_init(BlockDriverState *bs, int is_spi)
+SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc)
{
SDState *sd;
+ static int instance_number = 1;
sd = (SDState *) qemu_mallocz(sizeof(SDState));
sd->buf = qemu_memalign(512, 512);
sd->spi = is_spi;
+ sd->mmc = is_mmc;
sd->enable = 1;
- sd_reset(sd, bs);
+ sd->bdrv = bs;
+ sd_reset(sd);
if (sd->bdrv) {
bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
}
+ register_savevm("sd", instance_number++, 0,
+ sd_save_state, sd_load_state, sd);
return sd;
}
@@ -524,6 +660,46 @@ static void sd_function_switch(SDState *sd, uint32_t arg)
sd->data[66] = crc & 0xff;
}
+static void mmc_function_switch(SDState *sd, uint32_t arg)
+{
+ enum {
+ cmd_set = 0,
+ set_bits,
+ clear_bits,
+ write_byte,
+
+ unknown
+ } mode = (arg >> 24);
+ if (mode >= unknown) {
+ fprintf(stderr, "%s: unknown mode 0x%02x\n", __FUNCTION__, mode);
+ } else {
+ if (mode == cmd_set) {
+ fprintf(stderr, "%s: command set change not implemented!\n",
+ __FUNCTION__);
+ } else {
+ uint8_t index = (arg >> 16) & 0xff;
+ /* ignore writes to read-only fields */
+ if (index != 192 && index != 196 &&
+ (index < 212 || index > 215)) {
+ uint8_t value = (arg >> 8) & 0xff;
+ switch (mode) {
+ case set_bits:
+ sd->ext_csd[index] |= value;
+ break;
+ case clear_bits:
+ sd->ext_csd[index] &= ~value;
+ break;
+ case write_byte:
+ sd->ext_csd[index] = value;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
static inline int sd_wp_addr(SDState *sd, uint32_t addr)
{
return sd->wp_groups[addr >>
@@ -617,15 +793,21 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
default:
sd->state = sd_idle_state;
- sd_reset(sd, sd->bdrv);
+ sd_reset(sd);
return sd->spi ? sd_r1 : sd_r0;
}
break;
case 1: /* CMD1: SEND_OP_CMD */
+ if (sd->mmc) {
+ if (sd->state == sd_idle_state) {
+ sd->state = sd_ready_state;
+ return sd_r3;
+ }
+ break;
+ }
if (!sd->spi)
goto bad_cmd;
-
sd->state = sd_transfer_state;
return sd_r1;
@@ -647,8 +829,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
goto bad_cmd;
switch (sd->state) {
case sd_identification_state:
- case sd_standby_state:
sd->state = sd_standby_state;
+ case sd_standby_state:
+ if (sd->mmc) {
+ sd->rca = req.arg >> 16;
+ return sd_r1;
+ }
sd_set_rca(sd);
return sd_r6;
@@ -662,14 +848,25 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
goto bad_cmd;
switch (sd->state) {
case sd_standby_state:
- break;
+ return sd_r0;
default:
break;
}
break;
- case 5: /* CMD5: reserved for SDIO cards */
+ case 5: /* CMD5: reserved for SDIO cards / SLEEP_AWAKE (MMC) */
+ if (sd->mmc) {
+ if (sd->rca != rca) {
+ return sd_r0;
+ }
+ if (req.arg & (1 << 15)) {
+ sd->state = sd_transfer_state;
+ } else {
+ sd->state = sd_standby_state;
+ }
+ return sd_r1b;
+ }
sd->card_status |= ILLEGAL_COMMAND;
return sd_r0;
@@ -678,11 +875,16 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
goto bad_cmd;
switch (sd->mode) {
case sd_data_transfer_mode:
- sd_function_switch(sd, req.arg);
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return sd_r1;
+ if (sd->mmc) {
+ mmc_function_switch(sd, req.arg);
+ return sd_r1b;
+ } else {
+ sd_function_switch(sd, req.arg);
+ sd->state = sd_sendingdata_state;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
+ }
default:
break;
@@ -727,22 +929,30 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
break;
- case 8: /* CMD8: SEND_IF_COND */
- /* Physical Layer Specification Version 2.00 command */
- switch (sd->state) {
- case sd_idle_state:
- sd->vhs = 0;
+ case 8: /* CMD8: SEND_IF_COND / SEND_EXT_CSD (MMC) */
+ if (sd->mmc) {
+ sd->state = sd_sendingdata_state;
+ memcpy(sd->data, sd->ext_csd, 512);
+ sd->data_start = addr;
+ sd->data_offset = 0;
+ return sd_r1;
+ } else {
+ /* Physical Layer Specification Version 2.00 command */
+ switch (sd->state) {
+ case sd_idle_state:
+ sd->vhs = 0;
- /* No response if not exactly one VHS bit is set. */
- if (!(req.arg >> 8) || (req.arg >> ffs(req.arg & ~0xff)))
- return sd->spi ? sd_r7 : sd_r0;
+ /* No response if not exactly one VHS bit is set. */
+ if (!(req.arg >> 8) || (req.arg >> ffs(req.arg & ~0xff)))
+ return sd->spi ? sd_r7 : sd_r0;
- /* Accept. */
- sd->vhs = req.arg;
- return sd_r7;
+ /* Accept. */
+ sd->vhs = req.arg;
+ return sd_r7;
- default:
- break;
+ default:
+ break;
+ }
}
break;
@@ -901,8 +1111,33 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
break;
}
break;
+
+ /* Block write commands (Class 3) */
+ case 20: /* CMD20: WRITE_DAT_UNTIL_STOP */
+ if (sd->mmc) {
+ if (sd->state == sd_transfer_state) {
+ sd->state = sd_sendingdata_state;
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
+
+ if (sd->data_start + sd->blk_len > sd->size) {
+ sd->card_status |= ADDRESS_ERROR;
+ }
+ return sd_r0;
+ }
+ break;
+ }
+ goto bad_cmd;
/* Block write commands (Class 4) */
+ case 23: /* CMD23: SET_BLOCK_COUNT */
+ if (sd->mmc) {
+ sd->card_status |= ILLEGAL_COMMAND;
+ fprintf(stderr, "%s: CMD23 not implemented\n", __FUNCTION__);
+ return sd_r0;
+ }
+ goto bad_cmd;
+
case 24: /* CMD24: WRITE_SINGLE_BLOCK */
if (sd->spi)
goto unimplemented_cmd;
@@ -1042,6 +1277,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
/* Erase commands (Class 5) */
case 32: /* CMD32: ERASE_WR_BLK_START */
+ case 35: /* CMD35: ERASE_GROUP_START */
+ if ((req.cmd == 35 && !sd->mmc) ||
+ (req.cmd == 32 && sd->mmc)) {
+ goto bad_cmd;
+ }
switch (sd->state) {
case sd_transfer_state:
sd->erase_start = req.arg;
@@ -1053,6 +1293,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
break;
case 33: /* CMD33: ERASE_WR_BLK_END */
+ case 36: /* CMD36: ERASE_GROUP_END */
+ if ((req.cmd == 36 && !sd->mmc) ||
+ (req.cmd == 33 && sd->mmc)) {
+ goto bad_cmd;
+ }
switch (sd->state) {
case sd_transfer_state:
sd->erase_end = req.arg;
@@ -1081,6 +1326,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
break;
}
break;
+
+ /* Class 9 */
+ case 39: /* CMD39: FAST_IO */
+ case 40: /* CMD40: GO_IRQ_STATE */
+ if (sd->mmc) {
+ sd->card_status |= ILLEGAL_COMMAND;
+ fprintf(stderr, "%s: CMD%d not implemented\n",
+ __FUNCTION__, req.cmd);
+ return sd_r0;
+ }
+ goto bad_cmd;
/* Lock card commands (Class 7) */
case 42: /* CMD42: LOCK_UNLOCK */
@@ -1336,8 +1592,8 @@ int sd_do_command(SDState *sd, SDRequest *req,
int i;
DPRINTF("Response:");
for (i = 0; i < rsplen; i++)
- printf(" %02x", response[i]);
- printf(" state %d\n", sd->state);
+ fprintf(stderr, " %02x", response[i]);
+ fprintf(stderr, " state %d\n", sd->state);
} else {
DPRINTF("No response %d\n", sd->state);
}
@@ -1434,6 +1690,11 @@ void sd_write_data(SDState *sd, uint8_t value)
}
break;
+ case 20: /* CMD20: WRITE_DAT_UNTIL_STOP */
+ if (!sd->mmc) {
+ goto unknown_command;
+ }
+ /* fall through */
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
sd->data[sd->data_offset ++] = value;
if (sd->data_offset >= sd->blk_len) {
@@ -1521,6 +1782,7 @@ void sd_write_data(SDState *sd, uint8_t value)
break;
default:
+ unknown_command:
fprintf(stderr, "sd_write_data: unknown command\n");
break;
}
@@ -1536,7 +1798,7 @@ uint8_t sd_read_data(SDState *sd)
return 0x00;
if (sd->state != sd_sendingdata_state) {
- fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
+ fprintf(stderr, "sd_read_data: not in Sending-Data state (state=%d)\n", sd->state);
return 0x00;
}
@@ -1553,6 +1815,16 @@ uint8_t sd_read_data(SDState *sd)
sd->state = sd_transfer_state;
break;
+ case 8: /* CMD8: SEND_EXT_CSD (MMC only) */
+ if (sd->mmc) {
+ ret = sd->data[sd->data_offset++];
+ if (sd->data_offset >= 512) {
+ sd->state = sd_transfer_state;
+ }
+ } else {
+ goto unknown_command;
+ }
+ break;
case 9: /* CMD9: SEND_CSD */
case 10: /* CMD10: SEND_CID */
ret = sd->data[sd->data_offset ++];
@@ -1638,6 +1910,7 @@ uint8_t sd_read_data(SDState *sd)
break;
default:
+ unknown_command:
fprintf(stderr, "sd_read_data: unknown command\n");
return 0x00;
}
@@ -1654,3 +1927,8 @@ void sd_enable(SDState *sd, int enable)
{
sd->enable = enable;
}
+
+int sd_is_mmc(SDState *sd)
+{
+ return sd->mmc;
+}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 27/48] tsc2005 overhaul
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (22 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 26/48] SD overhaul Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 28/48] prepare smc driver support for omap Riku Voipio
` (20 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/tsc2005.c | 173 ++++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 120 insertions(+), 53 deletions(-)
diff --git a/hw/tsc2005.c b/hw/tsc2005.c
index b75cc86..da39979 100644
--- a/hw/tsc2005.c
+++ b/hw/tsc2005.c
@@ -2,7 +2,7 @@
* TI TSC2005 emulator.
*
* Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) 2009-2010 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,6 +23,15 @@
#include "console.h"
#include "devices.h"
+//#define TSC2005_DEBUG
+
+#ifdef TSC2005_DEBUG
+#define TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", \
+ __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10)))
typedef struct {
@@ -54,6 +63,7 @@ typedef struct {
uint16_t aux_thr[2];
int tr[8];
+ int z1_cons, z2_cons;
} TSC2005State;
enum {
@@ -98,10 +108,15 @@ static const uint16_t mode_regs[16] = {
((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
#define Y_TRANSFORM(s) \
((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
+/*
#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
+ (((s)->z1_cons - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+ (((s)->z2_cons + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+ */
+/* these simpler forms work much better */
+#define Z1_TRANSFORM(s) (((s)->z1_cons) << 4)
+#define Z2_TRANSFORM(s) (((s)->z2_cons) << 4)
#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */
#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */
@@ -114,33 +129,46 @@ static uint16_t tsc2005_read(TSC2005State *s, int reg)
switch (reg) {
case 0x0: /* X */
s->dav &= ~mode_regs[TSC_MODE_X];
+ TRACE("X = %d", TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
+ (s->noise & 3));
return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
(s->noise & 3);
case 0x1: /* Y */
s->dav &= ~mode_regs[TSC_MODE_Y];
s->noise ++;
+ TRACE("Y = %d", TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
+ (s->noise & 3));
return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
(s->noise & 3);
case 0x2: /* Z1 */
s->dav &= 0xdfff;
+ TRACE("Z1 = %d", TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
+ (s->noise & 3));
return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
(s->noise & 3);
case 0x3: /* Z2 */
s->dav &= 0xefff;
+ TRACE("Z2 = %d", TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
+ (s->noise & 3));
return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
(s->noise & 3);
case 0x4: /* AUX */
s->dav &= ~mode_regs[TSC_MODE_AUX];
+ TRACE("AUX = %d", TSC_CUT_RESOLUTION(AUX_VAL, s->precision));
return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
case 0x5: /* TEMP1 */
s->dav &= ~mode_regs[TSC_MODE_TEMP1];
+ TRACE("TEMP1 = %d", TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
+ (s->noise & 5));
return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
(s->noise & 5);
case 0x6: /* TEMP2 */
s->dav &= 0xdfff;
s->dav &= ~mode_regs[TSC_MODE_TEMP2];
+ TRACE("TEMP2 = %d", TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
+ (s->noise & 3));
return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
(s->noise & 3);
@@ -149,31 +177,43 @@ static uint16_t tsc2005_read(TSC2005State *s, int reg)
s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
mode_regs[TSC_MODE_TS_TEST]);
s->reset = 1;
+ TRACE("STATUS = 0x%04x", ret);
return ret;
case 0x8: /* AUX high treshold */
+ TRACE("AUX high threshold = 0x%04x", s->aux_thr[1]);
return s->aux_thr[1];
case 0x9: /* AUX low treshold */
+ TRACE("AUX low threshold = 0x%04x", s->aux_thr[0]);
return s->aux_thr[0];
case 0xa: /* TEMP high treshold */
+ TRACE("TEMP high threshold = 0x%04x", s->temp_thr[1]);
return s->temp_thr[1];
case 0xb: /* TEMP low treshold */
+ TRACE("TEMP low threshold = 0x%04x", s->temp_thr[0]);
return s->temp_thr[0];
case 0xc: /* CFR0 */
+ TRACE("CFR0 = 0x%04x", (s->pressure << 15) | ((!s->busy) << 14) |
+ (s->nextprecision << 13) | s->timing[0]);
return (s->pressure << 15) | ((!s->busy) << 14) |
(s->nextprecision << 13) | s->timing[0];
case 0xd: /* CFR1 */
+ TRACE("CFR1 = 0x%04x", s->timing[1]);
return s->timing[1];
case 0xe: /* CFR2 */
+ TRACE("CFR2 = 0x%04x", (s->pin_func << 14) | s->filter);
return (s->pin_func << 14) | s->filter;
case 0xf: /* Function select status */
+ TRACE("function select status = 0x%04x",
+ s->function >= 0 ? 1 << s->function : 0);
return s->function >= 0 ? 1 << s->function : 0;
}
/* Never gets here */
+ TRACE("unknown register = 0xffff");
return 0xffff;
}
@@ -181,46 +221,52 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
{
switch (reg) {
case 0x8: /* AUX high treshold */
+ TRACE("AUX high threshold = 0x%04x", data);
s->aux_thr[1] = data;
break;
case 0x9: /* AUX low treshold */
+ TRACE("AUX low threshold = 0x%04x", data);
s->aux_thr[0] = data;
break;
case 0xa: /* TEMP high treshold */
+ TRACE("TEMP high threshold = 0x%04x", data);
s->temp_thr[1] = data;
break;
case 0xb: /* TEMP low treshold */
+ TRACE("TEMP low threshold = 0x%04x", data);
s->temp_thr[0] = data;
break;
case 0xc: /* CFR0 */
+ TRACE("CFR0 = 0x%04x", data);
s->host_mode = data >> 15;
if (s->enabled != !(data & 0x4000)) {
s->enabled = !(data & 0x4000);
- fprintf(stderr, "%s: touchscreen sense %sabled\n",
- __FUNCTION__, s->enabled ? "en" : "dis");
- if (s->busy && !s->enabled)
+ TRACE("touchscreen sense %sabled", s->enabled ? "en" : "dis");
+ if (s->busy && !s->enabled) {
qemu_del_timer(s->timer);
+ }
s->busy &= s->enabled;
}
s->nextprecision = (data >> 13) & 1;
s->timing[0] = data & 0x1fff;
- if ((s->timing[0] >> 11) == 3)
- fprintf(stderr, "%s: illegal conversion clock setting\n",
- __FUNCTION__);
+ if ((s->timing[0] >> 11) == 3) {
+ TRACE("illegal conversion clock setting");
+ }
break;
case 0xd: /* CFR1 */
+ TRACE("CFR1 = 0x%04x", data);
s->timing[1] = data & 0xf07;
break;
case 0xe: /* CFR2 */
+ TRACE("CFR2 = 0x%04x", data);
s->pin_func = (data >> 14) & 3;
s->filter = data & 0x3fff;
break;
default:
- fprintf(stderr, "%s: write into read-only register %x\n",
- __FUNCTION__, reg);
+ TRACE("write into read-only register 0x%x, value 0x%04x", reg, data);
}
}
@@ -228,29 +274,16 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
static void tsc2005_pin_update(TSC2005State *s)
{
int64_t expires;
- int pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = !s->pressure && !!s->dav;
- break;
- case 1:
- case 3:
- default:
- pin_state = !s->dav;
- break;
- case 2:
- pin_state = !s->pressure;
- }
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, s->irq);
- }
-
+ TRACE("nextf=%d, press=%d, ena=%d, busy=%d, dav=0x%04x, irq=%d",
+ s->nextfunction, s->pressure, s->enabled, s->busy, s->dav, s->irq);
switch (s->nextfunction) {
case TSC_MODE_XYZ_SCAN:
case TSC_MODE_XY_SCAN:
+ if (!s->pin_func && !s->dav) {
+ TRACE("all values read, lowering irq");
+ s->irq = 0;
+ qemu_set_irq(s->pint, s->irq);
+ }
if (!s->host_mode && s->dav)
s->enabled = 0;
if (!s->pressure)
@@ -283,15 +316,14 @@ static void tsc2005_pin_update(TSC2005State *s)
return;
}
- if (!s->enabled || s->busy)
- return;
-
- s->busy = 1;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- s->pdst = !s->pnd0; /* Synchronised on internal clock */
- expires = qemu_get_clock(vm_clock) + (get_ticks_per_sec() >> 7);
- qemu_mod_timer(s->timer, expires);
+ if (s->enabled && !s->busy) {
+ s->busy = 1;
+ s->precision = s->nextprecision;
+ s->function = s->nextfunction;
+ s->pdst = !s->pnd0; /* Synchronised on internal clock */
+ expires = qemu_get_clock(vm_clock) + (get_ticks_per_sec() >> 7);
+ qemu_mod_timer(s->timer, expires);
+ }
}
static void tsc2005_reset(TSC2005State *s)
@@ -322,20 +354,20 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
{
TSC2005State *s = opaque;
uint32_t ret = 0;
-
+ TRACE("value = 0x%08x, state=%d", value, s->state + 1);
switch (s->state ++) {
case 0:
if (value & 0x80) {
/* Command */
- if (value & (1 << 1))
+ if (value & (1 << 1)) {
tsc2005_reset(s);
- else {
+ } else {
s->nextfunction = (value >> 3) & 0xf;
s->nextprecision = (value >> 2) & 1;
if (s->enabled != !(value & 1)) {
s->enabled = !(value & 1);
- fprintf(stderr, "%s: touchscreen sense %sabled\n",
- __FUNCTION__, s->enabled ? "en" : "dis");
+ TRACE("touchscreen sense %sabled",
+ s->enabled ? "en" : "dis");
if (s->busy && !s->enabled)
qemu_del_timer(s->timer);
s->busy &= s->enabled;
@@ -386,7 +418,7 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
{
uint32_t ret = 0;
-
+ TRACE("value=0x%08x, len=%d", value, len);
len &= ~7;
while (len > 0) {
len -= 8;
@@ -398,17 +430,44 @@ uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
static void tsc2005_timer_tick(void *opaque)
{
+ int pin_state;
TSC2005State *s = opaque;
/* Timer ticked -- a set of conversions has been finished. */
- if (!s->busy)
+ if (!s->busy) {
+ TRACE("not busy -> exit");
return;
+ }
- s->busy = 0;
- s->dav |= mode_regs[s->function];
- s->function = -1;
- tsc2005_pin_update(s);
+ switch (s->pin_func) {
+ case 0:
+ pin_state = s->pressure || !s->dav;
+ break;
+ case 1:
+ case 3:
+ default:
+ pin_state = !s->dav;
+ break;
+ case 2:
+ pin_state = s->pressure;
+ }
+ s->busy = 0;
+ if (!s->dav) {
+ TRACE("report new conversions ready");
+ s->dav |= mode_regs[s->function];
+ }
+ TRACE("pin_func=%d, pin_state=%d, pressure=%d, irq=%d, dav=0x%04x",
+ s->pin_func, pin_state, s->pressure, s->irq, s->dav);
+ s->function = -1;
+ tsc2005_pin_update(s);
+
+ if (pin_state != s->irq) {
+ TRACE("changing IRQ state to %d", pin_state);
+ s->irq = pin_state;
+ qemu_set_irq(s->pint, s->irq);
+ }
+ TRACE("done");
}
static void tsc2005_touchscreen_event(void *opaque,
@@ -428,8 +487,9 @@ static void tsc2005_touchscreen_event(void *opaque,
* signaling TS events immediately, but for now we simulate
* the first conversion delay for sake of correctness.
*/
- if (p != s->pressure)
+ if (p != s->pressure) {
tsc2005_pin_update(s);
+ }
}
static void tsc2005_save(QEMUFile *f, void *opaque)
@@ -541,6 +601,9 @@ void *tsc2005_init(qemu_irq pintdav)
s->tr[5] = 0;
s->tr[6] = 1;
s->tr[7] = 0;
+
+ s->z1_cons = 400;
+ s->z2_cons = 4000;
tsc2005_reset(s);
@@ -558,7 +621,8 @@ void *tsc2005_init(qemu_irq pintdav)
* from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration.
*/
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info,
+ int z1_cons, int z2_cons)
{
TSC2005State *s = (TSC2005State *) opaque;
@@ -590,4 +654,7 @@ void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
s->tr[4] >>= 11;
s->tr[5] >>= 11;
s->tr[7] <<= 4;
+
+ s->z1_cons = z1_cons;
+ s->z2_cons = z2_cons;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 28/48] prepare smc driver support for omap
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (23 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 27/48] tsc2005 overhaul Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 29/48] Add triton2 (twl4030) driver Riku Voipio
` (19 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 2255 bytes --]
From: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/devices.h | 5 ++++-
hw/smc91c111.c | 22 ++++++++++++++++++++++
2 files changed, 26 insertions(+), 1 deletions(-)
diff --git a/hw/devices.h b/hw/devices.h
index e9e8ec7..b4c10c5 100644
--- a/hw/devices.h
+++ b/hw/devices.h
@@ -5,6 +5,8 @@
/* smc91c111.c */
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+void *smc91c111_init_lite(NICInfo *, qemu_irq);
+int smc91c111_iomemtype(void *opaque);
/* lan9118.c */
void lan9118_init(NICInfo *, uint32_t, qemu_irq);
@@ -21,7 +23,8 @@ void tsc210x_key_event(uWireSlave *chip, int key, int down);
/* tsc2005.c */
void *tsc2005_init(qemu_irq pintdav);
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info,
+ int z1_cons, int z2_cons);
/* stellaris_input.c */
void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index c1a88c9..5d81d95 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -717,6 +717,7 @@ static int smc91c111_init1(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
+ qemu_register_reset((void *)smc91c111_reset, s);
smc91c111_reset(s);
s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
@@ -757,4 +758,25 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
sysbus_connect_irq(s, 0, irq);
}
+void *smc91c111_init_lite(NICInfo *nd, qemu_irq irq)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ qemu_check_nic_model(nd, "smc91c111");
+ dev = qdev_create(NULL, "smc91c111");
+ qdev_set_nic_properties(dev, nd);
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ //sysbus_mmio_map(s, 0, base);
+ sysbus_connect_irq(s, 0, irq);
+ return s;
+}
+
+int smc91c111_iomemtype(void *opaque)
+{
+ SysBusDevice *s = (SysBusDevice *)opaque;
+ return (FROM_SYSBUS(smc91c111_state, s))->mmio_index;
+}
+
device_init(smc91c111_register_devices)
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 29/48] Add triton2 (twl4030) driver
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (24 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 28/48] prepare smc driver support for omap Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 30/48] savevm and reset support for soc_dma Riku Voipio
` (18 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
The swiss knife companion chip for omap3
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/i2c.h | 10 +
hw/twl4030.c | 1469 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1479 insertions(+), 0 deletions(-)
create mode 100644 hw/twl4030.c
diff --git a/hw/i2c.h b/hw/i2c.h
index 83fd917..29d9f9c 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -79,4 +79,14 @@ void tmp105_set(i2c_slave *i2c, int temp);
/* lm832x.c */
void lm832x_key_event(i2c_slave *i2c, int key, int state);
+/* twl4030.c */
+typedef struct {
+ int code;
+ int column;
+ int row;
+} TWL4030KeyMap;
+void *twl4030_init(i2c_bus *gp_bus, qemu_irq irq1, qemu_irq irq2,
+ const TWL4030KeyMap *keymap);
+void twl4030_set_powerbutton_state(void *opaque, int pressed);
+
#endif
diff --git a/hw/twl4030.c b/hw/twl4030.c
new file mode 100644
index 0000000..0f2baab
--- /dev/null
+++ b/hw/twl4030.c
@@ -0,0 +1,1469 @@
+/*
+ * TI TWL4030 emulation
+ *
+ * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Register implementation based on TPS65950 ES1.0 specification.
+ *
+ * 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 or
+ * (at your option) version 3 of the License.
+ *
+ * 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 "hw.h"
+#include "qemu-timer.h"
+#include "i2c.h"
+#include "sysemu.h"
+#include "console.h"
+#include "cpu-all.h"
+
+//#define DEBUG_GENERAL
+//#define DEBUG_RTC
+
+#define DEBUG_TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", \
+ __FUNCTION__, __LINE__, ##__VA_ARGS__)
+
+#ifdef DEBUG_GENERAL
+#define TRACE(...) DEBUG_TRACE(__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+#ifdef DEBUG_RTC
+#define TRACE_RTC(...) DEBUG_TRACE(__VA_ARGS__)
+#else
+#define TRACE_RTC(...)
+#endif
+
+typedef struct TWL4030State TWL4030State;
+typedef struct TWL4030NodeState TWL4030NodeState;
+
+typedef uint8_t (*twl4030_read_func)(TWL4030NodeState *s,
+ uint8_t addr);
+typedef void (*twl4030_write_func)(TWL4030NodeState *s,
+ uint8_t addr, uint8_t value);
+
+struct TWL4030NodeState {
+ i2c_slave i2c;
+ int firstbyte;
+ uint8_t reg;
+
+ twl4030_read_func read_func;
+ twl4030_write_func write_func;
+ TWL4030State *twl4030;
+
+ uint8 reg_data[256];
+};
+
+struct TWL4030State {
+ qemu_irq irq1;
+ qemu_irq irq2;
+ const TWL4030KeyMap *keymap;
+ int extended_key;
+
+ int key_cfg;
+ int key_tst;
+
+ TWL4030NodeState *i2c[4];
+
+ uint8_t seq_mem[64][4]; /* power-management sequencing memory */
+};
+
+static const uint8_t addr_48_reset_values[256] = {
+ 0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */
+ 0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */
+ 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+ 0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */
+ 0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */
+ 0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */
+ 0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
+ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 /* 0xf8...0xff */
+};
+
+static const uint8_t addr_49_reset_values[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+ 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */
+ 0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */
+ 0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
+ 0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+ 0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */
+};
+
+static const uint8_t addr_4a_reset_values[256] = {
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
+ 0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */
+ 0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */
+ 0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */
+ 0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */
+ 0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */
+ 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xf8...0xff */
+};
+
+static const uint8_t addr_4b_reset_values[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, /* 0x28...0x2f */
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */
+ 0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */
+ 0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */
+ 0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */
+ 0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */
+ 0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */
+ 0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */
+ 0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+ 0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */
+ 0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */
+ 0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */
+ 0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xf8...0xff */
+};
+
+static void twl4030_interrupt_update(TWL4030State *s)
+{
+ uint8_t x = 0;
+ /* TODO: USB, MADC, BCI and GPIO interrupts */
+ if (s->irq1) {
+ /* KEYPAD */
+ if (((s->i2c[2]->reg_data[0xda] & 0x10) && /* SIR_EN */
+ s->i2c[2]->reg_data[0xe7]) || /* KEYP_SIR */
+ (s->i2c[2]->reg_data[0xe3] & /* KEYP_ISR1 */
+ ~s->i2c[2]->reg_data[0xe4])) /* KEYP_IMR1 */
+ x |= 0x02; /* PIH_ISR1 */
+ /* PM */
+ if ((s->i2c[3]->reg_data[0x2e] & /* PWR_ISR1 */
+ ~s->i2c[3]->reg_data[0x2f])) /* PWR_IMR1 */
+ x |= 0x20; /* PIH_ISR5 */
+
+ s->i2c[1]->reg_data[0x81] = x; /* PIH_ISR_P1 */
+ qemu_set_irq(s->irq1, x);
+ }
+ if (s->irq2) {
+ /* KEYPAD */
+ if (((s->i2c[2]->reg_data[0xda] & 0x10) && /* SIR_EN */
+ s->i2c[2]->reg_data[0xe7]) || /* KEYP_SIR */
+ (s->i2c[2]->reg_data[0xe5] & /* KEYP_ISR2 */
+ ~s->i2c[2]->reg_data[0xe6])) /* KEYP_IMR2 */
+ x |= 0x02; /* PIH_ISR1 */
+ /* PM */
+ if ((s->i2c[3]->reg_data[0x30] & /* PWR_ISR2 */
+ ~s->i2c[3]->reg_data[0x31])) /* PWR_IMR2 */
+ x |= 0x20; /* PIH_ISR5 */
+
+ s->i2c[1]->reg_data[0x82] = x; /* PIH_ISR_P2 */
+ qemu_set_irq(s->irq2, x);
+ }
+}
+
+static uint8_t twl4030_48_read(TWL4030NodeState *s, uint8_t addr)
+{
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ case 0x00: /* VENDOR_ID_LO */
+ case 0x01: /* VENDOR_ID_HI */
+ case 0x02: /* PRODUCT_ID_LO */
+ case 0x03: /* PRODUCT_ID_HI */
+ return s->reg_data[addr];
+ case 0x04: /* FUNC_CTRL */
+ case 0x05: /* FUNC_CRTL_SET */
+ case 0x06: /* FUNC_CRTL_CLR */
+ return s->reg_data[0x04];
+ case 0x07: /* IFC_CTRL */
+ case 0x08: /* IFC_CRTL_SET */
+ case 0x09: /* IFC_CRTL_CLR */
+ return s->reg_data[0x07];
+ case 0xac: /* POWER_CTRL */
+ case 0xad: /* POWER_SET */
+ case 0xae: /* POWER_CLR */
+ return s->reg_data[0xac];
+ case 0xfd: /* PHY_PWR_CTRL */
+ case 0xfe: /* PHY_CLK_CTRL */
+ return s->reg_data[addr];
+ case 0xff: /* PHY_CLK_CTRL_STS */
+ if (s->reg_data[0xfd] & 1) /* PHY_PWR_CTRL */
+ return 0;
+ if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */
+ return 1;
+ return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void twl4030_48_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
+{
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ case 0x04: /* FUNC_CTRL */
+ s->reg_data[0x04] = value & 0x7f;
+ break;
+ case 0x05: /* FUNC_CRTL_SET */
+ s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x7f;
+ break;
+ case 0x06: /* FUNC_CTRL_CLEAR */
+ s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x7f;
+ break;
+ case 0x07: /* IFC_CTRL */
+ s->reg_data[0x07] = value & 0x9e;
+ break;
+ case 0x08: /* IFC_CRTL_SET */
+ s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x9e;
+ break;
+ case 0x09: /* IFC_CRTL_CLEAR */
+ s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x9e;
+ break;
+ case 0xa1: /* CARKIT_SM_CTRL */
+ s->reg_data[0xa1] = value & 0x3f;
+ break;
+ case 0xa2: /* CARKIT_SM_CTRL_SET */
+ s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f;
+ break;
+ case 0xa3: /* CARKIT_SM_CTRL_CLR */
+ s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f;
+ break;
+ case 0xac: /* POWER_CTRL */
+ s->reg_data[0xac] = value & 0x20;
+ break;
+ case 0xad: /* POWER_SET */
+ s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
+ break;
+ case 0xae: /* POWER_CLEAR */
+ s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
+ break;
+ case 0xbb: /* CARKIT_ANA_CTRL */
+ s->reg_data[0xbb] = value;
+ break;
+ case 0xbc: /* CARKIT_ANA_CTRL_SET */
+ s->reg_data[0xbb] |= value;
+ break;
+ case 0xbd: /* CARKIT_ANA_CTRL_CLR */
+ s->reg_data[0xbb] &= ~value;
+ break;
+ case 0xfd: /* PHY_PWR_CTRL */
+ s->reg_data[addr] = value & 0x1;
+ break;
+ case 0xfe: /* PHY_CLK_CTRL */
+ s->reg_data[addr] = value & 0x7;
+ break;
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+}
+
+static uint8_t twl4030_49_read(TWL4030NodeState *s, uint8_t addr)
+{
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ /* AUDIO_VOICE region */
+ case 0x01 ... 0x49:
+ return s->reg_data[addr];
+ /* Test region */
+ case 0x4c ... 0x60:
+ return s->reg_data[addr];
+ /* PIH region */
+ case 0x81: /* PIH_ISR_P1 */
+ case 0x82: /* PIH_ISR_P2 */
+ case 0x83: /* PIH_SIR */
+ return s->reg_data[addr];
+ /* INTBR region */
+ case 0x85 ... 0x97:
+ return s->reg_data[addr];
+ /* GPIO region */
+ case 0x98 ... 0xc5:
+ return s->reg_data[addr];
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void twl4030_49_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
+{
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ /* AUDIO_VOICE region */
+ case 0x01 ... 0x49:
+ s->reg_data[addr] = value;
+ break;
+ /* Test region */
+ case 0x4c ... 0x59:
+ s->reg_data[addr] = value;
+ break;
+ case 0x5a ... 0x60:
+ /* read-only, ignore */
+ break;
+ /* PIH region */
+ case 0x81: /* PIH_ISR_P1 */
+ case 0x82: /* PIH_ISR_P2 */
+ case 0x83: /* PIH_SIR */
+ s->reg_data[addr] = value;
+ twl4030_interrupt_update(s->twl4030);
+ break;
+ /* INTBR region */
+ case 0x85 ... 0x90:
+ /* read-only, ignore */
+ break;
+ case 0x91 ... 0x97:
+ s->reg_data[addr] = value;
+ break;
+ /* GPIO region */
+ case 0x98 ... 0x9a:
+ /* read-only, ignore */
+ break;
+ case 0x9b ... 0xae:
+ s->reg_data[addr] = value;
+ break;
+ case 0xaf: /* GPIOPUPDCTR5 */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+ case 0xb0 ... 0xb5:
+ s->reg_data[addr] = value;
+ break;
+ case 0xb6: /* GPIO_IMR3A */
+ s->reg_data[addr] = value & 0x03;
+ break;
+ case 0xb7 ... 0xc4:
+ s->reg_data[addr] = value;
+ break;
+ case 0xc5: /* GPIO_SIH_CTRL */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+}
+
+static uint8_t twl4030_4a_read(TWL4030NodeState *s, uint8_t addr)
+{
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ /* MADC region */
+ case 0x00 ... 0x13:
+ case 0x61 ... 0x67:
+ return s->reg_data[addr];
+ case 0x17 ... 0x36: /* RT conversion registers */
+ case 0x37 ... 0x56: /* GP conversion registers */
+ case 0x57 ... 0x60: /* BCI conversion registers */
+ return (addr & 1) ? 0xc0 : 0xff;
+ /* MAIN_CHARGE region */
+ case 0x74 ... 0xa9:
+ return s->reg_data[addr];
+ /* PRECHARGE region */
+ case 0xaa ... 0xb8:
+ return s->reg_data[addr];
+ /* Interrupt region */
+ case 0xb9 ... 0xc6:
+ return s->reg_data[addr];
+ /* KEYPAD region */
+ case 0xd2 ... 0xe2:
+ case 0xe4:
+ case 0xe6 ... 0xe9:
+ return s->reg_data[addr];
+ case 0xe3: /* KEYP_ISR1 */
+ case 0xe5: /* KEYP_ISR2 */
+ {
+ uint8_t data = s->reg_data[addr];
+ if (s->reg_data[0xe9] & 0x04) { /* COR */
+ s->reg_data[addr] = 0x00;
+ twl4030_interrupt_update(s->twl4030);
+ }
+ return data;
+ }
+ /* LED region */
+ case 0xee: /* LEDEN */
+ return s->reg_data[addr];
+ /* PWMA region */
+ case 0xef: /* PWMAON */
+ case 0xf0: /* PWMAOFF */
+ return s->reg_data[addr];
+ /* PWMB region */
+ case 0xf1: /* PWMBON */
+ case 0xf2: /* PWMBOFF */
+ return s->reg_data[addr];
+ /* PWM0 region */
+ case 0xf8: /* PWM0ON */
+ case 0xf9: /* PWM0OFF */
+ return s->reg_data[addr];
+ /* PWM1 region */
+ case 0xfb: /* PWM1ON */
+ case 0xfc: /* PWM1OFF */
+ return s->reg_data[addr];
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void twl4030_4a_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
+{
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ /* MADC region */
+
+ case 0x00: /* CTRL1 */
+ case 0x01: /* CTRL2 */
+ s->reg_data[addr] = value;
+ break;
+ case 0x06: /* SW1SELECT_LSB */
+ case 0x07: /* SW1SELECT_MSB */
+ case 0x08: /* SW1AVERAGE_LSB */
+ case 0x09: /* SW1AVERAGE_MSB */
+ s->reg_data[addr] = value;
+ break;
+ case 0x12: /* CTRL_SW1 */
+ case 0x13: /* CTRL_SW2 */
+ /* always set all conversions ready, vbat&usb above ref value */
+ /* TODO: trigger interrupts if requested */
+ s->reg_data[addr] = 0xde;
+ break;
+ case 0x61: /* MADC_ISR1 */
+ s->reg_data[addr] &= ~(value & 0x0f);
+ break;
+ case 0x62: /* MADC_IMR1 */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+
+ /* MAIN_CHARGE region */
+
+ case 0x74: /* BCIMDEN */
+ /* read-only */
+ break;
+ case 0x75: /* BCIMDKEY */
+ s->reg_data[addr] = value;
+ switch (value) {
+ case 0x25: s->reg_data[0x74] = 0x12; break;
+ case 0x26: s->reg_data[0x74] = 0x11; break;
+ case 0x27: s->reg_data[0x74] = 0x0a; break;
+ case 0x28: s->reg_data[0x74] = 0x06; break;
+ case 0x29: s->reg_data[0x74] = 0x05; break;
+ default: s->reg_data[0x74] = 0; break;
+ }
+ break;
+ case 0x76 ... 0x84:
+ /* read-only registers */
+ break;
+ case 0x97: /* BCICTL1 */
+ s->reg_data[addr] = value;
+ break;
+
+ /* PRECHARGE region */
+
+ case 0xaa ... 0xb8: /* FIXME: unknown registers */
+ s->reg_data[addr] = value;
+ break;
+
+ /* Interrupt region */
+
+ case 0xb9: /* BCIISR1A */
+ s->reg_data[addr] &= ~value;
+ break;
+ case 0xba: /* BCIISR2A */
+ s->reg_data[addr] &= ~(value & 0x0f);
+ break;
+ case 0xbb: /* BCIIMR1A */
+ s->reg_data[addr] = value;
+ break;
+ case 0xbc: /* BCIIMR2A */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+
+ /* KEYPAD region */
+
+ case 0xd2: /* KEYP_CTRL_REG */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ case 0xd3: /* KEYP_DEB_REG */
+ s->reg_data[addr] = value & 0x3f;
+ break;
+ case 0xd5: /* LK_PTV_REG */
+ s->reg_data[addr] = value & 0xef;
+ break;
+ case 0xda: /* KEYP_SMS */
+ s->reg_data[addr] = value & 0x30;
+ twl4030_interrupt_update(s->twl4030);
+ break;
+ case 0xe3: /* KEYP_ISR1 */
+ case 0xe5: /* KEYP_ISR2 */
+ if (!(s->reg_data[0xe9] & 0x04)) { /* COR */
+ s->reg_data[addr] &= ~value;
+ twl4030_interrupt_update(s->twl4030);
+ }
+ break;
+ case 0xe4: /* KEYP_IMR1 */
+ case 0xe6: /* KEYP_IMR2 */
+ case 0xe7: /* KEYP_SIR */
+ s->reg_data[addr] = value & 0x0f;
+ twl4030_interrupt_update(s->twl4030);
+ break;
+ case 0xe9: /* KEYP_SIH_CTRL */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ case 0xd4: /* LONG_KEY_REG1 */
+ case 0xd6: /* TIME_OUT_REG1 */
+ case 0xd7: /* TIME_OUT_REG2 */
+ case 0xd8: /* KBC_REG */
+ case 0xe8: /* KEYP_EDR */
+ s->reg_data[addr] = value;
+ break;
+ case 0xd9: /* KBR_REG */
+ case 0xdb ... 0xe2: /* FULL_CODE_xx_yy */
+ /* read-only, ignore */
+ break;
+
+ /* LED region */
+
+ case 0xee: /* LEDEN */
+ s->reg_data[addr] = value;
+ TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
+ value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
+ value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
+ break;
+
+ /* PWMA/B/0/1 regions */
+
+ case 0xef: /* PWMAON */
+ case 0xf8: /* PWM0ON */
+ case 0xfb: /* PWM1ON */
+ s->reg_data[addr] = value;
+ break;
+ case 0xf0: /* PWMAOFF */
+ case 0xf9: /* PWM0OFF */
+ case 0xfc: /* PWM1OFF */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+}
+
+static inline struct tm *twl4030_gettime(void)
+{
+ time_t epoch_time = time(NULL);
+ return localtime(&epoch_time);
+}
+
+static uint8_t twl4030_4b_read(TWL4030NodeState *s, uint8_t addr)
+{
+ uint8_t x;
+ TRACE("addr=0x%02x value=0x%02x", addr, s->reg_data[addr]);
+ switch (addr) {
+ /* SECURED_REG region */
+ case 0x00 ... 0x13:
+ return s->reg_data[addr];
+ /* BACKUP_REG region */
+ case 0x14 ... 0x1b:
+ return s->reg_data[addr];
+ /* RTC region */
+ case 0x1c: /* SECONDS_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ x = ((t->tm_sec / 10) << 4) | (t->tm_sec % 10);
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("SECONDS_REG returns 0x%02x", x);
+ return x;
+ case 0x1d: /* MINUTES_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ x = ((t->tm_min / 10) << 4) | (t->tm_min % 10);
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("MINUTES_REG returns 0x%02x", x);
+ return x;
+ case 0x1e: /* HOURS_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ if (s->reg_data[0x29] & 0x08) { /* MODE_12_24 */
+ int h12 = t->tm_hour;
+ if (h12 > 11) {
+ h12 -= 12;
+ x = ((h12 / 10) << 4) | (h12 % 10) | 0x80; /* PM_NAM */
+ } else {
+ x = ((h12 / 10) << 4) | (h12 % 10);
+ }
+ } else {
+ x = ((t->tm_hour / 10) << 4) | (t->tm_hour % 10);
+ }
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("HOURS_REG returns 0x%02x", x);
+ return x;
+ case 0x1f: /* DAYS_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ x = ((t->tm_mday / 10) << 4) | (t->tm_mday % 10);
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("DAYS_REG returns 0x%02x", x);
+ return x;
+ case 0x20: /* MONTHS_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ x = (((t->tm_mon + 1) / 10) << 4) | ((t->tm_mon + 1) % 10);
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("MONTHS_REG returns 0x%02x", x);
+ return x;
+ case 0x21: /* YEARS_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ x = (((t->tm_year % 100) / 10) << 4) | (t->tm_year % 10);
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("YEARS_REG returns 0x%02x", x);
+ return x;
+ case 0x22: /* WEEKS_REG */
+ x = s->reg_data[addr];
+ if (x == 0xff) {
+ struct tm *t = twl4030_gettime();
+ x = t->tm_wday;
+ } else {
+ s->reg_data[addr] = 0xff;
+ }
+ TRACE_RTC("WEEKS_REG returns 0x%02x", x);
+ return x;
+ case 0x23: /* ALARM_SECONDS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("ALARM_SECONDS_REG returns 0x%02x", x);
+ return x;
+ case 0x24: /* ALARM_MINUTES_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("ALARM_MINUTES_REG returns 0x%02x", x);
+ return x;
+ case 0x25: /* ALARM_HOURS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("ALARM_HOURS_REG returns 0x%02x", x);
+ return x;
+ case 0x26: /* ALARM_DAYS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("ALARM_DAYS_REG returns 0x%02x", x);
+ return x;
+ case 0x27: /* ALARM_MONTHS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("ALARM_MONTHS_REG returns 0x%02x", x);
+ return x;
+ case 0x28: /* ALARM_YEARS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("ALARM_YEARS_REG returns 0x%02x", x);
+ return x;
+ case 0x29: /* RTC_CTRL_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("RTC_CTRL_REG returns 0x%02x", x);
+ return x;
+ case 0x2a: /* RTC_STATUS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("RTC_STATUS_REG returns 0x%02x", x);
+ return x;
+ case 0x2b: /* RTC_INTERRUPTS_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("RTC_INTERRUPTS_REG returns 0x%02x", x);
+ return x;
+ case 0x2c: /* RTC_COMP_LSB_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("RTC_COMP_LSB_REG returns 0x%02x", x);
+ return x;
+ case 0x2d: /* RTC_COMP_MSB_REG */
+ x = s->reg_data[addr];
+ TRACE_RTC("RTC_CTRL_REG returns 0x%02x", x);
+ return x;
+ /* INT region */
+ case 0x2f:
+ case 0x31 ... 0x35:
+ return s->reg_data[addr];
+ case 0x2e: /* PWR_ISR1 */
+ case 0x30: /* PWR_ISR2 */
+ {
+ uint8_t data = s->reg_data[addr];
+ if (s->reg_data[0x35] & 0x04) { /* COR */
+ s->reg_data[addr] = 0x00;
+ twl4030_interrupt_update(s->twl4030);
+ }
+ return data;
+ }
+ /* PM_MASTER region */
+ case 0x36 ... 0x44:
+ return s->reg_data[addr];
+ case 0x45: /* STS_HW_CONDITIONS */
+ /* FIXME: force USB always connected, no VBUS (host usb) */
+ return (s->reg_data[addr] & ~0x80) | 0x04;
+ case 0x46 ... 0x5a:
+ return s->reg_data[addr];
+ /* PM_RECEIVER region */
+ case 0x5b ... 0xf1:
+ return s->reg_data[addr];
+ default:
+ hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+
+static void twl4030_4b_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
+{
+ uint8_t seq_addr, seq_sub;
+
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ case 0x1c: /* SECONDS_REG */
+ case 0x1d: /* MINUTES_REG */
+ case 0x23: /* ALARM_SECONDS_REG */
+ case 0x24: /* ALARM_MINUTES_REG */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ case 0x1e: /* HOURS_REG */
+ case 0x25: /* ALARM_HOURS_REG */
+ s->reg_data[addr] = value & 0xbf;
+ break;
+ case 0x1f: /* DAYS_REG */
+ case 0x26: /* ALARM_DAYS_REG */
+ s->reg_data[addr] = value & 0x3f;
+ break;
+ case 0x20: /* MONTHS_REG */
+ case 0x27: /* ALARM_MONTHS_REG */
+ s->reg_data[addr] = value & 0x1f;
+ break;
+ case 0x21: /* YEARS_REG */
+ case 0x28: /* ALARM_YEARS_REG */
+ s->reg_data[addr] = value;
+ break;
+ case 0x22: /* WEEKS_REG */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ case 0x29: /* RTC_CTRL_REG */
+ TRACE_RTC("RTC_CTRL_REG = 0x%02x", value);
+ s->reg_data[addr] = value & 0x3f;
+ s->reg_data[0x2a] = (s->reg_data[0x2a] & ~0x01) | (value & 0x01);
+ if (value & 0x40) { /* GET_TIME */
+ struct tm *t = twl4030_gettime();
+ s->reg_data[0x1c] = ((t->tm_sec / 10) << 4) | (t->tm_sec % 10);
+ s->reg_data[0x1d] = ((t->tm_min / 10) << 4) | (t->tm_min % 10);
+ if (value & 0x08) { /* MODE_12_24 */
+ int h12 = t->tm_hour;
+ /* TODO: should we report hours 0-11 or 1-12? */
+ if (h12 > 11) {
+ h12 -= 12;
+ s->reg_data[0x1e] = ((h12 / 10) << 4) | (h12 % 10) |
+ 0x80; /* PM_NAM */
+ } else {
+ s->reg_data[0x1e] = ((h12 / 10) << 4) | (h12 % 10);
+ }
+ } else {
+ s->reg_data[0x1e] = ((t->tm_hour / 10) << 4) |
+ (t->tm_hour % 10);
+ }
+ s->reg_data[0x1f] = ((t->tm_mday / 10) << 4) |
+ (t->tm_mday % 10);
+ s->reg_data[0x20] = (((t->tm_mon + 1) / 10) << 4) |
+ ((t->tm_mon + 1) % 10);
+ s->reg_data[0x21] = (((t->tm_year % 100) / 10) << 4) |
+ (t->tm_year % 10);
+ s->reg_data[0x22] = t->tm_wday;
+ }
+ /* TODO: support bits 1, 2, 4 and 5 */
+ break;
+ case 0x2a: /* RTC_STATUS_REG */
+ TRACE_RTC("RTC_STATUS_REG = 0x%02x", value);
+ s->reg_data[addr] &= ~(value & 0xc0);
+ break;
+ case 0x2b: /* RTC_INTERRUPTS_REG */
+ TRACE_RTC("RTC_INTERRUPTS_REG = 0x%02x", value);
+ s->reg_data[addr] = value & 0x0f;
+ break;
+ case 0x2c: /* RTC_COMP_LSB_REG */
+ case 0x2d: /* RTC_COMP_MSB_REG */
+ TRACE_RTC("RTC_COMP_%s_REG = 0x%02x",
+ (addr == 0x2c) ? "LSB" : "MSB", value);
+ s->reg_data[addr] = value;
+ break;
+ case 0x2e: /* PWR_ISR1 */
+ case 0x30: /* PWR_ISR2 */
+ if (!(s->reg_data[0x35] & 0x04)) { /* COR */
+ s->reg_data[addr] &= ~value;
+ twl4030_interrupt_update(s->twl4030);
+ }
+ break;
+ case 0x2f: /* PWR_IMR1 */
+ case 0x31: /* PWR_IMR2 */
+ s->reg_data[addr] = value;
+ twl4030_interrupt_update(s->twl4030);
+ break;
+ case 0x33: /* PWR_EDR1 */
+ case 0x34: /* PWR_EDR2 */
+ s->reg_data[addr] = value;
+ break;
+ case 0x35: /* PWR_SIH_CTRL */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ case 0x36: /* CFG_P1_TRANSITION */
+ case 0x37: /* CFG_P2_TRANSITION */
+ case 0x38: /* CFG_P3_TRANSITION */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = (s->reg_data[addr] & 0x40) | (value & 0xbf);
+ break;
+ case 0x39: /* CFG_P123_TRANSITION */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = value;
+ break;
+ case 0x3a: /* STS_BOOT */
+ s->reg_data[addr] = value;
+ break;
+ case 0x3b: /* CFG_BOOT */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
+ break;
+ case 0x44: /* PROTECT_KEY */
+ s->twl4030->key_cfg = 0;
+ s->twl4030->key_tst = 0;
+ switch (value) {
+ case 0x0C:
+ if (s->reg_data[addr] == 0xC0)
+ s->twl4030->key_cfg = 1;
+ break;
+ case 0xE0:
+ if (s->reg_data[addr] == 0x0E)
+ s->twl4030->key_tst = 1;
+ break;
+ case 0xEC:
+ if (s->reg_data[addr] == 0xCE) {
+ s->twl4030->key_cfg = 1;
+ s->twl4030->key_tst = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ s->reg_data[addr] = value;
+ break;
+ case 0x46: /* P1_SW_EVENTS */
+ case 0x47: /* P2_SW_EVENTS */
+ case 0x48: /* P3_SW_EVENTS */
+ s->reg_data[addr] = value & 0x78;
+ if (value & 0x01) { /* DEVOFF */
+ TRACE("device power off sequence requested");
+ qemu_system_shutdown_request();
+ }
+ break;
+ case 0x4a: /* PB_CFG */
+ s->reg_data[addr] = value & 0xf;
+ break;
+ case 0x4b: /* PB_MSB */
+ case 0x4c: /* PB_LSB */
+ s->reg_data[addr] = value;
+ break;
+ case 0x52: /* SEQ_ADD_W2P */
+ case 0x53: /* SEQ_ADD_P2A */
+ case 0x54: /* SEQ_ADD_A2W */
+ case 0x55: /* SEQ_ADD_A2S */
+ case 0x56: /* SEQ_ADD_S2A12 */
+ case 0x57: /* SEQ_ADD_S2A3 */
+ case 0x58: /* SEQ_ADD_WARM */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = value & 0x3f;
+ break;
+ case 0x59: /* MEMORY_ADDRESS */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = value;
+ break;
+ case 0x5a: /* MEMORY_DATA */
+ if (s->twl4030->key_cfg) {
+ s->reg_data[addr] = value;
+ seq_addr = s->reg_data[0x59];
+ seq_sub = seq_addr & 3;
+ seq_addr >>= 2;
+ if ((seq_addr >= 0x2b && seq_addr <= 0x3e) ||
+ (seq_addr <= 0x0e && seq_sub == 3))
+ s->twl4030->seq_mem[seq_addr][seq_sub] = value;
+ }
+ /* TODO: check if autoincrement is write-protected as well */
+ s->reg_data[0x59]++;
+ break;
+ case 0x5e: /* WATCHDOG_CFG */
+ case 0x60: /* VIBRATOR_CFG */
+ case 0x6d: /* BB_CFG */
+ case 0x73: /* VAUX1_TYPE */
+ case 0x77: /* VAUX2_TYPE */
+ case 0x7b: /* VAUX3_TYPE */
+ case 0x7f: /* VAUX4_TYPE */
+ case 0x83: /* VMMC1_TYPE */
+ case 0x87: /* VMMC2_TYPE */
+ case 0x8b: /* VPLL1_TYPE */
+ case 0x8f: /* VPLL2_TYPE */
+ case 0x93: /* VSIM_TYPE */
+ case 0x97: /* VDAC_TYPE */
+ case 0x9b: /* VINTANA1_TYPE */
+ case 0x9f: /* VINTANA2_TYPE */
+ case 0xa3: /* VINTDIG_TYPE */
+ case 0xa7: /* VIO_TYPE */
+ case 0xaa: /* VIO_MISC_CFG */
+ case 0xb1: /* VDD1_TYPE */
+ case 0xb4: /* VDD1_MISC_CFG */
+ case 0xbd: /* VDD1_STEP */
+ case 0xbf: /* VDD2_TYPE */
+ case 0xc2: /* VDD2_MISC_CFG */
+ case 0xcb: /* VDD2_STEP */
+ case 0xcd: /* VUSB1V5_TYPE */
+ case 0xd0: /* VUSB1V8_TYPE */
+ case 0xd3: /* VUSB3V1_TYPE */
+ case 0xdb: /* REGEN_TYPE */
+ case 0xde: /* NRESPWRON_TYPE */
+ case 0xe1: /* CLKEN_TYPE */
+ case 0xe4: /* SYSEN_TYPE */
+ case 0xe7: /* HFCLKOUT_TYPE */
+ case 0xea: /* 2KCLKOUT_TYPE */
+ case 0xed: /* TRITON_RESET_TYPE */
+ case 0xf0: /* MAINREF_TYPE */
+ s->reg_data[addr] = value & 0x1f;
+ break;
+ case 0x5f: /* IT_CHECK_CFG */
+ case 0xb9: /* VDD1_VSEL */
+ case 0xbb: /* VDD1_VFLOOR */
+ case 0xbc: /* VDD1_VROOF */
+ case 0xc7: /* VDD2_VSEL */
+ case 0xc9: /* VDD2_VFLOOR */
+ case 0xca: /* VDD2_VROOF */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ case 0x61: /* DC/DC_GLOBAL_CFG */
+ case 0x68: /* MISC_CFG */
+ s->reg_data[addr] = value;
+ break;
+ case 0x62: /* VDD1_TRIM1 */
+ case 0x64: /* VDD2_TRIM1 */
+ case 0x66: /* VIO_TRIM1 */
+ case 0xac: /* VIO_TEST2 */
+ case 0xb6: /* VDD1_TEST2 */
+ case 0xc4: /* VDD2_TEST2 */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ case 0x63: /* VDD1_TRIM2 */
+ case 0x65: /* VDD2_TRIM2 */
+ case 0x67: /* VIO_TRIM2 */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x3f;
+ break;
+ case 0x72: /* VAUX1_DEV_GRP */
+ case 0x76: /* VAUX2_DEV_GRP */
+ case 0x7a: /* VAUX3_DEV_GRP */
+ case 0x7e: /* VAUX4_DEV_GRP */
+ case 0x82: /* VMMC1_DEV_GRP */
+ case 0x86: /* VMMC2_DEV_GRP */
+ case 0x8a: /* VPLL1_DEV_GRP */
+ case 0x8e: /* VPLL2_DEV_GRP */
+ case 0x92: /* VSIM_DEV_GRP */
+ case 0x96: /* VDAC_DEV_GRP */
+ case 0x9a: /* VINTANA1_DEV_GRP */
+ case 0x9e: /* VINTANA2_DEV_GRP */
+ case 0xa2: /* VINTDIG_DEV_GRP */
+ case 0xa6: /* VIO_DEV_GRP */
+ case 0xb0: /* VDD1_DEV_GRP */
+ case 0xbe: /* VDD2_DEV_GRP */
+ case 0xcc: /* VUSB1V5_DEV_GRP */
+ case 0xcf: /* VUSB1V8_DEV_GRP */
+ case 0xd2: /* VUSB3V1_DEV_GRP */
+ case 0xda: /* REGEN_DEV_GRP */
+ case 0xdd: /* NRESPWRON_DEV_GRP */
+ case 0xe0: /* CLKEN_DEV_GRP */
+ case 0xe3: /* SYSEN_DEV_GRP */
+ case 0xe6: /* HFCLKOUT_DEV_GRP */
+ case 0xe9: /* 2KCLKOUT_DEV_GRP */
+ case 0xec: /* TRITON_RESET_DEV_GRP */
+ case 0xef: /* MAINREF_DEV_GRP */
+ s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0);
+ break;
+ case 0x75: /* VAUX1_DEDICATED */
+ case 0x7d: /* VAUX3_DEDICATED */
+ case 0x8d: /* VPLL1_DEDICATED */
+ case 0x95: /* VSIM_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x77;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
+ break;
+ case 0x79: /* VAUX2_DEDICATED */
+ case 0x81: /* VAUX4_DEDICATED */
+ case 0x91: /* VPLL2_DEDICATED */
+ case 0xa5: /* VINTDIG_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x7f;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
+ break;
+ case 0x85: /* VMMC1_DEDICATED */
+ case 0x99: /* VDAC_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x73;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
+ break;
+ case 0x89: /* VMMC2_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x7f;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
+ break;
+ case 0x9d: /* VINTANA1_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x70;
+ break;
+ case 0xa1: /* VINTANA2_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x71;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x01);
+ break;
+ case 0x74: /* VAUX1_REMAP */
+ case 0x78: /* VAUX2_REMAP */
+ case 0x7c: /* VAUX3_REMAP */
+ case 0x80: /* VAUX4_REMAP */
+ case 0x84: /* VMMC1_REMAP */
+ case 0x88: /* VMMC2_REMAP */
+ case 0x8c: /* VPLL1_REMAP */
+ case 0x90: /* VPLL2_REMAP */
+ case 0x94: /* VSIM_REMAP */
+ case 0x98: /* VDAC_REMAP */
+ case 0x9c: /* VINTANA1_REMAP */
+ case 0xa0: /* VINTANA2_REMAP */
+ case 0xa4: /* VINTDIG_REMAP */
+ case 0xa8: /* VIO_REMAP */
+ case 0xb2: /* VDD1_REMAP */
+ case 0xc0: /* VDD2_REMAP */
+ case 0xdc: /* REGEN_REMAP */
+ case 0xdf: /* NRESPWRON_REMAP */
+ case 0xe2: /* CLKEN_REMAP */
+ case 0xe5: /* SYSEN_REMAP */
+ case 0xe8: /* HFCLKOUT_REMAP */
+ case 0xeb: /* 2KCLKOUT_REMAP */
+ case 0xee: /* TRITON_RESET_REMAP */
+ case 0xf1: /* MAINREF_REMAP */
+ s->reg_data[addr] = value;
+ break;
+ case 0xa9: /* VIO_CFG */
+ case 0xb3: /* VDD1_CFG */
+ case 0xc1: /* VDD2_CFG */
+ s->reg_data[addr] = value & 0x03;
+ break;
+ case 0xab: /* VIO_TEST1 */
+ case 0xb5: /* VDD1_TEST1 */
+ case 0xc3: /* VDD2_TEST1 */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value;
+ break;
+ case 0xad: /* VIO_OSC */
+ case 0xb7: /* VDD1_OSC */
+ case 0xc5: /* VDD2_OSC */
+ s->reg_data[addr] = value & 0x5f;
+ break;
+ case 0xae: /* VIO_RESERVED */
+ case 0xb8: /* VDD1_RESERVED */
+ case 0xc6: /* VDD2_RESERVED */
+ break;
+ case 0xaf: /* VIO_VSEL */
+ s->reg_data[addr] = value & 0x01;
+ break;
+ case 0xba: /* VDD1_VMODE_CFG */
+ case 0xc8: /* VDD2_VMODE_CFG */
+ s->reg_data[addr] = (s->reg_data[addr] & 0x38) | (value & 0x07);
+ break;
+ case 0xd8: /* VUSB_DEDICATED1 */
+ s->reg_data[addr] = value & 0x1f;
+ break;
+ case 0xd9: /* VUSB_DEDICATED2 */
+ s->reg_data[addr] = value & 0x08;
+ break;
+
+ default:
+ hw_error("%s: unknown register 0x%02x value 0x%02x",
+ __FUNCTION__, addr, value);
+ break;
+ }
+}
+
+static void twl4030_key_setstate(TWL4030NodeState *s,
+ int col, int row, int state)
+{
+ TRACE("col=%d, row=%d, state=%d", col, row, state);
+ if (col >= 0 && col < 8 && row >= 0 && row < 8) {
+ s->reg_data[0xd8] = col; /* KBC_REG */
+ s->reg_data[0xd9] = row; /* KBR_REG */
+ int gen_int = 0;
+ if (state) {
+ s->reg_data[0xdb + row] |= 1 << col; /* FULL_CODE_xx_yy */
+ gen_int = s->reg_data[0xe8] & 0x02; /* ITKPRISING */
+ } else {
+ s->reg_data[0xdb + row] &= ~(1 << col); /* FULL_CODE_xx_yy */
+ gen_int = s->reg_data[0xe8] & 0x01; /* ITKPFALLING */
+ }
+ if (gen_int) {
+ s->reg_data[0xe3] |= 0x01; /* ITKPISR1 */
+ s->reg_data[0xe5] |= 0x01; /* ITKPISR2 */
+ twl4030_interrupt_update(s->twl4030);
+ }
+ }
+}
+
+static void twl4030_key_handler(void *opaque, int keycode)
+{
+ TWL4030NodeState *s = (TWL4030NodeState *)opaque;
+ if (!s->twl4030->extended_key && keycode == 0xe0) {
+ s->twl4030->extended_key = 0x80;
+ } else {
+ const TWL4030KeyMap *k = s->twl4030->keymap;
+ int fullcode = (keycode & 0x7f) | (s->twl4030->extended_key);
+ for (; k && k->code >= 0; k++) {
+ if (k->code == fullcode) {
+ twl4030_key_setstate(s, k->column, k->row, !(keycode & 0x80));
+ }
+ }
+ s->twl4030->extended_key = 0;
+ }
+}
+
+static void twl4030_node_reset(TWL4030NodeState *s,
+ const uint8_t *reset_values)
+{
+ s->firstbyte = 0;
+ s->reg = 0x00;
+ memcpy(s->reg_data, reset_values, 256);
+}
+
+static void twl4030_node_init(TWL4030NodeState *s,
+ twl4030_read_func read,
+ twl4030_write_func write,
+ const uint8_t *reset_values)
+{
+ s->read_func = read;
+ s->write_func = write;
+ twl4030_node_reset(s, reset_values);
+}
+
+static int twl4030_48_init(i2c_slave *i2c)
+{
+ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
+ twl4030_48_read, twl4030_48_write,
+ addr_48_reset_values);
+ return 0;
+}
+
+static int twl4030_49_init(i2c_slave *i2c)
+{
+ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
+ twl4030_49_read, twl4030_49_write,
+ addr_49_reset_values);
+ return 0;
+}
+
+static int twl4030_4a_init(i2c_slave *i2c)
+{
+ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
+ twl4030_node_init(s,
+ twl4030_4a_read, twl4030_4a_write,
+ addr_4a_reset_values);
+ qemu_add_kbd_event_handler(twl4030_key_handler, s);
+ return 0;
+}
+
+static int twl4030_4b_init(i2c_slave *i2c)
+{
+ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
+ twl4030_4b_read, twl4030_4b_write,
+ addr_4b_reset_values);
+ return 0;
+}
+
+static void twl4030_event(i2c_slave *i2c, enum i2c_event event)
+{
+ if (event == I2C_START_SEND) {
+ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
+ s->firstbyte = 1;
+ }
+}
+
+static int twl4030_rx(i2c_slave *i2c)
+{
+ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
+ return s->read_func(s, s->reg++);
+}
+
+static int twl4030_tx(i2c_slave *i2c, uint8_t data)
+{
+ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
+ if (s->firstbyte) {
+ s->reg = data;
+ s->firstbyte = 0;
+ } else {
+ s->write_func(s, s->reg++, data);
+ }
+ return 1;
+}
+
+static void twl4030_save_state(QEMUFile *f, void *opaque)
+{
+ TWL4030State *s = (TWL4030State *)opaque;
+ int i;
+
+ qemu_put_sbe32(f, s->key_cfg);
+ qemu_put_sbe32(f, s->key_tst);
+ for (i = 0; i < 64; i++)
+ qemu_put_buffer(f, s->seq_mem[i], 4);
+ for (i = 0; i < 5; i++) {
+ qemu_put_sbe32(f, s->i2c[i]->firstbyte);
+ qemu_put_byte(f, s->i2c[i]->reg);
+ qemu_put_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
+ }
+}
+
+static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ TWL4030State *s = (TWL4030State *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->key_cfg = qemu_get_sbe32(f);
+ s->key_tst = qemu_get_sbe32(f);
+ for (i = 0; i < 64; i++)
+ qemu_get_buffer(f, s->seq_mem[i], 4);
+ for (i = 0; i < 5; i++) {
+ s->i2c[i]->firstbyte = qemu_get_sbe32(f);
+ s->i2c[i]->reg = qemu_get_byte(f);
+ qemu_get_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
+ }
+
+ return 0;
+}
+
+static void twl4030_reset(void *opaque)
+{
+ TWL4030State *s = opaque;
+
+ twl4030_node_reset(s->i2c[0], addr_48_reset_values);
+ twl4030_node_reset(s->i2c[1], addr_49_reset_values);
+ twl4030_node_reset(s->i2c[2], addr_4a_reset_values);
+ twl4030_node_reset(s->i2c[3], addr_4b_reset_values);
+
+ s->extended_key = 0;
+ s->key_cfg = 0;
+ s->key_tst = 0;
+
+ memset(s->seq_mem, 0, sizeof(s->seq_mem));
+
+ /* TODO: indicate correct reset reason */
+}
+
+static I2CSlaveInfo twl4030_info[4] = {
+ {
+ .qdev.name = "twl4030_48",
+ .qdev.size = sizeof(TWL4030NodeState),
+ .init = twl4030_48_init,
+ .event = twl4030_event,
+ .recv = twl4030_rx,
+ .send = twl4030_tx
+ },
+ {
+ .qdev.name = "twl4030_49",
+ .qdev.size = sizeof(TWL4030NodeState),
+ .init = twl4030_49_init,
+ .event = twl4030_event,
+ .recv = twl4030_rx,
+ .send = twl4030_tx
+ },
+ {
+ .qdev.name = "twl4030_4a",
+ .qdev.size = sizeof(TWL4030NodeState),
+ .init = twl4030_4a_init,
+ .event = twl4030_event,
+ .recv = twl4030_rx,
+ .send = twl4030_tx
+ },
+ {
+ .qdev.name = "twl4030_4b",
+ .qdev.size = sizeof(TWL4030NodeState),
+ .init = twl4030_4b_init,
+ .event = twl4030_event,
+ .recv = twl4030_rx,
+ .send = twl4030_tx
+ },
+};
+
+void *twl4030_init(i2c_bus *gp_bus, qemu_irq irq1, qemu_irq irq2,
+ const TWL4030KeyMap *keymap)
+{
+ TWL4030State *s = (TWL4030State *)qemu_mallocz(sizeof(*s));
+
+ s->irq1 = irq1;
+ s->irq2 = irq2;
+ s->key_cfg = 0;
+ s->key_tst = 0;
+ s->keymap = keymap;
+
+ int i;
+ for (i = 0; i < 4; i++) {
+ DeviceState *ds = i2c_create_slave(gp_bus, twl4030_info[i].qdev.name,
+ 0x48 + i);
+ s->i2c[i] = FROM_I2C_SLAVE(TWL4030NodeState, I2C_SLAVE_FROM_QDEV(ds));
+ s->i2c[i]->twl4030 = s;
+ }
+
+ register_savevm("twl4030", -1, 0,
+ twl4030_save_state, twl4030_load_state, s);
+ qemu_register_reset(twl4030_reset, s);
+ return s;
+}
+
+void twl4030_set_powerbutton_state(void *opaque, int pressed)
+{
+ TWL4030State *s = opaque;
+ if (pressed) {
+ if (!(s->i2c[3]->reg_data[0x45] & 0x01) && /* STS_PWON */
+ (s->i2c[3]->reg_data[0x33] & 0x02)) { /* PWRON_RISING */
+ s->i2c[3]->reg_data[0x2e] |= 0x01; /* PWRON */
+ s->i2c[3]->reg_data[0x30] |= 0x01; /* PWRON */
+ twl4030_interrupt_update(s);
+ }
+ s->i2c[3]->reg_data[0x45] |= 0x01; /* STS_PWON */
+ } else {
+ if ((s->i2c[3]->reg_data[0x45] & 0x01) && /* STS_PWON */
+ (s->i2c[3]->reg_data[0x33] & 0x01)) { /* PWRON_FALLING */
+ s->i2c[3]->reg_data[0x2e] |= 0x01; /* PWRON */
+ s->i2c[3]->reg_data[0x30] |= 0x01; /* PWRON */
+ twl4030_interrupt_update(s);
+ }
+ s->i2c[3]->reg_data[0x45] &= ~0x01; /* STS_PWON */
+ }
+}
+
+static void twl4030_register_devices(void)
+{
+ I2CSlaveInfo *p = twl4030_info;
+ int i;
+ for (i = 0; i < 4; p++, i++) {
+ i2c_register_slave(p);
+ }
+}
+
+device_init(twl4030_register_devices);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 30/48] savevm and reset support for soc_dma
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (25 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 29/48] Add triton2 (twl4030) driver Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 32/48] Add beagleboard and n900 machine definitions Riku Voipio
` (17 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio
From: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
---
hw/soc_dma.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
hw/soc_dma.h | 4 ++-
2 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/hw/soc_dma.c b/hw/soc_dma.c
index 8147ed5..280fe92 100644
--- a/hw/soc_dma.c
+++ b/hw/soc_dma.c
@@ -20,6 +20,7 @@
#include "qemu-common.h"
#include "qemu-timer.h"
#include "soc_dma.h"
+#include "hw.h"
static void transfer_mem2mem(struct soc_dma_ch_s *ch)
{
@@ -228,12 +229,79 @@ void soc_dma_reset(struct soc_dma_s *soc)
{
struct dma_s *s = (struct dma_s *) soc;
- s->soc.drqbmp = 0;
+ memset(s->soc.drqst, 0, sizeof(s->soc.drqst));
s->ch_enable_mask = 0;
s->enabled_count = 0;
soc_dma_ch_freq_update(s);
}
+static void soc_dma_save_state(QEMUFile *f, void *opaque)
+{
+ struct dma_s *s = (struct dma_s *)opaque;
+ int i;
+
+ qemu_put_buffer(f, s->soc.drqst, sizeof(s->soc.drqst));
+ qemu_put_sbe64(f, s->soc.freq);
+ qemu_put_be64(f, s->ch_enable_mask);
+ qemu_put_sbe64(f, s->channel_freq);
+ qemu_put_sbe32(f, s->enabled_count);
+ for (i = 0; i < s->chnum; i++) {
+ qemu_put_timer(f, s->ch[i].timer);
+ qemu_put_sbe32(f, s->ch[i].enable);
+ qemu_put_sbe32(f, s->ch[i].update);
+ qemu_put_sbe32(f, s->ch[i].bytes);
+ qemu_put_sbe32(f, s->ch[i].type[0]);
+ qemu_put_sbe32(f, s->ch[i].type[1]);
+#if TARGET_PHYS_ADDR_BITS == 32
+ qemu_put_be32(f, s->ch[i].vaddr[0]);
+ qemu_put_be32(f, s->ch[i].vaddr[1]);
+#elif TARGET_PHYS_ADDR_BITS == 64
+ qemu_put_be64(f, s->ch[i].vaddr[0]);
+ qemu_put_be64(f, s->ch[i].vaddr[1]);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+ qemu_put_sbe32(f, s->ch[i].running);
+ }
+}
+
+static int soc_dma_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct dma_s *s = (struct dma_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ qemu_get_buffer(f, s->soc.drqst, sizeof(s->soc.drqst));
+ s->soc.freq = qemu_get_sbe64(f);
+ s->ch_enable_mask = qemu_get_be64(f);
+ s->channel_freq = qemu_get_sbe64(f);
+ s->enabled_count = qemu_get_sbe32(f);
+ for (i = 0; i < s->chnum; i++) {
+ qemu_get_timer(f, s->ch[i].timer);
+ s->ch[i].enable = qemu_get_sbe32(f);
+ s->ch[i].update = qemu_get_sbe32(f);
+ s->ch[i].bytes = qemu_get_sbe32(f);
+ s->ch[i].type[0] = qemu_get_sbe32(f);
+ s->ch[i].type[1] = qemu_get_sbe32(f);
+#if TARGET_PHYS_ADDR_BITS == 32
+ s->ch[i].vaddr[0] = qemu_get_be32(f);
+ s->ch[i].vaddr[1] = qemu_get_be32(f);
+#elif TARGET_PHYS_ADDR_BITS == 64
+ s->ch[i].vaddr[0] = qemu_get_be64(f);
+ s->ch[i].vaddr[1] = qemu_get_be64(f);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+ s->ch[i].running = qemu_get_sbe32(f);
+
+ soc_dma_ch_update(&s->ch[i]);
+ }
+
+ return 0;
+}
+
/* TODO: take a functional-clock argument */
struct soc_dma_s *soc_dma_init(int n)
{
@@ -251,6 +319,8 @@ struct soc_dma_s *soc_dma_init(int n)
soc_dma_reset(&s->soc);
fifo_size = 0;
+ register_savevm("soc_dma", -1, 0,
+ soc_dma_save_state, soc_dma_load_state, s);
return &s->soc;
}
diff --git a/hw/soc_dma.h b/hw/soc_dma.h
index c0ebb8d..6bfd3a8 100644
--- a/hw/soc_dma.h
+++ b/hw/soc_dma.h
@@ -18,6 +18,8 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#define DMA_MAX_DRQ 96
+
struct soc_dma_s;
struct soc_dma_ch_s;
typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
@@ -65,7 +67,7 @@ struct soc_dma_ch_s {
struct soc_dma_s {
/* Following fields are set by the SoC DMA module and can be used
* by anybody. */
- uint64_t drqbmp; /* Is zeroed by soc_dma_reset() */
+ uint8_t drqst[DMA_MAX_DRQ]; /* Is zeroed by soc_dma_reset() */
qemu_irq *drq;
void *opaque;
int64_t freq;
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 32/48] Add beagleboard and n900 machine definitions
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (26 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 30/48] savevm and reset support for soc_dma Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 33/48] Add OpenGL ES accelerator support Riku Voipio
` (16 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: yajin, Riku Voipio, Juha Riihimäki
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 16696 bytes --]
From: Riku Voipio <riku.voipio@nokia.com>
Wire in all the code from previous patches. Beagleboard code based on
Yajin's initial work.
Cc: yajin@vm-kernel.org
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
Makefile.target | 7 +-
hw/beagle.c | 108 +++++++++++++++++++++
hw/nseries.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 397 insertions(+), 6 deletions(-)
create mode 100644 hw/beagle.c
diff --git a/Makefile.target b/Makefile.target
index eb4d010..c14d496 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -269,8 +269,11 @@ obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-arm-y += pflash_cfi01.o gumstix.o
obj-arm-y += zaurus.o ide/core.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
-obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
-obj-arm-y += omap2.o omap_dss.o soc_dma.o
+obj-arm-y += omap_gpio.o omap_uart.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o
+obj-arm-y += omap_i2c.o omap_spi.o omap_intc.o omap_dss.o soc_dma.o omap_gptimer.o
+obj-arm-y += omap_synctimer.o omap_sdrc.o omap_gpmc.o omap_tap.o omap_l4.o
+obj-arm-y += omap_usb.o omap3_mmc.o omap3_lcd.o omap3_boot.o omap1.o omap2.o omap3.o
+obj-arm-y += beagle.o twl4030.o
obj-arm-y += omap_sx1.o palm.o tsc210x.o
obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
obj-arm-y += mst_fpga.o mainstone.o
diff --git a/hw/beagle.c b/hw/beagle.c
new file mode 100644
index 0000000..ae4da1c
--- /dev/null
+++ b/hw/beagle.c
@@ -0,0 +1,108 @@
+/*
+ * Beagle board emulation. http://beagleboard.org/
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) any later version of the License.
+ *
+ * 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 "qemu-common.h"
+#include "sysemu.h"
+#include "omap.h"
+#include "arm-misc.h"
+#include "boards.h"
+#include "i2c.h"
+#include "net.h"
+#include "devices.h"
+#include "flash.h"
+
+#ifdef CONFIG_GLHW
+#include "helper_opengl.h"
+#endif
+
+#define BEAGLE_NAND_CS 0
+#define BEAGLE_SMC_CS 1
+#define BEAGLE_NAND_PAGESIZE 0x800
+#define BEAGLE_SDRAM_SIZE (128 * 1024 * 1024) /* 128MB */
+
+/* Beagle board support */
+struct beagle_s {
+ struct omap_mpu_state_s *cpu;
+
+ NANDFlashState *nand;
+ struct omap3_lcd_panel_s *lcd_panel;
+ i2c_bus *i2c;
+ void *twl4030;
+ void *smc;
+#ifdef CONFIG_GLHW
+ void *gl;
+#endif
+};
+
+static void beagle_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ struct beagle_s *s = (struct beagle_s *) qemu_mallocz(sizeof(*s));
+ DriveInfo *dmtd = drive_get(IF_MTD, 0, 0);
+ DriveInfo *dsd = drive_get(IF_SD, 0, 0);
+
+ if (!dmtd && !dsd) {
+ hw_error("%s: SD or NAND image required", __FUNCTION__);
+ }
+ s->cpu = omap3530_mpu_init(ram_size, NULL, NULL, serial_hds[0]);
+
+ s->nand = nand_init(NAND_MFR_MICRON, 0xba, dmtd);
+ nand_setpins(s->nand, 0, 0, 0, 1, 0); /* no write-protect */
+ omap_gpmc_attach(s->cpu->gpmc, BEAGLE_NAND_CS, 0, NULL, NULL, s->nand, 2);
+ if (dsd) {
+ omap3_mmc_attach(s->cpu->omap3_mmc[0], dsd, 0, 0);
+ }
+
+ s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
+ s->twl4030 = twl4030_init(s->i2c,
+ s->cpu->irq[0][OMAP_INT_3XXX_SYS_NIRQ],
+ NULL, NULL);
+ s->smc = smc91c111_init_lite(&nd_table[0], /*0x08000000,*/
+ omap2_gpio_in_get(s->cpu->gpif, 54));
+ omap_gpmc_attach(s->cpu->gpmc, BEAGLE_SMC_CS, smc91c111_iomemtype(s->smc),
+ NULL, NULL, s->smc, 0);
+
+ s->lcd_panel = omap3_lcd_panel_init(s->cpu->dss);
+ omap_lcd_panel_attach(s->cpu->dss, omap3_lcd_panel_get(s->lcd_panel));
+
+#ifdef CONFIG_GLHW
+ s->gl = helper_opengl_init(s->cpu->env);
+#endif
+
+ omap3_boot_rom_emu(s->cpu);
+}
+
+QEMUMachine beagle_machine = {
+ .name = "beagle",
+ .desc = "Beagle board (OMAP3530)",
+ .init = beagle_init,
+};
+
+static void beagle_machine_init(void)
+{
+ qemu_register_machine(&beagle_machine);
+}
+
+machine_init(beagle_machine_init);
diff --git a/hw/nseries.c b/hw/nseries.c
index ec8f8d1..27d517b 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1554,10 +1554,6 @@ static QEMUMachine n810_machine = {
.init = n810_init,
};
-#ifdef CONFIG_GLES2
-#include "gles2.h"
-#endif
-
#define N900_SDRAM_SIZE (256 * 1024 * 1024)
#define N900_ONENAND_CS 0
#define N900_ONENAND_BUFSIZE (0xc000 << 1)
@@ -2128,6 +2124,289 @@ static I2CSlaveInfo tpa6130_info = {
.send = tpa6130_tx
};
+struct n900_s {
+ struct omap_mpu_state_s *cpu;
+ void *twl4030;
+ void *nand;
+ void *lcd;
+ struct mipid_s *mipid;
+ void *tsc2005;
+ void *bq2415x;
+ void *tpa6130;
+ void *lis302dl;
+ void *smc;
+ int extended_key;
+ int slide_open;
+ int camera_cover_open;
+ int headphone_connected;
+ QEMUTimer *shutdown_timer;
+};
+
+/* this takes care of the keys which are not located on the
+ * n900 keypad (note that volume up/down keys are handled by
+ * the keypad eventhough the keys are not located on the keypad)
+ * as well as triggering some other hardware button/switch-like
+ * events that are mapped to the host keyboard:
+ *
+ * escape ... power
+ * f1 ....... keypad slider open/close
+ * f2 ....... keypad lock
+ * f3 ....... camera lens cover open/close
+ * f4 ....... camera focus
+ * f5 ....... camera take picture
+ * f6 ....... stereo headphone connect/disconnect
+ * kp1 ...... decrease accelerometer x axis value
+ * kp2 ...... increase accelerometer x axis value
+ * kp4 ...... decrease accelerometer y axis value
+ * kp5 ...... increase accelerometer y axis value
+ * kp7 ...... decrease accelerometer z axis value
+ * kp8 ...... increase accelerometer z axis value
+ */
+static void n900_key_handler(void *opaque, int keycode)
+{
+ struct n900_s *s = opaque;
+ if (!s->extended_key && keycode == 0xe0) {
+ s->extended_key = 0x80;
+ } else {
+ int release = keycode & 0x80;
+ keycode = (keycode & 0x7f) | s->extended_key;
+ s->extended_key = 0;
+ switch (keycode) {
+ case 0x01: /* escape */
+ twl4030_set_powerbutton_state(s->twl4030, !release);
+ break;
+ case 0x3b: /* f1 */
+ if (release) {
+ s->slide_open = !s->slide_open;
+ qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+ N900_SLIDE_GPIO),
+ !s->slide_open);
+ }
+ break;
+ case 0x3c: /* f2 */
+ qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+ N900_KBLOCK_GPIO),
+ !!release);
+ break;
+ case 0x3d: /* f3 */
+ if (release) {
+ s->camera_cover_open = !s->camera_cover_open;
+ qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+ N900_CAMCOVER_GPIO),
+ s->camera_cover_open);
+ }
+ break;
+ case 0x3e: /* f4 */
+ qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+ N900_CAMFOCUS_GPIO),
+ !!release);
+ break;
+ case 0x3f: /* f5 */
+ qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+ N900_CAMLAUNCH_GPIO),
+ !!release);
+ break;
+ case 0x40: /* f6 */
+ if (release) {
+ s->headphone_connected = !s->headphone_connected;
+ qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+ N900_HEADPHONE_GPIO),
+ !s->headphone_connected);
+ }
+ break;
+ case 0x4f ... 0x50: /* kp1,2 */
+ lis302dl_trigger(s->lis302dl, 0, keycode - 0x4f, !release);
+ break;
+ case 0x4b ... 0x4c: /* kp4,5 */
+ lis302dl_trigger(s->lis302dl, 1, keycode - 0x4b, !release);
+ break;
+ case 0x47 ... 0x48: /* kp7,8 */
+ lis302dl_trigger(s->lis302dl, 2, keycode - 0x47, !release);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void n900_reset(void *opaque)
+{
+ struct n900_s *s = opaque;
+ omap_gpmc_attach(s->cpu->gpmc, N900_ONENAND_CS, 0, onenand_base_update,
+ onenand_base_unmap, s->nand, 0);
+ omap_gpmc_attach(s->cpu->gpmc, N900_SMC_CS, smc91c111_iomemtype(s->smc),
+ NULL, NULL, s->smc, 0);
+ qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_KBLOCK_GPIO));
+ qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_HEADPHONE_GPIO));
+ qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_CAMLAUNCH_GPIO));
+ qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_CAMFOCUS_GPIO));
+ qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N900_CAMCOVER_GPIO));
+ qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N900_SLIDE_GPIO));
+ s->slide_open = 1;
+ s->camera_cover_open = 0;
+ s->headphone_connected = 0;
+ omap3_boot_rom_emu(s->cpu);
+}
+
+static void n900_shutdown_timer_callback(void *opaque)
+{
+ static int power_state = 0;
+ struct n900_s *s = opaque;
+ power_state = !power_state;
+ twl4030_set_powerbutton_state(s->twl4030, power_state);
+ qemu_mod_timer(s->shutdown_timer,
+ qemu_get_clock(vm_clock)
+ + get_ticks_per_sec() * (power_state ? 5LL : 1LL));
+}
+
+static int n900_display_close_callback(void *opaque)
+{
+ struct n900_s *s = opaque;
+ if (s->shutdown_timer == NULL) {
+ s->shutdown_timer = qemu_new_timer(vm_clock,
+ n900_shutdown_timer_callback,
+ s);
+ n900_shutdown_timer_callback(s);
+ }
+ return 0;
+}
+
+static const TWL4030KeyMap n900_twl4030_keymap[] = {
+ {0x10, 0, 0}, /* Q */
+ {0x11, 0, 1}, /* W */
+ {0x12, 0, 2}, /* E */
+ {0x13, 0, 3}, /* R */
+ {0x14, 0, 4}, /* T */
+ {0x15, 0, 5}, /* Y */
+ {0x16, 0, 6}, /* U */
+ {0x17, 0, 7}, /* I */
+ {0x18, 1, 0}, /* O */
+ {0x20, 1, 1}, /* D */
+ {0x34, 1, 2}, /* . */
+ {0x2f, 1, 3}, /* V */
+ {0xd0, 1, 4}, /* DOWN */
+ {0x41, 1, 7}, /* F7 -- volume/zoom down */
+ {0x19, 2, 0}, /* P */
+ {0x21, 2, 1}, /* F */
+ {0xc8, 2, 2}, /* UP */
+ {0x30, 2, 3}, /* B */
+ {0xcd, 2, 4}, /* RIGHT */
+ {0x42, 2, 7}, /* F8 -- volume/zoom up */
+ {0x33, 3, 0}, /* , */
+ {0x22, 3, 1}, /* G */
+ {0x1c, 3, 2}, /* ENTER */
+ {0x31, 3, 3}, /* N */
+ {0x0e, 4, 0}, /* BACKSPACE */
+ {0x23, 4, 1}, /* H */
+ {0x32, 4, 3}, /* M */
+ {0x1d, 4, 4}, /* LEFTCTRL */
+ {0x24, 5, 1}, /* J */
+ {0x2c, 5, 2}, /* Z */
+ {0x39, 5, 3}, /* SPACE */
+ {0x38, 5, 4}, /* LEFTALT -- "fn" */
+ {0x1e, 6, 0}, /* A */
+ {0x25, 6, 1}, /* K */
+ {0x2d, 6, 2}, /* X */
+ {0x39, 6, 3}, /* SPACE */
+ {0x2a, 6, 4}, /* LEFTSHIFT */
+ {0x1f, 7, 0}, /* S */
+ {0x26, 7, 1}, /* L */
+ {0x2e, 7, 2}, /* C */
+ {0xcb, 7, 3}, /* LEFT */
+ // {0x10, 0xff, 2}, /* F9 */
+ // {0x10, 0xff, 4}, /* F10 */
+ // {0x10, 0xff, 5}, /* F11 */
+ {-1, -1, -1}
+};
+
+static MouseTransformInfo n900_pointercal = {
+ .x = 800,
+ .y = 480,
+ .a = {14114, 18, -2825064, 34, -8765, 32972906, 65536},
+};
+
+static void n900_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ struct n900_s *s = qemu_mallocz(sizeof(*s));
+ DriveInfo *dmtd = drive_get(IF_MTD, 0, 0);
+ DriveInfo *dsd = drive_get(IF_SD, 0, 0);
+
+ if (!dmtd && !dsd) {
+ hw_error("%s: SD or NAND image required", __FUNCTION__);
+ }
+ s->cpu = omap3530_mpu_init(N900_SDRAM_SIZE,
+ serial_hds[1],
+ serial_hds[2],
+ serial_hds[0]);
+ s->lcd = omap3_lcd_panel_init(s->cpu->dss);
+ omap_lcd_panel_attach(s->cpu->dss, omap3_lcd_panel_get(s->lcd));
+
+ s->tsc2005 = tsc2005_init(omap2_gpio_in_get(s->cpu->gpif,
+ N900_TSC2005_IRQ_GPIO));
+ tsc2005_set_transform(s->tsc2005, &n900_pointercal, 600, 1500);
+ omap_mcspi_attach(s->cpu->mcspi[0], tsc2005_txrx, s->tsc2005, 0);
+ cursor_hide = 0; // who wants to use touchscreen without a pointer?
+ cursor_allow_grab = 0; // ...and please, don't stop the host cursor
+
+ s->mipid = mipid_init();
+ s->mipid->n900 = 1;
+ s->mipid->id = 0x101234;
+ omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, s->mipid, 2);
+
+ s->nand = onenand_init(NAND_MFR_SAMSUNG, 0x40, 0x121, 1,
+ omap2_gpio_in_get(s->cpu->gpif, N900_ONENAND_GPIO),
+ dmtd);
+
+ if (dsd) {
+ omap3_mmc_attach(s->cpu->omap3_mmc[1], dsd, 0, 1);
+ }
+ if ((dsd = drive_get(IF_SD, 0, 1)) >= 0) {
+ omap3_mmc_attach(s->cpu->omap3_mmc[0], dsd, 0, 0);
+ //qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_SDCOVER_GPIO));
+ }
+
+ cpu_register_physical_memory(0x48058000, 0x3c00,
+ cpu_register_io_memory(ssi_read_func,
+ ssi_write_func,
+ 0));
+
+ s->twl4030 = twl4030_init(omap_i2c_bus(s->cpu->i2c[0]),
+ s->cpu->irq[0][OMAP_INT_3XXX_SYS_NIRQ],
+ NULL, n900_twl4030_keymap);
+ s->bq2415x = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[1]),
+ "bq2415x", 0x6b);
+ s->tpa6130 = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[1]),
+ "tpa6130", 0x60);
+ omap2_gpio_out_set(s->cpu->gpif, N900_HEADPHONE_EN_GPIO,
+ tpa6130_get_irq(s->tpa6130, 0));
+ s->lis302dl = lis302dl_init(i2c_create_slave(omap_i2c_bus(s->cpu->i2c[2]),
+ "lis302dl", 0x1d),
+ omap2_gpio_in_get(s->cpu->gpif,
+ N900_LIS302DL_INT1_GPIO),
+ omap2_gpio_in_get(s->cpu->gpif,
+ N900_LIS302DL_INT2_GPIO));
+
+ s->smc = smc91c111_init_lite(&nd_table[0], /*0x08000000,*/
+ omap2_gpio_in_get(s->cpu->gpif, 54));
+
+ qemu_add_kbd_event_handler(n900_key_handler, s);
+ qemu_set_display_close_handler(n900_display_close_callback, s);
+
+ qemu_register_reset(n900_reset, s);
+ n900_reset(s);
+}
+
+static QEMUMachine n900_machine = {
+ .name = "n900",
+ .desc = "Nokia N900 (OMAP3)",
+ .init = n900_init,
+};
+
static void nseries_register_devices(void)
{
i2c_register_slave(&bq2415x_info);
@@ -2139,6 +2418,7 @@ static void nseries_machine_init(void)
{
qemu_register_machine(&n800_machine);
qemu_register_machine(&n810_machine);
+ qemu_register_machine(&n900_machine);
}
device_init(nseries_register_devices);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 33/48] Add OpenGL ES accelerator support
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (27 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 32/48] Add beagleboard and n900 machine definitions Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 34/48] target-arm: add support for smc Riku Voipio
` (15 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 111005 bytes --]
From: Riku Voipio <riku.voipio@nokia.com>
To make it possible to use UI's based OpenGL ES efficiently
in qemu emulator, we need to offload the rendering to the host.
This patch provides the QEMU side of the code for omap3 emulation.
A kernel module, gles wrapper library inside qemu target filesystem,
and a gles library outside qemu are still needed. These will be
provided outside qemu project at:
http://maemo.gitorious.org/qemu-maemo/gles-libs
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>
---
Makefile.target | 18 +
configure | 41 +-
hw/gles2.c | 764 ++++++++++++++++
hw/gles2.h | 323 +++++++
hw/gles2_calls.c | 2409 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/gles2_calls.h | 189 ++++
hw/nseries.c | 10 +
qemu-options.hx | 19 +
target-arm/helper.c | 10 +-
vl.c | 10 +
10 files changed, 3790 insertions(+), 3 deletions(-)
create mode 100644 hw/gles2.c
create mode 100644 hw/gles2.h
create mode 100644 hw/gles2_calls.c
create mode 100644 hw/gles2_calls.h
diff --git a/Makefile.target b/Makefile.target
index c14d496..60211a3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -309,6 +309,24 @@ obj-y += $(addprefix ../libdis/, $(libdis-y))
obj-y += $(libobj-y)
obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
+ifeq ($(TARGET_BASE_ARCH), arm)
+ifdef CONFIG_GLES2
+CFLAGS+=-I$(DGLES2)/include
+LIBS+=-L$(DGLES2)/lib
+ifdef CONFIG_GLES2_STATIC
+LIBS+=-Wl,-Bstatic -lEGL -lGLESv2 -lOSMesa -Wl,-Bdynamic
+else
+LIBS+=-lEGL -lGLESv2
+endif
+ifndef CONFIG_WIN32
+LIBS+=-LX11 -ldl
+endif
+gles2_calls.o: gles2_calls.c gles2.h gles2_calls.h
+gles2.o: gles2.c gles2.h gles2_calls.h
+obj-arm-y += gles2.o gles2_calls.o
+endif # CONFIG_GLES2
+endif # TARGET_BASE_ARCH==arm
+
endif # CONFIG_SOFTMMU
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
diff --git a/configure b/configure
index 6bc40a3..70f5c61 100755
--- a/configure
+++ b/configure
@@ -295,6 +295,8 @@ blobs="yes"
pkgversion=""
check_utests="no"
user_pie="no"
+gles2="no"
+gles2_static="no"
zero_malloc=""
# OS specific
@@ -651,6 +653,12 @@ for opt do
;;
--enable-docs) docs="yes"
;;
+ --enable-gles2) gles2="yes"; gles2dir="/usr";
+ ;;
+ --enable-gles2-static) gles2="yes"; gles2_static="yes" gles2dir="/usr";
+ ;;
+ --gles2dir=*) gles2dir="$optarg"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -806,6 +814,9 @@ echo " --disable-blobs disable installing provided firmware blobs"
echo " --kerneldir=PATH look for kernel includes in PATH"
echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
+echo " --enable-gles2 ARM target: Enable OpenGL ES 2.0 hardware accelerator"
+echo " --enable-gles2-static ARM target: Link OpenGL ES 2.0 hardware accelerator statically"
+echo " --gles2dir=PATH prefix where dgles2 is installed"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@@ -1629,6 +1640,21 @@ if compile_prog "" "" ; then
inotify=yes
fi
+inotify1=no
+cat > $TMPC << EOF
+#include <sys/inotify.h>
+
+int
+main(void)
+{
+ /* try to start inotify */
+ return inotify_init1(0);
+}
+EOF
+if compile_prog "" "" ; then
+ inotify1=yes
+fi
+
# check if utimensat and futimens are supported
utimens=no
cat > $TMPC << EOF
@@ -1966,8 +1992,9 @@ echo "Install blobs $blobs"
echo "KVM support $kvm"
echo "fdt support $fdt"
echo "preadv support $preadv"
-echo "fdatasync $fdatasync"
-echo "uuid support $uuid"
+echo "gles2 support $gles2"
+echo "gles2 static $gles2_static"
+echo "dgles2 prefix $gles2dir"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2136,6 +2163,9 @@ fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
+if test "$inotify1" = "yes" ; then
+ echo "CONFIG_INOTIFY1=y" >> $config_host_mak
+fi
if test "$byteswap_h" = "yes" ; then
echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
fi
@@ -2183,6 +2213,13 @@ fi
if test "$fdatasync" = "yes" ; then
echo "CONFIG_FDATASYNC=y" >> $config_host_mak
fi
+if test "$gles2" = "yes" ; then
+ echo "CONFIG_GLES2=y" >> $config_host_mak
+if test "$gles2_static" = "yes" ; then
+ echo "CONFIG_GLES2_STATIC=y" >> $config_host_mak
+fi
+ echo "DGLES2=$gles2dir" >> $config_host_mak
+fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
diff --git a/hw/gles2.c b/hw/gles2.c
new file mode 100644
index 0000000..51583e2
--- /dev/null
+++ b/hw/gles2.c
@@ -0,0 +1,764 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) any later version of the License.
+ *
+ * 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 "gles2.h"
+#include <pthread.h>
+
+// From target-arm/helper.c.
+extern int get_phys_addr(CPUState *env, uint32_t address,
+ int access_type, int is_user,
+ uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size);
+
+
+// Information holder for guest->host call.
+struct gles2_Call
+{
+#ifndef NDEBUG
+ char const* name;
+#endif //!NDEBUG
+ gles2_Callback* callback;
+};
+
+// List of calls to used by the kernel module (page 0).
+static gles2_Call const gles2_kcalls[];
+// List of calls used by clients (page 1->15).
+static gles2_Call const gles2_calls[];
+int gles2_quality = 100;
+
+// Translate a target virtual address to physical address.
+static target_ulong gles2_pa(gles2_State *s, target_ulong va,
+ int access_type)
+{
+ target_ulong pa, ps;
+ int prot;
+
+ if (get_phys_addr(s->env, va, access_type, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Page fault on guest!\n");
+ return 0;
+ }
+
+ return pa;
+}
+
+int gles2_transfer_compile(gles2_CompiledTransfer* tfr, gles2_State *s,
+ target_ulong va, target_ulong len)
+{
+ tfr->nsections = 0;
+ tfr->sections = 0;
+
+#if (GLES2_DEBUG == 1)
+ target_ulong first_page = TARGET_PAGE(va);
+#endif // GLES2_DEBUG == 1
+
+ target_ulong last_page = TARGET_PAGE(va + len - 1);
+ target_ulong start_addr = va;
+
+ GLES2_PRINT("DEBUG: Compiling transfer of %d bytes at 0x%x (0x%x->0x%x).\n",
+ len, va, first_page, last_page);
+
+ // Loop through the pages.
+ while (len) {
+ target_ulong start_page = TARGET_PAGE(start_addr);
+ target_ulong start_pa = gles2_pa(s, start_page, 0);
+ target_ulong end_pa = start_pa;
+
+ // Solve length of continuous section.
+ target_ulong end_page = start_page;
+ while(end_page < last_page) {
+ target_ulong next_page = end_page + TARGET_PAGE_SIZE;
+ target_ulong next_pa = gles2_pa(s, next_page, 0);
+
+ // If the target pages are not linearly spaced, stop..
+ if((next_pa < start_pa) ||
+ (next_pa - start_pa > next_page - start_page)) {
+ break;
+ }
+
+ end_page = next_page;
+ end_pa = next_pa;
+ }
+
+ unsigned id = tfr->nsections++;
+
+ GLES2_PRINT("\tContinuous from 0x%x to 0x%x (0x%x to 0x%x) #%d.\n",
+ start_page, end_page, start_pa, end_pa, id);
+ tfr->sections = realloc(tfr->sections,
+ tfr->nsections*sizeof(*(tfr->sections)));
+
+ target_phys_addr_t pages_len = end_page + TARGET_PAGE_SIZE - start_page;
+ void* target_pages = cpu_physical_memory_map(start_pa, &pages_len, 0);
+
+ if (!target_pages || !pages_len) {
+ fprintf(stderr, "ERROR: Failed to map memory to host!\n");
+ return 0;
+ }
+
+ target_ulong section_len = end_page + TARGET_PAGE_SIZE - start_addr;
+
+ if (section_len > len) {
+ section_len = len;
+ }
+
+ target_ulong offset = TARGET_OFFSET(start_addr);
+ void* target_data = target_pages + offset;
+
+ GLES2_PRINT("\tSlice of %d bytes at %p (offset = %x).\n",
+ section_len, target_data, offset);
+
+ tfr->sections[id].base = target_data;
+ tfr->sections[id].len = section_len;
+
+ cpu_physical_memory_unmap(target_pages, pages_len, 0, pages_len);
+ len -= section_len;
+ start_addr += section_len;
+ GLES2_PRINT("\t%d bytes remain...\n", len);
+ }
+ return 1;
+}
+
+void gles2_transfer_exec(gles2_CompiledTransfer* tfr, gles2_State *s,
+ void* data, int access_type)
+{
+ unsigned i;
+
+ for (i = 0; i < tfr->nsections; ++i) {
+ void* target_data = tfr->sections[i].base;
+ target_ulong len = tfr->sections[i].len;
+ if (access_type == 0) {
+ memcpy(data, target_data, len);
+ } else {
+ memcpy(target_data, data, len);
+ }
+ data += len;
+ }
+}
+
+void gles2_transfer_free(gles2_CompiledTransfer* tfr)
+{
+ free(tfr->sections);
+ tfr->sections = 0;
+ tfr->nsections = 0;
+}
+
+int gles2_transfer(gles2_State *s, target_ulong va, target_ulong len,
+ void* data, int access_type)
+{
+#if (GLES2_DEBUG == 1)
+ target_ulong first_page = TARGET_PAGE(va);
+#endif // GLES2_DEBUG == 1
+
+ target_ulong last_page = TARGET_PAGE(va + len - 1);
+ target_ulong start_addr = va;
+
+ GLES2_PRINT("DEBUG: Request transfer of %d bytes at 0x%x (0x%x->0x%x) (access=%d).\n",
+ len, va, first_page, last_page, access_type);
+
+ // Loop through the pages.
+ while (len) {
+ target_ulong start_page = TARGET_PAGE(start_addr);
+ target_ulong start_pa = gles2_pa(s, start_page, access_type);
+ target_ulong end_pa = start_pa;
+
+ // Solve length of continuous section.
+ target_ulong end_page = start_page;
+ while(end_page < last_page) {
+ target_ulong next_page = end_page + TARGET_PAGE_SIZE;
+ target_ulong next_pa = gles2_pa(s, next_page, access_type);
+
+ // If the target pages are not linearly spaced, stop..
+ if ((next_pa < start_pa) ||
+ (next_pa - start_pa > next_page - start_page)) {
+ break;
+ }
+
+ end_page = next_page;
+ end_pa = next_pa;
+ }
+
+ GLES2_PRINT("\tContinuous from 0x%x to 0x%x (0x%x to 0x%x).\n",
+ start_page, end_page, start_pa, end_pa);
+
+ target_phys_addr_t pages_len = end_page + TARGET_PAGE_SIZE - start_page;
+ void* target_pages = cpu_physical_memory_map(start_pa, &pages_len, access_type);
+ if (!target_pages || !pages_len) {
+ GLES2_PRINT("ERROR: Failed to map memory to host!\n");
+ return 0;
+ }
+
+ target_ulong section_len = end_page + TARGET_PAGE_SIZE - start_addr;
+ target_ulong offset = TARGET_OFFSET(start_addr);
+ void* target_data = target_pages + offset;
+
+ if (section_len > len) {
+ section_len = len;
+ }
+
+ GLES2_PRINT("\tTransfering %d bytes at %p (offset = %x).\n",
+ section_len, target_data, offset);
+
+ if (access_type == 0) {
+ memcpy(data, target_data, section_len);
+ } else {
+ memcpy(target_data, data, section_len);
+ }
+
+ cpu_physical_memory_unmap(target_pages, pages_len, access_type, pages_len);
+ len -= section_len;
+ start_addr += section_len;
+ data += section_len;
+
+ GLES2_PRINT("\t%d bytes remain...\n", len);
+ }
+ return 1;
+}
+
+void gles2_put_byte(gles2_State *s, target_ulong va, uint8_t byte)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written 0x%x to 0x%x(0x%x)\n", byte, va, pa);
+ stb_phys(pa, byte);
+}
+
+uint8_t gles2_get_byte(gles2_State *s, target_ulong va)
+{
+ uint8_t byte;
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return 0xDE;
+ }
+
+ byte = ldub_phys(pa);
+
+ GLES2_PRINT("DEBUG: Read 0x%x from 0x%x(0x%x)\n", byte, va, pa);
+
+ return byte;
+}
+
+void gles2_put_word(gles2_State *s, target_ulong va, uint16_t word)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written 0x%x to 0x%x(0x%x)\n", word, va, pa);
+ stw_phys(pa, word);
+}
+
+uint16_t gles2_get_word(gles2_State *s, target_ulong va)
+{
+ uint16_t word;
+
+ int prot;
+ target_ulong pa, ps;
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return 0xDEAD;
+ }
+
+ word = lduw_phys(pa);
+
+ GLES2_PRINT("DEBUG: Read 0x%x from 0x%x(0x%x)\n", word, va, pa);
+
+ return word;
+}
+
+uint32_t gles2_get_dword(gles2_State *s, target_ulong va)
+{
+ uint32_t dword;
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return 0xDEAD000;
+ }
+
+ dword = ldl_phys(pa);
+
+ GLES2_PRINT("DEBUG: Read 0x%x from 0x%x(0x%x)\n", dword, va, pa);
+
+ return dword;
+}
+
+void gles2_put_dword(gles2_State *s, target_ulong va, uint32_t dword)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written 0x%x to 0x%x(0x%x)\n", dword, va, pa);
+ stl_phys(pa, dword);
+}
+
+float gles2_get_float(gles2_State *s, target_ulong va)
+{
+ float flt;
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return -123456789.f;
+ }
+
+ cpu_physical_memory_read(pa, (unsigned char*)&flt, 4);
+ // flt = ldfl_p(pa);
+
+ GLES2_PRINT("DEBUG: Read %f from 0x%x(0x%x)\n", flt, va, pa);
+
+ return flt;
+}
+
+void gles2_put_float(gles2_State *s, target_ulong va, float flt)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written %f to 0x%x(0x%x)\n", flt, va, pa);
+ cpu_physical_memory_write(pa, (unsigned char*)&flt, 4);
+ // stfl_p(pa, flt);
+}
+
+uint32_t gles2_handle_create(gles2_State *s, void* data)
+{
+ uint32_t i = 0;
+
+ if (data) {
+ for (i = 0; i < GLES2_NHANDLES; ++i) {
+ if (!s->handles[i]) {
+ break;
+ }
+ }
+
+ if (i == GLES2_NHANDLES) {
+ fprintf(stderr, "ERROR: No free handles!\n");
+ return 0x0;
+ }
+ s->handles[i] = data;
+ i |= GLES2_HANDLE_BASE;
+ }
+
+ GLES2_PRINT("Handle %x created for %p!\n", i, data);
+ return i;
+}
+
+uint32_t gles2_handle_find(gles2_State *s, void* data)
+{
+ uint32_t i = 0;
+
+ if (data) {
+ for(i = 0; i < GLES2_NHANDLES; ++i) {
+ if(s->handles[i] == data) {
+ break;
+ }
+ }
+
+ if (i == GLES2_NHANDLES) {
+// fprintf(stderr, "ERROR: Handle not found!\n");
+ return 0x0;
+ }
+ i |= GLES2_HANDLE_BASE;
+ }
+
+ GLES2_PRINT("Handle %x found for %p!\n", i, data);
+ return i;
+}
+
+void* gles2_handle_get(gles2_State *s, uint32_t i)
+{
+#if(GLES2_DEBUG == 1)
+ if(i && (i & ~GLES2_HANDLE_MASK) != GLES2_HANDLE_BASE)
+ {
+ GLES2_PRINT("ERROR: Invalid handle %x!\n", i);
+ exit(1);
+ }
+#endif // GLES2_DEBUG == 1
+
+ void* data = i ? s->handles[i & GLES2_HANDLE_MASK] : NULL;
+
+ GLES2_PRINT("Reading handle %x => %p\n", i, data);
+
+ return data;
+}
+
+void* gles2_handle_free(gles2_State *s, uint32_t i)
+{
+ void* data = NULL;
+ if (i) {
+ data = s->handles[i & GLES2_HANDLE_MASK];
+ s->handles[i & GLES2_HANDLE_MASK] = NULL;
+ }
+
+ GLES2_PRINT("Freed handle %i => %p\n", i, data);
+ return data;
+}
+
+// Virtual register area write operation handler.
+static void gles2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ gles2_State *s = (gles2_State*)opaque;
+
+ target_ulong page = addr/(4*TARGET_PAGE_SIZE);
+ target_ulong callnr = TARGET_OFFSET(addr)/0x04;
+
+ GLES2_PRINT("Page %d write (call nr. %d).\n", page, callnr);
+
+ if (page) {
+ gles2_Call const *call = gles2_calls + callnr;
+
+ if (page > 1) {
+ gles2_Client* client;
+
+ // Client API calls without active context should be ignored.
+ if ((page - 2 > GLES2_NCLIENTS) ||
+ !(client = s->clients[page - 2])) {
+ return;
+ }
+
+ // Make sure nothing is running.
+ GLES2_PRINT("Syncing with worker...\n");
+ pthread_mutex_lock(&client->mutex_wait);
+ while (client->state != gles2_ClientState_ready) {
+ pthread_cond_wait(&client->cond_state, &client->mutex_wait);
+ }
+ pthread_mutex_lock(&client->mutex_run);
+ pthread_mutex_lock(&client->mutex_xcode);
+ client->call = call;
+ client->state = gles2_ClientState_pending;
+ client->phase_xcode = 0;
+ GLES2_PRINT("Requesting call %s...\n", call->name);
+ pthread_cond_signal(&client->cond_start);
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ GLES2_PRINT("Releasing worker for decoding...\n");
+ pthread_mutex_unlock(&client->mutex_run);
+ do {
+ pthread_cond_wait(&client->cond_xcode, &client->mutex_xcode);
+ } while (client->phase_xcode < 1);
+
+ pthread_mutex_unlock(&client->mutex_xcode);
+ GLES2_PRINT("Decoding finished.\n");
+ } else {
+ gles2_decode_t d = 0;
+ GLES2_PRINT("Calling clientless function %s...\n", call->name);
+ call->callback(s, &d, 0);
+ }
+ } else {
+ gles2_Call const *call = gles2_kcalls + callnr;
+ gles2_decode_t d = 0;
+
+ GLES2_PRINT("Calling kernel function %s...\n", call->name);
+
+ call->callback(s, &d, 0);
+ }
+}
+
+// Virtual register area read operation handler.
+static uint32_t gles2_read(void *opaque, target_phys_addr_t addr)
+{
+ gles2_State *s = (gles2_State*)opaque;
+
+ target_ulong page = addr/(4*TARGET_PAGE_SIZE);
+
+ if (page) {
+ gles2_Client* client;
+
+ // Client API calls without active context should be ignored.
+ if ((page - 2 > GLES2_NCLIENTS) ||
+ !(client = s->clients[page - 2])) {
+ return 0;
+ }
+
+ if(pthread_mutex_trylock(&client->mutex_xcode)) {
+ return 1;
+ }
+
+ if(client->phase_xcode == 2) {
+ while (client->phase_xcode < 4) {
+ client->phase_xcode = 3;
+ pthread_cond_signal(&client->cond_return);
+ pthread_cond_wait(&client->cond_xcode, &client->mutex_xcode);
+ }
+ pthread_mutex_unlock(&client->mutex_xcode);
+ return 0;
+ }
+ int ret = (client->phase_xcode == 4 ? 0 : 1);
+ pthread_mutex_unlock(&client->mutex_xcode);
+ return ret;
+ }
+ return 0;
+}
+
+static CPUReadMemoryFunc *gles2_readfn[] = {
+ gles2_read,
+ gles2_read,
+ gles2_read,
+};
+
+static CPUWriteMemoryFunc *gles2_writefn[] = {
+ gles2_write,
+ gles2_write,
+ gles2_write,
+};
+
+// Initializes a new gles2 device.
+void *gles2_init(CPUState *env)
+{
+ gles2_State *s = qemu_malloc(sizeof(*s));
+ unsigned i;
+
+ s->env = env;
+ s->quality = gles2_quality;
+
+ GLES2_PRINT("GLES2 quality: %d\n", s->quality);
+
+ cpu_register_physical_memory(GLES2_HWBASE,
+ GLES2_HWSIZE,
+ cpu_register_io_memory(gles2_readfn,
+ gles2_writefn, s));
+
+ for (i = 0; i < GLES2_NCLIENTS; ++i) {
+ s->clients[i] = NULL;
+ }
+
+ for (i = 0; i < GLES2_NHANDLES; ++i) {
+ s->handles[i] = NULL;
+ }
+
+ GLES2_PRINT("Registered IO memory!\n");
+ return s;
+}
+
+/******************************************************************************
+ *
+ * Kernel interface functions.
+ *
+ *****************************************************************************/
+
+static void* gles2_client_worker(void *opaque)
+{
+ gles2_Client *client = opaque;
+ int run = 1;
+
+ GLES2_PRINT("WORKER(%d): Starting!\n", client->nr);
+
+ pthread_mutex_lock(&client->mutex_xcode);
+ do
+ {
+ gles2_decode_t d = 0;
+ GLES2_PRINT("WORKER(%d): Waiting for call...\n", client->nr);
+ pthread_mutex_lock(&client->mutex_wait);
+
+ client->state = gles2_ClientState_ready;
+ pthread_cond_signal(&client->cond_state);
+ client->phase_xcode = 4;
+ pthread_cond_signal(&client->cond_xcode);
+ pthread_mutex_unlock(&client->mutex_xcode);
+ while (client->state != gles2_ClientState_pending) {
+ pthread_cond_wait(&client->cond_start, &client->mutex_wait);
+ }
+
+ GLES2_PRINT("WORKER(%d): Got call, waiting permission to run...\n", client->nr);
+
+ pthread_mutex_lock(&client->mutex_run);
+ GLES2_PRINT("WORKER(%d): Running!\n", client->nr);
+ client->state = gles2_ClientState_running;
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ if (client->call) {
+ GLES2_PRINT("WORKER(%d): Calling function %s (%p)...\n",
+ client->nr, client->call->name, client->call);
+ client->call->callback(client->s, &d, client);
+
+ GLES2_PRINT("\tWORKER(%d): Done.\n", client->nr);
+ client->state = gles2_ClientState_done;
+ } else {
+ GLES2_PRINT("WORKER(%d): Exit requested!\n", client->nr);
+ run = 0;
+ client->state = gles2_ClientState_exit;
+ pthread_cond_signal(&client->cond_state);
+ }
+ pthread_mutex_unlock(&client->mutex_run);
+ } while (run);
+
+ GLES2_PRINT("WORKER(%d): Exiting!\n", client->nr);
+ return opaque;
+}
+
+// Called by kernel module when a new client connects.
+static void gles2_init_cb(gles2_State *s, gles2_decode_t *d, gles2_Client *c)
+{
+ unsigned i;
+ gles2_Client *client;
+ pthread_attr_t attr;
+
+ for (i = 0; i < GLES2_NCLIENTS; ++i) {
+ if (!s->clients[i]) {
+ break;
+ }
+ }
+
+ if (i == GLES2_NCLIENTS) {
+ GLES2_PRINT("ERROR: No free slots!\n");
+ gles2_ret_dword(s, 0);
+ return;
+ }
+
+ GLES2_PRINT("Initialization!\n");
+
+ client = malloc(sizeof(*client));
+ client->s = s;
+ client->nr = i + 1;
+ pthread_mutex_init(&client->mutex_wait, NULL);
+ pthread_mutex_init(&client->mutex_run, NULL);
+ pthread_mutex_init(&client->mutex_xcode, NULL);
+ pthread_cond_init(&client->cond_start, NULL);
+ pthread_cond_init(&client->cond_state, NULL);
+ pthread_cond_init(&client->cond_xcode, NULL);
+ pthread_cond_init(&client->cond_return, NULL);
+ client->state = gles2_ClientState_init;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_mutex_lock(&client->mutex_wait);
+
+ GLES2_PRINT("Creating worker...\n");
+ pthread_create(&client->thread, &attr, gles2_client_worker, client);
+
+ do {
+ pthread_cond_wait(&client->cond_state, &client->mutex_wait);
+ } while(client->state != gles2_ClientState_ready);
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ GLES2_PRINT("Worker initialized\n");
+
+ s->clients[i] = client;
+ gles2_ret_dword(s, client->nr);
+}
+
+// Called by kernel module when an existing client disconnects.
+static void gles2_exit_cb(gles2_State *s, gles2_decode_t *d, gles2_Client *c)
+{
+ uint32_t nr = gles2_arg_dword(s, d);
+ gles2_Client *client;
+
+ GLES2_PRINT("Exit called for client %d!\n", nr);
+
+ if ((nr > GLES2_NCLIENTS + 1) ||
+ (nr == 0)) {
+ GLES2_PRINT("Client number out of range!\n");
+ return;
+ } else {
+ client = s->clients[nr - 1];
+ }
+
+ if (!client) {
+ GLES2_PRINT("Can't exit NULL client!\n");
+ return;
+ }
+
+ GLES2_PRINT("\tRequesting worker to exit.\n");
+
+ // Make sure nothing is running.
+ GLES2_PRINT("Syncing with worker...\n");
+ pthread_mutex_lock(&client->mutex_wait);
+ while (client->state != gles2_ClientState_ready) {
+ pthread_cond_wait(&client->cond_state, &client->mutex_wait);
+ }
+ pthread_mutex_lock(&client->mutex_run);
+ client->call = NULL;
+ client->state = gles2_ClientState_pending;
+ GLES2_PRINT("Requesting exit...\n");
+ pthread_cond_signal(&client->cond_start);
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ GLES2_PRINT("Waiting worker to exit...\n");
+ do {
+ pthread_cond_wait(&client->cond_state, &client->mutex_run);
+ } while (client->state != gles2_ClientState_exit);
+ pthread_mutex_unlock(&client->mutex_run);
+
+ GLES2_PRINT("\tJoining...\n");
+ pthread_join(client->thread, NULL);
+ pthread_mutex_destroy(&client->mutex_wait);
+ pthread_mutex_destroy(&client->mutex_run);
+ pthread_cond_destroy(&client->cond_start);
+ pthread_cond_destroy(&client->cond_state);
+
+ free(client);
+ s->clients[nr - 1] = NULL;
+
+ GLES2_PRINT("\tDone!\n");
+}
+
+/******************************************************************************
+ *
+ * Call tables
+ *
+ *****************************************************************************/
+
+/* Make a weak stub for every dummy function. */
+#define CALL_DUMMY(func) \
+ void gles2_##func##_cb(gles2_State *s, gles2_decode_t *d, struct gles2_Client *c); \
+ void gles2_##func##_cb(gles2_State *s, gles2_decode_t *d, struct gles2_Client *c) \
+ { \
+ fprintf(stderr, "GLES2: DUMMY " #func "\n"); \
+ }
+
+#define CALL_ENTRY(func) \
+ void gles2_##func##_cb(gles2_State *s, gles2_decode_t *d, struct gles2_Client *c);
+
+#include "gles2_calls.h"
+
+#undef CALL_ENTRY
+#undef CALL_DUMMY
+
+#define CALL_ENTRY(func) { #func, gles2_##func##_cb },
+#define CALL_DUMMY(func) { #func, gles2_##func##_cb },
+
+static gles2_Call const gles2_kcalls[] =
+{
+ CALL_ENTRY(init)
+ CALL_ENTRY(exit)
+};
+
+static gles2_Call const gles2_calls[] =
+{
+ { "<<none>>", 0 },
+#include "gles2_calls.h"
+};
+
+#undef CALL_ENTRY
+
diff --git a/hw/gles2.h b/hw/gles2.h
new file mode 100644
index 0000000..424d4ce
--- /dev/null
+++ b/hw/gles2.h
@@ -0,0 +1,323 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) any later version of the License.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GLES2_H__
+#define GLES2_H__
+
+#include "qemu-common.h"
+#include "cpu.h"
+#include <pthread.h>
+
+#define GLES2_HWBASE 0x4f000000
+#define GLES2_HWSIZE 0x00100000
+#define GLES2_NCLIENTS (GLES2_HWSIZE/TARGET_PAGE_SIZE - 2)
+#define GLES2_NHANDLES GLES2_NCLIENTS * 16
+// Address base for host to guest pointer handles.
+#define GLES2_HANDLE_BASE 0xCAFE0000
+#define GLES2_HANDLE_MASK 0x0000FFFF // Handle to index bitmask.
+
+// Round address to lower page boundary.
+#define TARGET_PAGE(addr) ((addr) & ~(TARGET_PAGE_SIZE - 1))
+// Return the page offset part of address.
+#define TARGET_OFFSET(addr) ((addr) & (TARGET_PAGE_SIZE - 1))
+
+#define GLES2_DEBUG 0
+#if(GLES2_DEBUG == 1)
+# define GLES2_PRINT(format, args...) \
+ fprintf(stderr, "GLES2: " format, ##args)
+#else
+# define GLES2_PRINT(format, args...) (void)0
+#endif // GLES_DEBUG != 1
+
+struct gles2_Array;
+typedef struct gles2_Array gles2_Array;
+struct gles2_Call;
+typedef struct gles2_Call gles2_Call;
+struct gles2_State;
+typedef struct gles2_State gles2_State;
+
+typedef enum gles2_ClientState
+{
+ gles2_ClientState_init,
+ gles2_ClientState_ready,
+ gles2_ClientState_pending,
+ gles2_ClientState_running,
+ gles2_ClientState_done,
+ gles2_ClientState_exit
+} gles2_ClientState;
+
+// A connected GLES2 client.
+typedef struct gles2_Client
+{
+ gles2_State *s; // Link to the device state the client was connected to.
+ target_ulong nr; // The client ID from kernel.
+
+ gles2_Call const *call; // Next/current call to perform.
+ pthread_t thread; // The worker thread.
+ pthread_cond_t cond_start; // To wake worker for a call.
+ pthread_cond_t cond_state; // Worker signals when state changes.
+ volatile gles2_ClientState state;// Status of the client.
+ pthread_mutex_t mutex_run; // Locked when thread is running, or is
+ // prevented from doing so.
+ pthread_mutex_t mutex_wait; // For synchronization of worker and caller.
+
+ pthread_mutex_t mutex_xcode; // For decode/encode synchronization.
+ volatile int phase_xcode; // Phase of call 0: pending 1: decode done
+ // 2: exec done 3: encode done
+ pthread_cond_t cond_xcode; // --''--
+ pthread_cond_t cond_return; // --''--
+
+ gles2_Array *arrays; // Host side vertex pointer arrays.
+ int narrays; // Number of arrays (the maximum too).
+} gles2_Client;
+
+// The GLES2 device state holder.
+struct gles2_State
+{
+ CPUState *env; // The CPU the device is attached to.
+ gles2_Client *clients[GLES2_NCLIENTS]; // Array of clients.
+ void *handles[GLES2_NHANDLES]; // Handles passed from host to guest.
+ int quality; // Rendering quality.
+};
+
+typedef unsigned int gles2_decode_t; // Function call decoding state.
+typedef uint32_t gles2_target_arg_t; // Target unit argument type.
+// Callback for register area access.
+typedef void gles2_Callback(gles2_State *s, gles2_decode_t *d,
+ gles2_Client *c);
+
+// Create and initialize a GLES2 device and attach to CPU.
+extern void *gles2_init(CPUState *env);
+// Rendering quality option.
+extern int gles2_quality;
+
+/******************************************************************************
+ *
+ * Guest memory continuous access functions
+ *
+ *****************************************************************************/
+
+// Holder for compiled transfer holder.
+typedef struct gles2_CompiledTransfer
+{
+ unsigned nsections; // Number of physical memory sections in the transfer.
+ struct
+ {
+ char* base; // Base address of the section.
+ target_ulong len; // Length of the section.
+ } *sections; // Sections of the transfer.
+} gles2_CompiledTransfer;
+
+// Pre-compile a transfer to or from virtual guest address.
+// NOTE: An assumption is made that the mapping is equal for read and write, for
+// complicated transfers, use gles2_transfer or Fix It!
+extern int gles2_transfer_compile(gles2_CompiledTransfer *tfr, gles2_State *s,
+ target_ulong va, target_ulong len);
+// Execute a pre-compiled transfer.
+extern void gles2_transfer_exec(gles2_CompiledTransfer *tfr, gles2_State *s,
+ void* data, int access_type);
+// Free a pre-compiled transfer.
+extern void gles2_transfer_free(gles2_CompiledTransfer *tfr);
+// Perform a non-compiled transfer between guest and host.
+// access_type, read = 0, write = 1, execute = 2
+extern int gles2_transfer(gles2_State *s, target_ulong va, target_ulong len,
+ void* data, int access_type);
+
+/******************************************************************************
+ *
+ * Guest memory random access functions
+ *
+ *****************************************************************************/
+
+// Read an 8-bit byte from target system memory.
+extern uint8_t gles2_get_byte(gles2_State *s, target_ulong va);
+// Write an 8-bit byte to target system memory.
+extern void gles2_put_byte(gles2_State *s, target_ulong va, uint8_t byte);
+// Read a 16-bit word from target system memory.
+extern uint16_t gles2_get_word(gles2_State *s, target_ulong va);
+// Write a 16-bit word to target system memory.
+extern void gles2_put_word(gles2_State *s, target_ulong va, uint16_t word);
+// Read a 32-bit double word from target system memory.
+extern uint32_t gles2_get_dword(gles2_State *s, target_ulong va);
+// Write a 32-bit double word to target system memory.
+extern void gles2_put_dword(gles2_State *s, target_ulong va,
+ uint32_t dword);
+// Read a 32-bit float from target system memory.
+extern float gles2_get_float(gles2_State *s, target_ulong va);
+// Write a 32-bit float to target system memory.
+extern void gles2_put_float(gles2_State *s, target_ulong va, float flt);
+
+#define gles2_put_handle(s, va, handle) gles2_put_dword(s, va, handle)
+#define gles2_get_handle(s, va) gles2_get_dword(s, va)
+
+/******************************************************************************
+ *
+ * Handle management functions
+ *
+ *****************************************************************************/
+
+// Create a handle from host side pointer to be passed to guest.
+extern uint32_t gles2_handle_create(gles2_State *s, void* data);
+// Find if there is previously created handle for pointer.
+extern uint32_t gles2_handle_find(gles2_State *s, void* data);
+// Get the host pointer by guest handle.
+extern void* gles2_handle_get(gles2_State *s, uint32_t i);
+// Release a handle for reuse.
+extern void* gles2_handle_free(gles2_State *s, uint32_t i);
+
+// Get the smallest function argument according to target CPU ABI.
+static inline gles2_target_arg_t gles2_arg_raw(gles2_State *s, unsigned i);
+static inline gles2_target_arg_t gles2_arg_raw(gles2_State *s, unsigned i)
+{
+ if (i < 4) {
+ return s->env->regs[i];
+ }
+
+ return gles2_get_dword(s, s->env->regs[13] + 2*0x04 + (i - 4)*0x04);
+}
+
+/******************************************************************************
+ *
+ * ABI function argument decoding functions
+ *
+ *****************************************************************************/
+
+#define GLES2_DEBUG_ARGS 1
+static inline uint8_t gles2_arg_byte(gles2_State *s, gles2_decode_t *d);
+static inline uint8_t gles2_arg_byte(gles2_State *s, gles2_decode_t *d)
+{
+ uint8_t byte = gles2_arg_raw(s, (*d)++) & 0xFF;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("byte arg(%d) = %x\n", *d - 1, byte);
+#endif
+ return byte;
+}
+
+static inline uint16_t gles2_arg_word(gles2_State *s, gles2_decode_t *d);
+static inline uint16_t gles2_arg_word(gles2_State *s, gles2_decode_t *d)
+{
+ uint16_t word = gles2_arg_raw(s, (*d)++) & 0xFFFF;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("word arg(%d) = %x\n", *d - 1, word);
+#endif
+ return word;
+}
+
+static inline uint32_t gles2_arg_dword(gles2_State *s, gles2_decode_t *d);
+static inline uint32_t gles2_arg_dword(gles2_State *s, gles2_decode_t *d)
+{
+ uint32_t dword = gles2_arg_raw(s, (*d)++);
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("dword arg(%d) = %x\n", *d - 1, dword);
+#endif
+ return dword;
+}
+
+static inline uint64_t gles2_arg_qword(gles2_State *s, gles2_decode_t *d);
+static inline uint64_t gles2_arg_qword(gles2_State *s, gles2_decode_t *d)
+{
+ uint64_t qword = gles2_arg_raw(s, (*d)++)
+ | ((uint64_t)gles2_arg_raw(s, (*d)++) << 32);
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("qword arg(%d) = %"PRIu64"\n", *d - 2, qword);
+#endif
+ return qword;
+}
+
+static inline uint32_t gles2_arg_handle(gles2_State *s, gles2_decode_t *d);
+static inline uint32_t gles2_arg_handle(gles2_State *s, gles2_decode_t *d)
+{
+ uint32_t handle = gles2_arg_raw(s, (*d)++);
+
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("handle arg(%d) = %x\n", *d - 1, handle);
+#endif
+ return handle;
+}
+
+// This needs to be its own special function, because we must preserve the byteorder.
+static inline float gles2_arg_float(gles2_State *s, gles2_decode_t *d);
+static inline float gles2_arg_float(gles2_State *s, gles2_decode_t *d)
+{
+ unsigned i = (*d)++;
+
+ if (i < 4) {
+ return *((float*)&s->env->regs[i]);
+ }
+
+ return gles2_get_float(s, s->env->regs[13] + 2*0x04 + (i - 4)*0x04);
+}
+
+/******************************************************************************
+ *
+ * ABI return value encoding functions
+ *
+ *****************************************************************************/
+
+static inline void gles2_ret_byte(gles2_State *s, uint8_t byte);
+static inline void gles2_ret_byte(gles2_State *s, uint8_t byte)
+{
+ s->env->regs[0] = byte;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("byte ret = %d\n", byte);
+#endif
+}
+
+static inline void gles2_ret_word(gles2_State *s, uint16_t word);
+static inline void gles2_ret_word(gles2_State *s, uint16_t word)
+{
+ s->env->regs[0] = word;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("word ret = %d\n", word);
+#endif
+}
+
+static inline void gles2_ret_dword(gles2_State *s, uint32_t dword);
+static inline void gles2_ret_dword(gles2_State *s, uint32_t dword)
+{
+ s->env->regs[0] = dword;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("dword ret = %d\n", dword);
+#endif
+}
+
+static inline void gles2_ret_qword(gles2_State *s, uint64_t qword);
+static inline void gles2_ret_qword(gles2_State *s, uint64_t qword)
+{
+ s->env->regs[0] = qword & 0xFFFFFFFF;
+ s->env->regs[1] = qword >> 32;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("qword ret = %"PRIu64"\n", qword);
+#endif
+}
+
+static inline void gles2_ret_handle(gles2_State *s, uint32_t handle);
+static inline void gles2_ret_handle(gles2_State *s, uint32_t handle)
+{
+ s->env->regs[0] = handle;
+
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("handle ret = %x\n", handle);
+#endif
+}
+
+static inline void gles2_ret_float(gles2_State *s, float flt);
+static inline void gles2_ret_float(gles2_State *s, float flt)
+{
+ s->env->regs[0] = *(uint32_t*)&flt;
+
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("float ret = %f\n", flt);
+#endif
+}
+
+#endif // GLES2_H__
+
diff --git a/hw/gles2_calls.c b/hw/gles2_calls.c
new file mode 100644
index 0000000..e4bad5b
--- /dev/null
+++ b/hw/gles2_calls.c
@@ -0,0 +1,2409 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) any later version of the License.
+ *
+ * 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 "gles2.h"
+#include "EGL/degl.h"
+#include "GLES2/gl2.h"
+
+// Automatically create the prototype and function definition.
+#define GLES2_CB(FUNC) \
+ void gles2_##FUNC##_cb(gles2_State *s, \
+ gles2_decode_t *d, gles2_Client *c); \
+ void gles2_##FUNC##_cb(gles2_State *s, \
+ gles2_decode_t *d, gles2_Client *c)
+
+// Sizes of primitive types in the ABI.
+#define GLES2_HTYPE_byte uint8_t
+#define GLES2_HTYPE_word uint16_t
+#define GLES2_HTYPE_dword uint32_t
+#define GLES2_HTYPE_float float
+#define GLES2_HTYPE_handle uint32_t
+
+// Defines shorthands for handling types.
+#define GLES2_TYPE(TYPE, SIZE) \
+ typedef GLES2_HTYPE_##SIZE TYPE; \
+ inline void gles2_ret_##TYPE(gles2_State *s, TYPE value); \
+ inline void gles2_ret_##TYPE(gles2_State *s, TYPE value) \
+ { gles2_ret_##SIZE(s, value); } \
+ inline void gles2_put_##TYPE(gles2_State *s, target_ulong va, TYPE value); \
+ inline void gles2_put_##TYPE(gles2_State *s, target_ulong va, TYPE value) \
+ { gles2_put_##SIZE(s, va, value); } \
+ inline TYPE gles2_get_##TYPE(gles2_State *s, target_ulong va); \
+ inline TYPE gles2_get_##TYPE(gles2_State *s, target_ulong va) \
+ { return (TYPE)gles2_get_##SIZE(s, va); } \
+ inline TYPE gles2_arg_##TYPE(gles2_State *s, gles2_decode_t *d); \
+ inline TYPE gles2_arg_##TYPE(gles2_State *s, gles2_decode_t *d) \
+ { return (TYPE)gles2_arg_##SIZE(s, d); }
+
+// Bunch of expansions of previous macro to ease things up.
+GLES2_TYPE(Tptr, dword)
+GLES2_TYPE(TEGLBoolean, dword)
+GLES2_TYPE(TEGLint, dword)
+GLES2_TYPE(TEGLDisplay, handle)
+GLES2_TYPE(TEGLConfig, handle)
+GLES2_TYPE(TEGLContext, handle)
+GLES2_TYPE(TEGLSurface, handle)
+
+GLES2_TYPE(TGLclampf, float)
+GLES2_TYPE(TGLbitfield, dword)
+GLES2_TYPE(TGLboolean, byte)
+GLES2_TYPE(TGLint, dword)
+GLES2_TYPE(TGLuint, dword)
+GLES2_TYPE(TGLushort, word)
+GLES2_TYPE(TGLubyte, byte)
+GLES2_TYPE(TGLenum, dword)
+GLES2_TYPE(TGLsizei, dword)
+GLES2_TYPE(TGLfloat, float)
+
+// Just one more macro for even less typing.
+#define GLES2_ARG(TYPE, NAME) \
+ TYPE NAME = gles2_arg_##TYPE(s, d)
+
+#define GLES2_BARRIER_ARG \
+ if (c) { \
+ pthread_mutex_lock(&c->mutex_xcode); \
+ c->phase_xcode = 1; \
+ pthread_cond_signal(&c->cond_xcode); \
+ pthread_mutex_unlock(&c->mutex_xcode); \
+ GLES2_PRINT("-- ARG BARRIER --\n"); \
+ }
+#define GLES2_BARRIER_ARG_NORET \
+ if (c) { \
+ pthread_mutex_lock(&c->mutex_xcode); \
+ c->phase_xcode = 3; \
+ GLES2_PRINT("-- ARG & RETURN BARRIER --\n"); \
+ }
+#define GLES2_BARRIER_RET \
+ if (c) { \
+ pthread_mutex_lock(&c->mutex_xcode); \
+ c->phase_xcode = 2; \
+ do { \
+ pthread_cond_wait(&c->cond_return, &c->mutex_xcode); \
+ } while (c->phase_xcode == 2); \
+ GLES2_PRINT("-- RETURN BARRIER --\n"); \
+ }
+
+// pthread_cond_signal(&s->cond_xcode);
+
+GLES2_CB(eglGetDisplay)
+{
+// GLES2_ARG(TEGLDisplay, dpy);
+// (void)dpy;
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Getting display...\n");
+
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ GLES2_PRINT("\tGot host display %p...\n", dpy);
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLDisplay(s, gles2_handle_create(s, dpy));
+}
+
+GLES2_CB(eglInitialize)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(Tptr, majorp);
+ GLES2_ARG(Tptr, minorp);
+
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ GLES2_PRINT("Request to initialize display %p...\n", dpy);
+
+ EGLint major, minor;
+ if (eglInitialize(dpy, &major, &minor)) {
+ GLES2_PRINT("Display initialized (EGL %d.%d)!\n", major, minor);
+ gles2_put_TEGLint(s, majorp, major);
+ gles2_put_TEGLint(s, minorp, minor);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+ return;
+ }
+
+ GLES2_PRINT("Failed to initialize...\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_FALSE);
+}
+
+GLES2_CB(eglGetConfigs)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(Tptr, configsp);
+ GLES2_ARG(TEGLint, config_size);
+ GLES2_ARG(Tptr, num_configp);
+
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ EGLConfig* configs = configsp ? malloc(sizeof(EGLConfig)*config_size) : NULL;
+
+ EGLint num_config;
+ EGLBoolean ret = eglGetConfigs(dpy, configs, config_size, &num_config);
+
+ GLES2_BARRIER_RET;
+ if (configs) {
+ EGLint i;
+
+ for (i = 0; i < num_config; ++i) {
+ uint32_t handle;
+ if (!(handle = gles2_handle_find(s, configs[i]))) {
+ handle = gles2_handle_create(s, configs[i]);
+ }
+ gles2_put_TEGLConfig(s, configsp + i*sizeof(TEGLConfig), handle);
+ }
+
+ free(configs);
+ }
+ gles2_put_TEGLint(s, num_configp, num_config);
+
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglChooseConfig)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(Tptr, attrib_listp);
+ GLES2_ARG(Tptr, configsp);
+ GLES2_ARG(TEGLint, config_size);
+ GLES2_ARG(Tptr, num_configp);
+ (void)config_size;
+ (void)attrib_listp;
+
+ EGLint attrib_list_n = 0;
+ while (gles2_get_TEGLint(s, attrib_listp
+ + attrib_list_n*sizeof(EGLint)) != EGL_NONE) {
+ attrib_list_n += 2;
+ }
+ EGLint* attrib_list = malloc((attrib_list_n + 1)*sizeof(EGLint));
+ EGLint i;
+
+ for (i = 0; i < attrib_list_n; ++i) {
+ attrib_list[i] = gles2_get_TEGLint(s, attrib_listp
+ + i*sizeof(EGLint));
+ }
+ attrib_list[attrib_list_n] = EGL_NONE;
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ EGLConfig* configs = configsp ? malloc(sizeof(EGLConfig)*config_size) : NULL;
+
+ EGLint num_config;
+ EGLBoolean ret = eglChooseConfig(dpy, attrib_list, configs, config_size, &num_config);
+ free(attrib_list);
+ GLES2_BARRIER_RET;
+ if (configs) {
+ EGLint i;
+
+ for (i = 0; i < num_config; ++i) {
+ uint32_t handle;
+ if (!(handle = gles2_handle_find(s, configs[i]))) {
+ handle = gles2_handle_create(s, configs[i]);
+ }
+ gles2_put_TEGLConfig(s, configsp + i*sizeof(TEGLConfig), handle);
+ }
+
+ free(configs);
+ }
+ gles2_put_TEGLint(s, num_configp, num_config);
+
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglGetConfigAttrib)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config);
+ GLES2_ARG(TEGLint, attribute);
+ GLES2_ARG(Tptr, valuep);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ EGLint value;
+ EGLBoolean ret = eglGetConfigAttrib(dpy, gles2_handle_get(s, config), attribute, &value);
+
+ GLES2_BARRIER_RET;
+
+ gles2_put_TEGLint(s, valuep, value);
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+typedef struct gles2_Surface
+{
+ uint32_t ddrawp; // Pointer to the offscreen drawable in guest memory.
+ DEGLDrawable ddraw; // Offscreen drawable, read from guest memory.
+ EGLSurface surf; // Pointer to the EGL surface.
+ uint32_t pixelsp; // Pointer to pixels in guest memory.
+ int pixmap; // True if surface is pixmap.
+ gles2_CompiledTransfer tfr; // Framebuffer transfer.
+} gles2_Surface;
+
+// See if guest offscreen drawable was changed and if so, update host copy.
+static int gles2_surface_update(gles2_State *s, gles2_Surface *surf)
+{
+ int ret = 0;
+
+ uint32_t width = gles2_get_dword(s, surf->ddrawp + 0*sizeof(uint32_t));
+ uint32_t height = gles2_get_dword(s, surf->ddrawp + 1*sizeof(uint32_t));
+ uint32_t depth = gles2_get_dword(s, surf->ddrawp + 2*sizeof(uint32_t));
+ uint32_t bpp = gles2_get_dword(s, surf->ddrawp + 3*sizeof(uint32_t));
+ uint32_t pixelsp = gles2_get_dword(s, surf->ddrawp + 4*sizeof(uint32_t));
+
+ if (width != surf->ddraw.width
+ || height != surf->ddraw.height
+ || depth != surf->ddraw.depth) {
+ surf->ddraw.width = width;
+ surf->ddraw.height = height;
+ surf->ddraw.depth = depth;
+ surf->ddraw.bpp = bpp;
+ ret = 1;
+ }
+
+ surf->pixelsp = pixelsp;
+
+ return ret;
+}
+
+// TODO: Support swapping of offscreen surfaces.
+static void gles2_eglSwapCallback(void* userdata)
+{
+ (void)userdata;
+ GLES2_PRINT("Swap called!\n");
+}
+
+GLES2_CB(eglCreateWindowSurface)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config_);
+ GLES2_ARG(Tptr, winp);
+ GLES2_ARG(Tptr, attrib_listp);
+
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLConfig config = (EGLConfig)gles2_handle_get(s, config_);
+ (void)attrib_listp;
+
+ gles2_Surface* fsurf;
+
+ if (!(fsurf = malloc(sizeof(*fsurf)))) {
+ GLES2_PRINT("\tFake window creation failed!\n");
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+
+ fsurf->ddrawp = winp;
+ fsurf->pixmap = 0;
+ gles2_surface_update(s, fsurf);
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Host window creation requested, %dx%d@%d(Bpp=%d) at 0x%x...\n",
+ fsurf->ddraw.width, fsurf->ddraw.height,
+ fsurf->ddraw.depth, fsurf->ddraw.bpp, fsurf->pixelsp);
+
+ unsigned nbytes = fsurf->ddraw.width*fsurf->ddraw.height*fsurf->ddraw.bpp;
+ fsurf->ddraw.pixels = malloc(nbytes);
+ fsurf->ddraw.userdata = fsurf;
+ fsurf->ddraw.swap = gles2_eglSwapCallback;
+
+ if((fsurf->surf = eglCreateWindowSurface(dpy, config,
+ (EGLNativeWindowType)&fsurf->ddraw, NULL)) == EGL_NO_CONTEXT)
+ {
+ GLES2_PRINT("\tHost window creation failed!\n");
+ free(fsurf->ddraw.pixels);
+ free(fsurf);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+ GLES2_PRINT("Created at %p!\n", fsurf);
+ GLES2_BARRIER_RET;
+ gles2_transfer_compile(&fsurf->tfr, s, fsurf->pixelsp, nbytes);
+ gles2_ret_TEGLSurface(s, gles2_handle_create(s, fsurf));
+}
+
+GLES2_CB(eglCreatePixmapSurface)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config_);
+ GLES2_ARG(Tptr, pixmapp);
+ GLES2_ARG(Tptr, attrib_listp);
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLConfig config = (EGLConfig)gles2_handle_get(s, config_);
+ (void)attrib_listp;
+
+ gles2_Surface* fsurf;
+
+ if (!(fsurf = malloc(sizeof(*fsurf)))) {
+ GLES2_PRINT("\tFake pixmap creation failed!\n");
+ GLES2_BARRIER_ARG_NORET;
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+ fsurf->ddrawp = pixmapp;
+ fsurf->pixmap = 1;
+ gles2_surface_update(s, fsurf);
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Host pixmap creation requested, %dx%d@%d(Bpp=%d) at 0x%x...\n",
+ fsurf->ddraw.width, fsurf->ddraw.height,
+ fsurf->ddraw.depth, fsurf->ddraw.bpp, fsurf->pixelsp);
+
+ unsigned nbytes = fsurf->ddraw.width*fsurf->ddraw.height*fsurf->ddraw.bpp;
+ fsurf->ddraw.pixels = malloc(nbytes);
+ fsurf->ddraw.userdata = fsurf;
+ fsurf->ddraw.swap = gles2_eglSwapCallback;
+
+ if((fsurf->surf = eglCreatePixmapSurface(dpy, config,
+ (EGLNativeWindowType)&fsurf->ddraw, NULL)) == EGL_NO_CONTEXT) {
+ GLES2_PRINT("\tHost pixmap creation failed!\n");
+ free(fsurf->ddraw.pixels);
+ free(fsurf);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+ GLES2_PRINT("Created at %p!\n", fsurf);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLSurface(s, gles2_handle_create(s, fsurf));
+}
+
+GLES2_CB(eglDestroySurface)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+ GLES2_BARRIER_ARG_NORET;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (EGLSurface)gles2_handle_get(s, surface_);
+ gles2_handle_free(s, surface_);
+
+ eglDestroySurface(dpy, fsurf->surf);
+ free(fsurf->ddraw.pixels);
+
+ if(fsurf->pixmap == 0) {
+ gles2_transfer_free(&fsurf->tfr);
+ }
+ free(fsurf);
+}
+
+GLES2_CB(eglBindTexImage)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+ GLES2_ARG(TEGLint, buffer);
+ gles2_CompiledTransfer tfr;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (gles2_Surface*)gles2_handle_get(s, surface_);
+
+ // FIXME: Not a very clean way..
+ uint32_t pixelsp = gles2_get_dword(s, fsurf->ddrawp + 4*sizeof(uint32_t));
+ if (pixelsp) {
+ unsigned nbytes = fsurf->ddraw.width
+ * fsurf->ddraw.height*fsurf->ddraw.bpp;
+ gles2_transfer_compile(&tfr, s, pixelsp, nbytes);
+ }
+ GLES2_BARRIER_ARG;
+
+ if (pixelsp) {
+// gles2_transfer(s, pixelsp, nbytes, fsurf->ddraw.pixels, 0);
+ gles2_transfer_exec(&tfr, s, fsurf->ddraw.pixels, 0);
+ }
+
+ EGLBoolean ret = eglBindTexImage(dpy, &fsurf->ddraw, buffer);
+ if (pixelsp) {
+ gles2_transfer_free(&tfr);
+ }
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglReleaseTexImage)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+ GLES2_ARG(TEGLint, buffer);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (gles2_Surface*)gles2_handle_get(s, surface_);
+
+ EGLBoolean ret = eglReleaseTexImage(dpy, &fsurf->ddraw, buffer);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglCreateContext)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config_);
+ GLES2_ARG(TEGLContext, share_context_);
+ GLES2_ARG(Tptr, attrib_listp);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLConfig config = (EGLConfig)gles2_handle_get(s, config_);
+ EGLContext share_context = (EGLContext)gles2_handle_get(s, share_context_);
+
+ GLES2_PRINT("TODO: Handle attribs...\n");
+ (void)attrib_listp;
+
+ GLES2_PRINT("Host context creation requested...\n");
+ EGLContext ctx;
+ if ((ctx = eglCreateContext(dpy, config,
+ share_context, NULL)) == EGL_NO_CONTEXT) {
+ GLES2_PRINT("\tContext creation failed!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLContext(s, 0);
+ return;
+ }
+ GLES2_PRINT("Created at %p!\n", ctx);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLContext(s, gles2_handle_create(s, ctx));
+}
+
+GLES2_CB(eglDestroyContext)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLContext, ctx_);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLContext ctx = (EGLContext)gles2_handle_get(s, ctx_);
+ gles2_handle_free(s, ctx_);
+ GLES2_PRINT("Destroyed %p!\n", ctx);
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, eglDestroyContext(dpy, ctx));
+}
+
+// Host to guest vertex array copy.
+struct gles2_Array
+{
+ GLuint indx; // Parameter of the call.
+ GLint size; // --''--
+ GLenum type; // --''--
+ GLboolean normalized; // --''--
+ GLsizei stride; // --''--
+ Tptr tptr; // Pointer in the guest memory.
+ void* ptr; // Pointer in the host memory.
+
+ GLboolean enabled; // State.
+};
+
+GLES2_CB(eglMakeCurrent)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, draw_);
+ GLES2_ARG(TEGLSurface, read_);
+ GLES2_ARG(TEGLContext, ctx_);
+ GLES2_BARRIER_ARG;
+ int i;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* draw = (EGLSurface)gles2_handle_get(s, draw_);
+ gles2_Surface* read = (EGLSurface)gles2_handle_get(s, read_);
+ EGLContext ctx = (EGLContext)gles2_handle_get(s, ctx_);
+
+ GLES2_PRINT("Making host context current...\n");
+
+ if (!eglMakeCurrent(dpy,
+ draw ? draw->surf : NULL,
+ read ? read->surf : NULL,
+ ctx)) {
+ GLES2_PRINT("\tMakeCurrent failed!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_FALSE);
+ return;
+ }
+
+ // Initialize client state.
+ if (ctx) {
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &c->narrays);
+
+ GLES2_PRINT("Maximum number of host vertex arrays: %d.\n", c->narrays);
+
+ c->arrays = malloc(c->narrays * sizeof(*c->arrays));
+ for (i = 0; i < c->narrays; ++i) {
+ c->arrays[i].type = GL_NONE;
+ c->arrays[i].enabled = 0;
+ c->arrays[i].ptr = 0;
+ }
+ }
+
+ GLES2_PRINT("Made %p current!\n", ctx);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+}
+
+GLES2_CB(eglSwapBuffers)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (EGLSurface)gles2_handle_get(s, surface_);
+ if (!fsurf) {
+ fprintf(stderr, "ERROR: Trying to swap NULL surface!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+ return;
+ }
+
+ if (gles2_surface_update(s, fsurf)) {
+ GLES2_BARRIER_ARG;
+ GLES2_PRINT("DIMENSIONS CHANGED!\n");
+ glFinish();
+ free(fsurf->ddraw.pixels);
+ unsigned nbytes = fsurf->ddraw.width
+ * fsurf->ddraw.height*fsurf->ddraw.bpp;
+ fsurf->ddraw.pixels = malloc(nbytes);
+
+ gles2_transfer_free(&fsurf->tfr);
+ GLES2_BARRIER_RET;
+ gles2_transfer_compile(&fsurf->tfr, s, fsurf->pixelsp, nbytes);
+ eglSwapBuffers(dpy, fsurf->surf);
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+ return;
+ }
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Swapping DGLES2 surfaces!\n");
+ eglSwapBuffers(dpy, fsurf->surf);
+
+ GLES2_PRINT("Transferring frame!\n");
+ gles2_transfer_exec(&fsurf->tfr, s, fsurf->ddraw.pixels, 1);
+ GLES2_PRINT("\tDone!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+}
+
+GLES2_CB(glClearColor)
+{
+ GLES2_ARG(TGLclampf, red);
+ GLES2_ARG(TGLclampf, green);
+ GLES2_ARG(TGLclampf, blue);
+ GLES2_ARG(TGLclampf, alpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClearColor(red, green, blue, alpha);
+}
+
+
+GLES2_CB(glClear)
+{
+ GLES2_ARG(TGLbitfield, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClear(mask);
+}
+
+GLES2_CB(glDisableVertexAttribArray)
+{
+ GLES2_ARG(TGLuint, index);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Disabling array %d\n", index);
+ c->arrays[index].enabled = 0;
+ glDisableVertexAttribArray(index);
+}
+
+static void fglTransferArrays(gles2_State *s, gles2_Client *c,
+ GLint first, GLsizei count)
+{
+ int i;
+
+ for(i = 0; i < c->narrays; ++i) {
+ gles2_Array* va = c->arrays + i;
+ if(!va->enabled) {
+ continue;
+ }
+ unsigned esize = 1;
+ switch (va->type) {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE: esize = 1; break;
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT: esize = 2; break;
+ case GL_FIXED:
+ case GL_FLOAT: esize = 4; break;
+ }
+ if (!va->stride) {
+ va->stride = va->size*esize;
+ }
+
+ if (va->ptr) {
+ free(va->ptr);
+ }
+ unsigned nbytes = esize*count*va->size;
+ va->ptr = malloc(nbytes);
+
+ GLsizei j;
+ for (j = 0; j < count; ++j) {
+ signed k;
+ for (k = 0; k < va->size; ++k) {
+ switch (esize) {
+ case 1:
+ ((TGLubyte*)va->ptr)[j*va->size + k] =
+ gles2_get_byte(s, va->tptr + va->stride*(first + j)
+ + k*sizeof(TGLubyte));
+ break;
+ case 2:
+ ((TGLushort*)va->ptr)[j*va->size + k] =
+ gles2_get_word(s, va->tptr + va->stride*(first + j)
+ + k*sizeof(TGLushort));
+ break;
+ case 4:
+ if(va->type == GL_FLOAT) {
+ ((TGLfloat*)va->ptr)[j*va->size + k] =
+ gles2_get_float(s, va->tptr
+ + va->stride*(first + j)
+ + k*sizeof(TGLfloat));
+ } else {
+ ((TGLuint*)va->ptr)[j*va->size + k] =
+ gles2_get_dword(s, va->tptr
+ + va->stride*(first + j)
+ + k*sizeof(TGLuint));
+ }
+ break;
+ }
+ }
+ }
+
+ glVertexAttribPointer(va->indx, va->size, va->type,
+ va->normalized, 0, va->ptr);
+ GLenum error;
+
+ if ((error = glGetError()) != GL_NO_ERROR) {
+ GLES2_PRINT("glVertexAttribPointer(%d, %d, 0x%x, 0, %d, %p\n)"
+ " failed with 0x%x!\n", va->indx, va->size, va->type,
+ va->normalized, va->ptr, error);
+ }
+ }
+}
+
+GLES2_CB(glDrawArrays)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_ARG(TGLint, first);
+ GLES2_ARG(TGLsizei, count);
+
+ fglTransferArrays(s, c, first, count);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDrawArrays(mode, 0, count);
+}
+
+GLES2_CB(glDrawElements)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, indicesp);
+
+ (void)indicesp;
+ (void)count;
+ (void)mode;
+
+ GLint indice_size;
+ switch (type) {
+ case GL_UNSIGNED_BYTE: indice_size = sizeof(TGLubyte); break;
+ case GL_UNSIGNED_SHORT: indice_size = sizeof(TGLushort); break;
+ default:
+ fprintf(stderr, "ERROR: Invalid type %d!\n", type);
+ return;
+ }
+
+ fglTransferArrays(s, c, (GLint)indicesp/indice_size, count);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDrawElements(mode, count, type, 0);
+}
+
+GLES2_CB(glEnableVertexAttribArray)
+{
+ GLES2_ARG(TGLuint, index);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Enabling array %d\n", index);
+ c->arrays[index].enabled = 1;
+ glEnableVertexAttribArray(index);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname,
+ GLfloat* params)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname,
+ GLint* params)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv(GLuint index,
+ GLenum pname, void** pointer)
+{
+ DUMMY();
+}
+#endif //0
+
+GLES2_CB(glVertexAttrib1f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib1f(indx, x);
+}
+
+GLES2_CB(glVertexAttrib1fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+ GLfloat x = gles2_get_float(s, valuesp);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib1f(indx, x);
+}
+
+GLES2_CB(glVertexAttrib2f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib2f(indx, x, y);
+}
+
+GLES2_CB(glVertexAttrib2fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+
+ GLfloat x = gles2_get_float(s, valuesp);
+ GLfloat y = gles2_get_float(s, valuesp + sizeof(TGLfloat));
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib2f(indx, x, y);
+}
+
+GLES2_CB(glVertexAttrib3f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib3f(indx, x, y, z);
+}
+
+GLES2_CB(glVertexAttrib3fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+
+ GLfloat x = gles2_get_float(s, valuesp + 0*sizeof(TGLfloat));
+ GLfloat y = gles2_get_float(s, valuesp + 1*sizeof(TGLfloat));
+ GLfloat z = gles2_get_float(s, valuesp + 2*sizeof(TGLfloat));
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib3f(indx, x, y, z);
+}
+
+GLES2_CB(glVertexAttrib4f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_ARG(TGLfloat, w);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib4f(indx, x, y, z, w);
+}
+
+GLES2_CB(glVertexAttrib4fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+
+ GLfloat x = gles2_get_float(s, valuesp + 0*sizeof(TGLfloat));
+ GLfloat y = gles2_get_float(s, valuesp + 1*sizeof(TGLfloat));
+ GLfloat z = gles2_get_float(s, valuesp + 2*sizeof(TGLfloat));
+ GLfloat w = gles2_get_float(s, valuesp + 3*sizeof(TGLfloat));
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib4f(indx, x, y, z, w);
+}
+
+GLES2_CB(glVertexAttribPointer)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLint, size);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(TGLboolean, normalized);
+ GLES2_ARG(TGLsizei, stride);
+ GLES2_ARG(Tptr, tptr);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Array %d at 0x%x (%d elements every %d bytes)\n",
+ indx, tptr, size, stride);
+
+ gles2_Array *va = c->arrays + indx;
+ va->type = type;
+ va->indx = indx;
+ va->size = size;
+ va->normalized = normalized;
+ va->stride = stride;
+ va->tptr = tptr;
+}
+
+static unsigned gles2_glGetCount(TGLenum pname)
+{
+ unsigned count;
+ switch(pname) {
+ case GL_ACTIVE_TEXTURE: count = 1; break;
+ case GL_ALIASED_LINE_WIDTH_RANGE: count = 2; break;
+ case GL_ALIASED_POINT_SIZE_RANGE: count = 2; break;
+ case GL_ALPHA_BITS: count = 1; break;
+ case GL_ARRAY_BUFFER_BINDING: count = 1; break;
+ case GL_BLEND: count = 1; break;
+ case GL_BLEND_COLOR: count = 4; break;
+ case GL_BLEND_DST_ALPHA: count = 1; break;
+ case GL_BLEND_DST_RGB: count = 1; break;
+ case GL_BLEND_EQUATION_ALPHA: count = 1; break;
+ case GL_BLEND_EQUATION_RGB: count = 1; break;
+ case GL_BLEND_SRC_ALPHA: count = 1; break;
+ case GL_BLEND_SRC_RGB: count = 1; break;
+ case GL_BLUE_BITS: count = 1; break;
+ case GL_COLOR_CLEAR_VALUE: count = 4; break;
+ case GL_COLOR_WRITEMASK: count = 4; break;
+ case GL_COMPRESSED_TEXTURE_FORMATS: count = GL_NUM_COMPRESSED_TEXTURE_FORMATS; break;
+ case GL_CULL_FACE: count = 1; break;
+ case GL_CULL_FACE_MODE: count = 1; break;
+ case GL_CURRENT_PROGRAM: count = 1; break;
+ case GL_DEPTH_BITS: count = 1; break;
+ case GL_DEPTH_CLEAR_VALUE: count = 1; break;
+ case GL_DEPTH_FUNC: count = 1; break;
+ case GL_DEPTH_RANGE: count = 2; break;
+ case GL_DEPTH_TEST: count = 1; break;
+ case GL_DEPTH_WRITEMASK: count = 1; break;
+ case GL_DITHER: count = 1; break;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING: count = 1; break;
+ case GL_FRAMEBUFFER_BINDING: count = 1; break;
+ case GL_FRONT_FACE: count = 1; break;
+ case GL_GENERATE_MIPMAP_HINT: count = 1; break;
+ case GL_GREEN_BITS: count = 1; break;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT: count = 1; break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE: count = 1; break;
+ case GL_LINE_WIDTH: count = 1; break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: count = 1; break;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE: count = 1; break;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS: count = 1; break;
+ case GL_MAX_RENDERBUFFER_SIZE: count = 1; break;
+ case GL_MAX_TEXTURE_IMAGE_UNITS: count = 1; break;
+ case GL_MAX_TEXTURE_SIZE: count = 1; break;
+ case GL_MAX_VARYING_VECTORS: count = 1; break;
+ case GL_MAX_VERTEX_ATTRIBS: count = 1; break;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: count = 1; break;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS: count = 1; break;
+ case GL_MAX_VIEWPORT_DIMS: count = 2; break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS: count = 1; break;
+ case GL_NUM_SHADER_BINARY_FORMATS: count = 1; break;
+ case GL_PACK_ALIGNMENT: count = 1; break;
+ case GL_POLYGON_OFFSET_FACTOR: count = 1; break;
+ case GL_POLYGON_OFFSET_FILL: count = 1; break;
+ case GL_POLYGON_OFFSET_UNITS: count = 1; break;
+ case GL_RED_BITS: count = 1; break;
+ case GL_RENDERBUFFER_BINDING: count = 1; break;
+ case GL_SAMPLE_BUFFERS: count = 1; break;
+ case GL_SAMPLE_COVERAGE_INVERT: count = 1; break;
+ case GL_SAMPLE_COVERAGE_VALUE: count = 1; break;
+ case GL_SAMPLES: count = 1; break;
+ case GL_SCISSOR_BOX: count = 4; break;
+ case GL_SCISSOR_TEST: count = 1; break;
+ case GL_SHADER_BINARY_FORMATS: count = GL_NUM_SHADER_BINARY_FORMATS; break;
+ case GL_SHADER_COMPILER: count = 1; break;
+ case GL_STENCIL_BACK_FAIL: count = 1; break;
+ case GL_STENCIL_BACK_FUNC: count = 1; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL: count = 1; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS: count = 1; break;
+ case GL_STENCIL_BACK_REF: count = 1; break;
+ case GL_STENCIL_BACK_VALUE_MASK: count = 1; break;
+ case GL_STENCIL_BACK_WRITEMASK: count = 1; break;
+ case GL_STENCIL_BITS: count = 1; break;
+ case GL_STENCIL_CLEAR_VALUE: count = 1; break;
+ case GL_STENCIL_FAIL: count = 1; break;
+ case GL_STENCIL_FUNC: count = 1; break;
+ case GL_STENCIL_PASS_DEPTH_FAIL: count = 1; break;
+ case GL_STENCIL_PASS_DEPTH_PASS: count = 1; break;
+ case GL_STENCIL_REF: count = 1; break;
+ case GL_STENCIL_TEST: count = 1; break;
+ case GL_STENCIL_VALUE_MASK: count = 1; break;
+ case GL_STENCIL_WRITEMASK: count = 1; break;
+ case GL_SUBPIXEL_BITS: count = 1; break;
+ case GL_TEXTURE_BINDING_2D: count = 1; break;
+ case GL_TEXTURE_BINDING_CUBE_MAP: count = 1; break;
+ case GL_UNPACK_ALIGNMENT: count = 1; break;
+ case GL_VIEWPORT: count = 4; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown pname 0x%x in glGet!\n", pname);
+ count = 1;
+ break;
+ }
+
+ GLES2_PRINT("glGet(0x%x) -> %u!\n", pname, count);
+
+ return count;
+}
+
+GLES2_CB(glGetBooleanv)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLboolean params[4];
+ glGetBooleanv(pname, params);
+ unsigned const count = gles2_glGetCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLboolean(s, paramsp + i*sizeof(TGLboolean), params[i]);
+ }
+}
+
+GLES2_CB(glGetError)
+{
+ GLES2_BARRIER_ARG;
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLenum(s, glGetError());
+}
+
+GLES2_CB(eglGetError)
+{
+ GLES2_BARRIER_ARG;
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLint(s, eglGetError());
+}
+
+GLES2_CB(glGetFloatv)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLfloat params[4];
+ glGetFloatv(pname, params);
+ unsigned const count = gles2_glGetCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLfloat(s, paramsp + i*sizeof(TGLfloat), params[i]);
+ }
+}
+
+GLES2_CB(glGetIntegerv)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint params[4];
+ glGetIntegerv(pname, params);
+ unsigned const count = gles2_glGetCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLint(s, paramsp + i*sizeof(TGLint), params[i]);
+ }
+}
+
+GLES2_CB(glColorMask)
+{
+ GLES2_ARG(TGLboolean, red);
+ GLES2_ARG(TGLboolean, green);
+ GLES2_ARG(TGLboolean, blue);
+ GLES2_ARG(TGLboolean, alpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glColorMask(red, green, blue, alpha);
+}
+
+GLES2_CB(glCullFace)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ glCullFace(mode);
+}
+
+GLES2_CB(glDisable)
+{
+ GLES2_ARG(TGLenum, cap);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDisable(cap);
+}
+
+GLES2_CB(glEnable)
+{
+ GLES2_ARG(TGLenum, cap);
+ GLES2_BARRIER_ARG_NORET;
+
+ glEnable(cap);
+}
+
+GLES2_CB(glFinish)
+{
+ GLES2_BARRIER_ARG_NORET;
+ glFinish();
+}
+
+GLES2_CB(glFlush)
+{
+ GLES2_BARRIER_ARG_NORET;
+ glFlush();
+}
+
+GLES2_CB(glFrontFace)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ glFrontFace(mode);
+}
+
+GLES2_CB(glIsEnabled)
+{
+ GLES2_ARG(TGLenum, cap);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsEnabled(cap));
+}
+
+GLES2_CB(glHint)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ if(s->quality <= 75)
+ {
+ switch(target)
+ {
+ default: mode = GL_FASTEST; break;
+ }
+ }
+
+ glHint(target, mode);
+}
+
+GLES2_CB(glLineWidth)
+{
+ GLES2_ARG(TGLfloat, width);
+ GLES2_BARRIER_ARG_NORET;
+
+ glLineWidth(width);
+}
+
+GLES2_CB(glPolygonOffset)
+{
+ GLES2_ARG(TGLfloat, factor);
+ GLES2_ARG(TGLfloat, units);
+ GLES2_BARRIER_ARG_NORET;
+
+ glPolygonOffset(factor, units);
+}
+
+GLES2_CB(glSampleCoverage)
+{
+ GLES2_ARG(TGLclampf, value);
+ GLES2_ARG(TGLboolean, invert);
+ GLES2_BARRIER_ARG_NORET;
+
+ glSampleCoverage(value, invert);
+}
+
+GLES2_CB(glScissor)
+{
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_BARRIER_ARG_NORET;
+
+ glScissor(x, y, width, height);
+}
+
+GLES2_CB(glViewport)
+{
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_BARRIER_ARG_NORET;
+
+ glViewport(x, y, width, height);
+}
+
+GLES2_CB(glActiveTexture)
+{
+ GLES2_ARG(TGLenum, texture);
+ GLES2_BARRIER_ARG_NORET;
+
+ glActiveTexture(texture);
+}
+
+GLES2_CB(glBindTexture)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, texture);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindTexture(target, texture);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D(GLenum target,
+ GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+ GLint border, GLsizei imageSize, const void* data)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D(GLenum target,
+ GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize, const void* data)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level,
+ GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glDeleteTextures)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, texturesp);
+
+ GLsizei i;
+ GLuint* textures = (GLuint*)malloc(sizeof(GLuint)*n);
+ for(i = 0; i < n; ++i) {
+ textures[i] = gles2_get_TGLuint(s, texturesp + i*sizeof(TGLuint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteTextures(n, textures);
+ free(textures);
+}
+
+GLES2_CB(glGenerateMipmap)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_BARRIER_ARG_NORET;
+
+ glGenerateMipmap(target);
+}
+
+GLES2_CB(glGenTextures)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, texturesp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLsizei i;
+ GLuint* textures = (GLuint*)malloc(sizeof(GLuint)*n);
+ glGenTextures(n, textures);
+ for(i = 0; i < n; ++i) {
+ gles2_put_TGLuint(s, texturesp + i*sizeof(TGLuint), textures[i]);
+ }
+ free(textures);
+}
+
+static unsigned gles2_glTexParameterCount(GLenum pname)
+{
+ unsigned count;
+
+ switch(pname) {
+ case GL_TEXTURE_MIN_FILTER: count = 1; break;
+ case GL_TEXTURE_MAG_FILTER: count = 1; break;
+ case GL_TEXTURE_WRAP_S: count = 1; break;
+ case GL_TEXTURE_WRAP_T: count = 1; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown texture parameter 0x%x!\n", pname);
+ count = 1;
+ break;
+ }
+
+ return count;
+}
+
+GLES2_CB(glGetTexParameterfv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLfloat params[4];
+ glGetTexParameterfv(target, pname, params);
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLfloat(s, paramsp + i*sizeof(TGLfloat), params[i]);
+ }
+}
+
+GLES2_CB(glGetTexParameteriv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint params[4];
+ glGetTexParameteriv(target, pname, params);
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLint(s, paramsp + i*sizeof(TGLint), params[i]);
+ }
+}
+
+GLES2_CB(glIsTexture)
+{
+ GLES2_ARG(TGLuint, texture);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsTexture(texture));
+}
+
+GLES2_CB(glReadPixels)
+{
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_ARG(TGLenum, format);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, pixelsp);
+ GLES2_BARRIER_ARG;
+
+ unsigned bpp;
+ switch (format) {
+ case GL_ALPHA: bpp = 1; break;
+ case GL_RGB: bpp = (type == GL_UNSIGNED_BYTE) ? 3 : 2; break;
+ case GL_RGBA: bpp = (type == GL_UNSIGNED_BYTE) ? 4 : 2; break;
+ case GL_LUMINANCE: bpp = 1; break;
+ case GL_LUMINANCE_ALPHA: bpp = 2; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown format 0x%x...\n", format);
+ bpp = 1;
+ break;
+ }
+
+ GLES2_PRINT("Reading %dx%dx%d image at %d,%d...\n",
+ width, height, bpp, x, y);
+ char* pixels = NULL;
+ unsigned nbytes = width*height*bpp;
+ pixels = malloc(nbytes);
+
+ glReadPixels(x, y, width, height, format, type, pixels);
+ GLES2_BARRIER_RET;
+ gles2_transfer(s, pixelsp, nbytes, pixels, 1);
+ free(pixels);
+}
+
+GLES2_CB(glTexImage2D)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLint, level);
+ GLES2_ARG(TGLint, internalformat);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_ARG(TGLint, border);
+ GLES2_ARG(TGLenum, format);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, pixelsp);
+
+ unsigned bpp;
+
+ switch(format) {
+ case GL_ALPHA: bpp = 1; break;
+ case GL_RGB: bpp = (type == GL_UNSIGNED_BYTE) ? 3 : 2; break;
+ case GL_RGBA: bpp = (type == GL_UNSIGNED_BYTE) ? 4 : 2; break;
+ case GL_LUMINANCE: bpp = 1; break;
+ case GL_LUMINANCE_ALPHA: bpp = 2; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown format 0x%x...\n", format);
+ bpp = 1;
+ break;
+ }
+
+ GLES2_PRINT("Uploading %dx%dx%d image...\n", width, height, bpp);
+ char* pixels = NULL;
+ if (pixelsp) {
+ unsigned nbytes = width*height*bpp;
+ pixels = malloc(nbytes);
+ gles2_transfer(s, pixelsp, nbytes, pixels, 0);
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+ free(pixels);
+}
+
+GLES2_CB(glTexParameterf)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(TGLfloat, param);
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexParameterf(target, pname, param);
+}
+
+GLES2_CB(glTexParameterfv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+
+ GLfloat params[4];
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ params[i] = gles2_get_TGLfloat(s, paramsp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexParameterfv(target, pname, params);
+}
+
+GLES2_CB(glTexParameteri)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(TGLint, param);
+ GLES2_BARRIER_ARG_NORET;
+
+ if(s->quality <= 50)
+ {
+ switch(pname)
+ {
+ case GL_TEXTURE_MIN_FILTER: param = GL_NEAREST; break;
+ case GL_TEXTURE_MAG_FILTER: param = GL_NEAREST; break;
+ default: break;
+ }
+ }
+
+ glTexParameterf(target, pname, param);
+}
+
+GLES2_CB(glTexParameteriv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+
+ GLint params[4];
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ params[i] = gles2_get_TGLint(s, paramsp + i*sizeof(GLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexParameteriv(target, pname, params);
+}
+
+GLES2_CB(glTexSubImage2D)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLint, level);
+ GLES2_ARG(TGLint, xoffset);
+ GLES2_ARG(TGLint, yoffset);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_ARG(TGLenum, format);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, pixelsp);
+
+ unsigned bpp;
+ switch (format) {
+ case GL_ALPHA: bpp = 1; break;
+ case GL_RGB: bpp = (type == GL_UNSIGNED_BYTE) ? 3 : 2; break;
+ case GL_RGBA: bpp = (type == GL_UNSIGNED_BYTE) ? 4 : 2; break;
+ case GL_LUMINANCE: bpp = 1; break;
+ case GL_LUMINANCE_ALPHA: bpp = 2; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown format 0x%x...\n", format);
+ bpp = 1;
+ break;
+ }
+
+ GLES2_PRINT("Uploading partial %dx%dx%d image at %d,%d...\n",
+ width, height, bpp, xoffset, yoffset);
+
+ unsigned nbytes = width*height*bpp;
+ char* pixels = malloc(nbytes);
+ gles2_transfer(s, pixelsp, nbytes, pixels, 0);
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+ free(pixels);
+}
+
+
+GLES2_CB(glCompileShader)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG_NORET;
+
+ glCompileShader(shader);
+}
+
+GLES2_CB(glCreateShader)
+{
+ GLES2_ARG(TGLenum, type);
+ GLES2_BARRIER_ARG_NORET;
+
+ gles2_ret_TGLuint(s, glCreateShader(type));
+}
+
+GLES2_CB(glDeleteShader)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteShader(shader);
+}
+
+GLES2_CB(glIsShader)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsShader(shader));
+}
+
+GLES2_CB(glGetShaderiv)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint param;
+ glGetShaderiv(shader, pname, ¶m);
+ gles2_put_TGLint(s, paramsp, param);
+}
+
+GLES2_CB(glGetShaderInfoLog)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_ARG(TGLsizei, bufsize);
+ GLES2_ARG(Tptr, lengthp);
+ GLES2_ARG(Tptr, infologp);
+
+ GLsizei length = gles2_get_TGLsizei(s, lengthp);
+ char* infolog = malloc(bufsize);
+ glGetShaderInfoLog(shader, bufsize, &length, infolog);
+ gles2_transfer(s, infologp, length, infolog, 1);
+ gles2_put_TGLsizei(s, lengthp, length);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("shader %d infolog:\n%.*s\n", shader, length, infolog);
+ free(infolog);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype,
+ GLenum precisiontype, GLint* range, GLint* precision)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize,
+ GLsizei* length, char* source)
+{
+ DUMMY();
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsShader(GLuint shader)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler(void)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders,
+ GLenum binaryformat, const void* binary, GLsizei length)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glShaderSource)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, stringp);
+ GLES2_ARG(Tptr, lengthp);
+
+ char** string_fgl = malloc(sizeof(char*)*count);
+ GLint* length_fgl = malloc(sizeof(GLint)*count);
+
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ length_fgl[i] = gles2_get_TGLint(s, lengthp + i*sizeof(TGLint));
+ string_fgl[i] = malloc(length_fgl[i] + 1);
+ gles2_transfer(s, gles2_get_dword(s, stringp + i*sizeof(Tptr)),
+ length_fgl[i], string_fgl[i], 0);
+ string_fgl[i][length_fgl[i]] = 0;
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("shader %d source:\n", shader);
+ #if(GLES2_DEBUG == 1)
+ for(i = 0; i < count; ++i) {
+ fprintf(stderr, "%.*s", length_fgl[i], string_fgl[i]);
+ }
+ #endif // GLES2_DEBUG == 1
+ GLES2_PRINT("\n--END--");
+
+ glShaderSource(shader, (GLsizei)count,
+ (const char**)string_fgl, length_fgl);
+
+ for (i = 0; i < count; ++i) {
+ free(string_fgl[i]);
+ }
+
+ free(string_fgl);
+ free(length_fgl);
+}
+
+GLES2_CB(glAttachShader)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG_NORET;
+
+ glAttachShader(program, shader);
+}
+
+GLES2_CB(glBindAttribLocation)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLuint, index);
+ GLES2_ARG(Tptr, namep);
+
+ char name[120];
+ Tptr i;
+
+ for(i = 0; (name[i] = gles2_get_byte(s, namep + i)) ; ++i);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Binding attribute %s at %d...\n", name, index);
+ glBindAttribLocation(program, index, name);
+}
+
+GLES2_CB(glCreateProgram)//(void)
+{
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLuint(s, glCreateProgram());
+}
+
+GLES2_CB(glDeleteProgram)//(GLuint program)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteProgram(program);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index,
+ GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index,
+ GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program,
+ GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glGetAttribLocation)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(Tptr, namep);
+
+ char name[120];
+ Tptr i;
+
+ for (i = 0; (name[i] = gles2_get_byte(s, namep + i)) ; ++i);
+
+ GLES2_PRINT("Getting attribute %s location...\n", name);
+
+ gles2_ret_TGLint(s, glGetAttribLocation(program, name));
+ GLES2_BARRIER_ARG_NORET;
+}
+
+GLES2_CB(glGetProgramiv)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint param;
+
+ glGetProgramiv(program, pname, ¶m);
+ gles2_put_TGLint(s, paramsp, param);
+}
+
+GLES2_CB(glGetProgramInfoLog)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLsizei, bufsize);
+ GLES2_ARG(Tptr, lengthp);
+ GLES2_ARG(Tptr, infologp);
+
+ GLsizei length = gles2_get_TGLsizei(s, lengthp);
+ char* infolog = malloc(bufsize);
+ glGetProgramInfoLog(program, bufsize, &length, infolog);
+ gles2_transfer(s, infologp, length, infolog, 1);
+ gles2_put_TGLsizei(s, lengthp, length);
+ GLES2_BARRIER_ARG_NORET;
+ GLES2_PRINT("program %d infolog:\n%.*s\n", program, length, infolog);
+ free(infolog);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glGetUniformLocation)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(Tptr, namep);
+
+ char name[120];
+ Tptr i;
+
+ for (i = 0; (name[i] = gles2_get_byte(s, namep + i)) ; ++i);
+
+ GLES2_PRINT("Getting uniform %s location...\n", name);
+
+ gles2_ret_TGLint(s, glGetUniformLocation(program, name));
+ GLES2_BARRIER_ARG_NORET;
+}
+
+GLES2_CB(glIsProgram)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsProgram(program));
+}
+
+GLES2_CB(glLinkProgram)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG_NORET;
+
+ glLinkProgram(program);
+}
+
+GLES2_CB(glUniform1f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1f(location, x);
+}
+
+GLES2_CB(glUniform1fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*1;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform1i)//(GLint location, GLint x)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1i(location, x);
+}
+
+GLES2_CB(glUniform1iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*1;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform2f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2f(location, x, y);
+}
+
+GLES2_CB(glUniform2fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*2;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLfloat(s, vp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform2i)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2i(location, x, y);
+}
+
+GLES2_CB(glUniform2iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*2;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform3f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3f(location, x, y, z);
+}
+
+GLES2_CB(glUniform3fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*3;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLfloat(s, vp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform3i)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLint, z);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3i(location, x, y, z);
+}
+
+GLES2_CB(glUniform3iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*3;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform4f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_ARG(TGLfloat, w);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform4f(location, x, y, z, w);
+}
+
+GLES2_CB(glUniform4fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*4;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLfloat(s, vp + i*sizeof(TGLfloat));
+ }
+
+ GLES2_BARRIER_ARG_NORET;
+ glUniform4fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform4i)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLint, z);
+ GLES2_ARG(TGLint, w);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform4i(location, x, y, z, w);
+}
+
+GLES2_CB(glUniform4iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*4;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+
+ GLES2_BARRIER_ARG_NORET;
+ glUniform4iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniformMatrix2fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, count);
+ GLES2_ARG(TGLboolean, transpose);
+ GLES2_ARG(Tptr, valuep);
+
+ unsigned nfloats = 2*2*count;
+ GLfloat* value = malloc(nfloats*sizeof(TGLfloat));
+ unsigned i;
+
+ for (i = 0; i < nfloats; ++i) {
+ value[i] = gles2_get_TGLfloat(s, valuep + i*sizeof(TGLfloat));
+ }
+
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniformMatrix2fv(location, count, transpose, value);
+ free(value);
+}
+
+GLES2_CB(glUniformMatrix3fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, count);
+ GLES2_ARG(TGLboolean, transpose);
+ GLES2_ARG(Tptr, valuep);
+
+ unsigned nfloats = 3*3*count;
+ GLfloat* value = malloc(nfloats*sizeof(TGLfloat));
+ unsigned i;
+ for(i = 0; i < nfloats; ++i) {
+ value[i] = gles2_get_TGLfloat(s, valuep + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniformMatrix3fv(location, count, transpose, value);
+ free(value);
+}
+
+GLES2_CB(glUniformMatrix4fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, count);
+ GLES2_ARG(TGLboolean, transpose);
+ GLES2_ARG(Tptr, valuep);
+
+ unsigned nfloats = 4*4*count;
+ GLfloat* value = malloc(nfloats*sizeof(TGLfloat));
+ unsigned i;
+ for(i = 0; i < nfloats; ++i) {
+ value[i] = gles2_get_TGLfloat(s, valuep + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniformMatrix4fv(location, count, transpose, value);
+ free(value);
+}
+
+GLES2_CB(glUseProgram)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUseProgram(program);
+}
+
+GLES2_CB(glBlendColor)
+{
+ GLES2_ARG(TGLclampf, red);
+ GLES2_ARG(TGLclampf, green);
+ GLES2_ARG(TGLclampf, blue);
+ GLES2_ARG(TGLclampf, alpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendColor(red, green, blue, alpha);
+}
+
+GLES2_CB(glBlendEquation)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendEquation(mode);
+}
+
+GLES2_CB(glBlendEquationSeparate)
+{
+ GLES2_ARG(TGLenum, modeRGB);
+ GLES2_ARG(TGLenum, modeAlpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+GLES2_CB(glBlendFunc)
+{
+ GLES2_ARG(TGLenum, sfactor);
+ GLES2_ARG(TGLenum, dfactor);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendFunc(sfactor, dfactor);
+}
+
+GLES2_CB(glBlendFuncSeparate)
+{
+ GLES2_ARG(TGLenum, srcRGB);
+ GLES2_ARG(TGLenum, dstRGB);
+ GLES2_ARG(TGLenum, srcAlpha);
+ GLES2_ARG(TGLenum, dstAlpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+GLES2_CB(glPixelStorei)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(TGLint, param);
+ GLES2_BARRIER_ARG_NORET;
+
+ glPixelStorei(pname, param);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glClearStencil)
+{
+ GLES2_ARG(TGLint, s_);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClearStencil(s_);
+}
+
+GLES2_CB(glStencilFunc)
+{
+ GLES2_ARG(TGLenum, func);
+ GLES2_ARG(TGLint, ref);
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilFunc(func, ref, mask);
+}
+
+GLES2_CB(glStencilFuncSeparate)
+{
+ GLES2_ARG(TGLenum, face);
+ GLES2_ARG(TGLenum, func);
+ GLES2_ARG(TGLint, ref);
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilFuncSeparate(face, func, ref, mask);
+}
+
+GLES2_CB(glStencilMask)
+{
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilMask(mask);
+}
+
+GLES2_CB(glStencilMaskSeparate)
+{
+ GLES2_ARG(TGLenum, face);
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilMaskSeparate(face, mask);
+}
+
+GLES2_CB(glStencilOp)
+{
+ GLES2_ARG(TGLenum, fail);
+ GLES2_ARG(TGLenum, zfail);
+ GLES2_ARG(TGLenum, zpass);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilOp(fail, zfail, zpass);
+}
+
+GLES2_CB(glStencilOpSeparate)
+{
+ GLES2_ARG(TGLenum, face);
+ GLES2_ARG(TGLenum, fail);
+ GLES2_ARG(TGLenum, zfail);
+ GLES2_ARG(TGLenum, zpass);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilOpSeparate(face, fail, zfail, zpass);
+}
+
+GLES2_CB(glBindFramebuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, framebuffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindFramebuffer(target, framebuffer);
+}
+
+GLES2_CB(glBindRenderbuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, renderbuffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindRenderbuffer(target, renderbuffer);
+}
+
+GLES2_CB(glCheckFramebufferStatus)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLenum(s, glCheckFramebufferStatus(target));
+}
+
+GLES2_CB(glDeleteFramebuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, framebuffersp);
+
+ GLsizei i;
+ GLuint* framebuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ for (i = 0; i < n; ++i) {
+ framebuffers[i] = gles2_get_TGLuint(s,
+ framebuffersp + i*sizeof(TGLuint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteFramebuffers(n, framebuffers);
+ free(framebuffers);
+}
+
+GLES2_CB(glDeleteRenderbuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, renderbuffersp);
+
+ GLsizei i;
+ GLuint* renderbuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ for (i = 0; i < n; ++i) {
+ renderbuffers[i] = gles2_get_TGLuint(s,
+ renderbuffersp + i*sizeof(TGLuint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteRenderbuffers(n, renderbuffers);
+ free(renderbuffers);
+}
+
+GLES2_CB(glFramebufferRenderbuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, attachment);
+ GLES2_ARG(TGLenum, renderbuffertarget);
+ GLES2_ARG(TGLuint, renderbuffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glFramebufferRenderbuffer(target, attachment,
+ renderbuffertarget, renderbuffer);
+}
+
+GLES2_CB(glFramebufferTexture2D)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, attachment);
+ GLES2_ARG(TGLenum, textarget);
+ GLES2_ARG(TGLuint, texture);
+ GLES2_ARG(TGLint, level);
+ GLES2_BARRIER_ARG_NORET;
+
+ glFramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+GLES2_CB(glGenFramebuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, framebuffersp);
+
+ GLsizei i;
+ GLuint* framebuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ glGenFramebuffers(n, framebuffers);
+ for(i = 0; i < n; ++i) {
+ gles2_put_TGLuint(s, framebuffersp + i*sizeof(TGLuint),
+ framebuffers[i]);
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ free(framebuffers);
+}
+
+GLES2_CB(glGenRenderbuffers)//(GLsizei n, GLuint* renderbuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, renderbuffersp);
+
+ GLsizei i;
+ GLuint* renderbuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ glGenRenderbuffers(n, renderbuffers);
+ for(i = 0; i < n; ++i) {
+ gles2_put_TGLuint(s, renderbuffersp + i*sizeof(TGLuint),
+ renderbuffers[i]);
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ free(renderbuffers);
+}
+
+#if 0
+GLES2_CB(glGetFramebufferAttachmentParameteriv)//(GLenum target,
+ GLenum attachment, GLenum pname, GLint* params)
+{
+ DUMMY();
+}
+
+GLES2_CB(glGetRenderbufferParameteriv)//(GLenum target, GLenum pname,
+ GLint* params)
+{
+ DUMMY();
+}
+
+GLES2_CB(glIsFramebuffer)//(GLuint framebuffer)
+{
+ DUMMY();
+}
+
+GLES2_CB(glIsRenderbuffer)//(GLuint renderbuffer)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glBindBuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, buffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindTexture(target, buffer);
+}
+
+
+GLES2_CB(glRenderbufferStorage)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, internalformat);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_BARRIER_ARG_NORET;
+
+ glRenderbufferStorage(target, internalformat, width, height);
+}
+
+GLES2_CB(glDepthFunc)
+{
+ GLES2_ARG(TGLenum, func);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDepthFunc(func);
+}
+
+GLES2_CB(glDepthMask)
+{
+ GLES2_ARG(TGLboolean, flag);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDepthMask(flag);
+}
+
+GLES2_CB(glDepthRangef)
+{
+ GLES2_ARG(TGLclampf, zNear);
+ GLES2_ARG(TGLclampf, zFar);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDepthRangef(zNear, zFar);
+}
+
+GLES2_CB(glClearDepthf)
+{
+ GLES2_ARG(TGLclampf, depth);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClearDepthf(depth);
+}
+
diff --git a/hw/gles2_calls.h b/hw/gles2_calls.h
new file mode 100644
index 0000000..208693b
--- /dev/null
+++ b/hw/gles2_calls.h
@@ -0,0 +1,189 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) any later version of the License.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+CALL_ENTRY(eglGetError)
+CALL_ENTRY(eglGetDisplay)
+CALL_ENTRY(eglInitialize)
+CALL_DUMMY(eglTerminate)
+CALL_DUMMY(eglQueryString)
+CALL_ENTRY(eglGetConfigs)
+CALL_ENTRY(eglChooseConfig)
+CALL_ENTRY(eglGetConfigAttrib)
+CALL_ENTRY(eglCreateWindowSurface)
+CALL_DUMMY(eglCreatePbufferSurface)
+CALL_ENTRY(eglCreatePixmapSurface)
+CALL_ENTRY(eglDestroySurface)
+CALL_DUMMY(eglQuerySurface)
+CALL_DUMMY(eglBindAPI)
+CALL_DUMMY(eglQueryAPI)
+CALL_DUMMY(eglWaitClient)
+CALL_DUMMY(eglReleaseThread)
+CALL_DUMMY(eglCreatePbufferFromClientBuffer)
+CALL_DUMMY(eglSurfaceAttrib)
+CALL_ENTRY(eglBindTexImage)
+CALL_ENTRY(eglReleaseTexImage)
+CALL_DUMMY(eglSwapInterval)
+CALL_ENTRY(eglCreateContext)
+CALL_ENTRY(eglDestroyContext)
+CALL_ENTRY(eglMakeCurrent)
+CALL_DUMMY(eglGetCurrentContext)
+CALL_DUMMY(eglGetCurrentSurface)
+CALL_DUMMY(eglGetCurrentDisplay)
+CALL_DUMMY(eglQueryContext)
+CALL_DUMMY(eglWaitGL)
+CALL_DUMMY(eglWaitNative)
+CALL_ENTRY(eglSwapBuffers)
+CALL_DUMMY(eglCopyBuffers)
+CALL_DUMMY(eglGetProcAddress)
+
+CALL_ENTRY(glActiveTexture)
+CALL_ENTRY(glAttachShader)
+CALL_ENTRY(glBindAttribLocation)
+CALL_ENTRY(glBindBuffer)
+CALL_ENTRY(glBindFramebuffer)
+CALL_ENTRY(glBindRenderbuffer)
+CALL_ENTRY(glBindTexture)
+CALL_ENTRY(glBlendColor)
+CALL_ENTRY(glBlendEquation)
+CALL_ENTRY(glBlendEquationSeparate)
+CALL_ENTRY(glBlendFunc)
+CALL_ENTRY(glBlendFuncSeparate)
+CALL_DUMMY(glBufferData)
+CALL_DUMMY(glBufferSubData)
+CALL_ENTRY(glCheckFramebufferStatus)
+CALL_ENTRY(glClear)
+CALL_ENTRY(glClearColor)
+CALL_ENTRY(glClearDepthf)
+CALL_ENTRY(glClearStencil)
+CALL_ENTRY(glColorMask)
+CALL_ENTRY(glCompileShader)
+CALL_DUMMY(glCompressedTexImage2D)
+CALL_DUMMY(glCompressedTexSubImage2D)
+CALL_DUMMY(glCopyTexImage2D)
+CALL_DUMMY(glCopyTexSubImage2D)
+CALL_ENTRY(glCreateProgram)
+CALL_ENTRY(glCreateShader)
+CALL_ENTRY(glCullFace)
+CALL_DUMMY(glDeleteBuffers)
+CALL_ENTRY(glDeleteFramebuffers)
+CALL_ENTRY(glDeleteProgram)
+CALL_ENTRY(glDeleteRenderbuffers)
+CALL_ENTRY(glDeleteShader)
+CALL_ENTRY(glDeleteTextures)
+CALL_ENTRY(glDepthFunc)
+CALL_ENTRY(glDepthMask)
+CALL_ENTRY(glDepthRangef)
+CALL_DUMMY(glDetachShader)
+CALL_ENTRY(glDisable)
+CALL_ENTRY(glDisableVertexAttribArray)
+CALL_ENTRY(glDrawArrays)
+CALL_ENTRY(glDrawElements)
+CALL_ENTRY(glEnable)
+CALL_ENTRY(glEnableVertexAttribArray)
+CALL_ENTRY(glFinish)
+CALL_ENTRY(glFlush)
+CALL_ENTRY(glFramebufferRenderbuffer)
+CALL_ENTRY(glFramebufferTexture2D)
+CALL_ENTRY(glFrontFace)
+CALL_DUMMY(glGenBuffers)
+CALL_ENTRY(glGenerateMipmap)
+CALL_ENTRY(glGenFramebuffers)
+CALL_ENTRY(glGenRenderbuffers)
+CALL_ENTRY(glGenTextures)
+CALL_DUMMY(glGetActiveAttrib)
+CALL_DUMMY(glGetActiveUniform)
+CALL_DUMMY(glGetAttachedShaders)
+CALL_ENTRY(glGetAttribLocation)
+CALL_ENTRY(glGetBooleanv)
+CALL_DUMMY(glGetBufferParameteriv)
+CALL_ENTRY(glGetError)
+CALL_ENTRY(glGetFloatv)
+CALL_DUMMY(glGetFramebufferAttachmentParameteriv)
+CALL_ENTRY(glGetIntegerv)
+CALL_ENTRY(glGetProgramiv)
+CALL_ENTRY(glGetProgramInfoLog)
+CALL_DUMMY(glGetRenderbufferParameteriv)
+CALL_ENTRY(glGetShaderiv)
+CALL_ENTRY(glGetShaderInfoLog)
+CALL_DUMMY(glGetShaderPrecisionFormat)
+CALL_DUMMY(glGetShaderSource)
+CALL_DUMMY(glGetString)
+CALL_ENTRY(glGetTexParameterfv)
+CALL_ENTRY(glGetTexParameteriv)
+CALL_DUMMY(glGetUniformfv)
+CALL_DUMMY(glGetUniformiv)
+CALL_ENTRY(glGetUniformLocation)
+CALL_DUMMY(glGetVertexAttribfv)
+CALL_DUMMY(glGetVertexAttribiv)
+CALL_DUMMY(glGetVertexAttribPointerv)
+CALL_ENTRY(glHint)
+CALL_DUMMY(glIsBuffer)
+CALL_ENTRY(glIsEnabled)
+CALL_DUMMY(glIsFramebuffer)
+CALL_ENTRY(glIsProgram)
+CALL_DUMMY(glIsRenderbuffer)
+CALL_ENTRY(glIsShader)
+CALL_ENTRY(glIsTexture)
+CALL_ENTRY(glLineWidth)
+CALL_ENTRY(glLinkProgram)
+CALL_ENTRY(glPixelStorei)
+CALL_ENTRY(glPolygonOffset)
+CALL_ENTRY(glReadPixels)
+CALL_DUMMY(glReleaseShaderCompiler)
+CALL_ENTRY(glRenderbufferStorage)
+CALL_ENTRY(glSampleCoverage)
+CALL_ENTRY(glScissor)
+CALL_DUMMY(glShaderBinary)
+CALL_ENTRY(glShaderSource)
+CALL_ENTRY(glStencilFunc)
+CALL_ENTRY(glStencilFuncSeparate)
+CALL_ENTRY(glStencilMask)
+CALL_ENTRY(glStencilMaskSeparate)
+CALL_ENTRY(glStencilOp)
+CALL_ENTRY(glStencilOpSeparate)
+CALL_ENTRY(glTexImage2D)
+CALL_ENTRY(glTexParameterf)
+CALL_ENTRY(glTexParameterfv)
+CALL_ENTRY(glTexParameteri)
+CALL_ENTRY(glTexParameteriv)
+CALL_ENTRY(glTexSubImage2D)
+CALL_ENTRY(glUniform1f)
+CALL_ENTRY(glUniform1fv)
+CALL_ENTRY(glUniform1i)
+CALL_ENTRY(glUniform1iv)
+CALL_ENTRY(glUniform2f)
+CALL_ENTRY(glUniform2fv)
+CALL_ENTRY(glUniform2i)
+CALL_ENTRY(glUniform2iv)
+CALL_ENTRY(glUniform3f)
+CALL_ENTRY(glUniform3fv)
+CALL_ENTRY(glUniform3i)
+CALL_ENTRY(glUniform3iv)
+CALL_ENTRY(glUniform4f)
+CALL_ENTRY(glUniform4fv)
+CALL_ENTRY(glUniform4i)
+CALL_ENTRY(glUniform4iv)
+CALL_ENTRY(glUniformMatrix2fv)
+CALL_ENTRY(glUniformMatrix3fv)
+CALL_ENTRY(glUniformMatrix4fv)
+CALL_ENTRY(glUseProgram)
+CALL_DUMMY(glValidateProgram)
+CALL_ENTRY(glVertexAttrib1f)
+CALL_ENTRY(glVertexAttrib1fv)
+CALL_ENTRY(glVertexAttrib2f)
+CALL_ENTRY(glVertexAttrib2fv)
+CALL_ENTRY(glVertexAttrib3f)
+CALL_ENTRY(glVertexAttrib3fv)
+CALL_ENTRY(glVertexAttrib4f)
+CALL_ENTRY(glVertexAttrib4fv)
+CALL_ENTRY(glVertexAttribPointer)
+CALL_ENTRY(glViewport)
+
diff --git a/hw/nseries.c b/hw/nseries.c
index 27d517b..2617de8 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1554,6 +1554,10 @@ static QEMUMachine n810_machine = {
.init = n810_init,
};
+#ifdef CONFIG_GLES2
+#include "gles2.h"
+#endif
+
#define N900_SDRAM_SIZE (256 * 1024 * 1024)
#define N900_ONENAND_CS 0
#define N900_ONENAND_BUFSIZE (0xc000 << 1)
@@ -2135,6 +2139,9 @@ struct n900_s {
void *tpa6130;
void *lis302dl;
void *smc;
+#ifdef CONFIG_GLES2
+ void *gles2;
+#endif
int extended_key;
int slide_open;
int camera_cover_open;
@@ -2397,6 +2404,9 @@ static void n900_init(ram_addr_t ram_size,
qemu_add_kbd_event_handler(n900_key_handler, s);
qemu_set_display_close_handler(n900_display_close_callback, s);
+#ifdef CONFIG_GLES2
+ s->gles2 = gles2_init(s->cpu->env);
+#endif
qemu_register_reset(n900_reset, s);
n900_reset(s);
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 8450b45..ea07497 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -863,6 +863,25 @@ STEXI
@end table
ETEXI
+#ifdef TARGET_ARM
+DEFHEADING(arm target only:)
+#endif
+STEXI
+@table @option
+ETEXI
+
+#if(defined TARGET_ARM && defined CONFIG_GLES2)
+DEF("gles2-quality", HAS_ARG, QEMU_OPTION_gles2_quality,
+ "-gles2-quality set GLES 2.0 rendering quality [0 ... 100]\n")
+#endif
+
+#ifdef TARGET_ARM
+DEFHEADING()
+#endif
+STEXI
+@end table
+ETEXI
+
DEFHEADING(Network options:)
STEXI
@table @option
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 99c5b12..a726947 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1168,7 +1168,15 @@ static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type,
return 0;
}
-static inline int get_phys_addr(CPUState *env, uint32_t address,
+#ifdef CONFIG_GLES2
+int get_phys_addr(CPUState *env, uint32_t address,
+ int access_type, int is_user,
+ uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size);
+#else
+static
+#endif
+int get_phys_addr(CPUState *env, uint32_t address,
int access_type, int is_user,
uint32_t *phys_ptr, int *prot,
target_ulong *page_size)
diff --git a/vl.c b/vl.c
index bc7635c..f43879b 100644
--- a/vl.c
+++ b/vl.c
@@ -4342,6 +4342,16 @@ int main(int argc, char **argv, char **envp)
}
break;
#endif
+#ifdef TARGET_ARM
+#ifdef CONFIG_GLES2
+ case QEMU_OPTION_gles2_quality:
+ {
+ extern int gles2_quality;
+ gles2_quality = strtoul(optarg, NULL, 10);
+ }
+ break;
+#endif
+#endif
#ifdef CONFIG_KVM
case QEMU_OPTION_enable_kvm:
kvm_allowed = 1;
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 34/48] target-arm: add support for smc
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (28 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 33/48] Add OpenGL ES accelerator support Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 35/48] target-arm: fix neon vmon/vmvn with modified immediate Riku Voipio
` (14 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/omap3_boot.c | 32 +++++++++++++++--------
target-arm/cpu.h | 10 +++++--
target-arm/helper.c | 67 +++++++++++++++++++++++++++++++++++++++++++-----
target-arm/translate.c | 31 ++++++++++++++++++---
4 files changed, 114 insertions(+), 26 deletions(-)
diff --git a/hw/omap3_boot.c b/hw/omap3_boot.c
index c079c1d..6f3389f 100644
--- a/hw/omap3_boot.c
+++ b/hw/omap3_boot.c
@@ -98,12 +98,17 @@ static const uint8_t omap3_boot_rom[] = { /* 0x40014000-0x4001bfff */
0xff, 0xff, 0xff, 0xff, /* 0x40014048: booting parameter structure 4-7 */
0xff, 0xff, 0xff, 0xff, /* 0x4001404c: booting parameter structure 8-11 */
0x0e, 0xf0, 0xb0, 0xe1, /* 0x40014050: "movs pc, lr" */
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, /* 0x40014054 */
+ 0xff, 0xff, 0xff, 0xff, /* 0x40014058 */
+ 0xff, 0xff, 0xff, 0xff, /* 0x4001405c */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x40014060: monitor vector 0 (unused) */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x40014064: monitor vector 1 (unused) */
+ 0x15, 0x00, 0x00, 0xea, /* 0x40014068: monitor vector 2 (smc) */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x4001406c: monitor vector 3 (pabt) */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x40014070: monitor vector 4 (dabt) */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x40014074: monitor vector 5 (unused) */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x40014078: monitor vector 6 (irq) */
+ 0xfe, 0xff, 0xff, 0xea, /* 0x4001407c: monitor vector 7 (fiq) */
/* 0x40014080: Dead loops */
0xfe, 0xff, 0xff, 0xea, /* b 0x40014080 @ undefined exception */
0xfe, 0xff, 0xff, 0xea, /* b 0x40014084 @ swi exception */
@@ -123,9 +128,12 @@ static const uint8_t omap3_boot_rom[] = { /* 0x40014000-0x4001bfff */
0xfe, 0xff, 0xff, 0xea, /* b 0x400140bc @ reserved */
/* 0x400140c0: should perform a software reset & jump to r0 */
0x00, 0xf0, 0xa0, 0xe1, /* mov pc, r0 */
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* 0x400140c4: monitor mode smc vector handler */
+ 0x02, 0x00, 0x5c, 0xe3, /* cmp r12, #2 */
+ 0x50, 0x0f, 0x29, 0xee, /* mcreq p15, 1, r0, c9, c0, 2 @ l2c aux ctrl */
+ 0x03, 0x00, 0x5c, 0xe3, /* cmp r12, #3 */
+ 0x30, 0x0f, 0x01, 0xee, /* mcreq p15, 0, r0, c1, c0, 1 @ aux ctrl*/
+ 0x0e, 0xf0, 0xb0, 0xe1, /* movs pc, r14 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -153,8 +161,10 @@ static const uint8_t omap3_boot_rom[] = { /* 0x40014000-0x4001bfff */
0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048 @ 2kB UND stack */
0xd3, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd3 @ enter SVC mode */
0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 @ 23kB left for SVC stack */
- 0x44, 0x00, 0x04, 0xe3, /* movw r0, #0x4044 */
- 0x01, 0x00, 0x44, 0xe3, /* movt r0, #0x4001 @ r0 -> booting parameter struct */
+ 0x60, 0x00, 0x04, 0xe3, /* movw r0, #0x4060 @ r0 -> monitor vba */
+ 0x01, 0x00, 0x44, 0xe3, /* movt r0, #0x4001 */
+ 0x30, 0x0f, 0x0c, 0xfe, /* mcr2 p15, 0, r0, c12, c0, 1 */
+ 0x1c, 0x00, 0x40, 0xe2, /* sub r0, r0, #1c @ r0 -> booting parameter struct */
0x01, 0xf0, 0xa0, 0xe1, /* mov pc, r1 */
};
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 3c5e181..7440163 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -41,6 +41,7 @@
#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */
#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */
#define EXCP_STREX 10
+#define EXCP_SMC 11 /* secure monitor call */
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
@@ -80,9 +81,9 @@ typedef struct CPUARMState {
uint32_t spsr;
/* Banked registers. */
- uint32_t banked_spsr[6];
- uint32_t banked_r13[6];
- uint32_t banked_r14[6];
+ uint32_t banked_spsr[7];
+ uint32_t banked_r13[7];
+ uint32_t banked_r14[7];
/* These hold r8-r12. */
uint32_t usr_regs[5];
@@ -129,6 +130,8 @@ typedef struct CPUARMState {
uint32_t c6_data;
uint32_t c9_insn; /* Cache lockdown registers. */
uint32_t c9_data;
+ uint32_t c12_vbar; /* secure/nonsecure vector base address register. */
+ uint32_t c12_mvbar; /* monitor vector base address register. */
uint32_t c13_fcse; /* FCSE PID. */
uint32_t c13_context; /* Context ID. */
uint32_t c13_tls1; /* User RW Thread register. */
@@ -308,6 +311,7 @@ enum arm_cpu_mode {
ARM_CPU_MODE_FIQ = 0x11,
ARM_CPU_MODE_IRQ = 0x12,
ARM_CPU_MODE_SVC = 0x13,
+ ARM_CPU_MODE_SMC = 0x16,
ARM_CPU_MODE_ABT = 0x17,
ARM_CPU_MODE_UND = 0x1b,
ARM_CPU_MODE_SYS = 0x1f
diff --git a/target-arm/helper.c b/target-arm/helper.c
index a726947..798e9f9 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -586,6 +586,8 @@ static inline int bank_number (int mode)
return 4;
case ARM_CPU_MODE_FIQ:
return 5;
+ case ARM_CPU_MODE_SMC:
+ return 6;
}
cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
return -1;
@@ -835,13 +837,39 @@ void do_interrupt(CPUARMState *env)
mask = CPSR_A | CPSR_I | CPSR_F;
offset = 4;
break;
+ case EXCP_SMC:
+ if (semihosting_enabled) {
+ cpu_abort(env, "SMC handling under semihosting not implemented\n");
+ return;
+ }
+ if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_SMC) {
+ env->cp15.c1_secfg &= ~1;
+ }
+ offset = env->thumb ? 2 : 0;
+ new_mode = ARM_CPU_MODE_SMC;
+ addr = 0x08;
+ mask = CPSR_A | CPSR_I | CPSR_F;
+ break;
default:
cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
return; /* Never happens. Keep compiler happy. */
}
- /* High vectors. */
- if (env->cp15.c1_sys & (1 << 13)) {
- addr += 0xffff0000;
+ if (arm_feature(env, ARM_FEATURE_TRUSTZONE)) {
+ if (new_mode == ARM_CPU_MODE_SMC ||
+ (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_SMC) {
+ addr += env->cp15.c12_mvbar;
+ } else {
+ if (env->cp15.c1_sys & (1 << 13)) {
+ addr += 0xffff0000;
+ } else {
+ addr += env->cp15.c12_vbar;
+ }
+ }
+ } else {
+ /* High vectors. */
+ if (env->cp15.c1_sys & (1 << 13)) {
+ addr += 0xffff0000;
+ }
}
switch_mode (env, new_mode);
env->spsr = cpsr_read(env);
@@ -1538,6 +1566,27 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
/* ??? TLB lockdown not implemented. */
break;
case 12: /* Reserved. */
+ if (!op1 && !crm) {
+ switch (op2) {
+ case 0:
+ if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)) {
+ goto bad_reg;
+ }
+ env->cp15.c12_vbar = val & ~0x1f;
+ break;
+ case 1:
+ if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)) {
+ goto bad_reg;
+ }
+ if (!(env->cp15.c1_secfg & 1)) {
+ env->cp15.c12_mvbar = val & ~0x1f;
+ }
+ break;
+ default:
+ goto bad_reg;
+ }
+ break;
+ }
goto bad_reg;
case 13: /* Process ID. */
switch (op2) {
@@ -1856,12 +1905,16 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
return 0;
case 11: /* TCM DMA control. */
case 12: /* Reserved. */
- if (!op1) {
- switch (crm) {
+ if (!op1 && !crm) {
+ switch (op2) {
case 0: /* secure or nonsecure vector base address */
if (arm_feature(env, ARM_FEATURE_TRUSTZONE)) {
- /* FIXME: implement true vector base addressing */
- return 0; /* reset value according to ARM Cortex-A8 TRM */
+ return env->cp15.c12_vbar;
+ }
+ break;
+ case 1: /* monitor vector base address */
+ if (arm_feature(env, ARM_FEATURE_TRUSTZONE)) {
+ return env->cp15.c12_mvbar;
}
break;
default:
diff --git a/target-arm/translate.c b/target-arm/translate.c
index b214bff..e5f5cfb 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -73,6 +73,7 @@ typedef struct DisasContext {
conditional executions state has been updated. */
#define DISAS_WFI 4
#define DISAS_SWI 5
+#define DISAS_SMC 6
static TCGv_ptr cpu_env;
/* We reuse the same 64-bit temporaries for efficiency. */
@@ -837,6 +838,12 @@ static inline void store_reg_bx(CPUState *env, DisasContext *s,
}
}
+static inline void gen_smc(CPUState *env, DisasContext *s)
+{
+ tcg_gen_movi_i32(cpu_R[15], s->pc);
+ s->is_jmp = DISAS_SMC;
+}
+
static inline TCGv gen_ld8s(TCGv addr, int index)
{
TCGv tmp = new_tmp();
@@ -6245,8 +6252,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
}
} else if ((insn & 0x0fe00000) == 0x0c400000) {
/* Coprocessor double register transfer. */
+ cpu_abort(env, "unsupported coprocessor double register transfer\n");
} else if ((insn & 0x0f000010) == 0x0e000010) {
/* Additional coprocessor register transfer. */
+ if (!disas_coproc_insn(env, s, insn)) {
+ return;
+ }
} else if ((insn & 0x0ff10020) == 0x01000000) {
uint32_t mask;
uint32_t val;
@@ -6401,10 +6412,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
s->is_jmp = DISAS_JUMP;
} else if (op1 == 3) {
/* smi/smc */
- if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s))
+ if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s)) {
goto illegal_op;
- /* TODO: real implementation; execute as NOP for now */
- /*fprintf(stderr, "smc [0x%08x] pc=0x%08x\n", insn, s->pc);*/
+ }
+ gen_smc(env, s);
} else {
goto illegal_op;
}
@@ -7991,8 +8002,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
goto illegal_op;
if (insn & (1 << 26)) {
- /* Secure monitor call (v6Z) */
- goto illegal_op; /* not implemented. */
+ /* Secure monitor call / smc (v6Z) */
+ if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s)) {
+ goto illegal_op;
+ }
+ gen_smc(env, s);
} else {
op = (insn >> 20) & 7;
switch (op) {
@@ -9245,6 +9259,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_SWI) {
gen_exception(EXCP_SWI);
+ } else if (dc->is_jmp == DISAS_SMC) {
+ gen_exception(EXCP_SMC);
} else {
gen_exception(EXCP_DEBUG);
}
@@ -9257,6 +9273,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
gen_exception(EXCP_SWI);
+ } else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) {
+ gen_exception(EXCP_SMC);
} else {
/* FIXME: Single stepping a WFI insn will not halt
the CPU. */
@@ -9291,6 +9309,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
case DISAS_SWI:
gen_exception(EXCP_SWI);
break;
+ case DISAS_SMC:
+ gen_exception(EXCP_SMC);
+ break;
}
if (dc->condjmp) {
gen_set_label(dc->condlabel);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 35/48] target-arm: fix neon vmon/vmvn with modified immediate
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (29 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 34/48] target-arm: add support for smc Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 36/48] target-arm: fix neon vqshl/vqshlu instructions Riku Voipio
` (13 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/translate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index e5f5cfb..26e6bf4 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4905,7 +4905,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
imm = (imm << 8) | (imm << 24);
break;
case 12:
- imm = (imm < 8) | 0xff;
+ imm = (imm << 8) | 0xff;
break;
case 13:
imm = (imm << 16) | 0xffff;
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 36/48] target-arm: fix neon vqshl/vqshlu instructions
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (30 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 35/48] target-arm: fix neon vmon/vmvn with modified immediate Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 37/48] target-arm: fix neon vqrshl instruction Riku Voipio
` (12 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/helpers.h | 4 +++
target-arm/neon_helper.c | 58 +++++++++++++++++++++++++++++++++++++++++----
target-arm/translate.c | 28 +++++++++++-----------
3 files changed, 70 insertions(+), 20 deletions(-)
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index a5fd2e8..e1a8136 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -253,6 +253,10 @@ DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32)
DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32)
DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64)
DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64)
DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32)
DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32)
DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 924bf40..7985293 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -600,8 +600,6 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
if (val) {
val = ~(uint64_t)0;
SET_QC();
- } else {
- val = 0;
}
} else if (shift <= -64) {
val = 0;
@@ -622,9 +620,10 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
int8_t tmp; \
tmp = (int8_t)src2; \
if (tmp >= (ssize_t)sizeof(src1) * 8) { \
- if (src1) \
+ if (src1) { \
SET_QC(); \
- dest = src1 >> 31; \
+ } \
+ dest = src1 ? ((uint32_t)(1 << (sizeof(src1) * 8 - 1)) - (src1 > 0 ? 1 : 0)) : 0; \
} else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
dest = src1 >> 31; \
} else if (tmp < 0) { \
@@ -633,7 +632,7 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
dest = src1 << tmp; \
if ((dest >> tmp) != src1) { \
SET_QC(); \
- dest = src2 >> 31; \
+ dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)) - (src1 > 0 ? 1 : 0); \
} \
}} while (0)
NEON_VOP_ENV(qshl_s8, neon_s8, 4)
@@ -650,7 +649,7 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
SET_QC();
val = (val >> 63) & ~SIGNBIT64;
}
- } else if (shift <= 64) {
+ } else if (shift <= -64) {
val >>= 63;
} else if (shift < 0) {
val >>= -shift;
@@ -665,6 +664,53 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
return val;
}
+#define NEON_FN(dest, src1, src2) do { \
+ if (src1 & (1 << (sizeof(src1) * 8 - 1))) { \
+ SET_QC(); \
+ dest = 0; \
+ } else { \
+ int8_t tmp; \
+ tmp = (int8_t)src2; \
+ if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+ if (src1) { \
+ SET_QC(); \
+ dest = ~0; \
+ } else { \
+ dest = 0; \
+ } \
+ } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+ dest = 0; \
+ } else if (tmp < 0) { \
+ dest = src1 >> -tmp; \
+ } else { \
+ dest = src1 << tmp; \
+ if ((dest >> tmp) != src1) { \
+ SET_QC(); \
+ dest = ~0; \
+ } \
+ } \
+ }} while (0)
+NEON_VOP_ENV(qshlu_s8, neon_u8, 4)
+NEON_VOP_ENV(qshlu_s16, neon_u16, 2)
+#undef NEON_FN
+
+uint32_t HELPER(neon_qshlu_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+{
+ if ((int32_t)valop < 0) {
+ SET_QC();
+ return 0;
+ }
+ return helper_neon_qshl_u32(env, valop, shiftop);
+}
+
+uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+{
+ if ((int64_t)valop < 0) {
+ SET_QC();
+ return 0;
+ }
+ return helper_neon_qshl_u64(env, valop, shiftop);
+}
/* FIXME: This is wrong. */
#define NEON_FN(dest, src1, src2) do { \
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 26e6bf4..97fac4d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4139,9 +4139,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 9: /* VQSHL */
if (u) {
gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
- cpu_V0, cpu_V0);
+ cpu_V1, cpu_V0);
} else {
- gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
+ gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
cpu_V1, cpu_V0);
}
break;
@@ -4612,10 +4612,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
break;
case 6: /* VQSHLU */
- gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0,
- cpu_V1);
+ gen_helper_neon_qshlu_s64(cpu_V0, cpu_env, cpu_V0,
+ cpu_V1);
break;
- case 7: /* VQSHL/VQSHLU */
+ case 7: /* VQSHL */
if (u) {
gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
cpu_V0, cpu_V1);
@@ -4673,26 +4673,26 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
break;
case 6: /* VQSHLU */
- GEN_NEON_INTEGER_OP_ENV(qshl);
- break;
- case 7: /* VQSHLU */
switch (size) {
case 0:
- gen_helper_neon_qshl_u8(tmp, cpu_env, tmp,
- tmp2);
+ gen_helper_neon_qshlu_s8(tmp, cpu_env, tmp,
+ tmp2);
break;
case 1:
- gen_helper_neon_qshl_u16(tmp, cpu_env, tmp,
- tmp2);
+ gen_helper_neon_qshlu_s16(tmp, cpu_env, tmp,
+ tmp2);
break;
case 2:
- gen_helper_neon_qshl_u32(tmp, cpu_env, tmp,
- tmp2);
+ gen_helper_neon_qshlu_s32(tmp, cpu_env, tmp,
+ tmp2);
break;
default:
abort(); /* size == 3 is handled earlier */
}
break;
+ case 7: /* VQSHL */
+ GEN_NEON_INTEGER_OP_ENV(qshl);
+ break;
}
tcg_temp_free_i32(tmp2);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 37/48] target-arm: fix neon vqrshl instruction
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (31 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 36/48] target-arm: fix neon vqshl/vqshlu instructions Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:06 ` [Qemu-devel] [PATCH 38/48] target-arm: fix neon vrshl instruction Riku Voipio
` (11 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 21 ++++++++++++++++++---
1 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 7985293..ec1964f 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -727,9 +727,24 @@ uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
}} while (0)
NEON_VOP_ENV(qrshl_u8, neon_u8, 4)
NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
-NEON_VOP_ENV(qrshl_u32, neon_u32, 1)
#undef NEON_FN
+uint32_t HELPER(neon_qrshl_u32)(CPUState *env, uint32_t val, uint32_t shiftop)
+{
+ int8_t shift = (int8_t)shiftop;
+ if (shift < 0) {
+ val = ((uint64_t)val + (1 << (-1 - shift))) >> -shift;
+ } else {
+ uint32_t tmp = val;
+ val <<= shift;
+ if ((val >> shift) != tmp) {
+ SET_QC();
+ val = ~0;
+ }
+ }
+ return val;
+}
+
uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
{
int8_t shift = (int8_t)shiftop;
@@ -755,7 +770,7 @@ uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
dest = src1 << tmp; \
if ((dest >> tmp) != src1) { \
SET_QC(); \
- dest = src1 >> 31; \
+ dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)) - (src1 > 0 ? 1 : 0); \
} \
}} while (0)
NEON_VOP_ENV(qrshl_s8, neon_s8, 4)
@@ -771,7 +786,7 @@ uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
if (shift < 0) {
val = (val + (1 << (-1 - shift))) >> -shift;
} else {
- int64_t tmp = val;;
+ int64_t tmp = val;
val <<= shift;
if ((val >> shift) != tmp) {
SET_QC();
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 38/48] target-arm: fix neon vrshl instruction
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (32 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 37/48] target-arm: fix neon vqrshl instruction Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 17:26 ` Nathan Froyd
2010-03-26 16:06 ` [Qemu-devel] [PATCH 39/48] target-arm: fix neon vrshr instruction Riku Voipio
` (10 subsequent siblings)
44 siblings, 1 reply; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 19 ++++++++++++++++---
1 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index ec1964f..0df13f5 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -547,20 +547,33 @@ uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
}} while (0)
NEON_VOP(rshl_u8, neon_u8, 4)
NEON_VOP(rshl_u16, neon_u16, 2)
-NEON_VOP(rshl_u32, neon_u32, 1)
#undef NEON_FN
+uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
+{
+ int8_t shift = (int8_t)shiftop;
+ if (shift >= 32 || shift < -32) {
+ val = 0;
+ } else if (shift == -32) {
+ val >>= shift - 1;
+ } else if (shift < 0) {
+ val = ((uint64_t)val + (1 << (-1 - shift))) >> -shift;
+ } else {
+ val <<= shift;
+ }
+ return val;
+}
+
uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
{
int8_t shift = (uint8_t)shiftop;
- if (shift >= 64 || shift < 64) {
+ if (shift >= 64 || shift < -64) {
val = 0;
} else if (shift == -64) {
/* Rounding a 1-bit result just preserves that bit. */
val >>= 63;
} if (shift < 0) {
val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift;
- val >>= -shift;
} else {
val <<= shift;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 38/48] target-arm: fix neon vrshl instruction
2010-03-26 16:06 ` [Qemu-devel] [PATCH 38/48] target-arm: fix neon vrshl instruction Riku Voipio
@ 2010-03-26 17:26 ` Nathan Froyd
0 siblings, 0 replies; 55+ messages in thread
From: Nathan Froyd @ 2010-03-26 17:26 UTC (permalink / raw)
To: Riku Voipio; +Cc: Riku Voipio, Juha Riihimäki, qemu-devel
On Fri, Mar 26, 2010 at 04:06:58PM +0000, Riku Voipio wrote:
> +uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
> +{
> + int8_t shift = (int8_t)shiftop;
> + if (shift >= 32 || shift < -32) {
> + val = 0;
> + } else if (shift == -32) {
> + val >>= shift - 1;
^^^^^^^^^^^^^^^^^
This looks wrong. Compare the equivalent case for 64-bit:
> uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
> } else if (shift == -64) {
> /* Rounding a 1-bit result just preserves that bit. */
> val >>= 63;
Bonus points for factoring out the duplicated 32/64-bit code.
-Nathan
^ permalink raw reply [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 39/48] target-arm: fix neon vrshr instruction
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (33 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 38/48] target-arm: fix neon vrshl instruction Riku Voipio
@ 2010-03-26 16:06 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 40/48] target-arm: fix neon v(r)sra instructions Riku Voipio
` (9 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 0df13f5..4604698 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -573,7 +573,13 @@ uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
/* Rounding a 1-bit result just preserves that bit. */
val >>= 63;
} if (shift < 0) {
- val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift;
+ uint64_t r = ((uint64_t)1 << (-1 - shift));
+ uint64_t lo = val + r;
+ if (lo < val || lo < r) {
+ val = (lo >> -shift) | ((1ull << 63) >> (-shift - 1));
+ } else {
+ val = lo >> -shift;
+ }
} else {
val <<= shift;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 40/48] target-arm: fix neon v(r)sra instructions
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (34 preceding siblings ...)
2010-03-26 16:06 ` [Qemu-devel] [PATCH 39/48] target-arm: fix neon vrshr instruction Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 41/48] target-arm: fix neon vld1 single element to all lanes Riku Voipio
` (8 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/translate.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 97fac4d..964baf5 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4627,7 +4627,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
if (op == 1 || op == 3) {
/* Accumulate. */
- neon_load_reg64(cpu_V0, rd + pass);
+ neon_load_reg64(cpu_V1, rd + pass);
tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
} else if (op == 4 || (op == 5 && u)) {
/* Insert */
@@ -4699,7 +4699,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (op == 1 || op == 3) {
/* Accumulate. */
tmp2 = neon_load_reg(rd, pass);
- gen_neon_add(size, tmp2, tmp);
+ gen_neon_add(size, tmp, tmp2);
dead_tmp(tmp2);
} else if (op == 4 || (op == 5 && u)) {
/* Insert */
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 41/48] target-arm: fix neon vld1 single element to all lanes
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (35 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 40/48] target-arm: fix neon v(r)sra instructions Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 42/48] target-arm: fix signed narrow 64->32 operation Riku Voipio
` (7 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/translate.c | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 964baf5..de2ea92 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3798,7 +3798,11 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
size = (insn >> 6) & 3;
nregs = ((insn >> 8) & 3) + 1;
- stride = (insn & (1 << 5)) ? 2 : 1;
+ if (nregs == 1) {
+ stride = 0;
+ } else {
+ stride = (insn & (1 << 5)) ? 2 : 1;
+ }
load_reg_var(s, addr, rn);
for (reg = 0; reg < nregs; reg++) {
switch (size) {
@@ -3819,7 +3823,12 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
default: /* Avoid compiler warnings. */
abort();
}
- tcg_gen_addi_i32(addr, addr, 1 << size);
+ if (stride && reg < nregs - 1) {
+ tcg_gen_addi_i32(addr, addr, 1 << size);
+ } else if (!stride) {
+ tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0));
+ tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1));
+ }
tmp2 = new_tmp();
tcg_gen_mov_i32(tmp2, tmp);
neon_store_reg(rd, 0, tmp2);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 42/48] target-arm: fix signed narrow 64->32 operation
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (36 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 41/48] target-arm: fix neon vld1 single element to all lanes Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 43/48] target-arm: fix neon vq(r)dmulh.s16 instructions Riku Voipio
` (6 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 4604698..910f84a 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -1183,9 +1183,13 @@ uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x)
{
- if ((int64_t)x != (int32_t)x) {
+ if ((int64_t)x < -2147483648ll) {
SET_QC();
- return (x >> 63) ^ 0x7fffffff;
+ return 0x80000000;
+ }
+ if ((int64_t)x > 2147483647ll) {
+ SET_QC();
+ return 0x7fffffff;
}
return x;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 43/48] target-arm: fix neon vq(r)dmulh.s16 instructions
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (37 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 42/48] target-arm: fix signed narrow 64->32 operation Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 44/48] target-arm: fix neon v(q)(r)shrn instructions Riku Voipio
` (5 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 910f84a..6464317 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -946,8 +946,9 @@ uint32_t HELPER(neon_cnt_u8)(uint32_t x)
if ((tmp ^ (tmp << 1)) & SIGNBIT) { \
SET_QC(); \
tmp = (tmp >> 31) ^ ~SIGNBIT; \
+ } else { \
+ tmp <<= 1; \
} \
- tmp <<= 1; \
if (round) { \
int32_t old = tmp; \
tmp += 1 << 15; \
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 44/48] target-arm: fix neon v(q)(r)shrn instructions
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (38 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 43/48] target-arm: fix neon vq(r)dmulh.s16 instructions Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 45/48] target-arm: fix neon vcvt fixed-point Riku Voipio
` (4 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 23 +++++++++++++++++++++--
target-arm/translate.c | 19 ++++++++++++++-----
2 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 6464317..7cef783 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -509,9 +509,28 @@ uint64_t HELPER(neon_shl_s64)(uint64_t valop, uint64_t shiftop)
}} while (0)
NEON_VOP(rshl_s8, neon_s8, 4)
NEON_VOP(rshl_s16, neon_s16, 2)
-NEON_VOP(rshl_s32, neon_s32, 1)
#undef NEON_FN
+uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
+{
+ int8_t shift =(int8_t)shiftop;
+ int32_t val = valop;
+ if (shift >= 32) {
+ val = 0;
+ } else if (shift < -32) {
+ val >>= 31;
+ } else if (shift == -32) {
+ val >>= 31;
+ val++;
+ val >>= 1;
+ } else if (shift < 0) {
+ val = ((int64_t)val + (1 << (-1 - shift))) >> -shift;
+ } else {
+ val <<= shift;
+ }
+ return val;
+}
+
uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
{
int8_t shift = (int8_t)shiftop;
@@ -520,7 +539,7 @@ uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
val = 0;
} else if (shift < -64) {
val >>= 63;
- } else if (shift == -63) {
+ } else if (shift == -64) {
val >>= 63;
val++;
val >>= 1;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index de2ea92..92c8a1a 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4781,6 +4781,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
abort();
}
+ TCGV_UNUSED(tmp5);
for (pass = 0; pass < 2; pass++) {
if (size == 3) {
neon_load_reg64(cpu_V0, rm + pass);
@@ -4812,18 +4813,26 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
dead_tmp(tmp);
dead_tmp(tmp3);
}
- tmp = new_tmp();
+ tmp4 = new_tmp();
if (op == 8) {
if (u) { /* VQSHRUN / VQRSHRUN */
- gen_neon_unarrow_sats(size - 1, tmp, cpu_V0);
+ gen_neon_unarrow_sats(size - 1, tmp4, cpu_V0);
} else { /* VSHRN / VRSHRN */
- gen_neon_narrow(size - 1, tmp, cpu_V0);
+ gen_neon_narrow(size - 1, tmp4, cpu_V0);
}
} else { /* VQSHRN / VQRSHRN */
- gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
+ if (u) {
+ gen_neon_narrow_satu(size - 1, tmp4, cpu_V0);
+ } else {
+ gen_neon_narrow_sats(size - 1, tmp4, cpu_V0);
+ }
+ }
+ if (!pass) {
+ tmp5 = tmp4;
}
- neon_store_reg(rd, pass, tmp);
} /* for pass */
+ neon_store_reg(rd, 0, tmp5);
+ neon_store_reg(rd, 1, tmp4);
if (size == 3) {
tcg_temp_free_i64(tmp64);
} else {
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 45/48] target-arm: fix neon vcvt fixed-point
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (39 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 44/48] target-arm: fix neon v(q)(r)shrn instructions Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 46/48] target-arm: fix neon vrsqrts instruction Riku Voipio
` (3 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/translate.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 92c8a1a..fd3a72e 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4874,20 +4874,21 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
return 1;
}
+ shift = 64 - ((insn >> 16) & 0x3f);
for (pass = 0; pass < (q ? 4 : 2); pass++) {
tcg_gen_ld_f32(cpu_F0s, cpu_env,
neon_reg_offset(rm, pass));
if (op & 1) {
if (u) {
- gen_vfp_ulto(0, shift);
+ gen_vfp_toul(0, shift);
} else {
- gen_vfp_slto(0, shift);
+ gen_vfp_tosl(0, shift);
}
} else {
if (u) {
- gen_vfp_toul(0, shift);
+ gen_vfp_ulto(0, shift);
} else {
- gen_vfp_tosl(0, shift);
+ gen_vfp_slto(0, shift);
}
}
tcg_gen_st_f32(cpu_F0s, cpu_env,
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 46/48] target-arm: fix neon vrsqrts instruction
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (40 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 45/48] target-arm: fix neon vcvt fixed-point Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 47/48] target-arm: fix neon vshll (shift < max) Riku Voipio
` (2 subsequent siblings)
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/helper.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 798e9f9..1f5f307 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2687,8 +2687,9 @@ float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env)
{
float_status *s = &env->vfp.fp_status;
+ float32 two = int32_to_float32(2, s);
float32 three = int32_to_float32(3, s);
- return float32_sub(three, float32_mul(a, b, s), s);
+ return float32_div(float32_sub(three, float32_mul(a, b, s), s), two, s);
}
/* NEON helpers. */
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 47/48] target-arm: fix neon vshll (shift < max)
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (41 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 46/48] target-arm: fix neon vrsqrts instruction Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 16:07 ` [Qemu-devel] [PATCH 48/48] usb: fix -usbdevice option handling with no parameters Riku Voipio
2010-03-26 17:48 ` [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Paul Brook
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
target-arm/neon_helper.c | 1 -
target-arm/translate.c | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 7cef783..d75cb47 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -1484,7 +1484,6 @@ uint64_t HELPER(neon_negl_u16)(uint64_t x)
return result;
}
-#include <stdio.h>
uint64_t HELPER(neon_negl_u32)(uint64_t x)
{
uint32_t low = -x;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index fd3a72e..cd9dbce 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4855,7 +4855,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
/* The shift is less than the width of the source
type, so we can just shift the whole register. */
tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
- if (size < 2 || !u) {
+ if (size < 2) {
uint64_t imm64;
if (size == 0) {
imm = (0xffu >> (8 - shift));
@@ -4864,7 +4864,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
imm = 0xffff >> (16 - shift);
}
imm64 = imm | (((uint64_t)imm) << 32);
- tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
+ tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
}
}
neon_store_reg64(cpu_V0, rd + pass);
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [Qemu-devel] [PATCH 48/48] usb: fix -usbdevice option handling with no parameters
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (42 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 47/48] target-arm: fix neon vshll (shift < max) Riku Voipio
@ 2010-03-26 16:07 ` Riku Voipio
2010-03-26 17:48 ` [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Paul Brook
44 siblings, 0 replies; 55+ messages in thread
From: Riku Voipio @ 2010-03-26 16:07 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
hw/usb-bus.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index ce8a694..9132d00 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -299,7 +299,7 @@ USBDevice *usbdevice_create(const char *cmdline)
}
if (!usb->usbdevice_init) {
- if (params) {
+ if (params && *params) {
error_report("usbdevice %s accepts no params", driver);
return NULL;
}
--
1.6.5
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection
2010-03-26 16:06 [Qemu-devel] [PATCH 00/48] RFC: omap3 patch collection Riku Voipio
` (43 preceding siblings ...)
2010-03-26 16:07 ` [Qemu-devel] [PATCH 48/48] usb: fix -usbdevice option handling with no parameters Riku Voipio
@ 2010-03-26 17:48 ` Paul Brook
44 siblings, 0 replies; 55+ messages in thread
From: Paul Brook @ 2010-03-26 17:48 UTC (permalink / raw)
To: qemu-devel; +Cc: Riku Voipio, Riku Voipio
> This set of patches is quite raw, intended mostly just for discussion
> at this point. We'd like to identify the unobjectionable patches and
> "ready for upstream with minor fixes" patches first, so we can send
> them for a pull request. After which we can start diving more deeply
> into restructuring the remaining patches.
Your first step should be to split out unrelated changes. You're unlikely to
get any interest in a 48-patch series that contains a load of random crap.
Paul
^ permalink raw reply [flat|nested] 55+ messages in thread