gpu.c (12798B)
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include "gpu.h" 5 #include "types.h" 6 #include "sr.h" 7 #include "log.h" 8 9 GPU* 10 GPU_new(void) 11 { 12 GPU* gpu; 13 14 gpu = (GPU*)malloc(sizeof(GPU)); 15 memset(gpu, 0, sizeof(GPU)); 16 gpu->display_disabled = 1; 17 gpu->ren = REN_new(); 18 19 return gpu; 20 } 21 22 u32 23 GPU_read(GPU* gpu) 24 { 25 (void)gpu; 26 return 0; 27 } 28 29 u32 30 GPU_status(GPU* gpu) 31 { 32 u32 r; 33 u32 dma_req; 34 35 dma_req = 0; 36 r = 0; 37 38 r |= ((u32)gpu->page_base_x) << 0; 39 r |= ((u32)gpu->page_base_y) << 4; 40 r |= ((u32)gpu->semi_transparency) << 5; 41 r |= ((u32)gpu->texture_depth) << 7; 42 r |= ((u32)gpu->dithering) << 9; 43 r |= ((u32)gpu->draw_to_display) << 10; 44 r |= ((u32)gpu->force_set_mask_bit) << 11; 45 r |= ((u32)gpu->preserve_masked_pixels) << 12; 46 r |= ((u32)gpu->field) << 13; 47 /* Bit 14 not supported */ 48 r |= ((u32)gpu->texture_disable) << 15; 49 r |= HOR_RES_into_status(gpu->hres); 50 /* If we don't emulate bit 31 correctly setting vres to 1 51 locks the BIOS. 4.17 on the guide. 52 */ 53 /*r |= ((u32)gpu->vres) << 19;*/ 54 r |= ((u32)gpu->vmode) << 20; 55 r |= ((u32)gpu->display_depth) << 21; 56 r |= ((u32)gpu->interlaced) << 22; 57 r |= ((u32)gpu->display_disabled) << 23; 58 r |= ((u32)gpu->interrupt) << 24; 59 60 /* Always GPU is ready */ 61 r |= 1 << 26; 62 r |= 1 << 27; 63 r |= 1 << 28; 64 65 r |= ((u32) gpu->dma_direction) << 29; 66 67 /* Ignore odd lines for now */ 68 r |= 0 << 31; 69 70 switch(gpu->dma_direction) 71 { 72 case DMA_DIR_OFF: dma_req = 0; break; 73 case DMA_DIR_FIFO: dma_req = 1; break; 74 case DMA_DIR_CPUTOGP0: dma_req = (r >> 28) & 1; break; 75 case DMA_DIR_VRAMTOCPU: dma_req = (r >> 27) & 1; break; 76 default: log_fatal("UNREACHABLE"); exit(1); 77 } 78 79 r |= dma_req << 25; 80 81 return r; 82 } 83 84 void 85 GPU_gp1(GPU* gpu, u32 val) 86 { 87 88 u32 opcode; 89 90 opcode = (val >> 24) & 0xff; 91 92 switch (opcode) 93 { 94 case 0x00: GPU_gp1_reset(gpu, val); break; 95 case 0x01: GPU_gp1_reset_command_buffer(gpu, val); break; 96 case 0x02: GPU_gp1_acknowledge_irq(gpu, val); break; 97 case 0x03: GPU_gp1_display_enable(gpu, val); break; 98 case 0x04: GPU_gp1_dma_direction(gpu, val); break; 99 case 0x05: GPU_gp1_display_vram_start(gpu, val); break; 100 case 0x06: GPU_gp1_display_horizontal_range(gpu, val); break; 101 case 0x07: GPU_gp1_display_vertical_range(gpu, val); break; 102 case 0x08: GPU_gp1_display_mode(gpu, val); break; 103 default: log_fatal("OP: %08X: Unhandled GP1 command %08X", opcode, val); exit(1); 104 } 105 106 } 107 108 void 109 GPU_gp1_reset(GPU* gpu, u32 val) 110 { 111 (void)val; 112 REN* tmp = gpu->ren; 113 memset(gpu, 0, sizeof(GPU)); 114 /* Fill out the rest of the fields with no$cash spec reset values*/ 115 gpu->display_disabled = 1; 116 gpu->interlaced = 1; 117 gpu->display_horiz_start = 0x200; 118 gpu->display_horiz_end = 0xc00; 119 gpu->display_line_start = 0x10; 120 gpu->display_line_end = 0x100; 121 gpu->ren = tmp; 122 } 123 124 void 125 GPU_gp1_display_enable(GPU* gpu, u32 val) 126 { 127 gpu->display_disabled = (val & 1) != 0; 128 } 129 130 void 131 GPU_gp1_acknowledge_irq(GPU* gpu, u32 val) 132 { 133 (void)val; 134 gpu->interrupt = 0; 135 } 136 137 void 138 GPU_gp1_reset_command_buffer(GPU* gpu, u32 val) 139 { 140 (void)val; 141 GPU_CMD_BUFFER_clear(&gpu->gp0_command); 142 gpu->gp0_words_remaining = 0; 143 gpu->gp0_mode = GP0_MODE_COMMAND; 144 145 /* XXX Should also clear the command FIFO when we implement it*/ 146 } 147 148 void 149 GPU_gp1_display_horizontal_range(GPU* gpu, u32 val) 150 { 151 gpu->display_horiz_start = (u16)(val & 0xfff); 152 gpu->display_horiz_end = (u16)((val >> 12) & 0xfff); 153 } 154 155 void 156 GPU_gp1_display_vertical_range(GPU* gpu, u32 val) 157 { 158 gpu->display_line_start = (u16)(val & 0x3ff); 159 gpu->display_line_end = (u16)((val >> 10) & 0x3ff); 160 } 161 162 void 163 GPU_gp1_display_vram_start(GPU* gpu, u32 val) 164 { 165 gpu->display_vram_x_start = (u16)(val & 0x3fe); 166 gpu->display_vram_y_start = (u16)((val >> 10) & 0x1ff); 167 } 168 169 void 170 GPU_gp1_dma_direction(GPU* gpu, u32 val) 171 { 172 switch (val & 3) { 173 case 0: gpu->dma_direction = DMA_DIR_OFF; break; 174 case 1: gpu->dma_direction = DMA_DIR_FIFO; break; 175 case 2: gpu->dma_direction = DMA_DIR_CPUTOGP0; break; 176 case 3: gpu->dma_direction = DMA_DIR_VRAMTOCPU; break; 177 default: log_fatal("UNREACHABLE"); exit(EXIT_FAILURE); 178 } 179 } 180 181 void 182 GPU_gp1_display_mode(GPU* gpu, u32 val) 183 { 184 u8 hr1, hr2; 185 186 hr1 = (u8)(val & 3); 187 hr2 = (u8)((val >> 6) & 1); 188 189 gpu->hres = HOR_RES_from_fields(hr1, hr2); 190 gpu->vres = (val & 0x4) != 0; 191 gpu->vmode = (val & 0x8) != 0 ? VMODE_NTSC : VMODE_PAL; 192 gpu->display_depth = (val & 0x10) != 0 ? DISP_DEPTH_D24BITS : DISP_DEPTH_D15BITS; 193 gpu->interlaced = (val & 0x20) != 0; 194 195 if (val & 0x80) 196 log_fatal("Unsupported display mode %08X", val), exit(EXIT_FAILURE); 197 } 198 199 void 200 GPU_gp0(GPU* gpu, u32 val) 201 { 202 if (gpu->gp0_words_remaining == 0) { 203 u32 opcode, len; 204 void (*method)(GPU*); 205 206 opcode = (val >> 24) & 0xff; 207 208 switch (opcode) { 209 case 0x00: len = 1; method = GPU_gp0_nop; break; 210 case 0x01: len = 1; method = GPU_gp0_clear_cache; break; 211 case 0xa0: len = 3; method = GPU_gp0_image_load; break; 212 case 0xe1: len = 1; method = GPU_gp0_draw_mode; break; 213 case 0xe2: len = 1; method = GPU_gp0_texture_window; break; 214 case 0xe3: len = 1; method = GPU_gp0_drawing_area_top_left; break; 215 case 0xe4: len = 1; method = GPU_gp0_drawing_area_bottom_right; break; 216 case 0xe5: len = 1; method = GPU_gp0_drawing_offset; break; 217 case 0xe6: len = 1; method = GPU_gp0_mask_bit_setting; break; 218 case 0x28: len = 5; method = GPU_gp0_quad_mono_opaque; break; 219 case 0x2c: len = 9; method = GPU_gp0_quad_texture_blend_opaque; break; 220 case 0x30: len = 6; method = GPU_gp0_triangle_shaded_opaque; break; 221 case 0x38: len = 8; method = GPU_gp0_quad_shaded_opaque; break; 222 case 0xc0: len = 3; method = GPU_gp0_image_store; break; 223 default: log_fatal("OP: %08X: Unhandled GP0 command %08X", opcode, val); exit(1); 224 } 225 226 gpu->gp0_words_remaining = len; 227 gpu->gp0_command_method = method; 228 GPU_CMD_BUFFER_clear(&gpu->gp0_command); 229 } 230 231 gpu->gp0_words_remaining -= 1; 232 233 switch (gpu->gp0_mode) { 234 case GP0_MODE_COMMAND: 235 GPU_CMD_BUFFER_push_word(&gpu->gp0_command, val); 236 if (gpu->gp0_words_remaining == 0) 237 gpu->gp0_command_method(gpu); 238 break; 239 case GP0_MODE_IMAGE_LOAD: 240 if (gpu->gp0_words_remaining == 0) 241 gpu->gp0_mode = GP0_MODE_COMMAND; 242 break; 243 } 244 } 245 246 void GPU_gp0_nop(GPU* gpu) {(void)gpu;} 247 248 void GPU_gp0_clear_cache(GPU* gpu) {(void)gpu;} 249 250 void 251 GPU_gp0_image_load(GPU* gpu) 252 { 253 u32 res, width, height, imgsize; 254 255 res = gpu->gp0_command.buffer[2]; 256 width = res & 0xffff; 257 height = res >> 16; 258 imgsize = width * height; 259 imgsize = (imgsize + 1) & ~1; 260 gpu->gp0_words_remaining = imgsize / 2; 261 gpu->gp0_mode = GP0_MODE_IMAGE_LOAD; 262 } 263 264 void 265 GPU_gp0_draw_mode(GPU* gpu) 266 { 267 u32 val; 268 val = gpu->gp0_command.buffer[0]; 269 270 gpu->page_base_x = (u8)(val & 0xf); 271 gpu->page_base_y = (u8)((val >> 4) & 1); 272 gpu->semi_transparency = (u8)((val >> 5) & 3); 273 274 switch ((val >> 7) & 3) 275 { 276 case 0: gpu->texture_depth = TD_T4BIT; break; 277 case 1: gpu->texture_depth = TD_T8BIT; break; 278 case 2: gpu->texture_depth = TD_T15BIT; break; 279 default: log_fatal("Unhandled texture depth %d", (val >> 7) & 3); exit(1); 280 } 281 282 gpu->dithering = ((val >> 9) & 1); 283 gpu->draw_to_display = ((val >> 10) & 1); 284 gpu->texture_disable = ((val >> 11) & 1); 285 gpu->rectangle_texture_x_flip = ((val >> 12) & 1); 286 gpu->rectangle_texture_y_flip = ((val >> 13) & 1); 287 } 288 289 void 290 GPU_gp0_drawing_area_top_left(GPU* gpu) 291 { 292 u32 val; 293 val = gpu->gp0_command.buffer[0]; 294 gpu->drawing_area_top = (u16)((val >> 10) & 0x3ff); 295 gpu->drawing_area_left = (u16)(val & 0x3ff); 296 } 297 298 void 299 GPU_gp0_drawing_area_bottom_right(GPU* gpu) 300 { 301 u32 val; 302 val = gpu->gp0_command.buffer[0]; 303 304 gpu->drawing_area_bottom = (u16)((val >> 10) & 0x3ff); 305 gpu->drawing_area_right = (u16)(val & 0x3ff); 306 } 307 308 void 309 GPU_gp0_drawing_offset(GPU* gpu) 310 { 311 u16 x, y; 312 u32 val; 313 314 val = gpu->gp0_command.buffer[0]; 315 x = (u16)(val & 0x7ff); 316 y = (u16)((val >> 11) & 0x7ff); 317 318 /* Values here are 11bit 2s complement signed values, we need to force sign extension */ 319 gpu->drawing_x_offset = ((i16)(x << 5)) >> 5; 320 gpu->drawing_y_offset = ((i16)(y << 5)) >> 5; 321 322 /* 323 This is a hack because I haven't implemented gpu timings yet. 324 But gp0_drawing_offset is called every frame apparently. 325 */ 326 REN_display(gpu->ren); 327 328 } 329 330 void 331 GPU_gp0_texture_window(GPU* gpu) 332 { 333 u32 val; 334 val = gpu->gp0_command.buffer[0]; 335 336 gpu->texture_window_x_mask = (u8)(val & 0x1f); 337 gpu->texture_window_y_mask = (u8)((val >> 5) & 0x1f); 338 gpu->texture_window_x_offset = (u8)((val >> 10) & 0x1f); 339 gpu->texture_window_y_offset = (u8)((val >> 15) & 0x1f); 340 } 341 342 void 343 GPU_gp0_mask_bit_setting(GPU* gpu) 344 { 345 u32 val; 346 val = gpu->gp0_command.buffer[0]; 347 348 gpu->force_set_mask_bit = (val & 1) != 0; 349 gpu->preserve_masked_pixels = (val & 2) != 0; 350 } 351 352 void 353 GPU_gp0_quad_mono_opaque(GPU* gpu) 354 { 355 ivec2 positions[4]; 356 C colors[4]; 357 358 positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); 359 positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[2]); 360 positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); 361 positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[4]); 362 363 colors[0] = colors[1] = colors[2] = colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); 364 365 /*GPU_LOG("Draw quad mono opaque at x: %d, y: %d\n", positions[0].x, positions[0].y, NULL);*/ 366 /*GPU_LOG("Draw quad mono opaque with R: %d, G: %d, B: %d\n", colors[0].r, colors[0].g, colors[0].b, NULL);*/ 367 368 REN_push_quad(gpu->ren, positions, colors); 369 } 370 371 void 372 GPU_gp0_triangle_shaded_opaque(GPU* gpu) 373 { 374 ivec2 positions[3]; 375 C colors[3]; 376 377 positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); 378 positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); 379 positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); 380 381 colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); 382 colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]); 383 colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); 384 385 REN_push_triangle(gpu->ren, positions, colors); 386 387 /*GPU_LOG("Draw triangle shaded at x: %d, y: %d\n", positions[0].x, positions[0].y, NULL);*/ 388 } 389 390 void 391 GPU_gp0_quad_texture_blend_opaque(GPU* gpu) 392 { 393 ivec2 positions[4]; 394 C colors[4]; 395 C tmp = {0x80, 0x00, 0x00}; 396 397 398 positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); 399 positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); 400 positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); 401 positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]); 402 403 colors[0] = colors[1] = colors[2] = colors[3] = tmp; 404 405 REN_push_quad(gpu->ren, positions, colors); 406 } 407 408 void 409 GPU_gp0_quad_shaded_opaque(GPU* gpu) 410 { 411 ivec2 positions[4]; 412 C colors[4]; 413 414 positions[0] = POSITION_from_gp0(gpu->gp0_command.buffer[1]); 415 positions[1] = POSITION_from_gp0(gpu->gp0_command.buffer[3]); 416 positions[2] = POSITION_from_gp0(gpu->gp0_command.buffer[5]); 417 positions[3] = POSITION_from_gp0(gpu->gp0_command.buffer[7]); 418 419 colors[0] = COLOR_from_gp0(gpu->gp0_command.buffer[0]); 420 colors[1] = COLOR_from_gp0(gpu->gp0_command.buffer[2]); 421 colors[2] = COLOR_from_gp0(gpu->gp0_command.buffer[4]); 422 colors[3] = COLOR_from_gp0(gpu->gp0_command.buffer[6]); 423 424 /*GPU_LOG("I GOT CALLED\n", NULL);*/ 425 REN_push_quad(gpu->ren, positions, colors); 426 } 427 428 void 429 GPU_gp0_image_store(GPU* gpu) 430 { 431 u32 res, width, height; 432 433 res = gpu->gp0_command.buffer[2]; 434 width = res & 0xffff; 435 height = res >> 16; 436 437 log_debug("Unhandled image store: %dx%d", width, height); 438 } 439 440 GPU_CMD_BUFFER* 441 GPU_CMD_BUFFER_new(void) 442 { 443 GPU_CMD_BUFFER* buffer; 444 445 buffer = (GPU_CMD_BUFFER*)malloc(sizeof(GPU_CMD_BUFFER)); 446 memset(buffer, 0, sizeof(GPU_CMD_BUFFER)); 447 448 return buffer; 449 } 450 451 void 452 GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer) 453 { 454 cmd_buffer->len = 0; 455 memset(cmd_buffer->buffer, 413, 12 * sizeof(u32)); 456 } 457 458 void 459 GPU_CMD_BUFFER_push_word(GPU_CMD_BUFFER* cmd_buffer, u32 word) 460 { 461 if (cmd_buffer->len > 12) 462 log_fatal("OUT OF BOUNDS GPU_CMD_BUFFER"), exit(EXIT_FAILURE); 463 464 cmd_buffer->buffer[cmd_buffer->len] = word; 465 cmd_buffer->len++; 466 }