diff options
Diffstat (limited to 'trunk/src/emu/sound/cdp1869.c')
-rw-r--r-- | trunk/src/emu/sound/cdp1869.c | 976 |
1 files changed, 976 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..5387abdf30a --- /dev/null +++ b/trunk/src/emu/sound/cdp1869.c @@ -0,0 +1,976 @@ +/********************************************************************** + + 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 ) + 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_t *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_ADDR16(bitmap, y, x) = color; + + if (!m_fresvert) + { + *BITMAP_ADDR16(bitmap, y + 1, x) = color; + } + + if (!m_freshorz) + { + *BITMAP_ADDR16(bitmap, y, x + 1) = color; + + if (!m_fresvert) + { + *BITMAP_ADDR16(bitmap, y + 1, x + 1) = color; + } + } + } + + if (!m_freshorz) + { + x++; + } + + x++; + + data <<= 1; + } +} + + +//------------------------------------------------- +// draw_char - draw character +//------------------------------------------------- + +void cdp1869_device::draw_char(bitmap_t *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 +//------------------------------------------------- + +void cdp1869_device::update_screen(bitmap_t *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; + } + + sect_rect(&outer, cliprect); + bitmap_fill(bitmap, &outer, m_bkg); + + 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.max_y - screen_rect.min_y + 1) / 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; + } + } + } +} |