diff --git a/asoft_basic-utils/Makefile b/asoft_basic-utils/Makefile index a5f6bb85..21e1ad55 100644 --- a/asoft_basic-utils/Makefile +++ b/asoft_basic-utils/Makefile @@ -1,6 +1,7 @@ include ../Makefile.inc -all: asoft_detoken tokenize_asoft integer_detoken asoft_compact +all: asoft_detoken tokenize_asoft integer_detoken asoft_compact bin2data + asoft_compact: asoft_compact.o $(CC) $(LFLAGS) -o asoft_compact asoft_compact.o @@ -14,6 +15,12 @@ asoft_detoken: asoft_detoken.o asoft_detoken.o: asoft_detoken.c $(CC) $(CFLAGS) -c asoft_detoken.c +bin2data: bin2data.o + $(CC) $(LFLAGS) -o bin2data bin2data.o + +bin2data.o: bin2data.c + $(CC) $(CFLAGS) -c bin2data.c + integer_detoken: integer_detoken.o $(CC) $(LFLAGS) -o integer_detoken integer_detoken.o @@ -31,7 +38,7 @@ install: cp asoft_detoken tokenize_asoft integer_detoken $(INSTALL_LOC) clean: - rm -f *~ *.o asoft_detoken tokenize_asoft \ + rm -f *~ *.o asoft_detoken tokenize_asoft bin2data \ integer_detoken asoft_compact diff --git a/asoft_basic-utils/README b/asoft_basic-utils/README index b8c5ea85..6df4290a 100644 --- a/asoft_basic-utils/README +++ b/asoft_basic-utils/README @@ -29,3 +29,10 @@ asoft_compact: tries to compress your Applesoft basic program to make it as small as possible %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bin2data: takes binary image and converts it to suitable + BASIC to poke into memory. + + Useful for getting machine language routines usable + in BASIC programs + diff --git a/asoft_basic-utils/bin2data.c b/asoft_basic-utils/bin2data.c new file mode 100644 index 00000000..bf539733 --- /dev/null +++ b/asoft_basic-utils/bin2data.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) { + + int address=0x300; + int bytes=0,line=10,i; + struct stat file_info; + int fd; + unsigned char c; + + if (argc<2) { + printf("Usage:\t%s binfile [addr]\n\n",argv[0]); + return -1; + } + + if (argc>2) { + address=strtol(argv[2],NULL,0); + } + + if (stat(argv[1],&file_info)<0) { + fprintf(stderr,"Could not stat file %s\n\n",argv[1]); + return -1; + } + bytes=(int)file_info.st_size; + + fd=open(argv[1],O_RDONLY); + if (fd<0) { + fprintf(stderr,"Could not open file %s\n\n",argv[1]); + return -1; + } + + printf("%d FOR I=0 TO %d: READ X: POKE %d+I,X:NEXT I\n", + line,bytes-1,address); + line+=10; + + for(i=0;i>8)&0xff,ts_list&0xff),SEEK_SET); + result=write(fd,sector_buffer,BYTES_PER_SECTOR); + + if (i==0) { + initial_ts_list=ts_list; + } + else { + /* we aren't the first t/s list so do special stuff */ + + /* load in the old t/s list */ + lseek(fd, + DISK_OFFSET(get_high_byte(old_ts_list), + get_low_byte(old_ts_list)), + SEEK_SET); + + result=read(fd,§or_buffer,BYTES_PER_SECTOR); + + /* point from old ts list to new one we just made */ + sector_buffer[TSL_NEXT_TRACK]=get_high_byte(ts_list); + sector_buffer[TSL_NEXT_SECTOR]=get_low_byte(ts_list); + + /* set offset into file */ + sector_buffer[TSL_OFFSET_H]=get_high_byte((i-122)*256); + sector_buffer[TSL_OFFSET_L]=get_low_byte((i-122)*256); + + /* write out the old t/s list with updated info */ + lseek(fd, + DISK_OFFSET(get_high_byte(old_ts_list), + get_low_byte(old_ts_list)), + SEEK_SET); + + result=write(fd,sector_buffer,BYTES_PER_SECTOR); + } + } + + /* allocate a sector */ + data_ts=dos33_allocate_sector(fd); sectors_used++; - if (ts_list<0) return -1; - /* clear the t/s sector */ - for(x=0;x>8)&0xff,ts_list&0xff),SEEK_SET); - result=write(fd,sector_buffer,BYTES_PER_SECTOR); - - if (i==0) initial_ts_list=ts_list; - else { - /* we aren't the first t/s list so do special stuff */ + if (data_ts<0) return -1; - /* load in the old t/s list */ - lseek(fd, - DISK_OFFSET(get_high_byte(old_ts_list), - get_low_byte(old_ts_list)), - SEEK_SET); + /* clear sector */ + for(x=0;x>8)&0xff; + sector_buffer[2]=(length)&0xff; + sector_buffer[3]=((length)>>8)&0xff; + bytes_read=read(input_fd,sector_buffer+4, + BYTES_PER_SECTOR-4); + bytes_read+=4; + } + else { + bytes_read=read(input_fd,sector_buffer, + BYTES_PER_SECTOR); + } + first_write=0; - result=write(fd,sector_buffer,BYTES_PER_SECTOR); - } - } - - - /* allocate a sector */ - data_ts=dos33_allocate_sector(fd); - sectors_used++; - - if (data_ts<0) return -1; - - /* clear sector */ - for(x=0;x>8)&0xff,data_ts&0xff),SEEK_SET); + result=write(fd,sector_buffer,BYTES_PER_SECTOR); - /* write to disk image */ - lseek(fd,DISK_OFFSET((data_ts>>8)&0xff,data_ts&0xff),SEEK_SET); - result=write(fd,sector_buffer,BYTES_PER_SECTOR); -// printf("Writing %i bytes to %i/%i\n",bytes_read,(data_ts>>8)&0xff, -// data_ts&0xff); - + if (debug) printf("Writing %i bytes to %i/%i\n", + bytes_read,(data_ts>>8)&0xff,data_ts&0xff); - - /* add to T/s table */ - - /* read in t/s list */ - lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET); - result=read(fd,sector_buffer,BYTES_PER_SECTOR); - - /* point to new data sector */ - sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST]=(data_ts>>8)&0xff; - sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST+1]=(data_ts&0xff); - - /* write t/s list back out */ - lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET); - result=write(fd,sector_buffer,BYTES_PER_SECTOR); - - i++; - } + /* add to T/s table */ + + /* read in t/s list */ + lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET); + result=read(fd,sector_buffer,BYTES_PER_SECTOR); + + /* point to new data sector */ + sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST]=(data_ts>>8)&0xff; + sector_buffer[((i%TSL_MAX_NUMBER)*2)+TSL_LIST+1]=(data_ts&0xff); + + /* write t/s list back out */ + lseek(fd,DISK_OFFSET((ts_list>>8)&0xff,ts_list&0xff),SEEK_SET); + result=write(fd,sector_buffer,BYTES_PER_SECTOR); + + i++; + } /* Add new file to Catalog */ @@ -632,43 +660,43 @@ continue_parsing_catalog: goto continue_parsing_catalog; -got_a_dentry: -// printf("Adding file at entry %i of catalog 0x%x:0x%x\n", -// i,catalog_track,catalog_sector); - - /* Point entry to initial t/s list */ - sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)]=(initial_ts_list>>8)&0xff; - sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+1]=(initial_ts_list&0xff); - /* set file type */ - sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_TYPE]= - dos33_char_to_type(type,0); +got_a_dentry: +// printf("Adding file at entry %i of catalog 0x%x:0x%x\n", +// i,catalog_track,catalog_sector); -// printf("Pointing T/S to %x/%x\n",(initial_ts_list>>8)&0xff,initial_ts_list&0xff); + /* Point entry to initial t/s list */ + sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)]=(initial_ts_list>>8)&0xff; + sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+1]=(initial_ts_list&0xff); + /* set file type */ + sector_buffer[CATALOG_FILE_LIST+(i*CATALOG_ENTRY_SIZE)+FILE_TYPE]= + dos33_char_to_type(dos_type,0); - /* copy over filename */ - for(x=0;x>8)&0xff; - - /* write out catalog sector */ - lseek(fd,DISK_OFFSET(catalog_track,catalog_sector),SEEK_SET); - result=write(fd,sector_buffer,BYTES_PER_SECTOR); +// printf("Pointing T/S to %x/%x\n",(initial_ts_list>>8)&0xff,initial_ts_list&0xff); - if (result<0) fprintf(stderr,"Error on I/O\n"); - - return 0; + /* copy over filename */ + for(x=0;x>8)&0xff; + + /* write out catalog sector */ + lseek(fd,DISK_OFFSET(catalog_track,catalog_sector),SEEK_SET); + result=write(fd,sector_buffer,BYTES_PER_SECTOR); + + if (result<0) fprintf(stderr,"Error on I/O\n"); + + return 0; } /* load a file. fts=entry/track/sector */ @@ -1174,10 +1202,13 @@ static int dos33_rename_hello(int fd, char *new_name) { return 0; } -static int display_help(char *name) { +static void display_help(char *name, int version_only) { printf("\ndos33 version %s\n",VERSION); printf("by Vince Weaver \n"); printf("\n"); + + if (version_only) return; + printf("Usage: %s [-h] [-y] disk_image COMMAND [options]\n",name); printf("\t-h : this help message\n"); printf("\t-y : always answer yes for anying warning questions\n"); @@ -1187,7 +1218,7 @@ static int display_help(char *name) { printf("\tCATALOG\n"); printf("\tLOAD apple_file \n"); printf("\tSAVE type local_file \n"); - printf("\tBSAVE type local_file \n"); + printf("\tBSAVE [-a addr] [-l len] local_file \n"); printf("\tDELETE apple_file\n"); printf("\tLOCK apple_file\n"); printf("\tUNLOCK apple_file\n"); @@ -1200,24 +1231,26 @@ static int display_help(char *name) { printf("\tCOPY\n"); #endif printf("\n"); - return 0; + return; } -#define COMMAND_UNKNOWN 0 -#define COMMAND_LOAD 1 -#define COMMAND_SAVE 2 -#define COMMAND_CATALOG 3 -#define COMMAND_DELETE 4 -#define COMMAND_UNDELETE 5 -#define COMMAND_LOCK 6 -#define COMMAND_UNLOCK 7 -#define COMMAND_INIT 8 -#define COMMAND_RENAME 9 -#define COMMAND_COPY 10 -#define COMMAND_DUMP 11 -#define COMMAND_HELLO 12 -#define COMMAND_BSAVE 13 +#define COMMAND_LOAD 0 +#define COMMAND_SAVE 1 +#define COMMAND_CATALOG 2 +#define COMMAND_DELETE 3 +#define COMMAND_UNDELETE 4 +#define COMMAND_LOCK 5 +#define COMMAND_UNLOCK 6 +#define COMMAND_INIT 7 +#define COMMAND_RENAME 8 +#define COMMAND_COPY 9 +#define COMMAND_DUMP 10 +#define COMMAND_HELLO 11 +#define COMMAND_BSAVE 12 +#define COMMAND_BLOAD 13 + #define MAX_COMMAND 14 +#define COMMAND_UNKNOWN 255 static struct command_type { int type; @@ -1242,7 +1275,7 @@ static int lookup_command(char *name) { int which=COMMAND_UNKNOWN,i; - for(i=1;i30) { + fprintf(stderr,"Warning! Truncating %s to 30 chars\n",in); + truncated=1; + } + strncpy(out,in,30); + out[30]='\0'; + + return truncated; +} + int main(int argc, char **argv) { char image[BUFSIZ]; @@ -1261,85 +1309,105 @@ int main(int argc, char **argv) { int command,catalog_entry; char temp_string[BUFSIZ]; char apple_filename[31],new_filename[31]; - char output_filename[BUFSIZ]; + char local_filename[BUFSIZ]; char *result_string; - int always_yes=0,firstarg=1,extra_ops=0; + int always_yes=0; + char *temp,*endptr; + int c; + int address=0, length=0; /* Check command line arguments */ - /* Ugh I should use getopt() or something similar here */ + while ((c = getopt (argc, argv,"a:l:hvy"))!=-1) { + switch (c) { - if (argc<2) { - display_help(argv[0]); - goto exit_program; + case 'a': + address=strtol(optarg,&endptr,0); + if (debug) printf("Address=%d\n",address); + break; + case 'l': + length=strtol(optarg,&endptr,0); + if (debug) printf("Length=%d\n",address); + break; + case 'v': + display_help(argv[0],1); + return 0; + case 'h': display_help(argv[0],0); + return 0; + case 'y': + always_yes=1; + break; + } } - if (!strncmp(argv[1],"-h",2)) { - display_help(argv[1]); - goto exit_program; - } - - if (!strncmp(argv[1],"-y",2)) { - always_yes=1; - extra_ops++; - firstarg++; - } - - if (argc<3) { - printf("\nInvalid arguments!\n"); - display_help(argv[0]); - goto exit_program; + if (optind==argc) { + fprintf(stderr,"ERROR! Must specify disk image!\n\n"); + return -1; } /* get argument 1, which is image name */ - strncpy(image,argv[firstarg],BUFSIZ); + strncpy(image,argv[optind],BUFSIZ); dos_fd=open(image,O_RDWR); if (dos_fd<0) { fprintf(stderr,"Error opening disk_image: %s\n",image); - exit(4); + return -1; } - /* Check argument #2 which is command */ - strncpy(temp_string,argv[firstarg+1],BUFSIZ); + /* Move to next argument */ + optind++; + + if (optind==argc) { + fprintf(stderr,"ERROR! Must specify command!\n\n"); + return -2; + } + + /* Grab command */ + strncpy(temp_string,argv[optind],BUFSIZ); /* Make command be uppercase */ for(i=0;i30) { - fprintf(stderr,"Warning! Truncating %s to 30 chars\n", - argv[firstarg+2]); - } - strncpy(apple_filename,argv[firstarg+2],30); - apple_filename[30]='\0'; + + truncate_filename(apple_filename,argv[optind]); + + if (debug) printf("\tApple filename: %s\n",apple_filename); /* get output filename */ - if (argc==5+extra_ops) { - strncpy(output_filename,argv[firstarg+3],BUFSIZ); + optind++; + if (argc>=optind) { + strncpy(local_filename,argv[optind],BUFSIZ); } else { - strncpy(output_filename,apple_filename,30); + strncpy(local_filename,apple_filename,30); } + if (debug) printf("\tOutput filename: %s\n",local_filename); + + /* get the entry/track/sector for file */ catalog_entry=dos33_check_file_exists(dos_fd, apple_filename, @@ -1350,243 +1418,276 @@ int main(int argc, char **argv) { goto exit_and_close; } - dos33_load_file(dos_fd,catalog_entry,output_filename); + dos33_load_file(dos_fd,catalog_entry,local_filename); break; case COMMAND_CATALOG: - /* get first catalog */ - catalog_entry=dos33_get_catalog_ts(dos_fd); + /* get first catalog */ + catalog_entry=dos33_get_catalog_ts(dos_fd); - printf("\nDISK VOLUME %i\n\n",sector_buffer[VTOC_DISK_VOLUME]); - while(catalog_entry>0) { - catalog_entry=dos33_find_next_file(dos_fd,catalog_entry); - if (catalog_entry>0) { - dos33_print_file_info(dos_fd,catalog_entry); - catalog_entry+=(1<<16); - /* dos33_find_next_file() handles wrapping issues */ - } - } - printf("\n"); - break; + printf("\nDISK VOLUME %i\n\n",sector_buffer[VTOC_DISK_VOLUME]); + while(catalog_entry>0) { + catalog_entry=dos33_find_next_file(dos_fd,catalog_entry); + if (catalog_entry>0) { + dos33_print_file_info(dos_fd,catalog_entry); + /* why 1<<16 ? */ + catalog_entry+=(1<<16); + /* dos33_find_next_file() handles wrapping issues */ + } + } + printf("\n"); + break; case COMMAND_SAVE: /* argv3 == type == A,B,T,I,N,L etc */ /* argv4 == name of local file */ /* argv5 == optional name of file on disk image */ - if (argc<5+extra_ops) { + if (argc==optind) { fprintf(stderr,"Error! Need type and file_name\n"); fprintf(stderr,"%s %s SAVE type " - "file_name apple_filename\n", + "file_name apple_filename\n\n", argv[0],image); goto exit_and_close; } - type=argv[firstarg+2][0]; + type=argv[optind][0]; + optind++; + + case COMMAND_BSAVE: + + if (debug) printf("\ttype=%c\n",type); + + if (argc==optind) { + fprintf(stderr,"Error! Need file_name\n"); + + if (command==COMMAND_BSAVE) { + fprintf(stderr,"%s %s BSAVE " + "file_name apple_filename\n\n", + argv[0],image); - if (argc==6+extra_ops) { - if (strlen(argv[firstarg+4])>30) { - fprintf(stderr, - "Warning! Truncating filename " - "to 30 chars!\n"); } - strncpy(apple_filename,argv[firstarg+4],30); - apple_filename[30]=0; + else { + fprintf(stderr,"%s %s SAVE type " + "file_name apple_filename\n\n", + argv[0],image); + } + goto exit_and_close; + } + + strncpy(local_filename,argv[optind],BUFSIZ); + optind++; + + if (debug) printf("\tLocal filename: %s\n",local_filename); + + if (argc>optind) { + /* apple filename specified */ + truncate_filename(apple_filename,argv[optind]); } else { /* If no filename specified for apple name */ /* Then use the input name. Note, we strip */ /* everything up to the last slash so useless */ /* path info isn't used */ - { - char *temp; - temp=argv[firstarg+3]+(strlen(argv[firstarg+3])-1); - - while(temp!=argv[firstarg+3]) { - temp--; - if (*temp == '/') { - temp++; - break; - } - } - - if (strlen(temp)>30) { - fprintf(stderr, - "Warning! Truncating filename to 30 chars!\n"); - } - - strncpy(apple_filename,temp,30); - apple_filename[30]=0; - } - } - - catalog_entry=dos33_check_file_exists(dos_fd,apple_filename, - FILE_NORMAL); - - if (catalog_entry>=0) { - fprintf(stderr,"Warning! %s exists!\n",apple_filename); - if (!always_yes) { - printf("Over-write (y/n)?"); - result_string=fgets(temp_string,BUFSIZ,stdin); - if ((result_string==NULL) || (temp_string[0]!='y')) { - printf("Exiting early...\n"); - goto exit_and_close; - } - } - fprintf(stderr,"Deleting previous version...\n"); - dos33_delete_file(dos_fd,catalog_entry); - } - dos33_add_file(dos_fd,type,argv[firstarg+3],apple_filename); + temp=local_filename+(strlen(local_filename)-1); + + while(temp!=local_filename) { + temp--; + if (*temp == '/') { + temp++; + break; + } + } + + truncate_filename(apple_filename,temp); + } + + if (debug) printf("\tApple filename: %s\n",apple_filename); + + catalog_entry=dos33_check_file_exists(dos_fd,apple_filename, + FILE_NORMAL); + + if (catalog_entry>=0) { + fprintf(stderr,"Warning! %s exists!\n",apple_filename); + if (!always_yes) { + printf("Over-write (y/n)?"); + result_string=fgets(temp_string,BUFSIZ,stdin); + if ((result_string==NULL) || (temp_string[0]!='y')) { + printf("Exiting early...\n"); + goto exit_and_close; + } + } + fprintf(stderr,"Deleting previous version...\n"); + dos33_delete_file(dos_fd,catalog_entry); + } + if (command==COMMAND_SAVE) { + dos33_add_file(dos_fd,type, + ADD_RAW, address, length, + local_filename,apple_filename); + } + else { + dos33_add_file(dos_fd,type, + ADD_BINARY, address, length, + local_filename,apple_filename); + } + break; + + case COMMAND_DELETE: + + if (argc==optind) { + fprintf(stderr,"Error! Need file_name\n"); + fprintf(stderr,"%s %s DELETE apple_filename\n", + argv[0],image); + goto exit_and_close; + } + + truncate_filename(apple_filename,argv[optind]); + + catalog_entry=dos33_check_file_exists(dos_fd, + apple_filename, + FILE_NORMAL); + if (catalog_entry<0) { + fprintf(stderr, "Error! File %s does not exist\n", + apple_filename); + goto exit_and_close; + } + dos33_delete_file(dos_fd,catalog_entry); break; - case COMMAND_DELETE: - if (argc+extra_ops<4) { - fprintf(stderr,"Error! Need file_name\n"); - fprintf(stderr,"%s %s DELETE apple_filename\n",argv[0],image); - goto exit_and_close; - } - catalog_entry=dos33_check_file_exists(dos_fd,argv[firstarg+2], - FILE_NORMAL); - if (catalog_entry<0) { - fprintf(stderr, - "Error! File %s does not exist\n",argv[firstarg+2]); - goto exit_and_close; - } - dos33_delete_file(dos_fd,catalog_entry); - break; - - case COMMAND_DUMP: - printf("Dumping %s!\n",argv[firstarg]); - dos33_dump(dos_fd); - break; - - case COMMAND_LOCK: - case COMMAND_UNLOCK: - /* check and make sure we have apple_filename */ - if (argc<4+extra_ops) { - fprintf(stderr,"Error! Need apple file_name\n"); - fprintf(stderr,"%s %s LOCK apple_filename\n",argv[0],image); - goto exit_and_close; - } - - /* Truncate filename if too long */ - if (strlen(argv[firstarg+2])>30) { - fprintf(stderr, - "Warning! Truncating %s to 30 chars\n",argv[firstarg+2]); - } - strncpy(apple_filename,argv[firstarg+2],30); - apple_filename[30]='\0'; - - /* get the entry/track/sector for file */ - catalog_entry=dos33_check_file_exists(dos_fd, - apple_filename, - FILE_NORMAL); - if (catalog_entry<0) { - fprintf(stderr,"Error! %s not found!\n",apple_filename); - goto exit_and_close; - } + case COMMAND_DUMP: + printf("Dumping %s!\n",image); + dos33_dump(dos_fd); + break; - dos33_lock_file(dos_fd,catalog_entry,command==COMMAND_LOCK); - - break; - - case COMMAND_RENAME: - /* check and make sure we have apple_filename */ - if (argc<5+extra_ops) { - fprintf(stderr,"Error! Need two filenames\n"); - fprintf(stderr,"%s %s LOCK apple_filename_old " - "apple_filename_new\n", - argv[0],image); - goto exit_and_close; - } - - /* Truncate filename if too long */ - if (strlen(argv[firstarg+2])>30) { - fprintf(stderr, - "Warning! Truncating %s to 30 chars\n",argv[firstarg+2]); - } - strncpy(apple_filename,argv[firstarg+2],30); - apple_filename[30]='\0'; - - /* Truncate filename if too long */ - if (strlen(argv[firstarg+3])>30) { - fprintf(stderr, - "Warning! Truncating %s to 30 chars\n",argv[firstarg+3]); - } - strncpy(new_filename,argv[firstarg+3],30); - new_filename[30]='\0'; - - /* get the entry/track/sector for file */ - catalog_entry=dos33_check_file_exists(dos_fd, - apple_filename, - FILE_NORMAL); - if (catalog_entry<0) { - fprintf(stderr,"Error! %s not found!\n",apple_filename); - goto exit_and_close; - } + case COMMAND_LOCK: + case COMMAND_UNLOCK: + /* check and make sure we have apple_filename */ + if (argc==optind) { + fprintf(stderr,"Error! Need apple file_name\n"); + fprintf(stderr,"%s %s %s apple_filename\n", + argv[0],image,temp_string); + goto exit_and_close; + } - dos33_rename_file(dos_fd,catalog_entry,new_filename); - - break; + truncate_filename(apple_filename,argv[optind]); + + /* get the entry/track/sector for file */ + catalog_entry=dos33_check_file_exists(dos_fd, + apple_filename, + FILE_NORMAL); + if (catalog_entry<0) { + fprintf(stderr,"Error! %s not found!\n", + apple_filename); + goto exit_and_close; + } + + dos33_lock_file(dos_fd,catalog_entry,command==COMMAND_LOCK); + + break; + + case COMMAND_RENAME: + /* check and make sure we have apple_filename */ + if (argc==optind) { + fprintf(stderr,"Error! Need two filenames\n"); + fprintf(stderr,"%s %s LOCK apple_filename_old " + "apple_filename_new\n", + argv[0],image); + goto exit_and_close; + } + + /* Truncate filename if too long */ + truncate_filename(apple_filename,argv[optind]); + optind++; + + if (argc==optind) { + fprintf(stderr,"Error! Need two filenames\n"); + fprintf(stderr,"%s %s LOCK apple_filename_old " + "apple_filename_new\n", + argv[0],image); + goto exit_and_close; + } + + truncate_filename(new_filename,argv[optind]); + + /* get the entry/track/sector for file */ + catalog_entry=dos33_check_file_exists(dos_fd, + apple_filename, + FILE_NORMAL); + if (catalog_entry<0) { + fprintf(stderr,"Error! %s not found!\n", + apple_filename); + goto exit_and_close; + } + + dos33_rename_file(dos_fd,catalog_entry,new_filename); + + break; case COMMAND_UNDELETE: /* check and make sure we have apple_filename */ - if (argc<4) { + if (argc==optind) { fprintf(stderr,"Error! Need apple file_name\n"); - fprintf(stderr,"%s %s LOCK apple_filename\n",argv[0],image); + fprintf(stderr,"%s %s UNDELETE apple_filename\n\n", + argv[0],image); goto exit_and_close; } /* Truncate filename if too long */ /* what to do about last char ? */ - if (strlen(argv[firstarg+2])>30) { - fprintf(stderr, - "Warning! Truncating %s to 30 chars\n",argv[firstarg+2]); - } - strncpy(apple_filename,argv[firstarg+2],30); - apple_filename[30]='\0'; + + truncate_filename(apple_filename,argv[optind]); /* get the entry/track/sector for file */ catalog_entry=dos33_check_file_exists(dos_fd, apple_filename, FILE_DELETED); if (catalog_entry<0) { - fprintf(stderr,"Error! %s not found!\n",apple_filename); + fprintf(stderr,"Error! %s not found!\n", + apple_filename); goto exit_and_close; } dos33_undelete_file(dos_fd,catalog_entry,apple_filename); break; - case COMMAND_HELLO: - if (argc+extra_ops<4) { - fprintf(stderr,"Error! Need file_name\n"); - fprintf(stderr,"%s %s HELLO apple_filename\n",argv[0],image); - goto exit_and_close; - } - catalog_entry=dos33_check_file_exists(dos_fd,argv[firstarg+2], - FILE_NORMAL); - if (catalog_entry<0) { - fprintf(stderr, - "Warning! File %s does not exist\n",argv[firstarg+2]); - } - dos33_rename_hello(dos_fd,argv[firstarg+2]); - break; - case COMMAND_INIT: - /* use common code from mkdos33fs? */ - case COMMAND_COPY: - /* use temp file? Walking a sector at a time seems a pain */ - default: - fprintf(stderr,"Sorry, unsupported command\n"); + + case COMMAND_HELLO: + if (argc==optind) { + fprintf(stderr,"Error! Need file_name\n"); + fprintf(stderr,"%s %s HELLO apple_filename\n\n", + argv[0],image); goto exit_and_close; + } + + truncate_filename(apple_filename,argv[optind]); + + catalog_entry=dos33_check_file_exists(dos_fd, + apple_filename, + FILE_NORMAL); + + if (catalog_entry<0) { + fprintf(stderr, + "Warning! File %s does not exist\n", + apple_filename); + } + dos33_rename_hello(dos_fd,apple_filename); + break; + + case COMMAND_INIT: + /* use common code from mkdos33fs? */ + case COMMAND_COPY: + /* use temp file? Walking a sector at a time seems a pain */ + default: + fprintf(stderr,"Sorry, unsupported command %s\n\n",temp_string); + goto exit_and_close; } exit_and_close: close(dos_fd); -exit_program: + return 0; } diff --git a/dos33fs-utils/tests/TODO b/dos33fs-utils/tests/TODO index c4b5b9ab..2fa2e41a 100644 --- a/dos33fs-utils/tests/TODO +++ b/dos33fs-utils/tests/TODO @@ -1,2 +1,4 @@ +Test hello +Test init Test copy Test over-writing existing file diff --git a/ethernet/Makefile b/ethernet/Makefile index a2f5259b..b8f956ba 100644 --- a/ethernet/Makefile +++ b/ethernet/Makefile @@ -4,38 +4,33 @@ MAKEB = ../dos33fs-utils/make_b all: ethernet.dsk +memcpy: memcpy.o + ld65 -o memcpy memcpy.o -t none + +memcpy.o: memcpy.s + ca65 -o memcpy.o memcpy.s -l memcpy.lst + SETUP.BAS: setup.bas $(TXT2BAS) < setup.bas > SETUP.BAS WEBSERVER.BAS: webserver.bas $(TXT2BAS) < webserver.bas > WEBSERVER.BAS -about.html: ./c/about.html - $(MAKEB) ./c/about.html about.html 0xc000 - -index.html: ./c/index.html - $(MAKEB) ./c/index.html index.html 0xc000 - -favicon.ico: ./c/favicon.ico - $(MAKEB) ./c/favicon.ico favicon.ico 0xc000 - -vmw_logo.png: ./c/vmw_logo.png - $(MAKEB) ./c/vmw_logo.png vmw_logo.png 0xc000 - R.TXT: request.txt $(MAKEB) request.txt R.TXT 0xc000 ethernet.dsk: SETUP.BAS \ WEBSERVER.BAS \ R.TXT \ - about.html index.html favicon.ico vmw_logo.png + ./c/about.html ./c/index.html ./c/favicon.ico ./c/vmw_logo.png $(DOS33) -y ethernet.dsk SAVE A SETUP.BAS $(DOS33) -y ethernet.dsk SAVE A WEBSERVER.BAS - $(DOS33) -y ethernet.dsk SAVE B R.TXT - $(DOS33) -y ethernet.dsk SAVE B about.html - $(DOS33) -y ethernet.dsk SAVE B index.html - $(DOS33) -y ethernet.dsk SAVE B favicon.ico - $(DOS33) -y ethernet.dsk SAVE B vmw_logo.png + $(DOS33) -y ethernet.dsk BSAVE R.TXT + $(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/about.html + $(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/index.html + $(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/favicon.ico + $(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/vmw_logo.png clean: - rm -f *~ *.BAS R.TXT + rm -f *~ *.BAS R.TXT *.o *.lst memcpy + diff --git a/ethernet/README b/ethernet/README index 8ebd484f..fd219978 100644 --- a/ethernet/README +++ b/ethernet/README @@ -1,2 +1,29 @@ Working on getting the Uthernet II card to do something interesting. + http://a2retrosystems.com/ + +Hardware Background: + + This board has a WIZnet W5100 on board. You can get raw Ethernet + packets on the board, but I am using it in hardware TCP/IP mode + where I set up the MAC/IP and then get raw packets from a TCP socket + (up to 4 sockets can be active at once). + +Webserver: + Included is a webserver written for Fall 2015 ECE435 + + It is written entirely in Applesoft BASIC + + It runs very slowly, but works. + + firefox and wget can get files just fine, + although they tend to send duplicate requests for some reason. + + You can serve arbitrary png, jpg, txt, or html files, however + they currently have to be less than 8kB. + + Much of the slowness is using peek/poke as a memcpy routine. + + Of course this would all be faster in assembly language, but + what's the fun of that. + diff --git a/ethernet/ethernet.dsk b/ethernet/ethernet.dsk index f1b2d629..7a680598 100644 Binary files a/ethernet/ethernet.dsk and b/ethernet/ethernet.dsk differ diff --git a/ethernet/memcpy.s b/ethernet/memcpy.s new file mode 100644 index 00000000..492f9752 --- /dev/null +++ b/ethernet/memcpy.s @@ -0,0 +1,66 @@ +.define EQU = + +PTR EQU $06 +PTRH EQU $07 + +WRAPL EQU $08 +WRAPH EQU $09 + +SIZEL EQU $0A +SIZEH EQU $0B + +tx_copy: + + lda #0 ; always copying from 0x4000 + sta PTR + lda #$40 + sta PTR+1 + + ldx #SIZEH ; number of 256-byte blocks + beq copy_remainder ; if none, skip ahead + + ldy #0 +copy256: + lda (PTR),y + sta $C0B7 ; change based on uthernet slot + + cmp WRAPH,x + bne nowrap256 + + cmp WRAPL,y + bne nowrap256 + + lda #$40 + sta $C0B5 + lda #$00 + sta $C0B6 ; wrap tx buffer address to 0x4000 + +nowrap256: + iny + bne copy256 + + inc PTR+1 ; update 16-bit pointer + dex ; finish a 256 byte block + bne copy256 + + ldx #SIZEL +copy_remainder: + lda (PTR),y + sta $C0B7 ; change based on uthernet slot + + cmp WRAPL,y + bne nowrap_r + + lda #$40 + sta $C0B5 + lda #$00 + sta $C0B6 ; wrap tx buffer address to 0x4000 + +nowrap_r: + iny + dex + bne copy_remainder + + rts + + diff --git a/ethernet/memcpy.txt b/ethernet/memcpy.txt new file mode 100644 index 00000000..27cff51b --- /dev/null +++ b/ethernet/memcpy.txt @@ -0,0 +1,46 @@ +Test 1: + 5 FOR J=1 to 1000: NEXT J + 10 PRINT CHR$(7) + 20 FOR I=16384 to 20479 + 30 POKE 20480,PEEK(I) + 40 NEXT I + 100 PRINT CHR$(7) + + Time (linapple2) 38s + +All one one line + + 5 FOR J=1 to 1000: NEXT J + 10 PRINT CHR$(7) + 20 FOR I=16384 to 20479 + 30 POKE 20480,PEEK(I) + 40 NEXT I + 100 PRINT CHR$(7) + + Time (linapple2) 37s + +Assembly language: + + PTR EQU $06 + + lda #0 + sta PTR + lda #$40 + sta PTR+1 + + ldx #8 + ldy #0 +copy_loop: + lda (PTR),y + sta $5000 + iny + bne copy_loop + dex + bne copy_loop + + rts + +Runs more or less instantaenously + + + diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 2d6c5f33..dd4619a8 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -1,30 +1,48 @@ +' Applesoft BASIC Webserver +' by Vince Weaver +' 1 REM *** Setup UTHERNET II - W5100 -2 REM *** Assumes slot 5 ($C0D0) -3 SLOT=49360: REM *** $C0D0 -4 MR=SLOT+4: REM *** MODE REGISTER C0D4 -5 HA=SLOT+5:LA=SLOT+6: REM *** HIGH/LOW ADDR $C0D5,$C0D6 -7 DP=SLOT+7: REM *** DATA PORT $C0D7 +' SLOT0=$C080 49280 SLOT4=$C0C0 49344 +' SLOT1=$C090 49296 SLOT5=$C0D0 49360 +' SLOT2=$C0A0 49312 SLOT6=$C0E0 49376 +' SLOT3=$C0B0 49328 SLOT7=$C0F0 49392 +' +' Set up the memory addresses to use +' +2 REM *** OURS IS IN SLOT3 ($C0B0) +3 SLOT=49328: REM *** $C0B0 +4 MR=SLOT+4: REM *** MODE REGISTER C0B4 +5 HA=SLOT+5:LA=SLOT+6: REM *** HIGH/LOW ADDR $C0B5,$C0B6 +7 DP=SLOT+7: REM *** DATA PORT $C0B7 +' +' Init the W5100 +' 10 REM *** Init W5100 12 POKE MR,128 : REM RESET W5100 14 POKE MR,3 : REM AUTOINCREMENT -20 REM *** Setup MAC Address -21 REM *** 41:50:50:4c:45:32 +20 REM *** Setup MAC Address 41:50:50:4c:45:32 22 POKE HA,0:POKE LA,9 -23 POKE DP,65 -23 POKE DP,80 -23 POKE DP,80 -23 POKE DP,76 -23 POKE DP,69 -23 POKE DP,50 -30 REM *** Setup IP Address -31 REM *** 192.168.8.15 +23 POKE DP,65:POKE DP,80:POKE DP,80:POKE DP,76:POKE DP,69:POKE DP,50 +30 REM *** Setup IP Address 192.168.8.15 32 POKE LA,15 -33 POKE DP,192 -34 POKE DP,168 -35 POKE DP,8 -36 POKE DP,15 +33 POKE DP,192:POKE DP,168:POKE DP,8:POKE DP,15 40 PRINT "UTHERNET II READY: 192.168.8.15" -100 REM *** Setup Socket +' +' Setup Machine Language Memcpy routine +' NOTE! This code assumes the Uthernet is in slot 3 +' FIXME: patch on the fly once it works +' See Appendix 1 at the end of this for more details +' +50 FOR I=0 TO 72: READ X: POKE 768+I,X:NEXT I +51 DATA 169,0,133,6,169,64,133,7,162,11,240,36,160,0,177,6 +52 DATA 141,183,192,213,9,208,15,217,8,0,208,10,169,64,141,181 +53 DATA 192,169,0,141,182,192,200,208,229,230,7,202,208,224,162,10 +54 DATA 177,6,141,183,192,217,8,0,208,10,169,64,141,181,192,169 +55 DATA 0,141,182,192,200,202,208,232,96 +' +' Setup Socket 0 +' +100 REM *** Setup Socket 0 102 PRINT "** Setting up Socket 0" 105 POKE HA,0:POKE LA,26: REM RX MEMSIZE 110 POKE DP,3: REM 8kB RX buffer @@ -36,106 +54,353 @@ 303 PRINT "** Setting up to use TCP port 80" 305 POKE HA,4: POKE LA,4: REM *** 0x404 port 310 POKE DP,0:POKE DP, 80: REM *** http port 80 +' +' OPEN the socket +' 400 REM *** OPEN socket 404 PRINT "** OPENing socket" 405 POKE HA,4: POKE LA,1: REM *** 0x401 command register 410 POKE DP, 1: REM *** OPEN ' +' Check return value +' 500 REM *** Check if opened 505 POKE HA,4: POKE LA,3: REM *** 0x403 status register 510 RE=PEEK(DP) 515 PRINT "** STATUS IS ";RE; 520 IF RE=19 THEN PRINT " OPENED":GOTO 600 -530 IF RE=0 THEN PRINT " CLOSED, ERROR" -540 POKE HA,4: POKE LA,1: REM *** 0x401 command register -550 POKE DP, 16: REM *** CLOSE -560 END +530 IF RE=0 THEN PRINT " CLOSED, ERROR": GOTO 5000 +540 PRINT "UNKNOWN ERROR ";RE +550 GOTO 5000 +' +' LISTEN on the socket ' 600 REM *** Connection opened, Listen 605 POKE HA,4: POKE LA,1: REM *** 0x401 command register 610 POKE DP, 2: REM *** LISTEN +' +' Check return value +' 620 REM *** Check if successful 625 POKE HA,4: POKE LA,3: REM *** 0x403 status register 630 RE=PEEK(DP) 635 PRINT "** STATUS IS ";RE; 640 IF RE=20 THEN PRINT " LISTENING":GOTO 700 -650 IF RE=0 THEN PRINT " CLOSED, ERROR" -655 PRINT "UNKNOWN" -660 POKE HA,4: POKE LA,1: REM *** 0x401 command register -670 POKE DP, 16: REM *** CLOSE -675 END +650 IF RE=0 THEN PRINT " CLOSED, ERROR":GOTO 5000 +655 PRINT "UNKNOWN ERROR ";RE +675 GOTO 5000 +' +' Wait for incoming connection ' 700 REM *** Wait for incoming connection 705 POKE HA,4: POKE LA,1: REM *** 0x401 command register 710 POKE DP, 2: REM *** LISTEN +' +' Check for result +' 720 REM *** Check if successful 725 POKE HA,4: POKE LA,3: REM *** 0x403 status register 730 RE=PEEK(DP) -740 IF RE=23 THEN GOTO 800 -745 IF RE<>20 THEN PRINT "WAITING: STATUS=";RE +740 IF RE=23 THEN GOTO 800: REM ESTABLISHED +745 IF RE<>20 THEN PRINT "WAITING: UNEXPECTED STATUS=";RE 750 GOTO 700: REM *** Repeat until connected ' -800 PRINT "CONNECTED" +' Established, repeat waiting for incoming data +' +800 PRINT "ESTABLISHED" 802 POKE HA,4: POKE LA,38: REM *** 0x426 Received Size 805 SH=PEEK(DP):SL=PEEK(DP) 810 SI=(SH*256)+SL 820 IF SI<>0 THEN GOTO 900 +' +' Should we delay? busy polling seems wasteful +' 830 REM DELAY? -840 GOTO 800 +840 GOTO 802 +' +' We have some data, let's read it ' 900 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr 905 OH=PEEK(DP):OL=PEEK(DP) -910 RO=(OH*256)+OL -920 REM *** SHOULD MASK WITH 0x1ff but how? -930 RA=RO+24576:REM $6000 -940 PRINT "READ OFFSET=";RO;" READ ADDRESS=";RA;" READ SIZE=";SI +910 RF=(OH*256)+OL +920 REM *** MASK WITH 0x1ff +925 R%=RF/8192:RM=RF-(8192*R%) +930 RA=RM+24576:REM $6000 +940 PRINT "READ OFFSET=";RM;" READ ADDRESS=";RA;" READ SIZE=";SI +' +' Check for buffer wraparound +' +942 BW=0 +945 IF (SI+TA>=32768) THEN BW=1:BO=32768-TA:PRINT "RX BUFFER WRAPAROUND IN ";BO +' +' Print received packet ' 1000 REM *** PRINT PACKET -1005 POKE HA,RA/256: POKE LA,RA-((RA/256)*256) +1001 FL=1:FL$="" +1003 R%=RA/256 +1005 POKE HA,R%: POKE LA,RA-(R%*256) 1010 FOR I=1 TO SI -1020 C=PEEK(DP) -1030 IF C<>13 THEN PRINT CHR$(C); +1020 C=PEEK(DP):C$=CHR$(C) +1025 IF FL=1 THEN FL$=FL$+C$ +1027 IF C=10 THEN FL=0 +1030 IF C<>10 THEN PRINT C$; +1032 IF BW=0 THEN GOTO 1040 +1033 BO=BO-1: IF BO=0 THEN POKE HA,96:POKE LA,0:BW=0 1040 NEXT I ' +' Deal with first line +' +1050 PRINT "FIRST LINE=";FL$ +1060 IF LEFT$(FL$,3)<>"GET" GOTO 7000 +1065 N$="" +1070 FOR I=6 TO LEN(FL$) +1075 M$=MID$(FL$,I,1) +1080 IF M$=" " GOTO 1090 +1085 N$=N$+M$ +1087 NEXT I +1090 IF N$="" THEN N$="index.html" +1095 PRINT "SENDING FILE: ";N$ +' ' TODO: handle wraparound of 8kb buffer ' +' +' Update read pointer +' 1100 REM *** Update read pointer -'"HTTP/1.1 200 OK\r\n" -'"Date: %s\r\n" -'"Server: VMW-web\r\n" -'"Last-Modified: %s\r\n" -'"Content-Length: %ld\r\n" -'"Content-Type: %s\r\n" -'"\r\n", -1200 REM *** SEND RESPONSE -1205 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10) -1210 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10) -1220 A$=A$+"Content-Length: 65"+CHR$(13)+CHR$(10) -1230 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10) -1250 A$=A$+CHR$(13)+CHR$(10) -1260 A$=A$+"test

Apple2 Test

" -1270 A$=A$+CHR$(13)+CHR$(10) -1280 PRINT "SENDING:":PRINT A$ -' TODO: read TX free size reg (0x420) -1900 POKE HA,4: POKE LA,34: REM *** 0x422 TX read ptr +1110 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr +1120 RA=RF+SI +1130 R%=RA/256 +1140 POKE DP,R%: POKE DP,RA-(R%*256) +1150 REM *** RECEIVE +1160 POKE HA,4: POKE LA,1: REM *** 0x401 command register +1170 POKE DP, 64: REM *** RECV +' +' Load file from disk +' +1200 REM *** LOAD FILE +1202 X$=RIGHT$(N$,3):M$="text/html" +1203 IF X$="txt" THEN M$="text/plain" +1204 IF X$="png" THEN M$="image/png" +1205 IF X$="jpg" THEN M$="image/jpg" +1206 IF X$="ico" THEN M$="image/x-icon" +1207 IF N$="teapot.html" GOTO 9000 +1208 ONERR GOTO 8000 +1209 PRINT "LOADING ";N$ +1210 PRINT CHR$(4)+"BLOAD ";N$ +1215 POKE 216,0: REM CANCEL ONERR +1220 FS=PEEK(43616)+256*PEEK(43617): REM FILESIZE +1225 PRINT "DONE LOADING" +' assume loaded at 0x4000, text page 2 +' and that max size is 8kb +1240 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10) +1250 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10) +1260 A$=A$+"Content-Length: "+STR$(FS)+CHR$(13)+CHR$(10) +1280 A$=A$+"Content-Type: "+M$+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10) +' +1380 PRINT "SENDING:":PRINT A$ +1385 C=0 +' +' read TX free size reg (0x420) +' +1700 SI=LEN(A$)+FS +1710 IF (SI>8192) THEN PRINT "FILE TOO BIG!": REM GOTO 403? +1800 POKE HA,4: POKE LA,32: REM *** 0x420 FREESIZE +1810 OH=PEEK(DP):OL=PEEK(DP) +1815 FR=(OH*256)+OL +1820 PRINT "FREE: ";FR +1830 IF SI>FR GOTO 1800: REM REPEAT UNTIL FREE +' +' Read tx offset +' +1900 POKE HA,4: POKE LA,36: REM *** 0x424 TX write ptr 1905 OH=PEEK(DP):OL=PEEK(DP) 1910 TF=(OH*256)+OL -1920 REM *** SHOULD MASK WITH 0x1ff -1925 T%=TF/8192:TF=TF-(8192*T%) -1930 TA=TF+16384:REM $4000 -1935 SI=LEN(A$) -1940 PRINT "TX OFFSET=";TF;" TX ADDRESS=";TA;" TX SIZE=";SI +1920 REM *** MASK WITH 0x1ff +1925 T%=TF/8192:TM=TF-(8192*T%) +1930 TA=TM+16384:REM $4000 +1940 PRINT "OH/OL=";OH;"/";OL;" TX OFFSET=";TM;" TX ADDRESS=";TA;" TX SIZE=";SI +' +' Check for buffer wraparound +' +1942 BW=0:BO=0 +1945 IF (SI+TA>=24576) THEN BW=1:BO=24576-TA:PRINT "TX BUFFER WRAPAROUND IN ";BO +' +' Write data to TX buffer +' First write header +' 2000 T%=TA/256 2005 POKE HA,T%: POKE LA,TA-(T%*256) -2010 FOR I=1 TO SI -2020 POKE DP,ASC(MID$(A$,I,1)) -2040 NEXT I +2010 FOR I=1 TO LEN(A$) +2015 POKE DP,ASC(MID$(A$,I,1)) +2017 IF BW=0 THEN GOTO 2020 +2018 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0 +2020 NEXT I +' +' Write disk part +' +2025 FOR I=1 TO FS +2026 C=C+1: IF C=50 THEN PRINT ".";:C=0 +2030 POKE DP,PEEK(16383+I) +2032 IF BW=0 THEN GOTO 2035 +2033 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0 +2035 NEXT I +2040 PRINT +' +' The above is slow +' Intead use our machine language routine +' +'2025 B%=BO/256:POKE 9,B%:POKE 8,BO-(B%*256) +'2027 B%=FS/256:POKE 11,B%:POKE 10,FS-(B%*256) +'2030 CALL 768 +' +' Update TX write ptr +' 2050 REM ** UPDATE TX WRITE PTR 2060 POKE HA,4: POKE LA,36: REM *** 0x424 TX write ptr -2075 TA=TA+SI +2075 TA=TF+SI 2080 T%=TA/256 -2085 POKE HA,T%: POKE LA,TA-(T%*256) +2085 POKE DP,T%: POKE DP,TA-(T%*256) +2090 PRINT "UPDATE TX TO ";T%;"/";TA-(T%*256) +' +' SEND packet +' 2100 REM *** SEND +2102 PRINT "SENDING" 2105 POKE HA,4: POKE LA,1: REM *** 0x401 command register 2110 POKE DP, 32: REM *** SEND -5000 REM *** CLOSE +' +' Return to reading +' +4000 REM *** Check if successful +4010 POKE HA,4: POKE LA,3: REM *** 0x403 status register +4020 RE=PEEK(DP) +4030 PRINT "STATUS AFTER SEND ";RE +4035 IF RE=28 THEN GOTO 6000: REM CLOSE_WAIT +4040 IF RE=0 THEN GOTO 400: REM CLOSED +4060 REM *** RECEIVE +4075 POKE HA,4: POKE LA,1: REM *** 0x401 command register +4080 POKE DP, 64: REM *** RECV +4090 GOTO 800 +' +' Close the socket +' +5000 REM *** CLOSE AND EXIT +5010 POKE HA,4: POKE LA,1: REM *** 0x401 command register +5020 POKE DP, 16: REM *** CLOSE +5030 END +6000 REM *** CLOSE AND RELISTEN +6010 POKE HA,4: POKE LA,1: REM *** 0x401 command register +6020 POKE DP, 16: REM *** CLOSE +' Check status? +6030 GOTO 400 +' +' +' ERROR MESSAGES +' +' +7000 REM 400 BAD REQUEST +7005 S$="400 Bad Request" +7010 M$="400 Bad Request

Bad Request

Your browser sent a request that this server could not understand.

"+CHR$(13)+CHR$(10) +7020 GOTO 9100 +8000 REM 404 NOT FOUND +8003 POKE 216,0: REM CANCEL ONERR +8004 PRINT "DISK ERROR: ";PEEK(222) +8005 S$="404 Not Found" +8010 M$="404 Not Found

Not Found

File not found.

"+CHR$(13)+CHR$(10) +8020 GOTO 9100 +9000 REM 418 TEAPOT +9005 S$="418 I'm a Teapot" +9010 M$="418 I'm a Teapot

I'm a Teapot

Short *and* stout.

"+CHR$(13)+CHR$(10) +' +' Make header +' +9100 A$="HTTP/1.1 "+S$+CHR$(13)+CHR$(10)+"Server: VMW-web"+CHR$(13)+CHR$(10) +9105 A$=A$+"Content-Length: "+STR$(LEN(M$))+CHR$(13)+CHR$(10) +9110 A$=A$+"Connection: close"+CHR$(13)+CHR$(10)+"Content-Type: text/html; charset=iso-8859-1"+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10) +' Poke as if we had loaded from disk +9200 FS=LEN(M$) +9210 FOR I=1 TO FS +9220 POKE 16383+I,ASC(MID$(M$,I,1)) +9300 NEXT I +9310 GOTO 1380 +' +' STATUSES +' p28 of W5100 manual +' 0x0 0 SOCK_CLOSED +' 0x13 SOCK_INIT +' 0x14 SOCK_LISTEN +' 0x17 23 SOCK_ESTABLISHED +' 0x1C 28 SOCK_CLOSE_WAIT +' 0x22 SOCK_UDP +' 0x32 SOCK_IPRAW +' 0x42 SOCK_MACRAW +' 0x5f SOCK_PPOE + +' +' Appendix 1: The memcpy machine code +' +' +'PTR EQU $06 +'PTRH EQU $07 +' +'WRAPL EQU $08 +'WRAPH EQU $09 +' +'SIZEL EQU $0A +'SIZEH EQU $0B +' +'tx_copy: +' +' lda #0 ; always copying from 0x4000 +' sta PTR +' lda #$40 +' sta PTR+1 +' +' ldx #SIZEH ; number of 256-byte blocks +' beq copy_remainder ; if none, skip ahead +' +' ldy #0 +'copy256: +' lda (PTR),y +' sta $C0B7 ; change based on uthernet slot +' +' cmp WRAPH,x +' bne nowrap256 +' +' cmp WRAPL,y +' bne nowrap256 +' +' lda #$40 +' sta $C0B5 +' lda #$00 +' sta $C0B6 ; wrap tx buffer address to 0x4000 +' +'nowrap256: +' iny +' bne copy256 +' +' inc PTR+1 ; update 16-bit pointer +' dex ; finish a 256 byte block +' bne copy256 +' +' ldx #SIZEL +'copy_remainder: +' lda (PTR),y +' sta $C0B7 ; change based on uthernet slot +' +' cmp WRAPL,y +' bne nowrap_r +' +' lda #$40 +' sta $C0B5 +' lda #$00 +' sta $C0B6 ; wrap tx buffer address to 0x4000 +' +'nowrap_r: +' iny +' dex +' bne copy_remainder +' +' rts + +