Reading/Writing Bytes of Main Memory (Syntax 3)

In PUB and PRI blocks, syntax 3 of BYTE is used to read or write byte-sized values of main memory. This is done by writing expressions that refer to main memory using the form: byte[BaseAddress][Offset]. Here's an example.

PUB MemTest | Temp
  Temp := byte[@MyData][1]       'Read byte value
  byte[@MyStr][0] := "M"         'Write byte value 

DAT
  MyData byte 64, $AA, 55        'Byte-sized/aligned data
  MyStr byte "Hello", 0          'A string of bytes (characters)

In this example, the DAT block (bottom of code) places its data in memory as shown in Main Memory Byte-Sized Data Structure and Addressing figure. The first data element of MyData is placed at memory address $18. The last data element of MyData is placed at memory address $1A, with the first element of MyStr immediately following it at $1B. Note that the starting address ($18) is arbitrary and is likely to change as the code is modified or the object itself is included in another application.

Main Memory Byte-Sized Data Structure and Addressing

Data —

64

$AA

55

"H"

"e"

"l"

"l"

"o"

0

 
Byte Address —$18$19$1A$1B$1C$1D$1E$1F$20
(Byte Offset) —(0)(1)(2)(0)(1)(2)(3)(4)(5)
[Byte Symbol] —[MyData]  [MyStr]     

Near the top of the code, the first executable line of the MemTest method, Temp := byte[@MyData][1], reads a byte-sized value from main memory. It sets local variable Temp to $AA; the value read from main memory address $19. The address $19 was determined by the address of the symbol MyData ($18) plus byte offset 1. The following progressive simplification demonstrates this.

byte[@MyData][1] → byte[$18][1] → byte[$18 + 1] → byte[$19]

The next line, byte[@MyStr][0] := "M", writes a byte-sized value to main memory. It sets the value at main memory address $1B to the character "M." The address $1B was calculated from the address of the symbol MyStr ($1B) plus byte offset 0.

byte[@MyStr][0] → byte[$1B][0] → byte[$1B + 0] → byte[$1B]

Addressing Main Memory

As Main Memory Byte-Sized Data Structure and Addressing figure shows, main memory is really just a set of contiguous bytes and the addresses are calculated in terms of bytes. This concept is a consistent theme for any commands that use addresses.
Main memory is ultimately addressed in terms of bytes regardless of the size of value you are accessing; byte, word, or long. This is advantageous when thinking about how bytes, words, and longs relate to each other, but it may prove problematic when thinking of multiple items of a single size, like words or longs. See the Syntax 3 discussions for WORD and LONG for examples of accessing words and longs.

For more explanation of how data is arranged in memory, see the DAT section's Declaring Data (Syntax 1).

An Alternative Memory Reference

There is yet another way to access the data from the code example above; you could reference the data symbols directly. For example, this statement reads the first byte of the MyData list:

Temp := MyData[0]

And these statements read the second and third bytes of MyData:

Temp := MyData[1]
Temp := MyData[2]

Other Addressing Phenomena

Both the BYTE and direct symbol reference techniques demonstrated above can be used to access any location in main memory, regardless of how it relates to defined data. Here are some examples:

Temp := byte[@MyStr][-1]         'Read last byte of MyData (before MyStr)
Temp := byte[@MyData][3]         'Read first byte of MyStr (after MyData)
Temp := MyStr[-3]                'Read first byte of MyData
Temp := MyData[-2]               'Read byte that is two bytes before MyData

These examples read beyond the logical borders (start point or end point) of the lists of data they reference. This may be a useful trick, but more often it's done by mistake; be careful when addressing memory, especially if you're writing to that memory.

Unless otherwise noted, content on this site is licensed under the
Creative Commons Attribution-ShareAlike 4.0 International License.