Saturday, July 25, 2020

Commander X16 is on its way...

In case you haven't heard, there's a new 8-bit retro computer being built, and it's new but old.

Try it out online here: https://www.commanderx16.com/forum/index.php?/home/



It's not a clone, so it's a new architecture.  And yet, it re-purposes an old, established architecture, so it's old.

The Commander X16 is a Commodore clone.  Since it uses the Commodore KERNAL and BASIC and runs with a 65C02 processor, it is as compatible with the Commodore family as the other Commodore machines are with each other.  But since it's not a C64 or PET or Plus/4, binaries from them will generally not run on it... unless, that is, the code is in a safe location and uses the KERNAL's jump table.

It supports the IEC serial bus, so you could attach a disk drive if you really wanted to.  But it replaces the cassette port with an SD card slot (good call!).

It's got a neat memory map, too.

The basic architecture draws from the VIC-20, which is uncomplicated: the ROMs are in the highest chunk of memory, and there's static RAM below it.  Static RAM itself is uncomplicated, compared to the dynamic RAM of the C64 and on.  Because we live in 2020, 64K of static RAM is cheap.  Back in the 80s, I suppose it was very expensive.

After that, things get interesting but still not complicated:

There's 39K of RAM, from $0000 to $9EFF.  I'm not sure how that's divided up: I bet it cheaper just to install a single 64K static RAM chip than to install a 32K and a 16K one!

Then there's a page of I/O registers, from $9F00 to $9FFF.

Then, there's 8K of high RAM, from $A000 to $BFFF.  Here's the tricky part though: this 8K window is banked.  In the production model, the bank will be switched at Zero page location $0000 (sound familiar?).  The X16 can have up to 256 banks of this RAM, so up to 2mb of RAM.

After that comes 16K of ROM, from $C000 to $FFFF.  This is where the KERNAL and BASIC ROMs live.  But there's another tricky bit: this 16K window is ALSO banked.  There are already four or five banks allocated, with one for GEOS, one for a proper assembler, another for a Structured BASIC, and so on.

Because 8-bit video chips are nonexistent, there is an FPGA for that.  Sound is still being discussed, I think, but of course the designers want sound to be stereo and at least SID quality.

Thursday, February 11, 2016

Perl6: classes and working with binary data

ROOM FOR IMPROVEMENT: It would probably be better if the class defined below implemented the Buf "role".  That way, code that used it could (for example) call .list and .elems directly on the class... which I think would be a very nice way to open up the class.  Or is that TOO open?  Meh, I think people who hack on Commodore 1541 diskette images should be implicitly trusted.

class Image {
    has Str $.sourcefile is rw;  # accessors auto-generated
    has Buf $!buffer;            # private, no accessors

    has $!hdr = (17 * 21) * 256; # byte offset
   
    method load() {
       return "no sourcefile specified" unless $.sourcefile;
       

       # read in a binary file
       my $fh = open( $.sourcefile, :r, :bin );
       $!buffer = $fh.slurp-rest(:bin);
       return "$.sourcefile loaded";

     
       # (oops - forgot to close the file)
    }
   

    method size()  { $!buffer.elems }
 


    # Each of these methods return "Buf": a class used
    # for dealing with binary data buffers.

    method label() { $!buffer.subbuf($!hdr + 143, 16) }
    method hdr()   { $!buffer.subbuf($!hdr, 256) }   
    method dir( Int $index ) {
        my $offset = $!hdr + 256 + $index * 32;
        return $!buffer.subbuf($offset+2, 30);
    }
}

my Image $test = Image.new( sourcefile => "mule.d64" );
say $test.load();
say $test.size(), " bytes read";

my $hdr   = $test.hdr();  
my $label = $test.label();

print "Label: ";
for $label.list -> $val {
   if 31 < $val < 92 { print chr($val) }
   else { print '.' }  
}
print "\n";

my $blob  = $test.dir(1); # (actually the 2nd entry)

for $blob.list -> $val {
   if 31 < $val < 92 { print chr($val) }
   else { print '.' }  
}


% perl6 Image.p6
mule.d64 loaded
174848 bytes read
Label: .M.U.L.E........
...MULE.2.....................


Friday, February 5, 2016

Wednesday, February 3, 2016

Perl6: insane (in a good way)

Just an example.  I can't believe how amusing yet efficient this syntax is.

my  %ingredients = :4eggs, :2sticks-of-butter, :4cups-of-sugar;
say %ingredients;
# OUTPUT>>:
# cups-of-sugar => 4, eggs => 4, sticks-of-butter => 2
 
 

Is Perl6 really Perl?

There has been some discussion about whether Perl6 was mis-named.

I thought that that was a silly discussion not worth getting involved in.  It's quite obviously Perl in some form.

The argument, if I understand it, is that Perl6 "sounds like" a version increment from Perl 5.  This violates the principle of least surprise.

OK, I can understand that.  In that sense it would be mis-named.  But then what do you CALL it?  I haven't seen any suggestions.

So I'll suggest one based on the compiler used for it.  Call it Rakudo.  At least until a better name is thunk up.


Monday, February 1, 2016

Perl6: error by design in split()?

So while splitting a string, I found some odd results.  But it's actually NOT a bug... and therefore I consider that to be a DESIGN ERROR.

Suppose we have a $string "Hello, world!", and we split it into characters.  In Perl, we do it these ways:

my @foo = split '', $string; # perl 5
my @foo = $string.split(''); # perl 6

And in both cases, we end up with an array:

[ H e l l o ,   w o r l d ! ]

HOWEVER, in Perl6 I see something odd: two extra characters in my stream:

[]  <= what's that?  \0? \b?
[H]
[e]
[l]
[l]
[o]
[,]
[ ]
[w]
[o]
[r]
[l]
[d]
[!]
[] <= what's that?  \0?  \b?


So let's check to see if those two end elements are defined.

for @bar -> $letter
{
   printf "[$letter] %x\n", $letter.ord if $letter;
   say "undef" unless $letter;
}


undef
[H] 48
[e] 65
[l] 6c
[l] 6c
[o] 6f
[,] 2c
[ ] 20
[w] 77
[o] 6f
[r] 72
[l] 6c
[d] 64
[!] 21
undef



Looks like a bug to me.  And yet the docs say:

If DELIMITER is a string, it is searched for literally and not treated as a regex. If DELIMITER is the empty string, it effectively returns all characters of the string separately (plus an empty string at the begin and at the end).

A number of optional named parameters can be specified, which alter the result being returned. The :v, :k, :kv and :p named parameters all perform a special action with regards to the delimiter found.

  • :skip-empty
If specified, do not return empty strings before or after a delimiter.

Baloney.  That's not how I expect split to work BY DEFAULT.  I expect that string to be split, and nothing added, thank you very much.

EVEN BETTER, :skip-empty doesn't appear to work in the admittedly pre-1.0 version of Perl6 I'm running (2015.09).







Friday, January 29, 2016

A Short Perl6 ASCII Rotator

This script rotates a simple chunk of ASCII art based on user input (90, 180, or 270 degrees). It's not very elegant, and there's a minor and annoying bug in it, but I'm done for the day, so.  Here's a test run:

+OO
OOO
OOO

% 90


OOO
OOO
+OO


% 180


OO+
OOO
OOO


% 270


OOO
OOO
OO+


% 180


+OO
OOO
OOO


%


And here's the code.


my Str @test = ("+OO"
               ,"OOO"
               ,"OOO");


my $r = 0;

loop
{
    run( 'cls' );
    say @test.join( "\n" );
    my $in = prompt "\n% ";

    @test = rotate( 90,  @test )  if $in ~~ /90/;
    @test = rotate( 180, @test ) if $in ~~ /180/;
    @test = rotate( 270, @test ) if $in ~~ /270/;
}          

sub rotate( $degrees, Str @pixobject )
{
   return @pixobject if $degrees % 360 == 0;
  
   my Str @a = @pixobject;
  
   @a = rotate90( @a );
   @a = rotate90( @a ) if $degrees > 90;
   @a = rotate90( @a ) if $degrees > 180;

   return @a;
}  

sub rotate90( Str @pixobject )
{
   my Str @new = ();
   for @pixobject -> $line
   {
      my Str @row = $line.split('');
      my $len = @row.elems;
      for (0..$len) -> $i
      {
         @new[$len-$i] = '' unless @new[$len-$i];
         @new[$len-$i] ~= @row[$i] if @row[$i];
      }
   }
   return @new;
}