Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by rje

  1. Spurred to action by the Mini-PET. He uses a 65816 as the CPU, and a CPLD to do a lot of the dirty work on the board. https://github.com/fachat/MicroPET Commodore 3032 / 4032 / 8032 / 8296 with options menu to select at boot Boot-menu to select different PET versions to run 40 col character display 80 col character display 8296 memory map emulation IEEE488 interface (card edge) Tape connector (card edge) PET graphics keyboard, or alternatively a C64 keyboard Improved system design: 512k video RAM, 512k fast RAM accessible using banks on the W65816 CPU boot from an SPI Flash ROM up to 12.5 MHz mode (via configuration register) VGA b/w video output Write protection for the PET ROMs once copied to RAM lower 32k RAM mappable from all of the 512k fast RAM Improved Video output: Hires graphics mode (using a configuration register) modifyable character set 40/80 column display switchable 25/50 rows display switch multiple video pages mappable to $8000 video mem address
  2. I think folks who can get the X16 have already decided to get the X16. The X8 won't change their minds -- they'll simply pick up one of those, too. If anything, I think the X8 is a marketing tool -- sending out the X8 to evangelize would bring greater awareness of the X16.
  3. KERNAL extensions are indeed "easy"... especially compared to hardware. Totally. And don't need to be done before release. Deferrable until needed.
  4. Yes, I agree with you. The reason I left the MEGA65 discussion lists is because I knew I wouldn't be able to justify buying one. The X16 is more affordable, but it's the same issue: I pay a significant amount of money for something that's going to take up desk space that I don't have, and I'm not sure what I'd do with it really. The X8, on the other hand: I already want one. It hits my price point so easily. Worth it. Regardless of whether or not I get the X16.
  5. Yes, I'm old and distracted. I guess I have to be talking about compiling and/or interpreting on the hardware. Which is kind of moot: I find it very hard to think of a reason to write code directly on these machines. (1) Batch-like coding, e.g. testing something or launching something else. (2) There doesn't appear to be a #2. I had thought that perhaps some filtering could be done on the X16. E.G. an AWK-like program that sifts file contents. Not sure.
  6. One application that would probably work on the X16 better than the X8 is GeckOS for the 6502. The main reason I think it would work (much) better on the X16 is the benefits of all that nice banked RAM. But, I could be wrong.
  7. The ecosystem for the X8 will be highly performant games and smaller demos. This includes BASIC programs like Lunar Lander and Rogue-like games. But I'll tell you, once I got CC65 working, I never looked back. BASIC is not friendly for longer and more complex games. Also, BASIC 2.0+ is no country for programs over 8K by people older than 12 years old. Your brain has to be super spongy. It also includes more cutting-edge assembly-coded games. Maybe even some shooters resembling Wolf 3D. * * * The ecosystem for the X16 will be larger, more capable games, and (potentially) richer small games. They're more likely to be fuller featured, with a standard ADSR envelope library, fewer SD accesses (maybe?), blah blah. Some fake examples: Ultima X16 will have banked music and the "current local map". The 7 Pirate Kingdoms of Gold will have its entire map (1024 x 1024) banked, running in a vast simulation. Traveller Trader implements a generous swath of interstellar space with a high level of RPG detail. * * * Wild guessing. Also assuming that all programmers cross over between two languages. 100% BASIC 2.0+ 25% Structured BASIC ("ALGOL X16") 25% Forth 25% C 25% Assembly So one in four developers for these platforms are working primarily in one of these, and secondarily everybody uses BASIC 2.0+ as the "batch mode" of the system.
  8. X8 is of course controversial in general, and so it was reasonable to keep the lid on it. IT is interesting to think about their incompatibilities, and what effort that might create. I'm not sure if it would... ...and actually not aiming for 100% compatibility helps in that regard. Aiming for a level of general compatibility, via a minimal set of KERNAL calls, gives them design flexibility. * * * In fact, think about a KERNAL where the video and sound calls are generalized, and aimed at a specific base capability. What prevents you from replacing VERA with something else, assuming you meet the KERNAL's capability assumptions? Just thinking out loud.
  9. Yes, there is that. I suspect it won't be that bad. I just re-read the KERNAL documentation https://github.com/commanderx16/x16-docs/blob/master/Commander X16 Programmer's Reference Guide.md#sprites), and had forgotten that there are already sprite calls in the KERNAL that serve as a translation layer between a program and VERA. And it had this for awhile. It stands to reason that there are also PSG KERNAL calls planned. If they also create a memory-move from system RAM to VERA, then the KERNAL effectively insulates the coder to a large degree from VERA access. It doesn't grant 100% compatibility, but it does let an (even larger) amount of code written on one platform work on the other. Niche cases will emigrate to one or the other platform. It's a strength that they have different emphases and price points. To sum up, the MAIN hoo-hah about the X8 is that VERA is interfaced differently. This is an old problem that the KERNAL would solve, so presumably we should be able to call things like: JSR $FFE0 ; psg_play_sound() JSR $FFE3 ; memcpy_to_vram() (The addresses are bogus; I just made a couple up)
  10. Micheal Steil has extended the KERNAL with lots of neat stuff -- more support for BASIC stuff, the DOS wedge, subdirectories, those 16 bit pseudo-registers in zero page, and so on. We also know that the KERNAL has calls for sprite management. It seems to me that KERNAL calls for PSG sound setup and copying memory to video would be generally useful. https://github.com/commanderx16/x16-docs/blob/master/Commander X16 Programmer's Reference Guide.md#sprites $FEF0: sprite_set_image - set the image of a sprite bool sprite_set_image(byte number: .a, width: .x, height: .y, apply_mask: .c, word pixels: r0, word mask: r1, byte bpp: r2L); Error returns: .C = 1 in case of error Fairly generic, in that this data is generally sufficient to describe a wide range of sprites, including C64 sprites, and including sprites that might exceed VERA's capability. So then, how about something like this: $FEE7 (memory_copy): extend this to allow copying memory to the video card. And: $FEF0: psg_set_sound: define and play a sound on a given voice bool psg_set_sount(byte voice: .a, word frequency: r0, byte channel: .x, byte volume: .y, word waveform: r1, word pulse_width: r2)
  11. That was my first impression. Bruce, who is an economist, helped show that the market separation between X8 and X16 make them reasonably distinct, and selling the X8 won't impact selling the X16, which is my only concern. Also, I just noted that the KERNAL is common between them. Therefore, a small VERA ABI layer in the KERNAL could help bridge the two to a degree, allowing more code compatibility without being full-featured.
  12. I COULD BE WRONG, BUT: I think compatibility is overrated, for two theoretical and two practical reasons. First, if the two systems were compatible, then the least capable one is likely to be what developers code for generally, and the more capable one is likely to be what the demoscene codes for. In other words, you split the user base REGARDLESS, so time and resources are spent and nothing is accomplished. Second, in order to make the two systems compatible, you must cripple features on one or both machines, which is a lose/lose overall. And if only ONE of the machines is crippled thus, it either drags them both down (because you code to the lowest common denominator) or it kills the more expensive of the two. So time and resources are spent and nothing is accomplished. * * * Now for the practical reasons: First, the X8 fits neither the ecosystem nor the market of the X16. Therefore, there's no reason to make the two architecturally compatible. Second, the X8 and X16 are architecturally DESIGN COMPLETE. I strongly doubt the X8 is going to be re-engineered, and neither is the X16 -- sticking with the plan is the way to finish, rather than reversing direction and starting over. THAT SAID: Both systems have the KERNAL in common. That means a lot of the two systems are ALREADY compatible. A VERA ABI layer in the KERNAL could increase this compatibility a bit.
  13. I've thought about Paul Scott Robson's Structured BASIC, and I think that's pretty much a kind of ALGOL, and also pretty near the apex for any imperative language "running" "native" on the X16. * * * Suppose I were to migrate an imperative language to the X16. import java.util.regex.*; public class GFG { public static void main(String[] args) { // Get the regex to be checked String regex = "Geeks"; // Create a pattern from regex Pattern pattern = Pattern.compile(regex); // Get the String to be matched String stringToBeMatched = "GeeksForGeeks"; // Create a matcher for the input String Matcher matcher = pattern.matcher(stringToBeMatched); // Get the Pattern using pattern() method System.out.println("Pattern: " + matcher.pattern()); } } 1. I'll start with Java, JavaScript, or, yes, Python or Smalltalk or other OO-like languages. First, I suspect that resources are too limited for a class and object system, though I could be wrong. So the syntax of these critters effectively reduces to that of Perl or C, perhaps with some special extra types for things we lose when leaving OO. import java.util.regex.*; void main(int argc, String[] argv) { // Get the regex to be checked String regex = "Geeks"; // Create a pattern from regex Pattern pattern = Pattern_compile(regex); // Get the String to be matched String stringToBeMatched = "GeeksForGeeks"; // Create a matcher for the input String Matcher matcher = pattern_matcher(stringToBeMatched); // Get the Pattern using pattern() method println("Pattern: " + matcher_pattern()); } 2. Now we're at Perl, C, and related things. These will experience the same reductions when porting to the X16: braces don't exist, and significant regular expressions don't either, and so we reduce scope while also moving to syntax brackets like BEGIN and END. Thus the syntax of these tend to merge with Pascal. import java.util.regex.*; void main(int argc, String[] argv) begin // Get the string to be checked String regex = "Geeks"; // Create a pattern from regex pattern_compile(regex); // Get the String to be matched String stringToBeMatched = "GeeksForGeeks"; // Call the simple pattern matcher on the input String simple_pattern_matcher(stringToBeMatched); // Get the match using matcher_pattern() method println("Pattern: " + matcher_pattern()); end 3. Now we're at some variant of Pascal, and we find we probably have to lose slices, strong "do it yourself" type systems, structures (?), any sense of an object system, and probably the general use of hashtables. Maybe we can save an "environment" table, which may have interesting environment variables and be partly useable as one general purpose hashtable. Maybe. This moves us to some version of ALGOL -- complete with capital letters. IMPORT JAVA.UTIL.REGEX.*; VOID MAIN(INT ARGC, STRING[] ARGV) BEGIN // GET THE STRING TO BE CHECKED STRING REGEX = "GEEKS"; // CREATE A PATTERN FROM REGEX PATTERN_COMPILE(REGEX); // GET THE STRING TO BE MATCHED STRING STRING_TO_BE_MATCHED = "GEEKS_FOR_GEEKS"; // CALL THE MATCHER WITH THE INPUT STRING SIMPLE_PATTERN_MATCHER(STRING_TO_BE_MATCHED); // GET THE PATTERN USING MATCHER_PATTERN() PRINTLN("PATTERN: " + MATCHER_PATTERN()); END 4. Now we're somewhere in ALGOL. The type system is next to be simplified. After using CC65 and considering Paul Scott Robson's posts and S-BASIC, I recommend throwing out floating point. Also, we use something like the ALGOL key word REF, (or the more obvious PTR), to indicate a pointer. The word itself isn't important. IMPORT JAVA.UTIL.REGEX.*; PROC MAIN(INT ARGC, PTR STRING ARGV) // ?? BEGIN // GET THE STRING TO BE CHECKED STRING REGEX = "GEEKS"; // CREATE A PATTERN FROM REGEX PATTERN_COMPILE(REGEX); // GET THE STRING TO BE MATCHED STRING STRING_TO_BE_MATCHED = "GEEKS_FOR_GEEKS"; // CALL THE MATCHER WITH THE INPUT STRING SIMPLE_PATTERN_MATCHER(STRING_TO_BE_MATCHED); // GET THE PATTERN USING MATCHER_PATTERN() PRINTLN("PATTERN: " + MATCHER_PATTERN()); END 5. The X16 doesn't really have a shell environment, so we change MAIN to be a regular PROC with params. I doubt libraries will exist, so that goes. Maybe (not sure) sigils come back in. If it reduces the complexity or resource use of the runtime, then sigils are an obvious choice. If not, then no need to have them. But if so, it would plant us firmly back in a form of Structured BASIC. CALL MATCH_TEST( "GEEKS", "GEEKS_FOR_GEEKS" ); END // REGEX$: THE STRING TO BE CHECKED // STRING_TO_BE_MATCHED$: THE STRING TO BE MATCHED PROC MATCH_TEST(PTR REGEX$, PTR STRING_TO_BE_MATCHED$) BEGIN // CREATE A PATTERN FROM REGEX PATTERN_COMPILE(REF REGEX$); // CALL THE MATCHER WITH THE INPUT STRING SIMPLE_PATTERN_MATCHER(REF STRING_TO_BE_MATCHED$); // GET THE PATTERN USING MATCHER_PATTERN() PRINTLN("PATTERN: " + MATCHER_PATTERN()); END
  14. AWK is a powerful filter DSL used for data extraction and reporting. Its fundamental structure is a set of matches and corresponding actions. It boils down, almost, to a set of if-thens based on the input stream. When you match THIS expression, do THAT. If you've ever done ladder logic, it seems kind of like that. PATTERN {ACTION} PARAMETER-ASSIGNMENTS 'FILENAME' There are shorter forms, since the condition defaults to "always", action defaults to "print the line", and parameters have defaults, so this short form means "cat": 'MYFILE' Original Intent "a tool that would easily manipulate both numbers and strings" and search for patterns in data. AWK-8 ? X16 Awk would be a stripped-down AWK. I think it can still be useful and even interesting to have tools that can do file tests, streaming filters, and report building. Reading through several introductions to AWK, here are the features I think might work in a non-shell 8-bit Commodore setting: PATTERNS 1 as the default pattern. Expression evaluating to non-zero. String matching. Range matching? ACTIONS "print($0)" as the default Action. A list of semicolon-terminated expressions. EXPRESSIONS RS (record separator). Integer. Default is \n. FS (field separator). Char or char*. Default is \s. NF: number of fields in the current record. NR: current record number. Starts at 1. $0 as the current record. $1..$9 as the fields in the current record. A reasonable stash of general purpose variables. Integer arithmetic. Integer comparison. Symbol table (hashtable) operations. Various library of function calls (like print). As many as you can fit into the binary.
  15. Different architectures serve different purposes, result in different programs. That's not necessarily a bad thing, since each has a slightly different ecosystem. * PRO X16. I LOVE the banked RAM in the X16, because it gives me an alternative to file access (it's nice to have choices), plus it gives me a huge playing field for Core Wars, which would not work well using swap files. I also worry (needlessly?) about programs that do a LOT of file access against an SD card, because I tend to think of SD cards as having a (large) read/write limit with no warning of impending doom. * PRO X8. I LOVE the idea of a significantly faster processor with a friendlier VERA window. This lets me focus on more twitch-intensive games, and also lets me toy with things like interpreters, which might run intense-r operations at reasonable speed.
  16. The 7F is interesting. I wonder if 127 is the place-holder for "no known character". If the character is guessed as a non-word character, the ASCII value would show up, but that's text (e.g. C:42 for the * character). The 0A sounds like a Windows artifact, but it was produced on Solaris so it can't be that... unless the file transfer to Windows added it in (unlikely). The C code itself could have written \r\n to the header to be friendlier to Windows-based code...
  17. Attached is a very old example of a pixobject, which I created at work using our handwriting analysis code which chops up connected writing based on best guesses. As a smoke test, I scanned in pages from the Codex Serafinianus and forced our code to try to segment it. The result is a fair pile of little snippets like this one. The header is a bit opaque to me. =C: 64 105 1012 3682 0 0 C : means it thinks it's a character, but can't tell what character it is. If for example it thought it was the letter "E", it would have shown C:E. If on the other hand it thought it was a symbol, it would have used an S: and the guessed symbol name. Then come the rows and columns. Those three fields are mandatory, always. The rest are optional. The next two numbers are -- most likely -- the original raster position of the image on the page. This allows the GUI to overlay the pixobject selection over the original raster image for human editing. I'm not sure what those last two numbers were for. They're always zero in the samples I've got. codex-test.pix
  18. Ha! I had completely forgotten about the computer vision assignments that used text-bitmaps to trace edges, sharpen, compute moments, determine shape, etc. Thanks for the reminder.
  19. And here's the corresponding script to deconstruct a sprite into a pixobject. use strict; # # Convert CX16 sprites to pixobjects # USAGE: perl bin2pix.pl <4bpp | 8bpp> <width> <sprite file> # =pod The VERA sprite format has two varieties: 4 bits per pixel 8 bits per pixel This script is not smart enough to know the color depth; therefore, the command line has to specify "4bpp" or "8bpp". Similarly, the script is not smart enough to know the image width. The output is a pixobject with this format: =NAME 4bpp|8bpp WIDTHxHEIGHT "NAME" is the filename minus the extension. WIDTH and HEIGHT are in pixels. What follows is the lines of data. These values are supported: 0-9 colors 0-9 A-Z colors 10-35 a-z colors 36-61 =cut my $bpp = shift || die "USAGE: $0 <4bpp | 8bpp> <width> <sprite file>\n"; my $width = shift || die "USAGE: $0 $bpp <width> <sprite file>\n"; my $infile = shift || die "USAGE: $0 $bpp $width <sprite file>\n"; my ($name) = $infile =~ /^(\w+)\./; my $line = ''; my @data = (); open my $in, '<:raw', $infile || die "ERROR: cannot open sprite file [$infile]\n"; read $in, my $nullbytes, 2; while (read($in, my $c, 1) != 0) { my $v = unpack 'C', $c; if ($bpp eq '4bpp') # two chars per byte { $line .= decodeByte($v >> 4); $line .= decodeByte($v & 0x0f); } else # one byte per byte { $line .= decodeByte($v); } if (length($line) == $width) { push @data, $line; $line = ''; } } close $in; my $height = scalar @data; my $dimensions = $width . 'x' . $height; my $data = join "\n", @data; print<<EOPIXOBJ; =$name $bpp $dimensions $data EOPIXOBJ sub decodeByte { my $val = shift; return '.' if $val == 0; return '*' if $val == 1; return chr(48+$val) if $val < 10; # '0'..'9' return chr(55+$val) if $val < 36; # 'A'..'Z' return chr(61+$val) if $val < 61; # 'a'..'z' return '.'; # everything else is a dot }
  20. Back in my first job, we represented raster images in a text format we called "pixobjects". Our data was monochrome, so an asterisk represented an "on" pixel, and a space or dot was "off". So a file representing a house would look sort of like this: =house1 4bpp 16x8 ****** ********** ************** ********** *** ** *** ****** *** I've embellished the header line, which used to only contain the name of the object and (optionally) its dimensions, to include bits per pixel, because I feel the need for this sort of command line tool again. ALTHOUGH I remember that someone already WROTE a REAL sprite editor. Nevertheless, I dashed out a Perl script that would handle 4bpp images in this textual format. It can also handle a subset of 8bpp -- values 0 through 61. use strict; # # Convert pixobjects to CX16 sprites # USAGE: perl pix2bin.pl <input file> # =pod The pixobject file format is as follows: A header line, containing the object's name, its bits per pixel, and its dimensions. Data lines following. Hexadecimal digits are interpreted properly. Values from 0 up to 61 are handled as 0-9, A-Z, and a-z. The full 8 bit range of values are not handled correctly. Example: =house1 4bpp 16x8 ****** ********** ************** ********** *** ** *** ****** *** This should be useful for creating small 4bpp sprites for the CX16. I naturally want to write a complementary utility that will unpack a CX16 4bpp sprite into a pixobject file. =cut my $infile = shift || die "SYNOPSIS: $0 pixobj\n"; open my $in, '<', $infile; my $header = <$in>; my @data = <$in>; close $in; chomp @data; my ($name, $bpp, $width, $height) = $header =~ /=(\w+) (4bpp|8bpp)\s+(\d\d?)x(\d\d?)/; die "Cannot read header\n" unless $bpp && $width && $height; my $dimensions = $3 . 'x' . $4; my $outfile = sprintf("%s_%s_%s.bin", $bpp, $name, $dimensions); print "===> $outfile <=== $bpp, $width x $height\n"; open my $out, '>', $outfile; print $out pack 'xx'; # initial two null bytes foreach my $line (@data) { my @bits = split '', $line; my @line = (); my $odd = 1; # This is how we'll handle 4 bits per pixel. my $value = 0; for (0..$width-1) { my $charval = getCharval($bits[$_]); if ($bpp =~ /4bpp/i && $odd) { $value = $charval << 4; # initial value = upper nybble } else # 8 bits OR we're even { $value += $charval; print $out pack 'C', $value; $value = 0; # and reset } $odd = 1 - $odd; # toggle for nybbles } } close $out; sub getCharval { my $c = shift; return ord($c)-48 if $c =~ /\d/; # 0-9 return ord($c)-55 if $c =~ /[A-Z]/; # 10-35 return ord($c)-64 if $c =~ /[a-z]/; # 35-61 return 1 if $c eq '*'; return 0; # everything else is a zero }
  21. ADSR data, I had earlier thought, could be four bytes per voice, for a total of 64 bytes, buried somewhere around $400 or so. It would also need a status counter for each voice, so that we'd know where the sound was along its envelope. The status would have to be, I think, a quantized (sic?) "unit" segment, with 0 meaning the sound is right at the start of the Attack phase, and MAX_VALUE meaning the sound has just finished the Release phase. OR I just do things a brute force way and not try to be clever about it.
  22. Here's my initial structure. The initial function would therefore be this: void defineVoice( Voice* voice ); ----- typedef struct { int frequency: 16; int channel: 2; int volume: 6; int waveform: 2; int pulseWidth: 6; int attack: 8; int decay: 8; int sustain: 8; int release: 8; } Voice; Then I've got things like these: #define CHANNEL_LEFT (1 << 6) #define CHANNEL_RIGHT (2 << 6) #define CHANNEL_BOTH (3 << 6) #define WAVE_PULSE (0 << 6) #define WAVE_SAWTOOTH (1 << 6) #define WAVE_TRIANGLE (2 << 6) #define WAVE_NOISE (3 << 6)
  23. I'm slowly building a kind of C toolchain so I can program interesting things on the CX16. Now it's time to start thinking about a PSG interface. With sprites, I've had success by defining a sprite record, then writing functions that do basic sprite things. I think that is how I will approach the PSG as well. I've muttered about a general PSG API in other discussions on this forum, so I'll probably dig through them to figure out where to start. Obviously, a voice definition struct would have the voice number, waveform, volume. Would it have EVERYTHING, including frequency? Then the functions just take what they need from the struct pointer? My thought is I don't want to multiply typedefs. 1. Does it make sense to have most or all data in one typedef? 2. Does it make sense to have ADSR data in there as well? 3. Does it make sense to try to implement envelope control (in C)? I suppose there will have to be an external "clock" that calls a C envelope manager, which means there will have to be one sound structure allocated per voice. And yes, that sound "structure" is probably just going to be a hunk of contiguous memory that an interrupt-driven assembly routine could also handily work in instead. 4. What else am I missing?
  24. Very true. That's a good option. But I'll have to stew on it for awhile. However, I think before I get to that point, I want to write a simple PSG interface in C.
  25. I've started thinking about how I'm going to interact with the map. The ship should "stop" when it hits land, and a landing party should take over movement. The ship's movement needs to be finer grained. (easy) The landing party should interact with settlements. If I have enough VERA RAM left, I want sprites to define a few key buildings (maybe 16 x 16?). In this way, the landing party can interact with the town without requiring a separate town map, and it keeps essential things without adding stuff I don't want to do. Replacing the "settlement" sprites gives me 8K VERA RAM to define buildings and groups of people. I can re-use the settlement graphics and chop them up into some of these smaller, 16 x 16 sprites.
  • Create New...

Important Information

Please review our Terms of Use