From 3d77f3f5ad41e931117425f58c74f49c9503bf7b Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Thu, 26 Nov 2020 19:55:02 +0100 Subject: more work on emulator, mainly debug and 7seg stuff --- emu/6502.c | 20 ++++++++++++----- emu/6502.h | 11 +++++++++- emu/7seg.c | 43 +++++++++++++++++++++++++++++++++++++ emu/7seg.h | 38 ++++++++++++++++++++++++++++---- emu/README | 3 ++- emu/emu.c | 39 ++++++++++++++++++++++++++------- emu/emul.c | 17 ++++++++++----- emu/emul.h | 6 ++++-- emu/memory.c | 40 ++++++++++++++++++++++++++++------ emu/memory.h | 6 +++++- emu/options.ggo | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ emu/options.ggo.in | 45 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 297 insertions(+), 34 deletions(-) create mode 100644 emu/options.ggo (limited to 'emu') diff --git a/emu/6502.c b/emu/6502.c index 5baaf32..ce1f0d3 100644 --- a/emu/6502.c +++ b/emu/6502.c @@ -11,7 +11,7 @@ static const uint16_t SP_base = 0x100; void cpu_6502_init( cpu_6502_t *cpu, struct memory_t *memory ) { cpu->memory = memory; - cpu->debug = false; + cpu->debug_flags = 0; } uint16_t cpu_6502_read_word( cpu_6502_t *cpu, uint16_t addr ) @@ -78,8 +78,14 @@ void cpu_6502_write_word( cpu_6502_t *cpu, uint16_t addr, uint16_t data ) void cpu_6502_run( cpu_6502_t *cpu, int steps ) { - for( int i = 0; i < steps; i++ ) { - cpu_6502_step( cpu ); + if( steps != -1 ) { + for( int i = 0; i < steps; i++ ) { + cpu_6502_step( cpu ); + } + } else { + while( true ) { + cpu_6502_step( cpu ); + } } } @@ -184,9 +190,13 @@ void cpu_6502_step( cpu_6502_t *cpu ) opcode = cpu_6502_read_byte( cpu, cpu->PC ); cpu->PC++; - if( cpu->debug ) { + if( cpu->debug_flags & DEBUG_STATUS ) { cpu_6502_print_state( cpu, opcode ); + } + if( cpu->debug_flags & DEBUG_STACK ) { cpu_6502_print_stack( cpu ); + } + if( cpu->debug_flags & DEBUG_ZERO_PAGE ) { cpu_6502_print_zerop_page( cpu ); } @@ -236,7 +246,7 @@ void cpu_6502_step( cpu_6502_t *cpu ) case STX_ABS: operand16 = cpu_6502_read_word( cpu, cpu->PC ); cpu->PC += 2; - cpu_6502_write_word( cpu, operand16, cpu->X ); + cpu_6502_write_byte( cpu, operand16, cpu->X ); break; case DEY_IMPL: diff --git a/emu/6502.h b/emu/6502.h index dac07a1..20574c3 100644 --- a/emu/6502.h +++ b/emu/6502.h @@ -15,11 +15,19 @@ typedef struct struct memory_t *memory; - bool debug; + int debug_flags; int steps; } cpu_6502_t; +// debug flags +enum { + DEBUG_STATUS = 0x01, + DEBUG_ZERO_PAGE = 0x02, + DEBUG_STACK = 0x04 +}; + +// processor state bits enum { PS_N = 0x80, PS_V = 0x40, @@ -30,6 +38,7 @@ enum { PS_C = 0x01 }; +// opcodes enum { LDX_IMM = 0xA2, LDX_ZERO = 0xA6, diff --git a/emu/7seg.c b/emu/7seg.c index e69de29..1aaf5f9 100644 --- a/emu/7seg.c +++ b/emu/7seg.c @@ -0,0 +1,43 @@ +#include "7seg.h" + +#include + +void seg7_init( seg7_t *seg ) +{ + seg->debug = false; +} + +uint8_t seg7_read( seg7_t *seg, uint16_t addr ) +{ + return 0; +} + +void seg7_write( seg7_t *seg, uint16_t addr, uint8_t data ) +{ + switch( addr ) { + case DDRA: + seg->ddr = data; + break; + + case PORTA: + // write bits from SER into shift register on positive SRCLK + if( ( seg->ddr | ( SRCLK & SER ) ) && ( data & SRCLK ) ) { + seg->shift = ( seg->shift << 1 ) | ( data & SER ); + if( seg->debug ) { + fprintf( stderr, "7seg shifting data, data is now %02X\n", seg->shift ); + } + } + + // copy shift to latch register on positive RCLK + if( ( seg->ddr | RCLK ) && ( data & RCLK ) ) { + seg->latch = seg->shift; + if( seg->debug ) { + fprintf( stderr, "7seg copying %02X from shift to latch\n", seg->latch ); + } + } + + break; + + // ignore writes to other addresses + } +} diff --git a/emu/7seg.h b/emu/7seg.h index c49a8a1..0cd585f 100644 --- a/emu/7seg.h +++ b/emu/7seg.h @@ -1,12 +1,42 @@ -#ifndef 7_SEG_H -#define 7_SEG_H +#ifndef SEG7_H +#define SEG7_H #ifdef WITH_GUI #include #endif -typedef struct 7seg_t +#include +#include + +// VIA connected on PORTA to 3 wires leading to the 3 coupled 74HC595 +// shift register which enable the ROM address lines to read the LED +// segment data (cells 0-15 contain the encoded 7 segments of 16 hexdigits) +// +// PORTA connected as follows: +// xxxxx111 +// +--- SER +// +---- RCLK +// +----- SRCLK +enum { + PORTA = 0x6001, + DDRA = 0x6003, + + SER = 0x01, + RCLK = 0x02, + SRCLK = 0x04 +}; + +typedef struct seg7_t { -} 7seg_t; + uint8_t ddr; + uint16_t shift; + uint16_t latch; + + 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 ); #endif diff --git a/emu/README b/emu/README index fc23a5d..37ccacb 100644 --- a/emu/README +++ b/emu/README @@ -1,4 +1,5 @@ emulator for homebrew 6502 based on ben eater ben6502 -gcc -DWITH_GUI -I/usr/include/SDL2 -lSDL2 -g -Wall -Os -o emu emu.c 6502.c memory.c emul.c +cmake . +make diff --git a/emu/emu.c b/emu/emu.c index 7c8f041..2723880 100644 --- a/emu/emu.c +++ b/emu/emu.c @@ -1,6 +1,7 @@ #include "emul.h" #include "6502.h" #include "memory.h" +#include "7seg.h" #include @@ -24,6 +25,7 @@ int main( int argc, char *argv[] ) emul_t emul; cpu_6502_t cpu; memory_t memory; + seg7_t seg7; if( parse_options_and_arguments( argc, argv, &args_info ) != 0 ) { exit( EXIT_FAILURE ); @@ -33,19 +35,40 @@ int main( int argc, char *argv[] ) printf( "emu version: %s, Copyright (c) 2020, LGPLv3, Andreas Baumann \n", EMU_VERSION ); exit( EXIT_SUCCESS ); } + + seg7_init( &seg7 ); + + memory_init( &memory, &seg7 ); + memory_load( &memory, ROM_START, ROM_SIZE, args_info.rom_arg ); - memory_init( &memory ); - memory_load( &memory, ROM_START, ROM_SIZE, "./rom.bin" ); - cpu_6502_init( &cpu, &memory ); - //cpu.debug = true; + if( args_info.debug_given ) { + if( args_info.print_cpu_given ) { + cpu.debug_flags |= DEBUG_STATUS; + } + if( args_info.print_zero_page_given ) { + cpu.debug_flags |= DEBUG_ZERO_PAGE; + } + if( args_info.print_stack_given ) { + cpu.debug_flags |= DEBUG_STACK; + } + if( args_info.print_7seg_given ) { + seg7.debug = true; + } + } cpu_6502_reset( &cpu ); - - emul_init( &emul, &cpu, &memory ); - emul.gui = true; + + emul_init( &emul, &cpu, &memory, 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" ); + exit( EXIT_SUCCESS ); + } + emul.gui = true; + } emul_start( &emul ); - emul_run( &emul ); + emul_run( &emul, args_info.steps_arg ); emul_free( &emul ); exit( EXIT_SUCCESS ); diff --git a/emu/emul.c b/emu/emul.c index 70a1144..930f112 100644 --- a/emu/emul.c +++ b/emu/emul.c @@ -3,11 +3,13 @@ #include #include -void emul_init( emul_t *emul, cpu_6502_t *cpu, memory_t *memory ) +void emul_init( emul_t *emul, cpu_6502_t *cpu, memory_t *memory, int width, int height ) { emul->cpu = cpu; emul->memory = memory; emul->gui = false; + emul->width = width; + emul->height = height; } void emul_start( emul_t *emul ) @@ -42,7 +44,7 @@ void emul_start( emul_t *emul ) emul->window = SDL_CreateWindow( "6502 emu", SDL_WINDOWPOS_UNDEFINED_DISPLAY( display ), SDL_WINDOWPOS_UNDEFINED_DISPLAY( display ), - 600, 250, 0 ); + emul->width, emul->height, 0 ); if( emul->window == NULL ) { fprintf( stderr, "ERROR: SDL_CreateWindow failed: %s\n", SDL_GetError( ) ); exit( EXIT_FAILURE ); @@ -69,7 +71,7 @@ void emul_start( emul_t *emul ) } } -void emul_run( emul_t *emul ) +void emul_run( emul_t *emul, int nof_steps ) { #ifdef WITH_GUI if( emul->gui ) { @@ -97,12 +99,17 @@ void emul_run( emul_t *emul ) if( delay > 0 ) { SDL_Delay( delay ); } + + if( nof_steps != -1 && emul->cpu->steps > nof_steps ) { + fprintf( stderr, "INFO: final number of steps reached (%d), terminating now\n", emul->cpu->steps ); + done = true; + } } } else { - cpu_6502_run( emul->cpu, 100 ); + cpu_6502_run( emul->cpu, nof_steps ); } #else - cpu_6502_run( emul->cpu, 100 ); + cpu_6502_run( emul->cpu, nof_steps ); #endif } diff --git a/emu/emul.h b/emu/emul.h index 131cd4c..6012309 100644 --- a/emu/emul.h +++ b/emu/emul.h @@ -21,6 +21,8 @@ typedef struct emul_t { cpu_6502_t *cpu; memory_t *memory; bool gui; + int width; + int height; #ifdef WITH_GUI SDL_Window *window; SDL_Renderer *renderer; @@ -29,9 +31,9 @@ typedef struct emul_t { #endif } emul_t; -void emul_init( emul_t *emul, cpu_6502_t *cpu, memory_t *memory ); +void emul_init( emul_t *emul, cpu_6502_t *cpu, memory_t *memory, int width, int height ); void emul_start( emul_t *emul ); -void emul_run( emul_t *emul ); +void emul_run( emul_t *emul, int nof_steps ); void emul_free( emul_t *emul ); #endif diff --git a/emu/memory.c b/emu/memory.c index c9d953b..408e621 100644 --- a/emu/memory.c +++ b/emu/memory.c @@ -2,25 +2,51 @@ #include -void memory_init( memory_t *memory ) +void memory_init( memory_t *memory, seg7_t *seg ) { memory->read = memory_read; memory->write = memory_write; + memory->seg = seg; } uint8_t memory_read( memory_t *memory, uint16_t addr ) { - return memory->cell[addr]; + 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]; + } } void memory_write( memory_t *memory, uint16_t addr, uint8_t data ) -{ - memory->cell[addr] = 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 + } } void memory_load( memory_t *memory, uint16_t addr, uint16_t size, const char *filename ) { - FILE *f = fopen( filename, "rb" ); - fread( &memory->cell[addr], size, 1, f ); - fclose( f ); + if( addr >= 0x8000 ) { + 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 ); + fclose( f ); + fprintf( stderr, "INFO: Loaded firware from '%s' of size %d starting on address %04X\n", + filename, size, addr ); + } else { + fprintf( stderr, "ERROR: Cannot load firmware into RAM at address %04X\n", addr ); + } } diff --git a/emu/memory.h b/emu/memory.h index 35fd0ef..b2abfee 100644 --- a/emu/memory.h +++ b/emu/memory.h @@ -1,6 +1,8 @@ #ifndef MEMORY_H #define MEMORY_H +#include "7seg.h" + #include enum { @@ -11,11 +13,13 @@ typedef struct memory_t { uint8_t cell[MEMORY_SIZE]; + 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_t; -void memory_init( memory_t *memory ); +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 ); diff --git a/emu/options.ggo b/emu/options.ggo new file mode 100644 index 0000000..2f97ea1 --- /dev/null +++ b/emu/options.ggo @@ -0,0 +1,63 @@ +package "emu" +version "0.0.1" +usage "emu [options]" +description "6502 emulator" + +section "Main Options" + option "long-version" - + "Full version and credentials" + optional + + option "gui" g + "Enable GUI" + optional + + option "debug" d + "Enable debugging output" + optional + +section "Run Options" + + option "rom" r + "The code to load into ROM" + string typestr="filename" + default="rom.bin" + optional + + option "steps" s + "Run at most 'steps' number of instructions (-1 means 'run forever')" + int typestr="steps" + default="-1" + optional + +section "Debug Options" + + option "print-cpu" - + "Print status of CPU (registers, status register)" + optional + + option "print-zero-page" - + "Print zero page of memory" + optional + + option "print-stack" - + "Print stack area of memory" + optional + + option "print-7seg" - + "Print what the 7-segment display on the VIA is doing" + optional + +section "GUI Options" + + option "width" - + "Manually set width of the gui to x" + int typestr="pixel" + default="600" + optional + + option "height" - + "Manually set height of the gui to y" + int typestr="pixel" + default="250" + optional diff --git a/emu/options.ggo.in b/emu/options.ggo.in index 61fb1d4..9cfbff9 100644 --- a/emu/options.ggo.in +++ b/emu/options.ggo.in @@ -16,3 +16,48 @@ section "Main Options" "Enable debugging output" optional +section "Run Options" + + option "rom" r + "The code to load into ROM" + string typestr="filename" + default="rom.bin" + optional + + option "steps" s + "Run at most 'steps' number of instructions (-1 means 'run forever')" + int typestr="steps" + default="-1" + optional + +section "Debug Options" + + option "print-cpu" - + "Print status of CPU (registers, status register)" + optional + + option "print-zero-page" - + "Print zero page of memory" + optional + + option "print-stack" - + "Print stack area of memory" + optional + + option "print-7seg" - + "Print what the 7-segment display on the VIA is doing" + optional + +section "GUI Options" + + option "width" - + "Manually set width of the gui to x" + int typestr="pixel" + default="600" + optional + + option "height" - + "Manually set height of the gui to y" + int typestr="pixel" + default="250" + optional -- cgit v1.2.3-54-g00ecf