+TheBF Posted December 22, 2022 Share Posted December 22, 2022 6 hours ago, Lee Stewart said: No prob. I can certainly be one pair of eyes. I may be just shy of “expert”, however. ...lee Lee is being somewhat modest IMHO. 1 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 22, 2022 Share Posted December 22, 2022 Look at page 28 in this document. TMS 9900 microprocessor manual It's about instruction timing, but if the instruction has a timing modifier labeled A or B, then it's a general addressing mode. If not, it's register or not applicable (like RTWP, which has no argments at all). 1 Quote Link to comment Share on other sites More sharing options...
GDMike Posted December 22, 2022 Share Posted December 22, 2022 8 hours ago, TheBF said: Lee is being somewhat modest IMHO. Lee for president Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted December 23, 2022 Share Posted December 23, 2022 13 hours ago, GDMike said: Lee for president Lee is president of my heart. It must be the nose. 2 Quote Link to comment Share on other sites More sharing options...
retrodroid Posted December 23, 2022 Author Share Posted December 23, 2022 (edited) On 12/21/2022 at 1:28 PM, retrodroid said: I noticed that the Magellan -> Export -> Assembly Data -> RLE Compress Maps only supports up char 127. Can someone share why that is? I wrote a little RLE byte compressor to see how my map data would benefit and it reduces my maps to anywhere from 60% of the original size to only 20% of original size, a huge savings. Ideally, I'd like to leverage the wonderful Magellan tool fully and have it produce my RLE compressed map data, but ran into this limitation. To answer my own question, I had a look at the Magellan source code and it's implementing a code-type RLE scheme which uses the MSB of a character byte to indicate a repeating sequence. That is why only 128 chars can be used. // RLE compression (byte) // We assume all characters are < 128. If msb is set, the next byte determines // how many times (2 - 256) the current byte (with msb cleared) should be repeated. // A repeat count of 0 is used as end marker. This is efficient since it doesn't require a dedicated "code" byte, thus, a repeating sequence of chars can be identified with only 2 bytes, one for the char to repeat (plus the MSB flag), and one to identify how many to repeat. However, I need to use 256 chars in my project so will implement my own RLE scheme. I aspire to provide this as an alternate RLE option back to the Magellan project in the future. I haven't implemented this yet, if anyone sees any potential "gotchas" with this approach please point them out. Apologies for the "mixed" ascii / Hex notation used below, thought it made visualizing it easier. Custom "Flag" type RLE Encoder to support up to 255 distinct chars, and unlimited number of char repeats. Dedicates the 255/FF character as the character repeat flag. * As a marker that a repeat of the next char value should be made * As an indicator that the char should be repeated 255 times + the next byte value (allows chaining of multiple repeat value bytes) Examples // RLE only applies if a char repeats > 3 times, otherwise no space savings to be had. Input: t e s t t e r Output: t e s t t e r Input: t e s t t t e r Output: t e s t t t e r Input: t e s t t t t e r Output: t e s FFt04 e r // "c" repeats 210 times Input: a b c*210 d e f Output: a b FFcD2 d e f // "c" repeats 255 times Input: a b c*255 d e f Output: a b FFcFF00 d e f // "c" repeats 256 times Input: a b c*256 d e f Output: a b FFcFF01 d e f // "c" repeats 550 times Input: a b c*550 d e f Output: a b FFcFFFF28 d e f // char(255) used as both a valid char value & the repeat/chaining flag... // This way we don't lose the use of the 255 char. Input: a b char(255) c d Output: a b FFFF01 c d // char(255) repeats 10 times Input: a b char(255)*10 c d Output: a b FFFF0A c d Edited December 23, 2022 by retrodroid 2 Quote Link to comment Share on other sites More sharing options...
retrodroid Posted December 24, 2022 Author Share Posted December 24, 2022 Well, it seems the Subject of this thread isn't really relevant to my current plans for this project. Should I change it and use this as my project thread, or start a new one? So I think I have a handle on how much memory I'll need to store the levels in my platform game. I'll be storing a template version of each unique screen type, without any decorations at all (ladders, monsters, treasures, etc.). Each level of the game will use a map featuring a combination of these screen templates + a unique set of decorations per screen instance. That way as the player progresses to higher levels, they can encounter different / more difficult combinations of obstacles, etc. This approach of separating the basic screen layout from the "stuff"/decorations also has the advantage of avoiding a lot of the small unique (non repeating) character usage, and vertically repeating chars like ladders, both of which can add a lot of bulk when using the RLE compression scheme, since they tend to break up what would otherwise be larger sections of repeating chars. I'm also working through the data structures for the various decorations. It looks like I need 2.5 bytes per item in terms of static information required to place the object on the screen. Not sure if there's an easy way to use 2.5 bytes vs 3, so call it 3? Of course, I'll need more bytes for each object to track the runtime state for each while they are in-use on the currently displayed screen. I ran some calculations/simulations to see how much memory was going to be required to store the maps (screen templates + decorations). The maps range from simple (hallway with a ladder) to middling, to complex, in terms of structure complexity and number of objects. As shown below, the difference between no compression, RLE compression with all decorations included/drawn on the screen, and "Smart" RLE compression, with the decorations removed from the screen and stored in their own data-structure (3 bytes each) is remarkable: Complex Screen: No compression: 768 bytes RLE compressed: 403 bytes Smart RLE compressed: 253 bytes Simple Screen: No compression: 768 bytes RLE compressed: 110 bytes Smart RLE compressed: 21 bytes! The "Smart" RLE approach requires that I implement both the RLE compressor I described earlier, and new decoration exporter that will detect placed objects on the screen (in Magellan) and output the required data structure, but the payoff is worth it. Quote Link to comment Share on other sites More sharing options...
retrodroid Posted December 24, 2022 Author Share Posted December 24, 2022 My goal for this game is to have the ability to deliver it via a physical cartridge, play it on a real TI, without requiring the memory expansion module (just like the OG games from back in the day). So I'm trying to understand the memory model I'll need to use to allow for that, but could use some advice in this regard. I believe I can store all my static data (map templates, decoration definitions, etc.) in GROM format and load it as required as each screen is visited. But can I execute my program logic directly from cartridge ROM? Of course I'll need the 256-byte scratchpad for storing the game state, but I should also be able to use a bunch of the VDP ram storage I'll have left over after char, sprite defs, correct? My understanding is accessing the VDP ram is quite slow, but is it feasible to use it this way? What considerations should I be making in order to target the pure cartridge + stock TI99 deployment model? Quote Link to comment Share on other sites More sharing options...
SteveB Posted December 25, 2022 Share Posted December 25, 2022 Returning to the original subject: I haven't found an easy and well documented example of passing parameters from XB to AL and back, for example CALL ADD(x,5,result) .. I learned there are 6 types of parameters and there is some kind of stack. Can someone provide an example or an explanation? Thank you Steve Quote Link to comment Share on other sites More sharing options...
Asmusr Posted December 25, 2022 Share Posted December 25, 2022 On 12/23/2022 at 4:35 PM, retrodroid said: To answer my own question, I had a look at the Magellan source code and it's implementing a code-type RLE scheme which uses the MSB of a character byte to indicate a repeating sequence. That is why only 128 chars can be used. I think I added that compression method for TI-Scramble where I could only use 128 characters anyway. That's the nature of a lot of the features I have added to Magellan: I add them for a specific project of mine, and if I think they are general enough for someone else to use, I include them in the master source. If you submit a pull request with your more general algorithm, I would be happy to merge it in. 21 hours ago, retrodroid said: Well, it seems the Subject of this thread isn't really relevant to my current plans for this project. Should I change it and use this as my project thread, or start a new one? If it's about Magellan, I think you should post in that thread, and if it's about assembly in general, there is also a thread about that. Otherwise it's your thread so feel free to dedicate it to your project (you could even change the title) or make another. 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 28, 2022 Share Posted December 28, 2022 On 12/25/2022 at 3:08 PM, SteveB said: Returning to the original subject: I haven't found an easy and well documented example of passing parameters from XB to AL and back, for example CALL ADD(x,5,result) .. I learned there are 6 types of parameters and there is some kind of stack. Can someone provide an example or an explanation? The "official" way is to use the provided utilities NUMREF, NUMASG for numerical reference and assignment, and STRREF, STRASG for strings. CFI and CIF are used to convert floating point to integer and back. Look at page 23 in this scan of the Swedish newsletter Programbiten. It's only the assembly program, but the calls are explained in the comments. The comments are in English, so no problem there. Note that the daisy wheel used to print the newsletter replaced @ with ', so when you read BLWP 'STRREF it really means BLWP @STRREF. The other way is to use CALL PEEK and CALL LOAD to read and store certain memory locations. But then you need to define these and keep them fixed (usually). 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted December 28, 2022 Share Posted December 28, 2022 On 12/25/2022 at 8:08 AM, SteveB said: Returning to the original subject: I haven't found an easy and well documented example of passing parameters from XB to AL and back, for example CALL ADD(x,5,result) .. I learned there are 6 types of parameters and there is some kind of stack. Can someone provide an example or an explanation? Thank you Steve Everything you need to know about this topic is in this document. TI Extended BASIC Assembly Language Code Programmer_s Guide.pdf 2 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 28, 2022 Share Posted December 28, 2022 Indeed. And some you don't need to know too. Quote Link to comment Share on other sites More sharing options...
SteveB Posted December 28, 2022 Share Posted December 28, 2022 53 minutes ago, Vorticon said: Everything you need to know about this topic is in this document. Thank you, I read this document (awful scan to read), but even if everything is in there, it is hard to understand. I also browsed through the E/A Manual. To get a first understanding the Assembly language primer from Thierry was most helpful. If you happen to read German, the "HAGERA ASSEMBLER KURS III" has the most detailed explanation I found to use Assembler in XB programs. With this I was able to understand much of your KPSUP.txt and started my first test program. A simple, well commented alas not very useful example-code. First I wanted to make a CALL and return without crashing anything. In the second iteration I wanted to put a character on the screen. And the third iteration finally got a parameter, which character to display, which I want to share with anyone having the same problem: Something small and well-documented to play with. DEF CPUT Export name of routine to be called VSBW EQU >2020 Write single character to VRAM VMBW EQU >2024 Write multiple characters to VRAM NUMREF EQU >200C Gets a numeric parameter NUMASG EQU >2008 Makes a numeric assignment STRREF EQU >2014 Gets a string parameter. STRASG EQU >2010 Makes a string assignment. XMLLNK EQU >2018 Links to the assembly language routines in the console CFI EQU >12B8 Convert Floating Point to Integer with XMLLNK CIF EQU >20 Convert Integer to Floating Point with XMLLNK FAC EQU >834A Floating Point Accumulator RETADR BSS 8 Reserve 8 bytes to save registers CPUT MOV R11,@RETADR Store registers R11, R13, R14, R15 MOV R13,@RETADR+2 MOV R14,@RETADR+4 MOV R15,@RETADR+6 CLR @FAC Clear Floating Point Accumulator LI R1,1 set R1 for reading the first parameter CLR R0 set R2 to zero for single value (no array) BLWP @NUMREF read first parameter in FAC BLWP @XMLLNK generic console assembly routine DATA CFI - CFI Converts FAC from RADIX-100 to Word MOV @FAC,R1 Store first parameter (character-code) in R1 AI R1,>60 VRAM charachters are offsetted >60 from ASCII SWPB R1 Swap bytes to get charachter number in Hi-Byte LI R0,>0080 Set R1 to the screen Position (row 4, col 1) BLWP @VSBW Output character to screen EXIT MOV @RETADR,R11 Restore registers before returning MOV @RETADR+2,R13 MOV @RETADR+4,R14 MOV @RETADR+6,R15 RT Return to caller END I hope you don't mind copying your save/restore lines for the registers, I really liked them. If anyone wants to start playing with it in Classic99: Copy the text to an editor, save it as CPUT.TXT, assemble it with Asm994a.exe included in the compiler package under Contributors\Harry_Wilhelm\ and store the obj-file on a FIAD disk, i.e. DSK1. Use CALL INIT when using XB 1.1 first. Then copy this XB program to Classic99 100 CALL CLEAR 110 CALL LOAD("DSK1.CPUT.OBJ") 120 CALL LINK("CPUT",64) I will continue to explore the possibilities based on this tiny program... 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 28, 2022 Share Posted December 28, 2022 1 hour ago, SteveB said: I hope you don't mind copying your save/restore lines for the registers, I really liked them. In this program, they have no purpose at all. Quote Link to comment Share on other sites More sharing options...
SteveB Posted December 28, 2022 Share Posted December 28, 2022 20 minutes ago, apersson850 said: In this program, they have no purpose at all. I know ... but this is my playground and template ... and other things I already tried changed R11 when I BL'ed ... others to follow. Talking of not messing up the XB environment ... can someone tell me when I need to clear the GPL status at >837C before returning? And when do I need to need the CALL LOAD("DSK1.BSCSUP") ? 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 28, 2022 Share Posted December 28, 2022 (edited) Sure, they'll do no harm. But one of the ideas behind going to assembly is efficiency, in speed and memory use, and in that case you don't want to add eight instructions that have no purpose. As far at I remember you need to clear >837C if the condition bit is set when you return. If you return with that bit set, the BASIC interpreter will assume you return an error condition. Since testing the condition bit is more complicated than just clearing it, you clear it whether it's set or not, and then you are good to go. Since the topic here is mixing assembly with Extended BASIC, the answer to when you need to load BSCSUP is: never. It's used if you call from TI BASIC, with the Editor/Assembler module plugged in (otherwise you can't) and you want to use the routines STRREF, NUMASG etcetera. Edited December 28, 2022 by apersson850 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted December 28, 2022 Share Posted December 28, 2022 1 hour ago, SteveB said: Talking of not messing up the XB environment ... can someone tell me when I need to clear the GPL status at >837C before returning? Usually you only need to bother clearing the GPL status byte just before you call a GPLLNK routine, but @apersson850’s point about clearing it before returning to XB is well taken. ...lee 1 Quote Link to comment Share on other sites More sharing options...
SteveB Posted December 28, 2022 Share Posted December 28, 2022 32 minutes ago, apersson850 said: Sure, they'll do no harm. But one of the ideas behind going to assembly is efficiency, in speed and memory use, and in that case you don't want to add eight instructions that have no purpose. Currently it is about learning for me, not speed. Yet. And if speed is the matter, I won't BLWP @VSBW to write a byte to VRAM either ... Crawl. Walk. Run... I'm in phase one concerning TMS9900 assembly. Thanks for the BSCSUP clarification .. it's hard to follow up what's for TI BASIC and XB or not XB. Or MiniMem. 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 28, 2022 Share Posted December 28, 2022 (edited) Alright, at least you know why you do it. I've seen some who save return addresses obviously without knowing why, and hence they don't know when they need to do it either. When it comes to BLWP @VSBW, there's at least a clean interface and no worries about which registers it uses to gain, compared to handling it all by yourself. Edited December 28, 2022 by apersson850 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted December 29, 2022 Share Posted December 29, 2022 4 hours ago, apersson850 said: In this program, they have no purpose at all. Why not? Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 29, 2022 Share Posted December 29, 2022 10 hours ago, Vorticon said: Why not? Because he saves R11, R13, R14 and R15 to begin with, and then restores them at the end. But he does nothing with them in between, so when he restores them, they already hold the same values as he puts back. Quote Link to comment Share on other sites More sharing options...
+retroclouds Posted December 29, 2022 Share Posted December 29, 2022 (edited) On 12/15/2022 at 11:21 PM, Lee Stewart said: I have used EA, asm994a, and xa99 (in that order). I like asm994a, but it has its quirks and is no longer maintained by its developer. For those reasons, I moved on to xa99—and I am glad I did. The developer, Ralph Benzinger ( @ralphb ) is ever-present with help, fixes, and improvements. There are a handful of others of us here on AtariAge who are using xa99 and can offer assistance along your journey through Assembler. ...lee Once I moved from asm994a to xas99 I didn't look back. For Stevie (a 64K cartridge) I have 8 banks that I assemble in parallel by using a bash batch file.https://github.com/FilipVanVooren/stevie/blob/master/build/assemble.sh https://github.com/FilipVanVooren/stevie/blob/master/build/build.sh Edited December 29, 2022 by retroclouds 4 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted December 29, 2022 Share Posted December 29, 2022 (edited) 21 hours ago, apersson850 said: As far at I remember you need to clear >837C if the condition bit is set when you return. If you return with that bit set, the BASIC interpreter will assume you return an error condition. Since testing the condition bit is more complicated than just clearing it, you clear it whether it's set or not, and then you are good to go. To me, what seems like the best way to return back to XB from the assembly sub is to: LWPI >83E0 (if you are using a different workspace) B @>006A which clears the condition bit and returns to XB If you think you might like to compile the XB code and use the A/L support then you must return to XB this way. B *R11 will not work. Edited December 29, 2022 by senior_falcon 3 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 29, 2022 Share Posted December 29, 2022 I see. Weel, compiled BASIC was not an option when I was using Extended BASIC back in the days. 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted December 30, 2022 Share Posted December 30, 2022 On 12/29/2022 at 5:36 AM, apersson850 said: Because he saves R11, R13, R14 and R15 to begin with, and then restores them at the end. But he does nothing with them in between, so when he restores them, they already hold the same values as he puts back. Got it. I have always thought these registers got altered by the XB assembly utility routines. Is this not the case? 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.