ZXS: Decode: Handle CB and ED-prefixed opcodes
authorLucian Mogosanu <lucian.mogosanu@gmail.com>
Sun, 14 Dec 2014 00:50:31 +0000 (02:50 +0200)
committerLucian Mogosanu <lucian.mogosanu@gmail.com>
Sun, 14 Dec 2014 00:50:31 +0000 (02:50 +0200)
src/Z80/ISA.hs
src/ZXS/Decode.hs

index 2ec3c73..41317d4 100644 (file)
@@ -137,9 +137,7 @@ data Instruction =
   | HALT
   | DI
   | EI
-  | IM0
-  | IM1
-  | IM2
+  | IM Word8
   -- 16-bit arithmetic group
   | ADD_HL_SS RegPair_ss
   | ADC_HL_SS RegPair_ss
@@ -163,13 +161,14 @@ data Instruction =
   | RR  SRSpec
   | SLA SRSpec
   | SRA SRSpec
+  | SLL SRSpec
   | SRL SRSpec
   | RLD
   | RRD
   -- bit set, reset and test group
-  | BIT BitwiseSpec
-  | SET BitwiseSpec
-  | RES BitwiseSpec
+  | BIT Word8 BitwiseSpec
+  | SET Word8 BitwiseSpec
+  | RES Word8 BitwiseSpec
   -- jump group
   | JP_NN Word16
   | JP_CC_NN Cond Word16
@@ -194,12 +193,14 @@ data Instruction =
   -- input and output group
   | IN_A_PN Word8
   | IN_R_PC Reg
+  | IN_PC -- only set the flag
   | INI
   | INIR
   | IND
   | INDR
   | OUT_PN_A Word8
   | OUT_PC_R Reg
+  | OUT_PC_Zero
   | OUTI
   | OUTIR
   | OUTD
index 820cec3..f048bc1 100644 (file)
@@ -71,9 +71,8 @@ decode = do
       -- z = 7
       7 -> if y > 7
         then return . IllegalInstruction $ "decode: opcode = " ++ show b
-        else return . snd . head $ filter (\ (y', _) -> y' == y)
-          [ (0, RLCA), (1, RRCA), (2, RLA), (3, RRA)
-          , (4, DAA), (5, CPL), (6, SCF), (7, CCF) ]
+        else return $
+          [ RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, CCF ] !! fromIntegral y
     -- x = 1
     1 -> if z /= 6 && y /= 6
       then return $ LD_R_R' (decodeReg y) (decodeReg z)
@@ -88,8 +87,7 @@ decode = do
         0 -> return . POP_QQ $ decodeRegPair_qq p
         1 -> if p > 3
           then return . IllegalInstruction $ "decode: opcode = " ++ show b
-          else return . snd . head $ filter (\ (y', _) -> y' == y)
-            [ (0, RET), (1, EXX), (2, JP_HL), (3, LD_SP_HL) ]
+          else return $ [ RET, EXX, JP_HL, LD_SP_HL ] !! fromIntegral y
       -- z = 2
       2 -> do
         lb <- fetch
@@ -132,10 +130,65 @@ decode = do
     -- x > 3
     _ -> return . IllegalInstruction $ "decode: opcode = " ++ show b
 
+-- decode prefixed opcodes
 decodeCB, decodeDD, decodeED, decodeFD :: ZXS Instruction
-decodeCB = undefined
+
+-- CB-prefixed opcodes
+decodeCB = do
+  b <- fetch
+  let x = (b `shiftR` 6) .&. 0x03
+      y = (b `shiftR` 3) .&. 0x07
+      z = (b `shiftR` 0) .&. 0x07
+  case x of
+    0 -> return . decodeSR y . SROp_R $ decodeReg z
+    1 -> return . BIT y . BOp_R $ decodeReg z
+    2 -> return . RES y . BOp_R $ decodeReg z
+    3 -> return . SET y . BOp_R $ decodeReg z
+
+decodeED = do
+  b <- fetch
+  let x = (b `shiftR` 6) .&. 0x03
+      y = (b `shiftR` 3) .&. 0x07
+      z = (b `shiftR` 0) .&. 0x07
+      p = (y `shiftR` 1) .&. 0x03
+      q = (y `shiftR` 0) .&. 0x01
+  case x of
+    0 -> return NOP -- NONI?
+    3 -> return NOP -- NONI?
+    -- x = 1
+    1 -> case z of
+      -- z = 0
+      0 -> if y == 6
+        then return IN_PC
+        else return . IN_R_PC $ decodeReg y
+      -- z = 1
+      1 -> if y == 6
+        then return OUT_PC_Zero
+        else return . OUT_PC_R $ decodeReg y
+      -- z = 2, 3, 4
+      2 -> let op = if q == 0 then SBC_HL_SS else ADC_HL_SS
+        in return . op $ decodeRegPair_ss p
+      3 -> do
+        lb <- fetch
+        hb <- fetch
+        let w = bbToWord hb lb
+        return $ if q == 0
+          then LD_PNN_DD w $ decodeRegPair_dd p
+          else LD_DD_PNN (decodeRegPair_dd p) w
+      4 -> return NEG
+      -- z = 5, 6
+      5 -> return $ if y /= 1 then RETN else RETI
+      6 -> return $ IM y -- handle interrupt mode based on y's value
+      7 -> return $
+        [ LD_I_A, LD_R_A, LD_A_I, LD_A_R, RRD, RLD, NOP, NOP ] !! fromIntegral y
+    -- x = 2
+    2 -> if z <= 3 && y >= 4
+      then return $ decodeBLI (y `mod` 4) z
+      else return NOP -- NONI?
+
+-- TODO: these are trickier and will require using extra logic in the decode
+-- function above and the getPrefixed field in the CPU. To bear in mind.
 decodeDD = undefined
-decodeED = undefined
 decodeFD = undefined
 
 bbToWord :: Word8 -> Word8 -> Word16
@@ -191,3 +244,22 @@ decodeALU b = case b of
   5 -> XOR_A_S
   6 -> OR_A_S
   7 -> CP_A_S
+
+decodeSR :: Word8 -> SRSpec -> Instruction
+decodeSR b = case b of
+  0 -> RLC
+  1 -> RRC
+  2 -> RL
+  3 -> RR
+  4 -> SLA
+  5 -> SRA
+  6 -> SLL
+  7 -> SRL
+
+decodeBLI :: Word8 -> Word8 -> Instruction
+decodeBLI a b = [
+  [ LDI, CPI, INI, OUTI ],
+  [ LDD, CPD, IND, OUTD ],
+  [ LDIR, CPIR, INIR, OUTIR ],
+  [ LDDR, CPDR, INDR, OUTDR ]
+  ] !! fromIntegral a !! fromIntegral b