Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 9:b4293b01083b, committed 2020-04-17
- Comitter:
- davervw
- Date:
- Fri Apr 17 09:15:50 2020 +0000
- Parent:
- 8:519febdce8db
- Commit message:
- comment updates, and implemented optional #define LOCAL_LOAD // for loading from Mbed filesystem
Changed in this revision
--- a/emuc64.cpp Wed Apr 15 05:15:07 2020 +0000
+++ b/emuc64.cpp Fri Apr 17 09:15:50 2020 +0000
@@ -36,98 +36,119 @@
//
// LIMITATIONS:
// Only keyboard/console I/O. No text pokes, no graphics. Just stdio.
-// No asynchronous input (GET K$), but INPUT S$ works
+// No asynchronous input (GET K$), but INPUT S$ works. No key scan codes.
// No keyboard color switching. No border displayed. No border color.
+// No background screen color. No reverse colors implemented in this version.
// No screen editing (gasp!) Just short and sweet for running C64 BASIC in
-// terminal/console window via 6502 chip emulation in software
-// No PETSCII graphic characters, only supports printables CHR$(32) to CHR$(126), and CHR$(147) clear screen
-// No memory management. Full 64K RAM not accessible via banking despite startup screen.
-// Just 44K RAM, 16K ROM, 1K VIC-II color RAM nybbles
+// terminal/console window via 6502 chip emulation in software.
+// No PETSCII graphic characters, only supports printables CHR$(32) to CHR$(126),
+// and CHR$(147) clear screen and HOME/LEFT/RIGHT/UP/DOWN (see cbmconsole.cpp)
// No timers. No interrupts except BRK. No NMI/RESTORE key. No STOP key.
-// No loading of files implemented.
+// IRQ is specifically commented out because breaks terminal I/O.
+// Loading of files at startup is optional depending on availability of
+// a local file system store (e.g. Mbed MSD)
+// Device I/O not implemented. No tape/serial/printer/disk/joystick.
+// No VIC II.
+// No CIA1/CIA2.
+// No sound. Sorry no SID.
+// No cartridges.
+// Simple means simple. This is a simple emulator using terminal console.
//
-// $00/$01 (DDR and banking and I/O of 6510 missing), just RAM
-// $0000-$9FFF RAM (199=reverse if non-zero, 646=foreground color)
-// $A000-$BFFF BASIC ROM (write to RAM underneath, but haven't implemented read/banking)
+// MEMORY MAP
+// $00 (data direction missing)
+// $01 Banking implemented (tape sense/controls missing)
+// $0000-$9FFF RAM (upper limit may vary based on MCU SRAM available)
+// $A000-$BFFF BASIC ROM
+// $A000-$BFFF Banked LORAM (may not be present based on MCU SRAM limits)
// $C000-$CFFF RAM
-// $D000-$DFFF (missing I/O and character ROM and RAM banks), just zeros except...
-// $D021 Background Screen Color
-// $D800-$DFFF VIC-II color RAM nybbles (note: haven't implemented RAM banking)
-// $E000-$FFFF KERNAL ROM (write to RAM underneath, but haven't implemented read/banking)
-//
-// Requires user provided Commodore 64 BASIC/KERNAL ROMs (e.g. from VICE)
-// as they are not provided, others copyrights may still be in effect.
+// $D000-$D7FF (I/O missing, reads as zeros)
+// $D800-$DFFF VIC-II color RAM nybbles in I/O space (1K x 4bits)
+// $D000-$DFFF Banked RAM (may not be present based on MCU SRAM limits)
+// $D000-$DFFF Banked Character ROM
+// $E000-$FFFF KERNAL ROM
+// $E000-$FFFF Banked HIRAM (may not be present based on MCU SRAM limits)
//
////////////////////////////////////////////////////////////////////////////////
// ROMs copyright Commodore or their assignees
////////////////////////////////////////////////////////////////////////////////
#include <mbed.h>
-//#include <LocalFileSystem.h>
#include "emu6502.h"
#include "cbmconsole.h"
+#include "emuc64.h"
+
+// for limited SRAM MCUs, use a smaller number than 64. 3 <= RAM_SIZE <= 64
+#define RAM_SIZE 16
+//#define RAM_SIZE 64
// global references
extern Serial pc;
// globals
+#ifdef LOCAL_LOAD
char* StartupPRG = 0;
+#endif
// locals
-//static int startup_state = 0;
-//LocalFileSystem local("local");
+#ifdef LOCAL_LOAD
+static int startup_state = 0;
+#endif
-//static void File_ReadAllBytes(byte* bytes, unsigned int size, const char* filename)
-//{
-// int file;
-// file = open(filename, O_RDONLY);
-// if (file < 0)
-// {
-// pc.printf("file ""%s"", errno=%d\n", filename, errno);
-// exit(1);
-// }
-// read(file, bytes, size);
-// close(file);
-//}
+#ifdef LOCAL_LOAD
+static void File_ReadAllBytes(byte* bytes, unsigned int size, const char* filename)
+{
+ int file;
+ file = open(filename, O_RDONLY);
+ if (file < 0)
+ {
+ pc.printf("file ""%s"", errno=%d\n", filename, errno);
+ exit(1);
+ }
+ read(file, bytes, size);
+ close(file);
+}
+#endif
-//// returns true if BASIC
-//static bool LoadPRG(const char* filename)
-//{
-// bool result;
-// byte lo, hi;
-// int file;
-// ushort loadaddr;
-//
-// file = open(filename, O_RDONLY);
-// if (file < 0
-// || read(file, &lo, 1) != 1
-// || read(file, &hi, 1) != 1
-// )
-// {
-// pc.printf("file ""%s"", errno=%d\n", filename, errno);
-// exit(1);
-// }
-// if (lo == 1)
-// {
-// loadaddr = (ushort)(GetMemory(43) | (GetMemory(44) << 8));
-// result = true;
-// }
-// else
-// {
-// loadaddr = (ushort)(lo | (hi << 8));
-// result = false;
-// }
-// while (true)
-// {
-// byte value;
-// if (read(file, &value, 1) == 1)
-// SetMemory(loadaddr++, value);
-// else
-// break;
-// }
-// close(file);
-// return result;
-//}
+#ifdef LOCAL_LOAD
+// returns true if BASIC
+static bool LoadPRG(const char* filename)
+{
+ bool result;
+ byte lo, hi;
+ int file;
+ ushort loadaddr;
+
+ file = open(filename, O_RDONLY);
+ if (file < 0
+ || read(file, &lo, 1) != 1
+ || read(file, &hi, 1) != 1
+ )
+ {
+ pc.printf("file ""%s"", errno=%d\n", filename, errno);
+ exit(1);
+ }
+ if (lo == 1)
+ {
+ loadaddr = (ushort)(GetMemory(43) | (GetMemory(44) << 8));
+ result = true;
+ }
+ else
+ {
+ loadaddr = (ushort)(lo | (hi << 8));
+ result = false;
+ }
+ while (true)
+ {
+ byte value;
+ if (read(file, &value, 1) == 1)
+ SetMemory(loadaddr++, value);
+ else
+ break;
+ }
+ close(file);
+ return result;
+}
+#endif
bool ExecutePatch(void)
{
@@ -152,75 +173,78 @@
return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
}
-// else if (PC == 0xA474) // READY
-// {
-// if (StartupPRG != 0 && strlen(StartupPRG) > 0) // User requested program be loaded at startup
-// {
-// const char* filename = StartupPRG;
-// StartupPRG = 0;
-//
-// if (LoadPRG(filename))
-// {
-// //UNNEW that I used in late 1980s, should work well for loang a program too, probably gleaned from BASIC ROM
-// //ldy #0
-// //lda #1
-// //sta(43),y
-// //iny
-// //sta(43),y
-// //jsr $a533 ; LINKPRG
-// //clc
-// //lda $22
-// //adc #2
-// //sta 45
-// //lda $23
-// //adc #0
-// //sta 46
-// //lda #0
-// //jsr $a65e ; CLEAR/CLR
-// //jmp $a474 ; READY
-//
-// // This part shouldn't be necessary as we have loaded, not recovering from NEW, bytes should still be there
-// ushort addr = (ushort)(GetMemory(43) | (GetMemory(44) << 8));
-// SetMemory(addr, 1);
-// SetMemory((ushort)(addr + 1), 1);
-//
-// // JSR equivalent
-// ushort retaddr = (ushort)(PC - 1);
-// Push(HI(retaddr));
-// Push(LO(retaddr));
-// PC = 0xA533; // LINKPRG
-//
-// startup_state = 1; // should be able to regain control when returns...
-//
-// return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
-// }
-// }
-// else if (startup_state == 1)
-// {
-// ushort addr = (ushort)(GetMemory(0x22) | (GetMemory(0x23) << 8) + 2);
-// SetMemory(45, (byte)addr);
-// SetMemory(46, (byte)(addr >> 8));
-//
-// // JSR equivalent
-// ushort retaddr = (ushort)(PC - 1);
-// Push(HI(retaddr));
-// Push(LO(retaddr));
-// PC = 0xA65E; // CLEAR/CLR
-// A = 0;
-//
-// startup_state = 2; // should be able to regain control when returns...
-//
-// return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
-// }
-// else if (startup_state == 2)
-// {
-// CBM_Console_Push("RUN\r");
-// PC = 0xA47B; // skip READY message, but still set direct mode, and continue to MAIN
-// C = false;
-// startup_state = 0;
-// return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
-// }
-// }
+#ifdef LOCAL_LOAD
+ else if (PC == 0xA474) // READY
+ {
+ if (StartupPRG != 0 && strlen(StartupPRG) > 0) // User requested program be loaded at startup
+ {
+ const char* filename = StartupPRG;
+ StartupPRG = 0;
+
+ if (LoadPRG(filename))
+ {
+ //UNNEW that I used in late 1980s, should work well for loang a program too, probably gleaned from BASIC ROM
+ //ldy #0
+ //lda #1
+ //sta(43),y
+ //iny
+ //sta(43),y
+ //jsr $a533 ; LINKPRG
+ //clc
+ //lda $22
+ //adc #2
+ //sta 45
+ //lda $23
+ //adc #0
+ //sta 46
+ //lda #0
+ //jsr $a65e ; CLEAR/CLR
+ //jmp $a474 ; READY
+
+ // This part shouldn't be necessary as we have loaded, not recovering from NEW, bytes should still be there
+ ushort addr = (ushort)(GetMemory(43) | (GetMemory(44) << 8));
+ SetMemory(addr, 1);
+ SetMemory((ushort)(addr + 1), 1);
+
+ // JSR equivalent
+ ushort retaddr = (ushort)(PC - 1);
+ Push(HI(retaddr));
+ Push(LO(retaddr));
+ PC = 0xA533; // LINKPRG
+
+ startup_state = 1; // should be able to regain control when returns...
+
+ return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
+ }
+ }
+ else if (startup_state == 1)
+ {
+ ushort addr = (ushort)(GetMemory(0x22) | (GetMemory(0x23) << 8) + 2);
+ SetMemory(45, (byte)addr);
+ SetMemory(46, (byte)(addr >> 8));
+
+ // JSR equivalent
+ ushort retaddr = (ushort)(PC - 1);
+ Push(HI(retaddr));
+ Push(LO(retaddr));
+ PC = 0xA65E; // CLEAR/CLR
+ A = 0;
+
+ startup_state = 2; // should be able to regain control when returns...
+
+ return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
+ }
+ else if (startup_state == 2)
+ {
+ CBM_Console_Push("RUN\r");
+ PC = 0xA47B; // skip READY message, but still set direct mode, and continue to MAIN
+ C = false;
+ startup_state = 0;
+ return true; // overriden, and PC changed, so caller should reloop before execution to allow breakpoint/trace/ExecutePatch/etc.
+ }
+ }
+#endif // LOCAL_LOAD
+
return false; // execute normally
}
@@ -873,7 +897,7 @@
'\xF0','\xF0','\xF0','\xF0','\xFF','\xFF','\xFF','\xFF','\xE7','\xE7','\xE7','\x07','\x07','\xFF','\xFF','\xFF','\x0F','\x0F','\x0F','\x0F','\xFF','\xFF','\xFF','\xFF','\x0F','\x0F','\x0F','\x0F','\xF0','\xF0','\xF0','\xF0'
};
-static byte ram[24 * 1024]; // MAX: 64 * 1024 if you have the SRAM, allows RAM banking
+static byte ram[RAM_SIZE * 1024]; // MAX: 64 * 1024 if you have the SRAM, allows RAM banking
static byte color_nybles[1024];
// note ram starts at 0x0000
@@ -888,6 +912,7 @@
void C64_Init(const char* basic_file, const char* chargen_file, const char* kernal_file)
{
//File_ReadAllBytes(basic_rom, sizeof(basic_rom), basic_file);
+ //File_ReadAllBytes(char_rom, sizeof(char_rom), chargen_file);
//File_ReadAllBytes(kernal_rom, sizeof(kernal_rom), kernal_file);
for (int i = 0; i < sizeof(ram); ++i)
@@ -943,8 +968,6 @@
)
)
ram[addr] = value;
- else if (addr == 0xD021) // background
- ;
else if (addr >= color_addr && addr < color_addr + sizeof(color_nybles))
color_nybles[addr - color_addr] = value;
//else if (addr >= io_addr && addr < io_addr + io.Length)
--- a/emuc64.h Wed Apr 15 05:15:07 2020 +0000 +++ b/emuc64.h Fri Apr 17 09:15:50 2020 +0000 @@ -32,6 +32,12 @@ #pragma once +// note: LOCAL_LOAD/StartupPRG requires a file system implementation (SD, Mbed MSD, etc.) +//#define LOCAL_LOAD + extern void C64_Init(const char* basic_file, const char* chargen_file, const char* kernal_file); + +#ifdef LOCAL_LOAD extern char* StartupPRG; +#endif
--- a/main.cpp Wed Apr 15 05:15:07 2020 +0000
+++ b/main.cpp Fri Apr 17 09:15:50 2020 +0000
@@ -35,17 +35,33 @@
#include "emuc64.h"
#include "emu6502.h"
+#ifdef LOCAL_LOAD
+#include <LocalFileSystem.h>
+LocalFileSystem local("local");
+#endif
+
Serial pc(USBTX, USBRX, 115200);
+//Serial pc(p9, p10, 115200);
int main(/*int argc, char* argv[]*/)
{
pc.printf("\n");
- pc.printf("c-simple-emu-cbm version 1.6\n");
+ pc.printf("c-simple-emu-cbm version 1.7 for Mbed\n");
pc.printf("Copyright (c) 2020 by David R. Van Wagner\n");
- pc.printf("MIT License\n");
+ pc.printf("Open Source - MIT License\n");
pc.printf("github.com/davervw\n");
pc.printf("\n");
- //StartupPRG = "/local/guess2.prg";
+ pc.printf("Contains other licensed software\n");
+ pc.printf(" ARM MBED OS\n");
+ pc.printf("\n");
+ pc.printf("Commodore ROMs not licensed\n");
+ pc.printf("\n");
+
+#ifdef LOCAL_LOAD
+ // note: requires a file system implementation (SD, Mbed MSD, etc.)
+ StartupPRG = "/local/startup.prg";
+#endif
+
C64_Init("/local/basic", "/local/chargen", "/local/kernal");
ResetRun(ExecutePatch);
return 0;
--- a/mbed-os.lib Wed Apr 15 05:15:07 2020 +0000 +++ b/mbed-os.lib Fri Apr 17 09:15:50 2020 +0000 @@ -1,1 +1,1 @@ -https://github.com/ARMmbed/mbed-os/#532654ebb31c7bf79601042a6fa976b85532ef47 +https://github.com/ARMmbed/mbed-os/#565ab149819481224ab43f878c3921b14b11d180