Compare commits
2 Commits
68b7667725
...
8e1f83ab31
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e1f83ab31 | |||
| fb3efc77c3 |
@@ -5,7 +5,8 @@ sources = files(
|
||||
'src/emu.c',
|
||||
'src/memory.c',
|
||||
'src/instruction.c',
|
||||
'src/util.c'
|
||||
'src/util.c',
|
||||
'src/device.c'
|
||||
)
|
||||
|
||||
asmSources = files(
|
||||
|
||||
32
src/device.c
32
src/device.c
@@ -2,11 +2,37 @@
|
||||
|
||||
Device* createDevice(
|
||||
const char* name,
|
||||
void (*sendToDevice)(uint16_t number),
|
||||
uint16_t (*receiveFromDevice)(),
|
||||
void (*update)()
|
||||
void (*update)(Device* self)
|
||||
) {
|
||||
Device* new = malloc(sizeof(Device));
|
||||
if (!new)
|
||||
return NULL;
|
||||
|
||||
size_t nameLen = strlen(name) + 1;
|
||||
nameLen = nameLen < 32 ? nameLen : 32;
|
||||
|
||||
memcpy(new->name, name, nameLen);
|
||||
new->name[nameLen] = 0;
|
||||
|
||||
new->update = update;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
uint16_t deviceRead(Device* self) {
|
||||
if (self->inPos == 0)
|
||||
return 0;
|
||||
|
||||
return self->in[--self->inPos];
|
||||
}
|
||||
|
||||
void deviceSend(Device* self, uint16_t value) {
|
||||
if (self->outPos == DEVICE_BUFFER_LENGTH)
|
||||
return;
|
||||
|
||||
self->out[self->outPos++] = value;
|
||||
}
|
||||
|
||||
bool deviceCanRead(Device* self) {
|
||||
return self->inPos > 0;
|
||||
}
|
||||
28
src/device.h
28
src/device.h
@@ -1,18 +1,30 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
#define DEVICE_BUFFER_LENGTH 128
|
||||
|
||||
typedef struct Device Device;
|
||||
struct Device {
|
||||
char name[32];
|
||||
|
||||
void (*sendToDevice)(uint16_t number);
|
||||
uint16_t (*receiveFromDevice)();
|
||||
void (*update)();
|
||||
} Device;
|
||||
uint16_t in[DEVICE_BUFFER_LENGTH];
|
||||
uint8_t inPos;
|
||||
|
||||
uint16_t out[DEVICE_BUFFER_LENGTH];
|
||||
uint8_t outPos;
|
||||
|
||||
void (*update)(Device* self);
|
||||
};
|
||||
|
||||
Device* createDevice(
|
||||
const char* name,
|
||||
void (*sendToDevice)(uint16_t number),
|
||||
uint16_t (*receiveFromDevice)(),
|
||||
void (*update)()
|
||||
void (*update)(Device* self)
|
||||
);
|
||||
|
||||
uint16_t deviceRead(Device* self);
|
||||
void deviceSend(Device* self, uint16_t value);
|
||||
bool deviceCanRead(Device* self);
|
||||
62
src/emu.c
62
src/emu.c
@@ -1,9 +1,7 @@
|
||||
#include "emu.h"
|
||||
|
||||
static inline Instruction fetchInst(Emulator* emu) {
|
||||
Instruction inst = decodeInstruction(emu->mem, &emu->pc);
|
||||
printf("%s\n", instructionToCStr(inst));
|
||||
return inst;
|
||||
return decodeInstruction(emu->mem, &emu->pc);
|
||||
}
|
||||
|
||||
static inline void updateFlagsRegister(Emulator* emu, int32_t value) {
|
||||
@@ -16,6 +14,17 @@ static inline void updateFlagsRegister(Emulator* emu, int32_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void updateDevices(Emulator* emu) {
|
||||
for (size_t i = 0; i < MAX_DEVICES; i++) {
|
||||
Device* device = emu->devices[i];
|
||||
if (!device) continue;
|
||||
|
||||
if (device->update) {
|
||||
device->update(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startEmulator(Emulator* emu) {
|
||||
static void* dispatchTable[] = {
|
||||
&&MOV,
|
||||
@@ -32,15 +41,16 @@ void startEmulator(Emulator* emu) {
|
||||
&&JIZ,
|
||||
&&CALL,
|
||||
&&RET,
|
||||
&&SYS,
|
||||
&&PORT,
|
||||
&&HLT
|
||||
};
|
||||
|
||||
emu->halted = false;
|
||||
Instruction inst;
|
||||
|
||||
#define DISPATCH() inst = fetchInst(emu); \
|
||||
goto *dispatchTable[inst.opcode];
|
||||
#define DISPATCH() updateDevices(emu); \
|
||||
inst = fetchInst(emu); \
|
||||
goto *dispatchTable[inst.opcode]
|
||||
|
||||
DISPATCH();
|
||||
|
||||
@@ -133,8 +143,39 @@ void startEmulator(Emulator* emu) {
|
||||
emu->pc = ((uint32_t*)emu->mem->data)[++emu->sp];
|
||||
DISPATCH();
|
||||
}
|
||||
SYS: {
|
||||
// TODO
|
||||
PORT: {
|
||||
uint16_t port = emu->regs[inst.operands[0]];
|
||||
if (port >= MAX_DEVICES) {
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
uint8_t direction = inst.operands[2];
|
||||
|
||||
Device* device = emu->devices[port];
|
||||
if (!device) {
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
if (direction == 0) {
|
||||
uint16_t value = emu->regs[inst.operands[1]];
|
||||
|
||||
if (device->inPos == DEVICE_BUFFER_LENGTH) {
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
device->in[device->inPos] = value;
|
||||
device->inPos++;
|
||||
} else {
|
||||
if (device->outPos == 0) {
|
||||
emu->regs[inst.operands[1]] = 0;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
emu->regs[inst.operands[1]] = device->out[device->outPos-1];
|
||||
if (device->outPos > 0)
|
||||
device->outPos--;
|
||||
}
|
||||
|
||||
DISPATCH();
|
||||
}
|
||||
HLT: {
|
||||
@@ -170,3 +211,8 @@ void freeEmulator(Emulator* emu) {
|
||||
freeMemory(emu->mem);
|
||||
free(emu);
|
||||
}
|
||||
|
||||
void installDevice(Emulator* emu, Device* device, uint8_t deviceNumber) {
|
||||
assert(deviceNumber < MAX_DEVICES);
|
||||
emu->devices[deviceNumber] = device;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "memory.h"
|
||||
#include "device.h"
|
||||
|
||||
@@ -11,10 +12,13 @@
|
||||
#define FLAG_NEGATIVE (1 << 1)
|
||||
#define FLAG_OVERFLOW (1 << 2)
|
||||
|
||||
#define MAX_DEVICES 64
|
||||
|
||||
// -- TYPES -- //
|
||||
typedef struct {
|
||||
uint16_t regs[REG_MAX];
|
||||
Memory* mem;
|
||||
Device* devices[MAX_DEVICES];
|
||||
|
||||
uint32_t pc;
|
||||
uint32_t ihp;
|
||||
@@ -27,3 +31,4 @@ typedef struct {
|
||||
Emulator* initEmulator(uint32_t memorySize);
|
||||
void freeEmulator(Emulator* emu);
|
||||
void startEmulator(Emulator* emu);
|
||||
void installDevice(Emulator* emu, Device* device, uint8_t deviceNumber);
|
||||
13
src/main.c
13
src/main.c
@@ -9,10 +9,17 @@ int main() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
RomFile* romFile = readProgramFromFile("../test.bin");
|
||||
memoryLoadProgram(emu->mem, romFile->instructions, romFile->header.numInstructions);
|
||||
Instruction program[] = {
|
||||
{INST_MVI, {REG_A}, 0, true},
|
||||
{INST_MVI, {REG_B}, 123, true},
|
||||
{INST_PORT, {REG_A, REG_B, 0}, 0, false},
|
||||
{INST_PORT, {REG_A, REG_B, 1}, 0, false},
|
||||
{INST_HLT, {}, 0, false}
|
||||
};
|
||||
|
||||
//startEmulator(emu);
|
||||
memoryLoadProgram(emu->mem, program, sizeof(program)/sizeof(program[0]));
|
||||
|
||||
startEmulator(emu);
|
||||
freeEmulator(emu);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -71,6 +71,7 @@ Instruction decodeInstruction(Memory* m, uint32_t* pc) {
|
||||
uint8_t offset = 0;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
switch (opTypes[i]) {
|
||||
case OP_IMM4:
|
||||
case OP_REG: {
|
||||
// get the data at the current offset, and grab the 4 bits that are there with a bitwise
|
||||
// "and" operator
|
||||
|
||||
Reference in New Issue
Block a user