Skip to content

Instantly share code, notes, and snippets.

@sugarflower
Last active January 15, 2024 13:34
Show Gist options
  • Save sugarflower/6c5171bd933adf1c44e8d9a40317a8e5 to your computer and use it in GitHub Desktop.
Save sugarflower/6c5171bd933adf1c44e8d9a40317a8e5 to your computer and use it in GitHub Desktop.

DAAうごいた。

なんかいろいろなところがおかしかったようで苦労したけど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")

ASM

こんなのを使ってる。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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment