Skip to content

Instantly share code, notes, and snippets.

@kirjavascript
Last active October 24, 2016 20:56
Show Gist options
  • Save kirjavascript/999422d40d8ee3817e85 to your computer and use it in GitHub Desktop.
Save kirjavascript/999422d40d8ee3817e85 to your computer and use it in GitHub Desktop.
Sonic Disassembly Opcode Frequency
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head><title>sonic.asm</title></head>
<body>
<div class="input">
<input type="button" value="Sonic 1" onclick="update(s1, 'Sonic 1')" />
<input type="button" value="Sonic 2" onclick="update(s2, 'Sonic 2')" />
<input type="button" value="Sonic 3&amp;K" onclick="update(s3, 'Sonic 3&amp;K')" />
</div>
</body>
<style>
.label {
font: 14px sans-serif
}
.axis text {
font: 12px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script>
/*
created by snkenjoi/kirjava/colourful/cake
*/
window.addEventListener("load", function() {
update(s1, "Sonic 1");
});
// config array for width/height/margin
var c = {
w: 1200,
h: 800,
m: 40
}
// setup svg and set viewbox based on w/h/margins
var s = d3.select("body").append("svg")
.attr("width",c.w).attr("height",c.h)
.attr("viewBox",[-c.m,-c.m,c.w+(c.m*2),c.h+(c.m*2)].join(" "))
// adjust scale if viewBox modification breaks stuff
.style("transform", "scale(1.1)")
.style("transform-origin", "0 0")
// for bg and grid
var bg = s.append("g")
// create bar container layer to get appended before the axis
var g = s.append("g");
// axis container
var axis = s.append("g")
// calculate linear (numeric) scale for y (qty) axis
var y = d3.scale.linear()
.range([c.h, 0]);
// calculate ordinal (non-numeric) scale for x (data.name) axis
// ordinal scales require discrete datapoints, so we use .map to
// create the correct array for domain and rangebands for range
var x = d3.scale.ordinal()
// rangeRoundBands produces ints vs rangeBands
// second param is padding
.rangeRoundBands([0, c.w], .2)
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(20)
// background
bg
.append("rect")
.style("fill", "#666")
.attr("width", c.w)
.attr("height", c.h)
// prepare x axis
axis
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + c.h + ")")
//.call(xAxis)
// label
s
.append("text")
.attr("y", -20)
.attr("x", c.w)
.attr("dy", ".71em")
.attr("class", "label")
.style("text-anchor", "end")
.style("font-weight", "bold")
// prepare y axis
axis
.append("g")
.attr("class", "y axis")
function update(data, dataname) {
// update domains
y.domain([0, d3.max(data, function(d){return d.qty})])
x.domain(data.map(function(d){return d.opcode}))
grid(bg)
// update selection
u = s.transition()
// update axis label
u.select(".label")
.text("Frequency of processor opcodes in "+dataname)
// update x axis
u.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-45)"
})
u.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
// save reference to databind
bars = g
.selectAll(".bars")
// the second function passed to data defines the data key for data prone to shifting positions
.data(data, function(d) {return d.opcode})
// enter //
bars
.enter()
.append("rect")
.attr("class","bars")
.style("fill", "steelblue")
.style("stroke", '#FFF')
.style("stroke-width", "1px")
// update //
d3.transition(bars)
.transition()
.duration(500)
.ease("quad")
// stagger animation
.delay(function(d,i){return i*40})
// set height based on data
.attr("height", function(d){return y(0)-y(d.qty)})
// set y position to data value
.attr("y", function(d){return y(d.qty)})
.attr("width", x.rangeBand())
.attr("x", function(d,i) { return x(d.opcode)})
// exit //
d3.transition(bars.exit())
.style("fill-opacity", 0)
.remove();
}
function grid(container) {
var grid = container.selectAll("line.hgrid")
.data(y.ticks(20))
grid
.enter()
.append("line")
.attr("class","hgrid")
.attr("x1",0)
.attr("x2",c.w)
.attr("y1",function(d){ return y(d)})
.attr("y2",function(d){ return y(d)})
.attr("stroke","#444")
//.attr('stroke-width','20')
.attr('stroke-linecap','round')
.attr('stroke-dasharray','1,2')
d3.transition(grid)
.transition()
.duration(500)
.ease("quad")
.attr("x", function(d,i) { return x(d.opcode)})
.attr("y1",function(d){ return y(d)})
.attr("y2",function(d){ return y(d)})
d3.transition(grid.exit())
.style("fill-opacity", 0)
.remove();
return grid;
}
// data was produced from the drx/Stealth disassemblies with this;
// c={};require("fs").readFileSync("s1.asm","utf-8").split("\n").forEach(function
// (d){d=d.match(/\s([A-Za-z]+)(\s|.)/);if(d&&c[d[1]])c[d[1]]++;else if(d)c[d[1]]
// =1});l={};for(ke in c){if(c[ke]>7*8)l[ke]=c[ke]}console.log(JSON.stringify(l))
var _s1 = {"bra":703,"tst":770,"bne":865,"lea":834,"move":7642,"andi":540,"beq":786,"moveq":1230,"movea":298,"add":639,"dbf":292,"btst":320,"cmpi":798,"cmp":221,"bcc":273,"bsr":917,"jsr":522,"rts":967,"addq":707,"addi":266,"bcs":283,"subq":451,"clr":321,"lsl":131,"sub":496,"adda":116,"asl":78,"lsr":128,"ext":140,"jmp":292,"bmi":190,"bpl":408,"swap":78,"neg":238,"bhi":91,"subi":221,"bset":206,"bclr":185,"asr":80,};
var _s2 = {"nop":94,"bra":1709,"tst":1323,"bne":1668,"lea":1920,"movem":134,"move":15588,"andi":1042,"beq":1831,"moveq":2206,"movea":542,"add":1348,"dbf":452,"btst":693,"cmpi":1478,"cmp":478,"bcc":497,"bsr":2578,"jsr":511,"jmp":975,"addq":1422,"subq":794,"rts":1737,"bcs":476,"S":285,"bge":77,"addi":710,"blt":152,"eori":77,"subi":383,"bgt":92,"lsr":281,"clr":529,"ori":215,"lsl":197,"or":130,"sub":720,"bpl":520,"swap":337,"adda":150,"asl":125,"ext":216,"bmi":388,"neg":495,"bhi":124,"bchg":58,"bset":353,"bclr":346,"st":68,"muls":69,"asr":188};
var _s3 =
{"lea":5893,"tst":3835,"bne":4509,"movem":351,"move":36167,"andi":2040,"beq":4511,"moveq":4968,"movea":1786,"add":3151,"dbf":814,"btst":2121,"bra":2278,"cmp":1308,"jmp":3560,"bsr":2427,"S":1565,"cmpi":3519,"rts":4338,"jsr":6930,"addq":2037,"subq":1673,"clr":2011,"eori":82,"bcc":1350,"bclr":1147,"ori":348,"subi":755,"bcs":1278,"sub":2529,"adda":265,"addi":1723,"swap":726,"lsl":485,"or":159,"not":62,"and":231,"bpl":1488,"bhi":317,"cmpa":69,"lsr":526,"asl":134,"ext":393,"bmi":916,"neg":1234,"divu":70,"bchg":117,"bls":201,"blt":181,"asr":557,"bset":1405,"muls":162,"bgt":105,"st":398,"ble":75,"bge":146,"mulu":57,"ds":326};
function o2oa(b){a=[];for(k in b)a.push({"opcode":k,"qty":b[k]});return a};
var s1 = o2oa(_s1);
var s2 = o2oa(_s2);
var s3 = o2oa(_s3);
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment