commit d410349

zzo38  ·  2023-04-07 23:30:02 +0000 UTC
parent 50838e3
Change the implementation of nonstandard features to a new one.
(Discuss in the mailing list of Uxn if you have any comments about it.)
2 files changed,  +95, -221
M main.c
+49, -136
  1@@ -69,8 +69,7 @@
  2   Set default screen width.
  3 
  4 -x
  5-  Enable extension device (only built-in extensions). (This feature is
  6-  deprecated; see varvara.doc and the mailing list.)
  7+  Enable nonstandard features.
  8 
  9 -y
 10   Enable read-only file system access.
 11@@ -151,138 +150,52 @@ are being used, then this number may be set higher than 273.
 12 (Currently there is not the setting of interpolation, filter, etc.)
 13 
 14 
 15-=== Extension device ===
 16-
 17-(This section is deprecated; see varvara.doc and the mailing list.)
 18-
 19-Device fifteen is the extension device, which is defined as:
 20-  f0 = vector *
 21-  f1
 22-  f2 = conventional memory transfer base *
 23-  f3
 24-  f4 = expanded memory transfer base *
 25-  f5
 26-  f6 = transfer length *
 27-  f7
 28-  f8 = command code / expanded memory pages
 29-  f9 = device version / status
 30-  fa = device seven UUID address *
 31-  fb
 32-  fc = device thirteen UUID address *
 33-  fd
 34-  fe = device fourteen UUID address *
 35-  ff
 36-
 37-(If the program file is too big to fit into conventional memory, then as
 38-much as will fit of the rest will be loaded into expanded memory.)
 39-
 40-Reading the command code port will be the number of expanded memory pages
 41-(from 0 to 16). Writing the command code will execute the command, where
 42-the high nybble specifies which command to do and the low nybble is the
 43-parameter of that command. The command codes are:
 44-
 45-* 0 = Copy conventional memory to expanded memory. The parameter is the
 46-zero-based page number.
 47-
 48-* 1 = Copy expanded memory to conventional memory. The parameter is the
 49-zero-based page number.
 50-
 51-* 2 = Clear the screen. If bit0 is set then clear the background layer,
 52-and if bit1 is set then clear the foreground layer (set both bits to clear
 53-both layers).
 54-
 55-Writing to the UUID address ports will read sixteen bytes at that address
 56-and then will set the device version field to the version number, which
 57-can be zero if it is not implemented, an odd number for an unstable
 58-implementation, or an even number for a stable implementation. (The memory
 59-that it points to can be reused afterward with no problem.)
 60-
 61-The vector is called after passing command-line arguments, but before any
 62-other events occur. If accepting input from stdin, then it will also be
 63-called after all input from stdin has been read.
 64-
 65-The -x switch also changes the meaning of the delete and append ports of
 66-the file device. See below about extended file device.
 67-
 68-(Note: Using this feature will make the program not portable to other
 69-implementations, and should be avoided if possible. However, it is
 70-available if its functions (e.g. expanded memory) are needed in your
 71-program for any reason. Most programs probably will not need expanded
 72-memory; some might be able to optionally use it.)
 73-
 74-
 75-=== Extended file device ===
 76-
 77-(This section may be deprecated in future.)
 78-
 79-If the -x switch is used, then the delete and append ports of the file
 80-device have a different meaning than usual.
 81-
 82-N.B. Use of these extensions in an implementation which does not support
 83-them may cause files to be inadvertently deleted or corrupted. (This
 84-implementation will ignore the delete port entirely if the -x switch is
 85-not specified.) Furthermore, they may be changed in future; please make
 86-a discussion if you have any intention to use these extensions, or even
 87-to use the delete/append ports without these extensions. There are some
 88-problems with the design of the file device, so I would want to suggest
 89-these changes in order to make an improvement. Unfortunately, it is not
 90-as simple as other devices, but it may be necessary if file handling is
 91-to be working properly.
 92-
 93-The delete port can be given any of the values:
 94-
 95-* 0x00 = Does nothing.
 96-
 97-* 0x01 = Delete the current file. (Not currently implemented.)
 98-
 99-* 0x10 = Close the file.
100-
101-* 0x11 = Open the file for reading. Success is 1 if opened.
102-
103-* 0x12 = Open the file for writing. Success is 1 if opened.
104-
105-* 0x80 to 0x8F = Seek. Bit0 and bit1 specify how much the length field
106-should be multiplied by, where 0 means zero, 1 means one, 2 means 64K,
107-and 3 is reserved. Bit2 and bit3 indicate where to seek and which way,
108-where 0 means forward from the current position, 1 means backward from
109-the current position, 2 means forward from the beginning, and 3 means
110-backward from the end.
111-
112-Telling it to open a file will close it first, even if it is already open
113-in the correct mode. Also, seeking will not work unless the file is already
114-open, so it must first be opened, either by one of the above commands for
115-opening a file or by attempting to read from or write to it.
116-
117-The append port has one of the following values:
118-
119-* 0 = Files opened for writing are truncated.
120-
121-* 1 = Files opened for writing will append at the end of the file.
122-
123-* 2 = Files are opened for both reading and writing. In this case,
124-switching from reading to writing or vice-versa will not close and reopen
125-the file like it does in other cases. If writing is disabled, then this is
126-treated the same as 0.
127-
128-Any value may be bitwise ORed by sixteen to refuse to open a file for
129-writing if the file already exists.
130-
131-
132-=== Extension loading ===
133-
134-(This section describes a feature which is not implemented yet. Some
135-details might be changed before being implemented.)
136-
137-Some extensions may be implemented internally if that is necessary, but it
138-is expected that most extensions might be external, so that it is possible
139-to avoid putting too many things into the emulator.
140-
141-In the specified directory, are files named by the UUID (in lowercase
142-hexadecimal with hyphens) followed by ".so". This must export a function
143-named "uxn_extension_main", which is called the first time the extension
144-is loaded by the device UUID address fields being filled in by the Uxn
145-program. This function should return a pointer to the UxnExtension
146-structure for this extension, or null if it is somehow not valid. The
147-first argument is a pointer to the (binary) UUID, which can be used in
148-case the same file implements multiple extensions.
149+=== Nonstandard features ===
150+
151+The -x switch enables the following nonstandard features, which include
152+some nonstandard expansion commands and nonstandard ports. They should not
153+be used in portable programs until they become standardized, though (you
154+can discuss in the mailing list of Uxn; changes may also be made in future,
155+possibly as a result of the discussions).
156+
157+If any such features listed below become standardized in future, then their
158+documentation will be moved to the varvara.doc file, and the -x switch will
159+no longer be required in order to use them.
160+
161+The list of expansion commands below uses > for output parameters (from the
162+emulator to the program), ? for parameters that may be input and/or output,
163+* for 16-bit values, and % for values of lengths other than 8-bits or
164+16-bits or if they are of a variable length.
165+
166+02 >pages*
167+  Tells number of expanded memory pages. (This is the maximum valid value
168+  for src_page and dst_page in expanded memory operations.)
169+
170+03 device_id uuid% >version ?extra%
171+  Loads a nonstandard device. The device ID is the starting port number to
172+  use, which must be nonzero and must be a multiple of sixteen; some
173+  implementations may impose further restrictions. The UUID is sixteen
174+  bytes long. The version is zero if not implemented or nonzero if it is
175+  implemented (the specific value is defined by the specification of that
176+  extension). The extra data depends on the extension, and may be unused
177+  (if it is unknown or unused, then the emulator MUST ignore it and not
178+  make changes to that data).
179+
180+20 flag
181+  Clear screen. If flag bit0 is set, do not clear the background layer. If
182+  flag bit1 is set, do not clear the foreground layer. Other bits are
183+  reserved and must be clear.
184+
185+Nonstandard ports of devices are:
186+
187+17
188+  Indicates type of input in the low nybble. The high bit is set if it
189+  should execute the standard I/O vector for EOF and for the end of
190+  command-line arguments (for compatibility, normally it will not do
191+  this). The types of input are:
192+   0 = Standard input
193+   1 = EOF (*)
194+   2 = Command-line argument text
195+   3 = Delimiter of command-line arguments
196+   4 = End of command-line arguments (*)
197 
M main.c
+46, -85
  1@@ -360,22 +360,7 @@ static void load_rom(void) {
  2 static Uint8 default_in(Device*misc1,Uint8 misc2) { return misc1->d[misc2&15]; }
  3 static void default_out(Device*misc1,Uint8 misc2) {}
  4 
  5-static void expansion_command(Uint16 addr) {
  6-  Uint32 src,dst;
  7-  Uint16 len;
  8-  switch(mem[addr]) {
  9-    case 0x01:
 10-      len=GET16(mem+addr+1);
 11-      src=(GET16(mem+addr+3)<<8L)|(GET16(mem+addr+5));
 12-      dst=(GET16(mem+addr+7)<<8L)|(GET16(mem+addr+9));
 13-      if(src+len<=MEMSIZE && dst+len<=MEMSIZE) {
 14-        memmove(mem+dst,mem+src,len);
 15-      } else {
 16-        if(use_debug) fprintf(stderr,"! Access expanded memory out of range\n");
 17-      }
 18-      break;
 19-  }
 20-}
 21+static void expansion_command(Uint16 addr);
 22 
 23 static void system_out(Device*dev,Uint8 id) {
 24   switch(id) {
 25@@ -405,45 +390,6 @@ static void system_out(Device*dev,Uint8 id) {
 26   }
 27 }
 28 
 29-static Uint8 extension_in(Device*dev,Uint8 id) {
 30-  switch(id) {
 31-    case 8: return EXPANDED_MEMORY;
 32-    default: return dev->d[id];
 33-  }
 34-}
 35-
 36-static void extension_out(Device*dev,Uint8 id) {
 37-  Uint16 x,y,len;
 38-  switch(id) {
 39-    case 8:
 40-      switch(dev->d[8]>>4) {
 41-        case 0:
 42-          x=GET16(dev->d+2);
 43-          y=GET16(dev->d+4);
 44-          len=GET16(dev->d+6);
 45-          if(x+len>0x10000 || y+len>0x10000 || (dev->d[8]&15)>=EXPANDED_MEMORY) uxnerr(5,x);
 46-          memcpy(mem+y+((dev->d[8]&15)<<16)+0x10000,mem+x,len);
 47-          break;
 48-        case 1:
 49-          x=GET16(dev->d+2);
 50-          y=GET16(dev->d+4);
 51-          len=GET16(dev->d+6);
 52-          if(x+len>0x10000 || y+len>0x10000 || (dev->d[8]&15)>=EXPANDED_MEMORY) uxnerr(5,x);
 53-          memcpy(mem+x,mem+y+((dev->d[8]&15)<<16)+0x10000,len);
 54-          break;
 55-        case 2:
 56-          if(!screen) break;
 57-          if(dev->d[8]&1) memset(bglayer,0,scr_w*scr_h);
 58-          if(dev->d[8]&2) memset(fglayer,0,scr_w*scr_h);
 59-          break;
 60-      }
 61-      break;
 62-    case 11: case 13: case 15:
 63-      dev->d[9]=0;
 64-      break;
 65-  }
 66-}
 67-
 68 static void console_out(Device*dev,Uint8 id) {
 69   switch(id) {
 70     case 8: putchar(dev->d[8]); break;
 71@@ -496,19 +442,7 @@ static int files_set(Device*dev,int rw) {
 72   uf->mode=0;
 73   dev->d[2]=dev->d[3]=0;
 74   if(!uf->name[0]) return 0;
 75-  if(m && !use_extension) m=1;
 76-  if((m&15)==2 && rw && allow_write) {
 77-    if(rw==1) m&=15;
 78-    if(uf->file=fopen(uf->name,m&16?"w+x":"r+")) {
 79-      uf->mode=4;
 80-      return 1;
 81-    } else if(uf->file=fopen(uf->name,m&16?"w+x":"w+")) {
 82-      uf->mode=4;
 83-      return 1;
 84-    } else {
 85-      warn("Cannot open file '%s' for reading and writing",uf->name);
 86-    }
 87-  } else if(rw==1) {
 88+  if(rw==1) {
 89     if(uf->dir=opendir(uf->name)) {
 90       uf->mode=3;
 91       return 1;
 92@@ -519,7 +453,7 @@ static int files_set(Device*dev,int rw) {
 93       warn("Cannot open file '%s' for reading",uf->name);
 94     }
 95   } else if(rw==2 && allow_write) {
 96-    if(uf->file=fopen(uf->name,m==1?"a":m==17?"ax":m==16?"wx":"w")) {
 97+    if(uf->file=fopen(uf->name,m?"a":"w")) {
 98       uf->mode=2;
 99       return 1;
100     } else {
101@@ -542,19 +476,6 @@ static void files_out(Device*dev,Uint8 id) {
102       y=files_stat(AT_FDCWD,uf->name,len,mem+addr);
103       if(y<=len) PUT16(dev->d+2,y);
104       break;
105-    case 6:
106-      if(!use_extension) break;
107-      dev->d[2]=dev->d[3]=0;
108-      switch(dev->d[6]) {
109-        case 0x10 ... 0x12: // Close/open
110-          if(dev->d[6]==0x12 && !allow_write) goto disallow;
111-          dev->d[3]=files_set(dev,dev->d[6]&0x0F);
112-          break;
113-        case 0x80 ... 0x8F: // Seek
114-          files_seek(uf,dev->d[6]&0x0F,len);
115-          break;
116-      }
117-      break;
118     case 9:
119       addr=GET16(dev->d+8);
120       files_set(dev,0);
121@@ -892,6 +813,37 @@ static void run_audio(void) {
122   }
123 }
124 
125+static void expansion_command(Uint16 addr) {
126+  Uint32 src,dst;
127+  Uint16 len;
128+  switch(mem[addr]) {
129+    case 0x01:
130+      len=GET16(mem+addr+1);
131+      src=(GET16(mem+addr+3)<<8L)|(GET16(mem+addr+5));
132+      dst=(GET16(mem+addr+7)<<8L)|(GET16(mem+addr+9));
133+      if(src+len<=MEMSIZE && dst+len<=MEMSIZE) {
134+        memmove(mem+dst,mem+src,len);
135+      } else {
136+        if(use_debug) fprintf(stderr,"! Access expanded memory out of range\n");
137+      }
138+      break;
139+    case 0x02:
140+      if(!use_extension) break;
141+      PUT16(mem+addr+1,EXPANDED_MEMORY);
142+      break;
143+    case 0x03:
144+      if(!use_extension) break;
145+      mem[addr+18]=0;
146+      break;
147+    case 0x20:
148+      if(!use_extension || !use_screen) break;
149+      if(size_changed || !bglayer) set_screen_mode(scr_w,scr_h);
150+      if(!(mem[addr+1]&0x01)) memset(bglayer,0,scr_w*scr_h);
151+      if(!(mem[addr+1]&0x02)) memset(bglayer+scr_w*scr_h,0,scr_w*scr_h);
152+      break;
153+  }
154+}
155+
156 static void debug_screen(Uint8*s,Uint8 k) {
157   static Sint8 page=0;
158   static Uint8 port=0;
159@@ -1337,7 +1289,7 @@ int main(int argc,char**argv) {
160     case 's': scroll_size=strtol(optarg,0,10); break;
161     case 't': timer_rate=strtol(optarg,0,10); break;
162     case 'w': default_width=strtol(optarg,0,10); break;
163-    case 'x': use_extension=1; device[15].in=extension_in; device[15].out=extension_out; break;
164+    case 'x': use_extension=1; break;
165     case 'y': allow_write=0; device[10].out=device[11].out=files_out; device[10].in=device[11].in=files_in; break;
166     case 'z': zoom=strtol(optarg,0,10); break;
167     default: return 1;
168@@ -1366,14 +1318,19 @@ int main(int argc,char**argv) {
169   ds.p=rs.p=0;
170   run(0x0100);
171   if(device[1].d[0] || device[1].d[1]) for(i=optind+1;i<argc;i++) {
172+    if(use_extension) device[1].d[7]=(device[1].d[7]&0xF0)|0x02;
173     for(j=0;argv[i][j];j++) {
174       device[1].d[2]=argv[i][j];
175       run(GET16(device[1].d));
176     }
177     device[1].d[2]='\n';
178+    if(use_extension) device[1].d[7]=(device[1].d[7]&0xF0)|0x03;
179+    run(GET16(device[1].d));
180+  }
181+  if(use_extension && (device[1].d[7]&0x80)) {
182+    device[1].d[7]=(device[1].d[7]&0xF0)|0x04;
183     run(GET16(device[1].d));
184   }
185-  if(device[15].out==extension_out) run(GET16(device[15].d));
186   if(use_screen) {
187     if(size_changed) set_screen_mode(scr_w,scr_h);
188     while(run_screen()) {
189@@ -1384,11 +1341,15 @@ int main(int argc,char**argv) {
190   } else if(audio_option) {
191     run_audio();
192   } else {
193+    if(use_extension) device[1].d[7]&=0xF0;
194     while((device[1].d[0] || device[1].d[1]) && ((i=getchar())>=0)) {
195       device[1].d[2]=i;
196       run(GET16(device[1].d));
197     }
198-    if(device[15].out==extension_out) run(GET16(device[15].d));
199+    if(use_extension && (device[1].d[7]&0x80)) {
200+      device[1].d[7]=(device[1].d[7]&0xF0)|0x01;
201+      run(GET16(device[1].d));
202+    }
203   }
204   return 0;
205 }