Cross platform

This commit is contained in:
Benjamin Jones 2019-09-03 23:25:58 -07:00
parent 9822aa07cd
commit a86f9e23d3
2 changed files with 98 additions and 46 deletions

15
cpu.c
View File

@ -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
View File

@ -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(&current_time, NULL); clock_gettime(CLOCK_MONOTONIC, &current_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(&current_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(&current_time, NULL); clock_gettime(CLOCK_MONOTONIC, &current_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();
} }