From fbe874b3e717fd39cae82e126115b17f80b9bc67 Mon Sep 17 00:00:00 2001 From: Raimon Zamora Date: Wed, 5 Feb 2025 13:59:56 +0100 Subject: [PATCH] =?UTF-8?q?-=20Comence=20a=20escriure=20la=20versi=C3=B3?= =?UTF-8?q?=20amb=20microcodi=20del=206502?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 6502m.cpp | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6502m.h | 9 +++ mem.h | 4 +- 3 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 6502m.cpp create mode 100644 6502m.h diff --git a/6502m.cpp b/6502m.cpp new file mode 100644 index 0000000..16da1fa --- /dev/null +++ b/6502m.cpp @@ -0,0 +1,200 @@ +#include "6502m.h" +#include "mem.h" + + // P register Flags + #define fC 0b00000001 // Carry + #define fZ 0b00000010 // Zero + #define fI 0b00000100 // Interrupt disable + #define fD 0b00001000 // Decimal + #define fB 0b00010000 // Interrupt type? + #define f1 0b00100000 // -Unused- + #define fV 0b01000000 // Overflow + #define fN 0b10000000 // Negative + + // Jump types + #define cUnconditional 255 + #define cNZ 0 + #define cZ 1 + #define cNC 2 + #define cC 3 + #define cNN 4 + #define cN 5 + #define cNV 6 + #define cV 7 + + // Addressing modes + #define aAccumulator 0 + #define aImmediate 1 + #define aZeroPage 2 + #define aZeroPageX 3 + #define aZeroPageY 4 + #define aRelative 5 // Is really needed? + #define aIndirect 6 + #define aIndirectX 7 + #define aIndirectY 8 + #define aAbsolute 9 + #define aAbsoluteX 10 + #define aAbsoluteY 11 + +namespace m6502 +{ + uint8_t interrupt_type = 0xfe; + + uint8_t regs[13]; + + uint8_t *_rA = ®s[0]; + uint8_t *_rX = ®s[1]; + uint8_t *_rY = ®s[2]; + uint8_t *_rS = ®s[3]; + uint8_t *_rP = ®s[4]; + uint8_t *_rPC_lo = ®s[5]; + uint8_t *_rPC_hi = ®s[6]; + uint16_t *_rPC = (uint16_t*)®s[5]; + + uint8_t *_rB = ®s[7]; + uint8_t *_rT = ®s[8]; + uint8_t *_rI = ®s[9]; + uint8_t *_rAD_lo = ®s[10]; + uint8_t *_rAD_hi = ®s[11]; + uint16_t *_rAD = (uint16_t*)®s[10]; + uint8_t *_rTEMP_lo = ®s[12]; + uint8_t *_rTEMP_hi = ®s[13]; + uint16_t *_rTEMP = (uint16_t*)®s[12]; + + #define rA (*_rA) + #define rX (*_rX) + #define rY (*_rY) + #define rS (*_rS) + #define rP (*_rP) + #define rPC_lo (*_rPC_lo) + #define rPC_hi (*_rPC_hi) + #define rPC (*_rPC) + + #define rB (*_rB) + #define rT (*_rT) + #define rI (*_rI) + #define rAD_lo (*_rAD_lo) + #define rAD_hi (*_rAD_hi) + #define rAD (*_rAD) + #define rTEMP_lo (*_rTEMP_lo) + #define rTEMP_hi (*_rTEMP_hi) + #define rTEMP (*_rTEMP) + + uint8_t microcode[256]; + uint8_t microcode_pos = 0; + uint8_t microcode_last = 0; + + enum microInstructions { + miFetchOpcode, + miFakeFetchOperand, + miFetchOperandLo, + miFetchOperandHi, + miFetchOperandHiAndIndexX, + miFetchOperandHiAndIndexY, + miPushPCHi, + miPushPCLo, + miPushP, + miPCLoInt, + miPCHiInt, + miIndexX, + miFetchAddressLo, + miFetchAddressHi, + miFetchAddressHiAndIndex, + miReadAddress, + miReadAddressAndSkip, + miWriteRegister, + miNumMicroinstructions + }; + + + uint8_t instructions[256][7] = { + /* 0x00 BRK */ { miFetchOperandLo, miPushPCHi, miPushPCLo, miPushP, miPCLoInt, miPCHiInt, miFetchOpcode }, + /* 0x01 ORA X,ind */ { miFetchOperandLo, miIndexX, miFetchAddressLo, miFetchAddressHi, miReadAddress, miFetchOpcode }, + /* 0x02 --- */ { miFetchOpcode }, + /* 0x03 --- */ { miFetchOpcode }, + /* 0x04 --- */ { miFetchOpcode }, + /* 0x05 ORA zpg */ { miFetchOperandLo, miReadAddress, miFetchOpcode }, + }; + + void SetFlags(uint8_t flags) + { + if (flags&fC) rP = ( rP & ~fC ) | ( rTEMP_hi & fC ); + if (flags&fN) rP = ( rP & ~fN ) | ( rB & fN ); + if (flags&fZ) rP = ( rB ? rP & ~fZ : rP | fZ ); + if (flags&fV) rP = ( (rTEMP_lo ^ rA) & (rTEMP_lo ^ rB) & 0x80 ) ? rP | fV : rP & ~fV; + } + + void DoOpcodeWork() + { + switch (rI&0x03) { + case 1: /* ALU */ + switch ((rI>>5)&0x07) { + case 0: /* ORA */ rB = rA | rB; SetFlags(fN|fZ); rA = rB; break; + case 1: /* AND */ rB = rA & rB; SetFlags(fN|fZ); rA = rB; break; + case 2: /* EOR */ rB = rA ^ rB; SetFlags(fN|fZ); rA = rB; break; + case 3: /* ADC */ rTEMP = rA + rB + fC; SetFlags(fN|fV|fZ|fC); rA = rTEMP_lo; break; + case 5: /* LDA */ SetFlags(fN|fZ); rA = rB; break; + case 6: /* CMP */ rTEMP = rA + ~rB; SetFlags(fN|fZ|fC); break; + case 7: /* SBC */ rTEMP = rA + ~rB + fC; SetFlags(fN|fV|fZ|fC); rA = rTEMP_lo; break; + }; + break; + }; + } + + void InsertFetchOpcode() + { + microcode[microcode_pos] = miFetchOpcode; + microcode_last = microcode_pos+1; + } + + void FetchOpcode() + { + DoOpcodeWork(); + rI = mem::read(rPC++); + int i=0; do { microcode[microcode_last++] = instructions[rI][i++]; } while (instructions[rI][i-1] != miFetchOpcode); + } + + void FakeFetchOperand() { rAD_lo = mem::read(rPC); } + void FetchOperandLo() { rTEMP = rAD_lo = rB = mem::read(rPC++); } + void FetchOperandHi() { rAD_hi = mem::read(rPC++); } + void FetchOperandHiAndIndexX() { rAD_hi = mem::read(rPC++); rTEMP = rAD_lo + rX; rAD_lo = rTEMP_lo; } + void FetchOperandHiAndIndexY() { rAD_hi = mem::read(rPC++); rTEMP = rAD_lo + rY; rAD_lo = rTEMP_lo; } + + void PushPCHi() { mem::write(0x0100+(rS++), rPC_hi); } + void PushPCLo() { mem::write(0x0100+(rS++), rPC_lo); } + void PushP() { mem::write(0x0100+(rS++), rP|f1|fB); rP |= fI; } + void PCLoInt() { rPC_lo = mem::read(0xff00+interrupt_type); } + void PCHiInt() { rPC_hi = mem::read(0xff00+interrupt_type+1); } + + void IndexX() { rB = mem::read(rAD); rAD_lo += rX; } + void FetchAddressLo() { rT = mem::read(rAD++); } + void FetchAddressHi() { rAD_hi = mem::read(rAD); rAD_lo = rT; } + void FetchAddressHiAndIndex() { rAD_hi = mem::read(rAD); rTEMP = rAD_lo + rY; rAD_lo = rTEMP_lo; } + void ReadAddress() { rB = mem::read(rAD); rAD_hi += rTEMP_hi; } + + void ReadAddressAndSkip() { rB = mem::read(rAD); rAD_hi += rTEMP_hi; if (rTEMP_hi) InsertFetchOpcode(); } + void WriteRegister() { mem::write(rAD, (rI&3)==1 ? rA : (rI&3)==2 ? rX : rY ); } + + void (*microinstructions[miNumMicroinstructions])(void) { + FetchOpcode, FakeFetchOperand, FetchOperandLo, FetchOperandHi, FetchOperandHiAndIndexX, FetchOperandHiAndIndexY, + PushPCHi, PushPCLo, PushP, PCLoInt, PCHiInt, + IndexX, FetchAddressLo, FetchAddressHi, FetchAddressHiAndIndex, ReadAddress, + ReadAddressAndSkip, WriteRegister }; + + void reset() + { + + } + + void interrupt(uint8_t type) + { + + } + + void tick() + { + uint8_t m_inst = microcode[microcode_pos++]; + microinstructions[m_inst](); + } + +} diff --git a/6502m.h b/6502m.h new file mode 100644 index 0000000..215c7e3 --- /dev/null +++ b/6502m.h @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace m6502 +{ + void reset(); + void interrupt(uint8_t type); + void tick(); +} diff --git a/mem.h b/mem.h index f12db3f..9a2ba35 100644 --- a/mem.h +++ b/mem.h @@ -18,8 +18,8 @@ namespace mem void reset(); - uint8_t readMem(uint16_t address); - void writeMem(uint16_t address, uint8_t value); + uint8_t read(uint16_t address); + void write(uint16_t address, uint8_t value); uint8_t getTag(uint16_t address); void setTag(uint16_t address, uint8_t value);