diff --git a/include/apple2.lores.h b/include/apple2.lores.h new file mode 100644 index 0000000..ca070f7 --- /dev/null +++ b/include/apple2.lores.h @@ -0,0 +1,9 @@ +#ifndef _APPLE2_LORES_H_ +#define _APPLE2_LORES_H_ + +#include "apple2.h" + +extern void apple2_lores_draw(apple2 *, size_t); +extern vm_color apple2_lores_color(vm_8bit); + +#endif diff --git a/include/apple2.text.h b/include/apple2.text.h index 4bbd799..1a34782 100644 --- a/include/apple2.text.h +++ b/include/apple2.text.h @@ -8,6 +8,8 @@ extern char apple2_text_alternate(vm_8bit); extern char apple2_text_primary(vm_8bit); extern int apple2_text_area(vm_area *, vm_bitfont *, size_t); +extern int apple2_text_col(size_t); +extern int apple2_text_row(size_t); extern void apple2_text_draw(apple2 *, size_t); #endif diff --git a/include/vm_screen.h b/include/vm_screen.h index e804b9e..5d708b7 100644 --- a/include/vm_screen.h +++ b/include/vm_screen.h @@ -7,6 +7,20 @@ #include "vm_area.h" #include "vm_bits.h" +typedef struct { + /* + * Red, green, blue + */ + vm_8bit r, g, b; + + /* + * This is alpha, which would be the degree of transparency of the + * graphics. This is here only if needed--for example, the Apple II + * doesn't have any alpha channel. + */ + vm_8bit a; +} vm_color; + typedef struct { /* * This is the window in SDL that we're displaying. It's fine for a @@ -65,7 +79,7 @@ extern void vm_screen_finish(); extern void vm_screen_free(vm_screen *); extern void vm_screen_prepare(vm_screen *); extern void vm_screen_refresh(vm_screen *); -extern void vm_screen_set_color(vm_screen *, uint8_t, uint8_t, uint8_t, uint8_t); +extern void vm_screen_set_color(vm_screen *, vm_color); extern void vm_screen_set_logical_coords(vm_screen *, int, int); #endif diff --git a/sources.cmake b/sources.cmake index c239605..3edb7f9 100644 --- a/sources.cmake +++ b/sources.cmake @@ -7,6 +7,7 @@ set(erc_sources apple2.draw.c apple2.enc.c apple2.kb.c + apple2.lores.c apple2.mem.c apple2.pc.c apple2.reflect.c diff --git a/src/apple2.draw.c b/src/apple2.draw.c index 9603c39..8184231 100644 --- a/src/apple2.draw.c +++ b/src/apple2.draw.c @@ -7,33 +7,9 @@ */ #include "apple2.h" +#include "apple2.lores.h" #include "apple2.text.h" -/* - * These are the color codes for the lo-res colors that are available. - * Each pixel in lo-res indicates one color. These are colors I found - * somewhere online -- I'm not sure if they are exact matches, and are - * subject to change. - */ -static int lores_colors[][3] = { - { 0x00, 0x00, 0x00 }, // black - { 0xff, 0x28, 0x97 }, // magenta - { 0x60, 0x4d, 0xbc }, // dark blue - { 0xff, 0x44, 0xfd }, // purple - { 0x00, 0xa3, 0x60 }, // dark green - { 0x9c, 0x9c, 0x9c }, // gray - { 0x14, 0xcf, 0xfd }, // medium blue - { 0xd0, 0xc3, 0xff }, // light blue - { 0x60, 0x72, 0x03 }, // brown - { 0xff, 0x6a, 0x3c }, // orange - { 0x9c, 0x9c, 0x9c }, // gray - { 0xff, 0xa0, 0xd0 }, // pink - { 0x14, 0xf5, 0x3c }, // light green - { 0xd0, 0xdd, 0x81 }, // yellow - { 0x72, 0xff, 0xd0 }, // aquamarine - { 0xff, 0xff, 0xff }, // white -}; - /* * Draw a pixel on screen at the given address. * FIXME: we do not draw anything D: @@ -55,6 +31,7 @@ apple2_draw_pixel(apple2 *mach, vm_16bit addr) void apple2_draw_pixel_lores(apple2 *mach, vm_16bit addr) { +#if 0 vm_8bit color = vm_segment_get(mach->main, addr); vm_8bit top, bottom; vm_area loc; @@ -85,6 +62,7 @@ apple2_draw_pixel_lores(apple2 *mach, vm_16bit addr) colors = lores_colors[bottom]; vm_screen_set_color(mach->screen, colors[0], colors[1], colors[2], 255); vm_screen_draw_rect(mach->screen, &loc); +#endif } /* @@ -103,6 +81,21 @@ apple2_draw_40col(apple2 *mach) } } +/* + * Draw low-resolution graphics on the screen + */ +void +apple2_draw_lores(apple2 *mach) +{ + size_t addr; + + vm_screen_prepare(mach->screen); + + for (addr = 0x400; addr < 0x800; addr++) { + apple2_lores_draw(mach, addr); + } +} + /* * Find the right draw method for the machine, based on its display * mode, and use that to refresh the screen. @@ -112,5 +105,8 @@ apple2_draw(apple2 *mach) { if (mach->display_mode & DISPLAY_TEXT) { apple2_draw_40col(mach); + return; } + + apple2_draw_lores(mach); } diff --git a/src/apple2.grid.c b/src/apple2.grid.c new file mode 100644 index 0000000..cc55ebc --- /dev/null +++ b/src/apple2.grid.c @@ -0,0 +1,11 @@ +/* + * apple2.grid.c + * + * Each of the display modes in the Apple II work off of a grid, but the + * grids are generally interleaved, so there's no simple formula to + * follow. + * + * In here we define tables which map addresses to rows or columns + * within a grid, and some functions to pull that information from those + * tables. + */ diff --git a/src/apple2.lores.c b/src/apple2.lores.c new file mode 100644 index 0000000..fa0a456 --- /dev/null +++ b/src/apple2.lores.c @@ -0,0 +1,94 @@ +/* + * apple2.lores.c + * + * The Apple II has several modes of display, and one of those modes is + * low-resolution graphics. Graphics are shown on a 40x48 grid, where + * each cell in the grid consumes 4 rows or columns of pixels. + * + * It's possible in low-resolution graphics (and high-resolution, for + * that matter) to show text with graphics--that is to say, exactly the + * kind of text that would be seen in 40-column text mode. If text is + * shown (this is indicated through a "mixed" mode flag), then it will + * be rendered at the bottom of the screen, and the rows of pixels that + * would have been rendered in full graphical mode will be skipped. + */ + +#include "apple2.h" +#include "apple2.lores.h" +#include "apple2.text.h" + +/* + * These are the color codes for the lo-res colors that are available. + * Each pixel in lo-res indicates one color. These are colors I found + * somewhere online -- I'm not sure if they are exact matches, and are + * subject to change. + */ +static vm_color lores_colors[] = { + { 0x00, 0x00, 0x00, 0x00 }, // black + { 0xff, 0x28, 0x97, 0x00 }, // magenta + { 0x60, 0x4d, 0xbc, 0x00 }, // dark blue + { 0xff, 0x44, 0xfd, 0x00 }, // purple + { 0x00, 0xa3, 0x60, 0x00 }, // dark green + { 0x9c, 0x9c, 0x9c, 0x00 }, // gray + { 0x14, 0xcf, 0xfd, 0x00 }, // medium blue + { 0xd0, 0xc3, 0xff, 0x00 }, // light blue + { 0x60, 0x72, 0x03, 0x00 }, // brown + { 0xff, 0x6a, 0x3c, 0x00 }, // orange + { 0x9c, 0x9c, 0x9c, 0x00 }, // gray + { 0xff, 0xa0, 0xd0, 0x00 }, // pink + { 0x14, 0xf5, 0x3c, 0x00 }, // light green + { 0xd0, 0xdd, 0x81, 0x00 }, // yellow + { 0x72, 0xff, 0xd0, 0x00 }, // aquamarine + { 0xff, 0xff, 0xff, 0x00 }, // white +}; + + +/* + * Draw two cells on the low-resolution grid. Each byte address holds + * two cells-worth of data. We may delegate the render to the text + * render code if we're in mixed mode. + */ +void +apple2_lores_draw(apple2 *mach, size_t addr) +{ + int row = apple2_text_row(addr), + col = apple2_text_col(addr); + + // In low-resolution mode, the row number is analagous to the text + // row number, like so: + row *= 2; + + // In mixed display mode, we have to render text in the lower rows + // of the screen + if ((mach->display_mode & DISPLAY_MIXED) && row >= 40) { + apple2_text_draw(mach, addr); + return; + } + + vm_8bit byte = mos6502_get(mach->cpu, addr); + vm_8bit topcell = byte & 0xF, + botcell = byte >> 4; + + vm_area dest; + + // Cells are more like rectangles than squares + dest.width = 7; + dest.height = 4; + dest.xoff = 7 * col; + dest.yoff = 4 * row; + + // Draw the top cell + vm_screen_set_color(mach->screen, apple2_lores_color(topcell)); + vm_screen_draw_rect(mach->screen, &dest); + + // And draw the bottom cell + dest.yoff += 4; + vm_screen_set_color(mach->screen, apple2_lores_color(botcell)); + vm_screen_draw_rect(mach->screen, &dest); +} + +vm_color +apple2_lores_color(vm_8bit byte) +{ + return lores_colors[byte & 0xf]; +} diff --git a/src/apple2.text.c b/src/apple2.text.c index 80a34c5..43aa317 100644 --- a/src/apple2.text.c +++ b/src/apple2.text.c @@ -225,6 +225,24 @@ static char alternate_display[] = { 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', ' ', }; +/* + * Return the row where the given address will be displayed. + */ +int +apple2_text_row(size_t addr) +{ + return buffer_rows[addr]; +} + +/* + * Return the column where the given address will be displayed. + */ +int +apple2_text_col(size_t addr) +{ + return buffer_cols[addr]; +} + /* * Return the primary character set representation matching the given * character code. diff --git a/src/mos6502.dis.c b/src/mos6502.dis.c index 35258da..8c5bef7 100644 --- a/src/mos6502.dis.c +++ b/src/mos6502.dis.c @@ -258,6 +258,7 @@ mos6502_dis_opcode(mos6502 *cpu, FILE *stream, int address) int addr_mode; int inst_code; int expected; + char status[9]; memset(s_bytes, 0, sizeof(s_bytes)); memset(s_inst, 0, sizeof(s_inst)); @@ -326,8 +327,18 @@ mos6502_dis_opcode(mos6502 *cpu, FILE *stream, int address) snprintf(s_bytes, sizeof(s_bytes) - 1, "%02X", opcode); } - fprintf(stream, "%04X:%-9s%20s %s\n", - cpu->PC, s_bytes, s_inst, s_operand); + snprintf(status, sizeof(status), "%c%c_%c%c%c%c%c", + cpu->P & MOS_NEGATIVE ? 'N' : '_', + cpu->P & MOS_OVERFLOW ? 'V' : '_', + cpu->P & MOS_BREAK ? 'B' : '_', + cpu->P & MOS_DECIMAL ? 'D' : '_', + cpu->P & MOS_INTERRUPT ? 'I' : '_', + cpu->P & MOS_ZERO ? 'Z' : '_', + cpu->P & MOS_CARRY ? 'C' : '_'); + + fprintf(stream, "%04X:%-9s%20s %-20s; A:%02X X:%02X Y:%02X P:%02X<%s> S:%02X\n", + cpu->PC, s_bytes, s_inst, s_operand, + cpu->A, cpu->X, cpu->Y, cpu->P, status, cpu->S); } // The expected number of bytes here is for the operand, but we need diff --git a/src/vm_screen.c b/src/vm_screen.c index 07d4851..9751bb3 100644 --- a/src/vm_screen.c +++ b/src/vm_screen.c @@ -129,7 +129,10 @@ vm_screen_add_window(vm_screen *screen, int width, int height) // the set_logical_coords function with different values. vm_screen_set_logical_coords(screen, width, height); - vm_screen_set_color(screen, 0, 0, 0, 0); + vm_color clr; + memset(&clr, 0, sizeof(vm_color)); + + vm_screen_set_color(screen, clr); vm_screen_prepare(screen); return OK; @@ -210,14 +213,11 @@ vm_screen_refresh(vm_screen *screen) * Set the color of a screen screen to a given RGBA value. */ void -vm_screen_set_color(vm_screen *screen, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha) +vm_screen_set_color(vm_screen *scr, vm_color clr) { - if (screen->render) { - SDL_SetRenderDrawColor(screen->render, red, green, blue, alpha); + if (scr->render) { + SDL_SetRenderDrawColor(scr->render, clr.r, clr.g, clr.g, + SDL_ALPHA_OPAQUE); } }