| Previous | 199869 Revisions | Next |
| r32612 Friday 10th October, 2014 at 05:03:12 UTC by Fabio Priuli |
|---|
| (MESS) maria.c: improved DMA accuracy. [Mike Saarna, Robert Tuccitto] - Last Line DMA value corrected to 6. GCC and Atari docs both show a difference between Other Line and Last Line as +6 at the lowest part of the range. - Blank scanlines are drawn when DMA is off, like real hardware. - If MARIA hits the DMA limit, the CPU doesn't run until the next scanline. |
| [src/mess/video] | maria.c |
| r32611 | r32612 | |
|---|---|---|
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | - some history: |
| 7 | 2014-10-03 Mike Saarna, Robert Tuccitto reorganized DMA penalties to | |
| 8 | support new rendering timeout code. | |
| 7 | 2014-10-05 Mike Saarna, Robert Tuccitto Last Line DMA value corrected | |
| 8 | to 6. GCC and Atari docs both show a difference between | |
| 9 | Other Line and Last Line as +6 at the lowest part of the | |
| 10 | range. | |
| 11 | Blank scanlines are drawn when DMA is off, like real | |
| 12 | hardware. | |
| 13 | If MARIA hits the DMA limit, the CPU doesn't run until | |
| 14 | the next scanline. | |
| 9 | 15 | |
| 16 | 2014-09-03 Mike Saarna, Robert Tuccitto reorganized DMA penalties to | |
| 17 | support new rendering timeout code. | |
| 18 | ||
| 10 | 19 | 2014-08-29 Mike Saarna Timeout rendering added. |
| 11 | 20 | |
| 12 | 21 | 2014-08-26 Fabio Priuli Converted to device |
| r32611 | r32612 | |
| 165 | 174 | int d, c, pixel_cell, cells; |
| 166 | 175 | int maria_cycles; |
| 167 | 176 | |
| 168 | // All lines in a zone have the same initial DMA startup time. We'll adjust | |
| 169 | // cycles for the special last zone line later, as those penalties happen after | |
| 170 | // MARIA is done rendering, or after its hit the maximum rendering time. | |
| 171 | maria_cycles = 16; | |
| 172 | ||
| 173 | 177 | cells = 0; |
| 174 | 178 | |
| 175 | /* Process this DLL entry */ | |
| 176 | dl = m_dl; | |
| 179 | if(m_dmaon) | |
| 180 | { | |
| 181 | // All lines in a zone have the same initial DMA startup time. We'll adjust | |
| 182 | // cycles for the special last zone line later, as those penalties happen after | |
| 183 | // MARIA is done rendering, or after its hit the maximum rendering time. | |
| 184 | maria_cycles = 16; | |
| 177 | 185 | |
| 178 | /* DMA */ | |
| 179 | /* Step through DL's while we're within maximum rendering time. max render time = ( scanline length - DMA start ) */ | |
| 180 | /* 426 = ( 454 - 28 ) */ | |
| 181 | 186 | |
| 182 | while (((READ_MEM(dl + 1) & 0x5f) != 0) && (maria_cycles<426)) | |
| 183 | { | |
| 184 | /* Extended header */ | |
| 185 | if (!(READ_MEM(dl + 1) & 0x1f)) | |
| 186 | { | |
| 187 | graph_adr = (READ_MEM(dl + 2) << 8) | READ_MEM(dl); | |
| 188 | width = ((READ_MEM(dl + 3) ^ 0xff) & 0x1f) + 1; | |
| 189 | hpos = READ_MEM(dl + 4); | |
| 190 | pal = READ_MEM(dl + 3) >> 5; | |
| 191 | m_write_mode = (READ_MEM(dl + 1) & 0x80) >> 5; | |
| 192 | ind = READ_MEM(dl + 1) & 0x20; | |
| 193 | dl += 5; | |
| 194 | maria_cycles += 10; | |
| 195 | } | |
| 196 | /* Normal header */ | |
| 197 | else | |
| 198 | { | |
| 199 | graph_adr = (READ_MEM(dl + 2) << 8) | READ_MEM(dl); | |
| 200 | width = ((READ_MEM(dl + 1) ^ 0xff) & 0x1f) + 1; | |
| 201 | hpos = READ_MEM(dl + 3); | |
| 202 | pal = READ_MEM(dl + 1) >> 5; | |
| 203 | ind = 0x00; | |
| 204 | dl += 4; | |
| 205 | maria_cycles += 8; | |
| 206 | } | |
| 187 | /* Process this DLL entry */ | |
| 188 | dl = m_dl; | |
| 207 | 189 | |
| 208 | /*logerror("%x DL: ADR=%x width=%x hpos=%x pal=%x mode=%x ind=%x\n", m_screen->vpos(), graph_adr, width, hpos, pal, m_write_mode, ind);*/ | |
| 190 | /* DMA */ | |
| 191 | /* Step through DL's while we're within maximum rendering time. */ | |
| 192 | /* max render time = ( scanline length - DMA start ) */ | |
| 193 | /* 426 = ( 454 - 28 ) */ | |
| 209 | 194 | |
| 210 | | |
| 195 | while (((READ_MEM(dl + 1) & 0x5f) != 0) && (maria_cycles<426)) | |
| 211 | 196 | { |
| 212 | if (maria_cycles >= 426) // ensure we haven't overrun the maximum render time | |
| 213 | break; | |
| 197 | /* Extended header */ | |
| 198 | if (!(READ_MEM(dl + 1) & 0x1f)) | |
| 199 | { | |
| 200 | graph_adr = (READ_MEM(dl + 2) << 8) | READ_MEM(dl); | |
| 201 | width = ((READ_MEM(dl + 3) ^ 0xff) & 0x1f) + 1; | |
| 202 | hpos = READ_MEM(dl + 4); | |
| 203 | pal = READ_MEM(dl + 3) >> 5; | |
| 204 | m_write_mode = (READ_MEM(dl + 1) & 0x80) >> 5; | |
| 205 | ind = READ_MEM(dl + 1) & 0x20; | |
| 206 | dl += 5; | |
| 207 | maria_cycles += 10; | |
| 208 | } | |
| 209 | /* Normal header */ | |
| 210 | else | |
| 211 | { | |
| 212 | graph_adr = (READ_MEM(dl + 2) << 8) | READ_MEM(dl); | |
| 213 | width = ((READ_MEM(dl + 1) ^ 0xff) & 0x1f) + 1; | |
| 214 | hpos = READ_MEM(dl + 3); | |
| 215 | pal = READ_MEM(dl + 1) >> 5; | |
| 216 | ind = 0x00; | |
| 217 | dl += 4; | |
| 218 | maria_cycles += 8; | |
| 219 | } | |
| 214 | 220 | |
| 215 | /* Do indirect mode */ | |
| 216 | if (ind) | |
| 221 | /*logerror("%x DL: ADR=%x width=%x hpos=%x pal=%x mode=%x ind=%x\n", m_screen->vpos(), graph_adr, width, hpos, pal, m_write_mode, ind);*/ | |
| 222 | ||
| 223 | for (int x = 0; x < width; x++) | |
| 217 | 224 | { |
| 218 | c = READ_MEM(graph_adr + x) & 0xff; | |
| 219 | data_addr = (m_charbase | c) + (m_offset << 8); | |
| 220 | if (is_holey(data_addr)) | |
| 221 | continue; | |
| 225 | if (maria_cycles >= 426) // ensure we haven't overrun the maximum render time | |
| 226 | break; | |
| 227 | ||
| 228 | /* Do indirect mode */ | |
| 229 | if (ind) | |
| 230 | { | |
| 231 | c = READ_MEM(graph_adr + x) & 0xff; | |
| 232 | data_addr = (m_charbase | c) + (m_offset << 8); | |
| 233 | if (is_holey(data_addr)) | |
| 234 | continue; | |
| 222 | 235 | |
| 223 | maria_cycles += 3; | |
| 224 | if (m_cwidth) // two data bytes per map byte | |
| 225 | { | |
| 226 | cells = write_line_ram(data_addr, hpos, pal); | |
| 227 | hpos += cells; | |
| 228 | cells = write_line_ram(data_addr+1, hpos, pal); | |
| 229 | hpos += cells; | |
| 230 | maria_cycles += 6; | |
| 236 | maria_cycles += 3; | |
| 237 | if (m_cwidth) // two data bytes per map byte | |
| 238 | { | |
| 239 | cells = write_line_ram(data_addr, hpos, pal); | |
| 240 | hpos += cells; | |
| 241 | cells = write_line_ram(data_addr+1, hpos, pal); | |
| 242 | hpos += cells; | |
| 243 | maria_cycles += 6; | |
| 244 | } | |
| 245 | else | |
| 246 | { | |
| 247 | cells = write_line_ram(data_addr, hpos, pal); | |
| 248 | hpos += cells; | |
| 249 | maria_cycles += 3; | |
| 250 | } | |
| 231 | 251 | } |
| 232 | else | |
| 252 | else // direct mode | |
| 233 | 253 | { |
| 254 | data_addr = graph_adr + x + (m_offset << 8); | |
| 255 | if (is_holey(data_addr)) | |
| 256 | continue; | |
| 234 | 257 | cells = write_line_ram(data_addr, hpos, pal); |
| 235 | 258 | hpos += cells; |
| 236 | 259 | maria_cycles += 3; |
| 237 | 260 | } |
| 238 | 261 | } |
| 239 | else // direct mode | |
| 240 | { | |
| 241 | data_addr = graph_adr + x + (m_offset << 8); | |
| 242 | if (is_holey(data_addr)) | |
| 243 | continue; | |
| 244 | cells = write_line_ram(data_addr, hpos, pal); | |
| 245 | hpos += cells; | |
| 246 | maria_cycles += 3; | |
| 247 | } | |
| 248 | 262 | } |
| 249 | } | |
| 250 | 263 | |
| 251 | // Last Line post-render DMA cycle penalties... | |
| 252 | if (m_offset == 0) | |
| 253 | { | |
| 254 | maria_cycles += 3; // extra shutdown time | |
| 255 | if (READ_MEM(m_dll + 3) & 0x80) | |
| 256 | maria_cycles += 21; // interrupt overhead | |
| 264 | // Last Line post-render DMA cycle penalties... | |
| 265 | if (m_offset == 0) | |
| 266 | { | |
| 267 | maria_cycles += 6; // extra shutdown time | |
| 268 | if (READ_MEM(m_dll + 3) & 0x80) | |
| 269 | maria_cycles += 17; // interrupt overhead | |
| 270 | } | |
| 271 | ||
| 272 | // If MARIA used up all of the DMA time then the CPU can't run until next line... | |
| 273 | if (maria_cycles>=426) | |
| 274 | { | |
| 275 | m_cpu->spin_until_trigger(TRIGGER_HSYNC); | |
| 276 | m_wsync = 1; | |
| 277 | } | |
| 278 | ||
| 279 | // Spin the CPU for Maria DMA, if it's not already spinning for WSYNC. | |
| 280 | // MARIA generates the 6502 clock by dividing its own clock by 4. It needs to HALT and unHALT | |
| 281 | // the 6502 on ths same clock phase, so MARIA will wait until its clock divides evenly by 4. | |
| 282 | // To spin until an even divisor, we just round-up any would-be truncations by adding 3. | |
| 283 | if (!m_wsync) | |
| 284 | m_cpu->spin_until_time(m_cpu->cycles_to_attotime((maria_cycles+3)/4)); | |
| 257 | 285 | } |
| 258 | 286 | |
| 259 | // Spin the CPU for Maria DMA, if it's not already spinning for WSYNC. | |
| 260 | // MARIA generates the 6502 clock by dividing its own clock by 4. It needs to HALT and unHALT | |
| 261 | // the 6502 on ths same clock phase, so MARIA will wait until its clock divides evenly by 4. | |
| 262 | // To spin until an even divisor, we just round-up any would-be truncations by adding 3. | |
| 263 | if (!m_wsync) | |
| 264 | m_cpu->spin_until_time(m_cpu->cycles_to_attotime((maria_cycles+3)/4)); | |
| 265 | ||
| 266 | 287 | // draw line buffer to screen |
| 267 | 288 | m_active_buffer = !m_active_buffer; // switch buffers |
| 268 | 289 | UINT16 *scanline; |
| r32611 | r32612 | |
| 335 | 356 | m_holey = (READ_MEM(m_dll) & 0x60) >> 5; |
| 336 | 357 | m_nmi = READ_MEM(m_dll) & 0x80; |
| 337 | 358 | /* logerror("DLL=%x\n",m_dll); */ |
| 338 | draw_scanline(); | |
| 339 | 359 | } |
| 340 | 360 | |
| 361 | if ((frame_scanline > 15) && (frame_scanline < (lines - 5))) | |
| 362 | draw_scanline(); | |
| 341 | 363 | |
| 342 | 364 | if ((frame_scanline > 16) && (frame_scanline < (lines - 5)) && m_dmaon) |
| 343 | 365 | { |
| 344 | draw_scanline(); | |
| 345 | 366 | if (m_offset == 0) |
| 346 | 367 | { |
| 347 | 368 | m_dll += 3; |
| Previous | 199869 Revisions | Next |