// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************
RCA CDP1869/1870/1876 Video Interface System (VIS) emulation
**********************************************************************
_____ _____
TPA 1 |* \_/ | 40 Vdd
TPB 2 | | 39 PMSEL
_MRD 3 | | 38 _PMWR
_MWR 4 | | 37 CMSEL
MA0/8 5 | | 36 _CMWR
MA1/9 6 | | 35 PMA0
MA2/10 7 | | 34 PMA1
MA3/11 8 | | 33 PMA2
MA4/12 9 | | 32 PMA3
MA5/13 10 | | 31 PMA4
MA6/14 11 | CDP1869 | 30 PMA5
MA7/15 12 | | 29 PMA6
N0 13 | | 28 PMA7
N1 14 | | 27 PMA8
N2 15 | | 26 PMA9
_H SYNC 16 | | 25 CMA3/PMA10
_DISPLAY 17 | | 24 CMA2
_ADDRSTB 18 | | 23 CMA1
SOUND 19 | | 22 CMA0
Vss 20 |_____________| 21 _N=3
_____ _____
_PREDISPLAY 1 |* \_/ | 40 Vdd
_DISPLAY 2 | | 39 PAL/_NTSC
PCB 3 | | 38 CPUCLK
CCB1 4 | | 37 XTAL (DOT)
BUS7 5 | | 36 _XTAL (DOT)
CCB0 6 | | 35 _ADDRSTB
BUS6 7 | | 34 _MRD
CDB5 8 | | 33 TPB
BUS5 9 | | 32 CMSEL
CDB4 10 | | 31 BURST
BUS4 11 | CDP1870 | 30 _H SYNC
CDB3 12 | | 29 _COMPSYNC
BUS3 13 | | 28 LUM
CDB2 14 | | 27 PAL CHROM
BUS2 15 | | 26 NTSC CHROM
CDB1 16 | | 25 _XTAL (CHROM)
BUS1 17 | | 24 XTAL (CHROM)
CDB0 18 | | 23 _EMS
BUS0 19 | | 22 _EVS
Vss 20 |_____________| 21 _N=3
_____ _____
_PREDISPLAY 1 |* \_/ | 40 Vdd
_DISPLAY 2 | | 39 PAL/_NTSC
PCB 3 | | 38 CPUCLK
CCB1 4 | | 37 XTAL (DOT)
BUS7 5 | | 36 _XTAL (DOT)
CCB0 6 | | 35 _ADDRSTB
BUS6 7 | | 34 _MRD
CDB5 8 | | 33 TPB
BUS5 9 | | 32 CMSEL
CDB4 10 | | 31 BURST
BUS4 11 | CDP1876 | 30 _H SYNC
CDB3 12 | | 29 _COMPSYNC
BUS3 13 | | 28 RED
CDB2 14 | | 27 BLUE
BUS2 15 | | 26 GREEN
CDB1 16 | | 25 _XTAL (CHROM)
BUS1 17 | | 24 XTAL (CHROM)
CDB0 18 | | 23 _EMS
BUS0 19 | | 22 _EVS
Vss 20 |_____________| 21 _N=3
**********************************************************************/
#ifndef MAME_SOUND_CDP1869_H
#define MAME_SOUND_CDP1869_H
#pragma once
#include "emupal.h"
#include "screen.h"
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_CDP1869_ADD(_tag, _pixclock, _map) \
MCFG_DEVICE_ADD(_tag, CDP1869, _pixclock) \
MCFG_DEVICE_ADDRESS_MAP(0, _map)
#define MCFG_CDP1869_SCREEN_PAL_ADD(_cdptag, _tag, _clock) \
MCFG_SCREEN_ADD(_tag, RASTER) \
MCFG_SCREEN_UPDATE_DEVICE(_cdptag, cdp1869_device, screen_update) \
MCFG_SCREEN_RAW_PARAMS(_clock, cdp1869_device::SCREEN_WIDTH, cdp1869_device::HBLANK_END, cdp1869_device::HBLANK_START, cdp1869_device::TOTAL_SCANLINES_PAL, cdp1869_device::SCANLINE_VBLANK_END_PAL, cdp1869_device::SCANLINE_VBLANK_START_PAL)
#define MCFG_CDP1869_SCREEN_NTSC_ADD(_cdptag, _tag, _clock) \
MCFG_SCREEN_ADD(_tag, RASTER) \
MCFG_SCREEN_UPDATE_DEVICE(_cdptag, cdp1869_device, screen_update) \
MCFG_SCREEN_RAW_PARAMS(_clock, cdp1869_device::SCREEN_WIDTH, cdp1869_device::HBLANK_END, cdp1869_device::HBLANK_START, cdp1869_device::TOTAL_SCANLINES_NTSC, cdp1869_device::SCANLINE_VBLANK_END_NTSC, cdp1869_device::SCANLINE_VBLANK_START_NTSC)
#define MCFG_CDP1869_SET_SCREEN MCFG_VIDEO_SET_SCREEN
#define CDP1869_CHAR_RAM_READ_MEMBER(name) uint8_t name(uint16_t pma, uint8_t cma, uint8_t pmd)
#define CDP1869_CHAR_RAM_WRITE_MEMBER(name) void name(uint16_t pma, uint8_t cma, uint8_t pmd, uint8_t data)
#define CDP1869_PCB_READ_MEMBER(name) int name(uint16_t pma, uint8_t cma, uint8_t pmd)
#define MCFG_CDP1869_PAL_NTSC_CALLBACK(_read) \
devcb = &downcast<cdp1869_device &>(*device).set_pal_ntsc_rd_callback(DEVCB_##_read);
#define MCFG_CDP1869_PRD_CALLBACK(_write) \
devcb = &downcast<cdp1869_device &>(*device).set_prd_wr_callback(DEVCB_##_write);
#define MCFG_CDP1869_COLOR_CLOCK(_clk) \
downcast<cdp1869_device &>(*device).set_color_clock(_clk);
#define MCFG_CDP1869_CHAR_RAM_READ_OWNER(_class, _method) \
downcast<cdp1869_device &>(*device).set_char_ram_read(cdp1869_device::char_ram_read_delegate(&_class::_method, #_class "::" #_method, this));
#define MCFG_CDP1869_CHAR_RAM_WRITE_OWNER(_class, _method) \
downcast<cdp1869_device &>(*device).set_char_ram_write(cdp1869_device::char_ram_write_delegate(&_class::_method, #_class "::" #_method, this));
#define MCFG_CDP1869_CHAR_PCB_READ_OWNER(_class, _method) \
downcast<cdp1869_device &>(*device).set_pcb_read(cdp1869_device::pcb_read_delegate(&_class::_method, #_class "::" #_method, this));
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> cdp1869_device
class cdp1869_device : public device_t,
public device_sound_interface,
public device_video_interface,
public device_memory_interface
{
public:
static constexpr auto DOT_CLK_PAL = XTAL(5'626'000);
static constexpr auto DOT_CLK_NTSC = XTAL(5'670'000);
static constexpr auto COLOR_CLK_PAL = XTAL(8'867'236);
static constexpr auto COLOR_CLK_NTSC = XTAL(7'159'090);
static constexpr auto CPU_CLK_PAL = DOT_CLK_PAL / 2;
static constexpr auto CPU_CLK_NTSC = DOT_CLK_NTSC / 2;
static constexpr unsigned CHAR_WIDTH = 6;
static constexpr unsigned HSYNC_START = 56 * CHAR_WIDTH;
static constexpr unsigned HSYNC_END = 60 * CHAR_WIDTH;
static constexpr unsigned HBLANK_START = 54 * CHAR_WIDTH;
static constexpr unsigned HBLANK_END = 5 * CHAR_WIDTH;
static constexpr unsigned SCREEN_START_PAL = 9 * CHAR_WIDTH;
static constexpr unsigned SCREEN_START_NTSC = 10 * CHAR_WIDTH;
static constexpr unsigned SCREEN_START = 10 * CHAR_WIDTH;
static constexpr unsigned SCREEN_END = 50 * CHAR_WIDTH;
static constexpr unsigned SCREEN_WIDTH = 60 * CHAR_WIDTH;
static constexpr unsigned TOTAL_SCANLINES_PAL = 312;
static constexpr unsigned SCANLINE_VBLANK_START_PAL = 304;
static constexpr unsigned SCANLINE_VBLANK_END_PAL = 10;
static constexpr unsigned SCANLINE_VSYNC_START_PAL = 308;
static constexpr unsigned SCANLINE_VSYNC_END_PAL = 312;
static constexpr unsigned SCANLINE_DISPLAY_START_PAL = 44;
static constexpr unsigned SCANLINE_DISPLAY_END_PAL = 260;
static constexpr unsigned SCANLINE_PREDISPLAY_START_PAL = 43;
static constexpr unsigned SCANLINE_PREDISPLAY_END_PAL = 260;
static constexpr unsigned VISIBLE_SCANLINES_PAL = SCANLINE_DISPLAY_END_PAL - SCANLINE_DISPLAY_START_PAL;
static constexpr unsigned TOTAL_SCANLINES_NTSC = 262;
static constexpr unsigned SCANLINE_VBLANK_START_NTSC = 252;
static constexpr unsigned SCANLINE_VBLANK_END_NTSC = 10;
static constexpr unsigned SCANLINE_VSYNC_START_NTSC = 258;
static constexpr unsigned SCANLINE_VSYNC_END_NTSC = 262;
static constexpr unsigned SCANLINE_DISPLAY_START_NTSC = 36;
static constexpr unsigned SCANLINE_DISPLAY_END_NTSC = 228;
static constexpr unsigned SCANLINE_PREDISPLAY_START_NTSC = 35;
static constexpr unsigned SCANLINE_PREDISPLAY_END_NTSC = 228;
static constexpr unsigned VISIBLE_SCANLINES_NTSC = SCANLINE_DISPLAY_END_NTSC - SCANLINE_DISPLAY_START_NTSC;
static constexpr unsigned PALETTE_LENGTH = 8+64;
typedef device_delegate<uint8_t (uint16_t pma, uint8_t cma, uint8_t pmd)> char_ram_read_delegate;
typedef device_delegate<void (uint16_t pma, uint8_t cma, uint8_t pmd, uint8_t data)> char_ram_write_delegate;
typedef device_delegate<int (uint16_t pma, uint8_t cma, uint8_t pmd)> pcb_read_delegate;
// construction/destruction
cdp1869_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
template <class Object> devcb_base &set_pal_ntsc_rd_callback(Object &&cb) { return m_read_pal_ntsc.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_prd_wr_callback(Object &&cb) { return m_write_prd.set_callback(std::forward<Object>(cb)); }
template <typename Object> void set_char_ram_read(Object &&cb) { m_in_char_ram_func = std::forward<Object>(cb); }
template <typename Object> void set_char_ram_write(Object &&cb) { m_out_char_ram_func = std::forward<Object>(cb); }
template <typename Object> void set_pcb_read(Object &&cb) { m_in_pcb_func = std::forward<Object>(cb); }
void set_color_clock(int color_clock) { m_color_clock = color_clock; }
void set_color_clock(const XTAL &xtal) { xtal.validate("selecting cdp1869 clock"); set_color_clock(xtal.value()); }
virtual void io_map(address_map &map);
virtual void char_map(address_map &map);
virtual void page_map(address_map &map);
DECLARE_WRITE8_MEMBER( out3_w );
DECLARE_WRITE8_MEMBER( out4_w );
DECLARE_WRITE8_MEMBER( out5_w );
DECLARE_WRITE8_MEMBER( out6_w );
DECLARE_WRITE8_MEMBER( out7_w );
DECLARE_READ8_MEMBER( char_ram_r );
DECLARE_WRITE8_MEMBER( char_ram_w );
DECLARE_READ8_MEMBER( page_ram_r );
DECLARE_WRITE8_MEMBER( page_ram_w );
DECLARE_READ_LINE_MEMBER( predisplay_r );
DECLARE_READ_LINE_MEMBER( pal_ntsc_r );
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void cdp1869(address_map &map);
protected:
// device-level overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_post_load() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
// device_sound_interface callbacks
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
inline bool is_ntsc();
inline uint8_t read_page_ram_byte(offs_t address);
inline void write_page_ram_byte(offs_t address, uint8_t data);
inline uint8_t read_char_ram_byte(offs_t pma, offs_t cma, uint8_t pmd);
inline void write_char_ram_byte(offs_t pma, offs_t cma, uint8_t pmd, uint8_t data);
inline int read_pcb(offs_t pma, offs_t cma, uint8_t pmd);
inline void update_prd_changed_timer();
inline rgb_t get_rgb(int i, int c, int l);
inline int get_lines();
inline uint16_t get_pmemsize(int cols, int rows);
inline uint16_t get_pma();
inline int get_pen(int ccb0, int ccb1, int pcb);
void draw_line(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, uint8_t data, int color);
void draw_char(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, uint16_t pma);
private:
devcb_read_line m_read_pal_ntsc;
devcb_write_line m_write_prd;
pcb_read_delegate m_in_pcb_func;
char_ram_read_delegate m_in_char_ram_func;
char_ram_write_delegate m_out_char_ram_func;
int m_color_clock;
//address_space *m_page_ram;
emu_timer *m_prd_timer;
sound_stream *m_stream;
required_device<palette_device> m_palette;
const address_space_config m_space_config;
// video state
int m_prd; // predisplay
int m_dispoff; // display off
int m_fresvert; // full resolution vertical
int m_freshorz; // full resolution horizontal
int m_cmem; // character memory access mode
int m_dblpage; // double page mode
int m_line16; // 16-line hi-res mode
int m_line9; // 9 line mode
int m_cfc; // color format control
uint8_t m_col; // character color control
uint8_t m_bkg; // background color
uint16_t m_pma; // page memory address
uint16_t m_hma; // home memory address
// sound state
int16_t m_signal; // current signal
int m_incr; // initial wave state
int m_toneoff; // tone off
int m_wnoff; // white noise off
uint8_t m_tonediv; // tone divisor
uint8_t m_tonefreq; // tone range select
uint8_t m_toneamp; // tone output amplitude
uint8_t m_wnfreq; // white noise range select
uint8_t m_wnamp; // white noise output amplitude
DECLARE_PALETTE_INIT(cdp1869);
};
// device type definition
DECLARE_DEVICE_TYPE(CDP1869, cdp1869_device)
#endif // MAME_SOUND_CDP1869_H