Cross platform
This commit is contained in:
parent
9822aa07cd
commit
a86f9e23d3
15
cpu.c
15
cpu.c
|
@ -11,10 +11,19 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <conio.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <curses.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned char CROSSED_PAGE;
|
unsigned char CROSSED_PAGE;
|
||||||
|
|
||||||
unsigned char different_page(uint16_t address1, uint16_t address2){
|
unsigned char different_page(uint16_t address1, uint16_t address2){
|
||||||
|
@ -1635,7 +1644,7 @@ void execute_6502(CPU_6502 *cpu, uint8_t (*read)(uint16_t), void (*write)(uint16
|
||||||
cpu->cycles += 2;
|
cpu->cycles += 2;
|
||||||
//Unknown operation
|
//Unknown operation
|
||||||
} else {
|
} else {
|
||||||
printf("Error: Unknown operation 0x%x\n", (int) opcode);
|
printw("Error: Unknown operation 0x%x\n", (int) opcode);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
129
emulate.c
129
emulate.c
|
@ -1,10 +1,27 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <conio.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <curses.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
void Sleep(long int msec){
|
||||||
|
struct timespec sleep_time;
|
||||||
|
|
||||||
|
sleep_time.tv_sec = msec/1000;
|
||||||
|
sleep_time.tv_nsec = (msec%1000)*1000000;
|
||||||
|
nanosleep(&sleep_time, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned char DEBUG_STEP = 0;
|
unsigned char DEBUG_STEP = 0;
|
||||||
|
|
||||||
uint8_t memory[0x10000];
|
uint8_t memory[0x10000];
|
||||||
|
@ -26,19 +43,19 @@ unsigned char tape_reading;
|
||||||
unsigned char current_tape_value;
|
unsigned char current_tape_value;
|
||||||
|
|
||||||
void print_state(CPU_6502 cpu){
|
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);
|
printw("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]);
|
printw("\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){
|
void load_tape(char *file_name){
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
fp = fopen(file_name, "rb");
|
fp = fopen(file_name, "rb");
|
||||||
printf("Reading from tape file named \"%s\"\n", file_name);
|
printw("Reading from tape file named \"%s\"\n", file_name);
|
||||||
if(fp){
|
if(fp){
|
||||||
fread(tape, 4, 0x100000, fp);
|
fread(tape, 4, 0x100000, fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
printf("file error\n");
|
printw("file error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -46,13 +63,13 @@ void load_tape(char *file_name){
|
||||||
|
|
||||||
void store_tape(char *file_name){
|
void store_tape(char *file_name){
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
printf("Storing tape to file named \"%s\"\n", file_name);
|
printw("Storing tape to file named \"%s\"\n", file_name);
|
||||||
fp = fopen(file_name, "wb");
|
fp = fopen(file_name, "wb");
|
||||||
if(fp){
|
if(fp){
|
||||||
fwrite(tape, 4, 0x100000, fp);
|
fwrite(tape, 4, 0x100000, fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
printf("file error\n");
|
printw("file error\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +78,7 @@ uint8_t read_mem(uint16_t index){
|
||||||
uint8_t output;
|
uint8_t output;
|
||||||
|
|
||||||
if(DEBUG_STEP){
|
if(DEBUG_STEP){
|
||||||
printf("READ: %04x ", index);
|
printw("READ: %04x ", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tape_writing && index >= 0xC000 && index <= 0xC0FF){
|
if(tape_writing && index >= 0xC000 && index <= 0xC0FF){
|
||||||
|
@ -82,7 +99,7 @@ uint8_t read_mem(uint16_t index){
|
||||||
output = 0;
|
output = 0;
|
||||||
}
|
}
|
||||||
if(DEBUG_STEP){
|
if(DEBUG_STEP){
|
||||||
printf("%02x\n", memory[index]);
|
printw("%02x\n", memory[index]);
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -93,16 +110,16 @@ void write_mem(uint16_t index, uint8_t value){
|
||||||
uint8_t y;
|
uint8_t y;
|
||||||
|
|
||||||
if(DEBUG_STEP){
|
if(DEBUG_STEP){
|
||||||
printf("WRITE: %02x --> %04x\n", value, index);
|
printw("WRITE: %02x --> %04x\n", value, index);
|
||||||
}
|
}
|
||||||
if((index&0xFF0F) == 0xD002){
|
if((index&0xFF0F) == 0xD002){
|
||||||
if((value&0x7F) == '\n' || (value&0x7F) == '\r'){//Print \n instead of \r
|
if((value&0x7F) == '\n' || (value&0x7F) == '\r'){//Print \n instead of \r
|
||||||
printf("\n");
|
printw("\n");
|
||||||
} else if((value&0x7F) == 0x5F){//Make the 0x5F character map to ASCII backspace
|
} else if((value&0x7F) == 0x5F){//Make the 0x5F character map to ASCII backspace
|
||||||
printf("\b \b");
|
printw("\b \b");
|
||||||
} else if((value&0x7F) >= 0x20 && (value&0x7F) != 127){
|
} else if((value&0x7F) >= 0x20 && (value&0x7F) != 127){
|
||||||
//Output a character
|
//Output a character
|
||||||
printf("%c", value&0x7F);
|
printw("%c", value&0x7F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memory[index] = value;
|
memory[index] = value;
|
||||||
|
@ -111,15 +128,15 @@ void write_mem(uint16_t index, uint8_t value){
|
||||||
int main(){
|
int main(){
|
||||||
CPU_6502 cpu;
|
CPU_6502 cpu;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
unsigned char key_hit;
|
int key_hit;
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
unsigned long int last_time;
|
|
||||||
unsigned long int next_time;
|
|
||||||
struct timeval current_time;
|
|
||||||
char temp_char;
|
char temp_char;
|
||||||
unsigned char str_index;
|
unsigned char str_index;
|
||||||
unsigned long long int last_cycles;
|
unsigned long long int last_cycles;
|
||||||
unsigned char last_cycle_diff;
|
unsigned char last_cycle_diff;
|
||||||
|
unsigned long long int last_time;
|
||||||
|
struct timespec current_time;
|
||||||
|
unsigned long long int next_time;
|
||||||
|
|
||||||
cpu.A_reg = 0;
|
cpu.A_reg = 0;
|
||||||
cpu.X_reg = 0;
|
cpu.X_reg = 0;
|
||||||
|
@ -130,24 +147,32 @@ int main(){
|
||||||
tape_writing = 0;
|
tape_writing = 0;
|
||||||
tape_reading = 0;
|
tape_reading = 0;
|
||||||
|
|
||||||
|
initscr();
|
||||||
|
cbreak();
|
||||||
|
noecho();
|
||||||
|
scrollok(stdscr, 1);
|
||||||
|
|
||||||
//Load Integer Basic
|
//Load Integer Basic
|
||||||
fp = fopen("BASIC", "rb");
|
fp = fopen("BASIC", "rb");
|
||||||
if(fp){
|
if(fp){
|
||||||
fread(memory + 0xE000, 1, 0x1000, fp);
|
fread(memory + 0xE000, 1, 0x1000, fp);
|
||||||
|
fclose(fp);
|
||||||
} else {
|
} 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");
|
printw("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");
|
||||||
|
printw("Press any key to continue...\n");
|
||||||
|
getch();
|
||||||
|
clear();
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
//Load Woz's ACI
|
//Load Woz's ACI
|
||||||
fp = fopen("WOZACI", "rb");
|
fp = fopen("WOZACI", "rb");
|
||||||
if(fp){
|
if(fp){
|
||||||
fread(memory + 0xC000, 1, 0x100, fp);
|
fread(memory + 0xC000, 1, 0x100, fp);
|
||||||
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
printf("file error\n");
|
fprintf(stderr, "file error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
memcpy(memory + 0xC100, memory + 0xC000, 0x100);
|
memcpy(memory + 0xC100, memory + 0xC000, 0x100);
|
||||||
|
|
||||||
|
@ -155,32 +180,33 @@ int main(){
|
||||||
fp = fopen("WOZMON", "rb");
|
fp = fopen("WOZMON", "rb");
|
||||||
if(fp){
|
if(fp){
|
||||||
fread(memory + 0xFF00, 1, 0x100, fp);
|
fread(memory + 0xFF00, 1, 0x100, fp);
|
||||||
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
printf("file error\n");
|
fprintf(stderr, "file error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
reset_6502(&cpu, read_mem);//Reset the cpu
|
reset_6502(&cpu, read_mem);//Reset the cpu
|
||||||
cpu.cycles = 0;
|
cpu.cycles = 0;
|
||||||
last_cycles = 0;
|
last_cycles = 0;
|
||||||
|
|
||||||
//Initialize the timing
|
//Initialize the timing
|
||||||
gettimeofday(¤t_time, NULL);
|
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
||||||
last_time = current_time.tv_usec + current_time.tv_sec*1000000;
|
last_time = 0;
|
||||||
last_cycle_diff = 0;
|
last_cycle_diff = 0;
|
||||||
next_tape_index = 0;
|
next_tape_index = 0;
|
||||||
|
nodelay(stdscr, 1);
|
||||||
while(1){
|
while(1){
|
||||||
/* Limit the speed of the processor
|
/* Limit the speed of the processor
|
||||||
* based on how many cycles the last
|
* based on how many cycles the last
|
||||||
* instruction took. The 6502 on the
|
* instruction took. The 6502 on the
|
||||||
* Apple 1 was clocked at 1MHz.
|
* Apple 1 was clocked at 1 MHz.
|
||||||
*/
|
*/
|
||||||
if(!DEBUG_STEP){
|
if(!DEBUG_STEP){
|
||||||
do{
|
last_time += last_cycle_diff;
|
||||||
gettimeofday(¤t_time, NULL);
|
if(last_time > 1000){
|
||||||
next_time = current_time.tv_usec + current_time.tv_sec*1000000;
|
Sleep(last_time/1000);
|
||||||
} while(next_time - last_time < last_cycle_diff);
|
last_time -= 1000;
|
||||||
last_time = last_time + last_cycle_diff;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Execute the instruction
|
//Execute the instruction
|
||||||
|
@ -190,26 +216,29 @@ int main(){
|
||||||
//Debugging I/O
|
//Debugging I/O
|
||||||
if(DEBUG_STEP){
|
if(DEBUG_STEP){
|
||||||
memset(str_buffer, 256, 0);
|
memset(str_buffer, 256, 0);
|
||||||
fgets(str_buffer, 256, stdin);
|
echo();
|
||||||
|
getstr(str_buffer);
|
||||||
|
noecho();
|
||||||
temp_char = str_buffer[6];
|
temp_char = str_buffer[6];
|
||||||
str_buffer[6] = (char) 0;
|
str_buffer[6] = (char) 0;
|
||||||
|
|
||||||
if(!strcmp(str_buffer, "resume")){
|
if(!strcmp(str_buffer, "resume")){
|
||||||
DEBUG_STEP = 0;
|
DEBUG_STEP = 0;
|
||||||
gettimeofday(¤t_time, NULL);
|
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
||||||
last_time = current_time.tv_usec + current_time.tv_sec*1000000;
|
last_time = 0;
|
||||||
|
nodelay(stdscr, 1);
|
||||||
} else if(temp_char == ' ' && !strcmp(str_buffer, "tstart")){
|
} else if(temp_char == ' ' && !strcmp(str_buffer, "tstart")){
|
||||||
tape_active = 1;
|
tape_active = 1;
|
||||||
str_buffer[12] = (char) 0;
|
str_buffer[12] = (char) 0;
|
||||||
if(temp_char == ' ' && !strcmp(str_buffer + 7, "write")){
|
if(temp_char == ' ' && !strcmp(str_buffer + 7, "write")){
|
||||||
tape_writing = 1;
|
tape_writing = 1;
|
||||||
printf("WRITING TO TAPE\n");
|
printw("WRITING TO TAPE\n");
|
||||||
}
|
}
|
||||||
str_buffer[11] = (char) 0;
|
str_buffer[11] = (char) 0;
|
||||||
if(temp_char == ' ' && !strcmp(str_buffer + 7, "read")){
|
if(temp_char == ' ' && !strcmp(str_buffer + 7, "read")){
|
||||||
tape_reading = 1;
|
tape_reading = 1;
|
||||||
current_tape_value = 0;
|
current_tape_value = 0;
|
||||||
printf("READING FROM TAPE\n");
|
printw("READING FROM TAPE\n");
|
||||||
}
|
}
|
||||||
tape_index = 0;
|
tape_index = 0;
|
||||||
} else if(temp_char == ' ' && !strcmp(str_buffer, "tstore")){
|
} else if(temp_char == ' ' && !strcmp(str_buffer, "tstore")){
|
||||||
|
@ -231,11 +260,13 @@ int main(){
|
||||||
tape_reading = 0;
|
tape_reading = 0;
|
||||||
} else if(!strcmp(str_buffer, "reset")){
|
} else if(!strcmp(str_buffer, "reset")){
|
||||||
reset_6502(&cpu, read_mem);
|
reset_6502(&cpu, read_mem);
|
||||||
|
} else if(!strcmp(str_buffer, "quit")){
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(temp_char == ' ' && !strcmp(str_buffer, "tload")){
|
if(temp_char == ' ' && !strcmp(str_buffer, "tload")){
|
||||||
str_index = 0;
|
str_index = 0;
|
||||||
while(str_buffer[str_index] != '\n' && str_index < 255){
|
while(str_buffer[str_index] != '\r' && str_buffer[str_index] != '\n' && str_index < 255){
|
||||||
str_index++;
|
str_index++;
|
||||||
}
|
}
|
||||||
str_buffer[str_index] = (char) 0;
|
str_buffer[str_index] = (char) 0;
|
||||||
|
@ -249,15 +280,14 @@ int main(){
|
||||||
}
|
}
|
||||||
|
|
||||||
//Handle keyboard I/O
|
//Handle keyboard I/O
|
||||||
if(!(count%200) && kbhit()){
|
if(!(count%200) && (key_hit = getch()) != ERR){
|
||||||
key_hit = getch();
|
|
||||||
|
|
||||||
if(key_hit == 0x08){//Emulate the backspace character
|
if(key_hit == 0x08){//Emulate the backspace character
|
||||||
memory[0xD010] = 0xDF;
|
memory[0xD010] = 0xDF;
|
||||||
memory[0xD011] |= 0x80;
|
memory[0xD011] |= 0x80;
|
||||||
} else if(key_hit == '~'){//Emulate the control character
|
} else if(key_hit == '~'){//Emulate the control character
|
||||||
while(!kbhit()){}
|
nodelay(stdscr, 0);
|
||||||
key_hit = getch();
|
key_hit = getch();
|
||||||
|
nodelay(stdscr, 1);
|
||||||
if(key_hit == 'd' || key_hit == 'D'){//Ctrl-D
|
if(key_hit == 'd' || key_hit == 'D'){//Ctrl-D
|
||||||
memory[0xD010] = 0x84;
|
memory[0xD010] = 0x84;
|
||||||
memory[0xD011] |= 0x80;
|
memory[0xD011] |= 0x80;
|
||||||
|
@ -270,13 +300,19 @@ int main(){
|
||||||
}
|
}
|
||||||
} else if(key_hit == '|'){
|
} else if(key_hit == '|'){
|
||||||
DEBUG_STEP = 1;
|
DEBUG_STEP = 1;
|
||||||
printf("\n");
|
printw("\n");
|
||||||
|
nodelay(stdscr, 0);
|
||||||
} else {
|
} else {
|
||||||
//Convert lower case characters to upper case
|
//Convert lower case characters to upper case
|
||||||
if(key_hit >= 'a' && key_hit <= 'z'){
|
if(key_hit >= 'a' && key_hit <= 'z'){
|
||||||
key_hit += 'A' - 'a';
|
key_hit += 'A' - 'a';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Replace \n with \r
|
||||||
|
if(key_hit == '\n'){
|
||||||
|
key_hit = '\r';
|
||||||
|
}
|
||||||
|
|
||||||
memory[0xD010] = key_hit|0x80;
|
memory[0xD010] = key_hit|0x80;
|
||||||
memory[0xD011] |= 0x80;
|
memory[0xD011] |= 0x80;
|
||||||
}
|
}
|
||||||
|
@ -304,5 +340,12 @@ int main(){
|
||||||
} else {
|
} else {
|
||||||
last_cycles = cpu.cycles;
|
last_cycles = cpu.cycles;
|
||||||
}
|
}
|
||||||
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printw("Press any key to exit...\n");
|
||||||
|
nodelay(stdscr, 0);
|
||||||
|
getch();
|
||||||
|
|
||||||
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue