Add a disk and two related examples

Signed-off-by: Junjie Mao <junjie.mao@enight.me>
This commit is contained in:
Junjie Mao 2015-12-01 17:00:21 +08:00
parent 7be53f250a
commit f70dee67dc
7 changed files with 491 additions and 182 deletions

50
examples/71-simple.txt Normal file
View File

@ -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

166
examples/72-seq-merge.txt Normal file
View File

@ -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

View File

@ -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>

View File

@ -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};
}
};
}]);

View File

@ -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;
}
}
};

View File

@ -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'];
}

View File

@ -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;