Dragon emulator written in Python ???

A place to discuss everything Dragon related that doesn't fall into the other categories.
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

I enhanced the scraping scripts with: https://github.com/jedie/DragonPy/commi ... ec04c4f6b6

Now i merged the informations from the three sources.

The merged python "data" script looks now -> https://github.com/jedie/DragonPy/blob/ ... ata_raw.py
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

I have worked more on the "code generator"...

The generated code skeleton looks now like this:

Code: Select all

class CPU6809Skeleton(object):
    @opcode( # Add B accumulator to X (unsigned)
        0x3a, # ABX (inherent)
    )
    def instruction_ABX(self, opcode):
        """
        Add the 8-bit unsigned value in accumulator B into index register X.

        source code forms: ABX

        CC bits "HNZVC": -----
        """
        raise NotImplementedError("TODO: $%x ABX") % opcode

    @opcode( # Add memory to accumulator with carry
        0x89, 0x99, 0xa9, 0xb9, # ADCA (immediate, direct, indexed, extended)
        0xc9, 0xd9, 0xe9, 0xf9, # ADCB (immediate, direct, indexed, extended)
    )
    def instruction_ADC(self, opcode, ea=None, operand=None):
        """
        Adds the contents of the C (carry) bit and the memory byte into an 8-bit
        accumulator.

        source code forms: ADCA P; ADCB P

        CC bits "HNZVC": aaaaa
        """
        self.CC_HNZVC(a, b, r)
        raise NotImplementedError("TODO: $%x ADC") % opcode
...
full code here: https://github.com/jedie/DragonPy/blob/ ... keleton.py
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

Now the generated code is used: https://github.com/jedie/DragonPy/compa ... ...220b514

I reimplement some instructions. e.g.:
COM: https://github.com/jedie/DragonPy/blob/ ... 1273-L1309
JMP: https://github.com/jedie/DragonPy/blob/ ... 1472-L1488
LDA,LDB: https://github.com/jedie/DragonPy/blob/ ... 1529-L1542

I have some trouble to get the CC flags worked. I copied the XRoar code for DEC together:

Code: Select all

 #define SET_Z(r) ( REG_CC |= ((r) ? 0 : CC_Z) )
#define SET_N8(r) ( REG_CC |= (r&0x80)>>4 )
#define SET_NZ8(r) ( SET_N8(r), SET_Z(r&0xff) )

#define CLR_NZV ( REG_CC &= ~(CC_N|CC_Z|CC_V) )

static uint8_t op_dec(struct MC6809 *cpu, uint8_t in) {
unsigned out = in - 1;
CLR_NZV;
SET_NZ8(out);
if (out == 0x7f) REG_CC |= CC_V;
return out;
}

tmp1 = op_dec(cpu, tmp1); break; // DEC, DECA, DECB
My Python interpretation is this:

Code: Select all

    def set_Z8(self, r):
        self.Z = 1 if r & 0xff == 0 else 0

    def set_N8(self, r):
        self.N = 1 if signed8(r) < 0 else 0

    def update_NZ8(self, r):
        self.set_N8(r)
        self.set_Z8(r)

...

        r = a - 1
        self.cc.update_NZ8(r)
        if r == 0x7f:
            self.cc.V = 1
My code is from:
DEC: https://github.com/jedie/DragonPy/blob/ ... 1358-L1418
CC: https://github.com/jedie/DragonPy/blob/ ... #L114-L175

I must collect some concrete example values for the unittests.
Can someone give me some 6809 assembler code examples for carry/overflow cc flags?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

Next question: Are all 8/16Bit arithmetic instruction signed?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

next small steps done: BEW, BIT, BNE and "relative" addressing mode, done.

Debug output looks like: https://gist.github.com/jedie/6779646

commints: https://github.com/jedie/DragonPy/commits
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
User avatar
JeeK
Posts: 67
Joined: Fri Aug 16, 2013 10:45 am
Location: Vienna, Austria
Contact:

Re: Dragon emulator written in Python ???

Post by JeeK »

jedie wrote: [..]
My Python interpretation is this:

Code: Select all

    def set_Z8(self, r):
        self.Z = 1 if r & 0xff == 0 else 0

    def set_N8(self, r):
        self.N = 1 if signed8(r) < 0 else 0

    def update_NZ8(self, r):
        self.set_N8(r)
        self.set_Z8(r)
Why not simply

Code: Select all

    def set_N8(self, r):
        self.N = 1 if r & 0x80 else 0
?
jedie wrote: [..]
I must collect some concrete example values for the unittests.
Can someone give me some 6809 assembler code examples for carry/overflow cc flags?

Code: Select all

 lda #-128
 suba #1
; overflow set but no carry
 lda #127
 adda #1
; overflow set but no carry
The dragon on my side: http://klasek.at/hc/dragon/
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

JeeK wrote:

Code: Select all

 lda #-128
 suba #1
; overflow set but no carry
 lda #127
 adda #1
; overflow set but no carry
Thank you, that's really really helps me!

I have made two unittests:

Code: Select all

    def test_Overflow01(self):
        self.cpu_test_run(start=0x1000, end=None, mem=[
            0x86, 0x80, # LDA #-128
            0x80, 0x01, # SUBA #1
        ])
        self.assertEqual(self.cpu.accu_a.get(), 0x7f) # $7f == signed: 127 == unsigned: 127
        self.assertEqual(self.cpu.cc.N, 0) # N - 0x08 - bit 3 - Negative result (twos complement)
        self.assertEqual(self.cpu.cc.Z, 0) # Z - 0x04 - bit 2 - Zero result
        self.assertEqual(self.cpu.cc.V, 1) # V - 0x02 - bit 1 - Overflow
        self.assertEqual(self.cpu.cc.C, 0) # C - 0x01 - bit 0 - Carry (or borrow)

    def test_Overflow02(self):
        self.cpu_test_run(start=0x1000, end=None, mem=[
            0x86, 0x7F, # LDA #+127
            0x8B, 0x01, # ADDA #1
        ])
        self.assertEqual(self.cpu.accu_a.get(), 0x80) # $80 == signed: -128 == unsigned: 128
        self.assertEqual(self.cpu.cc.N, 1) # N - 0x08 - bit 3 - Negative result (twos complement)
        self.assertEqual(self.cpu.cc.Z, 0) # Z - 0x04 - bit 2 - Zero result
        self.assertEqual(self.cpu.cc.V, 1) # V - 0x02 - bit 1 - Overflow
        self.assertEqual(self.cpu.cc.C, 0) # C - 0x01 - bit 0 - Carry (or borrow)
Debug putput is this:

Code: Select all

______________________________________________________________________
test_Overflow01 (__main__.Test6809_CC) ...
init 16384 Bytes ROM (0x8000 - 0xc000)
Read 16383Bytes from d32.rom into ROM 0x8000-0xbfff
init 32768 Bytes RAM (0x0 - 0x8000)
-------------------------------------------------------------------------------
$1000 read pc byte: $86
$1001 read pc byte: $80
$1001 addressing 'immediate byte' value: $80 	| $1001: $600-$1dff - Available graphics pages w/o DOS
$1001 *** new op code: $86 (IMMEDIATE) 'instruction_LD8' kwargs: {'operand': <A:0>, 'ea': 4097, 'opcode': 134, 'm': 128}
-------------------------------------------------------------------------------
$1002 read pc byte: $80
$1003 read pc byte: $1
$1003 addressing 'immediate byte' value: $1 	| $1003: $600-$1dff - Available graphics pages w/o DOS
$1003 *** new op code: $80 (IMMEDIATE) 'instruction_SUB8' kwargs: {'operand': <A:128>, 'ea': 4099, 'opcode': 128, 'm': 1}
$1004 SUB8 A: -128 - 1 = -129 (unsigned: 127)
-------------------------------------------------------------------------------
ok

______________________________________________________________________
test_Overflow02 (__main__.Test6809_CC) ...
init 16384 Bytes ROM (0x8000 - 0xc000)
Read 16383Bytes from d32.rom into ROM 0x8000-0xbfff
init 32768 Bytes RAM (0x0 - 0x8000)
-------------------------------------------------------------------------------
$1000 read pc byte: $86
$1001 read pc byte: $7f
$1001 addressing 'immediate byte' value: $7f 	| $1001: $600-$1dff - Available graphics pages w/o DOS
$1001 *** new op code: $86 (IMMEDIATE) 'instruction_LD8' kwargs: {'operand': <A:0>, 'ea': 4097, 'opcode': 134, 'm': 127}
-------------------------------------------------------------------------------
$1002 read pc byte: $8b
$1003 read pc byte: $1
$1003 addressing 'immediate byte' value: $1 	| $1003: $600-$1dff - Available graphics pages w/o DOS
$1003 *** new op code: $8b (IMMEDIATE) 'instruction_ADD8' kwargs: {'operand': <A:127>, 'ea': 4099, 'opcode': 139, 'm': 1}
$1004 ADD8 A: 127 + 1 = 128 (unsigned: 128)
-------------------------------------------------------------------------------
ok
The related commit is: https://github.com/jedie/DragonPy/commi ... 975f1c73c6


You can see: LDA #-128 and SUBA #1 results in accu A == $7f == signed: 127 == unsigned: 127
Flags set to:
N= 0
Z= 0
V= 1
C= 0

Second one LDA #+127 and ADDA #1 results in accu A == $80 == signed: -128 == unsigned: 128
Flags set to:
N= 1
Z= 0
V= 1
C= 0

Is that right?

Have you a example for Carry and Half-Carry?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

I've done some commits: https://github.com/jedie/DragonPy/compa ... ...21a9544

And have more questions:

Where is the STACK in memory? I have found (from http://dragon32.info/info/memmap.html ):

Code: Select all

$0021:0022	Top of stack, growing down ($7e36)
So i set the initial stack pointer to $7E36, is that right?

Next question: Is there no limitation of the stack size? What's happen, if i push more and more values on the stack? "Just" overwrite the "complete" RAM?
And what happen if i PULL more items from stack than exists? PULL memory outside the stack?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
Sarah
Posts: 177
Joined: Wed Apr 13, 2011 3:36 pm
Contact:

Re: Dragon emulator written in Python ???

Post by Sarah »

jedie wrote:So i set the initial stack pointer to $7E36, is that right?
Not really, no. The ROM loads S with a value after detecting how much RAM is installed.

It should wrap around between 0 and $FFFF just like other registers.
jedie
Posts: 655
Joined: Wed Aug 14, 2013 12:23 pm
Location: germany
Contact:

Re: Dragon emulator written in Python ???

Post by jedie »

Sarah wrote:
jedie wrote:So i set the initial stack pointer to $7E36, is that right?
Not really, no. The ROM loads S with a value after detecting how much RAM is installed.
OK, but what's the "default" / "undefined" value of S before RAM size detection? I set it now to 0xffff or maybe a better idea is to set it to 0x0 ? Or is the "start" address completely equal?

btw. Inside The Dragon says Stack Space begins at 7F36, so this is the result value if 32K RAM is installed?
Sarah wrote:It should wrap around between 0 and $FFFF just like other registers.
I implement "wrap around" for 8/16Bit registers here: https://github.com/jedie/DragonPy/commi ... b1cdb75960

Other question: Whats the initial state of PC ? I tried it to 0x8000 or 0xB3B4
Inside The Dragon says 0xB3B4. So the RESET interrups set the PC to 0xB3B4?

EDIT: OK, tried both:
If PC is set to 0xB3B4 at start, that happens:

Code: Select all

$b3b4 LEA Y: Set Y to $b39b
$b3b7 JMP to $8000
$8000 JMP to $bb40
So if i set initial PC directly to $8000 then Y is not set to $b39b

So i think 0xB3B4 is better as initial as $8000, isn't it?
... too many ideas and too little time ... Related stuff written in Python:
Dragon 32 emulator / PyDC - Python Dragon 32 converter: https://github.com/jedie/DragonPy
DWLOAD server / Dragon-Lib and other stuff: https://github.com/6809
Post Reply