paul_nicholls

Untitled

Oct 30th, 2025 (edited)
663
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. :BasicUpstart2(mainStartup)
  2.  
  3. * = $0900 "main code"
  4.  
  5. .var debug = false
  6.  
  7. .const SCREEN_RES_Y     = 200
  8. .const irq_top_line     = 0
  9. .const irq_top_vis_line = 51
  10. .const irq_bot_vis_line = 250
  11. .const irq_middle_line  = irq_top_vis_line + SCREEN_RES_Y / 2
  12. .const irq_blank_line   = irq_bot_vis_line+1
  13.  
  14. /*
  15. suggested memory map
  16. --------------------
  17. Type                      Start End   Start End   Bytes K       Objects
  18. Code & Some Data          0900  87FF    2304    34815   32512   31.8   
  19. Data (map, tiles, meta) 8800    BFFF    34816   49151   14336   14.0   
  20. Character Set             C000  C7FF    49152   51199   2048    2.0
  21. Screen 1                  C800  CBFF    51200   52223   1024    1.0
  22. Screen 2                  CC00  CFFF    52224   53247   1024    1.0
  23. Sprites                 D000    FFBF    53248   65471   12224   11.9    191.0
  24. IRQ Vectors **          FFFA    FFFF    65530   65535   6   0.0
  25. */
  26.  
  27. .const CHARSET_ADDRESS       = $c000
  28. .const SCREEN0_ADDRESS       = $c800
  29. .const SCREEN1_ADDRESS       = $cc00
  30. .const SPRITE_SHAPE_ADDRESS  = $d000
  31. .const SPRITE_SHAPE_POINTER0 = (SPRITE_SHAPE_ADDRESS - CHARSET_ADDRESS) / 64
  32.  
  33. .const COLOR_ADDRESS        = $d800
  34.  
  35. // keep buffers untill page flipping works
  36. .const COLOR_BUFFER_ADDRESS  = $8800
  37. //
  38. .const SCREEN_WIDTH     = 40
  39. .const SCREEN_HEIGHT    = 25
  40.  
  41. .const MIDDLE_SCREEN_LINE = SCREEN_HEIGHT /2
  42.  
  43. .const addressPntr1     = $f0
  44. .const addressPntr2     = $f3
  45.  
  46. .const screenPntr       = $f9
  47. .const bufferPntr       = $fb
  48.  
  49. #import "macros.asm"
  50. #import "random_RTL.asm"
  51. #import "keyboard_RTL.asm"
  52.  
  53. mainStartup: {
  54.   jsr init_screen
  55.  
  56.   sei
  57.   lda #$35        // Bank out kernal and basic
  58.   sta $01         // $e000-$ffff
  59.  
  60.   SetupIRQ(irq_blank, irq_blank_line,false)
  61.   cli
  62.  
  63.   lda #1
  64.   sta $d020
  65.   lda #0
  66.   sta $d021
  67.  
  68. MainScrollLoop:
  69.   lda IRQSignal_copy_screen_to_buffer
  70.   beq DontCopyScreen
  71.  
  72.   jsr copy_upper_color_to_buffer
  73.   jsr copy_lower_color_to_buffer
  74.   jsr copy_screen_to_buffer
  75.  
  76.   lda #$00
  77.   sta IRQSignal_copy_screen_to_buffer
  78. DontCopyScreen:
  79.   //... rest of outside-IRQ work
  80.   jmp MainScrollLoop
  81. }
  82.  
  83. init_screen: {
  84.   jsr copyCharSetFromROM
  85.   // setup screen and charset to point to screen 0
  86.   // and custom character set
  87.   :setScreenAndCharsetLocation(SCREEN0_ADDRESS,CHARSET_ADDRESS,true)
  88.  
  89.   // setup screen and back buffer pointers
  90.   :set16im(SCREEN0_ADDRESS,screenPntr)
  91.   :set16im(SCREEN1_ADDRESS,bufferPntr)
  92.  
  93.   // setup screen index (points to screen 0 or screen 1)
  94.   lda #0
  95.   sta visible_screen_index
  96.  
  97.   :clearScreen(SCREEN0_ADDRESS,32)
  98.   :clearScreen(SCREEN1_ADDRESS,32)
  99.  
  100. // 24 row mode
  101.   :clearBit($d011,3)
  102.  
  103.   :zero_y_scroll()
  104.  
  105.   lda $d012
  106.   jsr initRandomLFSR
  107.  
  108.   lda #$00
  109.   sta IRQSignal_copy_screen_to_buffer
  110.  
  111.   rts
  112. }
  113.  
  114. //----------------------------------------------------------------------------------
  115. //                             setup scroll velocities and counters
  116. //----------------------------------------------------------------------------------
  117. // use 2 * frame time as scrolling is every second frame
  118. .var frameTimeNTSC  = 2 * 1.0/60
  119. .var frameTimePAL   = 2 * 1.0/50
  120.  
  121. .var frameTime = frameTimePAL
  122.  
  123. .var MAX_SPEED = 24
  124.  
  125. .var speed    = MAX_SPEED
  126. .var velocity = floor(256 * speed * frameTime)
  127.  
  128. IRQSignal_copy_screen_to_buffer: .byte 0
  129.  
  130. scrollCounterData:
  131.   .byte 0,0
  132.  
  133. .const MIN_SCROLL_SPEED = 0.5
  134. .const MAX_SCROLL_SPEED = 2.0
  135.  
  136. .const MIN_I = 0
  137. .const MAX_I = 3
  138.  
  139. scrollVelocityData: {
  140.   .for(var i = MIN_I; i <= MAX_I; i++) {
  141.     .var t = i*1.0/(MAX_I - MIN_I)
  142.     .var v = floor(256 * (MIN_SCROLL_SPEED + t * (MAX_SCROLL_SPEED - MIN_SCROLL_SPEED)))
  143.  
  144.     .byte <v,>v
  145.   }
  146. }
  147.  
  148. scrollVelocityIndex:
  149.   .byte 0
  150.  
  151. newScrollVelocityIndex:
  152.   .byte 0
  153.  
  154. softScroll:   .byte 0
  155. frame:        .byte 0
  156. tileRowIndex: .byte 0
  157.  
  158. visible_screen_index: .byte 0
  159.  
  160. irq_blank: {
  161.   irq_start(end)
  162.  
  163.   lda frame
  164.   bne frame1 // every second frame do scroll, etc.
  165. frame0:
  166. // do AI, sprite movemenent, etc
  167.   jsr doFrame0Tasks
  168.  
  169.   lda softScroll
  170.  
  171.   cmp #4
  172.   bne !+
  173.  
  174.   inc IRQSignal_copy_screen_to_buffer
  175.  
  176.   jmp irqEnd
  177. !:
  178.   jmp irqEnd
  179.  
  180. frame1:
  181.   jsr doScroll
  182.  
  183. irqEnd:
  184.   // toggle frame
  185.   lda frame
  186.   eor #1
  187.   sta frame
  188.  
  189.   irq_end(irq_blank, irq_blank_line)
  190. end:
  191. }
  192.  
  193. //--------------------------------------------------------------------------------------------------
  194. //                                      doFrame0Tasks
  195. //--------------------------------------------------------------------------------------------------
  196. doFrame0Tasks: {
  197. // check keyboard for w,s keys and change scroll speed
  198.   jsr checkKeyboardInput
  199.   rts
  200. }
  201.  
  202. TempX: .byte 0
  203. TempY: .byte 0
  204.  
  205. .const DIGIT_1 = 48 + 1
  206. .const DIGIT_4 = 48 + 4
  207. .const DIGIT_9 = 48 + 9
  208.  
  209. checkKeyboardInput: {
  210.   jsr Keyboard
  211.   bcs NoValidInput
  212.     stx TempX
  213.     sty TempY
  214.     cmp #$ff
  215.     beq NoNewAphanumericKey
  216.       // Check A for Alphanumeric keys
  217.       if_in_rangeJSR DIGIT_1 : DIGIT_4 : changeScrollSpeed : NoValidInput
  218.   NoNewAphanumericKey:
  219.   // Check X & Y for Non-Alphanumeric Keys
  220.   ldx TempX
  221.   ldy TempY
  222. NoValidInput:  // This may be substituted for an errorhandler if needed.
  223.   rts
  224. }
  225.  
  226. changeScrollSpeed: {
  227.   sec
  228.   sbc #DIGIT_1
  229.   sta newScrollVelocityIndex
  230.   rts
  231. }
  232.  
  233. updatesoftscroll: {
  234.    lda scrollVelocityIndex
  235.    asl
  236.    tax
  237.  
  238.    // add velocity to counter
  239.    clc
  240.    lda scrollCounterData
  241.    adc scrollVelocityData,x
  242.    sta scrollCounterData
  243.  
  244.    lda scrollCounterData + 1
  245.    adc scrollVelocityData + 1,x
  246.    sta scrollCounterData + 1
  247.  
  248.   // check scroll data counter and inc soft scroll if necessary
  249.   // otherwise exit
  250. testyscroll:
  251.   lda scrollCounterData + 1
  252.   if_zeroRTS // counter high is 0 so exit
  253.  
  254.   // take 1 from counter hi and inc yscroll ready for testing aging
  255.   dec scrollCounterData + 1
  256.  
  257.   inc softScroll
  258.   jmp testyscroll
  259.   rts
  260. }
  261. //--------------------------------------------------------------------------------------------------
  262. //                                      doScroll
  263. //--------------------------------------------------------------------------------------------------
  264. doScroll: {
  265.   jsr updatesoftscroll
  266.  
  267.   lda softScroll
  268.   cmp #8
  269.   bcs scrollOverflowed
  270.  
  271.   :set_y_scroll(softScroll)
  272.   rts
  273. }
  274.  
  275. scrollOverflowed: {
  276. //  and #3
  277.   lda #0
  278.   sta softScroll
  279.  
  280.   lda newScrollVelocityIndex
  281.   sta scrollVelocityIndex
  282.  
  283.   :set_y_scroll(softScroll)
  284.  
  285.   jsr doCoarseScroll
  286.   rts
  287. }
  288.  
  289. doCoarseScroll: {
  290.   jsr fill_top_of_screen
  291.   jsr flip_screens
  292.   jsr copy_color_from_buffer_to_screen
  293.  
  294.   rts
  295. }
  296.  
  297. //--------------------------------------------------------------------------------------------------
  298. //                                      fill_top_of_screen
  299. //--------------------------------------------------------------------------------------------------
  300. fill_top_of_screen:
  301. // toggle tileRowIndex.
  302.   lda tileRowIndex
  303.   eor #1
  304.   sta tileRowIndex
  305.  
  306. // if tileRowIndex == 1 then is a new row of tiles
  307. // so expand that row into the expanded map row buffer
  308.   bne copyTileRow1
  309.   jmp copyTileRow0
  310. copyTileRow1:
  311.   // has hit new tile vertically so expand from map first
  312.   jsr expand_map_row
  313.  
  314. // copy expanded map row 1 to screen
  315.   ldy #0
  316.   .for (var x = 0; x < SCREEN_WIDTH; x++) {
  317.     lda expanded_map_row_characters1 + x
  318.     sta (bufferPntr),y
  319.  
  320.     lda expanded_map_row_colors1 + x
  321.     sta COLOR_ADDRESS + x
  322.     iny
  323.   }
  324.   rts
  325.  
  326. // expand this map line then copy to screen
  327. copyTileRow0:
  328. // copy expanded map row 0 to screen
  329.   ldy #0
  330.   .for (var x = 0; x < SCREEN_WIDTH; x++) {
  331.     lda expanded_map_row_characters0 + x
  332.     sta (bufferPntr),y
  333.  
  334.     lda expanded_map_row_colors0 + x
  335.     sta COLOR_ADDRESS + x
  336.     iny
  337.   }
  338.   rts
  339.  
  340. //--------------------------------------------------------------------------------------------------
  341. //                                      expand_map_row
  342. //--------------------------------------------------------------------------------------------------
  343. expand_map_row:
  344.   .for(var x = 0; x < SCREEN_WIDTH; x++) {
  345.     .if ((x & 1) == 0) {
  346.       // is column 0 of tile so get this new tile
  347.       // pick a random tile for testing purposes
  348. !:
  349.       jsr randomLFSR
  350.       and #3
  351.       cmp #4
  352.       bcs !-
  353.  
  354.       // convert A -> tile base address
  355.       :getTileBaseAddress(addressPntr1)
  356.  
  357.       ldx #x
  358.       jsr copyColumn0TileRowsToExpandedMap
  359.     } else {
  360.       // is column 1 of tile
  361.       ldx #x
  362.       jsr copyColumn1TileRowsToExpandedMap
  363.     }
  364.   }
  365.   rts
  366.  
  367. copyColumn0TileRowsToExpandedMap: {
  368.   .const col0 = 0
  369.   .const row0 = 0
  370.   .const row1 = 1
  371.  
  372.   :copyTileCharToExpandedMap(addressPntr1,col0,row1)
  373.   :copyTileColorToExpandedMap(addressPntr1,col0,row1)
  374.   :copyTileCharToExpandedMap(addressPntr1,col0,row0)
  375.   :copyTileColorToExpandedMap(addressPntr1,col0,row0)
  376.   rts
  377. }
  378.  
  379. copyColumn1TileRowsToExpandedMap: {
  380.   .const col1 = 1
  381.   .const row0 = 0
  382.   .const row1 = 1
  383.  
  384.   :copyTileCharToExpandedMap(addressPntr1,col1,row1)
  385.   :copyTileColorToExpandedMap(addressPntr1,col1,row1)
  386.   :copyTileCharToExpandedMap(addressPntr1,col1,row0)
  387.   :copyTileColorToExpandedMap(addressPntr1,col1,row0)
  388.   rts
  389. }
  390.  
  391. .macro copyTileCharToExpandedMap(_addressPntr1,_tilecol,_tilerow) {
  392.   .var yIndex = (_tilerow * 2) + _tilecol
  393.  
  394.   ldy #yIndex
  395.   lda (_addressPntr1),y
  396.   .if (_tilerow == 0)
  397.     sta expanded_map_row_characters0,x
  398.   else
  399.     sta expanded_map_row_characters1,x
  400. }
  401.  
  402. .macro copyTileColorToExpandedMap(_addressPntr1,_tilecol,_tilerow) {
  403.   .var yIndex = 4 + (_tilerow * 2) + _tilecol
  404.  
  405.   ldy #yIndex
  406.   lda (_addressPntr1),y
  407.   .if (_tilerow == 0)
  408.     sta expanded_map_row_colors0,x
  409.   else
  410.     sta expanded_map_row_colors1,x
  411. }
  412.  
  413. .macro getTileBaseAddress(_tileAddressPntr) {
  414. // A * 8 + tiles address -> _tileAddressPntr
  415.   sta _tileAddressPntr
  416.   lda #0
  417.   sta _tileAddressPntr + 1
  418.  
  419. // multipy * 8
  420.   asl _tileAddressPntr
  421.   rol _tileAddressPntr + 1
  422.  
  423.   asl _tileAddressPntr
  424.   rol _tileAddressPntr + 1
  425.  
  426.   asl _tileAddressPntr
  427.   rol _tileAddressPntr + 1
  428.  
  429. // add to base tiles address
  430.   lda _tileAddressPntr
  431.   clc
  432.   adc #<tiles
  433.   sta _tileAddressPntr
  434.  
  435.   lda _tileAddressPntr + 1
  436.   adc #>tiles
  437.   sta _tileAddressPntr + 1
  438. }
  439.  
  440. //--------------------------------------------------------------------------------------------------
  441. //                                      copy color ram (upper and lower halves)
  442. //                                      to buffer
  443. //--------------------------------------------------------------------------------------------------
  444. copy_upper_color_to_buffer:
  445.   .for (var y = 0; y < MIDDLE_SCREEN_LINE; y++) {
  446.     ldx #SCREEN_WIDTH - 1
  447.   !:
  448.     lda [COLOR_ADDRESS        + y * SCREEN_WIDTH],x
  449.     sta [COLOR_BUFFER_ADDRESS + y * SCREEN_WIDTH],x
  450.     dex
  451.     bpl !-
  452.   }
  453.  
  454.   rts
  455.  
  456. copy_lower_color_to_buffer:
  457.   .for (var y = MIDDLE_SCREEN_LINE; y < SCREEN_HEIGHT - 1; y++) {
  458.     ldx #SCREEN_WIDTH - 1
  459.   !:
  460.     lda [COLOR_ADDRESS        + y * SCREEN_WIDTH],x
  461.     sta [COLOR_BUFFER_ADDRESS + y * SCREEN_WIDTH],x
  462.     dex
  463.     bpl !-
  464.   }
  465.  
  466.   rts
  467.  
  468. //--------------------------------------------------------------------------------------------------
  469. //                                      copy_screen_to_buffer
  470. //--------------------------------------------------------------------------------------------------
  471. copy_screen_to_buffer: {
  472.   :copy16(screenPntr,addressPntr1)
  473.   :copy16(bufferPntr,addressPntr2)
  474.  
  475.   // one line down in buffer
  476.   :add16im(SCREEN_WIDTH,addressPntr2,addressPntr2)
  477.  
  478.   .for (var y = 0; y < SCREEN_HEIGHT - 1; y++) {
  479.     ldy #SCREEN_WIDTH - 1
  480.   !:
  481.     lda (addressPntr1),y
  482.     sta (addressPntr2),y
  483.     dey
  484.     bpl !-
  485.    
  486.     // inc pointers down one line
  487.     :add16im(SCREEN_WIDTH,addressPntr1,addressPntr1)
  488.     :add16im(SCREEN_WIDTH,addressPntr2,addressPntr2)
  489.   }
  490.   rts
  491. }
  492. //--------------------------------------------------------------------------------------------------
  493. //                                      copy_color_from_buffer_to_screen
  494. //--------------------------------------------------------------------------------------------------
  495. copy_color_from_buffer_to_screen:
  496.   .for (var y = 0; y < SCREEN_HEIGHT - 1; y++) {
  497.     .for (var x = 0; x < SCREEN_WIDTH; x++) {
  498.       lda COLOR_BUFFER_ADDRESS + y * SCREEN_WIDTH + x
  499.       sta COLOR_ADDRESS + (y + 1)  * SCREEN_WIDTH + x
  500.     }
  501.   }
  502.  
  503.   rts
  504.  
  505. //--------------------------------------------------------------------------------------------------
  506. //                                      flip the screens
  507. //--------------------------------------------------------------------------------------------------
  508. flip_screens: {
  509.   lda visible_screen_index
  510.   bne setScreen0AsVisible
  511. setScreen1AsVisible:
  512.   // toggle visible screen index
  513.   eor #1
  514.   sta visible_screen_index
  515.  
  516.   // setup visible screen to screen 1
  517.   :setScreenAndCharsetLocation(SCREEN1_ADDRESS,CHARSET_ADDRESS,false)
  518.  
  519.   // setup screen and back buffer pointers
  520.   :set16im(SCREEN1_ADDRESS,screenPntr)
  521.   :set16im(SCREEN0_ADDRESS,bufferPntr)
  522.   rts
  523.  
  524. setScreen0AsVisible:
  525.   // toggle visible screen index
  526.   eor #1
  527.   sta visible_screen_index
  528.  
  529.   // setup visible screen to screen 0
  530.   :setScreenAndCharsetLocation(SCREEN0_ADDRESS,CHARSET_ADDRESS,false)
  531.  
  532.   // setup screen and back buffer pointers
  533.   :set16im(SCREEN0_ADDRESS,screenPntr)
  534.   :set16im(SCREEN1_ADDRESS,bufferPntr)
  535.   rts
  536. }
  537.  
  538. //--------------------------------------------------------------------------------------------------
  539. //                                      color line buffer (middle of screen)
  540. //--------------------------------------------------------------------------------------------------
  541. COLOR_LINE_BUFFER: .fill SCREEN_WIDTH,0
  542.  
  543. //--------------------------------------------------------------------------------------------------
  544. //                                      map (2x2 tiles...$00 tile index = no tile)
  545. //--------------------------------------------------------------------------------------------------
  546.  
  547. active_tile_row_characters0: .byte 0,0
  548. active_tile_row_characters1: .byte 0,0
  549.  
  550. active_tile_row_colors0: .byte 0,0
  551. active_tile_row_colors1: .byte 0,0
  552.  
  553. tiles: {
  554.   .const DIGIT_00 = 48
  555.   .const DIGIT_10 = 49
  556.   .const DIGIT_01 = 50
  557.   .const DIGIT_11 = 51
  558.  
  559.   :generateTile(32,32,
  560.                 32,32,
  561.                 $f,$c,
  562.                 $c,$b)   // no tile
  563.  
  564.   :generateTile(160,160,
  565.                 160,160,
  566.                 $7,$7,
  567.                 $7,$7) // sand
  568.                
  569.   :generateTile(233,223,95,105,
  570.                 $f,$c,
  571.                 $c,$b) // filled diamond box
  572.  
  573.   :generateTile(85,73,74,75,3,3,3,3) // circle
  574.  
  575.   :generateTile(160,160,
  576.                 160,160,
  577.                 $c,$c,
  578.                 $b,$b) // ledge
  579.  
  580.   :generateTile(160,160,
  581.                 160,160,
  582.                 $f,$c,
  583.                 $c,$b)   // filled box
  584.  
  585.   :generateTile(DIGIT_00,DIGIT_10,DIGIT_01,DIGIT_11,1,3,4,2)   // numbers in corners
  586.  
  587.   :generateTile(79,80,
  588.                 76,122,
  589.                 $f,$c,
  590.                 $c,$b)   // box
  591. }
  592.  
  593. // holds 1 row of expanded 2x2 tile characters
  594. expanded_map_row_characters0: .fill SCREEN_WIDTH,0
  595. expanded_map_row_characters1: .fill SCREEN_WIDTH,0
  596.  
  597. // holds 1 row of expanded 2x2 tile colors
  598. expanded_map_row_colors0: .fill SCREEN_WIDTH,0
  599. expanded_map_row_colors1: .fill SCREEN_WIDTH,0
  600.  
  601. //----------------------------------------------------------------------------------
  602. //                                    copyCharSetFromROM
  603. //----------------------------------------------------------------------------------
  604.  
  605. copyCharSetFromROM:
  606.   sei           // disable interrupts while we copy
  607.   ldx #$08      // we loop 8 times (8x255 = 2Kb)
  608.   lda #$33      // make the CPU see the Character Generator ROM...
  609.   sta $01       // ...at $D000 by storing %00110011 into location $01
  610.  
  611.   lda #<$d000
  612.   sta addressPntr1
  613.   lda #>$d000
  614.   sta addressPntr1 + 1
  615.  
  616.   lda #<CHARSET_ADDRESS
  617.   sta addressPntr2
  618.   lda #>CHARSET_ADDRESS
  619.   sta addressPntr2 + 1
  620.  
  621.   ldx #8               // 256 * 8 = 2048 bytes
  622.   ldy #0
  623. !:    
  624.   lda (addressPntr1),y   // read byte from vector stored in addressPntr1
  625.   sta (addressPntr2),y   // write byte to vector stored in addressPntr2
  626.   iny                  // do this 255 times...
  627.   bne !-               // ..for low byte $00 to $FF
  628.   inc addressPntr1 + 1   // when we passed $FF increase high byte...
  629.   inc addressPntr2 + 1   // when we passed $FF increase high byte...
  630.   dex                  // ... and decrease X by one before restart
  631.   bne !-               // We repeat this until X becomes Zero
  632.  
  633.   lda #$37             // switch in I/O mapped registers again...
  634.   sta $01              // ... with %00110111 so CPU can see them
  635.   cli                  // turn off interrupt disable flag
  636.  
  637.   rts
  638.  
  639. //--------------------------------------------------------------------------------------------------
  640. //                                      generateTile macro
  641. //--------------------------------------------------------------------------------------------------
  642. .macro generateTile(char0,char1,char2,char3,col0,col1,col2,col3) {
  643.   /**
  644.   characters 2x2
  645.   char0 char1
  646.   char2 char3
  647.   **/
  648.   .byte char0,char1,char2,char3
  649.   /**
  650.   colours 2x2
  651.   col0 col1
  652.   col2 col3
  653.   **/
  654.   .byte col0,col1,col2,col3
  655. }
  656.  
Advertisement
Add Comment
Please, Sign In to add comment