mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-25 15:30:03 +00:00
zmachine: more split window stuff, ztrek
This commit is contained in:
parent
34aba0443e
commit
ccc011e048
1815
presets/zmachine/ztrek.inf
Normal file
1815
presets/zmachine/ztrek.inf
Normal file
File diff suppressed because it is too large
Load Diff
@ -122,6 +122,7 @@ export interface Platform {
|
||||
getRasterScanline?() : number;
|
||||
setBreakpoint?(id : string, cond : DebugCondition);
|
||||
clearBreakpoint?(id : string);
|
||||
hasBreakpoint?(id : string) : boolean;
|
||||
getCPUState?() : CpuState;
|
||||
|
||||
debugSymbols? : DebugSymbols;
|
||||
@ -226,6 +227,9 @@ export abstract class BaseDebugPlatform extends BasePlatform {
|
||||
clearBreakpoint(id : string) {
|
||||
delete this.breakpoints.id2bp[id];
|
||||
}
|
||||
hasBreakpoint(id : string) {
|
||||
return this.breakpoints.id2bp[id] != null;
|
||||
}
|
||||
getDebugCallback() : DebugCondition {
|
||||
return this.breakpoints.getDebugCondition();
|
||||
}
|
||||
|
@ -399,14 +399,19 @@ export class SourceEditor implements ProjectView {
|
||||
this.editor.execCommand('undo');
|
||||
}
|
||||
|
||||
toggleBreakpoint(lineno: number) {
|
||||
toggleBreakpoint(lineno: number) {
|
||||
// TODO: we have to always start at beginning of frame
|
||||
if (this.sourcefile != null) {
|
||||
var targetPC = this.sourcefile.line2offset[lineno+1];
|
||||
/* TODO: breakpoints
|
||||
/*
|
||||
var bpid = "pc" + targetPC;
|
||||
platform.setBreakpoint(bpid, () => {
|
||||
return platform.getPC() == targetPC;
|
||||
});
|
||||
if (platform.hasBreakpoint(bpid)) {
|
||||
platform.clearBreakpoint(bpid);
|
||||
} else {
|
||||
platform.setBreakpoint(bpid, () => {
|
||||
return platform.getPC() == targetPC;
|
||||
});
|
||||
}
|
||||
*/
|
||||
runToPC(targetPC);
|
||||
}
|
||||
@ -1352,6 +1357,7 @@ class TreeNode {
|
||||
this.getDiv();
|
||||
var text = "";
|
||||
// is it a function? call it first, if we are expanded
|
||||
// TODO: only call functions w/ signature
|
||||
if (typeof obj == 'function' && this._content != null) {
|
||||
obj = obj();
|
||||
}
|
||||
@ -1478,6 +1484,7 @@ export class DebugBrowserView extends TreeViewBase implements ProjectView {
|
||||
interface CallGraphNode {
|
||||
count : number;
|
||||
SP : number;
|
||||
PC : number;
|
||||
calls : {[id:string] : CallGraphNode};
|
||||
}
|
||||
|
||||
@ -1508,7 +1515,7 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView {
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.stack = []; // TODO??? should continue across frames
|
||||
this.stack = [];
|
||||
this.lastsp = -1;
|
||||
this.jsr = false;
|
||||
}
|
||||
@ -1518,28 +1525,34 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView {
|
||||
switch (op) {
|
||||
case ProbeFlags.SP_PUSH:
|
||||
// need a new root?
|
||||
if (this.stack.length == 0 || addr > this.stack[0].SP) {
|
||||
this.graph = {count:0, SP:addr, calls:{}};
|
||||
if (this.stack.length == 0) {
|
||||
this.graph = {count:0, PC:null, SP:addr, calls:{}};
|
||||
this.stack.unshift(this.graph);
|
||||
} else if (addr > this.stack[0].SP) {
|
||||
let calls = {};
|
||||
if (this.stack[0].PC !== null) calls[this.stack[0].PC] = this.stack[0];
|
||||
this.graph = {count:0, PC:null, SP:addr, calls:calls};
|
||||
this.stack.unshift(this.graph);
|
||||
}
|
||||
case ProbeFlags.SP_POP:
|
||||
if (this.stack.length) {
|
||||
var top = this.stack[this.stack.length-1];
|
||||
let top = this.stack[this.stack.length-1];
|
||||
if ((this.lastsp - addr) == 2 && addr < top.SP) { // TODO: look for opcode?
|
||||
this.jsr = true;
|
||||
}
|
||||
if ((this.lastsp - addr) == -2 && this.stack.length > 1 && addr > top.SP) {
|
||||
this.stack.pop();
|
||||
}
|
||||
this.lastsp = addr;
|
||||
}
|
||||
this.lastsp = addr;
|
||||
break;
|
||||
case ProbeFlags.EXECUTE:
|
||||
if (this.jsr && this.stack.length) {
|
||||
var top = this.stack[this.stack.length-1];
|
||||
var sym = this.addr2str(addr);
|
||||
var child = top.calls[sym];
|
||||
if (child == null) { child = top.calls[sym] = {count:0, SP:this.lastsp, calls:{}}; }
|
||||
let top = this.stack[this.stack.length-1];
|
||||
let sym = this.addr2str(addr);
|
||||
let child = top.calls[sym];
|
||||
if (child == null) { child = top.calls[sym] = {count:0, PC:addr, SP:this.lastsp, calls:{}}; }
|
||||
else if (child.PC === null) child.PC = addr;
|
||||
//this.stack.forEach((node) => node.count++);
|
||||
this.stack.push(child);
|
||||
child.count++;
|
||||
@ -1548,6 +1561,7 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView {
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (this.graph) this.graph['_stack'] = this.stack;
|
||||
return this.graph;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ const ZMACHINE_PRESETS = [
|
||||
{ id: 'balances.inf', name: 'Balances' },
|
||||
{ id: 'museum.inf', name: 'Museum of Inform' },
|
||||
{ id: 'advent.inf', name: 'Colossal Cave Adventure' },
|
||||
{ id: 'ztrek.inf', name: 'Super Z Trek' },
|
||||
];
|
||||
|
||||
declare var ZVM;
|
||||
@ -38,9 +39,14 @@ interface IFZVM {
|
||||
pc: number;
|
||||
ram: DataView;
|
||||
stack: DataView;
|
||||
read_data: { buffer?};
|
||||
read_data: { buffer?, routine?, time?};
|
||||
handle_line_input(len: number);
|
||||
handle_char_input(charcode: number);
|
||||
handle_create_fileref(fref: number);
|
||||
}
|
||||
|
||||
function debug(...args: any[]) {
|
||||
//console.log(arguments);
|
||||
}
|
||||
|
||||
class GlkWindow {
|
||||
@ -72,11 +78,12 @@ class GlkWindow {
|
||||
}
|
||||
ensureline() {
|
||||
if (this.curline == null) {
|
||||
this.curline = $('<div class="transcript-line"/>')[0];
|
||||
this.page.appendChild(this.curline);
|
||||
this.row++;
|
||||
this.col = 0;
|
||||
this.lines[this.row] = this.curline;
|
||||
this.curline = this.lines[++this.row];
|
||||
if (this.curline == null) {
|
||||
this.curline = $('<div class="transcript-line"/>')[0];
|
||||
this.page.appendChild(this.curline);
|
||||
this.lines[this.row] = this.curline;
|
||||
}
|
||||
}
|
||||
}
|
||||
flushline() {
|
||||
@ -86,24 +93,42 @@ class GlkWindow {
|
||||
addtext(line: string, style: number) {
|
||||
this.ensureline();
|
||||
if (line.length) {
|
||||
var span = $("<span/>").text(line).appendTo(this.curline);
|
||||
// in fixed mode, only do characters
|
||||
if (this.fixed && line.length > 1) {
|
||||
for (var i = 0; i < line.length; i++)
|
||||
this.addtext(line[i], style);
|
||||
return;
|
||||
}
|
||||
var span = $("<span/>").text(line);
|
||||
for (var i = 0; i < 8; i++) {
|
||||
if (style & (1 << i))
|
||||
span.addClass("transcript-style-" + (1 << i));
|
||||
}
|
||||
if (this.reverse) span.addClass("transcript-reverse");
|
||||
//span.data('vmip', this.vm.pc);
|
||||
// in fixed mode, we can overwrite individual characters
|
||||
if (this.fixed && line.length == 1 && this.col < this.curline.childNodes.length) {
|
||||
this.curline.replaceChild(span[0], this.curline.childNodes[this.col]);
|
||||
} else {
|
||||
span.appendTo(this.curline);
|
||||
}
|
||||
this.col += line.length;
|
||||
}
|
||||
}
|
||||
newline() {
|
||||
this.flushline();
|
||||
this.col = 0;
|
||||
}
|
||||
// TODO: bug in interpreter where it tracks cursor position but maybe doesn't do newlines?
|
||||
put_jstring(val: string) {
|
||||
// split by newlines
|
||||
var lines = val.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
if (i > 0) this.flushline();
|
||||
if (i > 0) this.newline();
|
||||
this.addtext(lines[i], this.curstyle);
|
||||
}
|
||||
}
|
||||
move_cursor(col:number, row:number) {
|
||||
move_cursor(col: number, row: number) {
|
||||
if (!this.fixed) return; // fixed windows only
|
||||
// ensure enough row elements
|
||||
while (this.lines.length <= row) {
|
||||
@ -115,24 +140,23 @@ class GlkWindow {
|
||||
this.row = row;
|
||||
// get children in row (individual text cells)
|
||||
var children = $(this.curline).children();
|
||||
// truncate line, or add whitespace
|
||||
// add whitespace to line?
|
||||
if (children.length > col) {
|
||||
children.slice(col).remove();
|
||||
this.col = col;
|
||||
} else {
|
||||
while (this.col < col)
|
||||
this.addtext(' ', this.curstyle);
|
||||
}
|
||||
}
|
||||
setrows(size:number) {
|
||||
setrows(size: number) {
|
||||
if (!this.fixed) return; // fixed windows only
|
||||
this.flushline();
|
||||
// truncate rows?
|
||||
var allrows = $(this.page).children();
|
||||
if (allrows.length > size) {
|
||||
this.flushline();
|
||||
allrows.slice(size).remove();
|
||||
this.lines = this.lines.slice(0, size);
|
||||
this.move_cursor(0,0);
|
||||
//this.move_cursor(0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,28 +261,40 @@ class GlkImpl {
|
||||
this.windows[1].addtext("** Game exited **", 1);
|
||||
}
|
||||
glk_window_clear(win) {
|
||||
console.log('glk_window_clear', arguments);
|
||||
debug('glk_window_clear', arguments);
|
||||
this.windows[win].clear();
|
||||
}
|
||||
glk_request_line_event_uni(win, buf, initlen) {
|
||||
this.waitingfor = 'line';
|
||||
this.focusinput();
|
||||
this.startinputtimer();
|
||||
}
|
||||
glk_request_char_event_uni(win, buf, initlen) {
|
||||
this.waitingfor = 'char';
|
||||
this.focusinput();
|
||||
this.startinputtimer();
|
||||
}
|
||||
startinputtimer() {
|
||||
/* TODO?
|
||||
var rd = this.vm.read_data;
|
||||
if (rd.routine && rd.time) {
|
||||
this.vm['call'](rd.routine);
|
||||
//this.vm.run();
|
||||
setTimeout(this.startinputtimer.bind(this), rd.time*10);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
glk_put_jstring(val: string, allbytes) {
|
||||
//console.log('glk_put_jstring', arguments);
|
||||
//debug('glk_put_jstring', arguments);
|
||||
this.curwnd.put_jstring(val);
|
||||
}
|
||||
glk_put_jstring_stream(stream: number, val: string) {
|
||||
//console.log('glk_put_jstring_stream', arguments);
|
||||
//debug('glk_put_jstring_stream', arguments);
|
||||
this.windows[stream].put_jstring(val);
|
||||
}
|
||||
glk_put_char_stream_uni(stream: number, ch: number) {
|
||||
//console.log('glk_put_char_stream_uni', arguments);
|
||||
//debug('glk_put_char_stream_uni', arguments);
|
||||
this.windows[stream].put_jstring(String.fromCharCode(ch));
|
||||
}
|
||||
glk_set_style(val) {
|
||||
@ -266,31 +302,31 @@ class GlkImpl {
|
||||
}
|
||||
/*
|
||||
glk_put_char(ch) {
|
||||
console.log('glk_put_char', arguments);
|
||||
debug('glk_put_char', arguments);
|
||||
}
|
||||
glk_put_string(val) {
|
||||
console.log('glk_put_string', arguments);
|
||||
debug('glk_put_string', arguments);
|
||||
}
|
||||
glk_put_string_stream(str, val) {
|
||||
console.log('glk_put_string_stream', arguments);
|
||||
debug('glk_put_string_stream', arguments);
|
||||
}
|
||||
glk_put_buffer(arr) {
|
||||
console.log('glk_put_buffer', arguments);
|
||||
debug('glk_put_buffer', arguments);
|
||||
}
|
||||
glk_put_buffer_stream(str, arr) {
|
||||
console.log('glk_put_buffer_stream', arguments);
|
||||
debug('glk_put_buffer_stream', arguments);
|
||||
}
|
||||
glk_set_style_stream(str, val) {
|
||||
console.log('glk_set_style_stream', arguments);
|
||||
debug('glk_set_style_stream', arguments);
|
||||
}
|
||||
glk_get_char_stream(str) {
|
||||
console.log('glk_get_char_stream', arguments);
|
||||
debug('glk_get_char_stream', arguments);
|
||||
}
|
||||
glk_get_line_stream(str, buf) {
|
||||
console.log('glk_get_line_stream', arguments);
|
||||
debug('glk_get_line_stream', arguments);
|
||||
}
|
||||
glk_get_buffer_stream(str, buf) {
|
||||
console.log('glk_get_buffer_stream', arguments);
|
||||
debug('glk_get_buffer_stream', arguments);
|
||||
}
|
||||
*/
|
||||
glk_char_to_lower(val) {
|
||||
@ -308,10 +344,10 @@ class GlkImpl {
|
||||
return val;
|
||||
}
|
||||
glk_stylehint_set(wintype, styl, hint, value) {
|
||||
//console.log('glk_stylehint_set', arguments);
|
||||
//debug('glk_stylehint_set', arguments);
|
||||
}
|
||||
glk_stylehint_clear(wintype, styl, hint) {
|
||||
//console.log('glk_stylehint_clear', arguments);
|
||||
//debug('glk_stylehint_clear', arguments);
|
||||
}
|
||||
glk_style_distinguish(win, styl1, styl2) {
|
||||
return 0;
|
||||
@ -322,62 +358,76 @@ class GlkImpl {
|
||||
return 0;
|
||||
}
|
||||
glk_select(eventref) {
|
||||
console.log('glk_select', arguments);
|
||||
debug('glk_select', arguments);
|
||||
}
|
||||
glk_window_open(splitwin, method, size, wintype, rock) {
|
||||
console.log('glk_window_open', arguments);
|
||||
debug('glk_window_open', arguments);
|
||||
if (splitwin) {
|
||||
// only support status lines for now
|
||||
if (method != 0x12 || wintype != 4 || size != 1) return 0;
|
||||
$(this.windows[2].page).show();
|
||||
if (method != 0x12 || wintype != 4) return 0;
|
||||
if (size) {
|
||||
$(this.windows[2].page).show();
|
||||
return 2; // split window
|
||||
} else {
|
||||
return 3; // fake window
|
||||
}
|
||||
} else {
|
||||
return 1; // main window
|
||||
}
|
||||
return ++this.windowcount;
|
||||
}
|
||||
glk_window_close(win) {
|
||||
console.log('glk_window_close', arguments);
|
||||
if (win == 2) $(this.windows[win].page).hide();
|
||||
debug('glk_window_close', arguments);
|
||||
if (win == 2) {
|
||||
this.windows[win].clear();
|
||||
$(this.windows[win].page).hide();
|
||||
}
|
||||
}
|
||||
glk_window_get_parent(win) {
|
||||
console.log('glk_window_get_parent', arguments);
|
||||
debug('glk_window_get_parent', arguments);
|
||||
if (win == 1) return 0;
|
||||
else return 1;
|
||||
}
|
||||
glk_window_move_cursor(win, col, row) {
|
||||
console.log('glk_window_move_cursor', arguments);
|
||||
debug('glk_window_move_cursor', arguments);
|
||||
this.windows[win].move_cursor(col, row);
|
||||
}
|
||||
glk_window_set_arrangement(win, method, size, unknown) {
|
||||
console.log('glk_window_set_arrangement', arguments);
|
||||
// TODO? this.windows[win].setrows(size);
|
||||
debug('glk_window_set_arrangement', arguments);
|
||||
if (win == 1) this.windows[2].setrows(size);
|
||||
}
|
||||
glk_window_get_stream(win) {
|
||||
console.log('glk_window_get_stream', arguments);
|
||||
debug('glk_window_get_stream', arguments);
|
||||
return this.windows[win].stream;
|
||||
}
|
||||
glk_set_window(win) {
|
||||
console.log('glk_set_window', arguments);
|
||||
debug('glk_set_window', arguments);
|
||||
this.curwnd = this.windows[win];
|
||||
if (this.curwnd == null) this.fatal_error("no window " + win);
|
||||
}
|
||||
glk_window_get_size(win, widthref: RefBox, heightref: RefBox) {
|
||||
console.log('glk_window_get_size', arguments);
|
||||
debug('glk_window_get_size', arguments);
|
||||
// TODO: made up sizes, only status line supported
|
||||
if (widthref) widthref.set_value(STATUS_NUM_COLS);
|
||||
if (heightref) heightref.set_value(win == 1 ? 25 : 1);
|
||||
}
|
||||
garglk_set_reversevideo(val) {
|
||||
console.log('garglk_set_reversevideo', arguments);
|
||||
debug('garglk_set_reversevideo', arguments);
|
||||
this.curwnd.reverse = !!val;
|
||||
}
|
||||
garglk_set_reversevideo_stream(win, val) {
|
||||
console.log('garglk_set_reversevideo_stream', arguments);
|
||||
this.windows[win].reverse = !!val; // TODO: per window
|
||||
debug('garglk_set_reversevideo_stream', arguments);
|
||||
this.windows[win].reverse = !!val;
|
||||
}
|
||||
glk_fileref_create_by_prompt(usage, mode, rock) {
|
||||
debug('glk_fileref_create_by_prompt', arguments);
|
||||
// TODO: support files?
|
||||
this.vm.handle_create_fileref(0);
|
||||
this.vm.run();
|
||||
}
|
||||
glk_gestalt(sel, val) {
|
||||
return this.glk_gestalt_ext(sel, val, null);
|
||||
}
|
||||
glk_gestalt_ext(sel, val, arr) {
|
||||
//console.log('glk_gestalt_ext', arguments);
|
||||
//debug('glk_gestalt_ext', arguments);
|
||||
switch (sel) {
|
||||
|
||||
case 0: // gestalt_Version
|
||||
@ -750,7 +800,7 @@ class ZmachinePlatform implements Platform {
|
||||
this.resize();
|
||||
}
|
||||
|
||||
resize : () => void;
|
||||
resize: () => void;
|
||||
|
||||
loadROM(title, data) {
|
||||
this.zfile = data;
|
||||
@ -833,6 +883,7 @@ class ZmachinePlatform implements Platform {
|
||||
if (this.zvm != null) {
|
||||
root['Objects'] = () => this.getRootObjects();
|
||||
root['Globals'] = () => this.getGlobalVariables();
|
||||
//root['VM'] = () => this.zvm;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user