If you thought software development was hard …

shot4-550x412

You should read about the development of a Ludum Dare entry called Ponk.

It’s a C64 version of Pong, developed on a real C64 with only a C2N datasette to save code. Back in the day I was lucky enough to have a 1541-II disk drive. I can’t imagine how painful it must have been working with a slow and unreliable cassette.

datassete

In the end he couldn’t transfer his game to a PC so he had to take screenshots of his game and OCR them, hand checking every byte. I did something similar about 20 years ago when I was tinkering with a C64 to Amiga cable and needed to somehow transfer a C64 programme from the Amiga to the C64 to do the transfer .. Painful.

playing

Wow. Well done Sosowski. (via Indiegames)

A Red Storm brewed some Beatles

Earlier this evening while listening to “I am the Walrus” by The Beatles my wife asked how I knew that song. She wasn’t familiar with it you see. I replied that I had heard it used in a Commodore 64 demo and then spent the next few minutes wracking my brains for the name of that demo.

I thought it might have been made by Nato, and the title started with “Red” but nothing jumped out at me. Then I thought of Fairlight but again, nothing there except some of their demos were produced with another group, Triad! Yes, that was it!

Triad created Red Storm in 1992, it’s not the most technically sophisticated demo but it’s one of my favourite C64 demos ever. It has some nice effects but I really loved the Zoo TV inspired visuals and poetry. The music was great too, but I didn’t realise it was covers of Beatles music. Granted, it was done on a C64 SID chip so it has that 8 bit sound but it still sounds great. ‘Course, that might just be my nostalgic ears playing tricks on me.

What do you think? Yay or Nay?

C64: Wanted Dead or Alive

Bon Jovi’s “Wanted Dead or Alive” as played on a real Commodore 64. The song was digitized on an Amiga, downsampled to 4 bit audio and copied onto a 3.5″ inch disk that the Commodore 1581 drive could read from. The song data was streamed in realtime from the drive to the tiny 64Kb of memory in the computer and fed to the SID chip for our aural delight. I presume the screen has been blanked to save processing power, or the data for the sample gets dumped into screen memory.

This did require an Amiga with the Perfect Sound digitizer. I hooked up the CD player to the digitizer and then using a custom routine on the Amiga, my brother would convert the data to a 4 bit sample. Then we used a null modem cable and Novaterm with a cartridge port adapter to transfer the data to a 1581 floppy. Quite a bit of work went into this.

20 years ago I recorded my own voice onto a cassette saying the word “Ozone” (the name of my demogroup) and I figured out how to sample my voice using the Commodore cassette deck hooked up to the C64. I can’t remember now what memory register it used, I’ll have to search my disk images or examine a C64 memory map one of these days. The quality was terrible but if you knew what was being said you could make it out. It had to be kept short because I’d ran out of memory! I think I used it in the last part of my demo “Awareness of Reality”. (via)

Commodore 64: 8 Bit Legend

Impressive video showing off some of the most popular games of the C64 and the biggest or most famous groups in the C64 demoscene. Must have taken ages to make.

Skip forward to 10:00 into the video for a message from Jim Butterfield. Though recorded in the 80’s I presume, the message still applies. Programming can be fun.

(via Jaz)

Happy Birthday Commodore 64!

issue 50 of Zzap 64!
Issue 50 of Zzap! 64

The Commodore 64 is 30 years old this year and it went on sale in August 1982 so I think it’s about time I wished it a happy birthday. Back then I was messing on a Commodore Vic 20 (or more likely it was 1984 or so), then I had a Speccy and I didn’t get my hands on a C64 until 1989. It was already declining somewhat but it still had a few years of life left in it. Issue 50 of Zzap! 64 was the first issue of that famous magazine I owned. My brother and I bought it in Paul’s Street Shopping Centre! The newsagent is long gone but I have that issue around here somewhere ..

Matt Allen visited a primary school and a secondary school and asked kids there what they thought of the Commodore 64. I don’t think they were impressed by loading errors and long loading times. He probably should have brought a 1541 disk drive and an Action Replay cartridge!

Continue reading “Happy Birthday Commodore 64!”

Batdance

I love the original Batman the Movie soundtrack. This video (which I saw for the first time today) though makes me cringe. (via Twitter but I found a YT copy)

Bonus: Batmania by Pretzel Logic on the C64. I remember watching this around the time the movie came out.

Digital Acid

“Turn the lights off, stand in the middle of the room and wave your arms about frantically….”

Watch it fullscreen, but not if you’re averse to flashing lights..

Smiley’s People, a BBC podcast I listened to recently inspired me to look up this old Ash & Dave C64 demo. Unfortunately the podcast is not available any more.

Prince of Persia: the Apple II source

It’s been a good few months for the 8 bit versions of Prince of Persia. Last October saw the release of a C64 version. Yesterday the original source code for the Apple II version was uploaded to github! Read about how Jason Scott recovered that source code from 20 year old disks (similar to what I did recently!)

The game was originally written in assembler so the source code was already out there. How? Machine code is the language a machine understands and assembler is a human representation of that machine code. For example, the machine code “A9 00 8D 20 D0” is actually this more readable assembler: (that inserts the value 0 into the memory location $D020)

LDA #00
STA $D020

The assembler code released yesterday goes one step further. It uses labels, variables and comments. See BOOT.S as a good example. Variables are defined at the top and labels are used throughout making it a lot easier to deal with moving and adding code around. Look for the text “skewtbl” where you’ll find a simple loop that reads in data from memory and inserts it into 2 registers.

:0 ldy sector
 lda skewtbl,y
 sta $3d
 lda sectaddr,y
 beq :1
 sta $27
:rdsect jsr $005c
:1 dec sector
 bne :0

 lda SLOT
 jmp $900

skewtbl hex 00,0d,0b,09,07,05,03,01
 hex 0e,0c,0a,08,06,04,02,0f

sectaddr hex 00,09,00,00,00,00,00,00
 hex 30,31,32,33,34,00,00,00

Jordan Mechner puts it more poetically:

Non-programming analogy: Video game source code is a bit like the sheet music to a piano sonata that’s already been performed and recorded. One might reasonably ask: If you have the recording, what do you need the sheet music for?
You don’t, if all you want is to listen and enjoy the music. But to a pianist performing the piece, or a composer who wants to study it or arrange it for different instruments, the original score is valuable.

Props to this Slashdot post for the extra links. Also worth a look is the development diary of the C64 version and there are videos showing how the game was made back in 1985!

The Commodore 64 Disk Masher (C64 DMS)

DMSREADER and DMSWRITER are two parts of a Commodore 64 tool I wrote way back in 1994. I presume I got the name from the Amiga DMS tool but I really don’t know. The purpose of the tool was to create an image of 5 1/4 disks but break the image up into smaller DMS files.

Download dms64-1.0.zip.

According to the attached note, I wrote it to upload C64 demos to local BBSes but it was also used by me and the few people I still swapped C64 disks with back then. Were D64 image files around in 1994? If they were I didn’t know about them. They could only be useful to users of higher capacity disks anyway. Don’t bother trying to send a message to the email address in the note. It’s an address I had in first year in college and is long gone!

I’m posting this here because there’s no sign of this tool at all online. Some of my demos are already on CSDB but not this. It’s obviously not that useful these days when a D64 image file is only 171KB but for historical reasons it’s probably of interest. Each of the two parts are a mixture of BASIC and assembly language. By the looks of things I used some sort of illegal character trick to hide the BASIC loader but you can view it easily in CBMXfer.

DMSWRITER recreates the disk from the DMS files. It’s fairly easy to use. Enter your drive number(s) and follow the instructions. Well, almost.

Where I wrote “destination disk” in the DMSWRITER it should have been “source disk” instead. Ooops. When data is written to the destination disk the border flashes with thick multicolour bars but when it flashes quickly with a grey/blue flicker you need to change the source disk to feed it more DMS files.
I noticed that the source drive light continues to flicker after the process is over but sending a reset or loading the disk directory will sort that out. I also noticed the text of the on screen display flashes up while writing as if that data is written to disk. I need to make sure that isn’t the case or we’ll end up with corrupted disks. I never noticed any problems previously so hopefully it’s a false alarm.

DMSREADER is responsible for creating DMS files. The process is much the same, only in reverse. The source drive should contain the disk you want to make an image of and the destination will be a blank disk. You’ll have to use two destination disks unfortunately as I never got around to compressing the output files. There’s still a bug in the READER where it asks you to flip the destination disk a second time, ignore that and just hit space.
Unfortunately when I first tested the reader I received a “?SYNTAX ERROR IN 1000” error just after I was told to flip the destination disk. Fixing it was easy, replacing the following code:

1000 IF (PEEK ($DC01)AND $10)< > 0THEN GOTO 1000
1000 IF PEEK (56321)< > 239THEN 1000

When I wrote that BASIC programme I was too smart by half. To stop people looking at the code I added REM commands followed by an illegal character. Just so I could debug the programme itself I had to edit the RAM where it lived and replace that character. Look for 8F CC in the screenshot below of the Action Replay machine code monitor. I replaced CC with 34 (character “4”) to get a code listing.

The DMSWRITER BASIC loader uses 56321 which is correct, but I have to wonder why I didn’t use a BASIC command to wait for a key press rather than fooling around with low level registers. The original file has been renamed DMSREADER.ORIG.

While looking at the ASM code in the file DMSREAD I think I found a small bug in the otherwise excellent CBMXfer. The first screenshot below is from CBMXfer and you’ll notice that the BNE returns to the wrong address. I loaded an Action Replay cartridge and used the monitor in that to view the same code in Vice where the BNE address is correct. Gave me a fright to think there was such an obvious bug in my code…

Oh yes, make sure you disable any fastloaders and enable true drive emulation in Vice when using these tools.

So totally chuffed that I can use an Action Replay in Vice. I did all my development in that monitor. Yes, not easy …

DMSREADER (BASIC listing)

2 A= 53280
  IF PEEK (52769)= 216OR LO= 1THEN GOTO 4
3 LO= 1
  LOAD "DMSREAD.ASM",8,1
4 POKE A,0
  POKE A+ 1,0
  PRINT CHR$ (8)
  PRINT "{CLR}{WHITE}   DMS 64 READER BY XEER/OZONE"
  REM 4
5 INPUT "SOURCE DEVICE NUMBER(RETURN FOR 8)";Z
6 INPUT "DEST DEVICE NUMBER(RETURN FOR 8)";X
7 IF Z= 0THEN  Z= 8
8 IF X= 0THEN  X= 8
9 SYS 4096
  POKE 52739,X
10 PRINT "{CLR}"
   SYS 52992
   OPEN 15,Z,15
   OPEN 5,Z,5,"#"
20 READ A,B,C
   IF A= - 1THEN GOTO 50
25 TR= A
30 PRINT# 15,"U1";5;0;TR;D
35 SYS 53008
   PRINT "{HOME}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}TRACK     ";"{LEFT}{LEFT}{LEFT}{LEFT}";TR,"SECTOR     ";"{LEFT}{LEFT}{LEFT}{LEFT}";D
40 D= D+ 1
   IF D= CTHEN TR= TR+ 1
   D= 0
45 IF TR= (B+ 1)THEN D= 0
   GOTO 60
46 GOTO 30
50 CLOSE 5
   CLOSE 15
   END 
60 CLOSE 5
   CLOSE 15
100 IF  TR< 33 THEN  GOTO  110
101 PRINT "FLIP DEST DISK!!!"
    GOSUB 1000
110 IF  Z= XTHEN PRINT "{HOME}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}  INSERT DEST DISK AND PRESS SPACE"
    GOSUB 1000
130 POKE 52800,NAME+ 65
    SYS 52736
140 IF Z= XTHEN  PRINT  "{UP}    INSERT SOURCE DISK AND PRESS SPACE"
    GOSUB 1000
150 NA= NA+ 1
    GOTO 10
200 DATA  1,3,21,4,6,21,7,9,21,10,12,21,13,15,21,16,17,21
210 DATA  18,19,19,20,22,19,23,24,19
220 DATA  25,27,18,28,30,18
230 DATA  31,33,17,34,35,17
240 DATA  -1,-1,-1
1000 IF (PEEK (56321))< > 239THEN GOTO 1000
1010 RETURN 

DMSWRITER (BASIC listing)

7 IF PEEK (52757)= 213THEN  LO= 4
8 IF LO= 4THEN GOTO 10
9 LO= 4
  LOAD "DMSWRITE.ASM",8,1
10 POKE 53280,0
   POKE 53281,0
   PRINT "{CLR}{WHITE}DMS 64 WRITE BY XEER/OZONE"
   SYS 4096
11 INPUT "SOURCE DEVICE NUMBER(RETURN FOR 8)";Z
12 INPUT "DEST DEVICE NUMBER(RETURN FOR 8)";X
13 PRINT "INSERT SOURCE DISK AND PRESS SPACE"
   GOSUB 3000
   IF Z= 0THEN Z= 8
14 IF X= 0THEN X= 8
15 NAME= 0
   D= - 1
   POKE 52739,Z
   GOSUB 1000
   POKE 52800,NAME+ 65
   SYS 52992
16 PRINT "{CLR}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}IF THE DISK STOPS ON ONE DISK MODE,"
17 PRINT "SWAP DISKS AND PRESS SPACE!"
18 PRINT "IF THE SCREEN FLASHES THEN U MUST USE   SIDE 2 OF THE DESTINATION DISK"
20 OPEN 15,X,15
   OPEN 5,X,5,"#"
   READ A,B,C
   IF A= - 1THEN GOTO 50
25 TR= A
30 PRINT# 15,"U2";5;0;TR;D
31 PRINT# 15,"B-P";5;0
32 SYS 53008
40 D= D+ 1
   IF D= CTHEN TR= TR+ 1
   D= 0
41 IF TR= (B+ 1)THEN D= 0
   GOTO 60
46 GOTO 30
50 PRINT "FINISHED!"
   CLOSE 5
   CLOSE 15
   END 
60 CLOSE 5
   CLOSE 15
100 TR= A
    D= - 1
    Z= 8
    GOSUB 1000
110 NA= NA+ 1
    POKE 52800,NA+ 65
115 IF  PEEK (52800)= 76 THEN  GOSUB 4000
120 GOSUB 1000
    SYS 52992
140 GOTO 20
200 DATA  1,3,21,4,6,21,7,9,21,10,12,21,13,15,21,16,17,21
210 DATA  18,19,19,20,22,19,23,24,19
220 DATA  25,27,18,28,30,18
230 DATA  31,33,17,34,35,17
240 DATA  -1,-1,-1
1000 IF Z= XTHEN GOSUB 3000
1005 SYS 52736
1010 IF Z= XTHEN GOSUB 3000
1020 RETURN 
3000 IF PEEK (56321)< > 239THEN 3000
3005 RETURN 
4000 POKE 53280,PEEK (53280)+ 1
     POKE 53280,PEEK (53280)- 1
4004 IF PEEK (56321)< > 239THEN 4000
4005 RETURN