From e7a04968e1d45c3fed3c9600c4868b47c1926ba1 Mon Sep 17 00:00:00 2001 From: Stefan Arentz Date: Sun, 4 Dec 2016 23:06:55 -1000 Subject: [PATCH] Fixes #48 Implement the Apple Language Card --- a2p.c | 183 +++---------------------------------------------------- alc.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ alc.h | 40 ++++++++++++ 3 files changed, 239 insertions(+), 175 deletions(-) create mode 100644 alc.c create mode 100644 alc.h diff --git a/a2p.c b/a2p.c index c3e83b2..e00bd92 100644 --- a/a2p.c +++ b/a2p.c @@ -27,6 +27,7 @@ #include "mem.h" #include "dsk.h" +#include "alc.h" #include "a2p.h" #define EWM_A2P_SS_KBD 0xc000 @@ -128,185 +129,17 @@ void a2p_screen_txt_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, u struct a2p_t *a2p = (struct a2p_t*) mem->obj; a2p->screen_txt_data[addr - mem->start] = b; a2p->screen_dirty = true; - //printf("[A2P] $%.4X = $%.2X\n", addr, b); } -// Apple Language Card -struct ewm_alc_t { - struct mem_t *ram1; // $D000 - $DFFF RAM Bank #1 - struct mem_t *ram2; // $D000 - $DFFF RAM Bank #2 - struct mem_t *ram3; // $E000 - $FFFF RAM Bank #3 - struct mem_t *rom; // $F800 - $FFFF Autostart ROM - struct mem_t *iom; // $C080 - $C08F - int wrtcount; -}; - -uint8_t alc_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { - struct ewm_alc_t *alc = (struct ewm_alc_t*) mem->obj; - - // Always enable the right banks - if (addr & 0b00001000) { - alc->ram1->enabled = true; - alc->ram2->enabled = false; - alc->ram3->enabled = true; - } else { - alc->ram1->enabled = false; - alc->ram2->enabled = true; - alc->ram3->enabled = true; - } - - switch (addr) { - // WRTCOUNT = 0, WRITE DISABLE, READ ENABLE - case 0xc080: - case 0xc084: - alc->wrtcount = 0; - alc->ram1->flags = MEM_FLAGS_READ; - alc->ram2->flags = MEM_FLAGS_READ; - alc->ram3->flags = MEM_FLAGS_READ; - break; - - // WRTCOUNT++, READ DISABLE, WRITE ENABLE IF WRTCOUNT >= 2 - case 0xc081: - case 0xc085: - alc->wrtcount = alc->wrtcount + 1; - alc->ram1->flags &= ~MEM_FLAGS_READ; - alc->ram2->flags &= ~MEM_FLAGS_READ; - alc->ram3->flags &= ~MEM_FLAGS_READ; - if (alc->wrtcount >= 2) { - alc->ram1->flags |= MEM_FLAGS_WRITE; - alc->ram2->flags |= MEM_FLAGS_WRITE; - alc->ram3->flags |= MEM_FLAGS_WRITE; - } - break; - - // WRTCOUNT = 0, WRITE DISABLE, READ DISABLE - case 0xc082: - case 0xc086: - alc->wrtcount = 0; - alc->ram1->flags &= ~MEM_FLAGS_WRITE; - alc->ram2->flags &= ~MEM_FLAGS_WRITE; - alc->ram3->flags &= ~MEM_FLAGS_WRITE; - alc->ram1->flags &= MEM_FLAGS_WRITE; - alc->ram2->flags &= MEM_FLAGS_WRITE; - alc->ram3->flags &= MEM_FLAGS_WRITE; - break; - - // WRTCOUNT++, READ ENABLE, WRITE ENABLE IF WRTCOUNT >= 2 - case 0xc083: - case 0xc08b: - alc->wrtcount = alc->wrtcount + 1; - alc->ram1->flags |= MEM_FLAGS_READ; - alc->ram2->flags |= MEM_FLAGS_READ; - alc->ram3->flags |= MEM_FLAGS_READ; - if (alc->wrtcount >= 2) { - alc->ram1->flags |= MEM_FLAGS_WRITE; - alc->ram2->flags |= MEM_FLAGS_WRITE; - alc->ram3->flags |= MEM_FLAGS_WRITE; - } - break; - - default: - fprintf(stderr, "[ALC] Unexpected read at $%.4X\n", addr); - break; - } - - return 0; +uint8_t a2p_screen_hgr_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { + struct a2p_t *a2p = (struct a2p_t*) mem->obj; + return a2p->screen_hgr_data[addr - mem->start]; } -static void alc_iom_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) { - struct ewm_alc_t *alc = (struct ewm_alc_t*) mem->obj; - - // Always enable the right banks - if (addr & 0b00001000) { - alc->ram1->enabled = true; - alc->ram2->enabled = false; - alc->ram3->enabled = true; - } else { - alc->ram1->enabled = false; - alc->ram2->enabled = true; - alc->ram3->enabled = true; - } - - switch (addr) { - // WRTCOUNT = 0, WRITE DISABLE, READ ENABLE - case 0xc080: - case 0xc084: - alc->wrtcount = 0; - alc->ram1->flags = MEM_FLAGS_READ; - alc->ram2->flags = MEM_FLAGS_READ; - alc->ram3->flags = MEM_FLAGS_READ; - break; - - // WRTCOUNT = 0, READ DISABLE - case 0xc081: - case 0xc085: - alc->wrtcount = 0; - alc->ram1->flags &= ~MEM_FLAGS_READ; - alc->ram2->flags &= ~MEM_FLAGS_READ; - alc->ram3->flags &= ~MEM_FLAGS_READ; - break; - - // WRTCOUNT = 0, WRITE DISABLE, READ DISABLE - case 0xc082: - case 0xc086: - alc->wrtcount = 0; - alc->ram1->flags &= ~MEM_FLAGS_WRITE; - alc->ram2->flags &= ~MEM_FLAGS_WRITE; - alc->ram3->flags &= ~MEM_FLAGS_WRITE; - alc->ram1->flags &= MEM_FLAGS_WRITE; - alc->ram2->flags &= MEM_FLAGS_WRITE; - alc->ram3->flags &= MEM_FLAGS_WRITE; - break; - - // WRTCOUNT = 0, READ ENABLE - case 0xc083: - case 0xc08b: - alc->wrtcount = 0; - alc->ram1->flags |= MEM_FLAGS_READ; - alc->ram2->flags |= MEM_FLAGS_READ; - alc->ram3->flags |= MEM_FLAGS_READ; - break; - - default: - fprintf(stderr, "[ALC] Unexpected write at $%.4X\n", addr); - break; - } -} - -int ewm_alc_init(struct ewm_alc_t *alc, struct cpu_t *cpu) { - memset(alc, 0x00, sizeof(struct ewm_alc_t)); - - // Order is important. First added is last tried when looking up - // addresses. So we register the ROM first, which means we never - // have to disable it. - - alc->rom = cpu_add_rom_file(cpu, 0xf800, "roms/341-0020.bin"); - alc->ram3 = cpu_add_ram(cpu, 0xe000, 0xe000 + 8192 - 1); - alc->ram2 = cpu_add_ram(cpu, 0xd000, 0xd000 + 4096 - 1); - alc->ram1 = cpu_add_ram(cpu, 0xd000, 0xd000 + 4096 - 1); - alc->iom = cpu_add_iom(cpu, 0xc080, 0xc08f, alc, alc_iom_read, alc_iom_write); - - // TODO Is this correct? Is everyting disabled at boot? - - alc->ram1->enabled = false; - alc->ram2->enabled = false; - alc->ram3->enabled = false; - - //cpu_mem_disable(cpu, alc->ram1, MEM_ENABLED_READ | MEM_ENABLED_WRITE); - //cpu_mem_disable(cpu, alc->ram2, MEM_ENABLED_READ | MEM_ENABLED_WRITE); - //cpu_mem_disable(cpu, alc->ram3, MEM_ENABLED_READ | MEM_ENABLED_WRITE); - //cpu_mem_disable(cpu, alc->rom, MEM_ENABLED_READ | MEM_ENABLED_WRITE); - - return 0; -} - -struct ewm_alc_t *ewm_alc_create(struct cpu_t *cpu) { - struct ewm_alc_t *alc = malloc(sizeof(struct ewm_alc_t)); - if (ewm_alc_init(alc, cpu) != 0) { - free(alc); - alc = NULL; - } - return alc; +void a2p_screen_hgr_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->screen_hgr_data[addr - mem->start] = b; + a2p->screen_dirty = true; } void a2p_init(struct a2p_t *a2p, struct cpu_t *cpu) { diff --git a/alc.c b/alc.c new file mode 100644 index 0000000..875c79c --- /dev/null +++ b/alc.c @@ -0,0 +1,191 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "alc.h" + +uint8_t alc_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { + struct ewm_alc_t *alc = (struct ewm_alc_t*) mem->obj; + + // Always enable the right banks + if (addr & 0b00001000) { + alc->ram1->enabled = true; + alc->ram2->enabled = false; + alc->ram3->enabled = true; + } else { + alc->ram1->enabled = false; + alc->ram2->enabled = true; + alc->ram3->enabled = true; + } + + switch (addr) { + // WRTCOUNT = 0, WRITE DISABLE, READ ENABLE + case 0xc080: + case 0xc084: + alc->wrtcount = 0; + alc->ram1->flags = MEM_FLAGS_READ; + alc->ram2->flags = MEM_FLAGS_READ; + alc->ram3->flags = MEM_FLAGS_READ; + break; + + // WRTCOUNT++, READ DISABLE, WRITE ENABLE IF WRTCOUNT >= 2 + case 0xc081: + case 0xc085: + alc->wrtcount = alc->wrtcount + 1; + alc->ram1->flags &= ~MEM_FLAGS_READ; + alc->ram2->flags &= ~MEM_FLAGS_READ; + alc->ram3->flags &= ~MEM_FLAGS_READ; + if (alc->wrtcount >= 2) { + alc->ram1->flags |= MEM_FLAGS_WRITE; + alc->ram2->flags |= MEM_FLAGS_WRITE; + alc->ram3->flags |= MEM_FLAGS_WRITE; + } + break; + + // WRTCOUNT = 0, WRITE DISABLE, READ DISABLE + case 0xc082: + case 0xc086: + alc->wrtcount = 0; + alc->ram1->flags &= ~MEM_FLAGS_WRITE; + alc->ram2->flags &= ~MEM_FLAGS_WRITE; + alc->ram3->flags &= ~MEM_FLAGS_WRITE; + alc->ram1->flags &= MEM_FLAGS_WRITE; + alc->ram2->flags &= MEM_FLAGS_WRITE; + alc->ram3->flags &= MEM_FLAGS_WRITE; + break; + + // WRTCOUNT++, READ ENABLE, WRITE ENABLE IF WRTCOUNT >= 2 + case 0xc083: + case 0xc08b: + alc->wrtcount = alc->wrtcount + 1; + alc->ram1->flags |= MEM_FLAGS_READ; + alc->ram2->flags |= MEM_FLAGS_READ; + alc->ram3->flags |= MEM_FLAGS_READ; + if (alc->wrtcount >= 2) { + alc->ram1->flags |= MEM_FLAGS_WRITE; + alc->ram2->flags |= MEM_FLAGS_WRITE; + alc->ram3->flags |= MEM_FLAGS_WRITE; + } + break; + + default: + fprintf(stderr, "[ALC] Unexpected read at $%.4X\n", addr); + break; + } + + return 0; +} + +static void alc_iom_write(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr, uint8_t b) { + struct ewm_alc_t *alc = (struct ewm_alc_t*) mem->obj; + + // Always enable the right banks + if (addr & 0b00001000) { + alc->ram1->enabled = true; + alc->ram2->enabled = false; + alc->ram3->enabled = true; + } else { + alc->ram1->enabled = false; + alc->ram2->enabled = true; + alc->ram3->enabled = true; + } + + switch (addr) { + // WRTCOUNT = 0, WRITE DISABLE, READ ENABLE + case 0xc080: + case 0xc084: + alc->wrtcount = 0; + alc->ram1->flags = MEM_FLAGS_READ; + alc->ram2->flags = MEM_FLAGS_READ; + alc->ram3->flags = MEM_FLAGS_READ; + break; + + // WRTCOUNT = 0, READ DISABLE + case 0xc081: + case 0xc085: + alc->wrtcount = 0; + alc->ram1->flags &= ~MEM_FLAGS_READ; + alc->ram2->flags &= ~MEM_FLAGS_READ; + alc->ram3->flags &= ~MEM_FLAGS_READ; + break; + + // WRTCOUNT = 0, WRITE DISABLE, READ DISABLE + case 0xc082: + case 0xc086: + alc->wrtcount = 0; + alc->ram1->flags &= ~MEM_FLAGS_WRITE; + alc->ram2->flags &= ~MEM_FLAGS_WRITE; + alc->ram3->flags &= ~MEM_FLAGS_WRITE; + alc->ram1->flags &= MEM_FLAGS_WRITE; + alc->ram2->flags &= MEM_FLAGS_WRITE; + alc->ram3->flags &= MEM_FLAGS_WRITE; + break; + + // WRTCOUNT = 0, READ ENABLE + case 0xc083: + case 0xc08b: + alc->wrtcount = 0; + alc->ram1->flags |= MEM_FLAGS_READ; + alc->ram2->flags |= MEM_FLAGS_READ; + alc->ram3->flags |= MEM_FLAGS_READ; + break; + + default: + fprintf(stderr, "[ALC] Unexpected write at $%.4X\n", addr); + break; + } +} + +int ewm_alc_init(struct ewm_alc_t *alc, struct cpu_t *cpu) { + memset(alc, 0x00, sizeof(struct ewm_alc_t)); + + // Order is important. First added is last tried when looking up + // addresses. So we register the ROM first, which means we never + // have to disable it. + + alc->rom = cpu_add_rom_file(cpu, 0xf800, "roms/341-0020.bin"); + alc->iom = cpu_add_iom(cpu, 0xc080, 0xc08f, alc, alc_iom_read, alc_iom_write); + alc->ram1 = cpu_add_ram(cpu, 0xd000, 0xd000 + 4096 - 1); + alc->ram2 = cpu_add_ram(cpu, 0xd000, 0xd000 + 4096 - 1); + alc->ram3 = cpu_add_ram(cpu, 0xe000, 0xe000 + 8192 - 1); + + alc->ram1->enabled = false; + alc->ram2->enabled = false; + alc->ram3->enabled = false; + + return 0; +} + +struct ewm_alc_t *ewm_alc_create(struct cpu_t *cpu) { + struct ewm_alc_t *alc = malloc(sizeof(struct ewm_alc_t)); + if (ewm_alc_init(alc, cpu) != 0) { + free(alc); + alc = NULL; + } + return alc; +} diff --git a/alc.h b/alc.h new file mode 100644 index 0000000..27b36bf --- /dev/null +++ b/alc.h @@ -0,0 +1,40 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef EWM_ALC_H +#define EWM_ALC_H + +struct mem_t; +struct cpu_t; + +struct ewm_alc_t { + struct mem_t *ram1; // $D000 - $DFFF RAM Bank #1 + struct mem_t *ram2; // $D000 - $DFFF RAM Bank #2 + struct mem_t *ram3; // $E000 - $FFFF RAM Bank #3 + struct mem_t *rom; // $F800 - $FFFF Autostart ROM + struct mem_t *iom; // $C080 - $C08F + int wrtcount; +}; + +struct ewm_alc_t *ewm_alc_create(struct cpu_t *cpu); + +#endif // EWM_ALC_H