Commodore VIC-20

My first real computer. Sure, the school I went to had Ohio Scientific Challenger C1-P (6502 CPU), but they also had the Commodore VIC-20 a-plenty, which had colour, sound and good documentation. We eventually got one for home with a datasette, programmer's reference and introduction to BASIC, so I became quite good at Commodore BASIC V2, writing dozens of my own programs.

Downloads

scuba.prg for the VIC-20 +8K (22x23chars). STANDARD.
scuba27x34.prg for the VIC-20 +16K (27x34chars). VICE.
scuba28x28.prg for the VIC-20 +16K (28x28chars). THEVIC-20.
screen3k.prg screen resize utility for VIC-20 unexpanded / +3K
screen8k.prg screen resize utility for VIC-20 8K+

How do you get the prg on your VIC-20? (1) buy an SSD 1541 emulator gadget, (2) convert prg to wav format then record the wav to cassette or audio out to audio in on a datasette adapter, (3) use VICE to run an emulator on your modern computer.

Scuba Diver (update: 2022-01-07; first released: 2022-01-01)

Inspired by the Oric game by Ronald Jeffs 1984, of which I have only seen a minute or so on YouTube. The Oric is bit mapped / sprite where as mine would be chunky character based. Why chunky characters? Well I thought I actually could fit everything into unexpanded memory. Wrong. Rather than dump everything and go full sprite, I added more RAM and persisted until the project was done.

  1. AIR: In your tank, measured in fancy KPA, maxes at 2800. If it gets to zero ... game over.
  2. SCORE: Get score by collecting treasure, lose score by getting more air, or hitting a monster.
  3. FISH: (Yes it is) don't touch, they will steal your air!
  4. SNAKE: (Sea snake) same as fish but they look different. There are also other monsters, they all behave the same.
  5. PLAYER: That's you.
  6. TREASURE: Run into these to get SCORE! When you have collected at least 3 treasures then you can leave the game if you want - go back to the boat.
  7. AIR: This cyan stuff will replenish your tank air. Keep moving into it and watch your tank air go up (and score go down a little).

CONTROLS WASDX (S and D both move your character down) or Joystick! The joystick allows you to move diagonally, which is nice.

Quick and dirty. There you go. Done! My first brand new VIC-20 game in many decades.

CODING Using TRSE I cobbled together a few screens of a game with user defined characters, but quickly ran out of memory - the unexpanded VIC-20 has under 4K to play with, so I revised the code to work with an 8K expansion. There are likely plenty of optimisations I could have made . I ran into some issues that I couldn't work out and after contacting the TRSE developer, I received some prompt help from AndyH - thank you very much!

TRSE user defined characters with 8K expansion or more

Below is the code snippet that AndyH helped with. The issue is that unexpanded and +3K expansion have the screen and character set locations in nice convenient places, but when you expand to 8K or more then the memory locations change, so you need a series of @ directives to tell the TRSE compiler where to place the code and avoid stomping over the user defined character memory area.

@VicMemoryConfig "8k"
@projectsettings "ignorebasicsysstart" 0
@projectsettings "basicsysaddress" $1201
@projectsettings "startaddress" $1610

VAR
// ...
charset: incbin("charset6.bin", $1400);

BEGIN
setcharsetlocation ($1400);
// ...
END.

Resize the VIC-20 Screen

22 columns by 23 rows should be enough for anyone's needs! But it really isn't much. Sure 22x23 (=506) ensures the screen fits nicely into 512 bytes but it is really on the wrong side of the border of usefulness for most applications. Also, only having 3583 bytes makes giving up another 400 or 500 on screen realestate a large expense. Note that colour memory has a bunch of unused memory just sitting there unused. Lawrence Woodman's article covers the method to expand the screen. Below are some hints for changing the screen dimensions using TRSE.

Target system : you can expand the screen, and move the display about quite easily. However you will need to test what your display device can show you. VICE (28x34=952bytes) can show an awful lot more than my HDMI TV (28x28=784bytes), and I hear that NTSC display capabilities are different to PAL ... if you're making software for the broadest base possible then you should probably limit the size that you expand screen. I have made two utilities Screen3K and Screen8K to allow you to explore the possibilities on your device(s).

You will also need to tell the VIC-20 to move the memory around so you don't run into memory that BASIC programs use or ROM or non-RAM blocks of memory. Briefly: unexpanded/3K machines need to move the screen address ($1E00) and colour address ($9600) back $200 (512bytes); 8K+ expanded VIC-20 needs to protect the $400 above screen RAM which starts at $1000 {even further if you want to place user defined characters at $1400}, and also ensure colour address is at $9400.

// unexpanded/3K code
VAR
	BIGSCREEN_COLS : byte = 28;
	BIGSCREEN_ROWS : byte = 28;
	BIGSCREEN_OFFX : byte = 6; // location of the display screen left-right
	BIGSCREEN_OFFY : byte = 27; // location of the display screen up-down
	SCREENLOC, COLOURLOC, moveToLoc: INTEGER;

	scrsz_loch : byte at $9000; // loc horiz $9000 = 36864
	scrsz_locv : byte at $9001; // loc vert $9001 = 36865
	scrsz_cols : byte at $9002; // nr cols $9002 = 36866
	scrsz_rows : byte at $9003; // nr rows(x2) $9003 = 36867
	scrsz_scrmem : byte at $9005;// bit7-4 $1000,$1200,$1400,$1600,$1800,$1A00,$1C00,$1E00
	
	int1,int2,int3 : integer;
	tmptr : pointer;

// Change screen dimensions. Call once at start
procedure BigScreenSetup(BIGSCREEN_COLS, BIGSCREEN_ROWS, BIGSCREEN_OFFX, BIGSCREEN_OFFY : global byte);
begin
scrsz_cols := ((scrsz_cols & 128) | BIGSCREEN_COLS);
scrsz_rows := ((scrsz_rows & 129) | BIGSCREEN_ROWS * 2);
scrsz_loch := BIGSCREEN_OFFX;
scrsz_locv := BIGSCREEN_OFFY;
end;

// Fill the screen with a character and a colour
// example: BigScreenFill(32,BLACK); // blank the screen
procedure BigScreenFill(thisChar,thisColour:byte);
begin
int1 := BIGSCREEN_COLS * BIGSCREEN_ROWS;
tmptr := SCREENLOC;
WHILE int1 > 0 DO
	BEGIN
	if int1 > 255 then
		begin
		Fill(tmptr,thisChar,255);
		tmptr := tmptr + 255;
		int1 := int1 - 255;
		end
	else
		begin
		Fill(tmptr,thisChar,LO(int1));
		int1 := 0;
		end;
	END;
int1 := BIGSCREEN_COLS * BIGSCREEN_ROWS;
tmptr := COLOURLOC;
WHILE int1 > 0 DO
	BEGIN
	if int1 > 255 then
		begin
		Fill(tmptr,thisColour,255);
		tmptr := tmptr + 255;
		int1 := int1 - 255;
		end
	else
		begin
		Fill(tmptr,thisColour,LO(int1));
		int1 := 0;
		end;
	END;
end;

// Use mymoveto instead of moveto, works with print* procedures
procedure mymoveto(mtx,mty:byte);
begin
int1 := CreateInteger($00,mtx);
int2 := CreateInteger($00,mty);
int3 := int1 + int2 * BIGSCREEN_COLS;
int1 := int3 / 22;
int2 := int3 - (int1 * 22);
InitMoveTo();
moveto(lo(int2),lo(int1),moveToLoc);
end;

// ### MAIN
BEGIN
DefineScreen();
SCREENLOC := $1C00; // replace SCREEN_CHAR_LOC (unexpanded/3K=$1E00)
COLOURLOC := $9400; // replace SCREEN_COL_LOC 
// unexpanded/+3K needs the screen memory start moved back $0200 to allow for the extra memory that the screen will need
SetScreenLocation(SCREENLOC); // $1E00=7608 vs $1C00=7168
// unexpanded/+3K needs the colour memory start moved back $0200 to allow for the extra memory that the screen will need
// SetColorMemoryAddress(); // ignore this and force the bit 7 to 0 : bit7=0 -> $9600=38400 || bit7=1 -> $9400=37888
scrsz_cols := (scrsz_cols & 127); // clear bit 7 to set colour memory to $9400
moveToLoc := HI(SCREENLOC);

BIGSCREEN_COLS := ;
BIGSCREEN_ROWS := ;
BIGSCREEN_OFFX := ;
BIGSCREEN_OFFY := ;
BigScreenSetup (BIGSCREEN_COLS, BIGSCREEN_ROWS, BIGSCREEN_OFFX, BIGSCREEN_OFFY);

AUX_COLOR_AND_VOLUME := %00000010;
SCREEN_BG_COLOR := BLACK + SCREEN_BG_BLUE; // border + background colours
// ... do the suff
// ... etc
END.

Links

Contact zapusten@lo5.me