Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding VCD file import/export #33

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,25 @@
#####################################################################
BIN := emu

CFLAGS += -O2
OPTIM=g
CFLAGS += -O$(OPTIM)
CFLAGS += -pipe
CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -Wshadow

# Uncomment to activate LTO
#CFLAGS += -flto
ifeq ($(USE_SWITCH_DISPATCH), 1)
CFLAGS += -DUSE_SWITCH_DISPATCH
endif

ifdef CYCLES_PER_INSTR
CFLAGS += -DCYCLES_PER_INSTR=$(CYCLES_PER_INSTR)
endif

# activate LTO
ifeq ($(USE_LTO), 1)
CFLAGS += -flto -DUSE_LTO=$(USE_LTO)
endif

CFLAGS += $(EXTRA)

LDLIBS += -lcurses

Expand Down
114 changes: 75 additions & 39 deletions core.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "emu8051.h"

static void serial_tx(struct em8051 *aCPU) {
Expand All @@ -52,7 +54,6 @@ static void serial_tx(struct em8051 *aCPU) {
}
}


static void timer_tick(struct em8051 *aCPU)
{
uint8_t increment;
Expand Down Expand Up @@ -445,20 +446,38 @@ void handle_interrupts(struct em8051 *aCPU)
aCPU->int_sp[hi] = aCPU->mSFR[REG_SP];
}

void execute_current_opcode(struct em8051 *aCPU) {
#if USE_SWITCH_DISPATCH
aCPU->mTickDelay = do_op(aCPU);
#else // USE_SWITCH_DISPATCH
assert(aCPU->mPC <= aCPU->mCodeMemMaxIdx);
uint16_t addr = aCPU->mPC;
uint8_t opcode = aCPU->mCodeMem[addr];
aCPU->mTickDelay = aCPU->op[opcode](aCPU);
#endif // USE_SWITCH_DISPATCH
}

bool tick(struct em8051 *aCPU)
{
uint8_t v;
bool ticked = false;

if (aCPU->mTickDelay)
{
aCPU->mTickDelay--;
aCPU->mTickDelay--; // Still executing the current instruction
aCPU->first_cycle = false;
timer_tick(aCPU); // execute timers

// If we are now in the last cycle for the instruction, update PC
if (aCPU->mTickDelay == 0) aCPU->mPC = aCPU->mPCSaved;

return true;
}

// Test for Power Down
if (aCPU->mTickDelay == 0 && (aCPU->mSFR[REG_PCON]) & 0x02) {
aCPU->mTickDelay = 1;
return 1;
bool is_powerdown = (aCPU->mSFR[REG_PCON]) & 0x02;
if (is_powerdown) {
return false; // Nothing happens, not even timers
}

// Interrupts are sent if the following cases are not true:
Expand All @@ -470,16 +489,17 @@ bool tick(struct em8051 *aCPU)
handle_interrupts(aCPU);
}

if (aCPU->mTickDelay == 0)
uint16_t old_pc = aCPU->mPC;

// IDL activate the idle mode to save power
// Interrupts can wake the CPU up so we have to check _after_ handle_interrupts()
bool is_idle = (aCPU->mSFR[REG_PCON]) & 0x01;
if (! is_idle && aCPU->mTickDelay == 0)
{
// IDL activate the idle mode to save power
bool is_idle = (aCPU->mSFR[REG_PCON]) & 0x01;
if (is_idle) {
aCPU->mTickDelay = 1;
} else {
aCPU->mTickDelay = aCPU->op[aCPU->mCodeMem[aCPU->mPC & (aCPU->mCodeMemMaxIdx)]](aCPU);
}
execute_current_opcode(aCPU);
ticked = true;
aCPU->first_cycle = true;

// update parity bit
v = aCPU->mSFR[REG_ACC];
v ^= v >> 4;
Expand All @@ -490,7 +510,13 @@ bool tick(struct em8051 *aCPU)

timer_tick(aCPU);

return ticked;
if (aCPU->mTickDelay > 0) {
// if multi cycle instr, do no yet update PC
aCPU->mPCSaved = aCPU->mPC;
aCPU->mPC = old_pc;
}

return ticked || is_idle;
}

uint8_t decode(struct em8051 *aCPU, uint16_t aPosition, char *aBuffer)
Expand All @@ -505,49 +531,59 @@ uint8_t decode(struct em8051 *aCPU, uint16_t aPosition, char *aBuffer)
strcpy(aBuffer, "POWER DOWN");
return 0;
}

if (! aCPU->first_cycle) {
// Current instruction has not finished executing
strcpy(aBuffer, "...");
return 0;
}

#if USE_SWITCH_DISPATCH
return do_dec(aCPU, aPosition, aBuffer);
#else // USE_SWITCH_DISPATCH
return aCPU->dec[aCPU->mCodeMem[aPosition & (aCPU->mCodeMemMaxIdx)]](aCPU, aPosition, aBuffer);
#endif // USE_SWITCH_DISPATCH
}

void disasm_setptrs(struct em8051 *aCPU);
void op_setptrs(struct em8051 *aCPU);

void reset(struct em8051 *aCPU, bool aWipe)
void reset(struct em8051 *aCPU, int aWipe)
{
// clear memory, set registers to bootup values, etc
if (aWipe)
// clear memory
if (aWipe & RESET_RAM)
{
memset(aCPU->mCodeMem, 0, aCPU->mCodeMemMaxIdx+1);
memset(aCPU->mExtData, 0, aCPU->mExtDataMaxIdx+1);
memset(aCPU->mLowerData, 0, 128);
if (aCPU->mUpperData)
memset(aCPU->mUpperData, 0, 128);
}

memset(aCPU->mSFR, 0, 128);
// Wipe out Code Region
if (aWipe & RESET_ROM)
memset(aCPU->mCodeMem, 0, aCPU->mCodeMemMaxIdx+1);

aCPU->mPC = 0;
aCPU->mTickDelay = 0;
aCPU->mSFR[REG_SP] = 7;
aCPU->mSFR[REG_P0] = 0xff;
aCPU->mSFR[REG_P1] = 0xff;
aCPU->mSFR[REG_P2] = 0xff;
aCPU->mSFR[REG_P3] = 0xff;
if (aWipe & RESET_SFR)
{
// set registers to bootup values, etc
memset(aCPU->mSFR, 0, 128);

aCPU->mPC = 0;
aCPU->mTickDelay = 0;
aCPU->mSFR[REG_SP] = 7;
aCPU->mSFR[REG_P0] = 0xff;
aCPU->mSFR[REG_P1] = 0xff;
aCPU->mSFR[REG_P2] = 0xff;
aCPU->mSFR[REG_P3] = 0xff;
aCPU->mSFR[REG_PCON] = 0x00;

// Random values
aCPU->mSFR[REG_SBUF] = rand();
}

// Power-off flag will be 1 only after a power on (cold reset).
// A warm reset doesn’t affect the value of this bit
// ... Therefore, we only set it if aWipe is 1
if (aWipe)
if (aWipe & RESET_RAM)
aCPU->mSFR[REG_PCON] |= (1<<4);

// Random values
if (aWipe)
aCPU->mSFR[REG_SBUF] = rand();

// build function pointer lists

disasm_setptrs(aCPU);
op_setptrs(aCPU);

// Clean internal variables
aCPU->mInterruptActive = 0;

Expand Down
Loading