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
|
||||
disk.rom
|
||||
parallel.rom
|
||||
*~
|
||||
*.o
|
||||
apple/applemmu-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
|
||||
|
||||
CXXFLAGS=-Wall -I .. -I . -I apple -O3
|
||||
CXXFLAGS=-Wall -I .. -I . -I apple -I opencv -O3
|
||||
|
||||
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
|
||||
|
||||
@ -14,17 +14,18 @@ opencv: roms $(OPENCVOBJS)
|
||||
g++ $(LDFLAGS) -o aiie-opencv $(OPENCVOBJS)
|
||||
|
||||
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)
|
||||
g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic
|
||||
g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose
|
||||
g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended
|
||||
|
||||
roms: apple2e.rom disk.rom
|
||||
./util/genrom.pl apple2e.rom disk.rom
|
||||
roms: apple2e.rom disk.rom parallel.rom
|
||||
./util/genrom.pl apple2e.rom disk.rom parallel.rom
|
||||
|
||||
apple/applemmu-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
|
||||
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
|
||||
* 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
|
||||
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
|
||||
|
||||
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
|
||||
-or-
|
||||
d666ea749f79a35faa31b4e9a7878eb7 parallel.rom
|
||||
|
||||
From those, the appropriate headers will be automatically generated by
|
||||
"make roms" (or any other target that relies on the ROMs).
|
||||
|
||||
|
@ -19,6 +19,10 @@ AppleVM::AppleVM()
|
||||
((AppleMMU *)mmu)->setSlot(6, disk6);
|
||||
|
||||
keyboard = new AppleKeyboard((AppleMMU *)mmu);
|
||||
|
||||
parallel = new ParallelCard();
|
||||
((AppleMMU *)mmu)->setSlot(1, parallel);
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
teensyClock = new TeensyClock((AppleMMU *)mmu);
|
||||
((AppleMMU *)mmu)->setSlot(7, teensyClock);
|
||||
@ -51,6 +55,7 @@ void AppleVM::cpuMaintenance(uint32_t cycles)
|
||||
}
|
||||
|
||||
keyboard->maintainKeyboard(cycles);
|
||||
parallel->update();
|
||||
}
|
||||
|
||||
void AppleVM::Reset()
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "appledisplay.h"
|
||||
#include "diskii.h"
|
||||
#include "vmkeyboard.h"
|
||||
#include "parallelcard.h"
|
||||
#ifdef TEENSYDUINO
|
||||
#include "teensy-clock.h"
|
||||
#endif
|
||||
@ -32,6 +33,7 @@ class AppleVM : public VM {
|
||||
protected:
|
||||
DiskII *disk6;
|
||||
VMKeyboard *keyboard;
|
||||
ParallelCard *parallel;
|
||||
#ifdef TEENSYDUINO
|
||||
TeensyClock *teensyClock;
|
||||
#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 {
|
||||
public:
|
||||
Slot();
|
||||
~Slot();
|
||||
virtual ~Slot() {};
|
||||
|
||||
virtual void Reset() = 0; // for use at cold-boot
|
||||
|
||||
|
@ -7,5 +7,6 @@ PhysicalDisplay *g_display = NULL;
|
||||
PhysicalKeyboard *g_keyboard = NULL;
|
||||
PhysicalSpeaker *g_speaker = NULL;
|
||||
PhysicalPaddles *g_paddles = NULL;
|
||||
PhysicalPrinter *g_printer = NULL;
|
||||
int16_t g_volume;
|
||||
uint8_t g_displayType = 3; // FIXME m_perfectcolor
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "physicalkeyboard.h"
|
||||
#include "physicalspeaker.h"
|
||||
#include "physicalpaddles.h"
|
||||
#include "physicalprinter.h"
|
||||
|
||||
extern FileManager *g_filemanager;
|
||||
extern Cpu *g_cpu;
|
||||
@ -15,5 +16,6 @@ extern PhysicalDisplay *g_display;
|
||||
extern PhysicalKeyboard *g_keyboard;
|
||||
extern PhysicalSpeaker *g_speaker;
|
||||
extern PhysicalPaddles *g_paddles;
|
||||
extern PhysicalPrinter *g_printer;
|
||||
extern int16_t g_volume;
|
||||
extern uint8_t g_displayType;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "dummy-speaker.h"
|
||||
#include "opencv-paddles.h"
|
||||
#include "opencv-filemanager.h"
|
||||
#include "opencv-printer.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
@ -247,14 +248,14 @@ static void *cpu_thread(void *dummyptr) {
|
||||
#endif
|
||||
|
||||
if (send_rst) {
|
||||
#if 0
|
||||
#if 1
|
||||
printf("Sending reset\n");
|
||||
// g_cpu->Reset();
|
||||
g_cpu->Reset();
|
||||
|
||||
// testing startup keyboard presses - perform Apple //e self-test
|
||||
g_vm->getKeyboard()->keyDepressed(RA);
|
||||
g_vm->Reset();
|
||||
g_cpu->Reset();
|
||||
//g_vm->getKeyboard()->keyDepressed(RA);
|
||||
//g_vm->Reset();
|
||||
//g_cpu->Reset();
|
||||
//((AppleVM *)g_vm)->insertDisk(0, "disks/DIAGS.DSK");
|
||||
|
||||
#else
|
||||
@ -293,6 +294,7 @@ static void *cpu_thread(void *dummyptr) {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_speaker = new DummySpeaker();
|
||||
g_printer = new OpenCVPrinter();
|
||||
|
||||
// create the filemanager - the interface to the host file system.
|
||||
g_filemanager = new OpenCVFileManager();
|
||||
|
@ -61,7 +61,7 @@ const char *OpenCVFileManager::fileName(int8_t 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
|
||||
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 $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($diskrom, 256, "a DiskII ROM image");
|
||||
validate($parallelrom, 256, "a parallel card ROM image");
|
||||
|
||||
dumpRom($romfile, "apple/applemmu-rom.h", "romData", 32768);
|
||||
dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256);
|
||||
dumpRom($parallelrom, "apple/parallel-rom.h", "romData", 256);
|
||||
exit 0;
|
||||
|
||||
sub validate {
|
||||
@ -38,7 +41,7 @@ sub dumpRom {
|
||||
#endif
|
||||
|
||||
static
|
||||
uint8_t romData[32768] PROGMEM = {
|
||||
uint8_t romData[$datasize] PROGMEM = {
|
||||
EOF
|
||||
;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user