4. The Instruction Set

JTT has eight instructions, which together makes up JTT?s mnemonic language (see later). Each has its own specific low-level function, and can be used in conjunction with each other. As with a Turing machine, almost any task can be accomplished with the correct sequence, and number, of any of these eight instructions. The word 'almost' is used here because JTT only has a limited amount of memory space. Set to 4,096 at default, this means that JTT can hold a maximum of 4,096 instructions (plus 4,096 data elements) at any one time.

Please Note
The instructions work in conjunction with memory, registers and flags. To learn about these in more detail, see Chapter 5 - Memory, Registers and Flags.
Do not confuse JTT's instruction set with the CLI's commands. The former is the series of eight instructions the emulator understands to perform operations within a JTT program. The latter are the operations of the CLI and GUI that the user can use to do things not related directly to JTT programs, such as quitting and displaying help. The functions of the CLI and GUI are dealt with in Chapter 6 and Chapter 7 respectively.
For a list of common instruction memory address ranges, and their corresponding mnemonic instructions, see Chapter 4.8 (on a separate page).

Each instructions, numbered (decimal) 0 to 7, are explained below, including the machinecode and mnemonic format of each and the limitations of use. The numerical result from all instructions (whether calculating new data or moving existing data) is placed in data memory at the given address.

No. Name Function
0 Load Constant Puts a datum constant directly into data memory
1 BitSelect Selects a given bit of a particular register
2 Add Adds two values together
3 Subtract Subtracts the second value from the first
4 Logical NAND NANDs two values together
5 Rotate Left Shifts the binary value once to the left
6 Fetch from Memory Gets a value from data memory
7 Store to Memory Puts a value into data memory

4.1 Inside JTT

JTT's architecture supports 16-bit Words, and each has its own function. Some work on their own independent of other operations. Others work in groups that change or have different functions depending on the instruction under which they are influenced. They are shown below in the table.

Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Name T I I I C D D D A A A A B B B B

  • The TRAP instruction bit (T, to the very right) allows additional functions to be added to JTT. However, this can largely be ignored for now.
  • The three INSTRUCTION bits (I, to the right of T) hold the unique identifier of the instruction to be carried out. Each of the eight instructions has its own I-bit code: Instruction 0 is $000, up to instruction (decimal) 7, which is $111.
  • The CONDITIONAL bit (C) determines whether the instruction is to be carried out only if the Q(uery) flag is set (yes if set to 1, no if otherwise).
  • The four DEST bits (D, to the right of the C bit) hold the destination where the result of the instruction will be placed. If the last D-bit (bit-11) is set to 0, then the destination is a register. The register number, 0 to (decimal) 7, is held in the leftover three D-bits, as with the three I-bits above.
  • The bits left over, the rightmost eight, are used differently by each instruction. Instruction 0, 'Load Constant', takes A and B as one.
  • Instructions 1 to 7 split these last 8 bits into two groups: A (the source) and B (the destination).
  • Please Note
    The TRAP bit (T) is never set to 1 during the use of one of the standard eight instructions. However, two additional implemented instruction make use of the TRAP expansion facility, HALT, occurs when all 16 bits are set to 1. In other words, the machinecode instruction $1111 1111 1111 1111 is HALT, which stops the program. NULL ($1111 1111 1111 1110) signifies a memory address that has not yet appropriated an instruction. More on these later.

    Each of the bits can be set to 1 (active) or 0 (inactive). Thus, every possible instruction combination can be represented by a code of 16 bits (i.e. a Word). This is directly recognisable by the processor, or in the case of JTT, by the emulator.

    Such a binary code, for these reasons, is called a machinecode language. The representation that is immediately recognisable to humans by its use of English words, is termed mnemonic code. The user can program using either convention. An explanation of each instruction, in both formats, is given in the sections below.

    4.2 Instruction Syntax

    The instructions will be referenced, in this Manual and in JTT itself, using a specific format. The format is simple, and avoids some ambiguities that may crop up. It is useful to learn the syntax before continuing, and the instructions used as examples will be used in Section 4.2.

    1. Necessary parts of an instruction are placed in pointed brackets (< and >). So, for example, the instruction 'r0=0x20' is referenced as <rx>=<value>.
    2. Required variables are denoted as x, y and z, which stand for register numbers or register bit numbers (see above example), or <value> which stands for any value given in decimal, binary or hex format (with appropriate identifier prefix).

    4.3 The Instructions: A Closer Look - Mnemonic Notation

    Please Note
    Some of the instructions below may appear to be unnecessarily restricted in their use. Section 4.4 provides the reasons why. However it may be wise to leave this section until you are experienced with using Mnemonic instructions below first.

    Template: Instruction 0 - Load Constant

       <rx>=<value|ry>;
    There are two uses of Load Constant. The first loads constant value <value> into register <rx>. The second loads the value contained in register <ry> into register <rx>. The constant, <value|ry> may thus be:

  • Any 7-bit value (i.e. decimal 0 to 127, $0 to $111 1111, 0x0 to 0x7f)
  • The contents of a register
  • The reason why only 7-bit constants are accepted is explained in Section 4.4. Only a constant value has this restriction; the contents of a register can be 16 bits wide, as normal. To load constants from and to data memory addresses, use fetch from memory and store to memory respectively. Examples of Load Constant:

  • To load constant value 0xf into r4: r4=0xf;
  • To load value of r6 into r0: r6=r0;
  • Template: Instruction 1 - BitSelect

       <rx>=<ry|value> [<rz|value>];
    With BitSelect, it should be remembered that the square brackets ([ and ]) are typed in as part of the instruction, and do not signify optional instruction arguments.

    This instruction places a given bit of a given value (or value inside a register) and places it in bit 0 (the least significant bit, to the right) of the destination register. Its major purpose is to test the states of the flags in r7. Since bit 0 of r7 is the Query flag, which can directly be influenced by the JTT programmer, the other bits, such as Negative and Zero, can be placed into Query in order to use the Comparison Instruction Extension (see Chapter 5.4).

    It can also allow the programmer to perform tests on the values of registers, by examining the settings of their bits without having to use the flags in r7. This way, you can use memory spaces and registers as your own custom flags amongst others.

    The destination must be a register. This can, and usually does include r7. The next value, <ry|value>, can either be one of the registers from which to take the value to BitSelect, or a constant to BitSelect.

    The last value is placed inside square brackets, and is the one that designates which bit to take out.

    Consequently, it can be a constant between 0 and 15, a register, or one of the flag names. The constant corresponds to bit 0 (the least significant, on the right), bit 15 (the most significant, on the left) or any bit in- between. If a register is given, the four least significant bits are red and the corresponding value is used.

    If any of the eight register names is given, it must be a lower-case, single character from those outlined in Chapter 5.4. Examples of its use follow.

       Example 1: Place the Zero flag into the Query flag for testing.
       Solution:  r7=r7[z];
     
       Example 2: Place bit 4 of r5 into r0.
       Solution:  r0=r5[4];
     
       Example 3: Place the bit of r1, as designated by r2, into r3.
       Solution:  r3=r1[r2];
     
       Example 4: Place the Carry bit into r0.
       Solution:  r0=r0[c];

    Template: Instruction 2 - Add

       <rx>=<value|ry>+<value|rz>;
    This simply adds two values, <value|ry> and <value|rz> together, and places the result into register <rx>. The rules for its use are that each constant, <value|reg>, must be:

  • Any 7-bit value (i.e. decimal 0 to 128, $0 to $0111 1111, 0x0 to 0x7f)
  • The contents of a register (which may, of course, be 16 bits long).
  • Thus, add can be used as Load Constant except that:

  • This is inefficient, since two values are always added together
  • The maximum constant that can be used is 254 (127+127)
  • Memory addresses cannot directly be accessed, so 'Fetch from Memory' and 'Store to Memory' should be utilised.

    If the result is larger than a 16-bit value, as may happen if two registers are added together, it will be truncated to the least significant 16 bits and the carry bit will be shown. It is therefore your job to check for such values (via the carry flag) and deal with them as necessary. This also means that the larger the value, the more information is lost and it becomes less accurate. Two examples are:

  • To add $1001 0111 to the value in r0 into r1: r1=r0+$10010111;
  • To add together r3 and r4 and place the result into r6: r6=r4+r3;
  • To multiply r0 by two and place the result back into r0: r0=r0+r0;
  • Template: Instruction 3 - Subtract

       <rx>=<value|ry>-<value|rz>;
    This simply subtracts the second value (<value|rz>) with from the first (<value|ry>), and places the result into register <rx>. The rules for its use are identical to add (above). The comparative examples to add are:

  • To take $1001 0111 from the value in r0 into r1: r1=r0-$10010111;
  • To add minus r3 from r4 and place the result into r6: r6=r4+r3;
  • To use r0 to get the value zero and place the result back into r0: r0=r0-r0;
  • Please Note
    The contents of the memory address which is the addition of the two given values is loaded. It is not the case that the memory address of the first is added to the constant of the second. For example, in the instruction r0=memory[r5+20] , where r5 contains 1, r0 does not become (the contents of address 1)+20. Instead, it becomes (the contents of memory address 21).

    Template: Instruction 4 - Logical NAND

       <memory[<value|rx>+<value|ry>]>=<value|rz>;
    As defined by De Morgan's Laws, any operation using AND, OR, NOT or XOR can be achieved using the appropriate number and combination of NAND. This stems from electronics in the use of logic gates, and thus may be somewhat a misnomer for some readers. However, the basics are simple, and relate to boolean logic.

    Consider that two values, A and B, can be true (1) or false (0). The result is also either true or false, but it is determined by the state of A and B. AND is used when the result is true only when both A AND B are true. With OR, the result is true if either A OR B are true, or if both are true. NOT causes the result to be true if both A and B are false (NOT true), and is therefore the opposite of AND. XOR, or 'exclusive OR', makes the result true if and only if either A OR B are true (but not both nor neither). The following truth tables show each of the four possibilities and outcomes of each:

    GATE A B RESULT GATE A B RESULT
    AND 0 0 0 OR 0 0 0
    AND 1 0 0 OR 1 0 1
    AND 0 1 0 OR 0 1 1
    AND 1 1 1 OR 1 1 1
    NOT 0 0 1 XOR 0 0 0
    NOT 1 0 0 XOR 1 0 1
    NOT 0 1 0 XOR 0 1 1
    NOT 1 1 0 XOR 1 1 0

    Consequently, NAND, or 'not AND', is true when either A or B are true, or if neither are true (but not both). NAND is therefore the opposite of AND. This means that if A and B are NANDed (to make A NAND B), the result is thus with each combination:

    0 NAND 0 = 1
    0 NAND 1 = 1
    1 NAND 0 = 1
    1 NAND 1 = 0

    When a result is NANDed by itself, as you can see in the table above, true becomes false and false becomes true. Therefore, if 'A NAND B = C', 'C NAND C' produces the same result as 'C NOT C'. Therefore, 'NAND (A NAND B)' = 'NOT (A AND B'). You will have to work out the repetition and order required to make NAND work for the other logic gates, but after NOT, more and more NAND gates will be required.

    Template: Instruction 5 - Rotate Left (rol)

       <rx>=<ry|value>rol<rz|value>;
    This instruction takes a value (as a constant or the value of a register) and converts it into binary notation. Then, each of the bits are moved ('rotated') to the left and the previous most significant bit (bit 15) is placed into the now vacant least significant bit (bit 0) on the right.

    Each time the bits are shifted one place, the result is effectively multiplied by 2, and the number of shifts to carry out is defined in the value (or register value) after the rol instruction.

    This provides a computationally uncostly method of squaring values and providing a 'multiply by two to the power of' function. The command can also be used (with the appropriate number of Rotate Left instructions) to the effect of 'rotating' the value right (and thereby square-rooting the result).

    As with the add instruction, although the destination has to be a register, the two values to use in the operation (i.e. the value and the number of times to rotate left) can be expressed either as a 7-bit constant or as a register.

    If the value becomes too large (i.e. more than 16 bits can hold, which is decimal 65,536 or $1111 1111 1111 1111 or 0xffff), the most significant figure (the leftmost bit) is rotated over to become the least significant figure instead of the 0, and the carry flag is set.

    Some examples of its use follow. The first is a straightforward multiplication of a given constant. The second increases a value by a larger power. The third shows what happens when the register runs out of space. The forth increases the value in a register by the power given in another register, and shows that, if the programmer is not careful (see Note for this instruction, below), the actual result may not bear any resemblance to the expected (or required) result.

       Example 1:  Double the number (decimal) 27.
       Manual Working:
       1. Decimal 27 in binary notation:          $0000 0000 0001 1011
       2. rotate Left once (27 rol 1):            $0000 0000 0011 0110
       3. The result is the following in decimal: 54
     
       Example 2:  Calculate 0xfff multiplied by two to the power of 4.
       Manual Working:
       1. Hex 0xfff in binary notation:           $0000 1111 1111 1111
       2. rol four times (0xfff rol 4):           $1111 1111 1111 0000
       3. The result is the following in hex:     0xfff0 (decimal 65521)
    
       Example 3:  Double the result calculated in Example 2.
       Manual Working:
       1. Decimal 65521 shown in binary:          $1111 1111 1111 0000
       2. Rotate left once:                       $1111 1111 1110 0000
       3. Place the prev. rightmost bit on left:  $1111 1111 1110 0001
       4. The result is the following in hex:     0xffe1 (decimal 65506)
    
       Example 4:  Multiple the value in r0 by the value in r1.
       Solution:   r0=r0 rol r1;
    Please Note
    To avoid garbled results from too many rotations, create a loop that tests the carry flag on each rotation. If the carry flag is set, you may either use it as a 17th bit or exit the loop. In either of these cases, if you just want it to left-shift, to double the result, use BitSelect (below) to clear the least significant bit each time.
    This command is not fussed whether or not you put spaces between the rol keyword and the two values to the right of the equals symbol. This goes with nand also.
    With a loop and a bit of brainpower, this instruction can also be used to imitate a 'rotate right' (ror) instruction. Rotate right is also common in some assembly programming languages.

    Template: Instruction 6 - Fetch from Memory

       <rx>=<memory[<value|ry>+<value|rz>]>;
    Fetch from Memory stores the contents of a data memory address into register rx. Data memory addresses must always be given as two values to add together, and each value must either be a 7-bit number or 16-bit register, as with the add instruction.

    Also as with add, the maximum memory address that can be implied as a constant is 254. However, memory addresses are temporarily stored as 32-bit numbers and are not truncated, allowing JTT to use a maximum of 4,294,967,295 (just over four billion) data and instruction memory a addresses. Some examples follow (next page).

  • To load memory address (decimal) 10 into r6: r6=memory[10+0];
  • To load memory address (r5+24) into r4: r4=memory[r5+24];
  • Template: Instruction 7 - Store to Memory

       <memory[<value|rx>+<value|ry>]>=<rz>;
    Store to Memory stores the contents of a register, or a constant value, into the given memory address. See Fetch from Memory for usage guide.

  • To load r6 into memory address (decimal) 10: memory[10+0]=r6;
  • To load constant 7 memory address (r5+24): memory[r5+24]=7;
  • Please Note
    This instruction can only store the contents of a register (i.e. not a constant value), due to how the machinecode is stored. See Section 4.4 for an explanation why.

    4.4 The Instructions: A Closer Look - Machinecode Notation

    Please Note
    Remember, unlike decimal, binary (and hex) numbers have their most significant figures to the left. As a result, binary numbers appear 'backwards' - that is, the higher bits are given on the left, and bit 0 on the extreme right. Don?t forget to adjust accordingly when dealing with binary values and using the following binary tables.

    Only more advanced users of JTT should attempt to insert instructions directly in machinecode notation. Other users should first study and use the mnemonic form of Section 4.1, then move onto this section. It is, however, extremely important to get around to machinecode eventually, since this it is the main goal of JTT to teach users the fundamentals of simple processor operations, and machinecode is at its heart. It is good practice, for learning computer fundamentals and for keeping the brain active.

    Instruction 0: Load Constant

    'Load Constant' loads a constant value, or the contents of a register, into a register. Due to "hardware" restrictions, this value cannot be smaller than 0 or larger than 2^7, or decimal 127, binary $111 1111 or hex 0x7f. It is evident why if we look at the table below that shows the machinecode representation of this instruction:

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 0 0 0 C D D D R K K K K K K K

    The trap bit and instruction bits are all set to 0, and bits (decimal) 0 to 7 (R and K) are treated as one group. Bit 7 denotes whether bits 4 to 6 are registers (if set to 0) or whether bits 0 to 6 should be treated as a direct constant value (if set to 1). Thus, the maximum literal value can be 7 bits wide (2^7, with a range of 0:127/$111 1111/0x7F), or 16 bits wide (by throwing into the destination the contents of another register) if a register is given.

    To use this instruction in machinecode is easy. Whilst the value or register to use as the constant is given in bits 0 to 7, are above, bits 8 to 10 contain the three bits designating the destination (D) register number ($000 to $111). Bit 11 is the conditional (C) bit. If the Comparison Instruction Extension (see Chapter 5.4) is used to denote a conditional execution of this instruction, bit 11 is set to 1.

    Examples follow.

       Example 1:  Load constant (decimal) 44 into register 4 (r4).
       Solution:
       1. The Trap bit and Instruction bits (i.e. bits 12 to 15) are set to 0.
       2. The instruction is not conditional, so bit 11 is set to 0.
       3. The destination register is r4, so the D bits become $100.
       4. The source is not a register, so bit 7 is set to 1.
       5. Bits 0 to 6 therefore contain the number (decimal) 44, or $010 1100.
       6. The machinecode instruction is thus: $0000 0100 1010 1100, or 
          decimal 1,196 or 0x04ac.
     
       Example 2: Load r1 into r0, but only if the query flag is set.
       Solution:
       1. The trap bit and instruction bits are set to 0.
       2. The instruction is conditional, so bit 11 is set to 1.
       3. The destination register is r0, so the D bits become $000.
       4. The source is a register, so bit 7 is set to 0.
       5. Bits 4 to 6 are $001 (r1), and bits 0 to 3 are set to 0.
       6. The machinecode instruction is thus: $0000 1000 0001 0000, or 
       7. decimal 2,064 or 0x0810.

    Instruction 1: BitSelect

    Here, the first value (RAAA) is the value from which to select a bit and the second (RBBB) contains the bit to select. If RBBB is a constant, it can access the least significant half. It a register, the four least significant bits are used to determine which bit to select, from 0 to 15.

    Please Note
    The bit is put into the least significant bit (bit 0, to the right) of the destination register. The other bits of the destination register remain as they were before the operation.

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 0 0 1 C D D D R A A A R B B B

       Example 1: Place bit (decimal) 6 of r2 into bit 0 of r2.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $001.
       2. The instruction is not conditional, so carry is set to 0.
       3. The destination is r2, so DDD becomes $010.
       4. The source value is in r2, so bit 7 is set to 0 and AAA become $010.
       5. The bit to select is (decimal) 6, so bit 7 is 1 and BBB become $110.
       6. The machinecode instruction is thus: $0001 0010 0010 1110, or 
          decimal 4,654 or 0x122e.
    
       Example 2:  Place the Zero flag into the Query flag, if Query is true.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $001.
       2. The instruction is conditional, so carry is set to 1.
       3. The destination is r7, so DDD becomes $111.
       4. The source value is in r7, so bit 7 is set to 0 and AAA become $111.
       5. The bit to select is (decimal) 1, so bit 7 is 1 and BBB become $001.
       6. The machinecode instruction is thus: $0001 1111 0111 1001, or 
          decimal 8,057 or 0x1f79.

    Instruction 2: Add

    'Add' places the addition of two values into a given register.

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 0 1 0 C D D D R A A A R B B B

    The instruction adds a value or register value to another value or register value, and places the result into the register given in the three DDD bits. If bit 11 is set to 1, the instruction is conditional. If bit 7 is set to 0, then AAA becomes the register from which to take the value. If set to 1, then AAA becomes a constant, from 0 to (decimal) 7. The same can be said for bit three and its relation to BBB.

    If the result of the addition of the two values is larger than a 16-bit number, the carry flag is set (thereby providing a temporary 17th bit) and the remaining 16 bits hold the 16 least significant bits of the result.

       Example 1:  Add one to the contents of r1 and place the result into r3.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $010.
       2. The instruction is not conditional, so carry is set to 0.
       3. The destination is r3, so DDD becomes $011.
       4. The first constant is r1, so bit 7 is set to 0 and AAA become $001.
       5. The second constant is 1, so bit 7 is set to 1 and BBB become $001.
       6. The machinecode instruction is thus: $0010 0011 0001 1001, or 
          decimal 8,985 or 0x2319.
    
       Example 2:  Multiply r5 by 2 and place the result into r0, only if the Query 
                   flag is 1.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $010.
       2. The instruction is conditional, so carry is set to 1.
       3. The destination is r0, so DDD becomes $000.
       4. The first constant is r5, so bit 7 is set to 0 and AAA become $101.
       5. The second constant is also r5, so bit 7 is set to 0 & BBB become $101.
       6. The machinecode instruction is thus: $0010 1000 0101 0101, or 
          decimal 10,325 or 0x2855.

    Instruction 3: Subtract

    'Subtract' places the result of the second value minus the first into a given register. The rules are as with Add. If the result of the subtraction is zero or less, the Zero or Negative flag are set to 1 accordingly, and the value 'wraps around' as in 2s-comp (See Chapter 3.7).

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 0 1 1 C D D D R A A A R B B B

       Example:  Minus two from one and place the result into r4.
       Solution: (NB. the result will be decimal 65535 and carry will be set.)
       1. The trap bit is set to 0. The instruction bits are set to $011.
       2. The instruction is not conditional, so carry is set to 0.
       3. The destination is r4, so DDD becomes $100.
       4. The first constant is (decimal) 2, so bit 7 is 1 and AAA become $010.
       5. The second constant is 1, so bit 7 is set to 1 and BBB become $001.
       6. The machinecode instruction is thus: $0011 0100 1010 1001, or 
          decimal 13,481 or 0x34a9.

    Instruction 4: Logical NAND

    'NAND' works similarly to Add and Subtract in terms of its syntax:

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 1 0 0 C D D D R A A A R B B B

    AAA and BBB can, once more, be registers or constants, the limits of the latter being similar to the other instructions as 7-bit values.

       Example 1:  NAND r1 and r2 and place the result into r3.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $100.
       2. The instruction is not conditional, so carry is set to 0.
       3. The destination is r3, so DDD becomes $011.
       4. The first constant is in r1, so bit 7 is set to 0 and AAA become $001.
       5. The second constant is r2, so bit 7 is 0 and BBB become $010.
       6. The machinecode instruction is thus: $0100 0011 0001 0010, or 
          decimal 17,170 or 0x4312.
    
       Example 2:  NAND the value (decimal) 5 by itself and place the result 
                   into r0, only if query is set.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $100.
       2. The instruction is conditional, so carry is set to 1.
       3. The destination is r0, so DDD becomes $000.
       4. The first constant is (decimal) 5, so bit 7 is set to 1 and AAA = $101.
       5. The second constant is the same, so bit 7 is 1 and BBB become $101.
       6. The machinecode instruction is thus: $0100 1000 0101 0101, or 
          decimal 18,517 or 0x4855.

    Instruction 5: Rotate Left (ROL)

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 1 0 1 C D D D R A A A R B B B

       Example 1:  Rotate r5 by 1 and place the result back into r5.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $101.
       2. The instruction is not conditional, so carry is set to 0.
       3. The destination is r5, so DDD becomes $101.
       4. The first constant is in r5, so bit 7 is set to 0 and AAA become $101.
       5. The second constant is 1, so bit 7 is 1 and BBB become $001.
       6. The machinecode instruction is thus: $0101 0101 0101 1001, or 
          decimal 21,849 or 0x5559.
     
       Example 2:  Rotate r1 by the value in r2 and place the result into r3,
                   only if the query flag is set.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $101.
       2. The instruction is conditional, so carry is set to 1.
       3. The destination is r3, so DDD becomes $011.
       4. The first constant is in r1, so bit 7 is set to 0 and AAA become $001.
       5. The second constant is in r2, so bit 7 is also 0 and BBB become $010.
       6. The machinecode instruction is thus: $0101 1011 0001 0010, or 
          decimal 23,314 or 0x5b12.

    Instruction 6: Fetch from Memory

    Our first memory instruction places the contents of a given data memory address into a given register.

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 1 1 0 C D D D R A A A R B B B

    The setup is identical to add and subtract. The destination must be one of the registers, and the address must be given as two values, which are added to find the appropriate data memory address from which to get the value. Either AAA or BBB can be either a register or value, but the latter can only be 3 bits long. Therefore, using only constants, addresses 0 to (decimal) 14 can be accessed.

    To get at higher addresses, you must go through registers. To access a 16- bit address (i.e. up to (decimal) 65,535), use a register and a value (such as r0+0, or 0+r4). If two registers are used together, their 32-bit value (rAAA+rBBB) is used. This is useful for JTT memory sizes larger than 16 bits (see MemSize, Chapter 6.2).

       Example 1:  Place contents of memory address (decimal) 13 into r0.
       Solution:   (N.B. There is more than one combination of constants to use.)
       1. The trap bit is set to 0. The instruction bits are set to $110.
       2. The instruction is not conditional, so carry is set to 0.
       3. The destination is r0, so DDD becomes $000.
       4. The first constant is (decimal) 7, so bit 7 is set to 1 and AAA = $111.
       5. The second constant is (decimal) 6, so bit 7 is 1 and BBB = $110.
       6. The machinecode instruction is thus: $0110 0000 1111 1110, or 
          decimal 24,830 or 0x60fe.
    
       Example 2:  Place contents of the memory address designated by the 
                   32-bit value r0+r1, placing result in r2, only if query is set.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $110.
       2. The instruction is conditional, so carry is set to 1.
       3. The destination is r2, so DDD becomes $010.
       4. The first constant is in r0, so bit 7 is set to 0 and AAA become $000.
       5. The second constant is r1, so bit 7 is 0 and BBB become $001.
       6. The machinecode instruction is thus: $0110 1010 0000 0001, or 
          decimal 27,137 or 0x6a01.

    Instruction 7: Store to Memory

    The second memory instruction places the contents of a given register into the given data memory address. It is slightly different to the rest. Whilst the other instructions hold (in machinecode binary, from right to left) the source and then the destination, Store to Memory holds the destination memory address followed by the source register or value. Thus, in the table below, S denotes the source constant or register.

    Bit No. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
    Name 0 1 1 1 C S S S R A A A R B B B

    One other thing to note is that the source (bits 8-10) can only refer to a register, since there is not enough room for the extra bit needed to store whether the source is a register or constant value. The instruction otherwise works as the reverse of Instruction 6. To illustrate, the two examples below are similarly contrary to those of 'Fetch from Memory'.

       Example 1:  Place contents of r0 into memory address (decimal) 13.
       Solution:   (N.B. There is more than one combination of constants to use.)
       1. The trap bit is set to 0. The instruction bits are set to $111.
       2. The instruction is not conditional, so carry is set to 0.
       3. The source is r0, so SSS becomes $000.
       4. The first constant is (decimal) 7, so bit 7 is set to 1 and AAA = $111.
       5. The second constant is (decimal) 6, so bit 7 is 1 and BBB = $110.
       6. The machinecode instruction is thus: $0111 0000 1111 1110, or 
          decimal 28,926 or 0x70fe.
    
       Example 2:  Place the contents of r2 into the memory address designated by 
                   the 32-bit value r0+r1, only query is set.
       Solution:
       1. The trap bit is set to 0. The instruction bits are set to $111.
       2. The instruction is conditional, so carry is set to 1.
       3. The source is r2, so SSS becomes $010.
       4. The first constant is in r0, so bit 7 is set to 0 and AAA become $000.
       5. The second constant is r1, so bit 7 is 0 and BBB become $001.
       6. The machinecode instruction is thus: $0111 1010 0000 0001, or 
          decimal 31,233 or 0x7a01.

    4.5 Mnemonic Exceptions and Keywords

    There are a few exceptions and additions to the mnemonic syntax that do not appear in JTT's machinecode language. There are still strictly only eight JTT machinecode instructions, and there can only therefore be eight mnemonic instructions. Those below, however are neither instructions nor CLI or GUI commands.

    The MaxMem Constant

    The MaxMem keyword can be used in the place of the largest available memory address. Whilst JTT's actual memory size is set at default to 4,096, this value can be altered by the user via the MemSize command (see Chapter 6.2).

    As a result, whenever the memory size is changed, a program, which addresses, uses or exceeds a high memory address may have to be altered when JTT's memory capacity is reduced.

    In mnemonic commands, this can be taken into account by using the MaxMem mnemonic in any operations regarding the largest memory address. Then, when the program is executed, its behaviour will alter depending upon the size of JTT's "physical" memory. You can also make provisions for lower memory states by comparing its value and "cutting out" sections of a program that require more instruction memory addresses than are available. This might work by manipulating the IP to skip sections of your code.

    As it takes the form of a Trap instruction, MaxMem can also be applied to machinecode (see later). Its primary (and only recommended) use is as a shortcut to changing mnemonic source code to accommodate different JTT versions. Its use must still be treated with the utmost care and skill to avoid overflow errors, memory use conflicts etc., though (see later for an example scenario).

    There are 8 possible uses of MaxMem (and thus 8 corresponding Trap instruction allocations):

       Mnemonic     Machinecode
       =========    =================================
       r0=maxmem    65520/$1111 1111 1111 0000/0xFFF0
       r1=maxmem    65521/$1111 1111 1111 0001/0xFFF1
       r2=maxmem    65522/$1111 1111 1111 0010/0xFFF2
       r3=maxmem    65523/$1111 1111 1111 0011/0xFFF3
       r4=maxmem    65524/$1111 1111 1111 0100/0xFFF4
       r5=maxmem    65525/$1111 1111 1111 0101/0xFFF5
       r6=maxmem    65526/$1111 1111 1111 0110/0xFFF6
       r7=maxmem    65527/$1111 1111 1111 0111/0xFFF7
       

    In other words, in binary representation, there are 12 ones, a zero and then the three bits corresponding to the octal value of the register to store to. Note also that code such as r0=maxmem+1 and r5=IP nand maxmem are not possible. A usage example follows.

       Example:  Say a program needs to put the value decimal 255 or 
                 $1111 1111 or 0xff into the last, and the second-to-last, 
                 data memory addresses. The code would look something 
                 like this:
    
                 r0=MaxMem;
                 memory[r0+0]=$11111111;
                 memory[r0-1]=$11111111;

    MaxMem may only be used in the form of a Load Constant instruction, and not in any form or as "pure" Load Constant, for architectural reasons. Load Constant only accepts 7-bit literal values and the memory size can be anything up to 16 bits! Therefore, trap instruction spaces are utilised. Moreover, to expand MaxMem to emulate the other instructions is wasteful and would take up considerable "trap space".

    Make sure that declarations to literal addresses are not going to conflict with the use of MaxMem. For example, the following program stores two literal values into memory at the same time:

       r0=127;
       memory[r0+0]=5;
       r1=MaxMem;
       memory[r1+0]=7;
       

    It would work fine with JTT memory sizes of (dec) 256 and greater, but would conflict by overwriting the same memory address and utilising it for two purposes with a memory size of (dec) 128. Possible work-arounds:
  • The first line could utilise "MaxMem-1", by expanding it in the following manner:
    r0=maxmem;
    r0=r0-1;
    ...
  • The first line could use memory address 62 or lower. The lowest JTT memory size possible is 63, and r1=MaxMem would use address space 63, so anything lower than this is (at least in our example) acceptable.
  • Please Note
    Be careful how MaxMem is used. Using r0=maxmem and then attempting a r0=r0+1 will result in a runtime error, and will by definition always be outside the legal memory range.
    The MaxMem constant is not case sensitive.
    See also the comparison instruction extension ( Chapter 5.4), which is also a mnemonic command extension.
    The comparison instruction extension cannot be used directly in your use of MaxMem; only the 8 representations given (see above) can be used.

    Comments

    A comment is a string, found in mnemonic instruction listings, which is intended to be read by a programmer but not to be executed as an instruction. Such devices allow the programmer to place notes or reminders inside a program at particular places. There are two comment keywords, both taken from other programming languages. These are the ?;? (semicolon) character and the '#' (hash) character. They can be used at any place on a line, and the number of spaces preceding it (whether after an instruction or on a new line) does not technically matter.

    During compilation of a mnemonic program into machinecode, these symbols and the rest of the line after them are ignored. Therefore, they may be used at the start of a new line, or after an instruction at the end of an old one. It is conventional to use the hash character to dedicate an entire line to a comment, and the semicolon to add a comment after an instruction. An entire mnemonic instruction line dedicated to a comment is treated as a non- instruction (a null instruction - see below).

    When such comments are entered, they are stripped away from the instruction and will not appear with the program listings. However, the comments will be stored in a special database of the CLI consisting of as many entries as there are memory addresses. Whenever you are about to overwrite an instruction memory address that you have marked with a comment, you will be informed of the comment and asked to confirm the overwrite of the address.

    Alternatively, you can view any or all comments using the comment command (see Chapter 6.2).

       Example:  The first of the following example lines of code adds a 
                 comment after the given instruction. The second 
                 dedicates an entire in line to a comment.
    
                 r6=MaxMem;      Places largest mem address into r6
                 r0=r1+r2;
                 # The preceding line adds r1 and r2 --> r0

    Null Instructions

    When JTT is first loaded, there are no instructions in instruction memory and data memory is filled with a series of 0s. This also occurs when the programmer uses the command in the CLI (see the Data command, Chapter 6.2). This way, when a programmer fills memory with instructions but leaves gaps between code, unwanted instructions the programmer did not ask for are not carried out. Such a marker in instruction memory, which tells JTT to carry out no action is called a non-instruction, or null instruction.

    The JTT machinecode for a null instruction is 65534, or $1111 1111 1111 1110, or 0xfffe, and is therefore a trap instruction (see Section 4.4). However, in both mnemonic and machinecode listings, it is shown simply as the word null.

    You can insert null instructions of your own by typing it as a mnemonic command, or using the above machinecode conversion.

    Please Note
    null is unique to this usage within JTT, and cannot be used as (and indeed is not) a value in itself.
    Originally, null was synonimous with the instruction r0=r0 (machinecode 0). However, it is now its own instruction. There are two reasons for this. Firstly, the specialised trap instruction does one operation (IE read the instruction) whilst r0=r0 does three (reads r0; stores r0; puts back into r0) which is clearly much less efficient and more wasteful. Secondly, it is easier for you to see whether an instruction in your mnemonic code is intended as an unfilled space, which is more difficult at a glance to see if r0=r0 (for example) is used.

    HALT Instructions

    HALT is the only other instruction that makes use of the TRAP extension. Its machinecode form is 65535, or $1111 1111 1111 1111, or 0xffff. It causes the program to stop running permanently, and you will be returned to the CLI/GUI window from which you ran it in the first place.

    Please Note
    Because it uses all 16 bits, there is no physical room to store whether the HALT instruction is conditional, and so can only make use of the Query flag indirectly. To do this, you should use a conditional statement that points r6 to a HALT command elsewhere. HALT itself should be placed with care.

    4.6 Helpful Tips: Basic

  • Some instructions cannot be applied to some contexts. For example, Load Constant cannot load a value directly into a data memory address. To get around this, use the instruction on a register, then store the contents of the register in a memory address using the Store to Memory instruction.
  • Place a semicolon after every instruction entered. This is good practice for programming languages like C and Java, which utilise the same convention.
  • If you do not currently wish to use a particular instruction or group of instructions, but may do in the future, 'comment out' the offending lines by prefixing them with the hash character (see Section 4.4).
  • 4.7 Helpful Tips: More Advanced

  • Jump to other places in instruction memory by assigning new values to the Instruction Pointer (Register 6) via Load Constant. For example, to move to instruction memory address (decimal) 20, use something like r6=0xf4. The registers are covered in more detail in Chapter 5.2.
  • It might pay to 'modularise' large programs - i.e. split them throughout instruction memory into separate functions, or modules, and work on each separately. Leave large gaps between memory addresses, depending on the size of the overall program and the amount of work/expansion to be done to each, between each. When one module ends, 'jump' (see above bullet-point) to the next.
  • To create loops (where the same sequence of instructions is repeated over until a particular condition is satisfied), use 'jump' at the end of the sequence twice - one to repeat if not satisfied and one to break the loop if otherwise. The 'q' (query) flag can be used here in conjunction with the '?' extension (see Chapter 5.4).
  • Go to next chapter Go to top of page Go to Contents Page Go to HomePage E-mail the author
    Hosted by www.Geocities.ws

    1