Compare commits

...
Author SHA1 Message Date
mahoneyt944 dff0ba6365 segas32 use opaque blending by default - dbzvrvs backgrounds working. (#2211)
* Update segas32.c

* Update segas32.c

* Update .gitlab-ci.yml

* Update segas32.c

* Update segas32.h

* Update segas32.c

* Update segas32.c

* Update .gitlab-ci.yml
2026-11-07 07:35:08 -05:00
arcadez2003 1035485897 Merge pull request #2210 from libretro/arcadez2003-patch-11
3on3dunk
2026-11-06 21:07:03 +00:00
arcadez2003 a0e0e75905 Merge pull request #2209 from libretro/arcadez2003-patch-10
3on3 Dunk Madness video code
2026-11-06 21:06:47 +00:00
arcadez2003 a45b70e19e Merge pull request #2208 from libretro/arcadez2003-patch-9
Attempt to support 3on3 Dunk Madness
2026-11-06 21:06:32 +00:00
arcadez2003 ea291bf560 3on3dunk 2026-11-06 21:02:07 +00:00
arcadez2003 0dd483f4c0 3on3 Dunk Madness video code 2026-11-06 20:59:50 +00:00
arcadez2003 7f35678403 Attempt to support 3on3 Dunk Madness
Ported from AdvanceMAME
2026-11-06 20:58:34 +00:00
zanacandClaude Opus 5.5 888122871c namcos22: Time Crisis light gun as MAME, with crosshair (#2207)
- the gun ports use MAME's position ranges (X 68-694, Y 43-284), what
  the game reads, instead of 8-bit values scaled in the handler;
- the screen edges read as off screen, as MAME: before, an off-screen
  position (1 or 254) reached the game as a shot at the edge;
- the crosshair (core option) is drawn where the game sees the shot,
  as MAME's PORT_CROSSHAIR(X/Y, 1.0, 0.0, 0).


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-06 03:33:05 -05:00
arcadez2003 d41198a39d Mention Akka Arrh can now be played using this core 2026-11-05 21:56:10 +00:00
zanacandClaude Opus 5.5 34988bc120 Namco System 22 / Super System 22 from current MAME (#2206)
Replaces the old namcos22 driver (no DSPs, every game not working) with a
C89 backport of the current MAME driver:

- new Namco C71 core (TMS320C25 with internal ROM) for the master and
  slave DSPs: MAME's tms320c2x instructions, a page table memory system;
- Super System 22 (68EC020, M37710 MCU with C352 and MB87078 volume) and
  System 22 (68020, C74 MCU with internal BIOS);
- the video: display list simulation, z-sorted polygons and sprites,
  text layer, fog, fades, alpha, spot RAM, gamma; MAME's rasterizer
  rules, single threaded, with 1/z every 8 pixels and fast paths;
- the "Threaded Video" option (was "ST-V Threaded Video") draws the
  frame in bands on 2 to 4 threads (3D scene, text layer, mix, gamma),
  same picture;
- M37710: timer A event counters count up or down (output pin or up/down
  register, as MAME), for the Prop Cycle pedal and the Armadillo Racing
  trackball;
- C352: optional routing of the four outputs to the stereo stream (rear
  speakers, cabinet speakers), as current MAME maps them to stereo; off
  unless a driver asks for it, System 11/12 unchanged;
- game I/O as MAME: driving games and Cyber Commando on System 22,
  Alpine Racer steplock motor, Alpine Surfer ROM banking, Armadillo
  Racing trackball, default EEPROMs.

System 22 sets (namcoc74 BIOS): ridgerac, ridgeraca, ridgeracb,
ridgeracc, ridgeracj, ridgera2, ridgera2j, ridgera2ja, ridgera28,
cybrcomm, raverace, raveracej, raveraceja, acedrive, victlap, victlapa,
victlapj.

Super System 22 sets: alpinerd, alpinerc, alpinerjc, airco22b, cybrcycc,
cybrcyccj, dirtdash, dirtdasha, dirtdashb, dirtdashj, timecris,
timecrisa, timecrisj, propcycl, propcyclj, alpines, tokyowar, tokyowarj,
aquajet, alpinr2b, alpinr2a, adillor, adillorj.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 13:08:58 -05:00
zanacandClaude Opus 5.5 af0f783b1e Cyclone mode: DrZ80(snd) also takes the unflagged sound Z80; default list cleanup (#2157) (#2205)
DrZ80(snd) and Cyclone+DrZ80(snd) only replaced the Z80s flagged
CPU_AUDIO_CPU, and many sound Z80s are not flagged (CPS2, Taito,
Toaplan, the Mega Drive based boards...): those games kept the C Z80
with no sign in the log.

Now, on a board with no flagged CPU whose first CPU is not a Z80, its
first Z80 is taken as the sound CPU too, except where DrZ80 can't run
it: a Z80 with a daisy chain (DrZ80 has none), the CPS1 QSound Z80
(Kabuki-encrypted opcodes) and the Tatsumi sound Z80 (Round Up 5
hangs). The log says which Z80s are replaced and which are kept.

frontend_list.h: removed the entries that could do nothing, with the
same result for every game: 82 names not in the core, 531 games with
neither a 68000 nor a Z80, and a second zzyzzyx2 entry never reached.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-05 03:36:34 -05:00
arcadez2003 b8afd2ddde Sigh this time surely 2026-11-04 22:48:46 +00:00
arcadez2003 00e1f93fc6 Fix build 2026-11-04 22:42:20 +00:00
arcadez2003 ae8299f57c Rename akkaarrh to akkaarrh.c 2026-11-04 22:32:18 +00:00
arcadez2003 11b6dd20a8 FFS try that again 2026-11-04 22:14:36 +00:00
arcadez2003 b6b9bae087 akkaarrh 2026-11-04 20:51:10 +00:00
arcadez2003 9f568e318b Declare akkaarrh 2026-11-04 20:46:46 +00:00
arcadez2003 5a0269a6fd New Driver Atari's Akka Arrh prototype
With thanks to AdvanceMAME
2026-11-04 20:44:15 +00:00
zanacandClaude Opus 5.5 91f2f15e15 ST-V: Cotton Boomerang English translation (cottonbme) (#2204)
Bootleg clone set of cottonbm in English: the stage result lines, the
character select panels, the full names of the characters in the
attract mode, and the translation credit under the title logo. The game always
runs in its Japanese (translated) mode, so the whole translation shows
with every BIOS region. The four changed chips are built from cottonbm
with github.com/zanac/cottonbm, which writes a complete cottonbme.zip.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-04 01:38:45 -05:00
zanacandClaude Opus 5.5 b974d670cc Golden Axe: the FD1094 sets goldnaxb, goldnaxc and goldnaxj working (#2203)
goldnaxb (317-0110), goldnaxc (317-0122) and goldnaxj (317-0121) are the
Golden Axe sets with the FD1094 encrypted 68000 (MAME goldnaxe1,
goldnaxeu, goldnaxej). They were marked not working.

- The decryption keys are added to the sets and the code is decrypted
  with the FD1094 module already used by Cotton (C 68000 core).
- They get their own memory maps: the ones of goldnaxa (171-5797 board)
  and goldnaxe (171-5704 board) without the handlers that stand in for
  the 8751 in the work RAM; these sets have no 8751, they read the I/O
  and send the sound commands themselves.
- The 315-5195 memory mapper, as far as these games use it: register 3 is
  the sound command, and every frame the program moves the sprite RAM to
  one of 8 bases (0x200000-0x900000), so the sprite RAM follows the base
  in register 0x19. The mapper registers are in the save states.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-03 20:16:15 -05:00
zanacandClaude Opus 5.5 ab52620ee4 ST-V and Model 2: save states, run-ahead and netplay; SCSP slot allocation (#2202)
Save states on ST-V were broken on master: a loaded state, a run-ahead
rewind or a netplay resync did not continue the emulation the same way.
Model 2 was almost right (hpyagu98 differed after a rewind).

Core:
- SH-2: each CPU registers its own state (both used to register the
  boot buffer), and the rest of the CPU is saved: delay slot, divider,
  interrupt queue and lines, on-chip registers, FRT, DMA timers.
- Memory banks are registered after the driver init, where the drivers
  point them (ST-V work RAM was saved from the wrong buffer).
- cpu_spinuntil_time / cpu_yielduntil_time trigger counters are saved.
- The crosshair idle timer is saved (the crosshair hid at another frame
  after a load or a rewind).

ST-V:
- SMPC, SCU registers and interrupts, SCU DSP, I/O, sound CPU control,
  CD block scalars, VDP1 clipping, CRTC line counter are saved.
- The RTC starts from the host date and time at boot and then follows the
  emulated time (it read the host clock at every query, so two runs from
  the same state could read different times).

SH-2 recompiler: the polling loop skip counted a whole chain of blocks
that came back to the loop start as one loop iteration, skipping the
writes and calls in between. It now only skips when the block ran one
turn of the loop. Results with a warm or a cold block cache are now the
same.

Model 2: the polygon count of the last display list is saved.

SCSP (issue #2194, regression of #2198): a key off on a slot that had
already stopped (a one-shot sample past its end) left its envelope at the
level it stopped at, because a stopped slot no longer updates it. The
monitor register (0x408) then showed the slot as still sounding, the
sound drivers took it for busy and, after a while, put every new note on
the one slot left. Cotton Boomerang lost all but the drums at the first
boss, Winter Heat's voices cut each other from the first attract demo on.
Such a slot now ends its release at once.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-03 12:04:40 -05:00
zanacandClaude Opus 5.5 7ed1af5370 Model 2: faster 3D, 2D layers, SCSP DSP, i960 and SHARC (#2201)
Renderer:
- texture sheets also kept one byte per texel, the texel fetch reads them
  straight (inlined, an opaque and a translucent span)
- the pixel of each texel worked out once for the colours of a polygon
- translucent texel pairs packed from a table; a translucent pixel sure to
  be discarded skips the next mipmap level
- 3D pixels kept as the 15-bit colour of the bitmap
- the tile layers drawn straight into the bitmap: the polygons are only
  drawn over the tile pixels behind them, no copy passes

System 24 tiles (rgb version, Model 1 and 2): eight pixels at a time, a
group all of the layer's priority without a test each, the last pixels of
the line as groups too.

SCSP DSP: the steps that only multiply and accumulate on a short path,
decoded when MPRO changes; the delay RAM float packing from a table.

i960: opcodes read straight from the memory block of the last fetch
(memory_get_read_range), execute_op inlined.

SHARC: no DMA call while channels 6 and 7 are idle.

AArch64 (QEMU, instructions per frame): fvipers -26%, doa -28%, daytona
-31%, vf2 -25%. Frames and audio are the same on the Model 2 sets, the
ST-V sets and in save states.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-03 02:19:01 -05:00
arcadez2003 35fee378f5 Merge pull request #2200 from zanac/stv-perf
ST-V: faster VDP2 and VDP1 drawing, SH-2 polling loops skipped, FTCSR as in MAME
2026-11-02 23:27:07 +00:00
VanniandClaude Opus 5.5 40dab5fe44 ST-V: faster VDP2 and VDP1 drawing, SH-2 polling loops skipped, FTCSR as in MAME
VDP2 tiles:
- vdp2_drawgfx_alpha drew every pixel through vdp2_window_process; with a
  window it now draws the runs of each line the windows show, from the line
  cache of vdp2_drawgfx_transpen (same pixels), and with no window it
  copies without checks. Both work out the window key once per tile and
  check the cached line inline.
- Each decoded element keeps two masks of its rows (a pixel other than
  pen 0; no pen 0). With transparency vdp2_drawgfx_transpen skips tiles
  and rows of pen 0 only and copies whole the rows without it.

VDP1 sprites: without color calculation draw_sprites walks the window runs
of the line instead of calling vdp2_window_process for every pixel.

SH-2:
- Only a read that includes FRC resyncs it (MAME frc_r); TIER and FTCSR
  reads (MAME ftcsr_r) do not.
- The recompiler skips the iterations of polling loops that only read, as
  it already did for the SGL idle loop: a block that starts with a short
  loop back to itself which leaves every register as it found it and read
  only RAM or TIER/FTCSR repeats the same iteration until the end of the
  timeslice, so those iterations are counted at once.

Makefile (unix): -fvisibility=hidden, only retro_* leaves the library.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-11-02 22:34:25 +01:00
arcadez2003 cc4bfcdf71 Merge pull request #2198 from zanac/stv-sound-2194
SCSP sound for ST-V and Model 2: voices, timers and interrupts from current MAME, Batman Forever RAX board
2026-11-02 19:30:41 +00:00
VanniandClaude Opus 5.5 93b073496c ST-V sound: SCSP voices from current MAME, Batman Forever RAX board
SCSP (also used by Model 2):
- The slot engine from current MAME: key off goes to the release, the
  envelope tables and the dB curve of the decay, pitch, interpolation,
  the four loop modes, FM from the ring buffer, noise (SSCTL), SBCTL,
  LPSLNK, STWINH/SDIR; 8-bit samples read in big-endian byte order.
- The monitor register 0x408 returns CA, SGC and EG of the slot set in
  MSLC: the sound drivers look there for a free slot, and Winter Heat
  played every voice on slot 0, each one cutting the previous.
- Real timers for timers A, B and C, as in MAME: counting them with the
  generated samples delayed every interrupt until the next stream update.
- Interrupts as in MAME: each source raises its own level until it is
  acknowledged in SCIRE, and an acknowledged expired timer is pending
  again with no new interrupt. Reading MIBUF drops the MIDI interrupt:
  left raised, the sound CPU took it again on an empty FIFO and read
  stale bytes as MIDI data, which broke music commands in Model 2
  (Fighting Vipers, Dead or Alive, Manx TT).
- The DMA used the common registers 0x412 words past them, inside the
  slots: now as in MAME.
- The common registers are 0x400-0x42f only (0x500 is not a mirror),
  the ring buffer at 0x600 can be read and written, the LFO saw wave and
  rate as in MAME.
- ST-V: a 16-bit access of the SH-2 touches only its half of the SCSP
  registers.

Batman Forever: the Acclaim RAX sound board (ADSP-2181), moved from zn.c
to sndhrdw/acclaim_rax.c and shared by NBA Jam Extreme and Batman
Forever, which writes its commands to 0x04800000 as in MAME.

docs/sega-model2.md: the MIDI interrupt of the sound link.

Fixes #2194.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-11-02 18:47:50 +01:00
GoodLuckTrying (Wolfric) 4930bf5be7 Ghosts'n Goblins: Princess Prin Prin Edition Hacks (#2196)
* Add files via upload

* Add files via upload
2026-11-02 07:41:43 -05:00
zanacandClaude Opus 5.5 6d162f313c ST-V: critcrsh hammer on the right input ports, lightgun crosshair (#2197)
critcrsh / tatacot: the hammer was read from input ports 10 and 11,
which don't exist (the lightgun ports are 7 and 8), so the game always
saw it in the top left corner. The lightgun ports default to the
centre, since in this core the lightgun moves from the default value,
and the crosshair is drawn as in MAME. Fixes #2195.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-02 07:41:07 -05:00
mahoneyt944 e455f1783a Add files via upload 2026-11-01 07:01:14 -05:00
zanacandClaude Opus 5.5 9275a6a775 ST-V: trackball for the medal games, max geometry from the screen size (#2193)
- techbowl, patocar, skychal, supgoal: trackball on the 315-5649 port G
  counters, as in MAME (mode register bit 7, counter select and byte in
  port G, auto-increment on read, reset when bit 7 is clear). New input
  stvtrack with trackball X/Y. Fixes #2189.
- libretro video: the max geometry and the conversion buffer use the
  larger of the default visible area and the screen size for raster
  games, so ST-V frames up to 704x480 fit. Fixes #2190.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-01 06:50:07 -05:00
zanacandClaude Opus 5.5 4d5e7f3e17 Sega ST-V: faster video (VDP1 clear, VDP2 windows, tiles, sprites, rotation copy); no freeze on reset (#2192)
Video, same results:
- vdp1_clear_framebuffer: rows filled as one or two runs, eight bytes at
  a time, instead of a masked index per pixel.
- VDP2 windows: the coordinates of each line cached for the whole screen
  update (one entry per line), and the runs of pixels each line shows for
  the current layer cached too; the tiles of a window layer are drawn in
  those runs instead of testing the windows on each pixel.
- Transparent tiles: four pixels tested at once, a transparent group is
  skipped.
- Sprites: in a run of zero frame buffer pixels, four skipped at once.
- vdp2_copy_roz_bitmap: the layer settings read once per line.

Reset (#2188): the machine's timers are freed at each reset, but
machine_init only allocated the SCU DMA, hopper and SMPC INTBACK timers
when its pointers were NULL, so after a reset it adjusted freed timers
and the timer list looped forever. They are allocated at each
machine_init, as the other drivers do.

Fixes #2188


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-01 02:04:12 -05:00
zanacandClaude Opus 5.5 b168882c39 SH-2 recompiler: compare for CMP/EQ on AArch64 (ST-V black screens) (#2187)
jit_cmp() asked the flags of the compare with SLJIT_SET(cond & ~1). For
SLJIT_EQUAL that is SLJIT_SET(0), no flag at all: the x86 back ends
compare anyway, the AArch64 one does not, so CMP/EQ Rm,Rn and CMP/EQ
#imm,R0 set T from stale flags. The ST-V BIOS then took wrong branches
and games stayed on a black screen or ran with broken graphics with the
SH-2 Dynarec option on. The zero flag is now asked with SLJIT_SET_Z, as
the SH-3 recompiler already does.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-31 15:46:16 -04:00
zanacandClaude 4125e63480 CV1000: faster SH-3 bus timing and screen copy, same results (#2186)
The cache and bus timing of every SH-3 data access (and of the
instruction fetch sampled with it) was most of the time spent on ARM.
Same output, cycle for cycle:

- fast RAM regions found through a 64 KB page table
- the time of the last bus access kept in 32 bits, relative to the
  start of the timeslice (exact up to 2^30 cycles, "far" beyond, where
  the timing only compares with small counts); the 64-bit value is
  still the one saved in the states
- the tag of the most recently used way of each cache block kept next
  to it, rebuilt eagerly instead of checked on every access
- the cycle count kept in locals across the fetch and data penalties
- the timing fields at the start of the CPU state
- the screen copy in at most two runs per line, with SSE2/NEON


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-31 14:22:28 -04:00
zanacandClaude Opus 5.5 90149e76d2 Sega ST-V: cotton2e and puyosune, English translation bootlegs (#2185)
- cotton2e: Cotton 2 with the story scenes, ending and staff roll,
  continue screen hints, prologue and character profiles in English,
  from the English fan translation of the Saturn port. All eight ROMs
  differ from cotton2; https://github.com/zanac/Cotton2 builds them.
- puyosune: Puyo Puyo Sun with the win quotes, story scenes, endings,
  menus and in-game lettering in English, from the Puyo Nexus English
  translation of the Windows version. Three ROMs differ from puyosun;
  https://github.com/zanac/sega_st-v_puyosune builds them.

znpwfve (All Japan Pro-Wrestling, English) is already in master.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-31 03:13:49 -04:00
zanacandClaude Opus 5.5 273f904d7d Sega ST-V: driver, VDP1/VDP2 video and SCU from current MAME, optional SH-2 recompiler and threaded video (#2124)
- Driver, SCU (DMA, interrupts, timers, DSP), SMPC, MINIT/SINIT, EEPROM
  and the protection chips as current MAME; the current MAME sets.
- VDP1/VDP2 video as current MAME's (one stvvid.c), with exact speedups:
  partial redraw of the rotation plane cache, rotation copy, sprite
  passes, window evaluation once per line.
- SH-2 recompiler on the bundled sljit (x86, x86-64, ARM32, ARM64; the
  "SH-2 Dynarec" core option, off by default): blocks with chaining,
  page tables for direct memory access, memory handlers called from the
  blocks; the SGL idle loop is skipped exactly; context switch by
  pointer. Same output as the interpreter on all the sets.
- "ST-V Threaded Video" core option (off by default): the screen drawn
  in strips by 2-4 threads (libretro-common rthreads, where thread-local
  storage is native), same output.

Two more sets of Zen Nippon Pro-Wrestling Featuring Virtua, both on the
Taiwan BIOS (the core selects it):
- znpwfvt: All Japan Pro-Wrestling Featuring Virtua (Taiwan), as in
  current MAME.
- znpwfve: English translation (bootleg) on the Taiwan program, with the
  graphics the English mode left in Japanese redrawn; the ROMs are built
  from the original ones by https://github.com/zanac/znpwfvt


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-30 21:57:04 -04:00
mahoneyt944 df60f6466d F1en fix attract sound - JD (#2184) 2026-10-30 12:28:35 -04:00
b47967f1f2 Sega System E MC-8123, Super Hang-On, Enduro Racer backports; Zero Team save states (#2183)
System E (segasyse.c, segasyse_vidhrdw.c, mc8123.c, sn76496.c):
- MC-8123 key based decryption from current MAME: Opa Opa (317-0042)
  and Fantasy Zone II (317-0057) now run (MAME set names and keys)
- 315-5124 VDP as in MAME: per VDP status, line counter and frame
  interrupts (only VDP #1 drives /INT), output levels, per-line CRAM and
  scroll latching, front layer backdrop, mode 4 sprites
- Sega PSG clock (10.738635 MHz / 3) and noise
- trackball state saved (Riddle of Pythagoras, Megumi Rescue)

Super Hang-On (outrun.c): backport of MAME segaorun for shangon,
shangon1, shangon2, shangon3, shangon3d, shangonle (FD1089B, memory
mapper, interrupt timing, ADC, YM2151 + SegaPCM).

Enduro Racer (sharrier.c): backport of MAME segahang: FD1089B, both
8255 PPIs (mode 2 sound handshake), ADC0804, sub CPU mirrors, YM2151 and
YM2203 sound boards, Space Harrier sprites and road. Sets enduror,
endurora, endurorb, enduror1, endurobl, endurob2, endurord, enduror1d.
The Hang-On conversions shangonrb and shangonrb2 (old shangonb) use the
same code with the Hang-On main board map.

Sound:
- SegaPCM: register layout as in MAME (current address at 0x84,
  loop at 0x04), 7-bit volumes, 8-voice discrete mode, save states;
  Super Hang-On PCM pitch fixed
- Seibu sound: latches, IRQ vectors and bank saved (Zero Team save
  states, run ahead and netplay now work)


Claude-Session: https://claude.ai/code/session_014P4GcczkZTrzVfrRW8odFY

Co-authored-by: zanac <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-30 03:39:56 -04:00
zanacandClaude a1fb5c7993 Sega System C/C2 as in current MAME: segac2.c only C/C2, the Mega Drive part in machine/megadriv.c, 25 new sets (#2181)
- machine/megadriv.c / includes/megadriv.h: the Mega Drive part shared by
  the Mega-Tech, Mega Play, bootleg, Y-BOX and Sun Mixing boards (the VDP
  interrupts, also used by System C/C2, the sound Z80 and its bus, the I/O,
  the machine drivers), moved out of segac2.c; the Mega-Tech / Mega Play
  BIOS VDP ports go to megatech.c, its interrupt to megaplay.c; dead code
  removed (the unused cart maps, inputs and I/O init)
- segac2.c: only System C/C2, with the sets, ROMs, titles, inputs and DIP
  switches of current MAME (57 sets instead of 32; puyopuyo/puyopuya/puyopuyb are now
  puyoj/puyoja/puyobl, columns2 and stkclmns (Japan) are now column2j and
  stkclmnsj, with the World sets as parents)
- the protection chip as the EPM5032 logic of each game of current MAME
  (identical to the old tables where they were real; Ribbit!, Poto Poto and
  Puyo Puyo 2 had fake tables and workarounds)
- the alternate palette mode of Ribbit! and Twin Squash (control bit 2),
  through palette lookups in the VDP, instead of watching Ribbit! ROM reads
- the 68000 at XL2/6 (8.95 MHz) and the refresh at 59.92 Hz as in current
  MAME (it was XL2/7 and 60 Hz); V-INT and H-INT held until the 68000
  acknowledges them, as on the board
- YM2612/YM3438 (shared): the busy flag for 192 clocks after a data write,
  and a timer started long after its last overflow runs a whole period, as
  in current MAME
- Mega Play: the BIOS VDP V-INT about 12 lines after the Mega Drive VBLANK,
  as in current MAME (Tecmo World Cup could stay on a black screen)
- Mega Play / System E: the BIOS VDP tile lines read byte by byte (wrong
  colours on big-endian hosts)
- the address mirrors, the battery-backed work RAM (0xff filled), the coin
  meters on the I/O chip, the Waku Waku Marine / Anpanman wheel
- save states: the alternate palette mode and the Bloxeed YM3438 kludge
- metadata/mame2003-plus.xml, CHANGELOG.md


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-30 03:39:39 -04:00
zanacandClaude d7117cdcdc Save states: exact load for Ms. Pac-Man, SNK, Bubble Bobble, OPL, SCSP and Sega Model 2 (#2182)
- mspacman: the mapped ROM (decoded set or boot ROM)
- snk.c: the sound command/busy register, the sprite blink parity, the
  tile cache marked dirty after a load
- fmopl.c: the whole YM3812/YM3526/Y8950 state (channels, operators,
  envelopes, LFO, noise, timers, status, Delta-T ADPCM); replaces the
  register replay of #2045 (3812intf.c back to its earlier version)
- scsp.c: chip registers, slots, LFOs, DSP, timers, MIDI FIFOs, DMA
- model2: which CPU waits on the i960/copro FIFOs, the SCSP IRQ line
- bublbobl: ROM bank, display enable, sound NMI, MCU port latches
- m6800.c: the 6801/6803/63701 internal registers (ports, timer, TCSR,
  RAM control, WAI state)
- mb86233.c: the stall flag


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-30 02:47:53 -04:00
arcadez2003 0ad96d5104 Merge pull request #2180 from zanac/z80-busyloop
Z80: the delay-loop shortcut counts the DEC cycles
2026-10-29 22:11:06 +00:00
Claude f80f7223f4 Z80: the delay-loop shortcut counts the DEC cycles of each skipped iteration
The TIME_LOOP_HACKS shortcut skips the iterations of a
DEC rr / LD A,r / OR r / JR NZ (or JP NZ) delay loop by burning their
cycles in one go. Each skipped iteration runs four opcodes (R is
advanced by 4), but only LD, OR and the jump were counted: the DEC was
left out, so every iteration took 6 cycles too few (20 instead of 26
with JR) and such delays ran about 23% short.

Count the DEC as well, for the BC, DE and HL loops with JR and JP.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-29 18:16:53 +01:00
ff5f1bd024 mame-memory: leave read-only banks of 1 MiB or more out of the save state (#2178)
register_banks() registers the RAM behind every bank that appears in a
memory map. Banks that only ever show up in read maps are ROM (the ST-V
cartridge bank, 48 MB, or the CAGE sound-board ROM banks, 2 + 16 MB),
but they were still copied into every save state, so states were
20-53 MB for those boards, and netplay, rewind and run-ahead keep many
states at once.

Remember whether each bank appears in a write map and skip a bank of
0x100000 bytes or more that never does. RAM banks and smaller banks are
unchanged, so the state layout of other drivers stays the same. An INFO
log line reports each skipped bank.

Co-authored-by: Squirbie <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-29 06:08:50 -04:00
dfc61f1689 H6280: register CPU state; battlera/actfancr: save HuC6270 VDC and driver state (#2177)
The H6280 core registered nothing with the save-state system, and the
HuC6270 video chip of the battlera board (VRAM, registers, palette,
scanline/IRQ bookkeeping) and the driver's port select / ADPCM toggle
were not registered either. After a state load the CPU kept running
from its own PC, registers, MMR bank map and timer, and the screen was
drawn from the old VRAM, so netplay guests saw a blank or diverging
screen and rewind / run-ahead diverged.

- h6280.c: register PPC/PC/SP/ZP/EA, A/X/Y/P, the 8 MMR registers, the
  IRQ mask, timer status/ack/value/load, extra cycles and the IRQ lines
  (plus NZ with LAZY_FLAGS) per CPU in h6280_init(), as m6809_init() does.
- battlera_vidhrdw.c: register VRAM, the 20 VDC registers, the VDC
  pointers and flags, last_line (was a function-local static) and the
  palette RAM; a postload handler marks everything dirty and rebuilds
  the palette.
- battlera.c: register control_port_select, msm5205next and the ADPCM
  toggle (was a function-local static) from a new DRIVER_INIT.

Co-authored-by: Squirbie <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-29 06:06:22 -04:00
zanacandClaude c6a2aa4700 Genie / Y-BOX and Sun Mixing boards in their own drivers (megadriv_ybox.c, megadriv_sunmix.c), as in current MAME (#2179)
Phase 2.4/5 of the Sega VDP / segac2.c clean-up: Puckman Pockimon and the
other Y-BOX games, and Super Bubble Bobble (Sun Mixing), move from
drivers/segac2.c to drivers/megadriv_ybox.c and drivers/megadriv_sunmix.c,
as in current MAME.

- Sets as in current MAME: puckpkmn is the Genie 2000 set of MAME, the old
  puckpkmn set is now its clone puckpkmnb; new jingling and topshoot.
  xmvsfmb (not working in MAME) is not added: no ROMs.
- The Y-BOX games run on the Mega Drive machine, as MAME's md_ntsc (they
  ran on the System C board): 68000, Z80, the YM3438 on the Z80 bus, I/O
  (no pads), the RAM mirrors, and the VDP interrupts and HBLANK status as
  on the real hardware (genesis_enable_iack). Songjiangyanyi Final waits
  on HBLANK to write the scroll of each line: it hung on a grey screen,
  it now works (imperfect graphics, as in MAME).
- Songjiangyanyi / Shuihu Feng Yun Zhuan protection as in MAME: two read
  back latches selected by A2 (it was a list of fixed addresses), the
  0x70001c value per game, the ROM address remapping at 0x600000 of
  Shuihu Feng Yun Zhuan (an address XOR while a value is latched: the
  data reads through a handler, the opcodes through an opbase handler).
- Jingling Jiazu / Puckman Pockimon: the ID at 0x4b2476 and 0x70001c.
- Top Shooter: the shared RAM inputs of the MCU (not emulated, as in MAME).
- Save states: the protection and remapping state.
- Metadata: mame2003-plus.xml, CHANGELOG.md.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-29 06:00:09 -04:00
zanacandClaude 6266128ce8 Save states: the missing YM2203/YM2610/YM2612, MultiPCM and 6809 state (RunAhead, netplay) (#2176)
Loading a state, and so every RunAhead or netplay rollback, put back an
incomplete sound chip or CPU, and the game went on differently from the
run that never loaded: the audio of the Mega Drive based boards, Neo Geo
and the YM2203 games diverged, and on the 6809 games the game itself.

OPN chips (sound/fm.c):
- The reset sets the L/R pan of all the channels (0xb4-0xb6) and clears
  0x30-0xb2 without storing them in REGS; the postload rewrites REGS, so
  a channel the game never panned itself was muted after a load (the DAC
  of the Bare Knuckle games). The reset values are now in REGS (YM2203,
  YM2608, YM2610, YM2612), and the YM2612 DAC select too.
- The postloads of the YM2608 and YM2610 skipped 0xb6 (pan, AMS, PMS of
  the 3rd channel of each bank), as the YM2612 one did before.
- The chip recomputes its phase steps and envelope rates only when a
  register asks for it, so they can lag behind the registers (e.g. after
  a 3 slot mode change). They are now saved as they are, with the key
  codes and the LFO step, instead of being remade from the registers. The
  YM2612 and YM2610 extra state is one shared block (OPN_EXT), now also
  used by the YM2203, which had none.
- The YM2612 DAC value is saved as it is: before the first write it is 0,
  which is not what the register gives (aladmdb).
- YM2610: the extra FM and SSG state was opt-in (only zn.c asked for it);
  it is now always saved (Neo Geo). The opt-in FM timers stay as they were.

SSG (sound/ay8910.c): the periods of the SSG of a YM chip are saved as they
were made; the register rewrite of the postload remade them with the
current clock. The YM2203 now saves the SSG extra state too.

MultiPCM (sound/multipcm.c): the sample pointer of a voice was remade from
the registers at load, without the bank and with the sample number of now,
not of the key on; it is saved as its offset in the ROM. The release
counter is saved too (Star Wars Arcade).

6809 family: the M6809 did not save the accumulators (D), the HD6309 D and
W; the M6809, HD6309 and Konami did not save the cycles of an interrupt
taken outside the execute loop.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-28 23:13:45 -04:00
zanacandClaude 9649c81834 Sega Mega Drive bootlegs in their own driver (drivers/megadriv_acbl.c), as in current MAME (#2175)
Phase 2.3/5 of the Sega VDP / segac2.c clean-up: the coin-op bootlegs of
Mega Drive games move from drivers/segac2.c to drivers/megadriv_acbl.c,
with the board variants of current MAME, and the nine new sets we have
the ROMs for are added. The Mega Drive part stays shared with the other
Mega Drive based boards (includes/segac2.h).

- Moved: aladmdb, barek2ch, barek3mb, jparkmb, sonic2mb, sonic3mb,
  twinktmb (titles as in current MAME). Same code paths as before: frames
  and audio identical to the previous build.
- New: barekch, barek2mb, barek3mba, biohzdmb, bk3ssrmb, mk3mdb, srmdb,
  srssf2mb, ssf2mdb.
- The board variants of MAME: the version register, 6 button pads (MAME's
  TH counter with the 1.5ms timeout), the 3rd I/O port coins, the DIP
  switches at 0x770070 of the scrambled boards (and the coins at 0x770078
  of biohzdmb), the 6MB linear map of ssf2mdb, the PIC16C57 of barek2mb (emulated, with its latches; the
  68000 byte writes reach both halves of the bus as on the real CPU; T0
  is not connected), the simulated PIC of barek3mba.
- The new sets take V-INT / H-INT through the VDP interrupt enables, as on
  the real hardware (mk3mdb took a V-INT before its RAM vector was set
  and crashed); the moved sets keep the old mode.
- Big-endian hosts: the descrambling of the bootlegs uses BYTE_XOR_LE,
  and the PIC program of barek2mb is put in the host order the PIC core
  fetches its opcodes in.
- Mega Drive VDP: in H32 mode the sprite table base uses bit 0 of
  register 5 (AT9), as on the real VDP and in MAME; it was always masked
  as in H40 (ssf2mdb sets 0x6d in H32: the fighters were missing; the sprites
  of mt_bbros were garbled).
- PIC16C5x core: the PC wraps at the end of the program memory (the 2K
  parts start at 0x7ff and ran past the ROM), and the save states no
  longer register the ports and STATUS through R.picRAM before it is set
  (a NULL pointer: saving a game with a PIC crashed). They are in the data
  RAM, saved with the CPU memory.
- Save states: the pad, frame counter and PIC latch state.
- Metadata: mame2003-plus.xml (the bootleg entries regenerated),
  CHANGELOG.md.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-28 23:10:27 -04:00
mahoneyt944 0e919473ca Add files via upload 2026-10-28 19:36:32 -04:00
arcadez2003 fa9eea238c Merge pull request #2173 from grant2258/Makefile
Makefile (Auto-Dependency Generation)
2026-10-28 20:59:25 +00:00
arcadez2003 ad755f06ad Merge pull request #2172 from grant2258/fixit
add Sky Robo and Big Fighter mcu support
2026-10-28 20:36:18 +00:00
Grantonius maximus 5b5d6f8a23 update gitignore 2026-10-28 20:33:19 +00:00
Grantonius maximus faa5ddf4e9 Makefile (Auto-Dependency Generation) 2026-10-28 20:32:18 +00:00
Grantonius maximus 46f354464a i dont want meee gold 2026-10-28 20:22:55 +00:00
Grantonius maximus 3b41adc749 add Sky Robo and Big Fighter mcu support 2026-10-28 20:19:28 +00:00
arcadez2003 bdfdc977c2 Mention Sky Robo / Tatakae! Big Fighter now works + credits 2026-10-28 20:05:19 +00:00
arcadez2003 5e593b6462 Sky Robo / Big Fighter fix MCU commands grant2258 2026-10-28 19:55:37 +00:00
zanacandClaude da7b539232 Sega Mega-Tech in its own driver (drivers/megatech.c), as in current MAME (#2170)
Phase 2.2/5 of the Sega VDP / segac2.c clean-up: the Mega-Tech BIOS,
memory maps, inputs, machine drivers, ROMs and game drivers move from
drivers/segac2.c to drivers/megatech.c. The Mega Drive part stays shared
with the other Mega Drive based boards (includes/segac2.h); genesis_base
now starts from the plain cartridge map, each board sets its own.

- Sets, ROM names and dumps as in current MAME (good dumps of mt_bbros,
  mt_ggolf, mt_gng and mt_tetri), the instruction ROMs in the cart at
  0x300000, titles and years as in current MAME.
- The Master System carts run on the Mega Drive in Mark III mode, as in
  current MAME: the 68000 is off, the sound Z80 runs the cart with the
  Sega mapper, 8KB of RAM, the PSG and the VDP in mode 4 (the 315-5313
  variant of the 315-5124 core of MAME). Astro Warrior, Great Golf,
  Shinobi, After Burner and Parlour Games work; Great Soccer is a bad
  dump (as in MAME).
- The BIOS cart slots as in current MAME (the CXD1095 port E slot select,
  the banked RAM per slot, the 0x6000 bank latch and the 0x8000 window
  into the cart): the menu lists the cart in slot 1 only, not in all 8.
- The BIOS display: the 315-5246 224 line mode the menu uses (the MENU
  title was cut), drawn line by line, its own palette levels.
- The Mega Drive VDP line timing and partial updates count its own lines
  below the BIOS screen (segavdp line_scale; 1 for the other boards).
- The H32 games are centred in the 320 pixel screen.
- Mega Play: the BIOS overlay is transparent on colour 0 of both its
  palettes and covers its borders, as in current MAME (the boot logo
  screen was behind a green background).
- Crash fix: the 68000 writes to 0xa02000-0xa03fff went to the Mega Play
  BIOS RAM pointer, NULL on the other boards (Great Golf crashed). The
  Mega Play handler moves to drivers/megaplay.c.
- Save states: the Mega-Tech BIOS, the slots and the Mark III mode state.
- Metadata: mame2003-plus.xml (Mega-Tech entries regenerated), CHANGELOG.md.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-28 15:22:08 -04:00
zanacandClaude eb11c10f08 Sega Mega Play in its own driver (drivers/megaplay.c), as in current MAME (#2168)
Phase 2.1/5 of the Sega VDP / segac2.c clean-up: the Mega Play BIOS, memory
maps, inputs, machine driver, NVRAM, ROMs and game drivers move from
drivers/segac2.c to drivers/megaplay.c. The Mega Drive part (68000, sound
Z80, I/O chip, interrupts, sound interfaces, pads) stays shared with the
other Mega Drive based boards and is declared in includes/segac2.h; the
Mega Play interrupt acknowledge is enabled through genesis_enable_iack().

- Set names as in current MAME: mp_twc is now mp_twcup, the BIOS version 2
  ROM is epr-a15294.ic2; new clone mp_gaxe2a (Golden Axe II, original
  revision), as in MAME.
- The Mega Play save state registrations move with the BIOS; the unused
  BIOS variables (bios_game, bios_6204, bios_6402) are removed.
- Metadata: driver.c, mame2003-plus.xml (Mega Play entries regenerated),
  catver.ini, history.dat, CHANGELOG.md.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-28 15:00:00 -04:00
mahoneyt944 b3328713bb segas32 fix priority for dbzvrvs and f1lap (#2169) 2026-10-28 14:43:44 -04:00
arcadez2003 7ec7d077f2 Merge pull request #2167 from zanac/sega-vdp
Phase 1: the Sega Mega Drive VDP (315-5313) as a shared module
2026-10-28 14:13:14 +00:00
arcadez2003 5c6f346782 Come back to it later 2026-10-28 12:49:34 +00:00
arcadez2003 51e87e8a46 FFS Forgot this 2026-10-28 12:41:15 +00:00
arcadez2003 6926b424a6 Attempt to get the main and prot MCU's talking :) 2026-10-28 12:27:07 +00:00
Claude 122405bb79 Sega VDP (315-5313) as a module shared by System C/C2, Mega-Tech, Mega Play and System 18
The Mega Drive VDP was part of the System C/C2 video code and System 18 used
it through file-static state and a few flags, so a change for one board could
reach the others. It is now a module, vidhrdw/segavdp.c:

- all its state is in one struct, cleared at every start;
- each user starts it with its own configuration (struct segavdp_interface):
  where the CRAM writes go (paletteram16, or the 64 System 18 colors set
  directly at 0x1800), the initial palette bases, the scanline base of the
  partial updates, the initial display enable, whether register 12 resizes
  the screen, and the interrupt callback for writes to registers 0/1;
- the boards use accessors (segavdp_get_reg, segavdp_set_palbank, ...);
- vidhrdw/segac2_vidhrdw.c keeps only the C/C2, Mega-Tech, Mega Play and
  bootleg video glue, vidhrdw/segas18.c the System 18 one.

Fixed on the way (state left over from a previous game in the same process):
the display enable and the Mega Play interrupt-acknowledge/HBLANK mode
(now also reset by the C/C2 machine init). The window X
position/width and the VBLANK flag are now in the save states. The dead
ddcrew/aquario VDP kludges of the old System 18 video are removed.

Save states loaded in a new instance (netplay, RunAhead with a second
instance) now continue exactly as the instance that saved them:
- Mega Drive based boards (drivers/segac2.c): the Z80 RAM and bus state
  (running flag, bank latch) and the Mega-Tech / Mega Play BIOS registers
  and RAM were not saved (mp_gunhe and mp_mazin went out of sync);
- sound/sn76496.c: the PSG had no save state at all;
- sound/fm.c: the YM2612 postload read the DAC enable from register 0x2d
  instead of 0x2b (the DAC channel was lost or computed as FM after a load).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-28 09:51:57 +01:00
arcadez2003 f51acae279 terraf_io_w 2026-10-28 00:43:49 +00:00
arcadez2003 02beadf6c1 hmmmmm 2026-10-28 00:30:19 +00:00
arcadez2003 c542bf7d24 Forgot cant share via port io's in this core 2026-10-28 00:11:52 +00:00
arcadez2003 4d19fd28b8 Adjust the MCU mem and port loading 2026-10-28 00:05:49 +00:00
arcadez2003 34bf3c28c6 Merge pull request #2165 from zanac/cotton
Sega System 18 and Cotton from current MAME
2026-10-27 23:41:19 +00:00
arcadez2003 ca185b19ad skyrobo and bigfghtr 2026-10-27 19:55:15 +00:00
arcadez2003 a2960b3fca Support Sky Robo / Tatakae! Big Fighter hook up I8071 MCU
With thanks to AdvanceMAME

MAME WIP

0.182: Dumped i8751 MCU for Sky Robo / Tatakae! Big Fighter and added basic hookup to make it work - Game now playable. Fixed screen refresh rate in Tatakae! Big Fighter [Team CAPS0ff, Angelo Salese]. Fixed service switch and updated DIPS/inputs with locations and content to match those showing on screen and observation [Tafoid]. Added debug code for initial area and promoted game to working [Angelo Salese]. Clocks verified for Sky Robo / Tatakae! Big Fighter [Guru]. Documented DACs for clone Tatakae! Big Fighter (Japan) [AJR]. Added I8751 (8MHz) CPU3. Changed VSync to 59.314620 Hz.

0.142u2: Angelo Salese merged Tatakae! Big Fighter driver into ArmedF driver.

0.141u1: Changed Z80 CPU2 clock speed to 4MHz.

0.140u3: Angelo Salese fixed service mode and removed ROM patches in clone 'Tatakae! Big Fighter'. Changed description of clone 'Tatakae! Big Fighter' to 'Tatakae! Big Fighter (Japan)'.

0.113u2: Stefan Lindberg added 'Sky Robo' (Nichibutsu 1989).

0.86: Tomasz Slanina added 'Tatakae! Big Fighter' (Nichibutsu 1989). TODO: Scroll, controls and dips.

15th August 2004: Tomasz Slanina - Tatatake! Big Fighter preliminary driver (based on my old one). Game doesn't work due to protection (RAM shared with 8751 MCU).

1st September 2003: Tomasz Slanina - VERY preliminary Tatake! Big Fighter driver. Unemulated protection (MCU). Only attract mode is working. Partially...
2026-10-27 19:51:44 +00:00
Claude 7d3a3547e3 Sega System 18 and Cotton from current MAME (FD1094 sets, mapper, VDP, save states)
Cotton (System 16B): the FD1094 sets cotton, cottonu, cottonj and cottonja
now run, with the decryption of machine/fd1094.c (from Moonwalker), and the
missing bootlegs cottonud, cottonjd and cottonjad are added. The dummy
cotton/cottona of system16.c are removed.

System 18: the games run on the 315-5195 mapper layout each of them sets
(read from MAME), the segaic16 video and the VDP layer, as in MAME's
segas18.cpp:
- Alien Storm (astorm, astorm3, astormu, astormj and bootlegs), Bloxeed
  (bloxeed, bloxeeda, bloxeedd), Clutch Hitter (cltchitr, cltchitrj and
  bootlegs), D. D. Crew (the six FD1094 sets and their bootlegs, 4 players
  through the 8255), Desert Breaker (desertbr, desertbrj and bootlegs),
  Laser Ghost (lghost, lghostu, lghostj and bootlegs, light guns through
  the MSM6253, MAME's gun offset correction), Wally wo Sagase! (wwallyj,
  wwallyja, wwallyja3p and bootlegs, uPD4701 trackballs), Shadow Dancer
  (shdancer, shdancerj, shdancer1, were shdancer, shdancrj, shdancrb).
- 171-5987 ROM board: ROM 1 at 200000, tile and sprite banking, 1MB and
  2MB program ROMs; fd1094.c decrypts several address windows.
- The VDP layer shows one frame after the other layers, as in MAME, and the
  VDP sees the VBLANK (VIDEO_EOF of segac2) for its partial updates.
- astormbl, shdancbl, moonwlkb, aquario, hamaway and mwalk are unchanged.

Save states (RunAhead, netplay):
- System 16B: uPD7759, sound ROM bank, segaic16 tilemap and sprite banks,
  flip, scroll latches, display enable.
- System 18: RF5C68 (registers and wave RAM), YM2612/YM3438 (envelope and
  LFO counters, key, frequencies, algorithm memory, FM timer overflow time;
  the postload also rewrites the b6/1b6 registers), sound ROM bank, VDP
  layer, mapper and I/O registers.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-27 11:53:07 +01:00
markwkidd 993403d033 Merge pull request #2159 from markwkidd/cpu-clock-core-options
Add a CPU Clock Scale core option for each CPU
2026-10-26 16:20:17 -04:00
zanacandClaude Opus 5.5 64b3c38ac6 Sound: 0-100 volume standard for the mixer and samples, fix filter.c float build (#2164)
- sample_set_volume()/sample_set_stereo_volume() take 0-100 like the
  mixer. The 0-255 callers are converted with identical results; Sea Wolf
  II and Thief get the full volume they meant, and the Sea Wolf II dive
  channels (always silent) work as in MAME 0.264.
- The mixer clamps volumes, mixing levels and default levels to 0-100.
  The old 0-255 default level conversion is removed; the drivers that
  used it get its result (25) explicitly. Buggy Boy's doubled YM2149 gain
  is kept with a doubled mixing level.
- filter.c: the non-integer build did not compile and scaled the
  coefficients twice; both builds now divide by the gain.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-26 13:31:46 -04:00
markwkidd 42176a69d1 Fix discrete adjuster ports and defaults (#2161) 2026-10-26 03:51:14 -04:00
bbb49d84d7 PSX GPU: 11-bit signed coordinates for rectangles, sprites, lines and dots (#2162)
Soul Calibur draws the attract transitions (the windows that open from
the title screen onto the next scene, and the wipes before each demo)
with rectangles whose coordinates only make sense as 11-bit signed
values. The core took them as 16-bit values, so the rectangles were
drawn in the wrong place or not at all, and the new scene showed
through white or washed out instead of in full colour.

As in current MAME (S11_COORD_X / S11_COORD_Y), rectangles, 8x8 and
16x16 sprites, lines and dots now take 11-bit signed coordinates, like
the polygons already did. The frame buffer fill (GP0 02h) keeps its
unsigned coordinates.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Vanni Brutto <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-26 03:49:56 -04:00
markwkidd 79a4e690a4 Update descriptions for core resolution options (#2155) 2026-10-26 03:48:57 -04:00
Mark W. Kidd 75f4dbb1d9 Name the romset in the CPU Clock Scale core option keys 2026-10-25 22:53:22 -04:00
arcadez2003 fd95cd4b28 Mention Heavy Unit and new code contributors 2026-10-25 23:39:17 +00:00
Mark W. Kidd e0815b5b43 Add a CPU Clock Scale core option for each CPU 2026-10-25 19:26:21 -04:00
arcadez2003 f584d820f6 Merge pull request #2158 from sunlollyking/model1-tgp-names
Model 1: rename the TGP's fadd, fsub, fmul, fdiv and fsqrt
2026-10-25 23:23:45 +00:00
arcadez2003 d373dcb4b1 New ones 2026-10-25 22:35:19 +00:00
Chris 0c777d48e6 Model 1: rename the TGP's fadd, fsub, fmul, fdiv and fsqrt
glibc declares fadd, fsub, fmul, fdiv and fsqrt in math.h for C23, and
GCC 15 builds as C23 by default, so the static TGP functions of the same
names conflict with them and model1_machine.c no longer builds. They are
tgp_fadd and so on now.
2026-10-25 22:33:44 +00:00
arcadez2003 8a0a74c79f Merge pull request #2154 from libretro/arcadez2003-patch-8
Add the two missing games to the Cave CV1000 driver
2026-10-25 22:31:03 +00:00
arcadez2003 4060e4c8e1 Hush Hush On The QT 2026-10-25 22:29:56 +00:00
arcadez2003 1f8b8b71b1 Try again another time 2026-10-25 22:15:46 +00:00
arcadez2003 ae45f94fc9 Revert for now 2026-10-25 22:15:04 +00:00
arcadez2003 e7b2e2706c FFS 2026-10-25 22:08:32 +00:00
arcadez2003 cf8d7da002 Update YGV608 namcond1 video code to MAME 113 part 2 2026-10-25 21:48:53 +00:00
arcadez2003 bbf2784396 Update YGV608 namcond1 video code to MAME 113 2026-10-25 21:47:29 +00:00
arcadez2003 7a361d0dad Merge pull request #2156 from zanac/mariner-sound
Mariner / Triple Punch: AY-8910 clock of current MAME, new clones; Galaxian/Scramble hardware save states
2026-10-25 21:09:21 +00:00
Claude ce9db6e3cc Mariner, Triple Punch: AY-8910 clock of current MAME, new clones; Galaxian/Scramble hardware save states
- AY-8910 of the Triple Punch board (Triple Punch, Knock Out!!, Mariner,
  800 Fathoms) at 18432000/12 = 1.536 MHz, as current MAME ("verified on
  hardware"): the sound was 16.7% too high and too fast. Mariner keeps
  GAME_IMPERFECT_SOUND: its discrete sound circuits are not emulated, in
  current MAME either; 800 Fathoms gets the flag, as in MAME
- new clones from current MAME: triplepa, knockoutb, knockoutc, 800fatha
  (names and manufacturers of the sets as in MAME)
- save states of the Galaxian/Scramble/Frogger hardware (rollback, RunAhead,
  netplay diverged):
  - Galaxian video: star scroll/blink state, star timer start, flip, graphics
    banks, background and bullet colors, rockclim scroll; a postload restores
    the tilemap flip, column scroll and tiles
  - 7474 flip-flops (machine/7474.c), registered by TTL7474_config
  - Scramble sound: the sound CPU RAM (scobra map) in the saved memory, the
    AY port B timer computed from the sound CPU cycles as current MAME
    (no state, no 32-bit overflow; same values)
  - RC filters of the sound streams (streams.c) and the global sound enable
    (mixer.c)
  - Galaxian sound statics (LFO, noise, tone generator)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-25 21:12:09 +01:00
arcadez2003 0742497860 Merge pull request #2152 from zanac/tx1
Tatsumi TX-1 / Buggy Boy from current MAME
2026-10-25 20:08:32 +00:00
arcadez2003 02cbb28183 Merge pull request #2151 from zanac/ymf278b-state
YMF278B, YMF262 and Fuuki FG-3: save states
2026-10-25 20:03:31 +00:00
arcadez2003 aca3960858 Add the two missing games to the Cave CV1000 driver
redone as per recent commits
2026-10-25 20:03:01 +00:00
arcadez2003 daf2acebc9 Merge pull request #2143 from zanac/mwalk
Moonwalker: the original System 18 board (FD1094 + 8751)
2026-10-25 19:38:30 +00:00
arcadez2003 f8aebaebbc Merge pull request #2153 from zanac/toaplan2-savestates
Toaplan 2: save states, RunAhead and netplay
2026-10-25 19:15:05 +00:00
arcadez2003 9dcf3f94ed Merge pull request #2150 from zanac/toaplan2-v25
Toaplan 2: NEC V25 sound CPU (Dogyuun, Knuckle Bash, FixEight, Grind Stormer / V-Five, Batsugun)
2026-10-25 19:08:06 +00:00
Claude ccdf3afc6a Tatsumi TX-1 / Buggy Boy from current MAME (TX-1, Buggy Boy, Buggy Boy Junior) Closes #1478
The driver of current MAME (Phil Bennett) in C89: the two 8086 CPUs and the
arithmetic unit, the road, object and character layers of the three screens,
the engine/noise sound with the AY-8910 / YM2149s, save states.

- 6 sets: tx1, tx1jb, tx1jc, buggyboy, buggyboyb, buggyboyjr
- the cockpit sets show their three screens side by side (768x240, 12:3), or
  only the middle one with the new core option "TX-1 / Buggy Boy Screens"
  (offered for those sets only)
- i86 core: the TEST input (WAIT instruction) and an opt-in 16-bit data bus
  (an aligned word is one access for the handlers); both off by default, the
  other i86/i186 games run as before
- the layer select and the TX-1 road pixel logic are lookup tables built
  from MAME's logic: same pixels, TX-1 about 40% faster

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-25 19:42:25 +01:00
VanniandClaude Opus 5.5 e764a06a04 Toaplan 2: save states, RunAhead and netplay (video, driver state, V25 timers)
The frames after loading a state are now the same as after the save, in
every Toaplan 2 / Raizing game, also when the state is loaded in the same
process as RunAhead and netplay do at every frame.

- Video (toaplan2_vidhrdw.c): the RAM of the GP9001 controllers (layers,
  sprites), their registers (scroll, flip, VRAM offset), the RAM of the
  68000 map written through a handler (palette, text layer, text tiles),
  as MAME's GP9001; after a load the tilemaps get their scroll and flip
  again and the text tiles in RAM whose bytes changed are decoded again
  (Batrider and Battle Bakraid: from a copy of the RAM when they were
  decoded).
- Driver: scanline counter, sound CPU latches and replies, Z80 bank,
  Raizing and FixEight bootleg OKI banks, Ghox paddles, the 68000 side of the Dogyuun location
  test shared RAM (now allocated once, 0x1000 bytes).
- V25: the timers are in the timer state; after a load only the clock
  divider is set again.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-25 18:11:56 +01:00
Claude 0c9afd4989 YMF278B, YMF262 and Fuuki FG-3: save states
None of the YMF278B (OPL4 PCM), YMF262 (OPL3) or Fuuki FG-3 state was in
the save states: after a load (RunAhead, netplay rollback, rewind) the
sound kept the voices of the frames run before the load, the YMF278B
timers and IRQ their old values, the sprites buffered by two frames and
the RAM shared by the two CPUs of the FG-3 too.

- YMF278B: every slot, the chip registers, timers and IRQ state.
- YMF262: every slot and channel, the chip registers; the slot outputs
  (pointers to the channel outputs) are saved as indexes.
- Fuuki FG-3: the two buffered sprite RAMs and tile banks, the shared RAM.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-25 17:09:58 +01:00
VanniandClaude Opus 5.5 127a425837 Toaplan 2: NEC V25 sound CPU (Dogyuun, Knuckle Bash, FixEight, Grind Stormer / V-Five, Batsugun)
New NEC V25 CPU core (src/cpu/nec/v25.c), a port of MAME 0.264's v25.cpp
and v25sfr.cpp, with the opcode decryption tables of the Toaplan chips.

The Toaplan 2 games with a V25 now run their sound program as in MAME
0.264, in place of the sample tables (Knuckle Bash, Batsugun) or no sound
(Dogyuun, Grind Stormer, V-Five). FixEight works: its V25 reads the inputs
and the EEPROM holding the settings and the region.

- 68000 and V25 memory maps, clocks, shared RAM, the V25 reset (coin
  register and RESET instruction), DIP switches and jumpers read by the V25.
- The GP9001 video status as in MAME (blank in the horizontal sync too):
  the boot RAM tests of these games now take the same time as in MAME.
- Sets and names of MAME 0.264: new dogyuuna, dogyuunb, dogyuunt, kbashk,
  kbashp, batsuguna, batsugunc, batsugunb, 13 FixEight regional sets;
  grindsta -> grindstma, batugnsp -> batsugunsp, fixeighb -> fixeightbl;
  grindstm is now the parent of vfive; new ROMs for dogyuun and batsugun.
- Memory: no save state zone for a CPU without a memory region.
- Metadata (xml, history, cheats, catver) and frontend list updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-25 17:00:58 +01:00
zanacandClaude eedb4b5ce0 CV1000: about 40% faster (SH-3 cache model, recompiler, SSE2/NEON blitter), same results (#2149)
- SH-3 cache model: a fast path for a hit in the most recently used way
  of its block (no LRU update, no miss handling); the bus timing inlined
  in the memory accessors.
- SH-3 recompiler: block table of 512K entries instead of 64K (two code
  areas of some games shared the entries and recompiled each other).
- SH-3: memory accessors inlined, the fast RAM region of the previous
  access first; DMA byte transfers to fast RAM without a region lookup
  per byte.
- Blitter: uploads a row at a time; draws 8 pixels at a time with SSE2
  or NEON, the blend tables computed exactly (T(a, b) = (a * b) / 31 =
  mulhi(a * b, 2115) for every product up to 31 * 63). The C loop stays
  for the other hosts.

The save states are byte-identical to before, with the interpreter and
with the recompiler.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-25 11:35:37 -04:00
zanacandClaude Opus 5.5 65456ae709 Random numbers: the emulation's generator in place of the C library's rand()): (#2144)
* Random numbers: the emulation's generator in place of the C library's rand()

The C library's rand() gives other numbers on each host and C library,
and its state is not in the save states: the games using it (the
Astrocade noise, the speech chips, the HuC6280 noise...) ran differently
after a state load (RunAhead, netplay rollback, rewind) and on another
host (netplay).

The code that only changes the picture gets a generator of its own, also
in the save states: the screen updates don't run on the skipped frames,
and the frameskip depends on the host speed.

Radar Scope's star noise compared mame_rand() with RAND_MAX, which is
0x7fff on MSVC.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

* Astrocade sound: the noise counter of the chip, not of the sample

The noise byte was refreshed reading current_count_N[i], with i the
sample position (up to the samples per frame), out of the array of two:
other variables and whatever follows them in memory, which is not the
same on every host and compiler.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

---------

Co-authored-by: Claude <[email protected]>
2026-10-25 09:23:14 -04:00
zanacandClaude ff31c50883 Astrocade: save states (sound chip, video, machine, speech) (#2145)
Nothing of the Astrocade games was in the save states: after a load
(RunAhead, netplay rollback, rewind) the interrupt and colour registers,
the magic RAM and pattern board, the sound chip and the speech word
being built kept their values from the frames run before the load.

The pattern board registers, the colour block counter and the Gorf timer
skip counter were static in their functions; they are now file statics.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-25 09:22:39 -04:00
zanacandClaude Opus 5.5 650346ec75 Cave CV1000: SH-3 (SH7709S) with recompiler, driver, EPIC12 blitter, YMZ770 Closes #751 (#2146)
* Save states: the audio frame length (samples per frame) and its fraction

When the frame rate doesn't divide the sample rate, the frames alternate
their number of samples; where they are in that was not in the save state,
so after a load the mixer asked the streams for a different number of
samples and the audio drifted from the run that never loaded (netplay CRC
mismatches in the mixer state, RunAhead audio).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

* Cave CV1000: SH-3 (SH7709S) with recompiler, driver, EPIC12 blitter, YMZ770

The Cave CV1000-B and CV1000-D games (Mushihime-Sama, Ibara, Espgaluda II,
Muchi Muchi Pork, Pink Sweets, Mushihime-Sama Futari, Deathsmiles, DoDonPachi
Dai-Fukkatsu and their sets), ported to C89 from current MAME:

- src/cpu/sh3: the SH7709S interpreter (current MAME's SH-3 with the cycle
  counts of MAME's recompiler and its cache and bus timing model), the
  interrupt controller, timers, DMA, ports.
- src/cpu/sh3/sh3jit.c: an SH-3 recompiler on sljit with the same results
  as the interpreter, cycle for cycle (save states, netplay and RunAhead
  don't depend on it); core option "SH-3 Dynarec", on by default, offered
  on x86, x86-64, ARMv7 and AArch64.
- src/drivers/cv1k.c: memory maps, NAND flash, RTC9701, idle loop
  speedups, the sets.
- src/vidhrdw/cv1k_vidhrdw.c: the EPIC12 blitter (16-bit VRAM).
- src/sound/ymz770.c and the AMM variant of MPEG audio in mpeg_audio.c.

Everything is in the save states. Details in docs/cave-cv1000.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

---------

Co-authored-by: Claude <[email protected]>
2026-10-25 09:22:06 -04:00
VanniandClaude Opus 5.5 3a553e7fb4 Moonwalker: the original System 18 board, with FD1094 and 8751
The original sets now run: mwalk, mwalku and mwalkj (FD1094 encrypted 68000)
and their decrypted versions mwalkd, mwalkud and mwalkjd, as in MAME 0.264.
moonwalk and moonwlka are renamed to the current MAME names (mwalk, mwalku).

- machine/fd1094.c: FD1094 decryption (the algorithm of MAME's fd1094.cpp,
  BSD-3-Clause). The decrypted opcodes are cached per state and fetched
  through the 68000 opcode base; the state follows CMPI.L #imm,D0, the
  interrupts and RTE through new hooks in the C 68000 core (NULL unless an
  FD1094 game runs).
- system18.c: the 8751 (315-5437) drives the game through the 315-5195
  mapper registers (68000 interrupts, 68000 memory reads and writes, sound
  CPU latches, 68000 reset), as MAME's system18_i8751. The game uses the
  segaic16 video like ddcrew, with the 171-5874 tile banking.

The FD1094 sets give the same frames as the decrypted ones, and the attract
mode and the first 2140 frames of a scripted game match MAME 0.264 pixel for
pixel.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-25 08:59:27 +01:00
zanacandClaude cc7b0dd9a1 Makefile: no fused multiply-add (-ffp-contract=off) (#2142)
GCC and clang fuse a*b+c into one FMA instruction where the CPU has one
(AArch64, ARMv7 VFPv4, PowerPC): rounded once instead of twice, so the
floating point results differ from x86, where there is no FMA in the
baseline instruction set. With the flag every host computes the same
values: netplay between x86 and ARM, save states and RunAhead.

x86 and x86-64: the generated code is the same with and without the flag.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-25 03:25:40 -04:00
d57fdfe4ee hvyunit: boots and plays (#2140) (#2141)
The black screen came from the protection MCU (Mermaid, i8051) clock: this
core takes the i8051 clock already divided by 12 (I8051_CLOCK_DIVIDER, as
the System 1 8751), the driver gave the 6MHz crystal, so the MCU ran 12
times too fast and its handshake with the slave Z80 never completed.

With that, the rest of the driver is brought in line with current MAME's
hvyunit.cpp:
- the slave Z80 <-> MCU latches as MAME's generic_latch_8 (reading a latch
  clears it, P0 bit 0 low reads the slave's byte and acknowledges INT0,
  P0 bit 4 updates the coin counters and lockouts), MCU ports at 0xff on
  start;
- the slave's vblank interrupt is held until it acknowledges it on port
  0x0e (it was the coin counter);
- the master's interrupts at lines 240 (vector 0xfd) and 64 (0xff);
- the YM2203 interrupt drives the sound CPU (no more vblank interrupt).

All four sets boot and play the first stage; the death/respawn sequence
and the music tempo match MAME 0.264.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-25 03:23:05 -04:00
zanacandClaude 4c70822b8f CPS1/CPS2: complete the save states (#2136)
Rollback (RunAhead, netplay) diverged on CPS2 games: the raster interrupt
counters, the object RAM bank, the sprite priorities and the latched
sprite lists were not saved, and the palette cache kept the values of the
discarded frames. The EEPROM didn't save its "sending" flag either.

- save scanline1/2, scancalls, scancount (moved out of cps2_interrupt),
  the object RAM bank, the sprite priorities and the buffered sprite lists
- after a load, recalculate the video RAM pointers and rebuild the whole
  palette on the next update
- EEPROM: save the "sending" flag


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-24 21:44:15 -04:00
arcadez2003 ef0071b1bd Merge pull request #2139 from libretro/arcadez2003-patch-6
hvyunit sets
2026-10-25 00:44:43 +01:00
arcadez2003 9e2bb67fe4 Merge pull request #2138 from libretro/arcadez2003-patch-5
Declare hvyunit.c
2026-10-25 00:44:28 +01:00
arcadez2003 30ed1cd5ad Merge pull request #2137 from libretro/arcadez2003-patch-4
New driver for Heavy Unit
2026-10-25 00:44:14 +01:00
arcadez2003 3e2c0db497 hvyunit sets 2026-10-25 00:17:01 +01:00
arcadez2003 38d906cb98 Declare hvyunit.c 2026-10-25 00:13:32 +01:00
arcadez2003 084b3535b3 New driver for Heavy Unit 2026-10-25 00:11:52 +01:00
arcadez2003 e49db47d7d paletteram_xxxxRRRRGGGGBBBB split types 1 and 2 2026-10-25 00:02:40 +01:00
arcadez2003 d87508ce4f New paletteram split types 2026-10-24 23:59:34 +01:00
arcadez2003 4fd1c76422 Merge pull request #2135 from zanac/seibuspi-v2
Seibu SPI and SYS386I: driver and i386 CPU from current MAME (57 sets)
2026-10-24 17:17:44 +01:00
zanacandClaude c262d4a4b6 Random numbers: the generator of current MAME, in the save states (#434, #445, #212) (#2132)
The drivers used the C library's rand() for game logic (protection,
hardware reads, the 4-way joystick restrictor). Its numbers:
- differ between C libraries (glibc, MSVC, bionic, macOS), so two netplay
  machines on different systems get different numbers;
- come from one sequence shared by the whole process: the frontend and the
  core's own drawing and sound code take numbers from it too, so how many
  the game gets depends on them;
- are not in the save states, so after a load (RunAhead, netplay rollback,
  rewind) the game gets other numbers than the first time.

mame_rand() is now the generator of current MAME (running_machine::rand()
in src/emu/machine.cpp): a linear congruential generator with MAME's seed,
rotated by 16 bits, whose 32-bit state is in the save states. It replaces
the Mersenne Twister of 0.78, whose state was not saved. mame_rand_int()
gives the same range as rand(). The rand() calls that change the state of
the emulation now use it; the ones that only draw, make sound noise or fill
memory at startup are unchanged.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-24 12:08:55 -04:00
zanacandClaude c47cda1f40 Save states: timer system and CPU scheduling (#434, #445, #212) (#2133)
A save state did not include the timer system: after a load, every timer
(interrupts, sound chip timers, CPU synchronizations, driver timers) went on
from where the running emulation was, not from the state. The CPU
scheduling state was also missing. So a loaded state ran differently from
the run it was saved from: RunAhead, netplay rollbacks and rewind replayed
the frames with other timings.

- timer.c: the timer pool and lists are saved, with the same fields as
  current MAME (param, enabled, period, start, expire). Pointers are saved
  as pool indexes and callbacks as their distance from timer_init(), which
  is the same on every machine running the same build; a fingerprint of the
  build is saved with them, and a state from another build loads without
  the timers, with a warning. Unlike current MAME, temporary timers
  (timer_set) are saved too: 0.78 drivers use them across frames. A new
  timer takes the lowest free slot, so a machine reset allocates the same
  slots again.
- cpuexec.c: suspend and eat-cycles states, trigger, interrupt loops,
  vblank countdown and frame number, as current MAME saves them in
  device_execute_interface, restored when the timers were loaded.
- cpuint.c: no second interrupt event timer after a load.
- Z80: the cycles taken by an interrupt. AY8910: the chip state.
- Input ports: the 4-way joystick states, the impulse and pressed states and
  the analog positions, which depend on the previous frames.
- libretro: retro_unserialize() refused to load at frame number 0, to block
  the automatic state loading at startup. A machine reset also sets the
  frame number to 0, so a rollback over the frame after a reset failed. It
  now refuses only until the first frame has run.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-24 12:08:34 -04:00
bc75df8087 Vector resolution: applied while the game runs (#435) (#2130)
Changing the Vector Resolution core option no longer needs a restart. At
the next frame the core resizes the display and gives the frontend the new
size with RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO (it can grow past the old
maximum).

- mame.c: vector_resize_display() does what vh_open() does for the
  display: the size from the option, the artwork, a new screen bitmap,
  the visible area again.
- artwork.c: artwork_resize_display() keeps the loaded artwork and makes
  again what depends on the size: the layer bitmaps, the scaled pieces,
  a driver's generated overlays (drawn at the game's size), the UI areas;
  the next frame is drawn whole, not from the vector dirty pixels. The
  palette lookup is allocated once per game.
- vector.c: the pixels drawn on the old bitmap are forgotten, and the next
  refresh does not compare with the old vector list.
- common.c: auto_free_ptr() / auto_bitmap_free() free one auto_malloc
  block before its tag ends, so the old bitmaps don't pile up.
- core_options.c: the option is applied only when it really changes (other
  options no longer reset the size the artwork chose).

The frames after a change are identical to a game started at that
resolution (Lunar Lander: no artwork, .art backdrop/overlay, a generated
overlay with disks; 640x480, 1600x1200, original), memory stays flat over
61 changes, and without a change the output matches master.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-24 12:01:06 -04:00
zanacandClaude ea58c97b57 GAME_DOESNT_SERIALIZE: own flag bit, it was IMPERFECT_SOUND | WRONG_COLORS (#212) (#2131)
GAME_DOESNT_SERIALIZE was 0x0420, which is GAME_IMPERFECT_SOUND (0x0400)
plus GAME_WRONG_COLORS (0x0020). state_get_dump_size() tests
flags & GAME_DOESNT_SERIALIZE, so every game flagged with imperfect sound
or wrong colors (323 games) reported a save state size of 0: no save
states, rewind, RunAhead or netplay, and the startup warning said the
game doesn't support save states. No driver uses the flag itself.

It now has its own bit, 0x0800, which no other flag uses.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-24 11:58:08 -04:00
Claude 14e3abc89f Seibu SPI and SYS386I: driver and i386 CPU from current MAME (57 sets)
- i386 CPU core: the C core of MAME 0.139 (mame2010-libretro), on the
  0.78 CPU interface, with save states. Fast memory: the driver gives
  its plain RAM and ROM, which the CPU fetches, reads and writes
  directly (a cached region per kind of access) instead of through
  the memory handlers.
- Seibu SPI driver from current MAME: the SXX2C main board with its
  cartridges, the SXX2E / SXX2F / SXX2G single boards and SYS386I.
  Senkyu / Battle Balls, Viper Phase 1, Raiden Fighters, Raiden
  Fighters 2 and Raiden Fighters Jet, 57 sets.
- Video, the CRTC, the tile and sprite decryption (SEI252, RISE10,
  RISE11) as current MAME.
- DS2404 RTC from current MAME. Its 256 Hz tick keeps the time it had
  left across a save state.
- intelfsh: 8-bit chips, the E28F008SA of the SPI main board.
- YMF271: the clock in the interface (16.384MHz on SXX2G).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-24 17:54:15 +02:00
arcadez2003 ac620b3686 Merge pull request #2134 from zanac/ikarijpb-dualstick
Closes #1581. **Ikari (joystick hack bootleg)** (`ikarijpb`) can now be played with two sticks
2026-10-24 15:59:23 +01:00
Claude bd64b9de5e ikarijpb: dual stick aiming with the right stick, as a DIP switch (#1581)
The bootleg has no rotary joystick: the game reads the direction the
player faces, and fires to, in the upper nibble of the joystick port, and
snk_rot8_ikarijpb() sets it from the joystick, so the player fires where
he walks. A new 'Aim with Right Stick' setting (a DIP switch that is not on
the board, Off by default) makes a pushed right stick set it instead: the
player walks with the left stick and aims with the right stick, in 8
directions. With the right stick released, the direction follows the
joystick again.

The right stick inputs (P1 Aim, P2 Aim) default to the right analog stick
of each player, and to I/J/K/L for player 1. They are read only by the
driver, not by the game. With the setting Off the game runs as before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-24 15:19:06 +02:00
zanacandClaude 196f1d69d3 libretro: ignore controller ports past the 8 players of the core (#445) (#2129)
retro_set_controller_port_device() wrote options.active_control_type[in_port]
for any port. That array has MAX_PLAYER_COUNT (8) entries, but RetroArch
sets the device of all its users, and on a netplay client it sets all 16
netplay ports (the host's devices, in NETPLAY_CMD_SYNC). Ports 8-15 then
overwrote the options that follow the array: restrict_4_way, tate_mode,
crosshair_enable/appearance, mame_remapping, samplerate, use_samples /
mips_dynarec / adsp_dynarec / use_alt_sound and brightness.

On a netplay client this turned on the alternate 4-way restrictor and TATE
mode, so with the same inputs a 4-way game ran differently on the client
than on the host (desync). Ports past MAX_PLAYER_COUNT are now ignored.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-24 04:52:48 -04:00
grant2258 2173c6021d llander map thruster too up/down (#2128) 2026-10-23 22:34:30 -04:00
arcadez2003 ab56912e49 Merge pull request #2127 from zanac/ymf271-stereo
The YMF271 sends its left output to the right speaker and its right output to the left one. This PR swaps them back.
2026-10-23 23:37:56 +01:00
Claude bf0dc9c8c0 YMF271: left and right outputs were swapped
The stream channels took the interface volumes in the wrong order:
channel 0 (the chip's left output) got the high 16 bits of
YM3012_VOL, the right one. Regression of #2100: before it the chip
output the same mix on both channels, so the order did not show.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-23 23:45:22 +02:00
zanacandClaude 03fc843ad8 Namco System 10: MEM(M), MEM(N) and EXIO(G) boards from current MAME (14 sets) (#2125)
The PSone based board with its ROM boards, from current MAME namcos10.cpp,
ns10crypt.cpp and nandflash.cpp:
- MEM(M): the Intel 28F640J5 flash (new in intelfsh, with the StrataFlash
  write buffer), the mask ROM banks, the type 1 decrypter (Mr. Driller 2)
- MEM(N): the Samsung K9F2808U0B NAND flashes, DMA channel 5, the type 2
  decrypter with the tables of each game
- the scramble of the data and of the boot loader copied to the BIOS space
- the I/O registers (inputs, DIP switches, EXIO ident, I2C, IRQ 10 at 100Hz)
- EXIO(G) without its MCU: the light gun counters of Point Blank 3 and
  Gunbalina
- the PSX DMA can end the GPU linked lists after 500 system clocks as MAME,
  for the drivers that ask for it (the movies of Point Blank 3)

Sets: mrdrilr2, mrdrilr2j, mrdrilr2u, gjspace, knpuzzle, mrdrilrg, chocovdr,
gamshara, gamsharao, panikuru, startrgn, konotako, ptblank3, gunbalina.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-23 15:07:52 -04:00
zanacandClaude 652fd97a6d n8080: Helifire uses 8 bits per gun output (#1150) (#2123)
The sky and sea gradients of Helifire are 256-level red and blue ramps.
Without VIDEO_NEEDS_6BITS_PER_GUN the core outputs RGB565, so they show
as 32 color bands. The flag makes the core use XRGB8888 for this machine.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-23 12:33:59 -04:00
arcadez2003 b79eb3e9fa Merge pull request #2118 from zanac/taito-gnet
Taito G-NET: the 39 games of current MAME, PC card games copied into flash, Zoom sound
2026-10-23 16:16:56 +01:00
arcadez2003 c0de8d54ba Merge pull request #2122 from zanac/asurabus-sets
Asura Buster: fix repeated sounds (YMF278B key on), sets and DIP switches from current MAME (#911)
2026-10-23 15:45:56 +01:00
Claude ce92716fca fuukifg3: Asura Buster sets and DIP switches from current MAME, fix repeated sounds (#911)
Sound: the sound program of Asura Buster and Asura Blade writes the key
on of a PCM slot again about once a second while the sound plays, with
the key already on. The 0.78 YMF278B restarted the sample on every key
on write, so voices and sound effects were repeated. As in current MAME,
the key on bit is now tracked per slot and a sample is only started on
a key off -> key on change. The YMF262 (the FM part of the OPL4) runs at
33.8688MHz / 2.375 = 14260547 Hz, as in MAME 0.143u3.

Sets as in current MAME:
- asurabus: USA set (new, parent)
- asurabusj: Japan set 1 (the set that was `asurabus`)
- asurabusja: Japan set 2 (new)
- asurabusjr: Japan, ARCADIA review build (new); P1 button 4 pauses
  the game, so its inputs have a 4th button per player

DIP switches as in current MAME, for Asura Blade too:
- "Demo Sounds & Music" (SW1:3,4), was two "Unknown" switches
- Difficulty, Damage and Max Rounds labels and defaults fixed: the old
  Max Rounds default ($0040) is shown as "Error" in the service mode
- Coin A/B: 1C_2C to 1C_5C and "2C Start / 1C Continue" added
- DIP locations as comments (the core has no PORT_DIPLOCATION)

Metadata: XML entries from the core's generator, hiscore and catver
entries for the new sets, CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX
2026-10-23 15:51:13 +02:00
Claude 453b679c80 Taito G-NET: the 39 games of current MAME (PC card games in flash, Zoom sound)
New: Intel/Sharp 16-bit flash memories (intelfsh.c), the RF5C296 PC card
controller with the ATA flash card and the three Taito locked cards
(ataflash.c), the G-NET board in zn.c (flash bank, control registers,
COM_DELAY, ZN-2 SPU toggle, the MCU protocol for analog and trackball
inputs, mahjong panel, Mawasunda handles), the Zoom board in flash mode
(samples read from the flashes), CHD metadata (CIS, IDNT, KEY), and a
PC hook in the PSX CPU for the IRQ hack of Space Invaders Anniversary
and Kollon. JP1 "Auto" for the mod BIOS and Compact Flash games.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-23 13:38:36 +02:00
zanacandClaude ffc68e38d9 epos: Tristar 9000 board from current MAME - The Dealer, Revenger '84, Beastie Feastie (#2117)
The Dealer was marked not working: the Tristar 9000 part of the driver was
an early draft. It now follows current MAME:

- program decryption: 4 keys for 0x0000-0x5fff, selected by a counter
  changed by writes to ports 0x20-0x24
- U04 banked at 0x6000-0x6fff by the PPI port C (bit 0); kept at 0x16000
  in the region, as 0x7000-0x7fff is RAM and uses the region there
- RAM based palette (ports 0x00-0x0f), no color PROM
- battery backed RAM at 0x7000-0x7fff with the default image of each game
- two input groups selected by the PPI port C (bits 5-6), DIP switches on
  the AY8910 port A, flip screen and DIP multiplexer on the AY8910 port B
- AY8910 at 0x34/0x38/0x3c, watchdog at 0x40, 22.1184 MHz clocks

New sets on this board: Revenger '84 (newer) `revngr84`, Revenger '84
(older) `revenger` (bad dump, not working, as in MAME) and Beastie Feastie
`beastf`. As in current MAME, the Pac-Man conversion of Beastie Feastie
is renamed `beastfp`; its hiscore and cheat entries follow it.

The Dealer's "Play" button is on START: BUTTON9 also opens the core menu.

Save states: the PPI port C, the banks and the flip screen are saved and
restored, and the screen bitmap is redrawn after a load. The redraw also
fixes the Tristar 8000 games, whose screen was not redrawn after a load.

The Tristar 8000 games (megadon, suprglob, theglob, theglob2, theglob3,
igmo, eeekk, catapult) are bit-identical to master over 6000 frames.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-23 06:10:29 -04:00
zanacandClaude 080e2f8916 pacman: Ali Baba mystery item clock from current MAME (#2116)
Ali Baba and 40 Thieves and its bootleg were marked as unemulated
protection. Current MAME emulates the mystery item clock instead:

- a write to 0x5080 starts/stops the clock (d0) and shows it (d1)
- the clock advances every 64 frames (VBLANK), and the mystery item
  lights up when it reaches 24 (0x50c1 read; was a free running counter)
- the clock is drawn in the middle of the maze from ab7.bin, now loaded
  as graphics (REGION_GFX2, reordered at init as in MAME)
- the sprites are clipped as in MAME's alibaba screen update

The Pac-Man sprite drawing is moved to a function shared by
VIDEO_UPDATE( pacman ) and the new VIDEO_UPDATE( alibaba ); the other
Pac-Man games draw exactly as before (Eggor: bit-identical frames and
audio over 9000 frames).

The clock state is saved in save states. Both sets are now marked as
working, as in MAME.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-23 06:08:47 -04:00
zanacandClaude 65d2272c9b Namco System 12: the current MAME sets, light guns, Golgo 13, Kart Duel; PSX fixes they need (#2115)
- 24 new sets: the Tekken 3 and Tekken Tag clones, Libero Grande, Toukon
  Retsuden 3, Super World Stadium '98 and 2000, Tenkomori Shooting, Point
  Blank 2 / Gunbarl, Ghoul Panic / Oh! Bakyuuun, Golgo 13 Kiseki no Dandou,
  Kart Duel, with the ROMs of current MAME.
- Light guns as MAME ptblank2_state and golgo13_state, with crosshairs.
  Golgo 13 now boots (the gun on the H8/3002 ADC, coh700b, alt bank).
- AT28C16 EEPROM: an erased chip reads 0xff, factory contents when the set
  has them; EEPROM, shared RAM and scratchpad in the save state.
- PSX GPU: texture flip of the rectangles and raw textured sprites (type 2
  GPU), as MAME.
- PSX MDEC: the output DMA as MAME (one macroblock handed out in pieces).
- PSX recompiler: a store over translated code drops only the blocks that
  hold the word, instead of the whole cache.
- Point Blank 2: the System 12 set is the parent, the placeholder goes.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-23 06:06:20 -04:00
zanacandClaude db6bffdae0 ZN: Beastorizer bootleg as MAME beastrzrb, drop the taitofx1 placeholder, BIOS sets in the XML (#2113)
- beastrzb is now beastrzrb (current MAME name), clone of beastrzr, on the
  COH-1002E board without its sound board, with the MAME ROM layout. It
  plays (no sound: the bootleg sound CPU is undumped, as in MAME).
- The taitofx1 placeholder, the old generic zn machine and the Taito
  serial protection hack it used are removed: nothing else used them.
- info.c: the BIOS sets coh1000w, coh1001l, coh1002e and coh1002v are
  printed in the XML, as the other ZN BIOS sets.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-22 16:37:27 -04:00
markwkidd c6a547a379 add dotron artwork (#2114) 2026-10-22 16:36:52 -04:00
arcadez2003 17c28f93c1 Merge pull request #2112 from zanac/nbajamex-zn
Acclaim ZN-1: NBA Jam Extreme playable with sound (RAX board, ADSP-2181), 1.9x faster than MAME
2026-10-22 20:08:57 +01:00
arcadez2003 da65b34feb Merge pull request #2111 from zanac/kinst-fix
Killer Instinct: no crash on exit, and save states that load
2026-10-22 20:08:31 +01:00
Claude d53b244990 Acclaim ZN-1: NBA Jam Extreme, RAX sound board, ADSP-2181
NBA Jam Extreme (ver. 1.10I and 1.04) as in current MAME, with the RAX
sound board: an ADSP-2181 (new in the ADSP-2100 core: its I/O space,
memory overlays, interrupts and instructions), byte DMA from the sound
ROM and two DACs fed by SPORT0 autobuffering.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-22 20:58:14 +02:00
Claude 5865842962 Killer Instinct: no crash on exit, save states that load
- ADSP recompiler: at exit, adsp_jit_exit() freed the translations
  through adsp_jit_flush(), which then scans the ADSP program memory
  again through OP_ROM. There is no active CPU at that point: closing
  Killer Instinct or Killer Instinct 2 with the ADSP recompiler on
  crashed. The exit now only frees the translations.
- MIPS3: its registers were not in the save state, so after a load the
  CPU went on with the registers of the moment of the load and crashed.
  They are saved now, and the Compare interrupt timer is set again
  after a load.
- Killer Instinct: the control registers and the end of the IRQ 0 pulse
  are saved too; the displayed buffer is set again after a load.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-22 20:52:38 +02:00
mahoneyt944 9525caa7e8 Add files via upload 2026-10-22 13:12:04 -04:00
zanacandClaude 483d854518 Acclaim ZN-1 (COH-1000A): Judge Dredd, light guns (#2110)
Judge Dredd (Rev C and Rev B) as in current MAME: the BIOS set coh1000a,
the sets jdredd and jdreddb with their hard disks, the IDE controller on
the game board, and the two light guns read through the PSX GPU, with
their crosshairs.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-22 12:42:08 -04:00
zanacandClaude 4e96962446 Atari ZN-1 (COH-1000W): Primal Rage II, and PSX fixes it needs (#2109)
- the Time Warner BIOS set coh1000w and primrag2, with the names and files of
  current MAME: 8MB of RAM, 2MB of game ROM, the VT83C461 IDE controller with
  the hard disk (registers, 32-bit data port, interrupt enable, DMA channel 5),
  the factory EEPROM, inputs as MAME
- PSX DMA: a block write to the SPU (channel 4) takes 24000 system clocks, as
  in MAME
- PSX SPU: a repeat address written while the voice plays is no longer
  changed by the loop start flags of its blocks, until the next key on
- save states: the root counters keep the clocks into their current count;
  the root counter and SPU DMA timers restored after a load no longer start
  late by the local time of the CPU; the delayed IDE events are on timers
  kept in the save state


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-22 12:19:53 -04:00
arcadez2003 67e99574d4 Merge pull request #2108 from zanac/atlus
Atlus ZN-1 (COH-1001L): Heaven's Gate playable with sound, 2.2x faster than MAME
2026-10-22 14:48:08 +01:00
Claude ca0dc1a147 Atlus ZN-1 (COH-1001L): Heaven's Gate, current MAME sets
- the Atlus BIOS set coh1001l and hvnsgate, with the names and files of current MAME
- 4 banks of 8MB of game ROM, selected by the byte at 0x1fb00002
- sound: a 68000 at 10MHz with a YMZ280B; 16-bit command latch at 0x1fb00000
  holding 68000 IRQ 3, YMZ280B on IRQ 2; and the PSX SPU

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-22 15:34:36 +02:00
arcadez2003 45d3576576 Merge pull request #2107 from zanac/capcom-zn
Capcom ZN-1 / ZN-2: the sets of current MAME, 1.7x to 3.1x faster than MAME
2026-10-22 14:18:09 +01:00
Claude 8ff668596c Capcom ZN-1 / ZN-2: the sets of current MAME, CAT702 keys from the sets, QSound at 250Hz
- the 45 sets and 2 BIOS sets of current MAME, with its names and files
- the CAT702 keys are read from the dumps in the sets (CP01/CP10, CPnn)
- inputs of current MAME (capcom6b, capcom4b, glpracr, plsmaswd, strider2, tgmj)
- game ROM bank: 16 banks, as in MAME
- QSound Z80: 250Hz interrupt, as in MAME; its phase and the Z80 ROM bank
  are in the save state
- GAME_IMPERFECT_GRAPHICS and GAME_NO_SOUND (glpracr) removed

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-22 14:55:10 +02:00
arcadez2003 1c23227c79 Merge pull request #2106 from zanac/visco
Video System ZN-1 (COH-1002V): Aero Fighters Special and Sonic Wings Limited playable, about 3x faster than MAME
2026-10-22 12:12:20 +01:00
Claude 39fcb104e2 Video System (COH-1002V): Aero Fighters Special and Sonic Wings Limited, current MAME sets
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-22 12:48:23 +02:00
d8ddd5b9f5 SH-2: FRT clock / 128 and MAC saturation as the hardwareSh2 fixes (#2105)
* SH-2: FRT internal clock / 128 as the hardware

The FRT clock select 2 (internal clock / 128) counted at / 8, sixteen
times too fast. VF Kids times its tasks with the FRT and, believing the
frame overloaded, never drew the old man's tea can. The resync also
keeps the cycles that don't make a whole count yet, as MAME.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

* SH-2: MAC.L and MAC.W saturation as MAME

With the S bit set MAC.L only added the low 16 bits of MACH, losing the
sign of the 48-bit accumulator; it now accumulates on 64 bits and
saturates to the 48-bit range. MAC.W sets MACH bit 0 on overflow.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-22 06:20:02 -04:00
zanacandClaude a514e1f0ac Eighting / Raizing (COH-1002E): the MAME sets, 68000 + YMF271 sound (#2104)
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-22 06:19:19 -04:00
zanacandClaude d0dd053834 PSX SPU: ADSR envelopes, SPUSTAT, end and repeat flags (#2103)
- ADSR envelopes as the hardware (nocash specifications): attack, decay,
  sustain, release, linear and exponential, the level readable in the
  voice ADSR volume register. Before, a voice in release was silenced at
  once: Bloody Roar 2 keys its attract movie sound on and off two frames
  later, with a release of some 17 seconds, and was silent.
- SPUSTAT: bits 0-5 follow SPUCNT, bits 7-9 the transfer mode, bit 6 the
  IRQ flag (cleared with the IRQ enable). Bloody Roar 2 waits for it after
  its first transfer, and skipped the voice set-up without it.
- An end flag with the loop start flag too (flags 7) no longer stops the
  voice: it jumps to the repeat address; only without the repeat flag is
  the voice released at level 0. ENDX (0x1f801d9c) reads the voices that
  reached an end flag. A write to the repeat address takes effect while
  the voice plays.
- A voice released to 0 is no longer decoded: with the SPU IRQ on, only
  its address moves on (IRQ address, flags); without, it is skipped.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-22 04:37:47 -04:00
zanacandClaude 73fcfe418d astrocde: draw each frame once and drop the per-pixel modulo (faster Gorf) (#2102)
Every Astrocade game drew each line twice per frame: once in
interrupt_common(), at each of the 256 scanline interrupts, and once more
in VIDEO_UPDATE( astrocde ), which redraws all the lines over the same
area at the end of the frame. The first drawing was always overwritten,
so it is removed.

wow_update_line() computed (rngoffs + x + CLOCKS_PER_LINE*line) % RNG_PERIOD
for each star/sparkle pixel. Both terms are below RNG_PERIOD, so a single
subtraction gives the same index. The per-line values are read once per
line.

Frames and audio are bit-identical to master (gorf, wow, spacezap, ebases,
seawolf2, robby; attract and gameplay, every frame). Gorf gameplay: 39%
fewer instructions; about 30% less time with the platform=rpi3 build.

Helps #675.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-22 04:21:37 -04:00
e36928faac SH-2: print the 64-bit division trace without the C99 %lld format (#2099)
Legacy MSVC does not support %lld; print the dividend and divisor
registers as 32-bit hex words instead.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-22 03:29:47 -04:00
zanacandClaude 7d9da4e99a Taito FX-1B playable with the Taito Zoom sound board, PSX GPU missing GP0 commands (#2101)
Taito FX-1B (zn.c): the 12 sets of current MAME (raystorm, raystormo,
raystormu, raystormj, ftimpcta, ftimpact, ftimpactu, ftimpactj, gdarius2,
gdarius, gdariusu, gdariusj) on the FX-1 board of #2095, with 2 MB VRAM on
G-Darius, 512 bytes of FRAM kept with the EEPROM, and the Taito Zoom sound
board. The old FX-1B sets and machine are replaced; taitofx1 stays as the
parent of beastrzb.

Taito Zoom (sndhrdw/taitozoom.c): MN10200 sound CPU, ZSG-2 and TMS57002 DSP,
as MAME taito_zm. The DSP runs one sample at a time from the stream, kept
going while its FIFO drains so the FIFO-empty line (MN10200 IRQ 1) falls as
on the board. Save states keep the time left on that kick.

New chips, ported from current MAME to C89:
- cpu/mn10200: Panasonic MN10200. A timer nobody sees (irq disabled with
  the request up, nothing cascaded on it) sleeps instead of firing: the
  Zoom program runs one as a 240 kHz baud clock, which cut the timeslices
  of every CPU. It keeps its phase and wakes when its irq control or the
  timer above it change.
- sound/zsg2: ZOOM ZSG-2.
- cpu/tms57002: TI TMS57002 DASP (API prefixed tms57002dsp_, Konami GX has
  its own tms57002_ stubs). Output identical to the MAME C++ core on the
  same recorded input.

PSX GPU (psx_vidhrdw.c): the GP0 commands missing from the parser, as MAME
(0x42/43, 0x4a/4e, 0x51/53, 0x5a/5e, 0x69-6b, 0x6c-6f textured dot,
0x70-73 and 0x78-7b flat 8x8 / 16x16 rectangles, 0x75/76, 0x7d/7e). Their
words were taken as commands: Ray Storm turned them into huge fills
(15 fps), other ZN games lost bits of their HUD. Lines and dots also do
semi-transparency now.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-22 03:21:24 -04:00
zanacandClaude 0f2695d091 Jaleco Mega System 32: driver, video and YMF271 as current MAME, F-1 Super Battle, current MAME sets (#2100)
The MS32 driver, video and sound brought up to current MAME, on the
MAME 0.78 core:

- ms32.c: system control (CRTC, VBLANK / field / programmable timer
  interrupts, acks), irq priority as the V70 sees it, sound CPU (Z80 at
  8 MHz with its own RAM bank, sound latch NMI, irq back to the main
  CPU), inputs as current MAME (mahjong key matrix, F-1 Super Battle
  wheel / pedals), start at the first VBLANK as current MAME; the
  F-1 Super Battle "jalfpu" coprocessors ported to C.
- ms32_vidhrdw.c: tile layers, ROZ (simple and per-line "super" mode),
  sprites (zoom and non-zoom cores), per-pixel priority RAM mixing,
  brightness, F-1 Super Battle road plane and mixer.
- ymf271.c: YMF271 (OPX) with FM, PCM, timers, external memory and IRQ.
- Sets and names as current MAME: hayaosi2 (ex hayaosi1), hayaosi3,
  hayaosi3a, suchie2 / suchie2o (ex 47pie2 / 47pie2o), p47acesa,
  akissa, kirarasta, wpksocv2 added; f1superb now playable with sound.
- Speed: opt-in idle loop fast-forward in the V60 core
  (v60_set_idle_loops, only ms32.c sets a table), YMF271 EG / LFO-PM
  caches and silent operators skipped, video row opacity flags and a
  mixer without the per-pixel switch. Output bit-identical with and
  without them.
- Save states: all the driver, video, Z80 RAM and YMF271 state plus the
  time left on the timers, so a loaded state goes on exactly.


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Claude <[email protected]>
2026-10-22 03:20:06 -04:00
zanacandClaude b96cd8c43a Street Fighter Zero 3 Mix v0.32 (sfz3mix): CPS2Turbo driver (#2097)
Zero800's Street Fighter Zero 3 Mix runs on his CPS2Turbo, an extended
CPS2 (https://sfz3mix.github.io/). Ported from his MAME 0.261 driver
and from FBNeo, romset sfz3mix with the FBNeo ROM names:

- 68000 at 23.6MHz (32MHz with the usual CPS2 slowdown) and Z80 at 16MHz
- 416x234 display; the "Aspect Ratio" DIP switch of FBNeo (16:9, 4:3,
  112:81) sets the aspect ratio sent to the frontend
- 6MB program space, object output moved to 0x665000 (also at 0xfffff0)
- 64MB sprite ROM: bit 12 of the sprite Y selects the upper half
- 16MB QSound sample ROM: one more bank bit, only for ROMs over 8MB
- optional music samples (samples/sfz3mix.zip, L01..R3F): the hacked Z80
  program leaves the tune number in its shared RAM, the sample replaces
  the QSound music; the tune is saved in the states and restarted on load

Other games are unchanged: the decryption buffer is still 4MB for them,
the QSound bank mask is still 7 bits up to 8MB, and sfa3 renders and
sounds bit-identical to master.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-21 22:07:27 -04:00
zanacandClaude 76a64e85dd segas32: Stadium Cross with the sets of current MAME (scross, scrossa, scrossu) (#2098)
The scross set used old ROM names and 2MB graphics and PCM dumps, so the
sets made for current MAME didn't load. Those 2MB files were the real
1MB ROMs twice (checked: each old CRC is the CRC of the new ROM doubled).

- scross now uses the ROM names, sizes and CRCs of current MAME, plus the
  comms board ROM epr-15033.ic17 that its set carries (not emulated, kept
  in REGION_USER1 like the other comms board ROMs in this driver)
- ROM_RELOAD fills the second half of each region, so the memory of the
  game is byte for byte what it was with the old dumps
- new clones from current MAME: scrossa (World, linkable) and scrossu (US)

Tested: the old set rebuilt from the new ROMs on master and the new set on
this branch give bit-identical frames and audio over 4000 frames (attract,
coin, start, race); scrossa and scrossu boot and race.


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
2026-10-21 22:06:33 -04:00
zanacandClaude Opus 5.5 d9ef30cf14 Core: add set_display_aspect_ratio() to change the display aspect ratio at run time; CPS-3 wide mode in 16:9 and sfiii3ws (#2096)
* Add set_display_aspect_ratio(): change the display aspect ratio at run time

Some drivers choose the shape of their display while the game runs
(DIP switches, monitor setups, wide video modes), but the core has no
call to change the aspect ratio after the game starts: it is computed
once from the machine driver, and the frontend only receives the
geometry again when the visible area changes. Drivers that need it
write the OSD video_config by hand (segas32.c multi32), which only
reaches the frontend if the visible area changes in the same frame.

set_display_aspect_ratio(x, y) updates the aspect ratio and flags the
display like set_visible_area() does, so the frontend gets the new
geometry (RETRO_ENVIRONMENT_SET_GEOMETRY) with the next display update,
through the existing GAME_VISIBLE_AREA_CHANGED path. Same ratio: no-op,
so drivers can call it every frame. No driver is changed here.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

* cps3: 16:9 for the wide video mode, "Wide Screen Aspect" setting; add sfiii3ws

First users of set_display_aspect_ratio().

Street Fighter III 2nd Impact has a wide video mode (Test Menu >
Configuration > Game > Screen Mode = Wide): the display goes from 384 to
495 pixels. VIDEO_UPDATE( cps3 ) already followed it with
set_visible_area(), but the aspect ratio stayed 4:3, so the wide picture
was squeezed. Now the wide mode is shown 16:9, which keeps the pixel shape
of the normal mode (like FBNeo); the new "Wide Screen Aspect" setting
(16:9 / 4:3, bit 0x10 of the fake region port, only in the sets that use
the wide mode) keeps the 4:3 of the arcade monitor instead. The setting
can be changed while the game runs.

Also adds sfiii3ws, Bank Bank's widescreen hack of 3rd Strike (20220908):
new program SIMM 1 on the 990608 game, ROM names as in FBNeo. Its program
switches the CRTC to the wide mode by itself, so no per-set code is needed.

Tested:
- sfiii2: Screen Mode = Wide switches to 495x224 at once and sends 16:9;
  saved in NVRAM, the next boot goes wide by itself; changing the setting
  from the MAME DIP menu sends 4:3 and 16:9 again; attract and fights in
  the wide mode
- sfiii3ws: wide from frame 161, attract, character select and fights;
  16:9 and 4:3
- sfiii2 in the normal mode: frames and audio bit-identical to master
- cps3.c / driver.c: gcc -std=c89 -pedantic, clang (osx flags), armhf,
  aarch64, PowerPC big-endian

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

---------

Co-authored-by: Claude <[email protected]>
2026-10-21 20:19:36 -04:00
mahoneyt944 1a3ae77e39 Increase description length 2026-10-21 18:50:32 -04:00
arcadez2003 d483d33314 Merge pull request #2095 from zanac/taito-fx1a
Taito FX-1A playable, PSX recompiler for all ZN games: 1.4x to 3.3x faster than MAME
2026-10-21 21:56:54 +01:00
Claude 3c9fe3a43b libretro input: build the joystick list only when a controller layout changes
osd_get_joy_list() rebuilt the whole list (4 players x all codes) at every
call, and the input code calls it at every key check: about 100 times a
frame, some 750k instructions a frame whatever the game. It is now built
again only when a port's layout changes.

doapp, 600 frames (callgrind): retro_run 15.02 G -> 14.57 G instructions
(-3%), video and audio identical frame by frame. The saving is per frame,
so it is a larger share on lighter games.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 20:41:26 +02:00
Claude 81fac8a81a PSX recompiler: offer it for the Sony ZN driver too
The MIPS Dynarec option was offered and turned on only for Namco System
11/12; zn.c already calls psxcpu_set_jit() when the option is on, but the
option stayed off, so the ZN games always ran the interpreter.

Video and audio identical frame by frame, recompiler vs interpreter, 4000
frames: the 17 Tecmo TPS sets and the 9 Taito FX-1A sets (branch
taito-fx1a).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 20:41:26 +02:00
Claude b3cf0a37d2 PSX video: honour the vertical display range, as MAME
The first displayed line goes at disstart - 16 and the lines out of the
range are black. Super Football Champ sets 24..248 (224 lines): the picture
was 8 lines too high with 16 lines of off-screen VRAM below it. With the
usual 16..256 range nothing changes: doapp, glpracr2, tekken3, psyforce
identical frame by frame over 2500 frames.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 18:52:32 +02:00
Claude 4f83ca25f1 YM2610: with the opt-in, save the FM and SSG state the save state left out
YM2610_save_state leaves out the global envelope and LFO counters, the key
state, the SSG-EG negation, the envelope output and the algorithm memory
of the FM part, and the counters, envelope and noise generator of the SSG
(the AY8910 has no save state, and the YM postload rewrites its registers,
which restarts the envelope). With YM2610_timer_state_register() these are
now kept in a copy and put back after the chip postload. Other YM2610
drivers: unchanged.

Save state, 600 frames after same-session and cross-session load:
- sfchamp: video and audio identical
- psyforce: audio identical (was: all 600 frames differ)
- mgcldtex, mgcldate: video identical; audio differs only in the first
  26-27 frames, by at most 103/32768, decaying to 0 (was: 470 frames)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 18:52:32 +02:00
Claude a275f8dfc4 YM2610: optional FM timers in save states, used by Taito FX-1A
The core does not save its timers, so after a load the two FM timers of
the YM2610 kept the state of the running session and the sound CPU drifted
(sfchamp: audio differed 2 s after a reload). A driver can now ask for the
timers to be saved with YM2610_timer_state_register() in its init; the
other YM2610 drivers keep their save state layout.

sfchamp: video and audio identical over 600 frames after same-session and
cross-session load.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 18:52:32 +02:00
Claude 2df7f7b29d Taito FX-1A: the 4 DSW bits not fitted read as 0, as MAME
Super Football Champ took them as the test switch and booted into the
test menu.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 18:52:31 +02:00
Claude 8ed414a1f5 Taito FX-1A (COH-1000T): the MAME sets, with Z80 + YM2610B sound
The Taito FX-1A games on the ZN-1 board code from #2081, with the sets
and file names of current MAME. Replaces the old non-working sets.

- zn.c: FX-1A board (1 MB VRAM, 8 MB game ROM banks at 0x1f000000, bank
  register at 0x1fb40000), CAT702 keys read from the TT01 / TTnn dumps in
  the sets, Z80 with a YM2610B and the TC0140SYT at 0x1fb80000, plus the
  PSX SPU.
- taitosnd.c: optional reset and save state registration for the
  TC0140SYT (used by the FX-1A only; other drivers unchanged).
- Sets: coh1000t (BIOS), sfchamp/o/u/j, psyforce/j/x, mgcldtex, mgcldate
  (MAME names: the old mgcldate is now mgcldtex, the old mgcldtea is now
  mgcldate). Old sound player and FX-1A machine removed.
- FX-1B sets (raystorm, ftimpcta, gdarius, gdarius2) unchanged for now.
- metadata/mame2003-plus.xml: FX-1A entries regenerated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 18:52:31 +02:00
zanacandClaude d708f399f7 Tecmo TPS (COH-1002M): all MAME sets playable with sound (#2094)
The Tecmo TPS games on the ZN-1 board code from #2081, with the sets and
file names of current MAME. Replaces the old non-working tps sets.

- zn.c: TPS board (2 MB VRAM, 8 MB game ROM banks at 0x1f000000, bank
  register at 0x1fb00006, four coin counters), CAT702 keys read from the
  MG01 / MGnn dumps in the sets, PSX SPU sound.
- Cool Boarders Arcade Jam: sound board with a Z80, a YMZ280B and the two
  IDT7202 FIFOs to the main CPU.
- 1 on 1 Government: the factory EEPROM of the set is used when there is
  no NVRAM yet (else: "loading backup data failed").
- Gallop Racer 2 Link HW: link board ROM in the set, CPU not emulated
  (not connected to anything in MAME either).
- Old protection hack and link machine removed; BIOS is coh1002m (was tps).
- metadata/mame2003-plus.xml: TPS entries regenerated.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-21 12:20:42 -04:00
arcadez2003 dc3148e25a Merge pull request #2091 from zanac/cps3-speed-enhanced
Capcom CPS-3: new driver, all games including 3rd Strike 4rd Arrange Edition, faster than MAME
2026-10-21 15:54:20 +01:00
arcadez2003 ee687592a7 Merge pull request #2092 from zanac/psxjit-codemap
PSX recompiler: track translated code per word, not per 64 bytes
2026-10-21 15:53:55 +01:00
arcadez2003 5e0aeb4cb4 Merge pull request #2093 from zanac/carnevil-seattle-stable
CarnEvil and the Seattle driver: MIPS III recompiler, Voodoo and timing as current MAME, SF Rush playable, The Rock, current MAME
2026-10-21 15:53:32 +01:00
Claude 620c7ba7d1 CarnEvil and the Seattle driver: MIPS III recompiler, Voodoo and timing as current MAME, SF Rush playable, The Rock, current MAME sets
CarnEvil (#1659): MIPS III recompiler and native FPU on the Seattle games
that were checked (CarnEvil, SF Rush, The Rock: identical frames to the
interpreter), Voodoo blitters for their common modes, IDE and Galileo DMA
straight into RAM, VBLANK latch, Galileo timers and IDE seek timing as
current MAME, 54.123711 Hz. Same frame cadence as current MAME.

Seattle driver toward current MAME: machine configurations and refresh
rates, I/O ASIC values, Voodoo clipping, LFB formats, dithering, alpha
blending, depth bias and alpha test, wheel board and latched shifter,
SMC91C94 ethernet on the Flagstaff board (SF Rush's race waited for it),
49-way joysticks on Blitz '99/2000 (I40) and Blitz, ROM names, disk SHA1s,
descriptions and clones of current MAME (mace 1.0ce, macea, wg3dhfe,
blitz99a), San Francisco Rush: The Rock.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5
2026-10-21 16:04:14 +02:00
Claude 4a9ed46a7b PSX recompiler: track translated code per word, not per 64 bytes
A store into a 64-byte granule holding translated code flushed the whole
translation cache. 1 on 1 Government keeps a variable next to code: 285
flushes and about 300000 recompiled blocks in 3000 frames, so the
recompiler was slower than the interpreter (220 vs 300 fps). The code map
now has one entry per 4-byte word (4 MB table, 16 MB of host addresses):
only a store over an instruction that was actually translated flushes.
A flush is still never missed, an aliased entry only flushes more.

1on1gov with the recompiler: 220 -> 360 fps; frames identical to the
interpreter on all the Tecmo TPS sets.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 15:56:53 +02:00
VanniandClaude Opus 5.5 969075a5ae Capcom CPS-3: new driver, all games including 3rd Strike 4rd Arrange Edition
A C89 port of current MAME's cps3.cpp and cps3_a.cpp: MAME's 53 sets
without the multi-game bootlegs, plus sfiii4n, the 3rd Strike "4rd
Arrange Edition 2013" hack that FBNeo has and MAME does not.

- Encryption with the per-game keys, through the new SH-2 hooks.
- Flash SIMMs (Fujitsu 29F016A), EEPROM, inputs, save states.
- Video: sprites with zoom, tilemaps, text layer, shadow/highlight,
  full screen zoom; palette and character DMA.
- The 16-voice sample chip (sndhrdw/cps3_sndhrdw.c).
- No CD drive: the BIOS no-CD flag is always set, so the CD sets run
  from the SIMMs; the Red Earth / Warzard CD BIOSes, with no such flag,
  start the game straight from the SIMMs.
- A "Region" DIP switch patches the cart's region byte at reset:
  Europe by default, USA on 2nd Impact (no European release), any
  region or "As BIOS" selectable.
- Idle loop skip per game (FBNeo's addresses).

Docs in docs/capcom-cps3.md, sets in metadata/mame2003-plus.xml.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-21 15:21:15 +02:00
VanniandClaude Opus 5.5 440a6dc232 ROM loading: look for the expected CRC in a zip before the name
Merged sets keep the files of the clones in subfolders of the parent's zip,
with the same names (sfiii3n/sfiii3-simm1.0, sfiii3nr1/sfiii3-simm1.0); the
loader matched the name only and took the first one, the wrong revision.
Loading and verifying now look for the expected CRC first, then for the
name. Split and non-merged sets load as before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-21 15:20:38 +02:00
VanniandClaude Opus 5.5 3234504360 SH-2: optional opcode fetch and DMA read hooks
Two optional callbacks in struct sh2_config, for the CPS-3 custom SH-2:
- opcode_read: the opcode fetch, for a CPU that decrypts its opcodes
- dma_read_hook: sees and can change each unit the internal DMA reads

Both are NULL in the other SH-2 drivers, which run as before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-21 15:20:38 +02:00
arcadez2003 7ebb758a6a Merge pull request #2090 from zanac/model2-enhanced-speed
Sega Model 2: 13% to 38% faster, same output (renderer + i960 idle-loop skipping)
2026-10-21 13:12:16 +01:00
arcadez2003 ffc7666884 Merge pull request #2089 from zanac/model1
Sega Model 1: new driver, TGP HLE checked bit for bit against the real TGP
2026-10-21 13:11:56 +01:00
Claude da3a90f659 i960: skip idle loops (Model 2), same output
The Model 2 games spend 80-86% of their i960 instructions in short wait
loops: read a RAM word or the video control register, maybe count, branch
back. Nothing else runs during the i960 timeslice, so when two iterations
in a row only load, compute and branch, read the same side-effect-free
addresses, cost the same cycles and change each register by the same
amount (none of them compared), the remaining iterations are skipped: their
cycles taken, the counters advanced. The last iteration of the timeslice
still runs, so the CPU stops exactly where the interpreter would.

The driver lists what an idle loop may read (i960_set_idle_read_callback):
ROM, RAM and the video control register. Off for other drivers.

Frame by frame identical video and audio on Daytona USA, The House of the
Dead, Virtua Cop and Virtua Cop 2; i960 time down by about 70%.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 12:36:45 +02:00
Claude 0f88b8feae model2: faster texel fetch (same output)
- the mipmap levels and the microtexture of a polygon are worked out once
  per polygon, not at every texel fetch
- texel addresses with unsigned shifts (the signed divisions by 2 were the
  hottest line), the column and row terms shared by the four texels
- four transparent texels return at once; the microtexture blend is
  skipped for a translucent texel with no alpha (it is discarded anyway)

Output identical frame by frame on Daytona USA, The House of the Dead,
Virtua Cop and Virtua Cop 2.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 12:36:45 +02:00
Claude 1624990be3 model2: clear and composite only the drawn part of the 3D frame
The 3D frame was cleared and composited over the whole screen every frame,
and the 64K z buckets cleared at every new frame. Now the buffer is its own
fill map (a drawn pixel is never 0), only the box of the pixels drawn since
the last clear is cleared and composited, and only the z buckets in use are
cleared. Output identical frame by frame.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ
2026-10-21 12:36:45 +02:00
VanniandClaude Opus 5.5 25900bae57 Sega Model 1: new driver, TGP HLE checked bit for bit against the real TGP
Virtua Racing, Virtua Formula, Virtua Fighter, Star Wars Arcade, Wing War
(and R360) and NetMerc, with current MAME's sets.

- Driver from current MAME: interrupt controller, interval timers, the
  UART to the Model 1 sound board, the Digital Sound Board for Star Wars
  Arcade; the I/O board firmware is simulated (inputs, DIP switches,
  analog channels, backup RAM).
- Video: C port of current MAME's model1_v.cpp; no fused multiply-add and
  x86 float to int conversions, so every CPU renders as x86.
- TGP: the geometry DSP runs in C (HLE), started from MAME 0.215. With the
  MB86233 core the real TGP program can run next to it (development
  builds, MODEL1_TGP=oracle): every function the games call was rewritten
  from the 315-5573, 315-5711 and 315-5724 programs until the results
  match bit for bit, bugs of the real programs included. Virtua Fighter
  gets its own table (MAME 0.215 used Virtua Racing's, with guessed camera
  functions).
- The TGP sits in the V60 I/O space too (Wing War boots it with an OUT).
- Save states keep the TGP FIFOs, the data ROM bank, the timers and the
  renderer's light setup, so a state loads in a new session.
- C89, own square root helper.

Details and open questions: docs/sega-model1.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
2026-10-21 12:34:33 +02:00
zanacandClaude 8343ab6b0e model2: light gun crosshairs (Virtua Cop, Virtua Cop 2, The House of the Dead) (#2088)
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-21 03:57:08 -04:00
zanacandClaude 38a7da6eac Hard disks: keep 4 MB of decompressed hunks per disk (#2087)
hard_disk_read cached a single hunk, so every hunk a game came back to
was decompressed again. CarnEvil streams ~7000 hunks over and over
during play (39000 decompressions in 3800 frames); a 4 MB
direct-mapped cache (1024 hunks of 4 KB) cuts them to ~7400. The cache
falls back to one hunk when the memory is not there; writes go through
it as before (into the differencing file).

CarnEvil: 10% less time over 12000 frames, video and audio identical.
Killer Instinct 1/2 identical.


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Claude <[email protected]>
2026-10-21 02:47:48 -04:00
mahoneyt944 f1abec1d1a Add files via upload 2026-10-20 23:06:48 -04:00
zanacandClaude 59f7ca7c30 i960: C89 fallback for logb() (MSVC 2005 link error) (#2086)
The LOGBNR/LOGBNRL opcodes called logb() directly, outside the block of
C89 fallbacks, so MSVC 2005 (no C99 math) failed to link with an
unresolved _logb. logb() is now used through i960_logb(), like round(),
trunc() and log2(): the C99 function where the compiler has it, otherwise
frexp() (exponent - 1), with logb()'s results for 0, infinities and NaN.

The fallback matches glibc's logb() on every edge case (zeros, denormals,
DBL_MAX, infinities, NaN) and on 5 million random doubles. Compiled as
C89, none of the Model 2 sources references a C99-only math function.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-20 19:41:58 -04:00
9aece938b6 Sega Model 2 (original, 2A, 2B, 2C): backport from current MAME, 84 sets (#2084)
The whole Model 2 family: i960 main CPU, TGP (MB86234) and TGPx4
(MB86235) geometrizers, SHARC (ADSP-21062) for Model 2B, geometrizer and
3D rasterizer, System 24 tile layers, 68000 + SCSP sound with the MIDI link
from the i960, Model 1 I/O board (Z80 with its BIOS, or simulated), the
315-5881/315-5838 protections, the Digital Sound Boards (DSB Z80 and DSB2
68000, MPEG audio) and the Model 1 sound board of Manx TT DX.

Beyond MAME:
- SCSP effect DSP from current MAME, without MAME's MADRS mirror that
  breaks the Dead or Alive reverb; master volume.
- Rail Chase 2: mirrored sample ROMs, the missing sound effects play.
- DSB music level measured on Top Skater cabinet recordings.
- Tile layers mixed before the polygons (Virtua Cop 2 stage select), black
  polygon pixels drawn.
- Games that do not start in MAME play: Virtual-On (comm board present,
  link stand-alone), Manx TT DX and Motor Raid DX (drive boards
  simulated), Sega Ski Super G, Top Skater in 3D (compact object format,
  second matrix, foot sensors), the Daytona USA hacks.
- Daytona USA factory link ID set to single, Super GT 24h sound queue.
- SHARC: a wait on a FIFO flag (NOP loop or jump to itself) gives up
  its timeslice (identical output, Model 2B games 1.3x-2.9x faster).

Royal Ascot II (SegaNet terminal) and Power Sled (network) are not added.
Choices that differ from the hardware: docs/sega-model2.md.

C89, no C99 math in the build paths (C89 fallbacks), checked on ARM, x86
and the Apple targets. DAT: the Model 2 entries added.


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 15:38:36 -04:00
505733a2df MIPS3: fix the 32-bit x86 build (undefined mips3_* speedup symbols) (#2085)
On 32-bit x86 hosts the Makefile builds the old x86 recompiler
(mips3drc.c, X86_MIPS3_DRC) instead of mips3.c. #2079 added optional
speedups to mips3.c/mips3.h (fast RAM, Cause poll skip, poll reads,
sljit recompiler) that Killer Instinct and core_options.c call, but
mips3drc.c does not define them, so the windows i686 / msvc05 / msvc10
jobs failed at link time:

  undefined reference to `mips3_jit_available'
  undefined reference to `mips3_set_cause_poll_skip'
  undefined reference to `mips3_add_poll_read'
  undefined reference to `mips3_add_fastram'
  undefined reference to `mips3_set_jit'

Define them in mips3drc.c as no-ops: they are optional and off by
default, so on these hosts Killer Instinct runs on the x86 recompiler
without them, and mips3_jit_available() returns 0 so the "MIPS Dynarec"
core option stays hidden. Every other target is unchanged.

Built with MinGW i686 (ARCH=x86, as on the CI runners): the symbols are
defined and the core links. C89 (-std=c89 -pedantic) clean.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 13:57:25 -04:00
23a56e6afe Sony ZN-1/ZN-2: Capcom games playable with sound and PSX recompiler (#2081)
The ZN main board backported from MAME 0.135 and the Capcom boards:
Battle Arena Toshinden 2, Star Gladiator, Street Fighter EX / EX Plus /
EX 2 / EX 2 Plus, Rival Schools / Justice Gakuen, Tetris The Grand
Master, Star Gladiator 2, Tech Romancer / Kikaioh, Strider 2 / Strider
Hiryu 2 and Gallop Racer (no sound: QSound ROMs never dumped).

- zn.c: CAT702 security chips, PSX serial port 0 bit by bit inside the
  driver (shared PSX code unchanged), inputs, board configuration, coin
  counters, AT28C16 EEPROM in NVRAM, one memory bank per RAM/BIOS mirror.
- Capcom COH-1000C/1002C/3002C: game and country ROM banking, QSound Z80
  with command latch and NMI, kick harness, ZN-1 and ZN-2 machines; the
  old placeholder QSound machine driver is removed.
- PSX recompiler: direct access to RAM, scratchpad and BIOS, turned on by
  the MIPS Dynarec core option as on System 11/12; frames and audio
  identical to the interpreter on all tested sets.
- sound/psx.c: PSX SPU from MAME 0.135 (voices and SPU IRQ); the old SPU
  was used by no driver.
- ROM sets: Star Gladiator ROM offsets, QSound samples word-swapped,
  Rival Schools / Justice Gakuen / Tetris TGM moved to ZN-2 (cpzn2).
- metadata/mame2003-plus.xml: ZN entries regenerated.

C89, no platform-specific code; checked on ARM, x86 and the Apple targets.


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 13:01:28 -04:00
zanacandClaude 28bb883273 Killer Instinct 1/2: wait states on boot EPROM data reads (attract mode music) (#2083)
Data reads from the boot EPROM cost 128 cycles (RdRdy wait states, as
FBNeo; instruction fetch stays direct). The boot (blue screen) then takes
about 7 seconds instead of 1, and the DCS has time to start the attract
mode music: it now plays in both games (it was missing). Pointed out by
barbudreadmon (issue #531).

MIPS III core: mips3_add_fastram_wait, a fast RAM region whose data reads
count wait cycles; the recompiler sends those reads through the fast RAM
handlers, so the interpreter and the recompiler give the same frames and
audio (kinst and kinst2, attract mode and a game, dynarec off and on).


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Claude <[email protected]>
2026-10-20 12:59:38 -04:00
149c6e2640 Killer Instinct 1 & 2: current MAME sets, MIPS III and ADSP-2100 recompilers, fast on low-end ARM (C89/MSVC/ARM) (#2079)
* Killer Instinct 1/2: current MAME sets, MIPS III and ADSP-2100 recompilers, speedups (C89/MSVC/ARM)

The kinst branch rebased on master, which now has libchdr (#2072) and the
shared sljit build (#2070): no CHD or sljit changes here.

- kinst: current MAME sets (kinst, kinst13, kinst14, kinstp, kinst2 and
  versions), video and dip switches, direct RGB output, idle-loop speedups
- MIPS III: optional recompiler with sljit (core option "MIPS Dynarec"),
  fast RAM and Cause polling skip, enabled for Killer Instinct only
- ADSP-2100: optional recompiler (core option "ADSP Dynarec") and exact
  skip of NOP delay loops, for Killer Instinct only; DCS ROM pointer
- KI video: the frame buffer converted a word at a time (SSE2/NEON)
- C89: no long long literals; built and checked for x86-64, x86-32,
  AArch64, ARMv7 (NEON and VFP), ARMv6 and macOS (x86-64, arm64)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* cheat.dat: keep the Killer Instinct cheats on kinst

kinst is now v1.5d (the parent, as in current MAME) and the old kinst
program (L1.4) is the clone kinst14. The cheats work on both: the
player data in RAM (0x8808BC00 / 0x8808BD00) has the same layout, checked
on a RAM dump in a fight. Leave them on the parent, which players run.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 06:43:43 -04:00
5bd572a2b8 Voodoo: fix texture RAM writes on big-endian hosts (#883) (#2080)
voodoo_textureram_w stored texels with BYTE4_XOR_LE / BYTE_XOR_LE, but
the rasterizer (voodblit.c) reads texel n from byte n (8-bit formats)
or halfword n (16-bit formats) with no swizzle. On little-endian hosts
the XOR is a no-op, so this only broke big-endian ones: every texel was
read from the wrong place and the Seattle games (BioFreaks, Blitz,
CarnEvil, California Speed, ...) showed a black screen with a few stray
pixels on PS3 / Wii U.

Texture RAM is a plain linear texel array, so store it linearly.

Tested by cross-compiling the core for 32-bit PowerPC (MSB_FIRST) and
running it under qemu-user: BioFreaks now reaches the title screen and
plays, with frames identical pixel for pixel to the x86 build. Output on
x86 is unchanged.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 06:41:53 -04:00
5262c77700 Hard disks: read CHDs with libchdr, drop the legacy CHD code (#2072)
* Hard disks: read CHDs with libchdr, drop the legacy CHD code

The legacy MAME CHD code read CHD v1-v3 only; current MAME sets are v5
(LZMA/zlib/Huffman/FLAC), which it rejected as an unsupported version.

- src/lib/libchdr: libchdr (rtissera, BSD) with LZMA SDK 19.00. libchdr
  reads every CHD version, so existing v3 CHDs keep working unchanged.
  Local changes for C89/MSVC (see MAME2003PLUS.txt); zstd is left out.
- src/lib/mame-chd/chd.c/.h removed (mame_sha1.c stays, hash.c uses it).
- harddisk.c opens the CHD through libchdr on top of the core's file
  layer, and keeps the sectors the game writes in its own differencing
  file (save/diff/<disk>.dif). The format is described at the top of
  harddisk.c: a header that identifies the disk data, then one record
  per written hunk. A .dif in the old CHD format, or made for another
  disk, is replaced by a new one.
- The disk handle drivers get is now the hard disk itself (IDE, 53CF96).
- Disk checksums: the data hashes (MD5+SHA1 for v1-v3, the raw data
  SHA1 for v4/v5) or the SHA1 of a v5 image, so the hashes listed by
  the drivers match the same dump in any CHD version.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* Hard disks: import differencing files from older versions of the core

Older versions of the core kept what the game wrote to the disk in an
uncompressed CHD v3 that used the disk as its parent. Instead of starting
a new, empty differencing file, the core now copies the hunks that file
holds into the new format, so saved settings, bookkeeping and high
scores survive the update.

- The old file is kept next to the new one as <name>.dif.old.
- Only the hunks the old file holds itself are imported (uncompressed,
  mini and self-referencing entries, with their CRC checked); the ones
  it takes from the parent are already in the CHD.
- The old file must have been made for the same disk data: its parent
  SHA1 is compared with the SHA1 of the disk data (MD5 for CHD v1/v2),
  so it also works after the CHD has been converted to v5.
- The v3 header is read directly: libchdr can't open these files, since
  it guesses the sector size from hard disk metadata they do not have.
- osd_rename() added to the file layer for the .old copy.

Tested with sfrush: an old-format file written by the legacy CHD code
(the same calls the previous core made) is imported byte for byte, a
second start reads the new file without importing again, a file made
for another disk is kept as .old and not imported, and a real file
written by the previous core while playing imports cleanly.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-20 03:45:36 -04:00
a27a08f661 System 1: rerom Shooting Master and Choplifter to current MAME (#2078)
Follow-up to #2074, as requested in review.

- shtngmst: same contents as current MAME shtngmst (the former
  shtngmste EVG set, promoted to parent in MAME 0.227 after the
  EPR-7100 redump); ROM file names updated to the MAME ic-numbered
  names. Set name unchanged.
- Choplifter sets renamed to the MAME names, ROM contents unchanged:
  chplft -> choplift, chplftb -> chopliftu, chplftbl -> chopliftbl,
  with ROM file names matching current MAME.
- PAL dumps are not added (not used by the driver).
- Updated driver list, frontend list, catver, cheat, history and the
  four entries in mame2003-plus.xml (regenerated from the core).


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 21:58:32 -04:00
2a14d0c3f8 S12 ciFix the macOS build of the MIPS recompiler (sljit) from #2070 (#2077)
* sljit: no recompiler on 3DS, PS Vita and ARM before v6

sljit's executable memory allocator needs mmap and pthreads, which the
3DS (devkitARM) and PS Vita (VitaSDK) C libraries do not have:
sljit_mame.c stopped on sys/mman.h and PTHREAD_MUTEX_INITIALIZER in
those lanes. ARMv5 (Miyoo) built but sljit's ARM back end emits ARMv6
code. These hosts now run the interpreter, as the other unsupported ones.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* sljit: Darwin extensions on macOS (fixes the osx-x64 and osx-arm64 builds)

The core builds with -D_XOPEN_SOURCE=500 on every non-MSVC platform. On
macOS that hides MAP_ANON and MAP_JIT from <sys/mman.h>, and sljit's Apple
executable allocator stopped on them:

  sljitExecAllocatorApple.c:121: error: use of undeclared identifier 'MAP_ANON'
  sljitExecAllocatorApple.c:121: error: use of undeclared identifier 'MAP_JIT' (arm64)

sljit_mame.c now defines _DARWIN_C_SOURCE on Apple hosts before any system
header. Checked with clang 18 and the macOS 11.3 SDK, targets
arm64-apple-macos11 and x86_64-apple-macos10.13, with the core's flags:
sljit and all the System 11/12 files compile.

Note on the previous commit: the 3DS and Vita lanes built fine in CI; the
JIT is kept off there as a precaution (their mmap does not give executable
memory), and the ARMv5 exclusion stands (sljit emits ARMv6 code).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 20:48:16 -04:00
f32b6d8a95 Backport Namco System 11/12 (Tekken series, Soul Calibur) with sound, MIPS recompiler - C89/MSVC/ARM (#2070)
* Namco System 11/12: Tekken series, Soul Calibur and the rest of the System 11/12 library

Rebased on the current master as one change (branch tektagt, 38 commits,
including the review fixes of #2064):

- Namco System 11 and System 12 drivers as current MAME: Tekken, Tekken 2,
  Tekken 3, Tekken Tag Tournament, Soul Edge, Soul Calibur, Ehrgeiz,
  Dunk Mania, Xevious 3D/G, Point Blank 2, Mr. Driller and the other
  System 11/12 sets, with the C76 (M37702) and H8/3002 sound CPUs and the
  C352
- PSX CPU, GTE, GPU, root counters and DMA as current MAME; MIPS
  recompiler (sljit) for the PSX CPU, core option "MIPS Dynarec"
- metadata (cheats, history, categories, XML DAT) for the new set names

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* Namco System 11/12: MSVC and C89 build lanes

- PSX GPU NEON paths only with GCC/clang (they use GCC attributes); MSVC,
  ARM included, takes the C code
- no MIPS recompiler with MSVC before 2013 (the 2003-2010 lanes): the
  interpreter is used there; sljit is still built for MSVC 2013+ and
  GCC/clang on x86 and ARM

All System 10/11/12 sources pass gcc -std=c89 -pedantic with
-Werror=declaration-after-statement and -Werror=variadic-macros, and
compile for aarch64 and armv7 (ARM/NEON, Thumb/VFP).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* Namco System 11/12: drop the GitHub Actions workflow

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 16:43:27 -04:00
0aaf055d11 Input: self-centering analog controls return at the key speed (#2075)
With digital controls, IPF_CENTER paddles and sticks drifted back to center
at 100/sensitivity per frame instead of the key delta: at sensitivity 30
(Model 2 steering wheels) the wheel took ~2 s to recenter after taking
0.8 s to reach full lock, so the car kept turning (Super GT 24h). Newer
MAME uses centerdelta, which defaults to keydelta; do the same and stop
exactly on the center instead of oscillating around it.


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 16:34:54 -04:00
zanacandClaude c53f2b4206 TMS34010: MMTM leaves the N flag alone on the 34010 (#2076)
Only the TMS34020 sets N from the destination register in MMTM; on the
TMS34010 the flag is unaffected (as in MAME 0.115 and later). Setting it
on the 34010 corrupted the N flag across register saves, which breaks
code that compares, pushes registers and then branches on the sign.

Fixes libretro issue #1864: in Mortal Kombat II Plus (mk2p) 2-on-2
Kombat Tag, the first hit on a character killed it outright. With this
change energy drains normally and tagging works. mk2 and mk play
identically to before over a 6000-frame scripted run.


Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

Co-authored-by: Claude <[email protected]>
2026-10-19 16:31:53 -04:00
arcadez2003 0b06ca52dc Add new games to the working list and update credits for raiden2.c 2026-10-19 20:44:30 +01:00
zanacandClaude Opus 5.5 7b46a717d8 Midway T-unit / Wolf-unit: save state support (MK2, UMK3) and UMK3 palette hack fix (#2073)
* UMK3: install the palette queue hack at the right address

The hack was backported from a later MAME, where the TMS34010 address
space is bit-addressed. In this core memory handlers take byte addresses
(TOBYTE), as every other handler and speedup in the driver does, so the
handler was installed far away from the palette queue pointers and never
ran. This is why raising the penalty had no effect on the select screen
palette corruption reported in libretro issue #1989.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

* Midway T-unit / Wolf-unit: save state support (MK, MK2, MK3, UMK3)

Fixes libretro issue #1989 (MK2 and UMK3 report "Core does not support
save state").

- TMS34010: the shift register was allocated in reset but registered in
  init while still NULL, so the save state size was 0 for every TMS34010
  game. Allocate it in init and keep it across resets (also fixes a leak
  on every reset). Internal interrupts queued on TIME_NOW timers are
  tracked and re-queued after a load, so a pending display interrupt is
  not lost.
- ADSP-2100 family: register the CPU state.
- DCS: register the board state and sample buffers, re-arm the
  autobuffer timer where it was, restore DCS2 banking, and keep the
  speedup's wait-for-interrupt across a load (new cpuexec helpers
  cpunum_get_suspend_trigger / cpunum_suspend_until_trigger).
- T-unit/Wolf video: local VRAM, DMA registers, banking; the DMA
  completion timer is re-armed after a load instead of being lost.
- T-unit/Wolf machine, serial PIC: protection, CMOS enable, I/O shuffle,
  UART and the (partly random) serial data.
- Williams ADPCM board (MK1): bank select and IRQ state. The core saves
  bank 6 contents into whichever ROM bank is mapped at load time; keep a
  copy of the banked ROM to undo that.

Tested headless on mk2 and umk3: after a load, both in the same session
and in a fresh one, video matches the original run frame for frame and
the audio output is identical sample for sample. No measurable speed
change. MK1 saves and loads, but its sound CPU still drifts after a load:
the 6809 core does not save its D register, a core-wide change left for
a separate commit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MEgow1uRCv8pxMErKhmoHZ

---------

Co-authored-by: Claude <[email protected]>
2026-10-19 13:45:13 -04:00
ce908de1c1 System 1: emulate the 8751 MCU for Shooting Master and Choplifter (#1934) (#2074)
Add an MCS-51 CPU core (backport of MAME 0.139 mcs51, Steve Ellenoff /
Couriersud) to the 0.78 cpu_interface: internal RAM and SFRs live in the
CPU context, MOVX goes through per-CPU driver handlers, P0-P3 are ports
0-3, timers support counter mode on T0/T1. DS5002FP/80C52 variants dropped.

Hook up the real 8751 on Sega System 1 as in current MAME (system1.cpp):
- MCU P1: bit 6 BUSREQ halts the Z80, bit 0 drives the Z80 /INT,
  bits 3-4 select the MOVX space (Z80 program / banked ROM / Z80 I/O)
- VBLANK -> MCU INT0, videomode bit 6 -> MCU INT1, Z80 INTACK -> MCU T0
- the firmware pulses /INT for a few machine cycles; the release is
  delivered in the Z80's own time so the pulse is not lost when the Z80
  runs ahead of the MCU within a timeslice

shtngmst: drop the fixed jump-table hack (broke in round 2), load
315-5159a.ic74. chplft: load 315-5151.ic74, protection now emulated.
Clones chplftb/chplftbl keep the unprotected board.


Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 13:39:51 -04:00
arcadez2003 fbd9882765 Merge pull request #2071 from zanac/raiden2
Raiden II / Raiden DX / Zero Team: backport of MAME raiden2.cpp and r2dx_v33.cpp
2026-10-19 18:07:25 +01:00
VanniandClaude Opus 5.5 1d96012a6f Raiden II / Raiden DX / Zero Team: backport MAME raiden2.cpp and r2dx_v33.cpp
Port the current MAME Seibu COP (SEI1000) driver to the 0.78 API (fixes #2056):

- V30 program banking from MAME: Raiden II / Zero Team 2 x 128 KB (0x6cb
  bit 7), Raiden DX 16 x 64 KB (0x470 and 0x6cb), so Raiden DX now runs
- COP: tilemap/palette DMA into the private video memory, palette
  brightness DMA (fades), PRNG, copy/fill modes
- video: layers and sprites drawn as palette indexes and composited as in
  MAME, with the blended pens drawn at 50%; sprite priority per game
- Zero Team: own memory map, 4 player inputs, YM3812 + OKI sound
- V33 boards (New Zero Team, Zero Team 2000, Raiden II New / Raiden DX)
  use the same tilemap/palette path
- save states for all families
- ROM sets and names synced with MAME (46 sets), driver list, XML DAT,
  catver and history updated

C89 / MSVC / ARM clean.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5
2026-10-19 14:07:24 +02:00
a6087d4e1a Backport PGM follow-up: C89/MSVC cleanup and IGS023 video (sprite zoom, priority, IRQs) (#2069)
* PGM / ARM7: C89 and MSVC-compatible sources

- // comments converted to /* */ in the ARM7 core, pgm.c and pgmcrypt.c
- the ARM7 core's local static inline: __inline for MSVC, __inline__ for
  GCC/clang, plain static otherwise (was GCC-only __inline__)
- no trailing comma in the ARM7 architecture flags enum, no nested comment
- prototypes with (void); killbld clears all of kb_regs at init (memset
  used the element count)

All touched files pass gcc -std=c89 -pedantic with
-Werror=declaration-after-statement and -Werror=variadic-macros.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* PGM video: IGS023 renderer as current MAME (zoom, priority, DMA, IRQs)

- sprites with the zoom / shrink tables, drawn from the end of the list
  with a priority bitmap: a sprite pixel is not drawn over one already
  drawn, and a sprite with the priority bit is hidden only where the
  background is opaque (was: the leading run of such sprites drawn before
  the background)
- control register 0xb0e000: sprite DMA only when bit 0 is set (the list
  was copied every frame, also while the game was rebuilding it), IRQ4
  every 62 lines and IRQ6 at vblank only when enabled and held until the
  enable bit is cleared, text / background / high priority sprite
  disables
- sprite DMA with the per-word masks; size word zero ends the list
- screen filled with pen 0x3ff; palette RAM up to 0xa013ff (0xa00 colours)
  so the text layer's upper 16 palettes exist

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* PGM video: IRQ4 divider started at video start; one 68000 IRQ level

- the IRQ4 timer (every 62 lines) is started in VIDEO_START: the base PGM
  machine has no MACHINE_INIT, so it never ran there (Cave games: no
  credits taken)
- the 68000 interface keeps a single interrupt level and CLEAR_LINE on any
  line drops it: set only the highest pending one

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-19 02:48:20 -04:00
fdb7a57451 Backport PolyGame Master (PGM) (#2067)
* DoDonPachi II - Bee Storm: IGS027A ARM7 protection, all current MAME sets

DoDonPachi II (ddp2) did not work: the IGS027A protection (an ARM7 with
an internal ROM) was not emulated, and that ROM had not been dumped.
It now runs as in current MAME (pgmprot_igs027a_type2.cpp):

- New CPU core: ARM7 (ARM7TDMI, with Thumb), the MAME 0.139 core (C)
  with the cpu interface of this version: the state in one static
  structure, memory through the 32-bit little endian handlers
  (cpu_readmem32ledw...), save states. No MMU or coprocessors are
  used. Built only where a driver uses it (CPUS+=ARM7@).
- PGM "type 2" protection hookup: the ARM7 at 20 MHz with its internal
  ROM, the encrypted external ROM (decrypted with the XOR table the
  internal ROM uploads at 0x50000000), 64KB of RAM shared with the
  68000 (0xd00000) and the latch at 0xd10000 (a 68000 write raises the
  ARM's FIRQ, the ARM's read clears it). The two idle loops of current
  MAME are skipped (ARM and 68000). pgm_ddp2_decrypt no longer applies
  the fixed table: the ARM uploads it.
- The 18 current MAME sets (World, Hong Kong, Korea, Japan, Taiwan,
  China; ver. 100, 101, 102) with their ROM names; the game region
  comes from the internal ROM of each set.

Tested (x86-64): ddp2, ddp2j and ddp2100c boot to their own region
warning and title and play, with sound; runs are deterministic; a save
state taken in game and loaded later gives the same frames as running
on (with the GAME_IMPERFECT_SOUND flag removed for the test: in this
version that flag also disables save states, GAME_DOESNT_SERIALIZE).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* PGM: Knights of Valour 2 / 2 Plus, Martial Masters, Dragon World 2001 / Pretty Chance

The other games on the IGS027A "type 2" ARM protection of DoDonPachi II,
as in current MAME: the same ARM7 hookup, with each game's decryption
(pgm_kov2_decrypt, pgm_kov2p_decrypt, pgm_mm_decrypt, pgm_dwpc_decrypt,
ported from current MAME's pgmcrypt.cpp with the IGS27_CRYPT steps) and
the ARM at 22 MHz for Martial Masters and Dragon World (MDRV_CPU_REPLACE
of the "arm7" CPU).

The 20 current MAME sets (kov2 and 7 clones, kov2p and 4 clones,
martmast and 3 clones, dw2001, dwpc, dwpc101j), converted from current
MAME: the 68000 program after the BIOS, the internal ARM ROM, the
external ARM ROM, and the text/background tiles at 0x400000 after the
BIOS ones as the other PGM games here; the region sizes are those of
the ROMs.

Also ported for the following commits: the decryptions of Demon Front,
The Gladiator, Killing Blade Plus, S.V.G., Happy 6-in-1 and Photo Y2K.

Tested (x86-64, 2400 frames with coin and start): kov2 (intro), kov2p
(mode select), martmast (in a fight), dw2001 and dwpc101j (in game).
dwpc (China) stops at "ASIC27 NOT DETECT": only the Japanese internal
ROM is dumped (current MAME patches it to boot); marked not working.
The other PGM games are unchanged (orlegend, kov, ket, ddp3, espgal:
same video and audio as the libretro master).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* PGM: Demon Front, The Gladiator, S.V.G., Killing Blade Plus, Happy 6-in-1

IGS027A (55857G) ARM7 protection ("type 3"), ported from current MAME's
pgmprot_igs027a_type3.cpp: banked shared RAM, FIRQ from the 68000, the
replacement code for the undumped execute-only area of the internal
ROMs, region patches, speedups, Happy 6 graphics/sample descrambling.
All 19 current MAME sets.

The ARM7 core now acknowledges FIRQ/IRQ through the irq callback so
HOLD_LINE works (the 68000 pulses the FIRQ).

Sprite mask regions of the new sets (types 2 and 3) use current MAME's
power-of-2 sizes: the video code masks the offsets with the region size,
a 0xa00000 region scrambled the sprites. GFX1 regions get MAME's size
too, zero filled.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

* PGM: Knights of Valour Super Heroes, Photo Y2K with the real ARM protection

IGS027A (55857E) ARM7 protection ("type 1") as in current MAME
(pgmprot_igs027a_type1.cpp): the internal ROMs are fully dumped, the ARM
talks to the 68000 through a polled latch and 64 bytes of shared RAM.

kovsh and photoy2k didn't start (old dumps, simulated protection): their
sets are replaced with current MAME's, with the clones (kovsh103/102/
101/100, photoy2k104/103j/102j). kovsh becomes a parent, as in current
MAME. The Japanese board set gets the Japan region.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

---------

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-18 23:00:01 -04:00
Andy Silverman b2855ef3b1 Fix normalized analog scaling for wide input ports (#2068) 2026-10-18 19:56:53 -04:00
arcadez2003 98ea5e6469 FFS 2026-10-19 00:00:57 +01:00
arcadez2003 6b20b595a4 Hook up banking for Raiden DX WIP
With thanks to AdvanceMAME
2026-10-18 23:40:36 +01:00
arcadez2003 804b9baabc Come back to it later 2026-10-17 22:01:27 +01:00
arcadez2003 5443426940 try again 2026-10-17 21:57:21 +01:00
arcadez2003 94ee7d65ee Correct blood colours for Primal Rage
Yellow -> Red
2026-10-17 21:51:22 +01:00
arcadez2003 f61aa3a0b5 Just some recent WIP from my side 2026-10-17 21:33:48 +01:00
arcadez2003 c797619396 Rollback 2026-10-16 18:51:16 +01:00
arcadez2003 9029a8abec Rollback on Seibu sound remove savesates
Raiden II sound can work with the ole Seibu core
2026-10-16 18:50:11 +01:00
arcadez2003 5563d70290 Disable savestates 2026-10-16 18:46:30 +01:00
arcadez2003 23c1680f56 raidendx 2026-10-15 21:28:13 +01:00
arcadez2003 f518b40918 Add Raiden DX 2026-10-15 21:27:04 +01:00
521a327dd9 Add spf2xpri (Super Puzzle Fighter 2 X', hack) (#2062)
Fan rebalance hack by Kaito Sinclaire recreating the X' balance changes
from Super Puzzle Fighter II HD Remix, built on the Euro set (spf2t).
https://github.com/KScl/puzzle-fighter-x-prime

- ROM set uses the Fightcade names (pzfxp.03/.04, pzfxp.14m-20m),
  sound ROMs and spf2t.key shared with the parent
- clone of spf2t (code is the patched pzfe.03, decrypted with spf2t.key)
- hiscore.dat entry shared with the spf2t family


Claude-Session: https://claude.ai/code/session_016PwPGTj4SDjmvPp3DRm9j5

Co-authored-by: Vanni <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-15 13:07:12 -04:00
Chris Dixon 8a9224a9a6 Save the Neo Geo's pd4990a clock in savestates (#2066)
None of the calendar chip's state was registered, so loading a state
left the clock, its serial shift registers and its test pulse where
they were. Run-ahead loads a state every frame, and a Neo Geo then
stalls on boot or stops at CALENDAR ERROR.
2026-10-15 13:06:38 -04:00
arcadez2003 cfac240042 Revert on c5233bc
Makes no difference with Raiden 2 gfx niggles
2026-10-15 15:22:02 +01:00
arcadez2003 c5233bcb58 Possible fix for Gfx niggles Raiden 2 Level 3 2026-10-15 00:34:15 +01:00
arcadez2003 a5e5261093 Bump up YM2151 music for Raiden 2 and enable COPX rom loading 2026-10-15 00:27:26 +01:00
arcadez2003 92c7b8e475 Merge pull request #2061 from libretro/arcadez2003-patch-3
For new Seibu sound savestates
2026-10-14 19:31:57 +01:00
arcadez2003 62eca3b507 Merge pull request #2060 from libretro/arcadez2003-patch-2
Update to support Raiden2 sound
2026-10-14 19:31:41 +01:00
arcadez2003 b8df278931 Merge pull request #2059 from libretro/arcadez2003-patch-1
Compile test
2026-10-14 19:31:24 +01:00
arcadez2003 bf6a7455d7 Update to support Raiden2 sound 2026-10-14 19:24:24 +01:00
arcadez2003 89a47488e9 Compile test 2026-10-14 19:22:11 +01:00
497 changed files with 347452 additions and 43652 deletions

No files matched your search

+1
View File
@@ -4,5 +4,6 @@
*.exe
*.dll
*.so
*.d
package.json
.npmignore
+131 -3
View File
@@ -2,7 +2,8 @@
* Current repository maintainers: arcadez, mahoneyt944, markwkidd, twinaphex
* Past repository maintiners: arnoldsecret, grant2258
* Significant code contributors to this project: AMadvanceMAME, BritneysPAIRS, dink, FBN Dev, grant2258, iq_132, MAME Dev, Mistydreams, ShmupMAME
* Significant code contributors to this project: AMadvanceMAME, BritneysPAIRS, dink,
* FBN Dev, grant2258, iq_132, MAME Dev, Mistydreams, ShmupMAME, Zanac, AI agent claude
The list of direct contributors to the MAME 2003-Plus github repository can be found at https://github.com/libretro/mame2003-plus-libretro/graphs/contributors. Additional contributor credits can be found in LICENSE.md, CHANGELOG.old, and in the individual driver source files.
@@ -18,6 +19,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Adventure Canoe
* Air Attack
* Air Rescue
* Akka Arrh (prototype)
* Aladdin (bootleg of Megadrive version)
* Angler Dangler (Deco Cassette)
* Argus (Gottlieb, prototype)
@@ -26,10 +28,14 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Backfire!
* Back Fire (Tecmo)
* Bang Bang Busters
* Bare Knuckle (scrambled bootleg of Mega Drive version) - Romset `barekch` - 6 button pads
* Bare Knuckle II (bootleg of Mega Drive version) - Romset `barek2mb` - its PIC16C57 emulated
* Bare Knuckle II (chinese bootleg of Megadrive version)
* Bare Knuckle III (bootleg of Megadrive version)
* Baryon: Future Assault
* Beastie Feastie (Epos Tristar 9000) - Romset `beastf`; the Pac-Man conversion is now `beastfp`, as in current MAME
* Big Fight - Big Trouble In The Atlantic Ocean
* Bio-Hazard Battle (scrambled bootleg of Mega Drive version) - Romset `biohzdmb`
* Bomb Kick
* Boogie Wings
* Born To Fight
@@ -38,6 +44,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Bubble Bobble 2 - The Return Of Super Drunk (prototype)
* Bubble Buster
* Buccaneers
* Buggy Boy/Speed Buggy (cockpit, rev. D and B), Buggy Boy Junior/Speed Buggy (upright)
* Bullet (unprotected of FD1094 317-0041 set)" )
* Cabal (World, Joystick version)
* Calorie Kun vs Moguranian
@@ -48,6 +55,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Choky! Choky!
* Choutetsu Brikin'ger - iron clad
* Clockwork Aquario
* Columns II: The Voyage Through Time (World) - Romset `columns2`; the old `columns2` (Japan) is now its clone `column2j`, as in current MAME
* Combat Hawk
* Come Back Toto
* Cookie & Bibi
@@ -62,6 +70,8 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Cycle Warriors
* Daikaiju no Gyakushu
* Danger Express (prototype)
* Deathsmiles - Romset `deathsml`
* Deathsmiles MegaBlack Label - Romset `dsmbl`
* Deluxe 5
* Denjin Makai
* Deer Hunting
@@ -69,6 +79,8 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Dice - The Dice Game
* Diet Go Go
* Digger (CVS)
* DoDonPachi Dai-Fukkatsu (Ver 1.5 and 1.0) - Romsets `ddpdfk`, `ddpdfk10`
* DoDonPachi Dai-Fukkatsu Black Label - Romset `dfkbl`
* Dolmen
* Dodge Man
* DoDonPachi Dai-Ou-Jou
@@ -80,6 +92,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Dyna Gear
* Eeekk!
* ESPGaluda
* Espgaluda II (all sets) - Romsets `espgal2`, `espgal2a`, `espgal2b`
* F1 Super Lap (World)
* Fantasy Zone II - The Tears of Opa-Opa (System 16C version)
* Fever SOS
@@ -109,15 +122,19 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Hard Times
* Head On Channel (Japan, Prototype)
* Heavy Smash
* Heavy Unit
* Hoops '96
* Hypernoid
* Hyper Crash
* Hyper Street Fighter II (All Sets)
* Ibara (all sets) - Romsets `ibara`, `ibarao`
* Ibara Kuro Black Label (all sets) - Romsets `ibarablk`, `ibarablka`
* In Your Face
* Inca * Mature *
* Indian Battle
* Invasion
* Jammin (Atari Prototype)
* Jingling Jiazu Genie 2000 - Romset `jingling`
* Joe & Mac Returns
* Jolly Jogger
* Jurassic Park (Bootleg Of Megadrive Version)
@@ -150,11 +167,17 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Monsters World (Bootleg Of Super Pang)
* Monster Maulers
* More More
* Mortal Kombat 3 (scrambled bootleg of Mega Drive version) - Romset `mk3mdb` - 6 button pads
* Mortal Race
* Mouse Shooter GoGo
* Ms. Pacman Twin
* Mrs. Dynamite
* Muchi Muchi Pork! - Romset `mmpork`
* Multi Champ Deluxe * Mature *
* Mushihime-Sama (all sets) - Romsets `mushisam`, `mushisama`, `mushisamb`
* Mushihime-Sama Futari Black Label (all sets) - Romsets `futaribl`, `futariblj`
* Mushihime-Sama Futari Ver 1.5 and 1.0 (all sets) - Romsets `futari15`, `futari15a`, `futari10`
* New Zero Team
* Ninja Kazan
* Oo Parts (Japan, Prototype)
* Opa Opa (Rev A Unprotected)
@@ -168,6 +191,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Passing Shot (Japan 2 players)
* Penky
* Photo Y2K 2
* Pink Sweets: Ibara Sorekara (all sets) - Romsets `pinkswts`, `pinkswtsa`, `pinkswtsb`, `pinkswtsx`
* Pirate Treasure
* Planet Probe
* Pochi & Nyaa
@@ -177,16 +201,23 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Power Instinct Matrimelee
* Power Up Baseball
* Progear
* Puckman Pockimon Genie 2000 - Romset `puckpkmn` - the set of current MAME; the old `puckpkmn` set is now its clone `puckpkmnb`, as in current MAME
* Puyo Puyo (World) - Romset `puyo`; the old `puyopuyo`, `puyopuya` and `puyopuyb` are now its clones `puyoj`, `puyoja` and `puyobl`, as in current MAME
* Puzz Loop 2 (All Sets)
* Puzzle Break
* Puzzle Star
* Puzzle! Mushihime-Tama (all sets) - Romsets `mushitam`, `mushitama`
* Puzzli 2
* Puzzli 2 Super
* Quick Shots (Clone Of Target Hits)
* Racing Beat
* Racing Hero
* Rage Of The Dragons
* Raiden II
* Raiden DX
* Raiden II / Raiden DX New
* Recalhorn (prototype)
* Revenger '84 (newer) - Romset `revngr84`; the older set `revenger` is a bad dump and stays not working
* Riot
* Rolling Crush
* Round Up 5 - Super Delta Force
@@ -202,10 +233,13 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Sega Megaplay : Streets Of Rage II
* Sega Megaplay : Tecmo World Cup
* Sega Sonic Bros (Japan, Prototype)
* SegaSonic Cosmo Fighter (World and Japan) - Romsets `sonicfgt`, `sonicfgtj`
* SegaSonic Popcorn Shop (Rev B) - Romset `sonicpop` - the popcorn machine itself isn't emulated, as in current MAME
* Sengoku 3
* Shuihu Feng Yun Zhuan
* Skater (Deco Cassette)
* Skull Fang
* Sky Robo / Tatakae! Big Fighter
* Slap Shooter
* Snow Brothers 3 - Magical Adventure
* Snk Vs Capcom : Svc Chaos (MVS)
@@ -213,19 +247,26 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Sonic Boom
* Sonic The Hedgehog 2 (Bootleg Of Megadrive Version)
* Sonic The Hedgehog 3 (Bootleg Of Megadrive Version)
* Soreike! Anpanman Popcorn Koujou (Rev B and Rev A) - Romsets `anpanman`, `anpanmana` - the popcorn machine itself isn't emulated, as in current MAME
* Space Fever High Splitter
* Space Launcher
* Space Raider
* Spectrum 2000 (Euro)
* Squash
* Stack Columns (World) - Romset `stkclmns`; the old `stkclmns` (Japan) is now its clone `stkclmnsj`, as in current MAME
* Stadium Cross (World, linkable) and (US) - Romsets `scrossa`, `scrossu`; `scross` now uses the ROM names of current MAME
* Star Fire 2
* Steel Worker
* Street Fighter III 3rd Strike: Fight for the Future (Widescreen 20220908, Bank Bank hack) - Romset `sfiii3ws`
* Street Fighter Zero 3 Mix v0.32 (Zero800 hack, CPS2Turbo) - Romset `sfz3mix`, optional music samples `sfz3mix.zip`
* Success Joe
* Super Bishi Bashi Championship (ver JAA, 2 Players)
* Super Bubble Bobble (Sun Mixing, Megadrive clone hardware)
* Super Doubles Tennis (Deco Cassette)
* Sunset Riders (scrambled bootleg of Mega Drive version) - Romset `srmdb`
* Super Monaco GP
* Super Rider
* Super Street Fighter II - The New Challengers (scrambled bootleg of Mega Drive version) - Romset `ssf2mdb` - 6 button pads
* Super Trio
* SWAT Police
* Tang Tang
@@ -241,6 +282,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* ThunderForce AC (Japan, prototype, bootleg)
* Top Driving
* Top Roller
* Top Shooter - Romset `topshoot`
* Toppy & Rappy
* Torus * Mature *
* Touch & Go (Korea, unprotected)
@@ -252,14 +294,21 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Turkey Hunting
* Twin Cobra 2
* Twin Action
* Twin Squash - Romset `twinsqua`
* Twinkle
* Twinkle Tale (Bootleg Of Megadrive Version)
* TX-1 (World, Japan rev. B and C)
* Tylz
* Ufo Senshi Yohko Chan
* Varia Metal
* Vasara 2
* Virtua Bowling
* Virtua Fighter
* Waku Waku Anpanman (Rev A and original) - Romsets `wwanpanm`, `wwanpanmo`
* Waku Waku Jumbo (Rev A) - Romset `wwjumbo`
* Waku Waku Marine - Romset `wwmarine`
* Waku Waku Pajero - Romset `wwpajero`
* Waku Waku Sonic Patrol Car - Romset `soniccar`
* Wheels Runner
* Wing Force
* Wing Shooting Championship
@@ -268,20 +317,39 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Woodpecker
* World Cup Volley 95
* Xeno Crisis
* Zero Team 2000
* Zintrick
* Zupapa
## New Clones
* 800 Fathoms (older), Knock Out!! (bootleg, set 2 and set 3), Triple Punch (set 2) - Romsets `800fatha`, `knockoutb`, `knockoutc`, `triplepa`
* Alien Storm (bootlegs of the 3 players and Japan sets) - Romsets `astorm3d`, `astormud`, `astormjd`
* Asura Buster - Eternal Warriors (USA), (Japan, set 2) and (Japan) (ARCADIA review build) - Romsets `asurabus`, `asurabusja`, `asurabusjr`; the Japan set 1 is now `asurabusj`, as in current MAME
* Bare Knuckle III (bootleg of Mega Drive version, alt set, the PIC simulated) - Romset `barek3mba` - not working, as in current MAME
* Bare Knuckle III / Sunset Riders (scrambled bootleg of Mega Drive versions) - Romset `bk3ssrmb` - not working, as in current MAME (only Bare Knuckle III boots)
* Bloxeed (US, C System, Rev A) - Romset `bloxeedu`
* Borench (set 2) and (Japan) - Romsets `borencha`, `borenchj`
* Columns (US, cocktail, Rev A) - Romset `columnsu`
* Print Club (World) and (Japan Vol.3) - Romsets `pclub`, `pclubjv3` - not working (camera and printer), as in current MAME
* Puzzle & Action: Ichidant-R (World) (bootleg) - Romset `ichirbl`
* Puzzle & Action: Tant-R (Japan) (bootleg set 3 and set 4) - Romsets `tantrbl3`, `tantrbl4`
* Ribbit! (Japan) - Romset `ribbitj`
* Sunset Riders / Super Street Fighter II - The New Challengers (scrambled bootleg of Mega Drive versions) - Romset `srssf2mb` - not working, as in current MAME (the order of the ROMs is not known)
* Battle Shark (Japan, Joystick)
* Bloxeed (bootleg) - Romset `bloxeedd`
* Botanic (French version)
* Bubble Bobble (prototype on tokio hardware)
* Calorie Kun vs Moguranian (bootleg)
* Cannon Dancer
* Clutch Hitter (bootlegs) - Romsets `cltchitrd`, `cltchitrjd`
* Competition Golf Final Round (old version) - `compglfo`
* Cotton (bootlegs of the US and Japan sets) - Romsets `cottonud`, `cottonjd`, `cottonjad`
* Crouching Tiger Hidden Dragon 2003
* Crouching Tiger Hidden Dragon 2003 Super Plus
* Crystal Castles (Joystick Version)
* D. D. Crew (bootlegs of the six FD1094 sets) - Romsets `ddcrewd`, `ddcrewud`, `ddcrew1d`, `ddcrew2d`, `ddcrewjd`, `ddcrewj2d`
* Desert Breaker (bootlegs) - Romsets `desertbrd`, `desertbrjd`
* DJ Boy (Japan)
* DoDonPachi Dai-Ou-Jou (Black Label)
* Double Dragon 3 - The Rosetta Stone (Japan)
@@ -295,6 +363,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Gals Panic DX * Mature *
* Ghox (Joystick)
* Ganbare! Gonta!! 2 / Party Time: Gonta the Diver II * Mature *
* Golden Axe II (Mega Play, original revision) - Romset `mp_gaxe2a`
* GunNail (Location Test)
* Guwange Special Version
* Hacha Mecha Fighter (bootleg)
@@ -307,6 +376,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* King of Gladiator
* Knuckle Bash 2
* Kyukyoku Tiger (Japan, 2 Players)
* Laser Ghost (bootlegs) - Romsets `lghostd`, `lghostud`
* Mad Ball V2.0 * Mature * - Romset `madball`
* Magical Drop
* Magical Drop Plus 1
@@ -315,6 +385,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Renegade (US, Bootleg)
* Safari Rally (World) - safarir
* Sexy Parodius (Ver AAA) * Mature *
* Shadow Dancer (World, Japan and US) - Romsets `shdancer`, `shdancerj`, `shdancer1` (were `shdancer`, `shdancrj`, `shdancrb`), now on the System 18 memory mapper and video as in current MAME
* Snk Vs Capcom : Svc Chaos (bootleg)
* Super Bishi Bashi Championship (ver KAA, 3 Players)
* Target Ball * Mature * (Romset `tgtballa`)
@@ -364,6 +435,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Metal Slug 2 - Turbo (Trap15, Hack)
* Midnight Resistance (joystick hack bootleg)
* Mortal Kombat 2 Plus Beta 2
* Pink Sweets: Suicide Club (2017 hack of Pink Sweets) - Romset `pinkswtssc`
* TANK III (joystick hack bootleg)
* The Eye Of The Typhoon (Beta 7)
* Tron freeplay custom rom
@@ -374,6 +446,8 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Agent Super Bond - Romset `superbon` - colors fixed
* Alcon - Romset: `alcon`
* Alien Storm (World and Japan 2 players, World and US 3 players) - Romsets `astorm`, `astormj`, `astorm3`, `astormu` - FD1094 encrypted 68000, Sega System 18
* Bloxeed (Japan, two sets) - Romsets `bloxeed`, `bloxeeda` - FD1094 encrypted 68000, Sega System 18
* Arch Rivals - Romset: `archrivl`
* Avengers In Galactic Storm US - Romset: `avengrgs`
* Avengers In Galactic Storm Japan - Romset: `avengrgsj`
@@ -391,10 +465,14 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Cheeky Mouse - Romset `cheekyms` - colors fixed
* Chouji Meikyuu Legion (ver 1.05) - Romset `legiono`
* Competition Golf Final Round (revision 3) - `compgolf`
* Cotton (World, US, Japan Rev A and Rev B) - Romsets `cotton`, `cottonu`, `cottonj`, `cottonja` - FD1094 encrypted 68000
* Clutch Hitter (US and Japan) - Romsets `cltchitr`, `cltchitrj` - FD1094 encrypted 68000, Sega System 18
* Crater Raider - Romset `crater`
* Crazy Climber 2 - Romset `cclimbr2`
* Dark Edge - Romset `darkedge`
* DD Crew - Romset `ddcrew`
* D. D. Crew (all FD1094 sets: World 2, 3 and 4 players, US, Japan 2 and 4 players) - Romsets `ddcrew`, `ddcrew1`, `ddcrew2`, `ddcrewu`, `ddcrewj`, `ddcrewj2` - Sega System 18, as in current MAME
* Desert Breaker (World and Japan) - Romsets `desertbr`, `desertbrj` - FD1094 encrypted 68000, Sega System 18
* Demolition Derby - Romset `demoderb`
* Die Hard Arcade - Romset `diehard` - Requires a fast system; video and sound issues remain
* Discs Of Tron - Romsets `dotron` and `dotrone`
@@ -436,6 +514,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Kick - Romset `kick`
* Kick'N Run- Romset `kicknrun`
* Kozmik Kroozr - Romset `kroozr`
* Laser Ghost (World, US and Japan) - Romsets `lghost`, `lghostu`, `lghostj` - FD1094 encrypted 68000, Sega System 18, light guns
* Legion (ver 2.03) - Romset `legion`
* Macho Mouse - Romset `machomou` - colors fixed
* Mario's Open Golf (Playchoice 10) - Romset `pc_moglf`
@@ -452,11 +531,13 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Phantasm - Romset `phantasm`
* Photo Y2k - Romset `photoy2k`
* Pigskin 621AD - Romset `pigskin`
* Princess Clara Daisakusen - Romset `prikura`
* Power Drive - Romset `powerdrv`
* Prebillian - `pbillian`
* Pro Baseball Skill Tryout - `tryout`
* Puzzle King (PacMan 2 with Tetris & HyperMan 2 & Snow Bros - `4in1boot`
* Rabbit - Romset `rabbit` - no sound
* Raiden II - Romset `raiden2`
* Rampage - Romsets `rampage` and `rampage2`
* Risky Challenge - Romset `riskchal`
* Rohga Armor Force - Romsets `rohga`, `rohgah`, `rohgau`
@@ -467,6 +548,15 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Satan's Hollow - Romset `shollow`
* Sega Megaplay : Golden Axe II - Romset `mp_gaxe2`
* Sega Megaplay : Sonic The Hedgehog - Romset `mp_sonic`
* Sega Mega-Tech : After Burner - Romset `mt_aftrb` - SMS based
* Sega Mega-Tech : Astro Warrior - Romset `mt_astro` - SMS based
* Sega Mega-Tech : Bonanza Bros. - Romset `mt_bbros` - the good dump of current MAME
* Sega Mega-Tech : Ghouls'n Ghosts - Romset `mt_gng` - the good dump of current MAME
* Sega Mega-Tech : Golden Axe II - Romset `mt_gaxe2`
* Sega Mega-Tech : Great Golf - Romset `mt_ggolf` - SMS based, the good dump of current MAME
* Sega Mega-Tech : Parlour Games - Romset `mt_parlg` - SMS based
* Sega Mega-Tech : Shinobi - Romset `mt_shnbi` - SMS based
* Sega Mega-Tech : Tetris - Romset `mt_tetri` - the good dump of current MAME
* Shisensho II * Mature * - Romset `shisen2`
* Shogun Warriors - Romset `shogwarr`
* Shrike Avenger - Romset `shrike`
@@ -475,6 +565,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Slipstream - Romset `slipstrm`
* Snowboard Championship - Romset `snowboar`
* Solar Fox - Romset `solarfox`
* Songjiangyanyi Final - Romset `songjang` - the Mega Drive board of current MAME, the HBLANK status it waits for
* Space Position - Romset `spcpostn`
* Space Seeker - Romset `spaceskr`
* Speed Spin - Romset `speedspn` - gfx glitches
@@ -487,6 +578,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Tapper - Romset `tapper`
* Target Ball (Nude) - Romset `tgtball`
* Task Force Harrier - Romsets `tharrier` and `tharierj`
* The Dealer - Romset `dealer` - Epos Tristar 9000 board from current MAME
* Thunder Blade - Romsets `thndrbld` and `thndrbld1`
* Thunder Dragon - Romset `tdragon` - Minor sound issues remaining
* Thunder Strike - Romset `tstrike`
@@ -502,6 +594,7 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
* Under Fire - Romset `undrfire`
* U.S. Classic - Romset `usclssic` - colors fixed
* VS. Hot Smash - `hotsmash`
* Wally wo Sagase! (rev A and B, 2 and 3 players) - Romsets `wwallyj`, `wwallyja`, `wwallyja3p` - FD1094 encrypted 68000, Sega System 18, trackballs
* Wonder Boy in Monster Land (Japan New Ver.) - Romset `wbml`
* Wonder Boy in Monster Land (Japan Old Ver.) - Romset `wbmljo`
* Xenophobe - Romset `xenophob`
@@ -571,10 +664,12 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
## Games now with improved sound
* 800 Fathoms, Knock Out!!, Mariner, Triple Punch: AY-8910 clock of current MAME (1.536 MHz, verified on hardware), the sound was 16% too high and too fast
* 1945kIII
* Air Buster
* Ashita no Joe
* Asterix
* Asura Blade, Asura Buster (no more repeated voices and sound effects)
* Athena
* Bandito
* Big Event Golf
@@ -692,6 +787,8 @@ The list of direct contributors to the MAME 2003-Plus github repository can be f
## New and/or Recommended Input Options and Settings
* Ikari (joystick hack bootleg): dual stick aiming. Set the 'Aim with Right Stick' DIP switch to On (Tab menu, Dip Switches): the player walks with the left stick and aims and fires with the right stick; with the right stick released he fires where he walks, as before. Off by default.
* Added 'X-Way Joystick' Option to Analog Controls Menu only for IPT_DIAL and IPT_DIAL_V devices. This option is for use with x-way rotary joysticks (where the joystick can rotate X discrete steps, 8 or 12 appears to be most common). The joystick can still move up, down, left, right and diagonally. The most famous game to use this control scheme is Ikari Warriors.
Notes on this option:
- When on, prevents the character from rotating two discrete steps sometimes when the rotary joystick is just rotated one step.
@@ -765,6 +862,24 @@ Notes on this option:
## Misc Changes
* Save states (RunAhead, netplay) of the Galaxian/Scramble/Frogger hardware: Galaxian video (stars, flip, banks, background), the 7474 flip-flops, the Scramble sound RAM and timer, the RC filters of the sound streams, the global sound enable
* Sega System 18: all the games on the 315-5195 memory mapper, the segaic16 video and the VDP layer as in current MAME (171-5874, 171-5987 and Shadow Dancer ROM boards, FD1094 sets, Laser Ghost light guns, Wally wo Sagase! trackballs); the old `astorm` and `astorm2p` are now `astormj` and `astorm`
* Sega Mega Drive VDP (315-5313): now a module of its own (`vidhrdw/segavdp.c`), started with its own configuration by System C/C2, Mega-Tech, Mega Play, the Mega Drive bootlegs and System 18, so a change for one board no longer reaches the others; a game loaded after a Mega Play game in the same session no longer inherits its interrupt mode (e.g. Columns attract out of sync), and the VDP window position and VBLANK flag are in the save states
* Sega Mega Play: its own driver (`drivers/megaplay.c`, as in current MAME), the Mega Drive part shared with the other Mega Drive based boards; Tecmo World Cup is now `mp_twcup` and the BIOS version 2 ROM `epr-a15294.ic2`, as in current MAME
* Sega Mega-Tech: its own driver (`drivers/megatech.c`, as in current MAME), sets, ROMs and names as in current MAME (good dumps of `mt_bbros`, `mt_ggolf`, `mt_gng`, `mt_tetri`, the instruction ROMs in the cart at 0x300000); the Master System carts now run, on the Mega Drive in Mark III mode as in current MAME (the VDP in mode 4, the Z80 with the Sega mapper); the BIOS cart slots as in current MAME (the menu lists the one cart in slot 1, the slot RAM, the window into the cart), the BIOS display in its 224 line mode (the MENU title was cut) and drawn line by line; the Mega Drive VDP line timing and partial updates now count its own lines below the BIOS screen (they used the scanlines of the double screen); the 68000 writes to 0xa02000 of the boards without the Mega Play BIOS no longer go through a NULL pointer (Great Golf and Great Soccer crashed)
* Sega Mega Play: the BIOS overlay is transparent on colour 0 of both its palettes and covers its borders, as in current MAME (the boot logo screen was hidden behind a green background)
* Sega Mega Drive based bootlegs: their own driver (`drivers/megadriv_acbl.c`, as in current MAME), with the board variants of current MAME (the 6 button pads, the DIP switches at 0x770070 of the scrambled boards, the 3rd I/O port coins, the PIC16C57 of `barek2mb`); the new sets take their V-INT / H-INT through the VDP interrupt enables as on the real hardware (Mortal Kombat 3 crashed at boot), the descrambling of the bootlegs and the PIC of `barek2mb` now also work on big-endian hosts
* Genie / Y-BOX and Sun Mixing boards: their own drivers (`drivers/megadriv_ybox.c`, `drivers/megadriv_sunmix.c`, as in current MAME); the Y-BOX games run on the Mega Drive machine as in MAME (Z80, I/O, the VDP interrupts and HBLANK as on the real hardware), with the protection read back latches and the ROM address remapping of Shuihu Feng Yun Zhuan of current MAME
* Sega System C/C2: `drivers/segac2.c` now has only System C/C2, the Mega Drive part shared by the other boards is in `machine/megadriv.c` (as `megadriv.cpp` in current MAME); the sets, ROMs, titles, inputs and DIP switches as in current MAME; the protection chip as the EPM5032 logic of each game of current MAME (no more Ribbit! and Puyo Puyo 2 workarounds and fake tables, Print Club Vol.2, 4 and 5 now get past the protection); the alternate palette mode of Ribbit! and Twin Squash (instead of the palette address watching of Ribbit!); the 68000 at 8.95 MHz and the 59.92 Hz refresh as in current MAME (it ran at 7.67 MHz and 60 Hz: the games now follow the timing of MAME frame for frame), the V-INT and H-INT held until the 68000 takes them as on the board, the address mirrors, the battery-backed work RAM (high scores kept, as in current MAME) and the coin meters on the I/O chip
* YM2612 / YM3438: the busy flag after a data write (192 clocks, as in current MAME), and a timer started long after its last overflow runs a whole period instead of firing at once (Thunder Force AC, Bloxeed and the other System C2 games follow MAME again)
* Sega Mega Play: the V-INT of the BIOS VDP comes about 12 lines after the Mega Drive VBLANK, as in current MAME (it came ~80 lines early, and the BIOS/game handshake on port C could miss: Tecmo World Cup stayed on a black screen)
* Sega Mega Play / System E: the tiles of the SMS-type VDP are read byte by byte, so they are drawn right on big-endian hosts (the Mega Play BIOS screen had the wrong colours)
* Sega Mega Drive VDP: in H32 mode the sprite table base uses bit 0 of register 5, as on the real VDP (the fighters of Super Street Fighter II were missing, the sprites of Bonanza Bros. on Mega-Tech were garbled)
* PIC16C5x CPU core: the program counter wraps at the end of the program memory (the 2K parts start at 0x7ff and ran past the ROM), and the save states no longer register the ports and STATUS through a NULL pointer (the save of a game with a PIC crashed); these are in the data RAM, saved with the CPU memory
* Save states (netplay, RunAhead with a second instance) of the Mega Drive based boards: the Z80 RAM and bus state and the Mega-Tech / Mega Play BIOS registers and RAM are saved (Gunstar Heroes and Mazin Wars Mega Play went out of sync after loading a state in a new instance); the SN76496 PSG is saved, and the YM2612 DAC enable is restored from its own register (0x2b, it was read from 0x2d)
* Sega System 18 (also Moonwalker): the VDP palette writes no longer overflow the System 16 palette RAM (they corrupted the memory after it, e.g. garbled graphics in Shadow Dancer), and the sprite shadows over the VDP layer no longer index past the palette
* Save states (RunAhead, netplay) of the Sega System 18 hardware: the RF5C68 PCM, the YM2612/YM3438 envelope, LFO, frequency and timer state, the VDP layer, the sound ROM bank
* Save states (RunAhead, netplay) of the Sega System 16B hardware: the uPD7759 ADPCM chip, the sound CPU ROM bank, the segaic16 tilemap and sprite banks, flip, scroll latches and display enable
* Added HD647180 MCU sound support for Fire Shark and Vimana [arcadez]
* Added sound sample support for Cosmic Alien [BritneysPAIRS, arcadez]
* Updated sample support for Donkey Kong and Donkey kong JR to MAME87 [BritneysPAIRS, arcadez]
@@ -1159,6 +1274,19 @@ could crash on the score calc between levels is sorted [amadvance, arcadez]
* Ported across from FBL dink's fix for the broken text gfx layer in the Japanese version Of Cameltry [dink, arcadez]
* Added support for Jammin a rare Atari prototype music game to the Donkey Kong driver [arcadez]
* Added Saurian Front a super rare Williams prototype of Midway's Strike Force to the midyunit driver [arcadez]
* Added Adventure Canoe to the taitosj driver [arcadez, jackphilippi, dink]
* Added Adventure Canoe to the taitosj driver [arcadez, jackphilippi, dink]
* Added support for Ketsui: Kizuna Jigoku Tachi - IKD 2007 Special Version to pgm.c [arcadez]
* Fixed a protection related problem with powerups in Burning Force [MAMEDev, arcadez]
* Extended IREM Drum sample support to Lode Runner 3 and 4 [dink, arcadez]
* Improved the dip switch options for Data East's Break Thru [arcadez]
* Fixed BG GFX colours for Crater Raider [MAMEDev, arcadez]
* Fixed multiple sound sample issues in TAD CORP's Toki [MAMEDev, arcadez]
* Fixed sound sample playing for SEGA's Zaxxon [MAMEDev, arcadez]
* Fixed Palette banking problems for Pleiads [MAMEDev, arcadez]
* Added fixes from later MAME so that Princess Clara Daisakusen now works [MAMEDev, arcadez]
* Ported a new raiden2.c driver Raiden II Raiden DX and Zero Team etc etc now playable [Salvia, MAMEDev, FBN, vanni and claude, arcadez]
* Ported the Cave CV1000 driver from current MAME: SH-3 CPU (interpreter and a recompiler with the same results), the blitter, the YMZ770 sound chip, the NAND flash and the RTC9701 [MAMEDev, vanni and claude]
* Added support for the hvyunit.c driver ported across from my xbox project [arcadez, mistydreams, vanni and claude]
* Added Sky Robo / Tatakae! Big Fighter to armedf.c and hooked it up to the new mcs51 cpu
[arcadez, grant2258, AdvanceMAME, Zanac]
* Ported a driver for Atari's Akka Arrh across from AdvanceMAME [arcadez, AdvanceMAME]
+44 -1
View File
@@ -100,7 +100,9 @@ endif
ifeq ($(platform), unix)
TARGET = $(TARGET_NAME)_libretro.so
fpic = -fPIC
CFLAGS += $(fpic)
# only the retro_* entry points (RETRO_API) leave the library: the rest is
# reached directly instead of through the GOT and PLT
CFLAGS += $(fpic) -fvisibility=hidden
LDFLAGS += $(fpic) -shared -Wl,--version-script=link.T
# Linux Portable
@@ -828,6 +830,14 @@ ifeq (,$(findstring msvc,$(platform)))
CFLAGS += -Werror=vla -Werror=declaration-after-statement
endif
# no fused multiply-add: a*b+c rounded once (FMA) on AArch64, ARMv7 VFPv4
# and PowerPC gives other results than x86, where it is rounded twice;
# with it off the floating point results are the same on every host
# (netplay between them, save states and RunAhead)
ifeq (,$(findstring msvc,$(platform)))
CFLAGS += -ffp-contract=off
endif
# Required for RZIP support in cheat.c
CFLAGS += -DHAVE_ZLIB
@@ -864,6 +874,24 @@ ifeq ($(HAVE_ARMv6),1)
CFLAGS += -DHAVE_ARMv6
endif
# threads (libretro-common rthreads), as the other libretro cores do (beetle-psx):
# on by default, off where there is no thread library, and on the MSVC builds
# (the ST-V threaded video needs MSVC 2015's thread-local storage, the
# buildbot's MSVC lanes are 2005 and 2010: nothing would use the threads)
HAVE_THREADS ?= 1
ifneq (,$(filter $(platform), emscripten linux-portable ngc wii wiiu ps2 ps3 psl1ght psp1 ctr vita))
HAVE_THREADS = 0
endif
ifneq (,$(findstring msvc,$(platform)))
HAVE_THREADS = 0
endif
ifeq ($(HAVE_THREADS),1)
# pthreads are in the C library on Darwin and Android, Windows uses its own threads
ifeq (,$(findstring msvc,$(platform))$(findstring android,$(platform))$(findstring ios,$(platform))$(findstring tvos,$(platform))$(filter osx win,$(platform)))
LIBS += -lpthread
endif
endif
# include the various .mak files
ifneq (,$(filter $(INCLUDE_DRV),all))
include Makefile.common
@@ -948,3 +976,18 @@ ifeq ($(SPLIT_UP_LINK), 1)
@rm $@.in
endif
$(HIDE)rm -f $(OBJECTS) $(TARGET)
# 1. Map object files to dependency trackers
DEPFILES := $(OBJECTS:.o=.d)
# 2. ONLY read or handle dependencies if we are NOT running a clean command
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPFILES)
# 3. FIXED: Generate a pure, clean dependency file directly using the -MM flag
%.d: %.c
@echo "Generating dependency tracker for $<..."
$(HIDE)$(CC) -MM -MP -MT $(@:.d=.o) -MF $@ $< $(CFLAGS)
# 4. Fallback stub to prevent build errors if a header file is deleted
$(DEPFILES):
endif
+186 -6
View File
@@ -69,6 +69,7 @@ SOURCES_C += \
SOURCES_C += \
$(CORE_DIR)/machine/fd1089.c \
$(CORE_DIR)/machine/fd1094.c \
$(CORE_DIR)/machine/6522via.c \
$(CORE_DIR)/machine/6532riot.c \
$(CORE_DIR)/machine/6821pia.c \
@@ -79,6 +80,9 @@ SOURCES_C += \
$(CORE_DIR)/machine/8255ppi.c \
$(CORE_DIR)/machine/eeprom.c \
$(CORE_DIR)/machine/idectrl.c \
$(CORE_DIR)/machine/intelfsh.c \
$(CORE_DIR)/machine/ds2404.c \
$(CORE_DIR)/machine/ataflash.c \
$(CORE_DIR)/machine/mathbox.c \
$(CORE_DIR)/machine/mb87078.c \
$(CORE_DIR)/machine/random.c \
@@ -127,6 +131,7 @@ CPUS+=I186@
CPUS+=V20@
CPUS+=V30@
CPUS+=V33@
CPUS+=V25@
CPUS+=V60@
CPUS+=V70@
CPUS+=I8035@
@@ -134,6 +139,7 @@ CPUS+=I8039@
CPUS+=I8048@
CPUS+=N7751@
CPUS+=I8X41@
CPUS+=I8051@
CPUS+=M6800@
CPUS+=M6801@
CPUS+=M6802@
@@ -166,23 +172,35 @@ CPUS+=TMS9995@
CPUS+=Z8000@
CPUS+=TMS32010@
CPUS+=TMS32025@
CPUS+=NAMCOC71@
CPUS+=TMS32031@
CPUS+=I960@
CPUS+=MB86233@
CPUS+=MB86235@
CPUS+=ADSP21062@
CPUS+=CCPU@
CPUS+=ADSP2100@
CPUS+=ADSP2101@
CPUS+=ADSP2104@
CPUS+=ADSP2105@
CPUS+=ADSP2115@
CPUS+=ADSP2181@
CPUS+=PSXCPU@
CPUS+=H83002@
CPUS+=I386@
CPUS+=MN10200@
CPUS+=M37702@
CPUS+=ASAP@
CPUS+=UPD7810@
CPUS+=UPD7807@
CPUS+=ARM@
CPUS+=ARM7@
CPUS+=JAGUAR@
CPUS+=R3000@
CPUS+=R4600@
CPUS+=R5000@
CPUS+=SH2@
CPUS+=SH3@
CPUS+=DSP32C@
#CPUS+=PIC16C54@
CPUS+=PIC16C55@
@@ -243,6 +261,7 @@ SOUNDS+=SEGAPCM@
SOUNDS+=RF5C68@
SOUNDS+=CEM3394@
SOUNDS+=C140@
SOUNDS+=C352@
SOUNDS+=QSOUND@
SOUNDS+=SAA1099@
SOUNDS+=IREMGA20@
@@ -367,7 +386,7 @@ SOURCES_C += \
$(CORE_DIR)/vidhrdw/gridlee_vidhrdw.c $(CORE_DIR)/sndhrdw/gridlee_sndhrdw.c $(CORE_DIR)/drivers/gridlee.c \
$(CORE_DIR)/drivers/seattle.c $(CORE_DIR)/vidhrdw/voodoo_vidhrdw.c \
$(CORE_DIR)/vidhrdw/exterm_vidhrdw.c $(CORE_DIR)/drivers/exterm.c \
$(CORE_DIR)/machine/midwayic.c $(CORE_DIR)/sndhrdw/dcs.c \
$(CORE_DIR)/machine/midwayic.c $(CORE_DIR)/machine/smc91c9x.c $(CORE_DIR)/sndhrdw/dcs.c \
$(CORE_DIR)/machine/midyunit_machine.c $(CORE_DIR)/vidhrdw/midyunit_vidhrdw.c $(CORE_DIR)/drivers/midyunit.c \
$(CORE_DIR)/drivers/midxunit.c \
$(CORE_DIR)/machine/midwunit_machine.c $(CORE_DIR)/drivers/midwunit.c \
@@ -481,7 +500,8 @@ SOURCES_C += \
$(CORE_DIR)/vidhrdw/mitchell_vidhrdw.c $(CORE_DIR)/drivers/mitchell.c \
$(CORE_DIR)/vidhrdw/cbasebal_vidhrdw.c $(CORE_DIR)/drivers/cbasebal.c \
$(CORE_DIR)/vidhrdw/cps1_vidhrdw.c $(CORE_DIR)/drivers/cps1.c $(CORE_DIR)/drivers/cps2.c $(CORE_DIR)/machine/cps2crypt.c\
$(CORE_DIR)/drivers/zn.c \
$(CORE_DIR)/drivers/zn.c $(CORE_DIR)/sndhrdw/acclaim_rax.c $(CORE_DIR)/sndhrdw/taitozoom.c $(CORE_DIR)/sound/zsg2.c $(CORE_DIR)/cpu/tms57002/tms57002.c \
$(CORE_DIR)/drivers/cps3.c $(CORE_DIR)/sndhrdw/cps3_sndhrdw.c \
$(CORE_DIR)/vidhrdw/tms34061_vidhrdw.c \
$(CORE_DIR)/machine/capbowl_machine.c $(CORE_DIR)/vidhrdw/capbowl_vidhrdw.c $(CORE_DIR)/drivers/capbowl.c \
$(CORE_DIR)/vidhrdw/itech8_vidhrdw.c $(CORE_DIR)/drivers/itech8.c \
@@ -510,10 +530,10 @@ SOURCES_C += \
$(CORE_DIR)/drivers/system24.c $(CORE_DIR)/machine/system24_machine.c $(CORE_DIR)/vidhrdw/system24_vidhrdw.c \
$(CORE_DIR)/vidhrdw/segaic24.c $(CORE_DIR)/vidhrdw/segas18.c \
$(CORE_DIR)/drivers/segas32.c $(CORE_DIR)/machine/segas32.c $(CORE_DIR)/vidhrdw/segas32.c \
$(CORE_DIR)/vidhrdw/segac2_vidhrdw.c $(CORE_DIR)/drivers/segac2.c \
$(CORE_DIR)/vidhrdw/segavdp.c $(CORE_DIR)/vidhrdw/segac2_vidhrdw.c $(CORE_DIR)/machine/megadriv.c $(CORE_DIR)/drivers/segac2.c $(CORE_DIR)/drivers/megaplay.c $(CORE_DIR)/drivers/megatech.c $(CORE_DIR)/drivers/megadriv_acbl.c $(CORE_DIR)/drivers/megadriv_ybox.c $(CORE_DIR)/drivers/megadriv_sunmix.c \
$(CORE_DIR)/drivers/stv.c $(CORE_DIR)/drivers/stvhacks.c $(CORE_DIR)/machine/stvcd.c \
$(CORE_DIR)/machine/scudsp.c \
$(CORE_DIR)/vidhrdw/stvvdp1_vidhrdw.c $(CORE_DIR)/vidhrdw/stvvdp2_vidhrdw.c \
$(CORE_DIR)/vidhrdw/stvvid.c \
$(CORE_DIR)/vidhrdw/deniam_vidhrdw.c $(CORE_DIR)/drivers/deniam.c \
$(CORE_DIR)/machine/btime_machine.c $(CORE_DIR)/vidhrdw/btime_vidhrdw.c $(CORE_DIR)/drivers/btime.c \
$(CORE_DIR)/machine/decocass_machine.c $(CORE_DIR)/vidhrdw/decocass_vidhrdw.c $(CORE_DIR)/drivers/decocass.c \
@@ -805,6 +825,7 @@ SOURCES_C += \
$(CORE_DIR)/vidhrdw/raiden_vidhrdw.c $(CORE_DIR)/drivers/raiden.c $(CORE_DIR)/drivers/raiden2.c \
$(CORE_DIR)/vidhrdw/dcon_vidhrdw.c $(CORE_DIR)/drivers/dcon.c \
$(CORE_DIR)/vidhrdw/sengokmj_vidhrdw.c $(CORE_DIR)/drivers/sengokmj.c \
$(CORE_DIR)/machine/seibuspi_machine.c $(CORE_DIR)/vidhrdw/seibuspi_vidhrdw.c $(CORE_DIR)/drivers/seibuspi.c \
$(CORE_DIR)/sndhrdw/t5182.c \
$(CORE_DIR)/vidhrdw/mustache_vidhrdw.c $(CORE_DIR)/drivers/mustache.c \
$(CORE_DIR)/vidhrdw/darkmist_vidhrdw.c $(CORE_DIR)/drivers/darkmist.c \
@@ -1042,10 +1063,17 @@ SOURCES_C += \
$(CORE_DIR)/drivers/n8080.c \
$(CORE_DIR)/drivers/mirax.c \
$(CORE_DIR)/machine/model1_machine.c $(CORE_DIR)/vidhrdw/model1_vidhrdw.c $(CORE_DIR)/drivers/model1.c \
$(CORE_DIR)/machine/model2_machine.c $(CORE_DIR)/vidhrdw/model2_vidhrdw.c $(CORE_DIR)/drivers/model2.c \
$(CORE_DIR)/sndhrdw/segadsb.c $(CORE_DIR)/sound/mpeg_audio.c \
$(CORE_DIR)/drivers/cv1k.c $(CORE_DIR)/vidhrdw/cv1k_vidhrdw.c $(CORE_DIR)/sound/ymz770.c \
$(CORE_DIR)/machine/sega315_5881.c $(CORE_DIR)/machine/sega315_5838.c \
$(CORE_DIR)/drivers/calorie.c \
$(CORE_DIR)/drivers/hvyunit.c \
$(CORE_DIR)/drivers/akkaarrh.c \
$(CORE_DIR)/machine/mc8123.c \
$(CORE_DIR)/machine/namcoio_machine.c \
$(CORE_DIR)/drivers/tatsumi.c $(CORE_DIR)/vidhrdw/tatsumi.c $(CORE_DIR)/machine/tatsumi.c
$(CORE_DIR)/drivers/tatsumi.c $(CORE_DIR)/vidhrdw/tatsumi.c $(CORE_DIR)/machine/tatsumi.c \
$(CORE_DIR)/drivers/tx1.c $(CORE_DIR)/vidhrdw/tx1_vidhrdw.c $(CORE_DIR)/machine/tx1_machine.c $(CORE_DIR)/sndhrdw/tx1_sndhrdw.c
@@ -1092,6 +1120,14 @@ else
CPUDEFS += -DHAS_ADSP2115=0
endif
CPU=$(strip $(findstring ADSP2181@,$(CPUS)))
ifneq ($(CPU),)
CPUDEFS += -DHAS_ADSP2181=1
HAS_ADSP2100 = 1
else
CPUDEFS += -DHAS_ADSP2181=0
endif
CPU=$(strip $(findstring Z80@,$(CPUS)))
ifneq ($(CPU),)
CPUDEFS += -DHAS_Z80=1
@@ -1348,6 +1384,15 @@ else
CPUDEFS += -DHAS_V33=0
endif
CPU=$(strip $(findstring V25@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/nec
CPUDEFS += -DHAS_V25=1
SOURCES_C += $(CORE_DIR)/cpu/nec/v25.c
else
CPUDEFS += -DHAS_V25=0
endif
ifeq ($(HAS_V30),1)
SOURCES_C += $(CORE_DIR)/cpu/nec/nec.c
ifeq ($(DEBUGGER),1)
@@ -1432,6 +1477,15 @@ else
CPUDEFS += -DHAS_I8X41=0
endif
CPU=$(strip $(findstring I8051@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/i8051
CPUDEFS += -DHAS_I8051=1
SOURCES_C += $(CORE_DIR)/cpu/i8051/i8051.c
else
CPUDEFS += -DHAS_I8051=0
endif
CPU=$(strip $(findstring M6800@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/m6800
@@ -1813,6 +1867,15 @@ else
CPUDEFS += -DHAS_TMS32010=0
endif
CPU=$(strip $(findstring NAMCOC71@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/namcoc71
CPUDEFS += -DHAS_NAMCOC71=1
SOURCES_C += $(CORE_DIR)/cpu/namcoc71/c71.c
else
CPUDEFS += -DHAS_NAMCOC71=0
endif
CPU=$(strip $(findstring TMS32025@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/tms32025
@@ -1825,6 +1888,42 @@ else
CPUDEFS += -DHAS_TMS32025=0
endif
CPU=$(strip $(findstring MB86233@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/mb86233
CPUDEFS += -DHAS_MB86233=1
SOURCES_C += $(CORE_DIR)/cpu/mb86233/mb86233.c
else
CPUDEFS += -DHAS_MB86233=0
endif
CPU=$(strip $(findstring MB86235@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/mb86235
CPUDEFS += -DHAS_MB86235=1
SOURCES_C += $(CORE_DIR)/cpu/mb86235/mb86235.c
else
CPUDEFS += -DHAS_MB86235=0
endif
CPU=$(strip $(findstring ADSP21062@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/sharc
CPUDEFS += -DHAS_ADSP21062=1
SOURCES_C += $(CORE_DIR)/cpu/sharc/sharc.c
else
CPUDEFS += -DHAS_ADSP21062=0
endif
CPU=$(strip $(findstring I960@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/i960
CPUDEFS += -DHAS_I960=1
SOURCES_C += $(CORE_DIR)/cpu/i960/i960.c
else
CPUDEFS += -DHAS_I960=0
endif
CPU=$(strip $(findstring TMS32031@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/tms32031
@@ -1862,6 +1961,42 @@ else
CPUDEFS += -DHAS_PSXCPU=0
endif
CPU=$(strip $(findstring H83002@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/h83002
CPUDEFS += -DHAS_H83002=1
SOURCES_C += $(CORE_DIR)/cpu/h83002/h83002.c
else
CPUDEFS += -DHAS_H83002=0
endif
CPU=$(strip $(findstring I386@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/i386
CPUDEFS += -DHAS_I386=1
SOURCES_C += $(CORE_DIR)/cpu/i386/i386.c
else
CPUDEFS += -DHAS_I386=0
endif
CPU=$(strip $(findstring MN10200@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/mn10200
CPUDEFS += -DHAS_MN10200=1
SOURCES_C += $(CORE_DIR)/cpu/mn10200/mn10200.c
else
CPUDEFS += -DHAS_MN10200=0
endif
CPU=$(strip $(findstring M37702@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/m37710
CPUDEFS += -DHAS_M37702=1
SOURCES_C += $(CORE_DIR)/cpu/m37710/m37710.c $(CORE_DIR)/cpu/m37710/m37710o0.c $(CORE_DIR)/cpu/m37710/m37710o1.c $(CORE_DIR)/cpu/m37710/m37710o2.c $(CORE_DIR)/cpu/m37710/m37710o3.c
else
CPUDEFS += -DHAS_M37702=0
endif
CPU=$(strip $(findstring ASAP@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/asap
@@ -1911,6 +2046,15 @@ else
CPUDEFS += -DHAS_ARM=0
endif
CPU=$(strip $(findstring ARM7@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/arm7
CPUDEFS += -DHAS_ARM7=1
SOURCES_C += $(CORE_DIR)/cpu/arm7/arm7.c
else
CPUDEFS += -DHAS_ARM7=0
endif
CPU=$(strip $(findstring JAGUAR@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/jaguar
@@ -1975,6 +2119,15 @@ else
CPUDEFS += -DHAS_SH2=0
endif
CPU=$(strip $(findstring SH3@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/sh3
CPUDEFS += -DHAS_SH3=1
SOURCES_C += $(CORE_DIR)/cpu/sh3/sh3.c
else
CPUDEFS += -DHAS_SH3=0
endif
CPU=$(strip $(findstring DSP32C@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/dsp32
@@ -2507,6 +2660,14 @@ else
SOUNDDEFS += -DHAS_C140=0
endif
SOUND=$(strip $(findstring C352@,$(SOUNDS)))
ifneq ($(SOUND),)
SOUNDDEFS += -DHAS_C352=1
SOURCES_C += $(CORE_DIR)/sound/c352.c
else
SOUNDDEFS += -DHAS_C352=0
endif
SOUND=$(strip $(findstring QSOUND@,$(SOUNDS)))
ifneq ($(SOUND),)
SOUNDDEFS += -DHAS_QSOUND=1
@@ -2660,9 +2821,19 @@ SOUNDDEFS += -DHAS_ICS2115=0
endif
SOURCES_C += \
$(CORE_DIR)/lib/mame-chd/chd.c \
$(CORE_DIR)/lib/mame-chd/mame_sha1.c
# libchdr: reads the hard disk CHDs (every version, zlib/LZMA/Huffman/FLAC)
SOURCES_C += \
$(CORE_DIR)/lib/libchdr/src/libchdr_bitstream.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_cdrom.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_chd.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_flac.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_huffman.c \
$(CORE_DIR)/lib/libchdr/deps/lzma/LzFind.c \
$(CORE_DIR)/lib/libchdr/deps/lzma/LzmaDec.c \
$(CORE_DIR)/lib/libchdr/deps/lzma/LzmaEnc.c
SOURCES_C += \
$(CORE_DIR)/libretro-deps/libFLAC/bitreader.c \
$(CORE_DIR)/libretro-deps/libFLAC/cpu.c \
@@ -2689,6 +2860,15 @@ SOURCES_C += \
$(CORE_DIR)/lib/zlib/unzip.c \
$(CORE_DIR)/lib/zlib/zutil.c
# sljit: run-time code generator of the MIPS recompilers (empty where they are not supported)
SOURCES_C += $(CORE_DIR)/lib/sljit/sljit_mame.c
# threads (libretro-common rthreads, set by the platform: see Makefile): the ST-V threaded video option
ifeq ($(HAVE_THREADS),1)
COREDEFINES += -DHAVE_THREADS
SOURCES_C += $(LIBRETRO_COMM_DIR)/rthreads/rthreads.c
endif
ifeq ($(STATIC_LINKING),1)
else
SOURCES_C += \
+95 -1
View File
@@ -69,6 +69,7 @@ SOURCES_C += \
SOURCES_C += \
$(CORE_DIR)/machine/fd1089.c \
$(CORE_DIR)/machine/fd1094.c \
$(CORE_DIR)/machine/6522via.c \
$(CORE_DIR)/machine/6532riot.c \
$(CORE_DIR)/machine/6821pia.c \
@@ -624,6 +625,7 @@ endif
ifneq (,$(filter $(INCLUDE_DRV),drv_backfire core_none))
CPUS+=ARM@
CPUS+=ARM7@
SOUNDS+=YMZ280B@
SOURCES_C += \
$(CORE_DIR)/machine/decocrpt.c \
@@ -1072,6 +1074,14 @@ else
CPUDEFS += -DHAS_ADSP2115=0
endif
CPU=$(strip $(findstring ADSP2181@,$(CPUS)))
ifneq ($(CPU),)
CPUDEFS += -DHAS_ADSP2181=1
HAS_ADSP2100 = 1
else
CPUDEFS += -DHAS_ADSP2181=0
endif
CPU=$(strip $(findstring Z80@,$(CPUS)))
ifneq ($(CPU),)
CPUDEFS += -DHAS_Z80=1
@@ -1328,6 +1338,15 @@ else
CPUDEFS += -DHAS_V33=0
endif
CPU=$(strip $(findstring V25@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/nec
CPUDEFS += -DHAS_V25=1
SOURCES_C += $(CORE_DIR)/cpu/nec/v25.c
else
CPUDEFS += -DHAS_V25=0
endif
ifeq ($(HAS_V30),1)
SOURCES_C += $(CORE_DIR)/cpu/nec/nec.c
ifeq ($(DEBUGGER),1)
@@ -1412,6 +1431,15 @@ else
CPUDEFS += -DHAS_I8X41=0
endif
CPU=$(strip $(findstring I8051@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/i8051
CPUDEFS += -DHAS_I8051=1
SOURCES_C += $(CORE_DIR)/cpu/i8051/i8051.c
else
CPUDEFS += -DHAS_I8051=0
endif
CPU=$(strip $(findstring M6800@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/m6800
@@ -1793,6 +1821,15 @@ else
CPUDEFS += -DHAS_TMS32010=0
endif
CPU=$(strip $(findstring NAMCOC71@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/namcoc71
CPUDEFS += -DHAS_NAMCOC71=1
SOURCES_C += $(CORE_DIR)/cpu/namcoc71/c71.c
else
CPUDEFS += -DHAS_NAMCOC71=0
endif
CPU=$(strip $(findstring TMS32025@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/tms32025
@@ -1842,6 +1879,33 @@ else
CPUDEFS += -DHAS_PSXCPU=0
endif
CPU=$(strip $(findstring H83002@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/h83002
CPUDEFS += -DHAS_H83002=1
SOURCES_C += $(CORE_DIR)/cpu/h83002/h83002.c
else
CPUDEFS += -DHAS_H83002=0
endif
CPU=$(strip $(findstring MN10200@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/mn10200
CPUDEFS += -DHAS_MN10200=1
SOURCES_C += $(CORE_DIR)/cpu/mn10200/mn10200.c
else
CPUDEFS += -DHAS_MN10200=0
endif
CPU=$(strip $(findstring M37702@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/m37710
CPUDEFS += -DHAS_M37702=1
SOURCES_C += $(CORE_DIR)/cpu/m37710/m37710.c $(CORE_DIR)/cpu/m37710/m37710o0.c $(CORE_DIR)/cpu/m37710/m37710o1.c $(CORE_DIR)/cpu/m37710/m37710o2.c $(CORE_DIR)/cpu/m37710/m37710o3.c
else
CPUDEFS += -DHAS_M37702=0
endif
CPU=$(strip $(findstring ASAP@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/asap
@@ -1891,6 +1955,15 @@ else
CPUDEFS += -DHAS_ARM=0
endif
CPU=$(strip $(findstring ARM7@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/arm7
CPUDEFS += -DHAS_ARM7=1
SOURCES_C += $(CORE_DIR)/cpu/arm7/arm7.c
else
CPUDEFS += -DHAS_ARM7=0
endif
CPU=$(strip $(findstring JAGUAR@,$(CPUS)))
ifneq ($(CPU),)
OBJDIRS += $(CORE_DIR)/cpu/jaguar
@@ -2487,6 +2560,14 @@ else
SOUNDDEFS += -DHAS_C140=0
endif
SOUND=$(strip $(findstring C352@,$(SOUNDS)))
ifneq ($(SOUND),)
SOUNDDEFS += -DHAS_C352=1
SOURCES_C += $(CORE_DIR)/sound/c352.c
else
SOUNDDEFS += -DHAS_C352=0
endif
SOUND=$(strip $(findstring QSOUND@,$(SOUNDS)))
ifneq ($(SOUND),)
SOUNDDEFS += -DHAS_QSOUND=1
@@ -2640,9 +2721,19 @@ SOUNDDEFS += -DHAS_ICS2115=0
endif
SOURCES_C += \
$(CORE_DIR)/lib/mame-chd/chd.c \
$(CORE_DIR)/lib/mame-chd/mame_sha1.c
# libchdr: reads the hard disk CHDs (every version, zlib/LZMA/Huffman/FLAC)
SOURCES_C += \
$(CORE_DIR)/lib/libchdr/src/libchdr_bitstream.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_cdrom.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_chd.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_flac.c \
$(CORE_DIR)/lib/libchdr/src/libchdr_huffman.c \
$(CORE_DIR)/lib/libchdr/deps/lzma/LzFind.c \
$(CORE_DIR)/lib/libchdr/deps/lzma/LzmaDec.c \
$(CORE_DIR)/lib/libchdr/deps/lzma/LzmaEnc.c
SOURCES_C += \
$(CORE_DIR)/libretro-deps/libFLAC/bitreader.c \
$(CORE_DIR)/libretro-deps/libFLAC/cpu.c \
@@ -2692,6 +2783,9 @@ SOURCES_C += \
$(CORE_DIR)/lib/zlib/uncompr.c \
$(CORE_DIR)/lib/zlib/unzip.c \
$(CORE_DIR)/lib/zlib/zutil.c
# sljit: run-time code generator of the MIPS recompilers (empty where they are not supported)
SOURCES_C += $(CORE_DIR)/lib/sljit/sljit_mame.c
endif
ifeq ($(ZLIB_UNCOMPRESS), 1)
+115
View File
@@ -0,0 +1,115 @@
# Capcom CPS-3: how the driver works and where it differs from the hardware
Sets: `redearth`, `warzard`, `sfiii`, `sfiii2`, `jojo`, `sfiii3`, `jojoba`
and their clones (53 in all, MAME's list without the multi-game bootlegs),
plus `sfiii4n`, the "4rd Arrange Edition 2013" hack of 3rd Strike that
FBNeo has and MAME does not.
Files: `src/drivers/cps3.c` (memory map, flash SIMMs, video, DMA, sets),
`src/sndhrdw/cps3_sndhrdw.c` (the 16 voice sample chip). A C89 port of
current MAME's `cps3.cpp` and `cps3_a.cpp`.
## The board
- A custom Hitachi SH-2 at 25 MHz that decrypts what it reads from the BIOS,
the program SIMMs and its cache RAM, with a per-game key stored in the
cartridge.
- The game in flash SIMMs: two SIMMs of 4 Fujitsu 29F016A chips (2 MB each)
for the program, up to four SIMMs of 8 chips for graphics and samples.
- 2D video: sprites with zoom, tilemaps drawn as sprites, a text layer,
palette DMA with fades, character DMA with RLE decompression.
- 16 voices of 8-bit samples read from the graphics SIMMs.
- A SCSI CD-ROM drive: the BIOS writes the game from the CD into the SIMMs.
## No CD drive
The CD drive is not emulated. All sets run from SIMMs already written:
- The "NO CD" sets come with their SIMMs and a BIOS that does not look for a
drive, as in MAME.
- The CD sets (Europe, USA, Japan, Asia, Hispanic versions) get the SIMM data
of their version, the same as the NO CD set of that date (the SIMM
contents do not depend on the region, the BIOS does). As in FBNeo, which
plays them the same way. MAME needs the CD image instead.
- The CD BIOSes would stop on the missing drive. The BIOS has a flag the
no-CD BIOSes have set (byte 0x1fecc, bit 0); the driver sets it, and the
game runs from the SIMMs.
- The Red Earth / Warzard CD BIOSes have no such flag: the driver starts the
game from the SIMMs as the BIOS would (PC and SP from the program's vector
table, VBR on it), as FBNeo does.
The flash chips answer the Fujitsu command set (ID, program, erase), but
what is written to them is not saved: no set writes them while playing.
## Region
The region is not a switch on the board: it is a byte in the cart's flash
(the low nibble of the BIOS byte 0x1fecb, 0x1fedb on Red Earth / Warzard),
which the BIOS and the games read. A fake DIP switch, "Region", patches it at
reset, as in FBNeo: Japan, Asia, Europe, USA, Hispanic, Brazil, Oceania or
the second Asia code, or "As BIOS" to keep the dumped value. The default is
Europe for every set, whatever region its BIOS has; 2nd Impact, which had no
European release, defaults to USA. It changes the boot screen colour, the
warnings, the coin settings, the language and the title (Warzard in Japan,
Red Earth elsewhere). Change it, then reset.
The game options (coins, difficulty, monitor flip, language...) are in the
games' own test menu (F2) and kept in the cart's EEPROM, saved as NVRAM.
## Encryption
The BIOS is decrypted at load. The program SIMMs are kept as dumped and also
decrypted into a copy the CPU fetches opcodes from; data reads come out
decrypted, as the custom CPU reads them. Two hooks in the SH-2 core (both
optional, unused by the other SH-2 drivers) do this:
- `opcode_read`: the opcode fetch, from the BIOS, the decrypted program copy
or the decrypted copy of the cache RAM.
- `dma_read_hook`: the SH-2 DMA bypasses the decryption on the real board;
the hook re-encrypts what the handlers decrypted.
`sfiii2` runs off a "dead" cartridge: the key is gone and its program is
stored with code encrypted and data not, as in MAME.
## Video
The renderer is MAME's: sprites and tilemaps go to a render buffer of
palette indexes (with the shadow/highlight blend bits), which is copied to the
screen through the full screen zoom; the text layer is drawn on top. Tiles
are read straight from the character RAM (no gfx elements to keep dirty).
Colours are 15-bit with no extension of the low bits, as on the board (its
video DAC has them grounded). The screen width follows the CRTC registers, as
in MAME (384 pixels in the games checked).
## Idle loop
Each game waits for the vblank interrupt by reading a word of the main RAM
in a loop. When the loop reads it, the CPU skips to the next event (the
addresses are FBNeo's, one per game and version). Speed goes from about
4.5x to 12-16x real time on an x86 core. The games run the same; only the
attract mode can pick other fighters, since the games draw random numbers
from the time spent in that loop.
## Sound
MAME's sound device: 16 voices, signed 8-bit samples, the board clock / 3 /
384 (37.3 kHz), loop and end addresses, a volume per side. Levels checked
against MAME's WAV output of the same attract mode.
## ROM loading of merged sets
Merged sets keep the files of the clones in subfolders of the parent's zip,
with the same names (`sfiii3n/sfiii3-simm1.0`, `sfiii3nr1/sfiii3-simm1.0`).
The ROM loader of this core matched by name only and took the first one.
It now looks for the expected CRC first, then for the name, so merged,
split and non-merged sets all load.
## Checked
- Attract mode of `sfiii3n`, `jojoba`, `sfiii2n`, `jojon`, `sfiiin`,
`redearthn` against MAME 0.264 at the same frames: the same screens.
- A game of 3rd Strike (coin, character select, fight).
- CD sets: the regional warning screens, then the game (`sfiii3`, `sfiii3u`,
`sfiiih`, `sfiii2`, `jojor2`, `jojobaner2`, `warzard`).
- Save states: loaded in a new process, the game goes on frame for frame.
- Big-endian: the PowerPC build renders as x86.
+119
View File
@@ -0,0 +1,119 @@
# Cave CV1000: how the driver works and where it differs from MAME
Sets (MAME's list without the touch screen mahjong game `mmmbanc`):
| Board | Sets |
|---|---|
| CV1000-B (8 MB RAM) | `mushisam`, `mushisama`, `mushisamb`, `ibara`, `ibarao`, `ibarablk`, `ibarablka`, `espgal2`, `espgal2a`, `espgal2b`, `mushitam`, `mushitama`, `pinkswts`, `pinkswtsa`, `pinkswtsb`, `pinkswtsx`, `pinkswtssc`, `futari15`, `futari15a`, `futari10`, `futaribl`, `futariblj`, `mmpork`, `deathsml` |
| CV1000-D (16 MB RAM) | `dsmbl`, `ddpdfk`, `ddpdfk10`, `dfkbl` |
`futaribl` is the World / English set; the others are Japanese.
Files:
- `src/cpu/sh3/sh3.c`: the SH-3 (SH7709S) CPU and its peripherals.
- `src/cpu/sh3/sh3jit.c`: the SH-3 recompiler, included by `sh3.c`.
- `src/drivers/cv1k.c`: memory maps, NAND flash, RTC9701, inputs, sets.
- `src/vidhrdw/cv1k_vidhrdw.c`: the blitter (Cave's EPIC12 FPGA).
- `src/sound/ymz770.c`: the Yamaha YMZ770 ("AMM"), on `src/sound/mpeg_audio.c`.
All are C89 ports of current MAME (`sh.cpp`, `sh3comn.cpp`, `sh4*.cpp`,
`cv1k.cpp`, `epic12*.cpp`, `ymz770.cpp`).
## The board
- Hitachi SH7709S, an SH-3 at 102.4 MHz, big-endian, no FPU. The boot code
copies the game from the NAND flash to work RAM and runs it from there.
- The blitter: copies sprites from an 8192 x 4096 VRAM to the screen with
flips, tint, transparency and 8 source and 8 destination blend modes, and
uploads graphics to VRAM. The games wait on it.
- The YMZ770: 16 channels of compressed audio from two 4 MB flash chips,
and a sequencer.
- 128 MB NAND flash with the graphics and data, a NOR flash with the boot
code, the RTC9701 with its EEPROM (settings and high scores).
## CPU
The interpreter follows current MAME's SH-3 instruction by instruction,
with the cycle counts of MAME's recompiler (MAME only runs the SH-3 with its
recompiler) and MAME's SH7709S cache and bus timing model: every data access
goes through a model of the 16 KB cache, the write-back, the burst fills and
the wait states of each bus area. The games' speed (and their slowdowns)
depends on it.
Peripherals: the interrupt controller, the three timers (TMU), the DMA
controller (the transfer at once, the end interrupt after the transfer
time, as MAME), the I/O ports (inputs, NAND control, RTC serial line), the
cache address array. The timers run on the machine time, as in MAME.
## Recompiler
Core option "SH-3 Dynarec" (enabled by default; offered for these games
only, on the hosts where it runs: x86, x86-64, ARMv7, AArch64, except the
systems that forbid run-time code generation). Big-endian hosts use the
interpreter.
It gives the same results as the interpreter, cycle for cycle: a saved
state is the same with and without it, so netplay, save states and RunAhead
don't depend on it.
- Straight runs of instructions, up to an unconditional branch and its
delay slot, become native code (sljit, as the MIPS and ADSP recompilers
of this core). Conditional branches leave the block or loop inside it.
- The timeslice is checked before every instruction, as the interpreter's
loop does; the cycles are taken in the interpreter's order around the
memory accesses and the bus timing.
- Loads and stores compute their address natively and call the
interpreter's accessors (memory handlers, cache and bus timing). The
instructions without native code call the interpreter for that
instruction.
- The block leaves when an interrupt becomes pending or a write touches
translated code. Writes over translated code (CPU stores, DMA) and state
loads flush the translations.
## Speedups
As in MAME, each game has an idle loop speedup: the read of the variable the
game polls in its wait loop skips 10 us of CPU time. The loop reads it in
the delay slot of its branch; MAME's recompiler reports there the PC it
stored two bytes after the loop start, so it skips on every pass; this
driver does the same with the delay slot's own PC.
MAME suspends the CPU for those 10 us. This core's scheduler doesn't give
the time back to a CPU resumed in the timeslice that suspended it, so the
CPU would fall further behind on every pass: the 10 us are eaten from the
timeslice instead (1024 cycles), with the same effect.
## Video
The VRAM is kept as 16-bit pixels (the 5-5-5 colour and the transparency
bit), 64 MB instead of MAME's 128 MB of 32-bit pixels; the blits work on
the same values as MAME's. The blitter runs at once when started, and is
busy for the time MAME computes for that blit (the games read the busy
flag). MAME can run it in a separate thread; this core doesn't.
## Sound
The YMZ770 decodes MAME's AMM variant of MPEG audio, added to
`mpeg_audio.c` next to layers I and II (used by the Sega DSB), which are
unchanged.
## NAND flash, RTC, NVRAM
- The NAND is read with its spare area and bad block table through the
flash interface and port E (busy for 25 us after a page read).
- The RTC9701 is set from the host clock at start, as MAME does.
- NVRAM: the RTC EEPROM, and the NAND blocks the game erased or programmed
(only those, not the 128 MB).
## Save states
Every part has its state saved (CPU, peripherals, cache model, blitter
and VRAM, YMZ770, NAND, RTC). A state is about 77 MB with the VRAM (85 MB on
CV1000-D). Tested: a save and load on every frame (RunAhead-like) gives the
same frames, audio and state as a run without them.
## Not done
- `mmmbanc` (Medal Mahjong Moukari Bancho), a touch screen game.
- Akai Katana and DoDonPachi SaiDaiOuJou: commented out in MAME too.
+203
View File
@@ -0,0 +1,203 @@
# Sega Model 1: how the driver works and where it differs from the hardware
Sets: `vr`, `vformula`, `vf`, `swa`, `swaj`, `wingwar`, `wingwaru`,
`wingwarj`, `wingwar360`, `netmerc`.
Files: `src/drivers/model1.c` (boards, maps, ROMs), `src/machine/model1_machine.c`
(the TGP), `src/vidhrdw/model1_vidhrdw.c` (the renderer, ported from current
MAME), `src/sndhrdw/segadsb.c` (the Digital Sound Board of Star Wars Arcade).
## The TGP (geometry coprocessor)
The TGP is a Fujitsu MB86233 DSP running a program from a 315-xxxx ROM:
315-5573 (Virtua Racing, Virtua Formula), 315-5724 (Virtua Fighter), 315-5711
(Star Wars Arcade, Wing War, NetMerc). The V60 sends it commands (a function
number and its arguments) through a FIFO and reads the results back.
The driver runs the TGP functions in C (high level emulation, HLE), started
from MAME 0.215, the last MAME with an HLE TGP. In MAME 0.215 Virtua Racing had
no HLE at all and Star Wars Arcade and Wing War did not work.
### Checked against the real program
The core also contains the MB86233 (from the Model 2 work), so the real TGP
program can run next to the HLE. A development build (`-DMODEL1_TGP_DEV`)
reads `MODEL1_TGP` from the environment:
- `lle`: the game runs on the real TGP program only.
- `oracle`: the game runs on the real TGP program, the HLE gets the same
input, and every call is compared: function, arguments, the results of
both. The pairing follows the input stream (a call ends when the DSP takes
the next function word), so a function giving a wrong number of results
does not shift the others. The TGP RAM both sides keep is compared every
frame. Every 600 frames it prints, for each function, the calls that were
exact, near (rounding), wrong, or gave a wrong number of results.
With this, every function the games call was rewritten from the DSP program
until the results match bit for bit: same table lookups (sine, 1/x, 1/sqrt,
atan come from the TGP's table ROM through its I/O ports, with one
multiply-subtract step), same order of the sums, same comparisons (the ALU's
`-0` is neither negative nor positive). Checked on attract and play of
`vr` (three tracks), `vformula`, `vf`, `swa`, `wingwar`, `wingwar360` and
`netmerc`: no call differs and the TGP RAM stays identical.
Virtua Fighter's program (315-5724) is marked as a bad dump in MAME, but it
runs the game on the MB86233 core, so it is checked the same way. About half
of its functions differ from 315-5573 (matrix stack and saved matrices at
other addresses, the camera, collision bitmaps, ground box test, list walks
in the copro RAM), so it has its own table. MAME 0.215 used the Virtua Racing
table for it, with guessed camera functions (one returned random numbers),
which put the camera far from the fighters. For Virtua Fighter the oracle
also compares the TGP's internal RAM after every call. Over 9000 frames of
attract and fights, 55 functions and 3.8 million calls give the same results
and the same RAM.
The table lookups, the copro RAM (0x2000 words; with address bit 0x40000 set
the address steps by 4) and the list functions follow current MAME.
### Program bugs reproduced
The HLE reproduces what the real programs do, bugs included, because the
games run with them on the real boards:
- 315-5711 `roty` starts its first sum from the DSP's `d` register, which
still holds the dispatch address (a denormal): the first matrix element
gets `0x6c` added to it.
- 315-5711 `normalize` never loads y; it uses whatever the scratch word at
`$71` holds from an earlier function (tracked by the HLE).
- 315-5711 `f47` starts its sum of squares from the z difference.
- 315-5711 `fsqrt` skips the mantissa step and does not return a square root.
- The matrix stack keeps 7 levels; past them the depth only counts (315-5711
pushes again past 8, while its pops past 7 only count). The matrix slots
and the 315-5711 accumulator stack sit in the same TGP RAM, as on the
board.
- 315-5711 `f52` (0x34, matrix inverse; Star Wars Arcade calls it) works
by cofactors, never reads the first element, ORs two elements where a
subtract is expected, and adds in the second element the scratch word
`$11` an earlier function left (push, multiply and read leave a matrix
element or argument there; tracked by the HLE).
- 315-5711 `f56` (0x38, segment against a polygon list) stops at the first
polygon hit, not the nearest one.
- The 315-5711 games use the current matrix before setting it: the HLE starts
from what the TGP RAM holds at power on (zeros in the emulated TGP).
### What is not emulated
- Table entries a program leaves empty (it returns at once) take no
arguments and give no results; 315-5724 functions no game was seen calling
are not emulated, except the simple ones (normalize, divide, set the
translation).
- 315-5711 functions no game was seen calling: self tests 0x04, 0x3d, 0x3e
(results 0), 0x42 (matrix stack pop and multiply, with bugs overwriting the
stack), 0x21 (the program jumps into the middle of another function). They
take and give the right number of words so the command stream stays in step.
### ROMs
The TGP program ROM stays in the sets as in current MAME. For Star Wars
Arcade, Wing War and NetMerc the HLE follows 315-5711 with CRC 6a21f304, as
current MAME. An older dump (CRC c5ddb8fc) differs in two words: the entry
of `f52` (which then reads the wrong RAM and gives NaNs) and the end test
of `f56`. It loads with a checksum warning; the HLE does not use the ROM.
The V60 reaches the TGP in its I/O space as well as in memory, with the
same mirrors as current MAME: Wing War sends its boot command (8, clear the
matrix stack) with an OUT to a mirror of the FIFO, and the real program
waits for it before taking any other command.
## I/O board
The Model 1 I/O board (model1io, model1io2: a Z80 with its own BIOS) is
simulated: inputs, DIP switches, analog channels and the backup are put where
the games read them in the 2 KB dual port RAM:
00-07 analog channels
08-0a IN0 - IN2 (active low)
0b-0d DSW1 - DSW3 (active low, all off)
0e board switches
0f outputs (lamps, coin counters)
11 drive board / motion base output
20 command (2 store the backup 0x100-0x1ff, 3 load it), 21 status
The DIP switches must read as off: 0 turned on the debug displays of Virtua
Racing and NetMerc. The backup is saved in the NVRAM file.
## Sound
Model 1 sound board (68000, two MultiPCM, YM3438) behind an i8251 UART at
31250 baud, as current MAME. Star Wars Arcade also has the Digital Sound
Board (Z80 + MPEG audio), which listens to the sound board's UART.
The simulated I/O board answers at once, so the V60 sends its first sound
commands before the 68000 has finished its init. The real UART holds one byte
and would lose the others; Virtua Fighter then stayed silent. The bytes for
the 68000 are kept in a queue.
Virtua Racing and Virtua Fighter play no sound in attract mode with their
default settings, as on the board.
## Save states
Besides the RAMs and registers, a save state keeps what MAME 0.78 does not
save by itself and what a game sets only once: the TGP FIFOs (a state can
fall between the words of a command, or before the V60 read the results),
the data ROM bank, the time left of the interval and UART timers, and the
renderer's view (viewport, light, light parameters: Virtua Fighter sends
them only when a stage starts, and without them a loaded state drew the
fighters black). Checked by loading in a new process: Virtua Fighter and
Virtua Racing's attract mode go on frame for frame as in a straight run
(analog controls: see Open questions).
## Other boards
- Link board (Virtua Racing, Virtua Formula, Wing War): not emulated; the
games see it with its CPU in reset and run stand-alone.
- R360 motion base (`wingwar360`): the game states it sends are answered as
the real base does, so a game starts. No motion.
- Polhemus tracker (`netmerc`): the board (a 386 with its own program) that
tracks the visor is not emulated. As in current MAME, the visor pose the
game reads at dual port RAM 0x80-0x8b (x, y, z, then three angles in
radians * 8192) is set once at reset, looking ahead. The gun on its mount
is not tracked: it uses the stick (analog channels 0 and 2), and moving
goes where the gun points.
- NetMerc gun mount calibration: the ends of both axes are kept in the
backup RAM (0x38 / 0x3c horizontal, 0x40 / 0x44 vertical). At boot the
game sets its factory calibration (0x46-0xc4, 0x21-0x69) only when one of
them is zero, so a new NetMerc backup RAM is 0-filled (the other games
get 1s, which Virtua Fighter needs): with 1s it kept them, divided by
zero, spun the gun, failed its checksum and stayed on one attract
screen. The stick covers the same range as the factory calibration.
- NetMerc sound: `mpr-18134` (the first sample ROM of the first MultiPCM)
is a bad dump, all 0xff, in the only set known (MAME has the same one).
That MultiPCM has no sample table, so the music it plays is silent; the
effects, on the second MultiPCM, play.
- NetMerc defaults (test menu, GAME ASSIGNMENTS): country Japan, attract
sound off, so attract mode is silent and starts with the Japan warning.
## Video
`model1_vidhrdw.c` is a C port of current MAME's `model1_v.cpp`. Two choices
keep the output the same on every CPU: float to int conversions follow x86
(out of range gives `INT_MIN`, other CPUs saturate), and the files of the TGP
and the renderer are compiled without fused multiply-add (GCC and clang fuse
`a*b+c` on PowerPC and ARM64). Big-endian PowerPC renders pixel for pixel as
x86.
Polygons with the moire flag (Virtua Fighter's shadows) are drawn as a
checkerboard, every other pixel, as in current MAME; a 720p capture of a
real Virtua Fighter board shows the same pattern.
Compared with captures of real boards: Virtua Fighter (the stages up to
Akira's: backgrounds, floors, colours, lighting, camera, shadows), Virtua
Racing (Bay Bridge: start grid, bridge, HUD), Star Wars Arcade (attract:
Star Destroyer, cockpit battle, hangar), Wing War and NetMerc.
## Open questions
- Virtua Fighter: the eight stages up to Akira's were compared with a
capture of a real board (backgrounds, floors, colours, camera); Dural's
stage and the bonus stage were not.
- After loading a state during play, an analog control (Virtua Racing's
accelerator) starts again from its rest position: the core's input
system does not save it. Digital inputs and attract mode go on as in a
straight run.
+517
View File
@@ -0,0 +1,517 @@
# Sega Model 2: choices that differ from the hardware
The Model 2 driver (`src/drivers/model2.c`) emulates the boards as the games
see them. In a few places the hardware is not available or not emulated, and
the driver does something simpler. Each of those choices is listed here, with
the reason and its consequences.
## Communication board (network link)
The communication board links cabinets for multi-player games over a network.
It is not emulated: there is no network.
For most games the board reads as **absent** (the CN register reads 0xff).
The games that look for it then run as single machines.
### Virtual-On: board present, link always stand-alone
Sets: `von`, `vonu`, `vonj`.
**Why.** Virtual-On does not start a game without the board, even on a
machine set to stand-alone. At boot (addresses from `von`):
1. `0x185d0` sets the defaults: role stand-alone, link mode 0.
2. `0x18920` reads the link ID from the backup RAM (byte `0x1d00028`:
0 slave, 1 master, other values stand-alone; the factory setting is 2).
3. `0xc6480` initialises the link. It reads the board's CN register first.
Without a board it prints "THERE IS NO COMMUNICATION BOARD!", sets the
link mode to 0xff and returns, without looking at the link ID.
With link mode 0xff the game never leaves the attract mode: after a coin the
screen stays black and silent (game mode 4, sub-state 0 waits on a status
word that stays 0xff).
With a board present, step 3 enables it (CN=1) and waits for the board's
firmware to report ready (ZFG=1, read as bit 7 of the FG register going to
0). With the link ID on stand-alone it then returns at once and the game never
uses the link. A board that is present but never ready stops the game at boot;
this is also what the current MAME device does without its network
simulation, and MAME lists these sets as not working.
**What the driver does.**
- The board reads as present and reports ready as soon as the game enables
it (`m2comm_ctrl_w`, CN=1 sets ZFG=1). Its shared RAM is plain RAM.
- The link ID always reads as stand-alone (`von_linkid_r`, installed over the
backup RAM dword at `0x1d00028`). Writes still go to the backup RAM.
**Consequences.**
- Master and slave are not available. The test menu always shows
stand-alone, whatever is chosen there.
- The game computes the backup RAM checksum by reading through the same
handler, so the checksum stays valid and the other settings are kept.
- An NVRAM from another emulator with the link set to master or slave fails
the checksum once: the game then restores its factory settings.
**How it was checked.** A valid NVRAM with the link ID on slave (checksum
recomputed with the game's own CRC, table at `0x2f20` in `von`) stops at boot
on "THIS IS SLAVE SITE" without the override. With the override, the same
NVRAM boots, plays a game, and keeps its other settings.
**Not added: `vonr` (Virtual-On Relay).** That version always sets its role
to relay (`0xf1cf0` writes 0) before the link is initialised, and then waits
for the network. It cannot run as a single machine.
### Daytona USA: factory link ID forced to single at start-up
Sets: `daytona`, `daytonase`, `daytona93`, `daytonas`.
**Why.** Daytona USA runs without the board, but its factory settings in the
program ROM set the link ID to master. On a new NVRAM (or after a factory
reset) the game uses those settings and keeps looking for the other cabinets
("NETWORK CHECKING"), so a game never starts.
**What the driver does.** When the game is loaded, `DRIVER_INIT( daytona )`
finds the factory settings table in the program ROM (it starts with
`SEGA@\x82`) and changes the link ID at offset 0x0b from 1 (master) to
0 (single). The board reads as absent.
| Set | Table | Factory link ID | Patched |
|---|---|---|---|
| `daytona` | `0x39d60` | 1 (master) | yes |
| `daytonase` | `0x3ab20` | 1 (master) | yes |
| `daytonas` | `0x3c570` | 1 (master) | yes |
| `daytona93` | `0x3c150` | 0 (single) | no, already single |
**Consequences.**
- Only the factory value changes. A link ID already saved in the NVRAM is
kept, and the setting can still be changed in the test menu. Set to master
or slave, the game waits for the network as on the real hardware; set it
back to single to play.
- Restoring the factory settings from the test menu gives single, not
master.
### Motor Raid
Sets: `motoraid`.
The game has link code ("Network Check"), but with the board absent it
starts and plays with its factory settings. Nothing is changed.
## Model 1 I/O board (original Model 2)
Sets: `daytona` and clones, `vcop`, `vcopa`.
The original Model 2 reads its inputs through a Model 1 I/O board: a Z80
with its own BIOS, behind a dual-port RAM at `0x1c00000`.
- With the BIOS (`model1io.zip` for Daytona USA, `model1io2.zip` for Virtua
Cop), the board runs its own firmware on an emulated Z80.
- Without it, the board's firmware is simulated: the driver writes the
inputs, the analog channels and the light guns where the games read them,
and handles the backup commands. Both BIOS files are optional ROMs.
## INDY 500 and Over Rev (Model 2B, `indy500` machine)
Sets: `indy500`, `indy500d`, `indy500to`, `overrevb`, `overrevba`.
- **Drive board (force feedback).** The games write their commands to it
through port E of the 315-5649 and never wait for an answer. It is not
emulated: the writes are ignored, as in MAME when no drive board program
is loaded.
- **Communication board program.** The Over Rev sets list the communication
board program (`epr-18643.7`) as in MAME. Its CPU is not run, so the ROM
is optional: the sets load with or without it.
- **Over Rev parent.** As in MAME, the parent `overrev` is the Model 2C
version (see the Model 2C sections), so `overrevb` and `overrevba` load
from `overrev.zip`. The I/O board BIOS entries (`model1io`, `model1io2`),
like the other BIOS sets of the core, are not in the game list: loading
their zip reports that there is no such game instead of starting a
machine without a program.
- **Inverted pedals.** Over Rev reads its pedals inverted (0xff released), as
`PORT_REVERSE` in MAME. The driver inverts those channels itself.
Super GT 24h (`sgt24h`) runs on the same machine. Its pedals are read
inverted too, and it uses the same driver init as Over Rev.
## Sound link (MIDI input of the SCSP)
On Model 2A and later the i960 sends its sound commands through a UART to the
MIDI input of the SCSP. The driver sends a byte only when the SCSP input
queue has room, so no command is lost; while the queue is full the UART
reports itself busy and the game waits.
The SCSP input queue holds 32 bytes, as in current MAME (the original MAME
0.78 code had 8). With 8 bytes Super GT 24h hung at the end of its boot: the
sound program does not read the queue for a while, and the game sends sound
commands from its vertical blank interrupt, so it waited there for several
frames. Its frame timer (same interrupt priority) expired meanwhile; the
i960 records such an interrupt in its interrupt table, which this game keeps
in ROM, so the interrupt was lost and the main loop waited for the timer
forever (black screen after "STAND ALONE"). With 32 bytes the commands fit
and the game plays.
**The MIDI interrupt.** The sound program reads one byte from the queue per
MIDI interrupt (level 3 on these boards). The interrupt is now dropped when
the program reads the byte, and raised again only while the queue still has
bytes, as in current MAME. Before, it could stay raised on an empty queue:
the sound program then took it again and read a stale byte as part of a
command. This corrupted the music commands of Dead or Alive (61 extra reads
in the attract mode) and Manx TT (189), whose music then played wrong or
stopped. The SCSP timers are now real timers, as in MAME, and each interrupt
source has its own level, which stays raised until the program acknowledges
it.
**How it was checked.** Each sound command the i960 sends is read once, with
no extra reads, in `doa`, `fvipers`, `hotd`, `manxtt`, `rchase2`, `srallyc`
and `vf2`. In Dead or Alive the sound commands and every slot register write
between 15 and 25 s of the attract mode are the same as in MAME 0.264.
## Rail Chase 2: mirrored sample ROMs
Sets: `rchase2`.
The sound board takes either four 16 Mbit sample ROMs (IC32, IC33, IC34,
IC35) or two 32 Mbit ones (IC32, IC34). Rail Chase 2 has two 16 Mbit ROMs in
the 32 Mbit positions IC32 and IC34. A 16 Mbit ROM there ignores the top
address line, so it shows up twice: the region at 0x200000 mirrors IC32 and
the one at 0x600000 mirrors IC34.
The sound program streams some effects through the 68000 into ring buffers
in sound RAM, reading them from those mirrors (the title screen animation
reads its stream from 0xa1e97c, inside the mirror of IC32). MAME loads the
ROMs at 0x000000 and 0x400000 and leaves the mirrors empty, so those effects
play silence: the title animation is silent and some in-game effects are
missing, as reported for MAME (mametesters 09393).
The ROM definition loads each ROM a second time into its mirror (`ROM_RELOAD`), as the same fix proposed to MAME.
**How it was checked.** Current MAME (built from source, October 2026), with
no input, plays nothing during the title animation (22-30 s, 56-62 s and
90-96 s of the attract mode), as this core did before the change. With the
same mirroring added to MAME's `init_rchase2`, MAME plays the title
animation sound at the same points as this core. The billboard ROM
(`segabill`), not dumped here, was an empty placeholder in that MAME test; it
drives the score display only. With it the title
animation has its sound and the in-game sound is about a third louder (the
effects that were missing). The video is unchanged. The other Model 2 sets
fill every ROM position they use, or (`dynabb`) use the four-ROM layout, where
an empty socket is not a mirror.
## Sound: the SCSP effect DSP
Sets: every SCSP game that loads a DSP program (Dead or Alive among them).
The SCSP has a small DSP for effects (reverb, echo). The slots send their
output to it (ISEL, IMXL), it runs its microprogram once per sample with its
delay lines in the sound RAM (RBP, RBL), and its 16 outputs are mixed with
the EFSDL and EFPAN of slots 0-15. The SCSP of this core did not emulate it,
so those effects were missing, and the sounds a game sends only to the DSP
were silent. The DSP is now the one of current MAME (`src/sound/scspdsp.c`),
compared with MAME's on the Dead or Alive program and on random programs:
same outputs, registers and delay RAM, sample by sample.
**Dead or Alive and the MADRS registers.** The DSP reads its delay line
addresses from the MADRS registers (`0x780-0x7bf`). MAME also writes the
range `0x7c0-0x7ff` to MADRS, as a mirror. Dead or Alive loads MADRS and then
clears `0x7c0-0x7ff`, so in MAME every delay line address becomes 0: the
reverb feeds back into one word, its output drifts to a DC level and
saturates, and the sound breaks up and then goes silent (listed in MAME's
known issues for `doa`). The mirror is not from the hardware: it replaced an
out-of-bounds write in 2014, and Mednafen (checked on Saturn hardware) maps
MADRS at `0x780-0x7bf` only. Here `0x7c0-0x7ff` is ignored and reads as 0.
**Master volume.** The SCSP master volume (MVOL) now scales the output once
the game has written it, as in MAME. Dead or Alive keeps it at 0 for the
first seconds while its DSP starts on an uninitialised delay RAM; without
MVOL that start was audible as a burst of noise. The games that use 15 (the
maximum) sound exactly as before.
**How it was checked.** MAME with the mirror removed plays the Dead or Alive
attract mode for over 11 minutes without the DC drift (it saturated within
the first minute before). In this core the games that do not start the DSP
produce exactly the same audio as before.
## Video: tile layers and polygons
The tile layers (System 24 tilemaps A and B) are mixed among themselves
first, A over B whatever their priority bits; the priority bit of the
pixel that wins then puts it behind or in front of the polygons. MAME draws
each priority on its own (the low tiles of A and B, the polygons, the high
tiles of A and B), so a high tile of B covers a low tile of A: on the
Virtua Cop 2 stage select the city map (tilemap B, priority set) hid
"SHOOT TO SELECT" (tilemap A), as listed in MAME's known issues for
`vcop2`. The other Model 2 games checked look the same as before.
## Video: black polygon pixels
The polygons are drawn into their own buffer, then laid over the tile
layers. MAME's buffer holds `rgb_t` pixels, whose alpha byte makes a drawn
black pixel (0xff000000) different from an empty one (0). This core stored
plain RGB and took every black pixel as empty, so wherever a polygon was
pure black the layer behind showed through: blue car shadows and missing
dust in Sega Rally, blue tyres and shadows in INDY 500 and Super GT, the
sky behind black clothes in Dead or Alive, the attract backgrounds of Motor
Raid. Drawn pixels now carry the same opaque marker in the top byte. All the
Model 2 games were compared before and after; the changed pixels are the
black ones, and they now match MAME.
## Sega Rally Championship (Model 2A)
Sets: `srallyc`, `srallycb`, `srallycc`, `srallycdx`, `srallycdxa`.
- **Gear lever.** The H-pattern lever is read on port C bits 4-6. As for
Daytona USA it is built from two buttons, shift up and shift down.
- **Drive board.** The force feedback board is written to through port E and
never answers; it is not emulated. Its program (`epr-17891`) and the
communication board program (`epr-16726`) are not listed.
- **Start grid.** MAME lists the initial placement of a few opponent cars as
slightly wrong, depending on the i960 clock. Here, with the i960 at half
and at double its clock, only one of the 8 start grid objects moves, by
about 0.3 units (it is still settling when the race starts). Compared with
a video of a real Model 2A-CRX, aligned on the race clock (chase view,
full throttle): same speed (220 km/h at 0'04"0), same course, and the
first opponent appears at the end of the village at 0'05"0 in both, at the
same distance up to 0'06"0. Nothing is changed.
## Manx TT Superbike (Model 2A)
Sets: `manxtt` (DX/Twin, Revision D), `manxttc` (DX/Twin, Revision C),
`manxttdx` (DX).
- **Cabinet type.** The MAME sets include an EEPROM image that sets the
cabinet type: DX for `manxtt`, Twin for `manxttc`. A new NVRAM starts from
it (`REGION_PROMS`, 16-bit little-endian as in MAME). The type can still be
changed in the test menu.
- **Motion slider (DX).** The DX bike moves; its drive board takes commands
on port E of the 315-5649 and answers on port D. At boot the game shows
"ACTIVE MOTION SLIDER / NOW CHECKING SYSTEM" (code at `0x5f580` in
`manxtt`): after command `0x3d` it waits up to 846 frames for status
`0xce`, sends the bike center value, then waits for `0xcd`. Without an
answer it shows "Error! ... Not Respond" and never starts; MAME stops
there (its known issue "no escape from active motion slider tutorial").
The board is simulated with those two answers: `0xce` while the command is
`0x3d`, `0xcd` otherwise. The board's error codes (`0xb0`-`0xb7`: first
setting, encoder, overcurrent, overheat, bank volume, ROM, RAM, centering)
are never sent. The bike does not move, of course.
- **Model 1 sound board (DX).** The DX cabinet has a Model 1 sound board
(68000, YM3438, two MultiPCM) next to the SCSP, for extra sounds. It runs as
a fourth CPU (`REGION_CPU4`, samples in `REGION_SOUND2`/`REGION_SOUND3`)
and gets the same sound commands from the i960 UART, as in MAME. Its replies
are not passed back: the i960 reads the SCSP's.
- **Communication board.** Its program (`epr-18643a`) is not listed; the
board is not emulated and the game runs as a single machine.
## Sky Target (Model 2A)
Sets: `skytargt`.
The stick is on analog channels 0 (Y) and 2 (X, reversed), as in MAME.
Machine gun, missile and view change are buttons 1-3.
## Air Walkers (Model 2A)
Sets: `airwlkrs`.
Up to four players on two input ports: port F bit 7 selects players 1-2 or
3-4 on ports C and D, and the matching start buttons on IN0 bits 4-5, as in
MAME.
## Hanguk Pro Yagu 98 (Model 2A)
Sets: `hpyagu98`.
The game stops with "Error #1" unless the NVRAM holds what its boot code
checks: EEPROM words 4-5, the string "98KOREA PRO B.B." at the start of the
backup RAM, a magic dword at `0x398` (`v * 3 + 0x3e82 == 0xf0c891a2`), and the
settings block at `0x10` with its CRC (a copy at `0x1d4` restores it when
only one is valid). MAME lists two hand-made images, EEPROM and backup RAM,
with the settings of Dynamite Baseball 97. A new NVRAM starts from them, as in
MAME (`REGION_PROMS` and `REGION_GFX1`); older sets without these two files
stop on "Error #1".
## Desert Tank (original Model 2)
Sets: `desert`.
Model 1 I/O board as Daytona USA (its BIOS runs when `model1io.zip` is
present). Steering, accelerator and brake on the I/O board analog inputs,
the shift lever as a toggle, as in MAME.
## Model 2C: the TGPx4 (MB86235)
The Model 2C boards replace the TGP with a Fujitsu MB86235 "TGPx4". Its
interpreter comes from current MAME (`src/cpu/mb86235`, in C89), with the
program memory, the external bus (buffer RAM at `0x400000`, the copro data
ROM at `0x800000`) and the two FIFOs as driver callbacks. As in MAME, the
CPU waits in halt until the i960 has sent its program, and a read from the
empty input FIFO repeats the instruction once the i960 pushes a value. Two
places differ from MAME, where its code is plainly a slip:
- **FEA/FES** (exponent add/subtract) keep the sign and the mantissa and
change only the exponent field; MAME keeps only the exponent field.
- **EBL** (the low 14 bits of the external base register) is written as the
low bits; MAME shifts the value up as for EBU.
None of the games checked showed a difference from either change.
The 2C games run faster than real time here, where MAME runs them at about
70%.
## Video: polygon clipping
A polygon is clipped against four planes, and a convex one gains at most one
vertex for each, so MAME's buffers hold 8. A bad polygon (self-crossing, or
with NaN coordinates) can double its vertices at each plane: Top Skater's
models drawn with the standard object format overflowed the buffers and
crashed the core. The buffers now hold 64 vertices and only polygons that
still fit in 8 are kept.
## Top Skater (Model 2C)
Sets: `topskatr`, `topskatru`, `topskatruo`, `topskatrj`.
The game uploads its own geometrizer program (MAME's notes: "a slightly
different geometry code"), and MAME shows no 3D. Its object data command
(`0x11`, the second bank of command numbers) reads a compact polygon list:
the attribute word, then only the points, three words for a triangle and
six for a quad. The standard format (no normals) also has three unused
normal words and, for triangles, an unused point. Read with the standard
format, every polygon after the first was garbage. The driver reads the
compact format for command `0x11` in this game only; the skaters, the
board, the ramps and the crowd are all drawn. The command word also carries the
center select in bits 6-7, as the rasterizer command does: the speed meter
is drawn around the window's second vanishing point, in the bottom left
corner. Compared with a video of the arcade game: the course, the HUD and
the speed meter are in the same places.
The program's command `0x1b` loads a second matrix and `0x1c` copies the
first matrix's translation into it; a vertex whose x has the lowest bit set
goes through the second matrix (the skinned joints of the skaters). MAME
pull request #16444 (jkind73, open) found the compact format and the second
matrix too.
The board has two foot sensors (front and tail), on while a foot stands on
it. MAME reads them active low, so with no input both feet are off the
board: the skater always jumps, floats 16 units above the ground with the
camera close behind, and its shadow (which the game puts on the ground
under the light) is far below, off screen. Here they are on at rest and a
button lifts a foot. Compared with a video of the arcade game at the same
race time, the skater now rides crouched, the camera is at the same
distance and the shadow is under the board. The attract demos, played by
the game, matched the video before already (shadows included).
The analog inputs are curving (channel 0, stick X) and slide (channel 1);
MAME puts both on the same axis, here slide is on stick Y so a pad can
reach both.
The music is on the DSB2 MPEG board (see the music board section).
## Sega Ski Super G (Model 2C)
Sets: `skisuprg`.
The drive board answers on port D to the commands on port E. At boot the
game shows "CHECK DRIVE BOARD" (code at `0x88b10`): it clears port E and
waits for `0xce` (ready), sends the inclining center and waits for `0xff`
(taken), within 479 frames; without an answer it stops on "DRIVE BOARD
TROUBLE CODE: FF", as in MAME. In game, `0xb0`-`0xb7` are board errors
(init, encoder, overload, overheat, bank volume, ROM...). The board is
simulated: `0xce` while port E is 0, `0xff` otherwise. The game then runs
through the World Series and the races.
Swing is on analog channel 0 (stick Y), inclining on channel 1 (stick X),
the foot sensors on port D are not read (port D is the drive board).
## Sega Touring Car Championship and Top Skater: music board (DSB)
Sets: `stcc`, `stccb`, `stcca`, `stcco` (DSB, Z80) and the Top Skater sets
(DSB2, 68000).
Their music is MPEG audio (layer II, 32 kHz stereo) on a Digital Sound
Board, from current MAME (`dsbz80.cpp`, `dsb2.cpp` and the decoder
`mpeg_audio.cpp`, in C89: `src/sndhrdw/segadsb.c`, `src/sound/mpeg_audio.c`).
The board's CPU gets the game's sound commands on its i8251, from the same
line as the SCSP (each byte the i960 sends goes to both), and drives the
decoder: start and end addresses, play, loop, stop, volume and stereo mode
for the DSB; a command FIFO and a 1 kHz timer interrupt for the DSB2. The
decoded audio is its own stream, mixed 9 dB under the SCSP's full level
(MAME mixes both at full level). The level was measured on two recordings
of Top Skater cabinets: with the music and the sound effects of the core as
separate tracks of the same run, aligned on the attract mode, the
recordings came out with the music 9 dB lower against the effects (within
1 dB, both recordings); at full level the music also clipped. The decoded
music itself matches the recordings (spectral correlation 0.9-0.97). The
recordings play the music about 0.45% faster than the core's 32 kHz
(emulated time); not changed, it may be the recordings. Touring Car's DSB
uses the same level (no recording checked).
The decoder never reads past the MPEG ROM (MAME guards this on the DSB2
only). The drive board and the communication board programs are not
listed.
## The House of the Dead (Model 2C)
Sets: `hotd`, `hotdo`.
The guns work as in Virtua Cop 2 (the 315-5649 serial channel), with the
ranges of MAME's `hotd` ports. MAME's prototype `hotdp` is not listed: one
of its texture ROMs was never dumped.
## Other Model 2C sets
`waverunr`, `bel`, `segawski`, `dynamcopc` and `overrev` (now the Model 2C
parent of the Model 2B sets) run with the inputs of MAME.
## Motor Raid - Twin/DX (Model 2A)
Sets: `motoraiddx`.
The DX cabinet has a moving bike, run by a drive board on the 315-5649
ports: the game writes commands to port E (inverted) and reads the board's
status on port D. The drive board's program is not dumped and MAME lists the
set as not working: the game stops at "DRIVEBOARD NOT RESPONSE ERROR".
The board is simulated, as for Manx TT DX. From the cabinet check (code
copied to RAM at `0x2158d0`, ROM `0xc58d0`):
- port D reads `0xcd` when the board is ready; the check then skips the
initialisation and centring steps (which wait for `0xcf` and `0xce`);
- the wire test sends commands `0xe0`-`0xef` and expects bit `n & 7`
cleared (table at ROM `0xc5720`); the simulation answers the same.
The bike does not move, the game runs as on a working cabinet.
## Rail Chase 2 (`rchase2a`)
A second program for Rail Chase 2 that reads the guns the other way round
(maybe a factory conversion). The guns are centred at `0x80` over the full
range, as MAME's `rchase2a` ports.
## Daytona USA hacks
Sets: `daytonat`, `daytonata` (Turbo hack), `daytonam` (To The MAXX),
`daytonagtx` (GTX 2004 Edition). Hacks by Kyle Hodgetts, listed by MAME as
not working; here they play.
- **To The MAXX**: the kit has a PIC 16F84 in socket IC15. It answers at
`0x240000`, where the third program ROM (`maxx.14`) is seen. As MAME:
16-bit reads of the first 32 bytes step a 4-bit counter and return the
PIC's answer.
- **GTX 2004**: a banked ROM over the data ROMs at `0x2c00000`. Reads of
some bytes switch the bank, as MAME (`0xff00c` and `0xf0003` bank 0,
`0xff000` bank 1, `0xffffc` the empty bank 2).
## Not added
- **Royal Ascot II** (`rascot2`): a horse racing terminal made for the
SegaNet network. It waits for the network ("SegaNet Wait Status" in MAME)
and never starts a race as a single machine.
- **Power Sled** (`powsled`, `powsledr`, `powsledm`): a network of
cabinets run by a Main unit, whose program was never dumped (MAME's
`powsledm` is a hack of the Relay program). Every version waits on the
network ("NETWORK: NG") in MAME, and would need the whole network to be
simulated.
+3
View File
@@ -3,6 +3,9 @@ LOCAL_PATH := $(call my-dir)
ROOT_DIR := $(LOCAL_PATH)/..
CORE_DIR := $(ROOT_DIR)/src
# threads: in bionic's C library
HAVE_THREADS := 1
include $(ROOT_DIR)/Makefile.common
COREFLAGS := $(DEFS) $(COREDEFINES) $(CPUDEFS) $(SOUNDDEFS) $(ASMDEFS) $(DBGDEFS) -ffast-math -funroll-loops -DANDROID -DHAVE_ZLIB $(INCFLAGS)
Binary file not shown.
+219 -19
View File
@@ -34,10 +34,36 @@
3stooges=Shooter / Field
3wonders=MultiGame / Compilation
3wonderu=MultiGame / Compilation
ddpdfk=Shooter / Flying Vertical
ddpdfk10=Shooter / Flying Vertical
deathsml=Shooter / Flying Horizontal
dfkbl=Shooter / Flying Vertical
dsmbl=Shooter / Flying Horizontal
espgal2=Shooter / Flying Vertical
espgal2a=Shooter / Flying Vertical
espgal2b=Shooter / Flying Vertical
futari10=Shooter / Flying Vertical
futari15=Shooter / Flying Vertical
futari15a=Shooter / Flying Vertical
futaribl=Shooter / Flying Vertical
futariblj=Shooter / Flying Vertical
ibara=Shooter / Flying Vertical
ibarablk=Shooter / Flying Vertical
ibarablka=Shooter / Flying Vertical
ibarao=Shooter / Flying Vertical
mmpork=Shooter / Flying Vertical
mushisam=Shooter / Flying Vertical
mushisama=Shooter / Flying Vertical
mushisamb=Shooter / Flying Vertical
mushitam=Puzzle / Drop
mushitama=Puzzle / Drop
pinkswts=Shooter / Flying Vertical
pinkswtsa=Shooter / Flying Vertical
pinkswtsb=Shooter / Flying Vertical
pinkswtssc=Shooter / Flying Vertical
pinkswtsx=Shooter / Flying Vertical
wonder3=MultiGame / Compilation
40love=Sports / Tennis
47pie2=Tabletop / Mahjong * Mature *
47pie2o=Tabletop / Mahjong * Mature *
4dwarrio=Shooter / Flying Horizontal
4enraya=Puzzle / Match
4in1=MultiGame / Compilation
@@ -100,6 +126,7 @@ ajax=Shooter / Flying Vertical
ajaxj=Shooter / Flying Vertical
typhoon=Shooter / Flying Vertical
akiss=Tabletop / Mahjong * Mature *
akissa=Tabletop / Mahjong * Mature *
aladmdb=Platform / Fighter Scrolling
alexkidd=Platform / Run, Jump & Scrolling
alexkidd1=Platform / Run, Jump & Scrolling
@@ -232,7 +259,12 @@ asteroib=Shooter / Field
astinvad=Shooter / Gallery
kamikaze=Shooter / Gallery
astorm=Platform / Shooter Scrolling
astorm2p=Platform / Shooter Scrolling
astorm3=Platform / Shooter Scrolling
astorm3d=Platform / Shooter Scrolling
astormj=Platform / Shooter Scrolling
astormjd=Platform / Shooter Scrolling
astormu=Platform / Shooter Scrolling
astormud=Platform / Shooter Scrolling
astormbl=Platform / Shooter Scrolling
astrass=Fighter / Versus
astrob=Shooter / Gallery
@@ -247,6 +279,9 @@ lordofk=Platform / Fighter Scrolling
asuka=Shooter / Flying Vertical
asurabld=Fighter / Versus
asurabus=Fighter / Versus
asurabusj=Fighter / Versus
asurabusja=Fighter / Versus
asurabusjr=Fighter / Versus
asylum=Shooter / Walking
atarifb=Sports / Football
atarifb1=Sports / Football
@@ -330,7 +365,10 @@ batrider=Shooter / Flying Vertical
batridra=Shooter / Flying Vertical
batridrk=Shooter / Flying Vertical
batsugun=Shooter / Flying Vertical
batugnsp=Shooter / Flying Vertical
batsuguna=Shooter / Flying Vertical
batsugunc=Shooter / Flying Vertical
batsugunb=Shooter / Flying Vertical
batsugunsp=Shooter / Flying Vertical
battlane=Shooter / Driving Vertical
battlan2=Shooter / Driving Vertical
battlan3=Shooter / Driving Vertical
@@ -454,6 +492,8 @@ bloods21=Fighter / Versus
bloods22=Fighter / Versus
bloodwar=Fighter / Versus
bloxeed=Puzzle / Drop
bloxeeda=Puzzle / Drop
bloxeedd=Puzzle / Drop
bloxeedc=Puzzle / Drop
blstroid=Shooter / Field
blsthead=Shooter / Field
@@ -577,6 +617,9 @@ buckrog=Shooter / Flying (chase view)
buckrogn=Shooter / Flying (chase view)
bucky=Shooter / Walking
buckyua=Shooter / Walking
buggyboy=Driving / Race (chase view)
buggyboyb=Driving / Race (chase view)
buggyboyjr=Driving / Race (chase view)
buggychl=Driving / Race (chase view)
buggycht=Driving / Race (chase view)
bulletd=Shooter / Walking
@@ -736,9 +779,9 @@ chopper=Shooter / Flying Vertical
choppera=Shooter / Flying Vertical
chopperb=Shooter / Flying Vertical
legofair=Shooter / Flying Vertical
chplft=Shooter / Flying Horizontal
chplftb=Shooter / Flying Horizontal
chplftbl=Shooter / Flying Horizontal
choplift=Shooter / Flying Horizontal
chopliftu=Shooter / Flying Horizontal
chopliftbl=Shooter / Flying Horizontal
chqflag=Driving / Race
chqflagj=Driving / Race
chukatai=Shooter / Flying Horizontal
@@ -780,6 +823,9 @@ clowns=Ball & Paddle / Jump and Touch
clowns1=Ball & Paddle / Jump and Touch
clshroad=Driving / Race Bike
cltchitr=Sports / Baseball
cltchitrd=Sports / Baseball
cltchitrj=Sports / Baseball
cltchitrjd=Sports / Baseball
club90s=Tabletop / Mahjong * Mature *
club90sa=Tabletop / Mahjong * Mature *
cluckypo=Casino / Cards
@@ -853,10 +899,15 @@ cosmogng=Shooter / Gallery
cosmognj=Shooter / Gallery
cosmos=Shooter / Gallery
cotton=Shooter / Flying Horizontal
cottona=Shooter / Flying Horizontal
cotton2=Shooter / Flying Horizontal
cottonbm=Shooter / Flying Horizontal
cottond=Shooter / Flying Horizontal
cottonj=Shooter / Flying Horizontal
cottonja=Shooter / Flying Horizontal
cottonjad=Shooter / Flying Horizontal
cottonjd=Shooter / Flying Horizontal
cottonu=Shooter / Flying Horizontal
cottonud=Shooter / Flying Horizontal
countrun=Maze / Driving
countrunb3=Maze / Driving
countrb2=Maze / Driving
@@ -985,6 +1036,8 @@ daitorid=Puzzle / Match
daiyogen=Tabletop / Mahjong * Mature *
dakkochn=Tabletop / Mahjong * Mature *
danceyes=Puzzle / Outline * Mature *
danceyesu=Puzzle / Outline * Mature *
danceyesj=Puzzle / Outline * Mature *
danchih=Tabletop / Hanafuda * Mature *
dangar=Shooter / Flying Vertical
dangar2=Shooter / Flying Vertical
@@ -1030,6 +1083,21 @@ dcon=Shooter / Command
dday=Shooter / Gallery
ddayc=Shooter / Gallery
ddcrew=Fighter / 2.5D
ddcrew1=Fighter / 2.5D
ddcrew1d=Fighter / 2.5D
ddcrew2=Fighter / 2.5D
ddcrew2d=Fighter / 2.5D
ddcrewd=Fighter / 2.5D
ddcrewj=Fighter / 2.5D
ddcrewj2=Fighter / 2.5D
ddcrewj2d=Fighter / 2.5D
ddcrewjd=Fighter / 2.5D
ddcrewu=Fighter / 2.5D
ddcrewud=Fighter / 2.5D
desertbr=Shooter / Walking
desertbrd=Shooter / Walking
desertbrj=Shooter / Walking
desertbrjd=Shooter / Walking
ddenlovr=Tabletop / Othello - Reversi * Mature *
ddonpach=Shooter / Flying Vertical
ddonpacha=Shooter / Flying Vertical
@@ -1190,6 +1258,9 @@ dogfgtj=Shooter / Flying
dogfight=Shooter / Flying
dogpatch=Shooter / Versus
dogyuun=Shooter / Flying Vertical
dogyuuna=Shooter / Flying Vertical
dogyuunb=Shooter / Flying Vertical
dogyuunt=Shooter / Flying Vertical
dogyuunto=Shooter / Flying Vertical
dokaben=Sports / Cards
dokidoki=Platform / Run Jump
@@ -1277,6 +1348,7 @@ dungeonm=Maze / Fighter
dungenmu=Maze / Fighter
lightbr=Maze / Fighter
dunkmnia=Sports / Basketball
dunkmniajc=Sports / Basketball
dunkshot=Sports / Basketball
dunkshota=Sports / Basketball
dunkshoto=Sports / Basketball
@@ -1312,6 +1384,8 @@ eggor=Maze / Shooter Small
eggventr=Shooter / Gun
eggvntdx=Shooter / Gun
ehrgeiz=Fighter / Versus
ehrgeizua=Fighter / Versus
ehrgeizja=Fighter / Versus
eightfrc=Shooter / Flying Vertical
eightman=Platform / Fighter Scrolling
einnings=Sports / Baseball
@@ -1424,6 +1498,7 @@ fghthista=Fighter / Versus
fghthistj=Fighter / Versus
fghthistu=Fighter / Versus
fgtlayer=Fighter / Versus
fgtlayerja=Fighter / Versus
fhawk=Shooter / Flying Vertical
fhawkj=Shooter / Flying Vertical
fhboxers=Sports / Boxing
@@ -1466,7 +1541,20 @@ countryc=Sports / Golf
fitegol2=Sports / Golf
fitfight=Fighter / Versus
fixeight=Shooter / Walking
fixeighb=Shooter / Walking
fixeightk=Shooter / Walking
fixeighth=Shooter / Walking
fixeighttw=Shooter / Walking
fixeighta=Shooter / Walking
fixeightu=Shooter / Walking
fixeightj=Shooter / Walking
fixeightt=Shooter / Walking
fixeightkt=Shooter / Walking
fixeightht=Shooter / Walking
fixeighttwt=Shooter / Walking
fixeightat=Shooter / Walking
fixeightut=Shooter / Walking
fixeightjt=Shooter / Walking
fixeightbl=Shooter / Walking
flagrall=Maze / Driving
flashgal=Fighter / 2D
flicky=Platform / Run Jump
@@ -1887,7 +1975,9 @@ hasamu=Puzzle / Match
hatena=Quiz / Questions in Japanese
hatris=Puzzle / Drop
hattrick=Sports / Hockey
hayaosi1=Quiz / Questions in Japanese
hayaosi2=Quiz / Questions in Japanese
hayaosi3=Quiz / Questions in Japanese
hayaosi3a=Quiz / Questions in Japanese
hbarrel=Shooter / Walking
hbarrelw=Shooter / Walking
hcastle=Platform / Fighter Scrolling
@@ -2169,6 +2259,7 @@ gblchmp=Fighter / Versus
kaiserkj=Fighter / Versus
kaitei=Shooter / Misc.
kaitein=Shooter / Misc.
kaiunqz=Quiz / Questions in Japanese
kakumei=Tabletop / Mahjong * Mature *
kakumei2=Tabletop / Mahjong * Mature *
kamenrid=Driving / Motorbike
@@ -2187,6 +2278,8 @@ karnovj=Platform / Shooter Scrolling
karnovr=Fighter / Versus
kazan=Platform / Fighter Scrolling
kbash=Fighter / Versus Co-op
kbashk=Fighter / Versus Co-op
kbashp=Fighter / Versus Co-op
kbash2=Fighter / Versus Co-op
kchamp=Fighter / Versus
karatedo=Fighter / Versus
@@ -2221,9 +2314,16 @@ ringkin2=Sports / Boxing
ringkin3=Sports / Boxing
ringking=Sports / Boxing
kinst=Fighter / Versus
kinst13=Fighter / Versus
kinst14=Fighter / Versus
kinst2=Fighter / Versus
kinst210=Fighter / Versus
kinst211=Fighter / Versus
kinst213=Fighter / Versus
kinstp=Fighter / Versus
kirameki=Quiz / Questions in Japanese
kirarast=Tabletop / Mahjong * Mature *
kirarasta=Tabletop / Mahjong * Mature *
kittenk=Maze / Blocks
nyanpani=Maze / Blocks
kiwame=Tabletop / Mahjong
@@ -2379,6 +2479,10 @@ lethalth=Shooter / Flying Vertical
thndblst=Shooter / Flying Vertical
levers=Platform / Run Jump
lghost=Shooter / Gun
lghostd=Shooter / Gun
lghostj=Shooter / Gun
lghostu=Shooter / Gun
lghostud=Shooter / Gun
lgtnfght=Shooter / Flying Vertical
trigon=Shooter / Flying Vertical
liberate=Shooter / Flying
@@ -2508,6 +2612,7 @@ marineb=Shooter / Flying
marinedt=Maze / Escape
mariner=Shooter / Misc. Horizontal
800fath=Shooter / Misc. Horizontal
800fatha=Shooter / Misc. Horizontal
mario=Platform / Run Jump
marioe=Platform / Run Jump
mariof=Platform / Run Jump
@@ -2751,11 +2856,12 @@ mouserc=Platform / Run Jump
mp_bio=Shooter / Flying Horizontal
mp_col3=Puzzle / Drop
mp_gaxe2=Fighter / 2.5D
mp_gaxe2a=Fighter / 2.5D
mp_shnb3=Platform / Shooter Scrolling
mp_soni2=Platform / Run, Jump & Scrolling
mp_sonic=Platform / Run, Jump & Scrolling
mp_sor2=Fighter / 2.5D
mp_twc=Sports / Soccer
mp_twcup=Sports / Soccer
mpang=Shooter / 3rd Person
mpanga=Shooter / 3rd Person
mpangj=Shooter / 3rd Person
@@ -2773,6 +2879,7 @@ mrdu=Maze / Digging
mrlo=Maze / Digging
yankeedo=Maze / Digging
mrdrillr=Puzzle / Misc.
mrdrillrja2=Puzzle / Misc.
mrdrilr2=Puzzle / Misc.
mrflea=Platform / Run Jump
mrgoemon=Platform / Fighter Scrolling
@@ -3104,7 +3211,10 @@ ozon1=Shooter / Gallery
p47=Shooter / Flying Horizontal
p47j=Shooter / Flying Horizontal
p47aces=Shooter / Flying Horizontal
p47acesa=Shooter / Flying Horizontal
pacapp=Music Game / Dance
pacapp2=Music Game / Dance
pacappsp=Music Game / Dance
pachiten=Tabletop / Mahjong * Mature *
packbang=Ball & Paddle / Breakout
pacland=Platform / Run, Jump & Scrolling
@@ -3318,6 +3428,7 @@ plusalph=Shooter / Flying Vertical
plygonet=Shooter / Driving 1st Person
pnickj=Puzzle / Drop
pnyaa=Puzzle / Drop
pocketrc=Driving / Race (chase view)
poitto=Puzzle / Drop
polaris=Shooter / Gallery
polarisa=Shooter / Gallery
@@ -3404,6 +3515,11 @@ psychos=Platform / Fighter Scrolling
psychosj=Platform / Fighter Scrolling
psyforce=Fighter / Versus
ptblank=Shooter / Gun
ptblank2a=Shooter / Gun
ptblank2b=Shooter / Gun
ptblank2c=Shooter / Gun
ptblank2ua=Shooter / Gun
gunbarla=Shooter / Gun
gunbulet=Shooter / Gun
pturn=Sports / Skiing
pubball=Sports / Baseball
@@ -3570,6 +3686,51 @@ raidena=Shooter / Flying Vertical
raidenk=Shooter / Flying Vertical
raident=Shooter / Flying Vertical
raiden2=Shooter / Flying Vertical
raiden2g=Shooter / Flying Vertical
raiden2gb=Shooter / Flying Vertical
raiden2hk=Shooter / Flying Vertical
raiden2j=Shooter / Flying Vertical
raiden2sw=Shooter / Flying Vertical
raiden2u=Shooter / Flying Vertical
raiden2f=Shooter / Flying Vertical
raiden2nl=Shooter / Flying Vertical
raiden2es=Shooter / Flying Vertical
raiden2i=Shooter / Flying Vertical
raiden2au=Shooter / Flying Vertical
raiden2e=Shooter / Flying Vertical
raiden2eub=Shooter / Flying Vertical
raiden2eua=Shooter / Flying Vertical
raiden2eg=Shooter / Flying Vertical
raiden2eup=Shooter / Flying Vertical
raiden2ea=Shooter / Flying Vertical
raiden2eu=Shooter / Flying Vertical
raiden2k=Shooter / Flying Vertical
raiden2dx=Shooter / Flying Vertical
raidendx=Shooter / Flying Vertical
raidendxg=Shooter / Flying Vertical
raidendxpt=Shooter / Flying Vertical
raidendxa1=Shooter / Flying Vertical
raidendxa2=Shooter / Flying Vertical
raidendxk=Shooter / Flying Vertical
raidendxu=Shooter / Flying Vertical
raidendxnl=Shooter / Flying Vertical
raidendxj=Shooter / Flying Vertical
raidendxja=Shooter / Flying Vertical
raidendxch=Shooter / Flying Vertical
zeroteam=Fighter / 2.5D
zeroteama=Fighter / 2.5D
zeroteamb=Fighter / 2.5D
zeroteamc=Fighter / 2.5D
zeroteamd=Fighter / 2.5D
zeroteame=Fighter / 2.5D
zeroteams=Fighter / 2.5D
zeroteamsr=Fighter / 2.5D
r2dx_v33=Shooter / Flying Vertical
r2dx_v33_r2=Shooter / Flying Vertical
nzeroteam=Fighter / 2.5D
nzeroteama=Fighter / 2.5D
nzeroteamb=Fighter / 2.5D
zerotm2k=Fighter / 2.5D
raiders5=Maze / Shooter Large
raidrs5t=Maze / Shooter Large
raimais=Maze / Collect
@@ -4034,9 +4195,9 @@ shanhigw=Puzzle / Match
sharkatt=Shooter / Underwater
sharrier=Shooter / Flying (chase view)
shdancer=Platform / Fighter Scrolling
shdancer1=Platform / Fighter Scrolling
shdancerj=Platform / Fighter Scrolling
shdancbl=Platform / Fighter Scrolling
shdancrb=Platform / Fighter Scrolling
shdancrj=Platform / Fighter Scrolling
sheriff=Shooter / Field
bandido=Shooter / Field
shienryu=Shooter / Flying Vertical
@@ -4202,9 +4363,18 @@ sonsonj=Platform / Shooter Scrolling
sos=Shooter / Flying Vertical * Mature *
sotsugyo=Multiplay / Mini-Games
soulclbr=Fighter / Versus
soulclbrab=Fighter / Versus
soulclbrac=Fighter / Versus
soulclbrub=Fighter / Versus
soulclbruc=Fighter / Versus
soulclbrja2=Fighter / Versus
soulclbrjb=Fighter / Versus
soulclbrjc=Fighter / Versus
souledge=Fighter / Versus
souledga=Fighter / Versus
souledgb=Fighter / Versus
souledgeuc=Fighter / Versus
souledgea=Fighter / Versus
souledgeua=Fighter / Versus
souledgeja=Fighter / Versus
spacbeam=Shooter / Gallery
spacduel=Shooter / Field
spacecr=Shooter / Gallery
@@ -4422,6 +4592,7 @@ starlstr=Shooter / Flying 1st Person
starshp1=Shooter / Flying 1st Person
starshpp=Shooter / Flying 1st Person
starswep=Puzzle / Misc.
starswepj=Puzzle / Misc.
startrek=Shooter / Flying 1st Person
starwars=Shooter / Flying 1st Person
starwar1=Shooter / Flying 1st Person
@@ -4482,6 +4653,8 @@ stunrune=Shooter / Driving (chase view)
stunrunj=Shooter / Driving (chase view)
stunrunp=Shooter / Driving (chase view)
subroc3d=Shooter / Flying 1st Person
suchie2=Tabletop / Mahjong * Mature *
suchie2o=Tabletop / Mahjong * Mature *
subs=Shooter / Field
sucasino=Casino / Cards
suikoenb=Fighter / Versus
@@ -4506,6 +4679,7 @@ superx=Shooter / Flying Vertical
superxm=Shooter / Flying Vertical
suprglob=Platform / Run Jump
beastf=Platform / Run Jump
beastfp=Platform / Run Jump
theglob=Platform / Run Jump
theglob2=Platform / Run Jump
theglob3=Platform / Run Jump
@@ -4606,13 +4780,23 @@ teetert=Shooter / Gallery
tehkanwc=Sports / Soccer
tekipaki=Puzzle / Drop
tekken=Fighter / Versus
tekkena=Fighter / Versus
tekkenac=Fighter / Versus
tekkenb=Fighter / Versus
tekkenjb=Fighter / Versus
tekken2=Fighter / Versus
tekken2a=Fighter / Versus
tekken2b=Fighter / Versus
tekken2ud=Fighter / Versus
tekken2ub=Fighter / Versus
tekken2jc=Fighter / Versus
tekken2jb=Fighter / Versus
tekken2a=Fighter / Versus
tekken2ua=Fighter / Versus
tekken3=Fighter / Versus
tekkentt=Fighter / Versus
tekken3je1=Fighter / Versus
tektagt=Fighter / Versus
tektagtub=Fighter / Versus
tektagtuc1=Fighter / Versus
tektagtjc1=Fighter / Versus
teljan=Tabletop / Mahjong * Mature *
telmahjn=Tabletop / Mahjong * Mature *
tempest=Shooter / Gallery
@@ -4799,7 +4983,10 @@ labyrunk=Shooter / Walking
labyrunr=Shooter / Walking
triothep=Platform / Fighter Scrolling
triplep=Maze / Outline
triplepa=Maze / Outline
knockout=Maze / Outline
knockoutb=Maze / Outline
knockoutc=Maze / Outline
triplew1=Tabletop / Mahjong * Mature *
triplew2=Tabletop / Mahjong * Mature *
triplhnt=Shooter / Gun
@@ -4886,6 +5073,9 @@ twinspri=Shooter / Flying Vertical
twotiger=Shooter / Field
twotigra=Shooter / Field
tws96=Sports / Soccer
tx1=Driving / Race (chase view)
tx1jb=Driving / Race (chase view)
tx1jc=Driving / Race (chase view)
tylz=Maze / Change Surface
uballoon=Platform / Run Jump
uccops=Fighter / 2.5D
@@ -4965,7 +5155,7 @@ venture2=Maze / Shooter Small
venture4=Maze / Shooter Small
vf=Fighter / Versus
vfive=Shooter / Flying Vertical
grindsta=Shooter / Flying Vertical
grindstma=Shooter / Flying Vertical
grindstm=Shooter / Flying Vertical
vfkids=Fighter / Versus
vfremix=Fighter / Versus
@@ -5146,6 +5336,7 @@ worldc94=Sports / Soccer
wotw=Shooter / Gallery
wow=Maze / Shooter Small
wpksoc=Sports / Soccer
wpksocv2=Sports / Soccer
wrally=Driving / Race
wrallya=Driving / Race
wrally2=Driving / Race
@@ -5160,6 +5351,11 @@ wschampa=Shooter / Gun
wseries=Sports / Baseball
wsf=Sports / Soccer
wtennis=Sports / Tennis
wwallyj=Puzzle / Find the Objects
wwallyja=Puzzle / Find the Objects
wwallyja3p=Puzzle / Find the Objects
wwallyjad=Puzzle / Find the Objects
wwallyjd=Puzzle / Find the Objects
wwestern=Shooter / Misc. Vertical
wwester1=Shooter / Misc. Vertical
wwfmania=Sports / Wrestling
@@ -5172,6 +5368,8 @@ xday2=Quiz / Questions in Japanese
xeno=Shooter / Walking
xenophob=Platform / Shooter Scrolling
xevi3dg=Shooter / Flying Vertical
xevi3dga=Shooter / Flying Vertical
xevi3dgj=Shooter / Flying Vertical
xevious=Shooter / Flying Vertical
battles=Shooter / Flying Vertical
sxevious=Shooter / Flying Vertical
@@ -5284,11 +5482,13 @@ decocass=System / BIOS
konamigx=System / BIOS
megaplay=System / BIOS
megatech=System / BIOS
namcoc76=System / BIOS
neogeo=System / BIOS
nss=System / BIOS
pgm=System / BIOS
playch10=System / BIOS
psarc95=System / BIOS
ptblank2=System / BIOS
skns=System / BIOS
stvbios=System / BIOS
taitofx1=System / BIOS
+527 -469
View File
File diff suppressed because it is too large. Load diff
+6 -2
View File
@@ -1688,6 +1688,7 @@ batriderhk:
mrdrillrj:
mrdrillr:
mrdrillrja2:
0:201038:288:76:76
sfiii3:
@@ -1829,6 +1830,7 @@ spf2xjd:
spf2ta:
spf2th:
spf2td:
spf2xpri:
0:ffd7aa:4e:00:02
0:ff8081:1:01:01
@@ -2775,7 +2777,9 @@ chinhero3:
0:e12a:1:03:03
asurabus:
asurabusa:
asurabusj:
asurabusja:
asurabusjr:
0:40326d:132:05:14
dynabomb:
@@ -3270,7 +3274,7 @@ theglob2:
0:7c4b:1:01:01
0:7c51:1:80:80
beastf:
beastfp:
0:4c46:3c:4d:00
0:4c8a:1:01:01
0:4cb0:1:15:15
+31 -31
View File
@@ -18291,7 +18291,7 @@ F.A.Q. by Kevin Butler A.K.A. War Doc
$end
$info=batsugun,batugnsp,batsugna,
$info=batsugun,batsuguna,batsugunc,batsugunb,batsugunsp,
$bio
Batsugun (c) 02/1993 Toaplan.
@@ -20586,7 +20586,7 @@ Commodore Amiga (1990)
$end
$info=beastf,
$info=beastf,beastfp,
$bio
Beastie Feastie (c) 1984 Epos Corporation.
@@ -39674,7 +39674,7 @@ Graphic : Kim Eun Ae, Hong Young Joo, Whang O-Sik, Hong Dae Hyun
$end
$info=chplft,chplftb,chplftbl,
$info=choplift,chopliftu,chopliftbl,
$bio
Choplifter (c) 1985 Sega.
@@ -49927,7 +49927,7 @@ The title of this game translates from Japanese as 'Hanafuda at the Apartments'.
$end
$info=danceyes,
$info=danceyes,danceyesu,danceyesj,
$bio
Dancing Eyes (c) 08/1996 Namco.
@@ -57433,7 +57433,7 @@ Nintendo Famicom (1988, "Ikari 2 - Dogosoken")
$end
$info=dogyuun,
$info=dogyuun,dogyuuna,dogyuunb,dogyuunt,
$bio
Dogyuun (c) 10/1992 Toaplan.
@@ -63256,7 +63256,7 @@ This game is also known as "Dataeast's Hoops".
$end
$info=dunkmnia,dunkmnic,
$info=dunkmnia,dunkmniajc,
$bio
Dunk Mania (c) 1995 Namco.
@@ -68525,7 +68525,7 @@ Designed by : Luis Sanchez
$end
$info=ehrgeiz,ehrgeiza,
$info=ehrgeiz,ehrgeizua,ehrgeizja,
$bio
EZ : Ehrgeiz - God Bless The Ring (c) 1998 Square / Namco.
@@ -71900,7 +71900,7 @@ Buttons : 2
$end
$info=fgtlayer,
$info=fgtlayer,fgtlayerja,
$bio
Fighting Layer (c) 12/1998 Arika.
@@ -74054,7 +74054,7 @@ This game is also known as "Round-Up".
$end
$info=fixeight,fixeighb,
$info=fixeight,fixeightk,fixeighth,fixeighttw,fixeighta,fixeightu,fixeightj,fixeightt,fixeightkt,fixeightht,fixeighttwt,fixeightat,fixeightut,fixeightjt,fixeightbl,
$bio
Fixeight (c) 1992 Toaplan.
@@ -84877,7 +84877,7 @@ The US version has the "Recycle It, Don't Trash It!" screen.
$end
$info=mp_gaxe2,
$info=mp_gaxe2,mp_gaxe2a,
$bio
Golden Axe II (c) 1993 Sega.
@@ -89643,7 +89643,7 @@ F.A.Q. by Kevin Butler A.K.A. War Doc
$end
$info=grindstm,grindsta,
$info=grindstm,grindstma,
$bio
Grind Stormer (c) 1992 Toaplan.
@@ -95537,7 +95537,7 @@ King Records released a limited-edition soundtrack album for this game (Konami G
$end
$info=hayaosi1,
$info=hayaosi2,
$bio
Hayaoshi Quiz Ouza Ketteisen (c) 1994 Jaleco.
@@ -100624,7 +100624,7 @@ Sega Saturn (1996, "Sega Ages : Rouka ni Ichidant-R")
$end
$info=47pie2,47pie2o,
$info=suchie2,suchie2o,
$bio
Idol Janshi Suchi-Pai II (c) 1994 Jaleco.
@@ -115022,7 +115022,7 @@ You can also get points by punching out enemies. If you can punch out an enemy w
$end
$info=kbash,
$info=kbash,kbashk,kbashp,
$bio
Knuckle Bash (c) 1993 Toaplan.
@@ -146695,7 +146695,7 @@ MSX (1985)
$end
$info=mrdrillr,
$info=mrdrillr,mrdrillrja2,
$bio
Mr. Driller (c) 1999 Namco.
@@ -153222,7 +153222,7 @@ PC [MS Windows] (2005, "Taito Legends")
$end
$info=nzerotea,
$info=nzeroteam,nzeroteama,nzeroteamb,zerotm2k,
$bio
New Zero Team (c) 1993 Seibu Kaihatsu.
@@ -168550,7 +168550,7 @@ Sony PlayStation 2 (2002, "Gunvari Collection + Time Crisis")
$end
$info=ptblank2,
$info=ptblank2,ptblank2a,ptblank2b,ptblank2c,ptblank2ua,gunbarla,
$bio
Point Blank 2 (c) 1999 Namco.
@@ -182610,7 +182610,7 @@ PC [MS-DOS, CD-ROM]
$end
$info=raidndx,raidndxa,raidndxb,raidndxj,raidndxm,
$info=raidendx,raidendxg,raidendxpt,raidendxa1,raidendxa2,raidendxk,raidendxu,raidendxnl,raidendxj,raidendxja,raidendxch,r2dx_v33,r2dx_v33_r2,
$bio
Raiden DX (c) 1994 Seibu Kaihatsu.
@@ -183143,7 +183143,7 @@ Level 15 : Before the boss appears, do not shoot any small tanks. Two small tank
$end
$info=raiden2,raiden2a,raiden2b,raiden2c,raiden2e,
$info=raiden2,raiden2g,raiden2gb,raiden2hk,raiden2j,raiden2sw,raiden2u,raiden2f,raiden2nl,raiden2es,raiden2i,raiden2au,raiden2e,raiden2eub,raiden2eua,raiden2eg,raiden2eup,raiden2ea,raiden2eu,raiden2k,raiden2dx,
$bio
Raiden II (c) 1993 Seibu Kaihatsu.
@@ -187724,7 +187724,7 @@ Total planner / Total cordinator : The Alive
$end
$info=revenger,
$info=revenger,revngr84,
$bio
Revenger (c) 1984 Epos.
@@ -210976,7 +210976,7 @@ Sega Saturn (1997)
$end
$info=soulclbr,soulclba,soulclbb,
$info=soulclbr,soulclbrab,soulclbrac,soulclbrub,soulclbruc,soulclbrja2,soulclbrjb,soulclbrjc,
$bio
Soul Calibur (c) 07/1998 Namco.
@@ -211061,7 +211061,7 @@ Sega Dreamcast (1999) : The new Weapon Master mode made it's debut in this versi
$end
$info=souledga,souledgb,souledgc,
$info=souledgea,souledgeua,souledgeja,
$bio
Soul Edge (c) 1995 Namco.
@@ -211188,7 +211188,7 @@ Sony PlayStation (1996)
$end
$info=souledge,
$info=souledge,souledgeuc,
$bio
Soul Edge Ver. II (c) 1996 Namco.
@@ -219296,7 +219296,7 @@ Sega Saturn (1997, "Sega Memorial Selection Vol.2")
$end
$info=starswep,
$info=starswep,starswepj,
$bio
Star Sweep (c) 07/1997 Axela.
@@ -242217,7 +242217,7 @@ Directed by : Strong Shima
$end
$info=mp_twc,
$info=mp_twcup,
$bio
Tecmo World Cup (c) 1993 Sega.
@@ -243474,7 +243474,7 @@ Music composed by : Tomoaki Takanohashi
$end
$info=tekken,tekkena,tekkenb,tekkenc,
$info=tekken,tekkenac,tekkenb,tekkenjb,
$bio
Tekken (c) 12/1994 Namco.
@@ -243635,7 +243635,7 @@ Sony PlayStation 2 (2005, "NamCollection") : Japan release only.
$end
$info=tekken2,tekken2a,tekken2b,
$info=tekken2,tekken2b,tekken2ud,tekken2ub,tekken2jc,tekken2jb,tekken2a,tekken2ua,
$bio
Tekken 2 (c) 08/1995 Namco.
@@ -243867,7 +243867,7 @@ Sony PlayStation 2 (2005, "Tekken 5 Ultimate Collectors Edition")
$end
$info=tekken3,tekken3a,
$info=tekken3,tekken3je1,
$bio
Tekken 3 (c) 1996 Namco.
@@ -244067,7 +244067,7 @@ Sony PlayStation 2 (2005, "Tekken 5 Ultimate Collectors Edition")
$end
$info=tektagt,tektagta,
$info=tektagt,tektagtub,tektagtuc1,tektagtjc1,
$bio
Tekken Tag Tournament (c) 1999 Namco.
@@ -275757,7 +275757,7 @@ F.A.Q. by Kevin Butler A.K.A. War Doc
$end
$info=xevi3dg,
$info=xevi3dg,xevi3dga,xevi3dgj,
$bio
Xevious 3D/G (c) 04/1995 Namco.
@@ -278372,7 +278372,7 @@ This game is known in Japan as "Gekitsui Oh".
$end
$info=zeroteam,zeroteaa,zeroteab,
$info=zeroteam,zeroteama,zeroteamb,zeroteamc,zeroteamd,zeroteame,zeroteams,zeroteamsr,
$bio
Zero Team (c) 1993 Seibu Kaihatsu.
+45368 -5973
View File
File diff suppressed because it is too large. Load diff
+119 -32
View File
@@ -377,6 +377,7 @@ struct artwork_piece
struct mame_bitmap * yrgbbitmap;
UINT32 * scanlinehint;
UINT8 blendflags;
const struct overlay_piece *overlay_data; /* a driver's overlay: drawn again on a resize */
/* derived/dynamic data */
int intersects_game;
@@ -408,6 +409,9 @@ static int gamescale;
static struct mame_bitmap *uioverlay;
static UINT32 *uioverlayhint;
static struct rectangle uibounds, last_uibounds;
static struct rectangle ui_changed_bounds;
static int ui_changed;
static int full_render_pending; /* after a resize: draw the whole game, not the vector dirty pixels */
static UINT32 *palette_lookup;
@@ -446,6 +450,7 @@ static void alpha_blend_intersecting_rect(struct mame_bitmap *dstbitmap, const s
static void add_intersecting_rect(struct mame_bitmap *dstbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, const struct rectangle *srcbounds);
static void cmy_blend_intersecting_rect(struct mame_bitmap *dstbitmap, struct mame_bitmap *dstyrgbbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, struct mame_bitmap *srcyrgbbitmap, const struct rectangle *srcbounds, UINT8 blendflags);
static int generate_overlay(const struct overlay_piece *list, int width, int height);
static int generate_overlay_bitmap(struct artwork_piece *piece, int width, int height);
static void add_range_to_hint(UINT32 *hintbase, int scanline, int startx, int endx);
@@ -596,7 +601,89 @@ static INLINE UINT32 blend_over(UINT32 game, UINT32 pre, UINT32 yrgb)
to osd_create_display
-------------------------------------------------*/
static int artwork_setup_display(struct osd_create_params *params, UINT32 *rgb_components);
int artwork_create_display(struct osd_create_params *params, UINT32 *rgb_components, const struct artwork_callbacks *callbacks)
{
/* reset UI */
uioverlay = NULL;
uioverlayhint = NULL;
palette_lookup = NULL;
/* first load the artwork; if none, quit now */
artwork_list = NULL;
if (!artwork_load(Machine->gamedrv, params->width, params->height, callbacks))
return 1;
if (!artwork_list && (!callbacks->activate_artwork || !callbacks->activate_artwork(params)))
return osd_create_display(params, rgb_components);
return artwork_setup_display(params, rgb_components);
}
/*-------------------------------------------------
artwork_resize_display - the game's display
changes size while it runs (the vector
resolution): the loaded artwork is kept, the
bitmaps that depend on the size are made again
-------------------------------------------------*/
int artwork_resize_display(struct osd_create_params *params, UINT32 *rgb_components)
{
struct artwork_piece *piece;
if (!artwork_list && !uioverlay)
{
osd_close_display();
return osd_create_display(params, rgb_components);
}
/* free what was made for the old size */
auto_bitmap_free(underlay);
auto_bitmap_free(overlay);
auto_bitmap_free(overlay_yrgb);
auto_bitmap_free(bezel);
auto_bitmap_free(final);
auto_bitmap_free(uioverlay);
auto_free_ptr(uioverlayhint);
underlay = overlay = overlay_yrgb = bezel = final = uioverlay = NULL;
uioverlayhint = NULL;
for (piece = artwork_list; piece; piece = piece->next)
{
auto_bitmap_free(piece->prebitmap);
auto_bitmap_free(piece->yrgbbitmap);
auto_free_ptr(piece->scanlinehint);
piece->prebitmap = piece->yrgbbitmap = NULL;
piece->scanlinehint = NULL;
/* a driver's overlay is drawn at the game's size: draw it again */
if (piece->overlay_data)
{
auto_bitmap_free(piece->rawbitmap);
piece->rawbitmap = NULL;
if (!generate_overlay_bitmap(piece, params->width, params->height))
return 1;
}
}
/* the UI areas were on the old size */
memset(&uibounds, 0, sizeof(uibounds));
memset(&last_uibounds, 0, sizeof(last_uibounds));
memset(&ui_changed_bounds, 0, sizeof(ui_changed_bounds));
ui_changed = 0;
full_render_pending = 1;
osd_close_display();
return artwork_setup_display(params, rgb_components);
}
/*-------------------------------------------------
artwork_setup_display - size the artwork
bitmaps for the display and create it
-------------------------------------------------*/
static int artwork_setup_display(struct osd_create_params *params, UINT32 *rgb_components)
{
int original_width = params->width;
int original_height = params->height;
@@ -605,17 +692,6 @@ int artwork_create_display(struct osd_create_params *params, UINT32 *rgb_compone
UINT32 rgb32_components[3];
struct artwork_piece *piece;
/* reset UI */
uioverlay = NULL;
uioverlayhint = NULL;
/* first load the artwork; if none, quit now */
artwork_list = NULL;
if (!artwork_load(Machine->gamedrv, original_width, original_height, callbacks))
return 1;
if (!artwork_list && (!callbacks->activate_artwork || !callbacks->activate_artwork(params)))
return osd_create_display(params, rgb_components);
/* determine the game bitmap scale factor */
gamescale = options.artwork_res;
if (gamescale < 1 || (params->video_attributes & VIDEO_TYPE_VECTOR))
@@ -798,8 +874,6 @@ void artwork_update_visible_area(struct mame_display *display)
void artwork_update_video_and_audio(struct mame_display *display)
{
static struct rectangle ui_changed_bounds;
static int ui_changed;
int artwork_changed = 0, ui_visible = 0;
/* do nothing if no artwork */
@@ -824,6 +898,13 @@ void artwork_update_video_and_audio(struct mame_display *display)
/* process the artwork and UI only if we're not frameskipping */
if (display->changed_flags & GAME_BITMAP_CHANGED)
{
if (full_render_pending)
{
display->changed_flags &= ~VECTOR_PIXELS_CHANGED;
display->vector_dirty_pixels = NULL;
full_render_pending = 0;
}
/* see if there's any UI to display this frame */
ui_visible = (uibounds.max_x != 0);
@@ -3349,6 +3430,25 @@ static int generate_right_triangle_piece(struct artwork_piece *piece, const stru
the given pieces
-------------------------------------------------*/
static int generate_overlay_bitmap(struct artwork_piece *piece, int width, int height)
{
const struct overlay_piece *list = piece->overlay_data;
/* switch off the type */
switch (list->type & ~OVERLAY_FLAG_MASK)
{
case OVERLAY_TYPE_RECTANGLE:
return generate_rect_piece(piece, list, width, height);
case OVERLAY_TYPE_DISK:
return generate_disk_piece(piece, list, width, height);
case OVERLAY_TYPE_RIGHT_TRIANGLE:
return generate_right_triangle_piece(piece, list, width, height);
}
return 1;
}
static int generate_overlay(const struct overlay_piece *list, int width, int height)
{
struct artwork_piece *piece;
@@ -3368,24 +3468,10 @@ static int generate_overlay(const struct overlay_piece *list, int width, int hei
piece->priority = priority++;
piece->blendflags = list->type & OVERLAY_FLAG_MASK;
piece->tag = list->tag; /* Handle someone using a different tag, for example, cocktail mode */
piece->overlay_data = list;
/* switch off the type */
switch (list->type & ~OVERLAY_FLAG_MASK)
{
case OVERLAY_TYPE_RECTANGLE:
if (!generate_rect_piece(piece, list, width, height))
return 0;
break;
case OVERLAY_TYPE_DISK:
if (!generate_disk_piece(piece, list, width, height))
return 0;
break;
case OVERLAY_TYPE_RIGHT_TRIANGLE:
if (!generate_right_triangle_piece(piece, list, width, height))
return 0;
break;
}
if (!generate_overlay_bitmap(piece, width, height))
return 0;
/* next */
list++;
@@ -3582,8 +3668,9 @@ static int compute_rgb_components(int depth, UINT32 rgb_components[3], UINT32 rg
/* compute a transparent color; this is in the premultiplied space, so alpha is inverted */
transparent_color = ASSEMBLE_ARGB(0xff,0x00,0x00,0x00);
/* allocate a palette lookup */
palette_lookup = auto_malloc(65536 * sizeof(palette_lookup[0]));
/* allocate a palette lookup (once per game: a resize keeps it, as the depth and palette stay) */
if (!palette_lookup)
palette_lookup = auto_malloc(65536 * sizeof(palette_lookup[0]));
/* switch off the depth */
+1
View File
@@ -163,6 +163,7 @@ struct overlay_piece
***************************************************************************/
int artwork_create_display(struct osd_create_params *params, UINT32 *rgb_components, const struct artwork_callbacks *callbacks);
int artwork_resize_display(struct osd_create_params *params, UINT32 *rgb_components);
void artwork_update_video_and_audio(struct mame_display *display);
void artwork_override_screenshot_params(struct mame_bitmap **bitmap, struct rectangle *rect, UINT32 *rgb_components);
+138 -88
View File
@@ -16,31 +16,6 @@
/*#define LOG_LOAD */
const char *chd_error_text[] =
{
"CHDERR_NONE",
"CHDERR_NO_INTERFACE",
"CHDERR_OUT_OF_MEMORY",
"CHDERR_INVALID_FILE",
"CHDERR_INVALID_PARAMETER",
"CHDERR_INVALID_DATA",
"CHDERR_FILE_NOT_FOUND",
"CHDERR_REQUIRES_PARENT",
"CHDERR_FILE_NOT_WRITEABLE",
"CHDERR_READ_ERROR",
"CHDERR_WRITE_ERROR",
"CHDERR_CODEC_ERROR",
"CHDERR_INVALID_PARENT",
"CHDERR_HUNK_OUT_OF_RANGE",
"CHDERR_DECOMPRESSION_ERROR",
"CHDERR_COMPRESSION_ERROR",
"CHDERR_CANT_CREATE_FILE",
"CHDERR_CANT_VERIFY",
"CHDERR_NOT_SUPPORTED",
"CHDERR_METADATA_NOT_FOUND",
"CHDERR_INVALID_METADATA_SIZE",
"CHDERR_UNSUPPORTED_VERSION"
};
/***************************************************************************
Constants
***************************************************************************/
@@ -182,7 +157,7 @@ size_t generic_nvram_size;
data8_t *generic_nvram;
/* disks */
static struct chd_file *disk_handle[4];
static struct hard_disk_file *disk_handle[4];
/* system BIOS */
static int system_bios;
@@ -996,6 +971,47 @@ void auto_free(void)
}
/*-------------------------------------------------
auto_free_ptr - free one auto_malloc block
before its tag ends, and stop tracking it
(for the buffers that are reallocated while
a game runs, as the vector bitmap)
-------------------------------------------------*/
void auto_free_ptr(void *ptr)
{
int i;
if (!ptr)
return;
for (i = malloc_list_index - 1; i >= 0; i--)
if (malloc_list[i].ptr == ptr)
{
free(ptr);
memmove(&malloc_list[i], &malloc_list[i + 1], (malloc_list_index - i - 1) * sizeof(malloc_list[0]));
malloc_list_index--;
return;
}
}
/*-------------------------------------------------
auto_bitmap_free - free an auto_bitmap_alloc
bitmap before its tag ends
-------------------------------------------------*/
void auto_bitmap_free(struct mame_bitmap *bitmap)
{
if (!bitmap)
return;
/* the line array was allocated before the safety rows were skipped */
auto_free_ptr(bitmap->line - BITMAP_SAFETY);
auto_free_ptr(bitmap);
}
/*-------------------------------------------------
bitmap_alloc - allocate a bitmap at the
current screen depth
@@ -1051,7 +1067,7 @@ void end_resource_tracking(void)
***************************************************************************/
struct chd_file *get_disk_handle(int diskindex)
struct hard_disk_file *get_disk_handle(int diskindex)
{
return disk_handle[diskindex];
}
@@ -1211,7 +1227,7 @@ static int count_roms(const struct RomModule *romp)
static void fill_random(UINT8 *base, UINT32 length)
{
while (length--)
*base++ = rand();
*base++ = mame_rand_int();
}
@@ -1824,11 +1840,14 @@ static int process_disk_entries(struct rom_load_data *romdata, const struct RomM
/* handle files */
if (ROMENTRY_ISFILE(romp))
{
struct chd_file *source, *diff = NULL;
struct chd_header header;
const struct GameDriver *drv;
struct hard_disk_file *disk;
mame_file *source = NULL, *diff = NULL;
UINT8 *legacydata = NULL;
UINT32 legacysize = 0;
char filename[1024], *c;
char acthash[HASH_BUF_SIZE];
int err;
char datahash[HASH_BUF_SIZE], imagehash[HASH_BUF_SIZE];
const char *error;
/* make the filename of the source */
strcpy(filename, ROM_GETNAME(romp));
@@ -1838,83 +1857,114 @@ static int process_disk_entries(struct rom_load_data *romdata, const struct RomM
else
strcat(filename, ".chd");
/* first open the source drive */
/* look for it in the ROM path, up the chain through the parents */
log_cb(RETRO_LOG_INFO, LOGPRE "Opening disk image: %s\n", filename);
source = chd_open(filename, 0, NULL);
for (drv = Machine->gamedrv; drv != NULL && source == NULL; drv = drv->clone_of)
source = mame_fopen(drv->name, filename, FILETYPE_IMAGE, 0);
if (!source)
{
if (chd_get_last_error() == CHDERR_UNSUPPORTED_VERSION)
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s UNSUPPORTED CHD VERSION\n", filename);
else
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s NOT FOUND\n", filename);
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s NOT FOUND\n", filename);
romdata->errors++;
romp++;
continue;
}
/* get the header and extract the MD5/SHA1 */
header = *chd_get_header(source);
hash_data_clear(acthash);
hash_data_insert_binary_checksum(acthash, HASH_MD5, header.md5);
hash_data_insert_binary_checksum(acthash, HASH_SHA1, header.sha1);
/* verify the MD5 */
if (!hash_data_is_equal(ROM_GETHASHDATA(romp), acthash, 0))
{
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s WRONG CHECKSUMS:\n", filename);
dump_wrong_and_correct_checksums(romdata, ROM_GETHASHDATA(romp), acthash);
romdata->warnings++;
}
/* if not read-only, make the diff file */
/* if not read-only, open or create the differencing file */
if (!DISK_ISREADONLY(romp))
{
/* make the filename of the diff */
strcpy(filename, ROM_GETNAME(romp));
c = strrchr(filename, '.');
char diffname[1024];
strcpy(diffname, ROM_GETNAME(romp));
c = strrchr(diffname, '.');
if (c)
strcpy(c, ".dif");
else
strcat(filename, ".dif");
strcat(diffname, ".dif");
log_cb(RETRO_LOG_INFO, LOGPRE "Opening differencing image: %s\n", diffname);
diff = mame_fopen(NULL, diffname, FILETYPE_IMAGE_DIFF, 1);
/* one made by older versions of the core (a CHD v3): keep its */
/* contents to import them, and the file itself as <name>.dif.old */
if (diff)
{
UINT8 tag[8];
UINT64 size = mame_fsize(diff);
mame_fseek(diff, 0, SEEK_SET);
if (size >= sizeof(tag) && size < 0x80000000 &&
mame_fread(diff, tag, sizeof(tag)) == sizeof(tag) && memcmp(tag, "MComprHD", 8) == 0)
{
char oldname[1024 + 4];
legacydata = malloc((size_t)size);
if (legacydata)
{
mame_fseek(diff, 0, SEEK_SET);
if (mame_fread(diff, legacydata, (UINT32)size) == size)
legacysize = (UINT32)size;
else
{
free(legacydata);
legacydata = NULL;
}
}
mame_fclose(diff);
/* keep the file even if it could not be read, so nothing is lost */
sprintf(oldname, "%s.old", diffname);
if (osd_rename(FILETYPE_IMAGE_DIFF, diffname, oldname))
log_cb(RETRO_LOG_INFO, LOGPRE "Old-format differencing image kept as %s\n", oldname);
else
log_cb(RETRO_LOG_WARN, LOGPRE "Old-format differencing image could not be kept as %s\n", oldname);
diff = mame_fopen(NULL, diffname, FILETYPE_IMAGE_DIFF, 1);
}
mame_fseek(diff, 0, SEEK_SET);
}
/* try to open the diff */
log_cb(RETRO_LOG_INFO, LOGPRE "Opening differencing image: %s\n", filename);
diff = chd_open(filename, 1, source);
if (!diff)
{
/* didn't work; try creating it instead */
log_cb(RETRO_LOG_INFO, LOGPRE "Creating differencing image: %s\n", filename);
err = chd_create(filename, 0, 0, CHDCOMPRESSION_NONE, source);
if (err != CHDERR_NONE)
{
if (chd_get_last_error() == CHDERR_UNSUPPORTED_VERSION)
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s UNSUPPORTED CHD VERSION\n", filename);
else
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s: CAN'T CREATE DIFF FILE Error code %s\n", filename, chd_error_text[err]);
romdata->errors++;
romp++;
continue;
}
/* open the newly-created diff file */
log_cb(RETRO_LOG_INFO, LOGPRE "Opening new differencing image: %s\n", filename);
diff = chd_open(filename, 1, source);
if (!diff)
{
if (chd_get_last_error() == CHDERR_UNSUPPORTED_VERSION)
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s UNSUPPORTED CHD VERSION\n", filename);
else
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s: CAN'T OPEN DIFF FILE Error code %s\n", filename, chd_error_text[err]);
romdata->errors++;
romp++;
continue;
}
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s: CAN'T OPEN OR CREATE DIFF FILE\n", diffname);
free(legacydata);
mame_fclose(source);
romdata->errors++;
romp++;
continue;
}
}
/* open the disk */
disk = hard_disk_open(source, diff, &error);
if (!disk)
{
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s: CAN'T OPEN DISK IMAGE (%s)\n", filename, error);
free(legacydata);
romdata->errors++;
romp++;
continue;
}
/* bring over what the game wrote with older versions of the core */
if (legacydata)
{
hard_disk_import_legacy_diff(disk, legacydata, legacysize);
free(legacydata);
}
/* verify the checksums: older sets list those of the data (the same for */
/* every CHD version of a dump), current MAME the one of a v5 image */
hard_disk_get_hashes(disk, datahash, imagehash);
if (!hash_data_is_equal(ROM_GETHASHDATA(romp), datahash, 0) &&
!hash_data_is_equal(ROM_GETHASHDATA(romp), imagehash, 0))
{
log_cb(RETRO_LOG_ERROR, LOGPRE "%-12s WRONG CHECKSUMS:\n", filename);
dump_wrong_and_correct_checksums(romdata, ROM_GETHASHDATA(romp), datahash);
romdata->warnings++;
}
/* we're okay, set the handle */
log_cb(RETRO_LOG_DEBUG, LOGPRE "Assigning to handle %d\n", DISK_GETINDEX(romp));
disk_handle[DISK_GETINDEX(romp)] = DISK_ISREADONLY(romp) ? source : diff;
disk_handle[DISK_GETINDEX(romp)] = disk;
romp++;
}
}
+5 -1
View File
@@ -452,12 +452,16 @@ static INLINE int get_resource_tag(void)
/* automatically-freeing memory */
void *auto_malloc(size_t size);
/* free one auto_malloc block (or auto bitmap) before its tag ends */
void auto_free_ptr(void *ptr);
void auto_bitmap_free(struct mame_bitmap *bitmap);
char *auto_strdup(const char *str);
struct mame_bitmap *auto_bitmap_alloc(int width,int height);
struct mame_bitmap *auto_bitmap_alloc_depth(int width,int height,int depth);
/* disk handling */
struct chd_file *get_disk_handle(int diskindex);
struct hard_disk_file *get_disk_handle(int diskindex);
/* ROM processing */
int rom_load(const struct RomModule *romp);
+31
View File
@@ -14699,6 +14699,37 @@ const char *sf_get_ctrl_name(int type)
return "";
}
const struct ControlInfo sfrush_ctrl =
{
false, /* 45_degree_rotation for joystick(s) */
false, /* alternating_controls */
false, /* mirrored_controls */
"Wheel, accelerator and brake on player 1 (the shifter stays in the last gear chosen). Clutch, music and the four track buttons are on player 2.", /* control_details */
&sfrush_get_ctrl_name
};
const char *sfrush_get_ctrl_name(int type)
{
switch(type)
{
case IPT_BUTTON1: return BTN1 "1st Gear / Music";
case IPT_BUTTON2: return BTN2 "2nd Gear / Track 1";
case IPT_BUTTON3: return BTN3 "3rd Gear / Track 2";
case IPT_BUTTON4: return BTN4 "4th Gear / Track 3";
case IPT_BUTTON5: return BTN5 "Track 4";
case IPT_BUTTON7: return BTN7 "View 1";
case IPT_BUTTON8: return BTN8 "View 2";
case IPT_BUTTON9: return "B9: View 3";
case IPT_BUTTON10: return "B10: Reverse";
case IPT_PEDAL: return "Accelerator / Clutch";
case IPT_PEDAL2: return "Brake";
case IPT_PADDLE: return "Steer Left";
case (IPT_PADDLE + IPT_EXTENSION): return "Steer Right";
} /* end of switch */
return "";
}
const struct ControlInfo sfa2_ctrl =
{
false, /* 45_degree_rotation for joystick(s) */
+3
View File
@@ -2440,6 +2440,9 @@ const char *stratgyx_get_ctrl_name(int type);
extern const struct ControlInfo sf_ctrl;
const char *sf_get_ctrl_name(int type);
extern const struct ControlInfo sfrush_ctrl;
const char *sfrush_get_ctrl_name(int type);
extern const struct ControlInfo sfa2_ctrl;
const char *sfa2_get_ctrl_name(int type);
+789 -45
View File
@@ -368,6 +368,27 @@ static void wr_px(INT32 val) { adsp2100.px = val; }
static void wr_ifc(INT32 val)
{
adsp2100.ifc = val;
#if (HAS_ADSP2181)
if (chip_type == CHIP_TYPE_ADSP2181)
{
if (val & 0x0002) adsp2100.irq_latch[ADSP2181_IRQ0] = 0;
if (val & 0x0004) adsp2100.irq_latch[ADSP2181_IRQ1] = 0;
if (val & 0x0008) adsp2100.irq_latch[ADSP2181_BDMA] = 0;
if (val & 0x0010) adsp2100.irq_latch[ADSP2181_IRQE] = 0;
if (val & 0x0020) adsp2100.irq_latch[ADSP2181_SPORT0_RX] = 0;
if (val & 0x0040) adsp2100.irq_latch[ADSP2181_SPORT0_TX] = 0;
if (val & 0x0080) adsp2100.irq_latch[ADSP2181_IRQ2] = 0;
if (val & 0x0200) adsp2100.irq_latch[ADSP2181_IRQ0] = 1;
if (val & 0x0400) adsp2100.irq_latch[ADSP2181_IRQ1] = 1;
if (val & 0x0800) adsp2100.irq_latch[ADSP2181_BDMA] = 1;
if (val & 0x1000) adsp2100.irq_latch[ADSP2181_IRQE] = 1;
if (val & 0x2000) adsp2100.irq_latch[ADSP2181_SPORT0_RX] = 1;
if (val & 0x4000) adsp2100.irq_latch[ADSP2181_SPORT0_TX] = 1;
if (val & 0x8000) adsp2100.irq_latch[ADSP2181_IRQ2] = 1;
check_irqs();
return;
}
#endif
if (val & 0x002) adsp2100.irq_latch[ADSP2101_IRQ0] = 0;
if (val & 0x004) adsp2100.irq_latch[ADSP2101_IRQ1] = 0;
if (val & 0x008) adsp2100.irq_latch[ADSP2101_SPORT0_RX] = 0;
@@ -384,6 +405,25 @@ static void wr_tx0(INT32 val) { if (sport_tx_callback) (*sport_tx_callback)(0, v
static void wr_tx1(INT32 val) { if (sport_tx_callback) (*sport_tx_callback)(1, val); }
static void wr_owrctr(INT32 val) { adsp2100.cntr = val & 0x3fff; }
static void wr_topstack(INT32 val) { pc_stack_push_val(val & 0x3fff); }
/* ADSP-2181: the memory overlay registers (group 1, 14 and 15) */
static void wr_pmovlay(INT32 val)
{
#if (HAS_ADSP2181)
if (chip_type == CHIP_TYPE_ADSP2181)
adsp2100.pmovlay = val & 0x3fff;
#endif
}
static void wr_dmovlay(INT32 val)
{
#if (HAS_ADSP2181)
if (chip_type == CHIP_TYPE_ADSP2181)
{
adsp2100.dmovlay = val & 0x3fff;
if (dmovlay_callback)
(*dmovlay_callback)(adsp2100.dmovlay);
}
#endif
}
#define WRITE_REG(grp,reg,val) ((*wr_reg[grp][reg])(val))
@@ -395,7 +435,7 @@ static void (*wr_reg[4][16])(INT32) =
},
{
wr_i0, wr_i1, wr_i2, wr_i3, wr_m0, wr_m1, wr_m2, wr_m3,
wr_l0, wr_l1, wr_l2, wr_l3, wr_inval, wr_inval, wr_inval, wr_inval
wr_l0, wr_l1, wr_l2, wr_l3, wr_inval, wr_inval, wr_pmovlay, wr_dmovlay
},
{
wr_i4, wr_i5, wr_i6, wr_i7, wr_m4, wr_m5, wr_m6, wr_m7,
@@ -469,6 +509,13 @@ static INT32 rd_px(void) { return adsp2100.px; }
static INT32 rd_rx0(void) { if (sport_rx_callback) return (*sport_rx_callback)(0); else return 0; }
static INT32 rd_rx1(void) { if (sport_rx_callback) return (*sport_rx_callback)(1); else return 0; }
static INT32 rd_stacktop(void) { return pc_stack_pop_val(); }
#if (HAS_ADSP2181)
static INT32 rd_pmovlay(void) { return (chip_type == CHIP_TYPE_ADSP2181) ? adsp2100.pmovlay : 0; }
static INT32 rd_dmovlay(void) { return (chip_type == CHIP_TYPE_ADSP2181) ? adsp2100.dmovlay : 0; }
#else
#define rd_pmovlay rd_inval
#define rd_dmovlay rd_inval
#endif
#define READ_REG(grp,reg) ((*rd_reg[grp][reg])())
@@ -480,7 +527,7 @@ static INT32 (*rd_reg[4][16])(void) =
},
{
rd_i0, rd_i1, rd_i2, rd_i3, rd_m0, rd_m1, rd_m2, rd_m3,
rd_l0, rd_l1, rd_l2, rd_l3, rd_inval, rd_inval, rd_inval, rd_inval
rd_l0, rd_l1, rd_l2, rd_l3, rd_inval, rd_inval, rd_pmovlay, rd_dmovlay
},
{
rd_i4, rd_i5, rd_i6, rd_i7, rd_m4, rd_m5, rd_m6, rd_m7,
@@ -498,16 +545,23 @@ static INT32 (*rd_reg[4][16])(void) =
Modulus addressing logic
===========================================================================*/
static INLINE void modify_address(UINT32 ireg, UINT32 mreg)
/* index register 'i' plus 'm', kept in its circular buffer; 'wrap14' (a
constant, set only in the ADSP-2181 interpreter loop) first keeps the
sum to 14 bits, as in current MAME: an index that steps below 0 wraps
to the top of memory instead of going out of the address space */
static INLINE ADSP_ALWAYS_INLINE UINT32 dag_step(UINT32 i, INT32 m, UINT32 base, UINT32 l, int wrap14)
{
UINT32 base = adsp2100.base[ireg];
UINT32 i = adsp2100.i[ireg];
UINT32 l = adsp2100.l[ireg];
i += adsp2100.m[mreg];
i += m;
if (wrap14)
i &= 0x3fff;
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
return i;
}
static INLINE ADSP_ALWAYS_INLINE void modify_address(UINT32 ireg, UINT32 mreg, int wrap14)
{
adsp2100.i[ireg] = dag_step(adsp2100.i[ireg], adsp2100.m[mreg], adsp2100.base[ireg], adsp2100.l[ireg], wrap14);
}
@@ -516,7 +570,7 @@ static INLINE void modify_address(UINT32 ireg, UINT32 mreg)
Data memory accessors
===========================================================================*/
static INLINE void data_write_dag1(UINT32 op, INT32 val)
static INLINE ADSP_ALWAYS_INLINE void data_write_dag1_f(UINT32 op, INT32 val, int fast)
{
UINT32 ireg = (op >> 2) & 3;
UINT32 mreg = op & 3;
@@ -527,19 +581,16 @@ static INLINE void data_write_dag1(UINT32 op, INT32 val)
if ( adsp2100.mstat & MSTAT_REVERSE )
{
UINT32 ir = reverse_table[ i & 0x3fff ];
WWORD_DATA(ir, val);
WWORD_DATA_F(ir, val, fast);
}
else
WWORD_DATA(i, val);
WWORD_DATA_F(i, val, fast);
i += adsp2100.m[mreg];
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
adsp2100.i[ireg] = dag_step(i, adsp2100.m[mreg], base, l, fast & 2);
}
static INLINE UINT32 data_read_dag1(UINT32 op)
static INLINE ADSP_ALWAYS_INLINE UINT32 data_read_dag1_f(UINT32 op, int fast)
{
UINT32 ireg = (op >> 2) & 3;
UINT32 mreg = op & 3;
@@ -551,20 +602,17 @@ static INLINE UINT32 data_read_dag1(UINT32 op)
if (adsp2100.mstat & MSTAT_REVERSE)
{
UINT32 ir = reverse_table[i & 0x3fff];
res = RWORD_DATA(ir);
res = RWORD_DATA_F(ir, fast);
}
else
res = RWORD_DATA(i);
res = RWORD_DATA_F(i, fast);
i += adsp2100.m[mreg];
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
adsp2100.i[ireg] = dag_step(i, adsp2100.m[mreg], base, l, fast & 2);
return res;
}
static INLINE void data_write_dag2(UINT32 op, INT32 val)
static INLINE ADSP_ALWAYS_INLINE void data_write_dag2_f(UINT32 op, INT32 val, int fast)
{
UINT32 ireg = 4 + ((op >> 2) & 3);
UINT32 mreg = 4 + (op & 3);
@@ -572,16 +620,13 @@ static INLINE void data_write_dag2(UINT32 op, INT32 val)
UINT32 i = adsp2100.i[ireg];
UINT32 l = adsp2100.l[ireg];
WWORD_DATA(i, val);
WWORD_DATA_F(i, val, fast);
i += adsp2100.m[mreg];
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
adsp2100.i[ireg] = dag_step(i, adsp2100.m[mreg], base, l, fast & 2);
}
static INLINE UINT32 data_read_dag2(UINT32 op)
static INLINE ADSP_ALWAYS_INLINE UINT32 data_read_dag2_f(UINT32 op, int fast)
{
UINT32 ireg = 4 + ((op >> 2) & 3);
UINT32 mreg = 4 + (op & 3);
@@ -589,21 +634,25 @@ static INLINE UINT32 data_read_dag2(UINT32 op)
UINT32 i = adsp2100.i[ireg];
UINT32 l = adsp2100.l[ireg];
UINT32 res = RWORD_DATA(i);
UINT32 res = RWORD_DATA_F(i, fast);
i += adsp2100.m[mreg];
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
adsp2100.i[ireg] = dag_step(i, adsp2100.m[mreg], base, l, fast & 2);
return res;
}
/* the interpreter's accessors; 'fast': bit 0 for the recompiler (direct
pointers), bit 1 for the ADSP-2181 (14-bit index wrap) */
#define data_write_dag1(op, val) data_write_dag1_f(op, val, 0)
#define data_read_dag1(op) data_read_dag1_f(op, 0)
#define data_write_dag2(op, val) data_write_dag2_f(op, val, 0)
#define data_read_dag2(op) data_read_dag2_f(op, 0)
/*===========================================================================
Program memory accessors
===========================================================================*/
static INLINE void pgm_write_dag2(UINT32 op, INT32 val)
static INLINE ADSP_ALWAYS_INLINE void pgm_write_dag2(UINT32 op, INT32 val, int wrap14)
{
UINT32 ireg = 4 + ((op >> 2) & 3);
UINT32 mreg = 4 + (op & 3);
@@ -613,14 +662,11 @@ static INLINE void pgm_write_dag2(UINT32 op, INT32 val)
WWORD_PGM(i, (val << 8) | adsp2100.px);
i += adsp2100.m[mreg];
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
adsp2100.i[ireg] = dag_step(i, adsp2100.m[mreg], base, l, wrap14);
}
static INLINE UINT32 pgm_read_dag2(UINT32 op)
static INLINE ADSP_ALWAYS_INLINE UINT32 pgm_read_dag2(UINT32 op, int wrap14)
{
UINT32 ireg = 4 + ((op >> 2) & 3);
UINT32 mreg = 4 + (op & 3);
@@ -633,10 +679,7 @@ static INLINE UINT32 pgm_read_dag2(UINT32 op)
adsp2100.px = res;
res >>= 8;
i += adsp2100.m[mreg];
if (i < base) i += l;
else if (i >= base + l) i -= l;
adsp2100.i[ireg] = i;
adsp2100.i[ireg] = dag_step(i, adsp2100.m[mreg], base, l, wrap14);
return res;
}
@@ -1326,6 +1369,707 @@ void mac_op_mf(int op)
#if (HAS_ADSP2181)
/*===========================================================================
ADSP-2181 only: ALU with a constant as Y, ALU with no result (NONE =),
MAC with X as both operands (X * X); the operations above, with
the other operand
===========================================================================*/
static const INT32 alu_constants[32] =
{
0x0001, 0xfffe, 0x0002, 0xfffd, 0x0004, 0xfffb, 0x0008, 0xfff7,
0x0010, 0xffef, 0x0020, 0xffdf, 0x0040, 0xffbf, 0x0080, 0xff7f,
0x0100, 0xfeff, 0x0200, 0xfdff, 0x0400, 0xfbff, 0x0800, 0xf7ff,
0x1000, 0xefff, 0x2000, 0xdfff, 0x4000, 0xbfff, 0x8000, 0x7fff
};
static void alu_op_ar_const(int op)
{
INT32 xop = (op >> 8) & 7;
INT32 yop = alu_constants[((op >> 5) & 7) | (((op >> 11) & 3) << 3)];
INT32 res;
/*switch ((op >> 13) & 15)*/
switch (op & (15<<13)) /*JB*/
{
case 0x00<<13:
/* Y Clear when y = 0 */
res = yop;
CALC_NZ(res);
break;
case 0x01<<13:
/* Y + 1 PASS 1 when y = 0 */
res = yop + 1;
CALC_NZ(res);
if (yop == 0x7fff) SET_V;
else if (yop == 0xffff) SET_C;
break;
case 0x02<<13:
/* X + Y + C */
xop = ALU_GETXREG_UNSIGNED(xop);
yop += GET_C >> 3;
res = xop + yop;
CALC_NZVC(xop, yop, res);
break;
case 0x03<<13:
/* X + Y X when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop + yop;
CALC_NZVC(xop, yop, res);
break;
case 0x04<<13:
/* NOT Y */
res = yop ^ 0xffff;
CALC_NZ(res);
break;
case 0x05<<13:
/* -Y */
res = -yop;
CALC_NZ(res);
if (yop == 0x8000) SET_V;
if (yop == 0x0000) SET_C;
break;
case 0x06<<13:
/* X - Y + C - 1 X + C - 1 when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop - yop + (GET_C >> 3) - 1;
CALC_NZVC_SUB(xop, yop, res);
break;
case 0x07<<13:
/* X - Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop - yop;
CALC_NZVC_SUB(xop, yop, res);
break;
case 0x08<<13:
/* Y - 1 PASS -1 when y = 0 */
res = yop - 1;
CALC_NZ(res);
if (yop == 0x8000) SET_V;
else if (yop == 0x0000) SET_C;
break;
case 0x09<<13:
/* Y - X -X when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = yop - xop;
CALC_NZVC_SUB(yop, xop, res);
break;
case 0x0a<<13:
/* Y - X + C - 1 -X + C - 1 when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = yop - xop + (GET_C >> 3) - 1;
CALC_NZVC_SUB(yop, xop, res);
break;
case 0x0b<<13:
/* NOT X */
res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
CALC_NZ(res);
break;
case 0x0c<<13:
/* X AND Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop & yop;
CALC_NZ(res);
break;
case 0x0d<<13:
/* X OR Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop | yop;
CALC_NZ(res);
break;
case 0x0e<<13:
/* X XOR Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop ^ yop;
CALC_NZ(res);
break;
case 0x0f<<13:
/* ABS X */
xop = ALU_GETXREG_UNSIGNED(xop);
res = (xop & 0x8000) ? -xop : xop;
if (xop == 0) SET_Z;
if (xop == 0x8000) SET_N, SET_V;
CLR_S;
if (xop & 0x8000) SET_S;
break;
default:
res = 0; /* just to keep the compiler happy */
break;
}
/* saturate */
if ((adsp2100.mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767;
/* set the final value */
adsp2100.core.ar.u = res;
}
static void alu_op_af_const(int op)
{
INT32 xop = (op >> 8) & 7;
INT32 yop = alu_constants[((op >> 5) & 7) | (((op >> 11) & 3) << 3)];
INT32 res;
/* switch ((op >> 13) & 15)*/
switch (op & (15<<13)) /*JB*/
{
case 0x00<<13:
/* Y Clear when y = 0 */
res = yop;
CALC_NZ(res);
break;
case 0x01<<13:
/* Y + 1 PASS 1 when y = 0 */
res = yop + 1;
CALC_NZ(res);
if (yop == 0x7fff) SET_V;
else if (yop == 0xffff) SET_C;
break;
case 0x02<<13:
/* X + Y + C */
xop = ALU_GETXREG_UNSIGNED(xop);
yop += GET_C >> 3;
res = xop + yop;
CALC_NZVC(xop, yop, res);
break;
case 0x03<<13:
/* X + Y X when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop + yop;
CALC_NZVC(xop, yop, res);
break;
case 0x04<<13:
/* NOT Y */
res = yop ^ 0xffff;
CALC_NZ(res);
break;
case 0x05<<13:
/* -Y */
res = -yop;
CALC_NZ(res);
if (yop == 0x8000) SET_V;
if (yop == 0x0000) SET_C;
break;
case 0x06<<13:
/* X - Y + C - 1 X + C - 1 when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop - yop + (GET_C >> 3) - 1;
CALC_NZVC_SUB(xop, yop, res);
break;
case 0x07<<13:
/* X - Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop - yop;
CALC_NZVC_SUB(xop, yop, res);
break;
case 0x08<<13:
/* Y - 1 PASS -1 when y = 0 */
res = yop - 1;
CALC_NZ(res);
if (yop == 0x8000) SET_V;
else if (yop == 0x0000) SET_C;
break;
case 0x09<<13:
/* Y - X -X when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = yop - xop;
CALC_NZVC_SUB(yop, xop, res);
break;
case 0x0a<<13:
/* Y - X + C - 1 -X + C - 1 when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
res = yop - xop + (GET_C >> 3) - 1;
CALC_NZVC_SUB(yop, xop, res);
break;
case 0x0b<<13:
/* NOT X */
res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
CALC_NZ(res);
break;
case 0x0c<<13:
/* X AND Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop & yop;
CALC_NZ(res);
break;
case 0x0d<<13:
/* X OR Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop | yop;
CALC_NZ(res);
break;
case 0x0e<<13:
/* X XOR Y */
xop = ALU_GETXREG_UNSIGNED(xop);
res = xop ^ yop;
CALC_NZ(res);
break;
case 0x0f<<13:
/* ABS X */
xop = ALU_GETXREG_UNSIGNED(xop);
res = (xop & 0x8000) ? -xop : xop;
if (xop == 0) SET_Z;
if (xop == 0x8000) SET_N, SET_V;
CLR_S;
if (xop & 0x8000) SET_S;
break;
default:
res = 0; /* just to keep the compiler happy */
break;
}
/* set the final value */
adsp2100.core.af.u = res;
}
static void alu_op_none(int op)
{
INT32 xop = (op >> 8) & 7;
INT32 yop = (op >> 11) & 3;
INT32 res;
/*switch ((op >> 13) & 15)*/
switch (op & (15<<13)) /*JB*/
{
case 0x00<<13:
/* Y Clear when y = 0 */
res = ALU_GETYREG_UNSIGNED(yop);
CALC_NZ(res);
break;
case 0x01<<13:
/* Y + 1 PASS 1 when y = 0 */
yop = ALU_GETYREG_UNSIGNED(yop);
res = yop + 1;
CALC_NZ(res);
if (yop == 0x7fff) SET_V;
else if (yop == 0xffff) SET_C;
break;
case 0x02<<13:
/* X + Y + C */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
yop += GET_C >> 3;
res = xop + yop;
CALC_NZVC(xop, yop, res);
break;
case 0x03<<13:
/* X + Y X when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = xop + yop;
CALC_NZVC(xop, yop, res);
break;
case 0x04<<13:
/* NOT Y */
res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff;
CALC_NZ(res);
break;
case 0x05<<13:
/* -Y */
yop = ALU_GETYREG_UNSIGNED(yop);
res = -yop;
CALC_NZ(res);
if (yop == 0x8000) SET_V;
if (yop == 0x0000) SET_C;
break;
case 0x06<<13:
/* X - Y + C - 1 X + C - 1 when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = xop - yop + (GET_C >> 3) - 1;
CALC_NZVC_SUB(xop, yop, res);
break;
case 0x07<<13:
/* X - Y */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = xop - yop;
CALC_NZVC_SUB(xop, yop, res);
break;
case 0x08<<13:
/* Y - 1 PASS -1 when y = 0 */
yop = ALU_GETYREG_UNSIGNED(yop);
res = yop - 1;
CALC_NZ(res);
if (yop == 0x8000) SET_V;
else if (yop == 0x0000) SET_C;
break;
case 0x09<<13:
/* Y - X -X when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = yop - xop;
CALC_NZVC_SUB(yop, xop, res);
break;
case 0x0a<<13:
/* Y - X + C - 1 -X + C - 1 when y = 0 */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = yop - xop + (GET_C >> 3) - 1;
CALC_NZVC_SUB(yop, xop, res);
break;
case 0x0b<<13:
/* NOT X */
res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff;
CALC_NZ(res);
break;
case 0x0c<<13:
/* X AND Y */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = xop & yop;
CALC_NZ(res);
break;
case 0x0d<<13:
/* X OR Y */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = xop | yop;
CALC_NZ(res);
break;
case 0x0e<<13:
/* X XOR Y */
xop = ALU_GETXREG_UNSIGNED(xop);
yop = ALU_GETYREG_UNSIGNED(yop);
res = xop ^ yop;
CALC_NZ(res);
break;
case 0x0f<<13:
/* ABS X */
xop = ALU_GETXREG_UNSIGNED(xop);
res = (xop & 0x8000) ? -xop : xop;
if (xop == 0) SET_Z;
if (xop == 0x8000) SET_N, SET_V;
CLR_S;
if (xop & 0x8000) SET_S;
break;
default:
res = 0; /* just to keep the compiler happy */
break;
}
/* no result: only the flags */
(void)res;
}
static void mac_op_mr_xop(int op)
{
INT8 shift = ((adsp2100.mstat & MSTAT_INTEGER) >> 4) ^ 1;
INT32 xop = (op >> 8) & 7;
INT32 yop;
INT32 temp;
INT64 res;
/* switch ((op >> 13) & 15)*/
switch (op & (15<<13)) /*JB*/
{
case 0x00<<13:
/* no-op */
return;
case 0x01<<13:
/* X * Y (RND) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
#ifdef ADSP_TWEAK
if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
else res += (res & 0x8000) << 1;
#else
temp &= 0xffff;
res += 0x8000;
if ( temp == 0x8000 )
res &= ~((UINT64)0x10000);
#endif
break;
case 0x02<<13:
/* MR + X * Y (RND) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
#ifdef ADSP_TWEAK
if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
else res += (res & 0x8000) << 1;
#else
temp &= 0xffff;
res += 0x8000;
if ( temp == 0x8000 )
res &= ~((UINT64)0x10000);
#endif
break;
case 0x03<<13:
/* MR - X * Y (RND) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
#ifdef ADSP_TWEAK
if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
else res += (res & 0x8000) << 1;
#else
temp &= 0xffff;
res += 0x8000;
if ( temp == 0x8000 )
res &= ~((UINT64)0x10000);
#endif
break;
case 0x04<<13:
/* X * Y (SS) Clear when y = 0 */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x05<<13:
/* X * Y (SU) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x06<<13:
/* X * Y (US) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x07<<13:
/* X * Y (UU) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x08<<13:
/* MR + X * Y (SS) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x09<<13:
/* MR + X * Y (SU) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x0a<<13:
/* MR + X * Y (US) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x0b<<13:
/* MR + X * Y (UU) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x0c<<13:
/* MR - X * Y (SS) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
case 0x0d<<13:
/* MR - X * Y (SU) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
case 0x0e<<13:
/* MR - X * Y (US) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
case 0x0f<<13:
/* MR - X * Y (UU) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
default:
res = 0; /* just to keep the compiler happy */
break;
}
/* set the final value */
temp = (res >> 31) & 0x1ff;
CLR_MV;
if (temp != 0x000 && temp != 0x1ff) SET_MV;
adsp2100.core.mr.mr = res;
}
static void mac_op_mf_xop(int op)
{
INT8 shift = ((adsp2100.mstat & MSTAT_INTEGER) >> 4) ^ 1;
INT32 xop = (op >> 8) & 7;
INT32 yop;
INT32 temp;
INT64 res;
/* switch ((op >> 13) & 15)*/
switch (op & (15<<13)) /*JB*/
{
case 0x00<<13:
/* no-op */
return;
case 0x01<<13:
/* X * Y (RND) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
#ifdef ADSP_TWEAK
if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
else res += (res & 0x8000) << 1;
#else
temp &= 0xffff;
res += 0x8000;
if ( temp == 0x8000 )
res &= ~((UINT64)0x10000);
#endif
break;
case 0x02<<13:
/* MR + X * Y (RND) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
#ifdef ADSP_TWEAK
if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
else res += (res & 0x8000) << 1;
#else
temp &= 0xffff;
res += 0x8000;
if ( temp == 0x8000 )
res &= ~((UINT64)0x10000);
#endif
break;
case 0x03<<13:
/* MR - X * Y (RND) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
#ifdef ADSP_TWEAK
if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000);
else res += (res & 0x8000) << 1;
#else
temp &= 0xffff;
res += 0x8000;
if ( temp == 0x8000 )
res &= ~((UINT64)0x10000);
#endif
break;
case 0x04<<13:
/* X * Y (SS) Clear when y = 0 */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x05<<13:
/* X * Y (SU) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x06<<13:
/* X * Y (US) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x07<<13:
/* X * Y (UU) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = (INT64)temp;
break;
case 0x08<<13:
/* MR + X * Y (SS) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x09<<13:
/* MR + X * Y (SU) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x0a<<13:
/* MR + X * Y (US) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x0b<<13:
/* MR + X * Y (UU) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr + (INT64)temp;
break;
case 0x0c<<13:
/* MR - X * Y (SS) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
case 0x0d<<13:
/* MR - X * Y (SU) */
xop = MAC_GETXREG_SIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
case 0x0e<<13:
/* MR - X * Y (US) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
case 0x0f<<13:
/* MR - X * Y (UU) */
xop = MAC_GETXREG_UNSIGNED(xop);
yop = xop;
temp = (xop * yop) << shift;
res = adsp2100.core.mr.mr - (INT64)temp;
break;
default:
res = 0; /* just to keep the compiler happy */
break;
}
/* set the final value */
adsp2100.core.mf.u = (UINT32)res >> 16;
}
#endif
/*===========================================================================
SHIFT operations (result in SR/SE/SB)
===========================================================================*/
+1201 -686
View File
File diff suppressed because it is too large. Load diff
+59
View File
@@ -92,6 +92,13 @@ extern unsigned adsp2100_get_reg(int regnum);
extern void adsp2100_set_reg(int regnum, unsigned val);
extern void adsp2100_set_irq_line(int irqline, int state);
extern void adsp2100_set_irq_callback(int (*callback)(int irqline));
/* exact skip of one-instruction NOP delay loops: off unless a driver enables it */
extern void adsp2100_set_nop_loop_skip(int enable);
/* optional recompiler (adsp2100jit.c): off unless a driver enables it */
extern int adsp2100_jit_available(void);
extern void adsp2100_set_jit(int enable);
/* data memory words [start, end] read through a handler with no side effects */
extern void adsp2100_jit_pure_read(UINT32 start, UINT32 end);
extern const char *adsp2100_info(void *context, int regnum);
extern unsigned adsp2100_dasm(char *buffer, unsigned pc);
@@ -262,4 +269,56 @@ extern void adsp2115_set_tx_callback( TX_CALLBACK cb );
extern void adsp2115_load_boot_data(data8_t *srcdata, data32_t *dstdata);
#endif
#if (HAS_ADSP2181)
/**************************************************************************
* ADSP2181 section
*
* 16K words of program RAM and 16K words of data RAM on the chip: the
* driver maps them (program memory at ADSP2181_PGM_OFFSET, data memory
* at ADSP2181_DATA_OFFSET), with its control registers at 0x3fe0-0x3fff
* of data memory. The I/O space (IO(x) instructions) and the data memory
* overlay (DMOVLAY) go through the callbacks below
**************************************************************************/
#define ADSP2181_DATA_OFFSET ADSP2100_DATA_OFFSET
#define ADSP2181_PGM_OFFSET ADSP2100_PGM_OFFSET
#define ADSP2181_SIZE ADSP2100_SIZE
#define adsp2181_icount adsp2100_icount
#define ADSP2181_IRQ0 0 /* IRQ0 */
#define ADSP2181_SPORT1_RX 0 /* SPORT1 receive IRQ */
#define ADSP2181_IRQ1 1 /* IRQ1 */
#define ADSP2181_SPORT1_TX 1 /* SPORT1 transmit IRQ */
#define ADSP2181_IRQ2 2 /* IRQ2 */
#define ADSP2181_SPORT0_RX 3 /* SPORT0 receive IRQ */
#define ADSP2181_SPORT0_TX 4 /* SPORT0 transmit IRQ */
#define ADSP2181_TIMER 5 /* internal timer IRQ */
#define ADSP2181_IRQE 6 /* IRQE */
#define ADSP2181_BDMA 7 /* BDMA */
#define ADSP2181_IRQL1 8 /* IRQL1 */
#define ADSP2181_IRQL0 9 /* IRQL0 */
typedef UINT16 (*ADSP2181_IO_READ)( UINT32 offset );
typedef void (*ADSP2181_IO_WRITE)( UINT32 offset, UINT16 data );
typedef void (*ADSP2181_DMOVLAY)( UINT32 dmovlay );
extern void adsp2181_init(void);
extern void adsp2181_reset(void *param);
extern void adsp2181_exit(void);
extern int adsp2181_execute(int cycles);
extern unsigned adsp2181_get_context(void *dst);
extern void adsp2181_set_context(void *src);
extern unsigned adsp2181_get_reg(int regnum);
extern void adsp2181_set_reg(int regnum, unsigned val);
extern void adsp2181_set_irq_line(int irqline, int state);
extern void adsp2181_set_irq_callback(int (*callback)(int irqline));
extern const char *adsp2181_info(void *context, int regnum);
extern unsigned adsp2181_dasm(char *buffer, unsigned pc);
extern void adsp2181_set_rx_callback( RX_CALLBACK cb );
extern void adsp2181_set_tx_callback( TX_CALLBACK cb );
extern void adsp2181_set_io_callbacks( ADSP2181_IO_READ rd, ADSP2181_IO_WRITE wr );
extern void adsp2181_set_dmovlay_callback( ADSP2181_DMOVLAY cb );
#endif
#endif /* _ADSP2100_H */
File diff suppressed because it is too large. Load diff
+235
View File
@@ -0,0 +1,235 @@
/*****************************************************************************
*
* arm7.c
* Portable CPU Emulator for 32-bit ARM v3/4/5/6
*
* Copyright Steve Ellenoff, all rights reserved.
* Thumb, DSP, and MMU support and many bugfixes by R. Belmont and Ryan Holtz.
*
* - This source code is released as freeware for non-commercial purposes.
* - You are free to use and redistribute this code in modified or
* unmodified form, provided you list me in the credits.
* - If you modify this source code, you must add a notice to each modified
* source file that it has been changed. If you're a nice person, you
* will clearly mark each change too. :)
* - If you wish to use this for commercial purposes, please contact me at
* sellenoff@hotmail.com
* - The author of this copywritten work reserves the right to change the
* terms of its usage and license at any time, including retroactively
* - This entire notice must remain in the source code.
*
* This work is based on:
* #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
* #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
*
*****************************************************************************
mame2003-plus: modified. The core files (arm7core.c/h, arm7exec.c) are
those of MAME 0.139, with the memory accesses going through this
version's 32-bit little endian memory system (cpu_readmem32ledw...) and
the state in one static structure; this file is the cpu interface of
this version. ARMv4T (ARM7TDMI): no MMU, no coprocessors.
******************************************************************************/
#include "driver.h"
#include "state.h"
#include "arm7.h"
#include "arm7core.h"
#define LOG(x) logerror x
#define fatalerror logerror
#define ENDIANNESS_BIG 1
/* the memory handlers of the core (arm7core.c) */
#define READ8(addr) arm7_cpu_read8(cpustate, addr)
#define WRITE8(addr,data) arm7_cpu_write8(cpustate, addr,data)
#define READ16(addr) arm7_cpu_read16(cpustate, addr)
#define WRITE16(addr,data) arm7_cpu_write16(cpustate, addr,data)
#define READ32(addr) arm7_cpu_read32(cpustate, addr)
#define WRITE32(addr,data) arm7_cpu_write32(cpustate, addr,data)
#define PTR_READ32 &arm7_cpu_read32
#define PTR_WRITE32 &arm7_cpu_write32
#define ARM7REG(reg) cpustate->sArmRegister[reg]
#define ARM7_ICOUNT arm7_ICount
static arm_state arm7_state;
int arm7_ICount;
/* the core's inline functions are local to this file */
#undef INLINE
#if defined( _MSC_VER )
#define INLINE static __inline
#elif defined( __GNUC__ )
#define INLINE static __inline__
#else
#define INLINE static
#endif
/* ARMv5 helpers the core refers to (CLZ, QADD...): not reached on the ARMv4T */
INLINE UINT32 count_leading_zeros(UINT32 val)
{
UINT32 count = 0;
if (val == 0)
return 32;
while (!(val & 0x80000000))
{
count++;
val <<= 1;
}
return count;
}
INLINE INT64 saturate_qbit_overflow(arm_state *cpustate, INT64 res)
{
if (res > 2147483647) /* INT32_MAX */
{
res = 2147483647;
SET_CPSR(GET_CPSR | Q_MASK);
}
else if (res < (-2147483647-1)) /* INT32_MIN */
{
res = (-2147483647-1);
SET_CPSR(GET_CPSR | Q_MASK);
}
return res;
}
/* no MMU on the ARM7TDMI: the core only calls this when one is enabled */
INLINE UINT32 arm7_tlb_translate(arm_state *cpustate, UINT32 vaddr)
{
return vaddr;
}
#include "arm7core.c"
void arm7_init(void)
{
arm_state *cpustate = &arm7_state;
memset(cpustate, 0, sizeof(*cpustate));
cpustate->archRev = 4;
cpustate->archFlags = eARM_ARCHFLAGS_T;
arm7_core_init(cpustate, "arm7", cpu_getactivecpu());
}
void arm7_reset(void *param)
{
arm7_core_reset(&arm7_state);
}
void arm7_exit(void)
{
}
int arm7_execute(int cycles)
{
arm7_ICount = cycles;
#include "arm7exec.c"
return cycles - arm7_ICount;
}
unsigned arm7_get_context(void *dst)
{
if (dst)
memcpy(dst, &arm7_state, sizeof(arm7_state));
return sizeof(arm7_state);
}
void arm7_set_context(void *src)
{
if (src)
memcpy(&arm7_state, src, sizeof(arm7_state));
}
unsigned arm7_get_reg(int regnum)
{
arm_state *cpustate = &arm7_state;
switch (regnum)
{
case REG_PC:
case ARM7_PC: return R15;
case REG_SP: return GetRegister(cpustate, 13);
case REG_PREVIOUSPC: return 0;
case ARM7_CPSR: return GET_CPSR;
}
if (regnum >= ARM7_R0 && regnum <= ARM7_R15)
return GetRegister(cpustate, regnum - ARM7_R0);
return 0;
}
void arm7_set_reg(int regnum, unsigned val)
{
arm_state *cpustate = &arm7_state;
switch (regnum)
{
case REG_PC:
case ARM7_PC: R15 = val; return;
case REG_SP: SetRegister(cpustate, 13, val); return;
case ARM7_CPSR: SET_CPSR(val); return;
}
if (regnum >= ARM7_R0 && regnum <= ARM7_R15)
SetRegister(cpustate, regnum - ARM7_R0, val);
}
void arm7_set_irq_line(int irqline, int state)
{
arm7_core_set_irq_line(&arm7_state, irqline, state);
}
void arm7_set_irq_callback(int (*callback)(int irqline))
{
arm7_state.irq_callback = callback;
}
const char *arm7_info(void *context, int regnum)
{
static char buffer[16][64];
static int which = 0;
arm_state *cpustate = context ? (arm_state *)context : &arm7_state;
which = (which + 1) % 16;
buffer[which][0] = '\0';
if (regnum >= CPU_INFO_REG + ARM7_R0 && regnum <= CPU_INFO_REG + ARM7_R15)
{
sprintf(buffer[which], "R%-3d:%08x", regnum - CPU_INFO_REG - ARM7_R0, GetRegister(cpustate, regnum - CPU_INFO_REG - ARM7_R0));
return buffer[which];
}
switch (regnum)
{
case CPU_INFO_REG + ARM7_PC: sprintf(buffer[which], "PC :%08x", R15); break;
case CPU_INFO_REG + ARM7_CPSR: sprintf(buffer[which], "CPSR:%08x", GET_CPSR); break;
case CPU_INFO_FLAGS:
sprintf(buffer[which], "%c%c%c%c%c%c%c %s",
(GET_CPSR & N_MASK) ? 'N' : '-',
(GET_CPSR & Z_MASK) ? 'Z' : '-',
(GET_CPSR & C_MASK) ? 'C' : '-',
(GET_CPSR & V_MASK) ? 'V' : '-',
(GET_CPSR & I_MASK) ? 'I' : '-',
(GET_CPSR & F_MASK) ? 'F' : '-',
(GET_CPSR & T_MASK) ? 'T' : '-',
GetModeText(GET_CPSR));
break;
case CPU_INFO_NAME: return "ARM7";
case CPU_INFO_FAMILY: return "Acorn Risc Machine";
case CPU_INFO_VERSION: return "2.0 (MAME 0.139 core)";
case CPU_INFO_FILE: return __FILE__;
case CPU_INFO_CREDITS: return "Copyright Steve Ellenoff, [email protected]";
}
return buffer[which];
}
unsigned arm7_dasm(char *buffer, unsigned pc)
{
if (T_IS_SET(arm7_state.sArmRegister[eCPSR]))
{
sprintf(buffer, "$%04x", cpu_readmem32ledw_word(pc & ~1));
return 2;
}
sprintf(buffer, "$%08x", cpu_readmem32ledw_dword(pc & ~3));
return 4;
}
+43
View File
@@ -0,0 +1,43 @@
/*****************************************************************************
*
* arm7.h
* Portable ARM7TDMI CPU Emulator
*
* Copyright Steve Ellenoff, all rights reserved.
* Thumb, DSP, and MMU support and many bugfixes by R. Belmont and Ryan Holtz.
* (see arm7core.c for the full notice)
*
* mame2003-plus: the MAME 0.139 core with the cpu interface of this
* version (one ARM7 at a time, 32-bit little endian bus).
*
*****************************************************************************/
#ifndef ARM7_H
#define ARM7_H
#include "driver.h"
/* interrupt lines and exceptions */
#define ARM7_IRQ_LINE 0
#define ARM7_FIRQ_LINE 1
#define ARM7_ABORT_EXCEPTION 2
#define ARM7_ABORT_PREFETCH_EXCEPTION 3
#define ARM7_UNDEFINE_EXCEPTION 4
extern int arm7_ICount;
extern void arm7_init(void);
extern void arm7_reset(void *param);
extern void arm7_exit(void);
extern int arm7_execute(int cycles);
extern unsigned arm7_get_context(void *dst);
extern void arm7_set_context(void *src);
extern unsigned arm7_get_reg(int regnum);
extern void arm7_set_reg(int regnum, unsigned val);
extern void arm7_set_irq_line(int irqline, int state);
extern void arm7_set_irq_callback(int (*callback)(int irqline));
extern const char *arm7_info(void *context, int regnum);
extern unsigned arm7_dasm(char *buffer, unsigned pc);
#endif /* ARM7_H */
File diff suppressed because it is too large. Load diff
+488
View File
@@ -0,0 +1,488 @@
/*****************************************************************************
*
* arm7core.h
* Portable ARM7TDMI Core Emulator
*
* Copyright Steve Ellenoff, all rights reserved.
*
* - This source code is released as freeware for non-commercial purposes.
* - You are free to use and redistribute this code in modified or
* unmodified form, provided you list me in the credits.
* - If you modify this source code, you must add a notice to each modified
* source file that it has been changed. If you're a nice person, you
* will clearly mark each change too. :)
* - If you wish to use this for commercial purposes, please contact me at
* sellenoff@hotmail.com
* - The author of this copywritten work reserves the right to change the
* terms of its usage and license at any time, including retroactively
* - This entire notice must remain in the source code.
*
* This work is based on:
* #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
* #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
*
*****************************************************************************
This file contains everything related to the arm7 core itself, and is presumed
to be cpu implementation non-specific, ie, applies to only the core.
******************************************************************************/
#ifndef __ARM7CORE_H__
#define __ARM7CORE_H__
/****************************************************************************************************
* INTERRUPT LINES/EXCEPTIONS
***************************************************************************************************/
/* ARM7_IRQ_LINE .. ARM7_UNDEFINE_EXCEPTION: in arm7.h */
#define ARM7_NUM_LINES 5
/* Really there's only 1 ABORT Line.. and cpu decides whether it's during data fetch or prefetch, but we let the user specify */
/****************************************************************************************************
* ARM7 CORE REGISTERS
***************************************************************************************************/
enum
{
ARM7_PC = 0,
ARM7_R0, ARM7_R1, ARM7_R2, ARM7_R3, ARM7_R4, ARM7_R5, ARM7_R6, ARM7_R7,
ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15,
ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14,
ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR,
ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR
};
/* There are 36 Unique - 32 bit processor registers */
/* Each mode has 17 registers (except user & system, which have 16) */
/* This is a list of each *unique* register */
enum
{
/* All modes have the following */
eR0 = 0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13, /* Stack Pointer */
eR14, /* Link Register (holds return address) */
eR15, /* Program Counter */
eCPSR, /* Current Status Program Register */
/* Fast Interrupt - Bank switched registers */
eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, eR13_FIQ, eR14_FIQ, eSPSR_FIQ,
/* IRQ - Bank switched registers */
eR13_IRQ, eR14_IRQ, eSPSR_IRQ,
/* Supervisor/Service Mode - Bank switched registers */
eR13_SVC, eR14_SVC, eSPSR_SVC,
/* Abort Mode - Bank switched registers */
eR13_ABT, eR14_ABT, eSPSR_ABT,
/* Undefined Mode - Bank switched registers */
eR13_UND, eR14_UND, eSPSR_UND,
kNumRegisters
};
/* Coprocessor-related macros */
#define COPRO_TLB_BASE cpustate->tlbBase
#define COPRO_TLB_BASE_MASK 0xffffc000
#define COPRO_TLB_VADDR_FLTI_MASK 0xfff00000
#define COPRO_TLB_VADDR_FLTI_MASK_SHIFT 18
#define COPRO_TLB_VADDR_CSLTI_MASK 0x000ff000
#define COPRO_TLB_VADDR_CSLTI_MASK_SHIFT 10
#define COPRO_TLB_VADDR_FSLTI_MASK 0x000ffc00
#define COPRO_TLB_VADDR_FSLTI_MASK_SHIFT 8
#define COPRO_TLB_CFLD_ADDR_MASK 0xfffffc00
#define COPRO_TLB_CFLD_ADDR_MASK_SHIFT 10
#define COPRO_TLB_SECTION_PAGE_MASK 0xfff00000
#define COPRO_TLB_LARGE_PAGE_MASK 0xffff0000
#define COPRO_TLB_SMALL_PAGE_MASK 0xfffff000
#define COPRO_TLB_TINY_PAGE_MASK 0xfffffc00
#define COPRO_TLB_UNMAPPED 0
#define COPRO_TLB_LARGE_PAGE 1
#define COPRO_TLB_SMALL_PAGE 2
#define COPRO_TLB_TINY_PAGE 3
#define COPRO_TLB_COARSE_TABLE 1
#define COPRO_TLB_SECTION_TABLE 2
#define COPRO_TLB_FINE_TABLE 3
#define COPRO_CTRL cpustate->control
#define COPRO_CTRL_MMU_EN 0x00000001
#define COPRO_CTRL_ADDRFAULT_EN 0x00000002
#define COPRO_CTRL_DCACHE_EN 0x00000004
#define COPRO_CTRL_WRITEBUF_EN 0x00000008
#define COPRO_CTRL_ENDIAN 0x00000080
#define COPRO_CTRL_SYSTEM 0x00000100
#define COPRO_CTRL_ROM 0x00000200
#define COPRO_CTRL_ICACHE_EN 0x00001000
#define COPRO_CTRL_INTVEC_ADJUST 0x00002000
#define COPRO_CTRL_ADDRFAULT_EN_SHIFT 1
#define COPRO_CTRL_DCACHE_EN_SHIFT 2
#define COPRO_CTRL_WRITEBUF_EN_SHIFT 3
#define COPRO_CTRL_ENDIAN_SHIFT 7
#define COPRO_CTRL_SYSTEM_SHIFT 8
#define COPRO_CTRL_ROM_SHIFT 9
#define COPRO_CTRL_ICACHE_EN_SHIFT 12
#define COPRO_CTRL_INTVEC_ADJUST_SHIFT 13
#define COPRO_CTRL_LITTLE_ENDIAN 0
#define COPRO_CTRL_BIG_ENDIAN 1
#define COPRO_CTRL_INTVEC_0 0
#define COPRO_CTRL_INTVEC_F 1
#define COPRO_CTRL_MASK 0x0000338f
/* Coprocessor Registers */
#define ARM7COPRO_REGS \
UINT32 control; \
UINT32 tlbBase;
enum
{
eARM_ARCHFLAGS_T = 1, /* Thumb present */
eARM_ARCHFLAGS_E = 2, /* extended DSP operations present (only for v5+) */
eARM_ARCHFLAGS_J = 4, /* "Jazelle" (direct execution of Java bytecode) */
eARM_ARCHFLAGS_MMU = 8, /* has on-board MMU (traditional ARM style like the SA1110) */
eARM_ARCHFLAGS_SA = 16, /* StrongARM extensions (enhanced TLB) */
eARM_ARCHFLAGS_XSCALE = 32 /* XScale extensions (CP14, enhanced TLB) */
};
#define ARM7CORE_REGS \
UINT32 sArmRegister[kNumRegisters]; \
UINT8 pendingIrq; \
UINT8 pendingFiq; \
UINT8 pendingAbtD; \
UINT8 pendingAbtP; \
UINT8 pendingUnd; \
UINT8 pendingSwi; \
INT32 iCount; \
int endian; \
int (*irq_callback)(int irqline);
/* CPU state struct */
typedef struct
{
ARM7CORE_REGS /* these must be included in your cpu specific register implementation */
ARM7COPRO_REGS
UINT8 archRev; /* ARM architecture revision (3, 4, and 5 are valid) */
UINT8 archFlags; /* architecture flags */
} arm_state;
/****************************************************************************************************
* VARIOUS INTERNAL STRUCS/DEFINES/ETC..
***************************************************************************************************/
/* Mode values come from bit 4-0 of CPSR, but we are ignoring bit 4 here, since bit 4 always = 1 for valid modes */
enum
{
eARM7_MODE_USER = 0x0, /* Bit: 4-0 = 10000 */
eARM7_MODE_FIQ = 0x1, /* Bit: 4-0 = 10001 */
eARM7_MODE_IRQ = 0x2, /* Bit: 4-0 = 10010 */
eARM7_MODE_SVC = 0x3, /* Bit: 4-0 = 10011 */
eARM7_MODE_ABT = 0x7, /* Bit: 4-0 = 10111 */
eARM7_MODE_UND = 0xb, /* Bit: 4-0 = 11011 */
eARM7_MODE_SYS = 0xf /* Bit: 4-0 = 11111 */
};
#define ARM7_NUM_MODES 0x10
static const int thumbCycles[256] =
{
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 4 */
2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 5 */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 6 */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 7 */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 8 */
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* 9 */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* a */
1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, /* b */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* d */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* e */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 /* f */
};
/* 17 processor registers are visible at any given time,
* banked depending on processor mode.
*/
static const int sRegisterTable[ARM7_NUM_MODES][18] =
{
{ /* USR */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13, eR14,
eR15, eCPSR /* No SPSR in this mode */
},
{ /* FIQ */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ,
eR13_FIQ, eR14_FIQ,
eR15, eCPSR, eSPSR_FIQ
},
{ /* IRQ */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13_IRQ, eR14_IRQ,
eR15, eCPSR, eSPSR_IRQ
},
{ /* SVC */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13_SVC, eR14_SVC,
eR15, eCPSR, eSPSR_SVC
},
{0}, {0}, {0}, /* values for modes 4,5,6 are not valid */
{ /* ABT */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13_ABT, eR14_ABT,
eR15, eCPSR, eSPSR_ABT
},
{0}, {0}, {0}, /* values for modes 8,9,a are not valid! */
{ /* UND */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13_UND, eR14_UND,
eR15, eCPSR, eSPSR_UND
},
{0}, {0}, {0}, /* values for modes c,d, e are not valid! */
{ /* SYS */
eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
eR8, eR9, eR10, eR11, eR12,
eR13, eR14,
eR15, eCPSR /* No SPSR in this mode */
}
};
#define N_BIT 31
#define Z_BIT 30
#define C_BIT 29
#define V_BIT 28
#define Q_BIT 27
#define I_BIT 7
#define F_BIT 6
#define T_BIT 5 /* Thumb mode */
#define N_MASK ((UINT32)(1 << N_BIT)) /* Negative flag */
#define Z_MASK ((UINT32)(1 << Z_BIT)) /* Zero flag */
#define C_MASK ((UINT32)(1 << C_BIT)) /* Carry flag */
#define V_MASK ((UINT32)(1 << V_BIT)) /* oVerflow flag */
#define Q_MASK ((UINT32)(1 << Q_BIT)) /* signed overflow for QADD, MAC */
#define I_MASK ((UINT32)(1 << I_BIT)) /* Interrupt request disable */
#define F_MASK ((UINT32)(1 << F_BIT)) /* Fast interrupt request disable */
#define T_MASK ((UINT32)(1 << T_BIT)) /* Thumb Mode flag */
#define N_IS_SET(pc) ((pc) & N_MASK)
#define Z_IS_SET(pc) ((pc) & Z_MASK)
#define C_IS_SET(pc) ((pc) & C_MASK)
#define V_IS_SET(pc) ((pc) & V_MASK)
#define Q_IS_SET(pc) ((pc) & Q_MASK)
#define I_IS_SET(pc) ((pc) & I_MASK)
#define F_IS_SET(pc) ((pc) & F_MASK)
#define T_IS_SET(pc) ((pc) & T_MASK)
#define N_IS_CLEAR(pc) (!N_IS_SET(pc))
#define Z_IS_CLEAR(pc) (!Z_IS_SET(pc))
#define C_IS_CLEAR(pc) (!C_IS_SET(pc))
#define V_IS_CLEAR(pc) (!V_IS_SET(pc))
#define Q_IS_CLEAR(pc) (!Q_IS_SET(pc))
#define I_IS_CLEAR(pc) (!I_IS_SET(pc))
#define F_IS_CLEAR(pc) (!F_IS_SET(pc))
#define T_IS_CLEAR(pc) (!T_IS_SET(pc))
/* Deconstructing an instruction */
/* todo: use these in all places (including dasm file) */
#define INSN_COND ((UINT32)0xf0000000u)
#define INSN_SDT_L ((UINT32)0x00100000u)
#define INSN_SDT_W ((UINT32)0x00200000u)
#define INSN_SDT_B ((UINT32)0x00400000u)
#define INSN_SDT_U ((UINT32)0x00800000u)
#define INSN_SDT_P ((UINT32)0x01000000u)
#define INSN_BDT_L ((UINT32)0x00100000u)
#define INSN_BDT_W ((UINT32)0x00200000u)
#define INSN_BDT_S ((UINT32)0x00400000u)
#define INSN_BDT_U ((UINT32)0x00800000u)
#define INSN_BDT_P ((UINT32)0x01000000u)
#define INSN_BDT_REGS ((UINT32)0x0000ffffu)
#define INSN_SDT_IMM ((UINT32)0x00000fffu)
#define INSN_MUL_A ((UINT32)0x00200000u)
#define INSN_MUL_RM ((UINT32)0x0000000fu)
#define INSN_MUL_RS ((UINT32)0x00000f00u)
#define INSN_MUL_RN ((UINT32)0x0000f000u)
#define INSN_MUL_RD ((UINT32)0x000f0000u)
#define INSN_I ((UINT32)0x02000000u)
#define INSN_OPCODE ((UINT32)0x01e00000u)
#define INSN_S ((UINT32)0x00100000u)
#define INSN_BL ((UINT32)0x01000000u)
#define INSN_BRANCH ((UINT32)0x00ffffffu)
#define INSN_SWI ((UINT32)0x00ffffffu)
#define INSN_RN ((UINT32)0x000f0000u)
#define INSN_RD ((UINT32)0x0000f000u)
#define INSN_OP2 ((UINT32)0x00000fffu)
#define INSN_OP2_SHIFT ((UINT32)0x00000f80u)
#define INSN_OP2_SHIFT_TYPE ((UINT32)0x00000070u)
#define INSN_OP2_RM ((UINT32)0x0000000fu)
#define INSN_OP2_ROTATE ((UINT32)0x00000f00u)
#define INSN_OP2_IMM ((UINT32)0x000000ffu)
#define INSN_OP2_SHIFT_TYPE_SHIFT 4
#define INSN_OP2_SHIFT_SHIFT 7
#define INSN_OP2_ROTATE_SHIFT 8
#define INSN_MUL_RS_SHIFT 8
#define INSN_MUL_RN_SHIFT 12
#define INSN_MUL_RD_SHIFT 16
#define INSN_OPCODE_SHIFT 21
#define INSN_RN_SHIFT 16
#define INSN_RD_SHIFT 12
#define INSN_COND_SHIFT 28
#define INSN_COPRO_N ((UINT32) 0x00100000u)
#define INSN_COPRO_CREG ((UINT32) 0x000f0000u)
#define INSN_COPRO_AREG ((UINT32) 0x0000f000u)
#define INSN_COPRO_CPNUM ((UINT32) 0x00000f00u)
#define INSN_COPRO_OP2 ((UINT32) 0x000000e0u)
#define INSN_COPRO_OP3 ((UINT32) 0x0000000fu)
#define INSN_COPRO_N_SHIFT 20
#define INSN_COPRO_CREG_SHIFT 16
#define INSN_COPRO_AREG_SHIFT 12
#define INSN_COPRO_CPNUM_SHIFT 8
#define INSN_COPRO_OP2_SHIFT 5
#define THUMB_INSN_TYPE ((UINT16)0xf000)
#define THUMB_COND_TYPE ((UINT16)0x0f00)
#define THUMB_GROUP4_TYPE ((UINT16)0x0c00)
#define THUMB_GROUP5_TYPE ((UINT16)0x0e00)
#define THUMB_GROUP5_RM ((UINT16)0x01c0)
#define THUMB_GROUP5_RN ((UINT16)0x0038)
#define THUMB_GROUP5_RD ((UINT16)0x0007)
#define THUMB_ADDSUB_RNIMM ((UINT16)0x01c0)
#define THUMB_ADDSUB_RS ((UINT16)0x0038)
#define THUMB_ADDSUB_RD ((UINT16)0x0007)
#define THUMB_INSN_ADDSUB ((UINT16)0x0800)
#define THUMB_INSN_CMP ((UINT16)0x0800)
#define THUMB_INSN_SUB ((UINT16)0x0800)
#define THUMB_INSN_IMM_RD ((UINT16)0x0700)
#define THUMB_INSN_IMM_S ((UINT16)0x0080)
#define THUMB_INSN_IMM ((UINT16)0x00ff)
#define THUMB_ADDSUB_TYPE ((UINT16)0x0600)
#define THUMB_HIREG_OP ((UINT16)0x0300)
#define THUMB_HIREG_H ((UINT16)0x00c0)
#define THUMB_HIREG_RS ((UINT16)0x0038)
#define THUMB_HIREG_RD ((UINT16)0x0007)
#define THUMB_STACKOP_TYPE ((UINT16)0x0f00)
#define THUMB_STACKOP_L ((UINT16)0x0800)
#define THUMB_STACKOP_RD ((UINT16)0x0700)
#define THUMB_ALUOP_TYPE ((UINT16)0x03c0)
#define THUMB_BLOP_LO ((UINT16)0x0800)
#define THUMB_BLOP_OFFS ((UINT16)0x07ff)
#define THUMB_SHIFT_R ((UINT16)0x0800)
#define THUMB_SHIFT_AMT ((UINT16)0x07c0)
#define THUMB_HALFOP_L ((UINT16)0x0800)
#define THUMB_HALFOP_OFFS ((UINT16)0x07c0)
#define THUMB_BRANCH_OFFS ((UINT16)0x07ff)
#define THUMB_LSOP_L ((UINT16)0x0800)
#define THUMB_LSOP_OFFS ((UINT16)0x07c0)
#define THUMB_MULTLS ((UINT16)0x0800)
#define THUMB_MULTLS_BASE ((UINT16)0x0700)
#define THUMB_RELADDR_SP ((UINT16)0x0800)
#define THUMB_RELADDR_RD ((UINT16)0x0700)
#define THUMB_INSN_TYPE_SHIFT 12
#define THUMB_COND_TYPE_SHIFT 8
#define THUMB_GROUP4_TYPE_SHIFT 10
#define THUMB_GROUP5_TYPE_SHIFT 9
#define THUMB_ADDSUB_TYPE_SHIFT 9
#define THUMB_INSN_IMM_RD_SHIFT 8
#define THUMB_STACKOP_TYPE_SHIFT 8
#define THUMB_HIREG_OP_SHIFT 8
#define THUMB_STACKOP_RD_SHIFT 8
#define THUMB_MULTLS_BASE_SHIFT 8
#define THUMB_RELADDR_RD_SHIFT 8
#define THUMB_HIREG_H_SHIFT 6
#define THUMB_HIREG_RS_SHIFT 3
#define THUMB_ALUOP_TYPE_SHIFT 6
#define THUMB_SHIFT_AMT_SHIFT 6
#define THUMB_HALFOP_OFFS_SHIFT 6
#define THUMB_LSOP_OFFS_SHIFT 6
#define THUMB_GROUP5_RM_SHIFT 6
#define THUMB_GROUP5_RN_SHIFT 3
#define THUMB_GROUP5_RD_SHIFT 0
#define THUMB_ADDSUB_RNIMM_SHIFT 6
#define THUMB_ADDSUB_RS_SHIFT 3
#define THUMB_ADDSUB_RD_SHIFT 0
enum
{
OPCODE_AND, /* 0000 */
OPCODE_EOR, /* 0001 */
OPCODE_SUB, /* 0010 */
OPCODE_RSB, /* 0011 */
OPCODE_ADD, /* 0100 */
OPCODE_ADC, /* 0101 */
OPCODE_SBC, /* 0110 */
OPCODE_RSC, /* 0111 */
OPCODE_TST, /* 1000 */
OPCODE_TEQ, /* 1001 */
OPCODE_CMP, /* 1010 */
OPCODE_CMN, /* 1011 */
OPCODE_ORR, /* 1100 */
OPCODE_MOV, /* 1101 */
OPCODE_BIC, /* 1110 */
OPCODE_MVN /* 1111 */
};
enum
{
COND_EQ = 0, /* Z equal */
COND_NE, /* ~Z not equal */
COND_CS, COND_HS = 2, /* C unsigned higher or same */
COND_CC, COND_LO = 3, /* ~C unsigned lower */
COND_MI, /* N negative */
COND_PL, /* ~N positive or zero */
COND_VS, /* V overflow */
COND_VC, /* ~V no overflow */
COND_HI, /* C && ~Z unsigned higher */
COND_LS, /* ~C || Z unsigned lower or same */
COND_GE, /* N == V greater or equal */
COND_LT, /* N != V less than */
COND_GT, /* ~Z && N == V greater than */
COND_LE, /* Z || N != V less than or equal */
COND_AL, /* 1 always */
COND_NV /* 0 never */
};
#define LSL(v, s) ((v) << (s))
#define LSR(v, s) ((v) >> (s))
#define ROL(v, s) (LSL((v), (s)) | (LSR((v), 32u - (s))))
#define ROR(v, s) (LSR((v), (s)) | (LSL((v), 32u - (s))))
/* Convenience Macros */
#define R15 ARM7REG(eR15)
#define SPSR 17 /* SPSR is always the 18th register in our 0 based array sRegisterTable[][18] */
#define GET_CPSR ARM7REG(eCPSR)
#define SET_CPSR(v) (GET_CPSR = (v))
#define MODE_FLAG 0xF /* Mode bits are 4:0 of CPSR, but we ignore bit 4. */
#define GET_MODE (GET_CPSR & MODE_FLAG)
#define SIGN_BIT ((UINT32)(1 << 31))
#define SIGN_BITS_DIFFER(a, b) (((a) ^ (b)) >> 31)
/* I really don't know why these were set to 16-bit, the thumb registers are still 32-bit ... */
#define THUMB_SIGN_BIT ((UINT32)(1 << 31))
#define THUMB_SIGN_BITS_DIFFER(a, b) (((a)^(b)) >> 31)
/* At one point I thought these needed to be cpu implementation specific, but they don't.. */
#define GET_REGISTER(state, reg) GetRegister(state, reg)
#define SET_REGISTER(state, reg, val) SetRegister(state, reg, val)
#define ARM7_CHECKIRQ arm7_check_irq_state(cpustate)
#ifdef UNUSED_DEFINITION
extern char *(*arm7_dasm_cop_dt_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
extern char *(*arm7_dasm_cop_rt_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
extern char *(*arm7_dasm_cop_do_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
#endif
#endif /* __ARM7CORE_H__ */
File diff suppressed because it is too large. Load diff
+26
View File
@@ -60,6 +60,7 @@
#include "memory.h"
#include "cpuintrf.h"
#include "state.h"
#include "mamedbg.h"
#include "h6280.h"
@@ -138,6 +139,31 @@ UINT8 H6280_debug_mmr[8];
/*****************************************************************************/
void h6280_init(void)
{
int cpu = cpu_getactivecpu();
state_save_register_UINT32("h6280", cpu, "PPC", &h6280.ppc.d, 1);
state_save_register_UINT32("h6280", cpu, "PC", &h6280.pc.d, 1);
state_save_register_UINT32("h6280", cpu, "SP", &h6280.sp.d, 1);
state_save_register_UINT32("h6280", cpu, "ZP", &h6280.zp.d, 1);
state_save_register_UINT32("h6280", cpu, "EA", &h6280.ea.d, 1);
state_save_register_UINT8("h6280", cpu, "A", &h6280.a, 1);
state_save_register_UINT8("h6280", cpu, "X", &h6280.x, 1);
state_save_register_UINT8("h6280", cpu, "Y", &h6280.y, 1);
state_save_register_UINT8("h6280", cpu, "P", &h6280.p, 1);
state_save_register_UINT8("h6280", cpu, "MMR", h6280.mmr, 8);
state_save_register_UINT8("h6280", cpu, "IRQ_MASK", &h6280.irq_mask, 1);
state_save_register_UINT8("h6280", cpu, "TIMER_STATUS", &h6280.timer_status, 1);
state_save_register_UINT8("h6280", cpu, "TIMER_ACK", &h6280.timer_ack, 1);
state_save_register_int("h6280", cpu, "TIMER_VALUE", &h6280.timer_value);
state_save_register_int("h6280", cpu, "TIMER_LOAD", &h6280.timer_load);
state_save_register_int("h6280", cpu, "EXTRA_CYCLES", &h6280.extra_cycles);
state_save_register_int("h6280", cpu, "NMI_STATE", &h6280.nmi_state);
state_save_register_int("h6280", cpu, "IRQ1_STATE", &h6280.irq_state[0]);
state_save_register_int("h6280", cpu, "IRQ2_STATE", &h6280.irq_state[1]);
state_save_register_int("h6280", cpu, "IRQT_STATE", &h6280.irq_state[2]);
#if LAZY_FLAGS
state_save_register_int("h6280", cpu, "NZ", &h6280.NZ);
#endif
}
void h6280_reset(void *param)
+930
View File
@@ -0,0 +1,930 @@
/***************************************************************************
h83002.c: Hitachi H8/3002 microcontroller emulator
Original by The_Author & DynaChicken for the ZiNc emulator.
MAME changes by R. Belmont, Luca Elia, and Tomasz Slanina.
TS 20060412 Added exts.l, sub.l, divxs.w (buggy), jsr @reg, rotxl.l reg, mov.l @(adr, reg), reg
LE 20070903 Added divxu.b shal.l extu.w dec.l #Imm,Rd subx.b
LE 20080202 Separated 3002/3044/3007, Added or.l shal.l rotl.l not.l neg.l exts.w
sub/or/xor.l #Imm:32,ERd bset/bnot/bclr.b Rn,@ERd bst/bist.b #Imm:3,@ERd bnot.b #Imm:3,@ERd
LE 20090128 Added mov.l ers,@aa:16; bild #xx:3,rd; eepmov.b; bnot #xx:3,@aa:8
mame2003-plus: backported from the legacy H8/3xx core of MAME 0.152
(h8_16.c, h8ops.h, h8periph.c) to the MAME 0.78 CPU interface.
Only the H8/3002 model is kept. The on-chip RAM and peripheral
registers are handled inside the core, the on-chip I/O ports are
routed to the driver through h8_3002_set_io_handlers().
This core keeps a single global context: get/set_context are no-ops,
so only one H8/3002 can exist in a machine (System 12 uses one).
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include "cpuintrf.h"
#include "memory.h"
#include "mamedbg.h"
#include "state.h"
#include "timer.h"
#include "mame.h"
#include "driver.h"
#include "h83002.h"
/* H8_LOG((fmt, ...)): debug log, compiled out */
#define H8_LOG(x) do { } while (0)
#define H8_SP (7)
/* on-chip resources of the H8/3002 */
#define H8_IRAM_START 0xfffd10
#define H8_IRAM_END 0xffff0f
#define H8_REG_START 0xffff10
typedef struct
{
/* main CPU stuff */
UINT32 h8err;
UINT32 regs[8];
UINT32 pc, ppc;
UINT32 irq_req[3];
UINT8 ccr, exr;
UINT8 h8nflag, h8vflag, h8cflag, h8zflag, h8iflag, h8hflag;
UINT8 h8uflag, h8uiflag;
UINT8 incheckirqs;
UINT8 has_exr;
int mode_8bit;
int (*irq_cb)(int irqline);
/* onboard peripherals stuff */
UINT8 per_regs[0x100];
UINT8 iram[H8_IRAM_END - H8_IRAM_START + 1];
UINT16 h8TCNT[5];
UINT8 h8TSTR;
mame_timer *timer[5];
int timer_running[5]; /* timer[] armed (not TIME_NEVER / disabled) */
UINT16 tcnt_start[5]; /* TCNT when the timer was last armed */
double tcnt_offset[5]; /* time counted before the timer was last armed by a state load */
double save_left[5], save_elapsed[5]; /* saved timer state (time left < 0: not armed) */
int clock;
} h83xx_state;
static h83xx_state h8state;
/* cycles left in the timeslice: cpuexec reads and adjusts it (abort,
cycles run), so the core counts down this very variable */
int h8_3002_ICount;
static h8_io_read_func h8_io_read = NULL;
static h8_io_write_func h8_io_write = NULL;
void h8_3002_set_io_handlers(h8_io_read_func readfn, h8_io_write_func writefn)
{
h8_io_read = readfn;
h8_io_write = writefn;
}
static data8_t h8_io_read_byte(int port)
{
return h8_io_read ? h8_io_read(port) : 0;
}
static void h8_io_write_byte(int port, data8_t data)
{
if (h8_io_write)
h8_io_write(port, data);
}
static UINT8 h8_register_read8(h83xx_state *h8, UINT32 address);
static void h8_register_write8(h83xx_state *h8, UINT32 address, UINT8 val);
void h8_3002_InterruptRequest(h83xx_state *h8, UINT8 source, UINT8 state);
/***************************************************************************
memory access (external bus via the 0.78 memory system, on-chip
RAM/registers handled here)
***************************************************************************/
static UINT8 h8_read8(h83xx_state *h8, UINT32 address)
{
address &= 0xffffff;
if (address >= H8_IRAM_START)
{
if (address <= H8_IRAM_END)
return h8->iram[address - H8_IRAM_START];
return h8_register_read8(h8, address);
}
return cpu_readmem24bew(address);
}
static void h8_write8(h83xx_state *h8, UINT32 address, UINT8 data)
{
address &= 0xffffff;
if (address >= H8_IRAM_START)
{
if (address <= H8_IRAM_END)
h8->iram[address - H8_IRAM_START] = data;
else
h8_register_write8(h8, address, data);
return;
}
cpu_writemem24bew(address, data);
}
static UINT16 h8_read16(h83xx_state *h8, UINT32 address)
{
address &= 0xfffffe;
if (address >= H8_IRAM_START)
return (h8_read8(h8, address) << 8) | h8_read8(h8, address + 1);
return cpu_readmem24bew_word(address);
}
static void h8_write16(h83xx_state *h8, UINT32 address, UINT16 data)
{
address &= 0xfffffe;
if (address >= H8_IRAM_START)
{
h8_write8(h8, address, data >> 8);
h8_write8(h8, address + 1, data & 0xff);
return;
}
cpu_writemem24bew_word(address, data);
}
static UINT16 h8_readop16(h83xx_state *h8, UINT32 address)
{
address &= 0xfffffe;
if (address >= H8_IRAM_START)
return h8_read16(h8, address);
return cpu_readop16(address);
}
#define h8_mem_read8(x) h8_read8(h8, x)
#define h8_mem_read16(z, x) h8_read16(h8, x)
#define h8_mem_write8(x, y) h8_write8(h8, x, y)
#define h8_mem_write16(z, x, y) h8_write16(h8, x, y)
/* timing macros
note: we assume a system 12 - type setup where external access is 3+1 states
timing will be off somewhat for other configurations. */
#define H8_IFETCH_TIMING(x) h8_3002_ICount -= (x) * 4;
#define H8_BRANCH_TIMING(x) h8_3002_ICount -= (x) * 4;
#define H8_STACK_TIMING(x) h8_3002_ICount -= (x) * 4;
#define H8_BYTE_TIMING(x, adr) if (address24 >= 0xffff10) h8_3002_ICount -= (x) * 3; else h8_3002_ICount -= (x) * 4;
#define H8_WORD_TIMING(x, adr) if (address24 >= 0xffff10) h8_3002_ICount -= (x) * 3; else h8_3002_ICount -= (x) * 4;
#define H8_IOP_TIMING(x) h8_3002_ICount -= (x);
static UINT32 h8_mem_read32(h83xx_state *h8, UINT32 address)
{
UINT32 result = h8_read16(h8, address) << 16;
return result | h8_read16(h8, address + 2);
}
static void h8_mem_write32(h83xx_state *h8, UINT32 address, UINT32 data)
{
h8_write16(h8, address, data >> 16);
h8_write16(h8, address + 2, data);
}
static void h8_check_irqs(h83xx_state *h8);
/***************************************************************************
implementation
***************************************************************************/
void h8_3002_InterruptRequest(h83xx_state *h8, UINT8 source, UINT8 state)
{
int request = source / 32;
int bit = source % 32;
/* don't allow clear on external interrupts */
if ((source <= 17) && (state == 0)) return;
if (state)
h8->irq_req[request] |= (1<<bit);
else
h8->irq_req[request] &= ~(1<<bit);
}
static UINT8 h8_get_ccr(h83xx_state *h8)
{
h8->ccr = 0;
if(h8->h8nflag)h8->ccr |= H8_NFLAG;
if(h8->h8zflag)h8->ccr |= H8_ZFLAG;
if(h8->h8vflag)h8->ccr |= H8_VFLAG;
if(h8->h8cflag)h8->ccr |= H8_CFLAG;
if(h8->h8uflag)h8->ccr |= H8_UFLAG;
if(h8->h8hflag)h8->ccr |= H8_HFLAG;
if(h8->h8uiflag)h8->ccr |= H8_UIFLAG;
if(h8->h8iflag)h8->ccr |= H8_IFLAG;
return h8->ccr;
}
static UINT8 h8_get_exr(h83xx_state *h8)
{
return h8->exr;
}
/* CCR into the flag bytes, without taking interrupts */
static void h8_unpack_ccr(h83xx_state *h8, UINT8 data)
{
h8->ccr = data;
h8->h8nflag = (data & H8_NFLAG) ? 1 : 0;
h8->h8zflag = (data & H8_ZFLAG) ? 1 : 0;
h8->h8vflag = (data & H8_VFLAG) ? 1 : 0;
h8->h8cflag = (data & H8_CFLAG) ? 1 : 0;
h8->h8hflag = (data & H8_HFLAG) ? 1 : 0;
h8->h8iflag = (data & H8_IFLAG) ? 1 : 0;
h8->h8uflag = (data & H8_UFLAG) ? 1 : 0;
h8->h8uiflag = (data & H8_UIFLAG) ? 1 : 0;
}
static void h8_set_ccr(h83xx_state *h8, UINT8 data)
{
h8_unpack_ccr(h8, data);
if (!h8->incheckirqs) h8_check_irqs(h8);
}
static void h8_set_exr(h83xx_state *h8, UINT8 data)
{
h8->exr = data;
}
/* register numbers come from opcode bits: keep them inside regs[] */
static INT16 h8_getreg16(h83xx_state *h8, UINT8 reg)
{
reg &= 15;
if(reg > 7)
return h8->regs[reg-8]>>16;
else
return h8->regs[reg];
}
static void h8_setreg16(h83xx_state *h8, UINT8 reg, UINT16 data)
{
reg &= 15;
if(reg > 7)
{
h8->regs[reg-8] &= 0xffff;
h8->regs[reg-8] |= data<<16;
}
else
{
h8->regs[reg] &= 0xffff0000;
h8->regs[reg] |= data;
}
}
static UINT8 h8_getreg8(h83xx_state *h8, UINT8 reg)
{
reg &= 15;
if(reg > 7)
return h8->regs[reg-8];
else
return h8->regs[reg]>>8;
}
static void h8_setreg8(h83xx_state *h8, UINT8 reg, UINT8 data)
{
reg &= 15;
if(reg > 7)
{
h8->regs[reg-8] &= 0xffffff00;
h8->regs[reg-8] |= data;
}
else
{
h8->regs[reg] &= 0xffff00ff;
h8->regs[reg] |= data<<8;
}
}
static UINT32 h8_getreg32(h83xx_state *h8, UINT8 reg)
{
return h8->regs[reg & 7];
}
static void h8_setreg32(h83xx_state *h8, UINT8 reg, UINT32 data)
{
h8->regs[reg & 7] = data;
}
static void h8_GenException(h83xx_state *h8, UINT8 vectornr)
{
/* push PC on stack (extended mode stack push!) */
h8_setreg32(h8, H8_SP, h8_getreg32(h8, H8_SP)-4);
h8_mem_write32(h8, h8_getreg32(h8, H8_SP), h8->pc | (h8_get_ccr(h8)<<24));
/* generate address from vector */
h8_set_ccr(h8, h8_get_ccr(h8) | 0x80);
if (h8->h8uiflag == 0)
h8_set_ccr(h8, h8_get_ccr(h8) | 0x40);
h8->pc = h8_mem_read32(h8, vectornr * 4) & 0xffffff;
/* I couldn't find timing info for exceptions, so this is a guess (based on JSR/BSR) */
H8_IFETCH_TIMING(2);
H8_STACK_TIMING(2);
}
static int h8_get_priority(h83xx_state *h8, UINT8 bit)
{
int res = 0;
switch(bit)
{
case 12: /* IRQ0 */
if (h8->per_regs[0xF8]&0x80) res = 1;
break;
case 13: /* IRQ1 */
if (h8->per_regs[0xF8]&0x40) res = 1;
break;
case 14: /* IRQ2 */
case 15: /* IRQ3 */
if (h8->per_regs[0xF8]&0x20) res = 1;
break;
case 16: /* IRQ4 */
case 17: /* IRQ5 */
if (h8->per_regs[0xF8]&0x10) res = 1;
break;
case 53: /* SCI0 Rx */
if (!(h8->per_regs[0xB2]&0x40)) res = -2;
else if (h8->per_regs[0xF9]&0x08) res = 1;
break;
case 54: /* SCI0 Tx Empty */
if (!(h8->per_regs[0xB2]&0x80)) res = -2;
else if (h8->per_regs[0xF9]&0x08) res = 1;
break;
case 55: /* SCI0 Tx End */
if (!(h8->per_regs[0xB2]&0x04)) res = -2;
else if (h8->per_regs[0xF9]&0x08) res = 1;
break;
case 57: /* SCI1 Rx */
if (!(h8->per_regs[0xBA]&0x40)) res = -2;
else if (h8->per_regs[0xF9]&0x04) res = 1;
break;
case 58: /* SCI1 Tx Empty */
if (!(h8->per_regs[0xBA]&0x80)) res = -2;
else if (h8->per_regs[0xF9]&0x04) res = 1;
break;
case 59: /* SCI1 Tx End */
if (!(h8->per_regs[0xBA]&0x04)) res = -2;
else if (h8->per_regs[0xF9]&0x04) res = 1;
break;
}
return res;
}
static void h8_check_irqs(h83xx_state *h8)
{
int lv = -1;
h8->incheckirqs = 1;
if (h8->has_exr)
{
lv = (h8->exr & 7);
}
else
{
if (h8->h8iflag == 0)
{
lv = 0;
}
else
{
if ((h8->per_regs[0xF2]&0x08)/*SYSCR*/ == 0)
{
if (h8->h8uiflag == 0)
lv = 1;
}
}
}
/* any interrupts wanted and can accept ? */
if(((h8->irq_req[0] != 0) || (h8->irq_req[1]!= 0) || (h8->irq_req[2] != 0)) && (lv >= 0))
{
UINT8 bit, source;
/* which one ? */
for(bit = 0, source = 0xff; source == 0xff && bit < 32; bit++)
{
if( h8->irq_req[0] & (1<<bit) )
{
if (h8_get_priority(h8, bit) >= lv)
{
h8->irq_req[0] &= ~(1<<bit);
source = bit;
}
}
}
for(bit = 0; source == 0xff && bit < 32; bit++)
{
if( h8->irq_req[1] & (1<<bit) )
{
if (h8_get_priority(h8, bit + 32) >= lv)
{
h8->irq_req[1] &= ~(1<<bit);
source = bit + 32;
}
}
}
for(bit = 0; source == 0xff && bit < 32; bit++)
{
if( h8->irq_req[2] & (1<<bit) )
{
if (h8_get_priority(h8, bit + 64) >= lv)
{
h8->irq_req[2] &= ~(1<<bit);
source = bit + 64;
}
}
}
/* call the MAME callback if it's one of the 6 external IRQs */
if (source >= 12 && source <= 17)
{
if (h8->irq_cb)
(*h8->irq_cb)(source - 12 + H8_IRQ0);
}
if (source != 0xff)
h8_GenException(h8, source);
}
h8->incheckirqs = 0;
}
#define H8_ADDR_MASK 0xffffff
static UINT32 h8_idle_start, h8_idle_end; /* polled memory (end 0 = off) */
static UINT32 h8_idle_pc; /* loop start last reached */
static int h8_idle_since; /* instructions since then */
static int h8_idle_cycles; /* h8_3002_ICount then */
void h8_3002_set_idle_poll(UINT32 start, UINT32 end)
{
h8_idle_start = start;
h8_idle_end = end;
}
/* at "mov.b @aa:24, Rd": the start of a polling loop? skip passes */
static void h8_idle_check(h83xx_state *h8)
{
UINT32 address = ((UINT32)h8_readop16(h8, h8->pc + 2) << 16) | h8_readop16(h8, h8->pc + 4);
UINT16 branch = h8_readop16(h8, h8->pc + 6);
address &= 0xffffff;
if (address < h8_idle_start || address > h8_idle_end || (branch != 0x46f8 && branch != 0x47f8))
{
h8_idle_since = -1;
return;
}
/* one whole pass just ran: skip the passes that still fit */
if (h8->pc == h8_idle_pc && h8_idle_since == 2)
{
int pass = h8_idle_cycles - h8_3002_ICount;
if (pass > 0 && h8_3002_ICount > pass)
h8_3002_ICount -= ((h8_3002_ICount - 1) / pass) * pass;
}
h8_idle_pc = h8->pc;
h8_idle_since = 0;
h8_idle_cycles = h8_3002_ICount;
}
#include "h8ops.h"
/***************************************************************************
on-chip peripherals (ITU timers, ports, serial, ADC)
***************************************************************************/
/* timer registers */
#define TSTR (0x60)
#define TIER0 (0x66)
#define TIER1 (0x70)
#define TIER2 (0x7a)
#define TIER3 (0x84)
#define TIER4 (0x94)
#define TSR0 (0x67)
#define TSR1 (0x71)
#define TSR2 (0x7b)
#define TSR3 (0x85)
#define TSR4 (0x95)
#define TCR0 (0x64)
#define TCR1 (0x6e)
#define TCR2 (0x78)
#define TCR3 (0x82)
#define TCR4 (0x92)
static const UINT8 tsr[5] = { TSR0, TSR1, TSR2, TSR3, TSR4 };
static const UINT8 tier[5] = { TIER0, TIER1, TIER2, TIER3, TIER4 };
static const UINT8 tcr[5] = { TCR0, TCR1, TCR2, TCR3, TCR4 };
static const int tscales[4] = { 1, 2, 4, 8 };
static void h8itu_timer_expire(int which)
{
h83xx_state *h8 = &h8state;
timer_adjust(h8->timer[which], TIME_NEVER, 0, 0);
h8->timer_running[which] = 0;
h8->tcnt_offset[which] = 0;
h8->tcnt_start[which] = 0;
h8->h8TCNT[which] = 0;
h8->per_regs[tsr[which]] |= 4;
/* interrupt on overflow ? */
if(h8->per_regs[tier[which]] & 4)
{
h8_3002_InterruptRequest(h8, 26 + 4*which, 1);
}
}
static void h8_itu_refresh_timer(h83xx_state *h8, int tnum)
{
int ourTCR = h8->per_regs[tcr[tnum]];
int ourTVAL = h8->h8TCNT[tnum];
double period;
period = TIME_IN_HZ(h8->clock) * tscales[ourTCR & 3] * (65536 - ourTVAL);
if (ourTCR & 4)
H8_LOG(("H8/3002: Timer %d is using an external clock. Unsupported!\n", tnum));
timer_adjust(h8->timer[tnum], period, tnum, 0);
h8->timer_running[tnum] = 1;
h8->tcnt_start[tnum] = ourTVAL;
h8->tcnt_offset[tnum] = 0;
}
static void h8_itu_sync_timers(h83xx_state *h8, int tnum)
{
int ourTCR = h8->per_regs[tcr[tnum]];
double cycle_time, cur;
/* get the time per unit */
cycle_time = TIME_IN_HZ(h8->clock) * tscales[ourTCR & 3];
cur = timer_timeelapsed(h8->timer[tnum]) + h8->tcnt_offset[tnum];
/* counted from the TCNT value the timer was armed with */
h8->h8TCNT[tnum] = (UINT16)(h8->tcnt_start[tnum] + (UINT32)(cur / cycle_time));
}
static UINT8 h8_itu_read8(h83xx_state *h8, UINT8 reg)
{
switch(reg)
{
case 0x60: return h8->h8TSTR;
case 0x68: h8_itu_sync_timers(h8, 0); return h8->h8TCNT[0]>>8;
case 0x69: h8_itu_sync_timers(h8, 0); return h8->h8TCNT[0]&0xff;
case 0x72: h8_itu_sync_timers(h8, 1); return h8->h8TCNT[1]>>8;
case 0x73: h8_itu_sync_timers(h8, 1); return h8->h8TCNT[1]&0xff;
case 0x7c: h8_itu_sync_timers(h8, 2); return h8->h8TCNT[2]>>8;
case 0x7d: h8_itu_sync_timers(h8, 2); return h8->h8TCNT[2]&0xff;
case 0x86: h8_itu_sync_timers(h8, 3); return h8->h8TCNT[3]>>8;
case 0x87: h8_itu_sync_timers(h8, 3); return h8->h8TCNT[3]&0xff;
default: return h8->per_regs[reg];
}
}
static void h8_itu_write8(h83xx_state *h8, UINT8 reg, UINT8 val)
{
int t;
h8->per_regs[reg] = val;
switch(reg)
{
case 0x60:
for (t = 0; t < 5; t++)
if ((val & (1 << t)) && !(h8->h8TSTR & (1 << t)))
h8_itu_refresh_timer(h8, t);
h8->h8TSTR = val;
break;
case 0x68: h8->h8TCNT[0] = (val<<8) | (h8->h8TCNT[0] & 0xff); if (h8->h8TSTR & 0x01) h8_itu_refresh_timer(h8, 0); break;
case 0x69: h8->h8TCNT[0] = (val) | (h8->h8TCNT[0] & 0xff00); if (h8->h8TSTR & 0x01) h8_itu_refresh_timer(h8, 0); break;
case 0x72: h8->h8TCNT[1] = (val<<8) | (h8->h8TCNT[1] & 0xff); if (h8->h8TSTR & 0x02) h8_itu_refresh_timer(h8, 1); break;
case 0x73: h8->h8TCNT[1] = (val) | (h8->h8TCNT[1] & 0xff00); if (h8->h8TSTR & 0x02) h8_itu_refresh_timer(h8, 1); break;
case 0x7c: h8->h8TCNT[2] = (val<<8) | (h8->h8TCNT[2] & 0xff); if (h8->h8TSTR & 0x04) h8_itu_refresh_timer(h8, 2); break;
case 0x7d: h8->h8TCNT[2] = (val) | (h8->h8TCNT[2] & 0xff00); if (h8->h8TSTR & 0x04) h8_itu_refresh_timer(h8, 2); break;
case 0x86: h8->h8TCNT[3] = (val<<8) | (h8->h8TCNT[3] & 0xff); if (h8->h8TSTR & 0x08) h8_itu_refresh_timer(h8, 3); break;
case 0x87: h8->h8TCNT[3] = (val) | (h8->h8TCNT[3] & 0xff00); if (h8->h8TSTR & 0x08) h8_itu_refresh_timer(h8, 3); break;
case 0x96: h8->h8TCNT[4] = (val<<8) | (h8->h8TCNT[4] & 0xff); if (h8->h8TSTR & 0x10) h8_itu_refresh_timer(h8, 4); break;
case 0x97: h8->h8TCNT[4] = (val) | (h8->h8TCNT[4] & 0xff00); if (h8->h8TSTR & 0x10) h8_itu_refresh_timer(h8, 4); break;
default: break;
}
}
static UINT8 h8_ISR_r(h83xx_state *h8)
{
UINT8 res = 0;
int i;
for (i = 0; i < 6; i++)
if (h8->irq_req[0] & (1 << (12+i))) res |= (1 << i);
return res;
}
static void h8_ISR_w(h83xx_state *h8, UINT8 val)
{
int i;
for (i = 0; i < 6; i++)
if ((~val) & (1 << i)) h8->irq_req[0] &= ~(1 << (12+i));
}
static UINT8 h8_register_read8(h83xx_state *h8, UINT32 address)
{
UINT8 val;
UINT8 reg = address & 0xff;
if(reg >= 0x60 && reg <= 0x9f)
return h8_itu_read8(h8, reg);
switch(reg)
{
case 0xb4: /* serial port A status */
val = h8->per_regs[reg];
val |= 0xc4; /* transmit finished, receive ready, no errors */
break;
case 0xb5: val = h8_io_read_byte(H8_SERIAL_0); break; /* serial port A receive */
case 0xbc: /* serial port B status */
val = h8->per_regs[reg];
val |= 0xc4; /* transmit finished, receive ready, no errors */
break;
case 0xbd: val = h8_io_read_byte(H8_SERIAL_1); break; /* serial port B receive */
case 0xe0: val = h8_io_read_byte(H8_ADC_0_H); break;
case 0xe1: val = h8_io_read_byte(H8_ADC_0_L); break;
case 0xe2: val = h8_io_read_byte(H8_ADC_1_H); break;
case 0xe3: val = h8_io_read_byte(H8_ADC_1_L); break;
case 0xe4: val = h8_io_read_byte(H8_ADC_2_H); break;
case 0xe5: val = h8_io_read_byte(H8_ADC_2_L); break;
case 0xe6: val = h8_io_read_byte(H8_ADC_3_H); break;
case 0xe7: val = h8_io_read_byte(H8_ADC_3_L); break;
case 0xe8: val = 0x80; break; /* adc status */
case 0xc7: val = h8_io_read_byte(H8_PORT_4); break; /* port 4 data */
case 0xcb: val = h8_io_read_byte(H8_PORT_6); break; /* port 6 data */
case 0xce: val = h8_io_read_byte(H8_PORT_7); break; /* port 7 data */
case 0xcf: val = h8_io_read_byte(H8_PORT_8); break; /* port 8 data */
case 0xd2: val = h8_io_read_byte(H8_PORT_9); break; /* port 9 data */
case 0xd3: val = h8_io_read_byte(H8_PORT_A); break; /* port a data */
case 0xd6: val = h8_io_read_byte(H8_PORT_B); break; /* port b data */
case 0xf6: val = h8_ISR_r(h8); break;
default: val = h8->per_regs[reg]; break;
}
return val;
}
static void h8_register_write8(h83xx_state *h8, UINT32 address, UINT8 val)
{
UINT8 reg = address & 0xff;
if(reg >= 0x60 && reg <= 0x9f)
h8_itu_write8(h8, reg, val);
switch (reg)
{
case 0xb3: /* serial 0 send */
h8_io_write_byte(H8_SERIAL_0, val);
h8_3002_InterruptRequest(h8, 54, 1);
h8_3002_InterruptRequest(h8, 55, 1);
break;
case 0xbb: /* serial 1 send */
h8_io_write_byte(H8_SERIAL_1, val);
h8_3002_InterruptRequest(h8, 58, 1);
h8_3002_InterruptRequest(h8, 59, 1);
break;
case 0xc7: h8_io_write_byte(H8_PORT_4, val); break;
case 0xcb: h8_io_write_byte(H8_PORT_6, val); break;
case 0xce: h8_io_write_byte(H8_PORT_7, val); break;
case 0xcf: h8_io_write_byte(H8_PORT_8, val); break;
case 0xd2: h8_io_write_byte(H8_PORT_9, val); break;
case 0xd3: h8_io_write_byte(H8_PORT_A, val); break;
case 0xd6: h8_io_write_byte(H8_PORT_B, val); break;
case 0xf6: h8_ISR_w(h8, val); break;
}
h8->per_regs[reg] = val;
}
/***************************************************************************
MAME 0.78 interface
***************************************************************************/
/* the ITU timers are MAME timers, which a state does not hold: save how
long each one has run and how long it has left, and re-arm them on load */
static void h8_onstatesave(void)
{
h83xx_state *h8 = &h8state;
int i;
/* the live flags are the flag bytes: ccr holds them in the state */
h8_get_ccr(h8);
for (i = 0; i < 5; i++)
{
h8->save_left[i] = h8->timer_running[i] ? timer_timeleft(h8->timer[i]) : -1;
h8->save_elapsed[i] = timer_timeelapsed(h8->timer[i]) + h8->tcnt_offset[i];
}
}
static void h8_onstateload(void)
{
h83xx_state *h8 = &h8state;
int i;
/* flags only: a load must not take an interrupt */
h8_unpack_ccr(h8, h8->ccr);
for (i = 0; i < 5; i++)
{
if (h8->save_left[i] >= 0)
{
timer_adjust(h8->timer[i], h8->save_left[i], i, 0);
h8->timer_running[i] = 1;
}
else
{
timer_adjust(h8->timer[i], TIME_NEVER, 0, 0);
timer_enable(h8->timer[i], 0);
h8->timer_running[i] = 0;
}
h8->tcnt_offset[i] = h8->save_elapsed[i];
}
}
void h8_3002_init(void)
{
h83xx_state *h8 = &h8state;
int cpu = cpu_getactivecpu();
int i;
memset(h8, 0, sizeof(*h8));
h8->h8iflag = 1;
h8->mode_8bit = 0;
for (i = 0; i < 5; i++)
h8->timer[i] = timer_alloc(h8itu_timer_expire);
state_save_register_UINT32("h8_3002", cpu, "h8err", &h8->h8err, 1);
state_save_register_UINT32("h8_3002", cpu, "regs", h8->regs, 8);
state_save_register_UINT32("h8_3002", cpu, "pc", &h8->pc, 1);
state_save_register_UINT32("h8_3002", cpu, "ppc", &h8->ppc, 1);
state_save_register_UINT32("h8_3002", cpu, "irq_req", h8->irq_req, 3);
state_save_register_UINT8 ("h8_3002", cpu, "ccr", &h8->ccr, 1);
state_save_register_UINT8 ("h8_3002", cpu, "per_regs", h8->per_regs, 0x100);
state_save_register_UINT8 ("h8_3002", cpu, "iram", h8->iram, sizeof(h8->iram));
state_save_register_UINT8 ("h8_3002", cpu, "h8TSTR", &h8->h8TSTR, 1);
state_save_register_UINT16("h8_3002", cpu, "h8TCNT", h8->h8TCNT, 5);
state_save_register_UINT16("h8_3002", cpu, "tcnt_start", h8->tcnt_start, 5);
state_save_register_double("h8_3002", cpu, "timer_left", h8->save_left, 5);
state_save_register_double("h8_3002", cpu, "timer_elapsed", h8->save_elapsed, 5);
state_save_register_func_presave(h8_onstatesave);
state_save_register_func_postload(h8_onstateload);
}
void h8_3002_reset(void *param)
{
h83xx_state *h8 = &h8state;
int i;
h8->clock = Machine->drv->cpu[cpu_getactivecpu()].cpu_clock;
h8->h8err = 0;
memset(h8->regs, 0, sizeof(h8->regs));
memset(h8->irq_req, 0, sizeof(h8->irq_req));
memset(h8->per_regs, 0, sizeof(h8->per_regs));
h8->incheckirqs = 0;
h8->exr = 0;
h8->has_exr = 0;
h8_set_ccr(h8, H8_IFLAG);
h8->pc = h8_mem_read32(h8, 0) & 0xffffff;
h8->ppc = h8->pc;
/* disable timers */
h8->h8TSTR = 0;
for (i = 0; i < 5; i++)
{
h8->h8TCNT[i] = 0;
timer_adjust(h8->timer[i], TIME_NEVER, 0, 0);
h8->timer_running[i] = 0;
h8->tcnt_start[i] = 0;
h8->tcnt_offset[i] = 0;
}
}
void h8_3002_exit(void)
{
h8_idle_end = 0;
}
/* single instance (one H8/3002 per machine): the state lives in h8state,
contexts are not swapped */
unsigned h8_3002_get_context(void *dst)
{
return 1;
}
void h8_3002_set_context(void *src)
{
}
unsigned h8_3002_get_reg(int regnum)
{
h83xx_state *h8 = &h8state;
switch (regnum)
{
case REG_PC:
case H8_PC: return h8->pc;
case REG_PREVIOUSPC: return h8->ppc;
case REG_SP: return h8->regs[7];
case H8_CCR: return h8_get_ccr(h8);
case H8_E0: case H8_E1: case H8_E2: case H8_E3:
case H8_E4: case H8_E5: case H8_E6: case H8_E7:
return h8->regs[regnum - H8_E0];
}
return 0;
}
void h8_3002_set_reg(int regnum, unsigned val)
{
h83xx_state *h8 = &h8state;
switch (regnum)
{
case REG_PC:
case H8_PC: h8->pc = val & 0xffffff; break;
case REG_SP: h8->regs[7] = val; break;
case H8_CCR: h8_set_ccr(h8, val); break;
case H8_E0: case H8_E1: case H8_E2: case H8_E3:
case H8_E4: case H8_E5: case H8_E6: case H8_E7:
h8->regs[regnum - H8_E0] = val; break;
}
}
void h8_3002_set_irq_line(int irqline, int state)
{
h83xx_state *h8 = &h8state;
int asserted = (state != CLEAR_LINE && state != INTERNAL_CLEAR_LINE);
switch (irqline)
{
case H8_IRQ0: case H8_IRQ1: case H8_IRQ2:
case H8_IRQ3: case H8_IRQ4: case H8_IRQ5:
h8_3002_InterruptRequest(h8, 12 + irqline - H8_IRQ0, asserted);
break;
case H8_SCI_0_RX: h8_3002_InterruptRequest(h8, 53, asserted); break;
case H8_SCI_1_RX: h8_3002_InterruptRequest(h8, 57, asserted); break;
}
}
void h8_3002_set_irq_callback(int (*callback)(int irqline))
{
h8state.irq_cb = callback;
}
const char *h8_3002_info(void *context, int regnum)
{
static char buffer[16][47+1];
static int which = 0;
h83xx_state *h8 = &h8state;
which = (which+1) % 16;
buffer[which][0] = '\0';
switch (regnum)
{
case CPU_INFO_REG+H8_PC: sprintf(buffer[which], "PC :%06X", h8->pc); break;
case CPU_INFO_REG+H8_CCR: sprintf(buffer[which], "CCR :%02X", h8_get_ccr(h8)); break;
case CPU_INFO_REG+H8_E0: sprintf(buffer[which], "ER0 :%08X", h8->regs[0]); break;
case CPU_INFO_REG+H8_E1: sprintf(buffer[which], "ER1 :%08X", h8->regs[1]); break;
case CPU_INFO_REG+H8_E2: sprintf(buffer[which], "ER2 :%08X", h8->regs[2]); break;
case CPU_INFO_REG+H8_E3: sprintf(buffer[which], "ER3 :%08X", h8->regs[3]); break;
case CPU_INFO_REG+H8_E4: sprintf(buffer[which], "ER4 :%08X", h8->regs[4]); break;
case CPU_INFO_REG+H8_E5: sprintf(buffer[which], "ER5 :%08X", h8->regs[5]); break;
case CPU_INFO_REG+H8_E6: sprintf(buffer[which], "ER6 :%08X", h8->regs[6]); break;
case CPU_INFO_REG+H8_E7: sprintf(buffer[which], " SP :%08X", h8->regs[7]); break;
case CPU_INFO_FLAGS:
sprintf(buffer[which], "%c%c%c%c%c%c%c%c",
h8->h8iflag ? 'I':'i', h8->h8uiflag ? 'U':'u',
h8->h8hflag ? 'H':'h', h8->h8uflag ? 'U':'u',
h8->h8nflag ? 'N':'n', h8->h8zflag ? 'Z':'z',
h8->h8vflag ? 'V':'v', h8->h8cflag ? 'C':'c');
break;
case CPU_INFO_NAME: return "H8/3002";
case CPU_INFO_FAMILY: return "Hitachi H8/300";
case CPU_INFO_VERSION: return "1.0";
case CPU_INFO_FILE: return __FILE__;
case CPU_INFO_CREDITS: return "The_Author & DynaChicken (ZiNc), R. Belmont, Luca Elia, Tomasz Slanina";
}
return buffer[which];
}
unsigned h8_3002_dasm(char *buffer, unsigned pc)
{
sprintf(buffer, "$%04X", h8_read16(&h8state, pc));
return 2;
}
+121
View File
@@ -0,0 +1,121 @@
/***************************************************************************
h83002.h : Public constants and function defs for the H8/3002 emulator.
Backported to the MAME 0.78 CPU interface (mame2003-plus) from the legacy
H8/3xx core of MAME 0.152 (original by The_Author & DynaChicken for ZiNc,
MAME changes by R. Belmont, Luca Elia, Tomasz Slanina, Tim Schuerewegen,
O. Galibert).
Only the H8/3002 (16-bit, advanced mode, 24-bit address space) is
supported. On-chip RAM (0xfffd10-0xffff0f) and the on-chip peripheral
registers (0xffff10-0xffffff) are handled inside the core.
The 0.78 I/O port space is sized after the data bus (16 bit), so the
H8 on-chip ports, ADC and serial channels are routed to the driver
through the callbacks below instead of a PORT map.
****************************************************************************/
#ifndef _H83002_H_
#define _H83002_H_
#include "osd_cpu.h"
#define H8_IFLAG 0x80
#define H8_UIFLAG 0x40
#define H8_HFLAG 0x20
#define H8_UFLAG 0x10
#define H8_NFLAG 0x08
#define H8_ZFLAG 0x04
#define H8_VFLAG 0x02
#define H8_CFLAG 0x01
/* registers */
enum
{
H8_E0 = 1,
H8_E1,
H8_E2,
H8_E3,
H8_E4,
H8_E5,
H8_E6,
H8_E7,
H8_PC,
H8_CCR
};
/* external interrupt lines */
enum
{
H8_IRQ0 = 0,
H8_IRQ1,
H8_IRQ2,
H8_IRQ3,
H8_IRQ4,
H8_IRQ5,
H8_SCI_0_RX, /* incoming character on SCI 0 */
H8_SCI_1_RX /* incoming character on SCI 1 */
};
/* I/O "ports" passed to the driver callbacks */
enum
{
/* digital I/O ports */
H8_PORT_4 = 3,
H8_PORT_6 = 5,
H8_PORT_7,
H8_PORT_8,
H8_PORT_9,
H8_PORT_A,
H8_PORT_B,
/* analog inputs */
H8_ADC_0_H = 0x20,
H8_ADC_0_L,
H8_ADC_1_H,
H8_ADC_1_L,
H8_ADC_2_H,
H8_ADC_2_L,
H8_ADC_3_H,
H8_ADC_3_L,
/* serial ports */
H8_SERIAL_0 = 0x30,
H8_SERIAL_1
};
typedef data8_t (*h8_io_read_func)(int port);
typedef void (*h8_io_write_func)(int port, data8_t data);
/* hook the on-chip ports/ADC/serial to the driver (call before reset) */
void h8_3002_set_io_handlers(h8_io_read_func readfn, h8_io_write_func writefn);
/*
Speedup (end 0 = off): memory in start-end only changes outside the
H8's timeslice (other CPUs, the H8's own interrupts) and reading it has
no side effects. A polling loop on it, "mov.b @aa:24, Rd / bne (or
beq) back", leaves the same state on every pass, so once one pass has
run in a timeslice the whole passes that still fit are skipped:
registers, memory and cycles end up exactly as if they had run.
*/
void h8_3002_set_idle_poll(UINT32 start, UINT32 end);
extern int h8_3002_ICount;
void h8_3002_init(void);
void h8_3002_reset(void *param);
void h8_3002_exit(void);
int h8_3002_execute(int cycles);
unsigned h8_3002_get_context(void *dst);
void h8_3002_set_context(void *src);
unsigned h8_3002_get_reg(int regnum);
void h8_3002_set_reg(int regnum, unsigned val);
void h8_3002_set_irq_line(int irqline, int state);
void h8_3002_set_irq_callback(int (*callback)(int irqline));
const char *h8_3002_info(void *context, int regnum);
unsigned h8_3002_dasm(char *buffer, unsigned pc);
#endif
File diff suppressed because it is too large. Load diff
+3
View File
@@ -587,6 +587,8 @@ void hd6309_init(void)
state_save_register_UINT16("hd6309", cpu, "X", &X, 1);
state_save_register_UINT16("hd6309", cpu, "Y", &Y, 1);
state_save_register_UINT16("hd6309", cpu, "V", &V, 1);
state_save_register_UINT16("hd6309", cpu, "D", &D, 1); /* the accumulators A and B */
state_save_register_UINT16("hd6309", cpu, "W", &W, 1); /* the accumulators E and F */
state_save_register_UINT8("hd6309", cpu, "DP", &DP, 1);
state_save_register_UINT8("hd6309", cpu, "CC", &CC, 1);
state_save_register_UINT8("hd6309", cpu, "MD", &MD, 1);
@@ -595,6 +597,7 @@ void hd6309_init(void)
state_save_register_UINT8("hd6309", cpu, "NMI", &hd6309.nmi_state, 1);
state_save_register_UINT8("hd6309", cpu, "IRQ", &hd6309.irq_state[0], 1);
state_save_register_UINT8("hd6309", cpu, "FIRQ", &hd6309.irq_state[1], 1);
state_save_register_int("hd6309", cpu, "extra_cycles", &hd6309.extra_cycles); /* the cycles of an interrupt taken outside the execute loop */
}
/****************************************************************************/
+674
View File
@@ -0,0 +1,674 @@
#pragma once
#ifndef __CYCLES_H__
#define __CYCLES_H__
typedef enum
{
CYCLES_MOV_REG_REG,
CYCLES_MOV_REG_MEM,
CYCLES_MOV_MEM_REG,
CYCLES_MOV_IMM_REG,
CYCLES_MOV_IMM_MEM,
CYCLES_MOV_ACC_MEM,
CYCLES_MOV_MEM_ACC,
CYCLES_MOV_REG_SREG,
CYCLES_MOV_MEM_SREG,
CYCLES_MOV_SREG_REG,
CYCLES_MOV_SREG_MEM,
CYCLES_MOVSX_REG_REG,
CYCLES_MOVSX_MEM_REG,
CYCLES_MOVZX_REG_REG,
CYCLES_MOVZX_MEM_REG,
CYCLES_PUSH_RM,
CYCLES_PUSH_REG_SHORT,
CYCLES_PUSH_SREG,
CYCLES_PUSH_IMM,
CYCLES_PUSHA,
CYCLES_POP_RM,
CYCLES_POP_REG_SHORT,
CYCLES_POP_SREG,
CYCLES_POPA,
CYCLES_XCHG_REG_REG,
CYCLES_XCHG_REG_MEM,
CYCLES_IN,
CYCLES_IN_VAR,
CYCLES_OUT,
CYCLES_OUT_VAR,
CYCLES_LEA,
CYCLES_LDS,
CYCLES_LES,
CYCLES_LFS,
CYCLES_LGS,
CYCLES_LSS,
CYCLES_CLC,
CYCLES_CLD,
CYCLES_CLI,
CYCLES_CLTS,
CYCLES_CMC,
CYCLES_LAHF,
CYCLES_POPF,
CYCLES_PUSHF,
CYCLES_SAHF,
CYCLES_STC,
CYCLES_STD,
CYCLES_STI,
CYCLES_ALU_REG_REG,
CYCLES_ALU_REG_MEM,
CYCLES_ALU_MEM_REG,
CYCLES_ALU_IMM_REG,
CYCLES_ALU_IMM_MEM,
CYCLES_ALU_IMM_ACC,
CYCLES_INC_REG,
CYCLES_INC_MEM,
CYCLES_DEC_REG,
CYCLES_DEC_MEM,
CYCLES_CMP_REG_REG,
CYCLES_CMP_REG_MEM,
CYCLES_CMP_MEM_REG,
CYCLES_CMP_IMM_REG,
CYCLES_CMP_IMM_MEM,
CYCLES_CMP_IMM_ACC,
CYCLES_TEST_REG_REG,
CYCLES_TEST_REG_MEM,
CYCLES_TEST_IMM_REG,
CYCLES_TEST_IMM_MEM,
CYCLES_TEST_IMM_ACC,
CYCLES_NEG_REG,
CYCLES_NEG_MEM,
CYCLES_AAA,
CYCLES_AAS,
CYCLES_DAA,
CYCLES_DAS,
CYCLES_MUL8_ACC_REG,
CYCLES_MUL8_ACC_MEM,
CYCLES_MUL16_ACC_REG,
CYCLES_MUL16_ACC_MEM,
CYCLES_MUL32_ACC_REG,
CYCLES_MUL32_ACC_MEM,
CYCLES_IMUL8_ACC_REG,
CYCLES_IMUL8_ACC_MEM,
CYCLES_IMUL16_ACC_REG,
CYCLES_IMUL16_ACC_MEM,
CYCLES_IMUL32_ACC_REG,
CYCLES_IMUL32_ACC_MEM,
CYCLES_IMUL8_REG_REG,
CYCLES_IMUL8_REG_MEM,
CYCLES_IMUL16_REG_REG,
CYCLES_IMUL16_REG_MEM,
CYCLES_IMUL32_REG_REG,
CYCLES_IMUL32_REG_MEM,
CYCLES_IMUL16_REG_IMM_REG,
CYCLES_IMUL16_MEM_IMM_REG,
CYCLES_IMUL32_REG_IMM_REG,
CYCLES_IMUL32_MEM_IMM_REG,
CYCLES_DIV8_ACC_REG,
CYCLES_DIV8_ACC_MEM,
CYCLES_DIV16_ACC_REG,
CYCLES_DIV16_ACC_MEM,
CYCLES_DIV32_ACC_REG,
CYCLES_DIV32_ACC_MEM,
CYCLES_IDIV8_ACC_REG,
CYCLES_IDIV8_ACC_MEM,
CYCLES_IDIV16_ACC_REG,
CYCLES_IDIV16_ACC_MEM,
CYCLES_IDIV32_ACC_REG,
CYCLES_IDIV32_ACC_MEM,
CYCLES_AAD,
CYCLES_AAM,
CYCLES_CBW,
CYCLES_CWD,
CYCLES_ROTATE_REG,
CYCLES_ROTATE_MEM,
CYCLES_ROTATE_CARRY_REG,
CYCLES_ROTATE_CARRY_MEM,
CYCLES_SHLD_REG,
CYCLES_SHLD_MEM,
CYCLES_SHRD_REG,
CYCLES_SHRD_MEM,
CYCLES_NOT_REG,
CYCLES_NOT_MEM,
CYCLES_CMPS,
CYCLES_INS,
CYCLES_LODS,
CYCLES_MOVS,
CYCLES_OUTS,
CYCLES_SCAS,
CYCLES_STOS,
CYCLES_XLAT,
CYCLES_REP_CMPS_BASE,
CYCLES_REP_INS_BASE,
CYCLES_REP_LODS_BASE,
CYCLES_REP_MOVS_BASE,
CYCLES_REP_OUTS_BASE,
CYCLES_REP_SCAS_BASE,
CYCLES_REP_STOS_BASE,
CYCLES_REP_CMPS,
CYCLES_REP_INS,
CYCLES_REP_LODS,
CYCLES_REP_MOVS,
CYCLES_REP_OUTS,
CYCLES_REP_SCAS,
CYCLES_REP_STOS,
CYCLES_BSF_BASE,
CYCLES_BSF,
CYCLES_BSR_BASE,
CYCLES_BSR,
CYCLES_BT_IMM_REG,
CYCLES_BT_IMM_MEM,
CYCLES_BT_REG_REG,
CYCLES_BT_REG_MEM,
CYCLES_BTC_IMM_REG,
CYCLES_BTC_IMM_MEM,
CYCLES_BTC_REG_REG,
CYCLES_BTC_REG_MEM,
CYCLES_BTR_IMM_REG,
CYCLES_BTR_IMM_MEM,
CYCLES_BTR_REG_REG,
CYCLES_BTR_REG_MEM,
CYCLES_BTS_IMM_REG,
CYCLES_BTS_IMM_MEM,
CYCLES_BTS_REG_REG,
CYCLES_BTS_REG_MEM,
CYCLES_CALL, /* E8 */
CYCLES_CALL_REG, /* FF /2 */
CYCLES_CALL_MEM, /* FF /2 */
CYCLES_CALL_INTERSEG, /* 9A */
CYCLES_CALL_REG_INTERSEG, /* FF /3 */
CYCLES_CALL_MEM_INTERSEG, /* FF /3 */
CYCLES_JMP_SHORT, /* EB */
CYCLES_JMP, /* E9 */
CYCLES_JMP_REG, /* FF /4 */
CYCLES_JMP_MEM, /* FF /4 */
CYCLES_JMP_INTERSEG, /* EA */
CYCLES_JMP_REG_INTERSEG, /* FF /5 */
CYCLES_JMP_MEM_INTERSEG, /* FF /5 */
CYCLES_RET, /* C3 */
CYCLES_RET_IMM, /* C2 */
CYCLES_RET_INTERSEG, /* CB */
CYCLES_RET_IMM_INTERSEG, /* CA */
CYCLES_JCC_DISP8,
CYCLES_JCC_FULL_DISP,
CYCLES_JCC_DISP8_NOBRANCH,
CYCLES_JCC_FULL_DISP_NOBRANCH,
CYCLES_JCXZ,
CYCLES_JCXZ_NOBRANCH,
CYCLES_LOOP,
CYCLES_LOOPZ,
CYCLES_LOOPNZ,
CYCLES_SETCC_REG,
CYCLES_SETCC_MEM,
CYCLES_ENTER,
CYCLES_LEAVE,
CYCLES_INT,
CYCLES_INT3,
CYCLES_INTO_OF1,
CYCLES_INTO_OF0,
CYCLES_BOUND_IN_RANGE,
CYCLES_BOUND_OUT_RANGE,
CYCLES_IRET,
CYCLES_HLT,
CYCLES_MOV_REG_CR0,
CYCLES_MOV_REG_CR2,
CYCLES_MOV_REG_CR3,
CYCLES_MOV_CR_REG,
CYCLES_MOV_REG_DR0_3,
CYCLES_MOV_REG_DR6_7,
CYCLES_MOV_DR6_7_REG,
CYCLES_MOV_DR0_3_REG,
CYCLES_MOV_REG_TR6_7,
CYCLES_MOV_TR6_7_REG,
CYCLES_NOP,
CYCLES_WAIT,
CYCLES_ARPL_REG,
CYCLES_ARPL_MEM,
CYCLES_LAR_REG,
CYCLES_LAR_MEM,
CYCLES_LGDT,
CYCLES_LIDT,
CYCLES_LLDT_REG,
CYCLES_LLDT_MEM,
CYCLES_LMSW_REG,
CYCLES_LMSW_MEM,
CYCLES_LSL_REG,
CYCLES_LSL_MEM,
CYCLES_LTR_REG,
CYCLES_LTR_MEM,
CYCLES_SGDT,
CYCLES_SIDT,
CYCLES_SLDT_REG,
CYCLES_SLDT_MEM,
CYCLES_SMSW_REG,
CYCLES_SMSW_MEM,
CYCLES_STR_REG,
CYCLES_STR_MEM,
CYCLES_VERR_REG,
CYCLES_VERR_MEM,
CYCLES_VERW_REG,
CYCLES_VERW_MEM,
CYCLES_LOCK,
CYCLES_BSWAP,
CYCLES_CMPXCHG8B,
CYCLES_CMPXCHG,
CYCLES_CPUID,
CYCLES_CPUID_EAX1,
CYCLES_INVD,
CYCLES_XADD,
CYCLES_RDTSC,
CYCLES_RSM,
CYCLES_RDMSR,
CYCLES_FABS,
CYCLES_FADD,
CYCLES_FBLD,
CYCLES_FBSTP,
CYCLES_FCHS,
CYCLES_FCLEX,
CYCLES_FCOM,
CYCLES_FCOS,
CYCLES_FDECSTP,
CYCLES_FDISI,
CYCLES_FDIV,
CYCLES_FDIVR,
CYCLES_FENI,
CYCLES_FFREE,
CYCLES_FIADD,
CYCLES_FICOM,
CYCLES_FIDIV,
CYCLES_FILD,
CYCLES_FIMUL,
CYCLES_FINCSTP,
CYCLES_FINIT,
CYCLES_FIST,
CYCLES_FISUB,
CYCLES_FLD,
CYCLES_FLDZ,
CYCLES_FLD1,
CYCLES_FLDL2E,
CYCLES_FLDL2T,
CYCLES_FLDLG2,
CYCLES_FLDLN2,
CYCLES_FLDPI,
CYCLES_FLDCW,
CYCLES_FLDENV,
CYCLES_FMUL,
CYCLES_FNOP,
CYCLES_FPATAN,
CYCLES_FPREM,
CYCLES_FPREM1,
CYCLES_FPTAN,
CYCLES_FRNDINT,
CYCLES_FRSTOR,
CYCLES_FSAVE,
CYCLES_FSCALE,
CYCLES_FSETPM,
CYCLES_FSIN,
CYCLES_FSINCOS,
CYCLES_FSQRT,
CYCLES_FST,
CYCLES_FSTCW,
CYCLES_FSTENV,
CYCLES_FSTSW,
CYCLES_FSUB,
CYCLES_FSUBR,
CYCLES_FTST,
CYCLES_FUCOM,
CYCLES_FXAM,
CYCLES_FXCH,
CYCLES_FXTRACT,
CYCLES_FYL2X,
CYCLES_FYL2XPI,
CYCLES_CMPXCHG_REG_REG_T,
CYCLES_CMPXCHG_REG_REG_F,
CYCLES_CMPXCHG_REG_MEM_T,
CYCLES_CMPXCHG_REG_MEM_F,
CYCLES_XADD_REG_REG,
CYCLES_XADD_REG_MEM,
CYCLES_NUM_OPCODES
} X86_CYCLES;
#define X86_NUM_CPUS 4
#define CPU_CYCLES_I386 0
#define CPU_CYCLES_I486 1
#define CPU_CYCLES_PENTIUM 2
#define CPU_CYCLES_MEDIAGX 3
typedef struct
{
X86_CYCLES op;
UINT8 cpu_cycles[X86_NUM_CPUS][2];
} X86_CYCLE_TABLE;
static const X86_CYCLE_TABLE x86_cycle_table[] =
{
/* opcode rm/pmode */
/* i386 i486 pentium mediagx */
{ CYCLES_MOV_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_REG_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_MEM_REG, { { 4, 4 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_IMM_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_ACC_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_MEM_ACC, { { 4, 4 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_MOV_REG_SREG, { { 2, 18 }, { 3, 3 }, { 2, 2 }, { 1, 6 } } },
{ CYCLES_MOV_MEM_SREG, { { 5, 19 }, { 9, 9 }, { 3, 3 }, { 1, 6 } } },
{ CYCLES_MOV_SREG_REG, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 6 } } },
{ CYCLES_MOV_SREG_MEM, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 6 } } },
{ CYCLES_MOVSX_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_MOVSX_MEM_REG, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_MOVZX_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_MOVZX_MEM_REG, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_PUSH_RM, { { 5, 5 }, { 4, 4 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_PUSH_REG_SHORT, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_PUSH_SREG, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_PUSH_IMM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_PUSHA, { { 18, 18 }, { 11, 11 }, { 5, 5 }, { 11, 11 } } },
{ CYCLES_POP_RM, { { 5, 5 }, { 4, 4 }, { 3, 3 }, { 4, 4 } } },
{ CYCLES_POP_REG_SHORT, { { 4, 4 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_POP_SREG, { { 7, 21 }, { 3, 3 }, { 3, 3 }, { 1, 6 } } },
{ CYCLES_POPA, { { 24, 24 }, { 9, 9 }, { 5, 5 }, { 9, 9 } } },
{ CYCLES_XCHG_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_XCHG_REG_MEM, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_IN, { { 12, 26 }, { 14, 27 }, { 7, 19 }, { 8, 8 } } },
{ CYCLES_IN_VAR, { { 13, 27 }, { 14, 27 }, { 7, 19 }, { 8, 8 } } },
{ CYCLES_OUT, { { 10, 24 }, { 16, 29 }, { 12, 24 }, { 14, 14 } } },
{ CYCLES_OUT_VAR, { { 11, 25 }, { 16, 29 }, { 12, 24 }, { 14, 14 } } },
{ CYCLES_LEA, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_LDS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
{ CYCLES_LES, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
{ CYCLES_LFS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
{ CYCLES_LGS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } },
{ CYCLES_LSS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 10 } } },
{ CYCLES_CLC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_CLD, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 4, 4 } } },
{ CYCLES_CLI, { { 8, 8 }, { 5, 5 }, { 7, 7 }, { 6, 6 } } },
{ CYCLES_CLTS, { { 6, 6 }, { 7, 7 }, { 10, 10 }, { 7, 7 } } },
{ CYCLES_CMC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_LAHF, { { 2, 2 }, { 3, 3 }, { 2, 2 }, { 2, 2 } } },
{ CYCLES_POPF, { { 5, 5 }, { 9, 9 }, { 6, 6 }, { 8, 8 } } },
{ CYCLES_PUSHF, { { 4, 4 }, { 4, 4 }, { 9, 9 }, { 2, 2 } } },
{ CYCLES_SAHF, { { 3, 3 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_STC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_STD, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 4, 4 } } },
{ CYCLES_STI, { { 8, 8 }, { 5, 5 }, { 7, 7 }, { 6, 6 } } },
{ CYCLES_ALU_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_ALU_REG_MEM, { { 7, 7 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_ALU_MEM_REG, { { 6, 6 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_ALU_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_ALU_IMM_MEM, { { 7, 7 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_ALU_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_INC_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_INC_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_DEC_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_DEC_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_CMP_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_CMP_REG_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_CMP_MEM_REG, { { 6, 6 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_CMP_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_CMP_IMM_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_CMP_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_TEST_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_TEST_REG_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_TEST_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_TEST_IMM_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_TEST_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_NEG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_NEG_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_AAA, { { 4, 4 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
{ CYCLES_AAS, { { 4, 4 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
{ CYCLES_DAA, { { 4, 4 }, { 2, 2 }, { 3, 3 }, { 2, 2 } } },
{ CYCLES_DAS, { { 4, 4 }, { 2, 2 }, { 3, 3 }, { 2, 2 } } },
{ CYCLES_MUL8_ACC_REG, { { 17, 17 }, { 13, 13 }, { 11, 11 }, { 4, 4 } } },
{ CYCLES_MUL8_ACC_MEM, { { 20, 20 }, { 13, 13 }, { 11, 11 }, { 4, 4 } } },
{ CYCLES_MUL16_ACC_REG, { { 25, 25 }, { 13, 13 }, { 11, 11 }, { 5, 5 } } },
{ CYCLES_MUL16_ACC_MEM, { { 28, 28 }, { 13, 13 }, { 11, 11 }, { 5, 5 } } },
{ CYCLES_MUL32_ACC_REG, { { 41, 41 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
{ CYCLES_MUL32_ACC_MEM, { { 44, 44 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
{ CYCLES_IMUL8_ACC_REG, { { 17, 17 }, { 18, 18 }, { 11, 11 }, { 4, 4 } } },
{ CYCLES_IMUL8_ACC_MEM, { { 20, 20 }, { 18, 18 }, { 11, 11 }, { 4, 4 } } },
{ CYCLES_IMUL16_ACC_REG, { { 25, 25 }, { 26, 26 }, { 11, 11 }, { 5, 5 } } },
{ CYCLES_IMUL16_ACC_MEM, { { 28, 28 }, { 26, 26 }, { 11, 11 }, { 5, 5 } } },
{ CYCLES_IMUL32_ACC_REG, { { 41, 41 }, { 42, 42 }, { 10, 10 }, { 15, 15 } } },
{ CYCLES_IMUL32_ACC_MEM, { { 44, 44 }, { 42, 42 }, { 10, 10 }, { 15, 15 } } },
{ CYCLES_IMUL8_REG_REG, { { 17, 17 }, { 13, 13 }, { 10, 10 }, { 4, 4 } } },
{ CYCLES_IMUL8_REG_MEM, { { 20, 20 }, { 13, 13 }, { 10, 10 }, { 4, 4 } } },
{ CYCLES_IMUL16_REG_REG, { { 25, 25 }, { 13, 13 }, { 10, 10 }, { 5, 5 } } },
{ CYCLES_IMUL16_REG_MEM, { { 28, 28 }, { 13, 13 }, { 10, 10 }, { 5, 5 } } },
{ CYCLES_IMUL32_REG_REG, { { 41, 41 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
{ CYCLES_IMUL32_REG_MEM, { { 44, 44 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } },
{ CYCLES_IMUL16_REG_IMM_REG,{ { 26, 26 }, { 26, 26 }, { 10, 10 }, { 6, 6 } } },
{ CYCLES_IMUL16_MEM_IMM_REG,{ { 27, 27 }, { 26, 26 }, { 10, 10 }, { 6, 6 } } },
{ CYCLES_IMUL32_REG_IMM_REG,{ { 42, 42 }, { 42, 42 }, { 10, 10 }, { 16, 16 } } },
{ CYCLES_IMUL32_MEM_IMM_REG,{ { 43, 43 }, { 42, 42 }, { 10, 10 }, { 16, 16 } } },
{ CYCLES_DIV8_ACC_REG, { { 14, 14 }, { 16, 16 }, { 17, 17 }, { 20, 20 } } },
{ CYCLES_DIV8_ACC_MEM, { { 17, 17 }, { 16, 16 }, { 17, 17 }, { 20, 20 } } },
{ CYCLES_DIV16_ACC_REG, { { 22, 22 }, { 24, 24 }, { 25, 25 }, { 29, 29 } } },
{ CYCLES_DIV16_ACC_MEM, { { 25, 25 }, { 24, 24 }, { 25, 25 }, { 29, 29 } } },
{ CYCLES_DIV32_ACC_REG, { { 38, 38 }, { 40, 40 }, { 41, 41 }, { 45, 45 } } },
{ CYCLES_DIV32_ACC_MEM, { { 41, 41 }, { 40, 40 }, { 41, 41 }, { 45, 45 } } },
{ CYCLES_IDIV8_ACC_REG, { { 19, 19 }, { 19, 19 }, { 22, 22 }, { 20, 20 } } },
{ CYCLES_IDIV8_ACC_MEM, { { 22, 22 }, { 20, 20 }, { 22, 22 }, { 20, 20 } } },
{ CYCLES_IDIV16_ACC_REG, { { 27, 27 }, { 27, 27 }, { 30, 30 }, { 29, 29 } } },
{ CYCLES_IDIV16_ACC_MEM, { { 30, 30 }, { 28, 28 }, { 30, 30 }, { 29, 29 } } },
{ CYCLES_IDIV32_ACC_REG, { { 43, 43 }, { 43, 43 }, { 46, 46 }, { 45, 45 } } },
{ CYCLES_IDIV32_ACC_MEM, { { 46, 46 }, { 44, 44 }, { 46, 46 }, { 45, 45 } } },
{ CYCLES_AAD, { { 19, 19 }, { 14, 14 }, { 10, 10 }, { 7, 7 } } },
{ CYCLES_AAM, { { 17, 17 }, { 15, 15 }, { 18, 18 }, { 19, 19 } } },
{ CYCLES_CBW, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
{ CYCLES_CWD, { { 2, 2 }, { 3, 3 }, { 2, 2 }, { 2, 2 } } },
{ CYCLES_ROTATE_REG, { { 3, 3 }, { 3, 3 }, { 1, 1 }, { 2, 2 } } },
{ CYCLES_ROTATE_MEM, { { 7, 7 }, { 4, 4 }, { 3, 3 }, { 2, 2 } } },
{ CYCLES_ROTATE_CARRY_REG, { { 9, 9 }, { 8, 8 }, { 7, 7 }, { 8, 8 } } },
{ CYCLES_ROTATE_CARRY_MEM, { { 10, 10 }, { 9, 9 }, { 8, 8 }, { 8, 8 } } },
{ CYCLES_SHLD_REG, { { 3, 3 }, { 2, 2 }, { 4, 4 }, { 3, 3 } } },
{ CYCLES_SHLD_MEM, { { 7, 7 }, { 3, 3 }, { 4, 4 }, { 6, 6 } } },
{ CYCLES_SHRD_REG, { { 3, 3 }, { 2, 2 }, { 4, 4 }, { 3, 3 } } },
{ CYCLES_SHRD_MEM, { { 7, 7 }, { 3, 3 }, { 4, 4 }, { 6, 6 } } },
{ CYCLES_NOT_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_NOT_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_CMPS, { { 10, 10 }, { 8, 8 }, { 5, 5 }, { 6, 6 } } },
{ CYCLES_INS, { { 15, 29 }, { 17, 30 }, { 9, 22 }, { 11, 11 } } },
{ CYCLES_LODS, { { 5, 5 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_MOVS, { { 8, 8 }, { 7, 7 }, { 4, 4 }, { 6, 6 } } },
{ CYCLES_OUTS, { { 14, 28 }, { 17, 30 }, { 13, 25 }, { 15, 15 } } },
{ CYCLES_SCAS, { { 8, 8 }, { 6, 6 }, { 4, 4 }, { 2, 2 } } },
{ CYCLES_STOS, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 2, 2 } } },
{ CYCLES_XLAT, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 5, 5 } } },
{ CYCLES_REP_CMPS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 11, 11 } } },
{ CYCLES_REP_INS_BASE, { { 14, 8 }, { 0, 0 }, { 0, 0 }, { 17, 17 } } },
{ CYCLES_REP_LODS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } },
{ CYCLES_REP_MOVS_BASE, { { 8, 8 }, { 0, 0 }, { 0, 0 }, { 12, 12 } } },
{ CYCLES_REP_OUTS_BASE, { { 12, 6 }, { 0, 0 }, { 0, 0 }, { 24, 24 } } },
{ CYCLES_REP_SCAS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } },
{ CYCLES_REP_STOS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } },
{ CYCLES_REP_CMPS, { { 5, 5 }, { 8, 8 }, { 5, 5 }, { 4, 4 } } },
{ CYCLES_REP_INS, { { 14, 8 }, { 17, 30 }, { 9, 22 }, { 4, 4 } } },
{ CYCLES_REP_LODS, { { 5, 5 }, { 5, 5 }, { 2, 2 }, { 2, 2 } } },
{ CYCLES_REP_MOVS, { { 8, 8 }, { 7, 7 }, { 4, 4 }, { 2, 2 } } },
{ CYCLES_REP_OUTS, { { 12, 6 }, { 17, 30 }, { 13, 25 }, { 4, 4 } } },
{ CYCLES_REP_SCAS, { { 5, 5 }, { 6, 6 }, { 4, 4 }, { 3, 3 } } },
{ CYCLES_REP_STOS, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 2, 2 } } },
{ CYCLES_BSF_BASE, { { 11, 11 }, { 6, 6 }, { 6, 6 }, { 4, 4 } } },
{ CYCLES_BSF, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_BSR_BASE, { { 9, 9 }, { 6, 6 }, { 7, 7 }, { 4, 4 } } },
{ CYCLES_BSR, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_BT_IMM_REG, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 1, 1 } } },
{ CYCLES_BT_IMM_MEM, { { 6, 6 }, { 6, 6 }, { 4, 4 }, { 1, 1 } } },
{ CYCLES_BT_REG_REG, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 1, 1 } } },
{ CYCLES_BT_REG_MEM, { { 12, 12 }, { 12, 12 }, { 9, 9 }, { 7, 7 } } },
{ CYCLES_BTC_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
{ CYCLES_BTC_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } },
{ CYCLES_BTC_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
{ CYCLES_BTC_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } },
{ CYCLES_BTR_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
{ CYCLES_BTR_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } },
{ CYCLES_BTR_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
{ CYCLES_BTR_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } },
{ CYCLES_BTS_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
{ CYCLES_BTS_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } },
{ CYCLES_BTS_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } },
{ CYCLES_BTS_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } },
{ CYCLES_CALL, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 3, 3 } } },
{ CYCLES_CALL_REG, { { 7, 7 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_CALL_MEM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 4, 4 } } },
{ CYCLES_CALL_INTERSEG, { { 17, 34 }, { 18, 20 }, { 4, 13 }, { 9, 14 } } },
{ CYCLES_CALL_REG_INTERSEG, { { 22, 38 }, { 17, 20 }, { 4, 14 }, { 11, 15 } } },
{ CYCLES_CALL_MEM_INTERSEG, { { 22, 38 }, { 17, 20 }, { 4, 14 }, { 11, 15 } } },
{ CYCLES_JMP_SHORT, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_JMP, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_JMP_REG, { { 7, 7 }, { 5, 5 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_JMP_MEM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_JMP_INTERSEG, { { 12, 27 }, { 17, 19 }, { 3, 3 }, { 8, 12 } } },
{ CYCLES_JMP_REG_INTERSEG, { { 17, 31 }, { 13, 18 }, { 4, 4 }, { 10, 10 } } },
{ CYCLES_JMP_MEM_INTERSEG, { { 17, 31 }, { 13, 18 }, { 4, 4 }, { 10, 13 } } },
{ CYCLES_RET, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_RET_IMM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } },
{ CYCLES_RET_INTERSEG, { { 18, 32 }, { 13, 13 }, { 4, 4 }, { 10, 13 } } },
{ CYCLES_RET_IMM_INTERSEG, { { 18, 32 }, { 14, 14 }, { 4, 4 }, { 10, 13 } } },
{ CYCLES_JCC_DISP8, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_JCC_FULL_DISP, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_JCC_DISP8_NOBRANCH,{ { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_JCC_FULL_DISP_NOBRANCH,{ { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_JCXZ, { { 9, 9 }, { 1, 1 }, { 1, 1 }, { 2, 2 } } },
{ CYCLES_JCXZ_NOBRANCH, { { 5, 5 }, { 1, 1 }, { 1, 1 }, { 2, 2 } } },
{ CYCLES_LOOP, { { 11, 11 }, { 6, 6 }, { 5, 5 }, { 2, 2 } } },
{ CYCLES_LOOPZ, { { 11, 11 }, { 9, 9 }, { 8, 8 }, { 2, 2 } } },
{ CYCLES_LOOPNZ, { { 11, 11 }, { 9, 9 }, { 8, 8 }, { 2, 2 } } },
{ CYCLES_SETCC_REG, { { 4, 4 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_SETCC_MEM, { { 5, 5 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_ENTER, { { 10, 10 }, { 14, 14 }, { 11, 11 }, { 13, 13 } } },
{ CYCLES_LEAVE, { { 4, 4 }, { 5, 5 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_INT, { { 37, 37 }, { 30, 30 }, { 16, 16 }, { 19, 19 } } },
{ CYCLES_INT3, { { 33, 33 }, { 26, 26 }, { 13, 13 }, { 19, 19 } } },
{ CYCLES_INTO_OF1, { { 35, 35 }, { 28, 28 }, { 13, 13 }, { 19, 19 } } },
{ CYCLES_INTO_OF0, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 4, 4 } } },
{ CYCLES_BOUND_IN_RANGE, { { 10, 10 }, { 7, 7 }, { 8, 8 }, { 7, 7 } } },
{ CYCLES_BOUND_OUT_RANGE, { { 44, 44 }, { 7, 7 }, { 8, 8 }, { 8, 8 } } },
{ CYCLES_IRET, { { 22, 22 }, { 15, 15 }, { 8, 8 }, { 13, 13 } } },
{ CYCLES_HLT, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 10, 10 } } },
{ CYCLES_MOV_REG_CR0, { { 11, 11 }, { 16, 16 }, { 16, 16 }, { 20, 18 } } },
{ CYCLES_MOV_REG_CR2, { { 4, 4 }, { 4, 4 }, { 4, 4 }, { 5, 5 } } },
{ CYCLES_MOV_REG_CR3, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 5, 6 } } },
{ CYCLES_MOV_CR_REG, { { 6, 6 }, { 4, 4 }, { 4, 4 }, { 6, 6 } } },
{ CYCLES_MOV_REG_DR0_3, { { 22, 22 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } },
{ CYCLES_MOV_REG_DR6_7, { { 16, 16 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } },
{ CYCLES_MOV_DR6_7_REG, { { 14, 14 }, { 11, 11 }, { 11, 11 }, { 9, 9 } } },
{ CYCLES_MOV_DR0_3_REG, { { 22, 22 }, { 11, 11 }, { 11, 11 }, { 9, 9 } } },
{ CYCLES_MOV_REG_TR6_7, { { 12, 12 }, { 4, 4 }, { 4, 4 }, { 11, 11 } } },
{ CYCLES_MOV_TR6_7_REG, { { 12, 12 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } },
{ CYCLES_NOP, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_WAIT, { { 7, 7 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_ARPL_REG, { { 0, 20 }, { 0, 9 }, { 0, 7 }, { 0, 9 } } },
{ CYCLES_ARPL_MEM, { { 0, 21 }, { 0, 9 }, { 0, 7 }, { 0, 9 } } },
{ CYCLES_LAR_REG, { { 0, 15 }, { 11, 11 }, { 8, 8 }, { 0, 9 } } },
{ CYCLES_LAR_MEM, { { 0, 16 }, { 11, 11 }, { 8, 8 }, { 0, 9 } } },
{ CYCLES_LGDT, { { 11, 11 }, { 11, 11 }, { 6, 6 }, { 10, 10 } } },
{ CYCLES_LIDT, { { 11, 11 }, { 11, 11 }, { 6, 6 }, { 10, 10 } } },
{ CYCLES_LLDT_REG, { { 0, 20 }, { 11, 11 }, { 9, 9 }, { 0, 8 } } },
{ CYCLES_LLDT_MEM, { { 0, 24 }, { 11, 11 }, { 9, 9 }, { 0, 8 } } },
{ CYCLES_LMSW_REG, { { 11, 11 }, { 13, 13 }, { 8, 8 }, { 11, 11 } } },
{ CYCLES_LMSW_MEM, { { 14, 14 }, { 13, 13 }, { 8, 8 }, { 11, 11 } } },
{ CYCLES_LSL_REG, { { 0, 21 }, { 10, 10 }, { 8, 8 }, { 0, 9 } } },
{ CYCLES_LSL_MEM, { { 0, 22 }, { 10, 10 }, { 8, 8 }, { 0, 9 } } },
{ CYCLES_LTR_REG, { { 0, 23 }, { 20, 20 }, { 10, 10 }, { 0, 9 } } },
{ CYCLES_LTR_MEM, { { 0, 27 }, { 20, 20 }, { 10, 10 }, { 0, 9 } } },
{ CYCLES_SGDT, { { 9, 9 }, { 10, 10 }, { 4, 4 }, { 6, 6 } } },
{ CYCLES_SIDT, { { 9, 9 }, { 10, 10 }, { 4, 4 }, { 6, 6 } } },
{ CYCLES_SLDT_REG, { { 0, 2 }, { 2, 2 }, { 2, 2 }, { 0, 1 } } },
{ CYCLES_SLDT_MEM, { { 0, 2 }, { 3, 3 }, { 2, 2 }, { 0, 1 } } },
{ CYCLES_SMSW_REG, { { 2, 2 }, { 2, 2 }, { 4, 4 }, { 4, 4 } } },
{ CYCLES_SMSW_MEM, { { 2, 2 }, { 3, 3 }, { 4, 4 }, { 4, 4 } } },
{ CYCLES_STR_REG, { { 0, 2 }, { 2, 2 }, { 2, 2 }, { 0, 3 } } },
{ CYCLES_STR_MEM, { { 0, 2 }, { 3, 3 }, { 2, 2 }, { 0, 3 } } },
{ CYCLES_VERR_REG, { { 0, 10 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
{ CYCLES_VERR_MEM, { { 0, 11 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
{ CYCLES_VERW_REG, { { 0, 15 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
{ CYCLES_VERW_MEM, { { 0, 16 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } },
{ CYCLES_LOCK, { { 0, 0 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } },
/* i486+ */
{ CYCLES_BSWAP, { { 0, 0 }, { 1, 1 }, { 1, 1 }, { 6, 6 } } },
{ CYCLES_CMPXCHG, { { 0, 0 }, { 6, 6 }, { 5, 5 }, { 6, 6 } } },
{ CYCLES_INVD, { { 0, 0 }, { 4, 4 }, { 15, 15 }, { 20, 20 } } },
{ CYCLES_XADD, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 2, 2 } } },
/* Pentium+ */
{ CYCLES_CMPXCHG8B, { { 0, 0 }, { 0, 0 }, { 10, 10 }, { 6, 6 } } },
{ CYCLES_CPUID, { { 0, 0 }, { 0, 0 }, { 14, 14 }, { 12, 12 } } },
{ CYCLES_CPUID_EAX1, { { 0, 0 }, { 0, 0 }, { 14, 14 }, { 12, 12 } } },
{ CYCLES_RDTSC, { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 1, 1 } } },
{ CYCLES_RSM, { { 0, 0 }, { 0, 0 }, { 82, 82 }, { 57, 57 } } },
{ CYCLES_RDMSR, { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 1, 1 } } },
/* FPU */
{ CYCLES_FABS, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FADD, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_FBLD, { { 0, 0 }, { 70, 70 }, { 48, 48 }, { 1, 1 } } },
{ CYCLES_FBSTP, { { 0, 0 }, {172,172 }, {148,148 }, { 1, 1 } } },
{ CYCLES_FCHS, { { 0, 0 }, { 6, 6 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FCLEX, { { 0, 0 }, { 7, 7 }, { 9, 9 }, { 1, 1 } } },
{ CYCLES_FCOM, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } },
{ CYCLES_FCOS, { { 0, 0 }, {255,255 }, {124,124 }, { 1, 1 } } },
{ CYCLES_FDECSTP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FDISI, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FDIV, { { 0, 0 }, { 73, 73 }, { 39, 39 }, { 1, 1 } } },
{ CYCLES_FDIVR, { { 0, 0 }, { 73, 73 }, { 39, 39 }, { 1, 1 } } },
{ CYCLES_FENI, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FFREE, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FIADD, { { 0, 0 }, { 20, 20 }, { 7, 7 }, { 1, 1 } } },
{ CYCLES_FICOM, { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 1, 1 } } },
{ CYCLES_FIDIV, { { 0, 0 }, { 85, 85 }, { 42, 42 }, { 1, 1 } } },
{ CYCLES_FILD, { { 0, 0 }, { 13, 13 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_FIMUL, { { 0, 0 }, { 23, 23 }, { 7, 7 }, { 1, 1 } } },
{ CYCLES_FINCSTP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FINIT, { { 0, 0 }, { 17, 17 }, { 16, 16 }, { 1, 1 } } },
{ CYCLES_FIST, { { 0, 0 }, { 29, 29 }, { 6, 6 }, { 1, 1 } } },
{ CYCLES_FISUB, { { 0, 0 }, { 20, 20 }, { 7, 7 }, { 1, 1 } } },
{ CYCLES_FLD, { { 0, 0 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FLDZ, { { 0, 0 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_FLD1, { { 0, 0 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_FLDL2E, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
{ CYCLES_FLDL2T, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
{ CYCLES_FLDLG2, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
{ CYCLES_FLDLN2, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
{ CYCLES_FLDPI, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } },
{ CYCLES_FLDCW, { { 0, 0 }, { 4, 4 }, { 7, 7 }, { 1, 1 } } },
{ CYCLES_FLDENV, { { 0, 0 }, { 44, 44 }, { 37, 37 }, { 1, 1 } } },
{ CYCLES_FMUL, { { 0, 0 }, { 16, 16 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_FNOP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FPATAN, { { 0, 0 }, {218,218 }, {173,173 }, { 1, 1 } } },
{ CYCLES_FPREM, { { 0, 0 }, { 70, 70 }, { 16, 16 }, { 1, 1 } } },
{ CYCLES_FPREM1, { { 0, 0 }, { 72, 72 }, { 20, 20 }, { 1, 1 } } },
{ CYCLES_FPTAN, { { 0, 0 }, {200,200 }, {173,173 }, { 1, 1 } } },
{ CYCLES_FRNDINT, { { 0, 0 }, { 21, 21 }, { 9, 9 }, { 1, 1 } } },
{ CYCLES_FRSTOR, { { 0, 0 }, {131,131 }, { 75, 75 }, { 1, 1 } } },
{ CYCLES_FSAVE, { { 0, 0 }, {154,154 }, {127,127 }, { 1, 1 } } },
{ CYCLES_FSCALE, { { 0, 0 }, { 30, 30 }, { 20, 20 }, { 1, 1 } } },
{ CYCLES_FSETPM, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FSIN, { { 0, 0 }, {255,255 }, {126,126 }, { 1, 1 } } },
{ CYCLES_FSINCOS, { { 0, 0 }, {255,255 }, {137,137 }, { 1, 1 } } },
{ CYCLES_FSQRT, { { 0, 0 }, { 83, 83 }, { 70, 70 }, { 1, 1 } } },
{ CYCLES_FST, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FSTCW, { { 0, 0 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_FSTENV, { { 0, 0 }, { 67, 67 }, { 48, 48 }, { 1, 1 } } },
{ CYCLES_FSTSW, { { 0, 0 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } },
{ CYCLES_FSUB, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_FSUBR, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } },
{ CYCLES_FTST, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } },
{ CYCLES_FUCOM, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } },
{ CYCLES_FXAM, { { 0, 0 }, { 8, 8 }, { 21, 21 }, { 1, 1 } } },
{ CYCLES_FXCH, { { 0, 0 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } },
{ CYCLES_FXTRACT, { { 0, 0 }, { 16, 16 }, { 13, 13 }, { 1, 1 } } },
{ CYCLES_FYL2X, { { 0, 0 }, {196,196 }, {111,111 }, { 1, 1 } } },
{ CYCLES_FYL2XPI, { { 0, 0 }, {171,171 }, {103,103 }, { 1, 1 } } },
{ CYCLES_CMPXCHG_REG_REG_T, { { 0, 0 }, { 6, 6 }, { 6, 6 }, { 6, 6 } } },
{ CYCLES_CMPXCHG_REG_REG_F, { { 0, 0 }, { 9, 9 }, { 9, 9 }, { 9, 9 } } },
{ CYCLES_CMPXCHG_REG_MEM_T, { { 0, 0 }, { 7, 7 }, { 7, 7 }, { 7, 7 } } },
{ CYCLES_CMPXCHG_REG_MEM_F, { { 0, 0 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } },
};
#endif /* __CYCLES_H__ */
+868
View File
@@ -0,0 +1,868 @@
/*
Intel 386 emulator
Written by Ville Linde
Currently supports:
Intel 386
Intel 486
Intel Pentium
Cyrix MediaGX
*/
#include <string.h>
#include "driver.h"
#include "state.h"
#include "i386priv.h"
#include "i386.h"
#include "mamedbg.h"
int i386_ICount;
/* the 0.139 core stops on what it does not implement; here it is logged once */
static void i386_fatal(const char *fmt, ...)
{
static int reported;
if (!reported)
{
char buf[256];
va_list va;
va_start(va, fmt);
vsprintf(buf, fmt, va);
va_end(va);
log_cb(RETRO_LOG_ERROR, LOGPRE "%s\n", buf);
reported = 1;
}
}
/* seems to be defined on mingw-gcc */
#undef i386
int i386_parity_table[256];
MODRM_TABLE i386_MODRM_table[256];
/*************************************************************************/
#define INT_DEBUG 1
static void i386_load_protected_mode_segment(i386_state *cpustate, I386_SREG *seg )
{
UINT32 v1,v2;
UINT32 base, limit;
int entry;
if ( seg->selector & 0x4 )
{
base = cpustate->ldtr.base;
limit = cpustate->ldtr.limit;
} else {
base = cpustate->gdtr.base;
limit = cpustate->gdtr.limit;
}
if (limit == 0 || seg->selector + 7 > limit)
return;
entry = seg->selector & ~0x7;
v1 = READ32(cpustate, base + entry );
v2 = READ32(cpustate, base + entry + 4 );
seg->flags = (v2 >> 8) & 0xf0ff;
seg->base = (v2 & 0xff000000) | ((v2 & 0xff) << 16) | ((v1 >> 16) & 0xffff);
seg->limit = (v2 & 0xf0000) | (v1 & 0xffff);
if (seg->flags & 0x8000)
seg->limit = (seg->limit << 12) | 0xfff;
seg->d = (seg->flags & 0x4000) ? 1 : 0;
}
static void i386_load_segment_descriptor(i386_state *cpustate, int segment )
{
if (PROTECTED_MODE)
{
if (!V8086_MODE)
i386_load_protected_mode_segment(cpustate, &cpustate->sreg[segment] );
else
{
cpustate->sreg[segment].base = cpustate->sreg[segment].selector << 4;
cpustate->sreg[segment].limit = 0xffff;
cpustate->sreg[segment].flags = (segment == CS) ? 0x009a : 0x0092;
}
}
else
{
cpustate->sreg[segment].base = cpustate->sreg[segment].selector << 4;
if( segment == CS && !cpustate->performed_intersegment_jump )
cpustate->sreg[segment].base |= 0xfff00000;
}
}
static UINT32 get_flags(i386_state *cpustate)
{
UINT32 f = 0x2;
f |= cpustate->CF;
f |= cpustate->PF << 2;
f |= cpustate->AF << 4;
f |= cpustate->ZF << 6;
f |= cpustate->SF << 7;
f |= cpustate->TF << 8;
f |= cpustate->IF << 9;
f |= cpustate->DF << 10;
f |= cpustate->OF << 11;
f |= cpustate->IOP1 << 12;
f |= cpustate->IOP2 << 13;
f |= cpustate->NT << 14;
return (cpustate->eflags & cpustate->eflags_mask) | (f & 0xffff);
}
static void set_flags(i386_state *cpustate, UINT32 f )
{
cpustate->CF = (f & 0x1) ? 1 : 0;
cpustate->PF = (f & 0x4) ? 1 : 0;
cpustate->AF = (f & 0x10) ? 1 : 0;
cpustate->ZF = (f & 0x40) ? 1 : 0;
cpustate->SF = (f & 0x80) ? 1 : 0;
cpustate->TF = (f & 0x100) ? 1 : 0;
cpustate->IF = (f & 0x200) ? 1 : 0;
cpustate->DF = (f & 0x400) ? 1 : 0;
cpustate->OF = (f & 0x800) ? 1 : 0;
cpustate->IOP1 = (f & 0x1000) ? 1 : 0;
cpustate->IOP2 = (f & 0x2000) ? 1 : 0;
cpustate->NT = (f & 0x4000) ? 1 : 0;
cpustate->eflags = f & cpustate->eflags_mask;
}
static void sib_byte(i386_state *cpustate,UINT8 mod, UINT32* out_ea, UINT8* out_segment)
{
UINT32 ea = 0;
UINT8 segment = 0;
UINT8 scale, i, base;
UINT8 sib = FETCH(cpustate);
scale = (sib >> 6) & 0x3;
i = (sib >> 3) & 0x7;
base = sib & 0x7;
switch( base )
{
case 0: ea = REG32(EAX); segment = DS; break;
case 1: ea = REG32(ECX); segment = DS; break;
case 2: ea = REG32(EDX); segment = DS; break;
case 3: ea = REG32(EBX); segment = DS; break;
case 4: ea = REG32(ESP); segment = SS; break;
case 5:
if( mod == 0 ) {
ea = FETCH32(cpustate);
segment = DS;
} else if( mod == 1 ) {
ea = REG32(EBP);
segment = SS;
} else if( mod == 2 ) {
ea = REG32(EBP);
segment = SS;
}
break;
case 6: ea = REG32(ESI); segment = DS; break;
case 7: ea = REG32(EDI); segment = DS; break;
}
switch( i )
{
case 0: ea += REG32(EAX) * (1 << scale); break;
case 1: ea += REG32(ECX) * (1 << scale); break;
case 2: ea += REG32(EDX) * (1 << scale); break;
case 3: ea += REG32(EBX) * (1 << scale); break;
case 4: break;
case 5: ea += REG32(EBP) * (1 << scale); break;
case 6: ea += REG32(ESI) * (1 << scale); break;
case 7: ea += REG32(EDI) * (1 << scale); break;
}
*out_ea = ea;
*out_segment = segment;
}
static void modrm_to_EA(i386_state *cpustate,UINT8 mod_rm, UINT32* out_ea, UINT8* out_segment)
{
INT8 disp8;
INT16 disp16;
INT32 disp32;
UINT8 mod = (mod_rm >> 6) & 0x3;
UINT8 rm = mod_rm & 0x7;
UINT32 ea;
UINT8 segment;
if( mod_rm >= 0xc0 )
i386_fatal("i386: Called modrm_to_EA with modrm value %02X !",mod_rm);
if( cpustate->address_size ) {
switch( rm )
{
default:
case 0: ea = REG32(EAX); segment = DS; break;
case 1: ea = REG32(ECX); segment = DS; break;
case 2: ea = REG32(EDX); segment = DS; break;
case 3: ea = REG32(EBX); segment = DS; break;
case 4: sib_byte(cpustate, mod, &ea, &segment ); break;
case 5:
if( mod == 0 ) {
ea = FETCH32(cpustate); segment = DS;
} else {
ea = REG32(EBP); segment = SS;
}
break;
case 6: ea = REG32(ESI); segment = DS; break;
case 7: ea = REG32(EDI); segment = DS; break;
}
if( mod == 1 ) {
disp8 = FETCH(cpustate);
ea += (INT32)disp8;
} else if( mod == 2 ) {
disp32 = FETCH32(cpustate);
ea += disp32;
}
if( cpustate->segment_prefix )
segment = cpustate->segment_override;
*out_ea = ea;
*out_segment = segment;
} else {
switch( rm )
{
default:
case 0: ea = REG16(BX) + REG16(SI); segment = DS; break;
case 1: ea = REG16(BX) + REG16(DI); segment = DS; break;
case 2: ea = REG16(BP) + REG16(SI); segment = SS; break;
case 3: ea = REG16(BP) + REG16(DI); segment = SS; break;
case 4: ea = REG16(SI); segment = DS; break;
case 5: ea = REG16(DI); segment = DS; break;
case 6:
if( mod == 0 ) {
ea = FETCH16(cpustate); segment = DS;
} else {
ea = REG16(BP); segment = SS;
}
break;
case 7: ea = REG16(BX); segment = DS; break;
}
if( mod == 1 ) {
disp8 = FETCH(cpustate);
ea += (INT32)disp8;
} else if( mod == 2 ) {
disp16 = FETCH16(cpustate);
ea += (INT32)disp16;
}
if( cpustate->segment_prefix )
segment = cpustate->segment_override;
*out_ea = ea & 0xffff;
*out_segment = segment;
}
}
static UINT32 GetNonTranslatedEA(i386_state *cpustate,UINT8 modrm)
{
UINT8 segment;
UINT32 ea;
modrm_to_EA(cpustate, modrm, &ea, &segment );
return ea;
}
static UINT32 GetEA(i386_state *cpustate,UINT8 modrm)
{
UINT8 segment;
UINT32 ea;
modrm_to_EA(cpustate, modrm, &ea, &segment );
return i386_translate(cpustate, segment, ea );
}
static void i386_trap(i386_state *cpustate,int irq, int irq_gate)
{
/* I386 Interrupts/Traps/Faults:
*
* 0x00 Divide by zero
* 0x01 Debug exception
* 0x02 NMI
* 0x03 Int3
* 0x04 Overflow
* 0x05 Array bounds check
* 0x06 Illegal Opcode
* 0x07 FPU not available
* 0x08 Double fault
* 0x09 Coprocessor segment overrun
* 0x0a Invalid task state
* 0x0b Segment not present
* 0x0c Stack exception
* 0x0d General Protection Fault
* 0x0e Page fault
* 0x0f Reserved
* 0x10 Coprocessor error
*/
UINT32 v1, v2;
UINT32 offset;
UINT16 segment;
int entry = irq * (PROTECTED_MODE ? 8 : 4);
/* Check if IRQ is out of IDTR's bounds */
if( entry > cpustate->idtr.limit ) {
i386_fatal("I386 Interrupt: IRQ out of IDTR bounds (IRQ: %d, IDTR Limit: %d)", irq, cpustate->idtr.limit);
}
if( !(PROTECTED_MODE) )
{
/* 16-bit */
PUSH16(cpustate, get_flags(cpustate) & 0xffff );
PUSH16(cpustate, cpustate->sreg[CS].selector );
PUSH16(cpustate, cpustate->eip );
cpustate->sreg[CS].selector = READ16(cpustate, cpustate->idtr.base + entry + 2 );
cpustate->eip = READ16(cpustate, cpustate->idtr.base + entry );
/* Interrupts that vector through either interrupt gates or trap gates cause TF */
/* (the trap flag) to be reset after the current value of TF is saved on the stack as part of EFLAGS. */
cpustate->TF = 0;
if (irq_gate)
{
cpustate->IF = 0;
}
}
else
{
int type;
/* 32-bit */
v1 = READ32(cpustate, cpustate->idtr.base + entry );
v2 = READ32(cpustate, cpustate->idtr.base + entry + 4 );
offset = (v2 & 0xffff0000) | (v1 & 0xffff);
segment = (v1 >> 16) & 0xffff;
type = (v2>>8) & 0x1F;
if(type != 0x0e && type != 0x0f) /* if not 386 interrupt or trap gate */
{
PUSH16(cpustate, get_flags(cpustate) & 0xffff );
PUSH16(cpustate, cpustate->sreg[CS].selector );
PUSH16(cpustate, cpustate->eip );
}
else
{
PUSH32(cpustate, get_flags(cpustate) & 0x00fcffff );
PUSH32(cpustate, cpustate->sreg[CS].selector );
PUSH32(cpustate, cpustate->eip );
}
cpustate->sreg[CS].selector = segment;
cpustate->eip = offset;
/* Interrupts that vector through either interrupt gates or trap gates cause TF */
/* (the trap flag) to be reset after the current value of TF is saved on the stack as part of EFLAGS. */
if ((type == 14) || (type==15))
cpustate->TF = 0;
if (type == 14)
{
cpustate->IF = 0;
}
}
i386_load_segment_descriptor(cpustate,CS);
CHANGE_PC(cpustate,cpustate->eip);
}
static void i386_check_irq_line(i386_state *cpustate)
{
/* Check if the interrupts are enabled */
if ( (cpustate->irq_state) && cpustate->IF )
{
i386_ICount -= 2;
i386_trap(cpustate,cpustate->irq_callback(0), 1);
}
}
#include "cycles.h"
static UINT8 *cycle_table_rm[X86_NUM_CPUS];
static UINT8 *cycle_table_pm[X86_NUM_CPUS];
#define CYCLES_NUM(x) (i386_ICount -= (x))
static INLINE void CYCLES(i386_state *cpustate,int x)
{
if (PROTECTED_MODE)
{
i386_ICount -= cpustate->cycle_table_pm[x];
}
else
{
i386_ICount -= cpustate->cycle_table_rm[x];
}
}
static INLINE void CYCLES_RM(i386_state *cpustate,int modrm, int r, int m)
{
if (modrm >= 0xc0)
{
if (PROTECTED_MODE)
{
i386_ICount -= cpustate->cycle_table_pm[r];
}
else
{
i386_ICount -= cpustate->cycle_table_rm[r];
}
}
else
{
if (PROTECTED_MODE)
{
i386_ICount -= cpustate->cycle_table_pm[m];
}
else
{
i386_ICount -= cpustate->cycle_table_rm[m];
}
}
}
static UINT8 cycle_tables[X86_NUM_CPUS][2][CYCLES_NUM_OPCODES];
static void build_cycle_table(void)
{
int i, j;
for (j=0; j < X86_NUM_CPUS; j++)
{
cycle_table_rm[j] = cycle_tables[j][0];
cycle_table_pm[j] = cycle_tables[j][1];
for (i=0; i < sizeof(x86_cycle_table)/sizeof(X86_CYCLE_TABLE); i++)
{
int opcode = x86_cycle_table[i].op;
cycle_table_rm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][0];
cycle_table_pm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][1];
}
}
}
/* Forward declarations */
static void I386OP(decode_opcode)(i386_state *cpustate);
static void I386OP(decode_two_byte)(i386_state *cpustate);
#include "i386ops.c"
#include "i386op16.c"
#include "i386op32.c"
#include "i486ops.c"
#include "pentops.c"
#include "x87ops.c"
#include "i386ops.h"
static void I386OP(decode_opcode)(i386_state *cpustate)
{
cpustate->opcode = FETCH(cpustate);
if( cpustate->operand_size )
cpustate->opcode_table1_32[cpustate->opcode](cpustate);
else
cpustate->opcode_table1_16[cpustate->opcode](cpustate);
}
/* Two-byte opcode prefix */
static void I386OP(decode_two_byte)(i386_state *cpustate)
{
cpustate->opcode = FETCH(cpustate);
if( cpustate->operand_size )
cpustate->opcode_table2_32[cpustate->opcode](cpustate);
else
cpustate->opcode_table2_16[cpustate->opcode](cpustate);
}
/*************************************************************************/
static void build_opcode_table(i386_state *cpustate, UINT32 features)
{
int i;
for (i=0; i < 256; i++)
{
cpustate->opcode_table1_16[i] = I386OP(invalid);
cpustate->opcode_table1_32[i] = I386OP(invalid);
cpustate->opcode_table2_16[i] = I386OP(invalid);
cpustate->opcode_table2_32[i] = I386OP(invalid);
}
for (i=0; i < sizeof(x86_opcode_table)/sizeof(X86_OPCODE); i++)
{
const X86_OPCODE *op = &x86_opcode_table[i];
if ((op->flags & features))
{
if (op->flags & OP_2BYTE)
{
cpustate->opcode_table2_32[op->opcode] = op->handler32;
cpustate->opcode_table2_16[op->opcode] = op->handler16;
}
else
{
cpustate->opcode_table1_32[op->opcode] = op->handler32;
cpustate->opcode_table1_16[op->opcode] = op->handler16;
}
}
}
}
/*************************************************************************
The interface of the CPU core (MAME 0.78 style): one context, copied
in and out by the CPU switch
*************************************************************************/
static i386_state I;
static void i386_postload(void)
{
i386_state *cpustate = &I;
int i;
for (i = 0; i < 6; i++)
i386_load_segment_descriptor(cpustate,i);
CHANGE_PC(cpustate,cpustate->eip);
}
/* the fast memory regions of the driver */
static struct
{
UINT32 start, end;
UINT8 *base;
int flags;
} i386_fastmem[I386_FASTMEM_MAX];
static int i386_fastmem_count;
void i386_set_fastmem(UINT32 start, UINT32 end, UINT8 *base, int flags)
{
if (i386_fastmem_count < I386_FASTMEM_MAX)
{
i386_fastmem[i386_fastmem_count].start = start;
i386_fastmem[i386_fastmem_count].end = end;
i386_fastmem[i386_fastmem_count].base = base;
i386_fastmem[i386_fastmem_count].flags = flags;
i386_fastmem_count++;
}
/* empty the caches */
memset(I.fast_size, 0, sizeof(I.fast_size));
}
/* a miss of the cache: the region of the address, cached; NULL if none */
static UINT8 *i386_fast_lookup(i386_state *cpustate, UINT32 address, UINT32 len, int kind)
{
int i;
for (i = 0; i < i386_fastmem_count; i++)
{
if ((i386_fastmem[i].flags & (1 << kind)) && address >= i386_fastmem[i].start &&
address <= i386_fastmem[i].end && i386_fastmem[i].end - address >= len - 1)
{
cpustate->fast_start[kind] = i386_fastmem[i].start;
cpustate->fast_size[kind] = i386_fastmem[i].end - i386_fastmem[i].start + 1;
cpustate->fast_base[kind] = i386_fastmem[i].base;
return i386_fastmem[i].base + (address - i386_fastmem[i].start);
}
}
return NULL;
}
void i386_init(void)
{
int i, j;
static const int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH};
static const int regs16[8] = {AX,CX,DX,BX,SP,BP,SI,DI};
static const int regs32[8] = {EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI};
int cpu = cpu_getactivecpu();
i386_state *cpustate = &I;
static const char *const sregname[6] = { "es", "cs", "ss", "ds", "fs", "gs" };
i386_fastmem_count = 0;
memset(I.fast_size, 0, sizeof(I.fast_size));
build_cycle_table();
for( i=0; i < 256; i++ ) {
int c=0;
for( j=0; j < 8; j++ ) {
if( i & (1 << j) )
c++;
}
i386_parity_table[i] = ~(c & 0x1) & 0x1;
}
for( i=0; i < 256; i++ ) {
i386_MODRM_table[i].reg.b = regs8[(i >> 3) & 0x7];
i386_MODRM_table[i].reg.w = regs16[(i >> 3) & 0x7];
i386_MODRM_table[i].reg.d = regs32[(i >> 3) & 0x7];
i386_MODRM_table[i].rm.b = regs8[i & 0x7];
i386_MODRM_table[i].rm.w = regs16[i & 0x7];
i386_MODRM_table[i].rm.d = regs32[i & 0x7];
}
state_save_register_UINT32("i386", cpu, "reg", cpustate->reg.d, 8);
for (i = 0; i < 6; i++)
{
char name[16];
sprintf(name, "%s_sel", sregname[i]);
state_save_register_UINT16("i386", cpu, name, &cpustate->sreg[i].selector, 1);
sprintf(name, "%s_flags", sregname[i]);
state_save_register_UINT16("i386", cpu, name, &cpustate->sreg[i].flags, 1);
sprintf(name, "%s_base", sregname[i]);
state_save_register_UINT32("i386", cpu, name, &cpustate->sreg[i].base, 1);
sprintf(name, "%s_limit", sregname[i]);
state_save_register_UINT32("i386", cpu, name, &cpustate->sreg[i].limit, 1);
sprintf(name, "%s_d", sregname[i]);
state_save_register_int("i386", cpu, name, &cpustate->sreg[i].d);
}
state_save_register_UINT32("i386", cpu, "eip", &cpustate->eip, 1);
state_save_register_UINT32("i386", cpu, "pc", &cpustate->pc, 1);
state_save_register_UINT32("i386", cpu, "prev_eip", &cpustate->prev_eip, 1);
state_save_register_UINT32("i386", cpu, "eflags", &cpustate->eflags, 1);
state_save_register_UINT32("i386", cpu, "eflags_mask", &cpustate->eflags_mask, 1);
state_save_register_UINT8("i386", cpu, "CF", &cpustate->CF, 1);
state_save_register_UINT8("i386", cpu, "DF", &cpustate->DF, 1);
state_save_register_UINT8("i386", cpu, "SF", &cpustate->SF, 1);
state_save_register_UINT8("i386", cpu, "OF", &cpustate->OF, 1);
state_save_register_UINT8("i386", cpu, "ZF", &cpustate->ZF, 1);
state_save_register_UINT8("i386", cpu, "PF", &cpustate->PF, 1);
state_save_register_UINT8("i386", cpu, "AF", &cpustate->AF, 1);
state_save_register_UINT8("i386", cpu, "IF", &cpustate->IF, 1);
state_save_register_UINT8("i386", cpu, "TF", &cpustate->TF, 1);
state_save_register_UINT8("i386", cpu, "IOP1", &cpustate->IOP1, 1);
state_save_register_UINT8("i386", cpu, "IOP2", &cpustate->IOP2, 1);
state_save_register_UINT8("i386", cpu, "NT", &cpustate->NT, 1);
state_save_register_UINT32("i386", cpu, "cr", cpustate->cr, 5);
state_save_register_UINT32("i386", cpu, "dr", cpustate->dr, 8);
state_save_register_UINT32("i386", cpu, "tr", cpustate->tr, 8);
state_save_register_UINT32("i386", cpu, "idtr_base", &cpustate->idtr.base, 1);
state_save_register_UINT16("i386", cpu, "idtr_limit", &cpustate->idtr.limit, 1);
state_save_register_UINT32("i386", cpu, "gdtr_base", &cpustate->gdtr.base, 1);
state_save_register_UINT16("i386", cpu, "gdtr_limit", &cpustate->gdtr.limit, 1);
state_save_register_UINT32("i386", cpu, "task_base", &cpustate->task.base, 1);
state_save_register_UINT16("i386", cpu, "task_segment", &cpustate->task.segment, 1);
state_save_register_UINT32("i386", cpu, "task_limit", &cpustate->task.limit, 1);
state_save_register_UINT16("i386", cpu, "task_flags", &cpustate->task.flags, 1);
state_save_register_UINT32("i386", cpu, "ldtr_base", &cpustate->ldtr.base, 1);
state_save_register_UINT16("i386", cpu, "ldtr_segment", &cpustate->ldtr.segment, 1);
state_save_register_UINT32("i386", cpu, "ldtr_limit", &cpustate->ldtr.limit, 1);
state_save_register_UINT16("i386", cpu, "ldtr_flags", &cpustate->ldtr.flags, 1);
state_save_register_int("i386", cpu, "halted", &cpustate->halted);
state_save_register_UINT8("i386", cpu, "irq_state", &cpustate->irq_state, 1);
state_save_register_UINT8("i386", cpu, "performed_intersegment_jump", &cpustate->performed_intersegment_jump, 1);
state_save_register_UINT32("i386", cpu, "a20_mask", &cpustate->a20_mask, 1);
state_save_register_func_postload(i386_postload);
}
void i386_reset(void *param)
{
i386_state *cpustate = &I;
int (*save_irqcallback)(int);
save_irqcallback = cpustate->irq_callback;
memset( cpustate, 0, sizeof(*cpustate) );
cpustate->irq_callback = save_irqcallback;
cpustate->sreg[CS].selector = 0xf000;
cpustate->sreg[CS].base = 0xffff0000;
cpustate->sreg[CS].limit = 0xffff;
cpustate->sreg[DS].base = cpustate->sreg[ES].base = cpustate->sreg[FS].base = cpustate->sreg[GS].base = cpustate->sreg[SS].base = 0x00000000;
cpustate->sreg[DS].limit = cpustate->sreg[ES].limit = cpustate->sreg[FS].limit = cpustate->sreg[GS].limit = cpustate->sreg[SS].limit = 0xffff;
cpustate->sreg[DS].flags = cpustate->sreg[ES].flags = cpustate->sreg[FS].flags = cpustate->sreg[GS].flags = cpustate->sreg[SS].flags = 0x0092;
cpustate->idtr.base = 0;
cpustate->idtr.limit = 0x3ff;
cpustate->a20_mask = ~0;
cpustate->cr[0] = 0x7ffffff0; /* reserved bits set to 1 */
cpustate->eflags = 0;
cpustate->eflags_mask = 0x00030000;
cpustate->eip = 0xfff0;
/* Family 3 (386), Model 0 (DX), Stepping 8 (D1) */
REG32(EAX) = 0;
REG32(EDX) = (3 << 8) | (0 << 4) | (8);
build_opcode_table(cpustate, OP_I386);
cpustate->cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386];
cpustate->cycle_table_pm = cycle_table_pm[CPU_CYCLES_I386];
CHANGE_PC(cpustate,cpustate->eip);
}
void i386_exit(void)
{
}
int i386_execute(int cycles)
{
i386_state *cpustate = &I;
i386_ICount = cycles;
cpustate->base_cycles = cycles;
CHANGE_PC(cpustate,cpustate->eip);
if (cpustate->halted)
{
cpustate->tsc += cycles;
i386_ICount = 0;
return cycles;
}
while( i386_ICount > 0 )
{
cpustate->operand_size = cpustate->sreg[CS].d;
cpustate->address_size = cpustate->sreg[CS].d;
cpustate->segment_prefix = 0;
cpustate->prev_eip = cpustate->eip;
CALL_MAME_DEBUG;
i386_check_irq_line(cpustate);
I386OP(decode_opcode)(cpustate);
}
cpustate->tsc += (cycles - i386_ICount);
return cycles - i386_ICount;
}
unsigned i386_get_context(void *dst)
{
if (dst)
*(i386_state *)dst = I;
return sizeof(i386_state);
}
void i386_set_context(void *src)
{
if (src)
I = *(i386_state *)src;
}
unsigned i386_get_reg(int regnum)
{
i386_state *cpustate = &I;
switch (regnum)
{
case REG_PC: return cpustate->pc;
case REG_PREVIOUSPC: return cpustate->sreg[CS].base + cpustate->prev_eip;
case REG_SP: return cpustate->sreg[SS].base + REG32(ESP);
case I386_EIP: return cpustate->eip;
case I386_EAX: return REG32(EAX);
case I386_EBX: return REG32(EBX);
case I386_ECX: return REG32(ECX);
case I386_EDX: return REG32(EDX);
case I386_ESI: return REG32(ESI);
case I386_EDI: return REG32(EDI);
case I386_EBP: return REG32(EBP);
case I386_ESP: return REG32(ESP);
case I386_EFLAGS: return get_flags(cpustate);
case I386_CS: return cpustate->sreg[CS].selector;
case I386_SS: return cpustate->sreg[SS].selector;
case I386_DS: return cpustate->sreg[DS].selector;
case I386_ES: return cpustate->sreg[ES].selector;
case I386_FS: return cpustate->sreg[FS].selector;
case I386_GS: return cpustate->sreg[GS].selector;
case I386_CR0: return cpustate->cr[0];
}
return 0;
}
void i386_set_reg(int regnum, unsigned val)
{
i386_state *cpustate = &I;
switch (regnum)
{
case REG_PC:
cpustate->eip = val - cpustate->sreg[CS].base;
CHANGE_PC(cpustate,cpustate->eip);
break;
case REG_SP: REG32(ESP) = val - cpustate->sreg[SS].base; break;
case I386_EIP: cpustate->eip = val; CHANGE_PC(cpustate,cpustate->eip); break;
case I386_EAX: REG32(EAX) = val; break;
case I386_EBX: REG32(EBX) = val; break;
case I386_ECX: REG32(ECX) = val; break;
case I386_EDX: REG32(EDX) = val; break;
case I386_ESI: REG32(ESI) = val; break;
case I386_EDI: REG32(EDI) = val; break;
case I386_EBP: REG32(EBP) = val; break;
case I386_ESP: REG32(ESP) = val; break;
case I386_EFLAGS: set_flags(cpustate, val); break;
}
}
void i386_set_irq_line(int irqline, int state)
{
i386_state *cpustate = &I;
if (state != CLEAR_LINE && cpustate->halted)
{
cpustate->halted = 0;
}
if ( irqline == IRQ_LINE_NMI )
{
/* NMI (I do not think that this is 100% right) */
if ( state )
i386_trap(cpustate,2, 1);
}
else if ( irqline == I386_INPUT_LINE_A20 )
{
cpustate->a20_mask = state ? ~0 : ~(1 << 20);
}
else
{
cpustate->irq_state = state;
}
}
void i386_set_irq_callback(int (*callback)(int irqline))
{
I.irq_callback = callback;
}
const char *i386_info(void *context, int regnum)
{
static char buffer[16][47+1];
static int which = 0;
i386_state *r = context ? (i386_state *)context : &I;
which = (which + 1) % 16;
buffer[which][0] = '\0';
switch( regnum )
{
case CPU_INFO_REG+I386_EIP: sprintf(buffer[which], "EIP:%08X", r->eip); break;
case CPU_INFO_REG+I386_EAX: sprintf(buffer[which], "EAX:%08X", r->reg.d[EAX]); break;
case CPU_INFO_REG+I386_EBX: sprintf(buffer[which], "EBX:%08X", r->reg.d[EBX]); break;
case CPU_INFO_REG+I386_ECX: sprintf(buffer[which], "ECX:%08X", r->reg.d[ECX]); break;
case CPU_INFO_REG+I386_EDX: sprintf(buffer[which], "EDX:%08X", r->reg.d[EDX]); break;
case CPU_INFO_REG+I386_ESI: sprintf(buffer[which], "ESI:%08X", r->reg.d[ESI]); break;
case CPU_INFO_REG+I386_EDI: sprintf(buffer[which], "EDI:%08X", r->reg.d[EDI]); break;
case CPU_INFO_REG+I386_EBP: sprintf(buffer[which], "EBP:%08X", r->reg.d[EBP]); break;
case CPU_INFO_REG+I386_ESP: sprintf(buffer[which], "ESP:%08X", r->reg.d[ESP]); break;
case CPU_INFO_FLAGS: sprintf(buffer[which], "%08X", r->eflags); break;
case CPU_INFO_NAME: return "I386";
case CPU_INFO_FAMILY: return "Intel 386";
case CPU_INFO_VERSION: return "1.0";
case CPU_INFO_FILE: return __FILE__;
case CPU_INFO_CREDITS: return "Copyright Ville Linde";
}
return buffer[which];
}
unsigned i386_dasm(char *buffer, unsigned pc)
{
sprintf(buffer, "$%02X", cpu_readmem32ledw(pc));
return 1;
}
+39
View File
@@ -0,0 +1,39 @@
/***************************************************************************
Intel 386 emulator (Ville Linde), from MAME 0.139
***************************************************************************/
#ifndef I386INTF_H
#define I386INTF_H
#include "cpuintrf.h"
/* the A20 gate, as an input line */
#define I386_INPUT_LINE_A20 1
extern int i386_ICount;
/* the fast memory: a range of plain RAM or ROM at base, which the CPU */
/* fetches, reads or writes directly (flags), without the memory handlers; */
/* set from DRIVER_INIT, emptied at the CPU init. Little endian hosts only */
#define I386_FASTMEM_MAX 8
#define I386_FASTMEM_FETCH 1
#define I386_FASTMEM_READ 2
#define I386_FASTMEM_WRITE 4
void i386_set_fastmem(UINT32 start, UINT32 end, UINT8 *base, int flags);
void i386_init(void);
void i386_reset(void *param);
void i386_exit(void);
int i386_execute(int cycles);
unsigned i386_get_context(void *dst);
void i386_set_context(void *src);
unsigned i386_get_reg(int regnum);
void i386_set_reg(int regnum, unsigned val);
void i386_set_irq_line(int irqline, int state);
void i386_set_irq_callback(int (*callback)(int irqline));
const char *i386_info(void *context, int regnum);
unsigned i386_dasm(char *buffer, unsigned pc);
#endif
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+377
View File
@@ -0,0 +1,377 @@
typedef struct {
UINT8 opcode;
UINT32 flags;
void (*handler16)(i386_state *cpustate);
void (*handler32)(i386_state *cpustate);
} X86_OPCODE;
#define OP_I386 0x1
#define OP_FPU 0x2
#define OP_I486 0x4
#define OP_PENTIUM 0x8
#define OP_MMX 0x10
#define OP_PPRO 0x20
#define OP_SSE 0x40
#define OP_SSE2 0x80
#define OP_SSE3 0x100
#define OP_CYRIX 0x8000
#define OP_2BYTE 0x80000000
static const X86_OPCODE x86_opcode_table[] =
{
/* Opcode Flags 16-bit handler 32-bit handler */
{ 0x00, OP_I386, I386OP(add_rm8_r8), I386OP(add_rm8_r8), },
{ 0x01, OP_I386, I386OP(add_rm16_r16), I386OP(add_rm32_r32), },
{ 0x02, OP_I386, I386OP(add_r8_rm8), I386OP(add_r8_rm8), },
{ 0x03, OP_I386, I386OP(add_r16_rm16), I386OP(add_r32_rm32), },
{ 0x04, OP_I386, I386OP(add_al_i8), I386OP(add_al_i8), },
{ 0x05, OP_I386, I386OP(add_ax_i16), I386OP(add_eax_i32), },
{ 0x06, OP_I386, I386OP(push_es16), I386OP(push_es32), },
{ 0x07, OP_I386, I386OP(pop_es16), I386OP(pop_es32), },
{ 0x08, OP_I386, I386OP(or_rm8_r8), I386OP(or_rm8_r8), },
{ 0x09, OP_I386, I386OP(or_rm16_r16), I386OP(or_rm32_r32), },
{ 0x0A, OP_I386, I386OP(or_r8_rm8), I386OP(or_r8_rm8), },
{ 0x0B, OP_I386, I386OP(or_r16_rm16), I386OP(or_r32_rm32), },
{ 0x0C, OP_I386, I386OP(or_al_i8), I386OP(or_al_i8), },
{ 0x0D, OP_I386, I386OP(or_ax_i16), I386OP(or_eax_i32), },
{ 0x0E, OP_I386, I386OP(push_cs16), I386OP(push_cs32), },
{ 0x0F, OP_I386, I386OP(decode_two_byte), I386OP(decode_two_byte), },
{ 0x10, OP_I386, I386OP(adc_rm8_r8), I386OP(adc_rm8_r8), },
{ 0x11, OP_I386, I386OP(adc_rm16_r16), I386OP(adc_rm32_r32), },
{ 0x12, OP_I386, I386OP(adc_r8_rm8), I386OP(adc_r8_rm8), },
{ 0x13, OP_I386, I386OP(adc_r16_rm16), I386OP(adc_r32_rm32), },
{ 0x14, OP_I386, I386OP(adc_al_i8), I386OP(adc_al_i8), },
{ 0x15, OP_I386, I386OP(adc_ax_i16), I386OP(adc_eax_i32), },
{ 0x16, OP_I386, I386OP(push_ss16), I386OP(push_ss32), },
{ 0x17, OP_I386, I386OP(pop_ss16), I386OP(pop_ss32), },
{ 0x18, OP_I386, I386OP(sbb_rm8_r8), I386OP(sbb_rm8_r8), },
{ 0x19, OP_I386, I386OP(sbb_rm16_r16), I386OP(sbb_rm32_r32), },
{ 0x1A, OP_I386, I386OP(sbb_r8_rm8), I386OP(sbb_r8_rm8), },
{ 0x1B, OP_I386, I386OP(sbb_r16_rm16), I386OP(sbb_r32_rm32), },
{ 0x1C, OP_I386, I386OP(sbb_al_i8), I386OP(sbb_al_i8), },
{ 0x1D, OP_I386, I386OP(sbb_ax_i16), I386OP(sbb_eax_i32), },
{ 0x1E, OP_I386, I386OP(push_ds16), I386OP(push_ds32), },
{ 0x1F, OP_I386, I386OP(pop_ds16), I386OP(pop_ds32), },
{ 0x20, OP_I386, I386OP(and_rm8_r8), I386OP(and_rm8_r8), },
{ 0x21, OP_I386, I386OP(and_rm16_r16), I386OP(and_rm32_r32), },
{ 0x22, OP_I386, I386OP(and_r8_rm8), I386OP(and_r8_rm8), },
{ 0x23, OP_I386, I386OP(and_r16_rm16), I386OP(and_r32_rm32), },
{ 0x24, OP_I386, I386OP(and_al_i8), I386OP(and_al_i8), },
{ 0x25, OP_I386, I386OP(and_ax_i16), I386OP(and_eax_i32), },
{ 0x26, OP_I386, I386OP(segment_ES), I386OP(segment_ES), },
{ 0x27, OP_I386, I386OP(daa), I386OP(daa), },
{ 0x28, OP_I386, I386OP(sub_rm8_r8), I386OP(sub_rm8_r8), },
{ 0x29, OP_I386, I386OP(sub_rm16_r16), I386OP(sub_rm32_r32), },
{ 0x2A, OP_I386, I386OP(sub_r8_rm8), I386OP(sub_r8_rm8), },
{ 0x2B, OP_I386, I386OP(sub_r16_rm16), I386OP(sub_r32_rm32), },
{ 0x2C, OP_I386, I386OP(sub_al_i8), I386OP(sub_al_i8), },
{ 0x2D, OP_I386, I386OP(sub_ax_i16), I386OP(sub_eax_i32), },
{ 0x2E, OP_I386, I386OP(segment_CS), I386OP(segment_CS), },
{ 0x2F, OP_I386, I386OP(das), I386OP(das), },
{ 0x30, OP_I386, I386OP(xor_rm8_r8), I386OP(xor_rm8_r8), },
{ 0x31, OP_I386, I386OP(xor_rm16_r16), I386OP(xor_rm32_r32), },
{ 0x32, OP_I386, I386OP(xor_r8_rm8), I386OP(xor_r8_rm8), },
{ 0x33, OP_I386, I386OP(xor_r16_rm16), I386OP(xor_r32_rm32), },
{ 0x34, OP_I386, I386OP(xor_al_i8), I386OP(xor_al_i8), },
{ 0x35, OP_I386, I386OP(xor_ax_i16), I386OP(xor_eax_i32), },
{ 0x36, OP_I386, I386OP(segment_SS), I386OP(segment_SS), },
{ 0x37, OP_I386, I386OP(aaa), I386OP(aaa), },
{ 0x38, OP_I386, I386OP(cmp_rm8_r8), I386OP(cmp_rm8_r8), },
{ 0x39, OP_I386, I386OP(cmp_rm16_r16), I386OP(cmp_rm32_r32), },
{ 0x3A, OP_I386, I386OP(cmp_r8_rm8), I386OP(cmp_r8_rm8), },
{ 0x3B, OP_I386, I386OP(cmp_r16_rm16), I386OP(cmp_r32_rm32), },
{ 0x3C, OP_I386, I386OP(cmp_al_i8), I386OP(cmp_al_i8), },
{ 0x3D, OP_I386, I386OP(cmp_ax_i16), I386OP(cmp_eax_i32), },
{ 0x3E, OP_I386, I386OP(segment_DS), I386OP(segment_DS), },
{ 0x3F, OP_I386, I386OP(aas), I386OP(aas), },
{ 0x40, OP_I386, I386OP(inc_ax), I386OP(inc_eax), },
{ 0x41, OP_I386, I386OP(inc_cx), I386OP(inc_ecx), },
{ 0x42, OP_I386, I386OP(inc_dx), I386OP(inc_edx), },
{ 0x43, OP_I386, I386OP(inc_bx), I386OP(inc_ebx), },
{ 0x44, OP_I386, I386OP(inc_sp), I386OP(inc_esp), },
{ 0x45, OP_I386, I386OP(inc_bp), I386OP(inc_ebp), },
{ 0x46, OP_I386, I386OP(inc_si), I386OP(inc_esi), },
{ 0x47, OP_I386, I386OP(inc_di), I386OP(inc_edi), },
{ 0x48, OP_I386, I386OP(dec_ax), I386OP(dec_eax), },
{ 0x49, OP_I386, I386OP(dec_cx), I386OP(dec_ecx), },
{ 0x4A, OP_I386, I386OP(dec_dx), I386OP(dec_edx), },
{ 0x4B, OP_I386, I386OP(dec_bx), I386OP(dec_ebx), },
{ 0x4C, OP_I386, I386OP(dec_sp), I386OP(dec_esp), },
{ 0x4D, OP_I386, I386OP(dec_bp), I386OP(dec_ebp), },
{ 0x4E, OP_I386, I386OP(dec_si), I386OP(dec_esi), },
{ 0x4F, OP_I386, I386OP(dec_di), I386OP(dec_edi), },
{ 0x50, OP_I386, I386OP(push_ax), I386OP(push_eax), },
{ 0x51, OP_I386, I386OP(push_cx), I386OP(push_ecx), },
{ 0x52, OP_I386, I386OP(push_dx), I386OP(push_edx), },
{ 0x53, OP_I386, I386OP(push_bx), I386OP(push_ebx), },
{ 0x54, OP_I386, I386OP(push_sp), I386OP(push_esp), },
{ 0x55, OP_I386, I386OP(push_bp), I386OP(push_ebp), },
{ 0x56, OP_I386, I386OP(push_si), I386OP(push_esi), },
{ 0x57, OP_I386, I386OP(push_di), I386OP(push_edi), },
{ 0x58, OP_I386, I386OP(pop_ax), I386OP(pop_eax), },
{ 0x59, OP_I386, I386OP(pop_cx), I386OP(pop_ecx), },
{ 0x5A, OP_I386, I386OP(pop_dx), I386OP(pop_edx), },
{ 0x5B, OP_I386, I386OP(pop_bx), I386OP(pop_ebx), },
{ 0x5C, OP_I386, I386OP(pop_sp), I386OP(pop_esp), },
{ 0x5D, OP_I386, I386OP(pop_bp), I386OP(pop_ebp), },
{ 0x5E, OP_I386, I386OP(pop_si), I386OP(pop_esi), },
{ 0x5F, OP_I386, I386OP(pop_di), I386OP(pop_edi), },
{ 0x60, OP_I386, I386OP(pusha), I386OP(pushad), },
{ 0x61, OP_I386, I386OP(popa), I386OP(popad), },
{ 0x62, OP_I386, I386OP(bound_r16_m16_m16), I386OP(bound_r32_m32_m32), },
{ 0x63, OP_I386, I386OP(arpl), I386OP(arpl), },
{ 0x64, OP_I386, I386OP(segment_FS), I386OP(segment_FS), },
{ 0x65, OP_I386, I386OP(segment_GS), I386OP(segment_GS), },
{ 0x66, OP_I386, I386OP(operand_size), I386OP(operand_size), },
{ 0x67, OP_I386, I386OP(address_size), I386OP(address_size), },
{ 0x68, OP_I386, I386OP(push_i16), I386OP(push_i32), },
{ 0x69, OP_I386, I386OP(imul_r16_rm16_i16), I386OP(imul_r32_rm32_i32), },
{ 0x6A, OP_I386, I386OP(push_i8), I386OP(push_i8), },
{ 0x6B, OP_I386, I386OP(imul_r16_rm16_i8), I386OP(imul_r32_rm32_i8), },
{ 0x6C, OP_I386, I386OP(insb), I386OP(insb), },
{ 0x6D, OP_I386, I386OP(insw), I386OP(insd), },
{ 0x6E, OP_I386, I386OP(outsb), I386OP(outsb), },
{ 0x6F, OP_I386, I386OP(outsw), I386OP(outsd), },
{ 0x70, OP_I386, I386OP(jo_rel8), I386OP(jo_rel8), },
{ 0x71, OP_I386, I386OP(jno_rel8), I386OP(jno_rel8), },
{ 0x72, OP_I386, I386OP(jc_rel8), I386OP(jc_rel8), },
{ 0x73, OP_I386, I386OP(jnc_rel8), I386OP(jnc_rel8), },
{ 0x74, OP_I386, I386OP(jz_rel8), I386OP(jz_rel8), },
{ 0x75, OP_I386, I386OP(jnz_rel8), I386OP(jnz_rel8), },
{ 0x76, OP_I386, I386OP(jbe_rel8), I386OP(jbe_rel8), },
{ 0x77, OP_I386, I386OP(ja_rel8), I386OP(ja_rel8), },
{ 0x78, OP_I386, I386OP(js_rel8), I386OP(js_rel8), },
{ 0x79, OP_I386, I386OP(jns_rel8), I386OP(jns_rel8), },
{ 0x7A, OP_I386, I386OP(jp_rel8), I386OP(jp_rel8), },
{ 0x7B, OP_I386, I386OP(jnp_rel8), I386OP(jnp_rel8), },
{ 0x7C, OP_I386, I386OP(jl_rel8), I386OP(jl_rel8), },
{ 0x7D, OP_I386, I386OP(jge_rel8), I386OP(jge_rel8), },
{ 0x7E, OP_I386, I386OP(jle_rel8), I386OP(jle_rel8), },
{ 0x7F, OP_I386, I386OP(jg_rel8), I386OP(jg_rel8), },
{ 0x80, OP_I386, I386OP(group80_8), I386OP(group80_8), },
{ 0x81, OP_I386, I386OP(group81_16), I386OP(group81_32), },
{ 0x82, OP_I386, I386OP(group80_8), I386OP(group80_8), },
{ 0x83, OP_I386, I386OP(group83_16), I386OP(group83_32), },
{ 0x84, OP_I386, I386OP(test_rm8_r8), I386OP(test_rm8_r8), },
{ 0x85, OP_I386, I386OP(test_rm16_r16), I386OP(test_rm32_r32), },
{ 0x86, OP_I386, I386OP(xchg_r8_rm8), I386OP(xchg_r8_rm8), },
{ 0x87, OP_I386, I386OP(xchg_r16_rm16), I386OP(xchg_r32_rm32), },
{ 0x88, OP_I386, I386OP(mov_rm8_r8), I386OP(mov_rm8_r8), },
{ 0x89, OP_I386, I386OP(mov_rm16_r16), I386OP(mov_rm32_r32), },
{ 0x8A, OP_I386, I386OP(mov_r8_rm8), I386OP(mov_r8_rm8), },
{ 0x8B, OP_I386, I386OP(mov_r16_rm16), I386OP(mov_r32_rm32), },
{ 0x8C, OP_I386, I386OP(mov_rm16_sreg), I386OP(mov_rm16_sreg), },
{ 0x8D, OP_I386, I386OP(lea16), I386OP(lea32), },
{ 0x8E, OP_I386, I386OP(mov_sreg_rm16), I386OP(mov_sreg_rm16), },
{ 0x8F, OP_I386, I386OP(pop_rm16), I386OP(pop_rm32), },
{ 0x90, OP_I386, I386OP(nop), I386OP(nop), },
{ 0x91, OP_I386, I386OP(xchg_ax_cx), I386OP(xchg_eax_ecx), },
{ 0x92, OP_I386, I386OP(xchg_ax_dx), I386OP(xchg_eax_edx), },
{ 0x93, OP_I386, I386OP(xchg_ax_bx), I386OP(xchg_eax_ebx), },
{ 0x94, OP_I386, I386OP(xchg_ax_sp), I386OP(xchg_eax_esp), },
{ 0x95, OP_I386, I386OP(xchg_ax_bp), I386OP(xchg_eax_ebp), },
{ 0x96, OP_I386, I386OP(xchg_ax_si), I386OP(xchg_eax_esi), },
{ 0x97, OP_I386, I386OP(xchg_ax_di), I386OP(xchg_eax_edi), },
{ 0x98, OP_I386, I386OP(cbw), I386OP(cwde), },
{ 0x99, OP_I386, I386OP(cwd), I386OP(cdq), },
{ 0x9A, OP_I386, I386OP(call_abs16), I386OP(call_abs32), },
{ 0x9B, OP_I386, I386OP(wait), I386OP(wait), },
{ 0x9C, OP_I386, I386OP(pushf), I386OP(pushfd), },
{ 0x9D, OP_I386, I386OP(popf), I386OP(popfd), },
{ 0x9E, OP_I386, I386OP(sahf), I386OP(sahf), },
{ 0x9F, OP_I386, I386OP(lahf), I386OP(lahf), },
{ 0xA0, OP_I386, I386OP(mov_al_m8), I386OP(mov_al_m8), },
{ 0xA1, OP_I386, I386OP(mov_ax_m16), I386OP(mov_eax_m32), },
{ 0xA2, OP_I386, I386OP(mov_m8_al), I386OP(mov_m8_al), },
{ 0xA3, OP_I386, I386OP(mov_m16_ax), I386OP(mov_m32_eax), },
{ 0xA4, OP_I386, I386OP(movsb), I386OP(movsb), },
{ 0xA5, OP_I386, I386OP(movsw), I386OP(movsd), },
{ 0xA6, OP_I386, I386OP(cmpsb), I386OP(cmpsb), },
{ 0xA7, OP_I386, I386OP(cmpsw), I386OP(cmpsd), },
{ 0xA8, OP_I386, I386OP(test_al_i8), I386OP(test_al_i8), },
{ 0xA9, OP_I386, I386OP(test_ax_i16), I386OP(test_eax_i32), },
{ 0xAA, OP_I386, I386OP(stosb), I386OP(stosb), },
{ 0xAB, OP_I386, I386OP(stosw), I386OP(stosd), },
{ 0xAC, OP_I386, I386OP(lodsb), I386OP(lodsb), },
{ 0xAD, OP_I386, I386OP(lodsw), I386OP(lodsd), },
{ 0xAE, OP_I386, I386OP(scasb), I386OP(scasb), },
{ 0xAF, OP_I386, I386OP(scasw), I386OP(scasd), },
{ 0xB0, OP_I386, I386OP(mov_al_i8), I386OP(mov_al_i8), },
{ 0xB1, OP_I386, I386OP(mov_cl_i8), I386OP(mov_cl_i8), },
{ 0xB2, OP_I386, I386OP(mov_dl_i8), I386OP(mov_dl_i8), },
{ 0xB3, OP_I386, I386OP(mov_bl_i8), I386OP(mov_bl_i8), },
{ 0xB4, OP_I386, I386OP(mov_ah_i8), I386OP(mov_ah_i8), },
{ 0xB5, OP_I386, I386OP(mov_ch_i8), I386OP(mov_ch_i8), },
{ 0xB6, OP_I386, I386OP(mov_dh_i8), I386OP(mov_dh_i8), },
{ 0xB7, OP_I386, I386OP(mov_bh_i8), I386OP(mov_bh_i8), },
{ 0xB8, OP_I386, I386OP(mov_ax_i16), I386OP(mov_eax_i32), },
{ 0xB9, OP_I386, I386OP(mov_cx_i16), I386OP(mov_ecx_i32), },
{ 0xBA, OP_I386, I386OP(mov_dx_i16), I386OP(mov_edx_i32), },
{ 0xBB, OP_I386, I386OP(mov_bx_i16), I386OP(mov_ebx_i32), },
{ 0xBC, OP_I386, I386OP(mov_sp_i16), I386OP(mov_esp_i32), },
{ 0xBD, OP_I386, I386OP(mov_bp_i16), I386OP(mov_ebp_i32), },
{ 0xBE, OP_I386, I386OP(mov_si_i16), I386OP(mov_esi_i32), },
{ 0xBF, OP_I386, I386OP(mov_di_i16), I386OP(mov_edi_i32), },
{ 0xC0, OP_I386, I386OP(groupC0_8), I386OP(groupC0_8), },
{ 0xC1, OP_I386, I386OP(groupC1_16), I386OP(groupC1_32), },
{ 0xC2, OP_I386, I386OP(ret_near16_i16), I386OP(ret_near32_i16), },
{ 0xC3, OP_I386, I386OP(ret_near16), I386OP(ret_near32), },
{ 0xC4, OP_I386, I386OP(les16), I386OP(les32), },
{ 0xC5, OP_I386, I386OP(lds16), I386OP(lds32), },
{ 0xC6, OP_I386, I386OP(mov_rm8_i8), I386OP(mov_rm8_i8), },
{ 0xC7, OP_I386, I386OP(mov_rm16_i16), I386OP(mov_rm32_i32), },
{ 0xC8, OP_I386, I386OP(enter16), I386OP(enter32), },
{ 0xC9, OP_I386, I386OP(leave16), I386OP(leave32), },
{ 0xCA, OP_I386, I386OP(retf_i16), I386OP(retf_i32), },
{ 0xCB, OP_I386, I386OP(retf16), I386OP(retf32), },
{ 0xCC, OP_I386, I386OP(int3), I386OP(int3), },
{ 0xCD, OP_I386, I386OP(int), I386OP(int), },
{ 0xCE, OP_I386, I386OP(into), I386OP(into), },
{ 0xCF, OP_I386, I386OP(iret16), I386OP(iret32), },
{ 0xD0, OP_I386, I386OP(groupD0_8), I386OP(groupD0_8), },
{ 0xD1, OP_I386, I386OP(groupD1_16), I386OP(groupD1_32), },
{ 0xD2, OP_I386, I386OP(groupD2_8), I386OP(groupD2_8), },
{ 0xD3, OP_I386, I386OP(groupD3_16), I386OP(groupD3_32), },
{ 0xD4, OP_I386, I386OP(aam), I386OP(aam), },
{ 0xD5, OP_I386, I386OP(aad), I386OP(aad), },
{ 0xD6, OP_I386, I386OP(setalc), I386OP(setalc), },
{ 0xD7, OP_I386, I386OP(xlat16), I386OP(xlat32), },
{ 0xD8, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xD9, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xDA, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xDB, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xDC, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xDD, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xDE, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xDF, OP_I386, I386OP(escape), I386OP(escape), },
{ 0xD8, OP_FPU, I386OP(fpu_group_d8), I386OP(fpu_group_d8), },
{ 0xD9, OP_FPU, I386OP(fpu_group_d9), I386OP(fpu_group_d9), },
{ 0xDA, OP_FPU, I386OP(fpu_group_da), I386OP(fpu_group_da), },
{ 0xDB, OP_FPU, I386OP(fpu_group_db), I386OP(fpu_group_db), },
{ 0xDC, OP_FPU, I386OP(fpu_group_dc), I386OP(fpu_group_dc), },
{ 0xDD, OP_FPU, I386OP(fpu_group_dd), I386OP(fpu_group_dd), },
{ 0xDE, OP_FPU, I386OP(fpu_group_de), I386OP(fpu_group_de), },
{ 0xDF, OP_FPU, I386OP(fpu_group_df), I386OP(fpu_group_df), },
{ 0xE0, OP_I386, I386OP(loopne16), I386OP(loopne32), },
{ 0xE1, OP_I386, I386OP(loopz16), I386OP(loopz32), },
{ 0xE2, OP_I386, I386OP(loop16), I386OP(loop32), },
{ 0xE3, OP_I386, I386OP(jcxz16), I386OP(jcxz32), },
{ 0xE4, OP_I386, I386OP(in_al_i8), I386OP(in_al_i8), },
{ 0xE5, OP_I386, I386OP(in_ax_i8), I386OP(in_eax_i8), },
{ 0xE6, OP_I386, I386OP(out_al_i8), I386OP(out_al_i8), },
{ 0xE7, OP_I386, I386OP(out_ax_i8), I386OP(out_eax_i8), },
{ 0xE8, OP_I386, I386OP(call_rel16), I386OP(call_rel32), },
{ 0xE9, OP_I386, I386OP(jmp_rel16), I386OP(jmp_rel32), },
{ 0xEA, OP_I386, I386OP(jmp_abs16), I386OP(jmp_abs32), },
{ 0xEB, OP_I386, I386OP(jmp_rel8), I386OP(jmp_rel8), },
{ 0xEC, OP_I386, I386OP(in_al_dx), I386OP(in_al_dx), },
{ 0xED, OP_I386, I386OP(in_ax_dx), I386OP(in_eax_dx), },
{ 0xEE, OP_I386, I386OP(out_al_dx), I386OP(out_al_dx), },
{ 0xEF, OP_I386, I386OP(out_ax_dx), I386OP(out_eax_dx), },
{ 0xF0, OP_I386, I386OP(lock), I386OP(lock), },
{ 0xF1, OP_I386, I386OP(invalid), I386OP(invalid), },
{ 0xF2, OP_I386, I386OP(repne), I386OP(repne), },
{ 0xF3, OP_I386, I386OP(rep), I386OP(rep), },
{ 0xF4, OP_I386, I386OP(hlt), I386OP(hlt), },
{ 0xF5, OP_I386, I386OP(cmc), I386OP(cmc), },
{ 0xF6, OP_I386, I386OP(groupF6_8), I386OP(groupF6_8), },
{ 0xF7, OP_I386, I386OP(groupF7_16), I386OP(groupF7_32), },
{ 0xF8, OP_I386, I386OP(clc), I386OP(clc), },
{ 0xF9, OP_I386, I386OP(stc), I386OP(stc), },
{ 0xFA, OP_I386, I386OP(cli), I386OP(cli), },
{ 0xFB, OP_I386, I386OP(sti), I386OP(sti), },
{ 0xFC, OP_I386, I386OP(cld), I386OP(cld), },
{ 0xFD, OP_I386, I386OP(std), I386OP(std), },
{ 0xFE, OP_I386, I386OP(groupFE_8), I386OP(groupFE_8), },
{ 0xFF, OP_I386, I386OP(groupFF_16), I386OP(groupFF_32), },
{ 0x00, OP_2BYTE|OP_I386, I386OP(group0F00_16), I386OP(group0F00_32), },
{ 0x01, OP_2BYTE|OP_I386, I386OP(group0F01_16), I386OP(group0F01_32), },
{ 0x01, OP_2BYTE|OP_I486, I486OP(group0F01_16), I486OP(group0F01_32), },
{ 0x02, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
{ 0x03, OP_2BYTE|OP_I386, I386OP(lsl_r16_rm16), I386OP(lsl_r32_rm32), },
{ 0x06, OP_2BYTE|OP_I386, I386OP(clts), I386OP(clts), },
{ 0x08, OP_2BYTE|OP_I486, I486OP(invd), I486OP(invd), },
{ 0x09, OP_2BYTE|OP_I486, I486OP(wbinvd), I486OP(wbinvd), },
{ 0x0B, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
{ 0x20, OP_2BYTE|OP_I386, I386OP(mov_r32_cr), I386OP(mov_r32_cr), },
{ 0x21, OP_2BYTE|OP_I386, I386OP(mov_r32_dr), I386OP(mov_r32_dr), },
{ 0x22, OP_2BYTE|OP_I386, I386OP(mov_cr_r32), I386OP(mov_cr_r32), },
{ 0x23, OP_2BYTE|OP_I386, I386OP(mov_dr_r32), I386OP(mov_dr_r32), },
{ 0x24, OP_2BYTE|OP_I386, I386OP(mov_r32_tr), I386OP(mov_r32_tr), },
{ 0x26, OP_2BYTE|OP_I386, I386OP(mov_tr_r32), I386OP(mov_tr_r32), },
{ 0x30, OP_2BYTE|OP_PENTIUM, PENTIUMOP(wrmsr), PENTIUMOP(wrmsr), },
{ 0x31, OP_2BYTE|OP_PENTIUM, PENTIUMOP(rdtsc), PENTIUMOP(rdtsc), },
{ 0x32, OP_2BYTE|OP_PENTIUM, PENTIUMOP(rdmsr), PENTIUMOP(rdmsr), },
{ 0x74, OP_2BYTE|OP_CYRIX, I386OP(cyrix_unknown), I386OP(cyrix_unknown), },
{ 0x80, OP_2BYTE|OP_I386, I386OP(jo_rel16), I386OP(jo_rel32), },
{ 0x81, OP_2BYTE|OP_I386, I386OP(jno_rel16), I386OP(jno_rel32), },
{ 0x82, OP_2BYTE|OP_I386, I386OP(jc_rel16), I386OP(jc_rel32), },
{ 0x83, OP_2BYTE|OP_I386, I386OP(jnc_rel16), I386OP(jnc_rel32), },
{ 0x84, OP_2BYTE|OP_I386, I386OP(jz_rel16), I386OP(jz_rel32), },
{ 0x85, OP_2BYTE|OP_I386, I386OP(jnz_rel16), I386OP(jnz_rel32), },
{ 0x86, OP_2BYTE|OP_I386, I386OP(jbe_rel16), I386OP(jbe_rel32), },
{ 0x87, OP_2BYTE|OP_I386, I386OP(ja_rel16), I386OP(ja_rel32), },
{ 0x88, OP_2BYTE|OP_I386, I386OP(js_rel16), I386OP(js_rel32), },
{ 0x89, OP_2BYTE|OP_I386, I386OP(jns_rel16), I386OP(jns_rel32), },
{ 0x8A, OP_2BYTE|OP_I386, I386OP(jp_rel16), I386OP(jp_rel32), },
{ 0x8B, OP_2BYTE|OP_I386, I386OP(jnp_rel16), I386OP(jnp_rel32), },
{ 0x8C, OP_2BYTE|OP_I386, I386OP(jl_rel16), I386OP(jl_rel32), },
{ 0x8D, OP_2BYTE|OP_I386, I386OP(jge_rel16), I386OP(jge_rel32), },
{ 0x8E, OP_2BYTE|OP_I386, I386OP(jle_rel16), I386OP(jle_rel32), },
{ 0x8F, OP_2BYTE|OP_I386, I386OP(jg_rel16), I386OP(jg_rel32), },
{ 0x90, OP_2BYTE|OP_I386, I386OP(seto_rm8), I386OP(seto_rm8), },
{ 0x91, OP_2BYTE|OP_I386, I386OP(setno_rm8), I386OP(setno_rm8), },
{ 0x92, OP_2BYTE|OP_I386, I386OP(setc_rm8), I386OP(setc_rm8), },
{ 0x93, OP_2BYTE|OP_I386, I386OP(setnc_rm8), I386OP(setnc_rm8), },
{ 0x94, OP_2BYTE|OP_I386, I386OP(setz_rm8), I386OP(setz_rm8), },
{ 0x95, OP_2BYTE|OP_I386, I386OP(setnz_rm8), I386OP(setnz_rm8), },
{ 0x96, OP_2BYTE|OP_I386, I386OP(setbe_rm8), I386OP(setbe_rm8), },
{ 0x97, OP_2BYTE|OP_I386, I386OP(seta_rm8), I386OP(seta_rm8), },
{ 0x98, OP_2BYTE|OP_I386, I386OP(sets_rm8), I386OP(sets_rm8), },
{ 0x99, OP_2BYTE|OP_I386, I386OP(setns_rm8), I386OP(setns_rm8), },
{ 0x9A, OP_2BYTE|OP_I386, I386OP(setp_rm8), I386OP(setp_rm8), },
{ 0x9B, OP_2BYTE|OP_I386, I386OP(setnp_rm8), I386OP(setnp_rm8), },
{ 0x9C, OP_2BYTE|OP_I386, I386OP(setl_rm8), I386OP(setl_rm8), },
{ 0x9D, OP_2BYTE|OP_I386, I386OP(setge_rm8), I386OP(setge_rm8), },
{ 0x9E, OP_2BYTE|OP_I386, I386OP(setle_rm8), I386OP(setle_rm8), },
{ 0x9F, OP_2BYTE|OP_I386, I386OP(setg_rm8), I386OP(setg_rm8), },
{ 0xA0, OP_2BYTE|OP_I386, I386OP(push_fs16), I386OP(push_fs32), },
{ 0xA1, OP_2BYTE|OP_I386, I386OP(pop_fs16), I386OP(pop_fs32), },
{ 0xA2, OP_2BYTE|OP_I486, I486OP(cpuid), I486OP(cpuid), },
{ 0xA3, OP_2BYTE|OP_I386, I386OP(bt_rm16_r16), I386OP(bt_rm32_r32), },
{ 0xA4, OP_2BYTE|OP_I386, I386OP(shld16_i8), I386OP(shld32_i8), },
{ 0xA5, OP_2BYTE|OP_I386, I386OP(shld16_cl), I386OP(shld32_cl), },
{ 0xA8, OP_2BYTE|OP_I386, I386OP(push_gs16), I386OP(push_gs32), },
{ 0xA9, OP_2BYTE|OP_I386, I386OP(pop_gs16), I386OP(pop_gs32), },
{ 0xAA, OP_2BYTE|OP_I386, I386OP(unimplemented), I386OP(unimplemented), },
{ 0xAB, OP_2BYTE|OP_I386, I386OP(bts_rm16_r16), I386OP(bts_rm32_r32), },
{ 0xAC, OP_2BYTE|OP_I386, I386OP(shrd16_i8), I386OP(shrd32_i8), },
{ 0xAD, OP_2BYTE|OP_I386, I386OP(shrd16_cl), I386OP(shrd32_cl), },
{ 0xAE, OP_2BYTE|OP_I386, I386OP(invalid), I386OP(invalid), },
{ 0xAF, OP_2BYTE|OP_I386, I386OP(imul_r16_rm16), I386OP(imul_r32_rm32), },
{ 0xB0, OP_2BYTE|OP_I486, I486OP(cmpxchg_rm8_r8), I486OP(cmpxchg_rm8_r8), },
{ 0xB1, OP_2BYTE|OP_I486, I486OP(cmpxchg_rm16_r16), I486OP(cmpxchg_rm32_r32), },
{ 0xB2, OP_2BYTE|OP_I386, I386OP(lss16), I386OP(lss32), },
{ 0xB3, OP_2BYTE|OP_I386, I386OP(btr_rm16_r16), I386OP(btr_rm32_r32), },
{ 0xB4, OP_2BYTE|OP_I386, I386OP(lfs16), I386OP(lfs32), },
{ 0xB5, OP_2BYTE|OP_I386, I386OP(lgs16), I386OP(lgs32), },
{ 0xB6, OP_2BYTE|OP_I386, I386OP(movzx_r16_rm8), I386OP(movzx_r32_rm8), },
{ 0xB7, OP_2BYTE|OP_I386, I386OP(invalid), I386OP(movzx_r32_rm16), },
{ 0xBA, OP_2BYTE|OP_I386, I386OP(group0FBA_16), I386OP(group0FBA_32), },
{ 0xBB, OP_2BYTE|OP_I386, I386OP(btc_rm16_r16), I386OP(btc_rm32_r32), },
{ 0xBC, OP_2BYTE|OP_I386, I386OP(bsf_r16_rm16), I386OP(bsf_r32_rm32), },
{ 0xBD, OP_2BYTE|OP_I386, I386OP(bsr_r16_rm16), I386OP(bsr_r32_rm32), },
{ 0xBE, OP_2BYTE|OP_I386, I386OP(movsx_r16_rm8), I386OP(movsx_r32_rm8), },
{ 0xBF, OP_2BYTE|OP_I386, I386OP(invalid), I386OP(movsx_r32_rm16), },
{ 0xC0, OP_2BYTE|OP_I486, I486OP(xadd_rm8_r8), I486OP(xadd_rm8_r8), },
{ 0xC1, OP_2BYTE|OP_I486, I486OP(xadd_rm16_r16), I486OP(xadd_rm32_r32), },
{ 0xC7, OP_2BYTE|OP_PENTIUM, PENTIUMOP(cmpxchg8b_m64), PENTIUMOP(cmpxchg8b_m64), },
{ 0xC8, OP_2BYTE|OP_I486, I486OP(bswap_eax), I486OP(bswap_eax), },
{ 0xC9, OP_2BYTE|OP_I486, I486OP(bswap_ecx), I486OP(bswap_ecx), },
{ 0xCA, OP_2BYTE|OP_I486, I486OP(bswap_edx), I486OP(bswap_edx), },
{ 0xCB, OP_2BYTE|OP_I486, I486OP(bswap_ebx), I486OP(bswap_ebx), },
{ 0xCC, OP_2BYTE|OP_I486, I486OP(bswap_esp), I486OP(bswap_esp), },
{ 0xCD, OP_2BYTE|OP_I486, I486OP(bswap_ebp), I486OP(bswap_ebp), },
{ 0xCE, OP_2BYTE|OP_I486, I486OP(bswap_esi), I486OP(bswap_esi), },
{ 0xCF, OP_2BYTE|OP_I486, I486OP(bswap_edi), I486OP(bswap_edi), }
};
File diff suppressed because it is too large. Load diff
+424
View File
@@ -0,0 +1,424 @@
/* Intel 486+ specific opcodes */
static void I486OP(cpuid)(i386_state *cpustate) /* Opcode 0x0F A2 */
{
if (cpustate->cpuid_id0 == 0)
{
/* this 486 doesn't support the CPUID instruction */
logerror("CPUID not supported at %08x!\n", cpustate->eip);
i386_trap(cpustate, 6, 0);
}
else
{
switch (REG32(EAX))
{
case 0:
{
REG32(EAX) = cpustate->cpuid_max_input_value_eax;
REG32(EBX) = cpustate->cpuid_id0;
REG32(ECX) = cpustate->cpuid_id2;
REG32(EDX) = cpustate->cpuid_id1;
CYCLES(cpustate,CYCLES_CPUID);
break;
}
case 1:
{
REG32(EAX) = cpustate->cpu_version;
REG32(EDX) = cpustate->feature_flags;
CYCLES(cpustate,CYCLES_CPUID_EAX1);
break;
}
}
}
}
static void I486OP(invd)(i386_state *cpustate) /* Opcode 0x0f 08 */
{
/* Nothing to do ? */
CYCLES(cpustate,CYCLES_INVD);
}
static void I486OP(wbinvd)(i386_state *cpustate) /* Opcode 0x0f 09 */
{
/* Nothing to do ? */
}
static void I486OP(cmpxchg_rm8_r8)(i386_state *cpustate) /* Opcode 0x0f b0 */
{
UINT8 modrm = FETCH(cpustate);
if( modrm >= 0xc0 ) {
UINT8 dst = LOAD_RM8(modrm);
UINT8 src = LOAD_REG8(modrm);
if( REG8(AL) == dst ) {
STORE_RM8(modrm, src);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
} else {
REG8(AL) = dst;
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
}
} else {
UINT32 ea = GetEA(cpustate,modrm);
UINT8 dst = READ8(cpustate,ea);
UINT8 src = LOAD_REG8(modrm);
if( REG8(AL) == dst ) {
WRITE8(cpustate,modrm, src);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
} else {
REG8(AL) = dst;
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
}
}
}
static void I486OP(cmpxchg_rm16_r16)(i386_state *cpustate) /* Opcode 0x0f b1 */
{
UINT8 modrm = FETCH(cpustate);
if( modrm >= 0xc0 ) {
UINT16 dst = LOAD_RM16(modrm);
UINT16 src = LOAD_REG16(modrm);
if( REG16(AX) == dst ) {
STORE_RM16(modrm, src);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
} else {
REG16(AX) = dst;
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
}
} else {
UINT32 ea = GetEA(cpustate,modrm);
UINT16 dst = READ16(cpustate,ea);
UINT16 src = LOAD_REG16(modrm);
if( REG16(AX) == dst ) {
WRITE16(cpustate,modrm, src);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
} else {
REG16(AX) = dst;
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
}
}
}
static void I486OP(cmpxchg_rm32_r32)(i386_state *cpustate) /* Opcode 0x0f b1 */
{
UINT8 modrm = FETCH(cpustate);
if( modrm >= 0xc0 ) {
UINT32 dst = LOAD_RM32(modrm);
UINT32 src = LOAD_REG32(modrm);
if( REG32(EAX) == dst ) {
STORE_RM32(modrm, src);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T);
} else {
REG32(EAX) = dst;
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F);
}
} else {
UINT32 ea = GetEA(cpustate,modrm);
UINT32 dst = READ32(cpustate,ea);
UINT32 src = LOAD_REG32(modrm);
if( REG32(EAX) == dst ) {
WRITE32(cpustate,ea, src);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
} else {
REG32(EAX) = dst;
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
}
}
}
static void I486OP(xadd_rm8_r8)(i386_state *cpustate) /* Opcode 0x0f c0 */
{
UINT8 modrm = FETCH(cpustate);
if( modrm >= 0xc0 ) {
UINT8 dst = LOAD_RM8(modrm);
UINT8 src = LOAD_REG8(modrm);
STORE_RM16(modrm, dst + src);
STORE_REG16(modrm, dst);
CYCLES(cpustate,CYCLES_XADD_REG_REG);
} else {
UINT32 ea = GetEA(cpustate,modrm);
UINT8 dst = READ8(cpustate,ea);
UINT8 src = LOAD_REG8(modrm);
WRITE8(cpustate,ea, dst + src);
STORE_REG8(modrm, dst);
CYCLES(cpustate,CYCLES_XADD_REG_MEM);
}
}
static void I486OP(xadd_rm16_r16)(i386_state *cpustate) /* Opcode 0x0f c1 */
{
UINT8 modrm = FETCH(cpustate);
if( modrm >= 0xc0 ) {
UINT16 dst = LOAD_RM16(modrm);
UINT16 src = LOAD_REG16(modrm);
STORE_RM16(modrm, dst + src);
STORE_REG16(modrm, dst);
CYCLES(cpustate,CYCLES_XADD_REG_REG);
} else {
UINT32 ea = GetEA(cpustate,modrm);
UINT16 dst = READ16(cpustate,ea);
UINT16 src = LOAD_REG16(modrm);
WRITE16(cpustate,ea, dst + src);
STORE_REG16(modrm, dst);
CYCLES(cpustate,CYCLES_XADD_REG_MEM);
}
}
static void I486OP(xadd_rm32_r32)(i386_state *cpustate) /* Opcode 0x0f c1 */
{
UINT8 modrm = FETCH(cpustate);
if( modrm >= 0xc0 ) {
UINT32 dst = LOAD_RM32(modrm);
UINT32 src = LOAD_REG32(modrm);
STORE_RM32(modrm, dst + src);
STORE_REG32(modrm, dst);
CYCLES(cpustate,CYCLES_XADD_REG_REG);
} else {
UINT32 ea = GetEA(cpustate,modrm);
UINT32 dst = READ32(cpustate,ea);
UINT32 src = LOAD_REG32(modrm);
WRITE32(cpustate,ea, dst + src);
STORE_REG32(modrm, dst);
CYCLES(cpustate,CYCLES_XADD_REG_MEM);
}
}
static void I486OP(group0F01_16)(i386_state *cpustate) /* Opcode 0x0f 01 */
{
UINT8 modrm = FETCH(cpustate);
UINT16 address;
UINT32 ea;
switch( (modrm >> 3) & 0x7 )
{
case 0: /* SGDT */
{
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate( cpustate, CS, address );
} else {
ea = GetEA(cpustate,modrm);
}
WRITE16(cpustate,ea, cpustate->gdtr.limit);
WRITE32(cpustate,ea + 2, cpustate->gdtr.base & 0xffffff);
CYCLES(cpustate,CYCLES_SGDT);
break;
}
case 1: /* SIDT */
{
if (modrm >= 0xc0)
{
address = LOAD_RM16(modrm);
ea = i386_translate( cpustate, CS, address );
}
else
{
ea = GetEA(cpustate,modrm);
}
WRITE16(cpustate,ea, cpustate->idtr.limit);
WRITE32(cpustate,ea + 2, cpustate->idtr.base & 0xffffff);
CYCLES(cpustate,CYCLES_SIDT);
break;
}
case 2: /* LGDT */
{
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate( cpustate, CS, address );
} else {
ea = GetEA(cpustate,modrm);
}
cpustate->gdtr.limit = READ16(cpustate,ea);
cpustate->gdtr.base = READ32(cpustate,ea + 2) & 0xffffff;
CYCLES(cpustate,CYCLES_LGDT);
break;
}
case 3: /* LIDT */
{
if( modrm >= 0xc0 ) {
address = LOAD_RM16(modrm);
ea = i386_translate( cpustate, CS, address );
} else {
ea = GetEA(cpustate,modrm);
}
cpustate->idtr.limit = READ16(cpustate,ea);
cpustate->idtr.base = READ32(cpustate,ea + 2) & 0xffffff;
CYCLES(cpustate,CYCLES_LIDT);
break;
}
case 4: /* SMSW */
{
if( modrm >= 0xc0 ) {
STORE_RM16(modrm, cpustate->cr[0]);
CYCLES(cpustate,CYCLES_SMSW_REG);
} else {
ea = GetEA(cpustate,modrm);
WRITE16(cpustate,ea, cpustate->cr[0]);
CYCLES(cpustate,CYCLES_SMSW_MEM);
}
break;
}
case 6: /* LMSW */
{
/* TODO: Check for protection fault */
UINT8 b;
if( modrm >= 0xc0 ) {
b = LOAD_RM8(modrm);
CYCLES(cpustate,CYCLES_LMSW_REG);
} else {
ea = GetEA(cpustate,modrm);
CYCLES(cpustate,CYCLES_LMSW_MEM);
b = READ8(cpustate,ea);
}
cpustate->cr[0] &= ~0x03;
cpustate->cr[0] |= b & 0x03;
break;
}
case 7: /* INVLPG */
{
/* Nothing to do ? */
break;
}
default:
i386_fatal("i486: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, cpustate->eip - 2);
break;
}
}
static void I486OP(group0F01_32)(i386_state *cpustate) /* Opcode 0x0f 01 */
{
UINT8 modrm = FETCH(cpustate);
UINT32 address, ea;
switch( (modrm >> 3) & 0x7 )
{
case 0: /* SGDT */
{
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
ea = i386_translate( cpustate, CS, address );
} else {
ea = GetEA(cpustate,modrm);
}
WRITE16(cpustate,ea, cpustate->gdtr.limit);
WRITE32(cpustate,ea + 2, cpustate->gdtr.base);
CYCLES(cpustate,CYCLES_SGDT);
break;
}
case 1: /* SIDT */
{
if (modrm >= 0xc0)
{
address = LOAD_RM32(modrm);
ea = i386_translate( cpustate, CS, address );
}
else
{
ea = GetEA(cpustate,modrm);
}
WRITE16(cpustate,ea, cpustate->idtr.limit);
WRITE32(cpustate,ea + 2, cpustate->idtr.base);
CYCLES(cpustate,CYCLES_SIDT);
break;
}
case 2: /* LGDT */
{
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
ea = i386_translate( cpustate, CS, address );
} else {
ea = GetEA(cpustate,modrm);
}
cpustate->gdtr.limit = READ16(cpustate,ea);
cpustate->gdtr.base = READ32(cpustate,ea + 2);
CYCLES(cpustate,CYCLES_LGDT);
break;
}
case 3: /* LIDT */
{
if( modrm >= 0xc0 ) {
address = LOAD_RM32(modrm);
ea = i386_translate( cpustate, CS, address );
} else {
ea = GetEA(cpustate,modrm);
}
cpustate->idtr.limit = READ16(cpustate,ea);
cpustate->idtr.base = READ32(cpustate,ea + 2);
CYCLES(cpustate,CYCLES_LIDT);
break;
}
case 7: /* INVLPG */
{
/* Nothing to do ? */
break;
}
default:
i386_fatal("i486: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, cpustate->eip - 2);
break;
}
}
static void I486OP(bswap_eax)(i386_state *cpustate) /* Opcode 0x0f 38 */
{
REG32(EAX) = SWITCH_ENDIAN_32(REG32(EAX));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_ecx)(i386_state *cpustate) /* Opcode 0x0f 39 */
{
REG32(ECX) = SWITCH_ENDIAN_32(REG32(ECX));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_edx)(i386_state *cpustate) /* Opcode 0x0f 3A */
{
REG32(EDX) = SWITCH_ENDIAN_32(REG32(EDX));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_ebx)(i386_state *cpustate) /* Opcode 0x0f 3B */
{
REG32(EBX) = SWITCH_ENDIAN_32(REG32(EBX));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_esp)(i386_state *cpustate) /* Opcode 0x0f 3C */
{
REG32(ESP) = SWITCH_ENDIAN_32(REG32(ESP));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_ebp)(i386_state *cpustate) /* Opcode 0x0f 3D */
{
REG32(EBP) = SWITCH_ENDIAN_32(REG32(EBP));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_esi)(i386_state *cpustate) /* Opcode 0x0f 3E */
{
REG32(ESI) = SWITCH_ENDIAN_32(REG32(ESI));
CYCLES(cpustate,1); /* TODO */
}
static void I486OP(bswap_edi)(i386_state *cpustate) /* Opcode 0x0f 3F */
{
REG32(EDI) = SWITCH_ENDIAN_32(REG32(EDI));
CYCLES(cpustate,1); /* TODO */
}
+53
View File
@@ -0,0 +1,53 @@
/* Pentium+ specific opcodes */
static void PENTIUMOP(rdmsr)(i386_state *cpustate) /* Opcode 0x0f 32 */
{
/* TODO */
CYCLES(cpustate,CYCLES_RDMSR);
}
static void PENTIUMOP(wrmsr)(i386_state *cpustate) /* Opcode 0x0f 30 */
{
/* TODO */
CYCLES(cpustate,1); /* TODO: correct cycle count */
}
static void PENTIUMOP(rdtsc)(i386_state *cpustate) /* Opcode 0x0f 31 */
{
UINT64 ts = cpustate->tsc + (cpustate->base_cycles - i386_ICount);
REG32(EAX) = (UINT32)(ts);
REG32(EDX) = (UINT32)(ts >> 32);
CYCLES(cpustate,CYCLES_RDTSC);
}
static void I386OP(cyrix_unknown)(i386_state *cpustate) /* Opcode 0x0f 74 */
{
CYCLES(cpustate,1);
}
static void PENTIUMOP(cmpxchg8b_m64)(i386_state *cpustate) /* Opcode 0x0f c7 */
{
UINT8 modm = FETCH(cpustate);
if( modm >= 0xc0 ) {
i386_fatal("pentium: cmpxchg8b_m64 - invalid modm");
} else {
UINT32 ea = GetEA(cpustate,modm);
UINT64 value = READ64(cpustate,ea);
UINT64 edx_eax = (((UINT64) REG32(EDX)) << 32) | REG32(EAX);
UINT64 ecx_ebx = (((UINT64) REG32(ECX)) << 32) | REG32(EBX);
if( value == edx_eax ) {
WRITE64(cpustate,ea, ecx_ebx);
cpustate->ZF = 1;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T);
} else {
REG32(EDX) = (UINT32) (value >> 32);
REG32(EAX) = (UINT32) (value >> 0);
cpustate->ZF = 0;
CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F);
}
}
}
+352
View File
@@ -0,0 +1,352 @@
/* Intel x87 FPU opcodes */
#define ST(x) (cpustate->fpu_reg[(cpustate->fpu_top + (x)) & 7])
#define FPU_INFINITY_DOUBLE COMBINE_64_32_32(0x7ff00000, 0x00000000)
#define FPU_INFINITY_SINGLE (0x7f800000)
#define FPU_SIGN_BIT_DOUBLE COMBINE_64_32_32(0x80000000, 0x00000000)
#define FPU_SIGN_BIT_SINGLE (0x80000000)
/* FPU control word flags */
#define FPU_MASK_INVALID_OP 0x0001
#define FPU_MASK_DENORMAL_OP 0x0002
#define FPU_MASK_ZERO_DIVIDE 0x0004
#define FPU_MASK_OVERFLOW 0x0008
#define FPU_MASK_UNDERFLOW 0x0010
#define FPU_MASK_PRECISION 0x0020
/* FPU status word flags */
#define FPU_BUSY 0x8000
#define FPU_C3 0x4000
#define FPU_STACK_TOP_MASK 0x3800
#define FPU_C2 0x0400
#define FPU_C1 0x0200
#define FPU_C0 0x0100
#define FPU_ERROR_SUMMARY 0x0080
#define FPU_STACK_FAULT 0x0040
#define FPU_EXCEPTION_PRECISION 0x0020
#define FPU_EXCEPTION_UNDERFLOW 0x0010
#define FPU_EXCEPTION_OVERFLOW 0x0008
#define FPU_EXCEPTION_ZERO_DIVIDE 0x0004
#define FPU_EXCEPTION_DENORMAL_OP 0x0002
#define FPU_EXCEPTION_INVALID_OP 0x0001
static INLINE void FPU_PUSH(i386_state *cpustate, X87_REG value)
{
cpustate->fpu_top--;
if (cpustate->fpu_top < 0)
{
cpustate->fpu_top = 7;
}
cpustate->fpu_reg[cpustate->fpu_top] = value;
}
static INLINE X87_REG FPU_POP(i386_state *cpustate)
{
X87_REG value = cpustate->fpu_reg[cpustate->fpu_top];
cpustate->fpu_tag_word |= 3 << (cpustate->fpu_top * 2); /* set FPU register tag to 3 (empty) */
cpustate->fpu_top++;
if (cpustate->fpu_top > 7)
{
cpustate->fpu_top = 0;
}
return value;
}
static void I386OP(fpu_group_d8)(i386_state *cpustate) /* Opcode 0xd8 */
{
UINT8 modrm = FETCH(cpustate);
i386_fatal("I386: FPU Op D8 %02X at %08X", modrm, cpustate->pc-2);
}
static void I386OP(fpu_group_d9)(i386_state *cpustate) /* Opcode 0xd9 */
{
UINT8 modrm = FETCH(cpustate);
if (modrm < 0xc0)
{
UINT32 ea = GetEA(cpustate,modrm);
switch ((modrm >> 3) & 0x7)
{
case 5: /* FLDCW */
{
cpustate->fpu_control_word = READ16(cpustate,ea);
CYCLES(cpustate,1); /* TODO */
break;
}
case 7: /* FSTCW */
{
WRITE16(cpustate,ea, cpustate->fpu_control_word);
CYCLES(cpustate,1); /* TODO */
break;
}
default:
i386_fatal("I386: FPU Op D9 %02X at %08X", modrm, cpustate->pc-2);
}
}
else
{
switch (modrm & 0x3f)
{
/* FLD */
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
{
X87_REG t = ST(modrm & 7);
FPU_PUSH(cpustate,t);
CYCLES(cpustate,1); /* TODO */
break;
}
case 0x20: /* FCHS */
{
ST(0).i ^= FPU_SIGN_BIT_DOUBLE;
CYCLES(cpustate,1); /* TODO */
break;
}
case 0x28: /* FLD1 */
{
X87_REG t;
t.f = 1.0;
FPU_PUSH(cpustate,t);
CYCLES(cpustate,1); /* TODO */
break;
}
case 0x2e: /* FLDZ */
{
X87_REG t;
t.f = 0.0;
FPU_PUSH(cpustate,t);
CYCLES(cpustate,1); /* TODO */
break;
}
default:
i386_fatal("I386: FPU Op D9 %02X at %08X", modrm, cpustate->pc-2);
}
}
}
static void I386OP(fpu_group_da)(i386_state *cpustate) /* Opcode 0xda */
{
UINT8 modrm = FETCH(cpustate);
i386_fatal("I386: FPU Op DA %02X at %08X", modrm, cpustate->pc-2);
}
static void I386OP(fpu_group_db)(i386_state *cpustate) /* Opcode 0xdb */
{
UINT8 modrm = FETCH(cpustate);
if (modrm < 0xc0)
{
i386_fatal("I386: FPU Op DB %02X at %08X", modrm, cpustate->pc-2);
}
else
{
switch (modrm & 0x3f)
{
case 0x23: /* FINIT */
{
cpustate->fpu_control_word = 0x37f;
cpustate->fpu_status_word = 0;
cpustate->fpu_tag_word = 0xffff;
cpustate->fpu_data_ptr = 0;
cpustate->fpu_inst_ptr = 0;
cpustate->fpu_opcode = 0;
CYCLES(cpustate,1); /* TODO */
break;
}
case 0x24: /* FSETPM (treated as nop on 387+) */
{
CYCLES(cpustate,1);
break;
}
default:
i386_fatal("I386: FPU Op DB %02X at %08X", modrm, cpustate->pc-2);
}
}
}
static void I386OP(fpu_group_dc)(i386_state *cpustate) /* Opcode 0xdc */
{
UINT8 modrm = FETCH(cpustate);
if (modrm < 0xc0)
{
/*UINT32 ea = GetEA(cpustate,modrm); */
switch ((modrm >> 3) & 0x7)
{
default:
i386_fatal("I386: FPU Op DC %02X at %08X", modrm, cpustate->pc-2);
}
}
else
{
switch (modrm & 0x3f)
{
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
{
/* FDIVR */
if ((ST(modrm & 7).i & COMBINE_64_32_32(0x7fffffff, 0xffffffff)) == 0)
{
/* set result as infinity if zero divide is masked */
if (cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
{
ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
}
}
else
{
ST(modrm & 7).f = ST(0).f / ST(modrm & 7).f;
}
CYCLES(cpustate,1); /* TODO */
break;
}
default:
i386_fatal("I386: FPU Op DC %02X at %08X", modrm, cpustate->pc-2);
}
}
}
static void I386OP(fpu_group_dd)(i386_state *cpustate) /* Opcode 0xdd */
{
UINT8 modrm = FETCH(cpustate);
if (modrm < 0xc0)
{
UINT32 ea = GetEA(cpustate,modrm);
switch ((modrm >> 3) & 0x7)
{
case 7: /* FSTSW */
{
WRITE16(cpustate,ea, (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10));
CYCLES(cpustate,1); /* TODO */
break;
}
default:
i386_fatal("I386: FPU Op DD %02X at %08X", modrm, cpustate->pc-2);
}
}
else
{
switch (modrm & 0x3f)
{
default:
i386_fatal("I386: FPU Op DD %02X at %08X", modrm, cpustate->pc-2);
}
}
}
static void I386OP(fpu_group_de)(i386_state *cpustate) /* Opcode 0xde */
{
UINT8 modrm = FETCH(cpustate);
if (modrm < 0xc0)
{
/* UINT32 ea = GetEA(cpustate,modrm); */
switch ((modrm >> 3) & 0x7)
{
default:
i386_fatal("I386: FPU Op DE %02X at %08X", modrm, cpustate->pc-2);
}
}
else
{
switch (modrm & 0x3f)
{
case 0x19: /* FCOMPP */
{
cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
if (ST(0).f > ST(1).f)
{
/* C3 = 0, C2 = 0, C0 = 0 */
}
else if (ST(0).f < ST(1).f)
{
cpustate->fpu_status_word |= FPU_C0;
}
else if (ST(0).f == ST(1).f)
{
cpustate->fpu_status_word |= FPU_C3;
}
else
{
/* unordered */
cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
}
FPU_POP(cpustate);
FPU_POP(cpustate);
CYCLES(cpustate,1); /* TODO */
break;
}
/* FDIVP */
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
{
if ((ST(0).i & COMBINE_64_32_32(0x7fffffff, 0xffffffff)) == 0)
{
/* set result as infinity if zero divide is masked */
if (cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
{
ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
}
}
else
{
ST(modrm & 7).f = ST(modrm & 7).f / ST(0).f;
}
FPU_POP(cpustate);
CYCLES(cpustate,1); /* TODO */
break;
}
default:
i386_fatal("I386: FPU Op DE %02X at %08X", modrm, cpustate->pc-2);
}
}
}
static void I386OP(fpu_group_df)(i386_state *cpustate) /* Opcode 0xdf */
{
UINT8 modrm = FETCH(cpustate);
if (modrm < 0xc0)
{
/* UINT32 ea = GetEA(cpustate,modrm); */
switch ((modrm >> 3) & 0x7)
{
default:
i386_fatal("I386: FPU Op DF %02X at %08X", modrm, cpustate->pc-2);
}
}
else
{
switch (modrm & 0x3f)
{
case 0x20: /* FSTSW AX */
{
REG16(AX) = (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10);
CYCLES(cpustate,1); /* TODO */
break;
}
default:
i386_fatal("I386: FPU Op DF %02X at %08X", modrm, cpustate->pc-2);
}
}
}
File diff suppressed because it is too large. Load diff
+104
View File
@@ -0,0 +1,104 @@
/*****************************************************************************
*
* i8051.h
* Portable MCS-51 Family Emulator
*
* Copyright Steve Ellenoff, all rights reserved.
*
* - This source code is released as freeware for non-commercial purposes.
* - You are free to use and redistribute this code in modified or
* unmodified form, provided you list me in the credits.
* - If you modify this source code, you must add a notice to each modified
* source file that it has been changed. If you're a nice person, you
* will clearly mark each change too. :)
* - If you wish to use this for commercial purposes, please contact me at
* sellenoff@hotmail.com
* - The author of this copywritten work reserves the right to change the
* terms of its usage and license at any time, including retroactively
* - This entire notice must remain in the source code.
*
* October 2008, Couriersud: Major rewrite (MAME 0.128-0.139 mcs51 core)
*
* MODIFIED for mame2003-plus: backported from MAME 0.139 src/emu/cpu/mcs51
* to the MAME 0.78 cpu_interface. DS5002FP and 80C52 variants removed,
* internal RAM/SFRs kept inside the CPU context, MOVX routed through
* per-CPU driver handlers (the 0.78 core has no DATA address space).
*
*****************************************************************************/
#ifndef _I8051_H
#define _I8051_H
#include "cpuintrf.h"
#include "osd_cpu.h"
#include "memory.h"
/* The MCS-51 runs one machine cycle every 12 oscillator clocks.
Give the CPU clock in the machine driver as XTAL / I8051_CLOCK_DIVIDER. */
#define I8051_CLOCK_DIVIDER 12
/****************************************************************************
* Input lines (use with cpu_set_irq_line)
* INT0/INT1 follow the TCON IT0/IT1 setting (edge or level);
* T0/T1 count 0->1 transitions when the timer is in counter mode,
* so drive them with PULSE_LINE.
****************************************************************************/
enum
{
I8051_INT0_LINE = 0, /* P3.2: External Interrupt 0 */
I8051_INT1_LINE, /* P3.3: External Interrupt 1 */
I8051_RX_LINE, /* P3.0: Serial Port Receive Line */
I8051_T0_LINE, /* P3.4: Timer 0 External Input */
I8051_T1_LINE, /* P3.5: Timer 1 External Input */
I8051_INPUT_LINES
};
/****************************************************************************
* Port space: the four parallel ports. Map them in the MCU's
* PORT_READ/PORT_WRITE tables, e.g. { I8051_P1, I8051_P1, mcu_p1_w }
****************************************************************************/
#define I8051_P0 0x00
#define I8051_P1 0x01
#define I8051_P2 0x02
#define I8051_P3 0x03
/****************************************************************************
* Registers
****************************************************************************/
enum
{
I8051_PC=1, I8051_SP, I8051_PSW, I8051_ACC, I8051_B, I8051_DPH, I8051_DPL, I8051_IE,
I8051_R0, I8051_R1, I8051_R2, I8051_R3, I8051_R4, I8051_R5, I8051_R6, I8051_R7, I8051_RB
};
/****************************************************************************
* Public functions
****************************************************************************/
extern int i8051_ICount;
extern void i8051_init(void);
extern void i8051_reset(void *param);
extern void i8051_exit(void);
extern int i8051_execute(int cycles);
extern unsigned i8051_get_context(void *dst);
extern void i8051_set_context(void *src);
extern unsigned i8051_get_reg(int regnum);
extern void i8051_set_reg(int regnum, unsigned val);
extern void i8051_set_irq_line(int irqline, int state);
extern void i8051_set_irq_callback(int (*callback)(int irqline));
extern const char *i8051_info(void *context, int regnum);
extern unsigned i8051_dasm(char *buffer, unsigned pc);
/* External data memory (MOVX). Called from MACHINE_INIT; cpunum is the MCU's
CPU index. Unmapped reads return 0xff, unmapped writes are dropped. */
extern void i8051_set_movx_handlers(int cpunum, read8_handler rd, write8_handler wr);
/* Serial port hooks (optional). */
extern void i8051_set_serial_tx_callback(int cpunum, void (*callback)(int data));
extern void i8051_set_serial_rx_callback(int cpunum, int (*callback)(void));
/* The 8751 is an 8051 with internal EPROM: the driver loads the dump in the
MCU's CPU region exactly as for the 8051. */
#define CPU_I8751 CPU_I8051
#endif /* _I8051_H */
+981
View File
@@ -0,0 +1,981 @@
/* MODIFIED for mame2003-plus: C89 comments, device reference removed (backport of MAME 0.139 mcs51ops.c) */
/*******************************************************************************************
NOTE: All registers are accessed directly, instead of using the SFR_R() function for speed
Direct register access is availabe from the R_(register name) macros.. ex: ACC for the ACC
with the exception of the PC
********************************************************************************************/
/*ACALL code addr 1: aaa1 0001 */
OPHANDLER( acall )
{
UINT8 addr = ROP_ARG(PC++); /*Grab code address byte */
PUSH_PC(); /*Save PC to the stack */
/*Thanks Gerrit for help with this! :) */
PC = (PC & 0xf800) | ((r & 0xe0) << 3) | addr;
}
/*ADD A, #data 1: 0010 0100 */
OPHANDLER( add_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
UINT8 result = ACC + data; /*Add data to accumulator */
DO_ADD_FLAGS(ACC,data,0); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADD A, data addr 1: 0010 0101 */
OPHANDLER( add_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
UINT8 result = ACC + data; /*Add data to accumulator */
DO_ADD_FLAGS(ACC,data,0); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADD A, @R0/@R1 1: 0010 011i */
OPHANDLER( add_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data from memory pointed to by R0 or R1 */
UINT8 result = ACC + data; /*Add data to accumulator */
DO_ADD_FLAGS(ACC,data,0); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADD A, R0 to R7 1: 0010 1rrr */
OPHANDLER( add_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0 - R7 */
UINT8 result = ACC + data; /*Add data to accumulator */
DO_ADD_FLAGS(ACC,data,0); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADDC A, #data 1: 0011 0100 */
OPHANDLER( addc_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
UINT8 result = ACC + data + GET_CY; /*Add data + carry flag to accumulator */
DO_ADD_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADDC A, data addr 1: 0011 0101 */
OPHANDLER( addc_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
UINT8 result = ACC + data + GET_CY; /*Add data + carry flag to accumulator */
DO_ADD_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADDC A, @R0/@R1 1: 0011 011i */
OPHANDLER( addc_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data from memory pointed to by R0 or R1 */
UINT8 result = ACC + data + GET_CY; /*Add data + carry flag to accumulator */
DO_ADD_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*ADDC A, R0 to R7 1: 0011 1rrr */
OPHANDLER( addc_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0 - R7 */
UINT8 result = ACC + data + GET_CY; /*Add data + carry flag to accumulator */
DO_ADD_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*AJMP code addr 1: aaa0 0001 */
OPHANDLER( ajmp )
{
UINT8 addr = ROP_ARG(PC++); /*Grab code address byte */
/*Thanks Gerrit for help with this! :) */
PC = (PC & 0xf800) | ((r & 0xe0) << 3) | addr;
}
/*ANL data addr, A 1: 0101 0010 */
OPHANDLER( anl_mem_a )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
IRAM_W(addr,data & ACC); /*Set data address value to it's value Logical AND with ACC */
}
/*ANL data addr, #data 1: 0101 0011 */
OPHANDLER( anl_mem_byte )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = ROP_ARG(PC++); /*Grab data */
UINT8 srcdata = IRAM_R(addr); /*Grab data from data address */
IRAM_W(addr,srcdata & data); /*Set data address value to it's value Logical AND with Data */
}
/*ANL A, #data 1: 0101 0100 */
OPHANDLER( anl_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
SET_ACC(ACC & data); /*Set ACC to value of ACC Logical AND with Data */
}
/*ANL A, data addr 1: 0101 0101 */
OPHANDLER( anl_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
SET_ACC(ACC & data); /*Set ACC to value of ACC Logical AND with Data */
}
/*ANL A, @RO/@R1 1: 0101 011i */
OPHANDLER( anl_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data from address R0 or R1 points to */
SET_ACC(ACC & data); /*Set ACC to value of ACC Logical AND with Data */
}
/*ANL A, RO to R7 1: 0101 1rrr */
OPHANDLER( anl_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0 - R7 */
SET_ACC(ACC & data); /*Set ACC to value of ACC Logical AND with Data */
}
/*ANL C, bit addr 1: 1000 0010 */
OPHANDLER( anl_c_bitaddr )
{
int cy = GET_CY;
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
UINT8 bit = BIT_R(addr); /*Grab bit data from bit address */
SET_CY( (cy & bit) ); /*Set Carry flag to Carry Flag Value Logical AND with Bit */
}
/*ANL C,/bit addr 1: 1011 0000 */
OPHANDLER( anl_c_nbitaddr )
{
int cy = GET_CY;
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
UINT8 bit = BIT_R(addr); /*Grab bit data from bit address */
bit = ((~bit)&1); /*Complement bit */
SET_CY( (cy & bit) ); /*Set Carry flag to Carry Flag Value Logical AND with Complemented Bit */
}
/*CJNE A, #data, code addr 1: 1011 0100 */
OPHANDLER( cjne_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(ACC != data) /*Jump if values are not equal */
{
PC = PC + rel_addr;
}
/*Set carry flag to 1 if 1st compare value is < 2nd compare value */
SET_CY( (ACC < data) );
}
/*CJNE A, data addr, code addr 1: 1011 0101 */
OPHANDLER( cjne_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
UINT8 data = IRAM_R(addr); /*Pull value from data address */
if(ACC != data) /*Jump if values are not equal */
{
PC = PC + rel_addr;
}
/*Set carry flag to 1 if 1st compare value is < 2nd compare value */
SET_CY( (ACC < data) );
}
/*CJNE @R0/@R1, #data, code addr 1: 1011 011i */
OPHANDLER( cjne_ir_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
UINT8 srcdata = IRAM_IR(R_REG(r)); /*Grab value pointed to by R0 or R1 */
if(srcdata != data) /*Jump if values are not equal */
{
PC = PC + rel_addr;
}
/*Set carry flag to 1 if 1st compare value is < 2nd compare value */
SET_CY( (srcdata < data) );
}
/*CJNE R0 to R7, #data, code addr 1: 1011 1rrr */
OPHANDLER( cjne_r_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
UINT8 srcdata = R_REG(r); /*Grab value of R0 - R7 */
if(srcdata != data) /*Jump if values are not equal */
{
PC = PC + rel_addr;
}
/*Set carry flag to 1 if 1st compare value is < 2nd compare value */
SET_CY( (srcdata < data) );
}
/*CLR bit addr 1: 1100 0010 */
OPHANDLER( clr_bitaddr )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
BIT_W(addr,0); /*Clear bit at specified bit address */
}
/*CLR C 1: 1100 0011 */
OPHANDLER( clr_c )
{
SET_CY(0); /*Clear Carry Flag */
}
/*CLR A 1: 1110 0100 */
OPHANDLER( clr_a )
{
SET_ACC(0); /*Clear Accumulator */
}
/*CPL bit addr 1: 1011 0010 */
OPHANDLER( cpl_bitaddr )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
UINT8 data = (~BIT_R(addr))&1;
BIT_W(addr,data); /*Complement bit at specified bit address */
}
/*CPL C 1: 1011 0011 */
OPHANDLER( cpl_c )
{
UINT8 bit = (~GET_CY)&1; /*Complement Carry Flag */
SET_CY(bit);
}
/*CPL A 1: 1111 0100 */
OPHANDLER( cpl_a )
{
UINT8 data = ((~ACC)&0xff);
SET_ACC(data); /*Complement Accumulator */
}
/*DA A 1: 1101 0100 */
OPHANDLER( da_a )
{
/*From several sources, since none said the same thing:
The decimal adjust instruction is associated with the use of the ADD and ADDC instructions.
The eight-bit value in the accumulator is adjusted to form two BCD digits of four bits each.
If the accumulator contents bits 0-3 are greater than 9, OR the AC flag is set, then six is added to
produce a proper BCD digit.
If the carry is set, OR the four high bits 4-7 exceed nine, six is added to the value of these bits.
The carry flag will be set if the result is > 0x99, but not cleared otherwise */
UINT16 new_acc = ACC & 0xff;
if(GET_AC || (new_acc & 0x0f) > 0x09)
new_acc += 0x06;
if(GET_CY || ((new_acc & 0xf0) > 0x90) || (new_acc & ~0xff))
new_acc += 0x60;
SET_ACC(new_acc&0xff);
if(new_acc & ~0xff)
SET_CY(1);
}
/*DEC A 1: 0001 0100 */
OPHANDLER( dec_a )
{
SET_ACC(ACC-1);
}
/*DEC data addr 1: 0001 0101 */
OPHANDLER( dec_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr);
IRAM_W(addr,data-1);
}
/*DEC @R0/@R1 1: 0001 011i */
OPHANDLER( dec_ir )
{
UINT8 data = IRAM_IR(R_REG(r));
IRAM_W(R_REG(r),data-1);
}
/*DEC R0 to R7 1: 0001 1rrr */
OPHANDLER( dec_r )
{
SET_REG(r, R_REG(r) - 1);
}
/*DIV AB 1: 1000 0100 */
OPHANDLER( div_ab )
{
if( B == 0 ) {
/*Overflow flag is set! */
SET_OV(1);
/*Really the values are undefined according to the manual, but we'll just leave them as is.. */
/*SET_ACC(0xff); */
/*SFR_W(B,0xff); */
}
else {
int a = (int)ACC / B;
int b = (int)ACC % B;
/*A gets quotient byte, B gets remainder byte */
SET_ACC(a);
B = b;
/*Overflow flag is cleared */
SET_OV(0);
}
/*Carry Flag is always cleared */
SET_CY(0);
}
/*DJNZ data addr, code addr 1: 1101 0101 */
OPHANDLER( djnz_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
IRAM_W(addr,IRAM_R(addr) - 1); /*Decrement value contained at data address */
if(IRAM_R(addr) != 0) /*Branch if contents of data address is not 0 */
{
PC = PC + rel_addr;
}
}
/*DJNZ R0 to R7,code addr 1: 1101 1rrr */
OPHANDLER( djnz_r )
{
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
SET_REG(r ,R_REG(r) - 1); /*Decrement value */
if(R_REG(r) != 0) /*Branch if contents of R0 - R7 is not 0 */
{
PC = PC + rel_addr;
}
}
/*INC A 1: 0000 0100 */
OPHANDLER( inc_a )
{
SET_ACC(ACC+1);
}
/*INC data addr 1: 0000 0101 */
OPHANDLER( inc_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr);
IRAM_W(addr,data+1);
}
/*INC @R0/@R1 1: 0000 011i */
OPHANDLER( inc_ir )
{
UINT8 data = IRAM_IR(R_REG(r));
IRAM_W(R_REG(r),data+1);
}
/*INC R0 to R7 1: 0000 1rrr */
OPHANDLER( inc_r )
{
UINT8 data = R_REG(r);
SET_REG(r, data + 1);
}
/*INC DPTR 1: 1010 0011 */
OPHANDLER( inc_dptr )
{
UINT16 dptr = (DPTR)+1;
SET_DPTR(dptr);
}
/*JB bit addr, code addr 1: 0010 0000 */
OPHANDLER( jb )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(BIT_R(addr)) /*If bit set at specified bit address, jump */
{
PC = PC + rel_addr;
}
}
/*JBC bit addr, code addr 1: 0001 0000 */
OPHANDLER( jbc )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(BIT_R(addr)) { /*If bit set at specified bit address, jump */
PC = PC + rel_addr;
BIT_W(addr,0); /*Clear Bit also */
}
}
/*JC code addr 1: 0100 0000 */
OPHANDLER( jc )
{
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(GET_CY) /*Jump if Carry Flag Set */
{
PC = PC + rel_addr;
}
}
/*JMP @A+DPTR 1: 0111 0011 */
OPHANDLER( jmp_iadptr )
{
PC = ACC + DPTR;
}
/*JNB bit addr, code addr 1: 0011 0000 */
OPHANDLER( jnb )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(!BIT_R(addr)) /*If bit NOT set at specified bit address, jump */
{
PC = PC + rel_addr;
}
}
/*JNC code addr 1: 0101 0000 */
OPHANDLER( jnc )
{
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(!GET_CY) /*Jump if Carry Flag not set */
{
PC = PC + rel_addr;
}
}
/*JNZ code addr 1: 0111 0000 */
OPHANDLER( jnz )
{
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(ACC != 0) /*Branch if ACC is not 0 */
{
PC = PC+rel_addr;
}
}
/*JZ code addr 1: 0110 0000 */
OPHANDLER( jz )
{
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
if(ACC == 0) /*Branch if ACC is 0 */
{
PC = PC+rel_addr;
}
}
/*LCALL code addr 1: 0001 0010 */
OPHANDLER( lcall )
{
UINT8 addr_hi, addr_lo;
addr_hi = ROP_ARG(PC++);
addr_lo = ROP_ARG(PC++);
PUSH_PC();
PC = (UINT16)((addr_hi<<8) | addr_lo);
}
/*LJMP code addr 1: 0000 0010 */
OPHANDLER( ljmp )
{
UINT8 addr_hi, addr_lo;
addr_hi = ROP_ARG(PC++);
addr_lo = ROP_ARG(PC++);
PC = (UINT16)((addr_hi<<8) | addr_lo);
}
/*MOV A, #data 1: 0111 0100 */
OPHANDLER( mov_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
SET_ACC(data); /*Store data to ACC */
}
/*MOV A, data addr 1: 1110 0101 */
OPHANDLER( mov_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
SET_ACC(IRAM_R(addr)); /*Store contents of data address to ACC */
}
/*MOV A,@RO/@R1 1: 1110 011i */
OPHANDLER( mov_a_ir )
{
SET_ACC(IRAM_IR(R_REG(r))); /*Store contents of address pointed by R0 or R1 to ACC */
}
/*MOV A,R0 to R7 1: 1110 1rrr */
OPHANDLER( mov_a_r )
{
SET_ACC(R_REG(r)); /*Store contents of R0 - R7 to ACC */
}
/*MOV data addr, #data 1: 0111 0101 */
OPHANDLER( mov_mem_byte )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = ROP_ARG(PC++); /*Grab data */
IRAM_W(addr,data); /*Store data to data address location */
}
/*MOV data addr, data addr 1: 1000 0101 */
OPHANDLER( mov_mem_mem )
{
/*1st address is src, 2nd is dst, but the mov command works as mov dst,src) */
UINT8 src,dst;
src = ROP_ARG(PC++); /*Grab source data address */
dst = ROP_ARG(PC++); /*Grab destination data address */
IRAM_W(dst,IRAM_R(src)); /*Read source address contents and store to destination address */
}
/*MOV @R0/@R1, #data 1: 0111 011i */
OPHANDLER( mov_ir_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
IRAM_IW(R_REG(r),data); /*Store data to address pointed by R0 or R1 */
}
/*MOV R0 to R7, #data 1: 0111 1rrr */
OPHANDLER( mov_r_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
SET_REG(r, data); /*Store to R0 - R7 */
}
/*MOV data addr, @R0/@R1 1: 1000 011i */
OPHANDLER( mov_mem_ir )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
IRAM_W(addr,IRAM_IR(R_REG(r))); /*Store contents pointed to by R0 or R1 to data address */
}
/*MOV data addr,R0 to R7 1: 1000 1rrr */
OPHANDLER( mov_mem_r )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
IRAM_W(addr,R_REG(r)); /*Store contents of R0 - R7 to data address */
}
/*MOV DPTR, #data16 1: 1001 0000 */
OPHANDLER( mov_dptr_byte )
{
UINT8 data_hi, data_lo;
data_hi = ROP_ARG(PC++); /*Grab hi byte */
data_lo = ROP_ARG(PC++); /*Grab lo byte */
SET_DPTR((UINT16)((data_hi<<8)|data_lo)); /*Store to DPTR */
}
/*MOV bit addr, C 1: 1001 0010 */
OPHANDLER( mov_bitaddr_c )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
BIT_W(addr,GET_CY); /*Store Carry Flag to Bit Address */
}
/*MOV @R0/@R1, data addr 1: 1010 011i */
OPHANDLER( mov_ir_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
IRAM_IW(R_REG(r),IRAM_R(addr)); /*Store data from data address to address pointed to by R0 or R1 */
}
/*MOV R0 to R7, data addr 1: 1010 1rrr */
OPHANDLER( mov_r_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
SET_REG(r, IRAM_R(addr)); /*Store to R0 - R7 */
}
/*MOV data addr, A 1: 1111 0101 */
OPHANDLER( mov_mem_a )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
IRAM_W(addr,ACC); /*Store A to data address */
}
/*MOV @R0/@R1, A 1: 1111 011i */
OPHANDLER( mov_ir_a )
{
IRAM_IW(R_REG(r),ACC); /*Store A to location pointed to by R0 or R1 */
}
/*MOV R0 to R7, A 1: 1111 1rrr */
OPHANDLER( mov_r_a )
{
SET_REG(r, ACC); /*Store A to R0-R7 */
}
/*MOVC A, @A + PC 1: 1000 0011 */
OPHANDLER( movc_a_iapc )
{
UINT8 data;
data = CODEMEM_R(ACC+PC); /*Move a byte from CODE(Program) Memory and store to ACC */
SET_ACC(data);
}
/*MOV C, bit addr 1: 1010 0010 */
OPHANDLER( mov_c_bitaddr )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
SET_CY( (BIT_R(addr)) ); /*Store Bit from Bit Address to Carry Flag */
}
/*MOVC A, @A + DPTR 1: 1001 0011 */
OPHANDLER( movc_a_iadptr )
{
UINT8 data;
data = CODEMEM_R(ACC + DPTR); /*Move a byte from CODE(Program) Memory and store to ACC */
SET_ACC(data);
}
/*MOVX A,@DPTR 1: 1110 0000 */
/*(Move External Ram 16 bit address to A) */
OPHANDLER( movx_a_idptr )
{
/* UINT8 byte = DATAMEM_R(R_DPTR); //Grab 1 byte from External DATA memory pointed to by dptr */
UINT32 addr = ERAM_ADDR(DPTR, 0xFFFF);
UINT8 byte = DATAMEM_R(addr); /*Grab 1 byte from External DATA memory pointed to by dptr */
SET_ACC(byte); /*Store to ACC */
}
/*MOVX A, @R0/@R1 1: 1110 001i */
/*(Move External Ram 8 bit address to A) */
OPHANDLER( movx_a_ir )
{
UINT32 addr = ERAM_ADDR(R_REG(r),0xFF); /*Grab address by reading location pointed to by R0 or R1 */
UINT8 byte = DATAMEM_R(addr); /*Grab 1 byte from External DATA memory pointed to by address */
SET_ACC(byte); /*Store to ACC */
}
/*MOVX @DPTR,A 1: 1111 0000 */
/*(Move A to External Ram 16 bit address) */
OPHANDLER( movx_idptr_a )
{
/* DATAMEM_W(R_DPTR, ACC); //Store ACC to External DATA memory address pointed to by DPTR */
UINT32 addr = ERAM_ADDR(DPTR, 0xFFFF);
DATAMEM_W(addr, ACC); /*Store ACC to External DATA memory address pointed to by DPTR */
}
/*MOVX @R0/@R1,A 1: 1111 001i */
/*(Move A to External Ram 8 bit address) */
OPHANDLER( movx_ir_a )
{
UINT32 addr = ERAM_ADDR(R_REG(r),0xFF); /*Grab address by reading location pointed to by R0 or R1 */
DATAMEM_W(addr, ACC); /*Store ACC to External DATA memory address */
}
/*MUL AB 1: 1010 0100 */
OPHANDLER( mul_ab )
{
UINT16 result = ACC * B;
/*A gets lo bits, B gets hi bits of result */
B = (UINT8) ((result & 0xFF00) >> 8);
SET_ACC((UINT8)(result & 0x00FF));
/*Set flags */
SET_OV( ((result & 0x100) >> 8) ); /*Set/Clear Overflow Flag if result > 255 */
SET_CY(0); /*Carry Flag always cleared */
}
/*NOP 1: 0000 0000 */
OPHANDLER( nop )
{
}
/*ORL data addr, A 1: 0100 0010 */
OPHANDLER( orl_mem_a )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
IRAM_W(addr,data | ACC); /*Set data address value to it's value Logical OR with ACC */
}
/*ORL data addr, #data 1: 0100 0011 */
OPHANDLER( orl_mem_byte )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = ROP_ARG(PC++); /*Grab data */
UINT8 srcdata = IRAM_R(addr); /*Grab data from data address */
IRAM_W(addr,srcdata | data); /*Set data address value to it's value Logical OR with Data */
}
/*ORL A, #data 1: 0100 0100 */
OPHANDLER( orl_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
SET_ACC(ACC | data); /*Set ACC to value of ACC Logical OR with Data */
}
/*ORL A, data addr 1: 0100 0101 */
OPHANDLER( orl_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
SET_ACC(ACC | data); /*Set ACC to value of ACC Logical OR with Data */
}
/*ORL A, @RO/@R1 1: 0100 011i */
OPHANDLER( orl_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data from address R0 or R1 points to */
SET_ACC(ACC | data); /*Set ACC to value of ACC Logical OR with Data */
}
/*ORL A, RO to R7 1: 0100 1rrr */
OPHANDLER( orl_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0 - R7 */
SET_ACC(ACC | data); /*Set ACC to value of ACC Logical OR with Data */
}
/*ORL C, bit addr 1: 0111 0010 */
OPHANDLER( orl_c_bitaddr )
{
int cy = GET_CY;
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
UINT8 bit = BIT_R(addr); /*Grab bit data from bit address */
SET_CY( (cy | bit) ); /*Set Carry flag to Carry Flag Value Logical OR with Bit */
}
/*ORL C, /bit addr 1: 1010 0000 */
OPHANDLER( orl_c_nbitaddr )
{
int cy = GET_CY;
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
UINT8 bit = BIT_R(addr); /*Grab bit data from bit address */
bit = ((~bit)&1); /*Complement bit */
SET_CY( (cy | bit) ); /*Set Carry flag to Carry Flag Value Logical OR with Complemented Bit */
}
/*POP data addr 1: 1101 0000 */
OPHANDLER( pop )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
IRAM_W(addr, IRAM_IR(SP)); /*Store to contents of data addr, data pointed to by Stack - IRAM_IR needed to access upper 128 bytes of stack */
/*IRAM_IW(addr, IRAM_IR(R_SP)); //Store to contents of data addr, data pointed to by Stack - doesn't work, sfr's are not restored this way and it's not an indirect access anyway */
SP = SP-1; /*Decrement SP */
}
/*PUSH data addr 1: 1100 0000 */
OPHANDLER( push )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 tmpSP = SP+1; /*Grab and Increment Stack Pointer */
SP = tmpSP; /* "" */
IRAM_IW(tmpSP, IRAM_R(addr)); /*Store to stack contents of data address - IRAM_IW needed to store to upper 128 bytes of stack, however, can't use IRAM_IR because that won't store the sfrs and it's not an indirect access anyway */
}
/*RET 1: 0010 0010 */
OPHANDLER( ret )
{
POP_PC();
}
/*RETI 1: 0011 0010 */
OPHANDLER( reti )
{
POP_PC();
CLEAR_CURRENT_IRQ();
}
/*RL A 1: 0010 0011 */
OPHANDLER( rl_a )
{
/*Left Shift A, Bit 7 carries to Bit 0 */
int carry = ((ACC & 0x80) >> 7);
int data = (ACC<<1) & 0xfe;
SET_ACC( data | carry);
}
/*RLC A 1: 0011 0011 */
OPHANDLER( rlc_a )
{
/*Left Shift A, Bit 7 goes to Carry Flag, Original Carry Flag goes to Bit 0 of ACC */
int carry = ((ACC & 0x80) >> 7);
int data = ((ACC<<1) & 0xfe) | GET_CY;
SET_ACC( data);
SET_CY(carry);
}
/*RR A 1: 0000 0011 */
OPHANDLER( rr_a )
{
/*Right Shift A, Bit 0 carries to Bit 7 */
int carry = ((ACC & 1) << 7);
int data = (ACC>>1) & 0x7f;
SET_ACC( data | carry);
}
/*RRC A 1: 0001 0011 */
OPHANDLER( rrc_a )
{
/*Right Shift A, Bit 0 goes to Carry Flag, Bit 7 of ACC gets set to original Carry Flag */
int carry = (ACC & 1);
int data = ((ACC>>1) & 0x7f) | (GET_CY<<7);
SET_ACC( data);
SET_CY(carry);
}
/*SETB C 1: 1101 0011 */
OPHANDLER( setb_c )
{
SET_CY(1); /*Set Carry Flag */
}
/*SETB bit addr 1: 1101 0010 */
OPHANDLER( setb_bitaddr )
{
UINT8 addr = ROP_ARG(PC++); /*Grab bit address */
BIT_W(addr,1); /*Set Bit at Bit Address */
}
/*SJMP code addr 1: 1000 0000 */
OPHANDLER( sjmp )
{
INT8 rel_addr = ROP_ARG(PC++); /*Grab relative code address */
PC = PC + rel_addr; /*Update PC */
}
/*SUBB A, #data 1: 1001 0100 */
OPHANDLER( subb_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
UINT8 result = ACC - data - GET_CY; /*Subtract data & carry flag from accumulator */
DO_SUB_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*SUBB A, data addr 1: 1001 0101 */
OPHANDLER( subb_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
UINT8 result = ACC - data - GET_CY; /*Subtract data & carry flag from accumulator */
DO_SUB_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*SUBB A, @R0/@R1 1: 1001 011i */
OPHANDLER( subb_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data from memory pointed to by R0 or R1 */
UINT8 result = ACC - data - GET_CY; /*Subtract data & carry flag from accumulator */
DO_SUB_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*SUBB A, R0 to R7 1: 1001 1rrr */
OPHANDLER( subb_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0 - R7 */
UINT8 result = ACC - data - GET_CY; /*Subtract data & carry flag from accumulator */
DO_SUB_FLAGS(ACC,data,GET_CY); /*Set Flags */
SET_ACC(result); /*Store 8 bit result of addtion in ACC */
}
/*SWAP A 1: 1100 0100 */
OPHANDLER( swap_a )
{
UINT8 a_nib_lo, a_nib_hi;
a_nib_hi = (ACC & 0x0f) << 4; /*Grab lo byte of ACC and move to hi */
a_nib_lo = (ACC & 0xf0) >> 4; /*Grab hi byte of ACC and move to lo */
SET_ACC( a_nib_hi | a_nib_lo);
}
/*XCH A, data addr 1: 1100 0101 */
OPHANDLER( xch_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data */
UINT8 oldACC = ACC; /*Hold value of ACC */
SET_ACC(data); /*Sets ACC to data */
IRAM_W(addr,oldACC); /*Sets data address to old value of ACC */
}
/*XCH A, @RO/@R1 1: 1100 011i */
OPHANDLER( xch_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data pointed to by R0 or R1 */
UINT8 oldACC = ACC; /*Hold value of ACC */
SET_ACC(data); /*Sets ACC to data */
IRAM_W(R_REG(r),oldACC); /*Sets data address to old value of ACC */
}
/*XCH A, RO to R7 1: 1100 1rrr */
OPHANDLER( xch_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0-R7 */
UINT8 oldACC = ACC; /*Hold value of ACC */
SET_ACC(data); /*Sets ACC to data */
SET_REG(r, oldACC); /*Sets data address to old value of ACC */
}
/*XCHD A, @R0/@R1 1: 1101 011i */
OPHANDLER( xchd_a_ir )
{
UINT8 acc, ir_data;
ir_data = IRAM_IR(R_REG(r)); /*Grab data pointed to by R0 or R1 */
acc = ACC; /*Grab ACC value */
SET_ACC( (acc & 0xf0) | (ir_data & 0x0f) ); /*Set ACC to lower nibble of data pointed to by R0 or R1 */
IRAM_W(R_REG(r), (ir_data & 0xf0) | (acc & 0x0f) ); /*Set data pointed to by R0 or R1 to lower nibble of ACC */
}
/*XRL data addr, A 1: 0110 0010 */
OPHANDLER( xrl_mem_a )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
IRAM_W(addr,data ^ ACC); /*Set data address value to it's value Logical XOR with ACC */
}
/*XRL data addr, #data 1: 0110 0011 */
OPHANDLER( xrl_mem_byte )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = ROP_ARG(PC++); /*Grab data */
UINT8 srcdata = IRAM_R(addr); /*Grab data from data address */
IRAM_W(addr,srcdata ^ data); /*Set data address value to it's value Logical XOR with Data */
}
/*XRL A, #data 1: 0110 0100 */
OPHANDLER( xrl_a_byte )
{
UINT8 data = ROP_ARG(PC++); /*Grab data */
SET_ACC(ACC ^ data); /*Set ACC to value of ACC Logical XOR with Data */
}
/*XRL A, data addr 1: 0110 0101 */
OPHANDLER( xrl_a_mem )
{
UINT8 addr = ROP_ARG(PC++); /*Grab data address */
UINT8 data = IRAM_R(addr); /*Grab data from data address */
SET_ACC(ACC ^ data); /*Set ACC to value of ACC Logical XOR with Data */
}
/*XRL A, @R0/@R1 1: 0110 011i */
OPHANDLER( xrl_a_ir )
{
UINT8 data = IRAM_IR(R_REG(r)); /*Grab data from address R0 or R1 points to */
SET_ACC(ACC ^ data); /*Set ACC to value of ACC Logical XOR with Data */
}
/*XRL A, R0 to R7 1: 0110 1rrr */
OPHANDLER( xrl_a_r )
{
UINT8 data = R_REG(r); /*Grab data from R0 - R7 */
SET_ACC(ACC ^ data); /*Set ACC to value of ACC Logical XOR with Data */
}
/*illegal opcodes */
OPHANDLER( illegal )
{
LOG(("i8051 #%d: illegal opcode at 0x%03x: %02x\n", cpu_getactivecpu(), PC-1, r));
}
+48
View File
@@ -63,6 +63,7 @@ typedef struct
INT8 nmi_state;
INT8 irq_state;
int extra_cycles; /* extra cycles for interrupts */
INT8 test_state; /* the TEST input */
}
i86_Regs;
@@ -123,12 +124,53 @@ static void i86_state_register(void)
state_save_register_INT8( type, cpu, "NMI_STATE", &I.nmi_state, 1);
state_save_register_INT8( type, cpu, "IRQ_STATE", &I.irq_state, 1);
state_save_register_int( type, cpu, "EXTRA_CYCLES", &I.extra_cycles);
state_save_register_INT8( type, cpu, "TEST_STATE", &I.test_state, 1);
}
/* the 16-bit data bus, see i86intf.h */
int i86_bus16;
int i86_bus16_word;
unsigned i86_read_word16(unsigned ea)
{
unsigned lo, hi;
/* an odd address is two byte cycles on the 8086 too */
if (ea & 1)
{
lo = cpu_readmem20(ea);
hi = cpu_readmem20((ea + 1) & AMASK);
return lo | (hi << 8);
}
i86_bus16_word = 1;
lo = cpu_readmem20(ea);
hi = cpu_readmem20(ea + 1);
i86_bus16_word = 0;
return lo | (hi << 8);
}
void i86_write_word16(unsigned ea, unsigned val)
{
if (ea & 1)
{
cpu_writemem20(ea, val & 0xff);
cpu_writemem20((ea + 1) & AMASK, (val >> 8) & 0xff);
return;
}
i86_bus16_word = 1;
cpu_writemem20(ea, val & 0xff);
cpu_writemem20(ea + 1, (val >> 8) & 0xff);
i86_bus16_word = 0;
}
void i86_init(void)
{
unsigned int i, j, c;
BREGS reg_name[8] = {AL, CL, DL, BL, AH, CH, DH, BH};
/* the 16-bit data bus is off unless the driver turns it on */
i86_bus16 = 0;
i86_bus16_word = 0;
for (i = 0; i < 256; i++)
{
for (j = i, c = 0; j > 0; j >>= 1)
@@ -157,6 +199,7 @@ void i86_reset(void *param)
{
memset(&I, 0, sizeof (I));
I.test_state = 1;
I.sregs[CS] = 0xf000;
I.base[CS] = SegBase(CS);
I.pc = 0xffff0 & AMASK;
@@ -287,6 +330,11 @@ void i86_set_reg(int regnum, unsigned val)
void i86_set_irq_line(int irqline, int state)
{
if (irqline == I86_TEST_LINE)
{
I.test_state = (state != CLEAR_LINE);
return;
}
if (irqline == IRQ_LINE_NMI)
{
if (I.nmi_state == state)
+8 -4
View File
@@ -71,20 +71,24 @@ typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,SIL,SIH,DIL,DIH } BREGS;
/************************************************************************/
/* the 16-bit data bus of the 8086 (see i86intf.h): off unless a driver turns it on */
unsigned i86_read_word16(unsigned ea);
void i86_write_word16(unsigned ea, unsigned val);
#define SegBase(Seg) (I.sregs[Seg] << 4)
#define DefaultBase(Seg) ((seg_prefix && (Seg == DS || Seg == SS)) ? prefix_base : I.base[Seg])
#define GetMemB(Seg,Off) (cpu_readmem20((DefaultBase(Seg) + (Off)) & AMASK))
#define GetMemW(Seg,Off) ((WORD)GetMemB(Seg, Off) + (WORD)(GetMemB(Seg, (Off) + 1) << 8))
#define GetMemW(Seg,Off) (i86_bus16 ? i86_read_word16((DefaultBase(Seg) + (Off)) & AMASK) : ((WORD)GetMemB(Seg, Off) + (WORD)(GetMemB(Seg, (Off) + 1) << 8)))
#define PutMemB(Seg,Off,x) cpu_writemem20((DefaultBase(Seg) + (Off)) & AMASK, (x))
#define PutMemW(Seg,Off,x) { PutMemB(Seg, Off, (x) & 0xff); PutMemB(Seg, (Off) + 1, ((x) >> 8) & 0xff); }
#define PutMemW(Seg,Off,x) { if (i86_bus16) i86_write_word16((DefaultBase(Seg) + (Off)) & AMASK, (x)); else { PutMemB(Seg, Off, (x) & 0xff); PutMemB(Seg, (Off) + 1, ((x) >> 8) & 0xff); } }
#define PEEKBYTE(ea) (cpu_readmem20((ea) & AMASK))
#define ReadByte(ea) (cpu_readmem20((ea) & AMASK))
#define ReadWord(ea) (cpu_readmem20((ea) & AMASK) + (cpu_readmem20(((ea) + 1) & AMASK) << 8))
#define ReadWord(ea) (i86_bus16 ? i86_read_word16((ea) & AMASK) : (cpu_readmem20((ea) & AMASK) + (cpu_readmem20(((ea) + 1) & AMASK) << 8)))
#define WriteByte(ea,val) cpu_writemem20((ea) & AMASK, val);
#define WriteWord(ea,val) { cpu_writemem20((ea) & AMASK, (val) & 0xff); cpu_writemem20(((ea) + 1) & AMASK, ((val) >> 8) & 0xff); }
#define WriteWord(ea,val) { if (i86_bus16) i86_write_word16((ea) & AMASK, (val)); else { cpu_writemem20((ea) & AMASK, (val) & 0xff); cpu_writemem20(((ea) + 1) & AMASK, ((val) >> 8) & 0xff); } }
#define read_port(port) cpu_readport16(port)
#define write_port(port,val) cpu_writeport16(port,val)
+14
View File
@@ -11,9 +11,23 @@ enum {
I86_VECTOR, I86_PENDING, I86_NMI_STATE, I86_IRQ_STATE
};
/* the TEST input (WAIT instruction): a CPU waits at a WAIT instruction
while it is cleared; it is asserted at reset, so WAIT goes on unless a
driver clears it */
#define I86_TEST_LINE 1
/* Public variables */
extern int i86_ICount;
/* The 8086 has a 16-bit data bus, but the core accesses memory a byte at a
time. A driver whose hardware needs an aligned word access to be one bus
cycle sets i86_bus16 (all the i86 CPUs of the machine): the core then
accesses an aligned word as its low byte then its high byte, with
i86_bus16_word set during the two accesses, so the handlers can make
them one 16-bit access. Off by default: nothing changes for the others. */
extern int i86_bus16;
extern int i86_bus16_word;
/* Public functions */
extern void i86_init(void);
+37 -8
View File
@@ -544,8 +544,13 @@ static void PREFIX(rep)(int flagval)
for (; count > 0; count--)
{
if (ICOUNT <= 0) { I.pc = I.prevpc; break; }
PutMemB(ES,I.regs.w[DI],I.regs.b[AL]);
PutMemB(ES,I.regs.w[DI]+1,I.regs.b[AH]);
if (i86_bus16)
PutMemW(ES,I.regs.w[DI],I.regs.w[AX])
else
{
PutMemB(ES,I.regs.w[DI],I.regs.b[AL]);
PutMemB(ES,I.regs.w[DI]+1,I.regs.b[AH]);
}
I.regs.w[DI] += 2 * I.DirVal;
ICOUNT -= cycles.rep_stos16_count;
}
@@ -1994,6 +1999,15 @@ static void PREFIX86(_call_far)(void)
static void PREFIX86(_wait)(void) /* Opcode 0x9b */
{
#ifndef I286
/* the TEST input cleared: wait on this instruction */
if (!I.test_state)
{
ICOUNT = 0;
I.pc--;
return;
}
#endif
ICOUNT -= cycles.wait;
}
@@ -2060,8 +2074,13 @@ static void PREFIX86(_mov_axdisp)(void) /* Opcode 0xa1 */
addr += FETCH << 8;
ICOUNT -= cycles.mov_am16;
I.regs.b[AL] = GetMemB(DS, addr);
I.regs.b[AH] = GetMemB(DS, addr+1);
if (i86_bus16)
I.regs.w[AX] = GetMemW(DS, addr);
else
{
I.regs.b[AL] = GetMemB(DS, addr);
I.regs.b[AH] = GetMemB(DS, addr+1);
}
}
static void PREFIX86(_mov_dispal)(void) /* Opcode 0xa2 */
@@ -2083,8 +2102,13 @@ static void PREFIX86(_mov_dispax)(void) /* Opcode 0xa3 */
addr += FETCH << 8;
ICOUNT -= cycles.mov_ma16;
PutMemB(DS, addr, I.regs.b[AL]);
PutMemB(DS, addr+1, I.regs.b[AH]);
if (i86_bus16)
PutMemW(DS, addr, I.regs.w[AX])
else
{
PutMemB(DS, addr, I.regs.b[AL]);
PutMemB(DS, addr+1, I.regs.b[AH]);
}
}
static void PREFIX86(_movsb)(void) /* Opcode 0xa4 */
@@ -2148,8 +2172,13 @@ static void PREFIX86(_stosb)(void) /* Opcode 0xaa */
static void PREFIX86(_stosw)(void) /* Opcode 0xab */
{
PutMemB(ES,I.regs.w[DI],I.regs.b[AL]);
PutMemB(ES,I.regs.w[DI]+1,I.regs.b[AH]);
if (i86_bus16)
PutMemW(ES,I.regs.w[DI],I.regs.w[AX])
else
{
PutMemB(ES,I.regs.w[DI],I.regs.b[AL]);
PutMemB(ES,I.regs.w[DI]+1,I.regs.b[AH]);
}
I.regs.w[DI] += 2 * I.DirVal;
ICOUNT -= cycles.stos16;
}
+2815
View File
File diff suppressed because it is too large. Load diff
+67
View File
@@ -0,0 +1,67 @@
/***************************************************************************
Intel 80960KA/KB, from current MAME (src/devices/cpu/i960,
copyright Farfetch'd, R. Belmont, BSD-3-Clause), in C for MAME 2003.
***************************************************************************/
#ifndef I960_H
#define I960_H
#include "osd_cpu.h"
enum
{
I960_PFP = 0,
I960_SP = 1,
I960_RIP = 2,
I960_FP = 31
};
/* register numbers for get_reg / set_reg */
enum
{
I960_IPREG = 1, I960_PIPREG, I960_SATREG, I960_PRCBREG, I960_PCREG, I960_ACREG,
I960_R0REG
/* I960_R0REG + n: r0..r15 g0..g15 */
};
enum
{
I960_IRQ0 = 0,
I960_IRQ1 = 1,
I960_IRQ2 = 2,
I960_IRQ3 = 3
};
extern int i960_icount;
extern void i960_init(void);
extern void i960_reset(void *param);
extern void i960_exit(void);
extern int i960_execute(int cycles);
extern unsigned i960_get_context(void *dst);
extern void i960_set_context(void *src);
extern unsigned i960_get_reg(int regnum);
extern void i960_set_reg(int regnum, unsigned val);
extern void i960_set_irq_line(int irqline, int state);
extern void i960_set_irq_callback(int (*callback)(int irqline));
extern const char *i960_info(void *context, int regnum);
extern unsigned i960_dasm(char *buffer, unsigned pc);
/* Model 2: a FIFO access that cannot complete now (copro FIFO empty or
full) repeats the instruction later; a multi-word access already half
done resumes where it stopped (current MAME, i960_stall) */
extern void i960_stall(void);
/* the regions where ldl/ldt/ldq/stl/stt/stq step through the addresses
(current MAME's BURST flag); elsewhere (FIFOs, registers) every word
goes to the same address. NULL: everywhere. */
extern void i960_set_burst_callback(int (*is_burst)(UINT32 address));
/* the addresses an idle loop may read: reading them has no side effect
and their contents change only between timeslices (RAM, a status
register updated by an interrupt). NULL (default): idle loops are not
skipped. */
extern void i960_set_idle_read_callback(int (*read_ok)(UINT32 address));
#endif
+1
View File
@@ -483,6 +483,7 @@ void konami_init(void)
state_save_register_UINT8("konami", cpu, "NMI", &konami.nmi_state, 1);
state_save_register_UINT8("konami", cpu, "IRQ", &konami.irq_state[0], 1);
state_save_register_UINT8("konami", cpu, "FIRQ", &konami.irq_state[1], 1);
state_save_register_int("konami", cpu, "extra_cycles", &konami.extra_cycles); /* the cycles of an interrupt taken outside the execute loop */
}
void konami_reset(void *param)
File diff suppressed because it is too large. Load diff
+172
View File
@@ -0,0 +1,172 @@
#ifndef HEADER__M37710
#define HEADER__M37710
/* ======================================================================== */
/* =============================== COPYRIGHT ============================== */
/* ======================================================================== */
/*
M37710 CPU Emulator v0.1
mame2003-plus: backported from MAME 0.121 to the 0.78 CPU interface.
The on-chip registers (0x00-0x7f), on-chip RAM (0x80-0x27f) and, for the
M37702 with internal mask ROM, the internal ROM (0xc000-0xffff) are
handled inside the core. The on-chip I/O ports and ADC are routed to the
driver through m37710_set_io_handlers(). Single instance only.
*/
#include "osd_cpu.h"
/* ======================================================================== */
/* =============================== DEFINES ================================ */
/* ======================================================================== */
/*
Input lines - used with cpu_set_irq_line() and the like.
WARNING: these are in the same order as the vector table for simplicity.
Do not alter this order!
*/
enum
{
/* these interrupts are maskable */
M37710_LINE_ADC = 0,
M37710_LINE_UART1XMIT,
M37710_LINE_UART1RECV,
M37710_LINE_UART0XMIT,
M37710_LINE_UART0RECV,
M37710_LINE_TIMERB2,
M37710_LINE_TIMERB1,
M37710_LINE_TIMERB0,
M37710_LINE_TIMERA4,
M37710_LINE_TIMERA3,
M37710_LINE_TIMERA2,
M37710_LINE_TIMERA1,
M37710_LINE_TIMERA0,
M37710_LINE_IRQ2,
M37710_LINE_IRQ1,
M37710_LINE_IRQ0,
/* these interrupts are non-maskable */
M37710_LINE_WATCHDOG,
M37710_LINE_DEBUG,
M37710_LINE_BRK,
M37710_LINE_ZERODIV,
M37710_LINE_RESET,
/* these are not interrupts, they're signals external hardware can send */
M37710_LINE_TIMERA0TICK,
M37710_LINE_TIMERA1TICK,
M37710_LINE_TIMERA2TICK,
M37710_LINE_TIMERA3TICK,
M37710_LINE_TIMERA4TICK,
M37710_LINE_TIMERB0TICK,
M37710_LINE_TIMERB1TICK,
M37710_LINE_TIMERB2TICK,
/* timer A output pins: the count direction of an event counter in up/down pin mode */
M37710_LINE_TIMERA0OUT,
M37710_LINE_TIMERA1OUT,
M37710_LINE_TIMERA2OUT,
M37710_LINE_TIMERA3OUT,
M37710_LINE_TIMERA4OUT,
M37710_LINE_MAX
};
/* Registers - used by m37710_set_reg() and m37710_get_reg() */
enum
{
M37710_PC=1, M37710_S, M37710_P, M37710_A, M37710_B, M37710_X, M37710_Y,
M37710_PB, M37710_DB, M37710_D, M37710_E,
M37710_NMI_STATE, M37710_IRQ_STATE
};
/* I/O ports */
enum
{
M37710_PORT0 = 0,
M37710_PORT1, M37710_PORT2, M37710_PORT3, M37710_PORT4,
M37710_PORT5, M37710_PORT6, M37710_PORT7, M37710_PORT8,
M37710_ADC0_L = 0x10, M37710_ADC0_H,
M37710_ADC1_L, M37710_ADC1_H, M37710_ADC2_L, M37710_ADC2_H, M37710_ADC3_L, M37710_ADC3_H,
M37710_ADC4_L, M37710_ADC4_H, M37710_ADC5_L, M37710_ADC5_H, M37710_ADC6_L, M37710_ADC6_H,
M37710_ADC7_L, M37710_ADC7_H,
M37710_SER0_REC = 0x20,
M37710_SER0_XMIT, M37710_SER1_REC, M37710_SER1_XMIT
};
/* ======================================================================== */
/* ============================== PROTOTYPES ============================== */
/* ======================================================================== */
typedef data8_t (*m37710_io_read_func)(int port);
typedef void (*m37710_io_write_func)(int port, data8_t data);
/* hook the on-chip ports/ADC to the driver */
void m37710_set_io_handlers(m37710_io_read_func readfn, m37710_io_write_func writefn);
/* M37702 with internal mask ROM: 16KB mapped at 0xc000-0xffff (NULL = external) */
void m37710_set_internal_rom(const UINT8 *rom);
/*
Speedup (0 = off): 'pc' (bank | address) starts a loop of 'count'
instructions that only polls memory written by interrupts (such as
"lda dp / beq loop"), so every pass leaves the same state. Once one
pass has run inside a timeslice, the whole passes that still fit in
it are skipped: registers, memory and cycles end up exactly as if
they had run.
*/
void m37710_set_idle_loop(UINT32 pc, int count);
extern int m37710_ICount; /* cycle count */
void m37710_init(void);
void m37710_reset(void *param);
void m37710_exit(void);
int m37710_execute(int cycles);
unsigned m37710_get_context(void *dst);
void m37710_set_context(void *src);
unsigned m37710_get_reg(int regnum);
void m37710_set_reg(int regnum, unsigned val);
void m37710_set_irq_line(int irqline, int state);
void m37710_set_irq_callback(int (*callback)(int irqline));
const char *m37710_info(void *context, int regnum);
unsigned m37710_dasm(char *buffer, unsigned pc);
#define m37702_ICount m37710_ICount
#define m37702_init m37710_init
#define m37702_reset m37710_reset
#define m37702_exit m37710_exit
#define m37702_execute m37710_execute
#define m37702_get_context m37710_get_context
#define m37702_set_context m37710_set_context
#define m37702_get_reg m37710_get_reg
#define m37702_set_reg m37710_set_reg
#define m37702_set_irq_line m37710_set_irq_line
#define m37702_set_irq_callback m37710_set_irq_callback
#define m37702_info m37710_info
#define m37702_dasm m37710_dasm
/* memory access, including the on-chip resources */
UINT8 m37710_mem_read8(UINT32 address);
UINT16 m37710_mem_read16(UINT32 address);
void m37710_mem_write8(UINT32 address, UINT8 data);
void m37710_mem_write16(UINT32 address, UINT16 data);
#undef M37710_CALL_DEBUGGER
#define M37710_CALL_DEBUGGER CALL_MAME_DEBUG
#define m37710_read_8(addr) m37710_mem_read8(addr)
#define m37710_write_8(addr,data) m37710_mem_write8(addr,data)
#define m37710_read_8_immediate(A) m37710_mem_read8(A)
#define m37710_read_16(addr) m37710_mem_read16(addr)
#define m37710_write_16(addr,data) m37710_mem_write16(addr,data)
#define m37710_jumping(A)
#define m37710_branching(A)
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* HEADER__M37710 */
+323
View File
@@ -0,0 +1,323 @@
/* M37710/M37702 core internals: from MAME 0.121 (MAME license; R. Belmont,
based on the G65816 core by Karl Stenerud) */
#ifndef HEADER__M37710CM
#define HEADER__M37710CM
#define m37710i_branching(A)
#define m37710i_jumping(A)
/* ======================================================================== */
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
#include <limits.h>
#include "driver.h"
#include "cpuintrf.h"
#include "mamedbg.h"
#include "m37710.h"
/* ======================================================================== */
/* ================================ GENERAL =============================== */
/* ======================================================================== */
/* Fallback on static if we don't have inline */
/* This should be set to the default size of your processor (min 16 bit) */
#undef uint
#define uint unsigned int
#undef uint8
#define uint8 unsigned char
#undef int8
/* Allow for architectures that don't have 8-bit sizes */
#if UCHAR_MAX == 0xff
#define int8 char
#define MAKE_INT_8(A) (int8)((A)&0xff)
#else
#define int8 int
static INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;}
#endif /* UCHAR_MAX == 0xff */
#define MAKE_UINT_8(A) ((A)&0xff)
#define MAKE_UINT_16(A) ((A)&0xffff)
#define MAKE_UINT_24(A) ((A)&0xffffff)
/* Bits */
#define BIT_0 0x01
#define BIT_1 0x02
#define BIT_2 0x04
#define BIT_3 0x08
#define BIT_4 0x10
#define BIT_5 0x20
#define BIT_6 0x40
#define BIT_7 0x80
/* ======================================================================== */
/* ================================== CPU ================================= */
/* ======================================================================== */
/* CPU Structure */
typedef struct
{
uint a; /* Accumulator */
uint b; /* holds high byte of accumulator */
uint ba; /* Secondary Accumulator */
uint bb; /* holds high byte of secondary accumulator */
uint x; /* Index Register X */
uint y; /* Index Register Y */
uint s; /* Stack Pointer */
uint pc; /* Program Counter */
uint ppc; /* Previous Program Counter */
uint pb; /* Program Bank (shifted left 16) */
uint db; /* Data Bank (shifted left 16) */
uint d; /* Direct Register */
uint flag_e; /* Emulation Mode Flag */
uint flag_m; /* Memory/Accumulator Select Flag */
uint flag_x; /* Index Select Flag */
uint flag_n; /* Negative Flag */
uint flag_v; /* Overflow Flag */
uint flag_d; /* Decimal Mode Flag */
uint flag_i; /* Interrupt Mask Flag */
uint flag_z; /* Zero Flag (inverted) */
uint flag_c; /* Carry Flag */
uint line_irq; /* Bitmask of pending IRQs */
uint ipl; /* Interrupt priority level (top of PSW) */
uint ir; /* Instruction Register */
uint im; /* Immediate load value */
uint im2; /* Immediate load target */
uint im3; /* Immediate load target */
uint im4; /* Immediate load target */
uint irq_delay; /* delay 1 instruction before checking irq */
uint irq_level; /* irq level */
int (*int_ack)(int); /* Interrupt Acknowledge */
uint stopped; /* Sets how the CPU is stopped */
void (**opcodes)(void); /* opcodes with no prefix */
void (**opcodes42)(void); /* opcodes with 0x42 prefix */
void (**opcodes89)(void); /* opcodes with 0x89 prefix */
uint (*get_reg)(int regnum);
void (*set_reg)(int regnum, uint val);
void (*set_line)(int line, int state);
int (*execute)(int cycles);
/* on-board peripheral stuff */
UINT8 m37710_regs[128];
double reload[8];
mame_timer *timers[8];
double timer_left[8]; /* saved: time left of each timer (< 0: not armed) */
} m37710i_cpu_struct;
extern m37710i_cpu_struct m37710i_cpu;
extern UINT32 m37710_idle_pc;
extern int m37710_idle_count, m37710_idle_since, m37710_idle_clocks;
extern int m37710_ICount;
extern uint m37710i_source;
extern uint m37710i_destination;
extern uint m37710i_adc_tbl[];
extern uint m37710i_sbc_tbl[];
extern void (**m37710i_opcodes[])(void);
extern void (**m37710i_opcodes2[])(void);
extern void (**m37710i_opcodes3[])(void);
extern uint (*m37710i_get_reg[])(int regnum);
extern void (*m37710i_set_reg[])(int regnum, uint val);
extern void (*m37710i_set_line[])(int line, int state);
extern int (*m37710i_execute[])(int cycles);
#define REG_A m37710i_cpu.a /* Accumulator */
#define REG_B m37710i_cpu.b /* Accumulator hi byte */
#define REG_BA m37710i_cpu.ba /* Secondary Accumulator */
#define REG_BB m37710i_cpu.bb /* Secondary Accumulator hi byte */
#define REG_X m37710i_cpu.x /* Index X Register */
#define REG_Y m37710i_cpu.y /* Index Y Register */
#define REG_S m37710i_cpu.s /* Stack Pointer */
#define REG_PC m37710i_cpu.pc /* Program Counter */
#define REG_PPC m37710i_cpu.ppc /* Previous Program Counter */
#define REG_PB m37710i_cpu.pb /* Program Bank */
#define REG_DB m37710i_cpu.db /* Data Bank */
#define REG_D m37710i_cpu.d /* Direct Register */
#define FLAG_M m37710i_cpu.flag_m /* Memory/Accumulator Select Flag */
#define FLAG_X m37710i_cpu.flag_x /* Index Select Flag */
#define FLAG_N m37710i_cpu.flag_n /* Negative Flag */
#define FLAG_V m37710i_cpu.flag_v /* Overflow Flag */
#define FLAG_D m37710i_cpu.flag_d /* Decimal Mode Flag */
#define FLAG_I m37710i_cpu.flag_i /* Interrupt Mask Flag */
#define FLAG_Z m37710i_cpu.flag_z /* Zero Flag (inverted) */
#define FLAG_C m37710i_cpu.flag_c /* Carry Flag */
#define LINE_IRQ m37710i_cpu.line_irq /* Status of the IRQ line */
#define REG_IR m37710i_cpu.ir /* Instruction Register */
#define REG_IM m37710i_cpu.im /* Immediate load value */
#define REG_IM2 m37710i_cpu.im2 /* Immediate load target */
#define REG_IM3 m37710i_cpu.im3 /* Immediate load target */
#define REG_IM4 m37710i_cpu.im4 /* Immediate load target */
#define INT_ACK m37710i_cpu.int_ack /* Interrupt Acknowledge function pointer */
#define CLOCKS m37710_ICount /* Clock cycles remaining */
#define IRQ_DELAY m37710i_cpu.irq_delay /* Delay 1 instruction before checking IRQ */
#define CPU_STOPPED m37710i_cpu.stopped /* Stopped status of the CPU */
#define FTABLE_OPCODES m37710i_cpu.opcodes
#define FTABLE_OPCODES2 m37710i_cpu.opcodes42
#define FTABLE_OPCODES3 m37710i_cpu.opcodes89
#define FTABLE_GET_REG m37710i_cpu.get_reg
#define FTABLE_SET_REG m37710i_cpu.set_reg
#define FTABLE_SET_LINE m37710i_cpu.set_line
#define FTABLE_EXECUTE m37710i_cpu.execute
#define SRC m37710i_source /* Source Operand */
#define DST m37710i_destination /* Destination Operand */
#define STOP_LEVEL_WAI 1
#define STOP_LEVEL_STOP 2
#define EXECUTION_MODE_M0X0 0
#define EXECUTION_MODE_M0X1 1
#define EXECUTION_MODE_M1X0 2
#define EXECUTION_MODE_M1X1 3
static INLINE void m37710i_set_execution_mode(uint mode)
{
FTABLE_OPCODES = m37710i_opcodes[mode];
FTABLE_OPCODES2 = m37710i_opcodes2[mode];
FTABLE_OPCODES3 = m37710i_opcodes3[mode];
FTABLE_GET_REG = m37710i_get_reg[mode];
FTABLE_SET_REG = m37710i_set_reg[mode];
FTABLE_SET_LINE = m37710i_set_line[mode];
FTABLE_EXECUTE = m37710i_execute[mode];
}
/* ======================================================================== */
/* ================================= CLOCK ================================ */
/* ======================================================================== */
#define CLK_OP 1
#define CLK_R8 1
#define CLK_R16 2
#define CLK_R24 3
#define CLK_W8 1
#define CLK_W16 2
#define CLK_W24 3
#define CLK_RMW8 3
#define CLK_RMW16 5
#define CLK_IMPLIED 1
#define CLK_IMPLIED 1
#define CLK_RELATIVE_8 1
#define CLK_RELATIVE_16 2
#define CLK_IMM 0
#define CLK_AI 4
#define CLK_AXI 4
#define CLK_A 2
#define CLK_AL 3
#define CLK_ALX 3
#define CLK_AX 2
#define CLK_AY 2
#define CLK_D 1
#define CLK_DI 3
#define CLK_DIY 3
#define CLK_DLI 4
#define CLK_DLIY 4
#define CLK_DX 2
#define CLK_DXI 4
#define CLK_DY 2
#define CLK_S 2
#define CLK_SIY 5
/* AX and AY addressing modes take 1 extra cycle when writing */
#define CLK_W_IMM 0
#define CLK_W_AI 4
#define CLK_W_AXI 4
#define CLK_W_A 2
#define CLK_W_AL 3
#define CLK_W_ALX 3
#define CLK_W_AX 3
#define CLK_W_AY 3
#define CLK_W_D 1
#define CLK_W_DI 3
#define CLK_W_DIY 3
#define CLK_W_DLI 4
#define CLK_W_DLIY 4
#define CLK_W_DX 2
#define CLK_W_DXI 4
#define CLK_W_DY 2
#define CLK_W_S 2
#define CLK_W_SIY 5
#define CLK(A) CLOCKS -= (A)
#define USE_ALL_CLKS() CLOCKS = 0
/* ======================================================================== */
/* ============================ STATUS REGISTER =========================== */
/* ======================================================================== */
/* Flag positions in Processor Status Register */
/* common */
#define FLAGPOS_N BIT_7 /* Negative */
#define FLAGPOS_V BIT_6 /* Overflow */
#define FLAGPOS_D BIT_3 /* Decimal Mode */
#define FLAGPOS_I BIT_2 /* Interrupt Mask */
#define FLAGPOS_Z BIT_1 /* Zero */
#define FLAGPOS_C BIT_0 /* Carry */
/* emulation */
#define FLAGPOS_R BIT_5 /* Reserved */
#define FLAGPOS_B BIT_4 /* BRK Instruction */
/* native */
#define FLAGPOS_M BIT_5 /* Mem/Reg Select */
#define FLAGPOS_X BIT_4 /* Index Select */
#define EFLAG_SET 1
#define EFLAG_CLEAR 0
#define MFLAG_SET FLAGPOS_M
#define MFLAG_CLEAR 0
#define XFLAG_SET FLAGPOS_X
#define XFLAG_CLEAR 0
#define NFLAG_SET 0x80
#define NFLAG_CLEAR 0
#define VFLAG_SET 0x80
#define VFLAG_CLEAR 0
#define DFLAG_SET FLAGPOS_D
#define DFLAG_CLEAR 0
#define IFLAG_SET FLAGPOS_I
#define IFLAG_CLEAR 0
#define BFLAG_SET FLAGPOS_B
#define BFLAG_CLEAR 0
#define ZFLAG_SET 0
#define ZFLAG_CLEAR 1
#define CFLAG_SET 0x100
#define CFLAG_CLEAR 0
/* Codition code tests */
#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */
#define COND_CS() (FLAG_C&0x100) /* Carry Set */
#define COND_EQ() (!FLAG_Z) /* Equal */
#define COND_NE() FLAG_Z /* Not Equal */
#define COND_MI() (FLAG_N&0x80) /* Minus */
#define COND_PL() (!(FLAG_N&0x80)) /* Plus */
#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */
#define COND_VS() (FLAG_V&0x80) /* Overflow Set */
/* Set Overflow flag in math operations */
#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R))
#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8)
#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D))
#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8)
#define CFLAG_8(A) (A)
#define CFLAG_16(A) ((A)>>8)
#define NFLAG_8(A) (A)
#define NFLAG_16(A) ((A)>>8)
#define CFLAG_AS_1() ((FLAG_C>>8)&1)
/* update IRQ state (internal use only) */
void m37710i_update_irqs(void);
/* ======================================================================== */
/* ================================== CPU ================================= */
/* ======================================================================== */
#endif /* HEADER__M37710CM */
+4
View File
@@ -0,0 +1,4 @@
/* M37710 opcode table instance: from MAME 0.121 (MAME license; R. Belmont) */
#include "m37710cm.h"
#define EXECUTION_MODE EXECUTION_MODE_M0X0
#include "m37710op.h"
+4
View File
@@ -0,0 +1,4 @@
/* M37710 opcode table instance: from MAME 0.121 (MAME license; R. Belmont) */
#include "m37710cm.h"
#define EXECUTION_MODE EXECUTION_MODE_M0X1
#include "m37710op.h"
+4
View File
@@ -0,0 +1,4 @@
/* M37710 opcode table instance: from MAME 0.121 (MAME license; R. Belmont) */
#include "m37710cm.h"
#define EXECUTION_MODE EXECUTION_MODE_M1X0
#include "m37710op.h"
+4
View File
@@ -0,0 +1,4 @@
/* M37710 opcode table instance: from MAME 0.121 (MAME license; R. Belmont) */
#include "m37710cm.h"
#define EXECUTION_MODE EXECUTION_MODE_M1X1
#include "m37710op.h"
File diff suppressed because it is too large. Load diff
+18
View File
@@ -554,6 +554,24 @@ static void state_register(const char *type)
state_save_register_UINT8 (type, cpu, "NMI_STATE", &m6800.nmi_state, 1);
state_save_register_UINT8 (type, cpu, "IRQ_STATE", &m6800.irq_state[M6800_IRQ_LINE], 1);
state_save_register_UINT8 (type, cpu, "TIN_STATE", &m6800.irq_state[M6800_TIN_LINE], 1);
state_save_register_UINT16(type, cpu, "PPC", &m6800.ppc.w.l, 1);
state_save_register_UINT8 (type, cpu, "WAI_STATE", &m6800.wai_state, 1);
state_save_register_UINT8 (type, cpu, "IC_EDDGE", &m6800.ic_eddge, 1);
state_save_register_int (type, cpu, "EXTRA_CYCLES", &m6800.extra_cycles);
/* the internal registers of the 6801/6803/63701: ports, timer, RAM control */
state_save_register_UINT8 (type, cpu, "PORT1_DDR", &m6800.port1_ddr, 1);
state_save_register_UINT8 (type, cpu, "PORT2_DDR", &m6800.port2_ddr, 1);
state_save_register_UINT8 (type, cpu, "PORT1_DATA", &m6800.port1_data, 1);
state_save_register_UINT8 (type, cpu, "PORT2_DATA", &m6800.port2_data, 1);
state_save_register_UINT8 (type, cpu, "TCSR", &m6800.tcsr, 1);
state_save_register_UINT8 (type, cpu, "PENDING_TCSR", &m6800.pending_tcsr, 1);
state_save_register_UINT8 (type, cpu, "IRQ2", &m6800.irq2, 1);
state_save_register_UINT8 (type, cpu, "RAM_CTRL", &m6800.ram_ctrl, 1);
state_save_register_UINT32(type, cpu, "COUNTER", &m6800.counter.d, 1);
state_save_register_UINT32(type, cpu, "OUTPUT_COMPARE", &m6800.output_compare.d, 1);
state_save_register_UINT16(type, cpu, "INPUT_CAPTURE", &m6800.input_capture, 1);
state_save_register_UINT32(type, cpu, "TIMER_OVER", &m6800.timer_over.d, 1);
state_save_register_UINT32(type, cpu, "TIMER_NEXT", &timer_next, 1);
}
void m6800_init(void)
+8
View File
@@ -260,6 +260,14 @@ void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
*/
void m68k_set_instr_hook_callback(void (*callback)(void));
/* Called after CMPI.L #imm,Dn with the immediate value and the register
* number, and when an RTE is executed in supervisor mode. The FD1094 changes
* its decryption state on these. Shared by all the 68000 CPUs; m68k_init()
* clears them.
*/
extern void (*m68k_cmpild_callback)(unsigned int val, int reg);
extern void (*m68k_rte_callback)(void);
/* ======================================================================== */
+16
View File
@@ -4178,6 +4178,14 @@ M68KMAKE_OP(cmpi, 32, ., d)
FLAG_Z = MASK_OUT_ABOVE_32(res);
FLAG_V = VFLAG_SUB_32(src, dst, res);
FLAG_C = CFLAG_SUB_32(src, dst, res);
if (m68k_cmpild_callback)
{
m68k_cmpild_callback(src, REG_IR & 7);
#if M68K_EMULATE_PREFETCH
CPU_PREF_ADDR = 1; /* the next words are fetched again (FD1094 state change) */
#endif
}
}
@@ -8968,6 +8976,14 @@ M68KMAKE_OP(rte, 32, ., .)
m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
if (m68k_rte_callback)
{
m68k_rte_callback();
#if M68K_EMULATE_PREFETCH
CPU_PREF_ADDR = 1; /* fetched again with the new state */
#endif
}
if(CPU_TYPE_IS_000(CPU_TYPE))
{
new_sr = m68ki_pull_16();
+6
View File
@@ -68,6 +68,10 @@ char* m68ki_cpu_names[9] =
/* The CPU core */
m68ki_cpu_core m68ki_cpu = {0};
/* FD1094 hooks, shared by all the 68000 CPUs (see m68k.h) */
void (*m68k_cmpild_callback)(unsigned int val, int reg) = NULL;
void (*m68k_rte_callback)(void) = NULL;
#if M68K_EMULATE_ADDRESS_ERROR
jmp_buf m68ki_aerr_trap;
#endif /* M68K_EMULATE_ADDRESS_ERROR */
@@ -755,6 +759,8 @@ void m68k_init(void)
m68k_set_pc_changed_callback(NULL);
m68k_set_fc_callback(NULL);
m68k_set_instr_hook_callback(NULL);
m68k_cmpild_callback = NULL;
m68k_rte_callback = NULL;
}
/* Pulse the RESET line on the CPU */
+8
View File
@@ -11782,6 +11782,14 @@ void m68k_op_cmpi_32_d(void)
FLAG_Z = MASK_OUT_ABOVE_32(res);
FLAG_V = VFLAG_SUB_32(src, dst, res);
FLAG_C = CFLAG_SUB_32(src, dst, res);
if (m68k_cmpild_callback)
{
m68k_cmpild_callback(src, REG_IR & 7);
#if M68K_EMULATE_PREFETCH
CPU_PREF_ADDR = 1; /* the next words are fetched again (FD1094 state change) */
#endif
}
}
+8
View File
@@ -3924,6 +3924,14 @@ void m68k_op_rte_32(void)
m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
if (m68k_rte_callback)
{
m68k_rte_callback();
#if M68K_EMULATE_PREFETCH
CPU_PREF_ADDR = 1; /* fetched again with the new state */
#endif
}
if(CPU_TYPE_IS_000(CPU_TYPE))
{
new_sr = m68ki_pull_16();
+2
View File
@@ -512,12 +512,14 @@ void m6809_init(void)
state_save_register_UINT16("m6809", cpu, "S", &S, 1);
state_save_register_UINT16("m6809", cpu, "X", &X, 1);
state_save_register_UINT16("m6809", cpu, "Y", &Y, 1);
state_save_register_UINT16("m6809", cpu, "D", &D, 1); /* the accumulators A and B */
state_save_register_UINT8("m6809", cpu, "DP", &DP, 1);
state_save_register_UINT8("m6809", cpu, "CC", &CC, 1);
state_save_register_UINT8("m6809", cpu, "INT", &m6809.int_state, 1);
state_save_register_UINT8("m6809", cpu, "NMI", &m6809.nmi_state, 1);
state_save_register_UINT8("m6809", cpu, "IRQ", &m6809.irq_state[0], 1);
state_save_register_UINT8("m6809", cpu, "FIRQ", &m6809.irq_state[1], 1);
state_save_register_int("m6809", cpu, "extra_cycles", &m6809.extra_cycles); /* the cycles of an interrupt taken outside the execute loop */
}
void m6809_reset(void *param)
File diff suppressed because it is too large. Load diff
+46
View File
@@ -0,0 +1,46 @@
/***************************************************************************
Fujitsu MB86233/MB86234 (TGP), from current MAME
(src/devices/cpu/mb86233, copyright Olivier Galibert, BSD-3-Clause),
in C for MAME 2003. The four address spaces (program, data, io and
register file) are driver callbacks.
***************************************************************************/
#ifndef MB86233_H
#define MB86233_H
#include "osd_cpu.h"
struct mb86233_config
{
UINT32 (*prog_r)( UINT32 offset );
UINT32 (*data_r)( UINT32 offset );
void (*data_w)( UINT32 offset, UINT32 data );
UINT32 (*io_r)( UINT32 offset );
void (*io_w)( UINT32 offset, UINT32 data );
UINT32 (*rf_r)( UINT32 offset );
void (*rf_w)( UINT32 offset, UINT32 data );
};
extern int mb86233_icount;
extern void mb86233_init(void);
extern void mb86233_reset(void *param);
extern void mb86233_exit(void);
extern int mb86233_execute(int cycles);
extern unsigned mb86233_get_context(void *dst);
extern void mb86233_set_context(void *src);
extern unsigned mb86233_get_reg(int regnum);
extern void mb86233_set_reg(int regnum, unsigned val);
extern void mb86233_set_irq_line(int irqline, int state);
extern void mb86233_set_irq_callback(int (*callback)(int irqline));
extern const char *mb86233_info(void *context, int regnum);
extern unsigned mb86233_dasm(char *buffer, unsigned pc);
/* a memory callback that cannot complete now (FIFO empty or full):
the instruction is repeated */
extern void mb86233_stall(void);
extern void mb86233_gpio_w(int pin, int state);
#endif
File diff suppressed because it is too large. Load diff
+50
View File
@@ -0,0 +1,50 @@
/***************************************************************************
Fujitsu MB86235 "TGPx4", from current MAME
(src/devices/cpu/mb86235; copyright Angelo Salese, ElSemi, Ville Linde,
Matthew Daniels, BSD-3-Clause), the interpreter in C for MAME 2003.
Program memory, the external bus and the FIFOs are driver callbacks;
the internal A and B bus RAMs are part of the CPU.
***************************************************************************/
#ifndef MB86235_H
#define MB86235_H
#include "osd_cpu.h"
#define MB86235_FIFO_IFF 0 /* input FIFO full */
#define MB86235_FIFO_IFE 1 /* input FIFO empty */
#define MB86235_FIFO_OFF 2 /* output FIFO full */
#define MB86235_FIFO_OFE 3 /* output FIFO empty */
struct mb86235_config
{
UINT64 (*prog_r)( UINT32 offset ); /* 64-bit words, 12-bit address */
UINT32 (*ext_r)( UINT32 offset ); /* external bus, dword address */
void (*ext_w)( UINT32 offset, UINT32 data );
UINT32 (*fifoin_r)( void ); /* calls mb86235_stall() when empty */
void (*fifoout_w)( UINT32 data );
int (*fifo_flag)( int which );
void (*fifo_clear)( int which ); /* 0: input, 1: output */
};
extern int mb86235_icount;
extern void mb86235_init(void);
extern void mb86235_reset(void *param);
extern void mb86235_exit(void);
extern int mb86235_execute(int cycles);
extern unsigned mb86235_get_context(void *dst);
extern void mb86235_set_context(void *src);
extern unsigned mb86235_get_reg(int regnum);
extern void mb86235_set_reg(int regnum, unsigned val);
extern void mb86235_set_irq_line(int irqline, int state);
extern void mb86235_set_irq_callback(int (*callback)(int irqline));
extern const char *mb86235_info(void *context, int regnum);
extern unsigned mb86235_dasm(char *buffer, unsigned pc);
/* a FIFO read that cannot complete now: the instruction is repeated */
extern void mb86235_stall(void);
#endif
+457 -1
View File
@@ -13,6 +13,7 @@
**
**#################################################################################################*/
#include "mips3jit.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@@ -21,6 +22,7 @@
#include "driver.h"
#include "mamedbg.h"
#include "mips3.h"
#include "state.h"
#define ENABLE_OVERFLOWS 0
@@ -292,6 +294,193 @@ static const memory_handlers le_memory =
/*###################################################################################################
** OPTIONAL SPEEDUPS
**
** Off unless a driver enables them (currently only Killer Instinct):
** - fast RAM: plain RAM regions read and written through a direct pointer
** instead of the memory system, including instruction fetch;
** - idle loop: a loop that polls the COP0 Cause register for an interrupt
** gives up the rest of its timeslice instead of spinning.
** They live outside the CPU context and are cleared by mips3_init().
**#################################################################################################*/
#define MIPS3_MAX_FASTRAM 8
struct mips3_fastram
{
offs_t start;
offs_t end;
UINT8 * base;
UINT8 readonly;
int wait; /* cycles each data read costs (wait states), 0 = none */
};
static struct mips3_fastram fastram[MIPS3_MAX_FASTRAM];
static int fastram_count;
static offs_t fastram_byte_xor, fastram_word_xor;
static memory_handlers fastram_slow; /* handlers for everything else */
static int fastram_has_wait; /* a region with read wait states exists */
/* exact skip of the loops that poll Cause for an interrupt (see cause_poll_skip) */
#define MIPS3_MAX_POLLREAD 4
static int cause_poll_enabled;
static struct { offs_t start, end; } pollread[MIPS3_MAX_POLLREAD];
static int pollread_count;
void mips3_add_fastram(offs_t start, offs_t end, int readonly, void *base)
{
mips3_add_fastram_wait(start, end, readonly, base, 0);
}
/* the same, with wait states: each data read (not instruction fetch) costs */
/* wait cycles, as a slow ROM does (instruction fetch and translation stay direct) */
void mips3_add_fastram_wait(offs_t start, offs_t end, int readonly, void *base, int wait)
{
if (fastram_count < MIPS3_MAX_FASTRAM)
{
fastram[fastram_count].start = start;
fastram[fastram_count].end = end;
fastram[fastram_count].base = (UINT8 *)base;
fastram[fastram_count].readonly = readonly;
fastram[fastram_count].wait = wait;
if (wait)
fastram_has_wait = 1;
fastram_count++;
}
}
void mips3_set_cause_poll_skip(int enable)
{
cause_poll_enabled = enable;
}
void mips3_add_poll_read(offs_t start, offs_t end)
{
if (pollread_count < MIPS3_MAX_POLLREAD)
{
pollread[pollread_count].start = start;
pollread[pollread_count].end = end;
pollread_count++;
}
}
static struct mips3_fastram *fastram_last = &fastram[0];
/* recompiler hook (mips3jit.c): a write may hit translated code */
static INLINE void jit_check_write(const void *host);
static INLINE struct mips3_fastram *find_fastram(offs_t address)
{
struct mips3_fastram *r = fastram_last;
int i;
/* most accesses hit the same region as the previous one */
if (address - r->start <= r->end - r->start)
return r;
for (i = 0; i < fastram_count; i++)
if (address - fastram[i].start <= fastram[i].end - fastram[i].start)
return fastram_last = &fastram[i];
return NULL;
}
static data8_t fastram_readbyte(offs_t address)
{
struct mips3_fastram *r = find_fastram(address);
if (r) { mips3_icount -= r->wait; return r->base[(address - r->start) ^ fastram_byte_xor]; }
return (*fastram_slow.readbyte)(address);
}
static data16_t fastram_readword(offs_t address)
{
struct mips3_fastram *r = find_fastram(address);
if (r) { mips3_icount -= r->wait; return *(data16_t *)&r->base[(address - r->start) ^ fastram_word_xor]; }
return (*fastram_slow.readword)(address);
}
static data32_t fastram_readlong(offs_t address)
{
struct mips3_fastram *r = find_fastram(address);
if (r) { mips3_icount -= r->wait; return *(data32_t *)&r->base[address - r->start]; }
return (*fastram_slow.readlong)(address);
}
static UINT64 fastram_readdouble(offs_t address)
{
struct mips3_fastram *r = find_fastram(address);
if (r && address + 7 <= r->end)
{
UINT64 first;
UINT64 second;
mips3_icount -= r->wait;
first = *(data32_t *)&r->base[address - r->start];
second = *(data32_t *)&r->base[address + 4 - r->start];
return mips3.bigendian ? ((first << 32) | second) : (first | (second << 32));
}
return (*fastram_slow.readdouble)(address);
}
static void fastram_writebyte(offs_t address, data8_t data)
{
struct mips3_fastram *r = find_fastram(address);
if (r && !r->readonly) { jit_check_write(&r->base[address - r->start]); r->base[(address - r->start) ^ fastram_byte_xor] = data; return; }
(*fastram_slow.writebyte)(address, data);
}
static void fastram_writeword(offs_t address, data16_t data)
{
struct mips3_fastram *r = find_fastram(address);
if (r && !r->readonly) { jit_check_write(&r->base[address - r->start]); *(data16_t *)&r->base[(address - r->start) ^ fastram_word_xor] = data; return; }
(*fastram_slow.writeword)(address, data);
}
static void fastram_writelong(offs_t address, data32_t data)
{
struct mips3_fastram *r = find_fastram(address);
if (r && !r->readonly) { jit_check_write(&r->base[address - r->start]); *(data32_t *)&r->base[address - r->start] = data; return; }
(*fastram_slow.writelong)(address, data);
}
static void fastram_writedouble(offs_t address, UINT64 data)
{
struct mips3_fastram *r = find_fastram(address);
if (r && !r->readonly && address + 7 <= r->end)
{
jit_check_write(&r->base[address - r->start]);
jit_check_write(&r->base[address + 4 - r->start]);
*(data32_t *)&r->base[address - r->start] = mips3.bigendian ? (data32_t)(data >> 32) : (data32_t)data;
*(data32_t *)&r->base[address + 4 - r->start] = mips3.bigendian ? (data32_t)data : (data32_t)(data >> 32);
return;
}
(*fastram_slow.writedouble)(address, data);
}
static const memory_handlers fastram_memory =
{
fastram_readbyte, fastram_readword, fastram_readlong, fastram_readdouble,
fastram_writebyte, fastram_writeword, fastram_writelong, fastram_writedouble
};
/* switch the memory handlers when fast RAM is in use */
static void fastram_attach(void)
{
if (!fastram_count || mips3.memory.readlong == fastram_readlong)
return;
fastram_slow = mips3.bigendian ? be_memory : le_memory;
fastram_byte_xor = mips3.bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0);
fastram_word_xor = mips3.bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0);
mips3.memory = fastram_memory;
}
#include "mips3jit.c"
/*###################################################################################################
** MEMORY ACCESSORS
**#################################################################################################*/
@@ -439,9 +628,66 @@ static void compare_int_callback(int cpu)
}
/* the Compare interrupt timer is not saved by the core: whether it is set
is. After a load it is set again from Count and Compare, in cycles of
this CPU, as a write to Compare sets it (both functions run in the
context of this CPU) */
static UINT8 compare_timer_set;
static void mips3_presave(void)
{
compare_timer_set = (timer_timeleft(mips3.compare_int_timer) < TIME_NEVER / 2);
}
static void mips3_postload(void)
{
int cpunum = cpu_getactivecpu();
timer_adjust(mips3.compare_int_timer, TIME_NEVER, cpunum, 0);
if (compare_timer_set)
{
UINT32 count = (cpu_gettotalcycles64(cpunum) - mips3.count_zero_time) / 2;
UINT32 cyclesleft = (UINT32)mips3.cpr[0][COP0_Compare] - count;
timer_adjust(mips3.compare_int_timer, TIME_IN_CYCLES(((UINT64)cyclesleft * 2), cpunum), cpunum, 0);
}
if (mips3.bigendian)
change_pc32bedw(mips3.pc);
else
change_pc32ledw(mips3.pc);
}
void mips3_init(void)
{
int cpunum = cpu_getactivecpu();
/* optional speedups are off until a driver asks for them */
fastram_count = 0;
fastram_has_wait = 0;
fastram_last = &fastram[0];
mips3_set_jit(0);
cause_poll_enabled = 0;
pollread_count = 0;
mips3.compare_int_timer = timer_alloc(compare_int_callback);
/* save states: the registers of the active context, swapped in per CPU
when the state is saved; the 64-bit registers as pairs of 32 bits */
state_save_register_UINT32("mips3", cpunum, "pc", &mips3.pc, 1);
state_save_register_UINT32("mips3", cpunum, "hi", (UINT32 *)&mips3.hi, 2);
state_save_register_UINT32("mips3", cpunum, "lo", (UINT32 *)&mips3.lo, 2);
state_save_register_UINT32("mips3", cpunum, "r", (UINT32 *)mips3.r, 32 * 2);
state_save_register_UINT32("mips3", cpunum, "cpr", (UINT32 *)mips3.cpr, 4 * 32 * 2);
state_save_register_UINT32("mips3", cpunum, "ccr", (UINT32 *)mips3.ccr, 4 * 32 * 2);
state_save_register_UINT8 ("mips3", cpunum, "cf", mips3.cf, 4);
state_save_register_UINT32("mips3", cpunum, "ppc", &mips3.ppc, 1);
state_save_register_UINT32("mips3", cpunum, "nextpc", &mips3.nextpc, 1);
state_save_register_int ("mips3", cpunum, "op", &mips3.op);
state_save_register_int ("mips3", cpunum, "interrupt_cycles", &mips3.interrupt_cycles);
state_save_register_UINT32("mips3", cpunum, "count_zero_time", (UINT32 *)&mips3.count_zero_time, 2);
state_save_register_UINT8 ("mips3", cpunum, "compare_timer_set", &compare_timer_set, 1);
state_save_register_func_presave(mips3_presave);
state_save_register_func_postload(mips3_postload);
}
@@ -535,6 +781,8 @@ void r5000le_reset(void *param)
void mips3_exit(void)
{
mips3_set_jit(0);
/* free cache memory */
if (mips3.icache)
free(mips3.icache);
@@ -624,6 +872,9 @@ static INLINE void set_cop0_reg(int idx, UINT64 val)
mips3.cpr[0][idx] = val;
if (diff & 0x8000)
update_cycle_counting();
/* the recompiler translates FPU instructions only while COP1 is usable */
if (diff & SR_COP1)
jit_flush();
check_irqs();
break;
}
@@ -682,6 +933,155 @@ static void logtlbentry(void)
logonetlbentry(1);
}
/*
Exact skip of the loops that wait for an interrupt by polling Cause.
Within a timeslice nothing changes Cause: interrupt lines and the
Count/Compare timer only change between timeslices. So every pass of
such a loop leaves the same state, except for counters, and the whole
passes that still fit in the timeslice can be skipped: registers and
cycles end up exactly as if they had run. The last passes always run
normally. Called by the MFC0 of Cause (mips3.ppc), after its read.
The loop, from the branch target L to the backward branch and its
delay slot, may only hold:
mfc0 rt, Cause (this instruction, once)
andi rt, rt, mask (Cause & mask is 0 now)
nop
lw/lh/lb $zero, off(rb) (rb + off in a range declared free of
side effects, mips3_add_poll_read)
beq rc, $zero, outside (a timeout counter)
beq rt, $zero, L (the loop branch, last)
delay slot: nop, or addi/addiu rc, rc, imm (a counter)
A timeout counter must count down by 1 and stays at 1 or more.
*/
static void cause_poll_skip(UINT32 mfc0_op)
{
UINT32 pc = mips3.ppc, a, op, branch_pc = 0, rt = (mfc0_op >> 16) & 31, mask = 0;
int count, i, n, cost, rc = -1, timeout = 0;
INT32 imm = 0;
UINT32 body[16];
if (rt == 0 || mips3.nextpc != ~0)
return;
/* find the backward branch beq rt, $zero, L with L <= pc */
for (a = pc + 4; a < pc + 4 * 12; a += 4)
{
op = ROPCODE(a);
if ((op >> 26) == 0x04 && ((op >> 21) & 31) == rt && ((op >> 16) & 31) == 0)
{
UINT32 target = a + 4 + ((INT32)(INT16)op << 2);
if (target <= pc && pc - target < 4 * 8)
{
branch_pc = a;
break;
}
}
}
if (!branch_pc)
return;
{
UINT32 target = branch_pc + 4 + ((INT32)(INT16)ROPCODE(branch_pc) << 2);
count = (branch_pc + 8 - target) / 4;
if (count > 16)
return;
for (i = 0; i < count; i++)
body[i] = ROPCODE(target + i * 4);
a = target;
}
/* check every instruction of the loop */
for (i = 0; i < count; i++)
{
UINT32 ia = a + i * 4;
op = body[i];
if (ia == pc)
continue;
if (ia == branch_pc)
continue;
if (op == 0)
continue;
if (ia == branch_pc + 4)
{
/* delay slot: a counter */
if (((op >> 26) == 0x08 || (op >> 26) == 0x09) && ((op >> 21) & 31) == ((op >> 16) & 31) &&
((op >> 16) & 31) != 0 && ((op >> 16) & 31) != rt)
{
rc = (op >> 16) & 31;
imm = (INT16)op;
continue;
}
return;
}
if ((op >> 26) == 0x0c && ((op >> 21) & 31) == rt && ((op >> 16) & 31) == rt)
{
/* the mask, between the mfc0 and the branch */
if (ia < pc || ia > branch_pc)
return;
mask |= op & 0xffff;
continue;
}
if (((op >> 26) == 0x23 || (op >> 26) == 0x21 || (op >> 26) == 0x20) && ((op >> 16) & 31) == 0)
{
UINT32 address = (UINT32)mips3.r[(op >> 21) & 31] + (INT16)op;
int p, ok = 0;
for (p = 0; p < pollread_count; p++)
if (address >= pollread[p].start && address <= pollread[p].end)
ok = 1;
if (ok)
continue;
return;
}
if ((op >> 26) == 0x04 && ((op >> 16) & 31) == 0 && ((op >> 21) & 31) != rt)
{
/* a timeout: beq rc, $zero, out of the loop */
UINT32 target = ia + 4 + ((INT32)(INT16)op << 2);
if (target >= a && target <= branch_pc + 4)
return;
if (timeout)
return;
timeout = (op >> 21) & 31;
continue;
}
return;
}
if (!mask || (CAUSE & mask))
return;
if (timeout && (timeout != rc || imm != -1))
return;
/* whole passes that fit, leaving at least two to run normally */
cost = count + 25;
n = mips3_icount / cost - 2;
if (n <= 0)
return;
if (rc >= 0)
{
INT64 value = (INT32)(UINT32)mips3.r[rc];
if (timeout)
{
if (value <= 1)
return;
if (n > value - 1)
n = (int)(value - 1);
}
else if ((body[(branch_pc + 4 - a) / 4] >> 26) == 0x08)
{
/* ADDI traps on overflow: stop before it */
INT64 limit = imm > 0 ? ((INT64)0x7fffffff - value) / imm : (value + (INT64)0x80000000) / -imm;
if (imm == 0)
limit = n;
if (n > limit)
n = (int)limit;
}
if (n <= 0)
return;
mips3.r[rc] = (INT64)(INT32)((UINT32)value + (UINT32)(imm * n));
}
mips3_icount -= n * cost;
}
static INLINE void handle_cop0(UINT32 op)
{
if ((SR & SR_KSU_MASK) != SR_KSU_KERNEL && !(SR & SR_COP0))
@@ -689,7 +1089,11 @@ static INLINE void handle_cop0(UINT32 op)
switch (RSREG)
{
case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_reg(RDREG); break;
case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_reg(RDREG);
/* optional: whole passes of a loop waiting for an interrupt in Cause */
if (cause_poll_enabled && RDREG == COP0_Cause)
cause_poll_skip(op);
break;
case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop0_reg(RDREG); break;
case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_creg(RDREG); break;
case 0x04: /* MTCz */ set_cop0_reg(RDREG, RTVAL32); break;
@@ -1119,6 +1523,14 @@ static INLINE void handle_cop1(UINT32 op)
/* a COP1 instruction (not a branch) from translated code: exactly the interpreter's */
static void jit_cop1_helper(UINT32 op)
{
handle_cop1(op);
}
/*###################################################################################################
** COP1X (FPU EXTRA) EXECUTION HANDLING
**#################################################################################################*/
@@ -1283,6 +1695,9 @@ int mips3_execute(int cycles)
change_pc32bedw(mips3.pc);
/* optional fast RAM (see mips3_add_fastram) */
fastram_attach();
/* check for IRQs */
check_irqs();
@@ -1297,6 +1712,47 @@ int mips3_execute(int cycles)
mips3.ppc = mips3.pc;
CALL_MAME_DEBUG;
#if MIPS3_JIT_SUPPORTED
/* recompiled block, when there are enough cycles left for all of it */
if (jit_enabled && mips3.nextpc == ~0)
{
struct jit_block *block = jit_lookup(mips3.pc);
if (block && (int)block->len <= mips3_icount)
{
/* run blocks back to back while they fit in the timeslice; */
/* each takes its own cycles, and none taken means a side exit */
/* before its first instruction, which the interpreter then runs */
int ran = 0, stalled = 0;
for (;;)
{
int before = mips3_icount;
mips3.pc = ((jit_func)block->code)();
if (mips3_icount == before)
{
stalled = 1;
break;
}
ran = 1;
if (mips3_icount <= 0)
break;
block = jit_lookup(mips3.pc);
if (!block || (int)block->len > mips3_icount)
break;
}
if (ran)
{
change_pc32bedw(mips3.pc);
if (!stalled)
{
mips3.ppc = mips3.pc - 4;
continue;
}
mips3.ppc = mips3.pc;
}
}
}
#endif
/* instruction fetch */
op = ROPCODE(mips3.pc);
+14
View File
@@ -183,6 +183,20 @@ extern void r5000le_reset(void *param);
void mips3drc_set_options(UINT8 cpunum, UINT32 opts);
/* optional speedups for a single MIPS3 CPU, off by default; set them up in DRIVER_INIT */
/* plain RAM accessed through a direct pointer (no handlers may sit in the range) */
void mips3_add_fastram(offs_t start, offs_t end, int readonly, void *base);
void mips3_add_fastram_wait(offs_t start, offs_t end, int readonly, void *base, int wait);
/* skip, exactly, the whole passes of loops waiting for an interrupt in Cause (see mips3.c) */
void mips3_set_cause_poll_skip(int enable);
/* loads from this range, into $zero, have no side effects (they may sit in such a loop) */
void mips3_add_poll_read(offs_t start, offs_t end);
/* recompile integer code in fast RAM with sljit, where supported (x86 and ARM, 32 and 64-bit) */
void mips3_set_jit(int enable);
void mips3_ram_written(offs_t address, UINT32 bytes);
/* nonzero when this build has the recompiler (x86/ARM hosts that allow run-time code) */
int mips3_jit_available(void);
#endif /* _MIPS3_H */
+46
View File
@@ -5830,3 +5830,49 @@ unsigned mips3_dasm(char *buffer, unsigned pc)
return 4;
#endif
}
/*###################################################################################################
** OPTIONAL SPEEDUPS (see mips3.h)
**
** This x86 recompiler is built instead of mips3.c when X86_MIPS3_DRC is set (32-bit x86 hosts).
** The speedups declared in mips3.h live in mips3.c; here they are accepted and ignored, so
** drivers that request them (Killer Instinct) still link and run, just without them.
**#################################################################################################*/
void mips3_add_fastram(offs_t start, offs_t end, int readonly, void *base)
{
(void)start; (void)end; (void)readonly; (void)base;
}
void mips3_add_fastram_wait(offs_t start, offs_t end, int readonly, void *base, int wait)
{
(void)start; (void)end; (void)readonly; (void)base; (void)wait;
}
void mips3_set_cause_poll_skip(int enable)
{
(void)enable;
}
void mips3_add_poll_read(offs_t start, offs_t end)
{
(void)start; (void)end;
}
void mips3_set_jit(int enable)
{
(void)enable;
}
int mips3_jit_available(void)
{
/* no sljit recompiler in this build: the "MIPS Dynarec" core option stays hidden */
return 0;
}
void mips3_ram_written(offs_t address, UINT32 bytes)
{
/* no translations to drop in this build */
(void)address; (void)bytes;
}
File diff suppressed because it is too large. Load diff
+18
View File
@@ -0,0 +1,18 @@
/***************************************************************************
mips3jit.h
Host support of the MIPS3 recompiler: the bundled sljit, configured
and built once for all the recompilers (src/lib/sljit/sljit_mame.h).
***************************************************************************/
#ifndef MIPS3JIT_H
#define MIPS3JIT_H
/* the sljit build shared by the recompilers decides where they run */
#include "../../lib/sljit/sljit_mame.h"
#define MIPS3_JIT_SUPPORTED SLJIT_MAME_SUPPORTED
#endif /* MIPS3JIT_H */
+14
View File
@@ -213,6 +213,20 @@ extern void mips_set_irq_callback(int (*callback)(int irqline));
extern const char *mips_info(void *context, int regnum);
extern unsigned mips_dasm(char *buffer, UINT32 pc);
/* optional speedups, off unless a driver enables them */
/* loads and stores in a plain RAM region use a direct pointer */
extern void psxcpu_add_fastram(offs_t start, offs_t end, int readonly, void *base);
/* fast RAM written behind the CPU's back (DMA, driver patches) */
extern void psxcpu_ram_written(const void *host, UINT32 bytes);
/* recompiler (sljit), where supported. The fast RAM table and the
recompiler state are global, not part of the CPU context: one PSXCPU
per machine. */
extern int psxcpu_jit_available(void);
extern void psxcpu_set_jit(int enable);
/* fn is called before the instruction at pc runs (NULL: none); set at */
/* machine init, cleared at the CPU init */
extern void psxcpu_set_pc_hook(UINT32 pc, void (*fn)(void));
#ifdef MAME_DEBUG
extern unsigned DasmMIPS(char *buff, unsigned _pc);
#endif
+1353 -1923
View File
File diff suppressed because it is too large. Load diff
+941
View File
@@ -0,0 +1,941 @@
/***************************************************************************
PlayStation Geometry Transformation Engine, as current MAME
(src/devices/cpu/psx/gte.cpp, copyright smf, BSD-3-Clause), in C.
The hardware divide (reciprocal table, result capped at 0x1ffff and
flagged), the 44-bit accumulators with their overflow flags, the
register moves (IRGB/ORGB, LZCS/LZCR, the sign extended control
registers, FLAG) of current MAME.
***************************************************************************/
#define GTE_SF( op ) ( ( op >> 19 ) & 1 )
#define GTE_MX( op ) ( ( op >> 17 ) & 3 )
#define GTE_V( op ) ( ( op >> 15 ) & 3 )
#define GTE_CV( op ) ( ( op >> 13 ) & 3 )
#define GTE_LM( op ) ( ( op >> 10 ) & 1 )
#define GTE_FUNCT( op ) ( op & 63 )
static int m_sf;
static INT64 m_mac0;
static INT64 m_mac1;
static INT64 m_mac2;
static INT64 m_mac3;
static INLINE int count_leading_zeros32( UINT32 v )
{
int n = 0;
if( v == 0 )
{
return 32;
}
while( ( v & 0x80000000 ) == 0 )
{
v <<= 1;
n++;
}
return n;
}
/* a 44-bit accumulator with sticky overflow flags (MAME's int44) */
typedef struct
{
INT64 value;
int pos;
int neg;
} int44;
static INLINE int44 i44( INT64 value )
{
int44 r;
r.value = value;
r.pos = value > ( ( (INT64)1 << 43 ) - 1 );
r.neg = value < -( (INT64)1 << 43 );
return r;
}
static INLINE int44 i44_add( int44 a, INT64 add )
{
int44 r;
INT64 value = (INT64)( (UINT64)( a.value + add ) << 20 ) >> 20;
r.value = value;
r.pos = a.pos || ( value < 0 && a.value >= 0 && add >= 0 );
r.neg = a.neg || ( value >= 0 && a.value < 0 && add < 0 );
return r;
}
#define VX0 ( (*(INT16 *)&mipscpu.cp2dr[ 0 ].w.l) )
#define VY0 ( (*(INT16 *)&mipscpu.cp2dr[ 0 ].w.h) )
#define VZ0 ( (*(INT16 *)&mipscpu.cp2dr[ 1 ].w.l) )
#define VX1 ( mipscpu.cp2dr[ 2 ].w.l )
#define VY1 ( mipscpu.cp2dr[ 2 ].w.h )
#define VZ1 ( mipscpu.cp2dr[ 3 ].w.l )
#define VX2 ( mipscpu.cp2dr[ 4 ].w.l )
#define VY2 ( mipscpu.cp2dr[ 4 ].w.h )
#define VZ2 ( mipscpu.cp2dr[ 5 ].w.l )
#define R ( mipscpu.cp2dr[ 6 ].b.l )
#define G ( mipscpu.cp2dr[ 6 ].b.h )
#define B ( mipscpu.cp2dr[ 6 ].b.h2 )
#define CODE ( mipscpu.cp2dr[ 6 ].b.h3 )
#define OTZ ( mipscpu.cp2dr[ 7 ].w.l )
#define IR0 ( (*(INT16 *)&mipscpu.cp2dr[ 8 ].w.l) )
#define IR1 ( (*(INT16 *)&mipscpu.cp2dr[ 9 ].w.l) )
#define IR2 ( (*(INT16 *)&mipscpu.cp2dr[ 10 ].w.l) )
#define IR3 ( (*(INT16 *)&mipscpu.cp2dr[ 11 ].w.l) )
#define SXY0 ( mipscpu.cp2dr[ 12 ].d )
#define SX0 ( (*(INT16 *)&mipscpu.cp2dr[ 12 ].w.l) )
#define SY0 ( (*(INT16 *)&mipscpu.cp2dr[ 12 ].w.h) )
#define SXY1 ( mipscpu.cp2dr[ 13 ].d )
#define SX1 ( (*(INT16 *)&mipscpu.cp2dr[ 13 ].w.l) )
#define SY1 ( (*(INT16 *)&mipscpu.cp2dr[ 13 ].w.h) )
#define SXY2 ( mipscpu.cp2dr[ 14 ].d )
#define SX2 ( (*(INT16 *)&mipscpu.cp2dr[ 14 ].w.l) )
#define SY2 ( (*(INT16 *)&mipscpu.cp2dr[ 14 ].w.h) )
#define SXYP ( mipscpu.cp2dr[ 15 ].d )
#define SXP ( (*(INT16 *)&mipscpu.cp2dr[ 15 ].w.l) )
#define SYP ( (*(INT16 *)&mipscpu.cp2dr[ 15 ].w.h) )
#define SZ0 ( mipscpu.cp2dr[ 16 ].w.l )
#define SZ1 ( mipscpu.cp2dr[ 17 ].w.l )
#define SZ2 ( mipscpu.cp2dr[ 18 ].w.l )
#define SZ3 ( mipscpu.cp2dr[ 19 ].w.l )
#define RGB0 ( mipscpu.cp2dr[ 20 ].d )
#define R0 ( mipscpu.cp2dr[ 20 ].b.l )
#define G0 ( mipscpu.cp2dr[ 20 ].b.h )
#define B0 ( mipscpu.cp2dr[ 20 ].b.h2 )
#define CD0 ( mipscpu.cp2dr[ 20 ].b.h3 )
#define RGB1 ( mipscpu.cp2dr[ 21 ].d )
#define R1 ( mipscpu.cp2dr[ 21 ].b.l )
#define G1 ( mipscpu.cp2dr[ 21 ].b.h )
#define B1 ( mipscpu.cp2dr[ 21 ].b.h2 )
#define CD1 ( mipscpu.cp2dr[ 21 ].b.h3 )
#define RGB2 ( mipscpu.cp2dr[ 22 ].d )
#define R2 ( mipscpu.cp2dr[ 22 ].b.l )
#define G2 ( mipscpu.cp2dr[ 22 ].b.h )
#define B2 ( mipscpu.cp2dr[ 22 ].b.h2 )
#define CD2 ( mipscpu.cp2dr[ 22 ].b.h3 )
#define RES1 ( mipscpu.cp2dr[ 23 ].d )
#define MAC0 ( (*(INT32 *)&mipscpu.cp2dr[ 24 ].d) )
#define MAC1 ( (*(INT32 *)&mipscpu.cp2dr[ 25 ].d) )
#define MAC2 ( (*(INT32 *)&mipscpu.cp2dr[ 26 ].d) )
#define MAC3 ( (*(INT32 *)&mipscpu.cp2dr[ 27 ].d) )
#define IRGB ( mipscpu.cp2dr[ 28 ].d )
#define ORGB ( mipscpu.cp2dr[ 29 ].d )
#define LZCS ( mipscpu.cp2dr[ 30 ].d )
#define LZCR ( mipscpu.cp2dr[ 31 ].d )
#define R11 ( (*(INT16 *)&mipscpu.cp2cr[ 0 ].w.l) )
#define R12 ( (*(INT16 *)&mipscpu.cp2cr[ 0 ].w.h) )
#define R13 ( (*(INT16 *)&mipscpu.cp2cr[ 1 ].w.l) )
#define R21 ( (*(INT16 *)&mipscpu.cp2cr[ 1 ].w.h) )
#define R22 ( (*(INT16 *)&mipscpu.cp2cr[ 2 ].w.l) )
#define R23 ( (*(INT16 *)&mipscpu.cp2cr[ 2 ].w.h) )
#define R31 ( (*(INT16 *)&mipscpu.cp2cr[ 3 ].w.l) )
#define R32 ( (*(INT16 *)&mipscpu.cp2cr[ 3 ].w.h) )
#define R33 ( (*(INT16 *)&mipscpu.cp2cr[ 4 ].w.l) )
#define TRX ( (*(INT32 *)&mipscpu.cp2cr[ 5 ].d) )
#define TRY ( (*(INT32 *)&mipscpu.cp2cr[ 6 ].d) )
#define TRZ ( (*(INT32 *)&mipscpu.cp2cr[ 7 ].d) )
#define L11 ( (*(INT16 *)&mipscpu.cp2cr[ 8 ].w.l) )
#define L12 ( (*(INT16 *)&mipscpu.cp2cr[ 8 ].w.h) )
#define L13 ( (*(INT16 *)&mipscpu.cp2cr[ 9 ].w.l) )
#define L21 ( (*(INT16 *)&mipscpu.cp2cr[ 9 ].w.h) )
#define L22 ( (*(INT16 *)&mipscpu.cp2cr[ 10 ].w.l) )
#define L23 ( (*(INT16 *)&mipscpu.cp2cr[ 10 ].w.h) )
#define L31 ( (*(INT16 *)&mipscpu.cp2cr[ 11 ].w.l) )
#define L32 ( (*(INT16 *)&mipscpu.cp2cr[ 11 ].w.h) )
#define L33 ( (*(INT16 *)&mipscpu.cp2cr[ 12 ].w.l) )
#define RBK ( (*(INT32 *)&mipscpu.cp2cr[ 13 ].d) )
#define GBK ( (*(INT32 *)&mipscpu.cp2cr[ 14 ].d) )
#define BBK ( (*(INT32 *)&mipscpu.cp2cr[ 15 ].d) )
#define LR1 ( (*(INT16 *)&mipscpu.cp2cr[ 16 ].w.l) )
#define LR2 ( (*(INT16 *)&mipscpu.cp2cr[ 16 ].w.h) )
#define LR3 ( (*(INT16 *)&mipscpu.cp2cr[ 17 ].w.l) )
#define LG1 ( (*(INT16 *)&mipscpu.cp2cr[ 17 ].w.h) )
#define LG2 ( (*(INT16 *)&mipscpu.cp2cr[ 18 ].w.l) )
#define LG3 ( (*(INT16 *)&mipscpu.cp2cr[ 18 ].w.h) )
#define LB1 ( (*(INT16 *)&mipscpu.cp2cr[ 19 ].w.l) )
#define LB2 ( (*(INT16 *)&mipscpu.cp2cr[ 19 ].w.h) )
#define LB3 ( (*(INT16 *)&mipscpu.cp2cr[ 20 ].w.l) )
#define RFC ( (*(INT32 *)&mipscpu.cp2cr[ 21 ].d) )
#define GFC ( (*(INT32 *)&mipscpu.cp2cr[ 22 ].d) )
#define BFC ( (*(INT32 *)&mipscpu.cp2cr[ 23 ].d) )
#define OFX ( (*(INT32 *)&mipscpu.cp2cr[ 24 ].d) )
#define OFY ( (*(INT32 *)&mipscpu.cp2cr[ 25 ].d) )
#define H ( (*(INT16 *)&mipscpu.cp2cr[ 26 ].w.l) )
#define DQA ( (*(INT16 *)&mipscpu.cp2cr[ 27 ].w.l) )
#define DQB ( (*(INT32 *)&mipscpu.cp2cr[ 28 ].d) )
#define ZSF3 ( (*(INT16 *)&mipscpu.cp2cr[ 29 ].w.l) )
#define ZSF4 ( (*(INT16 *)&mipscpu.cp2cr[ 30 ].w.l) )
#define FLAG ( mipscpu.cp2cr[ 31 ].d )
#define VX( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2dr[ n << 1 ].w.l) : IR1 )
#define VY( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2dr[ n << 1 ].w.h) : IR2 )
#define VZ( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2dr[ ( n << 1 ) + 1 ].w.l) : IR3 )
#define MX11( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) ].w.l) : -R << 4 )
#define MX12( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) ].w.h) : R << 4 )
#define MX13( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 1 ].w.l) : IR0 )
#define MX21( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 1 ].w.h) : R13 )
#define MX22( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 2 ].w.l) : R13 )
#define MX23( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 2 ].w.h) : R13 )
#define MX31( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 3 ].w.l) : R22 )
#define MX32( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 3 ].w.h) : R22 )
#define MX33( n ) ( n < 3 ? (*(INT16 *)&mipscpu.cp2cr[ ( n << 3 ) + 4 ].w.l) : R22 )
#define CV1( n ) ( n < 3 ? (*(INT32 *)&mipscpu.cp2cr[ ( n << 3 ) + 5 ].d) : 0 )
#define CV2( n ) ( n < 3 ? (*(INT32 *)&mipscpu.cp2cr[ ( n << 3 ) + 6 ].d) : 0 )
#define CV3( n ) ( n < 3 ? (*(INT32 *)&mipscpu.cp2cr[ ( n << 3 ) + 7 ].d) : 0 )
static INT32 LIM( INT32 value, INT32 max, INT32 min, UINT32 flag )
{
if( value > max )
{
FLAG |= flag;
return max;
}
else if( value < min )
{
FLAG |= flag;
return min;
}
return value;
}
static UINT32 getcp2dr( int reg )
{
switch( reg )
{
case 1:
case 3:
case 5:
case 8:
case 9:
case 10:
case 11:
mipscpu.cp2dr[ reg ].d = (INT32)(*(INT16 *)&mipscpu.cp2dr[ reg ].w.l);
break;
case 7:
case 16:
case 17:
case 18:
case 19:
mipscpu.cp2dr[ reg ].d = (UINT32)mipscpu.cp2dr[ reg ].w.l;
break;
case 15:
mipscpu.cp2dr[ reg ].d = SXY2;
break;
case 28:
case 29:
mipscpu.cp2dr[ reg ].d = LIM( IR1 >> 7, 0x1f, 0, 0 ) | ( LIM( IR2 >> 7, 0x1f, 0, 0 ) << 5 ) | ( LIM( IR3 >> 7, 0x1f, 0, 0 ) << 10 );
break;
}
return mipscpu.cp2dr[ reg ].d;
}
static void setcp2dr( int reg, UINT32 value )
{
switch( reg )
{
case 15:
SXY0 = SXY1;
SXY1 = SXY2;
SXY2 = value;
break;
case 28:
IR1 = ( value & 0x1f ) << 7;
IR2 = ( value & 0x3e0 ) << 2;
IR3 = ( value & 0x7c00 ) >> 3;
break;
case 30:
LZCR = ( value & 0x80000000 ) == 0 ? count_leading_zeros32( value ) : count_leading_zeros32( ~value );
break;
case 31:
return;
}
mipscpu.cp2dr[ reg ].d = value;
}
static UINT32 getcp2cr( int reg )
{
return mipscpu.cp2cr[ reg ].d;
}
static void setcp2cr( int reg, UINT32 value )
{
switch( reg )
{
case 4:
case 12:
case 20:
case 26:
case 27:
case 29:
case 30:
value = (INT32)(INT16) value;
break;
case 31:
value = value & 0x7ffff000;
if( ( value & 0x7f87e000 ) != 0 )
{
value |= 0x80000000;
}
break;
}
mipscpu.cp2cr[ reg ].d = value;
}
static INLINE INT64 gte_shift( INT64 a, int sf )
{
if( sf > 0 )
{
return a >> 12;
}
else if( sf < 0 )
{
return a << 12;
}
return a;
}
static INT32 BOUNDS( int44 value, UINT32 max_flag, UINT32 min_flag )
{
if( value.pos )
{
FLAG |= max_flag;
}
if( value.neg )
{
FLAG |= min_flag;
}
return gte_shift( value.value, m_sf );
}
static INLINE UINT32 gte_divide( UINT16 numerator, UINT16 denominator )
{
if( numerator < ( denominator * 2 ) )
{
static const UINT8 table[] =
{
0xff, 0xfd, 0xfb, 0xf9, 0xf7, 0xf5, 0xf3, 0xf1, 0xef, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe3,
0xe1, 0xdf, 0xdd, 0xdc, 0xda, 0xd8, 0xd6, 0xd5, 0xd3, 0xd1, 0xd0, 0xce, 0xcd, 0xcb, 0xc9, 0xc8,
0xc6, 0xc5, 0xc3, 0xc1, 0xc0, 0xbe, 0xbd, 0xbb, 0xba, 0xb8, 0xb7, 0xb5, 0xb4, 0xb2, 0xb1, 0xb0,
0xae, 0xad, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa4, 0xa3, 0xa2, 0xa0, 0x9f, 0x9e, 0x9c, 0x9b, 0x9a,
0x99, 0x97, 0x96, 0x95, 0x94, 0x92, 0x91, 0x90, 0x8f, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x87, 0x86,
0x85, 0x84, 0x83, 0x82, 0x81, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x75, 0x74,
0x73, 0x72, 0x71, 0x70, 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64,
0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55,
0x54, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x48,
0x47, 0x46, 0x45, 0x44, 0x43, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b,
0x3a, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x35, 0x34, 0x33, 0x33, 0x32, 0x31, 0x31, 0x30, 0x2f,
0x2e, 0x2e, 0x2d, 0x2c, 0x2c, 0x2b, 0x2a, 0x2a, 0x29, 0x28, 0x28, 0x27, 0x26, 0x26, 0x25, 0x24,
0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x11,
0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08,
0x07, 0x07, 0x06, 0x06, 0x05, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00,
0x00
};
int shift = ( count_leading_zeros32( denominator ) - 16 );
int r1 = ( denominator << shift ) & 0x7fff;
int r2 = table[ ( ( r1 + 0x40 ) >> 7 ) ] + 0x101;
int r3 = ( ( 0x80 - ( r2 * ( r1 + 0x8000 ) ) ) >> 8 ) & 0x1ffff;
UINT32 reciprocal = ( ( r2 * r3 ) + 0x80 ) >> 8;
return (UINT32)( ( ( (UINT64)reciprocal * ( (UINT32)numerator << shift ) ) + 0x8000 ) >> 16 );
}
return 0xffffffff;
}
/* Setting bits 12 & 19-22 in FLAG does not set bit 31 */
static INT32 A1i( int44 a ) { m_mac1 = a.value; return BOUNDS( a, ( 1U << 31 ) | ( 1 << 30 ), ( 1U << 31 ) | ( 1 << 27 ) ); }
static INT32 A1( INT64 a ) { return A1i( i44( a ) ); }
static INT32 A2i( int44 a ) { m_mac2 = a.value; return BOUNDS( a, ( 1U << 31 ) | ( 1 << 29 ), ( 1U << 31 ) | ( 1 << 26 ) ); }
static INT32 A2( INT64 a ) { return A2i( i44( a ) ); }
static INT32 A3i( int44 a ) { m_mac3 = a.value; return BOUNDS( a, ( 1U << 31 ) | ( 1 << 28 ), ( 1U << 31 ) | ( 1 << 25 ) ); }
static INT32 A3( INT64 a ) { return A3i( i44( a ) ); }
static INT32 Lm_B1( INT32 a, int lm ) { return LIM( a, 0x7fff, -0x8000 * !lm, ( 1U << 31 ) | ( 1 << 24 ) ); }
static INT32 Lm_B2( INT32 a, int lm ) { return LIM( a, 0x7fff, -0x8000 * !lm, ( 1U << 31 ) | ( 1 << 23 ) ); }
static INT32 Lm_B3( INT32 a, int lm ) { return LIM( a, 0x7fff, -0x8000 * !lm, ( 1 << 22 ) ); }
static INT32 Lm_B3_sf( INT64 value, int sf, int lm )
{
INT32 value_sf = (INT32)gte_shift( value, sf );
INT32 value_12 = (INT32)gte_shift( value, 1 );
int max = 0x7fff;
int min = 0;
if( lm == 0 )
{
min = -0x8000;
}
if( value_12 < -0x8000 || value_12 > 0x7fff )
{
FLAG |= ( 1 << 22 );
}
if( value_sf > max )
{
return max;
}
else if( value_sf < min )
{
return min;
}
return value_sf;
}
static INT32 Lm_C1( INT32 a ) { return LIM( a, 0x00ff, 0x0000, ( 1 << 21 ) ); }
static INT32 Lm_C2( INT32 a ) { return LIM( a, 0x00ff, 0x0000, ( 1 << 20 ) ); }
static INT32 Lm_C3( INT32 a ) { return LIM( a, 0x00ff, 0x0000, ( 1 << 19 ) ); }
static INT32 Lm_D( INT64 a, int sf ) { return LIM( gte_shift( a, sf ), 0xffff, 0x0000, ( 1U << 31 ) | ( 1 << 18 ) ); }
static UINT32 Lm_E( UINT32 result )
{
if( result == 0xffffffff )
{
FLAG |= ( 1U << 31 ) | ( 1 << 17 );
return 0x1ffff;
}
if( result > 0x1ffff )
{
return 0x1ffff;
}
return result;
}
static INT64 F( INT64 a )
{
m_mac0 = a;
if( a > 0x7fffffff )
{
FLAG |= ( 1U << 31 ) | ( 1 << 16 );
}
if( a < -( (INT64)1 << 31 ) )
{
FLAG |= ( 1U << 31 ) | ( 1 << 15 );
}
return a;
}
static INT32 Lm_G1( INT64 a )
{
if( a > 0x3ff )
{
FLAG |= ( 1U << 31 ) | ( 1 << 14 );
return 0x3ff;
}
if( a < -0x400 )
{
FLAG |= ( 1U << 31 ) | ( 1 << 14 );
return -0x400;
}
return a;
}
static INT32 Lm_G2( INT64 a )
{
if( a > 0x3ff )
{
FLAG |= ( 1U << 31 ) | ( 1 << 13 );
return 0x3ff;
}
if( a < -0x400 )
{
FLAG |= ( 1U << 31 ) | ( 1 << 13 );
return -0x400;
}
return a;
}
static INT32 Lm_H( INT64 value, int sf )
{
INT64 value_sf = gte_shift( value, sf );
INT32 value_12 = (INT32)gte_shift( value, 1 );
int max = 0x1000;
int min = 0x0000;
if( value_sf < min || value_sf > max )
{
FLAG |= ( 1 << 12 );
}
if( value_12 > max )
{
return max;
}
if( value_12 < min )
{
return min;
}
return value_12;
}
static int gte_docop2( int gteop )
{
int v;
int lm;
int cv;
int mx;
INT32 h_over_sz3 = 0;
lm = GTE_LM( gteop );
m_sf = GTE_SF( gteop );
FLAG = 0;
switch( GTE_FUNCT( gteop ) )
{
case 0x00: /* drop through to RTPS */
case 0x01:
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) TRX << 12 ), ( R11 * VX0 ) ), ( R12 * VY0 ) ), ( R13 * VZ0 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) TRY << 12 ), ( R21 * VX0 ) ), ( R22 * VY0 ) ), ( R23 * VZ0 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) TRZ << 12 ), ( R31 * VX0 ) ), ( R32 * VY0 ) ), ( R33 * VZ0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3_sf( m_mac3, m_sf, lm );
SZ0 = SZ1;
SZ1 = SZ2;
SZ2 = SZ3;
SZ3 = Lm_D( m_mac3, 1 );
h_over_sz3 = Lm_E( gte_divide( H, SZ3 ) );
SXY0 = SXY1;
SXY1 = SXY2;
SX2 = Lm_G1( F( (INT64) OFX + ( (INT64) IR1 * h_over_sz3 ) ) >> 16 );
SY2 = Lm_G2( F( (INT64) OFY + ( (INT64) IR2 * h_over_sz3 ) ) >> 16 );
MAC0 = F( (INT64) DQB + ( (INT64) DQA * h_over_sz3 ) );
IR0 = Lm_H( m_mac0, 1 );
return 1;
case 0x06:
MAC0 = F( (INT64) ( SX0 * SY1 ) + ( SX1 * SY2 ) + ( SX2 * SY0 ) - ( SX0 * SY2 ) - ( SX1 * SY0 ) - ( SX2 * SY1 ) );
return 1;
case 0x0c:
MAC1 = A1( (INT64) ( R22 * IR3 ) - ( R33 * IR2 ) );
MAC2 = A2( (INT64) ( R33 * IR1 ) - ( R11 * IR3 ) );
MAC3 = A3( (INT64) ( R11 * IR2 ) - ( R22 * IR1 ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
return 1;
case 0x10:
MAC1 = A1( ( R << 16 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( R << 16 ) ), 0 ) ) );
MAC2 = A2( ( G << 16 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( G << 16 ) ), 0 ) ) );
MAC3 = A3( ( B << 16 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( B << 16 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x11:
MAC1 = A1( ( IR1 << 12 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( IR1 << 12 ) ), 0 ) ) );
MAC2 = A2( ( IR2 << 12 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( IR2 << 12 ) ), 0 ) ) );
MAC3 = A3( ( IR3 << 12 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( IR3 << 12 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x12:
mx = GTE_MX( gteop );
v = GTE_V( gteop );
cv = GTE_CV( gteop );
switch( cv )
{
case 2:
MAC1 = A1( (INT64) ( MX12( mx ) * VY( v ) ) + ( MX13( mx ) * VZ( v ) ) );
MAC2 = A2( (INT64) ( MX22( mx ) * VY( v ) ) + ( MX23( mx ) * VZ( v ) ) );
MAC3 = A3( (INT64) ( MX32( mx ) * VY( v ) ) + ( MX33( mx ) * VZ( v ) ) );
Lm_B1( A1( ( (INT64) CV1( cv ) << 12 ) + ( MX11( mx ) * VX( v ) ) ), 0 );
Lm_B2( A2( ( (INT64) CV2( cv ) << 12 ) + ( MX21( mx ) * VX( v ) ) ), 0 );
Lm_B3( A3( ( (INT64) CV3( cv ) << 12 ) + ( MX31( mx ) * VX( v ) ) ), 0 );
break;
default:
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) CV1( cv ) << 12 ), ( MX11( mx ) * VX( v ) ) ), ( MX12( mx ) * VY( v ) ) ), ( MX13( mx ) * VZ( v ) ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) CV2( cv ) << 12 ), ( MX21( mx ) * VX( v ) ) ), ( MX22( mx ) * VY( v ) ) ), ( MX23( mx ) * VZ( v ) ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) CV3( cv ) << 12 ), ( MX31( mx ) * VX( v ) ) ), ( MX32( mx ) * VY( v ) ) ), ( MX33( mx ) * VZ( v ) ) ) );
break;
}
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
return 1;
case 0x13:
MAC1 = A1( (INT64) ( L11 * VX0 ) + ( L12 * VY0 ) + ( L13 * VZ0 ) );
MAC2 = A2( (INT64) ( L21 * VX0 ) + ( L22 * VY0 ) + ( L23 * VZ0 ) );
MAC3 = A3( (INT64) ( L31 * VX0 ) + ( L32 * VY0 ) + ( L33 * VZ0 ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) );
MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) );
MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x14:
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) );
MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) );
MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x16:
for( v = 0; v < 3; v++ )
{
MAC1 = A1( (INT64) ( L11 * VX( v ) ) + ( L12 * VY( v ) ) + ( L13 * VZ( v ) ) );
MAC2 = A2( (INT64) ( L21 * VX( v ) ) + ( L22 * VY( v ) ) + ( L23 * VZ( v ) ) );
MAC3 = A3( (INT64) ( L31 * VX( v ) ) + ( L32 * VY( v ) ) + ( L33 * VZ( v ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) );
MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) );
MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
}
return 1;
case 0x1b:
MAC1 = A1( (INT64) ( L11 * VX0 ) + ( L12 * VY0 ) + ( L13 * VZ0 ) );
MAC2 = A2( (INT64) ( L21 * VX0 ) + ( L22 * VY0 ) + ( L23 * VZ0 ) );
MAC3 = A3( (INT64) ( L31 * VX0 ) + ( L32 * VY0 ) + ( L33 * VZ0 ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1( ( R << 4 ) * IR1 );
MAC2 = A2( ( G << 4 ) * IR2 );
MAC3 = A3( ( B << 4 ) * IR3 );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x1c:
MAC1 = A1i( i44_add( i44_add( i44_add( i44( ( (INT64) RBK ) << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( ( (INT64) GBK ) << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( ( (INT64) BBK ) << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1( ( R << 4 ) * IR1 );
MAC2 = A2( ( G << 4 ) * IR2 );
MAC3 = A3( ( B << 4 ) * IR3 );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x1e:
MAC1 = A1( (INT64) ( L11 * VX0 ) + ( L12 * VY0 ) + ( L13 * VZ0 ) );
MAC2 = A2( (INT64) ( L21 * VX0 ) + ( L22 * VY0 ) + ( L23 * VZ0 ) );
MAC3 = A3( (INT64) ( L31 * VX0 ) + ( L32 * VY0 ) + ( L33 * VZ0 ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x20:
for( v = 0; v < 3; v++ )
{
MAC1 = A1( (INT64) ( L11 * VX( v ) ) + ( L12 * VY( v ) ) + ( L13 * VZ( v ) ) );
MAC2 = A2( (INT64) ( L21 * VX( v ) ) + ( L22 * VY( v ) ) + ( L23 * VZ( v ) ) );
MAC3 = A3( (INT64) ( L31 * VX( v ) ) + ( L32 * VY( v ) ) + ( L33 * VZ( v ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
}
return 1;
case 0x28:
MAC1 = A1( IR1 * IR1 );
MAC2 = A2( IR2 * IR2 );
MAC3 = A3( IR3 * IR3 );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
return 1;
case 0x1a: /* end of NCDT */
case 0x29:
MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) );
MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) );
MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x2a:
for( v = 0; v < 3; v++ )
{
MAC1 = A1( ( R0 << 16 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( R0 << 16 ) ), 0 ) ) );
MAC2 = A2( ( G0 << 16 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( G0 << 16 ) ), 0 ) ) );
MAC3 = A3( ( B0 << 16 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( B0 << 16 ) ), 0 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
}
return 1;
case 0x2d:
MAC0 = F( (INT64) ( ZSF3 * SZ1 ) + ( ZSF3 * SZ2 ) + ( ZSF3 * SZ3 ) );
OTZ = Lm_D( m_mac0, 1 );
return 1;
case 0x2e:
MAC0 = F( (INT64) ( ZSF4 * SZ0 ) + ( ZSF4 * SZ1 ) + ( ZSF4 * SZ2 ) + ( ZSF4 * SZ3 ) );
OTZ = Lm_D( m_mac0, 1 );
return 1;
case 0x30:
for( v = 0; v < 3; v++ )
{
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) TRX << 12 ), ( R11 * VX( v ) ) ), ( R12 * VY( v ) ) ), ( R13 * VZ( v ) ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) TRY << 12 ), ( R21 * VX( v ) ) ), ( R22 * VY( v ) ) ), ( R23 * VZ( v ) ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) TRZ << 12 ), ( R31 * VX( v ) ) ), ( R32 * VY( v ) ) ), ( R33 * VZ( v ) ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3_sf( m_mac3, m_sf, lm );
SZ0 = SZ1;
SZ1 = SZ2;
SZ2 = SZ3;
SZ3 = Lm_D( m_mac3, 1 );
h_over_sz3 = Lm_E( gte_divide( H, SZ3 ) );
SXY0 = SXY1;
SXY1 = SXY2;
SX2 = Lm_G1( F( (INT64) OFX + ( (INT64) IR1 * h_over_sz3 ) ) >> 16 );
SY2 = Lm_G2( F( (INT64) OFY + ( (INT64) IR2 * h_over_sz3 ) ) >> 16 );
}
MAC0 = F( (INT64) DQB + ( (INT64) DQA * h_over_sz3 ) );
IR0 = Lm_H( m_mac0, 1 );
return 1;
case 0x3d:
MAC1 = A1( IR0 * IR1 );
MAC2 = A2( IR0 * IR2 );
MAC3 = A3( IR0 * IR3 );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x3e:
MAC1 = A1( gte_shift( MAC1, -m_sf ) + ( IR0 * IR1 ) );
MAC2 = A2( gte_shift( MAC2, -m_sf ) + ( IR0 * IR2 ) );
MAC3 = A3( gte_shift( MAC3, -m_sf ) + ( IR0 * IR3 ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
return 1;
case 0x3f:
for( v = 0; v < 3; v++ )
{
MAC1 = A1( (INT64) ( L11 * VX( v ) ) + ( L12 * VY( v ) ) + ( L13 * VZ( v ) ) );
MAC2 = A2( (INT64) ( L21 * VX( v ) ) + ( L22 * VY( v ) ) + ( L23 * VZ( v ) ) );
MAC3 = A3( (INT64) ( L31 * VX( v ) ) + ( L32 * VY( v ) ) + ( L33 * VZ( v ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1i( i44_add( i44_add( i44_add( i44( (INT64) RBK << 12 ), ( LR1 * IR1 ) ), ( LR2 * IR2 ) ), ( LR3 * IR3 ) ) );
MAC2 = A2i( i44_add( i44_add( i44_add( i44( (INT64) GBK << 12 ), ( LG1 * IR1 ) ), ( LG2 * IR2 ) ), ( LG3 * IR3 ) ) );
MAC3 = A3i( i44_add( i44_add( i44_add( i44( (INT64) BBK << 12 ), ( LB1 * IR1 ) ), ( LB2 * IR2 ) ), ( LB3 * IR3 ) ) );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
MAC1 = A1( ( R << 4 ) * IR1 );
MAC2 = A2( ( G << 4 ) * IR2 );
MAC3 = A3( ( B << 4 ) * IR3 );
IR1 = Lm_B1( MAC1, lm );
IR2 = Lm_B2( MAC2, lm );
IR3 = Lm_B3( MAC3, lm );
RGB0 = RGB1;
RGB1 = RGB2;
CD2 = CODE;
R2 = Lm_C1( MAC1 >> 4 );
G2 = Lm_C2( MAC2 >> 4 );
B2 = Lm_C3( MAC3 >> 4 );
}
return 1;
}
return 0;
}
File diff suppressed because it is too large. Load diff
+588
View File
@@ -0,0 +1,588 @@
/***************************************************************************
psxloop.c
Exact skip of the PSX CPU's wait loops (included by psx_cpu.c).
Within a timeslice nothing but the CPU itself changes main RAM or the
CPU state: interrupts, timers, DMA and the other CPUs only act between
timeslices. A loop that waits for an interrupt therefore repeats the
same work until the timeslice ends, and the whole passes that still fit
can be done at once: registers, memory and cycles end up exactly as if
they had run (one cycle per instruction, as the interpreter counts),
and the last pass runs normally. Three kinds of loops are recognised:
LOOP_PURE a short loop of loads and register arithmetic, no stores, no
other branch, where no register is read before the pass
writes it: every pass leaves the same state (for example
"lhu v0,x(v1); nop; beqz v0,loop"). The recompiler has its
own version of this one (jit_is_idle_loop).
LOOP_COUNT "b<cond> r,self" with "addiu r,r,-1" in the delay slot: a
plain countdown.
LOOP_VSYNC the wait in the PsyQ libraries' VSync(): a timeout counter on
the stack, decremented and stored every pass, and a RAM word
compared with a target (used by most System 11/12 games).
LOOP_RNG the VBLANK wait of Tekken 3 / Tekken Tag Tournament: every pass
steps two random number generators in RAM (x = 5x + 1 and
x = (x + 1) * 69069) while a flag in RAM stays 0.
The loop's code is checked word by word every time before a skip, so
a changed program is never skipped by mistake. Main RAM and the BIOS
must be fast RAM (psxcpu_add_fastram) for any of this to apply; loads
from anything else (I/O, shared RAM) are never skipped over.
***************************************************************************/
#define LOOP_PURE 1
#define LOOP_COUNT 2
#define LOOP_VSYNC 3
#define LOOP_RNG 4
/* build with -DPSX_LOOPSKIP=0 to compare against the plain interpreter */
#ifndef PSX_LOOPSKIP
#define PSX_LOOPSKIP 1
#endif
static int loopskip_enabled = PSX_LOOPSKIP;
/* a word of code or data in fast RAM, or 0 if it is not there */
static int loop_word( UINT32 address, UINT32 *word )
{
struct psx_fastram *r = find_fastram( address, 4 );
if( r == NULL || ( address & 3 ) != 0 )
{
return 0;
}
*word = *(UINT32 *)&r->base[ address - r->start ];
return 1;
}
/* host pointer of a writable RAM word away from translated code, or NULL */
static UINT32 *loop_data( UINT32 address )
{
struct psx_fastram *r = find_fastram( address, 4 );
UINT8 *host;
if( r == NULL || r->readonly || ( address & 3 ) != 0 )
{
return NULL;
}
host = &r->base[ address - r->start ];
#if PSXJIT_SUPPORTED
if( jit_code_present && jit_codemap[ jit_codemap_index( host ) ] )
{
return NULL;
}
#endif
return (UINT32 *)host;
}
static UINT32 loop_branch_target( UINT32 op, UINT32 pc )
{
return pc + 4 + ( (INT32)(INT16)op << 2 );
}
/*************************************
* LOOP_PURE
*************************************/
/* registers read and written by an allowed loop instruction; 0 if not allowed */
static int loop_pure_op( UINT32 op, UINT32 *reads, UINT32 *writes, int *load )
{
UINT32 rs = INS_RS( op ), rt = INS_RT( op ), rd = INS_RD( op );
*reads = 0; *writes = 0; *load = 0;
switch( INS_OP( op ) )
{
case 0x00: /* SPECIAL */
switch( op & 63 )
{
case 0x00: case 0x02: case 0x03: /* SLL SRL SRA */
*reads = 1 << rt; *writes = 1 << rd; return 1;
case 0x04: case 0x06: case 0x07: /* SLLV SRLV SRAV */
case 0x21: case 0x23: case 0x24: case 0x25: /* ADDU SUBU AND OR */
case 0x26: case 0x27: case 0x2a: case 0x2b: /* XOR NOR SLT SLTU */
*reads = ( 1 << rs ) | ( 1 << rt ); *writes = 1 << rd; return 1;
}
return 0;
case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* ADDIU SLTI SLTIU ANDI ORI XORI */
*reads = 1 << rs; *writes = 1 << rt; return 1;
case 0x0f: /* LUI */
*writes = 1 << rt; return 1;
case 0x20: case 0x21: case 0x23: case 0x24: case 0x25: /* LB LH LW LBU LHU */
*reads = 1 << rs; *writes = 1 << rt; *load = 1; return 1;
}
return 0;
}
/* registers read by the closing branch, or -1 if 'op' is not a usable branch to 'target' */
static int loop_pure_branch( UINT32 op, UINT32 pc, UINT32 target, UINT32 *reads )
{
UINT32 rs = INS_RS( op ), rt = INS_RT( op );
switch( INS_OP( op ) )
{
case 0x01: /* BLTZ BGEZ */
if( rt != 0x00 && rt != 0x01 ) return -1;
*reads = 1 << rs;
break;
case 0x04: case 0x05: /* BEQ BNE */
*reads = ( 1 << rs ) | ( 1 << rt );
break;
case 0x06: case 0x07: /* BLEZ BGTZ */
if( rt != 0 ) return -1;
*reads = 1 << rs;
break;
default:
return -1;
}
return loop_branch_target( op, pc ) == target ? 0 : -1;
}
/*
The loop at 'l' as LOOP_PURE: the branch closing it in *branch, or 0.
Same rules as the recompiler's jit_is_idle_loop, plus no instruction
may use a register loaded by the one before it (the load delay would
make it see the previous pass's value).
*/
static int loop_is_pure( UINT32 l, UINT32 *branch )
{
UINT32 ops[ 18 ], reads[ 18 ], writes[ 18 ], all = 0, written = 0, b;
int load[ 18 ], n, i, found = -1;
for( n = 0; n < 16; n++ )
{
UINT32 r;
if( !loop_word( l + n * 4, &ops[ n ] ) )
{
return 0;
}
if( loop_pure_branch( ops[ n ], l + n * 4, l, &r ) == 0 )
{
found = n;
break;
}
}
if( found < 0 || !loop_word( l + ( found + 1 ) * 4, &ops[ found + 1 ] ) )
{
return 0;
}
b = l + found * 4;
for( i = 0; i <= found + 1; i++ )
{
if( i == found )
{
loop_pure_branch( ops[ i ], b, l, &reads[ i ] );
writes[ i ] = 0;
load[ i ] = 0;
}
else if( !loop_pure_op( ops[ i ], &reads[ i ], &writes[ i ], &load[ i ] ) )
{
return 0;
}
all |= writes[ i ];
}
for( i = 0; i <= found + 1; i++ )
{
if( reads[ i ] & all & ~written & ~1 )
{
return 0;
}
if( i > 0 && load[ i - 1 ] && ( reads[ i ] & writes[ i - 1 ] & ~1 ) )
{
return 0;
}
written |= writes[ i ];
}
/* the slot's load must not reach into the next pass */
if( load[ found + 1 ] )
{
return 0;
}
*branch = b;
return 1;
}
/*************************************
* LOOP_COUNT
*************************************/
/* "b<cond> r,self" + "addiu r,r,-1": the register, or -1 */
static int loop_is_count( UINT32 l )
{
UINT32 op, slot, r;
if( !loop_word( l, &op ) || !loop_word( l + 4, &slot ) )
{
return -1;
}
if( loop_branch_target( op, l ) != l )
{
return -1;
}
r = INS_RS( op );
if( r == 0 || slot != ( 0x24000000 | ( r << 21 ) | ( r << 16 ) | 0xffff ) )
{
return -1;
}
if( ( INS_OP( op ) == 0x01 && INS_RT( op ) == 0x01 ) || /* BGEZ */
( INS_OP( op ) == 0x07 && INS_RT( op ) == 0x00 ) || /* BGTZ */
( INS_OP( op ) == 0x05 && INS_RT( op ) == 0x00 ) ) /* BNE r,zero */
{
return (int)r;
}
return -1;
}
/*************************************
* LOOP_VSYNC
*************************************/
/*
L+0 lw v0,16(sp) X+0 lui v0,hi
L+1 nop X+1 lw v0,lo(v0)
L+2 addiu v0,v0,-1 X+2 nop
L+3 sw v0,16(sp) X+3 slt v0,v0,a0
L+4 lw v0,16(sp) X+4 bnez v0,L
L+5 nop X+5 nop
L+6 bne v0,v1,X
L+7 nop
One pass is 14 instructions; the RAM word at hi:lo is in *global.
*/
static int loop_is_vsync( UINT32 l, UINT32 *global )
{
static const UINT32 head[ 8 ] = { 0x8fa20010, 0, 0x2442ffff, 0xafa20010, 0x8fa20010, 0, 0, 0 };
UINT32 w[ 8 ], x, lui, lw, i;
for( i = 0; i < 8; i++ )
{
if( !loop_word( l + i * 4, &w[ i ] ) || ( i != 6 && w[ i ] != head[ i ] ) )
{
return 0;
}
}
if( ( w[ 6 ] & 0xffff0000 ) != 0x14430000 )
{
return 0;
}
x = loop_branch_target( w[ 6 ], l + 24 );
if( x <= l + 28 || x - l > 64 * 4 )
{
return 0;
}
if( !loop_word( x, &lui ) || ( lui & 0xffff0000 ) != 0x3c020000 ||
!loop_word( x + 4, &lw ) || ( lw & 0xffff0000 ) != 0x8c420000 ||
!loop_word( x + 8, &w[ 0 ] ) || w[ 0 ] != 0 ||
!loop_word( x + 12, &w[ 1 ] ) || w[ 1 ] != 0x0044102a ||
!loop_word( x + 16, &w[ 2 ] ) || ( w[ 2 ] & 0xffff0000 ) != 0x14400000 || loop_branch_target( w[ 2 ], x + 16 ) != l ||
!loop_word( x + 20, &w[ 3 ] ) || w[ 3 ] != 0 )
{
return 0;
}
*global = ( ( lui & 0xffff ) << 16 ) + (INT32)(INT16)lw;
return 1;
}
/*************************************
* LOOP_RNG
*************************************/
/*
L+0 jal F F+0 lw v1,o1(gp)
L+1 nop F+1 nop
L+2 lui v1,h2 F+2 sll v0,v1,2
L+3 lw v1,o2(v1) F+3 addu v0,v0,v1
L+4 lw a0,o3(gp) F+4 addiu v0,v0,1
L+5 addiu v1,v1,1 F+5 sw v0,o1(gp)
L+6.. v0 = v1 * 69069 F+6 jr ra
L+16 lui at,h2 F+7 nop
L+17 sw v0,o2(at)
L+18 beqz a0,L
L+19 lui v0,slot
One pass is 28 instructions.
*/
static const UINT32 loop_rng_mul[ 10 ] =
{
0x00031140, 0x00431021, 0x00021080, 0x00431023, 0x00021080,
0x00431023, 0x00021080, 0x00431021, 0x00021940, 0x00431021
};
struct loop_rng
{
UINT32 x1, x2, flag; /* addresses: generator 1 (5x + 1), generator 2, flag */
UINT32 at, v0; /* the values left in at and v0 */
};
static int loop_is_rng( UINT32 l, struct loop_rng *g )
{
UINT32 w[ 20 ], f[ 8 ], fa, i, gp = mipscpu.r[ 28 ];
for( i = 0; i < 20; i++ )
{
if( !loop_word( l + i * 4, &w[ i ] ) )
{
return 0;
}
}
if( INS_OP( w[ 0 ] ) != 0x03 || w[ 1 ] != 0 ||
( w[ 2 ] & 0xffff0000 ) != 0x3c030000 || ( w[ 3 ] & 0xffff0000 ) != 0x8c630000 ||
( w[ 4 ] & 0xffff0000 ) != 0x8f840000 || w[ 5 ] != 0x24630001 ||
( w[ 16 ] & 0xffff0000 ) != 0x3c010000 || ( w[ 16 ] & 0xffff ) != ( w[ 2 ] & 0xffff ) ||
( w[ 17 ] & 0xffff0000 ) != 0xac220000 || ( w[ 17 ] & 0xffff ) != ( w[ 3 ] & 0xffff ) ||
( w[ 18 ] & 0xffff0000 ) != 0x10800000 || loop_branch_target( w[ 18 ], l + 72 ) != l ||
( w[ 19 ] & 0xffff0000 ) != 0x3c020000 )
{
return 0;
}
for( i = 0; i < 10; i++ )
{
if( w[ 6 + i ] != loop_rng_mul[ i ] )
{
return 0;
}
}
fa = ( ( l + 4 ) & 0xf0000000 ) | ( ( w[ 0 ] & 0x03ffffff ) << 2 );
for( i = 0; i < 8; i++ )
{
if( !loop_word( fa + i * 4, &f[ i ] ) )
{
return 0;
}
}
if( ( f[ 0 ] & 0xffff0000 ) != 0x8f830000 || f[ 1 ] != 0 || f[ 2 ] != 0x00031080 || f[ 3 ] != 0x00431021 ||
f[ 4 ] != 0x24420001 || ( f[ 5 ] & 0xffff0000 ) != 0xaf820000 || ( f[ 5 ] & 0xffff ) != ( f[ 0 ] & 0xffff ) ||
f[ 6 ] != 0x03e00008 || f[ 7 ] != 0 )
{
return 0;
}
g->x1 = gp + (INT32)(INT16)f[ 0 ];
g->x2 = ( ( w[ 2 ] & 0xffff ) << 16 ) + (INT32)(INT16)w[ 3 ];
g->flag = gp + (INT32)(INT16)w[ 4 ];
g->at = ( w[ 16 ] & 0xffff ) << 16;
g->v0 = ( w[ 19 ] & 0xffff ) << 16;
return 1;
}
/*************************************
* Skipping
*************************************/
/* whole passes of 'pass' cycles that fit, leaving between 1 and 'pass' cycles */
static INLINE UINT32 loop_passes( UINT32 pass )
{
if( mips_ICount <= (int)pass )
{
return 0;
}
return ( (UINT32)mips_ICount - 1 ) / pass;
}
static int loop_state_ok( void )
{
return loopskip_enabled && mipscpu.delayr == 0 && ( mipscpu.cp0r[ CP0_SR ] & ( SR_ISC | SR_KUC ) ) == 0;
}
/* LOOP_COUNT, LOOP_VSYNC and LOOP_RNG at 'l' (the start of a pass) */
static void loop_skip_at( UINT32 l )
{
UINT32 n, global;
int r;
struct loop_rng g;
if( !loop_state_ok() )
{
return;
}
if( ( r = loop_is_count( l ) ) > 0 )
{
/* passes still taking the branch, counting the one starting now */
UINT32 op = 0, v = mipscpu.r[ r ], left;
loop_word( l, &op );
if( INS_OP( op ) == 0x01 ) /* BGEZ: while v >= 0 */
left = (INT32)v >= 0 ? v + 1 : 0;
else /* BGTZ, BNE zero: while v > 0 */
left = (INT32)v > 0 ? v : 0;
n = loop_passes( 2 );
if( left < 1 )
return;
if( n > left - 1 )
n = left - 1;
if( n == 0 )
return;
mipscpu.r[ r ] = v - n;
mips_ICount -= n * 2;
return;
}
if( loop_is_vsync( l, &global ) )
{
UINT32 *counter = loop_data( mipscpu.r[ 29 ] + 16 ), value, until;
if( counter == NULL || !loop_word( global, &value ) || global == mipscpu.r[ 29 ] + 16 )
{
return;
}
/* the RAM word must keep the loop going */
if( !( (INT32)value < (INT32)mipscpu.r[ 4 ] ) )
{
return;
}
/* passes before the counter reaches v1 (the timeout), that pass not included */
until = *counter - mipscpu.r[ 3 ];
n = loop_passes( 14 );
if( until != 0 && n > until - 1 )
{
n = until - 1;
}
if( n == 0 )
{
return;
}
*counter -= n;
mipscpu.r[ 2 ] = 1;
mips_ICount -= n * 14;
return;
}
if( loop_is_rng( l, &g ) )
{
UINT32 *x1 = loop_data( g.x1 ), *x2 = loop_data( g.x2 ), flag, a, b, k, last = 0;
if( x1 == NULL || x2 == NULL || !loop_word( g.flag, &flag ) || flag != 0 )
{
return;
}
/* the three words must be distinct, so the stores leave the flag alone */
if( g.x1 == g.x2 || g.flag == g.x1 || g.flag == g.x2 )
{
return;
}
n = loop_passes( 28 );
if( n == 0 )
{
return;
}
a = *x1;
b = *x2;
for( k = 0; k < n; k++ )
{
a = a * 5 + 1;
last = b;
b = ( b + 1 ) * 69069;
}
*x1 = a;
*x2 = b;
mipscpu.r[ 1 ] = g.at;
mipscpu.r[ 2 ] = g.v0;
mipscpu.r[ 3 ] = last + 1;
mipscpu.r[ 4 ] = 0;
mipscpu.r[ 31 ] = l + 8;
mips_ICount -= n * 28;
return;
}
}
/* the kind of loop starting at 'l', for the recompiler (LOOP_PURE is not reported) */
static int loop_kind( UINT32 l )
{
UINT32 global;
struct loop_rng g;
if( !loopskip_enabled )
{
return LOOP_NONE;
}
if( loop_is_count( l ) > 0 )
{
return LOOP_COUNT;
}
if( loop_is_vsync( l, &global ) )
{
return LOOP_VSYNC;
}
if( loop_is_rng( l, &g ) )
{
return LOOP_RNG;
}
return LOOP_NONE;
}
/*************************************
* Interpreter hook
*************************************/
/*
Called by the interpreter when the PC moves back to 'l' (a taken
backward branch or jump) from the instruction at 'from'. LOOP_PURE
needs one whole pass seen first: from the previous arrival at 'l' to
the loop's own branch, touching nothing but fast RAM (psx_slow_access).
*/
#define LOOP_CACHE_SIZE 1024
static struct
{
UINT32 pc, op, branch;
UINT8 kind;
} loop_cache[ LOOP_CACHE_SIZE ];
static UINT32 loop_pure_pc;
static void loop_arrive( UINT32 l, UINT32 from )
{
UINT32 op, idx = ( l >> 2 ) & ( LOOP_CACHE_SIZE - 1 );
int armed = loop_pure_armed && loop_pure_pc == l && !psx_slow_access;
loop_pure_armed = 0;
if( !loop_word( l, &op ) )
{
return;
}
if( loop_cache[ idx ].pc != l || loop_cache[ idx ].op != op )
{
UINT32 branch;
loop_cache[ idx ].pc = l;
loop_cache[ idx ].op = op;
loop_cache[ idx ].kind = loop_is_pure( l, &branch ) ? LOOP_PURE : LOOP_NONE;
loop_cache[ idx ].branch = branch;
if( loop_cache[ idx ].kind == LOOP_NONE )
{
/* the other kinds are told by their first words */
UINT32 global;
struct loop_rng g;
if( loop_is_count( l ) > 0 || loop_is_vsync( l, &global ) || loop_is_rng( l, &g ) )
{
loop_cache[ idx ].kind = LOOP_COUNT; /* "one of the checked kinds" */
}
}
}
switch( loop_cache[ idx ].kind )
{
case LOOP_PURE:
{
UINT32 branch;
/* a whole pass ran since the last arrival: back here from the slot of the loop's own branch */
if( armed && from == loop_cache[ idx ].branch + 4 && loop_state_ok() &&
loop_is_pure( l, &branch ) && branch == loop_cache[ idx ].branch )
{
UINT32 pass = ( branch + 8 - l ) / 4;
mips_ICount -= loop_passes( pass ) * pass;
}
loop_pure_pc = l;
loop_pure_armed = 1;
psx_slow_access = 0;
}
break;
case LOOP_COUNT:
loop_skip_at( l );
break;
}
}
/* recompiled code: the skip at a loop head inside a block */
#if PSXJIT_SUPPORTED
static void SLJIT_FUNC loop_skip_helper( sljit_u32 l )
{
loop_skip_at( l );
}
#endif
File diff suppressed because it is too large. Load diff
+67
View File
@@ -0,0 +1,67 @@
/***************************************************************************
mn10200.h : Panasonic MN10200 (MN1020012A) emulator
Backported to the MAME 0.78 CPU interface (mame2003-plus) from current
MAME (Olivier Galibert, R. Belmont, hap). The on-chip peripherals
(interrupt controller, 8-bit timers, ports) are at 0xfc00-0xffff and
handled inside the core; the four ports go to the driver through the
callbacks below.
****************************************************************************/
#ifndef _MN10200_H_
#define _MN10200_H_
#include "osd_cpu.h"
enum
{
MN10200_PC = 1,
MN10200_PSW,
MN10200_MDR,
MN10200_D0,
MN10200_D1,
MN10200_D2,
MN10200_D3,
MN10200_A0,
MN10200_A1,
MN10200_A2,
MN10200_A3,
MN10200_NMICR,
MN10200_IAGR
};
/* external interrupt pins */
enum
{
MN10200_IRQ0 = 0,
MN10200_IRQ1,
MN10200_IRQ2,
MN10200_IRQ3,
MN10200_MAX_EXT_IRQ
};
typedef data8_t (*mn10200_port_read_func)(int port);
typedef void (*mn10200_port_write_func)(int port, data8_t data);
/* hook the ports 0-3 to the driver (call before reset; NULL: open bus) */
void mn10200_set_port_handlers(mn10200_port_read_func readfn, mn10200_port_write_func writefn);
extern int mn10200_ICount;
void mn10200_init(void);
void mn10200_reset(void *param);
void mn10200_exit(void);
int mn10200_execute(int cycles);
unsigned mn10200_get_context(void *dst);
void mn10200_set_context(void *src);
unsigned mn10200_get_reg(int regnum);
void mn10200_set_reg(int regnum, unsigned val);
void mn10200_set_irq_line(int irqline, int state);
void mn10200_set_irq_callback(int (*callback)(int irqline));
const char *mn10200_info(void *context, int regnum);
unsigned mn10200_dasm(char *buffer, unsigned pc);
#endif
File diff suppressed because it is too large. Load diff
+75
View File
@@ -0,0 +1,75 @@
/***************************************************************************
Namco C71 (TMS320C25 with Namco internal ROM) - fast DSP core
Written for Namco System 22 / Super System 22. The instruction
semantics follow the TMS320C2x core of current MAME; the memory
system is a page table set up by the driver, so the core does not
go through the generic memory handlers.
Word addresses everywhere: program, data and I/O are 16-bit word
spaces.
***************************************************************************/
#ifndef C71_H
#define C71_H
#include "osd_cpu.h"
#include "cpuintrf.h"
#include "memory.h"
/* interrupt lines (IFR bits) */
#define C71_INT0 0
#define C71_INT1 1
#define C71_INT2 2
#define C71_TINT 3
#define C71_RINT 4
#define C71_XINT 5
enum
{
C71_PC=1,
C71_PFC, C71_STR0, C71_STR1, C71_IFR,
C71_RPTC, C71_ACC, C71_PREG, C71_TREG,
C71_AR0, C71_AR1, C71_AR2, C71_AR3,
C71_AR4, C71_AR5, C71_AR6, C71_AR7,
C71_STK0, C71_STK1, C71_STK2, C71_STK3,
C71_STK4, C71_STK5, C71_STK6, C71_STK7,
C71_DRR, C71_DXR, C71_TIM, C71_PRD,
C71_IMR, C71_GREG
};
/* the generic memory interface is not used: give the CPU empty maps */
#define NAMCOC71_PGM_OFFSET 0
typedef data16_t (*c71_read_fn)(offs_t offset);
typedef void (*c71_write_fn)(offs_t offset, data16_t data);
/* driver configuration, by CPU number; call from DRIVER_INIT or MACHINE_INIT */
void c71_set_internal_rom(int cpunum, const data16_t *rom); /* 0x1000 words, native order (a CPU region) */
void c71_map_data(int cpunum, offs_t start, offs_t end, data16_t *base, int writable);
void c71_map_program(int cpunum, offs_t start, offs_t end, data16_t *base, int writable);
void c71_set_data_handlers(int cpunum, c71_read_fn rd, c71_write_fn wr); /* everything not mapped */
void c71_set_io(int cpunum, int port, c71_read_fn rd, c71_write_fn wr);
void c71_set_bio(int cpunum, int (*bio)(void));
void c71_set_serial(int cpunum, data16_t (*dr_in)(void), void (*dx_out)(data16_t));
/* the DSP spins in [pc_start, pc_end] waiting for BIO or an interrupt: burn the timeslice there */
void c71_set_idle_loop(int cpunum, int slot, UINT16 pc_start, UINT16 pc_end);
extern int c71_icount;
void c71_init(void);
void c71_reset(void *param);
void c71_exit(void);
int c71_execute(int cycles);
unsigned c71_get_context(void *dst);
void c71_set_context(void *src);
unsigned c71_get_reg(int regnum);
void c71_set_reg(int regnum, unsigned val);
void c71_set_irq_line(int irqline, int state);
void c71_set_irq_callback(int (*callback)(int irqline));
const char *c71_info(void *context, int regnum);
unsigned c71_dasm(char *buffer, unsigned pc);
#endif
+1306
View File
File diff suppressed because it is too large. Load diff
+53
View File
@@ -0,0 +1,53 @@
/*****************************************************************************
NEC V25 (and V25+) CPU, see v25.c
license:BSD-3-Clause
copyright-holders:Bryan McPhail, Alex W. Jackson
*****************************************************************************/
#ifndef V25_H
#define V25_H
#include "memory.h"
#include "osd_cpu.h"
/* input lines, besides 0 (INT) and IRQ_LINE_NMI */
#define V25_INPUT_LINE_INTP0 10
#define V25_INPUT_LINE_INTP1 11
#define V25_INPUT_LINE_INTP2 12
#define V25_INPUT_LINE_POLL 20
enum
{
V25_PC=1, V25_IP, V25_AW, V25_CW, V25_DW, V25_BW, V25_SP, V25_BP, V25_IX, V25_IY,
V25_DS1, V25_PS, V25_SS, V25_DS0, V25_PSW, V25_IDB, V25_PENDING
};
extern int v25_ICount;
extern void v25_init(void);
extern void v25_reset(void *param);
extern void v25_exit(void);
extern int v25_execute(int cycles);
extern unsigned v25_get_context(void *dst);
extern void v25_set_context(void *src);
extern unsigned v25_get_reg(int regnum);
extern void v25_set_reg(int regnum, unsigned val);
extern void v25_set_irq_line(int irqline, int state);
extern void v25_set_irq_callback(int (*callback)(int irqline));
extern const char *v25_info(void *context, int regnum);
extern unsigned v25_dasm(char *buffer, unsigned pc);
/* Configuration, from DRIVER_INIT (before the CPU is reset).
The opcodes are decrypted with the table when the CPU is in secure
mode (the default when there is a table). */
extern void v25_set_decryption_table(int cpunum, const UINT8 *table);
/* the port pins: PT (input only), P0, P1 (upper 4 bits), P2 */
extern void v25_set_port_handlers(int cpunum,
read8_handler pt_in, read8_handler p0_in, read8_handler p1_in, read8_handler p2_in,
write8_handler p0_out, write8_handler p1_out, write8_handler p2_out);
#endif
+1710
View File
File diff suppressed because it is too large. Load diff
+3 -5
View File
@@ -704,11 +704,9 @@ void pic16C5x_init(void)
state_save_register_UINT8("pic16C5x", cpu, "TRISA", &R.TRISA, 1);
state_save_register_UINT8("pic16C5x", cpu, "TRISB", &R.TRISB, 1);
state_save_register_UINT8("pic16C5x", cpu, "TRISC", &R.TRISC, 1);
state_save_register_UINT8("pic16C5x", cpu, "PORTA", &R.PORTA, 1);
state_save_register_UINT8("pic16C5x", cpu, "PORTB", &R.PORTB, 1);
state_save_register_UINT8("pic16C5x", cpu, "PORTC", &R.PORTC, 1);
state_save_register_UINT8("pic16C5x", cpu, "Old_T0", &old_T0, 1);
state_save_register_UINT8("pic16C5x", cpu, "STR", &R.STATUS, 1);
/* STATUS and the ports are in the data RAM (picRAM), saved with the memory
of the CPU: R.picRAM is not set yet here */
state_save_register_UINT8("pic16C5x", cpu, "RAM_mask", &picRAMmask, 1);
state_save_register_UINT16("pic16C5x", cpu, "WDT", &R.WDT, 1);
state_save_register_UINT16("pic16C5x", cpu, "Prescaler", &R.prescaler, 1);
@@ -858,7 +856,7 @@ int pic16C5x_execute(int cycles)
CALL_MAME_DEBUG;
R.opcode.d = M_RDOP(R.PC);
R.PC++;
R.PC = (R.PC + 1) & ADDR_MASK; /* wraps to 0 after the reset vector 0x7ff of the 2K parts */
R.PCL++;
if ((R.opcode.w.l & 0xff0) != 0x000) { /* Do all opcodes except the 00? ones */
+238 -130
View File
@@ -145,15 +145,30 @@ typedef struct
int dma_timer_active[2];
int is_slave, cpu_number;
data16_t (*opcode_read)(offs_t pc);
data32_t (*dma_read_hook)(UINT32 src, UINT32 dst, data32_t data, int size);
UINT8 **jit_rpage; /* sh2jit.c: this CPU's page tables for direct reads and writes */
UINT8 **jit_wpage;
} SH2;
int sh2_icount;
static SH2 sh2;
/*
The state of the active SH-2 is its own context buffer: switching
CPUs (every timeslice, many thousand times a frame on the ST-V with
its tight interleave) only moves this pointer instead of copying
the whole state out and in. Each CPU's saved state items point into
its buffer too, so a state save reads it whether it is active or not.
*/
static SH2 sh2_boot; /* before a CPU's buffer is known */
static SH2 *sh2p = &sh2_boot;
#define sh2 (*sh2p)
/* Atrocious hack that makes the soldivid music correct*/
/*static const int div_tab[4] = { 3, 5, 7, 0 };*/
static const int div_tab[4] = { 3, 5, 3, 0 };
/* FRT clock: internal clock / 8, / 32, / 128, external */
static const int div_tab[4] = { 3, 5, 7, 0 };
enum {
ICF = 0x00800000,
@@ -177,6 +192,16 @@ static void sh2_timer_callback(int data);
#define Rn ((opcode>>8)&15)
#define Rm ((opcode>>4)&15)
#ifdef SH2JIT_VERIFY
extern int sh2_jit_verify_logging;
void sh2_jit_verify_store(UINT32 address, int size);
#define SH2JIT_STORE(A, size) do { if (sh2_jit_verify_logging) sh2_jit_verify_store(A, size); if (sh2_jit_code_present) sh2_jit_ram_written((A) & AM, size); } while (0)
#else
/* a store over translated code flushes the recompiler's cache */
#define SH2JIT_STORE(A, size) do { if (sh2_jit_code_present) sh2_jit_ram_written((A) & AM, size); } while (0)
#endif
static INLINE data8_t RB(offs_t A)
{
if (A >= 0xe0000000)
@@ -231,6 +256,7 @@ static INLINE void WB(offs_t A, data8_t V)
if (A >= 0xc0000000)
{
cpu_writemem32bedw(A,V);
SH2JIT_STORE(A, 1);
return;
}
@@ -238,6 +264,7 @@ static INLINE void WB(offs_t A, data8_t V)
return;
cpu_writemem32bedw(A & AM,V);
SH2JIT_STORE(A, 1);
}
static INLINE void WW(offs_t A, data16_t V)
@@ -251,6 +278,7 @@ static INLINE void WW(offs_t A, data16_t V)
if (A >= 0xc0000000)
{
cpu_writemem32bedw_word(A,V);
SH2JIT_STORE(A, 2);
return;
}
@@ -258,6 +286,7 @@ static INLINE void WW(offs_t A, data16_t V)
return;
cpu_writemem32bedw_word(A & AM,V);
SH2JIT_STORE(A, 2);
}
static INLINE void WL(offs_t A, data32_t V)
@@ -271,6 +300,7 @@ static INLINE void WL(offs_t A, data32_t V)
if (A >= 0xc0000000)
{
cpu_writemem32bedw_dword(A,V);
SH2JIT_STORE(A, 4);
return;
}
@@ -278,6 +308,7 @@ static INLINE void WL(offs_t A, data32_t V)
return;
cpu_writemem32bedw_dword(A & AM,V);
SH2JIT_STORE(A, 4);
}
static INLINE void sh2_exception(const char *message, int irqline)
@@ -1143,22 +1174,20 @@ static INLINE void MAC_L(UINT32 m, UINT32 n)
}
if (sh2.sr & S)
{
Res0 = sh2.macl + Res0;
if (sh2.macl > Res0)
Res2++;
Res2 += (sh2.mach & 0x0000ffff);
if (((INT32) Res2 < 0) && (Res2 < 0xffff8000))
/* full 64-bit accumulate, saturated to the 48-bit range with the sign of the product (as MAME) */
UINT64 sum = ((((UINT64)sh2.mach) << 32) | sh2.macl) + ((((UINT64)Res2) << 32) | Res0);
UINT32 sum_hi = (UINT32)(sum >> 32);
/* outside 0xffff800000000000 .. 0x00007fffffffffff */
if (sum_hi > 0x00007fff && sum_hi < 0xffff8000)
{
Res2 = 0x00008000;
Res0 = 0x00000000;
if (fnLmL < 0)
sum = ((UINT64)0xffff8000) << 32;
else
sum = (((UINT64)0x00007fff) << 32) | 0xffffffff;
}
else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff))
{
Res2 = 0x00007fff;
Res0 = 0xffffffff;
}
sh2.mach = Res2;
sh2.macl = Res0;
sh2.mach = (UINT32)(sum >> 32);
sh2.macl = (UINT32)sum;
}
else
{
@@ -1208,12 +1237,19 @@ static INLINE void MAC_W(UINT32 m, UINT32 n)
if (sh2.sr & S)
{
if (ans == 1)
{
/* both addends with the same sign: the sign change is an overflow */
if (src == 0)
{
if (src == 0)
sh2.macl = 0x7fffffff;
if (src == 2)
sh2.macl = 0x80000000;
sh2.macl = 0x7fffffff;
sh2.mach |= 1;
}
else if (src == 2)
{
sh2.macl = 0x80000000;
sh2.mach |= 1;
}
}
}
else
{
@@ -2284,6 +2320,61 @@ static INLINE void op1111(UINT16 opcode)
NOP();
}
/* one instruction (in the interpreter's loop and for the recompiler's checks) */
static INLINE void sh2_dispatch(UINT16 opcode)
{
switch ((opcode >> 12) & 15)
{
case 0: op0000(opcode); break;
case 1: op0001(opcode); break;
case 2: op0010(opcode); break;
case 3: op0011(opcode); break;
case 4: op0100(opcode); break;
case 5: op0101(opcode); break;
case 6: op0110(opcode); break;
case 7: op0111(opcode); break;
case 8: op1000(opcode); break;
case 9: op1001(opcode); break;
case 10: op1010(opcode); break;
case 11: op1011(opcode); break;
case 12: op1100(opcode); break;
case 13: op1101(opcode); break;
case 14: op1110(opcode); break;
default: op1111(opcode); break;
}
}
static INLINE void sh2_step(void)
{
UINT32 opcode;
if (sh2.delay)
{
opcode = sh2.opcode_read ? sh2.opcode_read(sh2.delay) : RW(sh2.delay & AM);
change_pc32bedw(sh2.pc & AM);
sh2.pc -= 2;
}
else
opcode = sh2.opcode_read ? sh2.opcode_read(sh2.pc) : RW(sh2.pc & AM);
CALL_MAME_DEBUG;
sh2.delay = 0;
sh2.pc += 2;
sh2.ppc = sh2.pc;
sh2_dispatch(opcode);
if(sh2.test_irq && !sh2.delay)
{
CHECK_PENDING_IRQ("mame_sh2_execute");
sh2.test_irq = 0;
}
sh2_icount--;
}
#include "sh2jit.c"
/*****************************************************************************
* MAME CPU INTERFACE
*****************************************************************************/
@@ -2307,12 +2398,20 @@ void sh2_reset(void *param)
memset(sh2.m, 0, 0x200);
if(conf)
{
sh2.is_slave = conf->is_slave;
sh2.opcode_read = conf->opcode_read;
sh2.dma_read_hook = conf->dma_read_hook;
}
else
sh2.is_slave = 0;
sh2.cpu_number = cpu_getactivecpu();
/* code and memory handlers may differ after a reset */
if (jit_enabled)
jit_flush();
sh2.pc = RL(0);
sh2.r[15] = RL(4);
sh2.sr = I;
@@ -2324,11 +2423,15 @@ void sh2_reset(void *param)
/* Shut down CPU core */
void sh2_exit(void)
{
sh2_jit_set(0);
if (sh2.m)
free(sh2.m);
sh2.m = NULL;
/* the core frees the buffers after this */
sh2p = &sh2_boot;
}
/* Execute cycles - returns number of cycles actually run */
int sh2_execute(int cycles)
{
@@ -2339,49 +2442,10 @@ int sh2_execute(int cycles)
do
{
UINT32 opcode;
if (sh2.delay)
{
opcode = RW(sh2.delay & AM);
change_pc32bedw(sh2.pc & AM);
sh2.pc -= 2;
}
else
opcode = RW(sh2.pc & AM);
CALL_MAME_DEBUG;
sh2.delay = 0;
sh2.pc += 2;
sh2.ppc = sh2.pc;
switch ((opcode >> 12) & 15)
{
case 0: op0000(opcode); break;
case 1: op0001(opcode); break;
case 2: op0010(opcode); break;
case 3: op0011(opcode); break;
case 4: op0100(opcode); break;
case 5: op0101(opcode); break;
case 6: op0110(opcode); break;
case 7: op0111(opcode); break;
case 8: op1000(opcode); break;
case 9: op1001(opcode); break;
case 10: op1010(opcode); break;
case 11: op1011(opcode); break;
case 12: op1100(opcode); break;
case 13: op1101(opcode); break;
case 14: op1110(opcode); break;
default: op1111(opcode); break;
}
if(sh2.test_irq && !sh2.delay)
{
CHECK_PENDING_IRQ("mame_sh2_execute");
sh2.test_irq = 0;
}
sh2_icount--;
/* a block, when there is one for the PC (no slot or interrupt test pending) */
if (jit_enabled && !sh2.delay && !sh2.test_irq && sh2_jit_run())
continue;
sh2_step();
} while( sh2_icount > 0 );
return cycles - sh2_icount;
@@ -2390,16 +2454,17 @@ int sh2_execute(int cycles)
/* Get registers, return context size */
unsigned sh2_get_context(void *dst)
{
if( dst )
memcpy(dst, &sh2, sizeof(SH2));
if( dst && dst != (void *)sh2p )
memcpy(dst, sh2p, sizeof(SH2));
return sizeof(SH2);
}
/* Set registers */
void sh2_set_context(void *src)
{
/* the core passes a CPU's own buffer: it becomes the live state */
if( src )
memcpy(&sh2, src, sizeof(SH2));
sh2p = (SH2 *)src;
}
static void sh2_timer_resync(void)
@@ -2407,9 +2472,15 @@ static void sh2_timer_resync(void)
int divider = div_tab[(sh2.m[5] >> 8) & 3];
UINT32 cur_time = cpunum_gettotalcycles(sh2.cpu_number);
if(divider)
sh2.frc += (cur_time - sh2.frc_base) >> divider;
sh2.frc_base = cur_time;
UINT32 add = (cur_time - sh2.frc_base) >> divider;
/* keep the cycles that don't make a whole count yet (as MAME) */
if (add > 0)
{
if (divider)
sh2.frc += add;
sh2.frc_base = cur_time;
}
}
static void sh2_timer_activate(void)
@@ -2536,6 +2607,10 @@ static void sh2_dmac_callback(int dma)
cpuintrf_pop_context();
}
/* a unit read by the internal DMA, through the optional hook */
#define DMA_READ(src, dst, data, size) \
(sh2.dma_read_hook ? sh2.dma_read_hook((src), (dst), (data), (size)) : (data))
static void sh2_dmac_check(int dma)
{
if(sh2.m[0x63+4*dma] & sh2.m[0x6c] & 1)
@@ -2575,7 +2650,8 @@ static void sh2_dmac_check(int dma)
src --;
if(incd == 2)
dst --;
cpu_writemem32bedw(dst, cpu_readmem32bedw(src));
cpu_writemem32bedw(dst, DMA_READ(src, dst, cpu_readmem32bedw(src), 0));
SH2JIT_STORE(dst, 1);
if(incs == 1)
src ++;
if(incd == 1)
@@ -2591,7 +2667,8 @@ static void sh2_dmac_check(int dma)
src -= 2;
if(incd == 2)
dst -= 2;
cpu_writemem32bedw_word(dst, cpu_readmem32bedw_word(src));
cpu_writemem32bedw_word(dst, DMA_READ(src, dst, cpu_readmem32bedw_word(src), 1));
SH2JIT_STORE(dst, 2);
if(incs == 1)
src += 2;
if(incd == 1)
@@ -2607,7 +2684,8 @@ static void sh2_dmac_check(int dma)
src -= 4;
if(incd == 2)
dst -= 4;
cpu_writemem32bedw_dword(dst, cpu_readmem32bedw_dword(src));
cpu_writemem32bedw_dword(dst, DMA_READ(src, dst, cpu_readmem32bedw_dword(src), 2));
SH2JIT_STORE(dst, 4);
if(incs == 1)
src += 4;
if(incd == 1)
@@ -2622,10 +2700,11 @@ static void sh2_dmac_check(int dma)
{
if(incd == 2)
dst -= 16;
cpu_writemem32bedw_dword(dst, cpu_readmem32bedw_dword(src));
cpu_writemem32bedw_dword(dst+4, cpu_readmem32bedw_dword(src+4));
cpu_writemem32bedw_dword(dst+8, cpu_readmem32bedw_dword(src+8));
cpu_writemem32bedw_dword(dst+12, cpu_readmem32bedw_dword(src+12));
cpu_writemem32bedw_dword(dst, DMA_READ(src, dst, cpu_readmem32bedw_dword(src), 2));
cpu_writemem32bedw_dword(dst+4, DMA_READ(src+4, dst+4, cpu_readmem32bedw_dword(src+4), 2));
cpu_writemem32bedw_dword(dst+8, DMA_READ(src+8, dst+8, cpu_readmem32bedw_dword(src+8), 2));
cpu_writemem32bedw_dword(dst+12, DMA_READ(src+12, dst+12, cpu_readmem32bedw_dword(src+12), 2));
SH2JIT_STORE(dst, 16);
src += 16;
if(incd == 1)
dst += 16;
@@ -2645,6 +2724,46 @@ static void sh2_dmac_check(int dma)
}
}
/* the division unit, as in current MAME (sh7604.cpp) */
static void sh2_divu_start(INT64 dividend)
{
INT32 divisor = (INT32)sh2.m[0x40];
INT64 remainder;
UINT32 quotient;
int i, negative;
sh2.m[0x41] = (UINT32)dividend;
if (divisor && (dividend != (INT64)((UINT64)1 << 63) || divisor != -1))
{
INT64 q = dividend / divisor;
if (q == (INT32)q)
{
sh2.m[0x45] = (UINT32)q;
sh2.m[0x44] = (UINT32)(dividend % divisor);
return;
}
}
/* overflow (zero divisor or a quotient outside 32 bits): the unit stops after three
steps, leaving the partial remainder in DVDNTH; with OVFIE clear DVDNTL saturates */
remainder = dividend >> 32;
quotient = (UINT32)dividend;
for (i = 0; i < 3; i++)
{
int subtract = (remainder < 0) == (divisor < 0);
remainder = (remainder << 1) | ((quotient >> 31) & 1);
quotient <<= 1;
remainder += subtract ? -(INT64)divisor : (INT64)divisor;
quotient |= ((remainder < 0) == (divisor < 0)) ? 1 : 0;
}
negative = (dividend < 0) != (divisor < 0);
sh2.m[0x44] = (UINT32)remainder;
sh2.m[0x45] = (sh2.m[0x42] & 2) ? quotient : negative ? 0x80000000 : 0x7fffffff;
sh2.m[0x42] |= 1;
sh2_recalc_irq();
}
WRITE32_HANDLER( sh2_internal_w )
{
UINT32 old = sh2.m[offset];
@@ -2707,64 +2826,19 @@ WRITE32_HANDLER( sh2_internal_w )
/* Division box*/
case 0x40: /* DVSR*/
break;
case 0x41: /* DVDNT*/
{
INT32 a = sh2.m[0x41];
INT32 b = sh2.m[0x40];
log_cb(RETRO_LOG_DEBUG, LOGPRE "SH2 #%d div+mod %d/%d\n", cpu_getactivecpu(), a, b);
if (b)
{
sh2.m[0x45] = a / b;
sh2.m[0x44] = a % b;
}
else
{
sh2.m[0x42] |= 0x00010000;
sh2.m[0x45] = 0x7fffffff;
sh2.m[0x44] = 0x7fffffff;
sh2_recalc_irq();
}
break;
}
case 0x42: /* DVCR*/
sh2.m[0x42] = (sh2.m[0x42] & ~0x00001000) | (old & sh2.m[0x42] & 0x00010000);
sh2_recalc_irq();
case 0x41: /* DVDNT: a 32-bit division, the dividend sign-extended into DVDNTH */
sh2_divu_start((INT32)sh2.m[0x41]);
break;
case 0x42: /* DVCR: OVF (bit 0) and OVFIE (bit 1) are plain read/write bits */
break;
case 0x43: /* VCRDIV*/
sh2_recalc_irq();
break;
case 0x44: /* DVDNTH*/
break;
case 0x45: /* DVDNTL*/
{
INT64 a = sh2.m[0x45] | ((UINT64)(sh2.m[0x44]) << 32);
INT64 b = sh2.m[0x40];
log_cb(RETRO_LOG_DEBUG, LOGPRE "SH2 #%d div+mod %lld/%lld\n", cpu_getactivecpu(), a, b);
if (b)
{
INT64 q = a / b;
if (q != (INT32)q)
{
sh2.m[0x42] |= 0x00010000;
sh2.m[0x45] = 0x7fffffff;
sh2.m[0x44] = 0x7fffffff;
sh2_recalc_irq();
}
else
{
sh2.m[0x45] = q;
sh2.m[0x44] = a % b;
}
}
else
{
sh2.m[0x42] |= 0x00010000;
sh2.m[0x45] = 0x7fffffff;
sh2.m[0x44] = 0x7fffffff;
sh2_recalc_irq();
}
break;
}
case 0x45: /* DVDNTL: a 64-bit division of DVDNTH:DVDNTL */
sh2_divu_start((INT64)(((UINT64)sh2.m[0x44] << 32) | sh2.m[0x45]));
break;
/* DMA controller*/
case 0x60: /* SAR0*/
@@ -2819,7 +2893,11 @@ READ32_HANDLER( sh2_internal_r )
switch( offset )
{
case 0x04: /* TIER, FTCSR, FRC*/
sh2_timer_resync();
/* only a read of FRC brings it up to date, as in current MAME (frc_r):
reading TIER or FTCSR does not (a slave CPU waiting for its input
capture flag reads FTCSR tens of thousands of times a frame) */
if ((mem_mask & 0xffff) != 0xffff)
sh2_timer_resync();
return (sh2.m[4] & 0xffff0000) | sh2.frc;
case 0x05: /* OCRx, TCR, TOCR*/
if(sh2.m[5] & 0x10)
@@ -3075,6 +3153,12 @@ void sh2_init(void)
{
int cpu = cpu_getactivecpu();
/* this CPU's buffer from now on (the core allocated it before the init) */
sh2p = (SH2 *)cpunum_get_context_buffer(cpu);
if (!sh2p)
sh2p = &sh2_boot;
memset(sh2p, 0, sizeof(SH2));
sh2.timer = timer_alloc(sh2_timer_callback);
timer_adjust(sh2.timer, TIME_NEVER, 0, 0);
@@ -3115,5 +3199,29 @@ void sh2_init(void)
state_save_register_UINT32("sh2", cpu, "R13", &sh2.r[13], 1);
state_save_register_UINT32("sh2", cpu, "R14", &sh2.r[14], 1);
state_save_register_UINT32("sh2", cpu, "EA", &sh2.ea, 1);
/* the rest of the CPU: the delay slot, the divider, the interrupts and
the on-chip modules (their registers, the free running timer, the DMA) */
state_save_register_UINT32("sh2", cpu, "PPC", &sh2.ppc, 1);
state_save_register_UINT32("sh2", cpu, "delay", &sh2.delay, 1);
state_save_register_UINT32("sh2", cpu, "cpu_off", &sh2.cpu_off, 1);
state_save_register_UINT32("sh2", cpu, "dvsr", &sh2.dvsr, 1);
state_save_register_UINT32("sh2", cpu, "dvdnth", &sh2.dvdnth, 1);
state_save_register_UINT32("sh2", cpu, "dvdntl", &sh2.dvdntl, 1);
state_save_register_UINT32("sh2", cpu, "dvcr", &sh2.dvcr, 1);
state_save_register_UINT32("sh2", cpu, "pending_irq", &sh2.pending_irq, 1);
state_save_register_UINT32("sh2", cpu, "test_irq", &sh2.test_irq, 1);
state_save_register_INT32("sh2", cpu, "irq_queue", (INT32 *)sh2.irq_queue, 16 * 2);
state_save_register_INT8("sh2", cpu, "irq_line_state", sh2.irq_line_state, 16);
state_save_register_INT8("sh2", cpu, "nmi_line_state", &sh2.nmi_line_state, 1);
state_save_register_UINT32("sh2", cpu, "m", sh2.m, 0x200 / 4);
state_save_register_UINT16("sh2", cpu, "frc", &sh2.frc, 1);
state_save_register_UINT16("sh2", cpu, "ocra", &sh2.ocra, 1);
state_save_register_UINT16("sh2", cpu, "ocrb", &sh2.ocrb, 1);
state_save_register_UINT16("sh2", cpu, "icr", &sh2.icr, 1);
state_save_register_UINT32("sh2", cpu, "frc_base", &sh2.frc_base, 1);
state_save_register_int("sh2", cpu, "frt_input", &sh2.frt_input);
state_save_register_int("sh2", cpu, "internal_irq_level", &sh2.internal_irq_level);
state_save_register_int("sh2", cpu, "internal_irq_vector", &sh2.internal_irq_vector);
state_save_register_INT32("sh2", cpu, "dma_timer_active", (INT32 *)sh2.dma_timer_active, 2);
return;
}
+18
View File
@@ -60,8 +60,26 @@ extern int sh2_icount; /* cycle count */
struct sh2_config
{
int is_slave;
/* optional: opcode fetch, for CPUs that decrypt opcodes (CPS-3);
NULL fetches opcodes as data */
data16_t (*opcode_read)(offs_t pc);
/* optional: called for each unit an internal DMA transfer reads, can
change the data (CPS-3: the DMA bypasses the decryption);
size 0 byte, 1 word, 2 long */
data32_t (*dma_read_hook)(UINT32 src, UINT32 dst, data32_t data, int size);
};
/* optional recompiler (sh2jit.c): a driver declares the RAM the CPUs run
from and read directly ('base': host memory of 'start', as the memory
system keeps it), then enables it; anything else stays with the
interpreter. Writes the driver makes there by other means than the
CPUs (DMA) must be reported with sh2_jit_ram_written. */
int sh2_jit_available(void);
void sh2_jit_add_fastram(offs_t start, offs_t end, int readonly, void *base);
void sh2_jit_set(int enable);
void sh2_jit_ram_written(UINT32 address, UINT32 bytes);
extern int sh2_jit_code_present;
extern void sh2_init(void);
extern void sh2_reset (void *param); /* Reset registers to the initial values */
extern void sh2_exit (void); /* Shut down CPU core */
+2229
View File
File diff suppressed because it is too large. Load diff
+3212
View File
File diff suppressed because it is too large. Load diff
+87
View File
@@ -0,0 +1,87 @@
/*****************************************************************************
sh3.h
Hitachi SH-3 (SH7709S) CPU core, from current MAME (sh.cpp, sh4.cpp,
sh3comn.cpp, sh4comn.cpp, sh4tmu.cpp, sh7709s.cpp: R. Belmont,
David Haywood, Jesus Ramos and the other authors of those files).
Big endian, 32-bit data bus (32bedw). No FPU and no MMU (current MAME
doesn't emulate the SH-3 MMU either). The internal registers of the
SH7709S are emulated in the core; the I/O ports call the driver.
*****************************************************************************/
#ifndef _SH3_H
#define _SH3_H
#include "cpuintrf.h"
#include "osd_cpu.h"
/* the external interrupt lines IRL0-IRL3 (current MAME: SH4_IRL0-SH4_IRL3) */
#define SH3_IRL0 0
#define SH3_IRL1 1
#define SH3_IRL2 2
#define SH3_IRL3 3
/* the I/O ports, for the port callbacks */
enum
{
SH3_PORT_A = 0, SH3_PORT_B, SH3_PORT_C, SH3_PORT_D, SH3_PORT_E, SH3_PORT_F,
SH3_PORT_G, SH3_PORT_H, SH3_PORT_J, SH3_PORT_K, SH3_PORT_L, SH3_PORT_COUNT
};
enum
{
SH3_PC=1, SH3_SR, SH3_PR, SH3_GBR, SH3_VBR, SH3_MACH, SH3_MACL,
SH3_R0, SH3_R1, SH3_R2, SH3_R3, SH3_R4, SH3_R5, SH3_R6, SH3_R7,
SH3_R8, SH3_R9, SH3_R10, SH3_R11, SH3_R12, SH3_R13, SH3_R14, SH3_R15,
SH3_SSR, SH3_SPC, SH3_EA
};
struct sh3_config
{
/* the SH7709S cache and bus timing of current MAME (sh7709s.cpp, made
for the CV1000): data accesses and cache misses cost cycles */
int cache_timing;
/* the clock of the peripheral modules (TMU), Hz */
int pm_clock;
/* the I/O ports (SH3_PORT_x); NULL reads 0 */
data8_t (*port_r)(int port);
void (*port_w)(int port, data8_t data);
};
extern int sh3_ICount;
/* the fast memory: plain RAM or ROM at base (an array of data32_t, as the
memory system keeps a 32-bit big-endian space), read, written and fetched
without the memory handlers; physical addresses (29 bits). Set from
DRIVER_INIT, emptied at the CPU init */
#define SH3_FASTRAM_MAX 4
void sh3_set_fastram(UINT32 start, UINT32 end, int readonly, data32_t *base);
/* the cache and bus timing of an access done by a memory handler (current
MAME: sh7709s_device::update_access_cycles) */
void sh3_update_access_cycles(UINT32 address, int write);
/* the recompiler (sh3jit.c): available on this host, and on/off (off by default) */
int sh3_jit_available(void);
void sh3_set_jit(int enable);
/* the total number of cycles run */
UINT32 sh3_total_cycles_lo(void);
void sh3_init(void);
void sh3_reset(void *param);
void sh3_exit(void);
int sh3_execute(int cycles);
unsigned sh3_get_context(void *dst);
void sh3_set_context(void *src);
unsigned sh3_get_reg(int regnum);
void sh3_set_reg(int regnum, unsigned val);
void sh3_set_irq_line(int irqline, int state);
void sh3_set_irq_callback(int (*callback)(int irqline));
const char *sh3_info(void *context, int regnum);
unsigned sh3_dasm(char *buffer, unsigned pc);
#endif
+1329
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 497 files, more files were not shown because too many files have changed in this diff. Show more