mirror of
https://github.com/JorjBauer/aiie.git
synced 2025-02-26 02:29:03 +00:00
added printer support
This commit is contained in:
parent
3af0b916d7
commit
32352fcc4c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,8 @@
|
|||||||
apple2e.rom
|
apple2e.rom
|
||||||
disk.rom
|
disk.rom
|
||||||
|
parallel.rom
|
||||||
*~
|
*~
|
||||||
*.o
|
*.o
|
||||||
apple/applemmu-rom.h
|
apple/applemmu-rom.h
|
||||||
apple/diskii-rom.h
|
apple/diskii-rom.h
|
||||||
|
apple/parallel-rom.h
|
13
Makefile
13
Makefile
@ -1,12 +1,12 @@
|
|||||||
LDFLAGS=-L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_features2d -lopencv_calib3d
|
LDFLAGS=-L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_features2d -lopencv_calib3d
|
||||||
|
|
||||||
CXXFLAGS=-Wall -I .. -I . -I apple -O3
|
CXXFLAGS=-Wall -I .. -I . -I apple -I opencv -O3
|
||||||
|
|
||||||
TSRC=cpu.cpp util/testharness.cpp
|
TSRC=cpu.cpp util/testharness.cpp
|
||||||
|
|
||||||
OPENCVOBJS=cpu.o opencv/dummy-speaker.o opencv/opencv-display.o opencv/opencv-keyboard.o opencv/opencv-paddles.o opencv/opencv-filemanager.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o apple/slot.o RingBuffer.o globals.o opencv/aiie.o
|
OPENCVOBJS=cpu.o opencv/dummy-speaker.o opencv/opencv-display.o opencv/opencv-keyboard.o opencv/opencv-paddles.o opencv/opencv-filemanager.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o RingBuffer.o globals.o opencv/aiie.o apple/parallelcard.o apple/fx80.o opencv/opencv-printer.o
|
||||||
|
|
||||||
ROMS=apple/applemmu-rom.h apple/diskii-rom.h
|
ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h
|
||||||
|
|
||||||
all: opencv
|
all: opencv
|
||||||
|
|
||||||
@ -14,17 +14,18 @@ opencv: roms $(OPENCVOBJS)
|
|||||||
g++ $(LDFLAGS) -o aiie-opencv $(OPENCVOBJS)
|
g++ $(LDFLAGS) -o aiie-opencv $(OPENCVOBJS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ */*.o */*~ testharness.basic testharness.verbose testharness.extended aiie-opencv apple/diskii-rom.h apple/applemmu-rom.h
|
rm -f *.o *~ */*.o */*~ testharness.basic testharness.verbose testharness.extended aiie-opencv apple/diskii-rom.h apple/applemmu-rom.h apple/parallel-rom.h
|
||||||
|
|
||||||
test: $(TSRC)
|
test: $(TSRC)
|
||||||
g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic
|
g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic
|
||||||
g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose
|
g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose
|
||||||
g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended
|
g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended
|
||||||
|
|
||||||
roms: apple2e.rom disk.rom
|
roms: apple2e.rom disk.rom parallel.rom
|
||||||
./util/genrom.pl apple2e.rom disk.rom
|
./util/genrom.pl apple2e.rom disk.rom parallel.rom
|
||||||
|
|
||||||
apple/applemmu-rom.h: roms
|
apple/applemmu-rom.h: roms
|
||||||
|
|
||||||
apple/diskii-rom.h: roms
|
apple/diskii-rom.h: roms
|
||||||
|
|
||||||
|
apple/parallel-rom.h: roms
|
||||||
|
@ -26,16 +26,21 @@ As with many emulators, you have to go get the ROMs yourself. I've got
|
|||||||
the ROMs that I dumped out of my Apple //e. You can probably get yours
|
the ROMs that I dumped out of my Apple //e. You can probably get yours
|
||||||
a lot easier.
|
a lot easier.
|
||||||
|
|
||||||
There are two files that you'll need:
|
There are three files that you'll need:
|
||||||
|
|
||||||
* apple2e.rom -- a 32k dump of the entire Apple //e ROM
|
* apple2e.rom -- a 32k dump of the entire Apple //e ROM
|
||||||
* disk.rom -- a 256 byte dump of the DiskII controller ROM (16-sector P5)
|
* disk.rom -- a 256 byte dump of the DiskII controller ROM (16-sector P5)
|
||||||
|
* parallel.rom -- a 256 byte dump of either of the two Apple Parallel cards
|
||||||
|
|
||||||
The MD5 sums of those two files are:
|
The MD5 sums of those files are:
|
||||||
|
|
||||||
* 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
|
* 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
|
||||||
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
|
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
|
||||||
|
|
||||||
|
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
|
||||||
|
-or-
|
||||||
|
d666ea749f79a35faa31b4e9a7878eb7 parallel.rom
|
||||||
|
|
||||||
From those, the appropriate headers will be automatically generated by
|
From those, the appropriate headers will be automatically generated by
|
||||||
"make roms" (or any other target that relies on the ROMs).
|
"make roms" (or any other target that relies on the ROMs).
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ AppleVM::AppleVM()
|
|||||||
((AppleMMU *)mmu)->setSlot(6, disk6);
|
((AppleMMU *)mmu)->setSlot(6, disk6);
|
||||||
|
|
||||||
keyboard = new AppleKeyboard((AppleMMU *)mmu);
|
keyboard = new AppleKeyboard((AppleMMU *)mmu);
|
||||||
|
|
||||||
|
parallel = new ParallelCard();
|
||||||
|
((AppleMMU *)mmu)->setSlot(1, parallel);
|
||||||
|
|
||||||
#ifdef TEENSYDUINO
|
#ifdef TEENSYDUINO
|
||||||
teensyClock = new TeensyClock((AppleMMU *)mmu);
|
teensyClock = new TeensyClock((AppleMMU *)mmu);
|
||||||
((AppleMMU *)mmu)->setSlot(7, teensyClock);
|
((AppleMMU *)mmu)->setSlot(7, teensyClock);
|
||||||
@ -51,6 +55,7 @@ void AppleVM::cpuMaintenance(uint32_t cycles)
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyboard->maintainKeyboard(cycles);
|
keyboard->maintainKeyboard(cycles);
|
||||||
|
parallel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppleVM::Reset()
|
void AppleVM::Reset()
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "appledisplay.h"
|
#include "appledisplay.h"
|
||||||
#include "diskii.h"
|
#include "diskii.h"
|
||||||
#include "vmkeyboard.h"
|
#include "vmkeyboard.h"
|
||||||
|
#include "parallelcard.h"
|
||||||
#ifdef TEENSYDUINO
|
#ifdef TEENSYDUINO
|
||||||
#include "teensy-clock.h"
|
#include "teensy-clock.h"
|
||||||
#endif
|
#endif
|
||||||
@ -32,6 +33,7 @@ class AppleVM : public VM {
|
|||||||
protected:
|
protected:
|
||||||
DiskII *disk6;
|
DiskII *disk6;
|
||||||
VMKeyboard *keyboard;
|
VMKeyboard *keyboard;
|
||||||
|
ParallelCard *parallel;
|
||||||
#ifdef TEENSYDUINO
|
#ifdef TEENSYDUINO
|
||||||
TeensyClock *teensyClock;
|
TeensyClock *teensyClock;
|
||||||
#endif
|
#endif
|
||||||
|
2570
apple/fx80-font.h
Normal file
2570
apple/fx80-font.h
Normal file
File diff suppressed because it is too large
Load Diff
259
apple/fx80.cpp
Normal file
259
apple/fx80.cpp
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
#include <string.h> // memset
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h> // while debugging
|
||||||
|
|
||||||
|
#include "fx80.h"
|
||||||
|
#include "fx80-font.h"
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
Fx80::Fx80()
|
||||||
|
{
|
||||||
|
clearLine();
|
||||||
|
escapeMode = false;
|
||||||
|
proportionalMode = false;
|
||||||
|
carriageDot = 0;
|
||||||
|
twoSixteenthsLineSpacing = 36; // 1/6" line spacing is the default (12 pixels)
|
||||||
|
graphicsWidth = 960;
|
||||||
|
ninePinGraphics = false;
|
||||||
|
escapeModeActive = 0;
|
||||||
|
escapeModeExpectingBytes = -1;
|
||||||
|
escapeModeLengthByteCount = 0;
|
||||||
|
escapeModeLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fx80::~Fx80()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::handleEscape(uint8_t c)
|
||||||
|
{
|
||||||
|
switch (c & 0x7F) {
|
||||||
|
case 75: // FIXME: single-density 480 dpi graphics line
|
||||||
|
graphicsWidth = 480;
|
||||||
|
break;
|
||||||
|
case 76: // FIXME: low-speed double-density graphics line
|
||||||
|
case 89: // FIXME: high-speed double-density graphics
|
||||||
|
graphicsWidth = 960;
|
||||||
|
escapeModeActive = c;
|
||||||
|
escapeModeExpectingBytes = -1;
|
||||||
|
escapeModeLengthByteCount = 0;
|
||||||
|
break;
|
||||||
|
case 90: // FIXME: quadruple-density graphics
|
||||||
|
graphicsWidth = 960 * 2;
|
||||||
|
break;
|
||||||
|
case 94: // FIXME: enable 9-pin graphics
|
||||||
|
escapeModeActive = c;
|
||||||
|
escapeModeExpectingBytes = -1;
|
||||||
|
escapeModeLengthByteCount = 0;
|
||||||
|
break;
|
||||||
|
case 65: // set line spacing
|
||||||
|
escapeModeActive = c;
|
||||||
|
escapeModeExpectingBytes = 1;
|
||||||
|
break;
|
||||||
|
case 33: // FIXME: mode select
|
||||||
|
case 35: // FIXME: enable 8-bit reception from computer
|
||||||
|
case 37: // FIXME: pick charset from ROM
|
||||||
|
case 38: // FIXME: define chars in RAM
|
||||||
|
case 42: // FIXME: set vertical tabs
|
||||||
|
case 43: // FIXME: set form length (default: 66 lines, 11 inches)
|
||||||
|
case 68: // FIXME: reset current tabs, pitch
|
||||||
|
case 69: // FIXME: emphasized mode on
|
||||||
|
case 70: // FIXME: emphasized mode off
|
||||||
|
case 71: // FIXME: double-strike on
|
||||||
|
case 72: // FIXME: double-strike off
|
||||||
|
case 73: // FIXME: enable printing chr[0..31] except control codes
|
||||||
|
case 74: // FIXME: line feed immediately, n/216th of an inch
|
||||||
|
case 77: // FIXME: elite mode (12cpi)
|
||||||
|
case 78: // FIXME: turn on skip-over perforation
|
||||||
|
case 79: // FIXME: turn off skip-over perforation
|
||||||
|
case 80: // FIXME: disable elite; enable pica mode (unless compressed is enabled)
|
||||||
|
case 81: // FIXME: cancel print buffer, set right margin
|
||||||
|
case 82: // FIXME: select international charset
|
||||||
|
case 83: // FIXME: script mode on
|
||||||
|
case 84: // FIXME: script mode off
|
||||||
|
case 85: // FIXME: unidirecitonal mode on/off
|
||||||
|
case 87: // FIXME: expanded mode
|
||||||
|
case 98: // FIXME: set vertical tab
|
||||||
|
case 105: // FIXME: immediate mode on
|
||||||
|
case 106: // FIXME: immediate reverse linefeed 1/216"
|
||||||
|
case 108: // FIXME: set left margin
|
||||||
|
case 112: // FIXME: turn on proportional mode
|
||||||
|
case 115: // FIXME: print speed
|
||||||
|
printf("unhandled escape code %d\n", c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::handleActiveEscapeMode(uint8_t c)
|
||||||
|
{
|
||||||
|
switch (escapeModeActive) {
|
||||||
|
case 76:
|
||||||
|
case 89:
|
||||||
|
// one column of double-density graphics
|
||||||
|
{
|
||||||
|
// FIXME: abstract this - second time it's being used
|
||||||
|
uint16_t byteIdx = (carriageDot+0) / 8 + (FX80_MAXWIDTH/8) * 0;
|
||||||
|
uint8_t bitIdx = (carriageDot+0) % 8;
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
if (c & (1 << (7-i))) {
|
||||||
|
rowOfBits[byteIdx] |= (1 << (7-bitIdx));
|
||||||
|
}
|
||||||
|
byteIdx += (FX80_MAXWIDTH/8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
carriageDot++;
|
||||||
|
break;
|
||||||
|
case 65: // set line spacing to n/72ths of an inch (n=0-85)
|
||||||
|
twoSixteenthsLineSpacing = 3 * c;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unhandled active escape mode %d\n", c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::input(uint8_t c)
|
||||||
|
{
|
||||||
|
if (escapeMode) {
|
||||||
|
handleEscape(c);
|
||||||
|
escapeMode = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this an escape mode that gets a fixed amount of input?
|
||||||
|
if (escapeModeActive) {
|
||||||
|
if (escapeModeExpectingBytes < 0) {
|
||||||
|
// We're reading 2 bytes of length
|
||||||
|
escapeModeLengthByteCount++;
|
||||||
|
if (escapeModeLengthByteCount == 1) {
|
||||||
|
escapeModeLength = c;
|
||||||
|
} else {
|
||||||
|
escapeModeLength |= (c << 8);
|
||||||
|
escapeModeExpectingBytes = escapeModeLength;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
escapeModeExpectingBytes--;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleActiveEscapeMode(c);
|
||||||
|
if (escapeModeExpectingBytes == 0) {
|
||||||
|
escapeModeActive = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 27) {
|
||||||
|
escapeMode = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: all these also work as 128 + c
|
||||||
|
switch (c & 0x7F) {
|
||||||
|
case 0: // FIXME: terminate horiz/vert tab setting
|
||||||
|
return;
|
||||||
|
case 7: // beep
|
||||||
|
return;
|
||||||
|
case 8: // FIXME: "at current width" instead of this fixed-12
|
||||||
|
if (carriageDot >= 12)
|
||||||
|
carriageDot -= 12;
|
||||||
|
return;
|
||||||
|
case 9: // FIXME: HTAB
|
||||||
|
return;
|
||||||
|
case 10:
|
||||||
|
lineFeed();
|
||||||
|
return;
|
||||||
|
case 11: // FIXME: VTAB
|
||||||
|
return;
|
||||||
|
case 12: // FIXME: Form Feed
|
||||||
|
lineFeed();
|
||||||
|
return;
|
||||||
|
case 13:
|
||||||
|
carriageDot = 0;
|
||||||
|
// lineFeed(); // FIXME: this was controlled by a switch
|
||||||
|
return;
|
||||||
|
case 14: // FIXME: Shift Out - turns on "Expanded Mode"
|
||||||
|
case 15: // FIXME: Shift In - turns on "Compressed Mode"
|
||||||
|
case 17: // FIXME: DC1
|
||||||
|
case 18: // FIXME: DC2
|
||||||
|
case 19: // FIXME: DC3
|
||||||
|
case 20: // FIXME: DC4
|
||||||
|
case 24: // FIXME: cancel text in print buffer; not the same as "clear line"
|
||||||
|
case 127: // FIXME: delete last char in the print buffer
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal print - send the character verbatim...
|
||||||
|
addCharacter(c & 0x7F); // FIXME: masking high bit
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the given character on the line at the current carriage dot position
|
||||||
|
void Fx80::addCharacter(uint8_t c)
|
||||||
|
{
|
||||||
|
uint8_t width = Fx80Font[c * 19];
|
||||||
|
// FIXME: is 12 right for non-proportional mode?
|
||||||
|
if (!proportionalMode)
|
||||||
|
width = 12;
|
||||||
|
|
||||||
|
// Each row for this char has two bytes of bits, left-to-right, high
|
||||||
|
// bit leftmost.
|
||||||
|
|
||||||
|
const uint8_t *charPtr = &Fx80Font[c * 19];
|
||||||
|
charPtr++;
|
||||||
|
|
||||||
|
for (uint8_t row=0; row<9; row++) {
|
||||||
|
// Don't print beyond end of line!
|
||||||
|
|
||||||
|
for (uint8_t xoff = 0; xoff < 8; xoff++) {
|
||||||
|
|
||||||
|
if (carriageDot+xoff >= FX80_MAXWIDTH)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint16_t byteIdx = (carriageDot+xoff) / 8 + (FX80_MAXWIDTH/8) * row;
|
||||||
|
uint8_t bitIdx = (carriageDot+xoff) % 8;
|
||||||
|
|
||||||
|
// We never clear bits - it's possible to overstrike, so just add more...
|
||||||
|
if (charPtr[2*row] & (1 << (7-xoff))) {
|
||||||
|
rowOfBits[byteIdx] |= (1 << (7-bitIdx));
|
||||||
|
}
|
||||||
|
if (charPtr[2*row+1] & (1 << (7-xoff))) {
|
||||||
|
rowOfBits[byteIdx+1] |= (1 << (7-bitIdx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
carriageDot += 12; // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::lineFeed()
|
||||||
|
{
|
||||||
|
emitLine();
|
||||||
|
g_printer->moveDownPixels(twoSixteenthsLineSpacing / 3); // pixel estimation
|
||||||
|
clearLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::clearLine()
|
||||||
|
{
|
||||||
|
memset(rowOfBits, 0, sizeof(rowOfBits));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::emitLine()
|
||||||
|
{
|
||||||
|
// FIXME: this is very wrong. Doesn't deal with line advance
|
||||||
|
// properly. But it's good enough for debugging basic operation.
|
||||||
|
g_printer->addLine(rowOfBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fx80::update()
|
||||||
|
{
|
||||||
|
// The onscreen window needs to update regularly, and we probably
|
||||||
|
// want to periodically flush the Teensy buffer.
|
||||||
|
if (g_printer) {
|
||||||
|
g_printer->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
75
apple/fx80.h
Normal file
75
apple/fx80.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#ifndef __FX80_H
|
||||||
|
#define __FX80_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* maximum width, in dots, that we're supporting. The FX80 supported
|
||||||
|
* up to 1920 ("quadruple density") -- which I'm not, b/c that's
|
||||||
|
* overkill for what I'm doing at the moment. I'm supporting "double density"
|
||||||
|
* (960 dots per 8-inch line).
|
||||||
|
*
|
||||||
|
* My general strategy here is to fill up a line with bits until the
|
||||||
|
* printer thinks it needs to move to the next line; and then do
|
||||||
|
* something with the bits (send them to a printer, a screen, a file,
|
||||||
|
* whatever). This gets both graphics and text modes in one swell foop.
|
||||||
|
*
|
||||||
|
* There is the troublesome "9-pin graphics mode" where each column of
|
||||||
|
* bits is > 1 byte of data; for that, we keep an extra "rowOfPin9"
|
||||||
|
* bits, which is just a bit stream across the width. It would be
|
||||||
|
* easier to make rowOfBits be uint16_t but it would consume more RAM,
|
||||||
|
* and I'm trying to minimize that as I'm down to about 13k of free
|
||||||
|
* space in the Teensy!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FX80_MAXWIDTH 960
|
||||||
|
|
||||||
|
#ifdef TEENSYDUINO
|
||||||
|
class TeensyPrinter;
|
||||||
|
#else
|
||||||
|
class OpenCVPrinter;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Fx80 {
|
||||||
|
public:
|
||||||
|
Fx80();
|
||||||
|
~Fx80();
|
||||||
|
|
||||||
|
void input(uint8_t c);
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void lineFeed();
|
||||||
|
void clearLine();
|
||||||
|
|
||||||
|
void addCharacter(uint8_t c);
|
||||||
|
|
||||||
|
void handleEscape(uint8_t c);
|
||||||
|
void handleActiveEscapeMode(uint8_t c);
|
||||||
|
void emitLine();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool escapeMode;
|
||||||
|
bool proportionalMode;
|
||||||
|
|
||||||
|
uint16_t carriageDot; // what dot-column we are at
|
||||||
|
|
||||||
|
// Line spacing. 1/216th of an inch is 1/3 of a dot, which is the minimum
|
||||||
|
// supported by the FX-80. This is usually set in terms of 72nds, and
|
||||||
|
// it's unlikely that I'll render anything at 1/216, but might as
|
||||||
|
// well interpret it the way the printer understands it.
|
||||||
|
// (That means 8/72, which is a setting of 24 here, is 8 dots tall.)
|
||||||
|
uint16_t twoSixteenthsLineSpacing;
|
||||||
|
|
||||||
|
uint16_t graphicsWidth;
|
||||||
|
bool ninePinGraphics;
|
||||||
|
uint8_t escapeModeActive;
|
||||||
|
int32_t escapeModeExpectingBytes;
|
||||||
|
uint8_t escapeModeLengthByteCount;
|
||||||
|
uint16_t escapeModeLength;
|
||||||
|
|
||||||
|
// 9 pixel-rows of (FX80_MAXWIDTH) bits (stuffed in 8-bit bytes)
|
||||||
|
uint8_t rowOfBits[(FX80_MAXWIDTH/8)*9];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
50
apple/parallelcard.cpp
Normal file
50
apple/parallelcard.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "parallelcard.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "parallel-rom.h"
|
||||||
|
#include "fx80.h"
|
||||||
|
|
||||||
|
ParallelCard::ParallelCard()
|
||||||
|
{
|
||||||
|
fx80 = new Fx80();
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelCard::~ParallelCard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParallelCard::Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ParallelCard::readSwitches(uint8_t s)
|
||||||
|
{
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParallelCard::writeSwitches(uint8_t s, uint8_t v)
|
||||||
|
{
|
||||||
|
if (s == 0x00) {
|
||||||
|
fx80->input(v);
|
||||||
|
} else {
|
||||||
|
// printf("unknown switch 0x%X\n", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParallelCard::loadROM(uint8_t *toWhere)
|
||||||
|
{
|
||||||
|
#ifdef TEENSYDUINO
|
||||||
|
Serial.println("loading parallel slot rom");
|
||||||
|
for (uint16_t i=0; i<=0xFF; i++) {
|
||||||
|
toWhere[i] = pgm_read_byte(&romData[i]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
printf("loading parallel slot rom\n");
|
||||||
|
memcpy(toWhere, romData, 256);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParallelCard::update()
|
||||||
|
{
|
||||||
|
fx80->update();
|
||||||
|
}
|
32
apple/parallelcard.h
Normal file
32
apple/parallelcard.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef __PARALLELCARD_H
|
||||||
|
#define __PARALLELCARD_H
|
||||||
|
|
||||||
|
#ifdef TEENSYDUINO
|
||||||
|
#include <Arduino.h>
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "applemmu.h"
|
||||||
|
#include "slot.h"
|
||||||
|
|
||||||
|
class Fx80;
|
||||||
|
|
||||||
|
class ParallelCard : public Slot {
|
||||||
|
public:
|
||||||
|
ParallelCard();
|
||||||
|
virtual ~ParallelCard();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Fx80 *fx80;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,9 +0,0 @@
|
|||||||
#include "slot.h"
|
|
||||||
|
|
||||||
Slot::Slot()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Slot::~Slot()
|
|
||||||
{
|
|
||||||
}
|
|
@ -11,8 +11,7 @@
|
|||||||
|
|
||||||
class Slot {
|
class Slot {
|
||||||
public:
|
public:
|
||||||
Slot();
|
virtual ~Slot() {};
|
||||||
~Slot();
|
|
||||||
|
|
||||||
virtual void Reset() = 0; // for use at cold-boot
|
virtual void Reset() = 0; // for use at cold-boot
|
||||||
|
|
||||||
|
@ -7,5 +7,6 @@ PhysicalDisplay *g_display = NULL;
|
|||||||
PhysicalKeyboard *g_keyboard = NULL;
|
PhysicalKeyboard *g_keyboard = NULL;
|
||||||
PhysicalSpeaker *g_speaker = NULL;
|
PhysicalSpeaker *g_speaker = NULL;
|
||||||
PhysicalPaddles *g_paddles = NULL;
|
PhysicalPaddles *g_paddles = NULL;
|
||||||
|
PhysicalPrinter *g_printer = NULL;
|
||||||
int16_t g_volume;
|
int16_t g_volume;
|
||||||
uint8_t g_displayType = 3; // FIXME m_perfectcolor
|
uint8_t g_displayType = 3; // FIXME m_perfectcolor
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "physicalkeyboard.h"
|
#include "physicalkeyboard.h"
|
||||||
#include "physicalspeaker.h"
|
#include "physicalspeaker.h"
|
||||||
#include "physicalpaddles.h"
|
#include "physicalpaddles.h"
|
||||||
|
#include "physicalprinter.h"
|
||||||
|
|
||||||
extern FileManager *g_filemanager;
|
extern FileManager *g_filemanager;
|
||||||
extern Cpu *g_cpu;
|
extern Cpu *g_cpu;
|
||||||
@ -15,5 +16,6 @@ extern PhysicalDisplay *g_display;
|
|||||||
extern PhysicalKeyboard *g_keyboard;
|
extern PhysicalKeyboard *g_keyboard;
|
||||||
extern PhysicalSpeaker *g_speaker;
|
extern PhysicalSpeaker *g_speaker;
|
||||||
extern PhysicalPaddles *g_paddles;
|
extern PhysicalPaddles *g_paddles;
|
||||||
|
extern PhysicalPrinter *g_printer;
|
||||||
extern int16_t g_volume;
|
extern int16_t g_volume;
|
||||||
extern uint8_t g_displayType;
|
extern uint8_t g_displayType;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "dummy-speaker.h"
|
#include "dummy-speaker.h"
|
||||||
#include "opencv-paddles.h"
|
#include "opencv-paddles.h"
|
||||||
#include "opencv-filemanager.h"
|
#include "opencv-filemanager.h"
|
||||||
|
#include "opencv-printer.h"
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
@ -247,14 +248,14 @@ static void *cpu_thread(void *dummyptr) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (send_rst) {
|
if (send_rst) {
|
||||||
#if 0
|
#if 1
|
||||||
printf("Sending reset\n");
|
printf("Sending reset\n");
|
||||||
// g_cpu->Reset();
|
g_cpu->Reset();
|
||||||
|
|
||||||
// testing startup keyboard presses - perform Apple //e self-test
|
// testing startup keyboard presses - perform Apple //e self-test
|
||||||
g_vm->getKeyboard()->keyDepressed(RA);
|
//g_vm->getKeyboard()->keyDepressed(RA);
|
||||||
g_vm->Reset();
|
//g_vm->Reset();
|
||||||
g_cpu->Reset();
|
//g_cpu->Reset();
|
||||||
//((AppleVM *)g_vm)->insertDisk(0, "disks/DIAGS.DSK");
|
//((AppleVM *)g_vm)->insertDisk(0, "disks/DIAGS.DSK");
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -293,6 +294,7 @@ static void *cpu_thread(void *dummyptr) {
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
g_speaker = new DummySpeaker();
|
g_speaker = new DummySpeaker();
|
||||||
|
g_printer = new OpenCVPrinter();
|
||||||
|
|
||||||
// create the filemanager - the interface to the host file system.
|
// create the filemanager - the interface to the host file system.
|
||||||
g_filemanager = new OpenCVFileManager();
|
g_filemanager = new OpenCVFileManager();
|
||||||
|
@ -61,7 +61,7 @@ const char *OpenCVFileManager::fileName(int8_t fd)
|
|||||||
return cachedNames[fd];
|
return cachedNames[fd];
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t OpenCVFileManager::readDir(const char *where, const char *suffix, char *outputFN, int8_t startIdx, uint8_t maxlen)
|
int8_t OpenCVFileManager::readDir(const char *where, const char *suffix, char *outputFN, int8_t startIdx, uint16_t maxlen)
|
||||||
{
|
{
|
||||||
// not used in this version
|
// not used in this version
|
||||||
return -1;
|
return -1;
|
||||||
|
75
opencv/opencv-printer.cpp
Normal file
75
opencv/opencv-printer.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include "opencv-printer.h"
|
||||||
|
|
||||||
|
#include "opencv2/core/core.hpp"
|
||||||
|
#include "opencv2/imgproc/imgproc.hpp"
|
||||||
|
#include "opencv2/highgui/highgui.hpp"
|
||||||
|
#include "opencv2/calib3d/calib3d.hpp"
|
||||||
|
#include "opencv2/features2d/features2d.hpp"
|
||||||
|
|
||||||
|
using namespace cv;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define WINDOWNAME "printer"
|
||||||
|
|
||||||
|
#define HEIGHT 800
|
||||||
|
#define NATIVEWIDTH 960 // FIXME: printer can change density...
|
||||||
|
|
||||||
|
|
||||||
|
//#define WIDTH 384 // emulating the teeny printer I've got
|
||||||
|
#define WIDTH 960
|
||||||
|
|
||||||
|
OpenCVPrinter::OpenCVPrinter()
|
||||||
|
{
|
||||||
|
pixels = new Mat(HEIGHT, WIDTH, CV_8U);
|
||||||
|
*pixels = cv::Scalar(0xFF);
|
||||||
|
ypos = 0;
|
||||||
|
isDirty = false;
|
||||||
|
namedWindow(WINDOWNAME, CV_WINDOW_AUTOSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenCVPrinter::~OpenCVPrinter()
|
||||||
|
{
|
||||||
|
delete pixels; pixels = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenCVPrinter::update()
|
||||||
|
{
|
||||||
|
if (isDirty) {
|
||||||
|
imshow(WINDOWNAME, *pixels);
|
||||||
|
isDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenCVPrinter::addLine(uint8_t *rowOfBits)
|
||||||
|
{
|
||||||
|
isDirty = true;
|
||||||
|
for (int yoff=0; yoff<8; yoff++) {
|
||||||
|
// 960 pixels == 120 bytes -- FIXME
|
||||||
|
for (int i=0; i<(NATIVEWIDTH/8); i++) {
|
||||||
|
uint8_t bv = rowOfBits[yoff*120+i];
|
||||||
|
for (int xoff=0; xoff<8; xoff++) {
|
||||||
|
// scale X from "actual FX80" coordinates to "real printer" coordinates
|
||||||
|
uint16_t actualX = (uint16_t)(((float)(i*8+xoff) * (float)WIDTH) / (float)NATIVEWIDTH);
|
||||||
|
|
||||||
|
uint8_t oldPixel = pixels->at<uchar>((ypos + yoff)%HEIGHT, actualX);
|
||||||
|
uint8_t pixelColor = (bv & (1 << (7-xoff))) ? 0x00 : 0xFF;
|
||||||
|
// Make sure to preserve any pixels we've already drawn
|
||||||
|
pixels->at<uchar>((ypos + yoff)%HEIGHT, actualX) = ~(~oldPixel | ~pixelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ypos >= HEIGHT) {
|
||||||
|
ypos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenCVPrinter::moveDownPixels(uint8_t p)
|
||||||
|
{
|
||||||
|
ypos+= p;
|
||||||
|
if (ypos >= HEIGHT) {
|
||||||
|
// clear page & restart
|
||||||
|
*pixels = cv::Scalar(0xFF);
|
||||||
|
ypos = 0;
|
||||||
|
}
|
||||||
|
}
|
31
opencv/opencv-printer.h
Normal file
31
opencv/opencv-printer.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __OPENCV_PRINTER_H
|
||||||
|
#define __OPENCV_PRINTER_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "opencv2/core/core.hpp"
|
||||||
|
#include "opencv2/imgproc/imgproc.hpp"
|
||||||
|
#include "opencv2/highgui/highgui.hpp"
|
||||||
|
#include "opencv2/calib3d/calib3d.hpp"
|
||||||
|
#include "opencv2/features2d/features2d.hpp"
|
||||||
|
|
||||||
|
#include "physicalprinter.h"
|
||||||
|
|
||||||
|
class OpenCVPrinter : public PhysicalPrinter {
|
||||||
|
public:
|
||||||
|
OpenCVPrinter();
|
||||||
|
virtual ~OpenCVPrinter();
|
||||||
|
|
||||||
|
virtual void addLine(uint8_t *rowOfBits); // must be 960 pixels wide (120 bytes)
|
||||||
|
|
||||||
|
virtual void update();
|
||||||
|
|
||||||
|
virtual void moveDownPixels(uint8_t p);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isDirty;
|
||||||
|
uint16_t ypos;
|
||||||
|
cv::Mat *pixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
13
physicalprinter.h
Normal file
13
physicalprinter.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef __PHYSICALPRINTER_H
|
||||||
|
#define __PHYSICALPRINTER_H
|
||||||
|
|
||||||
|
class PhysicalPrinter {
|
||||||
|
public:
|
||||||
|
virtual ~PhysicalPrinter() {}
|
||||||
|
// must be 960 pixels wide (120 bytes)
|
||||||
|
virtual void addLine(uint8_t *rowOfBits) = 0;
|
||||||
|
virtual void update() = 0;
|
||||||
|
virtual void moveDownPixels(uint8_t p) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1
teensy/fx80-font.h
Symbolic link
1
teensy/fx80-font.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../apple/fx80-font.h
|
1
teensy/fx80.cpp
Symbolic link
1
teensy/fx80.cpp
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../apple/fx80.cpp
|
1
teensy/fx80.h
Symbolic link
1
teensy/fx80.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../apple/fx80.h
|
1
teensy/parallel-rom.h
Symbolic link
1
teensy/parallel-rom.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../apple/parallel-rom.h
|
1
teensy/parallelcard.cpp
Symbolic link
1
teensy/parallelcard.cpp
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../apple/parallelcard.cpp
|
1
teensy/parallelcard.h
Symbolic link
1
teensy/parallelcard.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../apple/parallelcard.h
|
1
teensy/physicalprinter.h
Symbolic link
1
teensy/physicalprinter.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../physicalprinter.h
|
78
teensy/teensy-printer.cpp
Normal file
78
teensy/teensy-printer.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "teensy-printer.h"
|
||||||
|
|
||||||
|
#define WIDTH (384) // width of printer, in dots
|
||||||
|
#define NATIVEWIDTH 960 //
|
||||||
|
|
||||||
|
#define RXPIN 57
|
||||||
|
#define TXPIN 56
|
||||||
|
|
||||||
|
TeensyPrinter::TeensyPrinter()
|
||||||
|
{
|
||||||
|
ser = new SoftwareSerial(RXPIN, TXPIN, false);
|
||||||
|
ser->begin(19200);
|
||||||
|
char buf[6] = { 27, '@', // init command '@'
|
||||||
|
27, '3', 8, // ESC-3 is "set line spacing"; default 30
|
||||||
|
0 // terminator
|
||||||
|
};
|
||||||
|
ser->print(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TeensyPrinter::~TeensyPrinter()
|
||||||
|
{
|
||||||
|
delete ser;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TeensyPrinter::update()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TeensyPrinter::addLine(uint8_t *rowOfBits)
|
||||||
|
{
|
||||||
|
static uint8_t linebuf[WIDTH/8]; // output data for one line of pixels
|
||||||
|
|
||||||
|
// The rowOfBits is a set of *rows* of bits. The printer needs *columns*.
|
||||||
|
// Convert and send as necessary.
|
||||||
|
|
||||||
|
// Send bitmap command, followed by bitmap data, followed by linefeed?
|
||||||
|
// ser->write(27); // set line spacing
|
||||||
|
// ser->write('3');
|
||||||
|
// ser->write((uint8_t)30);
|
||||||
|
|
||||||
|
#define DC2 18
|
||||||
|
|
||||||
|
// FIXME: is this 0-6, or 1-7? One of them is empty..
|
||||||
|
// FIXME: also read this off of the print head size/line feed size?
|
||||||
|
for (int yoff=1; yoff<8; yoff++) {
|
||||||
|
memset(linebuf, 0, sizeof(linebuf)); // start clear...
|
||||||
|
for (int i=0; i<(NATIVEWIDTH/8); i++) {
|
||||||
|
uint8_t bv = rowOfBits[yoff*120+i];
|
||||||
|
// Process the 8 bits in this byte
|
||||||
|
for (int xoff=0; xoff<8; xoff++) {
|
||||||
|
// scale X from "actual FX80" coordinates to "real printer" coordinates
|
||||||
|
uint16_t actualX = (uint16_t)(((float)(i*8+xoff) * (float)WIDTH) / (float)NATIVEWIDTH);
|
||||||
|
|
||||||
|
if (bv & (1 << (7-xoff))) { // if it's on in the original
|
||||||
|
// then turn it on in our copy
|
||||||
|
uint8_t bitNum = actualX & 0x07;
|
||||||
|
linebuf[actualX>>3] |= (1<<(7-bitNum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send this line to the printer
|
||||||
|
ser->write(DC2); // send this line as a bitmap
|
||||||
|
ser->write('*');
|
||||||
|
ser->write(1); // FIXME: height
|
||||||
|
ser->write(48); // FIXME: width, in bytes
|
||||||
|
for (int i=0; i<WIDTH/8; i++) {
|
||||||
|
ser->write(linebuf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ser->write(10); // linefeed @ the end
|
||||||
|
}
|
||||||
|
|
||||||
|
void TeensyPrinter::moveDownPixels(uint8_t p)
|
||||||
|
{
|
||||||
|
}
|
25
teensy/teensy-printer.h
Normal file
25
teensy/teensy-printer.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __TEENSY_PRINTER_H
|
||||||
|
#define __TEENSY_PRINTER_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <SoftwareSerial.h>
|
||||||
|
|
||||||
|
#include "physicalprinter.h"
|
||||||
|
|
||||||
|
class TeensyPrinter : public PhysicalPrinter {
|
||||||
|
public:
|
||||||
|
TeensyPrinter();
|
||||||
|
virtual ~TeensyPrinter();
|
||||||
|
|
||||||
|
virtual void addLine(uint8_t *rowOfBits); // must be 960 pixels wide (120 bytes)
|
||||||
|
|
||||||
|
virtual void update();
|
||||||
|
|
||||||
|
virtual void moveDownPixels(uint8_t p);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t ypos;
|
||||||
|
SoftwareSerial *ser;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -5,12 +5,15 @@ use warnings;
|
|||||||
|
|
||||||
my $romfile = shift || die "Must provide the path to an Apple //e ROM image";
|
my $romfile = shift || die "Must provide the path to an Apple //e ROM image";
|
||||||
my $diskrom = shift || die "Must also provide the path to an Apple //e Disk II ROM image";
|
my $diskrom = shift || die "Must also provide the path to an Apple //e Disk II ROM image";
|
||||||
|
my $parallelrom = shift || die "Must also provide the path to an Apple // parallel card ROM image";
|
||||||
|
|
||||||
validate($romfile, 32768, "an Apple //e ROM image");
|
validate($romfile, 32768, "an Apple //e ROM image");
|
||||||
validate($diskrom, 256, "a DiskII ROM image");
|
validate($diskrom, 256, "a DiskII ROM image");
|
||||||
|
validate($parallelrom, 256, "a parallel card ROM image");
|
||||||
|
|
||||||
dumpRom($romfile, "apple/applemmu-rom.h", "romData", 32768);
|
dumpRom($romfile, "apple/applemmu-rom.h", "romData", 32768);
|
||||||
dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256);
|
dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256);
|
||||||
|
dumpRom($parallelrom, "apple/parallel-rom.h", "romData", 256);
|
||||||
exit 0;
|
exit 0;
|
||||||
|
|
||||||
sub validate {
|
sub validate {
|
||||||
@ -38,7 +41,7 @@ sub dumpRom {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
uint8_t romData[32768] PROGMEM = {
|
uint8_t romData[$datasize] PROGMEM = {
|
||||||
EOF
|
EOF
|
||||||
;
|
;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user