1
/*
2
Copyright (c) 2019-2021 Andreas T Jonsson
3

4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any damages
6
arising from the use of this software.
7

8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
10
freely, subject to the following restrictions:
11

12
1. The origin of this software must not be misrepresented; you must not
13
   claim that you wrote the original software. If you use this software
14
   in a product, an acknowledgment in the product documentation would be
15
   appreciated but is not required.
16
2. Altered source versions must be plainly marked as such, and must not be
17
   misrepresented as being the original software.
18
3. This notice may not be removed or altered from any source distribution.
19
*/
20

21
package cpu
22

23
import (
24
	"log"
25
	"runtime"
26
	"time"
27

28
	"github.com/andreas-jonsson/virtualxt/emulator/memory"
29
	"github.com/andreas-jonsson/virtualxt/emulator/processor"
30
	"github.com/andreas-jonsson/virtualxt/emulator/processor/validator"
31
)
32

33
var zero16 uint16
34

35
type instructionState struct {
36
	opcode, modRegRM,
37
	repeatMode byte
38

39
	isWide, rmToReg,
40
	halted bool
41

42
	decodeAt    uint16
43
	segOverride *uint16
44
	cycleCount  int
45
}
46

47
func (p *CPU) getReg() byte {
48 6
	return (p.modRegRM >> 3) & 7
49
}
50

51
func (p *CPU) regLocation() dataLocation {
52 6
	return dataLocation(p.getReg()) | registerLocation
53
}
54

55
func (p *CPU) segLocation() dataLocation {
56 6
	return dataLocation(p.getReg()) | segmentLocation
57
}
58

59
func (p *CPU) rmLocation() dataLocation {
60 6
	idx := p.modRegRM & 0xC7
61 6
	f := modRMLookup[idx]
62 6
	return f(p)
63
}
64

65
func (p *CPU) peakOpcodeStream() byte {
66 6
	return p.ReadByte(memory.NewPointer(p.CS, p.IP))
67
}
68

69
func (p *CPU) readOpcodeStream() byte {
70 6
	v := p.peakOpcodeStream()
71 6
	p.IP++
72 6
	return v
73
}
74

75
func (p *CPU) readOpcodeImm16() uint16 {
76 6
	v := p.ReadWord(memory.NewPointer(p.CS, p.IP))
77 6
	p.IP += 2
78 6
	return v
79
}
80

81
func (p *CPU) readModRegRM() {
82 6
	p.modRegRM = p.readOpcodeStream()
83
}
84

85
func (p *CPU) parseOperands() (dataLocation, dataLocation) {
86 6
	p.readModRegRM()
87 6
	reg, rm := p.regLocation(), p.rmLocation()
88 6
	if p.rmToReg {
89 6
		return reg, rm
90
	}
91 6
	return rm, reg
92
}
93

94
func (p *CPU) parseOpcode() {
95 6
	p.segOverride = nil
96 6
	p.repeatMode = 0
97 6
	p.decodeAt = p.IP
98

99 6
	var op byte
100 6
loop:
101
	for {
102 6
		switch op = p.readOpcodeStream(); op {
103 6
		case 0x26: // ES:
104 6
			p.segOverride = &p.ES
105 6
		case 0x2E: // CS:
106 6
			p.segOverride = &p.CS
107 6
		case 0x36: // SS:
108 6
			p.segOverride = &p.SS
109 0
		case 0x3E: // DS:
110 0
			p.segOverride = &p.DS
111 0
		case 0xF0: // LOCK
112
			// NOP...
113 0
		case 0xF1:
114
			//log.Printf("Unsupported instruction prefix: 0x%X", op)
115
			//p.invalidOpcode()
116
			//break loop
117 6
		case 0xF2, 0xF3: // REPNE/REPNZ,REP/REPE/REPZ
118 6
			p.repeatMode = op
119 6
		default:
120 6
			break loop
121
		}
122
	}
123

124 6
	p.opcode = op
125 6
	p.isWide = op&1 != 0
126 6
	p.rmToReg = op&2 != 0
127
}
128

129
func (p *CPU) packFlags8() byte {
130 6
	var flags byte = 0x2
131 6
	if p.CF {
132 6
		flags |= 0x001
133
	}
134 6
	if p.PF {
135 6
		flags |= 0x004
136
	}
137 6
	if p.AF {
138 6
		flags |= 0x010
139
	}
140 6
	if p.ZF {
141 6
		flags |= 0x040
142
	}
143 6
	if p.SF {
144 6
		flags |= 0x080
145
	}
146 6
	return flags
147
}
148

149
func (p *CPU) packFlags16() uint16 {
150 6
	flags := uint16(p.packFlags8())
151 6
	if p.TF {
152 0
		flags |= 0x100
153
	}
154 6
	if p.IF {
155 6
		flags |= 0x200
156
	}
157 6
	if p.DF {
158 6
		flags |= 0x400
159
	}
160 6
	if p.OF {
161 6
		flags |= 0x800
162
	}
163 6
	return flags
164
}
165

166
func (p *CPU) unpackFlags8(flags byte) {
167 6
	p.CF = flags&0x001 != 0
168 6
	p.PF = flags&0x004 != 0
169 6
	p.AF = flags&0x010 != 0
170 6
	p.ZF = flags&0x040 != 0
171 6
	p.SF = flags&0x080 != 0
172
}
173

174
func (p *CPU) unpackFlags16(flags uint16) {
175 6
	p.unpackFlags8(byte(flags & 0xFF))
176 6
	p.TF = flags&0x100 != 0
177 6
	p.IF = flags&0x200 != 0
178 6
	p.DF = flags&0x400 != 0
179 6
	p.OF = flags&0x800 != 0
180
}
181

182
func signExtend16(v byte) uint16 {
183 6
	if v&0x80 != 0 {
184 6
		return uint16(v) | 0xFF00
185
	}
186 6
	return uint16(v)
187
}
188

189
func signExtend32(v uint16) uint32 {
190 6
	if v&0x8000 != 0 {
191 6
		return uint32(v) | 0xFFFF0000
192
	}
193 6
	return uint32(v)
194
}
195

196
func (p *CPU) stackTop() memory.Pointer {
197 6
	return memory.NewPointer(p.SS, p.SP)
198
}
199

200
func (p *CPU) push16(v uint16) {
201 6
	p.SP -= 2
202 6
	p.WriteWord(p.stackTop(), v)
203
}
204

205
func (p *CPU) pop16() uint16 {
206 6
	v := p.ReadWord(p.stackTop())
207 6
	p.SP += 2
208 6
	return v
209
}
210

211
func (p *CPU) updateFlagsSZP8(res byte) {
212 6
	p.SF = res&0x80 != 0
213 6
	p.ZF = res == 0
214 6
	p.PF = parityLookup[res]
215
}
216

217
func (p *CPU) updateFlagsSZP16(res uint16) {
218 6
	p.SF = res&0x8000 != 0
219 6
	p.ZF = res == 0
220 6
	p.PF = parityLookup[res&0xFF]
221
}
222

223
func (p *CPU) getFlagsMask() (uint32, uint32) {
224 6
	maskC := uint32(0xFF00)
225 6
	maskO := uint32(0x0080)
226 6
	if p.isWide {
227 6
		maskC = 0xFFFF0000
228 6
		maskO = 0x00008000
229
	}
230 6
	return maskC, maskO
231
}
232

233
func (p *CPU) clearFlagsOC() {
234 6
	p.CF = false
235 6
	p.OF = false
236
}
237

238
func (p *CPU) updateFlagsOSZPCLog8(res byte) {
239 6
	p.updateFlagsSZP8(res)
240 6
	p.clearFlagsOC()
241
}
242

243
func (p *CPU) updateFlagsOSZPCLog16(res uint16) {
244 6
	p.updateFlagsSZP16(res)
245 6
	p.clearFlagsOC()
246
}
247

248
func (p *CPU) updateFlagsOACAdd(res, a, b uint32) {
249 6
	maskC, maskO := p.getFlagsMask()
250 6
	p.CF = res&maskC != 0
251 6
	p.AF = ((a ^ b ^ res) & 0x10) == 0x10
252 6
	p.OF = ((res ^ a) & (res ^ b) & maskO) == maskO
253
}
254

255
func (p *CPU) updateFlagsOACSub(res, a, b uint32) {
256 6
	maskC, maskO := p.getFlagsMask()
257 6
	p.CF = res&maskC != 0
258 6
	p.AF = ((a ^ b ^ res) & 0x10) != 0
259 6
	p.OF = ((res ^ a) & (a ^ b) & maskO) != 0
260
}
261

262
func (p *CPU) updateFlagsOACSubCarry(res, a, b uint32) {
263 6
	b += b2ui32(p.CF)
264 6
	p.updateFlagsOACSub(res, a, b)
265
}
266

267
func b2ui16(b bool) uint16 {
268 6
	if b {
269 6
		return 1
270
	}
271 6
	return 0
272
}
273

274
func b2ui32(b bool) uint32 {
275 6
	return uint32(b2ui16(b))
276
}
277

278
func opXCHG(a, b *uint16) {
279 6
	tmp := *a
280 6
	*a = *b
281 6
	*b = tmp
282
}
283

284
func (p *CPU) getSeg(seg uint16) uint16 {
285 6
	if p.segOverride != nil {
286 6
		return *p.segOverride
287
	}
288 6
	return seg
289
}
290

291
func (p *CPU) divisionByZero() {
292 6
	p.IP = p.decodeAt
293 6
	p.doInterrupt(0)
294
}
295

296
func (p *CPU) doInterrupt(n int) {
297 6
	p.stats.NumInterrupts++
298 6
	validator.Discard()
299

300 6
	p.halted = false
301

302 6
	if handler := p.interceptors[n]; handler != nil {
303 0
		if err := handler.HandleInterrupt(n); err == nil {
304 0
			p.TF, p.IF = false, false
305 0
			return
306 0
		} else if err != processor.ErrInterruptNotHandled {
307 0
			log.Panic(err)
308
		}
309
	}
310

311 6
	p.push16(p.packFlags16())
312 6
	p.push16(p.CS)
313 6
	p.push16(p.IP)
314

315 6
	offset := n * 4
316 6
	p.CS = p.ReadWord(memory.Pointer(offset + 2))
317 6
	p.IP = p.ReadWord(memory.Pointer(offset))
318 6
	p.TF, p.IF = false, false
319
}
320

321
func (p *CPU) Step() (int, error) {
322
	// Reset cycle counter.
323 6
	p.cycleCount = 0
324

325 6
	if p.trap {
326 0
		p.doInterrupt(1)
327
	}
328 6
	p.trap = p.TF
329

330 6
	if !p.trap && p.IF {
331 6
		if n, err := p.pic.GetInterrupt(); err == nil {
332 0
			p.doInterrupt(n)
333
		}
334
	}
335

336 6
	if p.halted {
337 6
		return 0, processor.ErrCPUHalt
338
	}
339

340 6
	p.parseOpcode()
341 6
	if p.repeatMode != 0 {
342 6
		err := p.doRepeat()
343 6
		return p.cycleCount, err
344
	}
345

346 6
	validator.Begin(p.opcode, p.Registers)
347 6
	if err := p.execute(); err != nil {
348 0
		return p.cycleCount, err
349
	}
350 6
	validator.End(p.Registers)
351

352
	for _, d := range p.peripherals {
353 6
		if err := d.Step(p.cycleCount); err != nil {
354 0
			return p.cycleCount, err
355
		}
356
	}
357 6
	return p.cycleCount, nil
358
}
359

360
func (p *CPU) execute() error {
361
	// All instructions are 1 cycle right now.
362 6
	p.cycleCount++
363

364 6
	op := p.opcode
365 6
	carry := op > 0x0F && p.CF
366 6
	carryOp := b2ui32(carry)
367

368 6
	switch op {
369 6
	case 0x00, 0x02, 0x10, 0x12: // ADD/ADC r/m8,r8
370 6
		dest, src := p.parseOperands()
371 6
		a, b := uint32(dest.readByte(p)), uint32(src.readByte(p))
372 6
		res := a + b + carryOp
373 6
		dest.writeByte(p, byte(res))
374 6
		p.updateFlagsSZP8(byte(res))
375 6
		p.updateFlagsOACAdd(res, a, b)
376 6
	case 0x01, 0x03, 0x11, 0x13: // ADD/ADC r/m16,r16
377 6
		dest, src := p.parseOperands()
378 6
		a, b := uint32(dest.readWord(p)), uint32(src.readWord(p))
379 6
		res := a + b + carryOp
380 6
		dest.writeWord(p, uint16(res))
381 6
		p.updateFlagsSZP16(uint16(res))
382 6
		p.updateFlagsOACAdd(res, a, b)
383 6
	case 0x04, 0x14: // ADD/ADC AL,d8
384 6
		a, b := uint32(p.AL()), uint32(p.readOpcodeStream())
385 6
		res := a + b + carryOp
386 6
		p.SetAL(byte(res))
387 6
		p.updateFlagsSZP8(byte(res))
388 6
		p.updateFlagsOACAdd(res, a, b)
389 6
	case 0x05, 0x15: // ADD/ADC AX,d16
390 6
		a, b := uint32(p.AX), uint32(p.readOpcodeImm16())
391 6
		res := a + b + carryOp
392 6
		p.AX = uint16(res)
393 6
		p.updateFlagsSZP16(uint16(res))
394 6
		p.updateFlagsOACAdd(res, a, b)
395 6
	case 0x06: // PUSH ES
396 6
		p.push16(p.ES)
397 6
	case 0x07: // POP ES
398 6
		p.ES = p.pop16()
399 6
	case 0x08, 0x0A: // OR r/m8,r8
400 6
		dest, src := p.parseOperands()
401 6
		a, b := dest.readByte(p), src.readByte(p)
402 6
		res := a | b
403 6
		dest.writeByte(p, res)
404 6
		p.updateFlagsOSZPCLog8(res)
405 6
	case 0x09, 0x0B: // OR r/m16,r16
406 6
		dest, src := p.parseOperands()
407 6
		a, b := dest.readWord(p), src.readWord(p)
408 6
		res := a | b
409 6
		dest.writeWord(p, res)
410 6
		p.updateFlagsOSZPCLog16(res)
411 6
	case 0x0C: // OR AL,d8
412 6
		a, b := p.AL(), p.readOpcodeStream()
413 6
		res := a | b
414 6
		p.SetAL(res)
415 6
		p.updateFlagsOSZPCLog8(res)
416 6
	case 0x0D: // OR AX,d16
417 6
		p.AX = p.AX | p.readOpcodeImm16()
418 6
		p.updateFlagsOSZPCLog16(p.AX)
419 0
	case 0x0E: // PUSH CS
420 0
		p.push16(p.CS)
421 0
	case 0x0F: // *POP CS
422 0
		if !p.isV20 {
423 0
			p.CS = p.pop16()
424
		}
425

426
	// 0x1x
427

428 0
	case 0x16: // PUSH SS
429 0
		p.push16(p.SS)
430 0
	case 0x17: // POP SS
431 0
		p.SS = p.pop16()
432 6
	case 0x18, 0x1A: // SBB r/m8,r8
433 6
		dest, src := p.parseOperands()
434 6
		a, b := uint32(dest.readByte(p)), uint32(src.readByte(p))
435 6
		res := a - (b + carryOp)
436 6
		dest.writeByte(p, byte(res))
437 6
		p.updateFlagsSZP8(byte(res))
438 6
		p.updateFlagsOACSubCarry(res, a, b)
439 6
	case 0x19, 0x1B: // SBB r/m16,r16
440 6
		dest, src := p.parseOperands()
441 6
		a, b := uint32(dest.readWord(p)), uint32(src.readWord(p))
442 6
		res := a - (b + carryOp)
443 6
		dest.writeWord(p, uint16(res))
444 6
		p.updateFlagsSZP16(uint16(res))
445 6
		p.updateFlagsOACSubCarry(res, a, b)
446 6
	case 0x1C: // SBB AL,d8
447 6
		a, b := uint32(p.AL()), uint32(p.readOpcodeStream())
448 6
		res := a - (b + carryOp)
449 6
		p.SetAL(byte(res))
450 6
		p.updateFlagsSZP8(byte(res))
451 6
		p.updateFlagsOACSubCarry(res, a, b)
452 0
	case 0x1D: // SBB AX,d16
453 0
		a, b := uint32(p.AX), uint32(p.readOpcodeImm16())
454 0
		res := a - (b + carryOp)
455 0
		p.updateFlagsSZP16(uint16(res))
456 0
		p.updateFlagsOACSubCarry(res, a, b)
457 0
	case 0x1E: // PUSH DS
458 0
		p.push16(p.DS)
459 0
	case 0x1F: // POP DS
460 0
		p.DS = p.pop16()
461

462
	// 0x2x
463

464 6
	case 0x20, 0x22: // AND r/m8,r8
465 6
		dest, src := p.parseOperands()
466 6
		a, b := dest.readByte(p), src.readByte(p)
467 6
		res := uint16(a) & uint16(b)
468 6
		dest.writeByte(p, byte(res))
469 6
		p.updateFlagsOSZPCLog8(byte(res))
470 6
	case 0x21, 0x23: // AND r/m16,r16
471 6
		dest, src := p.parseOperands()
472 6
		a, b := dest.readWord(p), src.readWord(p)
473 6
		res := uint32(a) & uint32(b)
474 6
		dest.writeWord(p, uint16(res))
475 6
		p.updateFlagsOSZPCLog16(uint16(res))
476 6
	case 0x24: // AND AL,d8
477 6
		a, b := p.AL(), p.readOpcodeStream()
478 6
		res := uint16(a) & uint16(b)
479 6
		p.SetAL(byte(res))
480 6
		p.updateFlagsOSZPCLog8(byte(res))
481 6
	case 0x25: // AND AX,d16
482 6
		b := p.readOpcodeImm16()
483 6
		res := uint32(p.AX) & uint32(b)
484 6
		p.AX = uint16(res)
485 6
		p.updateFlagsOSZPCLog16(uint16(res))
486 6
	case 0x27: // DAA
487 6
		if al := p.AL(); ((al & 0xF) > 9) || p.AF {
488 6
			v := uint16(al) + 6
489 6
			p.SetAL(byte(v & 0xFF))
490 6
			p.CF = (v & 0xFF00) != 0
491 6
			p.AF = true
492 6
		} else {
493 6
			p.AF = false
494
		}
495

496 6
		if al := p.AL(); ((al & 0xF0) > 0x90) || p.CF {
497 6
			p.SetAL(al + 0x60)
498 6
			p.CF = true
499 6
		} else {
500 6
			p.CF = false
501
		}
502

503 6
		al := p.AL()
504 6
		p.SetAL(al)
505 6
		p.updateFlagsSZP8(al)
506 6
	case 0x28, 0x2A: // SUB r/m8,r8
507 6
		dest, src := p.parseOperands()
508 6
		a, b := uint32(dest.readByte(p)), uint32(src.readByte(p))
509 6
		res := a - b
510 6
		dest.writeByte(p, byte(res))
511 6
		p.updateFlagsSZP8(byte(res))
512 6
		p.updateFlagsOACSub(res, a, b)
513 6
	case 0x29, 0x2B: // SUB r/m16,r16
514 6
		dest, src := p.parseOperands()
515 6
		a, b := uint32(dest.readWord(p)), uint32(src.readWord(p))
516 6
		res := a - b
517 6
		dest.writeWord(p, uint16(res))
518 6
		p.updateFlagsSZP16(uint16(res))
519 6
		p.updateFlagsOACSub(res, a, b)
520 6
	case 0x2C: // SUB AL,d8
521 6
		a, b := uint32(p.AL()), uint32(p.readOpcodeStream())
522 6
		res := a - b
523 6
		p.SetAL(byte(res))
524 6
		p.updateFlagsSZP8(byte(res))
525 6
		p.updateFlagsOACSub(res, a, b)
526 0
	case 0x2D: // SUB AX,d16
527 0
		a, b := uint32(p.AX), uint32(p.readOpcodeImm16())
528 0
		res := a - b
529 0
		p.AX = uint16(res)
530 0
		p.updateFlagsSZP16(uint16(res))
531 0
		p.updateFlagsOACSub(res, a, b)
532 6
	case 0x2F: // DAS
533 6
		if al := p.AL(); ((al & 15) > 9) || p.AF {
534 6
			v := uint16(al) - 6
535 6
			p.SetAL(byte(v & 0xFF))
536 6
			p.CF = (v & 0xFF00) != 0
537 6
			p.AF = true
538 6
		} else {
539 6
			p.AF = false
540
		}
541

542 6
		if al := p.AL(); ((al & 0xF0) > 0x90) || p.CF {
543 6
			p.SetAL(al - 0x60)
544 6
			p.CF = true
545 6
		} else {
546 6
			p.CF = false
547
		}
548 6
		p.updateFlagsSZP8(p.AL())
549

550
	// 0x3x
551

552 6
	case 0x30, 0x32: // XOR r/m8,r8
553 6
		dest, src := p.parseOperands()
554 6
		a, b := dest.readByte(p), src.readByte(p)
555 6
		res := uint16(a) ^ uint16(b)
556 6
		dest.writeByte(p, byte(res))
557 6
		p.updateFlagsOSZPCLog8(byte(res))
558 6
	case 0x31, 0x33: // XOR r/m16,r16
559 6
		dest, src := p.parseOperands()
560 6
		a, b := dest.readWord(p), src.readWord(p)
561 6
		res := uint32(a) ^ uint32(b)
562 6
		dest.writeWord(p, uint16(res))
563 6
		p.updateFlagsOSZPCLog16(uint16(res))
564 6
	case 0x34: // XOR AL,d8
565 6
		a, b := p.AL(), p.readOpcodeStream()
566 6
		res := uint16(a) ^ uint16(b)
567 6
		p.SetAL(byte(res))
568 6
		p.updateFlagsOSZPCLog8(byte(res))
569 6
	case 0x35: // XOR AX,d16
570 6
		b := p.readOpcodeImm16()
571 6
		res := uint32(p.AX) ^ uint32(b)
572 6
		p.AX = uint16(res)
573 6
		p.updateFlagsOSZPCLog16(uint16(res))
574 6
	case 0x37: // AAA
575 6
		if al := p.AL(); ((al & 0xF) > 9) || p.AF {
576 6
			p.SetAL(al + 6)
577 6
			p.SetAH(p.AH() + 1)
578 6
			p.AF, p.CF = true, true
579 6
		} else {
580 6
			p.AF, p.CF = false, false
581
		}
582 6
		al := p.AL() & 0xF
583 6
		p.SetAL(al)
584 6
		p.updateFlagsSZP8(al)
585 6
	case 0x38, 0x3A: // CMP r/m8,r8
586 6
		dest, src := p.parseOperands()
587 6
		a, b := uint32(dest.readByte(p)), uint32(src.readByte(p))
588 6
		res := a - b
589 6
		p.updateFlagsOACSub(res, a, b)
590 6
		p.updateFlagsSZP8(byte(res))
591 6
	case 0x39, 0x3B: // CMP r/m16,r16
592 6
		dest, src := p.parseOperands()
593 6
		a, b := uint32(dest.readWord(p)), uint32(src.readWord(p))
594 6
		res := a - b
595 6
		p.updateFlagsOACSub(res, a, b)
596 6
		p.updateFlagsSZP16(uint16(res))
597 6
	case 0x3C: // CMP AL,d8
598 6
		a, b := uint32(p.AL()), uint32(p.readOpcodeStream())
599 6
		res := a - b
600 6
		p.updateFlagsOACSub(res, a, b)
601 6
		p.updateFlagsSZP8(byte(res))
602 0
	case 0x3D: // CMP AX,d16
603 0
		a, b := uint32(p.AX), uint32(p.readOpcodeImm16())
604 0
		res := a - b
605 0
		p.updateFlagsOACSub(res, a, b)
606 0
		p.updateFlagsSZP16(uint16(res))
607 6
	case 0x3F: // AAS
608 6
		if al := p.AL(); ((al & 0xF) > 9) || p.AF {
609 6
			p.SetAL(al - 6)
610 6
			p.SetAH(p.AH() - 1)
611 6
			p.AF, p.CF = true, true
612 6
		} else {
613 6
			p.AF, p.CF = false, false
614
		}
615 6
		al := p.AL() & 0xF
616 6
		p.SetAL(al)
617 6
		p.updateFlagsSZP8(al)
618

619
	// 0x4x
620

621 6
	case 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47: // INC AX/CX/DX/BX/SP/BP/SI/DI
622 6
		reg := dataLocation(op-0x40) | registerLocation
623 6
		a := reg.readWord(p)
624 6
		res := a + 1
625 6
		reg.writeWord(p, res)
626

627 6
		cf := p.CF
628 6
		p.updateFlagsOACAdd(uint32(res), uint32(a), 1)
629 6
		p.updateFlagsSZP16(res)
630 6
		p.CF = cf
631 6
	case 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F: // DEC AX/CX/DX/BX/SP/BP/SI/DI
632 6
		reg := dataLocation(op-0x40) | registerLocation
633 6
		a := reg.readWord(p)
634 6
		res := a - 1
635 6
		reg.writeWord(p, res)
636

637 6
		cf := p.CF
638 6
		p.updateFlagsOACSub(uint32(res), uint32(a), 1)
639 6
		p.updateFlagsSZP16(res)
640 6
		p.CF = cf
641

642
	// 0x5x
643

644 6
	case 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57: // PUSH AX/CX/DX/BX/SP/BP/SI/DI
645 6
		p.push16((dataLocation(op-0x50) | registerLocation).readWord(p))
646 6
	case 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F: // POP AX/CX/DX/BX/SP/BP/SI/DI
647 6
		(dataLocation(op-0x58) | registerLocation).writeWord(p, p.pop16())
648

649
	// 0x6x
650

651 0
	case 0x60: // PUSHA (80186)
652 0
		if p.isV20 {
653 0
			sp := p.SP
654 0
			p.push16(p.AX)
655 0
			p.push16(p.CX)
656 0
			p.push16(p.DX)
657 0
			p.push16(p.BX)
658 0
			p.push16(sp)
659 0
			p.push16(p.BP)
660 0
			p.push16(p.SI)
661 0
			p.push16(p.DI)
662 0
		} else {
663 0
			p.invalidOpcode()
664
		}
665 0
	case 0x61: // POPA (80186)
666 0
		if p.isV20 {
667 0
			p.DI = p.pop16()
668 0
			p.SI = p.pop16()
669 0
			p.BP = p.pop16()
670 0
			p.pop16()
671 0
			p.BX = p.pop16()
672 0
			p.DX = p.pop16()
673 0
			p.CX = p.pop16()
674 0
			p.AX = p.pop16()
675 0
		} else {
676 0
			p.invalidOpcode()
677
		}
678 0
	case 0x62: // BOUND (80186)
679 0
		if p.isV20 {
680 0
			p.readModRegRM()
681 0
			idx := signExtend32(p.regLocation().readWord(p))
682 0
			addr := p.rmLocation().getAddress()
683

684 0
			if idx < signExtend32(p.ReadWord(addr.Pointer())) || idx > signExtend32(p.ReadWord(addr.AddInt(2).Pointer())) {
685 0
				p.IP = p.decodeAt
686 0
				p.doInterrupt(5)
687
			}
688 0
		} else {
689 0
			p.invalidOpcode()
690
		}
691 0
	case 0x69, 0x6B: // IMUL r/m16,d8/d16 (80186)
692 0
		if p.isV20 {
693 0
			p.readModRegRM()
694 0
			dest := p.rmLocation()
695 0
			a := signExtend32(dest.readWord(p))
696

697 0
			var res uint32
698 0
			if op == 69 {
699 0
				res = a * signExtend32(signExtend16(p.readOpcodeStream()))
700 0
			} else {
701 0
				res = a * signExtend32(p.readOpcodeImm16())
702
			}
703 0
			res16 := uint16(res & 0xFFFF)
704 0
			upper := uint16(res >> 16)
705

706 0
			dest.writeWord(p, res16)
707 0
			p.updateFlagsSZP16(res16)
708

709 0
			if res16&0x8000 == 0x8000 {
710 0
				p.CF = upper != 0xFFFF
711 0
			} else {
712 0
				p.CF = upper != 0x0
713
			}
714 0
			p.OF = p.CF
715 0
		} else {
716 0
			p.invalidOpcode()
717
		}
718 0
	case 0x68, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F:
719 0
		if p.isV20 {
720 0
			log.Printf("opcode not implemented: 0x%X", op)
721 0
			p.Break()
722 0
		} else {
723 0
			p.invalidOpcode()
724
		}
725

726
	// 0x7x
727

728 6
	case 0x70: // JO rel8
729 6
		p.jmpRel8Cond(p.OF)
730 6
	case 0x71: // JNO rel8
731 6
		p.jmpRel8Cond(!p.OF)
732 6
	case 0x72: // JB/JNAE rel8
733 6
		p.jmpRel8Cond(p.CF)
734 6
	case 0x73: // JNB/JAE rel8
735 6
		p.jmpRel8Cond(!p.CF)
736 6
	case 0x74: // JE/JZ rel8
737 6
		p.jmpRel8Cond(p.ZF)
738 6
	case 0x75: // JNE/JNZ rel8
739 6
		p.jmpRel8Cond(!p.ZF)
740 6
	case 0x76: // JBE/JNA rel8
741 6
		p.jmpRel8Cond(p.CF || p.ZF)
742 6
	case 0x77: // JNBE/JA rel8
743 6
		p.jmpRel8Cond(!p.CF && !p.ZF)
744 6
	case 0x78: // JS rel8
745 6
		p.jmpRel8Cond(p.SF)
746 6
	case 0x79: // JNS rel8
747 6
		p.jmpRel8Cond(!p.SF)
748 6
	case 0x7A: // JP/JPE rel8
749 6
		p.jmpRel8Cond(p.PF)
750 6
	case 0x7B: // JNP/JPO rel8
751 6
		p.jmpRel8Cond(!p.PF)
752 6
	case 0x7C: // JL/JNGE rel8
753 6
		p.jmpRel8Cond(p.SF != p.OF)
754 6
	case 0x7D: // JNL/JGE rel8
755 6
		p.jmpRel8Cond(p.SF == p.OF)
756 6
	case 0x7E: // JLE/JNG rel8
757 6
		p.jmpRel8Cond(p.SF != p.OF || p.ZF)
758 6
	case 0x7F: // JNLE/JG rel8
759 6
		p.jmpRel8Cond(!p.ZF && p.SF == p.OF)
760

761
	// 0x8x
762

763 6
	case 0x80, 0x82: // _ALU1 r/m8,d8
764 6
		p.grp1()
765 6
	case 0x81, 0x83: // _ALU1 r/m16,d16
766 6
		p.grp1w()
767 6
	case 0x84: // TEST r/m8,r8
768 6
		p.readModRegRM()
769 6
		a, b := p.rmLocation().readByte(p), p.regLocation().readByte(p)
770 6
		p.updateFlagsOSZPCLog8(a & b)
771 6
	case 0x85: // TEST r/m16,r16
772 6
		p.readModRegRM()
773 6
		a, b := p.rmLocation().readWord(p), p.regLocation().readWord(p)
774 6
		p.updateFlagsOSZPCLog16(a & b)
775 6
	case 0x86: // XCHG r8,r/m8
776 6
		p.readModRegRM()
777 6
		dst, src := p.regLocation(), p.rmLocation()
778 6
		d, s := dst.readByte(p), src.readByte(p)
779 6
		dst.writeByte(p, s)
780 6
		src.writeByte(p, d)
781 6
	case 0x87: // XCHG r16,r/m16
782 6
		p.readModRegRM()
783 6
		dst, src := p.regLocation(), p.rmLocation()
784 6
		d, s := dst.readWord(p), src.readWord(p)
785 6
		dst.writeWord(p, s)
786 6
		src.writeWord(p, d)
787 6
	case 0x88, 0x8A: // MOV r/m8,r8
788 6
		dest, src := p.parseOperands()
789 6
		dest.writeByte(p, src.readByte(p))
790 6
	case 0x89, 0x8B: // MOV r/m16,r16
791 6
		dest, src := p.parseOperands()
792 6
		dest.writeWord(p, src.readWord(p))
793 6
	case 0x8C: // _MOV r/m16,sr
794 6
		p.readModRegRM()
795 6
		p.rmLocation().writeWord(p, p.segLocation().readWord(p))
796 6
	case 0x8D: // LEA r16,r/m16
797 6
		p.readModRegRM()
798 6
		p.segOverride = &zero16
799 6
		addr := p.rmLocation().getPointer()
800 6
		p.regLocation().writeWord(p, uint16(addr))
801 6
	case 0x8E: // _MOV sr,r/m16
802 6
		p.readModRegRM()
803 6
		p.segLocation().writeWord(p, p.rmLocation().readWord(p))
804 6
	case 0x8F: // _POP r/m16
805 6
		p.readModRegRM()
806 6
		p.rmLocation().writeWord(p, p.pop16())
807

808
	// 0x9x
809

810 6
	case 0x90: // NOP
811 6
		p.stats.NOP++
812 0
	case 0x91: // XCHG AX,CX
813 0
		opXCHG(&p.AX, &p.CX)
814 0
	case 0x92: // XCHG AX,DX
815 0
		opXCHG(&p.AX, &p.DX)
816 6
	case 0x93: // XCHG AX,BX
817 6
		opXCHG(&p.AX, &p.BX)
818 0
	case 0x94: // XCHG AX,SP
819 0
		opXCHG(&p.AX, &p.SP)
820 0
	case 0x95: // XCHG AX,BP
821 0
		opXCHG(&p.AX, &p.BP)
822 0
	case 0x96: // XCHG AX,SI
823 0
		opXCHG(&p.AX, &p.SI)
824 0
	case 0x97: // XCHG AX,DI
825 0
		opXCHG(&p.AX, &p.DI)
826 6
	case 0x98: // CBW
827 6
		p.AX = signExtend16(p.AL())
828 6
	case 0x99: // CWD
829 6
		if p.AX&0x8000 != 0 {
830 6
			p.DX = 0xFFFF
831 6
		} else {
832 6
			p.DX = 0
833
		}
834 6
	case 0x9A: // CALL seg:a16
835 6
		ip := p.readOpcodeImm16()
836 6
		cs := p.readOpcodeImm16()
837 6
		p.push16(p.CS)
838 6
		p.push16(p.IP)
839 6
		p.IP, p.CS = ip, cs
840 0
	case 0x9B: // WAIT
841 6
	case 0x9C: // PUSHF
842 6
		p.push16(p.packFlags16())
843 6
	case 0x9D: // POPF
844 6
		p.unpackFlags16(p.pop16())
845 6
	case 0x9E: // SAHF
846 6
		p.unpackFlags8(p.AH())
847 6
	case 0x9F: // LAHF
848 6
		p.SetAH(p.packFlags8())
849

850
	// 0xAx
851

852 0
	case 0xA0: // MOV AL,[addr]
853 0
		p.SetAL(p.ReadByte(memory.NewPointer(p.getSeg(p.DS), p.readOpcodeImm16())))
854 6
	case 0xA1: // MOV AX,[addr]
855 6
		p.AX = p.ReadWord(memory.NewPointer(p.getSeg(p.DS), p.readOpcodeImm16()))
856 6
	case 0xA2: // MOV [addr],AL
857 6
		p.WriteByte(memory.NewPointer(p.getSeg(p.DS), p.readOpcodeImm16()), p.AL())
858 6
	case 0xA3: // MOV [addr],AX
859 6
		p.WriteWord(memory.NewPointer(p.getSeg(p.DS), p.readOpcodeImm16()), p.AX)
860 6
	case 0xA4: // MOVSB
861 6
		p.WriteByte(memory.NewPointer(p.ES, p.DI), p.ReadByte(memory.NewPointer(p.getSeg(p.DS), p.SI)))
862 6
		p.updateDISI()
863 6
	case 0xA5: // MOVSW
864 6
		p.WriteWord(memory.NewPointer(p.ES, p.DI), p.ReadWord(memory.NewPointer(p.getSeg(p.DS), p.SI)))
865 6
		p.updateDISI()
866 6
	case 0xA6: // CMPSB
867 6
		a, b := uint32(p.ReadByte(memory.NewPointer(p.getSeg(p.DS), p.SI))), uint32(p.ReadByte(memory.NewPointer(p.ES, p.DI)))
868 6
		res := a - b
869 6
		p.updateFlagsOACSub(res, a, b)
870 6
		p.updateFlagsSZP8(byte(res))
871 6
		p.updateDISI()
872 6
	case 0xA7: // CMPSW
873 6
		a, b := uint32(p.ReadWord(memory.NewPointer(p.getSeg(p.DS), p.SI))), uint32(p.ReadWord(memory.NewPointer(p.ES, p.DI)))
874 6
		res := a - b
875 6
		p.updateFlagsOACSub(res, a, b)
876 6
		p.updateFlagsSZP16(uint16(res))
877 6
		p.updateDISI()
878 6
	case 0xA8: // TEST AL,d8
879 6
		p.updateFlagsSZP8(p.AL() & p.readOpcodeStream())
880 6
	case 0xA9: // TEST AX,d16
881 6
		p.updateFlagsSZP16(p.AX & p.readOpcodeImm16())
882 6
	case 0xAA: // STOSB
883 6
		p.WriteByte(memory.NewPointer(p.ES, p.DI), p.AL())
884 6
		p.updateDI()
885 6
	case 0xAB: // STOSW
886 6
		p.WriteWord(memory.NewPointer(p.ES, p.DI), p.AX)
887 6
		p.updateDI()
888 6
	case 0xAC: // LODSB
889 6
		p.SetAL(p.ReadByte(memory.NewPointer(p.getSeg(p.DS), p.SI)))
890 6
		p.updateSI()
891 6
	case 0xAD: // LODSW
892 6
		p.AX = p.ReadWord(memory.NewPointer(p.getSeg(p.DS), p.SI))
893 6
		p.updateSI()
894 6
	case 0xAE: // SCASB
895 6
		a, b := uint32(p.AL()), uint32(p.ReadByte(memory.NewPointer(p.ES, p.DI)))
896 6
		res := a - b
897 6
		p.updateFlagsOACSub(res, a, b)
898 6
		p.updateFlagsSZP8(byte(res))
899 6
		p.updateDI()
900 6
	case 0xAF: // SCASW
901 6
		a, b := uint32(p.AX), uint32(p.ReadWord(memory.NewPointer(p.ES, p.DI)))
902 6
		res := a - b
903 6
		p.updateFlagsOACSub(res, a, b)
904 6
		p.updateFlagsSZP16(uint16(res))
905 6
		p.updateDI()
906

907
	// 0xBx
908

909 6
	case 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7: // MOV AL/CL/DL/BL/AH/CH/DH/BH,d8
910 6
		(dataLocation(op-0xB0) | registerLocation).writeByte(p, p.readOpcodeStream())
911 6
	case 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF: // MOV AX/CX/DX/BX/SP/BP/SI/DI,d16
912 6
		(dataLocation(op-0xB8) | registerLocation).writeWord(p, p.readOpcodeImm16())
913

914
	// 0xCx
915

916 0
	case 0xC0: // SHL r/m8,d8 (80186)
917 0
		if p.isV20 {
918 0
			p.readModRegRM()
919 0
			dest := p.rmLocation()
920 0
			dest.writeByte(p, p.shiftOrRotate8(p.getReg(), dest.readByte(p), p.readOpcodeStream()))
921 0
		} else {
922 0
			p.invalidOpcode()
923
		}
924 0
	case 0xC1: // SHL r/m16,d16 (80186)
925 0
		if p.isV20 {
926 0
			p.readModRegRM()
927 0
			dest := p.rmLocation()
928 0
			dest.writeWord(p, p.shiftOrRotate16(p.getReg(), dest.readWord(p), p.readOpcodeStream()))
929 0
		} else {
930 0
			p.invalidOpcode()
931
		}
932 6
	case 0xC2: // RET d16
933 6
		ip := p.pop16()
934 6
		p.SP += p.readOpcodeImm16()
935 6
		p.IP = ip
936 6
	case 0xC3: // RET
937 6
		p.IP = p.pop16()
938 6
	case 0xC4: // LES r16,m32
939 6
		p.readModRegRM()
940 6
		addr := p.rmLocation().getAddress()
941 6
		p.regLocation().writeWord(p, p.ReadWord(addr.Pointer()))
942 6
		p.ES = p.ReadWord(addr.AddInt(2).Pointer())
943 6
	case 0xC5: // LDS r16,m32
944 6
		p.readModRegRM()
945 6
		addr := p.rmLocation().getAddress()
946 6
		p.regLocation().writeWord(p, p.ReadWord(addr.Pointer()))
947 6
		p.DS = p.ReadWord(addr.AddInt(2).Pointer())
948 6
	case 0xC6: // _MOV r/m8,d8
949 6
		p.readModRegRM()
950 6
		p.rmLocation().writeByte(p, p.readOpcodeStream())
951 6
	case 0xC7: // _MOV r/m16,d16
952 6
		p.readModRegRM()
953 6
		p.rmLocation().writeWord(p, p.readOpcodeImm16())
954 0
	case 0xC8: // ENTER (80186)
955 0
		p.invalidOpcode()
956 0
	case 0xC9: // LEAVE (80186)
957 0
		p.invalidOpcode()
958 6
	case 0xCA: // RETF d16
959 6
		sp := p.readOpcodeImm16()
960 6
		p.IP = p.pop16()
961 6
		p.CS = p.pop16()
962 6
		p.SP += sp
963 6
	case 0xCB: // RETF
964 6
		p.IP = p.pop16()
965 6
		p.CS = p.pop16()
966 0
	case 0xCC: // INT 3
967 0
		p.doInterrupt(3)
968 6
	case 0xCD: // INT d8
969 6
		p.doInterrupt(int(p.readOpcodeStream()))
970 6
	case 0xCE: // INTO
971 6
		if p.OF {
972 6
			p.doInterrupt(4)
973
		}
974 6
	case 0xCF: // IRET
975 6
		p.IP = p.pop16()
976 6
		p.CS = p.pop16()
977 6
		p.unpackFlags16(p.pop16())
978

979
	// 0xDx
980

981 6
	case 0xD0: // _ROT r/m8,1
982 6
		p.readModRegRM()
983 6
		dest := p.rmLocation()
984 6
		dest.writeByte(p, p.shiftOrRotate8(p.getReg(), dest.readByte(p), 1))
985 6
	case 0xD1: // _ROT r/m16,1
986 6
		p.readModRegRM()
987 6
		dest := p.rmLocation()
988 6
		dest.writeWord(p, p.shiftOrRotate16(p.getReg(), dest.readWord(p), 1))
989 6
	case 0xD2: // _ROT r/m8,CL
990 6
		p.readModRegRM()
991 6
		dest := p.rmLocation()
992 6
		dest.writeByte(p, p.shiftOrRotate8(p.getReg(), dest.readByte(p), p.CL()))
993 6
	case 0xD3: // _ROT r/m16,CL
994 6
		p.readModRegRM()
995 6
		dest := p.rmLocation()
996 6
		dest.writeWord(p, p.shiftOrRotate16(p.getReg(), dest.readWord(p), p.CL()))
997 6
	case 0xD4: // AAM *d8
998 6
		if a, b := p.AL(), p.readOpcodeStream(); b == 0 {
999 6
			p.divisionByZero()
1000 6
		} else {
1001 6
			p.SetAH(a / b)
1002 6
			p.SetAL(a % b)
1003 6
			p.updateFlagsSZP16(p.AX)
1004
		}
1005 6
	case 0xD5: // AAD *d8
1006 6
		p.AX = (uint16(p.AL()) + uint16(p.AH())*uint16(p.readOpcodeStream())) & 0xFF
1007 6
		p.updateFlagsSZP16(p.AX)
1008 0
	case 0xD6: // *SALC
1009
		// This is XLAT on V20.
1010 0
		if !p.isV20 {
1011 0
			if p.CF {
1012 0
				p.SetAL(0xFF)
1013 0
			} else {
1014 0
				p.SetAL(0)
1015
			}
1016 0
			break
1017
		}
1018 0
		fallthrough
1019 6
	case 0xD7: // XLAT
1020 6
		p.SetAL(p.ReadByte(memory.NewPointer(p.getSeg(p.DS), p.BX+uint16(p.AL()))))
1021 0
	case 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF: // ESC
1022 0
		p.readModRegRM()
1023 0
		_, src := p.parseOperands()
1024 0
		src.readByte(p)
1025

1026
	// 0xEx
1027

1028 6
	case 0xE0: // LOOPNZ/NE rel8
1029 6
		p.CX--
1030 6
		p.jmpRel8Cond(p.CX != 0 && !p.ZF)
1031 6
	case 0xE1: // LOOPZ/E rel8
1032 6
		p.CX--
1033 6
		p.jmpRel8Cond(p.CX != 0 && p.ZF)
1034 6
	case 0xE2: // LOOP rel8
1035 6
		p.CX--
1036 6
		p.jmpRel8Cond(p.CX != 0)
1037 6
	case 0xE3: // JCXZ rel8
1038 6
		p.jmpRel8Cond(p.CX == 0)
1039 0
	case 0xE4: // IN AL,[d8]
1040 0
		p.SetAL(p.InByte(uint16(p.readOpcodeStream())))
1041 0
	case 0xE5: // IN AX,[d8]
1042 0
		p.AX = p.InWord(uint16(p.readOpcodeStream()))
1043 0
	case 0xE6: // OUT [d8],AL
1044 0
		p.OutByte(uint16(p.readOpcodeStream()), p.AL())
1045 0
	case 0xE7: // OUT [d8],AX
1046 0
		p.OutWord(uint16(p.readOpcodeStream()), p.AX)
1047 6
	case 0xE8: // CALL rel16
1048 6
		p.push16(p.jmpRel16())
1049 6
	case 0xE9: // JMP rel16
1050 6
		p.jmpRel16()
1051 6
	case 0xEA: // JMP seg:a16
1052 6
		ip := p.readOpcodeImm16()
1053 6
		p.CS = p.readOpcodeImm16()
1054 6
		p.IP = ip
1055 6
	case 0xEB: // JMP rel8
1056 6
		p.jmpRel8()
1057 0
	case 0xEC: // IN AL,[DX]
1058 0
		p.SetAL(p.InByte(p.DX))
1059 0
	case 0xED: // IN AX,[DX]
1060 0
		p.AX = p.InWord(p.DX)
1061 0
	case 0xEE: // OUT [DX],AL
1062 0
		p.OutByte(p.DX, p.AL())
1063 6
	case 0xEF: // OUT [DX],AX
1064 6
		p.OutWord(p.DX, p.AX)
1065

1066
	// 0xFx
1067

1068 6
	case 0xF4: // HLT
1069 6
		p.halted = true
1070 6
	case 0xF5: // CMC
1071 6
		p.CF = !p.CF
1072 6
	case 0xF6: // _ALU2 r/m8,d8
1073 6
		p.grp3a()
1074 6
	case 0xF7: // _ALU2 r/m16,d16
1075 6
		p.grp3b()
1076 6
	case 0xF8: // CLC
1077 6
		p.CF = false
1078 6
	case 0xF9: // STC
1079 6
		p.CF = true
1080 6
	case 0xFA: // CLI
1081 6
		p.IF = false
1082 6
	case 0xFB: // STI
1083 6
		p.IF = true
1084 6
	case 0xFC: // CLD
1085 6
		p.DF = false
1086 6
	case 0xFD: // STD
1087 6
		p.DF = true
1088 6
	case 0xFE: // _MISC r/m8
1089 6
		p.grp4()
1090 6
	case 0xFF: // _MISC r/m16
1091 6
		p.grp5()
1092 0
	default:
1093 0
		p.invalidOpcode()
1094
	}
1095

1096 6
	p.stats.NumInstructions++
1097 6
	return nil
1098
}
1099

1100
func (p *CPU) grp1() {
1101 6
	p.readModRegRM()
1102 6
	dest := p.rmLocation()
1103 6
	a, b := uint32(dest.readByte(p)), uint32(p.readOpcodeStream())
1104

1105 6
	var res uint32
1106 6
	switch op := p.getReg(); op {
1107 6
	case 0:
1108 6
		res = a + b
1109 6
		p.updateFlagsOACAdd(res, a, b)
1110 6
	case 1:
1111 6
		res = a | b
1112 6
		p.clearFlagsOC()
1113 6
	case 2:
1114 6
		res = a + b + b2ui32(p.CF)
1115 6
		p.updateFlagsOACAdd(res, a, b)
1116 6
	case 3:
1117 6
		res = a - (b + b2ui32(p.CF))
1118 6
		p.updateFlagsOACSubCarry(res, a, b)
1119 6
	case 4:
1120 6
		res = a & b
1121 6
		p.clearFlagsOC()
1122 6
	case 5:
1123 6
		res = a - b
1124 6
		p.updateFlagsOACSub(res, a, b)
1125 6
	case 6:
1126 6
		res = a ^ b
1127 6
		p.clearFlagsOC()
1128 6
	case 7:
1129 6
		res = a - b
1130 6
		p.updateFlagsOACSub(res, a, b)
1131 6
		p.updateFlagsSZP8(byte(res))
1132 6
		return
1133 0
	default:
1134 0
		log.Panicf("invalid opcode: grp1(0x%X)", op)
1135
	}
1136

1137 6
	dest.writeByte(p, byte(res))
1138 6
	p.updateFlagsSZP8(byte(res))
1139
}
1140

1141
func (p *CPU) grp1w() {
1142 6
	p.readModRegRM()
1143 6
	dest := p.rmLocation()
1144 6
	a := uint32(dest.readWord(p))
1145

1146
	// Not super nice. :(
1147 6
	var b uint32
1148 6
	if p.opcode == 0x83 {
1149 6
		b = uint32(signExtend16(p.readOpcodeStream()))
1150 6
	} else {
1151 6
		b = uint32(p.readOpcodeImm16())
1152
	}
1153

1154 6
	var res uint32
1155 6
	switch op := p.getReg(); op {
1156 6
	case 0:
1157 6
		res = a + b
1158 6
		p.updateFlagsOACAdd(res, a, b)
1159 6
	case 1:
1160 6
		res = a | b
1161 6
		p.clearFlagsOC()
1162 6
	case 2:
1163 6
		res = a + b + b2ui32(p.CF)
1164 6
		p.updateFlagsOACAdd(res, a, b)
1165 6
	case 3:
1166 6
		res = a - (b + b2ui32(p.CF))
1167 6
		p.updateFlagsOACSubCarry(res, a, b)
1168 6
	case 4:
1169 6
		res = a & b
1170 6
		p.clearFlagsOC()
1171 6
	case 5:
1172 6
		res = a - b
1173 6
		p.updateFlagsOACSub(res, a, b)
1174 6
	case 6:
1175 6
		res = a ^ b
1176 6
		p.clearFlagsOC()
1177 6
	case 7:
1178 6
		res = a - b
1179 6
		p.updateFlagsOACSub(res, a, b)
1180 6
		p.updateFlagsSZP16(uint16(res))
1181 6
		return
1182 0
	default:
1183 0
		log.Panicf("invalid opcode: grp1w(0x%X)", op)
1184
	}
1185

1186 6
	dest.writeWord(p, uint16(res))
1187 6
	p.updateFlagsSZP16(uint16(res))
1188
}
1189

1190
func (p *CPU) opDIV8(a uint16, b byte) {
1191 6
	if b == 0 {
1192 0
		p.divisionByZero()
1193 0
		return
1194
	}
1195

1196 6
	if res := a / uint16(b); res > 0xFF {
1197 6
		p.divisionByZero()
1198 6
	} else {
1199 6
		p.SetAL(byte(res))
1200 6
		p.SetAH(byte(a % uint16(b)))
1201
	}
1202
}
1203

1204
func (p *CPU) opIDIV8(a uint16, b byte) {
1205
	// Reference: fake86's - cpu.c
1206

1207 6
	if b == 0 {
1208 0
		p.divisionByZero()
1209 0
		return
1210
	}
1211

1212 6
	d := signExtend16(b)
1213 6
	sign := ((a ^ d) & 0x8000) != 0
1214

1215 6
	if a >= 0x8000 {
1216 6
		a = (^a + 1) & 0xFFFF
1217
	}
1218 6
	if d >= 0x8000 {
1219 6
		d = (^d + 1) & 0xFFFF
1220
	}
1221

1222 6
	res1, res2 := a/d, a%d
1223 6
	if res1&0xFF00 != 0 {
1224 6
		p.divisionByZero()
1225 6
		return
1226
	}
1227

1228 6
	if sign {
1229 6
		res1 = (^res1 + 1) & 0xFF
1230 6
		res2 = (^res2 + 1) & 0xFF
1231
	}
1232

1233 6
	p.SetAL(byte(res1))
1234 6
	p.SetAH(byte(res2))
1235
}
1236

1237
func (p *CPU) opDIV16(a uint32, b uint16) {
1238 6
	if b == 0 {
1239 6
		p.divisionByZero()
1240 6
		return
1241
	}
1242

1243 6
	if res := a / uint32(b); res > 0xFFFF {
1244 6
		p.divisionByZero()
1245 6
	} else {
1246 6
		p.AX, p.DX = uint16(res), uint16(a%uint32(b))
1247
	}
1248
}
1249

1250
func (p *CPU) opIDIV16(a uint32, b uint16) {
1251
	// Reference: fake86's - cpu.c
1252

1253 6
	if b == 0 {
1254 0
		p.divisionByZero()
1255 0
		return
1256
	}
1257

1258 6
	d := signExtend32(b)
1259 6
	sign := ((a ^ d) & 0x80000000) != 0
1260

1261 6
	if a >= 0x80000000 {
1262 6
		a = (^a + 1) & 0xFFFFFFFF
1263
	}
1264 6
	if d >= 0x80000000 {
1265 6
		d = (^d + 1) & 0xFFFFFFFF
1266
	}
1267

1268 6
	res1, res2 := a/d, a%d
1269 6
	if res1&0xFFFF0000 != 0 {
1270 6
		p.divisionByZero()
1271 6
		return
1272
	}
1273

1274 6
	if sign {
1275 6
		res1 = (^res1 + 1) & 0xFFFF
1276 6
		res2 = (^res2 + 1) & 0xFFFF
1277
	}
1278 6
	p.AX, p.DX = uint16(res1), uint16(res2)
1279
}
1280

1281
func (p *CPU) grp3a() {
1282 6
	p.readModRegRM()
1283 6
	operand := p.rmLocation()
1284

1285 6
	switch op := p.getReg(); op {
1286 6
	case 0, 1:
1287 6
		a, b := operand.readByte(p), p.readOpcodeStream()
1288 6
		p.updateFlagsSZP8(a & b)
1289 6
		p.clearFlagsOC()
1290 6
	case 2:
1291 6
		operand.writeByte(p, ^operand.readByte(p))
1292 6
	case 3:
1293 6
		a, b := uint32(0), uint32(operand.readByte(p))
1294 6
		res := a - b
1295 6
		operand.writeByte(p, byte(res))
1296 6
		p.updateFlagsOACSub(res, a, b)
1297 6
		p.updateFlagsSZP8(byte(res))
1298 6
		p.CF = b != 0
1299 6
	case 4:
1300 6
		a, b := uint32(p.AL()), uint32(operand.readByte(p))
1301 6
		res := a * b
1302 6
		p.AX = uint16(res & 0xFFFF)
1303 6
		p.updateFlagsSZP8(uint8(res))
1304 6
		p.CF = p.AH() != 0
1305 6
		p.OF = p.CF
1306 6
		if !p.isV20 {
1307 0
			p.ZF = false
1308
		}
1309 6
	case 5:
1310 6
		p.AX = signExtend16(p.AL()) * signExtend16(operand.readByte(p))
1311 6
		p.updateFlagsSZP8(byte(p.AX))
1312 6
		if p.AL()&0x80 == 0x80 {
1313 6
			p.CF = p.AH() != 0xFF
1314 6
		} else {
1315 6
			p.CF = p.AH() != 0x0
1316
		}
1317 6
		p.OF = p.CF
1318 6
		if !p.isV20 {
1319 0
			p.ZF = false
1320
		}
1321 6
	case 6:
1322 6
		p.opDIV8(p.AX, operand.readByte(p))
1323 6
	case 7:
1324 6
		p.opIDIV8(p.AX, operand.readByte(p))
1325 0
	default:
1326 0
		log.Panicf("invalid opcode: grp3a(0x%X)", op)
1327
	}
1328
}
1329

1330
func (p *CPU) grp3b() {
1331 6
	p.readModRegRM()
1332 6
	operand := p.rmLocation()
1333

1334 6
	switch op := p.getReg(); op {
1335 6
	case 0, 1:
1336 6
		a, b := operand.readWord(p), p.readOpcodeImm16()
1337 6
		p.updateFlagsSZP16(a & b)
1338 6
		p.clearFlagsOC()
1339 6
	case 2:
1340 6
		operand.writeWord(p, ^operand.readWord(p))
1341 6
	case 3:
1342 6
		a, b := uint32(0), uint32(operand.readWord(p))
1343 6
		res := a - b
1344 6
		operand.writeWord(p, uint16(res))
1345 6
		p.updateFlagsOACSub(res, a, b)
1346 6
		p.updateFlagsSZP16(uint16(res))
1347 6
		p.CF = b != 0
1348 6
	case 4:
1349 6
		a, b := uint32(p.AX), uint32(operand.readWord(p))
1350 6
		res := a * b
1351 6
		p.DX, p.AX = uint16(res>>16), uint16(res&0xFFFF)
1352 6
		p.updateFlagsSZP16(uint16(res))
1353 6
		p.CF = p.DX != 0
1354 6
		p.OF = p.CF
1355 6
		if !p.isV20 {
1356 0
			p.ZF = false
1357
		}
1358 6
	case 5:
1359 6
		res := signExtend32(p.AX) * signExtend32(operand.readWord(p))
1360 6
		p.DX, p.AX = uint16(res>>16), uint16(res&0xFFFF)
1361 6
		p.updateFlagsSZP16(uint16(res))
1362 6
		if p.AX&0x8000 == 0x8000 {
1363 6
			p.CF = p.DX != 0xFFFF
1364 6
		} else {
1365 6
			p.CF = p.DX != 0x0
1366
		}
1367 6
		p.OF = p.CF
1368 6
		if !p.isV20 {
1369 0
			p.ZF = false
1370
		}
1371 6
	case 6:
1372 6
		p.opDIV16((uint32(p.DX)<<16)|uint32(p.AX), operand.readWord(p))
1373 6
	case 7:
1374 6
		p.opIDIV16((uint32(p.DX)<<16)|uint32(p.AX), operand.readWord(p))
1375 0
	default:
1376 0
		log.Panicf("invalid opcode: grp3b(0x%X)", op)
1377
	}
1378
}
1379

1380
func (p *CPU) grp4() {
1381 6
	p.readModRegRM()
1382 6
	dest := p.rmLocation()
1383 6
	v := uint32(dest.readByte(p))
1384 6
	cf := p.CF
1385

1386 6
	var res uint32
1387 6
	switch op := p.getReg(); op {
1388 6
	case 0:
1389 6
		res = v + 1
1390 6
		p.updateFlagsOACAdd(res, v, 1)
1391 6
	case 1:
1392 6
		res = v - 1
1393 6
		p.updateFlagsOACSub(res, v, 1)
1394 0
	default:
1395 0
		p.invalidOpcode()
1396 0
		return
1397
	}
1398

1399 6
	dest.writeByte(p, byte(res))
1400 6
	p.updateFlagsSZP8(byte(res))
1401 6
	p.CF = cf
1402
}
1403

1404
func (p *CPU) grp5() {
1405 6
	p.readModRegRM()
1406 6
	dest := p.rmLocation()
1407 6
	v := uint32(dest.readWord(p))
1408 6
	cf := p.CF
1409

1410 6
	var res uint32
1411 6
	switch op := p.getReg(); op {
1412 6
	case 0:
1413 6
		res = v + 1
1414 6
		p.updateFlagsOACAdd(res, v, 1)
1415 6
	case 1:
1416 6
		res = v - 1
1417 6
		p.updateFlagsOACSub(res, v, 1)
1418 6
	case 2:
1419 6
		p.push16(p.IP)
1420 6
		p.IP = uint16(v)
1421 6
		return
1422 6
	case 3:
1423 6
		p.push16(p.CS)
1424 6
		p.push16(p.IP)
1425 6
		p.IP = uint16(v)
1426 6
		p.CS = p.ReadWord(dest.getAddress().AddInt(2).Pointer())
1427 6
		return
1428 6
	case 4:
1429 6
		p.IP = uint16(v)
1430 6
		return
1431 6
	case 5:
1432 6
		p.IP = uint16(v)
1433 6
		p.CS = p.ReadWord(dest.getAddress().AddInt(2).Pointer())
1434 6
		return
1435 6
	case 6:
1436 6
		p.push16(uint16(v))
1437 6
		return
1438 0
	default:
1439 0
		p.invalidOpcode()
1440 0
		return
1441
	}
1442

1443 6
	dest.writeWord(p, uint16(res))
1444 6
	p.updateFlagsSZP16(uint16(res))
1445 6
	p.CF = cf
1446
}
1447

1448
func (p *CPU) jmpRel8() uint16 {
1449 6
	diff := uint16(int8(p.readOpcodeStream()))
1450 6
	ip := p.IP
1451 6
	p.IP += diff
1452 6
	return ip
1453
}
1454

1455
func (p *CPU) jmpRel16() uint16 {
1456 6
	diff := p.readOpcodeImm16()
1457 6
	ip := p.IP
1458 6
	p.IP += diff
1459 6
	return ip
1460
}
1461

1462
func (p *CPU) jmpRel8Cond(cond bool) {
1463 6
	if cond {
1464 6
		p.jmpRel8()
1465 6
	} else {
1466 6
		p.readOpcodeStream()
1467
	}
1468
}
1469

1470
func (p *CPU) invalidOpcode() {
1471 0
	log.Printf("invalid opcode: 0x%X", p.opcode)
1472 0
	if p.isV20 {
1473 0
		p.IP = p.decodeAt
1474 0
		p.doInterrupt(6)
1475 0
	} else {
1476 0
		p.Break()
1477
	}
1478
}
1479

1480
func (p *CPU) isValidRepeat() (bool, bool) {
1481 6
	switch p.opcode {
1482 0
	case 0x6C, 0x6D, 0x6E, 0x6F:
1483 0
		if p.isV20 {
1484 0
			return false, false
1485
		}
1486 0
		fallthrough
1487 6
	case 0xA4, 0xA5, 0xAC, 0xAD, 0xAA, 0xAB:
1488 6
		return true, false
1489 6
	case 0xA6, 0xA7, 0xAE, 0xAF:
1490 6
		return true, true
1491
	}
1492 6
	return false, false
1493
}
1494

1495
func (p *CPU) doRepeat() error {
1496 6
	if valid, primitive := p.isValidRepeat(); valid {
1497 6
		ip := p.IP
1498
		for p.CX > 0 {
1499 6
			p.IP = ip
1500 6
			if err := p.execute(); err != nil {
1501 0
				return err
1502
			}
1503 6
			p.CX--
1504

1505 6
			if primitive && ((p.repeatMode == 0xF2 && p.ZF) || (p.repeatMode == 0xF3 && !p.ZF)) {
1506 6
				break
1507
			}
1508

1509
			// This is to prevent the JS backend from deadlocking.
1510 6
			if runtime.GOOS == "js" && p.CX%1000 == 0 {
1511 0
				time.Sleep(time.Nanosecond)
1512
			}
1513
		}
1514 6
	} else {
1515 6
		p.repeatMode = 0
1516 6
		if err := p.execute(); err != nil {
1517 0
			return err
1518
		}
1519
	}
1520 6
	return nil
1521
}
1522

1523
func (p *CPU) updateDI() {
1524 6
	var n uint16 = 1
1525 6
	if p.isWide {
1526 6
		n = 2
1527
	}
1528 6
	if p.DF {
1529 6
		p.DI -= n
1530 6
	} else {
1531 6
		p.DI += n
1532
	}
1533
}
1534

1535
func (p *CPU) updateSI() {
1536 6
	var n uint16 = 1
1537 6
	if p.isWide {
1538 6
		n = 2
1539
	}
1540 6
	if p.DF {
1541 6
		p.SI -= n
1542 6
	} else {
1543 6
		p.SI += n
1544
	}
1545
}
1546

1547
func (p *CPU) updateDISI() {
1548 6
	p.updateDI()
1549 6
	p.updateSI()
1550
}

Read our documentation on viewing source code .

Loading