Create Fibbonacci sequence example and test
This commit is contained in:
44
README.md
44
README.md
@@ -116,7 +116,7 @@ Done:
|
|||||||
VM {_pc = 8, _fp = -1, _stack = fromList [], _halt = True, _debug = False}
|
VM {_pc = 8, _fp = -1, _stack = fromList [], _halt = True, _debug = False}
|
||||||
```
|
```
|
||||||
### Example 3
|
### Example 3
|
||||||
The power ($2^{10}$) computation - loop variant
|
The power (`2^10`) computation - loop variant
|
||||||
```asm
|
```asm
|
||||||
push 2
|
push 2
|
||||||
push 10
|
push 10
|
||||||
@@ -153,7 +153,7 @@ Done:
|
|||||||
VM {_pc = 8, _fp = -1, _stack = fromList [1024], _halt = True, _debug = False}
|
VM {_pc = 8, _fp = -1, _stack = fromList [1024], _halt = True, _debug = False}
|
||||||
```
|
```
|
||||||
### Example 4
|
### Example 4
|
||||||
The power ($2^{10}$) computation - recursive variant
|
The power (`2^10`) computation - recursive variant
|
||||||
```asm
|
```asm
|
||||||
push 2 ; base
|
push 2 ; base
|
||||||
push 10 ; exp
|
push 10 ; exp
|
||||||
@@ -186,4 +186,44 @@ The result of execution:
|
|||||||
```
|
```
|
||||||
Done:
|
Done:
|
||||||
VM {_pc = 8, _fp = -1, _stack = fromList [1024], _halt = True, _debug = False}
|
VM {_pc = 8, _fp = -1, _stack = fromList [1024], _halt = True, _debug = False}
|
||||||
|
```
|
||||||
|
### Example 5
|
||||||
|
The `N`-th element of Fibbonaci sequence - recursive variant
|
||||||
|
```asm
|
||||||
|
push 6
|
||||||
|
call &fibb
|
||||||
|
clr 1
|
||||||
|
halt
|
||||||
|
|
||||||
|
fibb: lda 0 ; n | Stack:
|
||||||
|
ldl 0 ; n == 0 -> return 1 | n
|
||||||
|
je &done0 ; | n
|
||||||
|
pop ; |
|
||||||
|
ldl 0 ; n == 1 -> return 1 | n
|
||||||
|
push 1 ; | n 1
|
||||||
|
sub ; | n-1
|
||||||
|
je &done1 ; | n-1
|
||||||
|
dup ; Evaluate fibb | n-1 n-1
|
||||||
|
push 1 ; | n-1 n-1 1
|
||||||
|
sub ; | n-1 n-2
|
||||||
|
call &fibb ; | n-1 n-2 f(n-2)
|
||||||
|
clr 1 ; | n-1 f(n-2)
|
||||||
|
over ; | n-1 f(n-2) n-1
|
||||||
|
call &fibb ; | n-1 f(n-2) n-1 f(n-1)
|
||||||
|
clr 1 ; | n-1 f(n-2) f(n-1)
|
||||||
|
add ; | n-1 f(n-2)+f(n-1)
|
||||||
|
ret
|
||||||
|
|
||||||
|
done1: pop
|
||||||
|
push 1
|
||||||
|
ret
|
||||||
|
|
||||||
|
done0: pop
|
||||||
|
push 1
|
||||||
|
ret
|
||||||
|
```
|
||||||
|
The result of execution:
|
||||||
|
```
|
||||||
|
Done:
|
||||||
|
VM {_pc = 6, _fp = -1, _stack = fromList [13], _halt = True, _debug = False}
|
||||||
```
|
```
|
||||||
@@ -10,6 +10,11 @@ import Runner (run, exec)
|
|||||||
done :: [Int] -> Int -> Int -> Either String VM
|
done :: [Int] -> Int -> Int -> Either String VM
|
||||||
done stack pc fp = return $ empty { _stack = S.fromList stack, _pc = pc, _fp = fp, _halt = True }
|
done stack pc fp = return $ empty { _stack = S.fromList stack, _pc = pc, _fp = fp, _halt = True }
|
||||||
|
|
||||||
|
fibb :: Int -> Int
|
||||||
|
fibb 0 = 1
|
||||||
|
fibb 1 = 1
|
||||||
|
fibb n = fibb (n-1) + fibb (n-2)
|
||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
spec = do
|
spec = do
|
||||||
describe "nop" $ do
|
describe "nop" $ do
|
||||||
@@ -694,7 +699,7 @@ spec = do
|
|||||||
\ call &f \n\
|
\ call &f \n\
|
||||||
\ halt \n\
|
\ halt \n\
|
||||||
\ f: nop \n\
|
\ f: nop \n\
|
||||||
\ ret \n"
|
\ ret "
|
||||||
let expected = done [] 3 (-1)
|
let expected = done [] 3 (-1)
|
||||||
actual <- run input
|
actual <- run input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
@@ -704,7 +709,7 @@ spec = do
|
|||||||
\ halt \n\
|
\ halt \n\
|
||||||
\ f: nop \n\
|
\ f: nop \n\
|
||||||
\ push 4 \n\
|
\ push 4 \n\
|
||||||
\ ret \n"
|
\ ret "
|
||||||
-- ┌──── this is the top stack value at the time 'ret' instruction being invoked
|
-- ┌──── this is the top stack value at the time 'ret' instruction being invoked
|
||||||
let expected = done [4] 3 (-1)
|
let expected = done [4] 3 (-1)
|
||||||
actual <- run input
|
actual <- run input
|
||||||
@@ -724,7 +729,7 @@ spec = do
|
|||||||
\ add \n\
|
\ add \n\
|
||||||
\ ret \n\
|
\ ret \n\
|
||||||
\ h: push 6 \n\
|
\ h: push 6 \n\
|
||||||
\ ret \n"
|
\ ret "
|
||||||
-- ┌───── h: _ -> 6 │ = 6
|
-- ┌───── h: _ -> 6 │ = 6
|
||||||
-- │ g: _ -> h + 4 │ = 10 = 6 + 4
|
-- │ g: _ -> h + 4 │ = 10 = 6 + 4
|
||||||
-- │ f: _ -> h * 2 │ = 20 = 10 * 2
|
-- │ f: _ -> h * 2 │ = 20 = 10 * 2
|
||||||
@@ -752,8 +757,8 @@ spec = do
|
|||||||
let input = " push 14 \n\
|
let input = " push 14 \n\
|
||||||
\ call &f \n\
|
\ call &f \n\
|
||||||
\ nop \n\
|
\ nop \n\
|
||||||
\ f: lda 0 \n\
|
\ f: lda 0 \n\
|
||||||
\ halt"
|
\ halt "
|
||||||
let expected = done [14, 4, -1, 14] 7 1
|
let expected = done [14, 4, -1, 14] 7 1
|
||||||
actual <- run input
|
actual <- run input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
@@ -763,10 +768,10 @@ spec = do
|
|||||||
\ push 4 \n\
|
\ push 4 \n\
|
||||||
\ call &f \n\
|
\ call &f \n\
|
||||||
\ nop \n\
|
\ nop \n\
|
||||||
\ f: lda 2 \n\
|
\ f: lda 2 \n\
|
||||||
\ lda 1 \n\
|
\ lda 1 \n\
|
||||||
\ lda 0 \n\
|
\ lda 0 \n\
|
||||||
\ halt"
|
\ halt "
|
||||||
let expected = done [4, 11, 14, 8, -1, 4, 11, 14] 15 3
|
let expected = done [4, 11, 14, 8, -1, 4, 11, 14] 15 3
|
||||||
actual <- run input
|
actual <- run input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
@@ -775,8 +780,8 @@ spec = do
|
|||||||
\ push 11 \n\
|
\ push 11 \n\
|
||||||
\ call &sum \n\
|
\ call &sum \n\
|
||||||
\ halt \n\
|
\ halt \n\
|
||||||
\ sum: lda 1 \n\
|
\ sum: lda 1 \n\
|
||||||
\ lda 0 \n\
|
\ lda 0 \n\
|
||||||
\ add \n\
|
\ add \n\
|
||||||
\ ret "
|
\ ret "
|
||||||
let expected = done [25, 11, 14] 6 (-1)
|
let expected = done [25, 11, 14] 6 (-1)
|
||||||
@@ -784,35 +789,35 @@ spec = do
|
|||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
it "raises error if stack is empty" $ do
|
it "raises error if stack is empty" $ do
|
||||||
let input = " lda 0 \n\
|
let input = " lda 0 \n\
|
||||||
\ halt "
|
\ halt "
|
||||||
let expected = Left "Index 0 out of stack bounds"
|
let expected = Left "Index 0 out of stack bounds"
|
||||||
let vm = empty { _stack = S.fromList [], _fp = 0 }
|
let vm = empty { _stack = S.fromList [], _fp = 0 }
|
||||||
actual <- exec vm input
|
actual <- exec vm input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
it "raises error if stack contains only previous fp" $ do
|
it "raises error if stack contains only previous fp" $ do
|
||||||
let vm = empty { _stack = S.fromList [-1], _fp = 0 }
|
let vm = empty { _stack = S.fromList [-1], _fp = 0 }
|
||||||
let input = " lda 0 \n\
|
let input = " lda 0 \n\
|
||||||
\ halt "
|
\ halt "
|
||||||
let expected = Left "Index 0 out of stack bounds"
|
let expected = Left "Index 0 out of stack bounds"
|
||||||
actual <- exec vm input
|
actual <- exec vm input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
it "raises error if stack contains only previous fp and return address" $ do
|
it "raises error if stack contains only previous fp and return address" $ do
|
||||||
let vm = empty { _stack = S.fromList [2, -1], _fp = 0 }
|
let vm = empty { _stack = S.fromList [2, -1], _fp = 0 }
|
||||||
let input = " lda 0 \n\
|
let input = " lda 0 \n\
|
||||||
\ halt "
|
\ halt "
|
||||||
let expected = Left "Index 0 out of stack bounds"
|
let expected = Left "Index 0 out of stack bounds"
|
||||||
actual <- exec vm input
|
actual <- exec vm input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
it "loads the first (0) argument if stack contains only previous fp, return address and single argument" $ do
|
it "loads the first (0) argument if stack contains only previous fp, return address and single argument" $ do
|
||||||
let vm = empty { _stack = S.fromList [2, -1, 3], _fp = 1 }
|
let vm = empty { _stack = S.fromList [2, -1, 3], _fp = 1 }
|
||||||
let input = " lda 0 \n\
|
let input = " lda 0 \n\
|
||||||
\ halt "
|
\ halt "
|
||||||
let expected = done [3, 2, -1, 3] 2 1
|
let expected = done [3, 2, -1, 3] 2 1
|
||||||
actual <- exec vm input
|
actual <- exec vm input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
it "raises error when accessint second (1) argument if stack contains only previous fp, return address and single argument" $ do
|
it "raises error when accessint second (1) argument if stack contains only previous fp, return address and single argument" $ do
|
||||||
let vm = empty { _stack = S.fromList [2, -1, 3], _fp = 1 }
|
let vm = empty { _stack = S.fromList [2, -1, 3], _fp = 1 }
|
||||||
let input = " lda 1 \n\
|
let input = " lda 1 \n\
|
||||||
\ halt "
|
\ halt "
|
||||||
let expected = Left "Index 1 out of stack bounds"
|
let expected = Left "Index 1 out of stack bounds"
|
||||||
actual <- exec vm input
|
actual <- exec vm input
|
||||||
@@ -824,9 +829,9 @@ spec = do
|
|||||||
-- │ │
|
-- │ │
|
||||||
let vm = empty { _stack = S.fromList [ 2, -1, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ], _fp = 12 }
|
let vm = empty { _stack = S.fromList [ 2, -1, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ], _fp = 12 }
|
||||||
-- │ │
|
-- │ │
|
||||||
-- argument indexes (lda): └─ 0 1 2 3 4 5 6 7 8 9 10 11
|
-- argument indexes (lda): └─ 0 1 2 3 4 5 6 7 8 9 10 11
|
||||||
-- └───── lda 11 results in pushing 0 on to the top of the stack
|
-- └───── lda 11 results in pushing 0 on to the top of the stack
|
||||||
let input = " lda 11 \n\
|
let input = " lda 11 \n\
|
||||||
\ halt "
|
\ halt "
|
||||||
let expected = done [0, 2, -1, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 2 12
|
let expected = done [0, 2, -1, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 2 12
|
||||||
actual <- exec vm input
|
actual <- exec vm input
|
||||||
@@ -850,8 +855,8 @@ spec = do
|
|||||||
\ call &sum \n\
|
\ call &sum \n\
|
||||||
\ clr 2 \n\
|
\ clr 2 \n\
|
||||||
\ halt \n\
|
\ halt \n\
|
||||||
\ sum: lda 1 \n\
|
\ sum: lda 1 \n\
|
||||||
\ lda 0 \n\
|
\ lda 0 \n\
|
||||||
\ add \n\
|
\ add \n\
|
||||||
\ ret "
|
\ ret "
|
||||||
let expected = done [25] 8 (-1)
|
let expected = done [25] 8 (-1)
|
||||||
@@ -1124,4 +1129,37 @@ spec = do
|
|||||||
\ ret "
|
\ ret "
|
||||||
let expected = done [4 ^ (7 :: Int)] 8 (-1)
|
let expected = done [4 ^ (7 :: Int)] 8 (-1)
|
||||||
actual <- run input
|
actual <- run input
|
||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
|
|
||||||
|
it "example #5: 11-th element of Fibonacci sequence - recursive variant" $ do
|
||||||
|
let input = " push 11 \n\
|
||||||
|
\ call &fibb \n\
|
||||||
|
\ clr 1 \n\
|
||||||
|
\ halt \n\
|
||||||
|
\ fibb: lda 0 \n\
|
||||||
|
\ ldl 0 \n\
|
||||||
|
\ je &done0 \n\
|
||||||
|
\ pop \n\
|
||||||
|
\ ldl 0 \n\
|
||||||
|
\ push 1 \n\
|
||||||
|
\ sub \n\
|
||||||
|
\ je &done1 \n\
|
||||||
|
\ dup \n\
|
||||||
|
\ push 1 \n\
|
||||||
|
\ sub \n\
|
||||||
|
\ call &fibb \n\
|
||||||
|
\ clr 1 \n\
|
||||||
|
\ over \n\
|
||||||
|
\ call &fibb \n\
|
||||||
|
\ clr 1 \n\
|
||||||
|
\ add \n\
|
||||||
|
\ ret \n\
|
||||||
|
\ done1: pop \n\
|
||||||
|
\ push 1 \n\
|
||||||
|
\ ret \n\
|
||||||
|
\ done0: pop \n\
|
||||||
|
\ push 1 \n\
|
||||||
|
\ ret "
|
||||||
|
let expected = done [fibb 11] 6 (-1)
|
||||||
|
actual <- run input
|
||||||
|
actual `shouldBe` expected
|
||||||
Reference in New Issue
Block a user