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
- 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)
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
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
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 fi
. @ .