mirror of https://github.com/chyyuu/v8-cpu.git
Bugfixes and more examples
Signed-off-by: Junjie Mao <junjie.mao@enight.me>
This commit is contained in:
parent
05cb80c0b1
commit
fedc22763e
|
@ -1,4 +1,4 @@
|
|||
; c = a + b
|
||||
; 2.1 c = a + b
|
||||
|
||||
.data@0x6C:
|
||||
DB 0x01
|
|
@ -1 +1,90 @@
|
|||
; TODO Time-sharing between two processes
|
||||
; 3.1 Time-sharing Between Two Processes
|
||||
|
||||
.programA@0x00:
|
||||
LOADB R0, 0x00
|
||||
LOADB R1, 0x00
|
||||
LOADB R2, 0x01
|
||||
loop_a:
|
||||
ADDI R0, R0, R1
|
||||
ADDI R1, R1, R2
|
||||
JUMP R0, loop_a
|
||||
|
||||
.programB@0x40:
|
||||
LOADB R0, 0x00
|
||||
LOADB R1, 0x00
|
||||
LOADB R2, 0x58
|
||||
loop_b:
|
||||
ADDF R0, R0, R1
|
||||
ADDF R1, R1, R2
|
||||
JUMP R0, loop_b
|
||||
|
||||
interrupt_handler@0x80:
|
||||
STOREM R0, tmp2
|
||||
LOADM R0, saved_regs
|
||||
STOREM R0, tmp1
|
||||
LOADM R0, tmp2
|
||||
STOREM R0, saved_regs
|
||||
|
||||
LOADM R0, saved_pc
|
||||
STOREM R0, jmp+1
|
||||
|
||||
LOADM R0, interrupted_pc
|
||||
STOREM R0, saved_pc
|
||||
|
||||
MOVE R0, R1
|
||||
LOADM R1, saved_regs+1
|
||||
STOREM R0, saved_regs+1
|
||||
MOVE R0, R2
|
||||
LOADM R2, saved_regs+2
|
||||
STOREM R0, saved_regs+2
|
||||
MOVE R0, R3
|
||||
LOADM R3, saved_regs+3
|
||||
STOREM R0, saved_regs+3
|
||||
MOVE R0, R4
|
||||
LOADM R4, saved_regs+4
|
||||
STOREM R0, saved_regs+4
|
||||
MOVE R0, R5
|
||||
LOADM R5, saved_regs+5
|
||||
STOREM R0, saved_regs+5
|
||||
MOVE R0, R6
|
||||
LOADM R6, saved_regs+6
|
||||
STOREM R0, saved_regs+6
|
||||
MOVE R0, R7
|
||||
LOADM R7, saved_regs+7
|
||||
STOREM R0, saved_regs+7
|
||||
MOVE R0, R8
|
||||
LOADM R8, saved_regs+8
|
||||
STOREM R0, saved_regs+8
|
||||
MOVE R0, R9
|
||||
LOADM R9, saved_regs+9
|
||||
STOREM R0, saved_regs+9
|
||||
MOVE R0, RA
|
||||
LOADM RA, saved_regs+10
|
||||
STOREM R0, saved_regs+10
|
||||
MOVE R0, RB
|
||||
LOADM RB, saved_regs+11
|
||||
STOREM R0, saved_regs+11
|
||||
MOVE R0, RC
|
||||
LOADM RC, saved_regs+12
|
||||
STOREM R0, saved_regs+12
|
||||
MOVE R0, RD
|
||||
LOADM RD, saved_regs+13
|
||||
STOREM R0, saved_regs+13
|
||||
MOVE R0, RE
|
||||
LOADM RE, saved_regs+14
|
||||
STOREM R0, saved_regs+14
|
||||
|
||||
LOADM R0, tmp1
|
||||
jmp: JUMP R0, 00
|
||||
|
||||
saved_regs@0xEA:
|
||||
saved_pc@0xF9:
|
||||
tmp1@0xFA:
|
||||
tmp2@0xFB:
|
||||
interrupted_pc@0xFD:
|
||||
|
||||
.entry@0xF0:
|
||||
LOADB RF, 0x80
|
||||
LOADB R0, 0x40
|
||||
STOREM R0, saved_pc
|
||||
JUMP R0, 0x00
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
; 5.1 Insertion Sort
|
||||
;
|
||||
; The list of numbers to be sorted is stored from .data
|
||||
|
||||
.entry:
|
||||
;; Initialize some constants:
|
||||
LOADB R1, 0x01
|
||||
LOADB R2, 0xFF
|
||||
|
||||
LOADB R3, .data+1 ;; loop variable of the outer loop
|
||||
outer_loop:
|
||||
LOADB R0, .data_end
|
||||
JUMP R3, outer_loop_end
|
||||
LOADP R4, R3 ;; the pivot
|
||||
|
||||
MOVE R5, R3 ;; loop variable of the outer loop
|
||||
inner_loop:
|
||||
LOADB R0, .data
|
||||
JUMP R5, inner_loop_end
|
||||
MOVE R6, R5
|
||||
ADDI R5, R5, R2
|
||||
LOADP R0, R5
|
||||
JUMPL R4, tmp1
|
||||
ADDI R5, R5, R1
|
||||
JUMP R0, inner_loop_end
|
||||
tmp1: STOREP R0, R6
|
||||
JUMP R0, inner_loop
|
||||
|
||||
inner_loop_end:
|
||||
STOREP R4, R5
|
||||
ADDI R3, R3, R1
|
||||
JUMP R0, outer_loop
|
||||
|
||||
outer_loop_end:
|
||||
HALT
|
||||
|
||||
.data@0x40:
|
||||
DB 0x20
|
||||
DB 0x34
|
||||
DB 0xDE
|
||||
DB 0x65
|
||||
DB 0xAA
|
||||
DB 0xC0
|
||||
DB 0x00
|
||||
DB 0xF1
|
||||
.data_end:
|
|
@ -0,0 +1,147 @@
|
|||
; 5.2 Binary Search
|
||||
;
|
||||
; This example implements the following function:
|
||||
;
|
||||
; int list[];
|
||||
; int binary_search(int begin, int end, int target) {
|
||||
; if (end < begin)
|
||||
; return -1;
|
||||
; int mid = begin + (end - begin) / 2;
|
||||
; int mid_val = list[mid];
|
||||
; if (target == mid_val)
|
||||
; return mid;
|
||||
; else if (target < mid_val)
|
||||
; return binary_search(begin, mid - 1, target);
|
||||
; else
|
||||
; return binary_search(mid + 1, end, target);
|
||||
; }
|
||||
;
|
||||
; which will search for 'target' in the range [begin, end]
|
||||
; of the global list. The function returns the index of the
|
||||
; element if 'target' is found in the list. Otherwise it
|
||||
; returns -1.
|
||||
|
||||
|
||||
.entry:
|
||||
;; initialize some constants
|
||||
LOADB R1, 0x01
|
||||
LOADB R2, 0xFF
|
||||
;; initialize the stack
|
||||
LOADB RE, .stack
|
||||
|
||||
ADDI RE, RE, R2
|
||||
;; 3rd parameter 'target' = 0x34
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, 0x34
|
||||
STOREP R3, RE
|
||||
;; 2nd parameter 'end' = .data_end - .data - 1
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, .data
|
||||
XOR R3, R3, R2
|
||||
LOADB R4, .data_end
|
||||
ADDI R3, R3, R4
|
||||
STOREP R3, RE
|
||||
;; 1st parameter 'begin' = 0
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, 0x00
|
||||
STOREP R3, RE
|
||||
;; return address
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, tmp1
|
||||
STOREP R3, RE
|
||||
JUMP R0, binary_search
|
||||
tmp1: LOADB R3, 0x04
|
||||
ADDI RE, RE, R3
|
||||
LOADP R0, RE
|
||||
ADDI RE, RE, R1
|
||||
HALT
|
||||
|
||||
binary_search:
|
||||
ADDI R3, RE, R1
|
||||
LOADP RA, R3 ; 1st argument 'begin'
|
||||
ADDI R3, R3, R1
|
||||
LOADP RB, R3 ; 2nd argument 'end'
|
||||
ADDI R3, R3, R1
|
||||
LOADP RC, R3 ; 3rd argument 'target'
|
||||
LOADB RD, 0xFF ; RD has value to be returned
|
||||
|
||||
;; if (end < begin)
|
||||
;; return -1;
|
||||
MOVE R0, RA
|
||||
JUMPL RB, end
|
||||
|
||||
;; int mid = begin + (end - begin) / 2;
|
||||
XOR R4, RA, R2
|
||||
ADDI R4, R4, R1
|
||||
ADDI R4, R4, RB
|
||||
LOADB R3, 0xFE
|
||||
AND R4, R4, R3
|
||||
ROT R4, 1
|
||||
ADDI R4, R4, RA
|
||||
|
||||
;; int mid_val = list[middle];
|
||||
LOADB R5, .data
|
||||
ADDI R5, R5, R4
|
||||
LOADP R5, R5
|
||||
|
||||
MOVE R0, R5
|
||||
JUMP RC, equal
|
||||
JUMPL RC, target_less_than_mid
|
||||
JUMP R0, target_greater_than_mid
|
||||
|
||||
equal:
|
||||
;; if (target == mid_val)
|
||||
;; return mid;
|
||||
MOVE RD, R4
|
||||
JUMP R0, end
|
||||
|
||||
target_less_than_mid:
|
||||
;; else if (target < mid_val)
|
||||
;; return binary_search(begin, mid - 1, target);
|
||||
MOVE R8, RA
|
||||
MOVE R9, R4
|
||||
ADDI R9, R9, R2
|
||||
JUMP R0, recursive_call
|
||||
|
||||
target_greater_than_mid:
|
||||
;; else
|
||||
;; return binary_search(mid + 1, end, target);
|
||||
MOVE R8, R4
|
||||
ADDI R8, R8, R1
|
||||
MOVE R9, RB
|
||||
|
||||
recursive_call:
|
||||
ADDI RE, RE, R2
|
||||
ADDI RE, RE, R2
|
||||
STOREP RC, RE
|
||||
ADDI RE, RE, R2
|
||||
STOREP R9, RE
|
||||
ADDI RE, RE, R2
|
||||
STOREP R8, RE
|
||||
ADDI RE, RE, R2
|
||||
LOADB R4, tmp2
|
||||
STOREP R4, RE
|
||||
JUMP R0, binary_search
|
||||
tmp2: LOADB R4, 0x04
|
||||
ADDI RE, RE, R4
|
||||
LOADP RD, RE
|
||||
ADDI RE, RE, R1
|
||||
end:
|
||||
LOADB R3, 0x04
|
||||
ADDI R3, RE, R3
|
||||
STOREP RD, R3
|
||||
LOADP R3, RE
|
||||
STOREM R3, ret+1
|
||||
ret: JUMP R0, 0x00
|
||||
|
||||
.data@0xA0:
|
||||
DB 0xAA
|
||||
DB 0xC0
|
||||
DB 0xDE
|
||||
DB 0xF1
|
||||
DB 0x00
|
||||
DB 0x20
|
||||
DB 0x34
|
||||
DB 0x65
|
||||
.data_end:
|
||||
.stack@0xF8:
|
|
@ -0,0 +1,64 @@
|
|||
; 6.1 Passing Parameters by Value
|
||||
;
|
||||
; The corresponding C code looks like this:
|
||||
;
|
||||
; int a = 0xDE, b = 0xFA;
|
||||
; int swap (int a, int b) {
|
||||
; int c = a;
|
||||
; a = b;
|
||||
; b = c;
|
||||
; return (a + b);
|
||||
; }
|
||||
; main() {
|
||||
; swap(a, b);
|
||||
; }
|
||||
|
||||
.entry:
|
||||
;; initialize some constants
|
||||
LOADB R1, 0x01
|
||||
LOADB R2, 0xFF
|
||||
;; initialize the stack
|
||||
LOADB RE, .stack
|
||||
;; push a slot for the return value
|
||||
ADDI RE, RE, R2
|
||||
;; push the second parameter
|
||||
ADDI RE, RE, R2
|
||||
LOADM R3, .data+1
|
||||
STOREP R3, RE
|
||||
;; push the first parameter
|
||||
ADDI RE, RE, R2
|
||||
LOADM R3, .data
|
||||
STOREP R3, RE
|
||||
;; push the return address
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, next
|
||||
STOREP R3, RE
|
||||
JUMP R0, swap
|
||||
next: LOADB R4, 0x04
|
||||
ADDI RE, RE, R4
|
||||
HALT
|
||||
|
||||
swap@0x40:
|
||||
ADDI R8, RE, R1
|
||||
LOADP RA, R8 ; the first parameter
|
||||
ADDI R8, R8, R1
|
||||
LOADP RB, R8 ; the second parameter
|
||||
;; int c = a;
|
||||
MOVE RC, RA
|
||||
;; a = b;
|
||||
MOVE RA, RB
|
||||
;; b = c;
|
||||
MOVE RB, RC
|
||||
;; return (a + b);
|
||||
ADDI RD, RA, RB
|
||||
ADDI R8, R8, R1
|
||||
STOREP RD, R8
|
||||
LOADP R8, RE
|
||||
STOREM R8, ret+1
|
||||
ret: JUMP R0, 00
|
||||
|
||||
|
||||
.stack@0x80:
|
||||
.data@0x80:
|
||||
DB 0xDE
|
||||
DB 0xFA
|
|
@ -0,0 +1,66 @@
|
|||
; 6.2 Passing Parameters by Reference
|
||||
;
|
||||
; The corresponding C code looks like this:
|
||||
;
|
||||
; int a = 0xDE, b = 0xFA;
|
||||
; int swap (int *a, int *b) {
|
||||
; int c = *a;
|
||||
; *a = *b;
|
||||
; *b = c;
|
||||
; return (*a + *b);
|
||||
; }
|
||||
; main() {
|
||||
; swap(&a, &b);
|
||||
; }
|
||||
|
||||
.entry:
|
||||
;; initialize some constants
|
||||
LOADB R1, 0x01
|
||||
LOADB R2, 0xFF
|
||||
;; initialize the stack
|
||||
LOADB RE, .stack
|
||||
;; push a slot for the return value
|
||||
ADDI RE, RE, R2
|
||||
;; push the second parameter
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, .data+1
|
||||
STOREP R3, RE
|
||||
;; push the first parameter
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, .data
|
||||
STOREP R3, RE
|
||||
;; push the return address
|
||||
ADDI RE, RE, R2
|
||||
LOADB R3, next
|
||||
STOREP R3, RE
|
||||
JUMP R0, swap
|
||||
next: LOADB R4, 0x04
|
||||
ADDI RE, RE, R4
|
||||
HALT
|
||||
|
||||
swap@0x40:
|
||||
ADDI R8, RE, R1
|
||||
LOADP RA, R8 ; the first parameter
|
||||
ADDI R8, R8, R1
|
||||
LOADP RB, R8 ; the second parameter
|
||||
;; int c = *a;
|
||||
LOADP RC, RA
|
||||
;; *a = *b;
|
||||
LOADP RD, RB
|
||||
STOREP RD, RA
|
||||
;; *b = c;
|
||||
STOREP RC, RB
|
||||
;; return (*a + *b);
|
||||
LOADP RC, RA
|
||||
LOADP RD, RB
|
||||
ADDI RD, RC, RD
|
||||
ADDI R8, R8, R1
|
||||
STOREP RD, R8
|
||||
LOADP R8, RE
|
||||
STOREM R8, ret+1
|
||||
ret: JUMP R0, 00
|
||||
|
||||
.stack@0x80:
|
||||
.data@0x80:
|
||||
DB 0xDE
|
||||
DB 0xFA
|
|
@ -136,9 +136,9 @@
|
|||
<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>
|
||||
<span style="margin-left:5px;">View:</span>
|
||||
<a ng-click="displayHex = true" ng-hide="displayHex">Hex</a>
|
||||
<a ng-click="displayHex = false" ng-show="displayHex">Decimal</a>
|
||||
<!-- <span style="margin-left:5px;">View:</span> -->
|
||||
<!-- <a ng-click="displayHex = true" ng-hide="displayHex">Hex</a> -->
|
||||
<!-- <a ng-click="displayHex = false" ng-show="displayHex">Decimal</a> -->
|
||||
<!-- <br> -->
|
||||
<!-- Register addressing: -->
|
||||
<!-- <span style="margin-left:5px;">A:</span> -->
|
||||
|
|
|
@ -27,10 +27,7 @@
|
|||
<p>Valid number formats for constants are:</p>
|
||||
<pre>
|
||||
Decimal: 200
|
||||
Decimal: 200d
|
||||
Hex: 0xA4
|
||||
Octal: 0o48
|
||||
Binary: 101b
|
||||
</pre>
|
||||
<p>It is possible to define a number using a character or multiple numbers (see instruction <i>DB</i>) by using a string.</p>
|
||||
<pre>
|
||||
|
|
|
@ -30,22 +30,18 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
// Use https://www.debuggex.com/
|
||||
// Matches: "label: INSTRUCTION OPERAND1, OPERAND2, OPERAND3
|
||||
// GROUPS: 1 3 4 7 10
|
||||
//var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,4})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?/;
|
||||
//var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,6})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?)?/;
|
||||
//var regex = /^[\t ]*(?:([.A-Za-z]\w*)[:])?(?:[\t ]*([A-Za-z]{2,6})(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]*[,][\t ]*(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*))?)?)?)?/;
|
||||
var regex = /^[\t ]*(?:([.A-Za-z]\w*)(@\w+)?[:])?(?:[\t ]*([A-Za-z]{2,6})(?:[\t ]+([.A-Za-z0-9]\w*((\+|-)\d+)?)(?:[\t ]*[,][\t ]*([.A-Za-z0-9]\w*((\+|-)\d+)?)(?:[\t ]*[,][\t ]*([.A-Za-z0-9]\w*((\+|-)\d+)?))?)?)?)?/;
|
||||
//^[\t ]*(?:([.A-Za-z]\w*)[:])? -- label: or nothing
|
||||
//(?:[\t ]*([A-Za-z]{2,6}) -- instruction
|
||||
//(?:[\t ]+(\[(\w+((\+|-)\d+)?)\]|\".+?\"|\'.+?\'|[.A-Za-z0-9]\w*)(?:[\t ]* -- (["')OPERAND1(]"')
|
||||
// Regex group indexes for operands
|
||||
//^[\t ]*(?:([.A-Za-z]\w*)(@\w+)?[:])? -- label: or nothing
|
||||
//(?:[\t ]*([A-Za-z]{2,6}) -- instruction
|
||||
//([.A-Za-z0-9]\w*((\+|-)\d+)?) -- (OPERAND1)
|
||||
// Regex group indexes for operands
|
||||
var op1_group = 4;
|
||||
var op2_group = 7;
|
||||
var op3_group = 10;
|
||||
// MATCHES: "(+|-)INTEGER"
|
||||
var regexNum = /^[-+]?[0-9]+$/;
|
||||
// MATCHES: "(.L)abel"
|
||||
var regexLabel = /^[.A-Za-z]\w*$/;
|
||||
var regexLabelWithOffset = /^([.A-Za-z]\w*)((\+|-)\d+)?$/;
|
||||
var regexLabel = /^([.A-Za-z_]\w*)((\+|-)\d+)?$/;
|
||||
// Contains the program code & data generated by the assembler
|
||||
var memory = [];
|
||||
// The address where the next instruction/data will be placed at
|
||||
|
@ -64,12 +60,6 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
var parseNumber = function (input) {
|
||||
if (input.slice(0, 2) === "0x") {
|
||||
return parseInt(input.slice(2), 16);
|
||||
} else if (input.slice(0, 2) === "0o") {
|
||||
return parseInt(input.slice(2), 8);
|
||||
} else if (input.slice(input.length - 1) === "b") {
|
||||
return parseInt(input.slice(0, input.length - 1), 2);
|
||||
} else if (input.slice(input.length - 1) === "d") {
|
||||
return parseInt(input.slice(0, input.length - 1), 10);
|
||||
} else if (regexNum.exec(input)) {
|
||||
return parseInt(input, 10);
|
||||
} else {
|
||||
|
@ -125,7 +115,7 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
throw "addresses must have a value between 0-255";
|
||||
}
|
||||
|
||||
var match = regexLabelWithOffset.exec(input);
|
||||
var match = regexLabel.exec(input);
|
||||
if (match[1] === undefined)
|
||||
return undefined;
|
||||
var offset = 0;
|
||||
|
@ -141,9 +131,6 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
if (upperLabel in normalizedLabels)
|
||||
throw "Duplicate label: " + label;
|
||||
|
||||
if (upperLabel === "R0" || upperLabel === "R1" || upperLabel === "R2" || upperLabel === "R3" || upperLabel === "R4" || upperLabel === "R5" || upperLabel === "R6" || upperLabel === "R7" ||upperLabel === "R8" || upperLabel === "R9" || upperLabel === "RA" || upperLabel === "RB" ||upperLabel === "RC" || upperLabel === "RD" || upperLabel === "RE" || upperLabel === "RF")
|
||||
throw "Label contains keyword: " + upperLabel;
|
||||
|
||||
if (address === undefined) {
|
||||
labels[label] = current;
|
||||
} else if (address >= 0 && address <= 255) {
|
||||
|
@ -249,7 +236,7 @@ app.service('assembler', ['opcodes', function (opcodes) {
|
|||
break;
|
||||
case 'LOADB':
|
||||
p1 = parseRegister(match[op1_group]);
|
||||
p2 = parseNumber(match[op2_group]);
|
||||
p2 = parseAddress(match[op2_group]);
|
||||
checkNoExtraArg('LOADB', match[op3_group]);
|
||||
if (p1 !== undefined && p2 !== undefined)
|
||||
generate(opcodes.LOAD_WITH_CONSTANT << 4 | p1, p2);
|
||||
|
|
|
@ -150,7 +150,7 @@ app.service('cpu', ['opcodes', 'memory', function(opcodes, memory) {
|
|||
if (self.countdown > 0 && !self.updateTimer) {
|
||||
self.countdown -= 1;
|
||||
if (self.countdown === 0) {
|
||||
memory.store(0xFE, self.ip);
|
||||
memory.store(0xFD, self.ip);
|
||||
self.ip = 0x80;
|
||||
self.countdown = readReg(15);
|
||||
self.status = '(Interrupted!)';
|
||||
|
|
Loading…
Reference in New Issue