initial commit.
This commit is contained in:
32
src/units/16bit_arith.asm
Normal file
32
src/units/16bit_arith.asm
Normal file
@@ -0,0 +1,32 @@
|
||||
ADD HL, SP
|
||||
ADD HL, BC
|
||||
ADD HL, DE
|
||||
ADD HL, HL
|
||||
ADC HL, SP
|
||||
ADC HL, BC
|
||||
ADC HL, DE
|
||||
ADC HL, HL
|
||||
SBC HL, SP
|
||||
SBC HL, BC
|
||||
SBC HL, DE
|
||||
SBC HL, HL
|
||||
ADD IX, SP
|
||||
ADD IX, BC
|
||||
ADD IX, DE
|
||||
ADD IX, IX
|
||||
ADD IY, SP
|
||||
ADD IY, BC
|
||||
ADD IY, DE
|
||||
add IY, IY
|
||||
inc hl
|
||||
inc bc
|
||||
inc de
|
||||
inc sp
|
||||
inc ix
|
||||
inc iy
|
||||
dec hl
|
||||
dec bc
|
||||
dec de
|
||||
dec sp
|
||||
DEC ix
|
||||
dec iy
|
34
src/units/16bit_load.asm
Normal file
34
src/units/16bit_load.asm
Normal file
@@ -0,0 +1,34 @@
|
||||
PUSH DE
|
||||
PUSH BC
|
||||
PUSH HL
|
||||
PUSH AF
|
||||
PUSH IX
|
||||
PUSH IY
|
||||
POP IY
|
||||
POP IX
|
||||
POP DE
|
||||
POP BC
|
||||
POP HL
|
||||
POP AF
|
||||
LD SP, HL
|
||||
LD BC, 4567H
|
||||
LD DE, 4567H
|
||||
LD HL, 4567H
|
||||
LD IX, 4567H
|
||||
LD IY, 4567H
|
||||
LD SP, 4567H
|
||||
LD BC, (4567H)
|
||||
LD DE, (4567H)
|
||||
LD HL, (4567H)
|
||||
LD IX, (4567H)
|
||||
LD IY, (4567H)
|
||||
LD SP, (4567H)
|
||||
LD (4567H), IX
|
||||
LD (4567H), IY
|
||||
LD (4567H), SP
|
||||
LD (4567H), BC
|
||||
LD (4567H), DE
|
||||
LD (4567H), HL
|
||||
LD SP, HL
|
||||
LD SP, IX
|
||||
LD SP, IY
|
96
src/units/8bit_arith.asm
Normal file
96
src/units/8bit_arith.asm
Normal file
@@ -0,0 +1,96 @@
|
||||
ADD A, A
|
||||
ADD A, B
|
||||
ADD A, C
|
||||
ADD A, D
|
||||
ADD A, E
|
||||
ADD A, H
|
||||
ADD A, L
|
||||
ADD A, (HL)
|
||||
ADD A, 45H
|
||||
ADD A, (IX+45H)
|
||||
ADC A, A
|
||||
ADC A, B
|
||||
ADC A, C
|
||||
ADC A, D
|
||||
ADC A, E
|
||||
ADC A, H
|
||||
ADC A, L
|
||||
ADC A, (HL)
|
||||
ADC A, 45H
|
||||
ADC A, (IX+45H)
|
||||
SUB A, A
|
||||
SUB A, B
|
||||
SUB A, C
|
||||
SUB A, D
|
||||
SUB A, E
|
||||
SUB A, H
|
||||
SUB A, L
|
||||
SUB A, (HL)
|
||||
SUB A, 45H
|
||||
SUB A, (IX+45H)
|
||||
AND A
|
||||
AND B
|
||||
AND C
|
||||
AND D
|
||||
AND E
|
||||
AND H
|
||||
AND L
|
||||
AND (HL)
|
||||
AND 56H
|
||||
AND (IX+54H)
|
||||
AND (IY+54H)
|
||||
OR A
|
||||
OR B
|
||||
OR C
|
||||
OR D
|
||||
OR E
|
||||
OR H
|
||||
OR L
|
||||
OR (HL)
|
||||
OR 56H
|
||||
OR (IX+54H)
|
||||
OR (IY+54H)
|
||||
XOR A
|
||||
XOR B
|
||||
XOR C
|
||||
XOR D
|
||||
XOR E
|
||||
XOR H
|
||||
XOR L
|
||||
XOR (HL)
|
||||
XOR 56H
|
||||
XOR (IX+54H)
|
||||
XOR (IY+54H)
|
||||
CP A
|
||||
CP B
|
||||
CP C
|
||||
CP D
|
||||
CP E
|
||||
CP H
|
||||
CP L
|
||||
CP (HL)
|
||||
CP 56H
|
||||
CP (IX+54H)
|
||||
CP (IY+54H)
|
||||
INC A
|
||||
INC B
|
||||
INC C
|
||||
INC D
|
||||
INC E
|
||||
INC H
|
||||
INC L
|
||||
INC (HL)
|
||||
INC (IX+76H)
|
||||
INC (IY+76H)
|
||||
DEC A
|
||||
DEC B
|
||||
DEC C
|
||||
DEC D
|
||||
DEC E
|
||||
DEC H
|
||||
DEC L
|
||||
DEC (HL)
|
||||
DEC (IX+76H)
|
||||
DEC (IY+76H)
|
||||
|
||||
|
127
src/units/8bit_load.asm
Normal file
127
src/units/8bit_load.asm
Normal file
@@ -0,0 +1,127 @@
|
||||
LD A, A
|
||||
LD A, B
|
||||
LD A, C
|
||||
LD A, D
|
||||
LD A, E
|
||||
LD A, H
|
||||
LD A, L
|
||||
LD A, I
|
||||
LD A, R
|
||||
LD B, A
|
||||
LD B, B
|
||||
LD B, C
|
||||
LD B, D
|
||||
LD B, E
|
||||
LD B, H
|
||||
LD B, L
|
||||
LD C, A
|
||||
LD C, B
|
||||
LD C, C
|
||||
LD C, D
|
||||
LD C, E
|
||||
LD C, H
|
||||
LD C, L
|
||||
LD D, A
|
||||
LD D, B
|
||||
LD D, C
|
||||
LD D, D
|
||||
LD D, E
|
||||
LD D, H
|
||||
LD D, L
|
||||
LD E, A
|
||||
LD E, B
|
||||
LD E, C
|
||||
LD E, D
|
||||
LD E, E
|
||||
LD E, H
|
||||
LD H, A
|
||||
LD H, B
|
||||
LD H, C
|
||||
LD H, D
|
||||
LD H, E
|
||||
LD H, H
|
||||
LD H, L
|
||||
LD L, A
|
||||
LD L, B
|
||||
LD L, C
|
||||
LD L, D
|
||||
LD L, E
|
||||
LD L, H
|
||||
LD L, L
|
||||
LD E, A
|
||||
LD I, A
|
||||
LD R, A
|
||||
LD (HL), A
|
||||
LD (HL), B
|
||||
LD (HL), C
|
||||
LD (HL), D
|
||||
LD (HL), E
|
||||
LD (HL), H
|
||||
LD (HL), L
|
||||
LD A, (HL)
|
||||
LD B, (HL)
|
||||
LD C, (HL)
|
||||
LD D, (HL)
|
||||
LD E, (HL)
|
||||
LD H, (HL)
|
||||
LD L, (HL)
|
||||
LD (BC), A
|
||||
LD (DE), A
|
||||
LD A, (BC)
|
||||
LD A, (DE)
|
||||
LD A, (IX+3DH)
|
||||
LD B, (IX+3DH)
|
||||
LD C, (IX+3DH)
|
||||
LD D, (IX+3DH)
|
||||
LD E, (IX+3DH)
|
||||
LD H, (IX+3DH)
|
||||
LD L, (IX+3DH)
|
||||
LD A, (IY+1DH)
|
||||
LD B, (IY+8DH)
|
||||
LD C, (IY+2DH)
|
||||
LD D, (IY+15H)
|
||||
LD E, (IY+3DH)
|
||||
LD H, (IY+3DH)
|
||||
LD L, (IY+3DH)
|
||||
LD A, (IX+3DH)
|
||||
LD B, (IX+3DH)
|
||||
LD C, (IX+3DH)
|
||||
LD D, (IX+3DH)
|
||||
LD E, (IX+3DH)
|
||||
LD H, (IX+3DH)
|
||||
LD L, (IX+3DH)
|
||||
LD A, (IY+1DH)
|
||||
LD B, (IY+8DH)
|
||||
LD C, (IY+2DH)
|
||||
LD D, (IY+15H)
|
||||
LD E, (IY+3DH)
|
||||
LD H, (IY+3DH)
|
||||
LD (IX+3DH), A
|
||||
LD (IX+3DH), B
|
||||
LD (IX+3DH), C
|
||||
LD (IX+3DH), D
|
||||
LD (IX+3DH), E
|
||||
LD (IX+3DH), H
|
||||
LD (IX+3DH), L
|
||||
LD (IY+3DH), A
|
||||
LD (IY+3DH), B
|
||||
LD (IY+3DH), C
|
||||
LD (IY+3DH), D
|
||||
LD (IY+3DH), E
|
||||
LD (IY+3DH), H
|
||||
LD (IY+3DH), L
|
||||
LD A, 31H
|
||||
LD B, 31H
|
||||
LD C, 31H
|
||||
LD D, 31H
|
||||
LD E, 31H
|
||||
LD H, 31H
|
||||
LD L, 31H
|
||||
LD (BC), A
|
||||
LD (DE), A
|
||||
LD I, A
|
||||
LD R, A
|
||||
LD A, (8765H)
|
||||
LD (8762H), A
|
||||
LD (IX+87H), 65H
|
||||
LD (IY+87H), 65H
|
240
src/units/bit_set.asm
Normal file
240
src/units/bit_set.asm
Normal file
@@ -0,0 +1,240 @@
|
||||
BIT 0, A
|
||||
BIT 0, B
|
||||
BIT 0, C
|
||||
BIT 0, D
|
||||
BIT 0, E
|
||||
BIT 0, H
|
||||
BIT 0, L
|
||||
BIT 1, A
|
||||
BIT 1, B
|
||||
BIT 1, C
|
||||
BIT 1, D
|
||||
BIT 1, E
|
||||
BIT 1, H
|
||||
BIT 1, L
|
||||
BIT 2, A
|
||||
BIT 2, B
|
||||
BIT 2, C
|
||||
BIT 2, D
|
||||
BIT 2, E
|
||||
BIT 2, H
|
||||
BIT 2, L
|
||||
BIT 3, A
|
||||
BIT 3, B
|
||||
BIT 3, C
|
||||
BIT 3, D
|
||||
BIT 3, E
|
||||
BIT 3, H
|
||||
BIT 3, L
|
||||
BIT 4, A
|
||||
BIT 4, B
|
||||
BIT 4, C
|
||||
BIT 4, D
|
||||
BIT 4, E
|
||||
BIT 4, H
|
||||
BIT 4, L
|
||||
BIT 5, A
|
||||
BIT 5, B
|
||||
BIT 5, C
|
||||
BIT 5, D
|
||||
BIT 5, E
|
||||
BIT 5, H
|
||||
BIT 5, L
|
||||
BIT 6, A
|
||||
BIT 6, B
|
||||
BIT 6, C
|
||||
BIT 6, D
|
||||
BIT 6, E
|
||||
BIT 6, H
|
||||
BIT 6, L
|
||||
BIT 7, A
|
||||
BIT 7, B
|
||||
BIT 7, C
|
||||
BIT 7, D
|
||||
BIT 7, E
|
||||
BIT 7, H
|
||||
BIT 7, L
|
||||
BIT 0, (HL)
|
||||
BIT 1, (HL)
|
||||
BIT 2, (HL)
|
||||
BIT 3, (HL)
|
||||
BIT 4, (HL)
|
||||
BIT 5, (HL)
|
||||
BIT 6, (HL)
|
||||
BIT 7, (HL)
|
||||
BIT 0, (IX+87H)
|
||||
BIT 1, (IX+87H)
|
||||
BIT 2, (IX+87H)
|
||||
BIT 3, (IX+87H)
|
||||
BIT 4, (IX+87H)
|
||||
BIT 5, (IX+87H)
|
||||
BIT 6, (IX+87H)
|
||||
BIT 7, (IX+87H)
|
||||
BIT 0, (IY+87H)
|
||||
BIT 1, (IY+87H)
|
||||
BIT 2, (IY+87H)
|
||||
BIT 3, (IY+87H)
|
||||
BIT 4, (IY+87H)
|
||||
BIT 5, (IY+87H)
|
||||
BIT 6, (IY+87H)
|
||||
BIT 7, (IY+87H)
|
||||
SET 0, A
|
||||
SET 0, B
|
||||
SET 0, C
|
||||
SET 0, D
|
||||
SET 0, E
|
||||
SET 0, H
|
||||
SET 0, L
|
||||
SET 1, A
|
||||
SET 1, B
|
||||
SET 1, C
|
||||
SET 1, D
|
||||
SET 1, E
|
||||
SET 1, H
|
||||
SET 1, L
|
||||
SET 2, A
|
||||
SET 2, B
|
||||
SET 2, C
|
||||
SET 2, D
|
||||
SET 2, E
|
||||
SET 2, H
|
||||
SET 2, L
|
||||
SET 3, A
|
||||
SET 3, B
|
||||
SET 3, C
|
||||
SET 3, D
|
||||
SET 3, E
|
||||
SET 3, H
|
||||
SET 3, L
|
||||
SET 4, A
|
||||
SET 4, B
|
||||
SET 4, C
|
||||
SET 4, D
|
||||
SET 4, E
|
||||
SET 4, H
|
||||
SET 4, L
|
||||
SET 5, A
|
||||
SET 5, B
|
||||
SET 5, C
|
||||
SET 5, D
|
||||
SET 5, E
|
||||
SET 5, H
|
||||
SET 5, L
|
||||
SET 6, A
|
||||
SET 6, B
|
||||
SET 6, C
|
||||
SET 6, D
|
||||
SET 6, E
|
||||
SET 6, H
|
||||
SET 6, L
|
||||
SET 7, A
|
||||
SET 7, B
|
||||
SET 7, C
|
||||
SET 7, D
|
||||
SET 7, E
|
||||
SET 7, H
|
||||
SET 7, L
|
||||
SET 0, (HL)
|
||||
SET 1, (HL)
|
||||
SET 2, (HL)
|
||||
SET 3, (HL)
|
||||
SET 4, (HL)
|
||||
SET 5, (HL)
|
||||
SET 6, (HL)
|
||||
SET 7, (HL)
|
||||
SET 0, (IX+87H)
|
||||
SET 1, (IX+87H)
|
||||
SET 2, (IX+87H)
|
||||
SET 3, (IX+87H)
|
||||
SET 4, (IX+87H)
|
||||
SET 5, (IX+87H)
|
||||
SET 6, (IX+87H)
|
||||
SET 7, (IX+87H)
|
||||
SET 0, (IY+87H)
|
||||
SET 1, (IY+87H)
|
||||
SET 2, (IY+87H)
|
||||
SET 3, (IY+87H)
|
||||
SET 4, (IY+87H)
|
||||
SET 5, (IY+87H)
|
||||
SET 6, (IY+87H)
|
||||
SET 7, (IY+87H)
|
||||
RES 0, A
|
||||
RES 0, B
|
||||
RES 0, C
|
||||
RES 0, D
|
||||
RES 0, E
|
||||
RES 0, H
|
||||
RES 0, L
|
||||
RES 1, A
|
||||
RES 1, B
|
||||
RES 1, C
|
||||
RES 1, D
|
||||
RES 1, E
|
||||
RES 1, H
|
||||
RES 1, L
|
||||
RES 2, A
|
||||
RES 2, B
|
||||
RES 2, C
|
||||
RES 2, D
|
||||
RES 2, E
|
||||
RES 2, H
|
||||
RES 2, L
|
||||
RES 3, A
|
||||
RES 3, B
|
||||
RES 3, C
|
||||
RES 3, D
|
||||
RES 3, E
|
||||
RES 3, H
|
||||
RES 3, L
|
||||
RES 4, A
|
||||
RES 4, B
|
||||
RES 4, C
|
||||
RES 4, D
|
||||
RES 4, E
|
||||
RES 4, H
|
||||
RES 4, L
|
||||
RES 5, A
|
||||
RES 5, B
|
||||
RES 5, C
|
||||
RES 5, D
|
||||
RES 5, E
|
||||
RES 5, H
|
||||
RES 5, L
|
||||
RES 6, A
|
||||
RES 6, B
|
||||
RES 6, C
|
||||
RES 6, D
|
||||
RES 6, E
|
||||
RES 6, H
|
||||
RES 6, L
|
||||
RES 7, A
|
||||
RES 7, B
|
||||
RES 7, C
|
||||
RES 7, D
|
||||
RES 7, E
|
||||
RES 7, H
|
||||
RES 7, L
|
||||
RES 0, (HL)
|
||||
RES 1, (HL)
|
||||
RES 2, (HL)
|
||||
RES 3, (HL)
|
||||
RES 4, (HL)
|
||||
RES 5, (HL)
|
||||
RES 6, (HL)
|
||||
RES 7, (HL)
|
||||
RES 0, (IX+87H)
|
||||
RES 1, (IX+87H)
|
||||
RES 2, (IX+87H)
|
||||
RES 3, (IX+87H)
|
||||
RES 4, (IX+87H)
|
||||
RES 5, (IX+87H)
|
||||
RES 6, (IX+87H)
|
||||
RES 7, (IX+87H)
|
||||
RES 0, (IY+87H)
|
||||
RES 1, (IY+87H)
|
||||
RES 2, (IY+87H)
|
||||
RES 3, (IY+87H)
|
||||
RES 4, (IY+87H)
|
||||
RES 5, (IY+87H)
|
||||
RES 6, (IY+87H)
|
||||
RES 7, (IY+87H)
|
28
src/units/call_return.asm
Normal file
28
src/units/call_return.asm
Normal file
@@ -0,0 +1,28 @@
|
||||
CALL 7219H
|
||||
CALL NZ, 7219H
|
||||
CALL Z, 7219H
|
||||
CALL NC, 7219H
|
||||
CALL C, 7219H
|
||||
CALL PO, 7219H
|
||||
CALL PE, 7219H
|
||||
CALL P, 7219H
|
||||
CALL M, 7219H
|
||||
RETI
|
||||
RETN
|
||||
RET
|
||||
RET NZ
|
||||
RET Z
|
||||
RET NC
|
||||
RET C
|
||||
RET PO
|
||||
RET PE
|
||||
RET P
|
||||
RET M
|
||||
RST 0H
|
||||
RST 8H
|
||||
RST 10H
|
||||
RST 18H
|
||||
RST 20H
|
||||
RST 28H
|
||||
RST 30H
|
||||
RST 38H
|
14
src/units/exchange.asm
Normal file
14
src/units/exchange.asm
Normal file
@@ -0,0 +1,14 @@
|
||||
EX DE, HL
|
||||
EX AF, AF'
|
||||
EXX
|
||||
EX (SP), HL
|
||||
EX (SP), IX
|
||||
EX (SP), IY
|
||||
LDI
|
||||
LDIR
|
||||
LDD
|
||||
LDDR
|
||||
CPI
|
||||
CPIR
|
||||
CPD
|
||||
CPDR
|
14
src/units/general_purp.asm
Normal file
14
src/units/general_purp.asm
Normal file
@@ -0,0 +1,14 @@
|
||||
CPL
|
||||
DAA
|
||||
NEG
|
||||
CCF
|
||||
SCF
|
||||
HALT
|
||||
DI
|
||||
EI
|
||||
NOP
|
||||
IM 0
|
||||
IM 1
|
||||
IM 2
|
||||
|
||||
|
25
src/units/input_output.asm
Normal file
25
src/units/input_output.asm
Normal file
@@ -0,0 +1,25 @@
|
||||
IN A, (32H)
|
||||
IN B, (C)
|
||||
IN C, (C)
|
||||
IN D, (C)
|
||||
IN E, (C)
|
||||
IN F, (C)
|
||||
IN H, (C)
|
||||
IN L, (C)
|
||||
INI
|
||||
INIR
|
||||
IND
|
||||
INDR
|
||||
OUT (32H), A
|
||||
OUT (C), B
|
||||
OUT (C), C
|
||||
OUT (C), D
|
||||
OUT (C), E
|
||||
OUT (C), H
|
||||
OUT (C), L
|
||||
OUTI
|
||||
OTIR
|
||||
OUTD
|
||||
OTDR
|
||||
|
||||
|
12
src/units/jump_group.asm
Normal file
12
src/units/jump_group.asm
Normal file
@@ -0,0 +1,12 @@
|
||||
JP 7219H
|
||||
JP NZ, 7219H
|
||||
JP Z, 7219H
|
||||
JP NC, 7219H
|
||||
JP C, 7219H
|
||||
JP PO, 7219H
|
||||
JP PE, 7219H
|
||||
JP P, 7219H
|
||||
JP M, 7219H
|
||||
JP (HL)
|
||||
JP (IX)
|
||||
JP (IY)
|
65
src/units/rotate_shift.asm
Normal file
65
src/units/rotate_shift.asm
Normal file
@@ -0,0 +1,65 @@
|
||||
RLCA
|
||||
RLA
|
||||
RRA
|
||||
RLC A
|
||||
RLC B
|
||||
RLC C
|
||||
RLC D
|
||||
RLC E
|
||||
RLC H
|
||||
RLC L
|
||||
RLC (HL)
|
||||
RLC (IX+87H)
|
||||
RLC (IY+87H)
|
||||
RL A
|
||||
RL B
|
||||
RL C
|
||||
RL D
|
||||
RL E
|
||||
RL h
|
||||
RL l
|
||||
rl (hl)
|
||||
rl (ix+65h)
|
||||
rl (iy+43h)
|
||||
rr a
|
||||
rr b
|
||||
rr c
|
||||
rr d
|
||||
rr e
|
||||
rr h
|
||||
rr l
|
||||
rr (hl)
|
||||
rr (ix+87H)
|
||||
rr (iy+71H)
|
||||
rrc a
|
||||
rrc b
|
||||
rrc c
|
||||
rrc d
|
||||
rrc e
|
||||
rrc h
|
||||
rrc l
|
||||
rrc (hl)
|
||||
rrc (ix+87H)
|
||||
rrc (iy+71H)
|
||||
sla a
|
||||
sla b
|
||||
sla c
|
||||
sla d
|
||||
sla e
|
||||
sla h
|
||||
sla l
|
||||
sla (hl)
|
||||
sla (ix+76H)
|
||||
sla (iy+87h)
|
||||
sra a
|
||||
sra b
|
||||
sra c
|
||||
sra d
|
||||
sra e
|
||||
sra h
|
||||
sra l
|
||||
sra (hl)
|
||||
sra (ix+76H)
|
||||
sra (iy+87h)
|
||||
rld
|
||||
rrd
|
32
src/units/test_register.py
Normal file
32
src/units/test_register.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from z80 import registers
|
||||
import unittest
|
||||
|
||||
class TestZ80Registers(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.registers = registers.Registers(power=None)
|
||||
|
||||
def test_double_register_access(self):
|
||||
self.registers.H = 0x45
|
||||
self.registers.L = 0x46
|
||||
self.assertEqual(self.registers.HL, 0x4546)
|
||||
|
||||
def test_condition_flags(self):
|
||||
self.registers.F=0x0
|
||||
self.registers.condition.C=True
|
||||
self.assertEqual(self.registers.F, 0x01 << 0)
|
||||
|
||||
self.registers.F=0x0
|
||||
self.registers.condition.S=True
|
||||
self.assertEqual(self.registers.F, 0x01 << 7)
|
||||
|
||||
self.registers.F=0x0
|
||||
self.registers.condition.PV=True
|
||||
self.assertEqual(self.registers.F, 0x01 << 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
raw_input()
|
||||
|
||||
|
233
src/units/test_z80.py
Normal file
233
src/units/test_z80.py
Normal file
@@ -0,0 +1,233 @@
|
||||
import random
|
||||
import unittest
|
||||
from time import sleep
|
||||
import logging
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
import subprocess
|
||||
from subprocess import PIPE, STDOUT, Popen
|
||||
from z80 import util, registers, instructions
|
||||
import tempfile
|
||||
import string
|
||||
import inspect
|
||||
import os
|
||||
|
||||
def compile_code(code):
|
||||
p = Popen(["z80asm", "-o", "-"], stdout=PIPE, stdin=PIPE)
|
||||
|
||||
by = p.communicate(input=code)[0]
|
||||
object_code = [ord(b) for b in by]
|
||||
return object_code
|
||||
|
||||
class TestZ80Instructions(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.registers = registers.Registers(power=None)
|
||||
self.instructions = instructions.InstructionSet(self.registers)
|
||||
|
||||
self.mem = bytearray(48*1024)
|
||||
|
||||
def pass_bytes(self, bytes):
|
||||
for i in bytes:
|
||||
ins, args = self.instructions << i
|
||||
if ins:
|
||||
yield ins, args
|
||||
|
||||
def execute(self, ins):
|
||||
rd = ins[0].get_read_list(ins[1])
|
||||
data = [self.mem[i] for i in rd]
|
||||
wrt = ins[0].execute(data, ins[1])
|
||||
for i in wrt:
|
||||
self.mem[i[0]] = i[1]
|
||||
|
||||
def test_ld(self):
|
||||
by = [0x3E, 0x45]
|
||||
for ins in self.pass_bytes(by):
|
||||
print ins
|
||||
self.execute(ins)
|
||||
self.assertEqual(self.registers.A, 0x45)
|
||||
|
||||
def _test_assembler(self, file_name):
|
||||
file = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),
|
||||
file_name)
|
||||
with open(file, "r") as f:
|
||||
asm = f.read()
|
||||
by = subprocess.check_output(["z80asm", "-i", file, "-o", "-"])
|
||||
byts = [ord(b) for b in by]
|
||||
res = ""
|
||||
for ins, a in zip(self.pass_bytes(byts), asm.split("\n")):
|
||||
res = ins[0].assembler(ins[1])
|
||||
self.assertEqual(res, a.strip().upper())
|
||||
print res
|
||||
res = res[:-1]
|
||||
|
||||
def test_assembler_8bit_load(self):
|
||||
self._test_assembler("8bit_load.asm")
|
||||
|
||||
def test_assembler_16bit_load(self):
|
||||
self._test_assembler("16bit_load.asm")
|
||||
|
||||
def test_assembler_exchange_block_transfer(self):
|
||||
self._test_assembler("exchange.asm")
|
||||
|
||||
def test_assembler_8bit_arith(self):
|
||||
self._test_assembler("8bit_arith.asm")
|
||||
|
||||
def test_assembler_16bit_arith(self):
|
||||
self._test_assembler("16bit_arith.asm")
|
||||
|
||||
def test_assembler_general_arith(self):
|
||||
self._test_assembler("general_purp.asm")
|
||||
|
||||
|
||||
def test_assembler_rotate_and_shift_group(self):
|
||||
self._test_assembler("rotate_shift.asm")
|
||||
|
||||
|
||||
def test_assembler_bit_set_and_test_group(self):
|
||||
self._test_assembler("bit_set.asm")
|
||||
|
||||
def test_assembler_jump_group(self):
|
||||
self._test_assembler("jump_group.asm")
|
||||
|
||||
def test_assembler_call_return_group(self):
|
||||
self._test_assembler("call_return.asm")
|
||||
|
||||
def test_assembler_input_output(self):
|
||||
self._test_assembler("input_output.asm")
|
||||
|
||||
def compile_and_load(self,program):
|
||||
obj = compile_code(program)
|
||||
p=0
|
||||
for i in obj:
|
||||
self.mem[p]=i
|
||||
p+=1
|
||||
self.registers.reset()
|
||||
self.assertGreater(p, 0, msg="Zero length program, bad compile")
|
||||
return p
|
||||
|
||||
def test_program1(self):
|
||||
program = ("LD A, 54H",
|
||||
"NOP",
|
||||
"LD BC, 6543H",
|
||||
"LD HL, 1234H",
|
||||
"ADD HL, BC",
|
||||
"ADD A, A",
|
||||
"SUB A, 37H",
|
||||
# "LD B, 0H",
|
||||
# "LD C, 54H",
|
||||
"LD BC, 54H",
|
||||
"INC BC",
|
||||
"SBC HL, BC",
|
||||
"ADD IX, BC",
|
||||
"ADD IX, IX",
|
||||
"ADD IX, SP",
|
||||
"inc ix",
|
||||
"inc iy",
|
||||
"inc iy",
|
||||
"dec iy",
|
||||
"ld b, a",
|
||||
"ld a, 0x01",
|
||||
"rla",
|
||||
"ld C, 1H",
|
||||
"rlc c",
|
||||
"rlc c",
|
||||
"rlc c",
|
||||
"ld iy, 1ffH",
|
||||
"ld (iy+0H), 0x8",
|
||||
"rlc (iy+0H)",
|
||||
"HALT"
|
||||
)
|
||||
program = string.join(program, "\n")
|
||||
self.compile_and_load(program)
|
||||
while not self.registers.HALT:
|
||||
ins, args = False, []
|
||||
while not ins:
|
||||
ins, args = self.instructions << self.mem[self.registers.PC]
|
||||
self.registers.PC = util.inc8(self.registers.PC)
|
||||
|
||||
self.execute((ins, args))
|
||||
print self.registers.A
|
||||
|
||||
self.assertEqual(self.registers.B, 0x54+0x54-0x37)
|
||||
self.assertEqual(self.registers.HL, 0x6543+0x1234-0x55)
|
||||
self.assertEqual(self.registers.IX, 0x55 + 0x55 + 1)
|
||||
# self.assertEqual(self.registers.IY, 0x01)
|
||||
self.assertEqual(self.registers.A, 2)
|
||||
self.assertEqual(self.registers.C, 8)
|
||||
self.assertEqual(self.mem[0x1ff], 16)
|
||||
|
||||
class TestAdditionSubtraction(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.registers = registers.Registers(power=None)
|
||||
|
||||
def test_addition_overflow1_flag(self):
|
||||
res = util.add8(util.make_8bit_twos_comp(10), util.make_8bit_twos_comp(10),
|
||||
self.registers)
|
||||
self.assertEqual(util.get_8bit_twos_comp(res), 20)
|
||||
self.assertFalse(self.registers.condition.PV)
|
||||
|
||||
def test_addition_overflow2_flag(self):
|
||||
res = util.add8(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(10),
|
||||
self.registers)
|
||||
print util.get_8bit_twos_comp(res)
|
||||
self.assertEqual(util.get_8bit_twos_comp(res), 0)
|
||||
self.assertFalse(self.registers.condition.PV)
|
||||
self.assertFalse(self.registers.condition.S)
|
||||
|
||||
def test_addition_overflow3_flag(self):
|
||||
res = util.add8(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(-10),
|
||||
self.registers)
|
||||
self.assertEqual(util.get_8bit_twos_comp(res), util.get_8bit_twos_comp(-20))
|
||||
print util.get_8bit_twos_comp(res)
|
||||
self.assertFalse(self.registers.condition.PV)
|
||||
self.assertTrue(self.registers.condition.S)
|
||||
|
||||
def test_addition_overflow4_flag(self):
|
||||
res = util.add8(util.make_8bit_twos_comp(-100), util.make_8bit_twos_comp(-100),
|
||||
self.registers)
|
||||
self.assertTrue(self.registers.condition.PV)
|
||||
|
||||
def test_addition_overflow5_flag(self):
|
||||
res = util.add8(util.make_8bit_twos_comp(100), util.make_8bit_twos_comp(100),
|
||||
self.registers)
|
||||
self.assertTrue(self.registers.condition.PV)
|
||||
|
||||
def test_subtraction_overflow_flag_1(self):
|
||||
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(10), util.make_8bit_twos_comp(10),
|
||||
self.registers)
|
||||
self.assertEqual(res, util.get_8bit_twos_comp(0))
|
||||
self.assertFalse(self.registers.condition.PV)
|
||||
|
||||
def test_subtraction_overflow_flag_2(self):
|
||||
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(10),
|
||||
self.registers)
|
||||
self.assertEqual(util.get_8bit_twos_comp(res), -20)
|
||||
self.assertFalse(self.registers.condition.PV)
|
||||
self.assertTrue(self.registers.condition.S)
|
||||
|
||||
def test_subtraction_overflow_flag_3(self):
|
||||
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(-10),
|
||||
self.registers)
|
||||
self.assertEqual(util.get_8bit_twos_comp(res), 0)
|
||||
self.assertFalse(self.registers.condition.PV)
|
||||
|
||||
def test_subtraction_overflow_flag_4(self):
|
||||
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(-100), util.make_8bit_twos_comp(100),
|
||||
self.registers)
|
||||
self.assertTrue(self.registers.condition.PV)
|
||||
|
||||
def test_subtraction_overflow_flag_5(self):
|
||||
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(100), util.make_8bit_twos_comp(-100),
|
||||
self.registers)
|
||||
self.assertTrue(self.registers.condition.PV)
|
||||
|
||||
def test_twos_comp(self):
|
||||
self.assertEqual(util.get_8bit_twos_comp(0b100), 4)
|
||||
self.assertEqual(util.get_8bit_twos_comp(0b11100011), -29)
|
||||
self.assertEqual(util.make_8bit_twos_comp(-29),0b11100011)
|
||||
self.assertEqual(util.make_8bit_twos_comp(25),0b00011001)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
raw_input()
|
0
src/z80/__init__.py
Normal file
0
src/z80/__init__.py
Normal file
275
src/z80/gui.py
Normal file
275
src/z80/gui.py
Normal file
@@ -0,0 +1,275 @@
|
||||
import sys
|
||||
|
||||
from PySide.QtCore import *
|
||||
from PySide.QtGui import *
|
||||
from PySide.QtWebKit import *
|
||||
|
||||
from cStringIO import StringIO
|
||||
|
||||
class RegistersGUI(QWidget):
|
||||
_addresses = [0x80, 0x81]
|
||||
_update_sgl = Signal()
|
||||
format_data = """
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML Online Editor Sample</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
</p>
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="width: 100px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">A</span></td>
|
||||
<td>
|
||||
<span style="font-size:12px;">0x{A:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<span style="font-size:12px;">Flags</span>
|
||||
<table border="0" cellpadding="1" cellspacing="1" style="width: 100px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">S</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">Z</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">F5</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">H</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">F3</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">PV</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">N</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">C</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FS}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FZ}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FF5}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FH}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FF3}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FPV}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FN}</span></td>
|
||||
<td style="text-align: center;">
|
||||
<span style="font-size:12px;">{FC}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">BC</span></td>
|
||||
<td>
|
||||
<span style="font-size:12px;">0x{BC:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">DE</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{DE:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">HL</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{HL:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">PC</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{PC:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">SP</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{SP:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">IX</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{IX:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">IY</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{IY:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">I</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{I:X}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="font-size:12px;">R</span></td>
|
||||
<td>
|
||||
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{R:X}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></body>
|
||||
</html>
|
||||
|
||||
|
||||
"""
|
||||
def __init__(self, registers):
|
||||
super(RegistersGUI, self).__init__()
|
||||
|
||||
vbox=QVBoxLayout()
|
||||
self.setLayout(vbox)
|
||||
|
||||
self._view = QWebView()
|
||||
vbox.addWidget(self._view)
|
||||
|
||||
|
||||
|
||||
#self.setPlainText("")
|
||||
#self.setFontFamily("Mono")
|
||||
#self.setFontPointSize(8)
|
||||
#self._modifiers = {}
|
||||
#self.setCursorWidth(0)
|
||||
self._registers = registers
|
||||
self._update_sgl.connect(self._update)
|
||||
#self.setReadOnly(True)
|
||||
self.setGeometry(100, 0, 200, 480)
|
||||
|
||||
self.update()
|
||||
|
||||
@Slot()
|
||||
def update(self):
|
||||
#print "WRITE ", address
|
||||
self._update_sgl.emit()
|
||||
|
||||
def _update(self):
|
||||
fields = {}
|
||||
for f in "A,BC,DE,HL,SP,IX,IY,I,R,PC".split(","):
|
||||
fields[f] = self._registers[f]
|
||||
for b in ["S", "Z", "F5", "H", "F3", "PV", "N", "C"]:
|
||||
fields["F{}".format(b)] = getattr(self._registers.condition, b)
|
||||
self._view.setHtml(self.format_data.format(**fields))
|
||||
|
||||
|
||||
|
||||
class MemoryView(QWidget):
|
||||
_update_sgl = Signal(int)
|
||||
def __init__(self, memory, registers):
|
||||
super(MemoryView, self).__init__()
|
||||
self._modifiers = {}
|
||||
|
||||
self._page_height = 16
|
||||
|
||||
self._memory = memory
|
||||
self._registers = registers
|
||||
self._update_sgl.connect(self._update)
|
||||
self._web_view = QWebView()
|
||||
vbox = QVBoxLayout()
|
||||
self.setLayout(vbox)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
self._offset_entry = QLineEdit()
|
||||
self._offset_entry.returnPressed.connect(self.address_change)
|
||||
self._offset = 0x0
|
||||
self._offset_entry.setText(hex(self._offset))
|
||||
self._offset_next = QPushButton(">>")
|
||||
self._offset_prev = QPushButton("<<")
|
||||
self._offset_next.clicked.connect(self.on_next)
|
||||
self._offset_prev.clicked.connect(self.on_prev)
|
||||
hbox.addWidget(self._offset_entry)
|
||||
hbox.addWidget(self._offset_prev)
|
||||
hbox.addWidget(self._offset_next)
|
||||
hbox.addStretch(1)
|
||||
|
||||
vbox.addLayout(hbox)
|
||||
vbox.addWidget(self._web_view)
|
||||
|
||||
self.setGeometry(100, 580, 840, 480)
|
||||
self.update()
|
||||
|
||||
def on_next(self):
|
||||
self._offset += self._page_height * 16
|
||||
self._offset_entry.setText(hex(self._offset))
|
||||
self.update()
|
||||
pass
|
||||
def on_prev(self):
|
||||
if self._offset < 1:
|
||||
return
|
||||
self._offset -= self._page_height * 16
|
||||
self._offset_entry.setText(hex(self._offset))
|
||||
self.update()
|
||||
pass
|
||||
|
||||
def address_change(self):
|
||||
new_val=self._offset_entry.text()
|
||||
val=0
|
||||
ln=0
|
||||
try:
|
||||
val=int(new_val,16)
|
||||
ln=(val-(val%16))# * 16
|
||||
pg = ln - ln%(self._page_height*16)
|
||||
except:
|
||||
return
|
||||
|
||||
self._offset_entry.setText(hex(pg))
|
||||
self._offset=pg
|
||||
self.update(val)
|
||||
|
||||
|
||||
@Slot()
|
||||
def update(self,highlight=-1):
|
||||
self._update_sgl.emit(highlight)
|
||||
|
||||
def _update(self,highlight):
|
||||
|
||||
sp = self._registers.SP
|
||||
txt = StringIO()
|
||||
txt.write("<table><tr><td>Offset</td>")
|
||||
for i in range(16):
|
||||
txt.write("<td>{:X}</td>".format(i))
|
||||
txt.write("<td>ASCII</td></tr>")
|
||||
|
||||
for i in range(self._offset, min(len(self._memory),
|
||||
self._offset+16*self._page_height), 16):
|
||||
txt.write("<tr>")
|
||||
offset = i
|
||||
txt.write("<td>{}</td>".format(hex(offset)))
|
||||
ascii = ""
|
||||
for j in range(16):
|
||||
v = self._memory[offset+j]
|
||||
if v > 31 and v < 127:
|
||||
ascii += chr(self._memory[offset+j])
|
||||
else:
|
||||
ascii += "."
|
||||
if offset+j == sp:
|
||||
txt.write("<td style=\"color:red\">{:2X}</td>".format(v))
|
||||
elif highlight > 0 and offset+j==highlight:
|
||||
txt.write("<td style=\"color:blue\">{:2X}</td>".format(v))
|
||||
else:
|
||||
txt.write("<td>{:2X}</td>".format(v))
|
||||
txt.write("<td><tt>{}</tt></td>".format(ascii))
|
||||
txt.write("</tr>")
|
||||
txt.write( "</table>")
|
||||
text = txt.getvalue()
|
||||
txt.close()
|
||||
self._web_view.setHtml(text)
|
||||
|
||||
|
||||
pass
|
||||
|
2127
src/z80/instructions.py
Normal file
2127
src/z80/instructions.py
Normal file
File diff suppressed because it is too large
Load Diff
105
src/z80/io.py
Normal file
105
src/z80/io.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import sys
|
||||
|
||||
from PySide.QtCore import *
|
||||
from PySide.QtGui import *
|
||||
|
||||
class IO(object):
|
||||
_addresses = []
|
||||
def read(self, address):
|
||||
pass
|
||||
def write(self, address, value):
|
||||
pass
|
||||
|
||||
class Interruptable(object):
|
||||
def interrupt(self):
|
||||
print "interrupt"
|
||||
pass
|
||||
|
||||
class Console(QTextEdit, IO):
|
||||
_addresses = [0x80, 0x81]
|
||||
_wrt_sgnl = Signal(int, int)
|
||||
def __init__(self, interruptable):
|
||||
#assert isinstance(interruptable, Interruptable )
|
||||
super(Console, self).__init__()
|
||||
self.setPlainText("")
|
||||
self.setFontFamily("Courier")
|
||||
self.setFontPointSize(12)
|
||||
self._modifiers = {}
|
||||
self.setCursorWidth(0)
|
||||
self._interruptable = interruptable
|
||||
self._wrt_sgnl.connect(self._write)
|
||||
self.setReadOnly(True)
|
||||
self.setGeometry(300, 0, 640, 480)
|
||||
|
||||
|
||||
self._send_queue = None
|
||||
|
||||
def read(self, address):
|
||||
print "READ ", address
|
||||
if address == 0x80:
|
||||
v = ((1 << 1) | # RTS
|
||||
((self._send_queue is not None) << 0) | # interrupt?
|
||||
0 )
|
||||
return v
|
||||
elif address == 0x81:
|
||||
if self._send_queue is not None:
|
||||
val = self._send_queue
|
||||
self._send_queue = None
|
||||
return val
|
||||
return 0x13
|
||||
|
||||
|
||||
@Slot(int, int)
|
||||
def write(self, address, value):
|
||||
print "------> WRITE ", address
|
||||
self._wrt_sgnl.emit(address, value)
|
||||
|
||||
def _write(self, address, value):
|
||||
if address == 0x80:
|
||||
pass
|
||||
elif address == 0x81:
|
||||
if value < 128 and value > 10:
|
||||
self.setText(self.toPlainText()+chr(value))
|
||||
else:
|
||||
self.setText(self.toPlainText()+".")
|
||||
else:
|
||||
raise Exception("Trying Console IO with wrong address")
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
# print ("Event:", event)
|
||||
if isinstance(event, QKeyEvent):
|
||||
if event.key() > 255:
|
||||
self._modifiers[event.key()] = True
|
||||
#else:
|
||||
#self.setText(self.toPlainText()+chr(event.key()))
|
||||
if True:
|
||||
super(QTextEdit, self).keyPressEvent(event)
|
||||
|
||||
def keyReleaseEvent(self, event):
|
||||
# print ("Event:", event)
|
||||
if isinstance(event, QKeyEvent):
|
||||
key = event.key()
|
||||
if key == Qt.Key_Return or event.key() == Qt.Key_Enter:
|
||||
key = 13
|
||||
if event.key() > 255:
|
||||
self._modifiers[event.key()] = False
|
||||
#print (key)
|
||||
|
||||
if self._send_queue is None:
|
||||
self._send_queue = key
|
||||
self._interruptable.interrupt()
|
||||
pass
|
||||
|
||||
|
||||
class IOMap(object):
|
||||
def __init__(self):
|
||||
self.address = {}
|
||||
pass
|
||||
def addDevice(self, dev):
|
||||
assert isinstance(dev, IO)
|
||||
for i in dev._addresses:
|
||||
self.address[i] = dev
|
||||
|
||||
def interupt(self):
|
||||
pass
|
||||
|
93
src/z80/registers.py
Normal file
93
src/z80/registers.py
Normal file
@@ -0,0 +1,93 @@
|
||||
class BitAccesser(object):
|
||||
def __init__(self, bit_names, registers, reg):
|
||||
object.__setattr__(self, "bits",
|
||||
dict(zip(bit_names, range(7, -1, -1))))
|
||||
self.registers = registers
|
||||
#self.registers = registers
|
||||
self.reg = reg
|
||||
|
||||
def __getattr__(self, b):
|
||||
return (self.registers[self.reg] >> self.bits[b]) & 1
|
||||
|
||||
def __setattr__(self, b, v):
|
||||
if not b in self.bits:
|
||||
object.__setattr__(self, b, v)
|
||||
return
|
||||
|
||||
if v:
|
||||
self.registers[self.reg] = self.registers[self.reg] | (1 << self.bits[b])
|
||||
else:
|
||||
self.registers[self.reg] = self.registers[self.reg] & ((1 << self.bits[b]) ^ 0xFF)
|
||||
|
||||
class Registers(dict):
|
||||
def __init__(self, *arg, **kw):
|
||||
super(Registers, self).__init__(*arg, **kw)
|
||||
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self["PC"] = 0 # Program Counter (16bit)
|
||||
self["SP"] = 0 # Stack Pointer (16bit)
|
||||
self["IX"] = 0 # Index Register X (16bit)
|
||||
self["IY"] = 0 # Index Register Y (16bit)
|
||||
self["I"] = 0 # Interrupt Page Address (8bit)
|
||||
self["R"] = 0 # Memory Refresh (8bit)
|
||||
|
||||
self["A"] = 0 # Accumulator (8bit)
|
||||
self["F"] = 0 # Flags (8bit)
|
||||
self["A_"] = 0 # Alt. Accumulator (8bit)
|
||||
self["F_"] = 0 # Alt. Flags (8bit)
|
||||
|
||||
self["B"] = 0 # General (8bit)
|
||||
self["C"] = 0 # General (8bit)
|
||||
self["B_"] = 0 # General (8bit)
|
||||
self["C_"] = 0 # General (8bit)
|
||||
|
||||
self["D"] = 0 # General (8bit)
|
||||
self["E"] = 0 # General (8bit)
|
||||
self["D_"] = 0 # General (8bit)
|
||||
self["E_"] = 0 # General (8bit)
|
||||
|
||||
self["H"] = 0 # General (8bit)
|
||||
self["L"] = 0 # General (8bit)
|
||||
self["H_"] = 0 # General (8bit)
|
||||
self["L_"] = 0 # General (8bit)
|
||||
|
||||
self["condition"] = BitAccesser(["S", "Z", "F5", "H", "F3", "PV", "N", "C"], self, "F")
|
||||
|
||||
self['HALT']=False #
|
||||
self['IFF']=False # Interrupt flip flop
|
||||
self['IFF2']=False # NM Interrupt flip flop
|
||||
self['IM']=False # Iterrupt mode
|
||||
|
||||
def __setattr__(self, attr, val):
|
||||
if attr in ["HL", "AF", "BC", "DE"]:
|
||||
self[attr[0]] = val >> 8
|
||||
self[attr[1]] = val & 0xFF
|
||||
else:
|
||||
self[attr] = val
|
||||
|
||||
def __getattr__(self, reg):
|
||||
if self.has_key(reg):
|
||||
return self[reg]
|
||||
elif reg in ["HL", "AF", "BC", "DE"]:
|
||||
return self[reg[0]] << 8 | self[reg[1]]
|
||||
else:
|
||||
raise AttributeError("%s Not a known register."%reg)
|
||||
|
||||
def __getitem__(self, reg):
|
||||
if reg in ["BC", "HL", "DE", "AF"]:
|
||||
return getattr(self, reg)
|
||||
else:
|
||||
return super(Registers, self).__getitem__(reg)
|
||||
|
||||
def __setitem__(self, reg, val):
|
||||
if reg in ["BC", "HL", "DE", "AF"]:
|
||||
return setattr(self, reg, val)
|
||||
else:
|
||||
return super(Registers, self).__setitem__(reg, val)
|
||||
|
||||
@classmethod
|
||||
def create(cls):
|
||||
return cls()
|
||||
|
297
src/z80/util.py
Normal file
297
src/z80/util.py
Normal file
@@ -0,0 +1,297 @@
|
||||
register_bits = {'A': 7, 'B': 0, 'C': 1, 'D': 2, 'E': 3, 'H': 4, 'L': 5}
|
||||
index_bytes = [(0xDD, 'IX'), (0xfd, 'IY')]
|
||||
# i, name, bit, val
|
||||
conditions = [(0 << 3, 'NZ', 'Z', 0),
|
||||
(1 << 3, 'Z', 'Z', 1),
|
||||
(2 << 3, 'NC', 'C', 0),
|
||||
(3 << 3, 'C', 'C', 1),
|
||||
(4 << 3, 'PO', 'PV', 0),
|
||||
(5 << 3, 'PE', 'PV', 1),
|
||||
(6 << 3, 'P', 'S', 0),
|
||||
(7 << 3, 'M', 'S', 1),]
|
||||
|
||||
def get_16bit_twos_comp(val):
|
||||
""" Return the value of an 8bit 2s comp number"""
|
||||
sg = val >> 15
|
||||
if sg == 1:
|
||||
mag = - ((val ^ 0xFFFF) + 1)
|
||||
return mag
|
||||
else:
|
||||
return val
|
||||
|
||||
def get_8bit_twos_comp(val):
|
||||
""" Return the value of an 8bit 2s comp number"""
|
||||
sg = val >> 7
|
||||
if sg == 1:
|
||||
mag = - ((val ^ 0xFF) + 1)
|
||||
return mag
|
||||
else:
|
||||
return val
|
||||
|
||||
def make_8bit_twos_comp(val):
|
||||
if val > -1:
|
||||
return val
|
||||
val = (0 - val) ^ 0xFF
|
||||
val += 1
|
||||
return val
|
||||
|
||||
def subtract8(a, b, registers, S=True, N=True, Z=True,
|
||||
F3=True, F5=True, H=True, PV=False, C=False):
|
||||
""" subtract b from a, return result and set flags """
|
||||
res = a - b
|
||||
if S:
|
||||
registers.condition.S = (res >> 7) & 0x01
|
||||
if N:
|
||||
registers.condition.N = 1
|
||||
if Z:
|
||||
registers.condition.Z = (res == 0)
|
||||
if F3:
|
||||
registers.condition.F3 = res & 0x08
|
||||
if F5:
|
||||
registers.condition.F5 = res & 0x20
|
||||
if H:
|
||||
if (b & 0xF) > (a & 0xF) :
|
||||
registers.condition.H = 1
|
||||
else:
|
||||
registers.condition.H = 0
|
||||
if PV:
|
||||
#if (a >> 7 != b >> 7):
|
||||
#if (b >> 7):
|
||||
#if a > (a | (0x1 << 7)):
|
||||
#registers.condition.PV = 1 # overflow
|
||||
a = get_8bit_twos_comp(a)
|
||||
b = get_8bit_twos_comp(b)
|
||||
if (a - b) < -127 or (a - b) > 128:
|
||||
registers.condition.PV = 1 # overflow
|
||||
#if get_8bit_twos_comp(res) < -127 or get_8bit_twos_comp(res) > 128:
|
||||
#registers.condition.PV = 1 # overflow
|
||||
else:
|
||||
registers.condition.PV = 0
|
||||
if C:
|
||||
registers.condition.C = res > 0xFF or res < 0
|
||||
return res & 0xFF
|
||||
|
||||
def subtract8_check_overflow(a, b, registers):
|
||||
return subtract8(a, b, registers, PV=True, C=True)
|
||||
|
||||
def add8(a, b, registers, S=True, Z=True, H=True,
|
||||
PV=True, N=True, C=True, F3=True, F5=True):
|
||||
""" add a and b, return result and set flags """
|
||||
res = a + b
|
||||
if S:
|
||||
registers.condition.S = (res >> 7) & 0x01
|
||||
if Z:
|
||||
registers.condition.Z = (res & 0xFF == 0)
|
||||
if H:
|
||||
if ((a & 0xF) + (b & 0xF)) > 0xF :
|
||||
registers.condition.H = 1
|
||||
else:
|
||||
registers.condition.H = 0
|
||||
if PV:
|
||||
if ((a >> 7) == (b >> 7) and (a >> 7) != ((res & 0xFF) >> 7)):
|
||||
registers.condition.PV = 1 # overflow
|
||||
else:
|
||||
registers.condition.PV = 0
|
||||
if N:
|
||||
registers.condition.N = 0
|
||||
if C:
|
||||
registers.condition.C = res > 0xFF or res < 0
|
||||
if F3:
|
||||
registers.condition.F3 = res & 0x08
|
||||
if F5:
|
||||
registers.condition.F5 = res & 0x20
|
||||
return res & 0xFF
|
||||
|
||||
def add16(a, b, registers):
|
||||
""" add a and b, return result and set flags """
|
||||
res = a + b
|
||||
print a, "+",b,"=",res
|
||||
registers.condition.S = (res >> 15) & 0x01
|
||||
registers.condition.Z = (res == 0)
|
||||
if ((a & 0xFFF) + (b & 0xFFF)) > 0xFFF :
|
||||
registers.condition.H = 1
|
||||
else:
|
||||
registers.condition.H = 0
|
||||
if ((a >> 15) == (b >> 15) and (a >> 15) != ((res & 0xFFFF) >> 15)):
|
||||
registers.condition.PV = 1 # overflow
|
||||
else:
|
||||
registers.condition.PV = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.C = res >> 0xFFFF or res < 0
|
||||
|
||||
registers.condition.F3 = res & 0x0800
|
||||
registers.condition.F5 = res & 0x2000
|
||||
return res & 0xFFFF
|
||||
|
||||
def subtract16(a, b, registers):
|
||||
""" subtract b from a, return result and set flags """
|
||||
res = a - b
|
||||
print a, "-", b, "=", res, "(", hex(res), ")"
|
||||
registers.condition.S = (res >> 15) & 0x01
|
||||
registers.condition.N = 1
|
||||
registers.condition.Z = (res == 0)
|
||||
registers.condition.F3 = res & 0x0800
|
||||
registers.condition.F5 = res & 0x2000
|
||||
if (b & 0xFFF) > (a & 0xFFF) :
|
||||
registers.condition.H = 1
|
||||
else:
|
||||
registers.condition.H = 0
|
||||
|
||||
if (a >> 15 != (res&0xFFFF) >> 15):
|
||||
registers.condition.PV = 1 # overflow
|
||||
else:
|
||||
registers.condition.PV = 0
|
||||
|
||||
registers.condition.C = res > 0xFFFF or res < 0
|
||||
return res & 0xFFFF
|
||||
|
||||
def inc16(val):
|
||||
val += 1
|
||||
if val > 0xFFFF:
|
||||
val = 0x0
|
||||
return val
|
||||
|
||||
def dec16(val):
|
||||
val -= 1
|
||||
if val < 0:
|
||||
val = 0xFFFF
|
||||
return val
|
||||
|
||||
def inc8(val):
|
||||
val += 1
|
||||
if val > 0xFF:
|
||||
val = 0x0
|
||||
return val
|
||||
|
||||
def dec8(val):
|
||||
val -= 1
|
||||
if val < 0:
|
||||
val = 0xFF
|
||||
return val
|
||||
|
||||
def parity(n):
|
||||
p=0
|
||||
for i in range(0,8):
|
||||
p+=(n >> i) & 0x01
|
||||
return not (p % 2)
|
||||
|
||||
def a_and_n(registers, n):
|
||||
registers.A = registers.A & n
|
||||
registers.condition.H = 1
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(registers.A)
|
||||
registers.condition.C = 0
|
||||
registers.condition.Z = (registers.A==0)
|
||||
registers.condition.S = (registers.A>>7)
|
||||
set_f5_f3_from_a(registers)
|
||||
|
||||
|
||||
def a_or_n(registers, n):
|
||||
registers.A = registers.A | n
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(registers.A)
|
||||
registers.condition.C = 0
|
||||
registers.condition.Z = (registers.A==0)
|
||||
registers.condition.S = (registers.A>>7)
|
||||
set_f5_f3_from_a(registers)
|
||||
|
||||
def a_xor_n(registers, n):
|
||||
registers.A = registers.A ^ n
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(registers.A)
|
||||
registers.condition.C = 0
|
||||
registers.condition.Z = (registers.A==0)
|
||||
registers.condition.S = (registers.A>>7)
|
||||
set_f5_f3_from_a(registers)
|
||||
|
||||
def rotate_left_carry(registers, n):
|
||||
c = n >> 7
|
||||
v = (n << 1 | c) & 0xFF
|
||||
registers.condition.S = v >> 7
|
||||
registers.condition.Z = (v == 0)
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(v)
|
||||
registers.condition.C = c
|
||||
return v
|
||||
|
||||
|
||||
def rotate_left(registers, n):
|
||||
c = n >> 7
|
||||
v = (n << 1 | registers.condition.C) & 0xFF
|
||||
registers.condition.S = v >> 7
|
||||
registers.condition.Z = (v == 0)
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(v)
|
||||
registers.condition.C = c
|
||||
return v
|
||||
|
||||
|
||||
|
||||
|
||||
def rotate_right_carry(registers, n):
|
||||
c = n & 0x01
|
||||
v = n >> 1 | (c << 7)
|
||||
registers.condition.S = v >> 7
|
||||
registers.condition.Z = (v == 0)
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(v)
|
||||
registers.condition.C = c
|
||||
return v
|
||||
|
||||
|
||||
def rotate_right(registers, n):
|
||||
c = n & 0x01
|
||||
v = n >> 1 | (registers.condition.C << 7)
|
||||
registers.condition.S = v >> 7
|
||||
registers.condition.Z = (v == 0)
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(v)
|
||||
registers.condition.C = c
|
||||
return v
|
||||
|
||||
|
||||
def shift_left(registers, n):
|
||||
c = n >> 7
|
||||
v = (n << 1 ) & 0xFF
|
||||
registers.condition.S = v >> 7
|
||||
registers.condition.Z = (v == 0)
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(v)
|
||||
registers.condition.C = c
|
||||
return v
|
||||
|
||||
|
||||
def shift_right(registers, n):
|
||||
c = n & 0x01
|
||||
msb = n >> 7
|
||||
v = n >> 1 | (msb << 7)
|
||||
registers.condition.S = v >> 7
|
||||
registers.condition.Z = (v == 0)
|
||||
registers.condition.H = 0
|
||||
registers.condition.N = 0
|
||||
registers.condition.PV = parity(v)
|
||||
registers.condition.C = c
|
||||
return v
|
||||
|
||||
|
||||
def offset_pc(registers, jump):
|
||||
registers.PC += get_8bit_twos_comp(jump)
|
||||
if registers.PC > 0xFFFF:
|
||||
registers.PC -= 0xFFFF - 1
|
||||
if registers.PC < 0:
|
||||
registers.PC += 0xFFFF + 1
|
||||
|
||||
def set_f5_f3(registers, v):
|
||||
registers.condition.F5 = v & 0x20
|
||||
registers.condition.F3 = v & 0x08
|
||||
|
||||
def set_f5_f3_from_a(registers):
|
||||
set_f5_f3(registers, registers.A)
|
||||
|
118
src/z80sbc.py
Normal file
118
src/z80sbc.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from z80 import util, io, gui, registers, instructions
|
||||
|
||||
import copy
|
||||
|
||||
from time import sleep, time
|
||||
import sys
|
||||
from PySide.QtCore import *
|
||||
from PySide.QtGui import *
|
||||
|
||||
import threading
|
||||
|
||||
#logging.basicConfig(level=logging.INFO)
|
||||
|
||||
class Z80SBC(io.Interruptable):
|
||||
def __init__(self):
|
||||
self.registers = registers.Registers()
|
||||
self.instructions = instructions.InstructionSet(self.registers)
|
||||
self._memory = bytearray(64*1024)
|
||||
self._read_rom("../roms/ROM.HEX")
|
||||
self._iomap = io.IOMap()
|
||||
self._console = io.Console(self)
|
||||
self._reg_gui = gui.RegistersGUI(self.registers)
|
||||
self._mem_view = gui.MemoryView(self._memory, self.registers)
|
||||
|
||||
self._iomap.addDevice(self._console)
|
||||
self._console.show()
|
||||
self._reg_gui.show()
|
||||
self._mem_view.show()
|
||||
|
||||
self._interrupted = False
|
||||
|
||||
def interrupt(self):
|
||||
self._interrupted = True
|
||||
|
||||
def _read_rom(self, romfile):
|
||||
with open(romfile, "r") as f:
|
||||
while True:
|
||||
line = f.readline()
|
||||
if line[0] != ":":
|
||||
raise Exception("Bad start code in hex file.")
|
||||
count = int(line[1:3], 16)#.decode("hex")
|
||||
address = int(line[3:7], 16) #.decode("hex")
|
||||
if address + count > len(self._memory):
|
||||
raise Exception("Trying to create M2764 ROM with too large a ROM file")
|
||||
rtype = line[7:9]
|
||||
pos = 9
|
||||
if rtype == "01":
|
||||
break
|
||||
for b in range(count):
|
||||
byte = int(line[pos+(2*b):pos+(2*b)+2], 16) #. decode("hex")
|
||||
self._memory[address+b] = byte
|
||||
|
||||
def step_instruction(self):
|
||||
ins, args = False, []
|
||||
pc = self.registers.PC
|
||||
|
||||
if self._interrupted and self.registers.IFF:
|
||||
self.registers.IFF = False
|
||||
self._interrupted = False
|
||||
if self.registers.IM == 1:
|
||||
print "!!! Interrupt !!!"
|
||||
ins, args = self.instructions << 0xCD
|
||||
ins, args = self.instructions << 0x38
|
||||
ins, args = self.instructions << 0x00
|
||||
self.registers.IFF = False
|
||||
else:
|
||||
while not ins:
|
||||
ins, args = self.instructions << self._memory[self.registers.PC]
|
||||
self.registers.PC = util.inc16(self.registers.PC)
|
||||
#print( "{0:X} : {1} ".format(pc, ins.assembler(args)))
|
||||
|
||||
rd = ins.get_read_list(args)
|
||||
data = [0] * len(rd)
|
||||
for n, i in enumerate(rd):
|
||||
if i < 0x10000:
|
||||
data[n] = self._memory[i]
|
||||
else:
|
||||
address = i & 0xFF
|
||||
data[n] = self._iomap.address[address].read(address)
|
||||
wrt = ins.execute(data, args)
|
||||
for i in wrt:
|
||||
|
||||
if i[0] > 0x10000:
|
||||
address = i[0] & 0xFF
|
||||
#iomap.address[address].write.emit(address, i[1])
|
||||
self._iomap.address[address].write(address, i[1])
|
||||
#print (chr(i[1]))
|
||||
else:
|
||||
self._memory[i[0]] = i[1]
|
||||
|
||||
return ins, args
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
''' Main Program '''
|
||||
qt_app = QApplication(sys.argv)
|
||||
|
||||
mach = Z80SBC()
|
||||
def worker():
|
||||
t = time()
|
||||
|
||||
while True:
|
||||
# t = time()
|
||||
ins, args = mach.step_instruction()
|
||||
print ins.assembler(args)
|
||||
sleep(0.00000001)
|
||||
# print (time() - t) / ins.tstates
|
||||
|
||||
# mach._mem_view.update()
|
||||
# mach._reg_gui.update()
|
||||
|
||||
|
||||
|
||||
thread = threading.Thread(target=worker)
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
||||
qt_app.exec_()
|
Reference in New Issue
Block a user