visinstr.c revision 428cee1ba676b0cc80da92fb058bb7ee03143df7
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* VIS floating point instruction simulator for Sparc FPU simulator. */
#include <sys/vis_simulator.h>
#include <sys/privregs.h>
#include <sys/cpu_module.h>
#include <sys/machsystm.h>
void *);
void *);
kfpu_t *);
void *, kfpu_t *);
kfpu_t *);
void *);
void *, uint_t);
/*
* Simulator for VIS instructions with op3 == 0x36 that get fp_disabled
* traps.
*/
enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
union {
} f;
}
/* these instr's do not use fp regs */
case edge8:
case edge8l:
case edge8n:
case edge8ln:
case edge16:
case edge16l:
case edge16n:
case edge16ln:
case edge32:
case edge32l:
case edge32n:
case edge32ln:
break;
case array8:
case array16:
case array32:
break;
case alignaddr:
case alignaddrl:
break;
case bmask:
break;
case fcmple16:
case fcmpne16:
case fcmpgt16:
case fcmpeq16:
case fcmple32:
case fcmpne32:
case fcmpgt32:
case fcmpeq32:
break;
case fmul8x16:
case fmul8x16au:
case fmul8x16al:
case fmul8sux16:
case fmul8ulx16:
case fmuld8sux16:
case fmuld8ulx16:
break;
case fpack16:
case fpack32:
case fpackfix:
case fexpand:
case fpmerge:
break;
case pdist:
break;
case faligndata:
break;
case bshuffle:
break;
case fpadd16:
case fpadd16s:
case fpadd32:
case fpadd32s:
case fpsub16:
case fpsub16s:
case fpsub32:
case fpsub32s:
break;
case fzero:
lusr = 0;
break;
case fzeros:
usr = 0;
break;
case fnor:
break;
case fnors:
break;
case fandnot2:
break;
case fandnot2s:
break;
case fnot2:
break;
case fnot2s:
break;
case fandnot1:
break;
case fandnot1s:
break;
case fnot1:
break;
case fnot1s:
break;
case fxor:
break;
case fxors:
break;
case fnand:
break;
case fnands:
break;
case fand:
break;
case fands:
break;
case fxnor:
break;
case fxnors:
break;
case fsrc1:
break;
case fsrc1s:
break;
case fornot2:
break;
case fornot2s:
break;
case fsrc2:
break;
case fsrc2s:
break;
case fornot1:
break;
case fornot1s:
break;
case for_op:
break;
case fors_op:
break;
case fone:
lusr = 0xffffffffffffffff;
break;
case fones:
usr = 0xffffffffUL;
break;
case siam:
break;
default:
return (ftt_unimplemented);
}
return (ftt);
}
/*
* Simulator for edge instructions
*/
static enum ftt_type
void *prw) /* Pointer to locals and ins. */
{
int am32; /* Whether PSTATE.AM == 1 */
return (ftt);
return (ftt);
/* Get PSTATE.AM to determine 32-bit vs 64-bit addressing */
if (am32 == 1) {
} else {
}
case edge8:
case edge8n:
case edge8l:
case edge8ln:
case edge8:
case edge8n:
} else {
}
}
break;
case edge8l:
case edge8ln:
} else {
}
}
break;
}
break;
case edge16:
case edge16l:
case edge16n:
case edge16ln:
al3l >>= 0x1;
case edge16:
case edge16n:
} else {
}
al3r >>= 0x1;
}
break;
case edge16l:
case edge16ln:
} else {
}
al3r >>= 0x1;
}
break;
}
break;
case edge32:
case edge32l:
case edge32n:
case edge32ln:
al3l >>= 0x2;
case edge32:
case edge32n:
} else {
}
al3r >>= 0x2;
}
break;
case edge32l:
case edge32ln:
} else {
}
al3r >>= 0x2;
}
break;
}
break;
}
case edge8:
case edge8l:
case edge16:
case edge16l:
case edge32:
case edge32l:
/* Update flags per SUBcc outcome */
<< TSTATE_CCR_SHIFT);
break;
}
return (ftt);
}
/*
* Simulator for three dimentional array addressing instructions.
*/
static enum ftt_type
void *prw) /* Pointer to locals and ins. */
{
return (ftt);
return (ftt);
if (bsize > 5) {
bsize = 5;
}
baddr = 0;
case array8:
break;
case array16:
baddr <<= 1;
break;
case array32:
baddr <<= 2;
break;
}
return (ftt);
}
/*
* Simulator for alignaddr and alignaddrl instructions.
*/
static enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
short s;
return (ftt);
return (ftt);
g &= ~(GSR_ALIGN_MASK); /* zero the align offset */
r = ea & 0x7;
s = (short)(~r); /* 2's complement for alignaddrl */
if (s < 0)
else
r = (uint64_t)(s & 0x7);
}
g |= (r << GSR_ALIGN_SHIFT) & GSR_ALIGN_MASK;
return (ftt);
}
/*
* Simulator for bmask instruction.
*/
static enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
return (ftt);
return (ftt);
g &= ~(GSR_MASK_MASK); /* zero the mask offset */
/* Put the least significant 32 bits of ea in GSR.mask */
return (ftt);
}
/*
* Simulator for fp[add|sub]* instruction.
*/
static enum ftt_type
{
union {
uint32_t i[2];
uint16_t s[4];
union {
uint32_t i;
uint16_t s[2];
int i;
}
case fpadd16:
for (i = 0; i <= 3; i++) {
}
break;
case fpadd16s:
for (i = 0; i <= 1; i++) {
}
break;
case fpadd32:
for (i = 0; i <= 1; i++) {
}
break;
case fpadd32s:
break;
case fpsub16:
for (i = 0; i <= 3; i++) {
}
break;
case fpsub16s:
for (i = 0; i <= 1; i++) {
}
break;
case fpsub32:
for (i = 0; i <= 1; i++) {
}
break;
case fpsub32s:
break;
}
return (ftt_none);
}
/*
* Simulator for fcmp* instruction.
*/
static enum ftt_type
void *prw) /* Pointer to locals and ins. */
{
union {
uint32_t i[2];
uint16_t s[4];
case fcmple16:
for (i = 0; i <= 3; i++) {
}
break;
case fcmpne16:
for (i = 0; i <= 3; i++) {
}
break;
case fcmpgt16:
for (i = 0; i <= 3; i++) {
}
break;
case fcmpeq16:
for (i = 0; i <= 3; i++) {
}
break;
case fcmple32:
for (i = 0; i <= 1; i++) {
}
break;
case fcmpne32:
for (i = 0; i <= 1; i++) {
}
break;
case fcmpgt32:
for (i = 0; i <= 1; i++) {
}
break;
case fcmpeq32:
for (i = 0; i <= 1; i++) {
}
break;
}
return (ftt);
}
/*
* Simulator for fmul* instruction.
*/
static enum ftt_type
{
union {
uint32_t i[2];
uint16_t s[4];
uint8_t c[8];
union {
uint32_t i;
uint16_t s[2];
uint8_t c[4];
char c1;
int i;
}
case fmul8x16:
for (i = 0; i <= 3; i++) {
sres++;
}
break;
case fmul8x16au:
for (i = 0; i <= 3; i++) {
sres++;
}
break;
case fmul8x16al:
for (i = 0; i <= 3; i++) {
sres++;
}
break;
case fmul8sux16:
for (i = 0; i <= 3; i++) {
sres++;
if (sres < 0)
else
}
break;
case fmul8ulx16:
for (i = 0; i <= 3; i++) {
sres++;
}
break;
case fmuld8sux16:
for (i = 0; i <= 1; i++) {
}
break;
case fmuld8ulx16:
for (i = 0; i <= 1; i++) {
}
break;
}
return (ftt_none);
}
/*
* Simulator for fpixel formatting instructions.
*/
static enum ftt_type
{
int i, j, k, sf;
union {
uint32_t i[2];
uint16_t s[4];
uint8_t c[8];
union {
uint32_t i;
uint16_t s[2];
uint8_t c[4];
uint64_t r;
int64_t l, m;
short s;
}
case fpack16:
/* fpack16 ignores GSR.scale msb */
for (i = 0; i <= 3; i++) {
s = (short)lrs2.s[i]; /* preserve the sign */
j = ((int)s << sf);
k = j >> 7;
if (k < 0) {
uc = 0;
} else if (k > 255) {
uc = 255;
} else {
}
}
break;
case fpack32:
for (i = 0, k = 3; i <= 1; i++, k += 4) {
j = (int)lrs2.i[i]; /* preserve the sign */
m = l >> 23;
if (m < 0) {
uc = 0;
} else if (m > 255) {
uc = 255;
} else {
}
}
break;
case fpackfix:
for (i = 0; i <= 1; i++) {
j = (int)lrs2.i[i]; /* preserve the sign */
m = l >> 16;
if (m < -32768) {
s = -32768;
} else if (m > 32767) {
s = 32767;
} else {
s = (short)m;
}
krd.s[i] = s;
}
break;
case fexpand:
for (i = 0; i <= 3; i++) {
}
break;
case fpmerge:
for (i = 0, j = 0; i <= 3; i++, j += 2) {
}
break;
}
return (ftt_none);
}
/*
* Simulator for pdist instruction.
*/
enum ftt_type
{
int i;
short s;
union {
uint8_t c[8];
for (i = 0; i <= 7; i++) {
if (s < 0)
s = ~s + 1;
}
return (ftt_none);
}
/*
* Simulator for faligndata instruction.
*/
static enum ftt_type
{
int i, j, k, ao;
union {
uint8_t c[8];
uint64_t r;
for (i = 0, j = ao, k = 0; i <= 7; i++)
if (j <= 7) {
} else {
}
return (ftt_none);
}
/*
* Simulator for bshuffle instruction.
*/
static enum ftt_type
{
int i, j, ao;
union {
uint8_t c[8];
uint64_t r;
/*
* BSHUFFLE Destination Byte Selection
* rd Byte Source
* 0 rs byte[GSR.mask<31..28>]
* 1 rs byte[GSR.mask<27..24>]
* 2 rs byte[GSR.mask<23..20>]
* 3 rs byte[GSR.mask<19..16>]
* 4 rs byte[GSR.mask<15..12>]
* 5 rs byte[GSR.mask<11..8>]
* 6 rs byte[GSR.mask<7..4>]
* 7 rs byte[GSR.mask<3..0>]
* P.S. rs1 is the upper half and rs2 is the lower half
* Bytes in the source value are numbered from most to
* least significant
*/
if (j < 8) {
} else {
}
}
return (ftt_none);
}
/*
* Simulator for siam instruction.
*/
static enum ftt_type
{
uint64_t g, r;
g &= ~(GSR_IM_IRND_MASK); /* zero the IM and IRND fields */
g |= (r << GSR_IRND_SHIFT);
return (ftt_none);
}
/*
* Simulator for VIS loads and stores between floating-point unit and memory.
*/
enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
union {
} i;
switch (asi) {
case ASI_PST8_P:
case ASI_PST8_S:
case ASI_PST16_P:
case ASI_PST16_S:
case ASI_PST32_P:
case ASI_PST32_S:
case ASI_PST8_PL:
case ASI_PST8_SL:
case ASI_PST16_PL:
case ASI_PST16_SL:
case ASI_PST32_PL:
case ASI_PST32_SL:
case ASI_FL8_P:
case ASI_FL8_S:
case ASI_FL8_PL:
case ASI_FL8_SL:
case ASI_FL16_P:
case ASI_FL16_S:
case ASI_FL16_PL:
case ASI_FL16_SL:
case ASI_BLK_AIUP:
case ASI_BLK_AIUS:
case ASI_BLK_AIUPL:
case ASI_BLK_AIUSL:
case ASI_BLK_P:
case ASI_BLK_S:
case ASI_BLK_PL:
case ASI_BLK_SL:
case ASI_BLK_COMMIT_P:
case ASI_BLK_COMMIT_S:
default:
return (ftt_unimplemented);
}
}
/*
* Simulator for partial stores between floating-point unit and memory.
*/
static enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
int h, i, j;
union {
freg_type f;
uint32_t i[2];
uint16_t s[4];
uint8_t c[8];
} k, l, res;
return (ftt);
return (ftt);
} else {
return (ftt_unimplemented);
}
if ((ea & 0x3) != 0)
return (ftt_alignment); /* Require 32 bit-alignment. */
switch (asi) {
case ASI_PST8_P:
case ASI_PST8_S:
return (ftt);
for (i = 0, j = 0x80; i <= 7; i++, j >>= 1) {
if ((msk & j) == j)
res.c[i] = k.c[i];
else
res.c[i] = l.c[i];
}
return (ftt);
break;
case ASI_PST8_PL: /* little-endian */
case ASI_PST8_SL:
return (ftt);
for (h = 7, i = 0, j = 1; i <= 7; h--, i++, j <<= 1) {
if ((msk & j) == j)
res.c[i] = k.c[h];
else
res.c[i] = l.c[i];
}
return (ftt);
break;
case ASI_PST16_P:
case ASI_PST16_S:
return (ftt);
for (i = 0, j = 0x8; i <= 3; i++, j >>= 1) {
if ((msk & j) == j)
res.s[i] = k.s[i];
else
res.s[i] = l.s[i];
}
return (ftt);
break;
case ASI_PST16_PL:
case ASI_PST16_SL:
return (ftt);
for (h = 7, i = 0, j = 1; i <= 6; h -= 2, i += 2, j <<= 1) {
if ((msk & j) == j) {
res.c[i] = k.c[h];
} else {
res.c[i] = l.c[i];
}
}
return (ftt);
break;
case ASI_PST32_P:
case ASI_PST32_S:
return (ftt);
for (i = 0, j = 0x2; i <= 1; i++, j >>= 1) {
if ((msk & j) == j)
res.i[i] = k.i[i];
else
res.i[i] = l.i[i];
}
return (ftt);
break;
case ASI_PST32_PL:
case ASI_PST32_SL:
return (ftt);
for (h = 7, i = 0, j = 1; i <= 4; h -= 4, i += 4, j <<= 1) {
if ((msk & j) == j) {
res.c[i] = k.c[h];
} else {
res.c[i] = l.c[i];
}
}
return (ftt);
break;
}
return (ftt_none);
}
/*
*/
static enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
union {
freg_type f;
uint32_t i[2];
uint16_t s[4];
uint8_t c[8];
} k;
union {
int i;
} fp;
return (ftt);
return (ftt);
} else { /* effective address = rs1 + imm13 */
return (ftt);
}
if (get_udatamodel() == DATAMODEL_ILP32)
switch (asi) {
case ASI_FL8_P:
case ASI_FL8_S:
case ASI_FL8_PL: /* little-endian */
case ASI_FL8_SL:
return (ftt_fault);
k.ll = 0;
k.c[7] = uc;
} else { /* store byte */
uc = k.c[7];
return (ftt_fault);
}
break;
case ASI_FL16_P:
case ASI_FL16_S:
return (ftt_alignment);
return (ftt_fault);
k.ll = 0;
k.s[3] = us;
} else { /* store short */
us = k.s[3];
return (ftt_fault);
}
break;
case ASI_FL16_PL: /* little-endian */
case ASI_FL16_SL:
return (ftt_alignment);
return (ftt_fault);
k.ll = 0;
} else { /* store short */
uc = k.c[7];
return (ftt_fault);
}
break;
}
return (ftt_none);
}
/*
* Simulator for block loads and stores between floating-point unit and memory.
* XXX - OK, so it is really gross to flush the whole Ecache for a block commit
* store - but the circumstances under which this code actually gets
* used in real life are so obscure that you can live with it!
*/
static enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
union {
freg_type f;
uint8_t c[8];
} k, l;
union {
int32_t i;
} fp;
/* ensure register is 8-double precision aligned */
if ((nrd & 0xf) != 0)
return (ftt_unimplemented);
return (ftt);
return (ftt);
} else { /* effective address = rs1 + imm13 */
return (ftt);
}
return (ftt_alignment);
switch (asi) {
case ASI_BLK_AIUPL:
case ASI_BLK_AIUSL:
case ASI_BLK_PL:
case ASI_BLK_SL:
/* FALLTHROUGH */
case ASI_BLK_AIUP:
case ASI_BLK_AIUS:
case ASI_BLK_P:
case ASI_BLK_S:
case ASI_BLK_COMMIT_P:
case ASI_BLK_COMMIT_S:
return (ftt);
if (little_endian) {
for (j = 0, h = 7; j < 8; j++, h--)
l.c[h] = k.c[j];
}
}
} else { /* stdf */
if (little_endian) {
for (j = 0, h = 7; j < 8; j++, h--)
l.c[h] = k.c[j];
}
return (ftt);
}
}
break;
default:
/* addr of unimp inst */
return (ftt_unimplemented);
}
return (ftt_none);
}
/*
* Simulator for rd %gsr instruction.
*/
enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
uint64_t r;
return (ftt);
}
/*
* Simulator for wr %gsr instruction.
*/
enum ftt_type
void *prw, /* Pointer to locals and ins. */
{
return (ftt);
return (ftt);
} else { /* use sign_ext(simm13) */
union {
uint32_t i;
} fp;
}
return (ftt);
}
/*
* This is the loadable module wrapper.
*/
/*
* Module linkage information for the kernel.
*/
extern struct mod_ops mod_miscops;
"vis fp simulation",
};
static struct modlinkage modlinkage = {
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
{
}