1
/***************************************************************************
5
Functions to emulate the video hardware of the kc85/4,kc85/3
7
***************************************************************************/
10
#include "includes/kc.h"
11
#include "machine/ram.h"
13
/* KC85/4 and KC85/3 common graphics hardware */
15
static const unsigned short kc85_colour_table[KC85_PALETTE_SIZE] =
17
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
18
16, 17, 18, 19, 20, 21, 22, 23
24
"full" of each component
35
"full of each component + half of another component"
45
"half" of each component
58
static const unsigned char kc85_palette[KC85_PALETTE_SIZE * 3] =
60
/* 3 bit colour value. bit 2->green, bit 1->red, bit 0->blue */
62
/* foreground colours */
81
/* background colours are slightly darker than foreground colours */
94
/* Initialise the palette */
99
for ( i = 0; i < sizeof(kc85_palette) / 3; i++ ) {
100
palette_set_color_rgb(machine, i, kc85_palette[i*3], kc85_palette[i*3+1], kc85_palette[i*3+2]);
107
KC85_VIDEO_EVENT_SET_BLINK_STATE
110
/* set new blink state - record blink state in event list */
111
void kc85_video_set_blink_state(running_machine &machine, int data)
113
//spectrum_EventList_AddItemOffset(machine, KC85_VIDEO_EVENT_SET_BLINK_STATE, ((data & 0x01)<<7), machine.firstcpu->attotime_to_cycles(machine.primary_screen->scan_period() * machine.primary_screen->vpos()));
118
static void kc85_draw_8_pixels(kc_state *state, bitmap_t *bitmap,int x,int y, unsigned char colour_byte, unsigned char gfx_byte)
126
/* 16 foreground colours, 8 background colours */
128
/* bit 7 = 1: flash between foreground and background colour 0: no flash */
129
/* bit 6: adjusts foreground colours by adding half of another component */
130
/* bit 5,4,3 = foreground colour */
131
/* bit 5: background colour -> Green */
132
/* bit 4: background colour -> Red */
133
/* bit 3: background colour -> Blue */
134
/* bit 2,1,0 = background colour */
135
/* bit 2: background colour -> Green */
136
/* bit 1: background colour -> Red */
137
/* bit 0: background colour -> Blue */
138
background_pen = (colour_byte&7) + 16;
139
foreground_pen = ((colour_byte>>3) & 0x0f);
141
if (colour_byte & state->m_kc85_blink_state)
143
foreground_pen = background_pen;
146
pens[0] = background_pen;
147
pens[1] = foreground_pen;
155
pen = pens[(gfx_byte>>7) & 0x01];
157
if ((px >= 0) && (px < bitmap->width)
158
&& (y >= 0) && (y < bitmap->height))
160
*BITMAP_ADDR16(bitmap, y, px) = pen;
163
gfx_byte = gfx_byte<<1;
168
/* height of screen in lines */
169
#define KC85_SCREEN_HEIGHT 256
170
/* width of display in pixels */
171
#define KC85_SCREEN_WIDTH 320
172
/* height of top border in lines */
173
#define KC85_TOP_BORDER_SIZE 8
174
/* height of bottom border in lines */
175
#define KC85_BOTTOM_BORDER_SIZE 8
176
/* total number of lines in whole frame */
177
#define KC85_FRAME_NUM_LINES 312
178
/* width of whole line in pixels */
179
#define KC85_LINE_SIZE 512
180
/* width of left border in pixels */
181
#define KC85_LEFT_BORDER_SIZE 8
182
/* width of right border in pixels */
183
#define KC85_RIGHT_BORDER_SIZE 8
184
/* width of horizontal retrace in pixels */
185
#define KC85_RETRACE_SIZE (KC85_LINE_SIZE - KC85_LEFT_BORDER_SIZE - KC85_RIGHT_BORDER_SIZE - KC85_SCREEN_WIDTH)
186
/* number of lines in vertical retrace */
187
#define KC85_NUM_RETRACE_LINES (KC85_FRAME_NUM_LINES - KC85_TOP_BORDER_SIZE - KC85_BOTTOM_BORDER_SIZE - KC85_SCREEN_HEIGHT)
190
#define KC85_CYCLES_PER_FRAME 1750000.0f/50.0f
191
#define KC85_CYCLES_PER_LINE (KC85_CYCLES_PER_FRAME/KC85_FRAME_NUM_LINES)
192
#define KC85_CYCLES_PER_PIXEL (KC85_CYCLES_PER_LINE/KC85_LINE_SIZE)
196
- 1750000 cpu cycles per second
197
- 35000 cpu cycles per frame
198
- 35000/312 = 112.179 cycles per line
199
- 112.179/(512/8) = 1.752 cycles per 8-pixels
204
- Vertical and horizontal dimensions are split into states.
205
- Horizontal states take a multiple of horizontal cycles, and vertical states take a multiple of lines.
206
- The horizontal states comprise left border, main display, right border and horizontal retrace timing.
207
- The vertical states comprise top border, main display, bottom border and vertical retrace timing.
210
- if frame rate is 50Hz, and there are 312 lines, then the line rate is 15600Hz.
211
- Each frame takes 0.02 seconds, and each line takes 0.0000064 seconds - approx 64microseconds per line
213
- the event list is based on cpu time
217
static const int horizontal_next_state_table[]=
222
/* number of cycles for each state */
223
static const int horizontal_graphics_state_cycles[]=
226
(KC85_LEFT_BORDER_SIZE*KC85_CYCLES_PER_PIXEL),
228
(KC85_SCREEN_WIDTH*KC85_CYCLES_PER_PIXEL),
230
(KC85_RIGHT_BORDER_SIZE*KC85_CYCLES_PER_PIXEL),
231
/* horizontal retrace */
232
(KC85_RETRACE_SIZE*KC85_CYCLES_PER_PIXEL)
235
static const int vertical_next_state_table[]=
240
/* number of lines for each state */
241
static const int vertical_graphics_state_lines[]=
244
KC85_TOP_BORDER_SIZE*KC85_CYCLES_PER_LINE,
246
KC85_SCREEN_HEIGHT*KC85_CYCLES_PER_LINE,
248
KC85_BOTTOM_BORDER_SIZE*KC85_CYCLES_PER_LINE,
249
/* vertical retrace */
250
KC85_NUM_RETRACE_LINES*KC85_CYCLES_PER_LINE
257
/* number of cycles remaining in this state */
258
int cycles_remaining_in_state;
259
/* number of cycles remaining (starts at total of all states) */
260
int cycles_remaining;
265
unsigned char *pixel_ram;
266
unsigned char *colour_ram;
269
struct video_update_state
271
/* bitmap to render to */
273
/* grab colour and pixel information for 8-pixels referenced by x,y coordinate */
274
void (*pixel_grab_callback)(struct grab_info *,int x,int y, unsigned char *colour_ptr, unsigned char *pixel_ptr);
277
/* render coordinates */
278
int render_x,render_y;
280
struct video_state horizontal;
281
struct video_state vertical;
282
struct grab_info grab_data;
286
/* process visible cycles within a line */
287
/* the cycles will never span over the end of a line */
288
static void kc85_common_process_cycles(kc_state *state, struct video_update_state *video_update, int cycles)
294
/* do as many cycles up to end of current state */
295
cycles_to_do = MIN(video_update->horizontal.cycles_remaining_in_state, cycles);
297
//logerror("process cycles: cycles_to_do %d\n",cycles_to_do);
299
/* update screen based on current state */
300
switch (video_update->horizontal.state)
305
// video_update->render_x+=(cycles_to_do)*8;
314
for (i=0; i<cycles_to_do; i++)
316
unsigned char colour_byte;
317
unsigned char gfx_byte;
319
/* grab colour and pixel information */
320
video_update->pixel_grab_callback(&video_update->grab_data,video_update->x,video_update->y,&colour_byte, &gfx_byte);
322
kc85_draw_8_pixels(state, video_update->bitmap, video_update->render_x, video_update->render_y,colour_byte, gfx_byte);
323
/* update render coordinate */
324
video_update->render_x+=8;
327
if (video_update->x>=(320/8))
329
video_update->x = (320/8)-1;
332
if (video_update->render_x>=320)
334
video_update->render_x = 319;
345
// video_update->render_x+=(cycles_to_do)*8;
349
/* invisible/retrace */
358
video_update->horizontal.cycles_remaining_in_state -=cycles_to_do;
361
if (video_update->horizontal.cycles_remaining_in_state<=0)
364
video_update->horizontal.state = horizontal_next_state_table[video_update->horizontal.state];
365
video_update->horizontal.cycles_remaining_in_state+=horizontal_graphics_state_cycles[video_update->horizontal.state];
368
cycles-=cycles_to_do;
372
/* process a whole visible line */
373
static int kc85_common_vh_process_line(kc_state *state, struct video_update_state *video_update, int cycles)
377
/* do cycles in line */
378
while ((video_update->horizontal.cycles_remaining!=0) && (cycles!=0))
380
/* do as many cycles as will fit onto the line */
381
cycles_to_do = MIN(cycles,video_update->horizontal.cycles_remaining);
383
//logerror("process line: cycles_to_do: %d\n",cycles_to_do);
385
/* do the cycles - draw them */
386
kc85_common_process_cycles(state, video_update, cycles_to_do);
388
video_update->horizontal.cycles_remaining -= cycles_to_do;
389
cycles -=cycles_to_do;
394
if (video_update->horizontal.cycles_remaining==0)
397
video_update->horizontal.cycles_remaining+=KC85_CYCLES_PER_LINE;
398
/* update x,y fetch pos */
402
/* update x,y render pos */
403
video_update->render_x = 0;
404
video_update->render_y++;
406
if (video_update->y>=256)
408
video_update->y = 255;
411
if (video_update->render_y>=256)
413
video_update->render_y = 255;
419
/* cycles remaining */
423
static void kc85_common_vh_process_lines(kc_state *state, struct video_update_state *video_update, int cycles)
430
cycles_to_do = MIN(cycles, KC85_CYCLES_PER_LINE);
431
cycles_done = cycles_to_do;
433
//logerror("process lines: cycles_to_do: %d\n",cycles_to_do);
436
switch (video_update->vertical.state)
441
// cycles_done = cycles_to_do;
448
int cycles_remaining;
450
/* update cycles with number of cycles not processed */
451
cycles_remaining = kc85_common_vh_process_line(state, video_update, cycles_to_do);
453
cycles_done = cycles_to_do - cycles_remaining;
461
// cycles_done = cycles_to_do;
468
// cycles_done = cycles_to_do;
474
//logerror("cycles done: %d\n",cycles_done);
475
video_update->vertical.cycles_remaining_in_state -=cycles_done;
478
if (video_update->vertical.cycles_remaining_in_state<=0)
481
video_update->vertical.state = vertical_next_state_table[video_update->vertical.state];
482
video_update->vertical.cycles_remaining_in_state+=vertical_graphics_state_lines[video_update->vertical.state];
490
/* the kc85 screen is 320 pixels wide and 256 pixels tall */
491
/* if we assume a 50Hz display, there are 312 lines for the complete frame, leaving 56 lines not visible */
492
static void kc85_common_process_frame(running_machine &machine, bitmap_t *bitmap, void (*pixel_grab_callback)(struct grab_info *,int x,int y,unsigned char *, unsigned char *),struct grab_info *grab_data)
494
kc_state *state = machine.driver_data<kc_state>();
495
int cycles_remaining_in_frame = KC85_CYCLES_PER_FRAME;
497
// EVENT_LIST_ITEM *pItem;
500
struct video_update_state video_update;
501
// int cycles_offset = 0;
503
video_update.render_x = 0;
504
video_update.render_y = 0;
507
memcpy(&video_update.grab_data, grab_data, sizeof(struct grab_info));
508
video_update.bitmap = bitmap;
509
video_update.pixel_grab_callback = pixel_grab_callback;
510
video_update.horizontal.state = 0;
511
video_update.horizontal.cycles_remaining_in_state = horizontal_graphics_state_cycles[video_update.horizontal.state];
512
video_update.horizontal.cycles_remaining = KC85_CYCLES_PER_LINE;
513
video_update.vertical.state = 0;
514
video_update.vertical.cycles_remaining_in_state = vertical_graphics_state_lines[video_update.vertical.state];
515
video_update.vertical.cycles_remaining = KC85_CYCLES_PER_FRAME;
518
/* first item in list */
519
pItem = spectrum_EventList_GetFirstItem(machine);
520
/* number of items remaining */
521
NumItems = spectrum_EventList_NumEvents(machine);
527
/* number of cycles until event will trigger */
528
delta_cycles = pItem->Event_Time - cycles_offset;
530
//logerror("cycles between this event and next: %d\n",delta_cycles);
531
kc85_common_vh_process_lines(&video_update, delta_cycles);
533
/* update number of cycles remaining in frame */
534
cycles_remaining_in_frame -= delta_cycles;
535
/* set new blink state */
536
state->m_kc85_blink_state = pItem->Event_Data;
538
/* set new cycles into frame */
539
cycles_offset = pItem->Event_Time;
542
/* update number of events remaining */
547
/* process remainder */
548
kc85_common_vh_process_lines(state, &video_update, cycles_remaining_in_frame);
549
//spectrum_EventList_Reset(machine);
550
//spectrum_EventList_SetOffsetStartTime ( machine, machine.firstcpu->attotime_to_cycles(machine.primary_screen->scan_period() * machine.primary_screen->vpos()) );
555
/***************************************************************************
556
KC85/4 video hardware
557
***************************************************************************/
558
static void kc85_common_vh_start(running_machine &machine)
560
kc_state *state = machine.driver_data<kc_state>();
561
state->m_kc85_blink_state = 0;
562
//spectrum_EventList_Initialise(machine, 30000);
567
VIDEO_START( kc85_4 )
569
kc_state *state = machine.driver_data<kc_state>();
570
kc85_common_vh_start(machine);
572
state->m_kc85_4_video_ram = auto_alloc_array(machine, UINT8,
573
(KC85_4_SCREEN_COLOUR_RAM_SIZE*2) +
574
(KC85_4_SCREEN_PIXEL_RAM_SIZE*2));
576
state->m_kc85_4_display_video_ram = state->m_kc85_4_video_ram;
579
void kc85_4_video_ram_select_bank(running_machine &machine, int bank)
581
kc_state *state = machine.driver_data<kc_state>();
582
/* calculate address of video ram to display */
583
unsigned char *video_ram;
585
video_ram = state->m_kc85_4_video_ram;
590
(KC85_4_SCREEN_PIXEL_RAM_SIZE +
591
KC85_4_SCREEN_COLOUR_RAM_SIZE);
594
state->m_kc85_4_display_video_ram = video_ram;
597
unsigned char *kc85_4_get_video_ram_base(running_machine &machine, int bank, int colour)
599
kc_state *state = machine.driver_data<kc_state>();
600
/* base address: screen 0 pixel data */
601
unsigned char *addr = state->m_kc85_4_video_ram;
605
/* access screen 1 */
606
addr += KC85_4_SCREEN_PIXEL_RAM_SIZE +
607
KC85_4_SCREEN_COLOUR_RAM_SIZE;
612
/* access colour information of selected screen */
613
addr += KC85_4_SCREEN_PIXEL_RAM_SIZE;
619
static void kc85_4_pixel_grab_callback(struct grab_info *grab_data,int x,int y, unsigned char *colour, unsigned char *gfx)
623
offset = (y & 0xff) | ((x & 0x0ff)<<8);
625
*colour = grab_data->colour_ram[offset];
626
*gfx = grab_data->pixel_ram[offset];
631
/***************************************************************************
632
Draw the game screen in the given bitmap_t.
633
Do NOT call osd_update_display() from this function,
634
it will be called by the main emulation engine.
635
***************************************************************************/
636
SCREEN_UPDATE( kc85_4 )
638
kc_state *state = screen->machine().driver_data<kc_state>();
640
unsigned char *pixel_ram = state->m_kc85_4_display_video_ram;
641
unsigned char *colour_ram = pixel_ram + 0x04000;
645
for (y=0; y<KC85_SCREEN_HEIGHT; y++)
647
for (x=0; x<(KC85_SCREEN_WIDTH>>3); x++)
649
unsigned char colour_byte, gfx_byte;
654
colour_byte = colour_ram[offset];
655
gfx_byte = pixel_ram[offset];
657
kc85_draw_8_pixels(state, bitmap,(x<<3),y, colour_byte, gfx_byte);
662
struct grab_info grab_data;
664
grab_data.pixel_ram = state->m_kc85_4_display_video_ram;
665
grab_data.colour_ram = state->m_kc85_4_display_video_ram + 0x04000;
667
kc85_common_process_frame(screen->machine(), bitmap, kc85_4_pixel_grab_callback,&grab_data);
672
/***************************************************************************
674
***************************************************************************/
676
VIDEO_START( kc85_3 )
678
kc85_common_vh_start(machine);
682
static void kc85_3_pixel_grab_callback(struct grab_info *grab_data,int x,int y, unsigned char *colour, unsigned char *gfx)
684
int pixel_offset,colour_offset;
686
/* this has got to be speeded up!!! */
689
pixel_offset = (x & 0x01f) | (((y>>2) & 0x03)<<5) |
690
((y & 0x03)<<7) | (((y>>4) & 0x0f)<<9);
692
colour_offset = (x & 0x01f) | (((y>>2) & 0x03f)<<5);
696
/* 1 0 1 0 0 V7 V6 V1 V0 V3 V2 V5 V4 H2 H1 H0 */
697
/* 1 0 1 1 0 0 0 V7 V6 V3 V2 V5 V4 H2 H1 H0 */
699
pixel_offset = 0x02000+((x & 0x07) | (((y>>4) & 0x03)<<3) |
700
(((y>>2) & 0x03)<<5) | ((y & 0x03)<<7) | ((y>>6) & 0x03)<<9);
702
colour_offset = 0x0800+((x & 0x07) | (((y>>4) & 0x03)<<3) |
703
(((y>>2) & 0x03)<<5) | ((y>>6) & 0x03)<<7);
706
*colour = grab_data->colour_ram[colour_offset];
707
*gfx = grab_data->pixel_ram[pixel_offset];
711
/***************************************************************************
712
Draw the game screen in the given bitmap_t.
713
Do NOT call osd_update_display() from this function,
714
it will be called by the main emulation engine.
715
***************************************************************************/
716
SCREEN_UPDATE( kc85_3 )
719
/* colour ram takes up 0x02800 bytes */
720
unsigned char *pixel_ram = ram_get_ptr(machine.device(RAM_TAG))+0x08000;
721
unsigned char *colour_ram = pixel_ram + 0x02800;
725
for (y=0; y<KC85_SCREEN_HEIGHT; y++)
727
for (x=0; x<(KC85_SCREEN_WIDTH>>3); x++)
729
unsigned char colour_byte, gfx_byte;
730
int pixel_offset,colour_offset;
734
pixel_offset = (x & 0x01f) | (((y>>2) & 0x03)<<5) |
735
((y & 0x03)<<7) | (((y>>4) & 0x0f)<<9);
737
colour_offset = (x & 0x01f) | (((y>>2) & 0x03f)<<5);
741
/* 1 0 1 0 0 V7 V6 V1 V0 V3 V2 V5 V4 H2 H1 H0 */
742
/* 1 0 1 1 0 0 0 V7 V6 V3 V2 V5 V4 H2 H1 H0 */
744
pixel_offset = 0x02000+((x & 0x07) | (((y>>4) & 0x03)<<3) |
745
(((y>>2) & 0x03)<<5) | ((y & 0x03)<<7) | ((y>>6) & 0x03)<<9);
747
colour_offset = 0x0800+((x & 0x07) | (((y>>4) & 0x03)<<3) |
748
(((y>>2) & 0x03)<<5) | ((y>>6) & 0x03)<<7);
751
colour_byte = colour_ram[colour_offset];
752
gfx_byte = pixel_ram[pixel_offset];
754
kc85_draw_8_pixels(state, bitmap,(x<<3),y, colour_byte, gfx_byte);
759
struct grab_info grab_data;
761
grab_data.pixel_ram = ram_get_ptr(screen->machine().device(RAM_TAG))+0x08000;
762
grab_data.colour_ram = ram_get_ptr(screen->machine().device(RAM_TAG))+0x08000 + 0x02800;
764
kc85_common_process_frame(screen->machine(), bitmap, kc85_3_pixel_grab_callback,&grab_data);