mockbatheborg / runcpm Goto Github PK
View Code? Open in Web Editor NEWRunCPM is a multi-platform, portable, Z80 CP/M 2.2 emulator.
License: MIT License
RunCPM is a multi-platform, portable, Z80 CP/M 2.2 emulator.
License: MIT License
I built a tiny terminal using a 128x64 oled and a PS2 keyboard and an Arduino Uno. It is good enough for STAT and MBASIC and Kermit and other simple CP/M testing. I'm building a bigger display for Wordstar etc. It is pretty simple to put together with some jumper wires.
I know there are some CP/M versions out there that combine display and CP/M but I kind of like the idea of a generic box with a D9 socket and small display and PS2 socket and you can use it on different machines.
This issue can be noted as closed once read :)
Code below.
// Tiny terminal Arduino with I2C display, keyboard and RS232
// PS2 keyboard powered by 5V, data pin 2, clk pin 3
// I2C display on SCL and SDA A4 (SDA), A5 (SCL)
// Max3232 or Max2321 module powered by 5V, on Tx and Rx pins 0 and 1 (disconnect Rx when programming)
// for keyboard, // https://github.com/techpaul/PS2KeyMap/
// for display, #include <Adafruit_GFX.h> and #include <Adafruit_SSD1306.h>
// Scrolling screen, backspace but no VT100 cursor movement
// 21x6 display
// US keyboard but can change this if needed to UK, French or German (see code).
// outputs an ascii code for keypress. 9600 baud
// also output the control characters eg ^A outputs ascii 1, ^B ascii 2.
// arrow and home keys mapped to wordstar ^S^D etc
// caps lock, num lock work as do leds on the keyboard when press these
// function keys not mapped as don't map to any ascii values, could potentially map to ascii 128 to 255
/* KeyboardPS2AdvancedSimpleTest.ino
PS2KeyAdvanced library example
Advanced support PS2 Keyboard to get every key code byte from a PS2 Keyboard
for testing purposes.
IMPORTANT WARNING
If using a DUE or similar board with 3V3 I/O you MUST put a level translator
like a Texas Instruments TXS0102 or FET circuit as the signals are
Bi-directional (signals transmitted from both ends on same wire).
Failure to do so may damage your Arduino Due or similar board.
Test History
September 2014 Uno and Mega 2560 September 2014 using Arduino V1.6.0
January 2016 Uno, Mega 2560 and Due using Arduino 1.6.7 and Due Board
Manager V1.6.6
This is for a LATIN style keyboard using Scan code set 2. See various
websites on what different scan code sets use. Scan Code Set 2 is the
default scan code set for PS2 keyboards on power up.
Will support most keyboards even ones with multimedia keys or even 24 function keys.
The circuit:
* KBD Clock (PS2 pin 1) to an interrupt pin on Arduino ( this example pin 3 )
* KBD Data (PS2 pin 5) to a data pin ( this example pin 4 )
* +5V from Arduino to PS2 pin 4
* GND from Arduino to PS2 pin 3
The connector to mate with PS2 keyboard is a 6 pin Female Mini-Din connector
PS2 Pins to signal
1 KBD Data
3 GND
4 +5V
5 KBD Clock
Keyboard has 5V and GND connected see plenty of examples and
photos around on Arduino site and other sites about the PS2 Connector.
Interrupts
Clock pin from PS2 keyboard MUST be connected to an interrupt
pin, these vary with the different types of Arduino
PS2KeyAdvanced requires both pins specified for begin()
keyboard.begin( data_pin, irq_pin );
Valid irq pins:
Arduino Uno: 2, 3
Arduino Due: All pins, except 13 (LED)
Arduino Mega: 2, 3, 18, 19, 20, 21
Teensy 2.0: All pins, except 13 (LED)
Teensy 2.0: 5, 6, 7, 8
Teensy 1.0: 0, 1, 2, 3, 4, 6, 7, 16
Teensy++ 2.0: 0, 1, 2, 3, 18, 19, 36, 37
Teensy++ 1.0: 0, 1, 2, 3, 18, 19, 36, 37
Sanguino: 2, 10, 11
Read method Returns an UNSIGNED INT containing
Make/Break status
Caps status
Shift, CTRL, ALT, ALT GR, GUI keys
Flag for function key not a displayable/printable character
8 bit key code
Code Ranges (bottom byte of unsigned int)
0 invalid/error
1-1F Functions (Caps, Shift, ALT, Enter, DEL... )
1A-1F Functions with ASCII control code
(DEL, BS, TAB, ESC, ENTER, SPACE)
20-61 Printable characters noting
0-9 = 0x30 to 0x39 as ASCII
A to Z = 0x41 to 0x5A as upper case ASCII type codes
8B Extra European key
61-A0 Function keys and other special keys (plus F2 and F1)
61-78 F1 to F24
79-8A Multimedia
8B NOT included
8C-8E ACPI power
91-A0 and F2 and F1 - Special multilingual
A8-FF Keyboard communications commands (note F2 and F1 are special
codes for special multi-lingual keyboards)
By using these ranges it is possible to perform detection of any key and do
easy translation to ASCII/UTF-8 avoiding keys that do not have a valid code.
Top Byte is 8 bits denoting as follows with defines for bit code
Define name bit description
PS2_BREAK 15 1 = Break key code
(MSB) 0 = Make Key code
PS2_SHIFT 14 1 = Shift key pressed as well (either side)
0 = NO shift key
PS2_CTRL 13 1 = Ctrl key pressed as well (either side)
0 = NO Ctrl key
PS2_CAPS 12 1 = Caps Lock ON
0 = Caps lock OFF
PS2_ALT 11 1 = Left Alt key pressed as well
0 = NO Left Alt key
PS2_ALT_GR 10 1 = Right Alt (Alt GR) key pressed as well
0 = NO Right Alt key
PS2_GUI 9 1 = GUI key pressed as well (either)
0 = NO GUI key
PS2_FUNCTION 8 1 = FUNCTION key non-printable character (plus space, tab, enter)
0 = standard character key
Error Codes
Most functions return 0 or 0xFFFF as error, other codes to note and
handle appropriately
0xAA keyboard has reset and passed power up tests
will happen if keyboard plugged in after code start
0xFC Keyboard General error or power up fail
See PS2Keyboard.h file for returned definitions of Keys
Note defines starting
PS2_KEY_* are the codes this library returns
PS2_* remaining defines for use in higher levels
To get the key as ASCII/UTF-8 single byte character conversion requires use
of PS2KeyMap library AS WELL.
Written by Paul Carpenter, PC Services <[email protected]>
*/
// oled SSD1306 tiny display constants
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
char screen[126]; // 21 characters per line, 6 lines
uint8_t screenColumn = 0; // screen column 0 to 20 (there are 21 characters per line)
const uint8_t screenCols = 21; // 21
const uint8_t screenRows = 6; // 6
const uint8_t fontHeight = 10;
const uint8_t fontWidth = 6;
uint8_t cursorCol = 0;
uint8_t cursorRow = 0;
uint8_t screenArray[screenCols*screenRows];
boolean cursorOn = false;
// millisecond timer - used by oled and radio
uint32_t oldFiveHundredMillisecond = 0;
// string arrays
char inputString1[30]; // general purpose input string, 30 bytes, careful not to overflow this with long strings
//char inputString2[30]; // general purpose input string, 30 bytes
char outputString[30]; // general output string, 30 bytes
const uint16_t serialBufferSize = 128; // crashes with more than this, likely stack overflow
uint8_t serialBuffer[serialBufferSize];
uint16_t serialHead = 0;
uint16_t serialTail = 0;
#include <PS2KeyAdvanced.h>
#include <PS2KeyMap.h> // https://github.com/techpaul/PS2KeyMap/ and see examples folder.
// Keyboard constants Change to suit your Arduino
// Valid irq pins: Arduino Uno/Nano: 2, 3
#define DATAPIN 2
#define IRQPIN 3
PS2KeyAdvanced keyboard;
PS2KeyMap keymap;
void setup() {
Serial.begin(9600);
// display setup
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // some boards have the address as 0x78 but it actually is 3C
//display.begin(SSD1306_SWITCHCAPVCC, 0x78);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.display();
fillSpaces();
printScreenArray(); // clears screen and reprints but does not display
const static char s1[] PROGMEM = "*********************"; // store the text in flash
printString(getString(s1));
const static char s2[] PROGMEM = " Tiny Termimal 21x6"; // store the text in flash
printStringln(getString(s2));
const static char s3[] PROGMEM = " PS2 Key, 9600 Baud"; // store the text in flash
printStringln(getString(s3));
const static char s4[] PROGMEM = " SSD1306 Oled"; // store the text in flash
printStringln(getString(s4));
const static char s5[] PROGMEM = "*********************"; // store the text in flash
printString(getString(s5));
// Configure the keyboard library
keyboard.begin( DATAPIN, IRQPIN );
// see keytolcd demo, may be a bit more useful for just getting the characters
keyboard.setNoBreak( 1 ); // No break codes for keys (when key released)
keyboard.setNoRepeat( 1 ); // Don't repeat shift ctrl etc
keymap.selectMap( (char *)"US" );
//keymap.selectMap( (char *)"UK" );
//keymap.selectMap( (char *)"FR" );
//keymap.selectMap( (char *)"DE" );
}
void loop() {
// cycles approx 3x per millisecond if nothing much happening. display.display() takes 35ms
// https://github.com/arduino/Arduino/issues/4822 softSerial can't do loopback! Disables interrupts for sending so never gets its own message, so use the programming serial port
scanKeyboardRemap(); // scan and remap to ascii
while (Serial.available() > 0) {
writeSerialBuffer(Serial.read()); // read into buffer
}
if (availableSerialBuffer() == true) {
printLcdChar(readSerialBuffer()); // read in byte if available. If was just one byte, then refresh the display
if (availableSerialBuffer() == false) {
display.display(); // refresh display so more responsive
}
}
while (Serial.available() > 0) {
writeSerialBuffer(Serial.read()); // read into buffer any more bytes that might have come in while doing display.display as can't do two of these in a row, will overflow the internal arduino buffer
}
if ((millis() - oldFiveHundredMillisecond) >= 500) {
flashCursor();
if (availableSerialBuffer() == false) {
display.display(); // refresh display, this is slow so only do if there are no bytes pending in the serial buffer
}
oldFiveHundredMillisecond = millis();
}
}
// **************** begin OLED routines ******************
uint16_t decodeAddress(uint8_t x, uint8_t y)
{
// if width is 80 then array stores 0 to 79 then next row is 80 up
uint16_t address;
address = y;
address = address * screenCols;
address = address + x;
return address;
}
void printScreenArray()
{
uint8_t x = 0;
uint8_t y = 0;
uint16_t x1 = 0;
uint16_t y1 = 0;
uint16_t address;
display.clearDisplay(); // clear the display
for(y=0;y<screenRows;y++) {
x = 0;
address = decodeAddress(x,y);
y1 = y * fontHeight; // based on font size
x1 = 0;
for (x=0;x<screenCols;x++) {
display.setCursor(x1,y1);
display.write(screenArray[address]);
address++;
x1 = x1 + fontWidth; // based on character width
}
}
// display.display(); // done in the main loop, do need this to refresh the display
}
void storeCharacter(uint8_t ch, uint8_t y, uint8_t x)
{
uint16_t address;
address = decodeAddress(x, y);
screenArray[address] = ch;
}
void displayCharacter(uint8_t y, uint8_t x)
{
uint16_t address;
uint8_t ch;
uint16_t x1 = 0;
uint16_t y1 = 0;
address = decodeAddress(x, y);
ch = screenArray[address];
moveCursor(x, y);
display.write(ch);
// display.display done in main timing loop, only if no characters waiting to come in
}
void storeAndDisplayCharacter(uint8_t ch)
{
if ((ch > 31) && (ch < 127)) { // printable/stored character 32 to 126
storeCharacter(ch, cursorRow, cursorCol);
displayCharacter(cursorRow, cursorCol);
cursorCol++;
if (cursorCol >= screenCols) {
cursorCol = 0;
cursorRow++;
}
if (cursorRow >= screenRows) {
scrollUp();
cursorRow--;
printScreenArray(); // reprint whole screen after a scroll
}
moveCursor(cursorCol, cursorRow);
}
if (ch == 10) {
if (cursorRow == (screenRows - 1)) {
scrollUp(); // on bottom line of the screen so linefeed leaves cursor where it is, x and y, scrolls everything up one line.
printScreenArray(); // reprint whole screen after a scroll
}else{
cursorRow++; // otherwise just move the cursor down one line
}
}
if (ch == 13) {
cursorCol = 0; // carriage return, cursor to column 0
}
if (ch == 8) { // backspace
if (cursorCol > 0) {
cursorCol--; // move cursor back one
}else{
if (cursorRow >= 0 ) {
cursorRow--; // move cursor up to end of previous line
cursorCol = screenCols - 1; // move to end of previous line
}
}
printScreenArray(); // reprint whole screen after backspace - eg if CP/M gets a backspace, sends to monitor backspace then print space, then backspace again
}
}
void moveCursor(uint16_t col, uint16_t row)
{
uint16_t x;
uint16_t y;
y = row * fontHeight; // based on font size
x = col * fontWidth;
display.setCursor(x, y);
}
void scrollUp()
{
uint16_t addressDest;
uint16_t addressSource;
uint8_t x = 0;
uint8_t y = 0;
for (y=0;y<(screenRows - 1);y++) {
x = 0;
addressDest = decodeAddress(x, y);
addressSource = decodeAddress(x, (y+1));
for (x=0;x<screenCols;x++) {
screenArray[addressDest] = screenArray[addressSource];
addressDest++;
addressSource++;
}
}
y = screenRows - 1; // now make the bottom line on the screen blank
x = 0;
addressDest = decodeAddress(x, y);
for (x=0;x<screenCols;x++) {
screenArray[addressDest] = ' ';
addressDest++;
}
}
void fillScreenTest()
{
uint8_t x = 0;
uint8_t y = 0;
uint16_t address;
uint8_t i;
for (y=0;y<screenRows;y++) {
x = 0;
i=97+y;
address = decodeAddress(x, y);
for (x=0;x<screenCols;x++) {
screenArray[address] = i;
i++;
address++;
}
}
}
void fillSpaces()
{
uint16_t i;
uint16_t total;
total = screenCols*screenRows;
for (i=0;i<total;i++) {
screenArray[i] = ' ';
}
}
void dumpScreenArray()
{
uint16_t i;
uint16_t total;
total = screenCols*screenRows;
for (i=0;i<total;i++) {
Serial.print(screenArray[i]);
Serial.print(' ');
}
}
void flashCursor()
{
uint16_t curX;// in pixels so need 16 bit resolution for large displays
uint16_t curY;
curX = cursorCol * fontWidth;
curY = cursorRow * fontHeight;
display.fillRect(curX, curY, fontWidth, fontHeight,BLACK); // standard font behaviour for all libraries is to only print pixels and not erase the previous ones
moveCursor(cursorCol, cursorRow);
if (cursorOn == true) {
display.write('_');
}
cursorOn = !cursorOn;
}
void printLcdChar(uint8_t c)
{
cursorOn = false; // redisplay with no line before printing anything
flashCursor();
storeAndDisplayCharacter(c); // new version of code
}
// *********************** end OLED routines ********************
// *********************** string routines ***********************
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
char* getString(const char* str) // String replacement - move string from flash to local buffer
{
strcpy_P(outputString, (char*)str);
return outputString;
}
void printString(const char *str) // all output directed through this one routine, so can change Serial.print to whatever display is being used
{
const char *p;
p = str;
while (*p) {
//Serial.print(*p); // send to serial, explanation in majenko's webpage
printLcdChar(*p); // or send to lcd
p++;
}
}
void printStringln(const char *str) // print line with crlf
{
printString(str);
crlf(); // carriage return, line feed
}
void crlf() // carriage return and linefeed
{
const static char crlf[] PROGMEM = "\r\n"; // carriage return, then line feed, maybe not the most efficient way to do this but works
printString(getString(crlf)); // print out, using one central function for output so easier to change destination with different displays
}
void printNumber(long n)
{
char* outputString = integerToString(n); // convert to number
printString(outputString);
}
char* integerToString(int n) // returns outputString
{
itoa(n, outputString, 10); // itoa is for integers, 10 is for base 10 (could use 2 for binary, 16 for hex)
return outputString;
}
void printUnsigned(uint16_t n)
{
char* outputString = unsignedToString(n); // convert to number
printString(outputString);
}
char* unsignedToString(uint16_t n) // returns outputString
{
utoa(n, outputString, 10); // itoa is for integers, 10 is for base 10 (could use 2 for binary, 16 for hex)
return outputString;
}
// *********************** end string routines *****************************
void scanKeyboardRemap()
{
uint16_t code;
uint8_t remapCode;
uint8_t ascii;
uint8_t ctrl;
code = keyboard.available();
if( code > 0 ) {
code = keyboard.read();
//Serial.print( F( "Value " ) );
//Serial.print( code, HEX );
switch (code) {
// map arrow keys to Wordstar - comment out if not needed
case 0x0111: outputAscii(17); // Home = ^QS
outputAscii(19);
break;
case 0x0112: outputAscii(17); // End = ^QD
outputAscii(4);
break;
case 0x0113: outputAscii(18); // Page Up = ^R
break;
case 0x0114: outputAscii(3); // Page Down = ^C
break;
case 0x0115: outputAscii(19); // Left arrow = ^S
break;
case 0x0116: outputAscii(4); // Right arrow = ^D
break;
case 0x0117: outputAscii(5); // Up arrow = ^E
break;
case 0x0118: outputAscii(24); // Down arrow = ^X
break;
case 0x0119: outputAscii(22); // Insert = ^V
break;
}
remapCode = keymap.remapKey( code );
if( remapCode > 0 ) {
//Serial.print(F("["));
//Serial.print( remapCode, HEX );
//Serial.print(F("]"));
if( ( remapCode & 0xFF ) ) {
//Serial.print( F( " mapped " ) );
//Serial.print( remapCode, HEX );
//Serial.print( F( " - Status Bits " ) );
//Serial.print( remapCode >> 8, HEX );
//Serial.println("");
ctrl = (code >> 8);
ascii = remapCode & 0xFF;
if (ascii < 128) {
//Serial.print( F( " Ascii decimal " ) );
if (ctrl == 0x20) { // Ctrl/smalls so subtract 97
if ((ascii>= 97) && (ascii <=122)) {
ascii = ascii - 96; // a to z to ascii 1 to 26
}
}
if (ctrl == 0x30) { // Ctrl/caps so subtract 65
if ((ascii>= 65) && (ascii <=90)) {
ascii = ascii - 64; // A to Z to ascii 1 to 26
}
}
//Serial.print( ascii, DEC );
//Serial.print( F( " ( " ) );
//Serial.write( ascii );
//Serial.print( F( " )\n" ) );
outputAscii(ascii); // send out serial port
}
}
}
}
}
void outputAscii(uint8_t ch)
{
// single point to output anything to the serial port
Serial.write(ch);
//Serial.print(F(" = ascii ")); // debugging
//Serial.print(ch, DEC ); // debugging
//Serial.println(""); // debugging
}
void writeSerialBuffer(uint8_t ch)
{
serialBuffer[serialHead] = ch;
serialHead++;
if (serialHead >= serialBufferSize) {
serialHead = 0;
}
}
uint8_t readSerialBuffer()
{
uint8_t ch;
ch = serialBuffer[serialTail];
serialTail++;
if (serialTail >= serialBufferSize) {
serialTail = 0;
}
return ch;
}
boolean availableSerialBuffer()
{
boolean availableBuffer = false;
if (serialTail != serialHead) {
availableBuffer = true;
}
return availableBuffer;
}
I have a DUE with Keystudio WS100 Ethernet Card. Using the SD card driver examples I can read/write and list files on the SD card but when starting RunCPM I get the following error on the DUE serial port..
CCP: CCP-DR.60K CCP Address: 0xe400
BOARD: ARDUINO DUE
Initializing SD card.
Unable to initialize SD card.
CPU halted.
RunCPM is a 32 bits application which allows you to execute old CP/M 8 bits programs on Windows, Mac OS X, Linux, FreeBSD, MS-DOS and Arduino DUE.
I don't use any compiler options on Debian to force 32bit code generation...
runcpm/src/RunCPM/RunCPM$ file RunCPM
RunCPM: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=eb4fa888e367bcf02ffba3dbfb2f394b8d345bf1, not stripped
...so what is dropping out of the compiler is a 64bit executable.
...needs to mention the user areas now and where to drop the contents from A.ZIP
and/or packing A.ZIP
to contain the path A/0
may be an option...
I've tried configuring wordstar to use an ansi/vt100 terminal but it isn't working; is the terminal emulation something I need to turn on?
I have compiled the ESP32 port in a lolin D32 and all seem to be fine. All works except write files in the filesystem.
Each time i try to wite a file (saving zork, installing wordstar, editing with TE, etc i get an error.
A0>ed kk
DISK OR DIRECTORY FULL
the erase command is working, pip,rena, etc no.
Any clue?
only changed the pins in the SD definition and hat to change the sd.begin line to:
if (SD.begin(SDINIT,SD_SCK_MHZ(30))) {
(tried lower speeds, but the error is the same, with higher speeds, lots of problems accesing files)
$$$.SUB should always be checked on drive A: user area 0.
Even after many years, no standard was defined for this, and some CCPs and implementations of SUBMIT handled it differently.
A: user area 0 seems so be a good base for a standard (especially nowadays, when no one will complain about it), so I will implement this shortly.
Compiling using the Posix makefile and running this on Linux (Lubuntu) for both CCP_CCPZ with 64K and the CCP_DR with 60K only gives Bdos errors as below. No amount of pressing Enter or ^C ever resolved the problem.
Build Feb 17 2017 - 00:49:00
with Lua scripting support
-----------------------------------------
CCP: CCP-DR.60K CCP Address: 0xe400
RunCPM Version 2.8 (CP/M 2.2 60K)
Bdos Error on A : Select
Trying the CCP_INTERNAL I also get the error. Here two Enters gives me the A> -prompt, but the error comes back as soon as I try a disk access.
CP/M 2.2 Emulator v2.8 by Marcelo Dantas
Build Feb 17 2017 - 00:54:55
with Lua scripting support
-----------------------------------------
CCP: INTERNAL v1.3 CCP Address: 0xe400
RunCPM Version 2.8 (CP/M 2.2 60K)
Bdos Error on A : Select
Bdos Error on A : Select
A>DIR
Bdos Error on A : Select
The build process seems ok except for some minor nagging by the archiver that says:
ar: `u' modifier ignored since `D' is the default (see `U')
Is the CPPHEAD message really needed that often?
Its contents does not change.
Would showing this at most once be enough?
I'll mute it in a local branch if the majority loves to see it frequently...
MLOAD v2.1 has a bug where it will overwrite the first six bytes of the CCP.
Normally this is not a problem, unless the CCP is not rewritten following a warm boot.
MLOAD v2.5 fixes this problem.
See the version notes in the mload.asm
Since z80.eu is down, the wayback machine has the required zip file.
This isn't really an 'issue' so can be closed by Mr Mockba, but I thought I might write some notes about the code that was changed to enable Kermit file transfers.
The board I am using is called ESPDUINO-32 and if you google this and select images, you can see it is an arduino form factor. I specifically went for the one with the large USB socket as this is plugged and unplugged many times and is mechanically stronger than the small ones. This particular board is not listed in the arduino IDE but it seems to compile ok with many of the ones that are listed. I used the first board in the list which is called ESP332 Dev Module.
Near the beginning of the RunCPM module are some ifdef's, I changed the pins for the SD card to 19,23 and 18, the CS pin is 5, and the led is on pin 2.
#elif defined ESP32 // ESP32 boards
SdFatSoftSpiEX<19, 23, 18> SD; // MISO, MOSI, SCK Some boards use 2,15,14,13, other 12,14,27,26
#define SDINIT 5 // CS
#define LED 2 // TTGO_T1=22 LOLIN32_Pro=5(inverted) DOIT_Esp32=2 ESP32-PICO-KIT=no led, Espduino pin 2
#define LEDinv 0
#define BOARD "ESPDUINO-32"
#ifdef ESP32
Serial1.begin(9600,SERIAL_8N1, 26, 25); //Baud rate, parity mode, RX, TX ESP32
Serial2.begin(9600,SERIAL_8N1, 17, 16); //Baud rate, parity mode, RX, TX ESP32
#endif
For hardware I used Max3232 modules available on ebay. Run from the 3V3 pin. In keeping with the old-skool spirit, computers have male D9 plugs and devices (modems, terminals) are female D9. The female Max3232 modules are much more common - I had to search a bit to get the male ones. I made a crossover cable with two female sockets and pin 5 to 5, 2 to 3 and 3 to 2. I also had some modules with faults - some wouldn't work, and one had crosstalk between Tx and Rx so characters printed twice on the screen. I've also had some dodgy max3232 chips before and found that in this case it may be worth getting these from a big supplier like Radio Spares or Element 14 or similar.
I got a copy of generic Kermit from Columbia University. It is in the CP/M archives. This needs no modification at all. If anyone has problems getting this I'll post a copy here.
Below is a wall of code. This goes in the abstraction_arduino.h file. It needs to go above the console abstraction functions (I think this is because functions need to be declared before you use them, and this applies in .h files but not .ino files. ). Once this code is copied in, test everything still compiles ok. None of this should affect compilation as it isn't linked yet to any of the existing code.
// ***************************** Physical Device List **************************************
//CON: = TTY: CRT: BAT: UC1:
//RDR: = TTY: PTR: UR1: UR2:
//PUN: = TTY: PTP: UP1: UP2:
//LST: = TTY: CRT: LPT: UL1:
// TTY
void deviceTTYout(uint8_t ch) // same as _putch
{
Serial1.write(ch); // same as _putch but with buffer overflow protection
while (Serial1.availableForWrite() < 20) {
delay(100); // at 9600 baud, ESP32 output buffer is 128 bytes, if stops when only 20 chars left in the output buffer, and pause 100ms, then have about 115 left as sending about 1 per ms.
}
}
uint8_t deviceTTYavailable(void) { // same as _kbhit
return(Serial1.available());
}
uint8_t deviceTTYin(void) { // same as _getch
while (!Serial1.available());
return(Serial1.read());
}
uint8_t deviceTTYinEcho(void) { // same as _getche
uint8_t ch = deviceTTYin();
deviceTTYout(ch);
return(ch);
}
// CRT
void deviceCRTout(uint8_t ch) // same as _putch
{
Serial.write(ch); // same as _putch but with buffer overflow protection
while (Serial.availableForWrite() < 20) {
delay(100); // at 9600 baud, ESP32 output buffer is 128 bytes, if stop when only 20 chars left in the output buffer, and pause 100ms, then have about 115 left as sending about 1 per ms.
}
}
uint8_t deviceCRTavailable(void) { // same as _kbhit
return(Serial.available());
}
uint8_t deviceCRTin(void) { // same as _getch
while (!Serial.available());
return(Serial.read());
}
uint8_t deviceCRTinEcho(void) { // same as _getche
uint8_t ch = deviceCRTin();
deviceCRTout(ch);
return(ch);
}
// UR1
uint8_t deviceUR1in(void) {
uint8_t ch = 26;
return ch;
}
// UP1
void deviceUP1out(uint8_t ch) {
// add code here
}
// BAT, console device, input and output and can see if characters waiting, input used by Kermit as the default input device
void deviceBATout(uint8_t ch)
{
Serial2.write(ch); // same as _putch but with buffer overflow protection
while (Serial2.availableForWrite() < 20) {
delay(100); // at 9600 baud, ESP32 output buffer is 128 bytes, if stop when only 20 chars left in the output buffer, and pause 100ms, then have about 115 left as sending about 1 per ms.
}
}
uint8_t deviceBATavailable(void) {
return(Serial2.available());
}
uint8_t deviceBATin(void) {
while (!Serial2.available());
return(Serial2.read());
}
uint8_t deviceBATinEcho(void) {
uint8_t ch = deviceBATin();
deviceBATout(ch);
return(ch);
}
// UC1, console device
void deviceUC1out(uint8_t ch)
{
// add code here
}
uint8_t deviceUC1available(void) {
return(1); // add code here
}
uint8_t deviceUC1in(void) {
return(26); // add code here
}
uint8_t deviceUC1inEcho(void) {
uint8_t ch = deviceUC1in();
deviceUC1out(ch);
return(ch);
}
// PTR, reader device
uint8_t devicePTRin(void) {
return 26; // add code here
}
// UR2, reader device
uint8_t deviceUR2in(void) {
return 26; // add code here
}
// PTP, punch device
void devicePTPout(uint8_t ch) {
Serial2.write(ch); // used by Kermit as the default output device
while (Serial2.availableForWrite() < 20) {
delay(100); // at 9600 baud, if stop when only 20 chars left, and pause 100ms, then have about 115 left, as sending about 1 per ms. Should not need to do this if using small packets with Kermit
}
}
// UP2, punch device
void deviceUP2out(uint8_t ch) {
// add code here - eg write to file
}
// UL1, LST device
void deviceUL1out(uint8_t ch) {
// add code here - eg write to file
}
// LPT, LST device
void deviceLPTout(uint8_t ch) {
// add code here
}
// *************************************
// redirection for CON RDR PUN and LST eg CONin, CONout, CONavailable directed to one of four places depending on IOBYTE.
uint8_t iobyteCON()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0x03; // mask off 00000011
return iobyte;
}
uint8_t iobyteRDR()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0x0C; // mask off 00001100
iobyte = iobyte >> 2; // bitshift so low 2 bits
return iobyte;
}
uint8_t iobytePUN()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0x30; // mask off 00110000
iobyte = iobyte >> 4; // bitshift so low 2 bits
return iobyte;
}
uint8_t iobyteLST()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0xC0; // mask off 11000000
iobyte = iobyte >> 6; // bitshift so low 2 bits
return iobyte;
}
//CON: = TTY: CRT: BAT: UC1:
void outCON(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: deviceCRTout(ch);
break;
case 2: deviceBATout(ch);
break;
case 3: deviceUC1out(ch);
break;
}
}
uint8_t availableCON()
{
uint8_t iobyte;
uint8_t dataAvailable;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: dataAvailable = deviceTTYavailable();
break;
case 1: dataAvailable = deviceCRTavailable();
break;
case 2: dataAvailable = deviceBATavailable();
break;
case 3: dataAvailable = deviceUC1available();
break;
}
return dataAvailable;
}
uint8_t inCON(void)
{
uint8_t iobyte;
uint8_t dataIn;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: dataIn = deviceTTYin();
break;
case 1: dataIn = deviceCRTin();
break;
case 2: dataIn = deviceBATin();
break;
case 3: dataIn = deviceUC1in();
break;
}
return dataIn;
}
uint8_t echoCON()
{
uint8_t ch;
ch = inCON();
outCON(ch);
return(ch);
}
//RDR: = TTY: PTR: UR1: UR2:
uint8_t inRDR(void)
{
uint8_t iobyte;
uint8_t dataIn;
iobyte = iobyteRDR(); // 00, 01 10, 11
switch (iobyte) {
case 0: dataIn = deviceTTYin();
break;
case 1: dataIn = devicePTRin();
break;
case 2: dataIn = deviceUR1in();
break;
case 3: dataIn = deviceUR2in();
break;
}
return dataIn;
}
//PUN: = TTY: PTP: UP1: UP2:
void outPUN(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobytePUN(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: devicePTPout(ch);
break;
case 2: deviceUP1out(ch);
break;
case 3: deviceUP2out(ch);
break;
}
}
//LST: = TTY: CRT: LPT: UL1:
void outLST(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobyteLST(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: deviceCRTout(ch);
break;
case 2: deviceLPTout(ch);
break;
case 3: deviceUL1out(ch);
break;
}
}
/* Console abstraction functions */
/*===============================================================================*/
uint8_t _kbhit(void) {
//return(Serial.available());
return availableCON(); // redirect based on iobyte
}
uint8_t _getch(void) {
//while (!Serial.available());
//return(Serial.read());
return inCON(); // redirect based on iobyte
}
uint8_t _getche(void) {
//uint8_t ch = _getch();
//Serial.write(ch);
//return(ch);
return echoCON(); // redirect based on iobyte
}
void _putch(uint8_t ch) {
//Serial.write(ch);
outCON(ch); // redirect based on iobyte
}
void _clrscr(void) {
Serial.println("\e[H\e[J"); // done once at startup so left as is
}
/*
C = 3 : Auxiliary (Reader) input
Returns: A=Char
*/
case 3:
#ifdef ESP32
HL = inRDR();
#else
HL = 0x1a; // ^Z end file
#enif d
break;
Commented out the ioport ramwrite setting in cpm.h and moved it to the void setup() routine in RunCPM. I am not sure if this has been changed in a recent update. I did a clean install on 11th August and rebuilt it using these instructions and this did need to be changed.
_RamWrite(0x0003, 0x3D);
Thinking how to use the ports, Grant Searle has a system where the first character that comes in defines which port is being used. I am thinking of something even simpler. For debugging the iobyte is set at startup so CON goes to CRT on the USB serial port. Once a board is working and it is going in a box, recompile with the iobyte set at startup to TTY which is on Serial 1. The box I am making has a hole for the USB socket so you can plug that in and that is for programming and for using a PC terminal program. Then a male D9 for TTY and that goes to a physical terminal (eg a PropTerm, or a Raspberry Pi, or one using an Arduino Uno). And the second male D9 is BAT: and that is for file transfers. I have some vague ideas that the 4th port could be something to do with Wifi or Bluetooth as these are both on the ESP32.
One small bug I am working on - kermit works rock solid between two boards, but when using teraterm with a kermit transfer, it seems to have many dropped packets. This is true at baud rates from 1200 to 115200. I have tried different Max3232 modules, different USB to serial devices and different boards. I haven't tried different terminal programs. This may not be such an issue, because the huge advantage of RunCPM over all other real and emulated CP/M systems is that it uses Fat32 files on the SD card. Thanks++ to Mr Borg for this :)
My ESP32 boards will be arriving in a few days.
Let's see if this is going to work right out of the box, or if it will require a lot of coding to happen.
Or even if it will not be at all possible.
Stay tuned.
Hi All,
I have pulled my STM32 board from the drawer and gave it a try on the Arduino.
It seems to work fine with code from this project: https://www.stm32duino.com/
Source code here: https://github.com/rogerclarkmelbourne/Arduino_STM32
SD Library here: https://github.com/stm32duino/STM32SD (I have not tested this yet)
There's a good chance this will work for running RunCPM.
I have tried compiling RunCPM for it but got some errors, also, the code needs defines to use different settings when building for this board. Not sure when I will be able to port it, but if anyone wants to give it a try, check pages the above.
I am not using the guy's STM32duino boot loader, as I feel it is not needed, you can program the STM board from Arduino using the on-board st-link. Needs to install the ST-Link driver btw.
I was able to load a led-blink program onto it, which is already some progress.
Cheers,
Mockba.
Well... there is no standard for graphics with CP/M but there are SIXELs!
And because this kind of graphics is just like printing with a dot matrix printer, CP/M programs easily can do it if connected to a terminal capable of sixel graphics:
Above snapshot was taken from RunCPM in an XTerm on Debian9. There are more sixel enabled terminals and it should work similar, if you connect RunCPM on an Arduino-DUE to one of them.
These files...
(yeti@kumari:16)/home/wrk/runcpm/run/C/1$ ls -l MB6EL.*
-rw-r--r-- 1 yeti yeti 896 Aug 13 16:41 MB6EL.C
-rw-r--r-- 1 yeti yeti 3712 Aug 13 16:41 MB6EL.COM
-rw-r--r-- 1 yeti yeti 128 Aug 13 16:13 MB6EL.SUB
...are attached as: mb6el.zip
will you ever try to compile for esp cpu?
CCP : CCP-ZCP2.60K CCP Address: 0xe400
RunCPM Version 3.7 (CP/M 2.2 60K)
A>DIR
1STREAD .ME
C:\TEMP\RunCPM_Win>
`
I didnt got this with a v3.7 compiled under armbian-linux on a Pi-Style SBC.
While testing a variety of programs, I met one issue. The compiler run under runcpm hangs. It seems to be associated to the C.COM program chaining the various compilation steps. I did not go far enough to figure out what triggers the failure.
the same compiler works properly in a simh environment and a couple of other emulators.
the programs generated with it work perfectly under it.
STAT on my STM build doesn't consider a disk as present unless it's explicitly referenced, or has been 'visitied'. In any event, the free space for all disks seems to return the same value for all disks - but not always the same value, so, for example, A: is reported as different sizes (see examples below)
Here, I run STAT after walking round or referencing a few disks and doing a few RESETs. The system has drives A-D (all upper case), each with a '0' subfolder. The drives have different things on them.
CP/M 2.2 Emulator v3.7 by Marcelo Dantas
Arduino read/write support by Krzysztof Klis
Build Jun 24 2019 - 19:29:15
--------------------------------------------
CCP: CCP-DR.60K CCP Address: 0xe400
BOARD: STM32F411 Nucleo
Initializing SD card.
RunCPM Version 3.7 (CP/M 2.2 60K)
A>stat
A: R/W, Space: 898k
A>stat b:
Bytes Remaining On B: 898k
A>stat
A: R/W, Space: 898k
B: R/W, Space: 898k
A>
[RESET]
CP/M 2.2 Emulator v3.7 by Marcelo Dantas
Arduino read/write support by Krzysztof Klis
Build Jun 24 2019 - 19:29:15
--------------------------------------------
CCP: CCP-DR.60K CCP Address: 0xe400
BOARD: STM32F411 Nucleo
Initializing SD card.
RunCPM Version 3.7 (CP/M 2.2 60K)
A>stat b:
Bytes Remaining On B: 898k
A>stat
A: R/W, Space: 898k
B: R/W, Space: 898k
A>
B>a:stat
A: R/W, Space: 898k
[RESET]
CP/M 2.2 Emulator v3.7 by Marcelo Dantas
Arduino read/write support by Krzysztof Klis
Build Jun 24 2019 - 19:29:15
--------------------------------------------
CCP: CCP-DR.60K CCP Address: 0xe400
BOARD: STM32F411 Nucleo
Initializing SD card.
RunCPM Version 3.7 (CP/M 2.2 60K)
A>stat b:
Bytes Remaining On B: 898k
A>stat
A: R/W, Space: 898k
B: R/W, Space: 898k
A>d:
D>dir
D: ZORK1 COM : ZORK1 DAT : ZORK2 COM : ZORK2 DAT
D: ZORK3 COM : ZORK3 DAT
D>e:
Bdos Error on E : Select
RunCPM Version 3.7 (CP/M 2.2 60K)
D>dir
D: ZORK1 COM : ZORK1 DAT : ZORK2 COM : ZORK2 DAT
D: ZORK3 COM : ZORK3 DAT
D>a:
A>stat
A: R/W, Space: 962k
D: R/W, Space: 962k
A>b:
B>a:stat
A: R/W, Space: 962k
B: R/W, Space: 962k
D: R/W, Space: 962k
B>
B>a:stat
A: R/W, Space: 962k
B: R/W, Space: 962k
D: R/W, Space: 962k
B>a:stat c:
Bytes Remaining On C: 962k
B>a:stat
A: R/W, Space: 962k
B: R/W, Space: 962k
C: R/W, Space: 962k
D: R/W, Space: 962k
Is it just me or the latest (15.8.1) update of Visual Studio 2017 just broke text input?
Still wondering what might be the issue.
I'm trying to build and run RunCPM
on Debian-8.5/amd64 (tried on Debian-7.11/armhf (on Cubietruck) some days ago too) but I always get results like below...
CP/M 2.2 Emulator v2.6 by Marcelo Dantas
Build Sep 8 2016 - 17:31:15
-----------------------------------------
CCP: CCP-DR.BIN Loaded at 0xf400
RunCPM Version 2.6 (CP/M 2.2 64K)
A>dir
A: 1STREAD ME : BDOS ASM : BDOS SUB : CLEAN SUB
A: DISKDEF LIB : DUMP ASM : ED COM : EXIT ASM
A: EXIT COM : EXIT SUB : EXIT Z80 : LOAD COM
A: MBASIC COM : MLOAD ASM : MLOAD COM : MLOAD DOC
A: MOVCPM COM : OPCODES TXT : STAT COM : SUBMIT COM
A: SYSGEN COM : XSUB COM : Z80ASM COM : ZCPR ASM
A: ZCPR SUB : ZCPRHDR LIB : ZEXALL COM : ZEXDOC COM
A: ZSID COM : ZTRAN4 COM
A>exit
EXIT?
A>mbasic
MBASIC?
A>_
"Internal" commands like dir
work but others do not.
Now have Kermit working for file transfers to and from a PC, and also for transfers between two ESP32 boards running RunCPM. There are quite a few additions to the code, particularly with adding in handling for iobyte. Hopefully these can be added in some sort of 'official' way. They can all be added with conditional #ifdef ESP32 so as to not affect any other code. There is a small bug in the existing code where iobyte gets reset on return to the A> prompt so changing it with STAT was not working. Fixed by moving the initial iobyte declaration to a 'cold boot' part of the code, ie just before the signon message. Below is a copy of all the notes I made along the way.
Pinout for SD card https://github.com/espressif/arduino-esp32/tree/master/libraries/SD
MISO IO19, MOSI I023, CLK IO18, CS IO5, 3V and 0V. These are all in a group apart from the 3V3. (ESP32 pins are all 3V3)
for arduino sized boards they have a reset when uploading the program. The smaller boards need the reset button pushed prior to uploading
globals.h - commented out USE_PUN and USE_LST for the moment
changed the esp32 pin definitions for the arduino form factor board "ESPDUINO-32"
#elif defined ESP32 // ESP32 boards
SdFatSoftSpiEX<19, 23, 18> SD; // MISO, MOSI, SCK Some boards use 2,15,14,13, other 12,14,27,26
#define SDINIT 5 // CS
#define LED 2 // TTGO_T1=22 LOLIN32_Pro=5(inverted) DOIT_Esp32=2 ESP32-PICO-KIT=no led, Espduino pin 2
#define LEDinv 0
#define BOARD "ESPDUINO-32"
added in two new serial ports (the ESP32 has 3 hardware uarts, and later could possibly add software uarts as well)
Serial1.begin(SERIALSPD,SERIAL_8N1, 26, 25); //Baud rate, parity mode, RX, TX ESP32
Serial2.begin(SERIALSPD,SERIAL_8N1, 17, 16); //Baud rate, parity mode, RX, TX ESP32
commented out // _RamWrite(0x0003, 0x3D); in cpm.h as this is resetting the iobyte on a warm boot, which means that STAT could change the iobyte but as soon as stat finished, it got changed back again
now have this line in the RunCPM tab
_clrscr();
_RamWrite(0x0003, 0x3D); // IOBYTE set
_puts("CP/M 2.2 Emulator v" VERSION " by Marcelo Dantas\r\n");
Then extensive changes to abstraction_ardunio.h so that all IO is redirected as per the iobyte. Example of the code is for console out
void outCON(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: deviceCRTout(ch);
break;
case 2: deviceBATout(ch);
break;
case 3: deviceUC1out(ch);
break;
}
}
If you run STAT VAL: it prints out the list of all the 13 physical devices that can be connected (the table would suggest 4x4=16 but some are repeated)
CON: = TTY: CRT: BAT: UC1:
RDR: = TTY: PTR: UR1: UR2:
PUN: = TTY: PTP: UP1: UP2:
LST: = TTY: CRT: LPT: UL1:
In our case the important thing is the console is connected to the CRT, which is the first serial port
Run STAT DEV: and it lists the current layout eg CON: CRT:
To change this, run STAT CON:=TTY: and now the console changes from Serial to Serial 1
It is very helpful at this point to have a D9 to USB adaptor, and also a terminal program such as Teraterm
Next were lots of experiments with the RDR port. It is possible to do things like PIP TEST.TXT=RDR:
however, this does not work for large files over about 30K as CP/M runs out of Z80 memory and then goes to write all the data to the disk and then the buffer overflows.
Tried adding a very large buffer and slow baud rates but I think the ESP32 memory can be used for better things.
Outputting data works fine too, eg PIP PUN:=TEST.TXT but it did need code to poll the number of bytes still available in the buffer and put in a 100ms delay if the buffer is getting full.
The next experiment is with Kermit. There is a "generic" version of Kermit that uses iobyte. The kermit documentation says that it defaults to PTR being the port with the following settings:
SET PORT xxx input from output to
CRT CRT: CRT:
PTR PTR: PTP:
However, lots of experiments(which are much easier on a simulation) suggest that this documentation is not correct, and that in fact the default setting for Kermit is to redirect CON to BAT
This is done by changing the two lower bits for iobyte from (our default of 01 which is CRT) to 10 which is BAT
Putting a debug on _kbhit shows that Kermit alternately polls the default port then the BAT port, so you can abort the transfer with a keypress (not sure which one though)
So for debugging at this point, attach a D9 to USB to Serial1 and open another terminal and use STAT CON:=TTY: to test the Serial One port, and then STAT CON:=BAT to test the Serial Two port
Once that is working, then replicate the whole thing with another ESP32 board. Connect these two with a D9 male to male crossover cable (pin 2 to 3, 3 to 2 and 5 to 5)
and it is then possible to run kermit on both boards and transfer files
KERMIT SEND TEST.TXT and KERMIT RECEIVE TEST.TXT
Kermit pauses every 10 secs or so to write data out to the disk and some packets look like they are resent
Text files are fine. Sending MBASIC.COM did not seem to work, the file was corrupted. However, using UNLOAD MBASIC.COM and sending MBASIC.HEX and then LOAD MBASIC.HEX all worked fine
For debugging it makes sense to leave the USB programming cable and use a terminal program (or even the arduino terminal program). This default is Serial Zero port.
For using the board standalone, TTY on Serial One may be better. It may be worth copying Grant Searle's idea of iobyte being set by the first character that comes in a port, CRT or TTY
see Grant Searle's page http://searle.hostei.com/grant/cpm/index.html discussion using two serial ports and switching using iobyte
Further thoughts, the ESP32 has Wifi and Bluetooth. These could ?? be CP/M 'devices'. The ESP32 bluetooth example is only a few lines.
# Link the program
$(PROG): $(OBJS)
$(LD) $(OBJS) -o $(PROG) $(LDFLAGS)
$(PROG):
only depends on $(OBJS)
which is the only C source of this project.
Changes to headers or the Makefile itself will not trigger a rebuild.
Adding $(wildcard *.h) Makefile.posix
will be just a bit too active and trigger a rebuild even if a header for a different platform has changed, but I think that's tolerable. And it catches all headers by wildcard and so never adding a header to the Makefile can be forgotten.
...and later:
# Compile everything.
all: clean $(PROG)
I think a forced "make clean" before remake is not needed when the above change detects changed Makefile, C source and headers...
After building (make posix build
) several files not registered with git show up in git status
and in the comments on each commit. They are RunCPM
, main.o
, lua/lua
, lua/luac
and lots of lua/*.o
files. Will it cause problems to add them to .gitignore
?
Some original stuff for RunCPM is on my page:
Hello, I tried runcpm.exe and it runs under Windows 7 except for processing of ANSI terminal escape sequences. Upon investigation it seems there is a flag that must be set for the console host to filter and process the escape sequences ( ENABLE_VIRTUAL_TERMINAL_PROCESSING). I even tried the another method with a program called "ansicon.exe" and it did not work. I discovered this issue trying the TE.COM editor and TURBO Pascal for CPM-80. The ANSI escape sequences just get echoed to the console. I think this flag can be added to the function void _console_init(void) in abstraction_vstudio.h
Here is the Microsoft Reference URL on Console Virtual Terminal Sequences: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
When "user areas" get turned on as default feature:
Are you planning to add creating the missing numbered subdirectories on the fly?
...and... RunCPM/globals.h, line 48:
User numbers are 0-9, then A-F for users 12-15
...10-15...
I have teensy 3.6
Arduino 1.8.4
RunCPM Version 2.8
I have tried 64k and 60k
I have tried various cpm, cpmz, cpmz2, cpmz3, internal etc....
When I try to run adv.com, I get "Glitch! Symbol table not found. STOP UGG!"
That string is found inside the adv.com
I have tried the same files on a real Z80 CPM 2.2 and they run aok.
Is there some debugging I can try?
Submit.com and submitd.com doesn´t appear to work. The only program that appears to work is supersub.com, a more powerful submit-like utility, but only works in A: drive, not B:, C:,..
CP/M 2.2 Emulator v3.1 by Marcelo Dantas
Build Sep 24 2018 - 19:14:00
with Lua scripting support
-----------------------------------------
CCP: INTERNAL v1.4 CCP Address: 0xf400
A0>e:
E0>dir
A: VIDATT Z80 : WS COM : WS OVR : WSCHANGE COM
A: WSCHANGE OVR : WSCHHELP OVR : WSHELP OVR : WSMSGS OVR
A: WSPRINT OVR : WSPRINT TST : WSREADME BAK : WSREADME TXT
A: WSSHORT OVR : WSU COM
E0>█
The drive E directory listing lines should be prefixed with E:
.
I found screenlogs where other CCPs did it how I expected it to be e.g. in: #48 (comment)
A friendly neighbour:
Altair 8800 (Z80) simulator V3.9-0 build 1000 (scp created Jun 20 2017 at 15:02:55 with gcc 6.3.0 20170516)
64K CP/M Version 2.2 (SIMH ALTAIR 8800, BIOS V1.27, 2 HD, 02-May-2009)
A>e:
E>dir
E: VIDATT Z80 : WS OVR : WSCHANGE COM : WSCHANGE OVR
E: WSCHHELP OVR : WSHELP OVR : WSMSGS OVR : WSPRINT OVR
E: WSPRINT TST : WSREADME TXT : WSSHORT OVR : WSU COM
E: WS COM
E>█
Right now, if a file is renamed to an 8bit character on T1 and T2, STAT seems to see it as R/O and Hidden (SYS), but more coding is needed for it to work throughout the file system.
On Windows, RunCPM seems unable to cope with the RunCPM folder being on Dropbox. On startup, we get:
Bdos Error on A : Select
I'm not currently set up to recompile on Windows, but I think I can see the problem.
In abstraction_vstudio.h, around line 126, we have:
int _sys_select(uint8 *disk) {
return((uint8)GetFileAttributes((LPCSTR)disk) == 0x10);
}
I checked the file attributes returned by the WIN32 API using Python, and it seems that the folder in Dropbox returns 0x30 instead of 0x10. The attributes are a bit mask, so that's 0x20 | 0x10, where 0x10 is the "I'm a directory" bit and 0x20 is the "archive" bit.
I think the problem would go away if the above lines of code were replaced by:
int _sys_select(uint8 *disk) {
return(((uint8)GetFileAttributes((LPCSTR)disk) & 0x10) != 0);
}
Hi All,
I am trying to reduce the clock speed of my ESP32 module but it seems a bit difficult to change or somewhere I read we can't change the clock speed of the ESP32.
As my application is temperature sensitive and running on the battery so I thought by using lower clock speed I can achieve both.
Please let me know if anyone knows how to fix this issue.
CCP
for RunCPM
?The CPM-2.2 example disks set of AltairZ80 includes CCPZ Version 4.1
(attached here as ZIP).
What would I need to know about RunCPM
to get CCPZ
built and running with RunCPM
?
2016-09-24: ...added ccpz-binaries.zip.
Trying to compile latest download (as of today) and i get an overflow for the RAM array.
Not sure where it's coming from I've tried compiling for the uno (the actual target) but also for the mega and the due and they all get the same thing
D:\Arduino\arduino-builder -dump-prefs -logger=machine -hardware D:\Arduino\hardware -hardware C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages -tools D:\Arduino\tools-builder -tools D:\Arduino\hardware\tools\avr -tools C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages -built-in-libraries D:\Arduino\libraries -libraries C:\Users\Charles Blackburn\Documents\Arduino\libraries -fqbn=arduino:avr:uno -ide-version=10804 -build-path C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580 -warnings=none -build-cache C:\Users\CHARLE1\AppData\Local\Temp\arduino_cache_784956 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.arduinoOTA.path=C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\arduinoOTA\1.1.1 -prefs=runtime.tools.avrdude.path=C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino9 -prefs=runtime.tools.avr-gcc.path=C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2 -verbose C:\Users\Charles Blackburn\Documents\Arduino\RunCPM\RunCPM\RunCPM.ino
D:\Arduino\arduino-builder -compile -logger=machine -hardware D:\Arduino\hardware -hardware C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages -tools D:\Arduino\tools-builder -tools D:\Arduino\hardware\tools\avr -tools C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages -built-in-libraries D:\Arduino\libraries -libraries C:\Users\Charles Blackburn\Documents\Arduino\libraries -fqbn=arduino:avr:uno -ide-version=10804 -build-path C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580 -warnings=none -build-cache C:\Users\CHARLE1\AppData\Local\Temp\arduino_cache_784956 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.arduinoOTA.path=C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\arduinoOTA\1.1.1 -prefs=runtime.tools.avrdude.path=C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino9 -prefs=runtime.tools.avr-gcc.path=C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2 -verbose C:\Users\Charles Blackburn\Documents\Arduino\RunCPM\RunCPM\RunCPM.ino
Using board 'uno' from platform in folder: C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21
Using core 'arduino' from platform in folder: C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21
Detecting libraries used...
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp" -o "nul"1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp" -o "nul"
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "C:\Users\CHARLE
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp" -o "nul"1\AppData\Local\Temp\arduino_build_416580\sketch\main.c
Using cached library dependencies for file: C:\Users\CHARLE
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src\SPI.cpp" -o "nul"
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src\File.cpp" -o "nul"
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src\SD.cpp" -o "nul"
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src\utility\Sd2Card.cpp" -o "nul"
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src\utility\SdFile.cpp" -o "nul"
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src\utility\SdVolume.cpp" -o "nul"
Generating function prototypes...
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp" -o "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\preproc\ctags_target_for_gcc_minus_e.cpp"
"D:\Arduino\tools-builder\ctags\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\preproc\ctags_target_for_gcc_minus_e.cpp"1\AppData\Local\Temp\arduino_build_416580\sketch\main.c.o
Compiling sketch...
Using previously compiled file: C:\Users\CHARLE
"C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10804 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard" "-IC:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI\src" "-IC:\Users\Charles Blackburn\Documents\Arduino\libraries\SD\src" "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp" -o "C:\Users\CHARLE1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp.o"
In file included from C:\Users\Charles Blackburn\Documents\Arduino\RunCPM\RunCPM\RunCPM.ino:1:0:
globals.h:137: error: overflow in constant expression
uint8 RAM[RAMSIZE];
^
globals.h:137: error: overflow in array dimension
In file included from c:\users\charles blackburn\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\io.h:99:0,
from c:\users\charles blackburn\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\pgmspace.h:90,
from C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:28,
from C:\Users\CHARLE~1\AppData\Local\Temp\arduino_build_416580\sketch\RunCPM.ino.cpp:1:
cpu.h:14: error: expected unqualified-id before 'volatile'
int32 SP; /* SP register */
^
cpu.h:14: error: expected ')' before 'volatile'
cpu.h:14: error: expected ')' before 'volatile'
Multiple libraries were found for "SD.h"
Used: C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD
Not used: D:\Arduino\libraries\old_SD
Not used: D:\Arduino\libraries\SD
Using library SPI at version 1.0 in folder: C:\Users\Charles Blackburn\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\libraries\SPI
Using library SD at version 1.2.2 in folder: C:\Users\Charles Blackburn\Documents\Arduino\libraries\SD
exit status 1
overflow in constant expression
I've HiTech-C installed in C/0
and keep my C workspace in C/1
.
The location is defined in C/1/ENVIRON
:
C1>type environ
HITECH=0:C:
Watching the drive/user structure with watch 'ls -d ?/?'
in an own terminal window while compiling stuff shows, that the directory C/S
is created while compiling...
C1>c myhi.c
HI-TECH C COMPILER (CP/M-80) V3.09
Copyright (C) 1984-87 HI-TECH SOFTWARE
C1>myhi
No meltdown, no specte.
No rowhammer, no brainslammer!
CP/M!
;-)
C1>█
...and not while running the result.
I'm currently using the internal CCP but I remember having seen C/S
while using CCPZ too.
Is HiTech-C the only software creating strange drive/user directories?
Does this happen only on RunCPM's posix port?
Please have a look at your drive/user trees.
So far it looks like having no other side effects than generating this strange user area directory. I can live with that but if it shows up in other contexts too, narrowing it down may become easier.
I downloaded the Master today and did try to compile (with Arduino IDE 1.8.7) for the Arduino DUE.
First I did see I missed the SDFat Library and installed the v1.0.7 via "Manage Library"
But while compiling the IDE has some problems mit the SDFAT EX from the RunCPM.ino
Please read attached .txt file
Arduino_DUE_ErrMsgs.txt
Hi, I've been looking through the source code, getting an idea of RunCPM's strucutre and the BIOS emulation, and I noticed what looks like a debug monitor in the CPU module.
What I can't figure out is how to break into this debug module, so I can use this to test and debug 8080/Z80 code using the debugger.
Is there a way to do this from within the emulator, or should I build a custom version of the code with a way to break in to the debugger?
Since commit c80f7a0 Comal-80 for CP/M does not accept input on MacOS X and Linux.
How to reproduce:
Problem: With teensy 3.6, files in A/0 of sd showing duplicated, one normal short name e.g. asm.com and one false short name _AS~~.COM
Scenario:Using RunCPM files of 2018-feb-01, move contents of DISK/A.ZIP to SD under OSX (or Windows 10), and also copy DR 60K ccp to root of SD; take fresh Arduino 1.85 IDE for OSX, install teensyduino, open RunCPM.ino from unzip of github runcpm files. Build and upload Runcpm to teensy 3.6 with above SD card inserted. Terminal shows RunCPM running ok except no files visible on A; extract SD card to PC to move "A" files into folder A/0; re-insert SD card in teensy 3.6 and reboot; RunCPM working OK except see all files in folder A/0 ok and also see all files with a newly created short name, e.g. ASM.COM visible as ASM.COM and _AS~~1.COM. This looks like some sort of long/short naming problem.
Note 1) this error was visible also on windows10 hosted teensy3.6;
Note 2) on some occasions the error may show as only showing first file on disk folder A/0 with normal name, the other files wouldn't be visible. (on this occasion after teensy reboot to get screen shot, I only saw this flavour of error, could not get screen shot of error showing as full directory with duplicates.
Note 3) SD card is 4gb type 4 micro sd hc sandisk formatted as FAT 16
Note 4) with scenario on note 2 above , i found on subsequent testing that dir shows 1 file, but pip b:=a:. will find all files with proper name and all the false duplicates with _AS~.COM style of name
C:
contains Hi-Tech-C V3.09
.
...and there is a file OPTIONS
:
CP/M 2.2 Emulator v2.7 by Marcelo Dantas
Build Sep 21 2016 - 08:26:21
-----------------------------------------
CCP: CCP-DR.BIN Loaded at 0xf400
RunCPM Version 2.7 (CP/M 2.2 64K)
A>c:
C>dir options
C: OPTIONS
C>type options
OPTIONS?
C>a:stat options
Recs Bytes Ext Acc
0 0k 1 R/W C:OPTIONS
Bytes Remaining On C: 960k
C>_
...looking from Debian:
runcpm/run$ ls -l C/0/OPTIONS
-rw-r--r-- 1 yeti yeti 768 Sep 18 08:07 C/0/OPTIONS
runcpm/run$ stat -cx%nx C/0/OPTIONS
xC/0/OPTIONSx
runcpm/run$ _
It exists, has a length and has no spaces after the filename.
runcpm/run$ echo WORLD > C/0/HELLO
runcpm/run$ _
Look from CP/M...
CP/M 2.2 Emulator v2.7 by Marcelo Dantas
Build Sep 21 2016 - 08:26:21
-----------------------------------------
CCP: CCP-DR.BIN Loaded at 0xf400
RunCPM Version 2.7 (CP/M 2.2 64K)
A>c:
C>dir hello
C: HELLO
C>type hello
HELLO?
C>era hello
...then RunCPM
hangs.
It is ok to look confused now?
A>mbasic
BASIC-85 Rev. 5.29
[CP/M Version]
Copyright 1985-1986 $ by Microsoft
Created: 28-Jul-85
38968 Bytes free
Ok
open"O",1,"HELLO"
Ok
print#1,"WORLD"
Ok
close 1
Ok
system
RunCPM Version 2.7 (CP/M 2.2 64K)
A>dir hello
A: HELLO
A>type hello
WORLD
A>_
View from Debian:
runcpm/run$ ls -l A/0/HELL*
-rw-r--r-- 1 yeti yeti 128 Sep 21 10:02 A/0/HELLO.
runcpm/run$ stat -cx%nx A/0/HELLO.
xA/0/HELLO.x
runcpm/run$ _
Idea:
runcpm/run$ mv C/0/OPTIONS C/0/OPTIONS.
Back to CP/M:
C>type options
Z80 CP/M C compiler options:
-A Generate a self-relocating .COM program
-R Link in command line wild card expansion code
-V Be verbose during compilation
-S Generate assembler code in a .AS file; don't assemble or link
-C Generate object code only; don't link.
-O Invoke the peephole optimizer
-I Specify an include directory, e.g. -I1:B:
-U Undefine a predefined symbol, e.g. -UDEBUG
-D Define a symbol, e.g. -DDEBUG=1
-L Scan a library, e.g. -LF scans the floating point library
-F Generate a symbol file suitable for use with debug.com, e.g.
-Ffile.sym; default file name is L.SYM.
-W Set warning level, e.g. -w5 or -w-2
-X Suppress local symbols in symbol tables
-M Generate a map file, e.g. -Mfile.map
C>_
\o/
Files without extension need a trailing dot on *nixish filesystems for not confusing RunCPM (and me! )...
;-)
I have verified this with 2 CCP. I have used the internal as well as CCP-CCPZ.60
If I cause certain I/O errors to occur, files seem to disappear. After trying a few things, I discovered that my files were not truly disappearing, the User area was changing to "1".
How to test:
Create a system with at least 1 drive.
Do a DIR A: to verify that you see all of the files.
Try to switch to a non-existant drive letter. Example: C:
You will get a bdos error. Hit any key to put you back to A:
Do a DIR, where did the files go??
You have been put into USER 1.
Type USER 0 and poof! The files are back again.
I have verify that more than 1 CCP has this anomoly.
Is this an emulation problem or normal for CPM?
I am running Centos 7.6, make posix build
I have all user areas created A/0, A/1, A/2, etc...
As seen in commit 492c868 RunCPM has an icon now.
Maybe this is the moment to update RunCPM's gallery at hackaday.io?
Okay... this Sixel stuff maybe is overshooting a bit but RunCPM's page(s) at hackaday.io might benefit from an update due to the added platform(s) and other improvements.
Hello. I'm trying to run it on a teensy 3.5 but without success.
I change the SD type, A folder, 0 subfolder... there's something I'm missing?
It's great! Return to good old times of Speccy/80KB + home made disk drive.
As Win terminal seems very good Kitty (http://www.9bis.net/kitty/) with key remapping (PageUp/Down, arrows... can use almost standard WordStar command for cursor moving).
As CP/M text editor is ZDE (https://sites.google.com/site/vdeeditor/Home/vde-files) recommanded - very good stuff.
Once more - thanks for RunCMP
Platform: Arduino IDE ver 1.8.9
Board: ESP32
OS: Windows 10 with latest updates
Issue: Compiling runCPM produces the following error code:
In file included from C:\Users<myuser>\Documents\Arduino\Sketches\RunCPM\RunCPM\RunCPM.ino:50:0:
C:\Users<myuser>\AppData\Local\Temp\arduino_build_483789\sketch\abstraction_arduino.h: In function 'bool _sys_extendfile(char*, long unsigned int)':
C:\Users<myuser>\AppData\Local\Temp\arduino_build_483789\sketch\abstraction_arduino.h:171:29: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
if (f.write((uint8_t)0) < 0) {
^
Can you change the _sys_extendfile() routine so it functions correctly?
My changed routine is attached; however, modify it any way you desire to make if functional.
Thanks for developing this! I'm still waiting on my ESP32 board. Then I want to test runCPM on it.
Garry
$ make -f Makefile.posix run
rm -f RunCPM
rm -f main.o
gcc -Wall -O0 -fPIC -Wno-unused-variable -c main.c
gcc main.o -o RunCPM -lncurses
RunCPM
make: RunCPM: Command not found
Makefile.posix:51: recipe for target 'run' failed
make: *** [run] Error 127
$ tail -2 Makefile.posix
run: all
$(PROG)
Executing $(PROG)
will not work unless you include .
in your PATH
which is a big nono in the unix universe.
...and probably the sources directory does not have the CCP and the CP/M drives subdirectories, so make run
does not make much sense for 99,593% of all RunCPM users...
o;-)
Drop the "run:" target until somewhen there is "install:" too?
Has anyone done any speed tests? I'm wondering what the ESP32 runs at in terms of a real Z80 clock speed. It seems a little slow (but then, I got a bit spoiled with Grant Searle's Cyclone II board which runs like a 50Mhz Z80). On the ESP32, loading up, say MBASIC takes 6 seconds - and I'm wondering how much of this is disk activity and how much is CPU activity. Or maybe I've just forgotten how slow real floppy drives were!
Quick test on mbasic doing 10,000 multiplies in a loop takes 7 seconds.
The ESP32 reports a clock speed of an insane 240Mhz, and even allowing 20 instructions per Z80 instruction should still give a decent Z80 speed.
Hi All,
I am noticing something strange here, maybe you have seen the same and may be able to help.
I have tried many different things with no results. Here is the issue:
After I had to reinstall Windows 10, and Visual Studio 2017, when I built RunCPM it won't accept ESC-X to exit TE.COM (distributed on disk A:).
ESC-N and ESC-A seem to work, but not ESC-X.
Maybe I drew a blank, maybe I am not seeing something obvious, but if one of you has seen the same, let me know. I want to find out what is causing it.
Thanks,
Marcelo.
I just received a TTGO board. I compiled RunCPM and it seems to work.
I created a ESP32_telnetd.h and with a small change to the arduino_abstraction, I am now able to telnet into the ESP32/RunCPM board.
Seems to work, nothing has failed yet. The EXIT (was halt the emulator) command does a network close and waits for another inbound connection.
Is there a blog somewhere that we can post code and make comments?
Github seems to be the wrong tool for that type of activity.
$telnet 192.168.31.139
Trying 192.168.31.139...
Connected to 192.168.31.139.
Escape character is '^]'.
CP/M 2.2 Emulator v3.7 by Marcelo Dantas
Arduino read/write support by Krzysztof Klis
Build Jan 6 2019 - 22:27:16
'--------------------------------------------'
CCP: INTERNAL v1.5 CCP Address: 0xe400
BOARD: TTGO_T1
Initializing SD card.
RunCPM Version 3.7 (CP/M 2.2 60K)
A0>info
RunCPM System Information v1.0
RunCPM Version 3.7 running on ESP32
CCP is Internal Version 1.5
CCP loads at address E400h
BDOS is at address EC00h
BIOS is at address FE00h
60160 bytes available for applications
RunCPM Version 3.7 (CP/M 2.2 60K)
A0>exit
Connection closed by foreign host.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.