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 }