/* insnset.c -- Instruction specific functions.
|
/* insnset.c -- Instruction specific functions.
|
|
|
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
|
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
|
2000-2002 Marko Mlinar, markom@opencores.org
|
2000-2002 Marko Mlinar, markom@opencores.org
|
Copyright (C) 2008 Embecosm Limited
|
Copyright (C) 2008 Embecosm Limited
|
Copyright (C) 2009 Jungsook yang, jungsook.yang@uci.edu
|
Copyright (C) 2009 Jungsook yang, jungsook.yang@uci.edu
|
|
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
Contributor Julius Baxter julius@orsoc.se
|
Contributor Julius Baxter julius@orsoc.se
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
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
|
under the terms of the GNU General Public License as published by the Free
|
Software Foundation; either version 3 of the License, or (at your option)
|
Software Foundation; either version 3 of the License, or (at your option)
|
any later version.
|
any later version.
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
more details.
|
more details.
|
|
|
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
/* This program is commented throughout in a fashion suitable for processing
|
/* This program is commented throughout in a fashion suitable for processing
|
with Doxygen. */
|
with Doxygen. */
|
|
|
|
|
INSTRUCTION (l_add) {
|
INSTRUCTION (l_add) {
|
orreg_t temp1, temp2, temp3;
|
orreg_t temp1, temp2, temp3;
|
int8_t temp4;
|
int8_t temp4;
|
|
|
temp2 = (orreg_t)PARAM2;
|
temp2 = (orreg_t)PARAM2;
|
temp3 = (orreg_t)PARAM1;
|
temp3 = (orreg_t)PARAM1;
|
temp1 = temp2 + temp3;
|
temp1 = temp2 + temp3;
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
|
|
/* Set overflow if two negative values gave a positive sum, or if two
|
/* Set overflow if two negative values gave a positive sum, or if two
|
positive values gave a negative sum. Otherwise clear it */
|
positive values gave a negative sum. Otherwise clear it */
|
if ((((long int) temp2 < 0) &&
|
if ((((long int) temp2 < 0) &&
|
((long int) temp3 < 0) &&
|
((long int) temp3 < 0) &&
|
((long int) temp1 >= 0)) ||
|
((long int) temp1 >= 0)) ||
|
(((long int) temp2 >= 0) &&
|
(((long int) temp2 >= 0) &&
|
((long int) temp3 >= 0) &&
|
((long int) temp3 >= 0) &&
|
((long int) temp1 < 0)))
|
((long int) temp1 < 0)))
|
{
|
{
|
cpu_state.sprs[SPR_SR] |= SPR_SR_OV;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_OV;
|
}
|
}
|
else
|
else
|
{
|
{
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV;
|
}
|
}
|
|
|
/* Set the carry flag if (as unsigned values) the result is smaller than
|
/* Set the carry flag if (as unsigned values) the result is smaller than
|
either operand (if it smaller than one, it will be smaller than both, so
|
either operand (if it smaller than one, it will be smaller than both, so
|
we need only test one). */
|
we need only test one). */
|
if ((uorreg_t) temp1 < (uorreg_t) temp2)
|
if ((uorreg_t) temp1 < (uorreg_t) temp2)
|
{
|
{
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
}
|
}
|
else
|
else
|
{
|
{
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
}
|
}
|
|
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
is set. */
|
is set. */
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
((cpu_state.sprs[SPR_SR] & SPR_SR_OV) == SPR_SR_OV))
|
((cpu_state.sprs[SPR_SR] & SPR_SR_OV) == SPR_SR_OV))
|
{
|
{
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
}
|
}
|
|
|
temp4 = temp1;
|
temp4 = temp1;
|
if (temp4 == temp1)
|
if (temp4 == temp1)
|
or1k_mstats.byteadd++;
|
or1k_mstats.byteadd++;
|
}
|
}
|
INSTRUCTION (l_addc) {
|
INSTRUCTION (l_addc) {
|
orreg_t temp1, temp2, temp3;
|
orreg_t temp1, temp2, temp3;
|
int8_t temp4;
|
int8_t temp4;
|
int carry_in = (cpu_state.sprs[SPR_SR] & SPR_SR_CY) == SPR_SR_CY;
|
int carry_in = (cpu_state.sprs[SPR_SR] & SPR_SR_CY) == SPR_SR_CY;
|
|
|
temp2 = (orreg_t)PARAM2;
|
temp2 = (orreg_t)PARAM2;
|
temp3 = (orreg_t)PARAM1;
|
temp3 = (orreg_t)PARAM1;
|
temp1 = temp2 + temp3;
|
temp1 = temp2 + temp3;
|
|
|
if(carry_in)
|
if(carry_in)
|
{
|
{
|
temp1++; /* Add in the carry bit */
|
temp1++; /* Add in the carry bit */
|
}
|
}
|
|
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
|
|
/* Set overflow if two negative values gave a positive sum, or if two
|
/* Set overflow if two negative values gave a positive sum, or if two
|
positive values gave a negative sum. Otherwise clear it. There are no
|
positive values gave a negative sum. Otherwise clear it. There are no
|
corner cases with the extra bit carried in (unlike the carry flag - see
|
corner cases with the extra bit carried in (unlike the carry flag - see
|
below). */
|
below). */
|
if ((((long int) temp2 < 0) &&
|
if ((((long int) temp2 < 0) &&
|
((long int) temp3 < 0) &&
|
((long int) temp3 < 0) &&
|
((long int) temp1 >= 0)) ||
|
((long int) temp1 >= 0)) ||
|
(((long int) temp2 >= 0) &&
|
(((long int) temp2 >= 0) &&
|
((long int) temp3 >= 0) &&
|
((long int) temp3 >= 0) &&
|
((long int) temp1 < 0)))
|
((long int) temp1 < 0)))
|
{
|
{
|
cpu_state.sprs[SPR_SR] |= SPR_SR_OV;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_OV;
|
}
|
}
|
else
|
else
|
{
|
{
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV;
|
}
|
}
|
|
|
/* Set the carry flag if (as unsigned values) the result is smaller than
|
/* Set the carry flag if (as unsigned values) the result is smaller than
|
either operand (if it smaller than one, it will be smaller than both, so
|
either operand (if it smaller than one, it will be smaller than both, so
|
we need only test one). If there is a carry in, the test should be less
|
we need only test one). If there is a carry in, the test should be less
|
than or equal, to deal with the 0 + 0xffffffff + c = 0 case (which
|
than or equal, to deal with the 0 + 0xffffffff + c = 0 case (which
|
generates a carry). */
|
generates a carry). */
|
if ((carry_in && ((uorreg_t) temp1 <= (uorreg_t) temp2)) ||
|
if ((carry_in && ((uorreg_t) temp1 <= (uorreg_t) temp2)) ||
|
((uorreg_t) temp1 < (uorreg_t) temp2))
|
((uorreg_t) temp1 < (uorreg_t) temp2))
|
{
|
{
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
}
|
}
|
else
|
else
|
{
|
{
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
}
|
}
|
|
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
is set. */
|
is set. */
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
((cpu_state.sprs[SPR_SR] & SPR_SR_OV) == SPR_SR_OV))
|
((cpu_state.sprs[SPR_SR] & SPR_SR_OV) == SPR_SR_OV))
|
{
|
{
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
}
|
}
|
|
|
temp4 = temp1;
|
temp4 = temp1;
|
if (temp4 == temp1)
|
if (temp4 == temp1)
|
or1k_mstats.byteadd++;
|
or1k_mstats.byteadd++;
|
}
|
}
|
INSTRUCTION (l_sw) {
|
INSTRUCTION (l_sw) {
|
int old_cyc = 0;
|
int old_cyc = 0;
|
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
|
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
|
set_mem32(PARAM0, PARAM1, &breakpoint);
|
set_mem32(PARAM0, PARAM1, &breakpoint);
|
if (config.cpu.sbuf_len) {
|
if (config.cpu.sbuf_len) {
|
int t = runtime.sim.mem_cycles;
|
int t = runtime.sim.mem_cycles;
|
runtime.sim.mem_cycles = old_cyc;
|
runtime.sim.mem_cycles = old_cyc;
|
sbuf_store (t - old_cyc);
|
sbuf_store (t - old_cyc);
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_sb) {
|
INSTRUCTION (l_sb) {
|
int old_cyc = 0;
|
int old_cyc = 0;
|
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
|
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
|
set_mem8(PARAM0, PARAM1, &breakpoint);
|
set_mem8(PARAM0, PARAM1, &breakpoint);
|
if (config.cpu.sbuf_len) {
|
if (config.cpu.sbuf_len) {
|
int t = runtime.sim.mem_cycles;
|
int t = runtime.sim.mem_cycles;
|
runtime.sim.mem_cycles = old_cyc;
|
runtime.sim.mem_cycles = old_cyc;
|
sbuf_store (t- old_cyc);
|
sbuf_store (t- old_cyc);
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_sh) {
|
INSTRUCTION (l_sh) {
|
int old_cyc = 0;
|
int old_cyc = 0;
|
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
|
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
|
set_mem16(PARAM0, PARAM1, &breakpoint);
|
set_mem16(PARAM0, PARAM1, &breakpoint);
|
if (config.cpu.sbuf_len) {
|
if (config.cpu.sbuf_len) {
|
int t = runtime.sim.mem_cycles;
|
int t = runtime.sim.mem_cycles;
|
runtime.sim.mem_cycles = old_cyc;
|
runtime.sim.mem_cycles = old_cyc;
|
sbuf_store (t - old_cyc);
|
sbuf_store (t - old_cyc);
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_lws) {
|
INSTRUCTION (l_lws) {
|
uint32_t val;
|
uint32_t val;
|
if (config.cpu.sbuf_len) sbuf_load ();
|
if (config.cpu.sbuf_len) sbuf_load ();
|
val = eval_mem32(PARAM1, &breakpoint);
|
val = eval_mem32(PARAM1, &breakpoint);
|
/* If eval operand produced exception don't set anything. JPB changed to
|
/* If eval operand produced exception don't set anything. JPB changed to
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
if (!(except_pending || breakpoint))
|
if (!(except_pending || breakpoint))
|
SET_PARAM0(val);
|
SET_PARAM0(val);
|
}
|
}
|
INSTRUCTION (l_lwz) {
|
INSTRUCTION (l_lwz) {
|
uint32_t val;
|
uint32_t val;
|
if (config.cpu.sbuf_len) sbuf_load ();
|
if (config.cpu.sbuf_len) sbuf_load ();
|
val = eval_mem32(PARAM1, &breakpoint);
|
val = eval_mem32(PARAM1, &breakpoint);
|
/* If eval operand produced exception don't set anything. JPB changed to
|
/* If eval operand produced exception don't set anything. JPB changed to
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
if (!(except_pending || breakpoint))
|
if (!(except_pending || breakpoint))
|
SET_PARAM0(val);
|
SET_PARAM0(val);
|
}
|
}
|
INSTRUCTION (l_lbs) {
|
INSTRUCTION (l_lbs) {
|
int8_t val;
|
int8_t val;
|
if (config.cpu.sbuf_len) sbuf_load ();
|
if (config.cpu.sbuf_len) sbuf_load ();
|
val = eval_mem8(PARAM1, &breakpoint);
|
val = eval_mem8(PARAM1, &breakpoint);
|
/* If eval operand produced exception don't set anything. JPB changed to
|
/* If eval operand produced exception don't set anything. JPB changed to
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
if (!(except_pending || breakpoint))
|
if (!(except_pending || breakpoint))
|
SET_PARAM0(val);
|
SET_PARAM0(val);
|
}
|
}
|
INSTRUCTION (l_lbz) {
|
INSTRUCTION (l_lbz) {
|
uint8_t val;
|
uint8_t val;
|
if (config.cpu.sbuf_len) sbuf_load ();
|
if (config.cpu.sbuf_len) sbuf_load ();
|
val = eval_mem8(PARAM1, &breakpoint);
|
val = eval_mem8(PARAM1, &breakpoint);
|
/* If eval operand produced exception don't set anything. JPB changed to
|
/* If eval operand produced exception don't set anything. JPB changed to
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
if (!(except_pending || breakpoint))
|
if (!(except_pending || breakpoint))
|
SET_PARAM0(val);
|
SET_PARAM0(val);
|
}
|
}
|
INSTRUCTION (l_lhs) {
|
INSTRUCTION (l_lhs) {
|
int16_t val;
|
int16_t val;
|
if (config.cpu.sbuf_len) sbuf_load ();
|
if (config.cpu.sbuf_len) sbuf_load ();
|
val = eval_mem16(PARAM1, &breakpoint);
|
val = eval_mem16(PARAM1, &breakpoint);
|
/* If eval operand produced exception don't set anything. JPB changed to
|
/* If eval operand produced exception don't set anything. JPB changed to
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
if (!(except_pending || breakpoint))
|
if (!(except_pending || breakpoint))
|
SET_PARAM0(val);
|
SET_PARAM0(val);
|
}
|
}
|
INSTRUCTION (l_lhz) {
|
INSTRUCTION (l_lhz) {
|
uint16_t val;
|
uint16_t val;
|
if (config.cpu.sbuf_len) sbuf_load ();
|
if (config.cpu.sbuf_len) sbuf_load ();
|
val = eval_mem16(PARAM1, &breakpoint);
|
val = eval_mem16(PARAM1, &breakpoint);
|
/* If eval operand produced exception don't set anything. JPB changed to
|
/* If eval operand produced exception don't set anything. JPB changed to
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
trigger on breakpoint, as well as except_pending (seemed to be a bug). */
|
if (!(except_pending || breakpoint))
|
if (!(except_pending || breakpoint))
|
SET_PARAM0(val);
|
SET_PARAM0(val);
|
}
|
}
|
INSTRUCTION (l_movhi) {
|
INSTRUCTION (l_movhi) {
|
SET_PARAM0(PARAM1 << 16);
|
SET_PARAM0(PARAM1 << 16);
|
}
|
}
|
INSTRUCTION (l_and) {
|
INSTRUCTION (l_and) {
|
uorreg_t temp1;
|
uorreg_t temp1;
|
temp1 = PARAM1 & PARAM2;
|
temp1 = PARAM1 & PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
if (ARITH_SET_FLAG) {
|
if (ARITH_SET_FLAG) {
|
if(!temp1)
|
if(!temp1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_or) {
|
INSTRUCTION (l_or) {
|
uorreg_t temp1;
|
uorreg_t temp1;
|
temp1 = PARAM1 | PARAM2;
|
temp1 = PARAM1 | PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
}
|
}
|
INSTRUCTION (l_xor) {
|
INSTRUCTION (l_xor) {
|
uorreg_t temp1;
|
uorreg_t temp1;
|
temp1 = PARAM1 ^ PARAM2;
|
temp1 = PARAM1 ^ PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
}
|
}
|
INSTRUCTION (l_sub) {
|
INSTRUCTION (l_sub) {
|
orreg_t temp1;
|
orreg_t temp1;
|
temp1 = (orreg_t)PARAM1 - (orreg_t)PARAM2;
|
temp1 = (orreg_t)PARAM1 - (orreg_t)PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
}
|
}
|
/*int mcount = 0;*/
|
/*int mcount = 0;*/
|
INSTRUCTION (l_mul) {
|
INSTRUCTION (l_mul) {
|
orreg_t temp1;
|
orreg_t temp0, temp1, temp2;
|
|
LONGEST ltemp0, ltemp1, ltemp2;
|
|
ULONGEST ultemp0, ultemp1, ultemp2;
|
|
|
temp1 = (orreg_t)PARAM1 * (orreg_t)PARAM2;
|
/* Args in 32-bit */
|
SET_OV_FLAG_FN (temp1);
|
temp2 = (orreg_t) PARAM2;
|
SET_PARAM0(temp1);
|
temp1 = (orreg_t) PARAM1;
|
/*if (!(mcount++ & 1023)) {
|
|
PRINTF ("[%i]\n",mcount);
|
/* Compute initially in 64-bit */
|
}*/
|
ltemp1 = (LONGEST) temp1;
|
|
ltemp2 = (LONGEST) temp2;
|
|
ltemp0 = ltemp1 * ltemp2;
|
|
|
|
temp0 = (orreg_t) (ltemp0 & 0xffffffffLL);
|
|
SET_PARAM0 (temp0);
|
|
|
|
/* We have 2's complement overflow, if the result is less than the smallest
|
|
possible 32-bit negative number, or greater than the largest possible
|
|
32-bit positive number. */
|
|
if ((ltemp0 < (LONGEST) INT32_MIN) || (ltemp0 > (LONGEST) INT32_MAX))
|
|
{
|
|
cpu_state.sprs[SPR_SR] |= SPR_SR_OV;
|
|
}
|
|
else
|
|
{
|
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV;
|
|
}
|
|
|
|
/* We have 1's complement overflow, if, as an unsigned operation, the result
|
|
is greater than the largest possible 32-bit unsigned number. This is
|
|
probably quicker than unpicking the bits of the signed result. */
|
|
ultemp1 = (ULONGEST) temp1 & 0xffffffffULL;
|
|
ultemp2 = (ULONGEST) temp2 & 0xffffffffULL;
|
|
ultemp0 = ultemp1 * ultemp2;
|
|
|
|
if (ultemp0 > (ULONGEST) UINT32_MAX)
|
|
{
|
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
|
}
|
|
else
|
|
{
|
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
|
}
|
|
|
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
|
is set. */
|
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
|
((cpu_state.sprs[SPR_SR] & SPR_SR_OV) == SPR_SR_OV))
|
|
{
|
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
|
}
|
|
}
|
|
INSTRUCTION (l_mulu) {
|
|
uorreg_t temp0, temp1, temp2;
|
|
ULONGEST ultemp0, ultemp1, ultemp2;
|
|
|
|
/* Args in 32-bit */
|
|
temp2 = (uorreg_t) PARAM2;
|
|
temp1 = (uorreg_t) PARAM1;
|
|
|
|
/* Compute initially in 64-bit */
|
|
ultemp1 = (ULONGEST) temp1 & 0xffffffffULL;
|
|
ultemp2 = (ULONGEST) temp2 & 0xffffffffULL;
|
|
ultemp0 = ultemp1 * ultemp2;
|
|
|
|
temp0 = (uorreg_t) (ultemp0 & 0xffffffffULL);
|
|
SET_PARAM0 (temp0);
|
|
|
|
/* We never have 2's complement overflow */
|
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV;
|
|
|
|
/* We have 1's complement overflow, if the result is greater than the
|
|
largest possible 32-bit unsigned number. */
|
|
if (ultemp0 > (ULONGEST) UINT32_MAX)
|
|
{
|
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
|
}
|
|
else
|
|
{
|
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
|
}
|
}
|
}
|
INSTRUCTION (l_div) {
|
INSTRUCTION (l_div) {
|
orreg_t temp3, temp2, temp1;
|
orreg_t temp3, temp2, temp1;
|
|
|
temp3 = PARAM2;
|
temp3 = (orreg_t) PARAM2;
|
temp2 = PARAM1;
|
temp2 = (orreg_t) PARAM1;
|
if (temp3)
|
|
|
/* Check for divide by zero (sets carry) */
|
|
if (0 == temp3)
|
|
{
|
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
|
}
|
|
else
|
|
{
|
temp1 = temp2 / temp3;
|
temp1 = temp2 / temp3;
|
else {
|
SET_PARAM0(temp1);
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY; /* Div by zero sets carry */
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
|
}
|
|
|
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV; /* Never set */
|
|
|
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
|
is set. */
|
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
|
((cpu_state.sprs[SPR_SR] & SPR_SR_CY) == SPR_SR_CY))
|
|
{
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
except_handle (EXCEPT_RANGE, cpu_state.pc);
|
return;
|
|
}
|
}
|
SET_OV_FLAG_FN (temp1);
|
|
SET_PARAM0(temp1);
|
|
}
|
}
|
INSTRUCTION (l_divu) {
|
INSTRUCTION (l_divu) {
|
uorreg_t temp3, temp2, temp1;
|
uorreg_t temp3, temp2, temp1;
|
|
|
temp3 = PARAM2;
|
temp3 = (uorreg_t) PARAM2;
|
temp2 = PARAM1;
|
temp2 = (uorreg_t) PARAM1;
|
if (temp3)
|
|
|
/* Check for divide by zero (sets carry) */
|
|
if (0 == temp3)
|
|
{
|
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
|
|
}
|
|
else
|
|
{
|
temp1 = temp2 / temp3;
|
temp1 = temp2 / temp3;
|
else {
|
SET_PARAM0(temp1);
|
cpu_state.sprs[SPR_SR] |= SPR_SR_CY; /* Div by zero sets carry */
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
|
|
}
|
|
|
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV; /* Never set */
|
|
|
|
/* Trigger a range exception if the overflow flag is set and the SR[OVE] bit
|
|
is set. */
|
|
if (((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) == SPR_SR_OVE) &&
|
|
((cpu_state.sprs[SPR_SR] & SPR_SR_CY) == SPR_SR_CY))
|
|
{
|
except_handle(EXCEPT_RANGE, cpu_state.pc);
|
except_handle(EXCEPT_RANGE, cpu_state.pc);
|
return;
|
|
}
|
}
|
SET_OV_FLAG_FN (temp1);
|
|
SET_PARAM0(temp1);
|
|
/* runtime.sim.cycles += 16; */
|
|
}
|
}
|
INSTRUCTION (l_sll) {
|
INSTRUCTION (l_sll) {
|
uorreg_t temp1;
|
uorreg_t temp1;
|
|
|
temp1 = PARAM1 << PARAM2;
|
temp1 = PARAM1 << PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
/* runtime.sim.cycles += 2; */
|
/* runtime.sim.cycles += 2; */
|
}
|
}
|
INSTRUCTION (l_sra) {
|
INSTRUCTION (l_sra) {
|
orreg_t temp1;
|
orreg_t temp1;
|
|
|
temp1 = (orreg_t)PARAM1 >> PARAM2;
|
temp1 = (orreg_t)PARAM1 >> PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
/* runtime.sim.cycles += 2; */
|
/* runtime.sim.cycles += 2; */
|
}
|
}
|
INSTRUCTION (l_srl) {
|
INSTRUCTION (l_srl) {
|
uorreg_t temp1;
|
uorreg_t temp1;
|
temp1 = PARAM1 >> PARAM2;
|
temp1 = PARAM1 >> PARAM2;
|
SET_OV_FLAG_FN (temp1);
|
SET_OV_FLAG_FN (temp1);
|
SET_PARAM0(temp1);
|
SET_PARAM0(temp1);
|
/* runtime.sim.cycles += 2; */
|
/* runtime.sim.cycles += 2; */
|
}
|
}
|
INSTRUCTION (l_bf) {
|
INSTRUCTION (l_bf) {
|
if (config.bpb.enabled) {
|
if (config.bpb.enabled) {
|
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0;
|
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0;
|
or1k_mstats.bf[cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0][fwd]++;
|
or1k_mstats.bf[cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0][fwd]++;
|
bpb_update(current->insn_addr, cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0);
|
bpb_update(current->insn_addr, cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0);
|
}
|
}
|
if(cpu_state.sprs[SPR_SR] & SPR_SR_F) {
|
if(cpu_state.sprs[SPR_SR] & SPR_SR_F) {
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
btic_update(pcnext);
|
btic_update(pcnext);
|
next_delay_insn = 1;
|
next_delay_insn = 1;
|
} else {
|
} else {
|
btic_update(cpu_state.pc);
|
btic_update(cpu_state.pc);
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_bnf) {
|
INSTRUCTION (l_bnf) {
|
if (config.bpb.enabled) {
|
if (config.bpb.enabled) {
|
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0;
|
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0;
|
or1k_mstats.bnf[cpu_state.sprs[SPR_SR] & SPR_SR_F ? 0 : 1][fwd]++;
|
or1k_mstats.bnf[cpu_state.sprs[SPR_SR] & SPR_SR_F ? 0 : 1][fwd]++;
|
bpb_update(current->insn_addr, cpu_state.sprs[SPR_SR] & SPR_SR_F ? 0 : 1);
|
bpb_update(current->insn_addr, cpu_state.sprs[SPR_SR] & SPR_SR_F ? 0 : 1);
|
}
|
}
|
if (!(cpu_state.sprs[SPR_SR] & SPR_SR_F)) {
|
if (!(cpu_state.sprs[SPR_SR] & SPR_SR_F)) {
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
btic_update(pcnext);
|
btic_update(pcnext);
|
next_delay_insn = 1;
|
next_delay_insn = 1;
|
} else {
|
} else {
|
btic_update(cpu_state.pc);
|
btic_update(cpu_state.pc);
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_j) {
|
INSTRUCTION (l_j) {
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
next_delay_insn = 1;
|
next_delay_insn = 1;
|
}
|
}
|
INSTRUCTION (l_jal) {
|
INSTRUCTION (l_jal) {
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
|
|
|
setsim_reg(LINK_REGNO, cpu_state.pc + 8);
|
setsim_reg(LINK_REGNO, cpu_state.pc + 8);
|
next_delay_insn = 1;
|
next_delay_insn = 1;
|
if (config.sim.profile) {
|
if (config.sim.profile) {
|
struct label_entry *tmp;
|
struct label_entry *tmp;
|
if (verify_memoryarea(cpu_state.pc_delay) && (tmp = get_label (cpu_state.pc_delay)))
|
if (verify_memoryarea(cpu_state.pc_delay) && (tmp = get_label (cpu_state.pc_delay)))
|
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" %s\n",
|
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" %s\n",
|
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay,
|
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay,
|
tmp->name);
|
tmp->name);
|
else
|
else
|
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" @%"PRIxADDR"\n",
|
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" @%"PRIxADDR"\n",
|
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay,
|
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay,
|
cpu_state.pc_delay);
|
cpu_state.pc_delay);
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_jalr) {
|
INSTRUCTION (l_jalr) {
|
cpu_state.pc_delay = PARAM0;
|
cpu_state.pc_delay = PARAM0;
|
setsim_reg(LINK_REGNO, cpu_state.pc + 8);
|
setsim_reg(LINK_REGNO, cpu_state.pc + 8);
|
next_delay_insn = 1;
|
next_delay_insn = 1;
|
}
|
}
|
INSTRUCTION (l_jr) {
|
INSTRUCTION (l_jr) {
|
cpu_state.pc_delay = PARAM0;
|
cpu_state.pc_delay = PARAM0;
|
next_delay_insn = 1;
|
next_delay_insn = 1;
|
if (config.sim.profile)
|
if (config.sim.profile)
|
fprintf (runtime.sim.fprof, "-%08llX %"PRIxADDR"\n", runtime.sim.cycles,
|
fprintf (runtime.sim.fprof, "-%08llX %"PRIxADDR"\n", runtime.sim.cycles,
|
cpu_state.pc_delay);
|
cpu_state.pc_delay);
|
}
|
}
|
INSTRUCTION (l_rfe) {
|
INSTRUCTION (l_rfe) {
|
pcnext = cpu_state.sprs[SPR_EPCR_BASE];
|
pcnext = cpu_state.sprs[SPR_EPCR_BASE];
|
mtspr(SPR_SR, cpu_state.sprs[SPR_ESR_BASE]);
|
mtspr(SPR_SR, cpu_state.sprs[SPR_ESR_BASE]);
|
}
|
}
|
INSTRUCTION (l_nop) {
|
INSTRUCTION (l_nop) {
|
uint32_t k = PARAM0;
|
uint32_t k = PARAM0;
|
switch (k) {
|
switch (k) {
|
case NOP_NOP:
|
case NOP_NOP:
|
break;
|
break;
|
case NOP_EXIT:
|
case NOP_EXIT:
|
PRINTF("exit(%"PRIdREG")\n", evalsim_reg (3));
|
PRINTF("exit(%"PRIdREG")\n", evalsim_reg (3));
|
fprintf(stderr, "@reset : cycles %lld, insn #%lld\n",
|
fprintf(stderr, "@reset : cycles %lld, insn #%lld\n",
|
runtime.sim.reset_cycles, runtime.cpu.reset_instructions);
|
runtime.sim.reset_cycles, runtime.cpu.reset_instructions);
|
fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles,
|
fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles,
|
runtime.cpu.instructions);
|
runtime.cpu.instructions);
|
fprintf(stderr, " diff : cycles %lld, insn #%lld\n",
|
fprintf(stderr, " diff : cycles %lld, insn #%lld\n",
|
runtime.sim.cycles - runtime.sim.reset_cycles,
|
runtime.sim.cycles - runtime.sim.reset_cycles,
|
runtime.cpu.instructions - runtime.cpu.reset_instructions);
|
runtime.cpu.instructions - runtime.cpu.reset_instructions);
|
if (config.debug.gdb_enabled)
|
if (config.debug.gdb_enabled)
|
set_stall_state (1);
|
set_stall_state (1);
|
else
|
else
|
sim_done();
|
sim_done();
|
break;
|
break;
|
case NOP_CNT_RESET:
|
case NOP_CNT_RESET:
|
PRINTF("****************** counters reset ******************\n");
|
PRINTF("****************** counters reset ******************\n");
|
PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions);
|
PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions);
|
PRINTF("****************** counters reset ******************\n");
|
PRINTF("****************** counters reset ******************\n");
|
runtime.sim.reset_cycles = runtime.sim.cycles;
|
runtime.sim.reset_cycles = runtime.sim.cycles;
|
runtime.cpu.reset_instructions = runtime.cpu.instructions;
|
runtime.cpu.reset_instructions = runtime.cpu.instructions;
|
break;
|
break;
|
case NOP_PUTC: /*JPB */
|
case NOP_PUTC: /*JPB */
|
printf( "%c", (char)(evalsim_reg( 3 ) & 0xff));
|
printf( "%c", (char)(evalsim_reg( 3 ) & 0xff));
|
fflush( stdout );
|
fflush( stdout );
|
break;
|
break;
|
case NOP_GET_TICKS:
|
case NOP_GET_TICKS:
|
cpu_state.reg[11] = runtime.sim.cycles & 0xffffffff;
|
cpu_state.reg[11] = runtime.sim.cycles & 0xffffffff;
|
cpu_state.reg[12] = runtime.sim.cycles >> 32;
|
cpu_state.reg[12] = runtime.sim.cycles >> 32;
|
break;
|
break;
|
case NOP_GET_PS:
|
case NOP_GET_PS:
|
cpu_state.reg[11] = config.sim.clkcycle_ps;
|
cpu_state.reg[11] = config.sim.clkcycle_ps;
|
break;
|
break;
|
case NOP_REPORT:
|
case NOP_REPORT:
|
PRINTF("report(0x%"PRIxREG");\n", evalsim_reg(3));
|
PRINTF("report(0x%"PRIxREG");\n", evalsim_reg(3));
|
default:
|
default:
|
if (k >= NOP_REPORT_FIRST && k <= NOP_REPORT_LAST)
|
if (k >= NOP_REPORT_FIRST && k <= NOP_REPORT_LAST)
|
PRINTF("report %" PRIdREG " (0x%"PRIxREG");\n", k - NOP_REPORT_FIRST,
|
PRINTF("report %" PRIdREG " (0x%"PRIxREG");\n", k - NOP_REPORT_FIRST,
|
evalsim_reg(3));
|
evalsim_reg(3));
|
break;
|
break;
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_sfeq) {
|
INSTRUCTION (l_sfeq) {
|
if(PARAM0 == PARAM1)
|
if(PARAM0 == PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfne) {
|
INSTRUCTION (l_sfne) {
|
if(PARAM0 != PARAM1)
|
if(PARAM0 != PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfgts) {
|
INSTRUCTION (l_sfgts) {
|
if((orreg_t)PARAM0 > (orreg_t)PARAM1)
|
if((orreg_t)PARAM0 > (orreg_t)PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfges) {
|
INSTRUCTION (l_sfges) {
|
if((orreg_t)PARAM0 >= (orreg_t)PARAM1)
|
if((orreg_t)PARAM0 >= (orreg_t)PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sflts) {
|
INSTRUCTION (l_sflts) {
|
if((orreg_t)PARAM0 < (orreg_t)PARAM1)
|
if((orreg_t)PARAM0 < (orreg_t)PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfles) {
|
INSTRUCTION (l_sfles) {
|
if((orreg_t)PARAM0 <= (orreg_t)PARAM1)
|
if((orreg_t)PARAM0 <= (orreg_t)PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfgtu) {
|
INSTRUCTION (l_sfgtu) {
|
if(PARAM0 > PARAM1)
|
if(PARAM0 > PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfgeu) {
|
INSTRUCTION (l_sfgeu) {
|
if(PARAM0 >= PARAM1)
|
if(PARAM0 >= PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfltu) {
|
INSTRUCTION (l_sfltu) {
|
if(PARAM0 < PARAM1)
|
if(PARAM0 < PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_sfleu) {
|
INSTRUCTION (l_sfleu) {
|
if(PARAM0 <= PARAM1)
|
if(PARAM0 <= PARAM1)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
}
|
}
|
INSTRUCTION (l_extbs) {
|
INSTRUCTION (l_extbs) {
|
int8_t x;
|
int8_t x;
|
x = PARAM1;
|
x = PARAM1;
|
SET_PARAM0((orreg_t)x);
|
SET_PARAM0((orreg_t)x);
|
}
|
}
|
INSTRUCTION (l_extbz) {
|
INSTRUCTION (l_extbz) {
|
uint8_t x;
|
uint8_t x;
|
x = PARAM1;
|
x = PARAM1;
|
SET_PARAM0((uorreg_t)x);
|
SET_PARAM0((uorreg_t)x);
|
}
|
}
|
INSTRUCTION (l_exths) {
|
INSTRUCTION (l_exths) {
|
int16_t x;
|
int16_t x;
|
x = PARAM1;
|
x = PARAM1;
|
SET_PARAM0((orreg_t)x);
|
SET_PARAM0((orreg_t)x);
|
}
|
}
|
INSTRUCTION (l_exthz) {
|
INSTRUCTION (l_exthz) {
|
uint16_t x;
|
uint16_t x;
|
x = PARAM1;
|
x = PARAM1;
|
SET_PARAM0((uorreg_t)x);
|
SET_PARAM0((uorreg_t)x);
|
}
|
}
|
INSTRUCTION (l_extws) {
|
INSTRUCTION (l_extws) {
|
int32_t x;
|
int32_t x;
|
x = PARAM1;
|
x = PARAM1;
|
SET_PARAM0((orreg_t)x);
|
SET_PARAM0((orreg_t)x);
|
}
|
}
|
INSTRUCTION (l_extwz) {
|
INSTRUCTION (l_extwz) {
|
uint32_t x;
|
uint32_t x;
|
x = PARAM1;
|
x = PARAM1;
|
SET_PARAM0((uorreg_t)x);
|
SET_PARAM0((uorreg_t)x);
|
}
|
}
|
INSTRUCTION (l_mtspr) {
|
INSTRUCTION (l_mtspr) {
|
uint16_t regno = PARAM0 + PARAM2;
|
uint16_t regno = PARAM0 + PARAM2;
|
uorreg_t value = PARAM1;
|
uorreg_t value = PARAM1;
|
|
|
if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
|
if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
|
mtspr(regno, value);
|
mtspr(regno, value);
|
else {
|
else {
|
PRINTF("WARNING: trying to write SPR while SR[SUPV] is cleared.\n");
|
PRINTF("WARNING: trying to write SPR while SR[SUPV] is cleared.\n");
|
sim_done();
|
sim_done();
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_mfspr) {
|
INSTRUCTION (l_mfspr) {
|
uint16_t regno = PARAM1 + PARAM2;
|
uint16_t regno = PARAM1 + PARAM2;
|
uorreg_t value = mfspr(regno);
|
uorreg_t value = mfspr(regno);
|
|
|
if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
|
if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
|
SET_PARAM0(value);
|
SET_PARAM0(value);
|
else {
|
else {
|
SET_PARAM0(0);
|
SET_PARAM0(0);
|
PRINTF("WARNING: trying to read SPR while SR[SUPV] is cleared.\n");
|
PRINTF("WARNING: trying to read SPR while SR[SUPV] is cleared.\n");
|
sim_done();
|
sim_done();
|
}
|
}
|
}
|
}
|
INSTRUCTION (l_sys) {
|
INSTRUCTION (l_sys) {
|
except_handle(EXCEPT_SYSCALL, cpu_state.sprs[SPR_EEAR_BASE]);
|
except_handle(EXCEPT_SYSCALL, cpu_state.sprs[SPR_EEAR_BASE]);
|
}
|
}
|
INSTRUCTION (l_trap) {
|
INSTRUCTION (l_trap) {
|
/* TODO: some SR related code here! */
|
/* TODO: some SR related code here! */
|
except_handle(EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
|
except_handle(EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
|
}
|
}
|
INSTRUCTION (l_mac) {
|
INSTRUCTION (l_mac) {
|
uorreg_t lo, hi;
|
uorreg_t lo, hi;
|
LONGEST l;
|
LONGEST l;
|
orreg_t x, y, t;
|
orreg_t x, y, t;
|
|
|
lo = cpu_state.sprs[SPR_MACLO];
|
lo = cpu_state.sprs[SPR_MACLO];
|
hi = cpu_state.sprs[SPR_MACHI];
|
hi = cpu_state.sprs[SPR_MACHI];
|
x = PARAM0;
|
x = PARAM0;
|
y = PARAM1;
|
y = PARAM1;
|
/* PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y); */
|
/* PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y); */
|
|
|
/* Compute the temporary as (signed) 32-bits, then sign-extend to 64 when
|
/* Compute the temporary as (signed) 32-bits, then sign-extend to 64 when
|
adding in. */
|
adding in. */
|
l = (ULONGEST)lo | ((LONGEST)hi << 32);
|
l = (ULONGEST)lo | ((LONGEST)hi << 32);
|
t = x * y;
|
t = x * y;
|
l += (LONGEST) t;
|
l += (LONGEST) t;
|
|
|
/* This implementation is very fast - it needs only one cycle for mac. */
|
/* This implementation is very fast - it needs only one cycle for mac. */
|
lo = ((ULONGEST)l) & 0xFFFFFFFF;
|
lo = ((ULONGEST)l) & 0xFFFFFFFF;
|
hi = ((LONGEST)l) >> 32;
|
hi = ((LONGEST)l) >> 32;
|
cpu_state.sprs[SPR_MACLO] = lo;
|
cpu_state.sprs[SPR_MACLO] = lo;
|
cpu_state.sprs[SPR_MACHI] = hi;
|
cpu_state.sprs[SPR_MACHI] = hi;
|
/* PRINTF ("(%"PRIxREG",%"PRIxREG"\n", hi, lo); */
|
/* PRINTF ("(%"PRIxREG",%"PRIxREG"\n", hi, lo); */
|
}
|
}
|
INSTRUCTION (l_msb) {
|
INSTRUCTION (l_msb) {
|
uorreg_t lo, hi;
|
uorreg_t lo, hi;
|
LONGEST l;
|
LONGEST l;
|
orreg_t x, y;
|
orreg_t x, y;
|
|
|
lo = cpu_state.sprs[SPR_MACLO];
|
lo = cpu_state.sprs[SPR_MACLO];
|
hi = cpu_state.sprs[SPR_MACHI];
|
hi = cpu_state.sprs[SPR_MACHI];
|
x = PARAM0;
|
x = PARAM0;
|
y = PARAM1;
|
y = PARAM1;
|
|
|
/* PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y); */
|
/* PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y); */
|
|
|
l = (ULONGEST)lo | ((LONGEST)hi << 32);
|
l = (ULONGEST)lo | ((LONGEST)hi << 32);
|
l -= x * y;
|
l -= x * y;
|
|
|
/* This implementation is very fast - it needs only one cycle for msb. */
|
/* This implementation is very fast - it needs only one cycle for msb. */
|
lo = ((ULONGEST)l) & 0xFFFFFFFF;
|
lo = ((ULONGEST)l) & 0xFFFFFFFF;
|
hi = ((LONGEST)l) >> 32;
|
hi = ((LONGEST)l) >> 32;
|
cpu_state.sprs[SPR_MACLO] = lo;
|
cpu_state.sprs[SPR_MACLO] = lo;
|
cpu_state.sprs[SPR_MACHI] = hi;
|
cpu_state.sprs[SPR_MACHI] = hi;
|
/* PRINTF ("(%"PRIxREG",%"PRIxREG")\n", hi, lo); */
|
/* PRINTF ("(%"PRIxREG",%"PRIxREG")\n", hi, lo); */
|
}
|
}
|
INSTRUCTION (l_macrc) {
|
INSTRUCTION (l_macrc) {
|
orreg_t lo;
|
orreg_t lo;
|
/* No need for synchronization here -- all MAC instructions are 1 cycle long. */
|
/* No need for synchronization here -- all MAC instructions are 1 cycle long. */
|
lo = cpu_state.sprs[SPR_MACLO];
|
lo = cpu_state.sprs[SPR_MACLO];
|
//PRINTF ("<%08x>\n", (unsigned long)l);
|
//PRINTF ("<%08x>\n", (unsigned long)l);
|
SET_PARAM0(lo);
|
SET_PARAM0(lo);
|
cpu_state.sprs[SPR_MACLO] = 0;
|
cpu_state.sprs[SPR_MACLO] = 0;
|
cpu_state.sprs[SPR_MACHI] = 0;
|
cpu_state.sprs[SPR_MACHI] = 0;
|
}
|
}
|
INSTRUCTION (l_cmov) {
|
INSTRUCTION (l_cmov) {
|
SET_PARAM0(cpu_state.sprs[SPR_SR] & SPR_SR_F ? PARAM1 : PARAM2);
|
SET_PARAM0(cpu_state.sprs[SPR_SR] & SPR_SR_F ? PARAM1 : PARAM2);
|
}
|
}
|
INSTRUCTION (l_ff1) {
|
INSTRUCTION (l_ff1) {
|
SET_PARAM0(ffs(PARAM1));
|
SET_PARAM0(ffs(PARAM1));
|
}
|
}
|
INSTRUCTION (l_fl1) {
|
INSTRUCTION (l_fl1) {
|
orreg_t t = (orreg_t)PARAM1;
|
orreg_t t = (orreg_t)PARAM1;
|
|
|
/* Reverse the word and use ffs */
|
/* Reverse the word and use ffs */
|
t = (((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1));
|
t = (((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1));
|
t = (((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2));
|
t = (((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2));
|
t = (((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4));
|
t = (((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4));
|
t = (((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8));
|
t = (((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8));
|
t = ffs ((t >> 16) | (t << 16));
|
t = ffs ((t >> 16) | (t << 16));
|
|
|
SET_PARAM0 (0 == t ? t : 33 - t);
|
SET_PARAM0 (0 == t ? t : 33 - t);
|
}
|
}
|
/******* Floating point instructions *******/
|
/******* Floating point instructions *******/
|
/* Single precision */
|
/* Single precision */
|
INSTRUCTION (lf_add_s) {
|
INSTRUCTION (lf_add_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1, param2;
|
FLOAT param0, param1, param2;
|
param1.hval = (uorreg_t)PARAM1;
|
param1.hval = (uorreg_t)PARAM1;
|
param2.hval = (uorreg_t)PARAM2;
|
param2.hval = (uorreg_t)PARAM2;
|
param0.fval = param1.fval + param2.fval;
|
param0.fval = param1.fval + param2.fval;
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_div_s) {
|
INSTRUCTION (lf_div_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1, param2;
|
FLOAT param0, param1, param2;
|
param1.hval = (uorreg_t)PARAM1;
|
param1.hval = (uorreg_t)PARAM1;
|
param2.hval = (uorreg_t)PARAM2;
|
param2.hval = (uorreg_t)PARAM2;
|
param0.fval = param1.fval / param2.fval;
|
param0.fval = param1.fval / param2.fval;
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_ftoi_s) {
|
INSTRUCTION (lf_ftoi_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
// no other way appeared to work --jb
|
// no other way appeared to work --jb
|
float tmp_f; memcpy((void*)&tmp_f, (void*)&PARAM1, sizeof(float));
|
float tmp_f; memcpy((void*)&tmp_f, (void*)&PARAM1, sizeof(float));
|
SET_PARAM0((int)tmp_f);
|
SET_PARAM0((int)tmp_f);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_itof_s) {
|
INSTRUCTION (lf_itof_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0;
|
FLOAT param0;
|
param0.fval = (float)((int)PARAM1);
|
param0.fval = (float)((int)PARAM1);
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_madd_s) {
|
INSTRUCTION (lf_madd_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0,param1, param2;
|
FLOAT param0,param1, param2;
|
param0.hval = (uorreg_t)PARAM0;
|
param0.hval = (uorreg_t)PARAM0;
|
param1.hval = (uorreg_t)PARAM1;
|
param1.hval = (uorreg_t)PARAM1;
|
param2.hval = PARAM2;
|
param2.hval = PARAM2;
|
param0.fval += param1.fval * param2.fval;
|
param0.fval += param1.fval * param2.fval;
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_mul_s) {
|
INSTRUCTION (lf_mul_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1, param2;
|
FLOAT param0, param1, param2;
|
param1.hval = (uorreg_t)PARAM1;
|
param1.hval = (uorreg_t)PARAM1;
|
param2.hval = (uorreg_t)PARAM2;
|
param2.hval = (uorreg_t)PARAM2;
|
param0.fval = param1.fval * param2.fval;
|
param0.fval = param1.fval * param2.fval;
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_rem_s) {
|
INSTRUCTION (lf_rem_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1, param2;
|
FLOAT param0, param1, param2;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
param2.hval = PARAM2;
|
param2.hval = PARAM2;
|
param0.fval = fmodf (param1.fval, param2.fval);
|
param0.fval = fmodf (param1.fval, param2.fval);
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sfeq_s) {
|
INSTRUCTION (lf_sfeq_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1;
|
FLOAT param0, param1;
|
param0.hval = PARAM0;
|
param0.hval = PARAM0;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
if(param0.fval == param1.fval)
|
if(param0.fval == param1.fval)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sfge_s) {
|
INSTRUCTION (lf_sfge_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1;
|
FLOAT param0, param1;
|
param0.hval = PARAM0;
|
param0.hval = PARAM0;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
if(param0.fval >= param1.fval)
|
if(param0.fval >= param1.fval)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sfgt_s) {
|
INSTRUCTION (lf_sfgt_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1;
|
FLOAT param0, param1;
|
param0.hval = PARAM0;
|
param0.hval = PARAM0;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
if(param0.fval > param1.fval)
|
if(param0.fval > param1.fval)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sfle_s) {
|
INSTRUCTION (lf_sfle_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1;
|
FLOAT param0, param1;
|
param0.hval = PARAM0;
|
param0.hval = PARAM0;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
if(param0.fval <= param1.fval)
|
if(param0.fval <= param1.fval)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sflt_s) {
|
INSTRUCTION (lf_sflt_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1;
|
FLOAT param0, param1;
|
param0.hval = PARAM0;
|
param0.hval = PARAM0;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
if(param0.fval < param1.fval)
|
if(param0.fval < param1.fval)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sfne_s) {
|
INSTRUCTION (lf_sfne_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1;
|
FLOAT param0, param1;
|
param0.hval = PARAM0;
|
param0.hval = PARAM0;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
if(param0.fval != param1.fval)
|
if(param0.fval != param1.fval)
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
|
else
|
else
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
INSTRUCTION (lf_sub_s) {
|
INSTRUCTION (lf_sub_s) {
|
if (config.cpu.hardfloat) {
|
if (config.cpu.hardfloat) {
|
FLOAT param0, param1, param2;
|
FLOAT param0, param1, param2;
|
param1.hval = PARAM1;
|
param1.hval = PARAM1;
|
param2.hval = PARAM2;
|
param2.hval = PARAM2;
|
param0.fval = param1.fval - param2.fval;
|
param0.fval = param1.fval - param2.fval;
|
SET_PARAM0(param0.hval);
|
SET_PARAM0(param0.hval);
|
} else l_invalid();
|
} else l_invalid();
|
}
|
}
|
|
|
/******* Custom instructions *******/
|
/******* Custom instructions *******/
|
INSTRUCTION (l_cust1) {
|
INSTRUCTION (l_cust1) {
|
/*int destr = current->insn >> 21;
|
/*int destr = current->insn >> 21;
|
int src1r = current->insn >> 15;
|
int src1r = current->insn >> 15;
|
int src2r = current->insn >> 9;*/
|
int src2r = current->insn >> 9;*/
|
}
|
}
|
INSTRUCTION (l_cust2) {
|
INSTRUCTION (l_cust2) {
|
}
|
}
|
INSTRUCTION (l_cust3) {
|
INSTRUCTION (l_cust3) {
|
}
|
}
|
INSTRUCTION (l_cust4) {
|
INSTRUCTION (l_cust4) {
|
}
|
}
|
INSTRUCTION (lf_cust1) {
|
INSTRUCTION (lf_cust1) {
|
}
|
}
|
|
|