Compare commits

...
14 Commits
Author SHA1 Message Date
GuyPerfect ae22c95dbe Tweaks in preparation for web module 2024-10-31 19:14:18 -05:00
GuyPerfect b134903878 Fix first line of disassembly 2024-10-30 15:12:38 -05:00
GuyPerfect 52838e4a6d Disassembler adjustments 2024-10-30 14:54:13 -05:00
GuyPerfect 6cba6e5d4f Prevent disassembling over PC 2024-10-30 10:22:49 -05:00
GuyPerfect 650d9dfd05 Add util to makefile 2024-10-30 09:52:33 -05:00
GuyPerfect f5a84fd4d0 Implement disassembler 2024-10-30 09:48:56 -05:00
GuyPerfect 9cc01bb6f7 CCSR.CC_Rd does not require a communication 2024-10-28 19:20:08 -05:00
GuyPerfect e828d99da1 Implement communication port 2024-10-28 19:11:33 -05:00
GuyPerfect da001e02cd Fix overplane 2024-10-26 15:04:27 -05:00
GuyPerfect 67bcb6d508 Prepare for new BG processors 2024-10-24 10:59:11 -05:00
GuyPerfect bcd80d291b Pseudo-halt timing fix 2024-10-23 21:16:35 -05:00
GuyPerfect 0c914fce1a Implement additional pseudo-halt addresses 2024-10-23 20:35:40 -05:00
GuyPerfect 226da7a5b3 Introduce pseudo-halt 2024-10-23 16:29:11 -05:00
GuyPerfect 8f9950f39e Overplane and sweep fixes 2024-10-22 19:53:27 -05:00
13 changed files with 1902 additions and 330 deletions
+11 -10
View File
@@ -95,16 +95,16 @@ static int32_t busReadMisc(VB *sim, uint8_t address, int type) {
/* Access by register */
switch (address >> 2 & 15) {
case 0x00>>2: break; /* CCR */
case 0x04>>2: break; /* CCSR */
case 0x08>>2: break; /* CDTR */
case 0x0C>>2: break; /* CDRR */
case 0x00>>2: return extReadCCR(sim); /* CCR */
case 0x04>>2: return extReadCCSR(sim); /* CCSR */
case 0x08>>2: return sim->ext.cdtr; /* CDTR */
case 0x0C>>2: return sim->ext.cdrr; /* CDRR */
case 0x10>>2: return sim->pad.sdlr; /* SDLR */
case 0x14>>2: return sim->pad.sdhr; /* SDHR */
case 0x18>>2: return sim->tmr.counter & 0xFF; /* TLR */
case 0x1C>>2: return sim->tmr.counter >> 8 & 0xFF; /* THR */
case 0x20>>2: return tmrReadControl(sim); /* TCR */
case 0x24>>2: return sim->wcr; /* WCR */
case 0x24>>2: return sim->wcr.exp1w << 1 | sim->wcr.rom1w; /* WCR */
case 0x28>>2: return padReadControl(sim); /* SCR */
}
@@ -123,15 +123,16 @@ static void busWriteMisc(VB *sim, uint8_t address, int type, int32_t value) {
/* Access by register */
switch (address >> 2 & 15) {
case 0x00>>2: break; /* CCR */
case 0x04>>2: break; /* CCSR */
case 0x08>>2: break; /* CDTR */
case 0x0C>>2: break; /* CDRR */
case 0x00>>2: extWriteCCR (sim, value); break; /* CCR */
case 0x04>>2: extWriteCCSR(sim, value); break; /* CCSR */
case 0x08>>2: sim->ext.cdtr = value; break; /* CDTR */
case 0x18>>2: tmrWriteLow (sim, value); break; /* TLR */
case 0x1C>>2: tmrWriteHigh (sim, value); break; /* THR */
case 0x20>>2: tmrWriteControl(sim, value); break; /* TCR */
case 0x24>>2: sim->wcr = value & 3; break; /* WCR */
case 0x28>>2: padWriteControl(sim, value); break; /* SCR */
case 0x24>>2: /* WCR */
sim->wcr.exp1w = value >> 1 & 1;
sim->wcr.rom1w = value & 1;
}
}
+130 -92
View File
@@ -10,97 +10,86 @@
#define CPU_HALTING 1
#define CPU_FATAL 2
#define CPU_FETCH 3
#define CPU_ILLEGAL 4
#define CPU_BITSTRING 5
#define CPU_FLOATENDO 6
#define CPU_ADD_IMM 7
#define CPU_ADD_REG 8
#define CPU_ADDF_S 9
#define CPU_ADDI 10
#define CPU_AND 11
#define CPU_ANDI 12
#define CPU_BCOND 13
#define CPU_CAXI 14
#define CPU_CLI 15
#define CPU_CMP_IMM 16
#define CPU_CMP_REG 17
#define CPU_CMPF_S 18
#define CPU_CVT_SW 19
#define CPU_CVT_WS 20
#define CPU_DIV 21
#define CPU_DIVF_S 22
#define CPU_DIVU 23
#define CPU_HALT 24
#define CPU_IN_B 25
#define CPU_IN_H 26
#define CPU_IN_W 27
#define CPU_JAL 28
#define CPU_JMP 29
#define CPU_JR 30
#define CPU_LD_B 31
#define CPU_LD_H 32
#define CPU_LD_W 33
#define CPU_LDSR 34
#define CPU_MOV_IMM 35
#define CPU_MOV_REG 36
#define CPU_MOVEA 37
#define CPU_MOVHI 38
#define CPU_MPYHW 39
#define CPU_MUL 40
#define CPU_MULF_S 41
#define CPU_MULU 42
#define CPU_NOT 43
#define CPU_OR 44
#define CPU_ORI 45
#define CPU_OUT_B 46
#define CPU_OUT_H 47
#define CPU_OUT_W 48
#define CPU_RETI 49
#define CPU_REV 50
#define CPU_SAR_IMM 51
#define CPU_SAR_REG 52
#define CPU_SCH0BSD 53
#define CPU_SCH0BSU 54
#define CPU_SCH1BSD 55
#define CPU_SCH1BSU 56
#define CPU_SEI 57
#define CPU_SETF 58
#define CPU_SHL_IMM 59
#define CPU_SHL_REG 60
#define CPU_SHR_IMM 61
#define CPU_SHR_REG 62
#define CPU_ST_B 63
#define CPU_ST_H 64
#define CPU_ST_W 65
#define CPU_STSR 66
#define CPU_SUB 67
#define CPU_SUBF_S 68
#define CPU_TRAP 69
#define CPU_TRNC_SW 70
#define CPU_XB 71
#define CPU_XH 72
#define CPU_XOR 73
#define CPU_XORI 74
#define CPU_ANDBSU 75 /* Keep bit string ALU commands sequential */
#define CPU_ANDNBSU 76
#define CPU_MOVBSU 77
#define CPU_NOTBSU 78
#define CPU_ORBSU 79
#define CPU_ORNBSU 80
#define CPU_XORBSU 81
#define CPU_XORNBSU 82
/* Abstract operand types */
#define CPU_IMP(x) -x-1
#define CPU_DISP9 1
#define CPU_DISP26 2
#define CPU_IMM16S 3
#define CPU_IMM16U 4
#define CPU_IMM5S 5
#define CPU_IMM5U 6
#define CPU_MEM 7
#define CPU_REG1 8
#define CPU_REG2 9
#define CPU_PHALT 4
#define CPU_ILLEGAL 5
#define CPU_BITSTRING 6
#define CPU_FLOATENDO 7
#define CPU_ADD_IMM 8
#define CPU_ADD_REG 9
#define CPU_ADDF_S 10
#define CPU_ADDI 11
#define CPU_AND 12
#define CPU_ANDI 13
#define CPU_BCOND 14
#define CPU_CAXI 15
#define CPU_CLI 16
#define CPU_CMP_IMM 17
#define CPU_CMP_REG 18
#define CPU_CMPF_S 19
#define CPU_CVT_SW 20
#define CPU_CVT_WS 21
#define CPU_DIV 22
#define CPU_DIVF_S 23
#define CPU_DIVU 24
#define CPU_HALT 25
#define CPU_IN_B 26
#define CPU_IN_H 27
#define CPU_IN_W 28
#define CPU_JAL 29
#define CPU_JMP 30
#define CPU_JR 31
#define CPU_LD_B 32
#define CPU_LD_H 33
#define CPU_LD_W 34
#define CPU_LDSR 35
#define CPU_MOV_IMM 36
#define CPU_MOV_REG 37
#define CPU_MOVEA 38
#define CPU_MOVHI 39
#define CPU_MPYHW 40
#define CPU_MUL 41
#define CPU_MULF_S 42
#define CPU_MULU 43
#define CPU_NOT 44
#define CPU_OR 45
#define CPU_ORI 46
#define CPU_OUT_B 47
#define CPU_OUT_H 48
#define CPU_OUT_W 49
#define CPU_RETI 50
#define CPU_REV 51
#define CPU_SAR_IMM 52
#define CPU_SAR_REG 53
#define CPU_SCH0BSD 54
#define CPU_SCH0BSU 55
#define CPU_SCH1BSD 56
#define CPU_SCH1BSU 57
#define CPU_SEI 58
#define CPU_SETF 59
#define CPU_SHL_IMM 60
#define CPU_SHL_REG 61
#define CPU_SHR_IMM 62
#define CPU_SHR_REG 63
#define CPU_ST_B 64
#define CPU_ST_H 65
#define CPU_ST_W 66
#define CPU_STSR 67
#define CPU_SUB 68
#define CPU_SUBF_S 69
#define CPU_TRAP 70
#define CPU_TRNC_SW 71
#define CPU_XB 72
#define CPU_XH 73
#define CPU_XOR 74
#define CPU_XORI 75
#define CPU_ANDBSU 76 /* Keep bit string ALU IDs consecutive */
#define CPU_ANDNBSU 77
#define CPU_MOVBSU 78
#define CPU_NOTBSU 79
#define CPU_ORBSU 80
#define CPU_ORNBSU 81
#define CPU_XORBSU 82
#define CPU_XORNBSU 83
/* Functional operand types */
#define CPU_LITERAL 0
@@ -206,6 +195,13 @@ static const uint8_t OPDEFS_FLOATENDO[] = {
/**************************** Forward references *****************************/
static int phAssess (VB *, uint32_t, int, int32_t);
static uint32_t phUntil (VB *);
/***************************** Callback Handlers *****************************/
/* Prepare to handle an exception */
@@ -248,6 +244,10 @@ static int cpuRead(VB *sim, uint32_t address, int type, int32_t *value) {
/* Retrieve the value from the simulation state directly */
busRead(sim, address, type, value);
/* Check for pseudo-halt */
if (sim->ph.enabled && phAssess(sim, address, type, *value))
return 0;
/* Invoke the callback if available */
if (
sim->onRead != NULL &&
@@ -296,6 +296,10 @@ static int cpuWrite(VB *sim, uint32_t address, int type, int32_t value) {
int cancel = 0;
uint32_t cycles = 3; /* TODO: Research this */
/* Reset pseudo-halt */
if (sim->ph.enabled)
sim->ph.step = 0;
/* Invoke the callback if available */
if (
sim->onWrite != NULL &&
@@ -482,10 +486,13 @@ static int cpuException(VB *sim) {
/* Interrupts only */
if ((cause & 0xFF00) == 0xFE00) {
sim->cpu.psw.i = (cause >> 4 & 7) + 1;
/* HALT instruction */
if (sim->cpu.halt) {
sim->cpu.halt = 0;
sim->cpu.pc += 2;
}
}
/* All exceptions */
@@ -583,6 +590,30 @@ static int cpuHalt(VB *sim) {
return !cpuIRQ(sim);
}
/* Pseudo-halt is pending */
static int cpuPHalt(VB *sim) {
int32_t value; /* Value read from memory */
/* An interrupt will be accepted */
if (cpuIRQ(sim)) {
sim->ph.step = 0;
return 0;
}
/* Monitor value has not changed */
busRead(sim, sim->ph.address, sim->ph.type, &value);
if (value == sim->ph.value) {
sim->cpu.clocks = phUntil(sim);
return 1;
}
/* Release pseudo-halt */
sim->cpu.operation = CPU_FETCH;
sim->cpu.step = 0;
sim->ph.step = 0;
return 0;
}
/**************************** Instruction Helpers ****************************/
@@ -1703,6 +1734,7 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
case CPU_FATAL : return 0;
case CPU_FETCH : brk = cpuFetch (sim); break;
case CPU_HALTING : if (cpuHalt (sim)) return 0; break;
case CPU_PHALT : if (cpuPHalt(sim)) return 0; break;
case CPU_ADD_IMM: cpuADDImm (sim); break;
case CPU_ADD_REG: cpuADDReg (sim); break;
@@ -1826,8 +1858,14 @@ static void cpuReset(VB *sim) {
/* Determine how many clocks are guaranteed to process */
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
/* Pseudo-halting */
if (sim->cpu.operation == CPU_PHALT) {
if (sim->cpu.clocks == 0)
return clocks;
}
/* Halting */
if (sim->cpu.halt) {
else if (sim->cpu.halt) {
return
sim->cpu.operation == CPU_HALTING &&
!(sim->cpu.psw.id | sim->cpu.psw.ep | sim->cpu.psw.np) &&
+164
View File
@@ -0,0 +1,164 @@
/* This file is included into vb.c and cannot be compiled on its own. */
#ifdef VBAPI
/***************************** Callback Handlers *****************************/
/* Prepare to handle an exception */
#ifndef VB_DIRECT_LINK
#define VB_ON_LINK sim1->onLink
#else
extern int VB_DIRECT_LINK(VB *, VB *, uint8_t *, uint8_t *);
#define VB_ON_LINK VB_DIRECT_LINK
#endif
static int extOnLink(VB *sim1, VB *sim2, uint8_t *value1, uint8_t *value2) {
return sim1->onLink != NULL && VB_ON_LINK(sim1, sim2, value1, value2);
}
#undef VB_ON_LINK
/***************************** Library Functions *****************************/
/* Process component */
static int extEmulate(VB *sim, uint32_t clocks) {
VB *peer; /* Communication peer */
VB *sims[2]; /* Communication peers */
uint8_t values[2]; /* Transmission values */
int x; /* Iterator */
/* Communication will not occur */
if (!sim->ext.c_stat || sim->ext.c_clk_sel)
return 0;
/* Communication completes after time to process */
if (sim->ext.clocks > clocks) {
sim->ext.clocks -= clocks;
return 0;
}
/* Exchange transmission data */
sims [0] = sim;
sims [1] = sim->peer;
values[0] = sim->ext.cdtr;
values[1] = sim->peer == NULL ? 0 : sim->peer->ext.cdtr;
if (extOnLink(sim, sim->peer, &values[0], &values[1]))
return 1;
/* Update state */
for (x = 0; x < 2; x++) {
sim = sims[x];
peer = sims[x ^ 1];
if (sim == NULL)
break;
if (peer == NULL)
peer = sim;
/* Registers */
sim->ext.cdrr = values[x ^ 1];
sim->ext.c_irq |= !sim->ext.c_int_inh;
sim->ext.c_stat = 0;
sim->ext.cc_rd = sim->ext.cc_wr & peer->ext.cc_wr;
sim->ext.cc_smp = sim->ext.cc_sig & peer->ext.cc_sig & sim->ext.cc_rd;
sim->ext.cc_irq |= !sim->ext.cc_int_inh &&
sim->ext.cc_smp == sim->ext.cc_int_lev;
/* Interrupt */
if (sim->ext.c_irq | sim->ext.cc_irq)
sim->cpu.irq |= 0x0008;
}
return 0;
}
/* Read a value from CCR */
static int32_t extReadCCR(VB *sim) {
return 0x6D |
sim->ext.c_int_inh << 7 |
sim->ext.c_clk_sel << 4 |
sim->ext.c_stat << 1
;
}
/* Read a value from CCSR */
static int32_t extReadCCSR(VB *sim) {
sim->ext.cc_rd = sim->ext.cc_wr &
(sim->peer == NULL ? 1 : sim->peer->ext.cc_wr);
return 0x60 |
sim->ext.cc_int_inh << 7 |
sim->ext.cc_int_lev << 4 |
sim->ext.cc_sig << 3 |
sim->ext.cc_smp << 2 |
sim->ext.cc_wr << 1 |
sim->ext.cc_rd
;
}
/* Simulate a hardware reset */
static void extReset(VB *sim) {
/* Normal */
sim->ext.c_clk_sel = 0;
sim->ext.c_int_inh = 0;
sim->ext.c_stat = 0;
sim->ext.cc_int_inh = 1;
sim->ext.cc_int_lev = 1;
sim->ext.cc_sig = 1;
sim->ext.cc_wr = 1;
sim->ext.cdrr = 0x00;
sim->ext.cdtr = 0x00;
/* Other */
sim->ext.c_irq = 0;
sim->ext.cc_irq = 0;
}
/* Determine how many clocks are guaranteed to process */
static uint32_t extUntil(VB *sim, uint32_t clocks) {
return !sim->ext.c_stat || sim->ext.c_clk_sel || clocks < sim->ext.clocks ?
clocks : sim->ext.clocks;
}
/* Write a value to CCR */
static void extWriteCCR(VB *sim, uint8_t value) {
/* Configure state */
sim->ext.c_int_inh = value >> 7 & 1;
sim->ext.c_clk_sel = value >> 4 & 1;
/* Acknowledge interrupt */
if (sim->ext.c_int_inh) {
sim->ext.c_irq = 0;
if (!sim->ext.cc_irq)
sim->cpu.irq &= ~0x0008;
}
/* Do not initiate a communication */
if (sim->ext.c_stat || (value & 0x04) == 0) /* C-Start */
return;
/* Initiate a communication */
sim->ext.c_stat = 1;
sim->ext.clocks = 3200; /* 160us */
}
/* Write a value to CCSR */
static void extWriteCCSR(VB *sim, uint8_t value) {
/* Configure state */
sim->ext.cc_int_inh = value >> 7 & 1;
sim->ext.cc_int_lev = value >> 4 & 1;
sim->ext.cc_sig = value >> 3 & 1;
sim->ext.cc_wr = value >> 1 & 1;
/* Acknowledge interrupt */
if (!sim->ext.cc_int_inh)
return;
sim->ext.cc_irq = 0;
if (!sim->ext.c_irq)
sim->cpu.irq &= ~0x0008;
}
#endif /* VBAPI */
+9 -8
View File
@@ -9,12 +9,12 @@
static void padEmulate(VB *sim, uint32_t clocks) {
/* No hardware read in progress */
if (sim->pad.si_stat == 0)
if (!sim->pad.si_stat)
return;
/* Hardware read completes after time to process */
if (sim->pad.si_stat > clocks) {
sim->pad.si_stat -= clocks;
if (sim->pad.clocks > clocks) {
sim->pad.clocks -= clocks;
return;
}
@@ -38,7 +38,7 @@ static int32_t padReadControl(VB *sim) {
sim->pad.k_int_inh << 7 |
sim->pad.para_si << 5 |
sim->pad.soft_ck << 4 |
!!sim->pad.si_stat << 1 |
sim->pad.si_stat << 1 |
sim->pad.s_abt_dis
;
}
@@ -78,7 +78,8 @@ static void padWriteControl(VB *sim, uint8_t value) {
sim->pad.si_stat == 0 && /* No hardware read underway */
!sim->pad.s_abt_dis /* Hardware reads enabled */
) {
sim->pad.si_stat = 10240; /* 512us */
sim->pad.clocks = 10240; /* 512us */
sim->pad.si_stat = 1;
sim->pad.step = 0; /* Abort software read */
}
@@ -86,7 +87,7 @@ static void padWriteControl(VB *sim, uint8_t value) {
sim->pad.para_si = value >> 5 & 1;
if (
sim->pad.para_si &&
sim->pad.si_stat == 0 /* No hardware read underway */
!sim->pad.si_stat /* No hardware read underway */
) sim->pad.step = 32;
/* Signal a bit for a software read */
@@ -107,8 +108,8 @@ static void padWriteControl(VB *sim, uint8_t value) {
/* Determine how many clocks are guaranteed to process */
static uint32_t padUntil(VB *sim, uint32_t clocks) {
return sim->pad.si_stat != 0 && sim->pad.si_stat < clocks ?
sim->pad.si_stat : clocks;
return sim->pad.si_stat && sim->pad.clocks < clocks ?
sim->pad.clocks : clocks;
}
+264
View File
@@ -0,0 +1,264 @@
/* This file is included into vb.c and cannot be compiled on its own. */
#ifdef VBAPI
/********************************* Constants *********************************/
/* Pseudo-halt operations */
#define PH_NEVER 0
#define PH_DPSTTS 1
#define PH_GAME_PAD 2
#define PH_INTPND 3
#define PH_TCR 4
#define PH_TLHR 5
#define PH_XPSTTS 6
/***************************** Module Functions ******************************/
/* Activate pseudo-halt */
static void phActivate(VB *sim, uint32_t address, int type) {
int range; /* Memory address range by component */
/* Working variables */
address &= 0x07FFFFFF;
range = address >> 24;
/* Configure pseudo-halt */
sim->ph.operation = PH_NEVER;
/* VIP */
if (range == 0) {
address &= 0x0007FFFF;
/* TODO: Frame buffer */
/* I/O register */
switch (address) {
case 0x5F800: /* INTPND */
if (
sim->vip.dp.step != 0 ||
sim->vip.dp.enabled ||
(sim->vip.dp.disp && sim->vip.dp.synce) ||
sim->vip.xp.enabled ||
sim->vip.xp.xpen
) sim->ph.operation = PH_INTPND;
break;
case 0x5F820: /* DPSTTS */
if (
sim->vip.dp.step != 0 ||
sim->vip.dp.enabled ||
(sim->vip.dp.disp && sim->vip.dp.synce)
) sim->ph.operation = PH_DPSTTS;
break;
case 0x5F840: /* XPSTTS */
if (sim->vip.xp.enabled || sim->vip.xp.xpen)
sim->ph.operation = PH_XPSTTS;
break;
}
}
/* Misc. I/O */
else if (range == 2 && (type == VB_S8 || type == VB_U8)) {
address &= 0x0000003F;
switch (address) {
/* TODO: Communication port */
/* Game pad */
case 0x10: /* SDLR */
case 0x14: /* SDHR */
case 0x28: /* SCR */
if (sim->pad.si_stat != 0)
sim->ph.operation = PH_GAME_PAD;
break;
/* Timer */
case 0x18: /* TLR */
case 0x1C: /* THR */
if (sim->tmr.t_enb)
sim->ph.operation = PH_TLHR;
break;
case 0x20: /* TCR */
if (sim->tmr.t_enb)
sim->ph.operation = PH_TCR;
break;
}
}
/* Configure CPU */
sim->cpu.clocks = phUntil(sim);
sim->cpu.operation = CPU_PHALT;
}
/* Test whether the current memory access matches the monitored access */
static int phMatches(VB *sim, uint32_t address, int type, int32_t value) {
int match; /* Parameter match */
int x; /* Iterator */
/* New memory access */
if (sim->ph.step == 0)
return 0;
/* Check memory access parameters */
match =
address == sim->ph.address &&
sim->cpu.pc == sim->ph.pc &&
type == sim->ph.type &&
value == sim->ph.value
;
if (!match || sim->ph.step != 3)
return match;
/* Check full CPU state */
for (x = 1; x < 32; x++) {
if (sim->ph.program[x - 1] != sim->cpu.program[x])
return 0;
}
return
sim->ph.adtre == sim->cpu.adtre &&
sim->ph.chcw == cpuGetSystemRegister(sim, VB_CHCW) &&
sim->ph.ecr == cpuGetSystemRegister(sim, VB_ECR) &&
sim->ph.eipc == sim->cpu.eipc &&
sim->ph.eipsw == sim->cpu.eipsw &&
sim->ph.fepc == sim->cpu.fepc &&
sim->ph.fepsw == sim->cpu.fepsw &&
sim->ph.psw == cpuGetSystemRegister(sim, VB_PSW )
;
}
/****************************** Clock Measurers ******************************/
/* DPSTTS */
static uint32_t phDPSTTS(VB *sim) {
switch (sim->vip.dp.step) {
case 0: /* 0ms - FCLK rising edge */
case 2: /* 3ms-8ms - Display left frame buffer */
case 3: /* 8ms - L*BSY falling edge */
case 6: /* 13ms-18ms - Display right frame buffer */
case 7: /* 18ms - R*BSY falling edge */
case 8: /* 20ms - Display interval complete */
return sim->vip.dp.until;
}
/* case 1: 3ms - L*BSY rising edge */
/* case 4: 10ms - FCLK falling edge */
/* case 5: 13ms - R*BSY rising edge */
return sim->vip.dp.clocks;
}
/* INTPND */
static uint32_t phINTPND(VB *sim) {
if (!(
sim->vip.dp.step != 0 ||
sim->vip.dp.enabled ||
(sim->vip.dp.disp && sim->vip.dp.synce)
)) return sim->vip.xp.until;
if (!(sim->vip.xp.enabled || sim->vip.xp.xpen))
return sim->vip.dp.until;
return sim->vip.dp.until < sim->vip.xp.until ?
sim->vip.dp.until : sim->vip.xp.until;
}
/* XPSTTS */
static uint32_t phXPSTTS(VB *sim) {
uint32_t clocks; /* Return value */
uint16_t *halfwords; /* Drawing clocks this SBCOUNT */
uint32_t x; /* Iterator */
/* Drawing is underway */
if (sim->vip.xp.f0bsy || sim->vip.xp.f1bsy) {
clocks = 0;
halfwords = &sim->vip.halfwords[
(uint32_t) sim->vip.xp.sbcount * 384 + sim->vip.xp.column];
for (x = sim->vip.xp.column; x < 384; x++, halfwords++)
clocks += *halfwords;
return clocks;
}
/* Drawing is idle */
switch (sim->vip.dp.step) {
case 0: /* 0ms - FCLK rising edge */
return sim->vip.dp.until;
case 1: /* 3ms - L*BSY rising edge */
case 2: /* 3ms-8ms - Display left frame buffer */
case 3: /* 8ms - L*BSY falling edge */
return sim->vip.dp.until + vipClocksMs(12);
}
/* case 4: 10ms - FCLK falling edge */
/* case 5: 13ms - R*BSY rising edge */
/* case 6: 13ms-18ms - Display right frame buffer */
/* case 7: 18ms - R*BSY falling edge */
return sim->vip.dp.until + vipClocksMs(2);
}
/***************************** Library Functions *****************************/
/* Test whether to activate pseudo-halt */
static int phAssess(VB *sim, uint32_t address, int type, int32_t value) {
int x; /* Iterator */
/* Memory access does not match last time */
address &= TYPE_MASKS[type];
if (!phMatches(sim, address, type, value))
sim->ph.step = 0;
/* New memory access */
if (sim->ph.step == 0) {
sim->ph.address = address;
sim->ph.pc = sim->cpu.pc;
sim->ph.step = 1;
sim->ph.type = type;
sim->ph.value = value;
return 0;
}
/* Repeated memory access, not checking full CPU state */
if (sim->ph.step < 2) {
sim->ph.step++;
return 0;
}
/* Take a snapshot of the full CPU state */
if (sim->ph.step == 2) {
for (x = 1; x < 32; x++)
sim->ph.program[x - 1] = sim->cpu.program[x];
sim->ph.adtre = sim->cpu.adtre;
sim->ph.chcw = cpuGetSystemRegister(sim, VB_CHCW);
sim->ph.ecr = cpuGetSystemRegister(sim, VB_ECR);
sim->ph.eipc = sim->cpu.eipc;
sim->ph.eipsw = sim->cpu.eipsw;
sim->ph.fepc = sim->cpu.fepc;
sim->ph.fepsw = sim->cpu.fepsw;
sim->ph.psw = cpuGetSystemRegister(sim, VB_PSW);
sim->ph.step = 3;
return 0;
}
/* Activate pseudo-halt */
phActivate(sim, address, type);
return 1;
}
/* Determine how long the CPU should wait before checking the monitor value */
static uint32_t phUntil(VB *sim) {
switch (sim->ph.operation) {
case PH_DPSTTS : return phDPSTTS(sim);
case PH_GAME_PAD: return sim->pad.si_stat;
case PH_INTPND : return phINTPND(sim);
case PH_TCR : return sim->tmr.until;
case PH_TLHR : return sim->tmr.clocks;
case PH_XPSTTS : return phXPSTTS(sim);
}
return 0; /* PH_NEVER */
}
#endif /* VBAPI */
+168 -26
View File
@@ -146,6 +146,28 @@ struct VB {
int step; /* Operation sub-task ID */
} cpu;
/* Communication port */
struct {
/* Register state */
uint8_t c_clk_sel; /* Transmission clock source */
uint8_t c_int_inh; /* Interrupt acknowledge/disable */
uint8_t c_stat; /* Communication is underway */
uint8_t cc_int_inh; /* Interrupt acknowledge/disable */
uint8_t cc_int_lev; /* Interrupt condition */
uint8_t cc_rd; /* Manual read */
uint8_t cc_sig; /* Automatic write */
uint8_t cc_smp; /* Automatic read */
uint8_t cc_wr; /* Manual write */
uint8_t cdrr; /* Data received */
uint8_t cdtr; /* Data to transmit */
/* Other state */
int8_t c_irq; /* COM interrupt request */
int8_t cc_irq; /* COMCNT interrupt request */
uint32_t clocks; /* Master clocks to wait */
} ext;
/* Game pad */
struct {
@@ -159,6 +181,7 @@ struct VB {
uint8_t soft_ck; /* Controller communication signal */
/* Other state */
uint32_t clocks; /* Master clocks to wait */
uint16_t keys; /* Next input bits */
int step; /* Software read processing phase */
} pad;
@@ -209,6 +232,7 @@ struct VB {
uint32_t clocks; /* Master clocks to wait */
int column; /* Index of column to display */
uint32_t cta; /* Column table pointer in memory */
uint8_t enabled; /* Was enabled at FCLK */
uint32_t fbDest; /* Output frame pixel address */
uint32_t fbSrc; /* Source frame buffer address */
int32_t repeat; /* Current column table repeat value */
@@ -231,6 +255,7 @@ struct VB {
/* Other state */
uint32_t clocks; /* Master clocks to wait */
int column; /* Current horizontal output position */
uint8_t enabled; /* Was enabled at FCLK */
int frame; /* FRMCYC counter */
int32_t halfword; /* Current output halfword offset */
int step; /* Processing phase */
@@ -294,9 +319,10 @@ struct VB {
struct {
float i1[2]; /* Previous analog input sample */
float o1[2]; /* Previous analog output sample */
uint32_t capacity; /* Number of audio frames in samples */
uint32_t offset; /* Position in output buffer */
int16_t *samples; /* Output memory */
unsigned capacity; /* Number of audio frames in output buffer */
unsigned offset; /* Position in output buffer */
void *samples; /* Output buffer */
int type; /* Output data type */
} out;
/* Memory */
@@ -308,8 +334,37 @@ struct VB {
int sample; /* Output sample index, period 417 */
} vsu;
/* Wait controller */
struct {
uint8_t exp1w; /* Cartridge expansion 1-wait */
uint8_t rom1w; /* Cartridge ROM 1-wait */
} wcr;
/* Pseudo-halt */
struct {
uint32_t address; /* Monitor address */
uint8_t enabled; /* Pseudo-halt function is enabled */
uint8_t operation; /* Monitoring operation */
uint8_t step; /* Number of consecutive matching reads */
int type; /* Memory access type */
int32_t value; /* Value read from monitor address */
/* CPU snapshot */
uint32_t adtre;
uint32_t chcw;
uint32_t ecr;
uint32_t eipc;
uint32_t eipsw;
uint32_t fepc;
uint32_t fepsw;
uint32_t pc;
int32_t program[31];
uint32_t psw;
uint32_t sr29;
uint32_t sr31;
} ph;
/* Other state */
uint8_t wcr; /* Wait controller state */
uint8_t wram[0x10000]; /* System RAM */
/* Application data */
@@ -317,9 +372,11 @@ struct VB {
vbOnExecute onExecute; /* CPU instruction execute */
vbOnFetch onFetch; /* CPU instruction fetch */
vbOnFrame onFrame; /* VIP frame ready */
vbOnLink onLink; /* Communication transfer */
vbOnRead onRead; /* CPU instruction read */
vbOnSamples onSamples; /* VSU samples full */
vbOnWrite onWrite; /* CPU instruction write */
VB *peer; /* Communication peer */
void *tag; /* User data */
};
@@ -342,12 +399,14 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
/******************************** Sub-Modules ********************************/
#include "ext.c"
#include "game-pad.c"
#include "timer.c"
#include "bus.c"
#include "cpu.c"
#include "vip.c"
#include "vsu.c"
#include "pseudo-halt.c"
@@ -355,18 +414,29 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
/* Process a simulation for a given number of clocks */
static int sysEmulate(VB *sim, uint32_t clocks) {
int ret;
ret = cpuEmulate(sim, clocks);
int ret = 0;
/* CPU is in a pseudo-halt state that requires an interrupt to exit */
int never =
sim->cpu.operation == CPU_PHALT &&
sim->ph.operation == PH_NEVER
;
/* Process all components */
if (!never){ret = cpuEmulate(sim, clocks);}
ret |= extEmulate(sim, clocks);
padEmulate(sim, clocks);
tmrEmulate(sim, clocks);
vsuEmulate(sim, clocks);
ret |= vipEmulate(sim, clocks);
if ( never) ret |= cpuEmulate(sim, clocks);
return ret;
}
/* Determine how many clocks are guaranteed to process */
static uint32_t sysUntil(VB *sim, uint32_t clocks) {
clocks = cpuUntil(sim, clocks);
clocks = extUntil(sim, clocks);
clocks = padUntil(sim, clocks);
clocks = tmrUntil(sim, clocks);
clocks = vipUntil(sim, clocks);
@@ -392,19 +462,23 @@ VBAPI int vbEmulate(VB *sim, uint32_t *clocks) {
}
/* Process multiple simulations */
VBAPI int vbEmulateEx(VB **sims, int count, uint32_t *clocks) {
VBAPI int vbEmulateEx(VB **sims, unsigned count, uint32_t *clocks) {
int brk; /* A callback requested a break */
uint32_t until; /* Clocks guaranteed to process */
int x; /* Iterator */
unsigned x; /* Iterator */
/* Process one simulation */
if (count == 1)
return vbEmulate(sims[0], clocks);
/* Process multiple simulations */
while (*clocks != 0) {
until = *clocks;
for (x = count - 1; x >= 0; x--)
until = sysUntil(sims[x], until);
for (x = count; x > 0; x--)
until = sysUntil(sims[x - 1], until);
brk = 0;
for (x = count - 1; x >= 0; x--)
brk |= sysEmulate(sims[x], until);
for (x = count; x > 0; x--)
brk |= sysEmulate(sims[x - 1], until);
*clocks -= until;
if (brk)
return brk; /* TODO: return 1 */
@@ -451,6 +525,24 @@ VBAPI uint16_t vbGetKeys(VB *sim) {
return sim->pad.keys;
}
/* Retrieve the current link callback handler */
VBAPI vbOnLink vbGetLinkCallback(VB *sim) {
return sim->onLink;
}
/* Retrieve a core option value */
VBAPI int vbGetOption(VB *sim, int key) {
switch (key) {
case VB_PSEUDO_HALT: return sim->ph.enabled;
}
return 0;
}
/* Retrieve the communication peer */
VBAPI VB* vbGetPeer(VB *sim) {
return sim->peer;
}
/* Retrieve the most recent frame image pixels */
VBAPI void vbGetPixels(VB *sim, void *left, int leftStrideX, int leftStrideY,
void *right, int rightStrideX, int rightStrideY) {
@@ -497,7 +589,7 @@ VBAPI uint32_t vbGetProgramCounter(VB *sim) {
}
/* Retrieve the value in a program register */
VBAPI int32_t vbGetProgramRegister(VB *sim, int index) {
VBAPI int32_t vbGetProgramRegister(VB *sim, unsigned index) {
return index < 1 || index > 31 ? 0 : sim->cpu.program[index];
}
@@ -507,13 +599,18 @@ VBAPI vbOnRead vbGetReadCallback(VB *sim) {
}
/* Retrieve the audio samples buffer */
VBAPI void* vbGetSamples(VB *sim, uint32_t *capacity, uint32_t *position) {
VBAPI void* vbGetSamples(VB *sim, int *type,
unsigned *capacity, unsigned *position) {
if (sim->vsu.out.samples == NULL) {
if (type != NULL)
*type = 0;
if (capacity != NULL)
*capacity = 0;
if (position != NULL)
*position = 0;
} else {
if (type != NULL)
*type = sim->vsu.out.type;
if (capacity != NULL)
*capacity = sim->vsu.out.capacity;
if (position != NULL)
@@ -528,8 +625,8 @@ VBAPI vbOnSamples vbGetSamplesCallback(VB *sim) {
}
/* Retrieve the value in a system register */
VBAPI uint32_t vbGetSystemRegister(VB *sim, int index) {
return index < 0 || index > 31 ? 0 : cpuGetSystemRegister(sim, index);
VBAPI uint32_t vbGetSystemRegister(VB *sim, unsigned index) {
return index > 31 ? 0 : cpuGetSystemRegister(sim, index);
}
/* Retrieve a simulation's userdata pointer */
@@ -550,9 +647,12 @@ VBAPI VB* vbInit(VB *sim) {
sim->onExecute = NULL;
sim->onFetch = NULL;
sim->onFrame = NULL;
sim->onLink = NULL;
sim->onRead = NULL;
sim->onSamples = NULL;
sim->onWrite = NULL;
sim->peer = NULL;
sim->ph.enabled = 0;
vbReset(sim);
return sim;
}
@@ -571,7 +671,8 @@ VBAPI VB* vbReset(VB *sim) {
int x; /* Iterator */
/* Wait controller */
sim->wcr = 0x00;
sim->wcr.exp1w = 0;
sim->wcr.rom1w = 0;
/* WRAM (the hardware does not do this) */
for (x = 0; x < 0x10000; x++)
@@ -579,10 +680,14 @@ VBAPI VB* vbReset(VB *sim) {
/* Components */
cpuReset(sim);
extReset(sim);
padReset(sim);
tmrReset(sim);
vipReset(sim);
vsuReset(sim);
/* Pseudo-halt */
sim->ph.step = 0;
return sim;
}
@@ -641,6 +746,42 @@ VBAPI uint16_t vbSetKeys(VB *sim, uint16_t keys) {
return sim->pad.keys = keys;
}
/* Specify a new link callback handler */
VBAPI vbOnLink vbSetLinkCallback(VB *sim, vbOnLink callback) {
vbOnLink prev = sim->onLink;
sim->onLink = callback;
return prev;
}
/* Specify a new core option value */
VBAPI int vbSetOption(VB *sim, int key, int value) {
switch (key) {
case VB_PSEUDO_HALT:
sim->ph.enabled = value = !!value;
if (!value) {
sim->ph.step = 0;
if (sim->cpu.operation == CPU_PHALT) {
sim->cpu.operation = CPU_FETCH;
sim->cpu.step = 0;
}
}
break;
}
return value;
}
/* Specify a new communication peer */
VBAPI void vbSetPeer(VB *sim, VB *peer) {
if (sim->peer == peer)
return;
sim->peer = peer;
if (peer == NULL)
return;
if (peer->peer != NULL)
peer->peer->peer = NULL;
peer->peer = sim;
}
/* Specify a new value for the program counter */
VBAPI uint32_t vbSetProgramCounter(VB *sim, uint32_t value) {
sim->cpu.operation = CPU_FETCH;
@@ -650,7 +791,7 @@ VBAPI uint32_t vbSetProgramCounter(VB *sim, uint32_t value) {
}
/* Specify a new value for a program register */
VBAPI int32_t vbSetProgramRegister(VB *sim, int index, int32_t value) {
VBAPI int32_t vbSetProgramRegister(VB *sim, unsigned index, int32_t value) {
return index < 1 || index > 31 ? 0 : (sim->cpu.program[index] = value);
}
@@ -662,12 +803,14 @@ VBAPI vbOnRead vbSetReadCallback(VB *sim, vbOnRead callback) {
}
/* Specify a new audio samples buffer */
VBAPI int vbSetSamples(VB *sim, void *samples, uint32_t capacity) {
if (samples != NULL && (capacity == 0 || capacity > 0x40000000))
VBAPI int vbSetSamples(VB *sim, void *samples, int type, unsigned capacity) {
if (samples != NULL &&
(capacity == 0 || (type != VB_S16 && type != VB_F32)))
return 1;
sim->vsu.out.capacity = samples == NULL ? 0 : capacity;
sim->vsu.out.capacity = capacity;
sim->vsu.out.offset = 0;
sim->vsu.out.samples = samples;
sim->vsu.out.type = type;
return 0;
}
@@ -679,9 +822,8 @@ VBAPI vbOnSamples vbSetSamplesCallback(VB *sim, vbOnSamples callback) {
}
/* Specify a new value for a system register */
VBAPI uint32_t vbSetSystemRegister(VB *sim, int index, uint32_t value) {
return index < 0 || index > 31 ? 0 :
cpuSetSystemRegister(sim, index, value, 1);
VBAPI uint32_t vbSetSystemRegister(VB *sim, unsigned index, uint32_t value) {
return index > 31 ? 0 : cpuSetSystemRegister(sim, index, value, 1);
}
/* Specify a new write callback handler */
+19 -7
View File
@@ -22,6 +22,7 @@ extern "C" {
VB_DIRECT_EXECUTE
VB_DIRECT_FETCH
VB_DIRECT_FRAME
VB_DIRECT_LINK
VB_DIRECT_READ
VB_DIRECT_SAMPLES
VB_DIRECT_WRITE
@@ -78,6 +79,10 @@ extern "C" {
#define VB_S16 2
#define VB_U16 3
#define VB_S32 4
#define VB_F32 5
/* Option keys */
#define VB_PSEUDO_HALT 0
@@ -91,6 +96,7 @@ typedef int (*vbOnException)(VB *sim, uint16_t *cause);
typedef int (*vbOnExecute )(VB *sim, uint32_t address, const uint16_t *code, int length);
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
typedef int (*vbOnFrame )(VB *sim);
typedef int (*vbOnLink )(VB *sim1, VB *sim2, uint8_t *value1, uint8_t *value2);
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
typedef void (*vbOnSamples )(VB *sim, int16_t *buffer, uint32_t capacity);
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
@@ -101,7 +107,7 @@ typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *valu
/******************************* API Commands ********************************/
VBAPI int vbEmulate (VB *sim, uint32_t *clocks);
VBAPI int vbEmulateEx (VB **sims, int count, uint32_t *clocks);
VBAPI int vbEmulateEx (VB **sims, unsigned count, uint32_t *clocks);
VBAPI void* vbGetCallback (VB *sim, int id);
VBAPI void* vbGetCartRAM (VB *sim, uint32_t *size);
VBAPI void* vbGetCartROM (VB *sim, uint32_t *size);
@@ -110,13 +116,16 @@ VBAPI vbOnExecute vbGetExecuteCallback (VB *sim);
VBAPI vbOnFetch vbGetFetchCallback (VB *sim);
VBAPI vbOnFrame vbGetFrameCallback (VB *sim);
VBAPI uint16_t vbGetKeys (VB *sim);
VBAPI vbOnLink vbGetLinkCallback (VB *sim);
VBAPI int vbGetOption (VB *sim, int key);
VBAPI VB* vbGetPeer (VB *sim);
VBAPI void vbGetPixels (VB *sim, void *left, int leftStrideX, int leftStrideY, void *right, int rightStrideX, int rightStrideY);
VBAPI uint32_t vbGetProgramCounter (VB *sim);
VBAPI int32_t vbGetProgramRegister (VB *sim, int index);
VBAPI int32_t vbGetProgramRegister (VB *sim, unsigned index);
VBAPI vbOnRead vbGetReadCallback (VB *sim);
VBAPI void* vbGetSamples (VB *sim, uint32_t *capacity, uint32_t *position);
VBAPI void* vbGetSamples (VB *sim, int *type, unsigned *capacity, unsigned *position);
VBAPI vbOnSamples vbGetSamplesCallback (VB *sim);
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
VBAPI uint32_t vbGetSystemRegister (VB *sim, unsigned index);
VBAPI void* vbGetUserData (VB *sim);
VBAPI vbOnWrite vbGetWriteCallback (VB *sim);
VBAPI VB* vbInit (VB *sim);
@@ -128,13 +137,16 @@ VBAPI vbOnException vbSetExceptionCallback(VB *sim, vbOnException callback);
VBAPI vbOnExecute vbSetExecuteCallback (VB *sim, vbOnExecute callback);
VBAPI vbOnFetch vbSetFetchCallback (VB *sim, vbOnFetch callback);
VBAPI vbOnFrame vbSetFrameCallback (VB *sim, vbOnFrame callback);
VBAPI vbOnLink vbSetLinkCallback (VB *sim, vbOnLink callback);
VBAPI uint16_t vbSetKeys (VB *sim, uint16_t keys);
VBAPI int vbSetOption (VB *sim, int key, int value);
VBAPI void vbSetPeer (VB *sim, VB *peer);
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
VBAPI int32_t vbSetProgramRegister (VB *sim, int index, int32_t value);
VBAPI int32_t vbSetProgramRegister (VB *sim, unsigned index, int32_t value);
VBAPI vbOnRead vbSetReadCallback (VB *sim, vbOnRead callback);
VBAPI int vbSetSamples (VB *sim, void *samples, uint32_t capacity);
VBAPI int vbSetSamples (VB *sim, void *samples, int type, unsigned capacity);
VBAPI vbOnSamples vbSetSamplesCallback (VB *sim, vbOnSamples callback);
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
VBAPI uint32_t vbSetSystemRegister (VB *sim, unsigned index, uint32_t value);
VBAPI void* vbSetUserData (VB *sim, void *tag);
VBAPI vbOnWrite vbSetWriteCallback (VB *sim, vbOnWrite callback);
VBAPI size_t vbSizeOf ();
+187 -128
View File
@@ -42,18 +42,44 @@ static const uint8_t BG_TEMPLATES[][64] = {
/* 8-bit color magnitude by brightness level */
static const uint8_t BRIGHT8[] = {
0, 10, 16, 21, 25, 30, 33, 37, 40, 44, 47, 50, 53, 56, 59, 61,
64, 67, 69, 72, 74, 77, 79, 82, 84, 86, 89, 91, 93, 95, 97,100,
102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,131,
133,135,137,139,141,142,144,146,148,149,151,153,155,156,158,160,
161,163,165,166,168,170,171,173,175,176,178,179,181,183,184,186,
187,189,190,192,194,195,197,198,200,201,203,204,206,207,209,210,
212,213,215,216,217,219,220,222,223,225,226,227,229,230,232,233,
235,236,237,239,240,241,243,244,246,247,248,250,251,252,254,255
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,
129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,
161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,
193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,
225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255
};
/*********************************** Types ***********************************/
/* World attribtues per eye */
typedef struct {
int32_t bp; /* BG source parallax */
int32_t left, right; /* Window bounds */
int32_t wx; /* World horizontal position */
} EyeAttribs;
/* Parsed world attributes */
typedef struct {
int32_t base; /* Base BG map index */
uint8_t *bg; /* Background template */
int32_t bgm; /* World type */
int32_t bgw, bgh; /* Background dimension masks */
int32_t bottom, top; /* Window bounds */
int32_t gx, gp, gy; /* World screen position */
int32_t mx, mp, my; /* Background scroll */
uint8_t *over; /* Overplane character */
uint32_t params; /* Line parameters address */
int32_t scx, scy; /* Background dimensions */
int32_t w, h; /* Window size */
} WorldAttribs;
/***************************** Module Functions ******************************/
/* Retrieve a pointer to character data in host memory */
@@ -68,9 +94,8 @@ static int32_t vipReadPalette(uint8_t *entries) {
/* Raise an interrupt request */
static void vipThrow(VB *sim, uint16_t cause) {
if (!(sim->vip.intenb & cause))
return;
sim->vip.intpnd |= cause;
if (sim->vip.intenb & cause)
sim->cpu.irq |= 0x0010;
}
@@ -421,11 +446,10 @@ static void vipTransferColumn(VB *sim, int32_t eye) {
[sim->vip.dp.buffer][eye][sim->vip.dp.column];
/* Output is disabled */
if ((sim->vip.dp.disp & sim->vip.dp.synce) == 0) {
for (z = 0; z < 0x15000; z += 4) {
busWriteBuffer(dest, VB_S32, 0);
dest += 4;
}
if (!sim->vip.dp.enabled) {
for (y = 0; y < 224; y += 16)
for (z = 0; z < 16; z++, dest += 384)
*dest = 0;
return;
}
@@ -468,6 +492,7 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
case 0: /* 0ms - FCLK rising edge */
sim->vip.dp.clocks = vipClocksMs(3);
sim->vip.dp.enabled = sim->vip.dp.disp & sim->vip.dp.synce;
sim->vip.dp.fclk = 1;
sim->vip.dp.step = 1;
sim->vip.dp.until = vipClocksMs(8);
@@ -481,6 +506,7 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
/* Initiate drawing procedure */
if (sim->vip.xp.step == 0) {
sim->vip.dp.buffer ^= 1;
sim->vip.xp.enabled = 1;
sim->vip.xp.overtime = 0;
sim->vip.xp.step = 1;
vipThrow(sim, 0x0008); /* GAMESTART */
@@ -500,9 +526,11 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
/* 0ms-3ms - Idle */
case 1: /* 3ms - L*BSY rising edge */
if (sim->vip.dp.enabled) {
if (sim->vip.dp.buffer == 0)
sim->vip.dp.l0bsy = 1;
else sim->vip.dp.l1bsy = 1;
}
sim->vip.dp.column = 0;
sim->vip.dp.cta = 0x3DC00 | (uint32_t)sim->vip.cta.cta_l<<1;
sim->vip.dp.step = 2;
@@ -523,13 +551,15 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
break;
case 3: /* 8ms - L*BSY falling edge */
if (sim->vip.dp.enabled) {
if (sim->vip.dp.buffer == 0)
sim->vip.dp.l0bsy = 0;
else sim->vip.dp.l1bsy = 0;
vipThrow(sim, 0x0002); /* LFBEND */
}
sim->vip.dp.clocks = vipClocksMs(2);
sim->vip.dp.step = 4;
sim->vip.dp.until = vipClocksMs(10);
vipThrow(sim, 0x0002); /* LFBEND */
break;
/* 8ms-10ms - Idle */
@@ -543,9 +573,11 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
/* 10ms-13ms - Idle */
case 5: /* 13ms - R*BSY rising edge */
if (sim->vip.dp.enabled) {
if (sim->vip.dp.buffer == 0)
sim->vip.dp.r0bsy = 1;
else sim->vip.dp.r1bsy = 1;
}
sim->vip.dp.column = 0;
sim->vip.dp.cta = 0x3DE00 | (uint32_t)sim->vip.cta.cta_r<<1;
sim->vip.dp.step = 6;
@@ -565,19 +597,26 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
break;
case 7: /* 18ms - R*BSY falling edge */
if (sim->vip.dp.enabled) {
if (sim->vip.dp.buffer == 0)
sim->vip.dp.r0bsy = 0;
else sim->vip.dp.r1bsy = 0;
sim->vip.dp.clocks = vipClocksMs(2);
sim->vip.dp.step = 0;
sim->vip.dp.until = vipClocksMs(2);
vipThrow(sim, 0x0004); /* RFBEND */
if (vipOnFrame(sim))
return 1;
}
sim->vip.dp.clocks = vipClocksMs(2);
sim->vip.dp.enabled = 0;
sim->vip.dp.step = 8;
sim->vip.dp.until = vipClocksMs(2);
break;
/* 18ms-20ms - Idle */
case 8: /* 20ms - Display interval complete */
sim->vip.dp.step = 0;
if (vipOnFrame(sim))
return 1;
break;
}
}
@@ -588,6 +627,89 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
/****************************** Pixel Processor ******************************/
/* Parse eye attributes and test window bounds */
static int vipParseEye(WorldAttribs *wttr, EyeAttribs *ettr, int eye) {
/* Validate the world isn't right of frame */
ettr->wx = wttr->gx - (eye == 0 ? wttr->gp : -wttr->gp);
if (ettr->wx > 383)
return 1;
ettr->left = ettr->wx < 0 ? 0 : ettr->wx;
/* Validate the world isn't left of frame */
ettr->right = ettr->wx + wttr->w - 1;
if (ettr->right < 0)
return 1;
if (ettr->right > 383)
ettr->right = 383;
/* BG source parallax */
if (wttr->bgm != 2)
ettr->bp = eye == 0 ? -wttr->mp : wttr->mp;
return 0;
}
/* Parse world attributes and test window bounds */
static int vipParseWorld(VB*sim,uint8_t*world,uint16_t bits,WorldAttribs*attr){
int32_t z; /* Scratch */
/* Validate the world isn't below the frame */
attr->gy = busReadBuffer(world + 6, VB_S16);
if (attr->gy > 223)
return 1;
/* Validate the world isn't above the frame, and height is positive */
attr->bgm = bits >> 12 & 3;
attr->h = busReadBuffer(world + 16, VB_S16) + 1;
z = attr->bgm == 2 ? 0 : 8;
if (attr->h < z)
attr->h = z;
if (attr->h == 0)
return 1;
attr->bottom = attr->gy + attr->h - 1;
attr->top = (int32_t) sim->vip.xp.sbcount << 3;
if (attr->bottom < attr->top)
return 1;
if (attr->bottom > 223)
attr->bottom = 223;
if (attr->top < attr->gy)
attr->top = attr->gy;
/* Validate width is positive */
attr->w = SignExtend(busReadBuffer(world + 14, VB_U16),
attr->bgm == 2 ? 10 : 13) + 1;
if (attr->w < 1)
return 1;
/* Parse attributes */
attr->bg = (uint8_t *) BG_TEMPLATES[bits >> 8 & 15];
attr->gx = SignExtend(busReadBuffer(world + 2, VB_U16), 10);
attr->gp = SignExtend(busReadBuffer(world + 4, VB_U16), 10);
attr->over = (bits & 0x0080) == 0 ? NULL :
&sim->vip.ram[0x00020000 | busReadBuffer(world + 10, VB_U16) << 1];
attr->scx = bits >> 10 & 3;
attr->scy = bits >> 8 & 3;
attr->bgw = (1 << attr->scx) - 1;
attr->bgh = (1 << attr->scy) - 1;
z = attr->scx + attr->scy;
attr->base = bits & 15 & ~((1 << (z < 3 ? z : 3)) - 1);
if (attr->bgm != 2) {
attr->mx = SignExtend(busReadBuffer(world + 8, VB_U16), 13);
attr->mp = SignExtend(busReadBuffer(world + 10, VB_U16), 15);
attr->my = SignExtend(busReadBuffer(world + 12, VB_U16), 13);
}
if (attr->bgm != 0) {
attr->params =
0x20000 +
(attr->top - attr->gy) * (attr->bgm == 1 ? 4 : 16) +
((uint32_t) busReadBuffer(world + 18, VB_U16) << 1)
;
}
return 0;
}
/* Draw an object group into shadow memory */
static void vipDrawObjects(VB *sim, int group) {
uint8_t *dest; /* Pointer to object position in shadow memory */
@@ -678,124 +800,56 @@ static void vipDrawObjects(VB *sim, int group) {
}
/* Draw a background world into shadow memory */
static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) {
uint8_t *bg; /* Background arrangement */
static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t bits) {
uint16_t bgAttr; /* BG map cell attributes */
int32_t bgh; /* Height of background in BG maps, minus 1 */
int32_t bgw; /* Width of background in BG maps, minus 1 */
int32_t bottom; /* Window bottom edge position */
int32_t bp; /* Eye BG map source parallax */
int32_t bx; /* BG horizontal map source position */
int32_t by; /* BG vertical map source position */
int32_t bx; /* BG source X */
int32_t by; /* BG source Y */
uint8_t *cell; /* Pointer to BG map cell in host memory */
uint8_t *chr; /* Pointer to character data in host memory */
int32_t cx; /* BG cell/character horizontal pixel source position */
int32_t cy; /* BG cell/character vertical pixel source position */
int32_t cx; /* BG cell/character source X */
int32_t cy; /* BG cell/character source Y */
uint8_t *dest; /* Pointer to output in shadow memory */
int32_t left; /* Window left edge position */
EyeAttribs ettr; /* Eye attributes */
uint32_t param; /* Current line parameter address */
int8_t pixel; /* Character pixel value */
int32_t right; /* Window right edge position */
int32_t top; /* Window top edge position */
int32_t wx; /* Eye horizontal position */
int32_t i, x, y; /* Iterators */
/* World attributes */
int32_t base; /* BG map base index */
int bgm; /* BG mode */
WorldAttribs wttr; /* Common attributes */
int32_t dx; /* Affine per-pixel X delta */
int32_t dy; /* Affine per-pixel Y delta */
int16_t gp; /* Window stereo parallax */
int16_t gx; /* Window base horizontal position */
int16_t gy; /* Window vertical position */
int16_t h; /* Window height */
int32_t mp; /* BG source parallax */
int32_t mx; /* BG source X */
int32_t my; /* BG source Y */
int16_t hofst; /* H-bias shift */
int32_t mp; /* BG map source stereo parallax */
int32_t mx = 0; /* BG map horizontal source */
int32_t my = 0; /* BG map vertical source */
int32_t scx; /* Background width shift amount */
int32_t scy; /* Background height shift amount */
uint8_t *over; /* Pointer to overplane "cell" in host memory */
uint32_t params = 0; /* Base address of line parameters */
int16_t w; /* Window width */
/* Validate the world isn't below the frame */
gy = busReadBuffer(world + 6, VB_S16);
if (gy > 223)
return;
/* Validate the world isn't above the frame, and height is positive */
bgm = attr >> 12 & 3;
y = bgm == 2 ? 0 : 8;
h = busReadBuffer(world + 16, VB_S16) + 1;
if (h < y)
h = y;
if (h == 0)
return;
bottom = gy + h - 1;
top = (int32_t) sim->vip.xp.sbcount << 3;
if (bottom < top)
return;
if (bottom > 223)
bottom = 223;
if (top < gy)
top = gy;
/* Validate width is positive */
w = SignExtend(busReadBuffer(world + 14, VB_U16), bgm == 2 ? 10 : 13) + 1;
if (w < 1)
return;
/* Working variables */
ettr.bp = wttr.mp = wttr.mx = wttr.my = wttr.params = 0;
/* Parse attributes */
bg = (uint8_t *) BG_TEMPLATES[attr >> 8 & 15];
gx = SignExtend(busReadBuffer(world + 2, VB_U16), 10);
gp = SignExtend(busReadBuffer(world + 4, VB_U16), 10);
over = (attr & 0x0080) ? world + 20 : NULL;
scx = attr >> 10 & 3;
scy = attr >> 8 & 3;
bgw = (1 << scx) - 1;
bgh = (1 << scy) - 1;
base = attr & 15 & ~((1 << (scx + scy < 3 ? scx + scy : 3)) - 1);
if (bgm != 2) {
mx = SignExtend(busReadBuffer(world + 8, VB_U16), 13);
mp = SignExtend(busReadBuffer(world + 10, VB_U16), 15);
my = SignExtend(busReadBuffer(world + 12, VB_U16), 13);
}
if (bgm != 0) {
params = 0x20000 + (top - gy) * (bgm == 1 ? 4 : 16) +
((uint32_t) busReadBuffer(world + 18, VB_U16) << 1);
}
else hofst = 0;
if (vipParseWorld(sim, world, bits, &wttr))
return; /* Window not in frame */
/* Draw the world */
for (i = 0; i < 2; i++) {
/* Validate world is enabled */
if ((attr & (int32_t) 0x8000 >> i) == 0) /* LON, RON */
/* World is not visible */
if ((bits & (int32_t) 0x8000 >> i) == 0) /* LON, RON */
continue;
/* Validate the world isn't right of frame */
wx = gx - (i == 0 ? gp : -gp);
if (wx > 383)
return;
left = wx < 0 ? 0 : wx;
/* Validate the world isn't left of frame */
right = wx + w - 1;
if (right < 0)
return;
if (right > 383)
right = 383;
/* BG source parallax */
if (bgm != 2)
bp = i == 0 ? -mp : mp;
/* Process attributes */
if (vipParseEye(&wttr, &ettr, i))
continue;
/* Draw all rows */
for (y = top, param = params; y <= bottom; y++) {
for (y = wttr.top, param = wttr.params; y <= wttr.bottom; y++) {
/* Parse line parameters */
switch (bgm) {
hofst = 0;
mp = wttr.mp;
mx = wttr.mx;
my = wttr.my;
switch (wttr.bgm) {
case 1: /* H-bias */
hofst = SignExtend(vipParam(param | i << 1), 13);
param += 4;
@@ -804,22 +858,22 @@ static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) {
dx = (int32_t) (int16_t) vipParam(param|6) << 7;
dy = (int32_t) (int16_t) vipParam(param|8) << 7;
mp = (int32_t) (int16_t) vipParam(param|2);
mp = left - wx - ((mp < 0) ^ i ? mp : 0);
mp = ettr.left - ettr.wx - ((mp < 0) ^ i ? mp : 0);
mx = ((int32_t) (int16_t) vipParam(param ) << 13) + dx*mp;
my = ((int32_t) (int16_t) vipParam(param|4) << 13) + dy*mp;
param += 16;
}
/* Select output in shadow memory */
dest = &sim->vip.shadow[i][left * 224 + y];
dest = &sim->vip.shadow[i][ettr.left * 224 + y];
/* Draw all columns */
for (x = left; x <= right; x++, dest += 224) {
for (x = ettr.left; x <= ettr.right; x++, dest += 224) {
/* Locate the pixel in the background */
if (bgm != 2) { /* Normal, H-bias */
cx = x - wx + mx + bp + hofst;
cy = y - gy + my;
if (wttr.bgm != 2) { /* Normal, H-bias */
cx = x - ettr.wx + mx + ettr.bp + hofst;
cy = y - wttr.gy + my;
} else { /* Affine */
cx = (int16_t) (mx >> 16);
cy = (int16_t) (my >> 16);
@@ -833,19 +887,23 @@ static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) {
cell = NULL;
/* BG map is out of bounds */
if (bx < 0 || bx > bgw || by < 0 || by > bgh) {
if (over == NULL) {
bx &= bgw;
by &= bgh;
}
else cell = over;
if (
bx < 0 || bx > wttr.bgw ||
by < 0 || by > wttr.bgh
) {
if (wttr.over == NULL) {
bx &= wttr.bgw;
by &= wttr.bgh;
} else cell = wttr.over;
}
/* Locate the cell in the BG map */
if (cell == NULL) {
cell = &sim->vip.ram[
0x20000 |
(base + bg[by << scx | bx]) << 13 |
0x20000 | ((
wttr.base +
wttr.bg[by << wttr.scx | bx]
) << 13) |
(cy << 4 & 0x1F80) |
(cx >> 2 & 0x007E)
];
@@ -1008,6 +1066,7 @@ static void vipEmulateDrawing(VB *sim, uint32_t clocks) {
break;
case 4: /* Drawing complete */
sim->vip.xp.enabled = 0;
sim->vip.xp.step = 0;
if (sim->vip.dp.buffer == 0)
sim->vip.xp.f1bsy = 0;
+25 -6
View File
@@ -164,7 +164,7 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) {
if (!chan->int_.enb)
return;
sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval *
(sim->vsu.freqmod.clk == 0 ? 19201 : 153610);
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
}
} while (clocks != 0);
@@ -207,6 +207,8 @@ static void vsuWriteEV0(VB *sim, int index, uint8_t value) {
chan->env.interval = value & 7;
chan->env.value = value >> 4 & 15;
chan->env.reload = chan->env.value;
if (index == 4)
vsuNextFreqMod(sim, chan);
/* Configure state */
chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1);
@@ -243,6 +245,8 @@ static void vsuWriteFQH(VB *sim, int index, uint16_t value) {
value = value << 8 & 0x0700;
chan->freq.current = (chan->freq.current & 0x00FF) | value;
chan->freq.written = (chan->freq.written & 0x00FF) | value;
if (index == 4)
vsuNextFreqMod(sim, chan);
}
/* Write a value to S*FQL */
@@ -250,6 +254,8 @@ static void vsuWriteFQL(VB *sim, int index, uint8_t value) {
Channel *chan = &sim->vsu.channels[index];
chan->freq.current = (chan->freq.current & 0x0700) | value;
chan->freq.written = (chan->freq.written & 0x0700) | value;
if (index == 4)
vsuNextFreqMod(sim, chan);
}
/* Write a value to S*INT */
@@ -274,7 +280,7 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) {
}
if (index == 4) {
sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval *
(sim->vsu.freqmod.clk ? 153610 : 19201);
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
sim->vsu.freqmod.sample = 0;
}
@@ -299,12 +305,12 @@ static void vsuWriteSWP(VB *sim, uint8_t value) {
/* Parse fields */
sim->vsu.freqmod.clk = value >> 7 & 1;
sim->vsu.freqmod.dir = value >> 3 & 1;
sim->vsu.freqmod.interval = value >> 4 & 15;
sim->vsu.freqmod.interval = value >> 4 & 7;
sim->vsu.freqmod.shift = value & 7;
/* Configure state */
clocks = (uint32_t) sim->vsu.freqmod.interval *
(sim->vsu.freqmod.clk ? 153610 : 19201);
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
if (clocks < sim->vsu.freqmod.clocks)
sim->vsu.freqmod.clocks = clocks;
}
@@ -362,8 +368,21 @@ static void vsuEmulate(VB *sim, uint32_t clocks) {
sim->vsu.out.samples != NULL &&
sim->vsu.out.offset >> 1 < sim->vsu.out.capacity
) {
sim->vsu.out.samples[sim->vsu.out.offset++] =
(int16_t) (o0 * 32767.0f + (o0 < 0.0f ? -0.5f : +0.5f));
/* Processing by data type*/
switch (sim->vsu.out.type) {
case VB_S16:
((int16_t *) sim->vsu.out.samples)
[sim->vsu.out.offset++] = (int16_t)
(o0 * 32767.0f + (o0 < 0.0f ? -0.5f : +0.5f));
break;
case VB_F32:
((float *) sim->vsu.out.samples)
[sim->vsu.out.offset++] = o0;
break;
}
/* Invoke the samples callback */
if (
e == 1 &&
sim->vsu.out.offset >> 1 == sim->vsu.out.capacity
+24 -5
View File
@@ -10,6 +10,7 @@ help:
@echo "Available make targets:"
@echo " clean Remove output files"
@echo " core Check the C core source for compiler warnings"
@echo " util Check the C utility source for compiler warnings"
@echo " wasm Build the WebAssembly module"
@echo
@@ -29,7 +30,7 @@ core:
-D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \
-D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \
-D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_SAMPLES=testSamples \
-D VB_DIRECT_READ=testRead
-D VB_DIRECT_READ=testRead -D VB_DIRECT_LINK=testLink
# Clang generic
@emcc core/vb.c -I core -c -o /dev/null -O3 \
-Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing
@@ -40,14 +41,32 @@ core:
-D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \
-D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \
-D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_SAMPLES=testSamples \
-D VB_DIRECT_READ=testRead
-D VB_DIRECT_READ=testRead -D VB_DIRECT_LINK=testLink
.PHONY: util
util:
# GCC generic
@gcc util/vbu.c -I core -I util -c -o /dev/null -O3 \
-Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing
# GCC compilation control
@gcc util/vbu.c -I core -I util -c -o /dev/null -O3 \
-Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing \
-D VB_SIGNED_PROPAGATE -D VBU_REALLOC=testRealloc
# Clang generic
@emcc util/vbu.c -I core -I util -c -o /dev/null -O3 \
-Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing
# Clang compilation control
@emcc util/vbu.c -I core -I util -c -o /dev/null -O3 \
-Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing \
-D VB_SIGNED_PROPAGATE -D VBU_REALLOC=testRealloc
.PHONY: wasm
wasm:
@emcc -o web/core.wasm web/wasm.c core/vb.c -I core \
@emcc -o web/core.wasm web/wasm.c core/vb.c util/vbu.c -I core -I util \
-D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE \
-D "VBAPI=__attribute__((used))" \
--no-entry -O2 -flto -s WASM=1 -s WARN_ON_UNDEFINED_SYMBOLS=0 \
-D "VBAPI=__attribute__((used))" -D "VBUAPI=__attribute__((used))" \
-D VB_DIRECT_FRAME=wasmOnFrame \
--no-entry -O2 -flto -s WASM=1 \
-s EXPORTED_RUNTIME_METHODS=[] -s ALLOW_MEMORY_GROWTH \
-s MAXIMUM_MEMORY=4GB -fno-strict-aliasing
@rm -f web/*.wasm.tmp*
+694
View File
@@ -0,0 +1,694 @@
/* This file is included into vb.c and cannot be compiled on its own. */
#ifdef VBUAPI
/********************************* Constants *********************************/
/* Operand types */
#define DASM_BCOND 0
#define DASM_DISP9 1
#define DASM_DISP26 2
#define DASM_IMM5S 3
#define DASM_IMM5U 4
#define DASM_IMM16S 5
#define DASM_IMM16U 6
#define DASM_JMP 7
#define DASM_MEMORY 8
#define DASM_REG1 9
#define DASM_REG2 10
#define DASM_SETF 11
#define DASM_SYSTEM 12
/******************************** Lookup Data ********************************/
/* Instruction descriptor */
typedef struct {
char mnemonic[8]; /* Mnemonic, uppercase */
uint8_t operandsLength; /* Number of operands */
uint8_t operands[3]; /* Operand types */
} OpDef;
/* Instruction descriptors */
static const OpDef OPDEFS[] = {
{ "MOV" , 2, { DASM_REG1, DASM_REG2 } }, /* 000000 */
{ "ADD" , 2, { DASM_REG1, DASM_REG2 } },
{ "SUB" , 2, { DASM_REG1, DASM_REG2 } },
{ "CMP" , 2, { DASM_REG1, DASM_REG2 } },
{ "SHL" , 2, { DASM_REG1, DASM_REG2 } },
{ "SHR" , 2, { DASM_REG1, DASM_REG2 } },
{ "JMP" , 1, { DASM_JMP } },
{ "SAR" , 2, { DASM_REG1, DASM_REG2 } },
{ "MUL" , 2, { DASM_REG1, DASM_REG2 } },
{ "DIV" , 2, { DASM_REG1, DASM_REG2 } },
{ "MULU" , 2, { DASM_REG1, DASM_REG2 } },
{ "DIVU" , 2, { DASM_REG1, DASM_REG2 } },
{ "OR" , 2, { DASM_REG1, DASM_REG2 } },
{ "AND" , 2, { DASM_REG1, DASM_REG2 } },
{ "XOR" , 2, { DASM_REG1, DASM_REG2 } },
{ "NOT" , 1, { DASM_REG1 } },
{ "MOV" , 2, { DASM_IMM5S, DASM_REG2 } }, /* 010000 */
{ "ADD" , 2, { DASM_IMM5S, DASM_REG2 } },
{ "" , 0, { 0 } }, /* SETF */
{ "CMP" , 2, { DASM_IMM5S, DASM_REG2 } },
{ "SHL" , 2, { DASM_IMM5U, DASM_REG2 } },
{ "SHR" , 2, { DASM_IMM5U, DASM_REG2 } },
{ "CLI" , 0, { 0 } },
{ "SAR" , 2, { DASM_IMM5U, DASM_REG2 } },
{ "TRAP" , 1, { DASM_IMM5U } },
{ "RETI" , 0, { 0 } },
{ "HALT" , 0, { 0 } },
{ "---" , 0, { 0 } },
{ "LDSR" , 2, { DASM_REG2, DASM_SYSTEM } },
{ "STSR" , 2, { DASM_SYSTEM, DASM_REG2 } },
{ "SEI" , 0, { 0 } },
{ "" , 0, { 0 } }, /* Bit string */
{ "" , 0, { 0 } }, /* BCOND */ /* 100000 */
{ "" , 0, { 0 } }, /* BCOND */
{ "" , 0, { 0 } }, /* BCOND */
{ "" , 0, { 0 } }, /* BCOND */
{ "" , 0, { 0 } }, /* BCOND */
{ "" , 0, { 0 } }, /* BCOND */
{ "" , 0, { 0 } }, /* BCOND */
{ "" , 0, { 0 } }, /* BCOND */
{ "MOVEA", 3, { DASM_IMM16U, DASM_REG1, DASM_REG2 } },
{ "ADDI" , 3, { DASM_IMM16S, DASM_REG1, DASM_REG2 } },
{ "JR" , 1, { DASM_DISP26 } },
{ "JAL" , 1, { DASM_DISP26 } },
{ "ORI" , 3, { DASM_IMM16U, DASM_REG1, DASM_REG2 } },
{ "ANDI" , 3, { DASM_IMM16U, DASM_REG1, DASM_REG2 } },
{ "XORI" , 3, { DASM_IMM16U, DASM_REG1, DASM_REG2 } },
{ "MOVHI", 3, { DASM_IMM16U, DASM_REG1, DASM_REG2 } },
{ "LD.B" , 2, { DASM_MEMORY, DASM_REG2 } }, /* 110000 */
{ "LD.H" , 2, { DASM_MEMORY, DASM_REG2 } },
{ "---" , 0, { 0 } },
{ "LD.W" , 2, { DASM_MEMORY, DASM_REG2 } },
{ "ST.B" , 2, { DASM_REG2, DASM_MEMORY } },
{ "ST.H" , 2, { DASM_REG2, DASM_MEMORY } },
{ "---" , 0, { 0 } },
{ "ST.W" , 2, { DASM_REG2, DASM_MEMORY } },
{ "IN.B" , 2, { DASM_MEMORY, DASM_REG2 } },
{ "IN.H" , 2, { DASM_MEMORY, DASM_REG2 } },
{ "CAXI" , 0, { DASM_MEMORY, DASM_REG2 } },
{ "IN.W" , 2, { DASM_MEMORY, DASM_REG2 } },
{ "OUT.B", 2, { DASM_REG2, DASM_MEMORY } },
{ "OUT.H", 2, { DASM_REG2, DASM_MEMORY } },
{ "" , 0, { 0 } }, /* Floating-point/Nintendo */
{ "OUT.W", 2, { DASM_REG2, DASM_MEMORY } }
};
/* Bit string instruction descriptors */
static const OpDef OPDEFS_BITSTRING[] = {
{ "SCH0BSU", 0, { 0 } }, /* 00000 */
{ "SCH0BSD", 0, { 0 } },
{ "SCH1BSU", 0, { 0 } },
{ "SCH1BSD", 0, { 0 } },
{ "---" , 0, { 0 } },
{ "---" , 0, { 0 } },
{ "---" , 0, { 0 } },
{ "---" , 0, { 0 } },
{ "ORBSU" , 0, { 0 } },
{ "ANDBSU" , 0, { 0 } },
{ "XORBSU" , 0, { 0 } },
{ "MOVBSU" , 0, { 0 } },
{ "ORNBSU" , 0, { 0 } },
{ "ANDNBSU", 0, { 0 } },
{ "XORNBSU", 0, { 0 } },
{ "NOTBSU" , 0, { 0 } }
/* +16 invalid opcodes */
};
/* Floating-point/Nintendo instruction descriptors */
static const OpDef OPDEFS_FLOATENDO[] = {
{ "CMPF.S" , 2, { DASM_REG1, DASM_REG2 } },
{ "---" , 0, { 0 } },
{ "CVT.WS" , 2, { DASM_REG1, DASM_REG2 } },
{ "CVT.SW" , 2, { DASM_REG1, DASM_REG2 } },
{ "ADDF.S" , 2, { DASM_REG1, DASM_REG2 } },
{ "SUBF.S" , 2, { DASM_REG1, DASM_REG2 } },
{ "MULF.S" , 2, { DASM_REG1, DASM_REG2 } },
{ "DIVF.S" , 2, { DASM_REG1, DASM_REG2 } },
{ "XB" , 1, { DASM_REG2 } },
{ "XH" , 1, { DASM_REG2 } },
{ "REV" , 2, { DASM_REG1, DASM_REG2 } },
{ "TRNC.SW", 2, { DASM_REG1, DASM_REG2 } },
{ "MPYHW" , 2, { DASM_REG1, DASM_REG2 } },
/* +51 invalid opcodes */
};
/* Invalid instruction descriptors */
static const OpDef OPDEF_ILLEGAL = { "---", 0, { 0 } };
/***************************** Module Functions ******************************/
/* Select the display text for a condition */
static char* dasmCondition(VBU_DasmConfig *config, int cond) {
switch (cond) {
case 0: return "V" ;
case 1: return config->conditionCL == VBU_C ? "C" : "L";
case 2: return config->conditionEZ == VBU_E ? "E" : "Z";
case 3: return "NH";
case 4: return "N" ;
case 5: return "T" ;
case 6: return "LT";
case 7: return "LE";
case 8: return "NV";
case 9: return config->conditionCL == VBU_C ? "NC" : "NL";
case 10: return config->conditionEZ == VBU_E ? "NE" : "NZ";
case 11: return "H" ;
case 12: return "P" ;
case 13: return "F" ;
case 14: return "GE";
}
return "GT";
}
/* Format a number as hexadecimal */
static void dasmToHex(char *dest, VBU_DasmConfig *config,
int minDigits, int32_t value) {
char format[9];
char *prefix = "";
char *suffix = "";
switch (config->hexNotation) {
case VBU_0X : prefix = "0x"; break;
case VBU_DOLLAR: prefix = "$" ; break;
case VBU_H : suffix = "h" ; break;
}
sprintf(format, "%%s%%0%d%s%%s", minDigits,
config->hexCase == VBU_LOWER ? "x" : "X");
sprintf(dest, format, prefix, value, suffix);
if (config->hexNotation != VBU_H || *dest <= '9')
return;
*dest++ = '0';
sprintf(dest, format, prefix, value, suffix);
}
/* Convert a string to lowercase */
static void dasmToLower(char *str) {
for (; *str; str++) {
if (*str >= 'A' && *str <= 'Z')
*str += 'a' - 'A';
}
}
/* Format a program register */
static void dasmProgram(char *dest, VBU_DasmConfig *config, int id) {
char *text = NULL;
if (config->programNotation != VBU_NUMBERS) {
switch (id) {
case 2: text = "HP"; break;
case 3: text = "SP"; break;
case 4: text = "GP"; break;
case 5: text = "TP"; break;
case 31: text = "LP"; break;
}
}
if (text == NULL)
sprintf(dest, "R%d", id);
else strcpy(dest, text);
if (config->programCase == VBU_LOWER)
dasmToLower(dest);
}
/**************************** Operand Formatters *****************************/
/* Format the condition operand of a split BCOND instruction */
static void dasmOpBCOND(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int cond = line->code[1] >> 2 & 15;
if (config->conditionNotation == VBU_NUMBERS)
sprintf(dest, "%d", cond);
else {
strcpy(dest, dasmCondition(config, cond));
if (config->conditionCase == VBU_LOWER)
dasmToLower(dest);
}
}
/* Format a 9-bit displacement operand */
static void dasmOpDisp9(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int32_t disp = SignExtend((int32_t) line->code[1] << 8 | line->code[0], 9);
sprintf(dest, config->hexCase == VBU_LOWER ?
"%08x" : "%08X", line->address + disp);
}
/* Format a 26-bit displacement operand */
static void dasmOpDisp26(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int32_t disp = SignExtend(
(int32_t) line->code[1] << 24 |
(int32_t) line->code[0] << 16 |
(int32_t) line->code[3] << 8 |
line->code[2]
, 26);
sprintf(dest, config->hexCase == VBU_LOWER ?
"%08x" : "%08X", line->address + disp);
}
/* Format a 5-bit sign-extended immediate operand */
static void dasmOpImm5S(char *dest, VBU_DasmLine *line) {
sprintf(dest, "%d", SignExtend(line->code[0], 5));
}
/* Format a 5-bit zero-filled immediate operand */
static void dasmOpImm5U(char *dest, VBU_DasmLine *line) {
sprintf(dest, "%d", line->code[0] & 31);
}
/* Format a 16-bit sign-extended immediate operand */
static void dasmOpImm16S(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int32_t imm = (int16_t) ((int16_t) line->code[3] << 8 | line->code[2]);
if (imm >= -256 && imm <= 256) {
sprintf(dest, "%d", imm);
return;
}
if (imm < 0) {
*dest++ = '-';
imm = -imm;
}
dasmToHex(dest, config, 0, imm);
}
/* Format a 16-bit zero-filled immediate operand */
static void dasmOpImm16U(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
uint16_t imm = (uint16_t) line->code[3] << 8 | line->code[2];
dasmToHex(dest, config, 4, imm);
}
/* Format the operand of a JMP instruction */
static void dasmOpJMP(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
*dest++ = '[';
dasmProgram(dest, config, line->code[0] & 31);
strcat(dest, "]");
}
/* Format a memory operand */
static void dasmOpMemory(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int reg1 = line->code[0] & 31;
int32_t disp = (int16_t) ((int16_t) line->code[3] << 8 | line->code[2]);
/* Displacement of zero */
if (disp == 0) {
*dest++ = '[';
dasmProgram(dest, config, reg1);
strcat(dest, "]");
return;
}
/* Inside */
if (config->memoryNotation == VBU_INSIDE) {
*dest++ = '[';
dasmProgram(dest, config, reg1);
dest += strlen(dest);
if (disp < 0) {
strcpy(dest, " - ");
disp = -disp;
} else strcpy(dest, " + ");
dest += 3;
if (disp <= 256)
sprintf(dest, "%d", disp);
else dasmToHex(dest, config, 0, disp);
strcat(dest, "]");
}
/* Outside */
else {
if (disp < 0) {
*dest++ = '-';
disp = -disp;
}
if (disp <= 256)
sprintf(dest, "%d", disp);
else dasmToHex(dest, config, 0, disp);
dest += strlen(dest);
*dest++ = '[';
dasmProgram(dest, config, reg1);
strcat(dest, "]");
}
}
/* Format a source register operand */
static void dasmOpReg1(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
dasmProgram(dest, config, line->code[0] & 31);
}
/* Format a destination register operand */
static void dasmOpReg2(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
dasmProgram(dest, config,
((uint16_t) line->code[1] << 8 | line->code[0]) >> 5 & 31);
}
/* Format the condition operand of a split SETF instruction */
static void dasmOpSETF(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int cond = line->code[0] & 15;
if (config->conditionNotation == VBU_NUMBERS)
sprintf(dest, "%d", cond);
else {
strcpy(dest, dasmCondition(config, cond));
if (config->conditionCase == VBU_LOWER)
dasmToLower(dest);
}
}
/* Format a system register operand */
static void dasmOpSystem(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
int id = line->code[0] & 31;
char *text = NULL;
if (config->systemNotation != VBU_NUMBERS) {
switch (id) {
case 0: text = "EIPC" ; break;
case 1: text = "EIPSW"; break;
case 2: text = "FEPC" ; break;
case 3: text = "FEPSW"; break;
case 4: text = "ECR" ; break;
case 5: text = "PSW" ; break;
case 6: text = "PIR" ; break;
case 7: text = "TKCW" ; break;
case 24: text = "CHCW" ; break;
case 25: text = "ADTRE"; break;
}
}
if (text == NULL) {
sprintf(dest, "%d", id);
return;
}
strcpy(dest, text);
if (config->systemCase == VBU_LOWER)
dasmToLower(dest);
}
/***************************** Module Functions ******************************/
/* Prepare an OpDef for a BCOND instruction */
static OpDef* dasmBCOND(VBU_DasmConfig *config,
VBU_DasmLine *line, OpDef *opdef) {
int cond; /* Condition code */
char *text; /* Mnemonic text */
/* Split notation */
if (config->bcondNotation == VBU_SPLIT) {
strcpy(opdef->mnemonic, "BCOND");
opdef->operandsLength = 2;
opdef->operands[0] = DASM_BCOND;
opdef->operands[1] = DASM_DISP9;
return opdef;
}
/* Joined notation */
cond = line->code[1] >> 1 & 15;
switch (cond) {
case 0: text = "BV" ; break;
case 1: text = config->conditionCL == VBU_C ? "BC" : "BL"; break;
case 2: text = config->conditionEZ == VBU_E ? "BE" : "BZ"; break;
case 3: text = "BNH"; break;
case 4: text = "BN" ; break;
case 5: text = "BR" ; break;
case 6: text = "BLT"; break;
case 7: text = "BLE"; break;
case 8: text = "BNV"; break;
case 9: text = config->conditionCL == VBU_C ? "BNC" : "BNL"; break;
case 10: text = config->conditionEZ == VBU_E ? "BNE" : "BNZ"; break;
case 11: text = "BH" ; break;
case 12: text = "BP" ; break;
case 13: text = "NOP"; break;
case 14: text = "BGE"; break;
default: text = "BGT";
}
strcpy(opdef->mnemonic, text);
opdef->operandsLength = cond != 13;
opdef->operands[0] = DASM_DISP9;
return opdef;
}
/* Ensure an output buffer matches the required size */
static VBU_DasmLine* dasmGrow(
VBU_DasmLine **lines, size_t *size, size_t target, unsigned index) {
if (*size < target) {
while (*size < target)
*size *= 2;
*lines = VBU_REALLOC(*lines, *size);
}
return *lines == NULL ? NULL : &(*lines)[index];
}
/* Determine the size of an instruction */
static uint32_t dasmInstSize(VB *sim, uint32_t address) {
unsigned opcode = vbRead(sim, address, VB_U16) >> 10 & 63;
return opcode < 0x20 || opcode == 0x32 || opcode == 0x36 ? 2 : 4;
}
/* Format an operand */
static void dasmOperand(char *dest, VBU_DasmConfig *config,
VBU_DasmLine *line, uint8_t type) {
switch (type) {
case DASM_BCOND : dasmOpBCOND (dest, config, line); break;
case DASM_DISP9 : dasmOpDisp9 (dest, config, line); break;
case DASM_DISP26: dasmOpDisp26(dest, config, line); break;
case DASM_IMM5S : dasmOpImm5S (dest, line); break;
case DASM_IMM5U : dasmOpImm5U (dest, line); break;
case DASM_IMM16S: dasmOpImm16S(dest, config, line); break;
case DASM_IMM16U: dasmOpImm16U(dest, config, line); break;
case DASM_JMP : dasmOpJMP (dest, config, line); break;
case DASM_MEMORY: dasmOpMemory(dest, config, line); break;
case DASM_REG1 : dasmOpReg1 (dest, config, line); break;
case DASM_REG2 : dasmOpReg2 (dest, config, line); break;
case DASM_SETF : dasmOpSETF (dest, config, line); break;
case DASM_SYSTEM: dasmOpSystem(dest, config, line); break;
}
}
/* Prepare an OpDef for a SETF instruction */
static OpDef* dasmSETF(VBU_DasmConfig *config,
VBU_DasmLine *line, OpDef *opdef) {
/* Split notation */
if (config->bcondNotation == VBU_SPLIT) {
strcpy(opdef->mnemonic, "SETF");
opdef->operandsLength = 2;
opdef->operands[0] = DASM_SETF;
opdef->operands[1] = DASM_REG2;
return opdef;
}
/* Joined notation */
sprintf(opdef->mnemonic, "SETF%s",
dasmCondition(config, line->code[1] >> 1 & 15));
opdef->operandsLength = 1;
opdef->operands[0] = DASM_REG2;
return opdef;
}
/* Disassemble one instruction */
static int dasmLine(VB *sim, uint32_t *address, uint32_t pc,
VBU_DasmConfig *config, VBU_DasmLine **lines, size_t *size, size_t *offset,
unsigned index) {
char *dest; /* Text output pointer */
char *format; /* Hexadecimal format string */
VBU_DasmLine *line; /* Output line */
size_t more; /* Number of bytes to output */
OpDef *opdef; /* Instruction descriptor */
OpDef special; /* Special-case descriptor */
char tAddress[9]; /* Address display text */
char tCode[4][3]; /* Code display text */
char tMnemonic[8]; /* Mnemonic display text */
char tOperands[3][15]; /* Operands display text */
uint32_t x; /* Scratch and iterator */
/* Process non-text members */
line = &(*lines)[index];
line->address = *address;
line->codeLength = dasmInstSize(sim, *address);
line->isPC = *address == pc;
for (x = 0; x < line->codeLength; x++)
line->code[x] = vbRead(sim, *address + x, VB_U8);
*address += pc - *address < line->codeLength ?
pc - *address : line->codeLength;
/* Do not process text members */
if (config == NULL) {
line->text.address = NULL;
line->text.mnemonic = NULL;
line->text.operandsLength = 0;
for (x = 0; x < line->codeLength; x++)
line->text.code[x] = NULL;
return 0;
}
/* Select instruction descriptor */
x = line->code[1] >> 2 & 63;
switch (x) {
case 0x12: /* SETF */
opdef = dasmSETF(config, line, &special);
break;
case 0x1F: /* Bit string */
x = line->code[0] & 31;
opdef = (OpDef *) (x < 16 ? &OPDEFS_BITSTRING[x] : &OPDEF_ILLEGAL);
break;
case 0x20: case 0x21: case 0x22: case 0x23: /* BCOND */
case 0x24: case 0x25: case 0x26: case 0x27:
opdef = dasmBCOND(config, line, &special);
break;
case 0x3E: /* Floating-point/Nintendo */
x = line->code[3] >> 2 & 63;
opdef = (OpDef *) (x < 13 ? &OPDEFS_FLOATENDO[x] : &OPDEF_ILLEGAL);
break;
default: opdef = (OpDef *) &OPDEFS[x]; /* Other */
}
/* Address */
format = config->hexCase == VBU_LOWER ? "%08x" : "%08X";
sprintf(tAddress, format, line->address);
more = 9;
/* Code */
format = config->hexCase == VBU_LOWER ? "%02x" : "%02X";
for (x = 0; x < line->codeLength; x++) {
sprintf(tCode[x], format, (int) line->code[x]);
more += 3;
}
/* Mnemonic */
strcpy(tMnemonic, opdef->mnemonic);
if (config->mnemonicCase == VBU_LOWER)
dasmToLower(tMnemonic);
more += strlen(tMnemonic) + 1;
/* Operands */
line->text.operandsLength = opdef->operandsLength;
for (x = 0; x < opdef->operandsLength; x++) {
dasmOperand(tOperands[x], config, line, opdef->operands[x]);
more += strlen(tOperands[x]) + 1;
}
/* Grow the text buffer */
line = dasmGrow(lines, size, *offset + more, index);
if (line == NULL)
return 1;
/* Working variables */
dest = &((char *) *lines)[*offset];
*offset += more;
/* Address */
strcpy(dest, tAddress);
line->text.address = dest;
dest += 9;
/* Code */
for (x = 0; x < line->codeLength; x++) {
strcpy(dest, tCode[x]);
line->text.code[x] = dest;
dest += 3;
}
/* Mnemonic */
strcpy(dest, tMnemonic);
line->text.mnemonic = dest;
dest += strlen(dest) + 1;
/* Operands */
for (x = 0; x < opdef->operandsLength; x++) {
strcpy(dest, tOperands[
config->operandOrder == VBU_DEST_FIRST ?
opdef->operandsLength - 1 - x :
x
]);
line->text.operands[x] = dest;
dest += strlen(dest) + 1;
}
return 0;
}
/***************************** Library Functions *****************************/
/* Disassemble from a simulation */
static VBU_DasmLine* dasmDisassemble(VB *sim, uint32_t address,
VBU_DasmConfig *config, unsigned length, int line) {
uint32_t addr; /* Working address */
uint32_t *circle = NULL; /* Circular address buffer */
VBU_DasmLine *lines = NULL; /* Output line buffer */
size_t offset; /* Offset into lines buffer */
uint32_t pc; /* Program counter */
size_t size; /* Number of bytes in lines */
unsigned x; /* Iterator */
/* Nothing to disassemble */
if (length == 0)
return NULL;
/* Establish a circular buffer */
if (line > 0) {
circle = VBU_REALLOC(NULL, (size_t) (line + 1) * sizeof (uint32_t));
if (circle == NULL)
goto catch;
}
/* Begin decoding from at least 10 lines before first/reference */
addr = (address & 0xFFFFFFFE) -
(int32_t) (line <= 0 ? 10 : line + 10) * 4;
/* Locate the address of the line containing the reference address */
pc = vbGetProgramCounter(sim);
for (x = 0;;) {
/* Track the address in the circular buffer */
if (line > 0) {
circle[x] = addr;
if (++x > (size_t) line)
x = 0;
}
/* Check if the instruction contains the reference address */
size = dasmInstSize(sim, addr);
if (address - addr < size)
break;
addr += pc - addr < size ? pc - addr : size;
}
/* Address of first line is in the circular buffer */
if (line > 0) {
addr = circle[x];
circle = VBU_REALLOC(circle, 0);
}
/* Keep decoding until the first line of output */
else for (; line < 0; line++)
addr += dasmInstSize(sim, addr);
/* Working variables */
size = length * sizeof (VBU_DasmLine);
lines = VBU_REALLOC(NULL, size);
offset = size;
if (lines == NULL)
goto catch;
/* Process output lines */
for (x = 0; x < length; x++) {
if (dasmLine(sim, &addr, pc, config, &lines, &size, &offset, x))
goto catch;
}
return lines;
/* Exception handler */
catch:
circle = VBU_REALLOC(circle, 0);
lines = VBU_REALLOC(lines , 0);
return NULL;
}
#endif /* VBUAPI */
+65
View File
@@ -0,0 +1,65 @@
#ifndef VBUAPI
#define VBUAPI
#endif
#include <stdio.h>
#include <string.h>
#include <vbu.h>
/* Memory management */
#ifndef VBU_REALLOC
#include <stdlib.h>
#define VBU_REALLOC realloc
#else
extern void* VBU_REALLOC(void *, size_t);
#endif
/***************************** Library Functions *****************************/
/* Sign-extend an integer of variable width */
static int32_t SignExtend(int32_t value, int32_t bits) {
#ifndef VB_SIGNED_PROPAGATE
value &= ~((uint32_t) 0xFFFFFFFF << bits);
bits = (int32_t) 1 << (bits - (int32_t) 1);
return (value ^ bits) - bits;
#else
return value << (32 - bits) >> (32 - bits);
#endif
}
/******************************** Sub-Modules ********************************/
#include "disassembler.c"
/******************************* API Commands ********************************/
/* Initialize disassembler options with default settings */
VBUAPI VBU_DasmConfig* vbuDasmInit(VBU_DasmConfig *config) {
config->bcondNotation = VBU_JOINED;
config->conditionCase = VBU_LOWER;
config->conditionCL = VBU_L;
config->conditionEZ = VBU_Z;
config->conditionNotation = VBU_NAMES;
config->hexCase = VBU_UPPER;
config->hexNotation = VBU_0X;
config->memoryNotation = VBU_OUTSIDE;
config->mnemonicCase = VBU_UPPER;
config->operandOrder = VBU_DEST_LAST;
config->programCase = VBU_LOWER;
config->programNotation = VBU_NAMES;
config->setfNotation = VBU_SPLIT;
config->systemCase = VBU_LOWER;
config->systemNotation = VBU_NAMES;
return config;
}
/* Disassemble from a simulation */
VBUAPI VBU_DasmLine* vbuDisassemble(VB *sim, uint32_t address,
VBU_DasmConfig *config, unsigned length, int line) {
return dasmDisassemble(sim, address, config, length, line);
}
+94
View File
@@ -0,0 +1,94 @@
#ifndef VBU_H_
#define VBU_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef VBUAPI
#define VBUAPI extern
#endif
/* Header includes */
#include <vb.h>
/********************************* Constants *********************************/
/* Disassembler options */
#define VBU_0X 0
#define VBU_C 1
#define VBU_DEST_FIRST 1
#define VBU_DEST_LAST 0
#define VBU_DOLLAR 1
#define VBU_E 0
#define VBU_H 2
#define VBU_INSIDE 1
#define VBU_JOINED 0
#define VBU_L 0
#define VBU_LOWER 1
#define VBU_NAMES 1
#define VBU_NUMBERS 0
#define VBU_OUTSIDE 0
#define VBU_SPLIT 1
#define VBU_UPPER 0
#define VBU_Z 1
/*********************************** Types ***********************************/
/* Disassembler text options */
typedef struct { /* Defaults listed first */
uint8_t bcondNotation; /* JOINED, SPLIT */
uint8_t conditionCase; /* LOWER, UPPER */
uint8_t conditionCL; /* L, C */
uint8_t conditionEZ; /* Z, E */
uint8_t conditionNotation; /* NAMES, NUMBERS */
uint8_t hexCase; /* UPPER, LOWER */
uint8_t hexNotation; /* 0X, H, DOLLAR */
uint8_t memoryNotation; /* OUTSIDE, INSIDE */
uint8_t mnemonicCase; /* UPPER, LOWER */
uint8_t operandOrder; /* DEST_LAST, DEST_FIRST */
uint8_t programCase; /* LOWER, UPPER */
uint8_t programNotation; /* NAMES, NUMBERS */
uint8_t setfNotation; /* SPLIT, JOINED */
uint8_t systemCase; /* LOWER, UPPER */
uint8_t systemNotation; /* NAMES, NUMBERS */
} VBU_DasmConfig;
/* Disassembler output line */
typedef struct {
/* Parsed */
uint32_t address; /* Memory address */
uint16_t code[4]; /* Instruction bytes */
uint8_t codeLength; /* Number of items in code */
uint8_t isPC; /* Set if PC is on this line */
/* Display text */
struct {
char *address; /* Memory address */
char *code[4]; /* Instruction bytes */
char *mnemonic; /* Instruction mnemonic */
char *operands[3]; /* Instruction operands */
uint8_t operandsLength; /* Number of items in operands */
} text;
} VBU_DasmLine;
/******************************* API Commands ********************************/
VBUAPI VBU_DasmConfig* vbuDasmInit (VBU_DasmConfig *config);
VBUAPI VBU_DasmLine* vbuDisassemble(VB *sim, uint32_t address, VBU_DasmConfig *config, unsigned length, int line);
#ifdef __cplusplus
}
#endif
#endif /* VBU_H_ */