mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-21 21:29:11 +00:00
added base_z80 platform and viz.html example
This commit is contained in:
parent
1f45dfdd74
commit
5ae8d28922
11
bootstrap/css/bootstrap-darkly.min.css
vendored
Normal file
11
bootstrap/css/bootstrap-darkly.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
204
css/ui.css
Normal file
204
css/ui.css
Normal file
@ -0,0 +1,204 @@
|
||||
.dbg_info {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.gutter-offset {
|
||||
width: 3em;
|
||||
}
|
||||
.gutter-bytes {
|
||||
width: 6em;
|
||||
}
|
||||
.gutter-clock {
|
||||
width: 0.5em;
|
||||
}
|
||||
.gutter-info {
|
||||
width: 1em;
|
||||
}
|
||||
.tooltipbox {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border-bottom: 1px dotted black;
|
||||
}
|
||||
.tooltipbox .tooltiptext {
|
||||
visibility: hidden;
|
||||
width: 120px;
|
||||
background-color: black;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 5px 0;
|
||||
|
||||
/* Position the tooltip */
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
.tooltipbox:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
#controls_top {
|
||||
position: absolute;
|
||||
padding: 0.5em;
|
||||
height:3em;
|
||||
width:100%;
|
||||
background-color:#999;
|
||||
}
|
||||
#notebook {
|
||||
position:absolute;
|
||||
top:3em;
|
||||
bottom:0;
|
||||
left:0;
|
||||
right:0;
|
||||
background-color: #666;
|
||||
overflow: hidden;;
|
||||
}
|
||||
div.workspace {
|
||||
background-color:#999;
|
||||
}
|
||||
div.editor {
|
||||
width:50%;
|
||||
line-height:1.25;
|
||||
font-size:12pt;
|
||||
}
|
||||
div.emulator {
|
||||
position:absolute;
|
||||
left:50%;
|
||||
top:0;
|
||||
width:50%;
|
||||
background-color: #666;
|
||||
margin-top: 20px auto 0;
|
||||
}
|
||||
div.debugwindow {
|
||||
position:absolute;
|
||||
left:50%;
|
||||
top:0;
|
||||
width:50%;
|
||||
background-color: #666;
|
||||
color: #66ff66;
|
||||
white-space: pre;
|
||||
margin-top: 20px auto 0;
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
div.mem_info {
|
||||
position: fixed;
|
||||
left: 51%;
|
||||
bottom: 10px;
|
||||
background-color: #333;
|
||||
color: #66ff66;
|
||||
white-space: pre;
|
||||
padding: 20px;
|
||||
z-index: 12;
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
font-size: 12pt;
|
||||
}
|
||||
.btn_group {
|
||||
border-radius:6px;
|
||||
padding:6px;
|
||||
margin-left:8px;
|
||||
background-color: #666;
|
||||
}
|
||||
.btn_group.debug_group {
|
||||
}
|
||||
.btn_group.view_group {
|
||||
}
|
||||
.seg_code { color: #ff9966; }
|
||||
.seg_data { color: #66ff66; }
|
||||
.seg_stack { color: #ffff66; }
|
||||
.seg_unknown { color: #cccccc; }
|
||||
span.hilite {
|
||||
color: #ff66ff;
|
||||
}
|
||||
div.has-errors {
|
||||
background-color: #ff6666 !important;
|
||||
}
|
||||
div.is-busy-unused {
|
||||
background-color: #8888bb !important;
|
||||
}
|
||||
div.menu_div {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
div.booklink {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 6px;
|
||||
background-color: #ffffff;
|
||||
display:none;
|
||||
}
|
||||
div.twitbtn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
padding: 6px;
|
||||
}
|
||||
a {
|
||||
color:#333399;
|
||||
font-weight: bold;
|
||||
}
|
||||
a.dropdown-toggle {
|
||||
color:#66ee66;
|
||||
padding:3px;
|
||||
}
|
||||
// http://stackoverflow.com/questions/18023493/bootstrap-3-dropdown-sub-menu-missing
|
||||
.dropdown-submenu {
|
||||
position:relative;
|
||||
}
|
||||
.dropdown-submenu>.dropdown-menu {
|
||||
top:0;
|
||||
left:100%;
|
||||
margin-top:-6px;
|
||||
margin-left:-1px;
|
||||
-webkit-border-radius:0 6px 6px 6px;
|
||||
-moz-border-radius:0 6px 6px 6px;
|
||||
border-radius:0 6px 6px 6px;
|
||||
}
|
||||
.dropdown-submenu:hover>.dropdown-menu {
|
||||
display:block;
|
||||
}
|
||||
.dropdown-submenu>a:after {
|
||||
display:block;
|
||||
content:" ";
|
||||
float:right;
|
||||
width:0;
|
||||
height:0;
|
||||
border-color:transparent;
|
||||
border-style:solid;
|
||||
border-width:5px 0 5px 5px;
|
||||
border-left-color:#cccccc;
|
||||
margin-top:5px;
|
||||
margin-right:-10px;
|
||||
}
|
||||
.dropdown-submenu:hover>a:after {
|
||||
border-left-color:#ffffff;
|
||||
}
|
||||
.dropdown-submenu.pull-left {
|
||||
float:none;
|
||||
}
|
||||
.dropdown-submenu.pull-left>.dropdown-menu {
|
||||
left:-100%;
|
||||
margin-left:10px;
|
||||
-webkit-border-radius:6px 0 6px 6px;
|
||||
-moz-border-radius:6px 0 6px 6px;
|
||||
border-radius:6px 0 6px 6px;
|
||||
}
|
||||
.emubevel {
|
||||
padding:4%;
|
||||
background:#333;
|
||||
}
|
||||
.emuvideo {
|
||||
border-radius:20px;
|
||||
border: 4px solid #222;
|
||||
padding: 30px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
background: #000;
|
||||
outline-color: #666;
|
||||
}
|
||||
canvas.pixelated {
|
||||
image-rendering: optimizeSpeed; /* Older versions of FF */
|
||||
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
|
||||
image-rendering: -webkit-optimize-contrast; /* Safari */
|
||||
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
|
||||
image-rendering: pixelated; /* Awesome future-browsers */
|
||||
-ms-interpolation-mode: nearest-neighbor; /* IE */
|
||||
}
|
205
index.html
205
index.html
@ -7,211 +7,8 @@ body {
|
||||
overflow: hidden !important;
|
||||
font-size: 11px;
|
||||
}
|
||||
.dbg_info {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.gutter-offset {
|
||||
width: 3em;
|
||||
}
|
||||
.gutter-bytes {
|
||||
width: 6em;
|
||||
}
|
||||
.gutter-clock {
|
||||
width: 0.5em;
|
||||
}
|
||||
.gutter-info {
|
||||
width: 1em;
|
||||
}
|
||||
.tooltipbox {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border-bottom: 1px dotted black;
|
||||
}
|
||||
.tooltipbox .tooltiptext {
|
||||
visibility: hidden;
|
||||
width: 120px;
|
||||
background-color: black;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 5px 0;
|
||||
|
||||
/* Position the tooltip */
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
.tooltipbox:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
#controls_top {
|
||||
position: absolute;
|
||||
padding: 0.5em;
|
||||
height:3em;
|
||||
width:100%;
|
||||
background-color:#999;
|
||||
}
|
||||
#notebook {
|
||||
position:absolute;
|
||||
top:3em;
|
||||
bottom:0;
|
||||
left:0;
|
||||
right:0;
|
||||
background-color: #666;
|
||||
overflow: hidden;;
|
||||
}
|
||||
div.workspace {
|
||||
background-color:#999;
|
||||
}
|
||||
div.editor {
|
||||
width:50%;
|
||||
line-height:1.25;
|
||||
font-size:12pt;
|
||||
}
|
||||
div.emulator {
|
||||
position:absolute;
|
||||
left:50%;
|
||||
top:0;
|
||||
width:50%;
|
||||
background-color: #666;
|
||||
margin-top: 20px auto 0;
|
||||
}
|
||||
div.debugwindow {
|
||||
position:absolute;
|
||||
left:50%;
|
||||
top:0;
|
||||
width:50%;
|
||||
background-color: #666;
|
||||
color: #66ff66;
|
||||
white-space: pre;
|
||||
margin-top: 20px auto 0;
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
div.mem_info {
|
||||
position: fixed;
|
||||
left: 51%;
|
||||
bottom: 10px;
|
||||
background-color: #333;
|
||||
color: #66ff66;
|
||||
white-space: pre;
|
||||
padding: 20px;
|
||||
z-index: 12;
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
font-size: 12pt;
|
||||
}
|
||||
.btn_group {
|
||||
border-radius:6px;
|
||||
padding:6px;
|
||||
margin-left:8px;
|
||||
background-color: #666;
|
||||
}
|
||||
.btn_group.debug_group {
|
||||
}
|
||||
.btn_group.view_group {
|
||||
}
|
||||
.seg_code { color: #ff9966; }
|
||||
.seg_data { color: #66ff66; }
|
||||
.seg_stack { color: #ffff66; }
|
||||
.seg_unknown { color: #cccccc; }
|
||||
span.hilite {
|
||||
color: #ff66ff;
|
||||
}
|
||||
div.has-errors {
|
||||
background-color: #ff6666 !important;
|
||||
}
|
||||
div.is-busy-unused {
|
||||
background-color: #8888bb !important;
|
||||
}
|
||||
div.menu_div {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
div.booklink {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 6px;
|
||||
background-color: #ffffff;
|
||||
display:none;
|
||||
}
|
||||
div.twitbtn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
padding: 6px;
|
||||
}
|
||||
a {
|
||||
color:#333399;
|
||||
font-weight: bold;
|
||||
}
|
||||
a.dropdown-toggle {
|
||||
color:#66ee66;
|
||||
padding:3px;
|
||||
}
|
||||
// http://stackoverflow.com/questions/18023493/bootstrap-3-dropdown-sub-menu-missing
|
||||
.dropdown-submenu {
|
||||
position:relative;
|
||||
}
|
||||
.dropdown-submenu>.dropdown-menu {
|
||||
top:0;
|
||||
left:100%;
|
||||
margin-top:-6px;
|
||||
margin-left:-1px;
|
||||
-webkit-border-radius:0 6px 6px 6px;
|
||||
-moz-border-radius:0 6px 6px 6px;
|
||||
border-radius:0 6px 6px 6px;
|
||||
}
|
||||
.dropdown-submenu:hover>.dropdown-menu {
|
||||
display:block;
|
||||
}
|
||||
.dropdown-submenu>a:after {
|
||||
display:block;
|
||||
content:" ";
|
||||
float:right;
|
||||
width:0;
|
||||
height:0;
|
||||
border-color:transparent;
|
||||
border-style:solid;
|
||||
border-width:5px 0 5px 5px;
|
||||
border-left-color:#cccccc;
|
||||
margin-top:5px;
|
||||
margin-right:-10px;
|
||||
}
|
||||
.dropdown-submenu:hover>a:after {
|
||||
border-left-color:#ffffff;
|
||||
}
|
||||
.dropdown-submenu.pull-left {
|
||||
float:none;
|
||||
}
|
||||
.dropdown-submenu.pull-left>.dropdown-menu {
|
||||
left:-100%;
|
||||
margin-left:10px;
|
||||
-webkit-border-radius:6px 0 6px 6px;
|
||||
-moz-border-radius:6px 0 6px 6px;
|
||||
border-radius:6px 0 6px 6px;
|
||||
}
|
||||
.emubevel {
|
||||
padding:4%;
|
||||
background:#333;
|
||||
}
|
||||
.emuvideo {
|
||||
border-radius:20px;
|
||||
border: 4px solid #222;
|
||||
padding: 30px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
background: #000;
|
||||
outline-color: #666;
|
||||
}
|
||||
canvas.pixelated {
|
||||
image-rendering: optimizeSpeed; /* Older versions of FF */
|
||||
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
|
||||
image-rendering: -webkit-optimize-contrast; /* Safari */
|
||||
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
|
||||
image-rendering: pixelated; /* Awesome future-browsers */
|
||||
-ms-interpolation-mode: nearest-neighbor; /* IE */
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/ui.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
3
presets/base_z80/empty.c
Normal file
3
presets/base_z80/empty.c
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
void func() {
|
||||
}
|
9
presets/base_z80/fib.c
Normal file
9
presets/base_z80/fib.c
Normal file
@ -0,0 +1,9 @@
|
||||
int Fibonacci(int n)
|
||||
{
|
||||
if ( n == 0 )
|
||||
return 0;
|
||||
else if ( n == 1 )
|
||||
return 1;
|
||||
else
|
||||
return ( Fibonacci(n-1) + Fibonacci(n-2) );
|
||||
}
|
31
presets/base_z80/gfx.c
Normal file
31
presets/base_z80/gfx.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
|
||||
byte __at (0x2400) vidmem[224][32]; // 256x224x1 video memory
|
||||
|
||||
void clrscr() {
|
||||
memset(vidmem, 0, sizeof(vidmem));
|
||||
}
|
||||
|
||||
void xor_pixel(byte x, byte y) {
|
||||
byte* dest = &vidmem[x][y>>3];
|
||||
*dest ^= 0x1 << (y&7);
|
||||
}
|
||||
|
||||
byte xor_sprite(const byte* src, byte x, byte y) {
|
||||
byte i,j;
|
||||
byte result = 0;
|
||||
byte* dest = &vidmem[x][y];
|
||||
byte w = *src++;
|
||||
byte h = *src++;
|
||||
for (j=0; j<h; j++) {
|
||||
for (i=0; i<w; i++) {
|
||||
result |= (*dest++ ^= *src++);
|
||||
}
|
||||
dest += 32-w;
|
||||
}
|
||||
return result;
|
||||
}
|
8
presets/base_z80/prng.c
Normal file
8
presets/base_z80/prng.c
Normal file
@ -0,0 +1,8 @@
|
||||
unsigned int lfsr = 1;
|
||||
|
||||
unsigned int rand() {
|
||||
char lsb = lfsr & 1;
|
||||
lfsr >>= 1;
|
||||
if (lsb) lfsr ^= 0xd400;
|
||||
return lfsr;
|
||||
}
|
3
presets/base_z80/simple1.c
Normal file
3
presets/base_z80/simple1.c
Normal file
@ -0,0 +1,3 @@
|
||||
int func(int x) {
|
||||
return x * 2;
|
||||
}
|
3
presets/base_z80/simple2.c
Normal file
3
presets/base_z80/simple2.c
Normal file
@ -0,0 +1,3 @@
|
||||
int func(int x) {
|
||||
return x / 4;
|
||||
}
|
3
presets/base_z80/skeleton.sdcc
Normal file
3
presets/base_z80/skeleton.sdcc
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
void func() {
|
||||
}
|
79
src/platform/base_z80.js
Normal file
79
src/platform/base_z80.js
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
"use strict";
|
||||
var BASEZ80_PRESETS = [
|
||||
{id:'simple1.c', name:'Multiply by 2'},
|
||||
{id:'simple2.c', name:'Divide by 4'},
|
||||
{id:'prng.c', name:'Pseudorandom Numbers'},
|
||||
{id:'fib.c', name:'Fibonacci'},
|
||||
{id:'gfx.c', name:'Graphics'},
|
||||
{id:'empty.c', name:'Your Code Here...'},
|
||||
];
|
||||
|
||||
var Base_Z80Platform = function(mainElement) {
|
||||
var self = this;
|
||||
this.__proto__ = new BaseZ80Platform();
|
||||
|
||||
var cpu, ram, membus, iobus, rom, timer;
|
||||
|
||||
this.getPresets = function() {
|
||||
return BASEZ80_PRESETS;
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
ram = new RAM(0x8000);
|
||||
membus = {
|
||||
read: new AddressDecoder([
|
||||
[0x0000, 0x7fff, 0x7fff, function(a) { return rom ? rom[a] : null; }],
|
||||
[0x8000, 0xffff, 0x7fff, function(a) { return ram.mem[a]; }],
|
||||
]),
|
||||
write: new AddressDecoder([
|
||||
[0x8000, 0xffff, 0x7fff, function(a,v) { ram.mem[a] = v; }],
|
||||
]),
|
||||
isContended: function() { return false; },
|
||||
};
|
||||
this.readAddress = membus.read;
|
||||
iobus = {
|
||||
read: function(addr) {
|
||||
return 0;
|
||||
},
|
||||
write: function(addr, val) {
|
||||
}
|
||||
};
|
||||
cpu = this.newCPU(membus, iobus);
|
||||
}
|
||||
|
||||
this.loadROM = function(title, data) {
|
||||
rom = padBytes(data, 0x8000);
|
||||
self.reset();
|
||||
}
|
||||
|
||||
this.loadState = function(state) {
|
||||
cpu.loadState(state.c);
|
||||
ram.mem.set(state.b);
|
||||
}
|
||||
this.saveState = function() {
|
||||
return {
|
||||
c:self.getCPUState(),
|
||||
b:ram.mem.slice(0),
|
||||
};
|
||||
}
|
||||
this.getCPUState = function() {
|
||||
return cpu.saveState();
|
||||
}
|
||||
|
||||
this.isRunning = function() {
|
||||
return timer && timer.isRunning();
|
||||
}
|
||||
this.pause = function() {
|
||||
if (timer) timer.stop();
|
||||
}
|
||||
this.resume = function() {
|
||||
if (timer) timer.start();
|
||||
}
|
||||
this.reset = function() {
|
||||
cpu.reset();
|
||||
if (!this.getDebugCallback()) cpu.setTstates(0); // TODO?
|
||||
}
|
||||
}
|
||||
|
||||
PLATFORMS['base_z80'] = Base_Z80Platform;
|
94
src/ui.js
94
src/ui.js
@ -111,6 +111,7 @@ var TOOL_TO_SOURCE_STYLE = {
|
||||
}
|
||||
|
||||
var worker = new Worker("./src/worker/workermain.js");
|
||||
var main_editor;
|
||||
var current_output;
|
||||
var current_preset_index = -1;
|
||||
var current_preset_id;
|
||||
@ -173,8 +174,10 @@ function getCurrentPresetTitle() {
|
||||
}
|
||||
|
||||
function setLastPreset(id) {
|
||||
localStorage.setItem("__lastplatform", platform_id);
|
||||
localStorage.setItem("__lastid_"+platform_id, id);
|
||||
if (platform_id != 'base_z80') { // TODO
|
||||
localStorage.setItem("__lastplatform", platform_id);
|
||||
localStorage.setItem("__lastid_"+platform_id, id);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePreset(current_preset_id, text) {
|
||||
@ -185,7 +188,7 @@ function updatePreset(current_preset_id, text) {
|
||||
|
||||
function loadCode(text, fileid) {
|
||||
var tool = platform.getToolForFilename(fileid);
|
||||
newEditor(tool && TOOL_TO_SOURCE_STYLE[tool]);
|
||||
main_editor = newEditor(tool && TOOL_TO_SOURCE_STYLE[tool]);
|
||||
editor.setValue(text); // calls setCode()
|
||||
editor.clearHistory();
|
||||
current_output = null;
|
||||
@ -314,7 +317,7 @@ function _downloadROMImage(e) {
|
||||
}
|
||||
|
||||
function populateExamples(sel) {
|
||||
sel.append($("<option />").text("--------- Chapters ---------").attr('disabled',true));
|
||||
sel.append($("<option />").text("--------- Examples ---------").attr('disabled',true));
|
||||
for (var i=0; i<PRESETS.length; i++) {
|
||||
var preset = PRESETS[i];
|
||||
var name = preset.chapter ? (preset.chapter + ". " + preset.name) : preset.name;
|
||||
@ -341,8 +344,10 @@ function populateFiles(sel, name, prefix) {
|
||||
|
||||
function updateSelector() {
|
||||
var sel = $("#preset_select").empty();
|
||||
populateFiles(sel, "Local Files", "local/");
|
||||
populateFiles(sel, "Shared", "shared/");
|
||||
if (platform_id != 'base_z80') { // TODO
|
||||
populateFiles(sel, "Local Files", "local/");
|
||||
populateFiles(sel, "Shared", "shared/");
|
||||
}
|
||||
populateExamples(sel);
|
||||
// set click handlers
|
||||
sel.off('change').change(function(e) {
|
||||
@ -464,6 +469,7 @@ function setCompileOutput(data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
updateDisassembly();
|
||||
if (trace_pending_at_pc) {
|
||||
showLoopTimingForPC(trace_pending_at_pc);
|
||||
}
|
||||
@ -664,7 +670,12 @@ function updateDisassembly() {
|
||||
var state = lastDebugState || platform.saveState();
|
||||
var pc = state.c.PC;
|
||||
if (assemblyfile && assemblyfile.text) {
|
||||
disasmview.setValue(assemblyfile.text);
|
||||
var asmtext = assemblyfile.text;
|
||||
if (platform_id == 'base_z80') { // TODO
|
||||
asmtext = asmtext.replace(/[ ]+\d+\s+;.+\n/g, '');
|
||||
asmtext = asmtext.replace(/[ ]+\d+\s+.area .+\n/g, '');
|
||||
}
|
||||
disasmview.setValue(asmtext);
|
||||
var findPC = platform.getDebugCallback() ? pc : getCurrentPC();
|
||||
if (findPC) {
|
||||
var lineno = assemblyfile.findLineForOffset(findPC);
|
||||
@ -673,43 +684,44 @@ function updateDisassembly() {
|
||||
jumpToLine(disasmview, lineno-1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
var curline = 0;
|
||||
var selline = 0;
|
||||
// TODO: not perfect disassembler
|
||||
function disassemble(start, end) {
|
||||
if (start < 0) start = 0;
|
||||
if (end > 0xffff) end = 0xffff;
|
||||
// TODO: use pc2visits
|
||||
var a = start;
|
||||
var s = "";
|
||||
while (a < end) {
|
||||
var disasm = platform.disassemble(a, platform.readAddress);
|
||||
var srclinenum = sourcefile.offset2line[a];
|
||||
if (srclinenum) {
|
||||
var srcline = editor.getLine(srclinenum-1);
|
||||
if (srcline && srcline.trim().length) {
|
||||
s += "; " + srclinenum + ":\t" + srcline + "\n";
|
||||
else if (platform.disassemble) {
|
||||
var curline = 0;
|
||||
var selline = 0;
|
||||
// TODO: not perfect disassembler
|
||||
function disassemble(start, end) {
|
||||
if (start < 0) start = 0;
|
||||
if (end > 0xffff) end = 0xffff;
|
||||
// TODO: use pc2visits
|
||||
var a = start;
|
||||
var s = "";
|
||||
while (a < end) {
|
||||
var disasm = platform.disassemble(a, platform.readAddress);
|
||||
var srclinenum = sourcefile.offset2line[a];
|
||||
if (srclinenum) {
|
||||
var srcline = editor.getLine(srclinenum-1);
|
||||
if (srcline && srcline.trim().length) {
|
||||
s += "; " + srclinenum + ":\t" + srcline + "\n";
|
||||
}
|
||||
}
|
||||
var bytes = "";
|
||||
for (var i=0; i<disasm.nbytes; i++)
|
||||
bytes += hex(platform.readAddress(a+i));
|
||||
while (bytes.length < 14)
|
||||
bytes += ' ';
|
||||
var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + disasm.line + "\n";
|
||||
s += dline;
|
||||
if (a == pc) selline = curline;
|
||||
curline++;
|
||||
a += disasm.nbytes || 1;
|
||||
}
|
||||
var bytes = "";
|
||||
for (var i=0; i<disasm.nbytes; i++)
|
||||
bytes += hex(platform.readAddress(a+i));
|
||||
while (bytes.length < 14)
|
||||
bytes += ' ';
|
||||
var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + disasm.line + "\n";
|
||||
s += dline;
|
||||
if (a == pc) selline = curline;
|
||||
curline++;
|
||||
a += disasm.nbytes || 1;
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
var text = disassemble(pc-96, pc) + disassemble(pc, pc+96);
|
||||
disasmview.setValue(text);
|
||||
disasmview.setCursor(selline, 0);
|
||||
jumpToLine(disasmview, selline);
|
||||
}
|
||||
var text = disassemble(pc-96, pc) + disassemble(pc, pc+96);
|
||||
disasmview.setValue(text);
|
||||
disasmview.setCursor(selline, 0);
|
||||
jumpToLine(disasmview, selline);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1085,6 +1097,7 @@ function showWelcomeMessage() {
|
||||
tour.init();
|
||||
setTimeout(function() { tour.start(); }, 2000);
|
||||
}
|
||||
if (qs['redir']) delete qs['redir'];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
@ -1125,7 +1138,6 @@ function startPlatform() {
|
||||
platform = new PLATFORMS[platform_id]($("#emulator")[0]);
|
||||
PRESETS = platform.getPresets();
|
||||
if (qs['file']) {
|
||||
showWelcomeMessage();
|
||||
// start platform and load file
|
||||
preloadWorker(qs['file']);
|
||||
platform.start();
|
||||
@ -1192,9 +1204,11 @@ function startUI(loadplatform) {
|
||||
$.getScript(scriptfn, function() {
|
||||
console.log("loaded platform", platform_id);
|
||||
startPlatform();
|
||||
showWelcomeMessage();
|
||||
});
|
||||
} else {
|
||||
startPlatform();
|
||||
showWelcomeMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,13 @@ var PLATFORM_PARAMS = {
|
||||
data_size: 0x400,
|
||||
stack_end: 0x8000,
|
||||
},
|
||||
'base_z80': {
|
||||
code_start: 0x0,
|
||||
code_size: 0x8000,
|
||||
data_start: 0x8000,
|
||||
data_size: 0x8000,
|
||||
stack_end: 0x0,
|
||||
},
|
||||
};
|
||||
|
||||
var loaded = {}
|
||||
|
80
viz.html
Normal file
80
viz.html
Normal file
@ -0,0 +1,80 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>8bitworkshop ~ Z80 Compiler Visualization</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="stylesheet" href="css/ui.css">
|
||||
<style type="text/css" media="screen">
|
||||
div.CodeMirror {
|
||||
line-height:1.25;
|
||||
font-size:12pt;
|
||||
border: 1px solid #eee;
|
||||
height: 600pt;
|
||||
}
|
||||
#preset_select {
|
||||
color: #000;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="jquery/jquery-2.2.3.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap-darkly.min.css">
|
||||
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||
|
||||
<script src="codemirror/lib/codemirror.js"></script>
|
||||
<script src="codemirror/mode/clike/clike.js"></script>
|
||||
<script src="codemirror/mode/6502/6502.js"></script>
|
||||
<script src="codemirror/mode/z80/z80.js"></script>
|
||||
<link rel="stylesheet" href="css/codemirror.css">
|
||||
<script src="codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script src="codemirror/addon/selection/active-line.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="page-header">
|
||||
<p class="lead">
|
||||
Edit a C source file, and see the Z80 assembly output update in real-time.
|
||||
</p>
|
||||
<h6>Powered by <a target="_new" href="https://twitter.com/8bitworkshop">@8bitworkshop</a> and the Small Device C Compiler.</h6>
|
||||
<select id="preset_select" name="">
|
||||
</select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div id="editor" class="editor2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div id="disassembly">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
Javatari = {};
|
||||
PLATFORMS = {};
|
||||
</script>
|
||||
|
||||
<script src="src/cpu/z80.js"></script>
|
||||
<script src="src/util.js"></script>
|
||||
<script src="src/emu.js"></script>
|
||||
<script src="src/ui.js"></script>
|
||||
<script src="src/platform/base_z80.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
platform_id = 'base_z80';
|
||||
startPlatform();
|
||||
$('#disassembly').show();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user