/* Konami Cobra System Driver by Ville Linde Games on this hardware ---------------------- Game ID Year Notes ----------------------------------------------------------------------- Fighting Bujutsu / Fighting Wu-Shu | G?645 | 1997 | Racing Jam DX | GY676 | 1997 | GY676-PWB(F) LAN board Hardware overview: COBRA/603 GN645-PWB(A) CPU Board ---------------------------------- IBM PowerPC 603EV Motorola XPC105ARX66CD COBRA/403 GN645-PWB(B) SUB Board ---------------------------------- IBM PowerPC 403GA-JC33C1 (32MHz) TI TMS57002 Ricoh RF5c400 M48T58-70PC1 Timekeeper ADC1038CIN A/D Converter 2x AM7203A(?) FIFO (2K x 9) COBRA/604 GN645-PWB(C) GFX Board ---------------------------------- IBM PowerPC 604 Motorola XPC105ARX66CD Toshiba TMP47P241VM MCU (internal ROM?) 4x CY7C4231 FIFO (2K x 9) Xilinx XC4300E FPGA Xilinx XC9536 FPGA GN645-PWB(D) Video Board (Also labeled IBM 36H3800. Seems to be related to the RS/6000 OpenGL accelerators.) ----------------------------------- 89G9380 (Xilinx part with an IBM sticker) PKA0702 PLA0702 (4 dies on the chip) RAA0800 BTA0803 4x TOA2602 Bt121KPJ80 RAMDAC GY676-PWB(F) LAN Board ---------------------- Xilinx XC5210 FPGA Xilinx XC5204 FPGA Konami K001604 (2D tilemaps + 2x ROZ) Bt121KPC80 RAMDAC */ /* check_color_buffer(): 0, 0 gfxfifo_exec: ram write 00100: 00000800 gfxfifo_exec: ram write 00104: 00000000 gfxfifo_exec: ram write 00108: 00000080 gfxfifo_exec: ram write 0010C: 00000080 gfxfifo_exec: ram write 00110: 20200000 gfxfifo_exec: ram write 00120: 08800800 gfxfifo_exec: ram write 00124: 00081018 gfxfifo_exec: ram write 00128: 08080808 gfxfifo_exec: ram write 80100: 00800000 gfxfifo_exec: ram write 80104: 00800000 gfxfifo_exec: ram write 80110: 00800000 gfxfifo_exec: ram write 800A8: 00000000 gfxfifo_exec: ram write 80108: 00000000 check_color_buffer(): 0, 1 gfxfifo_exec: ram write 00120: 08800800 gfxfifo_exec: ram write 00124: 00081018 gfxfifo_exec: ram write 00128: 08080808 gfxfifo_exec: ram write 80100: 00200000 gfxfifo_exec: ram write 80104: 00200000 gfxfifo_exec: ram write 80110: 00200000 gfxfifo_exec: ram write 800A8: 00000000 check_overlay_buffer(): gfxfifo_exec: ram write 00120: 08800800 gfxfifo_exec: ram write 00124: 00081018 gfxfifo_exec: ram write 00128: 08080808 gfxfifo_exec: ram write 80100: 000E0000 gfxfifo_exec: ram write 80104: 000E0000 gfxfifo_exec: ram write 80110: 000E0000 gfxfifo_exec: ram write 800A8: 00000000 check_z_buffer(): gfxfifo_exec: ram write 00120: 08000800 gfxfifo_exec: ram write 00124: 00000010 gfxfifo_exec: ram write 00128: 00001010 gfxfifo_exec: ram write 80100: 00000000 gfxfifo_exec: ram write 80104: 00000800 gfxfifo_exec: ram write 80110: 00000800 gfxfifo_exec: ram write 800A8: 80000000 check_stencil_buffer(): gfxfifo_exec: ram write 00120: 08000800 gfxfifo_exec: ram write 00124: 00000010 gfxfifo_exec: ram write 00128: 00001010 gfxfifo_exec: ram write 80100: 00000000 gfxfifo_exec: ram write 80104: 00000200 gfxfifo_exec: ram write 80110: 00000200 gfxfifo_exec: ram write 800A8: 80000000 Bujutsu GL functions (603 board): ? : glDebugSwitch 0x0000b784: glBindTexture? 0x0000d40c: glEnable? 0x0000d7f4: glDisable? 0x0000d840: glAlphaFunc 0x0000d9a4: glNewList 0x0000dab0: glMatrixMode ? : glOrtho ? : glViewport 0x0000db6c: glIdentity? 0x0000dbf0: glFrustum ? : glCullFace ? : glClear ? : glCallList ? : glLightfv ? : glMaterialfv 0x0001b5c8: glBlendFunc 0x0001b8b0: glStencilOp ? : glStencilFunc 0x000471e0: glTexParameterf 0x0004a228: glColorMaterial ? : glFogfv ? : glFogf 0x0004a7a8: glDepthFunc 0x000508a8: glMaterialf 0x000508fc: glLightModelfv 0x00050a50: glTexEnvf ? : glTexEnvfv 0x00050cc8: ? (param 0xff) could be glStencilMask 0x00050d54: glFogi 0x00050da0: glHint 0x000cba6c: glTexParameteri GFX Registers: 0x00090: Viewport width / 2? 0x0009c: Viewport center X 0x000a4: Viewport height / 2? 0x000ac: Viewport center Y 0x00114: High word: framebuffer pitch? Low word: framebuffer pixel size? 0x00118: xxxxxxxx xxxxxxxx -------- -------- Framebuffer pixel read X pos -------- -------- xxxxxxxx xxxxxxxx Framebuffer pixel read Y pos 0x0011c: Same as above? 0x00454: (mask 0xff) 0x80000000 Tex related 0x00458: Set to 0x02100000 (0xff) by texselect() ------xx -------- -------- -------- Texture select (0-3) -------- ---x---- -------- -------- ? 0x02900: -------- -------- -------- -------- Texture[0] ? 0x02904: -------- ------xx xx------ -------- Texture[0] mag filter? -------- -------- --xxxx-- -------- Texture[0] min filter? 0x02908: -------- ----xxx- -------- -------- Texture[0] wrap S (0 = repeat, 1 = mirror, 2 = clamp) -------- -------x xx------ -------- Texture[0] wrap T 0x02910: xxxx---- -------- -------- -------- Texture[0] width shift (size = 1 << X) ----xxxx -------- -------- -------- Texture[0] height shift (size = 1 << X) -------- ----x--- -------- -------- ? -------- -------- -x------ -------- ? -------- -------- -------- xxx----- Texture[0] format (texel size, 2 = 4-bit, 3 = 8-bit, 4 = 16-bit) -------- -------- -------- ---xxx-- Texture[0] format param 0x02914: xxxxxxxx xxxxxxxx xxxx---- -------- Texture[0] address 0x02980: Texture[1] ? 0x02984: Texture[1] min/mag filter 0x02988: Texture[1] wrap 0x02990: Texture[1] width/height/format 0x02994: Texture[1] address 0x02a00: Texture[2] ? 0x02a04: Texture[2] min/mag filter 0x02a08: Texture[2] wrap 0x02a10: Texture[2] width/height/format 0x02a14: Texture[2] address 0x02a80: Texture[3] ? 0x02a84: Texture[3] min/mag filter 0x02a88: Texture[3] wrap 0x02a90: Texture[3] width/height/format 0x02a94: Texture[3] address 0x40018: Set to 0x0001040a (0xc0) by mode_stipple() (bits 24..27 = stipple pattern?) 0x400d0: Set to 0x80000000 (0x80) by mode_stipple() 0x400f4: xxx----- -------- -------- -------- Texture select (0-3) 0x40114: -------- ----x--- -------- -------- Scissor enable 0x40138: Set to 0x88800000 (0xe0) by mode_viewclip() 0x40160: xxxxxxxx xxxxxxxx -------- -------- Scissor Left -------- -------- xxxxxxxx xxxxxxxx Scissor Top 0x40164: xxxxxxxx xxxxxxxx -------- -------- Scissor Right -------- -------- xxxxxxxx xxxxxxxx Scissor Bottom 0x40170: xxxxxxxx xxxxxxxx -------- -------- Viewport Left -------- -------- xxxxxxxx xxxxxxxx Viewport Top 0x40174: xxxxxxxx xxxxxxxx -------- -------- Viewport Right -------- -------- xxxxxxxx xxxxxxxx Viewport Bottom 0x40198: x------- -------- -------- -------- Alpha test enable? -------- xxx----- -------- -------- Alpha test function (0 = never, 1 = less, 2 = lequal, 3 = greater, 4 = gequal, 5 = equal, 6 = notequal, 7 = always) -------- -------- xxxxxxxx xxxxxxxx Alpha test reference value? 0x4019c: x------- -------- -------- -------- Fog enable ----x--- -------- -------- -------- 0 = table fog, 1 = linear fog 0x401a8: (mask 0xff): 0x2CAB34FD ? 0x401ac: (mask 0xf0): 0x48C70000 ? 0x401b8: (mask 0x20): 0x00400000 ? 0x401bc: Texture env mode xxx----- -------- -------- -------- ? ---xxx-- -------- -------- -------- ? 0x8001c: (mask 0xfe) 0xc1d60060 = (not equal, 6) Stencil register 0xca9b0010 = (not equal, 1) 0x037dfff0 = (never) 0x2616fff0 = (greater) 0x459cfff0 = (greater/equal) 0x6672fff0 = (less) 0x8827fff0 = (less/equal) 0xa92b0100 = (equal, 16) -------- -------- xxxxxxxx xxxx---- Stencil reference value? ----xxxx xxxxxxxx -------- -------- Stencil fill value? xxx----- -------- -------- -------- Stencil function? 0x80020: -------- ----xxx- -------- -------- Depth test function (7 = always?) 0x80040: (mask 0x0f) 0x00002CAB (same value as 0x401a8) 0x80044: (mask 0x0f) 0x000034FD (same value as 0x401a8) 0x80048: (mask 0x0f) 0x000048C7 (same value as 0x401ac) 0x80050: (mask 0x7c) 0x04445500 = (As, 1-As) Blend register 0x04111100 = (1, 1) 0x04441100 = (As, 1) 0x04114400 = (1, As) 0x04681100 = (Cd, 1) 0x04680000 = (Cd, 0) 0x04002400 = (0, Cs) 0x04e11100 = (Ad, 1-Ad) 0x04889900 = (pseudo-fog) -----x-- -------- -------- -------- Blend enable? -------- xxxx---- -------- -------- source factor? -------- ----xxxx -------- -------- source? -------- -------- xxxx---- -------- dest factor? -------- -------- ----xxxx -------- dest? 0x80054: Set to 0x02400000 (0xe0) by mode_stencilmod() 0x800a4: x------- -------- -------- -------- Logic op enable? -----xxx x------- -------- -------- Logic op (0 = clear, 1 = and, 2 = and reverse, 3 = copy, 4 = and inverted, 5 = noop, 6 = xor, 7 = or inverted, 8 = nor, 9 = equiv, 10 = invert, 11 = or reverse, 12 = copy inverted, 13 = or inverted, 14 = nand, 15 = set) 0x80114: (0xcc) by mode_colormask() 0x80118: (0xcc) by mode_colormask() 0x8011c: xxxxxxxx xxxx---- -------- -------- Stencil mask 0x80120: -------- -------- xxxxxxxx xxxxxxxx Depth mask register 0xc0c00..fff: Texture RAM readback 0xc3020: Start address for texram writes? 0xc3028: Reads address from texram? 0xc4c00..fff: Texture RAM readback 0xc8c00..fff: Texture RAM readback 0xccc00..fff: Texture RAM readback Bujutsu status: Main: 0xe948 -> 0x1ea4(): Waiting for [0x168700] != 1 @ 0x1ebc Gfx: 0x3b1a0 -> 0x3ad70(): Waiting for [0x132000] != 0 @ 0x3adf4 */ #include "emu.h" #include "cpu/powerpc/ppc.h" #include "machine/pci.h" #include "machine/idectrl.h" #include "machine/timekpr.h" #include "machine/jvshost.h" #include "machine/jvsdev.h" #include "video/konicdev.h" #include "video/polynew.h" #include "video/rgbgen.h" #include "sound/rf5c400.h" #include "sound/dmadac.h" #define GFXFIFO_IN_VERBOSE 0 #define GFXFIFO_OUT_VERBOSE 0 #define M2SFIFO_VERBOSE 0 #define S2MFIFO_VERBOSE 0 #define LOG_DEBUG_STATES 0 #define LOG_JVS 0 #define LOG_GFX_RAM_WRITES 0 #define LOG_DRAW_COMMANDS 0 #define ENABLE_BILINEAR 1 #define DMA_SOUND_BUFFER_SIZE 16000 /* Cobra Renderer class */ struct cobra_polydata { UINT32 alpha_test; UINT32 zmode; UINT32 tex_format; UINT32 tex_address; }; class cobra_renderer : public poly_manager { public: cobra_renderer(running_machine &machine) : poly_manager(machine) { m_texture_ram = auto_alloc_array(machine, UINT32, 0x100000); m_framebuffer = auto_bitmap_rgb32_alloc(machine, 1024, 1024); m_backbuffer = auto_bitmap_rgb32_alloc(machine, 1024, 1024); m_overlay = auto_bitmap_rgb32_alloc(machine, 1024, 1024); m_zbuffer = auto_bitmap_ind32_alloc(machine, 1024, 1024); m_stencil = auto_bitmap_ind32_alloc(machine, 1024, 1024); m_gfx_regmask = auto_alloc_array(machine, UINT32, 0x100); for (int i=0; i < 0x100; i++) { UINT32 mask = 0; if (i & 0x01) mask |= 0x0000000f; if (i & 0x02) mask |= 0x000000f0; if (i & 0x04) mask |= 0x00000f00; if (i & 0x08) mask |= 0x0000f000; if (i & 0x10) mask |= 0x000f0000; if (i & 0x20) mask |= 0x00f00000; if (i & 0x40) mask |= 0x0f000000; if (i & 0x80) mask |= 0xf0000000; m_gfx_regmask[i] = mask; } } void render_texture_scan(INT32 scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid); void render_color_scan(INT32 scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid); void draw_point(const rectangle &visarea, vertex_t &v, UINT32 color); void draw_line(const rectangle &visarea, vertex_t &v1, vertex_t &v2); void gfx_init(running_machine &machine); void gfx_exit(running_machine &machine); void gfx_reset(running_machine &machine); void gfx_fifo_exec(running_machine &machine); UINT32 gfx_read_gram(UINT32 address); void gfx_write_gram(UINT32 address, UINT32 mask, UINT32 data); UINT64 gfx_read_reg(running_machine &machine); void gfx_write_reg(running_machine &machine, UINT64 data); void display(bitmap_rgb32 *bitmap, const rectangle &cliprect); private: bitmap_rgb32 *m_framebuffer; bitmap_rgb32 *m_backbuffer; bitmap_rgb32 *m_overlay; bitmap_ind32 *m_zbuffer; bitmap_ind32 *m_stencil; UINT32 *m_texture_ram; UINT32 *m_gfx_gram; UINT32 *m_gfx_regmask; UINT32 m_gfx_register_select; UINT64 *m_gfx_register; UINT32 m_texram_ptr; enum { RE_STATUS_IDLE = 0, RE_STATUS_COMMAND = 1, }; enum { POLY_Z = 0, POLY_R = 1, POLY_G = 2, POLY_B = 3, POLY_A = 4, POLY_U = 5, POLY_V = 6, POLY_W = 7, }; }; /* FIFO class */ class cobra_fifo { public: enum EventType { EVENT_EMPTY, EVENT_HALF_FULL, EVENT_FULL, }; typedef delegate event_delegate; cobra_fifo(running_machine &machine, int capacity, const char *name, bool verbose, event_delegate event_callback) { m_data = auto_alloc_array(machine, UINT64, capacity); m_name = name; m_size = capacity; m_wpos = 0; m_rpos = 0; m_num = 0; m_verbose = verbose; m_event_callback = event_callback; } void push(const device_t *cpu, UINT64 data); bool pop(const device_t *cpu, UINT64 *result); bool pop(const device_t *cpu, float *result); int current_num(); int space_left(); bool is_empty(); bool is_half_full(); bool is_full(); void flush(); private: int m_size; int m_wpos; int m_rpos; int m_num; bool m_verbose; const char *m_name; UINT64 *m_data; event_delegate m_event_callback; }; /* Cobra JVS Device class */ class cobra_jvs : public jvs_device { public: cobra_jvs(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); protected: virtual bool switches(UINT8 *&buf, UINT8 count_players, UINT8 bytes_per_switch); virtual bool coin_counters(UINT8 *&buf, UINT8 count); }; const device_type COBRA_JVS = &device_creator; cobra_jvs::cobra_jvs(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : jvs_device(mconfig, COBRA_JVS, "COBRA_JVS", tag, owner, clock) { } bool cobra_jvs::switches(UINT8 *&buf, UINT8 count_players, UINT8 bytes_per_switch) { #if LOG_JVS printf("jvs switch read: num players %d, bytes %d\n", count_players, bytes_per_switch); #endif if (count_players > 2 || bytes_per_switch > 2) return false; static const char* player_ports[2] = { ":P1", ":P2" }; *buf++ = ioport(":TEST")->read_safe(0); for (int i=0; i < count_players; i++) { UINT32 pval = ioport(player_ports[i])->read_safe(0); for (int j=0; j < bytes_per_switch; j++) { *buf++ = (UINT8)(pval >> ((1-j) * 8)); } } return true; } bool cobra_jvs::coin_counters(UINT8 *&buf, UINT8 count) { #if LOG_JVS printf("jvs coin counter read: count %d\n", count); #endif if (count > 2) return false; *buf++ = 0x00; *buf++ = 0x01; return true; } class cobra_jvs_host : public jvs_host { public: cobra_jvs_host(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); void write(UINT8, const UINT8 *&rec_data, UINT32 &rec_size); private: UINT8 m_send[512]; int m_send_ptr; }; const device_type COBRA_JVS_HOST = &device_creator; cobra_jvs_host::cobra_jvs_host(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : jvs_host(mconfig, COBRA_JVS_HOST, "COBRA_JVS_HOST", tag, owner, clock) { m_send_ptr = 0; } void cobra_jvs_host::write(UINT8 data, const UINT8 *&rec_data, UINT32 &rec_size) { m_send[m_send_ptr++] = data; push(data); if (m_send[0] == 0xe0) { if (m_send_ptr > 2) { UINT8 length = m_send[2]; if (length == 0xff) length = 4; else length = length + 3; if (m_send_ptr >= length) { commit_encoded(); get_encoded_reply(rec_data, rec_size); m_send_ptr = 0; return; } } } else { m_send_ptr = 0; } rec_data = NULL; rec_size = 0; } /* Cobra driver class */ class cobra_state : public driver_device { public: cobra_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_subcpu(*this, "subcpu"), m_gfxcpu(*this, "gfxcpu"), m_gfx_pagetable(*this, "pagetable") { } required_device m_maincpu; required_device m_subcpu; required_device m_gfxcpu; required_shared_ptr m_gfx_pagetable; DECLARE_READ64_MEMBER(main_comram_r); DECLARE_WRITE64_MEMBER(main_comram_w); DECLARE_READ64_MEMBER(main_fifo_r); DECLARE_WRITE64_MEMBER(main_fifo_w); DECLARE_READ64_MEMBER(main_mpc106_r); DECLARE_WRITE64_MEMBER(main_mpc106_w); DECLARE_READ32_MEMBER(sub_comram_r); DECLARE_WRITE32_MEMBER(sub_comram_w); DECLARE_READ32_MEMBER(sub_sound_r); DECLARE_WRITE32_MEMBER(sub_sound_w); DECLARE_READ32_MEMBER(sub_unk7e_r); DECLARE_WRITE32_MEMBER(sub_debug_w); DECLARE_READ32_MEMBER(sub_unk1_r); DECLARE_WRITE32_MEMBER(sub_unk1_w); DECLARE_READ32_MEMBER(sub_config_r); DECLARE_WRITE32_MEMBER(sub_config_w); DECLARE_READ32_MEMBER(sub_mainbd_r); DECLARE_WRITE32_MEMBER(sub_mainbd_w); DECLARE_READ32_MEMBER(sub_ata0_r); DECLARE_WRITE32_MEMBER(sub_ata0_w); DECLARE_READ32_MEMBER(sub_ata1_r); DECLARE_WRITE32_MEMBER(sub_ata1_w); DECLARE_READ32_MEMBER(sub_psac2_r); DECLARE_WRITE32_MEMBER(sub_psac2_w); DECLARE_WRITE32_MEMBER(sub_psac_palette_w); DECLARE_WRITE64_MEMBER(gfx_fifo0_w); DECLARE_WRITE64_MEMBER(gfx_fifo1_w); DECLARE_WRITE64_MEMBER(gfx_fifo2_w); DECLARE_WRITE64_MEMBER(gfx_debug_state_w); DECLARE_READ64_MEMBER(gfx_unk1_r); DECLARE_WRITE64_MEMBER(gfx_unk1_w); DECLARE_READ64_MEMBER(gfx_fifo_r); DECLARE_WRITE64_MEMBER(gfx_buf_w); DECLARE_WRITE_LINE_MEMBER(ide_interrupt); cobra_renderer *m_renderer; cobra_fifo *m_gfxfifo_in; cobra_fifo *m_gfxfifo_out; cobra_fifo *m_m2sfifo; cobra_fifo *m_s2mfifo; void gfxfifo_in_event_callback(cobra_fifo::EventType event); void gfxfifo_out_event_callback(cobra_fifo::EventType event); void m2sfifo_event_callback(cobra_fifo::EventType event); void s2mfifo_event_callback(cobra_fifo::EventType event); enum { MAIN_INT_M2S = 0x01, MAIN_INT_S2M = 0x02, }; UINT8 m_m2s_int_enable; UINT8 m_s2m_int_enable; UINT8 m_vblank_enable; UINT8 m_m2s_int_mode; UINT8 m_s2m_int_mode; UINT8 m_main_int_active; UINT32 *m_comram[2]; int m_comram_page; int m_main_debug_state; int m_main_debug_state_wc; int m_sub_debug_state; int m_sub_debug_state_wc; int m_gfx_debug_state; int m_gfx_debug_state_wc; UINT32 m_sub_psac_reg; int m_sub_psac_count; UINT32 m_sub_interrupt; UINT8 m_gfx_unk_flag; UINT32 m_gfx_re_command_word1; UINT32 m_gfx_re_command_word2; int m_gfx_re_word_count; int m_gfx_re_status; UINT32 m_gfx_unk_status; UINT64 m_gfx_fifo_mem[256]; int m_gfx_fifo_cache_addr; int m_gfx_fifo_loopback; int m_gfx_unknown_v1; int m_gfx_status_byte; bool m_has_psac; INT16 *m_sound_dma_buffer_l; INT16 *m_sound_dma_buffer_r; UINT32 m_sound_dma_ptr; dmadac_sound_device *m_dmadac[2]; DECLARE_DRIVER_INIT(racjamdx); DECLARE_DRIVER_INIT(bujutsu); DECLARE_DRIVER_INIT(cobra); virtual void machine_reset(); virtual void video_start(); UINT32 screen_update_cobra(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); INTERRUPT_GEN_MEMBER(cobra_vblank); void cobra_video_exit(); }; void cobra_renderer::render_color_scan(INT32 scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid) { UINT32 *fb = &m_backbuffer->pix32(scanline); float *zb = (float*)&m_zbuffer->pix32(scanline); float z = extent.param[POLY_Z].start; float dz = extent.param[POLY_Z].dpdx; float gr = extent.param[POLY_R].start; float dgr = extent.param[POLY_R].dpdx; float gg = extent.param[POLY_G].start; float dgg = extent.param[POLY_G].dpdx; float gb = extent.param[POLY_B].start; float dgb = extent.param[POLY_B].dpdx; float ga = extent.param[POLY_A].start; float dga = extent.param[POLY_A].dpdx; UINT32 zmode = extradata.zmode; for (int x = extent.startx; x < extent.stopx; x++) { if (z <= zb[x] || zmode == 7) { UINT32 r = (int)(gr); UINT32 g = (int)(gg); UINT32 b = (int)(gb); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; r <<= 16; g <<= 8; fb[x] = 0xff000000 | r | g | b; zb[x] = z; } z += dz; gr += dgr; gg += dgg; gb += dgb; ga += dga; } } INLINE rgb_t texture_fetch(UINT32 *texture, int u, int v, int width, int format) { UINT32 texel = texture[((v * width) + u) / 2]; if (u & 1) { texel &= 0xffff; } else { texel >>= 16; } rgb_t color; if (format == 6) { int r = (texel & 0xf000) >> 8; int g = (texel & 0x0f00) >> 4; int b = (texel & 0x00f0) >> 0; int a = (texel & 0x000f) | ((texel & 0x000f) << 4); color = MAKE_ARGB(a, r, g, b); } else { int r = (texel & 0xf800) >> 8; int g = (texel & 0x07c0) >> 3; int b = (texel & 0x003e) << 2; int a = (texel & 0x0001) ? 0xff : 0; color = MAKE_ARGB(a, r, g, b); } return color; } void cobra_renderer::render_texture_scan(INT32 scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid) { float u = extent.param[POLY_U].start; float v = extent.param[POLY_V].start; float du = extent.param[POLY_U].dpdx; float dv = extent.param[POLY_V].dpdx; float w = extent.param[POLY_W].start; float dw = extent.param[POLY_W].dpdx; float z = extent.param[POLY_Z].start; float dz = extent.param[POLY_Z].dpdx; float gr = extent.param[POLY_R].start; float dgr = extent.param[POLY_R].dpdx; float gg = extent.param[POLY_G].start; float dgg = extent.param[POLY_G].dpdx; float gb = extent.param[POLY_B].start; float dgb = extent.param[POLY_B].dpdx; float ga = extent.param[POLY_A].start; float dga = extent.param[POLY_A].dpdx; UINT32 *fb = &m_backbuffer->pix32(scanline); float *zb = (float*)&m_zbuffer->pix32(scanline); UINT32 texture_width = 1 << ((extradata.tex_format >> 28) & 0xf); UINT32 texture_height = 1 << ((extradata.tex_format >> 24) & 0xf); UINT32 tex_address = extradata.tex_address; UINT32 alpha_test = extradata.alpha_test; UINT32 zmode = extradata.zmode; UINT32 tex_format = (extradata.tex_format >> 2) & 0x7; for (int x = extent.startx; x < extent.stopx; x++) { int iu, iv; if (z <= zb[x] || zmode == 7) { float oow; if (w == 0) oow = 1.0f; else oow = 1.0f / w; #if !ENABLE_BILINEAR iu = (int)((u * oow) * texture_width) & 0x7ff; iv = (int)((v * oow) * texture_height) & 0x7ff; rgb_t texel = texture_fetch(&m_texture_ram[tex_address], iu, iv, texture_width, tex_format); #else float tex_u = (u * oow) * texture_width; float tex_v = (v * oow) * texture_height; iu = (int)(tex_u) & 0x7ff; iv = (int)(tex_v) & 0x7ff; float lerp_u = tex_u - (float)(iu); float lerp_v = tex_v - (float)(iv); rgb_t texel00 = texture_fetch(&m_texture_ram[tex_address], iu, iv, texture_width, tex_format); rgb_t texel01 = texture_fetch(&m_texture_ram[tex_address], iu+1, iv, texture_width, tex_format); rgb_t texel10 = texture_fetch(&m_texture_ram[tex_address], iu, iv+1, texture_width, tex_format); rgb_t texel11 = texture_fetch(&m_texture_ram[tex_address], iu+1, iv+1, texture_width, tex_format); rgb_t texel = rgba_bilinear_filter(texel00, texel01, texel10, texel11, (int)(lerp_u * 255), (int)(lerp_v * 255)); #endif int a = RGB_ALPHA(texel); if (a != 0 || !alpha_test) { UINT32 gour = (int)(gr); UINT32 goug = (int)(gg); UINT32 goub = (int)(gb); int r = (RGB_RED(texel) * gour) >> 8; int g = (RGB_GREEN(texel) * goug) >> 8; int b = (RGB_BLUE(texel) * goub) >> 8; if (a != 0xff) { int fb_r = (fb[x] >> 16) & 0xff; int fb_g = (fb[x] >> 8) & 0xff; int fb_b = fb[x] & 0xff; r = ((r * a) >> 8) + ((fb_r * (0xff-a)) >> 8); g = ((g * a) >> 8) + ((fb_g * (0xff-a)) >> 8); b = ((b * a) >> 8) + ((fb_b * (0xff-a)) >> 8); } if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; r <<= 16; g <<= 8; fb[x] = 0xff000000 | r | g | b; zb[x] = z; } } u += du; v += dv; w += dw; z += dz; gr += dgr; gg += dgg; gb += dgb; ga += dga; } } void cobra_renderer::draw_point(const rectangle &visarea, vertex_t &v, UINT32 color) { int x = v.x; int y = v.y; if (x >= visarea.min_x && x <= visarea.max_x && y >= visarea.min_y && y <= visarea.max_y) { UINT32 *fb = &m_backbuffer->pix32(y); fb[x] = color; } } void cobra_renderer::draw_line(const rectangle &visarea, vertex_t &v1, vertex_t &v2) { int dx = (v2.x - v1.x); int dy = (v2.y - v1.y); int x1 = v1.x; int y1 = v1.y; UINT32 color = 0xffffffff; // TODO: where does the color come from? if (v1.x < visarea.min_x || v1.x > visarea.max_x || v1.y < visarea.min_y || v1.y > visarea.max_y || v2.x < visarea.min_x || v2.x > visarea.max_x || v2.y < visarea.min_y || v2.y > visarea.max_x) return; if (dx > dy) { int x = x1; for (int i=0; i < abs(dx); i++) { int y = y1 + (dy * (float)(x - x1) / (float)(dx)); UINT32 *fb = &m_backbuffer->pix32(y); fb[x] = color; x++; } } else { int y = y1; for (int i=0; i < abs(dy); i++) { int x = x1 + (dx * (float)(y - y1) / (float)(dy)); UINT32 *fb = &m_backbuffer->pix32(y); fb[x] = color; y++; } } } void cobra_state::cobra_video_exit() { m_renderer->gfx_exit(machine()); } void cobra_state::video_start() { machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(cobra_state::cobra_video_exit), this)); m_renderer = auto_alloc(machine(), cobra_renderer(machine())); m_renderer->gfx_init(machine()); } UINT32 cobra_state::screen_update_cobra(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { if (m_has_psac) { device_t *k001604 = machine().device("k001604"); k001604_draw_back_layer(k001604, bitmap, cliprect); k001604_draw_front_layer(k001604, bitmap, cliprect); } m_renderer->display(&bitmap, cliprect); return 0; } /*****************************************************************************/ static int decode_debug_state_value(int v) { switch (v) { case 0x01: return 0; case 0xcf: return 1; case 0x92: return 2; case 0x86: return 3; case 0xcc: return 4; case 0xa4: return 5; case 0xa0: return 6; case 0x8d: return 7; case 0x80: return 8; case 0x84: return 9; case 0x88: return 10; case 0xe0: return 11; case 0xb1: return 12; case 0xc2: return 13; case 0xb0: return 14; case 0xb8: return 15; default: return 0; } } void cobra_fifo::push(const device_t *cpu, UINT64 data) { if (m_verbose) { char accessor_location[50]; if (cpu != NULL) { // cpu has a name and a PC sprintf(accessor_location, "(%s) %08X", cpu->tag(), const_cast(cpu)->safe_pc()); } else { // non-cpu sprintf(accessor_location, "(non-cpu)"); } printf("%s: push %08X%08X (%d) at %s\n", m_name, (UINT32)(data >> 32), (UINT32)(data), m_num, accessor_location); } if (m_num == m_size) { if (m_verbose) { int i, j; char accessor_location[50]; if (cpu != NULL) { // cpu has a name and a PC sprintf(accessor_location, "(%s) %08X", cpu->tag(), const_cast(cpu)->safe_pc()); } else { // non-cpu sprintf(accessor_location, "(non-cpu)"); } printf("%s overflow at %s\n", m_name, accessor_location); printf("%s dump:\n", m_name); for (j=0; j < 128; j+=4) { printf(" "); for (i=0; i < 4; i++) { UINT64 val = 0; pop(cpu, &val); printf("%08X ", (UINT32)(val)); } printf("\n"); } printf("\n"); } return; } m_data[m_wpos] = data; m_wpos++; if (m_wpos == m_size) { m_wpos = 0; } m_num++; if (m_num >= m_size) m_event_callback(EVENT_FULL); if (m_num == (m_size / 2)) m_event_callback(EVENT_HALF_FULL); } bool cobra_fifo::pop(const device_t *cpu, UINT64 *result) { UINT64 r; if (m_num == 0) { if (m_verbose) { char accessor_location[50]; if (cpu != NULL) { // cpu has a name and a PC sprintf(accessor_location, "(%s) %08X", cpu->tag(), const_cast(cpu)->safe_pc()); } else { // non-cpu sprintf(accessor_location, "(non-cpu)"); } printf("%s underflow at %s\n", m_name, accessor_location); } return false; } r = m_data[m_rpos]; if (m_verbose) { char accessor_location[50]; if (cpu != NULL) { // cpu has a name and a PC sprintf(accessor_location, "(%s) %08X", cpu->tag(), const_cast(cpu)->safe_pc()); } else { // non-cpu sprintf(accessor_location, "(non-cpu)"); } printf("%s: pop %08X%08X (%d) at %s\n", m_name, (UINT32)(r >> 32), (UINT32)(r), m_num-1, accessor_location); } m_rpos++; if (m_rpos == m_size) { m_rpos = 0; } m_num--; if (m_num == 0) m_event_callback(EVENT_EMPTY); if (m_num == (m_size / 2)) m_event_callback(EVENT_HALF_FULL); *result = r; return true; } bool cobra_fifo::pop(const device_t *cpu, float *result) { UINT64 value = 0; bool status = pop(cpu, &value); *result = u2f((UINT32)(value)); return status; } int cobra_fifo::current_num() { return m_num; } int cobra_fifo::space_left() { return m_size - m_num; } bool cobra_fifo::is_empty() { return (m_num == 0); } bool cobra_fifo::is_half_full() { return (m_num > (m_size / 2)); } bool cobra_fifo::is_full() { return (m_num >= m_size); } void cobra_fifo::flush() { m_num = 0; m_rpos = 0; m_wpos = 0; m_event_callback(EVENT_EMPTY); } /*****************************************************************************/ void cobra_state::m2sfifo_event_callback(cobra_fifo::EventType event) { switch (event) { case cobra_fifo::EVENT_EMPTY: { machine().device("subcpu")->execute().set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); // give sub cpu a bit more time to stabilize on the current fifo status machine().device("maincpu")->execute().spin_until_time(attotime::from_usec(1)); if (m_m2s_int_enable & 0x80) { if (!m_m2s_int_mode) m_main_int_active |= MAIN_INT_M2S; machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); } // EXISR needs to update for the *next* instruction during FIFO tests // TODO: try to abort the timeslice before the next instruction? m_subcpu->set_state_int(PPC_EXISR, m_subcpu->state_int(PPC_EXISR) & ~0x10); break; } case cobra_fifo::EVENT_HALF_FULL: break; case cobra_fifo::EVENT_FULL: break; } } void cobra_state::s2mfifo_event_callback(cobra_fifo::EventType event) { switch (event) { case cobra_fifo::EVENT_EMPTY: m_main_int_active &= ~MAIN_INT_S2M; break; case cobra_fifo::EVENT_HALF_FULL: break; case cobra_fifo::EVENT_FULL: break; } } void cobra_state::gfxfifo_in_event_callback(cobra_fifo::EventType event) { } void cobra_state::gfxfifo_out_event_callback(cobra_fifo::EventType event) { } /*****************************************************************************/ // Main board (PPC603) // MPC106 mem settings: // Bank 0: start 0x00, end 0x7f // Bank 1: start 0x81, end 0x81 // Bank 2: start 0x82, end 0x82 // Bank 3: start 0x83, end 0x83 // Bank 4: start 0x84, end 0x84 // Bank 5: start 0x85, end 0x85 // Bank 6: start 0x86, end 0x86 // Bank 7: start 0x87, end 0x87 // IBAT0 U: 0xfff00003 L: 0xfff00001 (0xfff00000, 128K) // IBAT1 U: 0x0000007f L: 0x00000001 (0x00000000, 4MB) // IBAT2 U: 0x0040007f L: 0x07c00001 (0x07c00000, 4MB) // IBAT3 U: 0x00000000 L: 0x00000001 unused // DBAT0 U: 0xfff0001f L: 0xfff0002a (0xfff00000, 1MB) // DBAT1 U: 0x0000007f L: 0x00000002 (0x00000000, 4MB) // DBAT2 U: 0x0040007f L: 0x07c00002 (0x07c00000, 4MB) // DBAT3 U: 0xc0000fff L: 0xc0000002 (0xc0000000, 128MB) // RPA: 0x8010C000 // Interrupts (0xFFFF0003): // 0x01: M2S FIFO // 0x02: S2M FIFO // 0x04: Vblank? static UINT32 mpc106_regs[256/4]; static UINT32 mpc106_pci_r(device_t *busdevice, device_t *device, int function, int reg, UINT32 mem_mask) { //printf("MPC106: PCI read %d, %02X, %08X\n", function, reg, mem_mask); switch (reg) { } return mpc106_regs[reg/4]; } static void mpc106_pci_w(device_t *busdevice, device_t *device, int function, int reg, UINT32 data, UINT32 mem_mask) { //printf("MPC106: PCI write %d, %02X, %08X, %08X\n", function, reg, data, mem_mask); COMBINE_DATA(mpc106_regs + (reg/4)); } READ64_MEMBER(cobra_state::main_mpc106_r) { pci_bus_legacy_device *device = machine().device("pcibus"); //return pci_64be_r(offset, mem_mask); return device->read_64be(space, offset, mem_mask); } WRITE64_MEMBER(cobra_state::main_mpc106_w) { pci_bus_legacy_device *device = machine().device("pcibus"); //pci_64be_w(offset, data, mem_mask); device->write_64be(space, offset, data, mem_mask); } READ64_MEMBER(cobra_state::main_fifo_r) { UINT64 r = 0; if (ACCESSING_BITS_56_63) { // Register 0xffff0000: // Main-to-Sub FIFO status register // Sub-to-Main FIFO status register // // 7 6 5 4 3 2 1 0 //---------------- // x M2S FIFO full flag // x M2S FIFO empty flag // x M2S FIFO half-full flag // x S2M FIFO full flag // x S2M FIFO empty flag // x S2M FIFO half-full flag // x Comram page int value = 0x00; value |= m_m2sfifo->is_full() ? 0x00 : 0x01; value |= m_m2sfifo->is_empty() ? 0x00 : 0x02; value |= m_m2sfifo->is_half_full() ? 0x00 : 0x04; value |= m_s2mfifo->is_full() ? 0x00 : 0x10; value |= m_s2mfifo->is_empty() ? 0x00 : 0x20; value |= m_s2mfifo->is_half_full() ? 0x00 : 0x40; value |= m_comram_page ? 0x80 : 0x00; r |= (UINT64)(value) << 56; } if (ACCESSING_BITS_48_55) { // Register 0xffff0001: // Sub board FIFO unknown register } if (ACCESSING_BITS_40_47) { // Register 0xffff0002: // Sub-to-Main FIFO read data UINT64 value; m_s2mfifo->pop(&space.device(), &value); r |= (UINT64)(value & 0xff) << 40; } if (ACCESSING_BITS_32_39) { // Register 0xffff0003: // // 7 6 5 4 3 2 1 0 //---------------- // x S2M FIFO interrupt active // x Graphics board/FIFO busy flag // x M2S FIFO interrupt active int value = 0x01; value |= (m_main_int_active & MAIN_INT_S2M) ? 0x00 : 0x02; value |= (m_main_int_active & MAIN_INT_M2S) ? 0x00 : 0x08; value |= (m_gfx_unk_flag & 0x80) ? 0x00 : 0x04; r |= (UINT64)(value) << 32; } return r; } WRITE64_MEMBER(cobra_state::main_fifo_w) { if (ACCESSING_BITS_40_47) { // Register 0xffff0002: // Main-to-Sub FIFO write data m_m2sfifo->push(&space.device(), (UINT8)(data >> 40)); if (!m_m2s_int_mode) m_main_int_active &= ~MAIN_INT_M2S; space.machine().device("subcpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); // EXISR needs to update for the *next* instruction during FIFO tests // TODO: try to abort the timeslice before the next instruction? m_subcpu->set_state_int(PPC_EXISR, m_subcpu->state_int(PPC_EXISR) | 0x10); } if (ACCESSING_BITS_32_39) { // Register 0xffff0003: // Main-to-Sub FIFO unknown // // 7 6 5 4 3 2 1 0 //---------------- // x M2S interrupt mode (0 = empty, 1 = half full) // x Comram page m_m2s_int_mode = ((data >> 32) & 0x8) ? 1 : 0; if (m_m2s_int_mode) { if (!m_m2sfifo->is_half_full()) { m_main_int_active |= MAIN_INT_M2S; } else { m_main_int_active &= ~MAIN_INT_M2S; } } else { if (m_m2sfifo->is_empty()) { m_main_int_active |= MAIN_INT_M2S; } else { m_main_int_active &= ~MAIN_INT_M2S; } } m_comram_page = ((data >> 32) & 0x80) ? 1 : 0; } if (ACCESSING_BITS_24_31) { // Register 0xffff0004: // Interrupt enable for ??? // // 7 6 5 4 3 2 1 0 //---------------- // x ? m_vblank_enable = (UINT8)(data >> 24); if ((m_vblank_enable & 0x80) == 0) { // clear the interrupt space.machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); } } if (ACCESSING_BITS_16_23) { // Register 0xffff0005: // Interrupt enable for S2MFIFO // // 7 6 5 4 3 2 1 0 //---------------- // x ? m_s2m_int_enable = (UINT8)(data >> 16); if ((m_s2m_int_enable & 0x80) == 0) { m_main_int_active &= ~MAIN_INT_S2M; // clear the interrupt space.machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); } } if (ACCESSING_BITS_8_15) { // Register 0xffff0007: // ??? printf("main_fifo_w: 0xffff0006: %02X\n", (UINT8)(data >> 8)); } if (ACCESSING_BITS_0_7) { // Register 0xffff0007: // Interrupt enable for M2SFIFO // // 7 6 5 4 3 2 1 0 //---------------- // x ? m_m2s_int_enable = (UINT8)(data); if ((m_m2s_int_enable & 0x80) == 0) { m_main_int_active &= ~MAIN_INT_M2S; // clear the interrupt space.machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); } } if (ACCESSING_BITS_56_63) { // Register 0xffff0000 // Debug state write m_main_debug_state |= decode_debug_state_value((data >> 56) & 0xff) << 4; m_main_debug_state_wc++; } if (ACCESSING_BITS_48_55) { // Register 0xffff0001 // Debug state write m_main_debug_state |= decode_debug_state_value((data >> 48) & 0xff); m_main_debug_state_wc++; } if (m_main_debug_state_wc >= 2) { #if LOG_DEBUG_STATES if (m_main_debug_state != 0) { printf("MAIN: debug state %02X\n", m_main_debug_state); } #endif m_main_debug_state = 0; m_main_debug_state_wc = 0; } } READ64_MEMBER(cobra_state::main_comram_r) { UINT64 r = 0; int page = m_comram_page; if (ACCESSING_BITS_32_63) { r |= (UINT64)(m_comram[page][(offset << 1) + 0]) << 32; } if (ACCESSING_BITS_0_31) { r |= (UINT64)(m_comram[page][(offset << 1) + 1]); } return r; } WRITE64_MEMBER(cobra_state::main_comram_w) { int page = m_comram_page; UINT32 w1 = m_comram[page][(offset << 1) + 0]; UINT32 w2 = m_comram[page][(offset << 1) + 1]; UINT32 d1 = (UINT32)(data >> 32); UINT32 d2 = (UINT32)(data); UINT32 m1 = (UINT32)(mem_mask >> 32); UINT32 m2 = (UINT32)(mem_mask); m_comram[page][(offset << 1) + 0] = (w1 & ~m1) | (d1 & m1); m_comram[page][(offset << 1) + 1] = (w2 & ~m2) | (d2 & m2); } static void main_cpu_dc_store(device_t *device, UINT32 address) { cobra_state *cobra = device->machine().driver_data(); if ((address & 0xf0000000) == 0xc0000000) { // force sync when writing to GFX board main ram cobra->m_maincpu->spin_until_time(attotime::from_usec(80)); } } static ADDRESS_MAP_START( cobra_main_map, AS_PROGRAM, 64, cobra_state ) AM_RANGE(0x00000000, 0x003fffff) AM_RAM AM_RANGE(0x07c00000, 0x07ffffff) AM_RAM AM_RANGE(0x80000cf8, 0x80000cff) AM_READWRITE(main_mpc106_r, main_mpc106_w) AM_RANGE(0xc0000000, 0xc03fffff) AM_RAM AM_SHARE("gfx_main_ram_0") // GFX board main ram, bank 0 AM_RANGE(0xc7c00000, 0xc7ffffff) AM_RAM AM_SHARE("gfx_main_ram_1") // GFX board main ram, bank 1 AM_RANGE(0xfff00000, 0xfff7ffff) AM_ROM AM_REGION("user1", 0) /* Boot ROM */ AM_RANGE(0xfff80000, 0xfffbffff) AM_READWRITE(main_comram_r, main_comram_w) AM_RANGE(0xffff0000, 0xffff0007) AM_READWRITE(main_fifo_r, main_fifo_w) ADDRESS_MAP_END /*****************************************************************************/ // Sub board (PPC403) // Interrupts: // Serial Transmit JVS // DMA0: DMA-driven DAC // DMA2: SCSI? // DMA3: JVS // External IRQ0 M2SFIFO // External IRQ1 S2MFIFO (mostly dummy, only disables the interrupt) // External IRQ2 SCSI Interrupt? //static int ucount = 0; READ32_MEMBER(cobra_state::sub_unk1_r) { UINT32 r = 0; if (ACCESSING_BITS_16_23) { r |= 0x10000; } return r; } WRITE32_MEMBER(cobra_state::sub_unk1_w) { /* if (!(mem_mask & 0xff000000)) { printf("%02X", data >> 24); ucount++; if (ucount >= 4) { ucount = 0; printf("\n"); } } */ } READ32_MEMBER(cobra_state::sub_mainbd_r) { UINT32 r = 0; if (ACCESSING_BITS_24_31) { // Register 0x7E380000 // M2S FIFO read UINT64 value; m_m2sfifo->pop(&space.device(), &value); r |= (value & 0xff) << 24; } if (ACCESSING_BITS_16_23) { // Register 0x7E380001 // Main-to-sub FIFO status register // Sub-to-main FIFO status register // // 7 6 5 4 3 2 1 0 //---------------- // x S2M FIFO full flag // x S2M FIFO empty flag // x S2M FIFO half-full flag // x M2S FIFO full flag // x M2S FIFO empty flag // x M2S FIFO half-full flag // x Comram page UINT32 value = 0x00; value |= m_s2mfifo->is_full() ? 0x00 : 0x01; value |= m_s2mfifo->is_empty() ? 0x00 : 0x02; value |= m_s2mfifo->is_half_full() ? 0x00 : 0x04; value |= m_m2sfifo->is_full() ? 0x00 : 0x10; value |= m_m2sfifo->is_empty() ? 0x00 : 0x20; value |= m_m2sfifo->is_half_full() ? 0x00 : 0x40; value |= m_comram_page ? 0x80 : 0x00; r |= (value) << 16; } return r; } WRITE32_MEMBER(cobra_state::sub_mainbd_w) { if (ACCESSING_BITS_24_31) { // Register 0x7E380000 // Sub-to-Main FIFO data m_s2mfifo->push(&space.device(), (UINT8)(data >> 24)); m_main_int_active |= MAIN_INT_S2M; // fire off an interrupt if enabled if (m_s2m_int_enable & 0x80) { space.machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); } } if (ACCESSING_BITS_16_23) { // Register 0x7E380001 // // 7 6 5 4 3 2 1 0 //---------------- // x S2M interrupt mode (0 = empty, 1 = half full) m_s2m_int_mode = (data & 0x10000) ? 1 : 0; if (m_s2m_int_mode) { if (!m_s2mfifo->is_half_full()) { m_subcpu->set_state_int(PPC_EXISR, m_subcpu->state_int(PPC_EXISR) | 0x08); } else { m_subcpu->set_state_int(PPC_EXISR, m_subcpu->state_int(PPC_EXISR) & ~0x08); } } else { if (m_s2mfifo->is_empty()) { m_subcpu->set_state_int(PPC_EXISR, m_subcpu->state_int(PPC_EXISR) | 0x08); } else { m_subcpu->set_state_int(PPC_EXISR, m_subcpu->state_int(PPC_EXISR) & ~0x08); } } } } READ32_MEMBER(cobra_state::sub_unk7e_r) { return 0xffffffff; } WRITE32_MEMBER(cobra_state::sub_debug_w) { if (ACCESSING_BITS_24_31) { m_sub_debug_state |= decode_debug_state_value((data >> 24) & 0xff) << 4; m_sub_debug_state_wc++; } if (ACCESSING_BITS_16_23) { m_sub_debug_state |= decode_debug_state_value((data >> 16) & 0xff); m_sub_debug_state_wc++; } if (m_sub_debug_state_wc >= 2) { #if LOG_DEBUG_STATES if (m_sub_debug_state != 0) { printf("SUB: debug state %02X\n", m_sub_debug_state); } #endif m_sub_debug_state = 0; m_sub_debug_state_wc = 0; } } READ32_MEMBER(cobra_state::sub_config_r) { UINT32 r = 0; if (ACCESSING_BITS_8_15) { r |= (0x2) << 8; // if bit 0x2 is zero, maskrom boot } if (ACCESSING_BITS_0_7) { r |= m_sub_interrupt; } return r; } WRITE32_MEMBER(cobra_state::sub_config_w) { } READ32_MEMBER(cobra_state::sub_ata0_r) { device_t *device = machine().device("ide"); UINT32 r = 0; if (ACCESSING_BITS_16_31) { UINT16 v = ide_bus_r(device, 0, (offset << 1) + 0); r |= ((v << 8) | (v >> 8)) << 16; } if (ACCESSING_BITS_0_15) { UINT16 v = ide_bus_r(device, 0, (offset << 1) + 1); r |= ((v << 8) | (v >> 8)) << 0; } return r; } WRITE32_MEMBER(cobra_state::sub_ata0_w) { device_t *device = machine().device("ide"); if (ACCESSING_BITS_16_31) { UINT16 d = ((data >> 24) & 0xff) | ((data >> 8) & 0xff00); ide_bus_w(device, 0, (offset << 1) + 0, d); } if (ACCESSING_BITS_0_15) { UINT16 d = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); ide_bus_w(device, 0, (offset << 1) + 1, d); } } READ32_MEMBER(cobra_state::sub_ata1_r) { device_t *device = machine().device("ide"); UINT32 r = 0; if (ACCESSING_BITS_16_31) { UINT16 v = ide_bus_r(device, 1, (offset << 1) + 0); r |= ((v << 8) | (v >> 8)) << 16; } if (ACCESSING_BITS_0_15) { UINT16 v = ide_bus_r(device, 1, (offset << 1) + 1); r |= ((v << 8) | (v >> 8)) << 0; } return r; } WRITE32_MEMBER(cobra_state::sub_ata1_w) { device_t *device = machine().device("ide"); if (ACCESSING_BITS_16_31) { UINT16 d = ((data >> 24) & 0xff) | ((data >> 8) & 0xff00); ide_bus_w(device, 1, (offset << 1) + 0, d); } if (ACCESSING_BITS_0_15) { UINT16 d = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); ide_bus_w(device, 1, (offset << 1) + 1, d); } } READ32_MEMBER(cobra_state::sub_comram_r) { int page = m_comram_page ^ 1; return m_comram[page][offset]; } WRITE32_MEMBER(cobra_state::sub_comram_w) { int page = m_comram_page ^ 1; COMBINE_DATA(m_comram[page] + offset); } WRITE32_MEMBER(cobra_state::sub_psac_palette_w) { COMBINE_DATA(&m_generic_paletteram_32[offset]); data = m_generic_paletteram_32[offset]; palette_set_color_rgb(machine(), offset, pal5bit(data >> 10), pal5bit(data >> 5), pal5bit(data >> 0)); } READ32_MEMBER(cobra_state::sub_psac2_r) { m_sub_psac_count++; if (m_sub_psac_count >= 0x8000) { m_sub_psac_reg ^= 0xffffffff; m_sub_psac_count = 0; } return m_sub_psac_reg; } WRITE32_MEMBER(cobra_state::sub_psac2_w) { } static void sub_sound_dma_w(device_t *device, int width, UINT32 data) { //printf("DMA write to unknown: size %d, data %08X\n", width, data); /* static FILE *out; if (out == NULL) out = fopen("sound.bin", "wb"); fputc((data >> 24) & 0xff, out); fputc((data >> 16) & 0xff, out); fputc((data >> 8) & 0xff, out); fputc((data >> 0) & 0xff, out); */ cobra_state *cobra = device->machine().driver_data(); INT16 ldata = (INT16)(data >> 16); INT16 rdata = (INT16)(data); cobra->m_sound_dma_buffer_l[cobra->m_sound_dma_ptr] = ldata; cobra->m_sound_dma_buffer_r[cobra->m_sound_dma_ptr] = rdata; cobra->m_sound_dma_ptr++; if (cobra->m_sound_dma_ptr >= DMA_SOUND_BUFFER_SIZE) { cobra->m_sound_dma_ptr = 0; dmadac_transfer(&cobra->m_dmadac[0], 1, 0, 1, DMA_SOUND_BUFFER_SIZE, cobra->m_sound_dma_buffer_l); dmadac_transfer(&cobra->m_dmadac[1], 1, 0, 1, DMA_SOUND_BUFFER_SIZE, cobra->m_sound_dma_buffer_r); } } static void sub_jvs_w(device_t *device, UINT8 data) { cobra_jvs_host *jvs = downcast(device->machine().device("cobra_jvs_host")); #if LOG_JVS printf("sub_jvs_w: %02X\n", data); #endif const UINT8 *rec_data; UINT32 rec_size; jvs->write(data, rec_data, rec_size); if (rec_size > 0) { #if LOG_JVS printf("jvs reply "); for (int i=0; i < rec_size; i++) { printf("%02X ", rec_data[i]); } printf("\n"); #endif for (int i=0; i < rec_size; i++) { ppc4xx_spu_receive_byte(device, rec_data[i]); } } } static ADDRESS_MAP_START( cobra_sub_map, AS_PROGRAM, 32, cobra_state ) AM_RANGE(0x00000000, 0x003fffff) AM_MIRROR(0x80000000) AM_RAM // Main RAM AM_RANGE(0x70000000, 0x7003ffff) AM_MIRROR(0x80000000) AM_READWRITE(sub_comram_r, sub_comram_w) // Double buffered shared RAM between Main and Sub // AM_RANGE(0x78000000, 0x780000ff) AM_MIRROR(0x80000000) AM_NOP // SCSI controller (unused) AM_RANGE(0x78040000, 0x7804ffff) AM_MIRROR(0x80000000) AM_DEVREADWRITE16_LEGACY("rfsnd", rf5c400_r, rf5c400_w, 0xffffffff) AM_RANGE(0x78080000, 0x7808000f) AM_MIRROR(0x80000000) AM_READWRITE(sub_ata0_r, sub_ata0_w) AM_RANGE(0x780c0010, 0x780c001f) AM_MIRROR(0x80000000) AM_READWRITE(sub_ata1_r, sub_ata1_w) AM_RANGE(0x78200000, 0x782000ff) AM_MIRROR(0x80000000) AM_DEVREADWRITE_LEGACY("k001604", k001604_reg_r, k001604_reg_w) // PSAC registers AM_RANGE(0x78210000, 0x78217fff) AM_MIRROR(0x80000000) AM_RAM_WRITE(sub_psac_palette_w) AM_SHARE("paletteram") // PSAC palette RAM AM_RANGE(0x78220000, 0x7823ffff) AM_MIRROR(0x80000000) AM_DEVREADWRITE_LEGACY("k001604", k001604_tile_r, k001604_tile_w) // PSAC tile RAM AM_RANGE(0x78240000, 0x7827ffff) AM_MIRROR(0x80000000) AM_DEVREADWRITE_LEGACY("k001604", k001604_char_r, k001604_char_w) // PSAC character RAM AM_RANGE(0x78280000, 0x7828000f) AM_MIRROR(0x80000000) AM_NOP // ??? AM_RANGE(0x78300000, 0x7830000f) AM_MIRROR(0x80000000) AM_READWRITE(sub_psac2_r, sub_psac2_w) // PSAC AM_RANGE(0x7e000000, 0x7e000003) AM_MIRROR(0x80000000) AM_READWRITE(sub_unk7e_r, sub_debug_w) AM_RANGE(0x7e040000, 0x7e041fff) AM_MIRROR(0x80000000) AM_DEVREADWRITE8_LEGACY("m48t58", timekeeper_r, timekeeper_w, 0xffffffff) /* M48T58Y RTC/NVRAM */ AM_RANGE(0x7e180000, 0x7e180003) AM_MIRROR(0x80000000) AM_READWRITE(sub_unk1_r, sub_unk1_w) // TMS57002? AM_RANGE(0x7e200000, 0x7e200003) AM_MIRROR(0x80000000) AM_READWRITE(sub_config_r, sub_config_w) AM_RANGE(0x7e280000, 0x7e28ffff) AM_MIRROR(0x80000000) AM_NOP // LANC AM_RANGE(0x7e300000, 0x7e30ffff) AM_MIRROR(0x80000000) AM_NOP // LANC AM_RANGE(0x7e380000, 0x7e380003) AM_MIRROR(0x80000000) AM_READWRITE(sub_mainbd_r, sub_mainbd_w) AM_RANGE(0x7ff80000, 0x7fffffff) AM_MIRROR(0x80000000) AM_ROM AM_REGION("user2", 0) /* Boot ROM */ ADDRESS_MAP_END /*****************************************************************************/ // Graphics board (PPC604) // MPC106 mem settings: // Bank 0: start 0x00, end 0x7f // Bank 1: start 0x81, end 0x81 // Bank 2: start 0x82, end 0x82 // Bank 3: start 0x83, end 0x83 // Bank 4: start 0x84, end 0x84 // Bank 5: start 0x100, end 0x13f // Bank 6: start 0x180, end 0x1bf // Bank 7: start 0x1e0, end 0x1ef // IBAT0 U: 0xfff00003 L: 0xfff00001 (0xfff00000, 0xfff00000, 128KB) // IBAT1 U: 0x0000007f L: 0x00000001 (0x00000000, 0x00000000, 4MB) // IBAT2 U: 0x0040007f L: 0x07c00001 (0x00400000, 0x07c00000, 4MB) // IBAT3 U: 0x00000000 L: 0x00000001 unused // DBAT0 U: 0xfff0001f L: 0xfff0002a (0xfff00000, 0xfff00000, 1MB) // DBAT1 U: 0x0000007f L: 0x00000002 (0x00000000, 0x00000000, 4MB) // DBAT2 U: 0x0040007f L: 0x07c00002 (0x00400000, 0x07c00000, 4MB) // DBAT3 U: 0xf8fe0003 L: 0xf8fe002a (0xf8fe0000, 0xf8fe0000, 128KB) // DBAT3 U: 0x10001fff L: 0x1000000a (0x10000000, 0x10000000, 256MB) // SR0: 0x00000000 SR1: 0x00000001 SR2: 0x00000002 SR3: 0x00000003 // SR4: 0x00000004 SR5: 0x00000005 SR6: 0x00000006 SR7: 0x00000007 // SR8: 0x00000008 SR9: 0x00000009 SR10: 0x0000000a SR11: 0x0000000b // SR12: 0x0000000c SR13: 0x0000000d SR14: 0x0000000e SR15: 0x0000000f void cobra_renderer::display(bitmap_rgb32 *bitmap, const rectangle &cliprect) { if (m_gfx_register[0] & 0x4) { copybitmap_trans(*bitmap, *m_framebuffer, 0, 0, 0, 0, cliprect, 0); } else { copybitmap_trans(*bitmap, *m_backbuffer, 0, 0, 0, 0, cliprect, 0); } } void cobra_renderer::gfx_init(running_machine &machine) { const rectangle& visarea = machine.primary_screen->visible_area(); m_gfx_gram = auto_alloc_array(machine, UINT32, 0x40000); m_gfx_register = auto_alloc_array(machine, UINT64, 0x3000); m_gfx_register_select = 0; float zvalue = 10000000.0f; m_zbuffer->fill(*(int*)&zvalue, visarea); } void cobra_renderer::gfx_exit(running_machine &machine) { /* FILE *file; file = fopen("texture_ram.bin","wb"); for (int i=0; i < 0x100000; i++) { fputc((UINT8)(m_texture_ram[i] >> 24), file); fputc((UINT8)(m_texture_ram[i] >> 16), file); fputc((UINT8)(m_texture_ram[i] >> 8), file); fputc((UINT8)(m_texture_ram[i] >> 0), file); } fclose(file); */ } void cobra_renderer::gfx_reset(running_machine &machine) { cobra_state *cobra = machine.driver_data(); cobra->m_gfx_re_status = RE_STATUS_IDLE; } UINT32 cobra_renderer::gfx_read_gram(UINT32 address) { if (address & 3) { printf("gfx_read_gram: %08X, not dword aligned!\n", address); return 0; } switch ((address >> 16) & 0xf) { case 0xc: // 0xCxxxx { if ((address >= 0xc0c00 && address < 0xc1000) || (address >= 0xc4c00 && address < 0xc5000) || (address >= 0xc8c00 && address < 0xc9000) || (address >= 0xccc00 && address < 0xcd000)) { UINT32 a = (((address >> 2) & 0xff) * 2) + ((address & 0x4000) ? 1 : 0); UINT32 page = ((m_gfx_gram[0xc3028/4] >> 9) * 0x800) + ((address & 0x8000) ? 0x400 : 0) + ((m_gfx_gram[0xc3028/4] & 0x100) ? 0x200 : 0); return m_texture_ram[page + a]; } break; } } return m_gfx_gram[address/4]; } void cobra_renderer::gfx_write_gram(UINT32 address, UINT32 mask, UINT32 data) { switch ((address >> 16) & 0xf) { case 0x4: // 0x4xxxx { if (address == 0x40fff) { printf("gfx: reg 40fff = %d, %d\n", (UINT16)(data >> 16), (UINT16)(data)); } break; } case 0xc: // 0xCxxxx { switch (address & 0xffff) { case 0x3020: case 0x0020: { m_texram_ptr = (data & mask) * 4; break; } } break; } } if (address & 3) { printf("gfx_write_gram: %08X, %08X, not dword aligned!\n", address, data); return; } m_gfx_gram[address/4] &= ~mask; m_gfx_gram[address/4] |= data & mask; } UINT64 cobra_renderer::gfx_read_reg(running_machine &machine) { return m_gfx_register[m_gfx_register_select]; } void cobra_renderer::gfx_write_reg(running_machine &machine, UINT64 data) { switch (m_gfx_register_select) { case 0x0000: { const rectangle& visarea = machine.primary_screen->visible_area(); copybitmap_trans(*m_framebuffer, *m_backbuffer, 0, 0, 0, 0, visarea, 0); m_backbuffer->fill(0xff000000, visarea); float zvalue = 10000000.0f; m_zbuffer->fill(*(int*)&zvalue, visarea); break; } } m_gfx_register[m_gfx_register_select] = data; } void cobra_renderer::gfx_fifo_exec(running_machine &machine) { cobra_state *cobra = machine.driver_data(); if (cobra->m_gfx_fifo_loopback != 0) return; const rectangle& visarea = machine.primary_screen->visible_area(); vertex_t vert[32]; cobra_fifo *fifo_in = cobra->m_gfxfifo_in; cobra_fifo *fifo_out = cobra->m_gfxfifo_out; while (fifo_in->current_num() >= 2) { UINT64 in1, in2 = 0; UINT32 w1, w2; if (cobra->m_gfx_re_status == RE_STATUS_IDLE) { fifo_in->pop(NULL, &in1); fifo_in->pop(NULL, &in2); w1 = (UINT32)(in1); w2 = (UINT32)(in2); cobra->m_gfx_re_command_word1 = w1; cobra->m_gfx_re_command_word2 = w2; cobra->m_gfx_re_word_count = 0; cobra->m_gfx_re_status = RE_STATUS_COMMAND; } else { w1 = cobra->m_gfx_re_command_word1; w2 = cobra->m_gfx_re_command_word2; } switch ((w1 >> 24) & 0xff) { case 0x00: { UINT64 param[6]; UINT32 w[6]; if (fifo_in->current_num() < 6) { // wait until there's enough data in FIFO memset(param, 0, sizeof(param)); memset(w, 0, sizeof(w)); return; } fifo_in->pop(NULL, ¶m[0]); fifo_in->pop(NULL, ¶m[1]); fifo_in->pop(NULL, ¶m[2]); fifo_in->pop(NULL, ¶m[3]); fifo_in->pop(NULL, ¶m[4]); fifo_in->pop(NULL, ¶m[5]); w[0] = (UINT32)param[0]; w[1] = (UINT32)param[1]; w[2] = (UINT32)param[2]; w[3] = (UINT32)param[3]; w[4] = (UINT32)param[4]; w[5] = (UINT32)param[5]; // mbuslib_pumpkin(): 0x00600000 0x10500010 // 0x00600000 0x10500018 if (w2 == 0x10500010) { // GFX register select m_gfx_register_select = w[3]; printf("GFX: register select %08X\n", m_gfx_register_select); } else if (w2 == 0x10500018) { // register write to the register selected above? // 64-bit registers, top 32-bits in word 2, low 32-bit in word 3 printf("GFX: register write %08X: %08X %08X\n", m_gfx_register_select, w[2], w[3]); gfx_write_reg(machine, ((UINT64)(w[2]) << 32) | w[3]); } else if (w2 == 0x10521000) { printf("gfxfifo_exec: unknown %08X %08X %08X %08X\n", w1, w2, w[0], w[1]); printf(" %08X %08X %08X %08X\n", w[2], w[3], w[4], w[5]); } else { logerror("gfxfifo_exec: unknown %08X %08X\n", w1, w2); } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0x0f: case 0xf0: { UINT64 in3 = 0, in4 = 0, ignore; // check_mergebus_self(): 0x0F600000 0x10520C00 if (fifo_in->current_num() < 6) { // wait until there's enough data in FIFO return; } if (w1 != 0x0f600000 && w1 != 0xf0600000) { logerror("gfxfifo_exec: unknown %08X %08X\n", w1, w2); } //printf("gfxfifo_exec: unhandled %08X %08X\n", w1, w2); fifo_in->pop(NULL, &in3); fifo_in->pop(NULL, &in4); fifo_in->pop(NULL, &ignore); fifo_in->pop(NULL, &ignore); fifo_in->pop(NULL, &ignore); fifo_in->pop(NULL, &ignore); if (w1 == 0x0f600000 && w2 == 0x10520c00) { fifo_out->push(NULL, w1); fifo_out->push(NULL, w2); fifo_out->push(NULL, in3); fifo_out->push(NULL, in4); } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xf1: case 0xf4: { //printf("gfxfifo_exec: unhandled %08X %08X\n", w1, w2); cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xe0: case 0xe2: case 0xe3: { // Draw graphics primitives // 0x00: xxxx---- -------- -------- -------- Command // 0x00: ----xxxx -------- -------- -------- Primitive type (0 = triangle, 2 = point, 3 = line) // 0x00: -------- xx------ -------- -------- ? // 0x00: -------- -------- -------- xxxxxxxx Number of units (amount of bits is uncertain) // // 0x01: -x------ -------- -------- -------- Has extra flags word (used by lines only) // 0x01: --x----- -------- -------- -------- Has extra unknown float (seems to be fog-related?) // 0x01: ---x---- -------- -------- -------- Always 1? // 0x01: -------- xx------ -------- -------- ? // 0x01: -------- --x----- -------- -------- Has texture coords // 0x01: -------- ---x---- -------- -------- ? // 0x01: -------- ----x--- -------- -------- ? // 0x01: -------- -------- ------xx xx------ ? (always set to 1s?) // 0x01: -------- -------- -------- -------x Has extra unknown float int i; int num = 0; int units = w1 & 0xff; // determine the expected packet size to see if we can process it yet int unit_size = 8; if (w2 & 0x40000000) unit_size += 1; // lines only if (w2 & 0x20000000) unit_size += 1; // unknown float if (w2 & 0x00200000) unit_size += 3; // texture coords? if (w2 & 0x00000001) unit_size += 1; // ? num = unit_size * units; if (fifo_in->current_num() < num) { // wait until there's enough data in FIFO return; } float vp_width = u2f(m_gfx_gram[0x00090/4]); float vp_height = u2f(m_gfx_gram[0x000a4/4]); float vp_center_x = u2f(m_gfx_gram[0x0009c/4]); float vp_center_y = u2f(m_gfx_gram[0x000ac/4]); if (vp_width == 0.0f) { vp_width = 256.0f; vp_center_x = 256.0f; } #if LOG_DRAW_COMMANDS printf("--- Draw command %08X %08X ---\n", w1, w2); #endif // extract vertex data for (int i=0; i < units; i++) { float x, y, z, w; float r, g, b, a; w = 1.0f; UINT64 in[4]; if (w2 & 0x40000000) // line flags { fifo_in->pop(NULL, &in[0]); } if (w2 & 0x20000000) // unknown float (0.0f ... 1.0f) { fifo_in->pop(NULL, &in[1]); } fifo_in->pop(NULL, &x); // X coord fifo_in->pop(NULL, &y); // Y coord fifo_in->pop(NULL, &in[2]); // coord? fifo_in->pop(NULL, &z); // Z coord if (w2 & 0x00200000) // texture coords { fifo_in->pop(NULL, &w); // W coord (1 / Z) fifo_in->pop(NULL, &vert[i].p[POLY_U]); // U/Z coord fifo_in->pop(NULL, &vert[i].p[POLY_V]); // V/Z coord } fifo_in->pop(NULL, &a); // Gouraud Color Alpha fifo_in->pop(NULL, &r); // Gouraud Color R fifo_in->pop(NULL, &g); // Gouraud Color G fifo_in->pop(NULL, &b); // Gouraud Color B if (w2 & 0x00000001) // unknown float (0.0f ... 1.0f) { fifo_in->pop(NULL, &in[3]); } vert[i].x = ((x / z) * vp_width) + vp_center_x; vert[i].y = ((y / z) * vp_height) + vp_center_y; vert[i].p[POLY_Z] = z; vert[i].p[POLY_W] = w; vert[i].p[POLY_R] = r * 255.0f; vert[i].p[POLY_G] = g * 255.0f; vert[i].p[POLY_B] = b * 255.0f; vert[i].p[POLY_A] = a * 255.0f; #if LOG_DRAW_COMMANDS if (w2 & 0x40000000) { printf(" ?: %08X\n", (UINT32)in[0]); } if (w2 & 0x20000000) { printf(" ?: %08X\n", (UINT32)in[1]); } printf(" x: %f\n", x); printf(" y: %f\n", y); printf(" ?: %08X\n", (UINT32)in[2]); printf(" z: %f\n", z); if (w2 & 0x00200000) { printf(" w: %f\n", w); printf(" u: %f\n", vert[i].p[POLY_U]); printf(" v: %f\n", vert[i].p[POLY_V]); } printf(" a: %f\n", a); printf(" r: %f\n", r); printf(" g: %f\n", g); printf(" b: %f\n", b); if (w2 & 0x00000001) { printf(" ?: %08X\n", (UINT32)in[3]); } printf("\n"); #endif } cobra_polydata &extra = object_data_alloc(); int texture = (m_gfx_gram[0x400f4/4] >> 29); extra.alpha_test = m_gfx_gram[0x40198/4] & 0x80000000; extra.zmode = (m_gfx_gram[0x80020/4] >> 17) & 0x7; extra.tex_format = m_gfx_gram[(0x2910 + (texture << 7)) / 4]; extra.tex_address = (m_gfx_gram[(0x2914 + (texture << 7)) / 4] >> 12) & 0xfffff; // render switch ((w1 >> 24) & 0xf) { case 0x0: // triangles { if (w2 & 0x00200000) { render_delegate rd = render_delegate(FUNC(cobra_renderer::render_texture_scan), this); for (int i=2; i < units; i++) { render_triangle(visarea, rd, 8, vert[i-2], vert[i-1], vert[i]); } } else { render_delegate rd = render_delegate(FUNC(cobra_renderer::render_color_scan), this); for (int i=2; i < units; i++) { render_triangle(visarea, rd, 5, vert[i-2], vert[i-1], vert[i]); } } break; } case 0x2: // points { for (int i=0; i < units; i++) { draw_point(visarea, vert[i], 0xffffffff); } break; } case 0x3: // lines { if ((units & 1) == 0) // batches of lines { for (i=0; i < units; i+=2) { draw_line(visarea, vert[i], vert[i+1]); } } else // line strip { printf("GFX: linestrip %08X, %08X\n", w1, w2); } break; } default: { printf("gfxfifo_exec: unhandled %08X %08X\n", w1, w2); break; } } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xe8: { // Write into a pixelbuffer int num = w2; int i; if (fifo_in->current_num() < num) { // wait until there's enough data in FIFO return; } if (num & 3) fatalerror("gfxfifo_exec: e8 with num %d\n", num); int x = (m_gfx_gram[0x118/4] >> 16) & 0xffff; int y = m_gfx_gram[0x118/4] & 0xffff; x &= 0x3ff; y &= 0x3ff; for (i=0; i < num; i+=4) { UINT32 *buffer; switch (m_gfx_gram[0x80104/4]) { case 0x800000: buffer = &m_framebuffer->pix32(y); break; case 0x200000: buffer = &m_backbuffer->pix32(y); break; case 0x0e0000: buffer = &m_overlay->pix32(y); break; case 0x000800: buffer = &m_zbuffer->pix32(y); break; case 0x000200: buffer = &m_stencil->pix32(y); break; default: { fatalerror("gfxfifo_exec: fb write to buffer %08X!\n", m_gfx_gram[0x80100/4]); } } UINT64 param[4]; param[0] = param[1] = param[2] = param[3] = 0; fifo_in->pop(NULL, ¶m[0]); fifo_in->pop(NULL, ¶m[1]); fifo_in->pop(NULL, ¶m[2]); fifo_in->pop(NULL, ¶m[3]); buffer[x+0] = (UINT32)(param[0]); buffer[x+1] = (UINT32)(param[1]); buffer[x+2] = (UINT32)(param[2]); buffer[x+3] = (UINT32)(param[3]); //printf("gfx: fb write %d, %d: %08X %08X %08X %08X\n", x, y, (UINT32)(param[0]), (UINT32)(param[1]), (UINT32)(param[2]), (UINT32)(param[3])); y++; } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xe9: { // Read a specified pixel position from a pixelbuffer // printf("GFX: FB read X: %d, Y: %d\n", (UINT16)(m_gfx_gram[0x118/4] >> 16), (UINT16)(m_gfx_gram[0x118/4])); int x = (m_gfx_gram[0x118/4] >> 16) & 0xffff; int y = m_gfx_gram[0x118/4] & 0xffff; UINT32 *buffer; switch (m_gfx_gram[0x80104/4]) { case 0x800000: buffer = &m_framebuffer->pix32(y); break; case 0x200000: buffer = &m_backbuffer->pix32(y); break; case 0x0e0000: buffer = &m_overlay->pix32(y); break; case 0x000800: buffer = &m_zbuffer->pix32(y); break; case 0x000200: buffer = &m_stencil->pix32(y); break; default: { fatalerror("gfxfifo_exec: fb read from buffer %08X!\n", m_gfx_gram[0x80100/4]); } } // flush fifo_out so we have fresh data at top fifo_out->flush(); fifo_out->push(NULL, buffer[x+0]); fifo_out->push(NULL, buffer[x+1]); fifo_out->push(NULL, buffer[x+2]); fifo_out->push(NULL, buffer[x+3]); cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0x8f: { // buf_flush(): 0x8FFF0000 0x00000000 if (w1 != 0x8fff0000 || w2 != 0x00000000) { logerror("gfxfifo_exec: buf_flush: %08X %08X\n", w1, w2); } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0x80: case 0xa4: case 0xa8: case 0xac: { // 0xA80114CC prm_flashcolor() // 0xA80118CC // 0xA80108FF // 0xA80108FF prm_flashmisc() // 0xA80110FF // 0xA8011CE0 // 0xA401BCC0 texenvmode() // 0xA4019CC0 mode_fog() // 0xA40018C0 mode_stipple() // 0xA400D080 // 0xA40138E0 mode_viewclip() // 0xA4011410 mode_scissor() // 0xA40198A0 mode_alphatest() // 0xA8002010 mode_depthtest() // 0xA800507C mode_blend() // 0xA8001CFE mode_stenciltest() // 0xA8002010 mode_stencilmod() // 0xA80054E0 // 0xA8001CFE // 0xA80118CC mode_colormask() // 0xA80114CC // 0xAxxxxxxx is different form in mbuslib_regwrite() // mbuslib_regwrite(): 0x800000FF 0x00000001 // 0xa40000FF 0x00000001 int reg = (w1 >> 8) & 0xfffff; UINT32 mask = m_gfx_regmask[w1 & 0xff]; gfx_write_gram(reg, mask, w2); #if LOG_GFX_RAM_WRITES if (reg != 0x118 && reg != 0x114 && reg != 0x11c) { printf("gfxfifo_exec: ram write %05X (mask %08X): %08X (%f)\n", reg, mask, w2, u2f(w2)); } #endif cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xb0: { // write multiple registers // mbuslib_pip_ints(): 0xB0300800 0x000001FE int reg = (w1 >> 8) & 0xfffff; int num = w2; int i; if (fifo_in->current_num() < num) { return; } printf("gfxfifo_exec: pip_ints %d\n", num); // writes to n ram location starting from x? for (i = 0; i < num; i++) { UINT64 value = 0; fifo_in->pop(NULL, &value); gfx_write_gram(reg + (i*4), 0xffffffff, value); } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xc0: case 0xc4: case 0xc8: case 0xcc: { // mbuslib_regread(): 0xC0300800 0x00000000 // read from register int reg = (w1 >> 8) & 0xfffff; UINT32 ret = gfx_read_gram(reg); fifo_out->push(NULL, ret); // printf("GFX: reg read %08X\n", reg); cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xd0: { // read multiple registers // 0xD0301000 0x000001FC int reg = (w1 >> 8) & 0xfffff; int num = w2; int i; if (fifo_out->space_left() < num) { return; } // reads back n ram locations starting from x? for (i=0; i < num; i++) { UINT32 value = gfx_read_gram(reg + (i*4)); fifo_out->push(NULL, value); } cobra->m_gfx_re_status = RE_STATUS_IDLE; break; } case 0xed: { // mbuslib_tex_ints()? //int reg = (w1 >> 8) & 0xff; int num = w2; int num_left = num - cobra->m_gfx_re_word_count; if (fifo_in->current_num() < num_left) { num_left = fifo_in->current_num(); } cobra->m_gfx_unk_status |= 0x400; if (cobra->m_gfx_re_word_count == 0 && num_left > 0) printf("gfxfifo_exec: tex_ints %d words left\n", num - cobra->m_gfx_re_word_count); for (int i=0; i < num_left; i++) { UINT64 param = 0; fifo_in->pop(NULL, ¶m); cobra->m_gfx_re_word_count++; m_texture_ram[m_texram_ptr] = (UINT32)(param); m_texram_ptr++; } if (cobra->m_gfx_re_word_count >= num) { cobra->m_gfx_re_status = RE_STATUS_IDLE; } break; } default: { int k = 0; int c = 0; printf("gfxfifo_exec: unknown command %08X %08X\n", w1, w2); if (fifo_in->current_num() < 0) { return; } while (fifo_in->current_num() > 0) { UINT64 param; fifo_in->pop(NULL, ¶m); if (c == 0) printf(" "); printf("%08X ", (UINT32)(param)); c++; if (c == 4) { printf("\n"); c = 0; } k++; }; logerror("\n"); } } // printf("gfxfifo_exec: %08X %08X\n", w1, w2); }; wait(); } READ64_MEMBER(cobra_state::gfx_fifo_r) { UINT64 r = 0; m_renderer->gfx_fifo_exec(space.machine()); if (ACCESSING_BITS_32_63) { UINT64 data; m_gfxfifo_out->pop(&space.device(), &data); data &= 0xffffffff; r |= (UINT64)(data) << 32; } if (ACCESSING_BITS_0_31) { UINT64 data; m_gfxfifo_out->pop(&space.device(), &data); data &= 0xffffffff; r |= (UINT64)(data); } // printf("GFX FIFO read %08X%08X\n", (UINT32)(r >> 32), (UINT32)(r)); return r; } WRITE64_MEMBER(cobra_state::gfx_fifo0_w) { m_gfx_fifo_cache_addr = 2; COMBINE_DATA(m_gfx_fifo_mem + offset); } WRITE64_MEMBER(cobra_state::gfx_fifo1_w) { m_gfx_fifo_cache_addr = 0; COMBINE_DATA(m_gfx_fifo_mem + offset); } WRITE64_MEMBER(cobra_state::gfx_fifo2_w) { m_gfx_fifo_cache_addr = 1; COMBINE_DATA(m_gfx_fifo_mem + offset); } READ64_MEMBER(cobra_state::gfx_unk1_r) { UINT64 r = 0; if (ACCESSING_BITS_56_63) { UINT64 v = 0; // mbuslib_init fails if bits 3-7 (0x78) are not set v |= 0x78; // the low 2 bits are vblank flags // bit 3 (0x8) may be graphics engine idle flag v |= m_gfx_status_byte; m_gfx_status_byte ^= 1; r |= v << 56; } if (ACCESSING_BITS_40_47) { // mbuslib_init fails if this is not 0x7f r |= (UINT64) 0x7f << 40; } if (ACCESSING_BITS_24_31) // this register returns FIFO number during check_fifo (see below) { r |= (m_gfx_unknown_v1 & 3) << 24; } return r; } WRITE64_MEMBER(cobra_state::gfx_unk1_w) { // printf("gfx_unk1_w: %08X %08X, %08X%08X\n", (UINT32)(data >> 32), (UINT32)(data), (UINT32)(mem_mask >> 32), (UINT32)(mem_mask)); if (ACCESSING_BITS_56_63) { if ((data >> 63) & 1) { m_gfx_fifo_loopback = 0; } } if (ACCESSING_BITS_24_31) { UINT64 in1, in2; int value = (data >> 24) & 0xff; // used in check_fifo(). fifo loopback or something? if (value == 0xc0) { m_gfxfifo_in->pop(&space.device(), &in1); m_gfxfifo_in->pop(&space.device(), &in2); m_gfx_unknown_v1 = (UINT32)(in1 >> 32); // FIFO number is read back from this same register m_gfxfifo_out->push(&space.device(), in1 & 0xffffffff); m_gfxfifo_out->push(&space.device(), in2 & 0xffffffff); } else if (value == 0x80) { // used in check_fifo() before the fifo test... m_gfx_fifo_loopback = 1; } else { printf("gfx_unk1_w: unknown value %02X\n", value); } } } WRITE64_MEMBER(cobra_state::gfx_buf_w) { // printf("buf_w: top = %08X\n", gfxfifo_get_top()); // buf_prc_read: 0x00A00001 0x10520200 // 0x00A00001 0x10500018 // teximage_load() / mbuslib_prc_read(): 0x00A00001 0x10520800 // printf("prc_read %08X%08X at %08X\n", (UINT32)(data >> 32), (UINT32)(data), activecpu_get_pc()); m_renderer->gfx_fifo_exec(space.machine()); if (data == U64(0x00a0000110500018)) { m_gfxfifo_out->flush(); // reads back the register selected by gfx register select UINT64 regdata = m_renderer->gfx_read_reg(space.machine()); m_gfxfifo_out->push(&space.device(), (UINT32)(regdata >> 32)); m_gfxfifo_out->push(&space.device(), (UINT32)(regdata)); } else if (data == U64(0x00a0000110520800)) { // in teximage_load() // some kind of busy flag for mbuslib_tex_ints()... // mbuslib_tex_ints() waits for bit 0x400 to be set // memcheck_teximage() wants 0x400 cleared m_gfxfifo_out->push(&space.device(), m_gfx_unk_status); m_gfx_unk_status &= ~0x400; } else if (data != U64(0x00a0000110520200)) // mbuslib_regread() { // prc_read always expects a value... m_gfxfifo_out->push(&space.device(), 0); } } static void gfx_cpu_dc_store(device_t *device, UINT32 address) { cobra_state *cobra = device->machine().driver_data(); UINT32 addr = address >> 24; if (addr == 0x10 || addr == 0x18 || addr == 0x1e) { UINT64 i = (UINT64)(cobra->m_gfx_fifo_cache_addr) << 32; cobra_fifo *fifo_in = cobra->m_gfxfifo_in; UINT32 a = (address / 8) & 0xff; fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+0] >> 32) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+0] >> 0) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+1] >> 32) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+1] >> 0) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+2] >> 32) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+2] >> 0) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+3] >> 32) | i); fifo_in->push(device, (UINT32)(cobra->m_gfx_fifo_mem[a+3] >> 0) | i); cobra->m_renderer->gfx_fifo_exec(device->machine()); } else { logerror("gfx: data cache store at %08X\n", address); } } WRITE64_MEMBER(cobra_state::gfx_debug_state_w) { if (ACCESSING_BITS_40_47) { m_gfx_unk_flag = (UINT8)(data >> 40); } if (ACCESSING_BITS_56_63) { m_gfx_debug_state |= decode_debug_state_value((data >> 56) & 0xff) << 4; m_gfx_debug_state_wc++; } if (ACCESSING_BITS_48_55) { m_gfx_debug_state |= decode_debug_state_value((data >> 48) & 0xff); m_gfx_debug_state_wc++; } if (m_gfx_debug_state_wc >= 2) { #if LOG_DEBUG_STATES if (m_gfx_debug_state != 0) { printf("GFX: debug state %02X\n", m_gfx_debug_state); } #endif m_gfx_debug_state = 0; m_gfx_debug_state_wc = 0; } } static ADDRESS_MAP_START( cobra_gfx_map, AS_PROGRAM, 64, cobra_state ) AM_RANGE(0x00000000, 0x003fffff) AM_RAM AM_SHARE("gfx_main_ram_0") AM_RANGE(0x07c00000, 0x07ffffff) AM_RAM AM_SHARE("gfx_main_ram_1") AM_RANGE(0x10000000, 0x100007ff) AM_WRITE(gfx_fifo0_w) AM_RANGE(0x18000000, 0x180007ff) AM_WRITE(gfx_fifo1_w) AM_RANGE(0x1e000000, 0x1e0007ff) AM_WRITE(gfx_fifo2_w) AM_RANGE(0x20000000, 0x20000007) AM_WRITE(gfx_buf_w) // this might really map to 0x1e000000, depending on the pagetable AM_RANGE(0x7f000000, 0x7f00ffff) AM_RAM AM_SHARE("pagetable") AM_RANGE(0xfff00000, 0xfff7ffff) AM_ROM AM_REGION("user3", 0) /* Boot ROM */ AM_RANGE(0xfff80000, 0xfff80007) AM_WRITE(gfx_debug_state_w) AM_RANGE(0xffff0000, 0xffff0007) AM_READWRITE(gfx_unk1_r, gfx_unk1_w) AM_RANGE(0xffff0010, 0xffff001f) AM_READ(gfx_fifo_r) ADDRESS_MAP_END /*****************************************************************************/ INPUT_PORTS_START( cobra ) PORT_START("TEST") PORT_SERVICE_NO_TOGGLE( 0x80, IP_ACTIVE_LOW) /* Test Button */ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Service") PORT_CODE(KEYCODE_7) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE2 ) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("P1") PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_PLAYER(1) PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(1) PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(1) PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(1) PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(1) PORT_START("P2") PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_PLAYER(2) PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(2) PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(2) PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(2) PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_PLAYER(2) INPUT_PORTS_END static powerpc_config main_ppc_cfg = { XTAL_66_6667MHz, /* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */ NULL, NULL }; static powerpc_config gfx_ppc_cfg = { XTAL_66_6667MHz, /* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */ NULL, NULL }; static const k001604_interface cobra_k001604_intf = { 0, 1, /* gfx index 1 & 2 */ 0, 1, /* layer_size, roz_size */ 0 /* slrasslt hack */ }; WRITE_LINE_MEMBER(cobra_state::ide_interrupt) { if (state == CLEAR_LINE) { m_sub_interrupt |= 0x80; } else { m_sub_interrupt &= ~0x80; } } INTERRUPT_GEN_MEMBER(cobra_state::cobra_vblank) { if (m_vblank_enable & 0x80) { device.execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); m_gfx_unk_flag = 0x80; } } void cobra_state::machine_reset() { m_sub_interrupt = 0xff; ide_controller_device *ide = (ide_controller_device *) machine().device("ide"); UINT8 *ide_features = ide->ide_get_features(0); // Cobra expects these settings or the BIOS fails ide_features[51*2+0] = 0; /* 51: PIO data transfer cycle timing mode */ ide_features[51*2+1] = 2; ide_features[67*2+0] = 0xe0; /* 67: minimum PIO transfer cycle time without flow control */ ide_features[67*2+1] = 0x01; m_renderer->gfx_reset(machine()); m_sound_dma_ptr = 0; m_dmadac[0] = machine().device("dac1"); m_dmadac[1] = machine().device("dac2"); dmadac_enable(&m_dmadac[0], 1, 1); dmadac_enable(&m_dmadac[1], 1, 1); dmadac_set_frequency(&m_dmadac[0], 1, 44100); dmadac_set_frequency(&m_dmadac[1], 1, 44100); } static MACHINE_CONFIG_START( cobra, cobra_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", PPC603, 100000000) /* 603EV, 100? MHz */ MCFG_CPU_CONFIG(main_ppc_cfg) MCFG_CPU_PROGRAM_MAP(cobra_main_map) MCFG_CPU_VBLANK_INT_DRIVER("screen", cobra_state, cobra_vblank) MCFG_CPU_ADD("subcpu", PPC403GA, 32000000) /* 403GA, 33? MHz */ MCFG_CPU_PROGRAM_MAP(cobra_sub_map) MCFG_CPU_ADD("gfxcpu", PPC604, 100000000) /* 604, 100? MHz */ MCFG_CPU_CONFIG(gfx_ppc_cfg) MCFG_CPU_PROGRAM_MAP(cobra_gfx_map) MCFG_QUANTUM_TIME(attotime::from_hz(15005)) MCFG_PCI_BUS_LEGACY_ADD("pcibus", 0) MCFG_PCI_BUS_LEGACY_DEVICE(0, NULL, mpc106_pci_r, mpc106_pci_w) MCFG_IDE_CONTROLLER_ADD("ide", ide_devices, "hdd", NULL, true) MCFG_IDE_CONTROLLER_IRQ_HANDLER(DEVWRITELINE(DEVICE_SELF, cobra_state, ide_interrupt)) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_SIZE(512, 400) MCFG_SCREEN_VISIBLE_AREA(0, 511, 0, 399) MCFG_PALETTE_LENGTH(65536) MCFG_SCREEN_UPDATE_DRIVER(cobra_state, screen_update_cobra) MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") MCFG_SOUND_ADD("rfsnd", RF5C400, XTAL_16_9344MHz) MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) MCFG_SOUND_ADD("dac1", DMADAC, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) MCFG_SOUND_ADD("dac2", DMADAC, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) MCFG_M48T58_ADD("m48t58") MCFG_K001604_ADD("k001604", cobra_k001604_intf) // on the LAN board in Racing Jam DX MCFG_DEVICE_ADD("cobra_jvs_host", COBRA_JVS_HOST, 4000000) MCFG_JVS_DEVICE_ADD("cobra_jvs", COBRA_JVS, "cobra_jvs_host") MACHINE_CONFIG_END /*****************************************************************************/ /*****************************************************************************/ DRIVER_INIT_MEMBER(cobra_state, cobra) { m_gfxfifo_in = auto_alloc(machine(), cobra_fifo(machine(), 8192, "GFXFIFO_IN", GFXFIFO_IN_VERBOSE != 0, cobra_fifo::event_delegate(FUNC(cobra_state::gfxfifo_in_event_callback), this)) ); m_gfxfifo_out = auto_alloc(machine(), cobra_fifo(machine(), 8192, "GFXFIFO_OUT", GFXFIFO_OUT_VERBOSE != 0, cobra_fifo::event_delegate(FUNC(cobra_state::gfxfifo_out_event_callback), this)) ); m_m2sfifo = auto_alloc(machine(), cobra_fifo(machine(), 2048, "M2SFIFO", M2SFIFO_VERBOSE != 0, cobra_fifo::event_delegate(FUNC(cobra_state::m2sfifo_event_callback), this)) ); m_s2mfifo = auto_alloc(machine(), cobra_fifo(machine(), 2048, "S2MFIFO", S2MFIFO_VERBOSE != 0, cobra_fifo::event_delegate(FUNC(cobra_state::s2mfifo_event_callback), this)) ); ppc_set_dcstore_callback(m_maincpu, main_cpu_dc_store); ppc_set_dcstore_callback(m_gfxcpu, gfx_cpu_dc_store); ppc4xx_set_dma_write_handler(m_subcpu, 0, sub_sound_dma_w, 44100); ppc4xx_spu_set_tx_handler(m_subcpu, sub_jvs_w); m_comram[0] = auto_alloc_array(machine(), UINT32, 0x40000/4); m_comram[1] = auto_alloc_array(machine(), UINT32, 0x40000/4); m_comram_page = 0; m_sound_dma_buffer_l = auto_alloc_array(machine(), INT16, DMA_SOUND_BUFFER_SIZE); m_sound_dma_buffer_r = auto_alloc_array(machine(), INT16, DMA_SOUND_BUFFER_SIZE); // setup fake pagetable until we figure out what really maps there... //m_gfx_pagetable[0x80 / 8] = U64(0x800001001e0001a8); m_gfx_pagetable[0x80 / 8] = U64(0x80000100200001a8); // should this map to 0x1e000000? } DRIVER_INIT_MEMBER(cobra_state,bujutsu) { DRIVER_INIT_CALL(cobra); // rom hacks for sub board... { UINT32 *rom = (UINT32*)machine().root_device().memregion("user2")->base(); rom[0x62094 / 4] = 0x60000000; // skip hardcheck()... } // rom hacks for gfx board... { int i; UINT32 sum = 0; UINT32 *rom = (UINT32*)machine().root_device().memregion("user3")->base(); rom[(0x022d4^4) / 4] = 0x60000000; // skip init_raster() for now ... // calculate the checksum of the patched rom... for (i=0; i < 0x20000/4; i++) { sum += (UINT8)((rom[i] >> 24) & 0xff); sum += (UINT8)((rom[i] >> 16) & 0xff); sum += (UINT8)((rom[i] >> 8) & 0xff); sum += (UINT8)((rom[i] >> 0) & 0xff); } rom[(0x0001fff0^4) / 4] = sum; rom[(0x0001fff4^4) / 4] = ~sum; } // fill in M48T58 data for now... { UINT8 *rom = (UINT8*)machine().root_device().memregion("m48t58")->base(); rom[0x00] = 0x47; // G rom[0x01] = 0x4e; // N // N = 2-player, Q = 1-player? rom[0x02] = 0x36; // 6 rom[0x03] = 0x34; // 4 rom[0x04] = 0x35; // 5 rom[0x05] = 0x00; rom[0x06] = 0x00; rom[0x07] = 0x00; rom[0x08] = 0x00; rom[0x09] = 0x00; rom[0x0a] = 0x4a; // J rom[0x0b] = 0x41; // A rom[0x0c] = 0x41; // A rom[0x0d] = 0x00; // calculate checksum UINT16 sum = 0; for (int i=0; i < 14; i+=2) { sum += ((UINT16)(rom[i]) << 8) | (rom[i+1]); } sum ^= 0xffff; rom[0x0e] = (UINT8)(sum >> 8); rom[0x0f] = (UINT8)(sum); } // hd patches // (gfx) // 0x18932c = 0x38600000 skips check_one_scene() // (sub) // 0x2d3568 = 0x60000000 [0x4082001c] skip IRQ fail // (main) // 0x5025ac = 0x60000000 [0x4082055c] skip IRQ fail... // 0x503ec4 = 0x60000000 [0x4186fff8] // 0x503f00 = 0x60000000 [0x4186fff8] m_has_psac = false; } DRIVER_INIT_MEMBER(cobra_state,racjamdx) { DRIVER_INIT_CALL(cobra); // rom hacks for sub board... { UINT32 *rom = (UINT32*)machine().root_device().memregion("user2")->base(); rom[0x62094 / 4] = 0x60000000; // skip hardcheck()... rom[0x62ddc / 4] = 0x60000000; // skip lanc_hardcheck() // calculate the checksum of the patched rom... UINT32 sum = 0; for (int i=0; i < 0x20000/4; i++) { sum += (UINT8)((rom[(0x60000/4)+i] >> 24) & 0xff); sum += (UINT8)((rom[(0x60000/4)+i] >> 16) & 0xff); sum += (UINT8)((rom[(0x60000/4)+i] >> 8) & 0xff); sum += (UINT8)((rom[(0x60000/4)+i] >> 0) & 0xff); } rom[(0x0007fff0^4) / 4] = ~sum; rom[(0x0007fff4^4) / 4] = sum; } // rom hacks for gfx board... { int i; UINT32 sum = 0; UINT32 *rom = (UINT32*)machine().root_device().memregion("user3")->base(); rom[(0x02448^4) / 4] = 0x60000000; // skip init_raster() for now ... rom[(0x02438^4) / 4] = 0x60000000; // awfully long delay loop (5000000 * 166) // calculate the checksum of the patched rom... for (i=0; i < 0x20000/4; i++) { sum += (UINT8)((rom[i] >> 24) & 0xff); sum += (UINT8)((rom[i] >> 16) & 0xff); sum += (UINT8)((rom[i] >> 8) & 0xff); sum += (UINT8)((rom[i] >> 0) & 0xff); } rom[(0x0001fff0^4) / 4] = sum; rom[(0x0001fff4^4) / 4] = ~sum; } // fill in M48T58 data for now... { UINT8 *rom = (UINT8*)machine().root_device().memregion("m48t58")->base(); rom[0x00] = 0x47; // G rom[0x01] = 0x59; // Y rom[0x02] = 0x36; // 6 rom[0x03] = 0x37; // 7 rom[0x04] = 0x36; // 6 rom[0x05] = 0x00; rom[0x06] = 0x00; rom[0x07] = 0x00; // calculate checksum UINT16 sum = 0; for (int i=0; i < 14; i+=2) { sum += ((UINT16)(rom[i]) << 8) | (rom[i+1]); } sum ^= 0xffff; rom[0x0e] = (UINT8)(sum >> 8); rom[0x0f] = (UINT8)(sum); } // hd patches // (gfx) // 0x144354 = 0x38600000 [0x4bfffb91] skips check_one_scene() // (sub) // 0x2a5394 = 0x4800001c [0x4182001c] sound chip check? // 0x2a53f4 = 0x4800001c [0x4082001c] ? // 0x2a546c = 0x60000000 [0x48001a0d] ? // 0x2a5510 = 0x48000014 [0x419e0014] ? // (main) // 0x14aa48 = 0x60000000 [0x4182fff4] ? m_has_psac = true; } /*****************************************************************************/ ROM_START(bujutsu) ROM_REGION64_BE(0x80000, "user1", 0) /* Main CPU program (PPC603) */ ROM_LOAD("645a01.33d", 0x00000, 0x80000, CRC(cb1a8683) SHA1(77b7dece84dc17e9d63242347b7202e879b9a10e) ) ROM_REGION32_BE(0x80000, "user2", 0) /* Sub CPU program (PPC403) */ ROM_LOAD("645a02.24r", 0x00000, 0x80000, CRC(7d1c31bd) SHA1(94907c4068a488a74b2fa9a486c832d380c5b184) ) ROM_REGION64_BE(0x80000, "user3", 0) /* Gfx CPU program (PPC604) */ ROM_LOAD("645a03.u17", 0x00000, 0x80000, CRC(086abd0b) SHA1(24df439eb9828ed3842f43f5f4014a3fc746e1e3) ) ROM_REGION(0x2000, "m48t58", ROMREGION_ERASE00) ROM_LOAD( "m48t58-70pc1.17l", 0x000000, 0x002000, NO_DUMP ) ROM_REGION(0x1000000, "rfsnd", ROMREGION_ERASE00) DISK_REGION( "drive_0" ) DISK_IMAGE_READONLY( "645c04", 0, SHA1(c0aabe69f6eb4e4cf748d606ae50674297af6a04) ) ROM_END ROM_START(racjamdx) ROM_REGION64_BE(0x80000, "user1", 0) /* Main CPU program (PPC603) */ ROM_LOAD( "676a01.33d", 0x000000, 0x080000, CRC(1e6238f1) SHA1(d55949d98e9e290ceb8c018ed60ca090ec16c9dd) ) ROM_REGION32_BE(0x80000, "user2", 0) /* Sub CPU program (PPC403) */ ROM_LOAD( "676a02.24r", 0x000000, 0x080000, CRC(371978ed) SHA1(c83f0cf04204212db00588df91b32122f37900f8) ) ROM_REGION64_BE(0x80000, "user3", 0) /* Gfx CPU program (PPC604) */ ROM_LOAD( "676a03.u17", 0x000000, 0x080000, CRC(66f77cbd) SHA1(f1c7e50dbbfcc27ac011cbbb8ad2fd376c2e9056) ) ROM_REGION(0x2000, "m48t58", ROMREGION_ERASE00) ROM_LOAD( "m48t58-70pc1.17l", 0x000000, 0x002000, NO_DUMP ) ROM_REGION(0x1000000, "rfsnd", ROMREGION_ERASE00) DISK_REGION( "drive_0" ) DISK_IMAGE_READONLY( "676a04", 0, SHA1(8e89d3e5099e871b99fccba13adaa3cf8a6b71f0) ) ROM_END /*************************************************************************/ GAME( 1997, bujutsu, 0, cobra, cobra, cobra_state, bujutsu, ROT0, "Konami", "Fighting Bujutsu", GAME_NOT_WORKING | GAME_NO_SOUND ) GAME( 1997, racjamdx, 0, cobra, cobra, cobra_state, racjamdx, ROT0, "Konami", "Racing Jam DX", GAME_NOT_WORKING | GAME_NO_SOUND )