summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Boddie <david@boddie.org.uk>2023-11-16 16:03:12 +0100
committerDavid Boddie <david@boddie.org.uk>2023-11-16 16:44:28 +0100
commit9d9206bbe07886f40dda30046114d847a52bde1e (patch)
tree746efb28bb1fecdce045a91bd51d2e900b368e28
parentb5ffd12d6aeb8c977cfefb0da5f569422b84ee5e (diff)
Used modified VFP instruction sequences from 5l.
-rw-r--r--utils/tl/thumb.c105
1 files changed, 40 insertions, 65 deletions
diff --git a/utils/tl/thumb.c b/utils/tl/thumb.c
index 51d13d83..6473675e 100644
--- a/utils/tl/thumb.c
+++ b/utils/tl/thumb.c
@@ -517,8 +517,8 @@ Optab thumboptab[] =
{ AMOVFW, C_FREG, C_NONE, C_REG, 58, 8, 0 },
{ AMOVWF, C_REG, C_NONE, C_FREG, 58, 8, 0 },
- { AMOVWD, C_REG, C_NONE, C_FREG, 58, 12, 0 },
- { AMOVDW, C_FREG, C_NONE, C_REG, 58, 12, 0 },
+ { AMOVWD, C_REG, C_NONE, C_FREG, 58, 8, 0 },
+ { AMOVDW, C_FREG, C_NONE, C_REG, 58, 8, 0 },
{ AMOVFD, C_FREG, C_NONE, C_FREG, 58, 4, 0 },
{ AMOVDF, C_FREG, C_NONE, C_FREG, 58, 4, 0 },
@@ -1362,69 +1362,43 @@ if(debug['G']) print("%ulx: %s: thumb\n", (ulong)(p->pc), p->from.sym->name);
break;
case 58: /* floating point fix and float (MOVDW/MOVWD) */
+ o1 = thumbopfp(p->as, p->scond);
rf = p->from.reg;
rt = p->to.reg;
- if(p->to.type == D_NONE){
- rt = 0;
- diag("to.type==D_NONE (asm/fp)");
- }
- if ((p->as == AMOVWD) || (p->as == AMOVWF)) {
- /* Transfer the contents of the register then convert it
- to a floating point representation. */
- // VMOV A7.7.240
- o1 = 0x0a10ee00;
- o1 |= ((rt & 1) << 23) | (rt >> 1); /* Fd */
- o1 |= (rf << 28); /* Rm */
-
- // VCVT (A7.7.225) - note invalid opc2 bits in manual
- // op=0, Fd=Fm=rt
- o3 = 0x0a40feb8;
- o3 |= 1; // signed
- o3 |= ((rt & 1) << 21) | ((rt & 0xe) << 16); /* Fm */
- o3 |= ((rt & 1) << 6) | ((rt & 0xe) << 28); /* Fd */
+ if (p->as == AMOVDF) {
+ // Vd:D M:Vm - only support 16 registers
+ o1 |= ((rt & 1) << 6) | ((rt & 0xe) << 27) | ((rf & 0x0f) << 16);
SPLIT_INS(o1, o2);
- SPLIT_INS(o3, o4);
-
- if (p->as == AMOVWD) {
- o5 = thumbopfp(AMOVFD, p->scond);
- o5 |= ((rt & 0x0f)<<28) | ((rf & 1) << 21) | ((rf & 0x0e) << 16);
- SPLIT_INS(o5, o6);
- }
- } else if ((p->as == AMOVDW) || (p->as == AMOVFW)) {
- /* Convert the floating point representation of the number
- to an integer then transfer the contents to a register. */
- // VCVT (A7.7.225) - note invalid opc2 bits in manual
- // op=0, Fd=Fm=rt
- o1 = 0x0a40feb8;
- o1 |= 4; // to integer
- o1 |= 1; // signed
- o1 |= ((rt & 1) << 6) | ((rt & 0xe) << 28); /* Fd */
- if (p->as == AMOVDW)
- o1 |= ((rt & 0xf) << 28) | 0x01000000; /* Fm */
- else
- o1 |= ((rt & 1) << 21) | ((rt & 0xe) << 16);/* Fm */
-
- // VMOV A7.7.240
- o3 = 0x0a10ee00 | 0x10;
- o3 |= ((rf & 1) << 23) | (rf >> 1);
- o3 |= (rt << 28);
+ } else if (p->as == AMOVFD) {
+ // MOVFD: D:Vd Vm:M - only support 16 registers
+ o1 |= ((rt & 0x0f)<<28) | ((rf & 1) << 21) | ((rf & 0x0e) << 16);
SPLIT_INS(o1, o2);
- SPLIT_INS(o3, o4);
} else {
- o1 = thumbopfp(p->as, p->scond);
- if (p->as == AMOVDF) {
- // Vd:D M:Vm - only support 16 registers
- o1 |= ((rt & 1) << 6) | ((rt & 0xe) << 27) | ((rf & 0x0f) << 16);
- } else if (p->as == AMOVFD) {
- // MOVFD: D:Vd Vm:M - only support 16 registers
- o1 |= ((rt & 0x0f)<<28) | ((rf & 1) << 21) | ((rf & 0x0e) << 16);
- } else
- diag("unhandled case 58");
-
+ if (p->from.type == D_REG) { // int -> float
+ // VCVT (A7.7.225)
+ o3 = o1 | (rt << 16); // Vm:M (*2 to align with doubles)
+ if (p->as == AMOVWD)
+ o3 |= rt << 28; // D:Vd
+ else
+ o3 |= ((rt >> 1) << 28) | ((rt & 1) << 6); // Vd:D
+ // VMOV F,R (A7.7.240)
+ o1 = 0x0a10ee00;
+ o1 |= rt | rf<<28; // rt = Vn:N (*2 to align with doubles)
+ } else { // float -> int
+ // VCVT (A7.7.225) rf -> FREGTMP
+ o1 |= FREGTMP<<28; // Vd:D
+ if (p->as == AMOVDW)
+ o1 |= rf << 16; // M:Vm
+ else
+ o1 |= ((rf & 1) << 21) | ((rf >> 1) << 16); // Vm:M
+ // VMOV R,F (A7.7.240) FREFTMP -> rt
+ o3 = 0x0a10ee10;
+ o3 |= FREGTMP | rt<<28;
+ }
SPLIT_INS(o1, o2);
+ SPLIT_INS(o3, o4);
}
-
break;
case 59: /* move to FP[CS]R */
@@ -1719,19 +1693,20 @@ thumboprrr(int a, int ld)
long
thumbopfp(int a, int sc)
{
+ /* See opvfprrr in 5l/asm.c for hints. */
long o = 0;
o |= 0xee00; // Prepare the first half-word in the sequence.
switch(a) {
- /* VMOV (ARMv7-M ARM, A7.7.240), encoding T1, op=0 */
- case AMOVWF: return o | (0x0a<<24) | (1<<20) | (0<<4);
- /* VMOV (ARMv7-M ARM, A7.7.240), encoding T1, op=1 */
- case AMOVFW: return o | (0x0a<<24) | (1<<20) | (1<<4);
- /* VMOV (ARMv7-M ARM, A7.7.242), encoding T1, op=0 */
- case AMOVWD: return o | (0x0b<<24) | (1<<20) | (1<<6) | (0<<4);
- /* VMOV (ARMv7-M ARM, A7.7.242), encoding T1, op=1 */
- case AMOVDW: return o | (0x0b<<24) | (1<<20) | (1<<6) | (1<<4);
+ /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1 */
+ case AMOVWF: return o | (0x0a << 24) | (0xc0 << 16) | 0xb8;
+ /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1 */
+ case AMOVFW: return o | (0x0a << 24) | (0xc0 << 16) | 0xbd;
+ /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1 */
+ case AMOVWD: return o | (0x0b << 24) | (0xc0 << 16) | 0xb8;
+ /* VCVT (ARMv7-M ARM, A7.7.225), encoding T1, op=1 */
+ case AMOVDW: return o | (0x0b << 24) | (0xc0 << 16) | 0xbd;
/* VCVT (ARMv7-M ARM, A7.7.227), encoding T1 */
case AMOVFD: return o | (0x0a<<24) | (0xc0<<16) | 0xb7;
case AMOVDF: return o | (0x0b<<24) | (0xc0<<16) | 0xb7;