RevEng Posted March 15, 2022 Share Posted March 15, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted March 16, 2022 Author Share Posted March 16, 2022 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__; } Quote Link to comment Share on other sites More sharing options...
+karri Posted March 16, 2022 Author Share Posted March 16, 2022 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. 2 Quote Link to comment Share on other sites More sharing options...
+karri Posted March 16, 2022 Author Share Posted March 16, 2022 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 Quote Link to comment Share on other sites More sharing options...
+Karl G Posted March 16, 2022 Share Posted March 16, 2022 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? Quote Link to comment Share on other sites More sharing options...
+karri Posted March 16, 2022 Author Share Posted March 16, 2022 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. Quote Link to comment Share on other sites More sharing options...
+Karl G Posted March 16, 2022 Share Posted March 16, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
gambler172 Posted March 16, 2022 Share Posted March 16, 2022 Hi Karri The file works on real hardware, but the joystick does NOTHING ...hope this helps Greetings Walter 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted March 16, 2022 Author Share Posted March 16, 2022 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. Quote Link to comment Share on other sites More sharing options...
+karri Posted March 17, 2022 Author Share Posted March 17, 2022 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 4 Quote Link to comment Share on other sites More sharing options...
gambler172 Posted March 17, 2022 Share Posted March 17, 2022 Hi Karri works very well on real hardware. 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted March 21, 2022 Author Share Posted March 21, 2022 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? Quote Link to comment Share on other sites More sharing options...
+SmittyB Posted March 21, 2022 Share Posted March 21, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
RevEng Posted March 21, 2022 Share Posted March 21, 2022 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 1 2 Quote Link to comment Share on other sites More sharing options...
+karri Posted March 22, 2022 Author Share Posted March 22, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
+Karl G Posted March 22, 2022 Share Posted March 22, 2022 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. 1 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted April 13, 2022 Author Share Posted April 13, 2022 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. 3 Quote Link to comment Share on other sites More sharing options...
RevEng Posted April 13, 2022 Share Posted April 13, 2022 Thanks - glad you're finding it useful! Quote Link to comment Share on other sites More sharing options...
+karri Posted January 4, 2023 Author Share Posted January 4, 2023 Back on track with Wizzy again. I wonder about using 160B for the hero and 160A for monsters. Any advice? The tiles are screenshot from the game, Wizzy, the spider and the palette in the top corner are planned stuff only. 5 Quote Link to comment Share on other sites More sharing options...
gambler172 Posted January 4, 2023 Share Posted January 4, 2023 looks good so far 1 Quote Link to comment Share on other sites More sharing options...
+Defender_2600 Posted January 4, 2023 Share Posted January 4, 2023 7 hours ago, karri said: Back on track with Wizzy again. I wonder about using 160B for the hero and 160A for monsters. Any advice? 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. 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted January 4, 2023 Author Share Posted January 4, 2023 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. Quote Link to comment Share on other sites More sharing options...
+karri Posted January 5, 2023 Author Share Posted January 5, 2023 Some problems in trying to understand the 160B colours. 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. Quote Link to comment Share on other sites More sharing options...
+karri Posted January 5, 2023 Author Share Posted January 5, 2023 This makes absolutely no sense to me. I just turned the palette 90 degrees in my python script and the graphics colours work. 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 Quote Link to comment Share on other sites More sharing options...
RevEng Posted January 5, 2023 Share Posted January 5, 2023 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. 1 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.