Fix BASIC
Fix cycle waiting Fix warnings
This commit is contained in:
1 parent
8101cc3f62
commit
a5e30a7b28
14 files changed
+114
-61
No files matched your search
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"msbasic",
|
||||||
|
"Wmissing",
|
||||||
|
"Wunused"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -10,12 +10,18 @@ enable_language(C)
|
|||||||
|
|
||||||
add_executable(${CMAKE_PROJECT_NAME})
|
add_executable(${CMAKE_PROJECT_NAME})
|
||||||
|
|
||||||
|
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE _POSIX_C_SOURCE=200809L)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE /W4)
|
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE /W4)
|
||||||
else()
|
else()
|
||||||
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic)
|
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
|
||||||
|
-include ${CMAKE_CURRENT_SOURCE_DIR}/inc/diag.h
|
||||||
|
)
|
||||||
|
|
||||||
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
|
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
|
||||||
"src/main.c"
|
"src/main.c"
|
||||||
"src/ram.c"
|
"src/ram.c"
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#define DIAG_STRINGIFY_(x) #x
|
||||||
|
#define DIAG_STRINGIFY(x) DIAG_STRINGIFY_(x)
|
||||||
|
|
||||||
|
#define DIAG_DO_PRAGMA(x) _Pragma(DIAG_STRINGIFY(x))
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
|
||||||
|
#define DIAG_PUSH() DIAG_DO_PRAGMA(clang diagnostic push)
|
||||||
|
|
||||||
|
#define DIAG_POP() DIAG_DO_PRAGMA(clang diagnostic pop)
|
||||||
|
|
||||||
|
#define DIAG_IGNORE(w) DIAG_DO_PRAGMA(clang diagnostic ignored w)
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
|
||||||
|
#define DIAG_PUSH() DIAG_DO_PRAGMA(GCC diagnostic push)
|
||||||
|
|
||||||
|
#define DIAG_POP() DIAG_DO_PRAGMA(GCC diagnostic pop)
|
||||||
|
|
||||||
|
#define DIAG_IGNORE(w) DIAG_DO_PRAGMA(GCC diagnostic ignored w)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define DIAG_PUSH()
|
||||||
|
#define DIAG_POP()
|
||||||
|
#define DIAG_IGNORE(w)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define IO_SIZE (1 * 1024) // 1KiB
|
#define IO_SIZE (1 * 1024) // 1KiB
|
||||||
#define IO_BASE (47 * 1024) // 47KiB RAM, hard coded, 0xBC00
|
#define IO_BASE (47 * 1024) // 47KiB RAM, hard coded, 0xBC00
|
||||||
|
|
||||||
#define SCREEN_ADDRESS 0
|
#define SCREEN_ADDRESS 0
|
||||||
|
|||||||
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
#ifndef MEMORY_MAP_H
|
#ifndef MEMORY_MAP_H
|
||||||
#define MEMORY_MAP_H
|
#define MEMORY_MAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "ram.h"
|
#include "ram.h"
|
||||||
#include "rom.h"
|
#include "rom.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom);
|
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom);
|
||||||
void writeMemory(uint16_t address, uint8_t value, uint8_t *ram);
|
void writeMemory(uint16_t address, uint8_t value, uint8_t *ram);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef RAM_H
|
#ifndef RAM_H
|
||||||
#define RAM_H
|
#define RAM_H
|
||||||
|
|
||||||
#include "stdint.h"
|
#include <stdint.h>
|
||||||
|
|
||||||
#define RAM_SIZE (64 * 1024) // 55KiB
|
#define RAM_SIZE (64 * 1024) // 64KiB, read/write to IO is ignored, ROM can be banked
|
||||||
#define RAM_BASE (0x00) // 0
|
#define RAM_BASE (0x00) // 0
|
||||||
|
|
||||||
int createRAM(uint8_t **ram);
|
int createRAM(uint8_t **ram);
|
||||||
void destroyRAM(uint8_t *ram);
|
void destroyRAM(uint8_t *ram);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define ROM_SIZE (16 * 1024) // 16KiB
|
#define ROM_SIZE (16 * 1024) // 16KiB
|
||||||
#define ROM_BASE (48 * 1024) // 47KiB RAM + 1KiB IO, hard coded
|
#define ROM_BASE (48 * 1024) // 47KiB RAM + 1KiB IO, hard coded
|
||||||
|
|
||||||
extern uint8_t rom[ROM_SIZE];
|
extern uint8_t rom[ROM_SIZE];
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ USR := GORESTART ; XXX
|
|||||||
; constants
|
; constants
|
||||||
SPACE_FOR_GOSUB := $3E
|
SPACE_FOR_GOSUB := $3E
|
||||||
STACK_TOP := $FA
|
STACK_TOP := $FA
|
||||||
WIDTH := 40
|
WIDTH := 80
|
||||||
WIDTH2 := 30
|
WIDTH2 := 30
|
||||||
RAMSTART2 := $0400
|
RAMSTART2 := $0400
|
||||||
+8
-1
@@ -200,6 +200,11 @@ L4098:
|
|||||||
lda #$01
|
lda #$01
|
||||||
sta INPUTBUFFER-3
|
sta INPUTBUFFER-3
|
||||||
sta INPUTBUFFER-4
|
sta INPUTBUFFER-4
|
||||||
|
.endif
|
||||||
|
.ifdef CONFIG_INPUTBUFFER_0200
|
||||||
|
lda #$01
|
||||||
|
sta INPUTBUFFER-3
|
||||||
|
sta INPUTBUFFER-4
|
||||||
.endif
|
.endif
|
||||||
ldx #TEMPST
|
ldx #TEMPST
|
||||||
stx TEMPPT
|
stx TEMPPT
|
||||||
@@ -226,7 +231,9 @@ L4098:
|
|||||||
.ifndef AIM65
|
.ifndef AIM65
|
||||||
.ifndef SYM1
|
.ifndef SYM1
|
||||||
cmp #$41
|
cmp #$41
|
||||||
beq PR_WRITTEN_BY
|
bne SKIPPED
|
||||||
|
jmp PR_WRITTEN_BY
|
||||||
|
SKIPPED:
|
||||||
.endif
|
.endif
|
||||||
.endif
|
.endif
|
||||||
tay
|
tay
|
||||||
|
|||||||
@@ -58,10 +58,10 @@ static void doSBC(CPU *cpu, uint8_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initCPU(CPU *cpu) {
|
void initCPU(CPU *cpu) {
|
||||||
#pragma clang diagnostic push
|
DIAG_PUSH();
|
||||||
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
DIAG_IGNORE("-Wmissing-field-initializers");
|
||||||
*cpu = (CPU){0x0000, 0xFF};
|
*cpu = (CPU){0x0000, 0xFF};
|
||||||
#pragma clang diagnostic pop
|
DIAG_POP();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetCPU(CPU *cpu, uint8_t *rom) {
|
void resetCPU(CPU *cpu, uint8_t *rom) {
|
||||||
|
|||||||
+41
-38
@@ -1,18 +1,23 @@
|
|||||||
#include "cpu.h"
|
|
||||||
#include "ram.h"
|
|
||||||
#include "rom.h"
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define MACHINE_SPEED_HZ 1e6 // 1 MHz;
|
#include "cpu.h"
|
||||||
|
#include "ram.h"
|
||||||
|
#include "rom.h"
|
||||||
|
|
||||||
static struct termios orig_termios;
|
#define MACHINE_SPEED_HZ 1000000ULL // 1 MHz;
|
||||||
static struct timespec sleepTime;
|
#define SYNC_CYCLES 100
|
||||||
|
|
||||||
|
struct termios orig_termios;
|
||||||
|
struct timespec emulationStart;
|
||||||
|
|
||||||
|
uint64_t totalCycles = 0;
|
||||||
|
uint64_t lastSyncCycles = 0;
|
||||||
|
|
||||||
void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); }
|
void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); }
|
||||||
|
|
||||||
@@ -36,11 +41,13 @@ void set_nonblocking_input(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
uint8_t *ram = NULL;
|
||||||
|
CPU cpu;
|
||||||
|
|
||||||
printf("6502PC Emulator with MS Basic\n");
|
printf("6502PC Emulator with MS Basic\n");
|
||||||
printf("CTRL + G to exit\n");
|
printf("CTRL + G to exit\n");
|
||||||
|
|
||||||
uint8_t *ram = NULL;
|
clock_gettime(CLOCK_MONOTONIC, &emulationStart);
|
||||||
CPU cpu;
|
|
||||||
|
|
||||||
set_nonblocking_input();
|
set_nonblocking_input();
|
||||||
|
|
||||||
@@ -51,44 +58,40 @@ int main(void) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DEBUG */
|
|
||||||
|
|
||||||
// FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_functional_test.bin", "rb");
|
|
||||||
// FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_decimal_test.bin", "rb");
|
|
||||||
// FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/6502_65C02_functional_tests/6502_functional_test.bin", "rb");
|
|
||||||
// FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/6502_65C02_functional_tests/6502_decimal_test.bin", "rb");
|
|
||||||
/*
|
|
||||||
if (!fp) {
|
|
||||||
perror("fopen");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fread(ram, 1, RAM_SIZE, fp);
|
|
||||||
if (ferror(fp)) {
|
|
||||||
perror("fread");
|
|
||||||
fclose(fp);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* DEBUG END*/
|
|
||||||
|
|
||||||
initCPU(&cpu);
|
initCPU(&cpu);
|
||||||
resetCPU(&cpu, rom);
|
resetCPU(&cpu, rom);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
uint8_t sleep = runCycle(&cpu, ram, rom);
|
uint8_t cycles = runCycle(&cpu, ram, rom);
|
||||||
if (sleep == 1) {
|
totalCycles += cycles;
|
||||||
|
|
||||||
|
// No 1 cycle instruction exists
|
||||||
|
if (cycles == 1) {
|
||||||
printf("Illegal opcode $%02X at $%04X "
|
printf("Illegal opcode $%02X at $%04X "
|
||||||
"A=$%02X X=$%02X Y=$%02X SP=$%02X\n",
|
"A=$%02X X=$%02X Y=$%02X SP=$%02X\n",
|
||||||
ram[cpu.ProgrammeCounter - 1], cpu.ProgrammeCounter - 1, cpu.Accumulator, cpu.X, cpu.Y, cpu.StackPointer);
|
ram[cpu.ProgrammeCounter - 1], cpu.ProgrammeCounter - 1, cpu.Accumulator, cpu.X, cpu.Y, cpu.StackPointer);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
sleepTime.tv_sec = 0;
|
|
||||||
sleepTime.tv_nsec = sleep * (1000 / MACHINE_SPEED_HZ);
|
// Sleep if batch is full
|
||||||
nanosleep(&sleepTime, NULL);
|
if (totalCycles - lastSyncCycles >= SYNC_CYCLES) {
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
uint64_t elapsed_ns =
|
||||||
|
(uint64_t)(now.tv_sec - emulationStart.tv_sec) * 1000000000ULL + (uint64_t)(now.tv_nsec - emulationStart.tv_nsec);
|
||||||
|
uint64_t target_ns = totalCycles * 1000000000ULL / MACHINE_SPEED_HZ;
|
||||||
|
|
||||||
|
if (target_ns > elapsed_ns) {
|
||||||
|
uint64_t wait_ns = target_ns - elapsed_ns;
|
||||||
|
|
||||||
|
struct timespec wait = {.tv_sec = wait_ns / 1000000000ULL, .tv_nsec = wait_ns % 1000000000ULL};
|
||||||
|
|
||||||
|
nanosleep(&wait, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSyncCycles = totalCycles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyRAM(ram);
|
destroyRAM(ram);
|
||||||
|
|||||||
+5
-2
@@ -1,13 +1,16 @@
|
|||||||
#include "memoryMap.h"
|
#include "memoryMap.h"
|
||||||
|
|
||||||
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
|
uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
|
||||||
if ((address < RAM_SIZE && address < IO_BASE) || address >= ROM_BASE) {
|
// RAM/ROM
|
||||||
|
if (address < IO_BASE || address >= ROM_BASE) {
|
||||||
if (address >= ROM_BASE && ram[IO_BASE + ROM_BANKED_OUT] == 0) {
|
if (address >= ROM_BASE && ram[IO_BASE + ROM_BANKED_OUT] == 0) {
|
||||||
return rom[address - ROM_BASE];
|
return rom[address - ROM_BASE];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ram[address];
|
return ram[address];
|
||||||
} else {
|
}
|
||||||
|
// I/O
|
||||||
|
else {
|
||||||
uint16_t _address = address - IO_BASE;
|
uint16_t _address = address - IO_BASE;
|
||||||
switch (_address) {
|
switch (_address) {
|
||||||
case KEYBOARD_ADDRESS: {
|
case KEYBOARD_ADDRESS: {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#include "ram.h"
|
#include "ram.h"
|
||||||
|
|
||||||
#include "io.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
int createRAM(uint8_t **ram) {
|
int createRAM(uint8_t **ram) {
|
||||||
*ram = (uint8_t *)malloc(RAM_SIZE);
|
*ram = (uint8_t *)malloc(RAM_SIZE);
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
#include "rom.h"
|
#include "rom.h"
|
||||||
|
|
||||||
#include "io.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
uint8_t rom[ROM_SIZE] = {0};
|
uint8_t rom[ROM_SIZE] = {0};
|
||||||
|
|
||||||
void initRom(uint8_t *rom) {
|
void initRom(uint8_t *rom) {
|
||||||
FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/msbasic/tmp/kilian.bin", "rb");
|
FILE *fp = fopen("msbasic/tmp/kilian.bin", "rb");
|
||||||
|
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
perror("fopen");
|
perror("fopen");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DIAG_PUSH();
|
||||||
|
DIAG_IGNORE("-Wunused-result");
|
||||||
fread(rom, 1, ROM_SIZE, fp);
|
fread(rom, 1, ROM_SIZE, fp);
|
||||||
|
DIAG_POP();
|
||||||
if (ferror(fp)) {
|
if (ferror(fp)) {
|
||||||
perror("fread");
|
perror("fread");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -22,8 +25,4 @@ void initRom(uint8_t *rom) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
/* Reset Vector, BASIC at DF02 */
|
|
||||||
//rom[0xFFFC - ROM_BASE] = 0x02; // Lower byte base of ROM
|
|
||||||
//rom[0xFFFD - ROM_BASE] = 0xDF; // Upper byte of base of ROM
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user