/**********************************************************************
 * $dump_mem_hex and $fill_mem example -- Verilog HDL test bench.
 *
 * Verilog test bench to test the $dump_mem_hex, $dump_mem_ascii
 * and $fill_mem PLI applications.
 *
 * For the book, "The Verilog PLI Handbook" by Stuart Sutherland
 *  Book copyright 1999, Kluwer Academic Publishers, Norwell, MA, USA
 *   Contact: www.wkap.il
 *  Example copyright 1998, Sutherland HDL Inc, Portland, Oregon, USA
 *   Contact: www.sutherland.com or (503) 692-0898
 *********************************************************************/
`timescale 1ns / 1ns 
module dump_mem_test;

  parameter LEFT_BIT = 23, RIGHT_BIT = 00, FIRST_ADDR = 0, LAST_ADDR = 3;
//  parameter LEFT_BIT = 00, RIGHT_BIT = 23, FIRST_ADDR = 0, LAST_ADDR = 3;
//  parameter LEFT_BIT = 23, RIGHT_BIT = 00, FIRST_ADDR = 3, LAST_ADDR = 0;
//  parameter LEFT_BIT = 00, RIGHT_BIT = 23, FIRST_ADDR = 3, LAST_ADDR = 0;
//  parameter LEFT_BIT = 24, RIGHT_BIT = 01, FIRST_ADDR = 0, LAST_ADDR = 3;
//  parameter LEFT_BIT = 01, RIGHT_BIT = 24, FIRST_ADDR = 0, LAST_ADDR = 3;
//  parameter LEFT_BIT = 23, RIGHT_BIT = 00, FIRST_ADDR = 1, LAST_ADDR = 4;
//  parameter LEFT_BIT = 23, RIGHT_BIT = 00, FIRST_ADDR = 4, LAST_ADDR = 1;

  reg  [LEFT_BIT:RIGHT_BIT] RAM [FIRST_ADDR:LAST_ADDR];

  integer addr;
  wire [23:0] vector1, vector2;

  initial
    begin
      $display("Loading memory from Verilog HDL...\n");
      fill_mem("Hello world!");
      #1 dump_mem_hex;
      #1 dump_mem_ascii;
      $display("Accessing memory using $dump_mem...\n");
      $dump_mem_hex(RAM[FIRST_ADDR]); /* address ignored by PLI */
      $dump_mem_ascii(RAM[FIRST_ADDR]);

      $display("\nModifying memory using $fill_mem...\n");
      $fill_mem(RAM[FIRST_ADDR], FIRST_ADDR);
      #1 dump_mem_hex;
      $dump_mem_hex(RAM[FIRST_ADDR]);
      #10 $finish;
    end

  assign vector1 = RAM[FIRST_ADDR];
  always @(vector1)
    $display("\nRAM[%0d] just changed to %h\n", FIRST_ADDR, RAM[FIRST_ADDR]);

  assign vector2 = RAM[LAST_ADDR];
  always @(vector2)
    $display("\nRAM[%0d] just changed to %h\n", LAST_ADDR, RAM[LAST_ADDR]);


  task dump_mem_ascii;
    begin
      $write("Within Verilog:\n Memory contents in ASCII are:\n   ");
      if (FIRST_ADDR < LAST_ADDR)
        for (addr=FIRST_ADDR; addr<=LAST_ADDR; addr=addr+1)
          $write("%s", RAM[addr]);
      else
        for (addr=FIRST_ADDR; addr>=LAST_ADDR; addr=addr-1)
          $write("%s", RAM[addr]);
      $display("\n");           //terminate dump string
    end
  endtask

  task dump_mem_hex;
    begin
      $display("Within Verilog:\n Memory contents in hex are:");
      if (FIRST_ADDR < LAST_ADDR)
        for (addr=FIRST_ADDR; addr<=LAST_ADDR; addr=addr+1)
          $display("   address %0d:\t %h", addr, RAM[addr]);
      else
        for (addr=FIRST_ADDR; addr>=LAST_ADDR; addr=addr-1)
          $display("   address %0d:\t %h", addr, RAM[addr]);
    end
  endtask

  task fill_mem; /* assumes at least 4 words, each word at least 24 bits wide */
    input [(20*8)-1:0] string; /* input for 20 ASCII characters */
    begin
      if (FIRST_ADDR < LAST_ADDR)
        begin
          if (   (LEFT_BIT - RIGHT_BIT) !== 23
              && (RIGHT_BIT - LEFT_BIT) !== 23 )
            disable fill_mem;  /* abort if word is not 24 bits wide */
          RAM[FIRST_ADDR+3] = string[23: 0];
          RAM[FIRST_ADDR+2] = string[47:24];
          RAM[FIRST_ADDR+1] = string[71:48];
          RAM[FIRST_ADDR+0] = string[95:72];
        end
      else
        begin
          if (   (LEFT_BIT - RIGHT_BIT) !== 23
              && (RIGHT_BIT - LEFT_BIT) !== 23 )
            disable fill_mem;  /* abort if word is not 24 bits wide */
          RAM[FIRST_ADDR-3] = string[23: 0];
          RAM[FIRST_ADDR-2] = string[47:24];
          RAM[FIRST_ADDR-1] = string[71:48];
          RAM[FIRST_ADDR-0] = string[95:72];
        end
    end
  endtask

endmodule


[ [ ['module', 'dump_mem_test', ';'],
    [ [ 'parameter',
        ['LEFT_BIT', '=', '23'],
        ['RIGHT_BIT', '=', '00'],
        ['FIRST_ADDR', '=', '0'],
        ['LAST_ADDR', '=', '3'],
        ';'],
      [ 'reg',
        '[',
        ['LEFT_BIT'],
        ':',
        ['RIGHT_BIT'],
        ']',
        ['RAM', '[', ['FIRST_ADDR'], ':', ['LAST_ADDR'], ']'],
        ';'],
      ['integer', ['addr'], ';'],
      ['wire', '[', '23', ':', '0', ']', ['vector1', 'vector2'], ';'],
      [ 'initial',
        [ 'begin',
          [ [ '$display',
              '(',
              '"Loading memory from Verilog HDL...\\n"',
              ')',
              ';'],
            ['fill_mem', '(', '"Hello world!"', ')', ';'],
            [['#', '1'], ['dump_mem_hex', ';']],
            [['#', '1'], ['dump_mem_ascii', ';']],
            [ '$display',
              '(',
              '"Accessing memory using $dump_mem...\\n"',
              ')',
              ';'],
            [ '$dump_mem_hex',
              '(',
              ['RAM', '[', ['FIRST_ADDR'], ']'],
              ')',
              ';'],
            [ '$dump_mem_ascii',
              '(',
              ['RAM', '[', ['FIRST_ADDR'], ']'],
              ')',
              ';'],
            [ '$display',
              '(',
              '"\\nModifying memory using $fill_mem...\\n"',
              ')',
              ';'],
            [ '$fill_mem',
              '(',
              ['RAM', '[', ['FIRST_ADDR'], ']'],
              ['FIRST_ADDR'],
              ')',
              ';'],
            [['#', '1'], ['dump_mem_hex', ';']],
            [ '$dump_mem_hex',
              '(',
              ['RAM', '[', ['FIRST_ADDR'], ']'],
              ')',
              ';'],
            [['#', '10'], ['$finish', ';']]],
          'end']],
      ['assign', [['vector1'], '=', ['RAM', '[', ['FIRST_ADDR'], ']']], ';'],
      [ 'always',
        ['@', '(', [['vector1']], ')'],
        [ '$display',
          '(',
          '"\\nRAM[%0d] just changed to %h\\n"',
          ['FIRST_ADDR'],
          ['RAM', '[', ['FIRST_ADDR'], ']'],
          ')',
          ';']],
      ['assign', [['vector2'], '=', ['RAM', '[', ['LAST_ADDR'], ']']], ';'],
      [ 'always',
        ['@', '(', [['vector2']], ')'],
        [ '$display',
          '(',
          '"\\nRAM[%0d] just changed to %h\\n"',
          ['LAST_ADDR'],
          ['RAM', '[', ['LAST_ADDR'], ']'],
          ')',
          ';']],
      [ 'task',
        'dump_mem_ascii',
        ';',
        [ 'begin',
          [ [ '$write',
              '(',
              '"Within Verilog:\\n Memory contents in ASCII are:\\n   "',
              ')',
              ';'],
            [ 'if',
              ['(', ['FIRST_ADDR'], '<', ['LAST_ADDR'], ')'],
              [ 'for',
                '(',
                [['addr'], '=', ['FIRST_ADDR']],
                ';',
                [['addr'], '<=', ['LAST_ADDR']],
                ';',
                [['addr'], '=', ['addr'], '+', '1'],
                ')',
                [ '$write',
                  '(',
                  '"%s"',
                  ['RAM', '[', ['addr'], ']'],
                  ')',
                  ';']],
              'else',
              [ 'for',
                '(',
                [['addr'], '=', ['FIRST_ADDR']],
                ';',
                [['addr'], '>=', ['LAST_ADDR']],
                ';',
                [['addr'], '=', ['addr'], '-', '1'],
                ')',
                [ '$write',
                  '(',
                  '"%s"',
                  ['RAM', '[', ['addr'], ']'],
                  ')',
                  ';']]],
            ['$display', '(', '"\\n"', ')', ';']],
          'end'],
        'endtask'],
      [ 'task',
        'dump_mem_hex',
        ';',
        [ 'begin',
          [ [ '$display',
              '(',
              '"Within Verilog:\\n Memory contents in hex are:"',
              ')',
              ';'],
            [ 'if',
              ['(', ['FIRST_ADDR'], '<', ['LAST_ADDR'], ')'],
              [ 'for',
                '(',
                [['addr'], '=', ['FIRST_ADDR']],
                ';',
                [['addr'], '<=', ['LAST_ADDR']],
                ';',
                [['addr'], '=', ['addr'], '+', '1'],
                ')',
                [ '$display',
                  '(',
                  '"   address %0d:\\t %h"',
                  ['addr'],
                  ['RAM', '[', ['addr'], ']'],
                  ')',
                  ';']],
              'else',
              [ 'for',
                '(',
                [['addr'], '=', ['FIRST_ADDR']],
                ';',
                [['addr'], '>=', ['LAST_ADDR']],
                ';',
                [['addr'], '=', ['addr'], '-', '1'],
                ')',
                [ '$display',
                  '(',
                  '"   address %0d:\\t %h"',
                  ['addr'],
                  ['RAM', '[', ['addr'], ']'],
                  ')',
                  ';']]]],
          'end'],
        'endtask'],
      [ 'task',
        'fill_mem',
        ';',
        [ 'input',
          '[',
          '(',
          ['20', '*', '8'],
          ')',
          '-',
          '1',
          ':',
          '0',
          ']',
          'string',
          ';'],
        [ 'begin',
          [ [ 'if',
              ['(', ['FIRST_ADDR'], '<', ['LAST_ADDR'], ')'],
              [ 'begin',
                [ [ 'if',
                    [ '(',
                      '(',
                      [['LEFT_BIT'], '-', ['RIGHT_BIT']],
                      ')',
                      '!==',
                      '23',
                      '&&',
                      '(',
                      [['RIGHT_BIT'], '-', ['LEFT_BIT']],
                      ')',
                      '!==',
                      '23',
                      ')'],
                    ['disable', 'fill_mem', ';']],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '+', '3', ']'],
                      '=',
                      ['string', '[', '23', '0', ']']],
                    ';'],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '+', '2', ']'],
                      '=',
                      ['string', '[', '47', '24', ']']],
                    ';'],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '+', '1', ']'],
                      '=',
                      ['string', '[', '71', '48', ']']],
                    ';'],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '+', '0', ']'],
                      '=',
                      ['string', '[', '95', '72', ']']],
                    ';']],
                'end'],
              'else',
              [ 'begin',
                [ [ 'if',
                    [ '(',
                      '(',
                      [['LEFT_BIT'], '-', ['RIGHT_BIT']],
                      ')',
                      '!==',
                      '23',
                      '&&',
                      '(',
                      [['RIGHT_BIT'], '-', ['LEFT_BIT']],
                      ')',
                      '!==',
                      '23',
                      ')'],
                    ['disable', 'fill_mem', ';']],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '-', '3', ']'],
                      '=',
                      ['string', '[', '23', '0', ']']],
                    ';'],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '-', '2', ']'],
                      '=',
                      ['string', '[', '47', '24', ']']],
                    ';'],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '-', '1', ']'],
                      '=',
                      ['string', '[', '71', '48', ']']],
                    ';'],
                  [ [ ['RAM', '[', ['FIRST_ADDR'], '-', '0', ']'],
                      '=',
                      ['string', '[', '95', '72', ']']],
                    ';']],
                'end']]],
          'end'],
        'endtask']],
    'endmodule']]
