LX.NET Posted October 10, 2013 Share Posted October 10, 2013 (edited) Hi everyone (and Karri in particular ), Investigating the ComLynx functionality I found that the uploader functionality from the BLL toolkit has been ported to the CC65 library. There is even a lynx-uploader.cfg linker configuration file that allows you to include the uploader in your project/game. When I tried to use it, it compiled OK, but seemed to give weird results on hardware, and not provide the intended behavior. Here are some facts: Created a ComLynx to USB cable myself and tested it with S.I.M.I.S. and Zeus to find out I could upload .o games. That part works. Used the -C lynx-uploader.cfg switch to compile and link my experiment project. Compiled OK. Tried both with and without including the comlynx driver. It seems as if the game is stuck after drawing the first screen. I noticed that the text that I render is cut-off at the bottom, as if the drawing suddenly stopped. That was with the comlynx driver. Without the rendering went OK, but the game did not react to an upload nor keypress, so seemed stuck as well. Some questions: Can you use other interruptor implementations together with the uploader? What do you need to do to get the uploader in place? I couldn't see other things (from the uploader.s source) to do apart from using the configuration in the make file. Anyone has a working implementation in CC65? Thanks. Edited October 10, 2013 by LX.NET Quote Link to comment Share on other sites More sharing options...
+karri Posted October 11, 2013 Share Posted October 11, 2013 oops I really have to check the code first. Its a long time since I wrote it. Quote Link to comment Share on other sites More sharing options...
LX.NET Posted October 12, 2013 Author Share Posted October 12, 2013 oops I really have to check the code first. Its a long time since I wrote it. I am investigating further and noticed that you once posted on how you need to set up the baudrate/timers first. Still midway that exercise, but any info is welcome. This is my current main routine: void main(void) { initialize(); MIKEY.serctl = 0x10|0x04|0x01|0x40|0x08; //MIKEY.SERCTL = TxParEnable|TxOpenColl|ParEven|RxIntEnable|ResetErr; _UART_TIMER.reload = 0x01; _UART_TIMER.control = 0x18; // %00011000 tgi_clear(); tgi_outtextxy(10, 10, "Upload your game!"); tgi_updatedisplay(); wait_joystick(); while (1) ; } Alex Quote Link to comment Share on other sites More sharing options...
LX.NET Posted October 17, 2013 Author Share Posted October 17, 2013 I think I found a possible cause. The UART irq is level sensitive instead of edge sensitive. It's a documented bug in the hardware. You have to clear the interrupt flag for timer 4 (via INTRST = $FD80) to avoid having the IRQ being triggered over and over again. Here's the fragment in the BLL source from upload.m65 (confirmed to work): ; ; last action : clear interrupt ; exit lda #$10 sta $fd80 rts Here you see the interrupt being cleared. In the CC65 uploader.s source: ; ; last action : clear interrupt ; exit: clc rts The interrupt handling mechanism in CC65 is different and less low-level. So, under normal circumstances this would be enough. But in this case you have to additionally clear the interrupt flag explicitly. I'll try and compile a version that has the additional calls. It makes me wonder if uploader.s has ever worked. Fingers crossed. 1 Quote Link to comment Share on other sites More sharing options...
GadgetUK Posted October 19, 2013 Share Posted October 19, 2013 Very nice work btw =) Quote Link to comment Share on other sites More sharing options...
LX.NET Posted December 30, 2013 Author Share Posted December 30, 2013 I've been digging deeper into this and got things working. Except... I am not satisfied yet. In my previous experiments I noticed that the Lynx would freeze on real hardware. Using Handybug.exe I debugged my way into the interruptor pipeline and found that the interruptor for the uploader was already executing, but the calls were going nowhere. With the map from the linker I was able to determine that the destination for the calls was correct. The interruptor code wasn't loaded yet. This figures, because it is not located in the resident memory segment "RAM", but in "UPLD". At the moment I have the uploader working, but it has a big workaround: the interruptor is in the RAM segment and sits somewhere low in memory. This means that larger .o modules cannot be loaded as they will overwrite the uploader code. To the best of my current knowledge I think that all code outside the RAM segment must be explicitly loaded by a call to lynx_load(filenr), as it will not reside in the first file (assuming you are using the micro loader as cart header). So, here's a new list of questions: Did the current lynx-uploader.cfg work at all? Did the original uploader code use different segments, like the configuration suggests? Does interruptor code always have to be in the resident memory (RAM segment)? Is there a way to load non-RAM segments automatically at startup? The last two questions are related and are meant to come to a solution. Ideally, I would say that the overhead of the interruptor should be negligible unless we are actually listening for incoming ComLynx traffic. I think that a routine that will load the necessary code and turn on timer 4 is a good thing. That way you know when and where to use the upload (at a particular screen e.g.) and not have the upload segment loaded unless necessary. So, everyone and Karri in particular (as the author of the original CC65 uploader port): your thoughts and answers are appreciated. Quote Link to comment Share on other sites More sharing options...
+karri Posted December 31, 2013 Share Posted December 31, 2013 My memory is not so good on this one but here we go.... The uploader used interrupts only to see if the MAGIC start sequence is there. After it is the code jumps to the uploader and will never return. It loads in all the code and jumps after thet to the start address. Th uploader goes to its own top segment called UPLOADER that sits in top memory between the SCREENS and the usable RAM. I don't remember how much I tested the code. But most likely it worked as it has been unchanged since the start. The original uploader was on top of the ROM. But today I have the SCREEN buffers there. The interruptor code could be anywhere afaik. You need to modify the boot code for loading more than one segment at boot time. SYMBOLS { __STACKSIZE__: type = weak, value = $0800; # 2k stack __STARTOFDIRECTORY__: type = weak, value = $00CB; # start just after loader __BLOCKSIZE__: type = weak, value = 1024; # cart block size __EXEHDR__: type = import; __BOOTLDR__: type = import; __DEFDIR__: type = import; __UPLOADER__: type = import;}MEMORY { ZP: file = "", define = yes, start = $0000, size = $0100; HEADER: file = %O, start = $0000, size = $0040; BOOT: file = %O, start = $0200, size = __STARTOFDIRECTORY__; DIR: file = %O, start = $0000, size = 8; RAM: file = %O, define = yes, start = $0200, size = $BD38 - __STACKSIZE__; UPLDR: file = %O, define = yes, start = $BFDC, size = $005C;} BR, Karri Quote Link to comment Share on other sites More sharing options...
LX.NET Posted January 2, 2014 Author Share Posted January 2, 2014 Thanks Karri, that gave me enough to continue. I will upload my progress and solution ASAP. Quote Link to comment Share on other sites More sharing options...
LX.NET Posted January 19 Author Share Posted January 19 Is 10 years fast enough? Lynx: Uploader implementation and configuration does not work · Issue #2369 · cc65/cc65 (github.com) I posted an issue and made a pull request to fix the IRQ issue and the feedback, plus did some work on the configuration. I also removed the reference to __BLOCKSIZE__ which is was split previously into __BANK0BLOCKSIZE__ and __BANK1BLOCKSIZE__. Some code in lynx-cart.s and lseek.s still referred to __BLOCKSIZE__, but not anymore. Should this pull request be approved you can easily add the uploader functionality to your code. This requires loading the file with the implementation and starting the serial 4 timer and the SERCTL settings. // Load file before enabling RX interrupt lynx_load((int)&UPLOAD_FILENR); MIKEY.timer4.control = 0x18; // ENABLE_RELOAD | ENABLE_COUNT; MIKEY.timer4.reload = 1; // AUD_2; MIKEY.serctl = 0x10 | 0x04 | 0x01 | 0x08; // PAREN | TXOPEN | PAREVEN | RESETERR; // Clear receive buffer while ((MIKEY.serctl & 0x40) > 0) { data = MIKEY.serdat; } // Enable interrupt for timer 4 serial rate MIKEY.serctl = 0x40 | 0x10 | 0x04 | 0x01 | 0x08; // PAREN | TXOPEN | PAREVEN | RESETERR | RXINTEN; Let me know what you think. Chime in on the discussion at the GitHub cc65 repository where relevant. Thanks. 1 Quote Link to comment Share on other sites More sharing options...
LX.NET Posted January 22 Author Share Posted January 22 Changes have been merged into the main branch. On a new build of lynx.lib the new uploaded will be included. I am creating a writeup on the uploader details and how to include it in your cc65 code. 1 Quote Link to comment Share on other sites More sharing options...
42bs Posted January 30 Share Posted January 30 If you want to use TURBOMODE, you should read the serial port w/o "JSR" else you miss byte. I implented it in uBLL and had so far no problems with TURBOMODE. (TURBOMODE == 1MBd) 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.