From f829f6893d94ed52044bf007bc447526c9d5e653 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Fri, 27 Nov 2020 20:04:18 +0100 Subject: emulator uses a bus now in the cpu, ROM, RAM and VIA (7-seg) are devices connected to the bus --- emu/6502.c | 12 ++++----- emu/6502.h | 6 +++-- emu/7seg.c | 27 +++++++++++++++++--- emu/7seg.h | 18 +++++++++---- emu/CMakeLists.txt | 4 ++- emu/bus.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ emu/bus.h | 28 ++++++++++++++++++++ emu/device.c | 44 ++++++++++++++++++++++++++++++++ emu/device.h | 24 +++++++++++++++++ emu/emu.c | 26 +++++++++++++------ emu/emul.c | 4 +-- emu/emul.h | 20 +++++++++++---- emu/memory.c | 75 +++++++++++++++++++++++++++++++----------------------- emu/memory.h | 29 +++++++++++---------- 14 files changed, 314 insertions(+), 78 deletions(-) create mode 100644 emu/bus.c create mode 100644 emu/bus.h create mode 100644 emu/device.c create mode 100644 emu/device.h (limited to 'emu') diff --git a/emu/6502.c b/emu/6502.c index ce1f0d3..dbdf5a1 100644 --- a/emu/6502.c +++ b/emu/6502.c @@ -8,9 +8,9 @@ static const uint16_t reset_vector = 0xFFFC; static const uint16_t ZP_base = 0x0; static const uint16_t SP_base = 0x100; -void cpu_6502_init( cpu_6502_t *cpu, struct memory_t *memory ) +void cpu_6502_init( cpu_6502_t *cpu, bus_t *bus ) { - cpu->memory = memory; + cpu->bus = bus; cpu->debug_flags = 0; } @@ -62,18 +62,18 @@ void cpu_6502_reset( cpu_6502_t *cpu ) uint8_t cpu_6502_read_byte( cpu_6502_t *cpu, uint16_t addr ) { - return cpu->memory->read( cpu->memory, addr ); + return cpu->bus->base.vtable->read( cpu->bus, addr ); } void cpu_6502_write_byte( cpu_6502_t *cpu, uint16_t addr, uint8_t data ) { - cpu->memory->write( cpu->memory, addr, data ); + cpu->bus->base.vtable->write( cpu->bus, addr, data ); } void cpu_6502_write_word( cpu_6502_t *cpu, uint16_t addr, uint16_t data ) { - cpu->memory->write( cpu->memory, addr, ( data && 0x00FF ) ); - cpu->memory->write( cpu->memory, addr + 1, ( data && 0x00FF ) ); + cpu->bus->base.vtable->write( cpu->bus, addr, ( data && 0x00FF ) ); + cpu->bus->base.vtable->write( cpu->bus, addr + 1, ( data && 0x00FF ) ); } void cpu_6502_run( cpu_6502_t *cpu, int steps ) diff --git a/emu/6502.h b/emu/6502.h index 20574c3..22da89f 100644 --- a/emu/6502.h +++ b/emu/6502.h @@ -4,6 +4,8 @@ #include #include +#include "bus.h" + typedef struct { uint8_t A; @@ -13,7 +15,7 @@ typedef struct uint16_t PC; uint8_t PS; - struct memory_t *memory; + bus_t *bus; int debug_flags; @@ -57,7 +59,7 @@ enum { TXS_IMPL = 0x9A }; -void cpu_6502_init( cpu_6502_t *cpu, struct memory_t *memory ); +void cpu_6502_init( cpu_6502_t *cpu, bus_t *bus ); void cpu_6502_reset( cpu_6502_t *cpu ); uint8_t cpu_6502_read_byte( cpu_6502_t *cpu, uint16_t addr ); uint16_t cpu_6502_read_word( cpu_6502_t *cpu, uint16_t addr ); diff --git a/emu/7seg.c b/emu/7seg.c index 1aaf5f9..04a37f5 100644 --- a/emu/7seg.c +++ b/emu/7seg.c @@ -2,19 +2,31 @@ #include -void seg7_init( seg7_t *seg ) +static device_vtable_t const seg7_vtable = { + seg7_read, + seg7_write, + seg7_deinit +}; + +void seg7_init( seg7_t *seg, uint16_t addr ) { + device_init( &seg->base, "seg7" ); + seg->base.vtable = (device_vtable_t *)&seg7_vtable; + + seg->addr = addr; seg->debug = false; } -uint8_t seg7_read( seg7_t *seg, uint16_t addr ) +uint8_t seg7_read( void *obj, uint16_t addr ) { return 0; } -void seg7_write( seg7_t *seg, uint16_t addr, uint8_t data ) +void seg7_write( void *obj, uint16_t addr, uint8_t data ) { - switch( addr ) { + seg7_t *seg = (seg7_t *)obj; + + switch( addr - seg->addr ) { case DDRA: seg->ddr = data; break; @@ -41,3 +53,10 @@ void seg7_write( seg7_t *seg, uint16_t addr, uint8_t data ) // ignore writes to other addresses } } + +void seg7_deinit( void *obj ) +{ + seg7_t *seg = (seg7_t *)obj; + + device_deinit( &seg->base ); +} diff --git a/emu/7seg.h b/emu/7seg.h index 0cd585f..3953c70 100644 --- a/emu/7seg.h +++ b/emu/7seg.h @@ -1,6 +1,8 @@ #ifndef SEG7_H #define SEG7_H +#include "device.h" + #ifdef WITH_GUI #include #endif @@ -18,8 +20,8 @@ // +---- RCLK // +----- SRCLK enum { - PORTA = 0x6001, - DDRA = 0x6003, + PORTA = 0x01, + DDRA = 0x03, SER = 0x01, RCLK = 0x02, @@ -28,6 +30,10 @@ enum { typedef struct seg7_t { + device_t base; + + uint16_t addr; + uint8_t ddr; uint16_t shift; uint16_t latch; @@ -35,8 +41,10 @@ typedef struct seg7_t bool debug; } seg7_t; -void seg7_init( seg7_t *seg ); -uint8_t seg7_read( seg7_t *seg, uint16_t addr ); -void seg7_write( seg7_t *seg, uint16_t addr, uint8_t data ); +void seg7_init( seg7_t *seg, uint16_t addr ); + +uint8_t seg7_read( void *obj, uint16_t addr ); +void seg7_write( void *obj, uint16_t addr, uint8_t data ); +void seg7_deinit( void *obj ); #endif diff --git a/emu/CMakeLists.txt b/emu/CMakeLists.txt index e1fe6c9..04b1788 100644 --- a/emu/CMakeLists.txt +++ b/emu/CMakeLists.txt @@ -8,7 +8,7 @@ project(emu C) set( EMU_VERSION 0.0.1 ) -set(CMAKE_C_FLAGS "-g -O0 -std=c99 -Wall -DWITH_GUI") +set(CMAKE_C_FLAGS "-g -O0 -std=c99 -Wall -DWITH_GUI -D_POSIX_C_SOURCE=200809L") add_custom_target(distclean COMMAND make clean @@ -21,6 +21,8 @@ configure_file( "${PROJECT_SOURCE_DIR}/version.h.in" "${PROJECT_SOURCE_DIR}/version.h" @ONLY ) set(SRC + device.c + bus.c 6502.c memory.c 7seg.c diff --git a/emu/bus.c b/emu/bus.c new file mode 100644 index 0000000..5bbbcb1 --- /dev/null +++ b/emu/bus.c @@ -0,0 +1,75 @@ +#include "bus.h" + +#include +#include + +static device_vtable_t const bus_vtable = { + bus_read, + bus_write, + bus_deinit +}; + +void bus_init( bus_t *bus ) +{ + device_init( &bus->base, "bus" ); + ((device_t *)bus)->vtable = (device_vtable_t *)&bus_vtable; + + bus->nof_devices = 0; +} + +void bus_register( bus_t *bus, device_t *device, uint16_t from, uint16_t to ) +{ + if( bus->nof_devices < MAX_NOF_DEVICES ) { + registered_device_t *reg = &bus->devices[bus->nof_devices]; + reg->device = device; + reg->from = from; + reg->to = to; + bus->nof_devices++; + } else { + fprintf( stderr, "ERROR: too many devices on bus\n" ); + exit( EXIT_FAILURE ); + } +} + +uint8_t bus_read( void *obj, uint16_t addr ) +{ + bus_t *bus = (bus_t *)obj; + + for( int i = 0; i < bus->nof_devices; i++ ) { + registered_device_t *reg = &bus->devices[i]; + if( reg->from <= addr && addr <= reg->to ) { + return reg->device->vtable->read( reg->device, addr ); + } + } + + fprintf( stderr, "ERROR: illegal bus access reading from address %04X\n", addr ); + + return 0; +} + +void bus_write( void *obj, uint16_t addr, uint8_t data ) +{ + bus_t *bus = (bus_t *)obj; + + for( int i = 0; i < bus->nof_devices; i++ ) { + registered_device_t *reg = &bus->devices[i]; + if( reg->from <= addr && addr <= reg->to ) { + return reg->device->vtable->write( reg->device, addr, data ); + } + } + + fprintf( stderr, "ERROR: illegal bus access writing from address %04X\n", addr ); +} + +void bus_deinit( void *obj ) +{ + bus_t *bus = (bus_t *)obj; + + for( int i = bus->nof_devices - 1; i >= 0; i-- ) { + registered_device_t *reg = &bus->devices[i]; + reg->device->vtable->deinit( reg->device ); + } + bus->nof_devices = 0; + + device_deinit( &bus->base ); +} diff --git a/emu/bus.h b/emu/bus.h new file mode 100644 index 0000000..baa2fe2 --- /dev/null +++ b/emu/bus.h @@ -0,0 +1,28 @@ +#ifndef BUS_H +#define BUS_H + +#include "device.h" + +enum { + MAX_NOF_DEVICES = 5 +}; + +typedef struct registered_device_t { + device_t *device; + uint16_t from; + uint16_t to; +} registered_device_t; + +typedef struct bus_t { + device_t base; + int nof_devices; + registered_device_t devices[MAX_NOF_DEVICES]; +} bus_t; + +void bus_init( bus_t *bus ); +void bus_register( bus_t *bus, device_t *device, uint16_t from, uint16_t to ); +uint8_t bus_read( void *obj, uint16_t addr ); +void bus_write( void *obj, uint16_t addr, uint8_t data ); +void bus_deinit( void *obj ); + +#endif diff --git a/emu/device.c b/emu/device.c new file mode 100644 index 0000000..ecf3d2d --- /dev/null +++ b/emu/device.c @@ -0,0 +1,44 @@ +#include "device.h" + +#include +#include +#include + +static device_vtable_t const device_vtable = { + device_read, + device_write, + device_deinit +}; + +void device_init( device_t *device, const char *name ) +{ + device->name = strdup( name ); + + device->vtable = &device_vtable; +} + +uint8_t device_read( void *obj, uint16_t addr ) +{ + device_t *device = (device_t *)obj; + + fprintf( stderr, "WARN: read access on abstract device '%s' on address %04X\n", + device->name, addr ); + + return 0; +} + +void device_write( void *obj, uint16_t addr, uint8_t data ) +{ + device_t *device = (device_t *)obj; + + fprintf( stderr, "WARN: write access on abstract device '%s' on address %04X\n", + device->name, addr ); +} + +void device_deinit( void *obj ) +{ + device_t *device = (device_t *)obj; + + free( device->name ); +} + diff --git a/emu/device.h b/emu/device.h new file mode 100644 index 0000000..ce2abad --- /dev/null +++ b/emu/device.h @@ -0,0 +1,24 @@ +#ifndef DEVICE_H +#define DEVICE_H + +#include + +struct device_t; + +typedef struct device_vtable_t { + uint8_t (*read)( void *obj, uint16_t addr ); + void (*write)( void *obj, uint16_t addr, uint8_t data ); + void (*deinit)( void *obj ); +} device_vtable_t; + +typedef struct device_t { + device_vtable_t const *vtable; + char *name; +} device_t; + +void device_init( device_t *device, const char *name ); +uint8_t device_read( void *obj, uint16_t addr ); +void device_write( void *obj, uint16_t addr, uint8_t data ); +void device_deinit( void *obj ); + +#endif diff --git a/emu/emu.c b/emu/emu.c index 2723880..95bc5cb 100644 --- a/emu/emu.c +++ b/emu/emu.c @@ -23,9 +23,11 @@ int main( int argc, char *argv[] ) { struct gengetopt_args_info args_info; emul_t emul; - cpu_6502_t cpu; - memory_t memory; + bus_t bus; + memory_t rom; + memory_t ram; seg7_t seg7; + cpu_6502_t cpu; if( parse_options_and_arguments( argc, argv, &args_info ) != 0 ) { exit( EXIT_FAILURE ); @@ -36,12 +38,19 @@ int main( int argc, char *argv[] ) exit( EXIT_SUCCESS ); } - seg7_init( &seg7 ); - - memory_init( &memory, &seg7 ); - memory_load( &memory, ROM_START, ROM_SIZE, args_info.rom_arg ); + bus_init( &bus ); + + memory_init( &rom, MEMORY_ROM, ROM_START, ROM_SIZE ); + memory_load( &rom, args_info.rom_arg ); + bus_register( &bus, &rom.base, ROM_START, ROM_END ); + + memory_init( &ram, MEMORY_RAM, RAM_START, RAM_SIZE ); + bus_register( &bus, &ram.base, RAM_START, RAM_END ); + + seg7_init( &seg7, VIA_START ); + bus_register( &bus, &seg7.base, VIA_START, VIA_END ); - cpu_6502_init( &cpu, &memory ); + cpu_6502_init( &cpu, &bus ); if( args_info.debug_given ) { if( args_info.print_cpu_given ) { cpu.debug_flags |= DEBUG_STATUS; @@ -58,7 +67,7 @@ int main( int argc, char *argv[] ) } cpu_6502_reset( &cpu ); - emul_init( &emul, &cpu, &memory, args_info.width_arg, args_info.height_arg ); + emul_init( &emul, &cpu, &bus, args_info.width_arg, args_info.height_arg ); if( args_info.gui_given ) { if( args_info.debug_given ) { fprintf( stderr, "ERROR: don't run debug and GUI together! Uses too many resources!\n" ); @@ -70,6 +79,7 @@ int main( int argc, char *argv[] ) emul_run( &emul, args_info.steps_arg ); + bus_deinit( &bus ); emul_free( &emul ); exit( EXIT_SUCCESS ); } diff --git a/emu/emul.c b/emu/emul.c index 930f112..602ce33 100644 --- a/emu/emul.c +++ b/emu/emul.c @@ -3,10 +3,10 @@ #include #include -void emul_init( emul_t *emul, cpu_6502_t *cpu, memory_t *memory, int width, int height ) +void emul_init( emul_t *emul, cpu_6502_t *cpu, bus_t *bus, int width, int height ) { emul->cpu = cpu; - emul->memory = memory; + emul->bus = bus; emul->gui = false; emul->width = width; emul->height = height; diff --git a/emu/emul.h b/emu/emul.h index 6012309..6945143 100644 --- a/emu/emul.h +++ b/emu/emul.h @@ -2,7 +2,7 @@ #define EMUL_H #include "6502.h" -#include "memory.h" +#include "bus.h" #include @@ -11,15 +11,25 @@ #endif enum { - ROM_START = 0xF800, - ROM_SIZE = 2048, + ROM_START = 0xf800, + ROM_END = 0xffff, + ROM_SIZE = 2048, + + RAM_START = 0x0000, + RAM_END = 0x01ff, + RAM_SIZE = 512, + + VIA_START = 0x6000, + VIA_END = 0x600f, + CPU_FREQUENCY = 1000000, + DISPLAY_FPS = 25 }; typedef struct emul_t { cpu_6502_t *cpu; - memory_t *memory; + bus_t *bus; bool gui; int width; int height; @@ -31,7 +41,7 @@ typedef struct emul_t { #endif } emul_t; -void emul_init( emul_t *emul, cpu_6502_t *cpu, memory_t *memory, int width, int height ); +void emul_init( emul_t *emul, cpu_6502_t *cpu, bus_t *bus, int width, int height ); void emul_start( emul_t *emul ); void emul_run( emul_t *emul, int nof_steps ); void emul_free( emul_t *emul ); diff --git a/emu/memory.c b/emu/memory.c index 408e621..52332e3 100644 --- a/emu/memory.c +++ b/emu/memory.c @@ -1,52 +1,63 @@ #include "memory.h" #include +#include -void memory_init( memory_t *memory, seg7_t *seg ) -{ - memory->read = memory_read; - memory->write = memory_write; - memory->seg = seg; -} +static device_vtable_t const memory_vtable = { + memory_read, + memory_write, + memory_deinit +}; -uint8_t memory_read( memory_t *memory, uint16_t addr ) +void memory_init( memory_t *memory, memory_type_t type, uint16_t addr, uint16_t size ) { - if( addr <= 0x3FFF ) { - // RAM access - return memory->cell[addr]; - } else if( addr <= 0x8000 ) { - return seg7_read( memory->seg, addr ); - } else { - // ROM access - return memory->cell[addr]; - } -} + device_init( &memory->base, ( type == MEMORY_ROM ) ? "ROM" : "RAM" ); -void memory_write( memory_t *memory, uint16_t addr, uint8_t data ) -{ - if( addr <= 0x3FFF ) { - // RAM access - memory->cell[addr] = data; - } else if( addr <= 0x8000 ) { - seg7_write( memory->seg, addr, data ); - } else { - // ignore writes to ROM - } + memory->type = type; + memory->addr = addr; + memory->size = size; + memory->cell = malloc( memory->size ); + memory->base.vtable = (device_vtable_t *)&memory_vtable; } -void memory_load( memory_t *memory, uint16_t addr, uint16_t size, const char *filename ) +void memory_load( memory_t *memory, const char *filename ) { - if( addr >= 0x8000 ) { + if( memory->type == MEMORY_ROM ) { FILE *f = fopen( filename, "rb" ); if( f == NULL ) { fprintf( stderr, "ERROR: Unable to open ROM file '%s'\n", filename ); exit( EXIT_FAILURE ); } - fread( &memory->cell[addr], size, 1, f ); + fread( &memory->cell[0], memory->size, 1, f ); fclose( f ); fprintf( stderr, "INFO: Loaded firware from '%s' of size %d starting on address %04X\n", - filename, size, addr ); + filename, memory->size, memory->addr ); } else { - fprintf( stderr, "ERROR: Cannot load firmware into RAM at address %04X\n", addr ); + fprintf( stderr, "ERROR: Cannot load firmware into RAM at address %04X\n", memory->addr ); } } + +uint8_t memory_read( void *obj, uint16_t addr ) +{ + memory_t *memory = (memory_t *)obj; + + return memory->cell[addr-memory->addr]; +} + +void memory_write( void *obj, uint16_t addr, uint8_t data ) +{ + memory_t *memory = (memory_t *)obj; + + if( memory->type && MEMORY_ROM ) { + // ignore writes to ROM + } else { + memory->cell[addr-memory->addr] = data; + } +} + +void memory_deinit( void *obj ) +{ + memory_t *memory = (memory_t *)obj; + + device_deinit( &memory->base ); +} diff --git a/emu/memory.h b/emu/memory.h index b2abfee..a0d45b9 100644 --- a/emu/memory.h +++ b/emu/memory.h @@ -1,27 +1,30 @@ #ifndef MEMORY_H #define MEMORY_H -#include "7seg.h" +#include "device.h" #include -enum { - MEMORY_SIZE = 65535 -}; +typedef enum memory_type_t { + MEMORY_ROM = 1, + MEMORY_RAM = 2 +} memory_type_t; typedef struct memory_t { - uint8_t cell[MEMORY_SIZE]; + device_t base; - seg7_t *seg; - - uint8_t (*read)( struct memory_t *memory, uint16_t addr ); - void (*write)( struct memory_t *memory, uint16_t addr, uint8_t data ); + memory_type_t type; + uint16_t addr; + int size; + uint8_t *cell; } memory_t; -void memory_init( memory_t *memory, seg7_t *seg ); -uint8_t memory_read( memory_t *memory, uint16_t addr ); -void memory_write( memory_t *memory, uint16_t addr, uint8_t data ); -void memory_load( memory_t *memory, uint16_t addr, uint16_t size, const char *filename ); +void memory_init( memory_t *memory, memory_type_t type, uint16_t addr, uint16_t size ); +void memory_load( memory_t *memory, const char *filename ); + +uint8_t memory_read( void *obj, uint16_t addr ); +void memory_write( void *obj, uint16_t addr, uint8_t data ); +void memory_deinit( void *obj ); #endif -- cgit v1.2.3-54-g00ecf