diff options
author | gameblabla | 2019-10-05 03:04:57 +0200 |
---|---|---|
committer | gameblabla | 2019-10-05 03:04:57 +0200 |
commit | d4753076e89d42cdad4a4f1ca4688fad3c56d873 (patch) | |
tree | c8641cf282f427d9329db00325e16609acca8663 /source/dsp4emu.h | |
parent | 943821f94b9b2e22315fce876c2e369da7a79bcf (diff) | |
download | snesemu-d4753076e89d42cdad4a4f1ca4688fad3c56d873.tar.gz snesemu-d4753076e89d42cdad4a4f1ca4688fad3c56d873.tar.bz2 snesemu-d4753076e89d42cdad4a4f1ca4688fad3c56d873.zip |
Port the libretro core and make it standalone.
TODO :
- Input should use our config file instead.
- Missing audio in some games. (Star Ocean, doesn't happen with stock retroarch code. Odd...)
Diffstat (limited to 'source/dsp4emu.h')
-rw-r--r-- | source/dsp4emu.h | 1227 |
1 files changed, 1227 insertions, 0 deletions
diff --git a/source/dsp4emu.h b/source/dsp4emu.h new file mode 100644 index 0000000..da6e80f --- /dev/null +++ b/source/dsp4emu.h @@ -0,0 +1,1227 @@ +#include "../copyright" + +#include "dsp4.h" +#include "memmap.h" + +#define DSP4_READ_WORD(x) \ + READ_WORD(DSP4.parameters+x) + +#define DSP4_WRITE_WORD(x,d) \ + WRITE_WORD(DSP4.output+x,d); + +/* used to wait for dsp i/o */ +#define DSP4_WAIT(x) \ + DSP4_Logic = x; \ + return + +int32_t DSP4_Multiply(int16_t Multiplicand, int16_t Multiplier) +{ + return Multiplicand * Multiplier; +} + +int16_t DSP4_UnknownOP11(int16_t A, int16_t B, int16_t C, int16_t D) +{ + return ((A * 0x0155 >> 2) & 0xf000) | ((B * 0x0155 >> 6) & 0x0f00) | ((C * 0x0155 >> 10) & 0x00f0) | ((D * 0x0155 >> 14) & 0x000f); +} + +void DSP4_Op06(bool size, bool msb) +{ + /* save post-oam table data for future retrieval */ + op06_OAM[op06_index] |= (msb << (op06_offset + 0)); + op06_OAM[op06_index] |= (size << (op06_offset + 1)); + op06_offset += 2; + + if (op06_offset == 8) + { + /* move to next byte in buffer */ + op06_offset = 0; + op06_index++; + } +} + +void DSP4_Op01(void) +{ + int16_t plane; + int16_t index, lcv; + int16_t py_dy, px_dx; + int16_t y_out, x_out; + uint16_t command; + DSP4.waiting4command = false; + + switch (DSP4_Logic) /* op flow control */ + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* + * process initial inputs + */ + + /* sort inputs */ + project_focaly = DSP4_READ_WORD(0x02); + raster = DSP4_READ_WORD(0x04); + viewport_top = DSP4_READ_WORD(0x06); + project_y = DSP4_READ_WORD(0x08); + viewport_bottom = DSP4_READ_WORD(0x0a); + project_x1low = DSP4_READ_WORD(0x0c); + project_focalx = DSP4_READ_WORD(0x0e); + project_centerx = DSP4_READ_WORD(0x10); + project_ptr = DSP4_READ_WORD(0x12); + project_pitchylow = DSP4_READ_WORD(0x16); + project_pitchy = DSP4_READ_WORD(0x18); + project_pitchxlow = DSP4_READ_WORD(0x1a); + project_pitchx = DSP4_READ_WORD(0x1c); + far_plane = DSP4_READ_WORD(0x1e); + project_y1low = DSP4_READ_WORD(0x22); + + /* pre-compute */ + view_plane = PLANE_START; + + /* find starting projection points */ + project_x1 = project_focalx; + project_y -= viewport_bottom; + project_x = project_centerx + project_x1; + + /* multi-op storage */ + multi_index1 = 0; + multi_index2 = 0; + + /* + * command check + */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* check for termination */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 8; + DSP4_WAIT(2); + + /* process one iteration of projection */ + + /* inspect inputs */ + +resume2: + plane = DSP4_READ_WORD(0); + px_dx = 0; + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* one-time init */ + if (far_plane) + { + /* setup final parameters */ + project_focalx += plane; + project_x1 = project_focalx; + project_y1 = project_focaly; + plane = far_plane; + far_plane = 0; + } + + /* use proportional triangles to project new coords */ + project_x2 = project_focalx * plane / view_plane; + project_y2 = project_focaly * plane / view_plane; + + /* quadratic regression (rough) */ + if (project_focaly >= -0x0f) + py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); + else + py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); + + /* approximate # of raster lines */ + segments = ABS(project_y2 - project_y1); + + /* prevent overdraw */ + if(project_y2 >= raster) + segments = 0; + else + raster = project_y2; + + /* don't draw outside the window */ + if(project_y2 < viewport_top) + segments = 0; + + /* project new positions */ + if (segments > 0) + px_dx = ((project_x2 - project_x1) << 8) / segments; /* interpolate between projected points */ + + /* prepare output */ + DSP4.out_count = 8 + 2 + 6 * segments; + + /* pre-block data */ + DSP4_WRITE_WORD(0, project_focalx); + DSP4_WRITE_WORD(2, project_x2); + DSP4_WRITE_WORD(4, project_focaly); + DSP4_WRITE_WORD(6, project_y2); + DSP4_WRITE_WORD(8, segments); + + index = 10; + + for (lcv = 0; lcv < segments; lcv++) /* iterate through each point */ + { + /* step through the projected line */ + y_out = project_y + ((py_dy * lcv) >> 8); + x_out = project_x + ((px_dx * lcv) >> 8); + + /* data */ + DSP4_WRITE_WORD(index + 0, project_ptr); + DSP4_WRITE_WORD(index + 2, y_out); + DSP4_WRITE_WORD(index + 4, x_out); + index += 6; + + /* post-update */ + project_ptr -= 4; + } + + /* post-update */ + project_y += ((py_dy * lcv) >> 8); + project_x += ((px_dx * lcv) >> 8); + + if (segments > 0) /* new positions */ + { + project_x1 = project_x2; + project_y1 = project_y2; + + /* multi-op storage */ + multi_focaly[multi_index2++] = project_focaly; + multi_farplane[1] = plane; + multi_raster[1] = project_y1 - 1; + } + + /* update projection points */ + project_pitchy += (int8_t)DSP4.parameters[3]; + project_pitchx += (int8_t)DSP4.parameters[5]; + + project_focaly += project_pitchy; + project_focalx += project_pitchx; + } while (1); + + /* terminate op */ + DSP4.waiting4command = true; + DSP4.out_count = 0; +} + +void DSP4_Op07(void) +{ + uint16_t command; + int16_t plane; + int16_t index, lcv; + int16_t y_out, x_out; + int16_t py_dy, px_dx; + + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* sort inputs */ + + project_focaly = DSP4_READ_WORD(0x02); + raster = DSP4_READ_WORD(0x04); + viewport_top = DSP4_READ_WORD(0x06); + project_y = DSP4_READ_WORD(0x08); + viewport_bottom = DSP4_READ_WORD(0x0a); + project_x1low = DSP4_READ_WORD(0x0c); + project_x1 = DSP4_READ_WORD(0x0e); + project_centerx = DSP4_READ_WORD(0x10); + project_ptr = DSP4_READ_WORD(0x12); + + /* pre-compute */ + view_plane = PLANE_START; + + /* find projection targets */ + project_y1 = project_focaly; + project_y -= viewport_bottom; + project_x = project_centerx + project_x1; + + /* multi-op storage */ + multi_index2 = 0; + + /* command check */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* check for opcode termination */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 12; + DSP4_WAIT(2); + + /* process one loop of projection */ + +resume2: + px_dx = 0; + + /* inspect inputs */ + plane = DSP4_READ_WORD(0); + project_y2 = DSP4_READ_WORD(2); + project_x2 = DSP4_READ_WORD(6); + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* multi-op storage */ + project_focaly = multi_focaly[multi_index2]; + + /* quadratic regression (rough) */ + if (project_focaly >= -0x0f) + py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); + else + py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); + + /* approximate # of raster lines */ + segments = ABS(project_y2 - project_y1); + + /* prevent overdraw */ + if(project_y2 >= raster) + segments = 0; + else + raster = project_y2; + + /* don't draw outside the window */ + if(project_y2 < viewport_top) + segments = 0; + + /* project new positions */ + if (segments > 0) + { + /* interpolate between projected points */ + px_dx = ((project_x2 - project_x1) << 8) / segments; + } + + /* prepare pre-output */ + DSP4.out_count = 4 + 2 + 6 * segments; + + DSP4_WRITE_WORD(0, project_x2); + DSP4_WRITE_WORD(2, project_y2); + DSP4_WRITE_WORD(4, segments); + + index = 6; + for (lcv = 0; lcv < segments; lcv++) + { + /* pre-compute */ + y_out = project_y + ((py_dy * lcv) >> 8); + x_out = project_x + ((px_dx * lcv) >> 8); + + /* data */ + DSP4_WRITE_WORD(index + 0, project_ptr); + DSP4_WRITE_WORD(index + 2, y_out); + DSP4_WRITE_WORD(index + 4, x_out); + index += 6; + + /* post-update */ + project_ptr -= 4; + } + + /* update internal variables */ + project_y += ((py_dy * lcv) >> 8); + project_x += ((px_dx * lcv) >> 8); + + /* new positions */ + if (segments > 0) + { + project_x1 = project_x2; + project_y1 = project_y2; + + /* multi-op storage */ + multi_index2++; + } + } while (1); + + DSP4.waiting4command = true; + DSP4.out_count = 0; +} + +void DSP4_Op08(void) +{ + uint16_t command; + /* used in envelope shaping */ + int16_t x1_final; + int16_t x2_final; + int16_t plane, x_left, y_left, x_right, y_right; + int16_t envelope1, envelope2; + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* process initial inputs */ + + /* clip values */ + path_clipRight[0] = DSP4_READ_WORD(0x00); + path_clipRight[1] = DSP4_READ_WORD(0x02); + path_clipRight[2] = DSP4_READ_WORD(0x04); + path_clipRight[3] = DSP4_READ_WORD(0x06); + + path_clipLeft[0] = DSP4_READ_WORD(0x08); + path_clipLeft[1] = DSP4_READ_WORD(0x0a); + path_clipLeft[2] = DSP4_READ_WORD(0x0c); + path_clipLeft[3] = DSP4_READ_WORD(0x0e); + + /* path positions */ + path_pos[0] = DSP4_READ_WORD(0x20); + path_pos[1] = DSP4_READ_WORD(0x22); + path_pos[2] = DSP4_READ_WORD(0x24); + path_pos[3] = DSP4_READ_WORD(0x26); + + /* data locations */ + path_ptr[0] = DSP4_READ_WORD(0x28); + path_ptr[1] = DSP4_READ_WORD(0x2a); + path_ptr[2] = DSP4_READ_WORD(0x2c); + path_ptr[3] = DSP4_READ_WORD(0x2e); + + /* project_y1 lines */ + path_raster[0] = DSP4_READ_WORD(0x30); + path_raster[1] = DSP4_READ_WORD(0x32); + path_raster[2] = DSP4_READ_WORD(0x34); + path_raster[3] = DSP4_READ_WORD(0x36); + + /* viewport_top */ + path_top[0] = DSP4_READ_WORD(0x38); + path_top[1] = DSP4_READ_WORD(0x3a); + path_top[2] = DSP4_READ_WORD(0x3c); + path_top[3] = DSP4_READ_WORD(0x3e); + + /* unknown (constants) */ + + view_plane = PLANE_START; + + /* command check */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* terminate op */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 18; + DSP4_WAIT(2); + +resume2: + /* projection begins */ + + /* look at guidelines */ + plane = DSP4_READ_WORD(0x00); + x_left = DSP4_READ_WORD(0x02); + y_left = DSP4_READ_WORD(0x04); + x_right = DSP4_READ_WORD(0x06); + y_right = DSP4_READ_WORD(0x08); + + /* envelope guidelines (one frame only) */ + envelope1 = DSP4_READ_WORD(0x0a); + envelope2 = DSP4_READ_WORD(0x0c); + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* first init */ + if (plane == 0x7fff) + { + int32_t pos1, pos2; + + /* initialize projection */ + path_x[0] = x_left; + path_x[1] = x_right; + + path_y[0] = y_left; + path_y[1] = y_right; + + /* update coordinates */ + path_pos[0] -= x_left; + path_pos[1] -= x_left; + path_pos[2] -= x_right; + path_pos[3] -= x_right; + + pos1 = path_pos[0] + envelope1; + pos2 = path_pos[1] + envelope2; + + /* clip offscreen data */ + if(pos1 < path_clipLeft[0]) + pos1 = path_clipLeft[0]; + if(pos1 > path_clipRight[0]) + pos1 = path_clipRight[0]; + if(pos2 < path_clipLeft[1]) + pos2 = path_clipLeft[1]; + if(pos2 > path_clipRight[1]) + pos2 = path_clipRight[1]; + + path_plane[0] = plane; + path_plane[1] = plane; + + /* initial output */ + DSP4.out_count = 2; + DSP4.output[0] = pos1 & 0xFF; + DSP4.output[1] = pos2 & 0xFF; + } + /* proceed with projection */ + else + { + int16_t index = 0, lcv; + int16_t left_inc = 0, right_inc = 0; + int16_t dx1 = 0, dx2 = 0, dx3, dx4; + + /* # segments to traverse */ + segments = ABS(y_left - path_y[0]); + + /* prevent overdraw */ + if(y_left >= path_raster[0]) + segments = 0; + else + path_raster[0] = y_left; + + /* don't draw outside the window */ + if(path_raster[0] < path_top[0]) + segments = 0; + + /* proceed if visibility rules apply */ + if (segments > 0) + { + /* use previous data */ + dx1 = (envelope1 * path_plane[0] / view_plane); + dx2 = (envelope2 * path_plane[0] / view_plane); + + /* use temporary envelope pitch (this frame only) */ + dx3 = (envelope1 * plane / view_plane); + dx4 = (envelope2 * plane / view_plane); + + /* project new shapes (left side) */ + x1_final = x_left + dx1; + x2_final = path_x[0] + dx3; + + /* interpolate between projected points with shaping */ + left_inc = ((x2_final - x1_final) << 8) / segments; + + /* project new shapes (right side) */ + x1_final = x_left + dx2; + x2_final = path_x[0] + dx4; + + /* interpolate between projected points with shaping */ + right_inc = ((x2_final - x1_final) << 8) / segments; + path_plane[0] = plane; + } + + /* zone 1 */ + DSP4.out_count = (2 + 4 * segments); + DSP4_WRITE_WORD(index, segments); + index += 2; + + for (lcv = 1; lcv <= segments; lcv++) + { + int16_t pos1, pos2; + + /* pre-compute */ + pos1 = path_pos[0] + ((left_inc * lcv) >> 8) + dx1; + pos2 = path_pos[1] + ((right_inc * lcv) >> 8) + dx2; + + /* clip offscreen data */ + if(pos1 < path_clipLeft[0]) + pos1 = path_clipLeft[0]; + if(pos1 > path_clipRight[0]) + pos1 = path_clipRight[0]; + if(pos2 < path_clipLeft[1]) + pos2 = path_clipLeft[1]; + if(pos2 > path_clipRight[1]) + pos2 = path_clipRight[1]; + + /* data */ + DSP4_WRITE_WORD(index, path_ptr[0]); + index += 2; + DSP4.output[index++] = pos1 & 0xFF; + DSP4.output[index++] = pos2 & 0xFF; + + /* post-update */ + path_ptr[0] -= 4; + path_ptr[1] -= 4; + } + lcv--; + + if (segments > 0) + { + /* project points w/out the envelopes */ + int16_t inc = ((path_x[0] - x_left) << 8) / segments; + + /* post-store */ + path_pos[0] += ((inc * lcv) >> 8); + path_pos[1] += ((inc * lcv) >> 8); + + path_x[0] = x_left; + path_y[0] = y_left; + } + + /* zone 2 */ + segments = ABS(y_right - path_y[1]); + + /* prevent overdraw */ + if(y_right >= path_raster[2]) + segments = 0; + else path_raster[2] = y_right; + + /* don't draw outside the window */ + if(path_raster[2] < path_top[2]) + segments = 0; + + /* proceed if visibility rules apply */ + if (segments > 0) + { + /* use previous data */ + dx1 = (envelope1 * path_plane[1] / view_plane); + dx2 = (envelope2 * path_plane[1] / view_plane); + + /* use temporary envelope pitch (this frame only) */ + dx3 = (envelope1 * plane / view_plane); + dx4 = (envelope2 * plane / view_plane); + + /* project new shapes (left side) */ + x1_final = x_left + dx1; + x2_final = path_x[1] + dx3; + + /* interpolate between projected points with shaping */ + left_inc = ((x2_final - x1_final) << 8) / segments; + + /* project new shapes (right side) */ + x1_final = x_left + dx2; + x2_final = path_x[1] + dx4; + + /* interpolate between projected points with shaping */ + right_inc = ((x2_final - x1_final) << 8) / segments; + + path_plane[1] = plane; + } + + /* write out results */ + DSP4.out_count += (2 + 4 * segments); + DSP4_WRITE_WORD(index, segments); + index += 2; + + for (lcv = 1; lcv <= segments; lcv++) + { + int16_t pos1, pos2; + + /* pre-compute */ + pos1 = path_pos[2] + ((left_inc * lcv) >> 8) + dx1; + pos2 = path_pos[3] + ((right_inc * lcv) >> 8) + dx2; + + /* clip offscreen data */ + if(pos1 < path_clipLeft[2]) + pos1 = path_clipLeft[2]; + if(pos1 > path_clipRight[2]) + pos1 = path_clipRight[2]; + if(pos2 < path_clipLeft[3]) + pos2 = path_clipLeft[3]; + if(pos2 > path_clipRight[3]) + pos2 = path_clipRight[3]; + + /* data */ + DSP4_WRITE_WORD(index, path_ptr[2]); + index += 2; + DSP4.output[index++] = pos1 & 0xFF; + DSP4.output[index++] = pos2 & 0xFF; + + /* post-update */ + path_ptr[2] -= 4; + path_ptr[3] -= 4; + } + lcv--; + + if (segments > 0) + { + /* project points w/out the envelopes */ + int16_t inc = ((path_x[1] - x_right) << 8) / segments; + + /* post-store */ + path_pos[2] += ((inc * lcv) >> 8); + path_pos[3] += ((inc * lcv) >> 8); + + path_x[1] = x_right; + path_y[1] = y_right; + } + } + } while (1); + + DSP4.waiting4command = true; + DSP4.out_count = 2; + DSP4_WRITE_WORD(0, 0); +} + +void DSP4_Op0D(void) +{ + uint16_t command; + /* inspect inputs */ + int16_t plane; + int16_t index, lcv; + int16_t py_dy, px_dx; + int16_t y_out, x_out; + + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* process initial inputs */ + + /* sort inputs */ + project_focaly = DSP4_READ_WORD(0x02); + raster = DSP4_READ_WORD(0x04); + viewport_top = DSP4_READ_WORD(0x06); + project_y = DSP4_READ_WORD(0x08); + viewport_bottom = DSP4_READ_WORD(0x0a); + project_x1low = DSP4_READ_WORD(0x0c); + project_x1 = DSP4_READ_WORD(0x0e); + project_focalx = DSP4_READ_WORD(0x0e); + project_centerx = DSP4_READ_WORD(0x10); + project_ptr = DSP4_READ_WORD(0x12); + project_pitchylow = DSP4_READ_WORD(0x16); + project_pitchy = DSP4_READ_WORD(0x18); + project_pitchxlow = DSP4_READ_WORD(0x1a); + project_pitchx = DSP4_READ_WORD(0x1c); + far_plane = DSP4_READ_WORD(0x1e); + + /* multi-op storage */ + multi_index1++; + multi_index1 %= 4; + + /* remap 0D->09 window data ahead of time */ + /* index starts at 1-3,0 */ + /* Op0D: BL,TL,BR,TR */ + /* Op09: TL,TR,BL,BR (1,2,3,0) */ + switch (multi_index1) + { + case 1: + multi_index2 = 3; + break; + case 2: + multi_index2 = 1; + break; + case 3: + multi_index2 = 0; + break; + case 0: + multi_index2 = 2; + break; + } + + /* pre-compute */ + view_plane = PLANE_START; + + /* figure out projection data */ + project_y -= viewport_bottom; + project_x = project_centerx + project_x1; + + /* command check */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* terminate op */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 8; + DSP4_WAIT(2); + + /* project section of the track */ + +resume2: + plane = DSP4_READ_WORD(0); + px_dx = 0; + + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* one-time init */ + if (far_plane) + { + /* setup final data */ + project_x1 = project_focalx; + project_y1 = project_focaly; + plane = far_plane; + far_plane = 0; + } + + /* use proportional triangles to project new coords */ + project_x2 = project_focalx * plane / view_plane; + project_y2 = project_focaly * plane / view_plane; + + /* quadratic regression (rough) */ + if (project_focaly >= -0x0f) + py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); + else + py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); + + /* approximate # of raster lines */ + segments = ABS(project_y2 - project_y1); + + /* prevent overdraw */ + if(project_y2 >= raster) + segments = 0; + else + raster = project_y2; + + /* don't draw outside the window */ + if(project_y2 < viewport_top) + segments = 0; + + /* project new positions */ + if (segments > 0) + { + /* interpolate between projected points */ + px_dx = ((project_x2 - project_x1) << 8) / segments; + } + + /* prepare output */ + DSP4.out_count = 8 + 2 + 6 * segments; + DSP4_WRITE_WORD(0, project_focalx); + DSP4_WRITE_WORD(2, project_x2); + DSP4_WRITE_WORD(4, project_focaly); + DSP4_WRITE_WORD(6, project_y2); + DSP4_WRITE_WORD(8, segments); + index = 10; + + for (lcv = 0; lcv < segments; lcv++) /* iterate through each point */ + { + /* step through the projected line */ + y_out = project_y + ((py_dy * lcv) >> 8); + x_out = project_x + ((px_dx * lcv) >> 8); + + /* data */ + DSP4_WRITE_WORD(index + 0, project_ptr); + DSP4_WRITE_WORD(index + 2, y_out); + DSP4_WRITE_WORD(index + 4, x_out); + index += 6; + + /* post-update */ + project_ptr -= 4; + } + + /* post-update */ + project_y += ((py_dy * lcv) >> 8); + project_x += ((px_dx * lcv) >> 8); + + if (segments > 0) + { + project_x1 = project_x2; + project_y1 = project_y2; + + /* multi-op storage */ + multi_farplane[multi_index2] = plane; + multi_raster[multi_index2] = project_y1; + } + + /* update focal projection points */ + project_pitchy += (int8_t)DSP4.parameters[3]; + project_pitchx += (int8_t)DSP4.parameters[5]; + + project_focaly += project_pitchy; + project_focalx += project_pitchx; + } while (1); + + DSP4.waiting4command = true; + DSP4.out_count = 0; +} + +void DSP4_Op09(void) +{ + uint16_t command; + bool clip; + int16_t sp_x, sp_y, sp_oam, sp_msb; + int16_t sp_dx, sp_dy; + + DSP4.waiting4command = false; + + /* op flow control */ + switch (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; + case 7: + goto resume7; + break; + } + + /* process initial inputs */ + + /* grab screen information */ + view_plane = PLANE_START; + center_x = DSP4_READ_WORD(0x00); + center_y = DSP4_READ_WORD(0x02); + viewport_left = DSP4_READ_WORD(0x06); + viewport_right = DSP4_READ_WORD(0x08); + viewport_top = DSP4_READ_WORD(0x0a); + viewport_bottom = DSP4_READ_WORD(0x0c); + + /* expand viewport dimensions */ + viewport_left -= 8; + + /* cycle through viewport window data */ + multi_index1++; + multi_index1 %= 4; + + /* convert track line to the window region */ + project_y2 = center_y + multi_raster[multi_index1] * (viewport_bottom - center_y) / (0x33 - 0); + if (!op09_mode) + project_y2 -= 2; + + goto no_sprite; + + do + { + /* check for new sprites */ + do + { + uint16_t second; + + DSP4.in_count = 4; + DSP4.in_index = 2; + DSP4_WAIT(1); + +resume1: + /* try to classify sprite */ + second = DSP4_READ_WORD(2); + + /* op termination */ + if(second == 0x8000) + goto terminate; + + second >>= 8; + sprite_type = 0; + + /* vehicle sprite */ + if (second == 0x90) + { + sprite_type = 1; + break; + } + /* terrain sprite */ + else if (second != 0) + { + sprite_type = 2; + break; + } + +no_sprite: + /* no sprite. try again */ + DSP4.in_count = 2; + DSP4_WAIT(2); + +resume2:; + } while (1); + + /* process projection information */ + +sprite_found: + /* vehicle sprite */ + if (sprite_type == 1) + { + int16_t plane; + int16_t car_left, car_right; + int16_t focal_back; + int32_t height; + + /* we already have 4 bytes we want */ + DSP4.in_count = 6 + 12; + DSP4.in_index = 4; + DSP4_WAIT(3); + +resume3: + /* filter inputs */ + project_y1 = DSP4_READ_WORD(0x00); + focal_back = DSP4_READ_WORD(0x06); + car_left = DSP4_READ_WORD(0x0c); + plane = DSP4_READ_WORD(0x0e); + car_right = DSP4_READ_WORD(0x10); + + /* calculate car's x-center */ + project_focalx = car_right - car_left; + + /* determine how far into the screen to project */ + project_focaly = focal_back; + project_x = project_focalx * plane / view_plane; + segments = 0x33 - project_focaly * plane / view_plane; + far_plane = plane; + + /* prepare memory */ + sprite_x = center_x + project_x; + sprite_y = viewport_bottom - segments; + far_plane = plane; + + /* make the car's x-center available */ + DSP4.out_count = 2; + DSP4_WRITE_WORD(0, project_focalx); + + /* grab a few remaining vehicle values */ + DSP4.in_count = 4; + + DSP4_WAIT(4); + +resume4: /* store final values */ + height = DSP4_READ_WORD(0); + sprite_offset = DSP4_READ_WORD(2); + + /* vertical lift factor */ + sprite_y += height; + } + else if (sprite_type == 2) /* terrain sprite */ + { + int16_t plane; + + /* we already have 4 bytes we want */ + DSP4.in_count = 6 + 6 + 2; + DSP4.in_index = 4; + DSP4_WAIT(5); + +resume5: + /* sort loop inputs */ + project_y1 = DSP4_READ_WORD(0x00); + plane = DSP4_READ_WORD(0x02); + project_centerx = DSP4_READ_WORD(0x04); + project_focalx = DSP4_READ_WORD(0x08); + project_focaly = DSP4_READ_WORD(0x0a); + sprite_offset = DSP4_READ_WORD(0x0c); + + /* determine distances into virtual world */ + segments = 0x33 - project_y1; + project_x = project_focalx * plane / view_plane; + project_y = project_focaly * plane / view_plane; + + /* prepare memory */ + sprite_x = center_x + project_x - project_centerx; + sprite_y = viewport_bottom - segments + project_y; + far_plane = plane; + } + + /* default sprite size: 16x16 */ + sprite_size = true; + + /* convert tile data to OAM */ + + do + { + DSP4.in_count = 2; + DSP4_WAIT(6); + +resume6: + command = DSP4_READ_WORD(0); + + /* opcode termination */ + if(command == 0x8000) + goto terminate; + + /* toggle sprite size */ + if (command == 0x0000) + { + sprite_size = !sprite_size; + continue; + } + + /* new sprite information */ + command >>= 8; + if (command != 0x20 && command != 0x40 && command != 0x60 && command != 0xa0 && command != 0xc0 && command != 0xe0) + break; + + DSP4.in_count = 6; + DSP4.in_index = 2; + DSP4_WAIT(7); + + /* process tile data */ + +resume7: + /* sprite deltas */ + sp_dy = DSP4_READ_WORD(2); + sp_dx = DSP4_READ_WORD(4); + + /* update coordinates */ + sp_y = sprite_y + sp_dy; + sp_x = sprite_x + sp_dx; + + /* reject points outside the clipping window */ + clip = false; + if(sp_x < viewport_left || sp_x > viewport_right) + clip = true; + if(sp_y < viewport_top || sp_y > viewport_bottom) + clip = true; + + /* track depth sorting */ + if(far_plane <= multi_farplane[multi_index1] && sp_y >= project_y2) + clip = true; + + /* don't draw offscreen coordinates */ + DSP4.out_count = 0; + if (!clip) + { + int16_t out_index = 0; + int16_t offset = DSP4_READ_WORD(0); + + /* update sprite nametable/attribute information */ + sp_oam = sprite_offset + offset; + sp_msb = (sp_x < 0 || sp_x > 255); + + /* emit transparency information */ + if((sprite_offset & 0x08) && ((sprite_type == 1 && sp_y >= 0xcc) || (sprite_type == 2 && sp_y >= 0xbb))) + { + DSP4.out_count = 6; + + /* one block of OAM data */ + DSP4_WRITE_WORD(0, 1); + + /* OAM: x,y,tile,no attr */ + DSP4.output[2] = sp_x & 0xFF; + DSP4.output[3] = (sp_y + 6) & 0xFF; + DSP4_WRITE_WORD(4, 0xEE); + out_index = 6; + + /* OAM: size,msb data */ + DSP4_Op06(sprite_size, (int8_t) sp_msb); + } + + /* normal data */ + DSP4.out_count += 8; + + /* one block of OAM data */ + DSP4_WRITE_WORD(out_index + 0, 1); + + /* OAM: x,y,tile,attr */ + DSP4.output[out_index + 2] = sp_x & 0xFF; + DSP4.output[out_index + 3] = sp_y & 0xFF; + DSP4_WRITE_WORD(out_index + 4, sp_oam); + + /* no following OAM data */ + DSP4_WRITE_WORD(out_index + 6, 0); + + /* OAM: size,msb data */ + DSP4_Op06(sprite_size, (int8_t) sp_msb); + } + + /* no sprite information */ + if (DSP4.out_count == 0) + { + DSP4.out_count = 2; + DSP4_WRITE_WORD(0, 0); + } + } while (1); + + /* special cases: plane == 0x0000 */ + + /* special vehicle case */ + if (command == 0x90) + { + sprite_type = 1; + + /* shift bytes */ + DSP4.parameters[2] = DSP4.parameters[0]; + DSP4.parameters[3] = DSP4.parameters[1]; + DSP4.parameters[0] = 0; + DSP4.parameters[1] = 0; + + goto sprite_found; + } + else if (command != 0x00 && command != 0xff) /* special terrain case */ + { + sprite_type = 2; + + /* shift bytes */ + DSP4.parameters[2] = DSP4.parameters[0]; + DSP4.parameters[3] = DSP4.parameters[1]; + DSP4.parameters[0] = 0; + DSP4.parameters[1] = 0; + + goto sprite_found; + } + } while (1); + +terminate: + DSP4.waiting4command = true; + DSP4.out_count = 0; +} |