-
Notifications
You must be signed in to change notification settings - Fork 2
/
x86.bas
440 lines (357 loc) · 12.4 KB
/
x86.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
Sub x86_int(ByVal num As Integer )
Dim As ULong addr =Any
pc=oldpc
if modoprotegido Then
pmodeint(num,0)
Else
if ssegs Then ss0=oldss
if stack32 Then
writememw_386(ss0,ESP-2,flags)
writememw_386(ss0,ESP-4,CS1)
writememw_386(ss0,ESP-6,pc)
ESP-=6
else
writememw_386(ss0,((SP-2) And &hFFFF),flags)
writememw_386(ss0,((SP-4) And &hFFFF),CS1)
writememw_386(ss0,((SP-6) And &hFFFF),pc)
SP-=6
EndIf
addr=num Shl 2
flags = flags And inv(I_FLAG)
flags = flags And inv(T_FLAG)
oxpc=pc
pc=readmemw_386(0,addr)
loadcs(readmemw_386(0,addr+2))
EndIf
cycles-=70
End Sub
' esta rutina viene del modulo 286.C que yo no empleo, pero no se si debe ser asi.
Sub x86illegal()
Dim As UShort addr =Any
'Print #5,"x86 ilegal MSW,CR0,CS,PC,OPCODE:";Hex(msw,4);",";Hex(cr0,8);",";Hex(cs0,4);",";Hex(pc,8);",";Hex(opcode,2)
if modoprotegido Then
pmodeint(6,0)
else
If ssegs Then
ss0=oldss
_ss.limit=oldsslimit
_ss.limitw=oldsslimitw
EndIf
writememw_386(ss0,((SP-2) And &hFFFF),flags)
writememw_386(ss0,((SP-4) And &hFFFF),CS1)
writememw_386(ss0,((SP-6) And &hFFFF),pc)
SP-=6
flags = flags And inv(I_FLAG)
flags = flags And inv(T_FLAG)
addr=6 Shl 2
pc=readmemw_386(0,addr)
loadcs(readmemw_386(0,addr+2))
EndIf
cycles-=70
End Sub
' deteccion del tipo de CPU: LO DEJO SOLO PARA UN i486 (instruccion &hA2)
Sub cpu_CPUID()
' aqui solo llega si CPUID<>0, como es el caso de las 486DX2-66
If (EAX = 0) Then
EAX = &h00000001
EBX = &h756e6547
EDX = &h49656e69
ECX = &h6c65746e
elseif (EAX = 1) then
EAX = CPUID
EBX = 0
ECX = 0
EDX = 1' FPU=SI
Else
EAX = 0
EndIf
End sub
' inicializa CPU
Sub resetx86(reset_cpu As Integer)
Dim a As Integer=Any
' inicializa puertos a FF al completo
For a=0 To 65535
puertosb(a)=&hff
puertosw(a)=&hffff
puertosl(a)=&hffffffff
Next
'resets+=1
ins = 0
use32=0
stack32=0
pc=0
msw=0
cr0=0
eflags=0
cgate32=0
loadcs(&hFFFF)
rammask=&hFFFFFFFF
flags=2
initmmucache() ' CPU cache
resetreadlookup() ' look ahead CPU
makemod1table()
'x87_reset() ' no es necesario
EDX=reset_cpu ' cpu_set_edx()= reset EDX segun tabla de tipo CPU (0x303=386, 0x430=486)
ESP=0
mmu_perm=4
' esto es del PREFETCHCLEAR que estaba en el X86.C pero ¿¿¿SOLO se emplea en el Reset????
'prefetchpc=pc
'prefetchw=0
'memcycs=cycdiff-cycles
'fetchclocks=0
End Sub
' esta rutina la usan el teclado (ctrl+alt+sup) la INS HALT, o las INS que generan errores graves.
' es para problemas gordos, que obligan a reiniciar si o si
Sub softresetx86()
'Print "EL PC SE REINICIA!!!!":Sleep
use32=0
stack32=0
pc=0
msw=0
cr0=0
eflags=0
cgate32=0
loadcs(&hFFFF)
flags=2
End Sub
' primero de todo, inicializa PC
Sub init_PC(bios As String)
keyboard_at_reset()
' inicializa los registros CRTC de la VGA estandar (pone a cero el resto)
resetvideo()
initega()
et4000_init()
svga_init()
'et4000w32p_init() ' este llama a su vez a svga_init()
'et4000w32_reset()
loadCMOS(bios) ' carga el fichero "xxxxxxxx.nvr" de la CMOS
''''''''''
'pc_reset'
''''''''''
cpu_multi=2 ' multiplicador BUS
' comun en 386/486
CPUID=&h433 ' INTEL DX2-66:ver los modelos en "http://datasheets.chipdb.org/Intel/x86/486/Intel486.htm"
' esto es solo para el 486, por ahora, suficiente
' accesos CPU i486DX
timing_rr = 1 'register dest - register src
timing_rm = 2 'register dest - memory src
timing_mr = 3 'memory dest - register src
timing_mm = 3 'memory dest - memory src
timing_rml = 2 'register dest - memory src long
timing_mrl = 3 'memory dest - register src long
timing_mml = 3 'memory dest - memory src
timing_bt = 2 'branch taken
timing_bnt = 1 'branch 0 =taken
'''''''''''''''''''
resetx86(CPUID)
'''''''''''''''''''
dma_reset()
pic_reset()
pit_reset()
serial_reset()
setpitclock(66666666) ' rspeed (aqui arriba) es la velocidad REAL de la CPU (66mhz=66666666=66.666.666)
'''''''''''''''''''''''''''''''''
'install_int_ex(onesec,BPS_TO_TIMER(1)) ' ni idea, pero en WIN-timer.C esta vacio, declarado sin nada
mem_updatecache()
ali1429_reset()
shadowbios=0
makeznptable()
initoplist() ' solo para el DEBUG, la lista de OP del x86 de momento
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' estas rutinas son SOLO para el modulo DMA, y solo hay una llamada
'Sub FETCHCOMPLETE()
' if (fetchcycles And 3)=0 Then return
' if prefetchw>3 Then return 'iif((is8086),4,3)) <<--viejo
' if prefetchw=0 Then nextcyc=(4-(fetchcycles And 3))
' cycles-=(4-(fetchcycles And 3))
' fetchclocks+=(4-(fetchcycles And 3))
'
' 'if (is8086 And 0 =(prefetchpc And 1)) Then
' ' prefetchqueue(prefetchw)=readmembf_x86(cs0+prefetchpc) ' readmembf_x86 es exclusivo de FETCHCOMPLETE, nadie mas lo usa
' ' prefetchpc+=1
' ' prefetchw+=1
' 'EndIf
'
' if (prefetchw<6) Then
' prefetchqueue(prefetchw)=readmembf_x86(cs0+prefetchpc) ' readmembf_x86 es exclusivo de FETCHCOMPLETE, nadie mas lo usa
' prefetchpc+=1
' prefetchw+=1
' EndIf
' fetchcycles+=(4-(fetchcycles And 3))
'End Sub
'Sub refreshread() 'rutina para DMA , llama a FETCHCOMPLETE
' FETCHCOMPLETE()
' memcycs+=4
'End Sub
' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub fetcheal32sib()
Dim As UByte sib
sib=rmdat Shr 8
Select Case As Const (modo)
case 0
eaaddr=regs(sib And 7).l
pc+=1
case 1
eaaddr=CULng(CByte(rmdat Shr 16))+regs(sib And 7).l
pc+=2
case 2
eaaddr=(fastreadl(cs0+pc+1))+regs(sib And 7).l
pc+=5
End Select
'SIB byte present
if ((sib And 7)=5) And (modo=0) Then
eaaddr=getlong()
elseif (sib And 6)=4 Then
easeg=ss0
ea_rseg=SS1
EndIf
if ((sib Shr 3) And 7) <> 4 Then eaaddr+=(regs((sib Shr 3) And 7).l) Shl (sib Shr 6)
End Sub
Sub fetcheal32nosib()
if (rm=5) Then
easeg=ss0
ea_rseg=SS1
EndIf
if (modo=1) Then
eaaddr+=CULng(CByte(rmdat Shr 8))
pc+=1
else
eaaddr+=getlong()
EndIf
End Sub
Sub fetchea32()
eal_r = 0'NULL
eal_w = 0'NULL
if (op32 And &h200) Then
pc+=1
reg=(rmdat Shr 3) And 7
modo=(rmdat Shr 6) And 3
rm=rmdat And 7
if (modo<>3) Then
easeg=ds0
ea_rseg=DS1
if (rm=4) Then
fetcheal32sib()
else
eaaddr=regs(rm).l
if (modo) Then
fetcheal32nosib()
ElseIf (rm=5) Then
eaaddr=getlong()
EndIf
EndIf
if (easeg <> &hFFFFFFFF) And (((easeg + eaaddr) And &hFFF) <= &hFFC) Then
If readlookup2[(easeg + eaaddr) Shr 12] <> &hFFFFFFFF Then
eal_r = @ram[ readlookup2[(easeg + eaaddr) Shr 12] + ((easeg + eaaddr) And &hFFF)]
EndIf
If writelookup2[(easeg + eaaddr) Shr 12] <> &hFFFFFFFF Then
eal_w = @ram[writelookup2[(easeg + eaaddr) Shr 12] + ((easeg + eaaddr) And &hFFF)]
EndIf
EndIf
EndIf
Else
pc+=1
reg=(rmdat Shr 3) And 7
modo=(rmdat Shr 6) And 3
rm=rmdat And 7
if (modo<>3) Then
if (modo=0) And (rm=6) Then
eaaddr=(rmdat Shr 8) And &hFFFF
pc+=2
easeg=ds0
ea_rseg=DS1
Else
Select Case As Const (modo)
case 0
eaaddr=0
Case 1
eaaddr=CUShort(CByte(rmdat Shr 8))
pc+=1
Case 2
eaaddr=getword()
End Select
' coge la direccion de un registro, segun la tabla "makemod1table"
eaaddr+=((*mod1add(0, rm))+(*mod1add(1, rm)))
easeg=*mod1seg(rm)
If mod1seg(rm)= @ss0 Then
ea_rseg=SS1
Else
ea_rseg=DS1
EndIf
eaaddr = eaaddr And &hFFFF
EndIf
if (easeg <> &hFFFFFFFF) And (((easeg + eaaddr) And &hFFF) <= &hFFC) Then
If readlookup2[(easeg + eaaddr) Shr 12] <> &hFFFFFFFF Then
eal_r = @ram[ readlookup2[(easeg + eaaddr) Shr 12] + ((easeg + eaaddr) And &hFFF)]
EndIf
If writelookup2[(easeg + eaaddr) Shr 12] <> &hFFFFFFFF Then
eal_w = @ram[writelookup2[(easeg + eaaddr) Shr 12] + ((easeg + eaaddr) And &hFFF)]
EndIf
EndIf
EndIf
EndIf
End Sub
sub fetchea2()
rmdat=fastreadl(cs0+pc)
fetchea32()
'if abrt break : al salir, debe romper el "select case"
End Sub
' tabla de almacen de registros, para luego acceder a ellos mediante punteros
Sub makemod1table()
mod1add(0, 0)= @BX: mod1add(0, 1)= @BX: mod1add(0, 2)= @BP: mod1add(0, 3)= @BP
mod1add(0, 4)= @SI: mod1add(0, 5)= @DI: mod1add(0, 6)= @BP: mod1add(0, 7)= @BX
mod1add(1, 0)= @SI: mod1add(1, 1)= @DI: mod1add(1, 2)= @SI: mod1add(1, 3)= @DI
mod1add(1, 4)= @zero: mod1add(1, 5)= @zero: mod1add(1, 6)= @zero: mod1add(1, 7)= @zero
slowrm(0)=0: slowrm(1)=1: slowrm(2)=1: slowrm(3)=0
mod1seg(0)= @ds0: mod1seg(1)= @ds0: mod1seg(2)= @ss0: mod1seg(3)= @ss0
mod1seg(4)= @ds0: mod1seg(5)= @ds0: mod1seg(6)= @ss0: mod1seg(7)= @ds0
End Sub
/'Flags'/
Sub makeznptable()
Dim As Integer c,d
'Print"Creando tabla Zero-Not-Parity"
for c=0 To 255
d=0
if (c And 1) Then d+=1
if (c And 2) Then d+=1
if (c And 4) Then d+=1
if (c And 8) Then d+=1
if (c And 16) Then d+=1
if (c And 32) Then d+=1
if (c And 64) Then d+=1
if (c And 128) Then d+=1
if (d And 1) Then
znptable8(c)=0
else
znptable8(c)=P_FLAG 'P_FLAG=&h0004
EndIf
'If (c = &hb1) Then print "znp8 b1 ", d, znptable8(c)
if (c =0) Then znptable8(c) Or= Z_FLAG 'Z_FLAG=&h0040
if (c And &h80) Then znptable8(c) or= N_FLAG 'N_FLAG=&h0080
Next
for c=0 To 65535
d=0
if (c And 1) Then d+=1
if (c And 2) Then d+=1
if (c And 4) Then d+=1
if (c And 8) Then d+=1
if (c And 16) Then d+=1
if (c And 32) Then d+=1
if (c And 64) Then d+=1
if (c And 128) Then d+=1
if (d And 1) Then
znptable16(c)=0
else
znptable16(c)=P_FLAG
EndIf
'If (c = &hb1) Then print "znp16 b1 ", d, znptable16(c)
'if (c = &h65b1) Then print "znp16 65b1 ", d, znptable16(c)
if (c =0) Then znptable16(c) or= Z_FLAG
if (c And &h8000) Then znptable16(c) or= N_FLAG
Next
End Sub
function NOTRM() As Byte
if (modoprotegido=0) Or ((eflags and VM_FLAG)<>0) Then x86_int(6): Return 1
Return 0
End Function