mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-23 18:31:08 +00:00
converted tms9918a to typescript class
This commit is contained in:
parent
a1aa24f2e8
commit
97f69c2af1
@ -63,6 +63,7 @@ function require(modname) {
|
|||||||
<script src="tss/js/tss/AudioLooper.js"></script>
|
<script src="tss/js/tss/AudioLooper.js"></script>
|
||||||
<script src="tss/js/Log.js"></script>
|
<script src="tss/js/Log.js"></script>
|
||||||
|
|
||||||
|
<script src="gen/video/tms9918a.js"></script>
|
||||||
<script src="gen/util.js"></script>
|
<script src="gen/util.js"></script>
|
||||||
<script src="gen/store.js"></script>
|
<script src="gen/store.js"></script>
|
||||||
<script src="src/vlist.js"></script>
|
<script src="src/vlist.js"></script>
|
||||||
|
@ -25,18 +25,55 @@ enum TMS9918A_Mode {
|
|||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export function TMS9918A(canvas, cru, enableFlicker) {
|
export class TMS9918A {
|
||||||
|
|
||||||
|
canvas;
|
||||||
|
|
||||||
|
cru : { setVDPInterrupt: (b:boolean) => void };
|
||||||
|
enableFlicker : boolean;
|
||||||
|
|
||||||
|
ram = new Uint8Array(16384); // VDP RAM
|
||||||
|
registers = new Uint8Array(8);
|
||||||
|
spriteBuffer = new Uint8Array(256);
|
||||||
|
addressRegister : number;
|
||||||
|
statusRegister : number;
|
||||||
|
|
||||||
|
palette : [number, number, number][];
|
||||||
|
|
||||||
|
latch : boolean;
|
||||||
|
prefetchByte : number;
|
||||||
|
|
||||||
|
displayOn = null;
|
||||||
|
interruptsOn = null;
|
||||||
|
screenMode : number;
|
||||||
|
bitmapMode : boolean;
|
||||||
|
textMode : boolean;
|
||||||
|
colorTable : number;
|
||||||
|
nameTable : number;
|
||||||
|
charPatternTable : number;
|
||||||
|
spriteAttributeTable : number;
|
||||||
|
spritePatternTable : number;
|
||||||
|
colorTableMask : number;
|
||||||
|
patternTableMask : number;
|
||||||
|
ramMask : number;
|
||||||
|
fgColor : number;
|
||||||
|
bgColor : number;
|
||||||
|
|
||||||
|
flicker : boolean;
|
||||||
|
redrawRequired : boolean;
|
||||||
|
|
||||||
|
canvasContext;
|
||||||
|
imageData;
|
||||||
|
|
||||||
|
width : number;
|
||||||
|
height : number;
|
||||||
|
|
||||||
|
constructor(canvas, cru, enableFlicker:boolean) {
|
||||||
|
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
this.cru = cru;
|
this.cru = cru;
|
||||||
this.enableFlicker = enableFlicker;
|
this.enableFlicker = enableFlicker;
|
||||||
|
|
||||||
this.ram = new Uint8Array(16384); // VDP RAM
|
|
||||||
this.registers = new Uint8Array(8);
|
|
||||||
this.spriteBuffer = new Uint8Array(256);
|
|
||||||
this.addressRegister = null;
|
|
||||||
this.statusRegister = null;
|
|
||||||
|
|
||||||
this.palette = [
|
this.palette = [
|
||||||
[0, 0, 0],
|
[0, 0, 0],
|
||||||
[0, 0, 0],
|
[0, 0, 0],
|
||||||
@ -56,41 +93,11 @@ export function TMS9918A(canvas, cru, enableFlicker) {
|
|||||||
[255, 255, 255]
|
[255, 255, 255]
|
||||||
];
|
];
|
||||||
|
|
||||||
this.latch = null;
|
|
||||||
this.prefetchByte = null;
|
|
||||||
|
|
||||||
this.displayOn = null;
|
|
||||||
this.interruptsOn = null;
|
|
||||||
this.screenMode = null;
|
|
||||||
this.bitmapMode = null;
|
|
||||||
this.textMode = null;
|
|
||||||
this.colorTable = null;
|
|
||||||
this.nameTable = null;
|
|
||||||
this.charPatternTable = null;
|
|
||||||
this.spriteAttributeTable = null;
|
|
||||||
this.spritePatternTable = null;
|
|
||||||
this.colorTableMask = null;
|
|
||||||
this.patternTableMask = null;
|
|
||||||
this.ramMask = null;
|
|
||||||
this.fgColor = null;
|
|
||||||
this.bgColor = null;
|
|
||||||
|
|
||||||
this.flicker = null;
|
|
||||||
this.redrawRequired = null;
|
|
||||||
|
|
||||||
this.canvasContext = this.canvas.getContext("2d");
|
this.canvasContext = this.canvas.getContext("2d");
|
||||||
this.imageData = null;
|
|
||||||
this.width = null;
|
|
||||||
this.height = null;
|
|
||||||
|
|
||||||
//this.log = Log.getLog();
|
|
||||||
|
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
TMS9918A.prototype = {
|
reset() {
|
||||||
|
|
||||||
reset: function () {
|
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
for (i = 0; i < this.ram.length; i++) {
|
for (i = 0; i < this.ram.length; i++) {
|
||||||
@ -133,9 +140,9 @@ TMS9918A.prototype = {
|
|||||||
this.imageData = this.canvasContext.getImageData(0, 0, this.canvas.width, this.canvas.height);
|
this.imageData = this.canvasContext.getImageData(0, 0, this.canvas.width, this.canvas.height);
|
||||||
this.width = this.canvas.width;
|
this.width = this.canvas.width;
|
||||||
this.height = this.canvas.height;
|
this.height = this.canvas.height;
|
||||||
},
|
}
|
||||||
|
|
||||||
drawFrame: function (timestamp) {
|
drawFrame(timestamp:number) {
|
||||||
if (this.redrawRequired) {
|
if (this.redrawRequired) {
|
||||||
for (var y = 0; y < this.height; y++) {
|
for (var y = 0; y < this.height; y++) {
|
||||||
this.drawScanline(y);
|
this.drawScanline(y);
|
||||||
@ -143,12 +150,12 @@ TMS9918A.prototype = {
|
|||||||
this.updateCanvas();
|
this.updateCanvas();
|
||||||
this.redrawRequired = false;
|
this.redrawRequired = false;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
initFrame: function (timestamp) {
|
initFrame(timestamp:number) {
|
||||||
},
|
}
|
||||||
|
|
||||||
drawScanline: function (y) {
|
drawScanline(y:number) {
|
||||||
var imageData = this.imageData.data,
|
var imageData = this.imageData.data,
|
||||||
width = this.width,
|
width = this.width,
|
||||||
imageDataAddr = (y * width) << 2,
|
imageDataAddr = (y * width) << 2,
|
||||||
@ -344,13 +351,13 @@ TMS9918A.prototype = {
|
|||||||
if (fifthSprite) {
|
if (fifthSprite) {
|
||||||
this.statusRegister |= 0x40;
|
this.statusRegister |= 0x40;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
updateCanvas: function () {
|
updateCanvas() {
|
||||||
this.canvasContext.putImageData(this.imageData, 0, 0);
|
this.canvasContext.putImageData(this.imageData, 0, 0);
|
||||||
},
|
}
|
||||||
|
|
||||||
writeAddress: function (i) {
|
writeAddress(i:number) {
|
||||||
if (!this.latch) {
|
if (!this.latch) {
|
||||||
this.addressRegister = (this.addressRegister & 0xFF00) | i;
|
this.addressRegister = (this.addressRegister & 0xFF00) | i;
|
||||||
}
|
}
|
||||||
@ -427,9 +434,9 @@ TMS9918A.prototype = {
|
|||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
}
|
}
|
||||||
this.latch = !this.latch;
|
this.latch = !this.latch;
|
||||||
},
|
}
|
||||||
|
|
||||||
updateMode: function (reg0, reg1) {
|
updateMode(reg0:number, reg1:number) {
|
||||||
this.bitmapMode = (reg0 & 0x02) !== 0;
|
this.bitmapMode = (reg0 & 0x02) !== 0;
|
||||||
this.textMode = (reg1 & 0x10) !== 0;
|
this.textMode = (reg1 & 0x10) !== 0;
|
||||||
// Check bitmap mode bit, not text or multicolor
|
// Check bitmap mode bit, not text or multicolor
|
||||||
@ -483,9 +490,9 @@ TMS9918A.prototype = {
|
|||||||
this.nameTable = (this.registers[2] & 0xf) << 10;
|
this.nameTable = (this.registers[2] & 0xf) << 10;
|
||||||
this.spriteAttributeTable = (this.registers[5] & 0x7f) << 7;
|
this.spriteAttributeTable = (this.registers[5] & 0x7f) << 7;
|
||||||
this.spritePatternTable = (this.registers[6] & 0x7) << 11;
|
this.spritePatternTable = (this.registers[6] & 0x7) << 11;
|
||||||
},
|
}
|
||||||
|
|
||||||
updateTableMasks: function () {
|
updateTableMasks() {
|
||||||
if (this.screenMode === TMS9918A_Mode.BITMAP) {
|
if (this.screenMode === TMS9918A_Mode.BITMAP) {
|
||||||
this.colorTableMask = ((this.registers[3] & 0x7F) << 6) | 0x3F; // 000CCCCCCC111111
|
this.colorTableMask = ((this.registers[3] & 0x7F) << 6) | 0x3F; // 000CCCCCCC111111
|
||||||
this.patternTableMask = ((this.registers[4] & 0x03) << 11) | (this.colorTableMask & 0x7FF); // 000PPCCCCC111111
|
this.patternTableMask = ((this.registers[4] & 0x03) << 11) | (this.colorTableMask & 0x7FF); // 000PPCCCCC111111
|
||||||
@ -500,15 +507,15 @@ TMS9918A.prototype = {
|
|||||||
this.colorTableMask = this.ramMask;
|
this.colorTableMask = this.ramMask;
|
||||||
this.patternTableMask = this.ramMask;
|
this.patternTableMask = this.ramMask;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
writeData: function (i) {
|
writeData(i:number) {
|
||||||
this.ram[this.addressRegister++] = i;
|
this.ram[this.addressRegister++] = i;
|
||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
},
|
}
|
||||||
|
|
||||||
readStatus: function () {
|
readStatus() : number {
|
||||||
var i = this.statusRegister;
|
var i = this.statusRegister;
|
||||||
this.statusRegister = 0x1F;
|
this.statusRegister = 0x1F;
|
||||||
if (this.interruptsOn) {
|
if (this.interruptsOn) {
|
||||||
@ -516,20 +523,20 @@ TMS9918A.prototype = {
|
|||||||
}
|
}
|
||||||
this.latch = false;
|
this.latch = false;
|
||||||
return i;
|
return i;
|
||||||
},
|
}
|
||||||
|
|
||||||
readData: function () {
|
readData() : number {
|
||||||
var i = this.prefetchByte;
|
var i = this.prefetchByte;
|
||||||
this.prefetchByte = this.ram[this.addressRegister++];
|
this.prefetchByte = this.ram[this.addressRegister++];
|
||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
return i;
|
return i;
|
||||||
},
|
}
|
||||||
|
|
||||||
getRAM: function () {
|
getRAM() : Uint8Array {
|
||||||
return this.ram;
|
return this.ram;
|
||||||
},
|
}
|
||||||
|
|
||||||
colorTableSize: function () {
|
colorTableSize() : number {
|
||||||
if (this.screenMode === TMS9918A_Mode.GRAPHICS) {
|
if (this.screenMode === TMS9918A_Mode.GRAPHICS) {
|
||||||
return 0x20;
|
return 0x20;
|
||||||
}
|
}
|
||||||
@ -539,18 +546,18 @@ TMS9918A.prototype = {
|
|||||||
else {
|
else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
patternTableSize: function () {
|
patternTableSize() : number {
|
||||||
if (this.bitmapMode) {
|
if (this.bitmapMode) {
|
||||||
return Math.min(this.patternTableMask + 1, 0x1800);
|
return Math.min(this.patternTableMask + 1, 0x1800);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return 0x800;
|
return 0x800;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
getRegsString: function () {
|
getRegsString() : string {
|
||||||
var s = "";
|
var s = "";
|
||||||
for (var i = 0; i < this.registers.length; i++) {
|
for (var i = 0; i < this.registers.length; i++) {
|
||||||
s += "VR" + i + ":" + hex(this.registers[i],2) + " ";
|
s += "VR" + i + ":" + hex(this.registers[i],2) + " ";
|
||||||
@ -559,36 +566,36 @@ TMS9918A.prototype = {
|
|||||||
" CT:" + hex(this.colorTable,4) + " (" + hex(this.colorTableSize(),4) + ") SDT:" + hex(this.spritePatternTable,4) +
|
" CT:" + hex(this.colorTable,4) + " (" + hex(this.colorTableSize(),4) + ") SDT:" + hex(this.spritePatternTable,4) +
|
||||||
" SAL:" + hex(this.spriteAttributeTable,4) + "\nVDP: " + hex(this.addressRegister,4);
|
" SAL:" + hex(this.spriteAttributeTable,4) + "\nVDP: " + hex(this.addressRegister,4);
|
||||||
return s;
|
return s;
|
||||||
},
|
}
|
||||||
|
|
||||||
hexView: function (start, length, anchorAddr) {
|
hexView(start:number, length:number, anchorAddr:number) : {text,lineCount,anchorLine} {
|
||||||
var text = "";
|
var text = "";
|
||||||
var anchorLine = null;
|
var anchorLine = null;
|
||||||
var addr = start;
|
var addr = start;
|
||||||
var line = 0;
|
var line = 0;
|
||||||
for (var i = 0; i < length && addr < 0x4000; addr++, i++) {
|
for (var i = 0; i < length && addr < 0x4000; addr++, i++) {
|
||||||
if ((i & 0x000F) === 0) {
|
if ((i & 0x000F) === 0) {
|
||||||
text += "\n" + addr.toHexWord() + ":";
|
text += "\n" + hex(addr,4) + ":";
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
text += " ";
|
text += " ";
|
||||||
if (anchorAddr && anchorAddr === addr) {
|
if (anchorAddr && anchorAddr === addr) {
|
||||||
anchorLine = line;
|
anchorLine = line;
|
||||||
}
|
}
|
||||||
var hex = this.ram[addr].toString(16).toUpperCase();
|
var hx = this.ram[addr].toString(16).toUpperCase();
|
||||||
if (hex.length === 1) {
|
if (hx.length === 1) {
|
||||||
text += "0";
|
text += "0";
|
||||||
}
|
}
|
||||||
text += hex;
|
text += hx;
|
||||||
}
|
}
|
||||||
return {text: text.substr(1), lineCount: line, anchorLine: anchorLine - 1};
|
return {text: text.substr(1), lineCount: line, anchorLine: anchorLine - 1};
|
||||||
},
|
}
|
||||||
|
|
||||||
getWord: function (addr) {
|
getWord(addr:number) : number {
|
||||||
return addr < 0x4000 ? this.ram[addr] << 8 | this.ram[addr+1] : 0;
|
return addr < 0x4000 ? this.ram[addr] << 8 | this.ram[addr+1] : 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
getCharAt: function (x, y) {
|
getCharAt(x:number, y:number) : number {
|
||||||
x -= 24;
|
x -= 24;
|
||||||
y -= 24;
|
y -= 24;
|
||||||
if (!this.textMode) {
|
if (!this.textMode) {
|
||||||
@ -597,14 +604,14 @@ TMS9918A.prototype = {
|
|||||||
else {
|
else {
|
||||||
return this.ram[this.nameTable + Math.floor((x - 8) / 6) + Math.floor(y / 8) * 40];
|
return this.ram[this.nameTable + Math.floor((x - 8) / 6) + Math.floor(y / 8) * 40];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
setFlicker: function (value) {
|
setFlicker(value:boolean) {
|
||||||
this.flicker = value;
|
this.flicker = value;
|
||||||
this.enableFlicker = value;
|
this.enableFlicker = value;
|
||||||
},
|
}
|
||||||
|
|
||||||
getState: function () {
|
getState() {
|
||||||
return {
|
return {
|
||||||
ram: this.ram,
|
ram: this.ram,
|
||||||
registers: this.registers,
|
registers: this.registers,
|
||||||
@ -629,9 +636,9 @@ TMS9918A.prototype = {
|
|||||||
bgColor: this.bgColor,
|
bgColor: this.bgColor,
|
||||||
flicker: this.flicker
|
flicker: this.flicker
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
restoreState: function (state) {
|
restoreState(state) {
|
||||||
this.ram = state.ram;
|
this.ram = state.ram;
|
||||||
this.registers = state.registers;
|
this.registers = state.registers;
|
||||||
this.addressRegister = state.addressRegister;
|
this.addressRegister = state.addressRegister;
|
||||||
|
@ -42,6 +42,7 @@ var _williams = require('gen/platform/williams.js');
|
|||||||
var _sound_williams = require('gen/platform/sound_williams.js');
|
var _sound_williams = require('gen/platform/sound_williams.js');
|
||||||
var _astrocade = require('gen/platform/astrocade.js');
|
var _astrocade = require('gen/platform/astrocade.js');
|
||||||
var _atari8 = require('gen/platform/atari8.js');
|
var _atari8 = require('gen/platform/atari8.js');
|
||||||
|
var _coleco = require('gen/platform/coleco.js');
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ dom.window.HTMLCanvasElement.prototype.getContext = function() {
|
|||||||
getImageData: function(x,y,w,h) { return {data: new Uint32Array(w*h) }; },
|
getImageData: function(x,y,w,h) { return {data: new Uint32Array(w*h) }; },
|
||||||
fillRect: function(x,y,w,h) { },
|
fillRect: function(x,y,w,h) { },
|
||||||
drawImage: function(img,x,y,w,h) { },
|
drawImage: function(img,x,y,w,h) { },
|
||||||
putImageData: function(data,w,h) { }
|
putImageData: function(data,w,h) { },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
global.navigator = {};
|
global.navigator = {};
|
||||||
@ -223,6 +224,15 @@ describe('Platform Replay', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
|
it('Should run coleco', () => {
|
||||||
|
var platform = testPlatform('coleco', 'shoot.c.rom', 92, (platform, frameno) => {
|
||||||
|
if (frameno == 62) {
|
||||||
|
keycallback(Keys.VK_SPACE.c, Keys.VK_SPACE.c, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
*/
|
||||||
/* TODO
|
/* TODO
|
||||||
it('Should run atari8-5200', () => {
|
it('Should run atari8-5200', () => {
|
||||||
var platform = testPlatform('atari8-5200', 'hello.a.rom', 92, (platform, frameno) => {
|
var platform = testPlatform('atari8-5200', 'hello.a.rom', 92, (platform, frameno) => {
|
||||||
|
BIN
test/roms/coleco/shoot.c.rom
Normal file
BIN
test/roms/coleco/shoot.c.rom
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user