Merge branch 'mouse41'

This commit is contained in:
Jorj Bauer 2021-01-11 12:33:43 -05:00
commit 5011dd5743
33 changed files with 1081 additions and 86 deletions

3
.gitignore vendored
View File

@ -13,4 +13,5 @@ apple/hd32-rom.h
aiie-sdl
mockingboard-d.rom
*.d
*.dSYM
suspend.vm

View File

@ -8,19 +8,19 @@ CXXFLAGS=-Wall -I/usr/include/SDL2 -I .. -I . -I apple -I nix -I sdl -I/usr/loca
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
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
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
ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h apple/hd32-rom.h
.PHONY: roms clean
@ -40,7 +40,7 @@ test: $(TSRC)
./testharness -f tests/65c02-all.bin -s 0x200
roms: apple2e.rom disk.rom parallel.rom HDDRVR.BIN
./util/genrom.pl apple2e.rom disk.rom parallel.rom HDDRVR.BIN
./util/genrom.pl apple2e.rom disk.rom parallel.rom HDDRVR.BIN
apple/applemmu-rom.h: roms

View File

@ -216,10 +216,13 @@ inline void AppleDisplay::Draw14DoubleHiresPixelsAt(uint16_t addr)
drawApplePixel(bitTrain & 0x0F, col+xoff+1,row);
} else {
// Perfect color, B&W, monochrome. Draw an exact version of the pixels, and let
// the physical display figure out if they need to be reduced to B&W or not.
// the physical display figure out if they need to be reduced to B&W or not
// (for the most part - the m_blackAndWhite piece here allows full-res displays
// to give the crispest resolution.)
uint8_t color = bitTrain & 0x0F;
if (g_displayType == m_blackAndWhite) { color = c_white; }
g_display->cachePixel((col*2)+(xoff*2), row,
((bitTrain & 0x01) ? color : c_black));

View File

@ -55,16 +55,24 @@ page 0-1 4 pages (1k) [altzp]
0xC1-0xCF 15 * 2 pages = 30 pages (7.5k) [intcxrom, slotLatch]
0xD0 - 0xDF 16 * 5 pages = 80 pages (20k) [altzp, bank2, {r,w}bsr]
0xE0 - 0xFF 32 * 3 pages = 96 pages (24k) [altzp, {r,w}bsr]
... plus 8 additional pages for the mouse ROM
= 147.75k (591 pages) stored off-chip
= 147.75k (591 pages) stored off-chip (+ 8 more)
Current read page table [512 bytes] in real ram
Current write page table [512 bytes] in real ram
*/
// This has a split memory model so more often addressed pages can be
// in internal memory, and an external memory can hold others.
// All the pages. Because we don't have enough RAM for both the
// display's DMA and the Apple's 148k (128k + ROM space), we're using
// an external SRAM for some of this. Anything that's accessed very
// often should be in the *low* pages, b/c those are in internal
// Teensy RAM. When we run out of preallocated RAM (cf. vmram.h), we
// fall over to an external 256kB SRAM (which is much slower).
//
// Zero page (and its alts) are the most used pages (the stack is in
// page 1).
//
// We want the video display pages in real RAM as much as possible,
// since blits wind up touching so much of it. If we can keep that in
@ -81,19 +89,19 @@ enum {
MP_ZP = 0, // page 0/1 * 2 page variants = 4; 0..3
MP_4 = 4, // 0x04 - 0x07 (text display pages) * 2 variants = 8; 4..11
MP_20 = 12, // 0x20 - 0x5F * 2 variants = 128; 12..139
// Pages that can go to external RAM if needed:
// Pages that can go to external SRAM:
MP_2 = 140, // 0x02 - 0x03 * 2 variants = 4; 140..143
MP_8 = 144, // 0x08 - 0x1F * 2 = 48; 144..191
MP_60 = 192, // 0x60 - 0xBF * 2 = 192; 192..383
MP_C1 = 384, // start of 0xC1-0xCF * 2 page variants = 30; 384-413
MP_D0 = 414, // start of 0xD0-0xDF * 5 page variants = 80; 414-493
MP_E0 = 493, // start of 0xE0-0xFF * 3 page variants = 96; 494-589
MP_C0 = 590
// = 591 pages in all (147.75k)
MP_C1 = 384, // start of 0xC1-0xC7 * 2 page variants = 14; 384-397
MP_C8 = 398, // 0xc8 - 0xcf, 3 page variants = 24; 398 - 421
MP_D0 = 422, // start of 0xD0-0xDF * 5 page variants = 80; 422 - 501
MP_E0 = 502, // start of 0xE0-0xFF * 3 page variants = 96; 502 - 597
MP_C0 = 598
// = 599 pages in all (149.75k)
};
static uint16_t _pageNumberForRam(uint8_t highByte, uint8_t variant)
{
if (highByte <= 1) {
@ -118,11 +126,14 @@ static uint16_t _pageNumberForRam(uint8_t highByte, uint8_t variant)
if (highByte == 0xc0) {
return MP_C0;
}
if (highByte <= 0xCF) {
// 0xC1-0xCF 15 * 2 pages = 30 pages (7.5k)
if (highByte <= 0xC7) {
// 0xC1-0xC7
return ((highByte - 0xC1) * 2 + variant + MP_C1);
}
if (highByte <= 0xCF) {
// bank-switched ROM. 0 = built-in; 1 = 80-column (slot 3); 2 = mouse (slot 4)
return ((highByte - 0xC8) * 3 + variant + MP_C8);
}
if (highByte <= 0xDF) {
// 0xD0 - 0xDF 16 * 5 pages = 80 pages (20k)
return ((highByte - 0xD0) * 5 + variant + MP_D0);
@ -220,6 +231,8 @@ bool AppleMMU::Deserialize(int8_t fd)
return false;
}
void AppleMMU::Reset()
{
resetRAM();
@ -914,6 +927,9 @@ void AppleMMU::resetRAM()
// Load system ROM
for (uint16_t i=0x80; i<=0xFF; i++) {
uint16_t page0 = _pageNumberForRam(i, 0);
uint16_t page1 = _pageNumberForRam(i, 1);
for (uint16_t k=0; k<0x100; k++) {
uint16_t idx = ((i-0x80) << 8) | k;
#ifdef TEENSYDUINO
@ -921,36 +937,30 @@ void AppleMMU::resetRAM()
#else
uint8_t v = romData[idx];
#endif
for (int j=0; j<5; j++) {
// For the ROM section from 0xc100 .. 0xcfff, we load in to
// an alternate page space (INTCXROM).
uint16_t page0 = _pageNumberForRam(i, 0);
// The space from 0xc1 through 0xcf is ROM image territory. We
// load the C3 ROM in to page 0, but not page 1; and then we
// load c800.CFFF to both main ROM (page 0) and the C3 aux ROM
// (page 1) to convince the VM that we've got 128k of RAM and an
// 80-column card.
if (i >= 0xc1 && i <= 0xcf) {
// If we want to convince the VM we've got 128k of RAM, we
// need to load C3 ROM in page 0 (but not 1, meaning there's
// a board installed); and C800.CFFF in both page [0] and [1]
// (meaning there's an extended 80-column ROM available,
// that is also physically in the slot).
// Everything else goes in page [1].
uint16_t page1 = _pageNumberForRam(i, 1);
if (i == 0xc3) {
g_ram.writeByte((page0 << 8) | (k & 0xFF), v);
}
else if (i >= 0xc8) {
g_ram.writeByte((page0 << 8) | (k & 0xFF), v);
g_ram.writeByte((page1 << 8) | (k & 0xFF), v);
}
else {
g_ram.writeByte((page1 << 8) | (k & 0xFF), v);
}
} else {
// Everything else goes in page 0.
if (i >= 0xc1 && i <= 0xcf) {
if (i == 0xc3) {
// C300..C3FF => built-in ROM
g_ram.writeByte((page0 << 8) | (k & 0xFF), v);
}
else if (i >= 0xc8) {
// C800..CFFF => built-in ROM and slot 3 extended ROM
g_ram.writeByte((page0 << 8) | (k & 0xFF), v);
g_ram.writeByte((page1 << 8) | (k & 0xFF), v);
}
else {
// C000..C2FF and C400..c7FF are main ROM
g_ram.writeByte((page1 << 8) | (k & 0xFF), v);
}
} else {
// Everything else goes in page 0.
g_ram.writeByte((page0 << 8) | (k & 0xFF), v);
}
}
}
@ -959,12 +969,33 @@ void AppleMMU::resetRAM()
for (uint8_t slotnum = 1; slotnum <= 7; slotnum++) {
uint16_t page0 = _pageNumberForRam(0xC0 + slotnum, 0);
if (slots[slotnum]) {
// Load the primary ROM for this peripheral (0xCsXX..0xCsFF)
uint8_t tmpBuf[256];
memset(tmpBuf, 0, sizeof(tmpBuf));
slots[slotnum]->loadROM(tmpBuf);
for (int i=0; i<256; i++) {
g_ram.writeByte( (page0 << 8) + i, tmpBuf[i] );
}
// See if there's an extended 2k ROM for this peripheral (0xC800..0xCFFF)
if (slots[slotnum]->hasExtendedRom()) {
for (int j=0; j<8; j++) {
// Load each of the 256 byte chunks separately to its own VMRam page
uint16_t slotPage = 0;
if (slotnum == 4) {
slotPage = _pageNumberForRam(0xC8 + j, 2);
} else {
#ifndef TEENSYDUINO
fprintf(stderr, "ERROR: unsupported extended ROM peripheral in slot %d\n", slotnum);
exit(1);
#endif
}
if (slotPage) {
uint8_t *p = g_ram.memPtr(slotPage << 8);
slots[slotnum]->loadExtendedRom(p, j * 256);
}
}
}
}
}
@ -1063,12 +1094,17 @@ void AppleMMU::updateMemoryPages()
// If slotLatch is set (!= -1), then we are mapping 2k of ROM
// for a given peripheral to C800..CFFF.
if (slotLatch != -1) {
// FIXME: the only peripheral we support this with right now is
// the 80-column card.
// FIXME: this is a hacky mess. Slot 3 (the 80-col card) is
// supported, as page "1"; and Slot 4 (the mouse card) is
// supported as page "2".
if (slotLatch == 3) {
for (int i=0xc8; i <= 0xcf; i++) {
readPages[i] = _pageNumberForRam(i, 1);
}
} else if (slotLatch == 4) {
for (int i=0xc8; i <= 0xcf; i++) {
readPages[i] = _pageNumberForRam(i, 2);
}
}
}

View File

@ -35,6 +35,9 @@ AppleVM::AppleVM()
hd32 = new HD32((AppleMMU *)mmu);
((AppleMMU *)mmu)->setSlot(7, hd32);
mouse = new Mouse();
((AppleMMU *)mmu)->setSlot(4, mouse);
}
AppleVM::~AppleVM()
@ -133,6 +136,7 @@ void AppleVM::cpuMaintenance(int64_t cycles)
keyboard->maintainKeyboard(cycles);
disk6->maintenance(cycles);
mouse->maintainMouse(cycles);
}
void AppleVM::Reset()
@ -189,3 +193,8 @@ VMKeyboard * AppleVM::getKeyboard()
{
return keyboard;
}
bool AppleVM::isMouseEnabled()
{
return mouse->isEnabled();
}

View File

@ -7,6 +7,7 @@
#include "hd32.h"
#include "vmkeyboard.h"
#include "parallelcard.h"
#include "mouse.h"
#include "vm.h"
class AppleVM : public VM {
@ -34,11 +35,14 @@ class AppleVM : public VM {
virtual VMKeyboard *getKeyboard();
bool isMouseEnabled();
DiskII *disk6;
HD32 *hd32;
protected:
VMKeyboard *keyboard;
ParallelCard *parallel;
Mouse *mouse;
};

361
apple/mouse.cpp Normal file
View File

@ -0,0 +1,361 @@
#include "mouse.h"
#include <string.h>
#include "globals.h"
enum {
SW_W_INIT = 0x00,
SW_R_HOMEMOUSE = 0x08,
SW_R_POSMOUSE = 0x09,
SW_R_CLEARMOUSE = 0x0A,
SW_R_READMOUSE = 0x0B,
SW_R_INITMOUSE = 0x0C,
SW_W_CLAMPMOUSE = 0x0D,
SW_R_SERVEMOUSE = 0x0E,
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 {
ST_MOUSEENABLE = 1,
ST_INTMOUSE = 2,
ST_INTBUTTON = 4,
ST_INTVBL = 8
};
Mouse::Mouse()
{
status = 0;
interruptsTriggered = 0;
lastX = lastY = 0;
lastXForInt = lastYForInt = 0;
lastButton = false;
lastButtonForInt = false;
}
Mouse::~Mouse()
{
}
bool Mouse::Serialize(int8_t fd)
{
return true;
}
bool Mouse::Deserialize(int8_t fd)
{
return true;
}
void Mouse::Reset()
{
}
uint8_t Mouse::readSwitches(uint8_t s)
{
switch (s) {
default:
printf("mouse: unknown switch read 0x%X\n", s);
};
return 0xFF;
}
void Mouse::writeSwitches(uint8_t s, uint8_t v)
{
switch (s) {
/* Many of these were designed to be reads, because they don't have to
* modify any state inside the VM directly -- but it's important (per docs)
* that we return A, X, and Y as they were when we were called. So these
* are all now writes, which don't modify A/X/Y. */
case SW_R_HOMEMOUSE:
g_mouse->setPosition( (g_vm->getMMU()->read(0x578) << 8) | g_vm->getMMU()->read(0x478),
(g_vm->getMMU()->read(0x5F8) << 8) | g_vm->getMMU()->read(0x4F8)
);
break;
case SW_R_POSMOUSE:
g_mouse->setPosition( (g_vm->getMMU()->read(0x578+4) << 8) | g_vm->getMMU()->read(0x478+4),
(g_vm->getMMU()->read(0x5F8+4) << 8) | g_vm->getMMU()->read(0x4F8+4)
);
break;
case SW_R_CLEARMOUSE:
g_vm->getMMU()->write(0x578+4, 0);
g_vm->getMMU()->write(0x478+4, 0);
g_vm->getMMU()->write(0x5F8+4, 0);
g_vm->getMMU()->write(0x4F8+4, 0);
g_mouse->setPosition(0,0);
break;
case SW_R_READMOUSE:
{
uint16_t xpos, ypos;
g_mouse->getPosition(&xpos, &ypos);
if (lastX != xpos || lastY != ypos) {
interruptsTriggered |= 0x20; // "x or y changed since last reading"
lastX = xpos; lastY = ypos;
}
curButton = g_mouse->getButton();
uint8_t newStatus = g_vm->getMMU()->read(0x778+4) & ~0xC0;
if (curButton) { newStatus |= 0x80; };
if (lastButton) { newStatus |= 0x40; };
g_vm->getMMU()->write(0x578+4, (xpos >> 8) & 0xFF); // high X
g_vm->getMMU()->write(0x478+4, xpos & 0xFF); // low X
g_vm->getMMU()->write(0x5F8+4, (ypos >> 8) & 0xFF); // high Y
g_vm->getMMU()->write(0x4F8+4, ypos); // low Y
}
break;
case SW_R_INITMOUSE:
// Set clamp to (0,0) - (1023,1023)
g_vm->getMMU()->write(0x578, 0); // high of lowclamp
g_vm->getMMU()->write(0x478, 0); // low of lowclamp
g_vm->getMMU()->write(0x5F8, 0x03); // high of highclamp
g_vm->getMMU()->write(0x4F8, 0xFF); // low of highclamp
g_mouse->setClamp(XCLAMP, 0, 1023);
g_mouse->setClamp(YCLAMP, 0, 1023);
break;
case SW_R_SERVEMOUSE:
if (lastButton) interruptsTriggered |= 0x40;
if (curButton != lastButton) {
interruptsTriggered |= 0x80;
lastButton = curButton;
}
g_vm->getMMU()->write(0x778+4, interruptsTriggered);
g_vm->getMMU()->write(0x6B8+4, interruptsTriggered); // hack to appease ROM
interruptsTriggered = 0;
break;
case SW_W_INIT:
v &= 0x03; // just the low 3 bits apparently?
// printf("Simple init: value is 0x%X\n", v);
status = v;
g_vm->getMMU()->write(0x7f8 + 4, v);
break;
case SW_W_CLAMPMOUSE:
{
uint16_t lowval = (g_vm->getMMU()->read(0x578) << 8) | (g_vm->getMMU()->read(0x478));
uint16_t highval = (g_vm->getMMU()->read(0x5F8) << 8) | (g_vm->getMMU()->read(0x4F8));
if (v) {
g_mouse->setClamp(YCLAMP, lowval, highval);
} else {
// X is clamping
g_mouse->setClamp(XCLAMP, lowval, highval);
}
}
break;
case SW_W_SETMOUSE:
status = v;
g_vm->getMMU()->write(0x7f8 + 4, v);
break;
default:
printf("mouse: unknown switch write 0x%X = 0x%2X\n", s, v);
break;
}
}
void Mouse::loadROM(uint8_t *toWhere)
{
/* This is a custom-built ROM which hands off control to the C++ code via
* soft switch writes. It's hard-coded to work with the mouse in Slot 4.
*
* ; $c400 is the entry point for PR#4
* $C400 2C 58 FF BIT $FF58
* $C403 70 1B BVS IOHandler
* ; $c405 is the entry point for IN#4 when we set KSW
* $C405 38 SEC
* $C406 90 18 BCC IOHandler
* $C408 B8 CLV
* $C409 50 15 BVC IOHandler ; always branch
* $C40B 01 20 8D 8D 8D ; data (ID bytes & such)
* $C410 8D 00 60 68 76 7B 80 85 ; data (lookup table of entrypoints)
* $C418 8F 94 8D 8D 8D 8D 8D 8D ; data (lookup table of entrypoints)
* ; IOHandler ORG $c420
* $C420 48 PHA ; save registers on stack
* $C421 98 TYA
* $C422 48 PHA
* $C423 8A TXA
* $C424 48 PHA
* $C425 08 PHP
* $C426 78 SEI ; disable interrupts
* $C427 20 58 FF JSR $FF58 ; JSR to this well-known location that has
* $C42A BA TSX ; an RTS (normally). Then when we get
* $C42B BD 00 01 LDA $100,X ; back, pull our address off the stack
* $C42E AA TAX ; and save the high byte in X
* $C42F 0A ASL
* $C430 0A ASL
* $C431 0A ASL
* $C432 0A ASL
* $C433 A8 TAY ; and (high byte << 4) in Y
* $C434 28 PLP ; restore interrupt state
* $C435 50 0F BVC $C446
* $C437 A5 38 LDA $0
* $C439 D0 0D BNE $C448
* $C43B 8A TXA
* $C43C 45 39 EOR $0
* $C43E D0 08 BNE $C448
* $C440 A9 05 LDA #$0
* $C442 85 38 STA $0
* $C444 D0 0B BNE SendInputToDOS
* $C446 B0 09 BCS SendInputToDOS
* $C448 68 PLA ; restore registers
* $C449 AA TAX
* $C44A 68 PLA
* $C44B EA NOP
* $C44C 68 PLA
* $C44D EA NOP
* $C44E EA NOP
* $C44F EA NOP
* $C450 60 RTS
* ; SendInputToDOS ORG $c451
* $C451 EA NOP
* $C452 EA NOP
* $C453 EA NOP
* $C454 68 PLA
* $C455 BD 38 06 LDA $638,X ; X is $C4, so this is $6F8+n - which is
* $C458 AA TAX ; a reserved hole
* $C459 68 PLA
* $C45A A8 TAY
* $C45B 68 PLA
* $C45C BD 00 02 LDA $200,X ; keyboard buffer output
* $C45F 60 RTS
* ; SetMouse ORG $c460
* $C460 C9 10 CMP #$0
* $C462 B0 29 BCS ExitWithError
* $C464 8D CF C0 STA $C0CF ; soft switch 0x0F invokes SetMouse
* $C467 60 RTS
* ; ServeMouse ORG $c468
* $C468 48 PHA
* $C469 18 CLC ; use CLC/BCC to force relative jump
* $C46A 90 2D BCC ServeMouseWorker
* ; ServeMouseExit ORG $c46c
* $C46C BD B8 06 LDA $6B8,X ; check what interrupts we say we serviced
* $C46F 29 0E AND #$0
* $C471 D0 01 BNE $C474 ; if we serviced any, leave carry clear
* $C473 38 SEC ; but set carry if we serviced none
* $C474 68 PLA
* $C475 60 RTS
* ; ReadMouse ORG $c476
* $C476 8D CB C0 STA $C0CB ; soft switch 0x0B
* $C479 18 CLC
* $C47A 60 RTS
* ; ClearMouse ORG $c47b
* $C47B 8D CA C0 STA $C0CA ; soft switch 0x0A
* $C47E 18 CLC
* $C47F 60 RTS
* ; PosMouse ORG $c480
* $C480 8D C9 C0 STA $C0C9 ; soft switch 0x09
* $C483 18 CLC
* $C484 60 RTS
* ; ClampMouse ORG $c485
* $C485 C9 02 CMP #$0
* $C487 B0 04 BCS $C48D
* $C489 8D CD C0 STA $C0CD ; soft switch 0x0D
* $C48C 60 RTS
* ; ExitWithError ORG $c48d
* $C48D 38 SEC ; the spec says carry is set on errors
* $C48E 60 RTS
* ; HomeMouse ORG $c48f
* $C48F 8D C8 C0 STA $C0C8 ; soft switch 0x08
* $C492 18 CLC
* $C493 60 RTS
* ; InitMouse ORG $c494
* $C494 8D CC C0 STA $C0CC ; soft switch 0x0C
* $C497 18 CLC
* $C498 60 RTS
* ; ServeMouseWorker ORG $c499
* $C499 78 SEI ; disable interrupts
* $C49A 8D CE C0 STA $C0CE ; soft switch 0x0E
* $C49D A2 04 LDX #$0
* $C49F 18 CLC
* $C4A0 90 CA BCC ServeMouseExit ; force relative jump
* ; $C4A2..C4FA is dead space (all $FF)
* $C4FB D6 FF FF FF 01 ; data (ID bytes)
*/
uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, // C400
0xb8, 0x50, 0x15, 0x01, 0x20, 0x8d, 0x8d, 0x8d,
0x8d, 0x00, 0x60, 0x68, 0x76, 0x7b, 0x80, 0x85, // C410
0x8f, 0x94, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x48, 0x98, 0x48, 0x8a, 0x48, 0x08, 0x78, 0x20, // C420
0x58, 0xFF, 0xBA, 0xBD, 0x00, 0x01, 0xAA, 0x0A,
0x0A, 0x0A, 0x0A, 0xA8, 0x28, 0x50, 0x0F, 0xA5, // C430
0x38, 0xd0, 0x0d, 0x8a, 0x45, 0x39, 0xd0, 0x08,
0xa9, 0x05, 0x85, 0x38, 0xd0, 0x0b, 0xb0, 0x09, // C440
0x68, 0xaa, 0x68, 0xea, 0x68, 0xea, 0xea, 0xea,
0x60, 0xea, 0xea, 0xea, 0x68, 0xbd, 0x38, 0x06, // C450
0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60,
0xc9, 0x10, 0xb0, 0x29, 0x8d, 0xcf, 0xc0, 0x60, // C460
0x48, 0x18, 0x90, 0x2d, 0xbd, 0xb8, 0x06, 0x29,
0x0e, 0xd0, 0x01, 0x38, 0x68, 0x60, 0x8d, 0xcb, // C470
0xc0, 0x18, 0x60, 0x8d, 0xca, 0xc0, 0x18, 0x60,
0x8d, 0xc9, 0xc0, 0x18, 0x60, 0xc9, 0x02, 0xb0, // C480
0x04, 0x8d, 0xcd, 0xc0, 0x60, 0x38, 0x60, 0x8d,
0xc8, 0xc0, 0x18, 0x60, 0x8d, 0xcc, 0xc0, 0x18, // C490
0x60, 0x78, 0x8d, 0xce, 0xc0, 0xa2, 0x04, 0x18,
0x90, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C4A0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4B0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4C0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4D0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4E0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4F0
0xff, 0xff, 0xff, 0xd6, 0xff, 0xff, 0xff, 0x01 };
memcpy(toWhere, rom, 256);
}
bool Mouse::hasExtendedRom()
{
return true;
}
void Mouse::loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset)
{
// There's no extended ROM needed, b/c we do the extended ROM work
// directly in C++
}
void Mouse::maintainMouse(int64_t cycleCount)
{
// Fake a 60Hz VBL in case we need it for our interrupts
static int64_t nextInterruptTime = cycleCount + 17050;
if ( (status & ST_MOUSEENABLE) &&
(status & ST_INTVBL) &&
(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 != lastXForInt || ypos != lastYForInt) ) {
g_cpu->irq();
interruptsTriggered |= ST_INTMOUSE;
lastXForInt = xpos; lastYForInt = ypos;
} else if ( (status & ST_MOUSEENABLE) &&
(status & ST_INTBUTTON) &&
lastButtonForInt != g_mouse->getButton()) {
g_cpu->irq();
interruptsTriggered |= ST_INTBUTTON;
lastButtonForInt = g_mouse->getButton();
}
}
/* FIXME: still need button */
}
bool Mouse::isEnabled()
{
return status & ST_MOUSEENABLE;
}

50
apple/mouse.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef __APPLEMOUSE_H
#define __APPLEMOUSE_H
#ifdef TEENSYDUINO
#include <Arduino.h>
#else
#include <stdint.h>
#include <stdio.h>
#endif
#include "applemmu.h"
#include "slot.h"
class Mouse : public Slot {
public:
Mouse();
virtual ~Mouse();
virtual bool Serialize(int8_t fd);
virtual bool Deserialize(int8_t fd);
virtual void Reset(); // used by BIOS cold-boot
virtual uint8_t readSwitches(uint8_t s);
virtual void writeSwitches(uint8_t s, uint8_t v);
virtual void loadROM(uint8_t *toWhere);
virtual bool hasExtendedRom();
virtual void loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset);
void maintainMouse(int64_t cycleCount);
bool isEnabled();
private:
uint8_t status;
uint8_t interruptsTriggered;
// Previous state vars used when we're asked "did this change since last time"
uint16_t lastX, lastY;
bool lastButton;
bool curButton;
// second set of previous state vars for use when checking if an interrupt
// needs to fire based on a change
uint16_t lastXForInt, lastYForInt;
bool lastButtonForInt;
};
#endif

43
apple/pia6821.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "pia6821.h"
PIA6821::PIA6821()
{
}
PIA6821::~PIA6821()
{
}
uint8_t PIA6821::read(uint8_t addr)
{
uint8_t rv;
switch (addr) {
case DDRA:
if (cra & 0x04) { // DDR or Peripherial Interface access control
// peripheral
// rv = readPeripheralA();
// FIXME continue here
} else {
rv = ddra;
}
break;
case CTLA:
rv = cra;
break;
case DDRB:
if (crb & 0x04) {
// rv = readPeripheralB();
// FIXME continue here
} else {
rv = ddrb;
}
break;
case CTLB:
rv = crb;
break;
}
return rv;
}

31
apple/pia6821.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _PIA6821_H
#define _PIA6821_H
#include <stdint.h>
// http://webpages.charter.net/coinopcauldron/piaarticle.html
#define DDRA 0
#define CTLA 1
#define DDRB 2
#define CTLB 3
class PIA6821 {
public:
PIA6821();
~PIA6821();
uint8_t read(uint8_t addr);
private:
uint8_t porta, portb;
uint8_t ddra, ddrb;
uint8_t cra, crb; // control registers
/*
2 ports - porta, portb
*/
};
#endif

View File

@ -22,6 +22,9 @@ class Slot {
virtual void writeSwitches(uint8_t s, uint8_t v) = 0;
virtual void loadROM(uint8_t *toWhere) = 0;
virtual bool hasExtendedRom() { return false; };
virtual void loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset) {};
};
#endif

View File

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

View File

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

View File

@ -51,6 +51,9 @@ Debugger::Debugger()
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(12345);
steppingOut = false;
singleStep = false;
if (bind(sd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("error binding to debug socket");
exit(1);
@ -71,10 +74,14 @@ Debugger::~Debugger()
bool getAddress(const char *buf, unsigned int *addrOut)
{
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;
return true;
} else if (sscanf(buf, " $%X", &val) == 1) {
} else if (sscanf(buf, " $%X", &val) == 1 ||
sscanf(buf, " $%x", &val) == 1
) {
*addrOut = val;
return true;
} 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 FROMHEXP(p) ((HEXCHAR(*p) << 4) | HEXCHAR(*(p+1)))
bool steppingOut = false;
void Debugger::step()
{
static char buf[256];
uint8_t cmdbuf[50];
// FIXME: add more than just RTS(0x60) here
if (steppingOut &&
@ -124,38 +130,49 @@ void Debugger::step()
return;
}
uint8_t cmdbuf[50];
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) {
if (!singleStep && breakpoint && g_cpu->pc != breakpoint) {
// Running until we reach the breakpoint
return;
}
singleStep = false; // we have taken a single step, so reset flag
uint8_t b; // byte value used in parsing
unsigned int val; // common value buffer used in parsing
GETCH;
snprintf(buf, sizeof(buf), "Got char %d\012\015", b);
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) {
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");
breakpoint = 0;
close(cd); cd=-1;
break;
case 's':
singleStep = true; // for when breakpoint is set: just step once
break;
case 'S':
steppingOut = true;
@ -176,6 +193,23 @@ void Debugger::step()
write(cd, buf, strlen(buf));
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
{
printf("Loading data\n");
@ -198,6 +232,7 @@ void Debugger::step()
}
}
}
goto doover;
break;
case '*': // read 1 byte of memory. Use '* 0x<address>'
@ -214,6 +249,7 @@ void Debugger::step()
write(cd, buf, strlen(buf));
}
}
goto doover;
break;
case 'G': // Goto (set PC)

View File

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

View File

@ -133,6 +133,7 @@ uint8_t Disassembler::instructionToMnemonic(uint16_t addr, uint8_t *p, char *out
addrmode amode = opcodes[*p].mode;
uint16_t target = 0;
char arg[40] = "\0";
char bytes[10] = "\0";
switch (amode) {
case A_REL:
@ -153,14 +154,19 @@ uint8_t Disassembler::instructionToMnemonic(uint16_t addr, uint8_t *p, char *out
switch (instructionBytes(*p)) {
case 1:
// no arguments
sprintf(bytes, " %.2X ", *(uint8_t *)p);
break;
case 2:
sprintf(arg, "%s$%X%s", om.prefix, target, om.suffix);
sprintf(bytes, " %.2X %.2X ", *(uint8_t *)p, *(uint8_t *)(p+1));
break;
case 3:
sprintf(arg, "%s$%X%s", om.prefix, target, om.suffix);
sprintf(bytes, "%.2X %.2X %.2X ", *(uint8_t *)p, *(uint8_t *)(p+1), *(uint8_t *)(p+2));
break;
}
sprintf(outp, "$%.4X %s %s", addr, mn, arg);
sprintf(outp, "$%.4X %s %s %s", addr, bytes, mn, arg);
return instructionBytes(*p);
}

27
physicalmouse.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef __PHYSICALMOUSE_H
#define __PHYSICALMOUSE_H
#include <stdint.h>
enum {
XCLAMP = 0,
YCLAMP = 1
};
class PhysicalMouse {
public:
PhysicalMouse() { lowClamp[XCLAMP] = lowClamp[YCLAMP] = 0; highClamp[XCLAMP] = highClamp[YCLAMP] = 1023; }
virtual ~PhysicalMouse() {};
virtual void maintainMouse() = 0;
virtual void setClamp(uint8_t direction, uint16_t low, uint16_t high) { lowClamp[direction] = low; highClamp[direction] = 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

View File

@ -7,6 +7,7 @@
#include "applevm.h"
#include "sdl-display.h"
#include "sdl-keyboard.h"
#include "sdl-mouse.h"
#include "sdl-speaker.h"
#include "sdl-paddles.h"
#include "nix-filemanager.h"
@ -291,7 +292,7 @@ struct timespec runMaintenance(struct timespec now)
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
// be until we need to run
@ -305,6 +306,7 @@ struct timespec runMaintenance(struct timespec now)
if (!g_biosInterrupt) {
// If the BIOS is running, then let it handle the keyboard directly
g_keyboard->maintainKeyboard();
g_mouse->maintainMouse();
}
doDebugging();
@ -389,6 +391,7 @@ int main(int argc, char *argv[])
g_vm = new AppleVM();
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.
g_cpu->SetMMU(g_vm->getMMU());

View File

@ -1,6 +1,7 @@
#include "sdl-keyboard.h"
#include "sdl-paddles.h"
#include "sdl-mouse.h"
#include "globals.h"
SDLKeyboard::SDLKeyboard(VMKeyboard *k) : PhysicalKeyboard(k)
@ -149,12 +150,18 @@ void SDLKeyboard::maintainKeyboard()
if (event.key.repeat == 0)
handleKeypress(&event.key);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
((SDLMouse *)g_mouse)->mouseButtonEvent(event.type == SDL_MOUSEBUTTONDOWN);
break;
case SDL_MOUSEMOTION:
// 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: event.motion.state & SDL_BUTTON_LMASK, et al?
((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;
case SDL_QUIT:

62
sdl/sdl-mouse.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "sdl-mouse.h"
#include "globals.h"
SDLMouse::SDLMouse() : PhysicalMouse()
{
xpos = ypos = 0;
button = false;
}
SDLMouse::~SDLMouse()
{
}
void SDLMouse::gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y)
{
xpos += x; ypos += y;
if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP];
if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP];
if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP];
if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP];
}
void SDLMouse::mouseButtonEvent(bool state)
{
button = state;
}
void SDLMouse::maintainMouse()
{
}
void SDLMouse::setPosition(uint16_t x, uint16_t y)
{
xpos = x;
ypos = y;
if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP];
if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP];
if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP];
if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP];
}
void SDLMouse::getPosition(uint16_t *x, uint16_t *y)
{
if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP];
if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP];
if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP];
if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP];
uint16_t outx = xpos;
uint16_t outy = ypos;
*x = outx;
*y = outy;
}
bool SDLMouse::getButton()
{
return button;
}

26
sdl/sdl-mouse.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __SDL_MOUSE_H
#define __SDL_MOUSE_H
#include "physicalmouse.h"
#include <SDL.h>
class SDLMouse : public PhysicalMouse {
public:
SDLMouse();
virtual ~SDLMouse();
virtual void maintainMouse();
virtual void setPosition(uint16_t x, uint16_t y);
virtual void getPosition(uint16_t *x, uint16_t *y);
virtual bool getButton();
void gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y);
void mouseButtonEvent(bool state);
private:
int32_t xpos, ypos;
bool button;
};
#endif

142
serialize.h Normal file
View File

@ -0,0 +1,142 @@
#ifndef __SERIALIZE_H
#define __SERIALIZE_H
#define serialize8(var) { uint8_t buf = (uint8_t)var; \
if (g_filemanager->write(fd, &buf, 1) != 1) { \
printf("Failed to write 1 byte\n"); \
goto err; \
} \
}
#define serializeMagic(var) { \
printf("Serializing magic '%d'\n", var); \
uint8_t buf = var; \
if (g_filemanager->write(fd, &buf, 1) != 1) { \
printf("Failed to write 1 byte of magic\n"); \
goto err; \
} \
}
#define serialize16(var) { \
uint8_t buf[2]; \
uint8_t ptr = 0; \
buf[ptr++] = ((var >> 8) & 0xFF); \
buf[ptr++] = ((var ) & 0xFF); \
if (g_filemanager->write(fd, buf, 2) != 2) { \
printf("Failed to write 2 bytes\n"); \
goto err; \
} \
}
#define serialize32(var) { \
uint8_t buf[4]; \
uint8_t ptr = 0; \
buf[ptr++] = ((var >> 24) & 0xFF); \
buf[ptr++] = ((var >> 16) & 0xFF); \
buf[ptr++] = ((var >> 8) & 0xFF); \
buf[ptr++] = ((var ) & 0xFF); \
if (g_filemanager->write(fd, buf, 4) != 4) { \
printf("Failed to write 4 bytes\n"); \
goto err; \
} \
}
#define serialize64(var) { \
uint8_t buf[8]; \
uint8_t ptr = 0; \
buf[ptr++] = ((var >> 56) & 0xFF); \
buf[ptr++] = ((var >> 48) & 0xFF); \
buf[ptr++] = ((var >> 40) & 0xFF); \
buf[ptr++] = ((var >> 32) & 0xFF); \
buf[ptr++] = ((var >> 24) & 0xFF); \
buf[ptr++] = ((var >> 16) & 0xFF); \
buf[ptr++] = ((var >> 8) & 0xFF); \
buf[ptr++] = ((var ) & 0xFF); \
if (g_filemanager->write(fd, buf, 8) != 8) { \
printf("Failed to write 8 bytes\n"); \
goto err; \
} \
}
#define serializeString(s) { \
if (g_filemanager->write(fd, s, strlen(s)+1) != strlen(s)+1) { \
printf("Failed to write string '%s'\n", s); \
goto err; \
} \
}
#define deserialize8(var) { \
uint8_t buf; \
if (g_filemanager->read(fd, &buf, 1) != 1) { \
printf("Failed to deserialize 1 byte\n"); \
goto err; \
} \
var = buf; \
}
#define deserializeMagic(expect) { \
uint8_t buf; \
printf("Deserializing magic, expecting 0x%X\n", expect); \
if (g_filemanager->read(fd, &buf, 1) != 1) { \
printf("Failed to deserialize 1 byte of magic\n"); \
goto err; \
} \
if (buf != expect) { \
printf("magic error: 0x%X does not match expected 0x%X\n", buf, expect); \
goto err; \
} \
}
#define deserialize16(var) { \
uint8_t buf[2]; \
uint8_t ptr = 0; \
if (g_filemanager->read(fd, buf, 2) != 2) { \
printf("Failed to deserialize 2 bytes\n"); \
goto err; \
} \
var = buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; }
#define deserialize32(var) { \
uint8_t buf[4]; \
uint8_t ptr = 0; \
if (g_filemanager->read(fd, buf, 4) != 4) { \
printf("Failed to deserialize 4 bytes\n"); \
goto err; \
} \
var = buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; }
#define deserialize64(var) { \
uint8_t buf[8]; \
uint8_t ptr = 0; \
if (g_filemanager->read(fd, buf, 8) != 8) { \
printf("Failed to deserialize 8 bytes\n"); \
goto err; \
} \
var = buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; \
var <<= 8; var |= buf[ptr++]; }
#define deserializeString(var) { \
uint8_t c; \
char *ptr = var; \
while (1) { \
if (g_filemanager->read(fd, &c, 1) != 1) { \
printf("Failed to read string byte\n"); \
goto err; \
} \
printf(". "); \
*(ptr++) = c; \
if (c == 0) { break; } \
} \
}
#endif

1
teensy/mouse.cpp Symbolic link
View File

@ -0,0 +1 @@
../apple/mouse.cpp

1
teensy/mouse.h Symbolic link
View File

@ -0,0 +1 @@
../apple/mouse.h

1
teensy/physicalmouse.h Symbolic link
View File

@ -0,0 +1 @@
../physicalmouse.h

1
teensy/serialize.h Symbolic link
View File

@ -0,0 +1 @@
../serialize.h

View File

@ -345,10 +345,14 @@ void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color)
// with a color between the two.
#if 1
// This is straight blending, R/G/B average
// This is straight blending, R/G/B average, except in B&W mode
uint16_t origColor = dmaBuffer[y+VOFFSET][(x>>1)+HOFFSET];
uint16_t newColor = loresPixelColors[color];
cacheDoubleWidePixel(x>>1, y, blendColors(origColor, newColor));
if (g_displayType == m_blackAndWhite) {
cacheDoubleWidePixel(x>>1, y, (origColor && newColor) ? 0xFFFF : 0x0000);
} else {
cacheDoubleWidePixel(x>>1, y, blendColors(origColor, newColor));
}
#endif
#if 0

View File

@ -4,6 +4,9 @@
#include "LRingBuffer.h"
#include "teensy-println.h"
#include "globals.h"
#include "teensy-mouse.h"
const byte ROWS = 5;
const byte COLS = 13;
@ -71,12 +74,13 @@ void TeensyKeyboard::pressedKey(uint8_t key)
break;
case PK_RSHFT:
rightShiftPressed = 1;
break;
break;
case PK_LOCK:
capsLock = !capsLock;
break;
case PK_LA:
leftApplePressed = 1;
((TeensyMouse *)g_mouse)->mouseButtonEvent(true);
leftApplePressed = 1;
break;
case PK_RA:
rightApplePressed = 1;
@ -162,6 +166,7 @@ void TeensyKeyboard::releasedKey(uint8_t key)
rightShiftPressed = 0;
break;
case PK_LA:
((TeensyMouse *)g_mouse)->mouseButtonEvent(false);
leftApplePressed = 0;
break;
case PK_RA:
@ -218,9 +223,15 @@ void TeensyKeyboard::maintainKeyboard()
switch (keypad.key[i].kstate) {
case PRESSED:
vmkeyboard->keyDepressed(keypad.key[i].kchar);
if (keypad.key[i].kchar == PK_LSHFT) {
((TeensyMouse *)g_mouse)->mouseButtonEvent(true);
}
break;
case RELEASED:
vmkeyboard->keyReleased(keypad.key[i].kchar);
if (keypad.key[i].kchar == PK_LSHFT) {
((TeensyMouse *)g_mouse)->mouseButtonEvent(false);
}
break;
case HOLD:
case IDLE:

85
teensy/teensy-mouse.cpp Normal file
View File

@ -0,0 +1,85 @@
#include <Arduino.h>
#include "teensy-mouse.h"
#include "globals.h"
#include "applevm.h"
TeensyMouse::TeensyMouse() : PhysicalMouse()
{
xpos = ypos = 0;
button = false;
}
TeensyMouse::~TeensyMouse()
{
}
void TeensyMouse::gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y)
{
xpos += x; ypos += y;
if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP];
if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP];
if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP];
if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP];
}
void TeensyMouse::mouseButtonEvent(bool state)
{
button = state;
}
void TeensyMouse::maintainMouse()
{
if (((AppleVM *)g_vm)->isMouseEnabled()) {
// only do this if the mouse card is enabled, so we're not incurring
// analogRead delays constantly
uint8_t paddle0 = g_paddles->paddle0();
uint8_t paddle1 = g_paddles->paddle1();
int16_t dx=0, dy=0;
if (paddle0 <= 25) {
dx = -1;
} else if (paddle0 >= 245) {
dx = 1;
}
if (paddle1 <= 25) {
dy = -1;
} else if (paddle1 >= 245) {
dy = 1;
}
if (dx || dy) {
gotMouseEvent(button, dx, dy);
}
}
}
void TeensyMouse::setPosition(uint16_t x, uint16_t y)
{
xpos = x;
ypos = y;
if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP];
if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP];
if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP];
if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP];
}
void TeensyMouse::getPosition(uint16_t *x, uint16_t *y)
{
if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP];
if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP];
if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP];
if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP];
uint16_t outx = xpos;
uint16_t outy = ypos;
*x = outx;
*y = outy;
}
bool TeensyMouse::getButton()
{
return button;
}

24
teensy/teensy-mouse.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __TEENSY_MOUSE_H
#define __TEENSY_MOUSE_H
#include "physicalmouse.h"
class TeensyMouse : public PhysicalMouse {
public:
TeensyMouse();
virtual ~TeensyMouse();
virtual void maintainMouse();
virtual void setPosition(uint16_t x, uint16_t y);
virtual void getPosition(uint16_t *x, uint16_t *y);
virtual bool getButton();
void gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y);
void mouseButtonEvent(bool state);
private:
int32_t xpos, ypos;
bool button;
};
#endif

View File

@ -6,6 +6,7 @@
#include "applevm.h"
#include "teensy-display.h"
#include "teensy-keyboard.h"
#include "teensy-mouse.h"
#include "teensy-speaker.h"
#include "teensy-paddles.h"
#include "teensy-filemanager.h"
@ -211,6 +212,7 @@ void setup()
// And the physical keyboard needs hooks in to the virtual keyboard...
println(" keyboard");
g_keyboard = new TeensyKeyboard(g_vm->getKeyboard());
g_mouse = new TeensyMouse();
println(" paddles");
g_paddles = new TeensyPaddles(A3, A2, g_invertPaddleX, g_invertPaddleY);
@ -286,7 +288,8 @@ void runMaintenance(uint32_t now)
static uint32_t nextRuntime = 0;
if (now >= nextRuntime) {
nextRuntime = now + 100000; // FIXME: what's a good time here? 1/10 sec?
// Run maintenance at 60 Hz because the mouse will need it
nextRuntime = now + 16667;
if (!resetButtonDebouncer.read()) {
// This is the BIOS interrupt. Wait for it to clear and process it.
@ -297,6 +300,7 @@ void runMaintenance(uint32_t now)
}
if (!g_biosInterrupt) {
g_mouse->maintainMouse();
g_keyboard->maintainKeyboard();
usb.maintain();
}

View File

@ -9,11 +9,10 @@
#include "globals.h"
#ifdef TEENSYDUINO
#include "iocompat.h"
EXTMEM uint8_t preallocatedRam[591*256];
EXTMEM uint8_t preallocatedRam[599*256];
#else
#include <stdio.h>
uint8_t preallocatedRam[591*256];
uint8_t preallocatedRam[599*256];
#endif
#ifndef TEENSYDUINO
@ -47,6 +46,13 @@ void VMRam::writeByte(uint32_t addr, uint8_t value)
preallocatedRam[addr] = value;
}
uint8_t *VMRam::memPtr(uint32_t addr)
{
// printf("Asked for preallocated RAM pointer at 0x%X\n", addr);
// printf("Base is 0x%llX\n", (unsigned long long) preallocatedRam);
return &preallocatedRam[addr];
}
bool VMRam::Serialize(int8_t fd)
{
uint32_t size = sizeof(preallocatedRam);

View File

@ -15,13 +15,15 @@ class VMRam {
uint8_t readByte(uint32_t addr);
void writeByte(uint32_t addr, uint8_t value);
uint8_t *memPtr(uint32_t addr);
bool Serialize(int8_t fd);
bool Deserialize(int8_t fd);
bool Test();
private:
// We need 591 pages of 256 bytes for the //e.
// We need 599 pages of 256 bytes for the //e.
//
// This previously used a split memory model where some of this was
// in internal ram and some was external - and while that's not true
@ -37,7 +39,7 @@ class VMRam {
// Pages 4-7 are 0x200 - 0x3FF. We want those in RAM too (text pages).
// Has to be static if we're using the EXTMEM sectioning, so it's now in vmram.cpp :/
//EXTMEM uint8_t preallocatedRam[591*256];
//EXTMEM uint8_t preallocatedRam[599*256];
};