Advertisement
ISSOtm

Game Boy CRC16 routine

Oct 13th, 2018
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; Context:
  2. ; - CRCs are stored little-endian starting at $0150
  3. ; - One CRC is computed per ROM bank
  4. ; - Assumes at most 256 ROM banks
  5. ; - Switches to an invalid ROM bank at the end, but it's harmless since the ROM is not accessed
  6. ; - Uses `rst bankswitch` to switch ROM banks, but that can be replaced with whatever you want
  7. ; - Uses $D000 - $D1FF as precomputation tables, but you can move this anywhere (storing it in ROM is probably a bad idea)
  8. ; - Stores results at $C000 - $C0XX; for ROM bank $RR, the byte at $C0RR will be set to 0 if the CRC check succeeded, or be set to $AF if the check failed
  9. ; - Clobbers every register known to mankind
  10.  
  11. wCRCSuccess   equ $C000
  12. wCRCLowTable  equ $D000
  13. wCRCHighTable equ $D100
  14.  
  15. CRCs          equ $0150
  16. CRCsEnd       equ $0150 + 2 * NB_ROM_BANKS
  17.  
  18.  
  19.     ; Perform CRC verification
  20. CRC_POLYNOM   equ $1021
  21.  
  22.     ; Compute CRC table to speed up later calculations
  23.     ld de, wCRCHighTable
  24. .computeCRCTable
  25.     ld h, e
  26.     ld l, 0
  27.     ld c, 8
  28. .bitLoop
  29.     add hl, hl
  30.     jr nc, .bitClear
  31.     ld a, l
  32.     xor LOW(CRC_POLYNOM)
  33.     ld l, a
  34.     ld a, h
  35.     xor HIGH(CRC_POLYNOM)
  36.     ld h, a
  37. .bitClear
  38.     dec c
  39.     jr nz, .bitLoop
  40.     dec d
  41.     ld a, l
  42.     ld [de], a
  43.     inc d
  44.     ld a, h
  45.     ld [de], a
  46.     inc e
  47.     jr nz, .computeCRCTable
  48.  
  49.     ld hl, $0000
  50.     ld c, l ; ld c, 0 ; Low byte of pointer to result
  51. .CRCLoop
  52.     ld b, $FF ; CRC low
  53.     ld e, b ; lb de, HIGH(wCRCHighTable), $FF ; CRC high & pointer to table
  54.     jr .feedByte ; Skip "skip hack"
  55. .skipBytes
  56.     ld l, LOW(CRCsEnd)
  57. .feedByte
  58.     ; Update CRC in `eb`
  59.     ld a, [hli]
  60.     xor e      ; XOR with high byte
  61.     ld e, a    ; Store back
  62.     dec d      ; Switch to low byte table
  63.     ld a, [de] ; Get low byte mask
  64.     xor b      ; XOR with low byte
  65.     ld b, a    ; Store back
  66.     inc d      ; Switch to high byte table
  67.     ld a, [de] ; Get high byte mask
  68.     xor e      ; XOR with high byte
  69.     ld e, a    ; Store back
  70.     ; Check if we should skip
  71.     ld a, h
  72.     dec a
  73.     ld a, l
  74.     jr nz, .dontSkipBytes
  75.     cp LOW($014E)
  76.     jr z, .skipBytes
  77. .dontSkipBytes
  78.     ; Check if reached end of a bank
  79.     and a
  80.     jr nz, .feedByte
  81.     ld a, h
  82.     and %111111
  83.     jr nz, .feedByte
  84.     ; Now check if the CRC matches
  85.     ; Get pointer to current
  86.     ld a, c
  87.     add a, LOW(CRCs) >> 1
  88.     add a, a
  89.     ld l, a
  90.     adc a, HIGH(CRCs)
  91.     sub l
  92.     ld h, a
  93.     ld a, [hli]
  94.     cp b
  95.     jr nz, .CRCFail
  96.     ld a, [hli]
  97.     cp e
  98.     jr z, .CRCSuccess
  99. .CRCFail
  100.     db $3E ; ld a, $AF
  101. .CRCSuccess
  102.     xor a
  103.     ld b, HIGH(wCRCSuccess)
  104.     ld [bc], a
  105.     ; Prepare next bank
  106.     ld hl, $4000
  107.     inc c
  108.     ld a, c
  109.     rst bankswitch ; Will switch to a bad bank on last iter, but that's not a problem.
  110.     ; ld a, c
  111.     cp NB_ROM_BANKS
  112.     jr nz, .CRCLoop
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement