dsp4emu.c
来自「linux下的任天堂模拟器代码。供大家参考。」· C语言 代码 · 共 2,173 行 · 第 1/5 页
C
2,173 行
x_left = (int16)(win_left >> 16); x_right = (int16)(win_right >> 16); // saturate offscreen data if (x_left < DSP4_vars.poly_clipLf[polygon][0]) x_left = DSP4_vars.poly_clipLf[polygon][0]; if (x_left > DSP4_vars.poly_clipRt[polygon][0]) x_left = DSP4_vars.poly_clipRt[polygon][0]; if (x_right < DSP4_vars.poly_clipLf[polygon][1]) x_right = DSP4_vars.poly_clipLf[polygon][1]; if (x_right > DSP4_vars.poly_clipRt[polygon][1]) x_right = DSP4_vars.poly_clipRt[polygon][1]; // 1. HDMA memory pointer // 2. Left window position ($2126/$2128) // 3. Right window position ($2127/$2129) DSP4_WRITE_WORD(DSP4_vars.poly_ptr[polygon][0]); DSP4_WRITE_BYTE(x_left & 0xff); DSP4_WRITE_BYTE(x_right & 0xff); // update memory pointers DSP4_vars.poly_ptr[polygon][0] -= 4; DSP4_vars.poly_ptr[polygon][1] -= 4; } // end rasterize line } //////////////////////////////////////////////// // Post-update // new projection spot to continue rasterizing from DSP4_vars.poly_start[polygon] = view_x[poly]; } // end polygon rasterizer } while (1); // unknown output DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(0); DSP4.waiting4command = TRUE;}//////////////////////////////////////////////////////////////void DSP4_OP09(){ DSP4.waiting4command = FALSE; // op flow control switch (DSP4_vars.DSP4_Logic) { case 1: goto resume1; break; case 2: goto resume2; break; case 3: goto resume3; break; case 4: goto resume4; break; case 5: goto resume5; break; case 6: goto resume6; break; } //////////////////////////////////////////////////// // process initial inputs // grab screen information DSP4_vars.viewport_cx = DSP4_READ_WORD(); DSP4_vars.viewport_cy = DSP4_READ_WORD(); DSP4_READ_WORD(); // 0x0000 DSP4_vars.viewport_left = DSP4_READ_WORD(); DSP4_vars.viewport_right = DSP4_READ_WORD(); DSP4_vars.viewport_top = DSP4_READ_WORD(); DSP4_vars.viewport_bottom = DSP4_READ_WORD(); // starting DSP4_vars.raster line below the horizon DSP4_vars.poly_bottom[0][0] = DSP4_vars.viewport_bottom - DSP4_vars.viewport_cy; DSP4_vars.poly_raster[0][0] = 0x100; do { //////////////////////////////////////////////////// // check for new sprites DSP4.in_count = 4; DSP4_WAIT(1) resume1 : //////////////////////////////////////////////// // DSP4_vars.raster overdraw check DSP4_vars.raster = DSP4_READ_WORD(); // continue updating the DSP4_vars.raster line where overdraw begins if (DSP4_vars.raster < DSP4_vars.poly_raster[0][0]) { DSP4_vars.sprite_clipy = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster); DSP4_vars.poly_raster[0][0] = DSP4_vars.raster; } ///////////////////////////////////////////////// // identify sprite // op termination DSP4_vars.distance = DSP4_READ_WORD(); if (DSP4_vars.distance == -0x8000) goto terminate; // no sprite if (DSP4_vars.distance == 0x0000) { continue; } //////////////////////////////////////////////////// // process projection information // vehicle sprite if ((uint16) DSP4_vars.distance == 0x9000) { int16 car_left, car_right, car_back; int16 impact_left, impact_back; int16 world_spx, world_spy; int16 view_spx, view_spy; uint16 energy; // we already have 4 bytes we want DSP4.in_count = 14; DSP4_WAIT(2) resume2 : // filter inputs energy = DSP4_READ_WORD(); impact_back = DSP4_READ_WORD(); car_back = DSP4_READ_WORD(); impact_left = DSP4_READ_WORD(); car_left = DSP4_READ_WORD(); DSP4_vars.distance = DSP4_READ_WORD(); car_right = DSP4_READ_WORD(); // calculate car's world (x,y) values world_spx = car_right - car_left; world_spy = car_back; // add in collision vector [needs bit-twiddling] world_spx -= energy * (impact_left - car_left) >> 16; world_spy -= energy * (car_back - impact_back) >> 16; // perspective correction for world (x,y) view_spx = world_spx * DSP4_vars.distance >> 15; view_spy = world_spy * DSP4_vars.distance >> 15; // convert to screen values DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx; DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - view_spy); // make the car's (x)-coordinate available DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(world_spx); // grab a few remaining vehicle values DSP4.in_count = 4; DSP4_WAIT(3) resume3 : // add vertical lift factor DSP4_vars.sprite_y += DSP4_READ_WORD(); } // terrain sprite else { int16 world_spx, world_spy; int16 view_spx, view_spy; // we already have 4 bytes we want DSP4.in_count = 10; DSP4_WAIT(4) resume4 : // sort loop inputs DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); DSP4_vars.poly_raster[0][1] = DSP4_READ_WORD(); world_spx = DSP4_READ_WORD(); world_spy = DSP4_READ_WORD(); // compute base DSP4_vars.raster line from the bottom DSP4_vars.segments = DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster; // perspective correction for world (x,y) view_spx = world_spx * DSP4_vars.distance >> 15; view_spy = world_spy * DSP4_vars.distance >> 15; // convert to screen values DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx - DSP4_vars.poly_cx[0][0]; DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - DSP4_vars.segments + view_spy; } // default sprite size: 16x16 DSP4_vars.sprite_size = 1; DSP4_vars.sprite_attr = DSP4_READ_WORD(); //////////////////////////////////////////////////// // convert tile data to SNES OAM format do { uint16 header; int16 sp_x, sp_y, sp_attr, sp_dattr; int16 sp_dx, sp_dy; int16 pixels; bool8 draw; DSP4.in_count = 2; DSP4_WAIT(5) resume5 : draw = TRUE; // opcode termination DSP4_vars.raster = DSP4_READ_WORD(); if (DSP4_vars.raster == -0x8000) goto terminate; // stop code if (DSP4_vars.raster == 0x0000 && !DSP4_vars.sprite_size) break; // toggle sprite size if (DSP4_vars.raster == 0x0000) { DSP4_vars.sprite_size = !DSP4_vars.sprite_size; continue; } // check for valid sprite header header = DSP4_vars.raster; header >>= 8; if (header != 0x20 && header != 0x2e && //This is for attractor sprite header != 0x40 && header != 0x60 && header != 0xa0 && header != 0xc0 && header != 0xe0) break; // read in rest of sprite data DSP4.in_count = 4; DSP4_WAIT(6) resume6 : draw = TRUE; ///////////////////////////////////// // process tile data // sprite deltas sp_dattr = DSP4_vars.raster; sp_dy = DSP4_READ_WORD(); sp_dx = DSP4_READ_WORD(); // update coordinates to screen space sp_x = DSP4_vars.sprite_x + sp_dx; sp_y = DSP4_vars.sprite_y + sp_dy; // update sprite nametable/attribute information sp_attr = DSP4_vars.sprite_attr + sp_dattr; // allow partially visibile tiles pixels = DSP4_vars.sprite_size ? 15 : 7; DSP4_CLEAR_OUT(); // transparent tile to clip off parts of a sprite (overdraw) if (DSP4_vars.sprite_clipy - pixels <= sp_y && sp_y <= DSP4_vars.sprite_clipy && sp_x >= DSP4_vars.viewport_left - pixels && sp_x <= DSP4_vars.viewport_right && DSP4_vars.sprite_clipy >= DSP4_vars.viewport_top - pixels && DSP4_vars.sprite_clipy <= DSP4_vars.viewport_bottom) { DSP4_OP0B(&draw, sp_x, DSP4_vars.sprite_clipy, 0x00EE, DSP4_vars.sprite_size, 0); } // normal sprite tile if (sp_x >= DSP4_vars.viewport_left - pixels && sp_x <= DSP4_vars.viewport_right && sp_y >= DSP4_vars.viewport_top - pixels && sp_y <= DSP4_vars.viewport_bottom && sp_y <= DSP4_vars.sprite_clipy) { DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, DSP4_vars.sprite_size, 0); } // no following OAM data DSP4_OP0B(&draw, 0, 0x0100, 0, 0, 1); } while (1); } while (1); terminate : DSP4.waiting4command = TRUE;}//////////////////////////////////////////////////////////////const uint16 OP0A_Values[16] = { 0x0000, 0x0030, 0x0060, 0x0090, 0x00c0, 0x00f0, 0x0120, 0x0150, 0xfe80, 0xfeb0, 0xfee0, 0xff10, 0xff40, 0xff70, 0xffa0, 0xffd0 };void DSP4_OP0A(int16 n2, int16 *o1, int16 *o2, int16 *o3, int16 *o4){ *o4 = OP0A_Values[(n2 & 0x000f)]; *o3 = OP0A_Values[(n2 & 0x00f0) >> 4]; *o2 = OP0A_Values[(n2 & 0x0f00) >> 8]; *o1 = OP0A_Values[(n2 & 0xf000) >> 12];}//////////////////////////////////////////////////////////////void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop){ int16 Row1, Row2; // SR = 0x00 // align to nearest 8-pixel row Row1 = (sp_y >> 3) & 0x1f; Row2 = (Row1 + 1) & 0x1f; // check boundaries if (!((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb))) { *draw = 0; } if (size) { if (DSP4_vars.OAM_Row[Row1] + 1 >= DSP4_vars.OAM_RowMax) *draw = 0; if (DSP4_vars.OAM_Row[Row2] + 1 >= DSP4_vars.OAM_RowMax) *draw = 0; } else { if (DSP4_vars.OAM_Row[Row1] >= DSP4_vars.OAM_RowMax) { *draw = 0; } } // emulator fail-safe (unknown if this really exists) if (DSP4_vars.sprite_count >= 128) { *draw = 0; } // SR = 0x80 if (*draw) { // Row tiles if (size) { DSP4_vars.OAM_Row[Row1] += 2; DSP4_vars.OAM_Row[Row2] += 2; } else { DSP4_vars.OAM_Row[Row1]++; } // yield OAM output DSP4_WRITE_WORD(1); // pack OAM data: x,y,name,attr DSP4_WRITE_BYTE(sp_x & 0xff); DSP4_WRITE_BYTE(sp_y & 0xff); DSP4_WRITE_WORD(sp_attr); DSP4_vars.sprite_count++; // OAM: size,msb data // save post-oam table data for future retrieval DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= ((sp_x <0 || sp_x> 255) << DSP4_vars.OAM_bits); DSP4_vars.OAM_bits++; DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= (size << DSP4_vars.OAM_bits); DSP4_vars.OAM_bits++; // move to next byte in buffer if (DSP4_vars.OAM_bits == 16) { DSP4_vars.OAM_bits = 0; DSP4_vars.OAM_index++; } } else if (stop) { // yield no OAM output DSP4_WRITE_WORD(0); }}//////////////////////////////////////////////////////////////void DSP4_OP0D(){ DSP4.waiting4command = FALSE; // op flow control switch (DSP4_vars.DSP4_Logic) { case 1: goto resume1; break; case 2: goto resume2; break; } //////////////////////////////////////////////////// // process initial inputs // sort inputs DSP4_vars.world_y = DSP4_READ_DWORD(); DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); DSP4_vars.viewport_bottom = DSP4_READ_WORD(); DSP4_vars.world_x = DSP4_READ_DWORD(); DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4_vars.world_yofs = DSP4_READ_WORD(); DSP4_vars.world_dy = DSP4_READ_DWORD();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?