From: Paul Brook <paul@codesourcery.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [patch] Arm arch5 support
Date: Sun, 1 Aug 2004 18:08:17 +0100 [thread overview]
Message-ID: <200408011808.17492.paul@codesourcery.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 194 bytes --]
The attached patch adds qemu target support for the new arm instructions
present in the armv5e instruction set.
I'm probably going to look at adding thumb support next, time permitting.
Paul
[-- Attachment #2: patch.qemu_5e --]
[-- Type: text/x-diff, Size: 14168 bytes --]
Index: cpu-exec.c
===================================================================
RCS file: /cvsroot/qemu/qemu/cpu-exec.c,v
retrieving revision 1.38
diff -u -p -r1.38 cpu-exec.c
--- cpu-exec.c 14 Jul 2004 17:20:55 -0000 1.38
+++ cpu-exec.c 1 Aug 2004 16:44:33 -0000
@@ -166,7 +166,8 @@ int cpu_exec(CPUState *env1)
env->CF = (psr >> 29) & 1;
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
env->VF = (psr << 3) & 0x80000000;
- env->cpsr = psr & ~0xf0000000;
+ env->QF = (psr >> 27) & 1;
+ env->cpsr = psr & ~0xf8000000;
}
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
@@ -296,7 +297,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
cpu_arm_dump_state(env, logfile, 0);
- env->cpsr &= ~0xf0000000;
+ env->cpsr &= ~0xf8000000;
#elif defined(TARGET_SPARC)
cpu_sparc_dump_state (env, logfile, 0);
#elif defined(TARGET_PPC)
Index: target-arm/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/cpu.h,v
retrieving revision 1.3
diff -u -p -r1.3 cpu.h
--- target-arm/cpu.h 25 Apr 2004 17:53:35 -0000 1.3
+++ target-arm/cpu.h 1 Aug 2004 16:44:33 -0000
@@ -35,6 +35,7 @@ typedef struct CPUARMState {
uint32_t CF; /* 0 or 1 */
uint32_t VF; /* V is the bit 31. All other bits are undefined */
uint32_t NZF; /* N is bit 31. Z is computed from NZF */
+ uint32_t QF; /* 0 or 1 */
/* exception/interrupt handling */
jmp_buf jmp_env;
Index: target-arm/exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/exec.h,v
retrieving revision 1.1
diff -u -p -r1.1 exec.h
--- target-arm/exec.h 30 Sep 2003 20:34:21 -0000 1.1
+++ target-arm/exec.h 1 Aug 2004 16:44:33 -0000
@@ -36,5 +36,5 @@ static inline int compute_cpsr(void)
int ZF;
ZF = (env->NZF == 0);
return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
- (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
+ (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27);
}
Index: target-arm/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/op.c,v
retrieving revision 1.3
diff -u -p -r1.3 op.c
--- target-arm/op.c 30 Nov 2003 19:40:08 -0000 1.3
+++ target-arm/op.c 1 Aug 2004 16:44:33 -0000
@@ -382,6 +382,14 @@ void OPPROTO op_imull_T0_T1(void)
T0 = res;
}
+/* 48 bit signed mul, top 32 bits */
+void OPPROTO op_imulw_T0_T1(void)
+{
+ uint64_t res;
+ res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
+ T0 = res >> 16;
+}
+
void OPPROTO op_addq_T0_T1(void)
{
uint64_t res;
@@ -391,6 +399,15 @@ void OPPROTO op_addq_T0_T1(void)
T0 = res;
}
+void OPPROTO op_addq_lo_T0_T1(void)
+{
+ uint64_t res;
+ res = ((uint64_t)T1 << 32) | T0;
+ res += (uint64_t)(env->regs[PARAM1]);
+ T1 = res >> 32;
+ T0 = res;
+}
+
void OPPROTO op_logicq_cc(void)
{
env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
@@ -643,6 +660,82 @@ void OPPROTO op_rorl_T1_T0_cc(void)
FORCE_RET();
}
+/* misc */
+void OPPROTO op_clz_T0(void)
+{
+ int count;
+ for (count = 32; T0 > 0; count--)
+ T0 = T0 >> 1;
+ T0 = count;
+ FORCE_RET();
+}
+
+void OPPROTO op_sarl_T0_im(void)
+{
+ T1 = (int32_t)T1 >> PARAM1;
+}
+
+/* Sign extend */
+void OPPROTO op_sxl_T0(void)
+{
+ T0 = (int16_t)T0;
+}
+
+void OPPROTO op_sxl_T1(void)
+{
+ T1 = (int16_t)T1;
+}
+
+#define SIGNBIT 0x80000000
+/* saturating arithmetic */
+void OPPROTO op_addl_T0_T1_setq(void)
+{
+ uint32_t res;
+
+ res = T0 + T1;
+ if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT))
+ env->QF = 1;
+
+ T0 = res;
+ FORCE_RET();
+}
+
+void OPPROTO op_addl_T0_T1_saturate(void)
+{
+ uint32_t res;
+
+ res = T0 + T1;
+ if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) {
+ env->QF = 1;
+ if (T0 & SIGNBIT)
+ T0 = 0x80000000;
+ else
+ T0 = 0x7fffffff;
+ }
+ else
+ T0 = res;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_subl_T0_T1_saturate(void)
+{
+ uint32_t res;
+
+ res = T0 - T1;
+ if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) {
+ env->QF = 1;
+ if (T0 & SIGNBIT)
+ T0 = 0x8000000;
+ else
+ T0 = 0x7fffffff;
+ }
+ else
+ T0 = res;
+
+ FORCE_RET();
+}
+
/* exceptions */
void OPPROTO op_swi(void)
Index: target-arm/translate.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/translate.c,v
retrieving revision 1.10
diff -u -p -r1.10 translate.c
--- target-arm/translate.c 22 Jun 2004 10:55:49 -0000 1.10
+++ target-arm/translate.c 1 Aug 2004 16:44:33 -0000
@@ -326,17 +326,136 @@ static void disas_arm_insn(DisasContext
s->pc += 4;
cond = insn >> 28;
- if (cond == 0xf)
+ if (cond == 0xf){
+ if ((insn & 0x0fd70f00) == 0x0550f000)
+ return; /* PLD */
goto illegal_op;
+ }
if (cond != 0xe) {
/* if not always execute, we generate a conditional jump to
next instruction */
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
s->is_jmp = DISAS_JUMP_NEXT;
}
- if (((insn & 0x0e000000) == 0 &&
- (insn & 0x00000090) != 0x90) ||
- ((insn & 0x0e000000) == (1 << 25))) {
+ if ((insn & 0x0d900000) == 0x01000000) {
+ /* Miscellaneous instructions */
+ if (insn & (1 << 25)) {
+ if ((insn & 0x0ff0f000) != 0x0360f000)
+ goto illegal_op;
+ /* CPSR = immediate */
+ val = insn & 0xff;
+ shift = ((insn >> 8) & 0xf) * 2;
+ if (shift)
+ val = (val >> shift) | (val << (32 - shift));
+ gen_op_movl_T0_im(val);
+ if (insn & (1 << 19))
+ gen_op_movl_psr_T0();
+ } else {
+ /* miscellaneous instructions */
+ op1 = (insn >> 21) & 3;
+ sh = (insn >> 4) & 0xf;
+ rm = insn & 0xf;
+ switch (sh) {
+ case 0x0: /* move program status register */
+ if (op1 & 2) {
+ /* SPSR not accessible in user mode */
+ goto illegal_op;
+ }
+ if (op1 & 1) {
+ /* CPSR = reg */
+ gen_movl_T0_reg(s, rm);
+ if (insn & (1 << 19))
+ gen_op_movl_psr_T0();
+ } else {
+ /* reg = CPSR */
+ rd = (insn >> 12) & 0xf;
+ gen_op_movl_T0_psr();
+ gen_movl_reg_T0(s, rd);
+ }
+ case 0x1:
+ if (op1 == 3) {
+ /* clz */
+ rd = (insn >> 12) & 0xf;
+ gen_movl_T0_reg(s, rm);
+ gen_op_clz_T0();
+ gen_movl_reg_T0(s, rd);
+ } else {
+ goto illegal_op;
+ }
+ break;
+ case 0x5: /* saturating add/subtract */
+ rd = (insn >> 12) & 0xf;
+ rn = (insn >> 16) & 0xf;
+ gen_movl_T0_reg (s, rn);
+ if (op1 & 2) {
+ gen_movl_T1_reg (s, rn);
+ if (op1 & 1)
+ gen_op_subl_T0_T1_saturate();
+ else
+ gen_op_addl_T0_T1_saturate();
+ }
+ gen_movl_T1_reg (s, rm);
+ if (op1 & 1)
+ gen_op_subl_T0_T1_saturate();
+ else
+ gen_op_addl_T0_T1_saturate();
+ gen_movl_reg_T0(s, rn);
+ break;
+ case 0x8: /* signed multiply */
+ case 0xa:
+ case 0xc:
+ case 0xe:
+ rs = (insn >> 8) & 0xf;
+ rn = (insn >> 12) & 0xf;
+ rd = (insn >> 16) & 0xf;
+ if (op1 == 1) {
+ /* (32 * 16) >> 16 */
+ gen_movl_T0_reg(s, rm);
+ gen_movl_T1_reg(s, rs);
+ if (sh & 4)
+ gen_op_sarl_T1_im(16);
+ else
+ gen_op_sxl_T1();
+ gen_op_imulw_T0_T1();
+ if ((sh & 2) == 0) {
+ gen_movl_T1_reg(s, rn);
+ gen_op_addl_T0_T1_setq();
+ }
+ gen_movl_reg_T0(s, rd);
+ } else {
+ /* 16 * 16 */
+ gen_movl_T0_reg(s, rm);
+ if (sh & 2)
+ gen_op_sarl_T0_im(16);
+ else
+ gen_op_sxl_T0();
+ gen_movl_T0_reg(s, rs);
+ if (sh & 4)
+ gen_op_sarl_T1_im(16);
+ else
+ gen_op_sxl_T1();
+ if (op1 == 2) {
+ gen_op_imull_T0_T1();
+ gen_op_addq_T0_T1(rn, rd);
+ gen_movl_reg_T0(s, rn);
+ gen_movl_reg_T1(s, rd);
+ } else {
+ gen_op_mul_T0_T1();
+ if (op1 == 0) {
+ gen_movl_T1_reg(s, rn);
+ gen_op_addl_T0_T1_setq();
+ }
+ gen_movl_reg_T0(s, rd);
+ }
+ }
+ break;
+ default:
+ goto illegal_op;
+ }
+ }
+ } else if (((insn & 0x0e000000) == 0 &&
+ (insn & 0x00000090) != 0x90) ||
+ ((insn & 0x0e000000) == (1 << 25))) {
int set_cc, logic_cc, shiftop;
op1 = (insn >> 21) & 0xf;
@@ -489,6 +608,7 @@ static void disas_arm_insn(DisasContext
switch(op1) {
case 0x0:
case 0x1:
+ /* multiplies, extra load/stores */
sh = (insn >> 5) & 3;
if (sh == 0) {
if (op1 == 0x0) {
@@ -496,7 +616,7 @@ static void disas_arm_insn(DisasContext
rn = (insn >> 12) & 0xf;
rs = (insn >> 8) & 0xf;
rm = (insn) & 0xf;
- if (!(insn & (1 << 23))) {
+ if (((insn >> 22) & 3) == 0) {
/* 32 bit mul */
gen_movl_T0_reg(s, rs);
gen_movl_T1_reg(s, rm);
@@ -516,30 +636,39 @@ static void disas_arm_insn(DisasContext
gen_op_imull_T0_T1();
else
gen_op_mull_T0_T1();
- if (insn & (1 << 21))
+ if (insn & (1 << 21)) /* mult accumulate */
gen_op_addq_T0_T1(rn, rd);
+ if (!(insn & (1 << 23))) { /* double accumulate */
+ gen_op_addq_lo_T0_T1(rn);
+ gen_op_addq_lo_T0_T1(rd);
+ }
if (insn & (1 << 20))
gen_op_logicq_cc();
gen_movl_reg_T0(s, rn);
gen_movl_reg_T1(s, rd);
}
} else {
- /* SWP instruction */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
- rm = (insn) & 0xf;
-
- gen_movl_T0_reg(s, rm);
- gen_movl_T1_reg(s, rn);
- if (insn & (1 << 22)) {
- gen_op_swpb_T0_T1();
+ if (insn & (1 << 23)) {
+ /* load/store exclusive */
+ goto illegal_op;
} else {
- gen_op_swpl_T0_T1();
+ /* SWP instruction */
+ rm = (insn) & 0xf;
+
+ gen_movl_T0_reg(s, rm);
+ gen_movl_T1_reg(s, rn);
+ if (insn & (1 << 22)) {
+ gen_op_swpb_T0_T1();
+ } else {
+ gen_op_swpl_T0_T1();
+ }
+ gen_movl_reg_T0(s, rd);
}
- gen_movl_reg_T0(s, rd);
}
} else {
- /* load/store half word */
+ /* Misc load/store */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
gen_movl_T1_reg(s, rn);
@@ -560,6 +689,27 @@ static void disas_arm_insn(DisasContext
break;
}
gen_movl_reg_T0(s, rd);
+ } else if (sh & 2) {
+ /* doubleword */
+ if (sh & 1) {
+ /* store */
+ gen_movl_T0_reg(s, rd);
+ gen_op_stl_T0_T1();
+ gen_op_addl_T1_im(4);
+ gen_movl_T0_reg(s, rd + 1);
+ gen_op_stl_T0_T1();
+ if ((insn & (1 << 24)) || (insn & (1 << 20)))
+ gen_op_addl_T1_im(-4);
+ } else {
+ /* load */
+ gen_op_ldl_T0_T1();
+ gen_movl_reg_T0(s, rd);
+ gen_op_addl_T1_im(4);
+ gen_op_ldl_T0_T1();
+ gen_movl_reg_T0(s, rd + 1);
+ if ((insn & (1 << 24)) || (insn & (1 << 20)))
+ gen_op_addl_T1_im(-4);
+ }
} else {
/* store */
gen_movl_T0_reg(s, rd);
next reply other threads:[~2004-08-01 17:11 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-08-01 17:08 Paul Brook [this message]
2004-08-01 17:41 ` [Qemu-devel] [patch] Arm arch5 support Lennert Buytenhek
2004-08-01 18:32 ` Paul Brook
2004-08-01 21:38 ` Lennert Buytenhek
2004-08-01 22:16 ` Lennert Buytenhek
2004-08-01 23:03 ` Paul Brook
2004-08-01 23:14 ` Paul Brook
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200408011808.17492.paul@codesourcery.com \
--to=paul@codesourcery.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).