├── Image-3.10.29
├── initramfs.cpio.lzo
├── vexpress-armjs.dtb
├── images
├── ui-icons_222222_256x240.png
├── ui-icons_2e83ff_256x240.png
├── ui-icons_454545_256x240.png
├── ui-icons_888888_256x240.png
├── ui-icons_cd0a0a_256x240.png
├── ui-bg_flat_0_aaaaaa_40x100.png
├── ui-bg_flat_75_ffffff_40x100.png
├── ui-bg_glass_55_fbf9ee_1x400.png
├── ui-bg_glass_65_ffffff_1x400.png
├── ui-bg_glass_75_dadada_1x400.png
├── ui-bg_glass_75_e6e6e6_1x400.png
├── ui-bg_glass_95_fef1ec_1x400.png
└── ui-bg_highlight-soft_75_cccccc_1x100.png
├── .gitmodules
├── misc
├── simple-http-server.rb
├── symbols.rb
├── term.js.patch
├── jquery-1.7.2-binary.patch
└── vexpress-armjs.dts
├── js
├── display.js
├── JSONlocalStorage.js
├── logger.js
├── utils.js
├── parameter.js
├── tracer.js
├── option.js
├── filesystem.js
├── number64.js
├── armv7-mmu.js
├── virtio.js
├── bitops.js
├── jquery-ui-1.8.18.custom.min.js
├── 9p.js
└── armv7-cp15.js
├── README.md
├── arm-js.html
└── css
└── jquery-ui-1.8.18.custom.css
/Image-3.10.29:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/Image-3.10.29
--------------------------------------------------------------------------------
/initramfs.cpio.lzo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/initramfs.cpio.lzo
--------------------------------------------------------------------------------
/vexpress-armjs.dtb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/vexpress-armjs.dtb
--------------------------------------------------------------------------------
/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/images/ui-icons_2e83ff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-icons_2e83ff_256x240.png
--------------------------------------------------------------------------------
/images/ui-icons_454545_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-icons_454545_256x240.png
--------------------------------------------------------------------------------
/images/ui-icons_888888_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-icons_888888_256x240.png
--------------------------------------------------------------------------------
/images/ui-icons_cd0a0a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-icons_cd0a0a_256x240.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "js/simpleterm"]
2 | path = js/simpleterm
3 | url = https://github.com/michaelko/simpleterm.git
4 |
--------------------------------------------------------------------------------
/images/ui-bg_flat_0_aaaaaa_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_flat_0_aaaaaa_40x100.png
--------------------------------------------------------------------------------
/images/ui-bg_flat_75_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_flat_75_ffffff_40x100.png
--------------------------------------------------------------------------------
/images/ui-bg_glass_55_fbf9ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_glass_55_fbf9ee_1x400.png
--------------------------------------------------------------------------------
/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/images/ui-bg_glass_75_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_glass_75_dadada_1x400.png
--------------------------------------------------------------------------------
/images/ui-bg_glass_75_e6e6e6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_glass_75_e6e6e6_1x400.png
--------------------------------------------------------------------------------
/images/ui-bg_glass_95_fef1ec_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_glass_95_fef1ec_1x400.png
--------------------------------------------------------------------------------
/images/ui-bg_highlight-soft_75_cccccc_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ozaki-r/arm-js/HEAD/images/ui-bg_highlight-soft_75_cccccc_1x100.png
--------------------------------------------------------------------------------
/misc/simple-http-server.rb:
--------------------------------------------------------------------------------
1 | require 'webrick'
2 |
3 | srv = WEBrick::HTTPServer.new({:DocumentRoot => '.',
4 | :BindAddress => '127.0.0.1',
5 | :Port => 8080})
6 |
7 | srv_shutdown = Proc.new do
8 | srv.shutdown()
9 | end
10 |
11 | Signal.trap(:INT, srv_shutdown)
12 | Signal.trap(:TERM, srv_shutdown)
13 |
14 | srv.start()
15 |
--------------------------------------------------------------------------------
/js/display.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function Display(display_id, options) {
8 | this.display_id = display_id;
9 | }
10 |
11 | Display.prototype.log = function(content) {
12 | var display = document.getElementById(this.display_id);
13 | display.innerHTML += content + "\n";
14 | };
15 |
16 | Display.prototype.wipe = function() {
17 | var display = document.getElementById(this.display_id);
18 | display.innerHTML = "";
19 | };
20 |
21 |
--------------------------------------------------------------------------------
/misc/symbols.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 | #
3 | # Javascript ARMv7 Emulator
4 | #
5 | # Copyright 2012, Ryota Ozaki
6 | # Dual licensed under the MIT or GPL Version 2 licenses.
7 | #
8 |
9 | symbols = {}
10 | sym2addr = {}
11 | ARGF.readlines.each do |line|
12 | #if line =~ /(\w+) <([\w_]+)>:/
13 | if line =~ /^(\w+) [Tt] ([\.\w_]+)$/
14 | addr = "0x" + $1
15 | name = $2
16 | symbols[addr] = name
17 | sym2addr[name] = addr
18 | end
19 | end
20 |
21 | puts "Symbols = Object();"
22 | symbols.each do |addr, name|
23 | puts "Symbols[#{addr}] = \"#{name}\";"
24 | end
25 |
26 | puts "Symbol2Address = Object();"
27 | sym2addr.each do |name, addr|
28 | puts "Symbol2Address[\"#{name}\"] = #{addr};"
29 | if name.include?('.')
30 | puts "Symbol2Address[\"#{name.gsub(/\..+/, '')}\"] = #{addr};"
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/misc/term.js.patch:
--------------------------------------------------------------------------------
1 | --- /tmp/term.js.beautiful 2012-09-30 23:18:01.000000000 +0900
2 | +++ term.js 2012-09-30 23:28:47.000000000 +0900
3 | @@ -39,14 +39,12 @@
4 | for (i = 0; i < this.w; i++) da[i] = c;
5 | this.lines[y] = da;
6 | }
7 | - document.writeln('
');
8 | for (y = 0; y < this.h; y++) {
9 | - document.writeln(' |
');
10 | + $('#terminal').append(' |
');
11 | }
12 | - document.writeln('
');
13 | this.refresh(0, this.h - 1);
14 | - document.addEventListener("keydown", this.keyDownHandler.bind(this), true);
15 | - document.addEventListener("keypress", this.keyPressHandler.bind(this), true);
16 | + $('#terminal').keydown(this.keyDownHandler.bind(this));
17 | + $('#terminal').keypress(this.keyPressHandler.bind(this));
18 | ea = this;
19 | setInterval(function() {
20 | ea.cursor_timer_cb();
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Arm-js
2 | ======
3 |
4 | Arm-js is an ARM emulator written in Javascript. It emulates ARMv7-A
5 | and some peripherals of Versatile Express. It can boot Linux 3.10.29
6 | and run busybox processes.
7 |
8 | Emulator Features
9 | ---
10 |
11 | * Suspend/resume (Chrome only)
12 | * You can restore emulator states at any time
13 | * Persistent storage (Chrome only)
14 | * Guest can access part of browser [filesystem](http://www.w3.org/TR/file-system-api/) via virtio-9p
15 | * Many debugging functions
16 |
17 | Tested Browsers
18 | ---
19 |
20 | * Chrome 33 beta (recommended)
21 | * Firefox 27
22 |
23 | Get Started
24 | ---
25 |
26 | 1. Download the source code
27 | 1. git clone git://github.com/ozaki-r/arm-js.git
28 | 2. cd arm-js/
29 | 2. git submodule init
30 | 3. git submodule update
31 | 2. Execute ruby misc/simple-http-server.rb on terminal
32 | 3. Access http://localhost:8080/arm-js.html
33 | 4. Push Boot button at the top-left corner to start the emulator
34 |
35 | Further Information
36 | ---
37 |
38 | See the [wiki](https://github.com/ozaki-r/arm-js/wiki).
39 |
--------------------------------------------------------------------------------
/js/JSONlocalStorage.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function JSONlocalStorage(name, target, list) {
8 | this.name = name;
9 | this.target = target;
10 | this.list = list;
11 | }
12 |
13 | JSONlocalStorage.prototype.restore = function() {
14 | var json = localStorage[this.name];
15 | if (!json)
16 | return;
17 | var data = JSON.parse(json);
18 | for (var i in this.list) {
19 | var name = this.list[i];
20 | var val = data[name];
21 | if (val || val === false) {
22 | //console.debug("localStorage[" + opt + "] => " + val);
23 | this.target[name] = val;
24 | }
25 | }
26 | };
27 |
28 | JSONlocalStorage.prototype.save = function() {
29 | var data = Object();
30 | //localStorage.clear();
31 | for (var i in this.list) {
32 | var name = this.list[i];
33 | var val = this.target[name];
34 | if (val || val === false) {
35 | //console.debug("localStorage[" + opt + "] <= " + val);
36 | data[name] = val;
37 | }
38 | }
39 | localStorage[this.name] = JSON.stringify(data);
40 | };
41 |
42 |
--------------------------------------------------------------------------------
/misc/jquery-1.7.2-binary.patch:
--------------------------------------------------------------------------------
1 | --- jquery-1.7.2.js 2012-03-22 04:46:56.000000000 +0900
2 | +++ jquery-1.7.2-binary.js 2012-06-02 22:02:16.000000000 +0900
3 | @@ -7302,6 +7302,7 @@
4 | html: "text/html",
5 | text: "text/plain",
6 | json: "application/json, text/javascript",
7 | + binary: "text/plain; charset=x-user-defined",
8 | "*": allTypes
9 | },
10 |
11 | @@ -7669,6 +7670,14 @@
12 | }
13 | }
14 |
15 | + if ( s.dataType == "binary" ) {
16 | + if (jqXHR.hasOwnProperty("responseType")) {
17 | + jqXHR.responseType = "arraybuffer";
18 | + } else {
19 | + jqXHR.overrideMimeType('text/plain; charset=x-user-defined');
20 | + }
21 | + }
22 | +
23 | // Set the Accepts header for the server, depending on the dataType
24 | jqXHR.setRequestHeader(
25 | "Accept",
26 | @@ -7834,7 +7843,7 @@
27 | }
28 |
29 | // Remove auto dataType and get content-type in the process
30 | - while( dataTypes[ 0 ] === "*" ) {
31 | + while( dataTypes[ 0 ] === "*" || dataTypes[ 0 ] === "binary") {
32 | dataTypes.shift();
33 | if ( ct === undefined ) {
34 | ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
35 |
--------------------------------------------------------------------------------
/js/logger.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function Logger(target, options) {
8 | this.target = target;
9 | this.options = options;
10 |
11 | this.reset();
12 | }
13 |
14 | Logger.prototype.reset = function() {
15 | this.logs = new Array();
16 | this.total = 0;
17 | };
18 |
19 | Logger.prototype.log = function(str) {
20 | if (!this.options.enable_logger)
21 | return;
22 | this.logs.push(str);
23 | this.total += 1;
24 | // log_size would change
25 | while (this.logs.length > this.options.log_size)
26 | this.logs.shift();
27 | };
28 |
29 |
30 | Logger.prototype.dump = function() {
31 | //if (!this.options.enable_logger)
32 | // return;
33 | var output = 0;
34 | var msgs = "";
35 | for (var i=0; i < this.logs.length; i++) {
36 | var log = this.logs[i];
37 | if (log) {
38 | msgs += log + "\n";
39 | output += 1;
40 | }
41 | if (i > 0 && (i % 100) === 0) {
42 | if (msgs)
43 | this.target.log(msgs);
44 | msgs = "";
45 | }
46 | }
47 | if (msgs)
48 | this.target.log(msgs);
49 | this.target.log("Logger: output=" + output);
50 | this.target.log("Logger: total=" + this.total);
51 | };
52 |
53 |
--------------------------------------------------------------------------------
/js/utils.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function assert(cond, val) {
8 | if (!cond) {
9 | if (typeof val == "string")
10 | throw "Assertion failed: " + val;
11 | if (val)
12 | throw "Assertion failed: " + val.toString(16) + "(" + val.toString(2) + ")";
13 | else
14 | throw "Assertion failed."
15 | }
16 | }
17 |
18 | function assert2(x, y, str) {
19 | if (x != y) {
20 | var msg = "";
21 | if (str == undefined)
22 | throw "Assertion failed: " + toStringNum(x) + " != " + toStringNum(y);
23 | else
24 | throw "Assertion failed(" + str + "): " + toStringNum(x) + " != " + toStringNum(y);
25 | }
26 | }
27 |
28 | function toStringBinInst(inst) {
29 | var ret = "";
30 | var bin = inst.toString(2);
31 | while (bin.length < 32)
32 | bin = "0" + bin;
33 | for (var i=0; i < 32; i++) {
34 | ret += bin.charAt(i);
35 | if ((i + 1) % 4 == 0 && i != 31)
36 | ret += " ";
37 | }
38 | return ret;
39 | }
40 |
41 | function toStringBin(val, n) {
42 | var ret = val.toString(2);
43 | while (ret.length < n)
44 | ret = "0" + ret;
45 | return ret;
46 | }
47 |
48 | function toStringBin32(val) {
49 | return toStringBin(val, 32);
50 | }
51 |
52 | function toStringBin64(val) {
53 | return toStringBin(val, 64);
54 | }
55 |
56 | function toStringBin16(val) {
57 | return toStringBin(val, 16);
58 | }
59 |
60 | function toStringHex32(ulong) {
61 | if (!ulong) {
62 | if (ulong === null)
63 | return "(null)";
64 | if (ulong === undefined)
65 | return "(undefined)";
66 | if (ulong === Number.NaN)
67 | return "(NaN)";
68 | }
69 | var ret = ulong.toString(16);
70 | while (ret.length < 8)
71 | ret = "0" + ret;
72 | return ret;
73 | }
74 |
75 | function toStringNum(num) {
76 | return num.toString(10) + "(" + num.toString(16) + ")";
77 | }
78 |
79 | function toStringInst(inst) {
80 | return toStringHex32(inst) + "(" + toStringBinInst(inst) + ")";
81 | }
82 |
83 | function toStringAscii(uint) {
84 | var ret = "";
85 | for (var i=0; i < 32; i += 8) {
86 | var b = bitops.get_bits(uint, 32-1 - i, 32-1 - i - 7);
87 | if (b >= 32 && b <= 126)
88 | ret += String.fromCharCode(b);
89 | else
90 | ret += '.';
91 | }
92 | return ret;
93 | }
94 |
95 | function abort(str) {
96 | throw str;
97 | }
98 |
99 | function stringToLong(str) {
100 | if (str.length != 4)
101 | abort("String.toLong: string too long: " + str.length + " > 4");
102 | var ret = 0;
103 | ret += str.charCodeAt(3) << 24;
104 | ret += str.charCodeAt(2) << 16;
105 | ret += str.charCodeAt(1) << 8;
106 | ret += str.charCodeAt(0);
107 | return ret;
108 | };
109 |
110 | function getCurrentTime() {
111 | return (new Date()).getTime();
112 | };
113 |
--------------------------------------------------------------------------------
/js/parameter.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function Configurations() {
8 | this.memory_size = 20*1024*1024;
9 |
10 | this.configuration_strings = [
11 | 'memory_size'
12 | ];
13 |
14 | this.JSONlocalStorage = new JSONlocalStorage("configurations", this, this.configuration_strings);
15 | }
16 |
17 | Configurations.prototype.read_saved_values = function() {
18 | display.log("Restoring Saved configurations");
19 | this.JSONlocalStorage.restore();
20 | this.reflect();
21 | };
22 |
23 | Configurations.prototype.save_to_localStorage = function() {
24 | display.log("Saving configurations");
25 | this.JSONlocalStorage.save();
26 | };
27 |
28 | Configurations.prototype.reflect_input_number = function(name) {
29 | if (!this[name])
30 | return;
31 | $('#' + name).val((this[name]/1024/1024).toString());
32 | };
33 |
34 | Configurations.prototype.reflect = function() {
35 | this.reflect_input_number('memory_size');
36 | };
37 |
38 | Configurations.prototype.register_input_number_handler = function(name) {
39 | var configs = this;
40 | $('#' + name).change(function() {
41 | configs[name] = parseInt(this.value)*1024*1024;
42 | }).change();
43 | };
44 |
45 | Configurations.prototype.register_handlers = function() {
46 | this.register_input_number_handler('memory_size');
47 | };
48 |
49 | Configurations.prototype.dump = function(target) {
50 | for (var i in this.configuration_strings) {
51 | var config = this.configuration_strings[i];
52 | target.log(config + ": " + this[config]);
53 | }
54 | };
55 |
56 | function Parameters() {
57 | this.Image_url = 'Image-3.10.29';
58 | this.cmdline = 'rw root=/dev/ram0 console=ttyAMA0 earlyprintk';
59 | this.initrd_url = 'initramfs.cpio.lzo';
60 | this.initrd_size = 172428;
61 | this.initrd_decomp_size = 310784;
62 | this.dtb_url = 'vexpress-armjs.dtb';
63 |
64 | this.parameter_strings = [
65 | 'Image_url',
66 | 'cmdline',
67 | 'initrd_url',
68 | 'initrd_size',
69 | 'initrd_decomp_size',
70 | 'dtb_url',
71 | ];
72 |
73 | this.JSONlocalStorage = new JSONlocalStorage("parameters", this, this.parameter_strings);
74 | }
75 |
76 | Parameters.prototype.read_saved_values = function() {
77 | display.log("Restoring Saved parameters");
78 | this.JSONlocalStorage.restore();
79 | this.reflect();
80 | };
81 |
82 | Parameters.prototype.save_to_localStorage = function() {
83 | display.log("Saving parameters");
84 | this.JSONlocalStorage.save();
85 | };
86 |
87 | Parameters.prototype.reflect_input_number = function(name) {
88 | if (!this[name])
89 | return;
90 | $('#' + name).val(this[name].toString());
91 | };
92 |
93 | Parameters.prototype.reflect_input_text = function(name) {
94 | $('#' + name).val(this[name]);
95 | };
96 |
97 | Parameters.prototype.reflect = function() {
98 | this.reflect_input_text('Image_url');
99 | this.reflect_input_text('cmdline');
100 | this.reflect_input_text('initrd_url');
101 | this.reflect_input_number('initrd_size');
102 | this.reflect_input_number('initrd_decomp_size');
103 | this.reflect_input_text('dtb_url');
104 | };
105 |
106 | Parameters.prototype.register_input_number_handler = function(name) {
107 | var params = this;
108 | $('#' + name).change(function() {
109 | params[name] = parseInt(this.value);
110 | }).change();
111 | };
112 |
113 | Parameters.prototype.register_input_text_handler = function(name) {
114 | var params = this;
115 | $('#' + name).change(function() {
116 | params[name] = this.value;
117 | }).change();
118 | };
119 |
120 | Parameters.prototype.register_handlers = function() {
121 | this.register_input_text_handler('Image_url');
122 | this.register_input_text_handler('cmdline');
123 | this.register_input_text_handler('initrd_url');
124 | this.register_input_number_handler('initrd_size');
125 | this.register_input_number_handler('initrd_decomp_size');
126 | this.register_input_text_handler('dtb_url');
127 | };
128 |
129 | Parameters.prototype.dump = function(target) {
130 | for (var i in this.parameter_strings) {
131 | var param = this.parameter_strings[i];
132 | target.log(param + ": " + this[param]);
133 | }
134 | };
135 |
136 |
--------------------------------------------------------------------------------
/misc/vexpress-armjs.dts:
--------------------------------------------------------------------------------
1 | /*
2 | * ARM Ltd. Versatile Express for arm-js
3 | * Licensed under GPL 2.0
4 | *
5 | * This DTS is based on vexpress-v2p-ca9.dts
6 | * and vexpress-v2m.dtsi.
7 | *
8 | */
9 |
10 | /dts-v1/;
11 |
12 | / {
13 | model = "ARM-JS";
14 | compatible = "arm,vexpress";
15 | interrupt-parent = <&gic>;
16 | #address-cells = <1>;
17 | #size-cells = <1>;
18 |
19 | chosen {
20 | //bootargs = "rw root=/dev/ram0 console=ttyAMA0 earlyprintk initrd=0x00800000,135433 debug ignore_loglevel";
21 | bootargs = "rw root=/dev/ram0 console=ttyAMA0 earlyprintk initrd=0x00800000,135433";
22 | };
23 |
24 | aliases {
25 | serial0 = &v2m_serial0;
26 | arm,v2m_timer = &v2m_timer01;
27 | };
28 |
29 | cpus {
30 | #address-cells = <1>;
31 | #size-cells = <0>;
32 |
33 | cpu@0 {
34 | device_type = "cpu";
35 | compatible = "arm,cortex-a9";
36 | reg = <0>;
37 | //next-level-cache = <&L2>;
38 | };
39 | };
40 |
41 | memory@0 {
42 | device_type = "memory";
43 | reg = <0x00000000 0x01400000>; /* 20 MB */
44 | };
45 |
46 | gic: interrupt-controller@1e001000 {
47 | compatible = "arm,cortex-a9-gic";
48 | #interrupt-cells = <3>;
49 | #address-cells = <0>;
50 | interrupt-controller;
51 | reg = <0x1e001000 0x1000>,
52 | <0x1e000100 0x100>;
53 | };
54 |
55 | motherboard {
56 | compatible = "simple-bus";
57 | #address-cells = <2>; /* SMB chipselect number and offset */
58 | #size-cells = <1>;
59 | #interrupt-cells = <1>;
60 |
61 | ranges = <7 0 0x10000000 0x00020000>;
62 |
63 | interrupt-map-mask = <0 0 63>;
64 | interrupt-map = <0 0 0 &gic 0 0 4>,
65 | <0 0 1 &gic 0 1 4>,
66 | <0 0 2 &gic 0 2 4>,
67 | <0 0 3 &gic 0 3 4>,
68 | <0 0 4 &gic 0 4 4>,
69 | <0 0 5 &gic 0 5 4>,
70 | <0 0 6 &gic 0 6 4>,
71 | <0 0 7 &gic 0 7 4>,
72 | <0 0 8 &gic 0 8 4>,
73 | <0 0 9 &gic 0 9 4>,
74 | <0 0 10 &gic 0 10 4>,
75 | <0 0 11 &gic 0 11 4>,
76 | <0 0 12 &gic 0 12 4>,
77 | <0 0 13 &gic 0 13 4>,
78 | <0 0 14 &gic 0 14 4>,
79 | <0 0 15 &gic 0 15 4>,
80 | <0 0 16 &gic 0 16 4>,
81 | <0 0 17 &gic 0 17 4>,
82 | <0 0 18 &gic 0 18 4>,
83 | <0 0 19 &gic 0 19 4>,
84 | <0 0 20 &gic 0 20 4>,
85 | <0 0 21 &gic 0 21 4>,
86 | <0 0 22 &gic 0 22 4>,
87 | <0 0 23 &gic 0 23 4>,
88 | <0 0 24 &gic 0 24 4>,
89 | <0 0 25 &gic 0 25 4>,
90 | <0 0 26 &gic 0 26 4>,
91 | <0 0 27 &gic 0 27 4>,
92 | <0 0 28 &gic 0 28 4>,
93 | <0 0 29 &gic 0 29 4>,
94 | <0 0 30 &gic 0 30 4>,
95 | <0 0 31 &gic 0 31 4>,
96 | <0 0 32 &gic 0 32 4>,
97 | <0 0 33 &gic 0 33 4>,
98 | <0 0 34 &gic 0 34 4>,
99 | <0 0 35 &gic 0 35 4>,
100 | <0 0 36 &gic 0 36 4>,
101 | <0 0 37 &gic 0 37 4>,
102 | <0 0 38 &gic 0 38 4>,
103 | <0 0 39 &gic 0 39 4>,
104 | <0 0 40 &gic 0 40 4>,
105 | <0 0 41 &gic 0 41 4>,
106 | <0 0 42 &gic 0 42 4>;
107 |
108 | iofpga@7,00000000 {
109 | compatible = "arm,amba-bus", "simple-bus";
110 | #address-cells = <1>;
111 | #size-cells = <1>;
112 | ranges = <0 7 0 0x20000>;
113 |
114 | v2m_sysreg: sysreg@00000 {
115 | compatible = "arm,vexpress-sysreg";
116 | reg = <0x00000 0x1000>;
117 | };
118 |
119 | v2m_sysctl: sysctl@01000 {
120 | compatible = "arm,sp810", "arm,primecell";
121 | reg = <0x01000 0x1000>;
122 | clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>;
123 | clock-names = "refclk", "timclk";
124 | #clock-cells = <1>;
125 | clock-output-names = "timerclken0", "timerclken1";
126 | };
127 |
128 | v2m_serial0: uart@09000 {
129 | compatible = "arm,pl011", "arm,primecell";
130 | reg = <0x09000 0x1000>;
131 | interrupts = <5>;
132 | arm,primecell-periphid = <0x00041011>;
133 | //clocks = <&v2m_oscclk2>, <&smbclk>;
134 | //clock-names = "uartclk", "apb_pclk";
135 | clocks = <&smbclk>;
136 | clock-names = "apb_pclk";
137 | };
138 |
139 | v2m_timer01: timer@11000 {
140 | compatible = "arm,sp804", "arm,primecell";
141 | reg = <0x11000 0x1000>;
142 | interrupts = <2>;
143 | clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>;
144 | clock-names = "timclken1", "timclken2";
145 | };
146 |
147 | v2m_refclk1mhz: refclk1mhz {
148 | compatible = "fixed-clock";
149 | #clock-cells = <0>;
150 | clock-frequency = <1000000>;
151 | clock-output-names = "v2m:refclk1mhz";
152 | };
153 |
154 | v2m_refclk32khz: refclk32khz {
155 | compatible = "fixed-clock";
156 | #clock-cells = <0>;
157 | clock-frequency = <32768>;
158 | clock-output-names = "v2m:refclk32khz";
159 | };
160 |
161 | virtio_9p@15000 {
162 | compatible = "virtio,mmio";
163 | reg = <0x15000 0x100>;
164 | interrupts = <15>;
165 | };
166 | };
167 | };
168 | dcc {
169 | compatible = "arm,vexpress,config-bus";
170 | arm,vexpress,config-bridge = <&v2m_sysreg>;
171 |
172 | smbclk: oscclk2: osc@2 {
173 | /* Reference clock for the test chip internal PLLs */
174 | compatible = "arm,vexpress-osc";
175 | arm,vexpress-sysreg,func = <1 2>;
176 | freq-range = <33000000 100000000>;
177 | #clock-cells = <0>;
178 | clock-output-names = "tcrefclk";
179 | };
180 | };
181 | };
182 |
--------------------------------------------------------------------------------
/js/tracer.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function Tracer(target, options) {
8 | this.target = target;
9 | this.options = options;
10 |
11 | this.reset();
12 | }
13 |
14 | Tracer.prototype.reset = function() {
15 | this.name_logs = new Array();
16 | this.inst_logs = new Array();
17 | this.counter = new Array();
18 | this.inst_dup_hash = new Array();
19 | this.inst_dup_list = new Array();
20 | this.total = 0;
21 | this.hit = 0;
22 | };
23 |
24 | Tracer.prototype.log = function(name, inst) {
25 | if (!this.options.enable_tracer)
26 | return;
27 | if (!this.options.tracer_buffering) {
28 | this.target.log(name);
29 | return;
30 | }
31 | this.total += 1;
32 | var ihash = this.inst_dup_hash;
33 | if (ihash[inst]) {
34 | this.hit += 1;
35 | return;
36 | }
37 | ihash[inst] = true;
38 |
39 | var ilist = this.inst_dup_list;
40 | ilist.push(inst);
41 | while (ilist.length > this.options.check_size) {
42 | var old = ilist.shift();
43 | ihash[old] = false;
44 | }
45 | var ilogs = this.inst_logs;
46 | ilogs.push(inst);
47 | this.name_logs.push(name);
48 | this.counter.push(this.total);
49 | while (ilogs.length > this.options.trace_size) {
50 | ilogs.shift();
51 | this.name_logs.shift();
52 | this.counter.shift();
53 | }
54 | };
55 |
56 | Tracer.prototype.dump = function() {
57 | //if (!this.options.enable_tracer)
58 | // return;
59 | var output = 0;
60 | var msgs = "";
61 | for (var i=0; i < this.inst_logs.length; i++) {
62 | var name = this.name_logs[i];
63 | var inst = this.inst_logs[i];
64 | var n = this.counter[i];
65 | if (name && inst) {
66 | msgs += "(" + n.toString() + ")" + "\t" + name + "\n";
67 | output += 1;
68 | }
69 | if (i > 0 && (i % 100) === 0) {
70 | if (msgs)
71 | this.target.log(msgs);
72 | msgs = "";
73 | }
74 | }
75 | if (msgs)
76 | this.target.log(msgs);
77 | this.target.log("Tracer: output=" + output + ", hit=" + this.hit + ", total=" + this.total);
78 | };
79 |
80 | function BranchTracer(target, options) {
81 | this.target = target;
82 | this.options = options;
83 |
84 | this.reset();
85 | }
86 |
87 | BranchTracer.prototype.reset = function() {
88 | this.addr_logs = new Array();
89 | this.from_addr_logs = new Array();
90 | this.counter = new Array();
91 | this.dup_counter = new Array();
92 | this.depth_logs = new Array();
93 | this.total = 0;
94 | this.last_symbol = "";
95 | this.last_from_addr = 0;
96 | this.omitted_counter = 0;
97 | };
98 |
99 | BranchTracer.prototype.log = function(addr, from_addr, depth) {
100 | if (!this.options.enable_branch_tracer)
101 | return;
102 | this.total += 1;
103 | if (!Symbols[addr])
104 | return;
105 | if (from_addr == this.last_from_addr && Symbols[addr] == this.last_symbol) {
106 | this.omitted_counter += 1;
107 | return;
108 | }
109 | this.last_symbol = Symbols[addr];
110 | this.last_from_addr = from_addr;
111 | var alogs = this.addr_logs;
112 | alogs.push(addr);
113 | this.from_addr_logs.push(from_addr);
114 | this.dup_counter.push(this.omitted_counter);
115 | this.counter.push(this.total);
116 | this.depth_logs.push(depth);
117 | while (alogs.length > this.options.branch_trace_size) {
118 | alogs.shift();
119 | this.from_addr_logs.shift();
120 | this.dup_counter.shift();
121 | this.counter.shift();
122 | this.depth_logs.shift();
123 | }
124 | this.omitted_counter = 0;
125 | };
126 |
127 | BranchTracer.prototype.dump = function() {
128 | //if (!this.options.enable_branch_tracer)
129 | // return;
130 | var output = 0;
131 | // XXX: have to displace by one
132 | this.dup_counter.push(this.omitted_counter);
133 | var msgs = "";
134 | for (var i=0; i < this.addr_logs.length; i++) {
135 | var addr = this.addr_logs[i];
136 | var from_addr = this.from_addr_logs[i];
137 | var n = this.counter[i];
138 | var d = this.dup_counter[i];
139 | var depth = this.depth_logs[i];
140 | if (addr && n) {
141 | // FIXME
142 | depth = depth % 20;
143 | var indent = new Array(depth + 1).join(" ");
144 | if (d)
145 | msgs += "(" + n.toString() + ")" + "\t" + toStringHex32(from_addr) + " =>\t" + toStringHex32(addr) + "\t" + indent + Symbols[addr] + " (" + d + ")\n";
146 | else
147 | msgs += "(" + n.toString() + ")" + "\t" + toStringHex32(from_addr) + " =>\t" + toStringHex32(addr) + "\t" + indent + Symbols[addr] + "\n";
148 | output += 1;
149 | }
150 | if (i > 0 && (i % 100) === 0) {
151 | if (msgs)
152 | this.target.log(msgs);
153 | msgs = "";
154 | }
155 | }
156 | if (msgs)
157 | this.target.log(msgs);
158 | this.target.log("BranchTracer: output=" + output + ", total=" + this.total);
159 | // XXX: have to remove last one
160 | this.dup_counter.pop();
161 | };
162 |
163 |
--------------------------------------------------------------------------------
/js/option.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function Options() {
8 | this.enable_stopper = false;
9 | this.enable_logger = false;
10 | this.enable_tracer = false;
11 | this.enable_branch_tracer = false;
12 | this.logger_buffering = true;
13 | this.log_size = 1000;
14 | this.trace_size = 1000;
15 | this.trace_check_size = 10;
16 | this.tracer_buffering = true;
17 | this.branch_trace_size = 1000;
18 | this.branch_tracer_buffering = true;
19 | this.stop_counter = Number.NaN;
20 | this.stop_instruction = Number.NaN;
21 | this.stop_address = Number.NaN;
22 | this.stop_at_every_branch = false;
23 | this.stop_at_every_funccall = false;
24 | this.update_current_function = false;
25 | this.suppress_interrupts = false;
26 | this.show_act_on_viraddr = Number.NaN;
27 | this.enable_instruction_counting = false;
28 |
29 | this.option_strings = [
30 | 'enable_stopper',
31 | 'stop_address',
32 | 'stop_counter',
33 | 'stop_instruction',
34 | 'stop_at_every_branch',
35 | 'stop_at_every_funccall',
36 | 'enable_logger',
37 | 'log_size',
38 | 'logger_buffering',
39 | 'enable_tracer',
40 | 'trace_size',
41 | 'trace_check_size',
42 | 'tracer_buffering',
43 | 'enable_branch_tracer',
44 | 'branch_trace_size',
45 | 'branch_tracer_buffering',
46 | 'update_current_function',
47 | 'suppress_interrupts',
48 | 'show_act_on_viraddr',
49 | 'enable_instruction_counting'
50 | ];
51 | this.hex_values = {
52 | 'stop_address': true,
53 | 'stop_instruction': true,
54 | 'show_act_on_viraddr': true
55 | };
56 |
57 | this.JSONlocalStorage = new JSONlocalStorage("options", this, this.option_strings);
58 | }
59 |
60 | Options.prototype.read_saved_values = function(display) {
61 | display.log("Restoring Saved options");
62 | this.JSONlocalStorage.restore();
63 | this.reflect();
64 | };
65 |
66 | Options.prototype.save_to_localStorage = function() {
67 | display.log("Saving options");
68 | this.JSONlocalStorage.save();
69 | };
70 |
71 | Options.prototype.reflect_input_number = function(name) {
72 | if (!this[name])
73 | return;
74 | if (this.hex_values[name])
75 | $('#' + name).val(this[name].toString(16));
76 | else
77 | $('#' + name).val(this[name].toString());
78 | };
79 |
80 | Options.prototype.reflect_checkbox = function(name) {
81 | if (this[name])
82 | $('#' + name).attr('checked','checked');
83 | else
84 | $('#' + name).removeAttr('checked');
85 | };
86 |
87 | Options.prototype.reflect = function() {
88 | this.reflect_input_number('log_size');
89 | this.reflect_checkbox('enable_logger');
90 | this.reflect_checkbox('logger_buffering');
91 | this.reflect_input_number('trace_size');
92 | this.reflect_input_number('trace_check_size');
93 | this.reflect_checkbox('enable_tracer');
94 | this.reflect_checkbox('tracer_buffering');
95 | this.reflect_input_number('branch_trace_size');
96 | this.reflect_checkbox('enable_branch_tracer');
97 | this.reflect_checkbox('branch_tracer_buffering');
98 | this.reflect_checkbox('enable_stopper');
99 | this.reflect_input_number('stop_address');
100 | if (Symbols[this.stop_address])
101 | $('#stop_address_name').val(Symbols[this.stop_address]);
102 | this.reflect_input_number('stop_instruction');
103 | this.reflect_input_number('stop_counter');
104 | this.reflect_checkbox('stop_at_every_branch');
105 | this.reflect_checkbox('stop_at_every_funccall');
106 | this.reflect_checkbox('update_current_function');
107 | this.reflect_checkbox('suppress_interrupts');
108 | this.reflect_input_number('show_act_on_viraddr');
109 | if (Symbols[this.show_act_on_viraddr])
110 | $('#show_act_on_symbol').val(Symbols[this.show_act_on_viraddr]);
111 | this.reflect_checkbox('enable_instruction_counting');
112 | };
113 |
114 | Options.prototype.register_checkbox_handler = function(name, childs) {
115 | var options = this;
116 | $('#' + name).change(function() {
117 | options[name] = this.checked;
118 | for (var i in childs) {
119 | if (this.checked)
120 | $('#' + childs[i]).removeAttr('disabled');
121 | else
122 | $('#' + childs[i]).attr('disabled', 'disabled');
123 | }
124 | }).change();
125 | };
126 |
127 | Options.prototype.register_input_number_handler = function(name) {
128 | var options = this;
129 | $('#' + name).change(function() {
130 | if (options.hex_values[name])
131 | options[name] = parseInt(this.value, 16);
132 | else
133 | options[name] = parseInt(this.value);
134 | }).change();
135 | };
136 |
137 | Options.prototype.register_symaddr_handler = function(addrname, symname) {
138 | var options = this;
139 | $('#' + addrname).change(function() {
140 | options[addrname] = parseInt(this.value, 16);
141 | if (Symbols[options[addrname]])
142 | $('#' + symname).val(Symbols[options[addrname]]);
143 | else
144 | $('#' + symname).val('');
145 | }).change();
146 | $("#" + symname).change(function() {
147 | var symname_value = this.value;
148 | if (Symbol2Address[symname_value]) {
149 | options[symname] = symname_value;
150 | options[addrname] = Symbol2Address[symname_value];
151 | $('#' + addrname).val(options[addrname].toString(16));
152 | } else {
153 | options[addrname] = Number.NaN;
154 | $('#' + addrname).val('');
155 | }
156 | }).change();
157 | };
158 |
159 | Options.prototype.register_handlers = function() {
160 | this.register_checkbox_handler('enable_logger', ['log_size', 'show_logs']);
161 | this.register_input_number_handler('log_size');
162 | this.register_checkbox_handler('logger_buffering');
163 | this.register_checkbox_handler('enable_tracer', ['trace_size', 'trace_check_size', 'show_traces']);
164 | this.register_input_number_handler('trace_size');
165 | this.register_input_number_handler('trace_check_size');
166 | this.register_checkbox_handler('tracer_buffering');
167 | this.register_checkbox_handler('enable_branch_tracer', ['branch_trace_size', 'show_branch_traces']);
168 | this.register_input_number_handler('branch_trace_size');
169 | this.register_checkbox_handler('branch_tracer_buffering');
170 | this.register_checkbox_handler('enable_stopper', ['stop_address', 'stop_address_name', 'stop_instruction', 'stop_counter', 'stop_at_every_branch', 'stop_at_every_funccall']);
171 | this.register_symaddr_handler('stop_address', 'stop_address_name');
172 | this.register_input_number_handler('stop_instruction');
173 | this.register_input_number_handler('stop_counter');
174 | this.register_checkbox_handler('stop_at_every_branch');
175 | this.register_checkbox_handler('stop_at_every_funccall');
176 | this.register_checkbox_handler('update_current_function');
177 | this.register_checkbox_handler('suppress_interrupts');
178 | this.register_symaddr_handler('show_act_on_viraddr', 'show_act_on_symbol');
179 | this.register_checkbox_handler('enable_instruction_counting');
180 | };
181 |
182 | Options.prototype.dump = function(target) {
183 | for (var i in this.option_strings) {
184 | var opt = this.option_strings[i];
185 | target.log(opt + ": " + this[opt]);
186 | }
187 | };
188 |
189 | Options.prototype.parse_querystring = function() {
190 | if (location.search == "")
191 | return;
192 | var qss = location.search.substring(1).split("&");
193 | for (var i in qss) {
194 | var qs = qss[i].split("=");
195 | var optname = qs[0];
196 | if (this[optname] == undefined)
197 | throw "Invalid option name = " + optname;
198 | var val = qs[1]
199 | if (val == "true")
200 | val = true;
201 | else if (val == "false")
202 | val = false;
203 | else if (val.indexOf("0x") == 0)
204 | val = parseInt(val, 16);
205 | else if (parseInt(val) != NaN)
206 | val = parseInt(val);
207 | this[optname] = val;
208 | }
209 | console.log(this);
210 | };
211 |
--------------------------------------------------------------------------------
/js/filesystem.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
8 |
9 | function fsTestAvailability(requestByte, sCallback, eCallback) {
10 | if (!window.webkitStorageInfo) {
11 | if (eCallback)
12 | eCallback();
13 | return;
14 | }
15 | window.webkitStorageInfo.requestQuota(window.PERSISTENT, requestByte, function(grantedBytes) {
16 | window.requestFileSystem(window.PERSISTENT, requestByte, function(fs) {
17 | if (sCallback)
18 | sCallback(fs);
19 | }, eCallback);
20 | }, eCallback);
21 | }
22 |
23 | function HTML5FileSystem(root, requestByte) {
24 | this.rootDirectory = root;
25 | this.requestByte = requestByte;
26 |
27 | this.enabled = false;
28 | this.fs = null;
29 |
30 | var that = this;
31 | fsTestAvailability(requestByte, function(fs) {
32 | that.fs = fs;
33 | that.enabled = true;
34 | fs.root.getDirectory(that.rootDirectory, {create: true}, null, errorHandler);
35 | }, errorHandler);
36 | }
37 |
38 | function errorHandler(e) {
39 | var msg = '';
40 | if (window.FileError === undefined) {
41 | console.log('Error: Unknown');
42 | return;
43 | }
44 |
45 | switch (e.code) {
46 | case FileError.ABORT_ERR:
47 | msg = 'ABORT_ERR';
48 | break;
49 | case FileError.ENCODING_ERR:
50 | msg = 'ENCODING_ERR';
51 | break;
52 | case FileError.QUOTA_EXCEEDED_ERR:
53 | msg = 'QUOTA_EXCEEDED_ERR';
54 | break;
55 | case FileError.NOT_FOUND_ERR:
56 | msg = 'NOT_FOUND_ERR';
57 | break;
58 | case FileError.NOT_READABLE_ERR:
59 | msg = 'NOT_READABLE_ERR';
60 | break;
61 | case FileError.NO_MODIFICATION_ALLOWED_ERR:
62 | msg = 'NO_MODIFICATION_ALLOWED_ERR';
63 | break;
64 | case FileError.SECURITY_ERR:
65 | msg = 'SECURITY_ERR';
66 | break;
67 | case FileError.INVALID_MODIFICATION_ERR:
68 | msg = 'INVALID_MODIFICATION_ERR';
69 | break;
70 | case FileError.INVALID_STATE_ERR:
71 | msg = 'INVALID_STATE_ERR';
72 | break;
73 | case FileError.SYNTAX_ERR:
74 | msg = 'SYNTAX_ERR';
75 | break;
76 | case FileError.TYPE_MISMATCH_ERR:
77 | msg = 'TYPE_MISMATCH_ERR';
78 | break;
79 | case FileError.PATH_EXISTS_ERR:
80 | msg = 'PATH_EXISTS_ERR';
81 | break;
82 | default:
83 | msg = 'Unknown Error';
84 | break;
85 | };
86 |
87 | console.log('Error: ' + msg);
88 | }
89 |
90 | HTML5FileSystem.prototype.fileWrite = function(name, data, as, callback) {
91 | var that = this;
92 | this.getRoot(function(dir) {
93 | dir.getFile(name, {create: true}, function(entry) {
94 | entry.createWriter(function(fileWriter) {
95 | fileWriter.onwriteend = function(e) {
96 | fileWriter.onwriteend = function(e) {
97 | console.log("Write done");
98 | if (callback)
99 | callback(_entry);
100 | };
101 | fileWriter.onerror = function(e) {
102 | console.log('Write failed: ' + e.toString());
103 | };
104 | if (as.text)
105 | fileWriter.write(new Blob([data], {type: "text/plain"}));
106 | else
107 | fileWriter.write(new Blob([data], {type: "example/binary"}));
108 | };
109 | fileWriter.onerror = function(e) {
110 | console.log('Truncate failed: ' + e.toString());
111 | };
112 | fileWriter.truncate(0);
113 | });
114 | });
115 | });
116 | };
117 |
118 | HTML5FileSystem.prototype.fileRead = function(name, as, callback) {
119 | this.getRoot(function(dir) {
120 | dir.getFile(name, {create: true}, function(entry) {
121 | entry.file(function(file) {
122 | var reader = new FileReader();
123 | reader.onloadend = function() {
124 | if (callback)
125 | callback(this.result);
126 | };
127 | reader.onerror = function(e) {
128 | console.log('Read failed: ' + e.toString());
129 | };
130 |
131 | if (as.text)
132 | reader.readAsText(file);
133 | else
134 | reader.readAsArrayBuffer(file);
135 | });
136 | }, errorHandler);
137 | });
138 | };
139 |
140 | HTML5FileSystem.prototype.getRoot = function(callback) {
141 | this.fs.root.getDirectory(this.rootDirectory, {}, function(entry) {
142 | entry.getMetadata(function(metadata) {
143 | entry.size = metadata.size;
144 | entry.mtime = metadata.modificationTime;
145 | callback(entry);
146 | });
147 | });
148 | };
149 |
150 | HTML5FileSystem.prototype.getEntry = function(parent, name, callback, errcb) {
151 | var _callback = function(entry) {
152 | entry.getMetadata(function(metadata) {
153 | entry.size = metadata.size;
154 | entry.mtime = metadata.modificationTime;
155 | callback(entry);
156 | });
157 | };
158 | parent.getFile(name, {}, _callback, function(e) {
159 | if (e.code == FileError.TYPE_MISMATCH_ERR) {
160 | parent.getDirectory(name, {}, _callback);
161 | } else {
162 | errorHandler(e);
163 | if (errcb)
164 | errcb(e);
165 | }
166 | });
167 | };
168 |
169 | HTML5FileSystem.prototype.getDirectoryEntries = function(dirEntry, callback) {
170 | var toArray = function(list) {
171 | return Array.prototype.slice.call(list || [], 0);
172 | }
173 |
174 | var readDirectoryEntries = function(entry, handler) {
175 | var dirReader = entry.createReader();
176 | var entries = [];
177 |
178 | var readEntries = function() {
179 | dirReader.readEntries (function(results) {
180 | if (results.length === 0) {
181 | handler(entries.sort());
182 | } else {
183 | entries = entries.concat(toArray(results));
184 | readEntries();
185 | }
186 | }, errorHandler);
187 | };
188 |
189 | readEntries();
190 | }
191 |
192 | readDirectoryEntries(dirEntry, function(entries) {
193 | var ret_entries = [];
194 | function getMetadata(entry) {
195 | if (!entry) {
196 | callback(ret_entries);
197 | return;
198 | }
199 | entry.getMetadata(function(metadata) {
200 | entry.size = metadata.size;
201 | entry.mtime = metadata.modificationTime;
202 | ret_entries.push(entry);
203 | if (entries.length)
204 | getMetadata(entries.shift());
205 | else
206 | callback(ret_entries);
207 | });
208 | };
209 | getMetadata(entries.shift());
210 | });
211 | };
212 |
213 | HTML5FileSystem.prototype.create = function(parent, name, is, callback) {
214 | var getEntry = is.file ? parent.getFile : parent.getDirectory;
215 | getEntry.call(parent, name, {create: true}, function(entry) {
216 | entry.getMetadata(function(metadata) {
217 | entry.size = metadata.size;
218 | entry.mtime = metadata.modificationTime;
219 | callback(entry);
220 | });
221 | });
222 | };
223 |
224 | HTML5FileSystem.prototype.truncate = function(entry, callback) {
225 | entry.createWriter(function(fileWriter) {
226 | fileWriter.truncate(0);
227 | callback(entry);
228 | });
229 | };
230 |
231 | HTML5FileSystem.prototype.write = function(entry, buffer, offset, callback) {
232 | entry.createWriter(function(fileWriter) {
233 | fileWriter.onwriteend = function(e) {
234 | callback(entry);
235 | };
236 |
237 | fileWriter.onerror = function(e) {
238 | console.log('Write failed: ' + e.toString());
239 | };
240 |
241 | fileWriter.seek(offset);
242 | var view = new Uint8Array(buffer);
243 | fileWriter.write(new Blob([view]));
244 | });
245 | };
246 |
247 | HTML5FileSystem.prototype.read = function(entry, offset, count, callback) {
248 | entry.file(function(file) {
249 | var fileReader = new FileReader();
250 |
251 | fileReader.onloadend = function(e) {
252 | var ret = [];
253 | var buffer = this.result;
254 |
255 | if (offset > buffer.byteLength) {
256 | callback([]);
257 | return;
258 | }
259 |
260 | var size = buffer.byteLength < count ? buffer.byteLength : count;
261 | if ((size + offset) > buffer.byteLength)
262 | size = buffer.byteLength - offset;
263 | var data = new Uint8Array(buffer, offset, size);
264 | for (var i=0; i < size; i++)
265 | ret.push(data[i]);
266 | callback(ret);
267 | };
268 | fileReader.readAsArrayBuffer(file);
269 | });
270 | };
271 |
272 | HTML5FileSystem.prototype.remove = function(entry, callback) {
273 | entry.remove(function() {
274 | callback();
275 | }, function(e) {
276 | // FIXME: when directory is not empty
277 | errorHandler(e);
278 | callback();
279 | });
280 | };
281 |
282 | HTML5FileSystem.prototype.rename = function(dir, oldname, newname, callback) {
283 | this.getEntry(dir, oldname, function(entry) {
284 | entry.moveTo(dir, newname, function() {
285 | callback();
286 | }, function(e) {
287 | // FIXME
288 | errorHandler(e);
289 | callback();
290 | });
291 | });
292 | };
293 |
--------------------------------------------------------------------------------
/js/number64.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function Number64(high, low) {
8 | this.high = high;
9 | this.low = low;
10 | this.overflow = 0;
11 | this._overflow = 0;
12 | };
13 |
14 | Number64.prototype.mul32 = function(sub, obj) {
15 | var sub_hi = bitops.get_bits(sub, 31, 16);
16 | var sub_lo = bitops.get_bits(sub, 15, 0);
17 | var obj_hi = bitops.get_bits(obj, 31, 16);
18 | var obj_lo = bitops.get_bits(obj, 15, 0);
19 | //display.log("sub_hi=" + sub_hi.toString(16));
20 | //display.log("sub_lo=" + sub_lo.toString(16));
21 | //display.log("obj_hi=" + obj_hi.toString(16));
22 | //display.log("obj_lo=" + obj_lo.toString(16));
23 | var ret = sub_lo * obj_lo + this._overflow;
24 | //display.log("ret=" + ret.toString(16));
25 | var tmp_hi = sub_lo * obj_hi + sub_hi * obj_lo;
26 | //display.log("tmp_hi=" + tmp_hi.toString(16));
27 | ret += bitops.get_bits(tmp_hi, 15, 0) * 0x10000;
28 | //display.log("ret=" + ret.toString(16));
29 | this._overflow = bitops.get_bits64(tmp_hi, 32, 16) + bitops.get_bits64(ret, 51, 32);
30 | //display.log("tmp_hi_hi=" + bitops.get_bits64(tmp_hi, 32, 16).toString(16));
31 | //display.log("ret_overflow=" + bitops.get_bits64(ret, 51, 32).toString(16));
32 | //display.log("overflow=" + this._overflow.toString(16));
33 | ret = bitops.get_bits64(ret, 31, 0);
34 | this._overflow += sub_hi * obj_hi;
35 | return ret;
36 | };
37 |
38 | Number64.prototype.mul = function(obj) {
39 | /* this.high and obj.high should be zero */
40 | /*
41 | var sub_lohi = bitops.get_bits(this.low, 31, 16);
42 | var sub_lolo = bitops.get_bits(this.low, 15, 0);
43 | var obj_lohi = bitops.get_bits(obj.low, 31, 16);
44 | var obj_lolo = bitops.get_bits(obj.low, 15, 0);
45 | var obj_lohi = bitops.get_bits(obj.low, 31, 16);
46 | var obj_lolo = bitops.get_bits(obj.low, 15, 0);
47 | var obj_hihi = bitops.get_bits(obj.high, 31, 16);
48 | var obj_hilo = bitops.get_bits(obj.high, 15, 0);
49 | */
50 | this._overflow = 0;
51 | var ret = this.mul32(this.low, obj.low);
52 | return new Number64(this._overflow, ret);
53 | };
54 |
55 | Number64.prototype.add = function(obj) {
56 | var tmp = this.low + obj.low;
57 | var overflow = bitops.get_bits64(tmp, 51, 32);
58 | var low = bitops.get_bits64(tmp, 31, 0);
59 | tmp = this.high + obj.high + overflow;
60 | overflow = bitops.get_bits64(tmp, 51, 32);
61 | var high = bitops.get_bits64(tmp, 31, 0);
62 | return new Number64(high, low);
63 | };
64 |
65 | Number64.prototype.sub = function(obj) {
66 | if (this.high > obj.high) {
67 | var hi = this.high - obj.high;
68 | var lo = this.low - obj.low;
69 | if (lo < 0) {
70 | hi -= 1;
71 | lo += 0x100000000;
72 | }
73 | return new Number64(hi, lo);
74 | } else if (this.high < obj.high) {
75 | var hi = this.high - obj.high;
76 | var lo = this.low - obj.low;
77 | if (hi < 0)
78 | hi += 0x100000000;
79 | if (lo < 0) {
80 | lo += 0x100000000;
81 | hi -= 1;
82 | }
83 | return new Number64(hi, lo);
84 | } else {
85 | var lo = this.low - obj.low;
86 | return new Number64(0, lo);
87 | }
88 | };
89 |
90 | Number64.prototype.lsl = function(amount) {
91 | this.high = this.low >>> (32 - amount);
92 | this.low = bitops.lsl(bitops.get_bits(this.low, 32 - amount - 1, 0), amount);
93 | return this;
94 | };
95 |
96 | Number64.prototype.sign_extend = function(from, to) {
97 | if (bitops.get_bit(this.low, from - 1)) {
98 | if (to <= 32)
99 | return new Number64(this.high, bitops.sign_extend(this.low, from, to));
100 | var low = (from == 32) ? this.low : bitops.sign_extend(this.low, from, 32);
101 | var high = bitops.sign_extend(1, 1, to - 32);
102 | return new Number64(high, low);
103 | } else {
104 | return new Number64(this.high, this.low);
105 | }
106 | };
107 |
108 | /*
109 | Number64.prototype.asr = function(amount) {
110 | var extended = this.sign_extend(32, 32 + amount);
111 | var result = bitops.get_bits(extended.low, 31, amount);
112 | result = bitops.set_bits(result, 31, 31 - amount - 1, bitops.get_bits(extended.high, amount - 1, 0));
113 | return new Number64(0, result);
114 | };
115 | */
116 |
117 | Number64.prototype.is_zero = function() {
118 | return this.high === 0 && this.low === 0;
119 | };
120 |
121 | function assert_equal(sub, obj, message) {
122 | //console.log(sub.high, sub.low, obj.high, obj.low);
123 | if (!(sub.high == obj.high && sub.low == obj.low)) {
124 | display.log(sub.high.toString(16) + " " + sub.low.toString(16) + " " + obj.high.toString(16) + " " + obj.low.toString(16));
125 | assert(sub.high == obj.high && sub.low == obj.low);
126 | }
127 | }
128 |
129 | function TestNumber64() {
130 | // mul tests
131 | var ret = new Number64(0, 0).mul(new Number64(0, 0));
132 | var obj = new Number64(0, 0);
133 | assert_equal(ret, obj, "0 * 0");
134 | var ret = new Number64(0, 1).mul(new Number64(0, 1));
135 | var obj = new Number64(0, 1);
136 | assert_equal(ret, obj, "1 * 1");
137 | var ret = new Number64(0, 0x80000000).mul(new Number64(0, 2));
138 | var obj = new Number64(1, 0);
139 | assert_equal(ret, obj, "0x80000000 * 2");
140 | var ret = new Number64(0, 0x80000000).mul(new Number64(0, 4));
141 | var obj = new Number64(2, 0);
142 | assert_equal(ret, obj, "0x80000000 * 4");
143 | var ret = new Number64(0, 0x8fffffff).mul(new Number64(0, 0x10));
144 | var obj = new Number64(8, 0xfffffff0);
145 | assert_equal(ret, obj, "0x8fffffff * 0x10");
146 | var ret = new Number64(0, 0x0fffffff).mul(new Number64(0, 0x0fffffff));
147 | var obj = new Number64(0x00ffffff, 0xe0000001);
148 | assert_equal(ret, obj, "0x0fffffff * 0x0fffffff");
149 | var ret = new Number64(0, 0xffffffff).mul(new Number64(0, 0xffffffff));
150 | var obj = new Number64(0xfffffffe, 1);
151 | assert_equal(ret, obj, "0xffffffff * 0xffffffff");
152 | // add tests
153 | var ret = new Number64(0, 0).add(new Number64(0, 0));
154 | var obj = new Number64(0, 0);
155 | assert_equal(ret, obj, "0 + 0");
156 | var ret = new Number64(0, 0).add(new Number64(0, 1));
157 | var obj = new Number64(0, 1);
158 | assert_equal(ret, obj, "0 + 1");
159 | var ret = new Number64(1, 0).add(new Number64(1, 0));
160 | var obj = new Number64(2, 0);
161 | assert_equal(ret, obj, "1:0 + 1:0");
162 | var ret = new Number64(0, 0xffffffff).add(new Number64(0, 1));
163 | var obj = new Number64(1, 0);
164 | assert_equal(ret, obj, "0:0xffffffff + 0:1");
165 | var ret = new Number64(0, 0x1ffffffff).add(new Number64(0, 1));
166 | var obj = new Number64(2, 0);
167 | assert_equal(ret, obj, "0:0x1ffffffff + 0:1");
168 | var ret = new Number64(0, 0xeeeeeeee).add(new Number64(0, 0x11111111));
169 | var obj = new Number64(0, 0xffffffff);
170 | assert_equal(ret, obj, "0:0xeeeeeeee + 0:0x11111111");
171 | var ret = new Number64(0xf, 0xf).add(new Number64(0x1, 0x1));
172 | var obj = new Number64(0x10, 0x10);
173 | assert_equal(ret, obj, "0xf:0xf + 0x1:0x1");
174 | var ret = new Number64(0xf, 0xffffffff).add(new Number64(0x1, 0x1));
175 | var obj = new Number64(0x11, 0);
176 | assert_equal(ret, obj, "0xf:0xfffffffff + 0x1:0x1");
177 | // sub tests
178 | var ret = new Number64(0, 1).sub(new Number64(0, 1));
179 | var obj = new Number64(0, 0);
180 | assert_equal(ret, obj, "1 - 1");
181 | var ret = new Number64(0, 0).sub(new Number64(0, 1));
182 | var obj = new Number64(0, -1);
183 | assert_equal(ret, obj, "0 - 1");
184 | var ret = new Number64(1, 0).sub(new Number64(0, 1));
185 | var obj = new Number64(0, 0xffffffff);
186 | assert_equal(ret, obj, "1:0 - 0:1");
187 | var ret = new Number64(1, 0xf).sub(new Number64(0, 1));
188 | var obj = new Number64(1, 0xe);
189 | assert_equal(ret, obj, "1:0xf - 0:1");
190 | var ret = new Number64(1, 0xf).sub(new Number64(0, 0xf0000000));
191 | var obj = new Number64(0, 0x1000000f);
192 | assert_equal(ret, obj, "1:0xf - 0:0xf0000000");
193 | var ret = new Number64(0, 0).sub(new Number64(0xf, 0));
194 | var obj = new Number64(0x100000000-0xf, 0);
195 | assert_equal(ret, obj, "0:0 - 0xf:0");
196 | var ret = new Number64(0xe, 0).sub(new Number64(0xf, 0xf0000000));
197 | var obj = new Number64(0xfffffffe, 0x10000000);
198 | assert_equal(ret, obj, "0xe:0x11111111 - 0xf:0");
199 | // lsl tests
200 | var ret = new Number64(0, 1).lsl(1);
201 | var obj = new Number64(0, 2);
202 | assert_equal(ret, obj, "1 << 1");
203 | var ret = new Number64(0, 0x80000000).lsl(1);
204 | var obj = new Number64(1, 0);
205 | assert_equal(ret, obj, "0x80000000 << 1");
206 | var ret = new Number64(0, 0x80000000).lsl(16);
207 | var obj = new Number64(0x8000, 0);
208 | assert_equal(ret, obj, "0x80000000 << 16");
209 | var ret = new Number64(0, 0x80000000).lsl(31);
210 | var obj = new Number64(0x40000000, 0);
211 | assert_equal(ret, obj, "0x80000000 << 31");
212 | // sign_extend tests
213 | var ret = new Number64(0, 0x10000000).sign_extend(31, 32);
214 | var obj = new Number64(0, 0x10000000);
215 | assert_equal(ret, obj, "0x10000000, 31, 32");
216 | var ret = new Number64(0, 0x10000000).sign_extend(29, 32);
217 | var obj = new Number64(0, 0xf0000000);
218 | assert_equal(ret, obj, "0x10000000, 29, 32");
219 | var ret = new Number64(0, 0x10000000).sign_extend(29, 36);
220 | var obj = new Number64(0xf, 0xf0000000);
221 | assert_equal(ret, obj, "0x10000000, 29, 36");
222 | var ret = new Number64(0, 0x80000000).sign_extend(32, 64);
223 | var obj = new Number64(0xffffffff, 0x80000000);
224 | assert_equal(ret, obj, "0x80000000, 32, 64");
225 | /*
226 | // asr tests
227 | var ret = new Number64(0, 0x80000000).asr(15);
228 | var obj = new Number64(0, 0xffff0000);
229 | assert_equal(ret, obj, "0x80000000 >> 15");
230 | */
231 |
232 | display.log("All Number64 tests passed successfully");
233 | };
234 |
235 |
--------------------------------------------------------------------------------
/js/armv7-mmu.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | /*
8 | * ARMv7 MMU (VMPA)
9 | */
10 | function ARMv7_MMU(cpu, memctlr) {
11 | this.cpu = cpu;
12 |
13 | this.enabled = false;
14 | this.baseaddr0 = 0;
15 | this.baseaddr1 = 0;
16 | this.memctlr = memctlr;
17 | this.asid = 0;
18 | this.width = 0;
19 | this.mask = (1 << (31 - this.width - 20 + 1)) - 1;
20 | this.cp15 = null;
21 | this.check_unaligned = false;
22 | }
23 |
24 | ARMv7_MMU.prototype.trans_to_phyaddr = function(vaddr, is_write) {
25 | if (this.enabled) {
26 | return this.walk_table(vaddr, is_write);
27 | } else {
28 | return vaddr;
29 | }
30 | };
31 |
32 | /*
33 | * Page Table Walk
34 | */
35 | ARMv7_MMU.prototype.ld_word = function(addr) {
36 | return this.memctlr.ld_word(addr);
37 | };
38 |
39 | ARMv7_MMU.prototype.get_1st_ptaddr = function(vaddr) {
40 | var index = (vaddr >>> 20) & this.mask;
41 | var ptaddr;
42 | if (this.width) {
43 | var is_zero = bitops.get_bits(vaddr, 31, 32 - this.width) === 0;
44 | if (is_zero)
45 | ptaddr = bitops.set_bits(this.baseaddr0, 13 - this.width, 2, index);
46 | else
47 | ptaddr = bitops.set_bits(this.baseaddr1, 13, 2, index);
48 | return bitops.clear_bits(ptaddr, 1, 0);
49 | } else {
50 | return this.baseaddr0 + (index << 2);
51 | }
52 | };
53 |
54 | ARMv7_MMU.prototype.get_2nd_ptaddr = function(vaddr, table) {
55 | var index = (vaddr >>> 12) & 0xff;
56 | var tmp = table & 0xfffffc00;
57 | if (tmp < 0)
58 | tmp += 0x100000000;
59 | return tmp + (index << 2);
60 | };
61 |
62 | ARMv7_MMU.prototype.check_permission = function(vaddr, ap2, ap10, is_write, is_section) {
63 | if (ap2) {
64 | switch (ap10) {
65 | case 0:
66 | throw "Reserved";
67 | break;
68 | case 1:
69 | if (is_write || !this.cpu.is_priviledged())
70 | throw "Permission Fault: ap2 == 1, ap10 == 1";
71 | break;
72 | case 2:
73 | // Deprecated
74 | if (is_write)
75 | throw "Permission Fault: ap2 == 1, ap10 == 2";
76 | break;
77 | case 3:
78 | if (is_write) {
79 | if (is_section)
80 | this.cp15.set_memory_abort(vaddr, this.cp15.PERMISSION_FAULT_SECTION, is_write);
81 | else
82 | this.cp15.set_memory_abort(vaddr, this.cp15.PERMISSION_FAULT_PAGE, is_write);
83 | throw "PF";
84 | }
85 | break;
86 | default:
87 | throw "Unknown ap10";
88 | break;
89 | }
90 | } else {
91 | switch (ap10) {
92 | case 0:
93 | if (is_section)
94 | this.cp15.set_memory_abort(vaddr, this.cp15.PERMISSION_FAULT_SECTION, is_write);
95 | else
96 | this.cp15.set_memory_abort(vaddr, this.cp15.PERMISSION_FAULT_PAGE, is_write);
97 | break;
98 | case 1:
99 | if (!this.cpu.is_priviledged())
100 | throw "Permission Fault: ap2 == 0, ap10 == 1";
101 | break;
102 | case 2:
103 | if (is_write && !this.cpu.is_priviledged())
104 | throw "Permission Fault: ap2 == 0, ap10 == 2";
105 | break;
106 | case 3:
107 | // Full access
108 | break;
109 | default:
110 | throw "Unknown ap10";
111 | break;
112 | }
113 | }
114 | };
115 |
116 | ARMv7_MMU.prototype.check_permission_table1 = function(vaddr, table, is_write) {
117 | var ap2 = (table >>> 15) & 1;
118 | var ap10 = (table >>> 10) & 3;
119 | this.check_permission(vaddr, ap2, ap10, is_write, true);
120 | };
121 |
122 | ARMv7_MMU.prototype.check_permission_table2 = function(vaddr, table, is_write) {
123 | var ap2 = (table >>> 9) & 1;
124 | var ap10 = (table >>> 4) & 3;
125 | this.check_permission(vaddr, ap2, ap10, is_write, false);
126 | };
127 |
128 | ARMv7_MMU.prototype.need_perm_check = function(table, is_supersection) {
129 | var domain;
130 | if (is_supersection)
131 | domain = this.cp15.domains[0];
132 | else
133 | domain = this.cp15.domains[(table >>> 5) & 0xf];
134 | switch (domain) {
135 | case 0:
136 | throw "Domain Fault";
137 | break;
138 | case 1:
139 | return true;
140 | break;
141 | case 2:
142 | throw "Domain Reserved";
143 | break;
144 | case 3:
145 | return false;
146 | break;
147 | default:
148 | throw "Unknown Domain";
149 | break;
150 | }
151 | throw "Unknown Domain";
152 | };
153 |
154 | ARMv7_MMU.prototype.walk_table = function(vaddr, is_write) {
155 | var paddr;
156 |
157 | var ptaddr1 = this.get_1st_ptaddr(vaddr);
158 | /*
159 | * First-level descriptors
160 | */
161 | var table1 = this.ld_word(ptaddr1);
162 |
163 | var format = table1 & 3;
164 | switch (format) {
165 | case 0:
166 | //throw "Translation fault (1st 0): " + vaddr.toString(16);
167 | this.cp15.set_memory_abort(vaddr, this.cp15.TRANS_FAULT_SECTION);
168 | throw "PF";
169 | break;
170 | case 1:
171 | // Small Pages or Large Pages. See the below.
172 | break;
173 | case 2:
174 | var is_supersection = (table1 >>> 18) & 1;
175 | if (is_supersection) {
176 | // Supersection
177 | if (this.need_perm_check(table1, true))
178 | this.check_permission(vaddr, table1, is_write);
179 | throw "Supersection";
180 | } else {
181 | // Section
182 | if (this.need_perm_check(table1))
183 | this.check_permission_table1(vaddr, table1, is_write);
184 | var tmp = table1 & 0xfff00000;
185 | if (tmp < 0)
186 | tmp += 0x100000000;
187 | paddr = tmp + (vaddr & 0x000fffff);
188 | }
189 | return paddr;
190 | case 3:
191 | throw "Translation fault (1st 3): " + vaddr.toString(16);
192 | break;
193 | default:
194 | throw "Unknown format: " + format.toString();
195 | break;
196 | }
197 | /*
198 | * Second-level descriptors
199 | */
200 | var ptaddr2 = this.get_2nd_ptaddr(vaddr, table1);
201 | var table2 = this.ld_word(ptaddr2);
202 |
203 | if (this.need_perm_check(table1)) // table1 is correct
204 | this.check_permission_table2(vaddr, table2, is_write);
205 | var format2 = table2 & 3;
206 | switch (format2) {
207 | case 0:
208 | this.cp15.set_memory_abort(vaddr, this.cp15.TRANS_FAULT_PAGE);
209 | throw "PF";
210 | break;
211 | case 1:
212 | throw "Large page: " + vaddr.toString(16);
213 | break;
214 | case 2:
215 | case 3:
216 | // See the below;
217 | break;
218 | default:
219 | throw "Unknown format: " + format2.toString();
220 | break;
221 | }
222 | var tmp2 = table2 & 0xfffff000;
223 | if (tmp2 < 0)
224 | tmp2 += 0x100000000;
225 | paddr = tmp2 + (vaddr & 0x00000fff);
226 | return paddr;
227 | };
228 |
229 | ARMv7_MMU.prototype.dump_table = function(table, ptaddr) {
230 | display.log(ptaddr.toString(16) + " PT=" + toStringHex32(table) + "(" + toStringBinInst(table) + ")");
231 | };
232 |
233 | function toStringPageTable(table, addr) {
234 | if (table)
235 | return toStringHex32(table) + "@" + toStringHex32(addr);
236 | else
237 | return "null@" + toStringHex32(addr);
238 | }
239 |
240 | ARMv7_MMU.prototype.show_table = function(vaddr) {
241 | var paddr;
242 | var str = "";
243 | str += vaddr.toString(16);
244 | var ptaddr = this.get_1st_ptaddr(vaddr);
245 | /*
246 | * First-level descriptor
247 | */
248 | var table = this.ld_word(ptaddr);
249 | str += " => " + toStringPageTable(table, ptaddr);
250 |
251 | var format = bitops.get_bits(table, 1, 0);
252 | switch (format) {
253 | case 0:
254 | str += "(Invalid)";
255 | return str;
256 | case 1:
257 | // See the below;
258 | break;
259 | case 2:
260 | is_supersection = bitops.get_bit(table, 18);
261 | if (is_supersection) {
262 | str += "(Supersection)";
263 | return str;
264 | } else {
265 | str += "(Section)";
266 | paddr = bitops.copy_bits(table, 19, 0, vaddr);
267 | }
268 | str += " => " + paddr.toString(16);
269 | return str;
270 | case 3:
271 | str += "(Reserved)";
272 | return str;
273 | default:
274 | return null;
275 | }
276 | /*
277 | * Second-level descriptor
278 | */
279 | ptaddr = this.get_2nd_ptaddr(vaddr, table);
280 | table = this.ld_word(ptaddr);
281 | str += " => " + toStringPageTable(table, ptaddr);
282 |
283 | if (!table)
284 | return str;
285 |
286 | var format2 = bitops.get_bits(table, 1, 0);
287 | switch (format2) {
288 | case 0:
289 | str += "(Invalid)";
290 | return str;
291 | case 1:
292 | str += "(LargePage)";
293 | return str;
294 | case 2:
295 | case 3:
296 | // See the below;
297 | break;
298 | default:
299 | return null;
300 | }
301 | paddr = bitops.copy_bits(table, 11, 0, vaddr);
302 | str += " => " + paddr.toString(16);
303 | return str;
304 | };
305 |
306 | ARMv7_MMU.prototype.show_current_tables = function() {
307 | var size;
308 | switch (this.width) {
309 | case 0:
310 | size = 16*1024;
311 | break;
312 | case 1:
313 | size = 8*1024;
314 | break;
315 | case 2:
316 | size = 4*1024;
317 | break;
318 | case 3:
319 | size = 2*1024;
320 | break;
321 | case 4:
322 | size = 1024;
323 | break;
324 | case 5:
325 | size = 512;
326 | break;
327 | case 6:
328 | size = 256;
329 | break;
330 | case 7:
331 | size = 128;
332 | break;
333 | default:
334 | throw "Uknown width: " + this.width.toString();
335 | break;
336 | }
337 | var str = "";
338 | var addr;
339 | for (addr=0xc0000000; addr < 0xc1000000; addr += 0x10000)
340 | str += this.show_table(addr) + "\n";
341 | for (addr=0xf8000000; addr < 0xf8100000; addr += 0x10000)
342 | str += this.show_table(addr) + "\n";
343 | for (addr=0xf8e00000; addr < 0xf8f00000; addr += 0x10000)
344 | str += this.show_table(addr) + "\n";
345 | display.log(str);
346 | };
347 |
348 | ARMv7_MMU.prototype.save = function() {
349 | var params = Object();
350 | params.baseaddr0 = this.baseaddr0;
351 | params.baseaddr1 = this.baseaddr1;
352 | params.width = this.width;
353 | return params;
354 | };
355 |
356 | ARMv7_MMU.prototype.restore = function(params) {
357 | this.baseaddr0 = params.baseaddr0;
358 | this.baseaddr1 = params.baseaddr1;
359 | this.width = params.width;
360 | this.mask = (1 << (31 - this.width - 20 + 1)) - 1;
361 | };
362 |
363 | ARMv7_MMU.prototype.dump = function() {
364 | var msg = "";
365 | msg += "baseaddr0: " + toStringHex32(this.baseaddr0) + "\n";
366 | msg += "baseaddr1: " + toStringHex32(this.baseaddr1) + "\n";
367 | msg += "width: " + this.width + "\n";
368 | display.log(msg);
369 | };
370 |
371 | ARMv7_MMU.prototype.dump_phymem = function(addr) {
372 | for (var i=0; i < 100; i++) {
373 | var cur = addr + i*4;
374 | var val = this.ld_word(cur);
375 | if (val !== undefined && val !== null)
376 | display.log(toStringHex32(cur) + ": " + toStringHex32(val) + "\t" + toStringAscii(val));
377 | else
378 | display.log(toStringHex32(cur) + ": (null)");
379 | }
380 | };
381 |
382 | ARMv7_MMU.prototype.dump_virmem = function(addr) {
383 | for (var i=0; i < 100; i++) {
384 | var cur = addr + i*4;
385 | var phyaddr = this.trans_to_phyaddr(cur);
386 | var val = this.ld_word(phyaddr);
387 | if (val !== undefined && val !== null)
388 | display.log(toStringHex32(phyaddr) + ": " + toStringHex32(val) + "\t" + toStringAscii(val));
389 | else
390 | display.log(toStringHex32(phyaddr) + ": (null)");
391 | }
392 | };
393 |
--------------------------------------------------------------------------------
/js/virtio.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 |
8 | function VirtioMMIO(baseaddr, irq, gic) {
9 | this.baseaddr = baseaddr;
10 | this.irq = irq;
11 | this.gic = gic;
12 |
13 | this.read = new Array();
14 | this.write = new Array();
15 | this.data = new Array();
16 |
17 | this.MagicValue = this.baseaddr + 0x000;
18 | this.Version = this.baseaddr + 0x004;
19 | this.DeviceID = this.baseaddr + 0x008;
20 | this.VendorID = this.baseaddr + 0x00c;
21 | this.HostFeatures = this.baseaddr + 0x010;
22 | this.HostFeaturesSel = this.baseaddr + 0x014;
23 | this.GuestFeatures = this.baseaddr + 0x020;
24 | this.GuestFeaturesSel = this.baseaddr + 0x024;
25 | this.GuestPageSize = this.baseaddr + 0x028;
26 | this.QueueSel = this.baseaddr + 0x030;
27 | this.QueueNumMax = this.baseaddr + 0x034;
28 | this.QueueNum = this.baseaddr + 0x038;
29 | this.QueueAlign = this.baseaddr + 0x03c;
30 | this.QueuePFN = this.baseaddr + 0x040;
31 | this.QueueNotify = this.baseaddr + 0x050;
32 | this.InterruptStatus = this.baseaddr + 0x060;
33 | this.InterruptACK = this.baseaddr + 0x064;
34 | this.Status = this.baseaddr + 0x070;
35 | this.ConfigSpace = this.baseaddr + 0x100;
36 |
37 | this.read[this.MagicValue] = stringToLong("virt");
38 | this.read[this.Version] = 1;
39 | this.read[this.DeviceID] = 0x9; // 9P
40 | this.read[this.VendorID] = 0xffffffff; // ANY
41 |
42 | virtio = this;
43 |
44 | this.data[this.Status] = 0;
45 | this.read[this.Status] = function() {
46 | display.log("[r]Status: " + virtio.data[virtio.Status].toString(2));
47 | return virtio.data[virtio.Status];
48 | };
49 | this.write[this.Status] = function(status) {
50 | //throw "Status";
51 | display.log("[w]Status: " + status.toString(2));
52 | virtio.data[virtio.Status] = status;
53 | };
54 |
55 | this.data[this.HostFeatures] = 1; // == 9P_MOUNT_TAG (See include/linux/virtio_9p.h)
56 | this.read[this.HostFeatures] = function() {
57 | display.log("[r]HostFeatures: " + virtio.data[virtio.HostFeatures].toString(2));
58 | return virtio.data[virtio.HostFeatures];
59 | };
60 | this.write[this.HostFeaturesSel] = function(features) {
61 | display.log("[w]HostFeaturesSel: " + features.toString(2));
62 | // Do nothing
63 | };
64 |
65 | this.data[this.GuestFeatures] = 0;
66 | this.write[this.GuestFeatures] = function(features) {
67 | display.log("[w]GuestFeatures: " + features.toString(2));
68 | virtio.data[virtio.GuestFeatures] = features;
69 | };
70 | this.write[this.GuestFeaturesSel] = function(features) {
71 | display.log("[w]GuestFeaturesSel: " + features.toString(2));
72 | virtio.data[virtio.GuestFeaturesSel] = features;
73 | };
74 |
75 | this.data[this.GuestPageSize] = 0;
76 | this.write[this.GuestPageSize] = function(size) {
77 | display.log("[w]GuestPageSize: " + size);
78 | virtio.data[virtio.GuestPageSize] = size;
79 | };
80 |
81 | this.data[this.QueueSel] = 0;
82 | this.write[this.QueueSel] = function(sel) {
83 | display.log("[w]QueueSel: " + sel.toString(16));
84 | virtio.data[virtio.QueueSel] = sel;
85 | };
86 |
87 | //this.data[this.QueueNumMax] = 1024; // Same as qemu
88 | this.data[this.QueueNumMax] = 256; // Minimum
89 | this.data[this.QueueNum] = 0;
90 | this.read[this.QueueNumMax] = function() {
91 | display.log("[r]QueueNumMax: " + virtio.data[virtio.QueueNumMax]);
92 | return virtio.data[virtio.QueueNumMax];
93 | };
94 | this.write[this.QueueNum] = function(num) {
95 | display.log("[w]QueueNum: " + num);
96 | virtio.data[virtio.QueueNum] = num;
97 | };
98 | this.data[this.QueueAlign] = 0;
99 | this.write[this.QueueAlign] = function(align) {
100 | display.log("[w]QueueAlign: " + align.toString(16));
101 | virtio.data[virtio.QueueAlign] = align;
102 | };
103 |
104 | this.data[this.QueuePFN] = 0;
105 | this.write[this.QueuePFN] = function(pfn) {
106 | display.log("[w]QueuePFN: " + pfn.toString(16));
107 | virtio.data[virtio.QueuePFN] = pfn;
108 | };
109 | this.read[this.QueuePFN] = function() {
110 | display.log("[r]QueuePFN: " + virtio.data[virtio.QueuePFN].toString(16));
111 | return virtio.data[virtio.QueuePFN];
112 | };
113 |
114 | this.data[this.QueueNotify] = 0;
115 | this.write[this.QueueNotify] = function(index) {
116 | display.log("[w]QueueNotify: " + index);
117 | virtio.data[virtio.QueueNotify] = index;
118 | var ready = virtio._notify_callback(index);
119 | if (ready) {
120 | virtio.data[virtio.InterruptStatus] = 1 << 0;
121 | gic.send_interrupt(virtio.irq);
122 | }
123 | };
124 | this.data[this.InterruptStatus] = 1 << 0; // VRING
125 | this.read[this.InterruptStatus] = function() {
126 | display.log("[r]InterruptStatus: " + virtio.data[virtio.InterruptStatus].toString(2));
127 | return virtio.data[virtio.InterruptStatus];
128 | };
129 | this.write[this.InterruptACK] = function(ack) {
130 | display.log("[w]InterruptACK: " + ack.toString(2));
131 | if (ack != virtio.data[virtio.InterruptStatus])
132 | throw "InterruptACK";
133 | };
134 | }
135 |
136 | VirtioMMIO.prototype.register_tagname = function(name) {
137 | this.read[this.ConfigSpace + 0] = name.length & 0xff;
138 | this.read[this.ConfigSpace + 1] = name.length >> 8;
139 |
140 | for (var i=0; i < name.length; i++)
141 | this.read[this.ConfigSpace + 2 + i] = name.charCodeAt(i);
142 | };
143 |
144 | VirtioMMIO.prototype.set_notify_callback = function(cb) {
145 | this._notify_callback = cb;
146 | };
147 |
148 | VirtioMMIO.prototype.get_queue_addr = function() {
149 | return this.data[this.QueuePFN] * this.data[this.GuestPageSize];
150 | };
151 |
152 | VirtioMMIO.prototype.get_queue_num = function() {
153 | return this.data[this.QueueNum];
154 | };
155 |
156 | VirtioMMIO.prototype.get_queue_align = function() {
157 | return this.data[this.QueueAlign];
158 | };
159 |
160 | VirtioMMIO.prototype.send_interrupt = function() {
161 | this.data[this.InterruptStatus] = 1 << 0;
162 | this.gic.send_interrupt(this.irq);
163 | };
164 |
165 | VirtioMMIO.prototype.save = function() {
166 | var params = new Object();
167 | for (var i in this.data) {
168 | params[i] = this.data[i];
169 | }
170 | return params;
171 | };
172 |
173 | VirtioMMIO.prototype.restore = function(params) {
174 | for (var i in this.data) {
175 | this.data[i] = params[i];
176 | }
177 | };
178 |
179 | /*
180 | * Virtio Vring
181 | */
182 | function VirtioVring(memctlr, mmio) {
183 | this.memctlr = memctlr;
184 | this.mmio = mmio;
185 |
186 | this.mmio.set_notify_callback(this.notify_callback.bind(this));
187 | }
188 |
189 | VirtioVring.prototype.get_desc = function(index) {
190 | var addr = this.get_desc_addr() + index * 16;
191 | var memctlr = this.memctlr;
192 | return {
193 | addr: memctlr.ld_word_fast(addr),
194 | len: memctlr.ld_word_fast(addr + 8),
195 | next: memctlr.ld_halfword_fast(addr + 12),
196 | flags: memctlr.ld_halfword_fast(addr + 14),
197 | };
198 | };
199 |
200 | VirtioVring.prototype.fill_desc = function(index, descaddr, len, next, flags) {
201 | var addr = this.get_desc_addr() + index * 16;
202 | var memctlr = this.memctlr;
203 | memctlr.st_word_fast(addr, descaddr);
204 | memctlr.st_word_fast(addr + 8, len);
205 | memctlr.st_halfword_fast(addr + 12, next);
206 | memctlr.st_halfword_fast(addr + 14, flags);
207 | };
208 |
209 | VirtioVring.prototype.consume_desc = function(desc_idx, desc_len) {
210 | var idx_addr = this.get_used_addr() + 2;
211 | var idx = this.memctlr.ld_halfword_fast(idx_addr);
212 | var used_addr = idx_addr + 2 + idx * 8;
213 | this.memctlr.st_word_fast(used_addr, desc_idx);
214 | this.memctlr.st_word_fast(used_addr + 4, desc_len);
215 | this.memctlr.st_halfword_fast(idx_addr, idx + 1);
216 | //this.dump_ring();
217 | };
218 |
219 | VirtioVring.prototype.notify_callback = function(index) {
220 | //this.dump_ring();
221 | return this._notify_callback(this.get_desc(index));
222 | };
223 |
224 | VirtioVring.prototype.set_notify_callback = function(cb) {
225 | this._notify_callback = cb;
226 | };
227 |
228 | VirtioVring.prototype.get_desc_addr = function() {
229 | return this.mmio.get_queue_addr();
230 | };
231 |
232 | VirtioVring.prototype.get_avail_addr = function() {
233 | return this.mmio.get_queue_addr() + this.mmio.get_queue_num() * 16;
234 | };
235 |
236 | VirtioVring.prototype.get_used_addr = function() {
237 | var num = this.mmio.get_queue_num();
238 | var addr = this.get_avail_addr() + 2 + 2 + 2 * num + 2;
239 | var align = this.mmio.get_queue_align();
240 |
241 | //display.log(addr.toString(16));
242 | // Skip padding
243 | if (addr & (align - 1)) {
244 | var mask = ~(align - 1);
245 | if (mask < 0)
246 | mask += 0x100000000;
247 | addr = (addr & mask) + align;
248 | }
249 | //display.log(addr.toString(16));
250 | return addr;
251 | };
252 |
253 | VirtioVring.prototype.kick = function() {
254 | this.mmio.send_interrupt();
255 | };
256 |
257 | VirtioVring.prototype.dump_ring = function() {
258 | var addr = this.mmio.get_queue_addr();
259 | var num = this.mmio.get_queue_num();
260 | var align = this.mmio.get_queue_align();
261 | var memctlr = this.memctlr;
262 | var i;
263 | var cur;
264 | var idx;
265 |
266 | cur = this.get_avail_addr();
267 | display.log("avail_flags: " + memctlr.ld_halfword_fast(cur).toString(2));
268 | cur += 2;
269 | var idx = memctlr.ld_halfword_fast(cur);
270 | display.log("avail_idx: " + idx);
271 | cur += 2;
272 | var items = [];
273 | for (i=0; i < idx; i++)
274 | items.push(memctlr.ld_halfword_fast(cur + (i * 2)).toString());
275 | display.log("available: " + items.join(" "));
276 | //display.log("available: " + memctlr.ld_halfword_fast(cur + idx * 2));
277 | cur += 2 * num;
278 | display.log("used_event_idx: " + memctlr.ld_halfword_fast(cur));
279 |
280 | cur = this.get_used_addr();
281 | display.log("used_flags: " + memctlr.ld_halfword_fast(cur).toString(2));
282 | cur += 2;
283 | idx = memctlr.ld_halfword_fast(cur);
284 | display.log("used_idx: " + idx);
285 | cur += 2;
286 | var items = [];
287 | for (i=0; i < idx; i++) {
288 | var id = memctlr.ld_word_fast(cur + (i * 8));
289 | var len = memctlr.ld_word_fast(cur + (i * 8 + 4));
290 | items.push("(" + id + "," + len + ")");
291 | }
292 | display.log("used_elem: " + items.join(" "));
293 | /*
294 | var id = memctlr.ld_word_fast(cur + (idx * 8));
295 | var len = memctlr.ld_word_fast(cur + (idx * 8 + 4));
296 | display.log("used: (" + id + "," + len + ")");
297 | */
298 | cur += 2 * num;
299 | display.log("avail_event_idx: " + memctlr.ld_halfword_fast(cur));
300 | };
301 |
302 |
303 | /*
304 | * Virtio 9P
305 | */
306 | function Virtio9P(memctlr, vring) {
307 | this.memctlr = memctlr;
308 | this.vring = vring;
309 | this.net9p = new Net9p(this);
310 |
311 | this.vring.set_notify_callback(this.receive_request.bind(this));
312 | }
313 |
314 | Virtio9P.prototype.receive_request = function(desc) {
315 | var memctlr = this.memctlr;
316 | var addr = desc.addr;
317 |
318 | var bytes = [];
319 | var len = this.net9p.get_header_size();
320 | for (var i=0; i < len; i++) {
321 | bytes.push(memctlr.ld_byte_fast(addr + i));
322 | }
323 | var header = this.net9p.unmarshal_header(bytes);
324 | //display.log("size=" + header.size + ", id=" + header.id + ", tag=" + header.tag.toString(16));
325 |
326 | addr += len;
327 | var remained = desc.len - len;
328 | var next_data = function() {
329 | if (remained-- > 0)
330 | return memctlr.ld_byte_fast(addr++);
331 | else
332 | return null;
333 | };
334 |
335 | var reply = this.net9p.proto[header.id](header.id, header.tag, next_data);
336 | if (reply) {
337 | desc = this.vring.get_desc(1);
338 | if (reply.length > desc.len)
339 | abort("reply too long: " + reply.length + " > " + desc.len);
340 | addr = desc.addr;
341 | for (var i=0; i < reply.length; i++)
342 | memctlr.st_byte_fast(addr + i, reply[i]);
343 | this.vring.consume_desc(0, reply.length);
344 |
345 | // Reply data is ready. Issue interrupt
346 | return true;
347 | } else {
348 | return false;
349 | }
350 | };
351 |
352 | Virtio9P.prototype.send_reply = function(reply) {
353 | var memctlr = this.memctlr;
354 | var idx = 1;
355 | var desc = this.vring.get_desc(idx);
356 | var addr = desc.addr;
357 | var rest = desc.len;
358 | offset = 0;
359 | for (var i=0; i < reply.length; i++, offset++, rest--) {
360 | if (rest <= 0) {
361 | idx += 1;
362 | desc = this.vring.get_desc(idx);
363 | addr = desc.addr;
364 | rest = desc.len;
365 | offset = 0;
366 | }
367 | this.memctlr.st_byte_fast(addr + offset, reply[i]);
368 | }
369 | this.vring.consume_desc(0, reply.length);
370 | this.vring.kick();
371 | };
372 |
373 |
--------------------------------------------------------------------------------
/arm-js.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
60 |
61 |
72 |
73 |
74 |
75 |
278 |
283 |
290 | 0.0 KIPS / 0 instructions executed / 0 sec elapsed
291 |
292 |
298 |
301 |
302 |
308 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
)
342 |
343 |
344 |
397 |
398 |
399 |
400 |
--------------------------------------------------------------------------------
/js/bitops.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | function assert(cond, val) {
8 | if (!cond) {
9 | if (typeof val == "string")
10 | throw "Assertion failed: " + val;
11 | if (val)
12 | throw "Assertion failed: " + val.toString(16) + "(" + val.toString(2) + ")";
13 | else
14 | throw "Assertion failed."
15 | }
16 | }
17 |
18 | function assert2(x, y, str) {
19 | if (x != y) {
20 | var msg = "";
21 | if (str == undefined)
22 | throw "Assertion failed: " + toStringNum(x) + " != " + toStringNum(y);
23 | else
24 | throw "Assertion failed(" + str + "): " + toStringNum(x) + " != " + toStringNum(y);
25 | }
26 | }
27 |
28 | function BitOps() {
29 | }
30 |
31 | BitOps.prototype.xor = function(x, y) {
32 | var ret = x ^ y;
33 | if (ret >= 0)
34 | return ret;
35 | else
36 | return ret + 0x100000000;
37 | };
38 |
39 | BitOps.prototype.xor64 = function(x, y) {
40 | var xh = Math.floor(x / 0x100000000);
41 | var yh = Math.floor(y / 0x100000000);
42 | var xl = x % 0x100000000;
43 | var yl = y % 0x100000000;
44 | return this.xor(xh, yh) * 0x100000000 + this.xor(xl, yl);
45 | };
46 |
47 | BitOps.prototype.and = function(x, y) {
48 | var ret = x & y;
49 | if (ret >= 0)
50 | return ret;
51 | else
52 | return ret + 0x100000000;
53 | };
54 |
55 | BitOps.prototype.and64 = function(x, y) {
56 | var xh = Math.floor(x / 0x100000000);
57 | var yh = Math.floor(y / 0x100000000);
58 | var xl = x % 0x100000000;
59 | var yl = y % 0x100000000;
60 | return this.and(xh, yh) * 0x100000000 + this.and(xl, yl);
61 | };
62 |
63 | BitOps.prototype.or = function(x, y) {
64 | var ret = x | y;
65 | if (ret >= 0)
66 | return ret;
67 | else
68 | return ret + 0x100000000;
69 | };
70 |
71 | BitOps.prototype.or64 = function(x, y) {
72 | var xh = Math.floor(x / 0x100000000);
73 | var yh = Math.floor(y / 0x100000000);
74 | var xl = x % 0x100000000;
75 | var yl = y % 0x100000000;
76 | return this.or(xh, yh) * 0x100000000 + this.or(xl, yl);
77 | };
78 |
79 | BitOps.prototype.not = function(x) {
80 | var ret = ~x;
81 | if (ret >= 0)
82 | return ret;
83 | else
84 | return ret + 0x100000000;
85 | };
86 |
87 | BitOps.prototype.lowest_set_bit = function(val, len) {
88 | var pos = 0;
89 | for (var i=0; i < len; i++) {
90 | if (val & 1 << i)
91 | return i;
92 | }
93 | return len;
94 | };
95 |
96 | BitOps.prototype.bit_count = function(val, len) {
97 | var count = 0;
98 | for (var i=0; i < len; i++) {
99 | if (val & 1 << i)
100 | count++;
101 | }
102 | return count;
103 | };
104 |
105 | BitOps.prototype.clear_bit = function(uint, pos) {
106 | if (uint < 0x80000000 && pos < 31)
107 | return uint & ~(1 << pos);
108 | if (pos < 31) {
109 | var ret = uint & ~(1 << pos);
110 | if (ret < 0)
111 | ret += 0x100000000;
112 | return ret;
113 | } else {
114 | if (uint >= 0x80000000)
115 | return uint - 0x80000000;
116 | else
117 | return uint;
118 | }
119 | /*
120 | var uints = toStringBin32(uint);
121 | var ret = "";
122 | for (var i=0; i < 32; i++) {
123 | if ((32-i-1) == pos)
124 | ret += "0";
125 | else
126 | ret += uints[i];
127 | }
128 | return parseInt(ret, 2);
129 | */
130 | };
131 |
132 | BitOps.prototype.clear_bits = function(uint, start, end) {
133 | if (uint < 0x80000000 && start < 31)
134 | return uint & ~(((1 << (start+1)) - 1) & ~((1 << end) - 1));
135 | if (start < 31) {
136 | var ret = uint & ~(((1 << (start+1)) - 1) & ~((1 << end) - 1));
137 | if (ret < 0)
138 | ret += 0x100000000;
139 | return ret;
140 | }
141 | var uints = toStringBin32(uint);
142 | var ret = "";
143 | for (var i=0; i < 32; i++) {
144 | if ((32-i-1) <= start && (32-i-1) >= end)
145 | ret += "0";
146 | else
147 | ret += uints[i];
148 | }
149 | return parseInt(ret, 2);
150 | };
151 |
152 | BitOps.prototype.set_bits = function(uint, start, end, val) {
153 | return this.or(this.clear_bits(uint, start, end), this.lsl(val, end));
154 | };
155 |
156 | BitOps.prototype.set_bit = function(uint, pos, val) {
157 | if (val)
158 | if (pos == 31)
159 | return this.or(uint, 0x80000000);
160 | else
161 | return this.or(uint, val << pos);
162 | else
163 | if (pos == 31)
164 | return this.clear_bit(uint, 31);
165 | else
166 | return this.and(uint, this.not(1 << pos));
167 | };
168 |
169 | BitOps.prototype.get_bit = function(uint, pos, dummy) {
170 | //assert(dummy === undefined, "get_bit: extra 3rd argument");
171 | return (uint & (1 << pos)) >>> pos;
172 | };
173 |
174 | BitOps.prototype.get_bit64 = function(ulong, pos, dummy) {
175 | //assert(dummy === undefined, "get_bit64: extra 3rd argument");
176 | if (pos > 31) {
177 | var ulong_h = Math.floor(ulong / 0x100000000);
178 | return this.get_bit(ulong_h, pos - 31);
179 | } else {
180 | var ulong_l = ulong % 0x100000000;
181 | return this.get_bit(ulong_l, pos);
182 | }
183 | };
184 |
185 | BitOps.prototype.zero_extend = function(val, n) {
186 | return val;
187 | };
188 |
189 | BitOps.prototype.zero_extend64 = function(val, n) {
190 | return val;
191 | };
192 |
193 | BitOps.prototype.get_bits = function(uint, start, end) {
194 | //assert(end != undefined, "get_bits: missing 3rd argument");
195 | if (start == 31) {
196 | if (end !== 0)
197 | return uint >>> end;
198 | if (uint > 0xffffffff)
199 | this.and(uint, 0xffffffff);
200 | else
201 | return uint;
202 | }
203 | //return this.and(uint >>> end, ((1 << (start - end + 1)) - 1));
204 | var ret = (uint >>> end) & ((1 << (start - end + 1)) - 1);
205 | if (ret >= 0x100000000)
206 | return ret - 0x100000000;
207 | else
208 | return ret;
209 | };
210 |
211 | BitOps.prototype.get_bits64 = function(ulong, start, end) {
212 | assert(end != undefined, "get_bits64: missing 3rd argument");
213 | assert(start != end, "get_bits64: start == end");
214 | //assert(start < 32 && end < 32, "get_bits64: too high range");
215 | if (ulong < 0x80000000 && start < 31 && end < 31)
216 | this.get_bits(ulong, start, end);
217 | var ulong_h = Math.floor(ulong / 0x100000000);
218 | var ulong_l = ulong % 0x100000000;
219 | var ret = 0;
220 | if (start > 31) {
221 | if (start == 32) {
222 | ret += this.get_bit(ulong_h, 0) << (31 - end + 1);
223 | } else {
224 | if (end > 31)
225 | ret += this.get_bits(ulong_h, start-32, end-32);
226 | else
227 | ret += this.get_bits(ulong_h, start-31, 0) << (31 - end + 1);
228 | }
229 | }
230 | if (end <= 31) {
231 | if (end == 31)
232 | ret += this.get_bit(ulong_l, 31);
233 | else
234 | ret += this.get_bits(ulong_l, start < 31 ? start : 31, end);
235 | }
236 | return ret;
237 | };
238 |
239 | BitOps.prototype.sign_extend = function(x, x_len, n) {
240 | assert(n !== undefined);
241 | var sign = this.get_bit(x, x_len - 1);
242 | if (sign) {
243 | /*
244 | var extend = "";
245 | for (var i=0; i < (n-x_len); i++)
246 | extend += "1";
247 | var str = extend + toStringBin(x, x_len);
248 | return parseInt32(str, 2);
249 | */
250 | if (n == 32)
251 | var tmp = 0xffffffff;
252 | else
253 | var tmp = (1<= 0 && ret >= x) {
267 | return ret;
268 | } else {
269 | return x * Math.pow(2, n);
270 | }
271 | };
272 |
273 | BitOps.prototype.lsr = function(x, n) {
274 | return (n == 32) ? 0 : x >>> n;
275 | };
276 |
277 | BitOps.prototype.asr = function(x, n) {
278 | if (n == 32)
279 | return 0;
280 | var ret = x >> n;
281 | if (ret < 0)
282 | ret += 0x100000000;
283 | return ret;
284 | };
285 |
286 | BitOps.prototype.sint32 = function(x) {
287 | return x & 0xffffffff;
288 | };
289 |
290 | BitOps.prototype.uint32 = function(x) {
291 | return this.and64(x, 0xffffffff);
292 | };
293 |
294 | BitOps.prototype.toUint32 = function(x) {
295 | if (x < 0) {
296 | if (x < (1 << 31)) {
297 | //throw "toUint32: too small";
298 | x = x + 0x10000000000000000;
299 | } else {
300 | x = x + 0x100000000;
301 | }
302 | }
303 | return this.and64(x, 0xffffffff);
304 | };
305 |
306 | BitOps.prototype.copy_bits = function(dest, start, end, src) {
307 | return this.set_bits(dest, start, end, this.get_bits(src, start, end));
308 | };
309 |
310 | BitOps.prototype.copy_bit = function(dest, pos, src) {
311 | return this.set_bit(dest, pos, this.get_bit(src, pos));
312 | };
313 |
314 | BitOps.prototype.ror = function(value, amount) {
315 | var m = amount % 32;
316 | //var lo = this.get_bits(value, m-1, 0);
317 | //var result = this.or(value >>> m, this.lsl(lo, (32-m)));
318 | var lo = value & ((1 << m) - 1);
319 | var result = (value >>> m) + this.lsl(lo, (32-m));
320 | //assert(result >= 0 && result <= 0xffffffff, "ror");
321 | return result;
322 | };
323 |
324 | BitOps.prototype.count_leading_zero_bits = function(val) {
325 | var n = 0;
326 | for (var i=31; i >= 0; i--) {
327 | if (bitops.get_bit(val, i))
328 | break;
329 | n++;
330 | }
331 | return n;
332 | };
333 |
334 | BitOps.prototype.test = function() {
335 | assert2(this.clear_bit(0xffffffff, 0), 0xfffffffe);
336 | assert2(this.clear_bit(0x13, 31), 0x13);
337 | assert2(this.clear_bit(0x13, 0), 0x12);
338 |
339 | assert2(this.clear_bits(0xffffffff, 31, 0), 0);
340 | assert2(this.clear_bits(0xffffffff, 31, 16), 0x0000ffff);
341 | assert2(this.clear_bits(0xffffffff, 15, 0), 0xffff0000);
342 | assert2(this.clear_bits(0xffffffff, 15, 12), 0xffff0fff);
343 | assert2(this.clear_bits(0x0fffffff, 15, 12), 0x0fff0fff);
344 |
345 | var tmp = 0;
346 | assert(this.xor(0xffffffff, 0xffffffff) == 0);
347 | assert(this.xor(0x11111111, 0x22222222) == 0x33333333);
348 | assert(this.xor(0xf0000000, 0xf0000000) == 0);
349 |
350 | assert(this.xor64(0xffffffff, 0xffffffff) == 0);
351 | assert(this.xor64(0x11111111, 0x22222222) == 0x33333333);
352 | assert(this.xor64(0xf0000000, 0xf0000000) == 0);
353 | assert(this.xor64(0x1f0000000, 0xf0000000) == 0x100000000);
354 |
355 | assert(this.not(0xffffffff) == 0x00000000);
356 | assert(this.not(0x00000000) == 0xffffffff);
357 | assert(this.not(0x00000001) == 0xfffffffe);
358 | assert(this.not(0x80000000) == 0x7fffffff);
359 |
360 | assert(this.or(0x11111111, 0x22222222) == 0x33333333);
361 | assert(this.or(0xffffffff, 0x00000000) == 0xffffffff);
362 | assert(this.or(0xffffffff, 0xffffffff) == 0xffffffff);
363 |
364 | assert(this.or64(0x11111111, 0x22222222) == 0x33333333);
365 | assert(this.or64(0xffffffff, 0x00000000) == 0xffffffff);
366 | assert(this.or64(0xffffffff, 0xffffffff) == 0xffffffff);
367 | assert(this.or64(0xf00000000, 0x00000000) == 0xf00000000);
368 | assert(this.or64(0xf00000000, 0x0000000f) == 0xf0000000f);
369 |
370 | assert(this.and(0x11111111, 0x22222222) == 0);
371 | assert(this.and(0xffffffff, 0) == 0);
372 |
373 | assert(this.and64(0x11111111, 0x22222222) == 0);
374 | assert2(this.and64(0xffffffff, 0), 0);
375 | assert2(this.and64(0xffffffffffff, 0), 0);
376 | assert2(this.and64(0xffffffffffff, 0xffffffff), 0xffffffff);
377 |
378 | assert2(this.get_bit(0xffffffff, 31), 1);
379 | assert2(this.get_bit(0xffffffff, 0), 1);
380 | assert(this.get_bit(0x80000000, 31) == 1);
381 | assert(this.get_bit(0, 31) == 0);
382 | assert(this.get_bit(0, 0) == 0);
383 | assert(this.get_bit(0x7fffffff, 31) == 0);
384 | assert2(this.get_bit(0x80000000, 31), 1);
385 |
386 | assert(this.get_bit64(0xffffffff, 31) == 1);
387 | assert2(this.get_bit64(0xffffffff, 0), 1);
388 | assert(this.get_bit64(0x80000000, 31) == 1);
389 | assert(this.get_bit64(0, 31) == 0);
390 | assert(this.get_bit64(0, 0) == 0);
391 | assert(this.get_bit64(0x7fffffff, 31) == 0);
392 | assert(this.get_bit64(0xffffffffffff, 31) == 1);
393 | assert2(this.get_bit64(0xffffffffffff, 50), 0);
394 |
395 | assert(this.get_bits(0xffffffff, 31, 0) == 0xffffffff);
396 | assert(this.get_bits(0xffffffff, 31, 16) == 0xffff);
397 | assert(this.get_bits(0, 31, 0) == 0);
398 | assert(this.get_bits(0x13, 4, 0) == 0x13, this.get_bits(0x13, 4, 0));
399 | assert2(this.get_bits(0xf0000000, 31, 27), 0x1e);
400 | assert2(this.get_bits(0xc0000000, 31, 27), 0x18);
401 |
402 | assert2(this.get_bits64(0xffffffff, 31, 0), 0xffffffff);
403 | assert2(this.get_bits64(0xffffffff, 31, 16), 0xffff);
404 | assert2(this.get_bits64(0, 31, 0), 0);
405 | assert2(this.get_bits64(0x13, 4, 0), 0x13);
406 | assert2(this.get_bits64(0x100000000, 31, 0), 0);
407 | assert2(this.get_bits64(0x100000000, 31, 0), 0);
408 | assert2(this.get_bits64(0x100000000, 32, 31), 2);
409 | assert2(this.get_bits64(0x300000000, 32, 31), 2);
410 | assert2(this.get_bits64(0x180000000, 32, 31), 3);
411 | assert2(this.get_bits64(0xf00000000, 33, 32), 3);
412 | assert2(this.get_bits64(0xf00000000, 34, 33), 3);
413 | assert2(this.get_bits64(0x180000000, 34, 31), 3);
414 | assert2(this.get_bits64(0x180000000, 34, 30), 6);
415 | assert2(this.get_bits64(0x100000000, 51, 32), 1);
416 |
417 | assert(this.set_bit(0xffffffff, 0, 0) == 0xfffffffe, this.set_bit(0xffffffff, 0, 0));
418 | assert(this.set_bit(0xffffffff, 31, 0) == 0x7fffffff, this.set_bit(0xffffffff, 31, 0));
419 | assert(this.set_bit(0xffffffff, 31, 1) == 0xffffffff, this.set_bit(0xffffffff, 31, 1));
420 | assert(this.set_bit(0x13, 31, 0) == 0x13, this.set_bit(0x13, 31, 0));
421 | assert(this.set_bit(0, 31, 1) == 0x80000000);
422 | assert(this.set_bit(0, 0, 1) == 1);
423 | assert(this.set_bit(0, 2, 1) == 4, this.set_bit(0, 2, 1));
424 |
425 | assert(this.set_bits(0xffffffff, 31, 0, 0) == 0);
426 | assert(this.set_bits(0xffffffff, 15, 0, 0) == 0xffff0000, this.set_bits(0xffffffff, 15, 0, 0));
427 | assert(this.set_bits(0, 4, 0, 0x13) == 0x13);
428 | assert2(this.set_bits(0xf0000000, 31, 27, 0x1e), 0xf0000000);
429 | assert2(this.set_bits(0x00000000, 31, 27, 0x1e), 0xf0000000);
430 | assert2(this.set_bits(0xf0000000, 31, 27, 0x18), 0xc0000000);
431 |
432 | assert2(this.lsl(1, 1), 2);
433 | assert2(this.lsl(0xf0000000, 1), 0x1e0000000);
434 | assert2(this.lsl(0xffffffff, 1), 0x1fffffffe);
435 | assert2(this.lsl(0xf0f0f0f0, 4), 0xf0f0f0f00);
436 | assert2(this.lsl(0x100000000, 1), 0x200000000);
437 |
438 | assert2(this.lsr(1, 1), 0);
439 | assert2(this.lsr(0xf0000000, 1), 0x78000000);
440 | assert2(this.lsr(0xffffffff, 1), 0x7fffffff);
441 | assert2(this.lsr(0xf0f0f0f0, 4), 0x0f0f0f0f);
442 | assert2(this.lsr(0x80000000, 32), 0);
443 | assert2(this.lsr(0x80000000, 1), 0x40000000);
444 |
445 | assert2(this.lsr(1, 1), 0);
446 | assert2(this.lsr(0xf0000000, 1), 0x78000000);
447 | assert2(this.lsr(0xffffffff, 1), 0x7fffffff);
448 | assert2(this.lsr(0xf0f0f0f0, 4), 0x0f0f0f0f);
449 | assert2(this.lsr(0x80000000, 32), 0);
450 | assert2(this.lsr(0x80000000, 1), 0x40000000);
451 |
452 | assert2(this.sint32(0x00000000), 0x00000000);
453 | assert2(this.sint32(0x80000000), 0x80000000 & 0xffffffff);
454 | assert2(this.sint32(0x100000000), 0x00000000);
455 |
456 | assert2(this.uint32(0x00000000), 0x00000000);
457 | assert2(this.uint32(0x80000000), 0x80000000);
458 | assert2(this.uint32(0x100000000), 0x00000000);
459 | assert2(this.uint32(0xffffffff), 0xffffffff);
460 | assert2(this.uint32(0xfffffffff), 0xffffffff);
461 |
462 | assert2(this.sign_extend(0, 26, 32), 0);
463 | //assert2(this.sign_extend(0, 1, 32), this.sint32(0));
464 | //assert2(this.sign_extend(1, 1, 32), this.sint32(0xffffffff));
465 | //assert2(this.sign_extend(0x0000ffff, 16, 32), this.sint32(0xffffffff));
466 | //assert2(this.sign_extend(0x00007fff, 16, 32), this.sint32(0x00007fff));
467 | assert2(this.sign_extend(0, 1, 32), 0);
468 | assert2(this.sign_extend(1, 1, 32), 0xffffffff);
469 | assert2(this.sign_extend(0x0000ffff, 16, 32), 0xffffffff);
470 | assert2(this.sign_extend(0x00007fff, 16, 32), 0x00007fff);
471 | assert2(this.sign_extend(0xffffe3 << 2, 26, 32), 0xffffff8c);
472 |
473 | assert2(this.copy_bits(0xf0000000, 31, 27, 0), 0);
474 | assert2(this.copy_bits(0xf0000000, 31, 27, 0xc0000000), 0xc0000000);
475 |
476 | assert2(this.copy_bit(0, 0, 1), 1);
477 | assert2(this.copy_bit(1, 0, 0), 0);
478 | assert2(this.copy_bit(0xffffffff, 0, 0), 0xfffffffe);
479 | assert2(this.copy_bit(0xffffffff, 31, 0), 0x7fffffff);
480 |
481 | assert2(this.ror(0x10000000, 1), 0x08000000);
482 | assert2(this.ror(0x10000001, 1), 0x88000000);
483 | assert2(this.ror(0xffffffff, 1), 0xffffffff);
484 | assert2(this.ror(0x0000ffff, 16), 0xffff0000);
485 | assert2(this.ror(0x000ffff0, 16), 0xfff0000f);
486 |
487 | assert2(this.count_leading_zero_bits(0), 32);
488 | assert2(this.count_leading_zero_bits(0x80000000), 0);
489 | assert2(this.count_leading_zero_bits(0x00008000), 16);
490 |
491 | display.log("All BitOps tests passed successfully");
492 | };
493 |
494 |
--------------------------------------------------------------------------------
/js/jquery-ui-1.8.18.custom.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery UI 1.8.18
3 | *
4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | * http://jquery.org/license
7 | *
8 | * http://docs.jquery.com/UI
9 | */(function(a,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(c,d){function h(b,c,d,f){a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)});return c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){if(c===b)return g["inner"+d].call(this);return this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){if(typeof b!="number")return g["outer"+d].call(this,b);return this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!!d&&!!a.element[0].parentNode)for(var e=0;e0)return!0;b[d]=1,e=b[d]>0,b[d]=0;return e},isOverAxis:function(a,b,c){return a>b&&a",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"#{label}"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash){e.selected=a;return!1}}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1){this.blur();return!1}e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected")){e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur();return!1}if(!f.length){e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur();return!1}}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$="+a+"]")));return a},destroy:function(){var b=this.options;this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie);return this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e]));return this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0]));return this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a])));return this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;this.anchors.eq(a).trigger(this.options.event+".tabs");return this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup();return this},url:function(a,b){this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b);return this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.18"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a>> 8;
459 |
460 | return stat;
461 | };
462 |
463 | Protocol9P2000u.prototype.build_stat_vals_from_data = function(data) {
464 | var types = [
465 | "h", // size
466 | "h", // type
467 | "w", // dev
468 | "Q", // qid
469 | "w", // mode
470 | "w", // atime
471 | "w", // mtime
472 | "w", // length0
473 | "w", // length1
474 | "s", // name
475 | "s", // uid
476 | "s", // gid
477 | "s", // muid
478 | "s", // extension
479 | "w", // n_uid
480 | "w", // n_gid
481 | "w" // n_muid
482 | ];
483 | var stat_vals = this.net9p.unmarshal(types, data);
484 |
485 | return stat_vals;
486 | };
487 |
488 | Protocol9P2000u.prototype.stat = function(id, tag, next_data) {
489 | var req = this.net9p.unmarshal(["w"], next_data);
490 | var fid = req[0];
491 |
492 | var qid = this.get_qid(fid);
493 | if (!qid)
494 | abort("[stat] No such QID found for fid=" + fid);
495 |
496 | display.log("[stat] path=" + qid.entry.fullPath);
497 | var filesize = qid.entry.isDirectory ? 0 : qid.entry.size;
498 | var payload = this.build_stat(qid.name, filesize, qid, qid.atime, qid.entry.mtime.getTime());
499 | payload = [0, 0].concat(payload); // Ignored by guest but required
500 |
501 | var reply = this.build_reply(id, tag, payload);
502 | return reply;
503 | };
504 | Protocol9P2000u.prototype[124] = Protocol9P2000u.prototype.stat;
505 |
506 | Protocol9P2000u.prototype.wstat = function(id, tag, next_data) {
507 | var req = this.net9p.unmarshal(["w"], next_data);
508 | var fid = req[0];
509 | next_data(); next_data(); // We need it to remove unknown halfword data
510 | var stat_vals = this.build_stat_vals_from_data(next_data);
511 |
512 | var qid = this.get_qid(fid);
513 | if (!qid)
514 | abort("[wstat] No such QID found for fid=" + fid);
515 |
516 | display.log("[wstat] path=" + qid.entry.fullPath);
517 |
518 | qid.atime = qid.parent.atime = getCurrentTime();
519 | if (stat_vals[9] && stat_vals[9] != qid.name) {
520 | var newname = stat_vals[9];
521 | // FIXME: support only rename
522 | display.log("[wstat] newname=" + newname + ", name=" + name);
523 |
524 | var net9p = this.net9p;
525 | var that = this;
526 | display.log("[wstat] parent=" + qid.parent.entry.fullPath);
527 | net9p.fs.rename(qid.parent.entry, qid.name, newname, function(entry) {
528 | var reply = that.build_reply(id, tag, []);
529 | net9p.send_reply(reply);
530 | });
531 |
532 | return null;
533 | } else {
534 | return this.build_reply(id, tag, []);
535 | }
536 | };
537 | Protocol9P2000u.prototype[126] = Protocol9P2000u.prototype.wstat;
538 |
539 | function Net9p(virtio) {
540 | this.virtio = virtio;
541 |
542 | this.proto = new Protocol9P2000u(this);
543 | this.fs = new HTML5FileSystem('/9proot', 50 * 1024 * 1024);
544 | }
545 |
546 | Net9p.prototype.marshal = function(type, data) {
547 | var out = [];
548 | var item;
549 | for (var i=0; i < type.length; i++) {
550 | item = data[i];
551 | switch (type[i]) {
552 | case "w":
553 | out.push(item & 0xff);
554 | out.push((item >>> 8) & 0xff);
555 | out.push((item >>> 16) & 0xff);
556 | out.push(item >>> 24);
557 | break;
558 | case "h":
559 | out.push(item & 0xff);
560 | out.push(item >>> 8);
561 | break;
562 | case "b":
563 | out.push(item);
564 | break;
565 | case "s":
566 | // Prepend size
567 | out.push(item.length & 0xff);
568 | out.push(item.length >>> 8);
569 | for (var j in item)
570 | out.push(item.charCodeAt(j));
571 | break;
572 | case "D":
573 | for (var j in item)
574 | out.push(item[j]);
575 | break;
576 | case "Q":
577 | out = out.concat(this.marshal(["b"], item.type));
578 | out = out.concat(this.marshal(["w"], item.version));
579 | out = out.concat(this.marshal(["w"], item.path));
580 | out = out.concat(this.marshal(["w"], 0)); // FIXME
581 | break;
582 | default:
583 | abort("marshal: Unknown type=" + type[i]);
584 | }
585 | }
586 | return out;
587 | };
588 |
589 | Net9p.prototype.unmarshal = function(type, data_or_generator) {
590 | var out = [];
591 | var get = (typeof data_or_generator == "function") ?
592 | data_or_generator :
593 | function() { return data_or_generator.shift(); };
594 | for (var i=0; i < type.length; i++) {
595 | switch (type[i]) {
596 | case "w":
597 | var val = get();
598 | val += get() << 8;
599 | val += get() << 16;
600 | var tmp = get() << 24;
601 | if (tmp < 0)
602 | tmp += 0x100000000;
603 | out.push(val + tmp);
604 | break;
605 | case "h":
606 | var val = get();
607 | out.push(val + (get() << 8));
608 | break;
609 | case "b":
610 | out.push(get());
611 | break;
612 | case "s":
613 | var len = get();
614 | len += get() << 8;
615 | var str = '';
616 | for (var j=0; j < len; j++)
617 | str += String.fromCharCode(get());
618 | out.push(str);
619 | break;
620 | case "Q":
621 | var stat = {
622 | type: 0,
623 | version: 0,
624 | path: 0
625 | };
626 | stat.type = this.unmarshal(["b"], get)[0];
627 | stat.version = this.unmarshal(["w"], get)[0];
628 | stat.path = this.unmarshal(["w", "w"], get)[0]; // FIXME
629 | out.push(stat);
630 | break;
631 | default:
632 | abort("unmarshal: Unknown type=" + type[i]);
633 | }
634 | }
635 | return out;
636 | };
637 |
638 | Net9p.prototype.get_header_size = function() {
639 | return this.proto.HEADER_SIZE;
640 | };
641 |
642 | Net9p.prototype.get_body_size = function(id) {
643 | return this.proto.HEADER_SIZE;
644 | };
645 |
646 | Net9p.prototype.unmarshal_header = function(data) {
647 | var header = this.unmarshal(["w", "b", "h"], data);
648 | return {
649 | size: header[0],
650 | id: header[1],
651 | tag: header[2]
652 | };
653 | };
654 |
655 | Net9p.prototype.send_reply = function(reply) {
656 | this.virtio.send_reply(reply);
657 | };
658 |
--------------------------------------------------------------------------------
/js/armv7-cp15.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Javascript ARMv7 Emulator
3 | *
4 | * Copyright 2012, Ryota Ozaki
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | */
7 | /*
8 | * CP15 System Control Coprocessor
9 | */
10 | function ARMv7_CP15(options, cpu) {
11 | this.options = options;
12 | this.cpu = cpu;
13 |
14 | this.interrupt_vector_address = 0;
15 | this.read = new Object();
16 | this.write = new Object();
17 | this.data = new Object();
18 |
19 | this.TRANS_FAULT_SECTION = 5; // 0b00101
20 | this.TRANS_FAULT_PAGE = 7; // 0b00111
21 | this.PERMISSION_FAULT_SECTION = 0xd; // 0b01101
22 | this.PERMISSION_FAULT_PAGE = 0xf; // 0b01111
23 |
24 | // crn, opc1, crm, opc2
25 | this.MIDR = [0, 0, 0, 0];
26 | this.CTR = [0, 0, 0, 1];
27 | this.ID_PFR0 = [0, 0, 1, 0];
28 | this.ID_MMFR0 = [0, 0, 1, 4];
29 | this.ID_MMFR1 = [0, 0, 1, 5];
30 | this.ID_ISAR0 = [0, 0, 2, 0];
31 | this.CCSIDR = [0, 1, 0, 0];
32 | this.CLIDR = [0, 1, 0, 1];
33 | this.CSSELR = [0, 2, 0, 0];
34 | this.SCTLR = [1, 0, 0, 0];
35 | this.CPACR = [1, 0, 0, 2];
36 | this.TTBR0 = [2, 0, 0, 0];
37 | this.TTBR1 = [2, 0, 0, 1];
38 | this.TTBCR = [2, 0, 0, 2];
39 | this.ICIALLU = [7, 0, 5, 0];
40 | this.ICIMVAU = [7, 0, 5, 1];
41 | this.BPIALL = [7, 0, 5, 6];
42 | this.BPIMVA = [7, 0, 5, 7];
43 | this.ISB = [7, 0, 5, 4];
44 | this.DCCMVAC = [7, 0,10, 1];
45 | this.DSB = [7, 0,10, 4];
46 | this.DMB = [7, 0,10, 5];
47 | this.DCCMVAU = [7, 0,11, 1];
48 | this.DCCIMVAC = [7, 0,14, 1];
49 | this.DACR = [3, 0, 0, 0];
50 | this.DFSR = [5, 0, 0, 0];
51 | this.IFSR = [5, 0, 0, 1]; // Instruction Fault Status Register (IFSR)
52 | this.DFAR = [6, 0, 0, 0]; // Data Fault Address Register (DFAR)
53 | this.IFAR = [6, 0, 0, 2]; // Instruction Fault Address Register (IFAR)
54 | this.ITLBIALL = [8, 0, 5, 0];
55 | this.ITLBIMVA = [8, 0, 5, 1];
56 | this.ITLBIASID = [8, 0, 5, 2];
57 | this.DTLBIALL = [8, 0, 6, 0];
58 | this.DTLBIMVA = [8, 0, 6, 1];
59 | this.DTLBIASID = [8, 0, 6, 2];
60 | this.UTLBIALL = [8, 0, 7, 0];
61 | this.UTLBIMVA = [8, 0, 7, 1];
62 | this.UTLBIASID = [8, 0, 7, 2];
63 | this.PRRR = [10, 0, 2, 0]; // c10, Primary Region Remap Register (PRRR)
64 | this.NMRR = [10, 0, 2, 1]; // c10, Normal Memory Remap Register (NMRR)
65 | this.CONTEXTIDR = [13, 0, 0, 1];
66 | this.TPIDRURW = [13, 0, 0, 2]; // User Read/Write Thread ID Register, TPIDRURW
67 | this.TPIDRURO = [13, 0, 0, 3]; // User Read-only Thread ID Register, TPIDRURO
68 |
69 | var mmu = this.cpu.mmu;
70 | var that = this;
71 |
72 | // [31:24]=Implementor [23:20]=Variant [19:16]=Architecture [15:4]=Primary part number [3:0]=Revision
73 | // MRC p15,0,,c0,c0,0 ; Read CP15 Main ID Register
74 | var midr = 0;
75 | midr = bitops.set_bits(midr, 31, 24, 0x41); // ARM Limited
76 | midr = bitops.set_bits(midr, 23, 20, 0x1); // Major Revison Number
77 | midr = bitops.set_bits(midr, 19, 16, 0xf); // Defined by CPUID scheme
78 | // [15:12] != 0x0 and != 0x7
79 | midr = bitops.set_bits(midr, 15, 12, 0xf);
80 | midr = bitops.set_bits(midr, 3, 0, 0x1); // Minor Revison Number
81 | this.register_readonly("MIDR", midr);
82 |
83 | /*
84 | * CTR: Cache Type Register
85 | * Bits [31:29]: Set to 0b100 for the ARMv7 register format.
86 | * CWG, bits [27:24]: Cache Writeback Granule
87 | * ERG, bits [23:20]: Exclusives Reservation Granule // Manual is wrong :-)
88 | * DminLine, bits [19:16]: Log2 of the number of words in the smallest cache line of all the data caches and unified caches that are controlled by the core.
89 | * L1Ip, bits [15:14]: Level 1 instruction cache policy.
90 | * IminLine, bits [3:0]: Log2 of the number of words in the smallest cache line of all the instruction caches that are controlled by the core.
91 | */
92 | var ctr = 0;
93 | ctr = bitops.set_bits(ctr, 31, 29, 4);
94 | ctr = bitops.set_bits(ctr, 27, 24, 0);
95 | ctr = bitops.set_bits(ctr, 23, 20, 0);
96 | ctr = bitops.set_bits(ctr, 19, 16, 0); // FIXME
97 | ctr = bitops.set_bits(ctr, 15, 14, 1); // ASID-tagged Virtual Index, Virtual Tag (AIVIVT)
98 | ctr = bitops.set_bits(ctr, 3, 0, 0); // FIXME
99 | this.register_readonly("CTR", ctr);
100 |
101 | // TODO
102 | var sctlr = 0;
103 | sctlr = bitops.set_bit(sctlr, 31, 0); // UNK/SBZP
104 | sctlr = bitops.set_bit(sctlr, 30, 0); // TE: Thumb Exception enable
105 | sctlr = bitops.set_bit(sctlr, 29, 0); // AFE: Access Flag Enable bit
106 | sctlr = bitops.set_bit(sctlr, 28, 0); // TRE: TEX Remap Enable bit
107 | sctlr = bitops.set_bit(sctlr, 27, 0); // NMFI: Non-maskable Fast Interrupts enable
108 | sctlr = bitops.set_bit(sctlr, 25, 0); // EE: Exception Endianness bit
109 | sctlr = bitops.set_bit(sctlr, 24, 0); // VE: Interrupt Vectors Enable bit
110 | sctlr = bitops.set_bit(sctlr, 22, 1); // U: In ARMv7 this bit is RAO/SBOP
111 | sctlr = bitops.set_bit(sctlr, 21, 0); // FI: Fast Interrupts configuration enable bit
112 | sctlr = bitops.set_bit(sctlr, 17, 0); // HA: Hardware Access Flag Enable bit
113 | sctlr = bitops.set_bit(sctlr, 14, 0); // RR: Round Robin bit
114 | sctlr = bitops.set_bit(sctlr, 13, 0); // V: Vectors bit
115 | sctlr = bitops.set_bit(sctlr, 12, 0); // I: Instruction cache enable bit
116 | sctlr = bitops.set_bit(sctlr, 11, 0); // Z: Branch prediction enable bit
117 | sctlr = bitops.set_bit(sctlr, 7, 0); // B: In ARMv7 this bit is RAZ/SBZP
118 | sctlr = bitops.set_bit(sctlr, 2, 0); // C: Cache enable bit
119 | sctlr = bitops.set_bit(sctlr, 1, 0); // A: Alignment bit
120 | sctlr = bitops.set_bit(sctlr, 0, 0); // M: MMU enable bit
121 | this.register_writable("SCTLR", sctlr, function (word) {
122 | that.data["SCTLR"] = word;
123 | if (word & 1) {
124 | mmu.enabled = true;
125 | } else {
126 | mmu.enabled = false;
127 | }
128 | if (!(word & 0x01000000)) { // SCTLR.VE[24]
129 | if (word & 0x00002000) { // SCTLR.V[13]
130 | that.interrupt_vector_address = 0xffff0000;
131 | } else {
132 | that.interrupt_vector_address = 0x00000000;
133 | }
134 | }
135 | if (word & 2) {// SCTLR.A[1]
136 | mmu.check_unaligned = true;
137 | throw "Check unaligned access!";
138 | } else {
139 | mmu.check_unaligned = false;
140 | }
141 | // Always 1
142 | that.data["SCTLR"] = bitops.set_bit(that.data["SCTLR"], 22, 1);
143 | });
144 |
145 | var id_pfr0 = 0;
146 | id_pfr0 = bitops.set_bits(id_pfr0, 3, 0, 1); // ARM instruction set supported
147 | this.register_readonly("ID_PFR0", id_pfr0);
148 |
149 | var id_mmfr0 = 0;
150 | id_mmfr0 = bitops.set_bits(id_mmfr0, 31, 28, 0); // Reserved, Read-As-Zero
151 | id_mmfr0 = bitops.set_bits(id_mmfr0, 37, 24, 0); // FCSE support
152 | id_mmfr0 = bitops.set_bits(id_mmfr0, 23, 20, 0); // Auxiliary registers
153 | // ARMv7 requires this setting.
154 | id_mmfr0 = bitops.set_bits(id_mmfr0, 19, 16, 1); // TCM support
155 | id_mmfr0 = bitops.set_bits(id_mmfr0, 15, 12, 0); // Outer Shareable
156 | id_mmfr0 = bitops.set_bits(id_mmfr0, 11, 8, 0); // Cache coherence
157 | id_mmfr0 = bitops.set_bits(id_mmfr0, 7, 4, 0); // PMSA support
158 | // VMSAv7 supported, with support for remapping and the access flag. ARMv7-A profile.
159 | id_mmfr0 = bitops.set_bits(id_mmfr0, 3, 0, 3); // VMSA support
160 | this.register_readonly("ID_MMFR0", id_mmfr0);
161 |
162 | var id_isar0 = 0;
163 | this.register_readonly("ID_ISAR0", id_mmfr0);
164 |
165 | var id_mmfr1 = 0;
166 | // For execution correctness, Branch Predictor requires no flushing at any time.
167 | id_mmfr1 = bitops.set_bits(id_mmfr1, 31, 28, 4); // Branch Predictor
168 | // None supported. This is the required setting for ARMv7.
169 | id_mmfr1 = bitops.set_bits(id_mmfr1, 37, 24, 0); // L1 cache Test and Clean
170 | // None supported. This is the required setting for ARMv7, because ARMv7 requires a hierarchical cache implementation.
171 | id_mmfr1 = bitops.set_bits(id_mmfr1, 23, 20, 0); // L1 unified cache
172 | id_mmfr1 = bitops.set_bits(id_mmfr1, 19, 16, 0); // L1 Harvard cache
173 | id_mmfr1 = bitops.set_bits(id_mmfr1, 15, 12, 0); // L1 unified cache s/w
174 | id_mmfr1 = bitops.set_bits(id_mmfr1, 11, 8, 0); // L1 Harvard cache s/w
175 | id_mmfr1 = bitops.set_bits(id_mmfr1, 7, 4, 0); // L1 unified cache VA
176 | id_mmfr1 = bitops.set_bits(id_mmfr1, 3, 0, 0); // L1 Harvard cache VA
177 | this.register_readonly("ID_MMFR1", id_mmfr1);
178 |
179 | // c0, Cache Size ID Registers (CCSIDR)
180 | /*
181 | * WT, bit [31]: Indicates whether the cache level supports Write-Through
182 | * WB, bit [30]: Indicates whether the cache level supports Write-Back
183 | * RA, bit [29]: Indicates whether the cache level supports Read-Allocation
184 | * WA, bit [28]: Indicates whether the cache level supports Write-Allocation
185 | * NumSets, bits [27:13]: Number of sets in cache
186 | * Associativity, bits [12:3]: Associativity of cache
187 | * LineSize, bits [2:0]: Log2(Number of words in cache line)
188 | */
189 | var ccsidr = 0;
190 | ccsidr = bitops.set_bit(ccsidr, 31, 1);
191 | ccsidr = bitops.set_bit(ccsidr, 30, 1);
192 | ccsidr = bitops.set_bit(ccsidr, 29, 1);
193 | ccsidr = bitops.set_bit(ccsidr, 28, 1);
194 | ccsidr = bitops.set_bits(ccsidr, 27, 13, 0); // One set
195 | ccsidr = bitops.set_bits(ccsidr, 12, 3, 1); // Two set associative
196 | ccsidr = bitops.set_bits(ccsidr, 2, 0, 0); // 4 words length
197 | this.register_readonly("CCSIDR", ccsidr);
198 |
199 | // Cache Level ID Register
200 | var clidr = 0;
201 | clidr = bitops.set_bits(clidr, 29, 27, 0); // LoU: Level of Unification for the cache hierarchy
202 | clidr = bitops.set_bits(clidr, 26, 24, 0); // LoC: Level of Coherency for the cache hierarchy
203 | clidr = bitops.set_bits(clidr, 23, 21, 0); // Ctype8
204 | clidr = bitops.set_bits(clidr, 20, 18, 0); // Ctype7
205 | clidr = bitops.set_bits(clidr, 17, 15, 0); // Ctype6
206 | clidr = bitops.set_bits(clidr, 14, 12, 0); // Ctype5
207 | clidr = bitops.set_bits(clidr, 11, 9, 0); // Ctype4
208 | clidr = bitops.set_bits(clidr, 8, 6, 0); // Ctype3
209 | clidr = bitops.set_bits(clidr, 5, 3, 0); // Ctype2
210 | clidr = bitops.set_bits(clidr, 2, 0, 0); // Ctype1
211 | this.register_readonly("CLIDR", clidr);
212 |
213 | // CSSELR, Cache Size Selection Register
214 | var csselr = 0;
215 | csselr = bitops.set_bits(csselr, 3, 1, 0); // Level: Cache level of required cache
216 | csselr = bitops.set_bit(csselr, 0, 0); // InD: Instruction not Data bit
217 | this.register_writable("CSSELR", csselr);
218 |
219 | /*
220 | * Translation Table Base Register 0 (TTBR0)
221 | * bits[31:14-N]: Translation table base 0 address
222 | * bit[5]: NOS: Not Outer Shareable bit
223 | * bits[4:3]: RGN: Region bits
224 | * bit[2]: IMP: Implementation defined bit
225 | * bit[1]: S: Shareable bit
226 | * bit[0]: C: Cacheable bit
227 | */
228 | this.register_writable("TTBR0", 0, function (word) {
229 | display.log("TTBR0");
230 | that.data["TTBR0"] = word;
231 | mmu.baseaddr0 = bitops.clear_bits(word, 13 - mmu.width, 0);
232 | if (that.options.enable_logger) {
233 | that.log_value(word, "ttbr0");
234 | that.log_value(mmu.baseaddr0, "baseaddr0 in ttbr0");
235 | }
236 | });
237 |
238 | /*
239 | * Translation Table Base Register 1 (TTBR1)
240 | * bits[31:14]: Translation table base 1 address
241 | * bit[5]: NOS: Not Outer Shareable bit
242 | * bits[4:3]: RGN: Region bits
243 | * bit[2]: IMP: Implementation defined bit
244 | * bit[1]: S: Shareable bit
245 | * bit[0]: C: Cacheable bit
246 | */
247 | this.register_writable("TTBR1", 0, function (word) {
248 | display.log("TTBR1");
249 | that.data["TTBR1"] = word;
250 | mmu.baseaddr1 = bitops.clear_bits(word, 13, 0);
251 | if (that.options.enable_logger) {
252 | that.log_value(word, "ttbr1");
253 | that.log_value(mmu.baseaddr1, "baseaddr1 in ttbr1");
254 | }
255 | });
256 |
257 | /*
258 | * Translation Table Base Control Register (TTBCR)
259 | * bits[2:0]: N: Indicate the width of the base address held in TTBR0
260 | */
261 | this.register_writable("TTBCR", 0, function(word) {
262 | display.log("TTBCR");
263 | that.data["TTBCR"] = word;
264 | var width = bitops.get_bits(word, 2, 0);
265 | var ttbr0 = that.data["TTBR0"];
266 | mmu.width = width;
267 | mmu.mask = (1 << (31 - width - 20 + 1)) - 1;
268 | mmu.baseaddr0 = bitops.clear_bits(ttbr0, 13 - width, 0);
269 | that.log_value(word, "word");
270 | that.log_value(mmu.baseaddr0, "baseaddr0 in ttbcr");
271 | if (width) {
272 | throw "width > 0";
273 | var ttbr1 = that.data["TTBR1"];
274 | mmu.baseaddr1 = bitops.clear_bits(ttbr1, 13, 0);
275 | that.log_value(word, "word");
276 | that.log_value(mmu.baseaddr1, "baseaddr1 in ttbcr");
277 | }
278 | display.log("TTBCR called.");
279 | });
280 |
281 | /*
282 | * CPACR, Coprocessor Access Control Register
283 | */
284 | this.register_writable("CPACR", 0);
285 |
286 | /*
287 | * Domain Access Control Register (DACR)
288 | * bits[31:30]: D15
289 | * ...
290 | * bits[1:0]: D0
291 | * 00: No access. Any access to the domain generates a Domain fault.
292 | * 01: Client. Accesses are checked against the permission bits in the translation tables.
293 | * 10: Reserved, effect is UNPREDICTABLE
294 | * 11: Manager. Accesses are not checked against the permission bits in the translation tables.
295 | */
296 | var dacr = 0;
297 | this.domains = new Array();
298 | for (var i=0; i < 16; i++)
299 | this.domains[i] = 0;
300 |
301 | this.register_writable("DACR", dacr, function (word) {
302 | that.data["DACR"] = word;
303 | for (var i=0; i < 16; i++) {
304 | that.domains[i] = bitops.get_bits(word, i*2+1, i*2);
305 | }
306 | });
307 |
308 | /*
309 | * Data Fault Status Register (DFSR)
310 | * bit[12]: ExT, External abort type
311 | * bit[11]: WnR, Write not Read
312 | * bits[10,3:0]: FS, Fault status
313 | * //bits[7:4]: Domain, The domain of the fault address
314 | */
315 | // Note that these registers are actually read-only POV of software,
316 | // however, the values are changed by hardware during memory abort.
317 | // To be save/restore-able, register them as writable.
318 | this.register_writable("DFAR", 0);
319 | this.register_writable("IFAR", 0);
320 | this.register_writable("DFSR", 0);
321 | this.register_writable("IFSR", 0);
322 |
323 | this.register_writeonly("ICIALLU");
324 | this.register_writeonly("ICIMVAU");
325 | this.register_writeonly("BPIALL");
326 | this.register_writeonly("BPIMVA");
327 | this.register_writeonly("ISB"); // Instruction Synchronization Barrier
328 | this.register_writeonly("DCCMVAC"); // Clean data cache linux by MVA to PoU
329 | this.register_writeonly("DSB"); // Data Synchronization Barrier
330 | this.register_writeonly("DMB"); // Data Memory Barrier
331 | this.register_writeonly("DCCMVAU"); // Clean data cache line by MVA to PoU
332 | this.register_writeonly("DCCIMVAC"); // Clean and invalidate data cache line by MVA to PoU
333 |
334 | this.register_writeonly("ITLBIALL"); // invalidate instruction TLB
335 | this.register_writeonly("ITLBIMVA"); // invalidate instruction TLB entry by MVA
336 | this.register_writeonly("ITLBIASID"); // invalidate instruction TLB by ASID match
337 | this.register_writeonly("DTLBIALL"); // invalidate data TLB
338 | this.register_writeonly("DTLBIMVA"); // invalidate data TLB entry by MVA
339 | this.register_writeonly("DTLBIASID"); // invalidate data TLB by ASID match
340 | this.register_writeonly("UTLBIALL"); // invalidate unified TLB
341 | this.register_writeonly("UTLBIMVA"); // invalidate unified TLB entry by MVA
342 | this.register_writeonly("UTLBIASID");
343 |
344 | this.register_writable("PRRR", 0); // TODO
345 | this.register_writable("NMRR", 0); // TODO
346 |
347 | // Context ID Register (CONTEXTIDR)
348 | this.register_writable("CONTEXTIDR", 0, function (word) {
349 | var procid = (word >>> 8) & 0x00ffffff;
350 | var asid = word & 0xff;
351 | var old_asid = that.data["CONTEXTIDR"] & 0xff;
352 | display.log("PROCID=" + procid + ", ASID=" + asid + ", ASID(old)=" + old_asid);
353 | mmu.asid = asid;
354 | that.data["CONTEXTIDR"] = word;
355 | });
356 |
357 | // Software Thread ID registers
358 | this.register_writable("TPIDRURW", 0);
359 | this.register_writable("TPIDRURO", 0);
360 | }
361 |
362 | ARMv7_CP15.prototype.register_readonly = function(name, initval) {
363 | this.read[this[name]] = initval;
364 | };
365 |
366 | ARMv7_CP15.prototype.register_writeonly = function(name, cb_w) {
367 | if (cb_w) {
368 | this.write[this[name]] = cb_w;
369 | } else {
370 | var that = this;
371 | this.write[this[name]] = function(word) {
372 | that.data[name] = word;
373 | };
374 | }
375 | };
376 |
377 | ARMv7_CP15.prototype.register_writable = function(name, initval, cb_w) {
378 | this.data[name] = initval;
379 | var that = this;
380 | if (cb_w) {
381 | this.read[this[name]] = function() {
382 | return that.data[name];
383 | };
384 | this.write[this[name]] = cb_w;
385 | } else {
386 | this.read[this[name]] = function() {
387 | return that.data[name];
388 | };
389 | this.write[this[name]] = function(word) {
390 | that.data[name] = word;
391 | };
392 | }
393 | };
394 |
395 | ARMv7_CP15.prototype.send_word = function(inst, word) {
396 | var opc1 = (inst >>> 21) & 0x7;
397 | var crn = (inst >>> 16) & 0xf; // the major register specifier
398 | var opc2 = (inst >>> 5) & 0x7;
399 | var crm = inst & 0xf;
400 | var func = this.write[[crn, opc1, crm, opc2]];
401 | if (func)
402 | func(word);
403 | else
404 | throw "write: " + [crn, opc1, crm, opc2];
405 | };
406 |
407 | ARMv7_CP15.prototype.get_word = function(inst) {
408 | var opc1 = (inst >>> 21) & 0x7;
409 | var crn = (inst >>> 16) & 0xf; // the major register specifier
410 | var opc2 = (inst >>> 5) & 0x7;
411 | var crm = inst & 0xf;
412 | //this.dump_inst(inst);
413 | var ret = this.read[[crn, opc1, crm, opc2]];
414 | if (typeof ret == "number")
415 | return ret;
416 | else if (ret !== undefined)
417 | return ret();
418 | else
419 | throw "read: " + [crn, opc1, crm, opc2];
420 | };
421 |
422 | ARMv7_CP15.prototype.save = function() {
423 | var params = Object();
424 | for (var i in this.data) {
425 | params[i] = this.data[i];
426 | }
427 | return params;
428 | };
429 |
430 | ARMv7_CP15.prototype.restore = function(params) {
431 | for (var i in this.data) {
432 | this.data[i] = params[i];
433 | }
434 | if (bitops.get_bit(this.data["SCTLR"], 0))
435 | this.cpu.mmu.enabled = true;
436 | else
437 | this.cpu.mmu.enabled = false;
438 | if (!bitops.get_bit(this.data["SCTLR"], 24)) { // SCTLR.VE
439 | if (bitops.get_bit(this.data["SCTLR"], 13)) { // SCTLR.V
440 | this.interrupt_vector_address = 0xffff0000;
441 | } else {
442 | this.interrupt_vector_address = 0x00000000;
443 | }
444 | }
445 | if (bitops.get_bit(this.data["SCTLR"], 1)) // SCTLR.A
446 | this.cpu.mmu.check_unaligned = true;
447 | else
448 | this.cpu.mmu.check_unaligned = false;
449 | for (var i=0; i < 16; i++)
450 | this.domains[i] = bitops.get_bits(this.data["DACR"], i*2+1, i*2);
451 | };
452 |
453 | ARMv7_CP15.prototype.dump_reg = function(name) {
454 | var val = this.data[name];
455 | display.log(name + ":\t" + toStringHex32(val) + " (" + toStringBin32(val) + ")");
456 | };
457 |
458 | ARMv7_CP15.prototype.sctlr_get_nmfi = function() {
459 | var sctlr = this.data["SCTLR"];
460 | return (sctlr >>> 27) & 1;
461 | };
462 |
463 | ARMv7_CP15.prototype.dump_sctlr = function() {
464 | var sctlr = this.data["SCTLR"];
465 | var val;
466 | var msgs = new Array();
467 | val = bitops.get_bit(sctlr, 29);
468 | msgs.push("AFE=" + (val ? "simple" : "full"));
469 | val = bitops.get_bit(sctlr, 28);
470 | msgs.push("TRE=" + (val ? "enabled" : "disabled"));
471 | val = bitops.get_bit(sctlr, 27);
472 | msgs.push("NMFI=" + (val ? "non-maskable" : "maskable"));
473 | val = bitops.get_bit(sctlr, 24);
474 | msgs.push("VE=" + val);
475 | val = bitops.get_bit(sctlr, 21);
476 | msgs.push("FI=" + (val ? "all" : "some"));
477 | val = bitops.get_bit(sctlr, 17);
478 | msgs.push("HA=" + (val ? "enabled" : "disabled"));
479 | val = bitops.get_bit(sctlr, 13);
480 | msgs.push("V=" + val);
481 | val = bitops.get_bit(sctlr, 1);
482 | msgs.push("A=" + (val ? "check unaligned" : "NOT check unaligned"));
483 | val = bitops.get_bit(sctlr, 0);
484 | msgs.push("MMU=" + (val ? "enabled" : "disabled"));
485 | display.log("SCTLR: " + msgs.join(", "));
486 | };
487 |
488 | ARMv7_CP15.prototype.dump = function() {
489 | this.dump_reg("CSSELR");
490 | this.dump_reg("TTBCR");
491 | this.dump_reg("SCTLR");
492 | this.dump_reg("TTBR0");
493 | this.dump_reg("TTBR1");
494 | this.dump_reg("DACR");
495 | this.dump_sctlr();
496 | display.log("domains=" + this.domains.toString());
497 | display.log("interrupt vector address=" + this.interrupt_vector_address.toString(16));
498 | };
499 |
500 | ARMv7_CP15.prototype.dump_inst = function(inst) {
501 | var opc1 = bitops.get_bits(inst, 23, 21);
502 | var crn = bitops.get_bits(inst, 19, 16);
503 | var opc2 = bitops.get_bits(inst, 7, 5);
504 | var crm = bitops.get_bits(inst, 3, 0);
505 | var msg = "";
506 | msg += "crn=" + crn.toString(16) + "(" + crn.toString(2) + ")";
507 | msg += ", ";
508 | msg += "opc1=" + opc1.toString(16) + "(" + opc1.toString(2) + ")";
509 | msg += ", ";
510 | msg += "crm=" + crm.toString(16) + "(" + crm.toString(2) + ")";
511 | msg += ", ";
512 | msg += "opc2=" + opc2.toString(16) + "(" + opc2.toString(2) + ")";
513 | logger.log(msg);
514 | };
515 |
516 | ARMv7_CP15.prototype.dump_value = function(value, name) {
517 | this.output_value(display, value, name);
518 | };
519 |
520 | ARMv7_CP15.prototype.log_value = function(value, name) {
521 | if (!this.options.enable_logger)
522 | return;
523 |
524 | this.output_value(logger, value, name);
525 | };
526 |
527 | ARMv7_CP15.prototype.output_value = function(target, value, name) {
528 | if (name)
529 | target.log(name + "=" + value.toString(10) + "\t" + toStringHex32(value) + "(" + toStringBin32(value) + ")");
530 | else
531 | target.log("value=" + value.toString(10) + "\t" + toStringHex32(value) + "(" + toStringBin32(value) + ")");
532 | };
533 |
534 | ARMv7_CP15.prototype.set_memory_abort = function(vaddr, status, is_write) {
535 | this.data["DFAR"] = vaddr;
536 | this.data["IFAR"] = vaddr; // XXX
537 | var dfsr = is_write ? (1 << 11) : 0;
538 | // This bit is for hardware error, so we can ignore it.
539 | //dfsr = bitops.set_bit(dfsr, 10, is_write);
540 | dfsr = dfsr + status;
541 | this.data["DFSR"] = dfsr;
542 | this.data["IFSR"] = dfsr; // XXX
543 | };
544 |
--------------------------------------------------------------------------------