diff --git a/cores/argus/README.md b/cores/argus/README.md new file mode 100644 index 000000000..d4d354a48 --- /dev/null +++ b/cores/argus/README.md @@ -0,0 +1,160 @@ +# Argus Core + +FPGA implementation of **Argus** (NMK/Jaleco, 1986), targeting the MiSTer +platform through JTFRAME. Copyright (C) 2026 Fulvio Venturelli, distributed +under the GNU General Public License version 3 or later (see +[LICENSE](../../LICENSE)). + +Built on top of Jose Tejada's `jtframe` framework (also GPL-3). This core is +being brought up from emulator references because no original schematics have +been found. The implementation is guided by MAME's Jaleco `argus.cpp` / +`argus_v.cpp` driver, the local MAME-compatible `argus.zip` ROM set, and live +Verilator comparison against MAME reference frames. + +# Authors + +Core implementation: + +- Fulvio Venturelli + +JTFRAME/JTCORES reusable infrastructure: + +- Jose Tejada Gomez and contributors + +Reference emulation: + +- MAME Argus driver by Yochizo +- FinalBurn Neo Argus driver contributors + +## Status + +Supported MAME set for the jtframe config: + +- `argus`: **Argus**. + +Related MAME sets `valtric`, `butasan`, and `butasanj` share parts of the same +driver, but they are out of scope for this first hardware pass. + +Verilator board simulation currently boots the real `argus` ROM image, transfers +ROM by frame 12, accepts the repeatable coin/start input script, and reaches the +title/credit path with recognizable background, logo, text, palette, and sprite +output. + +Current implemented video work includes: + +- MAME-described BG0 VROM metadata lookup cached with `jtframe_dual_ram` +- BG0 palette intensity add/subtract path +- Jaleco blend-device sprite alpha nibble handling +- Argus packed-MSB 4bpp tile conversion for BG, text, and sprites +- 256x224 active timing aligned to the MAME visible area, then rotated by + JTFRAME core-mod for the vertical cabinet view +- live frame viewer inherited from the Operation Wolf/Rainbow Islands workflow + +Known issues: + +- Ship departing smoke animation is corrupted. +- Background becomes black after the supernova. +- Scroll stuttering remains; movement is not yet as smooth as MAME/arcade. +- Cursor is offset upward on the score name entry screen. + +MAME itself marks the Argus driver as imperfect graphics, so each visual fix +should be checked against a saved MAME frame rather than assumed correct. + +## Repo Layout + +| Path | What it is | +|---|---| +| `hdl/` | Verilog - Argus-specific CPU, video, palette, sprite, and sound glue | +| `mist/` | Generated MiSTer SDRAM wrapper and memory port includes | +| `cfg/` | `files.yaml`, `mem.yaml`, `macros.def`, MRA, DIP, and pause text inputs | +| `doc/` | Local MAME/FBNeo reference snapshots | +| `ver/argus/` | Verilator sim wrapper and repeatable input script | +| `tools/` | `framewatch.py`, the live browser frame viewer | + +## Reused Blocks + +The Argus-specific RTL is intentionally limited to address decoding, BG0 VROM +lookup, palette/intensity rules, sprite table scanning, and board glue. Reused +JTFRAME/JTCORES blocks include: + +- Z80 CPUs: `jtframe_z80_romwait` +- YM2203: `jt03` +- video timing: `jtframe_vtimer` +- tile layers: `jtframe_scroll` +- sprite drawing: `jtframe_objdraw` +- local RAMs: `jtframe_dual_ram` and `jtframe_dual_ram16` + +## Building & Simulating + +Generate the MRA and ROM payloads from a MAME-compatible `argus.zip`: + +```bash +cd /path/to/jtcores +JTROOT=$PWD \ +JTFRAME=$PWD/modules/jtframe \ +CORES=$PWD/cores \ +MODULES=$PWD/modules \ +JTBIN=$PWD/release \ +PATH=$PWD/modules/jtframe/bin:$PATH \ +modules/jtframe/bin/jtframe mra argus --setname argus --path /path/to/roms +``` + +Expected local outputs: + +```text +release/mra/Argus.mra +rom/argus.rom +rom/argus.dip +rom/argus.mod +``` + +The local sim wrapper sets up the JTFRAME environment, refreshes +`rom/argus.rom`/`rom/argus.mod` when needed, and invokes `jtsim`: + +```bash +cd cores/argus/ver/argus +ARGUS_ROM=/path/to/roms ./sim.sh -frame 300 -fast +``` + +For a repeatable credit/start run: + +```bash +cd cores/argus/ver/argus +ARGUS_ROM=/path/to/roms ./sim.sh -frame 300 -fast -inputs start_game.cab +``` + +For a visual frame capture run: + +```bash +cd cores/argus/ver/argus +JTFRAME_SIM_VIDEO_EVERY=90 ARGUS_ROM=/path/to/roms ./sim.sh -frame 91 -fast +``` + +The live frame viewer can stay open across sim runs: + +```bash +python3 cores/argus/tools/framewatch.py --port 8766 +``` + +Open `http://127.0.0.1:8766/` and leave it running while the sim writes frames +under `ver/argus/frames/`. + +## Reference Sources + +- MAME Jaleco driver: `doc/argus.cpp` +- MAME Jaleco video driver: `doc/argus_v.cpp` +- MAME state header: `doc/argus.h` +- FBNeo reference driver: `doc/fbneo_d_argus.cpp` + +Upstream references: + +- +- +- + +## License + +GPL-3-or-later. Every HDL file carries its own attribution header where +applicable. The implementation uses JTFRAME/JTCORES reusable modules by Jose +Tejada and contributors, plus behavioural details derived from MAME and FBNeo +reference drivers. See [LICENSE](../../LICENSE) and [AUTHORS.md](AUTHORS.md). diff --git a/cores/argus/cfg/files.yaml b/cores/argus/cfg/files.yaml new file mode 100644 index 000000000..696cafaa6 --- /dev/null +++ b/cores/argus/cfg/files.yaml @@ -0,0 +1,29 @@ +argus: + - get: + - jtargus_*.v +jtframe: + - get: + - jtframe_edge.v + - jtframe_sh.v + - from: cpu + get: + - jtframe_z80.yaml + - jtframe_z80wait.v + - from: ram + get: + - jtframe_dual_ram.v + - jtframe_dual_ram16.v + - jtframe_obj_buffer.v + - from: video + get: + - jtframe_vtimer.v + - jtframe_scroll.yaml + - jtframe_draw.v + - jtframe_objdraw.v + - jtframe_objdraw_gate.v + - from: video/layouts + get: + - jtframe_8x8x4_packed_msb.v +jt12: + - get: + - jt03.yaml diff --git a/cores/argus/cfg/macros.def b/cores/argus/cfg/macros.def new file mode 100644 index 000000000..42a7fb3f2 --- /dev/null +++ b/cores/argus/cfg/macros.def @@ -0,0 +1,19 @@ +CORENAME=JTARGUS +JTFRAME_BUTTONS=2 +JTFRAME_CREDITS_PAGES=1 + +JTFRAME_VERTICAL +JTFRAME_WIDTH=256 +JTFRAME_HEIGHT=224 +JTFRAME_PXLCLK=6 +JTFRAME_ARX=5 +JTFRAME_ARY=4 + +# ROM layout +JTFRAME_BA1_START=0x30000 +JTFRAME_BA2_START=0x40000 +BG1_START=0x60000 +JTFRAME_BA3_START=0x80000 +TXT_START=0x68000 +VROM1_START=0x6C000 +VROM2_START=0x74000 diff --git a/cores/argus/cfg/mame2mra.toml b/cores/argus/cfg/mame2mra.toml new file mode 100644 index 000000000..cbd1f7d9a --- /dev/null +++ b/cores/argus/cfg/mame2mra.toml @@ -0,0 +1,32 @@ +[global] +overrule=[ {rotate=270} ] + +[parse] +sourcefile=[ "argus.cpp" ] +skip={machines=["butasan","valtric"]} + +[dipsw] +delete=[ + { names=["Unused"] }, +] + +[buttons] +names=[ + { names="Shot 1,Shot 2" } +] + +[ROM] +regions = [ + { name="maincpu" }, + { name="audiocpu", start="JTFRAME_BA1_START" }, + { name="gfx2", start="JTFRAME_BA2_START", rename="scr0" }, + { name="gfx3", start="BG1_START", rename="scr1" }, + { name="gfx4", start="TXT_START", rename="text" }, + { name="gfx1", start="JTFRAME_BA3_START", rename="sprites" }, + { name="vrom1", start="VROM1_START" }, + { name="vrom2", start="VROM2_START" }, +] + +order = [ + "maincpu", "audiocpu", "scr0", "scr1", "text", "vrom1", "vrom2", "sprites" +] diff --git a/cores/argus/cfg/mem.yaml b/cores/argus/cfg/mem.yaml new file mode 100644 index 000000000..3bc7365db --- /dev/null +++ b/cores/argus/cfg/mem.yaml @@ -0,0 +1,81 @@ +params: + - { name: BG1_OFFSET, value: "(`BG1_START-`JTFRAME_BA2_START)>>1" } + - { name: TXT_OFFSET, value: "(`TXT_START-`JTFRAME_BA2_START)>>1" } + - { name: VROM1_OFFSET, value: "(`VROM1_START-`JTFRAME_BA2_START)>>1" } + - { name: VROM2_OFFSET, value: "(`VROM2_START-`JTFRAME_BA2_START)>>1" } + +clocks: + clk48: + - freq: 5M + gate: [ "main", "snd" ] + outputs: + - cen5 + - cen5b + - freq: 1500000 + outputs: + - cen1p5 + - cen1p5b + +audio: + rsum: 10k + gain: 0.7 + channels: + - { name: fm, module: jt03_fm, rsum: 20k, rc: [{ r: 1rout, c: 1.2n }] } + - { name: psg, module: jt03_psg, rsum: 60k } + +sdram: + banks: + - buses: + - name: main + addr_width: 18 + data_width: 8 + - buses: + - name: snd + addr_width: 16 + data_width: 8 + - buses: + - name: bg0 + addr_width: 17 + data_width: 32 + - name: bg1 + addr_width: 15 + data_width: 32 + offset: BG1_OFFSET + - name: txt + addr_width: 15 + data_width: 32 + offset: TXT_OFFSET + - name: vrom1 + addr_width: 15 + data_width: 16 + offset: VROM1_OFFSET + - name: vrom2 + addr_width: 15 + data_width: 16 + offset: VROM2_OFFSET + - buses: + - name: obj + addr_width: 17 + data_width: 32 +bram: + - name: ram + addr_width: 13 + data_width: 8 + addr: "main_addr[12:0]" + din: cpu_dout + rw: true + dual_port: { name: ram_obj, dout: ram_obj_dout, din: "8'b0", } + - name: tx + addr_width: 11 + data_width: 16 + addr: "main_addr[10:1]" + din: "{2{cpu_dout}}" + rw: true + dual_port: { name: tx_vid, dout: tx_vid_dout, din: "16'b0"} + - name: bg1 + addr_width: 11 + data_width: 16 + addr: "main_addr[10:1]" + din: "{2{cpu_dout}}" + rw: true + dual_port: { name: bg1_vid, dout: bg1_vid_dout, din: "16'b0"} diff --git a/cores/argus/cfg/msg b/cores/argus/cfg/msg new file mode 100644 index 000000000..33acda5b1 --- /dev/null +++ b/cores/argus/cfg/msg @@ -0,0 +1,9 @@ + \BJTARGUS\W + FPGA core by Fulvio + + Version \C - \D + + Based on MAME + and FBNeo + + Work in progress diff --git a/cores/argus/cfg/reg.yaml b/cores/argus/cfg/reg.yaml new file mode 100644 index 000000000..6b3b7605a --- /dev/null +++ b/cores/argus/cfg/reg.yaml @@ -0,0 +1 @@ +argus: diff --git a/cores/argus/doc/argus.cpp b/cores/argus/doc/argus.cpp new file mode 100644 index 000000000..d2b71ff39 --- /dev/null +++ b/cores/argus/doc/argus.cpp @@ -0,0 +1,749 @@ +// license:BSD-3-Clause +// copyright-holders:Yochizo +/*************************************************************************** + +Argus (Early NMK driver 1986-1987) +------------------------------------- +driver by Yochizo + + +Special thanks to : +===================== + - Gerardo Oporto Jorrin for dipswitch informations. + - Suzuki2go for screenshots of Argus and Valtric. + - Jarek Parchanski for Psychic5 driver. + + +Supported games : +================== + Argus (C) 1986 NMK / Jaleco + Valtric (C) 1986 NMK / Jaleco + Butasan (C) 1987 NMK / Jaleco + + +System specs : +=============== + Argus + --------------------------------------------------------------- + CPU : Z80 (4MHz) + Z80 (4MHz, Sound) + Sound : YM2203 x 1 + Layers : BG0, BG1, Sprite, Text [BG0 is controlled by VROMs] + Colors : 832 colors + Sprite : 128 colors + BG0 : 256 colors + BG1 : 256 colors + Text : 256 colors + Others : Brightness controller (Emulated) + Half transparent color (Not emulated) + Reference : https://youtu.be/aSgRfAgd7yU + + Valtric + --------------------------------------------------------------- + CPU : Z80 (5MHz) + Z80 (5MHz, Sound) + Sound : YM2203 x 2 + Layers : BG1, Sprite, Text + Colors : 768 colors + Sprite : 256 colors + BG1 : 256 colors + Text : 256 colors + Others : Brightness controller (Emulated) + Half transparent color (Not emulated) + Mosaic effect (Emulated) + + Butasan + --------------------------------------------------------------- + CPU : Z80 (5MHz) + Z80 (5MHz, Sound) + Sound : YM2203 x 2 + Layers : BG0, BG1, Sprite, Text [BG0 and BG1 is not shown simultaneously] + Colors : 672 colors + Sprite : 16x4 + 8x8 = 128 colors + BG0 : 256 colors + BG1 : 32 colors + Text : 256 colors + Others : 2 VRAM pages (Emulated) + Various sprite sizes (Emulated) + + +PCB Edge Connector Pinout : +============================ + Argus + ---------------------------------- + PARTS SOLDER + -------------------------------- + GND 1 A GND + GND 2 B GND + 5V 3 C 5V + 5V 4 D 5V + 12V 5 E 12V + Video Red 6 F Video Blue + Video Green 7 H Video Sync + Speaker + 8 J Speaker - + Coin 2 9 K Coin 1 (*) see below + GND 10 L GND + 1P Start 11 M 2P Start + 1P Up 12 N 2P Up + 1P Down 13 P 2P Down + 1P Right 14 R 2P Right + 1P Left 15 S 2P Left + 1P Shot 1 16 T 2P Shot 1 + 1P Shot 2 17 U 2P Shot 2 + GND 18 V GND + (*) You may doubt that 9 and K are swapped. But they are not. + + Valtric and Butasan + ---------------------------------- + JAMMA + + +Note : +------ + - To enter test mode, press Coin 2 key at start in Argus, + press Coin 1 key at start in Valtric, + and press Service key at start in Butasan. + - DIP locations verified for: + butasan + argus + valtric + +- Information about the internal ROM tests (see also MT03219): + * argus: Checksum routine at $7fc9 (for banks at $7fc0). Checksum is a + simple sum of the contents. Our dump gives a result of 0x95 while the + game expects 0x9b, therefore it displays a checksum error. Checksums for + the banked ROMs match. + * valtric: Checksum routine at $987c (for banks at $f000). Checksum is a + XOR over the contents. The expected checksums are stored in ROM vt_06.bin + starting at $d000 (main ROM first, then banks). For our dump, the + expected checksums are all 0x00, but the calculated checksums differ, + therefore displays a checksum error for all ROMs. This has been validated + on real hardware to also fail there. + * butasan: Checksum routine is at $e0a8 (for banks at $ec74). Checksum is a + simple sum over the contents. The test seems to be broken (or hacked) as + it will only fail when the checksum is exactly 0x00. + + +Known issues : +=============== + - Half transparent color (50% alpha blending) is not emulated. + - Sprite priority switch of Butasan is shown in test mode. What will be + happened when set it ? JFF is not implemented this mystery switch too. + - Data proms of Butasan does exist. But I don't know what is used for. + - Though clock speed of Argus is actually 4 MHz, major sprite problems + are broken out in the middle of slowdown. So, it is set 5 MHz now. + - Sprite locations of Argus delay around 1 or 2 frames when horizontal + scroll occurs. + +****************************************************************************/ + + +#include "emu.h" +#include "argus.h" + +#include "cpu/z80/z80.h" +#include "machine/gen_latch.h" +#include "sound/ymopn.h" +#include "speaker.h" + + +void argus_common_state::machine_start() +{ + membank("mainbank")->configure_entries(0, 8, memregion("maincpu")->base() + 0x10000, 0x4000); +} + +/*************************************************************************** + + Interrupt(s) + +***************************************************************************/ + +TIMER_DEVICE_CALLBACK_MEMBER(argus_common_state::scanline) +{ + int scanline = param; + + if(scanline == 240) // vblank-out irq + m_maincpu->set_input_line_and_vector(0, HOLD_LINE,0xd7); /* Z80 - RST 10h */ + + if(scanline == 16) // vblank-in irq + m_maincpu->set_input_line_and_vector(0, HOLD_LINE,0xcf); /* Z80 - RST 08h */ +} + +TIMER_DEVICE_CALLBACK_MEMBER(butasan_state::scanline) +{ + int scanline = param; + + if(scanline == 248) // vblank-out irq + m_maincpu->set_input_line_and_vector(0, HOLD_LINE,0xd7); /* Z80 - RST 10h */ + + if(scanline == 8) // vblank-in irq + m_maincpu->set_input_line_and_vector(0, HOLD_LINE,0xcf); /* Z80 - RST 08h */ +} + + +/*************************************************************************** + + Memory Handler(s) + +***************************************************************************/ + +void argus_common_state::bankselect_w(u8 data) +{ + membank("mainbank")->set_entry(data & 7); /* Select 8 banks of 16k */ +} + + +/*************************************************************************** + + Memory Map(s) + +***************************************************************************/ + +void argus_state::argus_map(address_map &map) +{ + map(0x0000, 0x7fff).rom(); + map(0x8000, 0xbfff).bankr("mainbank"); + map(0xc000, 0xc000).portr("SYSTEM"); + map(0xc001, 0xc001).portr("P1"); + map(0xc002, 0xc002).portr("P2"); + map(0xc003, 0xc003).portr("DSW1"); + map(0xc004, 0xc004).portr("DSW2"); + map(0xc200, 0xc200).w("soundlatch", FUNC(generic_latch_8_device::write)); + map(0xc201, 0xc201).w(FUNC(argus_state::flipscreen_w)); + map(0xc202, 0xc202).w(FUNC(argus_state::bankselect_w)); + map(0xc300, 0xc301).ram().share("bg0_scrollx"); + map(0xc302, 0xc303).ram().share("bg0_scrolly"); + map(0xc308, 0xc309).ram().share("bg1_scrollx"); + map(0xc30a, 0xc30b).ram().share("bg1_scrolly"); + map(0xc30c, 0xc30c).w(FUNC(argus_state::bg_status_w)); + map(0xc400, 0xcfff).ram().w(FUNC(argus_state::paletteram_w)).share("paletteram"); + map(0xd000, 0xd7ff).ram().w(FUNC(argus_state::txram_w)).share("txram"); + map(0xd800, 0xdfff).ram().w(FUNC(argus_state::bg1ram_w)).share("bg1ram"); + map(0xe000, 0xf1ff).ram(); + map(0xf200, 0xf7ff).ram().share("spriteram"); + map(0xf800, 0xffff).ram(); +} + +void valtric_state::valtric_map(address_map &map) +{ + map(0x0000, 0x7fff).rom(); + map(0x8000, 0xbfff).bankr("mainbank"); + map(0xc000, 0xc000).portr("SYSTEM"); + map(0xc001, 0xc001).portr("P1"); + map(0xc002, 0xc002).portr("P2"); + map(0xc003, 0xc003).portr("DSW1"); + map(0xc004, 0xc004).portr("DSW2"); + map(0xc200, 0xc200).w("soundlatch", FUNC(generic_latch_8_device::write)); + map(0xc201, 0xc201).w(FUNC(valtric_state::flipscreen_w)); + map(0xc202, 0xc202).w(FUNC(valtric_state::bankselect_w)); + map(0xc300, 0xc300).w(FUNC(valtric_state::unknown_w)); + map(0xc308, 0xc309).ram().share("bg1_scrollx"); + map(0xc30a, 0xc30b).ram().share("bg1_scrolly"); + map(0xc30c, 0xc30c).w(FUNC(valtric_state::bg_status_w)); + map(0xc30d, 0xc30d).w(FUNC(valtric_state::mosaic_w)); + map(0xc400, 0xcfff).ram().w(FUNC(valtric_state::paletteram_w)).share("paletteram"); + map(0xd000, 0xd7ff).ram().w(FUNC(valtric_state::txram_w)).share("txram"); + map(0xd800, 0xdfff).ram().w(FUNC(valtric_state::bg1ram_w)).share("bg1ram"); + map(0xe000, 0xf1ff).ram(); + map(0xf200, 0xf7ff).ram().share("spriteram"); + map(0xf800, 0xffff).ram(); +} + +void butasan_state::butasan_map(address_map &map) +{ + map(0x0000, 0x7fff).rom(); + map(0x8000, 0xbfff).bankr("mainbank"); + map(0xc000, 0xc000).portr("SYSTEM"); + map(0xc001, 0xc001).portr("P1"); + map(0xc002, 0xc002).portr("P2"); + map(0xc003, 0xc003).portr("DSW1"); + map(0xc004, 0xc004).portr("DSW2"); + map(0xc100, 0xc100).w(FUNC(butasan_state::unknown_w)); + map(0xc200, 0xc200).w("soundlatch", FUNC(generic_latch_8_device::write)); + map(0xc201, 0xc201).w(FUNC(butasan_state::flipscreen_w)); + map(0xc202, 0xc202).w(FUNC(butasan_state::bankselect_w)); + map(0xc203, 0xc203).w(FUNC(butasan_state::pageselect_w)); + map(0xc300, 0xc301).ram().share("bg0_scrollx"); + map(0xc302, 0xc303).ram().share("bg0_scrolly"); + map(0xc304, 0xc304).w(FUNC(butasan_state::bg0_status_w)); + map(0xc308, 0xc309).ram().share("bg1_scrollx"); + map(0xc30a, 0xc30b).ram().share("bg1_scrolly"); + map(0xc30c, 0xc30c).w(FUNC(butasan_state::bg1_status_w)); + map(0xc400, 0xc7ff).ram().w(FUNC(butasan_state::bg1ram_w)).share("butasan_bg1ram"); + map(0xc800, 0xcfff).ram().w(FUNC(butasan_state::paletteram_w)).share("paletteram"); + map(0xd000, 0xdfff).rw(FUNC(butasan_state::pagedram_r), FUNC(butasan_state::pagedram_w)); + map(0xe000, 0xefff).ram(); + map(0xf000, 0xf67f).ram().share("spriteram"); + map(0xf680, 0xffff).ram(); +} + +void argus_common_state::sound_map_a(address_map &map) +{ + map(0x0000, 0x7fff).rom(); + map(0x8000, 0x87ff).ram(); + map(0xc000, 0xc000).r("soundlatch", FUNC(generic_latch_8_device::read)); +} + +void argus_common_state::sound_map_b(address_map &map) +{ + map(0x0000, 0xbfff).rom(); + map(0xc000, 0xc7ff).ram(); + map(0xe000, 0xe000).r("soundlatch", FUNC(generic_latch_8_device::read)); +} + +void argus_common_state::sound_portmap_1(address_map &map) +{ + map.global_mask(0xff); + map(0x00, 0x01).rw("ym1", FUNC(ym2203_device::read), FUNC(ym2203_device::write)); + map(0x80, 0x81).noprw(); // second ym2203 is not implemented on argus but still writes here +} + +void argus_common_state::sound_portmap_2(address_map &map) +{ + map.global_mask(0xff); + map(0x00, 0x01).rw("ym1", FUNC(ym2203_device::read), FUNC(ym2203_device::write)); + map(0x80, 0x81).rw("ym2", FUNC(ym2203_device::read), FUNC(ym2203_device::write)); +} + + +/*************************************************************************** + + Input Port(s) + +***************************************************************************/ + +static INPUT_PORTS_START( argus ) + PORT_START("SYSTEM") /* System control */ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START1 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN1 ) + + PORT_START("P1") /* Player 1 control */ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_START("P2") /* Player 2 control */ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + /* DIPSW default setting: all OFF */ + PORT_START("DSW1") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW1:8") + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x06, 0x06, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW1:7,6") + PORT_DIPSETTING( 0x04, DEF_STR( Easy ) ) + PORT_DIPSETTING( 0x06, DEF_STR( Normal ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Medium_Difficult ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Difficult ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW1:5") + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, DEF_STR( Cabinet ) ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x00, DEF_STR( Upright ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Cocktail ) ) + PORT_DIPNAME( 0x20, 0x00, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0xc0, 0xc0, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:2,1") + PORT_DIPSETTING( 0x80, "2" ) + PORT_DIPSETTING( 0xc0, "3" ) + PORT_DIPSETTING( 0x40, "4" ) + PORT_DIPSETTING( 0x00, "5" ) + + PORT_START("DSW2") + PORT_DIPUNUSED_DIPLOC( 0x01, 0x01, "SW2:8" ) /* Listed as "Unused" */ + PORT_DIPUNUSED_DIPLOC( 0x02, 0x02, "SW2:7" ) /* Listed as "Unused" */ + PORT_DIPNAME( 0x1c, 0x1c, DEF_STR( Coin_B ) ) PORT_DIPLOCATION("SW2:6,5,4") + PORT_DIPSETTING( 0x00, DEF_STR( 5C_1C ) ) + PORT_DIPSETTING( 0x04, DEF_STR( 4C_1C ) ) + PORT_DIPSETTING( 0x08, DEF_STR( 3C_1C ) ) + PORT_DIPSETTING( 0x0C, DEF_STR( 2C_1C ) ) + PORT_DIPSETTING( 0x1C, DEF_STR( 1C_1C ) ) + PORT_DIPSETTING( 0x18, DEF_STR( 1C_2C ) ) + PORT_DIPSETTING( 0x14, DEF_STR( 1C_3C ) ) + PORT_DIPSETTING( 0x10, DEF_STR( 1C_4C ) ) + PORT_DIPNAME( 0xe0, 0xe0, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW2:3,2,1") + PORT_DIPSETTING( 0x00, DEF_STR( 5C_1C ) ) + PORT_DIPSETTING( 0x20, DEF_STR( 4C_1C ) ) + PORT_DIPSETTING( 0x40, DEF_STR( 3C_1C ) ) + PORT_DIPSETTING( 0x60, DEF_STR( 2C_1C ) ) + PORT_DIPSETTING( 0xe0, DEF_STR( 1C_1C ) ) + PORT_DIPSETTING( 0xc0, DEF_STR( 1C_2C ) ) + PORT_DIPSETTING( 0xa0, DEF_STR( 1C_3C ) ) + PORT_DIPSETTING( 0x80, DEF_STR( 1C_4C ) ) +INPUT_PORTS_END + +static INPUT_PORTS_START( valtric ) + PORT_INCLUDE( argus ) + + PORT_MODIFY("SYSTEM") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE1 ) /* assigned JAMMA "Service", but not used */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN1 ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN2 ) + + /* DIPSW default setting: all OFF */ + PORT_MODIFY("DSW1") + PORT_DIPNAME( 0x06, 0x06, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW1:7,6") + PORT_DIPSETTING( 0x06, DEF_STR( Normal ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Medium_Difficult ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Difficult ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Very_Difficult ) ) + PORT_DIPNAME( 0xc0, 0xc0, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:2,1") + PORT_DIPSETTING( 0x00, "2" ) + PORT_DIPSETTING( 0xc0, "3" ) + PORT_DIPSETTING( 0x80, "4" ) + PORT_DIPSETTING( 0x40, "5" ) + + PORT_MODIFY("DSW2") + PORT_DIPNAME( 0x01, 0x01, "Invulnerability (Cheat)" ) PORT_DIPLOCATION("SW2:8") + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END + +static INPUT_PORTS_START( butasan ) + PORT_INCLUDE( valtric ) + + PORT_MODIFY("SYSTEM") + PORT_SERVICE( 0x20, IP_ACTIVE_LOW ) /* work as both "Service Credit SW" and "Test Mode SW" */ + + /* DIPSW default setting: all OFF */ + PORT_MODIFY("DSW1") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW1:8") + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, "Invulnerability (Cheat)" ) PORT_DIPLOCATION("SW1:7") + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:6,5") + PORT_DIPSETTING( 0x0c, "3" ) + PORT_DIPSETTING( 0x08, "4" ) + PORT_DIPSETTING( 0x04, "5" ) + PORT_DIPSETTING( 0x00, "6" ) + PORT_DIPNAME( 0x30, 0x30, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW1:4,3") + PORT_DIPSETTING( 0x30, DEF_STR( Normal ) ) + PORT_DIPSETTING( 0x20, DEF_STR( Medium_Difficult ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Difficult ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Very_Difficult ) ) + PORT_DIPUNUSED_DIPLOC( 0x40, 0x40, "SW1:2" ) /* Listed as "Unused" */ + PORT_DIPUNUSED_DIPLOC( 0x80, 0x80, "SW1:1" ) /* Listed as "Unused" */ + + PORT_MODIFY("DSW2") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW2:8") + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END + + +/*************************************************************************** + + Machine Driver(s) + +***************************************************************************/ + +static GFXDECODE_START( gfx_argus ) + GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x4_col_2x2_group_packed_msb, 0*16, 8 ) + GFXDECODE_ENTRY( "gfx2", 0, gfx_8x8x4_col_2x2_group_packed_msb, 8*16, 16 ) + GFXDECODE_ENTRY( "gfx3", 0, gfx_8x8x4_col_2x2_group_packed_msb, 24*16, 16 ) + GFXDECODE_ENTRY( "gfx4", 0, gfx_8x8x4_packed_msb, 40*16, 16 ) +GFXDECODE_END + +static GFXDECODE_START( gfx_valtric ) + GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x4_col_2x2_group_packed_msb, 0*16, 16 ) + GFXDECODE_ENTRY( "gfx2", 0, gfx_8x8x4_col_2x2_group_packed_msb, 16*16, 16 ) + GFXDECODE_ENTRY( "gfx3", 0, gfx_8x8x4_packed_msb, 32*16, 16 ) +GFXDECODE_END + +static GFXDECODE_START( gfx_butasan ) + GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x4_col_2x2_group_packed_msb, 0*16, 16 ) + GFXDECODE_ENTRY( "gfx2", 0, gfx_8x8x4_col_2x2_group_packed_msb, 16*16, 16 ) + GFXDECODE_ENTRY( "gfx3", 0, gfx_8x8x4_col_2x2_group_packed_msb, 12*16, 16 ) + GFXDECODE_ENTRY( "gfx4", 0, gfx_8x8x4_packed_msb, 32*16, 16 ) +GFXDECODE_END + + +void argus_state::argus(machine_config &config) +{ + /* basic machine hardware */ + Z80(config, m_maincpu, 5000000); /* 4 MHz */ + m_maincpu->set_addrmap(AS_PROGRAM, &argus_state::argus_map); + TIMER(config, "scantimer").configure_scanline(FUNC(argus_state::scanline), "screen", 0, 1); + + Z80(config, m_audiocpu, 5000000); + m_audiocpu->set_addrmap(AS_PROGRAM, &argus_state::sound_map_a); + m_audiocpu->set_addrmap(AS_IO, &argus_state::sound_portmap_1); + + config.set_maximum_quantum(attotime::from_hz(600)); + + /* video hardware */ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_refresh_hz(54); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); /* This value is referred to psychic5 driver */ + m_screen->set_size(32*16, 32*16); + m_screen->set_visarea(0*8, 32*8-1, 2*8, 30*8-1); + m_screen->set_screen_update(FUNC(argus_state::screen_update)); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx_argus); + PALETTE(config, m_palette).set_entries(896); + + JALECO_BLEND(config, m_blend, 0); + + /* sound hardware */ + SPEAKER(config, "mono").front_center(); + + GENERIC_LATCH_8(config, "soundlatch"); + + ym2203_device &ym1(YM2203(config, "ym1", 6000000 / 4)); + ym1.irq_handler().set_inputline(m_audiocpu, 0); + ym1.add_route(0, "mono", 0.15); + ym1.add_route(1, "mono", 0.15); + ym1.add_route(2, "mono", 0.15); + ym1.add_route(3, "mono", 0.50); +} + +void valtric_state::valtric(machine_config &config) +{ + /* basic machine hardware */ + Z80(config, m_maincpu, 5000000); /* 5 MHz */ + m_maincpu->set_addrmap(AS_PROGRAM, &valtric_state::valtric_map); + TIMER(config, "scantimer").configure_scanline(FUNC(valtric_state::scanline), "screen", 0, 1); + + Z80(config, m_audiocpu, 5000000); + m_audiocpu->set_addrmap(AS_PROGRAM, &valtric_state::sound_map_a); + m_audiocpu->set_addrmap(AS_IO, &valtric_state::sound_portmap_2); + + config.set_maximum_quantum(attotime::from_hz(600)); + + /* video hardware */ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_refresh_hz(54); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); /* This value is referred to psychic5 driver */ + m_screen->set_size(32*16, 32*16); + m_screen->set_visarea(0*8, 32*8-1, 2*8, 30*8-1); + m_screen->set_screen_update(FUNC(valtric_state::screen_update)); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx_valtric); + PALETTE(config, m_palette).set_entries(768); + + JALECO_BLEND(config, m_blend, 0); + + /* sound hardware */ + SPEAKER(config, "mono").front_center(); + + GENERIC_LATCH_8(config, "soundlatch"); + + ym2203_device &ym1(YM2203(config, "ym1", 6000000 / 4)); + ym1.irq_handler().set_inputline(m_audiocpu, 0); + ym1.add_route(0, "mono", 0.15); + ym1.add_route(1, "mono", 0.15); + ym1.add_route(2, "mono", 0.15); + ym1.add_route(3, "mono", 0.50); + + ym2203_device &ym2(YM2203(config, "ym2", 6000000 / 4)); + ym2.add_route(0, "mono", 0.15); + ym2.add_route(1, "mono", 0.15); + ym2.add_route(2, "mono", 0.15); + ym2.add_route(3, "mono", 0.50); +} + +void butasan_state::butasan(machine_config &config) +{ + /* basic machine hardware */ + Z80(config, m_maincpu, 5000000); /* 5 MHz */ + m_maincpu->set_addrmap(AS_PROGRAM, &butasan_state::butasan_map); + TIMER(config, "scantimer").configure_scanline(FUNC(butasan_state::scanline), "screen", 0, 1); + + Z80(config, m_audiocpu, 5000000); + m_audiocpu->set_addrmap(AS_PROGRAM, &butasan_state::sound_map_b); + m_audiocpu->set_addrmap(AS_IO, &butasan_state::sound_portmap_2); + + config.set_maximum_quantum(attotime::from_hz(600)); + + /* video hardware */ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_refresh_hz(54); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); /* This value is taken from psychic5 driver */ + m_screen->set_size(32*16, 32*16); + m_screen->set_visarea(0*8, 32*8-1, 1*8, 31*8-1); + m_screen->set_screen_update(FUNC(butasan_state::screen_update)); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx_butasan); + PALETTE(config, m_palette).set_entries(768); + + JALECO_BLEND(config, m_blend, 0); + + /* sound hardware */ + SPEAKER(config, "mono").front_center(); + + GENERIC_LATCH_8(config, "soundlatch"); + + ym2203_device &ym1(YM2203(config, "ym1", 6000000 / 4)); + ym1.irq_handler().set_inputline(m_audiocpu, 0); + ym1.add_route(0, "mono", 0.30); + ym1.add_route(1, "mono", 0.30); + ym1.add_route(2, "mono", 0.30); + ym1.add_route(3, "mono", 1.0); + + ym2203_device &ym2(YM2203(config, "ym2", 6000000 / 4)); + ym2.add_route(0, "mono", 0.30); + ym2.add_route(1, "mono", 0.30); + ym2.add_route(2, "mono", 0.30); + ym2.add_route(3, "mono", 1.0); +} + + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +ROM_START( argus ) + ROM_REGION( 0x28000, "maincpu", 0 ) /* Main CPU */ + ROM_LOAD( "ag_02.bin", 0x00000, 0x08000, CRC(278a3f3d) SHA1(c5ac5a004ebf0194c33f71dab4020fa636cefbc2) ) + ROM_LOAD( "ag_03.bin", 0x10000, 0x08000, CRC(3a7f3bfa) SHA1(b11e134c084fc3c982dfe31836c1cf3fc0d481fd) ) + ROM_LOAD( "ag_04.bin", 0x18000, 0x08000, CRC(76adc9f6) SHA1(e223a8b2371c51f121958ee3687c777f597334c9) ) + ROM_LOAD( "ag_05.bin", 0x20000, 0x08000, CRC(f76692d6) SHA1(1dc353a042cdda909eb9f1b1ca749a3b3eaa01e4) ) + + ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound CPU */ + ROM_LOAD( "ag_01.bin", 0x00000, 0x04000, CRC(769e3f57) SHA1(209160a96486ab0b90967c015143ec28fba2e2a4) ) + + ROM_REGION( 0x20000, "gfx1", 0 ) /* Sprite */ + ROM_LOAD( "ag_09.bin", 0x00000, 0x08000, CRC(6dbc1c58) SHA1(ef7b6901b702dd347b3a3f162162138175efe578) ) + ROM_LOAD( "ag_08.bin", 0x08000, 0x08000, CRC(ce6e987e) SHA1(9de257d8061ec917f4d443ff509fd457f995d73b) ) + ROM_LOAD( "ag_07.bin", 0x10000, 0x08000, CRC(bbb9638d) SHA1(61dec71d4d976bef3af26d0dc9c0355fd1098ffb) ) + ROM_LOAD( "ag_06.bin", 0x18000, 0x08000, CRC(655b48f8) SHA1(4fce1dffe091b97e7055955743434e49e97b4b79) ) + + ROM_REGION( 0x20000, "gfx2", 0 ) /* BG0 */ + ROM_LOAD( "ag_13.bin", 0x00000, 0x08000, CRC(20274268) SHA1(9b7767d14bd169dabe6add0623d353bf4b59779b) ) + ROM_LOAD( "ag_14.bin", 0x08000, 0x08000, CRC(ceb8860b) SHA1(90e094686d9d18e49e4848d18d1e31ac95f13937) ) + ROM_LOAD( "ag_11.bin", 0x10000, 0x08000, CRC(99ce8556) SHA1(39caababd6e20ecb0375b85fb6490ee0b04f0949) ) + ROM_LOAD( "ag_12.bin", 0x18000, 0x08000, CRC(e0e5377c) SHA1(b5981d832127d0b28b6a7bb0437716593e0ed71a) ) + + ROM_REGION( 0x08000, "gfx3", 0 ) /* BG1 */ + ROM_LOAD( "ag_17.bin", 0x00000, 0x08000, CRC(0f12d09b) SHA1(718db4ff016526dddacdf6f0088f247ee97c6543) ) + + ROM_REGION( 0x08000, "gfx4", 0 ) /* Text */ + ROM_LOAD( "ag_10.bin", 0x00000, 0x04000, CRC(2de696c4) SHA1(1ad0f1cde127a1618c2ea74a53e522963a79e5ce) ) + + ROM_REGION( 0x08000, "vrom1", 0 ) /* Map */ + ROM_LOAD( "ag_15.bin", 0x00000, 0x08000, CRC(99834c1b) SHA1(330f271771b158493b28bb178c8cda98efd1d90c) ) + + ROM_REGION( 0x08000, "vrom2", 0 ) /* Pattern */ + ROM_LOAD( "ag_16.bin", 0x00000, 0x08000, CRC(39a51714) SHA1(ad89a630f1352eb4d8beeeebf909d5e2b5d7cc12) ) +ROM_END + +ROM_START( valtric ) + ROM_REGION( 0x30000, "maincpu", 0 ) /* Main CPU */ + ROM_LOAD( "vt_04.bin", 0x00000, 0x08000, CRC(709c705f) SHA1(b82e2209a0371dcbc2708c485b02985cea04353f) ) // 512 + ROM_LOAD( "vt_06.bin", 0x10000, 0x10000, CRC(c9cbb4e4) SHA1(3c84cda778263a9bb2031e29f6f29f29878d2070) ) // 512 + ROM_LOAD( "vt_05.bin", 0x20000, 0x10000, CRC(7ab2684b) SHA1(9bca7e2fd3b5f4043de37cd439d5235957e5012f) ) // 512 + + ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound CPU */ + ROM_LOAD( "vt_01.bin", 0x00000, 0x08000, CRC(4616484f) SHA1(24d060218cc1542ebfc2100ecd6489a0e17b36ee) ) // 512 + + ROM_REGION( 0x20000, "gfx1", 0 ) /* Sprite */ + ROM_LOAD( "vt_02.bin", 0x00000, 0x10000, CRC(66401977) SHA1(91c527d0bcea54d723068715a12cb3c976d04294) ) // 512 + ROM_LOAD( "vt_03.bin", 0x10000, 0x10000, CRC(9203bbce) SHA1(f40cee48f62a87a0b5d18e271faa5b8dd36ae5f1) ) // 512 + + ROM_REGION( 0x40000, "gfx2", 0 ) /* BG */ + ROM_LOAD( "vt_08.bin", 0x00000, 0x10000, CRC(661dd338) SHA1(cc643a14607c10e4a1710766f77422cd89a6bf94) ) // 27512 + ROM_LOAD( "vt_09.bin", 0x10000, 0x10000, CRC(085a35b1) SHA1(ff589e67b6b5a6e661f29294a32a3840f45a9304) ) // 27512 + ROM_LOAD( "vt_10.bin", 0x20000, 0x10000, CRC(09c47323) SHA1(fcfbd5054e63fae00b6a3959228964ac8f3cbf37) ) // 27512 + ROM_LOAD( "vt_11.bin", 0x30000, 0x10000, CRC(4cf800b5) SHA1(7241e284b15475d8a6d533e4caadd0acbf058231) ) // 27512 + + ROM_REGION( 0x08000, "gfx3", 0 ) /* Text */ + ROM_LOAD( "vt_07.bin", 0x00000, 0x04000, CRC(4b9771ae) SHA1(6079f2d3abf836f04b83983485fdaba2fb357811) ) // 27128 + + ROM_REGION (0x100, "proms", 0) // currently not used by the emulation, without it you just get diagonal glitches on a real board. + ROM_LOAD( "82s129.1s", 0x000, 0x100, CRC(bc42f9b5) SHA1(962c812d5d1f0e539238a4ec49866ef3558db629) ) // located on the top board +ROM_END + +ROM_START( butasan ) /* English "subtitle" of Butasan for Japanese region. Original Jaleco PCB */ + ROM_REGION( 0x30000, "maincpu", 0 ) /* Main CPU */ + ROM_LOAD( "4.t2", 0x00000, 0x08000, CRC(1ba1d8e4) SHA1(ab141a1fbaab9f3ef6788b131833effb32c42930) ) /* M5L27256K-2 (32kb) - 4.4.bin */ + ROM_LOAD( "3.s2", 0x10000, 0x10000, CRC(a6b3ccc2) SHA1(fcc9db1cd68fd9477d86e63e6906d194d5ee477a) ) + ROM_LOAD( "2.p2", 0x20000, 0x10000, CRC(96517fa9) SHA1(03ee1f118f109c85b046098c457a90b40e163f3c) ) + + ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound CPU */ + ROM_LOAD( "1.b2", 0x00000, 0x10000, CRC(c9d23e2d) SHA1(cee289d5bf7626fc35808a09f9f1f4628fa16974) ) + + ROM_REGION( 0x80000, "gfx1", 0 ) /* Sprite */ + ROM_LOAD( "16.k16", 0x00000, 0x10000, CRC(e0ce51b6) SHA1(458c7c422a7b6ce42f397a8868610f6386fd815c) ) + ROM_LOAD( "15.k15", 0x10000, 0x10000, CRC(2105f6e1) SHA1(54c13073f0dc8b5d3fb5578aa5958a5dd01396a6) ) + ROM_LOAD( "14.k14", 0x20000, 0x10000, CRC(8ec891c1) SHA1(e16f18a0eed300752af8f07fd3cef5cd825a2a05) ) + ROM_LOAD( "13.k13", 0x30000, 0x10000, CRC(5023e74d) SHA1(edf43e6c89f0e537cebf1c21a671dba4cd7d91ea) ) + ROM_LOAD( "12.k12", 0x40000, 0x10000, CRC(44f59905) SHA1(bf364f7f907fee551e9228db7c27c106bcfecf6c) ) + ROM_LOAD( "11.k11", 0x50000, 0x10000, CRC(b8929f1d) SHA1(18a72f30284bed0c6723105f87eb10d64d3f461d) ) + ROM_LOAD( "10.k10", 0x60000, 0x10000, CRC(fd4d3baf) SHA1(fa8e3970a8aac83efcb669fe5d4683adade9aa4f) ) + ROM_LOAD( "9.k9", 0x70000, 0x10000, CRC(7da4c0fd) SHA1(fb2b148ccfee530313da886eddf7711ee83b4aeb) ) + + ROM_REGION( 0x20000, "gfx2", 0 ) /* BG0 */ + ROM_LOAD( "5.l7", 0x00000, 0x10000, CRC(b8e026b0) SHA1(eb6ff9042b21b7190000c571ccba7d81f11ce9f1) ) + ROM_LOAD( "6.n7", 0x10000, 0x10000, CRC(8bbacb81) SHA1(015be76e44ed2389eff912d8f61a757667d7670b) ) + + ROM_REGION( 0x10000, "gfx3", 0 ) /* BG1 */ + ROM_LOAD( "7.a8", 0x00000, 0x10000, CRC(3a48d531) SHA1(0ff6256bb7ea909d95b2bfb994ebc5432ea6d055) ) + + ROM_REGION( 0x08000, "gfx4", 0 ) /* Text */ + ROM_LOAD( "8.a7", 0x00000, 0x08000, CRC(85153252) SHA1(20af223f9dc2e29e506e257c36e96d10dc150467) ) + + ROM_REGION( 0x00200, "proms", 0 ) /* Data proms ??? */ + ROM_LOAD( "buta-01.prm", 0x00000, 0x00100, CRC(45baedd0) SHA1(afdafb67d55007e6fb99518657e27ce61d2cb7e6) ) + ROM_LOAD( "buta-02.prm", 0x00100, 0x00100, CRC(0dcb18fc) SHA1(0b097b873c9484981f87a5e3d1af767f901ae05f) ) +ROM_END + +ROM_START( butasanj ) + ROM_REGION( 0x30000, "maincpu", 0 ) /* Main CPU */ + ROM_LOAD( "buta-04.bin", 0x00000, 0x08000, CRC(47ff4ca9) SHA1(d89a41f6987c91d20b010f0cbda332cf54b21f8c) ) + ROM_LOAD( "buta-03.bin", 0x10000, 0x10000, CRC(69fd88c7) SHA1(fd827d7926a2de5ffe2982b3a59ea43de00ee46b) ) + ROM_LOAD( "buta-02.bin", 0x20000, 0x10000, CRC(519dc412) SHA1(48bbb01b217bd19c48ef7ab12c60805aaa02527c) ) + + ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound CPU */ + ROM_LOAD( "1.b2", 0x00000, 0x10000, CRC(c9d23e2d) SHA1(cee289d5bf7626fc35808a09f9f1f4628fa16974) ) // buta-01.bin + + ROM_REGION( 0x80000, "gfx1", 0 ) /* Sprite */ + ROM_LOAD( "16.k16", 0x00000, 0x10000, CRC(e0ce51b6) SHA1(458c7c422a7b6ce42f397a8868610f6386fd815c) ) // buta-16.bin + ROM_LOAD( "buta-15.bin", 0x10000, 0x10000, CRC(3ed19daa) SHA1(b8090c3baa2b31681bed15c682a97c024e229df7) ) + ROM_LOAD( "14.k14", 0x20000, 0x10000, CRC(8ec891c1) SHA1(e16f18a0eed300752af8f07fd3cef5cd825a2a05) ) // buta-14.bin + ROM_LOAD( "13.k13", 0x30000, 0x10000, CRC(5023e74d) SHA1(edf43e6c89f0e537cebf1c21a671dba4cd7d91ea) ) // buta-13.bin + ROM_LOAD( "12.k12", 0x40000, 0x10000, CRC(44f59905) SHA1(bf364f7f907fee551e9228db7c27c106bcfecf6c) ) // buta-12.bin + ROM_LOAD( "11.k11", 0x50000, 0x10000, CRC(b8929f1d) SHA1(18a72f30284bed0c6723105f87eb10d64d3f461d) ) // buta-11.bin + ROM_LOAD( "10.k10", 0x60000, 0x10000, CRC(fd4d3baf) SHA1(fa8e3970a8aac83efcb669fe5d4683adade9aa4f) ) // buta-10.bin + ROM_LOAD( "9.k9", 0x70000, 0x10000, CRC(7da4c0fd) SHA1(fb2b148ccfee530313da886eddf7711ee83b4aeb) ) // buta-09.bin + + ROM_REGION( 0x20000, "gfx2", 0 ) /* BG0 */ + ROM_LOAD( "5.l7", 0x00000, 0x10000, CRC(b8e026b0) SHA1(eb6ff9042b21b7190000c571ccba7d81f11ce9f1) ) // buta-05.bin + ROM_LOAD( "6.n7", 0x10000, 0x10000, CRC(8bbacb81) SHA1(015be76e44ed2389eff912d8f61a757667d7670b) ) // buta-06.bin + + ROM_REGION( 0x10000, "gfx3", 0 ) /* BG1 */ + ROM_LOAD( "7.a8", 0x00000, 0x10000, CRC(3a48d531) SHA1(0ff6256bb7ea909d95b2bfb994ebc5432ea6d055) ) // buta-07.bin + + ROM_REGION( 0x08000, "gfx4", 0 ) /* Text */ + ROM_LOAD( "buta-08.bin", 0x00000, 0x08000, CRC(5d45ce9c) SHA1(113c3e7ce20634ee4bb740705485572583298694) ) + + ROM_REGION( 0x00200, "proms", 0 ) /* Data proms ??? */ + ROM_LOAD( "buta-01.prm", 0x00000, 0x00100, CRC(45baedd0) SHA1(afdafb67d55007e6fb99518657e27ce61d2cb7e6) ) + ROM_LOAD( "buta-02.prm", 0x00100, 0x00100, CRC(0dcb18fc) SHA1(0b097b873c9484981f87a5e3d1af767f901ae05f) ) +ROM_END + + +/* ( YEAR NAME PARENT MACHINE INPUT STATE INIT MONITOR COMPANY FULLNAME ) */ +GAME( 1986, argus, 0, argus, argus, argus_state, empty_init, ROT270, "NMK (Jaleco license)", "Argus", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE | MACHINE_NO_COCKTAIL ) +GAME( 1986, valtric, 0, valtric, valtric, valtric_state, empty_init, ROT270, "NMK (Jaleco license)", "Valtric", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +GAME( 1987, butasan, 0, butasan, butasan, butasan_state, empty_init, ROT0, "NMK (Jaleco license)", "Butasan - Pig's & Bomber's (Japan, English)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +GAME( 1987, butasanj, butasan, butasan, butasan, butasan_state, empty_init, ROT0, "NMK (Jaleco license)", "Butasan (Japan, Japanese)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) diff --git a/cores/argus/doc/argus.h b/cores/argus/doc/argus.h new file mode 100644 index 000000000..b3e2696cf --- /dev/null +++ b/cores/argus/doc/argus.h @@ -0,0 +1,186 @@ +// license:BSD-3-Clause +// copyright-holders:Yochizo + +#include "machine/timer.h" +#include "jalblend.h" +#include "emupal.h" +#include "screen.h" +#include "tilemap.h" + +class argus_common_state : public driver_device +{ +protected: + argus_common_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_audiocpu(*this, "audiocpu") + , m_gfxdecode(*this, "gfxdecode") + , m_screen(*this, "screen") + , m_palette(*this, "palette") + , m_blend(*this, "blend") + , m_bg_scrollx(*this, "bg%u_scrollx", 0U) + , m_bg_scrolly(*this, "bg%u_scrolly", 0U) + , m_paletteram(*this, "paletteram") + , m_txram(*this, "txram") + , m_bg1ram(*this, "bg1ram") + , m_spriteram(*this, "spriteram") + , m_vrom(*this, "vrom%u", 1U) + { } + + required_device m_maincpu; + required_device m_audiocpu; + required_device m_gfxdecode; + required_device m_screen; + required_device m_palette; + required_device m_blend; + + optional_shared_ptr_array m_bg_scrollx; + optional_shared_ptr_array m_bg_scrolly; + required_shared_ptr m_paletteram; + optional_shared_ptr m_txram; + optional_shared_ptr m_bg1ram; + required_shared_ptr m_spriteram; + optional_region_ptr_array m_vrom; + + // common + u8 m_bg_status = 0U; + u8 m_flipscreen = 0U; + u16 m_palette_intensity = 0U; + + // argus specific + u8 m_vrom_offset = 0U; + + tilemap_t *m_tx_tilemap = nullptr; + tilemap_t *m_bg_tilemap[2]{}; + + // common + void bankselect_w(u8 data); + void txram_w(offs_t offset, u8 data); + void bg1ram_w(offs_t offset, u8 data); + void flipscreen_w(u8 data); + + template TILE_GET_INFO_MEMBER(get_tx_tile_info); + + virtual void machine_start() override ATTR_COLD; + + TIMER_DEVICE_CALLBACK_MEMBER(scanline); + + void reset_common(); + void change_palette(int color, int lo_offs, int hi_offs); + void change_bg_palette(int color, int lo_offs, int hi_offs); + void bg_setting(); + + void sound_map_a(address_map &map) ATTR_COLD; + void sound_map_b(address_map &map) ATTR_COLD; + void sound_portmap_1(address_map &map) ATTR_COLD; + void sound_portmap_2(address_map &map) ATTR_COLD; +}; + +class argus_state : public argus_common_state +{ +public: + argus_state(const machine_config &mconfig, device_type type, const char *tag) + : argus_common_state(mconfig, type, tag) + { } + + void argus(machine_config &config); + +protected: + virtual void video_start() override ATTR_COLD; + virtual void video_reset() override ATTR_COLD; + +private: + void bg_status_w(u8 data); + void paletteram_w(offs_t offset, u8 data); + + TILE_GET_INFO_MEMBER(get_bg0_tile_info); + TILE_GET_INFO_MEMBER(get_bg1_tile_info); + + void draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect, int priority); + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void argus_map(address_map &map) ATTR_COLD; +}; + +class valtric_state : public argus_common_state +{ +public: + valtric_state(const machine_config &mconfig, device_type type, const char *tag) + : argus_common_state(mconfig, type, tag) + { } + + void valtric(machine_config &config); + +protected: + virtual void video_start() override ATTR_COLD; + virtual void video_reset() override ATTR_COLD; + +private: + void mosaic_w(u8 data); + void bg_status_w(u8 data); + void paletteram_w(offs_t offset, u8 data); + void unknown_w(u8 data); + + TILE_GET_INFO_MEMBER(get_bg_tile_info); + + void draw_mosaic(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect); + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void valtric_map(address_map &map) ATTR_COLD; + + u8 m_valtric_mosaic = 0U; + bitmap_rgb32 m_mosaicbitmap = 0; + u8 m_valtric_unknown = 0U; + int m_mosaic = 0; +}; + +class butasan_state : public argus_common_state +{ +public: + butasan_state(const machine_config &mconfig, device_type type, const char *tag) + : argus_common_state(mconfig, type, tag) + , m_butasan_bg1ram(*this, "butasan_bg1ram") + { } + + void butasan(machine_config &config); + +protected: + virtual void video_start() override ATTR_COLD; + virtual void video_reset() override ATTR_COLD; + +private: + void bg0_status_w(u8 data); + void bg1_status_w(u8 data); + void paletteram_w(offs_t offset, u8 data); + void bg1ram_w(offs_t offset, u8 data); + void pageselect_w(u8 data); + u8 pagedram_r(offs_t offset); + void pagedram_w(offs_t offset, u8 data); + void unknown_w(u8 data); + + TILE_GET_INFO_MEMBER(get_tx_tile_info); + TILE_GET_INFO_MEMBER(get_bg0_tile_info); + TILE_GET_INFO_MEMBER(get_bg1_tile_info); + TILEMAP_MAPPER_MEMBER(bg_scan); + TILEMAP_MAPPER_MEMBER(tx_scan); + + void draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void log_vram(); + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + TIMER_DEVICE_CALLBACK_MEMBER(scanline); + + void butasan_map(address_map &map) ATTR_COLD; + + required_shared_ptr m_butasan_bg1ram; + + u8 *m_butasan_txram = nullptr; + u8 *m_butasan_bg0ram = nullptr; + u8 *m_butasan_bg0backram = nullptr; + u8 *m_butasan_txbackram = nullptr; + std::unique_ptr m_butasan_pagedram[2]{}; + u8 m_butasan_page_latch = 0U; + u8 m_butasan_bg1_status = 0U; + u8 m_butasan_unknown = 0U; +}; diff --git a/cores/argus/doc/argus_v.cpp b/cores/argus/doc/argus_v.cpp new file mode 100644 index 000000000..5c7338512 --- /dev/null +++ b/cores/argus/doc/argus_v.cpp @@ -0,0 +1,1031 @@ +// license:BSD-3-Clause +// copyright-holders:Yochizo +/*************************************************************************** + +Functions to emulate the video hardware of the machine. + + +BG RAM format [Argus and Butasan] +----------------------------------------------------------------------------- + +0 +1 + xxxx xxxx ---- ---- = 1st - 8th bits of tile number + ---- ---- xx-- ---- = 9th and 10th bit of tile number + ---- ---- --x- ---- = flip y + ---- ---- ---x ---- = flip x + ---- ---- ---- xxxx = color + +BG RAM format [Valtric] +----------------------------------------------------------------------------- + +0 +1 + xxxx xxxx ---- ---- = 1st - 8th bits of tile number + ---- ---- xx-- ---- = 9th and 10th bit of tile number + ---- ---- --x- ---- = 11th bit of tile number + ---- ---- ---- xxxx = color + + +Text RAM format [Argus, Valtric and Butasan] +----------------------------------------------------------------------------- + +0 +1 + xxxx xxxx ---- ---- = low bits of tile number + ---- ---- xx-- ---- = high bits of tile number + ---- ---- --x- ---- = flip y + ---- ---- ---x ---- = flip x + ---- ---- ---- xxxx = color + + +Sprite RAM format [Argus] +----------------------------------------------------------------------------- + +11 +12 +13 +14 +15 + xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = sprite y + ---- ---- xxxx xxxx ---- ---- ---- ---- ---- ---- = low bits of sprite x + ---- ---- ---- ---- xx-- ---- ---- ---- ---- ---- = high bits of tile number + ---- ---- ---- ---- --x- ---- ---- ---- ---- ---- = flip y + ---- ---- ---- ---- ---x ---- ---- ---- ---- ---- = flip x + ---- ---- ---- ---- ---- --x- ---- ---- ---- ---- = high bit of sprite y + ---- ---- ---- ---- ---- ---x ---- ---- ---- ---- = high bit of sprite x + ---- ---- ---- ---- ---- ---- xxxx xxxx ---- ---- = low bits of tile number + ---- ---- ---- ---- ---- ---- ---- ---- ---- x--- = BG1 / sprite priority (Argus only) + ---- ---- ---- ---- ---- ---- ---- ---- ---- -xxx = color + +Sprite RAM format [Valtric] +----------------------------------------------------------------------------- + +11 +12 +13 +14 +15 + xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- = sprite y + ---- ---- xxxx xxxx ---- ---- ---- ---- ---- ---- = low bits of sprite x + ---- ---- ---- ---- xx-- ---- ---- ---- ---- ---- = high bits of tile number + ---- ---- ---- ---- --x- ---- ---- ---- ---- ---- = flip y + ---- ---- ---- ---- ---x ---- ---- ---- ---- ---- = flip x + ---- ---- ---- ---- ---- --x- ---- ---- ---- ---- = high bit of sprite y + ---- ---- ---- ---- ---- ---x ---- ---- ---- ---- = high bit of sprite x + ---- ---- ---- ---- ---- ---- xxxx xxxx ---- ---- = low bits of tile number + ---- ---- ---- ---- ---- ---- ---- ---- ---- xxxx = color + +Sprite RAM format [Butasan] +----------------------------------------------------------------------------- + +8 +9 +10 +11 +12 + ---- -x-- ---- ---- ---- ---- ---- ---- ---- ---- = flip y + ---- ---x ---- ---- ---- ---- ---- ---- ---- ---- = flip x + ---- ---- ---- xxxx ---- ---- ---- ---- ---- ---- = color ($00 - $0B) + ---- ---- ---- ---- xxxx xxxx ---- ---- ---- ---- = low bits of sprite x + ---- ---- ---- ---- ---- ---- ---- ---x ---- ---- = top bit of sprite x + ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx = low bits of sprite y + +13 +14 +15 + ---- ---x ---- ---- ---- ---- = top bit of sprite y + ---- ---- xxxx xxxx ---- ---- = low bits of tile number + ---- ---- ---- ---- ---- xxxx = top bits of tile number + +(*) Sprite size is defined by its offset. + $F000 - $F0FF : 16x32 $F100 - $F2FF : 16x16 + $F300 - $F3FF : 16x32 $F400 - $F57F : 16x16 + $F580 - $F61F : 32x32 $F620 - $F67F : 64x64 + + +Scroll RAM of X and Y coordinates [Argus, Valtric and Butasan] +----------------------------------------------------------------------------- + +0 +1 + xxxx xxxx ---- ---- = scroll value + ---- ---- ---- ---x = top bit of scroll value + + +Video effect RAM ( $C30C ) +----------------------------------------------------------------------------- + +0 + ---- ---x = BG enable bit + ---- --x- = grey scale effect or tile bank select. + + +Flip screen controller +----------------------------------------------------------------------------- + +0 + x--- ---- = flip screen + + +BG0 palette intensity ( $C47F, $C4FF ) +----------------------------------------------------------------------------- + +0 (c47f) +1 (c4ff) + xxxx ---- ---- ---- = red intensity + ---- xxxx ---- ---- = green intensity + ---- ---- xxxx ---- = blue intensity + + +(*) Things which are not emulated. + - Color $000 - 00f, $01e, $02e ... are half transparent color. + - Sprite priority bit may be present in Butasan. But I don't know + what happens when it is set. + +***************************************************************************/ + +#include "emu.h" +#include "argus.h" + + +/*************************************************************************** + Callbacks for the tilemap code +***************************************************************************/ + +template +TILE_GET_INFO_MEMBER(argus_common_state::get_tx_tile_info) +{ + tile_index <<= 1; + + u8 lo = m_txram[tile_index]; + u8 hi = m_txram[tile_index + 1]; + + tileinfo.set(Gfx, + ((hi & 0xc0) << 2) | lo, + hi & 0x0f, + TILE_FLIPYX((hi & 0x30) >> 4)); +} + +TILE_GET_INFO_MEMBER(argus_state::get_bg0_tile_info) +{ + // logical width is 65536(4096*16) but we load only 1024 pixel each + // for reduce RAM usage + tile_index = (((m_vrom_offset << 9) + tile_index) & 0x1ffff) << 1; + int vrom_offset = (tile_index >> 3); + tile_index = (m_vrom[0][vrom_offset & ~1] << 4) | ((m_vrom[0][vrom_offset | 1] & 0x7) << 12) | (tile_index & 0xf); + + u8 lo = m_vrom[1][tile_index]; + u8 hi = m_vrom[1][tile_index | 1]; + + tileinfo.set(1, + ((hi & 0xc0) << 2) | lo, + hi & 0x0f, + TILE_FLIPYX((hi & 0x30) >> 4)); +} + +TILE_GET_INFO_MEMBER(argus_state::get_bg1_tile_info) +{ + tile_index <<= 1; + + u8 lo = m_bg1ram[tile_index]; + u8 hi = m_bg1ram[tile_index + 1]; + + tileinfo.set(2, + lo, + hi & 0x0f, + TILE_FLIPYX((hi & 0x30) >> 4)); +} + +TILE_GET_INFO_MEMBER(valtric_state::get_bg_tile_info) +{ + tile_index <<= 1; + + u8 lo = m_bg1ram[tile_index]; + u8 hi = m_bg1ram[tile_index + 1]; + + tileinfo.set(1, + ((hi & 0xc0) << 2) | ((hi & 0x20) << 5) | lo, + hi & 0x0f, + 0); +} + +TILE_GET_INFO_MEMBER(butasan_state::get_tx_tile_info) +{ + tile_index <<= 1; + + u8 lo = m_butasan_txram[tile_index]; + u8 hi = m_butasan_txram[tile_index + 1]; + + tileinfo.set(3, + ((hi & 0xc0) << 2) | lo, + hi & 0x0f, + TILE_FLIPYX((hi & 0x30) >> 4)); +} + +TILE_GET_INFO_MEMBER(butasan_state::get_bg0_tile_info) +{ + tile_index <<= 1; + + u8 lo = m_butasan_bg0ram[tile_index]; + u8 hi = m_butasan_bg0ram[tile_index + 1]; + + tileinfo.set(1, + ((hi & 0xc0) << 2) | lo, + hi & 0x0f, + TILE_FLIPYX((hi & 0x30) >> 4)); +} + +TILE_GET_INFO_MEMBER(butasan_state::get_bg1_tile_info) +{ + int const tile = m_butasan_bg1ram[tile_index] | ((m_butasan_bg1_status & 2) << 7); + + tileinfo.set(2, + tile, + (tile & 0x80) >> 7, + 0); +} + +TILEMAP_MAPPER_MEMBER(butasan_state::bg_scan) +{ + /* logical (col,row) -> memory offset */ + return (col & 0x0f) | ((row ^ 0x0f) << 4) | ((col & 0x10) << 5); +} + +TILEMAP_MAPPER_MEMBER(butasan_state::tx_scan) +{ + /* logical (col,row) -> memory offset */ + return (col & 0x1f) | ((row ^ 0x1f) << 5); +} + +/*************************************************************************** + Initialize and destroy video hardware emulation +***************************************************************************/ + +void argus_common_state::reset_common() +{ + m_bg_status = 0x01; + m_flipscreen = 0; + m_palette_intensity = 0; +} + +void argus_state::video_start() +{ + /* info offset w h col row */ +// m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(argus_state::get_bg0_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 4096, 32); // full 65536 width tilemap + m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(argus_state::get_bg0_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 1024/16, 32); + m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(argus_state::get_bg1_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 32, 32); + m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(argus_state::get_tx_tile_info<3>)), TILEMAP_SCAN_COLS, 8, 8, 32, 32); + + m_bg_tilemap[1]->set_transparent_pen(15); + m_tx_tilemap->set_transparent_pen(15); + + save_item(NAME(m_bg_status)); + save_item(NAME(m_flipscreen)); + save_item(NAME(m_palette_intensity)); +} + +void argus_state::video_reset() +{ + m_bg_scrollx[0][0] = 0; + m_bg_scrollx[0][1] = 0; + reset_common(); +} + +void valtric_state::video_start() +{ + /* info offset w h col row */ + m_bg_tilemap[0] = nullptr; + m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(valtric_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 32, 32); + m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(valtric_state::get_tx_tile_info<2>)), TILEMAP_SCAN_COLS, 8, 8, 32, 32); + + m_tx_tilemap->set_transparent_pen(15); + + m_screen->register_screen_bitmap(m_mosaicbitmap); + + save_item(NAME(m_bg_status)); + save_item(NAME(m_flipscreen)); + save_item(NAME(m_palette_intensity)); + save_item(NAME(m_valtric_mosaic)); + save_item(NAME(m_valtric_unknown)); + save_item(NAME(m_mosaic)); +} + +void valtric_state::video_reset() +{ + m_valtric_mosaic = 0x0f; + reset_common(); +} + +void butasan_state::video_start() +{ + /* info offset w h col row */ + m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(butasan_state::get_bg0_tile_info)), tilemap_mapper_delegate(*this, FUNC(butasan_state::bg_scan)), 16, 16, 32, 32); + m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(butasan_state::get_bg1_tile_info)), tilemap_mapper_delegate(*this, FUNC(butasan_state::bg_scan)), 16, 16, 32, 32); + m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(butasan_state::get_tx_tile_info)), tilemap_mapper_delegate(*this, FUNC(butasan_state::tx_scan)), 8, 8, 32, 32); + + m_bg_tilemap[1]->set_transparent_pen(15); + m_tx_tilemap->set_transparent_pen(15); + + m_butasan_pagedram[0] = std::make_unique(0x1000); + m_butasan_pagedram[1] = std::make_unique(0x1000); + + m_butasan_bg0ram = &m_butasan_pagedram[0][0x000]; + m_butasan_bg0backram = &m_butasan_pagedram[0][0x800]; + m_butasan_txram = &m_butasan_pagedram[1][0x000]; + m_butasan_txbackram = &m_butasan_pagedram[1][0x800]; + + save_item(NAME(m_bg_status)); + save_item(NAME(m_flipscreen)); + save_item(NAME(m_palette_intensity)); + save_pointer(NAME(m_butasan_pagedram[0]), 0x1000); + save_pointer(NAME(m_butasan_pagedram[1]), 0x1000); + save_item(NAME(m_butasan_page_latch)); + save_item(NAME(m_butasan_bg1_status)); + save_item(NAME(m_butasan_unknown)); +} + +void butasan_state::video_reset() +{ + m_butasan_page_latch = 0; + m_butasan_bg1_status = 0x01; + memset(m_butasan_pagedram[0].get(), 0, 0x1000); + memset(m_butasan_pagedram[1].get(), 0, 0x1000); + reset_common(); +} + + +/*************************************************************************** + Functions for handler of MAP roms in Argus and palette color +***************************************************************************/ + +void argus_common_state::change_palette(int color, int lo_offs, int hi_offs) +{ + u8 lo = m_paletteram[lo_offs]; + u8 hi = m_paletteram[hi_offs]; + m_palette->set_pen_color(color, rgb_t(hi & 0x0f, pal4bit(lo >> 4), pal4bit(lo), pal4bit(hi >> 4))); +} + +void argus_common_state::change_bg_palette(int color, int lo_offs, int hi_offs) +{ + u8 r,g,b,lo,hi,ir,ig,ib,ix; + rgb_t rgb,irgb; + + /* red,green,blue intensities */ + ir = pal4bit(m_palette_intensity >> 12); + ig = pal4bit(m_palette_intensity >> 8); + ib = pal4bit(m_palette_intensity >> 4); + ix = m_palette_intensity & 0x0f; + + irgb = rgb_t(ir,ig,ib); + + lo = m_paletteram[lo_offs]; + hi = m_paletteram[hi_offs]; + + /* red,green,blue component */ + r = pal4bit(lo >> 4); + g = pal4bit(lo); + b = pal4bit(hi >> 4); + + /* Grey background enable */ + if (m_bg_status & 2) + { + u8 val = (r + g + b) / 3; + rgb = rgb_t(val,val,val); + } + else + { + rgb = rgb_t(r,g,b); + } + + rgb = m_blend->func(rgb,irgb,ix); + + m_palette->set_pen_color(color,rgb); +} + + +/*************************************************************************** + Memory handler +***************************************************************************/ + +void valtric_state::mosaic_w(u8 data) +{ + m_valtric_mosaic = data; +} + +void argus_common_state::txram_w(offs_t offset, u8 data) +{ + m_txram[offset] = data; + m_tx_tilemap->mark_tile_dirty(offset >> 1); +} + +void argus_common_state::bg1ram_w(offs_t offset, u8 data) +{ + m_bg1ram[offset] = data; + m_bg_tilemap[1]->mark_tile_dirty(offset >> 1); +} + +void argus_state::bg_status_w(u8 data) +{ + if (m_bg_status != data) + { + m_bg_status = data; + + /* Gray / purple scale */ + if (m_bg_status & 2) + { + int offs; + + for (offs = 0x400; offs < 0x500; offs++) + { + change_bg_palette((offs - 0x400) + 0x080, offs, offs + 0x400); + } + } + } +} + +void valtric_state::bg_status_w(u8 data) +{ + if (m_bg_status != data) + { + m_bg_status = data; + + /* Gray / purple scale */ + if (m_bg_status & 2) + { + int offs; + + for (offs = 0x400; offs < 0x600; offs += 2) + { + change_bg_palette(((offs - 0x400) >> 1) + 0x100, offs & ~1, offs | 1); + } + } + } +} + +void butasan_state::bg0_status_w(u8 data) +{ + m_bg_status = data; +} + +void butasan_state::bg1_status_w(u8 data) +{ + if (m_butasan_bg1_status != data) + { + m_butasan_bg1_status = data; + + /* Bank changed */ + m_bg_tilemap[1]->mark_all_dirty(); + } +} + +void argus_common_state::flipscreen_w(u8 data) +{ + m_flipscreen = data & 0x80; +} + +void argus_state::paletteram_w(offs_t offset, u8 data) +{ + int offs; + + m_paletteram[offset] = data; + + if (offset <= 0x0ff) /* sprite color */ + { + offset &= 0x07f; + + change_palette(offset, offset, offset + 0x080); + + if (offset == 0x07f || offset == 0x0ff) + { + m_palette_intensity = m_paletteram[0x0ff] | (m_paletteram[0x07f] << 8); + + for (offs = 0x400; offs < 0x500; offs++) + change_bg_palette((offs & 0xff) + 0x080, offs, offs + 0x400); + } + } + else if ((offset >= 0x400 && offset <= 0x4ff) || + (offset >= 0x800 && offset <= 0x8ff)) /* BG0 color */ + { + offs = offset & 0xff; + offset = offs | 0x400; + + change_bg_palette(offs + 0x080, offset, offset + 0x400); + } + else if ((offset >= 0x500 && offset <= 0x5ff) || + (offset >= 0x900 && offset <= 0x9ff)) /* BG1 color */ + { + offs = offset & 0xff; + offset = offs | 0x500; + + change_palette(offs + 0x180, offset, offset + 0x400); + } + else if ((offset >= 0x700 && offset <= 0x7ff) || + (offset >= 0xb00 && offset <= 0xbff)) /* text color */ + { + offs = offset & 0xff; + offset = offs | 0x700; + + change_palette(offs + 0x280, offset, offset + 0x400); + } +} + +void valtric_state::paletteram_w(offs_t offset, u8 data) +{ + m_paletteram[offset] = data; + + if (offset <= 0x1ff) /* Sprite color */ + { + change_palette(offset >> 1, offset & ~1, offset | 1); + + if (offset == 0x1fe || offset == 0x1ff) + { + int offs; + + m_palette_intensity = m_paletteram[0x1ff] | (m_paletteram[0x1fe] << 8); + + for (offs = 0x400; offs < 0x600; offs += 2) + change_bg_palette(((offs & 0x1ff) >> 1) + 0x100, offs & ~1, offs | 1); + } + } + else if (offset >= 0x400 && offset <= 0x5ff) /* BG color */ + { + change_bg_palette(((offset & 0x1ff) >> 1) + 0x100, offset & ~1, offset | 1); + } + else if (offset >= 0x600 && offset <= 0x7ff) /* Text color */ + { + change_palette(((offset & 0x1ff) >> 1) + 0x200, offset & ~1, offset | 1); + } +} + +void butasan_state::paletteram_w(offs_t offset, u8 data) +{ + m_paletteram[offset] = data; + + if (offset <= 0x1ff) /* BG0 color */ + { + change_palette((offset >> 1) + 0x100, offset & ~1, offset | 1); + } + else if (offset <= 0x23f) /* BG1 color */ + { + change_palette(((offset & 0x3f) >> 1) + 0x0c0, offset & ~1, offset | 1); + } + else if (offset >= 0x400 && offset <= 0x47f) /* Sprite color */ + { /* 16 colors */ + change_palette((offset & 0x7f) >> 1, offset & ~1, offset | 1); + } + else if (offset >= 0x480 && offset <= 0x4ff) /* Sprite color */ + { /* 8 colors */ + int offs = (offset & 0x070) | ((offset & 0x00f) >> 1); + + change_palette(offs + 0x040, offset & ~1, offset | 1); + change_palette(offs + 0x048, offset & ~1, offset | 1); + } + else if (offset >= 0x600 && offset <= 0x7ff) /* Text color */ + { + change_palette(((offset & 0x1ff) >> 1) + 0x200, offset & ~1, offset | 1); + } + else if (offset >= 0x240 && offset <= 0x25f) // dummy + change_palette(((offset & 0x1f) >> 1) + 0xe0, offset & ~1, offset | 1); + else if (offset >= 0x500 && offset <= 0x51f) // dummy + change_palette(((offset & 0x1f) >> 1) + 0xf0, offset & ~1, offset | 1); +} + +void butasan_state::bg1ram_w(offs_t offset, u8 data) +{ + m_butasan_bg1ram[offset] = data; + m_bg_tilemap[1]->mark_tile_dirty(offset); +} + +void butasan_state::pageselect_w(u8 data) +{ + m_butasan_page_latch = data & 1; +} + +u8 butasan_state::pagedram_r(offs_t offset) +{ + if (offset <= 0x07ff) + return m_butasan_pagedram[m_butasan_page_latch][offset]; + else + return m_butasan_pagedram[0][offset]; +} + +void butasan_state::pagedram_w(offs_t offset, u8 data) +{ + m_butasan_pagedram[m_butasan_page_latch][offset] = data; + + if (!m_butasan_page_latch) + { + if (offset <= 0x07ff) + m_bg_tilemap[0]->mark_tile_dirty(offset >> 1); + } + else + { + if (offset <= 0x07ff) + m_tx_tilemap->mark_tile_dirty(offset >> 1); + } +} + +void valtric_state::unknown_w(u8 data) +{ + m_valtric_unknown = data; +} + +void butasan_state::unknown_w(u8 data) +{ + m_butasan_unknown = data; +} + + +/*************************************************************************** + Screen refresh +***************************************************************************/ + +#define bg_scrollx(layer) (m_bg_scrollx[layer][0] | (m_bg_scrollx[layer][1] << 8)) +#define bg_scrolly(layer) (m_bg_scrolly[layer][0] | (m_bg_scrolly[layer][1] << 8)) + +void argus_common_state::bg_setting() +{ + machine().tilemap().set_flip_all(m_flipscreen ? TILEMAP_FLIPY|TILEMAP_FLIPX : 0); + + if (!m_flipscreen) + { + if (m_bg_tilemap[0] != nullptr) + { + if ((m_vrom[0] != nullptr) && (m_vrom[1] != nullptr)) + { + if (m_vrom_offset != m_bg_scrollx[0][1]) + { + m_vrom_offset = m_bg_scrollx[0][1]; + m_bg_tilemap[0]->mark_all_dirty(); + } + m_bg_tilemap[0]->set_scrollx(0, m_bg_scrollx[0][0]); + m_bg_tilemap[0]->set_scrolly(0, bg_scrolly(0)); + } + else + { + m_bg_tilemap[0]->set_scrollx(0, bg_scrollx(0)); + m_bg_tilemap[0]->set_scrolly(0, bg_scrolly(0)); + } + } + m_bg_tilemap[1]->set_scrollx(0, bg_scrollx(1) & 0x1ff); + m_bg_tilemap[1]->set_scrolly(0, bg_scrolly(1) & 0x1ff); + } + else + { + if (m_bg_tilemap[0] != nullptr) + { + if ((m_vrom[0] != nullptr) && (m_vrom[1] != nullptr)) + { + if (m_vrom_offset != ((m_bg_scrollx[0][1] + 1) & 0xff)) + { + m_vrom_offset = ((m_bg_scrollx[0][1] + 1) & 0xff); + m_bg_tilemap[0]->mark_all_dirty(); + } + m_bg_tilemap[0]->set_scrollx(0, m_bg_scrollx[0][0]); + m_bg_tilemap[0]->set_scrolly(0, (bg_scrolly(0) + 256)); + } + else + { + m_bg_tilemap[0]->set_scrollx(0, (bg_scrollx(0) + 256)); + m_bg_tilemap[0]->set_scrolly(0, (bg_scrolly(0) + 256)); + } + } + m_bg_tilemap[1]->set_scrollx(0, (bg_scrollx(1) + 256) & 0x1ff); + m_bg_tilemap[1]->set_scrolly(0, (bg_scrolly(1) + 256) & 0x1ff); + } +} + +void argus_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect, int priority) +{ + /* Draw the sprites */ + for (int offs = 0; offs < m_spriteram.bytes(); offs += 16) + { + if (!(m_spriteram[offs+15] == 0 && m_spriteram[offs+11] == 0xf0)) + { + int sx, sy, tile, flipx, flipy, color, pri; + + sx = m_spriteram[offs+12]; if (m_spriteram[offs+13] & 0x01) sx -= 256; + sy = m_spriteram[offs+11]; if (!(m_spriteram[offs+13] & 0x02)) sy -= 256; + + tile = m_spriteram[offs+14] | ((m_spriteram[offs+13] & 0xc0) << 2); + flipx = m_spriteram[offs+13] & 0x10; + flipy = m_spriteram[offs+13] & 0x20; + color = m_spriteram[offs+15] & 0x07; + pri = (m_spriteram[offs+15] & 0x08) >> 3; + + if (m_flipscreen) + { + sx = 240 - sx; + sy = 240 - sy; + flipx = !flipx; + flipy = !flipy; + } + + if (priority != pri) + m_blend->drawgfx( + *m_palette, + m_gfxdecode->gfx(0), + bitmap, cliprect, + tile, + color, + flipx, flipy, + sx, sy, + 15); + } + } +} + +#if 1 +void valtric_state::draw_mosaic(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_valtric_mosaic!=0x80) + { + m_mosaic=0x0f-(m_valtric_mosaic&0x0f); + if (m_mosaic!=0) m_mosaic++; + if (m_valtric_mosaic&0x80) m_mosaic*=-1; + } + + if (m_mosaic==0) + m_bg_tilemap[1]->draw(screen, bitmap, cliprect, 0, 0); + else + { + m_bg_tilemap[1]->draw(screen, m_mosaicbitmap, cliprect, 0, 0); + int step=m_mosaic; + int c=0; + int width = screen.width(); + int height = screen.height(); + + if (m_mosaic<0)step*=-1; + + for (int y=0;ydraw(screen, bitmap, cliprect, 0, 0); + else + { + m_bg_tilemap[1]->draw(screen, m_mosaicbitmap, cliprect, 0, 0); + int c=0; + int width = screen.width(); + int height = screen.height(); + + for (int y = 0; y < width+step; y += step) + for (int x = 0; x < height+step; x += step) + { + if (y < height && x < width) + c = m_mosaicbitmap.pix(y, x); + + if (m_valtric_mosaic & 0x80) + if (y+step-1 < height && x+step-1 < width) + c = m_mosaicbitmap.pix(y+step-1, x+step-1); + + for (int yy = 0; yy < step; yy++) + for (int xx = 0; xx < step; xx++) + { + if (xx+x < width && yy+y < height) + bitmap.pix(y+yy, x+xx) = c; + } + } + } +} +#endif + +void valtric_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* Draw the sprites */ + for (int offs = 0; offs < m_spriteram.bytes(); offs += 16) + { + if (!(m_spriteram[offs+15] == 0 && m_spriteram[offs+11] == 0xf0)) + { + int sx, sy, tile, flipx, flipy, color; + + sx = m_spriteram[offs+12]; if (m_spriteram[offs+13] & 0x01) sx -= 256; + sy = m_spriteram[offs+11]; if (!(m_spriteram[offs+13] & 0x02)) sy -= 256; + + tile = m_spriteram[offs+14] | ((m_spriteram[offs+13] & 0xc0) << 2); + flipx = m_spriteram[offs+13] & 0x10; + flipy = m_spriteram[offs+13] & 0x20; + color = m_spriteram[offs+15] & 0x0f; + + if (m_flipscreen) + { + sx = 240 - sx; + sy = 240 - sy; + flipx = !flipx; + flipy = !flipy; + } + + m_blend->drawgfx( + *m_palette, + m_gfxdecode->gfx(0), + bitmap, cliprect, + tile, + color, + flipx, flipy, + sx, sy, + 15); + } + } +} + +void butasan_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* Draw the sprites */ + for (int offs = 0; offs < m_spriteram.bytes(); offs += 16) + { + int sx, sy, tile, flipx, flipy, color; + int fx, fy; + + tile = m_spriteram[offs+14] | ((m_spriteram[offs+15] & 0x0f) << 8); + flipx = m_spriteram[offs+8] & 0x01; + flipy = m_spriteram[offs+8] & 0x04; + color = m_spriteram[offs+9] & 0x0f; + + sx = m_spriteram[offs+10]; + sy = m_spriteram[offs+12]; + + if (m_spriteram[offs+11] & 0x01) sx-=256; + if (m_spriteram[offs+13] & 0x01) sy-=256; + + sy = 240 - sy; + + if (m_flipscreen) + { + sx = 240 - sx; + sy = 240 - sy; + flipx = !flipx; + flipy = !flipy; + } + + fx = flipx; + fy = flipy; + + { + int i, j, td; + + if ((offs >= 0x100 && offs <= 0x2ff) || (offs >= 0x400 && offs <= 0x57f)) + { + m_blend->drawgfx( + *m_palette, + m_gfxdecode->gfx(0), + bitmap, cliprect, + tile, + color, + flipx, flipy, + sx, sy, + 7); + } + else if ((offs >= 0x000 && offs <= 0x0ff) || (offs >= 0x300 && offs <= 0x3ff)) + { + for (i = 0; i <= 1; i++) + { + td = (fx) ? (1 - i) : i; + + m_blend->drawgfx( + *m_palette, + m_gfxdecode->gfx(0), + bitmap, cliprect, + tile + td, + color, + flipx, flipy, + sx + i * 16, sy, + 7); + } + } + else if (offs >= 0x580 && offs <= 0x61f) + { + for (i = 0; i <= 1; i++) + { + for (j = 0; j <= 1; j++) + { + if (fy) + td = (fx) ? ((1 - i) * 2) + 1 - j : (1 - i) * 2 + j; + else + td = (fx) ? (i * 2) + 1 - j : i * 2 + j; + + m_blend->drawgfx( + *m_palette, + m_gfxdecode->gfx(0), + bitmap, cliprect, + tile + td, + color, + flipx, flipy, + sx + j * 16, sy - i * 16, + 7); + } + } + } + else if (offs >= 0x620 && offs <= 0x67f) + { + for (i = 0; i <= 3; i++) + { + for (j = 0; j <= 3; j++) + { + if (fy) + td = (fx) ? ((3 - i) * 4) + 3 - j : (3 - i) * 4 + j; + else + td = (fx) ? (i * 4) + 3 - j : i * 4 + j; + + m_blend->drawgfx( + *m_palette, + m_gfxdecode->gfx(0), + bitmap, cliprect, + tile + td, + color, + flipx, flipy, + sx + j * 16, sy - i * 16, + 7); + } + } + } + } + } +} + + +void butasan_state::log_vram() +{ +#ifdef MAME_DEBUG + int offs; + + if (machine().input().code_pressed(KEYCODE_M)) + { + u8 *spriteram = &m_spriteram[0]; + int i; + logerror("\nSprite RAM\n"); + logerror("---------------------------------------\n"); + logerror(" +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f\n"); + for (offs = 0; offs < m_spriteram.bytes(); offs += 16) + { + for (i = 0; i < 16; i++) + { + if (i == 0) + { + logerror("%04x : ", offs + 0xf000); + logerror("%02x ", spriteram[offs]); + } + else if (i == 7) + logerror("%02x ", spriteram[offs + 7]); + else if (i == 15) + logerror("%02x\n", spriteram[offs + 15]); + else + logerror("%02x ", spriteram[offs + i]); + } + } + logerror("\nColor RAM\n"); + logerror("---------------------------------------\n"); + logerror(" +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f\n"); + for (offs = 0; offs < 0xbf0; offs += 16) + { + for (i = 0; i < 16; i++) + { + if (i == 0) + { + logerror("%04x : ", offs + 0xc400); + logerror("%02x ", m_paletteram[offs]); + } + else if (i == 7) + logerror("%02x ", m_paletteram[offs + 7]); + else if (i == 15) + logerror("%02x\n", m_paletteram[offs + 15]); + else + logerror("%02x ", m_paletteram[offs + i]); + } + } + } +#endif +} + +u32 argus_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bg_setting(); + + m_bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, 0); + draw_sprites(bitmap, cliprect, 0); + if (m_bg_status & 1) /* Background enable */ + m_bg_tilemap[1]->draw(screen, bitmap, cliprect, 0, 0); + draw_sprites(bitmap, cliprect, 1); + m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0); + return 0; +} + +u32 valtric_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bg_setting(); + + if (m_bg_status & 1) /* Background enable */ + draw_mosaic(screen, bitmap, cliprect); + else + bitmap.fill(m_palette->black_pen(), cliprect); + draw_sprites(bitmap, cliprect); + m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0); + return 0; +} + +u32 butasan_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bg_setting(); + + if (m_bg_status & 1) /* Background enable */ + m_bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, 0); + else + bitmap.fill(m_palette->black_pen(), cliprect); + if (m_butasan_bg1_status & 1) m_bg_tilemap[1]->draw(screen, bitmap, cliprect, 0, 0); + draw_sprites(bitmap, cliprect); + m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0); + + log_vram(); + return 0; +} diff --git a/cores/argus/doc/fbneo_d_argus.cpp b/cores/argus/doc/fbneo_d_argus.cpp new file mode 100644 index 000000000..28c31eb70 --- /dev/null +++ b/cores/argus/doc/fbneo_d_argus.cpp @@ -0,0 +1,1765 @@ +// FB Alpha NMK Argus driver module +// Based on MAME driver by Yochizo + +#include "tiles_generic.h" +#include "burn_bitmap.h" +#include "z80_intf.h" +#include "burn_ym2203.h" +#include "burn_pal.h" + +static UINT8 *AllMem; +static UINT8 *AllRam; +static UINT8 *RamEnd; +static UINT8 *MemEnd; +static UINT8 *DrvZ80ROM0; +static UINT8 *DrvZ80ROM1; +static UINT8 *DrvGfxROM0; +static UINT8 *DrvGfxROM1; +static UINT8 *DrvGfxROM2; +static UINT8 *DrvGfxROM3; +static UINT8 *DrvGfxROM4; +static UINT8 *DrvGfxROM5; +static UINT8 *DrvZ80RAM0; +static UINT8 *DrvZ80RAM1; +static UINT8 *DrvPalRAM; +static UINT8 *DrvTxtRAM; +static UINT8 *DrvBgRAM0; +static UINT8 *DrvBgRAM1; +static UINT8 *DrvSprRAM; +static UINT8 *DrvBlendTable; +static UINT32 *DrvTransBuffer; + +static UINT32 *DrvPalette; +static UINT32 *DrvPalette32; +static UINT8 DrvRecalc; + +static INT32 nExtraCycles; + +static UINT16 palette_intensity; +static UINT8 bg_status; +static UINT8 bg1_status; +static UINT8 flipscreen; +static UINT8 soundlatch; +static UINT16 scrollx0; +static UINT16 scrolly0; +static UINT16 scrollx1; +static UINT16 scrolly1; +static UINT8 mosaic_data; +static INT32 auto_mosaic; +static UINT8 bankdata; +static INT32 rambank = -1; + +static UINT8 DrvJoy1[8]; +static UINT8 DrvJoy2[8]; +static UINT8 DrvJoy3[8]; +static UINT8 DrvDips[2]; +static UINT8 DrvInputs[3]; +static UINT8 DrvReset; + +static INT32 is_argus = 0; + +static struct BurnInputInfo ArgusInputList[] = { + {"P1 Coin", BIT_DIGITAL, DrvJoy1 + 7, "p1 coin" }, + {"P1 Start", BIT_DIGITAL, DrvJoy1 + 0, "p1 start" }, + {"P1 Up", BIT_DIGITAL, DrvJoy2 + 3, "p1 up" }, + {"P1 Down", BIT_DIGITAL, DrvJoy2 + 2, "p1 down" }, + {"P1 Left", BIT_DIGITAL, DrvJoy2 + 1, "p1 left" }, + {"P1 Right", BIT_DIGITAL, DrvJoy2 + 0, "p1 right" }, + {"P1 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p1 fire 1" }, + {"P1 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p1 fire 2" }, + + {"P2 Coin", BIT_DIGITAL, DrvJoy1 + 6, "p2 coin" }, + {"P2 Start", BIT_DIGITAL, DrvJoy1 + 1, "p2 start" }, + {"P2 Up", BIT_DIGITAL, DrvJoy3 + 3, "p2 up" }, + {"P2 Down", BIT_DIGITAL, DrvJoy3 + 2, "p2 down" }, + {"P2 Left", BIT_DIGITAL, DrvJoy3 + 1, "p2 left" }, + {"P2 Right", BIT_DIGITAL, DrvJoy3 + 0, "p2 right" }, + {"P2 Button 1", BIT_DIGITAL, DrvJoy3 + 4, "p2 fire 1" }, + {"P2 Button 2", BIT_DIGITAL, DrvJoy3 + 5, "p2 fire 2" }, + + {"Reset", BIT_DIGITAL, &DrvReset, "reset" }, + {"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" }, + {"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" }, +}; + +STDINPUTINFO(Argus) + +static struct BurnInputInfo ValtricInputList[] = { + {"P1 Coin", BIT_DIGITAL, DrvJoy1 + 6, "p1 coin" }, + {"P1 Start", BIT_DIGITAL, DrvJoy1 + 0, "p1 start" }, + {"P1 Up", BIT_DIGITAL, DrvJoy2 + 3, "p1 up" }, + {"P1 Down", BIT_DIGITAL, DrvJoy2 + 2, "p1 down" }, + {"P1 Left", BIT_DIGITAL, DrvJoy2 + 1, "p1 left" }, + {"P1 Right", BIT_DIGITAL, DrvJoy2 + 0, "p1 right" }, + {"P1 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p1 fire 1" }, + {"P1 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p1 fire 2" }, + + {"P2 Coin", BIT_DIGITAL, DrvJoy1 + 7, "p2 coin" }, + {"P2 Start", BIT_DIGITAL, DrvJoy1 + 1, "p2 start" }, + {"P2 Up", BIT_DIGITAL, DrvJoy3 + 3, "p2 up" }, + {"P2 Down", BIT_DIGITAL, DrvJoy3 + 2, "p2 down" }, + {"P2 Left", BIT_DIGITAL, DrvJoy3 + 1, "p2 left" }, + {"P2 Right", BIT_DIGITAL, DrvJoy3 + 0, "p2 right" }, + {"P2 Button 1", BIT_DIGITAL, DrvJoy3 + 4, "p2 fire 1" }, + {"P2 Button 2", BIT_DIGITAL, DrvJoy3 + 5, "p2 fire 2" }, + + {"Reset", BIT_DIGITAL, &DrvReset, "reset" }, + {"Service", BIT_DIGITAL, DrvJoy1 + 5, "service" }, + {"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" }, + {"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" }, +}; + +STDINPUTINFO(Valtric) + +static struct BurnInputInfo ButasanInputList[] = { + {"P1 Coin", BIT_DIGITAL, DrvJoy1 + 7, "p1 coin" }, + {"P1 Start", BIT_DIGITAL, DrvJoy1 + 0, "p1 start" }, + {"P1 Up", BIT_DIGITAL, DrvJoy2 + 3, "p1 up" }, + {"P1 Down", BIT_DIGITAL, DrvJoy2 + 2, "p1 down" }, + {"P1 Left", BIT_DIGITAL, DrvJoy2 + 1, "p1 left" }, + {"P1 Right", BIT_DIGITAL, DrvJoy2 + 0, "p1 right" }, + {"P1 Button 1", BIT_DIGITAL, DrvJoy2 + 4, "p1 fire 1" }, + {"P1 Button 2", BIT_DIGITAL, DrvJoy2 + 5, "p1 fire 2" }, + + {"P2 Coin", BIT_DIGITAL, DrvJoy1 + 6, "p2 coin" }, + {"P2 Start", BIT_DIGITAL, DrvJoy1 + 1, "p2 start" }, + {"P2 Up", BIT_DIGITAL, DrvJoy3 + 3, "p2 up" }, + {"P2 Down", BIT_DIGITAL, DrvJoy3 + 2, "p2 down" }, + {"P2 Left", BIT_DIGITAL, DrvJoy3 + 1, "p2 left" }, + {"P2 Right", BIT_DIGITAL, DrvJoy3 + 0, "p2 right" }, + {"P2 Button 1", BIT_DIGITAL, DrvJoy3 + 4, "p2 fire 1" }, + {"P2 Button 2", BIT_DIGITAL, DrvJoy3 + 5, "p2 fire 2" }, + + {"Reset", BIT_DIGITAL, &DrvReset, "reset" }, + {"Service", BIT_DIGITAL, DrvJoy1 + 5, "service" }, + {"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" }, + {"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" }, +}; + +STDINPUTINFO(Butasan) + +static struct BurnDIPInfo ArgusDIPList[]= +{ + {0x11, 0xff, 0xff, 0xcf, NULL }, + {0x12, 0xff, 0xff, 0xff, NULL }, + + {0 , 0xfe, 0 , 2, "Flip Screen" }, + {0x11, 0x01, 0x01, 0x01, "Off" }, + {0x11, 0x01, 0x01, 0x00, "On" }, + + {0 , 0xfe, 0 , 4, "Difficulty" }, + {0x11, 0x01, 0x06, 0x04, "Easy" }, + {0x11, 0x01, 0x06, 0x06, "Normal" }, + {0x11, 0x01, 0x06, 0x02, "Medium Difficult" }, + {0x11, 0x01, 0x06, 0x00, "Difficult" }, + + {0 , 0xfe, 0 , 2, "Free Play" }, + {0x11, 0x01, 0x08, 0x08, "Off" }, + {0x11, 0x01, 0x08, 0x00, "On" }, + + {0 , 0xfe, 0 , 2, "Cabinet" }, + {0x11, 0x01, 0x10, 0x00, "Upright" }, + {0x11, 0x01, 0x10, 0x10, "Cocktail" }, + + {0 , 0xfe, 0 , 2, "Demo Sounds" }, + {0x11, 0x01, 0x20, 0x20, "Off" }, + {0x11, 0x01, 0x20, 0x00, "On" }, + + {0 , 0xfe, 0 , 4, "Lives" }, + {0x11, 0x01, 0xc0, 0x80, "2" }, + {0x11, 0x01, 0xc0, 0xc0, "3" }, + {0x11, 0x01, 0xc0, 0x40, "4" }, + {0x11, 0x01, 0xc0, 0x00, "5" }, + + {0 , 0xfe, 0 , 8, "Coin B" }, + {0x12, 0x01, 0x1c, 0x00, "5 Coins 1 Credits" }, + {0x12, 0x01, 0x1c, 0x04, "4 Coins 1 Credits" }, + {0x12, 0x01, 0x1c, 0x08, "3 Coins 1 Credits" }, + {0x12, 0x01, 0x1c, 0x0c, "2 Coins 1 Credits" }, + {0x12, 0x01, 0x1c, 0x1c, "1 Coin 1 Credits" }, + {0x12, 0x01, 0x1c, 0x18, "1 Coin 2 Credits" }, + {0x12, 0x01, 0x1c, 0x14, "1 Coin 3 Credits" }, + {0x12, 0x01, 0x1c, 0x10, "1 Coin 4 Credits" }, + + {0 , 0xfe, 0 , 8, "Coin A" }, + {0x12, 0x01, 0xe0, 0x00, "5 Coins 1 Credits" }, + {0x12, 0x01, 0xe0, 0x20, "4 Coins 1 Credits" }, + {0x12, 0x01, 0xe0, 0x40, "3 Coins 1 Credits" }, + {0x12, 0x01, 0xe0, 0x60, "2 Coins 1 Credits" }, + {0x12, 0x01, 0xe0, 0xe0, "1 Coin 1 Credits" }, + {0x12, 0x01, 0xe0, 0xc0, "1 Coin 2 Credits" }, + {0x12, 0x01, 0xe0, 0xa0, "1 Coin 3 Credits" }, + {0x12, 0x01, 0xe0, 0x80, "1 Coin 4 Credits" }, +}; + +STDDIPINFO(Argus) + +static struct BurnDIPInfo ValtricDIPList[]= +{ + {0x12, 0xff, 0xff, 0xcf, NULL }, + {0x13, 0xff, 0xff, 0xff, NULL }, + + {0 , 0xfe, 0 , 2, "Flip Screen" }, + {0x12, 0x01, 0x01, 0x01, "Off" }, + {0x12, 0x01, 0x01, 0x00, "On" }, + + {0 , 0xfe, 0 , 4, "Difficulty" }, + {0x12, 0x01, 0x06, 0x06, "Normal" }, + {0x12, 0x01, 0x06, 0x04, "Medium Difficult" }, + {0x12, 0x01, 0x06, 0x02, "Difficult" }, + {0x12, 0x01, 0x06, 0x00, "Very Difficult" }, + + {0 , 0xfe, 0 , 2, "Free Play" }, + {0x12, 0x01, 0x08, 0x08, "Off" }, + {0x12, 0x01, 0x08, 0x00, "On" }, + + {0 , 0xfe, 0 , 2, "Cabinet" }, + {0x12, 0x01, 0x10, 0x00, "Upright" }, + {0x12, 0x01, 0x10, 0x10, "Cocktail" }, + + {0 , 0xfe, 0 , 2, "Demo Sounds" }, + {0x12, 0x01, 0x20, 0x20, "Off" }, + {0x12, 0x01, 0x20, 0x00, "On" }, + + {0 , 0xfe, 0 , 4, "Lives" }, + {0x12, 0x01, 0xc0, 0x00, "2" }, + {0x12, 0x01, 0xc0, 0xc0, "3" }, + {0x12, 0x01, 0xc0, 0x80, "4" }, + {0x12, 0x01, 0xc0, 0x40, "5" }, + + {0 , 0xfe, 0 , 2, "Invulnerability" }, + {0x13, 0x01, 0x01, 0x01, "Off" }, + {0x13, 0x01, 0x01, 0x00, "On" }, + + {0 , 0xfe, 0 , 8, "Coin B" }, + {0x13, 0x01, 0x1c, 0x00, "5 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x04, "4 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x08, "3 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x0c, "2 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x1c, "1 Coin 1 Credits" }, + {0x13, 0x01, 0x1c, 0x18, "1 Coin 2 Credits" }, + {0x13, 0x01, 0x1c, 0x14, "1 Coin 3 Credits" }, + {0x13, 0x01, 0x1c, 0x10, "1 Coin 4 Credits" }, + + {0 , 0xfe, 0 , 8, "Coin A" }, + {0x13, 0x01, 0xe0, 0x00, "5 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0x20, "4 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0x40, "3 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0x60, "2 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0xe0, "1 Coin 1 Credits" }, + {0x13, 0x01, 0xe0, 0xc0, "1 Coin 2 Credits" }, + {0x13, 0x01, 0xe0, 0xa0, "1 Coin 3 Credits" }, + {0x13, 0x01, 0xe0, 0x80, "1 Coin 4 Credits" }, +}; + +STDDIPINFO(Valtric) + +static struct BurnDIPInfo ButasanDIPList[]= +{ + {0x12, 0xff, 0xff, 0xff, NULL }, + {0x13, 0xff, 0xff, 0xff, NULL }, + + {0 , 0xfe, 0 , 2, "Free Play" }, + {0x12, 0x01, 0x01, 0x01, "Off" }, + {0x12, 0x01, 0x01, 0x00, "On" }, + + {0 , 0xfe, 0 , 2, "Invulnerability (Cheat)" }, + {0x12, 0x01, 0x02, 0x02, "Off" }, + {0x12, 0x01, 0x02, 0x00, "On" }, + + {0 , 0xfe, 0 , 4, "Lives" }, + {0x12, 0x01, 0x0c, 0x0c, "3" }, + {0x12, 0x01, 0x0c, 0x08, "4" }, + {0x12, 0x01, 0x0c, 0x04, "5" }, + {0x12, 0x01, 0x0c, 0x00, "6" }, + + {0 , 0xfe, 0 , 4, "Difficulty" }, + {0x12, 0x01, 0x30, 0x30, "Normal" }, + {0x12, 0x01, 0x30, 0x20, "Medium Difficult" }, + {0x12, 0x01, 0x30, 0x10, "Difficult" }, + {0x12, 0x01, 0x30, 0x00, "Very Difficult" }, + + {0 , 0xfe, 0 , 2, "Flip Screen" }, + {0x13, 0x01, 0x01, 0x01, "Off" }, + {0x13, 0x01, 0x01, 0x00, "On" }, + + {0 , 0xfe, 0 , 8, "Coin B" }, + {0x13, 0x01, 0x1c, 0x00, "5 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x04, "4 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x08, "3 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x0c, "2 Coins 1 Credits" }, + {0x13, 0x01, 0x1c, 0x1c, "1 Coin 1 Credits" }, + {0x13, 0x01, 0x1c, 0x18, "1 Coin 2 Credits" }, + {0x13, 0x01, 0x1c, 0x14, "1 Coin 3 Credits" }, + {0x13, 0x01, 0x1c, 0x10, "1 Coin 4 Credits" }, + + {0 , 0xfe, 0 , 8, "Coin A" }, + {0x13, 0x01, 0xe0, 0x00, "5 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0x20, "4 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0x40, "3 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0x60, "2 Coins 1 Credits" }, + {0x13, 0x01, 0xe0, 0xe0, "1 Coin 1 Credits" }, + {0x13, 0x01, 0xe0, 0xc0, "1 Coin 2 Credits" }, + {0x13, 0x01, 0xe0, 0xa0, "1 Coin 3 Credits" }, + {0x13, 0x01, 0xe0, 0x80, "1 Coin 4 Credits" }, +}; + +STDDIPINFO(Butasan) + +static void bankswitch(UINT8 data) +{ + INT32 bank = (data & 0x07) * 0x4000; + + bankdata = data; + + ZetMapMemory(DrvZ80ROM0 + 0x10000 + bank, 0x8000, 0xbfff, MAP_ROM); +} + +static UINT32 blend_color(UINT32 dest, UINT32 addme, UINT8 alpha) +{ + INT32 r = dest / 0x10000; + INT32 g = (dest / 0x100) & 0xff; + INT32 b = dest & 0xff; + + INT32 ir = addme / 0x10000; + INT32 ig = (addme / 0x100) & 0xff; + INT32 ib = addme & 0xff; + + if (alpha & 4) + { r -= ir; if (r < 0) r = 0; } + else + { r += ir; if (r > 255) r = 255; } + + if (alpha & 2) + { g -= ig; if (g < 0) g = 0; } + else + { g += ig; if (g > 255) g = 255; } + + if (alpha & 1) + { b -= ib; if (b < 0) b = 0; } + else + { b += ib; if (b > 255) b = 255; } + + return r * 0x10000 + g * 0x100 + b; +} + +static void change_palette(INT32 color, INT32 lo_offs, INT32 hi_offs) +{ + UINT8 lo = DrvPalRAM[lo_offs]; + UINT8 hi = DrvPalRAM[hi_offs]; + + DrvBlendTable[color] = hi & 0xf; + + UINT8 r = pal4bit(lo >> 4); + UINT8 g = pal4bit(lo); + UINT8 b = pal4bit(hi >> 4); + + DrvPalette[color] = BurnHighCol(r,g,b,0); + DrvPalette32[color] = r * 0x10000 + g * 0x100 + b; +} + +static void change_bg_palette(INT32 color, INT32 lo_offs, INT32 hi_offs) +{ + UINT8 ir = pal4bit(palette_intensity >> 12); + UINT8 ig = pal4bit(palette_intensity >> 8); + UINT8 ib = pal4bit(palette_intensity >> 4); + UINT8 ix = palette_intensity & 0x0f; + + UINT32 irgb = ir * 0x10000 + ig * 0x100 + ib; + + UINT8 lo = DrvPalRAM[lo_offs]; + UINT8 hi = DrvPalRAM[hi_offs]; + + UINT8 r = pal4bit(lo >> 4); + UINT8 g = pal4bit(lo); + UINT8 b = pal4bit(hi >> 4); + + UINT32 rgb = 0; + + if (bg_status & 2) + { + UINT8 val = (r + g + b) / 3; + rgb = val * 0x10000 + val * 0x100 + val; + } + else + { + rgb = r * 0x10000 + g * 0x100 + b; + } + + rgb = blend_color(rgb,irgb,ix); + + r = rgb / 0x10000; + g = rgb / 0x100; + b = rgb; + + DrvPalette[color] = BurnHighCol(r,g,b,0); + DrvPalette32[color] = rgb; +} + +static void argus_palette_write(UINT16 offset, UINT8 data) +{ + DrvPalRAM[offset] = data; + + if (offset <= 0x0ff) + { + offset &= 0x07f; + + change_palette(offset, offset, offset + 0x080); + + if (offset == 0x07f || offset == 0x0ff) + { + palette_intensity = DrvPalRAM[0x0ff] | (DrvPalRAM[0x07f] << 8); + + for (INT32 offs = 0; offs < 0x100; offs++) + change_bg_palette(offs + 0x100, offs + 0x400, offs + 0x800); + } + } + else if ((offset >= 0x400 && offset <= 0x4ff) || (offset >= 0x800 && offset <= 0x8ff)) + { + INT32 offs = offset & 0xff; + offset = offs | 0x400; + + change_bg_palette(offs + 0x100, offset, offset + 0x400); + } + else if ((offset >= 0x500 && offset <= 0x5ff) || (offset >= 0x900 && offset <= 0x9ff)) + { + INT32 offs = offset & 0xff; + offset = offs | 0x500; + + change_palette(offs + 0x200, offset, offset + 0x400); + } + else if ((offset >= 0x700 && offset <= 0x7ff) || (offset >= 0xb00 && offset <= 0xbff)) + { + INT32 offs = offset & 0xff; + offset = offs | 0x700; + + change_palette(offs + 0x300, offset, offset + 0x400); + } +} + +static void argus_bg_status_write(UINT8 data) +{ + if (bg_status != data) + { + bg_status = data; + + if (bg_status & 2) + { + for (INT32 offs = 0; offs < 0x100; offs++) + { + change_bg_palette(offs + 0x100, offs + 0x400, offs + 0x800); + } + } + } +} + +static void __fastcall argus_main_write(UINT16 address, UINT8 data) +{ + if (address >= 0xc400 && address <= 0xcfff) { + argus_palette_write(address - 0xc400, data); + return; + } + + switch (address) + { + case 0xc200: + soundlatch = data; + return; + + case 0xc201: + flipscreen = data & 0x80; + return; + + case 0xc202: + bankswitch(data); + return; + + case 0xc300: + case 0xc301: + scrollx0 = (scrollx0 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc302: + case 0xc303: + scrolly0 = (scrolly0 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc308: + case 0xc309: + scrollx1 = (scrollx1 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc30a: + case 0xc30b: + scrolly1 = (scrolly1 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc30c: + argus_bg_status_write(data); + return; + } +} + +static UINT8 __fastcall argus_main_read(UINT16 address) +{ + switch (address) + { + case 0xc000: + case 0xc001: + case 0xc002: + return DrvInputs[address & 3]; + + case 0xc003: + return DrvDips[0]; + + case 0xc004: + return DrvDips[1]; + } + + return 0; +} + +static void valtric_palette_write(UINT16 offset, UINT8 data) +{ + DrvPalRAM[offset] = data; + + if (offset <= 0x1ff) + { + change_palette(offset >> 1, offset & ~1, offset | 1); + + if (offset == 0x1fe || offset == 0x1ff) + { + palette_intensity = DrvPalRAM[0x1ff] | (DrvPalRAM[0x1fe] << 8); + + for (INT32 offs = 0x400; offs < 0x600; offs += 2) + change_bg_palette(((offs & 0x1ff) >> 1) + 0x100, offs & ~1, offs | 1); + } + } + else if (offset >= 0x400 && offset <= 0x5ff) + { + change_bg_palette(((offset & 0x1ff) >> 1) + 0x100, offset & ~1, offset | 1); + } + else if (offset >= 0x600 && offset <= 0x7ff) + { + change_palette(((offset & 0x1ff) >> 1) + 0x200, offset & ~1, offset | 1); + } +} + +static void valtric_bg_status_write(UINT8 data) +{ + if (bg_status != data) + { + bg_status = data; + + if (bg_status & 2) + { + for (INT32 offs = 0x400; offs < 0x600; offs += 2) + { + change_bg_palette(((offs - 0x400) >> 1) + 0x100, offs & ~1, offs | 1); + } + } + } +} + +static void __fastcall valtric_main_write(UINT16 address, UINT8 data) +{ + if (address >= 0xc400 && address <= 0xcfff) { + valtric_palette_write(address - 0xc400, data); + return; + } + + switch (address) + { + case 0xc30c: + valtric_bg_status_write(data); + return; + + case 0xc30d: + mosaic_data = data; + return; + } + + argus_main_write(address,data); +} + +static void butasan_palette_write(UINT16 offset, UINT8 data) +{ + DrvPalRAM[offset] = data; + + if (offset <= 0x1ff) /* BG0 color */ + { + change_palette((offset >> 1) + 0x100, offset & ~1, offset | 1); + } + else if (offset <= 0x23f) /* BG1 color */ + { + change_palette(((offset & 0x3f) >> 1) + 0x0c0, offset & ~1, offset | 1); + } + else if (offset >= 0x400 && offset <= 0x47f) /* Sprite color */ + { /* 16 colors */ + change_palette((offset & 0x7f) >> 1, offset & ~1, offset | 1); + } + else if (offset >= 0x480 && offset <= 0x4ff) /* Sprite color */ + { /* 8 colors */ + INT32 offs = (offset & 0x070) | ((offset & 0x00f) >> 1); + + change_palette(offs + 0x040, offset & ~1, offset | 1); + change_palette(offs + 0x048, offset & ~1, offset | 1); + } + else if (offset >= 0x600 && offset <= 0x7ff) /* Text color */ + { + change_palette(((offset & 0x1ff) >> 1) + 0x200, offset & ~1, offset | 1); + } + else if (offset >= 0x240 && offset <= 0x25f) // dummy + change_palette(((offset & 0x1f) >> 1) + 0xe0, offset & ~1, offset | 1); + else if (offset >= 0x500 && offset <= 0x51f) // dummy + change_palette(((offset & 0x1f) >> 1) + 0xf0, offset & ~1, offset | 1); +} + +static void rambankswitch(INT32 data) +{ + rambank = data & 1; + + if (rambank == 0) { + ZetMapMemory(DrvBgRAM0, 0xd000, 0xd7ff, MAP_RAM); + ZetMapMemory(DrvBgRAM0 + 0x800, 0xd800, 0xdfff, MAP_RAM); + } else { + ZetMapMemory(DrvTxtRAM, 0xd000, 0xd7ff, MAP_RAM); + ZetMapMemory(DrvTxtRAM + 0x800, 0xd800, 0xdfff, MAP_WRITE); + ZetMapMemory(DrvBgRAM0 + 0x800, 0xd800, 0xdfff, MAP_ROM); + } +} + +static void __fastcall butasan_main_write(UINT16 address, UINT8 data) +{ + if ((address & 0xf800) == 0xc800) { + butasan_palette_write(address & 0x7ff, data); + return; + } + + switch (address) + { + case 0xc100: + return; // unknown + + case 0xc200: + soundlatch = data; + return; + + case 0xc201: + flipscreen = data & 0x80; + return; + + case 0xc202: + bankswitch(data); + return; + + case 0xc203: + rambankswitch(data); + return; + + case 0xc300: + case 0xc301: + scrollx0 = (scrollx0 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc302: + case 0xc303: + scrolly0 = (scrolly0 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc308: + case 0xc309: + scrollx1 = (scrollx1 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc30a: + case 0xc30b: + scrolly1 = (scrolly1 & (0xff00 >> ((address & 1) * 8))) | (data << ((address & 1) * 8)); + return; + + case 0xc304: + bg_status = data; + return; + + case 0xc30c: + bg1_status = data; + return; + } +} + +static UINT8 __fastcall argus_sound_read(UINT16 /*address*/) +{ + return soundlatch; +} + +static void __fastcall argus_sound_write_port(UINT16 port, UINT8 data) +{ + switch (port & 0xff) + { + case 0x00: + case 0x01: + BurnYM2203Write(0, port & 1, data); + return; + + case 0x80: + case 0x81: + BurnYM2203Write(1, port & 1, data); + return; + } +} + +static UINT8 __fastcall argus_sound_read_port(UINT16 port) +{ + switch (port & 0xff) + { + case 0x00: + case 0x01: + return BurnYM2203Read(0, port & 1); + + case 0x80: + case 0x81: + return BurnYM2203Read(1, port & 1); + } + + return 0; +} + +static tilemap_callback( bg0 ) +{ + offs *= 2; + INT32 vrom_offset = (offs >> 3); + offs = (DrvGfxROM4[vrom_offset & ~1] << 4) | ((DrvGfxROM4[vrom_offset | 1] & 0x7) << 12) | (offs & 0xf); + + INT32 attr = DrvGfxROM5[offs + 1]; + INT32 code = DrvGfxROM5[offs + 0] | ((attr & 0xc0) << 2); + + TILE_SET_INFO(1, code, attr, TILE_FLIPYX(attr >> 4)); +} + +static tilemap_callback( bg1 ) +{ + INT32 attr = DrvBgRAM0[offs * 2 + 1]; + INT32 code = DrvBgRAM0[offs * 2 + 0] | ((attr & 0xc0) << 2); + + TILE_SET_INFO(2, code, attr, TILE_FLIPYX(attr >> 4)); +} + +static tilemap_callback( vbg ) +{ + INT32 attr = DrvBgRAM0[offs * 2 + 1]; + INT32 code = DrvBgRAM0[offs * 2 + 0] | ((attr & 0xc0) << 2) | ((attr & 0x20) << 5); + + TILE_SET_INFO(1, code, attr, 0); +} + +static tilemap_callback( txt ) +{ + INT32 attr = DrvTxtRAM[offs * 2 + 1]; + INT32 code = DrvTxtRAM[offs * 2 + 0] | ((attr & 0xc0) << 2); + + TILE_SET_INFO(0, code, attr, TILE_FLIPYX(attr >> 4)); +} + +static tilemap_callback( bbg0 ) +{ + INT32 attr = DrvBgRAM0[offs * 2 + 1]; + INT32 code = DrvBgRAM0[offs * 2 + 0] | ((attr & 0xc0) << 2); + + TILE_SET_INFO(1, code, attr, TILE_FLIPYX(attr >> 4)); +} + +static tilemap_callback( bbg1 ) +{ + INT32 code = DrvBgRAM1[offs] + ((bg1_status & 2) << 7); + + TILE_SET_INFO(2, code, code >> 7, 0); +} + +static tilemap_scan( bg ) +{ + return (col & 0x0f) | ((row ^ 0x0f) << 4) | ((col & 0x10) << 5); +} + +static tilemap_scan( tx ) +{ + return (col & 0x1f) | ((row ^ 0x1f) << 5); +} + +inline static void DrvYM2203IRQHandler(INT32, INT32 nStatus) +{ + ZetSetIRQLine(0, nStatus ? CPU_IRQSTATUS_ACK : CPU_IRQSTATUS_NONE); +} + +static INT32 DrvDoReset() +{ + memset (AllRam, 0, RamEnd - AllRam); + + ZetOpen(0); + bankswitch(0); + ZetReset(); + ZetClose(); + + ZetOpen(1); + ZetReset(); + BurnYM2203Reset(); + ZetClose(); + + palette_intensity = 0; + bg_status = 1; + bg1_status = 0; + flipscreen = 0; + soundlatch = 0; + scrollx0 = 0; + scrollx1 = 0; + scrolly0 = 0; + scrolly1 = 0; + mosaic_data = 0; + auto_mosaic = 0; + + nExtraCycles = 0; + + HiscoreReset(); + + return 0; +} + +static INT32 MemIndex() +{ + UINT8 *Next; Next = AllMem; + + DrvZ80ROM0 = Next; Next += 0x030000; + DrvZ80ROM1 = Next; Next += 0x010000; + + DrvGfxROM0 = Next; Next += 0x100000; + DrvGfxROM1 = Next; Next += 0x080000; + DrvGfxROM2 = Next; Next += 0x020000; + DrvGfxROM3 = Next; Next += 0x020000; + DrvGfxROM4 = Next; Next += 0x008000; + DrvGfxROM5 = Next; Next += 0x008000; + + DrvPalette = (UINT32*)Next; Next += 0x0400 * sizeof(UINT32); + + AllRam = Next; + + DrvZ80RAM0 = Next; Next += 0x002000; + DrvZ80RAM1 = Next; Next += 0x000800; + DrvPalRAM = Next; Next += 0x000c00; + DrvTxtRAM = Next; Next += 0x001000; + DrvBgRAM0 = Next; Next += 0x001000; + DrvBgRAM1 = Next; Next += 0x000800; + DrvSprRAM = Next; Next += 0x000700; + + DrvBlendTable = Next; Next += 0x000400; + + DrvPalette32 = (UINT32*)Next; Next += 0x0400 * sizeof(UINT32); + + DrvTransBuffer = (UINT32*)Next; Next += 512 * 512 * sizeof(UINT32); + + RamEnd = Next; + + MemEnd = Next; + + return 0; +} + +static INT32 DrvGfxDecode() +{ + INT32 Plane[4] = { STEP4(0,1) }; + INT32 XOffs[16] = { STEP8(0,4), STEP8(4*8*16, 4) }; + INT32 YOffs[16] = { STEP16(0,32) }; + + UINT8 *tmp = (UINT8*)BurnMalloc(0x80000); + if (tmp == NULL) { + return 1; + } + + memcpy (tmp, DrvGfxROM0, 0x80000); + + GfxDecode(0x1000, 4, 16, 16, Plane, XOffs, YOffs, 0x400, tmp, DrvGfxROM0); + + memcpy (tmp, DrvGfxROM1, 0x40000); + + GfxDecode(0x0800, 4, 16, 16, Plane, XOffs, YOffs, 0x400, tmp, DrvGfxROM1); + + memcpy (tmp, DrvGfxROM2, 0x20000); + + GfxDecode(0x0200, 4, 16, 16, Plane, XOffs, YOffs, 0x400, tmp, DrvGfxROM2); + + memcpy (tmp, DrvGfxROM3, 0x08000); + + GfxDecode(0x0400, 4, 8, 8, Plane, XOffs, YOffs, 0x100, tmp, DrvGfxROM3); + + BurnFree(tmp); + + return 0; +} + +static INT32 ArgusInit() +{ + BurnSetRefreshRate(54.00); + + BurnAllocMemIndex(); + + { + INT32 k = 0; + if (BurnLoadRom(DrvZ80ROM0 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x18000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x20000, k++, 1)) return 1; + + if (BurnLoadRom(DrvZ80ROM1 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM0 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x08000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x18000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM1 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x08000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x18000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM2 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM3 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM4 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM5 + 0x00000, k++, 1)) return 1; + + DrvGfxDecode(); + } + + ZetInit(0); + ZetOpen(0); + ZetMapMemory(DrvZ80ROM0, 0x0000, 0x7fff, MAP_ROM); + ZetMapMemory(DrvPalRAM, 0xc400, 0xcfff, MAP_ROM); // handler + ZetMapMemory(DrvTxtRAM, 0xd000, 0xd7ff, MAP_RAM); + ZetMapMemory(DrvBgRAM0, 0xd800, 0xdfff, MAP_RAM); + ZetMapMemory(DrvZ80RAM0, 0xe000, 0xffff, MAP_RAM); + ZetMapMemory(DrvSprRAM, 0xf200, 0xf7ff, MAP_RAM); + ZetSetWriteHandler(argus_main_write); + ZetSetReadHandler(argus_main_read); + ZetClose(); + + ZetInit(1); + ZetOpen(1); + ZetMapMemory(DrvZ80ROM1, 0x0000, 0x7fff, MAP_ROM); + ZetMapMemory(DrvZ80RAM1, 0x8000, 0x87ff, MAP_RAM); + ZetSetReadHandler(argus_sound_read); + ZetSetOutHandler(argus_sound_write_port); + ZetSetInHandler(argus_sound_read_port); + ZetClose(); + + BurnYM2203Init(2, 1500000, &DrvYM2203IRQHandler, 0); + BurnTimerAttachZet(5000000); + BurnYM2203SetRoute(0, BURN_SND_YM2203_YM2203_ROUTE, 0.50, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_1, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_2, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_3, 0.15, BURN_SND_ROUTE_BOTH); + // not used on this set + BurnYM2203SetRoute(1, BURN_SND_YM2203_YM2203_ROUTE, 0.00, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_1, 0.00, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_2, 0.00, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_3, 0.00, BURN_SND_ROUTE_BOTH); + + GenericTilesInit(); + GenericTilemapInit(0, TILEMAP_SCAN_COLS, txt_map_callback, 8, 8, 32, 32); + GenericTilemapInit(1, TILEMAP_SCAN_COLS, bg0_map_callback, 16, 16, 4096, 32); + GenericTilemapInit(2, TILEMAP_SCAN_COLS, bg1_map_callback, 16, 16, 32, 32); + GenericTilemapSetGfx(0, DrvGfxROM3, 4, 8, 8, 0x10000, 0x300, 0xf); + GenericTilemapSetGfx(1, DrvGfxROM1, 4, 16, 16, 0x40000, 0x100, 0xf); + GenericTilemapSetGfx(2, DrvGfxROM2, 4, 16, 16, 0x10000, 0x200, 0xf); + GenericTilemapSetTransparent(2, 0xf); + GenericTilemapSetTransparent(0, 0xf); + GenericTilemapSetOffsets(TMAP_GLOBAL, 0, -((256 - nScreenHeight) / 2)); + + is_argus = 1; + + DrvDoReset(); + + return 0; +} + +static INT32 ValtricInit() +{ + BurnSetRefreshRate(54.00); + + BurnAllocMemIndex(); + + { + INT32 k = 0; + if (BurnLoadRom(DrvZ80ROM0 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x20000, k++, 1)) return 1; + + if (BurnLoadRom(DrvZ80ROM1 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM0 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x10000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM1 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x20000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x30000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM3 + 0x00000, k++, 1)) return 1; + + DrvGfxDecode(); + } + + ZetInit(0); + ZetOpen(0); + ZetMapMemory(DrvZ80ROM0, 0x0000, 0x7fff, MAP_ROM); + ZetMapMemory(DrvPalRAM, 0xc400, 0xcfff, MAP_ROM); // handler + ZetMapMemory(DrvTxtRAM, 0xd000, 0xd7ff, MAP_RAM); + ZetMapMemory(DrvBgRAM0, 0xd800, 0xdfff, MAP_RAM); + ZetMapMemory(DrvZ80RAM0, 0xe000, 0xffff, MAP_RAM); + ZetMapMemory(DrvSprRAM, 0xf200, 0xf7ff, MAP_RAM); + ZetSetWriteHandler(valtric_main_write); + ZetSetReadHandler(argus_main_read); + ZetClose(); + + ZetInit(1); + ZetOpen(1); + ZetMapMemory(DrvZ80ROM1, 0x0000, 0x7fff, MAP_ROM); + ZetMapMemory(DrvZ80RAM1, 0x8000, 0x87ff, MAP_RAM); + ZetSetReadHandler(argus_sound_read); + ZetSetOutHandler(argus_sound_write_port); + ZetSetInHandler(argus_sound_read_port); + ZetClose(); + + BurnYM2203Init(2, 1500000, &DrvYM2203IRQHandler, 0); + BurnTimerAttachZet(5000000); + BurnYM2203SetRoute(0, BURN_SND_YM2203_YM2203_ROUTE, 0.50, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_1, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_2, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_3, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_YM2203_ROUTE, 0.50, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_1, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_2, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_3, 0.15, BURN_SND_ROUTE_BOTH); + + GenericTilesInit(); + GenericTilemapInit(0, TILEMAP_SCAN_COLS, txt_map_callback, 8, 8, 32, 32); + GenericTilemapInit(1, TILEMAP_SCAN_COLS, vbg_map_callback, 16, 16, 32, 32); + GenericTilemapSetGfx(0, DrvGfxROM3, 4, 8, 8, 0x10000, 0x200, 0xf); + GenericTilemapSetGfx(1, DrvGfxROM1, 4, 16, 16, 0x80000, 0x100, 0xf); + GenericTilemapSetTransparent(0, 0xf); + GenericTilemapSetOffsets(TMAP_GLOBAL, 0, -((256 - nScreenHeight) / 2)); + + DrvDoReset(); + + return 0; +} + +static INT32 ButasanInit() +{ + BurnSetRefreshRate(54.00); + + BurnAllocMemIndex(); + + { + INT32 k = 0; + if (BurnLoadRom(DrvZ80ROM0 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvZ80ROM0 + 0x20000, k++, 1)) return 1; + + if (BurnLoadRom(DrvZ80ROM1 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM0 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x10000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x20000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x30000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x40000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x50000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x60000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM0 + 0x70000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM1 + 0x00000, k++, 1)) return 1; + if (BurnLoadRom(DrvGfxROM1 + 0x10000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM2 + 0x00000, k++, 1)) return 1; + + if (BurnLoadRom(DrvGfxROM3 + 0x00000, k++, 1)) return 1; + + DrvGfxDecode(); + } + + ZetInit(0); + ZetOpen(0); + ZetMapMemory(DrvZ80ROM0, 0x0000, 0x7fff, MAP_ROM); + ZetMapMemory(DrvBgRAM1, 0xc400, 0xc7ff, MAP_RAM); + ZetMapMemory(DrvPalRAM, 0xc800, 0xcfff, MAP_ROM); // handler + ZetMapMemory(DrvZ80RAM0, 0xe000, 0xffff, MAP_RAM); + ZetMapMemory(DrvSprRAM, 0xf000, 0xf6ff, MAP_RAM); + ZetSetWriteHandler(butasan_main_write); + ZetSetReadHandler(argus_main_read); + ZetClose(); + + ZetInit(1); + ZetOpen(1); + ZetMapMemory(DrvZ80ROM1, 0x0000, 0xbfff, MAP_ROM); + ZetMapMemory(DrvZ80RAM1, 0xc000, 0xc7ff, MAP_RAM); + ZetSetReadHandler(argus_sound_read); + ZetSetOutHandler(argus_sound_write_port); + ZetSetInHandler(argus_sound_read_port); + ZetClose(); + + BurnYM2203Init(2, 1500000, &DrvYM2203IRQHandler, 0); + BurnTimerAttachZet(5000000); + BurnYM2203SetRoute(0, BURN_SND_YM2203_YM2203_ROUTE, 0.50, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_1, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_2, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(0, BURN_SND_YM2203_AY8910_ROUTE_3, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_YM2203_ROUTE, 0.50, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_1, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_2, 0.15, BURN_SND_ROUTE_BOTH); + BurnYM2203SetRoute(1, BURN_SND_YM2203_AY8910_ROUTE_3, 0.15, BURN_SND_ROUTE_BOTH); + + GenericTilesInit(); + GenericTilemapInit(0, tx_map_scan, txt_map_callback, 8, 8, 32, 32); + GenericTilemapInit(1, bg_map_scan, bbg0_map_callback, 16, 16, 32, 32); + GenericTilemapInit(2, bg_map_scan, bbg1_map_callback, 16, 16, 32, 32); + GenericTilemapSetGfx(0, DrvGfxROM3, 4, 8, 8, 0x10000, 0x200, 0xf); + GenericTilemapSetGfx(1, DrvGfxROM1, 4, 16, 16, 0x40000, 0x100, 0xf); + GenericTilemapSetGfx(2, DrvGfxROM2, 4, 16, 16, 0x20000, 0x0c0, 0x1); + GenericTilemapSetTransparent(0, 0xf); + GenericTilemapSetTransparent(2, 0xf); + GenericTilemapSetOffsets(TMAP_GLOBAL, 0, -((256 - nScreenHeight) / 2)); + + DrvDoReset(); + + return 0; +} + +static INT32 DrvExit() +{ + GenericTilesExit(); + + ZetExit(); + + BurnYM2203Exit(); + + BurnFreeMemIndex(); + + rambank = -1; + + is_argus = 0; + + return 0; +} + +static void DrvPaletteRecalc() +{ + for (INT32 i = 0; i < 0x400; i++) + { + UINT8 r = (DrvPalette32[i] / 0x10000) & 0xff; + UINT8 g = (DrvPalette32[i] / 0x100) & 0xff; + UINT8 b = DrvPalette32[i] & 0xff; + + DrvPalette[i] = BurnHighCol(r,g,b,0); + } +} + +static void draw_sprite_blend(INT32 bgmask, INT32 code, INT32 sx, INT32 sy, INT32 flipx, INT32 flipy, INT32 color, INT32 depth, INT32 mask, INT32 color_offset, UINT8 *gfx) +{ + gfx += (code * 16 * 16); + + color = (color << depth) + color_offset; + + INT32 flip = (flipx ? 0x0f : 0) | (flipy ? 0xf0 : 0); + + for (INT32 y = 0; y < 16; y++, sy++) + { + if (sy < 0 || sy >= nScreenHeight) continue; + + for (INT32 x = 0; x < 16; x++) + { + if ((sx + x) < 0 || (sx + x) >= nScreenWidth) continue; + + INT32 c = gfx[((y * 16) + x) ^ flip]; + + if (c != mask) + { + c += color; + INT32 dst = (sy * nScreenWidth) + sx + x; + + if (pTransDraw[dst] >= bgmask) continue; // Don't draw over text layer + + // Don't allow the title "mask" to get blitted over the background + if (is_argus && ((code >= 0x3f0 && code <= 0x3f8) || (code >= 0x3b6 && code <= 0x3bf) || + (code >= 0x3ac && code <= 0x3af)) && (~pTransDraw[dst] & 0x200)) + continue; + + UINT8 a = DrvBlendTable[c]; + + if (a & 8) + { + UINT32 d = blend_color(DrvTransBuffer[dst], DrvPalette32[c], a); + DrvTransBuffer[dst] = d; + PutPix(pBurnDraw + (dst * nBurnBpp), BurnHighCol((d/0x10000)&0xff, (d/0x100)&0xff, d&0xff, 0)); + } + else + { + DrvTransBuffer[dst] = DrvPalette32[c]; + PutPix(pBurnDraw + (dst * nBurnBpp), DrvPalette[c]); + } + } + } + } +} + +static void argus_draw_sprites(INT32 prio_mask, INT32 priority, INT32 color_mask) +{ + for (INT32 offs = 0; offs < 0x600; offs += 16) + { + if (!(DrvSprRAM[offs + 15] == 0 && DrvSprRAM[offs + 11] == 0xf0)) + { + INT32 sy = DrvSprRAM[offs + 11]; + INT32 sx = DrvSprRAM[offs + 12]; + INT32 attr = DrvSprRAM[offs + 13]; + INT32 code = DrvSprRAM[offs + 14] | ((attr & 0xc0) << 2); + INT32 color = DrvSprRAM[offs + 15] & color_mask; + INT32 pri = DrvSprRAM[offs + 15] & prio_mask; + INT32 flipx = attr & 0x10; + INT32 flipy = attr & 0x20; + if ( attr & 0x01) sx -= 256; + if (~attr & 0x02) sy -= 256; + + if ((priority != pri) && prio_mask) continue; + + if (priority == 8) pri = 0x200; + if (priority == 0) pri = 0x300; + + if (flipscreen) + { + sx = 240 - sx; + sy = 240 - sy; + flipx = !flipx; + flipy = !flipy; + } + + draw_sprite_blend(pri, code, sx, sy - 16, flipx, flipy, color, 4, 0xf, 0, DrvGfxROM0); + } + } +} + +static INT32 ArgusDraw() +{ + if (DrvRecalc) { + DrvPaletteRecalc(); + DrvRecalc = 0; + } + + GenericTilemapSetFlip(TMAP_GLOBAL, flipscreen ? (TMAP_FLIPX|TMAP_FLIPY) : 0); + GenericTilemapSetScrollX(1, scrollx0); + GenericTilemapSetScrollY(1, scrolly0); + GenericTilemapSetScrollX(2, scrollx1); + GenericTilemapSetScrollY(2, scrolly1); + + if (nBurnLayer & 1) { + UINT32 p = DrvPalette32[0x100]; + DrvPalette[0x100] = BurnHighCol(p/0x10000, (p/0x100)&0xff, p&0xff, 0); + GenericTilemapDraw(1, pTransDraw, 0); + } else { + DrvPalette[0x100] = 0; + BurnTransferClear(0x100); + } + + if ((nBurnLayer & 2) && (bg_status & 1)) { + GenericTilemapDraw(2, pTransDraw, 0); + } + + if (nBurnLayer & 4) { + GenericTilemapDraw(0, pTransDraw, 0); + } + + BurnTransferCopy(DrvPalette); + + // copy screen to 32bit alpha-trans buffer. yay! :) + for (INT32 sy = 0; sy < nScreenHeight; sy++) + for (INT32 sx = 0; sx < nScreenWidth; sx++) { + DrvTransBuffer[(sy * nScreenWidth) + sx] = DrvPalette32[pTransDraw[(sy * nScreenWidth) + sx]]; + } + + if (nSpriteEnable & 2) argus_draw_sprites(8, 8, 0x07); + if (nSpriteEnable & 1) argus_draw_sprites(8, 0, 0x07); + + return 0; +} + +static void draw_mosaic() +{ + if (mosaic_data != 0x80) + { + auto_mosaic = 0x0f - (mosaic_data & 0x0f); + if (auto_mosaic) auto_mosaic++; + if (mosaic_data & 0x80) auto_mosaic *= -1; + } + + GenericTilemapSetScrollX(1, scrollx1); + GenericTilemapSetScrollY(1, scrolly1); + + if (auto_mosaic == 0) + { + GenericTilemapDraw(1, pTransDraw, 0); + } + else + { + UINT16 *pTempDraw = (UINT16*)DrvTransBuffer; + GenericTilemapDraw(1, pTempDraw, 0); + + { + INT32 step = auto_mosaic; + + if (auto_mosaic < 0) step*=-1; + + for (INT32 y=0;y= 0 && (xx+x) < nScreenWidth && (yy+y) >= 0 && (yy+y) < nScreenHeight) + { + pTransDraw[((y+yy) * nScreenWidth) + (x+xx)] = c; + } + } + } + } + } + } + } +} + +static INT32 ValtricDraw() +{ + if (DrvRecalc) { + DrvPaletteRecalc(); + DrvRecalc = 0; + } + + GenericTilemapSetFlip(TMAP_GLOBAL, flipscreen ? (TMAP_FLIPX|TMAP_FLIPY) : 0); + + if ((nBurnLayer & 1) && (bg_status & 1)) { + DrvPalette[0x100] = 0; + draw_mosaic(); + } else { + UINT32 p = DrvPalette32[0x100]; + DrvPalette[0x100] = BurnHighCol(p/0x10000, (p/0x100)&0xff, p&0xff, 0); + BurnTransferClear(0x100); + } + + if (nBurnLayer & 4) { + GenericTilemapDraw(0, pTransDraw, 0); + } + + BurnTransferCopy(DrvPalette); + + // copy screen to 32bit alpha-trans buffer. yay! :) + for (INT32 sy = 0; sy < nScreenHeight; sy++) + for (INT32 sx = 0; sx < nScreenWidth; sx++) { + DrvTransBuffer[(sy * nScreenWidth) + sx] = DrvPalette32[pTransDraw[(sy * nScreenWidth) + sx]]; + } + + if (nSpriteEnable & 1) argus_draw_sprites(0,8,0xf); + + return 0; +} + +static void butasan_draw_sprites() +{ + for (INT32 offs = 0; offs < 0x680; offs += 16) + { + INT32 flipx = DrvSprRAM[offs + 8] & 0x01; + INT32 flipy = DrvSprRAM[offs + 8] & 0x04; + INT32 color = DrvSprRAM[offs + 9] & 0x0f; + INT32 sx = DrvSprRAM[offs + 10]; + INT32 sy = DrvSprRAM[offs + 12]; + INT32 code = DrvSprRAM[offs + 14] | ((DrvSprRAM[offs + 15] & 0x0f) << 8); + + if (DrvSprRAM[offs + 11] & 0x01) sx -= 256; + if (DrvSprRAM[offs + 13] & 0x01) sy -= 256; + + sy = 240 - sy; + + if (flipscreen) + { + sx = 240 - sx; + sy = 240 - sy; + flipx = !flipx; + flipy = !flipy; + } + + if ((offs >= 0x100 && offs <= 0x2ff) || (offs >= 0x400 && offs <= 0x57f)) + { + draw_sprite_blend(0x200, code, sx, sy, flipx, flipy, color, 4, 7, 0, DrvGfxROM0); + } + else if ((offs <= 0xff) || (offs >= 0x300 && offs <= 0x3ff)) + { + for (INT32 i = 0; i <= 1; i++) + { + INT32 td = (flipx) ? (1 - i) : i; + + draw_sprite_blend(0x200, code + td, sx + i * 16, sy, flipx, flipy, color, 4, 7, 0, DrvGfxROM0); + } + } + else if (offs >= 0x580 && offs <= 0x61f) + { + for (INT32 i = 0; i <= 1; i++) + { + for (INT32 j = 0; j <= 1; j++) + { + INT32 td; + if (flipy) + td = (flipx) ? ((1 - i) * 2) + 1 - j : (1 - i) * 2 + j; + else + td = (flipx) ? (i * 2) + 1 - j : i * 2 + j; + + draw_sprite_blend(0x200, code + td, sx + j * 16, sy - i * 16, flipx, flipy, color, 4, 7, 0, DrvGfxROM0); + } + } + } + else if (offs >= 0x620) + { + for (INT32 i = 0; i <= 3; i++) + { + for (INT32 j = 0; j <= 3; j++) + { + INT32 td; + if (flipy) + td = (flipx) ? ((3 - i) * 4) + 3 - j : (3 - i) * 4 + j; + else + td = (flipx) ? (i * 4) + 3 - j : i * 4 + j; + + draw_sprite_blend(0x200, code + td, sx + j * 16, sy - i * 16, flipx, flipy, color, 4, 7, 0, DrvGfxROM0); + } + } + } + } +} + +static INT32 ButasanDraw() +{ + if (DrvRecalc) { + DrvPaletteRecalc(); + DrvRecalc = 0; + } + + GenericTilemapSetFlip(TMAP_GLOBAL, flipscreen ? (TMAP_FLIPX|TMAP_FLIPY) : 0); + GenericTilemapSetScrollX(1, scrollx0); + GenericTilemapSetScrollY(1, scrolly0); + GenericTilemapSetScrollX(2, scrollx1); + GenericTilemapSetScrollY(2, scrolly1); + + if ((nBurnLayer & 1) && (bg_status & 1)) { + UINT32 p = DrvPalette32[0x100]; + DrvPalette[0x100] = BurnHighCol(p/0x10000, (p/0x100)&0xff, p&0xff, 0); + GenericTilemapDraw(1, pTransDraw, 0); + } else { + DrvPalette[0x100] = 0; + BurnTransferClear(); + } + + if ((nBurnLayer & 1) && (bg1_status & 1)) { + GenericTilemapDraw(1, pTransDraw, 0); + } + + if (nBurnLayer & 4) { + GenericTilemapDraw(0, pTransDraw, 0); + } + + BurnTransferCopy(DrvPalette); + + // copy screen to 32bit alpha-trans buffer. yay! :) + for (INT32 sy = 0; sy < nScreenHeight; sy++) + for (INT32 sx = 0; sx < nScreenWidth; sx++) { + DrvTransBuffer[(sy * nScreenWidth) + sx] = DrvPalette32[pTransDraw[(sy * nScreenWidth) + sx]]; + } + + if (nSpriteEnable & 1) butasan_draw_sprites(); + + return 0; +} + +static INT32 DrvFrame() +{ + if (DrvReset) { + DrvDoReset(); + } + + ZetNewFrame(); + + { + DrvInputs[0] = 0xff; + DrvInputs[1] = 0xff; + DrvInputs[2] = 0xff; + + for (INT32 i = 0; i < 8; i++) { + DrvInputs[0] ^= (DrvJoy1[i] & 1) << i; + DrvInputs[1] ^= (DrvJoy2[i] & 1) << i; + DrvInputs[2] ^= (DrvJoy3[i] & 1) << i; + } + } + + INT32 nInterleave = 256; + INT32 nCyclesTotal[2] = { 5000000 / 54, 5000000 / 54 }; + INT32 nCyclesDone[2] = { nExtraCycles, 0 }; + + INT32 irq1_line = ((256 - nScreenHeight) / 2); + INT32 irq2_line = (256 - ((256 - nScreenHeight) / 2)); + + for (INT32 i = 0; i < nInterleave; i++) + { + ZetOpen(0); + CPU_RUN(0, Zet); + if (i == irq1_line) { + ZetSetVector(0xcf); + ZetSetIRQLine(0, CPU_IRQSTATUS_HOLD); + } + if (i == irq2_line) { + ZetSetVector(0xd7); + ZetSetIRQLine(0, CPU_IRQSTATUS_HOLD); + + if (pBurnDraw) { + BurnDrvRedraw(); + } + } + ZetClose(); + + ZetOpen(1); + CPU_RUN_TIMER(1); + ZetClose(); + } + + if (pBurnSoundOut) { + BurnYM2203Update(pBurnSoundOut, nBurnSoundLen); + } + + nExtraCycles = nCyclesDone[0] - nCyclesTotal[0]; + + return 0; +} + +static INT32 DrvScan(INT32 nAction, INT32 *pnMin) +{ + struct BurnArea ba; + + if (pnMin) { + *pnMin = 0x029702; + } + + if (nAction & ACB_VOLATILE) { + memset(&ba, 0, sizeof(ba)); + + ba.Data = AllRam; + ba.nLen = RamEnd - AllRam; + ba.szName = "All Ram"; + BurnAcb(&ba); + + ZetScan(nAction); + BurnYM2203Scan(nAction, pnMin); + + SCAN_VAR(palette_intensity); + SCAN_VAR(bg_status); + SCAN_VAR(bg1_status); + SCAN_VAR(flipscreen); + SCAN_VAR(soundlatch); + SCAN_VAR(scrollx0); + SCAN_VAR(scrollx1); + SCAN_VAR(scrolly0); + SCAN_VAR(scrolly1); + SCAN_VAR(mosaic_data); + SCAN_VAR(auto_mosaic); + SCAN_VAR(bankdata); + SCAN_VAR(rambank); + + SCAN_VAR(nExtraCycles); + } + + if (nAction & ACB_WRITE) + { + ZetOpen(0); + bankswitch(bankdata); + if (rambank >= 0) rambankswitch(rambank); // butasan + ZetClose(); + } + + return 0; +} + + +// Argus + +static struct BurnRomInfo argusRomDesc[] = { + { "ag_02.bin", 0x8000, 0x278a3f3d, 1 | BRF_PRG | BRF_ESS }, // 0 Z80 #0 Code + { "ag_03.bin", 0x8000, 0x3a7f3bfa, 1 | BRF_PRG | BRF_ESS }, // 1 + { "ag_04.bin", 0x8000, 0x76adc9f6, 1 | BRF_PRG | BRF_ESS }, // 2 + { "ag_05.bin", 0x8000, 0xf76692d6, 1 | BRF_PRG | BRF_ESS }, // 3 + + { "ag_01.bin", 0x4000, 0x769e3f57, 2 | BRF_PRG | BRF_ESS }, // 4 Z80 #1 Code + + { "ag_09.bin", 0x8000, 0x6dbc1c58, 3 | BRF_GRA }, // 5 Sprite Tiles + { "ag_08.bin", 0x8000, 0xce6e987e, 3 | BRF_GRA }, // 6 + { "ag_07.bin", 0x8000, 0xbbb9638d, 3 | BRF_GRA }, // 7 + { "ag_06.bin", 0x8000, 0x655b48f8, 3 | BRF_GRA }, // 8 + + { "ag_13.bin", 0x8000, 0x20274268, 4 | BRF_GRA }, // 9 Background Tiles + { "ag_14.bin", 0x8000, 0xceb8860b, 4 | BRF_GRA }, // 10 + { "ag_11.bin", 0x8000, 0x99ce8556, 4 | BRF_GRA }, // 11 + { "ag_12.bin", 0x8000, 0xe0e5377c, 4 | BRF_GRA }, // 12 + + { "ag_17.bin", 0x8000, 0x0f12d09b, 5 | BRF_GRA }, // 13 Midground Tiles + + { "ag_10.bin", 0x4000, 0x2de696c4, 6 | BRF_GRA }, // 14 Character Tiles + + { "ag_15.bin", 0x8000, 0x99834c1b, 7 | BRF_GRA }, // 15 Background Tilemap Look-up Table + + { "ag_16.bin", 0x8000, 0x39a51714, 8 | BRF_GRA }, // 16 Background Tilemap +}; + +STD_ROM_PICK(argus) +STD_ROM_FN(argus) + +struct BurnDriver BurnDrvArgus = { + "argus", NULL, NULL, NULL, "1986", + "Argus\0", NULL, "NMK (Jaleco license)", "Miscellaneous", + NULL, NULL, NULL, NULL, + BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_HISCORE_SUPPORTED, 2, HARDWARE_MISC_PRE90S, GBF_VERSHOOT, 0, + NULL, argusRomInfo, argusRomName, NULL, NULL, NULL, NULL, ArgusInputInfo, ArgusDIPInfo, + ArgusInit, DrvExit, DrvFrame, ArgusDraw, DrvScan, &DrvRecalc, 0x380, + 224, 256, 3, 4 +}; + + +// Valtric + +static struct BurnRomInfo valtricRomDesc[] = { + { "vt_04.bin", 0x08000, 0x709c705f, 1 | BRF_PRG | BRF_ESS }, // 0 Z80 #0 Code + { "vt_06.bin", 0x10000, 0xc9cbb4e4, 1 | BRF_PRG | BRF_ESS }, // 1 + { "vt_05.bin", 0x10000, 0x7ab2684b, 1 | BRF_PRG | BRF_ESS }, // 2 + + { "vt_01.bin", 0x08000, 0x4616484f, 2 | BRF_PRG | BRF_ESS }, // 3 Z80 #1 Code + + { "vt_02.bin", 0x10000, 0x66401977, 3 | BRF_GRA }, // 4 Sprite Tiles + { "vt_03.bin", 0x10000, 0x9203bbce, 3 | BRF_GRA }, // 5 + + { "vt_08.bin", 0x10000, 0x661dd338, 4 | BRF_GRA }, // 6 Background Tiles + { "vt_09.bin", 0x10000, 0x085a35b1, 4 | BRF_GRA }, // 7 + { "vt_10.bin", 0x10000, 0x09c47323, 4 | BRF_GRA }, // 8 + { "vt_11.bin", 0x10000, 0x4cf800b5, 4 | BRF_GRA }, // 9 + + { "vt_07.bin", 0x04000, 0x4b9771ae, 5 | BRF_GRA }, // 10 Character Tiles + + { "82s129.1s", 0x00100, 0xbc42f9b5, 0 | BRF_OPT }, // 11 Unused PROMs +}; + +STD_ROM_PICK(valtric) +STD_ROM_FN(valtric) + +struct BurnDriver BurnDrvValtric = { + "valtric", NULL, NULL, NULL, "1986", + "Valtric\0", NULL, "NMK (Jaleco license)", "Miscellaneous", + NULL, NULL, NULL, NULL, + BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_HISCORE_SUPPORTED, 2, HARDWARE_MISC_PRE90S, GBF_VERSHOOT, 0, + NULL, valtricRomInfo, valtricRomName, NULL, NULL, NULL, NULL, ValtricInputInfo, ValtricDIPInfo, + ValtricInit, DrvExit, DrvFrame, ValtricDraw, DrvScan, &DrvRecalc, 0x300, + 224, 256, 3, 4 +}; + + +// Butasan - Pig's & Bomber's (Japan, English) + +static struct BurnRomInfo butasanRomDesc[] = { + { "4.t2", 0x08000, 0x1ba1d8e4, 1 | BRF_PRG | BRF_ESS }, // 0 Z80 #0 Code + { "3.s2", 0x10000, 0xa6b3ccc2, 1 | BRF_PRG | BRF_ESS }, // 1 + { "2.p2", 0x10000, 0x96517fa9, 1 | BRF_PRG | BRF_ESS }, // 2 + + { "1.b2", 0x10000, 0xc9d23e2d, 2 | BRF_PRG | BRF_ESS }, // 3 Z80 #1 Code + + { "16.k16", 0x10000, 0xe0ce51b6, 3 | BRF_GRA }, // 4 Sprite Tiles + { "15.k15", 0x10000, 0x2105f6e1, 3 | BRF_GRA }, // 5 + { "14.k14", 0x10000, 0x8ec891c1, 3 | BRF_GRA }, // 6 + { "13.k13", 0x10000, 0x5023e74d, 3 | BRF_GRA }, // 7 + { "12.k12", 0x10000, 0x44f59905, 3 | BRF_GRA }, // 8 + { "11.k11", 0x10000, 0xb8929f1d, 3 | BRF_GRA }, // 9 + { "10.k10", 0x10000, 0xfd4d3baf, 3 | BRF_GRA }, // 10 + { "9.k9", 0x10000, 0x7da4c0fd, 3 | BRF_GRA }, // 11 + + { "5.l7", 0x10000, 0xb8e026b0, 4 | BRF_GRA }, // 12 Background Tiles + { "6.n7", 0x10000, 0x8bbacb81, 4 | BRF_GRA }, // 13 + + { "7.a8", 0x10000, 0x3a48d531, 5 | BRF_GRA }, // 14 Midground Tiles + + { "8.a7", 0x08000, 0x85153252, 6 | BRF_GRA }, // 15 Character Tiles + + { "buta-01.prm", 0x00100, 0x45baedd0, 0 | BRF_OPT }, // 16 Unused PROMs + { "buta-02.prm", 0x00100, 0x0dcb18fc, 0 | BRF_OPT }, // 17 +}; + +STD_ROM_PICK(butasan) +STD_ROM_FN(butasan) + +struct BurnDriver BurnDrvButasan = { + "butasan", NULL, NULL, NULL, "1987", + "Butasan - Pig's & Bomber's (Japan, English)\0", NULL, "NMK (Jaleco license)", "Miscellaneous", + NULL, NULL, NULL, NULL, + BDF_GAME_WORKING | BDF_HISCORE_SUPPORTED, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0, + NULL, butasanRomInfo, butasanRomName, NULL, NULL, NULL, NULL, ButasanInputInfo, ButasanDIPInfo, + ButasanInit, DrvExit, DrvFrame, ButasanDraw, DrvScan, &DrvRecalc, 0x300, + 256, 240, 4, 3 +}; + + +// Butasan (Japan, Japanese) + +static struct BurnRomInfo butasanjRomDesc[] = { + { "buta-04.bin", 0x08000, 0x47ff4ca9, 1 | BRF_PRG | BRF_ESS }, // 0 Z80 #0 Code + { "buta-03.bin", 0x10000, 0x69fd88c7, 1 | BRF_PRG | BRF_ESS }, // 1 + { "buta-02.bin", 0x10000, 0x519dc412, 1 | BRF_PRG | BRF_ESS }, // 2 + + { "1.b2", 0x10000, 0xc9d23e2d, 2 | BRF_PRG | BRF_ESS }, // 3 Z80 #1 Code + + { "16.k16", 0x10000, 0xe0ce51b6, 3 | BRF_GRA }, // 4 Sprite Tiles + { "buta-15.bin", 0x10000, 0x3ed19daa, 3 | BRF_GRA }, // 5 + { "14.k14", 0x10000, 0x8ec891c1, 3 | BRF_GRA }, // 6 + { "13.k13", 0x10000, 0x5023e74d, 3 | BRF_GRA }, // 7 + { "12.k12", 0x10000, 0x44f59905, 3 | BRF_GRA }, // 8 + { "11.k11", 0x10000, 0xb8929f1d, 3 | BRF_GRA }, // 9 + { "10.k10", 0x10000, 0xfd4d3baf, 3 | BRF_GRA }, // 10 + { "9.k9", 0x10000, 0x7da4c0fd, 3 | BRF_GRA }, // 11 + + { "5.l7", 0x10000, 0xb8e026b0, 4 | BRF_GRA }, // 12 Background Tiles + { "6.n7", 0x10000, 0x8bbacb81, 4 | BRF_GRA }, // 13 + + { "7.a8", 0x10000, 0x3a48d531, 5 | BRF_GRA }, // 14 Midground Tiles + + { "buta-08.bin", 0x08000, 0x5d45ce9c, 6 | BRF_GRA }, // 15 Character Tiles + + { "buta-01.prm", 0x00100, 0x45baedd0, 0 | BRF_OPT }, // 16 Unused PROMs + { "buta-02.prm", 0x00100, 0x0dcb18fc, 0 | BRF_OPT }, // 17 +}; + +STD_ROM_PICK(butasanj) +STD_ROM_FN(butasanj) + +struct BurnDriver BurnDrvButasanj = { + "butasanj", "butasan", NULL, NULL, "1987", + "Butasan (Japan, Japanese)\0", NULL, "NMK (Jaleco license)", "Miscellaneous", + NULL, NULL, NULL, NULL, + BDF_GAME_WORKING | BDF_CLONE | BDF_HISCORE_SUPPORTED, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0, + NULL, butasanjRomInfo, butasanjRomName, NULL, NULL, NULL, NULL, ButasanInputInfo, ButasanDIPInfo, + ButasanInit, DrvExit, DrvFrame, ButasanDraw, DrvScan, &DrvRecalc, 0x300, + 256, 240, 4, 3 +}; diff --git a/cores/argus/hdl/jtargus_8x8x4_packed_msb.v b/cores/argus/hdl/jtargus_8x8x4_packed_msb.v new file mode 100644 index 000000000..667280a4c --- /dev/null +++ b/cores/argus/hdl/jtargus_8x8x4_packed_msb.v @@ -0,0 +1,27 @@ +module jtargus_8x8x4_packed_msb( + input [31:0] raw, + output [31:0] sorted +); + +assign sorted = { + raw[ 7],raw[ 3],raw[15],raw[11],raw[23],raw[19],raw[31],raw[27], + raw[ 6],raw[ 2],raw[14],raw[10],raw[22],raw[18],raw[30],raw[26], + raw[ 5],raw[ 1],raw[13],raw[ 9],raw[21],raw[17],raw[29],raw[25], + raw[ 4],raw[ 0],raw[12],raw[ 8],raw[20],raw[16],raw[28],raw[24] +}; + +endmodule + +module jtargus_obj_8x8x4_packed_msb( + input [31:0] raw, + output [31:0] sorted +); + +assign sorted = { + raw[27],raw[31],raw[19],raw[23],raw[11],raw[15],raw[ 3],raw[ 7], + raw[26],raw[30],raw[18],raw[22],raw[10],raw[14],raw[ 2],raw[ 6], + raw[25],raw[29],raw[17],raw[21],raw[ 9],raw[13],raw[ 1],raw[ 5], + raw[24],raw[28],raw[16],raw[20],raw[ 8],raw[12],raw[ 0],raw[ 4] +}; + +endmodule diff --git a/cores/argus/hdl/jtargus_bg0.v b/cores/argus/hdl/jtargus_bg0.v new file mode 100644 index 000000000..dc9aab6fd --- /dev/null +++ b/cores/argus/hdl/jtargus_bg0.v @@ -0,0 +1,179 @@ +module jtargus_bg0( + input rst, + input clk, + input pxl_cen, + input hs, + input blankn, + input flip, + input [ 8:0] vdump, + input [ 8:0] hdump, + input [ 9:0] scrx, + input [ 8:0] scry, + input [ 7:0] vrom_offset, + + output rom_cs, + output [16:2] rom_addr, + input [31:0] rom_data, + input rom_ok, + + output reg [14:1] vrom1_addr, + input [15:0] vrom1_data, + output reg vrom1_cs, + input vrom1_ok, + + output reg [14:1] vrom2_addr, + input [15:0] vrom2_data, + output reg vrom2_cs, + input vrom2_ok, + + output [ 7:0] pxl +); + +localparam [2:0] REQ_VROM1 = 3'd0, + WAIT_VROM1= 3'd1, + LATCH_VROM1=3'd2, + REQ_VROM2 = 3'd3, + WAIT_VROM2= 3'd4, + LATCH_VROM2=3'd5; + +wire [10:0] map_addr; +wire [31:0] sorted; +wire [15:0] cache_q; +wire [16:0] fill_tile = {fill_vrom,9'd0} + {6'd0,fill_addr}; +wire [17:0] fill_tile_byte = {fill_tile,1'b0}; +wire [14:1] fill_vrom1_addr = fill_tile_byte[17:4]; +wire [14:0] fill_pat_addr = {vrom1_l[10:8],vrom1_l[7:0],tile_byte_l[3:0]}; +wire [ 7:0] vrom2_lo = fill_pat_addr[0] ? vrom2_data[15:8] : vrom2_data[7:0]; +wire [ 7:0] vrom2_hi = vrom2_data[15:8]; +wire [15:0] cache_din = { vrom2_hi[5:0],vrom2_hi[7:6],vrom2_lo }; + +reg [15:0] vrom1_l; +reg [ 2:0] phase; +reg [10:0] fill_addr; +reg [10:0] cache_waddr; +reg [ 7:0] fill_vrom; +reg [17:0] tile_byte_l; +reg [15:0] cache_wdata; +reg cache_we; +wire [ 9:0] code = cache_q[9:0]; +wire [ 3:0] pal = cache_q[13:10]; +wire hflip = cache_q[14]; +wire vflip = cache_q[15]; + +jtargus_8x8x4_packed_msb u_conv( + .raw ( rom_data ), + .sorted ( sorted ) +); + +always @(posedge clk) begin + if( rst ) begin + phase <= REQ_VROM1; + vrom1_cs <= 1'b0; + vrom2_cs <= 1'b0; + vrom1_addr <= 14'd0; + vrom2_addr <= 14'd0; + vrom1_l <= 16'd0; + fill_addr <= 11'd0; + cache_waddr <= 11'd0; + fill_vrom <= 8'd0; + tile_byte_l <= 18'd0; + cache_wdata <= 16'd0; + cache_we <= 1'b0; + end else begin + vrom1_cs <= 1'b0; + vrom2_cs <= 1'b0; + cache_we <= 1'b0; + if( fill_vrom != vrom_offset ) begin + fill_vrom <= vrom_offset; + fill_addr <= 11'd0; + phase <= REQ_VROM1; + end else case( phase ) + REQ_VROM1: begin + tile_byte_l <= fill_tile_byte; + vrom1_addr <= fill_vrom1_addr; + phase <= WAIT_VROM1; + end + WAIT_VROM1: begin + vrom1_cs <= 1'b1; + phase <= LATCH_VROM1; + end + LATCH_VROM1: begin + vrom1_cs <= 1'b1; + if( vrom1_ok ) begin + vrom1_l <= vrom1_data; + vrom1_cs <= 1'b0; + phase <= REQ_VROM2; + end + end + REQ_VROM2: begin + vrom2_addr <= fill_pat_addr[14:1]; + phase <= WAIT_VROM2; + end + WAIT_VROM2: begin + vrom2_cs <= 1'b1; + phase <= LATCH_VROM2; + end + default: begin + vrom2_cs <= 1'b1; + if( vrom2_ok ) begin + cache_waddr <= fill_addr; + cache_wdata <= cache_din; + cache_we <= 1'b1; + vrom2_cs <= 1'b0; + fill_addr <= fill_addr + 11'd1; + phase <= REQ_VROM1; + end + end + endcase + end +end + +jtframe_dual_ram #( + .DW ( 16 ), + .AW ( 11 ) +) u_meta_cache( + .clk0 ( clk ), + .data0 ( 16'd0 ), + .addr0 ( map_addr ), + .we0 ( 1'b0 ), + .q0 ( cache_q ), + .clk1 ( clk ), + .data1 ( cache_wdata ), + .addr1 ( cache_waddr ), + .we1 ( cache_we ), + .q1 ( ) +); + +jtframe_scroll #( + .SIZE ( 16 ), + .VA ( 11 ), + .CW ( 10 ), + .PW ( 8 ), + .MAP_HW ( 10 ), + .MAP_VW ( 9 ), + .SCAN_COLS ( 1 ), + .HJUMP ( 0 ) +) u_scroll( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( hs ), + .vdump ( vdump ), + .hdump ( hdump ), + .blankn ( blankn ), + .flip ( flip ), + .scrx ( scrx ), + .scry ( scry ), + .vram_addr ( map_addr ), + .code ( code ), + .pal ( pal ), + .hflip ( hflip ), + .vflip ( vflip ), + .rom_addr ( rom_addr ), + .rom_data ( sorted ), + .rom_cs ( rom_cs ), + .rom_ok ( rom_ok ), + .pxl ( pxl ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_colmix.v b/cores/argus/hdl/jtargus_colmix.v new file mode 100644 index 000000000..1919a24e6 --- /dev/null +++ b/cores/argus/hdl/jtargus_colmix.v @@ -0,0 +1,120 @@ +module jtargus_colmix( + input clk, + input pxl_cen, + input blankn, + input bg1_en, + input [ 7:0] bg0_pxl, + input [ 7:0] bg1_pxl, + input [ 7:0] tx_pxl, + input [ 8:0] obj_pxl, + output reg [ 9:0] pal_pxl, + output reg [ 9:0] blend_bg_pxl, + output reg [ 9:0] blend_obj_pxl, + input [11:0] pal_rgb, + input [11:0] blend_bg_rgb, + input [11:0] blend_obj_rgb, + input [ 3:0] blend_alpha, + output reg [ 3:0] red, + output reg [ 3:0] green, + output reg [ 3:0] blue, + input [ 3:0] gfx_en +); + +wire bg0_opaque = bg0_pxl[3:0] != 4'hf; +wire bg1_opaque = bg1_en && bg1_pxl[3:0] != 4'hf; +wire tx_opaque = tx_pxl [3:0] != 4'hf; +wire obj_opaque = obj_pxl[3:0] != 4'hf; +wire obj_pri = obj_pxl[7]; +wire obj_mask = obj_pxl[8]; +wire obj_draw = obj_opaque && !(obj_mask && !bg1_opaque); +wire [9:0] bg0_pal = 10'h080 + {2'd0,bg0_pxl}; +wire [9:0] bg1_pal = 10'h180 + {2'd0,bg1_pxl}; +wire [9:0] tx_pal = 10'h280 + {2'd0,tx_pxl}; +wire [9:0] obj_pal = {3'd0,obj_pxl[6:0]}; + +reg blend_sel; +reg blend_sel_l, blankn_l; +reg [11:0] rgb_mux; + +initial begin + blend_sel_l = 1'b0; + blankn_l = 1'b0; +end + +function [3:0] sub4; + input [3:0] a; + input [3:0] b; +begin + sub4 = a>b ? a-b : 4'd0; +end +endfunction + +function [3:0] add4; + input [3:0] a; + input [3:0] b; + reg [4:0] sum; +begin + sum = {1'b0,a} + {1'b0,b}; + add4 = sum[4] ? 4'hf : sum[3:0]; +end +endfunction + +function [3:0] blend4; + input [3:0] bg; + input [3:0] obj; + input subtract; +begin + blend4 = subtract ? sub4(bg,obj) : add4(bg,obj); +end +endfunction + +function [11:0] blend_rgb; + input [11:0] bg; + input [11:0] obj; + input [ 3:0] alpha; +begin + blend_rgb[11:8] = blend4(bg[11:8], obj[11:8], alpha[2]); + blend_rgb[ 7:4] = blend4(bg[ 7:4], obj[ 7:4], alpha[1]); + blend_rgb[ 3:0] = blend4(bg[ 3:0], obj[ 3:0], alpha[0]); +end +endfunction + +always @* begin + pal_pxl = bg0_pal; + blend_bg_pxl = bg0_pal; + blend_obj_pxl = obj_pal; + blend_sel = 1'b0; + + if( gfx_en[0] && obj_draw && obj_pri ) begin + pal_pxl = obj_pal; + blend_bg_pxl = bg0_pal; + blend_sel = blend_alpha != 4'd0; + end + if( gfx_en[2] && bg1_opaque ) begin + pal_pxl = bg1_pal; + blend_sel = 1'b0; + end + if( gfx_en[0] && obj_draw && !obj_pri ) begin + pal_pxl = obj_pal; + blend_bg_pxl = (gfx_en[2] && bg1_opaque) ? bg1_pal : bg0_pal; + blend_sel = blend_alpha != 4'd0; + end + if( gfx_en[3] && tx_opaque ) begin + pal_pxl = tx_pal; + blend_sel = 1'b0; + end + if( !blankn ) begin + pal_pxl = 10'd0; + blend_sel = 1'b0; + end + + rgb_mux = blend_sel_l ? blend_rgb(blend_bg_rgb, blend_obj_rgb, blend_alpha) : pal_rgb; +end + +always @(posedge clk) if( pxl_cen ) begin + blend_sel_l <= blend_sel; + blankn_l <= blankn; + {red,green,blue} <= blankn_l ? rgb_mux : 12'd0; +end + +endmodule diff --git a/cores/argus/hdl/jtargus_game.v b/cores/argus/hdl/jtargus_game.v new file mode 100644 index 000000000..c307b1758 --- /dev/null +++ b/cores/argus/hdl/jtargus_game.v @@ -0,0 +1,189 @@ +/* Argus hardware implementation for JTFRAME. + + This file intentionally wires together existing JTFRAME/JTCORES building + blocks. The game-specific logic lives in the address decoder, palette + mapper, VROM lookup, and object scanner described by MAME. +*/ + +module jtargus_game( + `include "jtframe_game_ports.inc" +); + +wire irq8, irq10, flip, bg1_en, grey_en; +wire [ 7:0] snd_latch; +wire [ 9:0] bg0_scrx; +wire [ 8:0] bg0_scry, bg1_scrx, bg1_scry; +wire [ 7:0] bg0_vrom; +wire [ 7:0] st_snd; + +wire [11:0] pal_addr; +wire [ 7:0] pal_din; +wire pal_we; + +wire [ 9:0] pal_pxl; +wire [11:0] pal_rgb; +wire [ 9:0] blend_bg_pxl, blend_obj_pxl; +wire [11:0] blend_bg_rgb, blend_obj_rgb; +wire [ 3:0] blend_alpha; + +assign debug_view = debug_bus[7] ? st_snd : { grey_en, bg1_en, flip, snd_latch[4:0] }; +assign dip_flip = flip; +`ifdef JTFRAME_IOCTL_RD +assign ioctl_din = 8'd0; +`endif + +jtargus_main u_main( + .rst ( rst ), + .clk ( clk ), + .cen5 ( cen5 ), + .irq8 ( irq8 ), + .irq10 ( irq10 ), + + .cpu_dout ( cpu_dout ), + + .snd_latch ( snd_latch ), + .flip ( flip ), + .bg1_en ( bg1_en ), + .grey_en ( grey_en ), + .bg0_scrx ( bg0_scrx ), + .bg0_scry ( bg0_scry ), + .bg0_vrom ( bg0_vrom ), + .bg1_scrx ( bg1_scrx ), + .bg1_scry ( bg1_scry ), + + .ram_dout ( ram_dout ), + .ram_we ( ram_we ), + .tx_dout ( tx_dout ), + .tx_we ( tx_we ), + .bg1_dout ( bg1_dout ), + .bg1_we ( bg1_we ), + + .pal_addr ( pal_addr ), + .pal_din ( pal_din ), + .pal_we ( pal_we ), + + .main_addr ( main_addr ), + .main_data ( main_data ), + .main_cs ( main_cs ), + .main_ok ( main_ok ), + + .cab_1p ( cab_1p[1:0] ), + .coin ( coin[1:0] ), + .joystick1 ( joystick1 ), + .joystick2 ( joystick2 ), + .dipsw_a ( dipsw[ 7:0] ), + .dipsw_b ( dipsw[15:8] ), + .dip_pause ( dip_pause ) +); + +jtargus_sound u_sound( + .rst ( rst ), + .clk ( clk ), + .cen5 ( cen5 ), + .cen1p5 ( cen1p5 ), + + .snd_latch ( snd_latch ), + + .snd_addr ( snd_addr ), + .snd_data ( snd_data ), + .snd_cs ( snd_cs ), + .snd_ok ( snd_ok ), + + .fm ( fm ), + .psg ( psg ), + .st_dout ( st_snd ) +); + +jtargus_palette u_palette( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + + .addr ( pal_addr ), + .din ( pal_din ), + .we ( pal_we ), + .grey_en ( grey_en ), + + .pxl ( pal_pxl ), + .blend_bg_pxl ( blend_bg_pxl ), + .blend_obj_pxl( blend_obj_pxl ), + .rgb ( pal_rgb ), + .blend_bg_rgb ( blend_bg_rgb ), + .blend_obj_rgb( blend_obj_rgb ), + .blend_alpha ( blend_alpha ) +); + +jtargus_video u_video( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + + .flip ( flip ), + .bg1_en ( bg1_en ), + + .bg0_scrx ( bg0_scrx ), + .bg0_scry ( bg0_scry ), + .bg0_vrom ( bg0_vrom ), + .bg1_scrx ( bg1_scrx ), + .bg1_scry ( bg1_scry ), + + .tx_addr ( tx_vid_addr ), + .tx_data ( tx_vid_dout ), + .bg1_addr ( bg1_vid_addr ), + .bg1_data ( bg1_vid_dout ), + + .objram_addr( ram_obj_addr ), + .objram_data( ram_obj_dout ), + + .bg0_addr ( bg0_addr ), + .bg0_data ( bg0_data ), + .bg0_cs ( bg0_cs ), + .bg0_ok ( bg0_ok ), + + .bg1rom_addr( bg1_addr ), + .bg1rom_data( bg1_data ), + .bg1rom_cs ( bg1_cs ), + .bg1rom_ok ( bg1_ok ), + + .txt_addr ( txt_addr ), + .txt_data ( txt_data ), + .txt_cs ( txt_cs ), + .txt_ok ( txt_ok ), + + .obj_addr ( obj_addr ), + .obj_data ( obj_data ), + .obj_cs ( obj_cs ), + .obj_ok ( obj_ok ), + + .vrom1_addr ( vrom1_addr ), + .vrom1_data ( vrom1_data ), + .vrom1_cs ( vrom1_cs ), + .vrom1_ok ( vrom1_ok ), + .vrom2_addr ( vrom2_addr ), + .vrom2_data ( vrom2_data ), + .vrom2_cs ( vrom2_cs ), + .vrom2_ok ( vrom2_ok ), + + .pal_pxl ( pal_pxl ), + .pal_rgb ( pal_rgb ), + .blend_bg_pxl ( blend_bg_pxl ), + .blend_obj_pxl( blend_obj_pxl ), + .blend_bg_rgb ( blend_bg_rgb ), + .blend_obj_rgb( blend_obj_rgb ), + .blend_alpha ( blend_alpha ), + + .red ( red ), + .green ( green ), + .blue ( blue ), + .LHBL ( LHBL ), + .LVBL ( LVBL ), + .HS ( HS ), + .VS ( VS ), + .irq8 ( irq8 ), + .irq10 ( irq10 ), + + .gfx_en ( gfx_en ), + .debug_bus ( debug_bus ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_main.v b/cores/argus/hdl/jtargus_main.v new file mode 100644 index 000000000..465038f1b --- /dev/null +++ b/cores/argus/hdl/jtargus_main.v @@ -0,0 +1,237 @@ +module jtargus_main( + input rst, + input clk, + input cen5, + input irq8, + input irq10, + + output [ 7:0] cpu_dout, + + output reg [ 7:0] snd_latch, + output reg flip, + output bg1_en, + output grey_en, + output [ 9:0] bg0_scrx, + output [ 8:0] bg0_scry, + output [ 7:0] bg0_vrom, + output [ 8:0] bg1_scrx, + output [ 8:0] bg1_scry, + + input [ 7:0] ram_dout, + output ram_we, + + input [15:0] tx_dout, + output [ 1:0] tx_we, + + input [15:0] bg1_dout, + output [ 1:0] bg1_we, + + output [11:0] pal_addr, + output [ 7:0] pal_din, + output pal_we, + + output reg [17:0] main_addr, + input [ 7:0] main_data, + output reg main_cs, + input main_ok, + + input [ 1:0] cab_1p, + input [ 1:0] coin, + input [ 5:0] joystick1, + input [ 5:0] joystick2, + input [ 7:0] dipsw_a, + input [ 7:0] dipsw_b, + input dip_pause +); + +reg [ 7:0] cpu_din, cpu_mux, int_vector, bg_status, + sys_din, p1_din, p2_din; +reg [ 2:0] bank; +reg [ 7:0] bg0_x[0:1]; +reg [ 7:0] bg0_y[0:1]; +reg [ 7:0] bg1_x[0:1]; +reg [ 7:0] bg1_y[0:1]; +reg rst_n, irq_pending, irq8_l, irq10_l; +reg sys_cs, p1_cs, p2_cs, dswa_cs, dswb_cs, snd_cs, + flip_cs, bank_cs, scx0_cs, scy0_cs, scx1_cs, scy1_cs, + bgst_cs, pal_cs, tx_cs, bg1_cs, ram_cs; + +wire [15:0] A; +wire mreq_n, iorq_n, rd_n, wr_n, rfsh_n, m1_n, int_n; +wire macc, wr, rd, irq_ack; + +assign macc = !mreq_n && rfsh_n; +assign wr = macc && !wr_n; +assign rd = macc && !rd_n; +assign irq_ack = !m1_n && !iorq_n; + + +assign bg1_en = bg_status[0]; +assign grey_en = bg_status[1]; +assign bg0_scrx = {2'd0, bg0_x[0]}; +assign bg0_scry = {bg0_y[1][0] ^ flip, bg0_y[0]}; +assign bg0_vrom = bg0_x[1] + {7'd0, flip}; +assign bg1_scrx = {bg1_x[1][0] ^ flip, bg1_x[0]}; +assign bg1_scry = {bg1_y[1][0] ^ flip, bg1_y[0]}; + +assign ram_we = ram_cs && !wr_n; +assign tx_we = {2{tx_cs && !wr_n}} & { A[0], ~A[0] }; +assign bg1_we = {2{bg1_cs && !wr_n}} & { A[0], ~A[0] }; + +assign pal_addr = A[11:0] - 12'h400; +assign pal_din = cpu_dout; +assign pal_we = pal_cs && !wr_n; +assign int_n = ~(irq_pending&dip_pause); + +always @* begin + sys_cs = 1'b0; + p1_cs = 1'b0; + p2_cs = 1'b0; + dswa_cs = 1'b0; + dswb_cs = 1'b0; + snd_cs = 1'b0; + flip_cs = 1'b0; + bank_cs = 1'b0; + scx0_cs = 1'b0; + scy0_cs = 1'b0; + scx1_cs = 1'b0; + scy1_cs = 1'b0; + bgst_cs = 1'b0; + pal_cs = 1'b0; + tx_cs = 1'b0; + bg1_cs = 1'b0; + ram_cs = 1'b0; + main_cs = 1'b0; + main_addr = {2'b0,A}; + if( !rst && macc && A<16'hc000 ) begin + main_cs = 1'b1; + if( A[15] ) + main_addr = 18'h1_0000 + {1'b0, bank, A[13:0]}; + end + if (&A[15:14]) begin + if(rd) begin + case(A[2:0]) + 0: sys_cs = 1; + 1: p1_cs = 1; + 2: p2_cs = 1; + 3: dswa_cs= 1; + 4: dswb_cs= 1; + default:; + endcase + end + if(wr && A[9])begin + case(A[11:8]) + 2: case(A[7:0]) + 8'h00: snd_cs = 1; + 8'h01: flip_cs = 1; + 8'h02: bank_cs = 1; + default:; + endcase + 3: case(A[7:1]) + 7'h00: scx0_cs = 1; + 7'h01: scy0_cs = 1; + 7'h04: scx1_cs = 1; + 7'h05: scy1_cs = 1; + 7'h18: bgst_cs = 1; + default:; + endcase + default:; + endcase + end + if(macc) begin + pal_cs = A[13:12]==0 && A[11:10]!=0; + tx_cs = A[13:11]==3'b10; + bg1_cs = A[13:11]==3'b11; + ram_cs = A[13]; + end + end +end + +always @* begin + sys_din = { coin[0], coin[1], 4'hf, cab_1p }; + p1_din = { 2'b11, joystick1 }; + p2_din = { 2'b11, joystick2 }; + + cpu_mux = + !iorq_n ? int_vector : + main_cs ? main_data : + ram_cs ? ram_dout : + tx_cs ? (A[0] ? tx_dout[ 15:8] : tx_dout[ 7:0]) : + bg1_cs ? (A[0] ? bg1_dout[15:8] : bg1_dout[7:0]) : + sys_cs ? sys_din : + p1_cs ? p1_din : + p2_cs ? p2_din : + dswa_cs ? dipsw_a : + dswb_cs ? dipsw_b : + 8'hff; +end + +always @(posedge clk) begin + cpu_din <= cpu_mux; + rst_n <= ~rst; + irq8_l <= irq8; + irq10_l <= irq10; +end + +always @(posedge clk) begin + if( rst ) begin + bank <= 3'd0; + snd_latch <= 8'd0; + flip <= 1'b0; + bg_status <= 8'h01; + bg0_x[0] <= 8'd0; + bg0_x[1] <= 8'd0; + bg0_y[0] <= 8'd0; + bg0_y[1] <= 8'd0; + bg1_x[0] <= 8'd0; + bg1_x[1] <= 8'd0; + bg1_y[0] <= 8'd0; + bg1_y[1] <= 8'd0; + irq_pending <= 1'b0; + int_vector <= 8'hcf; + end else begin + if( irq_ack ) begin + irq_pending <= 1'b0; + end else if( irq8 && !irq8_l ) begin + irq_pending <= 1'b1; + int_vector <= 8'hcf; + end else if( irq10 && !irq10_l ) begin + irq_pending <= 1'b1; + int_vector <= 8'hd7; + end + + if( snd_cs ) snd_latch <= cpu_dout; + if( flip_cs ) flip <= cpu_dout[7]; + if( bank_cs ) bank <= cpu_dout[2:0]; + if( bgst_cs ) bg_status <= cpu_dout; + if( scx0_cs ) bg0_x[A[0]] <= cpu_dout; + if( scy0_cs ) bg0_y[A[0]] <= cpu_dout; + if( scx1_cs ) bg1_x[A[0]] <= cpu_dout; + if( scy1_cs ) bg1_y[A[0]] <= cpu_dout; + end +end + +jtframe_z80_romwait #(.CLR_INT(0),.RECOVERY(1)) u_cpu( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen5 ), + .cpu_cen ( ), + .int_n ( int_n ), + .nmi_n ( 1'b1 ), + .busrq_n ( 1'b1 ), + .m1_n ( m1_n ), + .mreq_n ( mreq_n ), + .iorq_n ( iorq_n ), + .rd_n ( rd_n ), + .wr_n ( wr_n ), + .rfsh_n ( rfsh_n ), + .halt_n ( ), + .busak_n ( ), + .A ( A ), + .din ( cpu_din ), + .dout ( cpu_dout ), + .rom_cs ( main_cs ), + .rom_ok ( main_ok ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_obj.v b/cores/argus/hdl/jtargus_obj.v new file mode 100644 index 000000000..0a9d4dd4d --- /dev/null +++ b/cores/argus/hdl/jtargus_obj.v @@ -0,0 +1,139 @@ +module jtargus_obj( + input rst, + input clk, + input pxl_cen, + input hs, + input blankn, + input flip, + input [ 8:0] hdump, + input [ 8:0] vrender, + + output reg [12:0] ram_addr, + input [ 7:0] ram_data, + + output rom_cs, + output [16:2] rom_addr, + input [31:0] rom_data, + input rom_ok, + + output [ 8:0] pxl +); + +localparam SPR_BASE = 13'h1200; + +reg hs_l, draw, visible; +reg [10:0] scan; +reg [ 3:0] state; +reg [ 7:0] sy_b, sx_b, attr_b, code_b, color_b; +reg [ 9:0] sx_eff, sy_eff; +reg [ 9:0] line; +reg [ 9:0] code; +reg [ 3:0] pal; +reg hflip, vflip, title_mask; +wire busy; +wire [31:0] sorted; +wire [12:0] scan_ext = {2'd0,scan}; +wire [ 9:0] code_next = {attr_b[7:6],code_b}; +// FBNeo skips these Argus title mask sprites over plain BG0. +wire title_mask_next = (code_next>=10'h3f0 && code_next<=10'h3f8) || + (code_next>=10'h3b6 && code_next<=10'h3bf) || + (code_next>=10'h3ac && code_next<=10'h3af); +wire [ 9:0] spr_line = flip ? {1'b0,vrender} + sy_eff - 10'd240 : {1'b0,vrender} - sy_eff; +wire vis_next = !(color_b==8'd0 && sy_b==8'hf0) && spr_line[9:4]==6'd0; +wire [ 3:0] ysub = line[3:0] ^ {4{vflip}}; + +jtargus_obj_8x8x4_packed_msb u_conv( + .raw ( rom_data ), + .sorted ( sorted ) +); + +always @(posedge clk) begin + if( rst ) begin + hs_l <= 1'b0; + scan <= 11'd0; + state <= 4'd0; + draw <= 1'b0; + ram_addr <= SPR_BASE; + title_mask <= 1'b0; + end else begin + hs_l <= hs; + draw <= 1'b0; + + if( hs && !hs_l ) begin + scan <= 11'd0; + state <= 4'd0; + ram_addr <= SPR_BASE + 13'd11; + end else if( blankn ) begin + case( state ) + 4'd0: begin ram_addr <= SPR_BASE + scan_ext + 13'd11; state <= 4'd1; end + 4'd1: begin ram_addr <= SPR_BASE + scan_ext + 13'd12; state <= 4'd2; end + 4'd2: begin sy_b <= ram_data; ram_addr <= SPR_BASE + scan_ext + 13'd13; state <= 4'd3; end + 4'd3: begin sx_b <= ram_data; ram_addr <= SPR_BASE + scan_ext + 13'd14; state <= 4'd4; end + 4'd4: begin attr_b <= ram_data; ram_addr <= SPR_BASE + scan_ext + 13'd15; state <= 4'd5; end + 4'd5: begin code_b <= ram_data; state <= 4'd6; end + 4'd6: begin + color_b <= ram_data; + sx_eff <= attr_b[0] ? {2'b11,sx_b} : {2'b00,sx_b}; + sy_eff <= attr_b[1] ? {2'b00,sy_b} : {2'b11,sy_b}; + state <= 4'd7; + end + 4'd7: begin + line <= spr_line; + visible <= vis_next; + code <= code_next; + title_mask <= title_mask_next; + pal <= {color_b[3],color_b[2:0]}; + hflip <= flip ? ~attr_b[4] : attr_b[4]; + vflip <= flip ? ~attr_b[5] : attr_b[5]; + if( flip ) + sx_eff <= 10'd240 - sx_eff; + state <= 4'd8; + end + 4'd8: begin + if( visible && !busy ) begin + draw <= 1'b1; + state <= 4'd9; + end else if( !visible || !busy ) begin + state <= 4'd9; + end + end + 4'd9: begin + if( scan>=11'h5f0 ) begin + state <= 4'd9; + end else begin + scan <= scan + 11'd16; + ram_addr <= SPR_BASE + scan_ext + 13'd16 + 13'd11; + state <= 4'd0; + end + end + default: state <= 4'd0; + endcase + end + end +end + +jtframe_objdraw #(.AW(9),.CW(10),.PW(9),.LATCH(1),.HJUMP(0),.HFIX(0),.ALPHA(9'h00f)) u_draw( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( hs ), + .flip ( 1'b0 ), + .hdump ( hdump ), + .draw ( draw ), + .busy ( busy ), + .code ( code ), + .xpos ( sx_eff[8:0] ), + .ysub ( ysub ), + .hzoom ( 6'd0 ), + .hz_keep ( 1'b0 ), + .hflip ( hflip ), + .vflip ( vflip ), + .pal ( {title_mask,pal} ), + .rom_addr ( rom_addr ), + .rom_cs ( rom_cs ), + .rom_ok ( rom_ok ), + .rom_data ( sorted ), + .pxl ( pxl ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_palette.v b/cores/argus/hdl/jtargus_palette.v new file mode 100644 index 000000000..fed206518 --- /dev/null +++ b/cores/argus/hdl/jtargus_palette.v @@ -0,0 +1,296 @@ +/* This file is part of JTCORES. + JTCORES program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JTCORES program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JTCORES. If not, see . + + Author: Rafael Eduardo Paiva Feener. Copyright: Miki Saito + Version: 1.0 + Date: 4-6-2026 + */ +module jtargus_palette( + input rst, + input clk, + input pxl_cen, + + input [11:0] addr, + input [ 7:0] din, + input we, + input grey_en, + + input [ 9:0] pxl, + input [ 9:0] blend_bg_pxl, + input [ 9:0] blend_obj_pxl, + output reg [11:0] rgb, + output reg [11:0] blend_bg_rgb, + output reg [11:0] blend_obj_rgb, + output reg [ 3:0] blend_alpha +); + +reg [15:0] raw_pal, intensity; +reg [11:0] pal0_addr, pal1_addr, pre0_addr, pre1_addr; +reg [ 9:0] base_addr, pxl_l, blend_bg_pxl_l, blend_obj_pxl_l, + pxl_rd_addr; +reg [ 7:0] din_l; +wire [ 7:0] pal0_dout, pal1_dout; +reg pal0_we, pal1_we, base_we, pxlram_we, + sprb_we, int_we; +reg [ 1:0] rd_st; +reg [15:0] pxlram_din; +wire [15:0] pxlram_dout; +reg cen; + +localparam [1:0] ST_IDLE = 2'd0, + ST_PAL = 2'd1, + ST_BG = 2'd2, + ST_OBJ = 2'd3; + +localparam [9:0] BG0_OFF = 10'h080, + BG1_OFF = 10'h180, + TXT_OFF = 10'h280; + +always @(posedge clk) begin + cen <= ~cen; + if(pxl_cen) cen <= 0; +end + +initial begin + cen = 0; + int_we = 0; + sprb_we = 0; + base_we = 0; + din_l = 0; + base_addr = 0; + pxl_l = 0; + blend_bg_pxl_l = 0; + blend_obj_pxl_l = 0; + pxl_rd_addr = 0; + pal0_addr = 0; + pal1_addr = 0; + pal0_we = 0; + pal1_we = 0; + pxlram_we = 0; + pxlram_din = 0; + rd_st = ST_IDLE; + rgb = 0; + blend_bg_rgb = 0; + blend_obj_rgb = 0; + blend_alpha = 0; + base_addr = 0; +end + +function [3:0] sub4; + input [3:0] a; + input [3:0] b; +begin + sub4 = a>b ? a-b : 4'd0; +end +endfunction + +function [3:0] add4; + input [3:0] a; + input [3:0] b; + reg [4:0] sum; +begin + sum = {1'b0,a} + {1'b0,b}; + add4 = sum[4] ? 4'hf : sum[3:0]; +end +endfunction + +function [3:0] blend4; + input [3:0] rgb; + input [3:0] delta; + input subtract; +begin + blend4 = subtract ? sub4(rgb,delta) : add4(rgb,delta); +end +endfunction + +function [3:0] avg3; + input [3:0] r; + input [3:0] g; + input [3:0] b; + reg [5:0] sum; + reg [5:0] avg; +begin + sum = {2'b0,r} + {2'b0,g} + {2'b0,b}; + avg = sum / 6'd3; + avg3 = avg[3:0]; +end +endfunction + +function [11:0] bg_effect; + input [11:0] src; + reg [11:0] tmp; + reg [ 3:0] grey; +begin + tmp = src; + if( grey_en ) begin + grey = avg3(tmp[11:8], tmp[7:4], tmp[3:0]); + tmp = { grey, grey, grey }; + end + tmp[11:8] = blend4(tmp[11:8], intensity[15:12], intensity[2]); + tmp[ 7:4] = blend4(tmp[ 7:4], intensity[11: 8], intensity[1]); + tmp[ 3:0] = blend4(tmp[ 3:0], intensity[ 7: 4], intensity[0]); + bg_effect = tmp; +end +endfunction + +function [11:0] lookup_rgb; + input [9:0] addr; + input [11:0] raw; +begin + lookup_rgb = ~addr[9] & addr[8]^addr[7] ? bg_effect(raw) : raw; // only applies to bg0 +end +endfunction + +always @* begin + pre0_addr = addr; + pre1_addr = addr; + + if(addr[11:8]==0) begin + pre0_addr[7] = 0; + pre1_addr[7] = 1; + end + + if(^addr[11:10]) begin + pre0_addr[11:10] = 2'b01; + pre1_addr[11:10] = 2'b10; + end + raw_pal = { pal0_dout, pal1_dout }; + if(pal0_we) raw_pal[15:8] = din_l; + if(pal1_we) raw_pal[ 7:0] = din_l; +end + +always @(posedge clk) begin + int_we <= 0; + sprb_we <= 0; + base_we <= 0; + pal0_we <= 0; + pal1_we <= 0; + pxlram_we <= base_we; + din_l <= din; + + if(we) begin + pal0_addr <= pre0_addr; + pal1_addr <= pre1_addr; + pal0_we <= addr[11:7]==pre0_addr[11:7]; + pal1_we <= addr[11:7]==pre1_addr[11:7]; + case (addr[11:8]) + 0: begin // Sprites + base_addr <= {3'd0,addr[6:0]}; + base_we <= 1; + sprb_we <= 1; + int_we <= &addr[6:0]; + end + 4,8: begin // BG0 + base_we <= 1; + base_addr <= {2'd0,addr[7:0]} + BG0_OFF; + end + 5,9: begin // BG1 + base_we <= 1; + base_addr <= {2'd0,addr[7:0]} + BG1_OFF; + end + 7,11: begin // TXT + base_we <= 1; + base_addr <= {2'd0,addr[7:0]} + TXT_OFF; + end + default:; + endcase + end +end + +always @( posedge clk) begin + if( rst ) begin + rd_st <= ST_IDLE; + intensity <= 16'd0; + pxl_l <= 10'd0; + blend_bg_pxl_l <= 10'd0; + blend_obj_pxl_l <= 10'd0; + pxl_rd_addr <= 10'd0; + rgb <= 12'd0; + blend_bg_rgb <= 12'd0; + blend_obj_rgb <= 12'd0; + blend_alpha <= 4'd0; + pxlram_din <= 16'b0; + end else begin + if(int_we) intensity <= raw_pal; + if(base_we) begin + pxlram_din <= raw_pal; + if(!sprb_we) pxlram_din[3:0] <= 4'd0; + end + + if(pxl_cen) begin + pxl_l <= pxl; + blend_bg_pxl_l <= blend_bg_pxl; + blend_obj_pxl_l <= blend_obj_pxl; + pxl_rd_addr <= pxl; + rd_st <= ST_PAL; + end else if(cen) begin + case(rd_st) + ST_PAL: begin + rgb <= lookup_rgb(pxl_l, pxlram_dout[15:4]); + pxl_rd_addr <= blend_bg_pxl_l; + rd_st <= ST_BG; + end + ST_BG: begin + blend_bg_rgb <= lookup_rgb(blend_bg_pxl_l, pxlram_dout[15:4]); + pxl_rd_addr <= blend_obj_pxl_l; + rd_st <= ST_OBJ; + end + ST_OBJ: begin + blend_obj_rgb <= pxlram_dout[15:4]; + blend_alpha <= pxlram_dout[ 3:0]; + rd_st <= ST_IDLE; + end + default: begin + rd_st <= ST_IDLE; + end + endcase + end + end +end + +jtframe_dual_ram #( + .AW(12) +) u_palram( + // Port 0 - pal lo + .clk0 ( clk ), + .addr0 ( pal0_addr ), + .data0 ( din_l ), + .we0 ( pal0_we ), + .q0 ( pal0_dout ), + // Port 1 - pal hi + .clk1 ( clk ), + .data1 ( din_l ), + .addr1 ( pal1_addr ), + .we1 ( pal1_we ), + .q1 ( pal1_dout ) +); + +jtframe_dual_ram #( + .DW(16), .AW(10) +) u_pxlram( + // Port 0 - CPU palette writes + .clk0 ( clk ), + .addr0 ( base_addr ), + .data0 ( pxlram_din ), + .we0 ( pxlram_we ), + .q0 ( ), + // Port 1 - sequenced video reads + .clk1 ( clk ), + .data1 ( 16'b0 ), + .addr1 ( pxl_rd_addr ), + .we1 ( 1'b0 ), + .q1 ( pxlram_dout ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_scroll.v b/cores/argus/hdl/jtargus_scroll.v new file mode 100644 index 000000000..5c20cf61c --- /dev/null +++ b/cores/argus/hdl/jtargus_scroll.v @@ -0,0 +1,83 @@ +module jtargus_scroll #( + parameter CW=10, + parameter TEXT=0 +)( + input rst, + input clk, + input pxl_cen, + input hs, + input blankn, + input flip, + input [ 8:0] vdump, + input [ 8:0] hdump, + input [ 8:0] scrx, + input [ 8:0] scry, + + output [ 9:0] ram_addr, + input [15:0] ram_data, + + output rom_cs, + output [14:2] rom_addr, + input [31:0] rom_data, + input rom_ok, + + output [ 7:0] pxl +); + +localparam SIZE = TEXT ? 8 : 16; +localparam MAP_HW = TEXT ? 8 : 9; +localparam MAP_VW = TEXT ? 8 : 9; +localparam VA = 10; +localparam PW = 8; + +wire [31:0] sorted; +wire [CW-1:0] code; +wire [ 9:0] ram_code = {ram_data[15:14],ram_data[7:0]}; +wire [MAP_HW-1:0] scrx_eff = scrx[MAP_HW-1:0]; +wire [MAP_VW-1:0] scry_eff = scry[MAP_VW-1:0]; +wire [ 3:0] pal; +wire hflip, vflip; + +assign code = ram_code[CW-1:0]; +assign pal = ram_data[11:8]; +assign hflip = ram_data[12]; +assign vflip = ram_data[13]; + +jtargus_8x8x4_packed_msb u_conv_argus( + .raw ( rom_data ), + .sorted ( sorted ) +); + +jtframe_scroll #( + .SIZE ( SIZE ), + .VA ( VA ), + .CW ( CW ), + .PW ( PW ), + .MAP_HW ( MAP_HW ), + .MAP_VW ( MAP_VW ), + .SCAN_COLS ( 1 ), + .HJUMP ( 0 ) +) u_scroll( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( hs ), + .vdump ( vdump ), + .hdump ( hdump ), + .blankn ( blankn ), + .flip ( flip ), + .scrx ( scrx_eff ), + .scry ( scry_eff ), + .vram_addr ( ram_addr ), + .code ( code ), + .pal ( pal ), + .hflip ( hflip ), + .vflip ( vflip ), + .rom_addr ( rom_addr ), + .rom_data ( sorted ), + .rom_cs ( rom_cs ), + .rom_ok ( rom_ok ), + .pxl ( pxl ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_sound.v b/cores/argus/hdl/jtargus_sound.v new file mode 100644 index 000000000..03ece473a --- /dev/null +++ b/cores/argus/hdl/jtargus_sound.v @@ -0,0 +1,96 @@ +module jtargus_sound( + input rst, + input clk, + input cen5, + input cen1p5, + + input [ 7:0] snd_latch, + + output [15:0] snd_addr, + input [ 7:0] snd_data, + output reg snd_cs, + input snd_ok, + + output signed [15:0] fm, + output [ 9:0] psg, + output [ 7:0] st_dout +); + +wire [15:0] A; +wire [ 7:0] cpu_dout, ram_dout, ym_dout; +reg [ 7:0] cpu_din; +wire mreq_n, iorq_n, rd_n, wr_n, rfsh_n; +wire ym_cs, ram_cs, latch_cs, int_n; +reg rst_n; + +assign snd_addr = A; +assign ram_cs = !mreq_n && rfsh_n && A>=16'h8000 && A<=16'h87ff; +assign latch_cs = !mreq_n && rfsh_n && A==16'hc000; +assign ym_cs = !iorq_n && !A[7] && (A[1:0]==2'b00 || A[1:0]==2'b01); +assign st_dout = { int_n, ym_cs, latch_cs, snd_latch[4:0] }; + +always @* begin + snd_cs = !rst && !mreq_n && rfsh_n && A[15]==1'b0; + cpu_din = + ym_cs ? ym_dout : + snd_cs ? snd_data : + ram_cs ? ram_dout : + latch_cs ? snd_latch : + 8'hff; +end + +always @(posedge clk) rst_n <= ~rst; + +jtframe_sysz80 #(.RAM_AW(11),.RECOVERY(1)) u_cpu( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen5 ), + .cpu_cen ( ), + .int_n ( int_n ), + .nmi_n ( 1'b1 ), + .busrq_n ( 1'b1 ), + .m1_n ( ), + .mreq_n ( mreq_n ), + .iorq_n ( iorq_n ), + .rd_n ( rd_n ), + .wr_n ( wr_n ), + .rfsh_n ( rfsh_n ), + .halt_n ( ), + .busak_n ( ), + .A ( A ), + .cpu_din ( cpu_din ), + .cpu_dout ( cpu_dout ), + .ram_dout ( ram_dout ), + .ram_cs ( ram_cs ), + .rom_cs ( snd_cs ), + .rom_ok ( snd_ok ) +); + +jt03 #(.YM2203_LUMPED(1)) u_ym2203( + .rst ( rst ), + .clk ( clk ), + .cen ( cen1p5 ), + .din ( cpu_dout ), + .dout ( ym_dout ), + .addr ( A[0] ), + .cs_n ( ~ym_cs ), + .wr_n ( wr_n ), + .psg_snd ( psg ), + .fm_snd ( fm ), + .snd_sample ( ), + .irq_n ( int_n ), + + .IOA_oe ( ), + .IOB_oe ( ), + .IOA_in ( 8'd0 ), + .IOB_in ( 8'd0 ), + .IOA_out ( ), + .IOB_out ( ), + .psg_A ( ), + .psg_B ( ), + .psg_C ( ), + .snd ( ), + .debug_view ( ) +); + +endmodule diff --git a/cores/argus/hdl/jtargus_video.v b/cores/argus/hdl/jtargus_video.v new file mode 100644 index 000000000..ebfb59c9f --- /dev/null +++ b/cores/argus/hdl/jtargus_video.v @@ -0,0 +1,247 @@ +module jtargus_video( + input rst, + input clk, + input pxl_cen, + + input flip, + input bg1_en, + input [ 9:0] bg0_scrx, + input [ 8:0] bg0_scry, + input [ 7:0] bg0_vrom, + input [ 8:0] bg1_scrx, + input [ 8:0] bg1_scry, + + output [ 9:0] tx_addr, + input [15:0] tx_data, + output [ 9:0] bg1_addr, + input [15:0] bg1_data, + + output [12:0] objram_addr, + input [ 7:0] objram_data, + + output bg0_cs, + output [16:2] bg0_addr, + input [31:0] bg0_data, + input bg0_ok, + + output bg1rom_cs, + output [14:2] bg1rom_addr, + input [31:0] bg1rom_data, + input bg1rom_ok, + + output txt_cs, + output [14:2] txt_addr, + input [31:0] txt_data, + input txt_ok, + + output obj_cs, + output [16:2] obj_addr, + input [31:0] obj_data, + input obj_ok, + + output [14:1] vrom1_addr, + input [15:0] vrom1_data, + output vrom1_cs, + input vrom1_ok, + + output [14:1] vrom2_addr, + input [15:0] vrom2_data, + output vrom2_cs, + input vrom2_ok, + + output [ 9:0] pal_pxl, + input [11:0] pal_rgb, + output [ 9:0] blend_bg_pxl, + output [ 9:0] blend_obj_pxl, + input [11:0] blend_bg_rgb, + input [11:0] blend_obj_rgb, + input [ 3:0] blend_alpha, + + output [ 3:0] red, + output [ 3:0] green, + output [ 3:0] blue, + output LHBL, + output LVBL, + output HS, + output VS, + output reg irq8, + output reg irq10, + + input [ 3:0] gfx_en, + input [ 7:0] debug_bus +); + +wire [8:0] hdump, vdump, vrender; +wire [8:0] vdump_src = vdump; +wire [8:0] vrender_src = vrender; +wire latch_view = hdump==9'd0 && vdump==9'd15; +reg flip_view, bg1_en_view; +reg [9:0] bg0_scrx_view; +reg [8:0] bg0_scry_view, bg1_scrx_view, bg1_scry_view; +reg [7:0] bg0_vrom_view; +wire blankn = LHBL & LVBL; +wire tile_fetch = 1'b1; +wire bg1_fetch = tile_fetch & bg1_en_view; +wire [7:0] bg0_pxl, bg1_pxl, tx_pxl; +wire [8:0] obj_pxl; + +jtframe_vtimer #( + .VB_START ( 9'd239 ), + .VB_END ( 9'd15 ), + .VS_START ( 9'd240 ), + .VS_END ( 9'd244 ), + .VCNT_END ( 9'd287 ), + .HB_START ( 9'd255+9'd10 ), + .HB_END ( 9'd9 ), + .HS_START ( 9'd300 ), + .HS_END ( 9'd327 ), + .HCNT_END ( 9'd383 ) +) u_timer( + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .vdump ( vdump ), + .vrender ( vrender ), + .vrender1 ( ), + .H ( hdump ), + .Hinit ( ), + .Vinit ( ), + .LHBL ( LHBL ), + .LVBL ( LVBL ), + .HS ( HS ), + .VS ( VS ) +); + +always @(posedge clk) begin + if( rst ) begin + irq8 <= 1'b0; + irq10 <= 1'b0; + flip_view <= 1'b0; + bg1_en_view <= 1'b0; + bg0_scrx_view <= 10'd0; + bg0_scry_view <= 9'd0; + bg0_vrom_view <= 8'd0; + bg1_scrx_view <= 9'd0; + bg1_scry_view <= 9'd0; + end else if( pxl_cen ) begin + irq8 <= hdump==9'd0 && vdump==9'd16; + irq10 <= hdump==9'd0 && vdump==9'd240; + if( latch_view ) begin + flip_view <= flip; + bg1_en_view <= bg1_en; + bg0_scrx_view <= bg0_scrx; + bg0_scry_view <= bg0_scry; + bg0_vrom_view <= bg0_vrom; + bg1_scrx_view <= bg1_scrx; + bg1_scry_view <= bg1_scry; + end + end +end + +jtargus_bg0 u_bg0( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( HS ), + .blankn ( tile_fetch ), + .flip ( flip_view ), + .vdump ( vdump_src ), + .hdump ( hdump ), + .scrx ( bg0_scrx_view ), + .scry ( bg0_scry_view ), + .vrom_offset( bg0_vrom_view ), + .rom_cs ( bg0_cs ), + .rom_addr ( bg0_addr ), + .rom_data ( bg0_data ), + .rom_ok ( bg0_ok ), + .vrom1_addr ( vrom1_addr ), + .vrom1_data ( vrom1_data ), + .vrom1_cs ( vrom1_cs ), + .vrom1_ok ( vrom1_ok ), + .vrom2_addr ( vrom2_addr ), + .vrom2_data ( vrom2_data ), + .vrom2_cs ( vrom2_cs ), + .vrom2_ok ( vrom2_ok ), + .pxl ( bg0_pxl ) +); + +jtargus_scroll #(.CW(8),.TEXT(0)) u_bg1( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( HS ), + .blankn ( bg1_fetch ), + .flip ( flip_view ), + .vdump ( vdump_src ), + .hdump ( hdump ), + .scrx ( bg1_scrx_view ), + .scry ( bg1_scry_view ), + .ram_addr ( bg1_addr ), + .ram_data ( bg1_data ), + .rom_cs ( bg1rom_cs ), + .rom_addr ( bg1rom_addr ), + .rom_data ( bg1rom_data ), + .rom_ok ( bg1rom_ok ), + .pxl ( bg1_pxl ) +); + +jtargus_scroll #(.CW(10),.TEXT(1)) u_text( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( HS ), + .blankn ( tile_fetch ), + .flip ( flip_view ), + .vdump ( vdump_src ), + .hdump ( hdump ), + .scrx ( 9'd0 ), + .scry ( 9'd0 ), + .ram_addr ( tx_addr ), + .ram_data ( tx_data ), + .rom_cs ( txt_cs ), + .rom_addr ( txt_addr ), + .rom_data ( txt_data ), + .rom_ok ( txt_ok ), + .pxl ( tx_pxl ) +); + +jtargus_obj u_obj( + .rst ( rst ), + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .hs ( HS ), + .blankn ( blankn ), + .flip ( flip_view ), + .hdump ( hdump ), + .vrender ( vrender_src ), + .ram_addr ( objram_addr ), + .ram_data ( objram_data ), + .rom_cs ( obj_cs ), + .rom_addr ( obj_addr ), + .rom_data ( obj_data ), + .rom_ok ( obj_ok ), + .pxl ( obj_pxl ) +); + +jtargus_colmix u_colmix( + .clk ( clk ), + .pxl_cen ( pxl_cen ), + .blankn ( blankn ), + .bg1_en ( bg1_en_view ), + .bg0_pxl ( bg0_pxl ), + .bg1_pxl ( bg1_pxl ), + .tx_pxl ( tx_pxl ), + .obj_pxl ( obj_pxl ), + .pal_pxl ( pal_pxl ), + .blend_bg_pxl( blend_bg_pxl ), + .blend_obj_pxl( blend_obj_pxl ), + .pal_rgb ( pal_rgb ), + .blend_bg_rgb( blend_bg_rgb ), + .blend_obj_rgb( blend_obj_rgb ), + .blend_alpha( blend_alpha ), + .red ( red ), + .green ( green ), + .blue ( blue ), + .gfx_en ( gfx_en ) +); + +endmodule diff --git a/cores/argus/tools/framewatch.py b/cores/argus/tools/framewatch.py new file mode 100755 index 000000000..bb1bc29d6 --- /dev/null +++ b/cores/argus/tools/framewatch.py @@ -0,0 +1,402 @@ +#!/usr/bin/env python3 +"""framewatch - live viewer for Argus sim frames. + +The sim writes frame_NNNNN images into +$JTCORES/cores/argus/ver/argus/frames/ as it runs. This script starts +a tiny HTTP server with live-follow, frame navigation, scrubber, and +playback controls so you can watch and inspect sim output in a browser. + +Python stdlib only. Usage: + + python3 tools/framewatch.py # watch default dir + python3 tools/framewatch.py --dir /other/frames # override + python3 tools/framewatch.py --port 9000 --poll 50 # tweak + +Open the printed URL in any browser and leave it open across sim runs. +""" +import argparse +import http.server +import json +import os +import pathlib +import re +import sys +import urllib.parse + +FRAME_RE = re.compile(r"frame_(\d+)\.(jpg|bmp|png)$") +CONTENT_TYPES = { + "jpg": "image/jpeg", + "bmp": "image/bmp", + "png": "image/png", +} +DEFAULT_DIR = pathlib.Path(__file__).resolve().parents[1] / "ver/argus/frames" + + +def latest(frames_dir: pathlib.Path): + # Pick the most-recently-modified frame rather than the highest-numbered + # one. Old sim runs leave stale high-numbered files in this dir, so + # filename-max would pin us to the previous run's final frame until the + # current run overshoots it. + best_n = -1 + best_name = None + best_ext = None + best_mtime = -1.0 + try: + with os.scandir(frames_dir) as it: + for ent in it: + m = FRAME_RE.match(ent.name) + if not m: + continue + try: + mtime = ent.stat().st_mtime + except OSError: + continue + if mtime > best_mtime: + best_mtime = mtime + best_n = int(m.group(1)) + best_name = ent.name + best_ext = m.group(2) + except FileNotFoundError: + pass + return best_n, best_name, best_ext + + +def list_frames(frames_dir: pathlib.Path): + # Return every frame_NNNNN number in the directory, sorted ascending. + # Use a set so mixed image extensions do not duplicate the scrubber. + out = set() + try: + with os.scandir(frames_dir) as it: + for ent in it: + m = FRAME_RE.match(ent.name) + if m: + out.add(int(m.group(1))) + except FileNotFoundError: + pass + return sorted(out) + + +def build_html(poll_ms: int) -> bytes: + return f""" +argus sim frames + + +
+ latest - + | + status starting + | + + + | + + + + @ fps + | + jump + | + showing - / - frames +
+
+ - + + - +
+
waiting for frames...
+ +""".encode("utf-8") + + +def make_handler(frames_dir: pathlib.Path, html: bytes): + class H(http.server.BaseHTTPRequestHandler): + def log_message(self, *a, **k): + return + + def _send(self, status, ctype, body, *, cache=False): + self.send_response(status) + self.send_header("Content-Type", ctype) + self.send_header("Content-Length", str(len(body))) + if not cache: + self.send_header("Cache-Control", "no-store") + self.end_headers() + if body: + self.wfile.write(body) + + def do_GET(self): + path = urllib.parse.urlparse(self.path).path + if path in ("/", "/index.html"): + return self._send(200, "text/html; charset=utf-8", html) + if path == "/latest": + n, name, ext = latest(frames_dir) + body = json.dumps({"frame": n, "name": name, "ext": ext}).encode() + return self._send(200, "application/json", body) + if path == "/frames": + body = json.dumps(list_frames(frames_dir)).encode() + return self._send(200, "application/json", body) + if path.startswith("/frame/"): + token = path[len("/frame/"):] + try: + n = int(token) + except ValueError: + return self._send(404, "text/plain", b"bad frame id") + for ext in ("bmp", "jpg", "png"): + fpath = frames_dir / f"frame_{n:05d}.{ext}" + if fpath.is_file(): + try: + data = fpath.read_bytes() + except OSError: + return self._send(500, "text/plain", b"read error") + return self._send(200, CONTENT_TYPES[ext], data) + return self._send(404, "text/plain", b"no such frame") + return self._send(404, "text/plain", b"not found") + + return H + + +def main(): + ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + ap.add_argument( + "--dir", + default=str(DEFAULT_DIR), + help=f"frames directory (default: {DEFAULT_DIR})", + ) + ap.add_argument("--host", default="127.0.0.1") + ap.add_argument("--port", type=int, default=8766) + ap.add_argument( + "--poll", + type=int, + default=100, + help="browser poll interval in ms (default: 100)", + ) + args = ap.parse_args() + + frames_dir = pathlib.Path(args.dir).expanduser().resolve() + if not frames_dir.exists(): + print( + f"warning: {frames_dir} does not exist yet; will serve 404s " + "until the sim creates it", + file=sys.stderr, + ) + + html = build_html(args.poll) + handler = make_handler(frames_dir, html) + server = http.server.ThreadingHTTPServer((args.host, args.port), handler) + url = f"http://{args.host}:{args.port}/" + print(f"framewatch: {frames_dir}", file=sys.stderr) + print(f" {url}", file=sys.stderr) + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nbye", file=sys.stderr) + finally: + server.server_close() + + +if __name__ == "__main__": + main() diff --git a/cores/argus/ver/argus/start_game.cab b/cores/argus/ver/argus/start_game.cab new file mode 100644 index 000000000..792928dbc --- /dev/null +++ b/cores/argus/ver/argus/start_game.cab @@ -0,0 +1,6 @@ +# Wait briefly, add a credit, then press 1P start. +=180 +4 coin +40 +4 1p +=600 diff --git a/doc/mame.xml b/doc/mame.xml index e21d962a9..7f88c0365 100644 --- a/doc/mame.xml +++ b/doc/mame.xml @@ -14780,6 +14780,132 @@ + + Argus + 1986 + NMK (Jaleco license) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Arkanoid - Revenge of DOH (World) 1987 @@ -31060,6 +31186,272 @@ + + Butasan - Pig's & Bomber's (Japan, English) + 1987 + NMK (Jaleco license) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Butasan (Japan, Japanese) + 1987 + NMK (Jaleco license) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Caliber 50 (Ver. 1.01) 1989 @@ -216229,6 +216621,129 @@ + + Valtric + 1986 + NMK (Jaleco license) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vampire: The Night Warriors (Japan 940705) 1994 diff --git a/modules/jtframe/hdl/video/tilemap/jtframe_scroll.v b/modules/jtframe/hdl/video/tilemap/jtframe_scroll.v index a3717723b..1ec10f606 100644 --- a/modules/jtframe/hdl/video/tilemap/jtframe_scroll.v +++ b/modules/jtframe/hdl/video/tilemap/jtframe_scroll.v @@ -34,6 +34,7 @@ module jtframe_scroll #( parameter VW = SIZE==8 ? 3 : SIZE==16 ? 4:5, HW = VW, ROM_HFLIP = 1, + SCAN_COLS = 0, XOR_HFLIP = 0, // set to 1 so hflip gets ^ with flip XOR_VFLIP = 0, // set to 1 so vflip gets ^ with flip HJUMP = 1, // set to 0 for linear hdump starting at zero after HB @@ -107,6 +108,7 @@ jtframe_tilemap #( .FLIP_VDUMP ( 0 ), // same for vdump .FLIP_MSB ( 0 ), .ROM_HFLIP ( ROM_HFLIP ), + .SCAN_COLS ( SCAN_COLS ), .XOR_HFLIP ( XOR_HFLIP ), .XOR_VFLIP ( XOR_VFLIP ), .VW ( VW ), @@ -138,4 +140,4 @@ jtframe_tilemap #( .pxl ( pxl ) ); -endmodule \ No newline at end of file +endmodule diff --git a/modules/jtframe/hdl/video/tilemap/jtframe_tilemap.v b/modules/jtframe/hdl/video/tilemap/jtframe_tilemap.v index 404a2be53..861901643 100644 --- a/modules/jtframe/hdl/video/tilemap/jtframe_tilemap.v +++ b/modules/jtframe/hdl/video/tilemap/jtframe_tilemap.v @@ -35,6 +35,7 @@ module jtframe_tilemap #( parameter FLIP_HDUMP = 1, FLIP_VDUMP = 1, ROM_HFLIP = 1, + SCAN_COLS = 0, XOR_HFLIP = 0, // set to 1 so hflip gets ^ with flip XOR_VFLIP = 0, // set to 1 so vflip gets ^ with flip HDUMP_OFFSET = 0, // adds an offset to hdump @@ -116,7 +117,8 @@ assign vflip_g = (flip & XOR_VFLIP[0])^vflip; localparam AHW=MAP_HW-HW, AVW=MAP_VW-VW; -assign vram_addr={ veff[MAP_VW-1:VW], heff[MAP_HW-1:HW] }; +assign vram_addr = SCAN_COLS ? { heff[MAP_HW-1:HW], veff[MAP_VW-1:VW] } : + { veff[MAP_VW-1:VW], heff[MAP_HW-1:HW] }; initial begin if( AHW+AVW > VA ) begin @@ -169,4 +171,4 @@ always @(posedge clk) begin end end -endmodule \ No newline at end of file +endmodule