Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- :BasicUpstart2(mainStartup)
- * = $0900 "main code"
- .var debug = false
- .const SCREEN_RES_Y = 200
- .const irq_top_line = 0
- .const irq_top_vis_line = 51
- .const irq_bot_vis_line = 250
- .const irq_middle_line = irq_top_vis_line + SCREEN_RES_Y / 2
- .const irq_blank_line = irq_bot_vis_line+1
- /*
- suggested memory map
- --------------------
- Type Start End Start End Bytes K Objects
- Code & Some Data 0900 87FF 2304 34815 32512 31.8
- Data (map, tiles, meta) 8800 BFFF 34816 49151 14336 14.0
- Character Set C000 C7FF 49152 51199 2048 2.0
- Screen 1 C800 CBFF 51200 52223 1024 1.0
- Screen 2 CC00 CFFF 52224 53247 1024 1.0
- Sprites D000 FFBF 53248 65471 12224 11.9 191.0
- IRQ Vectors ** FFFA FFFF 65530 65535 6 0.0
- */
- .const CHARSET_ADDRESS = $c000
- .const SCREEN0_ADDRESS = $c800
- .const SCREEN1_ADDRESS = $cc00
- .const SPRITE_SHAPE_ADDRESS = $d000
- .const SPRITE_SHAPE_POINTER0 = (SPRITE_SHAPE_ADDRESS - CHARSET_ADDRESS) / 64
- .const COLOR_ADDRESS = $d800
- // keep buffers untill page flipping works
- .const COLOR_BUFFER_ADDRESS = $8800
- //
- .const SCREEN_WIDTH = 40
- .const SCREEN_HEIGHT = 25
- .const MIDDLE_SCREEN_LINE = SCREEN_HEIGHT /2
- .const addressPntr1 = $f0
- .const addressPntr2 = $f3
- .const screenPntr = $f9
- .const bufferPntr = $fb
- #import "macros.asm"
- #import "random_RTL.asm"
- #import "keyboard_RTL.asm"
- mainStartup: {
- jsr init_screen
- sei
- lda #$35 // Bank out kernal and basic
- sta $01 // $e000-$ffff
- SetupIRQ(irq_blank, irq_blank_line,false)
- cli
- lda #1
- sta $d020
- lda #0
- sta $d021
- MainScrollLoop:
- lda IRQSignal_copy_screen_to_buffer
- beq DontCopyScreen
- jsr copy_upper_color_to_buffer
- jsr copy_lower_color_to_buffer
- jsr copy_screen_to_buffer
- lda #$00
- sta IRQSignal_copy_screen_to_buffer
- DontCopyScreen:
- //... rest of outside-IRQ work
- jmp MainScrollLoop
- }
- init_screen: {
- jsr copyCharSetFromROM
- // setup screen and charset to point to screen 0
- // and custom character set
- :setScreenAndCharsetLocation(SCREEN0_ADDRESS,CHARSET_ADDRESS,true)
- // setup screen and back buffer pointers
- :set16im(SCREEN0_ADDRESS,screenPntr)
- :set16im(SCREEN1_ADDRESS,bufferPntr)
- // setup screen index (points to screen 0 or screen 1)
- lda #0
- sta visible_screen_index
- :clearScreen(SCREEN0_ADDRESS,32)
- :clearScreen(SCREEN1_ADDRESS,32)
- // 24 row mode
- :clearBit($d011,3)
- :zero_y_scroll()
- lda $d012
- jsr initRandomLFSR
- lda #$00
- sta IRQSignal_copy_screen_to_buffer
- rts
- }
- //----------------------------------------------------------------------------------
- // setup scroll velocities and counters
- //----------------------------------------------------------------------------------
- // use 2 * frame time as scrolling is every second frame
- .var frameTimeNTSC = 2 * 1.0/60
- .var frameTimePAL = 2 * 1.0/50
- .var frameTime = frameTimePAL
- .var MAX_SPEED = 24
- .var speed = MAX_SPEED
- .var velocity = floor(256 * speed * frameTime)
- IRQSignal_copy_screen_to_buffer: .byte 0
- scrollCounterData:
- .byte 0,0
- .const MIN_SCROLL_SPEED = 0.5
- .const MAX_SCROLL_SPEED = 2.0
- .const MIN_I = 0
- .const MAX_I = 3
- scrollVelocityData: {
- .for(var i = MIN_I; i <= MAX_I; i++) {
- .var t = i*1.0/(MAX_I - MIN_I)
- .var v = floor(256 * (MIN_SCROLL_SPEED + t * (MAX_SCROLL_SPEED - MIN_SCROLL_SPEED)))
- .byte <v,>v
- }
- }
- scrollVelocityIndex:
- .byte 0
- newScrollVelocityIndex:
- .byte 0
- softScroll: .byte 0
- frame: .byte 0
- tileRowIndex: .byte 0
- visible_screen_index: .byte 0
- irq_blank: {
- irq_start(end)
- lda frame
- bne frame1 // every second frame do scroll, etc.
- frame0:
- // do AI, sprite movemenent, etc
- jsr doFrame0Tasks
- lda softScroll
- cmp #4
- bne !+
- inc IRQSignal_copy_screen_to_buffer
- jmp irqEnd
- !:
- jmp irqEnd
- frame1:
- jsr doScroll
- irqEnd:
- // toggle frame
- lda frame
- eor #1
- sta frame
- irq_end(irq_blank, irq_blank_line)
- end:
- }
- //--------------------------------------------------------------------------------------------------
- // doFrame0Tasks
- //--------------------------------------------------------------------------------------------------
- doFrame0Tasks: {
- // check keyboard for w,s keys and change scroll speed
- jsr checkKeyboardInput
- rts
- }
- TempX: .byte 0
- TempY: .byte 0
- .const DIGIT_1 = 48 + 1
- .const DIGIT_4 = 48 + 4
- .const DIGIT_9 = 48 + 9
- checkKeyboardInput: {
- jsr Keyboard
- bcs NoValidInput
- stx TempX
- sty TempY
- cmp #$ff
- beq NoNewAphanumericKey
- // Check A for Alphanumeric keys
- if_in_rangeJSR DIGIT_1 : DIGIT_4 : changeScrollSpeed : NoValidInput
- NoNewAphanumericKey:
- // Check X & Y for Non-Alphanumeric Keys
- ldx TempX
- ldy TempY
- NoValidInput: // This may be substituted for an errorhandler if needed.
- rts
- }
- changeScrollSpeed: {
- sec
- sbc #DIGIT_1
- sta newScrollVelocityIndex
- rts
- }
- updatesoftscroll: {
- lda scrollVelocityIndex
- asl
- tax
- // add velocity to counter
- clc
- lda scrollCounterData
- adc scrollVelocityData,x
- sta scrollCounterData
- lda scrollCounterData + 1
- adc scrollVelocityData + 1,x
- sta scrollCounterData + 1
- // check scroll data counter and inc soft scroll if necessary
- // otherwise exit
- testyscroll:
- lda scrollCounterData + 1
- if_zeroRTS // counter high is 0 so exit
- // take 1 from counter hi and inc yscroll ready for testing aging
- dec scrollCounterData + 1
- inc softScroll
- jmp testyscroll
- rts
- }
- //--------------------------------------------------------------------------------------------------
- // doScroll
- //--------------------------------------------------------------------------------------------------
- doScroll: {
- jsr updatesoftscroll
- lda softScroll
- cmp #8
- bcs scrollOverflowed
- :set_y_scroll(softScroll)
- rts
- }
- scrollOverflowed: {
- // and #3
- lda #0
- sta softScroll
- lda newScrollVelocityIndex
- sta scrollVelocityIndex
- :set_y_scroll(softScroll)
- jsr doCoarseScroll
- rts
- }
- doCoarseScroll: {
- jsr fill_top_of_screen
- jsr flip_screens
- jsr copy_color_from_buffer_to_screen
- rts
- }
- //--------------------------------------------------------------------------------------------------
- // fill_top_of_screen
- //--------------------------------------------------------------------------------------------------
- fill_top_of_screen:
- // toggle tileRowIndex.
- lda tileRowIndex
- eor #1
- sta tileRowIndex
- // if tileRowIndex == 1 then is a new row of tiles
- // so expand that row into the expanded map row buffer
- bne copyTileRow1
- jmp copyTileRow0
- copyTileRow1:
- // has hit new tile vertically so expand from map first
- jsr expand_map_row
- // copy expanded map row 1 to screen
- ldy #0
- .for (var x = 0; x < SCREEN_WIDTH; x++) {
- lda expanded_map_row_characters1 + x
- sta (bufferPntr),y
- lda expanded_map_row_colors1 + x
- sta COLOR_ADDRESS + x
- iny
- }
- rts
- // expand this map line then copy to screen
- copyTileRow0:
- // copy expanded map row 0 to screen
- ldy #0
- .for (var x = 0; x < SCREEN_WIDTH; x++) {
- lda expanded_map_row_characters0 + x
- sta (bufferPntr),y
- lda expanded_map_row_colors0 + x
- sta COLOR_ADDRESS + x
- iny
- }
- rts
- //--------------------------------------------------------------------------------------------------
- // expand_map_row
- //--------------------------------------------------------------------------------------------------
- expand_map_row:
- .for(var x = 0; x < SCREEN_WIDTH; x++) {
- .if ((x & 1) == 0) {
- // is column 0 of tile so get this new tile
- // pick a random tile for testing purposes
- !:
- jsr randomLFSR
- and #3
- cmp #4
- bcs !-
- // convert A -> tile base address
- :getTileBaseAddress(addressPntr1)
- ldx #x
- jsr copyColumn0TileRowsToExpandedMap
- } else {
- // is column 1 of tile
- ldx #x
- jsr copyColumn1TileRowsToExpandedMap
- }
- }
- rts
- copyColumn0TileRowsToExpandedMap: {
- .const col0 = 0
- .const row0 = 0
- .const row1 = 1
- :copyTileCharToExpandedMap(addressPntr1,col0,row1)
- :copyTileColorToExpandedMap(addressPntr1,col0,row1)
- :copyTileCharToExpandedMap(addressPntr1,col0,row0)
- :copyTileColorToExpandedMap(addressPntr1,col0,row0)
- rts
- }
- copyColumn1TileRowsToExpandedMap: {
- .const col1 = 1
- .const row0 = 0
- .const row1 = 1
- :copyTileCharToExpandedMap(addressPntr1,col1,row1)
- :copyTileColorToExpandedMap(addressPntr1,col1,row1)
- :copyTileCharToExpandedMap(addressPntr1,col1,row0)
- :copyTileColorToExpandedMap(addressPntr1,col1,row0)
- rts
- }
- .macro copyTileCharToExpandedMap(_addressPntr1,_tilecol,_tilerow) {
- .var yIndex = (_tilerow * 2) + _tilecol
- ldy #yIndex
- lda (_addressPntr1),y
- .if (_tilerow == 0)
- sta expanded_map_row_characters0,x
- else
- sta expanded_map_row_characters1,x
- }
- .macro copyTileColorToExpandedMap(_addressPntr1,_tilecol,_tilerow) {
- .var yIndex = 4 + (_tilerow * 2) + _tilecol
- ldy #yIndex
- lda (_addressPntr1),y
- .if (_tilerow == 0)
- sta expanded_map_row_colors0,x
- else
- sta expanded_map_row_colors1,x
- }
- .macro getTileBaseAddress(_tileAddressPntr) {
- // A * 8 + tiles address -> _tileAddressPntr
- sta _tileAddressPntr
- lda #0
- sta _tileAddressPntr + 1
- // multipy * 8
- asl _tileAddressPntr
- rol _tileAddressPntr + 1
- asl _tileAddressPntr
- rol _tileAddressPntr + 1
- asl _tileAddressPntr
- rol _tileAddressPntr + 1
- // add to base tiles address
- lda _tileAddressPntr
- clc
- adc #<tiles
- sta _tileAddressPntr
- lda _tileAddressPntr + 1
- adc #>tiles
- sta _tileAddressPntr + 1
- }
- //--------------------------------------------------------------------------------------------------
- // copy color ram (upper and lower halves)
- // to buffer
- //--------------------------------------------------------------------------------------------------
- copy_upper_color_to_buffer:
- .for (var y = 0; y < MIDDLE_SCREEN_LINE; y++) {
- ldx #SCREEN_WIDTH - 1
- !:
- lda [COLOR_ADDRESS + y * SCREEN_WIDTH],x
- sta [COLOR_BUFFER_ADDRESS + y * SCREEN_WIDTH],x
- dex
- bpl !-
- }
- rts
- copy_lower_color_to_buffer:
- .for (var y = MIDDLE_SCREEN_LINE; y < SCREEN_HEIGHT - 1; y++) {
- ldx #SCREEN_WIDTH - 1
- !:
- lda [COLOR_ADDRESS + y * SCREEN_WIDTH],x
- sta [COLOR_BUFFER_ADDRESS + y * SCREEN_WIDTH],x
- dex
- bpl !-
- }
- rts
- //--------------------------------------------------------------------------------------------------
- // copy_screen_to_buffer
- //--------------------------------------------------------------------------------------------------
- copy_screen_to_buffer: {
- :copy16(screenPntr,addressPntr1)
- :copy16(bufferPntr,addressPntr2)
- // one line down in buffer
- :add16im(SCREEN_WIDTH,addressPntr2,addressPntr2)
- .for (var y = 0; y < SCREEN_HEIGHT - 1; y++) {
- ldy #SCREEN_WIDTH - 1
- !:
- lda (addressPntr1),y
- sta (addressPntr2),y
- dey
- bpl !-
- // inc pointers down one line
- :add16im(SCREEN_WIDTH,addressPntr1,addressPntr1)
- :add16im(SCREEN_WIDTH,addressPntr2,addressPntr2)
- }
- rts
- }
- //--------------------------------------------------------------------------------------------------
- // copy_color_from_buffer_to_screen
- //--------------------------------------------------------------------------------------------------
- copy_color_from_buffer_to_screen:
- .for (var y = 0; y < SCREEN_HEIGHT - 1; y++) {
- .for (var x = 0; x < SCREEN_WIDTH; x++) {
- lda COLOR_BUFFER_ADDRESS + y * SCREEN_WIDTH + x
- sta COLOR_ADDRESS + (y + 1) * SCREEN_WIDTH + x
- }
- }
- rts
- //--------------------------------------------------------------------------------------------------
- // flip the screens
- //--------------------------------------------------------------------------------------------------
- flip_screens: {
- lda visible_screen_index
- bne setScreen0AsVisible
- setScreen1AsVisible:
- // toggle visible screen index
- eor #1
- sta visible_screen_index
- // setup visible screen to screen 1
- :setScreenAndCharsetLocation(SCREEN1_ADDRESS,CHARSET_ADDRESS,false)
- // setup screen and back buffer pointers
- :set16im(SCREEN1_ADDRESS,screenPntr)
- :set16im(SCREEN0_ADDRESS,bufferPntr)
- rts
- setScreen0AsVisible:
- // toggle visible screen index
- eor #1
- sta visible_screen_index
- // setup visible screen to screen 0
- :setScreenAndCharsetLocation(SCREEN0_ADDRESS,CHARSET_ADDRESS,false)
- // setup screen and back buffer pointers
- :set16im(SCREEN0_ADDRESS,screenPntr)
- :set16im(SCREEN1_ADDRESS,bufferPntr)
- rts
- }
- //--------------------------------------------------------------------------------------------------
- // color line buffer (middle of screen)
- //--------------------------------------------------------------------------------------------------
- COLOR_LINE_BUFFER: .fill SCREEN_WIDTH,0
- //--------------------------------------------------------------------------------------------------
- // map (2x2 tiles...$00 tile index = no tile)
- //--------------------------------------------------------------------------------------------------
- active_tile_row_characters0: .byte 0,0
- active_tile_row_characters1: .byte 0,0
- active_tile_row_colors0: .byte 0,0
- active_tile_row_colors1: .byte 0,0
- tiles: {
- .const DIGIT_00 = 48
- .const DIGIT_10 = 49
- .const DIGIT_01 = 50
- .const DIGIT_11 = 51
- :generateTile(32,32,
- 32,32,
- $f,$c,
- $c,$b) // no tile
- :generateTile(160,160,
- 160,160,
- $7,$7,
- $7,$7) // sand
- :generateTile(233,223,95,105,
- $f,$c,
- $c,$b) // filled diamond box
- :generateTile(85,73,74,75,3,3,3,3) // circle
- :generateTile(160,160,
- 160,160,
- $c,$c,
- $b,$b) // ledge
- :generateTile(160,160,
- 160,160,
- $f,$c,
- $c,$b) // filled box
- :generateTile(DIGIT_00,DIGIT_10,DIGIT_01,DIGIT_11,1,3,4,2) // numbers in corners
- :generateTile(79,80,
- 76,122,
- $f,$c,
- $c,$b) // box
- }
- // holds 1 row of expanded 2x2 tile characters
- expanded_map_row_characters0: .fill SCREEN_WIDTH,0
- expanded_map_row_characters1: .fill SCREEN_WIDTH,0
- // holds 1 row of expanded 2x2 tile colors
- expanded_map_row_colors0: .fill SCREEN_WIDTH,0
- expanded_map_row_colors1: .fill SCREEN_WIDTH,0
- //----------------------------------------------------------------------------------
- // copyCharSetFromROM
- //----------------------------------------------------------------------------------
- copyCharSetFromROM:
- sei // disable interrupts while we copy
- ldx #$08 // we loop 8 times (8x255 = 2Kb)
- lda #$33 // make the CPU see the Character Generator ROM...
- sta $01 // ...at $D000 by storing %00110011 into location $01
- lda #<$d000
- sta addressPntr1
- lda #>$d000
- sta addressPntr1 + 1
- lda #<CHARSET_ADDRESS
- sta addressPntr2
- lda #>CHARSET_ADDRESS
- sta addressPntr2 + 1
- ldx #8 // 256 * 8 = 2048 bytes
- ldy #0
- !:
- lda (addressPntr1),y // read byte from vector stored in addressPntr1
- sta (addressPntr2),y // write byte to vector stored in addressPntr2
- iny // do this 255 times...
- bne !- // ..for low byte $00 to $FF
- inc addressPntr1 + 1 // when we passed $FF increase high byte...
- inc addressPntr2 + 1 // when we passed $FF increase high byte...
- dex // ... and decrease X by one before restart
- bne !- // We repeat this until X becomes Zero
- lda #$37 // switch in I/O mapped registers again...
- sta $01 // ... with %00110111 so CPU can see them
- cli // turn off interrupt disable flag
- rts
- //--------------------------------------------------------------------------------------------------
- // generateTile macro
- //--------------------------------------------------------------------------------------------------
- .macro generateTile(char0,char1,char2,char3,col0,col1,col2,col3) {
- /**
- characters 2x2
- char0 char1
- char2 char3
- **/
- .byte char0,char1,char2,char3
- /**
- colours 2x2
- col0 col1
- col2 col3
- **/
- .byte col0,col1,col2,col3
- }
Advertisement
Add Comment
Please, Sign In to add comment