fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 855 lines 18 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/cpu/arm/mmu.c * 7 * Created: 2004-11-03 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2004-2011 Hampa Hug <hampa@hampa.ch> * 9 * Copyright: (C) 2004-2006 Lukas Ruf <ruf@lpr.ch> * 10 *****************************************************************************/ 11 12/***************************************************************************** 13 * This program is free software. You can redistribute it and / or modify it * 14 * under the terms of the GNU General Public License version 2 as published * 15 * by the Free Software Foundation. * 16 * * 17 * This program is distributed in the hope that it will be useful, but * 18 * WITHOUT ANY WARRANTY, without even the implied warranty of * 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 20 * Public License for more details. * 21 *****************************************************************************/ 22 23/***************************************************************************** 24 * This software was developed at the Computer Engineering and Networks * 25 * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. * 26 *****************************************************************************/ 27 28 29#include <stdio.h> 30#include <stdlib.h> 31 32#include "arm.h" 33#include "internal.h" 34 35 36#if defined(PCE_HOST_PPC) || defined (PCE_HOST_SPARC) 37#define ARM_HOST_BE 38#endif 39 40#if defined(PCE_HOST_IA32) 41#define ARM_HOST_LE 42#endif 43 44 45static 46void arm_mmu_fault (arm_t *c, uint32_t addr, unsigned status, unsigned domn) 47{ 48 arm_copr15_t *mmu; 49 50 mmu = arm_get_mmu (c); 51 52 mmu->reg[6] = addr; 53 mmu->reg[5] = ((domn & 0x0f) << 4) | (status & 0x0f); 54 55 arm_exception_data_abort (c); 56} 57 58static 59void arm_mmu_translation_fault (arm_t *c, uint32_t addr, unsigned domn, int sect) 60{ 61 arm_mmu_fault (c, addr, sect ? 0x05 : 0x07, domn); 62} 63 64static 65void arm_mmu_domain_fault (arm_t *c, uint32_t addr, unsigned domn, int sect) 66{ 67 arm_mmu_fault (c, addr, sect ? 0x09 : 0x0b, domn); 68} 69 70static 71void arm_mmu_permission_fault (arm_t *c, uint32_t addr, unsigned domn, int sect) 72{ 73 arm_mmu_fault (c, addr, sect ? 0x0d : 0x0f, domn); 74} 75 76 77static inline 78void arm_tbuf_set (arm_tbuf_t *tb, uint32_t vaddr, uint32_t raddr, uint32_t mask) 79{ 80 tb->vaddr = vaddr & mask; 81 tb->vmask = mask; 82 tb->raddr = raddr & mask; 83 tb->rmask = ~mask; 84 tb->valid = 1; 85} 86 87 88/*!*************************************************************************** 89 * @short Check access permissions for reading 90 * @param cr The control register (coprocessor 15 register 1) 91 * @param perm The page or section permission bits 92 * @param priv Check for privileged access if true 93 * @return Zero if access violation, non-zero if ok 94 *****************************************************************************/ 95static 96int arm_mmu_check_perm_read (uint32_t cr, unsigned perm, int priv) 97{ 98 if (perm == 0) { 99 switch (cr & (ARM_C15_CR_S | ARM_C15_CR_R)) { 100 case 0x00: /* no access */ 101 return (0); 102 103 case ARM_C15_CR_S: /* priv: read only, user: no access */ 104 return (priv); 105 106 case ARM_C15_CR_R: /* read only */ 107 return (1); 108 109 case ARM_C15_CR_S | ARM_C15_CR_R: /* undefined */ 110 return (0); 111 } 112 113 return (0); 114 } 115 116 if (priv) { 117 return (1); 118 } 119 120 switch (perm) { 121 case 0x01: /* no access */ 122 return (0); 123 124 case 0x02: /* read only */ 125 return (1); 126 127 case 0x03: /* read/write */ 128 return (1); 129 } 130 131 return (0); 132} 133 134/*!*************************************************************************** 135 * @short Check access permissions for writing 136 * @param cr The control register (coprocessor 15 register 1) 137 * @param perm The page or section permission bits 138 * @param priv Check for privileged access if true 139 * @return Zero if access violation, non-zero if ok 140 *****************************************************************************/ 141static 142int arm_mmu_check_perm_write (uint32_t cr, unsigned perm, int priv) 143{ 144 if (perm == 0) { 145 switch (cr & (ARM_C15_CR_S | ARM_C15_CR_R)) { 146 case 0x00: /* no access */ 147 return (0); 148 149 case ARM_C15_CR_S: /* priv: read only, user: no access */ 150 return (0); 151 152 case ARM_C15_CR_R: /* read only */ 153 return (0); 154 155 case ARM_C15_CR_S | ARM_C15_CR_R: /* undefined */ 156 return (0); 157 } 158 159 return (0); 160 } 161 162 if (priv) { 163 return (1); 164 } 165 166 switch (perm) { 167 case 0x01: /* no access */ 168 return (0); 169 170 case 0x02: /* read only */ 171 return (0); 172 173 case 0x03: /* read/write */ 174 return (1); 175 } 176 177 return (0); 178} 179 180/*!*************************************************************************** 181 * @short Translate a virtual address 182 * @param c The ARM context 183 * @param addr Virtual address input, real address output 184 * @retval domn Returns the domain number 185 * @retval perm The page or section permission bits 186 * @retval sect The virtual address is in a section if true, in a page if false 187 * @return Non-zero on translation fault 188 *****************************************************************************/ 189static 190int arm_translate (arm_t *c, uint32_t *addr, uint32_t *mask, 191 unsigned *domn, unsigned *perm, int *sect) 192{ 193 arm_copr15_t *mmu; 194 unsigned ap; 195 uint32_t addr1, addr2; 196 uint32_t desc1, desc2; 197 198 mmu = arm_get_mmu (c); 199 200 addr1 = (mmu->reg[2] & 0xffffc000) | ((*addr >> 18) & 0x00003ffc); 201 desc1 = c->get_uint32 (c->mem_ext, addr1); 202 203 addr2 = 0; 204 205 switch (desc1 & 0x03) { 206 case 0x00: 207 /* section translation fault */ 208 *mask = 0; 209 *domn = 0; 210 *sect = 1; 211 return (1); 212 213 case 0x01: 214 /* coarse */ 215 addr2 = (desc1 & 0xfffffc00) | ((*addr >> 10) & 0x000003fc); 216 *domn = arm_get_bits (desc1, 5, 4); 217 break; 218 219 case 0x02: 220 /* section */ 221 *addr = (desc1 & 0xfff00000) | (*addr & 0x000fffff); 222 *mask = 0xfff00000; 223 *domn = arm_get_bits (desc1, 5, 4); 224 *perm = arm_get_bits (desc1, 10, 2); 225 *sect = 1; 226 return (0); 227 228 case 0x03: 229 /* fine */ 230 addr2 = (desc1 & 0xfffff000) | ((*addr >> 8) & 0x00000ffc); 231 *domn = arm_get_bits (desc1, 5, 4); 232 break; 233 } 234 235 desc2 = c->get_uint32 (c->mem_ext, addr2); 236 237 *sect = 0; 238 239 switch (desc2 & 0x03) { 240 case 0x00: 241 /* page translation fault */ 242 *mask = 0; 243 *perm = 0; 244 return (1); 245 246 case 0x01: 247 /* large page */ 248 ap = 4 + 2 * arm_get_bits (*addr, 14, 2); 249 *addr = (desc2 & 0xffff0000) | (*addr & 0x0000ffff); 250 *mask = 0xffff0000; 251 *perm = arm_get_bits (desc2, ap, 2); 252 return (0); 253 254 case 0x02: 255 /* small page */ 256 ap = 4 + 2 * arm_get_bits (*addr, 10, 2); 257 *addr = (desc2 & 0xfffff000) | (*addr & 0x00000fff); 258 *mask = 0xfffff000; 259 *perm = arm_get_bits (desc2, ap, 2); 260 return (0); 261 262 case 0x03: 263 if ((desc1 & 0x03) == 0x01) { 264 /* xscale extended small page */ 265 *addr = (desc2 & 0xfffff000) | (*addr & 0x00000fff); 266 *mask = 0xfffff000; 267 *perm = arm_get_bits (desc2, 4, 2); 268 return (0); 269 } 270 271 /* tiny page */ 272 *perm = arm_get_bits (desc2, 4, 2); 273 *addr = (desc2 & 0xfffffc00) | (*addr & 0x000003ff); 274 *mask = 0xfffffc00; 275 return (0); 276 } 277 278 /* non-reachable */ 279 280 *perm = 0; 281 282 return (1); 283} 284 285static 286int arm_translate_exec (arm_t *c, uint32_t *addr, int priv) 287{ 288 arm_copr15_t *mmu; 289 unsigned domn, perm; 290 int sect; 291 uint32_t vaddr, mask; 292 293 mmu = arm_get_mmu (c); 294 295 if ((mmu->reg[1] & ARM_C15_CR_M) == 0) { 296 return (0); 297 } 298 299 vaddr = *addr; 300 301 if (mmu->tbuf_exec.valid) { 302 arm_tbuf_t *tb = &mmu->tbuf_exec; 303 304 if ((vaddr & tb->vmask) == tb->vaddr) { 305 *addr = tb->raddr | (vaddr & tb->rmask); 306 return (0); 307 } 308 } 309 310 if (arm_translate (c, addr, &mask, &domn, &perm, &sect)) { 311 arm_exception_prefetch_abort (c); 312 return (1); 313 } 314 315 /* check domain */ 316 switch ((mmu->reg[3] >> (2 * domn)) & 0x03) { 317 case 0x00: /* no access */ 318 arm_mmu_domain_fault (c, vaddr, domn, sect); 319 return (1); 320 321 case 0x01: /* client */ 322 if (arm_mmu_check_perm_read (mmu->reg[1], perm, priv) == 0) { 323 arm_exception_prefetch_abort (c); 324 return (1); 325 } 326 arm_tbuf_set (&mmu->tbuf_exec, vaddr, *addr, mask); 327 return (0); 328 329 case 0x02: /* undefined */ 330 return (0); 331 332 case 0x03: /* manager */ 333 arm_tbuf_set (&mmu->tbuf_exec, vaddr, *addr, mask); 334 return (0); 335 } 336 337 return (0); 338} 339 340static 341int arm_translate_read (arm_t *c, uint32_t *addr, int priv) 342{ 343 arm_copr15_t *mmu; 344 unsigned domn, perm; 345 int sect; 346 uint32_t vaddr, mask; 347 348 mmu = arm_get_mmu (c); 349 350 if ((mmu->reg[1] & ARM_C15_CR_M) == 0) { 351 return (0); 352 } 353 354 vaddr = *addr; 355 356 if (mmu->tbuf_read.valid) { 357 arm_tbuf_t *tb = &mmu->tbuf_read; 358 359 if ((vaddr & tb->vmask) == tb->vaddr) { 360 *addr = tb->raddr | (vaddr & tb->rmask); 361 return (0); 362 } 363 } 364 365 if (arm_translate (c, addr, &mask, &domn, &perm, &sect)) { 366 arm_mmu_translation_fault (c, vaddr, domn, sect); 367 return (1); 368 } 369 370 /* check domain */ 371 switch ((mmu->reg[3] >> (2 * domn)) & 0x03) { 372 case 0x00: /* no access */ 373 arm_mmu_domain_fault (c, vaddr, domn, sect); 374 return (1); 375 376 case 0x01: /* client */ 377 if (arm_mmu_check_perm_read (mmu->reg[1], perm, priv) == 0) { 378 arm_mmu_permission_fault (c, vaddr, domn, sect); 379 return (1); 380 } 381 arm_tbuf_set (&mmu->tbuf_read, vaddr, *addr, mask); 382 return (0); 383 384 case 0x02: /* undefined */ 385 return (0); 386 387 case 0x03: /* manager */ 388 arm_tbuf_set (&mmu->tbuf_read, vaddr, *addr, mask); 389 return (0); 390 } 391 392 return (0); 393} 394 395static 396int arm_translate_write (arm_t *c, uint32_t *addr, int priv) 397{ 398 arm_copr15_t *mmu; 399 unsigned domn, perm; 400 int sect; 401 uint32_t vaddr, mask; 402 403 mmu = arm_get_mmu (c); 404 405 if ((mmu->reg[1] & ARM_C15_CR_M) == 0) { 406 return (0); 407 } 408 409 vaddr = *addr; 410 411 if (mmu->tbuf_write.valid) { 412 arm_tbuf_t *tb = &mmu->tbuf_write; 413 414 if ((vaddr & tb->vmask) == tb->vaddr) { 415 *addr = tb->raddr | (vaddr & tb->rmask); 416 return (0); 417 } 418 } 419 420 if (arm_translate (c, addr, &mask, &domn, &perm, &sect)) { 421 arm_mmu_translation_fault (c, vaddr, domn, sect); 422 return (1); 423 } 424 425 /* check domain */ 426 switch ((mmu->reg[3] >> (2 * domn)) & 0x03) { 427 case 0x00: /* no access */ 428 arm_mmu_domain_fault (c, vaddr, domn, sect); 429 return (1); 430 431 case 0x01: /* client */ 432 if (arm_mmu_check_perm_write (mmu->reg[1], perm, priv) == 0) { 433 arm_mmu_permission_fault (c, vaddr, domn, sect); 434 return (1); 435 } 436 437 arm_tbuf_set (&mmu->tbuf_write, vaddr, *addr, mask); 438 439 return (0); 440 441 case 0x02: /* undefined */ 442 return (0); 443 444 case 0x03: /* manager */ 445 arm_tbuf_set (&mmu->tbuf_write, vaddr, *addr, mask); 446 return (0); 447 } 448 449 return (0); 450} 451 452/* translate without causing exceptions */ 453int arm_translate_extern (arm_t *c, uint32_t *addr, unsigned xlat, 454 unsigned *domn, unsigned *perm) 455{ 456 arm_copr15_t *mmu; 457 unsigned domn1, perm1; 458 int sect; 459 uint32_t mask; 460 461 if (domn == NULL) { 462 domn = &domn1; 463 } 464 465 if (perm == NULL) { 466 perm = &perm1; 467 } 468 469 *domn = 0; 470 *perm = 0; 471 472 if (xlat == ARM_XLAT_REAL) { 473 return (0); 474 } 475 476 mmu = arm_get_mmu (c); 477 478 if ((xlat == ARM_XLAT_CPU) && ((mmu->reg[1] & ARM_C15_CR_M) == 0)) { 479 return (0); 480 } 481 482 if (arm_translate (c, addr, &mask, domn, perm, &sect)) { 483 return (1); 484 } 485 486 return (0); 487} 488 489 490int arm_ifetch (arm_t *c, uint32_t addr, uint32_t *val) 491{ 492 uint32_t tmp; 493 494 addr &= ~0x03UL; 495 496 if (arm_translate_exec (c, &addr, arm_is_privileged (c))) { 497 return (1); 498 } 499 500 if (addr < c->ram_cnt) { 501 unsigned char *p = &c->ram[addr]; 502 503 if (c->bigendian) { 504#ifdef ARM_HOST_BE 505 tmp = *(uint32_t *)p; 506#else 507 tmp = (uint32_t) p[0] << 24; 508 tmp |= (uint32_t) p[1] << 16; 509 tmp |= (uint32_t) p[2] << 8; 510 tmp |= p[3]; 511#endif 512 } 513 else { 514#ifdef ARM_HOST_LE 515 tmp = *(uint32_t *)p; 516#else 517 tmp = p[0]; 518 tmp |= (uint32_t) p[1] << 8; 519 tmp |= (uint32_t) p[2] << 16; 520 tmp |= (uint32_t) p[3] << 24; 521#endif 522 } 523 } 524 else { 525 tmp = c->get_uint32 (c->mem_ext, addr); 526 } 527 528 *val = tmp; 529 530 return (0); 531} 532 533int arm_dload8 (arm_t *c, uint32_t addr, uint8_t *val) 534{ 535 if (arm_translate_read (c, &addr, arm_is_privileged (c))) { 536 return (1); 537 } 538 539 if (addr < c->ram_cnt) { 540 *val = c->ram[addr]; 541 } 542 else { 543 *val = c->get_uint8 (c->mem_ext, addr); 544 } 545 546 return (0); 547} 548 549int arm_dload16 (arm_t *c, uint32_t addr, uint16_t *val) 550{ 551 if (arm_translate_read (c, &addr, arm_is_privileged (c))) { 552 return (1); 553 } 554 555 if ((addr + 1) < c->ram_cnt) { 556 unsigned char *p = &c->ram[addr]; 557 558 if (c->bigendian) { 559#ifdef ARM_HOST_BE 560 *val = *(uint16_t *) p; 561#else 562 *val = ((uint16_t) p[0] << 8) | p[1]; 563#endif 564 } 565 else { 566#ifdef ARM_HOST_LE 567 *val = *(uint16_t *) p; 568#else 569 *val = ((uint16_t) p[1] << 8) | p[0]; 570#endif 571 } 572 } 573 else { 574 *val = c->get_uint16 (c->mem_ext, addr); 575 } 576 577 return (0); 578} 579 580int arm_dload32 (arm_t *c, uint32_t addr, uint32_t *val) 581{ 582 if (arm_translate_read (c, &addr, arm_is_privileged (c))) { 583 return (1); 584 } 585 586 if ((addr + 3) < c->ram_cnt) { 587 unsigned char *p = &c->ram[addr]; 588 589 if (c->bigendian) { 590#ifdef ARM_HOST_BE 591 *val = *(uint32_t *) p; 592#else 593 *val = (uint32_t) p[0] << 24; 594 *val |= (uint32_t) p[1] << 16; 595 *val |= (uint32_t) p[2] << 8; 596 *val |= p[3]; 597#endif 598 } 599 else { 600#ifdef ARM_HOST_LE 601 *val = *(uint32_t *) p; 602#else 603 *val = p[0]; 604 *val |= (uint32_t) p[1] << 8; 605 *val |= (uint32_t) p[2] << 16; 606 *val |= (uint32_t) p[3] << 24; 607#endif 608 } 609 } 610 else { 611 *val = c->get_uint32 (c->mem_ext, addr); 612 } 613 614 return (0); 615} 616 617int arm_dstore8 (arm_t *c, uint32_t addr, uint8_t val) 618{ 619 if (arm_translate_write (c, &addr, arm_is_privileged (c))) { 620 return (1); 621 } 622 623 if (addr < c->ram_cnt) { 624 c->ram[addr] = val; 625 } 626 else { 627 c->set_uint8 (c->mem_ext, addr, val); 628 } 629 630 return (0); 631} 632 633int arm_dstore16 (arm_t *c, uint32_t addr, uint16_t val) 634{ 635 if (arm_translate_write (c, &addr, arm_is_privileged (c))) { 636 return (1); 637 } 638 639 if ((addr + 1) < c->ram_cnt) { 640 unsigned char *p = &c->ram[addr]; 641 642 if (c->bigendian) { 643#ifdef ARM_HOST_BE 644 *(uint16_t *) p = val; 645#else 646 p[0] = (val >> 8) & 0xff; 647 p[1] = val & 0xff; 648#endif 649 } 650 else { 651#ifdef ARM_HOST_LE 652 *(uint16_t *) p = val; 653#else 654 p[0] = val & 0xff; 655 p[1] = (val >> 8) & 0xff; 656#endif 657 } 658 } 659 else { 660 c->set_uint16 (c->mem_ext, addr, val); 661 } 662 663 return (0); 664} 665 666int arm_dstore32 (arm_t *c, uint32_t addr, uint32_t val) 667{ 668 if (arm_translate_write (c, &addr, arm_is_privileged (c))) { 669 return (1); 670 } 671 672 if ((addr + 3) < c->ram_cnt) { 673 unsigned char *p = &c->ram[addr]; 674 675 if (c->bigendian) { 676#ifdef ARM_HOST_BE 677 *(uint32_t *) p = val; 678#else 679 p[0] = (val >> 24) & 0xff; 680 p[1] = (val >> 16) & 0xff; 681 p[2] = (val >> 8) & 0xff; 682 p[3] = val & 0xff; 683#endif 684 } 685 else { 686#ifdef ARM_HOST_LE 687 *(uint32_t *) p = val; 688#else 689 p[0] = val & 0xff; 690 p[1] = (val >> 8) & 0xff; 691 p[2] = (val >> 16) & 0xff; 692 p[3] = (val >> 24) & 0xff; 693#endif 694 } 695 } 696 else { 697 c->set_uint32 (c->mem_ext, addr, val); 698 } 699 700 return (0); 701} 702 703int arm_dload8_t (arm_t *c, uint32_t addr, uint8_t *val) 704{ 705 if (arm_translate_read (c, &addr, 0)) { 706 return (1); 707 } 708 709 *val = c->get_uint8 (c->mem_ext, addr); 710 711 return (0); 712} 713 714int arm_dload16_t (arm_t *c, uint32_t addr, uint16_t *val) 715{ 716 if (arm_translate_read (c, &addr, 0)) { 717 return (1); 718 } 719 720 *val = c->get_uint16 (c->mem_ext, addr); 721 722 return (0); 723} 724 725int arm_dload32_t (arm_t *c, uint32_t addr, uint32_t *val) 726{ 727 if (arm_translate_read (c, &addr, 0)) { 728 return (1); 729 } 730 731 *val = c->get_uint32 (c->mem_ext, addr); 732 733 return (0); 734} 735 736int arm_dstore8_t (arm_t *c, uint32_t addr, uint8_t val) 737{ 738 if (arm_translate_write (c, &addr, 0)) { 739 return (1); 740 } 741 742 c->set_uint8 (c->mem_ext, addr, val); 743 744 return (0); 745} 746 747int arm_dstore16_t (arm_t *c, uint32_t addr, uint16_t val) 748{ 749 if (arm_translate_write (c, &addr, 0)) { 750 return (1); 751 } 752 753 c->set_uint16 (c->mem_ext, addr, val); 754 755 return (0); 756} 757 758int arm_dstore32_t (arm_t *c, uint32_t addr, uint32_t val) 759{ 760 if (arm_translate_write (c, &addr, 0)) { 761 return (1); 762 } 763 764 c->set_uint32 (c->mem_ext, addr, val); 765 766 return (0); 767} 768 769 770int arm_get_mem8 (arm_t *c, uint32_t addr, unsigned xlat, uint8_t *val) 771{ 772 if (arm_translate_extern (c, &addr, xlat, NULL, NULL)) { 773 return (1); 774 } 775 776 if (c->get_uint8 != NULL) { 777 *val = c->get_uint8 (c->mem_ext, addr); 778 } 779 else { 780 *val = 0xff; 781 } 782 783 return (0); 784} 785 786int arm_get_mem16 (arm_t *c, uint32_t addr, unsigned xlat, uint16_t *val) 787{ 788 if (arm_translate_extern (c, &addr, xlat, NULL, NULL)) { 789 return (1); 790 } 791 792 if (c->get_uint16 != NULL) { 793 *val = c->get_uint16 (c->mem_ext, addr); 794 } 795 else { 796 *val = 0xffff; 797 } 798 799 return (0); 800} 801 802int arm_get_mem32 (arm_t *c, uint32_t addr, unsigned xlat, uint32_t *val) 803{ 804 if (arm_translate_extern (c, &addr, xlat, NULL, NULL)) { 805 return (1); 806 } 807 808 if (c->get_uint32 != NULL) { 809 *val = c->get_uint32 (c->mem_ext, addr); 810 } 811 else { 812 *val = 0xffffffff; 813 } 814 815 return (0); 816} 817 818int arm_set_mem8 (arm_t *c, uint32_t addr, unsigned xlat, uint8_t val) 819{ 820 if (arm_translate_extern (c, &addr, xlat, NULL, NULL)) { 821 return (1); 822 } 823 824 if (c->set_uint8 != NULL) { 825 c->set_uint8 (c->mem_ext, addr, val); 826 } 827 828 return (0); 829} 830 831int arm_set_mem16 (arm_t *c, uint32_t addr, unsigned xlat, uint16_t val) 832{ 833 if (arm_translate_extern (c, &addr, xlat, NULL, NULL)) { 834 return (1); 835 } 836 837 if (c->set_uint16 != NULL) { 838 c->set_uint16 (c->mem_ext, addr, val); 839 } 840 841 return (0); 842} 843 844int arm_set_mem32 (arm_t *c, uint32_t addr, unsigned xlat, uint32_t val) 845{ 846 if (arm_translate_extern (c, &addr, xlat, NULL, NULL)) { 847 return (1); 848 } 849 850 if (c->set_uint32 != NULL) { 851 c->set_uint32 (c->mem_ext, addr, val); 852 } 853 854 return (0); 855}