cavelib_ram.asm 10.7 KB
Newer Older
Dennis Busch committed
1 2 3
// -----------------------
// Memory Block Operations
// -----------------------
4 5 6 7 8 9 10
// NOTE: The subroutines use self-modifying code 
//       and due to that are not safe to call again
//       before having finished during run-time.

.var subroutine_memset  = $0000
.var subroutine_memxor  = $0000
.var subroutine_memcpy  = $0000
Dennis Busch committed
11
.var subroutine_gapcpy  = $0000
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
.var subroutine_memswap = $0000

.var sm_ms_val = $0000
.var sm_ms_p0  = $0000

.var sm_mx_val = $0000
.var sm_mx_ps  = $0000
.var sm_mx_p0  = $0000

.var sm_mc_p0  = $0000
.var sm_mc_p1  = $0000

// see also "memset" further down
.pseudocommand place_subroutine_memset
{
  .if (subroutine_memset == $0000) 
  {  
    .eval subroutine_memset = *  
    .print getFilename() + ": subroutine_memset = " + address_of(subroutine_memset)
  
    loop:
    // condition code in status comes from before loop or before jmp near tail
    bne set // if high byte of count != 0
    txa
    beq done // if count == 0 
    
    set:
    .eval sm_ms_val = *+1 
    lda #$DA // load from self modifying value
    .eval sm_ms_p0 = *+1 
    sta $BEEF // store to self modifying pointer
      
    inc sm_ms_p0 // inc low byte of target pointer
    bne skipped_target_high_inc
    inc sm_ms_p0+1 // inc high byte of target pointer
    skipped_target_high_inc:
      
    // adjust count
    txa
    beq dec_high_and_low_maybe
    dex
    tya
    jmp loop
    dec_high_and_low_maybe:
    tya 
    beq done // if count == 0
    dex
    dey
    jmp loop
    done:
    rts
  }
}

// see also "memxor" further down
.pseudocommand place_subroutine_memxor
{
  .if (subroutine_memxor == $0000) 
  {  
    .eval subroutine_memxor = *  
    .print getFilename() + ": subroutine_memxor = " + address_of(subroutine_memxor)

    loop:
    // condition code in status comes from before loop or before jmp near tail
    bne set // if high byte of count != 0
    txa
    beq done // if count == 0 
    
    set:
    .eval sm_mx_ps = *+1 
    lda $DEAD // load from self modifying value
    .eval sm_mx_val = *+1 
    eor #$DE 
    .eval sm_mx_p0 = *+1
    sta $BEEF // store to self modifying pointer
    
    inc sm_mx_p0 // inc low byte of target pointer
    inc sm_mx_ps
    bne skipped_target_high_inc
    inc sm_mx_p0+1 // inc high byte of target pointer
    inc sm_mx_ps+1
    skipped_target_high_inc:
    
    // adjust count
    txa
    beq dec_high_and_low_maybe
    dex
    tya
    jmp loop
    dec_high_and_low_maybe:
    tya 
    beq done // if count == 0
    dex
    dey
    jmp loop
    done:  
    rts
  }
}

// see also "memcpy" further down
113
// see also "gapcpy" further down
Dennis Busch committed
114
// (NOTE: if you change this, also update :gapcpy which relies on this one)
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
.pseudocommand place_subroutine_memcpy
{
  .if (subroutine_memcpy == $0000) 
  {  
    .eval subroutine_memcpy = *  
    .print getFilename() + ": subroutine_memcpy = " + address_of(subroutine_memcpy)

    loop:
    // condition code in status comes from before loop or before jmp near tail
    bne set // if high byte of count != 0   
    txa
    beq done // if count == 0
    
    set:
    .eval sm_mc_p1 = *+1 
    lda $DEAD // load from self modifying pointer
    .eval sm_mc_p0 = *+1 
    sta $BEEF // store to self modifying pointer
    
    // adjust self modifying code pointers
    inc sm_mc_p1 // inc low byte of source pointer
    bne skipped_source_high_inc
    inc sm_mc_p1+1 // inc high byte of source pointer if low byte just wrapped around
    skipped_source_high_inc:
    inc sm_mc_p0 // inc low byte of target pointer
    bne skipped_target_high_inc
    inc sm_mc_p0+1 // inc high byte of target pointer if low byte just wrapped around
    skipped_target_high_inc:
    
    
    // adjust count
    txa
    beq dec_high_and_low_maybe
    dex
    tya
    jmp loop
    dec_high_and_low_maybe:
    tya 
    beq done // if count == 0
    dex
    dey
    jmp loop
    done:  
    rts
  }
}

Dennis Busch committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
// see also "memcpy" above
// see also "gapcpy" further down
.pseudocommand place_subroutine_gapcpy
{
  .if (subroutine_gapcpy == $0000) 
  {  
    .eval subroutine_gapcpy = *  
    .print getFilename() + ": subroutine_gapcpy = " + address_of(subroutine_gapcpy)
    
    .var s = cl_w0
    .var t = cl_w1
    .var sl = cl_w2
    .var tl = cl_w3
    .var c  = cl_b0
    .var bc = cl_b1 // and cl_b2
        
    lda c
    beq done
        
    go_again: 
182 183
      :fetch_pointer sm_mc_p1 : s // source and
      :fetch_pointer sm_mc_p0 : t // target updated in each iteration
Dennis Busch committed
184 185 186 187 188 189 190 191 192
        
      ldx bc
      ldy bc+1
        
      jsr subroutine_memcpy
        
      dec c
      beq done
        
193 194
      :add_words s : sl : s // skip line length in source
      :add_words t : tl : t // skip line length in target
Dennis Busch committed
195 196 197 198 199 200 201 202
        
      jmp go_again
    done:
    
    rts
  }
}

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
// see also "memswap" further down
.pseudocommand place_subroutine_memswap
{
  .if (subroutine_memswap == $0000) 
  {  
    .eval subroutine_memswap = *  
    .print getFilename() + ": subroutine_memswap = " + address_of(subroutine_memswap)

    loop:
    // condition code in status comes from before loop or before jmp near tail
    bne set // if high byte of count != 0   
    txa
    beq done // if count == 0
    
    set:
    sty cl_b0 // preserve y
    
    // swap bytes
    ldy #$00
    lda (cl_w0),y // 5
    sta cl_b1     // 3
    lda (cl_w1),y // 5
    sta (cl_w0),y // 6
    lda cl_b1     // 3
    sta (cl_w1),y // 6  
    
    ldy cl_b0 // restore y
    
    // adjust pointers
    inc cl_w0 // inc low byte of source pointer
    bne skipped_source_high_inc
    inc cl_w0+1 // inc high byte of source pointer if low byte just wrapped around
    skipped_source_high_inc:
    inc cl_w1 // inc low byte of target pointer
    bne skipped_target_high_inc
    inc cl_w1+1 // inc high byte of target pointer if low byte just wrapped around
    skipped_target_high_inc:
    
    
    // adjust count
    txa
    beq dec_high_and_low_maybe
    dex
    tya
    jmp loop
    dec_high_and_low_maybe:
    tya 
    beq done // if count == 0
    dex
    dey
    jmp loop
    done:  
    rts
  }
}

Dennis Busch committed
259 260 261 262

// target = any address expression EX-cluding immediate ones
// count = number of bytes to set as a 16bit value
// value = the 8bit value to write to each address starting at target   
263
.pseudocommand memset target : count : value 
264 265 266 267 268
{ 
  // make sure the subroutine was defined first 
  .if ( subroutine_memset == $0000 )
    .error ":memset used without :place_subroutine_memset"

269
  :fetch_pointer sm_ms_p0 : target
Dennis Busch committed
270 271
  
  lda value
272
  sta sm_ms_val
Dennis Busch committed
273
  
274 275
  ldx get_low(count)
  ldy get_high(count)
Dennis Busch committed
276
  
277
  jsr subroutine_memset
278 279 280
} 

// target = any address expression EX-cluding immediate ones
281
// count = number of bytes to modify as a 16bit value
282
// value = the 8bit value to XOR with each address starting at target   
283
.pseudocommand memxor target : count : value 
284 285 286 287 288
{ 
  // make sure the subroutine was defined first 
  .if ( subroutine_memxor == $0000 )
    .error ":memxor used without :place_subroutine_memxor"

289 290
  :fetch_pointer sm_mx_p0 : target
  :fetch_pointer sm_mx_ps : target
291 292
  
  lda value
293
  sta sm_mx_val
294
  
295 296
  ldx get_low(count)
  ldy get_high(count)
297
  
298
  jsr subroutine_memxor
Dennis Busch committed
299 300 301 302
} 

// target = any address expression EX-cluding immediate ones
// source = any address expression EX-cluding immediate ones
303
// count = number of bytes to copy as a 16bit value   
304
.pseudocommand memcpy target : source: count 
305 306 307 308 309
{ 
  // make sure the subroutine was defined first 
  .if ( subroutine_memcpy == $0000 )
    .error ":memcpy used without :place_subroutine_memcpy"

310 311
  :fetch_pointer sm_mc_p0 : target
  :fetch_pointer sm_mc_p1 : source
Dennis Busch committed
312
  
313 314
  ldx get_low(count)
  ldy get_high(count)
Dennis Busch committed
315
  
316
  jsr subroutine_memcpy
Dennis Busch committed
317 318
}

319 320 321 322 323
// this one uses subroutine_memcpy in a loop 
//
// target = any address expression EX-cluding immediate ones
// source = any address expression EX-cluding immediate ones
//    
Dennis Busch committed
324 325
// sl_length  (16 bit) = the distance between two whole lines in bytes in source (the gap)
//  b_copy    (16 bit) = the number of bytes per line to copy
326
// tl_length  (16 bit) = the distance between two whole lines in bytes in target (the gap) 
Dennis Busch committed
327
// count       (8 bit) = the number of lines(or parts of lines if b_copy<sl_length) to copy
328
.pseudocommand gapcpy target : source:  sl_length : b_copy : tl_length : count  
329 330
{ 
  // make sure the subroutine was defined first 
Dennis Busch committed
331 332
  .if ( subroutine_gapcpy == $0000 )
    .error ":gapcpy used without :subroutine_gapcpy"
333 334 335 336

  .var s = cl_w0
  .var t = cl_w1
  .var sl = cl_w2
Dennis Busch committed
337 338 339
  .var tl = cl_w3
  .var c  = cl_b0
  .var bc = cl_b1 // and cl_b2
340

341 342 343 344 345 346
  :fetch_pointer t : target
  :fetch_pointer s : source 
  :fetch_pointer sl : sl_length
  :fetch_pointer tl : tl_length
  :fetch_pointer bc : b_copy
  :set_bits c : count
347
  
Dennis Busch committed
348
  jsr subroutine_gapcpy
349 350
}

351 352 353 354 355
// target = any address expression EX-cluding immediate ones
// source = any address expression EX-cluding immediate ones
// count = number of bytes to swap as a 16bit value   
//
// clobbers cavelib zeropage vars: cl_w0, cl_w1, cl_b0, cl_b1
356
.pseudocommand memswap target : source : count 
357 358 359 360 361
{ 
  // make sure the subroutine was defined first 
  .if ( subroutine_memswap == $0000 )
    .error ":memswap used without :place_subroutine_memswap"

362 363
  :fetch_pointer cl_w0 : source
  :fetch_pointer cl_w1 : target
364
  
365 366
  ldx get_low(count)
  ldy get_high(count)
367
  
368
  jsr subroutine_memswap
369 370
}

371 372 373
// ------------------------------------------------------------------------
// special zero page versions for set and copy

374
// target = any address(in zero page)
Dennis Busch committed
375 376 377
// count = number of bytes to set as a 16bit value
// value = the 8bit value to write to each address starting at target   
// no sanity checks are made whether target+count wraps around in zp, so be careful
378
.pseudocommand zp_memset target : count : value { 
379
  lda target
Dennis Busch committed
380
  sta sm_p0+1
381
  lda value
Dennis Busch committed
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
  sta sm_p1+1
  
  ldx count
  
  loop:
  // condition code in status comes from before loop or before jmp near tail
  beq done // if count = 0 end loop
  
  set:
  sm_p1: lda #$DE // load from self modifying value
  sm_p0: sta $BE // store to self modifying pointer
  
  // adjust self modifying code pointer
  inc sm_p0+1 // inc target pointer
  
  // adjust count
  dex
  bne set // if count != 0 loop
  done:
} 

403 404
// target = any address(in zero page)
// source = any address(in zero page)
405
// count = number of bytes to copy as a 8bit value  
Dennis Busch committed
406
// no sanity checks are made whether target+count wraps around in zp, so be careful  
407
.pseudocommand zp_memcpy target : source: count { 
408
  lda target
Dennis Busch committed
409
  sta sm_p0+1
410
  lda source
Dennis Busch committed
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
  sta sm_p1+1
  
  ldx count
  
  loop:
  // condition code in status comes from before loop or before jmp near tail
  beq done // if count = 0 end loop
  
  set:
  sm_p1: lda $DE // load from self modifying pointer
  sm_p0: sta $BE // store to self modifying pointer
  
  // adjust self modifying code pointers
  inc sm_p1+1 // inc source pointer
  inc sm_p0+1 // inc target pointer
  
  // adjust count
  dex
  bne set // if count != 0 loop
  done:
431
}