2016-01-30 06:40:35 +00:00
|
|
|
//(0 = odd, 1 = even) number of bits set in value
|
2016-02-04 10:29:08 +00:00
|
|
|
auto V30MZ::parity(uint8 value) const -> bool {
|
2016-01-30 06:40:35 +00:00
|
|
|
value ^= value >> 4;
|
|
|
|
value ^= value >> 2;
|
|
|
|
value ^= value >> 1;
|
|
|
|
return !(value & 1);
|
|
|
|
}
|
|
|
|
|
2016-02-02 10:51:17 +00:00
|
|
|
#define bits (size == Byte ? 8 : 16)
|
|
|
|
#define mask (size == Byte ? 0xff : 0xffff)
|
2016-02-03 10:24:58 +00:00
|
|
|
#define sign (size == Byte ? 0x80 : 0x8000)
|
2016-02-02 10:51:17 +00:00
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::ADC(Size size, uint16 x, uint16 y) -> uint16 {
|
|
|
|
return ADD(size, x, y + r.f.c);
|
2016-02-02 10:51:17 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::ADD(Size size, uint16 x, uint16 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = (x + y) & mask;
|
|
|
|
r.f.c = x + y > mask;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = (uint4)x + (uint4)y >= 16;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = (result ^ x) & (result ^ y) & sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::AND(Size size, uint16 x, uint16 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = (x & y) & mask;
|
|
|
|
r.f.c = 0;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = 0;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::DEC(Size size, uint16 x) -> uint16 {
|
2016-02-03 10:24:58 +00:00
|
|
|
uint16 result = (x - 1) & mask;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = (x & 0x0f) == 0;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = result == sign - 1;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::DIV(Size size, uint32 x, uint32 y) -> uint32 {
|
2016-02-04 10:29:08 +00:00
|
|
|
if(y == 0) return interrupt(0), 0;
|
2016-02-03 10:24:58 +00:00
|
|
|
uint32 quotient = x / y;
|
|
|
|
uint32 remainder = x % y;
|
|
|
|
return (remainder & mask) << bits | (quotient & mask);
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::DIVI(Size size, int32 x, int32 y) -> uint32 {
|
2016-02-04 10:29:08 +00:00
|
|
|
if(y == 0) return interrupt(0), 0;
|
Update to v097r14 release.
byuu says:
This is a few days old, but oh well.
This WIP changes nall,hiro,ruby,icarus back to (u)int(8,16,32,64)_t.
I'm slowly pushing for (u)int(8,16,32,64) to use my custom
Integer<Size>/Natural<Size> classes instead. But it's going to be one
hell of a struggle to get that into higan.
2016-02-16 09:11:58 +00:00
|
|
|
x = size == Byte ? (int8_t)x : (int16_t)x;
|
|
|
|
y = size == Byte ? (int8_t)y : (int16_t)y;
|
2016-02-03 10:24:58 +00:00
|
|
|
uint32 quotient = x / y;
|
|
|
|
uint32 remainder = x % y;
|
|
|
|
return (remainder & mask) << bits | (quotient & mask);
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::INC(Size size, uint16 x) -> uint16 {
|
2016-02-03 10:24:58 +00:00
|
|
|
uint16 result = (x + 1) & mask;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = (x & 0x0f) == 0x0f;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = result == sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::MUL(Size size, uint16 x, uint16 y) -> uint32 {
|
2016-02-03 10:24:58 +00:00
|
|
|
uint32 result = x * y;
|
|
|
|
r.f.c = result >> bits;
|
|
|
|
r.f.v = result >> bits;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::MULI(Size size, int16 x, int16 y) -> uint32 {
|
Update to v097r14 release.
byuu says:
This is a few days old, but oh well.
This WIP changes nall,hiro,ruby,icarus back to (u)int(8,16,32,64)_t.
I'm slowly pushing for (u)int(8,16,32,64) to use my custom
Integer<Size>/Natural<Size> classes instead. But it's going to be one
hell of a struggle to get that into higan.
2016-02-16 09:11:58 +00:00
|
|
|
x = size == Byte ? (int8_t)x : (int16_t)x;
|
|
|
|
y = size == Byte ? (int8_t)y : (int16_t)y;
|
2016-02-03 10:24:58 +00:00
|
|
|
uint32 result = x * y;
|
|
|
|
r.f.c = result >> bits;
|
|
|
|
r.f.v = result >> bits;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::NEG(Size size, uint16 x) -> uint16 {
|
2016-02-03 10:24:58 +00:00
|
|
|
uint16 result = (-x) & mask;
|
|
|
|
r.f.c = x;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = x & 0x0f;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = x == sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::NOT(Size size, uint16 x) -> uint16 {
|
2016-02-03 10:24:58 +00:00
|
|
|
uint16 result = (~x) & mask;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::OR(Size size, uint16 x, uint16 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = (x | y) & mask;
|
|
|
|
r.f.c = 0;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = 0;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::RCL(Size size, uint16 x, uint5 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = x;
|
|
|
|
for(uint n = 0; n < y; n++) {
|
|
|
|
bool carry = result & sign;
|
Update to v097r26 release.
byuu says:
Changelog:
- WS: fixed 8-bit sign-extended imul (fixes Star Hearts completely,
Final Fantasy world map)
- WS: fixed rcl/rcr carry shifting (fixes Crazy Climber, others)
- WS: added sound DMA emulation (Star Hearts rain sound for one example)
- WS: added OAM caching, but it's forced every line for now because
otherwise there are too many sprite glitches
- WS: use headphoneEnable bit instead of speakerEnable bit (fixes muted
audio in games)
- WS: various code cleanups (I/O mapping, audio channel naming, etc)
The hypervoice channel doesn't sound all that great just yet. But I'm
not sure how it's supposed to sound. I need a better example of some
more complex music.
What's left are some unknown register status bits (especially in the
sound area), keypad interrupts, RTC emulation, CPU prefetch emulation.
And then it's all just bugs. Lots and lots of bugs that need to be
fixed.
EDIT: oops, bad typo in the code.
ws/ppu/ppu.cpp line 20: change range(256) to range(224).
Also, delete the r.speed stuff from channel5.cpp to make the rain sound
a lot better in Star Hearts. Apparently that's outdated and not what the
bits really do.
2016-03-17 11:28:15 +00:00
|
|
|
result = (result << 1) | r.f.c;
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = carry;
|
|
|
|
}
|
|
|
|
r.f.v = (x ^ result) & sign;
|
|
|
|
return result & mask;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::RCR(Size size, uint16 x, uint5 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = x;
|
|
|
|
for(uint n = 0; n < y; n++) {
|
|
|
|
bool carry = result & 1;
|
Update to v097r26 release.
byuu says:
Changelog:
- WS: fixed 8-bit sign-extended imul (fixes Star Hearts completely,
Final Fantasy world map)
- WS: fixed rcl/rcr carry shifting (fixes Crazy Climber, others)
- WS: added sound DMA emulation (Star Hearts rain sound for one example)
- WS: added OAM caching, but it's forced every line for now because
otherwise there are too many sprite glitches
- WS: use headphoneEnable bit instead of speakerEnable bit (fixes muted
audio in games)
- WS: various code cleanups (I/O mapping, audio channel naming, etc)
The hypervoice channel doesn't sound all that great just yet. But I'm
not sure how it's supposed to sound. I need a better example of some
more complex music.
What's left are some unknown register status bits (especially in the
sound area), keypad interrupts, RTC emulation, CPU prefetch emulation.
And then it's all just bugs. Lots and lots of bugs that need to be
fixed.
EDIT: oops, bad typo in the code.
ws/ppu/ppu.cpp line 20: change range(256) to range(224).
Also, delete the r.speed stuff from channel5.cpp to make the rain sound
a lot better in Star Hearts. Apparently that's outdated and not what the
bits really do.
2016-03-17 11:28:15 +00:00
|
|
|
result = (r.f.c ? sign : 0) | (result >> 1);
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = carry;
|
|
|
|
}
|
|
|
|
r.f.v = (x ^ result) & sign;
|
|
|
|
return result & mask;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::ROL(Size size, uint16 x, uint4 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = (x << y) & (1 << bits);
|
|
|
|
uint16 result = ((x << y) | (x >> (bits - y))) & mask;
|
|
|
|
r.f.v = (x ^ result) & sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::ROR(Size size, uint16 x, uint4 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = (x >> (y - 1)) & 1;
|
|
|
|
uint16 result = ((x >> y) | (x << (bits - y))) & mask;
|
|
|
|
r.f.v = (x ^ result) & sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::SAL(Size size, uint16 x, uint5 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = (x << y) & (1 << bits);
|
|
|
|
uint16 result = (x << y) & mask;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::SAR(Size size, uint16 x, uint5 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
if(y & 16) {
|
|
|
|
r.f.c = x & sign;
|
|
|
|
return 0 - r.f.c;
|
|
|
|
}
|
|
|
|
r.f.c = (x >> (y - 1)) & 1;
|
|
|
|
uint16 result = (x >> y) & mask;
|
|
|
|
if(x & sign) result |= mask << (bits - y);
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::SBB(Size size, uint16 x, uint16 y) -> uint16 {
|
|
|
|
return SUB(size, x, y + r.f.c);
|
2016-02-02 10:51:17 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::SHL(Size size, uint16 x, uint5 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = (x << y) & (1 << bits);
|
|
|
|
uint16 result = (x << y) & mask;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = (x ^ result) & sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::SHR(Size size, uint16 x, uint5 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.c = (x >> (y - 1)) & 1;
|
|
|
|
uint16 result = (x >> y) & mask;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = (x ^ result) & sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::SUB(Size size, uint16 x, uint16 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = (x - y) & mask;
|
|
|
|
r.f.c = y > x;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = (uint4)y > (uint4)x;
|
|
|
|
r.f.z = result == 0;
|
|
|
|
r.f.s = result & sign;
|
|
|
|
r.f.v = (x ^ y) & (x ^ result) & sign;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-08-10 11:26:02 +00:00
|
|
|
auto V30MZ::XOR(Size size, uint16 x, uint16 y) -> uint16 {
|
2016-02-02 10:51:17 +00:00
|
|
|
uint16 result = (x ^ y) & mask;
|
2016-01-30 06:40:35 +00:00
|
|
|
r.f.c = 0;
|
|
|
|
r.f.p = parity(result);
|
|
|
|
r.f.h = 0;
|
|
|
|
r.f.z = result == 0;
|
2016-02-02 10:51:17 +00:00
|
|
|
r.f.s = result & sign;
|
2016-01-30 06:40:35 +00:00
|
|
|
r.f.v = 0;
|
|
|
|
return result;
|
|
|
|
}
|
2016-02-02 10:51:17 +00:00
|
|
|
|
|
|
|
#undef mask
|
|
|
|
#undef sign
|