diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 12e948e2..c4323867 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "104.07"; + static const string Version = "104.08"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/upd96050/instructions.cpp b/higan/processor/upd96050/instructions.cpp index c96ae148..da1774fa 100644 --- a/higan/processor/upd96050/instructions.cpp +++ b/higan/processor/upd96050/instructions.cpp @@ -31,7 +31,7 @@ auto uPD96050::execOP(uint24 opcode) -> void { case 4: idb = regs.dp; break; case 5: idb = regs.rp; break; case 6: idb = dataROM[regs.rp]; break; - case 7: idb = 0x8000 - regs.flaga.s1; break; + case 7: idb = 0x8000 - flags.a.s1; break; case 8: idb = regs.dr; regs.sr.rqm = 1; break; case 9: idb = regs.dr; break; case 10: idb = regs.sr; break; @@ -45,7 +45,7 @@ auto uPD96050::execOP(uint24 opcode) -> void { if(alu) { uint16 p, q, r; Flag flag; - bool c; + boolean c; switch(pselect) { case 0: p = dataRAM[regs.dp]; break; @@ -55,61 +55,83 @@ auto uPD96050::execOP(uint24 opcode) -> void { } switch(asl) { - case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break; - case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break; + case 0: q = regs.a; flag = flags.a; c = flags.b.c; break; + case 1: q = regs.b; flag = flags.b; c = flags.a.c; break; } switch(alu) { - case 1: r = q | p; break; //OR - case 2: r = q & p; break; //AND - case 3: r = q ^ p; break; //XOR - case 4: r = q - p; break; //SUB - case 5: r = q + p; break; //ADD - case 6: r = q - p - c; break; //SBB - case 7: r = q + p + c; break; //ADC - case 8: r = q - 1; p = 1; break; //DEC - case 9: r = q + 1; p = 1; break; //INC - case 10: r = ~q; break; //CMP - case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR) - case 12: r = (q << 1) | c; break; //SHL1 (ROL) - case 13: r = (q << 2) | 3; break; //SHL2 - case 14: r = (q << 4) | 15; break; //SHL4 - case 15: r = (q << 8) | (q >> 8); break; //XCHG + case 1: r = q | p; break; //OR + case 2: r = q & p; break; //AND + case 3: r = q ^ p; break; //XOR + case 4: r = q - p; break; //SUB + case 5: r = q + p; break; //ADD + case 6: r = q - p - c; break; //SBB + case 7: r = q + p + c; break; //ADC + case 8: r = q - 1; p = 1; break; //DEC + case 9: r = q + 1; p = 1; break; //INC + case 10: r = ~q; break; //CMP + case 11: r = q >> 1 | q & 0x8000; break; //SHR1 (ASR) + case 12: r = q << 1 | c; break; //SHL1 (ROL) + case 13: r = q << 2 | 3; break; //SHL2 + case 14: r = q << 4 | 15; break; //SHL4 + case 15: r = q << 8 | q >> 8; break; //XCHG } - flag.s0 = (r & 0x8000); - flag.z = (r == 0); + flag.s0 = r & 0x8000; + flag.z = r == 0; switch(alu) { - case 1: case 2: case 3: case 10: case 13: case 14: case 15: { + case 1: //OR + case 2: //AND + case 3: //XOR + case 10: //CMP + case 13: //SHL2 + case 14: //SHL4 + case 15: { //XCHG flag.c = 0; flag.ov0 = 0; flag.ov1 = 0; break; } - case 4: case 5: case 6: case 7: case 8: case 9: { + case 4: //SUB + case 5: //ADD + case 6: //SBB + case 7: //ADC + case 8: //DEC + case 9: { //INC + if(!flag.ov1) { + flag.s1 = flag.s0; + } + if(alu & 1) { //addition flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000; - flag.c = (r < q); + flag.c = r < q; } else { //subtraction flag.ov0 = (q ^ r) & (q ^ p) & 0x8000; - flag.c = (r > q); - } - if(flag.ov0) { - flag.s1 = flag.ov1 ^ !(r & 0x8000); - flag.ov1 = !flag.ov1; + flag.c = r > q; } + + //ovh[] = last three overflow flags (0 = most recent result) + flag.ovh[2] = flag.ovh[1]; + flag.ovh[1] = flag.ovh[0]; + flag.ovh[0] = flag.ov0; + + flag.ov1 = ( + (flag.ovh[0] ^ flag.ovh[1] ^ flag.ovh[2]) + | (flag.ovh[0] & !flag.ovh[1] & flag.ovh[2] & flag.s0 == flag.s1) + ); + break; } - case 11: { + case 11: { //SHR1 (ASR) flag.c = q & 1; flag.ov0 = 0; flag.ov1 = 0; break; } - case 12: { + case 12: { //SHL1 (ROL) flag.c = q >> 15; flag.ov0 = 0; flag.ov1 = 0; @@ -118,16 +140,16 @@ auto uPD96050::execOP(uint24 opcode) -> void { } switch(asl) { - case 0: regs.a = r; regs.flaga = flag; break; - case 1: regs.b = r; regs.flagb = flag; break; + case 0: regs.a = r; flags.a = flag; break; + case 1: regs.b = r; flags.b = flag; break; } } execLD((idb << 6) + dst); switch(dpl) { - case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC - case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC + case 1: regs.dp = (regs.dp & 0xf0) + (regs.dp + 1 & 0x0f); break; //DPINC + case 2: regs.dp = (regs.dp & 0xf0) + (regs.dp - 1 & 0x0f); break; //DPDEC case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR } @@ -146,46 +168,52 @@ auto uPD96050::execJP(uint24 opcode) -> void { uint11 na = opcode >> 2; //next address uint2 bank = opcode >> 0; //bank address - uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0); + uint14 jp = regs.pc & 0x2000 | bank << 11 | na << 0; switch(brch) { case 0x000: regs.pc = regs.so; return; //JMPSO - case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return; //JNCA - case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return; //JCA - case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return; //JNCB - case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return; //JCB + case 0x080: if(flags.a.c == 0) regs.pc = jp; return; //JNCA + case 0x082: if(flags.a.c == 1) regs.pc = jp; return; //JCA + case 0x084: if(flags.b.c == 0) regs.pc = jp; return; //JNCB + case 0x086: if(flags.b.c == 1) regs.pc = jp; return; //JCB - case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return; //JNZA - case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return; //JZA - case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return; //JNZB - case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return; //JZB + case 0x088: if(flags.a.z == 0) regs.pc = jp; return; //JNZA + case 0x08a: if(flags.a.z == 1) regs.pc = jp; return; //JZA + case 0x08c: if(flags.b.z == 0) regs.pc = jp; return; //JNZB + case 0x08e: if(flags.b.z == 1) regs.pc = jp; return; //JZB - case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return; //JNOVA0 - case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return; //JOVA0 - case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return; //JNOVB0 - case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return; //JOVB0 + case 0x090: if(flags.a.ov0 == 0) regs.pc = jp; return; //JNOVA0 + case 0x092: if(flags.a.ov0 == 1) regs.pc = jp; return; //JOVA0 + case 0x094: if(flags.b.ov0 == 0) regs.pc = jp; return; //JNOVB0 + case 0x096: if(flags.b.ov0 == 1) regs.pc = jp; return; //JOVB0 - case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return; //JNOVA1 - case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return; //JOVA1 - case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return; //JNOVB1 - case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return; //JOVB1 + case 0x098: if(flags.a.ov1 == 0) regs.pc = jp; return; //JNOVA1 + case 0x09a: if(flags.a.ov1 == 1) regs.pc = jp; return; //JOVA1 + case 0x09c: if(flags.b.ov1 == 0) regs.pc = jp; return; //JNOVB1 + case 0x09e: if(flags.b.ov1 == 1) regs.pc = jp; return; //JOVB1 - case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return; //JNSA0 - case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return; //JSA0 - case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return; //JNSB0 - case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return; //JSB0 + case 0x0a0: if(flags.a.s0 == 0) regs.pc = jp; return; //JNSA0 + case 0x0a2: if(flags.a.s0 == 1) regs.pc = jp; return; //JSA0 + case 0x0a4: if(flags.b.s0 == 0) regs.pc = jp; return; //JNSB0 + case 0x0a6: if(flags.b.s0 == 1) regs.pc = jp; return; //JSB0 - case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return; //JNSA1 - case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return; //JSA1 - case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return; //JNSB1 - case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return; //JSB1 + case 0x0a8: if(flags.a.s1 == 0) regs.pc = jp; return; //JNSA1 + case 0x0aa: if(flags.a.s1 == 1) regs.pc = jp; return; //JSA1 + case 0x0ac: if(flags.b.s1 == 0) regs.pc = jp; return; //JNSB1 + case 0x0ae: if(flags.b.s1 == 1) regs.pc = jp; return; //JSB1 case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return; //JDPL0 case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return; //JDPLN0 case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return; //JDPLF case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return; //JDPLNF + //serial input/output acknowledge not emulated + case 0x0b4: if(0) regs.pc = jp; return; //JNSIAK + case 0x0b6: if(0) regs.pc = jp; return; //JSIAK + case 0x0b8: if(0) regs.pc = jp; return; //JNSOAK + case 0x0ba: if(0) regs.pc = jp; return; //JSOAK + case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return; //JNRQM case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return; //JRQM @@ -209,7 +237,7 @@ auto uPD96050::execLD(uint24 opcode) -> void { case 4: regs.dp = id; break; case 5: regs.rp = id; break; case 6: regs.dr = id; regs.sr.rqm = 1; break; - case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break; + case 7: regs.sr = regs.sr & 0x907c | id & ~0x907c; break; case 8: regs.so = id; break; //LSB case 9: regs.so = id; break; //MSB case 10: regs.k = id; break; diff --git a/higan/processor/upd96050/serialization.cpp b/higan/processor/upd96050/serialization.cpp index 5accd126..86f82cc2 100644 --- a/higan/processor/upd96050/serialization.cpp +++ b/higan/processor/upd96050/serialization.cpp @@ -1,27 +1,50 @@ auto uPD96050::serialize(serializer& s) -> void { s.array(dataRAM); - - s.array(regs.stack); - s.integer(regs.pc); - s.integer(regs.rp); - s.integer(regs.dp); - s.integer(regs.sp); - - s.integer(regs.k); - s.integer(regs.l); - s.integer(regs.m); - s.integer(regs.n); - s.integer(regs.a); - s.integer(regs.b); - - s.integer(regs.flaga.data); - s.integer(regs.flagb.data); - - s.integer(regs.tr); - s.integer(regs.trb); - - s.integer(regs.sr.data); - s.integer(regs.dr); - s.integer(regs.si); - s.integer(regs.so); + regs.serialize(s); + flags.a.serialize(s); + flags.b.serialize(s); +} + +auto uPD96050::Flag::serialize(serializer& s) -> void { + s.boolean(ov0); + s.boolean(ov1); + s.boolean(z); + s.boolean(c); + s.boolean(s0); + s.boolean(s1); + s.array(ovh); +} + +auto uPD96050::Status::serialize(serializer& s) -> void { + s.boolean(p0); + s.boolean(p1); + s.boolean(ei); + s.boolean(sic); + s.boolean(soc); + s.boolean(drc); + s.boolean(dma); + s.boolean(drs); + s.boolean(uf0); + s.boolean(uf1); + s.boolean(rqm); +} + +auto uPD96050::Registers::serialize(serializer& s) -> void { + s.array(stack); + s.integer(pc); + s.integer(rp); + s.integer(dp); + s.integer(sp); + s.integer(si); + s.integer(so); + s.integer(k); + s.integer(l); + s.integer(m); + s.integer(n); + s.integer(a); + s.integer(b); + s.integer(tr); + s.integer(trb); + s.integer(dr); + sr.serialize(s); } diff --git a/higan/processor/upd96050/upd96050.cpp b/higan/processor/upd96050/upd96050.cpp index 7fc54e23..a2bffa39 100644 --- a/higan/processor/upd96050/upd96050.cpp +++ b/higan/processor/upd96050/upd96050.cpp @@ -32,14 +32,14 @@ auto uPD96050::power() -> void { regs.n = 0x0000; regs.a = 0x0000; regs.b = 0x0000; - regs.flaga = 0x00; - regs.flagb = 0x00; regs.tr = 0x0000; regs.trb = 0x0000; - regs.sr = 0x0000; regs.dr = 0x0000; regs.si = 0x0000; regs.so = 0x0000; + + flags.a = 0x0000; + flags.b = 0x0000; } } diff --git a/higan/processor/upd96050/upd96050.hpp b/higan/processor/upd96050/upd96050.hpp index c6d0da96..10204502 100644 --- a/higan/processor/upd96050/upd96050.hpp +++ b/higan/processor/upd96050/upd96050.hpp @@ -1,4 +1,3 @@ -//NEC uPD7720 (not supported) //NEC uPD7725 //NEC uPD96050 @@ -33,62 +32,95 @@ struct uPD96050 { uint16 dataRAM[2048]; struct Flag { - union { - uint8_t data = 0; - BooleanBitField s1; - BooleanBitField s0; - BooleanBitField c; - BooleanBitField z; - BooleanBitField ov1; - BooleanBitField ov0; - }; + inline operator uint() const { + return ov0 << 0 | ov1 << 1 | z << 2 | c << 3 | s0 << 4 | s1 << 5; + } - inline operator uint() const { return data & 0x3f; } - inline auto& operator=(uint value) { return data = value, *this; } - inline auto& operator=(const Flag& value) { return data = value.data, *this; } + inline auto operator=(uint16 data) -> Flag& { + ov0 = data.bit(0); + ov1 = data.bit(1); + z = data.bit(2); + c = data.bit(3); + s0 = data.bit(4); + s1 = data.bit(5); + return *this; + } + + auto serialize(serializer&) -> void; + + boolean ov0; //overflow 0 + boolean ov1; //overflow 1 + boolean z; //zero + boolean c; //carry + boolean s0; //sign 0 + boolean s1; //sign 1 + + boolean ovh[3]; //overflow history (internal) }; struct Status { - union { - uint16_t data = 0; - BooleanBitField rqm; - BooleanBitField usf1; - BooleanBitField usf0; - BooleanBitField drs; - BooleanBitField dma; - BooleanBitField drc; - BooleanBitField soc; - BooleanBitField sic; - BooleanBitField ei; - BooleanBitField p1; - BooleanBitField p0; - }; + inline operator uint() const { + bool _drs = drs & !drc; //when DRC=1, DRS=0 + return p0 << 0 | p1 << 1 | ei << 7 | sic << 8 | soc << 9 | drc << 10 + | dma << 11 | _drs << 12 | uf0 << 13 | uf1 << 14 | rqm << 15; + } - inline operator uint() const { return data & 0xff83; } - inline auto& operator=(uint value) { return data = value, *this; } + inline auto operator=(uint16 data) -> Status& { + p0 = data.bit( 0); + p1 = data.bit( 1); + ei = data.bit( 7); + sic = data.bit( 8); + soc = data.bit( 9); + drc = data.bit(10); + dma = data.bit(11); + drs = data.bit(12); + uf0 = data.bit(13); + uf1 = data.bit(14); + rqm = data.bit(15); + return *this; + } + + auto serialize(serializer&) -> void; + + boolean p0; //output port 0 + boolean p1; //output port 1 + boolean ei; //enable interrupts + boolean sic; //serial input control (0 = 16-bit; 1 = 8-bit) + boolean soc; //serial output control (0 = 16-bit; 1 = 8-bit) + boolean drc; //data register size (0 = 16-bit; 1 = 8-bit) + boolean dma; //data register DMA mode + boolean drs; //data register status (1 = active; 0 = stopped) + boolean uf0; //user flag 0 + boolean uf1; //user flag 1 + boolean rqm; //request mode (=1 on internal access; =0 on external access) }; - struct Regs { + struct Registers { + auto serialize(serializer&) -> void; + uint16 stack[16]; //LIFO VariadicNatural pc; //program counter VariadicNatural rp; //ROM pointer VariadicNatural dp; //data pointer uint4 sp; //stack pointer + uint16 si; //serial input + uint16 so; //serial output int16 k; int16 l; int16 m; int16 n; int16 a; //accumulator int16 b; //accumulator - Flag flaga; - Flag flagb; uint16 tr; //temporary register uint16 trb; //temporary register - Status sr; //status register uint16 dr; //data register - uint16 si; - uint16 so; + Status sr; //status register } regs; + + struct Flags { + Flag a; + Flag b; + } flags; }; } diff --git a/higan/target-tomoko/settings/audio.cpp b/higan/target-tomoko/settings/audio.cpp index eba96f0c..110a44ef 100644 --- a/higan/target-tomoko/settings/audio.cpp +++ b/higan/target-tomoko/settings/audio.cpp @@ -57,7 +57,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { auto AudioSettings::updateDevice() -> void { frequencyList.reset(); for(auto& frequency : audio->availableFrequencies()) { - frequencyList.append(ComboButtonItem().setText(frequency)); + frequencyList.append(ComboButtonItem().setText((uint)frequency)); if(frequency == settings["Audio/Frequency"].real()) { frequencyList.item(frequencyList.itemCount() - 1).setSelected(); } diff --git a/higan/target-tomoko/settings/settings.hpp b/higan/target-tomoko/settings/settings.hpp index 3825d291..61e742d3 100644 --- a/higan/target-tomoko/settings/settings.hpp +++ b/higan/target-tomoko/settings/settings.hpp @@ -48,9 +48,9 @@ struct AudioSettings : TabFrameItem { Label deviceLabel{&controlLayout, Size{0, 0}}; ComboButton deviceList{&controlLayout, Size{~0, 0}}; Label frequencyLabel{&controlLayout, Size{0, 0}}; - ComboButton frequencyList{&controlLayout, Size{~0, 0}}; + ComboButton frequencyList{&controlLayout, Size{80, 0}}; Label latencyLabel{&controlLayout, Size{0, 0}}; - ComboButton latencyList{&controlLayout, Size{~0, 0}}; + ComboButton latencyList{&controlLayout, Size{80, 0}}; CheckLabel exclusiveMode{&layout, Size{~0, 0}}; Label effectsLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout volumeLayout{&layout, Size{~0, 0}};