orbitaldecay Posted October 3, 2015 Share Posted October 3, 2015 Hello All, I've recently become interested in programming on the TI-99/4A. After figuring out how to write and assemble a simple 'Hello, World' programing using the EA cart, I decided I'd give a go at writing a simple cart from scratch. Here is my code so far: AORG >6000 BYTE >AA * Standard header BYTE >01 * Version number BYTE >01 * Number of programs (optional) BYTE >00 * Reserved DATA >0000 * Pointer to power-up list DATA PRGLST * Pointer to program list DATA >0000 * Pointer to DSR list DATA >0000 * Pointer to subprogram list PRGLST DATA >0000 * Next program list entry DATA MAIN * Program address BYTE 5 * Length of name TEXT 'HELLO' * Name MAIN B *R11 I've gotten the GROM header format from http://www.unige.ch/medecine/nouspikel/ti99/groms.htm#GROM%20header. So far so good... except when I assemble it and try to load it with classic99, it doesn't work! I'd expect to see an entry in the main menu that says "2 FOR HELLO", but it doesn't show up. I'm using Asm994a. Does anyone know what I'm doing wrong? Quote Link to comment Share on other sites More sharing options...
Opry99er Posted October 4, 2015 Share Posted October 4, 2015 I don't have your answer, but WELCOME TO THE FORUM!!!!! Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 4, 2015 Author Share Posted October 4, 2015 I don't have your answer, but WELCOME TO THE FORUM!!!!! Thanks! Quote Link to comment Share on other sites More sharing options...
Tursi Posted October 4, 2015 Share Posted October 4, 2015 (edited) Good for you, diving right in! You've got the right idea, just missing a little background information. The first is that it's important to differentiate between "GROM" and "ROM". GROM is actually a completely separate memory space that TI used for a lot of stuff. The memories are auto-incrementing (much like a modern serial EEPROM) and can not run assembly language code. Normally they contain data or "GPL". You're writing assembly, so you will be dealing with ROM. All that said, of course, the header is the same for both (there are some limitations to deal with, but not for just making it show). Your header looks okay, so the next questions are "how are you assembling it?" and "how are you loading it?". If we can see your binary we can check that matches the source, but I suspect it's just how you're loading it. The issue that you are probably running into is a combination of those. I think you either are trying to load the object code instead of a binary cartridge (Asm994A can produce a cartridge, otherwise you need a couple of steps to convert the object file into a binary - this can be done with external tools or Classic99), or it's not loading at the right address. If the final cartridge name ends with "C.BIN" (for CPU memory cartridge) you can use Cartridge->User->Open to load it into Classic99. My last comment is unrelated to your problem -- I don't think B *R11 will return successfully from a cartridge launch... the best way to reset the console in a cartridge is to branch to the reset vector: BLWP @>0000 Edited October 4, 2015 by Tursi Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 4, 2015 Author Share Posted October 4, 2015 Good for you, diving right in! You've got the right idea, just missing a little background information. The first is that it's important to differentiate between "GROM" and "ROM". GROM is actually a completely separate memory space that TI used for a lot of stuff. The memories are auto-incrementing (much like a modern serial EEPROM) and can not run assembly language code. Normally they contain data or "GPL". You're writing assembly, so you will be dealing with ROM. All that said, of course, the header is the same for both (there are some limitations to deal with, but not for just making it show). Your header looks okay, so the next questions are "how are you assembling it?" and "how are you loading it?". If we can see your binary we can check that matches the source, but I suspect it's just how you're loading it. The issue that you are probably running into is a combination of those. I think you either are trying to load the object code instead of a binary cartridge (Asm994A can produce a cartridge, otherwise you need a couple of steps to convert the object file into a binary - this can be done with external tools or Classic99), or it's not loading at the right address. If the final cartridge name ends with "C.BIN" (for CPU memory cartridge) you can use Cartridge->User->Open to load it into Classic99. My last comment is unrelated to your problem -- I don't think B *R11 will return successfully from a cartridge launch... the best way to reset the console in a cartridge is to branch to the reset vector: BLWP @>0000 Thanks for your encouraging and informative post! "If the final cartridge name edits with 'C.BIN'" was the magic piece of information I was missing. I named the image 'HELLO.BIN' and I was bashing my head against the wall as to why Cartridge->User->Open wouldn't load it . Now that the file is named "HELLOC.BIN" I can see it in the menu! I have a friend who is able to burn ROMs to carts. Could he burn my HELLOC.BIN file to a rom, pop in the cart, and see that on the menu on his real deal TI-99/4A? Thanks again, I was really pulling my hair out over this one! Quote Link to comment Share on other sites More sharing options...
Tursi Posted October 4, 2015 Share Posted October 4, 2015 No worries.. the User->Cartridge->Load is just a helper I put in for loading the old V9T9 style carts, but since they are raw binaries, the filename is the only way to know where in the memory map they go! Normally the Classic99.ini is extended to add a permanent cartridge - check the manual for that, there are examples near the end. And yes! If you burned that to an EPROM it should load on a real TI. The only caveat is that if the TI displays "2.2" and a 1983 copyright on the title page, it won't work, because in the 2.2 consoles TI locked out ROM-only cartridges. Those are a bit more uncommon than the 1981 version though. Quote Link to comment Share on other sites More sharing options...
Opry99er Posted October 4, 2015 Share Posted October 4, 2015 Awesome... Quote Link to comment Share on other sites More sharing options...
RXB Posted October 4, 2015 Share Posted October 4, 2015 Hello All, I've recently become interested in programming on the TI-99/4A. After figuring out how to write and assemble a simple 'Hello, World' programing using the EA cart, I decided I'd give a go at writing a simple cart from scratch. Here is my code so far: AORG >6000 BYTE >AA * Standard header BYTE >01 * Version number BYTE >01 * Number of programs (optional) BYTE >00 * Reserved DATA >0000 * Pointer to power-up list DATA PRGLST * Pointer to program list DATA >0000 * Pointer to DSR list DATA >0000 * Pointer to subprogram list PRGLST DATA >0000 * Next program list entry DATA MAIN * Program address BYTE 5 * Length of name TEXT 'HELLO' * Name MAIN B *R11 I've gotten the GROM header format from http://www.unige.ch/medecine/nouspikel/ti99/groms.htm#GROM%20header. So far so good... except when I assemble it and try to load it with classic99, it doesn't work! I'd expect to see an entry in the main menu that says "2 FOR HELLO", but it doesn't show up. I'm using Asm994a. Does anyone know what I'm doing wrong? Ok if you go to Atari Age tutorials I wrote on GPL and Assembly of a GPL program here is your repaired program. GROM >6000 AORG >0000 BYTE >AA * Standard header BYTE >01 * Version number BYTE >01 * Number of programs (optional) BYTE >00 * Reserved DATA >0000 * Pointer to power-up list DATA PRGLST * Pointer to program list DATA >0000 * Pointer to DSR list DATA >0000 * Pointer to subprogram list PRGLST DATA >0000 * Next program list entry DATA MAIN * Program address BYTE 5 * Length of name MAIN ALL 32 * Clears screen with space character FMT * Get ready to do a text set up COL 14 * COLUMN 14 on screen 32x24 ROW 12 * ROW 12 on screen 32x24 TEXT 'HELLO' * Text to display FEND HERE B HERE * Loop to HERE forever * TEXT 'HELLO' * Name * must be in a command structure. * MAIN B *R11 * This is a ASSEMBLY COMMAND does not exist in GPL END Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 4, 2015 Author Share Posted October 4, 2015 Ok if you go to Atari Age tutorials I wrote on GPL and Assembly of a GPL program here is your repaired program. Thank you for your response. But as Tursi correctly identified, I was attempting to write a ROM in assembly and not a GROM in GPL. I was just conflating ROMs and GROMs because their headers looked the same. I now understand the difference. Quote Link to comment Share on other sites More sharing options...
Opry99er Posted October 4, 2015 Share Posted October 4, 2015 Very cool stuff, orbit. I hope you continue to work with the TI and produce some software... We have some awesome developers here, but not too many cart-makers. Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted October 4, 2015 Share Posted October 4, 2015 Although the number of cart makers has been increasing of late--and that is a wonderful thing from the availability of new software standpoint. There are still a lot of console-only folks out there, amazingly enough. . . Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 5, 2015 Author Share Posted October 5, 2015 Cool. So far I've got a working ROM that switches to Graphic II mode and clears the screen. Not much, but might be useful to other newcomers like myself. (See attached) GFXIIC.A99 GFXIIC.bin 2 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted October 5, 2015 Share Posted October 5, 2015 Very nice, I could have used this example when I started on TMS9900 assembler a few years ago. I noticed some of comments in your code: * Nice tight loop. Too bad we don't have a REP or LOOP * instruction like x86 PTLP MOVB R1, @VDPWD DEC R2 JNE PTLP One small improvement is to load VDPWD into a register: LI R0,VDPWD PTLP MOVB R1,*R0 DEC R2 JNE PTLP This is faster because the MOVB instruction is now only one word instead of two. Then you can start unrolling the loop, e.g: LI R0,VDPWD PTLP MOVB R1,*R0 MOVB R1,*R0 DECT R2 JNE PTLP You can go further and unroll the loop up to 8 times. After that the effect becomes negligible. Don't worry about pauses between writes, Tursi has shown you cannot overrun the VDP on writes. Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 5, 2015 Author Share Posted October 5, 2015 (edited) Very nice, I could have used this example when I started on TMS9900 assembler a few years ago. I noticed some of comments in your code: * Nice tight loop. Too bad we don't have a REP or LOOP * instruction like x86 PTLP MOVB R1, @VDPWD DEC R2 JNE PTLP One small improvement is to load VDPWD into a register: LI R0,VDPWD PTLP MOVB R1,*R0 DEC R2 JNE PTLP This is faster because the MOVB instruction is now only one word instead of two. Then you can start unrolling the loop, e.g: LI R0,VDPWD PTLP MOVB R1,*R0 MOVB R1,*R0 DECT R2 JNE PTLP You can go further and unroll the loop up to 8 times. After that the effect becomes negligible. Don't worry about pauses between writes, Tursi has shown you cannot overrun the VDP on writes. Nice! Thanks for the feedback and good ideas. I'll definitely be making use of them . Btw, do you know of any documentation of the number of clock cycles each instruction uses? If I unroll the loop 8 times, I imagine it would be faster (and more space efficient) to use S R2, 8 then DECT R2, 4 times (actually, I'm not even sure you can use an immediate value with S?), but I'd like some documentation to back that up. Edited October 5, 2015 by orbitaldecay Quote Link to comment Share on other sites More sharing options...
ralphb Posted October 5, 2015 Share Posted October 5, 2015 Btw, do you know of any documentation of the number of clock cycles each instruction uses? There's a recent (and somewhat meandering, but with lots of background info) thread on this topic over here. Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 5, 2015 Author Share Posted October 5, 2015 There's a recent (and somewhat meandering, but with lots of background info) thread on this topic over here. Thanks! Great thread. I'll have to take a look at the 9900 Data Manual. Quote Link to comment Share on other sites More sharing options...
Asmusr Posted October 5, 2015 Share Posted October 5, 2015 Nice! Thanks for the feedback and good ideas. I'll definitely be making use of them . Btw, do you know of any documentation of the number of clock cycles each instruction uses? If I unroll the loop 8 times, I imagine it would be faster (and more space efficient) to use S R2, 8 then DECT R2, 4 times (actually, I'm not even sure you can use an immediate value with S?), but I'd like some documentation to back that up. I use the debugger in Classic99 to time my loops. You can use AI R2,-8, but you can also divide it by 8 (SRL R2,3) before the loop and just use DEC R2. Quote Link to comment Share on other sites More sharing options...
orbitaldecay Posted October 5, 2015 Author Share Posted October 5, 2015 Thanks for the tips all. I've updated my example code. I've removed the (premature) optimization in the initialization code and wrote a nice, fast clear screen routine that wipes the pattern table that would be suitable in a render loop. Any other suggestions are welcome. GFXIIC.A99 GFXIIC.bin Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 5, 2015 Share Posted October 5, 2015 Nice! Thanks for the feedback and good ideas. I'll definitely be making use of them . Btw, do you know of any documentation of the number of clock cycles each instruction uses? If I unroll the loop 8 times, I imagine it would be faster (and more space efficient) to use S R2, 8 then DECT R2, 4 times (actually, I'm not even sure you can use an immediate value with S?), but I'd like some documentation to back that up. As you suspect, you can't use an immediate value with the SONY instruction. You'd use the AI instruction. AI R2,-8 That would do it. :-) 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.