Updated aspect ratio for CGA configs and added experimental 'aspect' URL parameter

This commit is contained in:
Jeff Parsons 2016-04-01 21:34:47 -07:00
commit d50f0ebb1a
44 changed files with 6634 additions and 318 deletions

113
modules/pcjs/README.md Normal file
View file

@ -0,0 +1,113 @@
---
layout: page
title: IBM PC Emulation Module
permalink: /modules/pcjs/
---
IBM PC Emulation Module
===
Structure
---
The PCjs IBM PC Emulation Module divides PC functionality into variety of logical and visual components.
In general, each JavaScript file is responsible for a single component or set of related components (eg,
[chipset.js](lib/chipset.js)). Most components represent familiar PC devices, such as video cards, disk
controllers, etc.
*Component* is an overloaded term, since **Component** is also the name of the shared base class in
[component.js](../shared/lib/component.js) used by most machine components. A few low-level components
(eg, the **Memory** and **State** components, the Card class of the **Video** component, the Color and Rectangle
classes of the **Panel** component, etc) do not extend **Component**, so don't assume that every PCjs object has
access to [component.js](../shared/lib/component.js) methods.
Examples of non-device components include visual components like [panel.js](lib/panel.js) and
[debugger.js](lib/debugger.js), and sub-components like [x86ops.js](lib/x86ops.js) and [x86func.js](lib/x86func.js),
which separate the CPU functionality of [x86.js](lib/x86.js) into more manageable pieces.
These components should always be loaded or compiled in the order listed by the *pcJSFiles* property in
[package.json](../../package.json), which includes all the necessary *shared* components as well.
At the time of this writing, the recommended order is:
* [shared/defines.js](../shared/lib/defines.js)
* [shared/diskapi.js](../shared/lib/diskapi.js)
* [shared/dumpapi.js](../shared/lib/dumpapi.js)
* [shared/reportapi.js](../shared/lib/reportapi.js)
* [shared/userapi.js](../shared/lib/userapi.js)
* [shared/strlib.js](../shared/lib/strlib.js)
* [shared/usrlib.js](../shared/lib/usrlib.js)
* [shared/weblib.js](../shared/lib/weblib.js)
* [shared/component.js](../shared/lib/component.js)
* [pcjs/defines.js](lib/defines.js)
* [pcjs/x86.js](lib/x86.js)
* [pcjs/interrupts.js](lib/interrupts.js)
* [pcjs/messages.js](lib/messages.js)
* [pcjs/panel.js](lib/panel.js)
* [pcjs/bus.js](lib/bus.js)
* [pcjs/memory.js](lib/memory.js)
* [pcjs/cpu.js](lib/cpu.js)
* [pcjs/x86seg.js](lib/x86seg.js)
* [pcjs/x86cpu.js](lib/x86cpu.js)
* [pcjs/x86fpu.js](lib/x86fpu.js)
* [pcjs/x86func.js](lib/x86func.js)
* [pcjs/x86help.js](lib/x86help.js)
* [pcjs/x86mods.js](lib/x86mods.js)
* [pcjs/x86ops.js](lib/x86ops.js)
* [pcjs/x86op0f.js](lib/x86op0f.js)
* [pcjs/chipset.js](lib/chipset.js)
* [pcjs/rom.js](lib/rom.js)
* [pcjs/ram.js](lib/ram.js)
* [pcjs/keyboard.js](lib/keyboard.js)
* [pcjs/video.js](lib/video.js)
* [pcjs/parallelport.js](lib/parallelport.js)
* [pcjs/serialport.js](lib/serialport.js)
* [pcjs/mouse.js](lib/mouse.js)
* [pcjs/disk.js](lib/disk.js)
* [pcjs/fdc.js](lib/fdc.js)
* [pcjs/hdc.js](lib/hdc.js)
* [pcjs/debugger.js](lib/debugger.js)
* [pcjs/state.js](lib/state.js)
* [pcjs/computer.js](lib/computer.js)
* [shared/embed.js](../shared/lib/embed.js)
* [shared/save.js](../shared/lib/save.js)
Some of the components *can* be reordered or even omitted (eg, [debugger.js](lib/debugger.js) or
[embed.js](../shared/lib/embed.js)), but you should observe the following:
* [component.js](../shared/lib/component.js) must be listed before any component that extends **Component**
* [panel.js](lib/panel.js) should be loaded early to initialize the Control Panel (if any) as soon as possible
* [computer.js](lib/computer.js) should be the last device component, as it supervises and notifies all the other device components
To minimize ordering requirements, the init() handlers and constructors of all components should avoid
referencing other components. Device components should define an initBus() notification handler, which the
*Computer* component will call after it has created/initialized the *Bus* component.
Features
---
[List of major existing features goes here]
### BackTrack Support
One major PCjs feature is known as BackTrack Support, or simply BackTracks. When BackTracks are enabled, every
memory location (at the byte level) and every general-purpose byte register may have an optional link back to its
source. These links are called BackTrack indexes.
All the code that a virtual machine initially executes enters the machine either via ROM or disk sectors, and as that
code executes, the machine is loading data into registers from memory locations and/or I/O ports and writing the results
to other memory locations and/or I/O ports. BackTracks keep track of that data flow, allowing us to examine the history
of any piece of data at any time, down to the byte level; while this feature could be extended to the bit level, it
would make the feature dramatically more expensive, both in terms of size and speed.
A BackTrack index is encoded as a 32-bit value with three parts:
- Bits 0-8: 9-bit BackTrack object offset (0-511)
- Bits 9-15: 7-bit type and access info
- Bits 16-30: 15-bit BackTrack object number (1-32767, 0 reserved for dynamic data)
This represents a total of 31 bits, with bit 31 reserved.
For example, look at one of the last things a ROM does during boot: loading a disk sector into RAM. It will be up to the
disk controller (or DMA controller, if used) to create a BackTrack object representing the sector that was read,
adding that object to the global BackTrack object array, and then associating the corresponding BackTrack index with
the first byte of RAM where the sector was loaded. Subsequent bytes of RAM containing the rest of the sector will refer
to the same BackTrack object, using BackTrack indexes containing offsets 1-511.

View file

@ -1,108 +0,0 @@
PCjs Sources
===
Structure
---
These JavaScript files divide PCjs functionality into major PC components. Most of the files are device
components, implementing a specific device (or set of devices, in the case of [chipset.js](chipset.js)).
Be aware that *component* is an overloaded term, since **Component** is also the name of the
shared base class in [component.js](../../shared/lib/component.js) used by most machine components.
A few low-level components (eg, the **Memory** and **State** components, the Card class of the **Video**
component, the Color and Rectangle classes of the **Panel** component, etc) do not extend **Component**,
so don't assume that every PCjs object has access to [component.js](../../shared/lib/component.js) methods.
Examples of non-device components include UI components like [panel.js](panel.js) and [debugger.js](debugger.js),
and sub-components like [x86ops.js](x86ops.js) and [x86func.js](x86func.js) that separate the CPU
functionality of [x86.js](x86.js) into more manageable pieces.
These components should always be loaded or compiled in the order listed by the *pcJSFiles* property in
[package.json](../../../package.json), which includes all the necessary *shared* components as well.
At the time of this writing, the recommended order is:
* [shared/defines.js](../../shared/lib/defines.js)
* [shared/diskapi.js](../../shared/lib/diskapi.js)
* [shared/dumpapi.js](../../shared/lib/dumpapi.js)
* [shared/reportapi.js](../../shared/lib/reportapi.js)
* [shared/userapi.js](../../shared/lib/userapi.js)
* [shared/strlib.js](../../shared/lib/strlib.js)
* [shared/usrlib.js](../../shared/lib/usrlib.js)
* [shared/weblib.js](../../shared/lib/weblib.js)
* [shared/component.js](../../shared/lib/component.js)
* [pcjs/defines.js](defines.js)
* [pcjs/x86.js](x86.js)
* [pcjs/interrupts.js](interrupts.js)
* [pcjs/messages.js](messages.js)
* [pcjs/panel.js](panel.js)
* [pcjs/bus.js](bus.js)
* [pcjs/memory.js](memory.js)
* [pcjs/cpu.js](cpu.js)
* [pcjs/x86seg.js](x86seg.js)
* [pcjs/x86cpu.js](x86cpu.js)
* [pcjs/x86cpu.js](x86fpu.js)
* [pcjs/x86func.js](x86func.js)
* [pcjs/x86ops.js](x86ops.js)
* [pcjs/x86op0f.js](x86op0f.js)
* [pcjs/x86modb.js](x86modb.js)
* [pcjs/x86modw.js](x86modw.js)
* [pcjs/x86modb16.js](x86modb16.js)
* [pcjs/x86modw16.js](x86modw16.js)
* [pcjs/x86modb32.js](x86modb32.js)
* [pcjs/x86modw32.js](x86modw32.js)
* [pcjs/x86modsib.js](x86modsib.js)
* [pcjs/chipset.js](chipset.js)
* [pcjs/rom.js](rom.js)
* [pcjs/ram.js](ram.js)
* [pcjs/keyboard.js](keyboard.js)
* [pcjs/video.js](video.js)
* [pcjs/serialport.js](serialport.js)
* [pcjs/mouse.js](mouse.js)
* [pcjs/disk.js](disk.js)
* [pcjs/fdc.js](fdc.js)
* [pcjs/hdc.js](hdc.js)
* [pcjs/debugger.js](debugger.js)
* [pcjs/state.js](state.js)
* [pcjs/computer.js](computer.js)
* [shared/embed.js](../../shared/lib/embed.js)
Some of the components *can* be reordered or even omitted (eg, [debugger.js](debugger.js) or
[embed.js](../../shared/lib/embed.js)), but you should observe the following:
* [component.js](../../shared/lib/component.js) must be listed before any component that extends **Component**
* [panel.js](panel.js) should be loaded early to initialize the Control Panel (if any) as soon as possible
* [computer.js](computer.js) should be the last device component, as it supervises and notifies all the other device components
To minimize ordering requirements, the init() handlers and constructors of all components should avoid
referencing other components. Device components should define an initBus() notification handler, which the
*Computer* component will call after it has created/initialized the *Bus* component.
Features
---
[List of major existing features goes here]
### BackTrack Support
The next major feature to be implemented is referred to as BackTrack Support, or simply BackTracks. When BackTracks
are enabled, every memory location (at the byte level) and every general-purpose byte register may have an optional link
back to its source. These links are called BackTrack indexes.
All the code that a virtual machine initially executes enters the machine either via ROM or disk sectors, and as that
code executes, the machine is loading data into registers from memory locations and/or I/O ports and writing the results
to other memory locations and/or I/O ports. BackTracks keep track of that data flow, allowing us to examine the history
of any piece of data at any time, down to the byte level; while this feature could be extended to the bit level, it
would make the feature dramatically more expensive, both in terms of size and speed.
A BackTrack index is encoded as a 32-bit value with three parts:
- Bits 0-8: 9-bit BackTrack object offset (0-511)
- Bits 9-15: 7-bit type and access info
- Bits 16-30: 15-bit BackTrack object number (1-32767, 0 reserved for dynamic data)
This represents a total of 31 bits, with bit 31 reserved.
For example, look at one of the last things a ROM does during boot: loading a disk sector into RAM. It will be up to the
disk controller (or DMA controller, if used) to create a BackTrack object representing the sector that was read,
adding that object to the global BackTrack object array, and then associating the corresponding BackTrack index with
the first byte of RAM where the sector was loaded. Subsequent bytes of RAM containing the rest of the sector will refer
to the same BackTrack object, using BackTrack indexes containing offsets 1-511.

View file

@ -394,7 +394,7 @@ Computer.prototype.getMachineParm = function(sParm, parmsComponent)
* but there are limits to my paranoia.
*/
var sParmLC = sParm.toLowerCase();
var value = Component.parmsURL && (Component.parmsURL[sParm] || Component.parmsURL[sParmLC]);
var value = Component.parmsURL[sParm] || Component.parmsURL[sParmLC];
if (value === undefined && this.parmsMachine) {
value = this.parmsMachine[sParm];

View file

@ -7260,7 +7260,10 @@ Video.init = function()
*
* HACK: A canvas style of "auto" provides for excellent responsive canvas scaling in EVERY browser
* except IE9/IE10, so I recalculate the appropriate CSS height every time the parent DIV is resized;
* IE11 works without this hack, so we take advantage of the fact that IE11 doesn't report itself as "MSIE".
* IE11 works without this hack, so we take advantage of the fact that IE11 doesn't identify as "MSIE".
*
* The other reason it's good to keep this particular hack limited to IE9/IE10 is that most other
* browsers don't actually support an 'onresize' handler on anything but the window object.
*/
eCanvas.style.height = "auto";
if (web.getUserAgent().indexOf("MSIE") >= 0) {
@ -7271,6 +7274,33 @@ Video.init = function()
}(eVideo, eCanvas, parmsVideo['screenWidth'], parmsVideo['screenHeight']);
eVideo.onresize();
}
/*
* The following is a related hack that allows the user to force the machine to use a particular aspect
* ratio if an 'aspect' URL parameter is set. Initially, it's just for testing purposes until we figure
* out a better UI. And note that we use our web.onPageEvent() helper function to make sure we don't
* trample on any other 'onresize' handler(s) attached to the window object.
*/
var aspect = +Component.parmsURL['aspect'];
if (aspect) {
web.onPageEvent('onresize', function(eParent, eChild, aspectRatio) {
return function onResizeWindow() {
/*
* Since aspectRatio is the target width/height, we have:
*
* eParent.clientWidth / eChild.style.height = aspectRatio
*
* which means that:
*
* eChild.style.height = eParent.clientWidth / aspectRatio
*
* so for example, if aspectRatio is 16:9, or 1.78, and clientWidth = 640,
* then the calculated height should approximately 360.
*/
eChild.style.height = ((eParent.clientWidth / aspectRatio)|0) + "px";
};
}(eVideo, eCanvas, aspect));
window['onresize']();
}
eVideo.appendChild(eCanvas);
/*