OpenCores
URL https://opencores.org/ocsvn/rtf65002/rtf65002/trunk

Subversion Repositories rtf65002

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 25 to Rev 26
    Reverse comparison

Rev 25 → Rev 26

/rtf65002/trunk/software/asm/asm.exe Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/rtf65002/trunk/software/asm/bootrom.asm
35,6 → 35,39
XON EQU 0x11
XOFF EQU 0x13
 
; error codes
E_Ok = 0x00
E_Arg = 0x01
E_BadMbx = 0x04
E_QueFull = 0x05
E_NoThread = 0x06
E_NotAlloc = 0x09
E_NoMsg = 0x0b
E_Timeout = 0x10
E_BadAlarm = 0x11
E_NotOwner = 0x12
; resource errors
E_NoMoreMbx = 0x40
E_NoMoreMsgBlks = 0x41
E_NoMoreAlarmBlks =0x44
E_NoMoreTCBs = 0x45
 
; task status
TS_NONE =0
TS_TIMEOUT =1
TS_WAITMSG =2
TS_PREEMP =4
TS_RUNNING =8
TS_READY =16
TS_WAITFOCUS = 32
 
 
; message queuing strategy
MQS_UNLIMITED =0 ; unlimited queue size
MQS_NEWEST =1 ; buffer queue size newest messages
MQS_OLDEST =2 ; buffer queue size oldest messages
 
 
TEXTSCR EQU 0xFFD00000
COLORSCR EQU 0xFFD10000
TEXTREG EQU 0xFFDA0000
45,6 → 78,13
KEYBDCLR EQU 0xFFDC0001
PIC EQU 0xFFDC0FF0
PIC_IE EQU 0xFFDC0FF1
TASK_SELECT EQU 0xFFDD0008
RQ_SEMA EQU 0xFFDB0000
TO_SEMA EQU 0xFFDB0010
SERIAL_SEMA EQU 0xFFDB0020
KEYBD_SEMA EQU 0xFFDB0030
IOF_LIST_SEMA EQU 0xFFDB0040
MBX_SEMA EQU 0xFFDB0050
 
SPIMASTER EQU 0xFFDC0500
SPI_MASTER_VERSION_REG EQU 0x00
77,37 → 117,142
RW_READ_SD_BLOCK EQU 0x02
RW_WRITE_SD_BLOCK EQU 0x03
 
BITMAPSCR EQU 0x04000000
SECTOR_BUF EQU 0x05FFEC00
UART EQU 0xFFDC0A00
UART_LS EQU 0xFFDC0A01
UART_MS EQU 0xFFDC0A02
UART_IS EQU 0xFFDC0A03
UART_IE EQU 0xFFDC0A04
UART_MC EQU 0xFFDC0A06
UART_CM1 EQU 0xFFDC0A09
UART_CM2 EQU 0xFFDC0A0A
UART_CM3 EQU 0xFFDC0A0B
txempty EQU 0x40
rxfull EQU 0x01
 
CONFIGREC EQU 0xFFDCFFF0
CR_CLOCK EQU 0xFFDCFFF4
GACCEL EQU 0xFFDAE000
 
ETHMAC EQU 0xFFDC2000
ETH_MODER EQU 0x00
ETH_INT_SOURCE EQU 0x01
ETH_INT_MASK EQU 0x02
ETH_IPGT EQU 0x03
ETH_IPGR1 EQU 0x04
ETH_IPGR2 EQU 0x05
ETH_PACKETLEN EQU 0x06
ETH_COLLCONF EQU 0x07
ETH_TX_BD_NUM EQU 0x08
ETH_CTRLMODER EQU 0x09
ETH_MIIMODER EQU 0x0A
ETH_MIICOMMAND EQU 0x0B
ETH_MIIADDRESS EQU 0x0C
ETH_MIITX_DATA EQU 0x0D
ETH_MIIRX_DATA EQU 0x0E
ETH_MIISTATUS EQU 0x0F
ETH_MAC_ADDR0 EQU 0x10
ETH_MAC_ADDR1 EQU 0x11
ETH_HASH0_ADDR EQU 0x12
ETH_HASH1_ADDR EQU 0x13
ETH_TXCTRL EQU 0x14
 
SPRITEREGS EQU 0xFFDAD000
SPRRAM EQU 0xFFD80000
 
THRD_AREA EQU 0x04000000 ; threading area 0x04000000-0x40FFFFF
BITMAPSCR EQU 0x04100000
SECTOR_BUF EQU 0x05FBEC00
BIOS_STACKS EQU 0x05FC0000 ; room for 256 1kW stacks
BIOS_SCREENS EQU 0x05C00000 ; 0x05C00000 to 0x05DFFFFF
 
BYTE_SECTOR_BUF EQU SECTOR_BUF<<2
PROG_LOAD_AREA EQU 0x4080000<<2
PROG_LOAD_AREA EQU 0x4180000<<2
INPUT_FOCUS EQU 0x05FBE000
OUTPUT_FOCUS EQU 0x05FBE001
 
macro m_lsr8
lsr
lsr
lsr
lsr
lsr
lsr
lsr
lsr
endm
eth_rx_buffer EQU 0x5F80000
eth_tx_buffer EQU 0x5F84000
 
macro m_asl8
asl
asl
asl
asl
asl
asl
asl
asl
endm
; Mailboxes, room for 2048
MBX_LINK EQU 0x05F90000
MBX_TQ_HEAD EQU 0x05F90800
MBX_TQ_TAIL EQU 0x05F91000
MBX_MQ_HEAD EQU 0x05F91800
MBX_MQ_TAIL EQU 0x05F92000
MBX_TQ_COUNT EQU 0x05F92800
MBX_MQ_SIZE EQU 0x05F93000
MBX_MQ_COUNT EQU 0x05F93800
MBX_MQ_MISSED EQU 0x05F94000
MBX_OWNER EQU 0x05F94800
MBX_MQ_STRATEGY EQU 0x05F95000
MBX_RESV EQU 0x05F95800
 
; Messages, room for 8kW (8,192) messages
MSG_LINK EQU 0x05FA0000
MSG_D1 EQU 0x05FA2000
MSG_D2 EQU 0x05FA4000
MSG_TYPE EQU 0x05FA6000
 
; Task control blocks, room for 256 tasks
TCB_NxtRdy EQU 0x05FBE100 ; next task on ready / timeout list
TCB_PrvRdy EQU 0x05FBE200 ; previous task on ready / timeout list
TCB_NxtTCB EQU 0x05FBE300
TCB_Timeout EQU 0x05FBE400
TCB_Priority EQU 0x05FBE500
TCB_MSGPTR_D1 EQU 0x05FBE600
TCB_MSGPTR_D2 EQU 0x05FBE700
TCB_hJCB EQU 0x05FBE800
TCB_Status EQU 0x05FBE900
TCB_SP8Save EQU 0x500 ; TCB_SP8Save area $500 to $5FF
TCB_SPSave EQU 0x600 ; TCB_SPSave area $600 to $6FF
TCB_CursorRow EQU 0x05FBD100
TCB_CursorCol EQU 0x05FBD200
TCB_hWaitMbx EQU 0x05FBD300 ; handle of mailbox task is waiting at
TCB_mbq_next EQU 0x05FBD400 ; mailbox queue next
TCB_mbq_prev EQU 0x05FBD500 ; mailbox queue previous
 
KeybdHead EQU 0x05FBEA00
KeybdTail EQU 0x05FBEB00
KeybdEcho EQU 0x05FBEC00
KeybdBad EQU 0x05FBED00
KeybdAck EQU 0x05FBEE00
KeybdLocks EQU 0x05FBEF00
KeybdBuffer EQU 0x05FBF000 ; buffer is 16 chars
 
IOFocusList EQU 0x05FBD000
 
 
; BIOS vars at the top of the 8kB scratch memory
;
NmiBase EQU 0xDC
IrqBase EQU 0xDF
 
 
 
 
; TinyBasic AREA = 0x700 to 0x77F
 
HeadRdy0 EQU 0x780
HeadRdy1 EQU HeadRdy0+1
HeadRdy2 EQU HeadRdy1+1
HeadRdy3 EQU HeadRdy2+1
HeadRdy4 EQU HeadRdy3+1
TailRdy0 EQU HeadRdy4+1
TailRdy1 EQU TailRdy0+1
TailRdy2 EQU TailRdy1+1
TailRdy3 EQU TailRdy2+1
TailRdy4 EQU TailRdy3+1
FreeTCB EQU TailRdy4+1
TimeoutList EQU FreeTCB+1
RunningTCB EQU TimeoutList+1
FreeMbx EQU RunningTCB + 1
nMailbox EQU FreeMbx + 1
FreeMsg EQU nMailbox + 1
nMsgBlk EQU FreeMsg + 1
 
IrqSource EQU 0x798
 
JMPTMP EQU 0x7A0
SP8Save EQU 0x7AE
SRSave EQU 0x7AF
R1Save EQU 0x7B0
R2Save EQU 0x7B1
124,7 → 269,6
R13Save EQU 0x7BC
R14Save EQU 0x7BD
R15Save EQU 0x7BE
SPSave EQU 0x7BF
 
CharColor EQU 0x7C0
ScreenColor EQU 0x7C1
133,14 → 277,24
CursorFlash EQU 0x7C4
Milliseconds EQU 0x7C5
IRQFlag EQU 0x7C6
RdyQueTick EQU 0x7C7
eth_unique_id EQU 0x7C8
LineColor EQU 0x7C9
 
KeybdHead EQU 0x7D0
KeybdTail EQU 0x7D1
KeybdEcho EQU 0x7D2
KeybdBad EQU 0x7D3
KeybdAck EQU 0x7D4
KeybdBuffer EQU 0x7D5 ; buffer is 16 chars
KeybdLocks EQU 0x7E5
Uart_rxfifo EQU 0x05FBC000
Uart_rxhead EQU 0x7D0
Uart_rxtail EQU 0x7D1
Uart_ms EQU 0x7D2
Uart_rxrts EQU 0x7D3
Uart_rxdtr EQU 0x7D4
Uart_rxxon EQU 0x7D5
Uart_rxflow EQU 0x7D6
Uart_fon EQU 0x7D7
Uart_foff EQU 0x7D8
Uart_txrts EQU 0x7D9
Uart_txdtr EQU 0x7DA
Uart_txxon EQU 0x7DB
Uart_txxonoff EQU 0x7DC
 
startSector EQU 0x7F0
 
148,18 → 302,28
cpu rtf65002
code
 
message "jump table"
; jump table of popular BIOS routines
org $FFFFC000
dw DisplayChar
dw KeybdCheckForKeyDirect
dw KeybdGetCharDirect
dw KeybdGetChar
dw KeybdCheckForKey
dw RequestIOFocus
dw ReleaseIOFocus
dw ClearScreen
dw HomeCursor
dw ExitTask
dw SetKeyboardEcho
 
org $FFFFC200 ; leave room for 128 vectors
message "cold start point"
KeybdRST
start
sei ; disable interrupts
cld ; disable decimal mode
ldx #$05FFFFF8 ; setup stack pointer top of memory
ldx #BIOS_STACKS+0x03FF ; setup stack pointer top of memory
txs
trs r0,dp ; set direct page register
trs r0,dp8 ; and 8 bit mode direct page
166,7 → 330,7
trs r0,abs8 ; and 8 bit mode absolute address offset
 
; setup interrupt vectors
ldx #$05FFF001 ; interrupt vector table from $5FFF000 to $5FFF1FF
ldx #$05FB0001 ; interrupt vector table from $5FB0000 to $5FB01FF
; also sets nmoi policy (native mode on interrupt)
trs r2,vbr
dex
182,6 → 346,11
sta 448+3,x
lda #KeybdIRQ
sta 448+15,x
lda #SerialIRQ
sta 448+8,x
lda #bus_err_rout
sta 508,x
sta 509,x
 
emm
cpu W65C02
189,18 → 358,118
txs
nat
cpu rtf65002
ldx #0
stz IrqBase ; support for EhBASIC's interrupt mechanism
stz NmiBase
; Initialize the BIOS task
lda #TS_RUNNING|TS_READY
sta TCB_Status
stz TCB_Priority ; set task#0 priority
lda #-1
sta TCB_NxtRdy ; set task#0 next and previous fields
sta TCB_PrvRdy
stz TCB_Timeout
stz RunningTCB ; the BIOS task is the running task
 
sta TimeoutList ; no entries in timeout list
stz HeadRdy0 ; task zero (the BIOS task) is always present
sta HeadRdy1
sta HeadRdy2
sta HeadRdy3
sta HeadRdy4
stz TailRdy0
sta TailRdy1
sta TailRdy2
sta TailRdy3
sta TailRdy4
 
; Initialize IO Focus List
;
ldx #0
st5:
stz IOFocusList,x
inx
cpx #8
bne st5
 
; Initialize free message list
lda #8192
sta nMsgBlk
stz FreeMsg
ldx #0
lda #1
st4:
sta MSG_LINK,x
ina
inx
cpx #8192
bne st4
lda #-1
sta MBX_LINK+8191
; Initialize free mailbox list
lda #2048
sta nMailbox
stz FreeMbx
ldx #0
lda #1
st3:
sta MBX_LINK,x
ina
inx
cpx #2048
bne st3
lda #-1
sta MBX_LINK+2047
 
; Initialize the FreeTCB list
lda #1 ; the next available TCB
sta FreeTCB
ldx #1
lda #2
st2:
sta TCB_NxtTCB,x
ina
inx
cpx #256
bne st2
lda #-1
sta TCB_NxtTCB+255
 
stz INPUT_FOCUS
stz OUTPUT_FOCUS
lda #1
sta MBX_SEMA
sta IOF_LIST_SEMA
sta RQ_SEMA ; set ready queue semaphore
sta TO_SEMA ; set timeout list semaphore
jsr RequestIOFocus ; Get the IO focus for the BIOS (must be after semaphore is initialized)
lda #$CE ; CE =blue on blue FB = grey on grey
sta ScreenColor
sta CharColor
sta CursorFlash
jsr ClearScreen
jsr ClearBmpScreen
stz CursorRow
stz CursorCol
lda #$3FFF ; turn on sprites
sta SPRITEREGS+120
jsr RandomizeSprram
jsr HomeCursor
lda #msgStart
jsr DisplayStringB
jsr KeybdInit
lda #1
sta KeybdEcho
; 19200 * 16
;-------------
; 25MHz / 2^32
lda #$03254E6E ; constant for 19,200 baud at 25MHz
; jsr SerialInit
lda #4
ldx #0
ldy #IdleTask
jsr StartTask
jsr PICInit
cli ; enable interrupts
jmp Monitor
224,9 → 493,10
; 13 = raster interrupt
; 15 = keyboard char
;----------------------------------------------------------
message "PICInit"
PICInit:
; enable: raster irq,
lda #$000F ; enable nmi,kbd_rst,and kbd_irq
lda #$810F ; enable nmi,kbd_rst,and kbd_irq
; A10F enable serial IRQ
sta PIC_IE
PICret:
233,29 → 503,1034
rts
 
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
message "DumpTaskList"
DumpTaskList:
pha
phx
phy
push r4
lda #msgTaskList
jsr DisplayStringB
ldy #0
php
sei
dtl2:
lda HeadRdy0,y
ld r4,r1
bmi dtl1
dtl3:
ldx #3
tya
jsr PRTNUM
lda #' '
jsr DisplayChar
ld r1,r4
ldx #3
jsr PRTNUM
lda #' '
jsr DisplayChar
jsr DisplayChar
jsr DisplayChar
ld r1,r4
lda TCB_Status,r1
jsr DisplayByte
lda #' '
jsr DisplayChar
ldx #3
lda TCB_PrvRdy,r4
jsr PRTNUM
lda #' '
jsr DisplayChar
ldx #3
lda TCB_NxtRdy,r4
jsr PRTNUM
lda #' '
jsr DisplayChar
lda TCB_Timeout,r4
jsr DisplayWord
jsr CRLF
ld r4,TCB_NxtRdy,r4
bpl dtl3
dtl1:
iny
cpy #5
bne dtl2
plp
pop r4
ply
plx
pla
rts
 
msgTaskList:
db CR,LF,"Pri Task Stat Prv Nxt Timeout",CR,LF,0
 
;------------------------------------------------------------------------------
; IdleTask is a low priority task that is always running. It runs when there
; is nothing else to run.
;------------------------------------------------------------------------------
IdleTask:
inc TEXTSCR+167 ; increment IDLE active flag
cli ; enable interrupts
wai ; wait for one to happen
bra IdleTask
 
;------------------------------------------------------------------------------
; r1 = task priority
; r2 = start flags
; r3 = start address
;------------------------------------------------------------------------------
message "StartTask"
StartTask:
pha
phx
phy
push r4
push r5
push r6
push r7
push r8
tsr sp,r4 ; save off current stack pointer
ld r6,r1 ; r6 = task priority
ld r8,r2
; get a free TCB
;
sei
lda FreeTCB ; get free tcb list pointer
bmi stask1
tax
lda TCB_NxtTCB,x
sta FreeTCB ; update the FreeTCB list pointer
cli
txa
; setup the stack for the task
ld r7,r2
asl r2,r2,#10 ; 1kW stack per task
add r2,r2,#BIOS_STACKS+0x3ff ; add in stack base
txs
ldx #$FF
stx TCB_SP8Save,r7
st r6,TCB_Priority,r7
stz TCB_Status,r7
stz TCB_Timeout,r7
 
; setup the initial stack image for the task
; Cause a return to the ExitTask routine when the task does a
; final rts.
; fake an IRQ call by stacking the return address and processor
; flags on the stack
ldx #ExitTask ; save the address of the task exit routine
phx
phy ; save start address on stack
push r8 ; save processor status reg on stack
; now fake pushing the register set onto the stack. Registers start up
; in an undefined state.
sub sp,#15 ; 15 registers
tsx
stx TCB_SPSave,r7
 
; now restore the current stack pointer
trs r4,sp
 
; Insert the task into the ready list
jsr AddTaskToReadyList
stask2:
pop r8
pop r7
pop r6
pop r5
pop r4
ply
plx
pla
rts
stask1:
cli
lda #msgNoTCBs
jsr DisplayStringB
bra stask2
 
msgNoTCBs:
db "No more task control blocks available.",CR,LF,0
 
;------------------------------------------------------------------------------
; This routine is called when the task exits with an rts instruction. OR
; it may be invoked with a JMP ExitTask.
;------------------------------------------------------------------------------
message "ExitTask"
ExitTask:
sei
; release any aquired resources
; - mailboxes
; - messages
lda RunningTCB
jsr RemoveTaskFromReadyList
stz TCB_Status,r1 ; set task status to TS_NONE
ldx FreeTCB
stx TCB_NxtTCB,r1
sta FreeTCB
jmp SelectTaskToRun
 
;------------------------------------------------------------------------------
; AddTaskToReadyList
; This subroutine is called from the timer ISR so it must be relatively
; fast.
; Parameters:
; r1 = task number
;
;------------------------------------------------------------------------------
message "AddTaskToReadyList"
AddTaskToReadyList:
phx
phy
php
sei
ldy TCB_Priority,r1 ; make sure the priority value isn't screwy.
cpy #5
bpl arl3
arl2:
ldx TCB_Status,r1 ; set the task status to ready
or r2,r2,#TS_READY
stx TCB_Status,r1
ldx TailRdy0,y ; insert the task at the list tail
sta TCB_NxtRdy,x
stx TCB_PrvRdy,r1
sta TailRdy0,y
ldx #-1
stx TCB_NxtRdy,r1
ldx HeadRdy0,y ; check if the head of the ready list needs to be updated
bpl arl3
sta HeadRdy0,y
ldx #-1
stx TCB_PrvRdy,r1
arl3:
plp
ply
plx
rts
 
 
;------------------------------------------------------------------------------
; RemoveTaskFromReadyList
; This subroutine removes a task from the ready list.
; This can be called from within an ISR.
;
; r1 = task number
;------------------------------------------------------------------------------
message "RemoveTaskFromReadyList"
RemoveTaskFromReadyList:
cmp #0
bmi rfr9 ; bad task number, must be >= 0
cmp #255 ; and must be <= 255
bpl rfr9
pha
phy
push r4
push r5
 
php ; save off interrupt mask state
sei
ld r4,TCB_NxtRdy,r1 ; Get previous and next fields.
ld r5,TCB_PrvRdy,r1 ; if there is no previous task, then this is
bmi rfr1 ; the head of the list. Update.
st r4,TCB_NxtRdy,r5
cmp r4,#0 ; is there a next task to update ?
bmi rfr8
st r5,TCB_PrvRdy,r4
ld r5,#-1
st r5,TCB_NxtRdy,r1
st r5,TCB_PrvRdy,r1
bra rfr8
 
; Update the head of the list
rfr1:
ldy TCB_Priority,r1
st r4,HeadRdy0,y
cmp r4,#0 ; did we empty the list ?
bmi rfr8
ld r5,#-1 ; flag no previous task for head of list
st r5,TCB_PrvRdy,r4
st r5,TCB_NxtRdy,r1
st r5,TCB_PrvRdy,r1
rfr8:
plp
pop r5
pop r4
ply
pla
rfr9:
rts
;------------------------------------------------------------------------------
; r1 = task
; r2 = timeout value
;------------------------------------------------------------------------------
message "AddToTimeoutList"
AddToTimeoutList:
phx
push r4
push r5
php
sei
 
ld r5,#-1
ld r4,TimeoutList ; are there any tasks on the timeout list ?
bmi attl1
attl_check_next:
sub r2,r2,TCB_Timeout,r4 ; is this timeout > next
bmi attl_insert_before
ld r5,r4
ld r4,TCB_NxtRdy,r4
bpl attl_check_next
 
; Here we scanned until the end of the timeout list and didn't find a
; timeout of a greater value. So we add the task to the end of the list.
attl_add_at_end:
st r4,TCB_NxtRdy,r1 ; r4 was = -1
st r1,TCB_NxtRdy,r5
st r5,TCB_PrvRdy,r1
st r2,TCB_Timeout,r1
bra attl_exit
 
attl_insert_before:
cmp r5,#-1
beq attl2
st r4,TCB_NxtRdy,r1 ; next on list goes after this task
st r5,TCB_PrvRdy,r1 ; set previous link
st r1,TCB_NxtRdy,r5
st r1,TCB_PrvRdy,r4
bra attl3
 
; Here there is no previous entry in the timeout list
; Add at start
attl2:
sta TCB_PrvRdy,r4
st r5,TCB_PrvRdy,r1 ; r5 = -1
st r4,TCB_NxtRdy,r1
sta TimeoutList ; update the head pointer
attl3:
add r2,r2,TCB_Timeout,r4 ; get back timeout
stx TCB_Timeout,r1
ld r5,TCB_Timeout,r4 ; adjust the timeout of the next task
sub r5,r5,r2
st r5,TCB_Timeout,r4
bra attl_exit
 
; Here there were no tasks on the timeout list, so we add at the
; head of the list.
attl1:
sta TimeoutList ; set the head of the timeout list
stx TCB_Timeout,r1
ldx #-1 ; flag no more entries in timeout list
stx TCB_NxtRdy,r1 ; no next entries
stx TCB_PrvRdy,r1 ; and no prev entries
attl_exit:
plp
pop r5
pop r4
plx
rts
 
;------------------------------------------------------------------------------
; This subroutine is called from within the timer ISR and already has the
; timeout list locked. Any other caller must lock the timeout list first
; before calling this routine.
;
; r1 = task number
;------------------------------------------------------------------------------
message "RemoveFromTimeoutList"
RemoveFromTimeoutList:
pha
phx
push r4
push r5
php
sei
 
ld r4,TCB_PrvRdy,r1 ; adjust the links of the next and previous
bmi rftl2
ld r5,TCB_NxtRdy,r1 ; tasks on the list to point around the task
st r5,TCB_NxtRdy,r4
bmi rftl1
st r4,TCB_PrvRdy,r5
ldx TCB_Timeout,r1 ; update the timeout of the next on list
add r2,r2,TCB_Timeout,r5 ; with any remaining timeout in the task
stx TCB_Timeout,r5 ; removed from the list
; Here there is no next item on the list
rftl1:
bra rftl3
 
; Here there is no previous item on the list, so update the head of
; the list.
rftl2:
ld r5,TCB_NxtRdy,r1
st r5,TimeoutList ; store next field into list head
bmi rftl3
lda #-1 ; there is no previous item to the head
sta TCB_PrvRdy,r5
; Here there is no previous or next items in the list, so the list
; will be empty once this task is removed from it.
rftl3:
plp
pop r5
pop r4
plx
pla
rts
;------------------------------------------------------------------------------
; Allocate a mailbox
; r1 = pointer to place to store handle
;------------------------------------------------------------------------------
message "AllocMbx"
AllocMbx:
cmp #0
beq ambx1
phx
phy
push r4
ld r4,r1
php
sei
lda FreeMbx ; Get mailbox off of free mailbox list
sta (r4) ; store off the mailbox number
bmi ambx2
ldx MBX_LINK,r1 ; and update the head of the list
stx FreeMbx
dec nMailbox ; decrement number of available mailboxes
tax
ldy RunningTCB ; set the mailbox owner
lda TCB_hJCB,y
sta MBX_OWNER,x
lda #-1 ; initialize the head and tail of the queues
sta MBX_TQ_HEAD,x
sta MBX_TQ_TAIL,x
sta MBX_MQ_HEAD,x
sta MBX_MQ_TAIL,x
stz MBX_TQ_COUNT,x ; initialize counts to zero
stz MBX_MQ_COUNT,x
stz MBX_MQ_MISSED,x
lda #8 ; set the max queue size
sta MBX_MQ_SIZE,x ; and
lda #MQS_NEWEST ; queueing strategy
sta MBX_MQ_STRATEGY,x
plp
pop r4
ply
plx
lda #E_Ok
rts
ambx1:
lda #E_Arg
rts
ambx2:
plp
pop r4
ply
plx
lda #E_NoMoreMbx
rts
 
;------------------------------------------------------------------------------
; r1 = message
; r2 = mailbox
;------------------------------------------------------------------------------
message "QueueMsgAtMbx"
QueueMsgAtMbx:
pha
phx
phy
php
sei
ldy MBX_MQ_TAIL,x
bmi qmam1
sta MBX_LINK,y
bra qmam2
qmam1:
sta MBX_MQ_HEAD,x
qmam2:
sta MBX_MQ_TAIL,x
inc MBX_MQ_COUNT,x ; increase the queued message count
ldx #-1
stx MSG_LINK,r1
plp
ply
plx
pla
rts
 
;------------------------------------------------------------------------------
; Returns
; r1 = message number
;------------------------------------------------------------------------------
message "DequeueMsgFromMbx"
DequeueMsgFromMbx:
phx
phy
php
sei
tax ; x = mailbox index
lda MBX_MQ_COUNT,x ; are there any messages available ?
beq dmfm1
dea
sta MBX_MQ_COUNT,x ; update the message count
lda MBX_MQ_HEAD,x ; Get the head of the list, this should not be -1
bmi dmfm1 ; since the message count > 0
ldy MSG_LINK,r1 ; get the link to the next message
sty MBX_MQ_HEAD,x ; update the head of the list
bpl dmfm2 ; if there was no more messages then update the
sty MBX_MQ_TAIL,x ; tail of the list as well.
dmfm2:
sta MSG_LINK,r1 ; point the link to the messahe itself to indicate it's dequeued
dmfm1:
plp
ply
plx
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
DequeueThreadFromMbx:
cpx #0
beq dtfm1
php
sei
push r4
ld r4,MBX_TQ_HEAD,r1
bpl dtfm2
pop r4
stz (x)
plp
lda #E_NoThread
rts
dtfm2:
push r5
dec MBX_TQ_COUNT,r1
st r4,(x)
ld r4,TCB_mbq_next,r4
st r4,MBX_TQ_HEAD,r1
bmi dtfm3
ld r5,#-1
st r5,TCB_mbq_prev,r4
bra dtfm4
dtfm3:
ld r5,#-1
st r5,MBX_TQ_TAIL,r1
dtfm4:
stz MBX_SEMA+1
ld r5,(x)
lda TCB_Status,r5
bit #TS_TIMEOUT
beq dtfm5
ld r1,r5
jsr RemoveFromTimeoutList
dtfm5:
ld r4,#-1
st r4,TCB_mbq_next,r5
st r4,TCB_mbq_prev,r5
stz TCB_hWaitMbx,r5
lda TCB_Status,r5
and #~TS_WAITMSG
sta TCB_Status,r5
pop r5
pop r4
plp
lda #E_Ok
rts
dtfm1:
lda #E_Arg
rts
 
;------------------------------------------------------------------------------
; r1 = handle to mailbox
; r2 = message D1
; r3 = message D2
;------------------------------------------------------------------------------
message "SendMsg"
SendMsg:
cmp #0 ; check the mailbox number to make sure
bmi smsg1 ; that it's sensible
cmp #2047
bpl smsg1
push r4
push r5
push r6
php
sei
ld r4,MBX_OWNER,r1
bmi smsg2 ; error: no owner
pha
phx
jsr DequeueThreadFromMbx ; r1=mbx, r2=thread (returned)
ld r6,r2 ; r6 = thread
plx
pla
cmp r6,#0
bpl smsg3
; Here there was no thread waiting at the mailbox, so a message needs to
; be allocated
ld r4,FreeMsg
bmi smsg4 ; no more messages available
ld r5,MSG_LINK,r4
st r5,FreeMsg
dec nMsgBlk ; decrement the number of available messages
stx MSG_D1,r4
sty MSG_D2,r4
pha
phx
tax ; x = mailbox
ld r1,r4 ; acc = message
jsr QueueMsgAtMbx
plx
pla
cmp r6,#0 ; check if there is a thread waiting for a message
bmi smsg5
smsg3:
ld r5,TCB_MSGPTR_D1,r6
beq smsg6
stx (r5)
smsg6:
ld r5,TCB_MSGPTR_D2,r6
beq smsg7
sty (r5)
smsg7:
ld r5,TCB_Status,r6
and r5,r5,#TS_TIMEOUT
beq smsg8
ld r1,r6
jsr RemoveFromTimeoutList
smsg8:
ld r1,r6
jsr AddTaskToReadyList
smsg5:
plp
pop r6
pop r5
pop r4
lda #E_Ok
rts
smsg1:
lda #E_BadMbx
rts
smsg2:
plp
pop r6
pop r5
pop r4
lda #E_NotAlloc
rts
smsg4:
plp
pop r6
pop r5
pop r4
lda #E_NoMsg
rts
 
;------------------------------------------------------------------------------
; WaitMsg
; Wait at a mailbox for a message to arrive. This subroutine will block the
; task until a message is available or the task times out on the timeout
; list.
;
; Parameters
; r1=mailbox
; r2=pointer to D1
; r3=pointer to D2
; r4=timeout
; Returns:
; r1=E_Ok if everything is ok
; r1=E_BadMbx for a bad mailbox number
; r1=E_NotAlloc for a mailbox that isn't allocated
;------------------------------------------------------------------------------
WaitMsg:
cmp #0 ; check the mailbox number to make sure
bmi wmsg1 ; that it's sensible
cmp #2047
bpl wmsg1
phx
phy
push r4
push r5
push r6
push r7
ld r6,r1
php
sei
ld r5,MBX_OWNER,r1
bmi wmsg2 ; error: no owner
jsr DequeueMsgFromMbx
cmp #0
bpl wmsg3
 
; Here there was no message available, remove the task from
; the ready list, and optionally add it to the timeout list.
; Queue the task at the mailbox.
lda RunningTCB ; remove the task from the ready list
jsr RemoveTaskFromReadyList
ld r7,TCB_Status,r1 ; set task status to waiting
or r7,r7,#TS_WAITMSG
st r7,TCB_Status,r1
st r6,TCB_hWaitMbx,r1 ; set which mailbox is waited for
ld r7,#-1
st r7,TCB_mbq_next,r1 ; adding at tail, so there is no next
stx TCB_MSGPTR_D1,r1 ; save off the message pointers
sty TCB_MSGPTR_D2,r1
ld r7,MBX_TQ_HEAD,r1 ; is there a task que setup at the mailbox ?
bmi wmsg6
ld r7,MBX_TQ_TAIL,r6
st r7,TCB_mbq_prev,r1
sta TCB_mbq_next,r7
sta MBX_TQ_TAIL,r6
inc MBX_TQ_COUNT,r6 ; increment number of tasks queued
wmsg7:
cmp r4,#0 ; check for a timeout
beq wmsg10
ld r2,r4
jsr AddToTimeoutList
wmsg10:
ld r2,#wmsg8 ; save the return address
phx
php ; save status register
pha ; and save the register set
phx
phy
push r4
push r5
push r6
push r7
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
jmp SelectTaskToRun
; Here there were no prior tasks queued at the mailbox
wmsg6:
ld r7,#-1
st r7,TCB_mbq_prev,r1 ; no previous tasks
st r7,TCB_mbq_next,r1
sta MBX_TQ_HEAD,r6 ; set both head and tail indexes
sta MBX_TQ_TAIL,r6
ld r7,#1
st r7,MBX_TQ_COUNT,r6 ; one task queued
bra wmsg7 ; check for a timeout value
; Store message D1 to pointer
wmsg3:
cpx #0
beq wmsg4
ld r7,MSG_D1,r1
st r7,(x)
; Store message D2 to pointer
wmsg4:
cpy #0
beq wmsg5
ld r7,MSG_D2,r1
st r7,(y)
; Add the newly dequeued message to the free messsage list
wmsg5:
ld r7,FreeMsg
st r7,MSG_LINK,r1
sta FreeMsg
inc nMsgBlk
wmsg8:
plp
pop r7
pop r6
pop r5
pop r4
ply
plx
lda #E_Ok
rts
wmsg1:
lda #E_BadMbx
rts
wmsg2:
plp
pop r7
pop r6
pop r5
pop r4
ply
plx
lda #E_NotAlloc
rts
 
;------------------------------------------------------------------------------
; CheckMsg
; Check for a message at a mailbox. Does not block.
;
; Parameters
; r1=mailbox
; r2=pointer to D1
; r3=pointer to D2
; r4=remove from queue if present
; Returns:
; r1=E_Ok if everything is ok
; r1=E_NoMsg if no message is available
; r1=E_BadMbx for a bad mailbox number
; r1=E_NotAlloc for a mailbox that isn't allocated
;------------------------------------------------------------------------------
CheckMsg:
cmp #0 ; check the mailbox number to make sure
bmi cmsg1 ; that it's sensible
cmp #2047
bpl cmsg1
phx
phy
push r4
push r5
php
sei
ld r5,MBX_OWNER,r1
bmi cmsg2 ; error: no owner
cmp r4,#0 ; are we to dequeue the message ?
beq cmsg3
jsr DequeueMsgFromMbx
bra cmsg4
cmsg3:
lda MBX_MQ_HEAD,r1
cmsg4:
cmp #0
bmi cmsg5
cpx #0
beq cmsg6
ld r5,MSG_D1,r1
st r5,(x)
cmsg6:
cpy #0
beq cmsg7
ld r5,MSG_D2,r1
st r5,(y)
cmsg7:
cmp r4,#0
beq cmsg8
ld r5,FreeMsg
st r5,MSG_LINK,r1
sta FreeMsg
inc nMsgBlk
cmsg8:
plp
pop r5
pop r4
ply
plx
lda #E_Ok
rts
cmsg1:
lda #E_BadMbx
rts
cmsg2:
plp
pop r5
pop r4
ply
plx
lda #E_NotAlloc
rts
cmsg5:
plp
pop r5
pop r4
ply
plx
lda #E_NoMsg
rts
 
;------------------------------------------------------------------------------
; r1 = task number
; r2 = timeout
;------------------------------------------------------------------------------
PutTaskToSleep:
jsr RemoveTaskFromReadyList
jsr AddToTimeoutList
rts
 
;------------------------------------------------------------------------------
; The I/O focus list is an array indicating which tasks are requesting the
; I/O focus. The I/O focus is user controlled by pressing ALT-TAB on the
; keyboard.
;------------------------------------------------------------------------------
message "RequestIOFocus"
RequestIOFocus:
pha
phx
phy
php
sei
ldx RunningTCB
and r1,r2,#$1F ; get bit index 0 to 31
ldy #1
asl r3,r3,r1 ; shift bit to proper place
lsr r2,r2,#5 ; get word index /32 bits per word
lda IOFocusList,x
or r1,r1,r3
sta IOFocusList,x
plp
ply
plx
pla
rts
message "ReleaseIOFocus"
ReleaseIOFocus:
pha
phx
phy
php
sei
ldx RunningTCB
and r1,r2,#$1F ; get bit index 0 to 31
ldy #1
asl r3,r3,r1 ; shift bit to proper place
eor r3,r3,#-1 ; invert bit mask
lsr r2,r2,#5 ; get word index /32 bits per word
lda IOFocusList,x
and r1,r1,r3
sta IOFocusList,x
plp
ply
plx
pla
rts
 
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
GetScreenLocation:
lda RunningTCB
cmp OUTPUT_FOCUS
beq gsl1
asl r1,r1,#13 ; 8192 words per screen
add r1,r1,#BIOS_SCREENS
rts
gsl1:
lda #TEXTSCR
rts
 
GetColorCodeLocation:
lda RunningTCB
cmp OUTPUT_FOCUS
beq gccl1
asl r1,r1,#13 ; 8192 words per screen
add r1,r1,#BIOS_SCREENS+4096
rts
gccl1:
lda #TEXTSCR+$10000
rts
 
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
message "CopyVirtualScreenToScreen"
CopyVirtualScreenToScreen
pha
phx
phy
lda #4095 ; number of words to copy-1
ldx OUTPUT_FOCUS ; compute virtual screen location
asl r2,r2,#13 ; 8192 words per screen
add r2,r2,#BIOS_SCREENS ; add in screens array base address
ldy #TEXTSCR
; mvn
cvss1:
ld r4,(x)
st r4,(y)
inx
iny
dea
bne cvss1
; now copy the color codes
lda #4095
ldx OUTPUT_FOCUS
asl r2,r2,#13
add r2,r2,#BIOS_SCREENS+4096 ; virtual char color array
ldy #TEXTSCR+$10000
cvss2:
ld r4,(x)
st r4,(y)
inx
iny
dea
bne cvss2
ply
plx
pla
rts
message "CopyScreenToVirtualScreen"
CopyScreenToVirtualScreen
pha
phx
phy
lda #4095
ldx #TEXTSCR
ldy OUTPUT_FOCUS
asl r3,r3,#13
add r3,r3,#BIOS_SCREENS
csvs1:
ld r4,(x)
st r4,(y)
inx
iny
dea
bne csvs1
lda #4095
ldx #TEXTSCR+$10000
ldy OUTPUT_FOCUS
asl r3,r3,#13
add r3,r3,#BIOS_SCREENS+4096
csvs2:
ld r4,(x)
st r4,(y)
inx
iny
dea
bne csvs2
ply
plx
pla
rts
 
;------------------------------------------------------------------------------
; Clear the screen and the screen color memory
; We clear the screen to give a visual indication that the system
; is working at all.
;------------------------------------------------------------------------------
;
message "ClearScreen"
ClearScreen:
pha ; holds a space character
phx ; loop counter
phy ; memory addressing
push r4 ; holds the screen color
push r5
lda TEXTREG+TEXT_COLS ; calc number to clear
ldx TEXTREG+TEXT_ROWS
mul r2,r1,r2 ; r2 = # chars to clear
jsr GetScreenLocation
tay
jsr GetColorCodeLocation
ld r5,r1
lda #' ' ; space char
ld r4,ScreenColor
jsr AsciiToScreen
ldy #TEXTSCR ; text screen address
csj4:
sta (y)
st r4,$10000,y ; color screen is 0x10000 higher
iny
st r4,(r5)
inc r5
dex
bne csj4
pop r5
pop r4
ply
plx
266,6 → 1541,7
; Scroll text on the screen upwards
;------------------------------------------------------------------------------
;
message "ScrollUp"
ScrollUp:
pha
phx
272,23 → 1548,32
phy
push r4
push r5
push r6
lda TEXTREG+TEXT_COLS ; acc = # text columns
ldx TEXTREG+TEXT_ROWS
mul r2,r1,r2 ; calc number of chars to scroll
sub r2,r2,r1 ; one less row
ldy #TEXTSCR
pha
jsr GetScreenLocation
tay
jsr GetColorCodeLocation
ld r6,r1
pla
scrup1:
add r5,r3,r1
ld r4,(r5) ; move character
st r4,(y)
ld r4,$10000,r5 ; and move color code
st r4,$10000,y
add r5,r6,r1
ld r4,(r5) ; and move color code
st r4,(r6)
iny
inc r6
dex
bne scrup1
lda TEXTREG+TEXT_ROWS
dea
jsr BlankLine
pop r6
pop r5
pop r4
ply
305,15 → 1590,22
pha
phx
phy
push r4
ldx TEXTREG+TEXT_COLS ; x = # chars to blank out from video controller
mul r3,r2,r1 ; y = screen index (row# * #cols)
add r3,r3,#TEXTSCR ; y = screen address
pha
jsr GetScreenLocation
ld r4,r1
pla
add r3,r3,r4 ; y = screen address
lda #' '
jsr AsciiToScreen
blnkln1:
sta (y)
iny
dex
bne blnkln1
pop r4
ply
plx
pla
352,6 → 1644,18
rts
 
;------------------------------------------------------------------------------
; HomeCursor
; Set the cursor location to the top left of the screen.
;------------------------------------------------------------------------------
HomeCursor:
phx
ldx RunningTCB
stz TCB_CursorRow,x
stz TCB_CursorCol,x
plx
rts
 
;------------------------------------------------------------------------------
; Calculate screen memory location from CursorRow,CursorCol.
; Also refreshes the cursor location.
; Returns:
360,77 → 1664,93
;
CalcScreenLoc:
phx
lda CursorRow
push r4
ld r4,RunningTCB
lda TCB_CursorRow,r4
ldx TEXTREG+TEXT_COLS
mul r2,r2,r1
add r2,r2,CursorCol
add r2,r2,TCB_CursorCol,r4
cmp r4,OUTPUT_FOCUS ; update cursor position in text controller
bne csl1 ; only for the task with the output focus
stx TEXTREG+TEXT_CURPOS
add r1,r2,#TEXTSCR ; r1 = screen location
csl1:
jsr GetScreenLocation
add r1,r2,r1
csl2:
pop r4
plx
rts
 
;------------------------------------------------------------------------------
; Display a character on the screen
; Display a character on the screen.
; If the task doesn't have the I/O focus then the character is written to
; the virtual screen.
; r1 = char to display
;------------------------------------------------------------------------------
;
message "DisplayChar"
DisplayChar:
push r4
ld r4,RunningTCB
and #$FF ; mask off any higher order bits (called from eight bit mode).
cmp #'\r' ; carriage return ?
bne dccr
stz CursorCol ; just set cursor column to zero on a CR
stz TCB_CursorCol,r4 ; just set cursor column to zero on a CR
jsr CalcScreenLoc
pop r4
rts
dccr:
cmp #$91 ; cursor right ?
bne dcx6
pha
lda CursorCol
lda TCB_CursorCol,r4
cmp #83
bcs dcx7
ina
sta CursorCol
sta TCB_CursorCol,r4
dcx7:
jsr CalcScreenLoc
pla
pop r4
rts
dcx6:
cmp #$90 ; cursor up ?
bne dcx8
pha
lda CursorRow
lda TCB_CursorRow,r4
beq dcx7
dea
sta CursorRow
sta TCB_CursorRow,r4
bra dcx7
dcx8:
cmp #$93 ; cursor left ?
bne dcx9
pha
lda CursorCol
lda TCB_CursorCol,r4
beq dcx7
dea
sta CursorCol
sta TCB_CursorCol,r4
bra dcx7
dcx9:
cmp #$92 ; cursor down ?
bne dcx10
pha
lda CursorRow
lda TCB_CursorRow,r4
cmp #46
beq dcx7
ina
sta CursorRow
sta TCB_CursorRow,r4
bra dcx7
dcx10:
cmp #$94 ; cursor home ?
bne dcx11
pha
lda CursorCol
lda TCB_CursorCol,r4
beq dcx12
stz CursorCol
stz TCB_CursorCol,r4
bra dcx7
dcx12:
stz CursorRow
stz TCB_CursorRow,r4
bra dcx7
dcx11:
pha
440,18 → 1760,18
bne dcx13
jsr CalcScreenLoc
tay ; y = screen location
lda CursorCol ; acc = cursor column
lda TCB_CursorCol,r4 ; acc = cursor column
bra dcx5
dcx13
cmp #CTRLH ; backspace ?
bne dcx3
lda CursorCol
lda TCB_CursorCol,r4
beq dcx4
dea
sta CursorCol
sta TCB_CursorCol,r4
jsr CalcScreenLoc ; acc = screen location
tay ; y = screen location
lda CursorCol
lda TCB_CursorCol,r4
dcx5:
ldx $4,y
stx (y)
473,8 → 1793,12
txa ; restore r1
jsr AsciiToScreen ; convert ascii char to screen char
sta (y)
jsr GetScreenLocation
sub r3,r3,r1 ; make y an index into the screen
jsr GetColorCodeLocation
add r3,r3,r1
lda CharColor
sta $10000,y
sta (y)
jsr IncCursorPos
bra dcx4
dclf:
483,6 → 1807,7
ply
plx
pla
pop r4
rts
 
;------------------------------------------------------------------------------
492,30 → 1817,35
IncCursorPos:
pha
phx
lda CursorCol
push r4
ld r4,RunningTCB
lda TCB_CursorCol,r4
ina
sta CursorCol
sta TCB_CursorCol,r4
ldx TEXTREG+TEXT_COLS
cmp r1,r2
bcc icc1
stz CursorCol ; column = 0
stz TCB_CursorCol,r4 ; column = 0
bra icr1
IncCursorRow:
pha
phx
push r4
ld r4,RunningTCB
icr1:
lda CursorRow
lda TCB_CursorRow,r4
ina
sta CursorRow
sta TCB_CursorRow,r4
ldx TEXTREG+TEXT_ROWS
cmp r1,r2
bcc icc1
beq icc1
dex ; backup the cursor row, we are scrolling up
stx CursorRow
stx TCB_CursorRow,r4
jsr ScrollUp
icc1:
jsr CalcScreenLoc
pop r4
plx
pla
rts
581,14 → 1911,20
; initializes the keyboard semaphore.
;------------------------------------------------------------------------------
;
message "KeybdInit"
KeybdInit:
lda #1 ; setup semaphore
; sta KEYBD_SEMA
stz KeybdHead ; setup keyboard buffer
stz KeybdTail
sta KEYBD_SEMA
ldx #0
kbdi1:
stz KeybdHead,x ; setup keyboard buffer
stz KeybdTail,x
lda #1 ; turn on keyboard echo
sta KeybdEcho
stz KeybdBad
sta KeybdEcho,x
stz KeybdBad,x
inx
cpx #256
bne kbdi1
lda #$ff ; issue keyboard reset
jsr SendByteToKeybd
611,6 → 1947,8
db "Keyboard not responding.",0
 
SendByteToKeybd:
phx
ldx RunningTCB
sta KEYBD
tsr TICK,r3
kbdi4: ; wait for transmit complete
623,13 → 1961,14
beq kbdi4
bra sbtk1
kbdbad:
lda KeybdBad
lda KeybdBad,x
bne sbtk1
lda #1
sta KeybdBad
sta KeybdBad,x
lda #msgBadKeybd
jsr DisplayStringCRLFB
sbtk1:
plx
rts
; Wait for keyboard to respond with an ACK (FA)
655,22 → 1994,43
; r2 = 0xFA (could also be 0xEE for echo command)
;
WaitForKeybdAck2:
lda KeybdAck
phx
ldx RunningTCB
WaitForKeybdAck2a:
lda KeybdAck,x
cmp r1,r2
bne WaitForKeybdAck2
stz KeybdAck
bne WaitForKeybdAck2a
stz KeybdAck,x
plx
rts
 
;------------------------------------------------------------------------------
; Normal keyboard interrupt, the lowest priority interrupt in the system.
; Grab the character from the keyboard device and store it in a buffer.
; Doesn't use the stack.
; The buffer of the task with the input focus is updated.
;------------------------------------------------------------------------------
;
message "KeybdIRQ"
KeybdIRQ:
cld
pha
phx
phy
push r4
 
; support EhBASIC's IRQ functionality
; code derived from minimon.asm
lda #15 ; Keyboard is IRQ #15
sta IrqSource
lb r1,IrqBase ; get the IRQ flag byte
; or #$20 ; set the pending bit
lsr r2,r1
or r1,r1,r2
and #$E0
sb r1,IrqBase ; save the new IRQ flag byte
 
ld r4,INPUT_FOCUS ; get the task with the input focus
 
ldx KEYBD ; get keyboard character
ld r0,KEYBD+1 ; clear keyboard strobe (turns off the IRQ)
txy ; check for a keyboard ACK code
677,23 → 2037,27
and r3,r3,#$ff
cmp r3,#$FA
bne KeybdIrq1
sty KeybdAck
sty KeybdAck,r4
bra KeybdIRQc
KeybdIrq1:
bit r2,#$800 ; test bit #11
bne KeybdIRQc ; ignore keyup messages for now
lda KeybdHead
KeybdIrq2:
lda KeybdHead,r4
ina ; increment head pointer
and #$f ; limit
ldy KeybdTail ; check for room in the keyboard buffer
ldy KeybdTail,r4 ; check for room in the keyboard buffer
cmp r1,r3
beq KeybdIRQc ; if no room, the newest char will be lost
sta KeybdHead
sta KeybdHead,r4
dea
and #$f
stx KeybdLocks,r4
asl r4,r4,#4 ; * 16
add r1,r1,r4
stx KeybdBuffer,r1 ; store character in buffer
stx KeybdLocks
KeybdIRQc:
pop r4
ply
plx
pla
700,68 → 2064,176
rti
 
KeybdRstIRQ:
jmp ColdStart
jmp start
 
;------------------------------------------------------------------------------
; r1 0=echo off, non-zero = echo on
;------------------------------------------------------------------------------
SetKeyboardEcho:
sta KeybdEcho
phx
ldx RunningTCB
sta KeybdEcho,x
plx
rts
 
;-----------------------------------------
;------------------------------------------------------------------------------
; Get a bit from the I/O focus table.
;------------------------------------------------------------------------------
GetIOFocusBit:
phx
phy
tax
and r1,r1,#$1F ; get bit index into word
lsr r2,r2,#5 ; get word index into table
ldy IOFocusList,x
lsr r3,r3,r1 ; extract bit
and r1,r3,#1
ply
plx
rts
;------------------------------------------------------------------------------
; SwitchIOFocus
; Switches the IO focus to the next task requesting the I/O focus.
; Destroys acc,x,y
;------------------------------------------------------------------------------
;
SwitchIOFocus:
phx
; Copy the current task's screen to it's virtual screen buffer.
jsr CopyScreenToVirtualScreen
 
ldy INPUT_FOCUS
lda TCB_Status,y
or r1,r1,#TS_WAITFOCUS
sta TCB_Status,y
tya
jsr RemoveTaskFromReadyList
 
; Cycle through the focus list to find the next task
; requesting the IO Focus
ldx #257 ; we want to cycle all the way around
ldy INPUT_FOCUS ; back to the original INPUT_FOCUS
bra kgc9 ; enter the loop at the next possible requester
kgc5:
tya
jsr GetIOFocusBit ; get the focus request status
cmp #0
bne kgc6 ; if requesting focus, break loop
kgc9:
iny ; move to test in array
and r3,r3,#$FF ; limit y to 0 to 255 array elements
dex
bne kgc5
ldy INPUT_FOCUS ; We cycled through the whole list and there wasn't another
; ; task requesting focus, so stick with the same task.
kgc6:
sty INPUT_FOCUS
sty OUTPUT_FOCUS
lda TCB_Status,y
and #~TS_WAITFOCUS
sta TCB_Status,y
tya
jsr AddTaskToReadyList
 
; Copy the virtual screen of the task recieving the I/O focus to the
; text screen.
jsr CopyVirtualScreenToScreen
plx
rts
;------------------------------------------------------------------------------
; Get character from keyboard buffer
; return character in acc or -1 if no
; characters available
;-----------------------------------------
; characters available.
; Also check for ALT-TAB and switch the I/O focus.
;------------------------------------------------------------------------------
message "KeybdGetChar"
KeybdGetChar:
phx
ldx KeybdTail ; if keybdTail==keybdHead then there are no
lda KeybdHead ; characters in the keyboard buffer
push r4
php
sei
ld r4,RunningTCB
ldx KeybdTail,r4 ; if keybdTail==keybdHead then there are no
lda KeybdHead,r4 ; characters in the keyboard buffer
cmp r1,r2
beq nochar
asl r4,r4,#4 ; * 16
phx
add r2,r2,r4
lda KeybdBuffer,x
plx
bit #$200 ; check for ALT-tab
beq kgc4
and #$FF
cmp #TAB ; if we find an ALT-tab
bne kgc4
jsr SwitchIOFocus
; Now eat up the ALT-TAB character
inx ; increment index
and r2,r2,#$0f
lsr r4,r4,#4 ; / 16
stx KeybdTail,r4
bra nochar
kgc4:
and r1,r1,#$ff ; mask off control bits
inx ; increment index
and r2,r2,#$0f
stx KeybdTail
ldx KeybdEcho
lsr r4,r4,#4 ; / 16
stx KeybdTail,r4
ldx KeybdEcho,r4
beq kgc3
cmp #CR
bne kgc2
bne kgc8
jsr CRLF ; convert CR keystroke into CRLF
bra kgc3
kgc2:
kgc8:
jsr DisplayChar
bra kgc3
nochar:
lda #-1
kgc3:
plp
pop r4
plx
rts
 
;------------------------------------------------------------------------------
; Check if there is a keyboard character available in the keyboard buffer.
; Returns
; r1 = 1, Z=0 if there is a key available, otherwise
; r1 = 0, Z=1 if there is not a key available
;------------------------------------------------------------------------------
;
message "KeybdCheckForKey"
KeybdCheckForKey:
phx
lda KeybdTail
ldx KeybdHead
push r4
php
sei
ld r4,RunningTCB
lda KeybdTail,r4
ldx KeybdHead,r4
sub r1,r1,r2
bne kcfk1
plp
pop r4
plx
lda #0
rts
kcfk1
plp
pop r4
plx
lda #1
plx
rts
message "668"
;------------------------------------------------------------------------------
; Check if there is a keyboard character available. If so return true (1)
; otherwise return false (0) in r1.
;------------------------------------------------------------------------------
;
message "KeybdCheckForKeyDirect"
KeybdCheckForKeyDirect:
lda KEYBD
and #$8000
784,6 → 2256,14
ld r0,KEYBD+1 ; clear keyboard strobe
bit #$800 ; is it a keydown event ?
bne kgc1
bit #$200 ; check for ALT-tab
bne kgc2
and r2,r1,#$7f
cmp r2,#TAB ; if we find an ALT-tab
bne kgc2
jsr SwitchIOFocus
bra kgc1
kgc2:
and #$ff ; remove strobe bit
ldx KeybdEcho ; is keyboard echo on ?
beq gk1
798,7 → 2278,309
rts
 
 
;==============================================================================
; Serial port
;==============================================================================
;------------------------------------------------------------------------------
; Initialize the serial port
; r1 = low 28 bits = baud rate
; r2 = other settings
; The desired baud rate must fit in 28 bits or less.
;------------------------------------------------------------------------------
;
SerialInit:
; asl r1,r1,#4 ; * 16
; shlui r1,r1,#32 ; * 2^32
; inhu r2,CR_CLOCK ; get clock frequency from config record
; divu r1,r1,r2 ; / clock frequency
 
lsr r1,r1,#8 ; drop the lowest 8 bits
sta UART_CM1 ; set LSB
lsr r1,r1,#8
sta UART_CM2 ; set middle bits
lsr r1,r1,#8
sta UART_CM3 ; set MSB
stz Uart_rxhead ; reset buffer indexes
stz Uart_rxtail
lda #0x1f0
sta Uart_foff ; set threshold for XOFF
lda #0x010
sta Uart_fon ; set threshold for XON
lda #1
sta UART_IE ; enable receive interrupt only
stz Uart_rxrts ; no RTS/CTS signals available
stz Uart_txrts ; no RTS/CTS signals available
stz Uart_txdtr ; no DTR signals available
stz Uart_rxdtr ; no DTR signals available
lda #1
sta Uart_txxon ; for now
lda #1
sta SERIAL_SEMA
rts
 
;---------------------------------------------------------------------------------
; Get character directly from serial port. Blocks until a character is available.
;---------------------------------------------------------------------------------
;
SerialGetCharDirect:
sgc1:
lda UART_LS ; uart status
and #rxfull ; is there a char available ?
beq sgc1
lda UART
rts
 
;------------------------------------------------
; Check for a character at the serial port
; returns r1 = 1 if char available, 0 otherwise
;------------------------------------------------
;
SerialCheckForCharDirect:
lda UART_LS ; uart status
and #rxfull ; is there a char available ?
rts
 
;-----------------------------------------
; Put character to serial port
; r1 = char to put
;-----------------------------------------
;
SerialPutChar:
phx
phy
push r4
push r5
 
ldx UART_MC
or r2,r2,#3 ; assert DTR / RTS
stx UART_MC
ldx Uart_txrts
beq spcb1
ld r4,Milliseconds
ldy #1000 ; delay count (1 s)
spcb3:
ldx UART_MS
and r2,r2,#$10 ; is CTS asserted ?
bne spcb1
ld r5,Milliseconds
cmp r4,r5
beq spcb3
ld r4,r5
dey
bne spcb3
bra spcabort
spcb1:
ldx Uart_txdtr
beq spcb2
ld r4,Milliseconds
ldy #1000 ; delay count
spcb4:
ldx UART_MS
and r2,r2,#$20 ; is DSR asserted ?
bne spcb2
ld r5,Milliseconds
cmp r4,r5
beq spcb4
ld r4,r5
dey
bne spcb4
bra spcabort
spcb2:
ldx Uart_txxon
beq spcb5
spcb6:
ldx Uart_txxonoff
beq spcb5
ld r4,UART_MS
and r4,r4,#0x80 ; DCD ?
bne spcb6
spcb5:
ld r4,Milliseconds
ldy #1000 ; wait up to 1s
spcb8:
ldx UART_LS
and r2,r2,#0x20 ; tx not full ?
bne spcb7
ld r5,Milliseconds
cmp r4,r5
beq spcb8
ld r4,r5
dey
bne spcb8
bra spcabort
spcb7:
sta UART
spcabort:
pop r5
pop r4
ply
plx
rts
 
;-------------------------------------------------
; Compute number of characters in recieve buffer.
; r4 = number of chars
;-------------------------------------------------
CharsInRxBuf:
ld r4,Uart_rxhead
ldx Uart_rxtail
sub r4,r4,r2
bpl cirxb1
ld r4,#0x200
add r4,r4,r2
ldx Uart_rxhead
sub r4,r4,r2
cirxb1:
rts
 
;----------------------------------------------
; Get character from rx fifo
; If the fifo is empty enough then send an XON
;----------------------------------------------
;
SerialGetChar:
phx
phy
push r4
 
ldy Uart_rxhead
ldx Uart_rxtail
cmp r2,r3
beq sgcfifo1 ; is there a char available ?
lda Uart_rxfifo,x ; get the char from the fifo into r1
inx ; increment the fifo pointer
and r2,r2,#$1ff
stx Uart_rxtail
ldx Uart_rxflow ; using flow control ?
beq sgcfifo2
ldy Uart_fon ; enough space in Rx buffer ?
jsr CharsInRxBuf
cmp r4,r3
bpl sgcfifo2
stz Uart_rxflow ; flow off
ld r4,Uart_rxrts
beq sgcfifo3
ld r4,UART_MC ; set rts bit in MC
or r4,r4,#2
st r4,UART_MC
sgcfifo3:
ld r4,Uart_rxdtr
beq sgcfifo4
ld r4,UART_MC ; set DTR
or r4,r4,#1
st r4,UART_MC
sgcfifo4:
ld r4,Uart_rxxon
beq sgcfifo5
ld r4,#XON
st r4,UART
sgcfifo5:
sgcfifo2: ; return with char in r1
pop r4
ply
plx
rts
sgcfifo1:
lda #-1 ; no char available
pop r4
ply
plx
rts
 
 
;-----------------------------------------
; Serial port IRQ
;-----------------------------------------
;
SerialIRQ:
pha
phx
phy
push r4
 
lda UART_IS ; get interrupt status
bpl sirq1 ; no interrupt
and #0x7f ; switch on interrupt type
cmp #4
beq srxirq
cmp #$0C
beq stxirq
cmp #$10
beq smsirq
; unknown IRQ type
sirq1:
pop r4
ply
plx
pla
rti
 
 
; Get the modem status and record it
smsirq:
lda UART_MS
sta Uart_ms
bra sirq1
 
stxirq:
bra sirq1
 
; Get a character from the uart and store it in the rx fifo
srxirq:
srxirq1:
lda UART ; get the char (clears interrupt)
ldx Uart_txxon
beq srxirq3
cmp #XOFF
bne srxirq2
lda #1
sta Uart_txxonoff
bra srxirq5
srxirq2:
cmp #XON
bne srxirq3
stz Uart_txxonoff
bra srxirq5
srxirq3:
stz Uart_txxonoff
ldx Uart_rxhead
sta Uart_rxfifo,x ; store in buffer
inx
and r2,r2,#$1ff
stx Uart_rxhead
srxirq5:
lda UART_LS ; check for another ready character
and #rxfull
bne srxirq1
lda Uart_rxflow ; are we using flow controls?
bne srxirq8
jsr CharsInRxBuf
lda Uart_foff
cmp r4,r1
bmi srxirq8
lda #1
sta Uart_rxflow
lda Uart_rxrts
beq srxirq6
lda UART_MC
and #$FD ; turn off RTS
sta UART_MC
srxirq6:
lda Uart_rxdtr
beq srxirq7
lda UART_MC
and #$FE ; turn off DTR
sta UART_MC
srxirq7:
lda Uart_rxxon
beq srxirq8
lda #XOFF
sta UART
srxirq8:
bra sirq1
 
 
;------------------------------------------------------------------------------
; Display nybble in r1
;------------------------------------------------------------------------------
;
884,15 → 2666,18
jsr CRLF
pla
rts
message "845"
 
message "Monitor"
;==============================================================================
; System Monitor Program
; The system monitor is task#0
;==============================================================================
;
Monitor:
ldx #$05FFFFF8 ; setup stack pointer top of memory
ldx #BIOS_STACKS+0x03FF ; setup stack pointer
txs
stz KeybdEcho ; turn off keyboard echo
ldx RunningTCB
stz KeybdEcho,x ; turn off keyboard echo
PromptLn:
jsr CRLF
lda #'$'
903,10 → 2688,12
Prompt3:
; lw r1,#2 ; get keyboard character
; syscall #417
jsr KeybdCheckForKeyDirect
cmp #0
; jsr KeybdCheckForKeyDirect
; cmp #0
jsr KeybdGetChar
cmp #-1
beq Prompt3
jsr KeybdGetCharDirect
; jsr KeybdGetCharDirect
cmp #CR
beq Prompt1
jsr DisplayChar
915,7 → 2702,8
; Process the screen line that the CR was keyed on
;
Prompt1:
stz CursorCol ; go back to the start of the line
ldx RunningTCB
stz TCB_CursorCol,x ; go back to the start of the line
jsr CalcScreenLoc ; r1 = screen memory location
tay
lda (y)
947,11 → 2735,20
Prompt7:
cmp #'B' ; $B - start tiny basic
bne Prompt4
jsr CSTART
lda #3
ldy #CSTART
ldx #0
jsr StartTask
; jsr CSTART
bra Monitor
Prompt4:
cmp #'b'
bne Prompt5
lda #3 ; priority level 3
ldy #$C000 ; start address $C000
ldx #$20000000 ; flags: emmulation mode set
jsr StartTask
bra Monitor
emm
cpu W65C02
jml $0C000
959,9 → 2756,10
Prompt5:
cmp #'J' ; $J - execute code
beq ExecuteCode
cmp #'L' ; $L - load S19 file
bne Prompt9
jmp LoadSector
cmp #'L' ; $L - load dector
beq LoadSector
cmp #'W'
beq WriteSector
Prompt9:
cmp #'?' ; $? - display help
bne Prompt10
971,9 → 2769,15
Prompt10:
cmp #'C' ; $C - clear screen
beq TestCLS
cmp #'R'
cmp #'r'
bne Prompt12
jmp RandomLinesCall
lda #4 ; priority level 4
ldx #0 ; zero all flags at startup
ldy #RandomLines ; task address
jsr (y)
; jsr StartTask
jmp Monitor
; jmp RandomLinesCall
Prompt12:
Prompt13:
cmp #'P'
982,7 → 2786,8
Prompt14:
cmp #'T'
bne Prompt15
call tmp_read
jsr DumpTaskList
jmp Monitor
Prompt15:
cmp #'S'
bne Prompt16
998,10 → 2803,23
jsr loadBootFile
jmp Monitor
Prompt16:
cmp #'e'
bne Prompt17
jsr eth_main
Prompt17:
cmp #'R'
bne Monitor
lda (y)
iny
jsr ScreenToAscii
cmp #'S'
beq ReadSector
dey
bra SetRegValue
jmp Monitor
message "Prompt16"
RandomLinesCall:
jsr RandomLines
; jsr RandomLines
jmp Monitor
 
TestCLS:
1016,17 → 2834,19
cmp #'S'
bne Monitor
jsr ClearScreen
stz CursorCol
stz CursorRow
ldx RunningTCB
stz TCB_CursorCol,x
stz TCB_CursorRow,x
jsr CalcScreenLoc
jmp Monitor
 
message "HelpMsg"
HelpMsg:
db "? = Display help",CR,LF
db "CLS = clear screen",CR,LF
db "S = Boot from SD Card",CR,LF
db ": = Edit memory bytes",CR,LF
db "L = Load S19 file",CR,LF
db "L = Load sector",CR,LF
db "W = Write sector",CR,LF
db "DR = Dump registers",CR,LF
db "D = Dump memory",CR,LF
db "F = Fill memory",CR,LF
1034,7 → 2854,9
db "b = start EhBasic 6502",CR,LF
db "J = Jump to code",CR,LF
db "R[n] = Set register value",CR,LF
db "T = get temperature",CR,LF
db "r = random lines - test bitmap",CR,LF
db "e = ethernet test",CR,LF
db "T = Dump task list",CR,LF
db "P = Piano",CR,LF,0
 
;------------------------------------------------------------------------------
1075,6 → 2897,7
; Execute code at the specified address.
;------------------------------------------------------------------------------
;
message "ExecuteCode"
ExecuteCode:
jsr ignBlanks
jsr GetHexNumber
1115,9 → 2938,9
st r14,R14Save
st r15,R15Save
tsr sp,r1
st r1,SPSave
st r1,TCB_SPSave
tsr sp8,r1
st r1,SP8Save
st r1,TCB_SP8Save
pla
sta SRSave
jmp Monitor
1124,14 → 2947,37
 
LoadSector:
jsr ignBlanks
jsr GetDecNumber
pha
jsr ignBlanks
jsr GetHexNumber
ld r2,#0x3800
tax
phx
; ld r2,#0x3800
jsr spi_init
plx
pla
jsr spi_read_sector
jmp Monitor
 
WriteSector:
jsr ignBlanks
jsr GetDecNumber
pha
jsr ignBlanks
jsr GetHexNumber
tax
phx
jsr spi_init
plx
pla
jsr spi_write_sector
jmp Monitor
 
;------------------------------------------------------------------------------
; Dump the register set.
;------------------------------------------------------------------------------
message "DumpReg"
DumpReg:
ldy #0
DumpReg1:
1140,8 → 2986,9
jsr DisplayChar
lda #'R'
jsr DisplayChar
ldx #0
ldx #1
tya
ina
jsr PRTNUM
lda #' '
jsr DisplayChar
1159,10 → 3006,22
jsr DisplayChar
lda #' '
jsr DisplayChar
lda SPSave
lda TCB_SPSave
jsr DisplayWord
jsr CRLF
rts
jmp Monitor
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
SetRegValue:
jsr GetDecNumber
cmp #15
bpl Monitor
pha
jsr ignBlanks
jsr GetHexNumber
ply
sta R1Save,y
jmp Monitor
;------------------------------------------------------------------------------
; Do a memory dump of the requested location.
1189,7 → 3048,7
 
 
bra Monitor
 
message "FillMem"
FillMem:
jsr ignBlanks
jsr GetHexNumber ; get start address of dump
1196,7 → 3055,7
tax
jsr ignBlanks
jsr GetHexNumber ; get number of bytes to fill
or r5,r1,r0
ld r5,r1
jsr ignBlanks
jsr GetHexNumber ; get the fill byte
FillmemW:
1235,6 → 3094,31
plx
rts
 
GetDecNumber:
phx
push r4
push r5
ldx #0
ld r4,#10
ld r5,#10
gtdcn2:
lda (y)
iny
jsr ScreenToAscii
jsr AsciiToDecNybble
cmp #-1
beq gtdcn1
mul r2,r2,r5
add r2,r2,r1
dec r4
bne gtdcn2
gtdcn1:
txa
pop r5
pop r4
plx
rts
 
;------------------------------------------------------------------------------
; Convert ASCII character in the range '0' to '9', 'a' to 'f' or 'A' to 'F'
; to a hex nybble.
1267,6 → 3151,18
lda #-1 ; not a hex number
rts
 
AsciiToDecNybble:
cmp #'0'
bcc gtdc3
cmp #'9'+1
bcs gtdc3
sub #'0'
rts
gtdc3:
lda #-1
rts
 
 
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ClearBmpScreen:
1292,7 → 3188,9
; Initialize the SD card
; Returns
; acc = 0 if successful, 1 otherwise
; Z=1 if successful, otherwise Z=0
;
message "spi_init"
spi_init
lda #SPI_INIT_SD
sta SPIMASTER+SPI_TRANS_TYPE_REG
1312,7 → 3210,7
lda #spi_init_ok_msg
jsr DisplayStringB
lda #0
bra spi_init_exit
rts
spi_error
jsr DisplayByte
lda #spi_init_error_msg
1326,9 → 3224,12
lda SPIMASTER+SPI_RESP_BYTE4
jsr DisplayByte
lda #1
spi_init_exit
rts
 
spi_delay:
nop
nop
rts
 
 
; SPI read sector
1366,8 → 3267,7
nop
spi_read_sect1:
lda SPIMASTER+SPI_TRANS_STATUS_REG
nop ; just a delay between consecutive status reg reads
nop
jsr spi_delay ; just a delay between consecutive status reg reads
cmp #SPI_TRANS_BUSY
beq spi_read_sect1
lda SPIMASTER+SPI_TRANS_ERROR_REG
1468,12 → 3368,15
rts
 
; read the partition table to find out where the boot sector is.
; Returns
; r1 = 0 everything okay, 1=read error
; also Z=1=everything okay, Z=0=read error
;
spi_read_part:
phx
stz startSector ; default starting sector
lda #0 ; r1 = sector number (#0)
ldx #SECTOR_BUF<<2 ; r2 = target address (word to byte address)
ldx #BYTE_SECTOR_BUF ; r2 = target address (word to byte address)
jsr spi_read_sector
cmp #0
bne spi_rp1
1495,6 → 3398,10
 
; Read the boot sector from the disk.
; Make sure it's the boot sector by looking for the signature bytes 'EB' and '55AA'.
; Returns:
; r1 = 0 means this card is bootable
; r1 = 1 means a read error occurred
; r1 = 2 means the card is not bootable
;
spi_read_boot:
phx
1503,32 → 3410,45
lda startSector ; r1 = sector number
ldx #BYTE_SECTOR_BUF ; r2 = target address
jsr spi_read_sector
cmp #0
bne spi_read_boot_err
lb r1,BYTE_SECTOR_BUF
cmp #$EB
beq spi_read_boot2
spi_read_boot3:
lda #1 ; r1 = 1 for error
bra spi_read_boot4
bne spi_eb_err
spi_read_boot2:
lda #msgFoundEB
jsr DisplayStringB
lb r1,BYTE_SECTOR_BUF+$1FE ; check for 0x55AA signature
cmp #$55
bne spi_read_boot3
bne spi_eb_err
lb r1,BYTE_SECTOR_BUF+$1FF ; check for 0x55AA signature
cmp #$AA
bne spi_read_boot3
bne spi_eb_err
pop r5
ply
plx
lda #0 ; r1 = 0, for okay status
spi_read_boot4:
rts
spi_read_boot_err:
pop r5
ply
plx
lda #1
rts
spi_eb_err:
lda #msgNotFoundEB
jsr DisplayStringB
pop r5
ply
plx
lda #2
rts
 
msgFoundEB:
db "Found EB code.",CR,LF,0
msgNotFoundEB:
db "EB/55AA Code missing.",CR,LF,0
 
 
; Load the root directory from disk
; r2 = where to place root directory in memory
;
1574,12 → 3494,12
add r2,r2,#512
dec r3
bne loadBootFile1
lda (PROG_LOAD_AREA>>2)+$80 ; make sure it's bootable
lda PROG_LOAD_AREA>>2 ; make sure it's bootable
cmp #$544F4F42
bne loadBootFile2
lda #msgJumpingToBoot
jsr DisplayStringB
lda (PROG_LOAD_AREA>>2)+$81
lda (PROG_LOAD_AREA>>2)+$1
jsr (r1)
jmp Monitor
loadBootFile2:
1601,27 → 3521,874
spi_init_error_msg:
db ": error occurred initializing the SD card.",0
spi_boot_error_msg:
db "SD card boot error",0
db "SD card boot error",CR,LF,0
spi_read_error_msg:
db "SD card read error",0
db "SD card read error",CR,LF,0
spi_write_error_msg:
db "SD card write error",0
 
;==============================================================================
; Ethernet
;==============================================================================
my_MAC1 EQU 0x00
my_MAC2 EQU 0xFF
my_MAC3 EQU 0xEE
my_MAC4 EQU 0xF0
my_MAC5 EQU 0xDA
my_MAC6 EQU 0x42
 
; Initialize the ethmac controller.
; Supply a MAC address, set MD clock
;
message "eth_init"
eth_init:
pha
phy
ldy #ETHMAC
lda #0x64 ; 100
sta ETH_MIIMODER,y
lda #7 ; PHY address
sta ETH_MIIADDRESS,y
lda #0xEEF0DA42
sta ETH_MAC_ADDR0,y ; MAC0
lda #0x00FF
sta ETH_MAC_ADDR1,y ; MAC1
ply
pla
rts
 
; Request a packet and display on screen
; r1 = address where to put packet
;
message "eth_request_packet"
eth_request_packet:
phx
phy
push r4
push r5
ldy #ETHMAC
ldx #4 ; clear rx interrupt
stx ETH_INT_SOURCE,y
sta 0x181,y ; storage address
ldx #0xe000 ; enable interrupt
stx 0x180,y
eth1:
nop
ldx ETH_INT_SOURCE,y
and r2,r2,#4 ; get bit #2
beq eth1
ldx 0x180,y ; get from descriptor
lsr r2,r2,#16
ldy #0
ld r4,#TEXTSCR+3780 ; second last line of screen
eth20:
add r5,r1,r3
ldx (r5) ; get byte
add r5,r4,r3
stx (r5) ; store to screen
iny
cpy #83
bne eth20
pop r5
pop r4
ply
plx
rts
 
; r1 = packet address
;
message "eth_interpret_packet"
eth_interpret_packet:
phx
phy
lb r2,12,r1
lb r3,13,r1
cpx #8 ; 0x806 ?
bne eth2
cpy #6
bne eth2
lda #2 ; return r1 = 2 for ARP
eth5:
ply
plx
rts
eth2:
cpx #8
bne eth3 ; 0x800 ?
cpy #0
bne eth3
lb r2,23,r1
cpx #1
bne eth4
lda #1
bra eth5 ; return 1 ICMP
eth4:
cpx #$11
bne eth6
lda #3 ; return 3 for UDP
bra eth5
eth6:
cpx #6
bne eth7
lda #4 ; return 4 for TCP
bra eth5
eth7:
eth3:
eor r1,r1,r1 ; return zero for unknown
ply
plx
rts
 
; r1 = address of packet to send
; r2 = packet length
;
message "eth_send_packet"
eth_send_packet:
phx
phy
push r4
ldy #ETHMAC
; wait for tx buffer to be clear
eth8:
ld r4,0x100,y
and r4,r4,#$8000
bne eth8
ld r4,#1 ; clear tx interrupt
st r4,ETH_INT_SOURCE,y
; set address
sta 0x101,y
; set the packet length field and enable interrupts
asl r2,r2,#16
or r2,r2,#0xF000
stx 0x100,y
pop r4
ply
plx
rts
 
; Only for IP type packets (not ARP)
; r1 = rx buffer address
; r2 = swap flag
; Returns:
; r1 = data start index
;
message "eth_build_packet"
eth_build_packet:
phy
push r4
push r5
push r6
push r7
push r8
push r9
push r10
 
lb r3,6,r1
lb r4,7,r1
lb r5,8,r1
lb r6,9,r1
lb r7,10,r1
lb r8,11,r1
; write to destination header
sb r3,0,r1
sb r4,1,r1
sb r5,2,r1
sb r6,3,r1
sb r7,4,r1
sb r8,5,r1
; write to source header
ld r3,#my_MAC1
sb r3,6,r1
ld r3,#my_MAC2
sb r3,7,r1
ld r3,#my_MAC3
sb r3,8,r1
ld r3,#my_MAC4
sb r3,9,r1
ld r3,#my_MAC5
sb r3,10,r1
ld r3,#my_MAC6
sb r3,11,r1
cmp r2,#1
bne eth16 ; if (swap)
lb r3,26,r1
lb r4,27,r1
lb r5,28,r1
lb r6,29,r1
; read destination
lb r7,30,r1
lb r8,31,r1
lb r9,32,r1
lb r10,33,r1
; write to sender
sb r7,26,r1
sb r8,27,r1
sb r9,28,r1
sb r10,29,r1
; write destination
sb r3,30,r1
sb r4,31,r1
sb r5,32,r1
sb r6,33,r1
eth16:
ldy eth_unique_id
iny
sty eth_unique_id
sb r3,19,r1
lsr r3,r3,#8
sb r3,18,r1
lb r3,14,r1
and r3,r3,#0xF
asl r3,r3,#2 ; *4
add r1,r3,#14 ; return datastart in r1
pop r10
pop r9
pop r8
pop r7
pop r6
pop r5
pop r4
ply
rts
 
; Compute IPv4 checksum of header
; r1 = packet address
; r2 = data start
;
message "eth_checksum"
eth_checksum:
phy
push r4
push r5
push r6
; set checksum to zero
stz 24,r1
stz 25,r1
eor r3,r3,r3 ; r3 = sum = zero
ld r4,#14
eth15:
ld r5,r2
dec r5 ; r5 = datastart - 1
cmp r4,r5
bpl eth14
add r6,r1,r4
lb r5,0,r6 ; shi = [rx_addr+i]
lb r6,1,r6 ; slo = [rx_addr+i+1]
asl r5,r5,#8
or r5,r5,r6 ; shilo
add r3,r3,r5 ; sum = sum + shilo
add r4,r4,#2 ; i = i + 2
bra eth15
eth14:
ld r5,r3 ; r5 = sum
and r3,r3,#0xffff
lsr r5,r5,#16
add r3,r3,r5
eor r3,r3,#-1
sb r3,25,r1 ; low byte
lsr r3,r3,#8
sb r3,24,r1 ; high byte
pop r6
pop r5
pop r4
ply
rts
 
; r1 = packet address
; returns r1 = 1 if this IP
;
message "eth_verifyIP"
eth_verifyIP:
phx
phy
push r4
push r5
lb r2,30,r1
lb r3,31,r1
lb r4,32,r1
lb r5,33,r1
; Check for general broadcast
cmp r2,#$FF
bne eth11
cmp r3,#$FF
bne eth11
cmp r4,#$FF
bne eth11
cmp r5,#$FF
bne eth11
eth12:
lda #1
eth13:
pop r5
pop r4
ply
plx
rts
eth11:
ld r1,r2
asl r1,r1,#8
or r1,r1,r3
asl r1,r1,#8
or r1,r1,r4
asl r1,r1,#8
or r1,r1,r5
cmp #$C0A8012A ; 192.168.1.42
beq eth12
eor r1,r1,r1
bra eth13
 
message "eth_main"
eth_main:
jsr eth_init
eth_loop:
jsr KeybdGetChar
cmp #-1
beq eth17
cmp #CTRLC
bne eth17
rts
eth17
lda #eth_rx_buffer<<2 ; memory address zero
jsr eth_request_packet
jsr eth_interpret_packet ; r1 = packet type
 
cmp #1
bne eth10
ld r2,r1 ; save off r1, r2 = packet type
lda #eth_rx_buffer<<2 ; memory address zero
jsr eth_verifyIP
tay
txa ; r1 = packet type again
cpy #1
bne eth10
 
lda #eth_rx_buffer<<2 ; memory address zero
ldx #1
jsr eth_build_packet
tay ; y = icmpstart
lda #eth_rx_buffer<<2 ; memory address zero
add r4,r1,r3
sb r0,0,r4 ; [rx_addr+icmpstart] = 0
lb r2,17,r1
add r2,r2,#14 ; r2 = len
ld r6,r2 ; r6 = len
add r15,r1,r3
lb r4,2,r15 ; shi
lb r5,3,r15 ; slo
asl r4,r4,#8
or r4,r4,r5 ; sum = {shi,slo};
eor r4,r4,#-1 ; sum = ~sum
sub r4,r4,#0x800 ; sum = sum - 0x800
eor r4,r4,#-1 ; sum = ~sum
add r15,r1,r3
sb r4,3,r15
lsr r4,r4,#8
sb r4,2,r15
tyx
jsr eth_checksum
lda #eth_rx_buffer<<2 ; memory address zero
ld r2,r6
jsr eth_send_packet
jmp eth_loop
eth10:
; r2 = rx_addr
cmp #2
bne eth_loop ; Do we have ARP ?
; xor r2,r2,r2 ; memory address zero
ldx #eth_rx_buffer<<2
; get the opcode
lb r13,21,x
cmp r13,#1
bne eth_loop ; ARP request
; get destination IP address
lb r9,38,x
lb r10,39,x
lb r11,40,x
lb r12,41,x
; set r15 = destination IP
ld r15,r9
asl r15,r15,#8
or r15,r15,r10
asl r15,r15,#8
or r15,r15,r11
asl r15,r15,#8
or r15,r15,r12
; Is it our IP ?
cmp r15,#$C0A8012A ; //192.168.1.42
bne eth_loop
; get source IP address
lb r5,28,x
lb r6,29,x
lb r7,30,x
lb r8,31,x
; set r14 = source IP
ld r14,r5
asl r14,r14,#8
or r14,r14,r6
asl r14,r14,#8
or r14,r14,r7
asl r14,r14,#8
or r14,r14,r8
; Get the source MAC address
push r6
push r7
push r8
push r9
push r10
push r11
lb r6,22,x
lb r7,23,x
lb r8,24,x
lb r9,25,x
lb r10,26,x
lb r11,27,x
; write to destination header
sb r6,0,x
sb r7,1,x
sb r8,2,x
sb r9,3,x
sb r10,4,x
sb r11,5,x
; and write to ARP destination
sb r6,32,x
sb r7,33,x
sb r8,34,x
sb r9,35,x
sb r10,36,x
sb r11,37,x
pop r11
pop r10
pop r9
pop r8
pop r7
pop r6
; write to source header
; stbc #0x00,6[r2]
; stbc #0xFF,7[r2]
; stbc #0xEE,8[r2]
; stbc #0xF0,9[r2]
; stbc #0xDA,10[r2]
; stbc #0x42,11[r2]
sb r0,6,x
lda #0xFF
sb r1,7,x
lda #0xEE
sb r1,8,x
lda #0xF0
sb r1,9,x
lda #0xDA
sb r1,10,x
lda #0x42
sb r1,11,x
; write to ARP source
; stbc #0x00,22[r2]
; stbc #0xFF,23[r2]
; stbc #0xEE,24[r2]
; stbc #0xF0,25[r2]
; stbc #0xDA,26[r2]
; stbc #0x42,27[r2]
sb r0,22,x
lda #0xFF
sb r1,23,x
lda #0xEE
sb r1,24,x
lda #0xF0
sb r1,25,x
lda #0xDA
sb r1,26,x
lda #0x42
sb r1,27,x
; swap sender / destination IP
; write sender
sb r9,28,x
sb r10,29,x
sb r11,30,x
sb r12,31,x
; write destination
sb r5,38,x
sb r6,39,x
sb r7,40,x
sb r8,41,x
; change request to reply
; stbc #2,21[r2]
lda #2
sb r1,21,x
txa ; r1 = packet address
ldx #0x2A ; r2 = packet length
jsr eth_send_packet
jmp eth_loop
 
;--------------------------------------------------------------------------
; Initialize sprite image caches with random data.
;--------------------------------------------------------------------------
RandomizeSprram:
ldx #SPRRAM
ld r4,#14336 ; number of chars to initialize
rsr1:
tsr LFSR,r1
sta (x)
inx
dec r4
bne rsr1
rts
 
;--------------------------------------------------------------------------
; Draw random lines on the bitmap screen.
;--------------------------------------------------------------------------
;
RandomLines:
pha
phx
phy
push r4
push r5
jsr RequestIOFocus
rl5:
tsr LFSR,r1
tsr LFSR,r2
jsr DrawPixel
tsr LFSR,r1
sta LineColor ; select a random color
rl1: ; random X0
tsr LFSR,r1
ld r5,#1364
mod r1,r1,r5
rl2: ; random X1
tsr LFSR,r3
mod r3,r3,r5
rl3: ; random Y0
tsr LFSR,r2
ld r5,#768
mod r2,r2,r5
rl4: ; random Y1
tsr LFSR,r4
ld r5,#768
mod r4,r4,r5
rl8:
jsr DrawLine
jsr KeybdGetChar
cmp #CTRLC
beq rl7
bra rl5
rl7:
jsr ReleaseIOFocus
pop r5
pop r4
ply
plx
pla
rts
 
DrawPixel:
pha
phx
phy
push r4
ld r4,#768
mod r2,r2,r4
ld r4,#1364
mod r1,r1,r4
mul r2,r2,r4 ; y * 1364
add r1,r1,r2 ; + x
ldy LineColor
sb r3,BITMAPSCR<<2,r1
pop r4
ply
plx
pla
rts
;50 REM DRAWLINE
;100 dx = ABS(xb-xa)
;110 dy = ABS(yb-ya)
;120 sx = SGN(xb-xa)
;130 sy = SGN(yb-ya)
;140 er = dx-dy
;150 PLOT xa,ya
;160 if xa<>xb goto 200
;170 if ya=yb goto 300
;200 ee = er * 2
;210 if ee <= -dy goto 240
;220 er = er - dy
;230 xa = xa + sx
;240 if ee >= dx goto 270
;250 er = er + dx
;260 ya = ya + sy
;270 GOTO 150
;300 RETURN
 
DrawLine:
pha
phx
phy
push r4
push r5
push r6
push r7
push r8
push r9
push r10
push r11
 
sub r5,r3,r1 ; dx = abs(x2-x1)
bpl dln1
sub r5,r0,r5
dln1:
sub r6,r4,r2 ; dy = abs(y2-y1)
bpl dln2
sub r6,r0,r6
dln2:
 
sub r7,r3,r1 ; sx = sgn(x2-x1)
beq dln5
bpl dln4
ld r7,#-1
bra dln5
dln4:
ld r7,#1
dln5:
 
sub r8,r4,r2 ; sy = sgn(y2-y1)
beq dln8
bpl dln7
ld r8,#-1
bra dln8
dln7:
ld r8,#1
 
dln8:
sub r9,r5,r6 ; er = dx-dy
dln150:
jsr DrawPixel
cmp r1,r3 ; if (xa <> xb)
bne dln200 ; goto 200
cmp r2,r4 ; if (ya==yb)
beq dln300 ; goto 300
dln200:
asl r10,r9 ; ee = er * 2
sub r11,r0,r6 ; r11 = -dy
cmp r10,r11 ; if (ee <= -dy)
bmi dln240 ; goto 240
beq dln240
sub r9,r9,r6 ; er = er - dy
add r1,r1,r7 ; xa = xa + sx
dln240:
cmp r10,r5 ; if (ee >= dx)
bpl dln150 ; goto 150
add r9,r9,r5 ; er = er + dx
add r2,r2,r8 ; ya = ya + sy
bra dln150 ; goto 150
 
dln300:
pop r11
pop r10
pop r9
pop r8
pop r7
pop r6
pop r5
pop r4
ply
plx
pla
rts
 
;include "float.asm"
 
;------------------------------------------------------------------------------
; Bus Error Routine
; This routine display a message then restarts the BIOS.
;------------------------------------------------------------------------------
;
message "bus_err_rout"
bus_err_rout:
cld
pla ; get rid of the stacked flags
ply ; get the error PC
ldx #$05FFFFF8 ; setup stack pointer top of memory
txs
jsr CRLF
lda #msgBusErr
jsr DisplayStringB
tya
jsr DisplayWord ; display the originating PC address
lda #msgDataAddr
jsr DisplayStringB
tsr #9,r1
jsr DisplayWord
cli ; enable interrupts so we can get a char
jsr KeybdGetChar
jmp start
msgBusErr:
db "Bus error at: ",0
msgDataAddr:
db " data address: ",0
 
strStartQue:
db 1,0,0,0,2,0,0,0,3,1,0,0,4,0,0,0
 
;------------------------------------------------------------------------------
; 100 Hz interrupt
; - takes care of "flashing" the cursor
; - switching tasks
;------------------------------------------------------------------------------
;
p100Hz:
inc IRQFlag ; support tiny basic's IRQ rout
inc TEXTSCR+83
; Handle every other interrupt because 100Hz interrupts may be too fast.
pha
lda IRQFlag
ina
sta IRQFlag
ror
bcc p100Hz11
pla
rti
 
p100Hz11:
 
cld ; clear extended precision mode
 
; save off regs on the stack
phx
phy
push r4
push r5
push r6
push r7
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
ldx RunningTCB
and r2,r2,#$FF
tsa ; save off the stack pointer
sta TCB_SPSave,x
tsr sp8,r1 ; and the eight bit mode stack pointer
sta TCB_SP8Save,x
 
; support EhBASIC's IRQ functionality
; code derived from minimon.asm
lda #3 ; Timer is IRQ #3
sta IrqSource ; stuff a byte indicating the IRQ source for PEEK()
lb r1,IrqBase ; get the IRQ flag byte
; ora #$20 ; set IRQ pending bit
lsr r2,r1
or r1,r1,r2
and #$E0
sb r1,IrqBase
 
 
inc TEXTSCR+83 ; update IRQ live indicator on screen
stz 0xFFDCFFFC ; clear interrupt
; flash the cursor
lda CursorFlash ; test if we want a flashing cursor
beq p100Hz1a
jsr CalcScreenLoc ; compute cursor location in memory
tay
lda $10000,y ; get color code $10000 higher in memory
ldx IRQFlag ; get counter
lsr r2,r2
and r2,r2,#$0F ; limit to low order nybble
and #$F0 ; prepare to or in new value, mask off foreground color
or r1,r1,r2 ; set new foreground color for cursor
sta $10000,y ; store the color code back to memory
p100Hz1a
 
; Check the timeout list to see if there are items ready to be removed from
; the list. Also decrement the timeout of the item at the head of the list.
 
p100Hz15:
ldx TimeoutList
bmi p100Hz12 ; are there any entries in the timeout list ?
lda TCB_Timeout,x
bne p100Hz14 ; has this entry timed out ?
txa
jsr RemoveFromTimeoutList
jsr AddTaskToReadyList
bra p100Hz15 ; go back and see if there's another task to be removed
 
p100Hz14:
dea ; decrement the entries timeout
sta TCB_Timeout,x
p100Hz12:
SelectTaskToRun:
; Search the ready queues for a ready task.
; The search is occasionally started at a lower priority queue in order
; to prevent starvation of lower priority tasks. This is managed by
; using a tick count as an index to a string containing the start que.
 
ld r6,#5 ; number of queues to search
ldy IRQFlag ; use the IRQFlag as a buffer index
lsr r3,r3,#1 ; the LSB is always the same
and r3,r3,#$0F ; counts from 0 to 15
lb r3,strStartQue,y ; get the queue to start search at
p100Hz2:
lda HeadRdy0,y
bmi p100Hz1
; Move the head of the ready queue to the tail
jsr RemoveTaskFromReadyList ; remove task
jsr AddTaskToReadyList ; add it back (automatically goes to tail spot)
ldx TCB_Status,r1 ; the task is no longer running
and r2,r2,#~TS_RUNNING
stx TCB_Status,r1
lda HeadRdy0,y
sta RunningTCB
ldx TCB_Status,r1 ; flag the task as the running task
or r2,r2,#TS_RUNNING
stx TCB_Status,r1
bra p100Hz3
p100Hz1:
iny
cpy #5
bne p100Hz5
ldy #0
p100Hz5
dec r6
bne p100Hz2
 
; here there were no tasks ready
stz RunningTCB ; select BIOS task
ldx TCB_Status ; flag the task as the running task
or r2,r2,#TS_RUNNING
stx TCB_Status
p100Hz3:
p100Hz10
ldx RunningTCB
and r2,r2,#$FF
lda TCB_SP8Save,x ; get back eight bit stack pointer
trs r1,sp8
ldx TCB_SPSave,x ; get back stack pointer
txs
; restore registers
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop r7
pop r6
pop r5
pop r4
ply
plx
pla
rti
 
 
;------------------------------------------------------------------------------
; 1000 Hz interrupt
; This IRQ must be fast.
; Increments the millisecond counter, and switches to the next context
; Increments the millisecond counter
;------------------------------------------------------------------------------
;
p1000Hz:
/rtf65002/trunk/software/asm/TinyBasic65002.asm
59,7 → 59,7
LOPVAR EQU 0x703
STKGOS EQU 0x704
CURRNT EQU 0x705
BUFFER EQU 0x406
BUFFER EQU 0x706
BUFLEN EQU 84
LOPPT EQU 0x760
LOPLN EQU 0x761
94,9 → 94,11
; Modifiable system constants:
;
align 4
TXTBGN dw 0x04080000 ;TXT ;beginning of program memory
ENDMEM dw 0x05FFDFF8 ; end of available memory
STACKOFFS dw 0x05FFDFF8 ; stack offset - leave a little room for the BIOS
;THRD_AREA dw 0x04000000 ; threading switch area 0x04000000-0x40FFFFF
;bitmap dw 0x04100000 ; bitmap graphics memory 0x04100000-0x417FFFF
TXTBGN dw 0x04180000 ;TXT ;beginning of program memory
ENDMEM dw 0x057FFFFF ; end of available memory
STACKOFFS dw 0x058FFFFF ; stack offset - leave a little room for the BIOS stacks
;
; The main interpreter starts here:
;
106,6 → 108,7
; r12 = end of text in text buffer
;
align 4
message "CSTART"
public CSTART:
; First save off the link register and OS sp value
tsx
112,10 → 115,11
stx OSSP
ldx STACKOFFS>>2 ; initialize stack pointer
txs
stz CursorRow ; set screen output
stz CursorCol
jsr RequestIOFocus
jsr HomeCursor
lda #0 ; turn off keyboard echoing
jsr SetKeyboardEcho
stz CursorFlash
stz pos
ldx #0x10000020 ; black chars, yellow background
; stx charToPrint
jsr ClearScreen
187,8 → 191,22
ld r1,r9 ; r1 = pointer to next line
ld r2,r13 ; pointer to line to be deleted
ldy TXTUNF ; points to top of save area
jsr MVUP ; move up to delete
stx TXTUNF ; update the end pointer
sub r1,r3,r9 ; r1 = length to move TXTUNF-pointer to next line
; dea ; count is one less
ld r2,r9 ; r2 = pointer to next line
ld r3,r13 ; r3 = pointer to line to delete
push r4
ST8:
ld r4,(x)
st r4,(y)
inx
iny
dea
bne ST8
pop r4
; mvn
; jsr MVUP ; move up to delete
sty TXTUNF ; update the end pointer
; we moved the lines of text after the line being
; deleted down, so the pointer to the next line
; needs to be reset
261,7 → 279,7
; executed if none of the other table items are matched.
;
; Character-matching tables:
 
message "TAB1"
TAB1:
db "LIS",'T'+0x80 ; Direct commands
db "LOA",'D'+0x80
384,6 → 402,7
; r9 = text table
; r10 = exec table
; r11 = trashed
message "DIRECT"
DIRECT:
ld r9,#TAB1
ld r10,#TAB1_1
423,14 → 442,7
EXGO:
; execute the appropriate routine
lb r1,1,r10 ; get the low mid order byte
asl
asl
asl
asl
asl
asl
asl
asl
asl r1,r1,#8
orb r1,r1,0,r10 ; get the low order byte
or r1,r1,#$FFFF0000 ; add in ROM base
jmp (r1)
1419,7 → 1431,7
rts
 
; <EXPR2>::=(+ or -)<EXPR3>(+ or -)<EXPR3>(...
 
message "EXPR2"
EXPR2:
ldy #'-'
ld r4,#XP21
2114,7 → 2126,7
; Note: a single zero word is stored on the stack in the
; case that no FOR loops need to be saved. This needs to be
; done because PUSHA / POPA is called all the time.
 
message "POPA"
POPA:
ply
pla
2244,10 → 2256,10
jsr GOOUT
rts
 
; 'PRTNUM' prints the 32 bit number in r3, leading blanks are added if
; needed to pad the number of spaces to the number in r4.
; 'PRTNUM' prints the 32 bit number in r1, leading blanks are added if
; needed to pad the number of spaces to the number in r2.
; However, if the number of digits is larger than the no. in
; r4, all digits are printed anyway. Negative sign is also
; r2, all digits are printed anyway. Negative sign is also
; printed and counted in, positive sign is not.
;
; r1 = number to print
2275,12 → 2287,11
stx (r7) ; and store in buffer
inc r7
dec r5 ; decrement width
beq PN6 ; safty, prevents infinte loop on div fail
cmp #0
bne PN1
PN6:
cmp r5,r0
bcc PN4 ; test pad count, skip padding if not needed
bmi PN4 ; test pad count, skip padding if not needed
beq PN4
PN3:
lda #' ' ; display the required leading spaces
2534,6 → 2545,7
; However, if a control-C is read, 'CHKIO' will warm-start BASIC and will
; not return to the caller.
;
message "CHKIO"
CHKIO:
jsr GOIN ; get input if possible
cmp #0
2607,11 → 2619,15
; return Zero status if there's no character available).
;
INCH:
jsr KeybdCheckForKeyDirect
cmp #0
; jsr KeybdCheckForKeyDirect
; cmp #0
; beq INCH1
jsr KeybdGetChar
cmp #-1
beq INCH1
jmp KeybdGetCharDirect
rts
INCH1:
ina ; return a zero for no-char
rts
 
;*
2638,8 → 2654,7
 
_cls
jsr ClearScreen
stz CursorRow
stz CursorCol
jsr HomeCursor
jmp FINISH
 
_wait10
2657,6 → 2672,7
; ===== Return to the resident monitor, operating system, etc.
;
BYEBYE:
jsr ReleaseIOFocus
ldx OSSP
txs
rts

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.