diff options
Diffstat (limited to 'src/mess/video/vc4000.c')
-rw-r--r-- | src/mess/video/vc4000.c | 655 |
1 files changed, 655 insertions, 0 deletions
diff --git a/src/mess/video/vc4000.c b/src/mess/video/vc4000.c new file mode 100644 index 00000000000..ccf85be6dc3 --- /dev/null +++ b/src/mess/video/vc4000.c @@ -0,0 +1,655 @@ + +#include "includes/vc4000.h" + + +/* + emulation of signetics 2636 video/audio device + + seams to me like a special microcontroller + mask programmed + + note about mame s2636 emulation: + less encapsuled + missing grid, sound generation, retriggered sprites, paddle reading, score display + not "rasterline" based + */ + +#define STICKCENTRE (105) +#define STICKLOW (20) +#define STICKHIGH (225) + +#define VC4000_END_LINE (269) + + + +VIDEO_START(vc4000) +{ + vc4000_state *state = machine.driver_data<vc4000_state>(); + screen_device *screen = machine.first_screen(); + int i; + + for (i=0;i<0x20; i++) + { + state->m_sprite_collision[i]=0; + if ((i&3)==3) state->m_sprite_collision[i]|=0x20; + if ((i&5)==5) state->m_sprite_collision[i]|=0x10; + if ((i&9)==9) state->m_sprite_collision[i]|=8; + if ((i&6)==6) state->m_sprite_collision[i]|=4; + if ((i&0xa)==0xa) state->m_sprite_collision[i]|=2; + if ((i&0xc)==0xc) state->m_sprite_collision[i]|=1; + state->m_background_collision[i]=0; + if ((i&0x11)==0x11) state->m_background_collision[i]|=0x80; + if ((i&0x12)==0x12) state->m_background_collision[i]|=0x40; + if ((i&0x14)==0x14) state->m_background_collision[i]|=0x20; + if ((i&0x18)==0x18) state->m_background_collision[i]|=0x10; + } + + state->m_joy1_x = STICKCENTRE; + state->m_joy1_y = STICKCENTRE; + state->m_joy2_x = STICKCENTRE; + state->m_joy2_y = STICKCENTRE; + + memset(&state->m_video, 0, sizeof(state->m_video)); + for (i=0; i<3; i++) + { + state->m_video.sprites[i].data = &state->m_video.reg.d.sprites[i]; + state->m_video.sprites[i].mask = 1 << i; + } + state->m_video.sprites[3].data = &state->m_video.reg.d.sprite4; + state->m_video.sprites[3].mask = 1 << 3; + + state->m_bitmap = auto_bitmap_ind16_alloc(machine, screen->width(), screen->height()); +} + +INLINE UINT8 vc4000_joystick_return_to_centre(UINT8 joy) +{ + UINT8 data; + + if (joy > (STICKCENTRE+5)) + data=joy-5; + else + if (joy < (STICKCENTRE-5)) + data=joy+5; + else + data=105; + + return data; +} + +READ8_MEMBER( vc4000_state::vc4000_video_r ) +{ + UINT8 data=0; + if (offset > 0xcf) offset &= 0xcf; // c0-cf is mirrored at d0-df, e0-ef, f0-ff + switch (offset) + { + case 0xca: // Background-sprite collision (bit 7-4) and sprite finished (bit 3-0) + data |= m_video.background_collision; + m_video.background_collision=0; + if (m_video.sprites[3].finished) + { + data |= 1; + m_video.sprites[3].finished = FALSE; + } + + if (m_video.sprites[2].finished) + { + data |= 2; + m_video.sprites[2].finished = FALSE; + } + if (m_video.sprites[1].finished) + { + data |= 4; + m_video.sprites[1].finished = FALSE; + } + if (m_video.sprites[0].finished) + { + data |= 8; + m_video.sprites[0].finished = FALSE; + } + break; + + case 0xcb: // VRST-Flag (bit 6) and intersprite collision (bit5-0) + data = m_video.sprite_collision | (m_video.reg.d.sprite_collision & 0xc0); + m_video.sprite_collision = 0; + m_video.reg.d.sprite_collision &= 0xbf; + break; + +#ifndef ANALOG_HACK + case 0xcc: + if (!activecpu_get_reg(S2650_FO)) data=ioport("JOY1_X")->read(); + else data=ioport("JOY1_Y")->read(); + break; + case 0xcd: + if (!activecpu_get_reg(S2650_FO)) data=ioport("JOY2_X")->read(); + else data=ioport("JOY2_Y")->read(); + break; +#else + + case 0xcc: /* left joystick */ + if (ioport("CONFIG")->read()&1) + { /* paddle */ + if (!cpu_get_reg(machine().device("maincpu"), S2650_FO)) + { + data = ioport("JOYS")->read() & 0x03; + switch (data) + { + case 0x01: + m_joy1_x-=5; + if (m_joy1_x < STICKLOW) m_joy1_x=STICKLOW; + break; + case 0x02: + m_joy1_x+=5; + if (m_joy1_x > STICKHIGH) m_joy1_x=STICKHIGH; + break; + case 0x00: + m_joy1_x = vc4000_joystick_return_to_centre(m_joy1_x); + } + data = m_joy1_x; + } + else + { + data = ioport("JOYS")->read() & 0x0c; + switch (data) + { + case 0x08: + m_joy1_y-=5; + if (m_joy1_y < STICKLOW) m_joy1_y=STICKLOW; + break; + case 0x04: + m_joy1_y+=5; + if (m_joy1_y > STICKHIGH) m_joy1_y=STICKHIGH; + break; + // case 0x00: + // m_joy1_y = vc4000_joystick_return_to_centre(m_joy1_y); + } + data = m_joy1_y; + } + } + else + { /* buttons */ + if (!cpu_get_reg(machine().device("maincpu"), S2650_FO)) + { + data = ioport("JOYS")->read() & 0x03; + switch (data) + { + case 0x01: + m_joy1_x=STICKLOW; + break; + case 0x02: + m_joy1_x=STICKHIGH; + break; + default: /* autocentre */ + m_joy1_x=STICKCENTRE; + } + data = m_joy1_x; + } + else + { + data = ioport("JOYS")->read() & 0x0c; + switch (data) + { + case 0x08: + m_joy1_y=STICKLOW; + break; + case 0x04: + m_joy1_y=STICKHIGH; + break; + default: + m_joy1_y=STICKCENTRE; + } + data = m_joy1_y; + } + } + break; + + case 0xcd: /* right joystick */ + if (ioport("CONFIG")->read()&1) + { + if (!cpu_get_reg(machine().device("maincpu"), S2650_FO)) + { + data = ioport("JOYS")->read() & 0x30; + switch (data) + { + case 0x10: + m_joy2_x-=5; + if (m_joy2_x < STICKLOW) m_joy2_x=STICKLOW; + break; + case 0x20: + m_joy2_x+=5; + if (m_joy2_x > STICKHIGH) m_joy2_x=STICKHIGH; + case 0x00: + m_joy2_x = vc4000_joystick_return_to_centre(m_joy2_x); + break; + } + data = m_joy2_x; + } + else + { + data = ioport("JOYS")->read() & 0xc0; + switch (data) + { + case 0x80: + m_joy2_y-=5; + if (m_joy2_y < STICKLOW) m_joy2_y=STICKLOW; + break; + case 0x40: + m_joy2_y+=5; + if (m_joy2_y > STICKHIGH) m_joy2_y=STICKHIGH; + break; + // case 0x00: + // m_joy2_y = vc4000_joystick_return_to_centre(m_joy2_y); + } + data = m_joy2_y; + } + } + else + { + if (!cpu_get_reg(machine().device("maincpu"), S2650_FO)) + { + data = ioport("JOYS")->read() & 0x30; + switch (data) + { + case 0x10: + m_joy2_x=STICKLOW; + break; + case 0x20: + m_joy2_x=STICKHIGH; + break; + default: /* autocentre */ + m_joy2_x=STICKCENTRE; + } + data = m_joy2_x; + } + else + { + data = ioport("JOYS")->read() & 0xc0; + switch (data) + { + case 0x80: + m_joy2_y=STICKLOW; + break; + case 0x40: + m_joy2_y=STICKHIGH; + break; + default: + m_joy2_y=STICKCENTRE; + } + data = m_joy2_y; + } + } + break; +#endif + + default: + data = m_video.reg.data[offset]; + break; + } + return data; +} + +WRITE8_MEMBER( vc4000_state::vc4000_video_w ) +{ +// m_video.reg.data[offset]=data; + if (offset > 0xcf) offset &= 0xcf; // c0-cf is mirrored at d0-df, e0-ef, f0-ff + + switch (offset) + { + + case 0xc0: // Sprite size + m_video.sprites[0].size=1<<(data&3); + m_video.sprites[1].size=1<<((data>>2)&3); + m_video.sprites[2].size=1<<((data>>4)&3); + m_video.sprites[3].size=1<<((data>>6)&3); + break; + + case 0xc1: // Sprite 1+2 color + m_video.sprites[0].scolor=((~data>>3)&7); + m_video.sprites[1].scolor=(~data&7); + break; + + case 0xc2: // Sprite 2+3 color + m_video.sprites[2].scolor=((~data>>3)&7); + m_video.sprites[3].scolor=(~data&7); + break; + + case 0xc3: // Score control + m_video.reg.d.score_control = data; + break; + + case 0xc6: // Background color + m_video.reg.d.background = data; + break; + + case 0xc7: // Soundregister + m_video.reg.data[offset] = data; + vc4000_soundport_w(machine().device("custom"), 0, data); + break; + + case 0xc8: // Digits 1 and 2 + m_video.reg.d.bcd[0] = data; + break; + + case 0xc9: // Digits 3 and 4 + m_video.reg.d.bcd[1] = data; + break; + + case 0xca: // Background-sprite collision (bit 7-4) and sprite finished (bit 3-0) + m_video.reg.data[offset]=data; + m_video.background_collision=data; + break; + + case 0xcb: // VRST-Flag (bit 6) and intersprite collision (bit5-0) + m_video.reg.data[offset]=data; + m_video.sprite_collision=data; + break; + + default: + m_video.reg.data[offset]=data; + } +} + + +READ8_MEMBER( vc4000_state::vc4000_vsync_r ) +{ + return m_video.line >= VC4000_END_LINE ? 0x80 : 0; +} + +static const char led[20][12+1] = +{ + "aaaabbbbcccc", + "aaaabbbbcccc", + "aaaabbbbcccc", + "aaaabbbbcccc", + "llll dddd", + "llll dddd", + "llll dddd", + "llll dddd", + "kkkkmmmmeeee", + "kkkkmmmmeeee", + "kkkkmmmmeeee", + "kkkkmmmmeeee", + "jjjj ffff", + "jjjj ffff", + "jjjj ffff", + "jjjj ffff", + "iiiihhhhgggg", + "iiiihhhhgggg", + "iiiihhhhgggg", + "iiiihhhhgggg" +}; + + +static void vc4000_draw_digit(vc4000_state *state, bitmap_ind16 &bitmap, int x, int y, int d, int line) +{ + static const int digit_to_segment[0x10]={ + 0x0fff, 0x007c, 0x17df, 0x15ff, 0x1c7d, 0x1df7, 0x1ff7, 0x007f, 0x1fff, 0x1dff + }; + + int i=line,j; + + for (j=0; j<sizeof(led[0]); j++) + { + if (digit_to_segment[d]&(1<<(led[i][j]-'a')) ) + bitmap.pix16(y+i, x+j) = ((state->m_video.reg.d.background>>4)&7)^7; + } +} + +INLINE void vc4000_collision_plot(UINT8 *collision, UINT8 data, UINT8 color, int scale) +{ + int i,j,m; + + for (j=0,m=0x80; j<8; j++, m>>=1) + { + if (data&m) + for (i=0; i<scale; i++, collision++) *collision|=color; + else + collision+=scale; + } +} + + +static void vc4000_sprite_update(vc4000_state *state, bitmap_ind16 &bitmap, UINT8 *collision, SPRITE *This) +{ + int i,j,m; + + if (state->m_video.line==0) + { + This->y=This->data->y1; + This->state=0; + This->delay=0; + This->finished=FALSE; + } + + This->finished_now=FALSE; + + if (state->m_video.line>VC4000_END_LINE) return; + + switch (This->state) + { + case 0: + if (state->m_video.line != This->y + 2) break; + This->state++; + + case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:case 9:case 10: + + vc4000_collision_plot(collision+This->data->x1, This->data->bitmap[This->state-1],This->mask,This->size); + + for (j=0,m=0x80; j<8; j++, m>>=1) + { + if (This->data->bitmap[This->state-1]&m) + { + for (i=0; i<This->size; i++) + { + state->m_objects[This->data->x1 + i + j*This->size] |= This->scolor; + state->m_objects[This->data->x1 + i + j*This->size] &= 7; + } + } + } + + This->delay++; + + if (This->delay>=This->size) + { + This->delay=0; + This->state++; + } + + if (This->state>10) + { + This->finished=TRUE; + This->finished_now=TRUE; + } + + break; + + case 11: + This->y=This->data->y2; + + if (This->y==255) + This->y=0; + else + This->y++; + + if (This->y>252) break; + + This->delay=0; + This->state++; + + case 12: + if (This->y!=0) + { + This->y--; + break; + } + This->state++; + + case 13: case 14: case 15: case 16: case 17: case 18: case 19:case 20:case 21:case 22: + + vc4000_collision_plot(collision+This->data->x2,This->data->bitmap[This->state-13],This->mask,This->size); + for (j=0,m=0x80; j<8; j++, m>>=1) + { + if (This->data->bitmap[This->state-13]&m) + { + for (i=0; i<This->size; i++) + { + int offset = This->data->x2 + i + j*This->size; + + // clip objects outside the object buffer. + // someone who knows this hardware should look at + // it properly. + if (offset < 256) + { + state->m_objects[offset] |= This->scolor; + state->m_objects[offset] &= 7; + } + } + } + } + This->delay++; + if (This->delay<This->size) break; + This->delay=0; + This->state++; + if (This->state<23) break; + This->finished=TRUE; + This->finished_now=TRUE; + This->state=11; + break; + } +} + +INLINE void vc4000_draw_grid(running_machine &machine, UINT8 *collision) +{ + vc4000_state *state = machine.driver_data<vc4000_state>(); + screen_device *screen = machine.first_screen(); + int width = screen->width(); + int height = screen->height(); + int i, j, m, x, line=state->m_video.line-20; + int w, k; + + if (state->m_video.line>=height) return; + + state->m_bitmap->plot_box(0, state->m_video.line, width, 1, (state->m_video.reg.d.background)&7); + + if (line<0 || line>=200) return; + if (~state->m_video.reg.d.background & 8) return; + + i=(line/20)*2; + if (line%20>=2) i++; + + k=state->m_video.reg.d.grid_control[i>>2]; + switch (k>>6) { + default: + case 0:case 2: w=1;break; + case 1: w=2;break; + case 3: w=4;break; + } + switch (i&3) { + case 0: + if (k&1) w=8;break; + case 1: + if ((line%40)<=10) { + if (k&2) w=8; + } else { + if (k&4) w=8; + } + break; + case 2: if (k&8) w=8;break; + case 3: + if ((line%40)<=30) { + if (k&0x10) w=8; + } else { + if (k&0x20) w=8; + } + break; + } + for (x=30, j=0, m=0x80; j<16; j++, x+=8, m>>=1) + { + if (state->m_video.reg.d.grid[i][j>>3]&m) + { + int l; + for (l=0; l<w; l++) collision[x+l]|=0x10; + state->m_bitmap->plot_box(x, state->m_video.line, w, 1, (state->m_video.reg.d.background>>4)&7); + } + if (j==7) m=0x100; + } +} + +INTERRUPT_GEN( vc4000_video_line ) +{ + vc4000_state *state = device->machine().driver_data<vc4000_state>(); + int x,y,i; + UINT8 collision[400]={0}; // better alloca or gcc feature of non constant long automatic arrays + const rectangle &visarea = device->machine().primary_screen->visible_area(); + assert(ARRAY_LENGTH(collision) >= device->machine().primary_screen->width()); + + state->m_video.line++; + if (state->m_irq_pause) state->m_irq_pause++; + if (state->m_video.line>311) state->m_video.line=0; + + if (state->m_video.line==0) + { + state->m_video.background_collision=0; + state->m_video.sprite_collision=0; + state->m_video.reg.d.sprite_collision=0; +// logerror("begin of frame\n"); + } + + if (state->m_irq_pause>10) + { + cputag_set_input_line(device->machine(), "maincpu", 0, CLEAR_LINE); + state->m_irq_pause = 0; + } + + if (state->m_video.line <= VC4000_END_LINE) + { + vc4000_draw_grid(device->machine(), collision); + + /* init object colours */ + for (i=visarea.min_x; i<visarea.max_x; i++) state->m_objects[i]=8; + + /* calculate object colours and OR overlapping object colours */ + vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[0]); + vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[1]); + vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[2]); + vc4000_sprite_update(state, *state->m_bitmap, collision, &state->m_video.sprites[3]); + + for (i=visarea.min_x; i<visarea.max_x; i++) + { + state->m_video.sprite_collision|=state->m_sprite_collision[collision[i]]; + state->m_video.background_collision|=state->m_background_collision[collision[i]]; + /* display final object colours */ + if (state->m_objects[i] < 8) + state->m_bitmap->pix16(state->m_video.line, i) = state->m_objects[i]; + } + + y = state->m_video.reg.d.score_control&1?200:20; + + if ((state->m_video.line>=y)&&(state->m_video.line<y+20)) + { + x = 60; + vc4000_draw_digit(state, *state->m_bitmap, x, y, state->m_video.reg.d.bcd[0]>>4, state->m_video.line-y); + vc4000_draw_digit(state, *state->m_bitmap, x+16, y, state->m_video.reg.d.bcd[0]&0xf, state->m_video.line-y); + if (state->m_video.reg.d.score_control&2) x -= 16; + vc4000_draw_digit(state, *state->m_bitmap, x+48, y, state->m_video.reg.d.bcd[1]>>4, state->m_video.line-y); + vc4000_draw_digit(state, *state->m_bitmap, x+64, y, state->m_video.reg.d.bcd[1]&0xf, state->m_video.line-y); + } + } + if (state->m_video.line==VC4000_END_LINE) state->m_video.reg.d.sprite_collision |=0x40; + + if (((state->m_video.line == VC4000_END_LINE) | + (state->m_video.sprites[3].finished_now) | + (state->m_video.sprites[2].finished_now) | + (state->m_video.sprites[1].finished_now) | + (state->m_video.sprites[0].finished_now)) && (!state->m_irq_pause)) + { + cputag_set_input_line_and_vector(device->machine(), "maincpu", 0, ASSERT_LINE, 3); + state->m_irq_pause=1; + } +} + +SCREEN_UPDATE_IND16( vc4000 ) +{ + vc4000_state *state = screen.machine().driver_data<vc4000_state>(); + copybitmap(bitmap, *state->m_bitmap, 0, 0, 0, 0, cliprect); + return 0; +} |