Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions cores/taitob/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# JTTAITOB — Taito B System FPGA core

JTCORES implementation of the **Taito B System** arcade board (1988–1991).

## Target

**Phase A** — first target: **Rastan Saga 2 / Nastar / Nastar Warrior**
(MAME `rastsag2` / `nastar` / `nastarw`, ROM prefix `b81`, 1988).

Future phases would cover the YM2610 family on the same bitstream:
Ashura Blaster, Crime City, Rambo 3, Silent Dragon, Sel Feena, Ryujin,
Tetris (B-System conversion). The YM2203-based outliers (Violence Fight,
Hit the Ice, Master of Weapon) would need a separate bitstream.

## Hardware

PCB: `K1100419A / J1100178A`. Two crystals + a third for video:

| Block | Chip | Clock |
|-------------------|-----------------|----------------------|
| Main CPU | Motorola 68000 | 12 MHz (24 / 2) |
| Sound CPU | Zilog Z80 | 4 MHz (16 / 4) |
| FM + ADPCM | Yamaha YM2610 | 8 MHz (16 / 2) |
| Sound comms | TC0140SYT | bus-paced |
| I/O | TC0220IOC | bus-paced |
| Video | TC0180VCU | 27.164 / 4 ≈ 6.79 MHz|
| Palette DAC | TC0260DAR | passive |

## State (bootstrap commit)

- [x] Directory scaffold + cfg files
- [x] CPU spine (68000 + DTACK + autovector IACK)
- [x] BRAM RAMs (work / palette / VRAM / sprite-scroll / VCU ctrl regs)
- [x] Sound subsystem (Z80 + YM2610 + TC0140SYT, all GPLv3 ports)
- [x] TC0220IOC stub (DIPs + cabinet inputs + coin latch)
- [x] TC0260DAR (passive palette DAC → RGB)
- [x] Video timing (320×224 @ 60 Hz)
- [x] **TC0180VCU stub** — palette viewer shows whatever the 68k writes
to palette, no tile/sprite rendering yet
- [ ] TC0180VCU real RTL — the major remaining work item
- [ ] IRQ 2 (VCU intl) — currently only IRQ 4 (vblank) is wired
- [ ] ADPCM-B SDRAM bus — voice samples currently silent
- [ ] MAME ground-truth traces (next step per AGENTS.md §0.5)
- [ ] FPGA sim diff vs MAME

## Provenance

The CPU + sound + TC0140SYT subsystems are ports from
[cores/superman/](../superman/) (Taito X System) — same silicon for
68k/Z80/YM2610/SYT, just a clock change on the 68k (8 MHz → 12 MHz).
The TC0140SYT module (`jttaitob_syt.v`) is a verbatim copy of
`jtsuperman_syt.v` with attribution updated.

The TC0180VCU is unique to the Taito B System. No reference
implementation exists in the wider open-source ecosystem (the
Arcade-TaitoF2_MiSTer and Arcade-Darius2NinjaWarriors_MiSTer repos
implement F2 / Z System chips but neither covers the VCU). It will be
built from MAME's [tc0180vcu.cpp](doc/tc0180vcu.cpp) as the only spec.
49 changes: 49 additions & 0 deletions cores/taitob/cfg/files.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
taitob:
- get:
- jttaitob_game.v
- jttaitob_main.v
- jttaitob_snd.v
# TC0140SYT — main↔Z80 sound communication chip.
# Same silicon as Taito X System; ported verbatim from
# cores/superman/hdl/jtsuperman_syt.v (GPLv3).
- jttaitob_syt.v
# TC0220IOC — I/O / dipswitch / coin chip. Stub for now.
- jttaitob_ioc.v
# TC0180VCU — fused video chip (2× 64×64 tile planes + zooming
# sprites + text plane). Currently a stub that exposes VRAM /
# sprite RAM / scroll RAM / ctrl registers as BRAM the 68k can
# read & write, but produces black video. Real pipeline TBD.
- jttaitob_video.v
# Tile-row ring buffer + fine-scroll read tap (TC0100SCN-style technique,
# used by the BG/FG/TX planes for correct sub-tile horizontal scroll).
- jttaitob_shifter.v
# TC0180VCU sprite engine (Phase 3d). Scans the 408-slot sprite list each
# line into a jtframe_obj_buffer line buffer; reuses the gfx_sort'd gfx.
- jttaitob_obj.v
- jttaitob_colmix.v
jtframe:
- get:
- jtframe_ff.v
- from: clocking
get:
- jtframe_cen48.v
- jtframe_cen24.v
- jtframe_sync.v
- from: ram
get:
- jtframe_ram.v
- jtframe_dual_ram.v
- jtframe_dual_ram16.v
- jtframe_obj_buffer.v
- jtframe_prom.v
- from: video
get:
- jtframe_vtimer.v
- jtframe_blank.v
- from: cpu
get:
- jtframe_z80.yaml
- jtframe_m68k.yaml
jt12:
- get:
- jt12.yaml # pulls the entire jt12 module incl. jt10 (YM2610) wrapper
86 changes: 86 additions & 0 deletions cores/taitob/cfg/macros.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
CORENAME=JTTAITOB

# Hardware: Taito B System (1988-91).
# Reference: MAME taito/taito_b.cpp (mirrored in cores/taitob/doc/)
#
# First target: Rastan Saga 2 / Nastar / Nastar Warrior (rastsag2, 1988).
# All three regional sets share the same `rastsag2` machine config.
#
# Clocks (24 MHz + 16 MHz master XTALs per MAME):
# 68000 = 24 / 2 = 12 MHz (main)
# Z80 = 16 / 4 = 4 MHz (sound)
# YM2610 = 16 / 2 = 8 MHz (sound)
# TC0180VCU pixel = 27.164 / 4 ≈ 6.79 MHz (video — synthesised below)
#
# Custom Taito chips on the Taito B board (taito_b.cpp:11):
# TC0220IOC — I/O / dipswitch / coin controller (jttaitob_ioc.v stub)
# TC0260DAR — passive 12-bit palette DAC (no device in MAME; palette
# lives at 0x200000 as plain CPU-writable RAM, jttaitob_main.v
# exposes it via a BRAM port to jttaitob_colmix.v)
# TC0180VCU — fused video chip: 2× 64×64 tile planes + zooming sprites
# + text plane + per-line scroll. No reference implementation
# exists anywhere — full HDL job. Currently stubbed.
# TC0140SYT — main↔sound comms. Reused verbatim from Superman
# (jtsuperman_syt.v copied to jttaitob_syt.v, same chip).

# ─── Controls ────────────────────────────────────────────────────────────────
# Rastan Saga 2 / Nastar uses 2 action buttons (Attack + Jump). All
# Taito B games are 2-button except Hit The Ice (4-player). Stick with
# 2 for now; revisit if/when hitice lands in this bitstream.
JTFRAME_BUTTONS=2

# Joystick reorder — Superman precedent: HPS_IO board_joy1 arrives in
# RLDU order (bit 0=RIGHT, 1=LEFT, 2=DOWN, 3=UP). MAME's
# TAITO_JOY_UDLR_2_BUTTONS_START expects UDLR. JTFRAME_JOY_RLDU
# applies the bit-reverse on bits 3:0 that maps RLDU → UDLR.
JTFRAME_JOY_RLDU

# ─── Video ───────────────────────────────────────────────────────────────────
# MAME's set_visarea(0*8, 40*8-1, 2*8, 30*8-1) = 320×224 active.
# Palette is 12-bit RGBx_444 (4 bits per channel), 4096 colours.
JTFRAME_COLORW=4
JTFRAME_WIDTH=320
JTFRAME_HEIGHT=224

# 48 MHz frame clock — Superman pattern. Gives clean integer cens for
# 12 MHz (÷4), 8 MHz (÷6), 4 MHz (÷12).
JTFRAME_CLK48

# Pixel clock — PXLCLK=70 = 7.00 MHz (fractional cen n=7/m=24, see
# jtframe_pxlcen.v). Real chip is 6.79 MHz (27.164/4). With H total 448
# (jttaitob_game.v vtimer) this gives 15.625 kHz / 60.1 Hz and a 128-px
# H-blank (~878 clk) — enough for the sequential BG/FG/TX ring fills
# (~840 clk), unlike PXLCLK=6/384 (512-clk blank, overruns). Image width
# 71% of the line (between 62.5% @8 MHz and 83% @6 MHz; ≈ real arcade).
JTFRAME_PXLCLK=70

# ─── SDRAM layout ────────────────────────────────────────────────────────────
# Bank 0 : 68k main ROM (max 512 KB) 0x000000
# Bank 1 : all audio ROM — Z80 + ADPCM-A + ADPCM-B
# snd@0x080000 adpcma@0x100000 adpcmb@0x180000
# Bank 2 : TC0180VCU gfx, copy 1 (1 MB) — bg/obj/tx 0x200000
# Bank 3 : TC0180VCU gfx, copy 2 (1 MB) — fg only 0x300000
# (duplicate so BG fill@bank2 and FG fill@bank3 interleave)
JTFRAME_HEADER=16
JTFRAME_BA1_START=0x080000
JTFRAME_BA2_START=0x200000
JTFRAME_BA3_START=0x300000
PCM_START=0x100000
ADPCMB_START=0x180000

# Debug knobs
JTFRAME_IOCTL_RD=2048
JTFRAME_STATUS

[mister]
JTFRAME_ARX=4
JTFRAME_ARY=3

[mist]
-JTFRAME_CREDITS
NOCREDITS
JTFRAME_OSD_NOCREDITS

[sidi]
# May not fit on smaller SiDi — leave as build-once and re-evaluate
JTFRAME_SKIP
92 changes: 92 additions & 0 deletions cores/taitob/cfg/mame2mra.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[global]
author=["jotego"]

[parse]
sourcefile=[ "taito_b.cpp" ]
# Phase A: Rastan Saga 2 / Nastar / Nastar Warrior — three regional sets
# of the same ROM (only the region-byte ROM B81-07/12/13 differs).
# All other Taito B games share the same TC0140SYT + TC0220IOC + TC0180VCU
# + YM2610 hardware and could ship in this bitstream once the video chip
# is solid:
# ashura blaster / crime city / rambo3 / silent dragon / sel feena /
# ryujin / tetris (B-System conversion) / space invaders DX / qzshowby /
# puzzle bobble / sonic blast man — all YM2610 family
#
# Out-of-scope variants (different sound chips, different IOCs, etc.):
# violence fight / hit the ice (YM2203 + M6295)
# master of weapon (YM2203, TMP82C265 I/O)
# ashura blaster / silent dragon variants
skip = { setnames = [
# Still skipped: games that need HDL work the core doesn't have yet.
# tetrista — Master of Weapon kit → YM2203 + PC060HA
# hitice* — YM2203 + OKIM6295
# rambo3* — 2 MB gfx (needs mem.yaml gfx bus 1MB→2MB + 4-ROM dup)
# pbobble/spacedx/qzshowby — EEPROM + TC0640FIO + MB87078 (B-tier)
# viofight/masterw — YM2203 (+OKI) sound subsystem
# silentd/ryujin/sbm — YM2610B / TC0510NIO (B-tier)
# realpunc — adds HD63484 2nd video path
# De-skipped (Group A, 1 MB gfx, YM2610+SYT+TC0220IOC): crimec, tetrist.
# Still re-skipped because they error out in jtframe-mra (fatal validation):
# ashura/ashuraj/ashurau — vertical (need JTFRAME_VERTICAL)
# selfeena, spacedxo — 3-button (need JTFRAME_BUTTONS=3, per-game)
# Once we add per-machine JTFRAME_VERTICAL / BUTTONS overrides they'll un-skip.
"ashura", "ashurau", "ashuraj",
"selfeena",
"spacedxo",
"tetrista",
"hitice", "hiticerb", "hiticej",
"rambo3", "rambo3p", "rambo3u",
"pbobble", "bublbust",
"spacedx", "spacedxj",
"qzshowby",
"viofight","viofightu","viofightj",
"masterw", "masterwj", "masterwu", "yukiwo",
"silentd", "silentdj", "silentdu",
"ryujin", "ryujina",
"sbm", "sbmj",
"realpunc","realpuncj",
]}

[buttons]
names=[
# Rastan Saga 2 / Nastar: 2 buttons — Attack + Jump.
{ machines=["nastar","nastarw","rastsag2"], names="Attack,Jump" },
]

[dipsw]
delete=[{names=["Unused","Unknown"]}]

[ROM]
# ROM regions for rastsag2 (taito_b.cpp:2793):
# maincpu = 512 KB (16-bit, 4 × ROM_LOAD16_BYTE pairs)
# audiocpu = 64 KB (Z80)
# tc0180vcu = 1 MB (2 × 512 KB ROMs, sprite+tile gfx)
# ymsnd:adpcma = 512 KB
# ymsnd:adpcmb = 512 KB (Delta-T voice samples — wired into the jt10
# ADPCM-B port; loaded into SDRAM bank 3 at
# JTFRAME_BA3_START)
regions = [
{ name="maincpu", width=16, reverse=true, no_offset=true },
{ name="audiocpu", start="JTFRAME_BA1_START" },
{ name="ymsnd:adpcma", rename="adpcma", start="PCM_START" },
{ name="ymsnd:adpcmb", rename="adpcmb", start="ADPCMB_START" },
# tc0180vcu graphics ROMs land at the start of bank 2.
# MAME loads the two 512 KB ROMs with plain ROM_LOAD (straight
# concatenation): b81-03 → 0x00000 (planes 0/1), b81-04 → 0x80000
# (planes 2/3, via the charlayout/tilelayout RGN_FRAC(1,2) split).
# They are NOT a 16-bit byte-interleaved pair, so width=8 keeps each
# ROM as a contiguous half. (width=16 interleaved every byte and
# scrambled all tile gfx into noise.)
# gfx duplicated into 2 MB: sequence=[0,1,0,1] lays b81-03,b81-04 twice
# → copy 1 at bank 2 (BA2, bg/obj/tx) and copy 2 at bank 3 (BA3, fg).
# Two banks let the BG fill (bank 2) and FG fill (bank 3) interleave on
# the SDRAM controller instead of serializing on one bank. Each 1 MB half
# is gfx_sort'd independently via its mem.yaml bus (tx for bank 2, fg for
# bank 3). BA3_START must equal BA2_START + 0x100000 for copy 2 to land
# where the fg bus reads it.
{ name="tc0180vcu", rename="gfx1", start="JTFRAME_BA2_START", width=8, no_offset=true, sequence=[0,1,0,1] },
]

order = [
"maincpu", "audiocpu", "adpcma", "adpcmb", "gfx1"
]
102 changes: 102 additions & 0 deletions cores/taitob/cfg/mem.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Taito B System SDRAM map — DRAFT
#
# Bus widths follow the MAME ROM regions (taito_b.cpp rastsag2 ROM_START):
# maincpu : 16-bit (68k), 512 KB
# audiocpu: 8-bit (Z80), 64 KB
# adpcma : 8-bit, up to 512 KB (YM2610 ADPCM-A samples)
# gfx1 : 16-bit interleaved sprite/tile graphics (TC0180VCU input)
#
# Memory map per rastsag2_map (taito_b.cpp:369):
# 0x000000-0x07FFFF 68k ROM → SDRAM bank 0 (main bus)
# 0x200000-0x201FFF palette RAM → BRAM in jttaitob_main.v
# 0x400000-0x47FFFF TC0180VCU → BRAM (vram/sprites/scroll/ctrl)
# 0x600000-0x607FFF 68k work RAM → BRAM (32 KB)
# 0x800000-0x800003 TC0140SYT → jttaitob_syt.v
# 0xA00000-0xA0000F TC0220IOC → jttaitob_ioc.v
#
# Bus ordering rule (rastan/gaiden pattern): rw buses come first on their
# bank so the auto-generated SDRAM slot wires the write enable correctly.

params:
- { name: ADPCMA_OFFSET, value: "(`PCM_START-`JTFRAME_BA1_START)>>1" }
- { name: ADPCMB_OFFSET, value: "(`ADPCMB_START-`JTFRAME_BA1_START)>>1" }

audio:
rsum: 10k
channels:
- { name: fm, module: jt12, rsum: 10k } # YM2610 FM, wrapped by jt10

sdram:
banks:
# Bank 0 — 68k main ROM (read-only). Work RAM, palette RAM, VRAM,
# sprite RAM, scroll RAM all live in BRAM inside jttaitob_main.v —
# SDRAM latency is incompatible with the 68k's memory-test loop and
# the BRAM model is the right one for these sizes anyway.
- buses:
- name: main
addr_width: 19
data_width: 16

# Bank 1 — all audio ROM (read-only): Z80 program + YM2610 ADPCM-A and
# ADPCM-B (Delta-T) samples. Kept together so banks 2/3 stay pure gfx.
- buses:
- name: snd
addr_width: 16
data_width: 8
- name: adpcma
addr_width: 19
data_width: 8
offset: ADPCMA_OFFSET
- name: adpcmb
addr_width: 19
data_width: 8
offset: ADPCMB_OFFSET

# Bank 2 — TC0180VCU graphics ROM, copy 1 (1 MB). Read by:
# bg → BG plane tile fetch
# obj → sprite gfx (active region)
# tx → text plane (8x8 tiles)
# FG has its own copy in bank 3 so the BG fill (bank 2) and FG fill
# (bank 3) hit different physical SDRAM banks and interleave.
#
# gfx_sort=hvvvx (mode gfx4, b0=1) rotates gfx-word address bits [3:0]
# so the tilelayout L/R-8px-half bit (px3, word bit 3) becomes the LSB.
# That puts a tile-row's two 8px halves at adjacent addresses, so the
# SDRAM read-cache turns the 2nd half-read into a hit (~2x fewer SDRAM
# round-trips per tile). The data inside each word is untouched, so the
# pen decode is unchanged — the HDL only reorders the bottom address
# bits ({A[18:4],A[2:0],A[3]}) in BG/FG/TX address generation.
# The three buses share ONE 1 MB region, so the sort is declared on a
# single bus to repack the bytes exactly once; the others read the
# already-sorted data with the same address swap. It must go on the
# LAST bus of the bank (tx): jtframe mem bounds a gfx_sort range at the
# next bus's offset, and bg/obj have none — declaring it on the final
# bus instead ends the range at the next bank, covering the full region.
- buses:
- name: obj
addr_width: 20
data_width: 16
- name: bg
addr_width: 20
data_width: 16
- name: tx
addr_width: 20
data_width: 16
gfx_sort: hvvvx

# Bank 3 — TC0180VCU graphics ROM, copy 2 (1 MB), read by the FG plane
# ONLY. Duplicating the gfx into its own physical SDRAM bank lets the BG
# fill (bank 2) and FG fill (bank 3) run on different banks → the SDRAM
# controller interleaves their accesses (BG's RAS/CAS latency overlaps
# FG's) instead of serializing on one shared bank. The +1 MB buys the
# parallel fill that fits the shorter 7 MHz H-blank. gfx_sort applied
# (only bus in the bank).
- buses:
- name: fg
addr_width: 20
data_width: 16
gfx_sort: hvvvx

# BRAM declarations for palette / VRAM / sprite RAM / scroll RAM live
# inside jttaitob_main.v (cabal/superman pattern). Keeping mem.yaml
# minimal so the auto-generated port surface stays tight.
Loading
Loading