Permalink
Browse files

Add self-modifying code example

  • Loading branch information...
jaspervdj committed Apr 11, 2012
1 parent f124ab1 commit f21d31e47e9dddeb720207aa20c3d97c7c86985f
Showing with 64 additions and 1 deletion.
  1. +40 −0 examples/self-copy.s
  2. +7 −0 src/Memory.hs
  3. +17 −1 tests/Examples.hs
View
@@ -0,0 +1,40 @@
; This is a self-adapting program. It figures out where it is located in the
; memory, copies itself so that the copy directly follows the original. This
; means that once the original program is finished, the copy will run, and, in
; turn, make a copy of itself...
;
; We use a counter to limit the number of copies.
; Number of copies to make
SET I, 9
:start SET A, PC
SUB A, 1 ; Because the previous instruction was 1 word long
SET B, A
ADD B, end
SUB B, start
; Bail out when enough copies have been made
IFE I, 0
SET PC, B
SUB I, 1
; Calculate relative position of loop label
SET C, loop
SUB C, start
ADD C, A
SET X, A
SET Y, B
; Jump to the newly written instructions when copy is done
:loop IFE X, B
SET PC, B
SET [Y], [X]
ADD X, 1
ADD Y, 1
; Remember that C is a modified 'loop'
SET PC, C
:end
View
@@ -12,6 +12,8 @@ module Memory
, store
) where
import Control.Monad (forM_)
import GHC.Base (Int (..))
import GHC.Prim
import GHC.ST (ST (..))
@@ -56,6 +58,11 @@ new = do
store mem Sp 0xffff
store mem O 0x0000
store mem Cycles 0x0000
-- TODO: This is slow.
forM_ [minBound .. maxBound] $ \r -> store mem (Register r) 0x0000
forM_ [minBound .. maxBound] $ \r -> store mem (Ram r) 0x0000
return mem
new' :: ST s (Memory s)
View
@@ -3,9 +3,10 @@ module Examples
( tests
) where
import Control.Applicative ((<$>))
import Control.Monad (forM)
import Data.Bits (shiftL)
import Data.List (sort)
import Data.List (isPrefixOf, sort)
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
@@ -50,6 +51,21 @@ tests = testGroup "Examples"
if f == f' then loop fs as else return False
return . assert =<< loop fibs addrs
, testCase "self-copy.s" $ example "examples/self-copy.s" $ do
let readRam i = do
x <- load $ Ram i
if x == 0x0000
then return []
else (x :) <$> readRam (i + 1)
programs <- readRam 1
let len = length programs `div` 10
equal xs = case splitAt len xs of
(_, []) -> True
(hs, ts) -> hs `isPrefixOf` ts && equal ts
return $ assert $ equal programs
]
example :: FilePath

0 comments on commit f21d31e

Please sign in to comment.