An emulator, assembler, and disassembler for the Sega Game Gear
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 

193 wiersze
5.2 KiB

  1. /* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <string.h>
  4. #include "vdp.h"
  5. #include "util.h"
  6. #define CODE_VRAM_READ 0
  7. #define CODE_VRAM_WRITE 1
  8. #define CODE_REG_WRITE 2
  9. #define CODE_CRAM_WRITE 3
  10. /*
  11. Initialize the Video Display Processor (VDP).
  12. */
  13. void vdp_init(VDP *vdp)
  14. {
  15. vdp->vram = cr_malloc(sizeof(uint8_t) * VDP_VRAM_SIZE);
  16. vdp->cram = cr_malloc(sizeof(uint8_t) * VDP_CRAM_SIZE);
  17. memset(vdp->vram, 0x00, VDP_VRAM_SIZE);
  18. memset(vdp->cram, 0x00, VDP_CRAM_SIZE);
  19. }
  20. /*
  21. Free memory previously allocated by the VDP.
  22. */
  23. void vdp_free(VDP *vdp)
  24. {
  25. free(vdp->vram);
  26. }
  27. /*
  28. Power on the VDP, setting up initial state.
  29. */
  30. void vdp_power(VDP *vdp)
  31. {
  32. vdp->regs[0x00] = 0x00;
  33. vdp->regs[0x01] = 0x00;
  34. vdp->regs[0x02] = 0xFF;
  35. vdp->regs[0x03] = 0xFF;
  36. vdp->regs[0x04] = 0xFF;
  37. vdp->regs[0x05] = 0xFF;
  38. vdp->regs[0x06] = 0xFF;
  39. vdp->regs[0x07] = 0x00;
  40. vdp->regs[0x08] = 0x00;
  41. vdp->regs[0x09] = 0x00;
  42. vdp->regs[0x0A] = 0x01;
  43. vdp->h_counter = 0;
  44. vdp->v_counter = 0;
  45. vdp->v_count_jump = false;
  46. vdp->control_code = 0;
  47. vdp->control_addr = 0;
  48. vdp->control_flag = false;
  49. vdp->stat_int = vdp->stat_ovf = vdp->stat_col = 0;
  50. vdp->read_buf = 0;
  51. vdp->cram_latch = 0;
  52. }
  53. /*
  54. Advance the V counter for the next scanline.
  55. */
  56. static void advance_scanline(VDP *vdp)
  57. {
  58. if (vdp->v_counter == 0xDA)
  59. vdp->v_count_jump = !vdp->v_count_jump;
  60. if (vdp->v_counter == 0xDA && vdp->v_count_jump)
  61. vdp->v_counter = 0xD5;
  62. else
  63. vdp->v_counter++;
  64. }
  65. /*
  66. Simulate one scanline within the VDP.
  67. TODO: elaborate
  68. */
  69. void vdp_simulate_line(VDP *vdp)
  70. {
  71. if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) {
  72. // TODO: draw current line
  73. }
  74. advance_scanline(vdp);
  75. }
  76. /*
  77. Read a byte from the VDP's control port, revealing status flags.
  78. The status byte consists of:
  79. 7 6 5 4 3 2 1 0
  80. F 9S C * * * * *
  81. - F: Interrupt flag: set when the effective display area is completed
  82. - 9S: 9th sprite / Sprite overflow: more than eight sprites on a scanline
  83. - C: Collision flag: two sprites have an overlapping pixel
  84. - *: Unused
  85. The control flag is also reset.
  86. */
  87. uint8_t vdp_read_control(VDP *vdp)
  88. {
  89. uint8_t status =
  90. (vdp->stat_int << 8) + (vdp->stat_ovf << 7) + (vdp->stat_col << 6);
  91. vdp->stat_int = vdp->stat_ovf = vdp->stat_col = 0;
  92. vdp->control_flag = false;
  93. return status;
  94. }
  95. /*
  96. Read a byte from the VDP's data port.
  97. This will return the contents of the read buffer, and then fill the buffer
  98. with the VRAM at the current control address, before incrementing the
  99. control address. The control flag is also reset.
  100. */
  101. uint8_t vdp_read_data(VDP *vdp)
  102. {
  103. uint8_t buffer = vdp->read_buf;
  104. vdp->read_buf = vdp->vram[vdp->control_addr];
  105. vdp->control_addr = (vdp->control_addr + 1) % 0x3FFF;
  106. vdp->control_flag = false;
  107. return buffer;
  108. }
  109. /*
  110. Write a byte into the VDP's control port.
  111. Depending on the status of the control flag, this will either update the
  112. lower byte of the control address, or the upper six bits of the control
  113. address and the control code. The flag is toggled by each control write,
  114. and reset by each control read and data read or write.
  115. If the control code indicates a VRAM read, the read buffer will be filled
  116. with the VRAM at the given control address, which is then incremented. If
  117. the code indicates a register write, the corresponding register
  118. (byte & 0x0F) will be written with the lower byte of the control address.
  119. */
  120. void vdp_write_control(VDP *vdp, uint8_t byte)
  121. {
  122. if (!vdp->control_flag) { // First byte
  123. vdp->control_addr = (vdp->control_addr & 0x3F00) + byte;
  124. } else { // Second byte
  125. vdp->control_addr = ((byte & 0x3F) << 8) + (vdp->control_addr & 0xFF);
  126. vdp->control_code = byte >> 6;
  127. }
  128. if (vdp->control_code == CODE_VRAM_READ) {
  129. vdp->read_buf = vdp->vram[vdp->control_addr];
  130. vdp->control_addr = (vdp->control_addr + 1) % 0x3FFF;
  131. } else if (vdp->control_code == CODE_REG_WRITE) {
  132. uint8_t reg = byte & 0x0F;
  133. if (reg <= VDP_REGS)
  134. vdp->regs[reg] = vdp->control_addr & 0xFF;
  135. }
  136. vdp->control_flag = !vdp->control_flag;
  137. }
  138. /*
  139. Write a byte into CRAM. Handles even/odd address latching.
  140. */
  141. static void write_cram(VDP *vdp, uint8_t byte)
  142. {
  143. if (!(vdp->control_addr % 2)) {
  144. vdp->cram_latch = byte;
  145. } else {
  146. vdp->cram[(vdp->control_addr - 1) % 0x3F] = vdp->cram_latch;
  147. vdp->cram[ vdp->control_addr % 0x3F] = byte % 0x0F;
  148. }
  149. }
  150. /*
  151. Write a byte into the VDP's data port.
  152. Depending on the control code, this either writes into the VRAM or CRAM at
  153. the current control address, which is then incremented. The control flag is
  154. also reset, and the read buffer is squashed.
  155. */
  156. void vdp_write_data(VDP *vdp, uint8_t byte)
  157. {
  158. if (vdp->control_code == CODE_CRAM_WRITE)
  159. write_cram(vdp, byte);
  160. else
  161. vdp->vram[vdp->control_addr] = byte;
  162. vdp->control_addr = (vdp->control_addr + 1) % 0x3FFF;
  163. vdp->control_flag = false;
  164. vdp->read_buf = byte;
  165. }