module memory_3(dout,err,addr,size,we,din,clk);
   input [31:0] addr;
   input [1:0]  size;
   input        we;
   input [31:0] din;
   input        clk;
   output [31:0] dout;
   output [2:0]  err;

   reg [31:0]    dout;
   reg [2:0]     err;

   parameter     text_base = 'h400000;
   parameter     text_size = 'h100;
   parameter     data_base = 'h10010000;
   parameter     data_size = 'h100;

   parameter     err_none = 0;
   parameter     err_bus  = 1;   // Bad alignment.
   parameter     err_seg  = 2;   // Bad address.

   reg [31:0]    storage [0:(text_size+data_size)>>2];
   reg [31:0]    saddr, mask, rd;
   reg [4:0]     amt;

   function [31:0] addr_to_saddr;
      input [31:0] a;

      if( a >= text_base && a < text_base + text_size ) begin
         addr_to_saddr = a - text_base >> 2;
      end else if( a >= data_base && a < data_base + data_size ) begin
         addr_to_saddr = a - data_base + text_size >> 2;
      end else begin
         addr_to_saddr = -1;
      end

   endfunction
   

   reg [2:0]  access_mem_err;

   function [31:0] access_mem;
      input [31:0] addr;
      input [1:0] size;
      input we;
      input [31:0] din;

      begin

         saddr = addr_to_saddr(addr);

         if( !size ) begin

            access_mem_err = err_none;
            access_mem = 0;

         end else if( saddr == -1 ) begin

            access_mem_err = err_seg;
            access_mem = 32'bz;

         end else begin

            access_mem_err  = addr << 3 - size & 3 ? err_bus : err_none;
            amt  = 3 - addr[1:0] - { &size, size[1] } << 3;
            mask = ( ( 1 << ( 8 << (size-1) ) ) - 1 ) << amt;
            rd   = storage[ saddr ];
            access_mem = err == err_bus ? 32'bzx : ( rd & mask ) >> amt;

            if( we ) storage[ saddr ] = ( rd & ~mask ) | ( (din<<amt ) & mask );

         end

      end

   endfunction

   function [31:0] peek_word;
      input [31:0] peek_addr;

      peek_word = access_mem(peek_addr,3,0,0);

   endfunction

   function [2:0] poke_word;
      input [31:0] poke_addr;
      input [31:0] poke_data;

      reg [31:0] dummy;

      begin
         dummy = access_mem(poke_addr,3,1,poke_data);
         poke_word = access_mem_err;
      end

   endfunction

   always @( negedge clk ) begin
      dout = access_mem(addr,size,we,din);
      err = access_mem_err;
   end


endmodule