diff --git a/core/cpu.c b/core/cpu.c index 3eee310..a5eddc1 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -376,7 +376,7 @@ static uint32_t cpuSetSystemRegister(VB*sim, case VB_FEPSW: return sim->cpu.fepsw = value & 0x000FF3FF; case VB_PIR : return 0x00005346; case VB_PSW : - sim->cpu.psw.i = value >> 16 & 0xF; + sim->cpu.psw.i = value >> 16 & 15; sim->cpu.psw.np = value >> 15 & 1; sim->cpu.psw.ep = value >> 14 & 1; sim->cpu.psw.ae = value >> 13 & 1; @@ -414,7 +414,7 @@ static int cpuIRQ(VB *sim) { if (sim->cpu.psw.id | sim->cpu.psw.ep | sim->cpu.psw.np) return 0; level = IRQ_LEVELS[sim->cpu.irq]; - if (level == -1 || level > sim->cpu.psw.i) + if (level < sim->cpu.psw.i) return 0; cpuThrow(sim, 0xFE00 | level << 4); return 1; @@ -476,6 +476,9 @@ static int cpuException(VB *sim) { /* Regular exception */ else { + /* All exceptions */ + sim->cpu.eipsw = cpuGetSystemRegister(sim, VB_PSW); + /* Interrupts only */ if ((cause & 0xFF00) == 0xFE00) { sim->cpu.psw.i = (cause >> 4 & 7) + 1; @@ -487,7 +490,6 @@ static int cpuException(VB *sim) { /* All exceptions */ sim->cpu.ecr.eicc = cause; - sim->cpu.eipsw = cpuGetSystemRegister(sim, VB_PSW); sim->cpu.eipc = sim->cpu.pc; sim->cpu.psw.ep = 1; sim->cpu.nextPC = 0xFFFF0000 | diff --git a/core/vb.c b/core/vb.c index 1da541e..5d2124a 100644 --- a/core/vb.c +++ b/core/vb.c @@ -8,6 +8,9 @@ /*********************************** Types ***********************************/ +/* Output image */ +typedef uint8_t Pixels[2][384*224]; + /* Simulation state */ struct VB { @@ -126,6 +129,7 @@ struct VB { /* Pixel processor */ struct { + /* Hardware state */ uint8_t f0bsy; /* Drawing into frame buffer 0 */ uint8_t f1bsy; /* Drawing into frame buffer 1 */ @@ -137,7 +141,9 @@ struct VB { /* Simulation state */ uint32_t clocks; /* Master clocks to wait */ + int column; /* Current horizontal output position */ int frame; /* FRMCYC counter */ + int32_t halfword; /* Current output halfword offset */ int step; /* Processing phase */ uint32_t until; /* Clocks until interrupt condition */ } xp; @@ -152,8 +158,10 @@ struct VB { uint8_t jplt[4][4]; /* Object palettes */ uint16_t spt[4]; /* Object control */ - /* Output frame buffers [buffer index][0=left, 1=right][pixel index] */ - uint8_t frames[2][2][384*224]; + /* Rendering shadow memory */ + uint16_t halfwords[384*28]; /* Output timing by 1x8 halfword */ + Pixels output[2]; /* Output images, row-major */ + Pixels shadow; /* Drawing shadow image, column-major */ /* Other state */ uint8_t ram[0x40000]; /* Video memory */ @@ -319,7 +327,7 @@ VBAPI void vbGetPixels(VB *sim, void *left, int leftStrideX, int leftStrideY, continue; /* Transfer pixels to the destination */ - src = sim->vip.frames[sim->vip.dp.buffer][i]; + src = sim->vip.output[sim->vip.dp.buffer ^ 1][i]; for (y = 0; y < 224; y++, dest += yStride) for (x = offset = 0; x < 384; x++, offset += xStride) dest[offset] = *src++; diff --git a/core/vip.c b/core/vip.c index 20d1f50..d8aa347 100644 --- a/core/vip.c +++ b/core/vip.c @@ -8,10 +8,47 @@ /* Compute how many clocks are in some number of milliseconds */ #define vipClocksMs(x) x * 20000 +/* Read a world line parameter value */ +#define vipParam(x) busReadBuffer(&sim->vip.ram[x], VB_U16) + + + +/******************************** Lookup Data ********************************/ + +/* BG map arrangement by world background dimensions */ +static const uint8_t BG_TEMPLATES[][64] = { + { 0 }, /* 1x1 */ + { 0, 1 }, /* 1x2 */ + { 0, 1, 2, 3 }, /* 1x4 */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* 1x8 */ + { 0, 1 }, /* 2x1 */ + { 0, 1, 2, 3 }, /* 2x2 */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* 2x4 */ + { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 }, /* 2x8 */ + { 0, 1, 2, 3 }, /* 4x1 */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* 4x2 */ + { 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7 }, /* 4x4 */ + { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, /* 4x8 */ + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7 }, + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* 8x1 */ + { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7 }, /* 8x2 */ + { 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, /* 8x4 */ + 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x8 */ + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7 } +}; + /***************************** 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; @@ -36,8 +73,8 @@ static void vipWritePalette(uint8_t *entries, int32_t mask, int32_t value) { /* Read a typed value from an I/O register */ static int32_t vipReadIO(VB *sim, uint32_t address, int type) { - int32_t mask; /* Byte access mask */ - int32_t value; /* Return value */ + int32_t mask = 0; /* Byte access mask */ + int32_t value; /* Return value */ /* Adjustments by type */ switch (type) { @@ -211,7 +248,7 @@ static void vipWriteIO( break; case 0x5F804>>1: /* INTCLR */ sim->vip.intpnd &= ~value; - if (sim->vip.intpnd == 0) + if ((sim->vip.intpnd & sim->vip.intenb) == 0) sim->cpu.irq &= ~0x0010; break; @@ -223,7 +260,16 @@ static void vipWriteIO( } if ((mask & 0x00FF) == 0) { sim->vip.dp.disp = value >> 1 & 1; - /* if (value & 1) {} TODO: DPRST */ + + /* DPRST */ + if (value & 1) { + sim->vip.intenb &= ~0x801F; + sim->vip.intpnd &= ~0x801F; + if ((sim->vip.intpnd & sim->vip.intenb) == 0) + sim->cpu.irq &= ~0x0010; + /* TODO: Research exact operation */ + } + } break; @@ -256,7 +302,16 @@ static void vipWriteIO( sim->vip.xp.sbcmp = value >> 8 & 31; if ((mask & 0x00FF) == 0) { sim->vip.xp.xpen = value >> 1 & 1; - /* if (value & 1) TODO: XPRST */ + + /* XPRST */ + if (value & 1) { + sim->vip.intenb &= ~0xE000; + sim->vip.intpnd &= ~0xE000; + if ((sim->vip.intpnd & sim->vip.intenb) == 0) + sim->cpu.irq &= ~0x0010; + /* TODO: Research exact operation */ + } + } break; @@ -350,7 +405,7 @@ static void vipTransferColumn(VB *sim, int32_t eye) { int y, z; /* Iterators */ /* Select destination address in host memory */ - dest = &sim->vip.frames + dest = &sim->vip.output [sim->vip.dp.buffer][eye][sim->vip.dp.column]; /* Output is disabled */ @@ -407,23 +462,26 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) { vipThrow(sim, 0x0010); /* FRAMESTART */ /* Game frame */ - if (sim->vip.xp.frame >= sim->vip.frmcyc) { - sim->vip.xp.frame = 0; + if (sim->vip.xp.xpen) { + if (sim->vip.xp.frame >= sim->vip.frmcyc) { + sim->vip.xp.frame = 0; - /* Initiate drawing procedure */ - if (sim->vip.xp.step == 0) { - sim->vip.xp.overtime = 0; - sim->vip.xp.step = 1; - vipThrow(sim, 0x0008); /* GAMESTART */ - } + /* Initiate drawing procedure */ + if (sim->vip.xp.step == 0) { + sim->vip.dp.buffer ^= 1; + sim->vip.xp.overtime = 0; + sim->vip.xp.step = 1; + vipThrow(sim, 0x0008); /* GAMESTART */ + } - /* Drawing procedure has run into overtime */ - else { - sim->vip.xp.overtime = 1; - vipThrow(sim, 0x8000); /* TIMEERR */ - } + /* Drawing procedure has run into overtime */ + else { + sim->vip.xp.overtime = 1; + vipThrow(sim, 0x8000); /* TIMEERR */ + } - } else sim->vip.xp.frame++; + } else sim->vip.xp.frame++; + } break; @@ -518,9 +576,375 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) { /****************************** Pixel Processor ******************************/ -/* Draw every world into a group of 8 rows of pixels */ -static void vipDrawWorlds(VB *sim) { - (void) sim; +/* 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 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 */ + + /* 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 = (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 */ + for (i = 0; i < 2; i++) { + if ((attr1 >> (15 - i) & 1) == 0) /* J*ON */ + 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 */ + } /* x */ + + } /* y */ + + } /* i */ + + /* All objects have been drawn */ + if (o == start) + break; + } + +} + +/* Draw a background world into shadow memory */ +static void vipDrawWorld(VB *sim, uint8_t *world, uint16_t attr) { + uint8_t *bg; /* Background arrangement */ + 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 */ + 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 */ + uint8_t *dest; /* Pointer to output in shadow memory */ + int32_t left; /* Window left edge position */ + 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 */ + 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 */ + 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; + + /* 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; + + /* Draw the world */ + for (i = 0; i < 2; i++) { + + /* Validate world is enabled */ + if ((attr & (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; + + /* Draw all rows */ + for (y = top, param = params; y <= bottom; y++) { + + /* Parse line parameters */ + switch (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); + mx = ((int32_t) (int16_t) vipParam(param ) << 13) + + dx * (left - ((mp < 0) ^ i ? mp : 0)); + my = ((int32_t) (int16_t) vipParam(param | 4) << 13) + + dy * (left - ((mp < 0) ^ i ? mp : 0)); + param += 16; + } + + /* Select output in shadow memory */ + dest = &sim->vip.shadow[i][left * 224 + y]; + + /* Draw all columns */ + for (x = left; x <= 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; + } 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 > bgw || by < 0 || by > bgh) { + if (over == NULL) { + bx &= bgw; + by &= bgh; + } + else cell = over; + } + + /* Locate the cell in the BG map */ + if (cell == NULL) { + cell = &sim->vip.ram[ + 0x20000 | + (base + bg[by << 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 */ + int32_t x, y; /* Iterators */ + + /* Erase all pixels */ + for (x = 0; x < 384*224; x += 224) + for (y = (int32_t) sim->vip.xp.sbcount << 3; y < 224; y++) + sim->vip.shadow[0][x + y] = sim->vip.shadow[1][x + y] = sim->vip.bkcol; + + /* 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); + + /* Non-graphical world */ + if (attr & 0x0020) /* END */ + break; /* Control world */ + if ((attr & 0xC000) == 0) /* LON, RON */ + continue; /* Dummy world */ + + /* Object world */ + if ((attr >> 12 & 3) == 3) { + vipDrawObjects(sim, group); + group = (group - 1) & 3; + } + + /* Background world */ + else if (attr & 0xC000) /* LON, RON */ + vipDrawWorld(sim, world, attr); + } + + /* + Supply filler timings for each group of 8 rows of pixels + Using 2.8ms experimental measurement for empty frame + = 125 clocks every 24 halfwords + */ + timing = &sim->vip.halfwords[(uint32_t) sim->vip.xp.sbcount * 384]; + x = sim->vip.xp.column; + for (y = sim->vip.xp.sbcount; y < 28; y++, x = 0) + for (; x < 384; x++, timing++) + *timing = 5 + ((uint32_t) 0x210884 >> x % 24 & 1); +} + +/* Transfer one halfword from shadow pixel memory to the frame buffer */ +static void vipTransferHalfword(VB *sim) { + uint32_t bits0; /* Upper 4 pixels from shadow memory */ + uint32_t bits1; /* Lower 4 pixels from shadow memory */ + uint8_t *dest; /* Pointer to frame buffer data in host memory */ + uint32_t offset; /* Position of halfword in shadow memory */ + uint8_t *src; /* Pointer to pixel data in host memory */ + int i; /* Iterator */ + + /* Determine the output address in frame buffer memory */ + dest = &sim->vip.ram[ + (uint32_t) (sim->vip.dp.buffer ^ 1) << 15 | + (uint32_t) sim->vip.xp.column << 6 | + (uint32_t) sim->vip.xp.sbcount << 1 + ]; + + /* Transfer halfwords to each eye's frame buffer */ + offset = (uint32_t) sim->vip.xp.column * 224 + + ((uint32_t) sim->vip.xp.sbcount << 3); + for (i = 0; i < 2; i++, dest += 0x10000) { + src = &sim->vip.shadow[i][offset]; + bits0 = busReadBuffer(src , VB_S32); + bits1 = busReadBuffer(src + 4, VB_S32); + busWriteBuffer(dest, VB_U16, + (bits0 & 0x0003) | + (bits0 >> 6 & 0x000C) | + (bits0 >> 12 & 0x0030) | + (bits0 >> 18 & 0x00C0) | + (bits1 << 8 & 0x0300) | + (bits1 << 2 & 0x0C00) | + (bits1 >> 4 & 0x3000) | + (bits1 >> 10 & 0xC000) + ); + } + } /* Process sub-component */ @@ -544,29 +968,49 @@ static void vipEmulateDrawing(VB *sim, uint32_t clocks) { /* Processing by operation phase */ switch (sim->vip.xp.step) { - case 1: /* Initialize */ - sim->vip.xp.sbcount = 0; + case 1: /* Initialization */ + sim->vip.xp.halfword = 0; + sim->vip.xp.sbcount = 0; + if (sim->vip.dp.buffer == 0) + sim->vip.xp.f1bsy = 1; + else sim->vip.xp.f0bsy = 1; + vipRender(sim); /* Fallthrough */ - case 2: /* Transition to a new row of halfwords */ - sim->vip.xp.sbout = 2240; /* 112us */ - sim->vip.xp.step = 3; + case 2: /* Begin drawing halfwords */ + sim->vip.xp.column = 0; + sim->vip.xp.sbout = 2240; /* 112us */ + sim->vip.xp.step = 3; + sim->vip.xp.until = 2000; /* 100us */ if (sim->vip.xp.sbcount == sim->vip.xp.sbcmp) vipThrow(sim, 0x2000); /* SBHIT */ + + /* Fallthrough */ + case 3: /* Draw one halfword */ + vipTransferHalfword(sim); + sim->vip.xp.clocks = sim->vip.halfwords[sim->vip.xp.halfword]; + sim->vip.xp.column ++; + sim->vip.xp.halfword++; + if (sim->vip.xp.column < 384) + break; + + /* Transition to a new line of halfwords */ + sim->vip.xp.sbcount++; + sim->vip.xp.step = sim->vip.xp.sbcount == 28 ? 4 : 2; break; - case 3: /* Draw halfwords */ - vipDrawWorlds(sim); - sim->vip.xp.until = 2000; /* 100us */ - break; - - case 4: /* Finalize */ + case 4: /* Drawing complete */ sim->vip.xp.step = 0; + if (sim->vip.dp.buffer == 0) + sim->vip.xp.f1bsy = 0; + else sim->vip.xp.f0bsy = 0; vipThrow(sim, 0x4000); /* XPEND */ + return; } } + return; /* Unreachable */ } @@ -578,12 +1022,13 @@ static int vipEmulate(VB *sim, uint32_t clocks) { /* Process sub-components */ int brk = vipEmulateDisplay(sim, clocks); - vipEmulateDrawing(sim, clocks); + if (sim->vip.xp.step != 0) + vipEmulateDrawing(sim, clocks); /* Process SBOUT */ if (sim->vip.xp.sbout != 0) { if (sim->vip.xp.sbout <= clocks) { - sim->vip.xp.sbout = 0; + sim->vip.xp.sbout = 0; } else sim->vip.xp.sbout -= clocks; } @@ -609,7 +1054,7 @@ static void vipRead(VB *sim, uint32_t address, int type, int32_t *value) { *value = vipReadIO(sim, address, type); /* Unmapped */ - if (address < 0x78000) + else if (address < 0x78000) *value = 0; /* Mirrors of character memory */ @@ -655,7 +1100,7 @@ static void vipReset(VB *sim) { sim->vip.dp.lock = 0; sim->vip.dp.r0bsy = 0; sim->vip.dp.r1bsy = 0; - sim->vip.dp.scanrdy = 0; + sim->vip.dp.scanrdy = 1; /* Pixel processor extra (the hardware does not do this) */ sim->vip.xp.f0bsy = 0; @@ -682,6 +1127,8 @@ static void vipReset(VB *sim) { static uint32_t vipUntil(VB *sim, uint32_t clocks) { if (clocks > sim->vip.dp.until) clocks = sim->vip.dp.until; + if (sim->vip.xp.step != 0 && clocks > sim->vip.xp.until) + clocks = sim->vip.xp.until; return clocks; } diff --git a/makefile b/makefile index 512f781..0565716 100644 --- a/makefile +++ b/makefile @@ -20,21 +20,21 @@ clean: .PHONY: core core: # GCC generic - @gcc core/vb.c -I core -c -o /dev/null \ - -Werror -std=c90 -Wall -Wextra -Wpedantic + @gcc core/vb.c -I core -c -o /dev/null -O3 \ + -Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing # GCC compilation control - @gcc core/vb.c -I core -c -o /dev/null \ - -Werror -std=c90 -Wall -Wextra -Wpedantic \ + @gcc core/vb.c -I core -c -o /dev/null -O3 \ + -Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing \ -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \ -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_READ=testRead # Clang generic - @emcc core/vb.c -I core -c -o /dev/null \ - -Werror -std=c90 -Wall -Wextra -Wpedantic + @emcc core/vb.c -I core -c -o /dev/null -O3 \ + -Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing # Clang compilation control - @emcc core/vb.c -I core -c -o /dev/null \ - -Werror -std=c90 -Wall -Wextra -Wpedantic \ + @emcc core/vb.c -I core -c -o /dev/null -O3 \ + -Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing \ -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \ -D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \ -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \