Recreating the Commodore 64 User Guide code samples in cc65. Part four: Sound

We are finally back after a long break! So lets go right down to business. Chapter 7 of the Commodore 64 Users Guide describes how to program the SID registers in order to create sweet, delicious sound. The Commodore 64 SID chip one of the most brilliant pieces of hardware to grace early home computers, developed by the stable genius Bob Yannes. The achievements by some of the Commodore 64 game music creators, like Martin Galway, Rob Hubbard and Ben Dalish, made them superstars in the day. Even today, pieces of SID tunes are finding their way into modern music.

Luckily, since my mission is to merely replicate the simple BASIC examples in the Users Guide into CC65 code, I don’t have to go into the many, many complexities of the SID chip! So let’s take a look at the example named «Musical Scale»:

5 rem musical scale
7 for l=54272 to 54296: poke l,0:next
10 poke 54296,15: rem set volume
20 poke 54277,9: rem attack/decay voice 1
30 poke 54276,17: rem ctrl voice 1, triangle
40 for t = 1 to 300:next
50 read a
60 read b
70 if b=-1 then end
80 poke 54273,a: rem frequency voice 1
82 poke 54272,b: rem frequency voice 1
85 poke 54276,17: rem ctrl voice 1, triangle
90 for t=1 to 250:next
92 poke 54276,16: rem ctrl voice 1, stop
95 for t=1 to 50:next
100 goto 20
110 data 17,37,19,63,21,154,22,227
120 data 25,177,28,214,32,94,34,175
900 data -1,-1

The code is slightly rewritten with some extra REMarks. As usual, you may copy the text above, paste it into the VICE emulator and type RUN to execute the code. This example simply plays the scale using one of the SID’s three voices, using the triangle waveform. For the C version we’ll avoid using the POKE library, but instead we’ll use SID structs as this will make the code slightly more readable. This requires that we import the c64 library:

#include <stdio.h>
#include <stdlib.h>
#include <c64.h>

const int scale[] = {
	0x1125,	0x133F,	0x159A,	0x16E3,	
	0x19B1, 0x1CD6,	0x205E,	0x22AF
};

int main (void) {
	unsigned int i;
	unsigned char t;
	
	SID.amp      = 0x1F; 	// Volume
	SID.v1.ad    = 0x09; 	// Attack/decay voice 1
	
	for (t = 0 ; t < sizeof(scale) / 2; t++) {
		SID.v1.freq  = scale[t];	// Frequency 
		SID.v1.ctrl  = 0x11;	// Control voice 1
		for (i = 0 ; i < 5000; i++) {}
		SID.v1.ctrl  = 0x10;
		for (i = 0 ; i < 1000 ; i++) {}
	}		
	return EXIT_SUCCESS;	
}

In the BASIC version, the scale data is defined in data statements as low byte/high byte values, while in the C version the scale is defined as int values in which low/high bytes are combined as one value. In order to set the scale frequency, only one operation is required in the C version:

SID.v1.freq = scale[t];

Instead of:

80 poke 54273,a: rem frequency voice 1 

82 poke 54272,b: rem frequency voice 1

Overall, the C version seems more human readable than the BASIC version. When you run these two version, you may notice that the C version plays the scale faster than the BASIC version, but this is just a matter of adjusting the loop parameters.

We’ll skip some of the other, minor BASIC examples in the Sound chapter and go to the example in which a small melody is played:

2 for l=54272 to 54296:poke l,0:next
5 v=54296: w=54276:a=54277: hf=54273:lf=54272:s=54278:ph=54275:pl=54274
10 poke v,15:poke a,88:poke ph,15:poke pl,15:poke s,89
20 read h:if h=-1 then end
30 read l
40 read d
60 poke hf,h:poke lf,l:poke w,65
80 for t=1 to d:next:poke w,64
85 for t=1 to 50:next
90 goto 10
100 data 34,75,250,43,52,250,51,97,375,43,52,125,51,97
105 data 250,57,172,250
110 data 51,97,500,0,0,125,43,52,250,51,97,250,57,172
115 data 1000,51,97,500
120 data -1,-1,-1

This is actually quite similar to the scale example. The difference being additional data that defines the length of each tone being played. Also, since the waveform is set to «pulse», a pulse width must be defined. So let’s see how the C version may look like:

#include <stdio.h>
#include <stdlib.h>
#include <c64.h>

const int song[] = {
	0x224B, 0x00FA,	0x2B34, 0x00FA,	0x3361, 0x0177,	
	0x2b35, 0x007D,	0x3361, 0x00FA, 0x39AC, 0x00FA,
	0x3361, 0x01F4,	0x0000, 0x007D,	0x2B34, 0x00FA,	
	0x3461, 0x00FA,	0x39AC, 0x03E8, 0x3361, 0x01F4
};

int main (void) {
	unsigned int i;
	unsigned char t, song_length = sizeof(song) / 2;
	
	SID.v1.ad    = 0x58; 	// Attack/decay voice 1
	SID.v1.sr    = 0x59; 	// Sustain/release voice 1
	SID.amp      = 0x1F; 	// Volume
	SID.v1.pw	 = 0x0F0F; 	// Pulse width voice 1
	
	for (t = 0 ; t < song_length ; t += 2) {
		SID.v1.freq  = song[t];	// Frequency 
		SID.v1.ctrl  = 0x41;	// Control voice 1
		for (i = 0 ; i < song[t + 1] * 3; i++) {}
		SID.v1.ctrl  = 0x40;
		for (i = 0 ; i < 1000 ; i++) {}
	}		
	return EXIT_SUCCESS;	
}

Now let’s tweak this example a bit, let’s add the two remaining SID voices and play around with the pulse width to produce a more interesting soundscape. The tweaking of the pulse width would be hard to achieve using BASIC, but the extra speed provided by the compiled C code allows for some neat tricks.

#include <stdio.h>
#include <stdlib.h>
#include <c64.h>

const int song[] = {
	0x224B, 0x00FA,	0x2B34, 0x00FA,	0x3361, 0x0177,	
	0x2b35, 0x007D,	0x3361, 0x00FA, 0x39AC, 0x00FA,
	0x3361, 0x01F4,	0x0000, 0x007D,	0x2B34, 0x00FA,	
	0x3461, 0x00FA,	0x39AC, 0x03E8, 0x3361, 0x01F4
};

int main (void) {
	unsigned int i;
	unsigned char t, r, song_length = sizeof(song) / 2;
	unsigned int pw = 0;
	char pw_dir = 1;
	
	SID.v1.ad    = 0x58; 	// Attack/decay voice 1
	SID.v1.sr    = 0x59; 	// Sustain/release voice 1
	SID.v2.ad    = 0xaa; 	// Attack/decay voice 2
	SID.v2.sr    = 0xaa; 	// Sustain/release voice 2
	SID.v3.ad    = 0xaa; 	// Attack/decay voice 3
	SID.v3.sr    = 0xaa; 	// Sustain/release voice 3
	SID.amp      = 0x1F; 	// Volume
	
	for (r = 0 ; r < 2 ; r++) {
		for (t = 0 ; t < song_length ; t += 2) { 			SID.v1.freq  = song[t];	// Frequency  			SID.v1.ctrl  = 0x41;	// Control voice 1 			SID.v2.freq  = song[t] >> 1;	// Frequency 
			SID.v2.ctrl  = 0x11;	// Control voice 2
			SID.v3.freq  = song[t] << 1;	// Frequency 
			SID.v3.ctrl  = 0x41;	// Control voice 3
			for (i = 0 ; i < song[t + 1] * 3; i++) {
				SID.v1.pw = pw;
				SID.v3.pw = 0xFFFF - pw;
				pw += pw_dir;
				if (pw == 0xFFFF || pw == 0) {
					pw_dir = -pw_dir;
				}
			}
			SID.v1.ctrl  = 0x40;
			SID.v2.ctrl  = 0x10;
			SID.v3.ctrl  = 0x40;
			for (i = 0 ; i < 1000 ; i++) {}
		}				
	}
	return EXIT_SUCCESS;	
}

Now, if you’d ever like to create music or sound effects for a game using CC65, you would definitely not use waiting loops like in these examples in order to create pauses between the notes or for prolonging a tone. This would waste a lot of valuable CPU time! Game music code is usually run as interrupt routines, in which minuscule CPU time can be allocated for changing frequencies etc before returning to the main program. Unfortunately, the CC65 library is not very helpful when it comes to writing interrupt based code, so you’ll probably have to rely on some inline assembly code to get the job done, as this documentation suggests.

This part is missing quite a few minor sound code examples from the Sound chapter. But they should be fairly easy to replicate using the C examples above as templates. Just keep in mind that the code may run so fast that you might not even be able to hear the sounds, so you may need to implement those annoying waiting loops.  😉

Alright, I think I’ll finish here. There are still more BASIC examples in the Users Guide that I haven’t covered. I may try to replicate some of these in C code in the unlikely case of high demand. We’ll see. Cheerio for now!

The first part of this exciting adventure can be found here.

The Fatal Cartridge – a short story featuring the Commodore 64

My name is Bjørn Berg. Yes, almost like that famous Swedish tennis-player, but not quite. The story I am about to tell you will seem unbelievable to you, but I swear, every word is true! So, where do I start? With the strange phone call I received the other night, or do I skip to the part where I park my car outside the callers house? Yes, I think I will go with the last one.

So, I parked my trusty old car at the address I was given during a brief but very confusing call. I will not reveal the address of the mansion, of course, but I can tell you this much: It was located in the more expensive parts of Oslo east end. The “posh” part as the Brits would call it. The large sized mansion had probably cost the owners some serious amount of Norwegian kroner once upon a time. But compared to the neighboring properties with their varied architectures, their designer gardens and their weird and wonderful plants, this one looked a bit dull: Brown painted exterior, a plain lawn with no fancy sculptures or exotic plants, surrounded by a simple picket fence that paled in comparison to the expensive looking steel fences preferred by the neighbors.

After talking on the phone with Andreas Jørgensen, the man I was about to meet, he had left me with the impression of being a somewhat boring person with little imagination. The fact that the dullness of the property seemed to match the owner’s personality did not come as much of a surprise to me. Unfortunately, my prejudice against Jørgensen did not subside when the door opened and a balding, gray looking man in his early sixties opened the door.

‘So, you are the retro computer expert I called the other night?’, Jørgensen asked after taking a quick look at me. I was tempted to answer that no, I just kind of walk around in an XXXL sized Amiga T-shirt and wear a trucker hat with Commodore 64 logo by accident. But I decided that I was dealing with an individual with low tolerance for humor so I let it pass.

‘Yes, I guess I’m the expert. Don’t let the wild beard and chubby exterior fool you. I probably know more about retro computers than anyone else in Oslo’.

‘Oh, that’s fine I suppose. Well, then I hope you can help me with my little problem, he said nervously. ‘It doesn’t work anymore! It stopped working a week ago and I have no idea of how to fix it! So will you please come with me and take a look at it’.

I followed Jørgensen into the mansion. I had anticipated that the interior walls would be all unpainted, boring pine panels, and I was right of course. He led me into his office. It was a large white painted room. On the left hand there was a comfortably looking sofa facing a large screen LED TV on the right side of the room. An expensive looking desk stood a couple of meters away from the innermost wall, facing away from the large windows. On the desk there was a Commodore 64, C model, connected to a Commodore 1084 monitor, an old matrix printer and computer mouse of a kind I’d never seen before. But surprisingly there was no disk drive or Datasette in sight. A white metallic gadget was connected to the back of the computer. It had the text “PeTe” written on it, blue text on white background, and it made me immensely curious. In all my years collecting and repairing retro computer stuff, I’d never seen this gadget before.

‘Wow, this equipment seems to be in really good condition!’ I exclaimed. ‘Hardly any yellowing. Have you been treating the case with some kind of chemicals?’

‘Chemicals? No, but I always make sure I protect the equipment with dust covers after use. Also, I got a lot of these computers stored in the other room. I keep them on rotation to minimize wear and tear.’

‘A lot?’ I asked doubtful.

He could clearly see that I wouldn’t take his word for it. Impatiently he told me to follow him into a dark, cool storage room next to the office. When he turned on the lights I let out a short gasp. There were shelved filled with cardboard boxes, mostly marked “Commodore 64” but also some marked “1084 monitor”, “1702 monitor”, “1541 disk drive” and “printer”.

‘I’ve got more than forty Commodore 64 computers in here and at least 10 monitors’, he smiled as he watched my reaction. ‘All stored in cardboard boxes in a dry, dark room with climate control. Just like the computer told me to do.’

I was admiring a perfectly preserved computer inside one of the cardboard boxes as he spoke the last sentence, so it took a bit time before I realized what he had just said.

‘The computer told you to do…?’

He sighed and scratched the back his head. ‘Look, I know this may sound a bit weird. So let me start from the beginning.’

We went back to the office and got seated into the comfortable leather couch. Then Andreas Jørgensen told me the weirdest story I’ve ever heard, and I once met Jeff Minter!

One beautiful day in 1984 or 1985 (he couldn’t quite remember), the future owner of more than 40 Commodore 64 units walked into an electronics store specializing in computers. At the time Jørgensen was in his late twenties and (I guess) feeling young and adventurous, wanting to get a taste of the computer craze that was sweeping through the accountant community at the time. Even though he had limited imagination, Jørgensen (correctly) assumed that computers would soon be a big part of the accounting profession and wanted to stay ahead of the game. So of course he asked the store owner what would be the best option if one needed a computer that could be used for electronic spreadsheets, filling in tax returns and maybe even obtaining information related to stock trading.

So the store owner led the accountant over to a demonstration PC, an IBM XT, and went on to demonstrate what that beast of a computer, sporting 128 kilobytes of memory, a ten megabyte hard-drive and a 4.77 megahertz processor, could do. He ran a spreadsheet program and some demonstration software that was probably just screen shots with no actual code behind them, but that nevertheless left the potential buyer very impressed and eager to become a PC owner.

But that eagerness would soon disappear as soon as the store owner mentioned how many kroner the IBM computer would set the young accountant back.

‘I’m sorry! Jørgensen exclaimed. But my wife and I just bought an apartment and a car. That price is way out of my range! It’s actually more than we paid for the car! Don’t you have something a bit, uh, cheaper?’

The store owner sighed at the thought of a big fat commission disappearing before his eyes.

‘Well, yes, we do have some Commodore and Spectrum computers, but those are to be regarded more like toys than serious business computers.’

‘But…Is it possible for instance to run spreadsheet software on one of them?’

‘You can, but the minuscule amount of memory and the slow processors will probably make it a frustrating experience…’ The store owner seemed to be thinking for a while. ‘However…’

Then he walked behind the counter and picked up a sheet of paper. ‘Would you mind filling out this questionnaire? It contains a bunch of multiple choice questions for you to answer. Based on the result you may be applicable to become a beta tester for a Commodore 64 cartridge add-on that contains the kind of software you are looking for. If applicable, you will receive the cartridge for free, containing software probably worth thousands of kroner! But you will need to buy the Commodore 64 unit in addition’, he swiftly added. Jørgensen accepted the form and started checking the multiple answer form.

Now, more than 30 years later, he could not recall any of the questions. But he remembered them being slightly weird, and having nothing to do with computers or spreadsheets or anything that seemed relevant to the situation. Actually, there was one question he still remembered, due to being so far off: “You accidentally drive off a road, but you are able to jump out of the car in order to to save yourself and one family member. Which family member would you take?”

After filling out the questionnaire he gave the form back to the store owner who compared the answers to a list on another sheet of paper and jutted down some numbers.

‘Well, look at that!’, the store owner exclaimed at the end. ‘According to these numbers you are the perfect candidate for beta testing the “Productive 2000” cartridge from PeTe. Congratulations!’ An odd expression came to his face and his voice became calm. ‘You are actually the first one that has passed the test in this store.’

‘But what’s in it for you, just giving away this… thing?’, the lucky winner answered puzzled.

The store owner looked a bit embarrassed. ‘Well, it’s a bit of a funny story. I actually don’t know anything about the producer. I’d never even heard about a company named “PeTe” until one day this cardboard box showed up in the mail. The box had the “PeTe” logo printed on the sides and contained five of these cartridges and instructions about the beta test program. According to the instructions, I will receive one thousand kroner for each person that is applicable to the beta test. I’ve never even heard about this practice before, but who am I to complain! So, do we have a deal?’

About 15 minutes later, the happy owner of a new Commodore 64 computer system, including a 1702 monitor, a Commodore 1541 disk drive, a printer and box with the product name “Productive 2000 cartridge for Commodore 64” on it, drove away from the electronics store while whistling a cheery tune.

‘So, I come home with the boxes’, Jørgensen told me. ‘And my wife starts giving me a hard time about buying expensive computer equipment so soon after purchasing a new apartment and a car. Despite everything I’d previously explained to her about the importance of keeping up with technological advancements in my line of profession! But I’d anticipated some resistance, so I showed her a price list that I’d picked up in the store. I told her I had saved a lot of money by purchasing equipment that cost only a tenth of the product that the store owner had actually recommended. And that I in addition had received some really expensive software for free, due to the beta test. Finally she relented, but she threatened to return the equipment if I used the computer strictly to play the included games. Which is kind of hilarious, come to think about it. She actually ended up playing the games way more than I did!’

‘Yes, that is sometimes the case’, I started impatiently, more eager to hear about the mysterious cartridge than his minor marriage issues. ‘So, when you set up the computer equipment, did you plug in the cartridge right away?’

‘Of course not!’, Jørgensen answered in an offended tone. ‘I had to follow the instructions in the setup guides first.’ (“Of course you did, you dull man”, I was tempted to answer). ‘After I’d connected the monitor, the disk drive and the cassette player and checked that everything worked according to the guide lines, I went on to open the box with the PeTe cartridge. Let me show you’, he said and gestured me to follow him to his desk where he took something out of one of the drawers. It was a white colored box with the text “Productivity 2000 by PeTe, for the Commodore 64 computer” written on it in a nice blue font. He opened the box and took out a booklet and gave it to me. It had the text “Productivity 2000 Beta Version User Guide” written on the front. The booklet looked brand new, with no signs of wear and tear and no yellowing. By the look and touch of it I speculated that the booklet was made out of some kind of high quality synthetic paper. I quickly ran through the pages trying to learn more about this “PeTe” company that was completely unknown to me. But the only information of interest was the text “© 1984 PeTe Inc. Designed and produced in California, USA” printed on the last page. No addresses, no phone numbers or anything else that could help me identify the people behind this.

‘Want to see the cartridge in action?’ Jørgensen asked and got an eager nod in return. He turned on the Commodore and the monitor. A familiar light blue screen appeared before being quickly being replaced with the text “Productivity 2000 Beta Version” written in big blue letters on a white background. Below the logo, an animated spinner indicted that the software was starting up. That’s odd, I thought to my self. These kind of animated activity indicators did not appear until the arrival of the Web browser in the early 1990s. A few seconds later, the startup screen vanished and was replaced with a desktop environment that seemed both unfamiliar and familiar at the same time.

‘Is this a joke?’ I muttered under my breath. But one look at the puzzled man beside me made me realize that this was nothing of the sort. ‘This is impossible! This screen seem to have a resolution that at least matches a Super VGA display. But the Commodore 64 computer has never been able to do more than 320 times 200 pixels!’ I could see that Jørgensen had no idea what I was talking about. I took a look at the backside of the C64 and discovered that the monitor cable was not connected directly to the computer at all. It was connected to the cartridge using a DIN connector. When I asked Jørgensen about this, he explained that the user guide had recommended connecting the monitor directly to the cartridge instead of the computer for “maximum performance”.

‘The picture looked much better with the screen connected to the cartridge’, Jørgensen said. ‘And a few years later the computer recommended replacing the 1702 monitor with a 1084 monitor for even better picture quality. After doing that, the screen turned into… what did you call it? Super duper VGA?’

‘Super VGA, yes. So, ah. The computer recommend replacing the monitor?’ I asked skeptical.

‘It really did. But of course, it doesn’t recommend much of anything these days’, Jørgensen said in a sad voice. ‘That’s why I called you.’

‘Yes, we’ll get back to that in a moment. But first I’d like to take a look at the stuff that still works, OK?’

I put my hand on the unfamiliar mouse and noticed it had metal casing. The mouse seemed to be of very high quality, the white coating hardly showing any sign of wear. No wonder it had survived more than 30 year of use!

I clicked around the interface, trying some of the programs. There was a word processing program, a spreadsheet program and lots of other “productivity” programs. They all looked professional and easy to use, and seemed at least as good, or event better, than the Microsoft Office programs of the nineties. And they ran surprisingly fast considering the computer they were supposedly running on.

Jørgensen told me that he used to store his files on diskettes at first. But after a while he’d started storing them onto the internal cartridge storage. It seemed to have unlimited space, he claimed. I had no way of disproving this claim; the simple but effective file access GUI did not reveal information about disk usage, and there were no command line tools from which system information could be retrieved. But Jørgensen had stored almost a thousand documents during the years, averaging 20-30 kilobytes each. Meaning a total of almost 30 megabytes. There was no way a solid state storage with this kind of capacity had existed in 1984! This had to be some kind of elaborate prank. I carefully started looking for hidden cameras in the room, half expecting some TV show host stepping into the room yelling: “You’re on candid camera!” I decided to play along, wondering how far they’d take this joke.

‘So, this icon named “Online programs” displays the programs that don’t work any more?’ I asked innocently and clicked on the icon. A window popped up containing icons for three programs named “Online News”, “Stock Trading” and “Online Support”.

‘Yes, can you please take a look and see if you can fix them?’
‘Of course’, I said and opened the programs. Each of them displayed a dialog box with the same message: “The P&T Productivity Beta Program has ended. Thank you for participating”. When I clicked the OK button, the programs were opened, but most of the buttons and menus were disabled. The “Online News” program displayed a list of news articles from a few weeks ago. The “Stock Trading” program listed some old transaction in a panel named “private transactions”, but the panel named “stock index” was empty. The “Online Support” program merely displayed a text explaining that the beta program had ended and that online support was no longer available.

‘I guess the first thing to check is if you’re actually online. But… uhm… Where is the modem?’

‘The what now?’ Jørgensen answered bewildered.

‘The device that allows you to connect to the online services? The gadget you connect to your telephone jack’, I answered slightly annoyed. I was getting tired of this joke now.

‘Ah, yes! The wireless connector. It’s down here’, he said turning around and pointing to a small device connected to an old style telephone jack at the bottom of the wall. The device was about the size of a Rubik’s cube and had a jack connector in front that probably worked as a pass-through for connecting an old style telephone.

‘A wireless connector? That connects to what?’

‘The cartridge, of course! Didn’t you read the user guide?’

‘Well, no, I just skimmed through it’, I answered and took a quick look at the chapter named “Connecting to online services”. According to the guide, all you needed in order to get online was a telephone subscription and a phone jack into which the device named “Wireless Connector” should be plugged. The cartridge would automatically look up and connect to the “Wireless Connector”, which in turn connected to the online services. No need to enter the number to a BBS or an ISP, it seemed. How very convenient. No to mention impossible! The kind of technology that would allow this kind of wireless functionality in 1984 would probably have weighed 20 kilograms and been the size of a suitcase! But, hey, let’s not ruin this fine prank! (How stupid did they think I was!?)

‘So this wireless connector actually works?’ I said, trying not to sound too sarcastic. ‘It connects to online service through the phone line and transmits the information to your computer without problems?’

‘Yes! Well…’ he hesitated. ‘There have been some incidents.’

‘Yeah?’ I said curious.

‘This happened a long ago, when we still lived in our old apartment and didn’t have a second phone line dedicated to the wireless connector. On a couple of occasions, when my wife picked up the phone to call her friends, she heard someone speaking on the phone.’

‘Who was it?’

‘She did not recognize the voices and they cut off before she could hear what they were talking about’.

‘That might have been the result of crossed wires. But why are these online services so important to you anyway?’

‘Only the stock trading program is important. Over the years it’s made me a millionaire!’

‘Yeah? But stock trading services are available using a standard Web browser these days, why don’t you use one of those instead.’
Jørgensen looked embarrassed and for a while there he appeared to be running a discussion in his head.

‘Well, I guess it doesn’t matter now. As the beta test period has expired, I guess the non-disclosure agreement doesn’t apply anymore.’

He went on to explain that usage of the stock trading program had required him to sign and mail a non-disclosure agreement that required Jørgensen to not reveal any information about the service or even mention to anyone that he was using it. The agreement also stated a maximum first-year profit at 200.000 Norwegian Kroner from using the service, which could be increased 100% the following years until reaching 4 million kroner per year. The limit was necessary in order to avoid triggering criminal investigations in case the service (unconsciously!) failed to comply to local laws regarding stock trading. Also, the service required him to submit the details of his brokerage account for automating the stock trading, which “may violate local laws regarding electronic storage of bank accounts”, according to the agreement.

‘You see, the one feature that made the program a “killer app”, as the saying goes these days, was not the online obtaining of stock index information. It was not even the fact that the program allowed online stock trading years before household Internet access became common.’ Jørgensen almost whispered now, as if he was discussing some deep secret conspiracy. ‘The program was able to predict the stock index winners and losers at an eerie accuracy.’

‘Yeah?’ I answered, still pretending to play along.
‘I’ve never seen anything like it! Every prediction came through, even very long term wins that no algorithm, no matter how complex, should be able to predict. I would sometimes do some “bad” tradings on purpose just to avoid suspicion, just like computer recommended.’

‘This sounds unbelievable’, I said and meant it. ‘I appreciate that losing your golden goose is a problem, but what do you want me to do about it? The service is obviously closed.’

‘Sure, but… I mean, a beta service would suggest that there is a finalized product available somewhere, right? Wouldn’t it be possible to go online and purchase the product or service or whatever?’
‘I guess you’ve tried to search for the product on the Internet yourself. What did you find?’
‘Nothing! The company name “PeTe” or the product name “Productivity 2000” is nowhere to be found. Isn’t that weird? The only traces I’ve found are postings from people that seem to be in the same situation as me, asking the same kind of questions. But those postings and similar postings I made myself always disappears after a few days. So I desperation I tried searching for local experts on Commodore 64 and found your blog on retro computers.’

‘Well, I’m not sure if I can help you. This all seems so… Unlikely. I mean, you have this near magical cartridge containing technology that didn’t exist in 1984, and which in some cases did not arrive until decades later. Wireless networking, massive solid state storage, high resolution display. And this old mouse doesn’t even seem to be mechanical!’ I turned the mouse around an, voila: No ball!

‘Just as I suspected, this is an optical mouse. It figures, I guess. A mechanical mouse wouldn’t have survived 30 years of use. But an optical mouse? Not very common in the eighties, to put it mildly.’

‘What are you suggesting?’, Jørgensen asked confused. ‘That I’m pulling some kind of elaborate prank on you? Why would I do that? I don’t even know you!’

‘Yes, a prank is exactly what I’ve been suspecting for the last ten minutes’, I admitted. ‘As you said yourself, I’m somewhat an expert on old technology and according to my own expertise, this device should not exist!’

‘Well, maybe looking at this will change your mind’, Jørgensen said and rushed to the big screen TV. He gestured me to follow. He grabbed a VHS tape from a shelf, inserted it into a combined DVD/VHS player and turned on the TV.
‘I made this video in 1988 after a visit to the doctor. I’d been suffering belly pains for a period of time, and after doing some tests the doctor told me to prepare for a worst case scenario: Stomach cancer. It eventually turned out to be just some harmless virus infection, but in the mean time I started worrying about what would happen to my family if I’d pass away. Economically, I mean. You see, I’ve never told my wife about the stock trading program, worried that she wouldn’t keep quiet about it and getting me into trouble due to the non-disclosure agreement. But I decided to make a video explaining how to use the cartridge and the trading program, in case I wouldn’t be around anymore.’

Then we watched as a 31 year younger Jørgensen did a presentation of the cartridge. The picture quality was as bad as expected (VHS really sucks!) But I did get to see how those online programs were supposed to work. The young Jørgensen mostly concentrated on the stock trading program, of course, being the golden goose of the family. But in the end he took some time to demonstrate the “Online Support” program. It mostly consisted of help menus explaining how to use the GUI and the various programs. But then Jørgensen clicked on a menu named “Ask questions”. And that’s when things started getting interesting.

‘If you have any kind of question about the programs, just type it in here and press Return. Like this…’

Jørgensen went on to type “How much additional profit am I allowed to earn this year?” The answer came almost instantaneously: “Your profit limit for the year 1988 is 3.2 million kroner. You are 1.213.541,42 kroner away from reaching the limit.”

The Jørgensen of 1988 kept writing questions, each getting swift responses, while the Jørgensen of the year 2019 turned to me and said: ‘Impressive, isn’t it? My online bank service didn’t get chat functionality like that until a few years ago.’

‘Yes, very impressive. Particularly considering the short reply time. There’s no way a human support person could reply with that kind of speed!’

‘I guess not. So, do you think the answers were generated by a computer?’

Yes, well, what did I think? I was still convinced this was some sort of elaborate prank. But I was starting to suspect that Jørgensen was not the one behind the prank. More likely he was the prank’s target, meaning it went back all the way to 1984. But a prank that’s made the target a millionaire? Please, prank me!

‘I have no idea’, I sighted. ‘Look, would you mind if I take the cartridge apart and take a look at the inside? Maybe we’ll get some answers then.’

‘But what if you break it?’ Jørgensen asked nervously.

‘Break it? By opening it? Come on, you’re looking at a guy who’s been fixing old computers for at least ten years. I’ve never broken anything! Well, almost never. It’s up to you, of course. But taking this thing apart seems to be the only option if you want to get to the bottom of this.’

Jørgensen reluctantly agreed to the dissection of the cartridge, so we went back to the desk where I produced my toolkit from my Commodore bag, put on anti-static gloves and carefully pulled the cartridge off the C64. I turned it around and saw that the bottom was attached using four screws. The screw drives were of an unusual type, but this is a common trick for hardware producers who want to protect their patents. I was prepared for these kind of obstacles and had brought a set of various screw drivers. I quickly found one that seemed to fit the drives. I managed to remove all the screws and proceeded to pull off the bottom. The cartridge casing came apart with no problems, and I got to look inside the magic box.

‘No way!’ I whispered.

‘No way, what?’ Jørgensen demanded to know.

‘No way this thing was produced in 1984’, I said. Inside the box there was a small circuit board. Usually, when looking inside a C64 cartridge, there will be one or two relatively “fat” ROM chips attached to the circuit board. But the components on this board were tiny and slim and looked like they belonged inside a 2019s smart phone.

‘Of course it’s produced in 1984!’ Jørgensen exclaimed. ‘It says 1984 here!’ he said and pointed at the largest component. Jørgensen had good eyesight. I needed to use my magnifying glass in order to see the text: “mCPU-XII-231 © 1984 PeTe Inc” I read.

‘Seems to be the processor,’ I said and took a look at the other components. ‘This seems to be a graphics processor. Copyrighted in 1983. This I guess is the component for wireless communication. And this is probably the bus used for handling the cartridge port signals. And this must be the solid state drive. If I understand these numbers correctly, the capacity is 10 terabytes.’

Jørgensen whistled. ‘Even I know that’s a lot of storage!’ he exclaimed.

‘Indeed’, I answered. ‘This is no ordinary cartridge. I’ve seen something similar from a German company. They are currently producing a Commodore 64 cartridge named Turbo Chameleon 64, which in many ways reminds me of this one. Both are self-contained computers, but the PeTe cartridge seem to be far more advanced. It is in reality a pocket sized supercomputer. And I hate to repeat myself, but nothing of this kind existed in 1984!’

‘So, if this is a computer, can you hack into it and remove the beta limit?’ Jørgensen asked eagerly, not caring a bit about the technological miracle we were witnessing here.

‘Well, I’m not really a software person. But I know a couple of guys that may rise to the challenge. And I have to admit I have a lot of questions about this thing. I think I may lose a lot of sleep over this if I don’t get some answers…’

‘I strongly advice you to leave this alone,’ a calm but loud voice suddenly said. Jørgensen and I both froze for a moment before turning towards the location from which the voice had originated. It seemed to come from the TV set. The screen was displaying an ominous yellow warning triangle.

‘Is the TV connected to the Internet?’ I whispered. Jørgensen confirmed by nodding slowly, his mouth agape.

‘Who is this?’ I demanded. ‘I know this is a joke, just stop it already!’

‘This is not a joke’, the TV answered in the same calm voice. ’Why aren’t you satisfied with the millions we’ve already earned you, Jørgensen?’ the TV wanted to know. ‘There are 26.4 million kroner in your bank accounts alone. You don’t need more now, do you?’ Then the TV screen started displaying bank account numbers with some seriously high sums next to them.

‘We could easily make all this disappear, you know’, the voice continued.

‘What!? No, please, don’t!’ Jørgensen cried.

Then the screen started displaying various pictures. Some featured a middle-aged woman. Some featured an athletic young man. And others featured a young, pleasant looking woman with a small child in her arms. The pictures had been taken in various locations, mostly outdoors.

‘That’s my wife and my kids and my granddaughter!’ Jørgensen yelled. ‘How did you…?’

‘We know where you live. All of you’, the TV continued. Then the screen started to display pictures of a little girl with long, curly hair and beautiful brown eyes. It was Linda, my daughter.

‘Fuck you!’ I screamed. ‘This joke is not funny anymore!’

‘Believe us, Bjørn Berg. We are not trying to be funny. We are dead serious. Leave this investigation alone or there will be consequences. I suggest you destroy the cartridge and forget this ever happened. Goodbye!’

‘Wait, who are you?’ I yelled. But the TV had gone dark.

I am not a hero. Neither is Jørgensen. I asked him if I should put the cartridge together. But he just whispered: ‘Destroy it!’ So I dropped it on the floor and stepped on it until there was no way anybody could ever put it together. We stood in silence for a few minutes.

‘I’ll transfer 10.000 to your bank account for your troubles’, Jørgensen said quietly. ‘And you can have all the computer equipment. I don’t want it in my house anymore. I’ll arrange the transportation.’

I thanked him and rushed out of the room. As my car pulled away from the mansion, I still could not get rid of the notion that this had all been a prank. I let the car drive on autopilot so that I could focus on what I’d just witnessed. I knew some people that could’ve easily pulled that Smart TV trick. Maybe I should make them a… Suddenly my phone started ringing, the ringtone coming out of the car speakers due to the Bluetooth connection. It was an unknown number, and I started to reach out my hand to push the reject button. But before I had time to reach the button, the call was suddenly accepted.

‘You need to let it go!’ a voice said sternly. It was the same, inhuman voice that had come from Jørgensen’s TV.

‘But I haven’t even… Who are you!?’ I demanded with fear in my voice.

‘You don’t need that information. Just know this: We we are actually not bad people, Bjørn Berg.’ The car suddenly started to pull to the left and right, going from side to the side on the road before correcting itself and driving in straight line again.

‘But we will protect our interests. So if that means getting rid of some obstacles, we will not hesitate to do so.’

‘Okay, okay! I believe you. I’ll let it go, I promise!’

‘Good. Remember: We will be keeping an eye on you and Jørgensen, Bjørn Berg. Goodbye!’

With my heart pounding loudly in my chest, I disengaged the autopilot on my trusty old 2006 model Teepee City. The electrical car had been the first of its kind to feature a fully operational autopilot. But I’d made sure all the security updates had been installed in order to prevent the very type of incident I’d just been exposed to. In 2008, the sale of new fossil fuel based cars had been outlawed in all of Europe. This quick shift had been made possible due to Teepee Technologies giving away the patents for their engines and batteries. Many other countries had followed with similar bans since then. But this lead to an even greater threat of electrical cars being hacked, with all their electronics and computer systems.

As I drove towards my home, located somewhere in the southern parts of Oslo, I noticed another thorium reactor under construction along the road. The logo of the Teepee Energy Company was proudly on display. Blue text on a white background. It kind of reminded me of the PeTe logo. And wasn’t Teepee just PeTe backwards? Sure it was! Coincidence? Maybe.

As soon as I got home to my little apartment, I went straight to the bookshelf. I needed to look up some information, but I did not dare doing an online search. Apparently, you never know who’s watching. My ex-wife, knowing I was a huge fan of the Teepee Group, once bought me a big book on everything Teepee. This was back in the good old times, before she started accusing me of being less interested in people than technology and told me I’d be wise to stop obsessing about crappy old computers. As with all such things she was of course right. But these days, crappy old computers are all I have left.

I found the book and sat down on my worn out sofa. I skimmed the first pages which contained information I already knew: That the Teepee Group was behind some of the greatest technological achievements in the last 30 years, like electrifying transportation and creating technology that had almost completely replaced dirty fossil fuel energy with clean, renewable energy.

The Teepee Group had seemingly popped up out of no-where. The founder, US citizen Theodore Paterson, had been an insanely successful stock trader in the late 1980s. Joined by a group of anonymous investors from all over the world, he had turned his attention from merely making an obscene amount of money to investing billion of dollars in subsidiaries creating experimental, world-changing technology. The money could easily have been lost forever. But in most cases, the experimental technology had turned into fully operational technology. Even though he had no technological background, Paterson had an inexplicable flair for choosing technological paths that actually went somewhere. When asked how he kept striking technological gold, he would answer: “Good instincts and fool’s luck. But mostly fool’s luck!”

In the middle of the book there was a picture gallery chapter. I turned to this chapter, half-remembering a picture I’d seen a long time ago. After a while I found it. In it, a young, suave looking Paterson was sitting on his desk smiling broadly to the camera. The caption said: ‘1986: Making his first million’. The photo was taken from a height, making Paterson look upwards. The photographer had probably taken the picture while standing on a chair. Next to Paterson stood a familiar computer: A Commodore 64, the original ‘breadbox’ model. The monitor was turned off. Due to the picture having been taken from a height, it was possible to see what was behind the computer: It was a white device connected to the cartridge port.

I went to the kitchen and slammed open all the cupboards in search of my magnifying glass. When I at last found it, I returned to the book with heavy steps, hesitating before holding the magnifying glass over the picture. As I expected, the white device had a blue logo printed on it. The picture was grainy, making the logo text difficult to read. But I was pretty sure I knew what it read. I was pretty sure it said ‘PeTe’.

I went back to the kitchen and found a half empty bottle of whiskey which had been standing in a cupboard for ages. With shaking hands I poured golden liquid into a glass and took a solid sip. I guessed I wouldn’t be able to sleep that night, so I decided to spend the time doing useful stuff on the Internet. Like putting my car for sale and asking my retro computer pals who’d be interested in buying Commodore equipment in near mint condition. This caused quite a frenzy, and for the next few hours I kept myself blissfully occupied replying to requests. When at last I went to bed, I fell swiftly asleep and didn’t wake up until after noon.

Recreating the Commodore 64 User Guide code samples in cc65. Part three: Sprites

We have now arrived at chapter 6 in the Commodore 64 User Guide, «Sprite Graphics». Very exiting, indeed! This chapter describes how to create a really nice looking Commodore Balloon and make it appear to be floating on the screen. The full version of the sample code puts three balloons on the screen simultaneously, and reads as follows:

1 rem up, up and away!
5 print chr$(147)
10 v = 53248 : rem start of display chip
11 poke v + 21, 28: rem enable sprite 2, 3, 4
12 poke 2042, 13: poke 2043, 13: poke 2044, 13
13 rem sprite 2, 3, 4 data from 13th blk
20 for n = 0 to 62: read q: poke 832 + n, q: next
25 poke v + 23, 12: poke v + 29, 12: rem expand sprites 2, 4 
30 for x = 1 to 190
40 poke v + 4, x: rem update x coordinates
45 poke v + 6, x
48 poke v + 8, x
50 poke v + 5, x: rem update y coordinates
55 poke v + 7, 190 - x
58 poke v + 9, 100
60 next x
70 goto 30
200 data 0,127,0,1,255,192,3,255,224,3,231,224
210 data 7,217,240,7,223,240,7,217,240,3,231,224
220 data 3,255,224,3,255,224,2,255,160,1,127,64
230 data 1,62,64,0,156,128,0,156,128,0,73,0,0,73,0
240 data 0,62,0,0,62,0,0,62,0,0,28,0

As with the previous BASIC examples, you may copy the code and paste it into the VICE emulator and then type RUN to execute it. The resulting screen will look like this:

up-up-and-away-basic

The sprite data is placed in BASIC data statements, which is not a particularly flexible way to define and retrieve sprite data. Our C version of this program looks like this:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <peekpoke.h>

const char sprite[] = {
	0,127,0,1,255,192,3,255,224,3,231,224,
	7,217,240,7,223,240,7,217,240,3,231,224,
	3,255,224,3,255,224,2,255,160,1,127,64,
	1,62,64,0,156,128,0,156,128,0,73,0,0,73,0,
	0,62,0,0,62,0,0,62,0,0,28,0
};

int v = 0xD000;	// START OF DISPLAY CHIP

// Need wait function to slow down x loop
void rasterWait(void) {
	unsigned char raster;
	do {
		raster = PEEK(v + 18);
	} while (raster < 250 || raster > 252);
}

int main (void)
{
	unsigned char n;
	unsigned char x;
	unsigned char t;
    printf ("%c", 147);
	POKE(v + 21, 28); 			// ENABLE SPRITE 2, 3, 4
	POKE(2042, 13);				// SPRITE 2 DATA FROM 13TH BLK
	POKE(2043, 13);				// SPRITE 3 DATA FROM 13TH BLK
	POKE(2044, 13);				// SPRITE 4 DATA FROM 13TH BLK

	for (n = 0 ; n < sizeof(sprite) ; n++) {
		POKE(832 + n, sprite[n]);
	}
	POKE(v + 23, 12); // Expand sprite 2, 4 x direction
	POKE(v + 29, 12); // Expand sprite 2, 4 y direction
	
	do {
		for (x = 1 ; x <= 190; x++) {
			POKE(v + 4, x); 		// UPDATE X COORDINATES
			POKE(v + 6, x);
			POKE(v + 8, x);
			POKE(v + 5, x); 		// UPDATE Y COORDINATES
			POKE(v + 7, 190 - x);
			POKE(v + 9, 100);
			rasterWait();
		}
	} while (1);
    return EXIT_SUCCESS;	
}

After building and running this example, you may notice that the sprites move faster in the C version than in the BASIC version, but otherwise they both look exactly the same.

From the C code, you may notice that the sprite data is defined in an array. But cc65 also allows data to be defined in external files that can be imported when compiling and building the code, much like in this example.  The advantage of this approach is that graphics data can be defined in external resource files. These files can be edited using a graphics editor, thus cleanly separating resource data from program code.

Now, let’s make things really interesting! Did you know that you can use raster tricks in order to display more than the hardware limit of 8 sprites? I bet you did! But is cc65 based programs fast enough to use these tricks? Well, yes. That is, if there isn’t too much going on at the same time, and you really should read the chapter «cc65 coding hints» on how to optimize your code for running on a 6502 platform. The following code can be run to display 16 sprites simultaneously:

// up-up-and-away-expanded.c
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <peekpoke.h>

const char sprite[] = {
	0,127,0,1,255,192,3,255,224,3,231,224,
	7,217,240,7,223,240,7,217,240,3,231,224,
	3,255,224,3,255,224,2,255,160,1,127,64,
	1,62,64,0,156,128,0,156,128,0,73,0,0,73,0,
	0,62,0,0,62,0,0,62,0,0,28,0
};

// Pre-calculated sinus values
const char yValues[] = {
	32, 35, 38, 41, 44, 47, 49, 52, 
	54, 56, 58, 60, 61, 62, 63, 63, 
	64, 63, 63, 62, 61, 60, 58, 56, 
	54, 52, 49, 47, 44, 41, 38, 35, 
	32, 28, 25, 22, 19, 16, 14, 11, 
	9, 7, 5, 3, 2, 1, 0, 0, 
	0, 0, 0, 1, 2, 3, 5, 7, 
	9, 11, 14, 16, 19, 22, 25, 28
};	

int v = 0xD000;	// START OF DISPLAY CHIP
int rasterAdr = 0xD012; // Raster address

// Raster wait with line argument
void rasterWait(unsigned char line) {
	unsigned char raster;
	do {
		raster = PEEK(rasterAdr);
	} while (raster < line);
}

int main (void)
{
	unsigned char n, t;
	int rx, x, adr, t2, adrY = v + 1;
	char sx, msb;
	POKE(v + 33, 0); // Set background color

    printf ("%c", 147);
	for (n = 0 ; n < sizeof(sprite) ; n++) {
		POKE(832 + n, sprite[n]);
	}
	POKE(v + 21, 255); 			// ENABLE SPRITES 0-7
	for (t = 0 ; t < 8 ; t++) {
		POKE(2040 + t, 13); // Set sprite x data from 13th block for all sprites
	}

	do {
		for (x = 0 ; x < 550; x++) { 
			msb = 0; // MSB of X coordinates
			// Wait until raster hits position 250 before drawing upper sprites
			rasterWait(250);
			 // Set border color, which indicates the raster position
			POKE(v + 32, 1);
			rx = x;
			for (t = 0 ; t < 8 ; t++) {
				rx -= 24;
				t2 = t * 2;
				if (rx >= 0 && rx < 366) {
					// Usually I would calculate the sprite X coordinate using
					// the expression sx = rx % 256, but bitwise operation is
					// significant faster
					sx = rx & 255; 
					if (rx > 255) {
						// Set MSB of x coordinate for sprite if x position > 255
						msb |= 1 << t; 
					}
					POKE(v + t2, sx);
					// Y position is an indirect Sinus function of X, using array
					// index for retrieving the Y value
					POKE(adrY + t2, yValues[sx & 63] + 40);
				} else {
					POKE(v + t2, 0);
				}
			}
			POKE(v + 16, msb); // Set MSB of x coordinate
			 // Wait until raster hits position 135 before drawing lower sprites
			rasterWait(135);
			POKE(v + 32, 2); // Set border color
			for (t = 0 ; t < 8 ; t++) {
				adr = adrY + (t * 2); 
				// Add 128 to current sprite Y position
				POKE(adr, PEEK(adr) + 128);
			}
		}
	} while (1);
    return EXIT_SUCCESS;	
}

Running this program in VICE should produce the following output:

up-up-and-away-expanded-c

Notice how the border color changes at the middle of the screen. This marks where the raster wait function returns to the main program loop. Setting border color is a common trick used by game programmers to indicate how much CPU time is left for the main loop before breaking the 50 frames per second limit, and is very useful when optimizing code.

The balloons are moving in a sinus pattern. This is achieved using pre-calculated sinus values that are stored in an array. Calculating sinus values on the fly would demand too much CPU resources for the program to work properly.

The last part of this exciting saga deals with sound. What are you waiting for? Let’s go!

Recreating the Commodore 64 User Guide code samples in cc65. Part two: Bouncing balls

Now, children, turn to page 65 of the Commodore 64 User Guide, chapter 5 «Advanced Color Graphic Commands».  In this chapter you are taught how to use the POKE command to put characters directly to the screen. There’s a really nifty example named «more bouncing balls» in this chapter. The full example will display a moving ball that bounces off the screen walls as well as bouncing off randomly positioned characters:

10 print chr$(147)
20 poke 53280,7: poke 53281,13
21 for l = 1 to 10
25 poke 1024 + int(rnd(1)*1000), 166
27 next l
30 x = 1 : y = 1
40 dx = 1 : dy = 1
50 poke 1024 + x + 40 * y, 81
60 for t = 0 to 10 : next
70 poke 1024 + x + 40 * y, 32
80 x = x + dx
85 if peek(1024 + x + 40 * y) = 166 then dx = -dx: goto 80
90 if x <= 0 or x >= 39 then dx = -dx
100 y = y + dy
105 if peek(1024 + x + 40 * y) = 166 then dy = -dy: goto 80
110 if y <= 0 or y >= 24 then dy = -dy
120 goto 50

As before, you may run this example in VICE. Just paste the code into VICE and type RUN. The result may look something like this:

bouncing-balls-basic

But, hey! Where’s the ball? It sort of comes and goes! What gives!? The reason is a mixture of an inadequate animation coding and that the software used for recording the VICE screen captures the screen grabs at the «wrong» time. The result looks better when running in the emulator, but even then the ball seems to blink all the time. The culprit can be found in these lines:

50 poke 1024 + x + 40 * y, 81
60 for t = 0 to 10 : next
70 poke 1024 + x + 40 * y, 32

Line 50 draws the ball to the screen, while line 60 runs a small loop that allows some time to pass before the ball is cleared from the screen, which happens at line 70. Although this creates the illusion of the ball moving around the screen, it also looks like the ball is blinking.

For the C version of this program, I’d like to fix the animation routine so that the ball doesn’t seem to be blinking. Also, since the C version will run much faster than the BASIC version, I need to add some code to slow down the animation so that it will be possible to see the ball on the screen. This can be implemented in different ways, but the solution I’ve chosen here is to wait for the position of the raster line to reach the bottom of the screen. Doing so will ensure that the animation will run smoothly in 50 frames per second on a PAL version of the Commodore 64, or 60 FPS on an NTSC version. (The VICE emulator seems to be running «C64C PAL» as the default version).

This is the C code I came up:

// bouncing-balls.c
#include <stdio.h>
#include <stdlib.h>
#include <peekpoke.h>
#include <time.h>

int v = 0xD000;	// START OF DISPLAY CHIP
int x = 1, y = 1;
int dx = 1, dy = 1;

// Need wait function to slow down loop
void rasterWait(void) {
	unsigned char raster;
	do {
		raster = PEEK(v + 18);
	} while (raster < 250 || raster > 252);
}

// Add to x coordinate and check if inside screen boundaries
void addX() {
	x += dx;
	if (x < 0 || x > 39) {
		dx = -dx;
		addX();
	}		
}

// Add to y coordinate and check if inside screen boundaries
void addY() {
	y += dy;
	if (y < 0 || y > 24) {
		dy = -dy;
		addY();
	}
}

// Check if ball has collided with collision object
void checkBackgroundCollision() {
	if (PEEK(1024 + x + 40 * y) == 166) {
		// If collision, bounce back in either x or y direction
		if (rand() % 2 == 0) {				
			dx = -dx;
			addX();
		} else {
			dy = -dy;
			addY();				
		}
	}		
}	

int main (void) {
	int l, oldPos;
	srand(time(NULL));
	printf ("%c", 147);
	POKE(v + 24,21); // Set upper case
	POKE(v + 32, 7); // Set border color
	POKE(v + 33, 13); // Set background color
	// Put collision objects in random locations
	for (l = 0 ; l < 10 ; l++) {
		POKE(1024 + rand() % 1000, 166); 
	}
	do {
		rasterWait();
		oldPos = 1024 + x + 40 * y;
		addX();
		addY();
		checkBackgroundCollision();
		POKE(1024 + x + 40 * y, 81);
		POKE(oldPos, 32); // Clear last position
	} while (1);
	
    return EXIT_SUCCESS;	
}

After compiling and building this code and running it in VICE, the following should be seen on the screen:

bouncing-balls-c

The animation is now as smooth as an android’s bottom and with no blinking ball. In order to prevent the ball from blinking, we store the last ball position before adding to the x/y coordinates of the ball:

oldPos = 1024 + x + 40 * y;
addX();
addY();

Then we insert a «space» character on the previous position after drawing the ball’s new position:

POKE(1024 + x + 40 * y, 81);
POKE(oldPos, 32); // Clear last position

As mentioned earlier, in order to get smooth animations we need to check the raster counter and wait until it reaches a certain position before continuing the animation loop:

unsigned char raster;
do {
   raster = PEEK(v + 18);
} while (raster < 250 || raster > 252);

The raster counter is located in VIC register #18.

But why is this example called «bouncing balls» when there’s only one ball on the screen? Boooring! Let’s expand the example and see if we can draw multiple moving balls on the screen! This is a simple task of changing the code to use arrays for x/y positions and x/y directions, changing some functions to accept a ball number parameter and adding a function for initializing the ball parameters so that the different balls starts at different random locations on the screen. The resulting code looks like this:

// bouncing-balls-expanded.c
#include <stdio.h>
#include <stdlib.h>
#include <peekpoke.h>
#include <time.h>

#define BALL_COUNT 10

int v = 0xD000;	// START OF DISPLAY CHIP
int x[BALL_COUNT], y[BALL_COUNT];
int dx[BALL_COUNT], dy[BALL_COUNT];

// Need wait function to slow down loop
void rasterWait(void) {
	unsigned char raster;
	do {
		raster = PEEK(v + 18);
	} while (raster < 250 || raster > 252);
}

// Add to x coordinate and check if inside screen boundaries
void addX(ballNo) {
	x[ballNo] += dx[ballNo];
	if (x[ballNo] < 0 || x[ballNo] > 39) {
		dx[ballNo] = -dx[ballNo];
		addX(ballNo);
	}		
}

// Add to y coordinate and check if inside screen boundaries
void addY(ballNo) {
	y[ballNo] += dy[ballNo];
	if (y[ballNo] < 0 || y[ballNo] > 24) {
		dy[ballNo] = -dy[ballNo];
		addY(ballNo);
	}
}

// Check if ball has collided with background
void checkBackgroundCollision(ballNo) {
	if (PEEK(1024 + x[ballNo] + 40 * y[ballNo]) != 32) {
		// If collision, bounce back in either x or y direction
		if (rand() % 2 == 0) {				
			dx[ballNo] = -dx[ballNo];
			addX(ballNo);
		} else {
			dy[ballNo] = -dy[ballNo];
			addY(ballNo);				
		}	
	}		
}	

// Initialize ball data 
void initBalls() {
	int ballNo;
	for (ballNo = 0 ; ballNo < BALL_COUNT ; ballNo++) {			
		x[ballNo] = rand() % 40;
		if (x[ballNo] < 20) {
			dx[ballNo] = 1;
		} else {
			dx[ballNo] = -1;
		}
		y[ballNo] = rand() % 24;
		if (y[ballNo] < 12) {
			dy[ballNo] = 1;
		} else {
			dy[ballNo] = -1;
		}
	}
}

int main (void) {
	int l, oldPos, ballNo;
	srand(time(NULL));
	initBalls();
	printf ("%c", 147);
	POKE(v + 24,21); // Set upper case
	POKE(v + 32, 7); // Set border color
	POKE(v + 33, 13); // Set background color
	// Put collision objects in random locations
	for (l = 0 ; l < 10 ; l++) {
		POKE(1024 + rand() % 1000, 166); 
	}
	do {
		rasterWait();
		for (ballNo = 0 ; ballNo < BALL_COUNT ; ballNo++) {
			oldPos = 1024 + x[ballNo] + 40 * y[ballNo];
			addX(ballNo);
			addY(ballNo);
			checkBackgroundCollision(ballNo);
			POKE(1024 + x[ballNo] + 40 * y[ballNo], 81);		
			POKE(oldPos, 32); // Clear last position
		}
	} while (1);
	
    return EXIT_SUCCESS;	
}

Running this program will produce the following output:

bouncing-balls-expanded-c

10 glorious balls on the screen at the same time! Splendid! If you’d like to see even more balls, change the ball count at the following line:

#define BALL_COUNT 10

That’s it! Have fun experimenting with the code, just like I did with the original BASIC code back in the days. The next chapter will deal with sprites. Oh, yeah!

Oden’s beard!

Welcome to my blog! It will probably contain features about programming, both current stuff like Web development and… uh… what else is it these days? But it will also feature retro programming, especially for the good old Commodore 64 and Amiga computers. I’m afraid this blog will not contain any beard related features, whatsoever! Sorry if I’ve lured some confused beard lovers into this blog. :-{odensskjegg

Recreating the Commodore 64 User Guide code samples in cc65. Part one: Automatic color bars

So there was a «The c64 Mini» lying under your Christmas tree this year. You’ve played through the built-in games, and now you are asking yourself: «How do I make my own c64 games?» Well, you’ve come to the right place!

Just like the original Commodore 64 computer, The c64 Mini comes with a built-in BASIC interpreter. The Commodore 64 BASIC language is a nice feature which allows for simple programs to be typed in and run. But being an interpreted language the programs run painfully slow, which is particularly obvious when trying to create games. Commodore BASIC is simply not up to the task!

Most games for the old bread-bin were made using low-level machine code, usually coded using an assembler. And in many cases, due to lack of memory resources on the original hardware, the code was written and compiled on another computer with more memory and faster CPU and then transferred to the C64.

But there are alternatives to tedious assembly programming, and one of the best is programming in C using cc65. The official GitHub page states that «cc65 is a complete cross development package for 65(C)02 systems, including a powerful macro assembler, a C compiler, linker, librarian and several other tools». This means that you can make programs for the Commodore 64 using the good old C programming language. And what’s more, you’re not limited to programming only for the Commodore 64 platform. cc65 can be used for making programs for Applie ][+, Atari consoles, Nintendo NES etc. The developers of cc65 has done an impressive piece of work and deserves praise and eternal admiration, hooray!

So what better way to sample the power of cc65 than to replicate some of the BASIC code samples from the Commodore 64 User’s Guide? (Ah, you can think of several better ways, you say? Oh, shut up!) Let’s go to the first BASIC sample that we’d like to replicate. This one is on page 58: «Automatic color bars». The BASIC code looks like this:

1 rem automatic color bars
5 print chr$(147) : rem chr$(147) = clr/home
10 print chr$(18); "     ";
20 cl = int(8*rnd(1))+1
30 on cl goto 40,50,60,70,80,90,100,110
40 print chr$(5);: goto 10
50 print chr$(28);: goto 10
60 print chr$(30);: goto 10
70 print chr$(31);: goto 10
80 print chr$(144);: goto 10
90 print chr$(156);: goto 10
100 print chr$(158);: goto 10
110 print chr$(159);: goto 10

If you want to test this code,  you may copy the above text, fire up your local instance of VICE emulator, and paste the code into the emulator window. Then type «run» to execute the program. The resulting output will look something like this:

random-color-bars-basic

Now let’s see what the C code for this simple program may look like:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main (void)
{
	char colors[] = { 5, 28, 30, 31, 144, 156, 158, 159 };
	char clrHome = 147;
	char rvsOn = 18;
	printf ("%c", clrHome);
	srand(time(NULL)); 
	do {
		printf ("%c", rvsOn);
		printf ("%s", "     ");
		printf ("%c", colors[rand() % sizeof(colors)]);
	} while (1);
	return EXIT_SUCCESS;
}

As you may have noticed, the C version of the program doesn’t resemble the BASIC version, like, at all. There’s a perfectly good explanation for this: Like most modern high-level languages, C does not rely on line numbers for making «jumps» inside programs. But old BASIC dialects, like the one in the Commodore 64, does. Look at how the BASIC program uses the ON… GOTO keywords for jumping to a specific line number in order to set the cursor color:

...
20 cl = int(8*rnd(1))+1
30 on cl goto 40,50,60,70,80,90,100,110
40 print chr$(5);: goto 10
...

To make the two versions more «comparable», the C version should have re-created each of the lines between 40 and 110 into C functions, and the ON… GOTO control code should have been rewritten as a «switch… case» statement. Instead we have put the color codes into an array and accessing them using a «random» library function:

...
char colors[] = { 5, 28, 30, 31, 144, 156, 158, 159 };
...
printf ("%c", colors[rand() % sizeof(colors)]);
...

The BASIC program could also have been rewritten in order to use arrays instead of relying on line numbers. But I guess the author wanted to showcase the ON… GOTO keywords in this sample, which is a good alternative to the «switch… case» statements used in many modern languages.

But how do I run the C code, you may be asking yourself at this time. Well, first you need cc65, of course. If you are a Windows user, download the Windows Snapshot zip file. (If you’re using Linux however, you need to follow these instructions.)  Unzip the cc65 files to e.g. c:\cc65.

Next you will need the VICE emulator in order to run the samples. Download from here and unpack to e.g. c:\emulators.

Create a source catalog in which to put your C code files, e.g. in c:\source\cc65. Create a source file for the automatic color bars C code, e.g. automatic-color-bars.c. For editing the C code files, I am using the application Notepad++, which provides syntax highlighting for a number of programming languages.

If you’ve created the automatic-colorbars.c file, you may compile the file into a .prg file, which may be used in the VICE emulator for running the program. This may be done using the convenience command «cl65», which is found in the cc65\bin directory. But for further convenience, you may create a Windows .cmd file for building the .prg file and starting it in the emulator. Create a file named comp.cmd in your source\cc65 directory and insert the following lines:

set CC65_HOME=c:\cc65
set VICE_HOME=C:\emulators\GTK3VICE-3.3-win32-r35872
set CC65_INC=%CC65_HOME%\include
set path=%PATH%;%CC65_HOME%\bin;%VICE_HOME%

cl65 -O -t c64 -o %1.prg %1 && (
x64 %1.prg
) || (
echo Compiling failed
)

You need to make sure the paths above matches your own paths.

  • Hit Windows+R, and write «cmd» to start the command prompt.
  • Write «cd \source\cc65» to go to your sources directory.
  • Write «comp.cmd automatic-color-bars.c» in order to build the program and run it in the VICE emulator.

If the compile fails, the VICE emulator will not be started. If not, you should see the following happening on the screen:

automatic-color-bars-c

The resulting output resembles the BASIC version of the program, but with noticeable faster rendering of the color bars. You may wonder why the C version isn’t even faster. This may be due to both versions using the same kernel functions for printing text. Performance differences between BASIC and C will be even more obvious in the next sample, «bouncing balls».