Compare commits

..
9 Commits
Author SHA1 Message Date
GuyPerfect 27e926bd58 Fix byte writes to VIP cells, objects and worlds 2024-12-25 13:48:39 -06:00
GuyPerfect d802d39d8d Prevent non-debug writes to CTA 2024-12-23 09:56:54 -06:00
GuyPerfect 18b2c589e6 Add vbuCodeSize() 2024-11-21 18:50:31 -06:00
GuyPerfect f45636a491 VIP bugfix 2024-11-19 22:22:34 -06:00
GuyPerfect 9ce8c9c778 VIP bugfix 2024-11-19 22:21:06 -06:00
GuyPerfect c90b8137de VIP optimizations 2024-11-19 21:56:44 -06:00
GuyPerfect bc864644f7 Aid VSU performance 2024-11-17 14:57:56 -06:00
GuyPerfect e97b52e944 Cleanup adjustments 2024-11-17 12:31:37 -06:00
GuyPerfect 7e31fbd582 VSU performance tweak, add immediate notation setting 2024-11-11 20:05:14 -06:00
11 changed files with 805 additions and 440 deletions
-5
View File
@@ -91,11 +91,6 @@
#define CPU_XORBSU 82
#define CPU_XORNBSU 83
/* Functional operand types */
#define CPU_LITERAL 0
#define CPU_MEMORY 1
#define CPU_REGISTER 2
/* Bit string operations */
#define CPU_AND_BS 0
#define CPU_ANDN_BS 1
+64 -4
View File
@@ -8,8 +8,11 @@
/*********************************** Types ***********************************/
/* Output image */
typedef uint8_t Pixels[2][384*224];
/* VIP BG map cell */
typedef struct {
uint8_t *palette; /* Points to a VB.vip.gplt */
uint8_t *pixels; /* Points to a VB.vip.characters */
} Cell;
/* VSU channel */
typedef struct {
@@ -64,9 +67,58 @@ typedef struct {
} wave;
/* Other state */
uint32_t clocks; /* Clocks until next sample */
uint32_t clocks; /* Clocks until next wave or noise sample */
uint8_t freqmod; /* Frequency modifications are active */
uint32_t until; /* Clocks until channel component update */
} Channel;
/* VIP character (hflp << 1 | vflp) */
typedef uint8_t Character[4][64];
/* VIP object */
typedef struct {
Cell cell; /* BG map-like attributes */
int16_t jp; /* Parallax */
int16_t jx; /* Screen base X */
int16_t jy; /* Screen Y */
uint8_t lron; /* Visible in left and right images */
} Object;
/* Output image */
typedef uint8_t Pixels[2][384*224];
/* VIP world */
typedef struct {
/* Attributes */
uint8_t bgm; /* Mode */
uint8_t end; /* Control world */
int16_t gp; /* World parallax */
int16_t gx; /* World base X */
int16_t gy; /* World Y */
int16_t mx; /* Scroll base X */
int16_t mp; /* Scroll parallax */
int16_t my; /* Scroll Y */
uint8_t over; /* Use overplane */
Cell *overplane; /* Overplane cell */
/* Non-attributes */
Cell *bg[64]; /* Background arrangement */
int32_t bgHeight; /* Height of background in pixels */
uint32_t bgMaskX; /* Horizontal background mask */
uint32_t bgMaskY; /* Vertical background mask */
uint32_t bgShift; /* Bits to shift when selecting a BG map */
int32_t bgWidth; /* Width of background in pixels */
uint32_t hAffine; /* H for affine mode */
uint32_t hNaffine; /* H for not affine mode */
uint32_t height; /* Height of world in pixels */
uint8_t lron; /* Visible in left and right images */
uint32_t paramBase; /* H-bias and affine parameter address */
uint32_t wAffine; /* W for affine mode */
uint32_t wNaffine; /* W for not affine mode */
uint32_t width; /* Width of world in pixels */
} World;
/* Simulation state */
struct VB {
@@ -278,7 +330,11 @@ struct VB {
Pixels shadow; /* Drawing shadow image, column-major */
/* Other state */
Cell cells[0x10000]; /* Pre-computed BG map attributes */
Character characters[2048]; /* Pre-computed character pixels */
Object objects[1024]; /* Pre-computed object attributes */
uint8_t ram[0x40000]; /* Video memory */
World worlds[32]; /* Pre-computed world attributes */
} vip;
/* VSU */
@@ -643,6 +699,7 @@ VBAPI vbOnWrite vbGetWriteCallback(VB *sim) {
VBAPI VB* vbInit(VB *sim) {
sim->cart.ram = NULL;
sim->cart.rom = NULL;
sim->ph.enabled = 0;
sim->vsu.out.samples = NULL;
sim->onExecute = NULL;
sim->onFetch = NULL;
@@ -652,7 +709,7 @@ VBAPI VB* vbInit(VB *sim) {
sim->onSamples = NULL;
sim->onWrite = NULL;
sim->peer = NULL;
sim->ph.enabled = 0;
sim->tag = NULL;
vbReset(sim);
return sim;
}
@@ -774,6 +831,8 @@ VBAPI int vbSetOption(VB *sim, int key, int value) {
VBAPI void vbSetPeer(VB *sim, VB *peer) {
if (sim->peer == peer)
return;
if (sim->peer != NULL)
sim->peer->peer = NULL;
sim->peer = peer;
if (peer == NULL)
return;
@@ -784,6 +843,7 @@ VBAPI void vbSetPeer(VB *sim, VB *peer) {
/* Specify a new value for the program counter */
VBAPI uint32_t vbSetProgramCounter(VB *sim, uint32_t value) {
sim->cpu.clocks = 0;
sim->cpu.operation = CPU_FETCH;
sim->cpu.pc = sim->cpu.nextPC = value & 0xFFFFFFFE;
sim->cpu.step = 0;
+580 -313
View File
@@ -56,37 +56,18 @@ static const uint8_t BRIGHT8[] = {
/*********************************** Types ***********************************/
/* World attribtues per eye */
/* Intersection of the screen and a world rectangle */
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;
int32_t x1; /* Left edge inclusive */
int32_t x2; /* Right edge exclusive */
int32_t y1; /* Top edge inclusive */
int32_t y2; /* Bottom edge exclusive */
} Window;
/***************************** Module Functions ******************************/
/* Retrieve a pointer to character data in host memory */
static uint8_t* vipCharacter(VB *sim, uint32_t c) {
return &sim->vip.ram[0x06000 | (c << 6 & 0x18000) | (c << 4 & 0x01FF0)];
}
/* Read a palette */
static int32_t vipReadPalette(uint8_t *entries) {
return entries[3] << 6 | entries[2] << 4 | entries[1] << 2;
@@ -244,6 +225,178 @@ static int32_t vipReadIO(VB *sim, uint32_t address, int type) {
value;
}
/* Write into BG map cell memory */
static void vipWriteCell(VB *sim, uint32_t offset, int type, int32_t value) {
Cell *cell;
/* Adjustments for byte and word writes */
switch (type) {
case VB_S8:
case VB_U8:
value = offset & 1 ?
value << 8 | sim->vip.ram[0x20001 ^ offset] :
value | (int32_t) sim->vip.ram[0x20001 | offset] << 8
;
break;
case VB_S32:
vipWriteCell(sim, offset + 2, VB_U16, value >> 16);
break;
}
/* Update pixel pointer */
cell = &sim->vip.cells[offset >> 1];
cell->palette = sim->vip.gplt[value >> 14 & 3];
cell->pixels = sim->vip.characters[value & 0x07FF][value >> 12 & 3];
}
/* Write into character memory */
static void vipWriteChr(VB *sim, uint32_t offset, int type, int32_t value) {
Character *chr; /* Pixel state */
int b, l, r, t; /* Pixel bounds */
int x, y, X, Y; /* Iterators */
/* Byte advance by data type */
static const uint8_t HORZ[] = { 4, 4, 8, 8, 8 };
static const uint8_t VERT[] = { 8, 8, 8, 8, 16 };
/* Working variables */
chr = &sim->vip.characters[offset >> 4];
l = (offset & 0x1) << 2;
t = (offset & 0xE) << 2;
r = l + HORZ[type];
b = t + VERT[type];
/* Process all pixels */
for (y = t, Y = 56 - y; y < b; y += 8, Y -= 8)
for (x = l, X = 7 - x; x < r; x += 1, X -= 1, value >>= 2) {
(*chr)[0][y | x] = (*chr)[1][Y | x] =
(*chr)[2][y | X] = (*chr)[3][Y | X] = value & 3;
}
}
/* Write into object attribute memory */
static void vipWriteObject(VB *sim, uint32_t offset, int type, int32_t value) {
Object *obj; /* Object state */
/* Adjustments for byte and word writes */
switch (type) {
case VB_S8:
case VB_U8:
value = offset & 1 ?
value << 8 | sim->vip.ram[0x3E001 ^ offset] :
value | (int32_t) sim->vip.ram[0x3E001 | offset] << 8
;
break;
case VB_S32:
vipWriteObject(sim, offset + 2, VB_U16, value >> 16);
break;
}
/* Processing by offset */
obj = &sim->vip.objects[offset >> 3];
switch (offset >> 1 & 3) {
case 0: obj->jx = SignExtend(value, 10); break;
case 1:
obj->jp = SignExtend(value, 10);
obj->lron = value >> 14 & 3;
break;
case 2:
value = (int8_t) value;
obj->jy = value > -8 ? value : value & 0xFF;
break;
case 3:
obj->cell.palette = sim->vip.jplt[value >> 14 & 3];
obj->cell.pixels =
sim->vip.characters[value & 0x07FF][value >> 12 & 3];
}
}
/* Write into world attribute memory */
static void vipWriteWorld(VB *sim, uint32_t offset, int type, int32_t value) {
uint32_t base; /* Base BG map index */
uint8_t *bg; /* Background template */
uint32_t count; /* Number of BG maps in background */
World *world; /* World state */
uint32_t z; /* Iterator */
/* Adjustments for byte and word writes */
switch (type) {
case VB_S8:
case VB_U8:
value = offset & 1 ?
value << 8 | sim->vip.ram[0x3D801 ^ offset] :
value | (int32_t) sim->vip.ram[0x3D801 | offset] << 8
;
break;
case VB_S32:
vipWriteWorld(sim, offset + 2, VB_U16, value >> 16);
break;
}
/* Processing by offset */
world = &sim->vip.worlds[offset >> 5];
switch (offset >> 1 & 15) {
case 0:
/* Parse attributes */
world->lron = value >> 14 & 3;
world->bgm = value >> 12 & 3;
world->over = value >> 7 & 1;
world->end = value >> 6 & 1;
/* Update background fields */
z = value >> 10 & 3;
world->bgMaskX = (1 << z) - 1;
world->bgWidth = 512 << z;
world->bgShift = z;
z = value >> 8 & 3;
world->bgMaskY = (1 << z) - 1;
world->bgHeight = 512 << z;
/* Update world dimensions */
if (world->bgm != 2) {
world->height = world->hNaffine;
world->width = world->wNaffine;
} else {
world->height = world->hAffine;
world->width = world->wAffine;
}
/* Update background arrangement */
count = (world->bgMaskX + 1) * (world->bgMaskY + 1);
base = value & 15 & ~(count > 8 ? 7 : count - 1);
bg = (uint8_t *) BG_TEMPLATES[value >> 8 & 15];
for (z = 0; z < count; z++)
world->bg[z] = &sim->vip.cells[(base + bg[z]) << 12];
break;
case 1: world->gx = SignExtend(value, 10); break;
case 2: world->gp = SignExtend(value, 10); break;
case 3: world->gy = (int16_t) value; break;
case 4: world->mx = SignExtend(value, 13); break;
case 5: world->mp = SignExtend(value, 15); break;
case 6: world->my = SignExtend(value, 13); break;
case 7: /* W */
value = SignExtend(value, 13) + 1;
world->wNaffine = value < 0 ? 0 : value;
value = SignExtend(value, 10) + 1;
world->wAffine = value < 0 ? 0 : value;
world->width = world->bgm != 2 ? world->wNaffine : world->wAffine;
break;
case 8: /* H */
value = (int16_t) value + 1;
world->hNaffine = value < 8 ? 8 : value;
world->hAffine = value < 0 ? 0 : value;
world->height = world->bgm != 2 ? world->hNaffine : world->hAffine;
break;
case 9: world->paramBase = 0x20000|(uint32_t)(uint16_t)value<<1;break;
case 10: world->overplane = &sim->vip.cells[(uint16_t) value]; break;
}
}
/* Write a typed value to an I/O register */
static void vipWriteIO(
VB *sim, uint32_t address, int type, int32_t value, int debug) {
@@ -328,10 +481,12 @@ static void vipWriteIO(
break;
case 0x5F830>>1: /* CTA */
if (debug) {
if ((mask & 0xFF00) == 0)
sim->vip.cta.cta_r = value >> 8;
if ((mask & 0x00FF) == 0)
sim->vip.cta.cta_l = value;
}
break;
case 0x5F842>>1: /* XPCTRL */
@@ -627,313 +782,354 @@ 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) {
/* Draw a cell into shadow memory */
static void vipDrawCell(uint8_t *shadow, Window *wnd,
Cell *cell, int32_t x, int32_t y) {
uint8_t *col, *row; /* Output pixel */
uint8_t pixel; /* Character pixel value */
int32_t px1, px2, py1, py2; /* Pixel bounds in cell */
int32_t px, py; /* Pixel origin in cell */
/* 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;
/* Identify the visible pixels */
py1 = y > wnd->y1 ? y : wnd->y1;
py2 = y + 8 < wnd->y2 ? y + 8 : wnd->y2;
px1 = x > wnd->x1 ? x : wnd->x1;
px2 = x + 8 < wnd->x2 ? x + 8 : wnd->x2;
/* 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;
/* Process all columns of pixels */
col = &shadow[px1 * 224 + py1];
for (px = px1; px < px2; px++, col += 224)
for (py = py1, row = col; py < py2; py++, row++) {
pixel = cell->pixels[(py - y) << 3 | (px - x)];
if (pixel != 0)
*row = cell->palette[pixel];
}
/* 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 */
/* Draw a BG map into shadow memory */
static void vipDrawBGMap(uint8_t *shadow, Window *wnd,
uint8_t over, Cell *map, int32_t x, int32_t y) {
Cell *col, *row; /* Source cell */
int32_t cx1, cx2, cy1, cy2; /* Cell bounds in BG map pixels */
int32_t cx, cy; /* Cell origin in BG map pixels */
/* Validate the world isn't below the frame */
attr->gy = busReadBuffer(world + 6, VB_S16);
if (attr->gy > 223)
return 1;
/* Identify the visible cells */
cy1 = (wnd->y1-y ) & ~7; if (cy1 < 0) cy1 = 0; if (cy1 > 512) cy1 = 512;
cy2 = (wnd->y2-y+7) & ~7; if (cy2 < 0) cy2 = 0; if (cy2 > 512) cy2 = 512;
cx1 = (wnd->x1-x ) & ~7; if (cx1 < 0) cx1 = 0; if (cx1 > 512) cx1 = 512;
cx2 = (wnd->x2-x+7) & ~7; if (cx2 < 0) cx2 = 0; if (cx2 > 512) cx2 = 512;
/* 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)
;
/* Process all cells as overplane */
if (over) {
for (cy = cy1; cy < cy2; cy += 8)
for (cx = cx1; cx < cx2; cx += 8)
vipDrawCell(shadow, wnd, map, x + cx, y + cy);
return;
}
return 0;
/* Process all cells normally */
row = &map[cy1 << 3 | cx1 >> 3];
for (cy = cy1 ; cy < cy2; cy += 8, row += 64)
for (cx = cx1, col = row; cx < cx2; cx += 8, col++)
vipDrawCell(shadow, wnd, col, x + cx, y + cy);
}
/* Draw a background into shadow memory */
static void vipDrawBackground(uint8_t *shadow, Window *wnd,
World *world, int32_t x, int32_t y) {
int32_t bx1, bx2, by1, by2; /* BG map bounds in background pixels */
int32_t bx, by; /* BG map origin in background pixels */
/* Identify the visible BG maps */
by1 = (wnd->y1 - y ) & ~511;
by2 = (wnd->y2 - y - 1) & ~511;
bx1 = (wnd->x1 - x ) & ~511;
bx2 = (wnd->x2 - x - 1) & ~511;
/* Process all rows of BG maps */
for (by = by1; by <= by2; by += 512) {
/* Row is out of bounds */
if (world->over && (by < 0 || by >= world->bgHeight)) {
for (bx = bx1; bx <= bx2; bx++)
vipDrawBGMap(shadow, wnd, 1, world->overplane, x + bx, y + by);
continue;
}
/* Process all columns of BG maps */
for (bx = bx1; bx <= bx2; bx += 512) {
/* Column is out of bounds */
if (world->over && (bx < 0 || bx >= world->bgWidth)) {
vipDrawBGMap(shadow, wnd, 1, world->overplane, x + bx, y + by);
continue;
}
/* Column is in bounds */
vipDrawBGMap(shadow, wnd, 0, world->bg[
(by >> 9 & world->bgMaskY) << world->bgShift |
(bx >> 9 & world->bgMaskX)
], x + bx, y + by);
}
}
}
/* Draw a Normal world into shadow memory */
static void vipDrawNormal(VB *sim, World *world) {
int32_t mx, my; /* Background origin */
Window wnd; /* Window bounds in pixels */
int i; /* Iterator */
/* No visible content */
if (world->width == 0)
return;
/* Vertical window bounds */
wnd.y1 = (int32_t) sim->vip.xp.sbcount << 3;
if (world->gy > wnd.y1)
wnd.y1 = world->gy;
if (wnd.y1 >= 224)
return;
wnd.y2 = world->gy + world->height;
if (wnd.y2 <= 0)
return;
my = world->gy - world->my;
if (wnd.y1 < 0)
wnd.y1 = 0;
if (wnd.y2 > 224)
wnd.y2 = 224;
/* Process both eyes */
for (i = 0; i < 2; i++) {
/* Check visibility */
if (!(world->lron >> (i ^ 1) & 1))
continue;
/* Horizontal window bounds */
wnd.x1 = world->gx + (i == 0 ? -world->gp : world->gp);
if (wnd.x1 >= 384)
continue;
wnd.x2 = wnd.x1 + world->width;
if (wnd.x2 <= 0)
continue;
mx = wnd.x1 - world->mx - (i == 0 ? -world->mp : world->mp);
if (wnd.x1 < 0)
wnd.x1 = 0;
if (wnd.x2 > 384)
wnd.x2 = 384;
/* Draw the background into the window */
vipDrawBackground(sim->vip.shadow[i], &wnd, world, mx, my);
}
}
/* Draw an H-bias world into shadow memory */
static void vipDrawHBias(VB *sim, World *world) {
int32_t mx, my; /* Background origin */
uint8_t *param; /* World parameter memory */
Window wnd; /* Window bounds in pixels */
int32_t y1, y2; /* Vertical window bounds */
int i, y; /* Iterators */
/* No visible content */
if (world->width == 0)
return;
/* Vertical window bounds */
y1 = (int32_t) sim->vip.xp.sbcount << 3;
if (world->gy > y1)
y1 = world->gy;
if (y1 >= 224)
return;
y2 = world->gy + world->height;
if (y2 <= 0)
return;
my = world->gy - world->my;
if (y1 < 0)
y1 = 0;
if (y2 > 224)
y2 = 224;
/* Process both eyes */
for (i = 0; i < 2; i++) {
/* Check visibility */
if (!(world->lron >> (i ^ 1) & 1))
continue;
/* Horizontal window bounds */
wnd.x1 = world->gx + (i == 0 ? -world->gp : world->gp);
if (wnd.x1 >= 384)
continue;
wnd.x2 = wnd.x1 + world->width;
if (wnd.x2 <= 0)
continue;
mx = wnd.x1 - world->mx - (i == 0 ? -world->mp : world->mp);
if (wnd.x1 < 0)
wnd.x1 = 0;
if (wnd.x2 > 384)
wnd.x2 = 384;
/* Process all visible lines */
param = &sim->vip.ram[world->paramBase +
((y1 - world->gy) << 2) + (i << 1)];
for (y = y1; y < y2; y++, param += 2) {
/* Configure window bounds */
wnd.y1 = y;
wnd.y2 = y + 1;
/* Draw the background into the window */
vipDrawBackground(sim->vip.shadow[i], &wnd, world,
mx + busReadBuffer(param, VB_S16), my);
}
}
}
/* Draw an Affine world into shadow memory */
static void vipDrawAffine(VB *sim, World *world) {
Cell *cell; /* Source cell */
uint8_t *col, *row; /* Output pixel */
uint8_t pixel; /* Character pixel value */
uint8_t *param; /* World parameter memory */
int32_t px, py; /* Pixel source coordinates */
int32_t dx, dy, mp, mx, my; /* Affine parameters */
int32_t wx; /* Base world X coordinate */
int32_t x1, x2, y1, y2; /* Window bounds */
int i, x, y; /* Iterators */
/* No visible content */
if (world->width == 0 || world->height == 0)
return;
/* Vertical window bounds */
y1 = (int32_t) sim->vip.xp.sbcount << 3;
if (world->gy > y1)
y1 = world->gy;
if (y1 >= 224)
return;
y2 = world->gy + world->height;
if (y2 <= 0)
return;
if (y1 < 0)
y1 = 0;
if (y2 > 224)
y2 = 224;
/* Process both eyes */
for (i = 0; i < 2; i++) {
/* Check visibility */
if (!(world->lron >> (i ^ 1) & 1))
continue;
/* Horizontal window bounds */
x1 = world->gx + (i == 0 ? -world->gp : world->gp);
if (x1 >= 384)
continue;
x2 = x1 + world->width;
if (x2 <= 0)
continue;
wx = x1;
if (x1 < 0)
x1 = 0;
if (x2 > 384)
x2 = 384;
wx = x1 - wx;
/* Process all visible rows */
param = &sim->vip.ram[world->paramBase | (y1 - world->gy) << 4];
row = &sim->vip.shadow[i][x1 * 224 + y1];
for (y = y1; y < y2; y++, param += 16, row++) {
/* Parse line parameters */
mx = (int32_t) busReadBuffer(param + 0, VB_S16) << 6;
mp = (int32_t) busReadBuffer(param + 2, VB_S16);
my = (int32_t) busReadBuffer(param + 4, VB_S16) << 6;
dx = (int32_t) busReadBuffer(param + 6, VB_S16);
dy = (int32_t) busReadBuffer(param + 8, VB_S16);
/* Adjust left-edge parameters */
if ((mp < 0) ^ i) {
mx += dx * (wx - mp);
my += dy * (wx - mp);
} else {
mx += dx * wx;
my += dy * wx;
}
/* Process all visible columns */
col = row;
for (x = x1; x < x2; x++, mx += dx, my += dy, col += 224) {
px = (int16_t) (mx >> 9);
py = (int16_t) (my >> 9);
/* Overplane */
if (world->over && (
px < 0 || px >= world->bgWidth ||
py < 0 || py >= world->bgHeight
)) cell = world->overplane;
/* Regular */
else cell = &world->bg[
(py >> 9 & world->bgMaskY) << world->bgShift |
(px >> 9 & world->bgMaskX)
][(py << 3 & 0xFC0) | (px >> 3 & 63)];
/* Sample the pixel */
pixel = cell->pixels[(py & 7) << 3 | (px & 7)];
if (pixel != 0)
*col = cell->palette[pixel];
} /* x */
} /* y */
} /* i */
}
/* Draw an object group into shadow memory */
static void vipDrawObjects(VB *sim, int group) {
uint8_t *dest; /* Pointer to object position in shadow memory */
int fx; /* Output horizontal position */
int fy; /* Output vertical position */
uint8_t *obj; /* Pointer to object attributes in host memory */
int32_t ox; /* Eye horizontal position */
int pixel; /* Character input pixel */
int start; /* Index of first object in group */
int stop; /* Index of last object in group */
int sx; /* Input horizontal position */
int sy; /* Input vertical position */
int32_t top; /* Window boundary */
int i, o, x, y; /* Iterators */
Object *obj; /* Object state */
int start; /* First object in the group */
int stop; /* Last object in the group */
Window wnd; /* Window bounds in pixels */
int i, o; /* Iterators */
/* Object attributes */
uint32_t attr1; /* Attribute bits */
uint32_t attr2; /* Attribute bits */
int jhflp; /* Is flipped horizontally */
int32_t jp; /* Stereo parallax */
int jvflp; /* Is flipped vetically */
int32_t jx; /* Base horizontal position */
int32_t jy; /* Vertical position */
uint8_t *plt; /* Palette */
uint8_t *src; /* Pointer to character source data in host memory */
/* Establish the viewing window */
wnd.x1 = 0;
wnd.y1 = (int32_t) sim->vip.xp.sbcount << 3;
wnd.x2 = 384;
wnd.y2 = 224;
/* Process all objects in the group */
start = group == 0 ? 0 : (sim->vip.spt[group - 1] + 1) & 1023;
stop = sim->vip.spt[group];
top = (int32_t) sim->vip.xp.sbcount << 3;
for (o = stop; o != -1; o = o == start ? -1 : (o - 1) & 1023) {
obj = &sim->vip.ram[0x3E000 | o << 3];
/* Validate object is enabled */
attr1 = busReadBuffer(obj + 2, VB_U16);
if ((attr1 & 0xC000) == 0) /* JLON, JRON */
continue;
/* Validate Y position */
jy = (int8_t) obj[4];
if (jy < 7)
jy &= 0xFF;
if (jy < top - 7 || jy > 223)
continue;
/* Parse attributes */
jx = SignExtend(busReadBuffer(obj, VB_U16), 10);
jp = SignExtend(attr1, 10);
attr2 = busReadBuffer(obj + 6, VB_U16);
jhflp = attr2 >> 13 & 1;
jvflp = attr2 >> 12 & 1;
/* Locate palette and character state in host memory */
plt = sim->vip.jplt[attr2 >> 14];
src = vipCharacter(sim, attr2);
/* Draw the character */
obj = &sim->vip.objects[o];
for (i = 0; i < 2; i++) {
if ((attr1 >> (15 - i) & 1) == 0) /* J*ON */
if (!(obj->lron >> (i ^ 1) & 1))
continue;
ox = jx - (i == 0 ? jp : -jp);
dest = &sim->vip.shadow[i][ox * 224 + jy];
/* Draw all columns */
for (x = 0; x < 8; x++, dest += 224) {
fx = ox + x;
if (fx < 0 || fx > 383)
continue;
sx = jhflp ? 7 - x : x;
/* Draw all rows */
for (y = 0; y < 8; y++) {
fy = jy + y;
if (fy < top || fy > 223)
continue;
sy = jvflp ? 7 - y : y;
pixel = src[sy << 1 | sx >> 2] >> ((sx & 3) << 1) & 3;
if (pixel != 0)
dest[y] = plt[pixel]; /* TODO: Research clocks */
} /* y */
} /* x */
} /* i */
vipDrawCell(sim->vip.shadow[i], &wnd, &obj->cell,
obj->jx + (i == 0 ? -obj->jp : obj->jp), obj->jy);
}
}
/* Draw a background world into shadow memory */
static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t bits) {
uint16_t bgAttr; /* BG map cell attributes */
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 source X */
int32_t cy; /* BG cell/character source Y */
uint8_t *dest; /* Pointer to output in shadow memory */
EyeAttribs ettr; /* Eye attributes */
uint32_t param; /* Current line parameter address */
int8_t pixel; /* Character pixel value */
int32_t i, x, y; /* Iterators */
/* World attributes */
WorldAttribs wttr; /* Common attributes */
int32_t dx; /* Affine per-pixel X delta */
int32_t dy; /* Affine per-pixel Y delta */
int32_t mp; /* BG source parallax */
int32_t mx; /* BG source X */
int32_t my; /* BG source Y */
int16_t hofst; /* H-bias shift */
/* Working variables */
ettr.bp = wttr.mp = wttr.mx = wttr.my = wttr.params = 0;
/* Parse attributes */
if (vipParseWorld(sim, world, bits, &wttr))
return; /* Window not in frame */
/* Draw the world */
for (i = 0; i < 2; i++) {
/* World is not visible */
if ((bits & (int32_t) 0x8000 >> i) == 0) /* LON, RON */
continue;
/* Process attributes */
if (vipParseEye(&wttr, &ettr, i))
continue;
/* Draw all rows */
for (y = wttr.top, param = wttr.params; y <= wttr.bottom; y++) {
/* Parse line parameters */
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;
break;
case 2: /* Affine */
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 = 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][ettr.left * 224 + y];
/* Draw all columns */
for (x = ettr.left; x <= ettr.right; x++, dest += 224) {
/* Locate the pixel in the background */
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);
mx += dx;
my += dy;
}
/* Locate the BG map in the background */
bx = SignExtend(cx >> 9, 23);
by = SignExtend(cy >> 9, 23);
cell = NULL;
/* BG map is out of bounds */
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 | ((
wttr.base +
wttr.bg[by << wttr.scx | bx]
) << 13) |
(cy << 4 & 0x1F80) |
(cx >> 2 & 0x007E)
];
}
/* Extract the pixel from the character */
bgAttr = busReadBuffer(cell, VB_U16);
chr = vipCharacter(sim, bgAttr);
cx = (bgAttr & 0x2000 ? 7 - cx : cx) & 7;
cy = (bgAttr & 0x1000 ? 7 - cy : cy) & 7;
pixel = chr[cy << 1 | cx >> 2] >> ((cx & 3) << 1) & 3;
/* Write the pixel into shadow memory */
if (pixel != 0)
*dest = sim->vip.gplt[bgAttr >> 14 & 3][pixel];
} /* x */
} /* y */
} /* i */
}
/* Draw the current graphics configuration into shadow memory */
static void vipRender(VB *sim) {
uint16_t attr; /* World attribute bits */
int group; /* Next object group index */
uint16_t *timing; /* Column timing in host memory */
uint8_t *world; /* World attribute source in host memory */
World *world; /* World attribute source in host memory */
int32_t x, y; /* Iterators */
/* Erase all pixels */
@@ -943,25 +1139,25 @@ static void vipRender(VB *sim) {
/* Process all worlds */
group = 3;
world = &sim->vip.ram[0x3DBE0]; /* World 31 */
for (x = 31; x >= 0; x--, world -= 32) {
attr = busReadBuffer(world, VB_U16);
for (x = 31; x >= 0; x--) {
world = &sim->vip.worlds[x];
/* Non-graphical world */
if (attr & 0x0040) /* END */
if (world->end)
break; /* Control world */
if ((attr & 0xC000) == 0) /* LON, RON */
if (world->lron == 0)
continue; /* Dummy world */
/* Object world */
if ((attr >> 12 & 3) == 3) {
/* Processing by world type */
switch (world->bgm) {
case 0: vipDrawNormal(sim, world); break;
case 1: vipDrawHBias (sim, world); break;
case 2: vipDrawAffine(sim, world); break;
case 3:
vipDrawObjects(sim, group);
group = (group - 1) & 3;
}
/* Background world */
else if (attr & 0xC000) /* LON, RON */
vipDrawWorld(sim, world, attr);
}
/*
@@ -1134,6 +1330,10 @@ static void vipRead(VB *sim, uint32_t address, int type, int32_t *value) {
/* Simulate a hardware reset */
static void vipReset(VB *sim) {
Cell *cell; /* BG map cell state */
Character *chr; /* Character state */
Object *obj; /* Object state */
World *world; /* World state */
int x, y; /* Iterators */
/* Normal */
@@ -1159,6 +1359,53 @@ static void vipReset(VB *sim) {
sim->vip.jplt[x][y] = 0;
}
}
for (x = 0; x < 0x10000; x++) {
cell = &sim->vip.cells[x];
cell->palette = sim->vip.gplt[0];
cell->pixels = sim->vip.characters[0][0];
}
for (x = 0; x < 2048; x++) {
chr = &sim->vip.characters[x];
for (y = 0; y < 64; y++)
(*chr)[0][y] = (*chr)[1][y] = (*chr)[2][y] = (*chr)[3][y] = 0;
}
for (x = 0; x < 32; x++) {
world = &sim->vip.worlds[x];
world->bgm = 0;
world->end = 0;
world->gp = 0;
world->gx = 0;
world->gy = 0;
world->mx = 0;
world->mp = 0;
world->my = 0;
world->over = 0;
world->overplane = &sim->vip.cells[0];
for (y = 0; y < 64; y++)
world->bg[0] = world->overplane;
world->bgHeight = 512;
world->bgMaskX = 0;
world->bgMaskY = 0;
world->bgShift = 0;
world->bgWidth = 512;
world->hAffine = 0;
world->hNaffine = 0;
world->height = 8;
world->lron = 0;
world->paramBase = 0;
world->wAffine = 0;
world->wNaffine = 0;
world->width = 0;
}
for (x = 0; x < 1024; x++) {
obj = &sim->vip.objects[x];
obj->cell.palette = sim->vip.jplt[0];
obj->cell.pixels = sim->vip.characters[0][0];
obj->jp = 0;
obj->jx = 0;
obj->jy = 0;
obj->lron = 0;
}
/* Display processor extra (the hardware does not do this) */
sim->vip.dp.fclk = 0;
@@ -1206,9 +1453,28 @@ static void vipWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
address &= 0x0007FFFF;
/* RAM */
if (address < 0x40000)
if (address < 0x40000) {
busWriteBuffer(&sim->vip.ram[address], type, value);
/* Character memory */
if ((address & 0x26000) == 0x06000) {
address = (address & 0x18000) >> 2 | (address & 0x01FFF);
vipWriteChr(sim, address, type, value);
}
/* BG map memory */
if (address >= 0x20000)
vipWriteCell(sim, address & 0x1FFFF, type, value);
/* World memory */
if ((address & 0x3FC00) == 0x3D800)
vipWriteWorld(sim, address &0x003FF, type, value);
/* Object memory */
if (address >= 0x3E000)
vipWriteObject(sim, address & 0x01FFF, type, value);
}
/* Unmapped */
else if (address < 0x5E000)
;
@@ -1223,6 +1489,7 @@ static void vipWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
/* Mirrors of character memory */
else {
vipWriteChr(sim, address & 0x07FFF, type, value);
address = 0x06000 | (address << 2 & 0x18000) | (address & 0x01FFF);
busWriteBuffer(&sim->vip.ram[address], type, value);
}
+57 -50
View File
@@ -74,49 +74,8 @@ static void vsuNextFreqMod(VB *sim, Channel *chan) {
}
/* Process one channel */
static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) {
static void vsuEmulateChannel(VB *sim, Channel *chan) {
uint32_t bit; /* Pseudorandom bit */
Channel *chan; /* Channel handle */
int freqmod; /* Frequency modifications enabled */
uint32_t until; /* Clocks to process sub-channel components */
/* Select channel */
chan = &sim->vsu.channels[index];
/* Channel is disabled */
if (!chan->int_.enb)
return;
/* Process all clocks */
do {
/* Frequency modifications are active */
freqmod =
index == 4 && /* Channel 5 */
sim->vsu.freqmod.enb && /* Modifications enabled */
sim->vsu.freqmod.interval != 0 /* Modifications valid */
;
/* Clocks until next state change */
until = clocks;
if (chan->clocks < until)
until = chan->clocks;
if (chan->env.enb && chan->env.clocks < until)
until = chan->env.clocks;
if (chan->int_.auto_ && chan->int_.clocks < until)
until = chan->int_.clocks;
if (freqmod && sim->vsu.freqmod.clocks < until)
until = sim->vsu.freqmod.clocks;
/* Manage clocks */
clocks -= until;
chan->clocks -= until;
if (chan->env.enb)
chan->env.clocks -= until;
if (chan->int_.auto_)
chan->int_.clocks -= until;
if (freqmod)
sim->vsu.freqmod.clocks -= until;
/* Automatic shutoff */
if (chan->int_.auto_ && chan->int_.clocks == 0) {
@@ -124,11 +83,11 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) {
return;
}
/* Next sample */
/* Next input sample */
if (chan->clocks == 0) {
/* Wave */
if (index != 5) {
if (chan != &sim->vsu.channels[5]) {
chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current);
chan->wave.sample = (chan->wave.sample + 1) & 31;
}
@@ -158,7 +117,7 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) {
}
/* Frequency modification */
if (freqmod && sim->vsu.freqmod.clocks == 0) {
if (chan->freqmod && sim->vsu.freqmod.clocks == 0) {
chan->freq.current = sim->vsu.freqmod.next;
vsuNextFreqMod(sim, chan);
if (!chan->int_.enb)
@@ -167,8 +126,6 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) {
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
}
} while (clocks != 0);
}
/* Produce output for a channel */
@@ -230,6 +187,8 @@ static void vsuWriteEV1(VB *sim, int index, uint8_t value) {
sim->vsu.freqmod.func = value >> 4 & 1;
sim->vsu.freqmod.rep = value >> 5 & 1;
vsuNextFreqMod(sim, chan);
chan->freqmod =
sim->vsu.freqmod.enb && sim->vsu.freqmod.interval != 0;
break;
case 5: /* Channel 6 */
@@ -313,6 +272,8 @@ static void vsuWriteSWP(VB *sim, uint8_t value) {
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
if (clocks < sim->vsu.freqmod.clocks)
sim->vsu.freqmod.clocks = clocks;
sim->vsu.channels[4].freqmod =
sim->vsu.freqmod.enb && sim->vsu.freqmod.interval != 0;
}
@@ -321,6 +282,8 @@ static void vsuWriteSWP(VB *sim, uint8_t value) {
/* Process component */
static void vsuEmulate(VB *sim, uint32_t clocks) {
Channel *chan; /* Input channel */
uint32_t chantil; /* Clocks until next channel state update */
float i0; /* Current analog input sample */
float o0; /* Current analog output sample */
uint16_t output[2]; /* Digital output samples */
@@ -340,12 +303,54 @@ static void vsuEmulate(VB *sim, uint32_t clocks) {
sim->vsu.clocks -= until;
/* Process all channels */
for (x = 0; x < 6; x++)
vsuEmulateChannel(sim, x, until);
for (x = 0; x < 6; x++) {
chan = &sim->vsu.channels[x];
chantil = until;
/* Process all clocks */
while (chan->int_.enb && chantil != 0) {
/* Determine when the next state change will occur */
if (chan->until == 0) {
/* Clocks until next state change */
chan->until = chan->clocks;
if (chan->env.enb && chan->env.clocks < chan->until)
chan->until = chan->env.clocks;
if (chan->int_.auto_ && chan->int_.clocks < chan->until)
chan->until = chan->int_.clocks;
if (chan->freqmod && sim->vsu.freqmod.clocks < chan->until)
chan->until = sim->vsu.freqmod.clocks;
/* Manage clocks */
chan->clocks -= chan->until;
if (chan->env.enb)
chan->env.clocks -= chan->until;
if (chan->int_.auto_)
chan->int_.clocks -= chan->until;
if (chan->freqmod)
sim->vsu.freqmod.clocks -= chan->until;
}
/* Manage clocks */
if (chan->until > chantil) {
chan->until -= chantil;
chantil = 0;
} else {
chantil -= chan->until;
chan->until = 0;
}
/* Update channel state */
if (chan->until == 0)
vsuEmulateChannel(sim, chan);
}
}
/* Wait for the current sample to finish */
if (sim->vsu.clocks != 0)
continue;
return;
/* Compute the output sample */
output[0] = output[1] = 0;
@@ -416,6 +421,8 @@ static void vsuReset(VB *sim) {
for (x = 0; x < 6; x++) {
chan = &sim->vsu.channels[x];
chan->clocks = 0;
chan->freqmod = 0;
chan->until = 0;
chan->env.clocks = 0;
chan->env.enb = 0;
chan->env.dir = 0;
+21 -15
View File
@@ -1,4 +1,4 @@
/* This file is included into vb.c and cannot be compiled on its own. */
/* This file is included into vbu.c and cannot be compiled on its own. */
#ifdef VBUAPI
@@ -253,18 +253,24 @@ static void dasmOpDisp26(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
}
/* Format a 5-bit sign-extended immediate operand */
static void dasmOpImm5S(char *dest, VBU_DasmLine *line) {
static void dasmOpImm5S(char *dest, VBU_DasmConfig*config, VBU_DasmLine *line){
if (config->immediateNotation == VBU_NUMBER)
*dest++ = '#';
sprintf(dest, "%d", SignExtend(line->code[0], 5));
}
/* Format a 5-bit zero-filled immediate operand */
static void dasmOpImm5U(char *dest, VBU_DasmLine *line) {
static void dasmOpImm5U(char *dest, VBU_DasmConfig*config, VBU_DasmLine *line){
if (config->immediateNotation == VBU_NUMBER)
*dest++ = '#';
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 (config->immediateNotation == VBU_NUMBER)
*dest++ = '#';
if (imm >= -256 && imm <= 256) {
sprintf(dest, "%d", imm);
return;
@@ -279,6 +285,8 @@ static void dasmOpImm16S(char*dest, VBU_DasmConfig*config, VBU_DasmLine*line) {
/* 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];
if (config->immediateNotation == VBU_NUMBER)
*dest++ = '#';
dasmToHex(dest, config, 4, imm);
}
@@ -441,12 +449,6 @@ static VBU_DasmLine* dasmGrow(
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) {
@@ -454,8 +456,8 @@ static void dasmOperand(char *dest, VBU_DasmConfig *config,
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_IMM5S : dasmOpImm5S (dest, config, line); break;
case DASM_IMM5U : dasmOpImm5U (dest, config, 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;
@@ -507,10 +509,12 @@ static int dasmLine(VB *sim, uint32_t *address, uint32_t pc,
/* Process non-text members */
line = &(*lines)[index];
line->address = *address;
line->codeLength = dasmInstSize(sim, *address);
line->codeLength = vbuCodeSize(sim, *address);
line->isPC = *address == pc;
for (x = 0; x < line->codeLength; x++)
line->code[x] = vbRead(sim, *address + x, VB_U8);
/* Advance to the next instruction or PC, whichever is sooner */
*address += pc != *address && pc - *address < line->codeLength ?
pc - *address : line->codeLength;
@@ -652,9 +656,11 @@ static VBU_DasmLine* dasmDisassemble(VB *sim, uint32_t address,
}
/* Check if the instruction contains the reference address */
size = dasmInstSize(sim, addr);
size = vbuCodeSize(sim, addr);
if (address - addr < size)
break;
/* Advance to the next instruction or PC, whichever is sooner */
addr += addr != pc && pc - addr < size ? pc - addr : size;
}
@@ -666,7 +672,7 @@ static VBU_DasmLine* dasmDisassemble(VB *sim, uint32_t address,
/* Keep decoding until the first line of output */
else for (; line < 0; line++)
addr += dasmInstSize(sim, addr);
addr += vbuCodeSize(sim, addr);
/* Working variables */
size = length * sizeof (VBU_DasmLine);
@@ -680,7 +686,7 @@ static VBU_DasmLine* dasmDisassemble(VB *sim, uint32_t address,
if (dasmLine(sim, &addr, pc, config, &lines, &size, &offset, x))
goto catch;
}
return lines;
return VBU_REALLOC(lines, offset);
/* Exception handler */
catch:
+7
View File
@@ -38,6 +38,12 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
/******************************* API Commands ********************************/
/* Determine the size in bytes of an instruction */
VBUAPI int vbuCodeSize(VB *sim, uint32_t address) {
int opcode = vbRead(sim, address, VB_U16) >> 10 & 63;
return opcode < 0x20 || opcode == 0x32 || opcode == 0x36 ? 2 : 4;
}
/* Initialize disassembler options with default settings */
VBUAPI VBU_DasmConfig* vbuDasmInit(VBU_DasmConfig *config) {
config->bcondNotation = VBU_JOINED;
@@ -47,6 +53,7 @@ VBUAPI VBU_DasmConfig* vbuDasmInit(VBU_DasmConfig *config) {
config->conditionNotation = VBU_NAMES;
config->hexCase = VBU_UPPER;
config->hexNotation = VBU_0X;
config->immediateNotation = VBU_NONE;
config->memoryNotation = VBU_OUTSIDE;
config->mnemonicCase = VBU_UPPER;
config->operandOrder = VBU_DEST_LAST;
+4
View File
@@ -29,6 +29,8 @@ extern "C" {
#define VBU_L 0
#define VBU_LOWER 1
#define VBU_NAMES 1
#define VBU_NONE 0
#define VBU_NUMBER 1
#define VBU_NUMBERS 0
#define VBU_OUTSIDE 0
#define VBU_SPLIT 1
@@ -48,6 +50,7 @@ typedef struct { /* Defaults listed first */
uint8_t conditionNotation; /* NAMES, NUMBERS */
uint8_t hexCase; /* UPPER, LOWER */
uint8_t hexNotation; /* 0X, H, DOLLAR */
uint8_t immediateNotation; /* NONE, NUMBER */
uint8_t memoryNotation; /* OUTSIDE, INSIDE */
uint8_t mnemonicCase; /* UPPER, LOWER */
uint8_t operandOrder; /* DEST_LAST, DEST_FIRST */
@@ -82,6 +85,7 @@ typedef struct {
/******************************* API Commands ********************************/
VBUAPI int vbuCodeSize (VB *sim, uint32_t address);
VBUAPI VBU_DasmConfig* vbuDasmInit (VBU_DasmConfig *config);
VBUAPI VBU_DasmLine* vbuDisassemble(VB *sim, uint32_t address, VBU_DasmConfig *config, unsigned length, int line);
+2
View File
@@ -61,6 +61,8 @@ let Constants = {
L : 0,
LOWER : 1,
NAMES : 1,
NONE : 0,
NUMBER : 1,
NUMBERS : 0,
OUTSIDE : 0,
SPLIT : 1,
+1
View File
@@ -128,6 +128,7 @@ new class Core {
message.config.conditionNotation,
message.config.hexCase,
message.config.hexNotation,
message.config.immediateNotation,
message.config.memoryNotation,
message.config.mnemonicCase,
message.config.operandOrder,
+15
View File
@@ -19,6 +19,7 @@ class DasmConfig {
#conditionNotation;
#hexCase;
#hexNotation;
#immediateNotation;
#memoryNotation;
#mnemonicCase;
#operandOrder;
@@ -40,6 +41,7 @@ class DasmConfig {
this.#conditionNotation = Constants.VBU.NAMES;
this.#hexCase = Constants.VBU.UPPER;
this.#hexNotation = Constants.VBU["0X"];
this.#immediateNotation = Constants.VBU.NONE;
this.#memoryNotation = Constants.VBU.OUTSIDE;
this.#mnemonicCase = Constants.VBU.UPPER;
this.#operandOrder = Constants.VBU.DEST_LAST;
@@ -125,6 +127,16 @@ class DasmConfig {
this.#hexNotation = value;
}
get immediateNotation() { return this.#immediateNotation; }
set immediateNotation(value) {
switch (value) {
case Constants.VBU.NONE :
case Constants.VBU.NUMBER: break;
default: return;
}
this.#immediateNotation = value;
}
get memoryNotation() { return this.#memoryNotation; }
set memoryNotation(value) {
switch (value) {
@@ -407,6 +419,7 @@ class Sim extends HTMLElement {
conditionNotation: config.conditionNotation,
hexCase : config.hexCase,
hexNotation : config.hexNotation,
immediateNotation: config.immediateNotation,
memoryNotation : config.memoryNotation,
mnemonicCase : config.mnemonicCase,
operandOrder : config.operandOrder,
@@ -650,6 +663,8 @@ class VB {
static get L () { return Constants.VBU.L ; }
static get LOWER () { return Constants.VBU.LOWER ; }
static get NAMES () { return Constants.VBU.NAMES ; }
static get NONE () { return Constants.VBU.NONE ; }
static get NUMBER () { return Constants.VBU.NUMBER ; }
static get NUMBERS () { return Constants.VBU.NUMBERS ; }
static get OUTSIDE () { return Constants.VBU.OUTSIDE ; }
static get RELATIVE () { return Constants.VBU.RELATIVE ; }
+4 -3
View File
@@ -108,9 +108,9 @@ EMSCRIPTEN_KEEPALIVE void* CreateSim() {
// Disassemble from a simulation
EMSCRIPTEN_KEEPALIVE void* Disassemble(
int bcondNotation, int conditionCase, int conditionCL, int conditionEZ,
int conditionNotation, int hexCase, int hexNotation, int memoryNotation,
int mnemonicCase, int operandOrder, int programCase, int programNotation,
int setfNotation, int systemCase, int systemNotation,
int conditionNotation, int hexCase, int hexNotation, int immediateNotation,
int memoryNotation, int mnemonicCase, int operandOrder, int programCase,
int programNotation, int setfNotation, int systemCase, int systemNotation,
VB *sim, uint32_t address, unsigned length, int line
) {
VBU_DasmConfig config;
@@ -121,6 +121,7 @@ EMSCRIPTEN_KEEPALIVE void* Disassemble(
config.conditionNotation = conditionNotation;
config.hexCase = hexCase;
config.hexNotation = hexNotation;
config.immediateNotation = immediateNotation;
config.memoryNotation = memoryNotation;
config.mnemonicCase = mnemonicCase;
config.operandOrder = operandOrder;