Cocoacrumbs

Cocoacrumbs

All of the buildings, all of those cars
were once just a dream
in somebody's head
Mercy Street - Peter Gabriel

Cocoacrumbs

10 minutes read

Pic 1

Continuing my series about the eZ80, “I don’t like Windows.” and “Why do you want to do/know that?”, I decided to see if I could make sense of the LOD file format produced by the Zilog tools.

Although an Intel HEX file can be produced by the Zilog tools, an Intel HEX file is pure binary and doesn’t contain any debug information. Debug information is present however in Zilog’s LOD file format as a simple HEX dump as in the above picture shows.

Digging inside the Zilog documentation, the LOD file format is actually using the IEEE-695 Object File Format. Unfortunately, this is where the good news stops. The only way to know more about it is buying the document from IEEE ($87.00). which is a bit steep for an obsolete standard that apparently hasn’t been used much and, if I can believe comments I found on the Internet, is a rather vague specification, open for interpretation.

Digging deeper in the obsolete corners of the Internet I found 2 pointers that could help me:

  • binutils-2.25.1. This version of binutils contains some code that can read/write IEEE-695 files for some processors but not the eZ80.
  • i960 Processor Software Utilities User’s Guide. This was my breakthrough. Appendix D HP/MRI IEEE 695 Object File Format is quite extensive and contained enough information to start an attempt in reading Zilog’s LOD file format.

Based on this information, I wrote a simple parser in C, parsing the various records/blocks I encountered on the way as I was progressing through a LOD file. Turns out that Zilog only uses a subset of the IEEE-695 specification but does seem to implement a few extra’s for which I couldn’t find information and is maybe specific for Zilog. When dumping the info, you can see this appearing as “unknown”.

Running the IEEE-695 reader:

Running make first will produce the IEEE_695_Reader executable. The repo contains a simple run.sh script which will run IEEE_695_Reader with a simple example:

  • examples/z20x-HelloWorld.lod : a very simple “Hello World!” program in C.
  • examples/CWS-1-EVE3-GD-Library : a bigger example containing quite a lot of C code.
$ ./run.sh
Read 88617 (0x15A29) bytes

Reached end of the ASW 0 section (offset 0x000000CD). Next record type is 0xF0.
Reached end of the ASW 1 section (offset 0x000000FF). Next record type is 0xF8.
Reached end of the ASW 2 section (offset 0x00014E5B). Next record type is 0xE5.
Reached end of the ASW 3 section (offset 0x00015A28). Next record type is 0xE1.
Reached end of the ASW 4 section (offset 0x0000E336). Next record type is 0xE5.
Reached end of the ASW 5 section (offset 0x00014E33). Next record type is 0xE6.
Reached end of the ASW 6 section.
--- No real ASW 6 section was present at offset 0x00000000
--- (a fake ASG record was created with start address 0x000000).
Reached end of the ASW 7 section (offset 0x00015A29).

#####################################
# Object File Components - IEEE 695 #
#####################################

Parsing the header:

After scanning the LOD file, dumping out the various sections begins. This is the header part:

  Header Part
  ===========
    Module Begin (MB)
    -----------------
    Record Type : 0xE0
    Processor . : "assembler"
    Module Name : "C:\Users\kvnie\Documents\ez80_projects\z20x-HelloWorld\Debug\z20x-HelloWorld.lod"

    Address Descriptor (AD)
    -----------------------
    Record Type ....................... : 0xEC
    Number of bits/minimum address unit : 8
    Number of minimum address units ... : 3

    Assign Value to Variable W0 (ASW0)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 0
    Byte offset in file : 0x00009F (159)

    Assign Value to Variable W1 (ASW1)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 1
    Byte offset in file : 0x0000CD (205)

    Assign Value to Variable W2 (ASW2)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 2
    Byte offset in file : 0x014E33 (85555)

    Assign Value to Variable W3 (ASW3)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 3
    Byte offset in file : 0x014E5B (85595)

    Assign Value to Variable W4 (ASW4)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 4
    Byte offset in file : 0x0000FF (255)

    Assign Value to Variable W5 (ASW5)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 5
    Byte offset in file : 0x00E336 (58166)

    Assign Value to Variable W6 (ASW6)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 6
    Byte offset in file : 0x000000 (0)

    Assign Value to Variable W7 (ASW7)
    ----------------------------------
    Record Type ....... : 0xE2D7
    ASWxRecord ........ : 7
    Byte offset in file : 0x015A28 (88616)
  • Module Begin : provides us the full path to the LOD file that is being parsed.
  • Address Descriptor : tells us that we use units 8 bits and 3 units of 8 bits (the eZ80 uses 24 bits for addressing and registers).
  • This is followed by the 8 ASW (Assign Value to Variable) sections which contains information pointing to the location of other parts within the file.

ASW0 (AD Extension Part)

The AD Extension Part contains information describing how the object module was created. This part is located after the header part and the AD record. It is pointed to by the W0 portion of ASW0. An NN record with a unique index associates ATN records defining the additional information.

  ASW0 (AD Extension Part)
  ========================
    Variable Names (NN) (Id: "ATN_37")
    ----------------------------------
      [DBG] Offset in File .. : 0x9F
      Record Type ........... : 0xF0
      n1 .................... : 0x25 (37)
      Id .................... : "ATN_37"

    Attribute Records (ATN)
    -----------------------
      [DBG] Offset in File .. : 0xA8
      Record Type ........... : 0xF1CE
      n1 .................... : 0x25 (37)
      n2 .................... : 0x0 (0)
      n3 .................... : 0x25 (37)
      version .......... (x1) : 0x1 (1)
      revision ......... (x2) : 0x0 (0)

    ...

Environmental Part (ASW1)

The Environmental Part contains information relating to the host environment where the object module was created.

  ASW1 (Environment Part)
  =======================
    Variable Names (NN) (Id: "ATN_50")
    ----------------------------------
      [DBG] Offset in File .. : 0xCD
      Record Type ........... : 0xF0
      n1 .................... : 0x32 (50)
      Id .................... : "ATN_50"

    Attribute Records (ATN)
    -----------------------
      [DBG] Offset in File .. : 0xD6
      Record Type ........... : 0xF1CE
      n1 .................... : 0x32 (50)
      n2 .................... : 0x0 (0)
      n3 .................... : 0x32 (50)
      year ............. (x1) : 2022
      month ............ (x2) : 11
      day .............. (x3) : 1
      hour ............. (x4) : 15
      minute ........... (x5) : 43
      second ........... (x6) : 52

    ...

ASW2 (Section Definition Part)

The Section part contains information defining the sections of the module. A “section” in this context is a contiguous area of memory. It may be absolute or relocatable, and may or may not have a name. All data minimum address units must be defined in a section.

  ASW2 (Section Definition Part)
  ==============================
    Section Type (ST) (Id: "RAM")
    -----------------------------
      [DBG] Offset in File .. : 0x14E33
      Record Type ........... : 0xE6
      n1 .................... : 0x4 (4)
      l ..................... : 0xC1D3D0
      Id .................... : "RAM"
      n2 .................... : 0x0 (0)
      n3 .................... : 0x0 (0)
      n4 .................... : 0x44 (68)

    Section Base Address (ASL)
    --------------------------
      [DBG] Offset in File .. : 0x14E3F
      Record Type ........... : 0xE2CC
      n1 .................... : 0x4 (4)
      n2 .................... : 0x0 (0)

    ...

ASW3 (External Part)

The External part contains records used to define global symbols. Variable miscellaneous records are also allowed in the External part.

  ASW3 (External Part)
  ====================
    Set Current Section (SB)
    ------------------------
      [DBG] Offset in File .. : 0x14E5B
      Record Type ........... : 0xE5
      n1 .................... : 0x4 (4)

    Public (External) Symbol (NI) (Id: "_reset")
    --------------------------------------------
      [DBG] Offset in File .. : 0x14E5D
      Record Type ........... : 0xE8
      n1 .................... : 0x33 (51)
      Id .................... : "_reset"

    ...

ASW4 (Debug Information Definition Part)

The Debug Information part contains records that define how to determine the symbol related information for a module at execution time. This is required for debuggers that provide high-level debugging capabilities.

  ASW4 (Debug Information Definition Part)
  ========================================
    Assembly Module Block Begin (BB10) (Id: ".\boot\common\vectors16.asm")
    ----------------------------------------------------------------------
      [DBG] Offset in File .. : 0xFF
      Record Type ........... : 0xF8
      Block Type ............ : 0xA (10)
      Block Size (bytes) .... : 0x0 (0)
      Id .................... : ".\boot\common\vectors16.asm"
      Zero Length String .... : ""
      n2 .................... : 0x0 (0)
      Version String ........ : "(null)"
      n3 .................... : 0x0 (0)
      n4 .................... : 0x0 (0)
      n5 .................... : 0x0 (0)
      n6 .................... : 0x0 (0)
      n7 .................... : 0x0 (0)
      n8 .................... : 0x0 (0)

    Assembler Section Block Begin (BB11) (Id: "IVJMPTBL")
    -----------------------------------------------------
      [DBG] Offset in File .. : 0x120
      Record Type ........... : 0xF8
      Block Type ............ : 0xB (11)
      Block Size (bytes) .... : 0x0 (0)
      Zero Length Name ...... : "IVJMPTBL"
      n2 .................... : 0x9 (9)
      n3 .................... : 0x40002D (4194349)
      n4 .................... : 0x44 (68)

      Variable Names (NN) (Id: "__2nd_jump_table")
      --------------------------------------------
        [DBG] Offset in File .. : 0x133
        Record Type ........... : 0xF0
        n1 .................... : 0x66 (102)
        Id .................... : "__2nd_jump_table"

    ...

ASW5 (Data Part)

The data part contains records defining fixed data for the module and is always loaded at the current PC value in the current section. The current section is defined by the SB record and the PC is defined by the ASP record. If no SB record is defined, the current section is specified as 0. If no ASP record is defined, the PC for a section is initially set to the start of the section.

  ASW5 (Data Part)
  ================
    Set Current Section (SB)
    ------------------------
      [DBG] Offset in File .. : 0xE336
      Record Type ........... : 0xE5
      n1 .................... : 0x4 (4)

    Set Current PC (APC)
    --------------------
      [DBG] Offset in File .. : 0xE338
      Record Type ........... : 0xE2D0
      n1 .................... : 0x4 (4)
      n2 .................... : 0x40002D (4194349)

    ...

    Load Constant Bytes (LD)
    ------------------------
      [DBG] Offset in File .. : 0xE34E
      Record Type ........... : 0xED
      n1 .................... : 0x1 (1)
      bytes ................. : 0xF3

    Set Current Section (SB)
    ------------------------
      [DBG] Offset in File .. : 0xE351
      Record Type ........... : 0xE5
      n1 .................... : 0x3 (3)

    Load Constant Bytes (LD)
    ------------------------
      [DBG] Offset in File .. : 0xE353
      Record Type ........... : 0xED
      n1 .................... : 0x2 (2)
      bytes ................. : 0xED 0x7E

    Set Current Section (SB)
    ------------------------
      [DBG] Offset in File .. : 0xE357
      Record Type ........... : 0xE5
      n1 .................... : 0x3 (3)

    Load Constant Bytes (LD)
    ------------------------
      [DBG] Offset in File .. : 0xE359
      Record Type ........... : 0xED
      n1 .................... : 0x5 (5)
      bytes ................. : 0x5B 0xC3 0x8C 0x02 0x00

    ...

ASW6 (Trailer Part)

The ASG record is optional and defines the execution starting address. And indeed it doesn’t seem to be used by Zilog. At least I didn’t find it in my test files. In such a case, I assume the starting address to be 0x000000.

  ASW6 (Trailer Part)
  ===================
    Starting Address (ASG)
    ----------------------
      [DBG] Offset in File .. : 0x0
      Record Type ........... : 0xE2C7
      n1 .................... : 0x0 (0)

ASW7 (End Part)

The ME record defines the end of the module and must be the last record in the module.

  ASW7 (End Part)
  ===============
    Module End (ME)
    ---------------
      [DBG] Offset in File .. : 0x15A28
      Record Type ........... : 0xE1

You can find the complete output of both example LOD files in the examples directory as well.

Extracting the binary data

Maybe it’s good to check if the binary data is present in the LOD file.

The easiest way to do this is looking at the ASW5 (Data Part) section. Take a look at the first 3 Load Constant Bytes (LD) records:

    Load Constant Bytes (LD)
    ------------------------
      [DBG] Offset in File .. : 0xE34E
      Record Type ........... : 0xED
      n1 .................... : 0x1 (1)
      bytes ................. : 0xF3

    Load Constant Bytes (LD)
    ------------------------
      [DBG] Offset in File .. : 0xE353
      Record Type ........... : 0xED
      n1 .................... : 0x2 (2)
      bytes ................. : 0xED 0x7E

    Load Constant Bytes (LD)
    ------------------------
      [DBG] Offset in File .. : 0xE359
      Record Type ........... : 0xED
      n1 .................... : 0x5 (5)
      bytes ................. : 0x5B 0xC3 0x8C 0x02 0x00

Now zoom in on the bytes field only:

      bytes ................. : 0xF3
      bytes ................. : 0xED 0x7E
      bytes ................. : 0x5B 0xC3 0x8C 0x02 0x00

And compare the above bytes with the screenshot below from the simulator which has loaded the same LOD file:

Running the same LOD file in the Zilog Simulator.

It’s not hard to imagine that there is now enough information available [and with a lot of work] to build your own IDE/Debugger/Emulator [for another OS than Windows] and only use the command line Zilog tools in e.g. Wine.

You can find the repo here.

Recent posts

See more

Categories

About

Cocoacrumbs