Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
    • RAL Overview
      • Why a Register Model: Desired, Mirrored and the DUT
      • Blocks, Registers, Fields and Memories
      • Maps, Offsets and Endianness
      • Nested Blocks and Submaps
      • Build, Lock and Generated Models
      • The Frontdoor Path, End to End
      • The Register Layer: Full Source
    • Register Access
    • Registers in Verification
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹RAL Overview
  1. Topics
  2. UVM Verification
  3. UVM Register Abstraction Layer (RAL)
  4. RAL Overview
  5. The Register Layer: Full Source

Part 9 · Register Model (RAL) · Intermediate

The Register Layer: Full Source

The complete dma_ral_tb.sv: register model, adapter, predictor, backdoor, env and the four register tests, ready to paste into EDA Playground.

This page holds the complete register-layer file used throughout this section. Lessons show it piece by piece; this is the version to copy.

How to run it

  • On EDA Playground: dma_dut.sv in the design tab, dma_tb.sv in the testbench tab, and dma_ral_tb.sv added as a second testbench file with the + button. dma_tb.sv comes from the DMA bench source (its three parts pasted together), and dma_ral_tb.sv is listed below.

  • Select UVM 1.2 and a simulator such as Aldec Riviera-PRO, make dma_ral_tb.sv the file that is compiled last (it includes dma_tb.sv itself), and set the top to top.

  • Pick a test with +UVM_TESTNAME=: dma_ral_job_test (the default), dma_ral_reset_test, dma_ral_bitbash_test, or dma_ral_busy_len_test (which ends with one UVM_ERROR on purpose).

  • Locally: UVM_HOME=<uvm>/src scripts/tools/uvm-bench/run.sh scripts/data/uvm-course/bench/dma_ral_tb.sv +UVM_TESTNAME=dma_ral_job_test.

dma_ral_tb.sv

dma_bd_if.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
// not-run: needs the UVM library. Paste into EDA Playground with UVM 1.2 selected.
// dma_ral_tb.sv - the DMA's register layer: a register model, an APB adapter, an
// explicit predictor and a user-defined backdoor. Compile with dma_dut.sv; this
// file includes dma_tb.sv (keep both files side by side) and replaces its top.
// Run: +UVM_TESTNAME=dma_ral_job_test (or dma_ral_reset_test, dma_ral_bitbash_test,
// dma_ral_busy_len_test).
`define DMA_NO_TOP
`include "dma_tb.sv"

// A read-only window into the DMA's internal registers, bound into every
// dma_dut. The register model's backdoor reads through it.
interface dma_bd_if (input logic [31:0] key, input logic [15:0] len, input logic [15:0] count);
endinterface

bind dma_dut dma_bd_if bd (.key(key), .len(len), .count(count));

package dma_ral_pkg;
  import uvm_pkg::*;
  import dma_pkg::*;

  // ---------------------------------------------------------------- registers
  // CTRL @0x00: GO is a trigger (write 1 to start, always reads 0), IRQ_EN is RW.
  class dma_ctrl_reg extends uvm_reg;
    `uvm_object_utils(dma_ctrl_reg)
    uvm_reg_field go;
    rand uvm_reg_field irq_en;

    function new(string name = "dma_ctrl_reg");
      super.new(name, 32, UVM_NO_COVERAGE);
    endfunction

    virtual function void build();
      go     = uvm_reg_field::type_id::create("go");
      irq_en = uvm_reg_field::type_id::create("irq_en");
      //               parent size lsb access volatile reset has_reset is_rand indiv
      go.configure    (this, 1,   0,  "WO",  0,       1'b0, 1,        0,      0);
      irq_en.configure(this, 1,   1,  "RW",  0,       1'b0, 1,        1,      0);
    endfunction
  endclass

  // STATUS @0x04: BUSY is read-only; DONE and ERR are set by the hardware and
  // cleared by writing 1. All three change without a bus write, so all are volatile.
  class dma_status_reg extends uvm_reg;
    `uvm_object_utils(dma_status_reg)
    uvm_reg_field busy, done, err;

    function new(string name = "dma_status_reg");
      super.new(name, 32, UVM_NO_COVERAGE);
    endfunction

    virtual function void build();
      busy = uvm_reg_field::type_id::create("busy");
      done = uvm_reg_field::type_id::create("done");
      err  = uvm_reg_field::type_id::create("err");
      busy.configure(this, 1, 0, "RO",  1, 1'b0, 1, 0, 0);
      done.configure(this, 1, 1, "W1C", 1, 1'b0, 1, 0, 0);
      err.configure (this, 1, 2, "W1C", 1, 1'b0, 1, 0, 0);
    endfunction
  endclass

  // LEN @0x08 and KEY @0x0C: plain RW registers (the DMA ignores writes to them
  // while BUSY - see dma_ral_busy_len_test).
  class dma_len_reg extends uvm_reg;
    `uvm_object_utils(dma_len_reg)
    rand uvm_reg_field value;
    function new(string name = "dma_len_reg");
      super.new(name, 32, UVM_NO_COVERAGE);
    endfunction
    virtual function void build();
      value = uvm_reg_field::type_id::create("value");
      value.configure(this, 16, 0, "RW", 0, 16'h0, 1, 1, 0);
    endfunction
  endclass

  class dma_key_reg extends uvm_reg;
    `uvm_object_utils(dma_key_reg)
    rand uvm_reg_field value;
    function new(string name = "dma_key_reg");
      super.new(name, 32, UVM_NO_COVERAGE);
    endfunction
    virtual function void build();
      value = uvm_reg_field::type_id::create("value");
      value.configure(this, 32, 0, "RW", 0, 32'h0, 1, 1, 0);
    endfunction
  endclass

  // COUNT @0x10: read-only, counts as the job runs, so volatile.
  class dma_count_reg extends uvm_reg;
    `uvm_object_utils(dma_count_reg)
    uvm_reg_field value;
    function new(string name = "dma_count_reg");
      super.new(name, 32, UVM_NO_COVERAGE);
    endfunction
    virtual function void build();
      value = uvm_reg_field::type_id::create("value");
      value.configure(this, 16, 0, "RO", 1, 16'h0, 1, 0, 0);
    endfunction
  endclass

  // ---------------------------------------------------------------- block
  class dma_reg_block extends uvm_reg_block;
    `uvm_object_utils(dma_reg_block)
    rand dma_ctrl_reg   ctrl;
         dma_status_reg status;
    rand dma_len_reg    len;
    rand dma_key_reg    key;
         dma_count_reg  count;
    uvm_reg_map         map;

    function new(string name = "dma_reg_block");
      super.new(name, UVM_NO_COVERAGE);
    endfunction

    virtual function void build();
      ctrl   = dma_ctrl_reg::type_id::create("ctrl");
      status = dma_status_reg::type_id::create("status");
      len    = dma_len_reg::type_id::create("len");
      key    = dma_key_reg::type_id::create("key");
      count  = dma_count_reg::type_id::create("count");
      ctrl.configure(this);    ctrl.build();
      status.configure(this);  status.build();
      len.configure(this);     len.build();
      key.configure(this);     key.build();
      count.configure(this);   count.build();

      // One APB map: base 0, 4-byte bus, little endian.
      map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
      map.add_reg(ctrl,   'h00, "RW");
      map.add_reg(status, 'h04, "RW");
      map.add_reg(len,    'h08, "RW");
      map.add_reg(key,    'h0C, "RW");
      map.add_reg(count,  'h10, "RO");
      lock_model();
    endfunction
  endclass

  // ---------------------------------------------------------------- adapter
  // Translates between register operations and APB items. The APB driver writes
  // read data and PSLVERR back into the request item, so there is no separate
  // response: provides_responses = 0.
  class apb_reg_adapter extends uvm_reg_adapter;
    `uvm_object_utils(apb_reg_adapter)

    function new(string name = "apb_reg_adapter");
      super.new(name);
      supports_byte_enable = 0;
      provides_responses   = 0;
    endfunction

    virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
      apb_item it = apb_item::type_id::create("it");
      it.addr  = rw.addr;
      it.write = (rw.kind == UVM_WRITE) || (rw.kind == UVM_BURST_WRITE);
      it.data  = rw.data;
      return it;
    endfunction

    virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
      apb_item it;
      if (!$cast(it, bus_item))
        `uvm_fatal("NOT_APB", "bus2reg got an item that is not an apb_item")
      rw.kind   = it.write ? UVM_WRITE : UVM_READ;
      rw.addr   = it.addr;
      rw.data   = it.write ? it.data : it.rdata;
      rw.status = it.slverr ? UVM_NOT_OK : UVM_IS_OK;   // a bus error is a status, not a fatal
    endfunction
  endclass

  // ---------------------------------------------------------------- backdoor
  // A user-defined backdoor: reads KEY, LEN and COUNT straight from the DUT
  // through the bound dma_bd_if, with no bus traffic and no simulation time.
  // It needs no HDL-path DPI, so it works on every simulator. Writes are refused.
  class dma_reg_backdoor extends uvm_reg_backdoor;
    virtual dma_bd_if vif;

    function new(string name = "dma_reg_backdoor");
      super.new(name);
    endfunction

    virtual function void read_func(uvm_reg_item rw);
      uvm_reg r;
      if (!$cast(r, rw.element)) begin
        rw.status = UVM_NOT_OK;
        return;
      end
      rw.status = UVM_IS_OK;
      case (r.get_name())
        "key":   rw.value[0] = vif.key;
        "len":   rw.value[0] = vif.len;
        "count": rw.value[0] = vif.count;
        default: rw.status = UVM_NOT_OK;
      endcase
    endfunction

    virtual task write(uvm_reg_item rw);
      `uvm_warning("BD_RO", "this backdoor is read-only")
      rw.status = UVM_NOT_OK;
    endtask
  endclass

  // ---------------------------------------------------------------- env
  // The block env plus the register layer: the model, the adapter on the APB
  // sequencer, and an explicit predictor fed by the APB monitor.
  class dma_ral_env extends dma_env;
    `uvm_component_utils(dma_ral_env)
    dma_reg_block                 regmodel;
    apb_reg_adapter               adapter;
    uvm_reg_predictor #(apb_item) predictor;
    dma_reg_backdoor              bd;
    virtual dma_bd_if             bd_vif;
    bit                           auto_predict;   // config_db knob, default 0

    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      void'(uvm_config_db#(bit)::get(this, "", "auto_predict", auto_predict));
      regmodel = dma_reg_block::type_id::create("regmodel");
      regmodel.build();
      adapter   = apb_reg_adapter::type_id::create("adapter");
      predictor = uvm_reg_predictor #(apb_item)::type_id::create("predictor", this);
      if (!uvm_config_db#(virtual dma_bd_if)::get(this, "", "bd_vif", bd_vif))
        `uvm_fatal("NOVIF", "dma_bd_if not set for the register env")
      bd = new("bd");
      bd.vif = bd_vif;
      regmodel.key.set_backdoor(bd);
      regmodel.len.set_backdoor(bd);
      regmodel.count.set_backdoor(bd);
    endfunction

    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      regmodel.map.set_sequencer(apb.sqr, adapter);
      // The explicit predictor updates the mirror from what the APB monitor sees.
      // That happens when the monitor publishes the transfer - in this bench a
      // moment after write()/read() return, in the same time step. Code that
      // reads the mirror the instant an access returns (uvm_reg_bit_bash_seq's
      // rg.get(), mirror()'s expected value) then sees the old value. Tests
      // that need it turn on auto_predict as well.
      regmodel.map.set_auto_predict(auto_predict);
      predictor.map     = regmodel.map;
      predictor.adapter = adapter;
      apb.ap.connect(predictor.bus_in);
    endfunction
  endclass

  // ---------------------------------------------------------------- tests
  class dma_ral_base_test extends dma_base_test;
    `uvm_component_utils(dma_ral_base_test)
    dma_ral_env renv;

    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
      dma_env::type_id::set_type_override(dma_ral_env::get_type());
      super.build_phase(phase);
    endfunction

    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      if (!$cast(renv, env)) `uvm_fatal("CAST", "env is not a dma_ral_env")
    endfunction

    // Register-only tests move no data, so the scoreboard's "nothing compared"
    // check does not apply to them.
    function void waive_empty_scoreboard();
      env.sb.set_report_severity_id_override(UVM_ERROR, "SB_EMPTY", UVM_INFO);
    endfunction
  endclass

  // Every register's reset value, read through the bus and checked against the model.
  class dma_ral_reset_test extends dma_ral_base_test;
    `uvm_component_utils(dma_ral_reset_test)
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    function void end_of_elaboration_phase(uvm_phase phase);
      super.end_of_elaboration_phase(phase);
      waive_empty_scoreboard();
    endfunction
    task run_phase(uvm_phase phase);
      uvm_reg_hw_reset_seq seq = uvm_reg_hw_reset_seq::type_id::create("seq");
      phase.raise_objection(this);
      seq.model = renv.regmodel;
      seq.start(null);
      `uvm_info("RAL", "reset values checked (registers whose fields are all volatile are skipped)", UVM_LOW)
      phase.drop_objection(this);
    endtask
  endclass

  // Walk a 1 and a 0 through every bit of the RW registers. CTRL and STATUS are
  // excluded: writing CTRL.GO would start a job, and STATUS bits are W1C.
  class dma_ral_bitbash_test extends dma_ral_base_test;
    `uvm_component_utils(dma_ral_bitbash_test)
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    function void build_phase(uvm_phase phase);
      uvm_config_db#(bit)::set(this, "env", "auto_predict", 1);  // bit-bash reads rg.get() right after write()
      super.build_phase(phase);
    endfunction
    function void end_of_elaboration_phase(uvm_phase phase);
      super.end_of_elaboration_phase(phase);
      waive_empty_scoreboard();
    endfunction
    task run_phase(uvm_phase phase);
      uvm_reg_bit_bash_seq seq = uvm_reg_bit_bash_seq::type_id::create("seq");
      phase.raise_objection(this);
      uvm_resource_db#(bit)::set({"REG::", renv.regmodel.ctrl.get_full_name()},   "NO_REG_TESTS", 1, this);
      uvm_resource_db#(bit)::set({"REG::", renv.regmodel.status.get_full_name()}, "NO_REG_TESTS", 1, this);
      seq.model = renv.regmodel;
      seq.start(null);
      `uvm_info("RAL", "bit-bash finished for LEN, KEY and COUNT (errors, if any, are reported above)", UVM_LOW)
      phase.drop_objection(this);
    endtask
  endclass

  // A whole DMA job driven through the register model: write by name, read
  // STATUS and COUNT, clear DONE, and compare the mirror with a backdoor peek.
  class dma_ral_job_test extends dma_ral_base_test;
    `uvm_component_utils(dma_ral_job_test)
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    task run_phase(uvm_phase phase);
      uvm_status_e   st;
      uvm_reg_data_t v, peeked, exp_key;
      dma_reg_block  rm  = renv.regmodel;
      axis_pkt_seq   pkt = axis_pkt_seq::type_id::create("pkt");
      phase.raise_objection(this);

      rm.key.write(st, 32'hCAFE_F00D);
      rm.len.write(st, 6);
      // GO is a trigger: write CTRL directly. update() would skip it on the next
      // job, because the mirror already holds GO = 1 from this write.
      rm.ctrl.write(st, 32'h3);
      if (!pkt.randomize() with { n == 6; }) `uvm_fatal("RAND", "axis_pkt_seq randomize failed")
      pkt.start(env.in_agt.sqr);
      wait (irq_vif.irq === 1'b1);

      rm.status.read(st, v);
      `uvm_info("RAL", $sformatf("STATUS=%0h: done=%0b err=%0b", v, rm.status.done.get_mirrored_value(),
                rm.status.err.get_mirrored_value()), UVM_LOW)
      rm.count.read(st, v);
      if (v != 6) `uvm_error("RAL", $sformatf("COUNT=%0d, expected 6", v))
      rm.status.write(st, 32'h2);                // W1C: clear DONE
      rm.status.read(st, v);
      if (v[2:0] != 3'b000) `uvm_error("RAL", $sformatf("STATUS not clear after W1C: %0h", v))
      exp_key = rm.key.get_mirrored_value();   // expectation first: peek() overwrites the mirror
      rm.key.peek(st, peeked);                  // backdoor: no bus, no time
      `uvm_info("RAL", $sformatf("KEY mirror=%0h, backdoor peek=%0h, status=%s",
                exp_key, peeked, st.name()), UVM_LOW)
      if (st != UVM_IS_OK || peeked != exp_key) `uvm_error("RAL", "KEY mirror and DUT disagree")
      #100ns;
      phase.drop_objection(this);
    endtask
  endclass

  // The model meets a DUT rule it does not know: the DMA ignores writes to LEN
  // while BUSY. The write goes out on the bus, the predictor updates the mirror,
  // and a mirror(UVM_CHECK) read then reports the DUT's real value as a mismatch.
  // This test is expected to end with one UVM_ERROR from the register model.
  class dma_ral_busy_len_test extends dma_ral_base_test;
    `uvm_component_utils(dma_ral_busy_len_test)
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    function void build_phase(uvm_phase phase);
      uvm_config_db#(bit)::set(this, "env", "auto_predict", 1);  // mirror() takes its expected value at once
      super.build_phase(phase);
    endfunction
    task run_phase(uvm_phase phase);
      uvm_status_e   st;
      uvm_reg_data_t peeked;
      dma_reg_block  rm  = renv.regmodel;
      axis_pkt_seq   pkt = axis_pkt_seq::type_id::create("pkt");
      phase.raise_objection(this);
      rm.key.write(st, 32'h0000_00FF);
      rm.len.write(st, 4);
      rm.ctrl.write(st, 32'h3);                 // the DMA is now BUSY
      rm.len.write(st, 9);                      // ignored by the DMA, believed by the mirror
      `uvm_info("RAL", $sformatf("LEN mirror after the write: %0d", rm.len.get_mirrored_value()), UVM_LOW)
      rm.len.mirror(st, UVM_CHECK);             // reads 4, expects 9: RegModel error
      // peek() after the check, not before: a peek predicts the value it reads,
      // so peeking first would quietly set the mirror to 4 and hide the mismatch.
      rm.len.peek(st, peeked);
      `uvm_info("RAL", $sformatf("DUT LEN (backdoor peek)=%0d, mirror now %0d", peeked, rm.len.get_mirrored_value()), UVM_LOW)
      if (!pkt.randomize() with { n == 4; }) `uvm_fatal("RAND", "axis_pkt_seq randomize failed")
      pkt.start(env.in_agt.sqr);
      wait (irq_vif.irq === 1'b1);
      rm.status.write(st, 32'h2);
      #100ns;
      phase.drop_objection(this);
    endtask
  endclass
endpackage

// ============================ top ============================
module top;
  import uvm_pkg::*;
  import dma_pkg::*;
  import dma_ral_pkg::*;

  logic clk = 0;
  always #5 clk = ~clk;
  rst_if rst (clk);
  wire rst_n = rst.rst_n;
  initial begin
    rst.rst_n = 1'b0;
    repeat (4) @(posedge clk);
    rst.rst_n <= 1'b1;
  end

  apb_if  apb  (clk, rst_n);
  axis_if s_ax (clk, rst_n);
  axis_if m_ax (clk, rst_n);
  irq_if  irqi (clk);
  initial m_ax.tready = 1'b1;

  dma_dut dut (
    .clk, .rst_n,
    .paddr(apb.paddr), .psel(apb.psel), .penable(apb.penable), .pwrite(apb.pwrite),
    .pwdata(apb.pwdata), .prdata(apb.prdata), .pready(apb.pready), .pslverr(apb.pslverr),
    .s_tdata(s_ax.tdata), .s_tvalid(s_ax.tvalid), .s_tlast(s_ax.tlast), .s_tready(s_ax.tready),
    .m_tdata(m_ax.tdata), .m_tvalid(m_ax.tvalid), .m_tlast(m_ax.tlast), .m_tready(m_ax.tready),
    .irq(irqi.irq)
  );

  initial begin
    uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env.apb.*", "vif", apb);
    uvm_config_db#(virtual axis_if)::set(null, "uvm_test_top.env.in_agt.*", "vif", s_ax);
    uvm_config_db#(virtual axis_if)::set(null, "uvm_test_top.env.out_agt.*", "vif", m_ax);
    uvm_config_db#(virtual irq_if)::set(null, "uvm_test_top", "irq_vif", irqi);
    uvm_config_db#(virtual dma_bd_if)::set(null, "uvm_test_top.env", "bd_vif", dut.bd);
    run_test("dma_ral_job_test");
  end
endmodule

Start with Why a register model for the walk-through.

Previous

153 / 280

Next: Register Access

Up next

Up nextRegister Access

Sign in to save progress

Practice this lessonReport an error

See also

  • Why a Register Model: Desired, Mirrored and the DUT
  • Blocks, Registers, Fields and Memories
  • Maps, Offsets and Endianness