From b758047c603d5c69f0499f86620537fe07e0f3b5 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 15:24:33 -0500 Subject: [PATCH 01/27] dos33: clean up whitespace --- dos33fs-utils/dos33.c | 215 +++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 107 deletions(-) diff --git a/dos33fs-utils/dos33.c b/dos33fs-utils/dos33.c index ab51424d..2b5a415a 100644 --- a/dos33fs-utils/dos33.c +++ b/dos33fs-utils/dos33.c @@ -506,88 +506,89 @@ static int dos33_add_file(int fd,char type,char *filename, i=0; while (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,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); - /* read from input */ - bytes_read=read(input_fd,sector_buffer,BYTES_PER_SECTOR); - if (bytes_read<0) fprintf(stderr,"Error reading bytes!\n"); + /* add to T/s table */ - /* 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); - + /* 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); - - /* 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++; - } + /* 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 +633,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(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 */ From 602b13736329504a270d81c17005e996b92d4096 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 15:39:29 -0500 Subject: [PATCH 02/27] dos33: more whitespace cleanup I blame jed --- dos33fs-utils/dos33.c | 102 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/dos33fs-utils/dos33.c b/dos33fs-utils/dos33.c index 2b5a415a..ad12d596 100644 --- a/dos33fs-utils/dos33.c +++ b/dos33fs-utils/dos33.c @@ -1265,6 +1265,7 @@ int main(int argc, char **argv) { char output_filename[BUFSIZ]; char *result_string; int always_yes=0,firstarg=1,extra_ops=0; + char *temp; /* Check command line arguments */ /* Ugh I should use getopt() or something similar here */ @@ -1357,20 +1358,20 @@ int main(int argc, char **argv) { 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); + 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 */ @@ -1401,44 +1402,43 @@ int main(int argc, char **argv) { /* 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); - } + + + 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); From e3f5ae0824f392a46a700ce2b595e8d6c1f888fa Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 16:50:34 -0500 Subject: [PATCH 03/27] dos33: update code to use common command line code also share the filename truncation code a few other minor cleanups too seems to pass test suite --- dos33fs-utils/dos33.c | 447 ++++++++++++++++++++++++------------------ 1 file changed, 252 insertions(+), 195 deletions(-) diff --git a/dos33fs-utils/dos33.c b/dos33fs-utils/dos33.c index ad12d596..12f519ca 100644 --- a/dos33fs-utils/dos33.c +++ b/dos33fs-utils/dos33.c @@ -10,7 +10,7 @@ #include "dos33.h" -static int debug=0; +static int debug=1; static unsigned char sector_buffer[BYTES_PER_SECTOR]; @@ -1175,10 +1175,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"); @@ -1201,24 +1204,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; @@ -1243,7 +1248,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]; @@ -1262,86 +1282,96 @@ 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; + int c; /* Check command line arguments */ - /* Ugh I should use getopt() or something similar here */ + while ((c = getopt (argc, argv,"hvy"))!=-1) { + switch (c) { - if (argc<2) { - display_help(argv[0]); - goto exit_program; + 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, @@ -1352,7 +1382,7 @@ 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; @@ -1366,6 +1396,7 @@ int main(int argc, char **argv) { 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 */ } @@ -1378,24 +1409,46 @@ int main(int argc, char **argv) { /* 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 */ @@ -1403,10 +1456,9 @@ int main(int argc, char **argv) { /* everything up to the last slash so useless */ /* path info isn't used */ + temp=local_filename+(strlen(local_filename)-1); - temp=argv[firstarg+3]+(strlen(argv[firstarg+3])-1); - - while(temp!=argv[firstarg+3]) { + while(temp!=local_filename) { temp--; if (*temp == '/') { temp++; @@ -1414,15 +1466,11 @@ int main(int argc, char **argv) { } } - if (strlen(temp)>30) { - fprintf(stderr, - "Warning! Truncating filename to 30 chars!\n"); - } - - strncpy(apple_filename,temp,30); - apple_filename[30]=0; + 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); @@ -1440,154 +1488,163 @@ int main(int argc, char **argv) { dos33_delete_file(dos_fd,catalog_entry); } - dos33_add_file(dos_fd,type,argv[firstarg+3],apple_filename); + dos33_add_file(dos_fd,type,local_filename,apple_filename); 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_DELETE: - 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; - } + 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; + } - dos33_rename_file(dos_fd,catalog_entry,new_filename); - - break; + 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_DUMP: + printf("Dumping %s!\n",image); + dos33_dump(dos_fd); + break; + + 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; + } + + 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; } From 0f1686c2209ba2142f9f7079425912787c1872c9 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 16:51:25 -0500 Subject: [PATCH 04/27] dos33: turn off debugging --- dos33fs-utils/dos33.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dos33fs-utils/dos33.c b/dos33fs-utils/dos33.c index 12f519ca..752baac0 100644 --- a/dos33fs-utils/dos33.c +++ b/dos33fs-utils/dos33.c @@ -10,7 +10,7 @@ #include "dos33.h" -static int debug=1; +static int debug=0; static unsigned char sector_buffer[BYTES_PER_SECTOR]; From b01e82b56d0ab55d9d6abf64162fb2ca12a435b3 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 16:51:44 -0500 Subject: [PATCH 05/27] dos33 tests: update TODO --- dos33fs-utils/tests/TODO | 2 ++ 1 file changed, 2 insertions(+) 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 From 2dbe3d4b7092df17725065cf255399125b5dce2f Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 16:57:02 -0500 Subject: [PATCH 06/27] webserver: update Makefile --- dos33fs-utils/Makefile | 2 +- ethernet/Makefile | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dos33fs-utils/Makefile b/dos33fs-utils/Makefile index 370fc7d5..b8731ffc 100644 --- a/dos33fs-utils/Makefile +++ b/dos33fs-utils/Makefile @@ -14,7 +14,7 @@ dos33: dos33.o $(CC) $(LFLAGS) -o dos33 dos33.o dos33.o: dos33.c dos33.h - $(CC) $(CFLAGS) -c dos33.c + $(CC) $(CFLAGS) -g -c dos33.c dos33_text2ascii: dos33_text2ascii.o $(CC) $(LFLGAS) -o dos33_text2ascii dos33_text2ascii.o diff --git a/ethernet/Makefile b/ethernet/Makefile index a2f5259b..b1de679b 100644 --- a/ethernet/Makefile +++ b/ethernet/Makefile @@ -10,17 +10,17 @@ 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 +#about.html: ./c/about.html +# $(MAKEB) ./c/about.html about.html 0xc000 -index.html: ./c/index.html - $(MAKEB) ./c/index.html index.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 +#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 +#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 @@ -28,14 +28,14 @@ R.TXT: request.txt 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 ./c/about.html + $(DOS33) -y ethernet.dsk BSAVE ./c/index.html + $(DOS33) -y ethernet.dsk BSAVE ./c/favicon.ico + $(DOS33) -y ethernet.dsk BSAVE ./c/vmw_logo.png clean: rm -f *~ *.BAS R.TXT From eccadc5beebb76837a99409b80cbb01148256b42 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 22:55:17 -0500 Subject: [PATCH 07/27] dos33: improve bsave functionality can specify address and length --- dos33fs-utils/dos33.c | 65 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/dos33fs-utils/dos33.c b/dos33fs-utils/dos33.c index 752baac0..332948a5 100644 --- a/dos33fs-utils/dos33.c +++ b/dos33fs-utils/dos33.c @@ -429,10 +429,14 @@ found_one: #define ERROR_IMAGE_NOT_FOUND 4 #define ERROR_CATALOG_FULL 5 +#define ADD_RAW 0 +#define ADD_BINARY 1 + /* creates file apple_filename on the image from local file filename */ /* returns ?? */ -static int dos33_add_file(int fd,char type,char *filename, - char *apple_filename) { +static int dos33_add_file(int fd, char dos_type, + int file_type, int address, int length, + char *filename, char *apple_filename) { int free_space,file_size,needed_sectors; struct stat file_info; @@ -441,6 +445,7 @@ static int dos33_add_file(int fd,char type,char *filename, int catalog_track,catalog_sector,sectors_used=0; int input_fd; int result; + int first_write=1; if (apple_filename[0]<64) { fprintf(stderr,"Error! First char of filename " @@ -471,6 +476,12 @@ static int dos33_add_file(int fd,char type,char *filename, if (debug) printf("Filesize: %d\n",file_size); + if (file_type==ADD_BINARY) { + if (debug) printf("Adding 4 bytes for size/offset\n"); + if (length==0) length=file_size; + file_size+=4; + } + /* We need to round up to nearest sector size */ /* Add an extra sector for the T/S list */ /* Then add extra sector for a T/S list every 122*256 bytes (~31k) */ @@ -564,14 +575,30 @@ static int dos33_add_file(int fd,char type,char *filename, for(x=0;x>16)&0xff; + sector_buffer[2]=(length)&0xff; + sector_buffer[3]=((length)>>16)&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; + if (bytes_read<0) fprintf(stderr,"Error reading bytes!\n"); /* 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 */ @@ -642,7 +669,7 @@ got_a_dentry: 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); + dos33_char_to_type(dos_type,0); // printf("Pointing T/S to %x/%x\n",(initial_ts_list>>8)&0xff,initial_ts_list&0xff); @@ -1191,7 +1218,7 @@ static void display_help(char *name, int version_only) { 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"); @@ -1285,13 +1312,20 @@ int main(int argc, char **argv) { char local_filename[BUFSIZ]; char *result_string; int always_yes=0; - char *temp; + char *temp,*endptr; int c; + int address=0, length=0; /* Check command line arguments */ - while ((c = getopt (argc, argv,"hvy"))!=-1) { + while ((c = getopt (argc, argv,"a:l:hvy"))!=-1) { switch (c) { + case 'a': + address=strtol(optarg,&endptr,0); + break; + case 'l': + length=strtol(optarg,&endptr,0); + break; case 'v': display_help(argv[0],1); return 0; @@ -1487,9 +1521,16 @@ int main(int argc, char **argv) { fprintf(stderr,"Deleting previous version...\n"); dos33_delete_file(dos_fd,catalog_entry); } - - dos33_add_file(dos_fd,type,local_filename,apple_filename); - + 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: From 127089371df94b7980c98fc856d0c4dec7cfb9b6 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 23:02:50 -0500 Subject: [PATCH 08/27] dos33: silly 8/16 bug when writing address/len in bsave --- dos33fs-utils/dos33.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dos33fs-utils/dos33.c b/dos33fs-utils/dos33.c index 332948a5..b9ecfd71 100644 --- a/dos33fs-utils/dos33.c +++ b/dos33fs-utils/dos33.c @@ -578,9 +578,9 @@ static int dos33_add_file(int fd, char dos_type, if ((first_write) && (file_type==ADD_BINARY)) { first_write=0; sector_buffer[0]=address&0xff; - sector_buffer[1]=(address>>16)&0xff; + sector_buffer[1]=(address>>8)&0xff; sector_buffer[2]=(length)&0xff; - sector_buffer[3]=((length)>>16)&0xff; + sector_buffer[3]=((length)>>8)&0xff; bytes_read=read(input_fd,sector_buffer+4, BYTES_PER_SECTOR-4); bytes_read+=4; @@ -1322,9 +1322,11 @@ int main(int argc, char **argv) { 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); From 82b7489da650d2a44536149a52911d33ff7ed9bd Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 13 Dec 2016 23:04:58 -0500 Subject: [PATCH 09/27] webserver: update Makefile to use new bsave functionality --- ethernet/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ethernet/Makefile b/ethernet/Makefile index b1de679b..3a626965 100644 --- a/ethernet/Makefile +++ b/ethernet/Makefile @@ -32,10 +32,10 @@ ethernet.dsk: SETUP.BAS \ $(DOS33) -y ethernet.dsk SAVE A SETUP.BAS $(DOS33) -y ethernet.dsk SAVE A WEBSERVER.BAS $(DOS33) -y ethernet.dsk BSAVE R.TXT - $(DOS33) -y ethernet.dsk BSAVE ./c/about.html - $(DOS33) -y ethernet.dsk BSAVE ./c/index.html - $(DOS33) -y ethernet.dsk BSAVE ./c/favicon.ico - $(DOS33) -y ethernet.dsk BSAVE ./c/vmw_logo.png + $(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 From 43ab033417c68de21687b4cb09fc5884b8c557fc Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 11:29:18 -0500 Subject: [PATCH 10/27] webserver.bas: move to slot 3, add more comments --- ethernet/webserver.bas | 124 ++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 39 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 2d6c5f33..fb35d355 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -1,30 +1,33 @@ 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 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,62 +39,85 @@ 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 +745 IF RE<>20 THEN PRINT "WAITING: UNEXPECTED STATUS=";RE 750 GOTO 700: REM *** Repeat until connected ' +' Connected, repeat waiting for incoming data +' 800 PRINT "CONNECTED" 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:RF=RF-(8192*R%) +930 RA=RF+24576:REM $6000 +940 PRINT "READ OFFSET=";RF;" READ ADDRESS=";RA;" READ SIZE=";SI +' +' Print received packet ' 1000 REM *** PRINT PACKET -1005 POKE HA,RA/256: POKE LA,RA-((RA/256)*256) +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); @@ -99,7 +125,15 @@ ' ' TODO: handle wraparound of 8kb buffer ' +' +' TODO: Update read pointer +' 1100 REM *** Update read pointer +1110 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr +1120 RA=RA+SI +1130 R%=RA/256 +1140 POKE DP,R%: POKE DP,RA-(R%*256) +' '"HTTP/1.1 200 OK\r\n" '"Date: %s\r\n" '"Server: VMW-web\r\n" @@ -108,15 +142,17 @@ '"Content-Type: %s\r\n" '"\r\n", 1200 REM *** SEND RESPONSE +1201 M$="test

Apple2 Test

"+CHR$(13)+CHR$(10) 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) +1220 A$=A$+"Content-Length: "+STR$(LEN(M$))+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) +1270 A$=A$+M$ 1280 PRINT "SENDING:":PRINT A$ +' ' TODO: read TX free size reg (0x420) +' 1900 POKE HA,4: POKE LA,34: REM *** 0x422 TX read ptr 1905 OH=PEEK(DP):OL=PEEK(DP) 1910 TF=(OH*256)+OL @@ -138,4 +174,14 @@ 2100 REM *** SEND 2105 POKE HA,4: POKE LA,1: REM *** 0x401 command register 2110 POKE DP, 32: REM *** SEND +' +' Return to reading +' +4000 GOTO 802 +' +' Close the socket +' 5000 REM *** CLOSE +5010 POKE HA,4: POKE LA,1: REM *** 0x401 command register +5020 POKE DP, 16: REM *** CLOSE +5030 END From 84d281f0b969271524b19251b6c3d6bd17fc0b93 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 11:29:37 -0500 Subject: [PATCH 11/27] webserver: clean up Makefile --- ethernet/Makefile | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ethernet/Makefile b/ethernet/Makefile index 3a626965..81ea0bc6 100644 --- a/ethernet/Makefile +++ b/ethernet/Makefile @@ -10,18 +10,6 @@ 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 From 16b87c53b12916d51cf40e5ccda536d363c0c2ec Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 12:18:06 -0500 Subject: [PATCH 12/27] webserver.bas: mixup of physical address and offset --- ethernet/webserver.bas | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index fb35d355..9f031f32 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -130,7 +130,7 @@ ' 1100 REM *** Update read pointer 1110 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr -1120 RA=RA+SI +1120 RA=RF+SI 1130 R%=RA/256 1140 POKE DP,R%: POKE DP,RA-(R%*256) ' @@ -142,7 +142,7 @@ '"Content-Type: %s\r\n" '"\r\n", 1200 REM *** SEND RESPONSE -1201 M$="test

Apple2 Test

"+CHR$(13)+CHR$(10) +1201 M$="test

Apple2 Test

"+CHR$(13)+CHR$(10) 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: "+STR$(LEN(M$))+CHR$(13)+CHR$(10) @@ -152,32 +152,52 @@ 1280 PRINT "SENDING:":PRINT A$ ' ' TODO: read TX free size reg (0x420) +' FREESIZE: +' get_free_size = Sn_TX_FSR; +' if (get_free_size < send_size) goto FREESIZE; ' -1900 POKE HA,4: POKE LA,34: REM *** 0x422 TX read ptr +' +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 +1920 REM *** 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 +1940 PRINT "OH/OL=";OH;"/";OL;" TX OFFSET=";TF;" TX ADDRESS=";TA;" TX SIZE=";SI +' +' Write data to TX buffer +' 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 +' +' 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) +' +' SEND packet +' 2100 REM *** SEND 2105 POKE HA,4: POKE LA,1: REM *** 0x401 command register 2110 POKE DP, 32: REM *** SEND ' ' Return to reading ' -4000 GOTO 802 +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 +4060 REM *** RECEIVE +4075 POKE HA,4: POKE LA,1: REM *** 0x401 command register +4080 POKE DP, 64: REM *** RECV +4090 GOTO 802 ' ' Close the socket ' From 6e1ae7580bf384101a7b0bf419e5ad3fec648a3b Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 13:47:46 -0500 Subject: [PATCH 13/27] wbeserver: update the *non-masked* version of the offset pointer urgh, couldn't figure out why sending 8kb of additional garbage each time --- ethernet/webserver.bas | 58 ++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 9f031f32..46c0e243 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -86,13 +86,13 @@ 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 +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 ' -' Connected, repeat waiting for incoming data +' Established, repeat waiting for incoming data ' -800 PRINT "CONNECTED" +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 @@ -109,9 +109,9 @@ 905 OH=PEEK(DP):OL=PEEK(DP) 910 RF=(OH*256)+OL 920 REM *** MASK WITH 0x1ff -925 R%=RF/8192:RF=RF-(8192*R%) -930 RA=RF+24576:REM $6000 -940 PRINT "READ OFFSET=";RF;" READ ADDRESS=";RA;" READ SIZE=";SI +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 ' ' Print received packet ' @@ -120,7 +120,7 @@ 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); +1030 IF C<>10 THEN PRINT CHR$(C); 1040 NEXT I ' ' TODO: handle wraparound of 8kb buffer @@ -133,6 +133,10 @@ 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 +'1180 GOTO 802 ' '"HTTP/1.1 200 OK\r\n" '"Date: %s\r\n" @@ -157,14 +161,22 @@ ' if (get_free_size < send_size) goto FREESIZE; ' ' +1700 SI=LEN(A$) +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 *** MASK WITH 0x1ff -1925 T%=TF/8192:TF=TF-(8192*T%) -1930 TA=TF+16384:REM $4000 -1935 SI=LEN(A$) -1940 PRINT "OH/OL=";OH;"/";OL;" TX OFFSET=";TF;" TX ADDRESS=";TA;" TX SIZE=";SI +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 ' ' Write data to TX buffer ' @@ -181,6 +193,7 @@ 2075 TA=TF+SI 2080 T%=TA/256 2085 POKE DP,T%: POKE DP,TA-(T%*256) +2090 PRINT "UPDATE TX TO ";T%;"/";TA-(T%*256) ' ' SEND packet ' @@ -194,14 +207,33 @@ 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 802 +4090 GOTO 800 ' ' Close the socket ' -5000 REM *** CLOSE +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 +' +' 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 From 8ad5b87bec16ef1f662f6b7a4a9e423044e139f2 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 14:20:23 -0500 Subject: [PATCH 14/27] webserver: BLOADs index.html off of disk --- ethernet/webserver.bas | 47 ++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 46c0e243..750f1781 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -119,8 +119,8 @@ 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<>10 THEN PRINT CHR$(C); +1020 C=PEEK(DP):C$=CHR$(C) +1030 IF C<>10 THEN PRINT C$; 1040 NEXT I ' ' TODO: handle wraparound of 8kb buffer @@ -136,7 +136,18 @@ 1150 REM *** RECEIVE 1160 POKE HA,4: POKE LA,1: REM *** 0x401 command register 1170 POKE DP, 64: REM *** RECV -'1180 GOTO 802 +' +' Load file from disk +' +1200 REM *** LOAD FILE +1210 PRINT CHR$(4)+"BLOAD index.html" +1220 FS=PEEK(43616)+256*PEEK(43617): REM FILESIZE +' assume loaded at 0x4000, text page 2 +' and that max size is 8kb +1225 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10) +1230 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10) +1235 A$=A$+"Content-Length: "+STR$(FS)+CHR$(13)+CHR$(10) +1240 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10) ' '"HTTP/1.1 200 OK\r\n" '"Date: %s\r\n" @@ -145,15 +156,15 @@ '"Content-Length: %ld\r\n" '"Content-Type: %s\r\n" '"\r\n", -1200 REM *** SEND RESPONSE -1201 M$="test

Apple2 Test

"+CHR$(13)+CHR$(10) -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: "+STR$(LEN(M$))+CHR$(13)+CHR$(10) -1230 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10) -1250 A$=A$+CHR$(13)+CHR$(10) -1270 A$=A$+M$ -1280 PRINT "SENDING:":PRINT A$ +'1300 REM *** SEND RESPONSE +'1301 M$="test

Apple2 Test

"+CHR$(13)+CHR$(10) +'1305 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10) +'1310 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10) +'1320 A$=A$+"Content-Length: "+STR$(LEN(M$))+CHR$(13)+CHR$(10) +'1330 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10) +'1350 A$=A$+CHR$(13)+CHR$(10) +'1370 A$=A$+M$ +1380 PRINT "SENDING:":PRINT A$ ' ' TODO: read TX free size reg (0x420) ' FREESIZE: @@ -161,7 +172,8 @@ ' if (get_free_size < send_size) goto FREESIZE; ' ' -1700 SI=LEN(A$) +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 @@ -182,9 +194,12 @@ ' 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)) +2020 NEXT I +2025 FOR I=1 TO FS +2030 POKE DP,PEEK(16383+I) +2035 NEXT I ' ' Update TX write ptr ' From 447cc49f6c2fe37d87350f1ed3d10e975a4df6c0 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 16:15:14 -0500 Subject: [PATCH 15/27] webserver: error messages now work --- ethernet/webserver.bas | 81 +++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 750f1781..559df358 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -116,12 +116,25 @@ ' Print received packet ' 1000 REM *** PRINT PACKET +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):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$; 1040 NEXT I +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 ' @@ -140,37 +153,25 @@ ' Load file from disk ' 1200 REM *** LOAD FILE -1210 PRINT CHR$(4)+"BLOAD index.html" +1202 X$=RIGHT$(N$,3):M$="text/html" +1205 IF X$="txt" THEN M$="text/plain" +1206 IF X$="png" THEN M$="image/png" +1207 IF X$="jpg" THEN M$="image/jpg" +1208 IF N$="teapot.html" GOTO 9000 +1209 ONERR GOTO 8000 +1210 PRINT CHR$(4)+"BLOAD ";N$ +1215 POKE 216,0: REM CANCEL ONERR 1220 FS=PEEK(43616)+256*PEEK(43617): REM FILESIZE ' assume loaded at 0x4000, text page 2 ' and that max size is 8kb -1225 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10) -1230 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10) -1235 A$=A$+"Content-Length: "+STR$(FS)+CHR$(13)+CHR$(10) -1240 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10) +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) ' -'"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", -'1300 REM *** SEND RESPONSE -'1301 M$="test

Apple2 Test

"+CHR$(13)+CHR$(10) -'1305 A$="HTTP/1.1 200 OK"+CHR$(13)+CHR$(10) -'1310 A$=A$+"Server: VMW-web"+CHR$(13)+CHR$(10) -'1320 A$=A$+"Content-Length: "+STR$(LEN(M$))+CHR$(13)+CHR$(10) -'1330 A$=A$+"Content-Type: text/html"+CHR$(13)+CHR$(10) -'1350 A$=A$+CHR$(13)+CHR$(10) -'1370 A$=A$+M$ 1380 PRINT "SENDING:":PRINT A$ ' -' TODO: read TX free size reg (0x420) -' FREESIZE: -' get_free_size = Sn_TX_FSR; -' if (get_free_size < send_size) goto FREESIZE; -' +' read TX free size reg (0x420) ' 1700 SI=LEN(A$)+FS 1710 IF (SI>8192) THEN PRINT "FILE TOO BIG!": REM GOTO 403? @@ -241,6 +242,36 @@ ' 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 From ad9db0d0e7f1356aecb0b6499f1bb59cbe598533 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 16:52:54 -0500 Subject: [PATCH 16/27] webserver: attempt to handle circular buffer overflow properly --- ethernet/webserver.bas | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 559df358..8556b323 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -113,6 +113,11 @@ 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 @@ -124,7 +129,12 @@ 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$="" @@ -139,7 +149,7 @@ ' TODO: handle wraparound of 8kb buffer ' ' -' TODO: Update read pointer +' Update read pointer ' 1100 REM *** Update read pointer 1110 POKE HA,4: POKE LA,40: REM *** 0x428 Received ptr @@ -191,15 +201,24 @@ 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 +1945 IF (SI+TA>=24576) THEN BW=1:BO=24576-TA:PRINT "TX BUFFER WRAPAROUND IN ";BO +' ' Write data to TX buffer ' 2000 T%=TA/256 2005 POKE HA,T%: POKE LA,TA-(T%*256) 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,96:POKE LA,0:BW=0 2020 NEXT I 2025 FOR I=1 TO FS 2030 POKE DP,PEEK(16383+I) +2032 IF BW=0 THEN GOTO 2035 +2033 BO=BO-1: IF BO=0 THEN POKE HA,96:POKE LA,0:BW=0 2035 NEXT I ' ' Update TX write ptr From 60a25f3958ba3b9d71a8da8ca284c9cdc0f87a13 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 14 Dec 2016 17:20:28 -0500 Subject: [PATCH 17/27] webserver: fix silly address bug, but it's not working now --- ethernet/webserver.bas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 8556b323..ab3c66e8 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -213,12 +213,12 @@ 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,96:POKE LA,0:BW=0 +2018 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0 2020 NEXT I 2025 FOR I=1 TO FS 2030 POKE DP,PEEK(16383+I) 2032 IF BW=0 THEN GOTO 2035 -2033 BO=BO-1: IF BO=0 THEN POKE HA,96:POKE LA,0:BW=0 +2033 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0 2035 NEXT I ' ' Update TX write ptr From 407c2296b36ee2cb6d239d535371e7a7119aac75 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Thu, 15 Dec 2016 13:40:03 -0500 Subject: [PATCH 18/27] webserver: print progress dots --- ethernet/webserver.bas | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index ab3c66e8..23312469 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -164,14 +164,16 @@ ' 1200 REM *** LOAD FILE 1202 X$=RIGHT$(N$,3):M$="text/html" -1205 IF X$="txt" THEN M$="text/plain" -1206 IF X$="png" THEN M$="image/png" -1207 IF X$="jpg" THEN M$="image/jpg" -1208 IF N$="teapot.html" GOTO 9000 -1209 ONERR GOTO 8000 +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 N$="teapot.html" GOTO 9000 +1207 ONERR GOTO 8000 +1208 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) @@ -180,6 +182,7 @@ 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) ' @@ -216,10 +219,12 @@ 2018 BO=BO-1: IF BO=0 THEN POKE HA,64:POKE LA,0:BW=0 2020 NEXT I 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 ' ' Update TX write ptr ' @@ -233,6 +238,7 @@ ' 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 ' From 7f37c1755559dafc43873e4123300767a6c9ee98 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Thu, 15 Dec 2016 13:40:21 -0500 Subject: [PATCH 19/27] webserver: update disk image --- ethernet/ethernet.dsk | Bin 143360 -> 143360 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ethernet/ethernet.dsk b/ethernet/ethernet.dsk index f1b2d629e9e6a46edad20e8efb04fb6299e75e64..e5591fe8c964899b2c9795ae1ceb0bc4c69f7006 100644 GIT binary patch literal 143360 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 Date: Thu, 15 Dec 2016 13:56:23 -0500 Subject: [PATCH 20/27] Update README --- ethernet/README | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) 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. + From d984f434077a14a0bcb943d7e16fb45536649c91 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Thu, 15 Dec 2016 13:57:30 -0500 Subject: [PATCH 21/27] webserver: add title/e-mail --- ethernet/webserver.bas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 23312469..ca788fa7 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -1,3 +1,6 @@ +' Applesoft BASIC Webserver +' by Vince Weaver +' 1 REM *** Setup UTHERNET II - W5100 ' SLOT0=$C080 49280 SLOT4=$C0C0 49344 ' SLOT1=$C090 49296 SLOT5=$C0D0 49360 From b42bd856ebb66c3b703ef42362aa0e94679fe86c Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Fri, 16 Dec 2016 12:26:51 -0500 Subject: [PATCH 22/27] webserver: some memory speed tests --- ethernet/Makefile | 7 +++++-- ethernet/memcpy.s | 20 ++++++++++++++++++++ ethernet/memcpy.txt | 46 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 ethernet/memcpy.s create mode 100644 ethernet/memcpy.txt diff --git a/ethernet/Makefile b/ethernet/Makefile index 81ea0bc6..16f9a796 100644 --- a/ethernet/Makefile +++ b/ethernet/Makefile @@ -2,7 +2,10 @@ DOS33 = ../dos33fs-utils/dos33 TXT2BAS = ../asoft_basic-utils/tokenize_asoft MAKEB = ../dos33fs-utils/make_b -all: ethernet.dsk +all: ethernet.dsk memcpy.o + +memcpy.o: memcpy.s + ca65 -o memcpy.o memcpy.s -l memcpy.lst SETUP.BAS: setup.bas $(TXT2BAS) < setup.bas > SETUP.BAS @@ -26,4 +29,4 @@ ethernet.dsk: SETUP.BAS \ $(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/vmw_logo.png clean: - rm -f *~ *.BAS R.TXT + rm -f *~ *.BAS R.TXT *.o *.lst diff --git a/ethernet/memcpy.s b/ethernet/memcpy.s new file mode 100644 index 00000000..03990e76 --- /dev/null +++ b/ethernet/memcpy.s @@ -0,0 +1,20 @@ +.define EQU = + +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 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 + + + From 56f0a711eb188b02e99fdfc261d273c4ad99ddea Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Fri, 16 Dec 2016 12:33:46 -0500 Subject: [PATCH 23/27] webserver: set a proper mime type for .ico files we were serving them up as html, which surprisingly firefox was fine with --- ethernet/webserver.bas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index ca788fa7..652479f3 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -170,9 +170,10 @@ 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 N$="teapot.html" GOTO 9000 -1207 ONERR GOTO 8000 -1208 PRINT "LOADING ";N$ +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 From c7f04713b3012775278910d9a8d12c4e7f6e1d9c Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Fri, 16 Dec 2016 13:36:48 -0500 Subject: [PATCH 24/27] asoft-utils: add new bin2data utility --- asoft_basic-utils/Makefile | 11 ++++++-- asoft_basic-utils/README | 7 +++++ asoft_basic-utils/bin2data.c | 54 ++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 asoft_basic-utils/bin2data.c 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..ea3d7d11 --- /dev/null +++ b/asoft_basic-utils/bin2data.c @@ -0,0 +1,54 @@ +#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,address); + + for(i=0;i Date: Fri, 16 Dec 2016 16:45:22 -0500 Subject: [PATCH 25/27] bin2data: fix off by one error --- asoft_basic-utils/bin2data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoft_basic-utils/bin2data.c b/asoft_basic-utils/bin2data.c index ea3d7d11..bf539733 100644 --- a/asoft_basic-utils/bin2data.c +++ b/asoft_basic-utils/bin2data.c @@ -35,7 +35,8 @@ int main(int argc, char **argv) { } printf("%d FOR I=0 TO %d: READ X: POKE %d+I,X:NEXT I\n", - line,bytes,address); + line,bytes-1,address); + line+=10; for(i=0;i Date: Fri, 16 Dec 2016 16:47:25 -0500 Subject: [PATCH 26/27] webserver: add faster memcpy, but comment out --- ethernet/Makefile | 8 ++++-- ethernet/ethernet.dsk | Bin 143360 -> 143360 bytes ethernet/memcpy.s | 58 ++++++++++++++++++++++++++++++++++++----- ethernet/webserver.bas | 22 +++++++++++++++- 4 files changed, 79 insertions(+), 9 deletions(-) diff --git a/ethernet/Makefile b/ethernet/Makefile index 16f9a796..b8f956ba 100644 --- a/ethernet/Makefile +++ b/ethernet/Makefile @@ -2,7 +2,10 @@ DOS33 = ../dos33fs-utils/dos33 TXT2BAS = ../asoft_basic-utils/tokenize_asoft MAKEB = ../dos33fs-utils/make_b -all: ethernet.dsk memcpy.o +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 @@ -29,4 +32,5 @@ ethernet.dsk: SETUP.BAS \ $(DOS33) -y ethernet.dsk BSAVE -a 0x4000 ./c/vmw_logo.png clean: - rm -f *~ *.BAS R.TXT *.o *.lst + rm -f *~ *.BAS R.TXT *.o *.lst memcpy + diff --git a/ethernet/ethernet.dsk b/ethernet/ethernet.dsk index e5591fe8c964899b2c9795ae1ceb0bc4c69f7006..7a68059885318a839f41f9326c24783b9e7d64f9 100644 GIT binary patch delta 10831 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 E3-fL)&;S4c delta 6665 zcmeI1dvp}l9mnU+&hE_4Gy9&I-C-YWo}`i&2_(FdunXISkZhLMIoN_lTNO||2vjWu zMcbZMRBmPDp@;|q5rxDW#kPXg(}1V4SdIs+2P4=D!a+oAd$3CH%-zkKp40x>l5=u) zX7}FNxp%(5-}m$TZCel1*26qKzhf*}^OLdqSYlR;7z5v#R!lZ1aQ{{}mr|}s?PE(yh{Xy_Z}pLz6#cPUFpAu-zy%2p z)1~ZmwGqb^xGLc%feM@3Mp3f5)~6p@4P4={y3W^LfhJd}bNn44bQG$qof1mMT4u&t zQ$({0zfJfk(SMU4);1{mqitYYNcJ!Cw~s4DlZyS5gT|zaP}7W5C_ZB*T6)~Cx2yp& zxxf#F21Qxvj|E$!>4-V#j%A_v9d|ET7$L6u;iQHK1NJ~Fh%coE3Pz$!m5vRiVztdP zQbYypX;8>F190E{>qtt2lOLE!R%)>Aff9132ES=sGQLy0I5OUvK3y<9T1dRET^YG1 zkuE(HZzbN>sOYPumE~j0yA#EKE%*!#C{7fY78VjcS}J;fg7{2>^VSwpG)*%QMO49!l~HrFPNeTh`p%}$pRcE=eDewNM2L{lo% zTwC7|OA(6WtR>!a``HpjzWNtcH`*zuwN}^7`xC5xGn;e%c<`P>I#7&NW zTI#WAs_UcaPYdb`i4_h&?KQ6Qrg0VY-(4Ri9&%Wyz4htR67*)egxKJ)q0?hW(fNV; zXbthCBZop8@{&WP4n*RKWNRwam}rVkh}59@#5;~Cwf9T`IxH?PgyVIg^@O94YBF!} zjN=9h-A(18)5hn8#1%(5H9eaC%p7g(Ho-Z^QhU)`kx-<)v}9ZfAv-4+lbfR5)1ySt zIm!6uYA4*HEB;pJRCEJI>?E3|hT@6FSam2;(-b9^I$>H5P@A2zD46qjp0>+5pGwxI zlksk}3okowqx!b#m=l6J#eLejiW(R$IW9Q=iBX9>*Lunb$I6OKIHGWxMO3@?WrjD- zK*~41nwaD2pyou=XA7E)g;yJESa$QuWut$zZ1JK9v0M-D0vdquU|qnn&(#GT8&%8O zu2*2wMp<~z^(wW)2*(oQybFfw-IUG!ItADK!3%DH&Gq@9Ro_|zqTpWmWPLul#|lg@@zL>Qx?sk%BS*aLjv8Qs}BW>zFg>+w5 zF{Y}r5N_S#^<`v!)|;kNx#<+vFXhv}-wu=3frL7ghd1aToT)Ayw@>MkD)O!ZS+d^`%=Se~}q=Vwy2>6EF4E?#Vo~&c@8V)wP6(V zwtJvr{_ZvvqhZCAn~I4KRm|+cin$jnW(QWxYZ=9O-ti1k%o&fqW&%q2bVf5lteIO) z%}6T-Xkoqny>_5Fws{9g;bpJBZ6a`u{;k&(!(nfq7(Vn45yNS(DFyU50&APO|SvO&`UWCnht!dWo z4f0^K{=E#3P8&tOFPm1sS)Vgxxx3y7f)itshZLx8A8_-TFl(@r9cpFcf zCq@ACcAn)qp63N#V$WDq}AlS9T0356eZe4gGw`mDk4M4T8=1+QpR$wf{ru~iX~FA zNR(uiY!WRol3ijYPU0m&5+z9_L?Du)MWjTlXcLXl=_XegQSb`Wbzleh9r?fON1l!z zUbN&$=5{@k0vmEb3Gl-6kr__ zI6O4d*Xf(P-KL{`kMCRzEE{%$qSgsnct^^T0yZ->Q`#r<6`>!0ZRF_+y z>IL=}1_ArQA;5mjF$maCI{E?oUmPZ|6ByW)YXN%|2KEJ6U|-T7*zX$v>^cVa-9v!= zJ*Nrm=bgg=J24EfkNCI1J{|-6Toc%rV_+B7^l_JNau@l!iCdOWT!-~-H6Q|b9qb1A zmKyh;;N(rk)Kd2e3f{TNOV-SR(iAoC!C~0z@j>i$$Yd|_Q@8%nZV)BEal>s>+_^bJ z=_@>#zG9fZ?!ff*V3xj~7)oCqn7+U<{pcPrf;{WdKi>nqpd8az?Ew0khw1C~f%Mgu zp|77}`hxxFYv)k<+KcJyh}T5%%iau%gZ}g-4WO?gOkYV%Uke7(*E&pJ&kjppZ(#bm z;4@n#U;FyCN@Pr5m6*N|i=kGDd;SpmdKlB!c1&N-XX)!LOkbB|+$*tT`jSlgD#r9R z7t`0Bz4Z0tEPXvPEPd_5^mR*r`l`CKm%i2xLtmTKVVffn%v;61yftAkZ_UQM^{L(PLezaQoK36xLpA?(S$)I~mozz7{(?gBptJg|_mQNw)E1%82; z#%`5uGA%Q*y^nunPUdAn7G+5x6oiS2MWGa{VpC`Z)n5kx^l&1junLFHa51F_il|5` zp#qguEh?p2RhvqyjA~a|l~Z|DP(@Yp6Mo=Fw}M<~OP>qHS-7ZSj<%q8-FFRM_b>6f z1DG@C;dQUW>;BeUx06Sl*;fVTYhR7j7qkQ4>dGu~;^MPGyE@XSF^%?6ZMHp>M4pVQ z%mtb~nyFKb*3xoKjAn=Sc9MRgxs0KYYPS5|@*H=fHfd6Rds)etlB{)@uTW%fru>v2 z(Ph@o{m6#1cJ8BquDi9<1}99KSUkC|F>Nq!HqD$DFaa>j9AFD`GQ0c zl@!@FU(gbyg4UodXy6g90QArW&;xT=kEwK>r^(Ak%V1Q93-KW#B!;9g5k}@7wuGs$ zHEavhVJ2)3vtcgGhlQ{hmLlj{hsmx!k^d*CWl`N3FRH^{v^3*I&tWer%e&qH@Ke_t z0NHl^f8793&JFKGcVQ>GuQwwL&inxxxvn=Ow+zh4 zw+xq&7vqe4-@uIg*l-#737nDJhi2qoUn?Vjmx_=P!viz9A!20bOm2wK5#z^!%ufIj WHo`^th!8Ov2$|dv$R~{ied1sIO?{mJ diff --git a/ethernet/memcpy.s b/ethernet/memcpy.s index 03990e76..492f9752 100644 --- a/ethernet/memcpy.s +++ b/ethernet/memcpy.s @@ -1,20 +1,66 @@ .define EQU = PTR EQU $06 +PTRH EQU $07 - lda #0 +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 #8 + ldx #SIZEH ; number of 256-byte blocks + beq copy_remainder ; if none, skip ahead + ldy #0 -copy_loop: +copy256: lda (PTR),y - sta $5000 + 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 - bne copy_loop dex - bne copy_loop + bne copy_remainder rts + + diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 652479f3..150f6b3f 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -28,6 +28,15 @@ 33 POKE DP,192:POKE DP,168:POKE DP,8:POKE DP,15 40 PRINT "UTHERNET II READY: 192.168.8.15" ' +' Setup Memcpy routine +' +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 @@ -210,10 +219,11 @@ ' ' Check for buffer wraparound ' -1942 BW=0 +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) @@ -222,6 +232,9 @@ 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) @@ -230,6 +243,13 @@ 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 From 2d8646f7246478c375db941c4b0eecc26f0befec Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Fri, 16 Dec 2016 16:51:54 -0500 Subject: [PATCH 27/27] webserver: comment the memcpy routine --- ethernet/webserver.bas | 74 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/ethernet/webserver.bas b/ethernet/webserver.bas index 150f6b3f..dd4619a8 100644 --- a/ethernet/webserver.bas +++ b/ethernet/webserver.bas @@ -28,7 +28,10 @@ 33 POKE DP,192:POKE DP,168:POKE DP,8:POKE DP,15 40 PRINT "UTHERNET II READY: 192.168.8.15" ' -' Setup Memcpy routine +' 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 @@ -332,3 +335,72 @@ ' 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 + +