949 lines
22 KiB
Plaintext
949 lines
22 KiB
Plaintext
|
====================================================================
|
|||
|
DR 6502 AER 201S Engineering Design 6502 Execution Simulator
|
|||
|
====================================================================
|
|||
|
|
|||
|
Supplementary Notes By: M.J.Malone
|
|||
|
|
|||
|
|
|||
|
Advanced 6502 Assembly Code Examples
|
|||
|
====================================
|
|||
|
|
|||
|
The remainder of this file will be in a format acceptable to
|
|||
|
TASM for direct assembly. Note there may be errors in the code, it
|
|||
|
is not intended that it be cut up and included in students files.
|
|||
|
It is meant only as an example of addressing modes and
|
|||
|
instructions. The first example is a prime number finder. The
|
|||
|
second example is a set of subroutines to maintain a multitasking
|
|||
|
system.
|
|||
|
|
|||
|
|
|||
|
;==============================================================================
|
|||
|
; Advanced Coding Examples for the Students of AER201S
|
|||
|
;==============================================================================
|
|||
|
;
|
|||
|
;
|
|||
|
.ORG $E000
|
|||
|
SEI ; INITIALIZING THE STACK POINTER
|
|||
|
LDX #$FF
|
|||
|
TXS
|
|||
|
;
|
|||
|
LDX #$00
|
|||
|
LDY #$00
|
|||
|
Delay DEX
|
|||
|
BNE Delay
|
|||
|
DEY
|
|||
|
BNE Delay
|
|||
|
;
|
|||
|
;=============================================================================
|
|||
|
; Prime Number Finder
|
|||
|
;=============================================================================
|
|||
|
; This Prime Number Finder uses the sieve method to find the primes up to 255
|
|||
|
; and then uses those primes to find the primes up to 65535. Note that this
|
|||
|
; is of course not THE most efficient way to find primes but it makes a good
|
|||
|
; demonstration.
|
|||
|
; It would be neat to stack this code up against a casually written/optimized
|
|||
|
; compiled C prime number finder on a raging 386. I have a feeling there will
|
|||
|
; be less than a factor of ten difference on execution speed. You may be
|
|||
|
; surprised just how fast the 6502 is on simple problems.
|
|||
|
;
|
|||
|
Test_num = $00 ; Test Number to Eliminate non-primes
|
|||
|
Array = $00 ; Base Address for the array of primes
|
|||
|
;
|
|||
|
;
|
|||
|
lda #$01
|
|||
|
sta $a003
|
|||
|
lda #$01
|
|||
|
sta $a001 ; Turns on an LED on bit zero of port A of VIA 1
|
|||
|
; to let you know it has started looking for primes
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 2
|
|||
|
|
|||
|
ldx #$01 ; Initialize the array of numbers
|
|||
|
Init_Loop txa
|
|||
|
sta Array,x
|
|||
|
inx
|
|||
|
bne Init_loop
|
|||
|
;
|
|||
|
lda #$02 ; Initialize the Test_num = 2
|
|||
|
sta Test_num
|
|||
|
lda #$04 ; Put the square of 2 in the accumulator
|
|||
|
; as the first non-prime
|
|||
|
;
|
|||
|
; Start Setting the Multiples of the Test_num to zero
|
|||
|
Start_num
|
|||
|
Got_Mult tax
|
|||
|
stz Array,x ; Set multiples of Test_num to zero since they
|
|||
|
clc ; are not prime.
|
|||
|
adc Test_num ; Calculate the next multiple
|
|||
|
bcs Next_num ; Until the Multiples are outside the array
|
|||
|
jmp Got_Mult
|
|||
|
;
|
|||
|
Next_num inc Test_num ; Go on to the next Test_num
|
|||
|
ldx Test_num
|
|||
|
cpx #$10 ; Until Test_num => sqrt(largest number)
|
|||
|
beq More_Primes
|
|||
|
lda Array,x
|
|||
|
beq Next_num ; Don't use Test_num if Test_num is not prime
|
|||
|
txa
|
|||
|
; Got a valid new Test_num, now find its square because all non-primes
|
|||
|
; multiples less than its square are eliminated already
|
|||
|
dex
|
|||
|
clc
|
|||
|
Square adc Test_num
|
|||
|
dex
|
|||
|
bne Square
|
|||
|
; OK Got the square of Test_num in the accumulator
|
|||
|
; lets start checking
|
|||
|
jmp Start_num
|
|||
|
;
|
|||
|
;
|
|||
|
More_Primes
|
|||
|
;
|
|||
|
; Ok now we have all the primes up to 255 in the memory locations $01-$FF
|
|||
|
; Lets repack them more neatly into an array with no spaces to make our
|
|||
|
; life easier
|
|||
|
;
|
|||
|
ldx #$00 ; .X is a pointer into the loose array
|
|||
|
ldy #$01 ; .Y is a pointer into the packed array
|
|||
|
Repack inx
|
|||
|
beq Done_packing
|
|||
|
lda Array,x
|
|||
|
beq Repack
|
|||
|
sta Array,y
|
|||
|
iny
|
|||
|
jmp Repack
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 3
|
|||
|
|
|||
|
Prime_Ptr = $F0 ; This is a points into the list of primes greater
|
|||
|
; than $FF and less that $10000
|
|||
|
;
|
|||
|
Poss_Prime = $F2 ; Possible prime
|
|||
|
Temp = $F4 ; A Temporary Number used to find modulus
|
|||
|
Shift = $F6 ; Number of Places that .A is shifted
|
|||
|
TempArg = $F7 ; A temporary number; argument of modulus
|
|||
|
|
|||
|
;
|
|||
|
Done_packing
|
|||
|
lda #$00 ; Store a $00 at the end of the array of short
|
|||
|
sta Array,y ; primes so we know when we have reached the end
|
|||
|
lda #$00
|
|||
|
sta Prime_ptr ; Set the Prime Pointer (for primes >$FF)
|
|||
|
lda #$02 ; pointing into $0200. The found primes will be
|
|||
|
sta Prime_ptr+1 ; recorded sequentially from there on.
|
|||
|
;
|
|||
|
lda #$01 ; Start with $0101 as the first possible prime
|
|||
|
sta Poss_Prime
|
|||
|
sta Poss_Prime+1
|
|||
|
;
|
|||
|
Next_PP ldy #$02
|
|||
|
Next_AP lda Array,y
|
|||
|
beq Prime
|
|||
|
jsr Mod
|
|||
|
beq Next_Poss_prime ; it was a multiple of Array,y
|
|||
|
; and therefore not prime
|
|||
|
iny
|
|||
|
jmp Next_AP
|
|||
|
;
|
|||
|
Prime ldx #$00
|
|||
|
lda Poss_prime ; Store prime away in the array of primes
|
|||
|
sta (Prime_ptr,x)
|
|||
|
inx
|
|||
|
lda Poss_prime+1
|
|||
|
sta (Prime_ptr,x)
|
|||
|
clc
|
|||
|
lda Prime_ptr ; Increment the pointer in the array of primes
|
|||
|
adc #$02
|
|||
|
sta Prime_ptr
|
|||
|
lda Prime_ptr+1
|
|||
|
adc #$00
|
|||
|
sta Prime_ptr+1
|
|||
|
;
|
|||
|
Next_Poss_prime
|
|||
|
clc ; Increment Poss_Prime to look at the next
|
|||
|
lda Poss_Prime ; number
|
|||
|
adc #$01
|
|||
|
sta Poss_Prime
|
|||
|
lda Poss_Prime+1
|
|||
|
adc #$00
|
|||
|
sta Poss_Prime+1
|
|||
|
bcc Next_PP ; Carry will be set when we reach $10000
|
|||
|
;
|
|||
|
; Ends when it has found all the primes up to 65535
|
|||
|
;
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 4
|
|||
|
|
|||
|
lda #$00
|
|||
|
sta $a001 ; Turns off the LED after the code finishes
|
|||
|
;
|
|||
|
DONE JMP DONE ; Endless loop at end to halt execution
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
; --------------------------------------------------------------------------
|
|||
|
; Find the Modulus Remainder of Poss_Prime and number in A
|
|||
|
; --------------------------------------------------------------------------
|
|||
|
; Input Regs: .A Number being divided into the Possible Prime
|
|||
|
; Poss_Prime contains the number being tested for primeness
|
|||
|
; Output Regs: .A Modulo remainder
|
|||
|
;
|
|||
|
Mod ldx Poss_Prime ; Transfer Poss_Prime to Temp
|
|||
|
stx Temp
|
|||
|
ldx Poss_Prime+1
|
|||
|
stx Temp+1
|
|||
|
ldx #$00 ; Set the bit shifting counter to #$00
|
|||
|
stx Shift
|
|||
|
;
|
|||
|
; Compare A to the upper byte of Temp
|
|||
|
;
|
|||
|
Compare sec ; Compare to see if the .A is greater than
|
|||
|
cmp Temp+1 ; (equal to) the high byte of Temp
|
|||
|
bcs A_Bigger
|
|||
|
;
|
|||
|
; If the accumulator is smaller than the upper byte of Temp then shift it
|
|||
|
; until it is bigger or it overflows the highest bit
|
|||
|
;
|
|||
|
clc
|
|||
|
rol a
|
|||
|
bcc Not_off_end
|
|||
|
;
|
|||
|
; It has overflowed the highest bit, unroll it by one position
|
|||
|
;
|
|||
|
ror a
|
|||
|
sta TempArg
|
|||
|
jmp Start_Mod
|
|||
|
;
|
|||
|
; Not overflowed yet, go and compare it to Temp+1 again
|
|||
|
;
|
|||
|
Not_off_end inc Shift
|
|||
|
jmp Compare
|
|||
|
;
|
|||
|
; If the accumulator is bigger and it has been shifted then unshift by one
|
|||
|
; bit
|
|||
|
;
|
|||
|
A_Bigger ldx Shift
|
|||
|
cpx #$00
|
|||
|
sta TempArg
|
|||
|
beq Start_Mod
|
|||
|
clc
|
|||
|
ror a
|
|||
|
dec Shift
|
|||
|
sta TempArg
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 5
|
|||
|
|
|||
|
; If the accumulator was smaller than the highest byte of Temp it now
|
|||
|
; has been shifted to strip off the high bit at least
|
|||
|
; If the accumulator was larger than the highest byte then proceed with the
|
|||
|
; regular modulus shift and subtracts
|
|||
|
;
|
|||
|
Start_Mod lda Temp+1
|
|||
|
sec
|
|||
|
cmp TempArg
|
|||
|
bcc Dont_Subt
|
|||
|
;
|
|||
|
; Subtract as a stage of division
|
|||
|
;
|
|||
|
sbc TempArg
|
|||
|
sta Temp+1
|
|||
|
;
|
|||
|
Dont_Subt
|
|||
|
;
|
|||
|
; We would now like to shift the TempArg relative the Temp
|
|||
|
; 1) Shift is greater than zero - accumulator was shifted - unshift it
|
|||
|
; 2) Shift Temp - if shift reaches -8 then we are out of Temp and
|
|||
|
; what we have left is the modulus --RTS
|
|||
|
;
|
|||
|
lda Shift
|
|||
|
bmi Sh_Temp ; Case 2
|
|||
|
beq Sh_Temp
|
|||
|
; Case 1
|
|||
|
clc
|
|||
|
ror TempArg
|
|||
|
dec Shift
|
|||
|
jmp Start_Mod
|
|||
|
;
|
|||
|
Sh_Temp cmp #$f8
|
|||
|
bne Continue
|
|||
|
lda Temp+1 ; This is the Modulus
|
|||
|
rts
|
|||
|
|
|||
|
Continue dec Shift
|
|||
|
clc
|
|||
|
rol Temp
|
|||
|
rol Temp+1
|
|||
|
jmp Start_Mod
|
|||
|
;
|
|||
|
.ORG $FFFC
|
|||
|
.WORD $E000
|
|||
|
.END
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;==============================================================================
|
|||
|
;******************************************************************************
|
|||
|
;==============================================================================
|
|||
|
;
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 6
|
|||
|
|
|||
|
;=============================================================================
|
|||
|
; The Multitasking 6502 - See you 6502 do several things at once
|
|||
|
;=============================================================================
|
|||
|
; This relies on the assumption that there is a source of IRQ's out there
|
|||
|
; that is repetitive and each task is allotted time between each IRQ.
|
|||
|
; Process 1 is started automatically by the RESET signal.
|
|||
|
; Any process can extend its life for a while (if it is doing something
|
|||
|
; important) by setting the SEI and then CLI after the important section.
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
.ORG $E000
|
|||
|
SEI ; INITIALIZING THE STACK POINTER
|
|||
|
LDX #$FF
|
|||
|
TXS
|
|||
|
;
|
|||
|
LDX #$00
|
|||
|
LDY #$00
|
|||
|
Delay DEX
|
|||
|
BNE Delay
|
|||
|
DEY
|
|||
|
BNE Delay
|
|||
|
;
|
|||
|
; Each Process has a reserved space in memory starting with process 1 at
|
|||
|
; $0200-$03FF, process 2 at $0400-$05FF. With this model, an 8K RAM can
|
|||
|
; support 15 such processes provided none of the RAM outside zero page and
|
|||
|
; stack is used during the execution of a particular process.
|
|||
|
;
|
|||
|
M_box = $F0 ; A Mailbox used to communicate between processes
|
|||
|
Com1 = $F8 ; User Communications Channel to other processes
|
|||
|
Com2 = $F9
|
|||
|
Temp = $FA ; A temporary variable used during SWAPS and SPAWNS
|
|||
|
Proc_Ptr = $FB ; Pointer to the reserved space of the current process
|
|||
|
Proc = $FC ; Current process number
|
|||
|
Proc_N = $FE ; Actual Number for active Processes
|
|||
|
Proc_M = $FF ; Maximum Number of Processes that have been concurrent
|
|||
|
;
|
|||
|
; A Process Record Consists of:
|
|||
|
; Offset Purpose
|
|||
|
; ------ -------
|
|||
|
; 00 Priority
|
|||
|
; 01 Priority Counter
|
|||
|
; 02 Accumulator
|
|||
|
; 03 X Register
|
|||
|
; 04 Y Register
|
|||
|
; 05 Stack Pointer
|
|||
|
;
|
|||
|
; 10-FF Zero Page Memory from $00-$EF
|
|||
|
; 100-1FF System Stack Space
|
|||
|
;
|
|||
|
lda #$01 ; Initialize the start up process as 1
|
|||
|
sta Proc
|
|||
|
sta Proc_N ; Set the number of processes to 1
|
|||
|
sta $0200 ; Set the priority of process 1 to 1
|
|||
|
lda #$00
|
|||
|
sta $0201 ; Set the priority counter of process 1 to 0
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 7
|
|||
|
|
|||
|
lda #$00
|
|||
|
sta Proc_Ptr ; Initialize the process pointer to point to
|
|||
|
lda #$02 ; Process 1 reserved space $0200-$03FF
|
|||
|
sta Proc_Ptr+1
|
|||
|
JMP Start_Code
|
|||
|
;
|
|||
|
;===========================================================================
|
|||
|
; IRQ Subroutine to Swap Tasks
|
|||
|
;===========================================================================
|
|||
|
;
|
|||
|
IRQ_VECT sta Temp ; Store .A Temporarily
|
|||
|
;
|
|||
|
; If there is only one active process currently then just return
|
|||
|
;
|
|||
|
lda Proc_N
|
|||
|
cmp #$01
|
|||
|
bne Cont_Swap1
|
|||
|
lda Temp
|
|||
|
rti
|
|||
|
;
|
|||
|
; Continue there is more than one Process
|
|||
|
;
|
|||
|
Cont_Swap1 tya
|
|||
|
pha
|
|||
|
;
|
|||
|
; Check process priority counter. If it equals the priority of the process
|
|||
|
; then attempt to swap in another process
|
|||
|
;
|
|||
|
ldy #$00
|
|||
|
lda (Proc_Ptr),y ; Load Priority Number
|
|||
|
beq Swap_In ; If 'killed' process then just swap in another
|
|||
|
iny
|
|||
|
inc (Proc_Ptr),y ; Increment Priority Counter
|
|||
|
cmp (Proc_Ptr),y
|
|||
|
beq Cont_Swap2
|
|||
|
;
|
|||
|
; Not done this Process, Return
|
|||
|
;
|
|||
|
pla
|
|||
|
tay
|
|||
|
lda Temp
|
|||
|
rti
|
|||
|
;
|
|||
|
; Other Processes available and this one is done: S W A P O U T
|
|||
|
;
|
|||
|
Cont_Swap2 pla
|
|||
|
ldy #$04
|
|||
|
sta (Proc_Ptr),y ; Save .Y
|
|||
|
dey
|
|||
|
txa
|
|||
|
sta (Proc_Ptr),y ; Save .X
|
|||
|
dey
|
|||
|
lda Temp
|
|||
|
sta (Proc_Ptr),y ; Save .A
|
|||
|
ldy #$05
|
|||
|
tsx
|
|||
|
txa
|
|||
|
sta (Proc_Ptr),y ; Save .SP
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 8
|
|||
|
|
|||
|
;
|
|||
|
; Swap Zero Page ($00-$EF) to (Proc_Ptr + $10-$FF)
|
|||
|
;
|
|||
|
ldy #$00
|
|||
|
lda #$10
|
|||
|
sta Proc_Ptr
|
|||
|
Out_Zero lda $00,y
|
|||
|
sta (Proc_Ptr),y
|
|||
|
iny
|
|||
|
cpy #$f0
|
|||
|
bne Out_Zero
|
|||
|
;
|
|||
|
; Swap System Stack
|
|||
|
;
|
|||
|
lda #$00
|
|||
|
sta Proc_Ptr
|
|||
|
inc Proc_Ptr+1
|
|||
|
tsx
|
|||
|
txa
|
|||
|
tay
|
|||
|
Out_Stack iny
|
|||
|
beq Swap_In
|
|||
|
lda $0100,y
|
|||
|
sta (Proc_Ptr),y
|
|||
|
jmp Out_Stack
|
|||
|
;
|
|||
|
;
|
|||
|
; Look for the next process to swap in
|
|||
|
;
|
|||
|
Swap_In
|
|||
|
Another lda Proc ; Looking for another process to Swap in
|
|||
|
cmp Proc_M
|
|||
|
bne Not_End
|
|||
|
;
|
|||
|
; Go back to Process #1
|
|||
|
;
|
|||
|
lda #$01
|
|||
|
sta Proc
|
|||
|
lda #$02
|
|||
|
sta Proc_Ptr+1
|
|||
|
jmp Check_Proc
|
|||
|
;
|
|||
|
; Go to the next Process
|
|||
|
;
|
|||
|
Not_End clc
|
|||
|
lda Proc_Ptr+1
|
|||
|
adc #$02
|
|||
|
sta Proc_Ptr+1
|
|||
|
inc Proc
|
|||
|
;
|
|||
|
; Check this Process if Non-Active, go try another
|
|||
|
;
|
|||
|
ldy #$00
|
|||
|
lda (Proc_Ptr),y
|
|||
|
beq Another
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 9
|
|||
|
|
|||
|
; Found an Acceptable Process: S W A P I N
|
|||
|
;
|
|||
|
;
|
|||
|
; Get the Stack Pointer
|
|||
|
;
|
|||
|
ldy #$05
|
|||
|
lda (Proc_Ptr),y ; Restore .SP
|
|||
|
tax
|
|||
|
txs
|
|||
|
;
|
|||
|
; Swap In Zero Page ($00-$EF) to (Proc_Ptr + $10-$FF)
|
|||
|
;
|
|||
|
ldy #$00
|
|||
|
lda #$10
|
|||
|
sta Proc_Ptr
|
|||
|
In_Zero lda (Proc_Ptr),y
|
|||
|
sta $00,y
|
|||
|
iny
|
|||
|
cpy #$f0
|
|||
|
bne In_Zero
|
|||
|
;
|
|||
|
; Swap System Stack
|
|||
|
;
|
|||
|
lda #$00
|
|||
|
sta Proc_Ptr
|
|||
|
inc Proc_Ptr+1
|
|||
|
tsx
|
|||
|
txa
|
|||
|
tay
|
|||
|
In_Stack iny
|
|||
|
beq Restore_Regs
|
|||
|
lda (Proc_Ptr),y
|
|||
|
sta $0100,y
|
|||
|
jmp In_Stack
|
|||
|
;
|
|||
|
; Restore all of the system registers
|
|||
|
;
|
|||
|
Restore_Regs
|
|||
|
lda #$00
|
|||
|
sta Proc_Ptr
|
|||
|
dec Proc_Ptr+1
|
|||
|
ldy #$01 ; Set Priority Counter to 0
|
|||
|
sta (Proc_Ptr),y
|
|||
|
iny
|
|||
|
lda (Proc_Ptr),y ; Temporarily store .A
|
|||
|
sta Temp
|
|||
|
iny
|
|||
|
lda (Proc_Ptr),y ; Restore .X
|
|||
|
tax
|
|||
|
iny
|
|||
|
lda (Proc_Ptr),y ; Restore .Y
|
|||
|
tay
|
|||
|
lda Temp ; Restore .A
|
|||
|
rti
|
|||
|
;--------------------- Done the Swap ----------------------
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 10
|
|||
|
|
|||
|
;==========================================================
|
|||
|
; Spawn a New Process
|
|||
|
;==========================================================
|
|||
|
; PHA Process PCH
|
|||
|
; PHA Process PCL
|
|||
|
; PHA Process Priority
|
|||
|
; JSR Spawn High
|
|||
|
; Spawn Low
|
|||
|
;
|
|||
|
;
|
|||
|
Spawn lda Proc_Ptr+1 ; Store Current Process Pointer
|
|||
|
sta Temp
|
|||
|
lda Proc ; Store Current Process Number
|
|||
|
pha
|
|||
|
lda #$01 ; Set Process Pointer and Number to 1
|
|||
|
sta Proc
|
|||
|
lda #$02
|
|||
|
sta Proc_Ptr+1
|
|||
|
;
|
|||
|
Free_Check ; See if there is an old process number no longer
|
|||
|
ldy #$00 ; in use
|
|||
|
lda (Proc_Ptr),y
|
|||
|
beq Got_Free
|
|||
|
inc Proc
|
|||
|
clc
|
|||
|
lda Proc_Ptr+1
|
|||
|
adc #$02
|
|||
|
sta Proc_Ptr+1
|
|||
|
lda Proc_M
|
|||
|
sec
|
|||
|
cmp Proc
|
|||
|
bcs Free_Check
|
|||
|
inc Proc_M ; Have to create an extra Process
|
|||
|
inc Proc_N
|
|||
|
;
|
|||
|
; Ok we are clear, Create this Process
|
|||
|
;
|
|||
|
Got_Free tsx ; Get the current stack pointer
|
|||
|
txa
|
|||
|
clc
|
|||
|
adc #$05
|
|||
|
tax ; Set x to point at Priority
|
|||
|
;
|
|||
|
ldy #$00
|
|||
|
lda $0100,x ; Transfer Priority to Process Space
|
|||
|
sta (Proc_Ptr),y
|
|||
|
;
|
|||
|
ldy #$05 ; Set .sp = #$FC
|
|||
|
lda #$FC
|
|||
|
sta (Proc_Ptr),y
|
|||
|
;
|
|||
|
ldy #$02 ; Set the accumulator to 1 to indicate: START
|
|||
|
lda #$01 ; to the new process
|
|||
|
sta (Proc_Ptr),y
|
|||
|
;
|
|||
|
inc Proc_Ptr+1 ; To point into stack swap space for this process
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 11
|
|||
|
|
|||
|
lda #$00 ; Processor Status Register, for this process
|
|||
|
ldy #$FD
|
|||
|
sta (Proc_Ptr),y
|
|||
|
;
|
|||
|
inx
|
|||
|
lda $0100,x ; Load PCL
|
|||
|
iny
|
|||
|
sta (Proc_Ptr),y ; Put into (swapped) Stack
|
|||
|
;
|
|||
|
inx
|
|||
|
lda $0100,x ; Load PCH
|
|||
|
iny
|
|||
|
sta (Proc_Ptr),y ; Put into (swapped) Stack
|
|||
|
;
|
|||
|
lda Temp ; Set Pointer back to original (Spawner) process
|
|||
|
sta Proc_Ptr+1
|
|||
|
;
|
|||
|
lda Proc ; Take Spawned Process number and put in Temp
|
|||
|
sta Temp
|
|||
|
;
|
|||
|
pla ; Restore Spawned Process number
|
|||
|
sta Proc
|
|||
|
;
|
|||
|
pla ; Pull 'Spawn' return address from stack
|
|||
|
tax
|
|||
|
pla
|
|||
|
tay
|
|||
|
;
|
|||
|
pla ; Pull Spawn data out of the stack
|
|||
|
pla
|
|||
|
pla
|
|||
|
;
|
|||
|
tya ; Push the Return Address back to the stack
|
|||
|
pha
|
|||
|
txa
|
|||
|
pha
|
|||
|
lda Temp ; Return Spawned Process Number
|
|||
|
rts
|
|||
|
;-------------- Done Spawn -----------------
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;=============================================================
|
|||
|
; Kill a Process
|
|||
|
;=============================================================
|
|||
|
;
|
|||
|
; Input Registers : NONE
|
|||
|
; Output Registers: NEVER RETURNS IF KILL IS SUCCESSFUL
|
|||
|
;
|
|||
|
Kill lda Proc_N
|
|||
|
cmp #$01 ; Can't Clear Last Process
|
|||
|
bne Ok_More
|
|||
|
rts
|
|||
|
Ok_More ldy #$00 ; OK Kill the Process, put a 0 in Priority
|
|||
|
tya
|
|||
|
sta (Proc_Ptr)
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 12
|
|||
|
|
|||
|
dec Proc_N ; One Less Process
|
|||
|
;
|
|||
|
lda Proc ; If we are clearing 'Maximum' Process then
|
|||
|
cmp Proc_M ; then reduce maximum
|
|||
|
beq Reduce_Max
|
|||
|
jmp Swap_In ; Otherwise Go swap another in
|
|||
|
;
|
|||
|
Reduce_Max
|
|||
|
dec Proc
|
|||
|
dec Proc_M
|
|||
|
dec Proc_Ptr+1
|
|||
|
dec Proc_Ptr+1
|
|||
|
lda (Proc_ptr),y
|
|||
|
beq Reduce_Max
|
|||
|
jmp Swap_In
|
|||
|
;---------------------- Done Clear a Process ---------------------------
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;=======================================================================
|
|||
|
; An Example Spawnable Process
|
|||
|
;=======================================================================
|
|||
|
; Input Registers: .A = #$00 Means that we just want the address of
|
|||
|
; (JSR Child) this process so that the process swapper
|
|||
|
; will know where to start.
|
|||
|
;
|
|||
|
; (RTI to CHILD1) .A = #$01 Means that the process swapper has signalled
|
|||
|
; this process to actually start
|
|||
|
;
|
|||
|
Child jsr Child1
|
|||
|
Child1 cmp #$00
|
|||
|
bne Go_For_It
|
|||
|
;
|
|||
|
; Process was called to get its start up address
|
|||
|
;
|
|||
|
pla ; Grab Child1 start up address
|
|||
|
clc
|
|||
|
adc #$01 ; Remember that an RTS return address points at the
|
|||
|
tax ; last byte of the JSR statement.
|
|||
|
pla ; RTI return addresses point to the first byte of the
|
|||
|
adc #$00 ; next instruction to be executed
|
|||
|
tay
|
|||
|
;
|
|||
|
pla ; Save Return Address to program calling Child
|
|||
|
sta Temp
|
|||
|
pla
|
|||
|
sta Proc_Ptr
|
|||
|
;
|
|||
|
tya ; Push Child1 RTI address
|
|||
|
pha
|
|||
|
txa
|
|||
|
pha
|
|||
|
;
|
|||
|
lda Proc_Ptr ; This Pushes the calling program's return address
|
|||
|
pha ; back into the stack
|
|||
|
lda Temp
|
|||
|
pha
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 13
|
|||
|
|
|||
|
lda #$00 ; Returns Proc_Ptr(low) to #$00 after its use as a
|
|||
|
sta Proc_Ptr ; Temporary variable
|
|||
|
rts
|
|||
|
;
|
|||
|
; Spawned Process actually starts:
|
|||
|
; Note that PLA's are not required to get rid of the JSR Child1 start up
|
|||
|
; address since the RTI address pushed in points to Child1 NOT Child
|
|||
|
Go_For_It
|
|||
|
|
|||
|
Body of the spawned process
|
|||
|
|
|||
|
;
|
|||
|
;
|
|||
|
;=======================================================================
|
|||
|
; An Example of a Kill of the present Process
|
|||
|
;=======================================================================
|
|||
|
;
|
|||
|
{ User Code }
|
|||
|
;
|
|||
|
sei
|
|||
|
jsr Kill ; This should kill the process unless it is the
|
|||
|
; only process
|
|||
|
cli
|
|||
|
;
|
|||
|
; This is the only process
|
|||
|
;
|
|||
|
{ More user code }
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;=======================================================================
|
|||
|
; Start of User Code
|
|||
|
;=======================================================================
|
|||
|
Start_Code
|
|||
|
{ Your first process goes here }
|
|||
|
;
|
|||
|
;
|
|||
|
; Example Spawn of Process 'Child'
|
|||
|
;
|
|||
|
sei ; Prevent swap attempts during process creation
|
|||
|
lda #$00
|
|||
|
jsr Child ; Request Address for Child1
|
|||
|
;
|
|||
|
lda #Priority
|
|||
|
pha ; Push Priority into the stack
|
|||
|
;
|
|||
|
jsr Spawn ; Ask the Process Swapper to set 'Child1' up in
|
|||
|
; the swap schedule
|
|||
|
rol a
|
|||
|
sta Ptr+1 ; Set pointer to the Child process zero page
|
|||
|
lda #$10 ; reserved area
|
|||
|
sta Ptr
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 14
|
|||
|
|
|||
|
; The Spawn call returns the process number. If there is some initial data
|
|||
|
; or a pointer that this process would like to pass to 'Child1' then the
|
|||
|
; address of its ZERO PAGE reserved data space is pointed to by '(Ptr),y'.
|
|||
|
; Once the data has been transferred:
|
|||
|
;
|
|||
|
cli ; Re-enable swap attempts
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;============================================================================
|
|||
|
; Example of Taking full control of execution temporarily
|
|||
|
;============================================================================
|
|||
|
;
|
|||
|
sei ; Disable swaps
|
|||
|
{ User Code }
|
|||
|
cli ; Re-enable swaps
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
;============================================================================
|
|||
|
; Example of taking full control by Killing all other processes
|
|||
|
;============================================================================
|
|||
|
;
|
|||
|
Ptr = $00
|
|||
|
K_Proc = $02
|
|||
|
;
|
|||
|
sei ; Disable swaps
|
|||
|
;
|
|||
|
lda #$00 ; Set Pointer to $0200
|
|||
|
sta Ptr
|
|||
|
lda #$02
|
|||
|
sta Ptr+1
|
|||
|
;
|
|||
|
lda #$01 ; Set Kill Process counter to 1
|
|||
|
sta K_Proc
|
|||
|
;
|
|||
|
Top lda Proc
|
|||
|
cmp K_Proc
|
|||
|
beq Don_t_Kill
|
|||
|
ldy #$00
|
|||
|
tya
|
|||
|
sta (Ptr),y
|
|||
|
;
|
|||
|
Don_t_Kill
|
|||
|
cmp Proc_M
|
|||
|
beq Done_Kill
|
|||
|
inc Ptr+1
|
|||
|
inc Ptr+1
|
|||
|
inc K_Proc
|
|||
|
jmp Top
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
page 15
|
|||
|
|
|||
|
Done_Kill
|
|||
|
lda #$01
|
|||
|
sta Proc_N
|
|||
|
lda Proc
|
|||
|
sta Proc_M
|
|||
|
cli ; Note that this is optional, if we know that there
|
|||
|
; are no other processes we could prevent swap decisions
|
|||
|
; by not clearing the IRQ mask.
|
|||
|
;
|
|||
|
{ More code that will not be swapped out }
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
.ORG $FFFC
|
|||
|
.WORD $E000
|
|||
|
.WORD IRQ_VECT
|
|||
|
.END
|
|||
|
;
|
|||
|
; -------------------- Done Multitasking example -------------------------
|
|||
|
|
|||
|
<eof>
|
|||
|
|