--- /dev/null
+#!/usr/bin/env python3
+
+import numpy
+import sys
+import PIL.Image
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+lsb_first = False # True for IIe, False for II+
+show_hi_bit = False
+while len(sys.argv) >= 2:
+ if sys.argv[1] == '--lsb_first':
+ lsb_first = True
+ elif sys.argv[1] == '--show_hi_bit':
+ show_hi_bit = True
+ else:
+ break
+ del sys.argv[1]
+if len(sys.argv) < 3:
+ print(f'usage: {sys.argv[0]} [--lsb_first] [--show_hi_bit] cg_rom.bin cg_rom.png')
+cg_rom_bin = sys.argv[1]
+cg_rom_png = sys.argv[2]
+
+with open(cg_rom_bin, 'rb') as fin:
+ data = list(fin.read())
+
+n_cols = 16
+assert len(data) % (n_cols * 8) == 0
+n_rows = len(data) // (n_cols * 8)
+
+data = (
+ (
+ numpy.array(data, numpy.uint8)[:, numpy.newaxis] >>
+ (
+ (
+ numpy.arange(8, dtype = numpy.int32)
+ if lsb_first else
+ numpy.arange(7, -1, -1, dtype = numpy.int32)
+ )
+ if show_hi_bit else
+ (
+ numpy.arange(7, dtype = numpy.int32)
+ if lsb_first else
+ numpy.arange(6, -1, -1, dtype = numpy.int32)
+ )
+ )[numpy.newaxis, :]
+ ) & 1
+).astype(bool)
+
+image = numpy.concatenate(
+ [
+ numpy.concatenate(
+ [
+ data[(i * n_cols + j) * 8:(i * n_cols + j + 1) * 8, :]
+ for j in range(n_cols)
+ ],
+ 1
+ )
+ for i in range(n_rows)
+ ],
+ 0
+)
+
+image_pil = PIL.Image.new('P', (image.shape[1], image.shape[0]))
+image_pil.frombytes(image.tobytes())
+image_pil.putpalette([0, 0, 0, 0xff, 0xff, 0xff])
+image_pil.save(cg_rom_png)
#define APPLE_WIDTH 560
#define APPLE_HEIGHT 192
+#define APPLE_TEXT0 0x400
+#define APPLE_TEXT1 0x800
#define APPLE_HIRES0 0x2000
#define APPLE_HIRES1 0x4000
#define IO_KBD 0xc000
#define IO_KBDSTRB 0xc010
#define IO_SPKR 0xc030
-#define IO_TXTCLR 0xc050
-#define IO_TXTSET 0xc051
-#define IO_MIXCLR 0xc052
-#define IO_MIXSET 0xc053
-#define IO_LOWSCR 0xc054
-#define IO_HISCR 0xc055
-#define IO_HIRES 0xc057
#define IO_PB0 0xc061
#define IO_PB1 0xc062
#define IO_PADDL0 0xc064
0xffffffff,
};
+// can make this green or amber to be more realistic
+uint32_t mono_palette[2] = {0xff000000, 0xffffffff};
+
VrEmu6502 *cpu;
#define ROM_SIZE 0x800
uint8_t key_waiting;
uint8_t usleep_lo;
uint8_t dos_lo;
-int hires = APPLE_HIRES0;
int usleep_count, exit_flag;
+#define SOFT_SWITCH_TEXT 1
+#define SOFT_SWITCH_MIXED 2
+#define SOFT_SWITCH_PAGE 4
+#define SOFT_SWITCH_HIRES 8
+uint8_t soft_switches = SOFT_SWITCH_TEXT;
+
void rom_load(char *name, uint8_t *data, int size) {
int fd = open(name, O_RDONLY);
if (fd == -1) {
switch (addr) {
case IO_KBD:
return key_waiting;
- case IO_LOWSCR:
- hires = APPLE_HIRES0;
+ case IO_KBDSTRB:
+ key_waiting &= 0x7f;
+ break;
+ case 0xc050:
+ case 0xc052:
+ case 0xc054:
+ case 0xc056:
+ case 0xc058:
+ case 0xc05a:
+ case 0xc05c:
+ case 0xc05e:
+ soft_switches &= ~(1 << ((addr >> 1) & 7));
break;
- case IO_HISCR:
- hires = APPLE_HIRES1;
+ case 0xc051:
+ case 0xc053:
+ case 0xc055:
+ case 0xc057:
+ case 0xc059:
+ case 0xc05b:
+ case 0xc05d:
+ case 0xc05f:
+ soft_switches |= 1 << ((addr >> 1) & 7);
break;
case STDIN_DATA:
{
case IO_KBDSTRB:
key_waiting &= 0x7f;
break;
- case IO_LOWSCR:
- hires = APPLE_HIRES0;
+ case 0xc050:
+ case 0xc052:
+ case 0xc054:
+ case 0xc056:
+ case 0xc058:
+ case 0xc05a:
+ case 0xc05c:
+ case 0xc05e:
+ soft_switches &= ~(1 << ((addr >> 1) & 7));
break;
- case IO_HISCR:
- hires = APPLE_HIRES1;
+ case 0xc051:
+ case 0xc053:
+ case 0xc055:
+ case 0xc057:
+ case 0xc059:
+ case 0xc05b:
+ case 0xc05d:
+ case 0xc05f:
+ soft_switches |= 1 << ((addr >> 1) & 7);
break;
case STDOUT_DATA:
if (write(fd_out, &val, 1) == -1) {
rom_load(cg_rom_file, cg_rom, CG_ROM_SIZE);
rom_load(f8_rom_file, mem + 0xf800, ROM_SIZE);
- int load_address = 0;
+ int load_address = -1;
while (argn < argc) {
char *p = argv[argn++];
if (strcmp(p, "--") == 0)
load_address = obj_load(p);
}
+ // do this before creating the CPU
+ if (load_address != -1) {
+ mem[RESET_VECTOR] = (uint8_t)(load_address & 0xff);
+ mem[RESET_VECTOR + 1] = (uint8_t)(load_address >> 8);
+ }
+
// open pty and child process if requested
if (argn < argc) {
int fd_master = posix_openpt(O_RDWR);
exit(EXIT_FAILURE);
}
- // Open the slave side ot the PTY
+ // open the slave side of the pty
char *slave_name = ptsname(fd_master);
int fd_slave = open(slave_name, O_RDWR);
if (fd_slave == -1) {
fd_out = fd_master;
}
- // do this before creating the CPU
- mem[RESET_VECTOR] = (uint8_t)(load_address & 0xff);
- mem[RESET_VECTOR + 1] = (uint8_t)(load_address >> 8);
-
if (isatty(fd_in)) {
if (tcgetattr(fd_in, &termios_attr) == -1) {
perror("tcgetattr()");
// draw
memset(frame, 0, WINDOW_HEIGHT * WINDOW_WIDTH * sizeof(uint32_t));
for (int i = 0; i < APPLE_HEIGHT; ++i) {
- int line =
- hires |
- (i >> 6) * 40 |
- ((i & 0x38) << 4) |
- ((i & 7) << 10);
+ int base = (i >> 6) * 40 | ((i & 0x38) << 4);
+ int row = i & 7;
uint32_t buf[PADDED_WORDS];
memset(buf, 0, PADDED_WORDS * sizeof(uint32_t));
- for (int j = 0; j < 40; ++j) {
- int data = mem[line + j];
- int hibit = data >> 7;
- for (int k = 0; k < 7; ++k) {
- if (data & 1) {
- int l = ((j * 7 + k) << 1) + hibit;
- buf[l >> 5] |= 1 << (l & 0x1f);
- ++l;
- buf[l >> 5] |= 1 << (l & 0x1f);
+
+ if (soft_switches & SOFT_SWITCH_HIRES) {
+ // hires
+ int line = (
+ soft_switches & SOFT_SWITCH_PAGE ? APPLE_HIRES1 : APPLE_HIRES0
+ ) | base | (row << 10);
+ for (int j = 0; j < 40; ++j) {
+ int data = mem[line + j];
+ int hibit = data >> 7;
+ for (int k = 0; k < 7; ++k) {
+ if (data & 1) {
+ int l = ((j * 7 + k) << 1) + hibit;
+ buf[l >> 5] |= 1 << (l & 0x1f);
+ ++l;
+ buf[l >> 5] |= 1 << (l & 0x1f);
+ }
+ data >>= 1;
+ }
+ }
+ }
+ else {
+ // text or gr (only text for now; MSB first)
+ int line = (
+ soft_switches & SOFT_SWITCH_PAGE ? APPLE_TEXT1 : APPLE_TEXT0
+ ) | base;
+ for (int j = 0; j < 40; ++j) {
+ int data = cg_rom[(mem[line + j] << 3) | row];
+ for (int k = 0; k < 7; ++k) {
+ if (data & 0x40) {
+ int l = (j * 7 + k) << 1;
+ buf[l >> 5] |= 1 << (l & 0x1f);
+ ++l;
+ buf[l >> 5] |= 1 << (l & 0x1f);
+ }
+ data <<= 1;
}
- data >>= 1;
}
}
- int k = 0, x = 0, y = i * WINDOW_Y_SCALE;
- for (int j = 0; j < PADDED_WIDTH; ++j) {
- int mask = 1 << (j & 3);
- k = (k & ~mask) | ((buf[j >> 5] >> (j & 0x1c)) & mask);
- uint32_t v = palette[k];
- for (int l = 0; l < WINDOW_X_SCALE; ++l) {
- for (int m = 0; m < WINDOW_Y_SCALE; ++m)
- frame[y + m][x] = v;
- ++x;
+
+ if (soft_switches & SOFT_SWITCH_TEXT) {
+ // text (no colour burst)
+ int x = 3 * WINDOW_X_SCALE / 2, y = i * WINDOW_Y_SCALE;
+ for (int j = 0; j < APPLE_WIDTH; ++j) {
+ uint32_t v = mono_palette[(buf[j >> 5] >> (j & 0x1f)) & 1];
+ for (int l = 0; l < WINDOW_X_SCALE; ++l) {
+ for (int m = 0; m < WINDOW_Y_SCALE; ++m)
+ frame[y + m][x] = v;
+ ++x;
+ }
+ }
+ }
+ else {
+ // hires or gr (colour burst)
+ int k = 0, x = 0, y = i * WINDOW_Y_SCALE;
+ for (int j = 0; j < PADDED_WIDTH; ++j) {
+ int mask = 1 << (j & 3);
+ k = (k & ~mask) | ((buf[j >> 5] >> (j & 0x1c)) & mask);
+ uint32_t v = palette[k];
+ for (int l = 0; l < WINDOW_X_SCALE; ++l) {
+ for (int m = 0; m < WINDOW_Y_SCALE; ++m)
+ frame[y + m][x] = v;
+ ++x;
+ }
}
}
}