// license:BSD-3-Clause// copyright-holders:David Haywood#include"emu.h"#include"machine/megacd.h"#include"machine/nvram.h"#include"megacd.lh"#define SEGACD_CLOCK 12500000#define RAM_MODE_2MEG (0)#define RAM_MODE_1MEG (2)#define DMA_PCM (0x0400)#define DMA_PRG (0x0500)#define DMA_WRAM (0x0700)// irq3 timer#define CHECK_SCD_LV3_INTERRUPT \ if (m_lc89510_temp->get_segacd_irq_mask() & 0x08) \ { \ m_scdcpu->set_input_line(3, HOLD_LINE); \ }// from master#define CHECK_SCD_LV2_INTERRUPT \ if (m_lc89510_temp->get_segacd_irq_mask() & 0x04) \ { \ m_scdcpu->set_input_line(2, HOLD_LINE); \ }// gfx convert#define CHECK_SCD_LV1_INTERRUPT \ if (m_lc89510_temp->get_segacd_irq_mask() & 0x02) \ { \ m_scdcpu->set_input_line(1, HOLD_LINE); \ }#define SEGACD_IRQ3_TIMER_SPEED (attotime::from_nsec(m_irq3_timer_reg*30720))DEFINE_DEVICE_TYPE(SEGA_SEGACD_US,sega_segacd_us_device,"segacd_us","Sega Sega CD (US)")DEFINE_DEVICE_TYPE(SEGA_SEGACD_JAPAN,sega_segacd_japan_device,"segacd_japan","Sega Mega-CD (Japan)")DEFINE_DEVICE_TYPE(SEGA_SEGACD_EUROPE,sega_segacd_europe_device,"segacd_europe","Sega Mega-CD (PAL)")/* Callback when the genesis enters interrupt code */IRQ_CALLBACK_MEMBER(sega_segacd_device::segacd_sub_int_callback){if(irqline==2){// clear this bitm_a12000_halt_reset_reg&=~0x0100;m_scdcpu->set_input_line(2,CLEAR_LINE);}return(0x60+irqline*4)/4;// vector address}TIMER_DEVICE_CALLBACK_MEMBER(sega_segacd_device::irq3_timer_callback){CHECK_SCD_LV3_INTERRUPTm_irq3_timer->adjust(SEGACD_IRQ3_TIMER_SPEED);}TIMER_DEVICE_CALLBACK_MEMBER(sega_segacd_device::stamp_timer_callback){//printf("stamp_timer_callback\n");CHECK_SCD_LV1_INTERRUPTsegacd_conversion_active=0;// this ends up as 0 after processing (soniccd bonus stage)segacd_imagebuffer_vdot_size=0;}voidsega_segacd_device::segacd_map(address_map&map){map(0x000000,0x07ffff).ram().share("prgram");map(0x080000,0x0bffff).rw(FUNC(sega_segacd_device::segacd_sub_dataram_part1_r),FUNC(sega_segacd_device::segacd_sub_dataram_part1_w)).share("dataram");map(0x0c0000,0x0dffff).rw(FUNC(sega_segacd_device::segacd_sub_dataram_part2_r),FUNC(sega_segacd_device::segacd_sub_dataram_part2_w));//AM_SHARE("dataram2")map(0xfe0000,0xfe3fff).rw(FUNC(sega_segacd_device::backupram_r),FUNC(sega_segacd_device::backupram_w)).umask16(0x00ff);// backup RAM, odd bytes only!map(0xff0000,0xff001f).w("rfsnd",FUNC(rf5c68_device::rf5c68_w)).umask16(0x00ff);// PCM, RF5C164map(0xff0020,0xff003f).r("rfsnd",FUNC(rf5c68_device::rf5c68_r)).umask16(0x00ff);map(0xff2000,0xff3fff).rw("rfsnd",FUNC(rf5c68_device::rf5c68_mem_r),FUNC(rf5c68_device::rf5c68_mem_w)).umask16(0x00ff);// PCM, RF5C164map(0xff8000,0xff8001).rw(FUNC(sega_segacd_device::segacd_sub_led_ready_r),FUNC(sega_segacd_device::segacd_sub_led_ready_w));map(0xff8002,0xff8003).rw(FUNC(sega_segacd_device::segacd_sub_memory_mode_r),FUNC(sega_segacd_device::segacd_sub_memory_mode_w));map(0xff8004,0xff8005).rw("tempcdc",FUNC(lc89510_temp_device::segacd_cdc_mode_address_r),FUNC(lc89510_temp_device::segacd_cdc_mode_address_w));map(0xff8006,0xff8007).rw("tempcdc",FUNC(lc89510_temp_device::segacd_cdc_data_r),FUNC(lc89510_temp_device::segacd_cdc_data_w));map(0xff8008,0xff8009).r("tempcdc",FUNC(lc89510_temp_device::cdc_data_sub_r));map(0xff800a,0xff800b).rw(FUNC(sega_segacd_device::segacd_dmaaddr_r),FUNC(sega_segacd_device::segacd_dmaaddr_w));// DMA Address (not CDC, used in conjunction with)map(0xff800c,0xff800d).rw(FUNC(sega_segacd_device::segacd_stopwatch_timer_r),FUNC(sega_segacd_device::segacd_stopwatch_timer_w));// Stopwatch timermap(0xff800e,0xff800f).rw(FUNC(sega_segacd_device::segacd_comms_flags_r),FUNC(sega_segacd_device::segacd_comms_flags_subcpu_w));map(0xff8010,0xff801f).rw(FUNC(sega_segacd_device::segacd_comms_sub_part1_r),FUNC(sega_segacd_device::segacd_comms_sub_part1_w));map(0xff8020,0xff802f).rw(FUNC(sega_segacd_device::segacd_comms_sub_part2_r),FUNC(sega_segacd_device::segacd_comms_sub_part2_w));map(0xff8030,0xff8031).rw(FUNC(sega_segacd_device::segacd_irq3timer_r),FUNC(sega_segacd_device::segacd_irq3timer_w));// Timer W/INT3map(0xff8032,0xff8033).rw("tempcdc",FUNC(lc89510_temp_device::segacd_irq_mask_r),FUNC(lc89510_temp_device::segacd_irq_mask_w));map(0xff8034,0xff8035).rw("tempcdc",FUNC(lc89510_temp_device::segacd_cdfader_r),FUNC(lc89510_temp_device::segacd_cdfader_w));// CD Fadermap(0xff8036,0xff8037).rw("tempcdc",FUNC(lc89510_temp_device::segacd_cdd_ctrl_r),FUNC(lc89510_temp_device::segacd_cdd_ctrl_w));map(0xff8038,0xff8041).r("tempcdc",FUNC(lc89510_temp_device::segacd_cdd_rx_r));map(0xff8042,0xff804b).w("tempcdc",FUNC(lc89510_temp_device::segacd_cdd_tx_w));map(0xff804d,0xff804d).rw(FUNC(sega_segacd_device::font_color_r),FUNC(sega_segacd_device::font_color_w));map(0xff804e,0xff804f).ram().share("font_bits");map(0xff8050,0xff8057).r(FUNC(sega_segacd_device::font_converted_r));map(0xff8058,0xff8059).rw(FUNC(sega_segacd_device::segacd_stampsize_r),FUNC(sega_segacd_device::segacd_stampsize_w));// Stamp sizemap(0xff805a,0xff805b).rw(FUNC(sega_segacd_device::segacd_stampmap_base_address_r),FUNC(sega_segacd_device::segacd_stampmap_base_address_w));// Stamp map base addressmap(0xff805c,0xff805d).rw(FUNC(sega_segacd_device::segacd_imagebuffer_vcell_size_r),FUNC(sega_segacd_device::segacd_imagebuffer_vcell_size_w));// Image buffer V cell sizemap(0xff805e,0xff805f).rw(FUNC(sega_segacd_device::segacd_imagebuffer_start_address_r),FUNC(sega_segacd_device::segacd_imagebuffer_start_address_w));// Image buffer start addressmap(0xff8060,0xff8061).rw(FUNC(sega_segacd_device::segacd_imagebuffer_offset_r),FUNC(sega_segacd_device::segacd_imagebuffer_offset_w));map(0xff8062,0xff8063).rw(FUNC(sega_segacd_device::segacd_imagebuffer_hdot_size_r),FUNC(sega_segacd_device::segacd_imagebuffer_hdot_size_w));// Image buffer H dot sizemap(0xff8064,0xff8065).rw(FUNC(sega_segacd_device::segacd_imagebuffer_vdot_size_r),FUNC(sega_segacd_device::segacd_imagebuffer_vdot_size_w));// Image buffer V dot sizemap(0xff8066,0xff8067).w(FUNC(sega_segacd_device::segacd_trace_vector_base_address_w));// Trace vector base address// AM_RANGE(0xff8068, 0xff8069) // Subcode address// AM_RANGE(0xff8100, 0xff817f) // Subcode buffer area// AM_RANGE(0xff8180, 0xff81ff) // mirror of subcode buffer area}voidsega_segacd_device::segacd_pcm_map(address_map&map){map.unmap_value_high();map(0x0000,0xffff).ram();}// the tiles in RAM are 8x8 tiles// they are referenced in the cell look-up map as either 16x16 or 32x32 tiles (made of 4 / 16 8x8 tiles)#define SEGACD_BYTES_PER_TILE16 (128)#define SEGACD_BYTES_PER_TILE32 (512)#define SEGACD_NUM_TILES16 (0x40000/SEGACD_BYTES_PER_TILE16)#define SEGACD_NUM_TILES32 (0x40000/SEGACD_BYTES_PER_TILE32)#define _16x16_SEQUENCE_1 { STEP8(0, 4), STEP8(512, 4) },#define _16x16_SEQUENCE_1_FLIP { STEP8(512+28, -4), STEP8(28, -4) },#define _16x16_SEQUENCE_2 { STEP16(0, 32) },#define _16x16_SEQUENCE_2_FLIP { STEP16(15*32, -32) },#define _16x16_START \{ \ 16,16, \ SEGACD_NUM_TILES16, \ 4, \ { STEP4(0,1) },#define _16x16_END \ 8*128 \};#define _32x32_START \{ \ 32,32, \ SEGACD_NUM_TILES32, \ 4, \ { STEP4(0,1) },#define _32x32_END \ 8*512 \};#define _32x32_SEQUENCE_1 { STEP8(0, 4), STEP8(1024, 4), STEP8(2048, 4), STEP8(3072, 4) },#define _32x32_SEQUENCE_1_FLIP { STEP8(3072+28, -4), STEP8(2048+28, -4), STEP8(1024+28, -4), STEP8(28, -4) },#define _32x32_SEQUENCE_2 { STEP32(0, 32) },#define _32x32_SEQUENCE_2_FLIP { STEP32(31*32, -32) },/* 16x16 decodes */staticconstgfx_layoutsega_16x16_r00_f0_layout=_16x16_START_16x16_SEQUENCE_1_16x16_SEQUENCE_2_16x16_ENDstaticconstgfx_layoutsega_16x16_r01_f0_layout=_16x16_START_16x16_SEQUENCE_2_16x16_SEQUENCE_1_FLIP_16x16_ENDstaticconstgfx_layoutsega_16x16_r10_f0_layout=_16x16_START_16x16_SEQUENCE_1_FLIP_16x16_SEQUENCE_2_FLIP_16x16_ENDstaticconstgfx_layoutsega_16x16_r11_f0_layout=_16x16_START_16x16_SEQUENCE_2_FLIP_16x16_SEQUENCE_1_16x16_ENDstaticconstgfx_layoutsega_16x16_r00_f1_layout=_16x16_START_16x16_SEQUENCE_1_FLIP_16x16_SEQUENCE_2_16x16_ENDstaticconstgfx_layoutsega_16x16_r01_f1_layout=_16x16_START_16x16_SEQUENCE_2_16x16_SEQUENCE_1_16x16_ENDstaticconstgfx_layoutsega_16x16_r10_f1_layout=_16x16_START_16x16_SEQUENCE_1_16x16_SEQUENCE_2_FLIP_16x16_ENDstaticconstgfx_layoutsega_16x16_r11_f1_layout=_16x16_START_16x16_SEQUENCE_2_FLIP_16x16_SEQUENCE_1_FLIP_16x16_END/* 32x32 decodes */staticconstgfx_layoutsega_32x32_r00_f0_layout=_32x32_START_32x32_SEQUENCE_1_32x32_SEQUENCE_2_32x32_ENDstaticconstgfx_layoutsega_32x32_r01_f0_layout=_32x32_START_32x32_SEQUENCE_2_32x32_SEQUENCE_1_FLIP_32x32_ENDstaticconstgfx_layoutsega_32x32_r10_f0_layout=_32x32_START_32x32_SEQUENCE_1_FLIP_32x32_SEQUENCE_2_FLIP_32x32_ENDstaticconstgfx_layoutsega_32x32_r11_f0_layout=_32x32_START_32x32_SEQUENCE_2_FLIP_32x32_SEQUENCE_1_32x32_ENDstaticconstgfx_layoutsega_32x32_r00_f1_layout=_32x32_START_32x32_SEQUENCE_1_FLIP_32x32_SEQUENCE_2_32x32_ENDstaticconstgfx_layoutsega_32x32_r01_f1_layout=_32x32_START_32x32_SEQUENCE_2_32x32_SEQUENCE_1_32x32_ENDstaticconstgfx_layoutsega_32x32_r10_f1_layout=_32x32_START_32x32_SEQUENCE_1_32x32_SEQUENCE_2_FLIP_32x32_ENDstaticconstgfx_layoutsega_32x32_r11_f1_layout=_32x32_START_32x32_SEQUENCE_2_FLIP_32x32_SEQUENCE_1_FLIP_32x32_ENDstaticGFXDECODE_START(gfx_segacd)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r00_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r01_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r10_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r11_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r00_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r11_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r10_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_16x16_r01_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r00_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r01_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r10_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r11_f0_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r00_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r11_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r10_f1_layout,0,0)GFXDECODE_DEVICE_RAM("dataram",0,sega_32x32_r01_f1_layout,0,0)GFXDECODE_ENDvoidsega_segacd_device::device_add_mconfig(machine_config&config){M68000(config,m_scdcpu,SEGACD_CLOCK);/* 12.5 MHz */m_scdcpu->set_addrmap(AS_PROGRAM,&sega_segacd_device::segacd_map);m_scdcpu->set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(sega_segacd_device::segacd_sub_int_callback),this));LC89510(config,"cdc",0);// cd controller// temporary until things are cleaned upLC89510_TEMP(config,m_lc89510_temp,0);// cd controllerm_lc89510_temp->set_cdc_do_dma_callback(FUNC(sega_segacd_device::SegaCD_CDC_Do_DMA),this);// hackm_lc89510_temp->set_cdrom_tag("^cdrom");m_lc89510_temp->set_68k_tag(m_scdcpu);TIMER(config,m_stopwatch_timer).configure_generic(timer_device::expired_delegate());//stopwatch timerTIMER(config,m_stamp_timer).configure_generic(FUNC(sega_segacd_device::stamp_timer_callback));TIMER(config,m_irq3_timer).configure_generic(FUNC(sega_segacd_device::irq3_timer_callback));TIMER(config,m_dma_timer).configure_generic(FUNC(sega_segacd_device::dma_timer_callback));config.set_default_layout(layout_megacd);RF5C68(config,m_rfsnd,SEGACD_CLOCK);// RF5C164!m_rfsnd->add_route(0,":lspeaker",0.50);m_rfsnd->add_route(1,":rspeaker",0.50);m_rfsnd->set_addrmap(0,&sega_segacd_device::segacd_pcm_map);NVRAM(config,"backupram",nvram_device::DEFAULT_ALL_0);config.m_perfect_cpu_quantum=subtag("segacd_68k");// perfect sync to the fastest cpu}sega_segacd_device::sega_segacd_device(constmachine_config&mconfig,device_typetype,constchar*tag,device_t*owner,uint32_tclock):device_t(mconfig,type,tag,owner,clock),device_gfx_interface(mconfig,*this,gfx_segacd),m_scdcpu(*this,"segacd_68k"),m_hostcpu(*this,finder_base::DUMMY_TAG),m_rfsnd(*this,"rfsnd"),m_lc89510_temp(*this,"tempcdc"),m_stopwatch_timer(*this,"sw_timer"),m_stamp_timer(*this,"stamp_timer"),m_irq3_timer(*this,"irq3_timer"),m_dma_timer(*this,"dma_timer"),m_prgram(*this,"prgram"),m_dataram(*this,"dataram"),m_font_bits(*this,"font_bits"){}sega_segacd_us_device::sega_segacd_us_device(constmachine_config&mconfig,constchar*tag,device_t*owner,uint32_tclock):sega_segacd_device(mconfig,SEGA_SEGACD_US,tag,owner,clock){}sega_segacd_japan_device::sega_segacd_japan_device(constmachine_config&mconfig,constchar*tag,device_t*owner,uint32_tclock):sega_segacd_device(mconfig,SEGA_SEGACD_JAPAN,tag,owner,clock){}sega_segacd_europe_device::sega_segacd_europe_device(constmachine_config&mconfig,constchar*tag,device_t*owner,uint32_tclock):sega_segacd_device(mconfig,SEGA_SEGACD_EUROPE,tag,owner,clock){}inlinevoidsega_segacd_device::write_pixel(uint8_tpix,intpixeloffset){intshift=12-(4*(pixeloffset&0x3));uint16_tdatamask=(0x000f)<<shift;intoffset=pixeloffset>>3;if(pixeloffset&4)offset++;offset&=0x1ffff;switch(segacd_memory_priority_mode){case0x00:// normal write, just write the datam_dataram[offset]=m_dataram[offset]&~datamask;m_dataram[offset]|=pix<<shift;break;case0x01:// underwrite, only write if the existing data is 0if((m_dataram[offset]&datamask)==0x0000){m_dataram[offset]=m_dataram[offset]&~datamask;m_dataram[offset]|=pix<<shift;}break;case0x02:// overwrite, only write non-zero dataif(pix){m_dataram[offset]=m_dataram[offset]&~datamask;m_dataram[offset]|=pix<<shift;}break;default:case0x03:pix=machine().rand()&0x000f;m_dataram[offset]=m_dataram[offset]&~datamask;m_dataram[offset]|=pix<<shift;break;}}// 1meg / 2meg swap is interleaved swap, not half/half of the ram?// Wily Beamish and Citizen X appear to rely on this// however, it breaks the megacdj bios (megacd2j still works!)// (maybe that's a timing issue instead?)uint16_tsega_segacd_device::segacd_1meg_mode_word_read(intoffset,uint16_tmem_mask){offset*=2;if((offset&0x20000))offset+=1;offset&=0x1ffff;returnm_dataram[offset];}voidsega_segacd_device::segacd_1meg_mode_word_write(intoffset,uint16_tdata,uint16_tmem_mask,intuse_pm){offset*=2;if((offset&0x20000))offset+=1;offset&=0x1ffff;if(use_pm){// priority mode can apply when writing with the double up buffer mode// Jaguar XJ220 relies on thisswitch(segacd_memory_priority_mode){case0x00:// normal write, just write the dataCOMBINE_DATA(&m_dataram[offset]);break;case0x01:// underwrite, only write if the existing data is 0if(ACCESSING_BITS_8_15){if((m_dataram[offset]&0xf000)==0x0000)m_dataram[offset]|=(data)&0xf000;if((m_dataram[offset]&0x0f00)==0x0000)m_dataram[offset]|=(data)&0x0f00;}if(ACCESSING_BITS_0_7){if((m_dataram[offset]&0x00f0)==0x0000)m_dataram[offset]|=(data)&0x00f0;if((m_dataram[offset]&0x000f)==0x0000)m_dataram[offset]|=(data)&0x000f;}break;case0x02:// overwrite, only write non-zero dataif(ACCESSING_BITS_8_15){if((data)&0xf000)m_dataram[offset]=(m_dataram[offset]&0x0fff)|((data)&0xf000);if((data)&0x0f00)m_dataram[offset]=(m_dataram[offset]&0xf0ff)|((data)&0x0f00);}if(ACCESSING_BITS_0_7){if((data)&0x00f0)m_dataram[offset]=(m_dataram[offset]&0xff0f)|((data)&0x00f0);if((data)&0x000f)m_dataram[offset]=(m_dataram[offset]&0xfff0)|((data)&0x000f);}break;default:case0x03:// invalid?COMBINE_DATA(&m_dataram[offset]);break;}}else{COMBINE_DATA(&m_dataram[offset]);}}WRITE16_MEMBER(sega_segacd_device::scd_a12000_halt_reset_w){uint16_told_halt=m_a12000_halt_reset_reg;COMBINE_DATA(&m_a12000_halt_reset_reg);if(ACCESSING_BITS_0_7){// reset lineif(m_a12000_halt_reset_reg&0x0001){m_scdcpu->set_input_line(INPUT_LINE_RESET,CLEAR_LINE);if(!(old_halt&0x0001))printf("clear reset slave\n");}else{m_scdcpu->set_input_line(INPUT_LINE_RESET,ASSERT_LINE);if((old_halt&0x0001))printf("assert reset slave\n");}// request BUSif(m_a12000_halt_reset_reg&0x0002){m_scdcpu->set_input_line(INPUT_LINE_HALT,ASSERT_LINE);if(!(old_halt&0x0002))printf("halt slave\n");}else{m_scdcpu->set_input_line(INPUT_LINE_HALT,CLEAR_LINE);if((old_halt&0x0002))printf("resume slave\n");}}if(ACCESSING_BITS_8_15){if(m_a12000_halt_reset_reg&0x0100){CHECK_SCD_LV2_INTERRUPT}if(m_a12000_halt_reset_reg&0x8000){// not writable.. but can read irq mask here?//printf("m_a12000_halt_reset_reg & 0x8000 set\n"); // irq2 mask?}}}READ16_MEMBER(sega_segacd_device::scd_a12000_halt_reset_r){returnm_a12000_halt_reset_reg;}/******************************************************************************** MEMORY MODE CONTROL - main / sub sides differ!********************************************************************************///// we might need a delay on the segacd_maincpu_has_ram_access registers, as they actually indicate requests being made// so probably don't change instantly...//READ16_MEMBER(sega_segacd_device::scd_a12002_memory_mode_r){inttemp=scd_rammode;inttemp2=0;temp2|=(scd_mode_dmna_ret_flags>>(temp*4))&0x7;return(segacd_ram_writeprotect_bits<<8)|(segacd_4meg_prgbank<<6)|temp2;}/* I'm still not 100% clear how this works, the sources I have are a bit vague, it might still be incorrect in both modes for a simple way to swap blocks of ram between cpus this is stupidly convoluted */// DMNA = Decleration Mainram No Access (bit 0)// RET = Return access (bit 1)voidsega_segacd_device::scd_a12002_memory_mode_w_8_15(u8data){if(data&0xff00){printf("write protect bits set %02x\n",data);}segacd_ram_writeprotect_bits=data;}voidsega_segacd_device::scd_a12002_memory_mode_w_0_7(u8data){//printf("scd_a12002_memory_mode_w_0_7 %04x\n",data);segacd_4meg_prgbank=(data&0x00c0)>>6;if(scd_rammode&0x2){// ==0x2 (1 meg mode)if(!(data&2))// check DMNA bit{scd_mode_dmna_ret_flags|=0x2200;}}else// == 0x0 (2 meg mode){if(data&2)// check DMNA bit{scd_rammode=1;}}}WRITE16_MEMBER(sega_segacd_device::scd_a12002_memory_mode_w){if(ACCESSING_BITS_8_15)scd_a12002_memory_mode_w_8_15(data>>8);if(ACCESSING_BITS_0_7)scd_a12002_memory_mode_w_0_7(data&0xff);}READ16_MEMBER(sega_segacd_device::segacd_sub_memory_mode_r){inttemp=scd_rammode;inttemp2=0;temp2|=(scd_mode_dmna_ret_flags>>(temp*4))&0x7;return(segacd_ram_writeprotect_bits<<8)|(segacd_memory_priority_mode<<3)|temp2;}voidsega_segacd_device::segacd_sub_memory_mode_w_8_15(u8data){/* setting write protect bits from sub-cpu has no effect? */}voidsega_segacd_device::segacd_sub_memory_mode_w_0_7(u8data){segacd_memory_priority_mode=(data&0x0018)>>3;// If the mode bit is 0 then we're requesting a change to// 2Meg mode?//printf("segacd_sub_memory_mode_w_0_7 %04x\n",data);if(!(data&4))// check ram mode bit{// == 0x0 - 2 meg modescd_mode_dmna_ret_flags&=0xddff;if(data&1)// check RET{// If RET is set and the Mode bit in the write is set to 2M then we want to change to 2M mode// If we're already in 2M mode it has no effectscd_rammode=0;}else{// == 0x4 - 1 meg modeinttemp=scd_rammode;if(temp&2)// check ram mode{// == 0x2 - 1 meg modescd_mode_dmna_ret_flags&=0xffde;scd_rammode=temp&1;}}}else{// == 0x4 - 1 meg modedata&=1;inttemp=data;intscd_rammode_old=scd_rammode;data|=2;temp^=scd_rammode_old;scd_rammode=data;if(scd_rammode_old&2){// == 0x2 - already in 1 meg modeif(temp&1)// ret bit{scd_mode_dmna_ret_flags&=0xddff;}}else{// == 0x0 - currently in 2 meg modescd_mode_dmna_ret_flags&=0xddff;}}}WRITE16_MEMBER(sega_segacd_device::segacd_sub_memory_mode_w){//printf("segacd_sub_memory_mode_w %04x %04x\n", data, mem_mask);if(ACCESSING_BITS_8_15)segacd_sub_memory_mode_w_8_15(data>>8);if(ACCESSING_BITS_0_7)segacd_sub_memory_mode_w_0_7(data&0xff);}/******************************************************************************** END MEMORY MODE CONTROL********************************************************************************//******************************************************************************** COMMUNICATION FLAGS - main / sub sides differ in which bits are write only********************************************************************************/READ16_MEMBER(sega_segacd_device::segacd_comms_flags_r){returnsegacd_comms_flags;}WRITE16_MEMBER(sega_segacd_device::segacd_comms_flags_subcpu_w){if(ACCESSING_BITS_8_15)// Dragon's Lair{segacd_comms_flags=(segacd_comms_flags&0xff00)|((data>>8)&0x00ff);}// flashback needs low bits to take priority in word writesif(ACCESSING_BITS_0_7){segacd_comms_flags=(segacd_comms_flags&0xff00)|(data&0x00ff);}}WRITE16_MEMBER(sega_segacd_device::segacd_comms_flags_maincpu_w){if(ACCESSING_BITS_8_15){segacd_comms_flags=(segacd_comms_flags&0x00ff)|(data&0xff00);}// flashback needs low bits to take priority in word writesif(ACCESSING_BITS_0_7){segacd_comms_flags=(segacd_comms_flags&0x00ff)|((data<<8)&0xff00);}}READ16_MEMBER(sega_segacd_device::scd_4m_prgbank_ram_r){uint16_trealoffset=((segacd_4meg_prgbank*0x20000)/2)+offset;returnm_prgram[realoffset];}WRITE16_MEMBER(sega_segacd_device::scd_4m_prgbank_ram_w){uint16_trealoffset=((segacd_4meg_prgbank*0x20000)/2)+offset;// todo:// check for write protection? (or does that only apply to writes on the SubCPU side?COMBINE_DATA(&m_prgram[realoffset]);}READ16_MEMBER(sega_segacd_device::segacd_comms_main_part1_r){returnsegacd_comms_part1[offset];}WRITE16_MEMBER(sega_segacd_device::segacd_comms_main_part1_w){COMBINE_DATA(&segacd_comms_part1[offset]);}READ16_MEMBER(sega_segacd_device::segacd_comms_main_part2_r){returnsegacd_comms_part2[offset];}WRITE16_MEMBER(sega_segacd_device::segacd_comms_main_part2_w){printf("Sega CD main CPU attempting to write to read only comms regs\n");}READ16_MEMBER(sega_segacd_device::segacd_comms_sub_part1_r){returnsegacd_comms_part1[offset];}WRITE16_MEMBER(sega_segacd_device::segacd_comms_sub_part1_w){printf("Sega CD sub CPU attempting to write to read only comms regs\n");}READ16_MEMBER(sega_segacd_device::segacd_comms_sub_part2_r){returnsegacd_comms_part2[offset];}WRITE16_MEMBER(sega_segacd_device::segacd_comms_sub_part2_w){COMBINE_DATA(&segacd_comms_part2[offset]);}READ16_MEMBER(sega_segacd_device::segacd_main_dataram_part1_r){if((scd_rammode&2)==RAM_MODE_2MEG){// is this correct?if(!(scd_rammode&1)){//printf("segacd_main_dataram_part1_r in mode 0 %08x %04x\n", offset*2, m_dataram[offset]);returnm_dataram[offset];}else{//printf("Illegal: segacd_main_dataram_part1_r in mode 0 without permission\n");return0xffff;}}elseif((scd_rammode&2)==RAM_MODE_1MEG){if(offset<0x20000/2){// wordram accees//printf("Unspported: segacd_main_dataram_part1_r (word RAM) in mode 1\n");// ret bit set by sub cpu determines which half of WorkRAM we have access to?if(scd_rammode&1){returnsegacd_1meg_mode_word_read(offset+0x20000/2,mem_mask);}else{returnsegacd_1meg_mode_word_read(offset+0x00000/2,mem_mask);}}else{// converts data stored in bitmap format (in dataram) to be read out as tiles (for dma->vram purposes)// used by Heart of the Alienif(offset<0x30000/2)/* 0x20000 - 0x2ffff */// 512x256 bitmap. tilesoffset=bitswap<24>(offset,23,22,21,20,19,18,17,16,15,8,7,6,5,4,3,2,1,14,13,12,11,10,9,0);elseif(offset<0x38000/2)/* 0x30000 - 0x37fff */// 512x128 bitmap. tilesoffset=bitswap<24>(offset,23,22,21,20,19,18,17,16,15,14,7,6,5,4,3,2,1,13,12,11,10,9,8,0);elseif(offset<0x3c000/2)/* 0x38000 - 0x3bfff */// 512x64 bitmap. tilesoffset=bitswap<24>(offset,23,22,21,20,19,18,17,16,15,14,13,6,5,4,3,2,1,12,11,10,9,8,7,0);else/* 0x3c000 - 0x3dfff and 0x3e000 - 0x3ffff */// 512x32 bitmap (x2) -> tilesoffset=bitswap<24>(offset,23,22,21,20,19,18,17,16,15,14,13,12,5,4,3,2,1,11,10,9,8,7,6,0);offset&=0xffff;// HOTA cares about thisif(!(scd_rammode&1)){returnsegacd_1meg_mode_word_read(offset+0x00000/2,mem_mask);}else{returnsegacd_1meg_mode_word_read(offset+0x20000/2,mem_mask);}}}return0x0000;}WRITE16_MEMBER(sega_segacd_device::segacd_main_dataram_part1_w){if((scd_rammode&2)==RAM_MODE_2MEG){// is this correct?if(!(scd_rammode&1)){COMBINE_DATA(&m_dataram[offset]);segacd_mark_tiles_dirty(offset);}else{//printf("Illegal: segacd_main_dataram_part1_w in mode 0 without permission\n");}}elseif((scd_rammode&2)==RAM_MODE_1MEG){if(offset<0x20000/2){//printf("Unspported: segacd_main_dataram_part1_w (word RAM) in mode 1\n");// wordram accees// ret bit set by sub cpu determines which half of WorkRAM we have access to?if(scd_rammode&1){segacd_1meg_mode_word_write(offset+0x20000/2,data,mem_mask,0);}else{segacd_1meg_mode_word_write(offset+0x00000/2,data,mem_mask,0);}}else{// printf("Unspported: segacd_main_dataram_part1_w (Cell rearranged RAM) in mode 1 (illega?)\n"); // is this legal??}}}READ16_MEMBER(sega_segacd_device::scd_hint_vector_r){// printf("read HINT offset %d\n", offset);switch(offset&1){case0x00://return 0x00ff; // doesn't make much sense..return0xffff;case0x01:returnsegacd_hint_register;}return0;}READ16_MEMBER(sega_segacd_device::scd_a12006_hint_register_r){returnsegacd_hint_register;}WRITE16_MEMBER(sega_segacd_device::scd_a12006_hint_register_w){COMBINE_DATA(&segacd_hint_register);}voidsega_segacd_device::segacd_mark_tiles_dirty(intoffset){gfx(0)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(1)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(2)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(3)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(4)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(5)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(6)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(7)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE16));gfx(8)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(9)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(10)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(11)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(12)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(13)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(14)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));gfx(15)->mark_dirty((offset*2)/(SEGACD_BYTES_PER_TILE32));}// mame specific.. map registers to which tilemap cache we useintsega_segacd_device::segacd_get_active_stampmap_tilemap(void){return(segacd_stampsize&0x6)>>1;}voidsega_segacd_device::SCD_GET_TILE_INFO_16x16_1x1(int&tile_region,int&tileno,inttile_index){tile_region=0;// 16x16 tilesinttile_base=(segacd_stampmap_base_address&0xff80)*4;inttiledat=m_dataram[((tile_base>>1)+tile_index)&0x1ffff];tileno=tiledat&0x07ff;intxflip=tiledat&0x8000;introll=(tiledat&0x6000)>>13;if(xflip)tile_region+=4;tile_region+=roll;}voidsega_segacd_device::SCD_GET_TILE_INFO_32x32_1x1(int&tile_region,int&tileno,inttile_index){tile_region=8;// 32x32 tilesinttile_base=(segacd_stampmap_base_address&0xffe0)*4;inttiledat=m_dataram[((tile_base>>1)+tile_index)&0x1ffff];tileno=(tiledat&0x07fc)>>2;intxflip=tiledat&0x8000;introll=(tiledat&0x6000)>>13;if(xflip)tile_region+=4;tile_region+=roll;}voidsega_segacd_device::SCD_GET_TILE_INFO_16x16_16x16(int&tile_region,int&tileno,inttile_index){tile_region=0;// 16x16 tilesinttile_base=(0x8000)*4;// fixed address in this modeinttiledat=m_dataram[((tile_base>>1)+tile_index)&0x1ffff];tileno=tiledat&0x07ff;intxflip=tiledat&0x8000;introll=(tiledat&0x6000)>>13;if(xflip)tile_region+=4;tile_region+=roll;}voidsega_segacd_device::SCD_GET_TILE_INFO_32x32_16x16(int&tile_region,int&tileno,inttile_index){tile_region=8;// 32x32 tilesinttile_base=(segacd_stampmap_base_address&0xe000)*4;inttiledat=m_dataram[((tile_base>>1)+tile_index)&0x1ffff];tileno=(tiledat&0x07fc)>>2;intxflip=tiledat&0x8000;introll=(tiledat&0x6000)>>13;if(xflip)tile_region+=4;tile_region+=roll;}/* Tilemap callbacks (we don't actually use the tilemaps due to the excessive overhead */TILE_GET_INFO_MEMBER(sega_segacd_device::get_stampmap_16x16_1x1_tile_info){inttile_region,tileno;SCD_GET_TILE_INFO_16x16_1x1(tile_region,tileno,(int)tile_index);SET_TILE_INFO_MEMBER(tile_region,tileno,0,0);}TILE_GET_INFO_MEMBER(sega_segacd_device::get_stampmap_32x32_1x1_tile_info){inttile_region,tileno;SCD_GET_TILE_INFO_32x32_1x1(tile_region,tileno,(int)tile_index);SET_TILE_INFO_MEMBER(tile_region,tileno,0,0);}TILE_GET_INFO_MEMBER(sega_segacd_device::get_stampmap_16x16_16x16_tile_info){inttile_region,tileno;SCD_GET_TILE_INFO_16x16_16x16(tile_region,tileno,(int)tile_index);SET_TILE_INFO_MEMBER(tile_region,tileno,0,0);}TILE_GET_INFO_MEMBER(sega_segacd_device::get_stampmap_32x32_16x16_tile_info){inttile_region,tileno;SCD_GET_TILE_INFO_32x32_16x16(tile_region,tileno,(int)tile_index);SET_TILE_INFO_MEMBER(tile_region,tileno,0,0);}// non-tilemap functions to get a pixel from a 'tilemap' based on the above, but looking up each pixel, as to avoid the heavy cache bitmapinlineuint16_tsega_segacd_device::get_stampmap_16x16_1x1_tile_info_pixel(intxpos,intypos){constinttilesize=4;// 0xf pixelsconstinttilemapsize=0x0f;intwraparound=segacd_stampsize&1;intxtile=xpos>>tilesize;intytile=ypos>>tilesize;if(wraparound){// wrap...xtile&=tilemapsize;ytile&=tilemapsize;}else{if(xtile>tilemapsize)return0;if(xtile<0)return0;if(ytile>tilemapsize)return0;if(ytile<0)return0;}inttile_index=(ytile*(tilemapsize+1))+xtile;inttile_region,tileno;SCD_GET_TILE_INFO_16x16_1x1(tile_region,tileno,(int)tile_index);tileno%=gfx(tile_region)->elements();if(tileno==0)return0x00;constuint16_t*srcdata=gfx(tile_region)->get_data(tileno);returnsrcdata[((ypos&((1<<tilesize)-1))*(1<<tilesize))+(xpos&((1<<tilesize)-1))];}inlineuint16_tsega_segacd_device::get_stampmap_32x32_1x1_tile_info_pixel(intxpos,intypos){constinttilesize=5;// 0x1f pixelsconstinttilemapsize=0x07;intwraparound=segacd_stampsize&1;intxtile=xpos>>tilesize;intytile=ypos>>tilesize;if(wraparound){// wrap...xtile&=tilemapsize;ytile&=tilemapsize;}else{if(xtile>tilemapsize)return0;if(xtile<0)return0;if(ytile>tilemapsize)return0;if(ytile<0)return0;}inttile_index=(ytile*(tilemapsize+1))+xtile;inttile_region,tileno;SCD_GET_TILE_INFO_32x32_1x1(tile_region,tileno,(int)tile_index);tileno%=gfx(tile_region)->elements();if(tileno==0)return0x00;// does this apply in this mode?constuint16_t*srcdata=gfx(tile_region)->get_data(tileno);returnsrcdata[((ypos&((1<<tilesize)-1))*(1<<tilesize))+(xpos&((1<<tilesize)-1))];}inlineuint16_tsega_segacd_device::get_stampmap_16x16_16x16_tile_info_pixel(intxpos,intypos){constinttilesize=4;// 0xf pixelsconstinttilemapsize=0xff;intwraparound=segacd_stampsize&1;intxtile=xpos>>tilesize;intytile=ypos>>tilesize;if(wraparound){// wrap...xtile&=tilemapsize;ytile&=tilemapsize;}else{if(xtile>tilemapsize)return0;if(xtile<0)return0;if(ytile>tilemapsize)return0;if(ytile<0)return0;}inttile_index=(ytile*(tilemapsize+1))+xtile;inttile_region,tileno;SCD_GET_TILE_INFO_16x16_16x16(tile_region,tileno,(int)tile_index);tileno%=gfx(tile_region)->elements();if(tileno==0)return0x00;// does this apply in this modeconstuint16_t*srcdata=gfx(tile_region)->get_data(tileno);returnsrcdata[((ypos&((1<<tilesize)-1))*(1<<tilesize))+(xpos&((1<<tilesize)-1))];}inlineuint16_tsega_segacd_device::get_stampmap_32x32_16x16_tile_info_pixel(intxpos,intypos){constinttilesize=5;// 0x1f pixelsconstinttilemapsize=0x7f;intwraparound=segacd_stampsize&1;intxtile=xpos>>tilesize;intytile=ypos>>tilesize;if(wraparound){// wrap...xtile&=tilemapsize;ytile&=tilemapsize;}else{if(xtile>tilemapsize)return0;if(xtile<0)return0;if(ytile>tilemapsize)return0;if(ytile<0)return0;}inttile_index=(ytile*(tilemapsize+1))+xtile;inttile_region,tileno;SCD_GET_TILE_INFO_32x32_16x16(tile_region,tileno,(int)tile_index);tileno%=gfx(tile_region)->elements();if(tileno==0)return0x00;constuint16_t*srcdata=gfx(tile_region)->get_data(tileno);returnsrcdata[((ypos&((1<<tilesize)-1))*(1<<tilesize))+(xpos&((1<<tilesize)-1))];}WRITE16_MEMBER(sega_segacd_device::segacd_stopwatch_timer_w){if(data==0)m_stopwatch_timer->reset();elseprintf("Stopwatch timer %04x\n",data);}READ16_MEMBER(sega_segacd_device::segacd_stopwatch_timer_r){int32_tresult=(m_stopwatch_timer->time_elapsed()*ATTOSECONDS_TO_HZ(ATTOSECONDS_IN_USEC(30.72))).as_double();returnresult&0xfff;}READ16_MEMBER(sega_segacd_device::segacd_sub_led_ready_r){uint16_tretdata=0x0000;if(ACCESSING_BITS_0_7){retdata|=segacd_ready;}if(ACCESSING_BITS_8_15){retdata|=segacd_redled<<8;retdata|=segacd_greenled<<9;}returnretdata;}WRITE16_MEMBER(sega_segacd_device::segacd_sub_led_ready_w){if(ACCESSING_BITS_0_7){if((data&0x01)==0x00){// reset CD unit}}if(ACCESSING_BITS_8_15){segacd_redled=(data>>8)&1;segacd_greenled=(data>>9)&1;machine().output().set_value("red_led",segacd_redled^1);machine().output().set_value("green_led",segacd_greenled^1);//popmessage("%02x %02x",segacd_greenled,segacd_redled);}}READ16_MEMBER(sega_segacd_device::segacd_sub_dataram_part1_r){if((scd_rammode&2)==RAM_MODE_2MEG){// is this correct?if(scd_rammode&1)returnm_dataram[offset];else{//printf("Illegal: segacd_sub_dataram_part1_r in mode 0 without permission\n");return0x0000;}}elseif((scd_rammode&2)==RAM_MODE_1MEG){// printf("Unspported: segacd_sub_dataram_part1_r in mode 1 (Word RAM Expander - 1 Byte Per Pixel)\n");uint16_tdata;if(scd_rammode&1){data=segacd_1meg_mode_word_read(offset/2+0x00000/2,0xffff);}else{data=segacd_1meg_mode_word_read(offset/2+0x20000/2,0xffff);}if(offset&1){return((data&0x00f0)<<4)|((data&0x000f)<<0);}else{return((data&0xf000)>>4)|((data&0x0f00)>>8);}}return0x0000;}WRITE16_MEMBER(sega_segacd_device::segacd_sub_dataram_part1_w){if((scd_rammode&2)==RAM_MODE_2MEG){// is this correct?if(scd_rammode&1){COMBINE_DATA(&m_dataram[offset]);segacd_mark_tiles_dirty(offset);}else{//printf("Illegal: segacd_sub_dataram_part1_w in mode 0 without permission\n");}}elseif((scd_rammode&2)==RAM_MODE_1MEG){//if (mem_mask==0xffff)// printf("Unspported: segacd_sub_dataram_part1_w in mode 1 (Word RAM Expander - 1 Byte Per Pixel) %04x %04x\n", data, mem_mask);data=(data&0x000f)|(data&0x0f00)>>4;mem_mask=(mem_mask&0x000f)|(mem_mask&0x0f00)>>4;// data = ((data & 0x00f0) >>4) | (data & 0xf000)>>8;// mem_mask = ((mem_mask & 0x00f0)>>4) | ((mem_mask & 0xf000)>>8);if(!(offset&1)){data<<=8;mem_mask<<=8;}if(scd_rammode&1){segacd_1meg_mode_word_write(offset/2+0x00000/2,data,mem_mask,1);}else{segacd_1meg_mode_word_write(offset/2+0x20000/2,data,mem_mask,1);}// printf("Unspported: segacd_sub_dataram_part1_w in mode 1 (Word RAM Expander - 1 Byte Per Pixel) %04x\n", data);}}READ16_MEMBER(sega_segacd_device::segacd_sub_dataram_part2_r){if((scd_rammode&2)==RAM_MODE_2MEG){//printf("ILLEGAL segacd_sub_dataram_part2_r in mode 0\n"); // not mapped to anything in mode 0return0x0000;}elseif((scd_rammode&2)==RAM_MODE_1MEG){//printf("Unsupported: segacd_sub_dataram_part2_r in mode 1 (Word RAM)\n");// ret bit set by sub cpu determines which half of WorkRAM we have access to?if(scd_rammode&1){returnsegacd_1meg_mode_word_read(offset+0x00000/2,mem_mask);}else{returnsegacd_1meg_mode_word_read(offset+0x20000/2,mem_mask);}}return0x0000;}WRITE16_MEMBER(sega_segacd_device::segacd_sub_dataram_part2_w){if((scd_rammode&2)==RAM_MODE_2MEG){printf("ILLEGAL segacd_sub_dataram_part2_w in mode 0\n");// not mapped to anything in mode 0}elseif((scd_rammode&2)==RAM_MODE_1MEG){//printf("Unsupported: segacd_sub_dataram_part2_w in mode 1 (Word RAM)\n");// ret bit set by sub cpu determines which half of WorkRAM we have access to?if(scd_rammode&1){segacd_1meg_mode_word_write(offset+0x00000/2,data,mem_mask,0);}else{segacd_1meg_mode_word_write(offset+0x20000/2,data,mem_mask,0);}}}READ16_MEMBER(sega_segacd_device::segacd_stampsize_r){uint16_tretdata=0x0000;retdata|=segacd_conversion_active<<15;retdata|=segacd_stampsize&0x7;returnretdata;}WRITE16_MEMBER(sega_segacd_device::segacd_stampsize_w){//printf("segacd_stampsize_w %04x %04x\n",data, mem_mask);if(ACCESSING_BITS_0_7){segacd_stampsize=data&0x07;//if (data & 0xf8)// printf(" unused bits (LSB) set in stampsize!\n");//if (data&1) printf(" Repeat On\n");//else printf(" Repeat Off\n");//if (data&2) printf(" 32x32 dots\n");//else printf(" 16x16 dots\n");//if (data&4) printf(" 16x16 screens\n");//else printf(" 1x1 screen\n");}if(ACCESSING_BITS_8_15){//if (data&0xff00) printf(" unused bits (MSB) set in stampsize!\n");}}// these functions won't cope if//// the lower 3 bits of segacd_imagebuffer_hdot_size are set// this really needs to be doing it's own lookups rather than depending on the inefficient MAME cache..inlineuint16_tsega_segacd_device::read_pixel_from_stampmap(bitmap_ind16*srcbitmap,intx,inty){/* if (!srcbitmap) { return machine().rand(); } if (x >= srcbitmap->width) return 0; if (y >= srcbitmap->height) return 0; uint16_t* cacheptr = &srcbitmap->pix16(y, x); return cacheptr[0] & 0xf;*/switch(segacd_get_active_stampmap_tilemap()&3){case0x00:returnget_stampmap_16x16_1x1_tile_info_pixel(x,y);case0x01:returnget_stampmap_32x32_1x1_tile_info_pixel(x,y);case0x02:returnget_stampmap_16x16_16x16_tile_info_pixel(x,y);case0x03:returnget_stampmap_32x32_16x16_tile_info_pixel(x,y);}return0;}// this triggers the conversion operation, which will cause an IRQ1 when finishedWRITE16_MEMBER(sega_segacd_device::segacd_trace_vector_base_address_w){if((scd_rammode&2)==RAM_MODE_1MEG){printf("ILLEGAL: segacd_trace_vector_base_address_w %04x %04x in mode 1!\n",data,mem_mask);}//printf("segacd_trace_vector_base_address_w %04x %04x\n",data,mem_mask);{intbase=(data&0xfffe)*4;//printf("actual base = %06x\n", base + 0x80000);// nasty nasty nasty//segacd_mark_stampmaps_dirty();segacd_conversion_active=1;// todo: proper time calculationm_stamp_timer->adjust(attotime::from_nsec(30000));intline;//bitmap_ind16 *srcbitmap = segacd_stampmap[segacd_get_active_stampmap_tilemap(->pixmap()]);bitmap_ind16*srcbitmap=nullptr;uint32_tbufferstart=((segacd_imagebuffer_start_address&0xfff8)*2)<<3;for(line=0;line<segacd_imagebuffer_vdot_size;line++){intcurrbase=base+line*0x8;// are the 256x256 tile modes using the same sign bits?int16_ttilemapxoffs,tilemapyoffs;int16_tdeltax,deltay;tilemapxoffs=m_dataram[(currbase+0x0)>>1];tilemapyoffs=m_dataram[(currbase+0x2)>>1];deltax=m_dataram[(currbase+0x4)>>1];// x-zoomdeltay=m_dataram[(currbase+0x6)>>1];// rotation//printf("%06x: %04x (%d) %04x (%d) %04x %04x\n", currbase, tilemapxoffs, tilemapxoffs>>3, tilemapyoffs, tilemapyoffs>>3, deltax, deltay);intxbase=tilemapxoffs*256;intybase=tilemapyoffs*256;intcount;for(count=0;count<(segacd_imagebuffer_hdot_size);count++){//int i;uint16_tpix=0x0;pix=read_pixel_from_stampmap(srcbitmap,xbase>>(3+8),ybase>>(3+8));xbase+=deltax;ybase+=deltay;// clamp to 24-bits, seems to be required for all the intro effects to workxbase&=0xffffff;ybase&=0xffffff;intcountx=count+(segacd_imagebuffer_offset&0x7);uint32_toffset;offset=bufferstart+((((segacd_imagebuffer_vcell_size+1)*0x10)*(countx>>3))<<3);offset+=((line*2)<<3);offset+=(segacd_imagebuffer_offset&0x38)<<1;offset+=countx&0x7;write_pixel(pix,offset);segacd_mark_tiles_dirty(offset>>3);segacd_mark_tiles_dirty((offset>>3)+1);}}}}// actually just the low 8 bits?READ16_MEMBER(sega_segacd_device::segacd_imagebuffer_vdot_size_r){returnsegacd_imagebuffer_vdot_size;}WRITE16_MEMBER(sega_segacd_device::segacd_imagebuffer_vdot_size_w){//printf("segacd_imagebuffer_vdot_size_w %04x %04x\n",data,mem_mask);COMBINE_DATA(&segacd_imagebuffer_vdot_size);}// basically the 'tilemap' base address, for the 16x16 / 32x32 source tilesREAD16_MEMBER(sega_segacd_device::segacd_stampmap_base_address_r){// different bits are valid in different modes, but I'm guessing the register// always returns all the bits set, even if they're not used?returnsegacd_stampmap_base_address;}WRITE16_MEMBER(sega_segacd_device::segacd_stampmap_base_address_w){// WORD ACCESS// low 3 bitsa aren't used, are they stored?COMBINE_DATA(&segacd_stampmap_base_address);}// destination for 'rendering' the section of the tilemap(stampmap) requestedREAD16_MEMBER(sega_segacd_device::segacd_imagebuffer_start_address_r){returnsegacd_imagebuffer_start_address;}WRITE16_MEMBER(sega_segacd_device::segacd_imagebuffer_start_address_w){COMBINE_DATA(&segacd_imagebuffer_start_address);//int base = (segacd_imagebuffer_start_address & 0xfffe) * 4;//printf("segacd_imagebuffer_start_address_w %04x %04x (actual base = %06x)\n", data, segacd_imagebuffer_start_address, base);}READ16_MEMBER(sega_segacd_device::segacd_imagebuffer_offset_r){returnsegacd_imagebuffer_offset;}WRITE16_MEMBER(sega_segacd_device::segacd_imagebuffer_offset_w){COMBINE_DATA(&segacd_imagebuffer_offset);// printf("segacd_imagebuffer_offset_w %04x\n", segacd_imagebuffer_offset);}READ16_MEMBER(sega_segacd_device::segacd_imagebuffer_vcell_size_r){returnsegacd_imagebuffer_vcell_size;}WRITE16_MEMBER(sega_segacd_device::segacd_imagebuffer_vcell_size_w){COMBINE_DATA(&segacd_imagebuffer_vcell_size);}READ16_MEMBER(sega_segacd_device::segacd_imagebuffer_hdot_size_r){returnsegacd_imagebuffer_hdot_size;}WRITE16_MEMBER(sega_segacd_device::segacd_imagebuffer_hdot_size_w){COMBINE_DATA(&segacd_imagebuffer_hdot_size);}READ16_MEMBER(sega_segacd_device::segacd_irq3timer_r){returnm_irq3_timer_reg;// always returns value written, not current counter!}WRITE16_MEMBER(sega_segacd_device::segacd_irq3timer_w){if(ACCESSING_BITS_0_7){m_irq3_timer_reg=data&0xff;// time = reg * 30.72 usif(m_irq3_timer_reg)m_irq3_timer->adjust(SEGACD_IRQ3_TIMER_SPEED);elsem_irq3_timer->adjust(attotime::never);//printf("segacd_irq3timer_w %02x\n", segacd_m_irq3_timer_reg);}}READ8_MEMBER(sega_segacd_device::backupram_r){returnm_backupram[offset];}WRITE8_MEMBER(sega_segacd_device::backupram_w){m_backupram[offset]=data;}READ8_MEMBER(sega_segacd_device::font_color_r){returnm_font_color;}WRITE8_MEMBER(sega_segacd_device::font_color_w){m_font_color=data;}READ16_MEMBER(sega_segacd_device::font_converted_r){intscbg=(m_font_color&0x0f);intscfg=(m_font_color&0xf0)>>4;uint16_tretdata=0;intbit;for(bit=0;bit<4;bit++){if(*m_font_bits&((0x1000>>offset*4)<<bit))retdata|=scfg<<(bit*4);elseretdata|=scbg<<(bit*4);}returnretdata;}voidsega_segacd_device::device_start(){address_space&space=m_hostcpu->space(AS_PROGRAM);m_backupram.resize(0x2000);subdevice<nvram_device>("backupram")->set_base(&m_backupram[0],0x2000);segacd_4meg_prgbank=0;space.unmap_readwrite(0x020000,0x3fffff);space.install_read_handler(0x0020000,0x003ffff,read16_delegate(FUNC(sega_segacd_device::scd_4m_prgbank_ram_r),this));space.install_write_handler(0x0020000,0x003ffff,write16_delegate(FUNC(sega_segacd_device::scd_4m_prgbank_ram_w),this));space.install_readwrite_handler(0x200000,0x23ffff,read16_delegate(FUNC(sega_segacd_device::segacd_main_dataram_part1_r),this),write16_delegate(FUNC(sega_segacd_device::segacd_main_dataram_part1_w),this));// RAM shared with subspace.install_readwrite_handler(0xa12000,0xa12001,read16_delegate(FUNC(sega_segacd_device::scd_a12000_halt_reset_r),this),write16_delegate(FUNC(sega_segacd_device::scd_a12000_halt_reset_w),this));// sub-cpu controlspace.install_readwrite_handler(0xa12002,0xa12003,read16_delegate(FUNC(sega_segacd_device::scd_a12002_memory_mode_r),this),write16_delegate(FUNC(sega_segacd_device::scd_a12002_memory_mode_w),this));// memory mode / write protect//space.install_readwrite_handler(0xa12004, 0xa12005, read16_delegate(FUNC(sega_segacd_device::segacd_cdc_mode_address_r),this), write16_delegate(FUNC(sega_segacd_device::segacd_cdc_mode_address_w),this));space.install_readwrite_handler(0xa12006,0xa12007,read16_delegate(FUNC(sega_segacd_device::scd_a12006_hint_register_r),this),write16_delegate(FUNC(sega_segacd_device::scd_a12006_hint_register_w),this));// where HINT points on main CPU//space.install_read_handler (0xa12008, 0xa12009, read16_delegate(FUNC(sega_segacd_device::cdc_data_main_r),this));space.install_readwrite_handler(0xa1200c,0xa1200d,read16_delegate(FUNC(sega_segacd_device::segacd_stopwatch_timer_r),this),write16_delegate(FUNC(sega_segacd_device::segacd_stopwatch_timer_w),this));// starbladspace.install_readwrite_handler(0xa1200e,0xa1200f,read16_delegate(FUNC(sega_segacd_device::segacd_comms_flags_r),this),write16_delegate(FUNC(sega_segacd_device::segacd_comms_flags_maincpu_w),this));// communication flags blockspace.install_readwrite_handler(0xa12010,0xa1201f,read16_delegate(FUNC(sega_segacd_device::segacd_comms_main_part1_r),this),write16_delegate(FUNC(sega_segacd_device::segacd_comms_main_part1_w),this));space.install_readwrite_handler(0xa12020,0xa1202f,read16_delegate(FUNC(sega_segacd_device::segacd_comms_main_part2_r),this),write16_delegate(FUNC(sega_segacd_device::segacd_comms_main_part2_w),this));space.install_read_handler(0x0000070,0x0000073,read16_delegate(FUNC(sega_segacd_device::scd_hint_vector_r),this));segacd_stampmap[0]=&machine().tilemap().create(*this,tilemap_get_info_delegate(FUNC(sega_segacd_device::get_stampmap_16x16_1x1_tile_info),this),TILEMAP_SCAN_ROWS,16,16,16,16);segacd_stampmap[1]=&machine().tilemap().create(*this,tilemap_get_info_delegate(FUNC(sega_segacd_device::get_stampmap_32x32_1x1_tile_info),this),TILEMAP_SCAN_ROWS,32,32,8,8);segacd_stampmap[2]=&machine().tilemap().create(*this,tilemap_get_info_delegate(FUNC(sega_segacd_device::get_stampmap_16x16_16x16_tile_info),this),TILEMAP_SCAN_ROWS,16,16,256,256);// 128kb!segacd_stampmap[3]=&machine().tilemap().create(*this,tilemap_get_info_delegate(FUNC(sega_segacd_device::get_stampmap_32x32_16x16_tile_info),this),TILEMAP_SCAN_ROWS,32,32,128,128);// 32kb!// todo register save state stuff}READ16_MEMBER(sega_segacd_device::segacd_dmaaddr_r){returnm_dmaaddr;}WRITE16_MEMBER(sega_segacd_device::segacd_dmaaddr_w){COMBINE_DATA(&m_dmaaddr);}voidsega_segacd_device::device_reset(){m_scdcpu->set_input_line(INPUT_LINE_RESET,ASSERT_LINE);m_scdcpu->set_input_line(INPUT_LINE_HALT,ASSERT_LINE);segacd_hint_register=0xffff;// -1m_a12000_halt_reset_reg=0x0000;scd_rammode=0;scd_mode_dmna_ret_flags=0x5421;m_lc89510_temp->reset_cd();m_dmaaddr=0;m_dma_timer->adjust(attotime::zero);m_total_scanlines=262;// HACK!!!! timegal, anettfut, roadaven end up with the SubCPU waiting in a loop for *something*// overclocking the CPU, even at the point where the game is hung, allows them to continue and boot// I'm not sure what the source of this timing problem is, it's not using IRQ3 or StopWatch at the// time. Changing the CDHock timer to 50hz from 75hz also stops the hang, but then the video is// too slow and has bad sound. -- Investigate!m_scdcpu->set_clock_scale(1.5000f);// initialize some stuff on resetsegacd_ram_writeprotect_bits=0;segacd_4meg_prgbank=0;segacd_memory_priority_mode=0;segacd_stampsize=0;segacd_imagebuffer_vdot_size=0;segacd_imagebuffer_vcell_size=0;segacd_imagebuffer_hdot_size=0;segacd_conversion_active=0;segacd_stampmap_base_address=0;segacd_imagebuffer_start_address=0;segacd_imagebuffer_offset=0;segacd_comms_flags=0x0000;segacd_redled=0;segacd_greenled=0;segacd_ready=1;// actually set 100ms after startup?m_irq3_timer_reg=0;m_stamp_timer->adjust(attotime::never);m_irq3_timer->adjust(attotime::never);}// todo: tidy upTIMER_DEVICE_CALLBACK_MEMBER(sega_segacd_device::dma_timer_callback){// todo: accurate timing of this!#define RATE 256m_lc89510_temp->CDC_Do_DMA(machine(),RATE);// timed reset of flagsscd_mode_dmna_ret_flags|=0x0021;m_dma_timer->adjust(attotime::from_hz(m_framerate)/m_total_scanlines);}// todo: tidy up, too many CDC internals herevoidsega_segacd_device::SegaCD_CDC_Do_DMA(int&dmacount,uint8_t*CDC_BUFFER,uint16_t&dma_addrc,uint16_t&destination){intlength=dmacount;uint16_t*dest;intsrcoffset=0;intdstoffset=0;boolPCM_DMA=false;if(destination==DMA_PCM){dstoffset=(m_dmaaddr&0x03FF)<<2;PCM_DMA=true;}else{dstoffset=(m_dmaaddr&0xFFFF)<<3;}while(dmacount--){uint16_tdata=(CDC_BUFFER[dma_addrc+srcoffset]<<8)|CDC_BUFFER[dma_addrc+srcoffset+1];if(destination==DMA_PRG){dest=m_prgram;}elseif(destination==DMA_WRAM){dest=m_dataram;}elseif(destination==DMA_PCM){dest=nullptr;//fatalerror("PCM RAM DMA unimplemented!\n");}else{fatalerror("Unknown DMA Destination!!\n");}if(PCM_DMA){m_rfsnd->rf5c68_mem_w(dstoffset&0xfff,data>>8);m_rfsnd->rf5c68_mem_w((dstoffset+1)&0xfff,data);// printf("PCM_DMA writing %04x %04x\n",0xff2000+(dstoffset*2), data);}else{if(dest){if(destination==DMA_WRAM){if((scd_rammode&2)==RAM_MODE_2MEG){dstoffset&=0x3ffff;dest[dstoffset/2]=data;segacd_mark_tiles_dirty(dstoffset/2);}else{dstoffset&=0x1ffff;if(!(scd_rammode&1)){segacd_1meg_mode_word_write((dstoffset+0x20000)/2,data,0xffff,0);}else{segacd_1meg_mode_word_write((dstoffset+0x00000)/2,data,0xffff,0);}}}else{// main ramdest[dstoffset/2]=data;}}}srcoffset+=2;dstoffset+=2;}if(PCM_DMA){m_dmaaddr+=length>>1;}else{m_dmaaddr+=length>>2;}}