summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/cdp1869.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/cdp1869.c')
-rw-r--r--trunk/src/emu/sound/cdp1869.c977
1 files changed, 977 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/cdp1869.c b/trunk/src/emu/sound/cdp1869.c
new file mode 100644
index 00000000000..3c7ead02d50
--- /dev/null
+++ b/trunk/src/emu/sound/cdp1869.c
@@ -0,0 +1,977 @@
+/**********************************************************************
+
+ RCA CDP1869/1870/1876 Video Interface System (VIS) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - white noise
+ - scanline based update
+ - CMSEL output
+
+*/
+
+#include "emu.h"
+#include "cdp1869.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+#define CDP1869_WEIGHT_RED 30 // % of max luminance
+#define CDP1869_WEIGHT_GREEN 59
+#define CDP1869_WEIGHT_BLUE 11
+
+#define CDP1869_COLUMNS_HALF 20
+#define CDP1869_COLUMNS_FULL 40
+#define CDP1869_ROWS_HALF 12
+#define CDP1869_ROWS_FULL_PAL 25
+#define CDP1869_ROWS_FULL_NTSC 24
+
+enum
+{
+ CDB0 = 0,
+ CDB1,
+ CDB2,
+ CDB3,
+ CDB4,
+ CDB5,
+ CCB0,
+ CCB1
+};
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+const device_type CDP1869 = &device_creator<cdp1869_device>;
+
+// default address map
+static ADDRESS_MAP_START( cdp1869, AS_0, 8, cdp1869_device )
+ AM_RANGE(0x000, 0x7ff) AM_RAM
+ADDRESS_MAP_END
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// is_ntsc - is device in NTSC mode
+//-------------------------------------------------
+
+inline bool cdp1869_device::is_ntsc()
+{
+ return m_in_pal_ntsc_func() ? false : true;
+}
+
+
+//-------------------------------------------------
+// read_page_ram_byte - read a page RAM byte at
+// the given address
+//-------------------------------------------------
+
+inline UINT8 cdp1869_device::read_page_ram_byte(offs_t pma)
+{
+ return space()->read_byte(pma);
+}
+
+
+//-------------------------------------------------
+// write_page_ram_byte - write a page RAM byte at
+// the given address
+//-------------------------------------------------
+
+inline void cdp1869_device::write_page_ram_byte(offs_t pma, UINT8 data)
+{
+ space()->write_byte(pma, data);
+}
+
+
+//-------------------------------------------------
+// read_char_ram_byte - read a char RAM byte at
+// the given address
+//-------------------------------------------------
+
+inline UINT8 cdp1869_device::read_char_ram_byte(offs_t pma, offs_t cma, UINT8 pmd)
+{
+ UINT8 data = 0;
+
+ if (m_in_char_ram_func != NULL)
+ {
+ data = m_in_char_ram_func(this, pma, cma, pmd);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_char_ram_byte - write a char RAM byte at
+// the given address
+//-------------------------------------------------
+
+inline void cdp1869_device::write_char_ram_byte(offs_t pma, offs_t cma, UINT8 pmd, UINT8 data)
+{
+ if (m_out_char_ram_func != NULL)
+ {
+ m_out_char_ram_func(this, pma, cma, pmd, data);
+ }
+}
+
+
+//-------------------------------------------------
+// read_pcb - read page control bit
+//-------------------------------------------------
+
+inline int cdp1869_device::read_pcb(offs_t pma, offs_t cma, UINT8 pmd)
+{
+ int pcb = 0;
+
+ if (m_in_pcb_func != NULL)
+ {
+ pcb = m_in_pcb_func(this, pma, cma, pmd);
+ }
+
+ return pcb;
+}
+
+
+//-------------------------------------------------
+// update_prd_changed_timer -
+//-------------------------------------------------
+
+inline void cdp1869_device::update_prd_changed_timer()
+{
+ int start = CDP1869_SCANLINE_PREDISPLAY_START_PAL;
+ int end = CDP1869_SCANLINE_PREDISPLAY_END_PAL;
+ int next_state;
+ int scanline = m_screen->vpos();
+ int next_scanline;
+
+ if (is_ntsc())
+ {
+ start = CDP1869_SCANLINE_PREDISPLAY_START_NTSC;
+ end = CDP1869_SCANLINE_PREDISPLAY_END_NTSC;
+ }
+
+ if (scanline < start)
+ {
+ next_scanline = start;
+ next_state = ASSERT_LINE;
+ }
+ else if (scanline < end)
+ {
+ next_scanline = end;
+ next_state = CLEAR_LINE;
+ }
+ else
+ {
+ next_scanline = start;
+ next_state = ASSERT_LINE;
+ }
+
+ if (m_dispoff)
+ {
+ next_state = CLEAR_LINE;
+ }
+
+ attotime duration = m_screen->time_until_pos(next_scanline);
+ m_prd_timer->adjust(duration, next_state);
+}
+
+
+//-------------------------------------------------
+// get_rgb - get RGB value
+//-------------------------------------------------
+
+inline rgb_t cdp1869_device::get_rgb(int i, int c, int l)
+{
+ int luma = 0, r, g, b;
+
+ luma += (l & 4) ? CDP1869_WEIGHT_RED : 0;
+ luma += (l & 1) ? CDP1869_WEIGHT_GREEN : 0;
+ luma += (l & 2) ? CDP1869_WEIGHT_BLUE : 0;
+
+ luma = (luma * 0xff) / 100;
+
+ r = (c & 4) ? luma : 0;
+ g = (c & 1) ? luma : 0;
+ b = (c & 2) ? luma : 0;
+
+ return MAKE_RGB(r, g, b);
+}
+
+
+//-------------------------------------------------
+// get_lines - get number of character lines
+//-------------------------------------------------
+
+inline int cdp1869_device::get_lines()
+{
+ if (m_line16 && !m_dblpage)
+ {
+ return 16;
+ }
+ else if (!m_line9)
+ {
+ return 9;
+ }
+ else
+ {
+ return 8;
+ }
+}
+
+
+//-------------------------------------------------
+// get_pmemsize - get page memory size
+//-------------------------------------------------
+
+inline UINT16 cdp1869_device::get_pmemsize(int cols, int rows)
+{
+ int pmemsize = cols * rows;
+
+ if (m_dblpage) pmemsize *= 2;
+ if (m_line16) pmemsize *= 2;
+
+ return pmemsize;
+}
+
+
+//-------------------------------------------------
+// get_pma - get page memory address
+//-------------------------------------------------
+
+inline UINT16 cdp1869_device::get_pma()
+{
+ if (m_dblpage)
+ {
+ return m_pma;
+ }
+ else
+ {
+ return m_pma & 0x3ff;
+ }
+}
+
+
+//-------------------------------------------------
+// get_pen - get pen for color bits
+//-------------------------------------------------
+
+inline int cdp1869_device::get_pen(int ccb0, int ccb1, int pcb)
+{
+ int r = 0, g = 0, b = 0;
+
+ switch (m_col)
+ {
+ case 0:
+ r = ccb0;
+ b = ccb1;
+ g = pcb;
+ break;
+
+ case 1:
+ r = ccb0;
+ b = pcb;
+ g = ccb1;
+ break;
+
+ case 2:
+ case 3:
+ r = pcb;
+ b = ccb0;
+ g = ccb1;
+ break;
+ }
+
+ int color = (r << 2) + (b << 1) + g;
+
+ if (m_cfc)
+ {
+ return color + ((m_bkg + 1) * 8);
+ }
+ else
+ {
+ return color;
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// cdp1869_device - constructor
+//-------------------------------------------------
+
+cdp1869_device::cdp1869_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, CDP1869, "RCA CDP1869", tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ device_memory_interface(mconfig, *this),
+ m_stream(NULL),
+ m_space_config("pageram", ENDIANNESS_LITTLE, 8, 11, 0, NULL, *ADDRESS_MAP_NAME(cdp1869))
+{
+
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cdp1869_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const cdp1869_interface *intf = reinterpret_cast<const cdp1869_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<cdp1869_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&in_pal_ntsc_cb, 0, sizeof(in_pal_ntsc_cb));
+ memset(&out_prd_cb, 0, sizeof(out_prd_cb));
+ in_pcb_cb = NULL;
+ in_char_ram_cb = NULL;
+ out_char_ram_cb = NULL;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cdp1869_device::device_start()
+{
+ // get the screen device
+ m_screen = machine().device<screen_device>(screen_tag);
+ assert(m_screen != NULL);
+
+ // resolve callbacks
+ m_in_pal_ntsc_func.resolve(in_pal_ntsc_cb, *this);
+ m_out_prd_func.resolve(out_prd_cb, *this);
+ m_in_pcb_func = in_pcb_cb;
+ m_in_char_ram_func = in_char_ram_cb;
+ m_out_char_ram_func = out_char_ram_cb;
+
+ // allocate timers
+ m_prd_timer = timer_alloc();
+ update_prd_changed_timer();
+
+ // initialize palette
+ initialize_palette();
+
+ // create sound stream
+ m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate());
+
+ // register for state saving
+ save_item(NAME(m_prd));
+ save_item(NAME(m_dispoff));
+ save_item(NAME(m_fresvert));
+ save_item(NAME(m_freshorz));
+ save_item(NAME(m_cmem));
+ save_item(NAME(m_dblpage));
+ save_item(NAME(m_line16));
+ save_item(NAME(m_line9));
+ save_item(NAME(m_cfc));
+ save_item(NAME(m_col));
+ save_item(NAME(m_bkg));
+ save_item(NAME(m_pma));
+ save_item(NAME(m_hma));
+ save_item(NAME(m_signal));
+ save_item(NAME(m_incr));
+ save_item(NAME(m_toneoff));
+ save_item(NAME(m_wnoff));
+ save_item(NAME(m_tonediv));
+ save_item(NAME(m_tonefreq));
+ save_item(NAME(m_toneamp));
+ save_item(NAME(m_wnfreq));
+ save_item(NAME(m_wnamp));
+}
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post-load
+//-------------------------------------------------
+
+void cdp1869_device::device_post_load()
+{
+ update_prd_changed_timer();
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void cdp1869_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_out_prd_func(param);
+ m_prd = param;
+
+ update_prd_changed_timer();
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *cdp1869_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == 0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// initialize_palette - initialize palette
+//-------------------------------------------------
+
+void cdp1869_device::initialize_palette()
+{
+ // color-on-color display (CFC=0)
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ palette_set_color(machine(), i, get_rgb(i, i, 15));
+ }
+
+ // tone-on-tone display (CFC=1)
+ for (int c = 0; c < 8; c++)
+ {
+ for (int l = 0; l < 8; l++)
+ {
+ palette_set_color(machine(), i, get_rgb(i, c, l));
+ i++;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// sound_stream_update - handle update requests for
+// our sound stream
+//-------------------------------------------------
+
+void cdp1869_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ // reset the output stream
+ memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+
+ INT16 signal = m_signal;
+ stream_sample_t *buffer = outputs[0];
+
+ if (!m_toneoff && m_toneamp)
+ {
+ double frequency = (clock() / 2) / (512 >> m_tonefreq) / (m_tonediv + 1);
+// double amplitude = m_toneamp * ((0.78*5) / 15);
+
+ int rate = machine().sample_rate() / 2;
+
+ /* get progress through wave */
+ int incr = m_incr;
+
+ if (signal < 0)
+ {
+ signal = -(m_toneamp * (0x07fff / 15));
+ }
+ else
+ {
+ signal = m_toneamp * (0x07fff / 15);
+ }
+
+ while( samples-- > 0 )
+ {
+ *buffer++ = signal;
+ incr -= frequency;
+ while( incr < 0 )
+ {
+ incr += rate;
+ signal = -signal;
+ }
+ }
+
+ /* store progress through wave */
+ m_incr = incr;
+ m_signal = signal;
+ }
+/*
+ if (!m_wnoff)
+ {
+ double amplitude = m_wnamp * ((0.78*5) / 15);
+
+ for (int wndiv = 0; wndiv < 128; wndiv++)
+ {
+ double frequency = (clock() / 2) / (4096 >> m_wnfreq) / (wndiv + 1):
+
+ sum_square_wave(buffer, frequency, amplitude);
+ }
+ }
+*/
+
+}
+
+
+//-------------------------------------------------
+// draw_line - draw character line
+//-------------------------------------------------
+
+void cdp1869_device::draw_line(bitmap_ind16 &bitmap, const rectangle &rect, int x, int y, UINT8 data, int color)
+{
+ int i;
+
+ data <<= 2;
+
+ for (i = 0; i < CDP1869_CHAR_WIDTH; i++)
+ {
+ if (data & 0x80)
+ {
+ bitmap.pix16(y, x) = color;
+
+ if (!m_fresvert)
+ {
+ bitmap.pix16(y + 1, x) = color;
+ }
+
+ if (!m_freshorz)
+ {
+ bitmap.pix16(y, x + 1) = color;
+
+ if (!m_fresvert)
+ {
+ bitmap.pix16(y + 1, x + 1) = color;
+ }
+ }
+ }
+
+ if (!m_freshorz)
+ {
+ x++;
+ }
+
+ x++;
+
+ data <<= 1;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_char - draw character
+//-------------------------------------------------
+
+void cdp1869_device::draw_char(bitmap_ind16 &bitmap, const rectangle &rect, int x, int y, UINT16 pma)
+{
+ UINT8 pmd = read_page_ram_byte(pma);
+
+ for (UINT8 cma = 0; cma < get_lines(); cma++)
+ {
+ UINT8 data = read_char_ram_byte(pma, cma, pmd);
+
+ int ccb0 = BIT(data, CCB0);
+ int ccb1 = BIT(data, CCB1);
+ int pcb = read_pcb(pma, cma, pmd);
+
+ int color = get_pen(ccb0, ccb1, pcb);
+
+ draw_line(bitmap, rect, rect.min_x + x, rect.min_y + y, data, color);
+
+ y++;
+
+ if (!m_fresvert)
+ {
+ y++;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// out3_w - register 3 write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::out3_w )
+{
+ /*
+ bit description
+
+ 0 bkg green
+ 1 bkg blue
+ 2 bkg red
+ 3 cfc
+ 4 disp off
+ 5 colb0
+ 6 colb1
+ 7 fres horz
+ */
+
+ m_bkg = data & 0x07;
+ m_cfc = BIT(data, 3);
+ m_dispoff = BIT(data, 4);
+ m_col = (data & 0x60) >> 5;
+ m_freshorz = BIT(data, 7);
+}
+
+
+//-------------------------------------------------
+// out4_w - register 4 write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::out4_w )
+{
+ /*
+ bit description
+
+ 0 tone amp 2^0
+ 1 tone amp 2^1
+ 2 tone amp 2^2
+ 3 tone amp 2^3
+ 4 tone freq sel0
+ 5 tone freq sel1
+ 6 tone freq sel2
+ 7 tone off
+ 8 tone / 2^0
+ 9 tone / 2^1
+ 10 tone / 2^2
+ 11 tone / 2^3
+ 12 tone / 2^4
+ 13 tone / 2^5
+ 14 tone / 2^6
+ 15 always 0
+ */
+
+ m_toneamp = offset & 0x0f;
+ m_tonefreq = (offset & 0x70) >> 4;
+ m_toneoff = BIT(offset, 7);
+ m_tonediv = (offset & 0x7f00) >> 8;
+
+ m_stream->update();
+}
+
+
+//-------------------------------------------------
+// out5_w - register 5 write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::out5_w )
+{
+ /*
+ bit description
+
+ 0 cmem access mode
+ 1 x
+ 2 x
+ 3 9-line
+ 4 x
+ 5 16 line hi-res
+ 6 double page
+ 7 fres vert
+ 8 wn amp 2^0
+ 9 wn amp 2^1
+ 10 wn amp 2^2
+ 11 wn amp 2^3
+ 12 wn freq sel0
+ 13 wn freq sel1
+ 14 wn freq sel2
+ 15 wn off
+ */
+
+ m_cmem = BIT(offset, 0);
+ m_line9 = BIT(offset, 3);
+ m_line16 = BIT(offset, 5);
+ m_dblpage = BIT(offset, 6);
+ m_fresvert = BIT(offset, 7);
+ m_wnamp = (offset & 0x0f00) >> 8;
+ m_wnfreq = (offset & 0x7000) >> 12;
+ m_wnoff = BIT(offset, 15);
+
+ m_stream->update();
+
+ if (m_cmem)
+ {
+ m_pma = offset;
+ }
+ else
+ {
+ m_pma = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// out6_w - register 6 write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::out6_w )
+{
+ /*
+ bit description
+
+ 0 pma0 reg
+ 1 pma1 reg
+ 2 pma2 reg
+ 3 pma3 reg
+ 4 pma4 reg
+ 5 pma5 reg
+ 6 pma6 reg
+ 7 pma7 reg
+ 8 pma8 reg
+ 9 pma9 reg
+ 10 pma10 reg
+ 11 x
+ 12 x
+ 13 x
+ 14 x
+ 15 x
+ */
+
+ m_pma = offset & 0x7ff;
+}
+
+
+//-------------------------------------------------
+// out7_w - register 7 write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::out7_w )
+{
+ /*
+ bit description
+
+ 0 x
+ 1 x
+ 2 hma2 reg
+ 3 hma3 reg
+ 4 hma4 reg
+ 5 hma5 reg
+ 6 hma6 reg
+ 7 hma7 reg
+ 8 hma8 reg
+ 9 hma9 reg
+ 10 hma10 reg
+ 11 x
+ 12 x
+ 13 x
+ 14 x
+ 15 x
+ */
+
+ m_hma = offset & 0x7fc;
+}
+
+
+//-------------------------------------------------
+// char_ram_r - character RAM read
+//-------------------------------------------------
+
+READ8_MEMBER( cdp1869_device::char_ram_r )
+{
+ UINT8 cma = offset & 0x0f;
+ UINT16 pma;
+
+ if (m_cmem)
+ {
+ pma = get_pma();
+ }
+ else
+ {
+ pma = offset;
+ }
+
+ if (m_dblpage)
+ {
+ cma &= 0x07;
+ }
+
+ UINT8 pmd = read_page_ram_byte(pma);
+
+ return read_char_ram_byte(pma, cma, pmd);
+}
+
+
+//-------------------------------------------------
+// char_ram_w - character RAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::char_ram_w )
+{
+ UINT8 cma = offset & 0x0f;
+ UINT16 pma;
+
+ if (m_cmem)
+ {
+ pma = get_pma();
+ }
+ else
+ {
+ pma = offset;
+ }
+
+ if (m_dblpage)
+ {
+ cma &= 0x07;
+ }
+
+ UINT8 pmd = read_page_ram_byte(pma);
+
+ write_char_ram_byte(pma, cma, pmd, data);
+}
+
+
+//-------------------------------------------------
+// page_ram_r - page RAM read
+//-------------------------------------------------
+
+READ8_MEMBER( cdp1869_device::page_ram_r )
+{
+ UINT16 pma;
+
+ if (m_cmem)
+ {
+ pma = get_pma();
+ }
+ else
+ {
+ pma = offset;
+ }
+
+ return read_page_ram_byte(pma);
+}
+
+
+//-------------------------------------------------
+// page_ram_w - page RAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( cdp1869_device::page_ram_w )
+{
+ UINT16 pma;
+
+ if (m_cmem)
+ {
+ pma = get_pma();
+ }
+ else
+ {
+ pma = offset;
+ }
+
+ write_page_ram_byte(pma, data);
+}
+
+
+//-------------------------------------------------
+// page_ram_w - predisplay
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cdp1869_device::predisplay_r )
+{
+ return m_prd;
+}
+
+
+//-------------------------------------------------
+// pal_ntsc_r - PAL/NTSC
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cdp1869_device::pal_ntsc_r )
+{
+ return m_in_pal_ntsc_func();
+}
+
+
+//-------------------------------------------------
+// update_screen - update screen
+//-------------------------------------------------
+
+UINT32 cdp1869_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ rectangle screen_rect, outer;
+
+ if (is_ntsc())
+ {
+ outer.min_x = CDP1869_HBLANK_END;
+ outer.max_x = CDP1869_HBLANK_START - 1;
+ outer.min_y = CDP1869_SCANLINE_VBLANK_END_NTSC;
+ outer.max_y = CDP1869_SCANLINE_VBLANK_START_NTSC - 1;
+ screen_rect.min_x = CDP1869_SCREEN_START_NTSC;
+ screen_rect.max_x = CDP1869_SCREEN_END - 1;
+ screen_rect.min_y = CDP1869_SCANLINE_DISPLAY_START_NTSC;
+ screen_rect.max_y = CDP1869_SCANLINE_DISPLAY_END_NTSC - 1;
+ }
+ else
+ {
+ outer.min_x = CDP1869_HBLANK_END;
+ outer.max_x = CDP1869_HBLANK_START - 1;
+ outer.min_y = CDP1869_SCANLINE_VBLANK_END_PAL;
+ outer.max_y = CDP1869_SCANLINE_VBLANK_START_PAL - 1;
+ screen_rect.min_x = CDP1869_SCREEN_START_PAL;
+ screen_rect.max_x = CDP1869_SCREEN_END - 1;
+ screen_rect.min_y = CDP1869_SCANLINE_DISPLAY_START_PAL;
+ screen_rect.max_y = CDP1869_SCANLINE_DISPLAY_END_PAL - 1;
+ }
+
+ outer &= cliprect;
+ bitmap.fill(m_bkg, outer);
+
+ if (!m_dispoff)
+ {
+ int width = CDP1869_CHAR_WIDTH;
+ int height = get_lines();
+
+ if (!m_freshorz)
+ {
+ width *= 2;
+ }
+
+ if (!m_fresvert)
+ {
+ height *= 2;
+ }
+
+ int cols = m_freshorz ? CDP1869_COLUMNS_FULL : CDP1869_COLUMNS_HALF;
+ int rows = screen_rect.height() / height;
+
+ UINT16 pmemsize = get_pmemsize(cols, rows);
+ UINT16 addr = m_hma;
+
+ for (int sy = 0; sy < rows; sy++)
+ {
+ for (int sx = 0; sx < cols; sx++)
+ {
+ int x = sx * width;
+ int y = sy * height;
+
+ draw_char(bitmap, screen_rect, x, y, addr);
+
+ addr++;
+
+ if (addr == pmemsize) addr = 0;
+ }
+ }
+ }
+ return 0;
+}