sm7238: implement double-sized characters and smooth scroll.

This commit is contained in:
Sergey Svishchev 2017-03-02 10:02:18 +03:00
parent 1d027e1d22
commit bc286f5d58

View File

@ -9,10 +9,9 @@
To do:
- handle more text_control_w bits
- more character attributes incl. double width and height, color
- 80/132 columns switching on the fly, reverse video
- smooth scroll
- graphics option
- colors
- run vblank from timer output?
- document hardware and ROM variants, verify if pixel stretching is done
@ -76,7 +75,6 @@ public:
, m_screen(*this, "screen")
{ }
TIMER_DEVICE_CALLBACK_MEMBER( scanline_callback );
DECLARE_PALETTE_INIT(sm7238);
DECLARE_WRITE_LINE_MEMBER(write_keyboard_clock);
@ -88,17 +86,14 @@ public:
void screen_eof(screen_device &screen, bool state);
private:
uint32_t draw_scanline(uint16_t *p, uint16_t offset, uint8_t scanline);
rectangle m_tmpclip;
bitmap_ind16 m_tmpbmp;
void text_memory_clear();
void recompute_parameters();
struct {
struct
{
uint8_t control;
uint8_t stride;
uint16_t ptr;
int stride;
} m_video;
virtual void machine_reset() override;
@ -155,8 +150,6 @@ void sm7238_state::machine_reset()
void sm7238_state::video_start()
{
m_tmpclip = rectangle(0, KSM_DISP_HORZ-1, 0, KSM_DISP_VERT-1);
m_tmpbmp.allocate(KSM_DISP_HORZ, KSM_DISP_VERT);
}
WRITE8_MEMBER(sm7238_state::control_w)
@ -174,7 +167,8 @@ WRITE8_MEMBER(sm7238_state::text_control_w)
if (!BIT(data, 2) && !BIT(data, 3))
text_memory_clear();
if (BIT((data ^ m_video.control), 0)) {
if (BIT((data ^ m_video.control), 0))
{
m_video.stride = BIT(data, 0) ? 80 : 132;
// recompute_parameters();
}
@ -194,98 +188,18 @@ WRITE_LINE_MEMBER(sm7238_state::write_printer_clock)
m_i8251prn->write_rxc(state);
}
uint32_t sm7238_state::draw_scanline(uint16_t *p, uint16_t offset, uint8_t scanline)
{
uint8_t attr, fg, bg, ra, gfx;
uint16_t x, chr;
int dw;
ra = scanline % 10;
for (x = offset; x < offset + m_video.stride; x++)
{
chr = m_p_videoram[x] << 4;
attr = m_p_videoram[x + 0x1000];
gfx = m_p_chargen[chr | ra] ^ 255;
bg = 0; fg = 1;
/* Process attributes */
if ((BIT(attr, 1)) && (ra == 9))
{
gfx = 0xff; // underline
}
// 2 = blink
if (BIT(attr, 3))
{
gfx ^= 0xff; // reverse video
}
if (BIT(attr, 4))
fg = 2; // highlight
else
fg = 1;
dw = 0; // BIT(attr, 4);
*p++ = BIT(gfx, 7) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 7) ? fg : bg;
*p++ = BIT(gfx, 6) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 6) ? fg : bg;
*p++ = BIT(gfx, 5) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 5) ? fg : bg;
*p++ = BIT(gfx, 4) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 4) ? fg : bg;
*p++ = BIT(gfx, 3) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 3) ? fg : bg;
*p++ = BIT(gfx, 2) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 2) ? fg : bg;
*p++ = BIT(gfx, 1) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 1) ? fg : bg;
*p++ = BIT(gfx, 0) ? fg : bg;
if (dw)
*p++ = BIT(gfx, 0) ? fg : bg;
}
return 0;
}
TIMER_DEVICE_CALLBACK_MEMBER(sm7238_state::scanline_callback)
{
uint16_t y = m_screen->vpos();
uint16_t o = m_video.ptr;
if (y < KSM_VERT_START) return;
y -= KSM_VERT_START;
if (y >= KSM_DISP_VERT) return;
if (y == 0)
m_video.ptr = 0;
else if (y%10 == 0) {
m_video.ptr = m_p_videoram[m_video.ptr + m_video.stride + 1] |
(m_p_videoram[m_video.ptr + 0x1000 + m_video.stride + 1] << 8);
m_video.ptr &= 0x0fff;
DBG_LOG(2,"scanline_cb",("y %d row %d old ptr %04x new ptr %04x\n", y, y%10, o, m_video.ptr));
}
draw_scanline(&m_tmpbmp.pix16(y), m_video.ptr, y%10);
}
void sm7238_state::text_memory_clear()
{
int y = 0, ptr = 0;
do {
do
{
memset(&m_p_videoram[ptr], 0x20, m_video.stride);
memset(&m_p_videoram[ptr + 0x1000], 0x20, m_video.stride);
ptr = m_p_videoram[ptr + m_video.stride + 1] | (m_p_videoram[ptr + 0x1000 + m_video.stride + 1] << 8);
ptr &= 0x0fff;
y++;
} while (y<26);
} while (y < 26);
}
void sm7238_state::recompute_parameters()
@ -300,8 +214,96 @@ void sm7238_state::recompute_parameters()
uint32_t sm7238_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (BIT(m_video.control, 3))
copybitmap(bitmap, m_tmpbmp, 0, 0, KSM_HORZ_START, KSM_VERT_START, cliprect);
uint8_t y, ra, gfx, fg, bg, attr, ctl1, ctl2 = 0;
uint16_t chr, sy = KSM_VERT_START, ma = 0, x = 0;
bool double_width = false, double_height = false, bottom_half = false;
if (!BIT(m_video.control, 3))
{
bitmap.fill(0);
return 0;
}
for (y = 0; y < 26; y++)
{
for (ra = 0; ra < 10; ra++)
{
if (y == 1 && ctl2 && ra < ctl2)
continue;
uint16_t *p = &bitmap.pix16(sy++, KSM_HORZ_START);
for (x = ma; x < ma + m_video.stride; x++)
{
chr = m_p_videoram[x] << 4;
attr = m_p_videoram[x + 0x1000];
if (double_height)
{
gfx = m_p_chargen[chr | (bottom_half ? (5 + (ra >> 1)) : (ra >> 1))] ^ 255;
}
else
{
gfx = m_p_chargen[chr | ra] ^ 255;
}
bg = 0;
fg = 1;
/* Process attributes */
if ((BIT(attr, 1)) && (ra == 9))
{
gfx = 0xff; // underline
}
// 2 = blink
if (BIT(attr, 3))
{
gfx ^= 0xff; // reverse video
}
if (BIT(attr, 4))
fg = 2; // highlight
else
fg = 1;
*p++ = BIT(gfx, 7) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 7) ? fg : bg;
*p++ = BIT(gfx, 6) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 6) ? fg : bg;
*p++ = BIT(gfx, 5) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 5) ? fg : bg;
*p++ = BIT(gfx, 4) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 4) ? fg : bg;
*p++ = BIT(gfx, 3) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 3) ? fg : bg;
*p++ = BIT(gfx, 2) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 2) ? fg : bg;
*p++ = BIT(gfx, 1) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 1) ? fg : bg;
*p++ = BIT(gfx, 0) ? fg : bg;
if (double_width)
*p++ = BIT(gfx, 0) ? fg : bg;
if (double_width) x++;
}
}
ctl1 = m_p_videoram[ma + 0x1000 + m_video.stride];
double_width = BIT(ctl1, 6);
double_height = BIT(ctl1, 7);
bottom_half = BIT(ctl1, 5);
ctl2 = m_p_videoram[ma + 0x1000 + m_video.stride + 1] >> 4;
ma = m_p_videoram[ma + m_video.stride + 1] |
(m_p_videoram[ma + 0x1000 + m_video.stride + 1] << 8);
ma &= 0x0fff;
}
return 0;
}
@ -342,8 +344,6 @@ static MACHINE_CONFIG_START( sm7238, sm7238_state )
MCFG_CPU_IO_MAP(sm7238_io)
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE("pic8259", pic8259_device, inta_cb)
MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", sm7238_state, scanline_callback, "screen", 0, 1)
MCFG_NVRAM_ADD_0FILL("nvram")
MCFG_SCREEN_ADD("screen", RASTER)
@ -364,7 +364,7 @@ static MACHINE_CONFIG_START( sm7238, sm7238_state )
MCFG_PALETTE_INIT_OWNER(sm7238_state, sm7238)
MCFG_GFXDECODE_ADD("gfxdecode", "palette", sm7238)
MCFG_PIC8259_ADD( "pic8259", INPUTLINE("maincpu", 0), VCC, NOOP)
MCFG_PIC8259_ADD("pic8259", INPUTLINE("maincpu", 0), VCC, NOOP)
MCFG_DEVICE_ADD("t_hblank", PIT8253, 0)
MCFG_PIT8253_CLK1(XTAL_16_384MHz/9) // XXX workaround -- keyboard is slower and doesn't sync otherwise
@ -429,4 +429,4 @@ ROM_END
/* Driver */
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
COMP( 1989, sm7238, 0, 0, sm7238, 0, driver_device, 0, "USSR", "SM 7238", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_IMPERFECT_KEYBOARD)
COMP( 1989, sm7238, 0, 0, sm7238, 0, driver_device, 0, "USSR", "SM 7238", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_IMPERFECT_KEYBOARD)