Harry Potter Posted September 14, 2021 Share Posted September 14, 2021 For those of you who use cc65 to program the Atari 800, I have a library called AtaSimpleIO. It is a library to handle text display and keyboard input. It is a minimal library that displays text with a minimum of processing. Basically, it calls the ROM directly. I don't remember the size of the Atari 8 version, but the CBM versions to test the code is worth <1k. You can get it at c65 additions - Manage /ui at SourceForge.net. I also have a new version of AltInput, which is a function to handle line input with a minimum of functionality, but I don't think it is online. Try it out! Quote Link to comment Share on other sites More sharing options...
baktra Posted September 14, 2021 Share Posted September 14, 2021 The library seems to be using unofficial vectors to the OS ROM of the Atari 800, so it will glitch with XL/XE models. Quote Link to comment Share on other sites More sharing options...
danwinslow Posted September 14, 2021 Share Posted September 14, 2021 Harry - you're missing a point of the OS architecture of the Atari. If you want to be compatible, use the OS-supplied CIO handlers rather than directly calling OS routines when you get ready to actually do the IO itself. 1 Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 I thank you for your response. I am new to the Atari 8 series and didn't know about the mentioned ROM issue. How can I get it to work on an Atari XL/XE? Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 Uhh...can somebody post a link to the info on the required CIO handlers online? Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted September 14, 2021 Share Posted September 14, 2021 This will get you started De-Re Atari has a section on CIO, Master Memory Map also has the memory locations to use. De-Re-Atari.pdf Mapping-the-Atari.pdf 1 Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted September 14, 2021 Share Posted September 14, 2021 18 minutes ago, Harry Potter said: I am new to the Atari 8 series and didn't know about the mentioned ROM issue. It was covered here? Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 (edited) I thank you for the download. I already had the Mapping PDF but will soon look at the other download. Edited September 14, 2021 by Harry Potter fixed grammatical error Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 I quickly looked at both docs. and didn't find the information. Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted September 14, 2021 Share Posted September 14, 2021 In De-Re Atari CIO is covered starting on Page 8-22 In Mapping the Atari have a look at Pages 81 through 88 where device handlers/tables/vectors are described. CIO works by opening a channel, depending on the Open mode, you can read/write to a device through its channel table, the values required for the table are described in those pages in Mapping the Atari. Each channel has a 16 byte block starting at $340 All commands end with a JSR CIOV ($E456) simple example, closes channel 2, then opens it for screen device "E:" 010000 CHANNEL LDA #CLOSE ; Close Channel 2 010010 LDX #$20 010020 STA $0342,X 010030 JSR CIOV 010040 LDA #OPEN ; Open Channel 2 for Screen Editor 010050 STA $0342,X 010060 LDA #NAME&255 010070 STA $0344,X 010080 LDA #NAME/256 010090 STA $0345,X 010100 LDA #3 010110 STA $0348,X 010120 LDA #0 010130 STA $0349,X 010140 LDA #12 ;R/W 010150 STA $034A,X 010160 LDA #0 010170 STA $034B,X 010180 JSR CIOV 010190 RTS 010200 NAME .BYTE "E:",$9B ; ; Address of message text passed in A and Y registers 010210 MESSAGE LDX #$20 ; Write a message to the screen 010220 STA $0344,X ; low byte of text address 010230 TYA 010240 STA $0345,X ; high byte of text address 010250 LDA #PUTREC 010260 STA $0342,X 010270 LDA #120 010280 STA $0348,X ; max bytes to write (low) 010290 LDA #0 010300 STA $0349,X ; max bytes to write (high) 010310 JSR CIOV 010320 RTS 1 Quote Link to comment Share on other sites More sharing options...
baktra Posted September 14, 2021 Share Posted September 14, 2021 I would like to point out that cc65 already ships with non-standard header <conio.h> which provides faster routines for screen input/output. It is because the video RAM is addressed directly. Theses functions are available for the atari target. The <stdio.h> provides functions that are using the E: device through CIO. I am pointing it out, so you do not waste time developing something that already exists. Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 The purpose of my SimpleIO libraries is to provide as little extra processing of data as possible. It is meant as a more optimal version of printf() and other console I/O functions. The CBM version comes with binaries to test the included functions which are worth <1k per version. If it's not possible on the Atari 8 versions, just tell me, and I will stop working on it for now. Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted September 14, 2021 Share Posted September 14, 2021 As mentioned earlier, the OS ROM's differ between models, so making calls directly into the OS will only work on the OS model you develop it on, it will not work on others. Quote Link to comment Share on other sites More sharing options...
danwinslow Posted September 14, 2021 Share Posted September 14, 2021 36 minutes ago, Harry Potter said: The purpose of my SimpleIO libraries is to provide as little extra processing of data as possible. It is meant as a more optimal version of printf() and other console I/O functions. The CBM version comes with binaries to test the included functions which are worth <1k per version. If it's not possible on the Atari 8 versions, just tell me, and I will stop working on it for now. That's kind of what conio.h does already. I don't think you are way offbase with your typed prints printu, printc, etc., as a smaller printf replacement, but they should be thin wrappers on top of the basic CIO calls that support outputting things to screen. So I wouldn't call it entirely unnecessary, but I wouldn't call it really valuable either. Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 So, the verdict is it's not worth it. Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 I found it. Thanks! BTW, I could just use the Get Byte and Put Byte routines to access the screen/keyboard, right? How do I get a line of input from the user? I have an AltInput function to handle it but want one for SimpleIO. Quote Link to comment Share on other sites More sharing options...
ivop Posted September 14, 2021 Share Posted September 14, 2021 I always assumed that (f)putc and putchar just call CIO. If you really want to make a faster screen IO library, you should write directly to the screen memory and ignore the E: CIO handler. Use SAVMSC (88,89 ($58,$59)) for that. Note that you have to write ANTIC screen codes instead of ATASCII. Quote Link to comment Share on other sites More sharing options...
xxl Posted September 14, 2021 Share Posted September 14, 2021 28 minutes ago, Harry Potter said: So, the verdict is it's not worth it. if someone really wants, he can use the standard library but here a friend creates a custom one that is supposed to give some benefit, for example in the form of extreme shortening of the code. Before you give up, know that the OS has calls that have the same addresses for all XL OS versions, so procedures like: GRAPHICS PLOT PRINT DISPLAY DRAWTO FILL LOCATE INPUT GETKEY CONVERT you can implement without any obstacles and they will be much faster and shorter. do not be discouraged by "good advice". classic example ldx #<hello ldy #>hello jsr $c642 ... hello dta c'Hello, world!',$9b 1 Quote Link to comment Share on other sites More sharing options...
Harry Potter Posted September 14, 2021 Author Share Posted September 14, 2021 Okay. I'll kill the project. The purpose was to create a smaller library, not a faster library. Quote Link to comment Share on other sites More sharing options...
ivop Posted September 14, 2021 Share Posted September 14, 2021 (edited) What xxl says is true, if you limit your target to a certain OS (family). Used a lot in sizecoding competitions, but for production code, you need several binaries to target the old and the new OS vectors. There's an in-between BTW. The direct vectors are in tables in the OS ROM, and you can read them and copy the address to self modifying code. JMP $0000, and then change the LSB/MSB of the argument. Only once. After that, you can call that JMP routine. Some extra cycles burnt, but OS agnostic, and faster than going through CIO. Edited September 14, 2021 by ivop Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted September 14, 2021 Share Posted September 14, 2021 (edited) Something like this can serve as a concise means of calling the keyboard handler's 'get' routine, providing the handler table is arranged as per the stock OS: .proc GetKey lda $E425 pha lda $E424 pha rts .endp As for direct jumps into undocumented entry points: this is just bad practice guaranteed to garner complaints from those users for whom your software crashes because the user favours some custom OS (many of which date back the Atari's heyday). Presumably anyone who asserts otherwise disregards said alternative operating systems as invalid. That's fine if you want to deliberately limit your user base. Mapping the Atari (which the most excited proponent of illegal OS entry points presumably read for the first time a couple of years ago) is a conspicuous culprit here, since it pointlessly lists entry points which at the time of publication were not even guaranteed to stay put in stock operating systems. Using said entry points when the OS itself is rather elegantly designed (it inherently allows for output redirection, for example) is rather unnecessary unless you are perpetually short of half a dozen bytes to complete your project. There are many ways to shorten the size of a library which are less egregious than resorting to jumps into undocumented entry points. Edited September 14, 2021 by flashjazzcat 3 Quote Link to comment Share on other sites More sharing options...
ivop Posted September 14, 2021 Share Posted September 14, 2021 @flashjazzcat's method is even more elegant. I had forgotten that the vectors were minus one, specifically designed for being a return address on the stack. Also, I agree on Mapping motivated bad practices by documenting both the vector locations and where it points to. Calliing the latter directly is a no go, but Chadwick didn't say that. 2 Quote Link to comment Share on other sites More sharing options...
drac030 Posted September 14, 2021 Share Posted September 14, 2021 Even if "undocumented entry points" are in fact documented somewhere, this does not automatically mean that they are to be used by direct JSR calls. There are two different things: 1) the, as they say now, API contract, and 2) things documented "for your information". The API contract is the stuff the OS designers guarantee to work across all OS revisions. Like CIOV $e456, accepts input parameters such and such, does this and that, returns this in X, that in Y, A is sometimes defined, but most of the time undefined. "Undefined" means that the returned value may change across OS revisions, because that value is accidental from the point of view of the program: it depends on the method used to execute the defined OS function, but the methods are in fact private internals of the OS (or any program, in fact, which exports some function to be externally called) and cannot be relied upon; some better method (shorter and/or faster) of doing things may be used in the next revision and thus the "undefined" stuff returned may change. The same applies to the location where the actual OS routines reside: the actual address is most of the time accidental and belongs to the category of methods; and methods are private to the OS. It is often good to know what are the side effects, performance etc. and this its the reason for documenting such stuff as "FYI" - but relying on them is just praying for problems. As about the ROM vectors at $E400, it should be remembered that only the default drivers can be called that way. In fact all CIO devices should be called so that the call goes indirectly through the HATABS. 2 Quote Link to comment Share on other sites More sharing options...
phaeron Posted September 16, 2021 Share Posted September 16, 2021 (edited) On 9/14/2021 at 12:27 PM, flashjazzcat said: Something like this can serve as a concise means of calling the keyboard handler's 'get' routine, providing the handler table is arranged as per the stock OS: .proc GetKey lda $E425 pha lda $E424 pha rts .endp This is actually not safe either, for a different reason. CIO device handlers aren't designed to be executed directly, they expect CIO to set up a calling environment for them. This is skipped if you call the CIO handler directly instead of going through CIOV, in which case you are responsible for setting up the environment. In this case, the subtle bug has to do with the way that the K: handler's GET BYTE routine handles the AUX1 permission byte. This is due to an undocumented behavior where the "forced read" function of E:, which is activated by bit 0 of AUX1 on open and tells E: to read lines from the screen without waiting for keyboard input, is actually implemented by K:. This means that the K: GET BYTE handler reads AUX1 even though K: is documented in the Atari OS manual as not having any device dependent bits in AUX1. Furthermore, as with any other CIO handler, K: GET BYTE expects the AUX1 byte of the IOCB to have been copied into ICAX1Z by CIO prior to the handler being called. If you don't do this before executing the code above, then you're at the mercy of whatever byte happens to be in ICAX1Z at the time. Most of the time it'll work because this happens to have bit 0 cleared, and occasionally it will break horribly with your program endlessly getting $9B instead of a key from the keyboard. This is not theoretical; it was the cause of a long-standing Ice-T bug where the program would print endless 'j' characters in some configurations. People thought it was an incompatibility with R: handlers, but it was actually a bug with the way that the program called directly into K: using code like the above. There are definitely uses for sidestepping CIO, but you have to know exactly what is involved, and the majority of references don't tell you all of the pitfalls. And as can be seen here, not even the official manuals do sometimes. Edited September 16, 2021 by phaeron 4 Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted September 16, 2021 Share Posted September 16, 2021 6 hours ago, phaeron said: In this case, the subtle bug has to do with the way that the K: handler's GET BYTE routine handles the AUX1 permission byte. This is due to an undocumented behavior where the "forced read" function of E:, which is activated by bit 0 of AUX1 on open and tells E: to read lines from the screen without waiting for keyboard input, is actually implemented by K:. This means that the K: GET BYTE handler reads AUX1 even though K: is documented in the Atari OS manual as not having any device dependent bits in AUX1. Furthermore, as with any other CIO handler, K: GET BYTE expects the AUX1 byte of the IOCB to have been copied into ICAX1Z by CIO prior to the handler being called. If you don't do this before executing the code above, then you're at the mercy of whatever byte happens to be in ICAX1Z at the time. Most of the time it'll work because this happens to have bit 0 cleared, and occasionally it will break horribly with your program endlessly getting $9B instead of a key from the keyboard. This is not theoretical; it was the cause of a long-standing Ice-T bug where the program would print endless 'j' characters in some configurations. People thought it was an incompatibility with R: handlers, but it was actually a bug with the way that the program called directly into K: using code like the above. Good points. I learned a lot of esoteric stuff about CIO devices recently while writing a new DOS, and not all of it is explained well in the documentation, as you say. 2 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.