├── 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 |
299 |
300 |
301 |
302 |
303 | 304 |
    305 |
  • 306 |
307 |
308 |
309 | 310 |
    311 |
  • 312 |
  • 313 |
  • 314 |
  • 315 |
  • 316 |
  • 317 |
318 |
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 |
345 |
346 | 347 | 348 | 349 |
    350 |
  • 351 |
  • 352 |
  • 353 | )
  • 354 |
  • 355 |
  • 356 |
357 |
358 |
359 | 360 | 361 | 362 |
    363 |
  • 364 |
  • 365 |
366 |
367 |
368 | 369 | 370 | 371 |
    372 |
  • 373 |
  • 374 |
  • 375 |
376 |
377 |
378 | 379 | 380 | 381 |
    382 |
  • 383 |
  • 384 |
385 |
386 |
387 | 388 | 389 | 390 |
    391 |
  • 392 |
  • 393 |
394 |
395 | 396 |
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 | --------------------------------------------------------------------------------