Although documented nowhere (!!!) ProDOS trashes the random counter locations $4E/$4F. Is discovered this because my TCP connections didn't have random local ports.
It's a really funny coincidence that David Finnigan discovered only 3 years ago the very same issue because of the very same reason: https://groups.google.com/forum/#!topic/comp.sys.apple2.programmer/1ciep_Oetvo
In order to have randomize() work as expected (and the Apple II random number generation in general) it is necessary to update the random counter during keypress wait just like the ROM function does.
Fixes this issue:
https://github.com/cc65/cc65/issues/722
ftell() returns the value returned by lseek(), and lseek() for the
Apple II wasn't returning a value.
According to https://github.com/cc65/wiki/wiki/Direct-console-IO it is undefined what happens when the end of the sceen is reached. But it is _not_ undefined what happens when the end of the line is reached. So implement the usual thing - which was easy enough to do after all.
Originally the Apple II had a 64 char set and used the upper two bits to control inverse and blinking. The Apple //e brought then an alternate char set without blinking but more individual chars. However, it does _not_ contain 128 chars and use the upper bit to control inverse as one would assume. Rather it contains more than 128 chars - the MouseText chars. And because Apple wanted to provide as much backward compatibility as possible with the original char set, the alternate char set has a rather weird layout for chars > 128 with the inverse lowercase chars _not_ at (normal lowercase char + 128).
So far the Apple II CONIO implementation mapped chars 128-255 to chars 0-127 (with the exception of \r and \n). It made use of alternate chars > 128 transparently for the user via reverse(1). The user didn't have direct access to the MouseText chars, they were only used interally for things like chline() and cvline().
Now the mapping of chars 128-255 to 0-127 is removed. Using chars > 128 gives the user direct access to the "raw" alternate chars > 128. This especially give the use direct access to the MouseText chars. But this clashes with the exsisting (and still desirable) revers(1) logic. Combining reverse(1) with chars > 128 just doesn't result in anything usable!
What motivated this change? When I worked on the VT100 line drawing support for Telnet65 on the Apple //e (not using CONIO at all) I finally understood how MouseText is intended to be used to draw arbitrary grids with just three chars: A special "L" type char, the underscore and a vertical bar at the left side of the char box. I notice that with those chars it is possible to follow the CONIO approach to boxes and grids: Combining chline()/cvline() with special CH_... char constants for edges and intersections.
But in order to actually do so I needed to be able to define CH_... constants that when fed into the ordinary cputc() pipeline end up as MouseText chars. The obvious approach was to allow chars > 128 to directly access MouseText chars :-)
Now that the native CONIO box/grid approach works I deleted the Apple //e proprietary textframe() function that I added as replacement quite some years ago.
Again: Please note that chline()/cvline() and the CH... constants don't work with reverse(1)!
We basically cast a struct timespec pointer to a time_t pointer when we pass the clock_settime() paramter to localtime(). Explicitly express that in the source code.
The situation on the Apple II is rather special: There are several types of RTCs. It's not desirable to have specific code for all of them. As the OS supports file timestamps RTC owners usually use OS drivers for their RTC. Those drivers read the RTC and write the result in a "date/time location" in RAM. The OS reads the date/time from the RAM location. If there's no RTC the RAM location keeps containing zeros. The OS uses those zeros as timestamps and the files show up in a directory as "<NO DATE>".
There's no common interface to set RTCs so if an RTC _IS_ present there's just nothing to do. However, if there's _NO_ RTC present the user might very well be interest to "manually" set the RAM location in order to have timestamps. But he surely doesn't want to manually set the RAM location over an over again. Rather he wants to set it just once after booting the OS.
From that perspective it makes most sense to not set both the date and the time but rather only set the date and have the time just stay zero. Then files show up in a directory as "DD-MON-YY 0:00".
So clock_settime() checks if the current time equals 0:00. If it does _NOT_ then an RTC is supposed to be active and clock_settime() fails with ERANGE. Otherwise clock_settime() ignores sets the date - and completely ignores the time provided as parameter.
clock_getres() too checks if the current time equals 0:00. If it does _NOT_ then an RTC is supposed to be active and clock_getres() returns a time resolution of one minute. Otherwise clock_getres() presumes that the only one who sets the RAM location is clock_settime() and therefore returns a time resolution of one day.
We want to add the capability to not only get the time but also set the time, but there's no "setter" for the "getter" time().
The first ones that come into mind are gettimeofday() and settimeofday(). However, they take a struct timezone argument that doesn't make sense - even the man pages says "The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL." And POSIX says "Applications should use the clock_gettime() function instead of the obsolescent gettimeofday() function."
The ...timeofday() functions work with microseconds while the clock_...time() functions work with nanoseconds. Given that we expect our targets to support only 1/10 of seconds the microseconds look preferable at first sight. However, already microseconds require the cc65 data type 'long' so it's not such a relevant difference to nanoseconds. Additionally clock_getres() seems useful.
In order to avoid code duplication clock_gettime() takes over the role of the actual time getter from _systime(). So time() now calls clock_gettime() instead of _systime().
For some reason beyond my understanding _systime() was mentioned in time.h. _systime() worked exactly like e.g. _sysremove() and those _sys...() functions are all considered internal. The only reason I could see would be a performance gain of bypassing the time() wrapper. However, all known _systime() implementations internally called mktime(). And mktime() is implemented in C using an iterative algorithm so I really can't see what would be left to gain here. From that perspective I decided to just remove _systime().
Although the primary target OS for the Apple II for sure isn't DOS 3.3 but ProDOS 8 the Apple II binary files contained a DOS 3.3 4-byte header. Recently I was made aware of the AppleSingle file format. That format is a much better way to transport Apple II meta data from the cc65 toolchain to the ProDOS 8 file system. Therefore I asked AppleCommander to support the AppleSingle file format. Now that there's an AppleCommander BETA with AppleSingle support it's the right time for this change.
I bumped version to 2.17 because of this from the perspective of Apple II users of course incompatible change.
All but one TGI drivers didn't use IRQs. Especially when the TGI driver kernel was the only .interruptor this meant quite some unnecessary overhead because it pulled in the whole IRQ infrastructure.
The one driver using IRQs (the graphics driver for the 160x102x16 mode on the Lynx) now uses a library reference to set up a JMP to its IRQ handler.
All but one joystick drivers didn't use IRQs. Espsecially when the joystick driver kernel was the only .interruptor this meant quite some unnecessary overhead because it pulled in the whole IRQ infrastructure.
I was told that the one driver using IRQs (the DXS/HIT-4 Player joystick driver for the C64) can be reworked to not do it. Until this is done that driver is defunct.
The Apple II linker configs don't define symbols for the STARTP segment anymore. There refer to the load/start address in the same way the executable file header does.
So far the joy_masks array allowed several joystick drivers for a single target to each have different joy_read return values. However this meant that every call to joy_read implied an additional joy_masks lookup to post-process the return value.
Given that almost all targets only come with a single joystick driver this seems an inappropriate overhead. Therefore now the target header files contain constants matching the return value of the joy_read of the joystick driver(s) on that target.
If there indeed are several joystick drivers for a single target they must agree on a common return value for joy_read. In some cases this was alredy the case as there's a "natural" return value for joy_read. However a few joystick drivers need to be adjusted. This may cause some overhead inside the driver. But that is for sure smaller than the overhead introduced by the joy_masks lookup before.
!!! ToDo !!!
The following three joystick drivers become broken with this commit and need to be adjusted:
- atrmj8.s
- c64-numpad.s
- vic20-stdjoy.s
For quite some time I deliberately didn't add cursor support to the Apple II CONIO imöplementation. I consider it inappropriate to increase the size of cgetc() unduly for a rather seldom used feature.
There's no hardware cursor on the Apple II so displaying a cursor during keyboard input means reading the character stored at the cursor location, writing the cursor character, reading the keyboard and finally writing back the character read initially.
The naive approach is to reuse the part of cputc() that determines the memory location of the character at the cursor position in order to read the character stored there. However that means to add at least one additional JSR / RTS pair to cputc() adding 4 bytes and 12 cycles :-( Apart from that this approach means still a "too" large cgetc().
The approach implemented instead is to include all functionality required by cgetc() into cputc() - which is to read the current character before writing a new one. This may seem surprising at first glance but an LDA(),Y / TAX sequence adds only 3 bytes and 7 cycles so it cheaper than the JSR / RTS pair and allows to brings down the code increase in cgetc() down to a reasonable value.
However so far the internal cputc() code in question saved the X register. Now it uses the X register to return the old character present before writing the new character for cgetc(). This requires some rather small adjustments in other functions using that internal cputc() code.
- Adds new ENOEXEC error code, also used by Apple2 targets.
- Maximum command line length is 40, incl. program name. This is
an XDOS restriction.
- testcode/lib/tinyshell.c has been extended to be able to run
programs.
About all CONIO functions offering a <...>xy variant call
popa
_gotoxy
By providing an internal gotoxy variant that starts with a popa all those CONIO function can be shortened by 3 bytes. As soon as program calls more than one CONIO function this means an overall code size reduction.
_sys() is supposed to be (primarily) intended to call ROM routines. Leveraging the "file overlay" mechanism of the cc65 build system allows to provide a Apple II specific _sys() implementation that temporarily switches in the ROM.
Make the same changes to the Apple II that were done with 0ee9b2e446 to the C64.
Notes:
- The startup code deliberately doesn't make use of symbols defined for the LC segment as that segment is optional.
- The <...>-asm.cfg configs move the segment BSS to an own memory area BSS although this doesn't seem necessary. However the benefit is that the size of the memeory area MAIN is identical to the number of bytes loaded from disk into RAM. To keep this an invariant for all Apple II configs allows to simplify the EXEHDR to just refer to the symbols defined for MAIN.
The constructors are _NOT_ allowed anymore to access the BSS. Rather they must use the DATA segment or the INIT segment. The latter isn't cleared at any point so the constructors may use it to expose values to the main program. However they must make sure to always write the values as they are not pre-initialized.
The way we want to use the INITBSS segment - and especially the fact that it won't have the type bss on all ROM based targets - means that the name INITBSS is misleading. After all INIT is the best name from my perspective as it serves several purposes and therefore needs a rather generic name.
Unfortunately this means that the current INIT segment needs to be renamed too. Looking for a short (ideally 4 letter) name I came up with ONCE as it contains all code (and data) accessed only once during initialization.
Moving __cwd from BSS into INITBSS does of course ;-) not only impact the CBM targets but all targets with disk I/O support.
Note: Code using `__cwd-1` may trigger an ld65 range error because __cwd may end up at the very begining of a segment. As far as I see this is an ld65 bug which I'm not try to fix - at least here.
The starting point is the CALL2051:REM <cmdline> approach. It uses the BASIC input buffer at $200. ProDOS stores the name of the loaded program at $280 (which we want for argv[0]) leaving us with 128 char buffer. If we run the program via exec() we don't need the CALL2051 but only the REM token (which is just one char). So have a maximum cmdline length of 126 (plus a terminating zero).
There's no specification for ProDOS BIN file cmdline parameters so exec() just supports the CALL2051:REM <cmdline> approach. In contrast ProDOS SYS files allow for a 'startup filename'. A ProDOS filename is short than 126 chars so having exec() general cut the cmdline after 126 chars seems reasonable. If the SYS file we exec() allows for less we cut the cmdline further.
Our 'loader.system' SYS file however allows for an unusually 126 char long "startup filename" as it is targeted towards cc65 BIN porgrams with their 126 cmdline length.