├── .cvsignore ├── .project ├── BUGS ├── CHANGES ├── COPYRIGHT ├── Makefile ├── README ├── README.dg ├── README.mlh ├── TODO ├── VERSION ├── autodetect.c ├── autodetect.h ├── bios.c ├── bios.h ├── config.c ├── cpu.c ├── cpu.h ├── curses.c ├── debugger.c ├── debugger.h ├── disasm.h ├── dot.pcemurc ├── ems.c ├── ems ├── Makefile.patch ├── bios.c.patch ├── bios.h.patch ├── ems.doc └── patch.script ├── fonts.dir ├── global.h ├── hardware.c ├── hardware.h ├── icon.h ├── instr.h ├── keytabs.h ├── log.dec ├── log.sun ├── main.c ├── mfs.c ├── mfs.h ├── mfs_link.h ├── mytypes.h ├── new.pcemurc ├── old.pcemurc ├── programs ├── Makefile ├── config.sys ├── dumpdisk.c ├── ekemm.asm ├── ekemm.sys ├── emufs.S ├── emufs.sys ├── lredir.c ├── lredir.readme └── vga50.com ├── report.ps ├── vga.bdf ├── vga.c ├── vga.h ├── vga.pcf ├── vgahard.c ├── vgahard.h ├── video.c ├── video.h ├── xstuff.c └── xstuff.h /.cvsignore: -------------------------------------------------------------------------------- 1 | autodetect 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | pcemu 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BUGS: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is a current list of bugs/misfeatures (not counting programs 4 | which wouldn't run because of unimplemented functions/features) 5 | 6 | 7 | 1. keyb reverses keystrokes when they are typed quickly. 8 | Not sure if this is my emulator at fault or keyb - investigating it... 9 | 10 | 2. mfs.c has bugs in it. I've fixed a couple of the more obvious 11 | ones, but it occasinally crashes a bit when running xtree. (the 12 | logged drive had to be disconnected and reconnnected again to cure 13 | the problem) 14 | 15 | 3. MSDOS 5 dosshell program refuses to switch tasks - claiming there 16 | is insufficient disk space. MSDOS 6 dosshell has no problem with this. 17 | Both MSDOS 5 and MSDOS 6 cause an invalid opcode to be executed when 18 | run on a monochrome screen. 19 | 20 | 21 | 4. MSDOS very occasionally hangs with 'stack overflow' if network 22 | load is heavy and lots of keys are pressed at once. 23 | 24 | Increasing the 'stacks=' line in the config.sys file can help this 25 | problem. 26 | 27 | 28 | This list is almost certainly not complete. 29 | 30 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 1.2.1 2 | There was a initilisation bug in the ems code that would crash it 3 | reliably on startup. The EMS code has some interesting edge 4 | conditions on the Total_EMS_Handles variables, so the emu may segfault 5 | when an application uses EMS. Thanks to Moritz Barsnick and Fred 6 | Weigel. 7 | 8 | FreeDOS beta 5 wont run as it uses the 386 specific FS register. Beta 9 | 4 works fine. 10 | 11 | Added an example set of flags for Solaris and changed on_exit to 12 | atexit (Moritz Barsnick). 13 | 14 | Updated the README to reflect the new .pcemurc 15 | 16 | 1.01 17 | 18 | Speeded up BIOS printing by buffering write requests which occured within a 19 | short space of time. Result is a dramatic increase in speed (particularly 20 | for slow X terminals) when doing directory listings etc. 21 | 22 | Added kludge to support vga 50 line mode. This will be redone when/if font 23 | changes are fully supported. For now, it uses the same font, but simply 24 | changes the window size to accomodate the larger screen area. Switching to 25 | 50 line mode can either be accomplished by loading ansi.sys in the 26 | config.sys file and then using 'mode con lines=50', or by using the program 27 | 'vga50.com' in the programs directory. You can type 'mode co80' to return 28 | to the normal 80x25 display... 29 | 30 | Added ability to change compile time options via the Makefile 31 | Added support for a .pcemurc file to read various parameters at run time 32 | 33 | Added dumpdisk.{exe,c} for people without access to a Unix floppy disk so they 34 | can create a disk image 35 | 36 | Improved support for Sun type 4 keyboards. Made Meta equivalent to Alt key 37 | 38 | Added support for Int 0x10 function 0x1b which many programs call. A lot of 39 | the information it returns it a bit dubious, but it means ansi.sys no 40 | longer minds switching into 50 line mode 41 | 42 | Made control-break clear the keyboard buffer 43 | 44 | Altered the directory stuff in mfs.c to try to make it more portable 45 | 46 | Fixed silly bug where caps lock was being treated as shift lock. 47 | 48 | 1.00 49 | 50 | Initial release 51 | 52 | 53 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | 2 | All files, documentation etc with the exception of 'mfs.c', 3 | 'emufs.sys', 'emufs.S', 'lredir.exe', 'lredir.c' and 'lredir.readme' 4 | are Copyright (C) 1994 University of Bristol, England 5 | 6 | Permission is granted to use, copy, modify, and distribute this 7 | software and its documentation for any non-commercial purpose, 8 | provided that the above copyright notice appear in all copies and that 9 | both that copyright notice and this permission notice appear in the 10 | supporting documentation. 11 | 12 | BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 13 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT 14 | WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER 15 | PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, 16 | EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 19 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 20 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 21 | 22 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 23 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 24 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 25 | DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 26 | DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 27 | (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 28 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 29 | THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER 30 | OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31 | 32 | --------------------------------------------------------------------- 33 | 34 | 'mfs.c', 'emufs.sys' and 'emufs.S' are covered by the following 35 | notice: 36 | 37 | Mach Operating System 38 | Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 39 | Copyright (c) 1991 IBM Corporation 40 | All Rights Reserved. 41 | 42 | Permission to use, copy, modify and distribute this software and its 43 | documentation is hereby granted, provided that both the copyright 44 | notice and this permission notice appear in all copies of the 45 | software, derivative works or modified versions, and any portions 46 | thereof, and that both notices appear in supporting documentation, 47 | and that the nema IBM not be used in advertising or publicity 48 | pertaining to distribution of the software without specific, written 49 | prior permission. 50 | 51 | CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" 52 | CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR 53 | ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 54 | 55 | Carnegie Mellon requests users of this software to return to 56 | 57 | Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 58 | School of Computer Science 59 | Carnegie Mellon University 60 | Pittsburgh PA 15213-3890 61 | 62 | any improvements or extensions that they make and grant Carnegie Mellon 63 | the rights to redistribute these changes. 64 | 65 | -------------------------------------------------------------------- 66 | 67 | 'lredir' was written by Tim Bird (Tim_R_Bird@Novell.COM) 68 | 69 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # # 3 | # Third Year Project # 4 | # # 5 | # An IBM PC Emulator # 6 | # For Unix and X Windows # 7 | # # 8 | # By David Hedley # 9 | # # 10 | # # 11 | # This program is Copyrighted. Consult the file COPYRIGHT for more details # 12 | # # 13 | ############################################################################# 14 | 15 | # Valid options are as follow: 16 | # -DINLINE_FUNCTIONS if your compiler support inline functions (most do) 17 | # -DDEBUG prints lots of debugging messages. 18 | # -DDEBUGGER compiles in the debugger 19 | # -DKBUK if you have a UK style 102 key keyboard 20 | # -DALIGNED_ACCESS if your computer requires words to be on even boundaries 21 | # -DBIGCASE If your compiler/computer can handle 256 case switches 22 | # 23 | # -D_HPUX_SOURCE If you are compiling on an HP 24 | # -DSOLARIS If you are using Solaris (only 2.3 has been tested) 25 | # -DSGI If you are using an SGI 26 | # -DRS6000 If you are using an RS6000 27 | # -DDISABLEX To disable the X output layer 28 | # -DDISABLECURSES To disable the curses output layer 29 | # 30 | # Note that when compiling on the RS6000 and SGI using the standard cc compiler 31 | # specifying -O2 to optimise the code results in the emulator crashing. I 32 | # believe this is due to compiler bugs (as the programs run OK without 33 | # optimisation). If anyone can shed light on what the problem is I would be 34 | # eternally grateful. 35 | # 36 | # Not specifying the following will mean the defaults are used. They can be 37 | # overridden in the .pcemurc file 38 | # 39 | # -DBOOT360 Boot from a 360k disk image file 40 | # -DBOOT720 Boot from a 720k disk image file 41 | # -DBOOT1_44 Boot from a 1.44Mb disk image file 42 | # -DBOOT1_2 Boot from a 1.2Mb disk image file 43 | # 44 | # -DBOOTFILE="xyz" Boot from disk image "xyz" (default "DriveA") 45 | # -DCURSORSPEED=n Set cursor flash speed to n frames per flash (default 30) 46 | # -DUPDATESPEED=n Set screen update speed to n frames per update (default 5) 47 | # 48 | # Including -fomit-frame-pointer should increase speed a little, but it has 49 | # been known to crash the emulator when running on certain machines (80x86 50 | # based PCs under Linux, and HPs running HPUX). 51 | 52 | # Linux settings 53 | CC = gcc 54 | OPTIONS = -DALIGNED_ACCESS -DBIGCASE -DINLINE_FUNCTIONS -DDISABLE_MFS 55 | XROOT = /usr/X11R6 56 | CFLAGS = -O2 -fomit-frame-pointer -fno-strength-reduce -Wall 57 | #CFLAGS = -ggdb 58 | 59 | # Solaris, thanks to Moritz Barnsnick 60 | #CC = gcc 61 | #OPTIONS = -DALIGNED_ACCESS -DBIGCASE -DSOLARIS -DINLINE_FUNCTIONS -DBOOT1_44 62 | #XROOT = /usr/openwin 63 | #CFLAGS = -O2 -Wall 64 | 65 | XLIBS = -lXext -lX11 66 | CURSESLIBS = -lncurses 67 | 68 | # Cross compiling to win32 settings 69 | #CC = i586-mingw32msvc-gcc 70 | #OPTIONS = -DALIGNED_ACCESS -DBIGCASE -DINLINE_FUNCTIONS -DDISABLE_MFS -DDISABLEX=1 71 | #XROOT = /usr/X11R6 72 | #CFLAGS = -O2 -fomit-frame-pointer -fno-strength-reduce -Wall 73 | #CFLAGS = -ggdb 74 | 75 | # You may need to add -N to the LFLAGS if you get sporadic segmentation 76 | # faults. So far I have only needed to do this when compiling under Linux 77 | # as Xlib seems to be mysteriously writing to its text segment 78 | 79 | LFLAGS = -g 80 | 81 | LIBRARIES = -L$(XROOT)/lib $(XLIBS) $(CURSESLIBS) 82 | 83 | XOFILES = xstuff.o 84 | CURSESOFILES = curses.o 85 | 86 | OFILES = main.o \ 87 | cpu.o \ 88 | bios.o \ 89 | vga.o \ 90 | vgahard.o \ 91 | debugger.o \ 92 | hardware.o \ 93 | mfs.o \ 94 | ems.o \ 95 | video.o \ 96 | config.o \ 97 | $(XOFILES) $(CURSESOFILES) 98 | 99 | PROGNAME = pcemu 100 | 101 | GLOBAL_DEP = global.h \ 102 | mytypes.h 103 | 104 | all: $(PROGNAME) 105 | 106 | cpu.o: $(GLOBAL_DEP) cpu.h instr.h debugger.h hardware.h 107 | ems.o: $(GLOBAL_DEP) cpu.h bios.h 108 | main.o: $(GLOBAL_DEP) bios.h hardware.h video.h 109 | bios.o: $(GLOBAL_DEP) bios.h cpu.h vga.h vgahard.h debugger.h hardware.h \ 110 | keytabs.h mfs_link.h 111 | vga.o: $(GLOBAL_DEP) bios.h cpu.h vga.h vgahard.h hardware.h 112 | vgahard.o: $(GLOBAL_DEP) vgahard.h video.h hardware.h 113 | debugger.o: $(GLOBAL_DEP) cpu.h debugger.h disasm.h vgahard.h 114 | xstuff.o: $(GLOBAL_DEP) vgahard.h video.h icon.h hardware.h 115 | hardware.o: $(GLOBAL_DEP) cpu.h vgahard.h debugger.h hardware.h 116 | mfs.o: $(GLOBAL_DEP) cpu.h mfs.h mfs_link.h 117 | mytypes.h: autodetect.h 118 | 119 | autodetect.h: autodetect 120 | ./autodetect > autodetect.h 121 | 122 | .c.o: 123 | $(CC) $(CFLAGS) $(OPTIONS) -c $< 124 | 125 | $(PROGNAME): $(OFILES) 126 | $(CC) $(CFLAGS) -o $(PROGNAME) $(OFILES) $(LFLAGS) $(LIBRARIES) 127 | 128 | clean: 129 | rm -f $(PROGNAME) autodetect *.o *~ 130 | 131 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | PC Emulator for Unix and X Windows 3 | 4 | As the title suggests, this is a Unix/X windows program which is 5 | designed to emulate a standard 8086 based PC. 6 | 7 | In its current form it runs most text based programs. The programs I have 8 | tried and found to work are as follows: 9 | 10 | MSDOS 5.0 MSDOS 6.2 11 | WordPerfect 5.1 Borland C++ 2.0 12 | Turbo Debugger 2.51 Turbo Assembler 2.51 13 | BBCBasic 4.61 MSDOS QBasic 14 | MSDOS GWBASIC Virtually all program that came with MSDOS 5 15 | Hitchhiker's Guide to the Galaxy PC Magazine's ANSI.COM 16 | SemWare's QEdit 2.1 Norton Utils 4.50 Advanced Edition 17 | Norton Utils 6.0 Xtree Professional 1.1 18 | PowerMeter Utils Autoroute (ancient version) 19 | Minitab 8.0 Microsoft Diagnostics 20 | 21 | FreeDOS beta 4 (http://www.freedos.org/) works fine. Beta 5 seems to 22 | use the 386 instruction set and hence wont load. 23 | 24 | This is all the programs I could lay my hands on which were text based 25 | and could run on an 8086 26 | 27 | The emulator runs at about 8-10MHz 80286 speed on a Sun SparcStation 28 | 10/40 (without the -mviking flag) and at about 6MHz 8088 speed on a 29 | 33MHz 80486 box running Linux. 30 | 31 | I have included a Postscript representation of my project report. It's 32 | a bit out of date now, but it's the closest thing I've got to 33 | documentation! I'll do some kind of latex thing for the next 34 | release.... 35 | 36 | The program rather hogs the cpu but unmapping the window (iconifying 37 | it) will put it to sleep. 38 | 39 | The most recent version of this program will always be in ftp.cs.bris.ac.uk 40 | currently in the directory /users/hedley 41 | 42 | INSTALLING THE EMULATOR 43 | 44 | Edit the Makefile to change the OPTIONS, CFLAGS and XROOT to be 45 | appropriate for your system (I am assuming you are using GNU GCC, 46 | although any ANSI C compiler should work just as well). Ensure you are 47 | using the best (speed) optimisations possible (e.g. -O2 -fomit-frame-poiner) 48 | 49 | Edit the file mytypes.h and ensure that the types for INT8, UINT8, 50 | INT16, UINT16 etc are correct. Hopefully nothing need be changed in 51 | this file, but you never can tell... I have assumed that 'char's are 8 52 | bit bytes, 'short's are 16 bit words and 'long's are 32 bit words. If 53 | your compiler treats these differently to the above then you will have 54 | to edit this header file. 55 | 56 | Type 'make' and go away and have a cup of tea! Compiling 'cpu.c' takes 57 | a while (and quite a bit of memory!). 58 | 59 | Get a floppy disk of the same size/type as you specified in the Makefile 60 | (i.e. if you chose -DBOOT720, then you'll need a 3.5" 720k disk). Install 61 | MSDOS on it. Copy the files 'config.sys', 'emufs.sys' and 'lredir.exe' from 62 | the 'programs' directory onto this floppy disk. Shove it in your Unix box 63 | and type cp /dev/fd0 DriveA This should create a 720k (or whatever) file 64 | which the emulator can boot from. If you do not have access to a Unix box 65 | with a floppy disk on it, then you can use the supplied 'dumpdisk' program 66 | to create a disk image. All you need is access to a PC. Simply put in a 67 | bootable MSDOS disk into the drive and type dumpdisk A (or dumpdisk B if in 68 | drive B). The program will copy the entire disk to a file called 69 | 'drivea'. You must then transfer it to your Unix box... 70 | 71 | You then need to convert the vga font (vga.bdf) into a font format 72 | your X server can understand (either SNF or PCF) using either 73 | 'bdftosnf' or 'bdftopcf' and install the resulting font file somewhere 74 | where your X server can find it. Then type 'mkfontdir' to rebuild the 75 | fonts.dir file and then type 'xset fp rehash' to tell your X server 76 | about the new font. If you type 'xlsfonts' you should see 'vga' as one 77 | of the fonts listed. If not, then something has gone wrong. I may or 78 | may not be able to help - it depends on your local setup. The emulator 79 | will run without the font as it uses the standard 8x16 X11 font - 80 | although most programs which use the extended character set will look 81 | pretty terrible. A warning will be displayed if the correct VGA font 82 | cannot be found. If you are using openwindows, you will have to type 83 | 'convertfont' and then 'bldfamily' 84 | 85 | You should now be in a position to run the emulator 86 | 87 | By default, the emulator requires the disk image called 'DriveA' to be in 88 | the current directory or else it will complain. If you don't like this, 89 | then you can change the file the emulator boots from by altering your 90 | .pcemurc file (see below) or by changing the default at compile time (by 91 | modifying the Makefile) 92 | 93 | Once run, the emulator should come up with the usual MSDOS banner and 94 | request the current date and time (which should already be 95 | correct). You can now run PC programs, mount Unix directories as 96 | drives etc. You will already have one drive redirection - drive C: is 97 | the Unix root directory. To mount further directories as drives, you 98 | must use the program 'lredir'. Consult the file 'lredir.readme' for 99 | instructions... 100 | 101 | The .pcemurc file 102 | 103 | At present this file allows a few things to be changed at run time. If this 104 | file is found (either in the current directory or in your home directory), 105 | then it is read and parsed and the values overwriting the equivalent 106 | compile time options. 107 | 108 | floppy 109 | 110 | where 111 | is 0 or 1 (A: or B:). 112 | is the disk image to use. 113 | , , specifies the geometry of the drive. 114 | 115 | For example, to load the FreeDOS beta4 mini boot image 116 | floppy 0 mini.bin 18 80 2 117 | 118 | harddrive 119 | 120 | where all the fields are as above for floppy. 121 | 122 | video 123 | 124 | where 125 | is currently one of curses or X. 126 | 127 | curses uses the curses library to run directly on the console. X pops 128 | up a seperate X window. 129 | 130 | updatespeed n 131 | 132 | where n is an integer > 0 133 | This is the rate at which the screen memory gets checked for changes (and 134 | hence the update speed at which the screen gets updated for non-BIOS 135 | writes). n is measured in internal interrupt ticks of which there are ~72.8 136 | per second (depends on the resolution of the system timer). 137 | 138 | cursorspeed n 139 | 140 | where n is an integer 141 | This specifies how fast the cursor should flash. Flashing the cursor can 142 | take a fair amount of bandwidth and so on slow/heavily loaded networks it 143 | may be best to slow down the cursor flashing. Setting n to 0 or less will 144 | disable cursor flashing - the cursor will be permanently on. 145 | 146 | An example .pcemurc file can be found in this directory in new.pcemurc. 147 | 148 | If you have problems compiling or running the emulator, then please contact 149 | me giving details of what went wrong (along with your computer type 150 | etc). 151 | 152 | Architectures tested: 153 | 154 | Computer OS Comments 155 | ----------------------------------------------------------------------------- 156 | PC 486/33 Linux 0.99.14w Runs quite well. A bit pointless though :) 157 | Sun 3/60 SunOS 4.1.x Takes an age to compile and not really worth 158 | the effort... 159 | SparcStation 10 SunOS 4.1.3 Runs well. Takes > 20MB RAM to compile though 160 | HP 755/99 HPUX Runs OK (>25MB RAM to compile...) 161 | Sun 4 Solaris 2.3 Runs OK 162 | RS6000 ??? Had a few problems getting it to compile. 163 | Getting there slowly though. 164 | SGI Indigo IRIX 4.?.? Doesn't work if compiled with optimisation 165 | using the standard compiler. Haven't tried 166 | it using gcc yet... 167 | 168 | As you can see this list is quite small. The main limiting factor is the range 169 | of machines I have access to. If anyone else can get it running on other 170 | architectures then please contact me! 171 | 172 | Warning: This program is not secure! Do not make is suid or sgid anything 173 | unless you wish to compromise the security of your system! 174 | 175 | EMULATOR LIMITATIONS etc 176 | 177 | Some parts of the PC architecture are emulated better than others. The 178 | BIOS has been partly implemented - enough to get MSDOS to boot and to 179 | allow most programs to run. Anyhow, most decent programs bypass the 180 | BIOS for screen access. BIOS Disk calls for drive A have been mostly 181 | emulated, although formatting doesn't work. 182 | 183 | Some of the hardware has been emulated but not much. Timer interrupts 184 | are generated by the system but there is now way (at present) to 185 | reprogram the timer. The Programmable Interrupt Controller has been 186 | emulated in part to respond to the End Of Interrupt command and reads 187 | from and writes to the mask register should work OK. 188 | 189 | None of the VGA hardware has been emulated at present (apart from 190 | screen updating) although this will change in the near future. Mode 191 | changes must therefore be done through the BIOS. 192 | 193 | The keyboard has been mostly emulated. The program converts X11 194 | keysyms to raw PC scan codes and then generates an interrupt 9 as per 195 | usual. There is a BIOS routine which takes these scan codes and 196 | generates the correct BIOS ASCII/scan code pair. The keysyms used can 197 | be found in the module 'xstuff.c'. In the future these keysyms will be 198 | read in from a file at run time. 199 | 200 | THANKS 201 | 202 | Thanks go to the following: 203 | 204 | Andy Norman at HPLabs, Bristol (ange@hpl.hewlett-packard.co.uk) for the HP 205 | port. 206 | Dieter Becker (becker@med-in.uni-sb.de) for help with the Solaris port 207 | Klaas Esselink (esselin1@ksla.nl) for help with the RS6000 port 208 | 209 | Please report bugs/comments etc to me (hedley@cs.bris.ac.uk) and I'll 210 | do my best to sort them out (no guarantees though). After June 25th I 211 | will be leaving University and will not be able to check email very 212 | frequently - please be patient if you want a response - I will reply 213 | eventually. 214 | 215 | Have fun... 216 | 217 | David 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /README.dg: -------------------------------------------------------------------------------- 1 | This document contains minimal information about the changes I've made to 2 | David Hedley's PC Emulator. I found David Hedley's PC Emulator several 3 | years ago, and spent some time working on it. Unfortunately this was ages 4 | ago and I can barely remember what I did! 5 | 6 | The improvements I *can* remember: 7 | 8 | * A pop-up menu allowing disc mounting and dismounting. 9 | * Better floppy disc support (inc. the above). 10 | * More secure. No longer stores host function pointers in the 11 | target's memory space (!). 12 | * Various smoothings-out all over. 13 | * Other stuff I can't remember. 14 | 15 | There is hardly any documentation other than David Hedley's original 16 | documentation. This is from memory: 17 | 18 | The AUTOEJECT compile-time definition is of a command to execute when 19 | dismounting discs (I originally used a Sun with autoeject disc drives). 20 | 21 | Press any mouse button in the pcemu window to pop up the menu. 22 | 23 | Don't look in mfs.c, it's not pretty (it also doesn't work on the DEC 24 | Alpha). 25 | 26 | Most of my changes are commented. Some are not. One of these days I should 27 | get round to doing a proper diff against David Hedley's original source. 28 | If you really want to know, you can download the original version from my 29 | web site. 30 | 31 | I recently discovered that the EMS driver module was written by someone 32 | else. Perhaps if we get our act together a proper COPYRIGHT and AUTHORS 33 | file could be written. 34 | 35 | Um, I think that's the lot... as you might of guessed, this file was 36 | hacked up quickly while waiting for something to compile. I don't even 37 | know if it works properly. Have fun, and let me know what happens! 38 | 39 | David Given 40 | http://wiredsoc.ml.org/~dg 41 | dg@tao.co.uk 42 | 43 | 44 | -------------------------------------------------------------------------------- /README.mlh: -------------------------------------------------------------------------------- 1 | In following with tradition, this document covers the changes since 2 | David Given's release. 3 | 4 | The video output layer was split, and a ncurses layer was added. You 5 | can now run directly on a terminal by adding the 6 | 7 | video curses 8 | 9 | line to your pcemurc. X is the default. 10 | 11 | A few of the missing 186 instructions were added so that FreeDOS could 12 | boot. Some were hooked in but not implemented (especially the mul 13 | instructions). 14 | 15 | The code was updated to compile cleanly against glibc 2.2.1. It has 16 | been tested under Debian 2.2-powerpc. 17 | 18 | Michael Hope 19 | michaelh@juju.net.nz 20 | 21 Jan 2001 21 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Follows is the older list of things to do. 2 | 3 | Current list of things to do. 4 | 5 | Most of the below should be implemented in the next version due out in 6 | August/September. 7 | 8 | 9 | 1. Recode CPU module. 10 | Speed it up! 11 | Reduce/eliminate penalty for big endian machines. 12 | Possibly including lazy flag evaluation, although initial 13 | indications are that it is actually slower than 14 | calculating the flags after each instruction. 15 | 16 | 2. Finish BIOS 17 | Exactly how much of the BIOS remains to do is open to question 18 | - it seems a little pointless wasting time writing code 19 | for BIOS functions that no program ever uses The VGA BIOS will be 20 | extended/rewritten to allow for graphics modes when they 21 | are implemented. 22 | 23 | 3. Printer support 24 | Dunno quite what to do about this - could dump all printer 25 | output to a file I suppose. 26 | 27 | 4. VGA support 28 | Initially the CGA 640x200x2 320x200x4 and MCGA 320x200x256, 29 | but eventually all VGA modes should be supported (albeit slowly :) 30 | Support for different character sets... 31 | Chip level access should eventually be possible (kind of vital 32 | for the graphics modes). Dunno about some of the more 33 | esoteric CRTC options though.... 34 | 35 | 5. Rewrite mfs.c 36 | mfs.c needs a complete rewrite/redesign as it has bugs in it 37 | and generates loads of warnings when compiling with the 38 | -Wall flag... 39 | 40 | 6. Chip level emulations... 41 | The timer chip should be properly emulated so that accuracy is 42 | not lost (irrespect of the resolution of the Unix system timer) 43 | 44 | 7. Sound support 45 | Should be possible to get the PC sound emulated OK (dunno 46 | about the sound cards though) 47 | 48 | 8. Idle time detector 49 | The emulator should try to detect when programs running under 50 | it are idle and consequently reduce the system load by 51 | going to sleep for a bit 52 | 53 | 9. Improved user interface 54 | Configuration files for boot drive, keyboard mappings etc 55 | Rewrite the X window module to allow for cutting/pasting etc 56 | Use Imake 57 | 58 | 59 | This list is not complete! - anything in particular you would like to 60 | see, then please mail me 61 | 62 | David 63 | 64 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.1.dg 2 | 3 | This is based on David Hedley's 1.01 release. 4 | 5 | --dg 6 | 7 | -------------------------------------------------------------------------------- /autodetect.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wordsize.c 3 | * 4 | * Produces a #include file that defines INT16, INT32 etc in a (hopefully) 5 | * portable manner. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | struct { 12 | char *name; 13 | int size; 14 | } typearray[] = { 15 | {"char", sizeof(char)}, 16 | {"short int", sizeof(short int)}, 17 | {"int", sizeof(int)}, 18 | {"long int", sizeof(long int)}, 19 | {NULL, 0}, 20 | }; 21 | 22 | void dotype(int size) 23 | { 24 | int i = 0; 25 | 26 | while (typearray[i].name) 27 | { 28 | if ((typearray[i].size * 8) == size) 29 | { 30 | printf("typedef signed %s INT%d;\n", typearray[i].name, size); 31 | printf("typedef unsigned %s UINT%d;\n", typearray[i].name, size); 32 | return; 33 | } 34 | i++; 35 | } 36 | 37 | fprintf(stderr, "Could find a type of length %d\n", size); 38 | exit(1); 39 | } 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | union { 44 | char c[4]; 45 | int i; 46 | } endian; 47 | 48 | printf("/* Automatically created file --- do not edit */\n\n"); 49 | 50 | dotype(8); 51 | dotype(16); 52 | dotype(32); 53 | 54 | endian.i = 0; 55 | endian.c[0] = 1; 56 | if (endian.i == 1) 57 | printf("#define PCEMU_LITTLE_ENDIAN\n"); 58 | else 59 | printf("#define PCEMU_BIG_ENDIAN\n"); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /autodetect.h: -------------------------------------------------------------------------------- 1 | /* Automatically created file --- do not edit */ 2 | 3 | typedef signed char INT8; 4 | typedef unsigned char UINT8; 5 | typedef signed short int INT16; 6 | typedef unsigned short int UINT16; 7 | typedef signed int INT32; 8 | typedef unsigned int UINT32; 9 | #define PCEMU_BIG_ENDIAN 10 | -------------------------------------------------------------------------------- /bios.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is BIOS.H It contains definitions for the BIOS functions */ 16 | 17 | 18 | #ifndef BIOS_H 19 | #define BIOS_H 20 | 21 | #include "mytypes.h" 22 | 23 | #define BOOT 24 | 25 | void (*bios_routine[256])(void); 26 | 27 | void init_bios(void); 28 | void init_timer(void); 29 | void bios_off(void); 30 | void set_int(unsigned, BYTE *, unsigned, void (*routine)(void), BYTE *, unsigned); 31 | 32 | void int_ems(void); 33 | void EMS_Setup(void); 34 | 35 | void disable(void); 36 | void enable(void); 37 | 38 | void put_scancode(BYTE *code, int count); 39 | 40 | BYTE read_port60(void); 41 | 42 | void loc(void); 43 | 44 | char *set_boot_file(char *); 45 | char *set_boot_type(int); 46 | 47 | #define MAXHDISKS 2 48 | #define MAXFDISKS 2 49 | 50 | typedef struct 51 | { 52 | char *name; 53 | unsigned sectors; 54 | unsigned cylinders; 55 | unsigned heads; 56 | int fd; 57 | char removable; 58 | char mounted; 59 | } DiskTab; 60 | 61 | extern DiskTab fdisk[MAXFDISKS]; 62 | extern DiskTab fdisk[MAXFDISKS]; 63 | 64 | extern char *set_num_fdrives(int); 65 | extern char *set_num_hdrives(int); 66 | char *set_floppy_drive(int drive, char *device, int sectors, int cylinders, int heads); 67 | char *set_hard_drive(int drive, char *device, int sectors, int cylinders, int heads); 68 | void open_drive(DiskTab [], int drive); 69 | char *set_boot_drive(int); 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /config.c: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "bios.h" 3 | #include "vgahard.h" 4 | #include "video.h" 5 | #include 6 | 7 | void check_error(const char *msg, int line) 8 | { 9 | if (msg) 10 | fprintf(stderr,"%s, line %d\n", msg, line); 11 | } 12 | 13 | void read_pcemurc(void) 14 | { /* This procedure is a bit of a hack :) - will be redone later */ 15 | FILE *f1; 16 | char buffer[1024]; /* Maximum path length. Should really be a #define */ 17 | char keyword[1024]; 18 | char value[1024]; 19 | int line = 0; 20 | int i; 21 | 22 | /* Try current directory first... */ 23 | 24 | if ((f1 = fopen(".pcemurc","r")) == NULL) 25 | { /* Try home directory */ 26 | sprintf(buffer,"%s/.pcemurc", getenv("HOME")); 27 | if ((f1 = fopen(buffer,"r")) == NULL) 28 | { 29 | printf("Warning: .pcemurc not found - using compile time defaults\n"); 30 | return; 31 | } 32 | } 33 | 34 | /* This bit hacked by David Given to, er, improve... */ 35 | 36 | while (fgets(buffer,sizeof buffer,f1) != NULL) 37 | { 38 | line++; 39 | i = 0; /* Strip leading spaces */ 40 | while(buffer[i] == ' ') 41 | i++; 42 | strcpy(keyword, buffer+i); 43 | 44 | while(buffer[i] != ' ') /* Skip to end of keyword */ 45 | i++; 46 | while(buffer[i] == ' ') 47 | i++; 48 | strcpy(value, buffer+i); /* Write value */ 49 | 50 | i = 0; /* Trim keyword to one word */ 51 | while(keyword[i] != ' ') 52 | i++; 53 | keyword[i] = '\0'; 54 | 55 | i = 0; /* Strip out \n */ 56 | while(value[i] != '\0') 57 | { 58 | if (value[i] == '\n') 59 | value[i] = '\0'; 60 | i++; 61 | } 62 | 63 | if ((keyword[0] == '#') || (keyword[0] == ' ') || (keyword[0] == '\n')) 64 | continue; 65 | 66 | if (strcasecmp(keyword, "floppy") == 0) 67 | { 68 | int drive; 69 | char device[1024]; 70 | int sectors; 71 | int cylinders; 72 | int heads; 73 | 74 | if (sscanf(value, "%d %s %d %d %d", &drive, device, §ors, &cylinders, &heads) == 5) 75 | check_error(set_floppy_drive(drive, device, sectors, cylinders, heads), line); 76 | else 77 | check_error("Syntax error in \"floppy\" directive", line); 78 | } 79 | else if (strcasecmp(keyword, "harddrive") == 0) 80 | { 81 | int drive; 82 | char device[1024]; 83 | int sectors; 84 | int cylinders; 85 | int heads; 86 | 87 | if (sscanf(value, "%d %s %d %d %d", &drive, device, §ors, &cylinders, &heads) == 5) 88 | check_error(set_hard_drive(drive, device, sectors, cylinders, heads), line); 89 | else 90 | check_error("Syntax error in \"hard\" directive", line); 91 | } 92 | else if (strcasecmp(keyword, "numharddrives") == 0) 93 | check_error(set_num_hdrives(strtol(value, NULL, 10)), line); 94 | else if (strcasecmp(keyword, "numfloppydrives") == 0) 95 | check_error(set_num_fdrives(strtol(value, NULL, 10)), line); 96 | else if (strcasecmp(keyword,"updatespeed") == 0) 97 | check_error(set_update_rate(strtol(value, NULL,10)), line); 98 | else if (strcasecmp(keyword,"cursorspeed") == 0) 99 | check_error(set_cursor_rate(strtol(value, NULL,10)), line); 100 | /* else if (strcasecmp(keyword,"keymap") == 0) 101 | check_error(set_keymap(buffer), line);*/ 102 | else if (strcasecmp(keyword, "video") == 0) 103 | check_error(set_video_mode(value), line); 104 | else 105 | check_error("Syntax error in .pcemu file", line); 106 | } 107 | fclose(f1); 108 | } 109 | -------------------------------------------------------------------------------- /cpu.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is CPU.H it contains definitions for cpu.c */ 16 | 17 | 18 | #ifndef CPU_H 19 | #define CPU_H 20 | 21 | #include "mytypes.h" 22 | 23 | enum { 24 | AX = 0, 25 | CX, 26 | DX, 27 | BX, 28 | SP, 29 | BP, 30 | SI, 31 | DI 32 | }; 33 | 34 | enum { 35 | AL = 0, 36 | CL, 37 | DL, 38 | BL, 39 | AH, 40 | CH, 41 | DH, 42 | BH 43 | }; 44 | 45 | enum { 46 | SPL = 8, 47 | SPH, 48 | BPL, 49 | BPH, 50 | SIL, 51 | SIH, 52 | DIL, 53 | DIH 54 | }; 55 | 56 | enum { 57 | ES = 0, 58 | CS, 59 | SS, 60 | DS 61 | }; 62 | 63 | 64 | /* parameter x = result, y = source 1, z = source 2 */ 65 | 66 | #define SetCFB_Add(x,y) (CF = (BYTE)(x) < (BYTE)(y)) 67 | #define SetCFW_Add(x,y) (CF = (WORD)(x) < (WORD)(y)) 68 | #define SetCFB_Sub(y,z) (CF = (BYTE)(y) > (BYTE)(z)) 69 | #define SetCFW_Sub(y,z) (CF = (WORD)(y) > (WORD)(z)) 70 | #define SetZFB(x) (ZF = !(BYTE)(x)) 71 | #define SetZFW(x) (ZF = !(WORD)(x)) 72 | #define SetTF(x) (TF = (x)) 73 | #define SetIF(x) (IF = (x)) 74 | #define SetDF(x) (DF = (x)) 75 | #define SetAF(x,y,z) (AF = ((x) ^ ((y) ^ (z))) & 0x10) 76 | #define SetPF(x) (PF = parity_table[(BYTE)(x)]) 77 | #define SetOFW_Add(x,y,z) (OF = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000) 78 | #define SetOFB_Add(x,y,z) (OF = ((x) ^ (y)) & ((x) ^ (z)) & 0x80) 79 | #define SetOFW_Sub(x,y,z) (OF = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000) 80 | #define SetOFB_Sub(x,y,z) (OF = ((z) ^ (y)) & ((z) ^ (x)) & 0x80) 81 | #define SetSFW(x) (SF = (x) & 0x8000) 82 | #define SetSFB(x) (SF = (x) & 0x80) 83 | 84 | 85 | #define GetMemInc(Seg,Off) ((Seg)[(Off)++]) 86 | 87 | #if defined(TEST) && defined(BSD386) 88 | # define SegToMemPtr(Seg) (sregs[Seg] == 0xa000 ? (BYTE *)0xe00a0000 : \ 89 | sregs[Seg] == 0xb800 ? (BYTE *)0xe00b8000 : \ 90 | &memory[sregs[Seg] << 4]) 91 | #else 92 | # define SegToMemPtr(Seg) (&memory[sregs[Seg] << 4]) 93 | #endif 94 | 95 | 96 | #define PutMemB(Seg,Off,x) ((Seg)[(WORD)(Off)] = (BYTE)(x)) 97 | #define GetMemB(Seg,Off) ((BYTE)(Seg)[(WORD)(Off)]) 98 | 99 | #define CalcAll() 100 | 101 | #define CompressFlags() (UINT32)(CF | (PF << 2) | (!(!AF) << 4) | (ZF << 6) \ 102 | | (!(!SF) << 7) | (TF << 8) | (IF << 9) \ 103 | | (DF << 10) | (!(!OF) << 11)) 104 | 105 | #define ExpandFlags(f) \ 106 | { \ 107 | CF = (f) & 1; \ 108 | PF = ((f) & 4) == 4; \ 109 | AF = (f) & 16; \ 110 | ZF = ((f) & 64) == 64; \ 111 | SF = (f) & 128; \ 112 | TF = ((f) & 256) == 256; \ 113 | IF = ((f) & 512) == 512; \ 114 | DF = ((f) & 1024) == 1024; \ 115 | OF = (f) & 2048; \ 116 | } 117 | 118 | 119 | /* ChangeE(x) changes x to little endian from the machine's natural endian 120 | format and back again. Obviously there is nothing to do for little-endian 121 | machines... */ 122 | 123 | #if defined(PCEMU_LITTLE_ENDIAN) 124 | # define ChangeE(x) (WORD)(x) 125 | #else 126 | # define ChangeE(x) (WORD)(((x) << 8) | ((BYTE)((x) >> 8))) 127 | #endif 128 | 129 | #if defined(PCEMU_LITTLE_ENDIAN) && !defined(ALIGNED_ACCESS) 130 | # define ReadWord(x) (*(x)) 131 | # define WriteWord(x,y) (*(x) = (y)) 132 | # define CopyWord(x,y) (*x = *y) 133 | # define PutMemW(Seg,Off,x) (Seg[Off] = (BYTE)(x), Seg[(WORD)(Off)+1] = (BYTE)((x) >> 8)) 134 | #if 0 135 | # define PutMemW(Seg,Off,x) (*(WORD *)((Seg)+(WORD)(Off)) = (WORD)(x)) 136 | #endif 137 | /* dtrg. `possible pointer alignment problem, Lint says */ 138 | # define GetMemW(Seg,Off) ((WORD)Seg[Off] + ((WORD)Seg[(WORD)(Off)+1] << 8)) 139 | #if 0 140 | # define GetMemW(Seg,Off) (*(WORD *)((Seg)+(Off))) */ 141 | #endif 142 | #else 143 | # define ReadWord(x) ((WORD)(*((BYTE *)(x))) + ((WORD)(*((BYTE *)(x)+1)) << 8)) 144 | # define WriteWord(x,y) (*(BYTE *)(x) = (BYTE)(y), *((BYTE *)(x)+1) = (BYTE)((y) >> 8)) 145 | # define CopyWord(x,y) (*(BYTE *)(x) = *(BYTE *)(y), *((BYTE *)(x)+1) = *((BYTE *)(y)+1)) 146 | # define PutMemW(Seg,Off,x) (Seg[Off] = (BYTE)(x), Seg[(WORD)(Off)+1] = (BYTE)((x) >> 8)) 147 | # define GetMemW(Seg,Off) ((WORD)Seg[Off] + ((WORD)Seg[(WORD)(Off)+1] << 8)) 148 | #endif 149 | 150 | extern WORD wregs[8]; /* Always little-endian */ 151 | extern BYTE *bregs[16]; /* Points to bytes within wregs[] */ 152 | extern unsigned sregs[4]; /* Always native machine word order */ 153 | 154 | extern unsigned ip; /* Always native machine word order */ 155 | 156 | /* All the byte flags will either be 1 or 0 */ 157 | extern BYTE CF, PF, ZF, TF, IF, DF; 158 | 159 | /* All the word flags may be either none-zero (true) or zero (false) */ 160 | extern unsigned AF, OF, SF; 161 | 162 | extern BYTE *c_cs,*c_ds,*c_es,*c_ss,*c_stack; 163 | 164 | extern volatile int int_pending; 165 | extern volatile int int_blocked; 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /curses.c: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | 3 | #include "vgahard.h" 4 | #include "hardware.h" 5 | #include "bios.h" 6 | #include "video.h" 7 | 8 | #include 9 | 10 | extern int mono; 11 | 12 | static WINDOW *scr; 13 | 14 | static void curses_end(void) 15 | { 16 | endwin(); 17 | } 18 | 19 | static void curses_init(void) 20 | { 21 | mono = 1; 22 | scr = initscr(); 23 | cbreak(); 24 | noecho(); 25 | nodelay(stdscr, TRUE); 26 | keypad(scr, TRUE); 27 | 28 | atexit(curses_end); 29 | } 30 | 31 | static void curses_flush(void) 32 | { 33 | refresh(); 34 | } 35 | 36 | static void curses_put_cursor(unsigned x, unsigned y) 37 | { 38 | } 39 | 40 | static void curses_unput_cursor(void) 41 | { 42 | } 43 | 44 | static void curses_copy(unsigned x1, unsigned y1, unsigned x2, unsigned y2, 45 | unsigned nx, unsigned ny) 46 | { 47 | /* Cant figure this out. Be evil. */ 48 | int x, y; 49 | 50 | for (y=0; y<=y2-y1; y++) { 51 | for (x=0; x<=x2-x1; x++) { 52 | int at = mvinch(y1+y, x1+x); 53 | mvaddch(ny+y, nx+x, at); 54 | } 55 | } 56 | } 57 | 58 | static void curses_new_cursor(int st, int end) 59 | { 60 | } 61 | 62 | static void curses_window_size(unsigned width, unsigned height) 63 | { 64 | } 65 | 66 | static void curses_draw_line(unsigned x, unsigned y, const char *text, unsigned len, BYTE attr) 67 | { 68 | mvaddnstr(y, x, text, len); 69 | } 70 | 71 | static BYTE scan_table1[256 - 0x20] = 72 | { 73 | 0x39, 0x02, 74 | #ifdef KBUK /* double quotes, hash symbol */ 75 | 0x03, 0x2b, 76 | #else 77 | 0x28, 0x04, 78 | #endif 79 | 0x05, 0x06, 0x08, 0x28, 80 | 0x0a, 0x0b, 0x09, 0x0d, 0x33, 0x0c, 0x34, 0x35, 81 | 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 82 | 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, 83 | #ifdef KBUK /* at symbol */ 84 | 0x28, 85 | #else 86 | 0x03, 87 | #endif 88 | 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 89 | 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 90 | 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 91 | 0x2d, 0x15, 0x2c, 0x1a, 92 | #ifdef KBUK /* backslash */ 93 | 0x56, 94 | #else 95 | 0x2b, 96 | #endif 97 | 0x1b, 0x07, 0x0c, 98 | 0x29, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 99 | 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 100 | 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 101 | 0x2d, 0x15, 0x2c, 0x1a, 102 | #ifdef KBUK /* vertical bar */ 103 | 0x56, 104 | #else 105 | 0x2b, 106 | #endif 107 | 108 | 0x1b, 109 | 110 | #ifdef KBUK /* tilde */ 111 | 0x2b, 112 | #else 113 | 0x29, 114 | #endif 115 | 0 116 | }; 117 | 118 | static struct { 119 | int code; 120 | int scan; 121 | } basic_keys[] = { 122 | { 263, 0x0e }, 123 | { 10, 0x1c }, 124 | { 27, 0x01 }, 125 | { 9, 0x0f } 126 | }; 127 | 128 | static unsigned translate(int key) 129 | { 130 | int i; 131 | if (key >= 0x20 && key <= 0x20+sizeof(scan_table1)) 132 | return (scan_table1[key - 0x20]); 133 | for (i=0; i<(sizeof(basic_keys)/sizeof(basic_keys[0])); i++) { 134 | if (basic_keys[i].code == key) 135 | return basic_keys[i].scan; 136 | } 137 | return 0; 138 | } 139 | 140 | static void curses_tick(void) 141 | { 142 | int got = getch(); 143 | 144 | if (got != ERR) { 145 | int scan, count; 146 | char buffer[10]; 147 | 148 | // printf("Got %u\n", got); 149 | if ((scan = translate(got)) != 0) { 150 | for (count = 0; scan; count++) 151 | { 152 | buffer[count] = scan & 0xff; 153 | 154 | scan >>= 8; 155 | } 156 | 157 | if (port60_buffer_ok(count)) 158 | { 159 | D(printf("Returning %d scan code bytes\n",count);); 160 | put_scancode(buffer, count); 161 | } 162 | } 163 | } 164 | } 165 | 166 | VIDEO_DRIVER curses_video = { 167 | "curses", 168 | curses_init, 169 | curses_end, 170 | curses_flush, 171 | curses_put_cursor, 172 | curses_unput_cursor, 173 | curses_copy, 174 | curses_new_cursor, 175 | curses_window_size, 176 | curses_draw_line, 177 | curses_tick 178 | }; 179 | -------------------------------------------------------------------------------- /debugger.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | #ifdef DEBUGGER 16 | 17 | #ifndef DEBUGGER_H 18 | #define DEBUGGER_H 19 | 20 | #define D_INT 0 21 | #define D_TRACE 1 22 | 23 | volatile int in_debug; 24 | void call_debugger(int); 25 | int debug_breakin(int); 26 | void print_regs(void); 27 | 28 | extern volatile int breakpoint; 29 | extern volatile int running; 30 | #endif 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /disasm.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | #ifdef DEBUGGER 16 | 17 | #ifndef DISASM_H 18 | #define DISASM_H 19 | 20 | #include "mytypes.h" 21 | 22 | static unsigned decode_br8(BYTE *, unsigned, char *); 23 | static unsigned decode_r8b(BYTE *, unsigned, char *); 24 | static unsigned decode_wr16(BYTE *, unsigned, char *); 25 | static unsigned decode_r16w(BYTE *, unsigned, char *); 26 | static unsigned decode_ald8(BYTE *, unsigned, char *); 27 | static unsigned decode_axd16(BYTE *, unsigned, char *); 28 | static unsigned decode_pushpopseg(BYTE *, unsigned, char *); 29 | static unsigned decode_databyte(BYTE *, unsigned, char *); 30 | static unsigned decode_wordreg(BYTE *, unsigned, char *); 31 | static unsigned decode_cond_jump(BYTE *, unsigned, char *); 32 | static unsigned decode_bd8(BYTE *, unsigned, char *); 33 | static unsigned decode_wd16(BYTE *, unsigned, char *); 34 | static unsigned decode_wd8(BYTE *, unsigned, char *); 35 | static unsigned decode_ws(BYTE *, unsigned, char *); 36 | static unsigned decode_sw(BYTE *, unsigned, char *); 37 | static unsigned decode_w(BYTE *, unsigned, char *); 38 | static unsigned decode_string(BYTE *, unsigned, char *); 39 | static unsigned decode_xchgax(BYTE *, unsigned, char *); 40 | static unsigned decode_far(BYTE *, unsigned, char *); 41 | static unsigned decode_almem(BYTE *, unsigned, char *); 42 | static unsigned decode_axmem(BYTE *, unsigned, char *); 43 | static unsigned decode_memal(BYTE *, unsigned, char *); 44 | static unsigned decode_memax(BYTE *, unsigned, char *); 45 | static unsigned decode_rd(BYTE *, unsigned, char *); 46 | static unsigned decode_d16(BYTE *, unsigned, char *); 47 | static unsigned decode_int3(BYTE *, unsigned, char *); 48 | static unsigned decode_d8(BYTE *, unsigned, char *); 49 | static unsigned decode_bbit1(BYTE *, unsigned, char *); 50 | static unsigned decode_wbit1(BYTE *, unsigned, char *); 51 | static unsigned decode_bbitcl(BYTE *, unsigned, char *); 52 | static unsigned decode_wbitcl(BYTE *, unsigned, char *); 53 | static unsigned decode_escape(BYTE *, unsigned, char *); 54 | static unsigned decode_disp(BYTE *, unsigned, char *); 55 | static unsigned decode_adjust(BYTE *, unsigned, char *); 56 | static unsigned decode_d8al(BYTE *, unsigned, char *); 57 | static unsigned decode_d8ax(BYTE *, unsigned, char *); 58 | static unsigned decode_axd8(BYTE *, unsigned, char *); 59 | static unsigned decode_disp16(BYTE *, unsigned, char *); 60 | static unsigned decode_far_ind(BYTE *, unsigned, char *); 61 | static unsigned decode_portdx(BYTE *, unsigned, char *); 62 | static unsigned decode_f6(BYTE *, unsigned, char *); 63 | static unsigned decode_f7(BYTE *, unsigned, char *); 64 | static unsigned decode_b(BYTE *, unsigned, char *); 65 | static unsigned decode_ff(BYTE *, unsigned, char *); 66 | static unsigned decode_bioscall(BYTE *, unsigned, char *); 67 | 68 | static char *byte_reg[] = { "al","cl","dl","bl","ah","ch","dh","bh" }; 69 | static char *word_reg[] = { "ax","cx","dx","bx","sp","bp","si","di" }; 70 | static char *seg_reg[] = { "es","cs","ss","ds" }; 71 | static char *index_reg[] = { "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" }; 72 | static char *nul_reg[] = { "??", "??", "??", "??", "??", "??", "??", "??" }; 73 | static char *condition[] = 74 | { 75 | "o","no","b","ae","z","nz","be","a","s","ns","p","np","l","ge","le","g" 76 | }; 77 | 78 | static char *itext[] = 79 | { 80 | "", "add", "push", "pop", "or", "adc", "sbb", "and", 81 | "es:", "daa", "sub", "cs:", "das", "xor", "ss:", "aaa", "cmp", "ds:", 82 | "aas", "inc", "dec", "j", "test", "xchg", "mov", "lea", "nop", "cbw", 83 | "cwd", "call", "wait", "pushf", "popf", "sahf", "lahf", "movs", 84 | "cmps", "stos", "lods", "scas", "ret", "les", "lds", "retf", "int", 85 | "into", "iret", "rol", "ror", "rcl", "rcr", "shl", "shr", "sar", "aam", 86 | "aad", "xlat", "esc", "loopne", "loope", "loop", "jcxz", "in", "out", 87 | "jmp", "lock", "repz", "repnz", "hlt", "cmc", "not", "neg", "mul", "imul", 88 | "div", "idiv", "clc", "stc", "cli", "sti", "cld", "std", "db", "???" 89 | }; 90 | 91 | enum instructions 92 | { 93 | none, add, push, pop, or, adc, sbb, and, es, daa, 94 | sub, cs, das, xor, ss, aaa, cmp, ds, aas, inc, dec, jump, test, xchg, 95 | mov, lea, nop, cbw, cwd, call, wait, pushf, popf, sahf, lahf, movs, 96 | cmps, stos, lods, scas, ret, les, lds, retf, intr, into, iret, rol, 97 | ror, rcl, rcr, shl, shr, sar, aam, aad, xlat, esc, loopne, loope, loop, 98 | jcxz, in, out, jmp, lock, repz, repnz, hlt, cmc, not, neg, mul, imul, 99 | divide, idiv, clc, stc, cli, sti, cld, std, db, illegal 100 | }; 101 | 102 | 103 | #define DF_PREFIX 1 104 | #define DF_NOSPACE 2 105 | 106 | static int table_8x[] = { add, or, adc, sbb, and, sub, xor, cmp }; 107 | static int table_cx[] = { rol, ror, rcl, rcr }; 108 | static int table_dx[] = { rol, ror, rcl, rcr, shl, shr, shl, sar }; 109 | static int table_f67[] = { test, illegal, not, neg, mul, imul, divide, idiv }; 110 | static int table_fe[] = { inc, dec, illegal, illegal, illegal, illegal, illegal, illegal }; 111 | static int table_ff[] = { inc, dec, call, call, jmp, jmp, push, illegal }; 112 | 113 | static struct Disasm 114 | { 115 | int text; 116 | unsigned (*type)(BYTE *, unsigned, char *); 117 | int flags; 118 | int *supp; 119 | } disasm_table[256] = 120 | { 121 | { add, decode_br8 }, /* 0x00 */ 122 | { add, decode_wr16 }, /* 0x01 */ 123 | { add, decode_r8b }, /* 0x02 */ 124 | { add, decode_r16w }, /* 0x03 */ 125 | { add, decode_ald8 }, /* 0x04 */ 126 | { add, decode_axd16 }, /* 0x05 */ 127 | { push,decode_pushpopseg }, /* 0x06 */ 128 | { pop, decode_pushpopseg }, /* 0x07 */ 129 | { or, decode_br8 }, /* 0x08 */ 130 | { or, decode_wr16 }, /* 0x09 */ 131 | { or, decode_r8b }, /* 0x0a */ 132 | { or, decode_r16w }, /* 0x0b */ 133 | { or, decode_ald8 }, /* 0x0c */ 134 | { or, decode_axd16 }, /* 0x0d */ 135 | { push,decode_pushpopseg }, /* 0x0e */ 136 | { db, decode_databyte }, /* 0x0f */ 137 | { adc, decode_br8 }, /* 0x10 */ 138 | { adc, decode_wr16 }, /* 0x11 */ 139 | { adc, decode_r8b }, /* 0x12 */ 140 | { adc, decode_r16w }, /* 0x13 */ 141 | { adc, decode_ald8 }, /* 0x14 */ 142 | { adc, decode_axd16 }, /* 0x15 */ 143 | { push,decode_pushpopseg }, /* 0x16 */ 144 | { pop, decode_pushpopseg }, /* 0x17 */ 145 | { sbb, decode_br8 }, /* 0x18 */ 146 | { sbb, decode_wr16 }, /* 0x19 */ 147 | { sbb, decode_r8b }, /* 0x1a */ 148 | { sbb, decode_r16w }, /* 0x1b */ 149 | { sbb, decode_ald8 }, /* 0x1c */ 150 | { sbb, decode_axd16 }, /* 0x1d */ 151 | { push,decode_pushpopseg }, /* 0x1e */ 152 | { pop, decode_pushpopseg }, /* 0x1f */ 153 | { and, decode_br8 }, /* 0x20 */ 154 | { and, decode_wr16 }, /* 0x21 */ 155 | { and, decode_r8b }, /* 0x22 */ 156 | { and, decode_r16w }, /* 0x23 */ 157 | { and, decode_ald8 }, /* 0x24 */ 158 | { and, decode_axd16 }, /* 0x25 */ 159 | { es, NULL, DF_PREFIX }, /* 0x26 */ 160 | { daa }, /* 0x27 */ 161 | { sub, decode_br8 }, /* 0x28 */ 162 | { sub, decode_wr16 }, /* 0x29 */ 163 | { sub, decode_r8b }, /* 0x2a */ 164 | { sub, decode_r16w }, /* 0x2b */ 165 | { sub, decode_ald8 }, /* 0x2c */ 166 | { sub, decode_axd16 }, /* 0x2d */ 167 | { cs, NULL, DF_PREFIX }, /* 0x2e */ 168 | { das }, /* 0x2f */ 169 | { xor, decode_br8 }, /* 0x30 */ 170 | { xor, decode_wr16 }, /* 0x31 */ 171 | { xor, decode_r8b }, /* 0x32 */ 172 | { xor, decode_r16w }, /* 0x33 */ 173 | { xor, decode_ald8 }, /* 0x34 */ 174 | { xor, decode_axd16 }, /* 0x35 */ 175 | { ss, NULL, DF_PREFIX }, /* 0x36 */ 176 | { aaa }, /* 0x37 */ 177 | { cmp, decode_br8 }, /* 0x38 */ 178 | { cmp, decode_wr16 }, /* 0x39 */ 179 | { cmp, decode_r8b }, /* 0x3a */ 180 | { cmp, decode_r16w }, /* 0x3b */ 181 | { cmp, decode_ald8 }, /* 0x3c */ 182 | { cmp, decode_axd16 }, /* 0x3d */ 183 | { ds, NULL, DF_PREFIX }, /* 0x3e */ 184 | { aas }, /* 0x3f */ 185 | { inc, decode_wordreg }, /* 0x40 */ 186 | { inc, decode_wordreg }, /* 0x41 */ 187 | { inc, decode_wordreg }, /* 0x42 */ 188 | { inc, decode_wordreg }, /* 0x43 */ 189 | { inc, decode_wordreg }, /* 0x44 */ 190 | { inc, decode_wordreg }, /* 0x45 */ 191 | { inc, decode_wordreg }, /* 0x46 */ 192 | { inc, decode_wordreg }, /* 0x47 */ 193 | { dec, decode_wordreg }, /* 0x48 */ 194 | { dec, decode_wordreg }, /* 0x49 */ 195 | { dec, decode_wordreg }, /* 0x4a */ 196 | { dec, decode_wordreg }, /* 0x4b */ 197 | { dec, decode_wordreg }, /* 0x4c */ 198 | { dec, decode_wordreg }, /* 0x4d */ 199 | { dec, decode_wordreg }, /* 0x4e */ 200 | { dec, decode_wordreg }, /* 0x4f */ 201 | { push,decode_wordreg }, /* 0x50 */ 202 | { push,decode_wordreg }, /* 0x51 */ 203 | { push,decode_wordreg }, /* 0x52 */ 204 | { push,decode_wordreg }, /* 0x53 */ 205 | { push,decode_wordreg }, /* 0x54 */ 206 | { push,decode_wordreg }, /* 0x55 */ 207 | { push,decode_wordreg }, /* 0x56 */ 208 | { push,decode_wordreg }, /* 0x57 */ 209 | { pop, decode_wordreg }, /* 0x58 */ 210 | { pop, decode_wordreg }, /* 0x59 */ 211 | { pop, decode_wordreg }, /* 0x5a */ 212 | { pop, decode_wordreg }, /* 0x5b */ 213 | { pop, decode_wordreg }, /* 0x5c */ 214 | { pop, decode_wordreg }, /* 0x5d */ 215 | { pop, decode_wordreg }, /* 0x5e */ 216 | { pop, decode_wordreg }, /* 0x5f */ 217 | { db, decode_databyte }, /* 0x60 */ 218 | { db, decode_databyte }, /* 0x61 */ 219 | { db, decode_databyte }, /* 0x62 */ 220 | { db, decode_databyte }, /* 0x63 */ 221 | { db, decode_databyte }, /* 0x64 */ 222 | { db, decode_databyte }, /* 0x65 */ 223 | { db, decode_databyte }, /* 0x66 */ 224 | { db, decode_databyte }, /* 0x67 */ 225 | { db, decode_databyte }, /* 0x68 */ 226 | { db, decode_databyte }, /* 0x69 */ 227 | { db, decode_databyte }, /* 0x6a */ 228 | { db, decode_databyte }, /* 0x6b */ 229 | { db, decode_databyte }, /* 0x6c */ 230 | { db, decode_databyte }, /* 0x6d */ 231 | { db, decode_databyte }, /* 0x6e */ 232 | { db, decode_databyte }, /* 0x6f */ 233 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x70 */ 234 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x71 */ 235 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x72 */ 236 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x73 */ 237 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x74 */ 238 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x75 */ 239 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x76 */ 240 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x77 */ 241 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x78 */ 242 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x79 */ 243 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x7a */ 244 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x7b */ 245 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x7c */ 246 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x7d */ 247 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x7e */ 248 | { jump,decode_cond_jump, DF_NOSPACE }, /* 0x7f */ 249 | { none,decode_bd8, 0, table_8x }, /* 0x80 */ 250 | { none,decode_wd16,0, table_8x }, /* 0x81 */ 251 | { db, decode_databyte }, /* 0x82 */ 252 | { none,decode_wd8, 0, table_8x }, /* 0x83 */ 253 | { test,decode_br8 }, /* 0x84 */ 254 | { test,decode_wr16 }, /* 0x85 */ 255 | { xchg,decode_br8 }, /* 0x86 */ 256 | { xchg,decode_wr16 }, /* 0x87 */ 257 | { mov, decode_br8 }, /* 0x88 */ 258 | { mov, decode_wr16 }, /* 0x89 */ 259 | { mov, decode_r8b }, /* 0x8a */ 260 | { mov, decode_r16w }, /* 0x8b */ 261 | { mov, decode_ws }, /* 0x8c */ 262 | { lea, decode_r16w }, /* 0x8d */ 263 | { mov, decode_sw }, /* 0x8e */ 264 | { pop, decode_w }, /* 0x8f */ 265 | { nop }, /* 0x90 */ 266 | { xchg,decode_xchgax }, /* 0x91 */ 267 | { xchg,decode_xchgax }, /* 0x92 */ 268 | { xchg,decode_xchgax }, /* 0x93 */ 269 | { xchg,decode_xchgax }, /* 0x94 */ 270 | { xchg,decode_xchgax }, /* 0x95 */ 271 | { xchg,decode_xchgax }, /* 0x96 */ 272 | { xchg,decode_xchgax }, /* 0x97 */ 273 | { cbw }, /* 0x98 */ 274 | { cwd }, /* 0x99 */ 275 | { call,decode_far }, /* 0x9a */ 276 | { wait }, /* 0x9b */ 277 | { pushf }, /* 0x9c */ 278 | { popf }, /* 0x9d */ 279 | { sahf }, /* 0x9e */ 280 | { lahf }, /* 0x9f */ 281 | { mov, decode_almem }, /* 0xa0 */ 282 | { mov, decode_axmem }, /* 0xa1 */ 283 | { mov, decode_memal }, /* 0xa2 */ 284 | { mov, decode_memax }, /* 0xa3 */ 285 | { movs,decode_string, DF_NOSPACE }, /* 0xa4 */ 286 | { movs,decode_string, DF_NOSPACE }, /* 0xa5 */ 287 | { cmps,decode_string, DF_NOSPACE }, /* 0xa6 */ 288 | { cmps,decode_string, DF_NOSPACE }, /* 0xa7 */ 289 | { test,decode_ald8, }, /* 0xa8 */ 290 | { test,decode_axd16 }, /* 0xa9 */ 291 | { stos,decode_string, DF_NOSPACE }, /* 0xaa */ 292 | { stos,decode_string, DF_NOSPACE }, /* 0xab */ 293 | { lods,decode_string, DF_NOSPACE }, /* 0xac */ 294 | { lods,decode_string, DF_NOSPACE }, /* 0xad */ 295 | { scas,decode_string, DF_NOSPACE }, /* 0xae */ 296 | { scas,decode_string, DF_NOSPACE }, /* 0xaf */ 297 | { mov, decode_rd }, /* 0xb0 */ 298 | { mov, decode_rd }, /* 0xb1 */ 299 | { mov, decode_rd }, /* 0xb2 */ 300 | { mov, decode_rd }, /* 0xb3 */ 301 | { mov, decode_rd }, /* 0xb4 */ 302 | { mov, decode_rd }, /* 0xb5 */ 303 | { mov, decode_rd }, /* 0xb6 */ 304 | { mov, decode_rd }, /* 0xb7 */ 305 | { mov, decode_rd }, /* 0xb8 */ 306 | { mov, decode_rd }, /* 0xb9 */ 307 | { mov, decode_rd }, /* 0xba */ 308 | { mov, decode_rd }, /* 0xbb */ 309 | { mov, decode_rd }, /* 0xbc */ 310 | { mov, decode_rd }, /* 0xbd */ 311 | { mov, decode_rd }, /* 0xbe */ 312 | { mov, decode_rd }, /* 0xbf */ 313 | { none,decode_bd8, 0, table_cx }, /* 0xc0 */ 314 | { none,decode_wd8, 0, table_cx }, /* 0xc1 */ 315 | { ret, decode_d16 }, /* 0xc2 */ 316 | { ret }, /* 0xc3 */ 317 | { les, decode_r16w }, /* 0xc4 */ 318 | { lds, decode_r16w }, /* 0xc5 */ 319 | { mov, decode_bd8 }, /* 0xc6 */ 320 | { mov, decode_wd16 }, /* 0xc7 */ 321 | { db, decode_databyte }, /* 0xc8 */ 322 | { db, decode_databyte }, /* 0xc9 */ 323 | { retf,decode_d16 }, /* 0xca */ 324 | { retf }, /* 0xcb */ 325 | { intr,decode_int3 }, /* 0xcc */ 326 | { intr,decode_d8 }, /* 0xcd */ 327 | { into }, /* 0xce */ 328 | { iret }, /* 0xcf */ 329 | { none,decode_bbit1, 0, table_dx }, /* 0xd0 */ 330 | { none,decode_wbit1, 0, table_dx }, /* 0xd1 */ 331 | { none,decode_bbitcl, 0, table_dx }, /* 0xd2 */ 332 | { none,decode_wbitcl, 0, table_dx }, /* 0xd3 */ 333 | { aam, decode_adjust }, /* 0xd4 */ 334 | { aad, decode_adjust }, /* 0xd5 */ 335 | { db, decode_databyte }, /* 0xd6 */ 336 | { xlat }, /* 0xd7 */ 337 | { esc, decode_escape }, /* 0xd8 */ 338 | { esc, decode_escape }, /* 0xd9 */ 339 | { esc, decode_escape }, /* 0xda */ 340 | { esc, decode_escape }, /* 0xdb */ 341 | { esc, decode_escape }, /* 0xdc */ 342 | { esc, decode_escape }, /* 0xdd */ 343 | { esc, decode_escape }, /* 0xde */ 344 | { esc, decode_escape }, /* 0xdf */ 345 | { loopne,decode_disp }, /* 0xe0 */ 346 | { loope,decode_disp }, /* 0xe1 */ 347 | { loop,decode_disp }, /* 0xe2 */ 348 | { jcxz,decode_disp }, /* 0xe3 */ 349 | { in, decode_ald8 }, /* 0xe4 */ 350 | { in, decode_axd8 }, /* 0xe5 */ 351 | { out, decode_d8al }, /* 0xe6 */ 352 | { out, decode_d8ax }, /* 0xe7 */ 353 | { call,decode_disp16 }, /* 0xe8 */ 354 | { jmp, decode_disp16 }, /* 0xe9 */ 355 | { jmp, decode_far }, /* 0xea */ 356 | { jmp, decode_disp }, /* 0xeb */ 357 | { in, decode_portdx }, /* 0xec */ 358 | { in, decode_portdx }, /* 0xed */ 359 | { out, decode_portdx }, /* 0xee */ 360 | { out, decode_portdx }, /* 0xef */ 361 | { lock,NULL, DF_PREFIX }, /* 0xf0 */ 362 | { none,decode_bioscall, DF_NOSPACE }, /* 0xf1 */ 363 | { repnz,NULL, DF_PREFIX }, /* 0xf2 */ 364 | { repz,NULL, DF_PREFIX }, /* 0xf3 */ 365 | { hlt }, /* 0xf4 */ 366 | { cmc }, /* 0xf5 */ 367 | { none,decode_f6, 0, table_f67 }, /* 0xf6 */ 368 | { none,decode_f7, 0, table_f67 }, /* 0xf7 */ 369 | { clc }, /* 0xf8 */ 370 | { stc }, /* 0xf9 */ 371 | { cli }, /* 0xfa */ 372 | { sti }, /* 0xfb */ 373 | { cld }, /* 0xfc */ 374 | { std }, /* 0xfd */ 375 | { none,decode_b, 0, table_fe }, /* 0xfe */ 376 | { none,decode_ff,0, table_ff }, /* 0xff */ 377 | }; 378 | 379 | #endif 380 | #endif 381 | -------------------------------------------------------------------------------- /dot.pcemurc: -------------------------------------------------------------------------------- 1 | # This is .pcemurc 2 | # At present only the following commands are recognised: 3 | # bootfile diskfile 4 | # boottype n (where n=360, 720, 144 or 12) 5 | # cursorspeed n 6 | # updatespeed n 7 | # 8 | # The following are the defaults (unless changed at compile time) 9 | 10 | # Note: see new.pcemurc. These options no longer work (25/1/01) 11 | bootfile DriveA 12 | boottype 144 13 | cursorspeed 30 14 | updatespeed 5 15 | -------------------------------------------------------------------------------- /ems.c: -------------------------------------------------------------------------------- 1 | /* ems.c- Adds LIM-EMS 3.2 to the PC emulator 2 | Copyright 1994, Eric Korpela 3 | Permission is given to copy, modify and distribute this code 4 | provided that this copyright notice is not modified. 5 | 6 | BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 7 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT 8 | WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER 9 | PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, 10 | EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 11 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 12 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 13 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 14 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 15 | 16 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 17 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 18 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 19 | DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 20 | DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 21 | (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 22 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 23 | THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER 24 | OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 25 | */ 26 | /* bug reports to */ 27 | #include "global.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "cpu.h" 38 | #include "vga.h" 39 | #include "bios.h" 40 | #include "debugger.h" 41 | #include "vgahard.h" 42 | #include "hardware.h" 43 | 44 | #define BIOS 45 | #define Total_EMS_Pages 1024 46 | #define Total_EMS_Handles 255 47 | #ifndef PAGEFRAME 48 | #define PAGEFRAME 0xe000 49 | #endif 50 | 51 | 52 | unsigned Unallocated_Pages, Free_EMS_Handles, 53 | Allocated_Pages[Total_EMS_Handles+1], 54 | EMS_Context_Pages[4], EMS_Context_Handles[4], 55 | Mapping_Context_Pages[Total_EMS_Handles+1][4], 56 | Mapping_Context_Handles[Total_EMS_Handles+1][4]; 57 | 58 | BYTE Handle_Flag[Total_EMS_Handles+1]; 59 | 60 | BYTE *EMS_Pointer[Total_EMS_Handles+1]; 61 | 62 | void EMS_Setup(void) 63 | { 64 | unsigned tmp,tmp2; 65 | D(printf("In EMS setup\n");); 66 | Unallocated_Pages=Total_EMS_Pages; 67 | for (tmp=0;tmp<=Total_EMS_Handles;tmp++) 68 | { 69 | /* Added the =0. Was just for(tmp2;tmp2... Accident? dtrg */ 70 | for (tmp2=0;tmp2<4;tmp2++) 71 | { 72 | Mapping_Context_Pages[tmp][tmp2]=0; 73 | Mapping_Context_Handles[tmp][tmp2]=0; 74 | } 75 | Handle_Flag[tmp]=0; 76 | Allocated_Pages[tmp]=0; 77 | Free_EMS_Handles=Total_EMS_Handles; 78 | } 79 | EMS_Pointer[0]=(BYTE *)malloc(0x04000*4); 80 | Allocated_Pages[0]=4; 81 | Handle_Flag[0]=1; 82 | } 83 | 84 | void EMS_Map(unsigned handle, unsigned logical_page, unsigned physical_page) 85 | { 86 | unsigned tmp,tmp1; 87 | BYTE *ptr0,*ptr1,*ptr2; 88 | D(printf("Mapping EMS handle=%04X, logical_page=%04X, physical_page=%1X\n" 89 | ,handle,logical_page,physical_page);); 90 | if ((Allocated_Pages[handle]>logical_page) || (handle==0)) 91 | { 92 | ptr0=&memory[(PAGEFRAME << 4) + physical_page * 0x04000 ]; 93 | D(printf("Mapping Page to 0x%05X\n",(PAGEFRAME << 4) + physical_page * 0x04000);); 94 | ptr2=EMS_Pointer[handle]+logical_page*0x04000; 95 | if ((EMS_Context_Handles[physical_page]!=0)&&((EMS_Context_Handles[physical_page]!=handle)||(EMS_Context_Pages[physical_page]!=logical_page))) 96 | { 97 | ptr1=EMS_Pointer[EMS_Context_Handles[physical_page]] 98 | +EMS_Context_Pages[physical_page]*0x04000; 99 | memcpy(ptr1,ptr0,0x04000); 100 | D(printf("EMS ptr0(0x%08X) ---> ptr1(0x%08X)\n",ptr0,ptr1);); 101 | } 102 | if ((EMS_Context_Handles[physical_page]!=handle)||(EMS_Context_Pages[physical_page]!=logical_page)) 103 | { 104 | D(printf("EMS ptr2(0x%08X) ---> ptr0(0x%08X)\n",ptr2,ptr0);); 105 | memcpy(ptr0,ptr2,0x04000); 106 | } 107 | *bregs[AH]=0x00; 108 | } else *bregs[AH]=0x8A; 109 | EMS_Context_Handles[physical_page]=handle; 110 | EMS_Context_Pages[physical_page]=logical_page; 111 | tmp1=0; 112 | for (tmp=0;tmp<4;tmp++) 113 | if ((EMS_Context_Handles[tmp]==handle) 114 | &&(EMS_Context_Pages[tmp]==logical_page)&&(handle!=0)) tmp1++; 115 | if ((tmp1!=1)&&(handle!=0)) 116 | printf("WARNING--Multiply mapped page: Handle 0x%02X, Page 0x%04X\n",handle,logical_page); 117 | } 118 | 119 | void int_ems(void) 120 | { 121 | unsigned tmp,tmp2,tmp3; 122 | D(printf("In INT 0x67 (EMS) AH = 0x%02X AL = 0x%02X\n",*bregs[AH],*bregs[AL]);); 123 | CalcAll(); 124 | switch(*bregs[AH]) 125 | { 126 | case 0x40: *bregs[AH] = 0; 127 | break; 128 | case 0x41: wregs[BX] = ChangeE(PAGEFRAME); 129 | *bregs[AH] = 0x00; 130 | break; 131 | case 0x42: *bregs[AH] = 0x00; 132 | wregs[BX] = ChangeE((WORD)Unallocated_Pages); 133 | wregs[DX] = ChangeE((WORD)Total_EMS_Pages); 134 | break; 135 | case 0x43: tmp=ChangeE(wregs[BX]); 136 | if (tmp>Total_EMS_Pages) {*bregs[AH]=0x87;break;} 137 | if (tmp>Unallocated_Pages) {*bregs[AH]=0x88;break;} 138 | if (tmp==0) {*bregs[AH]=0x89;break;} 139 | if (Free_EMS_Handles==0) {*bregs[AH]=0x85;break;} 140 | for (tmp2=1;tmp23) {*bregs[AH]=0x8B;break;} 155 | EMS_Map(tmp,tmp2,tmp3); 156 | break; 157 | case 0x45: tmp=ChangeE(wregs[DX]); 158 | if (tmp==0) 159 | { 160 | printf("Warning--Attempt to unallocate handle 0x00\n"); 161 | *bregs[AH]=0x83; 162 | } 163 | Handle_Flag[tmp]=0; 164 | Unallocated_Pages+=Allocated_Pages[tmp]; 165 | Allocated_Pages[tmp]=0; 166 | free(EMS_Pointer[tmp]); 167 | Free_EMS_Handles++; 168 | *bregs[AH]=0x00; 169 | break; 170 | case 0x46: *bregs[AH]=0x00; 171 | *bregs[AL]=0x32; 172 | break; 173 | case 0x47: tmp=ChangeE(wregs[DX]); 174 | for (tmp2=0;tmp2<4;tmp2++) 175 | { 176 | Mapping_Context_Pages[tmp][tmp2]=EMS_Context_Pages[tmp2]; 177 | Mapping_Context_Handles[tmp][tmp2]=EMS_Context_Handles[tmp2]; 178 | } 179 | *bregs[AH]=0x00; 180 | break; 181 | case 0x48: tmp=ChangeE(wregs[DX]); 182 | for (tmp2=0;tmp2<4;tmp2++) 183 | { 184 | EMS_Map(Mapping_Context_Handles[tmp][tmp2], 185 | Mapping_Context_Pages[tmp][tmp2],tmp2); 186 | } 187 | *bregs[AH]=0x00; 188 | break; 189 | case 0x4b: wregs[BX]=ChangeE(Total_EMS_Handles-Free_EMS_Handles); 190 | *bregs[AH]=0x00; 191 | break; 192 | case 0x4c: tmp=ChangeE(wregs[DX]); 193 | wregs[BX]=ChangeE(Allocated_Pages[tmp]); 194 | *bregs[AH]=0x00; 195 | break; 196 | case 0x4d: tmp=Total_EMS_Handles-Free_EMS_Handles; 197 | tmp3=0; 198 | for (tmp2=1;tmp2 hardware.o mfs.o ems.o 5 | 79a80,84 6 | > ems.o: $(GLOBAL_DEP) cpu.h bios.h 7 | > cpu.s: $(GLOBAL_DEP) cpu.h instr.h debugger.h hardware.h 8 | > 9 | > .c.s: 10 | > $(CC) $(CFLAGS) $(OPTIONS) -S $< 11 | -------------------------------------------------------------------------------- /ems/bios.c.patch: -------------------------------------------------------------------------------- 1 | 12a13 2 | > * Modifications for EMS, Copyright 1994, Eric Korpela * 3 | 40a42 4 | > 5 | 1117d1118 6 | < 7 | 1120a1122 8 | > EMS_Setup(); 9 | 1176c1178 10 | < 11 | --- 12 | > set_int(0x4b, NULL, 0, int_67, afterint, sizeof afterint); 13 | -------------------------------------------------------------------------------- /ems/bios.h.patch: -------------------------------------------------------------------------------- 1 | 12a13,14 2 | > * Modifications for EMS 3.2 Copyright 1994, Eric Korpela * 3 | > * * 4 | 29c31,32 5 | < 6 | --- 7 | > void int_67(void); 8 | > void EMS_Setup(void); 9 | -------------------------------------------------------------------------------- /ems/ems.doc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | 3 | Installation of the EMS driver.... 4 | 5 | Copy the files ems.c, patch.script and *.patch into the pcemu source 6 | directory. Execute the patch.script file. If you don't have "patch" on 7 | your machine you'll have to edit the source files manually. Remake the 8 | 'pcemu' executable. 9 | 10 | Copy the 'EKEMM.SYS' file to your boot drive/file. and add a line to 11 | your config.sys 'DEVICE=EKEMM.SYS' 12 | 13 | That's all there is to it. Report any problems to me. 14 | (korpela@ssl.berkeley.edu) 15 | 16 | There is no warantee expressed or implied in this software. Use at your own 17 | risk. See the files COPYRIGHT and ems.c for details. 18 | 19 | -----BEGIN PGP SIGNATURE----- 20 | Version: 2.6 21 | 22 | iQCVAgUBLj6fC+BZ/OT/DJLdAQHBCAP+IfVDyFHzI8qaQB1QeqXRVxjyMo9zWzje 23 | QXzyk3SU40oE/GfRdQm8YBotvY5IkH2gbHIkxDOzxRuErlihVqARBJVW1sRPiJWz 24 | PGQ1k2CRfUPKbwGegyjTmYXNaUx1CCmGMgA5doxOJU61Xfa5Z3vMYLHRFd3HXag4 25 | CxFtntwo6rM= 26 | =agEc 27 | -----END PGP SIGNATURE----- 28 | -------------------------------------------------------------------------------- /ems/patch.script: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | patch Makefile 26 | #include 27 | 28 | #ifdef ME 29 | # include "uprotos.h" 30 | #endif 31 | 32 | #ifndef FALSE 33 | # define FALSE 0 34 | #endif 35 | #ifndef TRUE 36 | # define TRUE (!FALSE) 37 | #endif 38 | 39 | #define MEMORY_SIZE (1024*1024+65536) 40 | 41 | #ifdef INLINE_FUNCTIONS 42 | # define INLINE inline 43 | # define INLINE2 inline 44 | #else 45 | # define INLINE 46 | # define INLINE2 47 | #endif 48 | 49 | #ifdef DEBUG 50 | # define D(x) x 51 | #else 52 | # define D(x) 53 | #endif 54 | 55 | #ifdef DEBUG2 56 | # define D2(x) x 57 | #else 58 | # define D2(x) 59 | #endif 60 | 61 | #ifdef _HPUX_SOURCE 62 | #ifndef __hpux 63 | #define __hpux 64 | #endif 65 | #endif 66 | 67 | extern BYTE *memory; 68 | extern char *progname; 69 | 70 | void init_cpu(void); 71 | void execute(void); 72 | void exit_emu(void); 73 | void read_pcemurc(void); 74 | 75 | #endif 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /hardware.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is HARDWARE.C It contains stuff about the PC hardware (chips etc) */ 16 | 17 | #include "global.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "hardware.h" 24 | #include "cpu.h" 25 | #include "vgahard.h" 26 | 27 | #ifdef DEBUGGER 28 | # include "debugger.h" 29 | #endif 30 | 31 | static struct itimerval timer; 32 | 33 | static volatile int disable_int; 34 | static volatile int timer_blocked = 1; 35 | 36 | #define PORT60SIZE 5 37 | 38 | static BYTE port60buffer[PORT60SIZE]; 39 | static int port60start, port60end; 40 | 41 | static unsigned PIC_inservice; 42 | static unsigned PIC_irq; 43 | static unsigned PIC_mask = ~(PIC_TIMER|PIC_KEYBOARD); 44 | 45 | static unsigned timer_tmp; 46 | 47 | static unsigned VGA_status; 48 | 49 | static void PIC_interrupt(void) 50 | { 51 | if (PIC_inservice) 52 | { 53 | D2(printf("PIC still blocked\n");); 54 | return; 55 | } 56 | 57 | if (PIC_irq & ~PIC_mask & PIC_TIMER) 58 | { 59 | D2(printf("INTR: timer\n");); 60 | PIC_inservice = PIC_TIMER; 61 | PIC_irq &= ~PIC_TIMER; 62 | if (IF) 63 | int_pending = 8; 64 | else 65 | { 66 | D2(printf("INTR blocked: IF disabled\n");); 67 | int_blocked = 8; 68 | } 69 | } 70 | else if (PIC_irq & ~PIC_mask & PIC_KEYBOARD) 71 | { 72 | D2(printf("INTR: keyboard\n");); 73 | PIC_inservice = PIC_KEYBOARD; 74 | PIC_irq &= ~PIC_KEYBOARD; 75 | if (IF) 76 | int_pending = 9; 77 | else 78 | { 79 | D2(printf("INTR blocked: IF disabled\n");); 80 | int_blocked = 9; 81 | } 82 | } 83 | } 84 | 85 | 86 | static void PIC_flagint(unsigned interrupt) 87 | { 88 | disable(); 89 | D2(printf("IRQ %02X\n", interrupt);); 90 | PIC_irq |= interrupt; 91 | enable(); 92 | } 93 | 94 | 95 | void PIC_EOI(void) 96 | { 97 | disable(); 98 | 99 | if (PIC_inservice & PIC_KEYBOARD) 100 | { 101 | if (++port60start >= PORT60SIZE) 102 | port60start = 0; 103 | 104 | if (port60start != port60end) 105 | PIC_irq |= PIC_KEYBOARD; 106 | } 107 | 108 | 109 | PIC_inservice = 0; 110 | PIC_interrupt(); 111 | enable(); 112 | } 113 | 114 | 115 | int port60_buffer_ok(int count) 116 | { 117 | int tmp = port60end; 118 | 119 | for (; count > 0; count--) 120 | { 121 | if (++tmp >= PORT60SIZE) 122 | tmp = 0; 123 | 124 | if (tmp == port60start) 125 | return FALSE; 126 | } 127 | 128 | return TRUE; 129 | } 130 | 131 | 132 | void put_scancode(BYTE *code, int count) 133 | { 134 | for (; count > 0; count--) 135 | { 136 | port60buffer[port60end] = *code++; 137 | 138 | if (++port60end >= PORT60SIZE) 139 | port60end = 0; 140 | } 141 | 142 | PIC_flagint(PIC_KEYBOARD); 143 | 144 | D2( 145 | { 146 | int tmp; 147 | 148 | printf("INT9 signalled\n"); 149 | printf("Port60 buffer: "); 150 | 151 | tmp = port60start; 152 | while (tmp != port60end) 153 | { 154 | printf("%02X ", port60buffer[tmp]); 155 | if (++tmp >= PORT60SIZE) 156 | tmp = 0; 157 | } 158 | printf("\n"); 159 | } 160 | ) 161 | } 162 | 163 | 164 | static BYTE read_port60(void) 165 | { 166 | BYTE ret; 167 | static BYTE lastread = 0; 168 | 169 | disable(); 170 | 171 | if (port60start == port60end) 172 | ret = lastread; 173 | else 174 | lastread = ret = port60buffer[port60start]; 175 | 176 | enable(); 177 | 178 | return ret; 179 | } 180 | 181 | #define TIMER_MULT 4 182 | 183 | static volatile int int8_counter = TIMER_MULT; 184 | 185 | static int timer_handler(int sig) 186 | { 187 | 188 | #ifdef DEBUGGER 189 | if (in_debug) 190 | return 0; 191 | #endif 192 | 193 | if (disable_int) 194 | { 195 | D2(printf("Timer called when disabled\n");); 196 | timer_blocked++; 197 | return 0; 198 | } 199 | 200 | disable(); 201 | 202 | vga_interrupt(); 203 | 204 | timer_tmp++; 205 | 206 | if (--int8_counter == 0) 207 | { 208 | PIC_flagint(PIC_TIMER); 209 | int8_counter = TIMER_MULT; 210 | } 211 | 212 | PIC_interrupt(); 213 | 214 | enable(); 215 | return 0; 216 | } 217 | 218 | 219 | #ifndef SA_RESTART 220 | #define SA_RESTART 0 221 | #endif 222 | 223 | void init_timer(void) 224 | { 225 | struct sigaction sa; 226 | 227 | sa.sa_handler = (void *)timer_handler; 228 | sa.sa_flags = SA_RESTART; 229 | sigemptyset(&sa.sa_mask); 230 | 231 | sigaction(SIGALRM, &sa, NULL); 232 | 233 | timer.it_interval.tv_sec = timer.it_value.tv_sec = 0; 234 | timer.it_interval.tv_usec = timer.it_value.tv_usec = 235 | (long)(1000000.0 /((float)TIMER_MULT*TICKSPERSEC)); 236 | 237 | D2(printf("Set timer to %ld microseconds\n", timer.it_interval.tv_usec);); 238 | setitimer(ITIMER_REAL, &timer, NULL); 239 | } 240 | 241 | 242 | void stoptimer(void) 243 | { 244 | timer.it_interval.tv_sec = timer.it_value.tv_sec = 245 | timer.it_interval.tv_usec = timer.it_value.tv_usec = 0; 246 | setitimer(ITIMER_REAL, &timer, NULL); 247 | signal(SIGALRM, SIG_IGN); 248 | } 249 | 250 | 251 | void starttimer(void) 252 | { 253 | init_timer(); 254 | } 255 | 256 | 257 | void disable(void) 258 | { 259 | if (disable_int == 0) 260 | timer_blocked = 0; 261 | disable_int++; 262 | } 263 | 264 | 265 | void enable(void) 266 | { 267 | if (disable_int > 0) 268 | disable_int--; 269 | 270 | if (disable_int == 0) 271 | while (timer_blocked > 0) 272 | { 273 | timer_blocked--; 274 | timer_handler(SIGALRM); 275 | } 276 | } 277 | 278 | 279 | static int PIT_toggle = 1; 280 | 281 | BYTE read_port(unsigned port) 282 | { 283 | BYTE val; 284 | static unsigned timer_tmp; 285 | 286 | switch(port) 287 | { 288 | case 0x21: 289 | val = PIC_mask; 290 | break; 291 | case 0x40: 292 | case 0x41: 293 | case 0x42: 294 | disable(); 295 | if ((PIT_toggle = !PIT_toggle) == 0) 296 | val = timer_tmp & 0xff; 297 | else 298 | { 299 | val = (timer_tmp & 0xff00) >> 8; 300 | timer_tmp++; 301 | } 302 | enable(); 303 | break; 304 | case 0x60: 305 | val = read_port60(); 306 | break; 307 | case 0x61: 308 | val = 0xd0; 309 | break; 310 | case 0x3da: 311 | val = VGA_status; 312 | VGA_status ^= 0x9; 313 | break; 314 | case 0x2fd: 315 | val = 0xff; 316 | break; 317 | default: 318 | val = 0; 319 | break; 320 | } 321 | 322 | D(printf("Reading 0x%02X from port 0x%04X\n", val, port);); 323 | return val; 324 | } 325 | 326 | 327 | void write_port(unsigned port, BYTE value) 328 | { 329 | switch(port) 330 | { 331 | case 0x20: 332 | if (value == 0x20) 333 | { 334 | PIC_EOI(); 335 | return; 336 | } 337 | break; 338 | case 0x21: 339 | disable(); 340 | PIC_mask = value; 341 | enable(); 342 | break; 343 | case 0x43: 344 | PIT_toggle = 1; 345 | break; 346 | default: 347 | break; 348 | } 349 | D(printf("Writing 0x%02X to port 0x%04X\n", value, port);); 350 | 351 | } 352 | 353 | 354 | -------------------------------------------------------------------------------- /hardware.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | #ifndef HARDWARE_H 16 | #define HARDWARE_H 17 | 18 | #include "mytypes.h" 19 | 20 | #define PIC_TIMER 1 21 | #define PIC_KEYBOARD 2 22 | 23 | #define TICKSPERSEC (1193180.0/65536.0) 24 | 25 | int port60_buffer_ok(int); 26 | void put_scancode(BYTE *, int); 27 | void init_timer(void); 28 | 29 | void disable(void); 30 | void enable(void); 31 | 32 | void starttimer(void); 33 | void stoptimer(void); 34 | 35 | BYTE read_port(unsigned); 36 | void write_port(unsigned, BYTE); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /icon.h: -------------------------------------------------------------------------------- 1 | #define icon_width 40 2 | #define icon_height 40 3 | static char icon_bits[] = { 4 | 0xfc, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xfe, 0x07, 5 | 0x00, 0x00, 0x00, 0x8e, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x1f, 0x00, 0x00, 6 | 0x00, 0x0e, 0x3c, 0x00, 0x00, 0x00, 0x0e, 0x78, 0x00, 0x00, 0x00, 0x0e, 7 | 0x78, 0x00, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x0e, 0xe0, 0x00, 8 | 0x00, 0x00, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x0e, 0xe0, 0x01, 0x00, 0x00, 9 | 0x0e, 0xe0, 0x01, 0x00, 0x00, 0x0e, 0xe0, 0x01, 0x00, 0x00, 0x0e, 0xc0, 10 | 0x03, 0x00, 0x00, 0x0e, 0xe0, 0x01, 0xfc, 0x0f, 0x0e, 0xe0, 0x01, 0xfe, 11 | 0x1f, 0x0e, 0xe0, 0x81, 0xff, 0x1f, 0x0e, 0xe0, 0xc0, 0x0f, 0x18, 0x0e, 12 | 0xe0, 0xe0, 0x03, 0x00, 0x0e, 0xf0, 0xe0, 0x01, 0x00, 0x0e, 0x78, 0xf0, 13 | 0x00, 0x00, 0x0e, 0x78, 0x78, 0x00, 0x00, 0x0e, 0x3c, 0x78, 0x00, 0x00, 14 | 0x0e, 0x1f, 0x38, 0x00, 0x00, 0x8e, 0x0f, 0x38, 0x00, 0x00, 0xfe, 0x07, 15 | 0x38, 0x00, 0x00, 0xfe, 0x03, 0x3c, 0x00, 0x00, 0xfe, 0x00, 0x38, 0x00, 16 | 0x00, 0x1e, 0x00, 0x38, 0x00, 0x00, 0x0e, 0x00, 0x38, 0x00, 0x00, 0x0e, 17 | 0x00, 0x78, 0x00, 0x00, 0x0e, 0x00, 0x78, 0x00, 0x00, 0x0e, 0x00, 0xf0, 18 | 0x00, 0x00, 0x0e, 0x00, 0xe0, 0x01, 0x00, 0x0e, 0x00, 0xe0, 0x03, 0x00, 19 | 0x0e, 0x00, 0xc0, 0x0f, 0x18, 0x0e, 0x00, 0x80, 0xff, 0x1f, 0x0e, 0x00, 20 | 0x00, 0xfe, 0x1f, 0x0e, 0x00, 0x00, 0xfc, 0x0f}; 21 | -------------------------------------------------------------------------------- /instr.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is INSTR.H It contains the functions corresponding to each individual 16 | instruction in the 80x86 set */ 17 | 18 | #ifndef INSTR_H 19 | #define INSTR_H 20 | 21 | static INLINE2 void i_add_br8(void); 22 | static INLINE2 void i_add_wr16(void); 23 | static INLINE2 void i_add_r8b(void); 24 | static INLINE2 void i_add_r16w(void); 25 | static INLINE2 void i_add_ald8(void); 26 | static INLINE2 void i_add_axd16(void); 27 | static INLINE2 void i_push_es(void); 28 | static INLINE2 void i_pop_es(void); 29 | static INLINE2 void i_or_br8(void); 30 | static INLINE2 void i_or_r8b(void); 31 | static INLINE2 void i_or_wr16(void); 32 | static INLINE2 void i_or_r16w(void); 33 | static INLINE2 void i_or_ald8(void); 34 | static INLINE2 void i_or_axd16(void); 35 | static INLINE2 void i_push_cs(void); 36 | static INLINE2 void i_adc_br8(void); 37 | static INLINE2 void i_adc_wr16(void); 38 | static INLINE2 void i_adc_r8b(void); 39 | static INLINE2 void i_adc_r16w(void); 40 | static INLINE2 void i_adc_ald8(void); 41 | static INLINE2 void i_adc_axd16(void); 42 | static INLINE2 void i_push_ss(void); 43 | static INLINE2 void i_pop_ss(void); 44 | static INLINE2 void i_sbb_br8(void); 45 | static INLINE2 void i_sbb_wr16(void); 46 | static INLINE2 void i_sbb_r8b(void); 47 | static INLINE2 void i_sbb_r16w(void); 48 | static INLINE2 void i_sbb_ald8(void); 49 | static INLINE2 void i_sbb_axd16(void); 50 | static INLINE2 void i_push_ds(void); 51 | static INLINE2 void i_pop_ds(void); 52 | static INLINE2 void i_and_br8(void); 53 | static INLINE2 void i_and_r8b(void); 54 | static INLINE2 void i_and_wr16(void); 55 | static INLINE2 void i_and_r16w(void); 56 | static INLINE2 void i_and_ald8(void); 57 | static INLINE2 void i_and_axd16(void); 58 | static INLINE2 void i_es(void); 59 | static INLINE2 void i_daa(void); 60 | static INLINE2 void i_sub_br8(void); 61 | static INLINE2 void i_sub_wr16(void); 62 | static INLINE2 void i_sub_r8b(void); 63 | static INLINE2 void i_sub_r16w(void); 64 | static INLINE2 void i_sub_ald8(void); 65 | static INLINE2 void i_sub_axd16(void); 66 | static INLINE2 void i_cs(void); 67 | static INLINE2 void i_xor_br8(void); 68 | static INLINE2 void i_xor_r8b(void); 69 | static INLINE2 void i_xor_wr16(void); 70 | static INLINE2 void i_xor_r16w(void); 71 | static INLINE2 void i_xor_ald8(void); 72 | static INLINE2 void i_xor_axd16(void); 73 | static INLINE2 void i_ss(void); 74 | static INLINE2 void i_cmp_br8(void); 75 | static INLINE2 void i_cmp_wr16(void); 76 | static INLINE2 void i_cmp_r8b(void); 77 | static INLINE2 void i_cmp_r16w(void); 78 | static INLINE2 void i_cmp_ald8(void); 79 | static INLINE2 void i_cmp_axd16(void); 80 | static INLINE2 void i_ds(void); 81 | static INLINE2 void i_inc_ax(void); 82 | static INLINE2 void i_inc_cx(void); 83 | static INLINE2 void i_inc_dx(void); 84 | static INLINE2 void i_inc_bx(void); 85 | static INLINE2 void i_inc_sp(void); 86 | static INLINE2 void i_inc_bp(void); 87 | static INLINE2 void i_inc_si(void); 88 | static INLINE2 void i_inc_di(void); 89 | static INLINE2 void i_dec_ax(void); 90 | static INLINE2 void i_dec_cx(void); 91 | static INLINE2 void i_dec_dx(void); 92 | static INLINE2 void i_dec_bx(void); 93 | static INLINE2 void i_dec_sp(void); 94 | static INLINE2 void i_dec_bp(void); 95 | static INLINE2 void i_dec_si(void); 96 | static INLINE2 void i_dec_di(void); 97 | static INLINE2 void i_push_ax(void); 98 | static INLINE2 void i_push_cx(void); 99 | static INLINE2 void i_push_dx(void); 100 | static INLINE2 void i_push_bx(void); 101 | static INLINE2 void i_push_sp(void); 102 | static INLINE2 void i_push_bp(void); 103 | static INLINE2 void i_push_si(void); 104 | static INLINE2 void i_push_di(void); 105 | static INLINE2 void i_pop_ax(void); 106 | static INLINE2 void i_pop_cx(void); 107 | static INLINE2 void i_pop_dx(void); 108 | static INLINE2 void i_pop_bx(void); 109 | static INLINE2 void i_pop_sp(void); 110 | static INLINE2 void i_pop_bp(void); 111 | static INLINE2 void i_pop_si(void); 112 | static INLINE2 void i_pop_di(void); 113 | static INLINE2 void i_jo(void); 114 | static INLINE2 void i_jno(void); 115 | static INLINE2 void i_jb(void); 116 | static INLINE2 void i_jnb(void); 117 | static INLINE2 void i_jz(void); 118 | static INLINE2 void i_jnz(void); 119 | static INLINE2 void i_jbe(void); 120 | static INLINE2 void i_jnbe(void); 121 | static INLINE2 void i_js(void); 122 | static INLINE2 void i_jns(void); 123 | static INLINE2 void i_jp(void); 124 | static INLINE2 void i_jnp(void); 125 | static INLINE2 void i_jl(void); 126 | static INLINE2 void i_jnl(void); 127 | static INLINE2 void i_jle(void); 128 | static INLINE2 void i_jnle(void); 129 | static INLINE2 void i_80pre(void); 130 | static INLINE2 void i_81pre(void); 131 | static INLINE2 void i_83pre(void); 132 | static INLINE2 void i_test_br8(void); 133 | static INLINE2 void i_test_wr16(void); 134 | static INLINE2 void i_xchg_br8(void); 135 | static INLINE2 void i_xchg_wr16(void); 136 | static INLINE2 void i_mov_br8(void); 137 | static INLINE2 void i_mov_r8b(void); 138 | static INLINE2 void i_mov_wr16(void); 139 | static INLINE2 void i_mov_r16w(void); 140 | static INLINE2 void i_mov_wsreg(void); 141 | static INLINE2 void i_lea(void); 142 | static INLINE2 void i_mov_sregw(void); 143 | static INLINE2 void i_notdone(void); 144 | static INLINE2 void i_popw(void); 145 | static INLINE2 void i_nop(void); 146 | static INLINE2 void i_xchg_axcx(void); 147 | static INLINE2 void i_xchg_axdx(void); 148 | static INLINE2 void i_xchg_axbx(void); 149 | static INLINE2 void i_xchg_axsp(void); 150 | static INLINE2 void i_xchg_axbp(void); 151 | static INLINE2 void i_xchg_axsi(void); 152 | static INLINE2 void i_xchg_axdi(void); 153 | static INLINE2 void i_cbw(void); 154 | static INLINE2 void i_cwd(void); 155 | static INLINE2 void i_call_far(void); 156 | static INLINE2 void i_pushf(void); 157 | static INLINE2 void i_popf(void); 158 | static INLINE2 void i_sahf(void); 159 | static INLINE2 void i_lahf(void); 160 | static INLINE2 void i_mov_aldisp(void); 161 | static INLINE2 void i_mov_axdisp(void); 162 | static INLINE2 void i_mov_dispal(void); 163 | static INLINE2 void i_mov_dispax(void); 164 | static INLINE2 void i_movsb(void); 165 | static INLINE2 void i_movsw(void); 166 | static INLINE2 void i_cmpsb(void); 167 | static INLINE2 void i_cmpsw(void); 168 | static INLINE2 void i_test_ald8(void); 169 | static INLINE2 void i_test_axd16(void); 170 | static INLINE2 void i_stosb(void); 171 | static INLINE2 void i_stosw(void); 172 | static INLINE2 void i_lodsb(void); 173 | static INLINE2 void i_lodsw(void); 174 | static INLINE2 void i_scasb(void); 175 | static INLINE2 void i_scasw(void); 176 | static INLINE2 void i_mov_ald8(void); 177 | static INLINE2 void i_mov_cld8(void); 178 | static INLINE2 void i_mov_dld8(void); 179 | static INLINE2 void i_mov_bld8(void); 180 | static INLINE2 void i_mov_ahd8(void); 181 | static INLINE2 void i_mov_chd8(void); 182 | static INLINE2 void i_mov_dhd8(void); 183 | static INLINE2 void i_mov_bhd8(void); 184 | static INLINE2 void i_mov_axd16(void); 185 | static INLINE2 void i_mov_cxd16(void); 186 | static INLINE2 void i_mov_dxd16(void); 187 | static INLINE2 void i_mov_bxd16(void); 188 | static INLINE2 void i_mov_spd16(void); 189 | static INLINE2 void i_mov_bpd16(void); 190 | static INLINE2 void i_mov_sid16(void); 191 | static INLINE2 void i_mov_did16(void); 192 | static INLINE2 void i_ret_d16(void); 193 | static INLINE2 void i_ret(void); 194 | static INLINE2 void i_les_dw(void); 195 | static INLINE2 void i_lds_dw(void); 196 | static INLINE2 void i_mov_bd8(void); 197 | static INLINE2 void i_mov_wd16(void); 198 | static INLINE2 void i_retf_d16(void); 199 | static INLINE2 void i_retf(void); 200 | static INLINE2 void i_int3(void); 201 | static INLINE2 void i_int(void); 202 | static INLINE2 void i_into(void); 203 | static INLINE2 void i_iret(void); 204 | static INLINE2 void i_d0pre(void); 205 | static INLINE2 void i_d1pre(void); 206 | static INLINE2 void i_d2pre(void); 207 | static INLINE2 void i_d3pre(void); 208 | static INLINE2 void i_aam(void); 209 | static INLINE2 void i_aad(void); 210 | static INLINE2 void i_xlat(void); 211 | static INLINE2 void i_escape(void); 212 | static INLINE2 void i_loopne(void); 213 | static INLINE2 void i_loope(void); 214 | static INLINE2 void i_loop(void); 215 | static INLINE2 void i_jcxz(void); 216 | static INLINE2 void i_inal(void); 217 | static INLINE2 void i_inax(void); 218 | static INLINE2 void i_outal(void); 219 | static INLINE2 void i_outax(void); 220 | static INLINE2 void i_call_d16(void); 221 | static INLINE2 void i_jmp_d16(void); 222 | static INLINE2 void i_jmp_far(void); 223 | static INLINE2 void i_jmp_d8(void); 224 | static INLINE2 void i_inaldx(void); 225 | static INLINE2 void i_inaxdx(void); 226 | static INLINE2 void i_outdxal(void); 227 | static INLINE2 void i_outdxax(void); 228 | static INLINE2 void i_lock(void); 229 | static INLINE2 void i_repne(void); 230 | static INLINE2 void i_repe(void); 231 | static INLINE2 void i_hlt(void); 232 | static INLINE2 void i_cmc(void); 233 | static INLINE2 void i_f6pre(void); 234 | static INLINE2 void i_f7pre(void); 235 | static INLINE2 void i_clc(void); 236 | static INLINE2 void i_stc(void); 237 | static INLINE2 void i_cli(void); 238 | static INLINE2 void i_sti(void); 239 | static INLINE2 void i_cld(void); 240 | static INLINE2 void i_std(void); 241 | static INLINE2 void i_fepre(void); 242 | static INLINE2 void i_ffpre(void); 243 | 244 | static INLINE2 void i_wait(void); 245 | static INLINE2 void i_gobios(void); 246 | 247 | void (*instruction[256])(void) = 248 | { 249 | i_add_br8, /* 0x00 */ 250 | i_add_wr16, /* 0x01 */ 251 | i_add_r8b, /* 0x02 */ 252 | i_add_r16w, /* 0x03 */ 253 | i_add_ald8, /* 0x04 */ 254 | i_add_axd16, /* 0x05 */ 255 | i_push_es, /* 0x06 */ 256 | i_pop_es, /* 0x07 */ 257 | i_or_br8, /* 0x08 */ 258 | i_or_wr16, /* 0x09 */ 259 | i_or_r8b, /* 0x0a */ 260 | i_or_r16w, /* 0x0b */ 261 | i_or_ald8, /* 0x0c */ 262 | i_or_axd16, /* 0x0d */ 263 | i_push_cs, /* 0x0e */ 264 | i_notdone, 265 | i_adc_br8, /* 0x10 */ 266 | i_adc_wr16, /* 0x11 */ 267 | i_adc_r8b, /* 0x12 */ 268 | i_adc_r16w, /* 0x13 */ 269 | i_adc_ald8, /* 0x14 */ 270 | i_adc_axd16, /* 0x15 */ 271 | i_push_ss, /* 0x16 */ 272 | i_pop_ss, /* 0x17 */ 273 | i_sbb_br8, /* 0x18 */ 274 | i_sbb_wr16, /* 0x19 */ 275 | i_sbb_r8b, /* 0x1a */ 276 | i_sbb_r16w, /* 0x1b */ 277 | i_sbb_ald8, /* 0x1c */ 278 | i_sbb_axd16, /* 0x1d */ 279 | i_push_ds, /* 0x1e */ 280 | i_pop_ds, /* 0x1f */ 281 | i_and_br8, /* 0x20 */ 282 | i_and_wr16, /* 0x21 */ 283 | i_and_r8b, /* 0x22 */ 284 | i_and_r16w, /* 0x23 */ 285 | i_and_ald8, /* 0x24 */ 286 | i_and_axd16, /* 0x25 */ 287 | i_es, /* 0x26 */ 288 | i_daa, /* 0x27 */ 289 | i_sub_br8, /* 0x28 */ 290 | i_sub_wr16, /* 0x29 */ 291 | i_sub_r8b, /* 0x2a */ 292 | i_sub_r16w, /* 0x2b */ 293 | i_sub_ald8, /* 0x2c */ 294 | i_sub_axd16, /* 0x2d */ 295 | i_cs, /* 0x2e */ 296 | i_notdone, 297 | i_xor_br8, /* 0x30 */ 298 | i_xor_wr16, /* 0x31 */ 299 | i_xor_r8b, /* 0x32 */ 300 | i_xor_r16w, /* 0x33 */ 301 | i_xor_ald8, /* 0x34 */ 302 | i_xor_axd16, /* 0x35 */ 303 | i_ss, /* 0x36 */ 304 | i_notdone, 305 | i_cmp_br8, /* 0x38 */ 306 | i_cmp_wr16, /* 0x39 */ 307 | i_cmp_r8b, /* 0x3a */ 308 | i_cmp_r16w, /* 0x3b */ 309 | i_cmp_ald8, /* 0x3c */ 310 | i_cmp_axd16, /* 0x3d */ 311 | i_ds, /* 0x3e */ 312 | i_notdone, 313 | i_inc_ax, /* 0x40 */ 314 | i_inc_cx, /* 0x41 */ 315 | i_inc_dx, /* 0x42 */ 316 | i_inc_bx, /* 0x43 */ 317 | i_inc_sp, /* 0x44 */ 318 | i_inc_bp, /* 0x45 */ 319 | i_inc_si, /* 0x46 */ 320 | i_inc_di, /* 0x47 */ 321 | i_dec_ax, /* 0x48 */ 322 | i_dec_cx, /* 0x49 */ 323 | i_dec_dx, /* 0x4a */ 324 | i_dec_bx, /* 0x4b */ 325 | i_dec_sp, /* 0x4c */ 326 | i_dec_bp, /* 0x4d */ 327 | i_dec_si, /* 0x4e */ 328 | i_dec_di, /* 0x4f */ 329 | i_push_ax, /* 0x50 */ 330 | i_push_cx, /* 0x51 */ 331 | i_push_dx, /* 0x52 */ 332 | i_push_bx, /* 0x53 */ 333 | i_push_sp, /* 0x54 */ 334 | i_push_bp, /* 0x55 */ 335 | i_push_si, /* 0x56 */ 336 | i_push_di, /* 0x57 */ 337 | i_pop_ax, /* 0x58 */ 338 | i_pop_cx, /* 0x59 */ 339 | i_pop_dx, /* 0x5a */ 340 | i_pop_bx, /* 0x5b */ 341 | i_pop_sp, /* 0x5c */ 342 | i_pop_bp, /* 0x5d */ 343 | i_pop_si, /* 0x5e */ 344 | i_pop_di, /* 0x5f */ 345 | i_notdone, 346 | i_notdone, 347 | i_notdone, 348 | i_notdone, 349 | i_notdone, 350 | i_notdone, 351 | i_notdone, 352 | i_notdone, 353 | i_notdone, 354 | i_notdone, 355 | i_notdone, 356 | i_notdone, 357 | i_notdone, 358 | i_notdone, 359 | i_notdone, 360 | i_notdone, 361 | i_jo, /* 0x70 */ 362 | i_jno, /* 0x71 */ 363 | i_jb, /* 0x72 */ 364 | i_jnb, /* 0x73 */ 365 | i_jz, /* 0x74 */ 366 | i_jnz, /* 0x75 */ 367 | i_jbe, /* 0x76 */ 368 | i_jnbe, /* 0x77 */ 369 | i_js, /* 0x78 */ 370 | i_jns, /* 0x79 */ 371 | i_jp, /* 0x7a */ 372 | i_jnp, /* 0x7b */ 373 | i_jl, /* 0x7c */ 374 | i_jnl, /* 0x7d */ 375 | i_jle, /* 0x7e */ 376 | i_jnle, /* 0x7f */ 377 | i_80pre, /* 0x80 */ 378 | i_81pre, /* 0x81 */ 379 | i_notdone, 380 | i_83pre, /* 0x83 */ 381 | i_test_br8, /* 0x84 */ 382 | i_test_wr16, /* 0x85 */ 383 | i_xchg_br8, /* 0x86 */ 384 | i_xchg_wr16, /* 0x87 */ 385 | i_mov_br8, /* 0x88 */ 386 | i_mov_wr16, /* 0x89 */ 387 | i_mov_r8b, /* 0x8a */ 388 | i_mov_r16w, /* 0x8b */ 389 | i_mov_wsreg, /* 0x8c */ 390 | i_lea, /* 0x8d */ 391 | i_mov_sregw, /* 0x8e */ 392 | i_popw, /* 0x8f */ 393 | i_nop, /* 0x90 */ 394 | i_xchg_axcx, /* 0x91 */ 395 | i_xchg_axdx, /* 0x92 */ 396 | i_xchg_axbx, /* 0x93 */ 397 | i_xchg_axsp, /* 0x94 */ 398 | i_xchg_axbp, /* 0x95 */ 399 | i_xchg_axsi, /* 0x97 */ 400 | i_xchg_axdi, /* 0x97 */ 401 | i_cbw, /* 0x98 */ 402 | i_cwd, /* 0x99 */ 403 | i_call_far, /* 0x9a */ 404 | i_wait, /* 0x9b */ 405 | i_pushf, /* 0x9c */ 406 | i_popf, /* 0x9d */ 407 | i_sahf, /* 0x9e */ 408 | i_lahf, /* 0x9f */ 409 | i_mov_aldisp, /* 0xa0 */ 410 | i_mov_axdisp, /* 0xa1 */ 411 | i_mov_dispal, /* 0xa2 */ 412 | i_mov_dispax, /* 0xa3 */ 413 | i_movsb, /* 0xa4 */ 414 | i_movsw, /* 0xa5 */ 415 | i_cmpsb, /* 0xa6 */ 416 | i_cmpsw, /* 0xa7 */ 417 | i_test_ald8, /* 0xa8 */ 418 | i_test_axd16, /* 0xa9 */ 419 | i_stosb, /* 0xaa */ 420 | i_stosw, /* 0xab */ 421 | i_lodsb, /* 0xac */ 422 | i_lodsw, /* 0xad */ 423 | i_scasb, /* 0xae */ 424 | i_scasw, /* 0xaf */ 425 | i_mov_ald8, /* 0xb0 */ 426 | i_mov_cld8, /* 0xb1 */ 427 | i_mov_dld8, /* 0xb2 */ 428 | i_mov_bld8, /* 0xb3 */ 429 | i_mov_ahd8, /* 0xb4 */ 430 | i_mov_chd8, /* 0xb5 */ 431 | i_mov_dhd8, /* 0xb6 */ 432 | i_mov_bhd8, /* 0xb7 */ 433 | i_mov_axd16, /* 0xb8 */ 434 | i_mov_cxd16, /* 0xb9 */ 435 | i_mov_dxd16, /* 0xba */ 436 | i_mov_bxd16, /* 0xbb */ 437 | i_mov_spd16, /* 0xbc */ 438 | i_mov_bpd16, /* 0xbd */ 439 | i_mov_sid16, /* 0xbe */ 440 | i_mov_did16, /* 0xbf */ 441 | i_notdone, 442 | i_notdone, 443 | i_ret_d16, /* 0xc2 */ 444 | i_ret, /* 0xc3 */ 445 | i_les_dw, /* 0xc4 */ 446 | i_lds_dw, /* 0xc5 */ 447 | i_mov_bd8, /* 0xc6 */ 448 | i_mov_wd16, /* 0xc7 */ 449 | i_notdone, 450 | i_notdone, 451 | i_retf_d16, /* 0xca */ 452 | i_retf, /* 0xcb */ 453 | i_int3, /* 0xcc */ 454 | i_int, /* 0xcd */ 455 | i_into, /* 0xce */ 456 | i_iret, /* 0xcf */ 457 | i_d0pre, /* 0xd0 */ 458 | i_d1pre, /* 0xd1 */ 459 | i_d2pre, /* 0xd2 */ 460 | i_d3pre, /* 0xd3 */ 461 | i_aam, /* 0xd4 */ 462 | i_aad, /* 0xd5 */ 463 | i_notdone, 464 | i_xlat, /* 0xd7 */ 465 | i_escape, /* 0xd8 */ 466 | i_escape, /* 0xd9 */ 467 | i_escape, /* 0xda */ 468 | i_escape, /* 0xdb */ 469 | i_escape, /* 0xdc */ 470 | i_escape, /* 0xdd */ 471 | i_escape, /* 0xde */ 472 | i_escape, /* 0xdf */ 473 | i_loopne, /* 0xe0 */ 474 | i_loope, /* 0xe1 */ 475 | i_loop, /* 0xe2 */ 476 | i_jcxz, /* 0xe3 */ 477 | i_inal, /* 0xe4 */ 478 | i_inax, /* 0xe5 */ 479 | i_outal, /* 0xe6 */ 480 | i_outax, /* 0xe7 */ 481 | i_call_d16, /* 0xe8 */ 482 | i_jmp_d16, /* 0xe9 */ 483 | i_jmp_far, /* 0xea */ 484 | i_jmp_d8, /* 0xeb */ 485 | i_inaldx, /* 0xec */ 486 | i_inaxdx, /* 0xed */ 487 | i_outdxal, /* 0xee */ 488 | i_outdxax, /* 0xef */ 489 | i_lock, /* 0xf0 */ 490 | i_gobios, /* 0xf1 */ 491 | i_repne, /* 0xf2 */ 492 | i_repe, /* 0xf3 */ 493 | i_hlt, /* 0xf4 */ 494 | i_cmc, /* 0xf5 */ 495 | i_f6pre, /* 0xf6 */ 496 | i_f7pre, /* 0xf7 */ 497 | i_clc, /* 0xf8 */ 498 | i_stc, /* 0xf9 */ 499 | i_cli, /* 0xfa */ 500 | i_sti, /* 0xfb */ 501 | i_cld, /* 0xfc */ 502 | i_std, /* 0xfd */ 503 | i_fepre, /* 0xfe */ 504 | i_ffpre /* 0xff */ 505 | }; 506 | 507 | #endif 508 | -------------------------------------------------------------------------------- /keytabs.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | BYTE scan_unshifted[256] = 16 | { 17 | 0 ,0x1b, '1', '2', '3', '4', '5', '6', 18 | '7', '8', '9', '0', '-', '=',0x08,0x09, 19 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 20 | 'o', 'p', '[', ']',0x0d, 0 , 'a', 's', 21 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 22 | '\'','`', 0 , 23 | #ifdef KBUK /* Keycode 0x2b */ 24 | '#', 25 | #else 26 | '\\', 27 | #endif 28 | 'z', 'x', 'c', 'v', 29 | 'b', 'n', 'm', ',', '.', '/', 0 , '*', 30 | 0 , ' ', 0 , 0 , 0 , 0 , 0 , 0 , 31 | 0 , 0 , 0 , 0 , 0 , 0 , 0 , '7', 32 | '8', '9', '-', '4', '5', '6', '+', '1', 33 | '2', '3', '0', '.', 0 , 0 , '\\' 34 | }; 35 | 36 | 37 | BYTE scan_shift[256] = 38 | { 39 | 0 ,0x1b, '!', 40 | #ifdef KBUK /* Keycode 0x03 and 0x04 + shift */ 41 | '"',0x9c, 42 | #else 43 | '@','#', 44 | #endif 45 | '$', '%', '^', 46 | '&', '*', '(', ')', '_', '+',0x08, 0 , 47 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 48 | 'O', 'P', '{', '}',0x0d, 0 , 'A', 'S', 49 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 50 | #ifdef KBUK /* Keycode 0x28 and 0x29 + shift */ 51 | '@',0xaa, 52 | #else 53 | '"','~', 54 | #endif 55 | 0 , 56 | #ifdef KBUK 57 | '~', 58 | #else 59 | '|', 60 | #endif 61 | 'Z', 'X', 'C', 'V', 62 | 'B', 'N', 'M', '<', '>', '?', '/', '*', 63 | 0 , ' ', 0 , 0 , 0 , 0 , 0 , 0 , 64 | 0 , 0 , 0 , 0 , 0 , 0 , 0 ,'7', 65 | '8', '9', '-', '4', '5', '6', '+', '1', 66 | '2', '3', '0', '.', 0 , 0 , '|' 67 | }; 68 | 69 | 70 | BYTE scan_alt[256] = 71 | { 72 | 0x00,0x01,0x78,0x79,0x7a,0x7b,0x7c,0x7d, 73 | 0x7e,0x7f,0x80,0x81,0x82,0x83,0x0e,0xa5, 74 | 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, 75 | 0x18,0x19,0x1a,0x1b,0x1c,0x00,0x1e,0x1f, 76 | 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, 77 | 0x28,0x29,0x00,0x2b,0x2c,0x2d,0x2e,0x2f, 78 | 0x30,0x31,0x32,0x33,0x34,0x35,0xa4,0x37, 79 | 0x00,0x39,0x00,0x68,0x69,0x6a,0x6b,0x6c, 80 | 0x6d,0x6e,0x6f,0x70,0x71,0x00,0x00,0x97, 81 | 0x98,0x99,0x4a,0x9b,0x4c,0x9d,0x4e,0x9f, 82 | 0xa0,0xa1,0xa2,0xa3 83 | }; 84 | 85 | 86 | BYTE scan_ctrl[256] = 87 | { 88 | 0 ,0x1b, 0 , 0 , 0 , 0 , 0 ,0x1e, 89 | 0 , 0 , 0 , 0 ,0x1f, 0 ,0x7f, 0 , 90 | 17 , 23 , 5 , 18 , 20 , 25 , 21 , 9 , 91 | 15 , 16 ,0x1b,0x1d,0x0a, 0 , 1 , 19 , 92 | 4 , 6 , 7 , 8 , 10 , 11 , 12 , 0 , 93 | 0 ,0x1c, 0 , 0 , 26 , 24 , 3 , 22 , 94 | 2 , 14 , 13 95 | }; 96 | 97 | BYTE scan_ctrl_high[] = 98 | { 99 | 0x95, 0x96, 0, 0, 0, 0x5e, 0x5f, 0x60, 0x61, 0x62, 100 | 0x63, 0x64, 0x65, 0x66, 0x67, 0, 0, 0x77, 0x8d, 0x84, 101 | 0x8e, 0x73, 0x8f, 0x74, 0x90, 0x75, 0x91, 0x76, 0x92, 0x93, 102 | 0, 0, 0, 0x89, 0x8a 103 | }; 104 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is MAIN.C This is where everything begins... */ 16 | 17 | 18 | #include "global.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "bios.h" 26 | #include "vga.h" 27 | #include "video.h" 28 | #include "hardware.h" 29 | #include "vgahard.h" 30 | 31 | BYTE *memory; 32 | char *progname; 33 | 34 | void exit_emu(void) 35 | { 36 | disable(); 37 | bios_off(); 38 | vga_off(); 39 | exit(0); 40 | } 41 | 42 | int main(int argc, char **argv) 43 | { 44 | progname = (progname = strrchr(argv[0],'/')) ? progname : argv[0]; 45 | 46 | #ifndef BOOT 47 | FILE *f1; 48 | if (argc != 2) 49 | { 50 | fprintf(stderr,"Format: %s testfile\n",progname); 51 | exit(1); 52 | } 53 | #endif 54 | if (!(memory = (BYTE *)malloc(MEMORY_SIZE))) 55 | { 56 | fprintf(stderr,"Insufficient available memory\n"); 57 | exit(1); 58 | } 59 | #ifdef BOOT 60 | memset(memory,0, MEMORY_SIZE); 61 | #else 62 | if (!(f1 = fopen(argv[1],"rb"))) 63 | { 64 | fprintf(stderr,"Cannot open test file\n"); 65 | exit(1); 66 | } 67 | 68 | 69 | fread(memory+0x800,1,MEMORY_SIZE-0x800,f1); 70 | fclose(f1); 71 | #endif 72 | 73 | read_pcemurc(); 74 | disable(); 75 | 76 | init_video(); 77 | init_cpu(); 78 | init_bios(); 79 | init_vga(); 80 | init_timer(); 81 | 82 | enable(); 83 | 84 | execute(); 85 | 86 | /* NOT REACHED */ 87 | return 0; 88 | } 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /mfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | adapted from dos.h in the mach dos emulator for the linux dosemu dos 3 | emulator. 4 | Andrew.Tridgell@anu.edu.au 30th March 1993 5 | */ 6 | 7 | 8 | /* ### Added by DH ### */ 9 | #ifndef DOSEMU 10 | # define DOSEMU 11 | #endif 12 | 13 | #include /* for SEEK_END */ 14 | 15 | /* ### End of addition ### */ 16 | 17 | #ifdef DOSEMU 18 | /* definitions to make mach emu code compatible with dosemu */ 19 | 20 | /* ### Commented out by DH ### 21 | * #include "emu.h" 22 | */ 23 | 24 | 25 | #ifndef SOLARIS 26 | typedef unsigned char boolean_t; 27 | #endif 28 | 29 | /* ### Commented out by DH ### 30 | * #define d_namlen d_reclen 31 | */ 32 | 33 | #ifndef MAX_DRIVE 34 | #define MAX_DRIVE 26 35 | #endif 36 | 37 | #define USE_DF_AND_AFS_STUFF 38 | 39 | /* ### Commented out by DH ### 40 | * #define VOLUMELABEL "Linux" 41 | * #define LINUX_RESOURCE "\\\\LINUX\\FS" 42 | */ 43 | 44 | /* ### Added by DH ### */ 45 | 46 | #include "mfs_link.h" 47 | 48 | #if !defined(__hpux) && !defined(SOLARIS) && !defined(SGI) && !defined(RS6000) && 0 49 | #define strerror(x) sys_errlist[x] 50 | #endif 51 | 52 | #ifdef RS6000 53 | #define strerror(x) mstrerror(x) 54 | #endif 55 | 56 | #define VOLUMELABEL "PCEmu" 57 | #define LINUX_RESOURCE "\\\\PCEMU\\FS" 58 | 59 | #define Write2Bytes(d,x) (*(BYTE *)(d) = (x) & 0xff, \ 60 | *((BYTE *)(d)+1) = ((x) >> 8) & 0xff) 61 | #define Write4Bytes(d,x) (*(BYTE *)(d) = (x) & 0xff, \ 62 | *((BYTE *)(d)+1) = ((x) >> 8) & 0xff, \ 63 | *((BYTE *)(d)+2) = ((x) >> 16) & 0xff, \ 64 | *((BYTE *)(d)+3) = ((x) >> 24) & 0xff) 65 | 66 | #define Read2Bytes(t,x) (t)(*(BYTE *)(x) + (*((BYTE *)(x) + 1) << 8)) 67 | #define Read4Bytes(t,x) (t)(*(BYTE *)(x) + ((UINT32)*((BYTE *)(x) + 1) << 8) + \ 68 | ((UINT32)*((BYTE *)(x) + 2) << 16) + \ 69 | ((UINT32)*((BYTE *)(x) + 3) << 24)) 70 | 71 | /* ### End of addition ### */ 72 | 73 | /* ### Added by DH ### */ 74 | #ifndef FALSE 75 | #define FALSE 0 76 | #endif 77 | #ifndef TRUE 78 | #define TRUE 1 79 | #endif 80 | /* ### End of addition ### */ 81 | 82 | /* ### Commented out by DH 83 | * #define FALSE 0 84 | * #define TRUE 1 85 | */ 86 | 87 | #define UNCHANGED 2 88 | #define REDIRECT 3 89 | 90 | #define us_debug_level 10 91 | #define Debug_Level_0 0 92 | #define dbg_fd stderr 93 | 94 | /* Some compilers cannot handle variable argument #defines 95 | #define d_Stub(arg1, s, a...) d_printf("MFS: "s, ##a) 96 | #define Debug0(args) d_Stub args 97 | #define Debug1(args) d_Stub args 98 | */ 99 | 100 | #define Debug0(args) 101 | #define Debug1(args) 102 | 103 | typedef struct vm86_regs state_t; 104 | 105 | #define uesp esp 106 | 107 | /* ### Added '(&memory[ ... ])' to line below ### */ 108 | #define Addr_8086(x,y) (&memory[(( ((x) & 0xffff) << 4) + ((y) & 0xffff))]) 109 | #define Addr(s,x,y) Addr_8086(((s)->x), ((s)->y)) 110 | #define MASK8(x) ((x) & 0xff) 111 | #define MASK16(x) ((x) & 0xffff) 112 | #define HIGH(x) MASK8((UINT32)(x) >> 8) 113 | #define LOW(x) MASK8((UINT32)(x)) 114 | #undef WORD 115 | #define WORD(x) MASK16((UINT32)(x)) 116 | #define SETHIGH(x,y) (*(x) = (*(x) & ~0xff00) | ((MASK8(y))<<8)) 117 | #define SETLOW(x,y) (*(x) = (*(x) & ~0xff) | (MASK8(y))) 118 | #define SETWORD(x,y) (*(x) = (*(x) & ~0xffff) | (MASK16(y))) 119 | #endif 120 | 121 | /* 122 | * Copyright (c) 1991 Carnegie Mellon University 123 | * All Rights Reserved. 124 | * 125 | * Permission to use, copy, modify and distribute this software and its 126 | * documentation is hereby granted, provided that both the copyright 127 | * notice and this permission notice appear in all copies of the 128 | * software, derivative works or modified versions, and any portions 129 | * thereof, and that both notices appear in supporting documentation. 130 | * 131 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 132 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 133 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 134 | * 135 | * Carnegie Mellon requests users of this software to return to 136 | * 137 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 138 | * School of Computer Science 139 | * Carnegie Mellon University 140 | * Pittsburgh PA 15213-3890 141 | * 142 | * any improvements or extensions that they make and grant Carnegie Mellon 143 | * the rights to redistribute these changes. 144 | */ 145 | /* 146 | * 147 | * Purpose: 148 | * V86 DOS disk emulation header file 149 | * 150 | * HISTORY: 151 | * $Log$ 152 | * Revision 1.1 2001/01/22 01:35:32 michaelh 153 | * Initial revision 154 | * 155 | * Revision 1.1.1.1 2000/12/12 06:08:44 michaelh 156 | * Created. 157 | * 158 | * Revision 1.6 1994/01/25 20:02:44 root 159 | * Exchange stderr <-> stdout. 160 | * 161 | * Revision 1.5 1994/01/20 21:14:24 root 162 | * Indent. 163 | * 164 | * Revision 1.4 1994/01/19 17:51:14 root 165 | * Added CDS_FLAG_NOTNET = 0x80 for mfs.c 166 | * 167 | * Revision 1.3 1993/12/22 11:45:36 root 168 | * Fixes for ftruncate 169 | * 170 | * Revision 1.2 1993/11/17 22:29:33 root 171 | * *** empty log message *** 172 | * 173 | * Revision 1.1 1993/11/12 12:32:17 root 174 | * Initial revision 175 | * 176 | * Revision 1.1 1993/07/07 00:49:06 root 177 | * Initial revision 178 | * 179 | * Revision 1.3 1993/05/04 05:29:22 root 180 | * added console switching, new parse commands, and serial emulation 181 | * 182 | * Revision 1.2 1993/04/07 21:04:26 root 183 | * big move 184 | * 185 | * Revision 1.1 1993/04/05 17:25:13 root 186 | * Initial revision 187 | * 188 | * Revision 2.3 91/12/06 15:29:23 grm 189 | * Redefined sda_cur_psp, and added psp_parent_psp. The 190 | * psp_parent_psp was used to find out what the psp of the parent of 191 | * the command.com program was. It seems that it is undefined. 192 | * [91/12/06 grm] 193 | * 194 | * Revision 2.2 91/12/05 16:42:08 grm 195 | * Added sft_rel and _abs_cluster macros. Used to debug the 196 | * MS-Write network drive problem. 197 | * [91/12/04 grm] 198 | * Added constants for Dos 4+ 199 | * [91/07/16 17:47:20 grm] 200 | * 201 | * Changed to allow for usage with Dos v4.01 and 5.00. 202 | * [91/06/28 18:53:42 grm] 203 | * 204 | * New Copyright 205 | * [91/05/28 15:12:28 grm] 206 | * 207 | * Added structures for the dos_general routines. 208 | * [91/04/30 13:43:58 grm] 209 | * 210 | * Structures and macros for the dos_fs.c 211 | * network redirector interface. 212 | * [91/04/30 13:36:42 grm] 213 | * 214 | * Name changed from dos_general.h to dos.h. 215 | * Added external declarations for dos_foo.c files. 216 | * [91/03/01 14:40:55 grm] 217 | * 218 | * Type works. Interrim changes. 219 | * [91/02/11 18:22:47 grm] 220 | * 221 | * Fancy dir. 222 | * [91/02/06 16:59:01 grm] 223 | * 224 | * Created. 225 | * [91/02/06 14:29:39 grm] 226 | * 227 | */ 228 | 229 | #include 230 | 231 | /* 232 | * Dos error codes 233 | */ 234 | /* MS-DOS version 2 error codes */ 235 | #define FUNC_NUM_IVALID 0x01 236 | #define FILE_NOT_FOUND 0x02 237 | #define PATH_NOT_FOUND 0x03 238 | #define TOO_MANY_OPEN_FILES 0x04 239 | #define ACCESS_DENIED 0x05 240 | #define HANDLE_INVALID 0x06 241 | #define MEM_CB_DEST 0x07 242 | #define INSUF_MEM 0x08 243 | #define MEM_BLK_ADDR_IVALID 0x09 244 | #define ENV_INVALID 0x0a 245 | #define FORMAT_INVALID 0x0b 246 | #define ACCESS_CODE_INVALID 0x0c 247 | #define DATA_INVALID 0x0d 248 | #define UNKNOWN_UNIT 0x0e 249 | #define DISK_DRIVE_INVALID 0x0f 250 | #define ATT_REM_CUR_DIR 0x10 251 | #define NOT_SAME_DEV 0x11 252 | #define NO_MORE_FILES 0x12 253 | /* mappings to critical-error codes */ 254 | #define WRITE_PROT_DISK 0x13 255 | #define UNKNOWN_UNIT_CERR 0x14 256 | #define DRIVE_NOT_READY 0x15 257 | #define UNKNOWN_COMMAND 0x16 258 | #define DATA_ERROR_CRC 0x17 259 | #define BAD_REQ_STRUCT_LEN 0x18 260 | #define SEEK_ERROR 0x19 261 | #define UNKNOWN_MEDIA_TYPE 0x1a 262 | #define SECTOR_NOT_FOUND 0x1b 263 | #define PRINTER_OUT_OF_PAPER 0x1c 264 | #define WRITE_FAULT 0x1d 265 | #define READ_FAULT 0x1e 266 | #define GENERAL_FAILURE 0x1f 267 | 268 | /* MS-DOS version 3 and later extended error codes */ 269 | #define SHARING_VIOLATION 0x20 270 | #define FILE_LOCK_VIOLATION 0x21 271 | #define DISK_CHANGE_INVALID 0x22 272 | #define FCB_UNAVAILABLE 0x23 273 | #define SHARING_BUF_EXCEEDED 0x24 274 | 275 | #define NETWORK_NAME_NOT_FOUND 0x35 276 | 277 | #define FILE_ALREADY_EXISTS 0x50 278 | 279 | #define DUPLICATE_REDIR 0x55 280 | 281 | struct dir_ent { 282 | char name[8]; /* dos name and ext */ 283 | char ext[3]; 284 | u_short mode; /* unix st_mode value */ 285 | long size; /* size of file */ 286 | time_t time; /* st_mtime */ 287 | struct dir_ent *next; 288 | }; 289 | 290 | struct dos_name { 291 | char name[8]; 292 | char ext[3]; 293 | }; 294 | 295 | typedef struct far_record { 296 | u_short offset; 297 | u_short segment; 298 | } far_t; 299 | 300 | #define DOSVER_31_33 1 301 | #define DOSVER_41 2 302 | #define DOSVER_50 3 303 | #define DOSVER_60 4 304 | 305 | typedef u_char *sdb_t; 306 | 307 | /* ### Changed all *(u_short *)... to Read2Bytes(u_short,...) ### */ 308 | /* ### Changed all *(u_long *)... to Read4Bytes(u_long,...) ### */ 309 | #define sdb_drive_letter(sdb) (*(u_char *)&sdb[sdb_drive_letter_off]) 310 | #define sdb_template_name(sdb) ((char *)&sdb[sdb_template_name_off]) 311 | #define sdb_template_ext(sdb) ((char *)&sdb[sdb_template_ext_off]) 312 | #define sdb_attribute(sdb) (*(u_char *)&sdb[sdb_attribute_off]) 313 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 314 | #define sdb_dir_entry_r(sdb) (Read2Bytes(u_short,&sdb[sdb_dir_entry_off])) 315 | #define sdb_dir_entry_w(sdb,x) (Write2Bytes(&sdb[sdb_dir_entry_off], x)) 316 | #define sdb_p_cluster(sdb) (Read2Bytes(u_short,&sdb[sdb_p_cluster_off])) 317 | #define sdb_file_name(sdb) ((char *)&sdb[sdb_file_name_off]) 318 | #define sdb_file_ext(sdb) ((char *)&sdb[sdb_file_ext_off]) 319 | #define sdb_file_attr(sdb) (*(u_char *)&sdb[sdb_file_attr_off]) 320 | #define sdb_file_time(sdb) (*(u_short *)&sdb[sdb_file_time_off]) 321 | #define sdb_file_date(sdb) (*(u_short *)&sdb[sdb_file_date_off]) 322 | #define sdb_file_st_cluster(sdb)(Read2Bytes(u_short,&sdb[sdb_file_st_cluster_off])) 323 | #define sdb_file_size(sdb,x) (Write4Bytes(&sdb[sdb_file_size_off],x)) 324 | 325 | typedef u_char *sft_t; 326 | 327 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 328 | #define sft_handle_cnt_r(sft) (Read2Bytes(u_short,&sft[sft_handle_cnt_off])) 329 | #define sft_handle_cnt_w(sft,x) (Write2Bytes(&sft[sft_handle_cnt_off], x)) 330 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 331 | #define sft_open_mode_r(sft) (Read2Bytes(u_short,&sft[sft_open_mode_off])) 332 | #define sft_open_mode_w(sft,x) (Write2Bytes(&sft[sft_open_mode_off],x)) 333 | #define sft_attribute_byte(sft) (*(u_char *)&sft[sft_attribute_byte_off]) 334 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 335 | #define sft_device_info_r(sft) (Read2Bytes(u_short,&sft[sft_device_info_off])) 336 | #define sft_device_info_w(sft,x) (Write2Bytes(&sft[sft_device_info_off], x)) 337 | #define sft_dev_drive_ptr(sft,x) (Write4Bytes(&sft[sft_dev_drive_ptr_off], x)) 338 | #define sft_start_cluster(sft) (Read2Bytes(u_short,&sft[sft_start_cluster_off])) 339 | #define sft_time(sft) (*(u_short *)&sft[sft_time_off]) 340 | #define sft_date(sft) (*(u_short *)&sft[sft_date_off]) 341 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 342 | #define sft_size_r(sft) (Read4Bytes(u_long,&sft[sft_size_off])) 343 | #define sft_size_w(sft, x) (Write4Bytes(&sft[sft_size_off], x)) 344 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 345 | #define sft_position_r(sft) (Read4Bytes(u_long,&sft[sft_position_off])) 346 | #define sft_position_w(sft,x) (Write4Bytes(&sft[sft_position_off],x)) 347 | #define sft_rel_cluster(sft) (Read2Bytes(u_short,&sft[sft_rel_cluster_off])) 348 | #define sft_abs_cluster(sft,x) (Write2Bytes(&sft[sft_abs_cluster_off], x)) 349 | #define sft_directory_sector(sft,x) (Write2Bytes(&sft[sft_directory_sector_off],x)) 350 | #define sft_directory_entry(sft) (*(u_char *)&sft[sft_directory_entry_off]) 351 | #define sft_name(sft) ( (char *)&sft[sft_name_off]) 352 | #define sft_ext(sft) ( (char *)&sft[sft_ext_off]) 353 | 354 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 355 | #define sft_fd_r(sft) (Read2Bytes(u_short,&sft[sft_fd_off])) 356 | #define sft_fd_w(sft,x) (Write2Bytes(&sft[sft_fd_off], x)) 357 | 358 | typedef u_char *cds_t; 359 | 360 | #define cds_current_path(cds) ((char *)&cds[cds_current_path_off]) 361 | /* ### Split next definition into read (..._r) and write (..._w) ### */ 362 | #define cds_flags_r(cds) (Read2Bytes(u_short,&cds[cds_flags_off])) 363 | #define cds_flags_w(cds,x) (Write2Bytes(&cds[cds_flags_off], x)) 364 | #define cds_DBP_pointer(cds) (Read4Bytes(u_long,&cds[cds_DBP_pointer_off])) 365 | #define cds_cur_cluster(cds,x) (Write2Bytes(&cds[cds_cur_cluster_off],x)) 366 | /* ### Split next difinition into read (..._r) and write (..._w) ### */ 367 | #define cds_rootlen_r(cds) (Read2Bytes(u_short,&cds[cds_rootlen_off])) 368 | #define cds_rootlen_w(cds,x) (Write2Bytes(&cds[cds_rootlen_off], x)) 369 | #define drive_cds(dd) ((cds_t)(((long)cds_base)+(cds_record_size*(dd)))) 370 | 371 | #define CDS_FLAG_REMOTE 0x8000 372 | #define CDS_FLAG_READY 0x4000 373 | #define CDS_FLAG_NOTNET 0x0080 374 | #define CDS_FLAG_SUBST 0x1000 375 | #define CDS_DEFAULT_ROOT_LEN 2 376 | 377 | #define FAR(x) (Addr_8086(x.segment, x.offset)) 378 | 379 | /* ### Commented out by DH ### 380 | * #define FARPTR(x) (Addr_8086((x)->segment, (x)->offset)) 381 | */ 382 | 383 | /* ### Added by DH ### */ 384 | #define FARPTR(x) &memory[Read2Bytes(u_short, (x)) + \ 385 | (Read2Bytes(u_short, (BYTE *)(x)+2) << 4)] 386 | /* ### End of addition ### */ 387 | 388 | typedef u_short *psp_t; 389 | 390 | #define PSPPTR(x) (Addr_8086(x, 0)) 391 | 392 | typedef u_char *sda_t; 393 | 394 | #define sda_current_dta(sda) ((char *)(FARPTR((far_t *)&sda[sda_current_dta_off]))) 395 | #define sda_cur_psp(sda) (Read2Bytes(u_short,&sda[sda_cur_psp_off])) 396 | #define sda_filename1(sda) ((char *)&sda[sda_filename1_off]) 397 | #define sda_filename2(sda) ((char *)&sda[sda_filename2_off]) 398 | #define sda_sdb(sda) ((sdb_t )&sda[sda_sdb_off]) 399 | #define sda_cds(sda) ((cds_t)(FARPTR((far_t *)&sda[sda_cds_off]))) 400 | #define sda_search_attribute(sda) (*(u_char *)&sda[sda_search_attribute_off]) 401 | #define sda_open_mode(sda) (*(u_char *)&sda[sda_open_mode_off]) 402 | #define sda_rename_source(sda) ((sdb_t )&sda[sda_rename_source_off]) 403 | #define sda_user_stack(sda) ((char *)(FARPTR((far_t *)&sda[sda_user_stack_off]))) 404 | 405 | /* 406 | * Data for extended open/create operations, DOS 4 or greater: 407 | */ 408 | #define sda_ext_act(sda) (Read2Bytes(u_short,&sda[sda_ext_act_off])) 409 | #define sda_ext_attr(sda) (Read2Bytes(u_short,&sda[sda_ext_attr_off])) 410 | #define sda_ext_mode(sda) (Read2Bytes(u_short,&sda[sda_ext_mode_off])) 411 | 412 | #define psp_parent_psp(psp) (Read2Bytes(u_short,&psp[0x16])) 413 | #define psp_handles(psp) ((char *)(FARPTR((far_t *)&psp[0x34]))) 414 | 415 | #define lol_cdsfarptr(lol) (Read4Bytes(u_long,&lol[lol_cdsfarptr_off])) 416 | #define lol_last_drive(lol) (*(u_char *)&lol[lol_last_drive_off]) 417 | 418 | typedef u_char *lol_t; 419 | 420 | #ifdef OLD_OBSOLETE 421 | typedef struct lol_record { 422 | u_char filler1[22]; 423 | far_t cdsfarptr; 424 | u_char filler2[6]; 425 | u_char last_drive; 426 | } *lol_t; 427 | 428 | #endif 429 | 430 | /* dos attribute byte flags */ 431 | #define REGULAR_FILE 0x00 432 | #define READ_ONLY_FILE 0x01 433 | #define HIDDEN_FILE 0x02 434 | #define SYSTEM_FILE 0x04 435 | #define VOLUME_LABEL 0x08 436 | #define DIRECTORY 0x10 437 | #define ARCHIVE_NEEDED 0x20 438 | 439 | /* dos access mode constants */ 440 | #define READ_ACC 0x00 441 | #define WRITE_ACC 0x01 442 | #define READ_WRITE_ACC 0x02 443 | 444 | #define COMPAT_MODE 0x00 445 | #define DENY_ALL 0x01 446 | #define DENY_WRITE 0x02 447 | #define DENY_READ 0x03 448 | #define DENY_ANY 0x40 449 | 450 | #define CHILD_INHERIT 0x00 451 | #define NO_INHERIT 0x01 452 | 453 | #define A_DRIVE 0x01 454 | #define B_DRIVE 0x02 455 | #define C_DRIVE 0x03 456 | #define D_DRIVE 0x04 457 | 458 | #define GET_REDIRECTION 2 459 | #define REDIRECT_DEVICE 3 460 | #define CANCEL_REDIRECTION 4 461 | #define EXTENDED_GET_REDIRECTION 5 462 | -------------------------------------------------------------------------------- /mfs_link.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* Attempt to fix mfs. dtrg */ 16 | 17 | /* #define u_long UINT32 */ 18 | 19 | struct vm86_regs 20 | { 21 | INT16 eax, ebx, ecx, edx, esi, edi, ebp, esp; 22 | INT16 cs,ds,es,ss; 23 | INT16 eip; 24 | UINT16 eflags; 25 | }; 26 | 27 | struct vm86_struct 28 | { 29 | struct vm86_regs regs; 30 | UINT32 flags; 31 | UINT32 screen_bitmap; 32 | }; 33 | 34 | extern struct vm86_struct vm86s; 35 | extern unsigned char *memory; 36 | 37 | #define us unsigned short 38 | 39 | #ifndef BIOS 40 | 41 | #define LWORD(reg) (*((unsigned short *)®(reg))) 42 | #define HWORD(reg) (*((unsigned short *)®(reg) + 1)) 43 | 44 | #define SEG_ADR(type, seg, reg) type(&memory[(LWORD(seg) << 4)+LWORD(e##reg)]) 45 | 46 | 47 | #define REGS vm86s.regs 48 | #define REG(reg) (REGS.##reg) 49 | 50 | #define CF (1 << 0) 51 | #define TF (1 << 8) 52 | #define IF (1 << 9) 53 | #define NT 0 54 | 55 | 56 | #define IS_REDIRECTED(i) (memory[(i << 2)+2] != 0xf000) 57 | 58 | #define INTE7_SEG (memory[(0xe7 << 2)+2] + (memory[(0xe7 << 2)+3] << 8)) 59 | #define INTE7_OFF (memory[0xe7 << 2] + (memory[(0xe7 << 2) + 1] << 8)) 60 | 61 | #define error printf 62 | 63 | /* Some compilers cannot handle variable numbers of arguments in #defines 64 | #ifdef DEBUG 65 | # define d_printf(arg1, a...) printf(arg1, ##a) 66 | #else 67 | # define d_printf(arg1, a...) 68 | #endif 69 | */ 70 | 71 | #endif 72 | 73 | int mfs_intentry(void); 74 | int mfs_redirector(void); 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /mytypes.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is MYTYPES.H It contains definitions for the basic types to ease 16 | portability */ 17 | 18 | 19 | #ifndef MYTYPES_H 20 | 21 | #define MYTYPES_H 22 | 23 | /* When cross compiling, we can't use autodetect */ 24 | #ifdef i386 25 | #define PCEMU_LITTLE_ENDIAN 1 26 | typedef signed char INT8; 27 | typedef unsigned char UINT8; 28 | typedef signed short INT16; 29 | typedef unsigned short UINT16; 30 | typedef signed int INT32; 31 | typedef unsigned int UINT32; 32 | 33 | #else 34 | #include "autodetect.h" 35 | 36 | #endif 37 | 38 | typedef UINT8 BYTE; 39 | typedef UINT16 WORD; 40 | typedef UINT32 DWORD; 41 | 42 | typedef BYTE Boolean; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /new.pcemurc: -------------------------------------------------------------------------------- 1 | # New-style pcemurc for a DEC Alpha. The floppy drive is on /dev/floppy, 2 | # surprise surprise. The other floppy drive is a minimal boot image. 3 | # Put this in ~/.pcemurc. 4 | # --dg 5 | 6 | floppy 0 /dev/floppy 18 80 2 7 | floppy 1 /user.jh/dg/lib/pcemu/bootimage 10 20 2 8 | updatespeed 10 9 | cursorspeed 35 10 | -------------------------------------------------------------------------------- /old.pcemurc: -------------------------------------------------------------------------------- 1 | # This is .pcemurc 2 | # At present only the following commands are recognised: 3 | # bootfile diskfile 4 | # boottype n (where n=360, 720, 144 or 12) 5 | # cursorspeed n 6 | # updatespeed n 7 | # 8 | # The following are the defaults (unless changed at compile time) 9 | 10 | bootfile /dev/floppy 11 | boottype 144 12 | cursorspeed 30 13 | updatespeed 5 14 | -------------------------------------------------------------------------------- /programs/Makefile: -------------------------------------------------------------------------------- 1 | AS86 = as86 -l 2 | LD86 = ld86 -0 -s 3 | 4 | all: emufs.sys 5 | 6 | %.sys: %.S 7 | $(AS86) -0 -o $*.o $< > $<.out 8 | $(LD86) -T 0 -s -o $*.tmp $*.o 9 | dd if=$*.tmp of=$@ bs=1 skip=32 10 | rm $*.tmp $*.o 11 | 12 | clean: 13 | rm -f emufs.sys *.o *.tmp *.out 14 | -------------------------------------------------------------------------------- /programs/config.sys: -------------------------------------------------------------------------------- 1 | device=emufs.sys / 2 | stacks 9,512 3 | -------------------------------------------------------------------------------- /programs/dumpdisk.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidgiven/pcemu/88061c7ad5efd5343bb42d97f14756881bc97e4e/programs/dumpdisk.c -------------------------------------------------------------------------------- /programs/ekemm.asm: -------------------------------------------------------------------------------- 1 | name driver 2 | page 55,132 3 | title 'EKEMM --- EMS 3.2 Driver For Hedley's PCEMU' 4 | 5 | ; 6 | ; 7 | ; 8 | ; Based on a template (c) Ray Duncan, April 1985 9 | ; Changes Copyright 1994, Eric Korpela. 10 | ; There is no warantee expressed or implied in this software. 11 | ; See the file COPYRIGHT and ems.c for details. 12 | 13 | code segment public 'CODE' 14 | 15 | driver proc far 16 | 17 | assume cs:code,ds:code,es:code 18 | 19 | org 0 20 | 21 | Max_Cmd equ 16 ; MS-DOS command code maximum 22 | 23 | cr equ 0dh 24 | lf equ 0ah 25 | eom equ '$' 26 | 27 | page 28 | ; 29 | ; Device Driver Header 30 | ; 31 | Header dd -1 ; link to next device, -1=end of list 32 | 33 | dw 0C000h ; Device Attribute word 34 | dw Strat ; Device "Strategy" entry point 35 | dw Intr ; Device "Interrupt" entry point 36 | db 'EMMXXXX0' ; character device name 37 | 38 | ; 39 | ; Double-word pointer to Request Header 40 | ; Passed to Strategy routine by MS-DOS 41 | ; 42 | 43 | RH_Ptr dd ? 44 | page 45 | ; 46 | ; MS-DOS Command Codes dispatch table. 47 | ; The "Interrupt" Routine uses this table and the 48 | ; Command Code supplied in the Request Header to 49 | ; transfer to the appropriate driver subroutine. 50 | 51 | Dispatch: 52 | dw Init ; 0=initialize driver 53 | dw Media_Chk ; 1=media check on block device 54 | dw Build_Bpb ; 2=build BIOS parameter block 55 | dw IOCTL_Rd ; 3=I/O Control read 56 | dw Read ; 4=Read from Device 57 | dw ND_Read ; 5=non-destructive read 58 | dw Inp_Stat ; 6=return current input status 59 | dw Inp_Flush ; 7=flush device input buffers 60 | dw Write ; 8=write to device 61 | dw Write_Vfy ; 9=write with verify 62 | dw Outp_Stat ; 10=return current output status 63 | dw Outp_Flush ; 11=flush output buffers 64 | dw IOCTL_Wrt ; 12=I/O control write 65 | dw Dev_Open ; 13=Device Open 66 | dw Dev_Close ; 14=Device Close 67 | dw Rem_Media ; 15=removable media 68 | dw Out_Busy ; 16=output until busy 69 | page 70 | ; 71 | ; MS-DOS Request Header Structure Definition 72 | ; 73 | ; The first 13 bytes of all Request Headers are the same 74 | ; and are referred to as the "Static" part of the header. 75 | ; The number and meaning of the following bytes varies. 76 | ; In this "Struc" definition we show the Request Header 77 | ; contents for Read and Write calls. 78 | ; 79 | Request struc ; Request Header template structure 80 | ; begining of static portion 81 | Rlength db ? ; length of request header 82 | Unit db ? ; unit number for this request 83 | Command db ? ; request header's command code 84 | Status dw ? ; Driver's return status word 85 | ; bit 15 = Error 86 | ; bits 10-14 = Reserved 87 | ; bit 9 = Busy 88 | ; bit 8 = Done 89 | ; bits 0-7 = Error code if bit 15 = 1 90 | Reserve db 8 dup (?) ; reserved area 91 | ; end of Static Portion, the remainder in 92 | ; this example is for Read Write functions. 93 | Media db ? ; Media Descriptor byte 94 | Address dd ? ; Memory Address for Transfer 95 | Count dw ? ; byte/sector count value 96 | Sector dw ? ; Starting sector value 97 | Request ends ; end of request header template 98 | page 99 | 100 | ; Device Driver Strategy Routine 101 | ; 102 | ; Each time a request is made for this device, MS-DOS 103 | ; first calls the "Strategy Routine", then immediately 104 | ; calls the "Interrupt routine". 105 | 106 | ; The Strategy routine is passed the address of the 107 | ; Request Header in ES:BX, which it saves in a local 108 | ; variable and then returns to MS-DOS. 109 | 110 | Strat proc far 111 | ; save addresss of Request Header 112 | mov word ptr cs:[RH_Ptr],bx 113 | mov word ptr cs:[RH_Ptr+2],es 114 | 115 | ret ; back to MS-DOS 116 | 117 | Strat endp 118 | page 119 | 120 | ; Device Driver Interrupt Routine 121 | 122 | ; This entry point is called by MS-DOS immediately after 123 | ; the call to the "Strategy Routine", which saved the long 124 | ; address of the Request Header in the local variable "RH_Ptr". 125 | 126 | ; The "Interrupt Routine" uses the Command Code passed in 127 | ; the Request Header to transfer to the appropriate device 128 | ; handling routine. Each command code routine must place 129 | ; any necessary return information into the Request Header, 130 | ; then perform a near return with AX=Status. 131 | 132 | Intr proc far 133 | 134 | push ax ; save general registers 135 | push bx 136 | push cx 137 | push dx 138 | push ds 139 | push es 140 | push di 141 | push si 142 | push bp 143 | 144 | push cs ; make local data addressable 145 | pop ds 146 | 147 | les di,[RH_Ptr] ; let ES:DI = Request header 148 | 149 | ; get BX = command code 150 | mov bl,es:[di.Command] 151 | xor bh,bh 152 | cmp bx,Max_Cmd ; make sure it's legal. 153 | jle Intr1 ; jump if fuction code is OK 154 | mov ax,8003h ; set Error bit and "Unknown Command" code 155 | jmp Intr2 156 | 157 | Intr1: shl bx,1 ; form index to dispatch table 158 | ; and branch to driver routine. 159 | call word ptr [bx+Dispatch] 160 | ; should return AX = status. 161 | les di,[RH_Ptr] ; restore ES:DI = addr of Request header 162 | 163 | Intr2: or ax,0100h ; merge Done bit into status, and 164 | ; store into request header 165 | mov es:[di.Status],ax 166 | 167 | pop bp ; restore general registers. 168 | pop si 169 | pop di 170 | pop es 171 | pop ds 172 | pop dx 173 | pop cx 174 | pop bx 175 | pop ax 176 | ret ; back to MS-DOS 177 | 178 | page 179 | 180 | ; 181 | ; Command Code subroutines called by Interrupt Routine 182 | ; 183 | ; These routines are called with ES:DI pointing to the 184 | ; Request Header. 185 | ; 186 | ; They should return AX = 0 if function was completed 187 | ; successfully, or AX = 8000H + Error code if function failed. 188 | ; 189 | 190 | Write proc near ; Function 8 = write 191 | xor ax,ax 192 | ret 193 | Write endp 194 | 195 | Media_Chk equ Offset Write ; Function 1 = Media Check 196 | 197 | Build_Bpb equ Offset Write ; Function 2 = Build BPB 198 | 199 | IOCTL_Rd proc near ; Function 3 = I/O Control Read 200 | 201 | xor ax,ax 202 | mov es:[di.Count],ax 203 | mov al,0FFh 204 | ret 205 | 206 | IOCTL_Rd endp 207 | 208 | Read equ Offset IOCTL_Rd ; Function 4 = Read 209 | 210 | ND_Read equ Offset IOCTL_Rd ; Function 5 = Non-Destructive Read 211 | 212 | Inp_Stat equ Offset Write ; Function 6 = Input Status 213 | 214 | Inp_Flush equ Offset Write ; Function 7 = Input Flush 215 | 216 | Write_Vfy equ Offset Write ; Function 9 = Write with Verify 217 | 218 | Outp_Stat equ Offset IOCTL_Wrt ; Function 10 = Output Status 219 | 220 | Outp_Flush equ Offset Write ; Function 11 = Flush Output Buffers 221 | 222 | IOCTL_Wrt proc near ; Function 12 = I/O Control Write 223 | mov ax,0FFh 224 | ret 225 | IOCTL_Wrt endp 226 | 227 | Int67 proc far 228 | int 4Bh 229 | iret 230 | Int67 endp 231 | Dev_Open equ Offset Write ; Function 13 = Device Open 232 | 233 | Dev_Close equ Offset Write ; Function 14 = Device Close 234 | 235 | Rem_Media equ Offset Write ; Function 15 = Removable Media 236 | 237 | Out_Busy equ Offset Write ; Function 16 = Output until busy 238 | 239 | page 240 | 241 | ; The initialization code for the driver is called only 242 | ; once, when the driver is loaded. It is reasponsible for 243 | ; initializing the hardware, setting up any necessary 244 | ; interrupt vectors, and it must return the address 245 | ; of the first free memory after the driver to MS-DOS. 246 | ; If it is a block device driver, Init must also return the 247 | ; address of the BIOS parameter block pointer array; if all 248 | ; units are the same, all pointers can be to the same BPB. 249 | ; Only MS-DOS services 01-0CH and 30H can be called by the 250 | ; Initialization Function. 251 | ; 252 | ; In this example, Init returns its own address to the DOS as 253 | ; the start of free memory after the driver, so that the memory 254 | ; occupied by INIT will be reclaimed after it is finished 255 | ; with its work. 256 | 257 | Init proc near ; Function 0 = Initialize Driver 258 | 259 | push es ; save address of Request Header. 260 | push di 261 | 262 | mov ax,cs ; convert load address to ASCII. 263 | mov bx, offset DHaddr 264 | call hexasc 265 | 266 | mov ah,9 ; print sign-on message and 267 | mov dx,offset Ident ; the load address of the driver. 268 | int 21h 269 | push ds 270 | push dx 271 | mov al,67h 272 | mov dx,cs 273 | mov ds,dx 274 | mov dx,offset Int67 275 | mov ah,25h 276 | int 21h 277 | 278 | pop dx 279 | pop ds 280 | pop di ; restore Request Header addr. 281 | pop es 282 | 283 | ; set first usable memory address 284 | mov word ptr es:[di.Address],offset init 285 | mov word ptr es:[di.Address+2],cs 286 | 287 | xor ax,ax ; Return Status 288 | ret 289 | 290 | Init endp 291 | 292 | Ident db cr,lf,lf 293 | db 'EKEMS Device Driver 1.0' 294 | db cr,lf 295 | db 'Device Header at ' 296 | 297 | DHaddr db 'XXXX:0000' 298 | db cr,lf,lf,eom 299 | 300 | Intr endp 301 | 302 | page 303 | 304 | ; HEXASC --- converts a binary 16 bit number into 305 | ; a "hexidecimal" ASCII string. 306 | ; 307 | ; Call with AX = value to convert 308 | ; DS:BX = address to store 4 character string 309 | ; 310 | ; Returns AX, BX destroyed, other registers preserved 311 | 312 | hexasc proc near 313 | 314 | push cx ; save registers. 315 | push dx 316 | 317 | mov dx,4 ; initialize character counter. 318 | 319 | hexasc1: 320 | mov cx,4 ; isolate next 4 bits. 321 | rol ax,cl 322 | mov cx,ax 323 | and cx,0fh 324 | add cx,'0' ; convert to ASCII. 325 | cmp cx,'9' ; is it 0-9? 326 | jbe hexasc2 ; yes, jump. 327 | ; add fudge factor for A-F. 328 | add cx,'A'-'9'-1 329 | 330 | hexasc2: ; store this character. 331 | mov [bx],cl 332 | inc bx ; bump string pointer. 333 | 334 | dec dx ; count characters converted. 335 | jnz hexasc1 ; loop, not four yet. 336 | 337 | pop dx ; restore registers. 338 | pop cx 339 | ret ; back to caller 340 | 341 | hexasc endp 342 | 343 | Driver endp 344 | 345 | code ends 346 | 347 | end 348 | 349 | 350 | -------------------------------------------------------------------------------- /programs/ekemm.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidgiven/pcemu/88061c7ad5efd5343bb42d97f14756881bc97e4e/programs/ekemm.sys -------------------------------------------------------------------------------- /programs/emufs.S: -------------------------------------------------------------------------------- 1 | ! 2 | ! 3 | ! Mach Operating System 4 | ! Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 5 | ! Copyright (c) 1991 IBM Corporation 6 | ! All Rights Reserved. 7 | ! 8 | ! Permission to use, copy, modify and distribute this software and its 9 | ! documentation is hereby granted, provided that both the copyright 10 | ! notice and this permission notice appear in all copies of the 11 | ! software, derivative works or modified versions, and any portions 12 | ! thereof, and that both notices appear in supporting documentation, 13 | ! and that the nema IBM not be used in advertising or publicity 14 | ! pertaining to distribution of the software without specific, written 15 | ! prior permission. 16 | ! 17 | ! CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" 18 | ! CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR 19 | ! ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 20 | ! 21 | ! Carnegie Mellon requests users of this software to return to 22 | ! 23 | ! Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 24 | ! School of Computer Science 25 | ! Carnegie Mellon University 26 | ! Pittsburgh PA 15213-3890 27 | ! 28 | ! any improvements or extensions that they make and grant Carnegie Mellon 29 | ! the rights to redistribute these changes. 30 | ! 31 | ! MACHFS.ASM MS-DOS device driver to interface mach file system 32 | ! with the dos server's monitor. 33 | ! 34 | ! Version 1.1 35 | ! 36 | ! Gerald Malan (grm) 4/5/1991 37 | ! 38 | ! modified for the linux dos emulator by Andrew Tridgell 13/4/93 39 | ! translated into as86 form by Robert Sanders ('murrcan style date!) 4/13/93 40 | ! (I probably broke something, but it seems to work) 41 | ! 42 | ! $Date$ 43 | ! $Source$ 44 | ! $Revision$ 45 | ! $State$ 46 | ! 47 | 48 | ! Altered slightly to run under PCEMU - DH 49 | ! Additions/alterations are marked 50 | 51 | use16 52 | 53 | .text 54 | .bss 55 | .data 56 | .align 0 57 | 58 | .org 0 59 | 60 | MaxCmd = 12 61 | cr = 0xd 62 | lf = 0xa 63 | eom = '$' ! DOS end-of-string character (barf) 64 | Linuxfs = 0xe6 ! 0xe6 is Int for Mach Dos Server 65 | Mivec = (Linuxfs * 4) ! mem loc for the interrupt vector 66 | 67 | .globl _main 68 | _main: 69 | 70 | Header: 71 | .long -1 ! link to next device driver 72 | .word 0 ! attribute word for driver 73 | .word Strat ! ptr to strategy routine 74 | .word Intr ! ptr to interrupt service routine 75 | ! ### Line below changed by DH ### 76 | .ascii "PCEMU " ! logical-device name 77 | 78 | ! the Strat and Intr routines are entered with a "far call". I don't 79 | ! know how to tell as86 that asI would in Turbo Assembler, so Ijust 80 | ! explicitly "retf" at the end of their execution. careful! 81 | 82 | ! BPB from horse.mach.cs.cmu.edu 83 | Bpb: .word 0x200 ! Bytes per Sector 84 | .byte 4 ! Sectors per allocation unit 85 | .word 1 ! Number of reserved sectors 86 | .byte 2 ! Number of FATS 87 | .word 0x200 ! Max number of root entries 88 | .word 0xac21 ! Total number of sectors 89 | .byte 0xf8 ! Media Desc Byte 90 | .word 0x2b ! Num sec per FAT 91 | .word 0x23 ! Sectors per track 92 | .word 0xf ! Number of heads 93 | .word 0 ! Number of hidden sectors 94 | .word 0 ! High order word of hidden sectors 95 | .long 0 ! zero 96 | .long 0 97 | .long 0 98 | .long 0 99 | .long 0 100 | .long 0 101 | .long 0 102 | .long 0 103 | 104 | BPBptr: .word Bpb 105 | 106 | RHPtr: .long 0 ! ptr to request header 107 | 108 | InitDone: .word 0 ! 1 when initialisation is complete 109 | 110 | Dispatch: 111 | 112 | .word Init ! initialize driver 113 | .word MediaChk 114 | .word BuildBpb 115 | .word Dummy 116 | .word Read ! read 117 | .word Dummy 118 | .word Dummy 119 | .word Dummy 120 | .word Write ! write 121 | .word Write ! write with verify 122 | .word Dummy 123 | .word Dummy 124 | .word Dummy 125 | 126 | Strat: 127 | ! was... 128 | ! mov word ptr cs:[RHPtr],bx 129 | ! mov word ptr cs:[RHPtr+2],es 130 | seg cs 131 | mov [RHPtr], bx 132 | seg cs 133 | mov [RHPtr+2],es 134 | retf 135 | 136 | 137 | Intr: 138 | push ax 139 | push bx 140 | push cx 141 | push dx 142 | push ds 143 | push es 144 | push di 145 | push si 146 | push bp 147 | 148 | push cs 149 | pop ds 150 | 151 | les di,[RHPtr] ! let es:di = request header 152 | 153 | seg es 154 | movb bl,[di+2] 155 | xorb bh,bh 156 | cmp bx, #MaxCmd 157 | jle Intr1 158 | call Error 159 | jmp Intr2 160 | 161 | Intr1: shl bx,#1 162 | 163 | call [bx+Dispatch] 164 | 165 | les di,[RHPtr] 166 | 167 | Intr2: or ax,#0x100 ! Merge done bit with status 168 | seg es 169 | mov [di+3],ax 170 | 171 | pop bp 172 | pop si 173 | pop di 174 | pop es 175 | pop ds 176 | pop dx 177 | pop cx 178 | pop bx 179 | pop ax 180 | retf 181 | 182 | Dummy: 183 | call MFSini 184 | les di, [RHPtr] 185 | seg es 186 | mov bl, [di+2] 187 | mov bh, #3 188 | 189 | mov ax, #0x20 190 | int Linuxfs 191 | 192 | xor ax,ax 193 | ret 194 | 195 | 196 | MediaChk: 197 | call MFSini 198 | ! was... 199 | ! mov byte ptr es:[di+14],#-1 ! disk has changed 200 | ! mov word ptr es:[di+15], offset NoName 201 | ! mov word ptr es:[di+17], cs 202 | seg es 203 | movb [di+14],#-1 ! disk has changed 204 | seg es 205 | mov [di+15], #NoName 206 | seg es 207 | mov [di+17], cs 208 | xor ax,ax 209 | ret 210 | 211 | 212 | BuildBpb: 213 | call MFSini 214 | ! was... 215 | ! mov word ptr es:[di+18],offset Bpb 216 | ! mov word ptr es:[di+20],cs 217 | seg es 218 | mov [di+18], #Bpb 219 | seg es 220 | mov [di+20], cs 221 | xor ax,ax 222 | ret 223 | 224 | 225 | Read: 226 | call MFSini 227 | mov bx,#0x101 228 | mov ax,#0x20 229 | int Linuxfs 230 | xor ax,ax 231 | ret 232 | 233 | 234 | Write: 235 | call MFSini 236 | mov bx,#0x202 237 | mov ax,#0x20 238 | int Linuxfs 239 | xor ax,ax 240 | ret 241 | 242 | 243 | Error: 244 | mov ax,#0x8003 245 | ret 246 | 247 | 248 | MyIret: 249 | xor ax,ax 250 | iret 251 | 252 | 253 | MFSini: 254 | push es 255 | push di 256 | 257 | push cs 258 | pop ds 259 | mov ax,[InitDone] 260 | cmp ax,#0 261 | jne AlreadyDone 262 | 263 | mov ax, #0x3000 264 | int 0x21 265 | push ax 266 | 267 | mov ah, #0x52 268 | int 0x21 269 | 270 | mov ax, #0x5d06 271 | int 0x21 272 | 273 | pop cx 274 | push bx 275 | pop dx 276 | mov bx, #0x500 277 | mov ax,#0x20 278 | int Linuxfs 279 | 280 | push cs 281 | pop ds 282 | mov ax,#1 283 | mov [InitDone],ax 284 | 285 | AlreadyDone: 286 | pop di 287 | pop es 288 | ret 289 | 290 | ! ### Added by DH ### 291 | 292 | Old2f: 293 | nop 294 | nop 295 | nop 296 | nop 297 | 298 | Int2fHandler: 299 | cmp ah,#0x11 300 | jnz NotRedir 301 | push bp 302 | mov bp,sp 303 | push word ptr [bp+8] 304 | int #0xe8 305 | pop bp 306 | pop bp 307 | jz NotRedir 308 | sti 309 | retf #2 310 | NotRedir: 311 | seg cs 312 | jmp far [Old2f] 313 | 314 | InitRedir: 315 | cli 316 | push ds 317 | push es 318 | push ax 319 | xor ax,ax 320 | mov ds,ax 321 | les ax,[0x2f*4] 322 | seg cs 323 | mov [Old2f],ax 324 | seg cs 325 | mov [Old2f+2],es 326 | mov [0x2f*4],#Int2fHandler 327 | mov [0x2f*4+2], cs 328 | pop ax 329 | pop es 330 | pop ds 331 | sti 332 | ret 333 | ! ### End of addition 334 | 335 | Init: 336 | xor bx,bx 337 | push si 338 | mov si, #DirName 339 | movb [si], #0x24 340 | mov ax, #0x20 341 | int Linuxfs 342 | pop si 343 | 344 | cmp ax, #0 345 | jne MFSin 346 | 347 | MFSout: 348 | push cs 349 | pop ds 350 | mov ah, #9 351 | mov dx, #OutMess 352 | int 0x21 353 | 354 | ! was... 355 | ! mov byte ptr es:[di+13],#0 ! No units!! 356 | ! mov word ptr es:[di+18],offset BPBptr 357 | ! mov word ptr es:[di+20],cs 358 | ! ### Line below changed from #0 to #InitRedir 359 | ! mov word ptr es:[di+14],#InitRedir !Break addr = cs:InitRedir 360 | ! mov word ptr es:[di+16],cs 361 | 362 | seg es 363 | movb [di+13],#0 ! No units!! 364 | seg es 365 | mov [di+18], #BPBptr 366 | seg es 367 | mov [di+20],cs 368 | seg es 369 | mov [di+14],#InitRedir !Break addr = cs:InitRedir 370 | seg es 371 | mov [di+16],cs 372 | 373 | ret 374 | 375 | MFSin: 376 | ! ### Added by DH ### 377 | call InitRedir 378 | ! ### End of addition ### 379 | call MFSini 380 | 381 | seg es 382 | movb al, [di+22] 383 | add al, #0x41 384 | 385 | push di 386 | push cs 387 | pop ds 388 | mov di, #Mesage1 389 | movb [di],al 390 | 391 | mov ah, #9 392 | mov dx, #Mesage 393 | int 0x21 394 | pop di 395 | 396 | ! was... 397 | ! mov byte ptr es:[di+13],#1 ! Number of units 398 | ! mov word ptr es:[di+18],offset BPBptr 399 | ! mov word ptr es:[di+20],cs 400 | ! mov word ptr es:[di+14],offset Init 401 | ! mov word ptr es:[di+16],cs 402 | 403 | ! this is part of diff9 404 | ! seg es 405 | ! movb [di+13],#1 ! Number of units 406 | 407 | seg es 408 | mov [di+18], #BPBptr 409 | seg es 410 | mov [di+20],cs 411 | seg es 412 | mov [di+14], #Init 413 | seg es 414 | mov [di+16],cs 415 | 416 | xor ax,ax 417 | 418 | ret 419 | 420 | ! ### Next line altered slightly by DH 421 | Mesage: .ascii "[PC Emulator File System] drive " 422 | Mesage1: 423 | .ascii "A: is directory " 424 | DirName: 425 | .space 128 426 | .byte cr,lf,eom 427 | 428 | OutMess: 429 | .byte cr,lf,lf 430 | .ascii "Linux Dos Server not responding." 431 | .byte cr,lf 432 | .ascii "Installation aborted." 433 | .byte cr,lf,lf,eom 434 | 435 | NoName: .ascii "NO NAME" 436 | .byte 0 437 | 438 | end 439 | 440 | 441 | -------------------------------------------------------------------------------- /programs/emufs.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidgiven/pcemu/88061c7ad5efd5343bb42d97f14756881bc97e4e/programs/emufs.sys -------------------------------------------------------------------------------- /programs/lredir.c: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | * File: LREDIR.C 3 | * Program for Linux DOSEMU disk redirector functions 4 | * Written: 10/29/93 by Tim Bird 5 | * 6 | * (altered slightly by DH - changed 'LINUX\FS' to 'PCEMU\FS' in help message) 7 | * 8 | * NOTES: 9 | * LREDIR supports the following commands: 10 | * LREDIR drive filepath 11 | * redirects the indicated drive to the specified linux filepath 12 | * drive = the drive letter followed by a colon (ex. 'E:') 13 | * filepath has linux and a file path (ex. 'LINUX\USR\SRC') 14 | * LREDIR DEL drive 15 | * cancels redirection of the indicated drive 16 | * LREDIR 17 | * shows drives that are currently redirected (mapped) 18 | * LREDIR HELP or LREDIR ? 19 | * show usage information for LREDIR ??? 20 | ***********************************************/ 21 | #include /* for printf */ 22 | #include /* for geninterrupt and MK_FP */ 23 | #include 24 | 25 | typedef unsigned char uint8; 26 | 27 | 28 | typedef unsigned int uint16; 29 | 30 | 31 | 32 | #define CARRY_FLAG 1 /* carry bit in flags register */ 33 | 34 | #define CC_SUCCESS 0 35 | 36 | #define DOS_GET_LIST_OF_LISTS 0x5200 37 | #define DOS_GET_SDA_POINTER 0x5D06 38 | #define DOS_GET_REDIRECTION 0x5F02 39 | #define DOS_REDIRECT_DEVICE 0x5F03 40 | #define DOS_CANCEL_REDIRECTION 0x5F04 41 | 42 | 43 | #define MAX_RESOURCE_STRING_LENGTH 36 /* 16 + 16 + 3 for slashes + 1 for NULL */ 44 | #define MAX_RESOURCE_PATH_LENGTH 128 /* added to support Linux paths */ 45 | #define MAX_DEVICE_STRING_LENGTH 5 /* enough for printer strings */ 46 | 47 | #define REDIR_PRINTER_TYPE 3 48 | #define REDIR_DISK_TYPE 4 49 | 50 | #define READ_ONLY_DRIVE_ATTRIBUTE 1 /* same as NetWare Lite */ 51 | 52 | #define KEYWORD_DEL "DELETE" 53 | #define KEYWORD_DEL_COMPARE_LENGTH 3 54 | 55 | #define DEFAULT_REDIR_PARAM 0 56 | 57 | #define DOS_HELPER_INT 0xE6 58 | #define DOS_HELPER_DOSEMU_CHECK 0x00 59 | 60 | /* returns non-zero major version number if DOSEMU is loaded */ 61 | uint16 CheckForDOSEMU(void) 62 | { 63 | 64 | _AL = DOS_HELPER_DOSEMU_CHECK; 65 | 66 | geninterrupt(DOS_HELPER_INT); 67 | 68 | /* check for signature in AX */ 69 | if (_AX == 0xaa55) { 70 | 71 | return (_BX); 72 | 73 | } 74 | else { 75 | 76 | return (0); 77 | 78 | } 79 | 80 | } 81 | 82 | 83 | 84 | char far * 85 | GetListOfLists() 86 | { 87 | 88 | char far *LOL; 89 | 90 | 91 | 92 | _AX = DOS_GET_LIST_OF_LISTS; 93 | 94 | geninterrupt(0x21); 95 | 96 | LOL = MK_FP(_ES, _BX); 97 | 98 | return (LOL); 99 | 100 | } 101 | 102 | 103 | 104 | char far * 105 | GetSDAPointer(void) 106 | { 107 | 108 | char far *SDA; 109 | 110 | 111 | 112 | _AX = DOS_GET_SDA_POINTER; 113 | 114 | asm { 115 | 116 | push ds 117 | int 0x21 118 | push ds 119 | pop es 120 | pop ds 121 | } 122 | 123 | SDA = MK_FP(_ES, _SI); 124 | 125 | return (SDA); 126 | 127 | } 128 | 129 | 130 | 131 | /******************************************** 132 | * InitMFS - call Emulator to initialize MFS 133 | ********************************************/ 134 | uint16 InitMFS(void) 135 | { 136 | 137 | uint16 ccode; 138 | 139 | char far *LOL; 140 | 141 | 142 | char far *SDA; 143 | 144 | 145 | 146 | LOL = GetListOfLists(); 147 | 148 | SDA = GetSDAPointer(); 149 | 150 | 151 | /* get DOS version into CX */ 152 | _CL = _osmajor; 153 | 154 | _CH = _osminor; 155 | 156 | 157 | asm { 158 | 159 | push ds 160 | } 161 | 162 | 163 | _DX = FP_OFF(LOL); 164 | 165 | _ES = FP_SEG(LOL); 166 | 167 | _SI = FP_OFF(SDA); 168 | 169 | _DS = FP_SEG(SDA); 170 | 171 | 172 | _BX = 0x500; 173 | 174 | _AX = 0x20; 175 | 176 | geninterrupt(DOS_HELPER_INT); 177 | 178 | 179 | asm { 180 | 181 | pop ds 182 | } 183 | 184 | } 185 | 186 | 187 | 188 | /******************************************** 189 | * RedirectDevice - redirect a device to a remote resource 190 | * ON ENTRY: 191 | * deviceStr has a string with the device name: 192 | * either disk or printer (ex. 'D:' or 'LPT1') 193 | * resourceStr has a string with the server and name of resource 194 | * (ex. 'TIM\TOOLS') 195 | * deviceType indicates the type of device being redirected 196 | * 3 = printer, 4 = disk 197 | * deviceParameter is a value to be saved with this redirection 198 | * which will be returned on GetRedirectionList 199 | * ON EXIT: 200 | * returns CC_SUCCESS if the operation was successful, 201 | * otherwise returns the DOS error code 202 | * NOTES: 203 | * deviceParameter is used in DOSEMU to return the drive attribute 204 | * It is not actually saved and returned as specified by the redirector 205 | * specification. This type of usage is common among commercial redirectors. 206 | ********************************************/ 207 | uint16 RedirectDevice(char *deviceStr, char *resourceStr, uint8 deviceType, 208 | uint16 deviceParameter) 209 | { 210 | 211 | char slashedResourceStr[MAX_RESOURCE_PATH_LENGTH]; 212 | 213 | 214 | 215 | /* prepend the resource string with slashes */ 216 | strcpy(slashedResourceStr, "\\\\"); 217 | 218 | strcat(slashedResourceStr, resourceStr); 219 | 220 | 221 | /* should verify strings before sending them down ??? */ 222 | asm { 223 | 224 | push ds 225 | } 226 | 227 | _DS = FP_SEG(deviceStr); 228 | 229 | _SI = FP_OFF(deviceStr); 230 | 231 | _ES = FP_SEG(slashedResourceStr); 232 | 233 | _DI = FP_OFF(slashedResourceStr); 234 | 235 | _CX = deviceParameter; 236 | 237 | _BL = deviceType; 238 | 239 | _AX = DOS_REDIRECT_DEVICE; 240 | 241 | geninterrupt(0x21); 242 | 243 | asm { 244 | 245 | pop ds 246 | pushf 247 | pop dx 248 | } 249 | 250 | if (_DX & CARRY_FLAG) { 251 | 252 | return (_AX); 253 | 254 | } 255 | else { 256 | 257 | return (CC_SUCCESS); 258 | 259 | } 260 | 261 | } 262 | 263 | 264 | 265 | /******************************************** 266 | * GetRedirection - get next entry from list of redirected devices 267 | * ON ENTRY: 268 | * redirIndex has the index of the next device to return 269 | * this should start at 0, and be incremented between calls 270 | * to retrieve all elements of the redirection list 271 | * ON EXIT: 272 | * returns CC_SUCCESS if the operation was successful, and 273 | * deviceStr has a string with the device name: 274 | * either disk or printer (ex. 'D:' or 'LPT1') 275 | * resourceStr has a string with the server and name of resource 276 | * (ex. 'TIM\TOOLS') 277 | * deviceType indicates the type of device which was redirected 278 | * 3 = printer, 4 = disk 279 | * deviceParameter has my rights to this resource 280 | * NOTES: 281 | * 282 | ********************************************/ 283 | uint16 GetRedirection(uint16 redirIndex, char *deviceStr, char *resourceStr, 284 | uint8 * deviceType, uint16 * deviceParameter) 285 | { 286 | 287 | uint16 ccode; 288 | 289 | uint8 deviceTypeTemp; 290 | 291 | char slashedResourceStr[MAX_RESOURCE_PATH_LENGTH]; 292 | 293 | 294 | 295 | asm { 296 | 297 | push ds 298 | } 299 | 300 | _DS = FP_SEG(deviceStr); 301 | 302 | _SI = FP_OFF(deviceStr); 303 | 304 | _ES = FP_SEG(slashedResourceStr); 305 | 306 | _DI = FP_OFF(slashedResourceStr); 307 | 308 | _BX = redirIndex; 309 | 310 | _AX = DOS_GET_REDIRECTION; 311 | 312 | asm { 313 | 314 | push bp 315 | int 21 h 316 | pop bp 317 | pushf 318 | pop dx /* get flags into DX */ 319 | pop ds 320 | } 321 | 322 | ccode = _AX; 323 | 324 | deviceTypeTemp = _BL; /* save device type before C ruins it */ 325 | 326 | *deviceType = deviceTypeTemp; 327 | 328 | *deviceParameter = _CX; 329 | 330 | 331 | /* copy back unslashed portion of resource string */ 332 | if (_DX & CARRY_FLAG) { 333 | 334 | return (ccode); 335 | 336 | } 337 | else { 338 | 339 | /* eat the leading slashes */ 340 | strcpy(resourceStr, slashedResourceStr + 2); 341 | 342 | return (CC_SUCCESS); 343 | 344 | } 345 | 346 | } 347 | 348 | 349 | 350 | /******************************************** 351 | * CancelRedirection - delete a device mapped to a remote resource 352 | * ON ENTRY: 353 | * deviceStr has a string with the device name: 354 | * either disk or printer (ex. 'D:' or 'LPT1') 355 | * ON EXIT: 356 | * returns CC_SUCCESS if the operation was successful, 357 | * otherwise returns the DOS error code 358 | * NOTES: 359 | * 360 | ********************************************/ 361 | uint16 CancelRedirection(char *deviceStr) 362 | { 363 | 364 | asm { 365 | 366 | push ds 367 | } 368 | 369 | _DS = FP_SEG(deviceStr); 370 | 371 | _SI = FP_OFF(deviceStr); 372 | 373 | _AX = DOS_CANCEL_REDIRECTION; 374 | 375 | geninterrupt(0x21); 376 | 377 | asm { 378 | 379 | pop ds 380 | pushf 381 | pop dx 382 | } 383 | 384 | if (_DX & CARRY_FLAG) { 385 | 386 | return (_AX); 387 | 388 | } 389 | else { 390 | 391 | return (CC_SUCCESS); 392 | 393 | } 394 | 395 | } 396 | 397 | 398 | 399 | /************************************* 400 | * ShowMyRedirections 401 | * show my current drive redirections 402 | * NOTES: 403 | * I show the read-only attribute for each drive 404 | * which is returned in deviceParam. 405 | *************************************/ 406 | void 407 | ShowMyRedirections(void) 408 | { 409 | 410 | 411 | int driveCount; 412 | 413 | 414 | uint16 redirIndex, deviceParam, ccode; 415 | 416 | uint8 deviceType; 417 | 418 | char deviceStr[MAX_DEVICE_STRING_LENGTH]; 419 | 420 | 421 | char resourceStr[MAX_RESOURCE_PATH_LENGTH]; 422 | 423 | 424 | 425 | redirIndex = 0; 426 | 427 | driveCount = 0; 428 | 429 | ccode = GetRedirection(redirIndex, deviceStr, resourceStr, 430 | &deviceType, &deviceParam); 431 | 432 | while (ccode == CC_SUCCESS) { 433 | 434 | /* only print disk redirections here */ 435 | if (deviceType == REDIR_DISK_TYPE) { 436 | 437 | if (driveCount == 0) { 438 | 439 | printf("Current Drive Redirections:\n"); 440 | 441 | } 442 | 443 | driveCount++; 444 | 445 | printf("%-2s = %-20s ", 446 | deviceStr, resourceStr); 447 | 448 | /* read attribute is returned in the device parameter */ 449 | if (deviceParam & 0x80) { 450 | 451 | printf("attrib = "); 452 | 453 | switch (deviceParam) { 454 | 455 | case READ_ONLY_DRIVE_ATTRIBUTE: 456 | 457 | printf("READ ONLY"); 458 | 459 | break; 460 | 461 | default: 462 | 463 | printf("READ/WRITE"); 464 | 465 | break; 466 | 467 | 468 | } 469 | 470 | } 471 | 472 | printf("\n"); 473 | 474 | } 475 | 476 | redirIndex++; 477 | 478 | ccode = GetRedirection(redirIndex, deviceStr, resourceStr, 479 | &deviceType, &deviceParam); 480 | 481 | } 482 | 483 | if (driveCount == 0) { 484 | 485 | printf("No drives are currently redirected to Linux.\n"); 486 | 487 | } 488 | 489 | } 490 | 491 | 492 | 493 | void 494 | DeleteDriveRedirection(char *deviceStr) 495 | { 496 | 497 | uint16 ccode; 498 | 499 | 500 | /* convert device string to upper case */ 501 | strupr(deviceStr); 502 | 503 | ccode = CancelRedirection(deviceStr); 504 | 505 | if (ccode) { 506 | 507 | printf("Error %x canceling redirection on drive %s\n", 508 | ccode, deviceStr); 509 | 510 | } 511 | else { 512 | 513 | printf("Redirection for drive %s was deleted.\n", deviceStr); 514 | 515 | } 516 | 517 | } 518 | 519 | 520 | 521 | main(int argc, char **argv) 522 | { 523 | 524 | uint16 ccode; 525 | 526 | uint16 redirIndex, deviceParam; 527 | 528 | uint8 deviceType; 529 | 530 | 531 | char deviceStr[MAX_DEVICE_STRING_LENGTH]; 532 | 533 | 534 | char resourceStr[MAX_RESOURCE_PATH_LENGTH]; 535 | 536 | 537 | 538 | ccode = CheckForDOSEMU(); 539 | 540 | if (ccode == 0) { 541 | 542 | printf("DOSEMU is not running. This program is intended for use\n"); 543 | 544 | printf("only with the Linux DOS emulator.\n"); 545 | 546 | exit(1); 547 | 548 | } 549 | 550 | 551 | /* initialize the MFS, just in case the user didn't run EMUFS.SYS */ 552 | InitMFS(); 553 | 554 | 555 | /* need to parse the command line */ 556 | /* if no parameters, then just show current mappings */ 557 | if (argc == 1) { 558 | 559 | ShowMyRedirections(); 560 | 561 | exit(0); 562 | 563 | } 564 | 565 | 566 | if (strncmpi(argv[1], KEYWORD_DEL, KEYWORD_DEL_COMPARE_LENGTH) == 0) { 567 | 568 | DeleteDriveRedirection(argv[2]); 569 | 570 | exit(0); 571 | 572 | } 573 | 574 | 575 | if (strcmpi(argv[1], "HELP") == 0 || argv[1][0] == '?') { 576 | 577 | printf("Usage: LREDIR drive: PCEMU\\FS\\path [R]\n"); 578 | 579 | printf(" redirect a drive to the Linux file system\n"); 580 | 581 | printf(" if R is specified, the drive will be read-only.\n"); 582 | 583 | printf(" LREDIR DEL drive:\n"); 584 | 585 | printf(" delete a drive redirection\n"); 586 | 587 | printf(" LREDIR\n"); 588 | 589 | printf(" show current drive redirections\n"); 590 | 591 | printf(" LREDIR HELP\n"); 592 | 593 | printf(" show this help screen\n"); 594 | 595 | exit(0); 596 | 597 | } 598 | 599 | 600 | /* assume the command is to redirect a drive */ 601 | /* read the drive letter and resource string */ 602 | strcpy(deviceStr, argv[1]); 603 | 604 | strcpy(resourceStr, argv[2]); 605 | 606 | deviceParam = DEFAULT_REDIR_PARAM; 607 | 608 | if (argc > 3) { 609 | 610 | if (toupper(argv[3][0]) == 'R') { 611 | 612 | deviceParam = 1; 613 | 614 | } 615 | 616 | } 617 | 618 | 619 | /* upper-case both strings */ 620 | strupr(deviceStr); 621 | 622 | strupr(resourceStr); 623 | 624 | 625 | /* now actually redirect the drive */ 626 | ccode = RedirectDevice(deviceStr, resourceStr, REDIR_DISK_TYPE, 627 | deviceParam); 628 | 629 | if (ccode) { 630 | 631 | printf("Error %x redirecting drive %s to %s\n", 632 | ccode, deviceStr, resourceStr); 633 | 634 | goto MainExit; 635 | 636 | } 637 | 638 | printf("Drive %s redirected to %s\n", deviceStr, resourceStr); 639 | 640 | 641 | MainExit: 642 | return (ccode); 643 | 644 | } 645 | 646 | 647 |  648 | -------------------------------------------------------------------------------- /programs/lredir.readme: -------------------------------------------------------------------------------- 1 | From Tim Bird (Tim_R_Bird@Novell.COM) : 2 | (altered slightly by DH - changed 'LINUX\FS' to 'PCEMU\FS') 3 | 4 | LREDIR is a general purpose DOS redirection utility, specifically 5 | implemented for use with the Linux DOS emulator DOSEMU. 6 | 7 | In general, DOSEMU provides emulation of a DOS disk redirector via the 8 | MFS (Mach File System) module of the emulator. This support was originally 9 | derived from the redirector for the DOS emulator for Mach. 10 | 11 | DOS supports installable file systems by issueing callouts to a "redirector" 12 | on any functions it receives for files or drives that are registered 13 | with it as being non-local. The installable file system support is intended 14 | mainly for use by CD-ROM drivers and network clients, so that these file 15 | systems may be presented to the DOS user as additional drives. In DOSEMU, 16 | MFS uses this mechanism to present a section of the Linux file system to 17 | the DOS which is running in the emulator. This means that any subtree in 18 | the Linux file system may be redirected and designated as a drive letter 19 | under DOS for use in the emulator. 20 | 21 | In order for DOS to use redirected drives, it must be configured for 22 | additional drives. This is done by putting a "LASTDRIVE=Z" statement in 23 | the CONFIG.SYS that is used by the emulator upon loading DOS. You can set 24 | the LASTDRIVE to any letter of the alphabet. The default is F if none is 25 | specified, which means that DOS can only use letters A-F for drives. The 26 | example above configures all possible drive letters, A through Z, to be 27 | available for use by DOS (and is what I recommend). There is a slight 28 | memory penalty for configuring this many drives (about 1K of the 29 | conventional memory inside the emulator). 30 | 31 | To use LREDIR, MFS must first have been enabled using EMUFS.SYS. To do 32 | this, load EMUFS.SYS in your CONFIG.SYS, with a line like: 33 | 34 | device=C:\EMUFS.SYS /usr/src 35 | 36 | This will initialize the MFS redirector, and create one redirection 37 | automatically on the first available drive letter (usually D:). Although 38 | EMUFS.SYS can be loaded multiple times to get additional drives, I 39 | recommend that you only load it once, and use LREDIR to redirect more 40 | drives to other places in the Linux file system as needed. 41 | 42 | LREDIR can be used to create new redirections, get a list of the current 43 | redirections, or to delete a redirection. To create a new redirection, 44 | specify the drive letter to use, and the Linux file system path which 45 | will become the root of that drive. Since LREDIR is a general-purpose 46 | redirection utility, it has a generic syntax which allows it to be used 47 | with other redirectors besides MFS (like the NetWare Lite client, or 48 | DOS VLM NetWare client). The syntax is: 49 | 50 | LREDIR drive: server\volume\path 51 | 52 | For use with the Linux file system, we use PCEMU as the server name, 53 | FS as the volume name, and then specify a path from the root of the 54 | Linux file system as the location to redirect the drive to. For example: 55 | 56 | LREDIR F: PCEMU\FS\USR\SRC 57 | 58 | would create a new redirection for drive F:, where the contents of 59 | /usr/src would appear at the root of drive F:. Note that this establishes 60 | a root for drive F: which will be enforced by DOS. ie, drive F: cannot 61 | be used to access files in /usr or /usr/bin, because those Linux directories 62 | are not in the subtree under /usr/src. 63 | 64 | LREDIR allows you to redirect any drive available to DOS, including one 65 | that is currently a physical drive. This means that you can replace one of 66 | your startup drives with a redirection. When you delete the redirection, 67 | the physical drive will become visible again. This can be used so that 68 | the boot diskimage disappears, and is replaced by the mounted MSDOS 69 | file system in Linux, with the drive letter and root the same as before 70 | Linux was installed. For example on my system, I have a partition 71 | with a DOS file system on it. If I boot my machine with a DOS boot 72 | diskette, this partition is my C: drive in DOS. When I boot Linux, I mount 73 | this partition, using the msdos file system type, at location /dos/cdrive. 74 | 75 | For this to work right, you actually need two AUTOEXEC.BAT files, one on 76 | the boot diskimage, and one in the directory that will become the root 77 | of the redirected drive. 78 | 79 | In the AUTOEXEC.BAT in the boot diskimage I put the line: 80 | 81 | LREDIR C: PCEMU\FS\DOS\CDRIVE 82 | 83 | and when DOS runs in DOSEMU, it redirects drive C: to be replaced with 84 | the drive C: I booted from. Also, parsing of the AUTOEXEC.BAT file 85 | will continue with the AUTOEXEC.BAT (if any) on the redirected drive. 86 | 87 | People who use LREDIR in this way should be careful because COMMAND.COM 88 | will continue parsing the AUTOEXEC.BAT from the redirected drive at the 89 | same file offset where it left off in the AUTOEXEC.BAT on the original 90 | C: drive. For this reason, it is best to have the LREDIR command on the 91 | first line of the original (diskimage) AUTOEXEC.BAT, and have the line 92 | be identical in the AUTOEXEC.BAT on the redirected drive. Is this clear 93 | as mud? 94 | 95 | -------------------------------------------------------------------------------- /programs/vga50.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidgiven/pcemu/88061c7ad5efd5343bb42d97f14756881bc97e4e/programs/vga50.com -------------------------------------------------------------------------------- /vga.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is VGA.C It contains stuff about the VGA BIOS */ 16 | 17 | #include "global.h" 18 | 19 | #include 20 | #include 21 | 22 | #include "vga.h" 23 | #include "bios.h" 24 | #include "cpu.h" 25 | #include "vgahard.h" 26 | #include "video.h" 27 | #include "hardware.h" 28 | 29 | #define MAXPAGES 8 30 | 31 | #define VIDEOFUNCTIONALITY 0x2000 32 | 33 | static BYTE *data_segment; /* pointer to 0040:0000 */ 34 | static BYTE *screen_mem; /* pointer to screen memory */ 35 | 36 | #define MAXMODE (sizeof defaults/sizeof defaults[0]) 37 | 38 | static struct 39 | { 40 | int cs, ce; 41 | int sx, sy; 42 | int colours; 43 | int pages; 44 | int base; 45 | int text; 46 | } defaults[] = 47 | { 48 | { 6, 7, 40, 25, 16, 8, 0xb800, TRUE }, /* Mode 0x00 */ 49 | { 6, 7, 40, 25, 16, 8, 0xb800, TRUE }, /* Mode 0x01 */ 50 | { 6, 7, 80, 25, 16, 8, 0xb800, TRUE }, /* Mode 0x02 */ 51 | { 6, 7, 80, 25, 16, 8, 0xb800, TRUE }, /* Mode 0x03 */ 52 | { 0, 0, 320, 200, 4, 4, 0xb800, FALSE }, /* Mode 0x04 */ 53 | { 0, 0, 320, 200, 4, 4, 0xb800, FALSE }, /* Mode 0x05 */ 54 | { 0, 0, 640, 200, 2, 4, 0xb800, FALSE }, /* Mode 0x06 */ 55 | { 11, 12, 80, 25, 2, 8, 0xb000, TRUE }, /* Mode 0x07 */ 56 | { 0, 0, 0, 0, 0, 0, 0, FALSE }, /* Mode 0x08 */ 57 | { 0, 0, 0, 0, 0, 0, 0, FALSE }, /* Mode 0x09 */ 58 | { 0, 0, 0, 0, 0, 0, 0, FALSE }, /* Mode 0x0a */ 59 | { 0, 0, 0, 0, 0, 0, 0, FALSE }, /* Mode 0x0b */ 60 | { 0, 0, 0, 0, 0, 0, 0, FALSE }, /* Mode 0x0c */ 61 | { 0, 0, 320, 200, 16, 8, 0xa000, FALSE },/* Mode 0x0d */ 62 | { 0, 0, 640, 200, 16, 4, 0xa000, FALSE },/* Mode 0x0e */ 63 | { 0, 0, 640, 350, 2, 2, 0xa000, FALSE }, /* Mode 0x0f */ 64 | { 0, 0, 640, 350, 16, 2, 0xa000, FALSE },/* Mode 0x10 */ 65 | { 0, 0, 640, 480, 2, 1, 0xa000, FALSE }, /* Mode 0x11 */ 66 | { 0, 0, 640, 480, 16, 1, 0xa000, FALSE },/* Mode 0x12 */ 67 | { 0, 0, 320, 200, 256, 1, 0xa000, FALSE },/* Mode 0x13 */ 68 | }; 69 | 70 | int mono; /* TRUE if on monochrome screen */ 71 | 72 | /* Remember: screen height is stored one less than actual!!! */ 73 | 74 | #define SetMode(m) PutMemB(data_segment, 0x49, m) 75 | #define GetMode() GetMemB(data_segment, 0x49) 76 | #define SetWidth(w) PutMemW(data_segment, 0x4a, w) 77 | #define GetWidth() GetMemW(data_segment, 0x4a) 78 | #define SetHeight(h) PutMemB(data_segment, 0x84, h) 79 | #define GetHeight() GetMemB(data_segment, 0x84) 80 | #define SetSize(s) PutMemW(data_segment, 0x4c, s) 81 | #define GetSize() GetMemW(data_segment, 0x4c) 82 | #define SetOffset(o) PutMemW(data_segment, 0x4e, o) 83 | #define GetOffset() GetMemW(data_segment, 0x4e) 84 | #define SetCx(page,cx) PutMemB(data_segment, 0x50+(page << 1), cx) 85 | #define GetCx(page) GetMemB(data_segment, 0x50+(page << 1)) 86 | #define SetCy(page,cy) PutMemB(data_segment, 0x51+(page << 1), cy) 87 | #define GetCy(page) GetMemB(data_segment, 0x51+(page << 1)) 88 | #define SetCs(s) PutMemB(data_segment, 0x61, s) 89 | #define GetCs() GetMemB(data_segment, 0x61) 90 | #define SetCe(s) PutMemB(data_segment, 0x60, s) 91 | #define GetCe() GetMemB(data_segment, 0x60) 92 | #define SetCp(cp) PutMemB(data_segment, 0x62, cp) 93 | #define GetCp() GetMemB(data_segment, 0x62) 94 | #define GetCRT() GetMemW(data_segment, 0x63) 95 | #define SetCRT(c) PutMemW(data_segment, 0x63, c) 96 | #define SetCharHeight(c) PutMemW(data_segment, 0x85, c) 97 | #define GetCharHeight() GetMemW(data_segment, 0x85) 98 | 99 | static int cur_emulate = TRUE; 100 | static int pages; /* Maximum number of pages */ 101 | 102 | #define page_start(page) &screen_mem[GetSize()*(page)] 103 | 104 | 105 | static BYTE functionality[] = 106 | { 107 | 0xff, /* Modes 0->7 supported */ 108 | 0x00, /* Modes 8->0x0f not supported yet */ 109 | 0x00, /* Modes 0x10->0x13 not supported yet */ 110 | 0,0,0,0, /* Reserved bytes */ 111 | 0x04, /* Only 400 scan lines supported at the moment */ 112 | 0x01, /* Character blocks */ 113 | 0x01, /* Number of active character blocks */ 114 | 0x04+0x08+0x16, /* Various functions */ 115 | 0x04+0x08, /* ditto */ 116 | 0,0, /* Reserved */ 117 | 0x00, /* Various saved things */ 118 | 0x00, /* Reserved */ 119 | }; 120 | 121 | 122 | static BYTE *get_offset(int page) 123 | { 124 | return &screen_mem[(GetSize() * page) + (2 * (GetCx(page) + 125 | GetCy(page)*GetWidth()))]; 126 | } 127 | 128 | 129 | static void clearscr(int x1,int y1,int x2,int y2,int attr) 130 | { 131 | BYTE *scr = &screen_mem[GetOffset()]; 132 | int x,y; 133 | unsigned width = GetWidth(); 134 | 135 | for (y = y1; y <= y2; y++) 136 | { 137 | for (x = x1; x <= x2; x++) 138 | { 139 | scr[2*(x+y*width)] = ' '; 140 | scr[2*(x+y*width)+1] = (BYTE)attr; 141 | } 142 | } 143 | update_display(); 144 | } 145 | 146 | 147 | static void scroll(int x1, int y1, int x2, int y2, int num, int attr) 148 | { 149 | int x,y; 150 | unsigned width = GetWidth(); 151 | BYTE *scr; 152 | 153 | if (x1 > x2 || y1 > y2) 154 | return; 155 | 156 | scr = &screen_mem[GetOffset()]; 157 | 158 | if (num == 0 || y2-y1 < abs(num)) 159 | { 160 | clearscr(x1,y1,x2,y2, attr); 161 | return; 162 | } 163 | 164 | if (num > 0) 165 | { 166 | disable(); /* To prevent occasional screen glitch */ 167 | for (y = y1; y <= y2-num; y++) 168 | for (x = x1; x <= x2; x++) 169 | { 170 | scr[2*(x+y*width)] = scr[2*(x+(y+num)*width)]; 171 | scr[2*(x+y*width)+1] = scr[2*(x+(y+num)*width)+1]; 172 | } 173 | y = y2-num+1; 174 | copy_text(x1,y1+num,x2,y2,x1,y1); 175 | enable(); 176 | } 177 | else 178 | { 179 | num = -num; 180 | disable(); /* To prevent occasional screen glitch */ 181 | for (y = y2-num; y >= y1; y--) 182 | for (x = x1; x <= x2; x++) 183 | { 184 | scr[2*(x+(y+num)*width)] = scr[2*(x+y*width)]; 185 | scr[2*(x+(y+num)*width)+1] = scr[2*(x+y*width)+1]; 186 | } 187 | y = y1; 188 | copy_text(x1,y1,x2,y2-num,x1,y1+num); 189 | enable(); 190 | } 191 | clearscr(x1,y,x2,y+num-1,attr); 192 | } 193 | 194 | 195 | void set_cursor_type(unsigned start, unsigned end) 196 | { 197 | if (start == 0x20) 198 | set_cursor_height(0, -1); 199 | else 200 | { 201 | start &= 0x1f; 202 | end &= 0x1f; 203 | 204 | SetCs(start); 205 | SetCe(end); 206 | if (cur_emulate && GetMode() <= 3 && start <= 8 && end <= 8) 207 | { 208 | start = (GetCharHeight()*start)/8; 209 | end = (GetCharHeight()*end)/8; 210 | } 211 | set_cursor_height(start, end); 212 | } 213 | } 214 | 215 | 216 | static void set_mode(int mode) 217 | { 218 | if (mode < MAXMODE) 219 | { 220 | if (!mono || (defaults[mode].colours <= 2 && mono)) 221 | { 222 | int i; 223 | 224 | if (!defaults[mode].text) 225 | return; 226 | SetMode(mode); 227 | SetWidth(defaults[mode].sx); 228 | SetHeight(defaults[mode].sy-1); 229 | SetSize(defaults[mode].sx * defaults[mode].sy * 2); 230 | SetCp(0); 231 | SetOffset(0); 232 | if (mode == 0x7) 233 | SetCRT(0x3b4); 234 | else 235 | SetCRT(0x3d4); 236 | pages = defaults[mode].pages; 237 | for (i = 0; i < pages; i++) 238 | { 239 | SetCx(i,0); 240 | SetCy(i,0); 241 | } 242 | SetCharHeight(16); 243 | set_cursor_type(defaults[mode].cs,defaults[mode].ce); 244 | move_cursor(0, 0); 245 | screen_mem = &memory[defaults[mode].base << 4]; 246 | new_screen(GetWidth(), GetHeight()+1, screen_mem); 247 | } 248 | } 249 | } 250 | 251 | 252 | static void display_message(void) 253 | { 254 | static char message1[] = 255 | "PC Emulator v1.01alpha (C) 1994 University of Bristol"; 256 | static char message2[] = 257 | "Please report comments, bugs etc to hedley@cs.bris.ac.uk"; 258 | BYTE *mem = get_offset(0); 259 | int i; 260 | 261 | disable(); 262 | 263 | for (i = 0; i < sizeof message1-1; i++) 264 | mem[i<<1] = message1[i]; 265 | 266 | for (i = 0; i < sizeof message2-1; i++) 267 | mem[(i+80)<<1] = message2[i]; 268 | 269 | SetCx(0, 0); 270 | SetCy(0, 4); 271 | move_cursor(GetCx(0),GetCy(0)); 272 | enable(); 273 | 274 | } 275 | 276 | 277 | static void fill_in_functionality(void) 278 | { 279 | WORD tmp = ChangeE(wregs[DI]); 280 | PutMemW(c_es, tmp, VIDEOFUNCTIONALITY); 281 | tmp += 2; 282 | PutMemW(c_es, tmp, 0xf000); 283 | tmp += 2; 284 | PutMemB(c_es, tmp, GetMode()); 285 | tmp++; 286 | PutMemW(c_es, tmp, GetWidth()); 287 | tmp += 2; 288 | PutMemW(c_es, tmp, GetSize()); 289 | tmp += 2; 290 | PutMemW(c_es, tmp, GetSize() * GetCp()); 291 | tmp += 2; 292 | 293 | PutMemB(c_es, tmp, GetCy(0)); 294 | tmp++; 295 | PutMemB(c_es, tmp, GetCx(0)); 296 | tmp++; 297 | PutMemB(c_es, tmp, GetCy(1)); 298 | tmp++; 299 | PutMemB(c_es, tmp, GetCx(1)); 300 | tmp++; 301 | PutMemB(c_es, tmp, GetCy(2)); 302 | tmp++; 303 | PutMemB(c_es, tmp, GetCx(2)); 304 | tmp++; 305 | PutMemB(c_es, tmp, GetCy(3)); 306 | tmp++; 307 | PutMemB(c_es, tmp, GetCx(3)); 308 | tmp++; 309 | PutMemB(c_es, tmp, GetCy(4)); 310 | tmp++; 311 | PutMemB(c_es, tmp, GetCx(4)); 312 | tmp++; 313 | PutMemB(c_es, tmp, GetCy(5)); 314 | tmp++; 315 | PutMemB(c_es, tmp, GetCx(5)); 316 | tmp++; 317 | PutMemB(c_es, tmp, GetCy(6)); 318 | tmp++; 319 | PutMemB(c_es, tmp, GetCx(6)); 320 | tmp++; 321 | PutMemB(c_es, tmp, GetCy(7)); 322 | tmp++; 323 | PutMemB(c_es, tmp, GetCx(7)); 324 | tmp++; 325 | 326 | PutMemB(c_es, tmp, GetCs()); 327 | tmp++; 328 | PutMemB(c_es, tmp, GetCe()); 329 | tmp++; 330 | PutMemB(c_es, tmp, GetCp()); 331 | tmp++; 332 | 333 | PutMemW(c_es, tmp, GetCRT()); 334 | tmp += 2; 335 | 336 | PutMemB(c_es, tmp, 0); 337 | tmp++; 338 | PutMemB(c_es, tmp, 0); 339 | tmp++; 340 | 341 | PutMemB(c_es, tmp, GetHeight()+1); 342 | tmp++; 343 | PutMemW(c_es, tmp, GetCharHeight()); 344 | tmp += 2; 345 | PutMemB(c_es, tmp, mono ? 7 : 8); 346 | tmp++; 347 | PutMemB(c_es, tmp, 0); 348 | tmp++; 349 | PutMemW(c_es, tmp, mono ? 0 : 256); 350 | tmp += 2; 351 | PutMemB(c_es, tmp, defaults[GetMode()].pages); 352 | tmp++; 353 | PutMemB(c_es, tmp, 0x02); 354 | tmp++; 355 | PutMemB(c_es, tmp, 0); 356 | tmp++; 357 | PutMemB(c_es, tmp, 0); 358 | tmp++; 359 | PutMemB(c_es, tmp, mono ? 4 : 0); 360 | tmp++; 361 | PutMemW(c_es, tmp, 0); 362 | tmp += 2; 363 | PutMemB(c_es, tmp, 0); 364 | tmp++; 365 | PutMemB(c_es, tmp, 3); 366 | tmp++; 367 | PutMemB(c_es, tmp, 1); 368 | } 369 | 370 | 371 | void int_video(void) 372 | { 373 | unsigned page, al; 374 | unsigned height, width; 375 | 376 | D(printf("In Video. Function = %02X\n", *bregs[AH]);); 377 | 378 | CalcAll(); 379 | page = *bregs[BH]; 380 | al = *bregs[AL]; 381 | height = GetHeight(); 382 | width = GetWidth()-1; 383 | 384 | switch(*bregs[AH]) 385 | { 386 | case 0: /* Set mode */ 387 | set_mode(al & 0x7f); 388 | if ((al & 0x80) == 0) 389 | clearscr(0,0,width, height, 0x07); 390 | break; 391 | case 1: /* Set cursor type */ 392 | set_cursor_type(*bregs[CH], *bregs[CL]); 393 | break; 394 | case 2: /* Move cursor position */ 395 | if (page < pages) 396 | { 397 | SetCx(page, *bregs[DL]); 398 | SetCy(page, *bregs[DH]); 399 | move_cursor(GetCx(page),GetCy(page)); 400 | } 401 | break; 402 | case 3: /* Get cursor position */ 403 | if (page < pages) 404 | { 405 | *bregs[CH] = GetCs(); 406 | *bregs[CL] = GetCe(); 407 | *bregs[DL] = GetCx(page); 408 | *bregs[DH] = GetCy(page); 409 | } 410 | break; 411 | case 4: /* Light pen (!) */ 412 | *bregs[AH] = 0; 413 | wregs[BX] = wregs[CX] = wregs[DX] = 0; 414 | break; 415 | case 5: /* Set display page */ 416 | if (al < pages) 417 | { 418 | SetCp(al); 419 | SetOffset(al*GetSize()); 420 | new_screen(width+1, height+1, page_start(al)); 421 | update_display(); 422 | } 423 | break; 424 | case 6: /* Scroll down/clear window */ 425 | scroll(*bregs[CL], *bregs[CH], *bregs[DL], *bregs[DH], al, *bregs[BH]); 426 | break; 427 | case 7: /* Scroll up/clear window */ 428 | scroll(*bregs[CL], *bregs[CH], *bregs[DL], *bregs[DH], -al,*bregs[BH]); 429 | break; 430 | case 8: /* Read character and attribute at cursor */ 431 | if (page < pages) 432 | { 433 | BYTE *pos = get_offset(page); 434 | 435 | *bregs[AL] = *pos++; 436 | *bregs[AH] = *pos; 437 | } 438 | break; 439 | case 9: /* Write character(s) and attribute(s) at cursor */ 440 | if (page < pages) 441 | { 442 | BYTE *pos = get_offset(page); 443 | unsigned i, count; 444 | 445 | count = ChangeE(wregs[CX]); 446 | for (i = count; i > 0; i--) 447 | { 448 | *pos++ = al; 449 | *pos++ = *bregs[BL]; 450 | } 451 | if (count > 1) 452 | update_display(); 453 | else 454 | if (count == 1) 455 | displaychar(); 456 | } 457 | break; 458 | case 0x0a: /* Write character at cursor */ 459 | if (page < pages) 460 | { 461 | BYTE *pos = get_offset(page); 462 | unsigned i, count; 463 | 464 | count = ChangeE(wregs[CX]); 465 | for (i = count; i > 0; i--) 466 | *pos++ = al; 467 | 468 | if (count > 1) 469 | update_display(); 470 | else 471 | if (count == 1) 472 | displaychar(); 473 | } 474 | break; 475 | 476 | case 0x0b: /* Set palette/background/border */ 477 | break; 478 | case 0x0e: /* Write character in teletype mode */ 479 | if (page < pages) 480 | { 481 | BYTE *pos = get_offset(page); 482 | int x,y; 483 | 484 | x = GetCx(page); 485 | y = GetCy(page); 486 | switch(al) 487 | { 488 | case 0x0a: /* Line feed */ 489 | y++; 490 | break; 491 | case 0x0d: /* Return */ 492 | x = 0; 493 | break; 494 | case 0x8: /* Backspace */ 495 | x--; 496 | break; 497 | case 0x7: /* Bell */ 498 | fprintf(stderr,"\a"); 499 | fflush(stderr); 500 | break; 501 | default: 502 | *pos = al; 503 | x++; 504 | displaychar(); 505 | } 506 | if (x > width) 507 | { 508 | x = 0; 509 | y++; 510 | } 511 | if (x < 0) 512 | { 513 | x = width; 514 | y--; 515 | } 516 | if (y > height) 517 | { 518 | BYTE attr; 519 | y = height; 520 | attr = screen_mem[GetSize()*(page+1) -1]; 521 | scroll(0,0,width,y,1,attr); 522 | } 523 | if (y < 0) 524 | { 525 | y = 0; 526 | scroll(0,0,width,height,-1,7); 527 | } 528 | SetCx(page,x); 529 | SetCy(page,y); 530 | move_cursor(x,y); 531 | } 532 | break; 533 | case 0x0f: /* Return information */ 534 | *bregs[AL] = GetMode(); 535 | *bregs[AH] = width+1; 536 | *bregs[BH] = GetCp(); 537 | break; 538 | case 0x10: /* Colour/palette stuff... */ 539 | break; 540 | case 0x11: /* Font stuff... */ 541 | switch(*bregs[AL]) 542 | { 543 | case 0x02: /* Load rom 8x8 font (set 50/42 lines) */ 544 | case 0x12: 545 | height = 49; 546 | SetHeight(height); 547 | SetSize((width+1) * (height+1) * 2); 548 | new_screen(width+1, height+1, screen_mem); 549 | clearscr(0,0,width, height, 0x07); 550 | break; 551 | case 0x30: /* Get font information */ 552 | switch(*bregs[BH]) 553 | { 554 | default: 555 | wregs[CX] = ChangeE(16); 556 | *bregs[DL] = height; 557 | sregs[ES] = 0xf000; 558 | c_es = SegToMemPtr(ES); 559 | wregs[BP] = ChangeE(0); 560 | } 561 | break; 562 | default: 563 | printf("Unimplemented int 0x10 function 0x11 sub-function %02X\n",*bregs[AL]); 564 | #ifdef DEBUG 565 | loc(); 566 | exit_emu(); 567 | #endif 568 | break; 569 | } 570 | break; 571 | case 0x12: /* Display information */ 572 | switch(*bregs[BL]) 573 | { 574 | case 0x10: /* Get config info */ 575 | *bregs[BH] = mono; 576 | *bregs[BL] = 3; 577 | wregs[CX] = ChangeE(0); 578 | break; 579 | case 0x30: /* Set scan lines */ 580 | *bregs[AL] = 0x12; 581 | break; 582 | case 0x34: /* Enable/disable cursor emulation */ 583 | cur_emulate = *bregs[AL] == 0; 584 | *bregs[AL] = 0x12; 585 | break; 586 | default: 587 | printf("Unimplemented int 10 function 0x12 sub-function 0x%02X\n",*bregs[BL]); 588 | #ifdef DEBUG 589 | loc(); 590 | exit_emu(); 591 | #endif 592 | break; 593 | } 594 | break; 595 | case 0x1a: /* Get/Set display combination */ 596 | if (*bregs[AL] == 0) 597 | { 598 | *bregs[BL] = mono ? 7 : 8; 599 | *bregs[BH] = 0; 600 | *bregs[AL] = 0x1a; 601 | } 602 | break; 603 | case 0x1b: /* Get functionality/state information etc */ 604 | fill_in_functionality(); 605 | *bregs[AL] = 0x1b; 606 | break; 607 | case 0x30: /* ??? Called by MSD.EXE */ 608 | case 0x4f: /* VESA functions... */ 609 | case 0x6f: /* ??? Called by borland C */ 610 | case 0xcc: /* ??? Called by Norton's disk edit */ 611 | case 0xef: /* ??? Called by QBASIC.EXE */ 612 | case 0xfa: /* ??? Called by MSD.EXE (Microsoft Diagonstics) */ 613 | case 0xfe: /* ??? - but several programs call it. Appears to do nothing */ 614 | case 0xff: /* ??? Called by WordPerfect 5.1 */ 615 | break; 616 | default: 617 | printf("Unimplemented int 10 function: %02X. AL = %02X BL = %02X\n", 618 | *bregs[AH], *bregs[AL], *bregs[BL]); 619 | #ifdef DEBUG 620 | loc(); 621 | exit_emu(); 622 | #endif 623 | break; 624 | } 625 | } 626 | 627 | void init_vga(void) 628 | { 629 | int mode = mono ? 7 : 3; 630 | static BYTE afterint[] = 631 | { 632 | 0xfb, 0xca, 0x02, 0x00 633 | }; 634 | 635 | init_hardware(); 636 | 637 | screen_mem = &memory[defaults[mode].base << 4]; 638 | data_segment = &memory[0x00400]; 639 | 640 | memcpy(&memory[0xf0000+VIDEOFUNCTIONALITY], &functionality, sizeof functionality); 641 | 642 | set_mode(mode); 643 | clearscr(0,0,GetWidth()-1, GetHeight(), 0x07); 644 | set_int(0x10, NULL, 0, int_video, afterint, sizeof afterint); 645 | display_message(); 646 | } 647 | 648 | void vga_off(void) 649 | { 650 | finish_hardware(); 651 | } 652 | -------------------------------------------------------------------------------- /vga.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is VGA.H It contains definitions for the VGA BIOS functions */ 16 | 17 | 18 | #ifndef VGA_H 19 | #define VGA_H 20 | 21 | #define VIDEOMEM (256*1024) 22 | 23 | extern int mono; 24 | 25 | void init_vga(void); 26 | void vga_off(void); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /vga.pcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidgiven/pcemu/88061c7ad5efd5343bb42d97f14756881bc97e4e/vga.pcf -------------------------------------------------------------------------------- /vgahard.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is VGA.C It contains stuff about the VGA hardware adapter */ 16 | 17 | #include "global.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "vga.h" 25 | #include "vgahard.h" 26 | #include "video.h" 27 | #include "hardware.h" 28 | 29 | #ifndef CURSORSPEED 30 | #define CURSORSPEED 30 31 | #endif 32 | 33 | #ifndef UPDATESPEED 34 | #define UPDATESPEED 5 35 | #endif 36 | 37 | #define BUFFER_DELAY 5 38 | 39 | static BYTE *screen_mem; /* pointer to screen memory */ 40 | 41 | extern int mono; /* TRUE if on monochrome screen */ 42 | 43 | static unsigned cx,cy; /* cursor position */ 44 | static int cs,ce; /* cursor start/end (height) */ 45 | static int height, width; /* screen size */ 46 | 47 | static volatile int busy = 0; 48 | 49 | static volatile int cursoron = FALSE; 50 | 51 | static unsigned tick_count; 52 | static unsigned chars_printed; 53 | static unsigned cursor_printed; 54 | 55 | static volatile int refresh_count = 1; 56 | static volatile int cursor_count = 1; 57 | 58 | static int refresh_speed = UPDATESPEED; 59 | static int cursor_speed = CURSORSPEED; 60 | 61 | static BYTE *disp_buffer; 62 | static BYTE *frame_buffer; 63 | 64 | 65 | static void toggle_cursor(void) 66 | { 67 | busy = TRUE; 68 | cursoron = !cursoron; 69 | 70 | if (cursoron) 71 | put_cursor(cx, cy); 72 | else 73 | unput_cursor(); 74 | 75 | busy = FALSE; 76 | } 77 | 78 | 79 | static void blank_cursor(void) 80 | { 81 | if (cursoron) 82 | { 83 | cursoron = FALSE; 84 | unput_cursor(); 85 | } 86 | } 87 | 88 | 89 | static void draw_cursor(void) 90 | { 91 | if (!cursoron) 92 | { 93 | if (cx < width && cy < height && ce > cs) 94 | { 95 | cursoron = TRUE; 96 | put_cursor(cx,cy); 97 | } 98 | } 99 | } 100 | 101 | 102 | void move_cursor(unsigned x, unsigned y) 103 | { 104 | static unsigned last_count; 105 | 106 | busy = TRUE; 107 | cx = x; 108 | cy = y; 109 | 110 | if (cursor_printed >= 1 && tick_count >= last_count && 111 | tick_count < last_count+BUFFER_DELAY) 112 | { 113 | last_count = tick_count; 114 | } 115 | else 116 | { 117 | last_count = tick_count; 118 | cursor_printed++; 119 | 120 | blank_cursor(); 121 | draw_cursor(); 122 | } 123 | 124 | busy = FALSE; 125 | } 126 | 127 | 128 | void copy_text(unsigned x1, unsigned y1, unsigned x2, unsigned y2, 129 | unsigned nx, unsigned ny) 130 | { 131 | unsigned w,h, bwidth, bheight; 132 | BYTE *src,*dest; 133 | 134 | busy = TRUE; 135 | blank_cursor(); 136 | copy(x1,y1,x2,y2,nx,ny); 137 | 138 | bwidth = x2-x1+1; 139 | bheight = y2-y1+1; 140 | 141 | if ((ny > y1 && nx >= x1) || (ny >= y1 && nx < x1)) 142 | { 143 | dest = &frame_buffer[2*((ny+bheight)*width+(nx+bwidth))]; 144 | src = &frame_buffer[2*(y2*width+x2)]; 145 | 146 | for (h = bheight; h > 0; h--) 147 | { 148 | for (w = 2*bwidth; w > 0; w--) 149 | *--dest = *--src; 150 | 151 | dest -= (width-bwidth); 152 | src -= (width-bwidth); 153 | } 154 | } 155 | else 156 | { 157 | dest = &frame_buffer[2*(ny*width+nx)]; 158 | src = &frame_buffer[2*(y1*width+x1)]; 159 | 160 | for (h = bheight; h > 0; h--) 161 | { 162 | for (w = 2*bwidth; w > 0; w--) 163 | *dest++ = *src++; 164 | 165 | dest += (width-bwidth); 166 | src += (width-bwidth); 167 | } 168 | } 169 | 170 | draw_cursor(); 171 | busy = FALSE; 172 | } 173 | 174 | 175 | void set_cursor_height(int s, int e) 176 | { 177 | busy = TRUE; 178 | cs = s; 179 | ce = e; 180 | blank_cursor(); 181 | new_cursor(s, e); 182 | draw_cursor(); 183 | busy = FALSE; 184 | } 185 | 186 | 187 | void new_screen(unsigned w, unsigned h, BYTE *mem) 188 | { 189 | busy = TRUE; 190 | 191 | screen_mem = mem; 192 | if (width != w || height != h) 193 | { 194 | if (width != w) 195 | { 196 | if (disp_buffer) 197 | free(disp_buffer); 198 | 199 | width = w; 200 | disp_buffer = (BYTE *)malloc(width+1); 201 | disp_buffer[width] = '\0'; 202 | } 203 | 204 | if (frame_buffer) 205 | free(frame_buffer); 206 | 207 | height = h; 208 | frame_buffer = (BYTE *)malloc(width*height*2+1); 209 | memset(frame_buffer, 0, width*height*2); 210 | 211 | window_size(width, height); 212 | } 213 | busy = FALSE; 214 | } 215 | 216 | 217 | void update_display(void) 218 | { 219 | register BYTE *scr = frame_buffer; 220 | register BYTE *mem = screen_mem; 221 | unsigned row,col,startcol; 222 | BYTE *end; 223 | BYTE *bufptr; 224 | BYTE attr; 225 | 226 | busy = TRUE; 227 | 228 | end = &scr[width*height*2]; 229 | *end = mem[width*height*2]+1; 230 | 231 | for(;;) 232 | { 233 | while (*scr == *mem) 234 | { 235 | scr++; 236 | mem++; 237 | } 238 | 239 | if (scr == end) 240 | break; 241 | 242 | blank_cursor(); 243 | 244 | col = (scr-frame_buffer) % (2*width); 245 | row = (scr-frame_buffer) / (2*width); 246 | 247 | bufptr = disp_buffer; 248 | startcol = col >> 1; 249 | 250 | if (col & 1) 251 | { 252 | attr = *mem; 253 | col--; 254 | scr--; 255 | mem--; 256 | } 257 | else 258 | attr = mem[1]; 259 | 260 | do 261 | { 262 | *bufptr++ = (*scr++ = *mem) ? *mem : 0x20; 263 | *scr++ = attr; 264 | mem += 2; 265 | col += 2; 266 | } while((*scr != *mem || scr[1] != mem[1]) && mem[1] == attr && 267 | col < 2*width); 268 | 269 | draw_line(startcol, row,(char *)disp_buffer, bufptr-disp_buffer, attr); 270 | } 271 | 272 | if (cursor_speed <= 0) 273 | draw_cursor(); 274 | busy = FALSE; 275 | } 276 | 277 | 278 | static void update_displayline(unsigned line) 279 | { 280 | unsigned x, startcol; 281 | BYTE *scr, *buf, *mem, attr; 282 | 283 | mem = &screen_mem[line*width*2]; 284 | scr = &frame_buffer[line*width*2]; 285 | 286 | busy = TRUE; 287 | blank_cursor(); 288 | 289 | x = 0; 290 | while (x < width) 291 | { 292 | buf = disp_buffer; 293 | attr = mem[1]; 294 | 295 | startcol = x; 296 | do 297 | { 298 | *buf++ = (*scr++ = *mem) ? *mem : 0x20; 299 | mem++; 300 | *scr++ = *mem++; 301 | x++; 302 | } while (x < width && mem[1] == attr); 303 | 304 | draw_line(startcol, line, (char *)disp_buffer, buf-disp_buffer, attr); 305 | } 306 | draw_cursor(); 307 | busy = FALSE; 308 | } 309 | 310 | 311 | void pcemu_refresh(void) 312 | { 313 | unsigned h; 314 | 315 | for (h = 0; h < height; h++) 316 | update_displayline(h); 317 | } 318 | 319 | 320 | void displaychar(void) 321 | { 322 | BYTE *mem; 323 | static unsigned last_count; 324 | 325 | if (chars_printed >= 1 && tick_count >= last_count && 326 | tick_count < last_count+BUFFER_DELAY) 327 | { 328 | last_count = tick_count; 329 | return; 330 | } 331 | 332 | last_count = tick_count; 333 | chars_printed++; 334 | 335 | mem = &screen_mem[2*(cx+cy*width)]; 336 | 337 | /* frame_buffer[2*(cx+cy*width)] = *mem; 338 | frame_buffer[2*(cx+cy*width)+1] = mem[1]; 339 | */ 340 | 341 | busy = TRUE; 342 | /* blank_cursor(); */ 343 | update_display(); 344 | /* draw_char(cx, cy, *mem, mem[1]); */ 345 | busy = FALSE; 346 | } 347 | 348 | 349 | void init_hardware(void) 350 | { 351 | busy = TRUE; 352 | set_cursor_height(14,15); 353 | busy = FALSE; 354 | } 355 | 356 | 357 | void finish_hardware(void) 358 | { 359 | busy = TRUE; 360 | end_video(); 361 | busy = FALSE; 362 | } 363 | 364 | 365 | void vga_interrupt(void) 366 | { 367 | tick_count++; 368 | if (!busy) 369 | { 370 | process_events(); 371 | if (cursor_speed > 0 && --cursor_count == 0) 372 | { 373 | cursor_count = cursor_speed; 374 | toggle_cursor(); 375 | } 376 | if (--refresh_count == 0) 377 | { 378 | refresh_count = refresh_speed; 379 | chars_printed = 0; 380 | cursor_printed = 0; 381 | update_display(); 382 | flush_video(); 383 | } 384 | } 385 | } 386 | 387 | 388 | char *set_update_rate(int frames) 389 | { 390 | if (frames > 0) 391 | { 392 | refresh_speed = frames; 393 | return NULL; 394 | } 395 | 396 | return "Invalid update speed"; 397 | } 398 | 399 | 400 | char *set_cursor_rate(int frames) 401 | { 402 | cursor_speed = frames; 403 | return NULL; 404 | } 405 | 406 | 407 | 408 | -------------------------------------------------------------------------------- /vgahard.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | /* This is VGAHARD.H It contains definitions for the VGA hardware */ 16 | 17 | 18 | #ifndef VGAHARD_H 19 | #define VGAHARD_H 20 | 21 | #include "mytypes.h" 22 | 23 | void new_screen(unsigned, unsigned, BYTE *); 24 | void pcemu_refresh(void); 25 | void update_display(void); 26 | void displaychar(void); 27 | void move_cursor(unsigned, unsigned); 28 | void set_cursor_height(int, int); 29 | void init_hardware(void); 30 | void finish_hardware(void); 31 | void copy_text(unsigned, unsigned, unsigned, unsigned, unsigned, unsigned); 32 | 33 | void vga_interrupt(void); 34 | 35 | char *set_update_rate(int); 36 | char *set_cursor_rate(int); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /video.c: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "video.h" 3 | #include 4 | 5 | VIDEO_DRIVER *video_driver; 6 | 7 | void put_cursor(unsigned x, unsigned y) 8 | { 9 | video_driver->put_cursor(x, y); 10 | } 11 | 12 | void unput_cursor(void) 13 | { 14 | video_driver->unput_cursor(); 15 | } 16 | 17 | extern VIDEO_DRIVER curses_video; 18 | extern VIDEO_DRIVER x_video; 19 | 20 | static VIDEO_DRIVER *modes[] = { 21 | #ifndef DISABLEX 22 | &x_video, 23 | #endif 24 | #ifndef DISABLECURSES 25 | &curses_video 26 | #endif 27 | }; 28 | 29 | #define NUM_MODES (sizeof(modes)/sizeof(*modes)) 30 | 31 | const char *set_video_mode(const char *mode) 32 | { 33 | int i; 34 | for (i=0; iname, mode)) { 36 | video_driver = modes[i]; 37 | return NULL; 38 | } 39 | } 40 | return "Invalid video mode."; 41 | } 42 | 43 | void init_video(void) 44 | { 45 | if (video_driver == NULL) 46 | video_driver = modes[0]; 47 | video_driver->init(); 48 | } 49 | 50 | void copy(unsigned x1, unsigned y1, unsigned x2, unsigned y2, unsigned newx, unsigned newy) 51 | { 52 | video_driver->copy(x1, y1, x2, y2, newx, newy); 53 | } 54 | 55 | void new_cursor(int st, int end) 56 | { 57 | video_driver->new_cursor(st, end); 58 | } 59 | 60 | void window_size(unsigned width, unsigned height) 61 | { 62 | video_driver->window_size(width, height); 63 | } 64 | 65 | void draw_line(unsigned x, unsigned y, const char *text, unsigned len, BYTE attr) 66 | { 67 | video_driver->draw_line(x, y, text, len, attr); 68 | } 69 | 70 | void end_video(void) 71 | { 72 | video_driver->end(); 73 | } 74 | 75 | void process_events(void) 76 | { 77 | video_driver->process_events(); 78 | } 79 | 80 | void flush_video(void) 81 | { 82 | video_driver->flush(); 83 | } 84 | -------------------------------------------------------------------------------- /video.h: -------------------------------------------------------------------------------- 1 | /* Simple abstraction to the video driver. 2 | The video driver is already very simple. 3 | */ 4 | #ifndef VIDEO_INCLUDE 5 | #define VIDEO_INCLUDE 6 | 7 | typedef struct 8 | { 9 | const char *name; 10 | void (*init)(void); 11 | void (*end)(void); 12 | void (*flush)(void); 13 | void (*put_cursor)(unsigned x, unsigned y); 14 | void (*unput_cursor)(void); 15 | void (*copy)(unsigned x1, unsigned y1, unsigned x2, unsigned y2, unsigned newx, unsigned newy); 16 | void (*new_cursor)(int st, int end); 17 | void (*window_size)(unsigned width, unsigned height); 18 | void (*draw_line)(unsigned x, unsigned y, const char *text, unsigned len, BYTE attr); 19 | void (*process_events)(void); 20 | } VIDEO_DRIVER; 21 | 22 | void put_cursor(unsigned x, unsigned y); 23 | void unput_cursor(void); 24 | void copy(unsigned x1, unsigned y1, unsigned x2, unsigned y2, unsigned newx, unsigned newy); 25 | void new_cursor(int st, int end); 26 | void window_size(unsigned width, unsigned height); 27 | void draw_line(unsigned x, unsigned y, const char *text, unsigned len, BYTE attr); 28 | 29 | extern VIDEO_DRIVER *video_driver; 30 | 31 | void init_video(void); 32 | void end_video(void); 33 | const char *set_video_mode(const char *mode); 34 | void process_events(void); 35 | void flush_video(void); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /xstuff.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * * 3 | * Third Year Project * 4 | * * 5 | * An IBM PC Emulator * 6 | * For Unix and X Windows * 7 | * * 8 | * By David Hedley * 9 | * * 10 | * * 11 | * This program is Copyrighted. Consult the file COPYRIGHT for more details * 12 | * * 13 | ****************************************************************************/ 14 | 15 | #ifndef XSTUFF_H 16 | #define XSTUFF_H 17 | 18 | void start_X(void); 19 | void end_X(void); 20 | void process_Xevents(void); 21 | void flush_X(void); 22 | 23 | void copy(unsigned, unsigned, unsigned, unsigned, unsigned, unsigned); 24 | void draw_char(unsigned, unsigned, char, BYTE); 25 | void draw_line(unsigned, unsigned, char *, unsigned, BYTE); 26 | void clear_screen(void); 27 | void window_size(unsigned, unsigned); 28 | 29 | void new_cursor(int, int); 30 | void put_cursor(unsigned, unsigned); 31 | void unput_cursor(void); 32 | 33 | extern int graphics,blink; 34 | #endif 35 | --------------------------------------------------------------------------------