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;