Skip to content

Instantly share code, notes, and snippets.

@JettMonstersGoBoom
Last active October 16, 2020 02:07
Show Gist options
  • Save JettMonstersGoBoom/fcd00dc4eaf98e501fd12b2bb07a6dc8 to your computer and use it in GitHub Desktop.
Save JettMonstersGoBoom/fcd00dc4eaf98e501fd12b2bb07a6dc8 to your computer and use it in GitHub Desktop.
//-------------------------------------------------------------
// Simple example of a tasking system
//-------------------------------------------------------------
// we only write CODE and DATA ( not VTABLE or ZP )
.file [name="tasker.prg", segments="CODE,DATA"]
.segment ZP [start=$02] // doesn't get written to the prg
.segment CODE [start=$0801]
.segment DATA [startAfter="CODE"]
.segment VTABLE [startAfter= "DATA",virtual,align=256] // doesn't get written to the prg
.segment CODE
//-------------------------------------------------------------
// This creates a basic sys line that can start your program
//-------------------------------------------------------------
BasicUpstart2(Start)
// Our code
Start:
{
// just to disable the kernal messing around
sei
// Initialize the TaskOS
jsr TaskOS.Init
// add some sample tasks
TaskOS_RegisterFunction(Sample_Ticker,5) // add Sample_Ticker and call it every 5 frames
TaskOS_RegisterFunction(Sample_Object,0) // add Sample_Object and call it right away
TaskOS_RegisterFunction(Sample_Object,240) // same but wait 240 frames first
// basic test
// wait for raster in middle of screen
vbl:
lda $d012
cmp #$80
bne vbl
// step the TaskOS
inc $d020
jsr TaskOS.Step
dec $d020
jmp vbl
}
//-------------------------------------------------------------
// just the bare example
// change first visible char on screen
//-------------------------------------------------------------
Sample_Ticker:
inc $0400
rts
//-------------------------------------------------------------
// more namespacey example
//-------------------------------------------------------------
Sample_Object:
{
.segment ZP
temp_var: .byte 0
// we can put our INIT function here
//
.segment CODE
// init gets called when the task is first called
Init:
{
// X is already this value
// though if you trash X
// you can get it back like this
ldx TaskOS.Step.CurrentTask
// we put an I on the screen
lda #'i'
sta $0400,x
// X is the current running task index
// so we use it to make a new value for delay
txa
asl
asl
asl
asl
// set our time and reset time to this value
sta TaskOS.ResetTime,x
sta TaskOS.Timer,x
// Change the function pointer
// to Update
TaskOS_SwitchFunction(Update)
rts
}
// we could skip the RTS above here and fall through to
// Init and Update in one shot, but we don't here for clarity
// The next "tick" after Init
Update:
{
// show we're update loop with U on screen
lda #'u'
sta $0400,x
// update the char underneath
inc $0428,x
rts
}
}
//-------------------------------------------------------------
// Simple Task OS type system
//-------------------------------------------------------------
// add's a new function to the OS
.macro TaskOS_RegisterFunction(func,Timer) {
ldx #Timer
lda #<func
ldy #>func
jsr TaskOS.RegisterFunction
}
// sets the current function index (X)
// to new function
.macro TaskOS_SwitchFunction(func) {
lda #<func
ldy #>func
jsr TaskOS.SwitchFunction
}
TaskOS:
{
.label MAX_TASKS = 16
// we use virtual segment here
// we don't need to store this data inside the prg
.segment VTABLE
Timer: .fill MAX_TASKS,0
ResetTime: .fill MAX_TASKS,0
UpdateLSB: .fill MAX_TASKS,0
UpdateMSB: .fill MAX_TASKS,0
TaskIndex: .fill 1,0
// the code
.segment CODE
Init:
{
ldx #MAX_TASKS-1
stx TaskIndex
!:
lda #$00
sta Timer,x
sta ResetTime,x
lda #$00
sta UpdateMSB,x
sta UpdateLSB,x
dex
bpl !-
rts
}
// assume X is set to current task index
// ay is function
SwitchFunction: {
sta UpdateLSB,x
tya
sta UpdateMSB,x
rts
}
// Add a new function
// ay is function
// x is Timer countdown
RegisterFunction: {
stx mod_time
ldx TaskIndex
sta UpdateLSB,x
tya
sta UpdateMSB,x
// self mod
.label mod_time = *+1
lda #$00
sta Timer,x
sta ResetTime,x
dec TaskIndex
bpl noerror
// crash with a red screen if we run out of space
lda #$02
sta $d020
jmp *
noerror:
rts
}
Step:
{
ldx #MAX_TASKS-1
!:
// Check we have a function to call.
// limitation is we can't have code in the zero page.
lda UpdateMSB,x
beq SkipTask
// store value in our selfmod section
sta TaskFunction+2
lda UpdateLSB,x
sta TaskFunction+1
// if ResetTime == 0 then ALWAYS run this task
lda ResetTime,x
beq StepTask
// count down
// if not zero then go to next task
dec Timer,x
bne SkipTask
StepTask:
// store X for safekeeping
stx CurrentTask
// this value is written over by the above code
// selfmod
TaskFunction:
jsr $dead
// more selfmod
// this is the X value of the current task
.label CurrentTask = *+1
ldx #$00
lda ResetTime,x
sta Timer,x
SkipTask:
dex
bpl !-
rts
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment