diff --git a/README.md b/README.md
index f1f9be36..b8c2d3b6 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,7 @@ The IDE uses custom forks for many of these, found at https://github.com/sehugg?
* https://github.com/dmsc/fastbasic
* https://github.com/wiz-lang/wiz
* https://github.com/sylefeb/Silice
+* https://github.com/steux/cc7800
### Assemblers/Linkers
diff --git a/index.html b/index.html
index fccd22fd..9be4b488 100644
--- a/index.html
+++ b/index.html
@@ -167,7 +167,6 @@ body {
MSX (libCV)
Apple ][+
ZX Spectrum
- x86 (FreeDOS)
Amstrad CPC6128
@@ -209,6 +208,7 @@ body {
NES (MAME)
Williams (6809)
+ x86 (FreeDOS)
diff --git a/presets/atari7800/example_small_sprites.c78 b/presets/atari7800/example_small_sprites.c78
new file mode 100644
index 00000000..e8de02f9
--- /dev/null
+++ b/presets/atari7800/example_small_sprites.c78
@@ -0,0 +1,59 @@
+// example from https://github.com/steux/cc7800 - license: GPLv3
+
+#include "prosystem.h"
+#include "multisprite.h"
+
+char i, xpos, ypos;
+
+#define NB_SMALL_SPRITES 128
+ramchip short sp_xpos[NB_SMALL_SPRITES], sp_ypos[NB_SMALL_SPRITES];
+ramchip char sp_direction[NB_SMALL_SPRITES];
+
+const signed short dx[24] = {300, 289, 259, 212, 149, 77, 0, -77, -150, -212, -259, -289, -300, -289, -259, -212, -149, -77, 0, 77, 149, 212, 259, 289};
+const signed short dy[24] = {0, 124, 240, 339, 415, 463, 480, 463, 415, 339, 240, 124, 0, -124, -239, -339, -415, -463, -480, -463, -415, -339, -240, -124};
+const char horizontal_pingpong[24] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13 };
+const char vertical_pingpong[24] = { 0, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
+
+// Generated with sprites7800 missile.yaml
+holeydma reversed scattered(16,1) char missile[16] = {
+ 0x18, 0x96, 0x7a, 0x7e, 0x7e, 0x6e, 0x9a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void main()
+{
+ multisprite_init();
+
+ *P0C1 = multisprite_color(0x1c); // Yellow
+ *P0C2 = multisprite_color(0x37); // Orange
+ *P0C3 = multisprite_color(0x43); // Red
+
+ // Initialize small sprites
+ for (ypos = 0, xpos = 0, i = 0, X = 0; X != NB_SMALL_SPRITES; xpos++, ypos++, X++) {
+ sp_xpos[X] = xpos << 8;
+ sp_ypos[X] = ypos << 8;
+ sp_direction[X] = i++;
+ if (i == 24) i = 0;
+ }
+
+ // Main loop
+ do {
+ multisprite_flip();
+ for (i = 0; i != NB_SMALL_SPRITES; i++) {
+ X = i;
+ Y = sp_direction[X];
+ sp_xpos[X] += dx[Y];
+ sp_ypos[X] += dy[Y];
+ xpos = sp_xpos[X] >> 8;
+ ypos = sp_ypos[X] >> 8;
+ if ((xpos < 5 && (dx[Y] >> 8) < 0) ||
+ (xpos >= 150 && (dx[Y] >> 8) >= 0)) {
+ sp_direction[X] = horizontal_pingpong[Y];
+ }
+ if ((ypos < 5 && (dy[Y] >> 8) < 0) ||
+ (ypos >= MS_YMAX - 20 && (dy[Y] >> 8) >= 0)) {
+ sp_direction[X] = vertical_pingpong[Y];
+ }
+ multisprite_display_small_sprite(xpos, ypos, missile, 1, 0, 8);
+ }
+ } while(1);
+}
diff --git a/presets/atari7800/example_vertical_scrolling.c78 b/presets/atari7800/example_vertical_scrolling.c78
new file mode 100644
index 00000000..b78eae87
--- /dev/null
+++ b/presets/atari7800/example_vertical_scrolling.c78
@@ -0,0 +1,110 @@
+// example from https://github.com/steux/cc7800 - license: GPLv3
+
+#include "prosystem.h"
+#include "gfx.h"
+#define DMA_CHECK
+#define VERTICAL_SCROLLING
+#define _MS_DL_SIZE 64
+#define _MS_DL_MALLOC(y) ((y == 6 || y == 7 || y == 8)?_MS_DL_SIZE * 2:_MS_DL_SIZE)
+#include "multisprite.h"
+
+char i, counter, xpos, ypos;
+char *ptr;
+char xchest;
+
+#define NB_SPRITES 32
+ramchip short sp_xpos[NB_SPRITES], sp_ypos[NB_SPRITES];
+ramchip char sp_direction[NB_SPRITES];
+
+const signed short dx[24] = {300, 289, 259, 212, 149, 77, 0, -77, -150, -212, -259, -289, -300, -289, -259, -212, -149, -77, 0, 77, 149, 212, 259, 289};
+const signed short dy[24] = {0, 124, 240, 339, 415, 463, 480, 463, 415, 339, 240, 124, 0, -124, -239, -339, -415, -463, -480, -463, -415, -339, -240, -124};
+const char horizontal_pingpong[24] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13 };
+const char vertical_pingpong[24] = { 0, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
+
+const char background[22] = { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 };
+#define LTR(x) (((x) - ' ') * 2)
+const char hello_world[] = { LTR('H'), LTR('E'), LTR('L'), LTR('L'), LTR('O'), LTR(' '), LTR('W'), LTR('O'), LTR('R'), LTR('L'), LTR('D') };
+
+void main()
+{
+ counter = 0;
+
+ multisprite_init();
+ multisprite_set_charbase(tiles);
+
+ // Set up a full background
+ for (counter = 0; counter < _MS_DLL_ARRAY_SIZE; counter++) {
+ if (counter & 2) {
+ ptr = background + 2;
+ } else {
+ ptr = background;
+ }
+ multisprite_display_tiles(0, _MS_DLL_ARRAY_SIZE - 1 - counter, ptr, 20, 1);
+ }
+ multisprite_save();
+
+ *P0C1 = multisprite_color(0x1c); // Setup Palette 0: Yellow
+ *P0C2 = multisprite_color(0xc5); // Green
+ *P0C3 = 0x0f; // White
+
+ *P1C1 = multisprite_color(0x55); // Dark pink
+ *P1C2 = multisprite_color(0x5B); // Light pink
+
+ *P2C1 = multisprite_color(0x32);
+ *P2C2 = multisprite_color(0x3D);
+ *P2C3 = multisprite_color(0x37);
+
+ *P3C1 = multisprite_color(0x92);
+ *P3C2 = multisprite_color(0x97);
+ *P3C3 = multisprite_color(0x9D);
+
+ // Initialize sprites
+ for (ypos = 0, xpos = 0, i = 0, X = 0; X != NB_SPRITES; xpos++, ypos++, X++) {
+ sp_xpos[X] = xpos << 8;
+ sp_ypos[X] = ypos << 8;
+ sp_direction[X] = i++;
+ if (i == 24) i = 0;
+ }
+
+ // Main loop
+ do {
+ // Prepare scrolling data
+ if (multisprite_vscroll_buffer_empty()) {
+ if (counter & 2) {
+ ptr = background + 2;
+ } else {
+ ptr = background;
+ }
+ multisprite_vscroll_buffer_tiles(0, ptr, 20, 1);
+ multisprite_vscroll_buffer_sprite(xchest, chest, 2, 3);
+ xchest += 45;
+ counter++;
+ }
+
+ while (*MSTAT & 0x80);
+ multisprite_flip();
+ multisprite_vertical_scrolling(-1);
+ multisprite_reserve_dma(104, sizeof(hello_world), 2);
+ for (i = 0; i != NB_SPRITES; i++) {
+ X = i;
+ Y = sp_direction[X];
+ sp_xpos[X] += dx[Y];
+ sp_ypos[X] += dy[Y];
+ xpos = sp_xpos[X] >> 8;
+ ypos = sp_ypos[X] >> 8;
+ if ((xpos < 5 && (dx[Y] >> 8) < 0) ||
+ (xpos >= 150 && (dx[Y] >> 8) >= 0)) {
+ sp_direction[X] = horizontal_pingpong[Y];
+ }
+ if ((ypos < 5 && (dy[Y] >> 8) < 0) ||
+ (ypos >= MS_YMAX - 20 && (dy[Y] >> 8) >= 0)) {
+ sp_direction[X] = vertical_pingpong[Y];
+ }
+ multisprite_display_sprite(xpos, ypos, bb_char1, 2, 0);
+ }
+ for (xpos = 40, i = 0; i != sizeof(hello_world); xpos += 8, i++) {
+ ptr = chars0 + hello_world[X = i];
+ multisprite_display_sprite_fast(xpos, 104, ptr, 2, 2);
+ }
+ } while(1);
+}
diff --git a/presets/atari7800/gfx.h b/presets/atari7800/gfx.h
new file mode 100644
index 00000000..5ab7562e
--- /dev/null
+++ b/presets/atari7800/gfx.h
@@ -0,0 +1,152 @@
+// example from https://github.com/steux/cc7800 - license: GPLv3
+
+reversed scattered(16,4) char tiles[64] = {
+ 0x5a, 0x5a, 0x95, 0x95, 0x69, 0x69, 0x65, 0x65, 0x69, 0x69, 0x95, 0x95, 0xa5, 0xa5, 0x65, 0x65,
+ 0xa5, 0xa5, 0xa9, 0xa9, 0x96, 0x96, 0xa6, 0xa6, 0x96, 0x96, 0xa9, 0xa9, 0x5a, 0x5a, 0xa6, 0xa6,
+ 0x5a, 0x5a, 0x95, 0x95, 0x69, 0x69, 0x65, 0x65, 0x69, 0x69, 0x95, 0x95, 0xa5, 0xa5, 0x65, 0x65,
+ 0xa5, 0xa5, 0xa9, 0xa9, 0x96, 0x96, 0xa6, 0xa6, 0x96, 0x96, 0xa9, 0xa9, 0x5a, 0x5a, 0xa6, 0xa6
+};
+holeydma reversed scattered(16,32) char chars0[512] = {
+ 0x00, 0x00, 0x05, 0x00, 0x50, 0x50, 0x51, 0x40, 0x05, 0x00, 0x50, 0x10, 0x15, 0x40, 0x00, 0x50,
+ 0x01, 0x40, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x50, 0x50, 0x51, 0x40, 0x05, 0x00, 0x50, 0x10, 0x15, 0x40, 0x00, 0x50,
+ 0x01, 0x40, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x60, 0x90, 0x62, 0x40, 0x16, 0x60, 0x90, 0x60, 0x5f, 0x90, 0x01, 0xb0,
+ 0x06, 0xc0, 0x36, 0x00, 0x90, 0x60, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
+ 0x00, 0x00, 0x05, 0x00, 0x50, 0x50, 0x51, 0x80, 0x25, 0x50, 0x50, 0x50, 0x90, 0x60, 0x01, 0x40,
+ 0x05, 0x00, 0x05, 0x00, 0x50, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
+ 0x00, 0x00, 0x09, 0x00, 0x50, 0x92, 0x65, 0x90, 0x6f, 0xf0, 0xf2, 0x70, 0xd9, 0x70, 0x09, 0xc0,
+ 0x27, 0x00, 0x0e, 0x40, 0xd6, 0x70, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
+ 0x00, 0x00, 0x06, 0x00, 0x90, 0x61, 0x99, 0x60, 0x50, 0x00, 0x01, 0x80, 0x26, 0x40, 0x06, 0x00,
+ 0x18, 0x00, 0x01, 0x80, 0x25, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90,
+ 0x00, 0x00, 0x06, 0x00, 0xf0, 0xf3, 0x6e, 0x70, 0xe6, 0x40, 0x06, 0xc0, 0x26, 0xc0, 0x0f, 0x00,
+ 0x24, 0x00, 0x02, 0x42, 0x66, 0x64, 0x66, 0x60, 0x00, 0x00, 0x66, 0x60, 0x00, 0x00, 0x02, 0x70,
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x62, 0x40, 0x26, 0x40, 0x06, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x02, 0x42, 0x66, 0x64, 0x66, 0x60, 0x00, 0x00, 0x66, 0x60, 0x00, 0x00, 0x02, 0x40,
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x02, 0x6a, 0x60, 0x3f, 0xa0, 0x1b, 0x00, 0x6d, 0xa0, 0x00, 0x00,
+ 0x28, 0x00, 0x02, 0x83, 0xda, 0x7c, 0xf6, 0xf0, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x09, 0xc0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa6, 0x90, 0x00, 0x90, 0x28, 0x00, 0x92, 0x60, 0x00, 0x00,
+ 0x24, 0x00, 0x01, 0x80, 0x29, 0x80, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xae, 0xb0, 0x6a, 0xb0, 0xac, 0xa0, 0xa2, 0x70, 0x00, 0x00,
+ 0x36, 0x00, 0x0a, 0xc0, 0xaf, 0xa0, 0x0a, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x27, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, 0xa6, 0x80, 0x90, 0x60, 0x62, 0x80, 0x00, 0x00,
+ 0x0a, 0x00, 0x06, 0x00, 0x90, 0x60, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x28, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xa2, 0x80, 0xfa, 0xc0, 0xb0, 0xa0, 0xea, 0xa0, 0x00, 0x00,
+ 0x0e, 0x80, 0x2b, 0x00, 0xf0, 0xf0, 0x0f, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xac, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xa2, 0x80, 0x0a, 0x00, 0x80, 0xa0, 0x2a, 0xa0, 0x00, 0x00,
+ 0x02, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xa0, 0x00,
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xf3, 0xc0, 0x0f, 0x00, 0xc0, 0xf0, 0x3f, 0xf0, 0x00, 0x00,
+ 0x03, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+holeydma reversed scattered(16,32) char chars1[512] = {
+ 0x15, 0x40, 0x05, 0x00, 0x15, 0x40, 0x15, 0x40, 0x01, 0x40, 0x55, 0x50, 0x15, 0x40, 0x55, 0x50,
+ 0x15, 0x40, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, 0x15, 0x40,
+ 0x15, 0x40, 0x05, 0x00, 0x15, 0x40, 0x15, 0x40, 0x01, 0x40, 0x55, 0x50, 0x15, 0x40, 0x55, 0x50,
+ 0x15, 0x40, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, 0x15, 0x40,
+ 0x5a, 0x70, 0x0d, 0x00, 0x7a, 0xd0, 0x7a, 0x50, 0x07, 0x40, 0xda, 0xa0, 0x5a, 0xd0, 0x7a, 0xd0,
+ 0x7a, 0x50, 0xda, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0xa0, 0x00, 0x00, 0xa7, 0x00, 0xda, 0x70,
+ 0x70, 0xd0, 0x05, 0x00, 0x50, 0x50, 0x50, 0xd0, 0x05, 0x40, 0x50, 0x00, 0xd0, 0x70, 0x50, 0x50,
+ 0x50, 0xd0, 0x70, 0x50, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x50, 0x50,
+ 0x51, 0x70, 0x1d, 0x00, 0xa0, 0xd0, 0xa0, 0xd0, 0x37, 0x40, 0xd7, 0x40, 0xd0, 0xa0, 0xa1, 0xe0,
+ 0x70, 0xd0, 0x70, 0x50, 0x07, 0x00, 0x0d, 0x00, 0x1e, 0x00, 0x75, 0xd0, 0x0b, 0x40, 0xa0, 0x70,
+ 0xd3, 0x50, 0x37, 0x00, 0x00, 0x70, 0x00, 0x70, 0x1d, 0xc0, 0x75, 0xc0, 0x70, 0x00, 0x03, 0x40,
+ 0xd0, 0x70, 0x50, 0xd0, 0x05, 0x00, 0x07, 0x00, 0x14, 0x00, 0xdd, 0x70, 0x01, 0xc0, 0x00, 0xd0,
+ 0x76, 0xd0, 0x27, 0x00, 0x03, 0x60, 0x07, 0x60, 0x6b, 0x40, 0xaa, 0x70, 0x77, 0x40, 0x07, 0x80,
+ 0xb7, 0x60, 0xb7, 0x70, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0xaa, 0xa0, 0x02, 0x70, 0x03, 0x60,
+ 0xdc, 0x70, 0x07, 0x00, 0x03, 0x40, 0x07, 0x40, 0x43, 0x40, 0x00, 0x70, 0x77, 0x40, 0x07, 0x00,
+ 0x37, 0x40, 0x37, 0x70, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x70, 0x03, 0x40,
+ 0xd8, 0xf0, 0x0d, 0x00, 0x36, 0x80, 0x0a, 0x70, 0xf7, 0xf0, 0x00, 0x70, 0x7a, 0xf0, 0x07, 0x00,
+ 0x7a, 0x70, 0x2a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xdf, 0x70, 0x03, 0xe0, 0x0d, 0x80,
+ 0xf0, 0x70, 0x0f, 0x00, 0x1c, 0x00, 0x00, 0xd0, 0x7d, 0xd0, 0x00, 0xf0, 0xd0, 0x70, 0x0f, 0x00,
+ 0xf0, 0xd0, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x7d, 0xf0, 0x03, 0x40, 0x07, 0x00,
+ 0xf0, 0xd0, 0x0f, 0x00, 0xf8, 0x00, 0xf0, 0xf0, 0xab, 0xe0, 0xf0, 0xf0, 0xf0, 0x70, 0x0f, 0x00,
+ 0xf0, 0xf0, 0x70, 0xf0, 0x0f, 0x00, 0x0f, 0x00, 0x2f, 0x00, 0xaa, 0xa0, 0x0f, 0x80, 0x0a, 0x00,
+ 0xd0, 0xf0, 0x0f, 0x00, 0xd0, 0x00, 0xf0, 0x70, 0x03, 0xc0, 0xd0, 0x70, 0x70, 0xf0, 0x0d, 0x00,
+ 0x70, 0x70, 0xf0, 0xd0, 0x0f, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0xbd, 0xe0, 0xff, 0xf0, 0xff, 0xf0, 0xbf, 0xe0, 0x03, 0xc0, 0xbf, 0xe0, 0xbf, 0xe0, 0x0f, 0x00,
+ 0xbf, 0xe0, 0xbf, 0xe0, 0x0a, 0x00, 0x3e, 0x00, 0x0b, 0xf0, 0x00, 0x00, 0xfe, 0x00, 0x0d, 0x00,
+ 0x3f, 0xc0, 0xff, 0xf0, 0xff, 0xf0, 0x3f, 0xc0, 0x03, 0xc0, 0x3f, 0xc0, 0x3f, 0xc0, 0x0f, 0x00,
+ 0x3f, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0x3c, 0x00, 0x03, 0xf0, 0x00, 0x00, 0xfc, 0x00, 0x0f, 0x00,
+ 0x2a, 0x80, 0xaa, 0xa0, 0xaa, 0xa0, 0x2a, 0x80, 0x02, 0x80, 0x2a, 0x80, 0x2a, 0x80, 0x0a, 0x00,
+ 0x2a, 0x80, 0x2a, 0x80, 0x00, 0x00, 0x28, 0x00, 0x02, 0xa0, 0x00, 0x00, 0xa8, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+holeydma reversed scattered(16,32) char chars2[512] = {
+ 0x15, 0x40, 0x05, 0x00, 0x55, 0x40, 0x15, 0x40, 0x55, 0x00, 0x55, 0x50, 0x55, 0x50, 0x15, 0x40,
+ 0x50, 0x50, 0x15, 0x40, 0x05, 0x50, 0x50, 0x50, 0x50, 0x00, 0x50, 0x14, 0x50, 0x50, 0x15, 0x40,
+ 0x15, 0x40, 0x05, 0x00, 0x55, 0x40, 0x15, 0x40, 0x55, 0x00, 0x55, 0x50, 0x55, 0x50, 0x15, 0x40,
+ 0x50, 0x50, 0x15, 0x40, 0x05, 0x50, 0x50, 0x50, 0x50, 0x00, 0x50, 0x14, 0x50, 0x50, 0x15, 0x40,
+ 0x5a, 0x70, 0x1d, 0xc0, 0x7a, 0xd0, 0x7a, 0x50, 0xdb, 0x40, 0xda, 0xa0, 0x5a, 0xa0, 0x7a, 0xd0,
+ 0x70, 0x50, 0x27, 0x80, 0x09, 0x60, 0x51, 0xe0, 0x70, 0x00, 0x74, 0x5c, 0xd4, 0x70, 0xda, 0x70,
+ 0x70, 0xd0, 0x15, 0x40, 0x50, 0x50, 0x50, 0xd0, 0x71, 0x40, 0x50, 0x00, 0xd0, 0x00, 0x50, 0x50,
+ 0x50, 0xd0, 0x05, 0x00, 0x03, 0x40, 0xd1, 0x40, 0x50, 0x00, 0x54, 0xd4, 0x74, 0x50, 0x50, 0x50,
+ 0x51, 0x70, 0xda, 0x70, 0x50, 0xd0, 0x70, 0xa0, 0x72, 0x50, 0xd0, 0x00, 0xd0, 0x00, 0x50, 0xa0,
+ 0x70, 0xd0, 0x07, 0x00, 0x03, 0x40, 0xdd, 0x80, 0x50, 0x00, 0x75, 0xdc, 0x77, 0x50, 0xd0, 0x70,
+ 0xd3, 0x50, 0x70, 0x50, 0xd0, 0x70, 0xd0, 0x00, 0x50, 0xd0, 0x70, 0x00, 0x70, 0x00, 0xd0, 0x00,
+ 0xd0, 0x70, 0x0d, 0x00, 0x01, 0xc0, 0x77, 0x00, 0xd0, 0x00, 0xdd, 0x74, 0x5d, 0xd0, 0x70, 0xd0,
+ 0x73, 0xd0, 0x77, 0x70, 0x77, 0x60, 0x70, 0x00, 0x70, 0x70, 0x77, 0x00, 0x77, 0x00, 0x73, 0x70,
+ 0x77, 0x70, 0x07, 0x00, 0x03, 0x40, 0x76, 0x00, 0x70, 0x00, 0x7b, 0xb4, 0x77, 0x70, 0x70, 0x70,
+ 0xd1, 0x70, 0x77, 0x70, 0x77, 0x40, 0x70, 0x00, 0x70, 0x70, 0x77, 0x00, 0x77, 0x00, 0x73, 0x70,
+ 0x77, 0x70, 0x07, 0x00, 0x03, 0x40, 0x74, 0x00, 0x70, 0x00, 0x73, 0x34, 0x77, 0x70, 0x70, 0x70,
+ 0xd2, 0xa0, 0x7a, 0xf0, 0xfa, 0xd0, 0x70, 0x00, 0xf0, 0xf0, 0xda, 0x00, 0x7a, 0x00, 0xf2, 0xd0,
+ 0x7a, 0x70, 0x07, 0x00, 0x03, 0x40, 0xf7, 0x00, 0x70, 0x00, 0xd2, 0x3c, 0xfb, 0xd0, 0x70, 0xf0,
+ 0xf0, 0x00, 0xd0, 0x70, 0xd0, 0x70, 0xf0, 0x00, 0x70, 0xd0, 0x70, 0x00, 0xd0, 0x00, 0xd0, 0x70,
+ 0xf0, 0xd0, 0x0d, 0x00, 0x01, 0xc0, 0xdf, 0x00, 0xf0, 0x00, 0x70, 0x34, 0xd3, 0x70, 0xf0, 0xd0,
+ 0xf0, 0x10, 0xf0, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0x73, 0xe0, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0x0f, 0x00, 0xf3, 0xc0, 0xfb, 0xc0, 0xf0, 0x00, 0xf0, 0x3c, 0xf2, 0xf0, 0xf0, 0xf0,
+ 0xd0, 0x30, 0xd0, 0xf0, 0xd0, 0x70, 0xf0, 0x70, 0xf3, 0xc0, 0xd0, 0x00, 0x70, 0x00, 0xd0, 0xd0,
+ 0x70, 0x70, 0x07, 0x00, 0xd3, 0x40, 0xd1, 0xc0, 0x70, 0x00, 0xd0, 0x34, 0xd0, 0xf0, 0xf0, 0xf0,
+ 0xbd, 0xe0, 0xf0, 0xf0, 0xff, 0xe0, 0xbf, 0xe0, 0xff, 0x80, 0xff, 0xf0, 0xf0, 0x00, 0xbf, 0xe0,
+ 0xf0, 0xf0, 0x3f, 0xc0, 0xbf, 0x80, 0xf2, 0xf0, 0xff, 0xf0, 0xf0, 0x3c, 0xf0, 0xf0, 0xbd, 0xe0,
+ 0x3f, 0xc0, 0xf0, 0xf0, 0xff, 0xc0, 0x3f, 0xc0, 0xff, 0x00, 0xff, 0xf0, 0xf0, 0x00, 0x3f, 0xc0,
+ 0xf0, 0xf0, 0x3f, 0xc0, 0x3f, 0x00, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x3c, 0xf0, 0xf0, 0x3f, 0xc0,
+ 0x2a, 0x80, 0xa0, 0xa0, 0xaa, 0x80, 0x2a, 0x80, 0xaa, 0x00, 0xaa, 0xa0, 0xa0, 0x00, 0x2a, 0x80,
+ 0xa0, 0xa0, 0x2a, 0x80, 0x2a, 0x00, 0xa0, 0xa0, 0xaa, 0xa0, 0xa0, 0x28, 0xa0, 0xa0, 0x2a, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+holeydma reversed scattered(16,32) char chars3[512] = {
+ 0x55, 0x40, 0x15, 0x40, 0x55, 0x40, 0x15, 0x40, 0x55, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x14,
+ 0x50, 0x50, 0x50, 0x50, 0x55, 0x50, 0x15, 0x40, 0x00, 0x50, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x55, 0x40, 0x15, 0x40, 0x55, 0x40, 0x15, 0x40, 0x55, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x14,
+ 0x50, 0x50, 0x50, 0x50, 0x55, 0x50, 0x15, 0x40, 0x00, 0x50, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x5a, 0x70, 0x5a, 0xd0, 0x7a, 0xd0, 0x7a, 0x50, 0xa7, 0xa0, 0xd0, 0x70, 0x50, 0xd0, 0x70, 0x1c,
+ 0x70, 0x50, 0xd0, 0x70, 0xaa, 0x70, 0x1e, 0x80, 0x01, 0xac, 0x2b, 0x40, 0x07, 0x00, 0x0c, 0x00,
+ 0x70, 0xd0, 0xd0, 0x70, 0x50, 0x50, 0x50, 0xd0, 0x05, 0x00, 0x50, 0x50, 0xd0, 0x70, 0x50, 0x14,
+ 0x50, 0xd0, 0x70, 0x50, 0x00, 0x50, 0x14, 0x00, 0x01, 0x04, 0x01, 0xc0, 0x05, 0x00, 0x04, 0x00,
+ 0x50, 0x70, 0xd0, 0x70, 0x50, 0xd0, 0x70, 0xa0, 0x07, 0x00, 0xd0, 0x70, 0xd0, 0x70, 0x50, 0x14,
+ 0xb5, 0xe0, 0x70, 0x50, 0x03, 0x60, 0x1c, 0x00, 0x0d, 0x08, 0x01, 0xc0, 0x37, 0x40, 0x14, 0x00,
+ 0xd0, 0x50, 0x70, 0x50, 0xd0, 0x70, 0xd0, 0x00, 0x0d, 0x00, 0x70, 0xd0, 0x70, 0x50, 0xd0, 0x34,
+ 0x1d, 0x40, 0x50, 0xd0, 0x01, 0xc0, 0x34, 0x00, 0x07, 0x00, 0x01, 0x40, 0x1d, 0xc0, 0x34, 0x00,
+ 0x77, 0xe0, 0x70, 0x70, 0x77, 0x60, 0xb7, 0x40, 0x07, 0x00, 0x70, 0x70, 0x70, 0x70, 0x73, 0x34,
+ 0x27, 0x80, 0xb7, 0x60, 0x07, 0x80, 0x34, 0x00, 0x37, 0x70, 0x03, 0x40, 0x77, 0x70, 0x77, 0x74,
+ 0xdd, 0x40, 0x70, 0x70, 0x77, 0x40, 0x37, 0x40, 0x07, 0x00, 0x70, 0x70, 0x70, 0x70, 0x73, 0x34,
+ 0x07, 0x00, 0x37, 0x40, 0x07, 0x00, 0x34, 0x00, 0x37, 0x70, 0x03, 0x40, 0x77, 0x70, 0x77, 0x74,
+ 0xda, 0x80, 0x70, 0xf0, 0xf7, 0x80, 0x2a, 0x70, 0x07, 0x00, 0xd0, 0x70, 0x70, 0xf0, 0xf7, 0xdc,
+ 0x3f, 0x40, 0x27, 0x80, 0x1e, 0x00, 0x34, 0x00, 0x2d, 0xa0, 0x03, 0x40, 0xa7, 0xa0, 0x7d, 0xf4,
+ 0xf0, 0x00, 0xd0, 0x70, 0xdf, 0x00, 0x00, 0xd0, 0x0d, 0x00, 0x70, 0xf0, 0xd0, 0x70, 0xdf, 0x7c,
+ 0x37, 0xc0, 0x0d, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x07, 0x00, 0x01, 0xc0, 0x0f, 0x00, 0xf7, 0xdc,
+ 0xf0, 0x00, 0xbf, 0x60, 0xfb, 0xc0, 0xf0, 0xf0, 0x0f, 0x00, 0xf0, 0xf0, 0xbf, 0x60, 0xfe, 0xfc,
+ 0xfa, 0xf0, 0x0f, 0x00, 0xf8, 0x00, 0x3c, 0x00, 0x3e, 0x0c, 0x03, 0xc0, 0x0f, 0x00, 0xb6, 0xa8,
+ 0xd0, 0x00, 0x1f, 0xc0, 0xd3, 0x40, 0xf0, 0x70, 0x07, 0x00, 0xd0, 0x70, 0x3f, 0xc0, 0xdc, 0xdc,
+ 0x70, 0x70, 0x07, 0x00, 0xd0, 0x00, 0x1c, 0x00, 0x34, 0x0c, 0x03, 0x40, 0x0d, 0x00, 0x3c, 0x00,
+ 0xf0, 0x00, 0x2b, 0xf0, 0xf2, 0xf0, 0xbf, 0xe0, 0x0f, 0x00, 0xbf, 0xe0, 0x2f, 0x80, 0xf8, 0xbc,
+ 0xf0, 0xf0, 0x0f, 0x00, 0xff, 0xf0, 0x3f, 0xc0, 0xff, 0xf8, 0x3f, 0xc0, 0x0f, 0x00, 0x2c, 0x00,
+ 0xf0, 0x00, 0x03, 0xf0, 0xf0, 0xf0, 0x3f, 0xc0, 0x0f, 0x00, 0x3f, 0xc0, 0x0f, 0x00, 0xf0, 0x3c,
+ 0xf0, 0xf0, 0x0f, 0x00, 0xff, 0xf0, 0x3f, 0xc0, 0xff, 0xf0, 0x3f, 0xc0, 0x0f, 0x00, 0x0c, 0x00,
+ 0xa0, 0x00, 0x02, 0xa0, 0xa0, 0xa0, 0x2a, 0x80, 0x0a, 0x00, 0x2a, 0x80, 0x0a, 0x00, 0xa0, 0x28,
+ 0xa0, 0xa0, 0x0a, 0x00, 0xaa, 0xa0, 0x2a, 0x80, 0xaa, 0xa0, 0x2a, 0x80, 0x0a, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+holeydma reversed scattered(16,2) char bb_char1[32] = {
+ 0x01, 0x00, 0x01, 0x40, 0x0a, 0x94, 0x2a, 0x90, 0x3b, 0xa0, 0xc8, 0xe5, 0xc8, 0xe4, 0xc8, 0xd0,
+ 0xc8, 0xe5, 0xbb, 0x84, 0x0c, 0x20, 0x2a, 0x90, 0x0e, 0x50, 0x3f, 0x94, 0x3d, 0x68, 0x5d, 0x6a
+};
+reversed scattered(16,2) char chest[32] = {
+ 0x00, 0x00, 0x05, 0x50, 0x2b, 0xf4, 0x96, 0xfc, 0x69, 0xbd, 0xbe, 0x6a, 0x55, 0x55, 0xaa, 0xbf,
+ 0xd5, 0xd5, 0xd9, 0xb7, 0xef, 0x9d, 0xef, 0x9d, 0xef, 0x9d, 0xdd, 0x9d, 0xd5, 0xf7, 0xff, 0x95
+};
diff --git a/presets/atari7800/skeleton.cc7800 b/presets/atari7800/skeleton.cc7800
new file mode 100644
index 00000000..5468f3df
--- /dev/null
+++ b/presets/atari7800/skeleton.cc7800
@@ -0,0 +1,16 @@
+// example from https://github.com/steux/cc7800 - license: GPLv3
+
+#include "conio.h"
+
+char i;
+
+void main()
+{
+ clrscr();
+ for (i = 0; i != 8; i++) {
+ textcolor(i);
+ gotoxy(0, i);
+ cputs("Hello World!");
+ }
+ while(1);
+}
diff --git a/presets/atari7800/test_conio.c78 b/presets/atari7800/test_conio.c78
new file mode 100644
index 00000000..ffae0eda
--- /dev/null
+++ b/presets/atari7800/test_conio.c78
@@ -0,0 +1,69 @@
+// example from https://github.com/steux/cc7800 - license: GPLv3
+
+#include "conio.h"
+#include "assert.h"
+
+char i;
+
+reversed scattered(8,1) char special_char[8] = {
+ 0x66, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00
+};
+
+void main()
+{
+ clrscr();
+ // Draw a square
+ gotoxy(0, 0);
+ textcolor(7);
+ putch(CONIO_TL_CORNER);
+ for (i = 0; i != 20; i++) {
+ putch(CONIO_HBAR);
+ }
+ putch(CONIO_TR_CORNER);
+ for (i = 0; i != 8; i++) {
+ gotoxy(0, i + 1);
+ putch(CONIO_VBAR);
+ gotoxy(21, i + 1);
+ putch(CONIO_VBAR);
+ }
+ gotoxy(0, 9);
+ putch(CONIO_BL_CORNER);
+ for (i = 0; i != 20; i++) {
+ putch(CONIO_HBAR);
+ }
+ putch(CONIO_BR_CORNER);
+ // Write some text
+ for (i = 0; i != 8; i++) {
+ textcolor(i);
+ gotoxy(i + 1, i + 1);
+ cputs("Hello World!");
+ }
+ // Long text test
+ gotoxy(0, 10);
+ cputs("This is a long text that fits in a line.");
+
+ gotoxy(10, 11);
+ cputs("World!");
+ gotoxy(4, 11);
+ cputs("Hello");
+
+ gotoxy(10, 12);
+ cputs("World!");
+ gotoxy(4, 12);
+ textcolor(4);
+ cputs("Hello");
+
+ gotoxy(0, 13);
+ for (i = 0; i != 8; i++) {
+ textcolor(i);
+ putch('!');
+ }
+
+ gotoxy(0, 14);
+ for (i = 0; i != 8; i++) {
+ textcolor(7 - i);
+ putch(128); // Special character
+ }
+
+ while(1);
+}
diff --git a/src/common/baseplatform.ts b/src/common/baseplatform.ts
index b63bbb13..09e83d94 100644
--- a/src/common/baseplatform.ts
+++ b/src/common/baseplatform.ts
@@ -957,7 +957,7 @@ export abstract class BaseMachinePlatform extends BaseDebugPl
export abstract class Base6502MachinePlatform extends BaseMachinePlatform {
getOpcodeMetadata = getOpcodeMetadata_6502;
- getToolForFilename = getToolForFilename_6502;
+ getToolForFilename(fn) { return getToolForFilename_6502(fn); }
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
diff --git a/src/common/wasi/wasishim.ts b/src/common/wasi/wasishim.ts
index e94fad48..9a752442 100644
--- a/src/common/wasi/wasishim.ts
+++ b/src/common/wasi/wasishim.ts
@@ -9,6 +9,7 @@
const use_debug = true;
const debug = use_debug ? console.log : () => { };
+const warning = console.log;
export enum FDType {
UNKNOWN = 0,
@@ -202,6 +203,9 @@ export class WASIFileDescriptor {
getBytes() {
return this.data.subarray(0, this.size);
}
+ getBytesAsString() {
+ return new TextDecoder().decode(this.getBytes());
+ }
toString() {
return `FD(${this.fdindex} "${this.name}" 0x${this.type.toString(16)} 0x${this.rights.toString(16)} ${this.offset}/${this.size}/${this.data.byteLength})`;
}
@@ -218,13 +222,21 @@ class WASIStreamingFileDescriptor extends WASIFileDescriptor {
}
}
-export class WASIFilesystem {
+export interface WASIFilesystem {
+ getFile(name: string) : WASIFileDescriptor;
+}
+
+export class WASIMemoryFilesystem implements WASIFilesystem {
+ private parent: WASIFilesystem | null = null;
private files: Map = new Map();
private dirs: Map = new Map();
constructor() {
this.putDirectory("/");
}
+ setParent(parent: WASIFilesystem) {
+ this.parent = parent;
+ }
putDirectory(name: string, rights?: number) {
if (!rights) rights = FDRights.PATH_OPEN | FDRights.PATH_CREATE_DIRECTORY | FDRights.PATH_CREATE_FILE;
const dir = new WASIFileDescriptor(name, FDType.DIRECTORY, rights);
@@ -243,29 +255,62 @@ export class WASIFilesystem {
return file;
}
getFile(name: string) {
- return this.files.get(name);
+ let file = this.files.get(name);
+ if (!file) {
+ file = this.parent?.getFile(name);
+ }
+ return file;
}
}
export class WASIRunner {
- #compiled: WebAssembly.Module;
#instance; // TODO
#memarr8: Uint8Array;
#memarr32: Int32Array;
#args: Uint8Array[] = [];
+ #envvars: Uint8Array[] = [];
- stdin = new WASIStreamingFileDescriptor(0, '', FDType.CHARACTER_DEVICE, FDRights.FD_READ, process.stdin);
- stdout = new WASIStreamingFileDescriptor(1, '', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE, process.stdout);
- stderr = new WASIStreamingFileDescriptor(2, '', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE, process.stderr);
+ stdin : WASIFileDescriptor;
+ stdout : WASIFileDescriptor;
+ stderr : WASIFileDescriptor;
- fds: WASIFileDescriptor[] = [this.stdin, this.stdout, this.stderr];
+ fds: WASIFileDescriptor[] = [];
exited = false;
errno = -1;
- fs = new WASIFilesystem();
+ fs = new WASIMemoryFilesystem();
+ constructor() {
+ this.createStdioBrowser();
+ }
+ createStdioNode() {
+ this.stdin = new WASIStreamingFileDescriptor(0, '', FDType.CHARACTER_DEVICE, FDRights.FD_READ, process.stdin);
+ this.stdout = new WASIStreamingFileDescriptor(1, '', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE, process.stdout);
+ this.stderr = new WASIStreamingFileDescriptor(2, '', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE, process.stderr);
+ this.fds[0] = this.stdin;
+ this.fds[1] = this.stdout;
+ this.fds[2] = this.stderr;
+ }
+ createStdioBrowser() {
+ this.stdin = new WASIFileDescriptor('', FDType.CHARACTER_DEVICE, FDRights.FD_READ);
+ this.stdout = new WASIFileDescriptor('', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE);
+ this.stderr = new WASIFileDescriptor('', FDType.CHARACTER_DEVICE, FDRights.FD_WRITE);
+ this.stdin.fdindex = 0;
+ this.stdout.fdindex = 1;
+ this.stderr.fdindex = 2;
+ this.fds[0] = this.stdin;
+ this.fds[1] = this.stdout;
+ this.fds[2] = this.stderr;
+ }
+ initSync(wasmModule: WebAssembly.Module) {
+ this.#instance = new WebAssembly.Instance(wasmModule, this.getImportObject());
+ }
+ loadSync(wasmSource: Uint8Array) {
+ let wasmModule = new WebAssembly.Module(wasmSource);
+ this.initSync(wasmModule);
+ }
async loadAsync(wasmSource: Uint8Array) {
- this.#compiled = await WebAssembly.compile(wasmSource);
- this.#instance = await WebAssembly.instantiate(this.#compiled, this.getImportObject());
+ let wasmModule = await WebAssembly.compile(wasmSource);
+ this.#instance = await WebAssembly.instantiate(wasmModule, this.getImportObject());
}
setArgs(args: string[]) {
this.#args = args.map(arg => new TextEncoder().encode(arg + '\0'));
@@ -296,6 +341,8 @@ export class WASIRunner {
if (o_flags & FDOpenFlags.EXCL) return WASIErrors.INVAL; // already exists
if (o_flags & FDOpenFlags.TRUNC) { // truncate
file.truncate();
+ } else {
+ file.llseek(0, 0); // seek to start
}
}
file.fdindex = this.fds.length;
@@ -371,14 +418,11 @@ export class WASIRunner {
//let errno_ptr = this.#instance.exports.__errno_location();
//return this.peek32(errno_ptr);
}
- args_sizes_get(argcount_ptr: number, argv_buf_size_ptr: number) {
- debug("args_sizes_get", argcount_ptr, argv_buf_size_ptr);
- this.poke32(argcount_ptr, this.#args.length);
- this.poke32(argv_buf_size_ptr, this.#args.reduce((acc, arg) => acc + arg.length, 0));
- return 0;
+ poke_str_array_sizes(strs: Uint8Array[], count_ptr: number, buf_size_ptr: number) {
+ this.poke32(count_ptr, strs.length);
+ this.poke32(buf_size_ptr, strs.reduce((acc, arg) => acc + arg.length, 0));
}
- args_get(argv_ptr: number, argv_buf_ptr: number) {
- debug("args_get", argv_ptr, argv_buf_ptr);
+ poke_str_args(strs: Uint8Array[], argv_ptr: number, argv_buf_ptr: number) {
let argv = argv_ptr;
let argv_buf = argv_buf_ptr;
for (let arg of this.#args) {
@@ -389,10 +433,28 @@ export class WASIRunner {
argv_buf++;
}
}
+ }
+ args_sizes_get(argcount_ptr: number, argv_buf_size_ptr: number) {
+ debug("args_sizes_get", argcount_ptr, argv_buf_size_ptr);
+ this.poke_str_array_sizes(this.#args, argcount_ptr, argv_buf_size_ptr);
return 0;
}
- fd_write(fd, iovs, iovs_len) {
- debug("fd_write", fd, iovs, iovs_len);
+ args_get(argv_ptr: number, argv_buf_ptr: number) {
+ debug("args_get", argv_ptr, argv_buf_ptr);
+ this.poke_str_args(this.#args, argv_ptr, argv_buf_ptr);
+ return 0;
+ }
+ environ_sizes_get(environ_count_ptr: number, environ_buf_size_ptr: number) {
+ debug("environ_sizes_get", environ_count_ptr, environ_buf_size_ptr);
+ this.poke_str_array_sizes(this.#envvars, environ_count_ptr, environ_buf_size_ptr);
+ return 0;
+ }
+ environ_get(environ_ptr: number, environ_buf_ptr: number) {
+ debug("environ_get", environ_ptr, environ_buf_ptr);
+ this.poke_str_args(this.#envvars, environ_ptr, environ_buf_ptr);
+ return 0;
+ }
+ fd_write(fd, iovs, iovs_len, nwritten_ptr) {
const stream = this.fds[fd];
const iovecs = this.mem32().subarray(iovs >>> 2, (iovs + iovs_len * 8) >>> 2);
let total = 0;
@@ -403,7 +465,9 @@ export class WASIRunner {
total += len;
stream.write(chunk);
}
- return total;
+ this.poke32(nwritten_ptr, total);
+ debug("fd_write", fd, iovs, iovs_len, '->', total);
+ return 0;
}
fd_read(fd, iovs, iovs_len, nread_ptr) {
const stream = this.fds[fd];
@@ -500,32 +564,50 @@ export class WASIRunner {
}
return WASIErrors.SUCCESS;
}
+ path_filestat_get(dirfd: number, dirflags: number, path_ptr: number, path_len: number, filestat_ptr: number) {
+ const dir = this.fds[dirfd];
+ if (dir == null) return WASIErrors.BADF;
+ if (dir.type !== FDType.DIRECTORY) return WASIErrors.NOTDIR;
+ const filename = this.peekUTF8(path_ptr, path_len);
+ const path = dir.name + '/' + filename;
+ const fd = this.fs.getFile(path);
+ console.log("path_filestat_get", dir+"", path, filestat_ptr, '->', fd+"");
+ if (!fd) return WASIErrors.NOENT;
+ this.poke64(filestat_ptr, fd.fdindex); // dev
+ this.poke64(filestat_ptr + 8, 0); // ino
+ this.poke8(filestat_ptr + 16, fd.type); // filetype
+ this.poke64(filestat_ptr + 24, 1); // nlink
+ this.poke64(filestat_ptr + 32, fd.size); // size
+ this.poke64(filestat_ptr + 40, 0); // atim
+ this.poke64(filestat_ptr + 48, 0); // mtim
+ this.poke64(filestat_ptr + 56, 0); // ctim
+ }
getWASISnapshotPreview1() {
return {
args_sizes_get: this.args_sizes_get.bind(this),
args_get: this.args_get.bind(this),
+ environ_sizes_get: this.environ_sizes_get.bind(this),
+ environ_get: this.environ_get.bind(this),
proc_exit: this.proc_exit.bind(this),
path_open: this.path_open.bind(this),
fd_prestat_get: this.fd_prestat_get.bind(this),
fd_prestat_dir_name: this.fd_prestat_dir_name.bind(this),
fd_fdstat_get: this.fd_fdstat_get.bind(this),
- fd_fdstat_set_flags() { debug("fd_fdstat_set_flags"); return 0; },
fd_read: this.fd_read.bind(this),
fd_write: this.fd_write.bind(this),
fd_seek: this.fd_seek.bind(this),
fd_close: this.fd_close.bind(this),
- fd_readdir() { debug("fd_readdir"); return 0; },
- path_unlink_file() { debug("path_unlink_file"); return 0; },
- environ_sizes_get() { debug("environ_sizes_get"); return 0; },
- environ_get() { debug("environ_get"); return 0; },
- clock_time_get() { debug("clock_time_get"); return 0; },
- path_filestat_get() { debug("path_filestat_get"); return 0; },
+ path_filestat_get: this.path_filestat_get.bind(this),
random_get: this.random_get.bind(this),
+ fd_fdstat_set_flags() { warning("TODO: fd_fdstat_set_flags"); return WASIErrors.NOTSUP; },
+ fd_readdir() { warning("TODO: fd_readdir"); return WASIErrors.NOTSUP; },
+ path_unlink_file() { warning("TODO: path_unlink_file"); return WASIErrors.NOTSUP; },
+ clock_time_get() { warning("TODO: clock_time_get"); return WASIErrors.NOTSUP; },
}
}
getEnv() {
return {
- __syscall_unlinkat() { debug('unlink'); return 0; },
+ __syscall_unlinkat() { warning('TODO: unlink'); return 0; },
}
}
}
diff --git a/src/ide/ui.ts b/src/ide/ui.ts
index 81920514..b119acb9 100644
--- a/src/ide/ui.ts
+++ b/src/ide/ui.ts
@@ -127,6 +127,7 @@ const TOOL_TO_SOURCE_STYLE = {
'armips': 'vasm',
'ecs': 'ecs',
'remote:llvm-mos': 'text/x-csrc',
+ 'cc7800': 'text/x-csrc',
}
// TODO: move into tool class
diff --git a/src/platform/atari7800.ts b/src/platform/atari7800.ts
index 50c97548..11160c7a 100644
--- a/src/platform/atari7800.ts
+++ b/src/platform/atari7800.ts
@@ -1,13 +1,18 @@
import { Atari7800 } from "../machine/atari7800";
-import { Platform, Base6502MachinePlatform } from "../common/baseplatform";
+import { Platform, Base6502MachinePlatform, getToolForFilename_6502 } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
var Atari7800_PRESETS = [
- {id:'sprites.dasm', name:'Sprites (ASM)'},
- {id:'wsync.c', name:'WSYNC'},
+ {id:'sprites.dasm', name:'Sprites (ASM)', category:'Assembler'},
+
+ {id:'wsync.c', name:'WSYNC', category:'CC65'},
{id:'sprites.c', name:'Double Buffering'},
{id:'scroll.c', name:'Scrolling'},
+
+ {id:'test_conio.c78', name:'Conio Test', category:'cc7800'},
+ {id:'example_small_sprites.c78', name:'Small Sprites'},
+ {id:'example_vertical_scrolling.c78', name:'Vertical Scrolling'},
];
class Atari7800Platform extends Base6502MachinePlatform implements Platform {
@@ -33,6 +38,11 @@ class Atari7800Platform extends Base6502MachinePlatform implements Pl
tree['display_list'] = this.machine.getDebugDisplayLists();
return tree;
}
+ getToolForFilename(filename: string) {
+ if (filename.endsWith(".cc7800")) return "cc7800";
+ if (filename.endsWith(".c78")) return "cc7800";
+ return getToolForFilename_6502(filename);
+ }
}
///
diff --git a/src/worker/fs/cc7800-fs.zip b/src/worker/fs/cc7800-fs.zip
new file mode 100755
index 00000000..3323ee0f
Binary files /dev/null and b/src/worker/fs/cc7800-fs.zip differ
diff --git a/src/worker/tools/acme.ts b/src/worker/tools/acme.ts
index 65197301..90d63b12 100644
--- a/src/worker/tools/acme.ts
+++ b/src/worker/tools/acme.ts
@@ -53,7 +53,7 @@ export function assembleACME(step: BuildStep): BuildStepResult {
var binpath = step.prefix + ".bin";
var lstpath = step.prefix + ".lst";
var sympath = step.prefix + ".sym";
- if (staleFiles(step, [binpath, lstpath])) {
+ if (staleFiles(step, [binpath])) {
var binout, lstout, symout;
var ACME: EmscriptenModule = emglobal.acme({
instantiateWasm: moduleInstFn('acme'),
diff --git a/src/worker/tools/cc7800.ts b/src/worker/tools/cc7800.ts
new file mode 100644
index 00000000..363b2be1
--- /dev/null
+++ b/src/worker/tools/cc7800.ts
@@ -0,0 +1,89 @@
+import { WASIFilesystem, WASIMemoryFilesystem, WASIRunner } from "../../common/wasi/wasishim";
+import { BuildStep, BuildStepResult, gatherFiles, getWASMBinary, loadNative, loadWASMBinary, makeErrorMatcher, putWorkFile, staleFiles, store } from "../workermain";
+import JSZip from 'jszip';
+
+let cc7800_fs: WASIFilesystem | null = null;
+let wasiModule: WebAssembly.Module | null = null;
+
+function loadBlobSync(path: string) {
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = 'blob';
+ xhr.open("GET", path, false); // synchronous request
+ xhr.send(null);
+ return xhr.response;
+}
+
+async function loadWASIFilesystemZip(zippath: string) {
+ const jszip = new JSZip();
+ const path = '../../src/worker/fs/' + zippath;
+ const zipdata = loadBlobSync(path);
+ console.log(zippath, zipdata);
+ await jszip.loadAsync(zipdata);
+ let fs = new WASIMemoryFilesystem();
+ let promises = [];
+ jszip.forEach(async (relativePath, zipEntry) => {
+ if (zipEntry.dir) {
+ fs.putDirectory(relativePath);
+ } else {
+ let path = './' + relativePath;
+ let prom = zipEntry.async("uint8array").then((data) => {
+ fs.putFile(path, data);
+ });
+ promises.push(prom);
+ }
+ });
+ await Promise.all(promises);
+ return fs;
+}
+
+
+export async function compileCC7800(step: BuildStep): Promise {
+ const errors = [];
+ gatherFiles(step, { mainFilePath: "main.c" });
+ const destpath = "./a.out";
+ if (staleFiles(step, [destpath])) {
+ if (!cc7800_fs) {
+ cc7800_fs = await loadWASIFilesystemZip("cc7800-fs.zip");
+ }
+ if (!wasiModule) {
+ wasiModule = new WebAssembly.Module(loadWASMBinary("cc7800"));
+ }
+ const wasi = new WASIRunner();
+ wasi.initSync(wasiModule);
+ wasi.fs.setParent(cc7800_fs);
+ for (let file of step.files) {
+ wasi.fs.putFile("./" + file, store.getFileData(file));
+ }
+ wasi.addPreopenDirectory("headers");
+ wasi.addPreopenDirectory(".");
+ wasi.setArgs(["cc7800", "-v", "-g", "-S", "-I", "headers", step.path]);
+ try {
+ wasi.run();
+ } catch (e) {
+ errors.push(e);
+ }
+ // TODO
+ let stdout = wasi.fds[1].getBytesAsString();
+ let stderr = wasi.fds[2].getBytesAsString();
+ console.log('stdout', stdout);
+ console.log('stderr', stderr);
+ // Syntax error: Unknown identifier cputes on line 11 of test.c78
+ if (stderr.indexOf("Syntax error:") >= 0) {
+ const matcher = makeErrorMatcher(errors, /^Syntax error: (.+?) on line (\d+) of (.+)/, 2, 1, step.path, 3);
+ for (let line of stderr.split('\n')) {
+ matcher(line);
+ }
+ }
+ if (errors.length) {
+ return { errors };
+ }
+ const combinedasm = wasi.fs.getFile(destpath).getBytesAsString();
+ putWorkFile(destpath, combinedasm);
+ }
+ return {
+ nexttool: "dasm",
+ path: destpath,
+ args: [destpath],
+ files: [destpath]
+ };
+}
diff --git a/src/worker/tools/z80.ts b/src/worker/tools/z80.ts
index 39ccea37..0c5292d7 100644
--- a/src/worker/tools/z80.ts
+++ b/src/worker/tools/z80.ts
@@ -11,7 +11,7 @@ export function assembleZMAC(step: BuildStep): BuildStepResult {
gatherFiles(step, { mainFilePath: "main.asm" });
var lstpath = step.prefix + ".lst";
var binpath = step.prefix + ".cim";
- if (staleFiles(step, [binpath, lstpath])) {
+ if (staleFiles(step, [binpath])) {
/*
error1.asm(4) : 'l18d4' Undeclared
JP L18D4
diff --git a/src/worker/wasm/cc7800.wasm b/src/worker/wasm/cc7800.wasm
new file mode 100755
index 00000000..52f6d9db
Binary files /dev/null and b/src/worker/wasm/cc7800.wasm differ
diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts
index 9615e4eb..371807b2 100644
--- a/src/worker/workermain.ts
+++ b/src/worker/workermain.ts
@@ -50,7 +50,9 @@ export function getWASMMemory() {
}
return wasmMemory;
}
-
+export function getWASMBinary(module_id:string) {
+ return wasmBlob[module_id];
+}
function getWASMModule(module_id:string) {
var module = _WASM_module_cache[module_id];
if (!module) {
@@ -813,9 +815,8 @@ export function load(modulename:string, debug?:boolean) {
loaded[modulename] = 1;
}
}
-export function loadWASM(modulename:string, debug?:boolean) {
+export function loadWASMBinary(modulename:string) {
if (!loaded[modulename]) {
- importScripts(PWORKER+"wasm/" + modulename+(debug?"."+debug+".js":".js"));
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open("GET", PWORKER+"wasm/"+modulename+".wasm", false); // synchronous request
@@ -828,6 +829,13 @@ export function loadWASM(modulename:string, debug?:boolean) {
throw Error("Could not load WASM file " + modulename + ".wasm");
}
}
+ return wasmBlob[modulename];
+}
+export function loadWASM(modulename:string, debug?:boolean) {
+ if (!loaded[modulename]) {
+ importScripts(PWORKER+"wasm/" + modulename+(debug?"."+debug+".js":".js"));
+ loadWASMBinary(modulename);
+ }
}
export function loadNative(modulename:string) {
// detect WASM
@@ -1140,6 +1148,7 @@ import * as arm from './tools/arm'
import * as ecs from './tools/ecs'
import * as remote from './tools/remote'
import * as acme from './tools/acme'
+import * as cc7800 from './tools/cc7800'
var TOOLS = {
'dasm': dasm.assembleDASM,
@@ -1175,7 +1184,8 @@ var TOOLS = {
'armips': arm.assembleARMIPS,
'vasmarm': arm.assembleVASMARM,
'ecs': ecs.assembleECS,
- 'remote': remote.buildRemote
+ 'remote': remote.buildRemote,
+ 'cc7800': cc7800.compileCC7800,
}
var TOOL_PRELOADFS = {