-- 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)
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
-- 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
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