Jump to content
IGNORED

Wizzy on the 7800?


karri

Recommended Posts

2 hours ago, karri said:

Small problems with EMU7800. For some reason the NMI interrupts don't seem to trigger if nothing changes. I can get an interrupt by pressing a key but my assumption to get a steady flow of interrupts to be used as a clock() source seem to work only if I press a key. When the system sits idle nothing moves. Could it be an emulator optimisation issue? Or is my code bad?

Hard to say for sure without actually seeing the issue, but EMU7800 is very old, not maintained, and deficient in a number of ways. It's not a good idea to depend on it's feedback, especially since you don't have real hardware to test on.

 

  • Like 1
Link to comment
Share on other sites

Just a small status update. I believe the segments are in place now.

Segment list:
-------------
Name                   Start     End    Size  Align
----------------------------------------------------
EXEHDR                000000  00007F  000080  00001
ZEROPAGE              000040  000059  00001A  00001
DATA                  001800  00184F  000050  00001
BSS                   001850  001C05  0003B6  00001
M000                  004000  004FFF  001000  00001
R000                  005000  0051AA  0001AB  00001
CODE                  0051AB  0063DD  001233  00001
RODATA                006400  006414  000015  00001
L000                  008000  009FFF  002000  00001
STARTUP               00FF29  00FF63  00003B  00001
ONCE                  00FF64  00FF79  000016  00001
ENCRYPTION            00FF7A  00FFF9  000080  00001
VECTORS               00FFFA  00FFFF  000006  00001


 

The M000 is the map of a level, R000 code for a level.

After that the resident code and libraries CODE, RODATA.

L000 graphics for the level.

- first $2000 for tiles that don't need holeys.

- next $5000 for animations (Wizzy + npc's + enemies)

- the last $1000 for STARTUP...VECTORS.

 

The way to configure the segments like this in cc65 cfg file:

# Atari VCS 7800 linker configuration file for cc65

SYMBOLS {
    __STACKSIZE__:        type = weak, value = $0600;
    __CARTSIZE__:         type = weak, value =  $c000;
    __EXEHDR__:           type = import;
    __VEC_BOTTOM__:       value = $fffa, type = export;
    __VEC_SIZE__:         value = $6, type = export;
    __ENCRYPT_BOTTOM__:   value = $ff7a, type = export;
    __ENCRYPT_SIZE__:     value = $80, type = export;
    __INIT_TOP__:         value = __ENCRYPT_BOTTOM__, type = export;
    __INIT_SIZE__:        value = 69+4+8, type = export;
    __INIT_BOTTOM__:      value = __INIT_TOP__ - __INIT_SIZE__, type = export;
    __ROMHI_BOTTOM__:     value = $f000, type = export;
    __ROMHI_SIZE__:       value = __INIT_BOTTOM__ - __ROMHI_BOTTOM__, type = export;
    __LEVEL_SIZE__:       value = $7000, type = export;
    __LEVEL_BOTTOM__:     value = $8000, type = export;
    __ROM000_BOTTOM__:    value = $5000, type = export;
    __ROM000_SIZE__:      value = __LEVEL_BOTTOM__ - __ROM000_BOTTOM__, type = export;
    __MAP_SIZE__:         value = $1000, type = export;
    __MAP_BOTTOM__:       value = $4000, type = export;
}

MEMORY {
    ZP:     file = "", define = yes, start = $0040, size = $00C0, type = rw;
    SP:     file = "", define = yes, start = $0140, size = $00C0, type = rw;
    RAM1:   file = "", define = yes, start = $1800, size = $0840, type = rw;
    RAM2:   file = "", define = yes, start = $2100, size = $0040, type = rw;
    RAM3:   file = "", define = yes, start = $2200, size = $0600, type = rw;
    # For emulators you also need a header file
    HEADER: file = %O,               start = $0000, size = 128;
    # Tilemap for level
    MLEVEL000:    file = %O, define = yes, start = __MAP_BOTTOM__, size = __MAP_SIZE__, type = ro, fill = yes, fillval = $ff;
    # Code and data for level
    RLEVEL000:    file = %O, define = yes, start = __ROM000_BOTTOM__, size = __ROM000_SIZE__, type = ro, fill = yes, fillval = $ff;
    # Graphics for level
    LEVEL000:    file = %O, define = yes, start = __LEVEL_BOTTOM__, size = __LEVEL_SIZE__, type = ro, fill = yes, fillval = $ff;
    # Extra area at top of ROM
    ROMH:   file = %O, define = yes, start = __ROMHI_BOTTOM__, size = __ROMHI_SIZE__, type = ro, fill = yes, fillval = $ff;
    # Startup code. Good to be close to ROMS.
    ROMS:   file = %O, define = yes, start = __INIT_BOTTOM__, size = __INIT_SIZE__, type = ro, fill = yes, fillval = $ff;
    # Encryption stuff
    ROME:   file = %O, start = __ENCRYPT_BOTTOM__, size = __ENCRYPT_SIZE__, type = ro, fill = yes, fillval = $ff;
    # Interrupt vectors
    ROMV:   file = %O, start = __VEC_BOTTOM__, size = __VEC_SIZE__, type = ro, fill = yes, fillval = $ff;
}

SEGMENTS {
    ZEROPAGE:   load = ZP,               type = zp;
    EXEHDR:     load = HEADER,           type = ro,  define = yes;
    M000:       load = MLEVEL000,        type = ro,  define = yes;
    R000:       load = RLEVEL000,        type = ro,  define = yes;
    L000:       load = LEVEL000,         type = ro,  define = yes;
    CODE:       load = RLEVEL000,        type = ro,  define = yes;
    RODATA:     load = RLEVEL000,        type = ro,  define = yes, align = 256;
    DATA:       load = RLEVEL000, run = RAM1, type = rw,  define = yes;
    BSS:        load = RAM1,             type = bss, define = yes;
    STARTUP:    load = ROMS,             type = ro,  define = yes;
    ONCE:       load = ROMS,             type = ro,  define = yes;
    ENCRYPTION: load = ROME,             type = ro   define = yes;
    VECTORS:    load = ROMV,             type = ro,  define = yes;
}

FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = ONCE;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}

 

Link to comment
Share on other sites

12 hours ago, RevEng said:

Hard to say for sure without actually seeing the issue, but EMU7800 is very old, not maintained, and deficient in a number of ways. It's not a good idea to depend on it's feedback, especially since you don't have real hardware to test on.

 

It was me. I used a wait-for-keypress that blocked the execution.

 

Here is a clock() driven scrolling of the display. You can stop the scroll wit K_FIRE (X in the emu).

wizzy.a78

 

A bit flickery still. But good enough for now.

 

        if (clock() > now) {
            switch (k) {
                case K_DOWN:
                    pany += 8;
                    scrollver(0);
                    break;
                case K_UP:
                    pany -= 8;
                    scrollver(1);
                    break;
                case K_LEFT:
                    panx -= 8;
                    scrollhor(0);
                    break;
                case K_RIGHT:
                    panx += 8;
                    scrollhor(1);
                    break;
                default:
                    break;
            }
            now = clock() + 2;
        }


The panx, pany tell the top left corner of the map. (0, 0) means that the screen shows the top left of the map. Negative values or values beyond 63*16 takes you out to the sea that continues until the signed 16 bit int wraps around.

 

In the real game you can fly to other islands with your broom.

  • Like 2
Link to comment
Share on other sites

I just made a joystick driver to cc65. It is based on the code I found in the forum so it might work on most joysticks.

 

    joy_install(&atari7800_stdjoy_joy);
    while (1) {
        joy = joy_read(JOY_1);
        if (JOY_DOWN(joy)) {
            pany += 8;
            scrollver(0);
        }
        if (JOY_UP(joy)) {
            pany -= 8;
            scrollver(1);
        }
        if (JOY_LEFT(joy)) {
            panx -= 8;
            scrollhor(0);
        }
        if (JOY_RIGHT(joy)) {
            panx += 8;
            scrollhor(1);
        }
        if (JOY_BTN_1(joy)) {
            panx -= 8;
            scrollhor(0);
        }
        if (JOY_BTN_2(joy)) {
            panx += 8;
            scrollhor(1);
        }
    }

 

I don't have any joysticks so it is a bit hard to know if it works. Nothing happens bhy pressing the keys... But if this does something on a real 7800 with a joystick it would be nice.

 

Sorry about previous binary. I forgot to assign the value to the joy parameter. This is the  working binary - I hope.

wizzy.a78

Link to comment
Share on other sites

3 hours ago, karri said:

I don't have any joysticks so it is a bit hard to know if it works. Nothing happens bhy pressing the keys... But if this does something on a real 7800 with a joystick it would be nice.

I'm not sure I follow. Are you saying that something should or shouldn't happen when the joystick is used? Is there any reason it wouldn't also work on an emulator?

Link to comment
Share on other sites

2 minutes ago, Karl G said:

I'm not sure I follow. Are you saying that something should or shouldn't happen when the joystick is used? Is there any reason it wouldn't also work on an emulator?

I was hoping it is ok. The first binary was wrong but the current binary should work.

 

Tonight I had to leave for a book binding course so there was no time to learn how to connect a joystick to an emulator.

 

Anyway, I tried to copy the code presented on AtariAge that works on many different joysticks.

 

Tomorrow I try to see if I can get the PC to recognize a joystick and an emulator to use it.

Link to comment
Share on other sites

6 minutes ago, karri said:

I was hoping it is ok. The first binary was wrong but the current binary should work.

 

Tonight I had to leave for a book binding course so there was no time to learn how to connect a joystick to an emulator.

 

Anyway, I tried to copy the code presented on AtariAge that works on many different joysticks.

 

Tomorrow I try to see if I can get the PC to recognize a joystick and an emulator to use it.

Most emulators will default to joysticks, and will default to using the arrow keys for the directionals.

 

For a7800 (recommended for developers), you can confirm the default settings by hitting tab, and choosing "Controller Selection" and "Console and Controller Inputs".

 

For js7800, hit the gear icon to view the default bindings.

 

Here's a js7800 link for the ROM you posted, made by putting in the link to the ROM on the forums as a parameter to js7800. Unfortunately it does not appear that the joystick does anything yet.

  • Like 1
Link to comment
Share on other sites

41 minutes ago, gambler172 said:

Hi Karri

The file works on real hardware, but the joystick does NOTHING ...hope this helps

 

Greetings Walter

Thanks. Back to the drawing board... I need to set up a joystick on my PC and try a few builds.

Link to comment
Share on other sites

Next version that works in a7800. I had polarities wrong. This should now work with 2600, 7800 and genesis sticks.

 

wizzy.a78

 

Both fire buttons do left or right movement. Just to test them.

 

I am also limiting the rate to keep both directions at same speed.

 

    joy_install(atari7800_stdjoy_joy);
    now = clock() + 15;
    while (1) {
        joy = joy_read(JOY_1);
        if (clock() > now) {
            now = clock() + 15;
            if (JOY_DOWN(joy)) {
                pany += 8;
                scrollver(0);
            }
            if (JOY_UP(joy)) {
                pany -= 8;
                scrollver(1);
            }
            if (JOY_LEFT(joy)) {
                panx -= 8;
                scrollhor(0);
            }
            if (JOY_RIGHT(joy)) {
                panx += 8;
                scrollhor(1);
            }
            if (JOY_BTN_1(joy)) {
                panx -= 8;
                scrollhor(0);
            }
            if (JOY_BTN_2(joy)) {
                panx += 8;
                scrollhor(1);
            }
        }
    }

Currently only one joystick is supported. (JOY_1)

 

The joy_read() returns a byte as RLDU..21

A high bit indicates a closure of the switch.
$81 = Right + Fire 1

  • Like 4
Link to comment
Share on other sites

I am a bit confused about MARIAs WSYNC register. It is a write only register. What happens if I write something to the WSYNC?

 

On a related topic. At startup I would like to find out if I have a NTSC or  PAL unit. How should I detect it before I have  DLL set up?

Link to comment
Share on other sites

WSYNC (Wait for Sync) is something inherited from the 2600. Writing to WSYNC halts the CPU until the beginning of the HBlank period between visible lines of the display. That means you can force the system to wait a number of lines for some basic 2600-like raster effects, but the downside is that you're wasting CPU time just counting lines.

  • Like 1
Link to comment
Share on other sites

With DMA off, Maria still puts out a valid (BACKGRND coloured) frame to the TV, and MSTAT can still be used to detect VBLANK/non-VBLANK. So you can use MSTAT and WSYNC to figure out how many lines there are in the non-vblank period...

 

     ; detect the console type...
pndetectvblankstart
     lda MSTAT
     bpl pndetectvblankstart ; if we're not in VBLANK, wait for it to start
pndetectvblankover
     lda MSTAT
     bmi pndetectvblankover ;  then wait for it to be over
     ldy #$00
     ldx #$00
pndetectvblankhappening
     lda MSTAT
     bmi pndetectinvblank   ;  if VBLANK starts, exit our counting loop
     sta WSYNC
     sta WSYNC              ;  count double-lines, to avoid overflowing
     inx
     bne pndetectvblankhappening
pndetectinvblank
     cpx #125
     bcc pndetecispal
     ldy #$01
pndetecispal
     sty paldetected

 

 

  • Like 1
  • Thanks 2
Link to comment
Share on other sites

I assume that the need of finding out PAL vs NTSC is common enough to always do it at startup in cc65.

 

Do we have a common name for the boolean value that defines the machine type?

 

Would paldetected be ok?

 

My next pull request to cc65 will contain detecting the machine, setting up the interruptor logic and adding a 24 bit clock() function.

 

  • Like 1
Link to comment
Share on other sites

41 minutes ago, karri said:

I assume that the need of finding out PAL vs NTSC is common enough to always do it at startup in cc65.

 

Do we have a common name for the boolean value that defines the machine type?

 

Would paldetected be ok?

 

My next pull request to cc65 will contain detecting the machine, setting up the interruptor logic and adding a 24 bit clock() function.

 

That's what 7800 BASIC calls it, in fact.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

  • 3 weeks later...
On 3/14/2022 at 4:01 PM, RevEng said:

I put together a small tia sfx library which anyone is welcome to take from, modified or not. There's a browser-based emulation link in that thread, so it's easy to check if there's anything there for you.

This sfx library is absolutely great! I am currently experimenting with sounds in Pirate Cove. It is really surprising in how expressive sounds you have available.

  • Like 3
Link to comment
Share on other sites

  • 8 months later...
25 minutes ago, Defender_2600 said:

 

Welcome back!  I'm assuming you won't have many sprites in the same line, so I would suggest using 160B for monsters as well.

My problem is that Wizzy has A LOT of moves - in 4 directions. In the Lynx version I believe I had 5 sprite sheets with about 6 rows of sprites.

The reason is that Wizzy will learn new capabilities to turn herself into dps, tank, healer, stealth, croud controller. And her appearance and weapons reflect the change.

So the main character will pretty much exhaust the resources compared to the enemy sprites.

 

The monsters are easier to control since I can decide to let them roam only left/right. Besides, the monsters don't do much...

 

But I will see where this takes me.

 

But you are correct. In this game one or two monsters at a time is what I aim for. If there is space left I might try to have more colours for monsters too.

Link to comment
Share on other sites

Some problems in trying to understand the 160B colours.

weird.thumb.png.a9f82ea2a7015e334aa0259abd4fdfd1.png

 

Obviously I am doing something right as the shape appears to be about right.
Which palette should I define. Here I try to define pal = 0.

 

It looks like colours 0,1,2,3,4,8,12 have became transparent. And the entire palette is rotated 90 degrees. Colour 15 is in the right spot.

 

Obviously my logic in turning GIMP raw output into 160B tiles does not really work as intended...

buildtiles.py

 

The strange thing is if I use the dark green colour (index 1) for two pixels I get 0x05 as (3276 1054)

 

7654 3210

0001 0001

 

This means that 3276 1054 should be 0000 0101 which should be 0x05. But it is invisible on the screen... sigh...

 

Another thing I don't get is that the 3276 should be the left pixel and 1054 the right pixel. For me the screen shows just the opposite.

 

Well, perhaps my head is clearer some other day.

 

Link to comment
Share on other sites

This makes absolutely no sense to me. I just turned the palette 90 degrees in my python script and the graphics colours work.

NoClue.thumb.png.41b3facca8e4617ad5928f0e6ac1fdf9.png

 

I added the palette to the left foot of Wizzy in an try to debug this.

 

I would still like to understand what I am doing, though...

 

The 90 degree turned script that works.

buildtiles.py

Link to comment
Share on other sites

From the first posted script, try the values in the comments instead. Bracketed values show the link to the 7800 bit ordering...

 

def map160B(val):
    ''' 3276 1054 '''
    ret = 0
    if (val & 1) == 1:
        ret = ret | 4    # 64 (6)
    if (val & 2) == 2:
        ret = ret | 8    #128 (7)
    if (val & 4) == 4:
        ret = ret | 64   #  4 (2)
    if (val & 8) == 8:
        ret = ret | 128  #  8 (3)

    if (val & 16) == 16: 
        ret = ret | 1    # 16 (4)
    if (val & 32) == 32: 
        ret = ret | 2    # 32 (5)
    if (val & 64) == 64: 
        ret = ret | 16   #  1 (0)
    if (val & 128) == 128:
        ret = ret | 32   #  2 (1)
    return ret

 

Transparent color indexes are at 0,4,8,12, so you'd need to skip those in your mapping.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...