Skip to content

Commit

Permalink
initial checkin
Browse files Browse the repository at this point in the history
  • Loading branch information
simmons committed Mar 28, 2012
0 parents commit 965c947
Show file tree
Hide file tree
Showing 22 changed files with 1,799 additions and 0 deletions.
19 changes: 19 additions & 0 deletions LICENSE
@@ -0,0 +1,19 @@
/*
* Valence 64 - The input-only VNC client for the Commodore 64.
*
* Copyright 2012 David Simmons
* http://cafbit.com/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

35 changes: 35 additions & 0 deletions Makefile
@@ -0,0 +1,35 @@

all: valence64.prg setup.prg hello.prg vncclient/vncclient.c64 combined.prg disk

clean:
$(MAKE) TARGET=c64 -C vncclient sterile
rm -f valence64.prg
rm -f combined.prg
rm -f setup.prg
rm -f valence64.d64
rm -f hello.o hello.prg

vncclient/vncclient.c64:
$(MAKE) TARGET=c64 -C vncclient build

combined.prg: valence64.prg vncclient/vncclient.c64
./combine.pl valence64.prg vncclient/vncclient.c64 vncclient/contiki-c64.map > combined.prg

%.o: %.asm
ca65 -o $@ $<

%.prg: %.o %.cfg
ld65 -C $(lastword $^) -o $@ $<

%.prg: %.bas
petcat -c -w2 -o $@ -- $<

disk:
c1541 -format valence64,00 d64 valence64.d64
c1541 -attach valence64.d64 -write combined.prg valence64,p
c1541 -attach valence64.d64 -write setup.prg setup,p
c1541 -attach valence64.d64 -write assets/contiki.cfg contiki.cfg,u
c1541 -attach valence64.d64 -write assets/valence.cfg valence.cfg,u
c1541 -attach valence64.d64 -write vncclient/cs8900a.eth cs8900a.eth,u
c1541 -attach valence64.d64 -write vncclient/lan91c96.eth lan91c96.eth,u
#./randomizesrcport.pl
97 changes: 97 additions & 0 deletions README
@@ -0,0 +1,97 @@

Valence64: The input-only VNC client for the Commodore 64
======================================================================

(c) 2012 David Simmons
Licensed under the Apache License, Version 2.0

http://cafbit.com/entry/valence64

Valence64 is a simple proof-of-concept application for controlling a
remote computer using a networked Commodore 64. It was developed as
a way for me to learn the Contiki framework and the uIP TCP/IP stack,
both of which are used in actual modern-day embedded systems.


Using Valence64
----------------------------------------

The easiest way to use Valence64 is to obtain a prebuilt version of the
valence.d64 disk image from the above web site. Attach the disk image
to your C64 emulator, or write the image to a 1541 5.25" disk for use on
an actual C64.

Run the SETUP program to configure your TCP/IP settings, select an
ethernet driver, and indicate the VNC server address of the host you
want to control:

LOAD "SETUP",8
RUN

Then, load and run Valence64:

LOAD "VALENCE64",8
RUN

Press F1 to connect to the VNC server. By default, the program is in
"mouse mode" -- CRSR keys will be used to move the mouse, and RETURN
will send a mouse click. Press F7 to toggle "keyboard mode" for typing.
A joystick in control port 2 can also be used to operate the mouse
pointer.


Building Valence64
----------------------------------------

Requirements:
Linux development machine.
(It could be made to work with other platforms.)
Contiki 2.5
The cc65 compiler/assembler (cc65-c64-2.13.2-1)

You must have a copy of the Contiki 2.5 source code located in the
../contiki-2.5 directory relative to the root of the Valence64 source.
Patch the Contiki source with the supplied contiki-2.5-autostart.patch
file:

$ cd ../contiki-2.5
$ patch -p1 < ../valence64/contiki-2.5-autostart.patch

If you want to use my randomizesrcport.pl script to randomize the
initial source port number (which is useful during development), then
also apply this patch (and uncomment ./randomizesrcport.pl from the disk
target of the Makefile):

$ patch -p1 < ../valence64/contiki-2.5-randomsrcport.patch

You must also have the cc65 compiler/assembler package installed in
/usr/local/bin. (Or edit the CC65_HOME value in vncclient/Makefile to
point to the location.)

Type "make".


Build concept
----------------------------------------

Valence64 uses a somewhat convoluted process to produce the final
product, due to it being a BASIC/ML hybrid program. In the final
output, the binary 6502 executable code ("ML code") is appended to the
end of the BASIC program, and launched from BASIC via a SYS call. This
poses several challenges:

1. The ML link step needs knowledge of the final memory location of the
program for proper linking. This location will change every time the
BASIC program is modified, since the starting address will be at the end
of the BASIC code.
2. The BASIC program doesn't know the memory locations to SYS until the
ML code is compiled/assembled/linked.

To work around this, I use scripts for post-processing. This allows the
BASIC program to SYS with placeholder addresses, which are filled in
based on the symbol table used by the linker. During linking, which
happens after the BASIC program has been rendered into a tight PRG file,
a script inspects the PRG file and determines the ML starting address.
A linker configuration is dynamically built from this information using
a template.

Binary file added assets/contiki.cfg
Binary file not shown.
1 change: 1 addition & 0 deletions assets/valence.cfg
@@ -0,0 +1 @@
���
106 changes: 106 additions & 0 deletions combine.pl
@@ -0,0 +1,106 @@
#!/usr/bin/perl
######################################################################
#
# combine
#
# Merge a BASIC program and a 6502 machine language program into one
# file for convenience and fast loading. The ML code should be linked
# for a starting address just after the end of the BASIC program.
#
# (c) 2012 David Simmons
#
# usage: combine.pl basicprogram.prg mlprog.prg > combinedprog.prg
#
######################################################################

use strict;
use warnings;
use bytes;

if (@ARGV < 2) {
die "usage: combine.pl basicprogram.prg mlprog.prg [symbol.map]\n";
}

my ($bas, $ml);

# read BASIC file
open(BAS, $ARGV[0]) || die "cannot open basic file: $!\n";
{
local $/;
$bas = <BAS>;
}
close(BAS);

# read ML file
open(ML, $ARGV[1]) || die "cannot open ml file: $!\n";
{
local $/;
$ml = <ML>;
}
close(ML);

# read symbol table, if available
my $exports;
if (@ARGV >= 3) {
my $in = 0;
open(MAP, $ARGV[2]) || die "cannot open symbol map: $!\n";
while (<MAP>) {
chomp;
if (/^Exports list:$/) {
$in = 1; next;
}
if ($in) {
if (/^$/) {
$in = 0; next;
}
if (/^\s*(\S+)\s+(\S+)\s+\S+\s+(\S+)\s+(\S+)\s+\S+\s*$/) {
$exports->{$1} = hex($2);
$exports->{$3} = hex($4);
} elsif (/^\s*(\S+)\s+(\S+)\s+\S+\s*$/) {
$exports->{$1} = hex($2);
}
}

}
close(MAP);
}

my $jumpaddr = sprintf("%05d", 0x7FF+length($bas));

# write the actual jump addresses into the basic program,
# replacing the placeholder 'SYS "symbol"' calls.
sub translate {
my $symbol = shift;
my $address;
if ($symbol eq 'JUMPSTART') {
$address = $jumpaddr;
} else {
$address = $exports->{lc $symbol};
}
printf(STDERR "TRANSLATE $symbol -> $address\n");
return $address;
}
my $l1 = bytes::length($bas);
$bas =~ s/\x9e "(\S+)"(.*?)\x00/sprintf("\x9e %d%s\x00",&translate($1),$2)/ge;
my $l2 = length($bas);
if ($l1 < $l2) {
die "symbol name substitution made the program larger\n";
} elsif ($l1 > $l2) {
# apply padding
#printf STDERR "PADDING: ".($l1-$l2)."\n";
$bas .= ("\xff" x ($l1-$l2));
}

# trim the first 14 bytes from the ML file. This contains
# the 2-byte starting address, and 12 bytes of needless
# BASIC bootstrap code.
$ml = substr($ml,14);

# while we're here, hack out the cc65 runtime's annoying
# shift to the upper/lowercase character set
$ml =~ s/\xa9\x0e\x20\xd2\xff/\xa9\x8e\x20\xd2\xff/g;

# combine and deliver to stdout
print $bas;
print $ml;

38 changes: 38 additions & 0 deletions contiki-2.5-autostart.patch
@@ -0,0 +1,38 @@
diff -Nru contiki-2.5.orig/platform/c64/contiki-main.c contiki-2.5/platform/c64/contiki-main.c
--- contiki-2.5.orig/platform/c64/contiki-main.c 2011-09-06 15:43:39.000000000 -0600
+++ contiki-2.5/platform/c64/contiki-main.c 2012-02-13 00:40:44.171722661 -0700
@@ -63,6 +63,7 @@
main(void)
{
struct ethernet_config *ethernet_config;
+ struct process *vncclient_process = NULL;

process_init();

@@ -120,6 +121,26 @@
process_run();

etimer_request_poll();
+
+ if (! vncclient_process) {
+ // look for vncclient
+ struct process *q;
+ for (q = PROCESS_LIST(); q != NULL; q = q->next) {
+ if (strcmp(q->name, "vncclient")==0) {
+ vncclient_process = q;
+ break;
+ }
+ }
+ } else {
+ struct process *q;
+ for (q = PROCESS_LIST(); q != vncclient_process && q != NULL; q = q->next);
+ if (q == NULL) {
+ // time to leave
+ break;
+ }
+ }
+
+
}
}
/*-----------------------------------------------------------------------------------*/
16 changes: 16 additions & 0 deletions contiki-2.5-randomsrcport.patch
@@ -0,0 +1,16 @@
--- contiki-2.5.orig/core/net/uip.c 2011-09-06 15:43:39.000000000 -0600
+++ contiki-2.5/core/net/uip.c 2012-02-15 23:15:18.413803065 -0700
@@ -377,7 +377,12 @@
uip_conns[c].tcpstateflags = UIP_CLOSED;
}
#if UIP_ACTIVE_OPEN || UIP_UDP
- lastport = 1024;
+
+{
+ // simmons-hack: marker for initial source-port
+ u16_t x[5] = {0xdead, 0xbeef, 0x0000, 0xdead, 0xbeef};
+ lastport = 1024 + x[2];
+}
#endif /* UIP_ACTIVE_OPEN || UIP_UDP */

#if UIP_UDP
29 changes: 29 additions & 0 deletions hello.asm
@@ -0,0 +1,29 @@

;set up some helpful labels
CLEAR = $E544
CHROUT = $FFD2

.segment "BASICSTUB"

.byte $00
.byte $C0

.code
main:
jsr CLEAR
ldx #0
loop:
lda greeting,x
cmp #0
beq finish
jsr CHROUT
inx
jmp loop
finish:
rts

.data
greeting:
.byte "HELLO, WORLD!"
.byte $00

8 changes: 8 additions & 0 deletions hello.cfg
@@ -0,0 +1,8 @@
MEMORY {
RAM: start = $BFFE, size = $1002, file = %O, define = yes;
}
SEGMENTS {
BASICSTUB: load = RAM, type = ro;
CODE: load = RAM, type = ro;
DATA: load = RAM, type = rw;
}

0 comments on commit 965c947

Please sign in to comment.