Add v0.7 source

This commit is contained in:
TomW
2013-04-21 14:54:35 +01:00
commit 3c253c2cf8
188 changed files with 52566 additions and 0 deletions

339
COPYING Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

BIN
acer386.nvr Normal file

Binary file not shown.

BIN
ami286.nvr Normal file

Binary file not shown.

BIN
ami386.nvr Normal file

Binary file not shown.

BIN
ami486.nvr Normal file

Binary file not shown.

BIN
at.nvr Normal file

Binary file not shown.

BIN
cmdpc30.nvr Normal file

Binary file not shown.

BIN
dell200.nvr Normal file

Binary file not shown.

BIN
europc.nvr Normal file

Binary file not shown.

BIN
hot-433.nvr Normal file

Binary file not shown.

BIN
mda.rom Normal file

Binary file not shown.

BIN
megapc.nvr Normal file

Binary file not shown.

BIN
pc1512.nvr Normal file

Binary file not shown.

BIN
pc1640.nvr Normal file

Binary file not shown.

BIN
pc2086.nvr Normal file

Binary file not shown.

BIN
pc3086.nvr Normal file

Binary file not shown.

483
readme.txt Normal file
View File

@@ -0,0 +1,483 @@
PCem v0.7
Changes since v0.6:
- New machines - DTK XT clone, Amstrad PC2086, Amstrad PC3086, Olivetti M24, Commodore PC 30 III,
PCI 486 clone
- New graphics cards - IBM EGA, Diamond Stealth 32 (ET4000/W32p), Paradise Bahamas 64 (S3 Vision864)
- IDE hard disc emulation. This replaces the old INT 13 trapping emulation on all models. For machines
which don't natively have IDE support, the XTIDE board is emulated. See the readme file for details.
- Fixed wrong code segment on page fault - eliminates some Win95 crashes
- Fixed trap flag on POPF/IRET - improves DOS box on Win95
- Fixed various pmode stuff, OS/2 v1.3 works
- Fixed MMU caching bug, Win95 more stable, IE4 now works, Win98 now works, Linux now appears to work
- Major improvements to floppy disc emulation - fixed occasional disc corruption, works with OS/2 and Linux
- ATAPI identify command now returns an ATAPI version, Win95 native CD-ROM drivers now work.
- CD-ROM emulation now uses raw read for audio - works on Windows 7
- Major internal changes to graphics emulation
- Major internal changes to memory and IO emulation
- Many other changes
PCem emulates the following machines:
IBM 5150 PC (1981)
The original PC. This shipped in 1981 with a 4.77mhz 8088, 64k of RAM, and a cassette port.
Disc drives quickly became standard, along with more memory.
ROM files needed:
pc102782.bin
basicc11.f6
basicc11.f8
basicc11.fa
basicc11.fc
IBM 5160 XT (1983)
From a hardware perspective, this is a minor tweak of the original PC. It originally shipped
with 128k of RAM and a 10mb hard disc, both of which could be easily fitted to the 1981 machine.
However, this was targetted as businesses and was more successful than the original.
ROM files needed:
xt050986.0
xt050986.1
IBM AT (1984)
This was the 'next generation' PC, fully 16-bit with an 80286. The original model came with a 6mhz
286, which ran three times as fast as the XT. This model also introduced EGA.
ROM files needed:
at111585.0
at111585.1
Olivetti M24 (1984)
An enhanced XT clone, also known as the AT&T PC 6300. Has an 8086 CPU, and an unusual 'double-res'
CGA display.
ROM files needed:
olivetti_m24_version_1.43_low.bin
olivetti_m24_version_1.43_high.bin
Tandy 1000 (1985)
This is a clone of the unsuccessful IBM PCjr, which added better graphics and sound to the XT,
but removed much expandability plus some other hardware (such as the DMA controller). The Tandy
puts back the DMA controller and ISA slots, making it a much more useful machine. Many games
from the late 80s support the Tandy.
ROM files needed:
tandy1t1.020
DTK Clone XT (1986)
A generic clone XT board.
ROM files needed:
DTK_ERSO_2.42_2764.bin
Amstrad PC1512 (1986)
This was Amstrad's first entry into the PC clone market (after the CPC and PCW machines), and
was the first cheap PC available in the UK, selling for only <20>500. It was a 'turbo' clone,
having an 8mhz 8086, as opposed to an 8088, and had 512k RAM as standard. It also had a
perculiar modification to its onboard CGA controller - the 640x200 mode had 16 colours instead
of the usual 2. This was put to good use by GEM, which shipped with the machine.
Amstrad's CGA implementation has a few oddities, these are emulated as best as possible. This
mainly affects games defining unusual video modes, though 160x100x16 still works (as on the real
machine).
ROM files needed:
40043.v1
40044.v2
40078.ic127
Amstrad PC1640 (1987)
Amstrad's followup to the PC1512, the PC1640 had 640k of RAM and onboard EGA, but was otherwise
mostly the same.
ROM files needed:
40043.v3
40044.v3
40100
Sinclair PC200/Amstrad PC20 (1988)
This was Amstrad's entry to the 16-bit home computer market, intended to compete with the Atari
ST and Commodore Amiga. It's similar to the PC1512, but is based on Amstrad's portable PPC512
system. With stock CGA and PC speaker, it couldn't compare with the ST or Amiga.
ROM files needed:
pc20v2.0
pc20v2.1
40109.bin
Schneider Euro PC (1988)
A German XT clone. An 'all-in-one' system like the Sinclair PC200. I don't know much about this
machine to be honest! This doesn't appear to work with the XTIDE BIOS, so therefore this is the
only model that does not support hard discs.
ROM files needed:
50145
50146
(c)Anonymous Generic Turbo XT BIOS (1988?)
This is a BIOS whose source code was made available on Usenet in 1988. It appears to be an
anonymous BIOS from an XT clone board. It was then heavily modified to fix bugs. The history of
this BIOS (and the source code) is at http://dizzie.narod.ru/bios.txt
ROM files needed:
pcxt.rom
Commodore PC30-III (1988)
A fairly generic 286 clone.
ROM files needed:
commodore pc 30 iii even.bin
commodore pc 30 iii odd.bin
Amstrad PC2086 (1989)
The PC2086 is essentially a PC1640 with VGA and 3.5" floppy drives.
ROM files needed:
40179.ic129
40180.ic132
40186.ic171
Amstrad PC3086 (1990)
The PC3086 is a version of the PC2086 with a more standard case.
ROM files needed:
fc00.bin
c000.bin
Dell System 200 (1990?)
This is a pretty generic 286 clone with a Phoenix BIOS.
HIMEM.SYS doesn't appear to work on this one, for some reason.
ROM files needed:
dell0.bin
dell1.bin
AMI 286 clone (1990)
This is a generic 286 clone with an AMI BIOS.
ROM files needed:
amic206.bin
Acermate 386SX/25N (1992?)
An integrated 386SX clone, with onboard Oak SVGA and IO.
ROM files needed:
acer386.bin
oti067.bin
Amstrad MegaPC (1992)
A 386SX clone (otherwise known as the PC7386SX) with a built-in Sega Megadrive. Only the PC section
is emulated, obv.
ROM files needed:
41651-bios lo.u18
211253-bios hi.u19
AMI 386 clone (1994)
This is a generic 386 clone with an AMI BIOS. The BIOS came from my 386DX/40, the motherboard is
dated June 1994.
ROM files needed:
ami495.bin
AMI 486 clone (1993)
This is a generic 486 clone with an AMI BIOS. The BIOS came from my 486SX/25, bought in December
1993.
ROM files needed:
ami1429.bin
AMI WinBIOS 486 clone (1994)
A 486 clone with a newer AMI BIOS.
ROM files needed:
ali1429g.amw
PCI 486 clone (1994)
A 486 clone with a PCI bus - specifically, a Shuttle HOT-433 board. Due to lack of documentation
this machine has some issues - in particular, don't enable the PCI IDE emulation.
ROM files needed:
hot-433.ami
PCem emulates the following graphics adapters :
MDA - The original PC adapter. This displays 80x25 text in monochrome.
Hercules - A clone of MDA, with the addition of a high-resolution 720x348 graphics mode.
CGA - The most common of the original adapters, supporting 40x25 and 80x25 text, and
320x200 in 4 colours, 640x200 in 2 colours, and a composite mode giving 160x200 in 16 colours.
IBM EGA - The original 1984 IBM EGA card, with 256k VRAM.
Trident 8900D SVGA - A low cost SVGA board circa 1992/1993. Not the greatest board in it's day, but
it has a reasonable VESA driver and (buggy) 15/16/24-bit colour modes.
Tseng ET4000AX SVGA - A somewhat better SVGA board than the Trident, here you get better compatibility
and speed (on the real card, not the emulator) in exchange for being limited to 8-bit colour.
Diamond Stealth 32 SVGA - An ET4000/W32p based board, has 15/16/24-bit colour modes, plus acceleration.
There is an odd bug with this one, where Windows 9x DOS boxes won't open with modes beyond 8-bit
colour. Supports PCI.
Paradise Bahamas 64 - An S3 Vision864 based board. This has the best Windows drivers, but the default
VESA driver is poor. Supports PCI.
Some models have fixed graphics adapters :
Olivetti M24 - CGA with double-res text modes and a 640x400 mode. I haven't seen a dump of the font
ROM for this yet, so if one is not provided the MDA font will be used - which looks slightly odd
as it is 14-line instead of 16-line.
Tandy 1000 - CGA with various new modes - 160x200x16, 320x200x16, 640x200x4. Widely supported in 80s
games.
Amstrad PC1512 - CGA with a new mode (640x200x16). Only supported in GEM to my knowledge.
Amstrad PC1640 - Paradise EGA.
Amstrad PC2086/PC3086 - Paradise PVGA1. An early SVGA clone with 256kb VRAM.
Amstrad MegaPC - Paradise 90C11. A development of the PVGA1, with 512kb VRAM.
Acer 386SX/25N - Oak OTI-067. Another 512kb SVGA clone.
Pcem emulates the following sound devices :
PC speaker - The standard beeper on all PCs. Supports samples/RealSound.
Tandy PSG - The Texas Instruments chip in the PCjr and Tandy 1000. Supports 3 voices plus
noise. I reused the emulator in B-em for this (slightly modified).
Gameblaster - The Creative Labs Gameblaster/Creative Music System, Creative's first sound card
introduced in 1987. Has two Philips SAA1099, giving 12 voices of square waves plus 4 noise
voices. In stereo!
Adlib - Has a Yamaha YM3812, giving 9 voices of 2 op FM, or 6 voices plus a useless drum section.
PCem uses Jarek Burczynski's emulator for this.
Sound Blaster - Several Sound Blasters are emulated :
SB v1.0 - The original. Limited to 22khz, and no auto-init DMA (can cause crackles sometimes).
SB v1.5 - Adds auto-init DMA
SB v2.0 - Upped to 41khz
SB Pro v1.0 - Stereo, with twin OPL2 chips.
SB Pro v2.0 - Stereo, with OPL 3 chip
SB 16 - 16 bit stereo
All are set to Address 220, IRQ 7 and DMA 1 (and High DMA 5). IRQ and DMA can be changed for the
SB16.
The relevant SET line for autoexec.bat is
SET BLASTER = A220 I7 D1 Tx - where Tx is T1 for SB v1.0, T3 for SB v2.0, T4 for SB Pro,
and T6 for SB16.
The SB16 software seems to work (including Windows drivers), but you must stick to these settings.
Gravis Ultrasound - 32 voice sample playback. PCem's emulation of this is a bit preliminary :
- Only older ULTRASND setup programs work, ie text mode instead of graphics (3.xx?)
- MIDI playback occasionally goes wrong
- 16-bit playback only uses top 8 bits of samples
- Some games, eg later versions of Epic Pinball, have no music
- No stereo
- Some clicking in sound output
- Does work well in lots of stuff though, eg Worms, Pinball Fantasies, Zone 66 etc.
- Settings are hardwired to Address 240, IRQ 5, DMA 3. The relevant SET line for autoexec.bat is
SET ULTRASND=240,3,3,5,12
This means unlike on a real board, you don't have to run a init program on bootup for sound
to work. You do need to install the ULTRAMID patches if you want MIDI.
Other stuff emulated :
Serial mouse - A Microsoft compatible serial mouse on COM1. Compatible drivers are all over the
place for this.
M24 mouse - I haven't seen a DOS mouse driver for this yet, but the regular scancode mode works, as
does the Windows 1.x driver.
PC1512 mouse - The PC1512's perculiar quadrature mouse. You need Amstrad's actual driver for this
one.
PS/2 mouse - A PS/2 mouse is emulated on the MegaPC and 386SX/25N model. As with serial, compatible
drivers are common.
ATAPI CD-ROM - Works with OAKCDROM.SYS and Windows 9x. It can only work with actual CD-ROM drives
at the minute, so to use ISO images you need a virtual CD drive.
XTIDE :
The XTIDE board is emulated for machines that don't natively support IDE hard discs.
You will need to download the XTIDE BIOS seperately. Of the various versions, ide_at.bin and ide_xt.bin
should be placed in the ROMS directory. ide_xt is used on all XT models, and ide_at is used on the IBM AT
and Commodore PC30-III machines.
The BIOS is available at :
http://code.google.com/p/xtideuniversalbios/
v2.0.0 beta 1 is the only version that has been tested.
Notes :
- The AT and AMI 286 both fail part of their self test. This doesn't really affect anything,
just puts an irritating message on the screen.
- The time on the PC1512 clock is wrong. The date is correct, though since the PC1512's bios isn't
Y2k compliant, it thinks it's 1988.
- The envelope system on the Gameblaster isn't emulated. The noise may not be right either.
- Some of the more unusual VGA features are not emulated. I haven't found anything that uses them yet.
- Windows 3.x should work okay in all modes now.
- Windows 95/98 run, with the following caveats :
- Mouse is not detected. Strangely, it still works - except during setup, when it stops working at one point.
Sometimes running the 'Add New Hardware' wizard a couple of times will find it.
- The default Trident driver only allows 16 and 256 colour modes. There is an alternative driver which enables
high and true colour modes, but it doesn't work with DirectX.
- Setup sometimes crashes in the first stage (during file copying). This appears to be a side effect of the
bugs fixed making OS/2 work. Unfortunately I haven't been able to eliminate this issue.
- OS/2 1.3 seems to work okay, but I haven't tested it very thoroughly.
- Linux appears to work. fdlinux runs okay, but is relatively useless. SuSE 6.3 seemed mostly okay, but I only
had the first disc of 6 when testing, so I didn't get very far.
- Windows NT does not work at all.
Software tested:
I removed most of this, and only put the stuff I actually tested on this release.
Booter games :
King's Quest (Tandy)
King's Quest (CGA)
DOS stuff :
MS-DOS 3.30
PC-DOS 3.30
PC-DOS 5.02
MS-DOS 6.22
- Most of the supplied software seems to work, eg Drivespace, Defrag, Scandisk, QBASIC
etc
OS/2 v1.3
Windows 3.0 (CGA, Hercules, EGA, VGA) (real and standard modes only)
Windows 3.1 (VGA, SVGA) (standard & enhanced modes)
Windows 95
Windows 98
Works for Windows 3.0
Microsoft Arcade
Internet Explorer 4
Jill of the Jungle (CGA,EGA,VGA)
Tetris
Zak McKraken (CGA, Tandy)
Brix (VGA)
Commander Keen 4 (EGA)
Duke Nukem 2 (VGA)
Heartlight (VGA)
Jetpack (VGA)
Cascada - Cronologia (VGA)
EMF - Verses
Renaissance - Amnesia
Future Crew - Second Reality
386/486 stuff :
Jungle Strike (EMM386)
Dawn Patrol (EMM386) (use ET4000 driver)
Doom
Doom 2
Duke Nukem 3D
Heretic
Hexen
Jazz Jackrabbit
Rise of the Triad
Simcity 2000
Terminal Velocity
Tyrian
Trasnport Tycoon
Transport Tycoon Deluxe
X-Com : Terror From The Deep
Theme Hospital - DOS and Windows versions
Zone 66 (don't use DOS 6.22)
Pro Pinball : Timeshock
Actua Soccer
Grand Theft Auto
Jazz Jackrabbit 2
Magic Carpet
Network Q RAC Rally
Quake
WinQuake
Quake 2 (SLOW - unsurprisingly)
Tomb Raider
Screamer
Screamer Rally
Virtual Pool (accelerated drivers work with both S3 and ET4000/W32)
Jedi Knight
Command & Conquer : Red Alert
Simcity 2000
ZSNES
Genecyst
Kgen98

1
roms/acer386/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/ami286/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/ami386/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/ami486/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/cmdpc30/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/dells200/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/dtk/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/europc/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/genxt/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/hot-433/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/ibmat/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/ibmpc/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/ibmxt/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/megapc/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/pc1512/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/pc1640/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/pc200/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/pc2086/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/pc3086/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/tandy/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

1
roms/win486/roms.txt Normal file
View File

@@ -0,0 +1 @@
This directory needs to contain some ROM files.

3787
src/286.c Normal file

File diff suppressed because it is too large Load Diff

8377
src/386.c Normal file

File diff suppressed because it is too large Load Diff

43
src/Makefile.mingw Normal file
View File

@@ -0,0 +1,43 @@
VPATH = . mame
CPP = g++.exe
CC = gcc.exe
WINDRES = windres.exe
CFLAGS = -O3 -march=i686 -fomit-frame-pointer
OBJ = 286.o 386.o acer386sx.o adlib.o ali1429.o amstrad.o cdrom-ioctl.o cms.o \
config.o cpu.o dac.o dma.o ega.o fdc.o gus.o harddisk.o \
headland.o ide.o io.o jim.o keyboard.o keyboard_amstrad.o keyboard_at.o \
keyboard_olim24.o keyboard_xt.o lpt.o mcr.o mem.o model.o \
mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \
opti.o pc.o pci.o pic.o pit.o \
ppi.o psg.o sblaster.o serial.o sound.o soundopenal.o um8881f.o \
vid_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \
vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_mda.o vid_olivetti_m24.o \
vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o \
vid_pc200.o vid_s3.o vid_sdac_ramdac.o vid_stg_ramdac.o \
vid_svga.o vid_tandy.o vid_tkd8001_ramdac.o vid_tvga.o \
vid_unk_ramdac.o video.o wd76c10.o win.o win-ddraw.o \
win-keyboard.o win-mouse.o win-timer.o win-video.o x86.o \
x86seg.o x87.o xtide.o pc.res
FMOBJ = fmopl.o ymf262.o
LIBS = -mwindows -lwinmm -lalut -lopenal32 -lddraw -ldinput -ldxguid
PCem.exe: $(OBJ) $(FMOBJ)
$(CC) $(OBJ) $(FMOBJ) -o "PCem.exe" $(LIBS)
all : PCem.exe
clean :
del *.o
del *.exe
del *.res
%.o : %.c
$(CC) $(CFLAGS) -c $<
%.o : %.cc
$(CPP) $(CFLAGS) -c $<
pc.res: pc.rc
$(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff

33
src/acer386sx.c Normal file
View File

@@ -0,0 +1,33 @@
#include "ibm.h"
#include "io.h"
#include "cpu.h"
#include "acer386sx.h"
static int acer_index = 0;
static uint8_t acer_regs[256];
void acer386sx_write(uint16_t addr, uint8_t val)
{
if (addr & 1)
acer_regs[acer_index] = val;
else
acer_index = val;
}
uint8_t acer386sx_read(uint16_t addr)
{
if (addr & 1)
{
if ((acer_index >= 0xc0 || acer_index == 0x20) && cpu_iscyrix)
return 0xff; /*Don't conflict with Cyrix config registers*/
return acer_regs[acer_index];
}
else
return acer_index;
}
void acer386sx_init()
{
io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL);
}

1
src/acer386sx.h Normal file
View File

@@ -0,0 +1 @@
void acer386sx_init();

187
src/adlib.c Normal file
View File

@@ -0,0 +1,187 @@
#include <stdint.h>
#include <stdlib.h>
#include "ibm.h"
#include "mame/fmopl.h"
#include "mame/ymf262.h"
/*Interfaces between PCem and the actual Adlib emulator*/
static int adlib_inited = 0;
int adlibpos=0;
void *YM3812[2];
void *YMF262;
int fm_timers[2][2],fm_timers_enable[2][2];
void adlib_write(uint16_t a, uint8_t v)
{
// printf("Adlib write %04X %02X %i\n",a,v,sbtype);
if (!sbtype) return;
if (sbtype<SBPRO && a<0x224) return;
switch (a)
{
case 0x220: case 0x221:
if (sbtype<SBPRO2) ym3812_write(YM3812[0],a,v);
else ymf262_write(YMF262,a,v);
break;
case 0x222: case 0x223:
if (sbtype<SBPRO2) ym3812_write(YM3812[1],a,v);
else ymf262_write(YMF262,a,v);
break;
case 0x228: case 0x229: case 0x388: case 0x389:
if (sbtype<SBPRO2)
{
ym3812_write(YM3812[0],a,v);
ym3812_write(YM3812[1],a,v);
}
else
ymf262_write(YMF262,a,v);
break;
}
}
uint8_t adlib_read(uint16_t a)
{
uint8_t temp;
// printf("Adlib read %04X\n",a);
if (sbtype>=SBPRO2)
{
switch (a)
{
case 0x220: case 0x221:
case 0x222: case 0x223:
case 0x228: case 0x229:
case 0x388: case 0x389:
temp=ymf262_read(YMF262,a);
// pclog("YMF262 read %03X %02X\n",a,temp);
cycles-=(int)(isa_timing * 8);
return temp;
}
}
if (!sbtype) return 0xFF;
switch (a)
{
case 0x220: case 0x221:
if (sbtype<SBPRO) return 0xFF;
case 0x228: case 0x229:
case 0x388: case 0x389:
cycles-=(int)(isa_timing * 8);
return ym3812_read(YM3812[0],a);
case 0x222: case 0x223:
if (sbtype<SBPRO) return 0xFF;
return ym3812_read(YM3812[1],a);
}
/* if (sbtype<SBPRO && a<0x224) return 0xFF;
if (a==0x222) return adlibstat2;
if (!(a&1)) return adlibstat;
return 0;*/
}
signed short *ad_bufs[4];
int16_t ad_filtbuf[2]={0,0};
void getadlib(signed short *bufl, signed short *bufr, int size)
{
int c;
if (sbtype>=SBPRO2)
{
ymf262_update_one(YMF262,ad_bufs,size);
for (c=0;c<size;c++)
{
ad_filtbuf[0]=bufl[c]=(ad_bufs[0][c]/4)+((ad_filtbuf[0]*11)/16);
ad_filtbuf[1]=bufr[c]=(ad_bufs[1][c]/4)+((ad_filtbuf[1]*11)/16);
}
if (fm_timers_enable[0][0])
{
fm_timers[0][0]--;
if (fm_timers[0][0]<0) ymf262_timer_over(YMF262,0);
}
if (fm_timers_enable[0][1])
{
fm_timers[0][1]--;
if (fm_timers[0][1]<0) ymf262_timer_over(YMF262,1);
}
}
else
{
ym3812_update_one(YM3812[0],bufl,size);
ym3812_update_one(YM3812[1],bufr,size);
for (c=0;c<size;c++)
{
ad_filtbuf[0]=bufl[c]=(bufl[c]/4)+((ad_filtbuf[0]*11)/16);
ad_filtbuf[1]=bufr[c]=(bufr[c]/4)+((ad_filtbuf[1]*11)/16);
}
if (fm_timers_enable[0][0])
{
fm_timers[0][0]--;
if (fm_timers[0][0]<0) ym3812_timer_over(YM3812[0],0);
}
if (fm_timers_enable[0][1])
{
fm_timers[0][1]--;
if (fm_timers[0][1]<0) ym3812_timer_over(YM3812[0],1);
}
if (fm_timers_enable[1][0])
{
fm_timers[1][0]--;
if (fm_timers[1][0]<0) ym3812_timer_over(YM3812[1],0);
}
if (fm_timers_enable[1][1])
{
fm_timers[1][1]--;
if (fm_timers[1][1]<0) ym3812_timer_over(YM3812[1],1);
}
}
// for (c=0;c<size;c++) buf[c]/=2;
}
void ym3812_timer_set_0(void *param,int timer,attotime period)
{
fm_timers[0][timer]=period/20833;
if (!fm_timers[0][timer]) fm_timers[0][timer]=1;
fm_timers_enable[0][timer]=(period)?1:0;
}
void ym3812_timer_set_1(void *param,int timer,attotime period)
{
fm_timers[1][timer]=period/20833;
if (!fm_timers[1][timer]) fm_timers[1][timer]=1;
fm_timers_enable[1][timer]=(period)?1:0;
}
void ymf262_timer_set(void *param,int timer,attotime period)
{
fm_timers[0][timer]=period/20833;
if (!fm_timers[0][timer]) fm_timers[0][timer]=1;
fm_timers_enable[0][timer]=(period)?1:0;
}
void adlib_init()
{
if (!adlib_inited)
{
ad_bufs[0]=(signed short *)malloc(48000);
ad_bufs[1]=(signed short *)malloc(48000);
ad_bufs[2]=(signed short *)malloc(48000);
ad_bufs[3]=(signed short *)malloc(48000);
YM3812[0]=ym3812_init((void *)NULL,3579545,48000);
ym3812_reset_chip(YM3812[0]);
ym3812_set_timer_handler(YM3812[0],ym3812_timer_set_0,NULL);
YM3812[1]=ym3812_init((void *)NULL,3579545,48000);
ym3812_reset_chip(YM3812[1]);
ym3812_set_timer_handler(YM3812[1],ym3812_timer_set_1,NULL);
YMF262=ymf262_init((void *)NULL,3579545*4,48000);
ymf262_reset_chip(YMF262);
ymf262_set_timer_handler(YMF262,ymf262_timer_set,NULL);
}
adlib_inited = 1;
io_sethandler(0x0388, 0x0002, adlib_read, NULL, NULL, adlib_write, NULL, NULL);
}
void adlib_reset()
{
ym3812_reset_chip(YM3812[0]);
ym3812_reset_chip(YM3812[1]);
ymf262_reset_chip(YMF262);
}

76
src/ali1429.c Normal file
View File

@@ -0,0 +1,76 @@
#include <string.h>
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "cpu.h"
#include "ali1429.h"
static int ali1429_index;
static uint8_t ali1429_regs[256];
void ali1429_write(uint16_t port, uint8_t val)
{
// return;
if (!(port&1)) ali1429_index=val;
else
{
ali1429_regs[ali1429_index]=val;
// pclog("ALI1429 write %02X %02X %04X:%04X %i\n",ali1429_index,val,CS,pc,ins);
switch (ali1429_index)
{
case 0x13:
/* if (val == 1)
{
times = 1;
ins = 0;
output = 3;
}*/
// pclog("write 13 %02X %i\n",val,shadowbios);
if (!(val&0xC0))
{
shadowbios=0;
if (!shadowbios_write)
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL );
else
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml);
flushmmucache();
}
break;
case 0x14:
shadowbios=val&1;//((val&3)==1);
shadowbios_write=val&2;
switch (val & 3)
{
case 0: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL ); break;
case 1: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL ); break;
case 2: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); break;
case 3: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); break;
}
// if (val==0x43) shadowbios=1;
// pclog("Shadow bios %i\n",shadowbios);
flushmmucache();
break;
}
}
}
uint8_t ali1429_read(uint16_t port)
{
if (!(port&1)) return ali1429_index;
if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix)
return 0xff; /*Don't conflict with Cyrix config registers*/
return ali1429_regs[ali1429_index];
}
void ali1429_reset()
{
memset(ali1429_regs,0xFF,256);
}
void ali1429_init()
{
io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL);
}

1
src/ali1429.h Normal file
View File

@@ -0,0 +1 @@
void ali1429_init();

84
src/amstrad.c Normal file
View File

@@ -0,0 +1,84 @@
#include "ibm.h"
#include "io.h"
#include "keyboard.h"
#include "lpt.h"
#include "mouse.h"
#include "amstrad.h"
static uint8_t amstrad_dead;
uint8_t amstrad_read(uint16_t port)
{
pclog("amstrad_read : %04X\n",port);
switch (port)
{
case 0x379:
return 7 | readdacfifo();
case 0x37a:
if (romset == ROM_PC1512) return 0x20;
if (romset == ROM_PC200) return 0x80;
return 0;
case 0xdead:
return amstrad_dead;
}
return 0xff;
}
void amstrad_write(uint16_t port, uint8_t val)
{
switch (port)
{
case 0xdead:
amstrad_dead = val;
break;
}
}
static uint8_t mousex,mousey;
void amstrad_mouse_write(uint16_t addr, uint8_t val)
{
// pclog("Write mouse %04X %02X %04X:%04X\n", addr, val, CS, pc);
if (addr==0x78) mousex=0;
else mousey=0;
}
uint8_t amstrad_mouse_read(uint16_t addr)
{
uint8_t temp;
// printf("Read mouse %04X %04X:%04X %02X\n", addr, CS, pc, (addr == 0x78) ? mousex : mousey);
if (addr==0x78) return mousex;
return mousey;
}
static int oldb = 0;
void amstrad_mouse_poll(int x, int y, int b)
{
mousex += x;
mousey += y;
if ((b & 1) && !(oldb & 1))
keyboard_send(0x7e);
if ((b & 2) && !(oldb & 2))
keyboard_send(0x7d);
if (!(b & 1) && (oldb & 1))
keyboard_send(0xfe);
if (!(b & 2) && (oldb & 2))
keyboard_send(0xfd);
oldb = b;
}
void amstrad_init()
{
lpt2_remove();
io_sethandler(0x0078, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL);
io_sethandler(0x007a, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL);
io_sethandler(0x0379, 0x0002, amstrad_read, NULL, NULL, NULL, NULL, NULL);
io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL);
mouse_poll = amstrad_mouse_poll;
}

2
src/amstrad.h Normal file
View File

@@ -0,0 +1,2 @@
void amstrad_init();

475
src/cdrom-ioctl.c Normal file
View File

@@ -0,0 +1,475 @@
/*Win32 CD-ROM support via IOCTL*/
#include <windows.h>
#include <io.h>
#include "ddk/ntddcdrm.h"
//#include "ntddcdrm.h"
#include "ibm.h"
#include "ide.h"
#include "cdrom-ioctl.h"
int cdrom_drive;
typedef struct _CDROM_TOC_SESSION_DATA {
UCHAR Length[2];
UCHAR FirstCompleteSession;
UCHAR LastCompleteSession;
TRACK_DATA TrackData[1];
} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA;
static ATAPI ioctl_atapi;
static int ioctl_inited = 0;
static char ioctl_path[8];
static void ioctl_close(void);
static HANDLE hIOCTL;
static CDROM_TOC toc;
static int tocvalid = 0;
#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150)
enum
{
CD_STOPPED = 0,
CD_PLAYING,
CD_PAUSED
};
static int ioctl_cd_state = CD_STOPPED;
static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0;
#define BUF_SIZE 32768
static int16_t cd_buffer[BUF_SIZE];
static int cd_buflen = 0;
void ioctl_audio_callback(int16_t *output, int len)
{
RAW_READ_INFO in;
DWORD count;
int c;
// return;
// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount());
if (ioctl_cd_state != CD_PLAYING)
{
memset(output, 0, len * 2);
return;
}
while (cd_buflen < len)
{
if (ioctl_cd_pos < ioctl_cd_end)
{
in.DiskOffset.LowPart = ioctl_cd_pos * 2048;
in.DiskOffset.HighPart = 0;
in.SectorCount = 1;
in.TrackMode = CDDA;
ioctl_open(0);
// pclog("Read to %i\n", cd_buflen);
if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL))
{
// pclog("DeviceIoControl returned false\n");
memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
ioctl_cd_state = CD_STOPPED;
cd_buflen = len;
}
else
{
// pclog("DeviceIoControl returned true\n");
ioctl_cd_pos++;
cd_buflen += (2352 / 2);
}
ioctl_close();
}
else
{
memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2);
ioctl_cd_state = CD_STOPPED;
cd_buflen = len;
}
}
memcpy(output, cd_buffer, len * 2);
// for (c = 0; c < BUF_SIZE - len; c++)
// cd_buffer[c] = cd_buffer[c + cd_buflen];
memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2);
cd_buflen -= len;
// pclog("Done %i\n", GetTickCount());
}
void ioctl_audio_stop()
{
ioctl_cd_state = CD_STOPPED;
}
static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf)
{
if (!cdrom_drive) return;
pclog("Play audio - %08X %08X %i\n", pos, len, ismsf);
if (ismsf)
{
pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60);
len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60);
pclog("MSF - pos = %08X len = %08X\n", pos, len);
}
else
len += pos;
ioctl_cd_pos = pos;// + 150;
ioctl_cd_end = len;// + 150;
ioctl_cd_state = CD_PLAYING;
pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len);
/* CDROM_PLAY_AUDIO_MSF msf;
long size;
BOOL b;
if (ismsf)
{
msf.StartingF=pos&0xFF;
msf.StartingS=(pos>>8)&0xFF;
msf.StartingM=(pos>>16)&0xFF;
msf.EndingF=len&0xFF;
msf.EndingS=(len>>8)&0xFF;
msf.EndingM=(len>>16)&0xFF;
}
else
{
msf.StartingF=(uint8_t)(addr%75); addr/=75;
msf.StartingS=(uint8_t)(addr%60); addr/=60;
msf.StartingM=(uint8_t)(addr);
addr=pos+len+150;
msf.EndingF=(uint8_t)(addr%75); addr/=75;
msf.EndingS=(uint8_t)(addr%60); addr/=60;
msf.EndingM=(uint8_t)(addr);
}
ioctl_open(0);
b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
pclog("DeviceIoControl returns %i\n", (int) b);
ioctl_close();*/
}
static void ioctl_pause(void)
{
long size;
if (!cdrom_drive) return;
if (ioctl_cd_state == CD_PLAYING)
ioctl_cd_state = CD_PAUSED;
// ioctl_open(0);
// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL);
// ioctl_close();
}
static void ioctl_resume(void)
{
long size;
if (!cdrom_drive) return;
if (ioctl_cd_state == CD_PAUSED)
ioctl_cd_state = CD_PLAYING;
// ioctl_open(0);
// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL);
// ioctl_close();
}
static void ioctl_stop(void)
{
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
// ioctl_open(0);
// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL);
// ioctl_close();
}
static void ioctl_seek(uint32_t pos)
{
long size;
if (!cdrom_drive) return;
// ioctl_cd_state = CD_STOPPED;
pclog("Seek %08X\n", pos);
ioctl_cd_pos = pos;
ioctl_cd_state = CD_STOPPED;
/* pos+=150;
CDROM_SEEK_AUDIO_MSF msf;
msf.F=(uint8_t)(pos%75); pos/=75;
msf.S=(uint8_t)(pos%60); pos/=60;
msf.M=(uint8_t)(pos);
// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F);
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL);
ioctl_close();*/
}
static int ioctl_ready(void)
{
long size;
int temp;
CDROM_TOC ltoc;
// pclog("Ready? %i\n",cdrom_drive);
if (!cdrom_drive) return 0;
ioctl_open(0);
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&ltoc,sizeof(ltoc),&size,NULL);
ioctl_close();
if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) ||
(ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) ||
(ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) ||
!tocvalid)
{
ioctl_cd_state = CD_STOPPED;
/* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3],
toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/
// atapi_discchanged();
/* ioctl_open(0);
temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
ioctl_close();*/
toc=ltoc;
tocvalid=1;
return 0;
}
// pclog("IOCTL says ready\n");
return 1;
// return (temp)?1:0;
}
static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf)
{
CDROM_SUB_Q_DATA_FORMAT insub;
SUB_Q_CHANNEL_DATA sub;
long size;
int pos=0;
int c;
uint32_t temp, cdpos;
if (!cdrom_drive) return 0;
insub.Format = IOCTL_CDROM_CURRENT_POSITION;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL);
ioctl_close();
b[pos++]=sub.CurrentPosition.Control;
b[pos++]=sub.CurrentPosition.TrackNumber;
b[pos++]=sub.CurrentPosition.IndexNumber;
/* pclog("Read subchannel %02X %02X %02X %02X%02X%02X%02X %02X%02X%02X%02X\n",sub.CurrentPosition.Control,sub.CurrentPosition.TrackNumber,sub.CurrentPosition.IndexNumber,
sub.CurrentPosition.AbsoluteAddress[0],sub.CurrentPosition.AbsoluteAddress[1],sub.CurrentPosition.AbsoluteAddress[2],sub.CurrentPosition.AbsoluteAddress[3],
sub.CurrentPosition.TrackRelativeAddress[0],sub.CurrentPosition.TrackRelativeAddress[1],sub.CurrentPosition.TrackRelativeAddress[2],sub.CurrentPosition.TrackRelativeAddress[3]);*/
cdpos = ioctl_cd_pos;
if (msf)
{
b[pos++] = (uint8_t)(cdpos % 75); cdpos /= 75;
b[pos++] = (uint8_t)(cdpos % 60); cdpos /= 60;
b[pos++] = (uint8_t)cdpos;
b[pos++] = 0;
b[pos++] = (uint8_t)(cdpos % 75); cdpos /= 75;
b[pos++] = (uint8_t)(cdpos % 60); cdpos /= 60;
b[pos++] = (uint8_t)cdpos;
b[pos++] = 0;
// for (c=0;c<4;c++) b[pos++]=sub.CurrentPosition.AbsoluteAddress[c];
// for (c=0;c<4;c++) b[pos++]=sub.CurrentPosition.TrackRelativeAddress[c];
}
else
{
b[pos++] = cdpos & 0xff;
b[pos++] = (cdpos >> 8) & 0xff;
b[pos++] = (cdpos >> 16) & 0xff;
b[pos++] = (cdpos >> 24) & 0xff;
b[pos++] = cdpos & 0xff;
b[pos++] = (cdpos >> 8) & 0xff;
b[pos++] = (cdpos >> 16) & 0xff;
b[pos++] = (cdpos >> 24) & 0xff;
/* temp=MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1],sub.CurrentPosition.AbsoluteAddress[2],sub.CurrentPosition.AbsoluteAddress[3]);
b[pos++]=temp>>24;
b[pos++]=temp>>16;
b[pos++]=temp>>8;
b[pos++]=temp;
temp=MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1],sub.CurrentPosition.TrackRelativeAddress[2],sub.CurrentPosition.TrackRelativeAddress[3]);
b[pos++]=temp>>24;
b[pos++]=temp>>16;
b[pos++]=temp>>8;
b[pos++]=temp;*/
}
if (ioctl_cd_state == CD_PLAYING) return 0x11;
if (ioctl_cd_state == CD_PAUSED) return 0x12;
return 0x13;
// return sub.CurrentPosition.Header.AudioStatus;
}
static void ioctl_eject(void)
{
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL);
ioctl_close();
}
static void ioctl_load(void)
{
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL);
ioctl_close();
}
static void ioctl_readsector(uint8_t *b, int sector)
{
LARGE_INTEGER pos;
long size;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
pos.QuadPart=sector*2048;
ioctl_open(0);
SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN);
ReadFile(hIOCTL,b,2048,&size,NULL);
ioctl_close();
}
static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single)
{
int len=4;
long size;
int c,d;
uint32_t temp;
if (!cdrom_drive) return 0;
ioctl_cd_state = CD_STOPPED;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL);
ioctl_close();
tocvalid=1;
// pclog("Read TOC done! %i\n",single);
b[2]=toc.FirstTrack;
b[3]=toc.LastTrack;
d=0;
for (c=0;c<=toc.LastTrack;c++)
{
if (toc.TrackData[c].TrackNumber>=starttrack)
{
d=c;
break;
}
}
b[2]=toc.TrackData[c].TrackNumber;
for (c=d;c<=toc.LastTrack;c++)
{
if ((len+8)>maxlen) break;
// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));
b[len++]=0; /*Reserved*/
b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control;
b[len++]=toc.TrackData[c].TrackNumber;
b[len++]=0; /*Reserved*/
if (msf)
{
b[len++]=toc.TrackData[c].Address[0];
b[len++]=toc.TrackData[c].Address[1];
b[len++]=toc.TrackData[c].Address[2];
b[len++]=toc.TrackData[c].Address[3];
}
else
{
temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
b[len++]=temp>>24;
b[len++]=temp>>16;
b[len++]=temp>>8;
b[len++]=temp;
}
if (single) break;
}
b[0] = (uint8_t)(((len-2) >> 8) & 0xff);
b[1] = (uint8_t)((len-2) & 0xff);
/* pclog("Table of Contents (%i bytes) : \n",size);
pclog("First track - %02X\n",toc.FirstTrack);
pclog("Last track - %02X\n",toc.LastTrack);
for (c=0;c<=toc.LastTrack;c++)
pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]);
for (c=0;c<=toc.LastTrack;c++)
pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/
return len;
}
static void ioctl_readtoc_session(unsigned char *b, int msf, int maxlen)
{
int len=4;
int size;
uint32_t temp;
CDROM_READ_TOC_EX toc_ex;
CDROM_TOC_SESSION_DATA toc;
if (!cdrom_drive) return;
ioctl_cd_state = CD_STOPPED;
memset(&toc_ex,0,sizeof(toc_ex));
memset(&toc,0,sizeof(toc));
toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION;
toc_ex.Msf=msf;
toc_ex.SessionTrack=0;
ioctl_open(0);
DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL);
ioctl_close();
// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber);
b[2]=toc.FirstCompleteSession;
b[3]=toc.LastCompleteSession;
b[len++]=0; /*Reserved*/
b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control;
b[len++]=toc.TrackData[0].TrackNumber;
b[len++]=0; /*Reserved*/
if (msf)
{
b[len++]=toc.TrackData[0].Address[0];
b[len++]=toc.TrackData[0].Address[1];
b[len++]=toc.TrackData[0].Address[2];
b[len++]=toc.TrackData[0].Address[3];
}
else
{
temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]);
b[len++]=temp>>24;
b[len++]=temp>>16;
b[len++]=temp>>8;
b[len++]=temp;
}
}
int ioctl_open(char d)
{
// char s[8];
if (!ioctl_inited)
{
sprintf(ioctl_path,"\\\\.\\%c:",d);
pclog("Path is %s\n",ioctl_path);
tocvalid=0;
}
// pclog("Opening %s\n",ioctl_path);
hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
if (!hIOCTL)
{
//fatal("IOCTL");
}
atapi=&ioctl_atapi;
if (!ioctl_inited)
{
ioctl_inited=1;
CloseHandle(hIOCTL);
}
return 0;
}
static void ioctl_close(void)
{
CloseHandle(hIOCTL);
}
static void ioctl_exit(void)
{
ioctl_stop();
ioctl_inited=0;
tocvalid=0;
}
static ATAPI ioctl_atapi=
{
ioctl_ready,
ioctl_readtoc,
ioctl_readtoc_session,
ioctl_getcurrentsubchannel,
ioctl_readsector,
ioctl_playaudio,
ioctl_seek,
ioctl_load,
ioctl_eject,
ioctl_pause,
ioctl_resume,
ioctl_stop,
ioctl_exit
};

9
src/cdrom-ioctl.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef CDROM_IOCTL_H
#define CDROM_IOCTL_H
/* this header file lists the functions provided by
various platform specific cdrom-ioctl files */
extern int ioctl_open(char d);
#endif /* ! CDROM_IOCTL_H */

141
src/cms.c Normal file
View File

@@ -0,0 +1,141 @@
#include <stdio.h>
#include "ibm.h"
int cmsaddrs[2];
uint8_t cmsregs[2][32];
uint16_t cmslatch[12],cmsnoisefreq[12];
int cmsfreq[12];
float cmscount[12];
int cmsvol[12][2];
int cmsstat[12];
uint16_t cmsnoise[4];
int cmsnoisecount[4];
int cmsnoisetype[4];
#define CMSCONST (62500.0/44100.0)
void getcms(signed short *p, int size)
{
int c,d;
int ena[12],noiseena[12];
for (c=0;c<6;c++)
{
ena[c]=(cmsregs[0][0x14]&(1<<c));
ena[c+6]=(cmsregs[1][0x14]&(1<<c));
}
if (!(cmsregs[0][0x1C]&1))
{
for (c=0;c<6;c++) ena[c]=0;
}
if (!(cmsregs[1][0x1C]&1))
{
for (c=0;c<6;c++) ena[c+6]=0;
}
for (c=0;c<6;c++)
{
noiseena[c]=(cmsregs[0][0x15]&(1<<c));
noiseena[c+6]=(cmsregs[1][0x15]&(1<<c));
}
if (!(cmsregs[0][0x1C]&1))
{
for (c=0;c<6;c++) noiseena[c]=0;
}
if (!(cmsregs[1][0x1C]&1))
{
for (c=0;c<6;c++) noiseena[c+6]=0;
}
for (c=0;c<4;c++)
{
switch (cmsnoisetype[c])
{
case 0: cmsnoisefreq[c]=31250; break;
case 1: cmsnoisefreq[c]=15625; break;
case 2: cmsnoisefreq[c]=7812; break;
case 3: cmsnoisefreq[c]=cmsfreq[c*3]; break;
}
}
for (c=0;c<(size<<1);c+=2)
{
p[c]=0;
p[c+1]=0;
for (d=0;d<12;d++)
{
if (ena[d])
{
if (cmsstat[d]) p[c] +=(cmsvol[d][0]*90);
if (cmsstat[d]) p[c+1]+=(cmsvol[d][1]*90);
cmscount[d]+=cmsfreq[d];
if (cmscount[d]>=(22050))
{
cmscount[d]-=(22050);
cmsstat[d]^=1;
}
}
else if (noiseena[d])
{
if (cmsnoise[d/3]&1) p[c] +=(cmsvol[d][0]*90);
if (cmsnoise[d/3]&1) p[c+1]+=(cmsvol[d][0]*90);
}
}
for (d=0;d<4;d++)
{
cmsnoisecount[d]+=cmsnoisefreq[d];
while (cmsnoisecount[d]>=22050)
{
cmsnoisecount[d]-=22050;
cmsnoise[d]<<=1;
if (!(((cmsnoise[d]&0x4000)>>8)^(cmsnoise[d]&0x40))) cmsnoise[d]|=1;
}
}
}
}
void writecms(uint16_t addr, uint8_t val)
{
int voice;
int chip=(addr&2)>>1;
if (addr&1)
cmsaddrs[chip]=val&31;
else
{
cmsregs[chip][cmsaddrs[chip]&31]=val;
switch (cmsaddrs[chip]&31)
{
case 0x00: case 0x01: case 0x02: /*Volume*/
case 0x03: case 0x04: case 0x05:
voice=cmsaddrs[chip]&7;
if (chip) voice+=6;
cmsvol[voice][0]=val&0xF;//((val&0xF)+(val>>4))>>1;
cmsvol[voice][1]=val>>4;
break;
case 0x08: case 0x09: case 0x0A: /*Frequency*/
case 0x0B: case 0x0C: case 0x0D:
voice=cmsaddrs[chip]&7;
if (chip) voice+=6;
cmslatch[voice]=(cmslatch[voice]&0x700)|val;
cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255));
break;
case 0x10: case 0x11: case 0x12: /*Octave*/
voice=(cmsaddrs[chip]&3)<<1;
if (chip) voice+=6;
cmslatch[voice]=(cmslatch[voice]&0xFF)|((val&7)<<8);
cmslatch[voice+1]=(cmslatch[voice+1]&0xFF)|((val&0x70)<<4);
cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255));
cmsfreq[voice+1]=(15625<<(cmslatch[voice+1]>>8))/(511-(cmslatch[voice+1]&255));
break;
case 0x16: /*Noise*/
voice=chip*2;
cmsnoisetype[voice]=val&3;
cmsnoisetype[voice+1]=(val>>4)&3;
break;
}
}
}
uint8_t readcms(uint16_t addr)
{
int chip=(addr&2)>>1;
if (addr&1) return cmsaddrs[chip];
return cmsregs[chip][cmsaddrs[chip]&31];
}

166
src/config.c Normal file
View File

@@ -0,0 +1,166 @@
#include <stdio.h>
#include <string.h>
#include "config.h"
static char config_file[256];
void set_config_file(char *s)
{
strcpy(config_file, s);
}
void config_new()
{
FILE *f = fopen(config_file, "wt");
fclose(f);
}
int get_config_int(char *head, char *name, int def)
{
char buffer[256];
char name2[256];
FILE *f = fopen(config_file, "rt");
int c, d;
int res = def;
if (!f)
return def;
pclog("Searching for %s\n", name);
while (1)
{
fgets(buffer, 255, f);
if (feof(f)) break;
c = d = 0;
while (buffer[c] == ' ' && buffer[c])
c++;
if (!buffer[c]) continue;
while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c])
name2[d++] = buffer[c++];
if (!buffer[c]) continue;
name2[d] = 0;
pclog("Comparing %s and %s\n", name, name2);
if (strcmp(name, name2)) continue;
pclog("Found!\n");
while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c])
c++;
if (!buffer[c]) continue;
sscanf(&buffer[c], "%i", &res);
pclog("Reading value - %i\n", res);
break;
}
fclose(f);
return res;
}
char config_return_string[256];
char *get_config_string(char *head, char *name, char *def)
{
char buffer[256];
char name2[256];
FILE *f = fopen(config_file, "rt");
int c, d;
strcpy(config_return_string, def);
if (!f)
return config_return_string;
pclog("Searching for %s\n", name);
while (1)
{
fgets(buffer, 255, f);
if (feof(f)) break;
c = d = 0;
while (buffer[c] == ' ' && buffer[c])
c++;
if (!buffer[c]) continue;
while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c])
name2[d++] = buffer[c++];
if (!buffer[c]) continue;
name2[d] = 0;
pclog("Comparing %s and %s\n", name, name2);
if (strcmp(name, name2)) continue;
pclog("Found!\n");
while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c])
c++;
if (!buffer[c]) continue;
strcpy(config_return_string, &buffer[c]);
c = strlen(config_return_string) - 1;
pclog("string len %i\n", c);
while (config_return_string[c] <= 32 && config_return_string[c])
config_return_string[c--] = 0;
pclog("Reading value - %s\n", config_return_string);
break;
}
fclose(f);
return config_return_string;
}
void set_config_int(char *head, char *name, int val)
{
FILE *f = fopen(config_file, "at");
if (!f) pclog("set_config_int - !f\n");
fprintf(f, "%s = %i\n", name, val);
pclog("Write %s = %i\n", name, val);
fclose(f);
pclog("fclose\n");
}
void set_config_string(char *head, char *name, char *val)
{
FILE *f = fopen(config_file, "at");
if (!f) pclog("set_config_string - !f\n");
fprintf(f, "%s = %s\n", name, val);
pclog("Write %s = %s\n", name, val);
fclose(f);
}
char *get_filename(char *s)
{
int c = strlen(s) - 1;
while (c > 0)
{
if (s[c] == '/' || s[c] == '\\')
return &s[c+1];
c--;
}
return s;
}
void append_filename(char *dest, char *s1, char *s2, int size)
{
sprintf(dest, "%s%s", s1, s2);
}
void put_backslash(char *s)
{
int c = strlen(s) - 1;
if (s[c] != '/' && s[c] != '\\')
s[c] = '/';
}

5
src/config.h Normal file
View File

@@ -0,0 +1,5 @@
void set_config_file(char *s);
int get_config_int(char *head, char *name, int def);
char *get_config_string(char *head, char *name, char *def);
void set_config_int(char *head, char *name, int val);
void set_config_string(char *head, char *name, char *val);

411
src/cpu.c Normal file
View File

@@ -0,0 +1,411 @@
#include "ibm.h"
#include "cpu.h"
#include "model.h"
#include "io.h"
int cpu = 3, cpu_manufacturer = 0;
CPU *cpu_s;
int cpu_multi;
int cpu_iscyrix;
int cpu_16bitbus;
int cpu_busspeed;
int timing_rr;
int timing_mr, timing_mrl;
int timing_rm, timing_rml;
int timing_mm, timing_mml;
int timing_bt, timing_bnt;
/*Available cpuspeeds :
0 = 16 MHz
1 = 20 MHz
2 = 25 MHz
3 = 33 MHz
4 = 40 MHz
5 = 50 MHz
6 = 66 MHz
7 = 75 MHz
8 = 80 MHz
9 = 90 MHz
10 = 100 MHz
11 = 120 MHz
12 = 133 MHz
13 = 150 MHz
14 = 160 MHz
*/
CPU cpus_8088[] =
{
/*8088 standard*/
{"8088/4.77", CPU_8088, 0, 4772727, 1, 0, 0, 0},
{"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0},
{"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0},
{"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0},
{"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_8086[] =
{
/*8086 standard*/
{"8086/7.16", CPU_8086, 1, 3579545*2, 1, 0, 0, 0},
{"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0},
{"8086/9.54", CPU_8086, 1, (3579545*8)/3, 1, 0, 0, 0},
{"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0},
{"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0},
{"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_pc1512[] =
{
/*8086 Amstrad*/
{"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_286[] =
{
/*286*/
{"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0},
{"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0},
{"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0},
{"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0},
{"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0},
{"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0},
{"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_ibmat[] =
{
/*286*/
{"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0},
{"", -1, 0, 0, 0, 0}
};
CPU cpus_i386[] =
{
/*i386*/
{"i386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0},
{"i386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0},
{"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
{"i386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0},
{"i386DX/16", CPU_386DX, 0, 16000000, 1, 0x0308, 0, 0},
{"i386DX/20", CPU_386DX, 1, 20000000, 1, 0x0308, 0, 0},
{"i386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0},
{"i386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_acer[] =
{
/*i386*/
{"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_Am386[] =
{
/*Am386*/
{"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0},
{"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0},
{"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0},
{"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0},
{"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0x2308, 0, 0},
{"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0},
{"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0},
{"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0x0308, 0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_486SDLC[] =
{
/*Cx486SLC/DLC*/
{"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0, 0x0000},
{"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0, 0x0000},
{"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0, 0x0000},
{"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0, 0x0006},
{"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0, 0x0006},
{"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0, 0x0006},
{"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0, 0x0001},
{"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0, 0x0001},
{"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0, 0x0001},
{"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0, 0x0007},
{"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0, 0x0007},
{"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0, 0x0007},
{"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0, 0x0007},
{"", -1, 0, 0, 0}
};
CPU cpus_i486[] =
{
/*i486*/
{"i486SX/16", CPU_i486SX, 0, 16000000, 1, 0x42a, 0, 0},
{"i486SX/20", CPU_i486SX, 1, 20000000, 1, 0x42a, 0, 0},
{"i486SX/25", CPU_i486SX, 2, 25000000, 1, 0x42a, 0, 0},
{"i486SX/33", CPU_i486SX, 3, 33333333, 1, 0x42a, 0, 0},
{"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 0x45b, 0, 0},
{"i486DX/25", CPU_i486DX, 2, 25000000, 1, 0x404, 0, 0},
{"i486DX/33", CPU_i486DX, 3, 33333333, 1, 0x404, 0, 0},
{"i486DX/50", CPU_i486DX, 5, 50000000, 1, 0x404, 0, 0},
{"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 0x430, 0, 0},
{"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 0x430, 0, 0},
{"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 0x430, 0, 0},
{"iDX4/75", CPU_i486DX, 7, 75000000, 3, 0x481, 0x481, 0}, /*CPUID available on DX4, >= 75 MHz*/
{"iDX4/100", CPU_i486DX,10, 100000000, 3, 0x481, 0x481, 0}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/
{"", -1, 0, 0, 0}
};
CPU cpus_Am486[] =
{
/*Am486/5x86*/
{"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 0x42a, 0, 0},
{"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 0x42a, 0, 0},
{"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 0x45b, 0x45b, 0}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/
{"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 0x45b, 0x45b, 0}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/
{"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 0x430, 0, 0},
{"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 0x430, 0, 0},
{"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 0x470, 0x470, 0},
{"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 0x470, 0x470, 0},
{"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 0x470, 0x470, 0},
{"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 0x482, 0x482, 0},
{"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 0x482, 0x482, 0},
{"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 0x482, 0x482, 0},
{"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 0x482, 0x482, 0},
{"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 0x4e0, 0x4e0, 0},
{"Am5x86/P75+", CPU_Am486DX, 13, 150000000, 4, 0x4e0, 0x4e0, 0},
{"", -1, 0, 0, 0}
};
CPU cpus_Cx486[] =
{
/*Cx486/5x86*/
{"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 0x420, 0, 0x0010},
{"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 0x420, 0, 0x0010},
{"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 0x420, 0, 0x0010},
{"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 0x430, 0, 0x051a},
{"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 0x430, 0, 0x051a},
{"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 0x430, 0, 0x081b},
{"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 0x430, 0, 0x0b1b},
{"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 0x430, 0, 0x311b},
{"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 0x480, 0, 0x361f},
{"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 0x480, 0, 0x361f},
{"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 0x480, 0, 0x002f},
{"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 0x480, 0, 0x002f},
{"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 0x480, 0, 0x002f},
{"", -1, 0, 0, 0}
};
void cpu_set_edx()
{
EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset;
}
void cpu_set()
{
CPU *cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu];
CPUID = cpu_s->cpuid_model;
cpuspeed = cpu_s->speed;
is8086 = (cpu_s->cpu_type >= CPU_8088);
is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC);
hasfpu = (cpu_s->cpu_type >= CPU_i486DX);
cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86);
cpu_16bitbus = (cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC);
if (cpu_s->multi)
cpu_busspeed = cpu_s->rspeed / cpu_s->multi;
cpu_multi = cpu_s->multi;
if (cpu_iscyrix)
io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL);
else
io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL);
pclog("hasfpu - %i\n",hasfpu);
pclog("is486 - %i %i\n",is486,cpu_s->cpu_type);
switch (cpu_s->cpu_type)
{
case CPU_386SX:
timing_rr = 2; /*register dest - register src*/
timing_rm = 6; /*register dest - memory src*/
timing_mr = 7; /*memory dest - register src*/
timing_mm = 6; /*memory dest - memory src*/
timing_rml = 8; /*register dest - memory src long*/
timing_mrl = 11; /*memory dest - register src long*/
timing_mml = 10; /*memory dest - memory src*/
timing_bt = 7-3; /*branch taken*/
timing_bnt = 3; /*branch not taken*/
break;
case CPU_386DX:
timing_rr = 2; /*register dest - register src*/
timing_rm = 6; /*register dest - memory src*/
timing_mr = 7; /*memory dest - register src*/
timing_mm = 6; /*memory dest - memory src*/
timing_rml = 6; /*register dest - memory src long*/
timing_mrl = 7; /*memory dest - register src long*/
timing_mml = 6; /*memory dest - memory src*/
timing_bt = 7-3; /*branch taken*/
timing_bnt = 3; /*branch not taken*/
break;
case CPU_486SLC:
timing_rr = 1; /*register dest - register src*/
timing_rm = 3; /*register dest - memory src*/
timing_mr = 5; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 5; /*register dest - memory src long*/
timing_mrl = 7; /*memory dest - register src long*/
timing_mml = 7;
timing_bt = 6-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_486DLC:
timing_rr = 1; /*register dest - register src*/
timing_rm = 3; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 3; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 6-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_i486SX:
case CPU_i486DX:
timing_rr = 1; /*register dest - register src*/
timing_rm = 2; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 2; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 3-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_Am486SX:
case CPU_Am486DX:
/*AMD timing identical to Intel*/
timing_rr = 1; /*register dest - register src*/
timing_rm = 2; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 2; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 3-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_Cx486S:
case CPU_Cx486DX:
timing_rr = 1; /*register dest - register src*/
timing_rm = 3; /*register dest - memory src*/
timing_mr = 3; /*memory dest - register src*/
timing_mm = 3;
timing_rml = 3; /*register dest - memory src long*/
timing_mrl = 3; /*memory dest - register src long*/
timing_mml = 3;
timing_bt = 4-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
case CPU_Cx5x86:
timing_rr = 1; /*register dest - register src*/
timing_rm = 1; /*register dest - memory src*/
timing_mr = 2; /*memory dest - register src*/
timing_mm = 2;
timing_rml = 1; /*register dest - memory src long*/
timing_mrl = 2; /*memory dest - register src long*/
timing_mml = 2;
timing_bt = 5-1; /*branch taken*/
timing_bnt = 1; /*branch not taken*/
break;
}
}
void cpu_CPUID()
{
switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type)
{
case CPU_i486DX:
if (!EAX)
{
EAX = 0x00000001;
EBX = 0x756e6547;
EDX = 0x49656e69;
ECX = 0x6c65746e;
}
else if (EAX == 1)
{
EAX = CPUID;
EBX = ECX = 0;
EDX = 1; /*FPU*/
}
else
EAX = 0;
break;
case CPU_Am486SX:
if (!EAX)
{
EBX = 0x68747541;
ECX = 0x444D4163;
EDX = 0x69746E65;
}
else if (EAX == 1)
{
EAX = CPUID;
EBX = ECX = EDX = 0; /*No FPU*/
}
else
EAX = 0;
break;
case CPU_Am486DX:
if (!EAX)
{
EBX = 0x68747541;
ECX = 0x444D4163;
EDX = 0x69746E65;
}
else if (EAX == 1)
{
EAX = CPUID;
EBX = ECX = 0;
EDX = 1; /*FPU*/
}
else
EAX = 0;
break;
}
}
static int cyrix_addr;
void cyrix_write(uint16_t addr, uint8_t val)
{
if (!(addr & 1)) cyrix_addr = val;
// else pclog("Write Cyrix %02X %02X\n",cyrix_addr,val);
}
uint8_t cyrix_read(uint16_t addr)
{
if (addr & 1)
{
switch (cyrix_addr)
{
case 0xfe: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id & 0xff;
case 0xff: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id >> 8;
}
if ((cyrix_addr & ~0xf0) == 0xc0) return 0xff;
if (cyrix_addr == 0x20 && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_Cx5x86) return 0xff;
}
return 0xff;
}

71
src/cpu.h Normal file
View File

@@ -0,0 +1,71 @@
extern int cpu, cpu_manufacturer;
/*808x class CPUs*/
#define CPU_8088 0
#define CPU_8086 1
/*286 class CPUs*/
#define CPU_286 2
/*386 class CPUs*/
#define CPU_386SX 3
#define CPU_386DX 4
#define CPU_486SLC 5
#define CPU_486DLC 6
/*486 class CPUs*/
#define CPU_i486SX 7
#define CPU_Am486SX 8
#define CPU_Cx486S 9
#define CPU_i486DX 10
#define CPU_Am486DX 11
#define CPU_Cx486DX 12
#define CPU_Cx5x86 13
#define MANU_INTEL 0
#define MANU_AMD 1
#define MANU_CYRIX 2
extern int timing_rr;
extern int timing_mr, timing_mrl;
extern int timing_rm, timing_rml;
extern int timing_mm, timing_mml;
extern int timing_bt, timing_bnt;
typedef struct
{
char name[16];
int cpu_type;
int speed;
int rspeed;
int multi;
uint32_t edx_reset;
uint32_t cpuid_model;
uint16_t cyrix_id;
} CPU;
extern CPU cpus_8088[];
extern CPU cpus_8086[];
extern CPU cpus_286[];
extern CPU cpus_i386[];
extern CPU cpus_Am386[];
extern CPU cpus_486SDLC[];
extern CPU cpus_i486[];
extern CPU cpus_Am486[];
extern CPU cpus_Cx486[];
extern CPU cpus_pc1512[];
extern CPU cpus_ibmat[];
extern CPU cpus_acer[];
extern int cpu_iscyrix;
extern int cpu_16bitbus;
extern int cpu_busspeed;
extern int cpu_multi;
void cyrix_write(uint16_t addr, uint8_t val);
uint8_t cyrix_read(uint16_t addr);
extern int is8086;

68
src/dac.c Normal file
View File

@@ -0,0 +1,68 @@
#include "ibm.h"
uint8_t dac,dac2;
uint8_t dacctrl;
int lptfifo;
uint8_t dssbuffer[16];
int dssstart=0,dssend=0;
int dssmode=0;
void writedac(uint16_t addr, uint8_t val)
{
if (dssmode) dac2=val;
else dac=val;
}
void writedacctrl(uint16_t addr, uint8_t val)
{
// printf("Write DAC ctrl %02X %i\n",val,lptfifo);
if (dacctrl&8 && !(val&8) && (lptfifo!=16))
{
// dac=dac2;
dssbuffer[dssend++]=dac2;
dssend&=15;
lptfifo++;
}
dacctrl=val;
}
uint8_t readdacfifo()
{
if (lptfifo==16) return 0x40;
return 0;
}
void pollss()
{
if (lptfifo)
{
dac=dssbuffer[dssstart++];
dssstart&=15;
lptfifo--;
}
}
int16_t dacbuffer[SOUNDBUFLEN+20];
int dacbufferpos=0;
void getdacsamp()
{
if (dacbufferpos<SOUNDBUFLEN+20) dacbuffer[dacbufferpos++]=(((int)(unsigned int)dac)-0x80)*0x20;
}
void adddac(int16_t *p)
{
int c;
if (dacbufferpos>SOUNDBUFLEN) dacbufferpos=SOUNDBUFLEN;
for (c=0;c<dacbufferpos;c++)
{
p[c<<1]+=(dacbuffer[c]);
p[(c<<1)+1]+=(dacbuffer[c]);
}
for (;c<SOUNDBUFLEN;c++)
{
p[c<<1]+=(dacbuffer[dacbufferpos-1]);
p[(c<<1)+1]+=(dacbuffer[dacbufferpos-1]);
}
dacbufferpos=0;
}

490
src/dma.c Normal file
View File

@@ -0,0 +1,490 @@
#include "ibm.h"
#include "video.h"
#include "io.h"
#include "dma.h"
extern int ins;
int output;
uint8_t dmaregs[16];
int dmaon[4];
uint8_t dma16regs[16];
int dma16on[4];
void dma_reset()
{
int c;
dma.wp=0;
for (c=0;c<16;c++) dmaregs[c]=0;
for (c=0;c<4;c++)
{
dma.mode[c]=0;
dma.ac[c]=0;
dma.cc[c]=0;
dma.ab[c]=0;
dma.cb[c]=0;
}
dma.m=0;
dma16.wp=0;
for (c=0;c<16;c++) dma16regs[c]=0;
for (c=0;c<4;c++)
{
dma16.mode[c]=0;
dma16.ac[c]=0;
dma16.cc[c]=0;
dma16.ab[c]=0;
dma16.cb[c]=0;
}
dma16.m=0;
}
uint8_t dma_read(uint16_t addr)
{
uint8_t temp;
// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc);
switch (addr&0xF)
{
case 0:
/* if (((dma.mode[0]>>2)&3)==2)
{
dma.ac[0]++;
dma.cc[0]--;
if (dma.cc[0]<0)
{
dma.ac[0]=dma.ab[0];
dma.cc[0]=dma.cb[0];
}
}*/
case 2: case 4: case 6: /*Address registers*/
dma.wp^=1;
if (dma.wp) return dma.ac[(addr>>1)&3]&0xFF;
return dma.ac[(addr>>1)&3]>>8;
case 1: case 3: case 5: case 7: /*Count registers*/
// printf("DMA count %i = %04X\n", (addr>>1)&3, dma.cc[(addr>>1)&3]);
dma.wp^=1;
if (dma.wp) temp=dma.cc[(addr>>1)&3]&0xFF;
else temp=dma.cc[(addr>>1)&3]>>8;
// printf("%02X\n",temp);
return temp;
case 8: /*Status register*/
temp=dma.stat;
dma.stat=0;
return temp|1;
case 0xD:
return 0;
}
// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc);
return dmaregs[addr&0xF];
}
void dma_write(uint16_t addr, uint8_t val)
{
// printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc);
dmaregs[addr&0xF]=val;
switch (addr&0xF)
{
case 0: case 2: case 4: case 6: /*Address registers*/
dma.wp^=1;
if (dma.wp) dma.ab[(addr>>1)&3]=(dma.ab[(addr>>1)&3]&0xFF00)|val;
else dma.ab[(addr>>1)&3]=(dma.ab[(addr>>1)&3]&0xFF)|(val<<8);
dma.ac[(addr>>1)&3]=dma.ab[(addr>>1)&3];
dmaon[(addr>>1)&3]=1;
// printf("DMA addr %i now %04X\n",(addr>>1)&3,dma.ac[(addr>>1)&3]);
return;
case 1: case 3: case 5: case 7: /*Count registers*/
dma.wp^=1;
if (dma.wp) dma.cb[(addr>>1)&3]=(dma.cb[(addr>>1)&3]&0xFF00)|val;
else dma.cb[(addr>>1)&3]=(dma.cb[(addr>>1)&3]&0xFF)|(val<<8);
dma.cc[(addr>>1)&3]=dma.cb[(addr>>1)&3];
dmaon[(addr>>1)&3]=1;
// printf("DMA count %i now %04X\n",(addr>>1)&3,dma.cc[(addr>>1)&3]);
return;
case 8: /*Control register*/
dma.command = val;
return;
case 0xA: /*Mask*/
if (val&4) dma.m|=(1<<(val&3));
else dma.m&=~(1<<(val&3));
return;
case 0xB: /*Mode*/
dma.mode[val&3]=val;
return;
case 0xC: /*Clear FF*/
dma.wp=0;
return;
case 0xD: /*Master clear*/
dma.wp=0;
dma.m=0xF;
return;
case 0xF: /*Mask write*/
dma.m=val&0xF;
return;
}
}
uint8_t dma16_read(uint16_t addr)
{
uint8_t temp;
// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc);
addr>>=1;
switch (addr&0xF)
{
case 0:
if (((dma16.mode[0]>>2)&3)==2)
{
dma16.ac[0]++;
dma16.cc[0]--;
if (dma16.cc[0]<0)
{
dma16.ac[0]=dma16.ab[0];
dma16.cc[0]=dma16.cb[0];
}
}
case 2: case 4: case 6: /*Address registers*/
dma16.wp^=1;
if (dma16.wp) return dma16.ac[(addr>>1)&3]&0xFF;
return dma16.ac[(addr>>1)&3]>>8;
case 1: case 3: case 5: case 7: /*Count registers*/
dma16.wp^=1;
// printf("Read %04X\n",dma16.cc[1]);
if (dma16.wp) temp=dma16.cc[(addr>>1)&3]&0xFF;
else temp=dma16.cc[(addr>>1)&3]>>8;
// printf("%02X\n",temp);
return temp;
case 8: /*Status register*/
temp=dma16.stat;
dma16.stat=0;
return temp|1;
}
return dma16regs[addr&0xF];
}
void dma16_write(uint16_t addr, uint8_t val)
{
// printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc);
addr>>=1;
dma16regs[addr&0xF]=val;
switch (addr&0xF)
{
case 0: case 2: case 4: case 6: /*Address registers*/
dma16.wp^=1;
if (dma16.wp) dma16.ab[(addr>>1)&3]=(dma16.ab[(addr>>1)&3]&0xFF00)|val;
else dma16.ab[(addr>>1)&3]=(dma16.ab[(addr>>1)&3]&0xFF)|(val<<8);
dma16.ac[(addr>>1)&3]=dma16.ab[(addr>>1)&3];
dma16on[(addr>>1)&3]=1;
// printf("dma16 addr %i now %04X\n",(addr>>1)&3,dma16.ac[(addr>>1)&3]);
return;
case 1: case 3: case 5: case 7: /*Count registers*/
dma16.wp^=1;
if (dma16.wp) dma16.cb[(addr>>1)&3]=(dma16.cb[(addr>>1)&3]&0xFF00)|val;
else dma16.cb[(addr>>1)&3]=(dma16.cb[(addr>>1)&3]&0xFF)|(val<<8);
dma16.cc[(addr>>1)&3]=dma16.cb[(addr>>1)&3];
dma16on[(addr>>1)&3]=1;
// printf("dma16 count %i now %04X\n",(addr>>1)&3,dma16.cc[(addr>>1)&3]);
return;
case 8: /*Control register*/
return;
case 0xA: /*Mask*/
if (val&4) dma16.m|=(1<<(val&3));
else dma16.m&=~(1<<(val&3));
return;
case 0xB: /*Mode*/
dma16.mode[val&3]=val;
return;
case 0xC: /*Clear FF*/
dma16.wp=0;
return;
case 0xD: /*Master clear*/
dma16.wp=0;
dma16.m=0xF;
return;
case 0xF: /*Mask write*/
dma16.m=val&0xF;
return;
}
}
uint8_t dmapages[16];
static int primed = 0;
void dma_page_write(uint16_t addr, uint8_t val)
{
if (!(addr&0xF))
{
// printf("Write page %03X %02X %04X:%04X\n",addr,val,CS,pc);
// if (val==0x29 && pc==0xD25) output=1;
}
dmapages[addr&0xF]=val;
switch (addr&0xF)
{
case 1:
dma.page[2]=(AT)?val:val&0xF;
break;
case 2:
dma.page[3]=(AT)?val:val&0xF;
break;
case 3:
dma.page[1]=(AT)?val:val&0xF;
// pclog("DMA1 page %02X\n",val);
break;
case 0xB:
dma16.page[1]=val;
break;
}
// printf("Page write %04X %02X\n",addr,val);
}
uint8_t dma_page_read(uint16_t addr)
{
return dmapages[addr&0xF];
}
void dma_init()
{
io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL);
io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL);
}
void dma16_init()
{
io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL);
io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL);
}
uint8_t _dma_read(uint32_t addr)
{
switch (addr&0xFFFF8000)
{
case 0xA0000: case 0xA8000:
return video_read_a000(addr);
case 0xB0000:
return video_read_b000(addr);
case 0xB8000:
return video_read_b800(addr);
}
if (isram[addr>>16]) return ram[addr];
return 0xff;
}
void _dma_write(uint32_t addr, uint8_t val)
{
switch (addr&0xFFFF8000)
{
case 0xA0000: case 0xA8000:
video_write_a000(addr,val);
return;
case 0xB0000:
video_write_b000(addr,val);
return;
case 0xB8000:
video_write_b800(addr,val);
return;
case 0xC0000: case 0xC8000: case 0xD0000: case 0xD8000:
case 0xE0000: case 0xE8000: case 0xF0000: case 0xF8000:
return;
}
if (isram[addr>>16]) ram[addr]=val;
}
/*void writedma2(uint8_t val)
{
// printf("Write to %05X %02X %i\n",(dma.page[2]<<16)+dma.ac[2],val,dma.m&4);
if (!(dma.m&4))
{
ram[((dma.page[2]<<16)+dma.ac[2])&rammask]=val;
dma.ac[2]++;
dma.cc[2]--;
if (dma.cc[2]==-1)
{
dma.m|=4;
dma.stat|=4;
}
}
}*/
uint8_t readdma2()
{
uint8_t temp;
// pclog("Read DMA2 %02X %02X\n",dma.m,dma.mode[2]);
if (dma.m&4)
{
fdc_abort();
return 0xFF;
}
if ((dma.mode[2]&0xC)!=8)
{
fdc_abort();
return 0xFF;
}
temp=_dma_read((dma.ac[2]+(dma.page[2]<<16))&rammask); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask];
// pclog("DMA2 %02X %05X\n",temp,(dma.ac[2]+(dma.page[2]<<16))&rammask);
if (dma.mode[2]&0x20) dma.ac[2]--;
else dma.ac[2]++;
dma.cc[2]--;
if (!dma.cc[2] && (dma.mode[2]&0x10))
{
dma.cc[2]=dma.cb[2]+1;
dma.ac[2]=dma.ab[2];
}
else if (dma.cc[2]<=-1)
dma.m|=4;
return temp;
}
void writedma2(uint8_t temp)
{
// pclog("Write DMA2 %02X %02X %04X\n",dma.m,dma.mode[2],dma.cc[2]);
if (dma.m&4)
{
fdc_abort();
return;
}
if ((dma.mode[2]&0xC)!=4)
{
fdc_abort();
return;
}
// pclog("Write %05X %05X %02X\n",(dma.ac[2]+(dma.page[2]<<16)),rammask,temp);
// ram[(dma.ac[2]+(dma.page[2]<<16))&rammask]=temp;
_dma_write((dma.ac[2]+(dma.page[2]<<16))&rammask,temp);
if (dma.mode[2]&0x20) dma.ac[2]--;
else dma.ac[2]++;
dma.cc[2]--;
if (!dma.cc[2] && (dma.mode[2]&0x10))
{
dma.cc[2]=dma.cb[2]+1;
dma.ac[2]=dma.ab[2];
}
else if (dma.cc[2]<=-1)
{
// pclog("Reached TC\n");
fdc_abort();
dma.m|=4;
}
}
uint8_t readdma1()
{
uint8_t temp=0;
/*if ((dma.ac[1]+(dma.page[1]<<16))<0x800000) */temp=ram[(dma.ac[1]+(dma.page[1]<<16))&rammask];
// printf("Read DMA1 from %05X %02X %04X %02X %i\n",dma.ac[1]+(dma.page[1]<<16),dma.mode[1],dma.cc[1],temp,dmaon[1]);
if (!dmaon[1])
{
// printf("DMA off!\n");
return temp;
}
dma.ac[1]++;
dma.cc[1]--;
if (dma.cc[1]<=-1 && (dma.mode[1]&0x10))
{
dma.cc[1]=dma.cb[1];
dma.ac[1]=dma.ab[1];
}
else if (dma.cc[1]<=-1)
dmaon[1]=0;
return temp;
}
uint16_t readdma5()
{
uint16_t temp=0;
// pclog("Read DMA5 %i %04X\n",dma16on[1],dma16.cc[1]);
/*if ((dma16.ac[1]+(dma16.page[1]<<16))<0x800000) */temp=ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16))&rammask]|(ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16)+1)&rammask]<<8);
//readmemwl(dma16.ac[1]+(dma16.page[1]<<16));
// printf("Read DMA1 from %05X %05X %02X %04X\n",dma.ac[1]+(dma.page[1]<<16),(dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16),dma16.mode[1],temp);
if (!dma16on[1])
{
// printf("DMA off!\n");
return temp;
}
dma16.ac[1]++;
dma16.cc[1]--;
if (dma16.cc[1]<=-1 && (dma16.mode[1]&0x10))
{
dma16.cc[1]=dma16.cb[1];
dma16.ac[1]=dma16.ab[1];
}
else if (dma16.cc[1]<=-1)
dma16on[1]=0;
return temp;
}
void writedma1(uint8_t temp)
{
if (!dmaon[1]) return;
ram[(dma.ac[1]+(dma.page[1]<<16))&rammask]=temp;
dma.ac[1]++;
dma.cc[1]--;
if (!dma.cc[1] && (dma.mode[1]&0x10))
{
dma.cc[1]=dma.cb[1]+1;
dma.ac[1]=dma.ab[1];
}
else if (dma.cc[1]<=-1)
dmaon[1]=0;
}
void writedma5(uint16_t temp)
{
if (!dma16on[1]) return;
ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16))&rammask]=temp;
ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16)+1)&rammask]=temp>>8;
dma16.ac[1]++;
dma16.cc[1]--;
if (dma16.cc[1]<=-1 && (dma16.mode[1]&0x10))
{
dma16.cc[1]=dma16.cb[1];
dma16.ac[1]=dma16.ab[1];
}
else if (dma16.cc[1]<=-1)
dma16on[1]=0;
}
int readdma3()
{
uint8_t temp=ram[((dma.page[3]<<16)+dma.ac[3])&rammask];
if (dma.m&8)
{
return -1;
}
// printf("Read DMA 3 - %02X %05X %i\n",temp,(dma.page[3]<<16)+dma.ac[3],dma.cc[3]);
if (!(dma.m&8))
{
dma.ac[3]++;
dma.cc[3]--;
if (dma.cc[3]==-1)
{
dma.m|=8;
dma.stat|=8;
}
}
return temp;
}
void readdma0()
{
if (AT) ppi.pb^=0x10;
if (dma.command & 4) return;
// if (AMSTRAD) return;
refreshread();
// pclog("Read refresh %02X %02X %04X %04X\n",dma.m,dma.mode[0],dma.ac[0],dma.cc[0]);
if (dma.m&1) return;
// readmembl((dma.page[0]<<16)+dma.ac[0]);
// if (!(dma.m&1))
// {
dma.ac[0]+=2;
dma.cc[0]--;
if (dma.cc[0]==-1)
{
dma.stat|=1;
dma.ac[0]=dma.ab[0];
dma.cc[0]=dma.cb[0];
}
// }
// ppi.pb^=0x10;
}
void dumpdma()
{
printf("Address : %04X %04X %04X %04X\n",dma.ac[0],dma.ac[1],dma.ac[2],dma.ac[3]);
printf("Count : %04X %04X %04X %04X\n",dma.cc[0],dma.cc[1],dma.cc[2],dma.cc[3]);
printf("Mask %02X Stat %02X\n",dma.m,dma.stat);
}

3
src/dma.h Normal file
View File

@@ -0,0 +1,3 @@
void dma_init();
void dma16_init();
void dma_reset();

298
src/ega.c Normal file
View File

@@ -0,0 +1,298 @@
#include "ibm.h"
#include "video.h"
void doblit();
int egareads=0,egawrites=0;
int framecount=0;
int changeframecount=2;
void redotextlookup();
int output;
int svgaon=0;
uint32_t svgarbank,svgawbank;
uint8_t svgaseg,svgaseg2;
uint8_t svga3d8;
uint8_t oldvram=0;
int frames;
int incga=1;
int hsync;
uint8_t cgastat;
uint8_t gdcreg[16];
int gdcaddr;
uint8_t attrregs[32];
int attraddr,attrff=0;
uint8_t ega3c2;
uint8_t rotatevga[8][256];
uint8_t writemask,charset;
int writemode,readmode,readplane,chain4;
uint8_t colourcompare,colournocare;
uint8_t la,lb,lc,ld;
uint8_t *vram;
int egares;
uint8_t seqregs[32];
int seqaddr;
uint8_t oak_regs[32];
int oak_index;
extern int egaswitchread,egaswitches;
/*For VGA non-interlace colour, ID bits should be 1 1 0 or 6*/
int vres=0;
PALETTE vgapal;
uint32_t *pallook,pallook16[256],pallook64[256],pallook256[256];
int dacread,dacwrite,dacpos=0;
int palchange=1;
int fullchange;
float dispontime,dispofftime,disptime;
int ega_vtotal,ega_dispend,ega_vsyncstart,ega_split,ega_hdisp,ega_rowoffset;
int vidclock;
float cpuclock;
int bpp;
uint32_t vrammask;
uint8_t changedvram[(8192*1024)/1024];
int charseta,charsetb;
int egapal[16];
int displine;
int rowdbl=0;
int scrblank=0;
uint8_t edatlookup[4][4];
uint32_t textlookup[256][2][16][16];
/*void redotextlookup()
{
int c,d,e;
uint32_t temp;
int coffset=(VGA)?0:64;
for (c=0;c<256;c++)
{
for (d=0;d<16;d++)
{
// printf("ATTR %i=%02X+%02X\n",d,attrregs[d],coffset);
for (e=0;e<16;e++)
{
temp=0;
if (c&0x80) temp|=(attrregs[d]+coffset);
else temp|=(attrregs[e]+coffset);
if (c&0x40) temp|=(attrregs[d]+coffset)<<8;
else temp|=(attrregs[e]+coffset)<<8;
if (c&0x20) temp|=(attrregs[d]+coffset)<<16;
else temp|=(attrregs[e]+coffset)<<16;
if (c&0x10) temp|=(attrregs[d]+coffset)<<24;
else temp|=(attrregs[e]+coffset)<<24;
// if (c==0x5) printf("%08X %i %i %02X %02X\n",temp,d,e,attrregs[d],attrregs[e]);
textlookup[c][0][d][e]=temp;
temp=0;
if (c&0x08) temp|=(attrregs[d]+coffset);
else temp|=(attrregs[e]+coffset);
if (c&0x04) temp|=(attrregs[d]+coffset)<<8;
else temp|=(attrregs[e]+coffset)<<8;
if (c&0x02) temp|=(attrregs[d]+coffset)<<16;
else temp|=(attrregs[e]+coffset)<<16;
if (c&0x01) temp|=(attrregs[d]+coffset)<<24;
else temp|=(attrregs[e]+coffset)<<24;
textlookup[c][1][d][e]=temp;
}
}
}
}*/
void initega()
{
int c,d,e;
bpp=8;
for (c=0;c<256;c++)
{
e=c;
for (d=0;d<8;d++)
{
rotatevga[d][c]=e;
e=(e>>1)|((e&1)?0x80:0);
}
}
crtc[0xC]=crtc[0xD]=0;
if (romset==ROM_PC1640 || romset==ROM_PC1512) incga=1;
else incga=0;
for (c=0;c<4;c++)
{
for (d=0;d<4;d++)
{
edatlookup[c][d]=0;
if (c&1) edatlookup[c][d]|=1;
if (d&1) edatlookup[c][d]|=2;
if (c&2) edatlookup[c][d]|=0x10;
if (d&2) edatlookup[c][d]|=0x20;
// printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]);
}
}
/*redotextlookup();*/
for (c=0;c<256;c++)
{
pallook64[c]=makecol32(((c>>2)&1)*0xAA,((c>>1)&1)*0xAA,(c&1)*0xAA);
pallook64[c]+=makecol32(((c>>5)&1)*0x55,((c>>4)&1)*0x55,((c>>3)&1)*0x55);
pallook16[c]=makecol32(((c>>2)&1)*0xAA,((c>>1)&1)*0xAA,(c&1)*0xAA);
pallook16[c]+=makecol32(((c>>4)&1)*0x55,((c>>4)&1)*0x55,((c>>4)&1)*0x55);
if ((c&0x17)==6) pallook16[c]=makecol32(0xAA,0x55,0);
// printf("%03i %08X\n",c,pallook[c]);
}
pallook=pallook16;
seqregs[0xC]=0x20;
vrammask=(ET4000)?0xFFFFF:0x1FFFFF;
// writeega_func=writeega;
gdcreg[6]=8;
gdcreg[8]=0xFF;
writemode=0;
chain4=0;
writemask=3;
et4k_b8000=0;
svgarbank=svgawbank=0;
}
uint32_t egabase,egaoffset;
void cacheega()
{
egabase=(crtc[0xC]<<8)|crtc[0xD];
if (ET4000 || ET4000W32 || TRIDENT)
egabase|=((crtc[0x33]&3)<<18);
// printf("EGABASE %05X\n",egabase);
// egaoffset=8-((attrregs[0x13])&7);
// printf("Cache base!\n");
}
void cacheega2()
{
// egabase=(crtc[0xC]<<8)|crtc[0xD];
if (gdcreg[5]&0x40) egaoffset=8-(((attrregs[0x13])&7)>>1);
else egaoffset=8-((attrregs[0x13])&7);
// printf("Cache offset!\n");
}
int olddisplines,oldxsize;
int oldreadflash;
int oldegaaddr,oldegasplit;
int vc,sc;
int egadispon=0;
int linepos;
int displine;
uint32_t ma,maback,ca;
int firstline,lastline;
int xsize,ysize;
int scrollcache;
int con,cursoron,cgablink;
BITMAP *buffer,*vbuf,*buffer32;
int linecountff=0;
void dumpegaregs()
{
int c;
printf("CRTC :");
for (c=0;c<0x20;c++) printf(" %02X",crtc[c]);
printf("\n");
printf(" EXT :");
for (c=0;c<0x20;c++) printf(" %02X",crtc[c+32]);
printf("\n");
printf(" EXT2:");
for (c=0;c<0x20;c++) printf(" %02X",crtc[c+64]);
printf("\n");
printf("SEQ :");
for (c=0;c<0x10;c++) printf(" %02X",seqregs[c]);
printf("\n");
printf(" EXT :");
for (c=0;c<0x10;c++) printf(" %02X",seqregs[c + 0x10]);
printf("\n");
printf("ATTR :");
for (c=0;c<0x20;c++) printf(" %02X",attrregs[c]);
printf("\n");
printf("GDC :");
for (c=0;c<0x10;c++) printf(" %02X",gdcreg[c]);
printf("\n");
// printf("OLD CTRL2 = %02X NEW CTRL2 = %02X DAC = %02X 3C2 = %02X\n",tridentoldctrl2,tridentnewctrl2,tridentdac,ega3c2);
printf("BPP = %02X\n",bpp);
}
int oddeven;
int wx,wy;
int vslines;
int frames = 0;
void doblit()
{
startblit();
if ((wx!=xsize || wy!=ysize) && !vid_resize)
{
xsize=wx;
ysize=wy+1;
if (xsize<64) xsize=656;
if (ysize<32) ysize=200;
if (vres) updatewindowsize(xsize,ysize<<1);
else updatewindowsize(xsize,ysize);
}
video_blit_memtoscreen(32, 0, 0, ysize, xsize, ysize);
if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF);
endblit();
frames++;
}
int ega_getdepth()
{
if (!(gdcreg[6]&1)) return 0;
switch (gdcreg[5]&0x60)
{
case 0x00:
return 4;
case 0x20:
return 2;
case 0x40: case 0x60:
if (TRIDENT || ET4000W32) return bpp;
return 8;
}
}
int ega_getx()
{
int x;
if (!(gdcreg[6]&1)) return (crtc[1]+1);
if ((attrregs[0x10]&0x40) && !(tridentoldctrl2&0x10)) x=(crtc[1]+1)*4;
else x=(crtc[1]+1)*8;
if (TRIDENT && (bpp==15 || bpp==16)) x>>=1;
if (TRIDENT && bpp==24) x=(x<<1)/3;
return x;
}
int ega_gety()
{
if (crtc[0x1E]&4) return (ega_dispend/((crtc[9]&31)+1))<<1;
if (crtc[9]&0x80) return (ega_dispend/((crtc[9]&31)+1))>>1;
return ega_dispend/((crtc[9]&31)+1);
}

806
src/fdc.c Normal file
View File

@@ -0,0 +1,806 @@
#include <stdio.h>
#include <string.h>
#include "ibm.h"
void fdc_poll();
int timetolive;
int TRACKS[2] = {80, 80};
int SECTORS[2]={9,9};
int SIDES[2]={2,2};
//#define SECTORS 9
int output;
int lastbyte=0;
uint8_t disc[2][2][80][36][512];
uint8_t disc_3f7;
int discchanged[2];
int discmodified[2];
int discrate[2];
void loaddisc(int d, char *fn)
{
FILE *f=fopen(fn,"rb");
int h,t,s,b;
if (!f)
{
SECTORS[d]=9; SIDES[d]=1;
driveempty[d]=1; discrate[d]=4;
return;
}
driveempty[d]=0;
SIDES[d]=2;
fseek(f,-1,SEEK_END);
if (ftell(f)<=(160*1024)) { SECTORS[d]=8; TRACKS[d] = 40; SIDES[d]=1; discrate[d]=2; }
else if (ftell(f)<=(180*1024)) { SECTORS[d]=9; TRACKS[d] = 40; SIDES[d]=1; discrate[d]=2; }
else if (ftell(f)<=(320*1024)) { SECTORS[d]=8; TRACKS[d] = 40; discrate[d]=2; }
else if (ftell(f)<(1024*1024)) { SECTORS[d]=9; TRACKS[d] = 80; discrate[d]=2; } /*Double density*/
else if (ftell(f)<(0x1A4000-1)) { SECTORS[d]=18; TRACKS[d] = 80; discrate[d]=0; } /*High density (not supported by Tandy 1000)*/
else if (ftell(f) == 1884159) { SECTORS[d]=23; TRACKS[d] = 80; discrate[d]=0; } /*XDF format - used by OS/2 Warp*/
else if (ftell(f) == 1763327) { SECTORS[d]=21; TRACKS[d] = 82; discrate[d]=0; } /*XDF format - used by OS/2 Warp*/
else if (ftell(f)<(2048*1024)) { SECTORS[d]=21; TRACKS[d] = 80; discrate[d]=0; } /*DMF format - used by Windows 95*/
else { SECTORS[d]=36; TRACKS[d] = 80; discrate[d]=3; } /*E density (not supported by anything)*/
printf("Drive %c: has %i sectors and %i sides and is %i bytes long\n",'A'+d,SECTORS[0],SIDES[0],ftell(f));
fseek(f,0,SEEK_SET);
for (t=0;t<80;t++)
{
for (h=0;h<SIDES[d];h++)
{
for (s=0;s<SECTORS[d];s++)
{
for (b=0;b<512;b++)
{
disc[d][h][t][s][b]=getc(f);
}
}
}
}
fclose(f);
discmodified[d]=0;
strcpy(discfns[d],fn);
discchanged[d]=1;
}
void ejectdisc(int d)
{
discfns[d][0]=0;
SECTORS[d]=9; SIDES[d]=1;
driveempty[d]=1; discrate[d]=4;
}
void savedisc(int d)
{
FILE *f;
int h,t,s,b;
if (!discmodified[d]) return;
f=fopen(discfns[d],"wb");
if (!f) return;
printf("Save disc %c: %s %i %i\n",'A'+d,discfns[0],SIDES[0],SECTORS[0]);
for (t=0;t<80;t++)
{
for (h=0;h<SIDES[d];h++)
{
for (s=0;s<SECTORS[d];s++)
{
for (b=0;b<512;b++)
{
putc(disc[d][h][t][s][b],f);
}
}
}
}
fclose(f);
}
int discint;
void fdc_reset()
{
fdc.stat=0x80;
fdc.pnum=fdc.ptot=0;
fdc.st0=0xC0;
fdc.lock = 0;
fdc.head = 0;
if (!AT)
fdc.rate=2;
// pclog("Reset FDC\n");
}
int ins;
void fdc_write(uint16_t addr, uint8_t val)
{
int c;
// printf("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate);
switch (addr&7)
{
case 1: return;
case 2: /*DOR*/
// if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3;
// printf("DOR was %02X\n",fdc.dor);
if (val&4)
{
fdc.stat=0x80;
fdc.pnum=fdc.ptot=0;
}
if ((val&4) && !(fdc.dor&4))
{
disctime=128;
discint=-1;
fdc_reset();
}
fdc.dor=val;
// printf("DOR now %02X\n",val);
return;
case 4:
if (val & 0x80)
{
disctime=128;
discint=-1;
fdc_reset();
}
return;
case 5: /*Command register*/
// pclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot);
if (fdc.pnum==fdc.ptot)
{
fdc.command=val;
// printf("Starting FDC command %02X\n",fdc.command);
switch (fdc.command&0x1F)
{
case 2: /*Read track*/
// printf("Read track!\n");
fdc.pnum=0;
fdc.ptot=8;
fdc.stat=0x90;
fdc.pos=0;
break;
case 3: /*Specify*/
fdc.pnum=0;
fdc.ptot=2;
fdc.stat=0x90;
break;
case 4: /*Sense drive status*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
break;
case 5: /*Write data*/
// printf("Write data!\n");
fdc.pnum=0;
fdc.ptot=8;
fdc.stat=0x90;
fdc.pos=0;
readflash=1;
break;
case 6: /*Read data*/
fullspeed();
fdc.pnum=0;
fdc.ptot=8;
fdc.stat=0x90;
fdc.pos=0;
readflash=1;
break;
case 7: /*Recalibrate*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
break;
case 8: /*Sense interrupt status*/
// printf("Sense interrupt status %i\n",fdc.drive);
fdc.lastdrive = fdc.drive;
// fdc.stat = 0x10 | (fdc.stat & 0xf);
// disctime=1024;
discint = 8;
fdc.pos = 0;
fdc_poll();
break;
case 10: /*Read sector ID*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
fdc.pos=0;
break;
case 15: /*Seek*/
fdc.pnum=0;
fdc.ptot=2;
fdc.stat=0x90;
break;
case 0x0e: /*Dump registers*/
fdc.lastdrive = fdc.drive;
discint = 0x0e;
fdc.pos = 0;
fdc_poll();
break;
case 0x10: /*Get version*/
fdc.lastdrive = fdc.drive;
discint = 0x10;
fdc.pos = 0;
fdc_poll();
break;
case 0x12: /*Set perpendicular mode*/
fdc.pnum=0;
fdc.ptot=1;
fdc.stat=0x90;
fdc.pos=0;
break;
case 0x13: /*Configure*/
fdc.pnum=0;
fdc.ptot=3;
fdc.stat=0x90;
fdc.pos=0;
break;
case 0x14: /*Unlock*/
case 0x94: /*Lock*/
fdc.lastdrive = fdc.drive;
discint = fdc.command;
fdc.pos = 0;
fdc_poll();
break;
case 0x18:
fdc.stat = 0x10;
discint = 0xfc;
fdc_poll();
break;
default:
pclog("Bad FDC command %02X\n",val);
// dumpregs();
// exit(-1);
fdc.stat=0x10;
discint=0xfc;
disctime=200;
break;
}
}
else
{
fdc.params[fdc.pnum++]=val;
if (fdc.pnum==fdc.ptot)
{
// pclog("Got all params\n");
fdc.stat=0x30;
discint=fdc.command&0x1F;
disctime=1024;
fdc.drive=fdc.params[0]&1;
if (discint==2 || discint==5 || discint==6)
{
fdc.track[fdc.drive]=fdc.params[1];
fdc.head=fdc.params[2];
fdc.sector=fdc.params[3];
fdc.eot[fdc.drive] = fdc.params[4];
if (!fdc.params[5])
{
fdc.params[5]=fdc.sector;
}
if (fdc.params[5]>SECTORS[fdc.drive]) fdc.params[5]=SECTORS[fdc.drive];
if (driveempty[fdc.drive])
{
// pclog("Drive empty\n");
discint=0xFE;
}
}
if (discint==2 || discint==5 || discint==6 || discint==10)
{
// pclog("Rate %i %i %i\n",fdc.rate,discrate[fdc.drive],driveempty[fdc.drive]);
if (fdc.rate!=discrate[fdc.drive])
{
// pclog("Wrong rate %i %i\n",fdc.rate,discrate[fdc.drive]);
discint=0xFF;
disctime=1024;
}
if (driveempty[fdc.drive])
{
// pclog("Drive empty\n");
discint=0xFE;
disctime=1024;
}
}
if (discint == 7 || discint == 0xf)
{
fdc.stat = 1 << fdc.drive;
// disctime = 8000000;
}
if (discint == 0xf)
{
fdc.head = (fdc.params[0] & 4) ? 1 : 0;
}
// if (discint==5) fdc.pos=512;
}
}
return;
case 7:
if (!AT) return;
fdc.rate=val&3;
disc_3f7=val;
return;
}
// printf("Write FDC %04X %02X\n",addr,val);
// dumpregs();
// exit(-1);
}
int paramstogo=0;
uint8_t fdc_read(uint16_t addr)
{
uint8_t temp;
// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,ins);
switch (addr&7)
{
case 1: /*???*/
temp=0x50;
break;
case 3:
temp = 0x20;
break;
case 4: /*Status*/
temp=fdc.stat;
break;
case 5: /*Data*/
fdc.stat&=~0x80;
if (paramstogo)
{
paramstogo--;
temp=fdc.res[10 - paramstogo];
// printf("Read param %i %02X\n",6-paramstogo,temp);
if (!paramstogo)
{
fdc.stat=0x80;
// fdc.st0=0;
}
else
{
fdc.stat|=0xC0;
// fdc_poll();
}
}
else
{
if (lastbyte)
fdc.stat=0x80;
lastbyte=0;
temp=fdc.dat;
}
if (discint==0xA) disctime=1024;
fdc.stat &= 0xf0;
break;
case 7: /*Disk change*/
if (fdc.dor & (0x10 << (fdc.dor & 1)))
temp = (discchanged[fdc.dor & 1] || driveempty[fdc.dor & 1])?0x80:0;
else
temp = 0;
if (AMSTRADIO) /*PC2086/3086 seem to reverse this bit*/
temp ^= 0x80;
// printf("- DC %i %02X %02X %i %i - ",fdc.dor & 1, fdc.dor, 0x10 << (fdc.dor & 1), discchanged[fdc.dor & 1], driveempty[fdc.dor & 1]);
// discchanged[fdc.dor&1]=0;
break;
default:
temp=0xFF;
// printf("Bad read FDC %04X\n",addr);
// dumpregs();
// exit(-1);
}
// /*if (addr!=0x3f4) */printf("%02X rate=%i\n",temp,fdc.rate);
return temp;
}
int fdc_abort_f = 0;
void fdc_abort()
{
fdc_abort_f = 1;
// pclog("FDC ABORT\n");
}
static int fdc_reset_stat = 0;
void fdc_poll()
{
int temp;
// pclog("fdc_poll %08X %i %02X\n", discint, fdc.drive, fdc.st0);
switch (discint)
{
case -3: /*End of command with interrupt*/
// if (output) printf("EOC - interrupt!\n");
//pclog("EOC\n");
picint(0x40);
case -2: /*End of command*/
fdc.stat = (fdc.stat & 0xf) | 0x80;
return;
case -1: /*Reset*/
//pclog("Reset\n");
picint(0x40);
fdc_reset_stat = 4;
return;
case 2: /*Read track*/
if (!fdc.pos)
{
// printf("Read Track Side %i Track %i Sector %02X sector size %i end sector %02X %05X\n",fdc.head,fdc.track,fdc.sector,fdc.params[4],fdc.params[5],(dma.page[2]<<16)+dma.ac[2]);
}
if (fdc.pos<512)
{
fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos];
// pclog("Read %i %i %i %i %02X\n",fdc.head,fdc.track,fdc.sector,fdc.pos,fdc.dat);
writedma2(fdc.dat);
disctime=60;
}
else
{
disctime=0;
discint=-2;
// pclog("RT\n");
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=fdc.res[2]=0;
fdc.res[6]=fdc.track[fdc.drive];
fdc.res[7]=fdc.head;
fdc.res[8]=fdc.sector;
fdc.res[9]=fdc.params[4];
paramstogo=7;
return;
disctime=1024;
picint(0x40);
fdc.stat=0xD0;
switch (fdc.pos-512)
{
case 0: case 1: case 2: fdc.dat=0; break;
case 3: fdc.dat=fdc.track[fdc.drive]; break;
case 4: fdc.dat=fdc.head; break;
case 5: fdc.dat=fdc.sector; break;
case 6: fdc.dat=fdc.params[4]; discint=-2; lastbyte=1; break;
}
}
fdc.pos++;
if (fdc.pos==512 && fdc.params[5]!=1)
{
fdc.pos=0;
fdc.sector++;
if (fdc.sector==SECTORS[fdc.drive]+1)
{
fdc.sector=1;
}
fdc.params[5]--;
}
return;
case 3: /*Specify*/
fdc.stat=0x80;
fdc.specify[0] = fdc.params[0];
fdc.specify[1] = fdc.params[1];
return;
case 4: /*Sense drive status*/
fdc.res[10] = (fdc.params[0] & 7) | 0x28;
if (!fdc.track[fdc.drive]) fdc.res[10] |= 0x10;
fdc.stat = (fdc.stat & 0xf) | 0xd0;
paramstogo = 1;
discint = 0;
disctime = 0;
return;
case 5: /*Write data*/
discmodified[fdc.drive]=1;
// printf("Write data %i\n",fdc.pos);
if (!fdc.pos)
{
// printf("Write data Side %i Track %i Sector %02X sector size %i end sector %02X\n",fdc.params[2],fdc.params[1],fdc.params[3],fdc.params[4],fdc.params[5]);
// dumpregs();
// exit(-1);
}
if (fdc.pos<512)
{
temp=readdma2();
if (fdc_abort_f)
{
fdc_abort_f=0;
discint=0xFD;
disctime=50;
return;
}
else
{
fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]=temp;
// printf("Write data %i %i %02X %i:%i:%i:%i\n",fdc.sector-1,fdc.pos,fdc.dat,fdc.head,fdc.track[fdc.drive],fdc.sector-1,fdc.pos);
disctime=60;
}
}
else
{
disctime=0;
discint=-2;
// pclog("WD\n");
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
disctime=1024;
picint(0x40);
fdc.stat=0xD0;
switch (fdc.pos-512)
{
case 0: fdc.dat=0x40; break;
case 1: fdc.dat=2; break;
case 2: fdc.dat=0; break;
case 3: fdc.dat=fdc.track[fdc.drive]; break;
case 4: fdc.dat=fdc.head; break;
case 5: fdc.dat=fdc.sector; break;
case 6: fdc.dat=fdc.params[4]; discint=-2; break;
}
}
fdc.pos++;
if (fdc.pos==512 && fdc.sector!=fdc.params[5])
{
fdc.pos=0;
fdc.sector++;
}
return;
case 6: /*Read data*/
if (!fdc.pos)
{
// printf("Reading sector %i track %i side %i drive %i %02X to %05X\n",fdc.sector,fdc.track[fdc.drive],fdc.head,fdc.drive,fdc.params[5],(dma.ac[2]+(dma.page[2]<<16))&rammask);
}
if (fdc.pos<512)
{
fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos];
// printf("Read disc %i %i %i %i %02X\n",fdc.head,fdc.track,fdc.sector,fdc.pos,fdc.dat);
writedma2(fdc.dat);
disctime=60;
}
else
{
// printf("End of command - params to go!\n");
fdc_abort_f = 0;
disctime=0;
discint=-2;
picint(0x40);
// pclog("RD\n");
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
switch (fdc.pos-512)
{
case 0: case 1: case 2: fdc.dat=0; break;
case 3: fdc.dat=fdc.track[fdc.drive]; break;
case 4: fdc.dat=fdc.head; break;
case 5: fdc.dat=fdc.sector; break;
case 6: fdc.dat=fdc.params[4]; discint=-2; lastbyte=1; break;
}
}
fdc.pos++;
if (fdc.pos==512)// && fdc.sector!=fdc.params[5])
{
// printf("Sector complete! %02X\n",fdc.params[5]);
fdc.pos=0;
fdc.sector++;
if (fdc.sector > fdc.params[5])
{
// printf("Overrunnit!\n");
// dumpregs();
// exit(-1);
fdc.sector=1;
if (fdc.command & 0x80)
{
fdc.head ^= 1;
if (!fdc.head)
{
fdc.track[fdc.drive]++;
if (fdc.track[fdc.drive] >= TRACKS[fdc.drive])
{
fdc.track[fdc.drive] = TRACKS[fdc.drive];
fdc.pos = 512;
}
}
}
else
fdc.pos = 512;
}
if (fdc_abort_f)
fdc.pos = 512;
}
return;
/* printf("Read data\n");
printf("Side %i Track %i Sector %i sector size %i\n",fdc.params[1],fdc.params[2],fdc.params[3],fdc.params[4]);
dumpregs();
exit(-1);*/
case 7: /*Recalibrate*/
fdc.track[fdc.drive]=0;
if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
fdc.st0=0x20|fdc.drive|(fdc.head?4:0);
discint=-3;
disctime=2048;
// printf("Recalibrate complete!\n");
fdc.stat = 0x80 | (1 << fdc.drive);
return;
case 8: /*Sense interrupt status*/
// pclog("Sense interrupt status %i\n", fdc_reset_stat);
fdc.dat = fdc.st0;
if (fdc_reset_stat)
{
fdc.st0 = (fdc.st0 & 0xf8) | (4 - fdc_reset_stat) | (fdc.head ? 4 : 0);
fdc_reset_stat--;
}
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[9] = fdc.st0;
fdc.res[10] = fdc.track[fdc.drive];
if (!fdc_reset_stat) fdc.st0 = 0x80;
paramstogo = 2;
discint = 0;
disctime = 0;
return;
case 10: /*Read sector ID*/
disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
fdc.sector++;
if (fdc.sector==SECTORS[fdc.drive]+1)
fdc.sector=1;
return;
case 15: /*Seek*/
fdc.track[fdc.drive]=fdc.params[1];
if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0;
// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive);
fdc.st0=0x20|fdc.drive|(fdc.head?4:0);
discint=-3;
disctime=2048;
fdc.stat = 0x80 | (1 << fdc.drive);
// pclog("Stat %02X ST0 %02X\n", fdc.stat, fdc.st0);
return;
case 0x0e: /*Dump registers*/
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[3] = fdc.track[0];
fdc.res[4] = fdc.track[1];
fdc.res[5] = 0;
fdc.res[6] = 0;
fdc.res[7] = fdc.specify[0];
fdc.res[8] = fdc.specify[1];
fdc.res[9] = fdc.eot[fdc.drive];
fdc.res[10] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0);
paramstogo=10;
discint=0;
disctime=0;
return;
case 0x10: /*Version*/
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0x90;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0x12:
fdc.perp = fdc.params[0];
fdc.stat = 0x80;
disctime = 0;
// picint(0x40);
return;
case 0x13: /*Configure*/
fdc.config = fdc.params[1];
fdc.pretrk = fdc.params[2];
fdc.stat = 0x80;
disctime = 0;
// picint(0x40);
return;
case 0x14: /*Unlock*/
fdc.lock = 0;
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0x94: /*Lock*/
fdc.lock = 1;
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0x10;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0xfc: /*Invalid*/
fdc.dat = fdc.st0 = 0x80;
// pclog("Inv!\n");
//picint(0x40);
fdc.stat = (fdc.stat & 0xf) | 0xd0;
// fdc.stat|=0xC0;
fdc.res[10] = fdc.st0;
paramstogo=1;
discint=0;
disctime=0;
return;
case 0xFD: /*DMA aborted (PC1512)*/
/*In the absence of other information, lie and claim the command completed successfully.
The PC1512 BIOS likes to program the FDC to write to all sectors on the track, but
program the DMA length to the number of sectors actually transferred. Not aborting
correctly causes disc corruption.
This only matters on writes, on reads the DMA controller will ignore excess data.
*/
pclog("DMA Aborted\n");
disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
case 0xFE: /*Drive empty*/
pclog("Drive empty\n");
fdc.stat = 0x10;
disctime = 0;
/* disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=0xC8|(fdc.head?4:0)|fdc.drive;
fdc.res[5]=0;
fdc.res[6]=0;
fdc.res[7]=0;
fdc.res[8]=0;
fdc.res[9]=0;
fdc.res[10]=0;
paramstogo=7;*/
return;
case 0xFF: /*Wrong rate*/
pclog("Wrong rate\n");
disctime=0;
discint=-2;
picint(0x40);
fdc.stat=0xD0;
fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive;
fdc.res[5]=5;
fdc.res[6]=0;
fdc.res[7]=0;
fdc.res[8]=0;
fdc.res[9]=0;
fdc.res[10]=0;
paramstogo=7;
return;
}
// printf("Bad FDC disc int %i\n",discint);
// dumpregs();
// exit(-1);
}
void fdc_init()
{
io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
}
void fdc_remove()
{
io_removehandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
io_removehandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL);
}

4
src/fdc.h Normal file
View File

@@ -0,0 +1,4 @@
void fdc_init();
void fdc_remove();
void fdc_reset();
void fdc_poll();

178
src/filters.h Normal file
View File

@@ -0,0 +1,178 @@
#define NCoef 2
//fc=350Hz
static inline float low_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.00049713569693400649,
0.00099427139386801299,
0.00049713569693400649
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.93522955470669530000,
0.93726236021404663000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=350Hz
static inline float low_cut_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.96839970114733542000,
-1.93679940229467080000,
0.96839970114733542000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.93522955471202770000,
0.93726236021916731000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=3.5kHz
static inline float high_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.72248704753064896000,
-1.44497409506129790000,
0.72248704753064896000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.36640781670578510000,
0.52352474706139873000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
//fc=3.5kHz
static inline float high_cut_iir(int i, float NewSample) {
float ACoef[NCoef+1] = {
0.03927726802250377400,
0.07855453604500754700,
0.03927726802250377400
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.36640781666419950000,
0.52352474703279628000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}
#undef NCoef
#define NCoef 1
//fc=3.2kHz
static inline float sb_iir(int i, float NewSample) {
/* float ACoef[NCoef+1] = {
0.03356837051492005100,
0.06713674102984010200,
0.03356837051492005100
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-1.41898265221812010000,
0.55326988968868285000
};*/
float ACoef[NCoef+1] = {
0.17529642630084405000,
0.17529642630084405000
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-0.64940759319751051000
};
static float y[2][NCoef+1]; //output samples
static float x[2][NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[i][n] = x[i][n-1];
y[i][n] = y[i][n-1];
}
//Calculate the new output
x[i][0] = NewSample;
y[i][0] = ACoef[0] * x[i][0];
for(n=1; n<=NCoef; n++)
y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
return y[i][0];
}

625
src/gus.c Normal file
View File

@@ -0,0 +1,625 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ibm.h"
extern int ins;
extern int timetolive;
int output;
//#define GUSRATECONST (44100.0/48000.0)
uint8_t *gusram;
struct
{
int global;
uint32_t addr,dmaaddr;
int voice;
uint32_t start[32],end[32],cur[32];
uint32_t startx[32],endx[32],curx[32];
uint32_t rstart[32],rend[32],rcur[32];
uint16_t freq[32];
uint16_t rfreq[32];
uint8_t ctrl[32];
uint8_t rctrl[32];
int curvol[32];
int t1on,t2on;
uint8_t tctrl;
uint16_t t1,t2,t1l,t2l;
uint8_t irqstatus,irqstatus2;
uint8_t adcommand;
int waveirqs[32],rampirqs[32];
int voices;
uint8_t dmactrl;
} gus;
double vol16bit[4096];
void initgus()
{
int c;
for (c=0;c<32;c++)
{
gus.ctrl[c]=1;
gus.rctrl[c]=1;
gus.rfreq[c]=63*512;
}
gusram=malloc(1024*1024);
double out = 1.0;
for (c=4095;c>=0;c--) {
vol16bit[c]=out;//(float)c/4095.0;//out;
out/=1.002709201; /* 0.0235 dB Steps */
}
printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]);
gus.voices=14;
}
void dumpgus()
{
/* FILE *f=fopen("gusram.dmp","wb");
fwrite(gusram,1024*1024,1,f);
fclose(f);*/
}
void pollgusirqs()
{
int c;
gus.irqstatus&=~0x60;
for (c=0;c<32;c++)
{
if (gus.waveirqs[c])
{
// gus.waveirqs[c]=0;
gus.irqstatus2=0x60|c;
gus.irqstatus|=0x20;
// printf("Voice IRQ %i %02X %i\n",c,gus.irqstatus2,ins);
picintlevel(0x20);
// output=3;
// timetolive=5000;
return;
}
if (gus.rampirqs[c])
{
// gus.rampirqs[c]=0;
gus.irqstatus2=0xA0|c;
gus.irqstatus|=0x40;
// printf("Ramp IRQ %i %02X %i\n",c,gus.irqstatus2,ins);
picintlevel(0x20);
return;
}
}
gus.irqstatus2=0xE0;
// gus.irqstatus&=~0x20;
if (!gus.irqstatus) picintc(0x20);
}
int gusirqnext=0;
void writegus(uint16_t addr, uint8_t val)
{
int c,d;
// printf("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc);
switch (addr)
{
case 0x342: /*Voice select*/
gus.voice=val&31;
break;
case 0x343: /*Global select*/
gus.global=val;
break;
case 0x344: /*Global low*/
// if (gus.global!=0x43 && gus.global!=0x44) printf("Writing register %02X %02X %02X\n",gus.global,gus.voice,val);
switch (gus.global)
{
case 0: /*Voice control*/
// if (val&1 && !(gus.ctrl[gus.voice]&1)) printf("Voice on %i\n",gus.voice);
gus.ctrl[gus.voice]=val;
break;
case 1: /*Frequency control*/
gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF00)|val;
break;
case 2: /*Start addr high*/
gus.startx[gus.voice]=(gus.startx[gus.voice]&0xF807F)|(val<<7);
gus.start[gus.voice]=(gus.start[gus.voice]&0x1F00FFFF)|(val<<16);
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
break;
case 3: /*Start addr low*/
gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFFFF00)|val;
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
break;
case 4: /*End addr high*/
gus.endx[gus.voice]=(gus.endx[gus.voice]&0xF807F)|(val<<7);
gus.end[gus.voice]=(gus.end[gus.voice]&0x1F00FFFF)|(val<<16);
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
break;
case 5: /*End addr low*/
gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFFFF00)|val;
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
break;
case 0x6: /*Ramp frequency*/
gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
// printf("RFREQ %02X %i %i %f\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))));
break;
case 0x9: /*Current volume*/
gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE0000)|(val<<9);
// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]);
break;
case 0xA: /*Current addr high*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1F00FFFF)|(val<<16);
gus.curx[gus.voice]=(gus.curx[gus.voice]&0xF807F00)|((val<<7)<<8);
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0F807F00)|((val<<7)<<8);
// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
break;
case 0xB: /*Current addr low*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFFFF00)|val;
// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
break;
case 0x42: /*DMA address low*/
gus.dmaaddr=(gus.dmaaddr&0xFF000)|(val<<4);
break;
case 0x43: /*Address low*/
gus.addr=(gus.addr&0xFFF00)|val;
break;
case 0x45: /*Timer control*/
// printf("Timer control %02X\n",val);
gus.tctrl=val;
break;
}
break;
case 0x345: /*Global high*/
// if (gus.global!=0x43 && gus.global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X\n",gus.global,gus.voice,val,CS,pc);
switch (gus.global)
{
case 0: /*Voice control*/
if (!(val&1) && gus.ctrl[gus.voice]&1)
{
// printf("Voice on %i - start %05X end %05X freq %04X\n",gus.voice,gus.start[gus.voice],gus.end[gus.voice],gus.freq[gus.voice]);
// if (val&0x40) gus.cur[gus.voice]=gus.end[gus.voice]<<8;
// else gus.cur[gus.voice]=gus.start[gus.voice]<<8;
}
if (val&2) val|=1;
gus.waveirqs[gus.voice]=val&0x80;
gus.ctrl[gus.voice]=val&0x7F;
pollgusirqs();
break;
case 1: /*Frequency control*/
gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF)|(val<<8);
break;
case 2: /*Start addr high*/
gus.startx[gus.voice]=(gus.startx[gus.voice]&0x07FFF)|(val<<15);
gus.start[gus.voice]=(gus.start[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
// printf("Write %i start %08X %08X %02X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice],val);
break;
case 3: /*Start addr low*/
gus.startx[gus.voice]=(gus.startx[gus.voice]&0xFFF80)|(val&0x7F);
gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFF00FF)|(val<<8);
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
break;
case 4: /*End addr high*/
gus.endx[gus.voice]=(gus.endx[gus.voice]&0x07FFF)|(val<<15);
gus.end[gus.voice]=(gus.end[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
// printf("Write %i end %08X %08X %02X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice],val);
break;
case 5: /*End addr low*/
gus.endx[gus.voice]=(gus.endx[gus.voice]&0xFFF80)|(val&0x7F);
gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFF00FF)|(val<<8);
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
break;
case 0x6: /*Ramp frequency*/
gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
// printf("RFREQ %02X %i %i %f %i\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))),ins);
break;
case 0x7: /*Ramp start*/
gus.rstart[gus.voice]=val<<17;
break;
case 0x8: /*Ramp end*/
gus.rend[gus.voice]=val<<17;
break;
case 0x9: /*Current volume*/
gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE00)|(val<<17);
// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]);
break;
case 0xA: /*Current addr high*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
gus.curx[gus.voice]=(gus.curx[gus.voice]&0x07FFF00)|((val<<15)<<8);
// printf("Write %i cur %08X %08X %02X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice],val);
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x007FFF00)|((val<<15)<<8);
break;
case 0xB: /*Current addr low*/
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFF00FF)|(val<<8);
gus.curx[gus.voice]=(gus.curx[gus.voice]&0xFFF8000)|((val&0x7F)<<8);
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0FFF8000)|((val&0x7F)<<8);
// printf("Write %i cur %08X %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
break;
case 0xD: /*Ramp control*/
if (val&2) val|=1;
gus.rampirqs[gus.voice]=val&0x80;
gus.rctrl[gus.voice]=val&0x7F;
pollgusirqs();
// printf("Ramp control %02i %02X %02X %i\n",gus.voice,val,gus.rampirqs[gus.voice],ins);
break;
case 0xE:
gus.voices=(val&63)+1;
if (gus.voices>32) gus.voices=32;
if (gus.voices<14) gus.voices=14;
gus.global=val;
// printf("GUS voices %i\n",val&31);
break;
case 0x41: /*DMA*/
if (val&1)
{
// printf("DMA start! %05X %02X\n",gus.dmaaddr,val);
c=0;
while (c<65536)
{
d=readdma3();
if (d==-1) break;
if (val&0x80) d^=0x80;
gusram[gus.dmaaddr]=d;
gus.dmaaddr++;
gus.dmaaddr&=0xFFFFF;
c++;
}
// printf("Transferred %i bytes\n",c);
gus.dmactrl=val&~0x40;
if (val&0x20) gusirqnext=1;
// exit(-1);
}
break;
case 0x42: /*DMA address low*/
gus.dmaaddr=(gus.dmaaddr&0xFF0)|(val<<12);
break;
case 0x43: /*Address low*/
gus.addr=(gus.addr&0xF00FF)|(val<<8);
break;
case 0x44: /*Address high*/
gus.addr=(gus.addr&0xFFFF)|((val<<16)&0xF0000);
break;
case 0x45: /*Timer control*/
if (!(val&4)) gus.irqstatus&=~4;
if (!(val&8)) gus.irqstatus&=~8;
// printf("Timer control %02X\n",val);
/* if ((val&4) && !(gus.tctrl&4))
{
gus.t1=gus.t1l;
gus.t1on=1;
}*/
gus.tctrl=val;
break;
case 0x46: /*Timer 1*/
gus.t1=gus.t1l=val;
gus.t1on=1;
// printf("GUS timer 1 %i\n",val);
break;
case 0x47: /*Timer 2*/
gus.t2=gus.t2l=val<<2;
gus.t2on=1;
// printf("GUS timer 2 %i\n",val);
break;
}
break;
case 0x347: /*DRAM access*/
gusram[gus.addr]=val;
// pclog("GUS RAM write %05X %02X\n",gus.addr,val);
gus.addr&=0xFFFFF;
break;
case 0x248: case 0x388: gus.adcommand=val; break;
}
}
uint8_t readgus(uint16_t addr)
{
uint8_t val;
// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus.global);
// output=3;
switch (addr)
{
case 0x240: return 0;
case 0x246: /*IRQ status*/
val=gus.irqstatus;
// printf("246 status %02X\n",val);
// gus.irqstatus=0;
// if (gus.irqstatus2==0xE0) picintc(0x20);
return val;
case 0x24A:
return gus.adcommand;
case 0x24B: case 0x24F: return 0;
case 0x340: /*MIDI status*/
case 0x341: /*MIDI data*/
return 0;
case 0x342: return gus.voice;
case 0x343: return gus.global;
case 0x344: /*Global low*/
// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("Reading register %02X %02X\n",gus.global,gus.voice);
switch (gus.global)
{
case 0x82: /*Start addr high*/
return gus.start[gus.voice]>>16;
case 0x83: /*Start addr low*/
return gus.start[gus.voice]&0xFF;
case 0x89: /*Current volume*/
return gus.rcur[gus.voice]>>9;
case 0x8A: /*Current addr high*/
return gus.cur[gus.voice]>>16;
case 0x8B: /*Current addr low*/
return gus.cur[gus.voice]&0xFF;
case 0x8F: /*IRQ status*/
val=gus.irqstatus2;
// pclog("Read IRQ status - %02X\n",val);
gus.rampirqs[gus.irqstatus2&0x1F]=0;
gus.waveirqs[gus.irqstatus2&0x1F]=0;
pollgusirqs();
return val;
}
//fatal("Bad GUS global low read %02X\n",gus.global);
break;
case 0x345: /*Global high*/
// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("HReading register %02X %02X\n",gus.global,gus.voice);
switch (gus.global)
{
case 0x80: /*Voice control*/
return gus.ctrl[gus.voice]|(gus.waveirqs[gus.voice]?0x80:0);
case 0x82: /*Start addr high*/
return gus.start[gus.voice]>>24;
case 0x83: /*Start addr low*/
return gus.start[gus.voice]>>8;
case 0x89: /*Current volume*/
return gus.rcur[gus.voice]>>17;
case 0x8A: /*Current addr high*/
return gus.cur[gus.voice]>>24;
case 0x8B: /*Current addr low*/
return gus.cur[gus.voice]>>8;
case 0x8D:
// pclog("Read ramp control %02X %08X %08X %08X %08X\n",gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0),gus.rcur[gus.voice],gus.rfreq[gus.voice],gus.rstart[gus.voice],gus.rend[gus.voice]);
return gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0);
case 0x8F: /*IRQ status*/
val=gus.irqstatus2;
// pclog("Read IRQ status - %02X\n",val);
gus.rampirqs[gus.irqstatus2&0x1F]=0;
gus.waveirqs[gus.irqstatus2&0x1F]=0;
pollgusirqs();
return val;
case 0x41: /*DMA control*/
val=gus.dmactrl|((gus.irqstatus&0x80)?0x40:0);
gus.irqstatus&=~0x80;
return val;
case 0x45: /*Timer control*/
return gus.tctrl;
case 0x49: /*Sampling control*/
return 0;
}
//fatal("Bad GUS global high read %02X\n",gus.global);
break;
case 0x346: return 0;
case 0x347: /*DRAM access*/
val=gusram[gus.addr];
// pclog("GUS RAM read %05X %02X\n",gus.addr,val);
// output=3;
gus.addr&=0xFFFFF;
return val;
case 0x349: return 0;
}
// printf("Bad GUS read %04X! %02X\n",addr,gus.global);
// exit(-1);
return 0;
}
void pollgus()
{
if (gus.t1on)
{
gus.t1++;
if (gus.t1>=0xFF)
{
// gus.t1on=0;
gus.t1=gus.t1l;
if (gus.tctrl&4)
{
picintlevel(0x20);
gus.irqstatus|=4;
// printf("GUS T1 IRQ!\n");
}
}
}
if (gusirqnext)
{
gusirqnext=0;
gus.irqstatus|=0x80;
picintlevel(0x20);
}
}
void pollgus2()
{
if (gus.t2on)
{
gus.t2++;
if (gus.t2>=(0xFF<<2))
{
// gus.t2on=0;
gus.t2=gus.t2l;
if (gus.tctrl&8)
{
picintlevel(0x20);
gus.irqstatus|=8;
// printf("GUS T2 IRQ!\n");
}
}
}
if (gusirqnext)
{
gusirqnext=0;
gus.irqstatus|=0x80;
picintlevel(0x20);
}
}
float gusfreqs[]=
{
44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696,
23746,22866,22050,21289,20580,19916,19293
};
int16_t gusbufferx[65536];
int guspos=0;
void getgus(int16_t *p, int count)
{
memcpy(p,gusbufferx,count*4);
// printf("Get %i samples %i\n",guspos,count);
guspos=0;
pollgusirqs();
}
void pollgussamp()
{
uint32_t addr;
int c,d;
int16_t v;
int32_t vl;
int16_t p[2];
float GUSRATECONST;
if (guspos>65500) return;
// return;
if (gus.voices<14) GUSRATECONST=44100.0/48000.0;
else GUSRATECONST=gusfreqs[gus.voices-14]/48000.0;
// printf("Voices %i freq %f\n",gus.voices,GUSRATECONST*48000.0);
// for (c=0;c<count;c++)
// {
p[0]=p[1]=0;
for (d=0;d<32;d++)
{
if (!(gus.ctrl[d]&1))
{
if (gus.ctrl[d]&4)
{
addr=gus.cur[d]>>9;
addr=(addr&0xC0000)|((addr<<1)&0x3FFFE);
if (!(gus.freq[d]>>10)) /*Interpolate*/
{
vl=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80)*(511-(gus.cur[d]&511));
vl+=(int16_t)(int8_t)((gusram[(addr+3)&0xFFFFF]^0x80)-0x80)*(gus.cur[d]&511);
v=vl>>9;
}
else
v=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80);
}
else
{
if (!(gus.freq[d]>>10)) /*Interpolate*/
{
vl=((int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80))*(511-(gus.cur[d]&511));
vl+=((int8_t)((gusram[((gus.cur[d]>>9)+1)&0xFFFFF]^0x80)-0x80))*(gus.cur[d]&511);
v=vl>>9;
}
else
v=(int16_t)(int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80);
}
// v=(int16_t)((float)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80)*32.0*vol16bit[(gus.rcur[d]>>13)&4095]);
if ((gus.rcur[d]>>13)>4095) v=(int16_t)(float)(v)*24.0*vol16bit[4095];
else v=(int16_t)(float)(v)*24.0*vol16bit[(gus.rcur[d]>>13)&4095];
// if (!d) printf("%08X %08X %08X %05X %08X %08X %04X %f %04X %08X %i\n",gus.cur[d],gus.start[d],gus.end[d],gus.cur[d]>>9,gus.startx[d],gus.endx[d],gus.rcur[d],vol16bit[0],v,gus.freq[d],ins);
// if (!d)
// {
p[0]+=v;
p[1]+=v;
// }
// printf("Data from %08X\n",gus.cur[d]>>8);
if (gus.ctrl[d]&0x40)
{
gus.cur[d]-=(gus.freq[d]>>1)*GUSRATECONST;
if (gus.cur[d]<=gus.start[d])
{
if (!(gus.rctrl[d]&4))
{
if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1;
else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40;
gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d];
}
if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1;
}
}
else
{
gus.cur[d]+=(gus.freq[d]>>1)*GUSRATECONST;
// pclog("GUS add %08X %f\n",gus.freq[d],GUSRATECONST);
if (gus.cur[d]>=gus.end[d])
{
if (!(gus.rctrl[d]&4))
{
// gus.ctrl[d]|=1;
if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1;
else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40;
gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d];
}
if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1;
}
}
}
if (!(gus.rctrl[d]&1))
{
if (gus.rctrl[d]&0x40)
{
gus.rcur[d]-=gus.rfreq[d]*GUSRATECONST*16;
// printf("RCUR- %i %i %i %i %i\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]);
if (gus.rcur[d]<=gus.rstart[d])
{
if (gus.rctrl[d]&8) gus.rcur[d]=gus.rend[d]<<8;
else gus.rctrl[d]|=1;
if (gus.rctrl[d]&0x20)
{
gus.rampirqs[d]=1;
// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]);
}
}
}
else
{
gus.rcur[d]+=gus.rfreq[d]*GUSRATECONST*16;
// printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]);
if (gus.rcur[d]>=gus.rend[d])
{
if (gus.rctrl[d]&8) gus.rcur[d]=gus.rstart[d]<<8;
else gus.rctrl[d]|=1;
if (gus.rctrl[d]&0x20)
{
gus.rampirqs[d]=1;
// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]);
}
}
}
}
}
gusbufferx[guspos++]=p[0];
gusbufferx[guspos++]=p[1];
if (guspos==65536) guspos=0;
// }
pollgusirqs();
}
void gus_init()
{
io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL);
io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL);
io_sethandler(0x0388, 0x0001, NULL, NULL, NULL, writegus, NULL, NULL);
}

155
src/harddisk.c Normal file
View File

@@ -0,0 +1,155 @@
/*Due to the lack of a real hard disc BIOS (other than the WD ST-506 one in MESS),
I wrote this. It's better as it can handle bigger discs, but is (potentially)
less compatible.*/
#include <stdio.h>
#include <string.h>
#include "ibm.h"
extern int output;
void inithdc()
{
return;
hdc[0].f=romfopen("hdc.img","rb+");
if (!hdc[0].f)
{
hdc[0].f=romfopen("hdc.img","wb");
putc(0,hdc[0].f);
fclose(hdc[0].f);
hdc[0].f=romfopen("hdc.img","rb+");
}
// hdc[0].spt=16;
// hdc[0].hpc=5;
// hdc[0].tracks=977;
hdc[1].f=romfopen("hdd.img","rb+");
if (!hdc[1].f)
{
hdc[1].f=romfopen("hdd.img","wb");
putc(0,hdc[1].f);
fclose(hdc[1].f);
hdc[1].f=romfopen("hdd.img","rb+");
}
// hdc[1].spt=32;
// hdc[1].hpc=16;
// hdc[1].tracks=447;
}
void int13hdc()
{
int drv=DL&1;
int track,head,sector;
uint32_t addr;
int c,d;
uint8_t buf[512];
fullspeed();
// ram[0x475]=2;
// printf("INT 13 HDC %04X %04X %04X %04X %04X:%04X\n",AX,BX,CX,DX,CS,pc);
switch (AH)
{
case 0: /*Reset disk system*/
AH=0;
flags&=~C_FLAG;
break;
case 2: /*Read sectors into memory*/
// printf("Read %i sectors to %04X:%04X\n",AL,es>>4,BX);
// if (es==0xf940) output=3;
track=CH|((CL&0xC0)<<2);
sector=(CL&63)-1;
head=DH;
addr=((((track*hdc[drv].hpc)+head)*hdc[drv].spt)+sector)*512;
// printf("Read track %i head %i sector %i addr %08X HPC %i SPT %i %08X\n",track,head,sector,addr,hdc[drv].hpc,hdc[drv].spt,old8);
fseek(hdc[drv].f,addr,SEEK_SET);
for (c=0;c<AL;c++)
{
fread(buf,512,1,hdc[drv].f);
for (d=0;d<512;d++)
{
writemembl(es+BX+(c*512)+d,buf[d]/*getc(hdc[drv].f)*/);
}
}
AH=0;
flags&=~C_FLAG;
readflash=1;
break;
case 3: /*Write sectors*/
track=CH|((CL&0xC0)<<2);
sector=(CL&63)-1;
head=DH;
addr=((((track*hdc[drv].hpc)+head)*hdc[drv].spt)+sector)*512;
fseek(hdc[drv].f,addr,SEEK_SET);
for (c=0;c<AL;c++)
{
for (d=0;d<512;d++)
{
putc(readmembl(es+BX+(c*512)+d),hdc[drv].f);
}
}
AH=0;
flags&=~C_FLAG;
readflash=1;
break;
case 4: /*Verify sectors*/
AH=0; /*We don't actually do anything here*/
flags&=~C_FLAG;
break;
case 8: /*Get drive parameters*/
AH=0;
CH=hdc[drv].tracks&255;
CL=hdc[drv].spt;
CL|=((hdc[drv].tracks>>2)&0xC0);
// printf("Drive params - %02X %02X %i %i\n",CL,CH,hdc[drv].tracks,hdc[drv].spt);
DH=hdc[drv].hpc-1;
DL=2;
flags&=~C_FLAG;
break;
case 0x10: /*Check drive ready*/
AH=0;
flags&=~C_FLAG;
break;
case 0x18: /*Set media type*/
AH=1;
flags|=C_FLAG;
break;
default:
AH=1;
flags|=C_FLAG;
// printf("Bad HDC int 13 %04X\n",AX);
// dumpregs();
// exit(-1);
}
}
char tempbuf[512*63];
void resizedrive(int drv)
{
FILE *f;
int c,d,e;
// char temp[512*63];
if (!drv)
{
fflush(hdc[0].f);
if (hdc[0].f) fclose(hdc[0].f);
f=romfopen("hdc.img","wb");
}
else
{
fflush(hdc[1].f);
if (hdc[1].f) fclose(hdc[1].f);
f=romfopen("hdd.img","wb");
}
memset(tempbuf,0,512*63);
for (c=0;c<hdc[drv].tracks;c++)
{
for (d=0;d<hdc[drv].hpc;d++)
{
// for (e=0;e<hdc[drv].spt;e++)
// {
fwrite(tempbuf,512*hdc[drv].spt,1,f);
// }
}
}
fclose(f);
if (!drv) hdc[0].f=romfopen("hdc.img","rb+");
else hdc[1].f=romfopen("hdd.img","rb+");
}

45
src/headland.c Normal file
View File

@@ -0,0 +1,45 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "cpu.h"
#include "headland.h"
static int headland_index;
static uint8_t headland_regs[256];
void headland_write(uint16_t addr, uint8_t val)
{
if (addr & 1)
{
if (headland_index == 0xc1 && !is486) val = 0;
headland_regs[headland_index] = val;
pclog("Headland write %02X %02X\n",headland_index,val);
if (headland_index == 0x82)
{
shadowbios = val & 0x10;
shadowbios_write = !(val & 0x10);
if (shadowbios)
mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL );
else
mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml);
}
}
else headland_index = val;
}
uint8_t headland_read(uint16_t addr)
{
if (addr & 1)
{
if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix)
return 0xff; /*Don't conflict with Cyrix config registers*/
return headland_regs[headland_index];
}
return headland_index;
}
void headland_init()
{
io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL);
}

1
src/headland.h Normal file
View File

@@ -0,0 +1 @@
void headland_init();

468
src/ibm.h Normal file
View File

@@ -0,0 +1,468 @@
#include <stdio.h>
#include <stdint.h>
#define printf pclog
/*Memory*/
uint8_t *ram,*vram;
unsigned char isram[0x10000];
uint32_t rammask;
int readlookup[256],readlookupp[256];
uint32_t *readlookup2;
int readlnext;
int writelookup[256],writelookupp[256];
uint32_t *writelookup2;
int writelnext;
extern int mmu_perm;
#define readmemb(a) ((readlookup2[(a)>>12]==0xFFFFFFFF)?readmembl(a):ram[readlookup2[(a)>>12]+((a)&0xFFF)])
#define readmemw(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE)?readmemwl(s,a):*((uint16_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)])))
#define readmeml(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC)?readmemll(s,a):*((uint32_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)])))
//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v
//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v
//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v
//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a))
//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v)
//void writememb(uint32_t addr, uint8_t val);
uint8_t readmembl(uint32_t addr);
void writemembl(uint32_t addr, uint8_t val);
uint8_t readmemb386l(uint32_t seg, uint32_t addr);
void writememb386l(uint32_t seg, uint32_t addr, uint8_t val);
uint16_t readmemwl(uint32_t seg, uint32_t addr);
void writememwl(uint32_t seg, uint32_t addr, uint16_t val);
uint32_t readmemll(uint32_t seg, uint32_t addr);
void writememll(uint32_t seg, uint32_t addr, uint32_t val);
uint8_t *getpccache(uint32_t a);
uint32_t mmutranslatereal(uint32_t addr, int rw);
void addreadlookup(uint32_t virt, uint32_t phys);
void addwritelookup(uint32_t virt, uint32_t phys);
/*IO*/
uint8_t inb(uint16_t port);
void outb(uint16_t port, uint8_t val);
uint16_t inw(uint16_t port);
void outw(uint16_t port, uint16_t val);
uint32_t inl(uint16_t port);
void outl(uint16_t port, uint32_t val);
FILE *romfopen(char *fn, char *mode);
extern int shadowbios,shadowbios_write;
extern int cache;
extern int mem_size;
extern int readlnum,writelnum;
extern int memwaitstate;
/*Processor*/
#define EAX regs[0].l
#define ECX regs[1].l
#define EDX regs[2].l
#define EBX regs[3].l
#define ESP regs[4].l
#define EBP regs[5].l
#define ESI regs[6].l
#define EDI regs[7].l
#define AX regs[0].w
#define CX regs[1].w
#define DX regs[2].w
#define BX regs[3].w
#define SP regs[4].w
#define BP regs[5].w
#define SI regs[6].w
#define DI regs[7].w
#define AL regs[0].b.l
#define AH regs[0].b.h
#define CL regs[1].b.l
#define CH regs[1].b.h
#define DL regs[2].b.l
#define DH regs[2].b.h
#define BL regs[3].b.l
#define BH regs[3].b.h
typedef union
{
uint32_t l;
uint16_t w;
struct
{
uint8_t l,h;
} b;
} x86reg;
x86reg regs[8];
uint16_t flags,eflags;
uint32_t /*cs,ds,es,ss,*/oldds,oldss,pc,olddslimit,oldsslimit,olddslimitw,oldsslimitw;
//uint16_t msw;
extern int ins,output;
extern int cycdiff;
typedef struct
{
uint32_t base;
uint32_t limit,limitw;
uint8_t access;
uint16_t seg;
} x86seg;
x86seg gdt,ldt,idt,tr;
x86seg _cs,_ds,_es,_ss,_fs,_gs;
x86seg _oldds;
uint32_t pccache;
uint8_t *pccache2;
/*Segments -
_cs,_ds,_es,_ss are the segment structures
CS,DS,ES,SS is the 16-bit data
cs,ds,es,ss are defines to the bases*/
//uint16_t CS,DS,ES,SS;
#define CS _cs.seg
#define DS _ds.seg
#define ES _es.seg
#define SS _ss.seg
#define FS _fs.seg
#define GS _gs.seg
#define cs _cs.base
#define ds _ds.base
#define es _es.base
#define ss _ss.base
#define fs _fs.base
#define gs _gs.base
#define CPL ((_cs.access>>5)&3)
void loadseg(uint16_t seg, x86seg *s);
void loadcs(uint16_t seg);
union
{
uint32_t l;
uint16_t w;
} CR0;
#define cr0 CR0.l
#define msw CR0.w
uint32_t cr2,cr3;
#define C_FLAG 0x0001
#define P_FLAG 0x0004
#define A_FLAG 0x0010
#define Z_FLAG 0x0040
#define N_FLAG 0x0080
#define T_FLAG 0x0100
#define I_FLAG 0x0200
#define D_FLAG 0x0400
#define V_FLAG 0x0800
#define NT_FLAG 0x4000
#define VM_FLAG 0x0002 /*In EFLAGS*/
#define WP_FLAG 0x10000 /*In CR0*/
#define IOPL ((flags>>12)&3)
#define IOPLp ((!(msw&1)) || (CPL<=IOPL))
//#define IOPLp 1
//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL))
extern int cycles;
extern int cycles_lost;
extern int is486;
extern uint8_t opcode;
extern int insc;
extern int fpucount;
extern float mips,flops;
extern int clockrate;
extern int cgate16;
extern int CPUID;
extern int cpl_override;
/*Timer*/
typedef struct PIT
{
uint32_t l[3];
double c[3];
uint8_t m[3];
uint8_t ctrl,ctrls[2];
int wp,rm[3],wm[3];
uint16_t rl[3];
int thit[3];
int delay[3];
int rereadlatch[3];
} PIT;
PIT pit;
void setpitclock(float clock);
int pitcount;
float pit_timer0_freq();
/*DMA*/
typedef struct DMA
{
uint16_t ab[4],ac[4];
uint16_t cb[4];
int cc[4];
int wp;
uint8_t m,mode[4];
uint8_t page[4];
uint8_t stat;
uint8_t command;
} DMA;
DMA dma,dma16;
/*PPI*/
typedef struct PPI
{
int s2;
uint8_t pa,pb;
} PPI;
PPI ppi;
extern int key_inhibit;
/*PIC*/
typedef struct PIC
{
uint8_t icw1,mask,ins,pend,mask2;
int icw;
uint8_t vector;
int read;
} PIC;
PIC pic,pic2;
extern int pic_intpending;
int intcount;
/*FDC*/
typedef struct FDC
{
uint8_t dor,stat,command,dat,st0;
int head,track[256],sector,drive,lastdrive;
int pos;
uint8_t params[256];
uint8_t res[256];
int pnum,ptot;
int rate;
uint8_t specify[256];
int eot[256];
int lock;
int perp;
uint8_t config, pretrk;
} FDC;
FDC fdc;
int disctime;
char discfns[2][256];
int driveempty[2];
/*Config stuff*/
#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) && (romset<ROM_TANDY || romset>=ROM_IBMAT))
#define HERCULES (gfxcard==GFX_HERCULES && (romset<ROM_TANDY || romset>=ROM_IBMAT))
#define AMSTRAD (romset==ROM_PC1512 || romset==ROM_PC1640 || romset==ROM_PC3086)
#define AMSTRADIO (romset==ROM_PC1512 || romset==ROM_PC1640 || romset==ROM_PC200 || romset==ROM_PC2086 || romset == ROM_PC3086)
#define TANDY (romset==ROM_TANDY/* || romset==ROM_IBMPCJR*/)
#define VID_EGA (gfxcard==GFX_EGA)
#define EGA (romset==ROM_PC1640 || VID_EGA || VGA)
#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200)
#define SVGA (gfxcard==GFX_ET4000 && VGA)
#define TRIDENT (gfxcard==GFX_TVGA && !OTI067)
#define OTI067 (romset==ROM_ACER386)
#define ET4000 (gfxcard==GFX_ET4000 && VGA)
#define ET4000W32 (gfxcard==GFX_ET4000W32 && VGA)
#define AT (romset>=ROM_IBMAT)
#define PCI (romset == ROM_PCI486)
#define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486)
int FASTDISC;
int ADLIB;
int GAMEBLASTER;
enum
{
ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/
ROM_IBMXT, /*301 keyboard error*/
ROM_GENXT, /*'Generic XT BIOS'*/
ROM_DTKXT,
ROM_EUROPC,
ROM_OLIM24,
ROM_TANDY,
ROM_PC1512,
ROM_PC200,
ROM_PC1640,
ROM_PC2086,
ROM_PC3086,
ROM_IBMAT,
ROM_CMDPC30,
ROM_AMI286,
ROM_DELL200,
ROM_MISC286,
ROM_IBMAT386,
ROM_ACER386,
ROM_MEGAPC,
ROM_AMI386,
ROM_AMI486,
ROM_WIN486,
ROM_PCI486
};
//#define ROM_IBMPCJR 5 /*Not working! ROMs are corrupt*/
#define is386 (romset>=ROM_IBMAT386)
#define is386sx 0
int hasfpu;
int romset;
#define GFX_CGA 0
#define GFX_MDA 1
#define GFX_HERCULES 2
#define GFX_EGA 3 /*Using IBM EGA BIOS*/
//#define GFX_OTI067 3 /*Using BIOS from Acer 386SX/25N - edit - only works with Acer BIOS! Stupid integrated systems*/
#define GFX_TVGA 4 /*Using Trident 8900D BIOS*/
#define GFX_ET4000 5 /*Tseng ET4000*/
#define GFX_ET4000W32 6 /*Tseng ET4000/W32p (Diamond Stealth 32)*/
#define GFX_BAHAMAS64 7 /*S3 Vision864 (Paradise Bahamas 64)*/
#define GFX_N9_9FX 8 /*S3 764/Trio64 (Number Nine 9FX)*/
#define GFX_STEALTH64 9 /*S3 Vision964 (Diamond Stealth 64 VRAM PCI)*/
int gfxcard;
int cpuspeed;
/*Video*/
void (*pollvideo)();
void pollega();
int readflash;
uint8_t hercctrl;
int slowega,egacycles,egacycles2;
extern uint8_t gdcreg[16];
extern int incga;
extern int egareads,egawrites;
extern int cga_comp;
extern int vid_resize;
extern int winsizex,winsizey;
extern int chain4;
uint8_t readvram(uint16_t addr);
void writevram(uint16_t addr, uint8_t val);
void writevramgen(uint16_t addr, uint8_t val);
uint8_t readtandyvram(uint16_t addr);
void writetandy(uint16_t addr, uint8_t val);
void writetandyvram(uint16_t addr, uint8_t val);
extern int et4k_b8000;
extern int changeframecount;
extern uint8_t changedvram[(8192*1024)/1024];
void writeega_chain4(uint32_t addr, uint8_t val);
extern uint32_t svgarbank,svgawbank;
/*Serial*/
extern int mousedelay;
/*Sound*/
uint8_t spkstat;
float spktime,soundtime,gustime,gustime2,vidtime,rtctime;
int ppispeakon;
//#define SPKCONST (8000000.0/44100.0)
float SPKCONST;
float SOUNDCONST;
float CASCONST;
float GUSCONST,GUSCONST2;
float CGACONST;
float MDACONST;
float VGACONST1,VGACONST2;
float RTCCONST;
int gated,speakval,speakon;
#define SOUNDBUFLEN (48000/10)
/*Sound Blaster*/
int sbenable,sblatchi,sblatcho,sbcount,sb_enable_i,sb_count_i;
int16_t sbdat;
void setsbclock(float clock);
#define SADLIB 1 /*No DSP*/
#define SB1 2 /*DSP v1.05*/
#define SB15 3 /*DSP v2.00*/
#define SB2 4 /*DSP v2.01 - needed for high-speed DMA*/
#define SBPRO 5 /*DSP v3.00*/
#define SBPRO2 6 /*DSP v3.02 + OPL3*/
#define SB16 7 /*DSP v4.05 + OPL3*/
int sbtype;
struct
{
int vocl,vocr,voc;
int midl,midr,mid;
int masl,masr,mas;
} sbpmixer;
extern int sb_freq;
struct
{
int master_l,master_r;
int voice_l,voice_r;
int fm_l,fm_r;
int bass_l,bass_r;
int treble_l,treble_r;
int filter;
} mixer;
int clocks[3][12][4];
int at70hz;
char pcempath[512];
/*Hard disc*/
typedef struct
{
FILE *f;
int spt,hpc; /*Sectors per track, heads per cylinder*/
int tracks;
} PcemHDC;
PcemHDC hdc[2];
/*Keyboard*/
int keybsenddelay;
extern int kb_win;
/*CD-ROM*/
extern int cdrom_drive;
extern int idecallback[2];
extern int cdrom_enabled;
void pclog(const char *format, ...);
extern int nmi;
extern int times;
extern float isa_timing, bus_timing;

1757
src/ide.c Normal file

File diff suppressed because it is too large Load Diff

42
src/ide.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef __IDE__
#define __IDE__
struct IDE;
extern void writeide(int ide_board, uint16_t addr, uint8_t val);
extern void writeidew(int ide_board, uint16_t val);
extern uint8_t readide(int ide_board, uint16_t addr);
extern uint16_t readidew(int ide_board);
extern void callbackide(int ide_board);
extern void resetide(void);
extern void ide_init();
/*ATAPI stuff*/
typedef struct ATAPI
{
int (*ready)(void);
int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single);
void (*readtoc_session)(uint8_t *b, int msf, int maxlen);
uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf);
void (*readsector)(uint8_t *b, int sector);
void (*playaudio)(uint32_t pos, uint32_t len, int ismsf);
void (*seek)(uint32_t pos);
void (*load)(void);
void (*eject)(void);
void (*pause)(void);
void (*resume)(void);
void (*stop)(void);
void (*exit)(void);
} ATAPI;
extern ATAPI *atapi;
void atapi_discchanged();
extern int ideboard;
extern int idecallback[2];
extern char ide_fn[2][512];
#endif //__IDE__

196
src/io.c Normal file
View File

@@ -0,0 +1,196 @@
#include "ibm.h"
#include "ide.h"
#include "video.h"
#include "cpu.h"
uint8_t (*port_inb[0x10000][2])(uint16_t addr);
uint16_t (*port_inw[0x10000][2])(uint16_t addr);
uint32_t (*port_inl[0x10000][2])(uint16_t addr);
void (*port_outb[0x10000][2])(uint16_t addr, uint8_t val);
void (*port_outw[0x10000][2])(uint16_t addr, uint16_t val);
void (*port_outl[0x10000][2])(uint16_t addr, uint32_t val);
void io_init()
{
int c;
for (c = 0; c < 0x10000; c++)
{
port_inb[c][0] = port_inw[c][0] = port_inl[c][0] = NULL;
port_outb[c][0] = port_outw[c][0] = port_outl[c][0] = NULL;
port_inb[c][1] = port_inw[c][1] = port_inl[c][1] = NULL;
port_outb[c][1] = port_outw[c][1] = port_outl[c][1] = NULL;
}
}
void io_sethandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val))
{
int c;
for (c = 0; c < size; c++)
{
if (!port_inb[ base + c][0]) port_inb[ base + c][0] = inb;
else if (!port_inb[ base + c][1]) port_inb[ base + c][1] = inb;
if (!port_inw[ base + c][0]) port_inw[ base + c][0] = inw;
else if (!port_inw[ base + c][1]) port_inw[ base + c][1] = inw;
if (!port_inl[ base + c][0]) port_inl[ base + c][0] = inl;
else if (!port_inl[ base + c][1]) port_inl[ base + c][1] = inl;
if (!port_outb[base + c][0]) port_outb[base + c][0] = outb;
else if (!port_outb[base + c][1]) port_outb[base + c][1] = outb;
if (!port_outw[base + c][0]) port_outw[base + c][0] = outw;
else if (!port_outw[base + c][1]) port_outw[base + c][1] = outw;
if (!port_outl[base + c][0]) port_outl[base + c][0] = outl;
else if (!port_outl[base + c][1]) port_outl[base + c][1] = outl;
}
}
void io_removehandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val))
{
int c;
for (c = 0; c < size; c++)
{
if (port_inb[ base + c][0] == inb)
port_inb[ base + c][0] = NULL;
if (port_inb[ base + c][1] == inb)
port_inb[ base + c][1] = NULL;
if (port_inw[ base + c][0] == inw)
port_inw[ base + c][0] = NULL;
if (port_inw[ base + c][1] == inw)
port_inw[ base + c][1] = NULL;
if (port_inl[ base + c][0] == inl)
port_inl[ base + c][0] = NULL;
if (port_inl[ base + c][1] == inl)
port_inl[ base + c][1] = NULL;
if (port_outb[ base + c][0] == outb)
port_outb[ base + c][0] = NULL;
if (port_outb[ base + c][1] == outb)
port_outb[ base + c][1] = NULL;
if (port_outw[ base + c][0] == outw)
port_outw[ base + c][0] = NULL;
if (port_outw[ base + c][1] == outw)
port_outw[ base + c][1] = NULL;
if (port_outl[ base + c][0] == outl)
port_outl[ base + c][0] = NULL;
if (port_outl[ base + c][1] == outl)
port_outl[ base + c][1] = NULL;
}
}
uint8_t cgamode,cgastat=0,cgacol;
int hsync;
uint8_t lpt2dat;
int sw9;
int t237=0;
uint8_t inb(uint16_t port)
{
uint8_t temp = 0xff;
int tempi;
if (port_inb[port][0])
temp &= port_inb[port][0](port);
if (port_inb[port][1])
temp &= port_inb[port][1](port);
return temp;
if (port&0x80) sw9=2;
// if ((port&0x3F0)==0x3D0) printf("Video access read %03X %04X:%04X\n",port,cs>>4,pc);
// if (cs<0xF0000 || cs>0x100000) printf("IN %04X %04X(%06X):%08X\n",port,CS,cs,pc);
// /*if (output==3) */printf("IN %04X %04X:%04X\n",port,CS,pc);
// if (port == 0x23) pclog("IN %04X %04X:%08X\n", port, CS, pc);
switch (port)
{
case 0x220: case 0x221: case 0x222: case 0x223: /*Gameblaster*/
if (sbtype>=SBPRO) return readsb(port);
if (GAMEBLASTER) return readcms(port);
return 0xFF;
}
// printf("Bad IN port %04X %04X:%04X\n",port,cs>>4,pc);
return 0xff;
/*dumpregs();
exit(-1);*/
}
/*uint8_t inb(uint16_t port)
{
uint8_t temp = _inb(port);
// if (port != 0x61) pclog("IN %04X %02X %04X(%08X):%08X %f %04X %i %i\n", port, temp, CS, cs, pc, pit.c[1], CX, keybsenddelay, GetTickCount());
return temp;
}*/
uint8_t cpu_readport(uint32_t port) { return inb(port); }
void outb(uint16_t port, uint8_t val)
{
// /*if (output==3) */printf("OUT %04X %02X %04X(%08X):%08X %i %i\n", port, val, CS, cs, pc, ins, GetTickCount());
if (port_outb[port][0])
port_outb[port][0](port, val);
if (port_outb[port][1])
port_outb[port][1](port, val);
return;
switch (port)
{
case 0x220: case 0x221: case 0x222: case 0x223: /*Gameblaster*/
if (GAMEBLASTER) writecms(port,val);
return;
}
pclog("OUT %04X %02X %04X:%08X\n",port,val,CS,pc);
}
uint16_t inw(uint16_t port)
{
if (port_inw[port][0])
return port_inw[port][0](port);
if (port_inw[port][1])
return port_inw[port][1](port);
return inb(port) | (inb(port + 1) << 8);
}
void outw(uint16_t port, uint16_t val)
{
// printf("OUTW %04X %04X %04X:%08X\n",port,val, CS, pc);
if (port_outw[port][0])
port_outw[port][0](port, val);
if (port_outw[port][1])
port_outw[port][1](port, val);
if (port_outw[port][0] || port_outw[port][1])
return;
outb(port,val);
outb(port+1,val>>8);
}
uint32_t inl(uint16_t port)
{
if (port_inl[port][0])
return port_inl[port][0](port);
if (port_inl[port][1])
return port_inl[port][1](port);
return inw(port) | (inw(port + 2) << 16);
}
void outl(uint16_t port, uint32_t val)
{
if (port_outl[port][0])
port_outl[port][0](port, val);
if (port_outl[port][1])
port_outl[port][1](port, val);
if (port_outl[port][0] || port_outl[port][1])
return;
outw(port, val);
outw(port + 2, val >> 16);
}

17
src/io.h Normal file
View File

@@ -0,0 +1,17 @@
void io_init();
void io_sethandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val));
void io_removehandler(uint16_t base, int size,
uint8_t (*inb)(uint16_t addr),
uint16_t (*inw)(uint16_t addr),
uint32_t (*inl)(uint16_t addr),
void (*outb)(uint16_t addr, uint8_t val),
void (*outw)(uint16_t addr, uint16_t val),
void (*outl)(uint16_t addr, uint32_t val));

78
src/jim.c Normal file
View File

@@ -0,0 +1,78 @@
#include <stdio.h>
#include <string.h>
#include "ibm.h"
uint8_t europcdat[16];
struct
{
uint8_t dat[16];
int stat;
int addr;
} europc_rtc;
void writejim(uint16_t addr, uint8_t val)
{
if ((addr&0xFF0)==0x250) europcdat[addr&0xF]=val;
switch (addr)
{
case 0x25A:
// printf("Write RTC stat %i val %02X\n",europc_rtc.stat,val);
switch (europc_rtc.stat)
{
case 0:
europc_rtc.addr=val&0xF;
europc_rtc.stat++;
// printf("RTC addr now %02X - contents %02X\n",val&0xF,europc_rtc.dat[europc_rtc.addr]);
break;
case 1:
europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF)|(val<<4);
europc_rtc.stat++;
break;
case 2:
europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF0)|(val&0xF);
europc_rtc.stat=0;
break;
}
break;
}
// printf("Write JIM %04X %02X\n",addr,val);
}
uint8_t readjim(uint16_t addr)
{
// printf("Read JIM %04X\n",addr);
switch (addr)
{
case 0x250: case 0x251: case 0x252: case 0x253: return 0;
case 0x254: case 0x255: case 0x256: case 0x257: return europcdat[addr&0xF];
case 0x25A:
if (europc_rtc.stat==1)
{
europc_rtc.stat=2;
return europc_rtc.dat[europc_rtc.addr]>>4;
}
if (europc_rtc.stat==2)
{
europc_rtc.stat=0;
return europc_rtc.dat[europc_rtc.addr]&0xF;
}
return 0;
}
return 0;
}
void jim_init()
{
uint8_t viddat;
memset(europc_rtc.dat,0,16);
europc_rtc.dat[0xF]=1;
europc_rtc.dat[3]=1;
europc_rtc.dat[4]=1;
europc_rtc.dat[5]=0x88;
if (gfxcard==GFX_CGA) viddat=0x12;
else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) viddat=3;
else viddat=0x10;
europc_rtc.dat[0xB]=viddat;
europc_rtc.dat[0xD]=viddat; /*Checksum*/
io_sethandler(0x250, 0x10, readjim, NULL, NULL, writejim, NULL, NULL);
}

1
src/jim.h Normal file
View File

@@ -0,0 +1 @@
void jim_init();

280
src/keyboard.c Normal file
View File

@@ -0,0 +1,280 @@
#include "ibm.h"
#include "plat-keyboard.h"
#include "keyboard.h"
int keybsendcallback = 0;
typedef struct
{
int scancodes_make[8];
int scancodes_break[8];
} scancode;
static scancode scancode_set1[256] =
{
{ {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
{ {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
{ {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
{ {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
{ {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
{ {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
{ {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
{ {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
{ {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
{ {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
{ {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
{ {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
{ {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
{ {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
{ {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
{ {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
{ {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
{ {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
{ {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} },
{ {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} },
{ {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} },
{ {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} },
{ {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} },
{ {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} },
{ {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} },
{ {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} },
{ {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} },
{ {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} },
{ {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} },
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
{ {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x2a, -1}, {0xe0, 0x8a, -1} }, { {-1}, {-1} }, /*a8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
{ {-1}, {-1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xb6, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/
{ {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0x47, -1}, {0xe0, 0xc7, -1} }, /*c4*/
{ {0xe0, 0x48, -1}, {0xe0, 0xc8, -1} }, { {0xe0, 0x49, -1}, {0xe0, 0xc9, -1} }, { {-1}, {-1} }, { {0xe0, 0x4b, -1}, {0xe0, 0xcb, -1} }, /*c8*/
{ {-1}, {-1} }, { {0xe0, 0x4d, -1}, {0xe0, 0xcd, -1} }, { {-1}, {-1} }, { {0xe0, 0x4f, -1}, {0xe0, 0xcf, -1} }, /*cc*/
{ {0xe0, 0x50, -1}, {0xe0, 0xd0, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xd1, -1} }, { {0xe0, 0x52, -1}, {0xe0, 0xd2, -1} }, { {0xe0, 0x53, -1}, {0xe0, 0xd3, -1} }, /*d0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, -1}, {-1} } /*fc*/
};
/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/
static scancode scancode_xt[256] =
{
{ {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
{ {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
{ {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
{ {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
{ {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
{ {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
{ {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
{ {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
{ {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
{ {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
{ {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
{ {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
{ {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
{ {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
{ {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
{ {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
{ {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
{ {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0x8a, -1} }, { {-1}, {-1} }, /*a8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
{ {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/
{ {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*c8*/
{ {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/
};
/*Tandy keyboard has slightly different scancodes to XT*/
static scancode scancode_tandy[256] =
{
{ {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
{ {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
{ {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
{ {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
{ {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
{ {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
{ {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
{ {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
{ {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
{ {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
{ {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
{ {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
{ {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
{ {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
{ {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
{ {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
{ {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
{ {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
{ {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
{ {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} },
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
{ {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0x8a, -1} }, { {-1}, {-1} }, /*a8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
{ {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/
{ {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/
{ {0x29, -1}, {0xa9, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x2b, -1}, {0xab, -1} }, /*c8*/
{ {-1}, {-1} }, { {0x4e, -1}, {0xce, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/
{ {0x4a, -1}, {0xca, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
{ {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/
};
static int oldkey[256];
static int keydelay[256];
void (*keyboard_send)(uint8_t val);
void (*keyboard_poll)();
int keyboard_scan = 1;
void keyboard_process()
{
int c;
int d;
scancode *scancodes = (AT) ? scancode_set1 : scancode_xt;
if (!keyboard_scan) return;
if (TANDY) scancodes = scancode_tandy;
for (c = 0; c < 256; c++)
{
if (key[c]) keydelay[c]++;
else keydelay[c] = 0;
}
for (c = 0; c < 256; c++)
{
if (key[c] != oldkey[c])
{
oldkey[c] = key[c];
if ( key[c] && scancodes[c].scancodes_make[0] == -1)
continue;
if (!key[c] && scancodes[c].scancodes_break[0] == -1)
continue;
pclog("Key %02X start\n", c);
d = 0;
if (key[c])
{
while (scancodes[c].scancodes_make[d] != -1)
keyboard_send(scancodes[c].scancodes_make[d++]);
}
else
{
while (scancodes[c].scancodes_break[d] != -1)
keyboard_send(scancodes[c].scancodes_break[d++]);
}
}
}
for (c = 0; c < 256; c++)
{
if (keydelay[c] >= 30)
{
keydelay[c] -= 10;
if (scancode_set1[c].scancodes_make[0] == -1)
continue;
d = 0;
while (scancode_set1[c].scancodes_make[d] != -1)
keyboard_send(scancode_set1[c].scancodes_make[d++]);
}
}
}

3
src/keyboard.h Normal file
View File

@@ -0,0 +1,3 @@
extern void (*keyboard_send)(uint8_t val);
extern void (*keyboard_poll)();
extern int keyboard_scan;

168
src/keyboard_amstrad.c Normal file
View File

@@ -0,0 +1,168 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sound.h"
#include "keyboard.h"
#include "keyboard_amstrad.h"
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
struct
{
int wantirq;
uint8_t pa;
uint8_t pb;
} keyboard_amstrad;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
static uint8_t amstrad_systemstat_1, amstrad_systemstat_2;
void keyboard_amstrad_poll()
{
if (keyboard_amstrad.wantirq)
{
keyboard_amstrad.wantirq = 0;
picint(2);
pclog("keyboard_amstrad : take IRQ\n");
}
if (key_queue_start != key_queue_end)
{
keyboard_amstrad.pa = key_queue[key_queue_start];
pclog("Reading %02X from the key queue at %i\n", keyboard_amstrad.pa, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_amstrad.wantirq = 1;
}
}
void keyboard_amstrad_adddata(uint8_t val)
{
key_queue[key_queue_end] = val;
pclog("keyboard_amstrad : %02X added to key queue at %i\n", val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0xf;
return;
}
void keyboard_amstrad_write(uint16_t port, uint8_t val)
{
pclog("keyboard_amstrad : write %04X %02X %02X\n", port, val, keyboard_amstrad.pb);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x61:
pclog("keyboard_amstrad : pb write %02X %02X %i %02X %i\n", val, keyboard_amstrad.pb, !(keyboard_amstrad.pb & 0x40), keyboard_amstrad.pb & 0x40, (val & 0x40));
if (!(keyboard_amstrad.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/
{
pclog("keyboard_amstrad : reset keyboard\n");
keyboard_amstrad_adddata(0xaa);
}
keyboard_amstrad.pb = val;
ppi.pb = val;
/* if (AMSTRADIO)
keyboard_amstrad.s2 = val & 4;
else
keyboard_amstrad.s2 = val & 8;*/
gated = ((val & 3) == 3);
if (gated)
wasgated = 1;
if (val & 0x80)
keyboard_amstrad.pa = 0;
break;
case 0x63:
break;
case 0x64:
amstrad_systemstat_1 = val;
break;
case 0x65:
amstrad_systemstat_2 = val;
break;
default:
pclog("\nBad XT keyboard write %04X %02X\n", port, val);
// dumpregs();
// exit(-1);
}
}
uint8_t keyboard_amstrad_read(uint16_t port)
{
uint8_t temp;
// pclog("keyboard_amstrad : read %04X ", port);
switch (port)
{
case 0x60:
if (keyboard_amstrad.pb & 0x80)
{
temp = (amstrad_systemstat_1 | 0xd) & 0x7f;
}
else
{
temp = keyboard_amstrad.pa;
if (key_queue_start == key_queue_end)
{
keyboard_amstrad.wantirq = 0;
}
else
{
keyboard_amstrad.pa = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_amstrad.wantirq = 1;
}
}
break;
case 0x61:
temp = keyboard_amstrad.pb;
break;
case 0x62:
if (keyboard_amstrad.pb & 0x04)
temp = amstrad_systemstat_2 & 0xf;
else
temp = amstrad_systemstat_2 >> 4;
temp |= (ppispeakon ? 0x20 : 0);
break;
default:
pclog("\nBad XT keyboard read %04X\n", port);
// dumpregs();
// exit(-1);
}
// pclog("%02X %04X:%04X\n", temp, CS, pc);
return temp;
}
void keyboard_amstrad_reset()
{
keyboard_amstrad.wantirq = 0;
keyboard_scan = 1;
}
void keyboard_amstrad_init()
{
//return;
pclog("keyboard_amstrad_init\n");
io_sethandler(0x0060, 0x0006, keyboard_amstrad_read, NULL, NULL, keyboard_amstrad_write, NULL, NULL);
keyboard_amstrad_reset();
keyboard_send = keyboard_amstrad_adddata;
keyboard_poll = keyboard_amstrad_poll;
}

3
src/keyboard_amstrad.h Normal file
View File

@@ -0,0 +1,3 @@
void keyboard_amstrad_init();
void keyboard_amstrad_reset();
void keyboard_amstrad_poll();

436
src/keyboard_at.c Normal file
View File

@@ -0,0 +1,436 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sound.h"
#include "keyboard.h"
#include "keyboard_at.h"
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_MFULL 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
struct
{
int initialised;
int want60;
int wantirq, wantirq12;
uint8_t command;
uint8_t status;
uint8_t mem[0x20];
uint8_t out;
uint8_t input_port;
uint8_t output_port;
uint8_t key_command;
int key_wantdata;
} keyboard_at;
static uint8_t key_ctrl_queue[16];
static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
static uint8_t mouse_queue[16];
int mouse_queue_start = 0, mouse_queue_end = 0;
void keyboard_at_poll()
{
if (keyboard_at.wantirq)
{
keyboard_at.wantirq = 0;
picint(2);
pclog("keyboard_at : take IRQ\n");
}
else if (keyboard_at.wantirq12)
{
keyboard_at.wantirq12 = 0;
picint(0x1000);
pclog("keyboard_at : take IRQ 12\n");
}
if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) &&
mouse_queue_start != mouse_queue_end)
{
pclog("Reading %02X from the mouse queue at %i\n", keyboard_at.out, key_queue_start);
keyboard_at.out = mouse_queue[mouse_queue_start];
mouse_queue_start = (mouse_queue_start + 1) & 0xf;
keyboard_at.status |= STAT_OFULL | STAT_MFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x02)
keyboard_at.wantirq12 = 1;
}
else if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) &&
key_queue_start != key_queue_end)
{
pclog("Reading %02X from the key queue at %i\n", keyboard_at.out, key_queue_start);
keyboard_at.out = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_at.status |= STAT_OFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x01)
keyboard_at.wantirq = 1;
}
else if (!(keyboard_at.status & STAT_OFULL) &&
key_ctrl_queue_start != key_ctrl_queue_end)
{
pclog("Reading %02X from the key ctrl_queue at %i\n", keyboard_at.out, key_ctrl_queue_start);
keyboard_at.out = key_ctrl_queue[key_ctrl_queue_start];
key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf;
keyboard_at.status |= STAT_OFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x01)
keyboard_at.wantirq = 1;
}
}
void keyboard_at_adddata(uint8_t val)
{
// if (keyboard_at.status & STAT_OFULL)
// {
key_ctrl_queue[key_ctrl_queue_end] = val;
key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf;
pclog("keyboard_at : %02X added to queue\n", val);
/* return;
}
keyboard_at.out = val;
keyboard_at.status |= STAT_OFULL;
keyboard_at.status &= ~STAT_IFULL;
if (keyboard_at.mem[0] & 0x01)
keyboard_at.wantirq = 1;
pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/
}
void keyboard_at_adddata_keyboard(uint8_t val)
{
key_queue[key_queue_end] = val;
key_queue_end = (key_queue_end + 1) & 0xf;
pclog("keyboard_at : %02X added to key queue\n", val);
return;
}
void keyboard_at_adddata_mouse(uint8_t val)
{
mouse_queue[mouse_queue_end] = val;
mouse_queue_end = (mouse_queue_end + 1) & 0xf;
pclog("keyboard_at : %02X added to mouse queue\n", val);
return;
}
void keyboard_at_write(uint16_t port, uint8_t val)
{
pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x60:
if (keyboard_at.want60)
{
/*Write to controller*/
keyboard_at.want60 = 0;
switch (keyboard_at.command)
{
case 0x60: case 0x61: case 0x62: case 0x63:
case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6a: case 0x6b:
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b:
case 0x7c: case 0x7d: case 0x7e: case 0x7f:
keyboard_at.mem[keyboard_at.command & 0x1f] = val;
if (keyboard_at.command == 0x60)
{
if ((val & 1) && (keyboard_at.status & STAT_OFULL))
keyboard_at.wantirq = 1;
if (!(val & 1) && keyboard_at.wantirq)
keyboard_at.wantirq = 0;
}
break;
case 0xcb: /*AMI - set keyboard mode*/
break;
case 0xcf: /*??? - sent by MegaPC BIOS*/
break;
case 0xd1: /*Write output port*/
pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc);
if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/
{
mem_a20_key = val & 0x02;
mem_a20_recalc();
// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02);
flushmmucache();
}
keyboard_at.output_port = val;
break;
case 0xd3: /*Write to mouse output buffer*/
keyboard_at_adddata_mouse(val);
break;
case 0xd4: /*Write to mouse*/
if (mouse_write)
mouse_write(val);
break;
default:
pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command);
// dumpregs();
// exit(-1);
}
}
else
{
/*Write to keyboard*/
keyboard_at.mem[0] &= ~0x10;
if (keyboard_at.key_wantdata)
{
keyboard_at.key_wantdata = 0;
switch (keyboard_at.key_command)
{
case 0xed: /*Set/reset LEDs*/
keyboard_at_adddata_keyboard(0xfa);
break;
case 0xf3: /*Set typematic rate/delay*/
keyboard_at_adddata_keyboard(0xfa);
break;
default:
pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command);
// dumpregs();
// exit(-1);
}
}
else
{
keyboard_at.key_command = val;
switch (val)
{
case 0x05: /*??? - sent by NT 4.0*/
keyboard_at_adddata_keyboard(0xfe);
break;
case 0xed: /*Set/reset LEDs*/
keyboard_at.key_wantdata = 1;
keyboard_at_adddata_keyboard(0xfa);
break;
case 0xf2: /*Read ID*/
keyboard_at_adddata_keyboard(0xfa);
keyboard_at_adddata_keyboard(0xab);
keyboard_at_adddata_keyboard(0x41);
break;
case 0xf3: /*Set typematic rate/delay*/
keyboard_at.key_wantdata = 1;
keyboard_at_adddata_keyboard(0xfa);
break;
case 0xf4: /*Enable keyboard*/
keyboard_scan = 1;
break;
case 0xff: /*Reset*/
keyboard_at_adddata_keyboard(0xfa);
keyboard_at_adddata_keyboard(0xaa);
break;
default:
pclog("Bad AT keyboard command %02X\n", val);
keyboard_at_adddata_keyboard(0xfe);
// dumpregs();
// exit(-1);
}
}
}
break;
case 0x61:
ppi.pb=val;
gated=((val&3)==3);
if (gated) wasgated=1;
break;
case 0x64:
keyboard_at.want60 = 0;
keyboard_at.command = val;
/*New controller command*/
switch (val)
{
case 0x20: case 0x21: case 0x22: case 0x23:
case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2a: case 0x2b:
case 0x2c: case 0x2d: case 0x2e: case 0x2f:
case 0x30: case 0x31: case 0x32: case 0x33:
case 0x34: case 0x35: case 0x36: case 0x37:
case 0x38: case 0x39: case 0x3a: case 0x3b:
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
keyboard_at_adddata(keyboard_at.mem[val & 0x1f]);
break;
case 0x60: case 0x61: case 0x62: case 0x63:
case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6a: case 0x6b:
case 0x6c: case 0x6d: case 0x6e: case 0x6f:
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b:
case 0x7c: case 0x7d: case 0x7e: case 0x7f:
keyboard_at.want60 = 1;
break;
case 0xa1: /*AMI - get controlled version*/
break;
case 0xa7: /*Disable mouse port*/
break;
case 0xa9: /*Test mouse port*/
keyboard_at_adddata(0x00); /*no error*/
break;
case 0xaa: /*Self-test*/
if (!keyboard_at.initialised)
{
keyboard_at.initialised = 1;
key_ctrl_queue_start = key_ctrl_queue_end = 0;
keyboard_at.status &= ~STAT_OFULL;
}
keyboard_at.status |= STAT_SYSFLAG;
keyboard_at.mem[0] |= 0x04;
keyboard_at_adddata(0x55);
break;
case 0xab: /*Interface test*/
keyboard_at_adddata(0x00); /*no error*/
break;
case 0xad: /*Disable keyboard*/
keyboard_at.mem[0] |= 0x10;
break;
case 0xae: /*Enable keyboard*/
keyboard_at.mem[0] &= ~0x10;
break;
case 0xc0: /*Read input port*/
keyboard_at_adddata(keyboard_at.input_port);
keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc);
break;
case 0xc9: /*AMI - block P22 and P23 ??? */
break;
case 0xca: /*AMI - read keyboard mode*/
keyboard_at_adddata(0x00); /*ISA mode*/
break;
case 0xcb: /*AMI - set keyboard mode*/
keyboard_at.want60 = 1;
break;
case 0xcf: /*??? - sent by MegaPC BIOS*/
keyboard_at.want60 = 1;
break;
case 0xd0: /*Read output port*/
keyboard_at_adddata(keyboard_at.output_port);
break;
case 0xd1: /*Write output port*/
keyboard_at.want60 = 1;
break;
case 0xd3: /*Write mouse output buffer*/
keyboard_at.want60 = 1;
break;
case 0xd4: /*Write to mouse*/
keyboard_at.want60 = 1;
break;
case 0xe0: /*Read test inputs*/
keyboard_at_adddata(0x00);
break;
case 0xef: /*??? - sent by AMI486*/
break;
case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/
softresetx86(); /*Pulse reset!*/
break;
case 0xff: /*Pulse output port - but no pins selected - sent by MegaPC BIOS*/
break;
default:
pclog("Bad AT keyboard controller command %02X\n", val);
// dumpregs();
// exit(-1);
}
}
}
uint8_t keyboard_at_read(uint16_t port)
{
uint8_t temp = 0xff;
cycles -= 4;
// if (port != 0x61) pclog("keyboard_at : read %04X ", port);
switch (port)
{
case 0x60:
temp = keyboard_at.out;
keyboard_at.status &= ~(STAT_OFULL | STAT_MFULL);
keyboard_at.wantirq = keyboard_at.wantirq12 = 0;
break;
case 0x61:
if (ppispeakon) return (ppi.pb&~0xC0)|0x20;
return ppi.pb&~0xC0;
break;
case 0x64:
temp = keyboard_at.status;
keyboard_at.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT);
break;
}
// if (port != 0x61) pclog("%02X %08X\n", temp, rammask);
return temp;
}
void keyboard_at_reset()
{
keyboard_at.initialised = 0;
keyboard_at.status = STAT_LOCK | STAT_CD;
keyboard_at.mem[0] = 0x11;
keyboard_at.wantirq = 0;
keyboard_at.output_port = 0;
keyboard_at.input_port = 0xb0;
keyboard_at.key_wantdata = 0;
keyboard_scan = 1;
}
void keyboard_at_init()
{
//return;
io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL);
keyboard_at_reset();
keyboard_send = keyboard_at_adddata_keyboard;
keyboard_poll = keyboard_at_poll;
mouse_write = NULL;
}

6
src/keyboard_at.h Normal file
View File

@@ -0,0 +1,6 @@
void keyboard_at_init();
void keyboard_at_reset();
void keyboard_at_poll();
void (*mouse_write)(uint8_t val);
extern int mouse_queue_start, mouse_queue_end;

285
src/keyboard_olim24.c Normal file
View File

@@ -0,0 +1,285 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "mouse.h"
#include "keyboard.h"
#include "keyboard_olim24.h"
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
struct
{
int wantirq;
uint8_t command;
uint8_t status;
uint8_t out;
uint8_t output_port;
int param, param_total;
uint8_t params[16];
int mouse_mode;
} keyboard_olim24;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
static uint8_t mouse_scancodes[7];
void keyboard_olim24_poll()
{
//pclog("poll %i\n", keyboard_olim24.wantirq);
if (keyboard_olim24.wantirq)
{
keyboard_olim24.wantirq = 0;
picint(2);
pclog("keyboard_olim24 : take IRQ\n");
}
if (!(keyboard_olim24.status & STAT_OFULL) && key_queue_start != key_queue_end)
{
pclog("Reading %02X from the key queue at %i\n", keyboard_olim24.out, key_queue_start);
keyboard_olim24.out = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_olim24.status |= STAT_OFULL;
keyboard_olim24.status &= ~STAT_IFULL;
keyboard_olim24.wantirq = 1;
}
}
void keyboard_olim24_adddata(uint8_t val)
{
key_queue[key_queue_end] = val;
key_queue_end = (key_queue_end + 1) & 0xf;
pclog("keyboard_olim24 : %02X added to key queue %02X\n", val, keyboard_olim24.status);
return;
}
void keyboard_olim24_write(uint16_t port, uint8_t val)
{
pclog("keyboard_olim24 : write %04X %02X\n", port, val);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x60:
if (keyboard_olim24.param != keyboard_olim24.param_total)
{
keyboard_olim24.params[keyboard_olim24.param++] = val;
if (keyboard_olim24.param == keyboard_olim24.param_total)
{
switch (keyboard_olim24.command)
{
case 0x11:
keyboard_olim24.mouse_mode = 0;
mouse_scancodes[0] = keyboard_olim24.params[0];
mouse_scancodes[1] = keyboard_olim24.params[1];
mouse_scancodes[2] = keyboard_olim24.params[2];
mouse_scancodes[3] = keyboard_olim24.params[3];
mouse_scancodes[4] = keyboard_olim24.params[4];
mouse_scancodes[5] = keyboard_olim24.params[5];
mouse_scancodes[6] = keyboard_olim24.params[6];
break;
case 0x12:
keyboard_olim24.mouse_mode = 1;
mouse_scancodes[0] = keyboard_olim24.params[0];
mouse_scancodes[1] = keyboard_olim24.params[1];
mouse_scancodes[2] = keyboard_olim24.params[2];
break;
default:
pclog("Bad keyboard command complete %02X\n", keyboard_olim24.command);
// dumpregs();
// exit(-1);
}
}
}
else
{
keyboard_olim24.command = val;
switch (val)
{
case 0x01: /*Self-test*/
break;
case 0x05: /*Read ID*/
keyboard_olim24_adddata(0x00);
break;
case 0x11:
keyboard_olim24.param = 0;
keyboard_olim24.param_total = 9;
break;
case 0x12:
keyboard_olim24.param = 0;
keyboard_olim24.param_total = 4;
break;
default:
pclog("Bad keyboard command %02X\n", val);
// dumpregs();
// exit(-1);
}
}
break;
}
}
uint8_t keyboard_olim24_read(uint16_t port)
{
uint8_t temp;
// pclog("keyboard_olim24 : read %04X ", port);
switch (port)
{
case 0x60:
temp = keyboard_olim24.out;
if (key_queue_start == key_queue_end)
{
keyboard_olim24.status &= ~STAT_OFULL;
keyboard_olim24.wantirq = 0;
}
else
{
keyboard_olim24.out = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_olim24.status |= STAT_OFULL;
keyboard_olim24.status &= ~STAT_IFULL;
keyboard_olim24.wantirq = 1;
}
break;
case 0x64:
temp = keyboard_olim24.status;
keyboard_olim24.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT);
break;
default:
pclog("\nBad olim24 keyboard read %04X\n", port);
// dumpregs();
// exit(-1);
}
// pclog("%02X\n", temp);
return temp;
}
void keyboard_olim24_reset()
{
keyboard_olim24.status = STAT_LOCK | STAT_CD;
keyboard_olim24.wantirq = 0;
keyboard_scan = 1;
keyboard_olim24.param = keyboard_olim24.param_total = 0;
keyboard_olim24.mouse_mode = 0;
mouse_scancodes[0] = 0x1c;
mouse_scancodes[1] = 0x53;
mouse_scancodes[2] = 0x01;
mouse_scancodes[3] = 0x4b;
mouse_scancodes[4] = 0x4d;
mouse_scancodes[5] = 0x48;
mouse_scancodes[6] = 0x50;
}
static int mouse_x = 0, mouse_y = 0, mouse_b = 0;
void mouse_olim24_poll(int x, int y, int b)
{
mouse_x += x;
mouse_y += y;
pclog("mouse_poll - %i, %i %i, %i\n", x, y, mouse_x, mouse_y);
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
if ((b & 1) && !(mouse_b & 1))
keyboard_olim24_adddata(mouse_scancodes[0]);
if (!(b & 1) && (mouse_b & 1))
keyboard_olim24_adddata(mouse_scancodes[0] | 0x80);
mouse_b = (mouse_b & ~1) | (b & 1);
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
if ((b & 2) && !(mouse_b & 2))
keyboard_olim24_adddata(mouse_scancodes[2]);
if (!(b & 2) && (mouse_b & 2))
keyboard_olim24_adddata(mouse_scancodes[2] | 0x80);
mouse_b = (mouse_b & ~2) | (b & 2);
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
if ((b & 4) && !(mouse_b & 4))
keyboard_olim24_adddata(mouse_scancodes[1]);
if (!(b & 4) && (mouse_b & 4))
keyboard_olim24_adddata(mouse_scancodes[1] | 0x80);
mouse_b = (mouse_b & ~4) | (b & 4);
if (keyboard_olim24.mouse_mode)
{
if (((key_queue_end - key_queue_start) & 0xf) > 12) return;
if (!mouse_x && !mouse_y) return;
mouse_y = -mouse_y;
if (mouse_x < -127) mouse_x = -127;
if (mouse_x > 127) mouse_x = 127;
if (mouse_x < -127) mouse_x = 0x80 | ((-mouse_x) & 0x7f);
if (mouse_y < -127) mouse_y = -127;
if (mouse_y > 127) mouse_y = 127;
if (mouse_y < -127) mouse_y = 0x80 | ((-mouse_y) & 0x7f);
keyboard_olim24_adddata(0xfe);
keyboard_olim24_adddata(mouse_x);
keyboard_olim24_adddata(mouse_y);
mouse_x = mouse_y = 0;
}
else
{
while (mouse_x < -4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_x+=4;
keyboard_olim24_adddata(mouse_scancodes[3]);
}
while (mouse_x > 4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_x-=4;
keyboard_olim24_adddata(mouse_scancodes[4]);
}
while (mouse_y < -4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_y+=4;
keyboard_olim24_adddata(mouse_scancodes[5]);
}
while (mouse_y > 4)
{
if (((key_queue_end - key_queue_start) & 0xf) > 14) return;
mouse_y-=4;
keyboard_olim24_adddata(mouse_scancodes[6]);
}
}
}
void keyboard_olim24_init()
{
//return;
io_sethandler(0x0060, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL);
io_sethandler(0x0064, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL);
keyboard_olim24_reset();
keyboard_send = keyboard_olim24_adddata;
keyboard_poll = keyboard_olim24_poll;
mouse_poll = mouse_olim24_poll;
}

3
src/keyboard_olim24.h Normal file
View File

@@ -0,0 +1,3 @@
void keyboard_olim24_init();
void keyboard_olim24_reset();
void keyboard_olim24_poll();

163
src/keyboard_xt.c Normal file
View File

@@ -0,0 +1,163 @@
#include "ibm.h"
#include "io.h"
#include "mem.h"
#include "sound.h"
#include "keyboard.h"
#include "keyboard_xt.h"
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
struct
{
int wantirq;
uint8_t pa;
uint8_t pb;
} keyboard_xt;
static uint8_t key_queue[16];
static int key_queue_start = 0, key_queue_end = 0;
void keyboard_xt_poll()
{
if (keyboard_xt.wantirq)
{
keyboard_xt.wantirq = 0;
picint(2);
pclog("keyboard_xt : take IRQ\n");
}
if (key_queue_start != key_queue_end)
{
keyboard_xt.pa = key_queue[key_queue_start];
pclog("Reading %02X from the key queue at %i\n", keyboard_xt.pa, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_xt.wantirq = 1;
}
}
void keyboard_xt_adddata(uint8_t val)
{
key_queue[key_queue_end] = val;
pclog("keyboard_xt : %02X added to key queue at %i\n", val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0xf;
return;
}
void keyboard_xt_write(uint16_t port, uint8_t val)
{
pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb);
/* if (ram[8] == 0xc3)
{
output = 3;
}*/
switch (port)
{
case 0x61:
pclog("keyboard_xt : pb write %02X %02X %i %02X %i\n", val, keyboard_xt.pb, !(keyboard_xt.pb & 0x40), keyboard_xt.pb & 0x40, (val & 0x40));
if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/
{
pclog("keyboard_xt : reset keyboard\n");
keyboard_xt_adddata(0xaa);
}
keyboard_xt.pb = val;
ppi.pb = val;
/* if (AMSTRADIO)
keyboard_xt.s2 = val & 4;
else
keyboard_xt.s2 = val & 8;*/
gated = ((val & 3) == 3);
if (gated)
wasgated = 1;
if (val & 0x80)
{
keyboard_xt.pa = 0;
picintc(2);
}
break;
}
}
uint8_t keyboard_xt_read(uint16_t port)
{
uint8_t temp;
// pclog("keyboard_xt : read %04X ", port);
switch (port)
{
case 0x60:
if (keyboard_xt.pb & 0x80)
{
if (VGA)
temp = 0x4D;
else if (MDA)
temp = 0x7D;
else
temp = 0x6D;
}
else
{
temp = keyboard_xt.pa;
if (key_queue_start == key_queue_end)
{
keyboard_xt.wantirq = 0;
}
else
{
keyboard_xt.pa = key_queue[key_queue_start];
key_queue_start = (key_queue_start + 1) & 0xf;
keyboard_xt.wantirq = 1;
}
}
break;
case 0x61:
temp = keyboard_xt.pb;
break;
case 0x62:
if (keyboard_xt.pb & 0x08)
{
if (VGA)
temp = 4;
else if (MDA)
temp = 7;
else
temp = 6;
}
else
temp = 0xD;
temp |= (ppispeakon ? 0x20 : 0);
break;
default:
pclog("\nBad XT keyboard read %04X\n", port);
//dumpregs();
//exit(-1);
}
// pclog("%02X\n", temp);
return temp;
}
void keyboard_xt_reset()
{
keyboard_xt.wantirq = 0;
keyboard_scan = 1;
}
void keyboard_xt_init()
{
//return;
io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL);
keyboard_xt_reset();
keyboard_send = keyboard_xt_adddata;
keyboard_poll = keyboard_xt_poll;
}

3
src/keyboard_xt.h Normal file
View File

@@ -0,0 +1,3 @@
void keyboard_xt_init();
void keyboard_xt_reset();
void keyboard_xt_poll();

66
src/lpt.c Normal file
View File

@@ -0,0 +1,66 @@
#include "ibm.h"
#include "io.h"
#include "lpt.h"
static uint8_t lpt1_dat, lpt2_dat;
void lpt1_write(uint16_t port, uint8_t val)
{
switch (port & 3)
{
case 0:
writedac(val);
lpt1_dat = val;
break;
case 2:
writedacctrl(val);
break;
}
}
uint8_t lpt1_read(uint16_t port)
{
switch (port & 3)
{
case 0:
return lpt1_dat;
case 1:
return readdacfifo();
}
return 0xff;
}
void lpt2_write(uint16_t port, uint8_t val)
{
switch (port & 3)
{
case 0:
writedac(val);
lpt2_dat = val;
break;
case 2:
writedacctrl(val);
break;
}
}
uint8_t lpt2_read(uint16_t port)
{
switch (port & 3)
{
case 0:
return lpt2_dat;
case 1:
return readdacfifo();
}
return 0xff;
}
void lpt_init()
{
io_sethandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL);
io_sethandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL);
}
void lpt2_remove()
{
io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL);
}

2
src/lpt.h Normal file
View File

@@ -0,0 +1,2 @@
void lpt_init();
void lpt2_remove();

2613
src/mame/fmopl.c Normal file

File diff suppressed because it is too large Load Diff

126
src/mame/fmopl.h Normal file
View File

@@ -0,0 +1,126 @@
#pragma once
#ifndef __FMOPL_H__
#define __FMOPL_H__
#ifndef STUFF
#define STUFF
typedef int64_t attotime;
#define ATTOTIME_IN_HZ(x) (1000000000/(x))
#define attotime_mul(x,y) ((x)*(y))
#define attotime_to_double(x) ((double)(x)/1000000000.0)
#define attotime_zero 0
#define running_device void
#define INLINE static
//#define M_PI 3.142
#endif
/* --- select emulation chips --- */
#define BUILD_YM3812 (1)
#define BUILD_YM3526 (0)
#define BUILD_Y8950 (0)
/* select output bits size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
/* compiler dependence */
#ifndef __OSDCOMM_H__
#define __OSDCOMM_H__
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif /* __OSDCOMM_H__ */
typedef signed short OPLSAMPLE;
/*
#if (OPL_SAMPLE_BITS==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_SAMPLE_BITS==8)
typedef INT8 OPLSAMPLE;
#endif
*/
typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period);
typedef void (*OPL_IRQHANDLER)(void *param,int irq);
typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(void *param);
#if BUILD_YM3812
void *ym3812_init(running_device *device, UINT32 clock, UINT32 rate);
void ym3812_shutdown(void *chip);
void ym3812_reset_chip(void *chip);
int ym3812_write(void *chip, int a, int v);
unsigned char ym3812_read(void *chip, int a);
int ym3812_timer_over(void *chip, int c);
void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length);
void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
#endif /* BUILD_YM3812 */
#if BUILD_YM3526
/*
** Initialize YM3526 emulator(s).
**
** 'num' is the number of virtual YM3526's to allocate
** 'clock' is the chip clock in Hz
** 'rate' is sampling rate
*/
void *ym3526_init(running_device *device, UINT32 clock, UINT32 rate);
/* shutdown the YM3526 emulators*/
void ym3526_shutdown(void *chip);
void ym3526_reset_chip(void *chip);
int ym3526_write(void *chip, int a, int v);
unsigned char ym3526_read(void *chip, int a);
int ym3526_timer_over(void *chip, int c);
/*
** Generate samples for one of the YM3526's
**
** 'which' is the virtual YM3526 number
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length);
void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
#endif /* BUILD_YM3526 */
#if BUILD_Y8950
/* Y8950 port handlers */
void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param);
void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param);
void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size );
void * y8950_init(running_device *device, UINT32 clock, UINT32 rate);
void y8950_shutdown(void *chip);
void y8950_reset_chip(void *chip);
int y8950_write(void *chip, int a, int v);
unsigned char y8950_read (void *chip, int a);
int y8950_timer_over(void *chip, int c);
void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length);
void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param);
void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param);
void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param);
#endif /* BUILD_Y8950 */
#endif /* __FMOPL_H__ */

2730
src/mame/ymf262.c Normal file

File diff suppressed because it is too large Load Diff

62
src/mame/ymf262.h Normal file
View File

@@ -0,0 +1,62 @@
#pragma once
#ifndef __YMF262_H__
#define __YMF262_H__
#ifndef STUFF
#define STUFF
typedef int64_t attotime;
#define ATTOTIME_IN_HZ(x) (1000000000/(x))
#define attotime_mul(x,y) ((x)*(y))
#define attotime_to_double(x) ((double)(x)/1000000000.0)
#define attotime_zero 0
#define running_device void
#define INLINE static
//#define M_PI 3.142
#endif
/* select number of output bits: 8 or 16 */
#define OPL3_SAMPLE_BITS 16
/* compiler dependence */
#ifndef __OSDCOMM_H__
#define __OSDCOMM_H__
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
typedef signed short OPL3SAMPLE;
//typedef stream_sample_t OPL3SAMPLE;
/*
#if (OPL3_SAMPLE_BITS==16)
typedef INT16 OPL3SAMPLE;
#endif
#if (OPL3_SAMPLE_BITS==8)
typedef INT8 OPL3SAMPLE;
#endif
*/
typedef void (*OPL3_TIMERHANDLER)(void *param,int timer,attotime period);
typedef void (*OPL3_IRQHANDLER)(void *param,int irq);
typedef void (*OPL3_UPDATEHANDLER)(void *param,int min_interval_us);
void *ymf262_init(running_device *device, int clock, int rate);
void ymf262_shutdown(void *chip);
void ymf262_reset_chip(void *chip);
int ymf262_write(void *chip, int a, int v);
unsigned char ymf262_read(void *chip, int a);
int ymf262_timer_over(void *chip, int c);
void ymf262_update_one(void *chip, OPL3SAMPLE **buffers, int length);
void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER TimerHandler, void *param);
void ymf262_set_irq_handler(void *chip, OPL3_IRQHANDLER IRQHandler, void *param);
void ymf262_set_update_handler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, void *param);
#endif /* __YMF262_H__ */

37
src/mcr.c Normal file
View File

@@ -0,0 +1,37 @@
/*INTEL 82355 MCR emulation
This chip was used as part of many 386 chipsets
It controls memory addressing and shadowing*/
#include "ibm.h"
int nextreg6;
uint8_t mcr22;
int mcrlock,mcrfirst;
void resetmcr()
{
mcrlock=0;
mcrfirst=1;
shadowbios=0;
}
void writemcr(uint16_t addr, uint8_t val)
{
printf("Write MCR %04X %02X %04X:%04X\n",addr,val,CS,pc);
switch (addr)
{
case 0x22:
if (val==6 && mcr22==6) nextreg6=1;
else nextreg6=0;
// if ((val&1) && (mcr22&1)) shadowbios=1;
// if (!(val&1) && !(mcr22&1)) shadowbios=0;
// if (!mcrfirst) shadowbios=val&1;
// mcrfirst=0;
// dumpregs();
// exit(-1);
break;
case 0x23:
if (nextreg6) shadowbios=!val;
break;
}
mcr22=val;
}

1358
src/mem.c Normal file

File diff suppressed because it is too large Load Diff

40
src/mem.h Normal file
View File

@@ -0,0 +1,40 @@
extern uint8_t *ram,*rom,*vram,*vrom;
extern uint8_t romext[32768];
extern int readlnum,writelnum;
extern int memspeed[11];
extern int nopageerrors;
extern int cache;
extern int memwaitstate;
void mem_sethandler(uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr),
uint16_t (*read_w)(uint32_t addr),
uint32_t (*read_l)(uint32_t addr),
void (*write_b)(uint32_t addr, uint8_t val),
void (*write_w)(uint32_t addr, uint16_t val),
void (*write_l)(uint32_t addr, uint32_t val));
void mem_removehandler(uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr),
uint16_t (*read_w)(uint32_t addr),
uint32_t (*read_l)(uint32_t addr),
void (*write_b)(uint32_t addr, uint8_t val),
void (*write_w)(uint32_t addr, uint16_t val),
void (*write_l)(uint32_t addr, uint32_t val));
extern int mem_a20_alt;
extern int mem_a20_key;
void mem_a20_recalc();
uint8_t mem_read_ram(uint32_t addr);
uint16_t mem_read_ramw(uint32_t addr);
uint32_t mem_read_raml(uint32_t addr);
void mem_write_ram(uint32_t addr, uint8_t val);
void mem_write_ramw(uint32_t addr, uint16_t val);
void mem_write_raml(uint32_t addr, uint32_t val);
uint8_t mem_read_bios(uint32_t addr);
uint16_t mem_read_biosw(uint32_t addr);
uint32_t mem_read_biosl(uint32_t addr);
FILE *romfopen(char *fn, char *mode);

200
src/model.c Normal file
View File

@@ -0,0 +1,200 @@
#include "ibm.h"
#include "cpu.h"
#include "model.h"
#include "io.h"
#include "acer386sx.h"
#include "ali1429.h"
#include "amstrad.h"
#include "dma.h"
#include "fdc.h"
#include "headland.h"
#include "ide.h"
#include "jim.h"
#include "keyboard_xt.h"
#include "keyboard_at.h"
#include "keyboard_olim24.h"
#include "lpt.h"
#include "mouse_ps2.h"
#include "mouse_serial.h"
#include "neat.h"
#include "nvr.h"
#include "olivetti_m24.h"
#include "pci.h"
#include "pic.h"
#include "pit.h"
#include "psg.h"
#include "serial.h"
#include "um8881f.h"
#include "wd76c10.h"
#include "xtide.h"
void xt_init();
void tandy1k_init();
void ams_init();
void europc_init();
void olim24_init();
void at_init();
void at_neat_init();
void at_acer386sx_init();
void at_wd76c10_init();
void at_ali1429_init();
void at_headland_init();
void at_um8881f_init();
int model;
MODEL models[] =
{
{"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init},
{"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init},
{"Generic XT clone", ROM_GENXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init},
{"DTK XT clone", ROM_DTKXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init},
{"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, tandy1k_init},
{"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512,"", NULL, "", NULL}, 1, ams_init},
{"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, europc_init},
{"Olivetti M24", ROM_OLIM24, { "", cpus_8086, "", NULL, "", NULL}, 1, olim24_init},
{"Amstrad PC1640", ROM_PC1640, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"Amstrad PC2086", ROM_PC2086, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"Amstrad PC3086", ROM_PC3086, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init},
{"IBM AT", ROM_IBMAT, { "", cpus_ibmat, "", NULL, "", NULL}, 0, at_init},
{"Commodore PC 30 III", ROM_CMDPC30, { "", cpus_286, "", NULL, "", NULL}, 0, at_init},
{"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, at_neat_init},
{"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, at_init},
{"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, at_acer386sx_init},
{"Amstrad MegaPC", ROM_MEGAPC, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 1, at_wd76c10_init},
{"AMI 386 clone", ROM_AMI386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, at_headland_init},
{"AMI 486 clone", ROM_AMI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_ali1429_init},
{"AMI WinBIOS 486", ROM_WIN486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_ali1429_init},
{"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_um8881f_init},
{"", -1, {"", 0, "", 0, "", 0}, 0}
};
int model_getromset()
{
return models[model].id;
}
char *model_getname()
{
return models[model].name;
}
void common_init()
{
dma_init();
fdc_init();
lpt_init();
pic_init();
pit_init();
serial1_init(0x3f8);
serial2_init(0x2f8);
}
void xt_init()
{
common_init();
keyboard_xt_init();
mouse_serial_init();
xtide_init();
}
void tandy1k_init()
{
common_init();
keyboard_xt_init();
mouse_serial_init();
psg_init();
xtide_init();
}
void ams_init()
{
common_init();
amstrad_init();
keyboard_amstrad_init();
nvr_init();
xtide_init();
}
void europc_init()
{
common_init();
jim_init();
keyboard_xt_init();
mouse_serial_init();
xtide_init();
}
void olim24_init()
{
common_init();
keyboard_olim24_init();
nvr_init();
olivetti_m24_init();
xtide_init();
}
void at_init()
{
common_init();
dma16_init();
ide_init();
keyboard_at_init();
if (models[model].init == at_init)
mouse_serial_init();
nvr_init();
pic2_init();
}
void at_neat_init()
{
at_init();
mouse_serial_init();
neat_init();
}
void at_acer386sx_init()
{
at_init();
mouse_ps2_init();
acer386sx_init();
}
void at_wd76c10_init()
{
at_init();
mouse_ps2_init();
wd76c10_init();
}
void at_headland_init()
{
at_init();
headland_init();
mouse_serial_init();
}
void at_ali1429_init()
{
at_init();
ali1429_init();
mouse_serial_init();
}
void at_um8881f_init()
{
at_init();
mouse_serial_init();
pci_init();
um8881f_init();
}
void model_init()
{
pclog("Initting as %s\n", model_getname());
io_init();
models[model].init();
}

16
src/model.h Normal file
View File

@@ -0,0 +1,16 @@
typedef struct
{
char name[24];
int id;
struct
{
char name[8];
CPU *cpus;
} cpu[3];
int fixed_gfxcard;
void (*init)();
} MODEL;
extern MODEL models[];
extern int model;

4
src/mouse.c Normal file
View File

@@ -0,0 +1,4 @@
#include "ibm.h"
#include "mouse.h"
void (*mouse_poll)(int x, int y, int b);

5
src/mouse.h Normal file
View File

@@ -0,0 +1,5 @@
extern void (*mouse_poll)(int x, int y, int b);
extern int mousepos;
extern int mousedelay;

152
src/mouse_ps2.c Normal file
View File

@@ -0,0 +1,152 @@
#include "ibm.h"
#include "keyboard_at.h"
#include "mouse.h"
#include "mouse_ps2.h"
#include "plat-mouse.h"
enum
{
MOUSE_STREAM,
MOUSE_REMOTE,
MOUSE_ECHO
};
#define MOUSE_ENABLE 0x20
#define MOUSE_SCALE 0x10
static struct
{
int mode;
uint8_t flags;
uint8_t resolution;
uint8_t command;
int cd;
} mouse_ps2;
void mouse_ps2_write(uint8_t val)
{
if (mouse_ps2.cd)
{
mouse_ps2.cd = 0;
switch (mouse_ps2.command)
{
case 0xe8: /*Set mouse resolution*/
mouse_ps2.resolution = val;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf3: /*Set sample rate*/
keyboard_at_adddata_mouse(0xfa);
break;
// default:
// fatal("mouse_ps2 : Bad data write %02X for command %02X\n", val, mouse_ps2.command);
}
}
else
{
mouse_ps2.command = val;
switch (mouse_ps2.command)
{
case 0xe6: /*Set scaling to 1:1*/
mouse_ps2.flags &= ~MOUSE_SCALE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xe7: /*Set scaling to 2:1*/
mouse_ps2.flags |= MOUSE_SCALE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xe8: /*Set mouse resolution*/
mouse_ps2.cd = 1;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf2: /*Read ID*/
keyboard_at_adddata_mouse(0xfa);
keyboard_at_adddata_mouse(0x00);
break;
case 0xf3: /*Set sample rate*/
mouse_ps2.cd = 1;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf4: /*Enable*/
mouse_ps2.flags |= MOUSE_ENABLE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xf5: /*Disable*/
mouse_ps2.flags &= ~MOUSE_ENABLE;
keyboard_at_adddata_mouse(0xfa);
break;
case 0xff: /*Reset*/
mouse_ps2.mode = MOUSE_STREAM;
mouse_ps2.flags = 0;
keyboard_at_adddata_mouse(0xfa);
keyboard_at_adddata_mouse(0xaa);
keyboard_at_adddata_mouse(0x00);
break;
// default:
// fatal("mouse_ps2 : Bad command %02X\n", val, mouse_ps2.command);
}
}
}
static int ps2_x = 0, ps2_y = 0, ps2_b = 0;
void mouse_ps2_poll(int x, int y, int b)
{
uint8_t packet[3] = {0x08, 0, 0};
if (!x && !y && b == ps2_b) return;
ps2_x += x;
ps2_y -= y;
if (mouse_ps2.mode == MOUSE_STREAM && (mouse_ps2.flags & MOUSE_ENABLE) &&
((mouse_queue_end - mouse_queue_start) & 0xf) < 13)
{
ps2_b = b;
// pclog("Send packet : %i %i\n", ps2_x, ps2_y);
if (ps2_x > 255)
ps2_x = 255;
if (ps2_x < -256)
ps2_x = -256;
if (ps2_y > 255)
ps2_y = 255;
if (ps2_y < -256)
ps2_y = -256;
if (ps2_x < 0)
packet[0] |= 0x10;
if (ps2_y < 0)
packet[0] |= 0x20;
if (mouse_b & 1)
packet[0] |= 1;
if (mouse_b & 2)
packet[0] |= 2;
if (mouse_b & 4)
packet[0] |= 4;
packet[1] = ps2_x & 0xff;
packet[2] = ps2_y & 0xff;
ps2_x = ps2_y = 0;
keyboard_at_adddata_mouse(packet[0]);
keyboard_at_adddata_mouse(packet[1]);
keyboard_at_adddata_mouse(packet[2]);
}
}
void mouse_ps2_init()
{
mouse_poll = mouse_ps2_poll;
mouse_write = mouse_ps2_write;
mouse_ps2.cd = 0;
mouse_ps2.flags = 0;
mouse_ps2.mode = MOUSE_STREAM;
}

1
src/mouse_ps2.h Normal file
View File

@@ -0,0 +1 @@
void mouse_ps2_init();

66
src/mouse_serial.c Normal file
View File

@@ -0,0 +1,66 @@
#include "ibm.h"
#include "mouse.h"
#include "serial.h"
static int oldb=0;
void mouse_serial_poll(int x, int y, int b)
{
uint8_t mousedat[3];
if (!(serial.ier&1)) return;
if (!x && !y && b==oldb) return;
oldb=b;
if (x>127) x=127;
if (y>127) y=127;
if (x<-128) x=-128;
if (y<-128) y=-128;
/*Use Microsoft format*/
mousedat[0]=0x40;
mousedat[0]|=(((y>>6)&3)<<2);
mousedat[0]|=((x>>6)&3);
if (b&1) mousedat[0]|=0x20;
if (b&2) mousedat[0]|=0x10;
mousedat[1]=x&0x3F;
mousedat[2]=y&0x3F;
if (!(serial.mctrl&0x10))
{
serial_write_fifo(mousedat[0]);
serial_write_fifo(mousedat[1]);
serial_write_fifo(mousedat[2]);
}
}
void mouse_serial_rcr()
{
mousepos=-1;
mousedelay=1000;
}
void mousecallback()
{
if (mousepos == -1)
{
mousepos = 0;
serial_fifo_read = serial_fifo_write = 0;
serial.linestat &= ~1;
serial_write_fifo('M');
}
else if (serial_fifo_read != serial_fifo_write)
{
serial.iir=4;
serial.linestat|=1;
if (serial.mctrl&8) picint(0x10);
}
// printf("Mouse callback\n");
}
void mouse_serial_init()
{
mouse_poll = mouse_serial_poll;
serial_rcr = mouse_serial_rcr;
}

Some files were not shown because too many files have changed in this diff Show More