OSDN Git Service

[General] Completely merge upstream 2019-01-11.
[csp-qt/common_source_project-fm7.git] / source / src / vm / m6502_base.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MAME
5         Author : Takeda.Toshiya
6         Date   : 2010.08.10-
7
8         [ M6502 ]
9 */
10
11 #include "m6502.h"
12 #include "debugger.h"
13
14 // vectors
15 #define NMI_VEC 0xfffa
16 #define RST_VEC 0xfffc
17 #define IRQ_VEC 0xfffe
18
19 // flags
20 #define F_C     0x01
21 #define F_Z     0x02
22 #define F_I     0x04
23 #define F_D     0x08
24 #define F_B     0x10
25 #define F_T     0x20
26 #define F_V     0x40
27 #define F_N     0x80
28
29 // some shortcuts for improved readability
30 #define A       a
31 #define X       x
32 #define Y       y
33 #define P       p
34 #define S       sp.b.l
35 #define SPD     sp.d
36
37 #define EAL ea.b.l
38 #define EAH ea.b.h
39 #define EAW ea.w.l
40 #define EAD ea.d
41
42 #define ZPL zp.b.l
43 #define ZPH zp.b.h
44 #define ZPW zp.w.l
45 #define ZPD zp.d
46
47 #define PCL pc.b.l
48 #define PCH pc.b.h
49 #define PCW pc.w.l
50 #define PCD pc.d
51
52 // virtual machine interface
53 #define RDMEM_ID(addr) d_mem->read_data8(addr)
54 #define WRMEM_ID(addr, data) d_mem->write_data8(addr, data)
55
56 #define RDOP() d_mem->read_data8(PCW++)
57 #define PEEKOP() d_mem->read_data8(PCW)
58 #define RDOPARG() d_mem->read_data8(PCW++)
59
60 #define RDMEM(addr) d_mem->read_data8(addr)
61 #define WRMEM(addr, data) d_mem->write_data8(addr, data)
62
63 #define CYCLES(c) icount -= (c)
64
65 // opcodes
66 #define PUSH(Rg) WRMEM(SPD, Rg); S--
67 #define PULL(Rg) S++; Rg = RDMEM(SPD)
68
69 void M6502_BASE::OP(uint8_t code)
70 {
71 }
72
73 inline void M6502_BASE::update_irq()
74 {
75         if(!(P & F_I)) {
76                 EAD = IRQ_VEC;
77                 CYCLES(2);
78                 PUSH(PCH);
79                 PUSH(PCL);
80                 PUSH(P & ~F_B);
81                 P |= F_I;
82                 PCL = RDMEM(EAD);
83                 PCH = RDMEM(EAD + 1);
84                 // call back the cpuintrf to let it clear the line
85                 d_pic->notify_intr_reti();
86                 irq_state = false;
87         }
88         pending_irq = false;
89 }
90
91 // main
92
93 void M6502_BASE::initialize()
94 {
95         DEVICE::initialize();
96         A = X = Y = P = 0;
97         SPD = EAD = ZPD = PCD = 0;
98 }
99
100 void M6502_BASE::reset()
101 {
102         PCL = RDMEM(RST_VEC);
103         PCH = RDMEM(RST_VEC + 1);
104         SPD = 0x01ff;
105         P = F_T | F_I | F_Z | F_B | (P & F_D);
106         
107         icount = 0;
108         pending_irq = after_cli = false;
109         irq_state = nmi_state = so_state = false;
110 }
111
112 int M6502_BASE::run(int clock)
113 {
114         if(clock == -1) {
115                 if (busreq) {
116                         // don't run cpu!
117                         return 1;
118                 } else {
119                         // run only one opcode
120                         icount = 0;
121                         run_one_opecode();
122                         return -icount;
123                 }
124         } else {
125                 icount += clock;
126                 int first_icount = icount;
127                 
128                 // run cpu while given clocks
129                 while(icount > 0 && !busreq) {
130                                 run_one_opecode();
131                 }
132                 // if busreq is raised, spin cpu while remained clock
133                 if(icount > 0 && busreq) {
134                         icount = 0;
135                 }
136                 return first_icount - icount;
137         }
138 }
139
140 void M6502_BASE::run_one_opecode()
141 {
142         int first_icount = icount;
143         // if an irq is pending, take it now
144         if(nmi_state) {
145                 EAD = NMI_VEC;
146                 CYCLES(2);
147                 PUSH(PCH);
148                 PUSH(PCL);
149                 PUSH(P & ~F_B);
150                 P |= F_I;       // set I flag
151                 PCL = RDMEM(EAD);
152                 PCH = RDMEM(EAD + 1);
153                 nmi_state = false;
154         } else if(pending_irq) {
155                 if(d_debugger != NULL) d_debugger->add_cpu_trace(PCW);
156                 update_irq();
157         }
158         prev_pc = PCW;
159         uint8_t code = RDOP();
160         OP(code);
161         
162         // check if the I flag was just reset (interrupts enabled)
163         if(after_cli) {
164                 after_cli = false;
165                 if(irq_state) {
166                         pending_irq = true;
167                 }
168         } else if(pending_irq) {
169                 update_irq();
170         }
171 }
172 void M6502_BASE::write_signal(int id, uint32_t data, uint32_t mask)
173 {
174         bool state = ((data & mask) != 0);
175         
176         if(id == SIG_CPU_NMI) {
177                 nmi_state = state;
178         } else if(id == SIG_CPU_IRQ) {
179                 irq_state = state;
180                 if(state) {
181                         pending_irq = true;
182                 }
183         } else if(id == SIG_M6502_OVERFLOW) {
184                 if(so_state && !state) {
185                         P |= F_V;
186                 }
187                 so_state = state;
188         } else if(id == SIG_CPU_BUSREQ) {
189                 busreq = ((data & mask) != 0);
190         }
191 }
192
193 //#ifdef USE_DEBUGGER
194 void M6502_BASE::write_debug_data8(uint32_t addr, uint32_t data)
195 {
196         int wait;
197         d_mem_stored->write_data8w(addr, data, &wait);
198 }
199
200 uint32_t M6502_BASE::read_debug_data8(uint32_t addr)
201 {
202         int wait;
203         return d_mem_stored->read_data8w(addr, &wait);
204 }
205
206 bool M6502_BASE::write_debug_reg(const _TCHAR *reg, uint32_t data)
207 {
208         if(_tcsicmp(reg, _T("PC")) == 0) {
209                 PCW = data;
210         } else if(_tcsicmp(reg, _T("A")) == 0) {
211                 A = data;
212         } else if(_tcsicmp(reg, _T("X")) == 0) {
213                 X = data;
214         } else if(_tcsicmp(reg, _T("Y")) == 0) {
215                 Y = data;
216         } else if(_tcsicmp(reg, _T("S")) == 0) {
217                 S = data;
218         } else if(_tcsicmp(reg, _T("P")) == 0) {
219                 P = data;
220         } else {
221                 return false;
222         }
223         return true;
224 }
225
226 void M6502_BASE::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
227 {
228         my_stprintf_s(buffer, buffer_len,
229         _T("PC = %04X  A = %02X  X = %02X  Y = %02X  S = %02X  P = %02X [%c%c%c%c%c%c%c%c]\nClocks = %llu (%llu) Since Scanline = %d/%d (%d/%d)"),
230         PCW, A, X, Y, S, P,
231         (P & F_N) ? _T('N') : _T('-'), (P & F_V) ? _T('V') : _T('-'), (P & F_T) ? _T('T') : _T('-'), (P & F_B) ? _T('B') : _T('-'), 
232         (P & F_D) ? _T('D') : _T('-'), (P & F_I) ? _T('I') : _T('-'), (P & F_Z) ? _T('Z') : _T('-'), (P & F_C) ? _T('C') : _T('-'),
233         total_icount, total_icount - prev_total_icount,
234         get_passed_clock_since_vline(), get_cur_vline_clocks(), get_cur_vline(), get_lines_per_frame());
235         prev_total_icount = total_icount;
236 }
237
238 // disassembler
239
240 #define offs_t UINT16
241
242 /*****************************************************************************/
243 /* src/emu/devcpu.h */
244
245 // CPU interface functions
246 #define CPU_DISASSEMBLE_NAME(name)              cpu_disassemble_##name
247 #define CPU_DISASSEMBLE(name)                   int CPU_DISASSEMBLE_NAME(name)(_TCHAR *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, symbol_t *first_symbol)
248 #define CPU_DISASSEMBLE_CALL(name)              CPU_DISASSEMBLE_NAME(name)(buffer, pc, oprom, oprom, d_debugger->first_symbol)
249
250 /*****************************************************************************/
251 /* src/emu/didisasm.h */
252
253 // Disassembler constants
254 const UINT32 DASMFLAG_SUPPORTED     = 0x80000000;   // are disassembly flags supported?
255 const UINT32 DASMFLAG_STEP_OUT      = 0x40000000;   // this instruction should be the end of a step out sequence
256 const UINT32 DASMFLAG_STEP_OVER     = 0x20000000;   // this instruction should be stepped over by setting a breakpoint afterwards
257 const UINT32 DASMFLAG_OVERINSTMASK  = 0x18000000;   // number of extra instructions to skip when stepping over
258 const UINT32 DASMFLAG_OVERINSTSHIFT = 27;           // bits to shift after masking to get the value
259 //const UINT32 DASMFLAG_LENGTHMASK    = 0x0000ffff;   // the low 16-bits contain the actual length
260
261 #include "mame/emu/cpu/m6502/6502dasm.c"
262
263 int M6502_BASE::debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len)
264 {
265    return 0;
266 }
267 //#endif
268