mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-04-02 10:42:14 -04:00
This represents a major code restructuring. The dot-based and scanline-based renderers are now split into two separate core libraries, asnes and bsnes. For now at least, these are -internal- names. I'm not entirely decided on how I'm going to handle releasing these two separate builds. Regardless, the folders need names. asnes has had all of the processor subfolders collapsed back into their parent folders. In other words, ppu's functions were moved into ppu/sppu, and then ppu was deleted, and then ppu/sppu became the new ppu. Repeat this for the cpu, smp and dsp and there you go. asnes/dsp also removed the DSP_STATE_MACHINE option. This was done for the sake of consistency with the rest of the core. asnes' debugger mode is currently extremely broken, but I will be fixing it in time. And for now, bsnes has kept the processor abstraction layer. I may keep it around, not sure yet. It doesn't hurt speed or anything, so I'm not too worried about making a decision right away. I may throw snesfilter, snesreader and supergameboy into this folder, just to have everything in one place. The alternate GUI forks are definitely going in there as dotnet, cocoa and python. Compiled output goes to the out/ folder now, to prevent conflicts with a file and folder named bsnes, for instance.
344 lines
11 KiB
C++
344 lines
11 KiB
C++
#ifdef SYSTEM_CPP
|
|
|
|
Input input;
|
|
|
|
uint8 Input::port_read(bool portnumber) {
|
|
if(cartridge.has_serial() && portnumber == 1) {
|
|
return serial.latch();
|
|
}
|
|
|
|
port_t &p = port[portnumber];
|
|
|
|
switch(p.device) {
|
|
case Device::Joypad: {
|
|
if(cpu.joylatch() == 0) {
|
|
if(p.counter0 >= 16) return 1;
|
|
return system.interface->input_poll(portnumber, p.device, 0, p.counter0++);
|
|
} else {
|
|
return system.interface->input_poll(portnumber, p.device, 0, 0);
|
|
}
|
|
} //case Device::Joypad
|
|
|
|
case Device::Multitap: {
|
|
if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0
|
|
|
|
unsigned deviceidx, deviceindex0, deviceindex1;
|
|
uint8 mask = (portnumber == 0 ? 0x40 : 0x80);
|
|
|
|
if(cpu.pio() & mask) {
|
|
deviceidx = p.counter0;
|
|
if(deviceidx >= 16) return 3;
|
|
p.counter0++;
|
|
|
|
deviceindex0 = 0; //controller 1
|
|
deviceindex1 = 1; //controller 2
|
|
} else {
|
|
deviceidx = p.counter1;
|
|
if(deviceidx >= 16) return 3;
|
|
p.counter1++;
|
|
|
|
deviceindex0 = 2; //controller 3
|
|
deviceindex1 = 3; //controller 4
|
|
}
|
|
|
|
return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0)
|
|
| (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1);
|
|
} //case Device::Multitap
|
|
|
|
case Device::Mouse: {
|
|
if(p.counter0 >= 32) return 1;
|
|
|
|
int position_x = system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::X); //-n = left, 0 = center, +n = right
|
|
int position_y = system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Y); //-n = up, 0 = center, +n = right
|
|
|
|
bool direction_x = position_x < 0; //0 = right, 1 = left
|
|
bool direction_y = position_y < 0; //0 = down, 1 = up
|
|
|
|
if(position_x < 0) position_x = -position_x; //abs(position_x)
|
|
if(position_y < 0) position_y = -position_y; //abs(position_x)
|
|
|
|
position_x = min(127, position_x); //range = 0 - 127
|
|
position_y = min(127, position_y); //range = 0 - 127
|
|
|
|
switch(p.counter0++) { default:
|
|
case 0: return 0;
|
|
case 1: return 0;
|
|
case 2: return 0;
|
|
case 3: return 0;
|
|
case 4: return 0;
|
|
case 5: return 0;
|
|
case 6: return 0;
|
|
case 7: return 0;
|
|
|
|
case 8: return system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Right);
|
|
case 9: return system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Left);
|
|
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
|
|
case 11: return 0; // ||
|
|
|
|
case 12: return 0; //signature
|
|
case 13: return 0; // ||
|
|
case 14: return 0; // ||
|
|
case 15: return 1; // ||
|
|
|
|
case 16: return (direction_y) & 1;
|
|
case 17: return (position_y >> 6) & 1;
|
|
case 18: return (position_y >> 5) & 1;
|
|
case 19: return (position_y >> 4) & 1;
|
|
case 20: return (position_y >> 3) & 1;
|
|
case 21: return (position_y >> 2) & 1;
|
|
case 22: return (position_y >> 1) & 1;
|
|
case 23: return (position_y >> 0) & 1;
|
|
|
|
case 24: return (direction_x) & 1;
|
|
case 25: return (position_x >> 6) & 1;
|
|
case 26: return (position_x >> 5) & 1;
|
|
case 27: return (position_x >> 4) & 1;
|
|
case 28: return (position_x >> 3) & 1;
|
|
case 29: return (position_x >> 2) & 1;
|
|
case 30: return (position_x >> 1) & 1;
|
|
case 31: return (position_x >> 0) & 1;
|
|
}
|
|
} //case Device::Mouse
|
|
|
|
case Device::SuperScope: {
|
|
if(portnumber == 0) break; //Super Scope in port 1 not supported ...
|
|
if(p.counter0 >= 8) return 1;
|
|
|
|
if(p.counter0 == 0) {
|
|
//turbo is a switch; toggle is edge sensitive
|
|
bool turbo = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Turbo);
|
|
if(turbo && !p.superscope.turbolock) {
|
|
p.superscope.turbo = !p.superscope.turbo; //toggle state
|
|
p.superscope.turbolock = true;
|
|
} else if(!turbo) {
|
|
p.superscope.turbolock = false;
|
|
}
|
|
|
|
//trigger is a button
|
|
//if turbo is active, trigger is level sensitive; otherwise it is edge sensitive
|
|
p.superscope.trigger = false;
|
|
bool trigger = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Trigger);
|
|
if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) {
|
|
p.superscope.trigger = true;
|
|
p.superscope.triggerlock = true;
|
|
} else if(!trigger) {
|
|
p.superscope.triggerlock = false;
|
|
}
|
|
|
|
//cursor is a button; it is always level sensitive
|
|
p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Cursor);
|
|
|
|
//pause is a button; it is always edge sensitive
|
|
p.superscope.pause = false;
|
|
bool pause = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Pause);
|
|
if(pause && !p.superscope.pauselock) {
|
|
p.superscope.pause = true;
|
|
p.superscope.pauselock = true;
|
|
} else if(!pause) {
|
|
p.superscope.pauselock = false;
|
|
}
|
|
|
|
p.superscope.offscreen =
|
|
p.superscope.x < 0 || p.superscope.x >= 256
|
|
|| p.superscope.y < 0 || p.superscope.y >= (ppu.overscan() ? 240 : 225);
|
|
}
|
|
|
|
switch(p.counter0++) {
|
|
case 0: return p.superscope.trigger;
|
|
case 1: return p.superscope.cursor;
|
|
case 2: return p.superscope.turbo;
|
|
case 3: return p.superscope.pause;
|
|
case 4: return 0;
|
|
case 5: return 0;
|
|
case 6: return p.superscope.offscreen;
|
|
case 7: return 0; //noise (1 = yes)
|
|
}
|
|
} //case Device::SuperScope
|
|
|
|
case Device::Justifier:
|
|
case Device::Justifiers: {
|
|
if(portnumber == 0) break; //Justifier in port 1 not supported ...
|
|
if(p.counter0 >= 32) return 1;
|
|
|
|
if(p.counter0 == 0) {
|
|
p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Trigger);
|
|
p.justifier.start1 = system.interface->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Start);
|
|
|
|
if(p.device == Device::Justifiers) {
|
|
p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Trigger);
|
|
p.justifier.start2 = system.interface->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Start);
|
|
} else {
|
|
p.justifier.x2 = -1;
|
|
p.justifier.y2 = -1;
|
|
|
|
p.justifier.trigger2 = false;
|
|
p.justifier.start2 = false;
|
|
}
|
|
}
|
|
|
|
switch(p.counter0++) {
|
|
case 0: return 0;
|
|
case 1: return 0;
|
|
case 2: return 0;
|
|
case 3: return 0;
|
|
case 4: return 0;
|
|
case 5: return 0;
|
|
case 6: return 0;
|
|
case 7: return 0;
|
|
case 8: return 0;
|
|
case 9: return 0;
|
|
case 10: return 0;
|
|
case 11: return 0;
|
|
|
|
case 12: return 1; //signature
|
|
case 13: return 1; // ||
|
|
case 14: return 1; // ||
|
|
case 15: return 0; // ||
|
|
|
|
case 16: return 0;
|
|
case 17: return 1;
|
|
case 18: return 0;
|
|
case 19: return 1;
|
|
case 20: return 0;
|
|
case 21: return 1;
|
|
case 22: return 0;
|
|
case 23: return 1;
|
|
|
|
case 24: return p.justifier.trigger1;
|
|
case 25: return p.justifier.trigger2;
|
|
case 26: return p.justifier.start1;
|
|
case 27: return p.justifier.start2;
|
|
case 28: return p.justifier.active;
|
|
|
|
case 29: return 0;
|
|
case 30: return 0;
|
|
case 31: return 0;
|
|
}
|
|
} //case Device::Justifier(s)
|
|
} //switch(p.device)
|
|
|
|
//no device connected
|
|
return 0;
|
|
}
|
|
|
|
//scan all input; update cursor positions if needed
|
|
void Input::update() {
|
|
system.interface->input_poll();
|
|
port_t &p = port[1];
|
|
|
|
switch(p.device) {
|
|
case Device::SuperScope: {
|
|
int x = system.interface->input_poll(1, p.device, 0, (unsigned)SuperScopeID::X);
|
|
int y = system.interface->input_poll(1, p.device, 0, (unsigned)SuperScopeID::Y);
|
|
x += p.superscope.x;
|
|
y += p.superscope.y;
|
|
p.superscope.x = max(-16, min(256 + 16, x));
|
|
p.superscope.y = max(-16, min(240 + 16, y));
|
|
|
|
latchx = p.superscope.x;
|
|
latchy = p.superscope.y;
|
|
} break;
|
|
|
|
case Device::Justifier:
|
|
case Device::Justifiers: {
|
|
int x1 = system.interface->input_poll(1, p.device, 0, (unsigned)JustifierID::X);
|
|
int y1 = system.interface->input_poll(1, p.device, 0, (unsigned)JustifierID::Y);
|
|
x1 += p.justifier.x1;
|
|
y1 += p.justifier.y1;
|
|
p.justifier.x1 = max(-16, min(256 + 16, x1));
|
|
p.justifier.y1 = max(-16, min(240 + 16, y1));
|
|
|
|
int x2 = system.interface->input_poll(1, p.device, 1, (unsigned)JustifierID::X);
|
|
int y2 = system.interface->input_poll(1, p.device, 1, (unsigned)JustifierID::Y);
|
|
x2 += p.justifier.x2;
|
|
y2 += p.justifier.y2;
|
|
p.justifier.x2 = max(-16, min(256 + 16, x2));
|
|
p.justifier.y2 = max(-16, min(240 + 16, y2));
|
|
|
|
if(p.justifier.active == 0) {
|
|
latchx = p.justifier.x1;
|
|
latchy = p.justifier.y1;
|
|
} else {
|
|
latchx = (p.device == Device::Justifiers ? p.justifier.x2 : -1);
|
|
latchy = (p.device == Device::Justifiers ? p.justifier.y2 : -1);
|
|
}
|
|
} break;
|
|
}
|
|
|
|
if(latchy < 0 || latchy >= (ppu.overscan() ? 240 : 225) || latchx < 0 || latchx >= 256) {
|
|
//cursor is offscreen, set to invalid position so counters are not latched
|
|
latchx = ~0;
|
|
latchy = ~0;
|
|
} else {
|
|
//cursor is onscreen
|
|
latchx += 40; //offset trigger position to simulate hardware latching delay
|
|
latchx <<= 2; //dot -> clock conversion
|
|
latchx += 2; //align trigger on half-dot ala interrupts (speed optimization for sCPU::add_clocks)
|
|
}
|
|
}
|
|
|
|
void Input::port_set_device(bool portnumber, Device device) {
|
|
port_t &p = port[portnumber];
|
|
|
|
p.device = device;
|
|
p.counter0 = 0;
|
|
p.counter1 = 0;
|
|
|
|
//set iobit to true if device is capable of latching PPU counters
|
|
iobit = port[1].device == Device::SuperScope
|
|
|| port[1].device == Device::Justifier
|
|
|| port[1].device == Device::Justifiers;
|
|
latchx = -1;
|
|
latchy = -1;
|
|
|
|
if(device == Device::SuperScope) {
|
|
p.superscope.x = 256 / 2;
|
|
p.superscope.y = 240 / 2;
|
|
|
|
p.superscope.trigger = false;
|
|
p.superscope.cursor = false;
|
|
p.superscope.turbo = false;
|
|
p.superscope.pause = false;
|
|
p.superscope.offscreen = false;
|
|
|
|
p.superscope.turbolock = false;
|
|
p.superscope.triggerlock = false;
|
|
p.superscope.pauselock = false;
|
|
} else if(device == Device::Justifier) {
|
|
p.justifier.active = 0;
|
|
p.justifier.x1 = 256 / 2;
|
|
p.justifier.y1 = 240 / 2;
|
|
p.justifier.x2 = -1;
|
|
p.justifier.y2 = -1;
|
|
|
|
p.justifier.trigger1 = false;
|
|
p.justifier.trigger2 = false;
|
|
p.justifier.start1 = false;
|
|
p.justifier.start2 = false;
|
|
} else if(device == Device::Justifiers) {
|
|
p.justifier.active = 0;
|
|
p.justifier.x1 = 256 / 2 - 16;
|
|
p.justifier.y1 = 240 / 2;
|
|
p.justifier.x2 = 256 / 2 + 16;
|
|
p.justifier.y2 = 240 / 2;
|
|
|
|
p.justifier.trigger1 = false;
|
|
p.justifier.trigger2 = false;
|
|
p.justifier.start1 = false;
|
|
p.justifier.start2 = false;
|
|
}
|
|
}
|
|
|
|
void Input::poll() {
|
|
port[0].counter0 = 0;
|
|
port[0].counter1 = 0;
|
|
port[1].counter0 = 0;
|
|
port[1].counter1 = 0;
|
|
|
|
port[1].justifier.active = !port[1].justifier.active;
|
|
}
|
|
|
|
void Input::init() {
|
|
}
|
|
|
|
#endif
|