WIP: all-in-one

This commit is contained in:
Andrei Holub 2025-06-20 10:05:18 -04:00
parent d3203aa34f
commit a54ca41c67
53 changed files with 2694 additions and 560 deletions

View File

@ -1,44 +0,0 @@
name: Rebuild BGFX shaders
on:
push:
paths:
- '.github/workflows/**'
- 'src/osd/modules/render/bgfx/shaders/**'
pull_request:
paths:
- '.github/workflows/**'
- 'src/osd/modules/render/bgfx/shaders/**'
permissions:
contents: read
jobs:
rebuild:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
install: git make mingw-w64-x86_64-gcc mingw-w64-x86_64-python mingw-w64-x86_64-libc++
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Prevent make from rebuilding GLSL parser source
run: |
touch 3rdparty/bgfx/3rdparty/glsl-optimizer/src/glsl/glcpp/glcpp-lex.c
touch 3rdparty/bgfx/3rdparty/glsl-optimizer/src/glsl/glcpp/glcpp-parse.c
touch 3rdparty/bgfx/3rdparty/glsl-optimizer/src/glsl/glcpp/glcpp-parse.h
touch 3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/glslang_tab.cpp
touch 3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/glslang_tab.cpp.h
- name: Build
env:
MINGW64: "/mingw64"
run: make shaders
- uses: actions/upload-artifact@main
with:
name: mame-bgfx-${{ github.sha }}
path: bgfx/shaders
if-no-files-found: error

View File

@ -1,76 +0,0 @@
name: CI (Linux)
on:
push:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- 'hash/**'
- 'scripts/**'
- 'src/**'
- 'COPYING'
- 'makefile'
pull_request:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- 'hash/**'
- 'scripts/**'
- 'src/**'
- 'COPYING'
- 'makefile'
permissions:
contents: read
jobs:
build-linux:
strategy:
matrix:
compiler: [gcc, clang]
include:
- compiler: gcc
cc: gcc
cxx: g++
archopts: -U_FORTIFY_SOURCE
subtarget: tiny
executable: mametiny
- compiler: clang
cc: clang
cxx: clang++
subtarget: mame
executable: mame
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libsdl2-dev libsdl2-ttf-dev libfontconfig-dev libasound2-dev libxinerama-dev libxi-dev qtbase5-dev qtbase5-dev-tools
- name: Install clang
if: matrix.compiler == 'clang'
run: sudo apt-get install -y clang
- name: Build
env:
OVERRIDE_CC: ${{ matrix.cc }}
OVERRIDE_CXX: ${{ matrix.cxx }}
ARCHOPTS: ${{ matrix.archopts }}
SUBTARGET: ${{ matrix.subtarget }}
TOOLS: 1
run: make -j3
- name: Validate
run: ./${{ matrix.executable }} -validate
- name: Reconcile driver list
run: ./${{ matrix.executable }} -listxml | python scripts/build/makedep.py reconcilelist -l src/mame/${{ matrix.subtarget }}.lst -
- name: ORM check
run: python scripts/minimaws/minimaws.py load --executable ./${{ matrix.executable }} --softwarepath hash
- uses: actions/upload-artifact@main
with:
name: ${{ matrix.executable }}-linux-${{ matrix.compiler }}-${{ github.sha }}
path: |
${{ matrix.executable }}
chdman
unidasm
if-no-files-found: error

View File

@ -1,47 +0,0 @@
name: CI (macOS)
on:
push:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- 'scripts/**'
- 'src/**'
- 'COPYING'
- 'makefile'
pull_request:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- 'scripts/**'
- 'src/**'
- 'COPYING'
- 'makefile'
permissions:
contents: read
jobs:
build-macos:
runs-on: macOS-latest
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Install dependencies
run: brew install python3 sdl2
- name: Build
env:
USE_LIBSDL: 1
TOOLS: 1
run: make -j2
- name: Validate
run: ./mame -validate
- uses: actions/upload-artifact@main
with:
name: mame-macos-${{ github.sha }}
path: |
mame
chdman
unidasm
if-no-files-found: error

View File

@ -25,7 +25,7 @@ jobs:
build-windows: build-windows:
strategy: strategy:
matrix: matrix:
compiler: [gcc-x64, clang-x64, clang-arm64] compiler: [gcc-x64]
include: include:
- compiler: gcc-x64 - compiler: gcc-x64
os: windows-latest os: windows-latest
@ -35,23 +35,6 @@ jobs:
cxx: g++ cxx: g++
subtarget: mame subtarget: mame
executable: mame executable: mame
- compiler: clang-x64
os: windows-latest
msys: MINGW64
slug: mingw-w64-x86_64
cc: clang
cxx: clang++
subtarget: tiny
executable: mametiny
- compiler: clang-arm64
os: windows-11-arm
msys: CLANGARM64
slug: mingw-w64-clang-aarch64
extrapkg: mingw-w64-clang-aarch64-gcc-compat
cc: clang
cxx: clang++
subtarget: mame
executable: mame
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
defaults: defaults:
run: run:
@ -71,15 +54,12 @@ jobs:
OVERRIDE_CXX: ${{ matrix.cxx }} OVERRIDE_CXX: ${{ matrix.cxx }}
ARCHOPTS: "-fuse-ld=lld" ARCHOPTS: "-fuse-ld=lld"
SUBTARGET: ${{ matrix.subtarget }} SUBTARGET: ${{ matrix.subtarget }}
TOOLS: 1 SOURCES: sinclair/sprinter.cpp,sinclair/tsconf.cpp,sinclair/specnext.cpp
run: make -j3 TOOLS: 0
- name: Validate run: make -j$(nproc)
run: ./${{ matrix.executable }}.exe -validate
- uses: actions/upload-artifact@main - uses: actions/upload-artifact@main
with: with:
name: ${{ matrix.executable }}-windows-${{ matrix.compiler }}-${{ github.sha }} name: ${{ matrix.executable }}-windows-${{ matrix.compiler }}-${{ github.sha }}
path: | path: |
${{ matrix.executable }}.exe ${{ matrix.executable }}.exe
chdman.exe
unidasm.exe
if-no-files-found: error if-no-files-found: error

View File

@ -1,38 +0,0 @@
name: Build documentation
on:
push:
paths:
- '.github/workflows/**'
- 'docs/**'
pull_request:
paths:
- '.github/workflows/**'
- 'docs/**'
permissions:
contents: read
jobs:
build-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y librsvg2-bin latexmk python3-pip python3-sphinx texlive texlive-formats-extra texlive-science
pip3 install sphinxcontrib-svg2pdfconverter
- name: Build HTML
run: make -C docs html
- name: Build PDF
run: make -C docs PAPER=a4 latexpdf
- uses: actions/upload-artifact@main
with:
name: mame-docs-${{ github.sha }}
path: |
docs/build/html
docs/build/latex/MAME.pdf
if-no-files-found: error

View File

@ -1,38 +0,0 @@
name: XML/JSON validation
on:
push:
paths:
- '.github/workflows/**'
- 'ctrlr/*'
- 'hash/*'
- 'plugins/**'
pull_request:
paths:
- '.github/workflows/**'
- 'ctrlr/*'
- 'hash/*'
- 'plugins/**'
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libxml2-utils python3-jsonschema
- name: Validate (controller configuration)
run: for x in ctrlr/*.cfg ; do xmllint --noout "$x" ; done
- name: Validate (HSI)
run: for x in hash/*.hsi ; do xmllint --noout "$x" ; done
- name: Validate (software list)
run: for x in hash/*.xml ; do xmllint --noout --valid "$x" ; done
- name: Validate (plugin properties)
run: for x in plugins/*/plugin.json ; do jsonschema -i "$x" plugins/plugin.schema ; done

View File

@ -1,29 +0,0 @@
name: Compile UI translations
on:
push:
paths:
- '.github/workflows/**'
- 'language/**'
pull_request:
paths:
- '.github/workflows/**'
- 'language/**'
permissions:
contents: read
jobs:
build-language:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Compile message catalogs
run: for x in language/*/*.po ; do python scripts/build/msgfmt.py --output-file "`dirname "$x"`/`basename "$x" .po`.mo" "$x" ; done
- uses: actions/upload-artifact@main
with:
name: mame-language-${{ github.sha }}
path: language/*/*.mo
if-no-files-found: error

View File

@ -158,6 +158,10 @@ Examples:
Address 9660 in the default address space of the device with the Address 9660 in the default address space of the device with the
absolute tag ``:ram``, or the ``ram`` space of the root machine absolute tag ``:ram``, or the ``ram`` space of the root machine
device. device.
``1883:vram.m``
Address 1883 in the memory region with the absolute tag ``:vram``.
``1923:sprites.s``
Address 1923 in the memory share with the absolute tag ``:sprites``.
The examples here include a lot of corner cases, but in general the The examples here include a lot of corner cases, but in general the
debugger should take the most likely meaning for a device or address debugger should take the most likely meaning for a device or address
@ -327,6 +331,7 @@ The size may optionally be preceded by an access type specification:
* ``o`` specifies direct read/write pointer access defaulting to space 3 * ``o`` specifies direct read/write pointer access defaulting to space 3
(opcodes) (opcodes)
* ``m`` specifies a memory region * ``m`` specifies a memory region
* ``s`` specifies a memory share
Finally, this may be preceded by a tag and/or address space name Finally, this may be preceded by a tag and/or address space name
followed by a dot (``.``). followed by a dot (``.``).

View File

@ -65,6 +65,7 @@ find
---- ----
**f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,…]]** **f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,…]]**
**f[ind] <address>:<memory>.{m|s},<length>[,<data>[,…]]**
Search through memory for the specified sequence of data. The Search through memory for the specified sequence of data. The
**<address>** is the address to begin searching from, optionally **<address>** is the address to begin searching from, optionally
@ -114,6 +115,7 @@ fill
---- ----
**fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,…]]** **fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,…]]**
**fill <address>:<memory>.{m|s},<length>[,<data>[,…]]**
Overwrite a block of memory with copies of the supplied data sequence. Overwrite a block of memory with copies of the supplied data sequence.
The **<address>** specifies the address to begin writing at, optionally The **<address>** specifies the address to begin writing at, optionally
@ -146,6 +148,7 @@ dump
---- ----
**dump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]]** **dump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]]**
**dump <filename>,<address>:<memory>.{m|s},<length>[,<group>[,<ascii>[,<rowsize>]]]**
Dump memory to the text file specified by the **<filename>** parameter. Dump memory to the text file specified by the **<filename>** parameter.
The **<address>** specifies the address to start dumping from, The **<address>** specifies the address to start dumping from,
@ -190,6 +193,7 @@ strdump
------- -------
**strdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>]** **strdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>]**
**strdump <filename>,<address>:<memory>.{m|s},<length>[,<term>]**
Dump memory to the text file specified by the **<filename>** parameter. Dump memory to the text file specified by the **<filename>** parameter.
The **<address>** specifies the address to start dumping from, The **<address>** specifies the address to start dumping from,
@ -216,6 +220,7 @@ save
---- ----
**save[{d|i|o}] <filename>,<address>[:<space>],<length>** **save[{d|i|o}] <filename>,<address>[:<space>],<length>**
**save <filename>,<address>:<memory>.{m|s},<length>**
Save raw memory to the binary file specified by the **<filename>** Save raw memory to the binary file specified by the **<filename>**
parameter. The **<address>** specifies the address to start saving parameter. The **<address>** specifies the address to start saving
@ -260,6 +265,9 @@ start saving from, and the **<length>** specifies how much memory to
save. The range **<address>** through **<address>+<length>-1**, save. The range **<address>** through **<address>+<length>-1**,
inclusive, will be output to the file. inclusive, will be output to the file.
Alternetevely use :ref:`debugger-command-save` syntax:
``save <filename>,<address>:<region>.m,<length>``
Examples: Examples:
``saver data.bin,200,100,:monitor`` ``saver data.bin,200,100,:monitor``
@ -278,6 +286,7 @@ load
---- ----
**load[{d|i|o}] <filename>,<address>[:<space>][,<length>]** **load[{d|i|o}] <filename>,<address>[:<space>][,<length>]**
**load <filename>,<address>:<memory>.{m|s}[,<length>]**
Load raw memory from the binary file specified by the **<filename>** Load raw memory from the binary file specified by the **<filename>**
parameter. The **<address>** specifies the address to start loading to, parameter. The **<address>** specifies the address to start loading to,
@ -334,6 +343,9 @@ through **<address>+<length>-1**, inclusive, will be read in from the
file. If the **<length>** is zero, or is greater than the total length file. If the **<length>** is zero, or is greater than the total length
of the file, the entire contents of the file will be loaded but no more. of the file, the entire contents of the file will be loaded but no more.
Alternetevely use :ref:`debugger-command-load` syntax:
``load <filename>,<address>:<region>.m[,<length>]``
Examples: Examples:
``loadr data.bin,200,100,:monitor`` ``loadr data.bin,200,100,:monitor``

456
hash/tsconf.xml Normal file
View File

@ -0,0 +1,456 @@
<?xml version="1.0"?>
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
<!--
license:CC0-1.0
-->
<softwarelist name="tsconf" description="TS-Configuration (All Formats)">
<software name="alterego">
<description>Alter Ego</description>
<year>2011</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<info name="developer" value="Shiru"/>
<info name="developer" value="brightentayle"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="32256">
<rom name="alteregobeta.spg" size="32256" crc="5645820c" sha1="957b66480d513bb8a34187326cb8b1824925bbc3" />
</dataarea>
</part>
</software>
<software name="bomberman">
<description>Bomberman</description>
<year>2012</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Budder"/>
<info name="developer" value="Wizart"/>
<info name="developer" value="Crash"/>
<info name="developer" value="Breeze"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="102400">
<rom name="bomber.spg" size="102400" crc="16601e87" sha1="7bc8bf23ffba2e8177485303ba0879bb26ac4453" />
</dataarea>
</part>
</software>
<software name="brucelee">
<description>Bruce Lee</description>
<year>2015</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="71680">
<rom name="brucelee.spg" size="71680" crc="a86875e1" sha1="475732defc8d88ad0160b071ad5a6535cb220ff5" />
</dataarea>
</part>
</software>
<software name="chase">
<description>Chase</description>
<year>2012</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<info name="developer" value="Shiru"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="13824">
<rom name="chase.spg" size="13824" crc="0b8b82fe" sha1="79a26756345f9178adb1305dbd5c31ea87d9f252" />
</dataarea>
</part>
</software>
<software name="copter">
<description>Copter v0.1</description>
<year>2012</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Wizart"/>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="COPTER.trd" size="655360" crc="43236562" sha1="c4e3a9bcfd2387e954372a633f7415db368dbd4b" />
</dataarea>
</part>
</software>
<software name="digger">
<description>Digger</description>
<year>2016</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Hacker VBI"/>
<info name="developer" value="Er"/>
<info name="developer" value="n1k-o"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="411648">
<rom name="Digger.spg" size="411648" crc="f6c1de1b" sha1="d2d85cefd758832dfb89abb24b672e1a05eef009" />
</dataarea>
</part>
</software>
<software name="edgegrinder">
<description>Edge Grinder v1.01</description>
<year>2018</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<info name="developer" value="Trevor Smila Storey"/>
<info name="developer" value="Tom+Jerry"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="43520">
<rom name="edge_grinder.spg" size="43520" crc="dfbce1ca" sha1="932a8627cd2a69392d7b6eb2995ab52d9ca60288" />
</dataarea>
</part>
</software>
<software name="jptst">
<description>Jim Power Test</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="60928">
<rom name="jptst.spg" size="60928" crc="f12f6921" sha1="4f1b2efc14ae006cb574bfa109e30680a96fbe18" />
</dataarea>
</part>
</software>
<software name="lirus">
<description>Lirus</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Denis Grachev"/>
<info name="developer" value="nodeus"/>
<info name="developer" value="Oleg Nikitin"/>
<info name="developer" value="Alex Lobov"/>
<info name="developer" value="Alex Semenov"/>
<info name="developer" value="Hacker VBI"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="323072">
<rom name="Lirus.spg" size="323072" crc="5c081bd8" sha1="abec5973471697b82f36bdfe6cbc71498892a945" />
</dataarea>
</part>
</software>
<software name="lost">
<description>Touhou Zero. Lost Donation Box Incident</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Nihirash"/>
<info name="developer" value="Hina"/>
<info name="developer" value="EA"/>
<info name="developer" value="Gogin"/>
<info name="developer" value="Scalesmann"/>
<info name="developer" value="wbc"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="1901568">
<rom name="lost-ts.spg" size="1901568" crc="d2322d8b" sha1="8176b473d3be34543be1e35749b1c6e4baa5db61" />
</dataarea>
</part>
</software>
<software name="multidude">
<description>MultiDude</description>
<year>2014</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Denis Grachev"/>
<info name="developer" value="Hacker VBI"/>
<info name="developer" value="brightentayle"/>
<info name="developer" value="MMCM"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="26624">
<rom name="MultiDude.spg" size="26624" crc="c3e10b45" sha1="e2046de86f546db2a8d95244d3c703358f5e1655" />
</dataarea>
</part>
</software>
<software name="ninjagarden">
<description>Ninja Gaiden</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="173056">
<rom name="NinjaGaiden.spg" size="173056" crc="10fca9ba" sha1="398eeb975604b1f75c36d750539f248e1aab114d" />
</dataarea>
</part>
</software>
<software name="otterandsmoker">
<description>Otter &amp; Smoker</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Black Cat"/>
<info name="developer" value="Hacker VBI"/>
<info name="developer" value="Marie Slip"/>
<info name="developer" value="Mike Gamaev"/>
<info name="developer" value="Colorizator"/>
<info name="developer" value="Joe Vondayl"/>
<info name="developer" value="Mister Robin"/>
<info name="developer" value="Fatalsnipe"/>
<info name="developer" value="Alex Mart"/>
<part name="v1_6_neogs" interface="spectrum_snapshot">
<dataarea name="dump" size="1703424">
<rom name="Otter&amp;Smocker v1.6 (NEOGS).spg" size="1703424" crc="b069bff4" sha1="b28ac7a9afcb11d7cbfc6392df601e3b6473d9b1" />
</dataarea>
</part>
<part name="v1_6_turbosound" interface="spectrum_snapshot">
<dataarea name="dump" size="1703424">
<rom name="Otter&amp;Smocker v1.6 (TAY).spg" size="1703424" crc="7539f2ca" sha1="e7c85f002e31b0ef4fe02c6565e8552ef528778b" />
</dataarea>
</part>
<part name="v1_6_nofx" interface="spectrum_snapshot">
<dataarea name="dump" size="1703424">
<rom name="Otter&amp;Smocker v1.6 (NoFX).spg" size="1703424" crc="a76b1815" sha1="063d1d0922bc1c70f0832c3ba17d35f413bb10b2" />
</dataarea>
</part>
</software>
<software name="ottifants">
<description>Ottifants</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Dr.Max"/>
<info name="developer" value="EA"/>
<info name="developer" value="Fatalsnipe"/>
<info name="developer" value="Gogin"/>
<info name="developer" value="MR287CC"/>
<info name="developer" value="n1k-o"/>
<info name="developer" value="Quiet"/>
<info name="developer" value="Hacker VBI"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="358912">
<rom name="Ottifants.spg" size="358912" crc="103cd3f2" sha1="159a7679873c6293f67740a0aa8c65924cdccac5" />
</dataarea>
</part>
</software>
<software name="ouk">
<description>Once Upon a Time in a Kingdom</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Marie Slip"/>
<info name="developer" value="Colorizator"/>
<info name="developer" value="Devstratum, Graf Cherry"/>
<info name="developer" value="Mister Robin"/>
<info name="developer" value="Fatalsnipe"/>
<info name="developer" value="Karbafos"/>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="O.U.K (AY) last-cat.trd" size="655360" crc="5f84d0f7" sha1="c4e061dde0b4cc3244e994b51b1ed02ef8b56fbc" />
</dataarea>
</part>
</software>
<software name="pacpack">
<description>PacPack</description>
<year>2018</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Hacker VBI"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="297472">
<rom name="PacPack.spg" size="297472" crc="a3918598" sha1="4d1497a8774c50ea962290078e1a2f2931a44f3b" />
</dataarea>
</part>
</software>
<software name="parallax">
<description>Cannon Fodder Parallax</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="20480">
<rom name="cfparallax.spg" size="20480" crc="4e500604" sha1="8e11d90a0bb72ec408dfc212f9fa01ce5acc7186" />
</dataarea>
</part>
</software>
<software name="sirababol">
<description>Sir Ababol</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<info name="developer" value="n1k-o"/>
<info name="developer" value="na_th_an"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="36864">
<rom name="sirababol.spg" size="36864" crc="a8158028" sha1="83997cbc28a16670ab0a1cdb470f2b7624062353" />
</dataarea>
</part>
</software>
<software name="socoban">
<description>Socoban</description>
<year>2015</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="g0blinish"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="24064">
<rom name="soco.spg" size="24064" crc="c5b5179c" sha1="3518bbc1145e4941c08703084d52b4ba4ea53272" />
</dataarea>
</part>
</software>
<software name="sonicthehedgehog">
<description>Sonic the Hedgehog</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="n1k-o"/>
<info name="developer" value="Hacker VBI"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="320512">
<rom name="Sonic.spg" size="320512" crc="84abf16d" sha1="8cd8b3083e3143d26262116bb07646f69c462909" />
</dataarea>
</part>
</software>
<software name="streetfighter2">
<description>Street Fighter 2 (v1.1)</description>
<year>2023</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Black Cat"/>
<info name="developer" value="Marie Slip"/>
<info name="developer" value="n1k-o"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="3172352">
<rom name="SFv1.1.spg" size="3172352" crc="a46029fc" sha1="10a65e1ea8d1f756edfd670820afcb3f7a81f9dd" />
</dataarea>
</part>
</software>
<software name="synchronization">
<description>Synchronization</description>
<year>201?</year>
<publisher>Robus</publisher>
<info name="developer" value="Hacker VBI"/>
<info name="developer" value="Robus"/>
<info name="developer" value="Mellona"/>
<info name="developer" value="n1k-o"/>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="SYNCHRO.TRD" size="655360" crc="8b99764d" sha1="022ea81b2f3e2154ee0fdd733dbe6ddc8a020ca6" />
</dataarea>
</part>
</software>
<software name="tcircles">
<description>T-circles</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Buyan"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="22528">
<rom name="Tcircles.spg" size="22528" crc="ac5c5b9b" sha1="13102d62ba48c45d77fbeb9e953c122fc8f6c8b2" />
</dataarea>
</part>
</software>
<software name="tetris">
<description>Tetris</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="denpopov"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="3584">
<rom name="tetris.spg" size="3584" crc="335c998d" sha1="f730ea4eabb1b301bf8b8e2713bbf0ae2d3745fe" />
</dataarea>
</part>
</software>
<software name="tsdemo">
<description>TS-TechDemo</description>
<year>2013</year>
<publisher>Wizart/DT</publisher>
<info name="developer" value="Wizart"/>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="TSDemo.trd" size="655360" crc="c2e72fe4" sha1="fe99a846c9702c3c424daa8b6509458853bcf5ff" />
</dataarea>
</part>
</software>
<software name="tsolitaire">
<description>TSolitaire</description>
<year>201?</year>
<publisher>ERA Creative Group (Multinational)</publisher>
<info name="developer" value="Marie Slip"/>
<info name="developer" value="n1k-o"/>
<info name="developer" value="Black Cat"/>
<info name="developer" value="Inside"/>
<part name="v2_0_turbosound" interface="floppy_5_25">
<dataarea name="flop1" size="655360">
<rom name="TS v2.0(TFM)_edited.trd" size="655360" crc="05cf31ef" sha1="6a25e71b805c21410607f8c62a62198333ced2fd" />
</dataarea>
</part>
<part name="v2_0" interface="floppy_5_25">
<dataarea name="flop1" size="655360">
<rom name="TS v2.0_edited.trd" size="655360" crc="e4d026bb" sha1="a8bbb38f301cc588f3af0f8ed01f0822c7b38ab3" />
</dataarea>
</part>
<part name="v1_1" interface="floppy_5_25">
<dataarea name="flop1" size="655360">
<rom name="TSolv1.1.trd" size="655360" crc="0ec1c4da" sha1="5c0a0cb8c8043748b582750d0171d68d9ac4d6c7" />
</dataarea>
</part>
</software>
<software name="uwol">
<description>Uwol - Quest for Money</description>
<year>2012</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<info name="developer" value="Shiru"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="53760">
<rom name="uwol_1.0.spg" size="53760" crc="768fc5ca" sha1="78c8c63ce896d03f620c03269d73ff018563f885" />
</dataarea>
</part>
</software>
<software name="wonderboy">
<description>Wonder Boy</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Blade"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="84992">
<rom name="WonderBoy.spg" size="84992" crc="f6fcc4cd" sha1="fd0ba88a6f521a664e70995188102c77e8cd8331" />
</dataarea>
</part>
</software>
<software name="xonix">
<description>Xonix</description>
<year>2012</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Shiru"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="224256">
<rom name="xnx.spg" size="224256" crc="b6da5a5d" sha1="a3ec74ce8bb239565fac7425283cd0c4adcc0d13" />
</dataarea>
</part>
</software>
<software name="zenloops">
<description>Zen Loops</description>
<year>201?</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="g0blinish"/>
<part name="dump" interface="spectrum_snapshot">
<dataarea name="dump" size="18432">
<rom name="zenloops.spg" size="18432" crc="50f3a0e4" sha1="6a99fdac432f5467dc16bbb7374a7455eca9df19" />
</dataarea>
</part>
</software>
<software name="zxbatlecity">
<description>ZX Battle City v1.4 (NoVDAC)</description>
<year>2020</year>
<publisher>&lt;homebrew&gt;</publisher>
<info name="developer" value="Marie Slip"/>
<info name="developer" value="n1k-o"/>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="zxbattlecity_1_4_novdac.trd" size="655360" crc="0a2bfb45" sha1="21747a464db723d934ec2fa8a398b212344f6c1e" />
</dataarea>
</part>
</software>
</softwarelist>

View File

@ -1,30 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
<!--
license:CC0-1.0
-->
<softwarelist name="tsconf_betadisc_flop" description="TS-Configuration Beta Disc / TR-DOS disk images">
<software name="copter">
<description>Copter v0.1</description>
<year>2012</year>
<publisher>Wizart/DT</publisher>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="COPTER.trd" size="655360" crc="43236562" sha1="c4e3a9bcfd2387e954372a633f7415db368dbd4b" />
</dataarea>
</part>
</software>
<software name="zxbatlecity">
<description>ZX Battle City v1.4 (NoVDAC)</description>
<year>2020</year>
<publisher>Marie Slip / n1k-o</publisher>
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="655360">
<rom name="zxbattlecity_1_4_novdac.trd" size="655360" crc="0a2bfb45" sha1="21747a464db723d934ec2fa8a398b212344f6c1e" />
</dataarea>
</part>
</software>
</softwarelist>

View File

@ -1920,6 +1920,8 @@ if (BUSES["ISA"]~=null) then
MAME_DIR .. "src/devices/bus/isa/xsu_cards.h", MAME_DIR .. "src/devices/bus/isa/xsu_cards.h",
MAME_DIR .. "src/devices/bus/isa/xtide.cpp", MAME_DIR .. "src/devices/bus/isa/xtide.cpp",
MAME_DIR .. "src/devices/bus/isa/xtide.h", MAME_DIR .. "src/devices/bus/isa/xtide.h",
MAME_DIR .. "src/devices/bus/isa/zxbus_adapter.cpp",
MAME_DIR .. "src/devices/bus/isa/zxbus_adapter.h",
} }
end end

View File

@ -41,7 +41,7 @@ DEFINE_DEVICE_TYPE(ISA8_COM, isa8_com_device, "isa_com", "Communications Adapter
void isa8_com_device::device_add_mconfig(machine_config &config) void isa8_com_device::device_add_mconfig(machine_config &config)
{ {
ins8250_device &uart0(INS8250(config, "uart_0", XTAL(1'843'200))); ns16550_device &uart0(NS16550(config, "uart_0", XTAL(1'843'200)));
uart0.out_tx_callback().set("serport0", FUNC(rs232_port_device::write_txd)); uart0.out_tx_callback().set("serport0", FUNC(rs232_port_device::write_txd));
uart0.out_dtr_callback().set("serport0", FUNC(rs232_port_device::write_dtr)); uart0.out_dtr_callback().set("serport0", FUNC(rs232_port_device::write_dtr));
uart0.out_rts_callback().set("serport0", FUNC(rs232_port_device::write_rts)); uart0.out_rts_callback().set("serport0", FUNC(rs232_port_device::write_rts));
@ -118,7 +118,7 @@ isa8_com_device::isa8_com_device(const machine_config &mconfig, device_type type
void isa8_com_device::device_start() void isa8_com_device::device_start()
{ {
set_isa_device(); set_isa_device();
m_isa->install_device(0x03f8, 0x03ff, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_0"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_0"), FUNC(ins8250_device::ins8250_w))); m_isa->install_device(0x03e8, 0x03ef, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_0"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_0"), FUNC(ins8250_device::ins8250_w)));
m_isa->install_device(0x02f8, 0x02ff, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_1"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_1"), FUNC(ins8250_device::ins8250_w))); m_isa->install_device(0x02f8, 0x02ff, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_1"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_1"), FUNC(ins8250_device::ins8250_w)));
// m_isa->install_device(0x03e8, 0x03ef, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_2"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_2"), FUNC(ins8250_device::ins8250_w))); // m_isa->install_device(0x03e8, 0x03ef, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_2"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_2"), FUNC(ins8250_device::ins8250_w)));
// m_isa->install_device(0x02e8, 0x02ef, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_3"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_3"), FUNC(ins8250_device::ins8250_w))); // m_isa->install_device(0x02e8, 0x02ef, read8sm_delegate(*subdevice<ins8250_uart_device>("uart_3"), FUNC(ins8250_device::ins8250_r)), write8sm_delegate(*subdevice<ins8250_uart_device>("uart_3"), FUNC(ins8250_device::ins8250_w)));

View File

@ -9,6 +9,7 @@
#include "emu.h" #include "emu.h"
#include "isa_cards.h" #include "isa_cards.h"
/*
// video // video
#include "aga.h" #include "aga.h"
#include "cga.h" #include "cga.h"
@ -98,10 +99,13 @@
#include "finalchs.h" #include "finalchs.h"
#include "hpblp.h" #include "hpblp.h"
#include "opus100pm.h" #include "opus100pm.h"
*/
#include "zxbus_adapter.h"
void pc_isa8_cards(device_slot_interface &device) void pc_isa8_cards(device_slot_interface &device)
{ {
/*
device.option_add("mda", ISA8_MDA); device.option_add("mda", ISA8_MDA);
device.option_add("cga", ISA8_CGA); device.option_add("cga", ISA8_CGA);
device.option_add("cga_ec1841", ISA8_EC1841_0002); device.option_add("cga_ec1841", ISA8_EC1841_0002);
@ -156,10 +160,13 @@ void pc_isa8_cards(device_slot_interface &device)
device.option_add("acb2072", ACB2072); device.option_add("acb2072", ACB2072);
device.option_add("3xtwin", ISA8_3XTWIN); device.option_add("3xtwin", ISA8_3XTWIN);
device.option_add("opus108pm", ISA8_OPUS108PM); device.option_add("opus108pm", ISA8_OPUS108PM);
*/
device.option_add("zxbus_adapter", ISA8_ZXBUS);
} }
void pc_isa16_cards(device_slot_interface &device) void pc_isa16_cards(device_slot_interface &device)
{ {
/*
// 8-bit // 8-bit
device.option_add("mda", ISA8_MDA); device.option_add("mda", ISA8_MDA);
device.option_add("cga", ISA8_CGA); device.option_add("cga", ISA8_CGA);
@ -261,4 +268,5 @@ void pc_isa16_cards(device_slot_interface &device)
device.option_add("omti8621", ISA16_OMTI8621); device.option_add("omti8621", ISA16_OMTI8621);
device.option_add("lrk331", LRK331); device.option_add("lrk331", LRK331);
device.option_add("hpblp", HPBLP); device.option_add("hpblp", HPBLP);
*/
} }

View File

@ -0,0 +1,28 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
#include "emu.h"
#include "zxbus_adapter.h"
DEFINE_DEVICE_TYPE(ISA8_ZXBUS, zxbus_adapter_device, "zxbus_adapter", "ISA8 to ZXBUS Adapter")
zxbus_adapter_device::zxbus_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, ISA8_ZXBUS, tag, owner, clock)
, device_isa8_card_interface(mconfig, *this)
, m_isa_io_view(*this, "isa_io_view")
, m_zxbus(*this, "zxbus")
{
}
void zxbus_adapter_device::device_start()
{
set_isa_device();
m_isa->space(isa8_device::AS_ISA_IO).install_view(0x0000, 0xffff, m_isa_io_view);
m_zxbus->set_io_space(m_isa_io_view[0], m_isa_io_view[0]);
m_isa_io_view.select(0);
}
void zxbus_adapter_device::device_add_mconfig(machine_config &config)
{
ZXBUS(config, m_zxbus, 0);
ZXBUS_SLOT(config, "card", 0, m_zxbus, zxbus_cards, nullptr);
}

View File

@ -0,0 +1,27 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
#ifndef MAME_BUS_ISA_ZXBUS_ADAPTER_H
#define MAME_BUS_ISA_ZXBUS_ADAPTER_H
#include "isa.h"
#include "bus/spectrum/zxbus/bus.h"
class zxbus_adapter_device: public device_t, public device_isa8_card_interface
{
public:
zxbus_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
private:
memory_view m_isa_io_view;
required_device<zxbus_device> m_zxbus;
};
DECLARE_DEVICE_TYPE(ISA8_ZXBUS, zxbus_adapter_device)
#endif // MAME_BUS_ISA_ZXBUS_ADAPTER_H

View File

@ -201,7 +201,13 @@ DEFINE_DEVICE_TYPE(PC_KBD_MICROSOFT_NATURAL, pc_kbd_microsoft_natural_device, "k
ROM_START( microsoft_natural ) ROM_START( microsoft_natural )
ROM_REGION(0x1000, "ms_natrl_cpu", 0) ROM_REGION(0x1000, "ms_natrl_cpu", 0)
ROM_LOAD("natural.bin", 0x0000, 0x1000, CRC(aa8243ab) SHA1(72134882a5c03e785db07cc54dfb7572c0a730d9)) ROM_DEFAULT_BIOS("orig")
ROM_SYSTEM_BIOS(0, "orig", "Original")
ROMX_LOAD("natural.bin", 0x0000, 0x1000, CRC(aa8243ab) SHA1(72134882a5c03e785db07cc54dfb7572c0a730d9), ROM_BIOS(0))
ROM_SYSTEM_BIOS(1, "sp2k", "Sprinter 2k Fix")
ROMX_LOAD("natural-sp2k.bin", 0x0000, 0x1000, CRC(16c21ab2) SHA1(72c6ebe8fd88a81a6c9622ff968ad2d0eb04a629), ROM_BIOS(1))
ROM_END ROM_END

View File

@ -40,8 +40,8 @@ zxbus_device::zxbus_device(const machine_config &mconfig, const char *tag, devic
zxbus_device::zxbus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) zxbus_device::zxbus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock) : device_t(mconfig, type, tag, owner, clock)
, m_iospace(*this, finder_base::DUMMY_TAG, -1) , m_io(nullptr)
, m_shadow_io_view(nullptr) , m_shadow_io(nullptr)
{ {
} }
@ -52,10 +52,14 @@ void zxbus_device::device_start()
void zxbus_device::add_slot(zxbus_slot_device &slot) void zxbus_device::add_slot(zxbus_slot_device &slot)
{ {
m_slot_list.push_front(&slot); m_slot_list.push_front(&slot);
if (m_shadow_io_view)
device_zxbus_card_interface *card = slot.get_card_device();
if (card)
{ {
device_zxbus_card_interface *dev = slot.get_card_device(); if (m_io)
(*m_shadow_io_view).install_device(0x0000, 0xffff, *dev, &device_zxbus_card_interface::map_shadow_io); m_io->install_device(0x0000, 0xffff, *card, &device_zxbus_card_interface::io_map);
if (m_shadow_io)
m_shadow_io->install_device(0x0000, 0xffff, *card, &device_zxbus_card_interface::shadow_io_map);
} }
} }
@ -65,11 +69,6 @@ device_zxbus_card_interface::device_zxbus_card_interface(const machine_config &m
{ {
} }
void zxbus_device::install_shadow_io(memory_view::memory_view_entry &io_view)
{
m_shadow_io_view = &io_view;
}
void device_zxbus_card_interface::interface_pre_start() void device_zxbus_card_interface::interface_pre_start()
{ {
if (!m_zxbus) if (!m_zxbus)

View File

@ -85,14 +85,13 @@ class zxbus_device : public device_t
public: public:
zxbus_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); zxbus_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
template <typename T> void set_iospace(T &&tag, int spacenum) { m_iospace.set_tag(std::forward<T>(tag), spacenum); } void set_io_space(address_space_installer &io, address_space_installer &shadow_io)
template<typename T> void install_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(class address_map &map), u64 unitmask = ~u64(0))
{ {
m_iospace->install_device(addrstart, addrend, device, map, unitmask); m_io = &io;
m_shadow_io = &shadow_io;
} }
void add_slot(zxbus_slot_device &slot); void add_slot(zxbus_slot_device &slot);
void install_shadow_io(memory_view::memory_view_entry &io_view);
protected: protected:
zxbus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); zxbus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
@ -100,8 +99,8 @@ protected:
virtual void device_start() override ATTR_COLD; virtual void device_start() override ATTR_COLD;
private: private:
required_address_space m_iospace; address_space_installer *m_io;
memory_view::memory_view_entry *m_shadow_io_view; address_space_installer *m_shadow_io;
std::forward_list<zxbus_slot_device *> m_slot_list; std::forward_list<zxbus_slot_device *> m_slot_list;
}; };
@ -114,7 +113,8 @@ class device_zxbus_card_interface : public device_interface
friend class zxbus_slot_device; friend class zxbus_slot_device;
public: public:
virtual void map_shadow_io(address_map &map) ATTR_COLD {} virtual void io_map(address_map &map) ATTR_COLD {}
virtual void shadow_io_map(address_map &map) ATTR_COLD {}
protected: protected:
device_zxbus_card_interface(const machine_config &mconfig, device_t &device); device_zxbus_card_interface(const machine_config &mconfig, device_t &device);

View File

@ -21,12 +21,13 @@ public:
, m_ata(*this, "ata") , m_ata(*this, "ata")
{ } { }
virtual void io_map(address_map &map) override ATTR_COLD;
protected: protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual void device_start() override ATTR_COLD; virtual void device_start() override ATTR_COLD;
private: private:
void map_io(address_map &map) ATTR_COLD;
u8 ata_r(offs_t offset); u8 ata_r(offs_t offset);
void ata_w(offs_t offset, u8 data); void ata_w(offs_t offset, u8 data);
@ -51,7 +52,7 @@ void nemoide_device::ata_w(offs_t offset, u8 data)
m_ata->cs0_w((offset >> 5) & 7, ata_data); m_ata->cs0_w((offset >> 5) & 7, ata_data);
} }
void nemoide_device::map_io(address_map &map) void nemoide_device::io_map(address_map &map)
{ {
map(0x0011, 0x0011).mirror(0xff00).lrw8(NAME([this]() { return m_ata_data_latch; }) map(0x0011, 0x0011).mirror(0xff00).lrw8(NAME([this]() { return m_ata_data_latch; })
, NAME([this](offs_t offset, u8 data) { m_ata_data_latch = data; })); , NAME([this](offs_t offset, u8 data) { m_ata_data_latch = data; }));
@ -74,8 +75,6 @@ void nemoide_device::device_add_mconfig(machine_config &config)
void nemoide_device::device_start() void nemoide_device::device_start()
{ {
save_item(NAME(m_ata_data_latch)); save_item(NAME(m_ata_data_latch));
m_zxbus->install_device(0x0000, 0xffff, *this, &nemoide_device::map_io);
} }
} // anonymous namespace } // anonymous namespace

View File

@ -85,6 +85,8 @@ public:
, m_neogs_led(*this, "neogs_led") , m_neogs_led(*this, "neogs_led")
{ } { }
virtual void io_map(address_map &map) override ATTR_COLD;
protected: protected:
// device_t implementation // device_t implementation
virtual void device_start() override ATTR_COLD; virtual void device_start() override ATTR_COLD;
@ -92,8 +94,6 @@ protected:
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void neogsmap(address_map &map) ATTR_COLD;
INTERRUPT_GEN_MEMBER(irq0_line_assert); INTERRUPT_GEN_MEMBER(irq0_line_assert);
void map_memory(address_map &map) ATTR_COLD; void map_memory(address_map &map) ATTR_COLD;
@ -437,7 +437,7 @@ const tiny_rom_entry *neogs_device::device_rom_region() const
return ROM_NAME( neogs ); return ROM_NAME( neogs );
} }
void neogs_device::neogsmap(address_map &map) void neogs_device::io_map(address_map &map)
{ {
map(0x00bb, 0x00bb).mirror(0xff00).rw(FUNC(neogs_device::neogs_status_r), FUNC(neogs_device::neogs_command_w)); map(0x00bb, 0x00bb).mirror(0xff00).rw(FUNC(neogs_device::neogs_status_r), FUNC(neogs_device::neogs_command_w));
map(0x00b3, 0x00b3).mirror(0xff00).rw(FUNC(neogs_device::neogs_data_r), FUNC(neogs_device::neogs_data_w)); map(0x00b3, 0x00b3).mirror(0xff00).rw(FUNC(neogs_device::neogs_data_r), FUNC(neogs_device::neogs_data_w));
@ -465,8 +465,6 @@ void neogs_device::device_start()
} }
}); });
m_zxbus->install_device(0x0000, 0xffff, *this, &neogs_device::neogsmap);
m_neogs_led.resolve(); m_neogs_led.resolve();
save_item(NAME(m_data_in)); save_item(NAME(m_data_in));

View File

@ -25,7 +25,7 @@ public:
, m_ata(*this, "ata") , m_ata(*this, "ata")
{ } { }
virtual void map_shadow_io(address_map &map) override ATTR_COLD; virtual void shadow_io_map(address_map &map) override ATTR_COLD;
protected: protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
@ -33,8 +33,6 @@ protected:
virtual void device_reset() override ATTR_COLD; virtual void device_reset() override ATTR_COLD;
private: private:
void map_io(address_map &map) ATTR_COLD {}
void port_ffba_w(offs_t offset, u8 data); void port_ffba_w(offs_t offset, u8 data);
u8 ata_r(offs_t offset); u8 ata_r(offs_t offset);
void ata_w(offs_t offset, u8 data); void ata_w(offs_t offset, u8 data);
@ -83,7 +81,7 @@ void smuc_device::ata_w(offs_t offset, u8 data)
m_ata->cs0_w(ata_offset, ata_data); m_ata->cs0_w(ata_offset, ata_data);
} }
void smuc_device::map_shadow_io(address_map &map) void smuc_device::shadow_io_map(address_map &map)
{ {
map(0x18a2, 0x18a2).mirror(0x4718) // 5fba | 0x011xxx101xx010 | Version: 2 map(0x18a2, 0x18a2).mirror(0x4718) // 5fba | 0x011xxx101xx010 | Version: 2
.lr8(NAME([]() { return 0x40; })); .lr8(NAME([]() { return 0x40; }));
@ -125,8 +123,6 @@ void smuc_device::device_start()
save_item(NAME(m_port_7fba_data)); save_item(NAME(m_port_7fba_data));
save_item(NAME(m_port_ffba_data)); save_item(NAME(m_port_ffba_data));
save_item(NAME(m_ide_hi)); save_item(NAME(m_ide_hi));
m_zxbus->install_device(0x0000, 0xffff, *this, &smuc_device::map_io);
} }
void smuc_device::device_reset() void smuc_device::device_reset()

View File

@ -61,7 +61,7 @@ protected:
virtual void signature() override; virtual void signature() override;
int m_can_identify_device; int m_can_identify_device;
uint16_t m_num_cylinders; uint32_t m_num_cylinders;
uint8_t m_num_sectors; uint8_t m_num_sectors;
uint8_t m_num_heads; uint8_t m_num_heads;

View File

@ -131,17 +131,20 @@ enum
****************************************************************************/ ****************************************************************************/
DEFINE_DEVICE_TYPE(Z80DMA, z80dma_device, "z80dma", "Z80 DMA Controller") DEFINE_DEVICE_TYPE(Z80DMA, z80dma_device, "z80dma", "Z80 DMA Controller")
ALLOW_SAVE_TYPE(z80dma_device::dma_mode);
/**************************************************************************** /****************************************************************************
* z80dma_device - constructor * z80dma_device - constructor
****************************************************************************/ ****************************************************************************/
z80dma_device::z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) z80dma_device::z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: z80dma_device(mconfig, Z80DMA, tag, owner, clock) : z80dma_device(mconfig, Z80DMA, tag, owner, clock, dma_mode::ZILOG)
{ {
} }
z80dma_device::z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) z80dma_device::z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, dma_mode dma_mode)
: device_t(mconfig, type, tag, owner, clock) : device_t(mconfig, type, tag, owner, clock)
, device_z80daisy_interface(mconfig, *this) , device_z80daisy_interface(mconfig, *this)
, m_dma_mode(dma_mode)
, m_out_busreq_cb(*this) , m_out_busreq_cb(*this)
, m_out_int_cb(*this) , m_out_int_cb(*this)
, m_out_ieo_cb(*this) , m_out_ieo_cb(*this)
@ -162,6 +165,7 @@ void z80dma_device::device_start()
m_timer = timer_alloc(FUNC(z80dma_device::clock_w), this); m_timer = timer_alloc(FUNC(z80dma_device::clock_w), this);
// register for state saving // register for state saving
save_item(NAME(m_dma_mode));
save_item(NAME(m_regs)); save_item(NAME(m_regs));
save_item(NAME(m_regs_follow)); save_item(NAME(m_regs_follow));
save_item(NAME(m_num_follow)); save_item(NAME(m_num_follow));
@ -179,6 +183,7 @@ void z80dma_device::device_start()
save_item(NAME(m_rdy)); save_item(NAME(m_rdy));
save_item(NAME(m_force_ready)); save_item(NAME(m_force_ready));
save_item(NAME(m_wait)); save_item(NAME(m_wait));
save_item(NAME(m_waits_extra));
save_item(NAME(m_busrq_ack)); save_item(NAME(m_busrq_ack));
save_item(NAME(m_is_pulse)); save_item(NAME(m_is_pulse));
save_item(NAME(m_latch)); save_item(NAME(m_latch));
@ -197,6 +202,7 @@ void z80dma_device::device_reset()
m_rdy = 0; m_rdy = 0;
m_force_ready = 0; m_force_ready = 0;
m_wait = 0; m_wait = 0;
m_waits_extra = 0;
m_num_follow = 0; m_num_follow = 0;
m_read_num_follow = m_read_cur_follow = 0; m_read_num_follow = m_read_cur_follow = 0;
m_reset_pointer = 0; m_reset_pointer = 0;
@ -445,10 +451,9 @@ void z80dma_device::do_write()
break; break;
} }
m_byte_counter++;
m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1; m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1; m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
m_byte_counter++;
} }
/**************************************************************************** /****************************************************************************
@ -497,7 +502,8 @@ TIMER_CALLBACK_MEMBER(z80dma_device::clock_w)
} }
const attotime clock = clocks_to_attotime(1); const attotime clock = clocks_to_attotime(1);
const attotime next = clock * (3 - ((PORTA_IS_SOURCE ? PORTA_TIMING : PORTB_TIMING) & 0x03)); const attotime next = clock * (3 - ((PORTA_IS_SOURCE ? PORTA_TIMING : PORTB_TIMING) & 0x03) + m_waits_extra);
m_waits_extra = 0;
m_timer->adjust(next, 0, clock); m_timer->adjust(next, 0, clock);
m_dma_seq = SEQ_TRANS1_READ_SOURCE; m_dma_seq = SEQ_TRANS1_READ_SOURCE;
@ -517,7 +523,8 @@ TIMER_CALLBACK_MEMBER(z80dma_device::clock_w)
case SEQ_TRANS1_INC_DEC_DEST_ADDRESS: case SEQ_TRANS1_INC_DEC_DEST_ADDRESS:
{ {
const attotime clock = clocks_to_attotime(1); const attotime clock = clocks_to_attotime(1);
const attotime next = clock * (3 - ((PORTB_IS_SOURCE ? PORTA_TIMING : PORTB_TIMING) & 0x03)); const attotime next = clock * (3 - ((PORTB_IS_SOURCE ? PORTA_TIMING : PORTB_TIMING) & 0x03) + m_waits_extra);
m_waits_extra = 0;
m_timer->adjust(next, 0, clock); m_timer->adjust(next, 0, clock);
m_dma_seq = SEQ_TRANS1_WRITE_DEST; m_dma_seq = SEQ_TRANS1_WRITE_DEST;
@ -672,7 +679,7 @@ void z80dma_device::write(u8 data)
if (data & 0x10) if (data & 0x10)
m_regs_follow[m_num_follow++] = GET_REGNUM(MATCH_BYTE); m_regs_follow[m_num_follow++] = GET_REGNUM(MATCH_BYTE);
if (BIT(data, 6)) if (BIT(data, 6) && m_dma_mode != dma_mode::UA858D)
{ {
enable(); enable();
} }
@ -875,7 +882,7 @@ TIMER_CALLBACK_MEMBER(z80dma_device::rdy_write_callback)
void z80dma_device::rdy_w(int state) void z80dma_device::rdy_w(int state)
{ {
LOG("Z80DMA RDY: %d Active High: %d\n", state, READY_ACTIVE_HIGH); LOG("Z80DMA RDY: %d Active High: %d\n", state, READY_ACTIVE_HIGH);
machine().scheduler().synchronize(timer_expired_delegate(FUNC(z80dma_device::rdy_write_callback),this), state); machine().scheduler().synchronize(timer_expired_delegate(FUNC(z80dma_device::rdy_write_callback), this), state);
} }
/**************************************************************************** /****************************************************************************
@ -885,3 +892,11 @@ void z80dma_device::bai_w(int state)
{ {
m_busrq_ack = state; m_busrq_ack = state;
} }
DEFINE_DEVICE_TYPE(UA858D, ua858d_device, "ua858d", "UA858D DMA Controller")
ua858d_device::ua858d_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: z80dma_device(mconfig, UA858D, tag, owner, clock, dma_mode::UA858D)
{
}

View File

@ -48,6 +48,12 @@ class z80dma_device : public device_t,
public device_z80daisy_interface public device_z80daisy_interface
{ {
public: public:
enum class dma_mode : u8
{
ZILOG = 0,
UA858D = 1
};
// construction/destruction // construction/destruction
z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
@ -60,12 +66,14 @@ public:
auto in_iorq_callback() { return m_in_iorq_cb.bind(); } auto in_iorq_callback() { return m_in_iorq_cb.bind(); }
auto out_iorq_callback() { return m_out_iorq_cb.bind(); } auto out_iorq_callback() { return m_out_iorq_cb.bind(); }
void set_dma_mode(dma_mode dma_mode) { m_dma_mode = dma_mode; }
u8 read(); u8 read();
virtual void write(u8 data); virtual void write(u8 data);
void iei_w(int state) { m_iei = state; interrupt_check(); } void iei_w(int state) { m_iei = state; interrupt_check(); }
void rdy_w(int state); void rdy_w(int state);
void wait_w(int state) { m_wait = state; } void wait_w(int state) { m_wait = state; }
void adjust_wait(int count) { m_waits_extra += count; }
void bai_w(int state); void bai_w(int state);
protected: protected:
@ -90,7 +98,7 @@ protected:
static inline constexpr int TM_SEARCH = 0x02; static inline constexpr int TM_SEARCH = 0x02;
static inline constexpr int TM_SEARCH_TRANSFER = 0x03; static inline constexpr int TM_SEARCH_TRANSFER = 0x03;
z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, dma_mode dma_mode);
// device_t implementation // device_t implementation
virtual void device_start() override ATTR_COLD; virtual void device_start() override ATTR_COLD;
@ -112,6 +120,7 @@ protected:
static constexpr unsigned REGNUM(unsigned m, unsigned s) { return (m << 3) + s; } static constexpr unsigned REGNUM(unsigned m, unsigned s) { return (m << 3) + s; }
dma_mode m_dma_mode;
u16 m_addressA; u16 m_addressA;
u16 m_addressB; u16 m_addressB;
u16 m_count; u16 m_count;
@ -153,6 +162,7 @@ private:
u8 m_reset_pointer; u8 m_reset_pointer;
int m_wait; int m_wait;
int m_waits_extra;
int m_busrq_ack; int m_busrq_ack;
bool m_is_pulse; bool m_is_pulse;
u8 m_latch; u8 m_latch;
@ -164,8 +174,14 @@ private:
u8 m_vector; // interrupt vector u8 m_vector; // interrupt vector
}; };
class ua858d_device : public z80dma_device
{
public:
ua858d_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// device type definition // device type definition
DECLARE_DEVICE_TYPE(Z80DMA, z80dma_device) DECLARE_DEVICE_TYPE(Z80DMA, z80dma_device)
DECLARE_DEVICE_TYPE(UA858D, ua858d_device)
#endif // MAME_MACHINE_Z80DMA_H #endif // MAME_MACHINE_Z80DMA_H

View File

@ -28,6 +28,7 @@
#include "softlist.h" #include "softlist.h"
#include "corestr.h" #include "corestr.h"
#include "multibyte.h"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
@ -2007,6 +2008,9 @@ void debugger_commands::execute_rewind(const std::vector<std::string_view> &para
void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> &params) void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> &params)
{ {
if (execute_save_try_memory(params))
return;
u64 offset, endoffset, length; u64 offset, endoffset, length;
address_space *space; address_space *space;
@ -2093,31 +2097,42 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
m_console.printf("Data saved successfully\n"); m_console.printf("Data saved successfully\n");
} }
/*------------------------------------------------- /*-------------------------------------------------
execute_saveregion - execute the save command on region memory execute_savememory - execute the save command on memory
-------------------------------------------------*/ -------------------------------------------------*/
void debugger_commands::execute_saveregion(const std::vector<std::string_view> &params) bool debugger_commands::execute_save_try_memory(const std::vector<std::string_view> &params)
{ {
u64 offset, length; u64 offset = u64(-1);
memory_region *region; memory_region *region = nullptr;
memory_share *share = nullptr;
if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share))
return false; // not memory case
// validate parameters u64 length;
if (!m_console.validate_number_parameter(params[1], offset)) if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr))
return; return true;
if (!m_console.validate_number_parameter(params[2], length))
return;
if (!m_console.validate_memory_region_parameter(params[3], region))
return;
if (offset >= region->bytes()) u32 msize;
u8 *base;
if (region != nullptr)
{
msize = region->bytes();
base = region->base();
}
else // if (share != nullptr)
{
msize = share->bytes();
base = reinterpret_cast<u8 *>(share->ptr());
}
if (offset >= msize)
{ {
m_console.printf("Invalid offset\n"); m_console.printf("Invalid offset\n");
return; return true;
} }
if ((length <= 0) || ((length + offset) >= region->bytes())) if ((length <= 0) || ((length + offset) >= msize))
length = region->bytes() - offset; length = msize - offset;
// open the file // open the file
std::string const filename(params[0]); std::string const filename(params[0]);
@ -2125,12 +2140,24 @@ void debugger_commands::execute_saveregion(const std::vector<std::string_view> &
if (!f) if (!f)
{ {
m_console.printf("Error opening file '%s'\n", params[0]); m_console.printf("Error opening file '%s'\n", params[0]);
return; return true;
} }
fwrite(region->base() + offset, 1, length, f); fwrite(base + offset, 1, length, f);
fclose(f); fclose(f);
m_console.printf("Data saved successfully\n"); m_console.printf("Data saved successfully\n");
return true;
}
/*-------------------------------------------------
execute_saveregion - execute the save command on region memory
-------------------------------------------------*/
void debugger_commands::execute_saveregion(const std::vector<std::string_view> &params)
{
execute_save(-1, std::vector<std::string_view>{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] });
} }
@ -2140,6 +2167,9 @@ void debugger_commands::execute_saveregion(const std::vector<std::string_view> &
void debugger_commands::execute_load(int spacenum, const std::vector<std::string_view> &params) void debugger_commands::execute_load(int spacenum, const std::vector<std::string_view> &params)
{ {
if (execute_load_try_memory(params))
return;
u64 offset, endoffset, length = 0; u64 offset, endoffset, length = 0;
address_space *space; address_space *space;
@ -2247,31 +2277,43 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, i-1); m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, i-1);
} }
/*------------------------------------------------- /*-------------------------------------------------
execute_loadregion - execute the load command on region memory execute_loadmemory - execute the load command on memory
-------------------------------------------------*/ -------------------------------------------------*/
void debugger_commands::execute_loadregion(const std::vector<std::string_view> &params) bool debugger_commands::execute_load_try_memory(const std::vector<std::string_view> &params)
{ {
u64 offset, length; u64 offset = u64(-1);
memory_region *region; memory_region *region = nullptr;
memory_share *share = nullptr;
if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share))
return false; // not memory case
u64 length;
// validate parameters // validate parameters
if (!m_console.validate_number_parameter(params[1], offset)) if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr))
return; return true;
if (!m_console.validate_number_parameter(params[2], length))
return;
if (!m_console.validate_memory_region_parameter(params[3], region))
return;
if (offset >= region->bytes()) u32 msize;
u8 *base;
if (region != nullptr)
{
msize = region->bytes();
base = region->base();
}
else // if (share != nullptr)
{
msize = share->bytes();
base = reinterpret_cast<u8 *>(share->ptr());
}
if (offset >= msize)
{ {
m_console.printf("Invalid offset\n"); m_console.printf("Invalid offset\n");
return; return true;
} }
if ((length <= 0) || ((length + offset) >= region->bytes())) if ((length <= 0) || ((length + offset) >= msize))
length = region->bytes() - offset; length = msize - offset;
// open the file // open the file
std::string filename(params[0]); std::string filename(params[0]);
@ -2279,7 +2321,7 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> &
if (!f) if (!f)
{ {
m_console.printf("Error opening file '%s'\n", params[0]); m_console.printf("Error opening file '%s'\n", params[0]);
return; return true;
} }
fseek(f, 0L, SEEK_END); fseek(f, 0L, SEEK_END);
@ -2290,10 +2332,22 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> &
if (length >= size) if (length >= size)
length = size; length = size;
fread(region->base() + offset, 1, length, f); fread(base + offset, 1, length, f);
fclose(f); fclose(f);
m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, offset + length - 1); m_console.printf("Data loaded successfully to memory : 0x%X to 0x%X\n", offset, offset + length - 1);
return true;
}
/*-------------------------------------------------
execute_loadregion - execute the load command on region memory
-------------------------------------------------*/
void debugger_commands::execute_loadregion(const std::vector<std::string_view> &params)
{
execute_load(-1, std::vector<std::string_view>{ params[0], std::string(params[1]) + std::string(params[3]) + ".m", params[2] });
} }
@ -2303,6 +2357,9 @@ void debugger_commands::execute_loadregion(const std::vector<std::string_view> &
void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> &params) void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> &params)
{ {
if (execute_dump_try_memory(params))
return;
// validate parameters // validate parameters
address_space *space; address_space *space;
u64 offset; u64 offset;
@ -2460,6 +2517,172 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
m_console.printf("Data dumped successfully\n"); m_console.printf("Data dumped successfully\n");
} }
/*-------------------------------------------------
execute_dumpmemory - execute the dump command on memory
-------------------------------------------------*/
bool debugger_commands::execute_dump_try_memory(const std::vector<std::string_view> &params)
{
u64 offset = u64(-1);
memory_region *region = nullptr;
memory_share *share = nullptr;
if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share))
return false; // not memory case
u64 length;
if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr))
return true;
u64 width = 0;
if (params.size() > 3 && !m_console.validate_number_parameter(params[3], width))
return true;
bool ascii = true;
if (params.size() > 4 && !m_console.validate_boolean_parameter(params[4], ascii))
return true;
u64 rowsize = 16;
if (params.size() > 5 && !m_console.validate_number_parameter(params[5], rowsize))
return true;
int shift = 0;
u64 granularity = shift >= 0 ? 1 : 1 << -shift;
u32 msize;
u8 *base;
bool be;
if (region != nullptr)
{
msize = region->bytes();
base = region->base();
be = region->endianness() == ENDIANNESS_BIG;
if (width == 0)
width = region->bytewidth();
}
else // if (share != nullptr)
{
msize = share->bytes();
base = reinterpret_cast<u8 *>(share->ptr());
be = share->endianness() == ENDIANNESS_BIG;
if (width == 0)
width = share->bytewidth();
}
if (offset >= msize)
{
m_console.printf("Invalid offset\n");
return true;
}
if ((length <= 0) || ((length + offset) >= msize))
length = msize - offset;
// further validation
if (width != 1 && width != 2 && width != 4 && width != 8)
{
m_console.printf("Invalid width! (must be 1,2,4 or 8)\n");
return true;
}
if (width < granularity)
{
m_console.printf("Invalid width! (must be at least %d)\n", granularity);
return true;
}
if (rowsize == 0 || (rowsize % width) != 0)
{
m_console.printf("Invalid row size! (must be a positive multiple of %d)\n", width);
return true;
}
u64 endoffset = offset + length - 1;
// open the file
std::string filename(params[0]);
FILE *const f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
return true;
}
// now write the data out
util::ovectorstream output;
output.reserve(200);
const unsigned delta = (shift >= 0) ? (width << shift) : (width >> -shift);
for (u64 i = offset; i <= endoffset; i += rowsize)
{
output.clear();
output.rdbuf()->clear();
// print the address
util::stream_format(output, "%0*X: ", 8, i);
// print the bytes
for (u64 j = 0; j < rowsize; j += delta)
{
if (i + j <= endoffset)
{
switch (width)
{
case 8:
util::stream_format(output, " %016X", get_u64be(&base[i+j]));
break;
case 4:
util::stream_format(output, " %08X", get_u32be(&base[i+j]));
break;
case 2:
util::stream_format(output, " %04X", get_u16be(&base[i+j]));
break;
case 1:
util::stream_format(output, " %02X", base[i+j]);
break;
}
}
else
util::stream_format(output, " %*s", width * 2, "");
}
// print the ASCII
if (ascii)
{
util::stream_format(output, " ");
for (u64 j = 0; j < rowsize && (i + j) <= endoffset; j += delta)
{
u64 data = 0;
switch (width)
{
case 8:
data = get_u64be(&base[i+j]);
break;
case 4:
data = get_u32be(&base[i+j]);
break;
case 2:
data = get_u16be(&base[i+j]);
break;
case 1:
data = base[i+j];
break;
}
for (unsigned int b = 0; b != width; b++) {
u8 byte = data >> (8 * (be ? (width-1-b) : b));
util::stream_format(output, "%c", (byte >= 32 && byte < 127) ? byte : '.');
}
}
}
// output the result
auto const &text = output.vec();
fprintf(f, "%.*s\n", int(unsigned(text.size())), &text[0]);
}
// close the file
fclose(f);
m_console.printf("Data dumped successfully\n");
return true;
}
//------------------------------------------------- //-------------------------------------------------
// execute_strdump - execute the strdump command // execute_strdump - execute the strdump command
@ -2467,6 +2690,9 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> &params) void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> &params)
{ {
if (execute_strdump_try_memory(params))
return;
// validate parameters // validate parameters
u64 offset; u64 offset;
if (!m_console.validate_number_parameter(params[1], offset)) if (!m_console.validate_number_parameter(params[1], offset))
@ -2637,6 +2863,187 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
m_console.printf("Data dumped successfully\n"); m_console.printf("Data dumped successfully\n");
} }
/*-------------------------------------------------
execute_strdumpmemory - execute the strdump command on memory
-------------------------------------------------*/
bool debugger_commands::execute_strdump_try_memory(const std::vector<std::string_view> &params)
{
u64 offset = u64(-1);
memory_region *region = nullptr;
memory_share *share = nullptr;
if (!m_console.validate_address_with_memory_parameter(params[1], offset, region, share))
return false; // not memory case
u64 length;
if (offset == u64(-1) || !m_console.validate_number_parameter(params[2], length) || (region == nullptr && share == nullptr))
return true;
u64 term = 0;
if (params.size() > 3 && !m_console.validate_number_parameter(params[3], term))
return true;
// further validation
if (term >= 0x100 && term != u64(-0x80))
{
m_console.printf("Invalid termination character\n");
return true;
}
// open the file
std::string filename(params[0]);
FILE *f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
return true;
}
u32 msize;
u8 *base;
bool be;
u64 width;
if (region != nullptr)
{
msize = region->bytes();
base = region->base();
be = region->endianness() == ENDIANNESS_BIG;
width = region->bytewidth();
}
else // if (share != nullptr)
{
msize = share->bytes();
base = reinterpret_cast<u8 *>(share->ptr());
be = share->endianness() == ENDIANNESS_BIG;
width = share->bytewidth();
}
if (offset >= msize)
{
m_console.printf("Invalid offset\n");
return true;
}
if ((length <= 0) || ((length + offset) >= msize))
length = msize - offset;
// now write the data out
util::ovectorstream output;
output.reserve(200);
bool terminated = true;
while (length-- != 0)
{
if (terminated)
{
terminated = false;
output.clear();
output.rdbuf()->clear();
// print the address
util::stream_format(output, "%0*X: \"", 8, offset);
}
// get the character data
u64 data = 0;
offs_t curaddr = offset;
switch (width)
{
case 1:
data = base[curaddr];
break;
case 2:
data = be ? get_u16be(&base[curaddr]) : get_u16le(&base[curaddr]);
break;
case 4:
data = be ? get_u32be(&base[curaddr]) : get_u32le(&base[curaddr]);
break;
case 8:
data = be ? get_u64be(&base[curaddr]) : get_u64le(&base[curaddr]);
break;
}
// print the characters
for (int n = 0; n < width; n++)
{
// check for termination within word
if (terminated)
{
terminated = false;
// output the result
auto const &text = output.vec();
fprintf(f, "%.*s\"\n", int(unsigned(text.size())), &text[0]);
output.clear();
output.rdbuf()->clear();
// print the address
util::stream_format(output, "%0*X.%d: \"", 8, offset, n);
}
u8 ch = data & 0xff;
data >>= 8;
// check for termination
if (term == u64(-0x80))
{
if (BIT(ch, 7))
{
terminated = true;
ch &= 0x7f;
}
}
else if (ch == term)
{
terminated = true;
continue;
}
// check for non-ASCII characters
if (ch < 0x20 || ch >= 0x7f)
{
// use special or octal escape
if (ch >= 0x07 && ch <= 0x0d)
util::stream_format(output, "\\%c", "abtnvfr"[ch - 0x07]);
else
util::stream_format(output, "\\%03o", ch);
}
else
{
if (ch == '"' || ch == '\\')
output << '\\';
output << char(ch);
}
}
if (terminated)
{
// output the result
auto const &text = output.vec();
fprintf(f, "%.*s\"\n", int(unsigned(text.size())), &text[0]);
output.clear();
output.rdbuf()->clear();
}
offset += width;
}
if (!terminated)
{
// output the result
auto const &text = output.vec();
fprintf(f, "%.*s\"\\\n", int(unsigned(text.size())), &text[0]);
}
// close the file
fclose(f);
m_console.printf("Data dumped successfully\n");
return true;
}
/*------------------------------------------------- /*-------------------------------------------------
execute_cheatrange - add a range to search for execute_cheatrange - add a range to search for
@ -3139,6 +3546,9 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string_view> &p
void debugger_commands::execute_find(int spacenum, const std::vector<std::string_view> &params) void debugger_commands::execute_find(int spacenum, const std::vector<std::string_view> &params)
{ {
if (execute_find_try_memory(params))
return;
u64 offset, length; u64 offset, length;
address_space *space; address_space *space;
@ -3262,6 +3672,140 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
m_console.printf("Not found\n"); m_console.printf("Not found\n");
} }
/*-------------------------------------------------
execute_findmemory - execute the find command on memory
-------------------------------------------------*/
bool debugger_commands::execute_find_try_memory(const std::vector<std::string_view> &params)
{
u64 offset = u64(-1);
memory_region *region = nullptr;
memory_share *share = nullptr;
if (!m_console.validate_address_with_memory_parameter(params[0], offset, region, share))
return false; // not memory case
u64 length;
if (offset == u64(-1) || !m_console.validate_number_parameter(params[1], length) || (region == nullptr && share == nullptr))
return true;
u32 msize;
u8 *base;
bool be;
if (region != nullptr)
{
msize = region->bytes();
base = region->base();
be = region->endianness() == ENDIANNESS_BIG;
}
else // if (share != nullptr)
{
msize = share->bytes();
base = reinterpret_cast<u8 *>(share->ptr());
be = share->endianness() == ENDIANNESS_BIG;
}
if (offset >= msize)
{
m_console.printf("Invalid offset\n");
return true;
}
if ((length <= 0) || ((length + offset) >= msize))
length = msize - offset;
// further validation
u64 const endoffset = offset + length - 1;
int cur_data_size = 1;
// parse the data parameters
u64 data_to_find[256];
u8 data_size[256];
int data_count = 0;
for (int i = 2; i < params.size(); i++)
{
std::string_view pdata = params[i];
if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') // check for a string
{
auto const pdatalen = params[i].length() - 1;
for (int j = 1; j < pdatalen; j++)
{
data_to_find[data_count] = pdata[j];
data_size[data_count++] = 1;
}
}
else // otherwise, validate as a number
{
// check for a 'b','w','d',or 'q' prefix
data_size[data_count] = cur_data_size;
if (pdata.length() >= 2)
{
if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); }
if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); }
if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); }
if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); }
}
// look for a wildcard
if (pdata == "?")
data_size[data_count++] |= 0x10;
// otherwise, validate as a number
else if (!m_console.validate_number_parameter(pdata, data_to_find[data_count++]))
return true;
}
}
// now search
int found = 0;
for (u64 i = offset; i <= endoffset; i += data_size[0])
{
int suboffset = 0;
bool match = true;
// find the entire string
for (int j = 0; j < data_count && match; j++)
{
offs_t address = i + suboffset;
switch (data_size[j])
{
case 1:
match = u8(data_to_find[j]) == base[address];
break;
case 2:
match = u16(data_to_find[j]) == (be ? get_u16be(&base[address]) : get_u16le(&base[address]));
break;
case 4:
match = u32(data_to_find[j]) == (be ? get_u32be(&base[address]) : get_u32le(&base[address]));
break;
case 8:
match = u64(data_to_find[j]) == (be ? get_u64be(&base[address]) : get_u64le(&base[address]));
break;
default:
// all other cases are wildcards
break;
}
suboffset += data_size[j] & 0x0f;
}
// did we find it?
if (match)
{
found++;
m_console.printf("Found at %04X\n", i);
}
}
// print something if not found
if (found == 0)
m_console.printf("Not found\n");
return true;
}
//------------------------------------------------- //-------------------------------------------------
// execute_fill - execute the fill command // execute_fill - execute the fill command
@ -3269,6 +3813,9 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> &params) void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> &params)
{ {
if (execute_fill_try_memory(params))
return;
u64 offset, length; u64 offset, length;
address_space *space; address_space *space;
@ -3371,6 +3918,139 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
} }
} }
/*-------------------------------------------------
execute_fillmemory - execute the fill command on memory
-------------------------------------------------*/
bool debugger_commands::execute_fill_try_memory(const std::vector<std::string_view> &params)
{
u64 offset = u64(-1);
memory_region *region = nullptr;
memory_share *share = nullptr;
if (!m_console.validate_address_with_memory_parameter(params[0], offset, region, share))
return false; // not memory case
u64 length;
if (offset == u64(-1) || !m_console.validate_number_parameter(params[1], length) || (region == nullptr && share == nullptr))
return true;
u32 msize;
u8 *base;
bool be;
if (region != nullptr)
{
msize = region->bytes();
base = region->base();
be = region->endianness() == ENDIANNESS_BIG;
}
else // if (share != nullptr)
{
msize = share->bytes();
base = reinterpret_cast<u8 *>(share->ptr());
be = share->endianness() == ENDIANNESS_BIG;
}
if (offset >= msize)
{
m_console.printf("Invalid offset\n");
return true;
}
if ((length <= 0) || ((length + offset) >= msize))
length = msize - offset;
// further validation
int cur_data_size = 1;
// parse the data parameters
u64 fill_data[256];
u8 fill_data_size[256];
int data_count = 0;
for (int i = 2; i < params.size(); i++)
{
std::string_view pdata = params[i];
// check for a string
if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"')
{
auto const pdatalen = pdata.length() - 1;
for (int j = 1; j < pdatalen; j++)
{
fill_data[data_count] = pdata[j];
fill_data_size[data_count++] = 1;
}
}
// otherwise, validate as a number
else
{
// check for a 'b','w','d',or 'q' prefix
fill_data_size[data_count] = cur_data_size;
if (pdata.length() >= 2)
{
if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); }
if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); }
if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); }
if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); }
}
// validate as a number
if (!m_console.validate_number_parameter(pdata, fill_data[data_count++]))
return true;
}
}
if (data_count == 0)
return true;
// now fill memory
u64 count = length;
while (count != 0)
{
// write the entire string
for (int j = 0; j < data_count; j++)
{
offs_t address = offset;
switch (fill_data_size[j])
{
case 1:
base[address] = u8(fill_data[j]);
break;
case 2:
if (be)
put_u16be(&base[address], u16(fill_data[j]));
else
put_u16le(&base[address], u16(fill_data[j]));
break;
case 4:
if (be)
put_u32be(&base[address], u32(fill_data[j]));
else
put_u32le(&base[address], u32(fill_data[j]));
break;
case 8:
if (be)
put_u64be(&base[address], u64(fill_data[j]));
else
put_u64le(&base[address], u64(fill_data[j]));
break;
}
offset += fill_data_size[j];
if (count <= fill_data_size[j])
{
count = 0;
break;
}
else
count -= fill_data_size[j];
}
}
return true;
}
/*------------------------------------------------- /*-------------------------------------------------
execute_dasm - execute the dasm command execute_dasm - execute the dasm command

View File

@ -127,18 +127,24 @@ private:
void execute_stateload(const std::vector<std::string_view> &params); void execute_stateload(const std::vector<std::string_view> &params);
void execute_rewind(const std::vector<std::string_view> &params); void execute_rewind(const std::vector<std::string_view> &params);
void execute_save(int spacenum, const std::vector<std::string_view> &params); void execute_save(int spacenum, const std::vector<std::string_view> &params);
bool execute_save_try_memory(const std::vector<std::string_view> &params);
void execute_saveregion(const std::vector<std::string_view> &params); void execute_saveregion(const std::vector<std::string_view> &params);
void execute_load(int spacenum, const std::vector<std::string_view> &params); void execute_load(int spacenum, const std::vector<std::string_view> &params);
bool execute_load_try_memory(const std::vector<std::string_view> &params);
void execute_loadregion(const std::vector<std::string_view> &params); void execute_loadregion(const std::vector<std::string_view> &params);
void execute_dump(int spacenum, const std::vector<std::string_view> &params); void execute_dump(int spacenum, const std::vector<std::string_view> &params);
bool execute_dump_try_memory(const std::vector<std::string_view> &params);
void execute_strdump(int spacenum, const std::vector<std::string_view> &params); void execute_strdump(int spacenum, const std::vector<std::string_view> &params);
bool execute_strdump_try_memory(const std::vector<std::string_view> &params);
void execute_cheatrange(bool init, const std::vector<std::string_view> &params); void execute_cheatrange(bool init, const std::vector<std::string_view> &params);
void execute_cheatnext(bool initial, const std::vector<std::string_view> &params); void execute_cheatnext(bool initial, const std::vector<std::string_view> &params);
void execute_cheatlist(const std::vector<std::string_view> &params); void execute_cheatlist(const std::vector<std::string_view> &params);
void execute_cheatundo(const std::vector<std::string_view> &params); void execute_cheatundo(const std::vector<std::string_view> &params);
void execute_dasm(const std::vector<std::string_view> &params); void execute_dasm(const std::vector<std::string_view> &params);
void execute_find(int spacenum, const std::vector<std::string_view> &params); void execute_find(int spacenum, const std::vector<std::string_view> &params);
bool execute_find_try_memory(const std::vector<std::string_view> &params);
void execute_fill(int spacenum, const std::vector<std::string_view> &params); void execute_fill(int spacenum, const std::vector<std::string_view> &params);
bool execute_fill_try_memory(const std::vector<std::string_view> &params);
void execute_trace(const std::vector<std::string_view> &params, bool trace_over); void execute_trace(const std::vector<std::string_view> &params, bool trace_over);
void execute_traceflush(const std::vector<std::string_view> &params); void execute_traceflush(const std::vector<std::string_view> &params);
void execute_history(const std::vector<std::string_view> &params); void execute_history(const std::vector<std::string_view> &params);

View File

@ -24,6 +24,7 @@
#include <cctype> #include <cctype>
#include <fstream> #include <fstream>
#include <iterator> #include <iterator>
#include <regex>
/*************************************************************************** /***************************************************************************
@ -883,7 +884,7 @@ bool debugger_console::validate_device_space_parameter(std::string_view param, i
/// optionally followed by a colon and a device identifier. If the /// optionally followed by a colon and a device identifier. If the
/// device identifier is not presnt, the current CPU with debugger focus /// device identifier is not presnt, the current CPU with debugger focus
/// is assumed. See #validate_device_parameter for information on how /// is assumed. See #validate_device_parameter for information on how
/// device parametersare interpreted. /// device parameters are interpreted.
/// \param [in] The parameter string. /// \param [in] The parameter string.
/// \param [in] spacenum The default address space index. If negative, /// \param [in] spacenum The default address space index. If negative,
/// the first address space exposed by the device (i.e. the address /// the first address space exposed by the device (i.e. the address
@ -916,6 +917,40 @@ bool debugger_console::validate_target_address_parameter(std::string_view param,
} }
/// \brief Validate a parameter as a address with memory region or share name
///
/// Validates a parameter as a address with memory region or share tag. addres
/// parameters stays unchanged if invalid and requires additional validation on
/// the caller side.
/// \param [in] The parameter string.
/// \param [out] addr The address on success, or unchanged on failure.
/// \param [out] region The region on success, or unchanged on failure.
/// \param [out] share The share on success, or unchanged on failure.
/// \return true if the parameter refers to a memory region in the
/// current system, or false otherwise.
bool debugger_console::validate_address_with_memory_parameter(std::string_view param, u64 &addr, memory_region *&region, memory_share *&share)
{
std::string str(param);
std::regex re("^([^:]+)(:.+)\\.([ms])$");
std::smatch m;
if (std::regex_match(str, m, re))
{
if ('m' == m[3])
validate_memory_region_parameter(m.str(2), region);
else if ('s' == m[3])
validate_memory_share_parameter(m.str(2), share);
else
return false;
validate_number_parameter(m.str(1), addr);
return true;
}
return false;
}
/// \brief Validate a parameter as a memory region /// \brief Validate a parameter as a memory region
/// ///
/// Validates a parameter as a memory region tag and retrieves the /// Validates a parameter as a memory region tag and retrieves the
@ -944,6 +979,34 @@ bool debugger_console::validate_memory_region_parameter(std::string_view param,
} }
/// \brief Validate a parameter as a memory share
///
/// Validates a parameter as a memory share tag and retrieves the
/// specified memory share.
/// \param [in] The parameter string.
/// \param [out] result The memory share on success, or unchanged on
/// failure.
/// \return true if the parameter refers to a memory share in the
/// current system, or false otherwise.
bool debugger_console::validate_memory_share_parameter(std::string_view param, memory_share *&result)
{
auto const &shares = m_machine.memory().shares();
std::string_view relative = param;
device_t &base = get_device_search_base(relative);
auto const iter = shares.find(base.subtag(strmakelower(relative)));
if (shares.end() != iter)
{
result = iter->second.get();
return true;
}
else
{
printf("No matching memory share found for '%s'\n", param);
return false;
}
}
/// \brief Get search base for device or address space parameter /// \brief Get search base for device or address space parameter
/// ///
/// Handles prefix prefixes used to indicate that a device tag should be /// Handles prefix prefixes used to indicate that a device tag should be

View File

@ -130,9 +130,15 @@ public:
// validates a parameter as a target address and retrieves the given address space and address // validates a parameter as a target address and retrieves the given address space and address
bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr);
// validates a parameter as a address with memory region or share name and retrieves the given address and region or share
bool validate_address_with_memory_parameter(std::string_view param, u64 &addr, memory_region *&region, memory_share *&share);
// validates a parameter as a memory region name and retrieves the given region // validates a parameter as a memory region name and retrieves the given region
bool validate_memory_region_parameter(std::string_view param, memory_region *&result); bool validate_memory_region_parameter(std::string_view param, memory_region *&result);
// validates a parameter as a memory region name and retrieves the given share
bool validate_memory_share_parameter(std::string_view param, memory_share *&result);
// validates a parameter as a debugger expression // validates a parameter as a debugger expression
bool validate_expression_parameter(std::string_view param, parsed_expression &result); bool validate_expression_parameter(std::string_view param, parsed_expression &result);

View File

@ -94,26 +94,32 @@ const help_item f_static_help_list[] =
"\n" "\n"
" dasm <filename>,<address>,<length>[,<opcodes>[,<CPU>]] -- disassemble to the given file\n" " dasm <filename>,<address>,<length>[,<opcodes>[,<CPU>]] -- disassemble to the given file\n"
" f[ind] <address>,<length>[,<data>[,...]] -- search memory for data\n" " f[ind] <address>,<length>[,<data>[,...]] -- search memory for data\n"
" f[ind] <address>:<memory>.{m|s},<length>[,<data>[,...]] -- search memory region or share for data\n"
" f[ind]d <address>,<length>[,<data>[,...]] -- search data memory for data\n" " f[ind]d <address>,<length>[,<data>[,...]] -- search data memory for data\n"
" f[ind]i <address>,<length>[,<data>[,...]] -- search I/O memory for data\n" " f[ind]i <address>,<length>[,<data>[,...]] -- search I/O memory for data\n"
" fill <address>,<length>[,<data>[,...]] -- fill memory with data\n" " fill <address>,<length>[,<data>[,...]] -- fill memory with data\n"
" fill <address>:<memory>.{m|s},<length>[,<data>[,...]] -- fill memory region or share with data\n"
" filld <address>[:<space>],<length>[,<data>[,...]] -- fill data memory with data\n" " filld <address>[:<space>],<length>[,<data>[,...]] -- fill data memory with data\n"
" filli <address>[:<space>],<length>[,<data>[,...][ -- fill I/O memory with data\n" " filli <address>[:<space>],<length>[,<data>[,...][ -- fill I/O memory with data\n"
" fillo <address>[:<space>],<length>[,<data>[,...][ -- fill opcode memory with data\n" " fillo <address>[:<space>],<length>[,<data>[,...][ -- fill opcode memory with data\n"
" dump <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump memory as text\n" " dump <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump memory as text\n"
" dump <filename>,<address>:<memory>.{m|s},<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump memory region or share as text\n"
" dumpd <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump data memory as text\n" " dumpd <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump data memory as text\n"
" dumpi <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump I/O memory as text\n" " dumpi <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump I/O memory as text\n"
" dumpo <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump opcodes memory as text\n" " dumpo <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] -- dump opcodes memory as text\n"
" strdump <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from memory\n" " strdump <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from memory\n"
" strdump <filename>,<address>:<memory>.{m|s},<length>[,<term>] -- dump ASCII strings from memory region or share\n"
" strdumpd <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from data memory\n" " strdumpd <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from data memory\n"
" strdumpi <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from I/O memory\n" " strdumpi <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from I/O memory\n"
" strdumpo <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from opcodes memory\n" " strdumpo <filename>,<address>[:<space>],<length>[,<term>] -- dump ASCII strings from opcodes memory\n"
" save <filename>,<address>[:<space>],<length> -- save binary memory to the given file\n" " save <filename>,<address>[:<space>],<length> -- save binary memory to the given file\n"
" save <filename>,<address>:<memory>.{m|s},<length> -- load binary memory region or share to the given file\n"
" saved <filename>,<address>[:<space>],<length> -- save binary data memory to the given file\n" " saved <filename>,<address>[:<space>],<length> -- save binary data memory to the given file\n"
" savei <filename>,<address>[:<space>],<length> -- save binary I/O memory to the given file\n" " savei <filename>,<address>[:<space>],<length> -- save binary I/O memory to the given file\n"
" saveo <filename>,<address>[:<space>],<length> -- save binary opcode memory to the given file\n" " saveo <filename>,<address>[:<space>],<length> -- save binary opcode memory to the given file\n"
" saver <filename>,<address>[:<space>],<length>,<region> -- save binary memory region to the given file\n" " saver <filename>,<address>[:<space>],<length>,<region> -- save binary memory region to the given file\n"
" load <filename>,<address>[:<space>][,<length>] -- load binary memory from the given file\n" " load <filename>,<address>[:<space>][,<length>] -- load binary memory from the given file\n"
" load <filename>,<address>:<memory>.{m|s}[,<length>] -- load binary memory region or share from the given file\n"
" loadd <filename>,<address>[:<space>][,<length>] -- load binary data memory from the given file\n" " loadd <filename>,<address>[:<space>][,<length>] -- load binary data memory from the given file\n"
" loadi <filename>,<address>[:<space>][,<length>] -- load binary I/O memory from the given file\n" " loadi <filename>,<address>[:<space>][,<length>] -- load binary I/O memory from the given file\n"
" loado <filename>,<address>[:<space>][,<length>] -- load binary opcode memory from the given file\n" " loado <filename>,<address>[:<space>][,<length>] -- load binary opcode memory from the given file\n"
@ -633,6 +639,7 @@ const help_item f_static_help_list[] =
"find", "find",
"\n" "\n"
" f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]\n" " f[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]\n"
" f[ind] <address>:<memory>.{m|s},<length>[,<data>[,...]]\n"
"\n" "\n"
"The find commands search through memory for the specified sequence of data. The <address> " "The find commands search through memory for the specified sequence of data. The <address> "
"is the address to begin searching from, optionally followed by a device and/or address " "is the address to begin searching from, optionally followed by a device and/or address "
@ -674,6 +681,7 @@ const help_item f_static_help_list[] =
"fill", "fill",
"\n" "\n"
" fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]\n" " fill[{d|i|o}] <address>[:<space>],<length>[,<data>[,...]]\n"
" fill <address>:<memory>.{m|s},<length>[,<data>[,...]]\n"
"\n" "\n"
"The fill commands overwrite a block of memory with copies of the supplied data sequence. " "The fill commands overwrite a block of memory with copies of the supplied data sequence. "
"The <address> specifies the address to begin writing at, optionally followed by a device " "The <address> specifies the address to begin writing at, optionally followed by a device "
@ -700,6 +708,7 @@ const help_item f_static_help_list[] =
"dump", "dump",
"\n" "\n"
" dump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]]\n" " dump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]]\n"
" dump <filename>,<address>:<memory>.{m|s},<length>[,<group>[,<ascii>[,<rowsize>]]]\n"
"\n" "\n"
"The dump commands dump memory to the text file specified in the <filename> parameter. The " "The dump commands dump memory to the text file specified in the <filename> parameter. The "
"<address> specifies the address to start dumping from, optionally followed by a device " "<address> specifies the address to start dumping from, optionally followed by a device "
@ -739,6 +748,7 @@ const help_item f_static_help_list[] =
"strdump", "strdump",
"\n" "\n"
" strdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>]\n" " strdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>]\n"
" strdump <filename>,<address>:<memory>.{m|s},<length>[,<term>]\n"
"\n" "\n"
"The strdump commands dump memory to the text file specified in the <filename> parameter. " "The strdump commands dump memory to the text file specified in the <filename> parameter. "
"The <address> specifies the address to start dumping from, optionally followed by a device " "The <address> specifies the address to start dumping from, optionally followed by a device "
@ -761,6 +771,7 @@ const help_item f_static_help_list[] =
"save", "save",
"\n" "\n"
" save[{d|i|o}] <filename>,<address>[:<space>],<length>\n" " save[{d|i|o}] <filename>,<address>[:<space>],<length>\n"
" save <filename>,<address>:<memory>.{m|s},<length>\n"
"\n" "\n"
"The save commands save raw memory to the binary file specified in the <filename> " "The save commands save raw memory to the binary file specified in the <filename> "
"parameter. The <address> specifies the address to start saving from, optionally followed " "parameter. The <address> specifies the address to start saving from, optionally followed "
@ -798,6 +809,9 @@ const help_item f_static_help_list[] =
"saving from, and the <length> specifies how much memory to save. The range <address> " "saving from, and the <length> specifies how much memory to save. The range <address> "
"through <address>+<length>-1, inclusive, will be output to the file.\n" "through <address>+<length>-1, inclusive, will be output to the file.\n"
"\n" "\n"
"Alternetevely use 'save' syntax:\n"
" save <filename>,<address>:<region>.m,<length>\n"
"\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"saver data.bin,200,100,:monitor\n" "saver data.bin,200,100,:monitor\n"
@ -811,6 +825,7 @@ const help_item f_static_help_list[] =
"load", "load",
"\n" "\n"
" load[{d|i|o}] <filename>,<address>[:<space>][,<length>]\n" " load[{d|i|o}] <filename>,<address>[:<space>][,<length>]\n"
" load <filename>,<address>:<memory>.{m|s}[,<length>]\n"
"\n" "\n"
"The load commands load raw memory from the binary file specified in the <filename> " "The load commands load raw memory from the binary file specified in the <filename> "
"parameter. The <address> specifies the address to start loading to, optionally followed " "parameter. The <address> specifies the address to start loading to, optionally followed "
@ -857,6 +872,9 @@ const help_item f_static_help_list[] =
"is zero, or is greater than the total length of the file, the entire contents of the file " "is zero, or is greater than the total length of the file, the entire contents of the file "
"will be loaded but no more.\n" "will be loaded but no more.\n"
"\n" "\n"
"Alternetevely use 'load' syntax:\n"
" load <filename>,<address>:<region>.m[,<length>]\n"
"\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"loadr data.bin,200,100,:monitor\n" "loadr data.bin,200,100,:monitor\n"

View File

@ -319,7 +319,7 @@ std::string expression_error::code_string() const
case TOO_MANY_STRINGS: return "too many strings"; case TOO_MANY_STRINGS: return "too many strings";
case INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)"; case INVALID_MEMORY_SIZE: return "invalid memory size (b/w/d/q expected)";
case NO_SUCH_MEMORY_SPACE: return "non-existent memory space"; case NO_SUCH_MEMORY_SPACE: return "non-existent memory space";
case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m expected)"; case INVALID_MEMORY_SPACE: return "invalid memory space (p/d/i/o/r/m/s expected)";
case INVALID_MEMORY_NAME: return "invalid memory name"; case INVALID_MEMORY_NAME: return "invalid memory name";
case MISSING_MEMORY_NAME: return "missing memory name"; case MISSING_MEMORY_NAME: return "missing memory name";
default: return "unknown error"; default: return "unknown error";
@ -673,6 +673,11 @@ u64 symbol_table::memory_value(const char *name, expression_space spacenum, u32
return read_memory_region(name, address, size); return read_memory_region(name, address, size);
break; break;
case EXPSPACE_SHARE:
if (name)
return read_memory_share(name, address, size);
break;
default: default:
break; break;
} }
@ -782,6 +787,55 @@ u64 symbol_table::read_memory_region(const char *rgntag, offs_t address, int siz
} }
//-------------------------------------------------
// read_memory_share - read memory from a
// memory share
//-------------------------------------------------
u64 symbol_table::read_memory_share(const char *shatag, offs_t address, int size)
{
auto search = get_device_search(m_machine, m_memintf, shatag);
memory_share *const share = search.first.memshare(search.second);
u64 result = ~u64(0) >> (64 - 8*size);
// make sure we get a valid base before proceeding
if (share)
{
// call ourself recursively until we are byte-sized
if (size > 1)
{
int halfsize = size / 2;
u64 r0, r1;
// read each half, from lower address to upper address
r0 = read_memory_share(shatag, address + 0, halfsize);
r1 = read_memory_share(shatag, address + halfsize, halfsize);
// assemble based on the target endianness
if (share->endianness() == ENDIANNESS_LITTLE)
result = r0 | (r1 << (8 * halfsize));
else
result = r1 | (r0 << (8 * halfsize));
}
// only process if we're within range
else if (address < share->bytes())
{
// lowmask specified which address bits are within the databus width
u32 lowmask = share->bytewidth() - 1;
u8 *base = reinterpret_cast<u8 *>(share->ptr()) + (address & ~lowmask);
// if we have a valid base, return the appropriate byte
if (share->endianness() == ENDIANNESS_LITTLE)
result = base[BYTE8_XOR_LE(address) & lowmask];
else
result = base[BYTE8_XOR_BE(address) & lowmask];
}
}
return result;
}
//------------------------------------------------- //-------------------------------------------------
// set_memory_value - write 1,2,4 or 8 bytes at // set_memory_value - write 1,2,4 or 8 bytes at
// the given offset in the given address space // the given offset in the given address space
@ -831,6 +885,11 @@ void symbol_table::set_memory_value(const char *name, expression_space spacenum,
write_memory_region(name, address, size, data); write_memory_region(name, address, size, data);
break; break;
case EXPSPACE_SHARE:
if (name)
write_memory_share(name, address, size, data);
break;
default: default:
break; break;
} }
@ -953,6 +1012,65 @@ void symbol_table::write_memory_region(const char *rgntag, offs_t address, int s
} }
//-------------------------------------------------
// write_memory_share - write memory to a
// memory share
//-------------------------------------------------
void symbol_table::write_memory_share(const char *shatag, offs_t address, int size, u64 data)
{
auto search = get_device_search(m_machine, m_memintf, shatag);
memory_share *const share = search.first.memshare(search.second);
// make sure we get a valid base before proceeding
if (share)
{
// call ourself recursively until we are byte-sized
if (size > 1)
{
int halfsize = size / 2;
// break apart based on the target endianness
u64 halfmask = ~u64(0) >> (64 - 8 * halfsize);
u64 r0, r1;
if (share->endianness() == ENDIANNESS_LITTLE)
{
r0 = data & halfmask;
r1 = (data >> (8 * halfsize)) & halfmask;
}
else
{
r0 = (data >> (8 * halfsize)) & halfmask;
r1 = data & halfmask;
}
// write each half, from lower address to upper address
write_memory_share(shatag, address + 0, halfsize, r0);
write_memory_share(shatag, address + halfsize, halfsize, r1);
}
// only process if we're within range
else if (address < share->bytes())
{
// lowmask specified which address bits are within the databus width
u32 lowmask = share->bytewidth() - 1;
u8 *base = reinterpret_cast<u8 *>(share->ptr()) + (address & ~lowmask);
// if we have a valid base, set the appropriate byte
if (share->endianness() == ENDIANNESS_LITTLE)
{
base[BYTE8_XOR_LE(address) & lowmask] = data;
}
else
{
base[BYTE8_XOR_BE(address) & lowmask] = data;
}
notify_memory_modified();
}
}
}
//------------------------------------------------- //-------------------------------------------------
// memory_valid - return true if the given // memory_valid - return true if the given
// memory name/space/offset combination is valid // memory name/space/offset combination is valid
@ -998,6 +1116,20 @@ expression_error::error_code symbol_table::memory_valid(const char *name, expres
} }
break; break;
case EXPSPACE_SHARE:
if (!name)
{
return expression_error::MISSING_MEMORY_NAME;
}
else
{
auto search = get_device_search(m_machine, m_memintf, name);
memory_share *const share = search.first.memshare(search.second);
if (!share || !share->ptr())
return expression_error::INVALID_MEMORY_NAME;
}
break;
default: default:
return expression_error::NO_SUCH_MEMORY_SPACE; return expression_error::NO_SUCH_MEMORY_SPACE;
} }
@ -1618,6 +1750,7 @@ void parsed_expression::parse_memory_operator(parse_token &token, const char *st
case 'r': memspace = EXPSPACE_PRGDIRECT; break; case 'r': memspace = EXPSPACE_PRGDIRECT; break;
case 'o': memspace = EXPSPACE_OPDIRECT; break; case 'o': memspace = EXPSPACE_OPDIRECT; break;
case 'm': memspace = EXPSPACE_REGION; break; case 'm': memspace = EXPSPACE_REGION; break;
case 's': memspace = EXPSPACE_SHARE; break;
default: throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring)); default: throw expression_error(expression_error::INVALID_MEMORY_SPACE, token.offset() + (string - startstring));
} }

View File

@ -41,7 +41,8 @@ enum expression_space
EXPSPACE_OPCODE_PHYSICAL, EXPSPACE_OPCODE_PHYSICAL,
EXPSPACE_PRGDIRECT, EXPSPACE_PRGDIRECT,
EXPSPACE_OPDIRECT, EXPSPACE_OPDIRECT,
EXPSPACE_REGION EXPSPACE_REGION,
EXPSPACE_SHARE
}; };
@ -215,8 +216,10 @@ private:
// memory helpers // memory helpers
u64 read_program_direct(address_space &space, int opcode, offs_t address, int size); u64 read_program_direct(address_space &space, int opcode, offs_t address, int size);
u64 read_memory_region(const char *rgntag, offs_t address, int size); u64 read_memory_region(const char *rgntag, offs_t address, int size);
u64 read_memory_share(const char *shatag, offs_t address, int size);
void write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data); void write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data);
void write_memory_region(const char *rgntag, offs_t address, int size, u64 data); void write_memory_region(const char *rgntag, offs_t address, int size, u64 data);
void write_memory_share(const char *shatag, offs_t address, int size, u64 data);
expression_error expression_get_space(const char *tag, int &spacenum, device_memory_interface *&memory); expression_error expression_get_space(const char *tag, int &spacenum, device_memory_interface *&memory);
void notify_memory_modified(); void notify_memory_modified();

View File

@ -515,7 +515,7 @@ void atm_state::atm(machine_config &config)
output_latch_device &cent_data_out(OUTPUT_LATCH(config, "cent_data_out")); output_latch_device &cent_data_out(OUTPUT_LATCH(config, "cent_data_out"));
m_centronics->set_output_latch(cent_data_out); m_centronics->set_output_latch(cent_data_out);
config.device_remove("exp"); //config.device_remove("exp");
} }
@ -587,6 +587,12 @@ ROM_START( atmtb2plus )
ROM_SYSTEM_BIOS(3, "v1.37", "Dual eXtra v1.37XT: BIOS v1.07.15, CP/M v2.2, TR-DOS v5.04R") ROM_SYSTEM_BIOS(3, "v1.37", "Dual eXtra v1.37XT: BIOS v1.07.15, CP/M v2.2, TR-DOS v5.04R")
ROMX_LOAD( "atmtb2x37xt.rom", 0x010000, 0x20000, CRC(e5ef44d9) SHA1(3fbb9ace7cb031e7365c19e4f8b67ed366e24064), ROM_BIOS(3)) ROMX_LOAD( "atmtb2x37xt.rom", 0x010000, 0x20000, CRC(e5ef44d9) SHA1(3fbb9ace7cb031e7365c19e4f8b67ed366e24064), ROM_BIOS(3))
ROM_SYSTEM_BIOS(4, "gluk", "Gluk")
ROMX_LOAD( "glukatm.rom", 0x020000, 0x10000, CRC(7a017f0d) SHA1(301d9195ecaeeba31b7a7d6b7c4037b8cc72a240), ROM_BIOS(4))
ROM_SYSTEM_BIOS(5, "gluk2", "Gluk2")
ROMX_LOAD( "glukatm2.rom", 0x020000, 0x10000, CRC(64cfee77) SHA1(cd180493e6c3ae4b0a0f753f0efff2debd43a329), ROM_BIOS(5))
ROM_REGION(0x01000, "keyboard", ROMREGION_ERASEFF) ROM_REGION(0x01000, "keyboard", ROMREGION_ERASEFF)
ROM_LOAD( "rf2ve3.rom", 0x0000, 0x0580, CRC(35e0f9ec) SHA1(adcf14758fab8472cfa0167af7e8326c66416416)) // XT Keyboard ROM_LOAD( "rf2ve3.rom", 0x0000, 0x0580, CRC(35e0f9ec) SHA1(adcf14758fab8472cfa0167af7e8326c66416416)) // XT Keyboard
ROM_LOAD( "rfat710.rom", 0x0600, 0x0680, CRC(03734365) SHA1(6cb6311727fad9bc4ccb18919c3c39b37529b8e6)) // AT Keyboard ROM_LOAD( "rfat710.rom", 0x0600, 0x0680, CRC(03734365) SHA1(6cb6311727fad9bc4ccb18919c3c39b37529b8e6)) // AT Keyboard

View File

@ -20,6 +20,26 @@ BUGS:
#include "formats/trd_dsk.h" #include "formats/trd_dsk.h"
namespace {
void floppy_formats(format_registration &fr)
{
fr.add_mfm_containers();
fr.add_pc_formats();
fr.add(FLOPPY_TRD_FORMAT);
}
void beta_disk_floppies(device_slot_interface &device)
{
device.option_add("525hd", FLOPPY_525_HD);
device.option_add("525qd", FLOPPY_525_QD);
device.option_add("35hd", FLOPPY_35_HD);
device.option_add("35dd", FLOPPY_35_DD);
}
} // anonymous namespace
/*************************************************************************** /***************************************************************************
TYPE DEFINITIONS TYPE DEFINITIONS
***************************************************************************/ ***************************************************************************/
@ -205,21 +225,6 @@ void beta_disk_device::motors_control()
} }
} }
void beta_disk_device::floppy_formats(format_registration &fr)
{
fr.add_mfm_containers();
fr.add_pc_formats();
fr.add(FLOPPY_TRD_FORMAT);
}
static void beta_disk_floppies(device_slot_interface &device)
{
device.option_add("525hd", FLOPPY_525_HD);
device.option_add("525qd", FLOPPY_525_QD);
device.option_add("35hd", FLOPPY_35_HD);
device.option_add("35dd", FLOPPY_35_DD);
}
ROM_START( beta_disk ) ROM_START( beta_disk )
ROM_REGION( 0x60000, "beta", 0 ) ROM_REGION( 0x60000, "beta", 0 )
@ -312,7 +317,7 @@ void beta_disk_device::device_add_mconfig(machine_config &config)
KR1818VG93(config, m_wd179x, 8_MHz_XTAL / 8); KR1818VG93(config, m_wd179x, 8_MHz_XTAL / 8);
m_wd179x->hld_wr_callback().set(FUNC(beta_disk_device::fdc_hld_w)); m_wd179x->hld_wr_callback().set(FUNC(beta_disk_device::fdc_hld_w));
for (auto &floppy : m_floppy) for (auto &floppy : m_floppy)
FLOPPY_CONNECTOR(config, floppy, beta_disk_floppies, "525qd", beta_disk_device::floppy_formats).enable_sound(true); FLOPPY_CONNECTOR(config, floppy, beta_disk_floppies, "525qd", floppy_formats).enable_sound(true);
} }
//------------------------------------------------- //-------------------------------------------------

View File

@ -59,8 +59,6 @@ private:
void motors_control(); void motors_control();
u8 m_control; u8 m_control;
bool m_motor_active; bool m_motor_active;
static void floppy_formats(format_registration &fr);
}; };
DECLARE_DEVICE_TYPE(BETA_DISK, beta_disk_device) DECLARE_DEVICE_TYPE(BETA_DISK, beta_disk_device)

View File

@ -958,11 +958,18 @@ void chloe_state::chloe(machine_config &config)
ROM_START(chloe) ROM_START(chloe)
ROM_REGION(0xc000, "maincpu", ROMREGION_ERASEFF) ROM_REGION(0xc000, "maincpu", ROMREGION_ERASEFF)
ROM_DEFAULT_BIOS("v101b")
// SE/OS 1.0 ROM_SYSTEM_BIOS(0, "v10", "System 1.0") // 05.01.2024 - SE/OS 1.0
ROM_LOAD( "10_boot.rom", 0x0000, 0x4000, CRC(efbfe46e) SHA1(f5a86b56955661f72fa416e7e644de0b3afe6509)) ROMX_LOAD( "10_boot.rom", 0x0000, 0x4000, CRC(efbfe46e) SHA1(f5a86b56955661f72fa416e7e644de0b3afe6509), ROM_BIOS(0))
ROM_LOAD( "10_basic_42.rom", 0x4000, 0x4000, CRC(c6273eaa) SHA1(f09a26c50f5cfe454e4d56c920cdcc62bc4f90cb)) ROMX_LOAD( "10_basic_42.rom", 0x4000, 0x4000, CRC(c6273eaa) SHA1(f09a26c50f5cfe454e4d56c920cdcc62bc4f90cb), ROM_BIOS(0))
ROM_LOAD( "10_dos_31.rom", 0x8000, 0x2000, CRC(67dfef09) SHA1(ba9616494071dfe65834d7db657e0d3bcce0b732)) ROMX_LOAD( "10_dos_31.rom", 0x8000, 0x2000, CRC(67dfef09) SHA1(ba9616494071dfe65834d7db657e0d3bcce0b732), ROM_BIOS(0))
// SE/OS 1.1
ROM_SYSTEM_BIOS(1, "v101b", "System 1.0.1b") // 05.xx.2024 - SE/OS 1.0.1b
ROMX_LOAD( "101_boot.rom", 0x0000, 0x4000, CRC(26c57f5a) SHA1(6680aaeac288c688f0400080faf07214959d5a1c), ROM_BIOS(1))
ROMX_LOAD( "101_basic_42.rom", 0x4000, 0x4000, CRC(0f8658ba) SHA1(b6975e66c029165a39a1ee85ebec50c8e7f4ec1e), ROM_BIOS(1))
ROMX_LOAD( "10_dos_31.rom", 0x8000, 0x2000, CRC(67dfef09) SHA1(ba9616494071dfe65834d7db657e0d3bcce0b732), ROM_BIOS(1))
ROM_END ROM_END
} // Anonymous namespace } // Anonymous namespace

View File

@ -151,7 +151,7 @@ void pentevo_state::atm_update_io()
{ {
if (BIT(m_port_bf_data, 0) || is_dos_active()) if (BIT(m_port_bf_data, 0) || is_dos_active())
{ {
m_io_view.select(0); m_io_view.select(1);
if (m_beta_drive_selected && m_beta_drive_virtual == m_beta_drive_selected) if (m_beta_drive_selected && m_beta_drive_virtual == m_beta_drive_selected)
m_io_dos_view.disable(); m_io_dos_view.disable();
else else
@ -161,7 +161,7 @@ void pentevo_state::atm_update_io()
} }
else else
{ {
m_io_view.disable(); m_io_view.select(0);
if (BIT(m_port_eff7_data, 7)) if (BIT(m_port_eff7_data, 7))
m_glukrs->enable(); m_glukrs->enable();
else else
@ -607,28 +607,32 @@ void pentevo_state::pentevo_io(address_map &map)
map(0xffdf, 0xffdf).lr8(NAME([this]() -> u8 { return ~m_io_mouse[1]->read(); })); map(0xffdf, 0xffdf).lr8(NAME([this]() -> u8 { return ~m_io_mouse[1]->read(); }));
map(0x001f, 0x001f).mirror(0xff00).lr8(NAME([]() -> u8 { return 0x00; })); // TODO Kepmston Joystick map(0x001f, 0x001f).mirror(0xff00).lr8(NAME([]() -> u8 { return 0x00; })); // TODO Kepmston Joystick
// PORTS: Shadow
map(0x0000, 0xffff).view(m_io_view); map(0x0000, 0xffff).view(m_io_view);
m_io_view[0](0x0000, 0xffff).view(m_io_dos_view); m_io_view[0];
// PORTS: Shadow
m_io_view[1](0x0000, 0xffff).view(m_io_dos_view);
m_io_dos_view[0](0x001f, 0x001f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)); m_io_dos_view[0](0x001f, 0x001f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w));
m_io_dos_view[0](0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); m_io_dos_view[0](0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w));
m_io_dos_view[0](0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); m_io_dos_view[0](0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w));
m_io_dos_view[0](0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); m_io_dos_view[0](0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w));
m_io_dos_view[0](0x00ff, 0x00ff).select(0xff00).r(m_beta, FUNC(beta_disk_device::state_r)); m_io_dos_view[0](0x00ff, 0x00ff).select(0xff00).r(m_beta, FUNC(beta_disk_device::state_r));
m_io_view[0](0x00ff, 0x00ff).select(0xff00).w(FUNC(pentevo_state::atm_port_ff_w)); m_io_view[1](0x00ff, 0x00ff).select(0xff00).w(FUNC(pentevo_state::atm_port_ff_w));
m_io_view[0](0x0077, 0x0077).select(0xff00).lr8(NAME([]() { return 0xff; })).w(FUNC(pentevo_state::atm_port_77_w)); m_io_view[1](0x0077, 0x0077).select(0xff00).lr8(NAME([]() { return 0xff; })).w(FUNC(pentevo_state::atm_port_77_w));
m_io_view[0](0x3ff7, 0x3ff7).select(0xc000).w(FUNC(pentevo_state::atm_port_f7_w)); // ATM m_io_view[1](0x3ff7, 0x3ff7).select(0xc000).w(FUNC(pentevo_state::atm_port_f7_w)); // ATM
m_io_view[0](0x37f7, 0x37f7).select(0xc000).w(FUNC(pentevo_state::pentevo_port_7f7_w)); // PENTEVO m_io_view[1](0x37f7, 0x37f7).select(0xc000).w(FUNC(pentevo_state::pentevo_port_7f7_w)); // PENTEVO
m_io_view[0](0x3bf7, 0x3bf7).select(0xc000).w(FUNC(pentevo_state::pentevo_port_bf7_w)); // RO m_io_view[1](0x3bf7, 0x3bf7).select(0xc000).w(FUNC(pentevo_state::pentevo_port_bf7_w)); // RO
// SPI // SPI
m_io_view[0](0x0057, 0x0057).select(0xff00) m_io_view[1](0x0057, 0x0057).select(0xff00)
.lw8(NAME([this](offs_t offset, u8 data) { if (BIT(offset, 15)) spi_port_77_w(offset, data); else spi_port_57_w(offset, data); })); .lw8(NAME([this](offs_t offset, u8 data) { if (BIT(offset, 15)) spi_port_77_w(offset, data); else spi_port_57_w(offset, data); }));
// Gluk // Gluk
m_io_view[0](0xdef7, 0xdef7).lw8(NAME([this](offs_t offset, u8 data) { m_glukrs->address_w(data); } )); m_io_view[1](0xdef7, 0xdef7).lw8(NAME([this](offs_t offset, u8 data) { m_glukrs->address_w(data); } ));
m_io_view[0](0xbef7, 0xbef7).rw(FUNC(pentevo_state::gluk_data_r), FUNC(pentevo_state::gluk_data_w)); m_io_view[1](0xbef7, 0xbef7).rw(FUNC(pentevo_state::gluk_data_r), FUNC(pentevo_state::gluk_data_w));
subdevice<zxbus_device>("zxbus")->set_io_space(m_io_view[0], m_io_view[1]);
} }
void pentevo_state::init_mem_write() void pentevo_state::init_mem_write()
@ -756,8 +760,7 @@ void pentevo_state::pentevo(machine_config &config)
AT_KEYB(config, m_keyboard, pc_keyboard_device::KEYBOARD_TYPE::AT, 3); AT_KEYB(config, m_keyboard, pc_keyboard_device::KEYBOARD_TYPE::AT, 3);
zxbus_device &zxbus(ZXBUS(config, "zxbus", 0)); zxbus_device &zxbus(ZXBUS(config, "zxbus", 0));
zxbus.set_iospace("maincpu", AS_IO); ZXBUS_SLOT(config, "zxbus1", 0, zxbus, zxbus_cards, nullptr);
ZXBUS_SLOT(config, "zxbus1", 0, "zxbus", zxbus_cards, nullptr);
} }

View File

@ -238,10 +238,7 @@ void scorpion_state::update_io(bool dos_enable)
scorpion_update_memory(); scorpion_update_memory();
if (dos()) m_io_shadow_view.select(dos() ? 1 : 0);
m_io_shadow_view.select(0);
else
m_io_shadow_view.disable();
} }
u8 scorpion_state::port_ff_r() u8 scorpion_state::port_ff_r()
@ -324,10 +321,7 @@ void scorpion_state::scorpion_mem(address_map &map)
void scorpion_state::scorpion_io(address_map &map) void scorpion_state::scorpion_io(address_map &map)
{ {
map.unmap_value_high(); map.unmap_value_high();
map(0x0022, 0x0022).select(0xffdc) // FE | xxxxxxxxxx1xxx10
.rw(FUNC(scorpion_state::spectrum_ula_r), FUNC(scorpion_state::spectrum_ula_w));
map(0x0023, 0x0023).mirror(0xffdc) // FF | xxxxxxxxxx1xxx11
.r(FUNC(scorpion_state::port_ff_r));
map(0x0021, 0x0021).mirror(0x3fdc) // 1FFD | 00xxxxxxxx1xxx01 map(0x0021, 0x0021).mirror(0x3fdc) // 1FFD | 00xxxxxxxx1xxx01
.w(FUNC(scorpion_state::port_1ffd_w)); .w(FUNC(scorpion_state::port_1ffd_w));
map(0x4021, 0x4021).mirror(0x3fdc) // 7FFD | 01xxxxxxxx1xxx01 map(0x4021, 0x4021).mirror(0x3fdc) // 7FFD | 01xxxxxxxx1xxx01
@ -338,23 +332,28 @@ void scorpion_state::scorpion_io(address_map &map)
map(0xe021, 0xe021).mirror(0x1fdc) // FFFD | 111xxxxxxx1xxx01 map(0xe021, 0xe021).mirror(0x1fdc) // FFFD | 111xxxxxxx1xxx01
.rw(m_ay_slot, FUNC(ay_slot_device::data_r), FUNC(ay_slot_device::address_w)); .rw(m_ay_slot, FUNC(ay_slot_device::data_r), FUNC(ay_slot_device::address_w));
// Mouse map(0x0000, 0xffff).view(m_io_shadow_view);
map(0xfadf, 0xfadf).lr8(NAME([this]() -> u8 { return 0x80 | (m_io_mouse[2]->read() & 0x07); }));
map(0xfbdf, 0xfbdf).lr8(NAME([this]() -> u8 { return m_io_mouse[0]->read(); })); // !Shadow
map(0xffdf, 0xffdf).lr8(NAME([this]() -> u8 { return ~m_io_mouse[1]->read(); })); m_io_shadow_view[0](0x0022, 0x0022).select(0xffdc) // FE | xxxxxxxxxx1xxx10
map(0x0003, 0x0003) // 1F | xxxxxxxx0x0xxx11 .rw(FUNC(scorpion_state::spectrum_ula_r), FUNC(scorpion_state::spectrum_ula_w));
m_io_shadow_view[0](0x0023, 0x0023).mirror(0xffdc) // FF | xxxxxxxxxx1xxx11
.r(FUNC(scorpion_state::port_ff_r));
m_io_shadow_view[0](0xfadf, 0xfadf).lr8(NAME([this]() -> u8 { return 0x80 | (m_io_mouse[2]->read() & 0x07); }));
m_io_shadow_view[0](0xfbdf, 0xfbdf).lr8(NAME([this]() -> u8 { return m_io_mouse[0]->read(); }));
m_io_shadow_view[0](0xffdf, 0xffdf).lr8(NAME([this]() -> u8 { return ~m_io_mouse[1]->read(); }));
m_io_shadow_view[0](0x0003, 0x0003) // 1F | xxxxxxxx0x0xxx11
.select(0xff5c).lr8(NAME([this]() -> u8 { return (m_beta->state_r() & 0xc0) | 0x00; })); // TODO Kepmston Joystick .select(0xff5c).lr8(NAME([this]() -> u8 { return (m_beta->state_r() & 0xc0) | 0x00; })); // TODO Kepmston Joystick
// Shadow // Shadow
// DOS + xxxxxxxx0nnxxx11 // DOS + xxxxxxxx0nnxxx11
map(0x0000, 0xffff).view(m_io_shadow_view); m_io_shadow_view[1](0x0003, 0x0003).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w));
m_io_shadow_view[0](0x0003, 0x0003).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)); m_io_shadow_view[1](0x0023, 0x0023).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w));
m_io_shadow_view[0](0x0023, 0x0023).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); m_io_shadow_view[1](0x0043, 0x0043).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w));
m_io_shadow_view[0](0x0043, 0x0043).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); m_io_shadow_view[1](0x0063, 0x0063).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w));
m_io_shadow_view[0](0x0063, 0x0063).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); m_io_shadow_view[1](0x00e3, 0x00e3).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w));
m_io_shadow_view[0](0x00e3, 0x00e3).mirror(0xff1c).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w));
subdevice<zxbus_device>("zxbus")->install_shadow_io(m_io_shadow_view[0]); subdevice<zxbus_device>("zxbus")->set_io_space(m_io_shadow_view[0], m_io_shadow_view[1]);
} }
void scorpion_state::scorpion_switch(address_map &map) void scorpion_state::scorpion_switch(address_map &map)
@ -502,9 +501,8 @@ void scorpion_state::scorpion(machine_config &config)
config.device_remove("exp"); config.device_remove("exp");
zxbus_device &zxbus(ZXBUS(config, "zxbus", 0)); zxbus_device &zxbus(ZXBUS(config, "zxbus", 0));
zxbus.set_iospace("maincpu", AS_IO); ZXBUS_SLOT(config, "zxbus:1", 0, zxbus, zxbus_gmx_cards, nullptr);
ZXBUS_SLOT(config, "zxbus:1", 0, "zxbus", zxbus_gmx_cards, nullptr); ZXBUS_SLOT(config, "zxbus:2", 0, zxbus, zxbus_gmx_cards, nullptr);
ZXBUS_SLOT(config, "zxbus:2", 0, "zxbus", zxbus_gmx_cards, nullptr);
} }
void scorpion_state::profi(machine_config &config) void scorpion_state::profi(machine_config &config)

View File

@ -238,6 +238,13 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data)
m_exp->iorq_w(offset | 1, data); m_exp->iorq_w(offset | 1, data);
} }
void spectrum_128_state::bank3_set_page(u8 page)
{
m_port_7ffd_data &= 0xf8;
m_port_7ffd_data |= page & 0x07;
spectrum_128_update_memory();
}
void spectrum_128_state::spectrum_128_update_memory() void spectrum_128_state::spectrum_128_update_memory()
{ {
m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4)); m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4));
@ -344,6 +351,15 @@ INPUT_PORTS_END
INPUT_PORTS_START( spec_plus ) INPUT_PORTS_START( spec_plus )
PORT_INCLUDE( spec128 ) PORT_INCLUDE( spec128 )
PORT_INCLUDE( spec_plus_joys ) PORT_INCLUDE( spec_plus_joys )
PORT_START("MOD_DMA")
PORT_CONFNAME( 0x03, 0x00, "DMA")
PORT_CONFSETTING( 0x00, DEF_STR( No ))
PORT_CONFSETTING( 0x01, "UA858D")
PORT_CONFSETTING( 0x03, "Zilog")
PORT_CONFNAME( 0x04, 0x00, "DMA Port") PORT_CONDITION("MOD_DMA", 0x01, EQUALS, 0x01)
PORT_CONFSETTING( 0x00, "11: MB02+")
PORT_CONFSETTING( 0x04, "107: DATAGEAR")
INPUT_PORTS_END INPUT_PORTS_END
void spectrum_128_state::machine_start() void spectrum_128_state::machine_start()
@ -374,6 +390,15 @@ void spectrum_128_state::machine_reset()
// set initial ram config // set initial ram config
m_port_7ffd_data = 0; m_port_7ffd_data = 0;
spectrum_128_update_memory(); spectrum_128_update_memory();
const u8 mod_dma = m_mod_dma.read_safe(0);
if (mod_dma & 1)
{
m_dma->set_dma_mode(mod_dma & 2 ? z80dma_device::dma_mode::ZILOG : z80dma_device::dma_mode::UA858D);
const u8 port = mod_dma & 4 ? 0x6b : 0x0b;
m_maincpu->space(AS_IO).install_readwrite_handler(port, port, 0, 0xff00, 0, read8smo_delegate(*m_dma, FUNC(z80dma_device::read)), write8smo_delegate(*m_dma, FUNC(z80dma_device::write)));
}
} }
bool spectrum_128_state::is_vram_write(offs_t offset) { bool spectrum_128_state::is_vram_write(offs_t offset) {
@ -419,9 +444,18 @@ void spectrum_128_state::spectrum_128(machine_config &config)
m_maincpu->set_m1_map(&spectrum_128_state::spectrum_128_fetch); m_maincpu->set_m1_map(&spectrum_128_state::spectrum_128_fetch);
m_maincpu->set_vblank_int("screen", FUNC(spectrum_128_state::spec_interrupt)); m_maincpu->set_vblank_int("screen", FUNC(spectrum_128_state::spec_interrupt));
m_maincpu->nomreq_cb().set(FUNC(spectrum_128_state::spectrum_nomreq)); m_maincpu->nomreq_cb().set(FUNC(spectrum_128_state::spectrum_nomreq));
m_maincpu->busack_cb().set(m_dma, FUNC(z80dma_device::bai_w));
config.set_maximum_quantum(attotime::from_hz(60)); config.set_maximum_quantum(attotime::from_hz(60));
Z80DMA(config, m_dma, X1_128_SINCLAIR / 10);
m_dma->out_busreq_callback().set_inputline(m_maincpu, Z80_INPUT_LINE_BUSRQ);
m_dma->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_dma->in_mreq_callback().set([this](offs_t offset) { return m_program.read_byte(offset); });
m_dma->out_mreq_callback().set([this](offs_t offset, u8 data) { m_program.write_byte(offset, data); });
m_dma->in_iorq_callback().set([this](offs_t offset) { return m_io.read_byte(offset); });
m_dma->out_iorq_callback().set([this](offs_t offset, u8 data) { m_io.write_byte(offset, data); });
// video hardware // video hardware
rectangle visarea = { get_screen_area().left() - SPEC_LEFT_BORDER, get_screen_area().right() + SPEC_RIGHT_BORDER, rectangle visarea = { get_screen_area().left() - SPEC_LEFT_BORDER, get_screen_area().right() + SPEC_RIGHT_BORDER,
get_screen_area().top() - SPEC_TOP_BORDER, get_screen_area().bottom() + SPEC_BOTTOM_BORDER }; get_screen_area().top() - SPEC_TOP_BORDER, get_screen_area().bottom() + SPEC_BOTTOM_BORDER };

View File

@ -13,14 +13,18 @@
#include "spectrum.h" #include "spectrum.h"
#include "machine/z80dma.h"
class spectrum_128_state : public spectrum_state class spectrum_128_state : public spectrum_state
{ {
public: public:
spectrum_128_state(const machine_config &mconfig, device_type type, const char *tag) : spectrum_128_state(const machine_config &mconfig, device_type type, const char *tag) :
spectrum_state(mconfig, type, tag), spectrum_state(mconfig, type, tag)
m_bank_rom(*this, "bank_rom%u", 0U), , m_bank_rom(*this, "bank_rom%u", 0U)
m_bank_ram(*this, "bank_ram%u", 0U) , m_bank_ram(*this, "bank_ram%u", 0U)
, m_dma(*this, "dma_ext")
, m_mod_dma(*this, "MOD_DMA")
{ } { }
void spectrum_128(machine_config &config); void spectrum_128(machine_config &config);
@ -35,6 +39,7 @@ protected:
virtual void machine_start() override ATTR_COLD; virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD; virtual void machine_reset() override ATTR_COLD;
virtual void bank3_set_page(u8 page) override;
virtual void spectrum_128_update_memory() override; virtual void spectrum_128_update_memory() override;
virtual rectangle get_screen_area() override; virtual rectangle get_screen_area() override;
@ -57,6 +62,10 @@ private:
void spectrum_128_io(address_map &map) ATTR_COLD; void spectrum_128_io(address_map &map) ATTR_COLD;
void spectrum_128_mem(address_map &map) ATTR_COLD; void spectrum_128_mem(address_map &map) ATTR_COLD;
void spectrum_128_fetch(address_map &map) ATTR_COLD; void spectrum_128_fetch(address_map &map) ATTR_COLD;
optional_device<z80dma_device> m_dma;
optional_ioport m_mod_dma;
}; };
#define X1_128_AMSTRAD 35'469'000 // Main clock (Amstrad 128K model, +2A?) #define X1_128_AMSTRAD 35'469'000 // Main clock (Amstrad 128K model, +2A?)

View File

@ -206,6 +206,15 @@ SNAPSHOT_LOAD_MEMBER(spectrum_state::snapshot_cb)
setup_frz(&snapshot_data[0], snapshot_size); setup_frz(&snapshot_data[0], snapshot_size);
} }
else if (image.is_filetype("spg"))
{
if (snapshot_data[32] != 'S' || snapshot_data[33] != 'p' || snapshot_data[34] != 'e' || snapshot_data[35] != 'c'
|| snapshot_data[36] != 't' || snapshot_data[37] != 'r' || snapshot_data[38] != 'u' || snapshot_data[39] != 'm'
|| snapshot_data[40] != 'P' || snapshot_data[41] != 'r' ||snapshot_data[42] != 'o' || snapshot_data[43] != 'g')
return std::make_pair(image_error::INVALIDIMAGE, "Invalid .SPG file header.");
setup_spg(&snapshot_data[0], snapshot_size);
}
else else
{ {
setup_z80(&snapshot_data[0], snapshot_size); setup_z80(&snapshot_data[0], snapshot_size);
@ -2396,6 +2405,449 @@ void spectrum_state::setup_z80(const uint8_t *snapdata, uint32_t snapsize)
} }
} }
void spectrum_state::hrust_decompress_block(address_space &space, const u8 *source, u16 dest, u16 size)
{
class bb_stream
{
private:
const u8 *m_base;
const u8 *m_read;
int m_offset;
int m_length;
bool m_eof;
u16 m_buffer;
public:
bb_stream(const u8 *src, int src_length)
{
m_base = m_read = src;
m_length = src_length;
m_offset = 0;
m_eof = false;
m_buffer = get_byte();
m_buffer += get_byte() << 8;
}
u8 get_byte()
{
m_eof |= ((m_read - m_base) == m_length);
return m_eof ? 0 : *m_read++;
}
u8 get_bit()
{
u8 bit = BIT(m_buffer, 15 - m_offset);
if (m_offset == 15)
{
m_buffer = get_byte();
m_buffer += get_byte() << 8;
}
m_offset = (m_offset + 1) & 0xf;
return bit;
}
u8 get_bits(u8 n)
{
u8 r = 0;
do
{
r = (r << 1) + get_bit();
} while (--n);
return r;
}
bool overflow() { return m_eof; }
};
constexpr u8 mask[] = { 0, 0, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0 };
u8 no_bits = 2;
bb_stream bitbuf(source, size);
space.write_byte(dest++, bitbuf.get_byte());
while (!bitbuf.overflow())
{
while (bitbuf.get_bit())
{
space.write_byte(dest++, bitbuf.get_byte());
}
u16 len = 0;
u8 bb;
do
{
bb = bitbuf.get_bits(2);
len += bb;
} while (bb == 0x03 && len != 0x0f);
s16 offset = 0;
if (len == 0)
{
offset = 0xfff8 + bitbuf.get_bits(3);
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
continue;
}
else if (len == 1)
{
const u8 code = bitbuf.get_bits(2);
if (code == 0 || code == 1)
{
offset = bitbuf.get_byte();
offset += (code ? 0xfe : 0xfd) << 8;
}
else if (code == 2)
{
u8 b = bitbuf.get_byte();
if (b >= 0xe0)
{
b <<= 1;
++b; // rlca
b ^= 2; // xor c
if (b == 0xff)
{
++no_bits;
continue;
}
offset = 0xff00 + b - 0x0f;
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
space.write_byte(dest++, bitbuf.get_byte());
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
continue;
}
offset = 0xff00 + b;
}
else if (code == 3)
{
offset = 0xffe0 + bitbuf.get_bits(5);
}
for (auto i = 0; i < 2; ++i)
{
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
}
continue;
}
else if (len == 3)
{
if (bitbuf.get_bit())
{
offset = 0xfff0 + bitbuf.get_bits(4);
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
space.write_byte(dest++, bitbuf.get_byte());
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
continue;
}
if (bitbuf.get_bit())
{
u8 bytes_no = 6 + bitbuf.get_bits(4);
for (u8 i = 0; i < (bytes_no << 1); ++i)
space.write_byte(dest++, bitbuf.get_byte());
continue;
}
len = bitbuf.get_bits(7);
if (len == 0x0f)
{
break; // EOF
}
if (len < 0x0f)
{
len = (len << 8) + bitbuf.get_byte();
}
}
if (len == 2)
{
++len;
}
const u8 code = bitbuf.get_bits(2);
if (code == 0)
{
offset = 0xfe00 + bitbuf.get_byte();
}
else if (code == 1)
{
u8 b = bitbuf.get_byte();
if (b >= 0xe0)
{
if (len > 3)
{
// logerror
break;
}
b <<= 1;
++b; // rlca
b ^= 3; // xor c
offset = 0xff00 + b - 0x0f;
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
space.write_byte(dest++, bitbuf.get_byte());
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
continue;
}
offset = 0xff00 + b;
}
else if (code == 2)
{
offset = 0xffe0 + bitbuf.get_bits(5);
}
else if (code == 3)
{
offset = (mask[no_bits] + bitbuf.get_bits(no_bits)) << 8;
offset += bitbuf.get_byte();
}
for (u16 i = 0; i < len; ++i)
{
space.write_byte(dest, space.read_byte(dest + offset));
++dest;
}
}
}
void spectrum_state::mlz_decompress_block(address_space &space, const u8 *source, u16 dest, u16 size)
{
class de_mlz
{
private:
address_space &m_space;
const u8 *m_src;
u16 m_to;
u8 m_buffer;
int m_buffer_size;
public:
de_mlz(address_space &space, const u8 *src, u16 dst) : m_space(space)
{
m_src = src;
m_to = dst;
}
void init_bitstream()
{
m_buffer = get_byte();
m_buffer_size = 8;
}
u8 get_byte()
{
return *m_src++;
}
void put_byte(u8 val)
{
m_space.write_byte(m_to++, val);
}
void repeat(u32 disp, int num)
{
for (int i = 0; i < num; i++)
{
u8 val = m_space.read_byte(m_to - disp);
put_byte(val);
}
}
// gets specified number of bits from bitstream
// returns them LSB-aligned
u32 get_bits(int count)
{
u32 bits = 0;
while (count--)
{
if (m_buffer_size--)
{
bits <<= 1;
bits |= 1 & (m_buffer >> 7);
m_buffer <<= 1;
}
else
{
init_bitstream();
count++; // repeat loop once more
}
}
return bits;
}
int get_bigdisp()
{
u32 bits;
// inter displacement
if (get_bits(1))
{
bits = get_bits(4);
return 0x1100 - (bits << 8) - get_byte();
}
// shorter displacement
else
return 256 - get_byte();
}
};
de_mlz s(space, source, dest);
u32 done = 0;
int i;
// get first byte of packed file and write to output
s.put_byte(s.get_byte());
// second byte goes to bitstream
s.init_bitstream();
// actual depacking loop!
do
{
// get 1st bit - either OUTBYTE or beginning of LZ code
// OUTBYTE
if (s.get_bits(1))
s.put_byte(s.get_byte());
// LZ code
else
{
switch (s.get_bits(2))
{
case 0: // 000
s.repeat(8 - s.get_bits(3), 1);
break;
case 1: // 001
s.repeat(256 - s.get_byte(), 2);
break;
case 2: // 010
s.repeat(s.get_bigdisp(), 3);
break;
case 3: // 011
// extract num of length bits
for (i = 1; !s.get_bits(1); i++)
;
// check for exit code
if (i == 9)
{
done = 1;
}
else if (i <= 7)
{
// get length bits itself
int bits = s.get_bits(i);
s.repeat(s.get_bigdisp(), 2 + (1 << i) + bits);
}
break;
}
}
} while (!done);
}
/*
Load a .SPG (Spectrum Prog) file.
v1.1: https://raw.githubusercontent.com/tslabs/zx-evo/master/pentevo/docs/Formats/SPGv1_1.txt
v1.0: https://raw.githubusercontent.com/tslabs/zx-evo/master/pentevo/docs/Formats/SPGv1_0.txt
v0.2 https://raw.githubusercontent.com/tslabs/zx-evo/master/pentevo/docs/Formats/SPGv0_2.txt
*/
void spectrum_state::setup_spg(const u8 *snapdata, u32 snapsize)
{
u16 data;
address_space &space = m_maincpu->space(AS_PROGRAM);
data = snapdata[SPG_OFFSET + 0x2c];
if (BIT(data, 4, 4) != 1 || BIT(data, 0, 4) != 0) // just v1.0 for now
{
logerror("Can't load .SPG file v%d.%d\n", BIT(data, 4, 4), BIT(data, 0, 4));
return;
}
m_maincpu->set_state_int(Z80_IY, 0x5c3a);
m_maincpu->set_state_int(Z80_HL2, 0x2758);
m_maincpu->set_state_int(Z80_I, 0x3f);
m_maincpu->set_state_int(Z80_IM, 1);
m_port_7ffd_data = 16;
data = (snapdata[SPG_OFFSET + 0x31] << 8) | snapdata[SPG_OFFSET + 0x30];
if (data < 0x4000)
{
logerror("PC(%04x) < 0x4000 is not allowed\n", data);
}
m_maincpu->set_state_int(Z80_PC, data);
data = (snapdata[SPG_OFFSET + 0x33] << 8) | snapdata[SPG_OFFSET + 0x32];
m_maincpu->set_state_int(Z80_SP, data);
const u8 page3 = snapdata[SPG_OFFSET + 0x34];
data = snapdata[SPG_OFFSET + 0x35];
m_maincpu->set_state_int(Z80_IFF1, BIT(data, 2));
offs_t data_offset = SPG_DATA;
for (auto b = 0; b < 0x100; b++)
{
data = snapdata[SPG_BLOCK_INFO(b) + 0];
const u16 offs = BIT(data, 0, 5) * 512;
const bool is_last = BIT(data, 7);
data = snapdata[SPG_BLOCK_INFO(b) + 1];
const u16 size = (BIT(data, 0, 5) + 1) * 512;
const u8 compression = BIT(data, 6, 2);
data = snapdata[SPG_BLOCK_INFO(b) + 2];
bank3_set_page(data);
switch (compression)
{
case 0x00:
for (auto i = 0; i < size; i++)
space.write_byte(0xc000 + offs + i, snapdata[data_offset + i]);
break;
case 0x01:
mlz_decompress_block(space, &snapdata[data_offset], 0xc000 + offs, size);
break;
case 0x02:
hrust_decompress_block(space, &snapdata[data_offset], 0xc000 + offs, size);
break;
default:
logerror("Unsupported compression: %d\n", compression);
return;
}
data_offset += size;
if (is_last)
break;
}
bank3_set_page(page3);
}
QUICKLOAD_LOAD_MEMBER(spectrum_state::quickload_cb) QUICKLOAD_LOAD_MEMBER(spectrum_state::quickload_cb)
{ {
size_t quickload_size = image.length(); size_t quickload_size = image.length();

View File

@ -119,6 +119,15 @@
#define SNX_COMPRESSED 0xff #define SNX_COMPRESSED 0xff
#define SNX_UNCOMPRESSED 0x00 #define SNX_UNCOMPRESSED 0x00
/*****************************************************************************
*
* .SPG format (used by TS-Conf, BASECONF, Next)
*
****************************************************************************/
#define SPG_OFFSET 0
#define SPG_BLOCK_INFO(_n) (SPG_OFFSET + 0x100 + (3 * _n))
#define SPG_DATA SPG_BLOCK_INFO(256)
/***************************************************************************** /*****************************************************************************
* *
* .FRZ format (used by CBSpeccy, ZX-Live and ASp) * .FRZ format (used by CBSpeccy, ZX-Live and ASp)

View File

@ -68,6 +68,7 @@ public:
specnext_state(const machine_config &mconfig, device_type type, const char *tag) specnext_state(const machine_config &mconfig, device_type type, const char *tag)
: spectrum_128_state(mconfig, type, tag) : spectrum_128_state(mconfig, type, tag)
, m_maincpu(*this, "maincpu") , m_maincpu(*this, "maincpu")
, m_io_shadow_view(*this, "io_shadow_view")
, m_bank_boot_rom(*this, "bootrom") , m_bank_boot_rom(*this, "bootrom")
, m_bank_ram(*this, "bank_ram%u", 0U) , m_bank_ram(*this, "bank_ram%u", 0U)
, m_view0(*this, "mem_view0") , m_view0(*this, "mem_view0")
@ -80,7 +81,7 @@ public:
, m_view7(*this, "mem_view7") , m_view7(*this, "mem_view7")
, m_copper(*this, "copper") , m_copper(*this, "copper")
, m_ctc(*this, "ctc") , m_ctc(*this, "ctc")
, m_dma(*this, "ndma") , m_dma(*this, "dma")
, m_i2cmem(*this, "i2cmem") , m_i2cmem(*this, "i2cmem")
, m_sdcard(*this, "sdcard") , m_sdcard(*this, "sdcard")
, m_ay(*this, "ay%u", 0U) , m_ay(*this, "ay%u", 0U)
@ -123,6 +124,7 @@ protected:
void mmu_x2_w(offs_t bank, u8 data); void mmu_x2_w(offs_t bank, u8 data);
u8 dma_r(bool dma_mode); u8 dma_r(bool dma_mode);
void dma_w(bool dma_mode, u8 data); void dma_w(bool dma_mode, u8 data);
u8 dma_mreq_r(offs_t offset);
u8 spi_data_r(); u8 spi_data_r();
void spi_data_w(u8 data); void spi_data_w(u8 data);
void spi_miso_w(u8 data); void spi_miso_w(u8 data);
@ -287,6 +289,7 @@ private:
void port_e7_reg_w(u8 data); void port_e7_reg_w(u8 data);
memory_access<8, 0, 0, ENDIANNESS_LITTLE>::specific m_next_regs; memory_access<8, 0, 0, ENDIANNESS_LITTLE>::specific m_next_regs;
memory_view m_io_shadow_view;
memory_bank_creator m_bank_boot_rom; memory_bank_creator m_bank_boot_rom;
memory_bank_array_creator<8> m_bank_ram; memory_bank_array_creator<8> m_bank_ram;
memory_view m_view0, m_view1, m_view2, m_view3, m_view4, m_view5, m_view6, m_view7; memory_view m_view0, m_view1, m_view2, m_view3, m_view4, m_view5, m_view6, m_view7;
@ -1154,6 +1157,15 @@ void specnext_state::dma_w(bool dma_mode, u8 data)
m_dma->write(data); m_dma->write(data);
} }
u8 specnext_state::dma_mreq_r(offs_t offset)
{
if (m_nr_07_cpu_speed == 0b11)
{
m_dma->adjust_wait(1);
}
return m_program.read_byte(offset);
}
u8 specnext_state::reg_r(offs_t nr_register) u8 specnext_state::reg_r(offs_t nr_register)
{ {
u8 port_253b_dat; u8 port_253b_dat;
@ -2254,7 +2266,7 @@ void specnext_state::nr_1a_ula_clip_y2_w(u8 data)
static const z80_daisy_config z80_daisy_chain[] = static const z80_daisy_config z80_daisy_chain[] =
{ {
{ "ndma" }, { "dma" },
{ "ctc" }, { "ctc" },
{ nullptr } { nullptr }
}; };
@ -2405,6 +2417,12 @@ void specnext_state::map_fetch(address_map &map)
approach gives better experience in debugger UI. */ approach gives better experience in debugger UI. */
do_m1(offset); do_m1(offset);
m_divmmc_delayed_check = 0; m_divmmc_delayed_check = 0;
// do_m1 performs read from m_program with waits, we need to take it back
if (!machine().side_effects_disabled() && (m_nr_07_cpu_speed == 0b11))
{
m_maincpu->adjust_icount(1);
}
} }
return m_program.read_byte(offset); return m_program.read_byte(offset);
@ -2753,6 +2771,10 @@ void specnext_state::map_io(address_map &map)
if (m_nr_08_dac_en) if (m_nr_08_dac_en)
m_dac[3]->data_w(data); m_dac[3]->data_w(data);
})); }));
map(0x0000, 0xffff).view(m_io_shadow_view);
subdevice<zxbus_device>("zxbus")->set_io_space(m_io_shadow_view[0], m_io_shadow_view[1]);
m_io_shadow_view.select(0);
} }
void specnext_state::map_regs(address_map &map) void specnext_state::map_regs(address_map &map)
@ -3426,6 +3448,14 @@ void specnext_state::video_start()
to[offset & 0x1fff] = data; to[offset & 0x1fff] = data;
} }
}); });
prg.install_read_tap(0x0000, 0xffff, "mem_wait_r", [this](offs_t offset, u8 &data, u8 mem_mask)
{
// The 28MHz with core 3.0.5 is adding extra wait state to every instruction opcode fetch and memory read
if (!machine().side_effects_disabled() && (m_nr_07_cpu_speed == 0b11))
{
m_maincpu->adjust_icount(-1);
}
});
} }
void specnext_state::tbblue(machine_config &config) void specnext_state::tbblue(machine_config &config)
@ -3453,7 +3483,7 @@ void specnext_state::tbblue(machine_config &config)
SPECNEXT_DMA(config, m_dma, 28_MHz_XTAL / 8); SPECNEXT_DMA(config, m_dma, 28_MHz_XTAL / 8);
m_dma->out_busreq_callback().set_inputline(m_maincpu, Z80_INPUT_LINE_BUSRQ); m_dma->out_busreq_callback().set_inputline(m_maincpu, Z80_INPUT_LINE_BUSRQ);
m_dma->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_dma->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_dma->in_mreq_callback().set([this](offs_t offset) { return m_program.read_byte(offset); }); m_dma->in_mreq_callback().set(FUNC(specnext_state::dma_mreq_r));
m_dma->out_mreq_callback().set([this](offs_t offset, u8 data) { m_program.write_byte(offset, data); }); m_dma->out_mreq_callback().set([this](offs_t offset, u8 data) { m_program.write_byte(offset, data); });
m_dma->in_iorq_callback().set([this](offs_t offset) { return m_io.read_byte(offset); }); m_dma->in_iorq_callback().set([this](offs_t offset) { return m_io.read_byte(offset); });
m_dma->out_iorq_callback().set([this](offs_t offset, u8 data) { m_io.write_byte(offset, data); }); m_dma->out_iorq_callback().set([this](offs_t offset, u8 data) { m_io.write_byte(offset, data); });
@ -3487,8 +3517,7 @@ void specnext_state::tbblue(machine_config &config)
SPECNEXT_DIVMMC(config, m_divmmc, 0); SPECNEXT_DIVMMC(config, m_divmmc, 0);
zxbus_device &zxbus(ZXBUS(config, "zxbus", 0)); zxbus_device &zxbus(ZXBUS(config, "zxbus", 0));
zxbus.set_iospace("maincpu", AS_IO); ZXBUS_SLOT(config, "zxbus:1", 0, zxbus, zxbus_cards, nullptr);
ZXBUS_SLOT(config, "zxbus:1", 0, "zxbus", zxbus_cards, nullptr);
const rectangle scr_full = { SCR_320x256.left() - 16, SCR_320x256.right() + 16, SCR_320x256.top() - 8, SCR_320x256.bottom() + 8 }; const rectangle scr_full = { SCR_320x256.left() - 16, SCR_320x256.right() + 16, SCR_320x256.top() - 8, SCR_320x256.bottom() + 8 };
m_screen->set_raw(28_MHz_XTAL / 2, CYCLES_HORIZ, CYCLES_VERT, scr_full); m_screen->set_raw(28_MHz_XTAL / 2, CYCLES_HORIZ, CYCLES_VERT, scr_full);

View File

@ -33,33 +33,22 @@ DEFINE_DEVICE_TYPE(SPECNEXT_DMA, specnext_dma_device, "specnext_dma", "Spectrum
specnext_dma_device::specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) specnext_dma_device::specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: z80dma_device(mconfig, SPECNEXT_DMA, tag, owner, clock) : z80dma_device(mconfig, SPECNEXT_DMA, tag, owner, clock, dma_mode::ZILOG)
{ {
} }
void specnext_dma_device::write(u8 data) void specnext_dma_device::write(u8 data)
{ {
z80dma_device::write(data); if (!m_ndma_mode && data == COMMAND_ENABLE_DMA && num_follow() == 0)
if (num_follow() == 0)
{ {
if ((data & 0x83) == 0x83) // WR6 m_byte_counter = 0;
{
switch (data)
{
case COMMAND_ENABLE_DMA:
m_byte_counter = 0;
break;
default:
break;
}
}
} }
z80dma_device::write(data);
} }
void specnext_dma_device::do_write() void specnext_dma_device::do_write()
{ {
if (m_dma_mode) if (m_ndma_mode)
{ {
z80dma_device::do_write(); z80dma_device::do_write();
return; return;
@ -101,12 +90,12 @@ void specnext_dma_device::device_start()
{ {
z80dma_device::device_start(); z80dma_device::device_start();
save_item(NAME(m_dma_mode)); save_item(NAME(m_ndma_mode));
} }
void specnext_dma_device::device_reset() void specnext_dma_device::device_reset()
{ {
z80dma_device::device_reset(); z80dma_device::device_reset();
m_dma_mode = 0; m_ndma_mode = 0;
} }

View File

@ -12,7 +12,7 @@ class specnext_dma_device : public z80dma_device
public: public:
specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
void dma_mode_w(bool dma_mode) { m_dma_mode = dma_mode; } void dma_mode_w(bool dma_mode) { m_ndma_mode = dma_mode; }
virtual void write(u8 data) override; virtual void write(u8 data) override;
@ -23,7 +23,7 @@ protected:
virtual void do_write() override; virtual void do_write() override;
private: private:
bool m_dma_mode; // 0 = zxn dma, 1 = z80 dma bool m_ndma_mode; // 0 = zxn dma, 1 = z80 dma
}; };
DECLARE_DEVICE_TYPE(SPECNEXT_DMA, specnext_dma_device) DECLARE_DEVICE_TYPE(SPECNEXT_DMA, specnext_dma_device)

View File

@ -775,7 +775,9 @@ void spectrum_state::spectrum_common(machine_config &config)
m_exp->fb_r_handler().set(FUNC(spectrum_state::floating_bus_r)); m_exp->fb_r_handler().set(FUNC(spectrum_state::floating_bus_r));
/* devices */ /* devices */
SNAPSHOT(config, "snapshot", "ach,frz,plusd,prg,sem,sit,sna,snp,snx,sp,z80,zx").set_load_callback(FUNC(spectrum_state::snapshot_cb)); snapshot_image_device &snapshot(SNAPSHOT(config, "snapshot", "ach,frz,plusd,prg,sem,sit,sna,snp,snx,sp,spg,z80,zx"));
snapshot.set_load_callback(FUNC(spectrum_state::snapshot_cb));
snapshot.set_interface("spectrum_snapshot");
QUICKLOAD(config, "quickload", "raw,scr", attotime::from_seconds(2)).set_load_callback(FUNC(spectrum_state::quickload_cb)); // The delay prevents the screen from being cleared by the RAM test at boot QUICKLOAD(config, "quickload", "raw,scr", attotime::from_seconds(2)).set_load_callback(FUNC(spectrum_state::quickload_cb)); // The delay prevents the screen from being cleared by the RAM test at boot
CASSETTE(config, m_cassette); CASSETTE(config, m_cassette);

View File

@ -91,6 +91,7 @@ protected:
virtual void video_start() override ATTR_COLD; virtual void video_start() override ATTR_COLD;
// until machine/spec_snqk.cpp gets somehow disentangled // until machine/spec_snqk.cpp gets somehow disentangled
virtual void bank3_set_page(u8 page) { }
virtual void plus3_update_memory() { } virtual void plus3_update_memory() { }
virtual void spectrum_128_update_memory() { } virtual void spectrum_128_update_memory() { }
virtual void ts2068_update_memory() { } virtual void ts2068_update_memory() { }
@ -209,7 +210,9 @@ protected:
void setup_frz(const uint8_t *snapdata, uint32_t snapsize); void setup_frz(const uint8_t *snapdata, uint32_t snapsize);
void z80_decompress_block(address_space &space, const uint8_t *source, uint16_t dest, uint16_t size); void z80_decompress_block(address_space &space, const uint8_t *source, uint16_t dest, uint16_t size);
void setup_z80(const uint8_t *snapdata, uint32_t snapsize); void setup_z80(const uint8_t *snapdata, uint32_t snapsize);
void hrust_decompress_block(address_space &space, const u8 *source, u16 dest, u16 size);
void mlz_decompress_block(address_space &space, const u8 *source, u16 dest, u16 size);
void setup_spg(const u8 *snapdata, u32 snapsize);
// quickload helpers // quickload helpers
void log_quickload(const char *type, uint32_t start, uint32_t length, uint32_t exec, const char *exec_format); void log_quickload(const char *type, uint32_t start, uint32_t length, uint32_t exec, const char *exec_format);
void setup_scr(const uint8_t *quickdata, uint32_t quicksize); void setup_scr(const uint8_t *quickdata, uint32_t quicksize);

View File

@ -80,7 +80,7 @@ public:
sprinter_state(const machine_config &mconfig, device_type type, const char *tag) sprinter_state(const machine_config &mconfig, device_type type, const char *tag)
: spectrum_128_state(mconfig, type, tag) : spectrum_128_state(mconfig, type, tag)
, m_maincpu(*this, "maincpu") , m_maincpu(*this, "maincpu")
, m_isa(*this, "isa%u", 0U) , m_isa(*this, "isa8%u", 0U)
, m_irqs(*this, "irqs") , m_irqs(*this, "irqs")
, m_rtc(*this, "rtc") , m_rtc(*this, "rtc")
, m_ata(*this, "ata%u", 1U) , m_ata(*this, "ata%u", 1U)
@ -105,6 +105,7 @@ public:
void sprinter(machine_config &config); void sprinter(machine_config &config);
INPUT_CHANGED_MEMBER(turbo_changed); INPUT_CHANGED_MEMBER(turbo_changed);
INPUT_CHANGED_MEMBER(on_nmi);
protected: protected:
virtual void machine_start() override ATTR_COLD; virtual void machine_start() override ATTR_COLD;
@ -260,6 +261,7 @@ private:
bool m_turbo; bool m_turbo;
bool m_turbo_hard; bool m_turbo_hard;
bool m_arom16; bool m_arom16;
bool m_nmi_ena;
u8 m_rom_rg; u8 m_rom_rg;
u8 m_pn; u8 m_pn;
u8 m_sc; u8 m_sc;
@ -317,7 +319,7 @@ void sprinter_state::update_memory()
else else
{ {
const bool cash_on = 0; const bool cash_on = 0;
const bool nmi_ena = 1; const bool nmi_ena = m_nmi_ena;
const bool sc0 = BIT(m_sc, 0); const bool sc0 = BIT(m_sc, 0);
const bool sc_lc = !(sc0 && m_ram_sys) && !cash_on; const bool sc_lc = !(sc0 && m_ram_sys) && !cash_on;
const u8 spr_ = BIT(m_sc, 1) ? 0 : ((m_dos << 1) | (BIT(m_pn, 4) || !m_dos)); const u8 spr_ = BIT(m_sc, 1) ? 0 : ((m_dos << 1) | (BIT(m_pn, 4) || !m_dos));
@ -1427,6 +1429,7 @@ void sprinter_state::machine_start()
save_item(NAME(m_turbo)); save_item(NAME(m_turbo));
save_item(NAME(m_turbo_hard)); save_item(NAME(m_turbo_hard));
save_item(NAME(m_arom16)); save_item(NAME(m_arom16));
save_item(NAME(m_nmi_ena));
save_item(NAME(m_rom_rg)); save_item(NAME(m_rom_rg));
save_item(NAME(m_pn)); save_item(NAME(m_pn));
save_item(NAME(m_sc)); save_item(NAME(m_sc));
@ -1468,6 +1471,13 @@ void sprinter_state::machine_start()
m_dcp_location = m_ram->pointer() + (0x40 << 14); m_dcp_location = m_ram->pointer() + (0x40 << 14);
for (int addr = 0; addr < m_fastram.bytes(); ++addr)
m_fastram.target()[addr] = machine().rand();
for (int addr = 0; addr < m_vram.bytes(); ++addr)
m_vram.target()[addr] = machine().rand();
for (int addr = 0; addr < m_ram->size(); ++addr)
m_ram->pointer()[addr] = machine().rand();
const u8 port_default[0x40] = { const u8 port_default[0x40] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Cx - SYS PORTS COPIES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Cx - SYS PORTS COPIES
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, // Dx - RAM PAGES 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, // Dx - RAM PAGES
@ -1482,6 +1492,31 @@ void sprinter_state::machine_start()
m_hold = {0, 0}; // cb m_hold = {0, 0}; // cb
m_conf_loading = 1; m_conf_loading = 1;
m_conf = 0; m_conf = 0;
int idx = Z84_MCR + 1;
m_maincpu->state_add_divider(-1);
m_maincpu->state_add(idx++, "PG0", m_pages[0]);
m_maincpu->state_add(idx++, "PG1", m_pages[1]);
m_maincpu->state_add(idx++, "PG2", m_pages[2]);
m_maincpu->state_add(idx++, "PG3", m_pages[3]);
m_maincpu->state_add(idx++, "7FFD", m_pn);
m_maincpu->state_add(idx++, "1FFD", m_sc);
m_maincpu->state_add_divider(-1);
m_maincpu->state_add(idx++, "DOS OFF", m_dos);
m_maincpu->state_add(idx++, "CNF", m_cnf);
m_maincpu->state_add(idx++, "PORT_Y", m_port_y);
m_maincpu->state_add(idx++, "RGMOD", m_rgmod);
m_maincpu->state_add_divider(-1);
m_maincpu->state_add(idx++, "ACC MODE", m_acc_dir);
m_maincpu->state_add(idx++, "ACC Buffer", m_rgacc);
m_maincpu->state_add(idx++, "Ext ACC", m_alt_acc);
m_maincpu->state_add(idx++, "ACC Counter", m_acc_cnt);
m_maincpu->state_add_divider(-1);
m_maincpu->state_add(idx++, "ISA_ADDR_EXT", m_isa_addr_ext);
} }
void sprinter_state::machine_reset() void sprinter_state::machine_reset()
@ -1499,6 +1534,7 @@ void sprinter_state::machine_reset()
m_ram_sys = 0; m_ram_sys = 0;
m_sys_pg = 0; m_sys_pg = 0;
m_arom16 = 0; m_arom16 = 0;
m_nmi_ena = 1; // off
m_cnf = 0x00; m_cnf = 0x00;
m_pn = 0x00; m_pn = 0x00;
m_sc = 0x00; m_sc = 0x00;
@ -1697,6 +1733,18 @@ INPUT_CHANGED_MEMBER(sprinter_state::turbo_changed)
update_cpu(); update_cpu();
} }
INPUT_CHANGED_MEMBER(sprinter_state::on_nmi)
{
if ((m_io_nmi->read() & 0x01) && m_nmi_ena)
{
m_nmi_ena = false;
update_memory();
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
machine().debug_break();
}
}
INPUT_PORTS_START( sprinter ) INPUT_PORTS_START( sprinter )
/* PORT_NAME = KEY Mode CAPS Mode SYMBOL Mode EXT Mode EXT+Shift Mode BASIC Mode */ /* PORT_NAME = KEY Mode CAPS Mode SYMBOL Mode EXT Mode EXT+Shift Mode BASIC Mode */
PORT_START("IO_LINE0") /* 0xFEFE */ PORT_START("IO_LINE0") /* 0xFEFE */
@ -1865,6 +1913,9 @@ INPUT_PORTS_START( sprinter )
PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON6) PORT_NAME("%p Z") PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON6) PORT_NAME("%p Z")
PORT_START("NMI")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(sprinter_state::on_nmi), 0)
PORT_START("TURBO") PORT_START("TURBO")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("TURBO") PORT_CODE(KEYCODE_F12) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(sprinter_state::turbo_changed), 0) PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("TURBO") PORT_CODE(KEYCODE_F12) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(sprinter_state::turbo_changed), 0)
INPUT_PORTS_END INPUT_PORTS_END
@ -1896,13 +1947,11 @@ void sprinter_state::sprinter(machine_config &config)
ISA8(config, m_isa[0], X_SP / 5); ISA8(config, m_isa[0], X_SP / 5);
m_isa[0]->set_custom_spaces(); m_isa[0]->set_custom_spaces();
zxbus_device &zxbus(ZXBUS(config, "zxbus", 0)); ISA8_SLOT(config, "isa0", 0, m_isa[0], pc_isa8_cards, "zxbus_adapter", false);
zxbus.set_iospace(m_isa[0], isa8_device::AS_ISA_IO);
ZXBUS_SLOT(config, "zxbus2isa", 0, "zxbus", zxbus_cards, nullptr);
ISA8(config, m_isa[1], X_SP / 5); ISA8(config, m_isa[1], X_SP / 5);
m_isa[1]->set_custom_spaces(); m_isa[1]->set_custom_spaces();
ISA8_SLOT(config, "isa8", 0, m_isa[1], pc_isa8_cards, nullptr, false); ISA8_SLOT(config, "isa1", 0, m_isa[1], pc_isa8_cards, nullptr, false);
m_screen->set_raw(X_SP / 3, SPRINT_WIDTH, SPRINT_HEIGHT, { 0, SPRINT_XVIS - 1, 0, SPRINT_YVIS - 1 }); m_screen->set_raw(X_SP / 3, SPRINT_WIDTH, SPRINT_HEIGHT, { 0, SPRINT_XVIS - 1, 0, SPRINT_YVIS - 1 });
m_screen->set_screen_update(FUNC(sprinter_state::screen_update)); m_screen->set_screen_update(FUNC(sprinter_state::screen_update));
@ -1950,24 +1999,32 @@ void sprinter_state::sprinter(machine_config &config)
ROM_START( sprinter ) ROM_START( sprinter )
ROM_REGION(0x040000, "maincpu", ROMREGION_ERASEFF) ROM_REGION(0x040000, "maincpu", ROMREGION_ERASEFF)
ROM_DEFAULT_BIOS("v3.04.253") ROM_DEFAULT_BIOS("v3.04")
ROM_SYSTEM_BIOS(0, "v2.13.251", "BIOS v2.13, SETUP v251") // 11.10.2002 ROM_SYSTEM_BIOS(0, "v2.13", "Firmware v2.13, 11.10.2002")
ROMX_LOAD( "sp2k-2.13.251.rom", 0x000000, 0x40000, CRC(6495575f) SHA1(a9ca06b27e7c5b2b5b9ff8fc2d19ee24ed64c258), ROM_BIOS(0)) ROMX_LOAD( "sp2k-2.13.rom", 0x000000, 0x40000, CRC(6495575f) SHA1(a9ca06b27e7c5b2b5b9ff8fc2d19ee24ed64c258), ROM_BIOS(0))
ROM_SYSTEM_BIOS(1, "v2.17.252", "BIOS v2.17, SETUP v252") // 03.03.2002 ROM_SYSTEM_BIOS(1, "v2.17", "Firmware v2.17, 03.03.2002")
ROMX_LOAD( "sp2k-2.17.252.rom", 0x000000, 0x40000, CRC(3c7f1025) SHA1(d5c3d10b3b67f9ef87d3ce8a52ae3c33b95b9171), ROM_BIOS(1)) ROMX_LOAD( "sp2k-2.17.rom", 0x000000, 0x40000, CRC(3c7f1025) SHA1(d5c3d10b3b67f9ef87d3ce8a52ae3c33b95b9171), ROM_BIOS(1))
ROM_SYSTEM_BIOS(2, "v3.00.253", "BIOS v3.00, SETUP v253") // 04.10.2002 ROM_SYSTEM_BIOS(2, "v3.00", "Firmware v3.00, 04.10.2002")
ROMX_LOAD( "sp2k-3.00.253.rom", 0x000000, 0x40000, CRC(193de3da) SHA1(428dcb1253a88e7b5aedcd68b5bf6d2487592e10), ROM_BIOS(2)) ROMX_LOAD( "sp2k-3.00.rom", 0x000000, 0x40000, CRC(193de3da) SHA1(428dcb1253a88e7b5aedcd68b5bf6d2487592e10), ROM_BIOS(2))
ROM_SYSTEM_BIOS(3, "v3.03.253", "BIOS v3.03, SETUP v253") // 02.05.2003 ROM_SYSTEM_BIOS(3, "v3.03", "Firmware v3.03, 02.05.2003")
ROMX_LOAD( "sp2k-3.03.253.rom", 0x000000, 0x40000, CRC(fe26f578) SHA1(ef6d0fe4ec1bae7bda572a4fb3b9497a8910b885), ROM_BIOS(3)) ROMX_LOAD( "sp2k-3.03.rom", 0x000000, 0x40000, CRC(fe26f578) SHA1(ef6d0fe4ec1bae7bda572a4fb3b9497a8910b885), ROM_BIOS(3))
ROM_SYSTEM_BIOS(4, "v3.04.253", "BIOS v3.04, SETUP v253") // 06.16.2003 ROM_SYSTEM_BIOS(4, "v3.04", "Firmware v3.04, 06.16.2003")
ROMX_LOAD( "sp2k-3.04.253.rom", 0x000000, 0x40000, CRC(1729cb5c) SHA1(fb4c9f80651aa87526f141839fb4d6cb86b654c7), ROM_BIOS(4)) ROMX_LOAD( "sp2k-3.04.rom", 0x000000, 0x40000, CRC(1729cb5c) SHA1(fb4c9f80651aa87526f141839fb4d6cb86b654c7), ROM_BIOS(4))
ROM_SYSTEM_BIOS(5, "v3.05", "Firmware v3.05, 01.10.2022")
ROMX_LOAD( "sp2k-3.05.rom", 0x000000, 0x40000, CRC(fe1c2685) SHA1(10e4e29bdc058cd4380837fb8831ce4f5977f6b8), ROM_BIOS(5))
ROM_SYSTEM_BIOS(6, "v3.06", "Firmware v3.06, 25.06.2025")
ROMX_LOAD( "sp2k-3.06.rom", 0x000000, 0x40000, CRC(187f4382) SHA1(717ed28c59f9533a9b3f9d24098b536a0d3c1573), ROM_BIOS(6))
ROM_SYSTEM_BIOS(7, "dev", "Firmware in development")
ROMX_LOAD( "_sprin.bin", 0x000000, 0x40000, CRC(00000000) SHA1(0000000000000000000000000000000000000000), ROM_BIOS(7))
ROM_END ROM_END
} // Anonymous namespace } // Anonymous namespace

View File

@ -27,9 +27,6 @@ TsConf: https://github.com/tslabs/zx-evo/blob/master/pentevo/docs/TSconf/tsconf_
FAQ-RUS: https://forum.tslabs.info/viewtopic.php?f=35&t=157 FAQ-RUS: https://forum.tslabs.info/viewtopic.php?f=35&t=157
ROM: https://github.com/tslabs/zx-evo/blob/master/pentevo/rom/bin/ts-bios.rom (validated on: 2021-12-14) ROM: https://github.com/tslabs/zx-evo/blob/master/pentevo/rom/bin/ts-bios.rom (validated on: 2021-12-14)
TODO:
- VDos
****************************************************************************/ ****************************************************************************/
#include "emu.h" #include "emu.h"
@ -83,12 +80,9 @@ void tsconf_state::tsconf_io(address_map &map)
{ {
map.unmap_value_high(); map.unmap_value_high();
map(0x0000, 0x0000).mirror(0x7ffd).w(FUNC(tsconf_state::tsconf_port_7ffd_w)); map(0x0000, 0x0000).mirror(0x7ffd).w(FUNC(tsconf_state::tsconf_port_7ffd_w));
map(0x001f, 0x001f).mirror(0xff00).r(FUNC(tsconf_state::tsconf_port_xx1f_r)).w(m_beta, FUNC(beta_disk_device::command_w)); map(0x001f, 0x001f).mirror(0xff00).r(FUNC(tsconf_state::tsconf_port_xx1f_r));
map(0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w));
map(0x0057, 0x0057).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_57_zctr_r), FUNC(tsconf_state::tsconf_port_57_zctr_w)); // spi config map(0x0057, 0x0057).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_57_zctr_r), FUNC(tsconf_state::tsconf_port_57_zctr_w)); // spi config
map(0x0077, 0x0077).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_77_zctr_r), FUNC(tsconf_state::tsconf_port_77_zctr_w)); // spi data map(0x0077, 0x0077).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_77_zctr_r), FUNC(tsconf_state::tsconf_port_77_zctr_w)); // spi data
map(0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w));
map(0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w));
// RS-232 // RS-232
map(0x00ef, 0x00ef).mirror(0xff00).rw(m_uart, FUNC(tsconf_rs232_device::dr_r), FUNC(tsconf_rs232_device::dr_w)); // 0x00ef..0xbfef map(0x00ef, 0x00ef).mirror(0xff00).rw(m_uart, FUNC(tsconf_rs232_device::dr_r), FUNC(tsconf_rs232_device::dr_w)); // 0x00ef..0xbfef
@ -98,7 +92,6 @@ void tsconf_state::tsconf_io(address_map &map)
.lw8(NAME([this](offs_t offset, u8 data) { m_uart->reg_w(offset >> 8, data); })); .lw8(NAME([this](offs_t offset, u8 data) { m_uart->reg_w(offset >> 8, data); }));
map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(tsconf_state::spectrum_ula_r), FUNC(tsconf_state::tsconf_ula_w)); map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(tsconf_state::spectrum_ula_r), FUNC(tsconf_state::tsconf_ula_w));
map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w));
map(0x00af, 0x00af).select(0xff00).rw(FUNC(tsconf_state::tsconf_port_xxaf_r), FUNC(tsconf_state::tsconf_port_xxaf_w)); map(0x00af, 0x00af).select(0xff00).rw(FUNC(tsconf_state::tsconf_port_xxaf_r), FUNC(tsconf_state::tsconf_port_xxaf_w));
map(0xfadf, 0xfadf).lr8(NAME([this]() -> u8 { return 0x80 | (m_io_mouse[2]->read() & 0x07); })); map(0xfadf, 0xfadf).lr8(NAME([this]() -> u8 { return 0x80 | (m_io_mouse[2]->read() & 0x07); }));
map(0xfbdf, 0xfbdf).lr8(NAME([this]() -> u8 { return m_io_mouse[0]->read(); })); map(0xfbdf, 0xfbdf).lr8(NAME([this]() -> u8 { return m_io_mouse[0]->read(); }));
@ -108,6 +101,13 @@ void tsconf_state::tsconf_io(address_map &map)
map(0x00fb, 0x00fb).mirror(0xff00).w(m_dac, FUNC(dac_byte_interface::data_w)); map(0x00fb, 0x00fb).mirror(0xff00).w(m_dac, FUNC(dac_byte_interface::data_w));
map(0x80fd, 0x80fd).mirror(0x3f00).w("ay_slot", FUNC(ay_slot_device::data_w)); map(0x80fd, 0x80fd).mirror(0x3f00).w("ay_slot", FUNC(ay_slot_device::data_w));
map(0xc0fd, 0xc0fd).mirror(0x3f00).rw("ay_slot", FUNC(ay_slot_device::data_r), FUNC(ay_slot_device::address_w)); map(0xc0fd, 0xc0fd).mirror(0x3f00).rw("ay_slot", FUNC(ay_slot_device::data_r), FUNC(ay_slot_device::address_w));
map(0x0000, 0xffff).view(m_io_shadow_view);
m_io_shadow_view[0]; // !Shadow
// IO: Shadow
m_io_shadow_view[1](0x0000, 0xffff).m(m_beta, FUNC(tsconf_beta_device::tsconf_beta_io));
subdevice<zxbus_device>("zxbus")->set_io_space(m_io_shadow_view[0], m_io_shadow_view[1]);
} }
void tsconf_state::tsconf_switch(address_map &map) void tsconf_state::tsconf_switch(address_map &map)
@ -178,6 +178,7 @@ void tsconf_state::machine_start()
m_bank_ram[0]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000); m_bank_ram[0]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000);
save_item(NAME(m_int_mask)); save_item(NAME(m_int_mask));
save_item(NAME(m_update_on_m1));
save_item(NAME(m_regs)); save_item(NAME(m_regs));
save_item(NAME(m_cache_line_addr)); save_item(NAME(m_cache_line_addr));
save_item(NAME(m_zctl_di)); save_item(NAME(m_zctl_di));
@ -188,11 +189,14 @@ void tsconf_state::machine_start()
void tsconf_state::machine_reset() void tsconf_state::machine_reset()
{ {
m_update_on_m1 = false;
m_frame_irq_timer->adjust(attotime::never); m_frame_irq_timer->adjust(attotime::never);
m_scanline_irq_timer->adjust(attotime::never); m_scanline_irq_timer->adjust(attotime::never);
m_int_mask = 0; m_int_mask = 0;
m_bank0_rom.select(0); m_bank0_rom.select(0);
update_io(0);
m_cache_line_addr = -1; m_cache_line_addr = -1;
m_glukrs->disable(); m_glukrs->disable();
@ -220,8 +224,7 @@ void tsconf_state::machine_reset()
m_regs[INT_MASK] = 0x01; // xxxxx001 m_regs[INT_MASK] = 0x01; // xxxxx001
m_regs[CACHE_CONFIG] &= 0xf0; // xxxx0000 m_regs[CACHE_CONFIG] &= 0xf0; // xxxx0000
if (m_beta->started()) m_beta->fddvirt_w(m_regs[FDD_VIRT] & 0x0f);
m_beta->enable();
m_zctl_cs = 1; m_zctl_cs = 1;
m_zctl_di = 0xff; m_zctl_di = 0xff;
@ -270,9 +273,9 @@ void tsconf_state::tsconf(machine_config &config)
config.device_remove("palette"); config.device_remove("palette");
Z80(config.replace(), m_maincpu, 14_MHz_XTAL / 4); Z80(config.replace(), m_maincpu, 14_MHz_XTAL / 4);
m_maincpu->set_addrmap(AS_PROGRAM, &tsconf_state::tsconf_mem); m_maincpu->set_memory_map(&tsconf_state::tsconf_mem);
m_maincpu->set_addrmap(AS_IO, &tsconf_state::tsconf_io); m_maincpu->set_io_map(&tsconf_state::tsconf_io);
m_maincpu->set_addrmap(AS_OPCODES, &tsconf_state::tsconf_switch); m_maincpu->set_m1_map(&tsconf_state::tsconf_switch);
m_maincpu->set_irq_acknowledge_callback(FUNC(tsconf_state::irq_vector)); m_maincpu->set_irq_acknowledge_callback(FUNC(tsconf_state::irq_vector));
m_maincpu->set_vblank_int("screen", FUNC(tsconf_state::tsconf_vblank_interrupt)); m_maincpu->set_vblank_int("screen", FUNC(tsconf_state::tsconf_vblank_interrupt));
@ -289,9 +292,8 @@ void tsconf_state::tsconf(machine_config &config)
rs232.cts_handler().set(m_uart, FUNC(tsconf_rs232_device::cts_w)); rs232.cts_handler().set(m_uart, FUNC(tsconf_rs232_device::cts_w));
zxbus_device &zxbus(ZXBUS(config, "zxbus", 0)); zxbus_device &zxbus(ZXBUS(config, "zxbus", 0));
zxbus.set_iospace("maincpu", AS_IO); ZXBUS_SLOT(config, "zxbus1", 0, zxbus, zxbus_cards, nullptr);
ZXBUS_SLOT(config, "zxbus1", 0, "zxbus", zxbus_cards, nullptr); //ZXBUS_SLOT(config, "zxbus2", 0, zxbus, zxbus_cards, nullptr);
//ZXBUS_SLOT(config, "zxbus2", 0, "zxbus", zxbus_cards, nullptr);
m_ram->set_default_size("4096K").set_default_value(0x00); // must be random but 0x00 behaves better than 0xff in tested software m_ram->set_default_size("4096K").set_default_value(0x00); // must be random but 0x00 behaves better than 0xff in tested software
@ -305,7 +307,10 @@ void tsconf_state::tsconf(machine_config &config)
m_dma->out_sfile_callback().set(FUNC(tsconf_state::sfile_write16)); m_dma->out_sfile_callback().set(FUNC(tsconf_state::sfile_write16));
m_dma->on_ready_callback().set(FUNC(tsconf_state::dma_ready)); m_dma->on_ready_callback().set(FUNC(tsconf_state::dma_ready));
BETA_DISK(config, m_beta, 0); TSCONF_BETA(config, m_beta, 0);
m_beta->out_dos_callback().set(FUNC(tsconf_state::update_io));
m_beta->out_vdos_m1_callback().set([this](int state) { m_update_on_m1 = true; });
SPEAKER(config, "speakers", 2).front(); SPEAKER(config, "speakers", 2).front();
AY_SLOT(config.replace(), "ay_slot", 14_MHz_XTAL / 8, default_ay_slot_devices, "ay_ym2149") AY_SLOT(config.replace(), "ay_slot", 14_MHz_XTAL / 8, default_ay_slot_devices, "ay_ym2149")
@ -328,7 +333,7 @@ void tsconf_state::tsconf(machine_config &config)
AT_KEYB(config, m_keyboard, pc_keyboard_device::KEYBOARD_TYPE::AT, 3); AT_KEYB(config, m_keyboard, pc_keyboard_device::KEYBOARD_TYPE::AT, 3);
SOFTWARE_LIST(config, "betadisc_list_pent").set_original("spectrum_betadisc_flop"); SOFTWARE_LIST(config, "betadisc_list_pent").set_original("spectrum_betadisc_flop");
SOFTWARE_LIST(config, "betadisc_list_tsconf").set_original("tsconf_betadisc_flop"); SOFTWARE_LIST(config, "tsconf_list").set_original("tsconf");
} }
ROM_START(tsconf) ROM_START(tsconf)

View File

@ -13,10 +13,10 @@
#include "spec128.h" #include "spec128.h"
#include "glukrs.h" #include "glukrs.h"
#include "tsconf_beta.h"
#include "tsconf_rs232.h" #include "tsconf_rs232.h"
#include "tsconfdma.h" #include "tsconfdma.h"
#include "beta_m.h"
#include "machine/pckeybrd.h" #include "machine/pckeybrd.h"
#include "machine/spi_sdcard.h" #include "machine/spi_sdcard.h"
#include "sound/dac.h" #include "sound/dac.h"
@ -28,12 +28,13 @@ class tsconf_state : public spectrum_128_state
public: public:
tsconf_state(const machine_config &mconfig, device_type type, const char *tag) tsconf_state(const machine_config &mconfig, device_type type, const char *tag)
: spectrum_128_state(mconfig, type, tag) : spectrum_128_state(mconfig, type, tag)
, m_io_shadow_view(*this, "io_shadow_view")
, m_bank0_rom(*this, "bank0_rom") , m_bank0_rom(*this, "bank0_rom")
, m_tiles_raw(*this, "tiles%u_raw", 0U, 64U * 64 * 8 * 8, ENDIANNESS_LITTLE) , m_tiles_raw(*this, "tiles%u_raw", 0U, 64U * 64 * 8 * 8, ENDIANNESS_LITTLE)
, m_sprites_raw(*this, "sprites_raw", 64U * 64 * 8 * 8, ENDIANNESS_LITTLE) , m_sprites_raw(*this, "sprites_raw", 64U * 64 * 8 * 8, ENDIANNESS_LITTLE)
, m_keyboard(*this, "pc_keyboard") , m_keyboard(*this, "pc_keyboard")
, m_io_mouse(*this, "mouse_input%u", 1U) , m_io_mouse(*this, "mouse_input%u", 1U)
, m_beta(*this, BETA_DISK_TAG) , m_beta(*this, "beta")
, m_dma(*this, "dma") , m_dma(*this, "dma")
, m_sdcard(*this, "sdcard") , m_sdcard(*this, "sdcard")
, m_uart(*this, "uart") , m_uart(*this, "uart")
@ -57,6 +58,8 @@ protected:
virtual void machine_reset() override ATTR_COLD; virtual void machine_reset() override ATTR_COLD;
virtual void device_post_load() override ATTR_COLD; virtual void device_post_load() override ATTR_COLD;
virtual void bank3_set_page(u8 page) override;
virtual TIMER_CALLBACK_MEMBER(irq_off) override; virtual TIMER_CALLBACK_MEMBER(irq_off) override;
TIMER_CALLBACK_MEMBER(irq_frame); TIMER_CALLBACK_MEMBER(irq_frame);
TIMER_CALLBACK_MEMBER(irq_scanline); TIMER_CALLBACK_MEMBER(irq_scanline);
@ -156,6 +159,7 @@ private:
INTERRUPT_GEN_MEMBER(tsconf_vblank_interrupt); INTERRUPT_GEN_MEMBER(tsconf_vblank_interrupt);
IRQ_CALLBACK_MEMBER(irq_vector); IRQ_CALLBACK_MEMBER(irq_vector);
u8 m_int_mask; u8 m_int_mask;
bool m_update_on_m1;
DECLARE_VIDEO_START(tsconf); DECLARE_VIDEO_START(tsconf);
TILE_GET_INFO_MEMBER(get_tile_info_txt); TILE_GET_INFO_MEMBER(get_tile_info_txt);
@ -188,6 +192,7 @@ private:
void tsconf_port_f7_w(offs_t offset, u8 data); void tsconf_port_f7_w(offs_t offset, u8 data);
void tsconf_update_bank0(); void tsconf_update_bank0();
void update_io(int dos);
u8 beta_neutral_r(offs_t offset); u8 beta_neutral_r(offs_t offset);
u8 beta_enable_r(offs_t offset); u8 beta_enable_r(offs_t offset);
u8 beta_disable_r(offs_t offset); u8 beta_disable_r(offs_t offset);
@ -212,6 +217,7 @@ private:
std::map<tsconf_regs, u8> m_scanline_delayed_regs_update; std::map<tsconf_regs, u8> m_scanline_delayed_regs_update;
u8 m_regs[0x100]; u8 m_regs[0x100];
memory_view m_io_shadow_view;
memory_view m_bank0_rom; memory_view m_bank0_rom;
memory_share_array_creator<u8, 2> m_tiles_raw; memory_share_array_creator<u8, 2> m_tiles_raw;
memory_share_creator<u8> m_sprites_raw; memory_share_creator<u8> m_sprites_raw;
@ -220,7 +226,7 @@ private:
required_device<at_keyboard_device> m_keyboard; required_device<at_keyboard_device> m_keyboard;
required_ioport_array<3> m_io_mouse; required_ioport_array<3> m_io_mouse;
required_device<beta_disk_device> m_beta; required_device<tsconf_beta_device> m_beta;
required_device<tsconfdma_device> m_dma; required_device<tsconfdma_device> m_dma;
required_device<spi_sdcard_device> m_sdcard; required_device<spi_sdcard_device> m_sdcard;
required_device<tsconf_rs232_device> m_uart; required_device<tsconf_rs232_device> m_uart;

View File

@ -0,0 +1,275 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
/**********************************************************************
Beta TR-DOS with virtual drives
**********************************************************************/
#include "emu.h"
#include "tsconf_beta.h"
#include "formats/trd_dsk.h"
namespace {
void floppy_formats(format_registration &fr)
{
fr.add_mfm_containers();
fr.add_pc_formats();
fr.add(FLOPPY_TRD_FORMAT);
}
void beta_disk_floppies(device_slot_interface &device)
{
device.option_add("525hd", FLOPPY_525_HD);
device.option_add("525qd", FLOPPY_525_QD);
device.option_add("35hd", FLOPPY_35_HD);
device.option_add("35dd", FLOPPY_35_DD);
}
} // anonymous namespace
// device type definition
DEFINE_DEVICE_TYPE(TSCONF_BETA, tsconf_beta_device, "tsconf_beta", "Virtual TR-DOS")
void tsconf_beta_device::tsconf_beta_io(address_map &map)
{
map(0x001f, 0x001f).mirror(0xff00).rw(FUNC(tsconf_beta_device::status_r), FUNC(tsconf_beta_device::command_w));
map(0x003f, 0x003f).mirror(0xff00).rw(FUNC(tsconf_beta_device::track_r), FUNC(tsconf_beta_device::track_w));
map(0x005f, 0x005f).mirror(0xff00).rw(FUNC(tsconf_beta_device::sector_r), FUNC(tsconf_beta_device::sector_w));
map(0x007f, 0x007f).mirror(0xff00).rw(FUNC(tsconf_beta_device::data_r), FUNC(tsconf_beta_device::data_w));
map(0x009f, 0x009f).select(0xff60).rw(FUNC(tsconf_beta_device::state_r), FUNC(tsconf_beta_device::param_w));
}
tsconf_beta_device::tsconf_beta_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, TSCONF_BETA, tag, owner, clock)
, m_out_dos_cb(*this)
, m_out_vdos_m1_cb(*this)
, m_wd179x(*this, "wd179x")
, m_floppy(*this, "wd179x:%u", 0U)
, m_floppy_led(*this, "fdd%u_led", 0U)
, m_control(0)
, m_motor_active(false)
{
}
bool tsconf_beta_device::pre_vg_in_check()
{
if (m_dos)
{
if (m_vdos)
{
m_vdos = false;
m_out_dos_cb(dos_io_r());
return false;
}
else if ((1 << (m_control & 3)) & m_fddvirt)
{
m_out_vdos_m1_cb(1);
return false;
}
}
return true;
}
u8 tsconf_beta_device::status_r()
{
return pre_vg_in_check() ? m_wd179x->status_r() : 0xff;
}
u8 tsconf_beta_device::track_r()
{
return pre_vg_in_check() ? m_wd179x->track_r() : 0xff;
}
u8 tsconf_beta_device::sector_r()
{
return pre_vg_in_check() ? m_wd179x->sector_r() : 0xff;
}
u8 tsconf_beta_device::data_r()
{
return pre_vg_in_check() ? m_wd179x->data_r() : 0xff;
}
u8 tsconf_beta_device::state_r()
{
if (pre_vg_in_check())
{
u8 result = 0x3f; // actually open bus
result |= m_wd179x->drq_r() ? 0x40 : 0;
result |= m_wd179x->intrq_r() ? 0x80 : 0;
return result;
}
else
{
return 0xff;
}
}
bool tsconf_beta_device::pre_vg_out_check(bool is_port_match = true)
{
if (m_dos)
{
if (m_vdos)
{
if (is_port_match)
{
m_vdos = false;
m_out_dos_cb(dos_io_r());
return false;
}
}
else if ((1 << (m_control & 3)) & m_fddvirt)
{
m_vdos = true;
m_out_dos_cb(dos_io_r());
return false;
}
}
return true;
}
void tsconf_beta_device::param_w(offs_t offset, u8 data)
{
if (pre_vg_out_check((offset & 0x60) != 0x60)) // not through 0xff
{
m_control = data;
floppy_image_device* floppy = m_floppy[data & 3]->get_device();
m_wd179x->set_floppy(floppy);
if (!m_vdos)
{
floppy->ss_w(BIT(data, 4) ? 0 : 1);
m_wd179x->dden_w(BIT(data, 6));
m_wd179x->mr_w(BIT(data, 2));
m_wd179x->hlt_w(BIT(data, 3));
motors_control();
}
}
}
void tsconf_beta_device::command_w(u8 data)
{
if (pre_vg_out_check())
{
m_wd179x->cmd_w(data);
}
}
void tsconf_beta_device::track_w(u8 data)
{
if (pre_vg_out_check())
{
m_wd179x->track_w(data);
}
}
void tsconf_beta_device::sector_w(u8 data)
{
if (pre_vg_out_check())
{
m_wd179x->sector_w(data);
}
}
void tsconf_beta_device::data_w(u8 data)
{
if (pre_vg_out_check())
{
m_wd179x->data_w(data);
}
}
void tsconf_beta_device::turbo_w(int state)
{
m_wd179x->set_clock_scale(1 << (state & 1));
}
void tsconf_beta_device::on_m1_w()
{
m_vdos = true;
m_out_dos_cb(dos_io_r());
}
void tsconf_beta_device::enable_w(bool state)
{
if ((state && !m_dos) || (!state && m_dos && !m_vdos))
{
m_dos = state;
m_out_dos_cb(dos_io_r());
}
}
void tsconf_beta_device::fddvirt_w(u8 fddvirt)
{
m_fddvirt = fddvirt & 0x0f;
}
void tsconf_beta_device::io_forced_w(bool io_forced)
{
m_io_forced = io_forced;
m_out_dos_cb(dos_io_r());
}
void tsconf_beta_device::fdc_hld_w(int state)
{
m_wd179x->set_force_ready(state); // HLD connected to RDY pin
m_motor_active = state;
motors_control();
}
void tsconf_beta_device::motors_control()
{
for (int i = 0; i < 4; i++)
{
if (m_motor_active && (m_control & 3) == i)
{
m_floppy[i]->get_device()->mon_w(CLEAR_LINE);
m_floppy_led[i] = 1;
}
else
{
m_floppy[i]->get_device()->mon_w(ASSERT_LINE);
m_floppy_led[i] = 0;
}
}
}
void tsconf_beta_device::device_start()
{
save_item(NAME(m_control));
save_item(NAME(m_motor_active));
save_item(NAME(m_dos));
save_item(NAME(m_vdos));
save_item(NAME(m_io_forced));
save_item(NAME(m_fddvirt));
m_floppy_led.resolve();
}
void tsconf_beta_device::device_reset()
{
m_control = 0;
for (int i = 0; i < m_floppy_led.size(); i++)
m_floppy_led[i] = 0;
m_dos = false;
m_vdos = false;
m_io_forced = false;
m_fddvirt = 0;
}
void tsconf_beta_device::device_add_mconfig(machine_config &config)
{
KR1818VG93(config, m_wd179x, 8_MHz_XTAL / 8);
m_wd179x->hld_wr_callback().set(FUNC(tsconf_beta_device::fdc_hld_w));
for (auto &floppy : m_floppy)
FLOPPY_CONNECTOR(config, floppy, beta_disk_floppies, "525qd", floppy_formats).enable_sound(true);
}

View File

@ -0,0 +1,72 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
#ifndef MAME_SINCLAIR_TSCONF_BETA_H
#define MAME_SINCLAIR_TSCONF_BETA_H
#pragma once
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
class tsconf_beta_device : public device_t
{
public:
tsconf_beta_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
void tsconf_beta_io(address_map &map) ATTR_COLD;
auto out_dos_callback() { return m_out_dos_cb.bind(); }
auto out_vdos_m1_callback() { return m_out_vdos_m1_cb.bind(); }
u8 status_r();
u8 track_r();
u8 sector_r();
u8 data_r();
u8 state_r();
void param_w(offs_t offset, u8 data);
void command_w(u8 data);
void track_w(u8 data);
void sector_w(u8 data);
void data_w(u8 data);
void turbo_w(int state);
void on_m1_w();
bool dos_r() { return m_dos; }
bool vdos_r() { return m_vdos; }
bool dos_io_r() { return m_dos || m_io_forced; }
void enable_w(bool state);
void fddvirt_w(u8 fddvirt);
void io_forced_w(bool io_forced);
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
devcb_write_line m_out_dos_cb;
devcb_write_line m_out_vdos_m1_cb;
private:
required_device<kr1818vg93_device> m_wd179x;
required_device_array<floppy_connector, 4> m_floppy;
output_finder<4> m_floppy_led;
void fdc_hld_w(int state);
void motors_control();
u8 m_control;
bool m_motor_active;
bool m_dos;
bool m_vdos;
bool m_io_forced;
u8 m_fddvirt;
bool pre_vg_in_check();
bool pre_vg_out_check(bool is_port_match);
};
DECLARE_DEVICE_TYPE(TSCONF_BETA, tsconf_beta_device)
#endif // MAME_SINCLAIR_TSCONF_BETA_H

View File

@ -55,13 +55,13 @@ void tsconf_state::tsconf_update_bank0()
if (!NW0_MAP) if (!NW0_MAP)
{ {
/* ROM: 0-SYS, 1-DOS, 2-128, 3-48 */ /* ROM: 0-SYS, 1-DOS, 2-128, 3-48 */
page0 = m_beta->started() && m_beta->is_active() ? ROM128 : (0x02 | ROM128); page0 &= 0xfc;
page0 |= (m_regs[PAGE0] & 0xfc); page0 |= m_beta->dos_r() ? ROM128 : (0x02 | ROM128);
} }
if (W0_RAM) if (W0_RAM || m_beta->vdos_r())
{ {
m_bank_ram[0]->set_entry(page0); m_bank_ram[0]->set_entry(m_beta->vdos_r() ? 0xff : page0);
m_bank0_rom.disable(); m_bank0_rom.disable();
} }
else else
@ -71,6 +71,12 @@ void tsconf_state::tsconf_update_bank0()
} }
} }
void tsconf_state::update_io(int dos)
{
m_io_shadow_view.select(dos ? 1 : 0);
tsconf_update_bank0();
}
void tsconf_state::tsconf_update_video_mode() void tsconf_state::tsconf_update_video_mode()
{ {
rectangle visarea = screen_area[3]; rectangle visarea = screen_area[3];
@ -399,8 +405,10 @@ void tsconf_state::ram_bank_write(u8 bank, offs_t offset, u8 data)
} }
} }
if (bank > 0 || (W0_WE && W0_RAM)) if (bank > 0 || W0_WE)
ram_page_write(m_regs[PAGE0 + bank], offset, data); ram_page_write(m_regs[PAGE0 + bank], offset, data);
else if (!bank && m_beta->vdos_r())
ram_page_write(0xff, offset, data);
} }
static int tiles_offset_to_raw(int t_offset) static int tiles_offset_to_raw(int t_offset)
@ -496,9 +504,12 @@ void tsconf_state::sfile_write16(offs_t offset, u16 data)
} }
u8 tsconf_state::tsconf_port_xx1f_r(offs_t offset) { u8 tsconf_state::tsconf_port_xx1f_r(offs_t offset) {
return m_beta->started() && m_beta->is_active() return 0x00; // TODO kempston read
? m_beta->status_r() }
: 0x00; // TODO kempston read
void tsconf_state::bank3_set_page(u8 page)
{
tsconf_port_xxaf_w(PAGE3 << 8, page);
} }
void tsconf_state::tsconf_port_7ffd_w(u8 data) void tsconf_state::tsconf_port_7ffd_w(u8 data)
@ -719,12 +730,15 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
update_frame_timer(); update_frame_timer();
break; break;
case FDD_VIRT:
m_beta->io_forced_w(BIT(data, 7));
m_beta->fddvirt_w(data & 0x0f);
break;
case FMAPS: case FMAPS:
case TS_CONFIG: case TS_CONFIG:
case INT_MASK: case INT_MASK:
case CACHE_CONFIG: case CACHE_CONFIG:
// TODO
case FDD_VIRT:
break; break;
default: default:
@ -899,7 +913,7 @@ INTERRUPT_GEN_MEMBER(tsconf_state::tsconf_vblank_interrupt)
void tsconf_state::dma_ready(int line) void tsconf_state::dma_ready(int line)
{ {
if (BIT(m_regs[INT_MASK], 2)) if (BIT(m_regs[INT_MASK], 2) && !(m_beta->vdos_r() || m_update_on_m1))
{ {
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_int_mask |= 4; m_int_mask |= 4;
@ -908,7 +922,7 @@ void tsconf_state::dma_ready(int line)
TIMER_CALLBACK_MEMBER(tsconf_state::irq_frame) TIMER_CALLBACK_MEMBER(tsconf_state::irq_frame)
{ {
if (BIT(m_regs[INT_MASK], 0)) if (BIT(m_regs[INT_MASK], 0) && !(m_beta->vdos_r() || m_update_on_m1))
{ {
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_irq_off_timer->adjust(attotime::from_ticks(32, m_maincpu->unscaled_clock())); m_irq_off_timer->adjust(attotime::from_ticks(32, m_maincpu->unscaled_clock()));
@ -918,7 +932,7 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_frame)
TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline) TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline)
{ {
if (BIT(m_regs[INT_MASK], 1)) if (BIT(m_regs[INT_MASK], 1) && !(m_beta->vdos_r() || m_update_on_m1))
{ {
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_int_mask |= 2; m_int_mask |= 2;
@ -977,6 +991,11 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline)
u8 tsconf_state::beta_neutral_r(offs_t offset) u8 tsconf_state::beta_neutral_r(offs_t offset)
{ {
if (!machine().side_effects_disabled() && m_update_on_m1)
{
m_update_on_m1 = false;
m_beta->on_m1_w();
}
return m_program.read_byte(offset); return m_program.read_byte(offset);
} }
@ -984,13 +1003,14 @@ u8 tsconf_state::beta_enable_r(offs_t offset)
{ {
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
{ {
if (!W0_RAM && m_bank_rom[0]->entry() == 3) if (m_update_on_m1)
{ {
if (m_beta->started() && !m_beta->is_active()) m_update_on_m1 = false;
{ m_beta->on_m1_w();
m_beta->enable(); }
tsconf_update_bank0(); if (ROM128 && !NW0_MAP)
} {
m_beta->enable_w(1);
} }
} }
return m_program.read_byte(offset + 0x3d00); return m_program.read_byte(offset + 0x3d00);
@ -1000,11 +1020,12 @@ u8 tsconf_state::beta_disable_r(offs_t offset)
{ {
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
{ {
if (m_beta->started() && m_beta->is_active()) if (m_update_on_m1)
{ {
m_beta->disable(); m_update_on_m1 = false;
tsconf_update_bank0(); m_beta->on_m1_w();
} }
m_beta->enable_w(0);
} }
return m_program.read_byte(offset + 0x4000); return m_program.read_byte(offset + 0x4000);
} }