MIPS queue for October 2018 - part 2 - v2

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJb0HIuAAoJENSXKoln91plGcUH/3Lje5KF8kkShQ5dIrH9e8Xz
 bvK6lXOLNnndEyrWqJNLaJs7eJKEV2N+E2sBmdIjKnWXVHW6gOW3QBMuVGPTT4rg
 C6cntrh2HpnxibgJqrR+3RmjQHAI1Ktixhker9LWimF3ZZhcy4H6mFHwW9z7eBK4
 +n/pbnk8fq4FlGHJ2teHhctVIma6slmd8lkMa9vdwVQwpAyzpP82XjrsoTeeYhmG
 uuTvX3TFnXKGa9mYGxybpwKd4i+397l9fTQ4egx1KlZMR8OHuQItCBDOFdiQpHOg
 yljCeG3jHEhNzVf+xW7JU692Lz097otWDbzWDJibYGJkdkhKfyHJ9PvCYaPiK6M=
 =Sg8J
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-oct-2018-part-2-v2' into staging

MIPS queue for October 2018 - part 2 - v2

# gpg: Signature made Wed 24 Oct 2018 14:22:54 BST
# gpg:                using RSA key D4972A8967F75A65
# gpg: Good signature from "Aleksandar Markovic <amarkovic@wavecomp.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 8526 FBF1 5DA3 811F 4A01  DD75 D497 2A89 67F7 5A65

* remotes/amarkovic/tags/mips-queue-oct-2018-part-2-v2: (33 commits)
  target/mips: Fix decoding of ALIGN and DALIGN instructions
  target/mips: Fix the title of translate.c
  linux-user/mips: Recognize the R5900 CPU model
  target/mips: Define the R5900 CPU
  tests/tcg/mips: Add tests for R5900 DIVU1
  tests/tcg/mips: Add tests for R5900 DIV1
  tests/tcg/mips: Add tests for R5900 MTLO1 and MTHI1
  tests/tcg/mips: Add tests for R5900 MFLO1 and MFHI1
  tests/tcg/mips: Add tests for R5900 three-operand MULTU1
  tests/tcg/mips: Add tests for R5900 three-operand MULT1
  tests/tcg/mips: Add tests for R5900 three-operand MULTU
  tests/tcg/mips: Add tests for R5900 three-operand MULT
  target/mips: Make R5900 DMULT[U], DDIV[U], LL[D] and SC[D] user only
  target/mips: Support R5900 MOVN, MOVZ and PREF instructions from MIPS IV
  target/mips: Support R5900 DIV1 and DIVU1 instructions
  target/mips: Support R5900 MFLO1, MTLO1, MFHI1 and MTHI1 instructions
  target/mips: Support R5900 three-operand MULT1 and MULTU1 instructions
  target/mips: Support R5900 three-operand MULT and MULTU instructions
  target/mips: Add a placeholder for R5900 MMI3 instruction subclass
  target/mips: Add a placeholder for R5900 MMI2 instruction subclass
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-10-24 16:31:40 +01:00
commit c96292036a
11 changed files with 1281 additions and 19 deletions

View File

@ -12,6 +12,9 @@ static inline const char *cpu_get_model(uint32_t eflags)
if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
return "mips32r6-generic";
}
if ((eflags & EF_MIPS_MACH) == EF_MIPS_MACH_5900) {
return "R5900";
}
return "24Kf";
}
#endif

View File

@ -64,9 +64,11 @@
#define INSN_LOONGSON2E 0x0001000000000000ULL
#define INSN_LOONGSON2F 0x0002000000000000ULL
#define INSN_VR54XX 0x0004000000000000ULL
#define INSN_R5900 0x0008000000000000ULL
/*
* bits 56-63: vendor-specific ASEs
*/
#define ASE_MMI 0x0100000000000000ULL
/* MIPS CPU defines. */
#define CPU_MIPS1 (ISA_MIPS1)
@ -74,6 +76,7 @@
#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3)
#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4)
#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX)
#define CPU_R5900 (CPU_MIPS3 | INSN_R5900)
#define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E)
#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F)

File diff suppressed because it is too large Load Diff

View File

@ -410,6 +410,65 @@ const mips_def_t mips_defs[] =
.insn_flags = CPU_MIPS32R5 | ASE_MSA,
.mmu_type = MMU_TYPE_R4000,
},
{
/*
* The Toshiba TX System RISC TX79 Core Architecture manual
*
* https://wiki.qemu.org/File:C790.pdf
*
* describes the C790 processor that is a follow-up to the R5900.
* There are a few notable differences in that the R5900 FPU
*
* - is not IEEE 754-1985 compliant,
* - does not implement double format, and
* - its machine code is nonstandard.
*/
.name = "R5900",
.CP0_PRid = 0x00002E00,
/* No L2 cache, icache size 32k, dcache size 32k, uncached coherency. */
.CP0_Config0 = (0x3 << 9) | (0x3 << 6) | (0x2 << CP0C0_K0),
.CP0_Status_rw_bitmask = 0xF4C79C1F,
#ifdef CONFIG_USER_ONLY
/*
* R5900 hardware traps to the Linux kernel for IEEE 754-1985 and LL/SC
* emulation. For user only, QEMU is the kernel, so we emulate the traps
* by simply emulating the instructions directly.
*
* Note: Config1 is only used internally, the R5900 has only Config0.
*/
.CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
.CP0_LLAddr_rw_bitmask = 0xFFFFFFFF,
.CP0_LLAddr_shift = 4,
.CP1_fcr0 = (0x38 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0x0183FFFF,
#else
/*
* The R5900 COP1 FPU implements single-precision floating-point
* operations but is not entirely IEEE 754-1985 compatible. In
* particular,
*
* - NaN (not a number) and +/- infinities are not supported;
* - exception mechanisms are not fully supported;
* - denormalized numbers are not supported;
* - rounding towards nearest and +/- infinities are not supported;
* - computed results usually differs in the least significant bit;
* - saturations can differ more than the least significant bit.
*
* Since only rounding towards zero is supported, the two least
* significant bits of FCR31 are hardwired to 01.
*
* FPU emulation is disabled here until it is implemented.
*
* Note: Config1 is only used internally, the R5900 has only Config0.
*/
.CP0_Config1 = (47 << CP0C1_MMU),
#endif /* !CONFIG_USER_ONLY */
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_R5900 | ASE_MMI,
.mmu_type = MMU_TYPE_R4000,
},
{
/* A generic CPU supporting MIPS32 Release 6 ISA.
FIXME: Support IEEE 754-2008 FP.

View File

@ -0,0 +1,30 @@
-include ../../config-host.mak
CROSS=mipsr5900el-unknown-linux-gnu-
SIM=qemu-mipsel
SIM_FLAGS=-cpu R5900
CC = $(CROSS)gcc
CFLAGS = -Wall -mabi=32 -march=r5900 -static
TESTCASES = div1.tst
TESTCASES += divu1.tst
TESTCASES += mflohi1.tst
TESTCASES += mtlohi1.tst
TESTCASES += mult.tst
TESTCASES += multu.tst
all: $(TESTCASES)
%.tst: %.c
$(CC) $(CFLAGS) $< -o $@
check: $(TESTCASES)
@for case in $(TESTCASES); do \
echo $(SIM) $(SIM_FLAGS) ./$$case;\
$(SIM) $(SIM_FLAGS) ./$$case; \
done
clean:
$(RM) -rf $(TESTCASES)

View File

@ -0,0 +1,73 @@
/*
* Test R5900-specific DIV1.
*/
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
struct quotient_remainder { int32_t quotient, remainder; };
static struct quotient_remainder div1(int32_t rs, int32_t rt)
{
int32_t lo, hi;
__asm__ __volatile__ (
" div1 $0, %2, %3\n"
" mflo1 %0\n"
" mfhi1 %1\n"
: "=r" (lo), "=r" (hi)
: "r" (rs), "r" (rt));
assert(rs / rt == lo);
assert(rs % rt == hi);
return (struct quotient_remainder) { .quotient = lo, .remainder = hi };
}
static void verify_div1(int32_t rs, int32_t rt,
int32_t expected_quotient,
int32_t expected_remainder)
{
struct quotient_remainder qr = div1(rs, rt);
assert(qr.quotient == expected_quotient);
assert(qr.remainder == expected_remainder);
}
static void verify_div1_negations(int32_t rs, int32_t rt,
int32_t expected_quotient,
int32_t expected_remainder)
{
verify_div1(rs, rt, expected_quotient, expected_remainder);
verify_div1(rs, -rt, -expected_quotient, expected_remainder);
verify_div1(-rs, rt, -expected_quotient, -expected_remainder);
verify_div1(-rs, -rt, expected_quotient, -expected_remainder);
}
int main()
{
verify_div1_negations(0, 1, 0, 0);
verify_div1_negations(1, 1, 1, 0);
verify_div1_negations(1, 2, 0, 1);
verify_div1_negations(17, 19, 0, 17);
verify_div1_negations(19, 17, 1, 2);
verify_div1_negations(77773, 101, 770, 3);
verify_div1(-0x80000000, 1, -0x80000000, 0);
/*
* Supplementary explanation from the Toshiba TX System RISC TX79 Core
* Architecture manual, A-38 and B-7, https://wiki.qemu.org/File:C790.pdf
*
* Normally, when 0x80000000 (-2147483648) the signed minimum value is
* divided by 0xFFFFFFFF (-1), the operation will result in an overflow.
* However, in this instruction an overflow exception doesn't occur and
* the result will be as follows:
*
* Quotient is 0x80000000 (-2147483648), and remainder is 0x00000000 (0).
*/
verify_div1(-0x80000000, -1, -0x80000000, 0);
return 0;
}

View File

@ -0,0 +1,48 @@
/*
* Test R5900-specific DIVU1.
*/
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
struct quotient_remainder { uint32_t quotient, remainder; };
static struct quotient_remainder divu1(uint32_t rs, uint32_t rt)
{
uint32_t lo, hi;
__asm__ __volatile__ (
" divu1 $0, %2, %3\n"
" mflo1 %0\n"
" mfhi1 %1\n"
: "=r" (lo), "=r" (hi)
: "r" (rs), "r" (rt));
assert(rs / rt == lo);
assert(rs % rt == hi);
return (struct quotient_remainder) { .quotient = lo, .remainder = hi };
}
static void verify_divu1(uint32_t rs, uint32_t rt,
uint32_t expected_quotient,
uint32_t expected_remainder)
{
struct quotient_remainder qr = divu1(rs, rt);
assert(qr.quotient == expected_quotient);
assert(qr.remainder == expected_remainder);
}
int main()
{
verify_divu1(0, 1, 0, 0);
verify_divu1(1, 1, 1, 0);
verify_divu1(1, 2, 0, 1);
verify_divu1(17, 19, 0, 17);
verify_divu1(19, 17, 1, 2);
verify_divu1(77773, 101, 770, 3);
return 0;
}

View File

@ -0,0 +1,35 @@
/*
* Test R5900-specific MFLO1 and MFHI1.
*/
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
int main()
{
int32_t rs = 12207031, rt = 305175781;
int32_t rs1 = 32452867, rt1 = 49979687;
int64_t lo, hi, lo1, hi1;
int64_t r, r1;
/* Test both LO/HI and LO1/HI1 to verify separation. */
__asm__ __volatile__ (
" mult $0, %4, %5\n"
" mult1 $0, %6, %7\n"
" mflo %0\n"
" mfhi %1\n"
" mflo1 %2\n"
" mfhi1 %3\n"
: "=r" (lo), "=r" (hi),
"=r" (lo1), "=r" (hi1)
: "r" (rs), "r" (rt),
"r" (rs1), "r" (rt1));
r = ((int64_t)hi << 32) | (uint32_t)lo;
r1 = ((int64_t)hi1 << 32) | (uint32_t)lo1;
assert(r == 3725290219116211);
assert(r1 == 1621984134912629);
return 0;
}

View File

@ -0,0 +1,40 @@
/*
* Test R5900-specific MTLO1 and MTHI1.
*/
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
int main()
{
int32_t tlo = 12207031, thi = 305175781;
int32_t tlo1 = 32452867, thi1 = 49979687;
int32_t flo, fhi, flo1, fhi1;
/* Test both LO/HI and LO1/HI1 to verify separation. */
__asm__ __volatile__ (
" mtlo %4\n"
" mthi %5\n"
" mtlo1 %6\n"
" mthi1 %7\n"
" move %0, $0\n"
" move %1, $0\n"
" move %2, $0\n"
" move %3, $0\n"
" mflo %0\n"
" mfhi %1\n"
" mflo1 %2\n"
" mfhi1 %3\n"
: "=r" (flo), "=r" (fhi),
"=r" (flo1), "=r" (fhi1)
: "r" (tlo), "r" (thi),
"r" (tlo1), "r" (thi1));
assert(flo == 12207031);
assert(fhi == 305175781);
assert(flo1 == 32452867);
assert(fhi1 == 49979687);
return 0;
}

View File

@ -0,0 +1,76 @@
/*
* Test R5900-specific three-operand MULT and MULT1.
*/
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
static int64_t mult(int32_t rs, int32_t rt)
{
int32_t rd, lo, hi;
int64_t r;
__asm__ __volatile__ (
" mult %0, %3, %4\n"
" mflo %1\n"
" mfhi %2\n"
: "=r" (rd), "=r" (lo), "=r" (hi)
: "r" (rs), "r" (rt));
r = ((int64_t)hi << 32) | (uint32_t)lo;
assert((int64_t)rs * rt == r);
assert(rd == lo);
return r;
}
static int64_t mult1(int32_t rs, int32_t rt)
{
int32_t rd, lo, hi;
int64_t r;
__asm__ __volatile__ (
" mult1 %0, %3, %4\n"
" mflo1 %1\n"
" mfhi1 %2\n"
: "=r" (rd), "=r" (lo), "=r" (hi)
: "r" (rs), "r" (rt));
r = ((int64_t)hi << 32) | (uint32_t)lo;
assert((int64_t)rs * rt == r);
assert(rd == lo);
return r;
}
static int64_t mult_variants(int32_t rs, int32_t rt)
{
int64_t rd = mult(rs, rt);
int64_t rd1 = mult1(rs, rt);
assert(rd == rd1);
return rd;
}
static void verify_mult_negations(int32_t rs, int32_t rt, int64_t expected)
{
assert(mult_variants(rs, rt) == expected);
assert(mult_variants(-rs, rt) == -expected);
assert(mult_variants(rs, -rt) == -expected);
assert(mult_variants(-rs, -rt) == expected);
}
int main()
{
verify_mult_negations(17, 19, 323);
verify_mult_negations(77773, 99991, 7776600043);
verify_mult_negations(12207031, 305175781, 3725290219116211);
assert(mult_variants(-0x80000000, 0x7FFFFFFF) == -0x3FFFFFFF80000000);
assert(mult_variants(-0x80000000, -0x7FFFFFFF) == 0x3FFFFFFF80000000);
assert(mult_variants(-0x80000000, -0x80000000) == 0x4000000000000000);
return 0;
}

View File

@ -0,0 +1,68 @@
/*
* Test R5900-specific three-operand MULTU and MULTU1.
*/
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
static uint64_t multu(uint32_t rs, uint32_t rt)
{
uint32_t rd, lo, hi;
uint64_t r;
__asm__ __volatile__ (
" multu %0, %3, %4\n"
" mflo %1\n"
" mfhi %2\n"
: "=r" (rd), "=r" (lo), "=r" (hi)
: "r" (rs), "r" (rt));
r = ((uint64_t)hi << 32) | (uint32_t)lo;
assert((uint64_t)rs * rt == r);
assert(rd == lo);
return r;
}
static uint64_t multu1(uint32_t rs, uint32_t rt)
{
uint32_t rd, lo, hi;
uint64_t r;
__asm__ __volatile__ (
" multu1 %0, %3, %4\n"
" mflo1 %1\n"
" mfhi1 %2\n"
: "=r" (rd), "=r" (lo), "=r" (hi)
: "r" (rs), "r" (rt));
r = ((uint64_t)hi << 32) | (uint32_t)lo;
assert((uint64_t)rs * rt == r);
assert(rd == lo);
return r;
}
static uint64_t multu_variants(uint32_t rs, uint32_t rt)
{
uint64_t rd = multu(rs, rt);
uint64_t rd1 = multu1(rs, rt);
assert(rd == rd1);
return rd;
}
int main()
{
assert(multu_variants(17, 19) == 323);
assert(multu_variants(77773, 99991) == 7776600043);
assert(multu_variants(12207031, 305175781) == 3725290219116211);
assert(multu_variants(0x80000000U, 0x7FFFFFFF) == 0x3FFFFFFF80000000);
assert(multu_variants(0x80000000U, 0x80000000U) == 0x4000000000000000);
assert(multu_variants(0xFFFFFFFFU, 0xFFFFFFFFU) == 0xFFFFFFFE00000001U);
return 0;
}