Implement VIP, fix interrupts
This commit is contained in:
		
							parent
							
								
									3c2c9bb938
								
							
						
					
					
						commit
						37b9a94338
					
				| 
						 | 
				
			
			@ -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 |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								core/vb.c
								
								
								
								
							
							
						
						
									
										14
									
								
								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++;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										479
									
								
								core/vip.c
								
								
								
								
							
							
						
						
									
										479
									
								
								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,7 +73,7 @@ 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 mask = 0; /* Byte access mask */
 | 
			
		||||
    int32_t value;    /* Return value */
 | 
			
		||||
 | 
			
		||||
    /* Adjustments by 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,11 +462,13 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
 | 
			
		|||
                vipThrow(sim, 0x0010); /* FRAMESTART */
 | 
			
		||||
 | 
			
		||||
                /* Game frame */
 | 
			
		||||
                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.dp.buffer  ^= 1;
 | 
			
		||||
                            sim->vip.xp.overtime = 0;
 | 
			
		||||
                            sim->vip.xp.step     = 1;
 | 
			
		||||
                            vipThrow(sim, 0x0008); /* GAMESTART */
 | 
			
		||||
| 
						 | 
				
			
			@ -424,6 +481,7 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                    } 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 */
 | 
			
		||||
            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 */
 | 
			
		||||
            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;
 | 
			
		||||
 | 
			
		||||
            case 3: /* Draw halfwords */
 | 
			
		||||
                vipDrawWorlds(sim);
 | 
			
		||||
                sim->vip.xp.until = 2000; /* 100us */
 | 
			
		||||
                /* Transition to a new line of halfwords */
 | 
			
		||||
                sim->vip.xp.sbcount++;
 | 
			
		||||
                sim->vip.xp.step = sim->vip.xp.sbcount == 28 ? 4 : 2;
 | 
			
		||||
                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,6 +1022,7 @@ static int vipEmulate(VB *sim, uint32_t clocks) {
 | 
			
		|||
 | 
			
		||||
    /* Process sub-components */
 | 
			
		||||
    int brk = vipEmulateDisplay(sim, clocks);
 | 
			
		||||
    if (sim->vip.xp.step != 0)
 | 
			
		||||
        vipEmulateDrawing(sim, clocks);
 | 
			
		||||
 | 
			
		||||
    /* Process SBOUT */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								makefile
								
								
								
								
							
							
						
						
									
										16
									
								
								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 \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue