From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!feeder.eternal-september.org!news.uzoreto.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Niklas Holsti Newsgroups: comp.lang.ada Subject: Re: Creating several types from a base type and conversion Date: Sat, 18 Jan 2020 19:57:06 +0200 Organization: Tidorum Ltd Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net ITDKqqBHw7mwKUGNxCiZYAScXdSH8FZNmYVhcGkaIGS9XBRQ+U Cancel-Lock: sha1:1/RPBepawaWvJXZgBRzL4NhQFRA= User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Thunderbird/68.3.1 In-Reply-To: Content-Language: en-US Xref: reader01.eternal-september.org comp.lang.ada:57876 Date: 2020-01-18T19:57:06+02:00 List-Id: On 2020-01-18 9:32, Ken Roberts wrote: > New to ada with a question about types. Welcome to the language! What did you program in before? Sometimes it is easier to give advice if one knows the background of the person asking for it. > The theory is creating an old computer emulator. Memory is an array > of BaseWord's (Older computer had 32K of memory, so making an array > on a modern computer is peanuts). Yes, but note that in some Ada compilers, the predefined Integer is only 16 bits, so some memory address computations (offsets) in a 32K range might overflow... better define your own "memory address" type with the computational range you need (which may be more than 32K, or should perhaps use modular arithmetic). > Creating a base type that is stored into the memory array > > > > type BaseWord is array (00 .. 29) of Boolean; > pragma pack (BaseWord); > > Note that such a definition does not ensure that the Boolean with index 0 is the least significant bit, or the most significant bit -- different compilers can use different conventions. And there is no way in current Ada to specify the indexing order. I think the first thing you should consider, and decide, is whether you want your emulator to be fully portable to all standard Ada implementations, or to the commonly available Ada compilers. The main issues are the endianness and the word length of the computer you want to emulate: - Can the computer to be emulated address only full 30-bit words, or can it address also, say, characters (bytes) within a word? - Is the computer you intend to emulate big-endian or little-endian? There are two aspects to this question: first, conventions for numbering bits (is bit 0 most significant or least significant?) and second, addressing sub-word-units like characters (if possible) within a word (does the lowest sub-word address access the most significant end of the addressed word, or the least-significant end?). I'll sketch an approach that applies to the commonly available Ada compilers and makes no a-priori assumptions on the endianness of the computer to be emulated. I recommend starting from the type Interfaces.Unsigned_32. This is a 32-bit, unsigned, modular integer type, and has predefined shift and rotate operations as well as bit-wise Boolean operations. The type is not required to exist in all Ada compilers (for example, the computer you are emulating would probably instead have had a type Interfaces.Unsigned_30) but does exist in GNAT and other Ada compilers for most modern computers which tend to have 32-bit machine integers. The 30-bit unsigned integer type is then subtype Base_Word is Interfaces.Unsigned_32 range 0 .. 2**30 - 1; and the emulated memory is an array of 2**15 Base_Word elements, indexed by the memory-address type. Note that Base_Word does not wrap around at 30 bits (as the type "mod 2**30" would) but at 32 bits. But you can emulate 30-bit wrap-around by clearing the two high bits after every arithmetic operation. I would then define a function to extract any desired bit-field from a Base_Word, for example function Field (Word : Base_Word; Low_Bit, High_Bit : Bit_Number) return Base_Word where Bit_Number is range 0 .. 29. The easiest way to implement such a function is by the left-shift and right-shift operations for Base_Word. In this implementation, you can decide if you want Bit_Number to work in a little-endian or big-endian way. I would also define a procedure Set_Field similarly: procedure Set_Field ( Word : in out Base_Word; Low_Bit, High_Bit : in Bit_Number; New_Value : in Base_Word); Again, this can be done with the shift operations (or rotate operations) and some Boolean operations on Base_Word. If the computer to be emulated can access sub-word data, for example bytes with a byte address, you can now use the above subprograms to implement operations to read or write such sub-word data, and again you can implement either little-endian sub-word order or big-endian sub-word order. These tools should let you decode instructions and their bit-fields and emulate all "logical" (Boolean) instructions and load/store instructions. If you prefer to implement the bit-field lay-outs of instruction words by means of record representation clauses, that is fine too. However, note that the endianness of the bit numbering in such clauses may be different in different Ada compilers, so you should also use the Bit_Order aspect, together with the representation clause, to define the order you want to use (which is probably the same as in the instruction-set manuals for the emulated computer). Also, you then have to use Unchecked_Conversion to convert between Base_Word and the instruction record types, but that is good and safe as long as you have taken care of the bit order. For the arithmetic instructions, you must of course first consider how the emulated computer represents negative numbers: two's complement, one's complement, or sign-magnitude? The answer will tell you how to convert, using ordinary type conversions and ordinary arithmetic (not Unchecked_Conversion) from Base_Word to the corresponding signed type (for use as an operand in the emulation of an arithmetic instruction) and from the signed type (as the result of the arithmetic instruction) back to Base_Type for storing in an emulated register or in the emulated memory. Remember that you may have to use wider types for the results of arithmetic operations so as to handle and detect overflows. Unsigned_32 already gives you two more high-end bits, so it can be used for addition and subtraction, but for multiplication you may want to use a 64-bit type, for example. (I agree with others that there are some errors in the declarations you gave (elided here) which should have made GNAT reject the code.) > For most stuff, memory will be returning either DataWord or > InstructionWord for each memory access, but I'm also looking at an > easier way to manage characters for text display on the emulated > monitors. I would assume that in the original system, the diplay of characters on the monitors was implemented in the SW programs that ran on the emulated processor. Why should the processor emulator do something special for this? Did the monitors display data directly from "display buffers" in the 32K memory, using DMA? -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .