mirror of
https://github.com/st3fan/ewm.git
synced 2025-04-19 00:41:15 +00:00
parent
1a26f30350
commit
8c540daa1b
115
a2p.c
115
a2p.c
@ -29,23 +29,27 @@
|
||||
#include "dsk.h"
|
||||
#include "a2p.h"
|
||||
|
||||
#define EWM_A2P_SS_KBD 0xc000
|
||||
#define EWM_A2P_SS_KBDSTRB 0xc010
|
||||
#define EWM_A2P_SS_SPKR 0xc030
|
||||
#define EWM_A2P_SS_TXTCLR 0xc050
|
||||
#define EWM_A2P_SS_TXTSET 0xc051
|
||||
#define EWM_A2P_SS_LOSCR 0xc054
|
||||
#define EWM_A2P_SS_HISCR 0xc055
|
||||
#define EWM_A2P_SS_LORES 0xc056
|
||||
#define EWM_A2P_SS_HIRES 0xc057
|
||||
#define EWM_A2P_SS_SETAN0 0xc058
|
||||
#define EWM_A2P_SS_KBD 0xc000
|
||||
#define EWM_A2P_SS_KBDSTRB 0xc010
|
||||
#define EWM_A2P_SS_SPKR 0xc030
|
||||
|
||||
#define EWM_A2P_SS_SCREEN_MODE_GRAPHICS 0xc050
|
||||
#define EWM_A2P_SS_SCREEN_MODE_TEXT 0xc051
|
||||
#define EWM_A2P_SS_GRAPHICS_STYLE_FULL 0xc052
|
||||
#define EWM_A2P_SS_GRAPHICS_STYLE_MIXED 0xc053
|
||||
#define EWM_A2P_SS_SCREEN_PAGE1 0xc054
|
||||
#define EWM_A2P_SS_SCREEN_PAGE2 0xc055
|
||||
#define EWM_A2P_SS_GRAPHICS_MODE_LGR 0xc056
|
||||
#define EWM_A2P_SS_GRAPHICS_MODE_HGR 0xc057
|
||||
|
||||
#define EWM_A2P_SS_SETAN0 0xc058
|
||||
#define EWM_A2P_SS_CLRAN0 0xc059
|
||||
#define EWM_A2P_SS_SETAN1 0xc05a
|
||||
#define EWM_A2P_SS_SETAN1 0xc05a
|
||||
#define EWM_A2P_SS_CLRAN1 0xc05b
|
||||
#define EWM_A2P_SS_SETAN2 0xc05c
|
||||
#define EWM_A2P_SS_CLRAN2 0xc05d
|
||||
#define EWM_A2P_SS_CLRAN2 0xc05d
|
||||
#define EWM_A2P_SS_SETAN3 0xc05e
|
||||
#define EWM_A2P_SS_CLRAN3 0xc05f
|
||||
#define EWM_A2P_SS_CLRAN3 0xc05f
|
||||
|
||||
uint8_t a2p_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
|
||||
struct a2p_t *a2p = (struct a2p_t*) mem->obj;
|
||||
@ -56,16 +60,48 @@ uint8_t a2p_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
|
||||
a2p->key &= 0x7f;
|
||||
return 0x00;
|
||||
|
||||
case EWM_A2P_SS_LOSCR:
|
||||
a2p->current_screen = 0;
|
||||
a2p->screen1_dirty = true;
|
||||
a2p->screen2_dirty = false;
|
||||
case EWM_A2P_SS_SCREEN_MODE_GRAPHICS:
|
||||
a2p->screen_mode = EWM_A2P_SCREEN_MODE_GRAPHICS;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
case EWM_A2P_SS_SCREEN_MODE_TEXT:
|
||||
a2p->screen_mode = EWM_A2P_SCREEN_MODE_TEXT;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
|
||||
case EWM_A2P_SS_HISCR:
|
||||
a2p->current_screen = 1;
|
||||
a2p->screen1_dirty = false;
|
||||
a2p->screen2_dirty = true;
|
||||
case EWM_A2P_SS_GRAPHICS_MODE_LGR:
|
||||
a2p->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_LGR;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
case EWM_A2P_SS_GRAPHICS_MODE_HGR:
|
||||
a2p->screen_graphics_mode = EWM_A2P_SCREEN_GRAPHICS_MODE_HGR;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
|
||||
case EWM_A2P_SS_GRAPHICS_STYLE_FULL:
|
||||
a2p->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
case EWM_A2P_SS_GRAPHICS_STYLE_MIXED:
|
||||
a2p->screen_graphics_style = EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
|
||||
case EWM_A2P_SS_SCREEN_PAGE1:
|
||||
a2p->screen_page = EWM_A2P_SCREEN_PAGE1;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
case EWM_A2P_SS_SCREEN_PAGE2:
|
||||
a2p->screen_page = EWM_A2P_SCREEN_PAGE2;
|
||||
a2p->screen_dirty = true;
|
||||
break;
|
||||
|
||||
case EWM_A2P_SS_SPKR:
|
||||
// TODO Implement speaker support
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("[A2P] Unexpected read at $%.4X\n", addr);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -77,33 +113,26 @@ void a2p_iom_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t
|
||||
case EWM_A2P_SS_KBDSTRB:
|
||||
a2p->key &= 0x7f;
|
||||
break;
|
||||
default:
|
||||
printf("[A2P] Unexpected write at $%.4X\n", addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t a2p_screen1_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
|
||||
uint8_t a2p_screen_txt_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
|
||||
struct a2p_t *a2p = (struct a2p_t*) mem->obj;
|
||||
return a2p->screen1_data[addr - mem->start];
|
||||
return a2p->screen_txt_data[addr - mem->start];
|
||||
}
|
||||
|
||||
void a2p_screen1_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) {
|
||||
void a2p_screen_txt_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) {
|
||||
struct a2p_t *a2p = (struct a2p_t*) mem->obj;
|
||||
a2p->screen1_data[addr - mem->start] = b;
|
||||
a2p->screen1_dirty = true;
|
||||
}
|
||||
|
||||
uint8_t a2p_screen2_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) {
|
||||
struct a2p_t *a2p = (struct a2p_t*) mem->obj;
|
||||
return a2p->screen2_data[addr - mem->start];
|
||||
}
|
||||
|
||||
void a2p_screen2_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) {
|
||||
struct a2p_t *a2p = (struct a2p_t*) mem->obj;
|
||||
a2p->screen2_data[addr - mem->start] = b;
|
||||
a2p->screen2_dirty = true;
|
||||
a2p->screen_txt_data[addr - mem->start] = b;
|
||||
a2p->screen_dirty = true;
|
||||
//printf("[A2P] $%.4X = $%.2X\n", addr, b);
|
||||
}
|
||||
|
||||
void a2p_init(struct a2p_t *a2p, struct cpu_t *cpu) {
|
||||
memset(a2p, sizeof(struct a2p_t), 0x00);
|
||||
memset(a2p, 0x00, sizeof(struct a2p_t));
|
||||
|
||||
a2p->ram = cpu_add_ram(cpu, 0x0000, 48 * 1024);
|
||||
a2p->rom = cpu_add_rom_file(cpu, 0xd000, "roms/a2p.rom");
|
||||
@ -111,11 +140,13 @@ void a2p_init(struct a2p_t *a2p, struct cpu_t *cpu) {
|
||||
|
||||
a2p->dsk = ewm_dsk_create(cpu);
|
||||
|
||||
a2p->screen1_data = malloc(1 * 1024);
|
||||
a2p->screen1 = cpu_add_iom(cpu, 0x0400, 0x07ff, a2p, a2p_screen1_read, a2p_screen1_write);
|
||||
// TODO Introduce ewm_scr_t that captures everything related to the apple 2 screen so that it can be re-used.
|
||||
|
||||
a2p->screen2_data = malloc(1 * 1024);
|
||||
a2p->screen2 = cpu_add_iom(cpu, 0x0800, 0x0bff, a2p, a2p_screen2_read, a2p_screen2_write);
|
||||
a2p->screen_txt_data = malloc(2 * 1024);
|
||||
a2p->screen_txt_iom = cpu_add_iom(cpu, 0x0400, 0x0bff, a2p, a2p_screen_txt_read, a2p_screen_txt_write);
|
||||
|
||||
//a2p->screen_hgr_data = malloc(16 * 1024);
|
||||
//a2p->screen_hgr_iom = cpu_add_iom(cpu, 0x2000, 0x7fff, a2p, a2p_screen_hgr_read, a2p_screen_hgr_write);
|
||||
}
|
||||
|
||||
int a2p_load_disk(struct a2p_t *a2p, int drive, char *path) {
|
||||
|
27
a2p.h
27
a2p.h
@ -28,21 +28,32 @@
|
||||
struct mem_t;
|
||||
struct ewm_dsk_t;
|
||||
|
||||
#define EWM_A2P_SCREEN_MODE_TEXT 0
|
||||
#define EWM_A2P_SCREEN_MODE_GRAPHICS 1
|
||||
|
||||
#define EWM_A2P_SCREEN_GRAPHICS_MODE_LGR 0
|
||||
#define EWM_A2P_SCREEN_GRAPHICS_MODE_HGR 1
|
||||
|
||||
#define EWM_A2P_SCREEN_GRAPHICS_STYLE_FULL 0
|
||||
#define EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED 1
|
||||
|
||||
#define EWM_A2P_SCREEN_PAGE1 0
|
||||
#define EWM_A2P_SCREEN_PAGE2 1
|
||||
|
||||
struct a2p_t {
|
||||
struct mem_t *ram;
|
||||
struct mem_t *rom;
|
||||
struct mem_t *iom;
|
||||
struct ewm_dsk_t *dsk;
|
||||
|
||||
struct mem_t *screen1;
|
||||
uint8_t *screen1_data;
|
||||
bool screen1_dirty;
|
||||
uint8_t *screen_txt_data;
|
||||
struct mem_t *screen_txt_iom;
|
||||
|
||||
struct mem_t *screen2;
|
||||
uint8_t *screen2_data;
|
||||
bool screen2_dirty;
|
||||
|
||||
int current_screen;
|
||||
int screen_mode;
|
||||
int screen_graphics_mode;
|
||||
int screen_graphics_style;
|
||||
int screen_page;
|
||||
int screen_dirty;
|
||||
|
||||
uint8_t key;
|
||||
};
|
||||
|
171
scr.c
171
scr.c
@ -44,7 +44,7 @@ void scr_init() {
|
||||
|
||||
//
|
||||
|
||||
window = SDL_CreateWindow("Test", 40, 60, 280*3, 192*3, SDL_WINDOW_SHOWN);
|
||||
window = SDL_CreateWindow("Test", 400, 60, 280*3, 192*3, SDL_WINDOW_SHOWN);
|
||||
if (window == NULL) {
|
||||
fprintf(stderr, "Failed create window: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
@ -75,6 +75,113 @@ static int screen2_offsets[24] = {
|
||||
0xa28, 0xaa8, 0xb28, 0xba8, 0x850, 0x8d0, 0x950, 0x9d0, 0xa50, 0xad0, 0xb50, 0xbd0
|
||||
};
|
||||
|
||||
static inline void _render_character(struct a2p_t *a2p, int row, int column, int *offsets) {
|
||||
uint8_t c = a2p->screen_txt_data[(offsets[row] + column) - 0x0400];
|
||||
if (chr->characters[c] != NULL) {
|
||||
SDL_Rect dst;
|
||||
dst.x = column * 21;
|
||||
dst.y = row * 24;
|
||||
dst.w = 21;
|
||||
dst.h = 24;
|
||||
SDL_RenderCopy(renderer, chr->characters[c], NULL, &dst);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_Color lores_colors[16] = {
|
||||
{ 0, 0, 0, 0 }, // 0 Black
|
||||
{ 255, 0, 255, 0 }, // 1 Magenta
|
||||
{ 0, 0, 204, 0 }, // 2 Dark Blue
|
||||
{ 128, 0, 128, 0 }, // 3 Purple
|
||||
{ 0, 100, 0, 0 }, // 4 Dark Green
|
||||
{ 128, 128, 128, 0 }, // 5 Grey 1
|
||||
{ 0, 0, 205, 0 }, // 6 Medium Blue
|
||||
{ 173, 216, 230, 0 }, // 7 Light Blue
|
||||
{ 165, 42, 42, 0 }, // 8 Brown
|
||||
{ 255, 165, 0, 0 }, // 9 Orange
|
||||
{ 211, 211, 211, 0 }, // 10 Grey 2
|
||||
{ 255, 192, 203, 0 }, // 11 Pink
|
||||
{ 144, 238, 144, 0 }, // 12 Light Green
|
||||
{ 255, 255, 0, 0 }, // 13 Yellow
|
||||
{ 127, 255, 212, 0 }, // 14 Aquamarine
|
||||
{ 255, 255, 255, 0 }, // 15 White
|
||||
};
|
||||
|
||||
static inline void _render_lores_block(struct a2p_t *a2p, int row, int column, int *offsets) {
|
||||
uint8_t block = a2p->screen_txt_data[(offsets[row] + column) - 0x0400];
|
||||
if (block != 0) {
|
||||
SDL_Rect dst;
|
||||
dst.x = column * 21;
|
||||
dst.y = row * 24;
|
||||
dst.w = 21;
|
||||
dst.h = 12;
|
||||
|
||||
uint c = block & 0x0f;
|
||||
if (c != 0) {
|
||||
SDL_SetRenderDrawColor(renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a);
|
||||
SDL_RenderFillRect(renderer, &dst);
|
||||
}
|
||||
|
||||
c = (block & 0xf0) >> 4;
|
||||
if (c != 0) {
|
||||
dst.y += 12;
|
||||
SDL_SetRenderDrawColor(renderer, lores_colors[c].r, lores_colors[c].g, lores_colors[c].b, lores_colors[c].a);
|
||||
SDL_RenderFillRect(renderer, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _render_txt_screen1(struct a2p_t *a2p) {
|
||||
for (int row = 0; row < 24; row++) {
|
||||
for (int column = 0; column < 40; column++) {
|
||||
_render_character(a2p, row, column, screen1_offsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _render_txt_screen2(struct a2p_t *a2p) {
|
||||
for (int row = 0; row < 24; row++) {
|
||||
for (int column = 0; column < 40; column++) {
|
||||
_render_character(a2p, row, column, screen2_offsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _render_lgr_screen1(struct a2p_t *a2p, bool mixed) {
|
||||
// Render graphics
|
||||
int rows = mixed ? 20 : 24;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int column = 0; column < 40; column++) {
|
||||
_render_lores_block(a2p, row, column, screen1_offsets);
|
||||
}
|
||||
}
|
||||
// Render bottom 4 lines
|
||||
if (mixed) {
|
||||
for (int row = 20; row < 24; row++) {
|
||||
for (int column = 0; column < 40; column++) {
|
||||
_render_character(a2p, row, column, screen1_offsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _render_lgr_screen2(struct a2p_t *a2p, bool mixed) {
|
||||
// Render graphics
|
||||
int rows = mixed ? 20 : 24;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int column = 0; column < 40; column++) {
|
||||
_render_lores_block(a2p, row, column, screen2_offsets);
|
||||
}
|
||||
}
|
||||
// Render bottom 4 lines
|
||||
if (mixed) {
|
||||
for (int row = 20; row < 24; row++) {
|
||||
for (int column = 0; column < 40; column++) {
|
||||
_render_character(a2p, row, column, screen2_offsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scr_main(struct cpu_t *cpu, struct a2p_t *a2p) {
|
||||
bool quit = false;
|
||||
//bool running = true;
|
||||
@ -166,53 +273,43 @@ void scr_main(struct cpu_t *cpu, struct a2p_t *a2p) {
|
||||
|
||||
// Render
|
||||
|
||||
if (a2p->screen1_dirty || a2p->screen2_dirty) {
|
||||
if (a2p->screen_dirty) {
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
switch (a2p->current_screen) {
|
||||
case 0:
|
||||
if (a2p->screen1_dirty) {
|
||||
for (int row = 0; row < 24; row++) {
|
||||
uint16_t row_offset = screen1_offsets[row] - 0x0400;
|
||||
for (int column = 0; column < 40; column++) {
|
||||
uint8_t c = a2p->screen1_data[row_offset + column];
|
||||
if (chr->characters[c] != NULL) {
|
||||
SDL_Rect dst;
|
||||
dst.x = column * 21;
|
||||
dst.y = row * 24;
|
||||
dst.w = 21;
|
||||
dst.h = 24;
|
||||
SDL_RenderCopy(renderer, chr->characters[c], NULL, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (a2p->screen_mode) {
|
||||
case EWM_A2P_SCREEN_MODE_TEXT:
|
||||
switch (a2p->screen_page) {
|
||||
case EWM_A2P_SCREEN_PAGE1:
|
||||
_render_txt_screen1(a2p);
|
||||
break;
|
||||
case EWM_A2P_SCREEN_PAGE2:
|
||||
_render_txt_screen2(a2p);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (a2p->screen2_dirty) {
|
||||
for (int row = 0; row < 24; row++) {
|
||||
uint16_t row_offset = screen2_offsets[row] - 0x0800;
|
||||
for (int column = 0; column < 40; column++) {
|
||||
uint8_t c = a2p->screen2_data[row_offset + column];
|
||||
if (chr->characters[c] != NULL) {
|
||||
SDL_Rect dst;
|
||||
dst.x = column * 21;
|
||||
dst.y = row * 24;
|
||||
dst.w = 21;
|
||||
dst.h = 24;
|
||||
SDL_RenderCopy(renderer, chr->characters[c], NULL, &dst);
|
||||
}
|
||||
case EWM_A2P_SCREEN_MODE_GRAPHICS:
|
||||
switch (a2p->screen_graphics_mode) {
|
||||
case EWM_A2P_SCREEN_GRAPHICS_MODE_LGR:
|
||||
switch (a2p->screen_page) {
|
||||
case EWM_A2P_SCREEN_PAGE1:
|
||||
_render_lgr_screen1(a2p, a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED);
|
||||
break;
|
||||
case EWM_A2P_SCREEN_PAGE2:
|
||||
_render_lgr_screen2(a2p, a2p->screen_graphics_style == EWM_A2P_SCREEN_GRAPHICS_STYLE_MIXED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EWM_A2P_SCREEN_GRAPHICS_MODE_HGR:
|
||||
// TODO Implement
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
a2p->screen1_dirty = false;
|
||||
a2p->screen2_dirty = false;
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
a2p->screen_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user