Skip to content

Commit

Permalink
Merge branch 'MockbaTheBorg:master' into streamio
Browse files Browse the repository at this point in the history
  • Loading branch information
pzembrod authored May 7, 2024
2 parents 0449a56 + 3771101 commit 801715b
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 11 deletions.
57 changes: 47 additions & 10 deletions RunCPM/ccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ bool sFlag = FALSE; // Submit Flag
uint8 sRecs = 0; // Number of records on the Submit file
uint8 prompt[8] = "\r\n >";
uint16 pbuf, perr;
uint8 blen; // Actual size of the typed command line (size of the buffer)
uint8 blen = 0; // Actual size of the typed command line (size of the buffer)

static const char *Commands[] =
{
Expand Down Expand Up @@ -685,22 +685,54 @@ void _ccp(void) {
sFlag = (bool)_ccp_bdos(DRV_ALLRESET, 0x0000);
_ccp_bdos(DRV_SET, curDrive);

for (i = 0; i < 36; ++i)
for (i = 0; i < 36; ++i) {
_RamWrite(BatchFCB + i, _RamRead(tmpFCB + i));

}

// Loads an autoexec file if it exists and this is the first boot
// The file contents are loaded at ccpAddr+8 up to 126 bytes then the size loaded is stored at ccpAddr+7
if (firstBoot && !sFlag) {
uint8 dmabuf[128];
uint16 cmd = inBuf + 1;
if (_sys_exists((uint8*)AUTOEXEC)) {
FILE* file = _sys_fopen_r((uint8*)AUTOEXEC);
blen = (uint8)_sys_fread(&dmabuf[0], 1, 128, file);
int count = 0;
if (blen) {
for (int i = 0; i < 126; ++i) {
_RamWrite(cmd + 1 + i, 0x00);
if (dmabuf[i] == 0x0D || dmabuf[i] == 0x0A || dmabuf[i] == 0x1A || dmabuf[i] == 0x00) {
break;
}
_RamWrite(cmd + 1 + i, dmabuf[i]);
count++;
}
}
_RamWrite(cmd, count);
_sys_fclose(file);
}
if (BOOTONLY)
firstBoot = FALSE;
} else {
_RamWrite(inBuf, 0); // Clears the buffer
_RamWrite(inBuf + 1, 0); // Clears the buffer
blen = 0;
}

while (TRUE) {
curDrive = (uint8)_ccp_bdos(DRV_GET, 0x0000); // Get current drive
curUser = (uint8)_ccp_bdos(F_USERNUM, 0x00FF); // Get current user
_RamWrite(DSKByte, (curUser << 4) + curDrive); // Set user/drive on addr DSKByte

parDrive = curDrive; // Initially the parameter drive is the same as the current drive

sprintf((char *) prompt, "\r\n%c%u%c", 'A' + curDrive, curUser, sFlag ? '$' : '>');
_puts((char *)prompt);

_RamWrite(inBuf, cmdLen); // Sets the buffer size to read the command line
_ccp_readInput();

if(!blen){
_puts((char *)prompt);

_RamWrite(inBuf, cmdLen); // Sets the buffer size to read the command line
_ccp_readInput();
}
blen = _RamRead(inBuf + 1); // Obtains the number of bytes read

_ccp_bdos(F_DMAOFF, defDMA); // Reset current DMA
Expand All @@ -714,8 +746,10 @@ void _ccp(void) {
}
if (!blen) // There were only spaces
continue;
if (_RamRead(pbuf) == ';') // Found a comment line
if (_RamRead(pbuf) == ';') { // Found a comment line
blen = 0; // Ignore the rest of the line
continue;
}

// parse for DU: command line shortcut
bool errorFlag = FALSE, continueFlag = FALSE;
Expand Down Expand Up @@ -757,16 +791,19 @@ void _ccp(void) {
}
if (errorFlag) {
_ccp_cmdError(); // print command error
blen = 0; // ignore the rest of the line
continue;
}
if (continueFlag) {
blen = 0; // ignore the rest of the line
continue;
}
_ccp_initFCB(CmdFCB, 36); // Initializes the command FCB

perr = pbuf; // Saves the pointer in case there's an error
if (_ccp_nameToFCB(CmdFCB) > 8) { // Extracts the command from the buffer
_ccp_cmdError(); // Command name cannot be non-unique or have an extension
blen = 0; // ignore the rest of the line
continue;
}
_RamWrite(defDMA, blen); // Move the command line at this point to 0x0080
Expand Down
7 changes: 6 additions & 1 deletion RunCPM/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#define USE_LST

/* Definitions for file/console based debugging */
//#define DEBUG // Enables the internal debugger (enabled by default on vstudio debug builds)
#define DEBUG // Enables the internal debugger (enabled by default on vstudio debug builds)
//#define DEBUGONHALT // Enables the internal debugger when the CPU halts
//#define iDEBUG // Enables instruction logging onto iDebug.log (for development debug only)
//#define DEBUGLOG // Writes extensive call trace information to RunCPM.log
Expand Down Expand Up @@ -224,6 +224,11 @@ static uint16 physicalExtentBytes;// # bytes described by 1 directory entry

#define tohex(x) ((x) < 10 ? (x) + 48 : (x) + 87)

/* definition of an autoexec functionality */
static uint8 firstBoot = TRUE; // True if this is the first boot
#define AUTOEXEC "AUTOEXEC.TXT" // Name of the autoexec file
#define BOOTONLY FALSE // If TRUE, the autoexec file will only be loaded on the first boot

static uint32 timer;

#ifdef STREAMIO
Expand Down
28 changes: 28 additions & 0 deletions RunCPM/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,34 @@ int main(int argc, char* argv[]) {
break;
}
_RamLoad((uint8*)CCPname, CCPaddr); // Loads the CCP binary file into memory

// Loads an autoexec file if it exists and this is the first boot
// The file contents are loaded at ccpAddr+8 up to 126 bytes then the size loaded is stored at ccpAddr+7
if (firstBoot an not sFlag) {
uint8 dmabuf[128];
uint8 bytesread;
uint16 cmd = CCPaddr + 7;
if (_sys_exists((uint8*)AUTOEXEC)) {
FILE* file = _sys_fopen_r((uint8*)AUTOEXEC);
bytesread = (uint8)_sys_fread(&dmabuf[0], 1, 128, file);
int count = 0;
if (bytesread) {
for (int i = 0; i < 126; ++i) {
_RamWrite(cmd + 1 + i, 0x00);
if (dmabuf[i] == 0x0D || dmabuf[i] == 0x0A || dmabuf[i] == 0x1A || dmabuf[i] == 0x00) {
break;
}
_RamWrite(cmd + 1 + i, dmabuf[i]);
count++;
}
}
_RamWrite(cmd, count);
_sys_fclose(file);
}
if (BOOTONLY)
firstBoot = FALSE;
}

Z80reset(); // Resets the Z80 CPU
SET_LOW_REGISTER(BC, _RamRead(DSKByte)); // Sets C to the current drive/user
PC = CCPaddr; // Sets CP/M application jump point
Expand Down
6 changes: 6 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ Disks created by **FORMAT** cannot be removed from inside RunCPM itself, if need
The master disk also contains **Z80ASM**, which is a very powerful Z80 assembly that generates .COM files directly.<br>
Other CP/M applications which were not part of the official DRI's distribution are also provided to improve the RunCPM experience. These applications are listed on the 1STREAD.ME file.

## Automation

If a single line text file named AUTOEXEC.TXT containing a CP/M command up to 125 characters long is placed onto the same folder as the RunCPM executable, the command on this file will be loaded onto the CCP buffer, emulating the patch of the CCP sector on a real CP/M disk.<br>
This command will then be executed every time the CCP is restarted or once when RunCPM loads, which is configurable in the globals.h header file.

## Printing

Printing to the PUN: and LST: devices is allowed and will generate files called "PUN.TXT" and "LST.TXT" under user area 0 of disk A:. These files can then be tranferred over to a host computer via XMODEM for real physical printing.
Expand Down Expand Up @@ -300,6 +305,7 @@ I dedicate it also to the memory of some awesome people who unfortunately are no
* *Mr. Jon Saxton* - For finding the very first RunCPM bug back in 2014.<br>
* *Dr. Richard Walters* - For writing the Z80 version of mumps, one of the most useful and fun languages I had the joy to use.<br>
* *Mr. Tom L. Burnett* - For helping me with testing/debugging many different CP/M 2.2 applications on RunCPM.<br>

May the computers in heaven be all 8-bit.<br>

## Donations
Expand Down
92 changes: 92 additions & 0 deletions tools/gensub.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
gensub - Generates a $$$.SUB file from a text file passed as argument and saves it to a destination also passed as argument.
Usage: gensub <source> <destination>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 128

int main(int argc, char* argv[]) {
// Check if the user passed a file as argument
if (argc < 2) {
printf("Usage: %s <filename> <destination>\n", argv[0]);
return 1;
}

// Check if the user passed a destination as argument
if (argc < 3) {
printf("Usage: %s <filename> <destination>\n", argv[0]);
return 1;
}

// Open the input file
FILE* file = fopen(argv[1], "r");
if (file == NULL) {
printf("Error: Could not open input file %s\n", argv[1]);
return 1;
}
// Count the number of lines in the file
int lines = 0;
char buffer[BUFSIZE];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
lines++;
}
// Reset the file pointer
fseek(file, 0, SEEK_SET);

// Check if the file is empty
if (lines == 0) {
printf("Error: File is empty\n");
fclose(file);
return 1;
}

// Allocate 128 bytes for each axisting line
char* subfile = (char*)malloc(lines * 128);
if (subfile == NULL) {
printf("Error: Could not allocate memory\n");
fclose(file);
return 1;
}

// Read the file line by line and copy it to the subfile buffer in reverse order of 128 byte blocks
int offset = (lines - 1) * 128;
while (fgets(buffer, sizeof(buffer), file) != NULL) {
int len = strlen(buffer);
if (len > 0) {
if (buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
len--;
}
}
if (len > 0) {
if (buffer[len - 1] == '\r') {
buffer[len - 1] = '\0';
len--;
}
}
subfile[offset] = len;
memcpy(subfile + offset + 1, buffer, len);
offset -= 128;
}

// Close the input file
fclose(file);

// Write the subfile buffer to the destination file
FILE* dest = fopen(argv[2], "w");
if (dest == NULL) {
printf("Error: Could not open output file %s\n", argv[2]);
free(subfile);
return 1;
}

// Write the subfile buffer to the destination file
fwrite(subfile, 1, lines * 128, dest);

// Close the destination file
fclose(dest);

}

0 comments on commit 801715b

Please sign in to comment.