add int instruction, make cross-page accesses work

This commit is contained in:
hyenasky 2022-10-26 11:37:27 -06:00 committed by Ry
parent b06f6de79c
commit 7d383cff3c
5 changed files with 144 additions and 17 deletions

View File

@ -7,6 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include "bus.h" #include "bus.h"
#include "cpu.h" #include "cpu.h"
@ -15,6 +16,9 @@
#include "keyboard.h" #include "keyboard.h"
#include "mouse.h" #include "mouse.h"
extern struct timeval rtc_current_time;
extern uint32_t rtc_uptime;
extern fox32_vm_t vm; extern fox32_vm_t vm;
extern disk_controller_t disk_controller; extern disk_controller_t disk_controller;
extern mouse_t mouse; extern mouse_t mouse;
@ -81,6 +85,18 @@ int bus_io_read(void *user, uint32_t *value, uint32_t port) {
break; break;
} }
case 0x80000700 ... 0x80000706: { // RTC port
uint8_t setting = port & 0x000000FF;
switch (setting) {
case 0x06: { // ms since startup
*value = rtc_uptime;
break;
}
}
break;
}
case 0x80001000 ... 0x80002003: { // disk controller port case 0x80001000 ... 0x80002003: { // disk controller port
size_t id = port & 0xFF; size_t id = port & 0xFF;
uint8_t operation = (port & 0x0000F000) >> 8; uint8_t operation = (port & 0x0000F000) >> 8;

113
src/cpu.c
View File

@ -2,6 +2,7 @@
#include <stdnoreturn.h> #include <stdnoreturn.h>
#include <string.h> #include <string.h>
#include <setjmp.h> #include <setjmp.h>
#include <stdlib.h>
#include "cpu.h" #include "cpu.h"
#include "mmu.h" #include "mmu.h"
@ -88,6 +89,7 @@ enum {
OP_LOOP = 0x28, OP_LOOP = 0x28,
OP_RLOOP = 0x29, OP_RLOOP = 0x29,
OP_RET = 0x2A, OP_RET = 0x2A,
OP_INT = 0x2C,
OP_TLB = 0x2D, OP_TLB = 0x2D,
OP_DEC = 0x31, OP_DEC = 0x31,
OP_REM = 0x32, OP_REM = 0x32,
@ -96,7 +98,7 @@ enum {
OP_IREM = 0x35, OP_IREM = 0x35,
OP_RTA = 0x39, OP_RTA = 0x39,
OP_RETI = 0x3A, OP_RETI = 0x3A,
OP_FLP = 0x3D OP_FLP = 0x3D,
}; };
enum { enum {
@ -235,6 +237,7 @@ static const asm_iinfo_t asm_iinfos[256] = {
[OP_LOOP ] = { "LOOP ", 1 }, [OP_LOOP ] = { "LOOP ", 1 },
[OP_RLOOP] = { "RLOOP", 1 }, [OP_RLOOP] = { "RLOOP", 1 },
[OP_RET ] = { "RET ", 0 }, [OP_RET ] = { "RET ", 0 },
[OP_INT ] = { "INT ", 1 },
[OP_TLB ] = { "TLB ", 1 }, [OP_TLB ] = { "TLB ", 1 },
[OP_DEC ] = { "DEC ", 1 }, [OP_DEC ] = { "DEC ", 1 },
[OP_REM ] = { "REM ", 2 }, [OP_REM ] = { "REM ", 2 },
@ -475,8 +478,78 @@ static uint8_t *vm_findmemory(vm_t *vm, uint32_t address, uint32_t size, bool wr
} }
} }
static uint32_t vm_read_across(vm_t *vm, uint32_t address, int size) {
uint32_t result = 0;
int shift = 0;
// read the first page
int bytes = 0x1000 - (address&0xFFF);
uint8_t *ptr = vm_findmemory(vm, address, bytes, false);
while (bytes) {
result |= (*ptr<<shift);
shift += 8;
ptr++;
bytes--;
}
// read the second page
bytes = (address+size)&0xFFF;
address = (address+size)&0xFFFFF000;
ptr = vm_findmemory(vm, address, bytes, false);
while (bytes) {
result |= (*ptr<<shift);
shift += 8;
ptr++;
bytes--;
}
return result;
}
void vm_write_across(vm_t *vm, uint32_t address, int size, uint32_t value) {
// write the first page
int bytes = 0x1000 - (address&0xFFF);
uint8_t *ptr = vm_findmemory(vm, address, bytes, true);
while (bytes) {
*ptr = value&0xFF;
value >>= 8;
ptr++;
bytes--;
}
// write the second page
bytes = (address+size)&0xFFF;
address = (address+size)&0xFFFFF000;
ptr = vm_findmemory(vm, address, bytes, true);
while (bytes) {
*ptr = value&0xFF;
value >>= 8;
ptr++;
bytes--;
}
}
#define VM_READ_BODY(_ptr_get, _size) \ #define VM_READ_BODY(_ptr_get, _size) \
return _ptr_get(vm_findmemory(vm, address, _size, false)); if ((address&0xFFFFF000) == ((address+_size-1)&0xFFFFF000)) { \
return _ptr_get(vm_findmemory(vm, address, _size, false)); \
} else { \
return vm_read_across(vm, address, _size); \
}
static uint8_t vm_read8(vm_t *vm, uint32_t address) { static uint8_t vm_read8(vm_t *vm, uint32_t address) {
VM_READ_BODY(ptr_get8, SIZE8) VM_READ_BODY(ptr_get8, SIZE8)
@ -489,7 +562,12 @@ static uint32_t vm_read32(vm_t *vm, uint32_t address) {
} }
#define VM_WRITE_BODY(_ptr_set, _size) \ #define VM_WRITE_BODY(_ptr_set, _size) \
_ptr_set(vm_findmemory(vm, address, _size, true), value); if ((address&0xFFFFF000) == ((address+_size-1)&0xFFFFF000)) { \
return _ptr_set(vm_findmemory(vm, address, _size, true), value); \
} else { \
return vm_write_across(vm, address, _size, value); \
}
static void vm_write8(vm_t *vm, uint32_t address, uint8_t value) { static void vm_write8(vm_t *vm, uint32_t address, uint8_t value) {
VM_WRITE_BODY(ptr_set8, SIZE8) VM_WRITE_BODY(ptr_set8, SIZE8)
@ -502,7 +580,8 @@ static void vm_write32(vm_t *vm, uint32_t address, uint32_t value) {
} }
#define VM_PUSH_BODY(_vm_write, _size) \ #define VM_PUSH_BODY(_vm_write, _size) \
_vm_write(vm, vm->pointer_stack -= _size, value); _vm_write(vm, vm->pointer_stack - _size, value); \
vm->pointer_stack -= _size;
static void vm_push8(vm_t *vm, uint8_t value) { static void vm_push8(vm_t *vm, uint8_t value) {
VM_PUSH_BODY(vm_write8, SIZE8) VM_PUSH_BODY(vm_write8, SIZE8)
@ -515,8 +594,9 @@ static void vm_push32(vm_t *vm, uint32_t value) {
} }
#define VM_POP_BODY(_vm_read, _size) \ #define VM_POP_BODY(_vm_read, _size) \
uint32_t pointer_stack_prev = vm->pointer_stack; \ uint32_t result = _vm_read(vm, vm->pointer_stack); \
return _vm_read(vm, (vm->pointer_stack += _size, pointer_stack_prev)); vm->pointer_stack += _size; \
return result;
static uint8_t vm_pop8(vm_t *vm) { static uint8_t vm_pop8(vm_t *vm) {
VM_POP_BODY(vm_read8, SIZE8) VM_POP_BODY(vm_read8, SIZE8)
@ -872,6 +952,9 @@ static void vm_execute(vm_t *vm) {
VM_PRELUDE_0(); VM_PRELUDE_0();
vm_flags_set(vm, vm_pop8(vm)); vm_flags_set(vm, vm_pop8(vm));
vm->pointer_instr_mut = vm_pop32(vm); vm->pointer_instr_mut = vm_pop32(vm);
if (vm->flag_swap_sp) {
vm->pointer_stack = vm_pop32(vm);
}
break; break;
}; };
@ -997,6 +1080,14 @@ static void vm_execute(vm_t *vm) {
vm->mmu_enabled = false; vm->mmu_enabled = false;
break; break;
}; };
case OP(SZ_WORD, OP_INT): {
VM_PRELUDE_1(SIZE32);
uint32_t intr = vm_source32(vm, instr.source);
vm->pointer_instr = vm->pointer_instr_mut;
fox32_raise(vm, intr);
vm->pointer_instr_mut = vm->pointer_instr;
break;
};
case OP(SZ_WORD, OP_TLB): { case OP(SZ_WORD, OP_TLB): {
VM_PRELUDE_1(SIZE32); VM_PRELUDE_1(SIZE32);
set_and_flush_tlb(vm_source32(vm, instr.source)); set_and_flush_tlb(vm_source32(vm, instr.source));
@ -1022,14 +1113,18 @@ static err_t vm_step(vm_t *vm) {
vm_execute(vm); vm_execute(vm);
return FOX32_ERR_OK; return FOX32_ERR_OK;
} }
static err_t vm_resume(vm_t *vm, uint32_t count) { static err_t vm_resume(vm_t *vm, uint32_t count, uint32_t *executed) {
if (setjmp(vm->panic_jmp) != 0) { if (setjmp(vm->panic_jmp) != 0) {
return vm->halted = true, vm->panic_err; return vm->halted = true, vm->panic_err;
} }
vm->halted = false;
uint32_t remaining = count; uint32_t remaining = count;
while (!vm->halted && remaining > 0) { while (!vm->halted && remaining > 0) {
vm_execute(vm); vm_execute(vm);
remaining -= 1; remaining -= 1;
*executed += 1;
} }
return FOX32_ERR_OK; return FOX32_ERR_OK;
} }
@ -1143,8 +1238,8 @@ void fox32_init(fox32_vm_t *vm) {
fox32_err_t fox32_step(fox32_vm_t *vm) { fox32_err_t fox32_step(fox32_vm_t *vm) {
return vm_step(vm); return vm_step(vm);
} }
fox32_err_t fox32_resume(fox32_vm_t *vm, uint32_t count) { fox32_err_t fox32_resume(fox32_vm_t *vm, uint32_t count, uint32_t *executed) {
return vm_resume(vm, count); return vm_resume(vm, count, executed);
} }
fox32_err_t fox32_raise(fox32_vm_t *vm, uint16_t vector) { fox32_err_t fox32_raise(fox32_vm_t *vm, uint16_t vector) {
return vm_raise(vm, vector); return vm_raise(vm, vector);

View File

@ -5,7 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <setjmp.h> #include <setjmp.h>
#define FOX32_CPU_HZ 33000000 #define FOX32_CPU_HZ 10000000
#define FOX32_MEMORY_RAM 0x04000000 // 64 MiB #define FOX32_MEMORY_RAM 0x04000000 // 64 MiB
#define FOX32_MEMORY_ROM 0x00080000 // 512 KiB #define FOX32_MEMORY_ROM 0x00080000 // 512 KiB
@ -77,7 +77,7 @@ typedef struct {
void fox32_init(fox32_vm_t *vm); void fox32_init(fox32_vm_t *vm);
fox32_err_t fox32_step(fox32_vm_t *vm); fox32_err_t fox32_step(fox32_vm_t *vm);
fox32_err_t fox32_resume(fox32_vm_t *vm, uint32_t count); fox32_err_t fox32_resume(fox32_vm_t *vm, uint32_t count, uint32_t *executed);
fox32_err_t fox32_raise(fox32_vm_t *vm, uint16_t vector); fox32_err_t fox32_raise(fox32_vm_t *vm, uint16_t vector);
fox32_err_t fox32_recover(fox32_vm_t *vm, fox32_err_t err); fox32_err_t fox32_recover(fox32_vm_t *vm, fox32_err_t err);

View File

@ -6,6 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include "bus.h" #include "bus.h"
#include "cpu.h" #include "cpu.h"
@ -30,6 +31,9 @@ uint32_t tick_end;
int ticks = 0; int ticks = 0;
bool done = false; bool done = false;
struct timeval rtc_current_time;
uint32_t rtc_uptime;
void main_loop(void); void main_loop(void);
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -95,17 +99,26 @@ void main_loop(void) {
fox32_err_t error = FOX32_ERR_OK; fox32_err_t error = FOX32_ERR_OK;
for (int i = 0; i < dt; i++) { for (int i = 0; i < dt; i++) {
rtc_uptime += 1;
gettimeofday(&rtc_current_time, 0);
int cycles_left = cycles_per_tick; int cycles_left = cycles_per_tick;
if (i == dt - 1) if (i == dt - 1)
cycles_left += extra_cycles; cycles_left += extra_cycles;
error = fox32_resume(&vm, cycles_left); while (cycles_left > 0) {
uint32_t executed = 0;
error = fox32_resume(&vm, cycles_left, &executed);
if (error != FOX32_ERR_OK) { if (error != FOX32_ERR_OK) {
//puts(fox32_strerr(error)); //puts(fox32_strerr(error));
error = fox32_recover(&vm, error); error = fox32_recover(&vm, error);
//if (error != FOX32_ERR_OK) if (error != FOX32_ERR_OK)
//puts(fox32_strerr(error)); break;
}
cycles_left -= executed;
} }
} }

View File

@ -15,13 +15,16 @@ mmu_page_t mmu_tlb[64];
extern fox32_vm_t vm; extern fox32_vm_t vm;
uint32_t replacement_index = 0;
static size_t find_free_tlb_entry_index() { static size_t find_free_tlb_entry_index() {
for (size_t i = 0; i < 64; i++) { for (size_t i = 0; i < 64; i++) {
if (!mmu_tlb[i].present) { if (!mmu_tlb[i].present) {
return i; return i;
} }
} }
return 0;
return (replacement_index++)&63;
} }
void set_and_flush_tlb(uint32_t virtual_address) { void set_and_flush_tlb(uint32_t virtual_address) {