// license:BSD-3-Clause // copyright-holders:James Wallace /*************************************************************************** Bellfruit dotmatrix driver, (under heavy construction !!!) 19-08-2005: Re-Animator 25-08-2005: Fixed feedback through sc2 input line A.G.E Code Copyright J. Wallace and the AGEMAME Development Team. Visit http://www.mameworld.net/agemame/ for more information. Standard dm01 memorymap hex |r/w| D D D D D D D D | location | | 7 6 5 4 3 2 1 0 | function -----------+---+-----------------+----------------------------------------- 0000-1FFF |R/W| D D D D D D D D | RAM (8k) -----------+---+-----------------+----------------------------------------- 2000 |R/W| D D D D D D D D | control register -----------+---+-----------------+----------------------------------------- 2800 |R/W| D D D D D D D D | mux -----------+---+-----------------+----------------------------------------- 3000 |R/W| D D D D D D D D | communication with mainboard -----------+---+-----------------+----------------------------------------- 3800 |R/W| D D D D D D D D | ??? -----------+---+-----------------+----------------------------------------- 4000-FFFF | W | D D D D D D D D | ROM (48k) -----------+---+-----------------+----------------------------------------- TODO: - find out clockspeed of CPU - sometimes screen isn't cleared, is the a clear bit missing? ***************************************************************************/ #include "emu.h" #include "cpu/m6809/m6809.h" #include "bfm_dm01.h" // local vars ///////////////////////////////////////////////////////////// #define DM_MAXLINES 21 #ifdef MAME_DEBUG #define VERBOSE 1 #else #define VERBOSE 0 #endif #define LOG(x) do { if (VERBOSE) logerror x; } while (0) DEFINE_DEVICE_TYPE(BFM_DM01, bfm_dm01_device, "bfm_dm01", "BFM Dotmatrix 01") bfm_dm01_device::bfm_dm01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, BFM_DM01, tag, owner, clock), m_matrixcpu(*this, "matrix"), m_screen(*this, "dmd"), m_palette(*this, "palette_lcd"), m_data_avail(0), m_control(0), m_xcounter(0), m_busy(0), m_comdata(0), m_busy_cb(*this) { for (auto & elem : m_segbuffer) elem = 0; for (auto & elem : m_scanline) elem = 0; } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void bfm_dm01_device::device_start() { if(!m_screen->started()) throw device_missing_dependencies(); if(!m_palette->started()) throw device_missing_dependencies(); m_busy_cb.resolve_safe(); save_item(NAME(m_data_avail)); save_item(NAME(m_control)); save_item(NAME(m_xcounter)); save_item(NAME(m_busy)); save_item(NAME(m_comdata)); for (int i = 0; i < 65; i++) save_item(NAME(m_segbuffer), i); for (int i = 0; i < BYTES_PER_ROW; i++) save_item(NAME(m_scanline), i); m_screen->register_screen_bitmap(m_tmpbitmap); m_palette->set_pen_color(0, rgb_t(0, 0, 0)); // background m_palette->set_pen_color(1, rgb_t(15, 1, 1)); // off dot m_palette->set_pen_color(2, rgb_t(255, 31, 31)); // on dot } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void bfm_dm01_device::device_reset() { m_busy = 0; m_control = 0; m_xcounter = 0; m_data_avail = 0; m_busy_cb(m_busy); } /////////////////////////////////////////////////////////////////////////// int bfm_dm01_device::read_data(void) { int data = m_comdata; m_data_avail = 0; return data; } /////////////////////////////////////////////////////////////////////////// READ8_MEMBER( bfm_dm01_device::control_r ) { return 0; } /////////////////////////////////////////////////////////////////////////// WRITE8_MEMBER( bfm_dm01_device::control_w ) { int changed = m_control ^ data; m_control = data; if ( changed & 2 ) { // reset horizontal counter if ( !(data & 2) ) { //int offset = 0; m_xcounter = 0; } } if ( changed & 8 ) { // bit 3 changed = BUSY line if ( data & 8 ) m_busy = 0; else m_busy = 1; m_busy_cb(m_busy); } } /////////////////////////////////////////////////////////////////////////// READ8_MEMBER( bfm_dm01_device::mux_r ) { return 0; } /////////////////////////////////////////////////////////////////////////// WRITE8_MEMBER( bfm_dm01_device::mux_w ) { g_profiler.start(PROFILER_USER2); if ( m_xcounter < BYTES_PER_ROW ) { m_scanline[m_xcounter] = data; m_xcounter++; } if ( m_xcounter == 9 ) { int row = ((0xFF^data) & 0x7C) >> 2; // 7C = 000001111100 m_scanline[8] &= 0x80;//filter all other bits if ( (row >= 0) && (row < DM_MAXLINES) ) { int p = 0; while ( p < (BYTES_PER_ROW) ) { uint8_t d = m_scanline[p]; for (int bitpos=0; bitpos <8; bitpos++) { if (((p*8)+bitpos) <65) { if (d & 1<<(7-bitpos)) m_segbuffer[(p*8)+bitpos]=1; else m_segbuffer[(p*8)+bitpos]=0; } } p++; } uint16_t* pix = &m_tmpbitmap.pix16(row*2); uint16_t* pix2 = &m_tmpbitmap.pix16((row*2)+1); for (int pos=0;pos<65;pos++) { pix[0 + (pos * 2)] = m_segbuffer[(pos)]+1; pix[1 + (pos * 2)] = 0; pix2[0 + (pos * 2)] = 0; pix2[1 + (pos * 2)] = 0; } } } g_profiler.stop(); } /////////////////////////////////////////////////////////////////////////// READ8_MEMBER( bfm_dm01_device::comm_r ) { int result = 0; if ( m_data_avail ) { result = read_data(); #ifdef UNUSED_FUNCTION if ( m_data_avail() ) { cpu_set_irq_line(1, M6809_IRQ_LINE, ASSERT_LINE ); // trigger IRQ } #endif } return result; } /////////////////////////////////////////////////////////////////////////// WRITE8_MEMBER( bfm_dm01_device::comm_w ) { } /////////////////////////////////////////////////////////////////////////// READ8_MEMBER( bfm_dm01_device::unknown_r ) { return 0; } /////////////////////////////////////////////////////////////////////////// WRITE8_MEMBER( bfm_dm01_device::unknown_w ) { m_matrixcpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE ); //? } /////////////////////////////////////////////////////////////////////////// void bfm_dm01_device::bfm_dm01_memmap(address_map &map) { map(0x0000, 0x1fff).ram(); // 8k RAM map(0x2000, 0x2000).rw(FUNC(bfm_dm01_device::control_r), FUNC(bfm_dm01_device::control_w)); // control reg map(0x2800, 0x2800).rw(FUNC(bfm_dm01_device::mux_r), FUNC(bfm_dm01_device::mux_w)); // mux map(0x3000, 0x3000).rw(FUNC(bfm_dm01_device::comm_r), FUNC(bfm_dm01_device::comm_w)); // map(0x3800, 0x3800).rw(FUNC(bfm_dm01_device::unknown_r), FUNC(bfm_dm01_device::unknown_w)); // ??? map(0x4000, 0xFfff).rom(); // 48k ROM } uint32_t bfm_dm01_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { copybitmap(bitmap, m_tmpbitmap, 0, 0, 0, 0, cliprect); return 0; } INTERRUPT_GEN_MEMBER( bfm_dm01_device::nmi_line_assert ) { m_matrixcpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); } void bfm_dm01_device::device_add_mconfig(machine_config &config) { MC6809(config, m_matrixcpu, 8000000); // MC68B09CP (clock unknown) m_matrixcpu->set_addrmap(AS_PROGRAM, &bfm_dm01_device::bfm_dm01_memmap); m_matrixcpu->set_periodic_int(FUNC(bfm_dm01_device::nmi_line_assert), attotime::from_hz(1500)); /* generate 1500 NMI's per second ?? what is the exact freq?? */ PALETTE(config, m_palette).set_entries(3); SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_refresh_hz(60); m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); m_screen->set_size(65*2, 21*2); m_screen->set_visarea(0, 65*2-1, 0, 21*2-1); m_screen->set_screen_update(FUNC(bfm_dm01_device::screen_update)); m_screen->set_palette(m_palette); } /////////////////////////////////////////////////////////////////////////// void bfm_dm01_device::writedata(uint8_t data) { m_comdata = data; m_data_avail = 1; //pulse IRQ line m_matrixcpu->set_input_line(M6809_IRQ_LINE, HOLD_LINE ); // trigger IRQ } /////////////////////////////////////////////////////////////////////////// int bfm_dm01_device::busy(void) { return m_data_avail; }