diff --git a/specification/aie2ps/isa-spec.html b/specification/aie2ps/isa-spec.html
index 2be12c994..33a01ae13 100644
--- a/specification/aie2ps/isa-spec.html
+++ b/specification/aie2ps/isa-spec.html
@@ -135,6 +135,8 @@
Directives
@@ -1647,6 +1649,95 @@ REL_ACQ_SYNC (0x21)
REL_ACQ_SYNC 0x0205720c, 0x02057004 ; barrierId: 0, lockId: 28, release_aquire relVal: 1 acqVal: 3
+
+UC_DMA_MASK_POLL_EXT (0x22)
+Polls an external (NoC-mapped) register until (read & mask) == value.
+
+
+
+| 0x22 |
+- |
+- |
+addr_hi |
+addr_lo |
+mask |
+value |
+instruction size |
+
+
+
+
+| opcode (8b) |
+pad (8b) |
+pad (16b) |
+const (32b) |
+const (32b) |
+const (32b) |
+const (32b) |
+20B |
+
+
+
+Reads a 32-bit value from the external address formed by (addr_hi << 32 | addr_lo) via
+a uC-DMA MM2DM transfer and busy-waits until (read_value & mask) == value.
+Analogous to MASK_POLL_32 but for addresses outside the AIE array register space,
+reachable via NMU -> NoC (e.g. PL IP AXI-Lite registers).
+Used to poll ap_done (bit[1]) of a wts_pl_ctrl AP_CTRL register after triggering ap_start.
+Example:
+
; Poll ap_done (bit[1]) on wts_pl_ctrl instance 0 (base 0x80000030000):
+UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+
+APPLY_OFFSET_PL (0x23)
+Patches the physical DDR address (words 8+9) of one or more wts_params blocks for PL IP start_address.
+
+
+
+| 0x23 |
+- |
+table_ptr |
+buffer_id |
+- |
+instruction size |
+
+
+
+
+| opcode (8b) |
+pad (8b) |
+const (16b) |
+const (16b) |
+pad (16b) |
+8B |
+
+
+
+Patches wts_params blocks (each 10 words / 40 bytes) starting at table_ptr.
+XRT resolves buffer_id to a 64-bit physical address at BO bind time and
+writes word[8] <- phys_addr[31:0] and word[9] <- phys_addr[63:32] in each block.
+Example:
+START_JOB 1
+ APPLY_OFFSET_PL @wts_params, WTS_BUFFER_ID
+ UC_DMA_WRITE_DES_SYNC @wts_pl_bd_chain
+ UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+END_JOB
+.align 16
+wts_pl_bd_chain:
+ UC_DMA_BD 0x800, 0x00030010, @wts_params, 10, 1, 1
+ UC_DMA_BD 0x800, 0x00030000, @val_ap_start, 1, 1, 0
+.align 4
+wts_params:
+ .long 0x00000000 ; word 0 offset
+ .long 0x00000000 ; word 1 (reserved)
+ .long 0x00000004 ; word 2 length
+ .long 0x00000000 ; word 3 (reserved)
+ .long 0x00000000 ; word 4 stride
+ .long 0x00000000 ; word 5 (reserved)
+ .long 0x00000001 ; word 6 iterations
+ .long 0x00000000 ; word 7 (reserved)
+ .long 0x00000000 ; word 8 start_addr[31:0] <- APPLY_OFFSET_PL
+ .long 0x00000000 ; word 9 start_addr[63:32] <- APPLY_OFFSET_PL
+val_ap_start:
+ .long 0x00000001
Directives
The directive syntax is same as that used by GNU assembler https://sourceware.org/binutils/docs/as/Pseudo-Ops.html,
diff --git a/specification/aie2ps/isa-spec.md b/specification/aie2ps/isa-spec.md
index 0f21e2d0b..8248aeaf3 100644
--- a/specification/aie2ps/isa-spec.md
+++ b/specification/aie2ps/isa-spec.md
@@ -862,6 +862,65 @@ REL_ACQ_SYNC 0x0205720c, 0x02057004 ; barrierId: 0, lockId: 28, release_aquire r
```
+## UC_DMA_MASK_POLL_EXT (0x22)
+
+Polls an external (NoC-mapped) register until (read & mask) == value.
+
+| 0x22 | - | - | addr_hi | addr_lo | mask | value | instruction size |
+| :-: | - | - | - | - | - | - | -: |
+| opcode (8b) | pad (8b) | pad (16b) | const (32b) | const (32b) | const (32b) | const (32b) | 20B |
+
+Reads a 32-bit value from the external address formed by (addr_hi << 32 | addr_lo) via
+a uC-DMA MM2DM transfer and busy-waits until (read_value & mask) == value.
+Analogous to MASK_POLL_32 but for addresses outside the AIE array register space,
+reachable via NMU -> NoC (e.g. PL IP AXI-Lite registers).
+Used to poll ap_done (bit[1]) of a wts_pl_ctrl AP_CTRL register after triggering ap_start.
+Example:
+```
+; Poll ap_done (bit[1]) on wts_pl_ctrl instance 0 (base 0x80000030000):
+UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+```
+
+
+## APPLY_OFFSET_PL (0x23)
+
+Patches the physical DDR address (words 8+9) of one or more wts_params blocks for PL IP start_address.
+
+| 0x23 | - | table_ptr | buffer_id | - | instruction size |
+| :-: | - | - | - | - | -: |
+| opcode (8b) | pad (8b) | const (16b) | const (16b) | pad (16b) | 8B |
+
+Patches wts_params blocks (each 10 words / 40 bytes) starting at `table_ptr`.
+XRT resolves `buffer_id` to a 64-bit physical address at BO bind time and
+writes word[8] <- phys_addr[31:0] and word[9] <- phys_addr[63:32] in each block.
+Example:
+```
+START_JOB 1
+ APPLY_OFFSET_PL @wts_params, WTS_BUFFER_ID
+ UC_DMA_WRITE_DES_SYNC @wts_pl_bd_chain
+ UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+END_JOB
+.align 16
+wts_pl_bd_chain:
+ UC_DMA_BD 0x800, 0x00030010, @wts_params, 10, 1, 1
+ UC_DMA_BD 0x800, 0x00030000, @val_ap_start, 1, 1, 0
+.align 4
+wts_params:
+ .long 0x00000000 ; word 0 offset
+ .long 0x00000000 ; word 1 (reserved)
+ .long 0x00000004 ; word 2 length
+ .long 0x00000000 ; word 3 (reserved)
+ .long 0x00000000 ; word 4 stride
+ .long 0x00000000 ; word 5 (reserved)
+ .long 0x00000001 ; word 6 iterations
+ .long 0x00000000 ; word 7 (reserved)
+ .long 0x00000000 ; word 8 start_addr[31:0] <- APPLY_OFFSET_PL
+ .long 0x00000000 ; word 9 start_addr[63:32] <- APPLY_OFFSET_PL
+val_ap_start:
+ .long 0x00000001
+```
+
+
# Directives
The directive syntax is same as that used by GNU assembler ,
diff --git a/specification/aie2ps/isa-spec.yaml b/specification/aie2ps/isa-spec.yaml
index 4b1c5a063..b16a6a0b7 100644
--- a/specification/aie2ps/isa-spec.yaml
+++ b/specification/aie2ps/isa-spec.yaml
@@ -815,6 +815,81 @@ operations:
```
+ - mnemonic: UC_DMA_MASK_POLL_EXT
+ opcode: 0x22
+ regular: True
+ arguments:
+ - type: pad
+ width: 16
+ - name: addr_hi
+ type: const
+ width: 32
+ - name: addr_lo
+ type: const
+ width: 32
+ - name: mask
+ type: const
+ width: 32
+ - name: value
+ type: const
+ width: 32
+ brief: Polls an external (NoC-mapped) register until (read & mask) == value.
+ description: |
+ Reads a 32-bit value from the external address formed by (addr_hi << 32 | addr_lo) via
+ a uC-DMA MM2DM transfer and busy-waits until (read_value & mask) == value.
+ Analogous to MASK_POLL_32 but for addresses outside the AIE array register space,
+ reachable via NMU -> NoC (e.g. PL IP AXI-Lite registers).
+ Used to poll ap_done (bit[1]) of a wts_pl_ctrl AP_CTRL register after triggering ap_start.
+ Example:
+ ```
+ ; Poll ap_done (bit[1]) on wts_pl_ctrl instance 0 (base 0x80000030000):
+ UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+ ```
+
+ - mnemonic: APPLY_OFFSET_PL
+ opcode: 0x23
+ regular: True
+ arguments:
+ - name: table_ptr
+ type: const
+ width: 16
+ - name: buffer_id
+ type: const
+ width: 16
+ - type: pad
+ width: 16
+ brief: Patches the physical DDR address (words 8+9) of one or more wts_params blocks for PL IP start_address.
+ description: |
+ Patches wts_params blocks (each 10 words / 40 bytes) starting at `table_ptr`.
+ XRT resolves `buffer_id` to a 64-bit physical address at BO bind time and
+ writes word[8] <- phys_addr[31:0] and word[9] <- phys_addr[63:32] in each block.
+ Example:
+ ```
+ START_JOB 1
+ APPLY_OFFSET_PL @wts_params, WTS_BUFFER_ID
+ UC_DMA_WRITE_DES_SYNC @wts_pl_bd_chain
+ UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+ END_JOB
+ .align 16
+ wts_pl_bd_chain:
+ UC_DMA_BD 0x800, 0x00030010, @wts_params, 10, 1, 1
+ UC_DMA_BD 0x800, 0x00030000, @val_ap_start, 1, 1, 0
+ .align 4
+ wts_params:
+ .long 0x00000000 ; word 0 offset
+ .long 0x00000000 ; word 1 (reserved)
+ .long 0x00000004 ; word 2 length
+ .long 0x00000000 ; word 3 (reserved)
+ .long 0x00000000 ; word 4 stride
+ .long 0x00000000 ; word 5 (reserved)
+ .long 0x00000001 ; word 6 iterations
+ .long 0x00000000 ; word 7 (reserved)
+ .long 0x00000000 ; word 8 start_addr[31:0] <- APPLY_OFFSET_PL
+ .long 0x00000000 ; word 9 start_addr[63:32] <- APPLY_OFFSET_PL
+ val_ap_start:
+ .long 0x00000001
+ ```
+
directives:
- mnemonic: .long
brief: Specifies a 4 byte integer value.
diff --git a/specification/aie2ps/isa.h b/specification/aie2ps/isa.h
index 258a1994c..13b1e4149 100644
--- a/specification/aie2ps/isa.h
+++ b/specification/aie2ps/isa.h
@@ -44,6 +44,8 @@ constexpr int OPCODE_SAVE_TIMESTAMPS = 28;
constexpr int OPCODE_SLEEP = 29;
constexpr int OPCODE_SAVE_REGISTER = 30;
constexpr int OPCODE_REL_ACQ_SYNC = 33;
+constexpr int OPCODE_UC_DMA_MASK_POLL_EXT = 34;
+constexpr int OPCODE_APPLY_OFFSET_PL = 35;
constexpr int OPCODE_ALIGN = 0xA5;
constexpr int BIT_WIDTH_8 = 8;
constexpr int BIT_WIDTH_16 = 16;
@@ -196,6 +198,14 @@ class isa
opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16), opArg("rel_address", opArg::optype::CONST, BIT_WIDTH_32), opArg("acq_address", opArg::optype::CONST, BIT_WIDTH_32),
});
+ (*m_isa)["uc_dma_mask_poll_ext"] = std::make_shared("uc_dma_mask_poll_ext", OPCODE_UC_DMA_MASK_POLL_EXT, std::vector{
+ opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16), opArg("addr_hi", opArg::optype::CONST, BIT_WIDTH_32), opArg("addr_lo", opArg::optype::CONST, BIT_WIDTH_32), opArg("mask", opArg::optype::CONST, BIT_WIDTH_32), opArg("value", opArg::optype::CONST, BIT_WIDTH_32),
+ });
+
+ (*m_isa)["apply_offset_pl"] = std::make_shared("apply_offset_pl", OPCODE_APPLY_OFFSET_PL, std::vector{
+ opArg("table_ptr", opArg::optype::CONST, BIT_WIDTH_16), opArg("buffer_id", opArg::optype::CONST, BIT_WIDTH_16), opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16),
+ });
+
(*m_isa)[".align"] = std::make_shared(".align", OPCODE_ALIGN, std::vector{});
(*m_isa)[".long"] = std::make_shared(".long", 0/* dummy*/, std::vector{});
(*m_isa)["uc_dma_bd"] = std::make_shared("uc_dma_bd", 0/* dummy*/, std::vector{});
@@ -349,6 +359,14 @@ class isa_disassembler
opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16), opArg("rel_address", opArg::optype::CONST, BIT_WIDTH_32), opArg("acq_address", opArg::optype::CONST, BIT_WIDTH_32),
}));
+ m_isa_disasm.emplace(OPCODE_UC_DMA_MASK_POLL_EXT, isa_op_disasm("uc_dma_mask_poll_ext", OPCODE_UC_DMA_MASK_POLL_EXT, std::vector{
+ opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16), opArg("addr_hi", opArg::optype::CONST, BIT_WIDTH_32), opArg("addr_lo", opArg::optype::CONST, BIT_WIDTH_32), opArg("mask", opArg::optype::CONST, BIT_WIDTH_32), opArg("value", opArg::optype::CONST, BIT_WIDTH_32),
+ }));
+
+ m_isa_disasm.emplace(OPCODE_APPLY_OFFSET_PL, isa_op_disasm("apply_offset_pl", OPCODE_APPLY_OFFSET_PL, std::vector{
+ opArg("table_ptr", opArg::optype::CONST, BIT_WIDTH_16), opArg("buffer_id", opArg::optype::CONST, BIT_WIDTH_16), opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16),
+ }));
+
m_isa_disasm.emplace(OPCODE_EOF, isa_op_disasm("eof", OPCODE_EOF, std::vector{
opArg("_pad", opArg::optype::PAD, BIT_WIDTH_16),
}));
diff --git a/specification/aie2ps/isa_defines.h b/specification/aie2ps/isa_defines.h
index 0a896cfe4..ce6d9b50e 100644
--- a/specification/aie2ps/isa_defines.h
+++ b/specification/aie2ps/isa_defines.h
@@ -45,6 +45,8 @@ static unsigned int control_op_save_timestamps(const uint8_t *_pc, uint32_t unq_
static unsigned int control_op_sleep(const uint8_t *_pc, uint32_t target);
static unsigned int control_op_save_register(const uint8_t *_pc, uint32_t address, uint32_t unq_id);
static unsigned int control_op_rel_acq_sync(const uint8_t *_pc, uint32_t rel_address, uint32_t acq_address);
+static unsigned int control_op_uc_dma_mask_poll_ext(const uint8_t *_pc, uint32_t addr_hi, uint32_t addr_lo, uint32_t mask, uint32_t value);
+static unsigned int control_op_apply_offset_pl(const uint8_t *_pc, uint16_t table_ptr, uint16_t buffer_id);
// Dispatchers
@@ -344,6 +346,26 @@ FORCE_INLINE_FOR_RELEASE_ONLY static inline unsigned int control_dispatch_rel_ac
);
}
+FORCE_INLINE_FOR_RELEASE_ONLY static inline unsigned int control_dispatch_uc_dma_mask_poll_ext(const uint8_t *pc)
+{
+ return control_op_uc_dma_mask_poll_ext(
+ pc,
+ /* addr_hi (const) */ *(uint32_t *)(&pc[4]),
+ /* addr_lo (const) */ *(uint32_t *)(&pc[8]),
+ /* mask (const) */ *(uint32_t *)(&pc[12]),
+ /* value (const) */ *(uint32_t *)(&pc[16])
+ );
+}
+
+FORCE_INLINE_FOR_RELEASE_ONLY static inline unsigned int control_dispatch_apply_offset_pl(const uint8_t *pc)
+{
+ return control_op_apply_offset_pl(
+ pc,
+ /* table_ptr (const) */ *(uint16_t *)(&pc[2]),
+ /* buffer_id (const) */ *(uint16_t *)(&pc[4])
+ );
+}
+
// Case statements for regular operations
@@ -376,7 +398,9 @@ FORCE_INLINE_FOR_RELEASE_ONLY static inline unsigned int control_dispatch_rel_ac
case ISA_OPCODE_SAVE_TIMESTAMPS: pc += control_dispatch_save_timestamps(pc); break; \
case ISA_OPCODE_SLEEP: pc += control_dispatch_sleep(pc); break; \
case ISA_OPCODE_SAVE_REGISTER: pc += control_dispatch_save_register(pc); break; \
- case ISA_OPCODE_REL_ACQ_SYNC: pc += control_dispatch_rel_acq_sync(pc); break;
+ case ISA_OPCODE_REL_ACQ_SYNC: pc += control_dispatch_rel_acq_sync(pc); break; \
+ case ISA_OPCODE_UC_DMA_MASK_POLL_EXT: pc += control_dispatch_uc_dma_mask_poll_ext(pc); break; \
+ case ISA_OPCODE_APPLY_OFFSET_PL: pc += control_dispatch_apply_offset_pl(pc); break;
#endif
diff --git a/specification/aie2ps/isa_stubs.h b/specification/aie2ps/isa_stubs.h
index c82607299..12df76554 100644
--- a/specification/aie2ps/isa_stubs.h
+++ b/specification/aie2ps/isa_stubs.h
@@ -59,6 +59,8 @@
#define ISA_OPCODE_SLEEP 0x1d
#define ISA_OPCODE_SAVE_REGISTER 0x1e
#define ISA_OPCODE_REL_ACQ_SYNC 0x21
+#define ISA_OPCODE_UC_DMA_MASK_POLL_EXT 0x22
+#define ISA_OPCODE_APPLY_OFFSET_PL 0x23
// Operation sizes
@@ -97,5 +99,7 @@
#define ISA_OPSIZE_SLEEP 0x08
#define ISA_OPSIZE_SAVE_REGISTER 0x0c
#define ISA_OPSIZE_REL_ACQ_SYNC 0x0c
+#define ISA_OPSIZE_UC_DMA_MASK_POLL_EXT 0x14
+#define ISA_OPSIZE_APPLY_OFFSET_PL 0x08
#endif
diff --git a/src/cpp/analyzer/transform_manager.cpp b/src/cpp/analyzer/transform_manager.cpp
index c0f7943fe..833957415 100644
--- a/src/cpp/analyzer/transform_manager.cpp
+++ b/src/cpp/analyzer/transform_manager.cpp
@@ -36,6 +36,14 @@ struct apply_offset_57 {
uint16_t offset; // Offset value to be modified
};
+struct apply_offset_pl {
+ uint8_t opcode; // Opcode identifier
+ uint8_t pad; // Padding byte
+ uint16_t table_ptr; // Pointer to wts_params block
+ uint16_t buffer_id; // XRT buffer id (patched to xrt_idx at update time)
+ uint16_t pad2; // Trailing padding to reach 8-byte instruction size
+};
+
/**
* @brief Constructor - loads ELF data and initializes ISA map
* @param elf_data Raw ELF binary data
@@ -156,6 +164,15 @@ modify_apply_offset_57(char* text_section_data, size_t text_section_size, uint32
code->offset = static_cast(lookup_it->second * num_32bit_register); // Convert xrt_id to register offset
}
+ // Process apply_offset_pl opcode
+ if (opcode == OPCODE_APPLY_OFFSET_PL) {
+ auto code = reinterpret_cast(text_section_data + offset);
+ auto key = get_key(code->table_ptr, section_idx);
+ auto lookup_it = xrt_idx_lookup.find(key);
+ if (lookup_it != xrt_idx_lookup.end())
+ code->buffer_id = static_cast(lookup_it->second);
+ }
+
// Move to next instruction
offset += size(op_it->second);
}
@@ -221,6 +238,17 @@ modify_apply_offset_57_merged(char* section_data, size_t section_size, uint32_t
code->offset = static_cast(lookup_it->second * num_32bit_register);
}
+ if (opcode == OPCODE_APPLY_OFFSET_PL) {
+ auto* code = reinterpret_cast(section_data + offset);
+ uint32_t adjusted_ptr = static_cast(code->table_ptr) +
+ static_cast(page_start) +
+ static_cast(elf_section_header_size);
+ auto key = get_key(adjusted_ptr, section_idx);
+ auto lookup_it = xrt_idx_lookup.find(key);
+ if (lookup_it != xrt_idx_lookup.end())
+ code->buffer_id = static_cast(lookup_it->second);
+ }
+
const uint32_t inst_sz = size(op_it->second);
offset += inst_sz;
@@ -454,6 +482,31 @@ write57_aie4(uint32_t* bd_data_ptr, uint64_t bd_offset)
bd_data_ptr[0] = static_cast((bd_data_ptr[0] & 0xFE000000) | ((bd_offset >> 32) & 0x1FFFFFF));// NOLINT
}
+/**
+ * @brief Read 64-bit DDR address from wts_params block (words 8+9)
+ * @param bd_data_ptr Pointer to wts_params data (32-bit words)
+ * @return 64-bit physical address: word[8] = [31:0], word[9] = [63:32]
+ */
+uint64_t
+transform_manager::
+read_pl_ddr64(const uint32_t* bd_data_ptr) const
+{
+ return (static_cast(bd_data_ptr[9]) << 32) | bd_data_ptr[8]; // NOLINT
+}
+
+/**
+ * @brief Write 64-bit DDR address into wts_params block (words 8+9)
+ * @param bd_data_ptr Pointer to wts_params data (32-bit words)
+ * @param bd_offset 64-bit physical DDR address to write
+ */
+void
+transform_manager::
+write_pl_ddr64(uint32_t* bd_data_ptr, uint64_t bd_offset)
+{
+ bd_data_ptr[8] = static_cast(bd_offset & 0xFFFFFFFF); // NOLINT
+ bd_data_ptr[9] = static_cast((bd_offset >> 32) & 0xFFFFFFFF); // NOLINT
+}
+
/**
* @brief Read buffer descriptor offset from control packet for AIE2PS
* @param bd_data_ptr Pointer to control packet header (32-bit words)
@@ -567,6 +620,8 @@ get_controlcode_bd_offset(const std::string& section_name, uint32_t offset, symb
return read57(bd_data_ptr);
case symbol::patch_schema::shim_dma_57_aie4:
return read57_aie4(bd_data_ptr);
+ case symbol::patch_schema::pl_ddr_64:
+ return read_pl_ddr64(bd_data_ptr);
default:
throw error(error::error_code::internal_error, "Invalid schema found\n");
}
@@ -625,6 +680,9 @@ set_controlcode_bd_offset(const std::string& section_name, uint32_t offset, uint
case symbol::patch_schema::shim_dma_57_aie4:
write57_aie4(bd_data_ptr, bd_offset);
break;
+ case symbol::patch_schema::pl_ddr_64:
+ write_pl_ddr64(bd_data_ptr, bd_offset);
+ break;
default:
throw error(error::error_code::internal_error, "Invalid schema found\n");
}
diff --git a/src/cpp/analyzer/transform_manager.h b/src/cpp/analyzer/transform_manager.h
index ffb8c7cb2..5970fafe9 100644
--- a/src/cpp/analyzer/transform_manager.h
+++ b/src/cpp/analyzer/transform_manager.h
@@ -132,6 +132,8 @@ class transform_manager {
uint64_t read57_aie4(const uint32_t* bd_data_ptr) const;
void write57(uint32_t* bd_data_ptr, uint64_t bd_offset);
void write57_aie4(uint32_t* bd_data_ptr, uint64_t bd_offset);
+ uint64_t read_pl_ddr64(const uint32_t* bd_data_ptr) const;
+ void write_pl_ddr64(uint32_t* bd_data_ptr, uint64_t bd_offset);
uint64_t ctrlpkt_read57(const uint32_t* bd_data_ptr) const;
void ctrlpkt_write57(uint32_t* bd_data_ptr, uint64_t bd_offset);
uint64_t ctrlpkt_read57_aie4(const uint32_t* bd_data_ptr) const;
diff --git a/src/cpp/common/assembler_state.cpp b/src/cpp/common/assembler_state.cpp
index c61be24ab..5bea040d7 100644
--- a/src/cpp/common/assembler_state.cpp
+++ b/src/cpp/common/assembler_state.cpp
@@ -116,12 +116,12 @@ process(bool makeunique)
m_jobmap[cjob_id]->set_end_index(index);
cjob_id.clear();
}
- // maintain map of label and num_entries for apply_offset_57
+ // maintain map of label and num_entries for apply_offset_57 / apply_offset_pl
// only used in pager
// since label are after control code ops we need to record intermediately and resolve it later
- if (!name.compare("apply_offset_57") && makeunique)
+ if ((!name.compare("apply_offset_57") || !name.compare("apply_offset_pl")) && makeunique)
apply_label_map[data->get_qualify_label(data->get_operation().get_args()[0].substr(1))]
- = std::stoul(data->get_operation().get_args()[1]);
+ = !name.compare("apply_offset_pl") ? 1 : std::stoul(data->get_operation().get_args()[1]);
} else {
throw error(error::error_code::internal_error, "Unknown type found!!!");
}
diff --git a/src/cpp/common/assembler_state.h b/src/cpp/common/assembler_state.h
index 3e29ea57e..d08c330ea 100644
--- a/src/cpp/common/assembler_state.h
+++ b/src/cpp/common/assembler_state.h
@@ -238,9 +238,10 @@ class assembler_state : public std::enable_shared_from_this
void process_optimization(uint32_t optimize_level)
{
- if (optimize_level >= 1)
+ if (optimize_level >= 1) {
m_opt_opcodes.insert("apply_offset_57");
- else
+ m_opt_opcodes.insert("apply_offset_pl");
+ } else
m_opt_opcodes.clear();
}
diff --git a/src/cpp/common/symbol.h b/src/cpp/common/symbol.h
index 8a74015fd..4a8b88bf5 100644
--- a/src/cpp/common/symbol.h
+++ b/src/cpp/common/symbol.h
@@ -25,6 +25,7 @@ class symbol
address_64 = 8,
control_packet_57_aie4 = 9,
unknown = 10,
+ pl_ddr_64 = 11,
};
private:
diff --git a/src/cpp/ops/ops.cpp b/src/cpp/ops/ops.cpp
index 81a2f4fd0..bbdeec704 100644
--- a/src/cpp/ops/ops.cpp
+++ b/src/cpp/ops/ops.cpp
@@ -175,6 +175,22 @@ serialize(std::shared_ptr state, std::vector& symbols,
}
}
}
+
+ // For apply_offset_pl, arg 'buffer_id' emits a pl_ddr_64 ELF relocation
+ // for the single wts_params block so XRT can patch words 8+9 at BO bind time.
+ if (!m_opcode->get_code_name().compare("apply_offset_pl") && !arg.get_name().compare("buffer_id"))
+ {
+ sval = std::to_string(val); // buffer_id is the XRT arg index
+ size_t index = state->find_label_entry(m_args[0].substr(1));
+ const std::string ctrltext_patch_sec_name =
+ state->merged_ctrltext_elf()
+ ? (".ctrltext." + std::to_string(colnum))
+ : (".ctrltext." + std::to_string(colnum) + "." + std::to_string(pagenum));
+ auto label = state->get_label_at(index);
+ symbols.emplace_back(sval, state->parse_num_arg(label),
+ colnum, pagenum, 0, 0, ctrltext_patch_sec_name,
+ symbol::patch_schema::pl_ddr_64);
+ }
if (!state->is_optimization_enabled_for_op(m_opcode->get_code_name())){
ret.push_back(val & BYTE_MASK);
ret.push_back((val >> SECOND_BYTE_SHIFT) & BYTE_MASK);
diff --git a/src/tree-sitter/tree-sitter-aie4-ctrlcode/grammar.js b/src/tree-sitter/tree-sitter-aie4-ctrlcode/grammar.js
index c360a7e3d..aa84c2ac7 100644
--- a/src/tree-sitter/tree-sitter-aie4-ctrlcode/grammar.js
+++ b/src/tree-sitter/tree-sitter-aie4-ctrlcode/grammar.js
@@ -83,6 +83,7 @@ module.exports = grammar({
$.uc_dma_write_des_sync_statement,
$.mask_write_32_statement,
$.mask_poll_32_statement,
+ $.uc_dma_mask_poll_ext_statement,
$.apply_offset_statement,
$.uc_dma_bd_statement,
$.load_pdi_statement,
@@ -127,6 +128,17 @@ module.exports = grammar({
$.hexint
),
+ uc_dma_mask_poll_ext_statement: $ => seq(
+ token(choice('UC_DMA_MASK_POLL_EXT', 'uc_dma_mask_poll_ext')),
+ $.hexint,
+ ',',
+ $.hexint,
+ ',',
+ $.hexint,
+ ',',
+ $.hexint
+ ),
+
apply_offset_statement: $ => seq(
token(seq('APPLY_OFFSET_', /\d+/)),
$.address,
diff --git a/test/aie2ps-ctrlcode/CMakeLists.txt b/test/aie2ps-ctrlcode/CMakeLists.txt
index e95399afa..1bee2dce0 100644
--- a/test/aie2ps-ctrlcode/CMakeLists.txt
+++ b/test/aie2ps-ctrlcode/CMakeLists.txt
@@ -85,3 +85,5 @@ add_subdirectory(eff_net_coal)
add_subdirectory(legal_duplicate_include)
add_subdirectory(decode_opcode)
+
+add_subdirectory(plip)
diff --git a/test/aie2ps-ctrlcode/plip/CMakeLists.txt b/test/aie2ps-ctrlcode/plip/CMakeLists.txt
new file mode 100644
index 000000000..c2a10387e
--- /dev/null
+++ b/test/aie2ps-ctrlcode/plip/CMakeLists.txt
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: MIT
+# Copyright (C) 2026 Advanced Micro Devices, Inc.
+
+# Assemble wts_pl_ctrl ctrlcode to ELF (C++ assembler)
+add_test(NAME "aie2ps_plip_asm"
+ COMMAND aiebu-asm -t aie2ps -c "${CMAKE_CURRENT_SOURCE_DIR}/ctrlcode.asm" -o ctrlcode_plip.elf -f disabledump)
+
+# Verify round-trip ELF is byte-identical to the original
+add_test(NAME "aie2ps_plip_elf_md5sum"
+ COMMAND cmake -P "${AIEBU_SOURCE_DIR}/cmake/md5sum-compare.cmake" "${CMAKE_CURRENT_BINARY_DIR}/ctrlcode_plip.elf" "${CMAKE_CURRENT_SOURCE_DIR}/gold.md5"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+# Convert C++ ELF to legacy text
+add_test(NAME "aie2ps_plip_cpp_elftolegacy"
+ COMMAND "${AIEBU_SOURCE_DIR}/src/python/aiebu/elf_to_legacy.py"
+ -o ctrlcode_plip_cpp.out.txt -i ctrlcode_plip.elf
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+add_test(NAME "aie2ps_plip_cpp_compare"
+ COMMAND ${CMAKE_COMMAND} -E compare_files
+ ctrlcode_plip_cpp.out.txt "${CMAKE_CURRENT_SOURCE_DIR}/ctrlcode.txt"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+set_tests_properties("aie2ps_plip_asm" PROPERTIES LABELS memcheck)
+set_tests_properties("aie2ps_plip_elf_md5sum" PROPERTIES DEPENDS "aie2ps_plip_asm")
+set_tests_properties("aie2ps_plip_cpp_elftolegacy" PROPERTIES DEPENDS "aie2ps_plip_asm")
+set_tests_properties("aie2ps_plip_cpp_compare" PROPERTIES DEPENDS "aie2ps_plip_cpp_elftolegacy")
\ No newline at end of file
diff --git a/test/aie2ps-ctrlcode/plip/ctrlcode.asm b/test/aie2ps-ctrlcode/plip/ctrlcode.asm
new file mode 100644
index 000000000..fdcec1707
--- /dev/null
+++ b/test/aie2ps-ctrlcode/plip/ctrlcode.asm
@@ -0,0 +1,36 @@
+;
+; Test: APPLY_OFFSET_PL + UC_DMA_MASK_POLL_EXT
+; Verifies assembly, disassembly round-trip for the wts_pl_ctrl PL IP opcodes.
+;
+
+START_JOB 0
+ APPLY_OFFSET_PL @wts_params, 2
+ UC_DMA_WRITE_DES_SYNC @wts_pl_bd_chain
+ UC_DMA_MASK_POLL_EXT 0x00000800, 0x00030000, 0x00000002, 0x00000002
+END_JOB
+
+EOF
+
+;
+; Data
+;
+
+.align 16
+wts_pl_bd_chain:
+ UC_DMA_BD 0x800, 0x00030010, @wts_params, 10, 1, 1
+ UC_DMA_BD 0x800, 0x00030000, @val_ap_start, 1, 1, 0
+
+.align 4
+wts_params:
+ .long 0x00000001
+ .long 0x00000002
+ .long 0x00000003
+ .long 0x00000004
+ .long 0x00000005
+ .long 0x00000006
+ .long 0x00000007
+ .long 0x00000008
+ .long 0x00000009
+ .long 0x00000010
+val_ap_start:
+ .long 0x00000001
diff --git a/test/aie2ps-ctrlcode/plip/ctrlcode.txt b/test/aie2ps-ctrlcode/plip/ctrlcode.txt
new file mode 100644
index 000000000..772791a01
--- /dev/null
+++ b/test/aie2ps-ctrlcode/plip/ctrlcode.txt
@@ -0,0 +1,1024 @@
+ff ff 00 00 00 00 00 00
+8c 00 00 00 00 00 00 00
+00 00 00 00 2c 00 00 00
+23 00 50 00 02 00 00 00
+09 00 30 00 22 00 00 00
+00 08 00 00 00 00 03 00
+02 00 00 00 02 00 00 00
+07 00 00 00 ff 00 00 00
+0a 00 07 00 20 00 00 00
+10 00 03 00 00 08 00 00
+01 00 06 00 38 00 00 00
+00 00 03 00 00 08 00 00
+01 00 00 00 02 00 00 00
+03 00 00 00 04 00 00 00
+05 00 00 00 06 00 00 00
+07 00 00 00 08 00 00 00
+09 00 00 00 10 00 00 00
+01 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00
diff --git a/test/aie2ps-ctrlcode/plip/gold.md5 b/test/aie2ps-ctrlcode/plip/gold.md5
new file mode 100644
index 000000000..dc573f73b
--- /dev/null
+++ b/test/aie2ps-ctrlcode/plip/gold.md5
@@ -0,0 +1 @@
+2a8ea552a773c48bdb0679632e3e6087