Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

verbalise instructions example #55

Open
mortenjc opened this issue Feb 25, 2024 · 1 comment
Open

verbalise instructions example #55

mortenjc opened this issue Feb 25, 2024 · 1 comment
Assignees
Labels

Comments

@mortenjc
Copy link

I just downloaded your emulator which I plan to use for understanding an
ancient computer called Q1. This is part of a danish computer history project.

I managed to write a brief loader code to load the ROMs into memory and
then use the single_step python example to get started.

However it is not exactly clear to me how to customise this to my needs and
maybe you could advise me on this?

The code currently looks like this:

import z80, sys

def load(m, file, address):
        fh = open(file, 'rb')
        block = list(fh.read())
        assert len(block) + address < 65535
        for i in range(len(block)):
            m.memory[address + i] = block[i]
        print(f'loaded {len(block)} bytes from {file} at address {address}')

def main():
    m = z80.Z80Machine()

    load(m, "../../mjcgit/Q1/src/roms/IC25.BIN", 0x0000)
    load(m, "../../mjcgit/Q1/src/roms/IC26.BIN", 0x0400)
    load(m, "../../mjcgit/Q1/src/roms/IC27.BIN", 0x0800)
    load(m, "../../mjcgit/Q1/src/roms/IC28.BIN", 0x0C00)

    while True:
        print(f'PC={m.pc:04X} {m.memory[m.pc]:02X} {m.memory[m.pc+1]:02X} {m.memory[m.pc+2]:02X} {m.memory[m.pc+3]:02X} ;          | SP={m.sp:04X}, BC={m.bc:04X}, DE={m.de:04X}, HL={m.hl:04X}')

        data = m.memory[m.pc] +  (m.memory[m.pc+1] << 8) + (m.memory[m.pc+2] << 16) + (m.memory[m.pc+3] << 24)
        if data == 0:
            print(f'all zeroes at {m.pc:04x}, exiting ...')
            sys.exit()

        # Limit runs to a single tick so each time we execute exactly one instruction.
        m.ticks_to_stop = 1
        m.run()

And produces output like this:

loaded 1024 bytes from ../../mjcgit/Q1/src/roms/IC25.BIN at address 0
loaded 1024 bytes from ../../mjcgit/Q1/src/roms/IC26.BIN at address 1024
loaded 1024 bytes from ../../mjcgit/Q1/src/roms/IC27.BIN at address 2048
loaded 1024 bytes from ../../mjcgit/Q1/src/roms/IC28.BIN at address 3072
PC=0000 C3 E5 01 C3 ;          | SP=0000, BC=0000, DE=0000, HL=0000
PC=01E5 ED 56 3E 04 ;          | SP=0000, BC=0000, DE=0000, HL=0000
PC=01E7 3E 04 D3 01 ;          | SP=0000, BC=0000, DE=0000, HL=0000
etc.

However I'd like to be able to produce output like this:

loaded 1024 bytes from roms/IC25.BIN at address 0
loaded 1024 bytes from roms/IC26.BIN at address 1024
0000 C3 E5 01     ; JP 01E5        | PC:01E5, SP:0000, A:00,  BC:0000, DE:0000 HL:0000, S Z PV N: 0 0 0 0
01E5 ED 56        ; IM1            | PC:01E7, SP:0000, A:00,  BC:0000, DE:0000 HL:0000, S Z PV N: 0 0 0 0
01E7 3E 04        ; LD A,4         | PC:01E9, SP:0000, A:04,  BC:0000, DE:0000 HL:0000, S Z PV N: 0 0 0 0
01E9 D3 01        ; OUT (1),A      | PC:01EB, SP:0000, A:04,  BC:0000, DE:0000 HL:0000, S Z PV N: 0 0 0 0
01EB 11 3F 00     ; LD DE,003F     | PC:01EE, SP:0000, A:04,  BC:0000, DE:003F HL:0000, S Z PV N: 0 0 0 0

which is from an early attempt to write my own emulator. I realised that a) I was probably not smart enough to do this correctly and 2b) there are plenty of emulators 'out there', this being one of them :-)

But I could not understand from looking at your code how I can adapt the single_step code to print out

  1. just the actually used bytes 1, 2, 3 or 4 according to the opcode and
  2. how to integrate the disassembler to print out the mnemonics

I hope you can help to shed some light on this.

Thanks for making this project available

Best

Morten

@kosarev kosarev self-assigned this Feb 25, 2024
@kosarev
Copy link
Owner

kosarev commented Feb 25, 2024

(This was originally discussed in a private email thread; I replicate the response here for visibility.)

Hi Morten,

If you just want to verbalise the instruction that is about to be executed, then I think something like the following should do.

Thanks for asking -- I think I should add some example code disassembling and executing individual instructions. It would also be nice to have means to run a disassembled instruction directly without even having it in memory!

def main():
    m = z80.Z80Machine()

    # This part of the emulator is still under development,
    # hence the underscore in the name.
    b = z80._Z80InstrBuilder()

    load(m, "../../mjcgit/Q1/src/roms/IC25.BIN", 0x0000)
    load(m, "../../mjcgit/Q1/src/roms/IC26.BIN", 0x0400)
    load(m, "../../mjcgit/Q1/src/roms/IC27.BIN", 0x0800)
    load(m, "../../mjcgit/Q1/src/roms/IC28.BIN", 0x0C00)

    while True:
        # Decode the instruction.
        MAX_INSTR_SIZE = 4
        instr = b.build_instr(m.pc, bytes(m.memory[m.pc:m.pc + MAX_INSTR_SIZE]))

        # Get and verbalise the instruction bytes.
        instr_bytes = bytes(m.memory[instr.addr:instr.addr + instr.size])
        instr_bytes = ' '.join(f'{b:02X}' for b in instr_bytes)

        # Execute the instruction.
        # Limit runs to a single tick so each time we execute exactly one instruction.
        m.ticks_to_stop = 1
        m.run()

        # Print the instruction, its address and bytes and registers after execution.
        # print('0000 C3 E5 01     ; JP 01E5        | PC:01E5, SP:0000, A:00,  BC:0000, DE:0000 HL:0000, S Z PV N: 0 0 0 0')
        print(f'{instr.addr:04X} {instr_bytes:12} ; {str(instr).upper():14} '
              f'| PC:{m.pc:04X}, SP:{m.sp:04X} {m.memory[m.pc]:02X} ...')

        data = m.memory[m.pc] +  (m.memory[m.pc+1] << 8) + (m.memory[m.pc+2] << 16) + (m.memory[m.pc+3] << 24)
        if data == 0:
            print(f'all zeroes at {m.pc:04x}, exiting ...')
            sys.exit()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants