1 /*
2  *  Copyright (C) 2002-2021  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef DOSBOX_LAZYFLAGS_H
20 #define DOSBOX_LAZYFLAGS_H
21 
22 #include "cpu.h"
23 
24 #include <cassert>
25 
26 // Flag Handling
27 uint32_t get_CF();
28 uint32_t get_AF();
29 uint32_t get_ZF();
30 uint32_t get_SF();
31 uint32_t get_OF();
32 uint32_t get_PF();
33 
34 uint32_t FillFlags(void);
35 void FillFlagsNoCFOF(void);
36 void DestroyConditionFlags(void);
37 
38 #ifndef DOSBOX_REGS_H
39 #include "regs.h"
40 #endif
41 
42 struct LazyFlags {
43 	GenReg32 var1 = {};
44 	GenReg32 var2 = {};
45 	GenReg32 res = {};
46 	Bitu type = 0;
47 	Bitu prev_type = 0;
48 	Bitu oldcf = 0;
49 };
50 
51 extern LazyFlags lflags;
52 
53 inline constexpr uint8_t &lf_var1b = lflags.var1.byte[BL_INDEX];
54 inline constexpr uint8_t &lf_var2b = lflags.var2.byte[BL_INDEX];
55 inline constexpr uint8_t &lf_resb = lflags.res.byte[BL_INDEX];
56 
57 inline constexpr uint16_t &lf_var1w = lflags.var1.word[W_INDEX];
58 inline constexpr uint16_t &lf_var2w = lflags.var2.word[W_INDEX];
59 inline constexpr uint16_t &lf_resw = lflags.res.word[W_INDEX];
60 
61 inline constexpr uint32_t &lf_var1d = lflags.var1.dword[DW_INDEX];
62 inline constexpr uint32_t &lf_var2d = lflags.var2.dword[DW_INDEX];
63 inline constexpr uint32_t &lf_resd = lflags.res.dword[DW_INDEX];
64 
65 // many places in the code want to shift by "lf_var2b - 1", so this wrapper
66 // catches potential negative shifts.
lf_var2b_minus_one()67 inline uint8_t lf_var2b_minus_one()
68 {
69 	assert(lf_var2b > 0);
70 	return lf_var2b - 1;
71 }
72 
73 // Types of Flag changing instructions
74 enum {
75 	t_UNKNOWN=0,
76 	t_ADDb,t_ADDw,t_ADDd,
77 	t_ORb,t_ORw,t_ORd,
78 	t_ADCb,t_ADCw,t_ADCd,
79 	t_SBBb,t_SBBw,t_SBBd,
80 	t_ANDb,t_ANDw,t_ANDd,
81 	t_SUBb,t_SUBw,t_SUBd,
82 	t_XORb,t_XORw,t_XORd,
83 	t_CMPb,t_CMPw,t_CMPd,
84 	t_INCb,t_INCw,t_INCd,
85 	t_DECb,t_DECw,t_DECd,
86 	t_TESTb,t_TESTw,t_TESTd,
87 	t_SHLb,t_SHLw,t_SHLd,
88 	t_SHRb,t_SHRw,t_SHRd,
89 	t_SARb,t_SARw,t_SARd,
90 	t_ROLb,t_ROLw,t_ROLd,
91 	t_RORb,t_RORw,t_RORd,
92 	t_RCLb,t_RCLw,t_RCLd,
93 	t_RCRb,t_RCRw,t_RCRd,
94 	t_NEGb,t_NEGw,t_NEGd,
95 
96 	t_DSHLw,t_DSHLd,
97 	t_DSHRw,t_DSHRd,
98 	t_MUL,t_DIV,
99 	t_NOTDONE,
100 	t_LASTFLAG
101 };
102 
SETFLAGSb(const uint8_t FLAGB)103 inline void SETFLAGSb(const uint8_t FLAGB)
104 {
105 	SETFLAGBIT(OF, get_OF());
106 	lflags.type = t_UNKNOWN;
107 	CPU_SetFlags(FLAGB, FMASK_NORMAL & 0xff);
108 }
109 
SETFLAGSw(const uint16_t FLAGW)110 inline void SETFLAGSw(const uint16_t FLAGW)
111 {
112 	lflags.type = t_UNKNOWN;
113 	CPU_SetFlagsw(FLAGW);
114 }
115 
SETFLAGSd(const uint32_t FLAGD)116 inline void SETFLAGSd(const uint32_t FLAGD)
117 {
118 	lflags.type = t_UNKNOWN;
119 	CPU_SetFlagsd(FLAGD);
120 }
121 
122 #define LoadCF SETFLAGBIT(CF, get_CF());
123 #define LoadZF SETFLAGBIT(ZF, get_ZF());
124 #define LoadSF SETFLAGBIT(SF, get_SF());
125 #define LoadOF SETFLAGBIT(OF, get_OF());
126 #define LoadAF SETFLAGBIT(AF, get_AF());
127 
128 #define TFLG_O   (get_OF())
129 #define TFLG_NO  (!get_OF())
130 #define TFLG_B   (get_CF())
131 #define TFLG_NB  (!get_CF())
132 #define TFLG_Z   (get_ZF())
133 #define TFLG_NZ  (!get_ZF())
134 #define TFLG_BE  (get_CF() || get_ZF())
135 #define TFLG_NBE (!get_CF() && !get_ZF())
136 #define TFLG_S   (get_SF())
137 #define TFLG_NS  (!get_SF())
138 #define TFLG_P   (get_PF())
139 #define TFLG_NP  (!get_PF())
140 #define TFLG_L   ((get_SF() != 0) != (get_OF() != 0))
141 #define TFLG_NL  ((get_SF() != 0) == (get_OF() != 0))
142 #define TFLG_LE  (get_ZF() || ((get_SF() != 0) != (get_OF() != 0)))
143 #define TFLG_NLE (!get_ZF() && ((get_SF() != 0) == (get_OF() != 0)))
144 
145 #endif
146