Refactor GTE Core to be included as an independent Segment in other projects

This commit is contained in:
Lucas Scharenbroich 2021-08-25 09:38:02 -05:00
parent 023332dfe6
commit 7d5f7aa721
11 changed files with 1315 additions and 1128 deletions

View File

@ -7,7 +7,7 @@ MoveLeft
lsr
jsr SetBG1XPos
jsr Render
jsr _Render
rts
MoveRight
@ -23,7 +23,7 @@ MoveRight
lsr
jsr SetBG1XPos
jsr Render
jsr _Render
pla
rts
@ -46,7 +46,7 @@ MoveUp
; lsr
; jsr SetBG1YPos
jsr Render
jsr _Render
rts
MoveDown
@ -62,7 +62,7 @@ MoveDown
; lsr
; jsr SetBG1YPos
jsr Render
jsr _Render
pla
rts
@ -108,7 +108,7 @@ Demo
; jsr MoveLeft
jsr UpdateBG1Rotation
; jsr DoColorCycle
jsr Render
jsr _Render
inc frameCount
@ -190,7 +190,7 @@ AngleUp
sbc #64
sta angle
jsr _ApplyAngle
jsr Render
jsr _Render
rts
AngleDown
@ -201,7 +201,7 @@ AngleDown
adc #64
sta angle
jsr _ApplyAngle
jsr Render
jsr _Render
rts
angle dw 0
@ -295,3 +295,4 @@ _DoTimers

View File

@ -16,7 +16,7 @@
mx %00
MemInit PushLong #0 ; space for result
InitMemory PushLong #0 ; space for result
PushLong #$008000 ; size (32k)
PushWord UserId
PushWord #%11000000_00010111 ; Fixed location
@ -123,7 +123,7 @@ AllocOneBank PushLong #0
:bank ldal $000001,X ; recover the bank address in A=XX/00
rts
; Variation that return pointer in the X/A registers (X = low, A = high)
; Variation that returns the pointer in the X/A registers (X = low, A = high)
AllocOneBank2 PushLong #0
PushLong #$10000
PushWord UserId
@ -134,75 +134,3 @@ AllocOneBank2 PushLong #0
pla ; high address 00XX of the new handle (bank)
_Deref
rts
; Set up the interrupts
;
; oldOneVect = GetVector( oneSecHnd );
; SetVector( oneSecHnd, (Pointer) ONEHANDLER );
; IntSource( oSecEnable );
; SetHeartBeat( VBLTASK );
IntInit rts
; IntSource( oSecDisable ); /* disable one second interrupts */
; SetVector( oneSecHnd, oldOneVect ); /* reset to the old handler */
ShutDown rts

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
; ALI BANK
SNA Tiles
;Segment #3 -- Rotation table data
; Segment #3 -- Rotation table data
ASM RotData.s
DS 0
@ -28,3 +28,4 @@
ALI BANK
SNA RotData

428
src/Core.s Normal file
View File

@ -0,0 +1,428 @@
use Util.Macs.s
use Locator.Macs.s
use Mem.Macs.s
use Misc.Macs.s
use Tool222.MACS.s
use Core.MACS.s
use .\Defs.s
; Feature flags
NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging
NO_MUSIC equ 1 ; turn music + tool loading off
; External data provided by the main program segment
tiledata EXT
; Core engine functionality. The idea is that that source file can be PUT into
; a main source file and all of the functionality will be available.
;
; There are some constancts that must be externally defined that can affect how
; the GTE runtime works
;
; NO_MUSIC : Set to non-zero to avoid using any source
; NO_INTERRUPTS : Set to non-zero to avoid installing custom interrupt handlers
mx %00
; High-Level StartUp and ShutDown functions
EngineStartUp ENT
phb
phk
plb
jsr ToolStartUp ; Start up the toolbox tools we rely on
jsr SoundStartUp ; Start up any sound/music tools
jsr IntStartUp ; Enable certain iterrupts
jsr InitMemory ; Allocate and initialize memory for the engine
jsr InitGraphics ; Initialize all of the graphics-related dat
jsr InitTimers ; Initialize the timee subsystem
jsr EngineReset ; All of the resources are allocated, put the engine in a known state
plb
rtl
EngineShutDown ENT
jsr IntShutDown
jsr SoundShutDown
jsr ToolShutDown
rtl
ToolStartUp
_TLStartUp ; normal tool initialization
pha
_MMStartUp
_Err ; should never happen
pla
sta MasterId ; our master handle references the memory allocated to us
ora #$0100 ; set auxID = $01 (valid values $01-0f)
sta UserId ; any memory we request must use our own id
_MTStartUp
rts
MasterId ds 2
UserId ds 2
; Fatal error handler invoked by the _Err macro
PgmDeath tax
pla
inc
phx
phk
pha
bra ContDeath
PgmDeath0 pha
pea $0000
pea $0000
ContDeath ldx #$1503
jsl $E10000
ToolShutDown
rts
; Use Tool222 (NinjaTrackerPlus) for music playback
SoundStartUp
lda #NO_MUSIC
bne :no_music
pea $00DE
pea $0000
_LoadOneTool
_Err
lda UserId
pha
_NTPStartUp
:no_music
rts
SoundShutDown
lda #NO_MUSIC
bne :no_music
_NTPShutDown
:no_music
rts
; Install interrupt handlers. We use the VBL interrupt to keep animations
; moving at a consistent rate, regarless of the rendered frame rate. The
; one-second timer is generally just used for counters and as a handy
; frames-per-second trigger.
IntStartUp
lda #NO_INTERRUPTS
bne :no_interrupts
PushLong #0
pea $0015 ; Get the existing 1-second interrupt handler and save
_GetVector
PullLong OldOneSecVec
pea $0015 ; Set the new handler and enable interrupts
PushLong #OneSecHandler
_SetVector
pea $0006
_IntSource
PushLong #VBLTASK ; Also register a Heart Beat Task
_SetHeartBeat
:no_interrupts
rts
IntShutDown
lda #NO_INTERRUPTS
bne :no_interrupts
pea $0007 ; disable 1-second interrupts
_IntSource
PushLong #VBLTASK ; Remove our heartbeat task
_DelHeartBeat
pea $0015
PushLong OldOneSecVec ; Reset the interrupt vector
_SetVector
:no_interrupts
rts
; Interrupt handlers. We install a heartbeat (1/60th second and a 1-second timer)
OneSecHandler mx %11
phb
pha
phk
plb
rep #$20
inc OneSecondCounter
sep #$20
ldal $E0C032
and #%10111111 ;clear IRQ source
stal $E0C032
pla
plb
clc
rtl
mx %00
OneSecondCounter dw 0
OldOneSecVec ds 4
VBLTASK hex 00000000
dw 0
hex 5AA5
; Reset the engine to a known state
; Blitter initialization
EngineReset
stz ScreenHeight
stz ScreenWidth
stz ScreenY0
stz ScreenY1
stz ScreenX0
stz ScreenX1
stz ScreenTileHeight
stz ScreenTileWidth
stz StartX
stz OldStartX
stz StartXMod164
stz StartY
stz OldStartY
stz StartYMod208
stz EngineMode
stz DirtyBits
stz LastPatchOffset
stz BG1StartX
stz BG1StartXMod164
stz BG1StartY
stz BG1StartYMod208
stz BG1OffsetIndex
stz BG0TileOriginX
stz BG0TileOriginY
stz OldBG0TileOriginX
stz OldBG0TileOriginY
stz BG1TileOriginX
stz BG1TileOriginY
stz OldBG1TileOriginX
stz OldBG1TileOriginY
stz TileMapWidth
stz TileMapHeight
stz TileMapPtr
stz TileMapPtr+2
stz OneSecondCounter
]step equ 0
lup 13
ldx #BlitBuff
lda #^BlitBuff
ldy #]step
jsr BuildBank
]step equ ]step+4
--^
rts
; Allow the user to dynamically select one of the pre-configured screen sizes, or pass
; in a specific width and height. The screen is automatically centered. If this is
; not desired, then SetScreenRect should be used directly
;
; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%))
; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%))
; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%))
; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%))
; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%))
; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%))
; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%))
; 7. Ancient Land of Y's : 36 x 16 288 x 128 (18,432 bytes ( 57.6%))
; 8. Game Boy Color : 20 x 18 160 x 144 (11,520 bytes ( 36.0%))
;
; X = mode number OR width in pixels (must be multiple of 2)
; Y = hwight in pixels (if X > 8)
ScreenModeWidth dw 320,272,256,256,280,256,240,288,160,320
ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,1
SetScreenMode ENT
phb
phk
plb
cpx #9
bcs :direct ; if x > 8, then assume X and Y are the dimensions
txa
asl
tax
ldy ScreenModeHeight,x
lda ScreenModeWidth,x
tax
:direct cpy #201
bcs :exit
cpx #321
bcs :exit
txa
lsr
pha ; Save X (width / 2) and Y (height)
phy
lda #160 ; Center the screen
sec
sbc 3,s
lsr
xba
pha ; Save half the origin coordinate
lda #200
sec
sbc 3,s ; This is now Y because of the PHA above
lsr
ora 1,s
plx ; Throw-away to pop the stack
ply
plx
jsr SetScreenRect
jsr FillScreen
:exit
plb
rtl
WaitForKey sep #$20
stal KBD_STROBE_REG ; clear the strobe
:WFK ldal KBD_REG
bpl :WFK
rep #$20
and #$007F
rts
ClearKbdStrobe sep #$20
stal KBD_STROBE_REG
rep #$20
rts
; Read the keyboard and paddle controls and return in a game-cotroller-like format
ReadControl ENT
pea $0000 ; low byte = key code, high byte = %------AB
sep #$20
ldal OPTION_KEY_REG ; 'B' button
and #$80
beq :BNotDown
lda #1
ora 1,s
sta 1,s
:BNotDown
ldal COMMAND_KEY_REG
and #$80
beq :ANotDown
lda #2
ora 1,s
sta 1,s
:ANotDown
ldal KBD_STROBE_REG ; read the keyboard
bit #$80
beq :KbdNotDwn ; check the key-down status
and #$7f
ora 1,s
sta 1,s
:KbdNotDwn
rep #$20
pla
rtl
put App.Init.s
put Graphics.s
; put App.Msg.s
; put Actions.s
; put font.s
put Render.s
; put Overlay.s
put blitter/Blitter.s
put blitter/Horz.s
put blitter/PEISlammer.s
put blitter/Tables.s
put blitter/Template.s
put blitter/Tiles.s
put blitter/Vert.s
put blitter/BG1.s
put TileMap.s

View File

@ -1,3 +1,23 @@
; Global addresses and engine values
SHADOW_REG equ $E0C035
STATE_REG equ $E0C068
NEW_VIDEO_REG equ $E0C029
BORDER_REG equ $E0C034 ; 0-3 = border, 4-7 Text color
VBL_VERT_REG equ $E0C02E
VBL_HORZ_REG equ $E0C02F
KBD_REG equ $E0C000
KBD_STROBE_REG equ $E0C010
VBL_STATE_REG equ $E0C019
MOD_REG equ $E0C025
COMMAND_KEY_REG equ $E0C061
OPTION_KEY_REG equ $E0C062
SHADOW_SCREEN equ $012000
SHR_SCREEN equ $E12000
SHR_SCB equ $E19D00
SHR_PALETTES equ $E19E00
; Direct page locations used by the engine
ScreenHeight equ 0 ; Height of the playfield in scan lines
ScreenWidth equ 2 ; Width of the playfield in bytes
@ -59,10 +79,12 @@ Next equ 86
BankLoad equ 128
tiletmp equ 186 ; 8 bytes of temp storage for the tile renderers
blttmp equ 192 ; 32 bytes of local cache/scratch space
AppSpace equ 160 ; 16 bytes of space reserved for application use
tmp8 equ 224
tiletmp equ 186 ; 8 bytes of temp storage for the tile renderers
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch
tmp9 equ 226
tmp10 equ 228
tmp11 equ 230
@ -89,3 +111,10 @@ DIRTY_BIT_BG1_REFRESH equ $0020

22
src/GTE.s Normal file
View File

@ -0,0 +1,22 @@
; Collection of the EXTernal labels exported by GTE. This is the closest thing
; we have to an API definition.
EngineStartUp EXT
EngineShutDown EXT
SetScreenMode EXT
ReadControl EXT
Render EXT
AddTimer EXT
RemoveTimer EXT
DoTimers EXT
StartScript EXT
StopScript EXT
; Super Hires line address lookup table for convenience
ScreenAddr EXT

118
src/Graphics.s Normal file
View File

@ -0,0 +1,118 @@
; Graphic screen initialization
InitGraphics
jsr ShadowOn
jsr GrafOn
lda #0
jsr ClearToColor
lda #0
jsr SetSCBs
ldx #DefaultPalette
lda #0
jsr SetPalette
rts
DefaultPalette dw $0000,$007F,$0090,$0FF0
dw $000F,$0080,$0f70,$0FFF
dw $0fa9,$0ff0,$00e0,$04DF
dw $0d00,$078f,$0ccc,$0FFF
; Return the current border color ($0 - $F) in the accumulator
GetBorderColor lda #0000
sep #$20
ldal BORDER_REG
and #$0F
rep #$20
rts
; Set the border color to the accumulator value.
SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z
eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z)
and #$0F ; ACC = $0_(Y^Z)
eorl BORDER_REG ; ACC = $W_(Y^Z^Z) = $W_Y
stal BORDER_REG
rep #$20
rts
; Clear to SHR screen to a specific color
ClearToColor ldx #$7D00 ;start at top of pixel data! ($2000-9D00)
:clearloop dex
dex
stal SHR_SCREEN,x ;screen location
bne :clearloop ;loop until we've worked our way down to 0
rts
; Set a palette values
; A = palette number, X = palette address
SetPalette
and #$000F ; palette values are 0 - 15 and each palette is 32 bytes
asl
asl
asl
asl
asl
txy
tax
]idx equ 0
lup 16
lda: $0000+]idx,y
stal SHR_PALETTES+]idx,x
]idx equ ]idx+2
--^
rts
; Initialize the SCB
SetSCBs ldx #$0100 ;set all $100 scbs to A
:scbloop dex
dex
stal SHR_SCB,x
bne :scbloop
rts
; Turn SHR screen On/Off
GrafOn sep #$20
lda #$81
stal NEW_VIDEO_REG
rep #$20
rts
GrafOff sep #$20
lda #$01
stal NEW_VIDEO_REG
rep #$20
rts
; Enable/Disable Shadowing.
ShadowOn sep #$20
ldal SHADOW_REG
and #$F7
stal SHADOW_REG
rep #$20
rts
ShadowOff sep #$20
ldal SHADOW_REG
ora #$08
stal SHADOW_REG
rep #$20
rts
GetVBL sep #$20
ldal VBL_HORZ_REG
asl
ldal VBL_VERT_REG
rol ; put V5 into carry bit, if needed. See TN #39 for details.
rep #$20
and #$00FF
rts
WaitForVBL sep #$20
:wait1 ldal VBL_STATE_REG ; If we are already in VBL, then wait
bmi :wait1
:wait2 ldal VBL_STATE_REG
bpl :wait2 ; spin until transition into VBL
rep #$20
rts

View File

@ -53,7 +53,13 @@
; This function examines the dirty bits and actually performs the work to update the code field
; and internal data structure to properly render the play field. Then the update pipeline is
; executed.
Render
Render ENT
phb
phk
plb
jsr _Render
plb
rtl
; TODO -- actually check the dirty bits and be selective on what gets updated. For example, if
; only the Y position changes, then we should only need to set new values on the
@ -63,7 +69,7 @@ Render
; It's important to do _ApplyBG0YPos first because it calculates the value of StartY % 208 which is
; used in all of the other loops
_Render
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
jsr _ApplyBG1YPos
@ -137,6 +143,11 @@ Render

62
src/Sprite.s Normal file
View File

@ -0,0 +1,62 @@
; Some sample code / utilities to help integrate compiled sprites int the GTE rendering
; pipeline.
;
; The main point of this file to to establish calling conventions and provide a framework
; for blitting a range of sprite lines, instead of always the full sprite.
; A = address, X = scroll_mask offset, Y = HHLL, LL = first line, HH = last line
draw
sei
cli
rts
lines dw line0,line1,line2,line3,line4,line5,line6,line7
line0
lda 0
and #$FF00
ora #$00DD
sta 0
line1
lda 0
and #$FF00
ora #$00DD
sta 0
line2
lda 0
and #$FF00
ora #$00DD
sta 0
line3
lda 0
and #$FF00
ora #$00DD
sta 0
line4
lda 0
and #$FF00
ora #$00DD
sta 0
line5
lda 0
and #$FF00
ora #$00DD
sta 0
line6
lda 0
and #$FF00
ora #$00DD
sta 0
line7
lda 0
and #$FF00
ora #$00DD
sta 0

View File

@ -215,7 +215,8 @@ CodeFieldOddBRA
bra *-6 ; 0 -- branch back 6 to skip the JMP even path
]step equ $2000
ScreenAddr lup 200
ScreenAddr ENT
lup 200
dw ]step
]step = ]step+160
--^
@ -256,3 +257,4 @@ BG1YOffsetTable lup 26