mirror of https://github.com/chyyuu/v8-cpu.git
Add a disk and two related examples
Signed-off-by: Junjie Mao <junjie.mao@enight.me>
This commit is contained in:
parent
7be53f250a
commit
f70dee67dc
|
@ -0,0 +1,50 @@
|
|||
; 7.1 Disk Operation Demo
|
||||
;
|
||||
; This small program loads sector 0 from the disk, place
|
||||
; the data in memory cells whose addresses range from 0x20
|
||||
; to 0x2F, and store the same data to sector 1 on the disk.
|
||||
;
|
||||
; To load a sector from the disk, you should:
|
||||
;
|
||||
; 1) Store to the memory address 0xFF, which is the register
|
||||
; of the disk in V8 architecture, the sector address you
|
||||
; want to load.
|
||||
; 2) Store to 0xFF the memory address where the data should
|
||||
; be stored in.
|
||||
; 3) Store to 0xFF the constant 0, indicating that this is a
|
||||
; LOAD operation.
|
||||
; 4) Load the bit pattern in 0xFF repeatedly until the pattern
|
||||
; is not zero.
|
||||
;
|
||||
; Similar operations should be done to store a sector to the disk.
|
||||
;
|
||||
|
||||
LOADB R0, 0
|
||||
LOADB R1, 1
|
||||
LOADB R2, 0x20
|
||||
|
||||
; Load from sector 0
|
||||
STOREM R0, 0xFF
|
||||
STOREM R2, 0xFF
|
||||
STOREM R0, 0xFF
|
||||
.again_load:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_load
|
||||
|
||||
; Store to sector 1
|
||||
STOREM R1, 0xFF
|
||||
STOREM R2, 0xFF
|
||||
STOREM R1, 0xFF
|
||||
.again_store:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_store
|
||||
|
||||
HALT
|
||||
|
||||
==========
|
||||
; Data in the disk are listed below.
|
||||
|
||||
04 0C 05 0F 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
@ -0,0 +1,166 @@
|
|||
; 7.2 Merge two sequential files
|
||||
;
|
||||
; Organization of the disk
|
||||
;
|
||||
; On the disk, each file is represented by a file allocation
|
||||
; table (FAT). The sector address 0 is used to represent the
|
||||
; end of a file (EOF).
|
||||
;
|
||||
; In this example, there are two files on the disk, namely
|
||||
; file A and file B, whose FATs are located at sector
|
||||
; address 1 and 2 respectively. Each record in these files
|
||||
; uses exactly one sector. The first byte of each record is
|
||||
; the key used for comparison. Given two ordered sequential
|
||||
; files, the following program merges the two files and
|
||||
; create a new file, namely file C, on the disk. The FAT of
|
||||
; file C is located at sector address 3 on the disk.
|
||||
;
|
||||
; Register usage in the program
|
||||
; R0 - For comparison
|
||||
; R1 - The constant 1
|
||||
; Sector address of FAT of file A
|
||||
; The 'write to disk' command
|
||||
; R2 - The constant 2
|
||||
; Sector address of FAT of file B
|
||||
; R3 - Pointer to in-memory FAT of file A
|
||||
; R4 - Pointer to in-memory FAT of file B
|
||||
; R5 - Pointer to in-memory FAT of file C
|
||||
; R6 - Buffer for data in file A
|
||||
; R7 - Buffer for data in file B
|
||||
; R8 - Sector address of current record in file A
|
||||
; R9 - Sector address of current record in file B
|
||||
; RA - Key of current record of file A
|
||||
; RB - Key of current record of file B
|
||||
; RE - Status of the disk
|
||||
|
||||
.entry:
|
||||
LOADB R0, 0
|
||||
LOADB R1, 1
|
||||
LOADB R2, 2
|
||||
LOADB R3, fat_a
|
||||
LOADB R4, fat_b
|
||||
LOADB R5, fat_c
|
||||
LOADB R6, buffer_a
|
||||
LOADB R7, buffer_b
|
||||
|
||||
; load FAT of file A
|
||||
STOREM R1, 0xFF
|
||||
STOREM R3, 0xFF
|
||||
STOREM R0, 0xFF
|
||||
.again_load_fat_a:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_load_fat_a
|
||||
|
||||
; load FAT of file B
|
||||
STOREM R2, 0xFF
|
||||
STOREM R4, 0xFF
|
||||
STOREM R0, 0xFF
|
||||
.again_load_fat_b:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_load_fat_b
|
||||
|
||||
; load the first sector of file A
|
||||
LOADP R8, R3
|
||||
STOREM R8, 0xFF
|
||||
STOREM R6, 0xFF
|
||||
STOREM R0, 0xFF
|
||||
.again_load_sec_a:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_load_sec_a
|
||||
|
||||
; load the first sector of file B
|
||||
LOADP R9, R4
|
||||
STOREM R9, 0xFF
|
||||
STOREM R7, 0xFF
|
||||
STOREM R0, 0xFF
|
||||
.again_load_sec_b:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_load_sec_b
|
||||
|
||||
; begin of the main loop
|
||||
.loop:
|
||||
; have we encounter an EOF (i.e. sector 00)?
|
||||
JUMP R8, .eof_a
|
||||
JUMP R9, .eof_b_1
|
||||
JUMP R0, .compare
|
||||
.eof_b_1:
|
||||
JUMP R0, .insert_record_of_a
|
||||
.eof_a:
|
||||
JUMP R9, .eof_b_2
|
||||
JUMP R0, .insert_record_of_b
|
||||
.eof_b_2:
|
||||
JUMP R0, .exit
|
||||
|
||||
.compare:
|
||||
LOADP RA, R6
|
||||
LOADP RB, R7
|
||||
MOVE R0, RA
|
||||
JUMPL RB, .insert_record_of_b
|
||||
|
||||
.insert_record_of_a:
|
||||
STOREP R8, R5
|
||||
ADDI R5, R5, R1
|
||||
ADDI R3, R3, R1
|
||||
LOADP R8, R3
|
||||
STOREM R8, 0xFF
|
||||
STOREM R6, 0xFF
|
||||
JUMP R0, .load_next
|
||||
|
||||
.insert_record_of_b:
|
||||
STOREP R9, R5
|
||||
ADDI R5, R5, R1
|
||||
ADDI R4, R4, R1
|
||||
LOADP R9, R4
|
||||
STOREM R9, 0xFF
|
||||
STOREM R7, 0xFF
|
||||
|
||||
.load_next:
|
||||
LOADB R0, 0
|
||||
STOREM R0, 0xFF
|
||||
.again_load_next:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_load_next
|
||||
JUMP R0, .loop
|
||||
|
||||
.exit:
|
||||
; store FAT of file C
|
||||
LOADB R2, 3
|
||||
STOREM R2, 0xFF
|
||||
LOADB R5, fat_c
|
||||
STOREM R5, 0xFF
|
||||
STOREM R1, 0xFF
|
||||
.again_write_fat_c:
|
||||
LOADM RE, 0xFF
|
||||
JUMP RE, .again_write_fat_c
|
||||
|
||||
HALT
|
||||
|
||||
fat_a@0xA0:
|
||||
|
||||
fat_b@0xB0:
|
||||
|
||||
fat_c@0xC0:
|
||||
|
||||
buffer_a@0xD0:
|
||||
|
||||
buffer_b@0xE0:
|
||||
|
||||
==========
|
||||
; Data in the disk are listed below.
|
||||
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
06 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
04 0C 05 0F 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
43 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
359
index.html
359
index.html
|
@ -1,190 +1,203 @@
|
|||
<!DOCTYPE html>
|
||||
<html ng-app="ASMSimulator">
|
||||
<head>
|
||||
<head>
|
||||
<title>Simple 8-bit V8-CPU in Javascript</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body ng-controller="Ctrl">
|
||||
</head>
|
||||
<body ng-controller="Ctrl">
|
||||
<nav class="navbar navbar-inverse" role="navigation" style="background-color:#428BCA;border:0px;border-radius:0px;">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-success navbar-btn" ng-click="run()" ng-hide="isRunning"><span class="glyphicon glyphicon-play"></span> Run</button>
|
||||
<button type="button" class="btn btn-default navbar-btn" ng-click="stop()" ng-show="isRunning"><span class="glyphicon glyphicon-stop"></span> Stop</button>
|
||||
<button type="button" class="btn btn-default navbar-btn" ng-click="executeStep()" ng-disabled="isRunning"><span class="glyphicon glyphicon-forward"></span> Step</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default navbar-btn" ng-click="reset()">Reset</button>
|
||||
</div>
|
||||
<div class="navbar-header navbar-right">
|
||||
<a class="navbar-brand" style="color:#FFFFFF">Simple 8-bit V8-CPU</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-success navbar-btn" ng-click="run()" ng-hide="isRunning"><span class="glyphicon glyphicon-play"></span> Run</button>
|
||||
<button type="button" class="btn btn-default navbar-btn" ng-click="stop()" ng-show="isRunning"><span class="glyphicon glyphicon-stop"></span> Stop</button>
|
||||
<button type="button" class="btn btn-default navbar-btn" ng-click="executeStep()" ng-disabled="isRunning"><span class="glyphicon glyphicon-forward"></span> Step</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default navbar-btn" ng-click="reset()">Reset</button>
|
||||
</div>
|
||||
<div class="navbar-header navbar-right">
|
||||
<a class="navbar-brand" style="color:#FFFFFF">Simple 8-bit V8-CPU</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<div class="alert alert-danger" ng-hide="error === ''">{{ error }}</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-7 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Code <small>(<a href="./instruction-set.html" target="_blank" style="color: #337AB7">Instruction Set</a>) (<a href="http://enight.me/files/csao/v8spec.pdf" target="_blank" style="color: #337AB7">Specification</a>)</small></h4>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default" ng-click="compile()">Compile</button>
|
||||
<script>
|
||||
function postcode()
|
||||
{
|
||||
var ta = document.getElementById("sourceCode");
|
||||
$.post('/',{"1":ta.value},function(response){
|
||||
ta.value = response;
|
||||
});
|
||||
}
|
||||
<div class="alert alert-danger" ng-hide="error === ''">{{ error }}</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-7 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Code <small>(<a href="./instruction-set.html" target="_blank" style="color: #337AB7">Instruction Set</a>) (<a href="http://enight.me/files/csao/v8spec.pdf" target="_blank" style="color: #337AB7">Specification</a>)</small></h4>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default" ng-click="compile()">Compile</button>
|
||||
<script>
|
||||
function postcode()
|
||||
{
|
||||
var ta = document.getElementById("sourceCode");
|
||||
$.post('/',{"1":ta.value},function(response){
|
||||
ta.value = response;
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<button type="button" class="btn btn-default" ng-click="assemble()">Assemble</button>
|
||||
<button type="button" class="btn btn-default" ng-click="upload()">Upload</button>
|
||||
Examples:
|
||||
<select ng-model="example" ng-options="item.id as item.desc for item in examples" ng-change="showExample(example)" ng-init="initExamples()"></select>
|
||||
<!-- <select id="examples" ng-change="showExample(x)" ng-model="x"> -->
|
||||
<!-- <option value="haha">haha</option> -->
|
||||
<!-- <option value="hoho">hoho</option> -->
|
||||
<!-- </select> -->
|
||||
<form role="form">
|
||||
<textarea id="sourceCode"
|
||||
class="form-control source-code"
|
||||
style="margin-bottom:5px;"
|
||||
rows="30"
|
||||
tab-support
|
||||
select-line
|
||||
ng-model="code"></textarea>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix visible-xs visible-sm"></div>
|
||||
<div class="col-lg-5 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Printer</h4>
|
||||
</div>
|
||||
<div class="panel-body source-code">{{ printer.data }}</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">CPU & Memory</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">General Registers</p>
|
||||
<table class="table table-condensed table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">0</th>
|
||||
<th style="text-align:center">1</th>
|
||||
<th style="text-align:center">2</th>
|
||||
<th style="text-align:center">3</th>
|
||||
<th style="text-align:center">4</th>
|
||||
<th style="text-align:center">5</th>
|
||||
<th style="text-align:center">6</th>
|
||||
<th style="text-align:center">7</th>
|
||||
<th style="text-align:center">8</th>
|
||||
<th style="text-align:center">9</th>
|
||||
<th style="text-align:center">A</th>
|
||||
<th style="text-align:center">B</th>
|
||||
<th style="text-align:center">C</th>
|
||||
<th style="text-align:center">D</th>
|
||||
<th style="text-align:center">E</th>
|
||||
<th style="text-align:center">F</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="text-align:center;" class="source-code">
|
||||
<td><div style="margin:auto;" ng-class="displayA && 'marker marker-a'"><small>{{ cpu.gpr[0] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayB && 'marker marker-b'"><small>{{ cpu.gpr[1] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayC && 'marker marker-c'"><small>{{ cpu.gpr[2] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[3] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[4] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[5] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[6] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[7] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[8] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[9] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[10] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[11] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[12] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[13] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[14] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[15] | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="text-muted">Other Registers</p>
|
||||
<table class="table table-condensed table-striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">Program counter <font color="E81F1F">{{ cpu.status }}</font> </td>
|
||||
<td style="text-align:center;" class="source-code"><div style="margin:auto;" class="marker marker-ip"><small>{{ cpu.ip | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Instruction register</td>
|
||||
<td style="text-align:center;" class="source-code"><div style="margin:auto;"><small>{{ cpu.ir | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Timer countdown</td>
|
||||
<td style="text-align:center;" class="source-code"><div style="margin:auto;"><small>{{ cpu.countdown | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="text-muted">RAM</p>
|
||||
<div style="width:29em;" class="source-code">
|
||||
<div class="memory-block"
|
||||
ng-repeat="m in memory.data track by $index"
|
||||
ng-class="getMemoryCellCss($index)">
|
||||
<div ng-class="getMemoryInnerCellCss($index)" ng-switch="isInstruction($index)">
|
||||
<small ng-switch-default>{{ m | number:displayHex }}</small>
|
||||
<a ng-switch-when="true" ng-click="jumpToLine($index)">
|
||||
<small>{{ m | number:displayHex }}</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin-top:5px;">
|
||||
<small>
|
||||
<span>Clock speed:</span>
|
||||
<select ng-model="speed" ng-options="item.speed as item.desc for item in speeds"></select>
|
||||
<span style="margin-left:5px;">Instructions:</span>
|
||||
<a ng-click="displayInstr = true" ng-hide="displayInstr">Show</a>
|
||||
<a ng-click="displayInstr = false" ng-show="displayInstr">Hide</a>
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Labels</h4>
|
||||
</div>
|
||||
<div class="panel-body source-code">
|
||||
<table class="table table-condensed table-striped codelabels">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Address</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<tr ng-repeat="(name, value) in labels" class="codelabel">
|
||||
<td class="codelabel-name">{{ name }}</td>
|
||||
<td class="codelabel-line"><a ng-click="jumpToLine(value)">{{ value | number:displayHex }}</a></td>
|
||||
<td class="codelabel-value">{{ memory.data[value] | number:displayHex }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<button type="button" class="btn btn-default" ng-click="assemble()">Assemble</button>
|
||||
<button type="button" class="btn btn-default" ng-click="upload()">Upload</button>
|
||||
Examples:
|
||||
<select ng-model="example" ng-options="item.id as item.desc for item in examples" ng-change="showExample(example)" ng-init="initExamples()"></select>
|
||||
<!-- <select id="examples" ng-change="showExample(x)" ng-model="x"> -->
|
||||
<!-- <option value="haha">haha</option> -->
|
||||
<!-- <option value="hoho">hoho</option> -->
|
||||
<!-- </select> -->
|
||||
<form role="form">
|
||||
<textarea id="sourceCode"
|
||||
class="form-control source-code"
|
||||
style="margin-bottom:5px;"
|
||||
rows="30"
|
||||
tab-support
|
||||
select-line
|
||||
ng-model="code"></textarea>
|
||||
</form>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Labels</h4>
|
||||
</div>
|
||||
<div class="panel-body source-code">
|
||||
<table class="table table-condensed table-striped codelabels">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Address</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<tr ng-repeat="(name, value) in labels" class="codelabel">
|
||||
<td class="codelabel-name">{{ name }}</td>
|
||||
<td class="codelabel-line"><a ng-click="jumpToLine(value)">{{ value | number:displayHex }}</a></td>
|
||||
<td class="codelabel-value">{{ memory.data[value] | number:displayHex }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr style="margin-top:10px;margin-bottom:10px;"/>
|
||||
<p><small>by Yuanchun Shi, Yu Chen, Junjie Mao, Yukang Yan (2015) | MIT License | <a href="https://www.github.com/chyyuu/v8-cpu" target="_blank">Source Code</a></small></p>
|
||||
<p><small>by Marco Schweighauser (2015) | MIT License | <a href="https://www.mschweighauser.com/make-your-own-assembler-simulator-in-javascript-part1/" target="_blank">Blog</a></small></p>
|
||||
<div class="clearfix visible-xs visible-sm"></div>
|
||||
<div class="col-lg-5 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">CPU & Memory</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="text-muted">General Registers</p>
|
||||
<table class="table table-condensed table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">0</th>
|
||||
<th style="text-align:center">1</th>
|
||||
<th style="text-align:center">2</th>
|
||||
<th style="text-align:center">3</th>
|
||||
<th style="text-align:center">4</th>
|
||||
<th style="text-align:center">5</th>
|
||||
<th style="text-align:center">6</th>
|
||||
<th style="text-align:center">7</th>
|
||||
<th style="text-align:center">8</th>
|
||||
<th style="text-align:center">9</th>
|
||||
<th style="text-align:center">A</th>
|
||||
<th style="text-align:center">B</th>
|
||||
<th style="text-align:center">C</th>
|
||||
<th style="text-align:center">D</th>
|
||||
<th style="text-align:center">E</th>
|
||||
<th style="text-align:center">F</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="text-align:center;" class="source-code">
|
||||
<td><div style="margin:auto;" ng-class="displayA && 'marker marker-a'"><small>{{ cpu.gpr[0] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayB && 'marker marker-b'"><small>{{ cpu.gpr[1] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayC && 'marker marker-c'"><small>{{ cpu.gpr[2] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[3] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[4] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[5] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[6] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[7] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[8] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[9] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[10] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[11] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[12] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[13] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[14] | number:displayHex }}</small></div></td>
|
||||
<td><div style="margin:auto;" ng-class="displayD && 'marker marker-d'"><small>{{ cpu.gpr[15] | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="text-muted">Other Registers</p>
|
||||
<table class="table table-condensed table-striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">Program counter <font color="E81F1F">{{ cpu.status }}</font> </td>
|
||||
<td style="text-align:center;" class="source-code"><div style="margin:auto;" class="marker marker-ip"><small>{{ cpu.ip | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Instruction register</td>
|
||||
<td style="text-align:center;" class="source-code"><div style="margin:auto;"><small>{{ cpu.ir | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Timer countdown</td>
|
||||
<td style="text-align:center;" class="source-code"><div style="margin:auto;"><small>{{ cpu.countdown | number:displayHex }}</small></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="text-muted">RAM</p>
|
||||
<div style="width:29em;" class="source-code">
|
||||
<div class="memory-block"
|
||||
ng-repeat="m in memory.data track by $index"
|
||||
ng-class="getMemoryCellCss($index)">
|
||||
<div ng-class="getMemoryInnerCellCss($index)" ng-switch="isInstruction($index)">
|
||||
<small ng-switch-default>{{ m | number:displayHex }}</small>
|
||||
<a ng-switch-when="true" ng-click="jumpToLine($index)">
|
||||
<small>{{ m | number:displayHex }}</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin-top:5px;">
|
||||
<small>
|
||||
<span>Clock speed:</span>
|
||||
<select ng-model="speed" ng-options="item.speed as item.desc for item in speeds"></select>
|
||||
<span style="margin-left:5px;">Instructions:</span>
|
||||
<a ng-click="displayInstr = true" ng-hide="displayInstr">Show</a>
|
||||
<a ng-click="displayInstr = false" ng-show="displayInstr">Hide</a>
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Printer</h4>
|
||||
</div>
|
||||
<div class="panel-body source-code">{{ printer.data }}</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Disk</h4>
|
||||
</div>
|
||||
<div style="width:29em;" class="source-code">
|
||||
<div class="memory-block"
|
||||
ng-repeat="m in memory.diskdata track by $index">
|
||||
<div ng-switch="false">
|
||||
<small ng-switch-default>{{ m | number:displayHex }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr style="margin-top:10px;margin-bottom:10px;"/>
|
||||
<p><small>by Yuanchun Shi, Yu Chen, Junjie Mao, Yukang Yan (2015) | MIT License | <a href="https://www.github.com/chyyuu/v8-cpu" target="_blank">Source Code</a></small></p>
|
||||
<p><small>by Marco Schweighauser (2015) | MIT License | <a href="https://www.mschweighauser.com/make-your-own-assembler-simulator-in-javascript-part1/" target="_blank">Blog</a></small></p>
|
||||
</div>
|
||||
<script src="node_modules/angular/angular.min.js"></script>
|
||||
<script src="assets/asmsimulator.min.js"></script>
|
||||
<script src="assets/asmsimulator.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
|
||||
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,6 +3,8 @@ app.service('uploader', ['opcodes', function (opcodes) {
|
|||
go: function (input) {
|
||||
// Contains the program code & data generated by the assembler
|
||||
var code = [];
|
||||
// Contains data on disk
|
||||
var disk = [];
|
||||
// Contains the mapping from instructions to assembler line
|
||||
var mapping = {};
|
||||
// Hash map of label used to replace the labels after the assembler generated the code
|
||||
|
@ -23,13 +25,13 @@ app.service('uploader', ['opcodes', function (opcodes) {
|
|||
for (var k = 1; k < codes[j].length; k += 2) {
|
||||
var codevalue = parseInt(codes[j].slice(k - 1, k + 1), 16);
|
||||
if (codevalue < 0 || codevalue > 255) {
|
||||
throw "code must be a value between 0...255";
|
||||
throw {error: "code must be a value between 0...255"};
|
||||
}
|
||||
code.push(codevalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {code: code, mapping: mapping, labels: labels};
|
||||
return {code: code, disk: disk, mapping: mapping, labels: labels};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
@ -54,6 +56,8 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
var regexLabel = /^([.A-Za-z_]\w*)((\+|-)\d+)?$/;
|
||||
// Contains the program code & data generated by the assembler
|
||||
var memory = [];
|
||||
// Contains data on disk
|
||||
var disk = [];
|
||||
// The address where the next instruction/data will be placed at
|
||||
var current = 0;
|
||||
// Contains the mapping from instructions to assembler line
|
||||
|
@ -63,6 +67,8 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
// Hash of uppercase labels used to detect duplicates
|
||||
var normalizedLabels = {};
|
||||
|
||||
var diskpart = false;
|
||||
|
||||
// Split text into code lines
|
||||
var lines = input.split('\n');
|
||||
|
||||
|
@ -173,6 +179,26 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
};
|
||||
|
||||
for (var i = 0, l = lines.length; i < l; i++) {
|
||||
var line = lines[i].trim();
|
||||
|
||||
// Comments are not parsed
|
||||
if (line === "" || line.slice(0, 1) == ";")
|
||||
continue;
|
||||
|
||||
// Fastpath: if the line contains data in disk, simply parse them as a sequence of hex numbers
|
||||
if (diskpart) {
|
||||
var bytes = line.split(' ');
|
||||
for (var j = 0, codenum = bytes.length; j < codenum; j++) {
|
||||
if (bytes[j] === '')
|
||||
continue;
|
||||
disk.push(parseInt(bytes[j], 16) % 256);
|
||||
}
|
||||
continue;
|
||||
} else if (line === "==========") {
|
||||
diskpart = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
var match = regex.exec(lines[i]);
|
||||
if (match[1] !== undefined || match[3] !== undefined) {
|
||||
|
@ -339,11 +365,7 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// Check if line starts with a comment otherwise the line contains an error and can not be parsed
|
||||
var line = lines[i].trim();
|
||||
if (line !== "" && line.slice(0, 1) !== ";") {
|
||||
throw "Syntax error";
|
||||
}
|
||||
throw "Syntax error";
|
||||
}
|
||||
} catch (e) {
|
||||
throw {error: e, line: i};
|
||||
|
@ -362,7 +384,7 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
}
|
||||
}
|
||||
|
||||
return {code: memory, mapping: mapping, labels: labels};
|
||||
return {code: memory, disk: disk, mapping: mapping, labels: labels};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
|
|
@ -2,6 +2,14 @@ app.service('memory', ['printer', function (printer) {
|
|||
var memory = {
|
||||
data: Array(256),
|
||||
lastAccess: -1,
|
||||
diskdata: Array(256),
|
||||
statusnow: 0,
|
||||
sector_address: 0,
|
||||
memory_address: 0,
|
||||
disk_operation: 0,
|
||||
disk_latency: 0,
|
||||
sectorlength: 16,
|
||||
|
||||
load: function (address) {
|
||||
var self = this;
|
||||
|
||||
|
@ -13,6 +21,22 @@ app.service('memory', ['printer', function (printer) {
|
|||
|
||||
if (address == 0xFE) {
|
||||
return printer.load();
|
||||
} else if (address == 0xFF) {
|
||||
if (self.disk_latency > 0) {
|
||||
self.disk_latency = self.disk_latency - 1;
|
||||
return 0;
|
||||
}
|
||||
if (self.disk_operation === 0x00) {
|
||||
for(var i = 0; i < self.sectorlength; i++)
|
||||
self.data[self.memory_address + i] = self.diskdata[self.sector_address * self.sectorlength + i];
|
||||
} else if (self.disk_operation === 0x01) {
|
||||
for(var j = 0; j < self.sectorlength; j++)
|
||||
self.diskdata[self.sector_address * self.sectorlength + j] = self.data[self.memory_address + j];
|
||||
}
|
||||
self.statusnow = 0;
|
||||
self.sector_address = 0;
|
||||
self.memory_address = 0;
|
||||
return 0xFF;
|
||||
}
|
||||
return self.data[address];
|
||||
},
|
||||
|
@ -28,15 +52,39 @@ app.service('memory', ['printer', function (printer) {
|
|||
if (address == 0xFE) {
|
||||
return printer.store(value);
|
||||
}
|
||||
if (address == 0xFF)
|
||||
{
|
||||
if (self.statusnow === 0)
|
||||
{
|
||||
self.statusnow = 1;
|
||||
self.sector_address = value;
|
||||
} else if (self.statusnow === 1) {
|
||||
self.statusnow = 2;
|
||||
self.memory_address = value;
|
||||
} else if(self.statusnow === 2) {
|
||||
self.disk_operation = value;
|
||||
self.disk_latency = 3;
|
||||
}
|
||||
return;
|
||||
}
|
||||
self.data[address] = value;
|
||||
},
|
||||
reset: function () {
|
||||
var self = this;
|
||||
|
||||
self.lastAccess = -1;
|
||||
self.statusnow = 0;
|
||||
self.sector_address = 0;
|
||||
self.memory_address = 0;
|
||||
self.disk_operation = 0;
|
||||
self.disk_latency = 0;
|
||||
for (var i = 0, l = self.data.length; i < l; i++) {
|
||||
self.data[i] = 0;
|
||||
}
|
||||
for(i = 0;i < self.diskdata.length;i++)
|
||||
{
|
||||
self.diskdata[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -97,15 +97,23 @@ app.controller('Ctrl', ['$document', '$scope', '$timeout', '$http', 'cpu', 'memo
|
|||
var assembly = assembler.go($scope.code);
|
||||
$scope.mapping = assembly.mapping;
|
||||
var binary = assembly.code;
|
||||
var disk = assembly.disk;
|
||||
$scope.labels = assembly.labels;
|
||||
|
||||
if (binary.length > memory.data.length)
|
||||
throw "Binary code does not fit into the memory. Max " + memory.data.length + " bytes are allowed";
|
||||
throw {error: "Binary code does not fit into the memory. Max " + memory.data.length + " bytes are allowed"};
|
||||
|
||||
if (disk.length > memory.diskdata.length)
|
||||
throw {error: "Disk data does not fit into the disk. Max " + memory.diskdata.length + " bytes are allowed"};
|
||||
|
||||
for (var i = 0, l = binary.length; i < l; i++) {
|
||||
memory.data[i] = binary[i];
|
||||
}
|
||||
|
||||
for (i = 0, l = disk.length; i < l; i++) {
|
||||
memory.diskdata[i] = disk[i];
|
||||
}
|
||||
|
||||
if ($scope.labels['.entry'] !== undefined) {
|
||||
cpu.ip = $scope.labels['.entry'];
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
app.filter('number', function() {
|
||||
return function(input, isHex) {
|
||||
if (input === 0 || input === undefined)
|
||||
return "00";
|
||||
if (isHex) {
|
||||
var hex = input.toString(16).toUpperCase();
|
||||
return hex.length == 1 ? "0" + hex: hex;
|
||||
|
|
Loading…
Reference in New Issue