From caae2876d7cb5b555ab52fa6a05c9b95fea80534 Mon Sep 17 00:00:00 2001 From: Gergo ERDI Date: Sun, 3 Sep 2023 17:06:54 +0200 Subject: [PATCH 1/3] `db @[Word8]` should be lazy in the content of the bytes --- src/Z80/Assembler.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Z80/Assembler.hs b/src/Z80/Assembler.hs index 8d2e2e9..2264de1 100644 --- a/src/Z80/Assembler.hs +++ b/src/Z80/Assembler.hs @@ -62,7 +62,12 @@ class Bytes a where instance Bytes ByteString where defb = defByteString instance (b ~ Word8) => Bytes [b] where - defb = defByteString . BS.pack + defb bs = Z80 $ do + tell $ BS.pack bs + modify (incrementLoc . fromIntegral $ length bs) + -- The new location has to be computed lazily in the actual + -- content of the bytes, so that we can emit byte values + -- referring to later labels. db :: Bytes a => a -> Z80ASM db = defb From 57a70e19aed48783260fce58f2c5352e1fcab3f9 Mon Sep 17 00:00:00 2001 From: Gergo ERDI Date: Fri, 8 Sep 2023 12:10:42 +0200 Subject: [PATCH 2/3] Add `resb` to reserve uninitialized bytes. Only really makes sense at the end --- src/Z80/Assembler.hs | 59 +++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/src/Z80/Assembler.hs b/src/Z80/Assembler.hs index 2264de1..c9453a2 100644 --- a/src/Z80/Assembler.hs +++ b/src/Z80/Assembler.hs @@ -10,6 +10,7 @@ module Z80.Assembler , code , Bytes (..) , db + , resb , equ , label , labelled @@ -34,6 +35,7 @@ import Z80.Operands data ASMState = ASMState { loc :: Location + , lastLoc :: Location , entry :: Maybe Location } @@ -48,13 +50,29 @@ data ASMBlock , asmData :: ByteString } deriving (Eq, Show) -incrementLoc :: Location -> ASMState -> ASMState -incrementLoc x st = st { loc = loc st + x } +fillToLoc :: Z80ASM +fillToLoc = Z80 $ do + padding <- gets $ \st -> loc st - lastLoc st + tell $ BS.replicate (fromIntegral padding) 0x00 + +incrementLoc :: Location -> Z80ASM +incrementLoc x = do + fillToLoc + Z80 $ modify $ \st -> let loc' = loc st + x in st{ loc = loc', lastLoc = loc' } + +reserveLoc :: Location -> ASMState -> ASMState +reserveLoc x st = st{ loc = loc st + x } + +tellBytes :: [Word8] -> Z80ASM +tellBytes bytes = do + Z80 $ tell $ BS.pack bytes + incrementLoc . fromIntegral $ length bytes + -- The new location has to be computed lazily in the actual + -- content of the bytes, so that we can emit byte values + -- referring to later labels. code :: [Word8] -> Z80ASM -code bytes = Z80 $ do - tell $ BS.pack bytes - modify (incrementLoc . fromIntegral $ length bytes) +code = tellBytes class Bytes a where defb :: a -> Z80ASM @@ -62,20 +80,19 @@ class Bytes a where instance Bytes ByteString where defb = defByteString instance (b ~ Word8) => Bytes [b] where - defb bs = Z80 $ do - tell $ BS.pack bs - modify (incrementLoc . fromIntegral $ length bs) - -- The new location has to be computed lazily in the actual - -- content of the bytes, so that we can emit byte values - -- referring to later labels. + defb = tellBytes db :: Bytes a => a -> Z80ASM db = defb +resb :: Word16 -> Z80ASM +resb n = Z80 $ do + modify $ reserveLoc n + defByteString :: ByteString -> Z80ASM -defByteString bs = Z80 $ do - tell bs - modify (incrementLoc . fromIntegral $ BS.length bs) +defByteString bs = do + Z80 $ tell bs + incrementLoc . fromIntegral $ BS.length bs label :: Z80 Location label = loc <$> Z80 get @@ -97,16 +114,18 @@ beginExecution :: Z80ASM beginExecution = do l <- label Z80 . modify $ setEntry l - where setEntry l st@(ASMState _ Nothing) = st { entry = Just l } - setEntry l st@(ASMState _ (Just e)) = - error $ "Cannot set execution start point twice. First start point: " ++ show e ++ - " This start point: " ++ show l + where setEntry l st = case entry st of + Nothing -> st{ entry = Just l } + Just e -> + error $ "Cannot set execution start point twice. First start point: " ++ show e ++ + " This start point: " ++ show l org :: Location -> Z80ASM -> ASMBlock org addr (Z80 mc) = ASMBlock { asmOrg = addr, asmEntry = fromMaybe addr $ entry finalState, - asmData = asm } - where ((), finalState, asm) = runRWS mc () (ASMState addr Nothing) + asmData = truncate asm } + where ((), finalState, asm) = runRWS mc () (ASMState addr addr Nothing) + truncate = BS.take (fromIntegral $ lastLoc finalState - addr) equ :: a -> Z80 a equ = return From 7dab1a505a3cb783ea6ceb2cf5ef672cb7281dc0 Mon Sep 17 00:00:00 2001 From: Gergo ERDI Date: Sat, 30 May 2026 09:12:55 +0800 Subject: [PATCH 3/3] Fill to the current location *before* emitting new output --- src/Z80/Assembler.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Z80/Assembler.hs b/src/Z80/Assembler.hs index c9453a2..123f13b 100644 --- a/src/Z80/Assembler.hs +++ b/src/Z80/Assembler.hs @@ -65,8 +65,9 @@ reserveLoc x st = st{ loc = loc st + x } tellBytes :: [Word8] -> Z80ASM tellBytes bytes = do + loc <- incrementLoc . fromIntegral $ length bytes Z80 $ tell $ BS.pack bytes - incrementLoc . fromIntegral $ length bytes + pure loc -- The new location has to be computed lazily in the actual -- content of the bytes, so that we can emit byte values -- referring to later labels. @@ -91,8 +92,9 @@ resb n = Z80 $ do defByteString :: ByteString -> Z80ASM defByteString bs = do + loc <- incrementLoc . fromIntegral $ BS.length bs Z80 $ tell bs - incrementLoc . fromIntegral $ BS.length bs + pure loc label :: Z80 Location label = loc <$> Z80 get