patching together more mouse work

This commit is contained in:
Jorj Bauer 2021-01-10 23:52:58 -05:00
parent b09df8e5f9
commit 0b8e027096
10 changed files with 196 additions and 78 deletions

View File

@ -8,17 +8,17 @@ CXXFLAGS=-Wall -I/usr/include/SDL2 -I .. -I . -I apple -I nix -I sdl -I/usr/loca
TSRC=cpu.cpp util/testharness.cpp TSRC=cpu.cpp util/testharness.cpp
COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp apple/mouse.c
COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o apple/pia6821.o COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o
FBSRCS=linuxfb/linux-speaker.cpp linuxfb/fb-display.cpp linuxfb/linux-keyboard.cpp linuxfb/fb-paddles.cpp nix/nix-filemanager.cpp linuxfb/aiie.cpp linuxfb/linux-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp FBSRCS=linuxfb/linux-speaker.cpp linuxfb/fb-display.cpp linuxfb/linux-keyboard.cpp linuxfb/fb-paddles.cpp nix/nix-filemanager.cpp linuxfb/aiie.cpp linuxfb/linux-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp
FBOBJS=linuxfb/linux-speaker.o linuxfb/fb-display.o linuxfb/linux-keyboard.o linuxfb/fb-paddles.o nix/nix-filemanager.o linuxfb/aiie.o linuxfb/linux-printer.o nix/nix-clock.o nix/nix-prefs.o FBOBJS=linuxfb/linux-speaker.o linuxfb/fb-display.o linuxfb/linux-keyboard.o linuxfb/fb-paddles.o nix/nix-filemanager.o linuxfb/aiie.o linuxfb/linux-printer.o nix/nix-clock.o nix/nix-prefs.o
SDLSRCS=sdl/sdl-speaker.cpp sdl/sdl-display.cpp sdl/sdl-keyboard.cpp sdl/sdl-paddles.cpp nix/nix-filemanager.cpp sdl/aiie.cpp sdl/sdl-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp nix/debugger.cpp nix/disassembler.cpp SDLSRCS=sdl/sdl-speaker.cpp sdl/sdl-display.cpp sdl/sdl-keyboard.cpp sdl/sdl-paddles.cpp nix/nix-filemanager.cpp sdl/aiie.cpp sdl/sdl-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp nix/debugger.cpp nix/disassembler.cpp sdl/sdl-mouse.cpp
SDLOBJS=sdl/sdl-speaker.o sdl/sdl-display.o sdl/sdl-keyboard.o sdl/sdl-paddles.o nix/nix-filemanager.o sdl/aiie.o sdl/sdl-printer.o nix/nix-clock.o nix/nix-prefs.o nix/debugger.o nix/disassembler.o SDLOBJS=sdl/sdl-speaker.o sdl/sdl-display.o sdl/sdl-keyboard.o sdl/sdl-paddles.o nix/nix-filemanager.o sdl/aiie.o sdl/sdl-printer.o nix/nix-clock.o nix/nix-prefs.o nix/debugger.o nix/disassembler.o sdl/sdl-mouse.o
ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h apple/hd32-rom.h MouseInterface.rom ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h apple/hd32-rom.h MouseInterface.rom

View File

@ -5,6 +5,7 @@
#include "mouse-rom.h" #include "mouse-rom.h"
enum { enum {
SW_W_INIT = 0x00,
SW_R_HOMEMOUSE = 0x08, SW_R_HOMEMOUSE = 0x08,
SW_R_POSMOUSE = 0x09, SW_R_POSMOUSE = 0x09,
SW_R_CLEARMOUSE = 0x0A, SW_R_CLEARMOUSE = 0x0A,
@ -15,6 +16,11 @@ enum {
SW_W_SETMOUSE = 0x0F SW_W_SETMOUSE = 0x0F
}; };
// The first 3 soft switch bits technically should pass directly to
// the PIA6821. In practice, so far, I've only seen the first (SW_W_INIT)
// used when PR#4 is invoked to initialize the mouse interface from DOS,
// so for the moment I'll just catch that specifically.
enum { enum {
ST_MOUSEENABLE = 1, ST_MOUSEENABLE = 1,
ST_INTMOUSE = 2, ST_INTMOUSE = 2,
@ -26,6 +32,8 @@ Mouse::Mouse()
{ {
status = 0; status = 0;
interruptsTriggered = 0; interruptsTriggered = 0;
lastX = lastY = 0;
lastButton = false;
} }
Mouse::~Mouse() Mouse::~Mouse()
@ -50,29 +58,43 @@ uint8_t Mouse::readSwitches(uint8_t s)
{ {
switch (s) { switch (s) {
case SW_R_HOMEMOUSE: case SW_R_HOMEMOUSE:
printf("unimplemented SW_R_HOMEMOUSE\n"); g_mouse->setPosition( (g_ram.readByte(0x578) << 8) | g_ram.readByte(0x478),
/* physical mouse X = $578/$478; (g_ram.readByte(0x5F8) << 8) | g_ram.readByte(0x4F8)
* physical mouse Y = $5f8/$4f8 */ );
break; break;
case SW_R_POSMOUSE: case SW_R_POSMOUSE:
printf("unimplemented SW_R_POSMOUSE\n"); g_mouse->setPosition( (g_ram.readByte(0x578+4) << 8) | g_ram.readByte(0x478+4),
/* physical mouse X = $578+4/$478+4; (g_ram.readByte(0x5F8+4) << 8) | g_ram.readByte(0x4F8+4)
* physical mouse Y + $5F8+4/$4f8+4 */ );
break; break;
case SW_R_CLEARMOUSE: case SW_R_CLEARMOUSE:
g_ram.writeByte(0x578+4, 0); g_ram.writeByte(0x578+4, 0);
g_ram.writeByte(0x478+4, 0); g_ram.writeByte(0x478+4, 0);
g_ram.writeByte(0x5F8+4, 0); g_ram.writeByte(0x5F8+4, 0);
g_ram.writeByte(0x4F8+4, 0); g_ram.writeByte(0x4F8+4, 0);
/* physical mouse X = Y = 0 */ g_mouse->setPosition(0,0);
break; break;
case SW_R_READMOUSE: case SW_R_READMOUSE:
printf("unimplemented SW_R_READMOUSE\n"); {
// FIXME: read from physical mouse and write to: uint16_t xpos, ypos;
g_ram.writeByte(0x578+4, 0); // high X g_mouse->getPosition(&xpos, &ypos);
g_ram.writeByte(0x478+4, 0); // low X if (lastX != xpos || lastY != ypos) {
g_ram.writeByte(0x5F8+4, 0); // high Y interruptsTriggered |= 0x20; // "x or y changed since last reading"
g_ram.writeByte(0x4F8+4, 0); // low Y lastX = xpos; lastY = ypos;
}
curButton = g_mouse->getButton();
uint8_t newStatus = g_ram.readByte(0x778+4) & ~0xC0;
if (curButton) { newStatus |= 0x80; };
if (lastButton) { newStatus |= 0x40; };
uint16_t xv = xpos >> 8; xv &= 0xFF;
printf("XPOS: %d => 0x%X 0x%X\n", xpos, xv, xpos & 0xFF);
g_ram.writeByte(0x578+4, xv); // high X
g_ram.writeByte(0x478+4, xpos & 0xFF); // low X
g_ram.writeByte(0x5F8+4, (ypos >> 8) & 0xFF); // high Y
g_ram.writeByte(0x4F8+4, ypos); // low Y
}
break; break;
case SW_R_INITMOUSE: case SW_R_INITMOUSE:
// Set clamp to (0,0) - (1023,1023) // Set clamp to (0,0) - (1023,1023)
@ -80,11 +102,15 @@ uint8_t Mouse::readSwitches(uint8_t s)
g_ram.writeByte(0x478, 0); // low of lowclamp g_ram.writeByte(0x478, 0); // low of lowclamp
g_ram.writeByte(0x5F8, 0x03); // high of highclamp g_ram.writeByte(0x5F8, 0x03); // high of highclamp
g_ram.writeByte(0x4F8, 0xFF); // low of highclamp g_ram.writeByte(0x4F8, 0xFF); // low of highclamp
printf("unimplemented SW_R_INITMOUSE\n"); g_mouse->setClamp(XCLAMP, 0, 1023);
/* physicalMouse->setClamp(XCLAMP, 0, 1023); g_mouse->setClamp(YCLAMP, 0, 1023);
* physicalMouse->setClamp(YCLAMP, 0, 1023); */
break; break;
case SW_R_SERVEMOUSE: case SW_R_SERVEMOUSE:
if (lastButton) interruptsTriggered |= 0x40;
if (curButton != lastButton) {
interruptsTriggered |= 0x80;
lastButton = curButton;
}
g_ram.writeByte(0x778+4, interruptsTriggered); g_ram.writeByte(0x778+4, interruptsTriggered);
g_ram.writeByte(0x6B8+4, interruptsTriggered); // hack to appease ROM g_ram.writeByte(0x6B8+4, interruptsTriggered); // hack to appease ROM
interruptsTriggered = 0; interruptsTriggered = 0;
@ -98,25 +124,30 @@ uint8_t Mouse::readSwitches(uint8_t s)
void Mouse::writeSwitches(uint8_t s, uint8_t v) void Mouse::writeSwitches(uint8_t s, uint8_t v)
{ {
switch (s) { switch (s) {
case SW_W_INIT:
v &= 0x03; // just the low 3 bits apparently?
printf("Simple init: value is 0x%X\n", v);
status = v;
g_ram.writeByte(0x7f8 + 4, v);
break;
case SW_W_CLAMPMOUSE: case SW_W_CLAMPMOUSE:
{ {
uint16_t lowval = (g_ram.readByte(0x578) << 8) | (g_ram.readByte(0x478)); uint16_t lowval = (g_ram.readByte(0x578) << 8) | (g_ram.readByte(0x478));
uint16_t highval = (g_ram.readByte(0x5F8) << 8) | (g_ram.readByte(0x4F8)); uint16_t highval = (g_ram.readByte(0x5F8) << 8) | (g_ram.readByte(0x4F8));
if (v) { if (v) {
// Y is clamping g_mouse->setClamp(YCLAMP, lowval, highval);
/* physicalMouse->setClamp(YCLAMP, lowval, highval); */
} else { } else {
// X is clamping // X is clamping
/* physicalMouse->setClamp(XCLAMP, lowval, highval); */ g_mouse->setClamp(XCLAMP, lowval, highval);
} }
printf("unimplemented SW_W_CLAMPMOUSE [0x%X]\n", v);
} }
break; break;
case SW_W_SETMOUSE: case SW_W_SETMOUSE:
status = v; status = v;
g_ram.writeByte(0x7f8 + 4, v);
break; break;
default: default:
printf("mouse: unknown switch write 0x%X\n", s); printf("mouse: unknown switch write 0x%X = 0x%2X\n", s, v);
break; break;
} }
} }
@ -125,7 +156,7 @@ void Mouse::loadROM(uint8_t *toWhere)
{ {
/* Actual mouse ROM Disassembly: /* Actual mouse ROM Disassembly:
C400- 2C 58 FF BIT $FF58 ; test bits in FF58 w/ A C400- 2C 58 FF BIT $FF58 ; test bits in FF58 w/ A
C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $20 on boot-up C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $60 on boot-up (RTS), which has $40 set, so should branch here
C405- 38 SEC C405- 38 SEC
C406- 90 18 BCC $C420 ; no-op; unless called @ $C406 directly? C406- 90 18 BCC $C420 ; no-op; unless called @ $C406 directly?
@ -154,13 +185,12 @@ C41D- AE
C41E- AE C41E- AE
C41F- AE C41F- AE
; Main ; Main (installs KSW for IN# handling)
C420- 48 PHA ; push accumulator to stack C420- 48 PHA ; push accumulator to stack
C421- 98 TYA C421- 98 TYA
C422- 48 PHA ; push Y to stack C422- 48 PHA ; push Y to stack
C423- 8A TXA C423- 8A TXA
C424- 48 PHA ; push X to stack C424- 48 PHA ; push X to stack
C424- 48 PHA
C425- 08 PHP ; push status to stack C425- 08 PHP ; push status to stack
C426- 78 SEI ; disable interrupts C426- 78 SEI ; disable interrupts
@ -176,28 +206,30 @@ C426- 78 SEI ; disable interrupts
; TSX ; TSX
; LDA $100, X ; grab the return address off the stack ; LDA $100, X ; grab the return address off the stack
C427- 20 58 FF JSR $FF58 C427- 20 58 FF JSR $FF58 ; call something that will RTS
C42A- BA TSX C42A- BA TSX ; pull stack pointer to X
C42B- BD 00 01 LDA $0100,X C42B- BD 00 01 LDA $0100,X ; grab A from the current stack pointer, which has our return addr
C42E- AA TAX C42E- AA TAX ; X = return addr
C42F- 0A ASL C42F- 0A ASL
C430- 0A ASL C430- 0A ASL
C431- 0A ASL C431- 0A ASL
C432- 0A ASL C432- 0A ASL
C433- A8 TAY C433- A8 TAY ; Y = (return addr) << 4
C434- 28 PLP ; restore status from stack C434- 28 PLP ; restore status from stack (includes V,C)
C435- 50 0F BVC $C446 ; overflow is clear if ... ? C435- 50 0F BVC $C446 ; overflow is clear from when we were called?
C437- A5 38 LDA $38 ; >> what's in $38? C437- A5 38 LDA $38 ; >> $38 is the IN# vector ("KSW") low byte
C439- D0 0D BNE $C448 ; restore stack & return C439- D0 0D BNE $C448 ; restore stack & return
C43B- 8A TXA C43B- 8A TXA
C43C- 45 39 EOR $39 ; >> what's in $39? C43C- 45 39 EOR $39 ; >> KSW high byte
C43E- D0 08 BNE $C448 ; restore stack & return C43E- D0 08 BNE $C448 ; restore stack & return
C440- A9 05 LDA #$05 C440- A9 05 LDA #$05
C442- 85 38 STA $38 ; ($38) = $05 C442- 85 38 STA $38 ; ($38) = $05
C442- 85 38 STA $38
C444- D0 0B BNE $C451 C444- D0 0B BNE $C451
;; we wind up here when the entry vector $c405 is called directly (from $9eba)
C446- B0 09 BCS $C451 ; carry set if ... ? C446- B0 09 BCS $C451 ; carry set if ... ?
;; entry point when called as PR# so BASIC/DOS can init the mouse
C448- 68 PLA ; pull X from stack C448- 68 PLA ; pull X from stack
C449- AA TAX C449- AA TAX
C44A- 68 PLA ; pull Y from stack, but C44A- 68 PLA ; pull Y from stack, but
@ -277,6 +309,7 @@ C4A7- D0 F1 BNE $C49A
C4A9- EA NOP C4A9- EA NOP
C4AA- A9 07 LDA #$07 C4AA- A9 07 LDA #$07
C4AC- D0 EC BNE $C49A C4AC- D0 EC BNE $C49A
; "TimeData" to set freq before init to 50/60 Hz? Doesn't look like it...
C4AE- A2 03 LDX #$03 C4AE- A2 03 LDX #$03
C4B0- 38 SEC C4B0- 38 SEC
C4B1- 60 RTS C4B1- 60 RTS
@ -314,8 +347,7 @@ Patch: C471 from 99 82 C0 60 => 8D CF C0 60
SERVEMOUSE @ $C4B2: SERVEMOUSE @ $C4B2:
78 SEI 78 SEI
AD CE C0 LDA $C0CE ; use soft switch 0xE (read) to trigger this - expect ne\ AD CE C0 LDA $C0CE ; use soft switch 0xE (read) to trigger this - expect new value to be placed in $7f8+4 and $6b8+4
w value to be placed in $7f8+4 and $6b8+4
A2 04 LDX #$04 ; our slot number, for cleanup code A2 04 LDX #$04 ; our slot number, for cleanup code
18 CLC 18 CLC
90 C1 BCC $C47C 90 C1 BCC $C47C
@ -324,7 +356,7 @@ Patch: C4B2 from 08 A5 00 48 A9 60 85 00 78 =>
78 AD CE C0 A2 04 18 90 C1 78 AD CE C0 A2 04 18 90 C1
READMOUSE READMOUSE
C48E- AD CB C0 LDA $C04B ; soft switch 0x0B for readmouse C48E- AD CB C0 LDA $C0CB ; soft switch 0x0B for readmouse
18 CLC 18 CLC
60 RTS 60 RTS
@ -332,14 +364,14 @@ Patch: from A9 04 99 83 C0 =>
AD CB C0 18 60 AD CB C0 18 60
CLEARMOUSE CLEARMOUSE
C49F- AD CA C0 LDA $C04A ; soft switch 0x0A for clearmouse C49F- AD CA C0 LDA $C0CA ; soft switch 0x0A for clearmouse
18 CLC 18 CLC
60 RTS 60 RTS
Patch: from EA A9 05 D0 F6 => Patch: from EA A9 05 D0 F6 =>
AD CA C0 18 60 AD CA C0 18 60
POSMOUSE POSMOUSE
C4a4- AD C9 C0 LDA $C049 ; soft switch 0x09 for posmouse C4a4- AD C9 C0 LDA $C0C9 ; soft switch 0x09 for posmouse
18 CLC 18 CLC
60 RTS 60 RTS
@ -347,20 +379,20 @@ Patch: from EA A9 06 D0 F1 =>
AD C9 C0 18 60 AD C9 C0 18 60
CLAMPMOUSE CLAMPMOUSE
C48A- 8D CD C0 STA $C04D ; use write to soft switch 0x0D to trigger clamp C48A- 8D CD C0 STA $C0CD ; use write to soft switch 0x0D to trigger clamp
60 RTS 60 RTS
Patch: from 99 83 C0 60 => 8D CD C0 60 Patch: from 99 83 C0 60 => 8D CD C0 60
HOMEMOUSE HOMEMOUSE
C4A9- AD C8 C0 LDA $c048 ; soft switch 0x08 for homemouse (read) C4A9- AD C8 C0 LDA $c0C8 ; soft switch 0x08 for homemouse (read)
18 CLC 18 CLC
60 RTS 60 RTS
Patch: from EA A9 07 D0 EC => AD C8 C0 18 60 Patch: from EA A9 07 D0 EC => AD C8 C0 18 60
INITMOUSE INITMOUSE
C498- AD CC C0 LDA $C04C ; soft switch 0x0C read for initmouse C498- AD CC C0 LDA $C0CC ; soft switch 0x0C read for initmouse
18 CLC 18 CLC
60 RTS 60 RTS
@ -376,8 +408,8 @@ Patch: from A9 02 99 83 C0 => AD CC C0 18 60
0x0A, 0x0A, 0x0A, 0xA8, 0x28, 0x50, 0x0F, 0xA5, // C430 0x0A, 0x0A, 0x0A, 0xA8, 0x28, 0x50, 0x0F, 0xA5, // C430
0x38, 0xd0, 0x0d, 0x8a, 0x45, 0x39, 0xd0, 0x08, 0x38, 0xd0, 0x0d, 0x8a, 0x45, 0x39, 0xd0, 0x08,
0xa9, 0x05, 0x85, 0x38, 0xd0, 0x0b, 0xb0, 0x09, // C440 0xa9, 0x05, 0x85, 0x38, 0xd0, 0x0b, 0xb0, 0x09, // C440
0x68, 0xaa, 0x68, 0xea, 0x68, 0x99, 0x80, 0xc0, 0x68, 0xaa, 0x68, 0xea, 0x68, 0xea, 0xea, 0xea,
0x60, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, // C450 0x60, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, // C450
0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60, 0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C460
0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x10, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x10, 0xb0,
@ -426,13 +458,25 @@ void Mouse::maintainMouse(int64_t cycleCount)
static int64_t nextInterruptTime = cycleCount + 17050; static int64_t nextInterruptTime = cycleCount + 17050;
if ( (status & ST_MOUSEENABLE) && if ( (status & ST_MOUSEENABLE) &&
(status & ST_INTVBL) ) { (status & ST_INTVBL) &&
if (cycleCount >= nextInterruptTime) { (cycleCount >= nextInterruptTime) ) {
g_cpu->irq();
interruptsTriggered |= ST_INTVBL;
nextInterruptTime += 17050;
} else {
uint16_t xpos, ypos;
g_mouse->getPosition(&xpos, &ypos);
if ( (status & ST_MOUSEENABLE) &&
(status & ST_INTMOUSE) &&
(xpos != lastX || ypos != lastY) ) {
g_cpu->irq(); g_cpu->irq();
interruptsTriggered |= ST_INTVBL; interruptsTriggered |= ST_INTMOUSE;
lastX = xpos; lastY = ypos;
nextInterruptTime += 17050;
} }
} }
/* FIXME: still need button */
} }

View File

@ -32,6 +32,10 @@ class Mouse : public Slot {
private: private:
uint8_t status; uint8_t status;
uint8_t interruptsTriggered; uint8_t interruptsTriggered;
uint16_t lastX, lastY;
bool lastButton;
bool curButton;
}; };
#endif #endif

View File

@ -5,6 +5,7 @@ Cpu *g_cpu = NULL;
VM *g_vm = NULL; VM *g_vm = NULL;
PhysicalDisplay *g_display = NULL; PhysicalDisplay *g_display = NULL;
PhysicalKeyboard *g_keyboard = NULL; PhysicalKeyboard *g_keyboard = NULL;
PhysicalMouse *g_mouse = NULL;
PhysicalSpeaker *g_speaker = NULL; PhysicalSpeaker *g_speaker = NULL;
PhysicalPaddles *g_paddles = NULL; PhysicalPaddles *g_paddles = NULL;
PhysicalPrinter *g_printer = NULL; PhysicalPrinter *g_printer = NULL;

View File

@ -8,6 +8,7 @@
#include "vm.h" #include "vm.h"
#include "physicaldisplay.h" #include "physicaldisplay.h"
#include "physicalkeyboard.h" #include "physicalkeyboard.h"
#include "physicalmouse.h"
#include "physicalspeaker.h" #include "physicalspeaker.h"
#include "physicalpaddles.h" #include "physicalpaddles.h"
#include "physicalprinter.h" #include "physicalprinter.h"
@ -41,6 +42,7 @@ extern Cpu *g_cpu;
extern VM *g_vm; extern VM *g_vm;
extern PhysicalDisplay *g_display; extern PhysicalDisplay *g_display;
extern PhysicalKeyboard *g_keyboard; extern PhysicalKeyboard *g_keyboard;
extern PhysicalMouse *g_mouse;
extern PhysicalSpeaker *g_speaker; extern PhysicalSpeaker *g_speaker;
extern PhysicalPaddles *g_paddles; extern PhysicalPaddles *g_paddles;
extern PhysicalPrinter *g_printer; extern PhysicalPrinter *g_printer;

View File

@ -51,6 +51,9 @@ Debugger::Debugger()
server.sin_addr.s_addr = INADDR_ANY; server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(12345); server.sin_port = htons(12345);
steppingOut = false;
singleStep = false;
if (bind(sd, (struct sockaddr *) &server, sizeof(server)) < 0) { if (bind(sd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("error binding to debug socket"); perror("error binding to debug socket");
exit(1); exit(1);
@ -71,10 +74,14 @@ Debugger::~Debugger()
bool getAddress(const char *buf, unsigned int *addrOut) bool getAddress(const char *buf, unsigned int *addrOut)
{ {
unsigned int val; unsigned int val;
if (sscanf(buf, " 0x%X", &val) == 1) { if (sscanf(buf, " 0x%X", &val) == 1 ||
sscanf(buf, " 0x%x", &val) == 1
) {
*addrOut = val; *addrOut = val;
return true; return true;
} else if (sscanf(buf, " $%X", &val) == 1) { } else if (sscanf(buf, " $%X", &val) == 1 ||
sscanf(buf, " $%x", &val) == 1
) {
*addrOut = val; *addrOut = val;
return true; return true;
} else if (sscanf(buf, " %d", &val) == 1) { } else if (sscanf(buf, " %d", &val) == 1) {
@ -91,11 +98,10 @@ bool getAddress(const char *buf, unsigned int *addrOut)
#define HEXCHAR(x) ((x>='0'&&x<='9')?x-'0':(x>='a'&&x<='f')?x-'a'+10:(x>='A'&&x<='F')?x-'A'+10:(x=='i' || x=='I')?1:(x=='o' || x=='O')?0:0) #define HEXCHAR(x) ((x>='0'&&x<='9')?x-'0':(x>='a'&&x<='f')?x-'a'+10:(x>='A'&&x<='F')?x-'A'+10:(x=='i' || x=='I')?1:(x=='o' || x=='O')?0:0)
#define FROMHEXP(p) ((HEXCHAR(*p) << 4) | HEXCHAR(*(p+1))) #define FROMHEXP(p) ((HEXCHAR(*p) << 4) | HEXCHAR(*(p+1)))
bool steppingOut = false;
void Debugger::step() void Debugger::step()
{ {
static char buf[256]; static char buf[256];
uint8_t cmdbuf[50];
// FIXME: add more than just RTS(0x60) here // FIXME: add more than just RTS(0x60) here
if (steppingOut && if (steppingOut &&
@ -124,39 +130,55 @@ void Debugger::step()
return; return;
} }
uint8_t cmdbuf[50]; if (!singleStep && breakpoint && g_cpu->pc != breakpoint) {
uint16_t loc=g_cpu->pc;
for (int i=0; i<50/3; i++) {
for (int idx=0; idx<sizeof(cmdbuf); idx++) {
cmdbuf[idx] = g_vm->getMMU()->read(loc+idx);
}
loc += dis.instructionToMnemonic(loc, cmdbuf, buf, sizeof(buf));
write(cd, buf, strlen(buf));
buf[0] = 13;
buf[1] = 10;
write(cd, buf, 2);
}
if (breakpoint && g_cpu->pc != breakpoint) {
// Running until we reach the breakpoint // Running until we reach the breakpoint
return; return;
} }
singleStep = false; // we have taken a single step, so reset flag
uint8_t b; // byte value used in parsing uint8_t b; // byte value used in parsing
unsigned int val; // common value buffer used in parsing unsigned int val; // common value buffer used in parsing
GETCH; // debugging what's at FF58 right now
snprintf(buf, sizeof(buf), "Got char %d\012\015", b); uint8_t tmp = g_vm->getMMU()->read(0xff58);
sprintf(buf, " 0xFF58: 0x%.2X\r\n", tmp);
write(cd, buf, strlen(buf)); write(cd, buf, strlen(buf));
doover:
do {
GETCH;
} while (b != 'c' && // continue (with breakpoint set)
b != 'q' && // quit
b != 's' && // single step
b != 'S' && // step out
b != 'b' && // set breakpoint
b != 'd' && // show disassembly
b != 'L' && // load memory (lines)
b != '*' // show memory (byte)
);
switch (b) { switch (b) {
case 'c': // Continue - close connection and let execution flow case 'c': // continue (if there is a breakpoint set)
if (breakpoint) {
snprintf(buf, sizeof(buf), "Continuing until breakpoint 0x%X\012\015", breakpoint);
write(cd, buf, strlen(buf));
} else {
snprintf(buf, sizeof(buf), "No breakpoint to continue until\012\015");
write(cd, buf, strlen(buf));
goto doover;
}
break;
case 'q': // Close debugging socket and quit
printf("Closing debugging socket\n"); printf("Closing debugging socket\n");
breakpoint = 0;
close(cd); cd=-1; close(cd); cd=-1;
break; break;
case 's':
singleStep = true; // for when breakpoint is set: just step once
break;
case 'S': case 'S':
steppingOut = true; steppingOut = true;
break; break;
@ -176,6 +198,23 @@ void Debugger::step()
write(cd, buf, strlen(buf)); write(cd, buf, strlen(buf));
break; break;
case 'd': // show disassembly @ PC
{
uint16_t loc=g_cpu->pc;
for (int i=0; i<50/3; i++) {
for (int idx=0; idx<sizeof(cmdbuf); idx++) {
cmdbuf[idx] = g_vm->getMMU()->read(loc+idx);
}
loc += dis.instructionToMnemonic(loc, cmdbuf, buf, sizeof(buf));
write(cd, buf, strlen(buf));
buf[0] = 13;
buf[1] = 10;
write(cd, buf, 2);
}
}
goto doover;
break;
case 'L': // Load data to memory. Use: "L 0x<address>\n" followed by lines of packed hex; ends with a blank line case 'L': // Load data to memory. Use: "L 0x<address>\n" followed by lines of packed hex; ends with a blank line
{ {
printf("Loading data\n"); printf("Loading data\n");
@ -198,6 +237,7 @@ void Debugger::step()
} }
} }
} }
goto doover;
break; break;
case '*': // read 1 byte of memory. Use '* 0x<address>' case '*': // read 1 byte of memory. Use '* 0x<address>'
@ -214,6 +254,7 @@ void Debugger::step()
write(cd, buf, strlen(buf)); write(cd, buf, strlen(buf));
} }
} }
goto doover;
break; break;
case 'G': // Goto (set PC) case 'G': // Goto (set PC)

View File

@ -19,6 +19,8 @@ class Debugger {
pthread_t listenThreadID; pthread_t listenThreadID;
uint32_t breakpoint; uint32_t breakpoint;
bool steppingOut;
bool singleStep;
}; };

View File

@ -2,13 +2,27 @@
#define __PHYSICALMOUSE_H #define __PHYSICALMOUSE_H
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
enum {
XCLAMP = 0,
YCLAMP = 1
};
class PhysicalMouse { class PhysicalMouse {
public: public:
PhysicalMouse() {} PhysicalMouse() { lowClamp[XCLAMP] = lowClamp[YCLAMP] = 0; highClamp[XCLAMP] = highClamp[YCLAMP] = 1023; }
virtual ~PhysicalMouse() {}; virtual ~PhysicalMouse() {};
virtual void maintainMouse() = 0; virtual void maintainMouse() = 0;
virtual void setClamp(uint8_t direction, uint16_t low, uint16_t high) { lowClamp[direction] = low; highClamp[direction] = high; printf("clamp %d %d-%d\n", direction, low, high); }
virtual void setPosition(uint16_t x, uint16_t y) = 0;
virtual void getPosition(uint16_t *x, uint16_t *y) = 0;
virtual bool getButton() = 0;
protected:
uint16_t lowClamp[2], highClamp[2];
}; };
#endif #endif

View File

@ -7,6 +7,7 @@
#include "applevm.h" #include "applevm.h"
#include "sdl-display.h" #include "sdl-display.h"
#include "sdl-keyboard.h" #include "sdl-keyboard.h"
#include "sdl-mouse.h"
#include "sdl-speaker.h" #include "sdl-speaker.h"
#include "sdl-paddles.h" #include "sdl-paddles.h"
#include "nix-filemanager.h" #include "nix-filemanager.h"
@ -291,7 +292,7 @@ struct timespec runMaintenance(struct timespec now)
initialized = true; initialized = true;
} }
timespec_add_us(&startTime, 100000*cycleCount, &nextRuntime); // FIXME: what's a good time here? 1/10 sec? timespec_add_us(&startTime, 16667*cycleCount, &nextRuntime); // FIXME: what's a good time here? 60 Hz?
// Check if it's time to run - and if not, return how long it will // Check if it's time to run - and if not, return how long it will
// be until we need to run // be until we need to run
@ -305,6 +306,7 @@ struct timespec runMaintenance(struct timespec now)
if (!g_biosInterrupt) { if (!g_biosInterrupt) {
// If the BIOS is running, then let it handle the keyboard directly // If the BIOS is running, then let it handle the keyboard directly
g_keyboard->maintainKeyboard(); g_keyboard->maintainKeyboard();
g_mouse->maintainMouse();
} }
doDebugging(); doDebugging();
@ -389,6 +391,7 @@ int main(int argc, char *argv[])
g_vm = new AppleVM(); g_vm = new AppleVM();
g_keyboard = new SDLKeyboard(g_vm->getKeyboard()); g_keyboard = new SDLKeyboard(g_vm->getKeyboard());
g_mouse = new SDLMouse();
// Now that the VM exists and it has created an MMU, we tell the CPU how to access memory through the MMU. // Now that the VM exists and it has created an MMU, we tell the CPU how to access memory through the MMU.
g_cpu->SetMMU(g_vm->getMMU()); g_cpu->SetMMU(g_vm->getMMU());

View File

@ -1,6 +1,7 @@
#include "sdl-keyboard.h" #include "sdl-keyboard.h"
#include "sdl-paddles.h" #include "sdl-paddles.h"
#include "sdl-mouse.h"
#include "globals.h" #include "globals.h"
SDLKeyboard::SDLKeyboard(VMKeyboard *k) : PhysicalKeyboard(k) SDLKeyboard::SDLKeyboard(VMKeyboard *k) : PhysicalKeyboard(k)
@ -149,12 +150,18 @@ void SDLKeyboard::maintainKeyboard()
if (event.key.repeat == 0) if (event.key.repeat == 0)
handleKeypress(&event.key); handleKeypress(&event.key);
break; break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
((SDLMouse *)g_mouse)->mouseButtonEvent(event.type == SDL_MOUSEBUTTONDOWN);
break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
// We are handling the SDL input loop, so need to pass this off to the paddles. :/ // We are handling the SDL input loop, so need to pass this off to the paddles. :/
// FIXME: nasty rooting around in other objects and typecasting. // FIXME: nasty rooting around in other objects and typecasting.
// FIXME: event.motion.state & SDL_BUTTON_LMASK, et al? // FIXME: event.motion.state & SDL_BUTTON_LMASK, et al?
((SDLPaddles *)g_paddles)->gotMouseMovement(event.motion.x, event.motion.y); ((SDLPaddles *)g_paddles)->gotMouseMovement(event.motion.x, event.motion.y);
((SDLMouse *)g_mouse)->gotMouseEvent(event.motion.state, // button
event.motion.xrel, event.motion.yrel);
break; break;
case SDL_QUIT: case SDL_QUIT: