|
|
1.1 root 1: /*
2: Hatari
3:
4: VDI (Virtual Device Interface) (Trap #2)
5:
6: To get higher resolutions on the Desktop, we intercept the VDI/Line-A calls and set elements
7: in their structures to the higher width/height/cel/planes. We need to intercept the initial Line-A
8: call(which we force into the TOS on boot-up) and also the init calls to the VDI.
9: As we intercept the VDI calls, this is a good point to pass them on to the accelerated native
10: PC functions if we need to - this improves drawing speed far greater than any ST software
11: accelerator.
12: */
13:
14: #include "main.h"
15: #include "decode.h"
16: #include "file.h"
17: #include "gemdos.h"
18: #include "m68000.h"
19: #include "memAlloc.h"
20: #include "screen.h"
21: #include "stMemory.h"
22: #include "vdi.h"
23: #include "video.h"
1.1.1.3 ! root 24: #include "uae-cpu/newcpu.h"
1.1 root 25:
26:
1.1.1.2 root 27: BOOL bUseVDIRes=FALSE; /* Set to TRUE (if want VDI), or FALSE (ie for games) */
28: int LineABase; /* Line-A structure */
29: int FontBase; /* Font base, used for 16-pixel high font */
30: unsigned int VDI_OldPC; /* When call Trap#2, store off PC */
31:
32: int VDIWidth=640,VDIHeight=480; /* 640x480,800x600 or 1024x768 */
33: int VDIRes=0; /* 0,1 or 2(low, medium, high) */
34: int VDIPlanes=4,VDIColours=16,VDICharHeight=8; /* To match VDIRes */
1.1 root 35:
36: unsigned long Control;
37: unsigned long Intin;
38: unsigned long Ptsin;
39: unsigned long Intout;
40: unsigned long Ptsout;
41:
1.1.1.2 root 42:
43: /*-----------------------------------------------------------------------*/
44: /* Desktop TOS 1.04 and TOS 2.06 desktop configuration files */
1.1.1.3 ! root 45: unsigned char DesktopScript[504] =
! 46: {
1.1 root 47: 0x23,0x61,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,0x23,0x62,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,0x23,0x63,0x37,0x37,0x37,0x30,0x30,0x30,0x37,0x30,0x30,0x30,
48: 0x36,0x30,0x30,0x30,0x37,0x30,0x30,0x35,0x35,0x32,0x30,0x30,0x35,0x30,0x35,0x35,0x35,0x32,0x32,0x32,0x30,0x37,0x37,0x30,0x35,0x35,0x37,0x30,0x37,0x35,0x30,0x35,
49: 0x35,0x35,0x30,0x37,0x37,0x30,0x33,0x31,0x31,0x31,0x31,0x30,0x33,0x0D,0x0A,0x23,0x64,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
50: 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0D,0x0A,
51: 0x23,0x45,0x20,0x31,0x38,0x20,0x31,0x31,0x20,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x37,0x20,0x32,0x36,0x20,0x30,0x43,0x20,
52: 0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x32,0x20,0x30,0x42,0x20,0x32,0x36,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,
53: 0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x41,0x20,0x30,0x46,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,
54: 0x30,0x20,0x30,0x30,0x20,0x30,0x45,0x20,0x30,0x31,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x31,0x20,0x30,0x30,0x20,
55: 0x30,0x30,0x20,0x46,0x46,0x20,0x43,0x20,0x48,0x41,0x52,0x44,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,0x30,0x20,
56: 0x30,0x30,0x20,0x46,0x46,0x20,0x41,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,
57: 0x31,0x20,0x30,0x30,0x20,0x46,0x46,0x20,0x42,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x54,0x20,0x30,0x30,
58: 0x20,0x30,0x33,0x20,0x30,0x32,0x20,0x46,0x46,0x20,0x20,0x20,0x54,0x52,0x41,0x53,0x48,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x46,0x20,0x46,0x46,0x20,0x30,0x34,0x20,
59: 0x20,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x0D,0x0A,0x23,0x44,0x20,0x46,0x46,0x20,0x30,0x31,0x20,0x20,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x0D,0x0A,0x23,
60: 0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x20,0x20,0x2A,0x2E,0x41,0x50,0x50,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x20,0x20,
61: 0x2A,0x2E,0x50,0x52,0x47,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x50,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x20,0x20,0x2A,0x2E,0x54,0x54,0x50,0x40,0x20,0x40,0x20,0x0D,
62: 0x0A,0x23,0x46,0x20,0x30,0x33,0x20,0x30,0x34,0x20,0x20,0x20,0x2A,0x2E,0x54,0x4F,0x53,0x40,0x20,0x40,0x20,0x0D,0x0A,0x1A,
63: };
64:
1.1.1.3 ! root 65: unsigned char NewDeskScript[786] =
! 66: {
1.1 root 67: 0x23,0x61,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,0x23,0x62,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,0x23,0x63,0x37,0x37,0x37,0x30,0x30,0x30,0x37,0x30,0x30,0x30,
68: 0x36,0x30,0x30,0x30,0x37,0x30,0x30,0x35,0x35,0x32,0x30,0x30,0x35,0x30,0x35,0x35,0x35,0x32,0x32,0x32,0x30,0x37,0x37,0x30,0x35,0x35,0x37,0x30,0x37,0x35,0x30,0x35,
69: 0x35,0x35,0x30,0x37,0x37,0x30,0x33,0x31,0x31,0x31,0x31,0x30,0x33,0x0D,0x0A,0x23,0x64,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
70: 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0D,0x0A,
71: 0x23,0x4B,0x20,0x34,0x46,0x20,0x35,0x33,0x20,0x34,0x43,0x20,0x30,0x30,0x20,0x34,0x36,0x20,0x34,0x32,0x20,0x34,0x33,0x20,0x35,0x37,0x20,0x34,0x35,0x20,0x35,0x38,
72: 0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,
73: 0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x35,0x32,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x34,0x44,0x20,0x35,0x36,0x20,0x35,0x30,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,
74: 0x23,0x45,0x20,0x31,0x38,0x20,0x30,0x31,0x20,0x30,0x30,0x20,0x30,0x36,0x20,0x0D,0x0A,0x23,0x51,0x20,0x34,0x31,0x20,0x34,0x30,0x20,0x34,0x33,0x20,0x34,0x30,0x20,
75: 0x34,0x33,0x20,0x34,0x30,0x20,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x37,0x20,0x32,0x36,0x20,0x30,0x43,0x20,0x30,0x30,0x20,
76: 0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x32,0x20,0x30,0x42,0x20,0x32,0x36,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,
77: 0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x41,0x20,0x30,0x46,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,
78: 0x30,0x20,0x30,0x45,0x20,0x30,0x31,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x34,0x20,
79: 0x30,0x37,0x20,0x32,0x36,0x20,0x30,0x43,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x43,0x20,0x30,0x42,0x20,0x32,0x36,
80: 0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x38,0x20,0x30,0x46,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,
81: 0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x36,0x20,0x30,0x31,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,
82: 0x23,0x4E,0x20,0x46,0x46,0x20,0x30,0x34,0x20,0x30,0x30,0x30,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x44,0x20,0x46,0x46,0x20,0x30,0x31,
83: 0x20,0x30,0x30,0x30,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x41,
84: 0x50,0x50,0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x50,0x52,0x47,0x40,0x20,0x40,0x20,
85: 0x40,0x20,0x0D,0x0A,0x23,0x59,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x47,0x54,0x50,0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x50,
86: 0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x54,0x54,0x50,0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x46,0x20,0x30,0x33,0x20,0x30,0x34,
87: 0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x54,0x4F,0x53,0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,0x31,0x20,0x30,0x30,0x20,0x46,0x46,
88: 0x20,0x43,0x20,0x48,0x41,0x52,0x44,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x46,0x46,
89: 0x20,0x41,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x31,0x20,0x30,0x30,0x20,0x30,0x30,0x20,
90: 0x46,0x46,0x20,0x42,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x54,0x20,0x30,0x30,0x20,0x30,0x33,0x20,0x30,
91: 0x32,0x20,0x46,0x46,0x20,0x20,0x20,0x54,0x52,0x41,0x53,0x48,0x40,0x20,0x40,0x20,0x0D,0x0A,
92: };
93:
1.1.1.2 root 94:
95: /*-----------------------------------------------------------------------*/
1.1 root 96: /*
97: Set Width/Height/BitDepth according to passed GEMRES_640x480, GEMRES_800x600 or GEMRES_1024x768
98: */
99: void VDI_SetResolution(int GEMRes,int GEMColour)
100: {
1.1.1.2 root 101: /* Resolution */
1.1.1.3 ! root 102: switch(GEMRes)
! 103: {
1.1 root 104: case GEMRES_640x480:
105: VDIWidth = 640;
106: VDIHeight = 480;
107: break;
108: case GEMRES_800x600:
109: VDIWidth = 800;
110: VDIHeight = 600;
111: break;
112: case GEMRES_1024x768:
113: VDIWidth = 1024;
114: VDIHeight = 768;
115: break;
116: }
117:
1.1.1.2 root 118: /* Colour depth */
1.1.1.3 ! root 119: switch(GEMColour)
! 120: {
1.1 root 121: case GEMCOLOUR_2:
122: VDIRes = 2;
123: VDIPlanes = 1;
124: VDIColours = 2;
125: VDICharHeight = 16;
126: break;
127: case GEMCOLOUR_4:
128: VDIRes = 1;
129: VDIPlanes = 2;
130: VDIColours = 4;
131: VDICharHeight = 8;
132: break;
133: case GEMCOLOUR_16:
134: VDIRes = 0;
135: VDIPlanes = 4;
136: VDIColours = 16;
137: VDICharHeight = 8;
138: break;
139: }
140:
1.1.1.2 root 141: /* Force screen code to re-set bitmap/full-screen */
1.1 root 142: Screen_SetDrawModes();
1.1.1.3 ! root 143: /*Screen_SetupRGBTable();*/
1.1 root 144: Screen_SetFullUpdate();
145: PrevSTRes = -1;
146:
1.1.1.2 root 147: /* Write resolution to re-boot takes effect with correct bit-depth */
1.1 root 148: VDI_FixDesktopInf();
149: }
150:
1.1.1.2 root 151:
152: /*-----------------------------------------------------------------------*/
1.1 root 153: /*
154: Check VDI call and see if we need to re-direct to our own routines
155: Return TRUE if we've handled the exception, else return FALSE
156:
157: We enter here with Trap #2, so D1 is pointer to VDI vectors, ie Control, Intin, Ptsin etc...
158: */
159: BOOL VDI(void)
160: {
161: unsigned long TablePtr = Regs[REG_D1];
1.1.1.3 ! root 162: /*unsigned short int OpCode;*/
1.1 root 163:
1.1.1.2 root 164: /* Read off table pointers */
1.1 root 165: Control = STMemory_ReadLong(TablePtr);
166: Intin = STMemory_ReadLong(TablePtr+4);
167: Ptsin = STMemory_ReadLong(TablePtr+8);
168: Intout = STMemory_ReadLong(TablePtr+12);
169: Ptsout = STMemory_ReadLong(TablePtr+16);
170:
1.1.1.3 ! root 171: /*
! 172: OpCode = STMemory_ReadWord(Control);
1.1 root 173: // Check OpCode
174: // 8 - Text Font
1.1.1.3 ! root 175: if (OpCode==9)
! 176: {
! 177: return(TRUE);
! 178: }
! 179: */
1.1 root 180:
1.1.1.2 root 181: /* Call as normal! */
1.1 root 182: return(FALSE);
183: }
184:
1.1.1.2 root 185:
186: /*-----------------------------------------------------------------------*/
1.1 root 187: /*
188: Modify Line-A structure for our VDI resolutions
189: */
190: void VDI_LineA(void)
191: {
1.1.1.3 ! root 192: if (bUseVDIRes)
! 193: {
1.1.1.2 root 194: STMemory_WriteWord(LineABase-6*2,VDIWidth); /* v_rez_hz */
195: STMemory_WriteWord(LineABase-2*2,VDIHeight); /* v_rez_vt */
196: STMemory_WriteWord(LineABase-1*2,(VDIWidth*VDIPlanes)/8); /* bytes_lin */
197: STMemory_WriteWord(LineABase+1*2,(VDIWidth*VDIPlanes)/8); /* width */
198:
199: STMemory_WriteWord(LineABase-23*2,VDICharHeight); /* char height */
200: STMemory_WriteWord(LineABase-22*2,(VDIWidth/8)-1); /* v_cel_mx */
201: STMemory_WriteWord(LineABase-21*2,(VDIHeight/VDICharHeight)-1); /* v_cel_my */
202: STMemory_WriteWord(LineABase-20*2,VDICharHeight*((VDIWidth*VDIPlanes)/8)); /* v_cel_wr */
1.1 root 203:
1.1.1.2 root 204: STMemory_WriteWord(LineABase-0*2,VDIPlanes); /* planes */
1.1 root 205: }
206: }
207:
1.1.1.2 root 208:
209: /*-----------------------------------------------------------------------*/
1.1 root 210: /*
211: This is called on completion of a VDI Trap, used to modify return structure for
212: */
213: void VDI_Complete(void)
214: {
215: unsigned short int OpCode;
216:
217: OpCode = STMemory_ReadWord(Control);
1.1.1.2 root 218: /* Is 'Open Workstation', or 'Open Virtual Screen Workstation'? */
1.1.1.3 ! root 219: if ( (OpCode==1) || (OpCode==100) )
! 220: {
1.1.1.2 root 221: STMemory_WriteWord(Intout,VDIWidth-1); /* IntOut[0] Width-1 */
222: STMemory_WriteWord(Intout+1*2,VDIHeight-1); /* IntOut[1] Height-1 */
223: STMemory_WriteWord(Intout+13*2,VDIColours); /* IntOut[13] #colours */
224: STMemory_WriteWord(Intout+39*2,512); /* IntOut[39] #available colours */
1.1 root 225:
1.1.1.2 root 226: STMemory_WriteWord(LineABase-0x15a*2,VDIWidth-1); /* WKXRez */
227: STMemory_WriteWord(LineABase-0x159*2,VDIHeight-1); /* WKYRez */
1.1 root 228:
1.1.1.2 root 229: VDI_LineA(); /* And modify Line-A structure accordingly */
1.1 root 230: }
231: }
232:
1.1.1.2 root 233:
234: /*-----------------------------------------------------------------------*/
1.1 root 235: /*
236: Save desktop configuration file for VDI, eg desktop.inf(TOS 1.04) or newdesk.inf(TOS 2.06)
237: */
238: void VDI_SaveDesktopInf(char *pszFileName,unsigned char *Script,long ScriptSize)
239: {
1.1.1.2 root 240: /* Just save file */
241: File_Save(pszFileName, Script, ScriptSize, FALSE);
1.1 root 242: }
243:
1.1.1.2 root 244:
245: /*-----------------------------------------------------------------------*/
1.1 root 246: /*
247: Modify exisiting ST desktop configuration files to set resolution(keep user settings)
248: */
249: void VDI_ModifyDesktopInf(char *pszFileName)
250: {
251: long InfSize;
252: unsigned char *pInfData;
253: int i;
254:
1.1.1.2 root 255: /* Load our '.inf' file */
1.1 root 256: pInfData = (unsigned char *)File_Read(pszFileName,NULL,&InfSize,NULL);
1.1.1.3 ! root 257: if (pInfData)
! 258: {
1.1.1.2 root 259: /* Scan file for '#E' */
1.1 root 260: i = 0;
1.1.1.3 ! root 261: while(i<(InfSize-8))
! 262: {
! 263: if ( (pInfData[i]=='#') && (pInfData[i+1]=='E') )
! 264: {
1.1.1.2 root 265: /* Modify resolution */
1.1 root 266: pInfData[i+7] = '1'+VDIRes;
267: goto done_modify;
268: }
269:
270: i++;
271: }
272:
273: done_modify:;
274: /* And save */
1.1.1.2 root 275: File_Save(pszFileName, pInfData, InfSize, FALSE);
1.1 root 276: /* Free */
277: Memory_Free(pInfData);
278: }
279: }
280:
1.1.1.2 root 281:
282: /*-----------------------------------------------------------------------*/
1.1 root 283: /*
1.1.1.3 ! root 284: Modify (or create) ST desktop configuration files so VDI boots up in
! 285: correct color depth
1.1 root 286: */
287: void VDI_FixDesktopInf(void)
288: {
289: char szDesktopFileName[MAX_FILENAME_LENGTH],szNewDeskFileName[MAX_FILENAME_LENGTH];
290:
1.1.1.3 ! root 291: if(!GEMDOS_EMU_ON)
! 292: {
! 293: /* Can't modify DESKTOP.INF when not using GEMDOS hard disk emulation */
! 294: return;
! 295: }
! 296:
1.1 root 297: /* Create filenames for hard-drive */
1.1.1.3 ! root 298: GemDOS_CreateHardDriveFileName(2,"/DESKTOP.INF",szDesktopFileName);
! 299: GemDOS_CreateHardDriveFileName(2,"/NEWDESK.INF",szNewDeskFileName);
1.1 root 300:
301: /* First, check if files exist(ie modify or replace) */
302: if (!File_Exists(szDesktopFileName))
303: VDI_SaveDesktopInf(szDesktopFileName,DesktopScript,sizeof(DesktopScript));
304: VDI_ModifyDesktopInf(szDesktopFileName);
305:
306: if (!File_Exists(szNewDeskFileName))
307: VDI_SaveDesktopInf(szNewDeskFileName,NewDeskScript,sizeof(NewDeskScript));
308: VDI_ModifyDesktopInf(szNewDeskFileName);
309: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.