├── asmWidget.py
├── bus.py
├── core.py
├── docs
└── gbz80-decoding.html
├── functions.py
├── gz80.py
├── interface.py
├── kea.py
├── solver.py
└── text.py
/asmWidget.py:
--------------------------------------------------------------------------------
1 | from PySide.QtCore import *
2 | from PySide.QtGui import *
3 | from text import *
4 |
5 | class AsmArea(QAbstractScrollArea):
6 | def __init__(self, parent=None):
7 | super(AsmArea, self).__init__(parent)
8 |
9 | self.setBackgroundRole(QPalette.Base)
10 | self.setAutoFillBackground(True)
11 |
12 | text = [[Text("ROM0:0150", gray), Tab(100), Text("cp ", blue), Text("a", orange), Text(", ", blue), Text("0x11", green)],[Text("ROM0:0152", gray), Tab(100), Text("jr ", blue), Text("z", orange), Text(", ", blue), Text("0x157", green)]]
13 | self.setMouseTracking(True)
14 | self.setFocusPolicy(Qt.ClickFocus)
15 |
16 | self.font = QFont("Courier", 10)
17 | self.fm = QFontMetrics(self.font)
18 | self.h = self.fm.height()
19 | self.setFont(self.font)
20 | self.selectedLine = 0
21 | self.hoverLine = 0
22 | self.hover = None
23 | self.scroll = 0
24 |
25 | self.verticalScrollBar().setSingleStep(self.h)
26 | self.verticalScrollBar().setPageStep(self.height())
27 |
28 | def resizeEvent(self, event):
29 | self.updateContent()
30 | self.verticalScrollBar().setPageStep(self.height())
31 |
32 | def scrollContentsBy(self, dx, dy):
33 | self.scroll = self.verticalScrollBar().value()
34 | self.updateContent()
35 |
36 | def notify(self, subject):
37 | self.updateContent()
38 |
39 | def setContentSource(self, source):
40 | self.source = source
41 | source.addObserver(self)
42 | self.updateContent()
43 |
44 | def updateContent(self):
45 | line = self.scroll / self.h
46 | self.text = self.source.getText(line, self.height() / self.h + 1)
47 | for line in self.text:
48 | x = 5
49 | for word in line:
50 | word.left = x
51 | if type(word) is Tab:
52 | x = max(word.stop, x)
53 | else:
54 | x += self.fm.width(str(word))
55 | word.right = x
56 | self.viewport().update()
57 | self.verticalScrollBar().setRange(0, self.source.getTextSize() * self.h - self.height())
58 |
59 | def mouseMoveEvent(self, event):
60 | self.hoverLine = event.pos().y() / self.h
61 | x = event.pos().x()
62 | try:
63 | hover = filter(lambda w: w.left < x and w.right > x, self.text[self.hoverLine])[0]
64 | except IndexError:
65 | hover = None
66 | if hover is not self.hover:
67 | try:
68 | hover.mouseIn(self.viewport())
69 | except AttributeError:
70 | pass
71 | try:
72 | self.hover.mouseOut(self.viewport())
73 | except AttributeError:
74 | pass
75 | self.hover = hover
76 |
77 | def mousePressEvent(self, event):
78 | self.selectedLine = self.hoverLine
79 | self.viewport().update()
80 |
81 | def keyPressEvent(self, event):
82 | if event.key() == Qt.Key_Up:
83 | self.selectedLine -= 1
84 | self.viewport().update()
85 | elif event.key() == Qt.Key_Down:
86 | self.selectedLine += 1
87 | self.viewport().update()
88 | elif event.key() == Qt.Key_C:
89 | self.source.makeCode(self.selectedLine + self.scroll / self.h)
90 | else:
91 | super(AsmArea, self).keyPressEvent(event)
92 |
93 | def paintEvent(self, event):
94 | painter = QPainter(self.viewport())
95 |
96 | painter.fillRect(0, self.h * self.selectedLine - self.scroll % self.h, self.width(), self.h, self.palette().alternateBase())
97 |
98 | for i,line in enumerate(self.text, 1):
99 | for word in line:
100 | try:
101 | painter.setPen(QColor(*word.color))
102 | except AttributeError:
103 | painter.setPen(QColor(0, 0, 0))
104 | painter.drawText(word.left, i * self.h - self.fm.descent() - self.scroll % self.h, str(word))
105 |
106 |
--------------------------------------------------------------------------------
/bus.py:
--------------------------------------------------------------------------------
1 | import struct
2 |
3 | class Stream(object):
4 | """ This object provides an interface to a variable number of bytes
5 | at a fixed offset in memory for processor modules to use.
6 |
7 | It also takes care of endiness for larger reads. """
8 | def __init__(self, block, offset):
9 | self.block = block
10 | self.offset = offset
11 | self.count = 0
12 |
13 | def read8(self):
14 | byte = struct.unpack_from(" 1:
48 | count -= 1
49 | try:
50 | del self.decoded[pc + count]
51 | except KeyError:
52 | pass
53 | if inst.stores(self.pc): # If the program counter gets stored somewhere (aka, a function call)
54 | # Push the computed pc value on the stack to be explored later
55 | self.stack.append(solver.solve(trace, inst.stores(self.pc)))
56 | try: # if there is a conditional jump, then we follow both paths.
57 | if inst.effects[self.pc].isConditional():
58 | a, b = solver.solveBoth(trace, self.pc);
59 | self.stack.append(a)
60 | self.stack.append(b)
61 | self.notifyObservers()
62 | return
63 | except:
64 | pass
65 | pc = solver.solve(trace, self.pc)
66 | self.notifyObservers()
67 | try:
68 | print "pc = " + pc.infix()
69 | except:
70 | print "pc = 0x%x" % (pc)
71 |
72 | def addObserver(self, observer):
73 | self.observers.append(observer)
74 |
75 | def notifyObservers(self):
76 | for observer in self.observers:
77 | observer.notify(self)
78 |
79 | def getText(self, start, length):
80 | text = []
81 | lines = sorted(self.decoded.keys())
82 | for i in range(start, start + length):
83 | try:
84 | text.append([Text("ROM0:%04x" % lines[i], gray), Tab(100)] + self.decoded[lines[i]])
85 | except KeyError:
86 | break
87 | return text
88 |
89 | def getTextSize(self):
90 | return len(self.decoded)
91 |
92 | def makeCode(self, line):
93 | lines = sorted(self.decoded.keys())
94 | self.stack.append(lines[line])
95 | while(len(self.stack)):
96 | self.startTrace(self.stack.pop())
97 |
98 | if __name__ == "__main__":
99 | core = Core(gz80())
100 | core.attachMemory(open("page00").read())
101 | core.startTrace(0x88)
102 |
--------------------------------------------------------------------------------
/docs/gbz80-decoding.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Decoding Gamboy Z80 Opcodes
5 |
6 |
7 |
263 |
264 | DECODING Gameboy Z80 OPCODES
265 | - of use to disassembler and emulator writers -
266 | Revision 3 (gameboy)
267 |
By Scott Mansell, Based on the orignal by Cristian Dinu.
268 |
269 | CONTENTS
270 |
283 |
284 |
285 | 1. INTRODUCTION
286 | Instruction format and emulation notes
287 | Z80 instructions are represented in memory as byte sequences of the form (items in brackets are optional):
288 |
289 | [prefix byte,] opcode [,displacement byte] [,immediate data]
290 | - OR -
291 | two prefix bytes, displacement byte, opcode
292 |
293 | The opcode
294 | (operation code) is a single byte whose bit pattern indicates the
295 | operation we need the Z80 to perform (register loading, arithmetic,
296 | I/O, etc.). The opcode may also contain information regarding the
297 | operation's parameters (operands), e.g. the registers which will be
298 | used/affected by the operation.
299 | An optional prefix byte
300 | may appear before the opcode, changing its meaning and causing the Z80
301 | to look up the opcode in a different bank of instructions. The prefix
302 | byte, if present, may have the values CB, DD, ED, or FD
303 | (these are hexadecimal values). Although there are opcodes which have
304 | these values too, there is no ambiguity: the first byte in the
305 | instruction, if it has one of these values, is always a prefix byte.
306 | The displacement byte
307 | is a signed 8-bit integer (-128..+127) used in some instructions to
308 | specifiy a displacement added to a given memory address. Its presence
309 | or absence depends on the instruction at hand, therefore, after reading
310 | the prefix and opcode, one has enough information to figure out whether
311 | to expect a displacement byte or not.
312 | Similarly, immediate data
313 | consists of zero, one, or two bytes of additional information
314 | specifying explicit parameters for certain instructions (memory
315 | addresses, arithmetic operands, etc.). Its presence and number of bytes
316 | are also completely determined by the instruction at hand.
317 | Note: Signed data is stored in 2's complement form. 16-bit data is stored LSB first.
318 | A special class of instructions is accesed by using a DD or FD prefix, and then a CB byte. In this situation, the CB byte is also interpreted as a prefix, a mandatory
319 | displacement byte follows, and, finally, the actual opcode occurs. This
320 | is the situation that is described by the second byte pattern shown
321 | above.
322 | Not all (prefix, opcode) combinations map to valid
323 | instructions. However, it is important to note that, unlike some other
324 | processors, upon encountering an invalid instruction, the Z80 will not
325 | 'crash' or signal an error - it will simply appear to do nothing (as if
326 | executing a NOP instruction), and continue with the next byte
327 | sequence in memory. There may also be several subtle effects, such as
328 | the temporary setting of some internal flags or the prevention of
329 | interrupts immediately after the read instruction. Invalid instructions
330 | are sometimes used to mark special commands and signals for emulators
331 | (e.g. Gerton Lunter's 'Z80' ZX Spectrum emulator).
332 | There may be
333 | several combinations of bytes that map to the same instruction. The
334 | sequences will usually have different execution times and memory
335 | footprints. Additionally, there are many instructions (not necessarily
336 | 'invalid') which do virtually nothing meaningful, such as LD A, A, etc., and therefore are reasonable substitutes for NOP.
337 | Some instructions and effects are undocumented
338 | in that they usually do not appear in 'official' Z80 references.
339 | However, by now, these have all been researched and described in
340 | unofficial documents, and they are also used by several programs, so
341 | emulator authors should strive to implement these too, with maximal
342 | accuracy.
343 | Finally, it is important to note that the disassembly
344 | approach described in this document is a rather 'algorithmic one',
345 | focused on understanding the functional structure of the instruction
346 | matrix, and on how the Z80 figures out what to do upon reading the
347 | bytes. If space isn't a concern, it is faster and easier to use
348 | complete disassembly tables that cover all possible (prefix, opcode)
349 | combinations - with text strings for the instruction display, and
350 | microcode sequences for the actual execution.
351 | Notations used in this document
352 |
378 | Upon establishing the opcode, the Z80's path of action is generally dictated by these values:
379 |
380 | x = the opcode's 1st octal digit (i.e. bits 7-6)
381 | y = the opcode's 2nd octal digit (i.e. bits 5-3)
382 | z = the opcode's 3rd octal digit (i.e. bits 2-0)
383 | p = y rightshifted one position (i.e. bits 5-4)
384 | q = y modulo 2 (i.e. bit 3)
385 |
386 | The following placeholders for instructions and operands are used:
387 |
388 | d = displacement byte (8-bit signed integer)
389 | n = 8-bit immediate operand (unsigned integer)
390 | nn = 16-bit immediate operand (unsigned integer)
391 | tab[x] = whatever is contained in the table named tab at index x (analogous for y and z and other table names)
392 |
393 | Operand
394 | data may be interpreted as the programmer desires (either signed or
395 | unsigned), but, in disassembly displays, is generally displayed in
396 | unsigned integer format.
397 | All instructions with d, n or nn in their expression are generally immediately followed by the displacement/operand (a byte or a word, respectively).
398 | Although relative jump instructions are traditionally shown with a 16-bit address for an operand, here they will take the form JR/DJNZ d, where d
399 | is the signed 8-bit displacement that follows (as this is how they are
400 | actually stored). The jump's final address is obtained by adding the
401 | displacement to the instruction's address plus 2.
402 | In this document, the 'jump to the address contained in HL' instruction is written in its correct form JP HL, as opposed to the traditional JP (HL).
403 | IN (C)/OUT (C) instructions are displayed using the traditional form, although they actually use the full 16-bit port address contained in BC.
404 | In the expression of an instruction, everything in bold should be taken ad literam, everything in italics should be evaluated.
405 | This document makes use of an imaginary instruction with the mnemonic NONI
406 | (No Operation No Interrupts). Its interpretation is 'perform a
407 | no-operation (wait 4 T-states) and do not allow interrupts to occur
408 | immediately after this instruction'. The Z80 may actually do more than
409 | just a simple NOP, but the effects are irrelevant assuming normal
410 | operation of the processor.
411 | Disassembly tables
412 | These
413 | tables enable us to represent blocks of similar instructions in a
414 | compact form, taking advantage of the many obvious patterns in the
415 | Z80's instruction matrix.
416 |
417 | |
418 |
419 |
420 | Table "r" |
421 | 8-bit registers |
422 | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
423 | Value | B | C | D | E | H | L | (HL) | A |
424 |
425 |
426 |
427 |
428 | Table "rp" |
429 | Register pairs featuring SP |
430 | Index | 0 | 1 | 2 | 3 |
431 | Value | BC | DE | HL | SP |
432 |
433 | |
434 | |
435 |
436 |
437 | Table "rp2" |
438 | Register pairs featuring AF |
439 | Index | 0 | 1 | 2 | 3 |
440 | Value | BC | DE | HL | AF |
441 |
442 | |
443 |
444 |
445 | Table "cc" |
446 | Conditions |
447 | Index | 0 | 1 | 2 | 3 |
448 | Value | NZ | Z | NC | C |
449 |
450 |
451 | Table "alu" |
452 | Arithmetic/logic operations |
453 | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
454 | Value | ADD A, | ADC A, | SUB | SBC A, | AND | XOR | OR | CP |
455 |
456 |
457 | Table "rot" |
458 | Rotation/shift operations |
459 | Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
460 | Value | RLC | RRC | RL | RR | SLA | SRA | SWAP | SRL |
461 |
462 | |
463 | |
464 |
465 |
466 |
467 | 2. UNPREFIXED OPCODES
468 |
469 |
470 |
471 | z=0 |
472 |
473 | | y=0 | NOP | y=2 | STOP |
474 | | y=1 | LD (nn), SP | y=3 | JR d |
475 | | | | y=4..7 | JR cc[y-4], d |
476 | |
477 |
478 |
479 |
480 | z=1 |
481 |
482 | q=0 | | LD rp[p], nn |
483 | q=1 | | ADD HL, rp[p] |
484 | |
485 |
486 |
487 |
488 | z=2 |
489 |
490 | q=0 | p=0 | LD (BC), A | p=2 | LD (HL+), A |
491 | | p=1 | LD (DE), A | p=3 | LD (HL-), A |
492 | q=1 | p=0 | LD A, (BC) | p=2 | LD A, (HL+) |
493 | | p=1 | LD A, (DE) | p=3 | LD A, (HL-) |
494 | |
495 |
496 |
497 |
498 | z=3 |
499 |
500 | q=0 | | INC rp[p] |
501 | q=1 | | DEC rp[p] |
502 | |
503 |
504 |
505 |
506 | z=4 |
507 | |
510 |
511 |
512 |
513 | z=5 |
514 | |
517 |
518 |
519 |
520 | z=6 |
521 | |
524 |
525 |
526 |
527 | z=7 |
528 |
529 | | y=0 | RLCA | y=4 | DAA |
530 | | y=1 | RRCA | y=5 | CPL |
531 | | y=2 | RLA | y=6 | SCF |
532 | | y=3 | RRA | y=7 | CCF |
533 | |
534 |
535 |
536 |
537 |
538 | |
539 |
540 | | | LD r[y], r[z] |
541 | |
542 |
543 |
544 |
545 | z=6 |
546 | |
549 |
550 |
551 |
552 |
553 | |
554 | |
557 |
558 |
559 |
560 |
561 | z=0 |
562 |
563 | | y=0..3 | RET cc[y] |
564 | | y=4 | LD (0xFF00 + n), A |
565 | y=6 | LD A, (0xFF00 + n) |
566 | | y=5 | ADD SP, d | y=7 | LD HL, SP+ d |
567 | |
568 |
569 |
570 |
571 | z=1 |
572 |
573 | q=0 | | POP rp2[p] |
574 | q=1 | p=0 | RET | p=2 | JP HL |
575 | | p=1 | RETI | p=3 | LD SP, HL |
576 | |
577 |
578 |
579 |
580 | z=2 |
581 |
582 | | y=0..3 | JP cc[y], nn |
583 | | y=4 | LD (0xFF00+C), A | y=6 | LD A, (0xFF00+C) |
584 | | y=5 | LD (nn), A | y=7 | LD A, (nn) |
585 | |
586 |
587 |
588 |
589 | z=3 |
590 |
591 | | y=0 | JP nn | y=4 | (removed) |
592 | | y=1 | (CB prefix) | y=5 | (removed) |
593 | | y=2 | (removed) | y=6 | DI |
594 | | y=3 | (removed) | y=7 | EI |
595 | |
596 |
597 |
598 |
599 | z=4 |
600 |
601 | | y=0..3 | CALL cc[y], nn | y=4..7 | (removed) |
602 | |
603 |
604 |
605 |
606 | z=5 |
607 |
608 | q=0 | | PUSH rp2[p] |
609 | q=1 | p=0 | CALL nn | p=1..3 | (removed) |
610 | |
611 |
612 |
613 |
614 | z=6 |
615 | |
618 |
619 |
620 |
621 | z=7 |
622 | |
625 |
626 |
627 |
628 |
629 |
630 |
631 | 3. CB-PREFIXED OPCODES
632 |
633 |
634 |
635 | x=0 |
636 | |
639 |
640 |
641 |
642 | x=1 |
643 | |
646 |
647 |
648 |
649 | x=2 |
650 | |
653 |
654 |
655 |
656 | x=3 |
657 | |
660 |
661 |
662 |
663 |
664 |
665 |
666 | 4. ACKNOWLEDGEMENTS
667 | The
668 | original 'algorithm' described herein was constructed by studying an
669 | "instruction/flags affected/binary form/effect" list in a Romanian book
670 | called "Ghidul Programatorului ZX Spectrum" ("The ZX Spectrum
671 | Programmer's Guide").
672 | Later, the opcodes was modified to represent the opcodes of
673 | the LR35902, a Z80 workalike used in the gameboy.
674 | The exact effects and quirks of the
675 | CB/DD/ED/FD prefixes, as well as the undocumented ED and CB
676 | instructions, were learnt from "The Undocumented Z80 Documented" by
677 | Sean Young.
678 | My sincere thanks to all those who have contributed
679 | with suggestions or corrections. They are mentioned in the following
680 | section.
681 |
682 |
683 | 5. REVISION HISTORY
684 |
685 | - Revision 1
686 | - Implemented a better representation for the DDCB instructions (thanks to Ven Reddy) and for certain "invalid" ED instructions, e.g. a more accurate NOP/NONI instead of an 8T NOP (thanks to Dr. Phillip Kendall). Fixed some typos.
687 | - Revision 2
688 | - Radically
689 | altered the presentation. Added an intro section, some diagrams, more
690 | comments and a Revision History section. Fixed some important typos and
691 | changed the wording in some places to avoid misunderstandings (thanks
692 | to BlueChip for his numerous and helpful suggestions; he also suggested
693 | that I add info on the signed number format and byte order).
694 | - Revison 3 (gameboy)
695 | - Alot of opcodes were stripped out to better represent the state of the gameboy's Z80 cpu. A few new ones were added
696 |
697 |
698 | - EOF -
699 |
700 |
--------------------------------------------------------------------------------
/functions.py:
--------------------------------------------------------------------------------
1 | def infix(fmt):
2 | def decorator(fn):
3 | def pp(t):
4 | return fmt % t
5 | fn.pp = pp
6 | return fn
7 | return decorator
8 |
9 | def conditional(fn):
10 | fn.conditional = True
11 | return fn
12 |
13 | @infix("%s + %s")
14 | def add(a, b):
15 | return a + b
16 |
17 | @infix("%s - %s")
18 | def sub(a, b):
19 | return a - b
20 |
21 | @infix("%s & %s")
22 | def andl(a, b):
23 | return a & b
24 |
25 |
26 | @infix("%s ^ %s")
27 | def xorl(a, b):
28 | return a ^ b
29 |
30 | @infix("%s | %s")
31 | def orl(a, b):
32 | return a | b
33 |
34 | def bit(bit, val):
35 | mask = ~(1 << bit)
36 | return int(not (val ^ mask))
37 |
38 | @infix("%s > %s")
39 | def gt(a, b):
40 | return int(a > b)
41 |
42 | @infix("%s < %s")
43 | def lt(a, b):
44 | return int(a < b)
45 |
46 | @infix("%s == %s")
47 | def eq(a, b):
48 | return int(a == b)
49 |
50 | @infix("%s * %s")
51 | def mul(a, b):
52 | return a * b
53 |
54 | @infix("%s %% %s")
55 | def mod(val, d):
56 | return val % d
57 |
58 | class Memory8(object):
59 | def __init__(self, addr):
60 | self.addr = addr
61 |
62 | def __repr__(self):
63 | if type(self.addr) is int:
64 | return "mem8[0x%04x]" % self.addr
65 | return "mem8[%s]" % self.addr
66 |
67 | class Memory16(object):
68 | def __init__(self, addr):
69 | self.addr = addr
70 |
71 | def __repr__(self):
72 | if type(self.addr) is int:
73 | return "mem16[0x%04x]" % self.addr
74 | return "mem16[%s]" % self.addr
75 |
76 | def infix(self):
77 | return self.__repr__()
78 |
79 | def rotleft(shift, size, value):
80 | value = value << shift
81 | value = (value & ((1 << size) - 1)) | value >> size
82 | return value
83 |
84 | def rotright(shift, size, value):
85 | overflow = value & ((1 << shift) -1)
86 | value = (value >> shift) | overflow << (size - shift)
87 | return value
88 |
89 | def shiftleft(shift, value):
90 | return value << shift
91 |
92 | def shiftright(shift, value):
93 | return value >> shift
94 |
95 | @conditional
96 | @infix("if (%s): %s else %s")
97 | def if_(cond, expr1, expr2):
98 | if cond:
99 | return expr1
100 | else:
101 | return expr2
102 | if_.func_name = "if"
103 |
--------------------------------------------------------------------------------
/gz80.py:
--------------------------------------------------------------------------------
1 | from interface import *
2 | from functions import *
3 |
4 | regs = ["b", "c", "d", "e", "h", "l", Memory8("hl"), "a"]
5 | regpairs = ["bc", "de", "hl", "sp"]
6 |
7 | x0z2 = [Instruction("ld (bc),a", {Memory8("bc"): "a", "pc": [add, "pc", 1]}),
8 | Instruction("ld a,(bc)", {"a": Memory8("bc"), "pc": [add, "pc", 1]}),
9 | Instruction("ld (de),a", {Memory8("de"): "a", "pc": [add, "pc", 1]}),
10 | Instruction("ld a,(de)", {"a": Memory8("de"), "pc": [add, "pc", 1]}),
11 | Instruction("ld (hl+),a", {Memory8("hl"): "a", "hl": [add, "hl", 1], "pc": [add, "pc", 1]}),
12 | Instruction("ld a,(hl+)", {"a": Memory8("hl"), "hl": [add, "hl", 1], "pc": [add, "pc", 1]}),
13 | Instruction("ld (hl-),a", {Memory8("hl"): "a", "hl": [sub, "hl", 1], "pc": [add, "pc", 1]}),
14 | Instruction("ld a,(hl-)", {"a": Memory8("hl"), "hl": [sub, "hl", 1], "pc": [add, "pc", 1]})]
15 |
16 | x0z7 = [Instruction("rlca",
17 | {"a": [rotleft, 1, 8, "a"],
18 | "pc": [add, "pc", 1],
19 | "z": 0, "n": 0, "h": 0, "c": [bit, 7, "a"]}),
20 | Instruction("rrca",
21 | {"a": [rotright, 1, 8, "a"],
22 | "pc": [add, "pc", 1],
23 | "z": 0, "n": 0, "h": 0, "c": [bit, 0, "a"]}),
24 | Instruction("rla",
25 | {"a": [orl, [shiftleft, 1, "a"], [shiftleft, 7, "c"]],
26 | "pc": [add, "pc", 1],
27 | "z": 0, "n": 0, "h": 0, "c": [bit, 7, "a"]}),
28 | Instruction("rra",
29 | {"a": [orl, [shiftright, 1, "a"], [shiftleft, 7, "c"]],
30 | "pc": [add, "pc", 1],
31 | "z": 0, "n": 0, "h": 0, "c": [bit, 0, "a"]}),
32 | Instruction("daa", #This instruction is going to give me nightmares
33 | {"a": [if_, [orl, "h", [gt, [xorl, "a", 0xf], 0x9]],
34 | [if_, [orl, [gt, [xorl, [add, "a", 0x06], 0xf0], 0x90], "c"],
35 | [add, "a", 0x66],
36 | [add, "a", 0x06]],
37 | [if_, [orl, [gt, [xorl, "a", 0xf0], 0x90], "c"],
38 | [add, "a", 0x60],
39 | "a"]], # Maybe this should be optimised later to get rid of the if statements
40 | "c": [orl, [gt, [xorl, [add, "a", [mul, 0x06, [orl, "h", [gt, [xorl, "a", 0xf], 0x9]]]], 0xf0], 0x90], "c"],
41 | "h": 0,
42 | "z": [eq, [if_, [orl, "h", [gt, [xorl, "a", 0xf], 0x9]],
43 | [if_, [orl, [gt, [xorl, [add, "a", 0x06], 0xf0], 0x90], "c"],
44 | [add, "a", 0x66],
45 | [add, "a", 0x06]],
46 | [if_, [orl, [gt, [xorl, "a", 0xf0], 0x90], "c"],
47 | [add, "a", 0x60],
48 | "a"]], 0],
49 | "pc": [add, "pc", 1]}), # end of daa
50 | Instruction("cpl",
51 | {"a": [xorl, "a", 0xff],
52 | "pc": [add, "pc", 1],
53 | "n": 1, "h": 1}),
54 | Instruction("scf",
55 | {"pc": [add, "pc", 1],
56 | "n": 0, "h": 0, "c": 1}),
57 | Instruction("ccf",
58 | {"pc": [add, "pc", 1],
59 | "n": 0, "h": 0, "c": 0})]
60 |
61 | class gz80(Processor):
62 | def getDescription(self):
63 | return { "pc" : ProgramCounter(16),
64 | "af" : Register(16),
65 | "bc" : Register(16),
66 | "de" : Register(16),
67 | "hl" : Register(16),
68 | "sp" : Register(16),
69 | "a" : SubRegister("af", 8, 7),
70 | "b" : SubRegister("bc", 8, 7),
71 | "c" : SubRegister("bc", 8, 0),
72 | "d" : SubRegister("de", 8, 7),
73 | "e" : SubRegister("de", 8, 0),
74 | "h" : SubRegister("hl", 8, 7),
75 | "l" : SubRegister("hl", 8, 0),
76 | # cpu state
77 | "interupts": Register(1),
78 | "halted": Register(1),
79 | # flags
80 | "z" : SubRegister("af", 1, 7),
81 | "n" : SubRegister("af", 1, 6),
82 | "h" : SubRegister("af", 1, 5),
83 | "c" : SubRegister("af", 1, 4)}
84 |
85 | def decode(self, state, stream):
86 | b = stream.read8()
87 | x = b >> 6
88 | y = (b >> 3) & 0x7
89 | z = b & 0x7
90 | p = y >> 1
91 | q = y & 1
92 | if x == 1:
93 | if y == 6 and z == 6:
94 | return Instruction("halt", {"pc": [add, "pc", 1], "halted": 1})
95 | else:
96 | return Instruction("ld %s, %s" % (regs[y], regs[z]),
97 | {regs[y]: regs[z],
98 | "pc": [add, "pc", 1]})
99 | if x == 2:
100 | if y == 0:
101 | return Instruction("add a,%s" % regs[z],
102 | {"pc": [add, "pc", 1],
103 | "a": [add, "a", regs[z]],
104 | "z": [eq, [xorl, [add, "a", regs[z]], 0xff], 0],
105 | "n": 0,
106 | "h": [gt, [add, [xorl, "a", 0xf], [xorl, regs[z], 0xf]], 0xf],
107 | "c": [gt, [add, "a", regs[z]], 0xff]})
108 | if y == 1:
109 | return Instruction("adc a,%s" % regs[z],
110 | {"pc": [add, "pc", 1],
111 | "a": [add, [add, "a", regs[z]], "c"],
112 | "z": [eq, [xorl, [add, [add, "a", regs[z]], "c"], 0xff], 0],
113 | "n": 0,
114 | "h": [gt, [add, [add, [xorl, "a", 0xf], [xorl, regs[z], 0xf]], "c"], 0xf],
115 | "c": [gt, [add, [add, "a", regs[z]], "c"], 0xff]})
116 | if y == 2:
117 | return Instruction("sub %s" % regs[z],
118 | {"pc": [add, "pc", 1],
119 | "a": [sub, "a", regs[z]],
120 | "z": [eq, [mod, [sub, "a", regs[z]], 0xff], 0],
121 | "n": 1,
122 | "h": [gt, [add, [xorl, "a", 0xf], [xorl, regs[z], 0xf]], 0xf],
123 | "c": [gt, [add, "a", regs[z]], 0xff]})
124 | if y == 3:
125 | return Instruction("sbc a,%s" % regs[z],
126 | {"pc": [add, "pc", 1],
127 | "a": [sub, [sub, "a", regs[z]], "c"],
128 | "z": [eq, [mod, [sub, [sub, "a", regs[z]], "c"], 0xff], 0],
129 | "n": 1,
130 | "h": [gt, [sub, [sub, [xorl, "a", 0xf], [xorl, regs[z], 0xf]], "c"], 0xf],
131 | "c": [gt, [sub, [sub, "a", regs[z]], "c"], 0xff]})
132 | if y == 4:
133 | return Instruction("and %s" % regs[z],
134 | {"pc": [add, "pc", 1],
135 | "a": [andl, "a", regs[z]],
136 | "z": [eq, [andl, "a", regs[z]], 0],
137 | "n": 0, "h": 1, "c": 0})
138 | if y == 5:
139 | return Instruction("xor %s" % regs[z],
140 | {"pc": [add, "pc", 1],
141 | "a": [xorl, "a", regs[z]],
142 | "z": [eq, [xorl, "a", regs[z]], 0],
143 | "n": 0, "h": 0, "c": 0})
144 | if y == 6:
145 | return Instruction("or %s" % regs[z],
146 | {"pc": [add, "pc", 1],
147 | "a": [orl, "a", regs[z]],
148 | "z": [eq, [orl, "a", regs[z]], 0],
149 | "n": 0, "h": 0, "c": 0})
150 | if y == 7:
151 | return Instruction("cp %s" % regs[z],
152 | {"pc": [add, "pc", 1],
153 | "z": [eq, [mod, [sub, "a", regs[z]], 0xff], 0],
154 | "n": 1,
155 | "h": [gt, [add, [xorl, "a", 0xf], [xorl, regs[z], 0xf]], 0xf],
156 | "c": [gt, [add, "a", regs[z]], 0xff]})
157 | if x == 0:
158 | if z == 0:
159 | if y == 0:
160 | return Instruction("nop", {"pc": [add, "pc", 1]})
161 | if y == 1:
162 | nn = stream.read16()
163 | return Instruction("ld 0x%04x,sp" % nn,
164 | {Memory8(nn): "sp", "pc": [add, "pc", 3]})
165 | if y == 2:
166 | return Instruction("stop", {"pc": [add, "pc", 1], "halted": 1})
167 | d = stream.read8s()
168 | if y == 3:
169 | return Instruction("jr %i" % d, {"pc": [add, "pc", d+2]})
170 | if y == 4:
171 | return Instruction("jr nz,%i" % d,
172 | {"pc": [if_, "z",
173 | [add, "pc", 2],
174 | [add, "pc", d+2]]})
175 | if y == 5:
176 | return Instruction("jr z,%i" % d,
177 | {"pc": [if_, "z",
178 | [add, "pc", d+2],
179 | [add, "pc", 2]]})
180 | if y == 6:
181 | return Instruction("jr nc,%i" % d,
182 | {"pc": [if_, "c",
183 | [add, "pc", 2],
184 | [add, "pc", d+2]]})
185 | if y == 7:
186 | return Instruction("jr c,%i" % d,
187 | {"pc": [if_, "c",
188 | [add, "pc", d+2],
189 | [add, "pc", 2]]})
190 | if z == 1:
191 | if q == 0:
192 | nn = stream.read16()
193 | return Instruction("ld %s,0x%04x" % (regpairs[p], nn),
194 | {regpairs[p]: nn,
195 | "pc": [add, "pc", 3]})
196 | if q == 1:
197 | return Instruction("add hl,%s" % regpairs[p],
198 | {"hl": [add, "hl", regpairs[p]],
199 | "pc": [add, "pc", 1],
200 | "n": 0,
201 | # h is undefined for 16 bit adds
202 | "c": [gt, [add, "hl", regpairs[p]], 0xffff]})
203 | if z == 2:
204 | return x0z2[y]
205 | if z == 3 and not q:
206 | return Instruction("inc %s" % regpairs[p],
207 | {regpairs[p]: [add, regpairs[p], 1],
208 | "pc": [add, "pc", 1]})
209 | if z == 3 and q:
210 | return Instruction("dec %s" % regpairs[p],
211 | {regpairs[p]: [add, regpairs[p], 1],
212 | "pc": [add, "pc", 1]})
213 | if z == 4:
214 | return Instruction("inc %s" % regs[y],
215 | {regs[y]: [add, regs[y], 1],
216 | "pc": [add, "pc", 1],
217 | "z": [eq, regs[y], 0xff],
218 | "n": 0,
219 | "h": [eq, [xorl, regs[y], 0xf], 0xf]})
220 | if z == 5:
221 | return Instruction("dec %s" % regs[y],
222 | {regs[y]: [sub, regs[y], 1],
223 | "pc": [add, "pc", 1],
224 | "z": [eq, regs[y], 0x01],
225 | "n": 1,
226 | "h": [eq, [xorl, regs[y], 0xf], 0x0]})
227 | if z == 6:
228 | n = stream.read8()
229 | return Instruction("ld %s,0x%02x" % (regs[y],n),
230 | {regs[y]: n,
231 | "pc": [add, "pc", 2]})
232 | if z == 7:
233 | return x0z7[y]
234 | if x == 3:
235 | if z == 0:
236 | if y == 0:
237 | return Instruction("ret nz",
238 | {"pc": [if_, "z",
239 | [add, "pc", 1],
240 | Memory16("sp")],
241 | "sp": [if_, "z",
242 | None, # None means nothing happens
243 | [add, "sp", 2]]})
244 | if y == 1:
245 | return Instruction("ret z",
246 | {"pc": [if_, "z",
247 | Memory16("sp"),
248 | [add, "pc", 1]],
249 | "sp": [if_, "z",
250 | [add, "sp", 2],
251 | None]}) # None means nothing happens
252 | if y == 2:
253 | return Instruction("ret nc",
254 | {"pc": [if_, "c",
255 | [add, "pc", 1],
256 | Memory16("sp")],
257 | "sp": [if_, "c",
258 | None, # None means nothing happens
259 | [add, "sp", 2]]})
260 | if y == 3:
261 | return Instruction("ret c",
262 | {"pc": [if_, "c",
263 | Memory16("sp"),
264 | [add, "pc", 1]],
265 | "sp": [if_, "c",
266 | [add, "sp", 2],
267 | None]}) # None means nothing happens
268 | if y == 4:
269 | n = stream.read8()
270 | return Instruction("ld (0xff00 + 0x%02x), a" % n,
271 | {Memory8(0xff00+n): "a",
272 | "pc": [add, "pc", 2]})
273 | if y == 5:
274 | d = stream.read8s()
275 | return Instruction("add sp,%i" % d,
276 | {"sp": [add, "sp", d],
277 | "pc": [add, "pc", 2],
278 | "z": 0,
279 | "n": 0,
280 | # h is undefined for 16 bit adds
281 | "c": [gt, [add, "sp", d], 0xffff]}) # Question, what happens on underflow?
282 | if y == 6:
283 | n = stream.read8()
284 | return Instruction("ld a,(0xff00+0x%02x)" % n,
285 | {"a": Memory8(0xff00+n),
286 | "pc": [add, "pc", 2]})
287 | if y == 7:
288 | d = stream.read8s()
289 | return Instruction("ld hl,sp+%i" % d,
290 | {"hl": [add, "sp", d],
291 | "pc": [add, "pc", 2]})
292 | if z == 1:
293 | if q == 0:
294 | return Instruction("pop %s" % regpairs[p],
295 | {"pc": [add, "pc", 1],
296 | regpairs[p]: Memory16("sp"),
297 | "sp": [add, "sp", 2]})
298 | if p == 0:
299 | return Instruction("ret",
300 | {"pc": Memory16("sp"),
301 | "sp": [add, "sp", 2]})
302 | if p == 1:
303 | return Instruction("reti",
304 | {"pc": Memory16("sp"),
305 | "sp": [add, "sp", 2]})
306 | if p == 2:
307 | return Instruction("reti",
308 | {"pc": Memory16("sp"),
309 | "sp": [add, "sp", 2]})
310 | if p == 3:
311 | return Instruction("ld sp, hl",
312 | {"sp": "hl",
313 | "pc": [add, "pc", 1]})
314 | if z == 2:
315 | if y == 0:
316 | nn = stream.read16()
317 | return Instruction("jp nz,0x%04x" % nn,
318 | {"pc": [if_, "z",
319 | [add, "pc", 3],
320 | nn],
321 | "sp": [add, "sp", 2]})
322 | if y == 1:
323 | nn = stream.read16()
324 | return Instruction("jp z,0x%04x" % nn,
325 | {"pc": [if_, "z",
326 | nn,
327 | [add, "pc", 3]]})
328 | if y == 2:
329 | nn = stream.read16()
330 | return Instruction("jp nc,0x%04x" % nn,
331 | {"pc": [if_, "c",
332 | [add, "pc", 3],
333 | nn]})
334 | if y == 3:
335 | nn = stream.read16()
336 | return Instruction("jp c,0x%04x" % nn,
337 | {"pc": [if_, "c",
338 | nn,
339 | [add, "pc", 3]]})
340 | if y == 4:
341 | return Instruction("ld (0xff00+c),a",
342 | {Memory8([add, 0xff00, "c"]): "a",
343 | "pc": [add, "pc", 1]})
344 | if y == 5:
345 | nn = stream.read16()
346 | return Instruction("ld (0x%04x),a" % nn,
347 | {Memory8(nn): "a",
348 | "pc": [add, "pc", 3]})
349 | if y == 6:
350 | return Instruction("ld a,(0xff00+c)",
351 | {"a": Memory8([add, 0xff00, "c"]),
352 | "pc": [add, "pc", 1]})
353 | if y == 7:
354 | nn = stream.read16()
355 | return Instruction("ld a,(0x%04x)" % nn,
356 | {"a": Memory8(nn),
357 | "pc": [add, "pc", 3]})
358 | if z == 3:
359 | if y == 0:
360 | nn = stream.read16()
361 | return Instruction("jp 0x%04x" % nn, {"pc": nn})
362 | if y == 1:
363 | return self.CBdecode(stream.read8())
364 | if y == 6:
365 | return Instruction("di",
366 | {"interupts": 0,
367 | "pc": [add, "pc", 1]})
368 | if y == 7:
369 | return Instruction("ei",
370 | {"interupts": 1,
371 | "pc": [add, "pc", 1]})
372 | if z == 4:
373 | if y == 0:
374 | nn = stream.read16()
375 | return Instruction("call nz",
376 | {"pc": [if_, "z",
377 | [add, "pc", 3],
378 | nn],
379 | Memory16([sub, "sp", 2]): [if_, "z",
380 | None, # None means nothing happens
381 | [add, "pc", 3]],
382 | "sp": [if_, "z",
383 | None,
384 | [sub, "sp", 2]]})
385 | if y == 1:
386 | nn = stream.read16()
387 | return Instruction("call z",
388 | {"pc": [if_, "z",
389 | nn,
390 | [add, "pc", 3]],
391 | Memory16([sub, "sp", 2]): [if_, "z",
392 | [add, "pc", 3],
393 | None], # None means nothing happens
394 | "sp": [if_, "z",
395 | [sub, "sp", 2],
396 | None]})
397 | if y == 2:
398 | nn = stream.read16()
399 | return Instruction("call nc",
400 | {"pc": [if_, "c",
401 | [add, "pc", 3],
402 | nn],
403 | Memory16([sub, "sp", 2]): [if_, "c",
404 | None,
405 | [add, "pc", 3]],
406 | "sp": [if_, "c",
407 | None,
408 | [sub, "sp", 2]]})
409 | if y == 3:
410 | nn = stream.read16()
411 | return Instruction("call c",
412 | {"pc": [if_, "c",
413 | nn,
414 | [add, "pc", 1]],
415 | Memory16([sub, "sp", 2]): [if_, "c",
416 | [add, "pc", 3],
417 | None], # None means nothing happens
418 | "sp": [if_, "c",
419 | [sub, "sp", 2],
420 | None]})
421 | if z == 5:
422 | if q == 0:
423 | return Instruction("push %s" % regpairs[p],
424 | {"pc": [add, "pc", 1],
425 | Memory16([sub, "sp", 2]): regpairs[p],
426 | "sp": [sub, "sp", 2]})
427 | if p == 0:
428 | nn = stream.read16()
429 | return Instruction("call 0x%04x" % nn,
430 | {"pc": nn,
431 | Memory16([sub, "sp", 2]): [add, "pc", 3],
432 | "sp": [sub, "sp", 2]})
433 | if z == 6:
434 | n = stream.read8()
435 | if y == 0:
436 | return Instruction("add a,0x%02x" % n,
437 | {"pc": [add, "pc", 2],
438 | "a": [add, "a", n],
439 | "z": [eq, [xorl, [add, "a", n], 0xff], 0],
440 | "n": 0,
441 | "h": [gt, [add, [xorl, "a", 0xf], n ^ 0xf], 0xf],
442 | "c": [gt, [add, "a", n], 0xff]})
443 | if y == 1:
444 | return Instruction("adc a,0x%02x" % n,
445 | {"pc": [add, "pc", 2],
446 | "a": [add, [add, "a", n], "c"],
447 | "z": [eq, [xorl, [add, [add, "a", n], "c"], 0xff], 0],
448 | "n": 0,
449 | "h": [gt, [add, [add, [xorl, "a", 0xf], n^0xf], "c"], 0xf],
450 | "c": [gt, [add, [add, "a", n], "c"], 0xff]})
451 | if y == 2:
452 | return Instruction("sub 0x%02x" % n,
453 | {"pc": [add, "pc", 2],
454 | "a": [sub, "a", n],
455 | "z": [eq, [mod, [sub, "a", n], 0xff], 0],
456 | "n": 1,
457 | "h": [gt, [add, [xorl, "a", 0xf], n^0xf], 0xf],
458 | "c": [gt, [add, "a", n], 0xff]})
459 | if y == 3:
460 | return Instruction("sbc a,0x%02x" % n,
461 | {"pc": [add, "pc", 2],
462 | "a": [sub, [sub, "a", n], "c"],
463 | "z": [eq, [mod, [sub, [sub, "a", n], "c"], 0xff], 0],
464 | "n": 1,
465 | "h": [gt, [sub, [sub, [xorl, "a", 0xf], n^0xf], "c"], 0xf],
466 | "c": [gt, [sub, [sub, "a", n], "c"], 0xff]})
467 | if y == 4:
468 | return Instruction("and 0x%02x" % n,
469 | {"pc": [add, "pc", 2],
470 | "a": [andl, "a", n],
471 | "z": [eq, [andl, "a", n], 0],
472 | "n": 0, "h": 1, "c": 0})
473 | if y == 5:
474 | return Instruction("xor 0x%02x" % n,
475 | {"pc": [add, "pc", 2],
476 | "a": [xorl, "a", n],
477 | "z": [eq, [xorl, "a", n], 0],
478 | "n": 0, "h": 0, "c": 0})
479 | if y == 6:
480 | return Instruction("or 0x%02x" % n,
481 | {"pc": [add, "pc", 2],
482 | "a": [orl, "a", n],
483 | "z": [eq, [orl, "a", n], 0],
484 | "n": 0, "h": 0, "c": 0})
485 | if y == 7:
486 | return Instruction("cp 0x%02x" % n,
487 | {"pc": [add, "pc", 2],
488 | "z": [eq, [mod, [sub, "a", n], 0xff], 0],
489 | "n": 1,
490 | "h": [gt, [add, [xorl, "a", 0xf], n^0xf], 0xf],
491 | "c": [gt, [add, "a", n], 0xff]})
492 | if z==7:
493 | return Instruction("rst 0x%02x" % (y*8),
494 | {"pc": y*8,
495 | Memory16([sub, "sp", 2]): [add, "pc", 1],
496 | "sp": [sub, "sp", 2]})
497 |
498 | def CBdecode(self, b):
499 | x = b >> 6
500 | y = (b >> 3) & 0x7
501 | z = b & 0x7
502 | if x == 0:
503 | if y == 0:
504 | return Instruction("rlc %s" % regs[z],
505 | {"pc": [add, "pc", 2],
506 | regs[z]: [rotleft, 1, 8, regs[z]],
507 | "z": [eq, regs[z], 0],
508 | "c": [bit, 7, regs[z]],
509 | "n": 0, "h": 0})
510 | if y == 1:
511 | return Instruction("rrc %s" % regs[z],
512 | {"pc": [add, "pc", 2],
513 | regs[z]: [rotright, 1, 8, regs[z]],
514 | "z": [eq, regs[z], 0],
515 | "c": [bit, 0, regs[z]],
516 | "n": 0, "h": 0})
517 | if y == 2:
518 | return Instruction("rl %s" % regs[z],
519 | {"pc": [add, "pc", 2],
520 | regs[z]: [orl, [shiftleft, 1, regs[z]], "c"],
521 | "z": [eq, [orl, [xorl, regs[z], 0x7f], "c"], 0],
522 | "c": [bit, 7, regs[z]],
523 | "n": 0, "h": 0})
524 | if y == 3:
525 | return Instruction("rr %s" % regs[z],
526 | {"pc": [add, "pc", 2],
527 | regs[z]: [orl, [shiftright, 1, regs[z]], [shiftleft, "c", 7]],
528 | "z": [eq, [orl, [shiftright, 1, regs[z]], "c"], 0],
529 | "c": [bit, 0, regs[z]],
530 | "n": 0, "h": 0})
531 | if y == 4:
532 | return Instruction("sla %s" % regs[z],
533 | {"pc": [add, "pc", 2],
534 | regs[z]: [shiftleft, 1, regs[z]],
535 | "z": [eq, [xorl, regs[z], 0x7f], 0],
536 | "c": [bit, 7, regs[z]],
537 | "n": 0, "h": 0})
538 | if y == 5:
539 | return Instruction("sra %s" % regs[z],
540 | {"pc": [add, "pc", 2],
541 | regs[z]: [orl, [shiftright, 1, regs[z]], [xorl, regs[z], 0x80]],
542 | "z": [lt, regs[z], 2],
543 | "c": [bit, 0, regs[z]],
544 | "n": 0, "h": 0})
545 | if y == 6:
546 | return Instruction("swap %s" % regs[z],
547 | {"pc": [add, "pc", 2],
548 | regs[z]: [orl, [shiftleft, 4, regs[z]], [shiftright, 4, regs[z]]],
549 | "z": [eq, regs[z], 0],
550 | "n": 0, "h": 0, "c": 0})
551 | if y == 7:
552 | return Instruction("srl %s" % regs[z],
553 | {"pc": [add, "pc", 2],
554 | regs[z]: [shiftright, 1, regs[z]],
555 | "z": [lt, regs[z], 2],
556 | "c": [bit, 0, regs[z]],
557 | "n": 0, "h": 0})
558 | if x == 1:
559 | return Instruction("bit %i,%s" % (y, regs[z]),
560 | {"pc": [add, "pc", 2],
561 | "z": [bit, y, regs[z]],
562 | "n": 0, "h": 0})
563 | if x == 2:
564 | return Instruction("set %i,%s" % (y, regs[z]),
565 | {"pc": [add, "pc", 2],
566 | regs[z]: [orl, regs[z], 1 << y]})
567 | if x == 3:
568 | return Instruction("res %i,%s" % (y, regs[z]),
569 | {"pc": [add, "pc", 2],
570 | regs[z]: [xorl, regs[z], ~(1 << y)]})
571 |
572 |
573 |
--------------------------------------------------------------------------------
/interface.py:
--------------------------------------------------------------------------------
1 | class Processor(object):
2 | """ All Processor modules implement this class."""
3 |
4 | def getDescription(self):
5 | """ Returns the register layout of the cpu """
6 | return None
7 |
8 | def decodeInstruction(self, state, stream):
9 | """ Decodes a single instruction.
10 | State contains any registers that might effect the decoding
11 | for example, thumb mode on arm.
12 | Stream is a source of bytes for the processor module to decode.
13 | Returns an Instruction object.
14 | """
15 | return None
16 |
17 | class Register(object):
18 | def __init__(self, size):
19 | self.size = size
20 |
21 | class ProgramCounter(Register):
22 | pass
23 |
24 | class SubRegister(Register):
25 | def __init__(self, parent, size, offset):
26 | self.parent = parent
27 | self.size = size
28 | self.offset = offset
29 |
30 | class Sexpression(list):
31 | def __init__(self, l):
32 | for i, x in enumerate(l):
33 | if type(x) is list:
34 | l[i] = Sexpression(x)
35 | super(Sexpression, self).__init__(l)
36 |
37 | def __str__(self):
38 | string = "(" + self[0].func_name
39 | for x in self[1:]:
40 | string += " "
41 | string += str(x)
42 | return string + ")"
43 |
44 | def infix(self):
45 | t = tuple([x.infix() if type(x) is Sexpression else x for x in self[1:]])
46 | return self[0].pp(t)
47 |
48 | def contains(self, reg):
49 | for x in self[1:]:
50 | if type(x) is Sexpression:
51 | if x.contains(reg):
52 | return True
53 | elif x == reg:
54 | return True
55 | return False
56 |
57 | def isConditional(self):
58 | return hasattr(self[0], "conditional")
59 |
60 | class Instruction(object):
61 | def __setattr__(self, *args):
62 | raise TypeError("can't modify immutable instance")
63 | __delattr__ = __setattr__
64 | def __init__(self, asm, effects):
65 | super(Instruction, self).__setattr__('asm', asm) #self.asm = asm
66 | for e in effects.keys():
67 | if type(effects[e]) is list:
68 | effects[e] = Sexpression(effects[e])
69 | super(Instruction, self).__setattr__('effects', effects) #self.effects = effects
70 |
71 | def __repr__(self):
72 | return self.asm
73 |
74 | def prettyPrint(self):
75 | return self.asm
76 |
77 | def stores(self, reg):
78 | """ If this instruciton stores reg into another register or a
79 | memory address, this will return that memory address/register.
80 | Otherwise, returns None.
81 | """
82 | for e in self.effects.keys():
83 | if type(self.effects[e]) is Sexpression:
84 | if self.effects[e].contains(reg):
85 | if e is not reg:
86 | return e
87 | return None
88 |
89 | class Address(object):
90 | def __init__(self, addr):
91 | pass
92 |
93 | #class RealtiveAddress(Address):
94 |
--------------------------------------------------------------------------------
/kea.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2
2 |
3 | import sys
4 | from PySide.QtCore import *
5 | from PySide.QtGui import *
6 | from asmWidget import AsmArea
7 | from core import Core
8 | from gz80 import gz80
9 |
10 | class MainWindow(QMainWindow):
11 | def __init__(self):
12 | super(MainWindow, self).__init__()
13 |
14 | self.createMenus()
15 | self.asmArea = AsmArea()
16 | self.core = Core(gz80())
17 | self.core.attachMemory(open("page00").read())
18 | self.asmArea.setContentSource(self.core)
19 | self.setCentralWidget(self.asmArea)
20 |
21 | self.setWindowTitle("kea - page00")
22 | self.resize(800,600)
23 |
24 | def createMenus(self):
25 | self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q",
26 | triggered=self.close)
27 |
28 | fileMenu = QMenu("&File", self)
29 | fileMenu.addAction(self.exitAct)
30 | self.menuBar().addMenu(fileMenu)
31 |
32 | app = QApplication(sys.argv)
33 |
34 | main = MainWindow()
35 | main.show()
36 |
37 | app.exec_()
38 | sys.exit()
39 |
--------------------------------------------------------------------------------
/solver.py:
--------------------------------------------------------------------------------
1 | import types
2 | from interface import *
3 | import copy
4 |
5 | def solve(trace, var):
6 | equ = build_equ(trace, var)
7 | return execute(equ)
8 |
9 | def solveBoth(trace, var):
10 | equ = build_equ(trace, var)
11 | return (execute(equ[2]), execute(equ[3]))
12 |
13 | def build_equ(trace, var):
14 | equ = var
15 | need = [var]
16 | neededNext = []
17 | for inst in reversed(trace):
18 | for v in need[:]:
19 | if v in inst.effects:
20 | equ = replace(v, inst.effects[v], equ)
21 | need.remove(v)
22 | neededNext += needed(inst.effects[v])
23 | need = Sexpression(set(neededNext + need))
24 | if len(need) == 0:
25 | return equ
26 | return equ
27 |
28 | def needed(eq):
29 | """ Iterates over an equation and returns a list of any missing variables
30 | """
31 | need = []
32 | if type(eq) is str:
33 | need.append(eq)
34 | elif type(eq) is Sexpression:
35 | for i in range(len(eq)):
36 | need += needed(eq[i])
37 | return need
38 |
39 |
40 | def replace(var, with_equ, in_equ):
41 | out = in_equ
42 | if out == var:
43 | out = copy.deepcopy(with_equ) # Make sure we get a copy, otherwise solved equations might escape.
44 | elif type(out) is Sexpression:
45 | for i in range(len(out)):
46 | out[i] = replace(var, with_equ, out[i])
47 | return out
48 |
49 | def execute(eq):
50 | if type(eq) is Sexpression:
51 | if type(eq[0]) is not types.FunctionType:
52 | raise Exception("Invalid s-expression doesn't start with function\n%s" % eq)
53 | for i in range(1, len(eq)):
54 | if type(eq[i]) is Sexpression:
55 | eq[i] = execute(eq[i])
56 | for arg in eq[1:]:
57 | if type(arg) is not int:
58 | return eq
59 | return eq[0](*eq[1:])
60 | return eq
61 |
--------------------------------------------------------------------------------
/text.py:
--------------------------------------------------------------------------------
1 | class Text(object):
2 | def __init__(self, text, color=(0, 0, 0)):
3 | self.text = text
4 | self.color = color
5 |
6 | def __str__(self):
7 | return self.text
8 |
9 | def mouseIn(self, widget):
10 | self.oldColor = self.color
11 | self.color = (255, 0, 0)
12 | widget.update()
13 |
14 | def mouseOut(self, widget):
15 | self.color = self.oldColor
16 | widget.update()
17 |
18 | class Tab(object):
19 | def __init__(self, stop):
20 | self.stop = stop
21 |
22 | def __str__(self):
23 | return ''
24 |
25 | gray = (150, 150, 150)
26 | blue = (0, 60, 200)
27 | green = (0, 200, 60)
28 | orange = (255, 176, 31)
29 |
30 |
--------------------------------------------------------------------------------