src/mess/video/super80.c
| r0 | r4352 | |
| 1 | /* Super80.c written by Robbbert, 2005-2009. See the MESS wiki for documentation. */
|
| 2 | |
| 3 | #include "driver.h"
|
| 4 | #include "super80.h"
|
| 5 | |
| 6 | |
| 7 | static UINT16 vidpg=0xfe00; /* Home position of video page being displayed */
|
| 8 | |
| 9 | static UINT8 current_palette; /* for super80m and super80v */
|
| 10 | static UINT8 current_charset; /* for super80m */
|
| 11 | |
| 12 | static UINT8 mc6845_cursor[16]; // cursor shape
|
| 13 | static UINT8 mc6845_reg[20]; /* registers */
|
| 14 | static UINT8 mc6845_ind; /* register index */
|
| 15 | static const UINT8 mc6845_mask[]={0xff,0xff,0xff,0x0f,0x7f,0x1f,0x7f,0x7f,3,0x1f,0x7f,0x1f,0x3f,0xff,0x3f,0xff,0,0};
|
| 16 | |
| 17 | /**************************** PALETTES for super80m and super80v ******************************************/
|
| 18 | |
| 19 | static const UINT8 super80_rgb_palette[16*3] =
|
| 20 | {
|
| 21 | 0x00, 0x00, 0x00, /* 0 Black */
|
| 22 | 0x00, 0x00, 0x00, /* 1 Black */
|
| 23 | 0x00, 0x00, 0x7f, /* 2 Blue */
|
| 24 | 0x00, 0x00, 0xff, /* 3 Light Blue */
|
| 25 | 0x00, 0x7f, 0x00, /* 4 Green */
|
| 26 | 0x00, 0xff, 0x00, /* 5 Bright Green */
|
| 27 | 0x00, 0x7f, 0x7f, /* 6 Cyan */
|
| 28 | 0x00, 0xff, 0xff, /* 7 Turquoise */
|
| 29 | 0x7f, 0x00, 0x00, /* 8 Dark Red */
|
| 30 | 0xff, 0x00, 0x00, /* 9 Red */
|
| 31 | 0x7f, 0x00, 0x7f, /* 10 Purple */
|
| 32 | 0xff, 0x00, 0xff, /* 11 Magenta */
|
| 33 | 0x7f, 0x7f, 0x00, /* 12 Lime */
|
| 34 | 0xff, 0xff, 0x00, /* 13 Yellow */
|
| 35 | 0xbf, 0xbf, 0xbf, /* 14 Off White */
|
| 36 | 0xff, 0xff, 0xff, /* 15 White */
|
| 37 | };
|
| 38 | |
| 39 | static const UINT8 super80_comp_palette[16*3] =
|
| 40 | {
|
| 41 | 0x00, 0x00, 0x00, /* 0 Black */
|
| 42 | 0x80, 0x80, 0x80, /* 1 Grey */
|
| 43 | 0x00, 0x00, 0xff, /* 2 Blue */
|
| 44 | 0xff, 0xff, 0x80, /* 3 Light Yellow */
|
| 45 | 0x00, 0xff, 0x00, /* 4 Green */
|
| 46 | 0xff, 0x80, 0xff, /* 5 Light Magenta */
|
| 47 | 0x00, 0xff, 0xff, /* 6 Cyan */
|
| 48 | 0xff, 0x40, 0x40, /* 7 Light Red */
|
| 49 | 0xff, 0x00, 0x00, /* 8 Red */
|
| 50 | 0x00, 0x80, 0x80, /* 9 Dark Cyan */
|
| 51 | 0xff, 0x00, 0xff, /* 10 Magenta */
|
| 52 | 0x80, 0xff, 0x80, /* 11 Light Green */
|
| 53 | 0xff, 0xff, 0x00, /* 12 Yellow */
|
| 54 | 0x00, 0x00, 0x80, /* 13 Dark Blue */
|
| 55 | 0xff, 0xff, 0xff, /* 14 White */
|
| 56 | 0x00, 0x00, 0x00, /* 15 Black */
|
| 57 | };
|
| 58 | |
| 59 | static void palette_set_colors_rgb(running_machine *machine, const UINT8 *colors)
|
| 60 | {
|
| 61 | UINT8 r, b, g, color_count = 16;
|
| 62 | |
| 63 | while (color_count--)
|
| 64 | {
|
| 65 | r = *colors++; g = *colors++; b = *colors++;
|
| 66 | colortable_palette_set_color(machine->colortable, 15 - color_count, MAKE_RGB(r, g, b));
|
| 67 | }
|
| 68 | }
|
| 69 | |
| 70 | PALETTE_INIT( super80m )
|
| 71 | {
|
| 72 | int i;
|
| 73 | machine->colortable = colortable_alloc(machine, 16);
|
| 74 | palette_set_colors_rgb(machine, super80_rgb_palette);
|
| 75 | |
| 76 | for( i = 0; i < 256; i++ )
|
| 77 | {
|
| 78 | colortable_entry_set_value(machine->colortable, i*2, i>>4);
|
| 79 | colortable_entry_set_value(machine->colortable, i*2+1, i&15);
|
| 80 | }
|
| 81 | }
|
| 82 | |
| 83 | |
| 84 | /**************************** VIDEO *****************************************************************/
|
| 85 | /* the following are for super80v */
|
| 86 | READ8_HANDLER( super80v_low_r )
|
| 87 | {
|
| 88 | if (!super80v_vid_col)
|
| 89 | return colorram[offset];
|
| 90 | else
|
| 91 | return videoram[offset];
|
| 92 | }
|
| 93 | |
| 94 | WRITE8_HANDLER( super80v_low_w )
|
| 95 | {
|
| 96 | if (!super80v_vid_col)
|
| 97 | colorram[offset] = data;
|
| 98 | else
|
| 99 | videoram[offset] = data;
|
| 100 | }
|
| 101 | |
| 102 | READ8_HANDLER( super80v_high_r )
|
| 103 | {
|
| 104 | if (!super80v_vid_col)
|
| 105 | return colorram[0x800+offset];
|
| 106 | |
| 107 | if (!super80v_rom_pcg)
|
| 108 | return pcgram[offset];
|
| 109 | else
|
| 110 | return pcgram[0x800+offset];
|
| 111 | }
|
| 112 | |
| 113 | WRITE8_HANDLER( super80v_high_w )
|
| 114 | {
|
| 115 | if (!super80v_vid_col)
|
| 116 | colorram[offset+0x800] = data;
|
| 117 | else
|
| 118 | {
|
| 119 | videoram[offset+0x800] = data;
|
| 120 | |
| 121 | if (super80v_rom_pcg)
|
| 122 | {
|
| 123 | int chr = 0x80 + (offset>>4);
|
| 124 | pcgram[0x800+offset] = data;
|
| 125 | |
| 126 | /* decode character graphics again */
|
| 127 | gfx_element_mark_dirty(space->machine->gfx[0], chr);
|
| 128 | }
|
| 129 | }
|
| 130 | }
|
| 131 | |
| 132 | /* The 6845 can produce a variety of cursor shapes - all are emulated here */
|
| 133 | static void mc6845_cursor_configure(void)
|
| 134 | {
|
| 135 | UINT8 i,curs_type=0,r9,r10,r11;
|
| 136 | |
| 137 | /* curs_type holds the general cursor shape to be created
|
| 138 | 0 = no cursor
|
| 139 | 1 = partial cursor (only shows on a block of scan lines)
|
| 140 | 2 = full cursor
|
| 141 | 3 = two-part cursor (has a part at the top and bottom with the middle blank) */
|
| 142 | |
| 143 | for ( i = 0; i < ARRAY_LENGTH(mc6845_cursor); i++) mc6845_cursor[i] = 0; // prepare cursor by erasing old one
|
| 144 | |
| 145 | r9 = mc6845_reg[9]; // number of scan lines - 1
|
| 146 | r10 = mc6845_reg[10] & 0x1f; // cursor start line = last 5 bits
|
| 147 | r11 = mc6845_reg[11]+1; // cursor end line incremented to suit for-loops below
|
| 148 | |
| 149 | /* decide the curs_type by examining the registers */
|
| 150 | if (r10 < r11) curs_type=1; // start less than end, show start to end
|
| 151 | else
|
| 152 | if (r10 == r11) curs_type=2; // if equal, show full cursor
|
| 153 | else curs_type=3; // if start greater than end, it's a two-part cursor
|
| 154 | |
| 155 | if ((r11 - 1) > r9) curs_type=2; // if end greater than scan-lines, show full cursor
|
| 156 | if (r10 > r9) curs_type=0; // if start greater than scan-lines, then no cursor
|
| 157 | if (r11 > 16) r11=16; // truncate 5-bit register to fit our 4-bit hardware
|
| 158 | |
| 159 | /* create the new cursor */
|
| 160 | if (curs_type > 1) for (i = 0;i < ARRAY_LENGTH(mc6845_cursor);i++) mc6845_cursor[i]=0xff; // turn on full cursor
|
| 161 | |
| 162 | if (curs_type == 1) for (i = r10;i < r11;i++) mc6845_cursor[i]=0xff; // for each line that should show, turn on that scan line
|
| 163 | |
| 164 | if (curs_type == 3) for (i = r11; i < r10;i++) mc6845_cursor[i]=0; // now take a bite out of the middle
|
| 165 | }
|
| 166 | |
| 167 | /* Resize the screen within the limits of the hardware. Expand the image to fill the screen area */
|
| 168 | static void mc6845_screen_configure(running_machine *machine)
|
| 169 | {
|
| 170 | rectangle visarea;
|
| 171 | |
| 172 | UINT16 width = mc6845_reg[1]*7-1; // width in pixels
|
| 173 | UINT16 height = mc6845_reg[6]*(mc6845_reg[9]+1)-1; // height in pixels
|
| 174 | UINT16 bytes = mc6845_reg[1]*mc6845_reg[6]-1; // video ram needed -1
|
| 175 | |
| 176 | /* Resize the screen */
|
| 177 | visarea.min_x = 0;
|
| 178 | visarea.max_x = width-1;
|
| 179 | visarea.min_y = 0;
|
| 180 | visarea.max_y = height-1;
|
| 181 | if ((width < 610) && (height < 460) && (bytes < 0x1000)) /* bounds checking to prevent an assert or violation */
|
| 182 | video_screen_set_visarea(machine->primary_screen, 0, width, 0, height);
|
| 183 | }
|
| 184 | |
| 185 | VIDEO_EOF( super80m )
|
| 186 | {
|
| 187 | /* if we chose another palette or colour mode, enable it */
|
| 188 | UINT8 chosen_palette = (input_port_read(machine, "CONFIG") & 0x60)>>5; // read colour dipswitches
|
| 189 | |
| 190 | if (chosen_palette != current_palette) // any changes?
|
| 191 | {
|
| 192 | current_palette = chosen_palette; // save new palette
|
| 193 | if (!current_palette)
|
| 194 | palette_set_colors_rgb(machine, super80_comp_palette); // composite colour
|
| 195 | else
|
| 196 | palette_set_colors_rgb(machine, super80_rgb_palette); // rgb and b&w
|
| 197 | }
|
| 198 | }
|
| 199 | |
| 200 | VIDEO_UPDATE( super80 )
|
| 201 | {
|
| 202 | UINT8 x, y, code=32, screen_on=0;
|
| 203 | UINT8 mask = screen->machine->gfx[0]->total_elements - 1; /* 0x3F for super80; 0xFF for super80d & super80e */
|
| 204 | |
| 205 | if ((super80_mhz == 1) || (!(input_port_read(screen->machine, "CONFIG") & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */
|
| 206 | screen_on++;
|
| 207 | |
| 208 | /* display the picture */
|
| 209 | for (y=0; y<16; y++)
|
| 210 | {
|
| 211 | for (x=0; x<32; x++)
|
| 212 | {
|
| 213 | if (screen_on)
|
| 214 | code = memory_read_byte(cputag_get_address_space(screen->machine,"maincpu",ADDRESS_SPACE_PROGRAM), vidpg | x | (y<<5));
|
| 215 | |
| 216 | drawgfx(bitmap, screen->machine->gfx[0], code & mask, 0, 0, 0, x*8, y*10,
|
| 217 | cliprect, TRANSPARENCY_NONE, 0);
|
| 218 | }
|
| 219 | }
|
| 220 | |
| 221 | return 0;
|
| 222 | }
|
| 223 | |
| 224 | VIDEO_UPDATE( super80m )
|
| 225 | {
|
| 226 | UINT8 x, y, code=32, col=0, screen_on=0, options=input_port_read(screen->machine, "CONFIG");
|
| 227 | |
| 228 | /* get selected character generator */
|
| 229 | UINT8 cgen = current_charset ^ ((options & 0x10)>>4); /* bit 0 of port F1 and cgen config switch */
|
| 230 | |
| 231 | if ((super80_mhz == 1) || (!(options & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */
|
| 232 | screen_on++;
|
| 233 | |
| 234 | if (screen_on)
|
| 235 | {
|
| 236 | if ((options & 0x60) == 0x60)
|
| 237 | col = 15; /* b&w */
|
| 238 | else
|
| 239 | col = 5; /* green */
|
| 240 | }
|
| 241 | |
| 242 | /* display the picture */
|
| 243 | for (y=0; y<16; y++)
|
| 244 | {
|
| 245 | for (x=0; x<32; x++)
|
| 246 | {
|
| 247 | if (screen_on)
|
| 248 | {
|
| 249 | code = memory_read_byte(cputag_get_address_space(screen->machine,"maincpu",ADDRESS_SPACE_PROGRAM), vidpg | x | (y<<5)); /* get character to display */
|
| 250 | |
| 251 | if (!(options & 0x40)) col = memory_read_byte(cputag_get_address_space(screen->machine,"maincpu",ADDRESS_SPACE_PROGRAM), 0xfe00 | x | (y<<5)); /* byte of colour to display */
|
| 252 | }
|
| 253 | |
| 254 | drawgfx(bitmap, screen->machine->gfx[cgen], code, col, 0, 0, x*8, y*10,
|
| 255 | cliprect, TRANSPARENCY_NONE, 0);
|
| 256 | }
|
| 257 | }
|
| 258 | |
| 259 | return 0;
|
| 260 | }
|
| 261 | |
| 262 | VIDEO_UPDATE( super80v )
|
| 263 | {
|
| 264 | static UINT8 framecnt=0;
|
| 265 | UINT16 i, bytes = mc6845_reg[1]*mc6845_reg[6];
|
| 266 | UINT8 speed = mc6845_reg[10]&0x20, flash = mc6845_reg[10]&0x40; // cursor modes
|
| 267 | UINT16 cursor = (mc6845_reg[14]<<8) | mc6845_reg[15]; // get cursor position
|
| 268 | UINT16 screen_home = (mc6845_reg[12]<<8) | mc6845_reg[13]; // screen home offset (usually zero)
|
| 269 | UINT8 options=input_port_read(screen->machine, "CONFIG");
|
| 270 | framecnt++;
|
| 271 | |
| 272 | /* Get the graphics of the character under the cursor, xor with the visible cursor scan lines,
|
| 273 | and store as character number 256. If inverse mode, drop bit 7 of character before xoring */
|
| 274 | if (!super80v_rom_pcg)
|
| 275 | for ( i = 0; i < ARRAY_LENGTH(mc6845_cursor); i++)
|
| 276 | pcgram[0x1000+i] = pcgram[(videoram[cursor]&0x7f)*16+i] ^ mc6845_cursor[i];
|
| 277 | else
|
| 278 | for ( i = 0; i < ARRAY_LENGTH(mc6845_cursor); i++)
|
| 279 | pcgram[0x1000+i] = pcgram[(videoram[cursor])*16 + i] ^ mc6845_cursor[i];
|
| 280 | |
| 281 | gfx_element_mark_dirty(screen->machine->gfx[0],256); // and into machine graphics
|
| 282 | |
| 283 | for( i = 0; i < bytes; i++ )
|
| 284 | {
|
| 285 | int mem = (i + screen_home) & 0xfff;
|
| 286 | int sy = (i / mc6845_reg[1]) * (mc6845_reg[9] + 1);
|
| 287 | int sx = (i % mc6845_reg[1]) * 7;
|
| 288 | int chr = videoram[mem];
|
| 289 | |
| 290 | /* get colour or b&w */
|
| 291 | int col = 5; /* green */
|
| 292 | if ((options & 0x60) == 0x60) col = 15; /* b&w */
|
| 293 | if (!(options & 0x40)) col = colorram[mem]; // read a byte of colour
|
| 294 | |
| 295 | if ((!super80v_rom_pcg) && (chr > 0x7f)) // is it a high chr in inverse mode
|
| 296 | {
|
| 297 | col = BITSWAP8(col,3,2,1,0,7,6,5,4); // swap nibbles
|
| 298 | chr &= 0x7f; // and drop bit 7
|
| 299 | }
|
| 300 | |
| 301 | /* if cursor is on and we are at cursor position, show it */
|
| 302 | /* NOTE: flash rates obtained from real hardware */
|
| 303 | |
| 304 | if ((((!flash) && (!speed)) || // (5,6)=(0,0) = cursor on always
|
| 305 | ((flash) && (speed) && (framecnt & 0x10)) || // (5,6)=(1,1) = cycle per 32 frames
|
| 306 | ((flash) && (!speed) && (framecnt & 8))) && // (5,6)=(0,1) = cycle per 16 frames
|
| 307 | (i == cursor)) // displaying at cursor position?
|
| 308 | chr = 256; // 256 = cursor character
|
| 309 | |
| 310 | drawgfx( bitmap, screen->machine->gfx[0],chr,col,0,0,sx,sy,
|
| 311 | cliprect,TRANSPARENCY_NONE,0); // put character on the screen
|
| 312 | |
| 313 | }
|
| 314 | |
| 315 | return 0;
|
| 316 | }
|
| 317 | |
| 318 | /**************************** I/O PORTS *****************************************************************/
|
| 319 | |
| 320 | READ8_HANDLER( super80v_11_r )
|
| 321 | {
|
| 322 | if ((mc6845_ind > 13) && (mc6845_ind < 18)) /* determine readable registers */
|
| 323 | return mc6845_reg[mc6845_ind];
|
| 324 | else
|
| 325 | return 0;
|
| 326 | }
|
| 327 | |
| 328 | WRITE8_HANDLER( super80v_10_w )
|
| 329 | {
|
| 330 | if (data < 18) mc6845_ind = data; else mc6845_ind = 19; /* make sure if you try using an invalid register your write will go nowhere */
|
| 331 | }
|
| 332 | |
| 333 | WRITE8_HANDLER( super80v_11_w )
|
| 334 | {
|
| 335 | if (mc6845_ind < 16) mc6845_reg[mc6845_ind] = data & mc6845_mask[mc6845_ind]; /* save data in register */
|
| 336 | if ((mc6845_ind == 1) || (mc6845_ind == 6) || (mc6845_ind == 9)) mc6845_screen_configure(space->machine); /* adjust screen size */
|
| 337 | if ((mc6845_ind > 8) && (mc6845_ind < 12)) mc6845_cursor_configure(); /* adjust cursor shape */
|
| 338 | }
|
| 339 | |
| 340 | WRITE8_HANDLER( super80_f1_w )
|
| 341 | {
|
| 342 | vidpg = (data & 0xfe) << 8;
|
| 343 | current_charset = data & 1;
|
| 344 | }
|
| 345 | |
src/mess/drivers/super80.c
| r4351 | r4352 | |
| 1 | | /* Super80.c written by Robbbert, 2005-2008. See the MESS wiki for documentation. */ |
| 1 | /* Super80.c written by Robbbert, 2005-2009. See the MESS wiki for documentation. */ |
| 2 | 2 | |
| 3 | 3 | #include "driver.h" |
| 4 | 4 | #include "cpu/z80/z80.h" |
| r4351 | r4352 | |
| 11 | 11 | #include "devices/z80bin.h" |
| 12 | 12 | #include "sound/speaker.h" |
| 13 | 13 | #include "machine/ctronics.h" |
| 14 | #include "super80.h" |
| 14 | 15 | |
| 15 | 16 | |
| 16 | | static UINT8 super80_mhz=2; /* state of bit 2 of port F0 */ |
| 17 | | static UINT16 vidpg=0xfe00; /* Home position of video page being displayed */ |
| 18 | | static UINT8 int_sw; /* internal 1 MHz flipflop */ |
| 19 | | |
| 20 | | static UINT8 current_palette; /* for super80m and super80v */ |
| 21 | | static UINT8 current_charset; /* for super80m */ |
| 22 | 17 | static UINT8 irq_counter; |
| 23 | 18 | |
| 24 | 19 | static const device_config *super80_z80pio; |
| r4351 | r4352 | |
| 26 | 21 | static const device_config *super80_cassette; |
| 27 | 22 | static const device_config *super80_printer; |
| 28 | 23 | |
| 29 | | /* the rest are for super80v */ |
| 30 | | static UINT8 *pcgram; |
| 31 | | static UINT8 framecnt = 0; |
| 32 | | static UINT8 super80v_vid_col=1; // 0 = color ram ; 1 = video ram |
| 33 | | static UINT8 super80v_rom_pcg=1; // 0 = prom ; 1 = pcg |
| 34 | | static UINT8 mc6845_cursor[16]; // cursor shape |
| 35 | | static UINT8 mc6845_reg[20]; /* registers */ |
| 36 | | static UINT8 mc6845_ind; /* register index */ |
| 37 | | static const UINT8 mc6845_mask[]={0xff,0xff,0xff,0x0f,0x7f,0x1f,0x7f,0x7f,3,0x1f,0x7f,0x1f,0x3f,0xff,0x3f,0xff,0,0}; |
| 24 | UINT8 *pcgram; |
| 25 | UINT8 super80v_vid_col=1; // 0 = color ram ; 1 = video ram |
| 26 | UINT8 super80v_rom_pcg=1; // 0 = prom ; 1 = pcg |
| 27 | UINT8 super80_mhz=2; /* state of bit 2 of port F0 */ |
| 38 | 28 | |
| 39 | 29 | #define MASTER_CLOCK (XTAL_12MHz) |
| 40 | 30 | #define PIXEL_CLOCK (MASTER_CLOCK/2) |
| r4351 | r4352 | |
| 48 | 38 | #define SUPER80V_SCREEN_WIDTH (560) |
| 49 | 39 | #define SUPER80V_SCREEN_HEIGHT (300) |
| 50 | 40 | |
| 51 | | /**************************** PALETTES for super80m and super80v ******************************************/ |
| 52 | 41 | |
| 53 | | static const UINT8 super80_rgb_palette[16*3] = |
| 54 | | { |
| 55 | | 0x00, 0x00, 0x00, /* 0 Black */ |
| 56 | | 0x00, 0x00, 0x00, /* 1 Black */ |
| 57 | | 0x00, 0x00, 0x7f, /* 2 Blue */ |
| 58 | | 0x00, 0x00, 0xff, /* 3 Light Blue */ |
| 59 | | 0x00, 0x7f, 0x00, /* 4 Green */ |
| 60 | | 0x00, 0xff, 0x00, /* 5 Bright Green */ |
| 61 | | 0x00, 0x7f, 0x7f, /* 6 Cyan */ |
| 62 | | 0x00, 0xff, 0xff, /* 7 Turquoise */ |
| 63 | | 0x7f, 0x00, 0x00, /* 8 Dark Red */ |
| 64 | | 0xff, 0x00, 0x00, /* 9 Red */ |
| 65 | | 0x7f, 0x00, 0x7f, /* 10 Purple */ |
| 66 | | 0xff, 0x00, 0xff, /* 11 Magenta */ |
| 67 | | 0x7f, 0x7f, 0x00, /* 12 Lime */ |
| 68 | | 0xff, 0xff, 0x00, /* 13 Yellow */ |
| 69 | | 0xbf, 0xbf, 0xbf, /* 14 Off White */ |
| 70 | | 0xff, 0xff, 0xff, /* 15 White */ |
| 71 | | }; |
| 72 | | |
| 73 | | static const UINT8 super80_comp_palette[16*3] = |
| 74 | | { |
| 75 | | 0x00, 0x00, 0x00, /* 0 Black */ |
| 76 | | 0x80, 0x80, 0x80, /* 1 Grey */ |
| 77 | | 0x00, 0x00, 0xff, /* 2 Blue */ |
| 78 | | 0xff, 0xff, 0x80, /* 3 Light Yellow */ |
| 79 | | 0x00, 0xff, 0x00, /* 4 Green */ |
| 80 | | 0xff, 0x80, 0xff, /* 5 Light Magenta */ |
| 81 | | 0x00, 0xff, 0xff, /* 6 Cyan */ |
| 82 | | 0xff, 0x40, 0x40, /* 7 Light Red */ |
| 83 | | 0xff, 0x00, 0x00, /* 8 Red */ |
| 84 | | 0x00, 0x80, 0x80, /* 9 Dark Cyan */ |
| 85 | | 0xff, 0x00, 0xff, /* 10 Magenta */ |
| 86 | | 0x80, 0xff, 0x80, /* 11 Light Green */ |
| 87 | | 0xff, 0xff, 0x00, /* 12 Yellow */ |
| 88 | | 0x00, 0x00, 0x80, /* 13 Dark Blue */ |
| 89 | | 0xff, 0xff, 0xff, /* 14 White */ |
| 90 | | 0x00, 0x00, 0x00, /* 15 Black */ |
| 91 | | }; |
| 92 | | |
| 93 | | static void palette_set_colors_rgb(running_machine *machine, const UINT8 *colors) |
| 94 | | { |
| 95 | | UINT8 r, b, g, color_count = 16; |
| 96 | | |
| 97 | | while (color_count--) |
| 98 | | { |
| 99 | | r = *colors++; g = *colors++; b = *colors++; |
| 100 | | colortable_palette_set_color(machine->colortable, 15 - color_count, MAKE_RGB(r, g, b)); |
| 101 | | } |
| 102 | | } |
| 103 | | |
| 104 | | static PALETTE_INIT( super80m ) |
| 105 | | { |
| 106 | | int i; |
| 107 | | machine->colortable = colortable_alloc(machine, 16); |
| 108 | | palette_set_colors_rgb(machine, super80_rgb_palette); |
| 109 | | |
| 110 | | for( i = 0; i < 256; i++ ) |
| 111 | | { |
| 112 | | colortable_entry_set_value(machine->colortable, i*2, i>>4); |
| 113 | | colortable_entry_set_value(machine->colortable, i*2+1, i&15); |
| 114 | | } |
| 115 | | } |
| 116 | | |
| 117 | | |
| 118 | | /**************************** VIDEO *****************************************************************/ |
| 119 | | /* the following are for super80v */ |
| 120 | | static READ8_HANDLER( super80v_low_r ) |
| 121 | | { |
| 122 | | if (!super80v_vid_col) |
| 123 | | return colorram[offset]; |
| 124 | | else |
| 125 | | return videoram[offset]; |
| 126 | | } |
| 127 | | |
| 128 | | static WRITE8_HANDLER( super80v_low_w ) |
| 129 | | { |
| 130 | | if (!super80v_vid_col) |
| 131 | | colorram[offset] = data; |
| 132 | | else |
| 133 | | videoram[offset] = data; |
| 134 | | } |
| 135 | | |
| 136 | | static READ8_HANDLER( super80v_high_r ) |
| 137 | | { |
| 138 | | if (!super80v_vid_col) |
| 139 | | return colorram[0x800+offset]; |
| 140 | | |
| 141 | | if (!super80v_rom_pcg) |
| 142 | | return pcgram[offset]; |
| 143 | | else |
| 144 | | return pcgram[0x800+offset]; |
| 145 | | } |
| 146 | | |
| 147 | | static WRITE8_HANDLER( super80v_high_w ) |
| 148 | | { |
| 149 | | if (!super80v_vid_col) |
| 150 | | colorram[offset+0x800] = data; |
| 151 | | else |
| 152 | | { |
| 153 | | videoram[offset+0x800] = data; |
| 154 | | |
| 155 | | if (super80v_rom_pcg) |
| 156 | | { |
| 157 | | int chr = 0x80 + (offset>>4); |
| 158 | | pcgram[0x800+offset] = data; |
| 159 | | |
| 160 | | /* decode character graphics again */ |
| 161 | | gfx_element_mark_dirty(space->machine->gfx[0], chr); |
| 162 | | } |
| 163 | | } |
| 164 | | } |
| 165 | | |
| 166 | | /* The 6845 can produce a variety of cursor shapes - all are emulated here */ |
| 167 | | static void mc6845_cursor_configure(void) |
| 168 | | { |
| 169 | | UINT8 i,curs_type=0,r9,r10,r11; |
| 170 | | |
| 171 | | /* curs_type holds the general cursor shape to be created |
| 172 | | 0 = no cursor |
| 173 | | 1 = partial cursor (only shows on a block of scan lines) |
| 174 | | 2 = full cursor |
| 175 | | 3 = two-part cursor (has a part at the top and bottom with the middle blank) */ |
| 176 | | |
| 177 | | for ( i = 0; i < ARRAY_LENGTH(mc6845_cursor); i++) mc6845_cursor[i] = 0; // prepare cursor by erasing old one |
| 178 | | |
| 179 | | r9 = mc6845_reg[9]; // number of scan lines - 1 |
| 180 | | r10 = mc6845_reg[10] & 0x1f; // cursor start line = last 5 bits |
| 181 | | r11 = mc6845_reg[11]+1; // cursor end line incremented to suit for-loops below |
| 182 | | |
| 183 | | /* decide the curs_type by examining the registers */ |
| 184 | | if (r10 < r11) curs_type=1; // start less than end, show start to end |
| 185 | | else |
| 186 | | if (r10 == r11) curs_type=2; // if equal, show full cursor |
| 187 | | else curs_type=3; // if start greater than end, it's a two-part cursor |
| 188 | | |
| 189 | | if ((r11 - 1) > r9) curs_type=2; // if end greater than scan-lines, show full cursor |
| 190 | | if (r10 > r9) curs_type=0; // if start greater than scan-lines, then no cursor |
| 191 | | if (r11 > 16) r11=16; // truncate 5-bit register to fit our 4-bit hardware |
| 192 | | |
| 193 | | /* create the new cursor */ |
| 194 | | if (curs_type > 1) for (i = 0;i < ARRAY_LENGTH(mc6845_cursor);i++) mc6845_cursor[i]=0xff; // turn on full cursor |
| 195 | | |
| 196 | | if (curs_type == 1) for (i = r10;i < r11;i++) mc6845_cursor[i]=0xff; // for each line that should show, turn on that scan line |
| 197 | | |
| 198 | | if (curs_type == 3) for (i = r11; i < r10;i++) mc6845_cursor[i]=0; // now take a bite out of the middle |
| 199 | | } |
| 200 | | |
| 201 | | /* Resize the screen within the limits of the hardware. Expand the image to fill the screen area */ |
| 202 | | static void mc6845_screen_configure(running_machine *machine) |
| 203 | | { |
| 204 | | rectangle visarea; |
| 205 | | |
| 206 | | UINT16 width = mc6845_reg[1]*7-1; // width in pixels |
| 207 | | UINT16 height = mc6845_reg[6]*(mc6845_reg[9]+1)-1; // height in pixels |
| 208 | | UINT16 bytes = mc6845_reg[1]*mc6845_reg[6]-1; // video ram needed -1 |
| 209 | | |
| 210 | | /* Resize the screen */ |
| 211 | | visarea.min_x = 0; |
| 212 | | visarea.max_x = width-1; |
| 213 | | visarea.min_y = 0; |
| 214 | | visarea.max_y = height-1; |
| 215 | | if ((width < 610) && (height < 460) && (bytes < 0x1000)) /* bounds checking to prevent an assert or violation */ |
| 216 | | video_screen_set_visarea(machine->primary_screen, 0, width, 0, height); |
| 217 | | } |
| 218 | | |
| 219 | | static VIDEO_EOF( super80m ) |
| 220 | | { |
| 221 | | /* if we chose another palette or colour mode, enable it */ |
| 222 | | UINT8 chosen_palette = (input_port_read(machine, "CONFIG") & 0x60)>>5; // read colour dipswitches |
| 223 | | |
| 224 | | if (chosen_palette != current_palette) // any changes? |
| 225 | | { |
| 226 | | current_palette = chosen_palette; // save new palette |
| 227 | | if (!current_palette) |
| 228 | | palette_set_colors_rgb(machine, super80_comp_palette); // composite colour |
| 229 | | else |
| 230 | | palette_set_colors_rgb(machine, super80_rgb_palette); // rgb and b&w |
| 231 | | } |
| 232 | | } |
| 233 | | |
| 234 | | static VIDEO_UPDATE( super80 ) |
| 235 | | { |
| 236 | | UINT8 x, y, code=32, screen_on=0; |
| 237 | | UINT8 mask = screen->machine->gfx[0]->total_elements - 1; /* 0x3F for super80; 0xFF for super80d & super80e */ |
| 238 | | |
| 239 | | if ((super80_mhz == 1) || (!(input_port_read(screen->machine, "CONFIG") & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */ |
| 240 | | screen_on++; |
| 241 | | |
| 242 | | /* display the picture */ |
| 243 | | for (y=0; y<16; y++) |
| 244 | | { |
| 245 | | for (x=0; x<32; x++) |
| 246 | | { |
| 247 | | if (screen_on) |
| 248 | | code = memory_read_byte(cputag_get_address_space(screen->machine,"maincpu",ADDRESS_SPACE_PROGRAM), vidpg + x + (y<<5)); |
| 249 | | |
| 250 | | drawgfx(bitmap, screen->machine->gfx[0], code & mask, 0, 0, 0, x*8, y*10, |
| 251 | | cliprect, TRANSPARENCY_NONE, 0); |
| 252 | | } |
| 253 | | } |
| 254 | | |
| 255 | | return 0; |
| 256 | | } |
| 257 | | |
| 258 | | static VIDEO_UPDATE( super80m ) |
| 259 | | { |
| 260 | | UINT8 x, y, code=32, col=0, screen_on=0, options=input_port_read(screen->machine, "CONFIG"); |
| 261 | | |
| 262 | | /* get selected character generator */ |
| 263 | | UINT8 cgen = current_charset ^ ((options & 0x10)>>4); /* bit 0 of port F1 and cgen config switch */ |
| 264 | | |
| 265 | | if ((super80_mhz == 1) || (!(options & 4))) /* bit 2 of port F0 is high, OR user turned on config switch */ |
| 266 | | screen_on++; |
| 267 | | |
| 268 | | if (screen_on) |
| 269 | | { |
| 270 | | if ((options & 0x60) == 0x60) |
| 271 | | col = 15; /* b&w */ |
| 272 | | else |
| 273 | | col = 5; /* green */ |
| 274 | | } |
| 275 | | |
| 276 | | /* display the picture */ |
| 277 | | for (y=0; y<16; y++) |
| 278 | | { |
| 279 | | for (x=0; x<32; x++) |
| 280 | | { |
| 281 | | if (screen_on) |
| 282 | | { |
| 283 | | code = memory_read_byte(cputag_get_address_space(screen->machine,"maincpu",ADDRESS_SPACE_PROGRAM), vidpg + x + (y<<5)); /* get character to display */ |
| 284 | | |
| 285 | | if (!(options & 0x40)) col = memory_read_byte(cputag_get_address_space(screen->machine,"maincpu",ADDRESS_SPACE_PROGRAM), 0xfe00 + x + (y<<5)); /* byte of colour to display */ |
| 286 | | } |
| 287 | | |
| 288 | | drawgfx(bitmap, screen->machine->gfx[cgen], code, col, 0, 0, x*8, y*10, |
| 289 | | cliprect, TRANSPARENCY_NONE, 0); |
| 290 | | } |
| 291 | | } |
| 292 | | |
| 293 | | return 0; |
| 294 | | } |
| 295 | | |
| 296 | | static VIDEO_UPDATE( super80v ) |
| 297 | | { |
| 298 | | UINT16 i, bytes = mc6845_reg[1]*mc6845_reg[6]; |
| 299 | | UINT8 speed = mc6845_reg[10]&0x20, flash = mc6845_reg[10]&0x40; // cursor modes |
| 300 | | UINT16 cursor = (mc6845_reg[14]<<8) | mc6845_reg[15]; // get cursor position |
| 301 | | UINT16 screen_home = (mc6845_reg[12]<<8) | mc6845_reg[13]; // screen home offset (usually zero) |
| 302 | | UINT8 options=input_port_read(screen->machine, "CONFIG"); |
| 303 | | framecnt++; |
| 304 | | |
| 305 | | /* Get the graphics of the character under the cursor, xor with the visible cursor scan lines, |
| 306 | | and store as character number 256. If inverse mode, drop bit 7 of character before xoring */ |
| 307 | | if (!super80v_rom_pcg) |
| 308 | | for ( i = 0; i < ARRAY_LENGTH(mc6845_cursor); i++) |
| 309 | | pcgram[0x1000+i] = pcgram[(videoram[cursor]&0x7f)*16+i] ^ mc6845_cursor[i]; |
| 310 | | else |
| 311 | | for ( i = 0; i < ARRAY_LENGTH(mc6845_cursor); i++) |
| 312 | | pcgram[0x1000+i] = pcgram[(videoram[cursor])*16 + i] ^ mc6845_cursor[i]; |
| 313 | | |
| 314 | | gfx_element_mark_dirty(screen->machine->gfx[0],256); // and into machine graphics |
| 315 | | |
| 316 | | for( i = 0; i < bytes; i++ ) |
| 317 | | { |
| 318 | | int mem = (i + screen_home) & 0xfff; |
| 319 | | int sy = (i / mc6845_reg[1]) * (mc6845_reg[9] + 1); |
| 320 | | int sx = (i % mc6845_reg[1]) * 7; |
| 321 | | int chr = videoram[mem]; |
| 322 | | |
| 323 | | /* get colour or b&w */ |
| 324 | | int col = 5; /* green */ |
| 325 | | if ((options & 0x60) == 0x60) col = 15; /* b&w */ |
| 326 | | if (!(options & 0x40)) col = colorram[mem]; // read a byte of colour |
| 327 | | |
| 328 | | if ((!super80v_rom_pcg) && (chr > 0x7f)) // is it a high chr in inverse mode |
| 329 | | { |
| 330 | | col = BITSWAP8(col,3,2,1,0,7,6,5,4); // swap nibbles |
| 331 | | chr &= 0x7f; // and drop bit 7 |
| 332 | | } |
| 333 | | |
| 334 | | /* if cursor is on and we are at cursor position, show it */ |
| 335 | | /* NOTE: flash rates obtained from real hardware */ |
| 336 | | |
| 337 | | if ((((!flash) && (!speed)) || // (5,6)=(0,0) = cursor on always |
| 338 | | ((flash) && (speed) && (framecnt & 0x10)) || // (5,6)=(1,1) = cycle per 32 frames |
| 339 | | ((flash) && (!speed) && (framecnt & 8))) && // (5,6)=(0,1) = cycle per 16 frames |
| 340 | | (i == cursor)) // displaying at cursor position? |
| 341 | | chr = 256; // 256 = cursor character |
| 342 | | |
| 343 | | drawgfx( bitmap, screen->machine->gfx[0],chr,col,0,0,sx,sy, |
| 344 | | cliprect,TRANSPARENCY_NONE,0); // put character on the screen |
| 345 | | |
| 346 | | } |
| 347 | | |
| 348 | | return 0; |
| 349 | | } |
| 350 | | |
| 351 | 42 | /**************************** PIO ******************************************************************************/ |
| 352 | 43 | |
| 353 | 44 | static UINT8 keylatch; |
| r4351 | r4352 | |
| 463 | 154 | |
| 464 | 155 | /**************************** I/O PORTS *****************************************************************/ |
| 465 | 156 | |
| 466 | | static READ8_HANDLER( super80v_11_r ) |
| 467 | | { |
| 468 | | if ((mc6845_ind > 13) && (mc6845_ind < 18)) /* determine readable registers */ |
| 469 | | return mc6845_reg[mc6845_ind]; |
| 470 | | else |
| 471 | | return 0; |
| 472 | | } |
| 473 | | |
| 474 | 157 | static READ8_HANDLER( super80_dc_r ) |
| 475 | 158 | { |
| 476 | 159 | UINT8 data=0x7f; |
| r4351 | r4352 | |
| 491 | 174 | return data; |
| 492 | 175 | } |
| 493 | 176 | |
| 494 | | static WRITE8_HANDLER( super80v_10_w ) |
| 495 | | { |
| 496 | | if (data < 18) mc6845_ind = data; else mc6845_ind = 19; /* make sure if you try using an invalid register your write will go nowhere */ |
| 497 | | } |
| 498 | | |
| 499 | | static WRITE8_HANDLER( super80v_11_w ) |
| 500 | | { |
| 501 | | if (mc6845_ind < 16) mc6845_reg[mc6845_ind] = data & mc6845_mask[mc6845_ind]; /* save data in register */ |
| 502 | | if ((mc6845_ind == 1) || (mc6845_ind == 6) || (mc6845_ind == 9)) mc6845_screen_configure(space->machine); /* adjust screen size */ |
| 503 | | if ((mc6845_ind > 8) && (mc6845_ind < 12)) mc6845_cursor_configure(); /* adjust cursor shape */ |
| 504 | | } |
| 505 | | |
| 506 | 177 | static WRITE8_HANDLER( super80_dc_w ) |
| 507 | 178 | { |
| 508 | 179 | /* hardware strobe driven from port select, bit 7..0 = data */ |
| r4351 | r4352 | |
| 552 | 223 | last_data = data; |
| 553 | 224 | } |
| 554 | 225 | |
| 555 | | static WRITE8_HANDLER( super80_f1_w ) |
| 556 | | { |
| 557 | | vidpg = (data & 0xfe) << 8; |
| 558 | | current_charset = data & 1; |
| 559 | | } |
| 560 | | |
| 561 | 226 | static READ8_HANDLER( super80_f8_r ) { return z80pio_d_r (super80_z80pio,0); } |
| 562 | 227 | static READ8_HANDLER( super80_f9_r ) { return z80pio_c_r (super80_z80pio,0); } |
| 563 | 228 | static READ8_HANDLER( super80_fa_r ) { return z80pio_d_r (super80_z80pio,1); } |
| r4351 | r4352 | |
| 945 | 610 | |
| 946 | 611 | static TIMER_CALLBACK( super80_halfspeed ) |
| 947 | 612 | { |
| 613 | static UINT8 int_sw=0; |
| 948 | 614 | UINT8 go_fast = 0; |
| 949 | 615 | if ((super80_mhz == 2) || (!(input_port_read(machine, "CONFIG") & 2))) /* bit 2 of port F0 is low, OR user turned on config switch */ |
| 950 | 616 | go_fast++; |