Category: Commodore Toggle Comment Threads | Keyboard Shortcuts

30 years after its release it’s time to re-kindle with my first computer spirit – the C64. This was my first computer which changed my life forever. Thanks to VICE we can now enjoy the little guy again on modern hardware. Here are all my notes on how to talk to him, and his other friends from the 8 Bit Age.

  • Jay Versluis 10:17 am on April 1, 2018 Permalink | Reply
    Tags: , , ,   

    Categories: Commodore   

    Sorting an Array on the Commodore 64 

    In this video I’ll demonstrate how to sort a numeric array on the Commodore 64. The same principle works for string arrays, and of course on all other Commodore BASIC computers.

    The technique I’m using here is called Bubble Sort: in effect we’re comparing the first two items in the array, and if the left one is larger than the right one, the values are swapped around. This loop continues until all items in the array have been compared and sorted (hence the smallest items “bubble” to the front of the array, much like the smallest bubbles in a soda float to the top first).

    Here’s the full code I’m building, including the lottery portion. The Bubble Sort code starts in line 200.

    10 x=rnd(-ti)
    20 for i=1 to 6
    30 rn=int(rnd(1)*49)+1
    40 for j=1 to i
    50 if n(j)=rn then 30
    60 next j
    70 n(i)=rn
    80 next i
    100 print:gosub 200
    110 for i=1 to 6
    120 print n(i);
    130 next
    140 print
    199 goto 20
    200 rem bubble sort
    210 for i=5 to 1 step -1
    220 for j=1 to i
    230 x=n(j):y=n(j+1)
    240 if x>y then n(j)=y:n(j+1)=x
    250 next:next
    299 return

    I’ve explained how to build the lottery generator in this code here: https://wpguru.co.uk/2018/03/how-to-generate-lottery-numbers-on-the-commodore-64/

    Happy retro hacking!





     
  • Jay Versluis 12:39 pm on March 31, 2018 Permalink | Reply
    Tags: , ,   

    Categories: Commodore, Screencast ( 87 )   

    How to generate Lottery Numbers on the Commodore 64 

    In this video I’ll demonstrate how to draw random lottery numbers on a Commodore 64. The secret sauce here is not only the RND function to generate random numbers, but also two loops inside each other that prevent the same number from coming up more than once.

    Here’s the lottery generator code:

    10 x=rnd(-ti)
    20 for i=1 to 6
    30 rn=int(rnd(1)*49)+1
    40 for j=1 to i
    50 if n(j)=rn then 30
    60 next j
    70 n(i)=rn
    80 next i
    100 print
    110 for i=1 to 6
    120 print n(i);
    130 next
    140 print
    199 end

    To adapt this listing to match your local lottery, change line 20 to the amount of numbers to be drawn from your pool (6 in my example), and change the value in line 30 to match the size of your pool (49 in my example).

    Any questions, please let me know below.

    Happy retro hacking!





     
  • Jay Versluis 9:45 am on March 29, 2018 Permalink | Reply
    Tags: ,   

    Categories: Commodore, Screencast ( 87 )   

    How to build a Word Splitter on the C64 in Commodore BASIC 

    In this video I’m demonstrating how to build a word splitter on the Commodore 64. We’ll use string functions to parse a sentence and split each word off into an array of words so that they can be analysed later (for example, as part of an adventure game).

    Here’s the code I’m building:

    20 input a$
    30 gosub 100
    40 print:print wd;" words:"
    50 for i=1 to wd
    60 print wd$(i)
    70 next
    99 end
    100 rem word splitter
    110 lt$="":wd=1
    120 for i=1 to len(a$)
    130 lt$=mid$(a$,i,1)
    140 if lt$=" " then wd=wd+1:next
    150 wd$(wd)=wd$(wd)+lt$
    160 next
    199 return

    The interesting part starts in line 100 and onwards, where I’m building a subroutine that deals with the string functions. In line 110 I’m resetting/initialising two of the three important variables: LT$ holds a single letter from the phrase we’re getting in A$, while WD is counting each word we’re splitting out.

    The FOR loop in line 120 parses each letter of the phrase, and if it finds a space character (line 140), the word count is increased. If the letter is not a space, then it’s added to the current word held in WD$(WD). The current word is assembled character by character.

    Apologies for the audio quality, I did this on my laptop while sitting on the balcony, hence sea planes flying overhead can be heard (as well as the neighbours dog and kids).

    Happy hacking 🙂





     
  • Jay Versluis 9:58 am on March 28, 2018 Permalink | Reply
    Tags: ,   

    Categories: Commodore, Screencast ( 87 )   

    How to build a time of day clock on the Commodore 64 

    In this video I’ll demonstrate how to build a simple clock on the C64. We’ll go through this process step by step, including the built-in TI and TI$ variables, string formatting with LEFT$, RIGHT$ and MID$, as well as screen formatting.

    Here’s the code I’m writing – works in Commodore BASIC v2 and above:

    5 input "qwhat is the current time (hhmm
    ss) ";ti$
    10 print chr$(147):print chr$(5)
    20 a$ = left$(ti$,2)
    25 a$ = a$ +":"
    30 a$ = a$ + mid$(ti$,3,2)
    35 a$ = a$ +":"
    40 a$ = a$ +right$(ti$,2)
    50 gosub 200
    60 print chr$(19)
    70 print "qqqqqqqqqqq]]]]]]]]]]]]]]curre
    nt time"
    80 print "]]]]]]]]]]]]]]]]";
    90 print a$
    100 goto 20
    200 rem print a box
    210 print chr$(19)
    220 print "qqqqqqqqqq]]]]]]]]]]]]]UCCCCC
    CCCCCCCI"
    230 print "]]]]]]]]]]]]]B]]]]]]]]]]]]B"
    240 print "]]]]]]]]]]]]]B]]]]]]]]]]]]B"
    250 print "]]]]]]]]]]]]]JCCCCCCCCCCCCK"
    299 return

    Many of the characters that appear in this listing are cursor control characters and appear in reverse in the video. They either position the cursor or print PETSCII graphics.

    Inspired by David’s video, in which he connects an LCD screen to his C64’s User Port: https://www.youtube.com/watch?v=vV8FbwobrKY





     
  • Jay Versluis 9:51 am on March 27, 2018 Permalink | Reply
    Tags: ,   

    Categories: Commodore, Screencast ( 87 )   

    How to create random YouTube URLs in Commodore BASIC v2 

    In this episode I’ll demonstrate how to create those seemingly random YouTube Video IDs using a Commodore 64.

    Here’s the code I’m writing – works in BASIC v2 and above:

    10 print chr$(14)
    20 gosub 100:x=rnd(-ti):cn=1
    30 a$="https://youtu.be/"
    40 for i=1 to 11
    50 rn=int(rnd(0)*62)+1
    60 a$=a$+yt$(rn)
    70 next
    80 print:print cn;" : ";a$
    85 cn=cn+1
    90 goto 30
    85 cn=cn+1
    90 goto 30
    
    100 rem populate array
    110 dim yt$(62)
    120 i=1
    130 for j=65 to 90
    140 yt$(i)=chr$(j)
    150 i=i+1
    160 next j
    170 for j=193 to 218
    180 yt$(i)=chr$(j)
    190 i=i+1
    200 next j
    210 for j=48 to 57
    220 yt$(i)=chr$(j)
    230 i=i+1
    240 next j
    299 return

    The first line switches to lower case letters (I forgot to show that in the video).

    NOTE: In addition to the upper case and lower case alphabet, and the numbers 0-9, YouTube also use two special characters that I forgot to mention in the video. One is the standard minus sign (-), and the other one is the underscore (_). The Commodore machines cannot produce the latter. For simplicity’s sake, I’ve left both of those out (just though I’d mention it here).

    Inspired by Tom Scott’s video “Will YouTube ever run out of Video IDs” – watch it here: https://www.youtube.com/watch?v=gocwRvLhDf8





     
  • Jay Versluis 11:43 am on March 14, 2018 Permalink | Reply
    Tags: , , , VIC-20   

    Categories: Commodore   

    String Operations on Commodore Computers 

    Commodore BASIC has some interesting and simple string functions built in. Three of them are self explanatory: LEN, LEFT$ and RIGHT$. But others, like the mysterious MID$ and INSTR functions, are a little tricker, and I can never remember how they works.

    So here’s a quick recap on how they all work.

    LEN (A$)

    Returns the length of any given string. For example,

    a$=”the cake is a lie”

    print len (a$)
    17

    returns 17, which is the number of characters in our string.

    LEFT$ (A$,X)

    The LEFT$ function takes the x left characters from a given string. Here’s an example:

    a$="one-two-three"
    
    print left$(a$,3)
    one

    We get “one”, because those are the 3 leftmost characters in our string a$.

    RIGHT$ (A$,X)

    Likewise, RIGHT$ takes the x right characters from any given string:

    a$="one-two-three"
    
    print right$(a$,5)
    three

    Here we get “three”, because those are the 5 right characters of a$.

    MID$ (A$,X,Y)

    MID$ is a little more complex. It takes x characters from a given string, starting at position y. Let’s look at our earlier example again:

    a$="one-two-three"
    
    print mid$(a$,5,3)
    two

    We get “two”, because those are the 3 characters, starting at position 5. The first position in all these string operations counts as one rather than zero.

    But did you know that MID$ can also be used to assign and replace different characters in a string? Consider this:

    mid$(a$,5,3)="ten"
    
    print a$
    one-ten-three

    Now we’ve replaced the 3 characters in our string with another string, starting at position 5.

    I had no idea it cold do that! All these string operations work in all variations of the Commodore BASIC, except for the MID$ assignment which only works on the Plus/4 and the C128.

     

    INSTR (A$, B$)

    On the Plus/4 and C128, we can even check if one string is contained in another and at which position this occurs. Consider this:

    a$="the cake is a lie"
    
    b$="cake"
    
    print instr(a$,b$)
     5

    In our example, INSTR returns 5 because “cake” has been found at position 5 of “the cake is a lie”.

    We can also specify a position from which the search shall be started like this:

    print instr(a$,b$,6)
     0

    Now INSTR returns 0 because “cake” has not been found beyond position 6 of our input string.





     
  • Jay Versluis 11:04 pm on March 13, 2018 Permalink | Reply
    Tags:   

    Categories: Commodore   

    How to play sounds and music on the Commodore Plus/4 

    The Plus/4 has a total of two voices thanks to its integrated TED chip, which is also responsible for rendering text and graphics on screen. The first voice can play square waves, while the second one can generate either square wave sounds or white noise.

    Let’s see how we can make him play a tune.

    We can use some BASIC keywords to make the Plus/4 be all musical. First we need to turn up the volume by using the VOL command. We can set this to anything between 0 and 8.

    VOL 8

    Next we can use the SOUND command to make each channel play a note, like so:

    SOUND 1,400,60

    This will play a one-second long note on channel 1.

    (More …)





     
  • Jay Versluis 5:16 pm on January 13, 2016 Permalink | Reply
    Tags: , ,   

    Categories: Commodore   

    How to use direct block access commands in Commodore DOS 

    Commodore-Logo-PaddedWe can access each sector’s raw data on Commodore disk drives with direct block access commands. Supported drives include the 1541, 1571, the VICE emulator as well as the SD2IEC card reader (for the most part).

    Each single sided floppy contains 35 sectors, while a double sided 1571 formatted disk contains 70 sectors. Each track contains between 17 and 21 sectors depending on how far inside or outside they are. Each sector contains 255 bytes we can read or write.

    Sectors are the same as blocks: only the directory refers to them as “blocks” and shows us how many we have available.

    We’ll need to open two channels to our disk drives: a command channel and a data channel. Here’s how to do it:
    (More …)





     
  • Jay Versluis 9:17 am on January 2, 2016 Permalink | Reply
    Tags:   

    Categories: Commodore   

    How to save data to your C128 RAM Expansion Unit (REU) 

    Commodore-Logo-PaddedWith a RAM Expansion Unit (REU), the Commodore 128 could address up to 512k of data. That was huge in the late eighties! All you needed was one of those REUs, plug it into your cartridge port, and so much more super fast memory was at your fingertips.

    But even with such a cartridge at hand, how do we actually make use of it from CBM BASIC 7.0? With three funky commands called STASH, FETCH and SWAP. Here’s how we can use them.

    The REUs cannot be addressed directly, like other memory in your computer. Instead, data has to be either copied from the C128 to the REU, or vice versa, or swapped out. All three commands take the same four parameters:

    • number of bytes to transfer
    • location in the C128 memory to start
    • REU bank (0-7, depending on the size of the REU)
    • location in the REU bank memory

    This sounds more cryptic than it actually is: the largest REU split 512k over 8 banks of 64k, so that the 8bit operating system could address it.

    So to store 200 bytes of C128 memory, starting at location 5000, saving it inside the REU’s bank 0, location 0, we can use the STASH command like so:

    STASH 200,3000,0,0
    

    To retrieve our data later and bring it back to the same C128 location as before, we can use FETCH with the same parameters:

    FETCH 200,3000,0,0
    

    Rather than copying, we can also exchange data in two places by literally swapping it over. Again the parameters are the same:

    SWAP 200,3000,0,0
    

    Enabling REUs in VICE

    Although I have a physical C128, I do not have a real REU. Maybe one day I’ll find one on eBay, but until then there’s an easy way to emulate an REU using VICE.

    To enable one, head over to Settings – Resource Inspector – Cartridges – REU. Pick the size you like, and even a hard disk location to make the contents of your REU survive restarts.

    Screen Shot 2016-01-02 at 09.08.35

    Screen Shot 2016-01-02 at 09.09.19

    Demo Listing

    Here’s a quick test that allows us to store an arbitrary message in memory, then stash or retrieve it from an attached REU.

    100 print "1 store message in internal memory"
    110 print "2 print message"
    120 print "3 stash message in reu"
    130 print "4 retrieve message from reu"
    140 print "5 clear internal memory"
    141 print "6 quit"
    150 input "your choice";m
    160 on m gosub 1010,1090,1210,1410,1310,2000
    170 run
    1000 :
    1010 rem input and save
    1020 input "what shall we store";a$
    1030 for i=1 to len(a$)
    1040 c$=mid$(a$,i,1)
    1050 poke 3000+i,asc(c$)
    1060 next
    1070 return
    1080 :
    1090 rem retrieve message
    1100 print:print "retrieving..."
    1110 for i=1 to 100
    1120 c=peek(3000+i)
    1130 b$=b$+chr$(c)
    1140 next
    1150 print b$
    1160 return
    1200 :
    1210 rem stash to reu
    1220 stash 200,3000,0,0
    1230 return
    1300 :
    1310 rem clear internal memory
    1320 for i=1 to 200
    1330 poke 3000+i,0
    1340 next
    1350 return
    1400 :
    1410 rem retrieve from reu
    1420 fetch 200,3000,0,0
    1430 return
    2000 :
    2010 rem the end
    2020 end
    

    We don’t see many BASIC listings these days anymore. Enjoy!





     
  • Jay Versluis 5:58 pm on December 27, 2015 Permalink | Reply
    Tags:   

    Categories: Commodore   

    How to create relative data files on your Commodore 128 

    Commodore-Logo-PaddedThe CBM DOS can write “relative data” onto disk, based on individual records. The advantage is that all space is allocated once and then randomly accessed if and when it’s needed – much like the tracks on a CD.

    This approach is different from sequential files, which have to read or write the whole file in one go (Apple call this “reading and writing atomically”). So finding the 50th record in a sequential file can take some time, whereas retrieving record 50 from a relative file is just as fast as retrieving record 1 or record 157.

    Let’s see how we can deal with such relative files in CBM BASIC 7.0. This works with all physical disk drives (1541, 1571, etc) as well as the SD2IEC card reader – but not with your trusty old Datasette (for obvious reasons).

    This was revolutionary back in 1982!

    Creating Relative Files

    Here we create a new file with a REL extension using the DOPEN# keyword. When we do this for the first time, we need to tell the operating system how much data we’d like to allocate per record. Anything up to 255 bytes is fine. We’ll use 100 bytes in this example (the letter L followed by the length).

    10 dopen#1,"rel test",l100
    20 for i=1 to 100
    30 record#1,i
    40 a$="record"+str$(i)
    45 print "writing record ";i
    50 print#1,a$
    60 next
    70 close 1
    80 print "all done!"
    

    When we create a new file, CBM DOS doesn’t know how many records we’ll need, but it will create as many as necessary on the file. Here we create 100 entries using a for loop and write them to disk using the PRINT# statement.

    Notice that before saving a record, we must position the record pointer using RECORD#. That’s how our data is written to the correct position on disk. The whole loop will take a while to complete, but all space will be allocated on the disk as soon as we CLOSE the file.

    To add more records, we’ll simply position the record pointer to a later entry – even if one does not yet exist. CBM DOS will create the last record and all records leading up to it so they can be used later, up to a maximum of 65535 (space permitting obviously).

    Reading data from Relative Files

    Much like with sequential data, we can either use INPUT# or GET# to grab the data for an individual record. INPUT# reads everything until a CHR$(13) is found and works much faster, while GET# reads data one character at a time and is a lot slower.

    10 input"which record shall we retrieve";r$
    20 dopen#1,"rel test"
    30 record#1,val(r$)
    40 input#1,a$
    50 close 1
    60 print:print a$:print
    70 print"need another one? (y/n)"
    80 getkey k$:if k$="y" then goto 10:else end
    

    Here we ask the user which record we want to retrieve. Next we open our relative file using DOPEN#, position to the desired RECORD# and then read in its value using INPUT#. When we’re done we close the file and ask if the user wants to retrieve another record.

    While this type of data access is quick and convenient, it doesn’t help much unless you know which record is stored at which position. Think of an address book application: to find “Johnny Appleseed” can’t be done unless you sift through every single record until you find him.

    Commodore therefore suggest to use sequential files alongside relative files, in which things like a last name could be saved together with the record number. Likewise, another sequential file could hold all records for the first names, and appended accordingly when a new record is created, or replaced when updated.





     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel