diff --git a/cpu.c b/cpu.c index e4776cf..d68ebed 100644 --- a/cpu.c +++ b/cpu.c @@ -15,8 +15,22 @@ #include #include "cpu.h" +unsigned char CROSSED_PAGE; + +unsigned char different_page(uint16_t address1, uint16_t address2){ + return (address1&0xFF00) != (address2&0xFF00); +} + uint8_t get_absolute(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t)){ - return read((((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8)) + index); + uint16_t address1; + uint16_t address2; + + address1 = ((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8); + address2 = address1 + index; + + CROSSED_PAGE = different_page(address1, address2); + + return read(address2); } uint8_t get_indirect_X(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t)){ @@ -24,11 +38,27 @@ uint8_t get_indirect_X(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t)){ } uint8_t get_indirect_Y(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t)){ - return read((((uint16_t) read(index)) | (((uint16_t) read(index + 1))<<8)) + cpu->Y_reg); + uint16_t address1; + uint16_t address2; + + address1 = ((uint16_t) read(index)) | (((uint16_t) read(index + 1))<<8); + address2 = address1 + cpu->Y_reg; + + CROSSED_PAGE = different_page(address1, address2); + + return read(address2); } void set_absolute(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t), void (*write)(uint16_t, uint8_t), uint8_t value){ - write((((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8)) + index, value); + uint16_t address1; + uint16_t address2; + + address1 = ((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8); + address2 = address1 + index; + + CROSSED_PAGE = different_page(address1, address2); + + write(address2, value); } void set_indirect_X(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t), void (*write)(uint16_t, uint8_t), uint8_t value){ @@ -36,7 +66,15 @@ void set_indirect_X(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t), voi } void set_indirect_Y(CPU_6502 *cpu, uint8_t index, uint8_t (*read)(uint16_t), void (*write)(uint16_t, uint8_t), uint8_t value){ - write((((uint16_t) read(index)) | (((uint16_t) read(index + 1))<<8)) + cpu->Y_reg, value); + uint16_t address1; + uint16_t address2; + + address1 = ((uint16_t) read(index)) | (((uint16_t) read(index + 1))<<8); + address2 = address1 + cpu->Y_reg; + + CROSSED_PAGE = different_page(address1, address2); + + write(address2, value); } void push(CPU_6502 *cpu, void (*write)(uint16_t, uint8_t), uint8_t value){ @@ -59,6 +97,8 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 uint8_t prev; //The first byte at PC uniquely determines the operation uint8_t opcode; + uint16_t address1; + uint16_t address2; opcode = read(cpu->PC_reg); @@ -67,27 +107,47 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0x69){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0x65){//Zero page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x75){//Zero page X value1 = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x6D){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0x7D){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x79){//Absolute Y value1 = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x61){//Indirect X value1 = get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x71){//Indirect Y value1 = get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } prev = cpu->A_reg; @@ -134,27 +194,47 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0x29){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0x25){//Zero page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x35){//Zero page X value1 = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x2D){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0x3D){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x39){//Absolute Y value1 = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x21){//Indirect X value1 = get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x31){//Indirect Y value1 = get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } //Perform the AND @@ -176,14 +256,19 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x0A || opcode == 0x06 || opcode == 0x16 || opcode == 0x0E || opcode == 0x1E){ if(opcode == 0x0A){//Accumulator value1 = cpu->A_reg; + cpu->cycles += 2; } else if(opcode == 0x06){//Zero page value1 = read(read(cpu->PC_reg + 1)); + cpu->cycles += 5; } else if(opcode == 0x16){//Zero page X value1 = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); + cpu->cycles += 6; } else if(opcode == 0x0E){//Absolute value1 = get_absolute(cpu, 0, read); + cpu->cycles += 6; } else if(opcode == 0x1E){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); + cpu->cycles += 7; } //Set the carry flag @@ -228,36 +313,69 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } //BCC } else if(opcode == 0x90){//Branch carry clear + cpu->cycles += 2; + if(!(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } else {//If it is a positive jump - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; } //BCS } else if(opcode == 0xB0){//Branch carry set + cpu->cycles += 2; + if(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } else {//If it is a positive jump - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; } //BEQ } else if(opcode == 0xF0){//Branch equals + cpu->cycles += 2; + if(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } else {//If it is a postive jump - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; @@ -267,9 +385,11 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0x24){//Zero page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x2C){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } //Set the zero flag @@ -294,36 +414,69 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } //BMI } else if(opcode == 0x30){//Branch minus + cpu->cycles += 2; + if(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; - } else { - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; + } else {//If it is a positive jump + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; } //BNE } else if(opcode == 0xD0){//Branch not equal + cpu->cycles += 2; + if(!(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; - } else { - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; + } else {//If it is a positive jump + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; } //BPL } else if(opcode == 0x10){//Branch positive + cpu->cycles += 2; + if(!(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } else {//If it is a positive jump - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; @@ -338,26 +491,49 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 push(cpu, write, cpu->P_reg); cpu->P_reg |= 1<PC_reg = (((uint16_t) read(0xFFFF))<<8) | read(0xFFFE); + cpu->cycles += 7; //BVC } else if(opcode == 0x50){//Branch overflow clear + cpu->cycles += 2; + if(!(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } else {//If it is a positive jump - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; } //BVS } else if(opcode == 0x70){//Branch overflow set + cpu->cycles += 2; + if(cpu->P_reg&(1<cycles++; value1 = read(cpu->PC_reg + 1); if(value1&0x80){//If it is a negative jump - cpu->PC_reg -= ((uint16_t) ((~value1) - 1))&0xFF; + address1 = cpu->PC_reg - (((uint16_t) ((~value1) - 1))&0xFF); + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } else {//If it is a positive jump - cpu->PC_reg += value1 + 2; + address1 = cpu->PC_reg + value1 + 2; + if(different_page(cpu->PC_reg, address1)){ + cpu->cycles++; + } + cpu->PC_reg = address1; } } else { cpu->PC_reg += 2; @@ -366,44 +542,68 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x18){//Clear carry flag cpu->P_reg &= ~(1<PC_reg += 1; + cpu->cycles += 2; //CLD } else if(opcode == 0xD8){//Clear decimal flag cpu->P_reg &= ~(1<PC_reg += 1; + cpu->cycles += 2; //CLI } else if(opcode == 0x58){//Clear interrupt flag cpu->P_reg &= ~(1<PC_reg += 1; + cpu->cycles += 2; //CLV } else if(opcode == 0xB8){//Clear overflow flag cpu->P_reg &= ~(1<PC_reg += 1; + cpu->cycles += 2; //CMP } else if(opcode == 0xC9 || opcode == 0xC5 || opcode == 0xD5 || opcode == 0xCD || opcode == 0xDD || opcode == 0xD9 || opcode == 0xC1 || opcode == 0xD1){ if(opcode == 0xC9){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xC5){//Zero page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xD5){//Zero page X value1 = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0xCD){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0xDD){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0xD9){//Absolute Y value1 = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0xC1){//Indirect X value1 = get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0xD1){//Indirect Y value1 = get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } value2 = cpu->A_reg - value1; @@ -433,12 +633,15 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0xE0){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xE4){//Zero Page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xEC){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } value2 = cpu->X_reg - value1; @@ -468,12 +671,15 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0xC0){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xC4){//Zero Page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xCC){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } value2 = cpu->Y_reg - value1; @@ -506,20 +712,24 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 value1--; write(value2, value1); cpu->PC_reg += 2; + cpu->cycles += 5; } else if(opcode == 0xD6){//Zero page X value2 = read(cpu->PC_reg + 1); value1 = read((value2 + cpu->X_reg)&0xFF); value1--; write((value2 + cpu->X_reg)&0xFF, value1); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0xCE){//Absolute value1 = get_absolute(cpu, 0, read) - 1; set_absolute(cpu, 0, read, write, value1); cpu->PC_reg += 3; + cpu->cycles += 6; } else if(opcode == 0xDE){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read) - 1; set_absolute(cpu, cpu->X_reg, read, write, value1); cpu->PC_reg += 3; + cpu->cycles += 7; } //Set the zero flag @@ -539,6 +749,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0xCA){ cpu->X_reg--; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->X_reg){ @@ -557,6 +768,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x88){ cpu->Y_reg--; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->Y_reg){ @@ -576,27 +788,47 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0x49){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0x45){//Zero page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x55){//Zero page X value1 = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x4D){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0x5D){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x59){//Absolute Y value1 = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x41){//Indirect X value1 = get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x51){//Indirect Y value1 = get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } cpu->A_reg ^= value1; @@ -622,20 +854,24 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 value1++; write(value2, value1); cpu->PC_reg += 2; + cpu->cycles += 5; } else if(opcode == 0xF6){//Zero page X value2 = read(cpu->PC_reg + 1); value1 = read((value2 + cpu->X_reg)&0xFF); value1++; write((value2 + cpu->X_reg)&0xFF, value1); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0xEE){//Absolute value1 = get_absolute(cpu, 0, read) + 1; set_absolute(cpu, 0, read, write, value1); cpu->PC_reg += 3; + cpu->cycles += 6; } else if(opcode == 0xFE){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read) + 1; set_absolute(cpu, cpu->X_reg, read, write, value1); cpu->PC_reg += 3; + cpu->cycles += 7; } //Set the zero flag @@ -655,6 +891,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0xE8){ cpu->X_reg++; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->X_reg){ @@ -673,6 +910,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0xC8){ cpu->Y_reg++; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->Y_reg){ @@ -691,45 +929,66 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x4C || opcode == 0x6C){ if(opcode == 0x4C){//Absolute cpu->PC_reg = ((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8); + cpu->cycles += 3; } else if(opcode == 0x6C){//Indirect value_absolute = ((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8); value1 = read(value_absolute); value2 = read((value_absolute&0xFF00) | ((value_absolute + 1)&0xFF)); cpu->PC_reg = (((uint16_t) value2)<<8) | value1; - //printf("indirect jump: %04x %02x %02x\n", (int) value_absolute, (int) value1, (int) value2); - //DEBUG_STEP = 1; + cpu->cycles += 5; } //JSR } else if(opcode == 0x20){ push(cpu, write, (cpu->PC_reg + 2)&0xFF); push(cpu, write, (cpu->PC_reg + 2)>>8); cpu->PC_reg = ((uint16_t) read(cpu->PC_reg + 1)) | (((uint16_t) read(cpu->PC_reg + 2))<<8); + cpu->cycles += 6; //LDA } else if(opcode == 0xA9 || opcode == 0xA5 || opcode == 0xB5 || opcode == 0xAD || opcode == 0xBD || opcode == 0xB9 || opcode == 0xA1 || opcode == 0xB1){ if(opcode == 0xA9){//Immediate cpu->A_reg = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xA5){//Zero page cpu->A_reg = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xB5){//Zero page X cpu->A_reg = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0xAD){//Absolute cpu->A_reg = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0xBD){//Absolute X cpu->A_reg = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0xB9){//Absolute Y cpu->A_reg = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0xA1){//Indirect X cpu->A_reg = get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0xB1){//Indirect Y cpu->A_reg = get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } //Set the zero flag @@ -750,18 +1009,27 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0xA2){//Immediate cpu->X_reg = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xA6){//Zero page cpu->X_reg = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xB6){//Zero page Y cpu->X_reg = read((read(cpu->PC_reg + 1) + cpu->Y_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0xAE){//Absolute cpu->X_reg = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0xBE){//Absolute Y cpu->X_reg = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } //Set the zero flag @@ -782,18 +1050,27 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0xA0){//Immediate cpu->Y_reg = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xA4){//Zero page cpu->Y_reg = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xB4){//Zero page X cpu->Y_reg = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0xAC){//Absolute cpu->Y_reg = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0xBC){//Absolute X cpu->Y_reg = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } //Set the zero flag @@ -815,24 +1092,29 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 value1 = cpu->A_reg; cpu->A_reg >>= 1; cpu->PC_reg++; + cpu->cycles += 2; } else if(opcode == 0x46){//Zero page value2 = read(cpu->PC_reg + 1); value1 = read(value2); write(value2, value1>>1); cpu->PC_reg += 2; + cpu->cycles += 5; } else if(opcode == 0x56){//Zero page X value2 = read(cpu->PC_reg + 1); value1 = read((value2 + cpu->X_reg)&0xFF); write((value2 + cpu->X_reg)&0xFF, value1>>1); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x4E){//Absolute value1 = get_absolute(cpu, 0, read); set_absolute(cpu, 0, read, write, value1>>1); cpu->PC_reg += 3; + cpu->cycles += 6; } else if(opcode == 0x5E){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); set_absolute(cpu, cpu->X_reg, read, write, value1>>1); cpu->PC_reg += 3; + cpu->cycles += 7; } //Set the carry flag @@ -856,27 +1138,47 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 if(opcode == 0x09){//Immediate cpu->A_reg |= read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0x05){//Zero page cpu->A_reg |= read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x15){//Zero page X cpu->A_reg |= read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x0D){//Absolute cpu->A_reg |= get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0x1D){//Absolute X cpu->A_reg |= get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x19){//Absolute Y cpu->A_reg |= get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0x01){//Indirect X cpu->A_reg |= get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x11){//Indirect Y cpu->A_reg |= get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } //Set zero flag @@ -896,14 +1198,17 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x48){ push(cpu, write, cpu->A_reg); cpu->PC_reg += 1; - //PHP + cpu->cycles += 3; + //PHP (sucks) } else if(opcode == 0x08){ push(cpu, write, cpu->P_reg); cpu->PC_reg += 1; + cpu->cycles += 3; //PLA } else if(opcode == 0x68){ cpu->A_reg = pop(cpu, read); cpu->PC_reg += 1; + cpu->cycles += 4; //Set the zero flag if(!cpu->A_reg){ @@ -922,6 +1227,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x28){ cpu->P_reg = pop(cpu, read); cpu->PC_reg += 1; + cpu->cycles += 4; //ROL } else if(opcode == 0x2A || opcode == 0x26 || opcode == 0x36 || opcode == 0x2E || opcode == 0x3E){ //Determine whether to append a 1 or 0 for bit 0 @@ -934,24 +1240,29 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 value1 = cpu->A_reg; cpu->A_reg = (value1<<1) | value2; cpu->PC_reg += 1; + cpu->cycles += 2; } else if(opcode == 0x26){//Zero page value3 = read(cpu->PC_reg + 1); value1 = read(value3); write(value3, (value1<<1) | value2); cpu->PC_reg += 2; + cpu->cycles += 5; } else if(opcode == 0x36){//Zero page X value3 = read(cpu->PC_reg + 1); value1 = read((value3 + cpu->X_reg)&0xFF); write((value3 + cpu->X_reg)&0xFF, (value1<<1) | value2); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x2E){//Absolute value1 = get_absolute(cpu, 0, read); set_absolute(cpu, 0, read, write, (value1<<1) | value2); cpu->PC_reg += 3; + cpu->cycles += 6; } else if(opcode == 0x3E){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); set_absolute(cpu, cpu->X_reg, read, write, (value1<<1) | value2); cpu->PC_reg += 3; + cpu->cycles += 7; } value2 = (value1<<1) | value2; @@ -990,24 +1301,29 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 value1 = cpu->A_reg; cpu->A_reg = (value1>>1) | value2; cpu->PC_reg += 1; + cpu->cycles += 2; } else if(opcode == 0x66){//Zero page value3 = read(cpu->PC_reg + 1); value1 = read(value3); write(value3, (value1>>1) | value2); cpu->PC_reg += 2; + cpu->cycles += 5; } else if(opcode == 0x76){//Zero page X value3 = read(cpu->PC_reg + 1); value1 = read((value3 + cpu->X_reg)&0xFF); write((value3 + cpu->X_reg)&0xFF, (value1>>1) | value2); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x6E){//Absolute value1 = get_absolute(cpu, 0, read); set_absolute(cpu, 0, read, write, (value1>>1) | value2); cpu->PC_reg += 3; + cpu->cycles += 6; } else if(opcode == 0x7E){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); set_absolute(cpu, cpu->X_reg, read, write, (value1>>1) | value2); cpu->PC_reg += 3; + cpu->cycles += 7; } value2 = (value1>>1) | value2; @@ -1040,38 +1356,60 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 value1 = pop(cpu, read); value2 = pop(cpu, read); cpu->PC_reg = (((uint16_t) value1)<<8) | value2; + cpu->cycles += 6; //RTS } else if(opcode == 0x60){ value1 = pop(cpu, read); value2 = pop(cpu, read); cpu->PC_reg = (((uint16_t) value1)<<8) | value2; cpu->PC_reg++; + cpu->cycles += 6; //SBC } else if(opcode == 0xE9 || opcode == 0xE5 || opcode == 0xF5 || opcode == 0xED || opcode == 0xFD || opcode == 0xF9 || opcode == 0xE1 || opcode == 0xF1){ if(opcode == 0xE9){//Immediate value1 = read(cpu->PC_reg + 1); cpu->PC_reg += 2; + cpu->cycles += 2; } else if(opcode == 0xE5){//Zero page value1 = read(read(cpu->PC_reg + 1)); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0xF5){//Zero page X value1 = read((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0xED){//Absolute value1 = get_absolute(cpu, 0, read); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0xFD){//Absolute X value1 = get_absolute(cpu, cpu->X_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0xF9){//Absolute Y value1 = get_absolute(cpu, cpu->Y_reg, read); cpu->PC_reg += 3; + if(CROSSED_PAGE){ + cpu->cycles += 5; + } else { + cpu->cycles += 4; + } } else if(opcode == 0xE1){//Indirect X value1 = get_indirect_X(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0xF1){//Indirect Y value1 = get_indirect_Y(cpu, read(cpu->PC_reg + 1), read); cpu->PC_reg += 2; + if(CROSSED_PAGE){ + cpu->cycles += 6; + } else { + cpu->cycles += 5; + } } value2 = cpu->A_reg; @@ -1119,66 +1457,83 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x38){ cpu->P_reg |= 1<PC_reg += 1; + cpu->cycles += 2; //SED } else if(opcode == 0xF8){ cpu->P_reg |= 1<PC_reg += 1; + cpu->cycles += 2; //SEI } else if(opcode == 0x78){ cpu->P_reg |= 1<PC_reg += 1; + cpu->cycles += 2; //STA } else if(opcode == 0x85 || opcode == 0x95 || opcode == 0x8D || opcode == 0x9D || opcode == 0x99 || opcode == 0x81 || opcode == 0x91){ if(opcode == 0x85){//Zero page write(read(cpu->PC_reg + 1), cpu->A_reg); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x95){//Zero page X write((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF, cpu->A_reg); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x8D){//Absolute set_absolute(cpu, 0, read, write, cpu->A_reg); cpu->PC_reg += 3; + cpu->cycles += 4; } else if(opcode == 0x9D){//Absolute X set_absolute(cpu, cpu->X_reg, read, write, cpu->A_reg); cpu->PC_reg += 3; + cpu->cycles += 5; } else if(opcode == 0x99){//Absolute Y set_absolute(cpu, cpu->Y_reg, read, write, cpu->A_reg); cpu->PC_reg += 3; + cpu->cycles += 5; } else if(opcode == 0x81){//Indirect X set_indirect_X(cpu, read(cpu->PC_reg + 1), read, write, cpu->A_reg); cpu->PC_reg += 2; + cpu->cycles += 6; } else if(opcode == 0x91){//Indirect Y set_indirect_Y(cpu, read(cpu->PC_reg + 1), read, write, cpu->A_reg); cpu->PC_reg += 2; + cpu->cycles += 6; } //STX } else if(opcode == 0x86 || opcode == 0x96 || opcode == 0x8E){ if(opcode == 0x86){//Zero page write(read(cpu->PC_reg + 1), cpu->X_reg); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x96){//Zero page Y write((read(cpu->PC_reg + 1) + cpu->Y_reg)&0xFF, cpu->X_reg); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x8E){//Absolute set_absolute(cpu, 0, read, write, cpu->X_reg); cpu->PC_reg += 3; + cpu->cycles += 4; } //STY } else if(opcode == 0x84 || opcode == 0x94 || opcode == 0x8C){ if(opcode == 0x84){//Zero page write(read(cpu->PC_reg + 1), cpu->Y_reg); cpu->PC_reg += 2; + cpu->cycles += 3; } else if(opcode == 0x94){//Zero page X write((read(cpu->PC_reg + 1) + cpu->X_reg)&0xFF, cpu->Y_reg); cpu->PC_reg += 2; + cpu->cycles += 4; } else if(opcode == 0x8C){//Absolute set_absolute(cpu, 0, read, write, cpu->Y_reg); cpu->PC_reg += 3; + cpu->cycles += 4; } //TAX } else if(opcode == 0xAA){ cpu->X_reg = cpu->A_reg; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->X_reg){ @@ -1197,6 +1552,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0xA8){ cpu->Y_reg = cpu->A_reg; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->Y_reg){ @@ -1215,6 +1571,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0xBA){ cpu->X_reg = cpu->SP_reg; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->X_reg){ @@ -1233,6 +1590,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x8A){ cpu->A_reg = cpu->X_reg; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->A_reg){ @@ -1251,10 +1609,12 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 } else if(opcode == 0x9A){ cpu->SP_reg = cpu->X_reg; cpu->PC_reg += 1; + cpu->cycles += 2; //TYA } else if(opcode == 0x98){ cpu->A_reg = cpu->Y_reg; cpu->PC_reg += 1; + cpu->cycles += 2; //Set the zero flag if(!cpu->A_reg){ @@ -1272,6 +1632,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16 //NOP } else if(opcode == 0xEA){ cpu->PC_reg += 1; + cpu->cycles += 2; //Unknown operation } else { printf("Error: Unknown operation 0x%x\n", (int) opcode); diff --git a/cpu.h b/cpu.h index c06745d..d87a4d8 100644 --- a/cpu.h +++ b/cpu.h @@ -32,6 +32,7 @@ struct CPU_6502{ uint16_t PC_reg; //The bits status register are all of the processor flags, but it is its own register whose value can be pushed to the stack uint8_t P_reg; + unsigned long long int cycles; }; diff --git a/emulate.c b/emulate.c index 5cfff42..935ef15 100644 --- a/emulate.c +++ b/emulate.c @@ -1,18 +1,61 @@ #include #include +#include #include #include #include "cpu.h" -unsigned DEBUG_STEP = 0; +unsigned char DEBUG_STEP = 0; uint8_t memory[0x10000]; +uint32_t tape[0x100000]; + +uint32_t tape_index; + +char str_buffer[256]; + +unsigned char next_tape_index; + +unsigned char tape_active; + +unsigned char tape_writing; + +unsigned char tape_reading; + +unsigned char current_tape_value; + void print_state(CPU_6502 cpu){ printf("A: %02x X:%02x Y:%02x SP:%02x P:%02x PC:%02x\n", (int) cpu.A_reg, (int) cpu.X_reg, (int) cpu.Y_reg, (int) cpu.SP_reg, (int) cpu.P_reg, (int) cpu.PC_reg); printf("\nNext: %02x %02x %02x\n", (int) memory[cpu.PC_reg], (int) memory[cpu.PC_reg + 1], (int) memory[cpu.PC_reg + 2]); } +void load_tape(char *file_name){ + FILE *fp; + fp = fopen(file_name, "rb"); + printf("Reading from tape file named \"%s\"\n", file_name); + if(fp){ + fread(tape, 4, 0x100000, fp); + fclose(fp); + } else { + printf("file error\n"); + } + + return; +} + +void store_tape(char *file_name){ + FILE *fp; + printf("Storing tape to file named \"%s\"\n", file_name); + fp = fopen(file_name, "wb"); + if(fp){ + fwrite(tape, 4, 0x100000, fp); + fclose(fp); + } else { + printf("file error\n"); + } +} + //Special read memory routine for memory-mapped I/O uint8_t read_mem(uint16_t index){ uint8_t output; @@ -20,7 +63,19 @@ uint8_t read_mem(uint16_t index){ if(DEBUG_STEP){ printf("READ: %04x ", index); } - output = memory[index]; + + if(tape_writing && index >= 0xC000 && index <= 0xC0FF){ + next_tape_index = 1; + } else if(index >= 0xC081 && index <= 0xC0FF){ + if(current_tape_value){ + output = memory[index]; + } else { + output = memory[index&0xFFFE]; + } + } else { + output = memory[index]; + } + if(index == 0xD010){ memory[0xD011] &= 0x7F; } else if((index&0xFF0F) == 0xD002){ @@ -59,6 +114,10 @@ int main(){ unsigned long int last_time; unsigned long int next_time; struct timeval current_time; + char temp_char; + unsigned char str_index; + unsigned long long int last_cycles; + unsigned char last_cycle_diff; cpu.A_reg = 0; cpu.X_reg = 0; @@ -66,45 +125,62 @@ int main(){ cpu.SP_reg = 0; cpu.P_reg = 0; cpu.PC_reg = 0xE000; + tape_writing = 0; + tape_reading = 0; //Load Integer Basic fp = fopen("BASIC", "rb"); if(fp){ - fread(memory + 0xE000, 1, 0x2000, fp); + fread(memory + 0xE000, 1, 0x1000, fp); + } else { + printf("Warning: could not load file named \"BASIC\".\nStarting without apple 1 BASIC loaded.\nApple 1 basic can still be loaded from a cassette file into address 0xE000.\n---\n"); + } + fclose(fp); + + //Load Woz's ACI + fp = fopen("WOZACI", "rb"); + if(fp){ + fread(memory + 0xC000, 1, 0x100, fp); } else { printf("file error\n"); exit(1); } fclose(fp); - - //The emulator does not support ACI at the moment - + + memcpy(memory + 0xC100, memory + 0xC000, 0x100); + //Load Woz's monitor fp = fopen("WOZMON", "rb"); if(fp){ fread(memory + 0xFF00, 1, 0x100, fp); } else { - printf("file error 3\n"); + printf("file error\n"); exit(1); } fclose(fp); reset_6502(&cpu, read_mem);//Reset the cpu + cpu.cycles = 0; + last_cycles = 0; //Initialize the timing gettimeofday(¤t_time, NULL); last_time = current_time.tv_usec + current_time.tv_sec*1000000; + last_cycle_diff = 0; + next_tape_index = 0; while(1){ - /*Limit the speed of the processor to - * a realistic 4usec per instruction + /* Limit the speed of the processor to + * a realistic 4nsec per instruction * * Will count cpu cycles soon to make * better timing. */ - do{ - gettimeofday(¤t_time, NULL); - next_time = current_time.tv_usec + current_time.tv_sec*1000000; - } while(next_time - last_time < 4); - last_time = last_time + 4; + if(!DEBUG_STEP){ + do{ + gettimeofday(¤t_time, NULL); + next_time = current_time.tv_usec + current_time.tv_sec*1000000; + } while(next_time - last_time < last_cycle_diff); + last_time = last_time + last_cycle_diff; + } //Execute the instruction execute_6502(&cpu, read_mem, write_mem); @@ -112,13 +188,60 @@ int main(){ //Debugging I/O if(DEBUG_STEP){ - print_state(cpu); - key_hit = getchar(); - if(key_hit == '|'){ + memset(str_buffer, 256, 0); + fgets(str_buffer, 256, stdin); + temp_char = str_buffer[6]; + str_buffer[6] = (char) 0; + + if(!strcmp(str_buffer, "resume")){ DEBUG_STEP = 0; - } else if(key_hit != ' '){ - memory[0xD010] = key_hit|0x80; - memory[0xD011] = 0xFF; + gettimeofday(¤t_time, NULL); + last_time = current_time.tv_usec + current_time.tv_sec*1000000; + } else if(temp_char == ' ' && !strcmp(str_buffer, "tstart")){ + tape_active = 1; + str_buffer[12] = (char) 0; + if(temp_char == ' ' && !strcmp(str_buffer + 7, "write")){ + tape_writing = 1; + printf("WRITING TO TAPE\n"); + } + str_buffer[11] = (char) 0; + if(temp_char == ' ' && !strcmp(str_buffer + 7, "read")){ + tape_reading = 1; + current_tape_value = 0; + printf("READING FROM TAPE\n"); + } + tape_index = 0; + } else if(temp_char == ' ' && !strcmp(str_buffer, "tstore")){ + str_index = 0; + while(str_buffer[str_index] != '\n' && str_index < 255){ + str_index++; + } + str_buffer[str_index] = (char) 0; + store_tape(str_buffer + 7); + } + + str_buffer[6] = temp_char; + temp_char = str_buffer[5]; + str_buffer[5] = (char) 0; + + if(!strcmp(str_buffer, "tstop")){ + tape_active = 0; + tape_writing = 0; + tape_reading = 0; + } + + if(temp_char == ' ' && !strcmp(str_buffer, "tload")){ + str_index = 0; + while(str_buffer[str_index] != '\n' && str_index < 255){ + str_index++; + } + str_buffer[str_index] = (char) 0; + load_tape(str_buffer + 6); + } + + if(str_buffer[0] != (char) 0 && str_buffer[1] == (char) 0){ + memory[0xD010] = str_buffer[0]|0x80; + memory[0xD011] |= 0x80; } } @@ -128,10 +251,34 @@ int main(){ if(key_hit == '|'){ DEBUG_STEP = 1; + printf("\n"); } else { memory[0xD010] = key_hit|0x80; memory[0xD011] |= 0x80; } } + + last_cycle_diff = cpu.cycles - last_cycles; + + //Handle tape + if(tape_active && tape_reading){ + while(last_cycles < cpu.cycles){ + if(!tape[tape_index]){ + tape_index++; + current_tape_value = !current_tape_value; + } + tape[tape_index] -= 1; + last_cycles++; + } + } else if(tape_active && tape_writing){ + tape[tape_index] += cpu.cycles - last_cycles; + if(next_tape_index){ + tape_index++; + next_tape_index = 0; + } + last_cycles = cpu.cycles; + } else { + last_cycles = cpu.cycles; + } } }