/* Redraw the current raster line. This happens at the last cycle of each line. */ static void crtc_raster_draw_alarm_handler(CLOCK offset, void *data) { int new_sync_diff; int new_venable; int new_vsync; int screen_width = (int)crtc.screen_width; new_venable = crtc.venable; new_vsync = crtc.vsync; /****************************************************************** * handle one rasterline */ /* first the time between two sync pulses */ new_sync_diff = (crtc.prev_rl_len + 1 - crtc.prev_rl_sync) + crtc.rl_sync; /* compute the horizontal position */ /* the original PET displays have quite a variety of sync timings (or I haven't found the scheme yet). Therefore we cannot simply center the part between the syncs. We assume the sync in the first rasterline of the screen to be the default for the next frame. */ /* FIXME: crtc.regs[3] & 15 == 0 -> 16 */ if (crtc.raster.current_line == 0) { crtc.screen_xoffset = ((screen_width - (crtc.sync_diff * 8 * crtc.hw_cols)) / 2) + ((crtc.prev_rl_len + 1 - crtc.prev_rl_sync - ((crtc.regs[3] & 0x0f) / 2)) * 8 * crtc.hw_cols); /* FIXME: The 320 is the pixel width of a window with 40 cols. make that a define - or measure the visible line length? but how to do that reliably? */ crtc.xoffset = CRTC_SCREEN_BORDERWIDTH + (CRTC_EXTRA_COLS * 4) /* ((screen_width - crtc.rl_visible * 8 * crtc.hw_cols) / 2) */ - crtc.screen_xoffset + ((screen_width - (crtc.sync_diff * 8 * crtc.hw_cols)) / 2) + ((crtc.prev_rl_len + 1 - crtc.prev_rl_sync - ((crtc.regs[3] & 0x0f) / 2)) * 8 * crtc.hw_cols); } /* emulate the line */ if (crtc.raster.current_line >= crtc.screen_height - 2 * CRTC_SCREEN_BORDERHEIGHT) { /* FIXFRAME: crtc.raster.current_line ++; */ } else { raster_line_emulate(&crtc.raster); } /* now add jitter if this is out of phase (sync_diff changes) */ crtc.hjitter -= (new_sync_diff - crtc.sync_diff) * 4 * crtc.hw_cols; if (crtc.hjitter > 16) crtc.hjitter = 16; if (crtc.hjitter < -16) crtc.hjitter = -16; /* exponential/sine decay */ crtc.hjitter = (int)((double)(crtc.hjitter) * -0.5); /* if (crtc.hjitter) { printf("rl=%d, jitter=%d, sync_diff=%d, old diff=%d, \n", crtc.raster.current_line, crtc.hjitter, new_sync_diff, crtc.sync_diff); } */ crtc.sync_diff = new_sync_diff; /* if (crtc.raster.current_line == 10) { printf("centering=%d, sync2start=%d -> xoff=%d, jitter=%d\n", ((screen_width - (sync_diff * crtc.hw_cols * 8)) / 2), (crtc.prev_rl_len + 1 - crtc.prev_rl_sync - ((crtc.regs[3] & 0x0f) / 2)), ((screen_width - (sync_diff * crtc.hw_cols * 8)) / 2) + ((crtc.prev_rl_len + 1 - crtc.prev_rl_sync - ((crtc.regs[3] & 0x0f) / 2)) * crtc.hw_cols * 8), crtc.hjitter); } */ crtc.prev_rl_visible = crtc.rl_visible; crtc.prev_rl_sync = crtc.rl_sync; crtc.prev_rl_len = crtc.rl_len; crtc.prev_screen_rel = crtc.screen_rel; crtc.rl_visible = crtc.regs[1]; crtc.rl_sync = crtc.regs[2]; crtc.rl_len = crtc.regs[0]; crtc.rl_start = maincpu_clk - offset; /****************************************************************** * handle the rasterline numbering */ crtc.current_line ++; /* FIXFRAME; crtc.framelines --; if (crtc.framelines == crtc.screen_yoffset) { */ if ((crtc.framelines - crtc.current_line) == crtc.screen_yoffset) { crtc.raster.current_line = 0; raster_canvas_handle_end_of_frame(&crtc.raster); raster_skip_frame(&crtc.raster, vsync_do_vsync(crtc.raster.canvas, crtc.raster.skip_frame)); } { /* FIXME: charheight */ if (crtc.current_charline >= crtc.regs[4] + 1) { if ((crtc.raster.ycounter + 1) >= crtc.regs[5]) { long cycles; /* Do vsync stuff. */ /* printf("new screen at clk=%d\n",crtc.rl_start); */ crtc_reset_screen_ptr(); crtc.raster.ycounter = 0; crtc.current_charline = 0; new_venable = 1; /* expected number of rasterlines for next frame */ crtc.framelines = crtc.current_line; crtc.current_line = 0; /* hardware cursor handling */ if (crtc.crsrmode & 2) { crtc.crsrcnt --; if (!crtc.crsrcnt) { crtc.crsrcnt = (crtc.crsrmode & 1) ? 16 : 32; crtc.crsrstate ^= 1; } } /* cycles per frame, for speed adjustments */ cycles = crtc.rl_start - crtc.frame_start; if (crtc.frame_start && (cycles != crtc.cycles_per_frame)) { machine_set_cycles_per_frame(cycles); crtc.cycles_per_frame = cycles; } crtc.frame_start = crtc.rl_start; } else { crtc.raster.ycounter ++; } } else { if (crtc.raster.ycounter != crtc.regs[9] ) { crtc.raster.ycounter ++; crtc.raster.ycounter &= 0x1f; } else { crtc.raster.ycounter = 0; crtc.current_charline ++; crtc.current_charline &= 0x7f; if (crtc.henable) { crtc.screen_rel += crtc.rl_visible * crtc.hw_cols; } if (crtc.current_charline == crtc.regs[6]) { new_venable = 0; } if ((crtc.current_charline == crtc.regs[7])) { /* printf("hsync starts at clk=%d\n",crtc.rl_start); */ new_vsync = (crtc.regs[3] >> 4) & 0x0f; if (!new_vsync) new_vsync = 16; new_vsync ++; /* compensate for the first decrease below */ } } if (crtc.raster.ycounter == (unsigned int)(crtc.regs[10] & 0x1f)) { crtc.cursor_lines = 1; } else if (crtc.raster.ycounter == (unsigned int)((crtc.regs[11] + 1) & 0x1f)) { crtc.cursor_lines = 0; } crtc.henable = 1; } if (new_vsync) { new_vsync --; } }
/* Redraw the current raster line. This happens at cycle TED_DRAW_CYCLE of each line. */ void ted_raster_draw_alarm_handler(CLOCK offset, void *data) { int in_visible_area; in_visible_area = (ted.tv_current_line >= (unsigned int)ted.first_displayed_line && ted.tv_current_line <= (unsigned int)ted.last_displayed_line); if (ted.tv_current_line < ted.screen_height) { raster_line_emulate(&ted.raster); } else { log_debug("Skip line %d %d", ted.tv_current_line, ted.screen_height); } if (ted.ted_raster_counter == ted.last_dma_line) { ted.idle_state = 1; } ted.tv_current_line++; ted.ted_raster_counter++; if (ted.ted_raster_counter == ted.screen_height) { ted.memptr = 0; ted.memptr_col = 0; ted.mem_counter = 0; ted.chr_pos_count = 0; ted.ted_raster_counter = 0; if (!ted.raster.blank) { ted.character_fetch_on = 1; } ted.raster.ycounter = 0; } if (ted.ted_raster_counter == 512) { ted.ted_raster_counter = 0; } if (ted.ted_raster_counter == 0xcc) { ted.character_fetch_on = 0; } if (ted.regs[0x06] & 8) { if (ted.ted_raster_counter == ted.row_25_start_line && (!ted.raster.blank || ted.raster.blank_off)) { ted.raster.blank_enabled = 0; } if (ted.ted_raster_counter == ted.row_25_stop_line + 1) { ted.raster.blank_enabled = 1; } } else { if (ted.ted_raster_counter == ted.row_24_start_line && (!ted.raster.blank || ted.raster.blank_off)) { ted.raster.blank_enabled = 0; } if (ted.ted_raster_counter == ted.row_24_stop_line + 1) { ted.raster.blank_enabled = 1; } } /* DO VSYNC if the raster_counter in the TED reached the VSYNC signal */ /* Also do VSYNC if oversized screen reached a certain threashold, this will result in rolling screen just like on the real thing */ if (((signed int)(ted.tv_current_line - ted.screen_height) > 40) || (ted.ted_raster_counter == ted.vsync_line )) { if (ted.tv_current_line < ted.screen_height) { ted.raster.current_line = 0; raster_canvas_handle_end_of_frame(&ted.raster); } /*log_debug("Vsync %d %d",ted.tv_current_line, ted.ted_raster_counter);*/ raster_skip_frame(&ted.raster, vsync_do_vsync(ted.raster.canvas, ted.raster.skip_frame)); ted.tv_current_line = 0; /* FIXME increment at appropriate cycle */ ted.cursor_phase = (ted.cursor_phase + 1) & 0x1f; ted.cursor_visible = ted.cursor_phase & 0x10; #ifdef __MSDOS__ if (ted.raster.canvas->draw_buffer->canvas_width <= TED_SCREEN_XPIX && ted.raster.canvas->draw_buffer->canvas_height <= TED_SCREEN_YPIX) { canvas_set_border_color(ted.raster.canvas, ted.raster.border_color); } #endif } if (in_visible_area) { /* log_debug("Idle state %03x, %03x, %d",ted.ted_raster_counter, ted.idle_state, ted.raster.ycounter);*/ if (!ted.idle_state) { ted.mem_counter = (ted.mem_counter + ted.mem_counter_inc) & 0x3ff; ted.chr_pos_count = (ted.chr_pos_count + ted.mem_counter_inc) & 0x3ff; } ted.mem_counter_inc = TED_SCREEN_TEXTCOLS; /* `ycounter' makes the chip go to idle state when it reaches the maximum value. */ if (ted.raster.ycounter == 6) { ted.memptr_col = ted.mem_counter; } if (ted.raster.ycounter == 7) { ted.memptr = ted.chr_pos_count; /* ted.idle_state = 1;*/ } if (!ted.idle_state && ted.allow_bad_lines /*|| ted.bad_line*/) { ted.raster.ycounter = (ted.raster.ycounter + 1) & 0x7; ted.idle_state = 0; } if (ted.force_display_state) { ted.idle_state = 0; ted.force_display_state = 0; } ted.raster.draw_idle_state = ted.idle_state; /*ted.bad_line = 0;*/ } ted.ycounter_reset_checked = 0; ted.memory_fetch_done = 0; if (ted.ted_raster_counter == ted.first_dma_line) { ted.allow_bad_lines = !ted.raster.blank; } if (ted.allow_bad_lines && (ted.ted_raster_counter & 7) == (unsigned int)((ted.raster.ysmooth + 1) & 7)) { memcpy(ted.cbuf, ted.cbuf_tmp, ted.mem_counter_inc); } /* FIXME */ if (ted.idle_state) { if (ted.regs[0x6] & 0x40) { ted.idle_data_location = IDLE_39FF; ted.idle_data = mem_ram[0xffff]; } else { ted.idle_data_location = IDLE_3FFF; ted.idle_data = mem_ram[0xffff]; } } else { ted.idle_data_location = IDLE_NONE; } /* Set the next draw event. */ ted.last_emulate_line_clk += ted.cycles_per_line; ted.draw_clk = ted.last_emulate_line_clk + ted.draw_cycle; alarm_set(ted.raster_draw_alarm, ted.draw_clk); }
void vic_raster_draw_alarm_handler(CLOCK offset, void *data) { static int pending_mem_offset; static int possible_mem_offset; int blank_this_line; /* remember if this line stays blank */ blank_this_line = vic.raster.blank_this_line; /* check if first visible line is reached */ if (vic.area == 0 && !blank_this_line && vic.raster.current_line >= vic.raster.display_ystart) { vic.area = 1; } /* check if row step is pending */ if (vic.row_increase_line == (unsigned int)vic.raster.ycounter || 2 * vic.row_increase_line == (unsigned int)vic.raster.ycounter) { vic.row_counter++; vic.raster.ycounter = 0; vic.raster.display_ystop = vic.raster.current_line + (vic.text_lines - vic.row_counter) * vic.char_height; /* if XPOS is 0 VIC displays one more rasterline */ if (vic.raster.display_xstart == 0) vic.raster.display_ystop++; pending_mem_offset = possible_mem_offset; } /* update memptr */ if (vic.area == 1) vic.memptr += pending_mem_offset; pending_mem_offset = 0; /* max offset for next row */ possible_mem_offset = vic.text_cols; /* emulate the line */ raster_line_emulate(&vic.raster); /* xstart may have changed; recalculate xstop */ vic.raster.display_xstop = vic.raster.display_xstart + vic.text_cols * 8 * VIC_PIXEL_WIDTH; if (vic.raster.display_xstop >= (int)(vic.screen_width * VIC_PIXEL_WIDTH)) vic.raster.display_xstop = (int)((vic.screen_width - 1) * VIC_PIXEL_WIDTH); /* increment ycounter and set offset for memptr */ if (vic.area == 1) { vic.raster.ycounter++; if (vic.row_offset != 0 || (unsigned int)vic.raster.ycounter == vic.row_increase_line) { pending_mem_offset = (vic.row_offset > 0 ? vic.row_offset : possible_mem_offset); vic.row_offset = 0; if (blank_this_line) { possible_mem_offset = 0; } } if (vic.raster.current_line >= vic.raster.display_ystop) vic.area = 2; } /* handle start of frame */ if (vic.raster.current_line == 0) { raster_skip_frame(&vic.raster, vsync_do_vsync(vic.raster.canvas, vic.raster.skip_frame)); vic.raster.blank_enabled = 1; vic.row_counter = 0; vic.raster.ycounter = 0; vic.memptr = 0; vic.area = 0; if (vic.pending_ystart >= 0) { vic.raster.display_ystart = vic.pending_ystart; vic.raster.geometry->gfx_position.y = vic.pending_ystart - vic.first_displayed_line; vic.raster.display_ystop = vic.raster.display_ystart + vic.text_lines * vic.char_height; vic.pending_ystart = -1; } if (vic.pending_text_lines >= 0) { vic.text_lines = vic.pending_text_lines; vic.raster.display_ystop = (vic.raster.display_ystart + vic.text_lines * vic.char_height); vic.raster.geometry->gfx_size.height = vic.pending_text_lines * 8; vic.raster.geometry->text_size.height = vic.pending_text_lines; vic.pending_text_lines = -1; } vic.raster.blank = 0; vic.light_pen.triggered = 0; } /* Set the next draw event. */ vic.last_emulate_line_clk += vic.cycles_per_line; vic.draw_clk = vic.last_emulate_line_clk + vic.cycles_per_line; alarm_set(vic.raster_draw_alarm, vic.draw_clk); }