なんかいろいろなところがおかしかったようで苦労したけどDAAは何とかなった模様。
MEMORY_SIZE = 0xfff
#MEMORY_SIZE = 0x0f
import time
class Memory:
def __init__(self):
self.memory = bytearray([0] * (MEMORY_SIZE + 1))
def get(self, addr):
return self.memory[addr]
def set(self, addr, value):
self.memory[addr] = value & 0xff
def get_word(self, addr):
return self.get(addr) | self.get(addr + 1) << 8
def set_word(self, addr, value):
self.set(addr, (value & 0xff))
self.set(addr + 1, (value >> 8))
class Register:
def __init__(self, memory):
# B C D E H L (M) A F SP PC
self.register = bytearray([0] * 13)
self.memory = memory
def get(self, index):
if index == 8:
buf = self.register[8]
buf = buf & 0b1101_0111
buf = buf | 0b0000_0010
else:
buf = self.register[index]
return buf
def set(self, index, value):
self.register[index] = value & 0xff
if index == 6:
self.memory.set(self.get_word(2), value)
if index == 4 or index == 5:
self.update()
def get_word(self, index):
# BC DE HL AF SP PC
if index < 3:
lval = self.get(index << 1)
hval = self.get((index << 1) + 1)
else:
lval = self.get((index << 1) + 1)
hval = self.get((index << 1) + 2)
return (lval << 8) | hval
def set_word(self, index, value):
# BC DE HL AF SP PC
hval = value & 0xff
lval = value >> 8
if index < 3:
self.set(index << 1, lval)
self.set((index <<1 ) + 1, hval)
else:
self.set((index << 1) + 1, lval)
self.set((index << 1) + 2, hval)
def update(self):
self.register[6] = self.memory.get(self.get_word(2))
def monitor(self):
print("B %02X C %02X" % (self.get(0), self.get(1)) )
print("D %02X E %02X" % (self.get(2), self.get(3)) )
print("H %02X L %02X" % (self.get(4), self.get(5)) )
print("M %02X SZ0A0P1C" % self.get(6) )
print("A %02X F %s" % (self.get(7), format(self.get(8), "08b")) )
print("SP %04X" % self.get_word(4) )
print("PC %04X" % self.get_word(5) )
print("")
def a16(value):
if value > MEMORY_SIZE:
value -= MEMORY_SIZE + 1
elif value < 0:
value += MEMORY_SIZE
return value & MEMORY_SIZE
def d16(value):
if value > 0xffff:
value -= 0xffff + 1
elif value < 0:
value += 0xffff
return value & 0xffff
def d8(value):
if value > 0xff:
value -= 0xff + 1
elif value < 0:
value += 0xff
return value & 0xff
class CPU:
def __init__(self, memory, register, hardware):
self.memory = memory
self.register = register
self.hardware = hardware
self.running = True
def fetch(self):
pc = self.register.get_word(5)
value = self.memory.get(pc)
self.register.set_word(5, a16(pc + 1))
return value
def fetch_word(self):
pc = self.register.get_word(5)
value = self.memory.get_word(pc)
self.register.set_word(5, a16(pc + 2))
return value
def push(self, value):
sp = a16(self.register.get_word(4) - 2)
self.memory.set_word(sp, value)
self.register.set_word(4, a16(sp))
def pop(self):
sp = self.register.get_word(4)
value = self.memory.get_word(sp)
self.register.set_word(4, a16(sp + 2))
return value
# flg
# S Z 0 A 0 P 1 C
# A (HC) not impl
def check_parity(self, buf):
v = buf
v ^= (v >> 4)
v ^= (v >> 2)
v ^= (v >> 1)
v &= 1
f = self.register.get(8)
self.register.set(8, f & 0b11111011 | ((v ^ 1) << 2))
def check_carry(self, buf):
v = 0
if buf > 0xff:
v = 1
f = self.register.get(8)
self.register.set(8, f & 0b11111110 | v)
def check_signed(self, buf):
v = 0
#if buf < 0 or buf & 0x100 != 0:
if buf & 0x80 != 0:
v = 1
f = self.register.get(8)
self.register.set(8, f & 0b01111111 | (v << 7))
def check_zero(self, buf):
v = 0
if buf == 0:
v = 1
f = self.register.get(8)
self.register.set(8, f & 0b10111111 | (v << 6))
def get_parity(self):
f = self.register.get(8)
return (f >> 2) & 1
def get_carry(self):
f = self.register.get(8)
return f & 1
def get_halfcarry(self):
f = self.register.get(8)
return (f >> 4) & 1
def get_signed(self):
f = self.register.get(8)
return (f >> 7) & 1
def get_zero(self):
f = self.register.get(8)
return (f >> 6) & 1
def set_carry(self, v):
f = self.register.get(8)
self.register.set(8, f & 0b11111110 | v)
def set_signed(self, v):
f = self.register.get(8)
self.register.set(8, f & 0b01111111 | (v << 7))
def set_halfcarry(self, buf):
f = self.register.get(8)
self.register.set(8, f & 0b11101111 | (buf << 4))
# group 0 - 3
# con 0 or 1
def check_flg(self, op):
f = op & 1
t = op >> 1
if t == 0: # Z
return self.get_zero() == f
elif t == 1: # C
return self.get_carry() == f
elif t == 2: # P
return self.get_parity() == f
elif t == 3: # S
return self.get_signed() == f
def calc(self, op, v):
buf = 0
acm = self.register.get(7)
if op == 0: # ADD HC
buf = acm + v
if (acm & 0xf) + (v & 0xf) > 0xf:
self.set_halfcarry(1)
else:
self.set_halfcarry(0)
elif op == 1: # ADC HC
c = self.get_carry()
buf = acm + v + c
if ((acm & 0xf) + ((v + c) & 0xf)) > 0xf:
self.set_halfcarry(1)
else:
self.set_halfcarry(0)
elif op == 2: # SUB HC
buf = acm - v
if ((acm & 0xf0) - (v & 0xf0)) & 0xf != 0:
self.set_halfcarry(1)
else:
self.set_halfcarry(0)
elif op == 3: # SBB HC
c = self.get_carry()
buf = acm - v - c
if (acm & 0xf0 - ((v - c) & 0xf0)) & 0xf != 0:
self.set_halfcarry(1)
else:
self.set_halfcarry(0)
elif op == 4: # ANA
buf = acm & v
elif op == 5: # XRA
buf = acm ^ v
elif op == 6: # ORA
buf = acm | v
elif op == 7: # CMP
buf = acm - v
self.check_parity(buf)
self.check_signed(buf)
self.check_zero(buf)
#if op not in (1, 3):
if op in (0, 1):
self.check_carry(buf)
if op != 7:
self.register.set(7, buf)
def mainloop(self):
while self.running:
opcode = self.fetch()
op1 = opcode >> 6
op2 = opcode >> 3 & 0x07
op3 = opcode & 0x07
if op1 == 0:
if op3 == 0: #NOP 保留
pass
elif op3 == 1: #LXI DAD
op4 = op2 & 1
op2 = op2 >> 1
if op2 == 3: # AF指定の場合SPに修正
op2 = 4
if op4 == 0: #LXI
v = self.fetch_word()
self.register.set_word(op2, v)
else: #DAD
hl = self.register.get_word(2)
v = self.register.get_word(op2)
self.register.set_word(2, d16(hl + v))
elif op3 == 2: #STAX SHLD STA LDAX LHLD LDA
if op2 in (0, 2): #STAX
addr = self.register.get_word(op2 >> 1)
a = self.register.get(7)
self.memory.set(addr, a)
elif op2 == 4: #SHLD
hl = self.register.get_word(2)
addr = self.fetch_word()
self.memory.set_word(addr, hl)
elif op2 == 6: #STA
a = self.register.get(7)
addr = self.fetch_word()
self.memory.set(addr, a)
elif op2 in (1, 3): #LDAX
addr = self.register.get_word((op2 - 1) >> 1)
v = self.memory.get(addr)
self.register.set(7, v)
elif op2 == 5: #LHLD
addr = self.fetch_word()
v = self.memory.get_word(addr)
self.register.set_word(2, v)
elif op2 == 7: #LDA
addr = self.fetch_word()
v = self.memory.get(addr)
self.register.set(7, v)
elif op3 == 3: #INX DCX
op4 = op2 & 1
op2 = op2 >> 1
if op4 == 0: #INX
v = self.register.get_word(op2) + 1
self.register.set_word(op2, d16(v))
else: #DCX
v = self.register.get_word(op2) - 1
self.register.set_word(op2, d16(v))
elif op3 == 4: #INR HC
v = self.register.get(op2)
h = (v & 0x0f) + 1
if h > 0x0f:
self.set_halfcarry(1)
else:
self.set_halfcarry(0)
a = v + 1
self.check_parity(a)
self.check_signed(a)
self.check_zero(a)
self.check_carry(a)
self.register.set(op2, d8(a))
elif op3 == 5: #DCR HC
v = self.register.get(op2)
h = (v & 0xf0) - 1
a = v - 1
if 0xf != 0:
self.set_halfcarry(1)
else:
self.set_halfcarry(0)
self.check_parity(a)
self.check_signed(a)
self.check_zero(a)
self.register.set(op2, d8(a))
elif op3 == 6: #MVI
v = self.fetch()
self.register.set(op2, v)
elif op3 == 7: # RLC RAL DAA STC RRC RAR CMA CMC
if op2 == 0: #RLC
a = self.register.get(7)
c = a >> 7 & 1
a = (a << 1) & 0xff | c
self.set_carry(c)
self.register.set(7, a)
elif op2 == 1: #RRC
a = self.register.get(7)
c = a & 1
a = (a >> 1) | (c << 7)
self.set_carry(c)
self.register.set(7, a)
elif op2 == 2: #RAL
a = self.register.get(7)
b = a >> 7 & 1
c = self.get_carry()
a = (a << 1) & 0xff | c
self.register.set(7, a)
self.set_carry(b)
elif op2 == 3: #RAR
a = self.register.get(7)
b = a & 1
c = self.get_carry()
a = (a >> 1) | (c << 7)
self.register.set(7, a)
self.set_carry(b)
elif op2 == 4: #DAA
a = self.register.get(7)
if self.get_halfcarry() == 1 or ((a & 0xf) > 9):
self.calc(0, 0x06)
a = self.register.get(7)
if self.get_carry() == 1 or a > 0x99:
self.calc(0, 0x60)
elif op2 == 5: #CMA
a = self.register.get(7) ^ 0xff
self.register.set(7, a)
elif op2 == 6: #STC
self.set_carry(1)
elif op2 == 7: #CMC
c = self.get_carry()
self.set_carry(c ^ 1)
elif op1 == 1: # MOV / HLT
if opcode == 0x76: # HLT
self.running = False
else: # MOV
self.register.set(op2, self.register.get(op3))
elif op1 == 2: # ADD/ ADC / SUB / SBB / ANA / XRA / ORA / CMP
self.calc(op2, self.register.get(op3))
elif op1 == 3:
if op3 == 0: # RNZ RNC RPO RP RZ RC RPE RM
if self.check_flg(op2):
addr = self.pop()
self.register.set_word(5, addr)
elif op3 == 1: #POP RET PCHL SPHL
b1 = op2 & 1
b2 = op2 >> 1
if b1 == 0: # POP
v = self.pop()
self.register.set_word(b2, v)
else: # RET PCHL SPHL
if b2 == 2: # PCHL
hl = self.register.get_word(2)
self.register.set_word(5, hl)
elif b2 == 3: # SPHL
hl = self.register.get_word(2)
self.register.set_word(4, hl)
else: # RET
addr = self.pop()
self.register.set_word(5, addr)
elif op3 == 2: #JNZ JNC JPO JP JZ JC JPE JM
addr = self.fetch_word()
if self.check_flg(op2):
self.register.set_word(5, addr)
elif op3 == 3: #JMP OUT XTHL DI JMP IN XCHG EI
if op2 in (0, 1): # JMP
addr = self.fetch_word()
self.register.set_word(5, addr)
elif op2 == 2: #OUT
v = self.fetch()
self.hardware.out_(self.register.get(7), v)
elif op2 == 3: #IN
v = self.fetch()
self.register.set(7, self.hardware.in_(v))
elif op2 == 4: # XTHL
v = self.pop()
self.push(self.register.get_word(2))
self.register.set_word(2, v)
elif op2 == 5: # XCHG
v = self.register.get_word(1)
self.register.set_word(1, self.register.get_word(2))
self.register.set_word(2, v)
pass
elif op2 == 6: # DI
pass
elif op2 == 7: # EI
pass
elif op3 == 4: #CNZ CNC CPO CP CZ CC CPE CM
addr = self.fetch_word()
if self.check_flg(op2):
pc = self.register.get_word(5)
self.push(pc)
self.register.set_word(5, addr)
elif op3 == 5: #PUSH CALL
b1 = op2 & 1
b2 = op2 >> 1
if b1 == 0: # PUSH
v = self.register.get_word(b2)
self.push(v)
else: # CALL
addr = self.fetch_word()
pc = self.register.get_word(5)
self.push(pc)
self.register.set_word(5, addr)
elif op3 == 6: # ADI SUI ANI ORI ACI SBI XRI CPI
self.calc(op2, self.fetch())
elif op3 == 7: # RST
vec = op2 << 3
self.register.set_word(5, addr)
self.register.update()
time.sleep(0.001)
"""
self.register.monitor()
# memory monitor
for i in range(len(pg)):
print(format(memory.get(i), "02X"), end=" ")
print("\n\n")
"""
class Hardware:
def __init__(self):
pass
def in_(self, n):
return 0xff
def out_(self, a, n):
if n == 5:
print(chr(a), end="")
if __name__ == "__main__":
memory = Memory()
register = Register(memory)
hardware = Hardware()
cpu = CPU(memory=memory, register=register, hardware=hardware)
pg = (
0x21, 0x13, 0x00,
0x3e, 0x04,
0x46,
0x88,
0x27,
0x77,
0xd2, 0x12, 0x00,
0x3e, 0x00,
0x23,
0xc3, 0x05, 0x00,
0x76,
0x99, 0x99, 0x11, 0x00
)
for i, p in enumerate(pg):
memory.set(i, p)
#cpu.register.set_word(5, 0x800)
cpu.mainloop()
# memory monitor
for i in range(len(pg)):
print(format(memory.get(i), "02X"), end=" ")
print("\n\n")
こんなのを使ってる。z80asmでアセンブルしているのでザイログニーモニックにて失礼
0000 21 13 00 ld hl, data
0003 3e 01 ld a, 1
0005
0005 46 loop: ld b, (hl)
0006 88 adc a, b
0007
0007 27 daa
0008 77 ld (hl), a
0009
0009 d2 12 00 jp nc, end
000c 3e 00 ld a, 0
000e 23 inc hl
000f c3 05 00 jp loop
0012
0012
0012
0012 76 end: halt
0013
0013
0013
0013 99 00 00 00 data: db 0x99, 0x00, 0x00, 0x00