Inform - Support - Patches

About Patches  

Compiler  
Library  

DM4 Errata  

Issue C62114

Inform-generated V6 and V7 files are limited to 320K
Submitted by: Kevin Bracey     Appeared in: Compiler 6.21 or before     Fixed in: Compiler 6.30
Problem

The ofclass and metaclass operators in Inform take a 16-bit number, which in some way describes an entity, and have to determine what the number represents. The scheme currently used is (HON is the highest object number):

  0          represents "nothing"
  1..HON     represent that object
  HON+1..X-1 represent the packed address of a routine
  X..        represent the packed address of a string

For more details see section 8.8 of the Inform Technical Manual.

For this scheme to work, all packed addresses need to be higher than the highest object number, and in V6 and V7 the string offset and routine offset need to be the same so that the packed addresses of strings are higher than the packed addresses of routines.

The first of these is not a significant problem, but by requiring the string and routine offsets to be the same, the maximum size of Inform-generated V6 and V7 games is limited to 320K.

V6 and V7 allow up to 64K of low memory, 256K of code and 256K of strings, with a total size limit of 512K (limited by the file size field in the header - otherwise it could be 576K). Inform limits us to 64K of low memory + 256K of code/strings.

Solution

Modify the compiler to place routines at byte addresses which are multiples of 8, and strings at byte addresses which are not. Then strings and routines can be distinguished by inspecting the least significant bit of the packed address, and the string offset can be raised.

This will slightly impact code size, because of the increased padding between routines and strings, thus losing the space advantage that the other versions have over V8, but it will allow files of up to (nearly) 512K.

--- asm.c~   Wed Apr 28 21:14:08 1999
+++ asm.c    Sun Nov 25 21:48:14 2001
@@ -1017,7 +1017,10 @@

     {   uchar zero[1];
         zero[0] = 0;
-        while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
+        if (oddeven_packing_switch)
+            while ((adjusted_pc%(scale_factor*2))!=0) transfer_byte(zero);
+        else
+            while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
     }

     zmachine_pc = adjusted_pc;
--- expressp.c~      Wed Apr 28 21:15:42 1999
+++ expressp.c       Thu Nov 22 23:07:33 2001
@@ -660,6 +660,9 @@
                  case lowest_fake_action_number_SC:
                      o->type = LONG_CONSTANT_OT; o->marker = 0;
                      v = ((grammar_version_number==1)?256:4096); break;
+                 case oddeven_packing_SC:
+                     o->type = SHORT_CONSTANT_OT; o->marker = 0;
+                     v = oddeven_packing_switch; break;
                  default:
                      v = t.value;
                      o->marker = INCON_MV;
--- inform.c~        Wed Apr 28 21:16:02 1999
+++ inform.c         Sun Nov 25 21:49:58 2001
@@ -83,6 +83,7 @@
     nowarnings_switch,              /* -w */
     hash_switch,                    /* -x */
     memory_map_switch,              /* -z */
+    oddeven_packing_switch,         /* -B */
     define_DEBUG_switch,            /* -D */
     temporary_files_switch,         /* -F */
     module_switch,                  /* -M */
@@ -135,6 +136,7 @@
     nowarnings_switch = FALSE;
     hash_switch = FALSE;
     memory_map_switch = FALSE;
+    oddeven_packing_switch = FALSE;
     define_DEBUG_switch = FALSE;
 #ifdef USE_TEMPORARY_FILES
     temporary_files_switch = TRUE;
@@ -1011,6 +1013,7 @@
   z   print memory map of the Z-machine\n\n");

 printf("\
+  B   use big memory model (for large V6/V7 files)\n\
   C0  text character set is plain ASCII only\n\
   Cn  text character set is ISO 8859-n (n = 1 to 9)\n\
       (1 to 4, Latin1 to Latin4; 5, Cyrillic; 6, Arabic;\n\
@@ -1128,6 +1131,7 @@
         case 'y': s=2; linker_trace_setting=p[i+1]-'0'; break;
         case 'z': memory_map_switch = state; break;

+        case 'B': oddeven_packing_switch = state; break;
         case 'C': s=2; character_set_setting=p[i+1]-'0';
                   if ((character_set_setting < 0)
                       || (character_set_setting > 9))
--- lexer.c~ Wed Apr 28 21:16:13 1999
+++ lexer.c  Thu Nov 22 22:35:33 2001
@@ -331,6 +331,7 @@
     "constant_names_array",
     "lowest_class_number", "highest_class_number", "class_objects_array",
     "lowest_object_number", "highest_object_number",
+    "oddeven_packing",
     "" },
     SYSTEM_CONSTANT_TT, FALSE, TRUE
 };
--- tables.c~        Wed Apr 28 21:17:46 1999
+++ tables.c         Sun Nov 25 21:39:14 2001
@@ -155,7 +155,7 @@
               + 2*no_grammar_token_routines;     /* general parsing routines */

     total += (subtract_pointers(dictionary_top, dictionary))  /* dictionary */
-             + ((module_switch)?18:0);                        /* module map */
+             + ((module_switch)?30:0);                        /* module map */

     total += scale_factor*0x100            /* maximum null bytes before code */
             + 1000;             /* fudge factor (in case the above is wrong) */
@@ -516,6 +516,8 @@

     while ((mark%length_scale_factor) != 0) p[mark++]=0;
     while (mark < (scale_factor*0x100)) p[mark++]=0;
+    if (oddeven_packing_switch)
+        while ((mark%(scale_factor*2)) != 0) p[mark++]=0;

     if (mark > 0x10000)
     {   error("This program has overflowed the maximum readable-memory \
@@ -534,7 +536,14 @@

     /*  ------------------ Another synchronising gap ----------------------- */

-    while ((mark%scale_factor) != 0) mark++;
+    if (oddeven_packing_switch)
+    {   if (module_switch)
+             while ((mark%(scale_factor*2)) != 0) mark++;
+        else
+             while ((mark%(scale_factor*2)) != scale_factor) mark++;
+    }
+    else
+        while ((mark%scale_factor) != 0) mark++;

     /*  ------------------------- Strings Area ----------------------------- */

@@ -559,8 +568,8 @@
         case 4:
         case 5: excess = Out_Size-((int32) 0x40000L); limit = 256; break;
         case 6:
+        case 7:
         case 8: excess = Out_Size-((int32) 0x80000L); limit = 512; break;
-        case 7: excess = 0;                           limit = 320; break;
     }

     if (module_switch)
@@ -589,8 +598,42 @@
     {   extend_offset=256;
         if (no_objects+9 > extend_offset) extend_offset=no_objects+9;
         while ((extend_offset%length_scale_factor) != 0) extend_offset++;
+        /* Not sure why above line is necessary, but oddeven_packing
+         * will need extend_offset to be even */
         code_offset = extend_offset*scale_factor;
-        strings_offset = code_offset + (Write_Strings_At-Write_Code_At);
+        if (oddeven_packing_switch)
+            strings_offset = code_offset + scale_factor;
+        else
+            strings_offset = code_offset + (Write_Strings_At-Write_Code_At);
+
+        /* With the extended memory model, need to specifically check that we
+         * haven't overflowed the packed address range for routines or strings.
+         * With the standard memory model, we only need the earlier total size
+         * check.
+         */
+        excess = zmachine_pc + code_offset - (scale_factor*((int32) 0x10000L));
+        if (excess > 0)
+        {   char code_full_error[80];
+            sprintf(code_full_error,
+                "The code area limit has been exceeded by %d bytes",
+                 excess);
+            fatalerror(code_full_error);
+        }
+
+        excess = strings_length + strings_offset - (scale_factor*((int32) 0x10000L));
+        if (excess > 0)
+        {   char strings_full_error[140];
+            if (oddeven_packing_switch)
+                sprintf(strings_full_error,
+                    "The strings area limit has been exceeded by %d bytes",
+                     excess);
+            else
+                sprintf(strings_full_error,
+                    "The code+strings area limit has been exceeded by %d bytes. \
+ Try running Inform again with -B on the command line.",
+                     excess);
+            fatalerror(strings_full_error);
+        }
     }
     else
     {   code_offset = Write_Code_At;
@@ -632,6 +675,8 @@
     if (extend_memory_map)
     {   j=(Write_Code_At - extend_offset*scale_factor)/length_scale_factor;
         p[40]=j/256; p[41]=j%256;                         /* Routines offset */
+        if (oddeven_packing_switch)
+            j=(Write_Strings_At - extend_offset*scale_factor)/length_scale_factor;
         p[42]=j/256; p[43]=j%256;                        /* = Strings offset */
     }

--- text.c~  Wed Apr 28 21:17:59 1999
+++ text.c   Sun Nov 25 21:51:36 2001
@@ -188,9 +188,14 @@
     /* Insert null bytes as needed to ensure that the next static string */
     /* also occurs at an address expressible as a packed address         */

-    while ((i%scale_factor)!=0)
-    {   i+=2; *c++ = 0; *c++ = 0;
-    }
+    if (oddeven_packing_switch)
+        while ((i%(scale_factor*2))!=0)
+        {   i+=2; *c++ = 0; *c++ = 0;
+        }
+    else
+        while ((i%scale_factor)!=0)
+        {   i+=2; *c++ = 0; *c++ = 0;
+        }

     j = static_strings_extent;

--- veneer.c~        Tue May 08 20:01:16 2001
+++ veneer.c         Sun Nov 25 16:32:34 2001
@@ -594,9 +594,18 @@
         "addr;\
          if (addr==0) rfalse;\
          if (addr>=1 && addr<=(#largest_object-255)) rtrue;\
+         #iftrue #oddeven_packing;\
+         @test addr 1 ?~NotString;\
+         if (Unsigned__Compare(addr, #strings_offset)<0) rfalse;\
+         return 3;\
+         .NotString;\
+         if (Unsigned__Compare(addr, #code_offset)<0) rfalse;\
+         return 2;\
+         #ifnot;\
          if (Unsigned__Compare(addr, #strings_offset)>=0) return 3;\
          if (Unsigned__Compare(addr, #code_offset)>=0) return 2;\
          rfalse;\
+         #endif;\
          ]", "", "", "", "", ""
     },
     {   /*  Unsigned__Compare:  returns 1 if x>y, 0 if x=y, -1 if x<y        */

--- header.h~        Wed Apr 14 21:25:58 1999
+++ header.h         Thu Nov 22 22:35:10 2001
@@ -1183,7 +1183,7 @@

 /*  Index numbers into the keyword group "system_constants" (see "lexer.c")  */

-#define NO_SYSTEM_CONSTANTS   58
+#define NO_SYSTEM_CONSTANTS   59

 #define adjectives_table_SC   0
 #define actions_table_SC      1
@@ -1254,6 +1254,8 @@
 #define lowest_object_number_SC       56
 #define highest_object_number_SC      57

+#define oddeven_packing_SC            58
+
 /*  Index numbers into the keyword group "system_functions" (see "lexer.c")  */

 #define CHILD_SYSF       0
@@ -2000,6 +2002,8 @@
     memory_map_switch,      module_switch,        temporary_files_switch,
     define_DEBUG_switch,    define_USE_MODULES_switch, define_INFIX_switch,
     runtime_error_checking_switch;
+
+extern int oddeven_packing_switch;

 extern int error_format,    store_the_text,       asm_trace_setting,
     double_space_setting,   trace_fns_setting,    character_set_setting;


Last updated 17 April 2013. This site is no longer supported; information may be out of date.
Maintained as a historical archive by the Interactive Fiction Technology Foundation. Copyright 1993-2018 IFTF, CC-BY-SA unless otherwise noted.
This page was originally managed by Roger Firth.