commit 95d5c37

zzo38  ·  2022-10-29 06:26:33 +0000 UTC
parent 3396c1b
Extensions (currently only expanded memory)
2 files changed,  +97, -2
M main.c
+71, -0
 1@@ -54,6 +54,9 @@
 2 -w #
 3   Set default screen width.
 4 
 5+-x
 6+  Enable extension device (only built-in extensions).
 7+
 8 -y
 9   Enable read-only file system access.
10 
11@@ -96,3 +99,71 @@ work in this program; therefore, END is an alias for the joypad A button
12 (the left control key also corresponds to the joypad A button, but if used
13 together with letter keys, will enter control characters instead).
14 
15+
16+=== Extension device ===
17+
18+Device fifteen is the extension device, which is defined as:
19+  f0 = vector *
20+  f1
21+  f2 = conventional memory transfer base *
22+  f3
23+  f4 = expanded memory transfer base *
24+  f5
25+  f6 = transfer length *
26+  f7
27+  f8 = transfer operation
28+  f9 = device version
29+  fa = device seven UUID address *
30+  fb
31+  fc = device thirteen UUID address *
32+  fd
33+  fe = device fourteen UUID address *
34+  ff
35+
36+The transfer operation is used for copying data to/from expanded memory.
37+Use the bits as following:
38+
39+* bit0 = Set to transfer conventional to expanded memory, or clear to
40+transfer expanded to conventional memory.
41+
42+* bit1 = Selects which page of expanded memory to use.
43+
44+Other bits are reserved and must be clear.
45+
46+If the program file is too big to fit into conventional memory, then as
47+much as will fit of the rest will be loaded into expanded memory.
48+
49+Writing to the UUID address ports will read sixteen bytes at that address
50+and then will set the device version field to the version number, which
51+can be zero if it is not implemented, an odd number for an unstable
52+implementation, or an even number for a stable implementation. (The memory
53+that it points to can be reused afterward with no problem.)
54+
55+The vector is called after passing command-line arguments, but before any
56+other events occur.
57+
58+(Note: Using this feature will make the program not portable to other
59+implementations, and should be avoided if possible. However, it is
60+available if its functions (e.g. expanded memory) are needed in your
61+program for any reason. Most programs probably will not need expanded
62+memory; some might be able to optionally use it.)
63+
64+
65+=== Extension loading ===
66+
67+(This section describes a feature which is not implemented yet. Some
68+details might be changed before being implemented.)
69+
70+Some extensions may be implemented internally if that is necessary, but it
71+is expected that most extensions might be external, so that it is possible
72+to avoid putting too many things into the emulator.
73+
74+In the specified directory, are files named by the UUID (in lowercase
75+hexadecimal with hyphens) followed by ".so". This must export a function
76+named "uxn_extension_main", which is called the first time the extension
77+is loaded by the device UUID address fields being filled in by the Uxn
78+program. This function should return a pointer to the UxnExtension
79+structure for this extension, or null if it is somehow not valid. The
80+first argument is a pointer to the (binary) UUID, which can be used in
81+case the same file implements multiple extensions.
82+
M main.c
+26, -2
 1@@ -296,6 +296,29 @@ static void system_out(Device*dev,Uint8 id) {
 2   }
 3 }
 4 
 5+static void extension_out(Device*dev,Uint8 id) {
 6+  Uint8*p;
 7+  Uint8*q;
 8+  Uint16 x,y;
 9+  Uint16 len;
10+  switch(id) {
11+    case 8:
12+      x=GET16(dev->d+2);
13+      y=GET16(dev->d+4);
14+      len=GET16(dev->d+6);
15+      if(dev->d[8]&4) len=256;
16+      if(x+len>0x10000 || y+len>0x10000) uxnerr(5,x);
17+      *(dev->d[8]&1?&p:&q)=mem+x;
18+      *(dev->d[8]&1?&q:&p)=mem+y+(dev->d[8]&2?0x20000:0x10000);
19+      memcpy(q,p,len);
20+      dev->d[8]=0;
21+      break;
22+    case 11: case 13: case 15:
23+      dev->d[9]=0;
24+      break;
25+  }
26+}
27+
28 static void console_out(Device*dev,Uint8 id) {
29   switch(id) {
30     case 8: putchar(dev->d[8]); break;
31@@ -663,8 +686,7 @@ int main(int argc,char**argv) {
32   device[10].aux=&uxnfile0;
33   device[11].aux=&uxnfile1;
34   device[12].in=datetime_in;
35-  while((i=getopt(argc,argv,"+ADFNQT:YZdh:inp:qt:w:yz:"))>0) switch(i) {
36-    case 'A': scrflags|=SDL_ASYNCBLIT; break;
37+  while((i=getopt(argc,argv,"+ADFNQT:YZdh:inp:qt:w:xyz:"))>0) switch(i) {
38     case 'D': scrflags|=SDL_DOUBLEBUF; break;
39     case 'F': scrflags|=SDL_FULLSCREEN; break;
40     case 'N': scrflags|=SDL_NOFRAME; break;
41@@ -680,6 +702,7 @@ int main(int argc,char**argv) {
42     case 'q': use_console=0; break;
43     case 't': timer_rate=strtol(optarg,0,10); break;
44     case 'w': default_width=strtol(optarg,0,10); break;
45+    case 'x': device[15].out=extension_out; break;
46     case 'y': allow_write=0; device[10].out=device[11].out=files_out; device[10].in=device[11].in=files_in; break;
47     case 'z': zoom=strtol(optarg,0,10); break;
48     default: return 1;
49@@ -715,6 +738,7 @@ int main(int argc,char**argv) {
50     device[1].d[2]='\n';
51     run(GET16(device[1].d));
52   }
53+  if(device[15].out==extension_out) run(GET16(device[15].d));
54   if(use_screen) {
55     while(run_screen()) {
56       for(i=0;i<15;i++) for(j=0;j<16;j++) device[i].d[j]=0;