Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions fujinet_pc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ set(SOURCES src/main.cpp
lib/network-protocol/Protocol.h lib/network-protocol/Protocol.cpp
lib/network-protocol/ProtocolParser.h lib/network-protocol/ProtocolParser.cpp
lib/network-protocol/CPM.h lib/network-protocol/CPM.cpp
# Single shared RunCPM core (one Z80/CP/M state + engine). Compiled on every
# target because the N:CPM:// device (CPM.cpp, above) is available on all of
# them; the SIO 'G' and telnet transports that also drive it are ATARI-only.
lib/runcpm/runcpm_session.h lib/runcpm/runcpm_core.cpp
lib/network-protocol/GDRIVE.h lib/network-protocol/GDRIVE.cpp
lib/network-protocol/Test.h lib/network-protocol/Test.cpp
lib/network-protocol/TCP.h lib/network-protocol/TCP.cpp
Expand Down
92 changes: 64 additions & 28 deletions lib/device/drivewire/cpm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

#ifdef ESP_PLATFORM

#define CCP_INTERNAL
/*
* drivewire/cpm.cpp — CoCo DriveWire CP/M transport: a thin console back-end
* for the shared RunCPM core (lib/runcpm/runcpm_core.cpp). Supplies a
* queue-based console over the DriveWire rx/tx queues and runs a session.
*/

#include "cpm.h"

Expand All @@ -12,38 +16,70 @@
#include "fnFS.h"
#include "fnFsSD.h"

#include "../runcpm/globals.h"
#include "../runcpm/abstraction_fujinet_apple2.h"
#include "../runcpm/ram.h" // ram.h - Implements the RAM
#include "../runcpm/console.h" // console.h - implements console.
#include "../runcpm/cpu.h" // cpu.h - Implements the emulated CPU
#include "../runcpm/disk.h" // disk.h - Defines all the disk access abstraction functions
#include "../runcpm/host.h" // host.h - Custom host-specific BDOS call
#include "../runcpm/cpm.h" // cpm.h - Defines the CPM structures and calls
#ifdef CCP_INTERNAL
# include "../runcpm/ccp.h" // ccp.h - Defines a simple internal CCP
#endif
#include "../runcpm/runcpm_session.h"

/*
* DriveWire console queues (this TU owns them).
* rxq : CP/M stdout -> host read (putch pushes; read() pops)
* txq : host write -> CP/M stdin (write() pushes; getch pops)
*/
static QueueHandle_t rxq = nullptr;
static QueueHandle_t txq = nullptr;

/* ----- console back-end (runcpm_console_ops) ----- */

static int cpm_kbhit(void)
{
return txq ? (int)uxQueueMessagesWaiting(txq) : 0;
}

static int cpm_getch(void)
{
uint8_t c = 0;
if (txq)
xQueueReceive(txq, &c, portMAX_DELAY);
return c;
}

static int cpm_getche(void)
{
uint8_t c = (uint8_t)cpm_getch();
if (rxq)
xQueueSend(rxq, &c, portMAX_DELAY);
return c;
}

static void cpm_putch(uint8_t ch)
{
if (rxq)
xQueueSend(rxq, &ch, portMAX_DELAY);
}

static void cpm_clrscr(void)
{
/* VT100 cursor-home + clear-screen */
static const uint8_t seq[] = {0x1B, '[', '1', ';', '1', 'H',
0x1B, '[', '2', 'J'};
for (size_t i = 0; i < sizeof(seq); i++)
cpm_putch(seq[i]);
}

static const runcpm_console_ops cpm_console_ops = {
cpm_getch,
cpm_getche,
cpm_kbhit,
cpm_putch,
cpm_clrscr,
};

static void cpmTask(void *arg)
{
(void)arg;
Debug_printf("cpmTask()\n");
// The shared core owns the CCP + warm-boot loop; keep re-running it so the
// DriveWire console behaves like the original always-on task.
while (1)
{
Status = Debug = 0;
Break = Step = -1;
RAM = (uint8_t *)malloc(MEMSIZE);
memset(RAM, 0, MEMSIZE);
memset(filename, 0, sizeof(filename));
memset(newname, 0, sizeof(newname));
memset(fcbname, 0, sizeof(fcbname));
memset(pattern, 0, sizeof(pattern));
#ifdef ESP_PLATFORM // OS
vTaskDelay(100);
#endif
_puts(CCPHEAD);
_PatchCPM();
_ccp();
}
runcpm_session_run(&cpm_console_ops);
}

drivewireCPM::drivewireCPM()
Expand Down
111 changes: 85 additions & 26 deletions lib/device/iwm/cpm.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#ifdef BUILD_APPLE
#define CCP_INTERNAL

/*
* iwm/cpm.cpp — Apple II SmartPort CP/M transport: a thin console back-end for
* the shared RunCPM core (lib/runcpm/runcpm_core.cpp). Supplies a queue-based
* console over the SmartPort rx/tx queues and runs a session on the core.
*/

#include "cpm.h"

Expand All @@ -11,39 +16,93 @@
#include "fnConfig.h"
#include "compat_string.h"

#include "../runcpm/abstraction_fujinet_apple2.h"

#include "../runcpm/globals.h"
#include "../runcpm/ram.h" // ram.h - Implements the RAM
#include "../runcpm/console.h" // console.h - implements console.
#include "../runcpm/cpu.h" // cpu.h - Implements the emulated CPU
#include "../runcpm/disk.h" // disk.h - Defines all the disk access abstraction functions
#include "../runcpm/host.h" // host.h - Custom host-specific BDOS call
#include "../runcpm/cpm.h" // cpm.h - Defines the CPM structures and calls
#ifdef CCP_INTERNAL
#include "../runcpm/ccp.h" // ccp.h - Defines a simple internal CCP
#endif
#include "../hardware/led.h"

#include "../runcpm/runcpm_session.h"

#define CPM_TASK_PRIORITY 10

/*
* SmartPort console queues (this TU owns them).
* rxq : CP/M stdout -> host read (putch pushes; iwm_read pops)
* txq : host write -> CP/M stdin (iwm_write pushes; getch pops)
* They are FreeRTOS queues, so they only exist on the ESP target; on
* FujiNet-PC the Apple-II CP/M console is inert (as it was before).
*/
#ifdef ESP_PLATFORM // OS
static QueueHandle_t rxq = nullptr;
static QueueHandle_t txq = nullptr;
#endif

/* ----- console back-end (runcpm_console_ops) ----- */

static int cpm_kbhit(void)
{
#ifdef ESP_PLATFORM // OS
return txq ? (int)uxQueueMessagesWaiting(txq) : 0;
#else
return 0;
#endif
}

static int cpm_getch(void)
{
uint8_t c = 0;
#ifdef ESP_PLATFORM // OS
if (txq)
xQueueReceive(txq, &c, portMAX_DELAY);
#endif
return c;
}

static int cpm_getche(void)
{
uint8_t c = (uint8_t)cpm_getch();
#ifdef ESP_PLATFORM // OS
if (rxq)
xQueueSend(rxq, &c, portMAX_DELAY);
#endif
return c;
}

static void cpm_putch(uint8_t ch)
{
#ifdef ESP_PLATFORM // OS
if (rxq)
xQueueSend(rxq, &ch, portMAX_DELAY);
#else
(void)ch;
#endif
}

static void cpm_clrscr(void)
{
/* VT100 cursor-home + clear-screen */
static const uint8_t seq[] = {0x1B, '[', '1', ';', '1', 'H',
0x1B, '[', '2', 'J'};
for (size_t i = 0; i < sizeof(seq); i++)
cpm_putch(seq[i]);
}

static const runcpm_console_ops cpm_console_ops = {
cpm_getch,
cpm_getche,
cpm_kbhit,
cpm_putch,
cpm_clrscr,
};

#ifdef ESP_PLATFORM // OS
static void cpmTask(void *arg)
{
(void)arg;
Debug_printf("cpmTask()\n");
// The shared core owns the CCP + warm-boot loop; keep re-running it so the
// SmartPort console behaves like the original always-on task.
while (1)
{
Status = Debug = 0;
Break = Step = -1;
RAM = (uint8_t *)malloc(MEMSIZE);
memset(RAM, 0, MEMSIZE);
memset(filename, 0, sizeof(filename));
memset(newname, 0, sizeof(newname));
memset(fcbname, 0, sizeof(fcbname));
memset(pattern, 0, sizeof(pattern));
_puts(CCPHEAD);
_PatchCPM();
_ccp();
}
runcpm_session_run(&cpm_console_ops);
}
#endif

iwmCPM::iwmCPM()
{
Expand Down
102 changes: 54 additions & 48 deletions lib/device/rc2014/rc2014cpm.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,56 @@
#ifdef BUILD_RC2014

#define CCP_INTERNAL
/*
* rc2014cpm.cpp — RC2014 CP/M transport: a thin console back-end for the shared
* RunCPM core (lib/runcpm/runcpm_core.cpp). The RC2014 bus has no
* character-stream console, so the back-end is a no-op stub (see below).
*/

#include "rc2014cpm.h"

#include <string.h>

#include "fnSystem.h"
#include "fnWiFi.h"
#include "fujiDevice.h"
#include "fnFS.h"
#include "fnFsSD.h"

#include "../runcpm/globals.h"
#include "../runcpm/abstraction_fujinet.h"
#include "../runcpm/ram.h" // ram.h - Implements the RAM
#include "../runcpm/console.h" // console.h - implements console.
#include "../runcpm/cpu.h" // cpu.h - Implements the emulated CPU
#include "../runcpm/disk.h" // disk.h - Defines all the disk access abstraction functions
#include "../runcpm/host.h" // host.h - Custom host-specific BDOS call
#include "../runcpm/cpm.h" // cpm.h - Defines the CPM structures and calls
#ifdef CCP_INTERNAL
# include "../runcpm/ccp.h" // ccp.h - Defines a simple internal CCP
#endif

#include "../runcpm/runcpm_session.h"

/* console back-end: the RC2014 bus has no character-stream console (it never
* had a working one), so these ops are no-ops; getch returns CP/M EOF (^Z) so
* the session ends gracefully instead of busy-looping. */

static int rc2014_kbhit(void)
{
return 0;
}

static int rc2014_getch(void)
{
return 0x1a; /* ^Z / CP/M EOF */
}

static int rc2014_getche(void)
{
return rc2014_getch();
}

static void rc2014_putch(uint8_t ch)
{
(void)ch;
}

static void rc2014_clrscr(void)
{
}

static const runcpm_console_ops rc2014_console_ops = {
rc2014_getch,
rc2014_getche,
rc2014_kbhit,
rc2014_putch,
rc2014_clrscr,
};

/* =========================== rc2014CPM device ========================== */

void rc2014CPM::rc2014_status()
{
Expand All @@ -31,41 +60,18 @@ void rc2014CPM::rc2014_status()

void rc2014CPM::rc2014_handle_cpm()
{
_puts(CCPHEAD);
_PatchCPM();
Status = 0;
#ifdef CCP_INTERNAL
_ccp();
#else
if (!_sys_exists((uint8 *)CCPname))
{
_puts("Unable to load CP/M CCP.\r\nCPU halted.\r\n");
break;
}
_RamLoad((uint8 *)CCPname, CCPaddr); // Loads the CCP binary file into memory
Z80reset(); // Resets the Z80 CPU
SET_LOW_REGISTER(BC, _RamRead(0x0004)); // Sets C to the current drive/user
PC = CCPaddr; // Sets CP/M application jump point
Z80run(); // Starts simulation
#endif
if (Status == 1) // This is set by a call to BIOS 0 - ends CP/M
{
cpmActive = false;
free(RAM);
}
// Run a full CP/M session on the shared core using the RC2014 console.
// Blocks until the session ends; the bus service loop then stops calling
// us because cpmActive is cleared.
runcpm_session_run(&rc2014_console_ops);
cpmActive = false;
}

void rc2014CPM::init_cpm(int baud)
{
// fnUartBUS.set_baudrate(baud); // RC2014 SPI bus does not use UART
Status = Debug = 0;
Break = Step = -1;
RAM = (uint8_t *)malloc(MEMSIZE);
memset(RAM, 0, MEMSIZE);
memset(filename, 0, sizeof(filename));
memset(newname, 0, sizeof(newname));
memset(fcbname, 0, sizeof(fcbname));
memset(pattern, 0, sizeof(pattern));
// RAM/globals are owned by the shared core now; the RC2014 SPI bus does not
// use a UART baud rate, so nothing transport-specific to set up here.
(void)baud;
}

void rc2014CPM::rc2014_process(uint32_t commanddata, uint8_t checksum)
Expand Down
Loading
Loading