mirror of
https://github.com/trudnai/Steve2.git
synced 2024-10-08 09:55:39 +00:00
256 lines
6.4 KiB
C
256 lines
6.4 KiB
C
//
|
|
// main.c
|
|
// 6502
|
|
//
|
|
// Created by Tamas Rudnai on 7/14/19.
|
|
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
|
|
//
|
|
// This file is part of Steve ][ -- The Apple ][ Emulator.
|
|
//
|
|
// Steve ][ is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Steve ][ is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
// Documentations:
|
|
//
|
|
// http://nesdev.com/6502_cpu.txt
|
|
// http://www.oxyron.de/html/opcodes02.html
|
|
// https://macgui.com/kb/article/46
|
|
// https://www.masswerk.at/6502/6502_instruction_set.html
|
|
//
|
|
|
|
#define CLK_WAIT
|
|
|
|
#define DEBUGGER
|
|
#undef DISASSEMBLER
|
|
|
|
#define FETCH_ADDR disass_addr
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "6502.h"
|
|
#include "speaker.h"
|
|
|
|
|
|
#include "../util/common.h"
|
|
|
|
|
|
#define SOFTRESET_VECTOR 0x3F2
|
|
|
|
#define NMI_VECTOR 0xFFFA
|
|
#define RESET_VECTOR 0xFFFC
|
|
#define IRQ_VECTOR 0xFFFE
|
|
|
|
extern m6502_t m6502;
|
|
m6502_t m6502_saved;
|
|
|
|
uint16_t disass_addr = 0xFDED;
|
|
|
|
//#include "6502_dis.h"
|
|
#include "../dev/mem/mmio.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
uint8_t L;
|
|
uint8_t H;
|
|
} bytes_t;
|
|
|
|
|
|
/**
|
|
Instruction Implementations
|
|
!!!! `his has to be here!!!
|
|
This idea is that "INLINE" would work only if it is
|
|
located in the same source file -- hence the include...
|
|
**/
|
|
|
|
|
|
#include "6502_dbg.h"
|
|
#include "6502_instructions.h"
|
|
#include "6502_bp.h"
|
|
|
|
INLINE int m6502_Step_dbg(void) {
|
|
disNewInstruction();
|
|
|
|
switch ( fetch() ) {
|
|
#include "6502_std.h" // Standard 6502 instructions
|
|
//#include "6502_und.h" // Undocumented 6502 instructions
|
|
#include "6502_C.h" // Extended 65C02 instructions
|
|
#include "6502_C_Rockwell.h" // Extended 65C02 instructions
|
|
|
|
default:
|
|
dbgPrintf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, memread( m6502.PC -1 ));
|
|
m6502.interrupt = INV;
|
|
return 2;
|
|
} // switch fetch16
|
|
|
|
return 2;
|
|
}
|
|
|
|
|
|
void m6502_Debug(void) {
|
|
m6502.clktime += m6502.clkfrm;
|
|
m6502.clkfrm = 0;
|
|
m6502.lastIO = 0;
|
|
m6502.interrupt = NO_INT; // TODO: This should be taken care by the interrupt handler
|
|
|
|
m6502_dbg_on();
|
|
|
|
if( diskAccelerator_count ) {
|
|
if( --diskAccelerator_count <= 0 ) {
|
|
// make sure we only adjust clock once to get back to normal
|
|
diskAccelerator_count = 0;
|
|
clk_6502_per_frm = clk_6502_per_frm_set;
|
|
}
|
|
}
|
|
|
|
clk_6502_per_frm_max = clk_6502_per_frm;
|
|
|
|
while ( m6502.clkfrm < clk_6502_per_frm_max ) {
|
|
m6502_saved = m6502;
|
|
m6502.clkfrm += m6502_Step_dbg();
|
|
|
|
switch (m6502.interrupt) {
|
|
case HALT:
|
|
if (m6502.debugger.mask.hlt) {
|
|
cpuState = cpuState_halted;
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case BREAK:
|
|
if (m6502.debugger.mask.brk) {
|
|
cpuState = cpuState_halted;
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case BREAKRDMEM:
|
|
case BREAKWRMEM:
|
|
if (m6502.debugger.mask.brk) {
|
|
cpuState = cpuState_halted;
|
|
|
|
// memory break happens *after* executing the instruction,
|
|
// therefore we need to step back to get it right in the debugger
|
|
m6502_saved.interrupt = m6502.interrupt; // we need to keep the new interrupt though
|
|
m6502 = m6502_saved; // copy over only A, X, Y, Status, PC & SP...
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case IRQ:
|
|
if (m6502.debugger.mask.irq) {
|
|
cpuState = cpuState_halted;
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case NMI:
|
|
if (m6502.debugger.mask.nmi) {
|
|
cpuState = cpuState_halted;
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case INV:
|
|
if (m6502.debugger.mask.inv) {
|
|
cpuState = cpuState_halted;
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case RET:
|
|
// Step_Out & Step_Over: Return to caller
|
|
if (m6502.debugger.mask.out) {
|
|
if ( m6502.SP >= m6502.debugger.SP ) {
|
|
cpuState = cpuState_halted;
|
|
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HARDRESET:
|
|
hardReset();
|
|
break;
|
|
|
|
case SOFTRESET:
|
|
softReset();
|
|
break;
|
|
|
|
default:
|
|
// Step_Out: If there was a POP (PLA, PLX, PLY, PLP), then we should update the monitoring stack pointer
|
|
// (so we can return to the caller, not stopping at the POP)
|
|
if ( m6502.SP > m6502.debugger.SP ) {
|
|
m6502.debugger.SP = m6502.SP;
|
|
}
|
|
break;
|
|
}
|
|
|
|
m6502.interrupt = NO_INT;
|
|
|
|
if ( m6502_dbg_bp_exists(breakpoints, m6502.PC) ) {
|
|
cpuState = cpuState_halted;
|
|
m6502.interrupt = BREAKPOINT;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// play the entire sound buffer for this frame
|
|
spkr_update();
|
|
// this will take care of turning off disk motor sound when time is up
|
|
spkr_update_disk_sfx();
|
|
|
|
}
|
|
|
|
|
|
/// Turn On Debugger
|
|
void m6502_dbg_on(void) {
|
|
m6502.debugger.on = 1;
|
|
}
|
|
|
|
|
|
/// Turn Off Debugger
|
|
void m6502_dbg_off(void) {
|
|
m6502.debugger.on = 0;
|
|
}
|
|
|
|
|
|
/// Initialize Breakpoints
|
|
void m6502_dbg_init(void) {
|
|
m6502_dbg_on();
|
|
m6502.debugger.wMask = 0;
|
|
m6502.debugger.mask.hlt = 1;
|
|
m6502.debugger.mask.brk = 1;
|
|
m6502.debugger.mask.inv = 1;
|
|
m6502.debugger.SP = 0xFF;
|
|
m6502_dbg_bp_del_all(breakpoints);
|
|
m6502_dbg_bp_del_all(mem_read_breakpoints);
|
|
m6502_dbg_bp_del_all(mem_write_breakpoints);
|
|
|
|
// TODO: TESTING ONLY!!!
|
|
// m6502_dbg_bp_add(mem_read_breakpoints, 0xC000);
|
|
// m6502_dbg_bp_add(mem_write_breakpoints, 0xC099);
|
|
}
|
|
|
|
|