Ported some PCjs drawing code to PC8080, still needs work though
This commit is contained in:
parent
98597a21da
commit
59b6dd3be6
23 changed files with 781 additions and 499 deletions
|
|
@ -9,7 +9,7 @@
|
|||
<rom id="romF" addr="0x1000" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-F.json"/>
|
||||
<rom id="romE" addr="0x1800" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-E.json"/>
|
||||
<ram id="ram" addr="0x2000" size="0x0400"/>
|
||||
<video id="video" screenWidth="224" screenHeight="256" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" interruptRate="120" rotation="90" width="40%" pos="left" padding="8px">
|
||||
<video id="video" screenWidth="896" screenHeight="1024" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" interruptRate="120" rotation="90" width="40%" pos="left" padding="8px">
|
||||
<menu>
|
||||
<title>224x256 Screen (Rotated)</title>
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs ChipSet Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<chipset>...</chipset>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -103,15 +105,20 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<chipset id="chipset" model="5150" sw1="01000001" sw2="11110000"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-chipset pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-chipset" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'"></div>
|
||||
<div class="pcjs-chipset" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<component>...</component>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -35,14 +37,20 @@ Attributes
|
|||
|
||||
Example
|
||||
---
|
||||
<component id="ibm5150" class="pcjs" width="740px" pos="center" border="1">...</component>
|
||||
```xml
|
||||
<component id="ibm5150" class="pcjs" width="740px" pos="center" border="1">
|
||||
...
|
||||
</component>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-component">
|
||||
<div class="pc-container">
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[Return to [PCjs Documentation](..)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Computer Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<computer>...</computer>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -51,16 +53,20 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<computer id="pc" name="IBM PC"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-computer pc-component" style="">
|
||||
<div class="pc-container" style="">
|
||||
<div class="pcjs-computer" data-value="id:'...',name:'...',resume:'...',state:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs CPU Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<cpu>...</cpu>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -19,7 +21,7 @@ Attributes
|
|||
---
|
||||
* *model* (optional; default is 8088; supported values include: 8086, 8088, 80186, 80286, and 80386)
|
||||
* Defines the CPU model, adjusting the CPU's capabilities accordingly.
|
||||
* *stepping* (optional; if specified, it must be a 2-character string, such as "A0" or "B1")
|
||||
* *stepping* (optional; if specified, it should be a 2-character string, such as "A0" or "B1")
|
||||
* Defines the CPU stepping, adjusting the CPU's capabilities accordingly.
|
||||
* Currently supported only on the 80386 model.
|
||||
* *cycles* (optional; default is 4772727)
|
||||
|
|
@ -44,26 +46,30 @@ Bindings
|
|||
*[Computer](/docs/pcjs/computer/)* component, because every component is reset, but the CPU offers the binding
|
||||
for convenience.
|
||||
* *speed*
|
||||
* For use with any control with an *innerHTML* property, to display the current CPU speed.
|
||||
* For use with any control with an *textContent* property, to display the current CPU speed.
|
||||
* *setSpeed*
|
||||
* For use with a control of type *button*, to increase the CPU speed.
|
||||
* *AX*, *BX*, *CX*, *DX*, *SP*, *BP*, *SI*, *DI*, *CS*, *DS*, *SS*, *ES*, *PC*, *PS*, *C*, *P*, *A*, *Z*, *S*, *T*, *I*, *D*, *O*
|
||||
* For use with any control with an *innerHTML* property, to display the corresponding register's contents.
|
||||
* For use with any control with an *textContent* property, to display the corresponding register's contents.
|
||||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<cpu id="cpu8088" model="8088" autoStart="true">
|
||||
<control type="button" class="input" binding="run">Run</control>
|
||||
</cpu>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-cpu pc-component" style="">
|
||||
<div class="pc-container" style="">
|
||||
<div class="pcjs-cpu" data-value="id:'...',name:'...',model:'...',cycles:'...',multiplier:'...',autoStart:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Debugger Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<debugger>...</debugger>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -17,7 +19,7 @@ Creates an instance of the Debugger component.
|
|||
|
||||
Attributes
|
||||
---
|
||||
* *message* (optional)
|
||||
* *messages* (optional)
|
||||
* One or more message categories to enable, separated by |. By default, all message categories are disabled.
|
||||
See the Debugger's "m" command for a current list of message categories.
|
||||
|
||||
|
|
@ -40,16 +42,20 @@ Use the Debugger's built-in help for a list of commands.
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<debugger/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-debugger pc-component" style="">
|
||||
<div class="pc-container" style="">
|
||||
<div class="pcjs-debugger" data-value="id:'...',name:'...',message:'...'">
|
||||
<div class="pcjs-debugger" data-value="id:'...',name:'...',messages:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -9,7 +9,9 @@ PCjs Floppy Drive Controller (FDC) Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<fdc>...</fdc>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -53,24 +55,28 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<fdc id="fdcNEC" autoMount="'{A: {name: "PC-DOS 1.0", path: "pcdos-1.00.json"}}'">
|
||||
<control type="container">
|
||||
<control type="list" class="input" binding="listDrives"/>
|
||||
<control type="list" class="input" binding="listDisks">
|
||||
<disk path="">None</disk>
|
||||
<disk path="pcdos-1.00.json">PC-DOS 1.0</disk>
|
||||
</control>
|
||||
<control type="button" class="input" binding="loadDrive">Load Drive</control>
|
||||
</control>
|
||||
</fdc>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-fdc pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-fdc" data-value="id:'...',name:'...',listDrives:'...',listDisks:'...',loadDrive:'...'"></div>
|
||||
<div class="pcjs-fdc" data-value="id:'...',name:'...',listDrives:'...',listDisks:'...',loadDrive:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Hard Drive Controller (HDC) Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<hdc>...</hdc>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -46,11 +48,15 @@ Attributes
|
|||
|
||||
For the Xebec (*'xt'*) controller, you should install the Xebec ROM; eg:
|
||||
|
||||
```xml
|
||||
<rom id="romHDC" addr="0xc8000" size="0x2000" file="/devices/pc/hdc/ibm-xebec-1982.json"/>
|
||||
```
|
||||
|
||||
For the Western Digital (*'at'*) controller, use a Model 5170 (or newer) ROM module; eg:
|
||||
|
||||
```xml
|
||||
<rom id="romBIOS" addr="0xf0000" size="0x10000" alias="0xff0000" file="/devices/pc/rom/5170/1984-01-10/1984-01-10.json"/>
|
||||
```
|
||||
|
||||
The default *type* setting is *'xt'*.
|
||||
|
||||
|
|
@ -62,15 +68,20 @@ This component has no bindings. Fixed disks cannot be loaded or unloaded once th
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<hdc id="hdcXT" drives="[{name:'10Mb Hard Drive',type:3}]"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-hdc pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-hdc" data-value="id:'...',name:'...',drives:'...'"></div>
|
||||
<div class="pcjs-hdc" data-value="id:'...',name:'...',drives:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Keyboard Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<keyboard>...</keyboard>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -41,18 +43,23 @@ for the specified model.
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<keyboard id="keyboard" model="us83"/>
|
||||
```
|
||||
|
||||
See [/devices/pc/keyboard/us83-softkeys.xml](/devices/pc/keyboard/us83-softkeys.xml) for an example that provides a
|
||||
complete "soft keyboard".
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-keyboard pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-keyboard" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'"></div>
|
||||
<div class="pcjs-keyboard" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Machine Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<machine>...</machine>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -32,14 +34,18 @@ None.
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<machine id="ibm5150" class="pcjs" width="740px" pos="center" border="1" style="background-color:#FAEBD7">...</machine>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-machine pc-component" style="">
|
||||
<div class="pc-container" style="">
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[Return to [PCjs Documentation](..)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Mouse Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<mouse>...</mouse>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -30,14 +32,19 @@ None.
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<mouse serial="com1"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-mouse pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-mouse" data-value="id:'...',name:'...',serial:'...'></div>
|
||||
<div class="pcjs-mouse" data-value="id:'...',name:'...',serial:'...'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[Return to [PCjs Documentation](..)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Control Panel Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<panel>...</panel>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -28,27 +30,32 @@ and [Debugger](/docs/pcjs/debugger/) components.
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<panel id="panel" pos="center" width="900px" padleft="8px">
|
||||
<name>Control Panel</name>
|
||||
<control type="container" width="500px" pos="left" padbottom="10px">
|
||||
<control type="textarea" class="output" binding="print" width="480px" height="200px"/>
|
||||
<control type="container">
|
||||
<control type="text" class="input" binding="debugInput" width="360px"/>
|
||||
control type="text" class="input" binding="debugInput" width="360px"/>
|
||||
<control type="button" class="input" binding="debugEnter">Enter</control>
|
||||
<control type="button" class="input" binding="clear">Clear</control>
|
||||
</control>
|
||||
</control>
|
||||
</panel>
|
||||
```
|
||||
|
||||
See [/devices/pc/panel/default.xml](/devices/pc/panel/default.xml) for a more complete example.
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-panel pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-panel" data-value="id:'...',name:'...'"></div>
|
||||
<div class="pcjs-panel" data-value="id:'...',name:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs ParallelPort Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<parallel>...</parallel>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -39,14 +41,19 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<parallel id="lpt1" adapter="2" binding="print"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-parallel pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-parallel" data-value="id:'...',name:'...',adapter:'...',binding:'...'"></div>
|
||||
<div class="pcjs-parallel" data-value="id:'...',name:'...',adapter:'...',binding:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[Return to [PCjs Documentation](..)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Random-Access Memory (RAM) Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<ram>...</ram>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -43,15 +45,20 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<ram id="ramLow" addr="0x00000"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-ram pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-ram" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'"></div>
|
||||
<div class="pcjs-ram" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Read-Only Memory (ROM) Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<rom>...</rom>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -43,14 +45,19 @@ None.
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<rom id="romBIOS" addr="0xfe000" size="0x02000" file="/devices/pc/rom/5150/bios/1981-04-24.json"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-rom pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-rom" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'"></div>
|
||||
<div class="pcjs-rom" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[Return to [PCjs Documentation](..)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs SerialPort Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<serial>...</serial>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -39,14 +41,19 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
```xml
|
||||
<serial id="com1" adapter="1" binding="print"/>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-serial pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-serial" data-value="id:'...',name:'...',adapter:'...',binding:'...'"></div>
|
||||
<div class="pcjs-serial" data-value="id:'...',name:'...',adapter:'...',binding:'...'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[Return to [PCjs Documentation](..)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ PCjs Video Component
|
|||
|
||||
Format
|
||||
---
|
||||
```xml
|
||||
<video>...</video>
|
||||
```
|
||||
|
||||
Purpose
|
||||
---
|
||||
|
|
@ -22,24 +24,6 @@ Creates an instance of the Video component. This component is responsible for:
|
|||
|
||||
Attributes
|
||||
---
|
||||
* *addr* (required)
|
||||
|
||||
The ROM starting address (e.g., 0xfe000).
|
||||
|
||||
* *size* (required)
|
||||
|
||||
The length of ROM, in bytes (e.g., 0x02000 for an 8Kb ROM). This must match the length of the ROM image file.
|
||||
|
||||
* *file* (required)
|
||||
|
||||
URL of the ROM image file to load at the specified addr.
|
||||
|
||||
* *notify* (optional)
|
||||
|
||||
The *id* of a component to notify when *file* has been loaded. For example, the Video component may need
|
||||
to know when an external video ROM has been loaded. Any component can load its own files, including ROM image files,
|
||||
but it's simpler to use the ROM component and request notification.
|
||||
|
||||
* *model* (optional)
|
||||
|
||||
* "mda" (Monochrome Display Adapter)
|
||||
|
|
@ -49,17 +33,13 @@ Attributes
|
|||
If *model* is not set, the SW1 switch block settings from the [ChipSet](/docs/pcjs/chipset/) component will
|
||||
determine the video model to use ("mda" or "cga" only).
|
||||
|
||||
* *scale* (optional; default is false)
|
||||
|
||||
true scales text modes to fill the canvas;
|
||||
false centers text modes on the canvas (this generally provides the sharpest rendering).
|
||||
|
||||
* *screenwidth*, *screenheight* (required)
|
||||
* *screenWidth*, *screenHeight* (required)
|
||||
|
||||
The width and height of the canvas, in pixels (these are numbers, not style attributes, so do not include
|
||||
a "px" suffix).
|
||||
a "px" suffix); the canvas resolution does not need to match the *model* resolution (in fact, it should probably
|
||||
be closer to the resolution of modern monitors, but still proportional to the resolution of the *model* being used).
|
||||
|
||||
* *fontrom* (formerly *charset*; required for models "mda" and "cga")
|
||||
* *fontROM* (formerly *charset*; required for models "mda" and "cga")
|
||||
|
||||
The name of a character generator (font ROM) file. The MDA and CGA adapters did not contain a separate
|
||||
system ROM, but they did contain on-board font data in ROM that the adapter used internally to generate character
|
||||
|
|
@ -68,6 +48,11 @@ Attributes
|
|||
The EGA uses font data stored in its system ROM, which is loaded by the ROM component, so do not use this
|
||||
setting with model "ega".
|
||||
|
||||
* *scale* (optional; default is false)
|
||||
|
||||
true scales text modes to fill the canvas;
|
||||
false centers text modes on the canvas (this generally provides the sharpest rendering).
|
||||
|
||||
Also supports the attributes of *[Component](/docs/pcjs/component/)*.
|
||||
|
||||
Bindings
|
||||
|
|
@ -79,17 +64,22 @@ Bindings
|
|||
|
||||
Example
|
||||
---
|
||||
<video id="videoMDA" screenwidth="720" screenheight="350" scale="true" fontrom="ibm-mda-cga.json">
|
||||
```xml
|
||||
<video id="videoMDA" screenWidth="720" screenHeight="350" fontROM="ibm-mda-cga.json" scale="true">
|
||||
<name>Monochrome Display</name>
|
||||
</video>
|
||||
```
|
||||
|
||||
Output
|
||||
---
|
||||
```html
|
||||
<div id="..." class="pc-video pc-component">
|
||||
<div class="pc-container">
|
||||
<div class="pcjs-video" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'"></div>
|
||||
<div class="pcjs-video" data-value="...">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also, if any controls are defined, another <div> of class="pc-controls" is created in the container <div>,
|
||||
with each control inside a <div> of class="pc-control".
|
||||
|
|
|
|||
|
|
@ -1091,11 +1091,11 @@ CPUSim.prototype.updateStatus = function(fForce)
|
|||
this.updateReg("PC", this.getPC(), 4);
|
||||
var regPS = this.getPS();
|
||||
this.updateReg("PS", regPS, 4);
|
||||
this.updateReg("SF", (regPS & CPUDef.PS.SF), 1);
|
||||
this.updateReg("ZF", (regPS & CPUDef.PS.ZF), 1);
|
||||
this.updateReg("AF", (regPS & CPUDef.PS.AF), 1);
|
||||
this.updateReg("PF", (regPS & CPUDef.PS.PF), 1);
|
||||
this.updateReg("CF", (regPS & CPUDef.PS.CF), 1);
|
||||
this.updateReg("SF", (regPS & CPUDef.PS.SF)? 1 : 0, 1);
|
||||
this.updateReg("ZF", (regPS & CPUDef.PS.ZF)? 1 : 0, 1);
|
||||
this.updateReg("AF", (regPS & CPUDef.PS.AF)? 1 : 0, 1);
|
||||
this.updateReg("PF", (regPS & CPUDef.PS.PF)? 1 : 0, 1);
|
||||
this.updateReg("CF", (regPS & CPUDef.PS.CF)? 1 : 0, 1);
|
||||
}
|
||||
}
|
||||
var controlSpeed = this.bindings["speed"];
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ if (NODE) {
|
|||
* bufferAddr: the starting address of the frame buffer (eg, 0x2400)
|
||||
* bufferCols: the width of a single frame buffer row, in pixels (eg, 256)
|
||||
* bufferRows: the number of frame buffer rows (eg, 224)
|
||||
* bufferBits: the number of bits per pixel (eg, 1)
|
||||
* bufferBits: the number of bits per pixel (default is 1 if omitted)
|
||||
* interruptRate: normally the same as (or some multiple of) the refreshRate (eg, 120)
|
||||
* refreshRate: how many times updateScreen() should be called per second (eg, 60)
|
||||
*
|
||||
|
|
@ -75,9 +75,35 @@ if (NODE) {
|
|||
function Video(parmsVideo, canvas, context, textarea, container)
|
||||
{
|
||||
Component.call(this, "Video", parmsVideo, Video, Messages.VIDEO);
|
||||
|
||||
this.cxScreen = parmsVideo['screenWidth'];
|
||||
this.cyScreen = parmsVideo['screenHeight'];
|
||||
|
||||
this.addrBuffer = parmsVideo['bufferAddr'];
|
||||
this.cxBuffer = parmsVideo['bufferCols'];
|
||||
this.cyBuffer = parmsVideo['bufferRows'];
|
||||
this.nBitsPerPixel = parmsVideo['bufferBits'] || 1;
|
||||
|
||||
this.interruptRate = parmsVideo['interruptRate'];
|
||||
this.refreshRate = parmsVideo['refreshRate'] || 60;
|
||||
this.setReady();
|
||||
|
||||
this.canvasScreen = canvas;
|
||||
this.contextScreen = context;
|
||||
this.textareaScreen = textarea;
|
||||
this.inputScreen = textarea || canvas || null;
|
||||
|
||||
this.initColors();
|
||||
|
||||
/*
|
||||
* Allocate off-screen buffers.
|
||||
*
|
||||
* TODO: Do this only if there is a mismatch between the screen's (canvas) dimensions and the frame buffer's.
|
||||
*/
|
||||
this.imageBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer);
|
||||
this.canvasBuffer = document.createElement("canvas");
|
||||
this.canvasBuffer.width = this.cxBuffer;
|
||||
this.canvasBuffer.height = this.cyBuffer;
|
||||
this.contextBuffer = this.canvasBuffer.getContext("2d");
|
||||
}
|
||||
|
||||
Component.subclass(Video);
|
||||
|
|
@ -97,6 +123,20 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.bus = bus;
|
||||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
|
||||
/*
|
||||
* Compute the size of the frame buffer and allocate.
|
||||
*/
|
||||
this.sizeBuffer = ((this.cxBuffer * this.nBitsPerPixel) >> 3) * this.cyBuffer;
|
||||
if (this.bus.addMemory(this.addrBuffer, this.sizeBuffer, Memory.TYPE.VIDEO)) {
|
||||
/*
|
||||
* Compute the number of cells and initialize the cell cache.
|
||||
*/
|
||||
this.nCellCache = this.sizeBuffer >> 1;
|
||||
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
|
||||
this.initCache();
|
||||
}
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -110,6 +150,62 @@ Video.prototype.getRefreshRate = function()
|
|||
return Math.max(this.refreshRate, this.interruptRate);
|
||||
};
|
||||
|
||||
/**
|
||||
* initCache()
|
||||
*
|
||||
* Initializes the contents of our internal cell cache.
|
||||
*
|
||||
* @this {Video}
|
||||
*/
|
||||
Video.prototype.initCache = function()
|
||||
{
|
||||
this.fCellCacheValid = false;
|
||||
if (this.aCellCache === undefined || this.aCellCache.length != this.nCellCache) {
|
||||
this.aCellCache = new Array(this.nCellCache);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* initColors()
|
||||
*
|
||||
* @this {Video}
|
||||
*/
|
||||
Video.prototype.initColors = function()
|
||||
{
|
||||
this.aRGB = [
|
||||
[0x00, 0x00, 0x00, 0xff], // black
|
||||
[0xff, 0xff, 0xff, 0xff] // white
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* getColors()
|
||||
*
|
||||
* @this {Video}
|
||||
*/
|
||||
Video.prototype.getColors = function()
|
||||
{
|
||||
return this.aRGB;
|
||||
};
|
||||
|
||||
/**
|
||||
* setPixel(imageData, x, y, rgb)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Object} imageData
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {Array.<number>} rgb is a 4-element array containing the red, green, blue and alpha values
|
||||
*/
|
||||
Video.prototype.setPixel = function(imageData, x, y, rgb)
|
||||
{
|
||||
var index = (x + y * imageData.width) * rgb.length;
|
||||
imageData.data[index] = rgb[0];
|
||||
imageData.data[index+1] = rgb[1];
|
||||
imageData.data[index+2] = rgb[2];
|
||||
imageData.data[index+3] = rgb[3];
|
||||
};
|
||||
|
||||
/**
|
||||
* updateScreen(n)
|
||||
*
|
||||
|
|
@ -126,6 +222,7 @@ Video.prototype.getRefreshRate = function()
|
|||
*/
|
||||
Video.prototype.updateScreen = function(n)
|
||||
{
|
||||
if (n >= 0) {
|
||||
if (!(n & 1)) {
|
||||
/*
|
||||
* On even updates, call cpu.requestINTR(1), and also update our copy of the screen.
|
||||
|
|
@ -138,6 +235,87 @@ Video.prototype.updateScreen = function(n)
|
|||
* update the bottom half of the frame buffer after acknowledging this interrupt.
|
||||
*/
|
||||
this.cpu.requestINTR(2);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since this is not a forced update, if our cell cache is valid AND the buffer is clean, then do nothing.
|
||||
*/
|
||||
if (this.fCellCacheValid && this.bus.cleanMemory(this.addrBuffer, this.sizeBuffer)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're still here, then either this is a forced update, or our cell cache hasn't been filled yet, or
|
||||
* the frame buffer is dirty. Time to actually update the screen.
|
||||
*/
|
||||
|
||||
var addr = this.addrBuffer;
|
||||
var addrLimit = addr + this.sizeBuffer;
|
||||
|
||||
var iCell = 0;
|
||||
var wPixelMask = 0x10000;
|
||||
var nPixelShift = 1;
|
||||
var aPixelColors = this.getColors();
|
||||
|
||||
var x = 0, y = 0;
|
||||
var xDirty = this.cxBuffer, xMaxDirty = 0, yDirty = this.cyBuffer, yMaxDirty = 0;
|
||||
|
||||
while (addr < addrLimit) {
|
||||
var data = this.bus.getShortDirect(addr);
|
||||
this.assert(iCell < this.aCellCache.length);
|
||||
if (this.fCellCacheValid && data === this.aCellCache[iCell]) {
|
||||
x += this.nPixelsPerCell;
|
||||
} else {
|
||||
this.aCellCache[iCell] = data;
|
||||
var wPixels = (data >> 8) | ((data & 0xff) << 8);
|
||||
var wMask = wPixelMask, nShift = 16;
|
||||
if (x < xDirty) xDirty = x;
|
||||
for (var iPixel = 0; iPixel < this.nPixelsPerCell; iPixel++) {
|
||||
var bPixel = (wPixels & (wMask >>= nPixelShift)) >> (nShift -= nPixelShift);
|
||||
this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
|
||||
}
|
||||
if (x > xMaxDirty) xMaxDirty = x;
|
||||
if (y < yDirty) yDirty = y;
|
||||
if (y >= yMaxDirty) yMaxDirty = y + 1;
|
||||
}
|
||||
addr += 2;
|
||||
iCell++;
|
||||
if (x >= this.cxBuffer) {
|
||||
x = 0;
|
||||
y++;
|
||||
if (y > this.cyBuffer) break;
|
||||
}
|
||||
}
|
||||
|
||||
this.fCellCacheValid = true;
|
||||
|
||||
/*
|
||||
* Instead of blasting the ENTIRE imageBuffer into contextBuffer, and then blasting the ENTIRE
|
||||
* canvasBuffer onto contextScreen, even for the smallest change, let's try to be a bit smarter about
|
||||
* the update (well, to the extent that the canvas APIs permit).
|
||||
*/
|
||||
if (xDirty < this.cxBuffer) {
|
||||
var cxDirty = xMaxDirty - xDirty;
|
||||
var cyDirty = yMaxDirty - yDirty;
|
||||
// this.contextBuffer.putImageData(this.imageBuffer, 0, 0);
|
||||
this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
/*
|
||||
* While ideally I would draw only the dirty portion of canvasBuffer, there usually isn't a 1-1 pixel mapping
|
||||
* between canvasBuffer and contextScreen. In fact, the WHOLE POINT of the canvasBuffer is to leverage
|
||||
* drawImage()'s scaling ability; for example, a CGA graphics mode might be 640x200, whereas the canvas representing
|
||||
* the screen might be 960x400. In those situations, if we draw interior rectangles, we often end up with subpixel
|
||||
* artifacts along the edges of those rectangles. So it appears I must continue to redraw the entire canvasBuffer
|
||||
* on every change.
|
||||
*
|
||||
var xScreen = (((xDirty * this.cxScreen) / this.cxBuffer) | 0);
|
||||
var yScreen = (((yDirty * this.cyScreen) / this.cyBuffer) | 0);
|
||||
var cxScreen = (((cxDirty * this.cxScreen) / this.cxBuffer) | 0);
|
||||
var cyScreen = (((cyDirty * this.cyScreen) / this.cyBuffer) | 0);
|
||||
this.contextScreen.drawImage(this.canvasBuffer, xDirty, yDirty, cxDirty, cyDirty, xScreen, yScreen, cxScreen, cyScreen);
|
||||
*/
|
||||
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.cxBuffer, this.cyBuffer, 0, 0, this.cxScreen, this.cyScreen);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue