1
0
mirror of https://github.com/jscrane/r65emu.git synced 2024-10-28 07:25:06 +00:00

33 support pi pico (#36)

* building for rp2040

* ...

* timer callback for pico

* implement Display for DVI

* bugfix

* dvi

* PS/2 keyboard

* support 1/8/16 bit depths for DVI

* 0-bit depth + bugfix

* resolutions

* bugfix

* cleanup

* centering display
This commit is contained in:
Stephen Crane 2024-10-16 10:19:10 +01:00 committed by GitHub
parent c2e2f44ad3
commit 9690ffb019
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 269 additions and 68 deletions

View File

@ -3,8 +3,6 @@
#undef PC
class Stream;
#define O(o, e) case o: e(); break
#define A(o, e, a) case o: e(a); break
#define C(o) case o:

View File

@ -42,6 +42,49 @@ static const fabgl::RGB888 rgb(colour_t c) {
return Color::BrightWhite;
}
#elif defined(USE_DVI)
#pragma message "PicoDVI configured"
#include <PicoDVI.h>
#if DVI_BIT_DEPTH == 8
static DVIGFX8 dvi(DVI_RESOLUTION, DVI_DOUBLE_BUFFERED, DVI_CONFIG);
#elif DVI_BIT_DEPTH == 0
static DVItext1 dvi(DVI_RESOLUTION, DVI_CONFIG);
#elif DVI_BIT_DEPTH == 1
static DVIGFX1 dvi(DVI_RESOLUTION, DVI_DOUBLE_BUFFERED, DVI_CONFIG);
#elif DVI_BIT_DEPTH == 16
static DVIGFX16 dvi(DVI_RESOLUTION, DVI_CONFIG);
#endif
static const colour_t colours[] = {
BLACK, WHITE, NAVY, DARKGREEN, DARKCYAN, MAROON, PURPLE, OLIVE, LIGHTGREY, DARKGREY, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, ORANGE, GREENYELLOW, PINK,
};
#define NCOLOURS (sizeof(colours) / sizeof(colour_t))
inline int col(colour_t c) {
#if DVI_BIT_DEPTH == 8
for (int i = 0; i < NCOLOURS; i++)
if (c == colours[i])
return i;
return 1;
#elif DVI_BIT_DEPTH == 1 || DVI_BIT_DEPTH == 0
return c != 0;
#elif DVI_BIT_DEPTH == 16
return c;
#endif
}
inline int rot(orientation_t r) {
switch(r) {
case landscape: return 0;
case portrait: return 1;
case reverse_portrait: return 3;
case reverse_landscape: return 2;
}
return 0;
}
#else
#pragma error "Display not configured!"
#endif
@ -53,18 +96,20 @@ static inline void setColor(colour_t c) {
espi.setTextColor(c);
#elif defined(USE_VGA)
canvas.setPenColor(rgb(c));
#elif defined(USE_DVI)
dvi.setTextColor(col(c));
#endif
}
void Display::begin(colour_t bg, colour_t fg, orientation_t orient, unsigned dispx, unsigned dispy) {
begin(bg, fg, orient);
_xoff = (_dx - dispx) / 2;
_yoff = (_dy - dispy) / 2;
_dx -= _xoff;
_dy -= _yoff;
DBG(printf("xoff %d yoff %d dx %d dy %d", _xoff, _yoff, _dx, _dy));
DBG(println());
void Display::setScreen(unsigned sx, unsigned sy) {
if (sx < _w) {
_xoff = (_w - sx) / 2;
_dx = _w - _xoff;
}
if (sy < _h) {
_yoff = (_h - sy) / 2;
_dy = _h - _yoff;
}
}
void Display::begin(colour_t bg, colour_t fg, orientation_t orient) {
@ -88,7 +133,29 @@ void Display::begin(colour_t bg, colour_t fg, orientation_t orient) {
_dx = espi.width();
_dy = espi.height();
_cy = espi.fontHeight();
_cx = 6; // FIXME
_cx = 6;
#elif defined(USE_DVI)
static bool init;
bool success = true;
if (!init)
success = dvi.begin();
init = true;
_dx = dvi.width();
_dy = dvi.height();
// Adafruit_GFX default font size
_cx = 6;
_cy = 8;
dvi.setRotation(rot(orient));
#if DVI_BIT_DEPTH == 8
for (int i = 0; i < NCOLOURS; i++)
dvi.setColor(i, colours[i]);
#endif
DBG(printf("DVI: %d: w %d h %d\r\n", success, _dx, _dy));
#elif defined(USE_VGA)
static bool init;
@ -108,11 +175,13 @@ void Display::begin(colour_t bg, colour_t fg, orientation_t orient) {
_dx = canvas.getWidth();
_dy = canvas.getHeight();
DBG(printf("w %d h %d\r\n", _dx, _dy));
DBG(printf("VGA: w %d h %d\r\n", _dx, _dy));
#endif
setColor(fg);
_oxs = _dx;
_w = _dx;
_h = _dy;
}
void Display::clear() {
@ -122,6 +191,8 @@ void Display::clear() {
espi.fillScreen(_bg);
#elif defined(USE_VGA)
canvas.clear();
#elif defined(USE_DVI)
dvi.fillScreen(_bg);
#endif
}
@ -143,6 +214,14 @@ void Display::status(const char *s) {
canvas.fillRectangle(_dx - _oxs, _dy - _cy, _dx, _dy);
_oxs = canvas.textExtent(s) + _cx;
canvas.drawText(_dx - _oxs, _dy - _cy, s);
#elif defined(USE_DVI)
int16_t x, y;
uint16_t w, h;
dvi.fillRect(_dx - _oxs, _dy - _cy, _oxs, _cy, _bg);
dvi.getTextBounds(s, 0, 0, &x, &y, &w, &h);
dvi.setCursor(_dx - w, _dy - h);
dvi.print(s);
_oxs = _dx - w;
#endif
}
@ -155,103 +234,120 @@ void Display::statusf(const char *fmt, ...) {
status(buf);
}
void Display::drawPixel(unsigned x, unsigned y, colour_t col) {
void Display::drawPixel(unsigned x, unsigned y, colour_t c) {
x += _xoff;
y += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.drawPixel(x, y);
#elif defined(USE_ESPI)
espi.drawPixel(x, y, col);
espi.drawPixel(x, y, c);
#elif defined(USE_VGA)
canvas.setPixel(x, y, rgb(col));
canvas.setPixel(x, y, rgb(c));
#elif defined(USE_DVI)
dvi.drawPixel(x, y, col(c));
#endif
}
void Display::drawLine(unsigned x1, unsigned y1, unsigned x2, unsigned y2, colour_t col) {
void Display::drawLine(unsigned x1, unsigned y1, unsigned x2, unsigned y2, colour_t c) {
x1 += _xoff;
y1 += _yoff;
x2 += _xoff;
y2 += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.drawLine(x1, y1, x2, y2);
#elif defined(USE_ESPI)
espi.drawLine(x1, y1, x2, y2, col);
espi.drawLine(x1, y1, x2, y2, c);
#elif defined(USE_VGA)
canvas.setPenColor(rgb(col));
canvas.setPenColor(rgb(c));
canvas.drawLine(x1, y1, x2, y2);
#elif defined(USE_DVI)
dvi.drawLine(x1, y1, x2, y2, col(c));
#endif
}
void Display::drawCircle(unsigned x, unsigned y, unsigned r, colour_t col) {
void Display::drawCircle(unsigned x, unsigned y, unsigned r, colour_t c) {
x += _xoff;
y += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.drawCircle(x, y, r);
#elif defined(USE_ESPI)
espi.drawCircle(x, y, r, col);
espi.drawCircle(x, y, r, c);
#elif defined(USE_VGA)
canvas.setPenColor(rgb(col));
canvas.setPenColor(rgb(c));
canvas.drawEllipse(x, y, r, r);
#elif defined(USE_DVI)
dvi.drawCircle(x, y, r, col(c));
#endif
}
void Display::fillCircle(unsigned x, unsigned y, unsigned r, colour_t col) {
void Display::fillCircle(unsigned x, unsigned y, unsigned r, colour_t c) {
x += _xoff;
y += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.fillCircle(x, y, r);
#elif defined(USE_ESPI)
espi.fillCircle(x, y, r, col);
espi.fillCircle(x, y, r, c);
#elif defined(USE_VGA)
canvas.setBrushColor(rgb(col));
canvas.setBrushColor(rgb(c));
canvas.fillEllipse(x, y, r, r);
#elif defined(USE_DVI)
dvi.fillCircle(x, y, r, col(c));
#endif
}
void Display::drawRectangle(unsigned x, unsigned y, unsigned w, unsigned h, colour_t col) {
void Display::drawRectangle(unsigned x, unsigned y, unsigned w, unsigned h, colour_t c) {
x += _xoff;
y += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.drawRect(x, y, x+w, y+h);
#elif defined(USE_ESPI)
espi.drawRect(x, y, w, h, col);
espi.drawRect(x, y, w, h, c);
#elif defined(USE_VGA)
canvas.setPenColor(rgb(col));
canvas.setPenColor(rgb(c));
canvas.drawRectangle(x, y, x+w, y+h);
#elif defined(USE_DVI)
dvi.drawRect(x, y, w, h, col(c));
#endif
}
void Display::fillRectangle(unsigned x, unsigned y, unsigned w, unsigned h, colour_t col) {
void Display::fillRectangle(unsigned x, unsigned y, unsigned w, unsigned h, colour_t c) {
x += _xoff;
y += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.fillRect(x, y, x+w, y+h);
#elif defined(USE_ESPI)
espi.fillRect(x, y, w, h, col);
espi.fillRect(x, y, w, h, c);
#elif defined(USE_VGA)
canvas.setBrushColor(rgb(col));
canvas.setBrushColor(rgb(c));
canvas.fillRectangle(x, y, x+w, y+h);
#elif defined(USE_DVI)
dvi.fillRect(x, y, w, h, col(c));
#endif
}
void Display::drawString(const char *s, unsigned x, unsigned y, colour_t col) {
void Display::drawString(const char *s, unsigned x, unsigned y, colour_t c) {
x += _xoff;
y += _yoff;
#if defined(USE_UTFT)
utft.setColor(col);
utft.setColor(c);
utft.print(s, x, y);
#elif defined(USE_ESPI)
espi.setTextDatum(TL_DATUM);
espi.setTextColor(col, _bg, true);
espi.setTextColor(c, _bg, true);
espi.drawString(s, x, y);
#elif defined(USE_VGA)
canvas.setPenColor(rgb(col));
canvas.setPenColor(rgb(c));
canvas.drawText(x, y, s);
#elif defined(USE_DVI)
dvi.setTextColor(col(c));
dvi.setCursor(x, y);
dvi.fillRect(x, y, x+_cx*strlen(s), y+_cy, _bg);
dvi.print(s);
#endif
}

View File

@ -7,6 +7,7 @@ typedef enum {
typedef unsigned colour_t;
// 5-6-5 colours
const colour_t BLACK = 0x0000;
const colour_t NAVY = 0x000F;
const colour_t DARKGREEN = 0x03E0;
@ -29,10 +30,14 @@ const colour_t PINK = 0xFC9F;
class Display {
public:
void begin(colour_t bg, colour_t fg, orientation_t o, unsigned sx, unsigned sy) {
begin(bg, fg, o);
setScreen(sx, sy);
}
void begin(colour_t bg, colour_t fg, orientation_t o);
void begin(colour_t bg, colour_t fg, orientation_t o, unsigned dispx, unsigned dispy);
void setScreen(unsigned sx, unsigned sy);
void clear();
void status(const char *s);
void statusf(const char *fmt, ...);
@ -57,8 +62,21 @@ public:
void drawString(const char *s, unsigned x, unsigned y, colour_t col);
void drawString(const char *s, unsigned x, unsigned y) { drawString(s, x, y, _fg); }
protected:
unsigned _bg, _fg, _cx, _cy, _dx, _dy, _oxs, _xoff, _yoff;
unsigned screenWidth() const { return _dx; }
unsigned screenHeight() const { return _dy; }
unsigned width() const { return _w; }
unsigned height() const { return _h; }
unsigned charWidth() const { return _cx; }
unsigned charHeight() const { return _cy; }
private:
unsigned _bg, _fg;
unsigned _cx, _cy;
unsigned _dx, _dy;
unsigned _oxs, _xoff, _yoff;
unsigned _w, _h;
};
#endif

View File

@ -1,3 +1,6 @@
#if defined(ARDUINO)
#include <Arduino.h>
#endif
#include <stdint.h>
#include "hardware.h"
@ -22,6 +25,10 @@ static File dir;
static Dir dir;
#endif
#if defined(USE_LITTLEFS) && !defined(LITTLEFS_READ_MODE)
#define LITTLEFS_READ_MODE "r+"
#endif
bool flash_file::seek(uint32_t pos)
{
#if defined(USE_SPIFFS) || defined(USE_LITTLEFS)
@ -67,13 +74,12 @@ bool flash_filer::start()
{
#if defined(USE_LITTLEFS)
dir = LittleFS.openDir(_programs);
return true;
#elif defined(USE_SPIFFS)
dir = SPIFFS.open(_programs);
if (!dir)
return false;
return (bool)dir;
#endif
return true;
return false;
}
void flash_filer::stop()
@ -86,25 +92,27 @@ void flash_filer::stop()
const char *flash_filer::advance() {
#if defined(USE_SPIFFS) || defined(USE_LITTLEFS)
files[_current].close();
File &f = files[_current];
f.close();
#if defined(USE_LITTLEFS)
static char buf[32];
while (true) {
if (dir.next()) {
files[_current] = dir.openFile("r+");
DBG(println(dir.fileName()));
if (!dir.isFile())
continue;
f = dir.openFile(LITTLEFS_READ_MODE);
break;
}
dir = LittleFS.openDir(_programs);
dir.rewind();
}
strncpy(buf, dir.fileName().c_str(), sizeof(buf));
return buf;
return f.name();
#else
bool rewound = false;
while (true) {
files[_current] = dir.openNextFile();
if (files[_current]) {
if (files[_current].isDirectory())
files[_current].close();
f = dir.openNextFile();
if (f) {
if (f.isDirectory())
f.close();
else
break;
} else if (!rewound) {
@ -113,7 +121,7 @@ const char *flash_filer::advance() {
} else
return 0;
}
return files[_current].name();
return f.name();
#endif
#else
return 0;
@ -123,6 +131,8 @@ const char *flash_filer::advance() {
const char *flash_filer::rewind() {
#if defined(USE_SPIFFS)
dir.rewindDirectory();
#elif defined(USE_LITTLEFS)
dir.rewind();
#endif
return advance();
}

View File

@ -20,7 +20,7 @@ private:
class flash_filer: public filer, public flash_file {
public:
flash_filer(const char *programs): _programs(programs) {}
flash_filer(const char *programs): _programs(programs), _current(0) {}
const char *advance();
const char *rewind();

View File

@ -28,7 +28,7 @@ spiram sram(SPIRAM_SIZE);
static CPU *_cpu;
bool hardware_reset() {
bool success = true;
bool success = false;
#if defined(USE_SPIRAM)
extern SPIClass SPIRAM_DEV;
@ -71,6 +71,8 @@ void hardware_init(CPU &cpu) {
#if defined(DEBUGGING) || defined(CPU_DEBUG) || defined(USE_SERIAL)
Serial.begin(TERMINAL_SPEED);
while (!Serial);
delay(800);
#endif
#if defined(TFT_BACKLIGHT)

View File

@ -0,0 +1,64 @@
// Adafruit Feather DVI
// https://www.adafruit.com/product/5710
// FIXME:
// #define DAC_SOUND
// see https://arduino-pico.readthedocs.io/en/stable/i2s.html
#if !defined(PWM_SOUND)
#define PWM_SOUND 25
#endif
// PS/2 keyboard
// Note: this requires the keyboard to operate at 3.3v (e.g., Dell QuietKey)
// https://github.com/lurk101/pico-ps2kbd
// GPIO14 is labelled SCK and GPIO15 MO on the board
// https://learn.adafruit.com/assets/119662
#if !defined(USE_OWN_KBD)
#define USE_PS2_KBD
#endif
#if !defined(PS2_KBD_DATA)
#define PS2_KBD_DATA 14
#endif
#if !defined(PS2_KBD_IRQ)
#define PS2_KBD_IRQ 15
#endif
// Display
// https://cdn-learn.adafruit.com/downloads/pdf/picodvi-arduino-library-video-out-for-rp2040-boards.pdf
#define USE_DVI
#define DVI_CONFIG adafruit_feather_dvi_cfg
#if !defined(DVI_BIT_DEPTH)
#define DVI_BIT_DEPTH 8
//#define DVI_BIT_DEPTH 0 // 1-bit text
//#define DVI_BIT_DEPTH 1
//#define DVI_BIT_DEPTH 16
#endif
#if !defined(DVI_RESOLUTION)
#define DVI_RESOLUTION DVI_RES_320x240p60
//#define DVI_RESOLUTION DVI_RES_640x480p60
//#define DVI_RESOLUTION DVI_RES_400x240p60
//#define DVI_RESOLUTION DVI_RES_640x240p60
//#define DVI_RESOLUTION DVI_RES_800x480p60
#endif
#if !defined(DVI_DOUBLE_BUFFERED)
#define DVI_DOUBLE_BUFFERED false
//#define DVI_DOUBLE_BUFFERED true
#endif
// 64kB RAM
#define RAM_SIZE 0x10000u
#if !defined(NO_STORAGE) && !defined(USE_SD)
#undef USE_SD
#undef USE_SPIFFS
#define USE_LITTLEFS
#endif
// see https://github.com/jscrane/r65emu/issues/34
#if defined(USE_LITTLEFS)
#define LITTLEFS_READ_MODE "r"
#endif

View File

@ -1,3 +1,6 @@
#if defined(ARDUINO)
#include <Arduino.h>
#endif
#include <stdint.h>
#include "memory.h"

View File

@ -1,8 +1,6 @@
#ifndef __MEMORY_H__
#define __MEMORY_H__
class Stream;
class Checkpointable {
public:
virtual void checkpoint(Stream &s) = 0;

View File

@ -11,7 +11,7 @@ inline bool c1_high_to_low(uint8_t cr) { return !c1_low_to_high(cr); }
inline bool c2_output(uint8_t cr) { return cr & 0x20; }
inline bool c2_input(uint8_t cr) { return !c2_input(cr); }
inline bool c2_input(uint8_t cr) { return !c2_output(cr); }
inline bool c2_low_to_high(uint8_t cr) { return cr & 0x10; }

View File

@ -4,7 +4,6 @@
#undef PC
#undef cli
#undef sei
class Stream;
class r6502: public CPU {
public:

View File

@ -1,8 +1,6 @@
#ifndef __SERIAL_FILER_H__
#define __SERIAL_FILER_H__
class HardwareSerial;
// see https://playground.arduino.cc/Interfacing/LinuxTTY
// FIXME: do this in minicom config file
class serial_filer: public filer {

View File

@ -47,4 +47,19 @@ void timer_create(unsigned freq, handler_t handler) {
os_timer_setfn(&t, (os_timer_func_t *)handler, 0);
os_timer_arm(&t, 1000 / freq, true);
}
#elif defined(ARDUINO_ARCH_rp2040)
static handler_t client_handler;
static int64_t period;
int64_t alarm_callback(alarm_id_t, void *) {
client_handler();
return -period;
}
void timer_create(unsigned freq, handler_t handler) {
period = 1000000 / freq;
client_handler = handler;
add_alarm_in_us(period, alarm_callback, 0, false);
}
#endif