%begin ! ! Tiny Kernel for 6809 Graham Toal ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %vector NMI == $FFF0, %c IRQ == $FFF2, %c FIRQ == $FFF4, %c RESET == $FFF6 %const %byte NoIRQs = $20, NoFIRQs = $10 ;! Made-up values !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %const %byte TRUE = 0, FALSE = $FF !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %const %byte %array Lookup send count (1:20) = %c 5, 0, 5, 0, 5, 0, 0, 0, 5, 9, 5, 0, 8, 16, 16, 13, 1, 128, 8, 128 %const %byte %array Lookup send count (1:20) = %c 0, 5, 0, 5, 2, 5, 8, 14, 4, 1, 1, 5, 0, 16, 16, 16, 13, 0, 8, 128 %const %byte R1 = 0, R2 = 2, R3 = 4, R4 = 6, %c read mask = $80, write mask = $40 %const %byte ReadLn Upper bound Offset = 2, %c ReadLn Lower Bound Offset = 1, %c ReadLn Length Offset = 0 %const %byte %array %name NIL == 0 %const %byte %array %name Tube status == $F808, Tube data = $F800 %byte Returned CC, Returned A, Returned X, Returned Y !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %byte %array Entry Address (0:3) %routine Execute Last File Received *jsr _ Entry Address (2) %end !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %routine Put (%byte R, A) %cycle %repeat %until Tube status (R) & write mask # 0 Tube data (R) = A %end %routine Get (%byte R, %byte %name A) %cycle %repeat %until Tube status (R) & read mask # 0 A = Tube data (R) %end %routine Put String (%byte R, %byte %array %name Text) ! Local routine to send a string terminated by %byte Char, Next = 0 %cycle Char = Text (Next) Put (R, Char) %if Char = 13 %then %exit Next = Next + 1 %repeat %end %routine Get String (%byte R, %byte %array %name Text) ! Local routine to receive a string terminated by %byte Char, Next = 0 %cycle Get (R, Char) Text (Next) = Char %if Char = 13 %or Char = 0 %then %return Next = Next + 1 %repeat %end %routine Put block (%byte R, Count, %byte %array %name Block) %cycle Count = Count - 1 %if Count < 0 %then %exit Put (R, Block (Count) %repeat %end %routine Get block (%byte R, Count, %byte %array %name Block) %cycle Count = Count - 1 %if Count < 0 %then %exit Get (R, Block (Count) %repeat %end !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!! KERNEL INTERFACE !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %routine OSWRCH (%byte Char) Put (R1, Char) %end %byte %function OSRDCH %const %byte RdCh No = 0 Put (R2, RdCh No) Get (R2, Returned CC) Get (R2, Returned A) %result = Returned A %end %routine OSCLI (%byte %array %name Command) %const %byte Cli No = 2 Put (R2, Cli No) Put String (R2, Command) Get (R2, Returned CC) %if Returned CC = $80 %then Execute Last File Received %end %routine OSBYTE (%byte A, X, Y) %const %byte Short Byte No = 4, Byte No = 6 %if A < $80 %start Put (R2, Short Byte No) Put (R2, X) Put (R2, A) Get (R2, Returned X) %finish %else %if A = $82 %start %finish %else %if A = $83 %start %finish %else %if A = $84 %start %finish %else %start Put (R2, Byte No) Put (R2, X) Put (R2, Y) Put (R2, A) Get (R2, Returned CC) Get (R2, Returned Y) Get (R2, Returned X) %finish %end ! local routine for OSWORD to determine no of parameters ! to send/receive to IO processor %byte %function Send param count (%integer Osword No) %if Osword No < $14 %start %result = Lookup send count (OsWord No) %finish %else %start %result = 16 %finish %end %byte %function Receive param count (%integer Osword No) %if Osword No < $14 %start %result = Lookup receive count (OsWord No) %finish %else %start %result = 16 %finish %end %routine OSWORD (%integer A, %byte %array %name Param block) %const %byte RdLn No = $A, Word No = 8 %byte Count %if A = 0 %start Put (R2, RdLn No) Put (R2, Param block (RdLn Upper bound offset)) Put (R2, Param block (RdLn Lower bound offset)) Put (R2, Param block (RdLn Length offset)) Put (R2, $07) Put (R2, $00) ;! IO side Buffer address Get (R2, Returned CC) %if Returned CC & $80 # 0 %then %return ;! Escape pressed Get String (R2, Param block) %finish %else %start Put (R2, Word No) Put (R2, A) Count = Send param count (A) Put (R2, Count) Put block (R2, Count, Param block) Count = Receive param count (A) Get block (R2, Count, Param block) %finish %end %routine OSBPUT (%byte A, Y) %const %byte Bput No = $10 Put (R2, Bput No) Put (R2, Y) Put (R2, A) Get (R2, Returned CC) %end %byte %function OSBGET (%byte A) %const %byte Bget No = $0E Put (R2, Bget No) Put (R2, A) Get (R2, Returned CC) Get (R2, Returned A) %result = Returned A %end %byte %function OSFIND (%byte A, Y, %byte %array %name File) %const %byte Find No = $12 Put (R2, Find No) Put (R2, A) %if A = 0 %start Put (R2, Y) Get (R2, Returned A) %result = Returned A %finish PutString (R2, File) Get (R2, Returned A) %result = Returned A %end %routine OSARGS (%byte Opcode, Handle, %byte %array %name Address) %const %byte Args No = $0C %byte Offset Put (R2, Args No) Put (R2, Handle) Offset = 3 %cycle Put (R2, Address (Offset)) Offset = Offset - 1 ;! *** Order may need reversing for 6809 sex %repeat %until Offset < 0 Put (R2, Opcode) Get (R2, Returned A) Offset = 3 %cycle Get (R2, Address (Offset)) Offset = Offset - 1 ;! Ditto. %repeat %until Offset < 0 %end %routine OSFILE (%byte A, %byte %array %name File, Param block) %const %byte File No = $14 Put (R2, File No) Put Block (R2, 16, Param block) Put String (R2, File) Put (R2, A) !!!!!!!!!!!!!! Filing system transfers here under interrupt Get (R2, Returned A) Returned A = Returned A & $7F Get Block (R2, 16, Param block) %end %routine OSGBPB (%byte A, %byte %array %name Param block) %const %byte GBPB No = $16 Put (R2, GBPB No) Put block (R2, 13, Param block) Put (R2, A) Get block (R2, 13, Param block) Get (R2, Returned CC) Get (R2, Returned A) %end !!!!!!!!!!!!!!!!!!!!!!!!!! R1/R4 protocols !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %byte %array Event message (0:255) %byte Event Error code %byte DMA Finished %routine R3 Service (%byte Type) ! R3 interrupts come in under the masked IRQ/SYNC mechanism %byte Claim type, Next, Junk Get (R4, Claim type) %if Type = 5 %start DMA Finished = TRUE %finish %else %start Get (R4, Base address (3)) Get (R4, Base address (2)) Get (R4, Base address (1)) Get (R4, Base address (0)) %if Type = 0 %start ! Single byte parasite to host DMA Finished = FALSE %cycle; %repeat %until Tube status (R4) & read mask # 0 *PSHS _ "CC" *ORCC _ NoIRQs *LDX _ Base address (2) *LDA _ Tube data (R4) %cycle *SYNC *LDA _ 0,X+ *STA _ Tube data (R3) %repeat %until DMA Finished = TRUE *STX _ Base address (2) *PULS _ "CC" %finish %else %if Type = 1 %start ! Single byte host to parasite DMA Finished = FALSE %cycle; %repeat %until Tube status (R4) & read mask # 0 *PSHS _ "CC" *ORCC _ NoIRQs *LDX _ Base address (2) *LDA _ Tube data (R4) %cycle *SYNC *LDA _ Tube data (R3) *STA _ 0,X+ %repeat %until DMA Finished = TRUE *STX _ Base address (2) *PULS _ "CC" %finish %else %if Type = 2 %start ! Double byte parasite to host DMA Finished = FALSE %cycle; %repeat %until Tube status (R4) & read mask # 0 *PSHS _ "CC" *ORCC _ NoIRQs *LDX _ Base address (2) *LDA _ Tube data (R4) %cycle *SYNC *LDD _ 0,X++ *STD _ Tube data (R3) ;! two consecutive addresses - one register %repeat %until DMA Finished = TRUE *STX _ Base address (2) *PULS _ "CC" %finish %else %if Type = 3 %start ! Double byte host to parasite DMA Finished = FALSE %cycle; %repeat %until Tube status (R4) & read mask # 0 *PSHS _ "CC" *ORCC _ NoIRQs *LDX _ Base address (2) *LDA _ Tube data (R4) %cycle *SYNC *LDD _ Tube data (R3) ;! two consecutive addresses - one register *STD _ 0,X++ %repeat %until DMA Finished = TRUE *STX _ Base address (2) *PULS _ "CC" %finish %else %if Type = 4 %start ! programme execute address Get (R4, Junk) Next = 3 %cycle Entry address (Next) = Base address (Next) Next = Next - 1 %repeat %until Next < 0 %finish %else %if Type = 6 %start ! Multiple byte parasite to host %cycle; %repeat %until Tube status (R4) & read mask # 0 *PSHS _ "CC" *ORCC _ NoIRQs!NoFIRQs *LDX _ Base address (2) *LDB _ #0 *$SETDP $F8 *Lda _ #$F8 *Tfr _ A,DP *Ldy _ #256 ! Push L4, followed by 127 times L2 *LDA _ Tube data (R4) !============================================================================= !FOR I = 0 TO 127 DO Ldb #$40 ;! 2 L2 BitB >TubeStatus+R3 ;! 4 Beq L2 ;! 3 Lda >TubeData+R3 ;! 4 L3 BitB >TubeStatus+R3 ;! 4 Beq L3 ;! 3 Ldb >TubeData+R3 ;! 4 Std ,X++ ;! 8 !ENDDO !============================================================================= *STX _ Base address (2) *PULS _ "CC" %finish %else %if Type = 7 %start ! Multiple byte host to parasite %cycle; %repeat %until Tube status (R4) & read mask # 0 *PSHS _ "CC" *ORCC _ NoIRQs!NoFIRQs *LDX _ Base address (2) *LDB _ #0 *LDA _ Tube data (R4) 1: %cycle; %repeat %until Tube status (R3) < 0 *LDA _ B,X *STA _ Tube data (R3) *INC _ B *BNE _ L1 *LEAX _ 256,X *STX _ Base address (2) *PULS _ "CC" %finish %finish ;! any type except 5 %end %routine R4 Service ;! R1/R4 interrupts come in under FIRQ %byte R4 Type, Junk R4 Type = Tube data (R4) %if R4 Type < 0 %start Get (R4, Junk) Get (R4, Event Error code) Get String (R4, Event message) %finish %else %start R3 Service (R4 Type) %finish %end %byte %function Int r1 read %cycle %if Tube status (R4) & read mask # 0 %then R4 Service %repeat %until Tube status (R1) & read mask # 0 %result = Tube data (R1) %end !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %byte %array Command (0:255) %on %event RESET %start Print string ("Acorn 6809 62K Simple command interpreter "); OSWRCH (0); ! +... Get (R2, Startup) %if Startup = $80 %then Execute Last File Received Prompt ("$ ") %cycle Read line (Command) OSCLI (Command) %repeat %finish %on %event FIRQ %start %byte Event A, Event X, Event Y %byte R1 Type R1 Type = Int r1 read %if R1 Type < 0 %start Escape flag = Int Type & $40 %return %finish Event Y = Int r1 read Event X = Int r1 read Event A = Int r1 read %return %finish !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!! IO Library etc. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %const %byte NL = 10, CR = 13, LF = 10, FF = 12 %byte %array %name Prompt string == "Data:" %byte Echo = TRUE, Last was NL = TRUE %routine Set echoing (%byte ON or OFF) Echo = ON or OFF %end %routine Print symbol (%byte Char) %if Char = NL %then OSWRCH (CR) OSWRCH (Char) %end %routine Print string (%byte %array %name String) %byte Char, Next = 0 %cycle Char = String (Next) %if Char = 0 %then %exit Print symbol (Char) Next = Next + 1 %repeat %end %routine New line Print symbol (NL) %end %routine New page Print symbol (FF) %end %routine Read symbol (%byte %name Char) %if Echo=TRUE %and Last was NL=TRUE %then Print string (Prompt string) OSRDCH (Char) %if Char = CR %start Char = NL Last was NL = TRUE %finish %else Last was NL = FALSE %if Echo=TRUE %then Print symbol (Char) %end %routine Skip symbol %byte Lost Read symbol (Lost) %end %routine Read line (%byte %array %name Line) ;! read a 0 terminated line %byte Char, Next = 0 ;! with no CR or LF %if Echo=TRUE %start Line (RdLn Length Offset) = 255 Line (RdLn Lower Bound Offset) = 32 ;! filter out controls Line (RdLn Upper Bound Offset) = 126 ;! and deletes OSWORD (0, Line) Last was NL = TRUE %finish %else %start %cycle Read symbol (Char) %if Char = NL %then %exit Line (Next) = Char Next = Next + 1 %repeat %finish Next = 0 Next = Next + 1 %while Line (Next) >= 32 Line (Next) = 0 %end %routine Prompt (%byte %array %name String) Prompt string = String %end !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!! Applications code goes here !!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! %end %of %programme