src/mess/video/samcoupe.c
| r7628 | r7629 | |
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | |
| 3 | | SAM Coupe Driver - Written By Lee Hammerton |
| 3 | SAM Coupe |
| 4 | 4 | |
| 5 | | Functions to emulate the video hardware of the coupe. |
| 5 | Functions to emulate the video hardware |
| 6 | 6 | |
| 7 | | At present these are not done using the mame driver standard, they are |
| 8 | | simply plot pixelled.. I will fix this in a future version. |
| 9 | | |
| 10 | 7 | ***************************************************************************/ |
| 11 | 8 | |
| 12 | 9 | #include "emu.h" |
| 13 | 10 | #include "includes/samcoupe.h" |
| 14 | 11 | |
| 15 | 12 | |
| 13 | /*************************************************************************** |
| 14 | MACROS |
| 15 | ***************************************************************************/ |
| 16 | |
| 17 | /* border color from border register */ |
| 16 | 18 | #define BORDER_COLOR(x) ((x & 0x20) >> 2 | (x & 0x07)) |
| 17 | 19 | |
| 18 | | static void draw_left_border(running_device *screen, bitmap_t *bitmap, int y) |
| 19 | | { |
| 20 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 20 | /* foreground and background color from attribute byte in mode 1 and 2 */ |
| 21 | #define ATTR_BG(x) ((x >> 3) & 0x07) |
| 22 | #define ATTR_FG(x) (((x >> 3) & 0x08) | (x & 0x07)) |
| 21 | 23 | |
| 22 | | for (int x = 0; x < SAM_BORDER_LEFT; x++) |
| 23 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, x) = asic->clut[BORDER_COLOR(asic->border)]; |
| 24 | | } |
| 25 | 24 | |
| 26 | | static void draw_right_border(running_device *screen, bitmap_t *bitmap, int y) |
| 27 | | { |
| 28 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 25 | /*************************************************************************** |
| 26 | IMPLEMENTATION |
| 27 | ***************************************************************************/ |
| 29 | 28 | |
| 30 | | for (int x = SAM_BORDER_LEFT + SAM_SCREEN_WIDTH; x < SAM_BORDER_LEFT + SAM_SCREEN_WIDTH + SAM_BORDER_RIGHT; x++) |
| 31 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, x) = asic->clut[BORDER_COLOR(asic->border)]; |
| 32 | | } |
| 33 | | |
| 34 | | static void draw_mode4_line(running_device *screen, bitmap_t *bitmap, int y) |
| 29 | static void draw_mode4_line(running_machine *machine, int y, int hpos) |
| 35 | 30 | { |
| 36 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 31 | coupe_asic *asic = (coupe_asic *)machine->driver_data; |
| 37 | 32 | |
| 38 | 33 | /* get start address */ |
| 39 | | UINT8 *vram = screen->machine->generic.videoram.u8 + (y * 128); |
| 34 | UINT8 *vram = machine->generic.videoram.u8 + ((y - SAM_BORDER_TOP) * 128) + ((hpos - SAM_BORDER_LEFT) / 4); |
| 40 | 35 | |
| 41 | | for (int x = 0; x < SAM_SCREEN_WIDTH/4; x++) |
| 36 | for (int i = 0; i < (SAM_BLOCK*2)/4; i++) |
| 42 | 37 | { |
| 43 | 38 | /* draw 2 pixels (doublewidth) */ |
| 44 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 0) = asic->clut[(*vram >> 4) & 0x0f]; |
| 45 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 1) = asic->clut[(*vram >> 4) & 0x0f]; |
| 46 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 2) = asic->clut[(*vram >> 0) & 0x0f]; |
| 47 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 3) = asic->clut[(*vram >> 0) & 0x0f]; |
| 39 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 0) = asic->clut[(*vram >> 4) & 0x0f]; |
| 40 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 1) = asic->clut[(*vram >> 4) & 0x0f]; |
| 41 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 2) = asic->clut[(*vram >> 0) & 0x0f]; |
| 42 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 3) = asic->clut[(*vram >> 0) & 0x0f]; |
| 48 | 43 | |
| 49 | 44 | /* move to next address */ |
| 50 | 45 | vram++; |
| 46 | |
| 47 | /* attribute register contains the third displayed byte */ |
| 48 | if (i == 2) |
| 49 | asic->attribute = *vram; |
| 51 | 50 | } |
| 52 | 51 | } |
| 53 | 52 | |
| 54 | | static void draw_mode3_line(running_device *screen, bitmap_t *bitmap, int y) |
| 53 | static void draw_mode3_line(running_machine *machine, int y, int hpos) |
| 55 | 54 | { |
| 56 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 55 | coupe_asic *asic = (coupe_asic *)machine->driver_data; |
| 57 | 56 | |
| 58 | 57 | /* get start address */ |
| 59 | | UINT8 *vram = screen->machine->generic.videoram.u8 + (y * 128); |
| 58 | UINT8 *vram = machine->generic.videoram.u8 + ((y - SAM_BORDER_TOP) * 128) + ((hpos - SAM_BORDER_LEFT) / 4); |
| 60 | 59 | |
| 61 | | for (int x = 0; x < 512/4; x++) |
| 60 | for (int i = 0; i < (SAM_BLOCK*2)/4; i++) |
| 62 | 61 | { |
| 63 | 62 | /* draw 4 pixels */ |
| 64 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 0) = asic->clut[(*vram >> 6) & 0x03]; |
| 65 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 1) = asic->clut[(*vram >> 4) & 0x03]; |
| 66 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 2) = asic->clut[(*vram >> 2) & 0x03]; |
| 67 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x * 4 + 3) = asic->clut[(*vram >> 0) & 0x03]; |
| 63 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 0) = asic->clut[(*vram >> 6) & 0x03]; |
| 64 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 1) = asic->clut[(*vram >> 4) & 0x03]; |
| 65 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 2) = asic->clut[(*vram >> 2) & 0x03]; |
| 66 | *BITMAP_ADDR16(machine->generic.tmpbitmap, y, hpos + i * 4 + 3) = asic->clut[(*vram >> 0) & 0x03]; |
| 68 | 67 | |
| 69 | 68 | /* move to next address */ |
| 70 | 69 | vram++; |
| 70 | |
| 71 | /* attribute register contains the third displayed byte */ |
| 72 | if (i == 2) |
| 73 | asic->attribute = *vram; |
| 71 | 74 | } |
| 72 | 75 | } |
| 73 | 76 | |
| 74 | | static void draw_mode2_line(running_device *screen, bitmap_t *bitmap, int y) |
| 77 | static void draw_mode12_block(coupe_asic *asic, bitmap_t *bitmap, int vpos, int hpos, UINT8 mask) |
| 75 | 78 | { |
| 76 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 77 | | int b, scrx = 0; |
| 78 | | UINT16 ink = 127, pap = 0; |
| 79 | | UINT8 *attr = screen->machine->generic.videoram.u8 + 32*192 + y*32; |
| 80 | | int x; |
| 79 | /* extract colors from attribute */ |
| 80 | UINT8 ink = asic->clut[ATTR_FG(asic->attribute)]; |
| 81 | UINT8 pap = asic->clut[ATTR_BG(asic->attribute)]; |
| 81 | 82 | |
| 82 | | for (x = 0; x < 256/8; x++) |
| 83 | /* draw block of 8 pixels (doubled to 16) */ |
| 84 | for (int i = 0; i < SAM_BLOCK; i++) |
| 83 | 85 | { |
| 84 | | UINT8 tmp = screen->machine->generic.videoram.u8[x + (y*32)]; |
| 85 | | |
| 86 | | #ifndef MONO |
| 87 | | ink = asic->clut[(*attr) & 0x07]; |
| 88 | | pap = asic->clut[((*attr) >> 3) & 0x07]; |
| 89 | | #endif |
| 90 | | |
| 91 | | attr++; |
| 92 | | |
| 93 | | for (b = 0x80; b!= 0; b >>= 1) |
| 94 | | { |
| 95 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + scrx++) = (tmp & b) ? ink : pap; |
| 96 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + scrx++) = (tmp & b) ? ink : pap; |
| 97 | | } |
| 86 | *BITMAP_ADDR16(bitmap, vpos, hpos + i*2 + 0) = BIT(mask, 7 - i) ? ink : pap; |
| 87 | *BITMAP_ADDR16(bitmap, vpos, hpos + i*2 + 1) = BIT(mask, 7 - i) ? ink : pap; |
| 98 | 88 | } |
| 99 | 89 | } |
| 100 | 90 | |
| 101 | | static void draw_mode1_line(running_device *screen, bitmap_t *bitmap, int y) |
| 91 | static void draw_mode2_line(running_machine *machine, int y, int hpos) |
| 102 | 92 | { |
| 103 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 104 | | int block, x = 0; |
| 93 | coupe_asic *asic = (coupe_asic *)machine->driver_data; |
| 105 | 94 | |
| 106 | | /* get base address of attribute and data values */ |
| 107 | | UINT8 *attr = screen->machine->generic.videoram.u8 + 32*192 + ((y & 0xf8) << 2); |
| 108 | | UINT8 *data = screen->machine->generic.videoram.u8 + (((y & 0xc0) << 5) | ((y & 0x07) << 8) | ((y & 0x38) << 2)); |
| 95 | int cell = (y - SAM_BORDER_TOP) * 32 + (hpos - SAM_BORDER_LEFT) / SAM_BLOCK / 2; |
| 109 | 96 | |
| 110 | | /* loop over all 32 blocks */ |
| 111 | | for (block = 0; block < 32; block++) |
| 112 | | { |
| 113 | | int bit; |
| 97 | UINT8 mask = machine->generic.videoram.u8[cell]; |
| 98 | asic->attribute = machine->generic.videoram.u8[cell + 0x2000]; |
| 114 | 99 | |
| 115 | | /* get current colors from attribute byte */ |
| 116 | | UINT8 ink = asic->clut[(*attr & 0x07) + ((*attr >> 3) & 0x08)]; |
| 117 | | UINT8 paper = asic->clut[(*attr >> 3) & 0x0f]; |
| 100 | draw_mode12_block(asic, machine->generic.tmpbitmap, y, hpos, mask); |
| 101 | } |
| 118 | 102 | |
| 119 | | /* draw a block (8 pixels, doubled) */ |
| 120 | | for (bit = 0x80; bit != 0; bit >>= 1) |
| 121 | | { |
| 122 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x++) = (*data & bit) ? ink : paper; |
| 123 | | *BITMAP_ADDR16(bitmap, SAM_BORDER_TOP + y, SAM_BORDER_LEFT + x++) = (*data & bit) ? ink : paper; |
| 124 | | } |
| 103 | static void draw_mode1_line(running_machine *machine, int y, int hpos) |
| 104 | { |
| 105 | coupe_asic *asic = (coupe_asic *)machine->driver_data; |
| 125 | 106 | |
| 126 | | /* save current attribute */ |
| 127 | | asic->attribute = *attr; |
| 107 | UINT8 mask = machine->generic.videoram.u8[((((y - SAM_BORDER_TOP) & 0xc0) << 5) | (((y - SAM_BORDER_TOP) & 0x07) << 8) | (((y - SAM_BORDER_TOP) & 0x38) << 2)) + (hpos - SAM_BORDER_LEFT) / SAM_BLOCK / 2]; |
| 108 | asic->attribute = machine->generic.videoram.u8[32*192 + (((y - SAM_BORDER_TOP) & 0xf8) << 2) + (hpos - SAM_BORDER_LEFT) / SAM_BLOCK / 2]; |
| 128 | 109 | |
| 129 | | /* move to the next block of values */ |
| 130 | | attr++; |
| 131 | | data++; |
| 132 | | } |
| 110 | draw_mode12_block(asic, machine->generic.tmpbitmap, y, hpos, mask); |
| 133 | 111 | } |
| 134 | 112 | |
| 135 | | VIDEO_UPDATE( samcoupe ) |
| 113 | TIMER_CALLBACK( sam_video_update_callback ) |
| 136 | 114 | { |
| 137 | | int scanline = video_screen_get_vpos(screen); |
| 138 | | coupe_asic *asic = (coupe_asic *)screen->machine->driver_data; |
| 115 | coupe_asic *asic = (coupe_asic *)machine->driver_data; |
| 139 | 116 | |
| 140 | | /* border area? */ |
| 141 | | if (scanline < SAM_BORDER_TOP || scanline >= SAM_SCREEN_HEIGHT + SAM_BORDER_BOTTOM) |
| 117 | int vpos = video_screen_get_vpos(machine->primary_screen); |
| 118 | int hpos = video_screen_get_hpos(machine->primary_screen); |
| 119 | |
| 120 | int next_vpos = vpos; |
| 121 | int next_hpos = hpos + SAM_BLOCK*2; |
| 122 | |
| 123 | /* next scanline? */ |
| 124 | if (next_hpos >= SAM_BORDER_LEFT + SAM_SCREEN_WIDTH + SAM_BORDER_RIGHT) |
| 142 | 125 | { |
| 143 | | plot_box(bitmap, 0, scanline, SAM_BORDER_LEFT + SAM_SCREEN_WIDTH + SAM_BORDER_RIGHT, 1, asic->clut[BORDER_COLOR(asic->border)]); |
| 126 | next_vpos = (vpos + 1) % (SAM_BORDER_TOP + SAM_SCREEN_HEIGHT + SAM_BORDER_BOTTOM); |
| 127 | next_hpos = 0; |
| 144 | 128 | } |
| 129 | |
| 130 | /* display disabled? (only in mode 3 or 4) */ |
| 131 | if (BIT(asic->vmpr, 6) && BIT(asic->border, 7)) |
| 132 | { |
| 133 | plot_box(machine->generic.tmpbitmap, hpos, vpos, SAM_BLOCK*2, 1, 0); |
| 134 | } |
| 145 | 135 | else |
| 146 | 136 | { |
| 147 | | /* adjust for border */ |
| 148 | | scanline -= SAM_BORDER_TOP; |
| 149 | | |
| 150 | | /* line interrupt? */ |
| 151 | | if (asic->line_int == scanline) |
| 152 | | samcoupe_irq(screen->machine->firstcpu, SAM_LINE_INT); |
| 153 | | |
| 154 | | /* display disabled? (only in mode 3 or 4) */ |
| 155 | | if ((asic->vmpr & 0x40) && (asic->border & 0x80)) |
| 137 | /* border area? */ |
| 138 | if (vpos < SAM_BORDER_TOP || vpos >= SAM_BORDER_TOP + SAM_SCREEN_HEIGHT || hpos < SAM_BORDER_LEFT || hpos >= SAM_BORDER_LEFT + SAM_SCREEN_WIDTH) |
| 156 | 139 | { |
| 157 | | /* display is disabled, draw a black screen */ |
| 158 | | bitmap_fill(bitmap, cliprect, 0); |
| 140 | asic->attribute = 0xff; |
| 141 | plot_box(machine->generic.tmpbitmap, hpos, vpos, SAM_BLOCK*2, 1, asic->clut[BORDER_COLOR(asic->border)]); |
| 159 | 142 | } |
| 160 | 143 | else |
| 161 | 144 | { |
| 162 | | /* display enabled, start drawing border */ |
| 163 | | draw_left_border(screen, bitmap, scanline); |
| 164 | | |
| 165 | | /* draw line in the right screen mode */ |
| 145 | /* main screen area */ |
| 166 | 146 | switch ((asic->vmpr & 0x60) >> 5) |
| 167 | 147 | { |
| 168 | | case 0: draw_mode1_line(screen, bitmap, scanline); break; |
| 169 | | case 1: draw_mode2_line(screen, bitmap, scanline); break; |
| 170 | | case 2: draw_mode3_line(screen, bitmap, scanline); break; |
| 171 | | case 3: draw_mode4_line(screen, bitmap, scanline); break; |
| 148 | case 0: draw_mode1_line(machine, vpos, hpos); break; |
| 149 | case 1: draw_mode2_line(machine, vpos, hpos); break; |
| 150 | case 2: draw_mode3_line(machine, vpos, hpos); break; |
| 151 | case 3: draw_mode4_line(machine, vpos, hpos); break; |
| 172 | 152 | } |
| 173 | | |
| 174 | | /* rest of the border */ |
| 175 | | draw_right_border(screen, bitmap, scanline); |
| 176 | 153 | } |
| 177 | | //printf("videomode: %u\n", (asic->vmpr & 0x60) >> 5); |
| 178 | 154 | } |
| 179 | 155 | |
| 180 | | return 0; |
| 156 | /* do we need to trigger the scanline interrupt (interrupt happens at the start of the right border before the specified line)? */ |
| 157 | if (asic->line_int < SAM_SCREEN_HEIGHT && hpos == SAM_BORDER_LEFT + SAM_SCREEN_WIDTH && vpos == (asic->line_int + SAM_BORDER_TOP - 1)) |
| 158 | samcoupe_irq(machine->firstcpu, SAM_LINE_INT); |
| 159 | |
| 160 | /* schedule next update */ |
| 161 | timer_adjust_oneshot(asic->video_update_timer, video_screen_get_time_until_pos(machine->primary_screen, next_vpos, next_hpos), 0); |
| 181 | 162 | } |