diff options
Diffstat (limited to 'src/mame/drivers/cobra.cpp')
-rw-r--r-- | src/mame/drivers/cobra.cpp | 3531 |
1 files changed, 3531 insertions, 0 deletions
diff --git a/src/mame/drivers/cobra.cpp b/src/mame/drivers/cobra.cpp new file mode 100644 index 00000000000..b53e655ec6c --- /dev/null +++ b/src/mame/drivers/cobra.cpp @@ -0,0 +1,3531 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* 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/lpci.h" +#include "machine/ataintf.h" +#include "machine/idehd.h" +#include "machine/jvshost.h" +#include "machine/jvsdev.h" +#include "machine/timekpr.h" +#include "video/k001604.h" +#include "video/poly.h" +#include "video/rgbutil.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<float, cobra_polydata, 8, 10000> +{ +public: + cobra_renderer(screen_device &screen) + : poly_manager<float, cobra_polydata, 8, 10000>(screen) + { + 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(); + void gfx_exit(); + void gfx_reset(); + void gfx_fifo_exec(); + UINT32 gfx_read_gram(UINT32 address); + void gfx_write_gram(UINT32 address, UINT32 mask, UINT32 data); + UINT64 gfx_read_reg(); + void gfx_write_reg(UINT64 data); + + void display(bitmap_rgb32 *bitmap, const rectangle &cliprect); + inline rgb_t texture_fetch(UINT32 *texture, int u, int v, int width, int format); +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<void (EventType)> 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::cobra_jvs(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : jvs_device(mconfig, COBRA_JVS, "JVS (COBRA)", tag, owner, clock, "cobra_jvs", __FILE__) +{ +} + +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++ = read_safe(ioport(":TEST"), 0); + + for (int i=0; i < count_players; i++) + { + UINT32 pval = read_safe(ioport(player_ports[i]), 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::cobra_jvs_host(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : jvs_host(mconfig, COBRA_JVS_HOST, "JVS-HOST (COBRA)", tag, owner, clock, "cobra_jvs_host", __FILE__) +{ + 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"), + m_k001604(*this, "k001604"), + m_ata(*this, "ata"), + m_screen(*this, "screen"), + m_palette(*this, "palette"), + m_generic_paletteram_32(*this, "paletteram"), + m_main_ram(*this, "main_ram"), + m_sub_ram(*this, "sub_ram"), + m_gfx_ram0(*this, "gfx_main_ram_0"), + m_gfx_ram1(*this, "gfx_main_ram_1") + { + } + + required_device<ppc_device> m_maincpu; + required_device<ppc4xx_device> m_subcpu; + required_device<ppc_device> m_gfxcpu; + required_shared_ptr<UINT64> m_gfx_pagetable; + required_device<k001604_device> m_k001604; + required_device<ata_interface_device> m_ata; + required_device<screen_device> m_screen; + required_device<palette_device> m_palette; + required_shared_ptr<UINT32> m_generic_paletteram_32; + required_shared_ptr<UINT64> m_main_ram; + required_shared_ptr<UINT32> m_sub_ram; + required_shared_ptr<UINT64> m_gfx_ram0; + required_shared_ptr<UINT64> m_gfx_ram1; + + 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_WRITE32_MEMBER(main_cpu_dc_store); + + 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_READ16_MEMBER(sub_ata0_r); + DECLARE_WRITE16_MEMBER(sub_ata0_w); + DECLARE_READ16_MEMBER(sub_ata1_r); + DECLARE_WRITE16_MEMBER(sub_ata1_w); + DECLARE_READ32_MEMBER(sub_psac2_r); + DECLARE_WRITE32_MEMBER(sub_psac2_w); + DECLARE_WRITE32_MEMBER(sub_psac_palette_w); + DECLARE_WRITE32_MEMBER(sub_sound_dma_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_WRITE32_MEMBER(gfx_cpu_dc_store); + + DECLARE_WRITE8_MEMBER(sub_jvs_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(); + int decode_debug_state_value(int v); +}; + +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; + } +} + +rgb_t cobra_renderer::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 = rgb_t(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 = rgb_t(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 = rgbaint_t::bilinear_filter(texel00, texel01, texel10, texel11, (int)(lerp_u * 255), (int)(lerp_v * 255)); + +#endif + + int a = texel.a(); + + if (a != 0 || !alpha_test) + { + UINT32 gour = (int)(gr); + UINT32 goug = (int)(gg); + UINT32 goub = (int)(gb); + + int r = (texel.r() * gour) >> 8; + int g = (texel.g() * goug) >> 8; + int b = (texel.b() * 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(); +} + +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(*m_screen)); + m_renderer->gfx_init(); +} + +UINT32 cobra_state::screen_update_cobra(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_has_psac) + { + m_k001604->draw_back_layer(bitmap, cliprect); + m_k001604->draw_front_layer(screen, bitmap, cliprect); + } + + m_renderer->display(&bitmap, cliprect); + return 0; +} + + + + +/*****************************************************************************/ + +int cobra_state::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<device_t *>(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<device_t *>(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<device_t *>(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<device_t *>(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: + { + m_subcpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); + + // give sub cpu a bit more time to stabilize on the current fifo status + m_maincpu->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; + + m_maincpu->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<pci_bus_legacy_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<pci_bus_legacy_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; + + m_subcpu->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 + m_maincpu->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 + m_maincpu->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 + m_maincpu->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 + + if (m_main_debug_state == 0x6b) + { + // install HD patches for bujutsu + if (strcmp(space.machine().system().name, "bujutsu") == 0) + { + UINT32 *main_ram = (UINT32*)(UINT64*)m_main_ram; + UINT32 *sub_ram = (UINT32*)m_sub_ram; + UINT32 *gfx_ram = (UINT32*)(UINT64*)m_gfx_ram0; + + main_ram[(0x0005ac^4) / 4] = 0x60000000; // skip IRQ fail + main_ram[(0x001ec4^4) / 4] = 0x60000000; // waiting for IRQ? + main_ram[(0x001f00^4) / 4] = 0x60000000; // waiting for IRQ? + + sub_ram[0x568 / 4] = 0x60000000; // skip IRQ fail + + gfx_ram[(0x38632c^4) / 4] = 0x38600000; // skip check_one_scene() + } + } + + 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); +} + +WRITE32_MEMBER(cobra_state::main_cpu_dc_store) +{ + if ((offset & 0xf0000000) == 0xc0000000) + { + // force sync when writing to GFX board main ram + 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_SHARE("main_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 = 0; + 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) + { + m_maincpu->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) +{ +} + +READ16_MEMBER(cobra_state::sub_ata0_r) +{ + mem_mask = ( mem_mask << 8 ) | ( mem_mask >> 8 ); + + UINT32 data = m_ata->read_cs0(space, offset, mem_mask); + data = ( data << 8 ) | ( data >> 8 ); + + return data; +} + +WRITE16_MEMBER(cobra_state::sub_ata0_w) +{ + mem_mask = ( mem_mask << 8 ) | ( mem_mask >> 8 ); + data = ( data << 8 ) | ( data >> 8 ); + + m_ata->write_cs0(space, offset, data, mem_mask); +} + +READ16_MEMBER(cobra_state::sub_ata1_r) +{ + mem_mask = ( mem_mask << 8 ) | ( mem_mask >> 8 ); + + UINT32 data = m_ata->read_cs1(space, offset, mem_mask); + + return ( data << 8 ) | ( data >> 8 ); +} + +WRITE16_MEMBER(cobra_state::sub_ata1_w) +{ + mem_mask = ( mem_mask << 8 ) | ( mem_mask >> 8 ); + data = ( data << 8 ) | ( data >> 8 ); + + m_ata->write_cs1(space, offset, data, mem_mask); +} + +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]; + m_palette->set_pen_color(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) +{ +} + +WRITE32_MEMBER(cobra_state::sub_sound_dma_w) +{ + //printf("DMA write to unknown: size %d, data %08X\n", address, 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); + */ + + INT16 ldata = (INT16)(data >> 16); + INT16 rdata = (INT16)(data); + + m_sound_dma_buffer_l[m_sound_dma_ptr] = ldata; + m_sound_dma_buffer_r[m_sound_dma_ptr] = rdata; + m_sound_dma_ptr++; + + if (m_sound_dma_ptr >= DMA_SOUND_BUFFER_SIZE) + { + m_sound_dma_ptr = 0; + + dmadac_transfer(&m_dmadac[0], 1, 0, 1, DMA_SOUND_BUFFER_SIZE, m_sound_dma_buffer_l); + dmadac_transfer(&m_dmadac[1], 1, 0, 1, DMA_SOUND_BUFFER_SIZE, m_sound_dma_buffer_r); + } +} + +WRITE8_MEMBER(cobra_state::sub_jvs_w) +{ + cobra_jvs_host *jvs = machine().device<cobra_jvs_host>("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++) + { + m_subcpu->ppc4xx_spu_receive_byte(rec_data[i]); + } + } +} + +static ADDRESS_MAP_START( cobra_sub_map, AS_PROGRAM, 32, cobra_state ) + AM_RANGE(0x00000000, 0x003fffff) AM_MIRROR(0x80000000) AM_RAM AM_SHARE("sub_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("rfsnd", rf5c400_device, rf5c400_r, rf5c400_w, 0xffffffff) + AM_RANGE(0x78080000, 0x7808000f) AM_MIRROR(0x80000000) AM_READWRITE16(sub_ata0_r, sub_ata0_w, 0xffffffff) + AM_RANGE(0x780c0010, 0x780c001f) AM_MIRROR(0x80000000) AM_READWRITE16(sub_ata1_r, sub_ata1_w, 0xffffffff) + AM_RANGE(0x78200000, 0x782000ff) AM_MIRROR(0x80000000) AM_DEVREADWRITE("k001604", k001604_device, reg_r, 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("k001604", k001604_device, tile_r, tile_w) // PSAC tile RAM + AM_RANGE(0x78240000, 0x7827ffff) AM_MIRROR(0x80000000) AM_DEVREADWRITE("k001604", k001604_device, char_r, 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("m48t58", timekeeper_device, read, write, 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() +{ + const rectangle& visarea = 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() +{ + /* + 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() +{ + cobra_state *cobra = machine().driver_data<cobra_state>(); + + 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() +{ + return m_gfx_register[m_gfx_register_select]; +} + +void cobra_renderer::gfx_write_reg(UINT64 data) +{ + switch (m_gfx_register_select) + { + case 0x0000: + { + const rectangle& visarea = 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() +{ + cobra_state *cobra = machine().driver_data<cobra_state>(); + + if (cobra->m_gfx_fifo_loopback != 0) + return; + + const rectangle& visarea = 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(((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 + { + cobra->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) + { + cobra->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) + { + cobra->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++; + }; + cobra->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(); + + if (ACCESSING_BITS_32_63) + { + UINT64 data = 0; + m_gfxfifo_out->pop(&space.device(), &data); + + data &= 0xffffffff; + + r |= (UINT64)(data) << 32; + } + if (ACCESSING_BITS_0_31) + { + UINT64 data = 0; + 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(); + + if (data == U64(0x00a0000110500018)) + { + m_gfxfifo_out->flush(); + + // reads back the register selected by gfx register select + + UINT64 regdata = m_renderer->gfx_read_reg(); + + 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); + } +} + +WRITE32_MEMBER(cobra_state::gfx_cpu_dc_store) +{ + UINT32 addr = offset >> 24; + if (addr == 0x10 || addr == 0x18 || addr == 0x1e) + { + UINT64 i = (UINT64)(m_gfx_fifo_cache_addr) << 32; + cobra_fifo *fifo_in = m_gfxfifo_in; + + UINT32 a = (offset / 8) & 0xff; + + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+0] >> 32) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+0] >> 0) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+1] >> 32) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+1] >> 0) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+2] >> 32) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+2] >> 0) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+3] >> 32) | i); + fifo_in->push(&space.device(), (UINT32)(m_gfx_fifo_mem[a+3] >> 0) | i); + + m_renderer->gfx_fifo_exec(); + } + else + { + logerror("gfx: data cache store at %08X\n", offset); + } +} + +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_START1 ) + 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_START2 ) + 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 + +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_hdd_device *hdd = m_ata->subdevice<ata_slot_device>("0")->subdevice<ide_hdd_device>("hdd"); + UINT16 *identify_device = hdd->identify_device_buffer(); + + // Cobra expects these settings or the BIOS fails + identify_device[51] = 0x0200; /* 51: PIO data transfer cycle timing mode */ + identify_device[67] = 0x01e0; /* 67: minimum PIO transfer cycle time without flow control */ + + m_renderer->gfx_reset(); + + m_sound_dma_ptr = 0; + + m_dmadac[0] = machine().device<dmadac_sound_device>("dac1"); + m_dmadac[1] = machine().device<dmadac_sound_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_PPC_BUS_FREQUENCY(XTAL_66_6667MHz) /* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */ + 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_PPC_BUS_FREQUENCY(XTAL_66_6667MHz) /* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */ + 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_ATA_INTERFACE_ADD("ata", ata_devices, "hdd", NULL, true) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(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_SCREEN_UPDATE_DRIVER(cobra_state, screen_update_cobra) + MCFG_PALETTE_ADD("palette", 65536) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_RF5C400_ADD("rfsnd", 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_GFXDECODE_ADD("gfxdecode", "palette", empty) + MCFG_DEVICE_ADD("k001604", K001604, 0) // on the LAN board in Racing Jam DX + MCFG_K001604_GFX_INDEX1(0) + MCFG_K001604_GFX_INDEX2(1) + MCFG_K001604_LAYER_SIZE(0) + MCFG_K001604_ROZ_SIZE(1) + MCFG_K001604_TXT_OFFSET(0) // correct? + MCFG_K001604_ROZ_OFFSET(0) // correct? + MCFG_K001604_GFXDECODE("gfxdecode") + MCFG_K001604_PALETTE("palette") + + 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)) + ); + + m_maincpu->ppc_set_dcstore_callback(write32_delegate(FUNC(cobra_state::main_cpu_dc_store),this)); + + m_gfxcpu->ppc_set_dcstore_callback(write32_delegate(FUNC(cobra_state::gfx_cpu_dc_store), this)); + + m_subcpu->ppc4xx_set_dma_write_handler(0, write32_delegate(FUNC(cobra_state::sub_sound_dma_w), this), 44100); + m_subcpu->ppc4xx_spu_set_tx_handler(write8_delegate(FUNC(cobra_state::sub_jvs_w), this)); + + + 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*)memregion("user2")->base(); + + rom[0x62094 / 4] = 0x60000000; // skip hardcheck()... + } + + + // rom hacks for gfx board... + { + int i; + UINT32 sum = 0; + + UINT32 *rom = (UINT32*)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*)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*)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*)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*)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_REGION16_LE(0x1000000, "rfsnd", ROMREGION_ERASE00) + + DISK_REGION( "ata:0:hdd:image" ) + 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_REGION16_LE(0x1000000, "rfsnd", ROMREGION_ERASE00) + + DISK_REGION( "ata:0:hdd:image" ) + DISK_IMAGE_READONLY( "676a04", 0, SHA1(8e89d3e5099e871b99fccba13adaa3cf8a6b71f0) ) +ROM_END + +/*************************************************************************/ + +GAME( 1997, bujutsu, 0, cobra, cobra, cobra_state, bujutsu, ROT0, "Konami", "Fighting Bujutsu", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 1997, racjamdx, 0, cobra, cobra, cobra_state, racjamdx, ROT0, "Konami", "Racing Jam DX", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) |