URL
https://opencores.org/ocsvn/rtf65002/rtf65002/trunk
Subversion Repositories rtf65002
[/] [rtf65002/] [trunk/] [software/] [asm/] [bootrom.asm] - Rev 39
Compare with Previous | Blame | View Log
; ============================================================================; __; \\__/ o\ (C) 2013, 2014 Robert Finch, Stratford; \ __ / All rights reserved.; \/_// robfinch<remove>@opencores.org; ||;;; This source file is free software: you can redistribute it and/or modify; it under the terms of the GNU Lesser General Public License as published; by the Free Software Foundation, either version 3 of the License, or; (at your option) any later version.;; This source file is distributed in the hope that it will be useful,; but WITHOUT ANY WARRANTY; without even the implied warranty of; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License; along with this program. If not, see <http://www.gnu.org/licenses/>.;; ============================================================================;cpu RTF65002CR EQU 0x0D ;ASCII equatesLF EQU 0x0ATAB EQU 0x09CTRLC EQU 0x03BELL EQU 0x07CTRLH EQU 0x08CTRLI EQU 0x09CTRLJ EQU 0x0ACTRLK EQU 0x0BCTRLM EQU 0x0DCTRLS EQU 0x13CTRLX EQU 0x18ESC EQU 0x1bXON EQU 0x11XOFF EQU 0x13; error codesE_Ok = 0x00E_Arg = 0x01E_BadMbx = 0x04E_QueFull = 0x05E_NoThread = 0x06E_NotAlloc = 0x09E_NoMsg = 0x0bE_Timeout = 0x10E_BadAlarm = 0x11E_NotOwner = 0x12E_QueStrategy = 0x13E_BadDevNum = 0x18E_DCBInUse = 0x19; Device driver errorsE_BadDevNum = 0x20E_NoDev = 0x21E_BadDevOp = 0x22E_ReadError = 0x23E_WriteError = 0x24E_BadBlockNum = 0x25E_TooManyBlocks = 0x26; resource errorsE_NoMoreMbx = 0x40E_NoMoreMsgBlks = 0x41E_NoMoreAlarmBlks =0x44E_NoMoreTCBs = 0x45E_NoMem = 12; task statusTS_NONE =0TS_TIMEOUT =1TS_WAITMSG =2TS_PREEMPT =4TS_RUNNING =8TS_READY =16TS_SLEEP =32TS_TIMEOUT_BIT =0TS_WAITMSG_BIT =1TS_RUNNING_BIT =3TS_READY_BIT =4PRI_HIGHEST =0PRI_HIGH =1PRI_NORMAL =2PRI_LOW =3PRI_LOWEST =4MAX_TASKNO = 63DRAM_BASE = $04000000DIRENT_NAME =0x00 ; file nameDIRENT_EXT =0x1C ; file name extensionDIRENT_ATTR =0x20 ; attributesDIRENT_DATETIME =0x28DIRENT_CLUSTER =0x30 ; starting cluster of fileDIRENT_SIZE =0x34 ; file size (6 bytes); One FCB is allocated and filled out for each file that is open.;nFCBs = 128FCB_DE_NAME =0x00FCB_DE_EXT =0x1CFCB_DE_ATTR =0x20FCB_DE_DATETIME =0x28FCB_DE_CLUSTER =0x30 ; starting cluster of fileFCB_DE_SIZE =0x34 ; 6 byte file sizeFCB_DIR_SECTOR =0x40 ; LBA directory sector this is fromFCB_DIR_ENT =0x44 ; offset in sector for dir entryFCB_LDRV =0x48 ; logical drive this is onFCB_MODE =0x49 ; 0 read, 1=modifyFCB_NUSERS =0x4A ; number of users of this fileFCB_FMOD =0x4B ; flag: this file was modifiedFCB_RESV =0x4C ; padding out to 80 bytesFCB_SIZE =0x50FUB_JOB =0x00 ; User's job umberFUB_iFCB =0x02 ; FCB number for this fileFUB_CrntLFA =0x04 ; six byte current logical file addressFUB_pBuf =0x0C ; pointer to buffer if in stream modeFUB_sBuf =0x10 ; size of buffer for stream fileFUB_LFABuf =0x14 ; S-First LFA in Clstr BufferFUB_LFACluster =0x18 ; LFA of clusterFUB_Clstr = 0x20 ; The last cluster readFUB_fModified = 0x24 ; data in buffer was modifiedFUB_fStream = 0x25 ; non-zero for stream modeFUB_PAD =0x26FUB_SIZE =0x30; Boot sector info (62 byte structure) */BSI_JMP = 0x00BSI_OEMName = 0x03BSI_bps = 0x0BBSI_SecPerCluster = 0x0DBSI_ResSectors = 0x0EBSI_FATS = 0x10BSI_RootDirEnts = 0x11BSI_Sectors = 0x13BSI_Media = 0x15BSI_SecPerFAT = 0x16BSI_SecPerTrack = 0x18BSI_Heads = 0x1ABSI_HiddenSecs = 0x1CBSI_HugeSecs = 0x1EBSI_DriveNum = 0x24BSI_Rsvd1 = 0x25BSI_BootSig = 0x26BSI_VolID = 0x27BSI_VolLabel = 0x2BBSI_FileSysType = 0x36MEM_CHK =0MEM_FLAG =1MEM_PREV =2MEM_NEXT =3; message queuing strategyMQS_UNLIMITED =0 ; unlimited queue sizeMQS_NEWEST =1 ; buffer queue size newest messagesMQS_OLDEST =2 ; buffer queue size oldest messagesLEDS EQU 0xFFDC0600TEXTSCR EQU 0xFFD00000COLORSCR EQU 0xFFD10000TEXTREG EQU 0xFFDA0000TEXT_COLS EQU 0x0TEXT_ROWS EQU 0x1TEXT_CURPOS EQU 11TEXT_CURCTL EQU 8BMP_CLUT EQU $FFDC5800KEYBD EQU 0xFFDC0000KEYBDCLR EQU 0xFFDC0001PIC EQU 0xFFDC0FF0PIC_IE EQU 0xFFDC0FF1PIC_ES EQU 0xFFDC0FF4PIC_RSTE EQU 0xFFDC0FF5TASK_SELECT EQU 0xFFDD0008RQ_SEMA EQU 0xFFDB0000to_sema EQU 0xFFDB0010SERIAL_SEMA EQU 0xFFDB0020keybd_sema EQU 0xFFDB0030iof_sema EQU 0xFFDB0040mbx_sema EQU 0xFFDB0050freembx_sema EQU 0xFFDB0060mem_sema EQU 0xFFDB0070freemsg_sema EQU 0xFFDB0080tcb_sema EQU 0xFFDB0090readylist_sema EQU 0xFFDB00A0tolist_sema EQU 0xFFDB00B0msg_sema EQU 0xFFDB00C0freetcb_sema EQU 0xFFDB00D0freejcb_sema EQU 0xFFDB00E0jcb_sema EQU 0xFFDB00F0device_semas EQU 0xFFDB1000device_semas_end EQU 0xFFDB1200SPIMASTER EQU 0xFFDC0500SPI_MASTER_VERSION_REG EQU 0x00SPI_MASTER_CONTROL_REG EQU 0x01SPI_TRANS_TYPE_REG EQU 0x02SPI_TRANS_CTRL_REG EQU 0x03SPI_TRANS_STATUS_REG EQU 0x04SPI_TRANS_ERROR_REG EQU 0x05SPI_DIRECT_ACCESS_DATA_REG EQU 0x06SPI_SD_SECT_7_0_REG EQU 0x07SPI_SD_SECT_15_8_REG EQU 0x08SPI_SD_SECT_23_16_REG EQU 0x09SPI_SD_SECT_31_24_REG EQU 0x0aSPI_RX_FIFO_DATA_REG EQU 0x10SPI_RX_FIFO_DATA_COUNT_MSB EQU 0x12SPI_RX_FIFO_DATA_COUNT_LSB EQU 0x13SPI_RX_FIFO_CTRL_REG EQU 0x14SPI_TX_FIFO_DATA_REG EQU 0x20SPI_TX_FIFO_CTRL_REG EQU 0x24SPI_RESP_BYTE1 EQU 0x30SPI_RESP_BYTE2 EQU 0x31SPI_RESP_BYTE3 EQU 0x32SPI_RESP_BYTE4 EQU 0x33SPI_INIT_SD EQU 0x01SPI_TRANS_START EQU 0x01SPI_TRANS_BUSY EQU 0x01SPI_INIT_NO_ERROR EQU 0x00SPI_READ_NO_ERROR EQU 0x00SPI_WRITE_NO_ERROR EQU 0x00RW_READ_SD_BLOCK EQU 0x02RW_WRITE_SD_BLOCK EQU 0x03CONFIGREC EQU 0xFFDCFFF0CR_CLOCK EQU 0xFFDCFFF4GACCEL EQU 0xFFDAE000GA_X0 EQU 0xFFDAE002GA_Y0 EQU 0xFFDAE003GA_PEN EQU 0xFFDAE000GA_X1 EQU 0xFFDAE004GA_Y1 EQU 0xFFDAE005GA_STATE EQU 0xFFDAE00EGA_CMD EQU 0xFFDAE00FAC97 EQU 0xFFDC1000PSG EQU 0xFFD50000PSGFREQ0 EQU 0xFFD50000PSGPW0 EQU 0xFFD50001PSGCTRL0 EQU 0xFFD50002PSGADSR0 EQU 0xFFD50003ETHMAC EQU 0xFFDC2000ETH_MODER EQU 0x00ETH_INT_SOURCE EQU 0x01ETH_INT_MASK EQU 0x02ETH_IPGT EQU 0x03ETH_IPGR1 EQU 0x04ETH_IPGR2 EQU 0x05ETH_PACKETLEN EQU 0x06ETH_COLLCONF EQU 0x07ETH_TX_BD_NUM EQU 0x08ETH_CTRLMODER EQU 0x09ETH_MIIMODER EQU 0x0AETH_MIICOMMAND EQU 0x0BETH_MIIADDRESS EQU 0x0CETH_MIITX_DATA EQU 0x0DETH_MIIRX_DATA EQU 0x0EETH_MIISTATUS EQU 0x0FETH_MAC_ADDR0 EQU 0x10ETH_MAC_ADDR1 EQU 0x11ETH_HASH0_ADDR EQU 0x12ETH_HASH1_ADDR EQU 0x13ETH_TXCTRL EQU 0x14ETH_WCTRLDATA EQU 4ETH_MIICOMMAND_RSTAT EQU 2ETH_MIISTATUS_BUSY EQU 2ETH_MIIMODER_RST EQU $200ETH_MODER_RST EQU $800ETH_MII_BMCR EQU 0 ; basic mode control registerETH_MII_ADVERTISE EQU 4ETH_MII_EXPANSION =6ETH_MII_CTRL1000 =9ETH_ADVERTISE_ALL EQU $1E0ETH_ADVERTISE_1000FULL =0x0200 ; Advertise 1000BASE-T full duplexETH_ADVERTISE_1000HALF =0x0100 ; Advertise 1000BASE-T half duplexETH_ESTATUS_1000_TFULL =0x2000 ; Can do 1000BT FullETH_ESTATUS_1000_THALF =0x1000 ; Can do 1000BT HalfETH_BMCR_ANRESTART = 0x0200 ; Auto negotiation restartETH_BMCR_ISOLATE = 0x0400 ; Disconnect DP83840 from MIIETH_BMCR_PDOWN = 0x0800 ; Powerdown the DP83840ETH_BMCR_ANENABLE = 0x1000 ; Enable auto negotiationETH_PHY =7MMU EQU 0xFFDC4000MMU_KVMMU EQU 0xFFDC4800MMU_FUSE EQU 0xFFDC4811MMU_AKEY EQU 0xFFDC4812MMU_OKEY EQU 0xFFDC4813MMU_MAPEN EQU 0xFFDC4814DATETIME EQU 0xFFDC0400DATETIME_TIME EQU 0xFFDC0400DATETIME_DATE EQU 0xFFDC0401DATETIME_ALMTIME EQU 0xFFDC0402DATETIME_ALMDATE EQU 0xFFDC0403DATETIME_CTRL EQU 0xFFDC0404DATETIME_SNAPSHOT EQU 0xFFDC0405SPRITEREGS EQU 0xFFDAD000SPRRAM EQU 0xFFD80000THRD_AREA EQU 0x00000000 ; threading area 0x04000000-0x40FFFFFBITMAPSCR EQU 0x00100000SECTOR_BUF EQU 0x01FBEC00BYTE_SECTOR_BUF EQU SECTOR_BUF<<2PROG_LOAD_AREA EQU 0x0300000<<2FCBs EQU 0x1F40000 ; room for 128 FCB'sFATOFFS EQU 0x1F50000 ; offset into FAT on cardFATBUF EQU 0x1F60000DIRBUF EQU 0x1F70000eth_rx_buffer EQU 0x1F80000eth_tx_buffer EQU 0x1F84000; Mailboxes, room for 2048.bss.org 0x01F90000NR_MBX EQU $800MBX_LINK fill.w NR_MBX,0 ; link to next mailbox in list (free list)MBX_TQ_HEAD fill.w NR_MBX,0 ; head of task queueMBX_TQ_TAIL fill.w NR_MBX,0MBX_MQ_HEAD fill.w NR_MBX,0 ; head of message queueMBX_MQ_TAIL fill.w NR_MBX,0MBX_TQ_COUNT fill.w NR_MBX,0 ; count of queued threadsMBX_MQ_SIZE fill.w NR_MBX,0 ; number of messages that may be queuedMBX_MQ_COUNT fill.w NR_MBX,0 ; count of messages that are queuedMBX_MQ_MISSED fill.w NR_MBX,0 ; number of messages dropped from queueMBX_OWNER fill.w NR_MBX,0 ; job handle of mailbox ownerMBX_MQ_STRATEGY fill.w NR_MBX,0 ; message queueing strategyMBX_RESV fill.w NR_MBX,0; Messages, room for 64kW (16,384) messages.bss.org 0x01FA0000NR_MSG EQU 16384MSG_LINK fill.w NR_MSG,0 ; link to next message in queue or free listMSG_D1 fill.w NR_MSG,0 ; message data 1MSG_D2 fill.w NR_MSG,0 ; message data 2MSG_TYPE fill.w NR_MSG,0 ; message typeMSG_END EQU MSG_TYPE + NR_MSGMT_SEMA EQU 0xFFFFFFFFMT_IRQ EQU 0xFFFFFFF0MT_GETCHAR EQU 0xFFFFFFEFNR_JCB EQU 32JCB_Number EQU 0JCB_Name EQU 1 ; 32 bytes (1 len + 31)JCB_Map EQU 9 ; memory map number associated with jobJCB_pCode EQU 10JCB_nCode EQU 11 ; size of codeJCB_pData EQU 12JCB_nData EQU 13 ; size of dataJCB_pStack EQU 14JCB_nStack EQU 15JCB_UserName EQU 16 ; 32 bytesJCB_Path EQU 24 ; 80 bytesJCB_ExitRF EQU 44 ; 80 bytesJCB_CmdLine EQU 84 ; 240 bytesJCB_SysIn EQU 140 ; 40 charsJCB_SysOut EQU 150 ; 40 charsJCB_ExitError EQU 160JCB_pVidMem EQU 161 ; pointer to video memoryJCB_pVidMemAttr EQU 162JCB_pVirtVid EQU 163 ; pointer to virtual video bufferJCB_pVirtVidAttr EQU 164JCB_VideoMode EQU 165JCB_VideoRows EQU 166JCB_VideoCols EQU 167JCB_CursorRow EQU 168JCB_CursorCol EQU 169JCB_CursorOn EQU 170JCB_CursorFlash EQU 171JCB_CursorType EQU 172JCB_NormAttr EQU 173JCB_CurrAttr EQU 174JCB_ScrlCnt EQU 175JCB_fVidPause EQU 176JCB_Next EQU 177JCB_iof_next EQU 178 ; I/O focus listJCB_iof_prev EQU 179JCB_VMP_bitmap_b0 EQU 180 ; 512 bits - virtual memory page bitmapJCB_VMP_bitmap_b1 EQU 196 ; 512 bits - virtual memory page bitmapJCB_KeybdHead EQU 212JCB_KeybdTail EQU 213JCB_KeybdEcho EQU 214JCB_KeybdBad EQU 215JCB_KeybdAck EQU 216JCB_KeybdLocks EQU 217JCB_KeybdBuffer EQU 218 ; buffer is 16 words (chars = words)JCB_esc EQU 234 ; escape flag for DisplayChar processingJCB_Size EQU 256JCB_LogSize EQU 8.bssJCBs fill.w NR_JCB * JCB_Size,0FreeJCB dw 0.bss.org 0x01FBA000; Task control blocks, room for 256 tasksNR_TCB EQU 256TCB_NxtRdy fill.w NR_TCB,0 ; EQU 0x01FBE100 ; next task on ready / timeout listTCB_PrvRdy fill.w NR_TCB,0 ; EQU 0x01FBE200 ; previous task on ready / timeout listTCB_NxtTCB fill.w NR_TCB,0 ; EQU 0x01FBE300TCB_Timeout fill.w NR_TCB,0 ; EQU 0x01FBE400TCB_Priority fill.w NR_TCB,0 ; EQU 0x01FBE500TCB_MSG_D1 fill.w NR_TCB,0 ; EQU 0x01FBE600TCB_MSG_D2 fill.w NR_TCB,0 ; EQU 0x01FBE700TCB_hJCB fill.w NR_TCB,0 ; EQU 0x01FBE800TCB_Status fill.w NR_TCB,0 ; EQU 0x01FBE900TCB_CursorRow fill.w NR_TCB,0 ; EQU 0x01FBD100TCB_CursorCol fill.w NR_TCB,0 ; EQU 0x01FBD200TCB_hWaitMbx fill.w NR_TCB,0 ; EQU 0x01FBD300 ; handle of mailbox task is waiting atTCB_mbq_next fill.w NR_TCB,0 ; EQU 0x01FBD400 ; mailbox queue nextTCB_mbq_prev fill.w NR_TCB,0 ; EQU 0x01FBD500 ; mailbox queue previousTCB_SP8Save fill.w NR_TCB,0 ; EQU 0x01FBD800 ; TCB_SP8Save areaTCB_SPSave fill.w NR_TCB,0 ; EQU 0x01FBD900 ; TCB_SPSave areaTCB_StackTop fill.w NR_TCB,0TCB_ABS8Save fill.w NR_TCB,0 ; EQU 0x01FBDA00TCB_mmu_map fill.w NR_TCB,0 ; EQU 0x01FBDB00TCB_npages fill.w NR_TCB,0 ; EQU 0x01FBDC00TCB_ASID fill.w NR_TCB,0 ; EQU 0x01FBDD00TCB_errno fill.w NR_TCB,0 ; EQU 0x01FBDE00TCB_NxtTo fill.w NR_TCB,0 ; EQU 0x01FBDF00TCB_PrvTo fill.w NR_TCB,0 ; EQU 0x01FBE000TCB_MbxList fill.w NR_TCB,0 ; EQU 0x01FBCF00 ; head pointer to list of mailboxes associated with taskTCB_mbx fill.w NR_TCB,0 ; EQU 0x01FBCE00TCB_HeapStart fill.w NR_TCB,0 ; Starting address of heap in task's memory spaceTCB_HeapEnd fill.w NR_TCB,0 ; Ending addres of heap in task's memory space;include "jcb.inc"NR_MMU_MAP EQU 32VPM_bitmap_b0 fill.w NR_MMU_MAP * 16,0VPM_bitmap_b1 fill.w NR_MMU_MAP * 16,0nPagesFree dw 0message "cachInvRout".bss.align 4096cacheInvRout:fill.w 4096,0cacheLineInvRout:fill.w 4096,0message "SCREEN_SIZE".bss.org 0x01D00000SCREEN_SIZE EQU 8192BIOS_SCREENS fill.w SCREEN_SIZE * NR_JCB ; 0x01D00000 to 0x01EFFFFF; Bitmap of tasks requesting the I/O focus;IOFocusTbl fill.w 8,0MAX_DEV_OP EQU 31; Device Control Block;DCB_NAME EQU 0DCB_NAME_LEN EQU 3DCB_TYPE EQU 4DCB_nBPB EQU 5DCB_last_erc EQU 6DCB_nBlocks EQU 7DCB_pDevOp EQU 8DCB_pDevInit EQU 9DCB_pDevStat EQU 10DCB_ReentCount EQU 11DCB_fSingleUser EQU 12DCB_hJob EQU 13DCB_Mbx EQU 14DCB_Sema EQU 15DCB_OSD3 EQU 16DCB_OSD4 EQU 17DCB_OSD5 EQU 18DCB_OSD6 EQU 19DCB_SIZE EQU 20;Standard Devices are:;# Device Standard name;0 NULL device NUL (OS built-in);1 Keyboard (sequential) KBD (OS built-in);2 Video (sequential) VID (OS built-in);3 Printer (parallel 1) LPT;4 Printer (parallel 2) LPT2;5 RS-232 1 COM1 (OS built-in);6 RS-232 2 COM2;7 RS-232 3 COM3;8 RS-232 4 COM4;9;10 Floppy FD0;11 Floppy FD1;12 Hard disk HD0;13 Hard disk HD1;14;15;16 SDCard CARD1 (OS built-in);17;18;19;20;21;22;23;24;25;26;27;28 Audio PSG1 (OS built-in);29;30;31NR_DCB EQU 32DCBs fill NR_DCB * DCB_SIZE,0 ; EQU MSG_ENDDCBs_END EQU DCBs + DCB_SIZE * NR_DCB; preallocated stacks for TCBs.bss.org 0x01FC0000 ; to 0x01FFFFFFSTACK_SIZE EQU $400 ; 1kWBIOS_STACKS fill.w STACK_SIZE * NR_TCB ; room for 256 1kW stacksHeapStart EQU 0x00540000HeapEnd EQU BIOS_SCREENS-1; EhBASIC vars:;NmiBase EQU 0xDCIrqBase EQU 0xDF; BIOS vars at the top of the 8kB scratch memory;; TinyBasic AREA = 0x6C0 to 0x77FPageMap EQU 0x600PageMapEnd EQU 0x63FPageMap2 EQU 0x640PageMap2End EQU 0x67Fmem_pages_free EQU 0x680bssorg 0x780QNdx0 dw 0QNdx1 dw 0QNdx2 dw 0QNdx3 dw 0QNdx4 dw 0FreeTCB dw 0TimeoutList dw 0RunningTCB dw 0FreeMbxHandle dw 0nMailbox dw 0FreeMsg dw 0nMsgBlk dw 0missed_ticks dw 0keybdmsg_d1 dw 0keybdmsg_d2 dw 0keybd_mbx dw 0keybd_char dw 0keybdIsSetup dw 0keybdLock dw 0keybdInIRQ dw 0iof_switch dw 0clockmsg_d1 dw 0clockmsg_d2 dw 0tcbsema_d1 dw 0tcbsema_d2 dw 0mmu_acc_save dw 0; The IO focus list is a doubly linked list formed into a ring.;IOFocusNdx dw 0 ; really a pointer to the JCB owning the IO focus;test_mbx dw 0test_D1 dw 0test_D2 dw 0tone_cnt dw 0IrqSource EQU 0x79F.align 0x10JMPTMP dw 0SP8Save dw 0SRSave dw 0R1Save dw 0R2Save dw 0R3Save dw 0R4Save dw 0R5Save dw 0R6Save dw 0R7Save dw 0R8Save dw 0R9Save dw 0R10Save dw 0R11Save dw 0R12Save dw 0R13Save dw 0R14Save dw 0R15Save dw 0SPSave dw 0.align 0x10CharColor dw 0ScreenColor dw 0CursorRow dw 0CursorCol dw 0CursorFlash dw 0Milliseconds dw 0IRQFlag dw 0UserTick dw 0eth_unique_id dw 0LineColor dw 0QIndex dw 0ROMcs dw 0mmu_present dw 0TestTask dw 0BASIC_SESSION dw 0gr_cmd dw 0.align 0x10startSector dw 0disk_size dw 0;; CAUTION:; - do not use these macros.; - there is currently a bug in the assembler that causes it to lose the; macro text;macro mStartTask pri,flags,start_addr,param,joblda prildx flagsldy start_addrld r4,paramld r5,jobint #4db 1endmmacro mSleep tmlda tmint #4db 5endmmacro mAllocMbxint #4db 6endmmacro mWaitMsg mbx,tmoutlda mbxldx tmoutint #4db 10endmmacro mPostMsg mbx,d1,d2lda mbxldx d1ldy d2int #4db 8endmmacro DisTimerphalda #3sta PIC+2plaendmmacro EnTimerphalda #3sta PIC+3plaendmmacro DisTmrKbdphalda #3sta PIC+2lda #15sta PIC+2plaendmmacro EnTmrKbdphalda #3sta PIC+3lda #15sta PIC+3plaendmmacro GoRescheduleint #2endm;------------------------------------------------------------------------------; Wait for the TCB array to become available;------------------------------------------------------------------------------;macro mAquireTCBlda #33ldx #0txyld r4,#-1jsr WaitMsgendmmacro mReleaseTCBlda #33ldx #$FFFFFFFEtxyjsr SendMsgendmmacro mAquireMBXlda #34ldx #0txyld r4,#-1jsr WaitMsgendmmacro mReleaseMBXlda #34ldx #$FFFFFFFEtxyjsr SendMsgendmcpu rtf65002codemessage "jump table"; jump table of popular BIOS routinesorg $FFFF8000ROMStart:dw DisplayChardw KeybdCheckForKeyDirectdw KeybdGetCharDirectdw KeybdGetChardw KeybdCheckForKeydw RequestIOFocusdw ReleaseIOFocusdw ClearScreendw HomeCursordw ExitTaskdw SetKeyboardEchodw Sleepdw do_loaddw do_savedw ICacheInvalidateAlldw ICacheInvalidateLineorg $FFFF8400 ; leave room for 256 vectorsmessage "cold start point"KeybdRSTstartsei ; disable interruptscld ; disable decimal modelda #1sta LEDSldx #BIOS_STACKS+0x03FF ; setup stack pointer top of memorytxstrs r0,abs8 ; set 8 bit mode absolute address offsetlda #3trs r1,cc ; enable dcache and icachejsr ROMChecksumsta ROMcsjsr SetupCacheInvalidatejsr InitDevicesstz mmu_present ; assume no mmulda CONFIGRECbit #4096beq st_nommujsr InitMMU ; setup the maps and enable the mmulda #1sta mmu_presentst_nommu:jsr MemInit ; Initialize the heapstz iof_switchlda #2sta LEDS; setup interrupt vectorsldx #$01FB8001 ; interrupt vector table from $5FB0000 to $5FB01FF; also sets nmoi policy (native mode on interrupt)trs r2,vbrand r2,r2,#-2 ; mask off policy bitphxtxy ; y = pointer to vector tablelda #511 ; 512 vectors to setupldx #brk_rout ; point vector to brk routinestosplxlda #brk_routsta (x)lda #slp_routsta 1,xlda #reschedule ; must be initialized after vectors are initialized to the break vectorsta 2,xlda #spinlock_irqsta 3,xlda #syscall_intsta 4,xlda #KeybdRSTsta 448+1,xlda #p1000Hzsta 448+2,xlda #MTKTicksta 448+3,xlda #KeybdIRQsta 448+15,xlda #SerialIRQsta 448+8,xlda #InvalidOpIRQsta 495,xlda #bus_err_routsta 508,xsta 509,xlda #3sta LEDS; stay in native mode in case emulation is not supported.ldx #$1FF ; set 8 bit stack pointertrs r2,sp8ldx #0stz IrqBase ; support for EhBASIC's interrupt mechanismstz NmiBasejsr ($FFFFC000>>2) ; Initialize multi-taskinglda #TickRout ; setup tick routinesta UserTicklda #1sta iof_semalda #(DCB_SIZE * NR_DCB)-1ldx #0ldy #DCBsstoslda #$CE ; CE =blue on blue FB = grey on greysta ScreenColorsta CharColorsta CursorFlashjsr ClearScreenjsr InitBMPjsr ClearBmpScreenjsr PICInit; Enable interrupts; This will likely cause an interrupt right away because the timer; pulses run since power-up.cli; mStartTask #PRI_LOWEST,#0,#IdleTask,#0,#0lda #PRI_LOWESTldx #0ldy #IdleTaskld r4,#0ld r5,#0int #4db 1lda CONFIGREC ; do we have a serial port ?bit #32beq st7; 19200 * 16;-------------; 25MHz / 2^32lda #$03254E6E ; constant for 19,200 baud at 25MHzjsr SerialInitst7:lda #5sta LEDSlda CONFIGREC ; do we have sprites ?bit #1beq st8lda #$3FFF ; turn on spritessta SPRITEREGS+120jsr RandomizeSprramst8:; Enable interrupts.; Keyboard initialization must take place after interrupts are; enabled.clilda #14sta LEDSstz keybdIsSetup; mStartTask #PRI_NORMAL,#0,#KeybdSetup,#0lda #PRI_NORMALldx #0ldy #KeybdSetupld r4,#0ld r5,#0int #4db 1; lea r3,KeybdStatusLEDs; jsr StartTasklda #6sta LEDS; The following must be after interrupts are enabled.lda #9sta LEDSjsr HomeCursorlda #msgStartjsr DisplayStringBjsr ReportMemFreelda #msgChecksumjsr DisplayStringBlda ROMcsjsr DisplayWordjsr CRLFlda #10sta LEDS; The AC97 setup uses the millisecond counter and the; keyboard.lda CONFIGREC ; do we have a sound generator ?bit #4beq st6jsr SetupAC97lda #4ldx #0ldy #Beep; jsr StartTaskst6:lda #11sta LEDSstz BASIC_SESSIONjmp Monitorst1jsr KeybdGetCharDirectbra st1stpbra startmsgStartdb "RTF65002 system starting.",$0d,$0a,00;------------------------------------------------------------------------------; SetupCacheInvalidate:;; Setup the cache invalidate routines. Cache's in the FPGA don't have; invalidate logic as it cannot be efficiently implemented. So we handle; cache invalidations using software. By calling a software routine, or; accessing data in the setup cache invalidate area, the cache will be; effectively invalidated. This works for caches up to 16kB. (4kW);------------------------------------------------------------------------------message "SetupCacheInvalidate"SetupCacheInvalidate:lda #4095ldx #$EAEAEAEA ; fill memory with NOP'sldy #cacheInvRoutstoslda #4095ldx #$60606060 ; fill memory with RTS'sldy #cacheLineInvRoutstosrts;------------------------------------------------------------------------------; ICacheInvalidateAll:;; Call to invalidate the entire ICache;------------------------------------------------------------------------------ICacheInvalidateAll:jml cacheInvRout<<2;------------------------------------------------------------------------------; ICacheInvalidateLine:;; Call to invalidate a specific cache line;; Parameters:; r1 = code address in line to invalidate;------------------------------------------------------------------------------;ICacheInvalidateLine:and #$3FFFadd #cacheLineInvRout<<2jmp (r1) ; this will touch the cache line then RTS;------------------------------------------------------------------------------; DCacheInvalidateAll:;; Call to invalidate the entire DCache. Works by performing a data fetch from; dummy data at each possible cache address. Works for caches up to 16kB in; size.;------------------------------------------------------------------------------DCacheInvalidateAll:phxldx #0.0001:ld r0,cacheInvRout,xinxcpx #$FFFbls .0001plxrts;------------------------------------------------------------------------------; DCacheInvalidateLine:;; Call to invalidate a specific cache line in the data cache.;; Parameters:; r1 = data address in line to invalidate;------------------------------------------------------------------------------;DCacheInvalidateLine:phaand #$FFFld r0,cacheInvRout,r1plarts;------------------------------------------------------------------------------;------------------------------------------------------------------------------InitBMP:ldx #0ibmp1:tsr LFSR,r1sta BMP_CLUT,xinxcpx #512bne ibmp1rts;------------------------------------------------------------------------------; The ROM contents are summed up to ensure the ROM is okay.;------------------------------------------------------------------------------ROMChecksum:lda #0ldx #ROMStart>>2idc1:add (x)inxcpx #$100000000>>2bne idc1cmp #0 ; The sum of all the words in the; ROM should be zero.rtsmsgChecksum:db CR,LF,"ROM checksum: ",0;----------------------------------------------------------; Initialize programmable interrupt controller (PIC); 0 = nmi (parity error); 1 = keyboard reset; 2 = 1000Hz pulse; 3 = 100Hz pulse (cursor flash); 4 = ethmac; 8 = uart; 13 = raster interrupt; 15 = keyboard char;----------------------------------------------------------message "PICInit"PICInit:;lda #$000C ; clock pulses are edge sensitivesta PIC_ESlda #$000F ; enable nmi,kbd_rst; A10F enable serial IRQsta PIC_IEPICret:rts;------------------------------------------------------------------------------;------------------------------------------------------------------------------message "DumpTaskList"DumpTaskList:phaphxphypush r4lda #msgTaskListjsr DisplayStringBldy #0spl tcb_sema + 1dtl2:lda QNdx0,yld r4,r1bmi dtl1dtl3:ldx #3tyajsr PRTNUMlda #' 'jsr DisplayCharld r1,r4ldx #3jsr PRTNUMlda #' 'jsr DisplayCharjsr DisplayCharjsr DisplayCharld r1,r4lda TCB_Status,r1jsr DisplayBytelda #' 'jsr DisplayCharldx #3lda TCB_PrvRdy,r4jsr PRTNUMlda #' 'jsr DisplayCharldx #3lda TCB_NxtRdy,r4jsr PRTNUMlda #' 'jsr DisplayCharlda TCB_Timeout,r4jsr DisplayWordjsr CRLFld r4,TCB_NxtRdy,r4cmp r4,QNdx0,ybne dtl3dtl1:inycpy #5bne dtl2stz tcb_sema + 1pop r4plyplxplartsmsgTaskList:db CR,LF,"Pri Task Stat Prv Nxt Timeout",CR,LF,0;------------------------------------------------------------------------------;------------------------------------------------------------------------------message "DumpTimeoutList"DumpTimeoutList:phaphxphypush r4lda #msgTimeoutListjsr DisplayStringBldy #11dtol2:lda TimeoutListld r4,r1bmi dtol1spl tcb_sema + 1dtol3:deybeq dtol1ld r1,r4ldx #3jsr PRTNUMlda #' 'jsr DisplayCharjsr DisplayCharjsr DisplayCharld r1,r4ldx #3lda TCB_PrvTo,r4jsr PRTNUMlda #' 'jsr DisplayCharldx #3lda TCB_NxtTo,r4jsr PRTNUMlda #' 'jsr DisplayCharlda TCB_Timeout,r4jsr DisplayWordjsr CRLFld r4,TCB_NxtTo,r4bpl dtol3dtol1:stz tcb_sema + 1pop r4plyplxplartsmsgTimeoutList:db CR,LF,"Task Prv Nxt Timeout",CR,LF,0;------------------------------------------------------------------------------;------------------------------------------------------------------------------message "DumpIOFocusList"DumpIOFocusList:phaphxphylda #msgIOFocusListjsr DisplayStringBspl iof_sema + 1lda IOFocusNdxdiofl2:beq diofl1tayldx #3jsr PRTNUMlda #' 'jsr DisplayCharlda JCB_iof_prev,yldx #3jsr PRTNUMlda #' 'jsr DisplayCharlda JCB_iof_next,yldx #3jsr PRTNUMjsr CRLFlda JCB_iof_next,ycmp IOFocusNdxbne diofl2diofl1:stz iof_sema + 1plyplxplartsmsgIOFocusList:db CR,LF,"Task Prv Nxt",CR,LF,0RunningTCBErr:; lda #$FF; sta LEDSlda #msgRunningTCBjsr DisplayStringBrtcberr1:jsr KeybdGetCharcmp #-1beq rtcberr1jmp startmsgRunningTCB:db CR,LF,"RunningTCB is bad.",CR,LF,0;------------------------------------------------------------------------------; Get the handle of the currently running job.;------------------------------------------------------------------------------;GetCurrentJob:ld r1,RunningTCBld r1,TCB_hJCB,r1 ; get the handlerts;------------------------------------------------------------------------------; Get a pointer to the JCB for the currently running task.;------------------------------------------------------------------------------;GetPtrCurrentJCB:jsr GetCurrentJoband r1,r1,#NR_JCB-1 ; and convert it to a pointer; mul r1,r1,#JCB_Sizeasl r1,r1,#JCB_LogSize ; 256 wordsadd r1,r1,#JCBsrts;------------------------------------------------------------------------------; Get the location of the screen and screen attribute memory. The location; depends on whether or not the task has the output focus.;------------------------------------------------------------------------------GetScreenLocation:jsr GetPtrCurrentJCBlda JCB_pVidMem,r1rtsGetColorCodeLocation:jsr GetPtrCurrentJCBlda JCB_pVidMemAttr,r1rtsGetNormAttr:jsr GetPtrCurrentJCBlda JCB_NormAttr,r1rtsGetCurrAttr:jsr GetPtrCurrentJCBlda JCB_CurrAttr,r1rts;------------------------------------------------------------------------------;------------------------------------------------------------------------------message "CopyVirtualScreenToScreen"CopyVirtualScreenToScreenphaphxphypush r4ldx IOFocusNdx ; compute virtual screen locationbeq cvss3; copy screen charslda #4095 ; number of words to copy-1ldx JCB_pVirtVid,xldy #TEXTSCRmvn; now copy the color codeslda #4095ldx IOFocusNdxldx JCB_pVirtVidAttr,xldy #TEXTSCR+$10000mvncvss3:; reset the cursor position in the text controllerldy IOFocusNdxldx JCB_CursorRow,ylda TEXTREG+TEXT_COLSmul r2,r2,r1add r2,r2,JCB_CursorCol,ystx TEXTREG+TEXT_CURPOSpop r4plyplxplartsmessage "CopyScreenToVirtualScreen"CopyScreenToVirtualScreenphaphxphypush r4lda #4095ldx #TEXTSCRldy IOFocusNdxbeq csvs3ldy JCB_pVirtVid,ymvnlda #4095ldx #TEXTSCR+$10000ldy IOFocusNdxldy JCB_pVirtVidAttr,ymvncsvs3:pop r4plyplxplarts;------------------------------------------------------------------------------; 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 characterphx ; loop counterphy ; memory addressinglda TEXTREG+TEXT_COLS ; calc number to clearldx TEXTREG+TEXT_ROWSmul r1,r1,r2 ; r1 = # chars to clearphajsr GetScreenLocationtay ; y = target addresslda #' ' ; space charjsr AsciiToScreentax ; x is value to storepla ; a is countphastos ; clear the memoryjsr GetCurrAttrtax ; x = value to usejsr GetColorCodeLocationtay ; y = target addresspla ; a = countstosplyplxplarts;------------------------------------------------------------------------------; Scroll text on the screen upwards;------------------------------------------------------------------------------;message "ScrollUp"ScrollUp:phaphxphypush r4push r5push r6lda TEXTREG+TEXT_COLS ; acc = # text columnsldx TEXTREG+TEXT_ROWSmul r2,r1,r2 ; calc number of chars to scrollsub r2,r2,r1 ; one less rowphajsr GetScreenLocationtayjsr GetColorCodeLocationld r6,r1plascrup1:add r5,r3,r1ld r4,(r5) ; move characterst r4,(y)add r5,r6,r1ld r4,(r5) ; and move color codest r4,(r6)inyinc r6dexbne scrup1lda TEXTREG+TEXT_ROWSdeajsr BlankLinepop r6pop r5pop r4plyplxplarts;------------------------------------------------------------------------------; Blank out a line on the display; line number to blank is in acc;------------------------------------------------------------------------------;BlankLine:phaphxphypush r4push r5ldx TEXTREG+TEXT_COLS ; x = # chars to blank out from video controllermul r3,r2,r1 ; y = screen index (row# * #cols)ld r5,r3 ; r5 = screen indexphajsr GetScreenLocationld r4,r1plaadd r3,r3,r4 ; y = screen addresslda #' 'jsr AsciiToScreenblnkln1:sta (y)inydexbne blnkln1; reset the color codes on the display line to the normal attributejsr GetColorCodeLocationtay ; y = destinationadd r3,r3,r5 ; add in indexjsr GetNormAttr ; get the value to settaxlda TEXTREG+TEXT_COLS ; number of columns to blank outdea ; acc is one lessstospop r5pop r4plyplxplarts;------------------------------------------------------------------------------; Convert ASCII character to screen display character.;------------------------------------------------------------------------------;align 8AsciiToScreen:and #$FFor #$100bit #%00100000 ; if bit 5 isn't setbeq .00001bit #%01000000 ; or bit 6 isn't setbeq .00001and #%110011111.00001:rts;------------------------------------------------------------------------------; Convert screen character to ascii character;------------------------------------------------------------------------------;ScreenToAscii:and #$FFcmp #26+1bcs stasc1add #$60stasc1:rts;------------------------------------------------------------------------------; HomeCursor; Set the cursor location to the top left of the screen.;------------------------------------------------------------------------------HomeCursor:phaphxphyspl jcb_sema + 1jsr GetPtrCurrentJCBtaxstz JCB_CursorRow,xstz JCB_CursorCol,xstz jcb_sema + 1cpx IOFocusNdxbne hc1stz TEXTREG+TEXT_CURPOShc1:plyplxplarts;------------------------------------------------------------------------------; Update the cursor position in the text controller based on the; CursorRow,CursorCol.;------------------------------------------------------------------------------;UpdateCursorPos:phajsr GetPtrCurrentJCBcmp IOFocusNdx ; update cursor position in text controllerbne .ucp1 ; only for the task with the output focusld r0,JCB_CursorOn,r4 ; only update if cursor is showingbeq .ucp2jsr CursorOnphxpush r4ld r4,r1lda JCB_CursorRow,r4and #$3F ; limit of 63 rowsldx TEXTREG+TEXT_COLSmul r2,r2,r1lda JCB_CursorCol,r4and #$7F ; limit of 127 colsadd r2,r2,r1stx TEXTREG+TEXT_CURPOSpop r4plx.ucp1:plarts.ucp2:jsr CursorOffplartsCursorOff:phalda #5bms TEXTREG+TEXT_CURCTLlda #6bmc TEXTREG+TEXT_CURCTLplartsCursorOn:phalda #5bmc TEXTREG+TEXT_CURCTLlda #6bms TEXTREG+TEXT_CURCTLplarts;------------------------------------------------------------------------------; Calculate screen memory location from CursorRow,CursorCol.; Also refreshes the cursor location.; Returns:; r1 = screen location;------------------------------------------------------------------------------;CalcScreenLoc:phxpush r4jsr GetPtrCurrentJCBld r4,r1lda JCB_CursorRow,r4and #$3F ; limit to 63 rowsldx TEXTREG+TEXT_COLSmul r2,r2,r1lda JCB_CursorCol,r4and #$7F ; limit to 127 colsadd r2,r2,r1cmp r4,IOFocusNdx ; update cursor position in text controllerbne csl1 ; only for the task with the output focusstx TEXTREG+TEXT_CURPOScsl1:jsr GetScreenLocationadd r1,r1,r2pop r4plxrts;------------------------------------------------------------------------------; 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.;; Parameters:; r1 = char to display;------------------------------------------------------------------------------;message "DisplayChar"DisplayChar:push r4phajsr GetPtrCurrentJCBld r4,r1lda JCB_esc,r4 ; are we building an escape sequence ?bne .processEscplaand #$FF ; mask off any higher order bits (called from eight bit mode).cmp #ESCbne .0001sta JCB_esc,r4 ; begin the esc sequencepop r4rts.0001cmp #BELLbne .noBelljsr Beeppop r4rts.noBellcmp #'\r' ; carriage return ?bne .dccrstz JCB_CursorCol,r4 ; just set cursor column to zero on a CRjsr UpdateCursorPos.dcx14:pop r4rts.dccr:cmp #$91 ; cursor right ?bne .dcx6phalda JCB_CursorCol,r4inacmp JCB_VideoCols,r4bhs .dcx7sta JCB_CursorCol,r4.dcx7:jsr UpdateCursorPosplapop r4rts.dcx6:cmp #$90 ; cursor up ?bne .dcx8phalda JCB_CursorRow,r4beq .dcx7deasta JCB_CursorRow,r4bra .dcx7.dcx8:cmp #$93 ; cursor left ?bne .dcx9phalda JCB_CursorCol,r4beq .dcx7deasta JCB_CursorCol,r4bra .dcx7.dcx9:cmp #$92 ; cursor down ?bne .dcx10phalda JCB_CursorRow,r4inacmp JCB_VideoRows,r4bhs .dcx7sta JCB_CursorRow,r4bra .dcx7.dcx10:cmp #$94 ; cursor home ?bne .dcx11phalda JCB_CursorCol,r4beq .dcx12stz JCB_CursorCol,r4bra .dcx7.dcx12:stz JCB_CursorRow,r4bra .dcx7.dcx11:phaphxphycmp #$99 ; delete ?bne .dcx13.doDel:jsr CalcScreenLoctay ; y = screen locationlda JCB_CursorCol,r4 ; acc = cursor columnbra .dcx5.dcx13cmp #CTRLH ; backspace ?bne .dcx3lda JCB_CursorCol,r4beq .dcx4deasta JCB_CursorCol,r4jsr CalcScreenLoc ; acc = screen locationtay ; y = screen locationlda JCB_CursorCol,r4.dcx5:ldx $4,ystx (y)inyinacmp JCB_VideoCols,r4blo .dcx5lda #' 'jsr AsciiToScreendeysta (y)bra .dcx4.dcx3:cmp #'\n' ; linefeed ?beq .dclftax ; save acc in xjsr CalcScreenLoc ; acc = screen locationtay ; y = screen locationtxa ; restore r1jsr AsciiToScreen ; convert ascii char to screen charsta (y)jsr GetScreenLocationsub r3,r3,r1 ; make y an index into the screenjsr GetColorCodeLocationadd r3,r3,r1jsr GetCurrAttrsta (y)jsr IncCursorPosbra .dcx4.dclf:jsr IncCursorRow.dcx4:plyplxplapop r4rts; ESC processing.processEsc:cmp #(ESC<<24)+('('<<16)+(ESC<<8)+'G'beq .procAttrbit #$FF000000 ; is it some other five byte escape sequence ?bne .unrecogEsccmp #(ESC<<16)+('('<<8)+ESCbeq .testGbit #$FF0000 ; is it some other four byte escape sequence ?bne .unrecogEsc ; - unrecognized escape sequencecmp #(ESC<<8)+'`'beq .cursOnOffcmp #(ESC<<8)+'('beq .testEscbit #$FF00 ; is it some other three byte sequence ?bne .unrecogEsc ; - unrecognized escape sequencecmp #ESC ; check for single char escapesbeq .esc1pla ; some other garbage in the esc buffer ?stz JCB_esc,r4pop r4rts.cursOnOff:plastz JCB_CursorOn,r4and #$FFcmp #'0'beq .escRstinc JCB_CursorOn,r4.escRst:stz JCB_esc,r4 ; reset escape sequence capturepop r4rts.procAttr:plaand #$FFcmp #'0'bne .0005lda JCB_NormAttr,r4sta JCB_CurrAttr,r4bra .escRst.0005:cmp #'4'bne .escRstphxlda JCB_NormAttr,r4 ; get the normal attributetaxlsr r1,r1,#5 ; swap foreground and background colorsand #$1Fasl r2,r2,#5or r1,r1,r2plxsta JCB_CurrAttr,r4 ; store in current attributebra .escRst.esc1:plaand #$FFcmp #'W' ; esc 'W' - delete char under cursorbne .0006stz JCB_esc,r4phaphxphybra .doDel.0006:cmp #'T' ; esc 'T' - clear to end of linebne .0009phxphyldx JCB_CursorCol,r4jsr CalcScreenLoc ; acc = screen locationtaylda #' 'jsr AsciiToScreen.0008:sta (y)inyinxcpx JCB_VideoCols,r4blo .0008plyplxbra .escRst.0009:cmp #'`'bne .0010bra .stuffChar.0010:cmp #'('bne .escRstbra .stuffChar.unrecogEsc:plabra .escRst.testG:plaand #$FFcmp #'G'bne .escRst; stuff a character into the escape sequence.stuffChar:phalda JCB_esc,r4asl r1,r1,#8or r1,r1,0,spsta JCB_esc,r4plapop r4rts.testEsc:plaand #$FFcmp #ESCbne .escRstbra .stuffChar;------------------------------------------------------------------------------; Increment the cursor position, scroll the screen if needed.;------------------------------------------------------------------------------;message "IncCursorPos"IncCursorPos:phaphxpush r4jsr GetPtrCurrentJCBld r4,r1lda JCB_CursorCol,r4inasta JCB_CursorCol,r4ldx JCB_VideoCols,r4cmp r1,r2blo icc1stz JCB_CursorCol,r4 ; column = 0bra icr1IncCursorRow:phaphxpush r4jsr GetPtrCurrentJCBld r4,r1icr1:lda JCB_CursorRow,r4inasta JCB_CursorRow,r4ldx JCB_VideoRows,r4cmp r1,r2blo icc1dex ; backup the cursor row, we are scrolling upstx JCB_CursorRow,r4jsr ScrollUpicc1:jsr UpdateCursorPosicc2:pop r4plxplarts;------------------------------------------------------------------------------; Display a string on the screen.; The characters are packed 4 per word;------------------------------------------------------------------------------;message "DisplayStringB"DisplayStringB:phaphxtax ; r2 = pointer to stringdspj1B:lb r1,0,x ; move string char into accinx ; increment pointercmp #0 ; is it end of string ?beq dsretBjsr DisplayChar ; display characterbra dspj1BdsretB:plxplartsDisplayStringQ:phaphxtax ; r2 = pointer to stringlda #TEXTSCRsta QIndexdspj1Q:lb r1,0,x ; move string char into accinx ; increment pointercmp #0 ; is it end of string ?beq dsretQjsr DisplayCharQ ; display characterbra dspj1QdsretQ:plxplartsDisplayCharQ:phaphxjsr AsciiToScreenldx #0sta (QIndex,x)lda QIndexinasta QIndex; inc QIndexplxplarts;------------------------------------------------------------------------------; Display a string on the screen.; The characters are packed 1 per word;------------------------------------------------------------------------------;message "DisplayStringW"DisplayStringW:phaphxtax ; r2 = pointer to stringdspj1W:lda (x) ; move string char into accinx ; increment pointercmp #0 ; is it end of string ?beq dsretWjsr DisplayChar ; display characterbra dspj1W ; go back for next characterdsretW:plxplartsDisplayStringCRLFB:jsr DisplayStringBCRLF:phalda #'\r'jsr DisplayCharlda #'\n'jsr DisplayCharplarts;------------------------------------------------------------------------------;------------------------------------------------------------------------------message "TickRout"TickRout:; support EhBASIC's IRQ functionality; code derived from minimon.asmlda #3 ; Timer is IRQ #3sta IrqSource ; stuff a byte indicating the IRQ source for PEEK()lb r1,IrqBase ; get the IRQ flag bytelsr r4,r1or r1,r1,r4and #$E0sb r1,IrqBaseinc TEXTSCR+55 ; update IRQ live indicator on screen; flash the cursorjsr GetPtrCurrentJCBtaxcpx IOFocusNdx ; only bother to flash the cursor for the task with the IO focus.bne tr1alda JCB_CursorFlash,x ; test if we want a flashing cursorbeq tr1ajsr CalcScreenLoc ; compute cursor location in memorytaylda $10000,y ; get color code $10000 higher in memoryld r4,IRQFlag ; get counterlsr r4,r4and r4,r4,#$0F ; limit to low order nybbleand #$F0 ; prepare to or in new value, mask off foreground coloror r1,r1,r4 ; set new foreground color for cursorsta $10000,y ; store the color code back to memorytr1artsmessage "null.asm"include "null.asm"message "keyboard.asm"include "keyboard.asm"message "iofocus.asm"include "iofocus.asm"message "serial.asm"include "serial.asm"message "797";------------------------------------------------------------------------------; Display the half-word in r1;------------------------------------------------------------------------------;DisplayWord:phalsr r1,r1,#16jsr DisplayHalfpla;------------------------------------------------------------------------------; Display the half-word in r1;------------------------------------------------------------------------------;DisplayHalf:phalsr r1,r1,#8jsr DisplayBytepla;------------------------------------------------------------------------------; Display the byte in r1;------------------------------------------------------------------------------;DisplayByte:phalsr r1,r1,#4jsr DisplayNybblepla;------------------------------------------------------------------------------; Display nybble in r1;------------------------------------------------------------------------------;DisplayNybble:phaand #$0Fadd #'0'cmp #'9'+1bcc dispnyb1add #7dispnyb1:jsr DisplayCharplartsmessage "810";------------------------------------------------------------------------------; Display memory pointed to by r2.; destroys r1,r3;------------------------------------------------------------------------------;DisplayMemW:phalda #'>'jsr DisplayChartxajsr DisplayWordlda #' 'jsr DisplayCharlda (x)jsr DisplayWordinxlda #' 'jsr DisplayCharlda (x)jsr DisplayWordinxlda #' 'jsr DisplayCharlda (x)jsr DisplayWordinxlda #' 'jsr DisplayCharlda (x)jsr DisplayWordinxjsr CRLFplarts;------------------------------------------------------------------------------; Display memory pointed to by r2.; destroys r1,r3;------------------------------------------------------------------------------;DisplayMemBytes:phaphylda #'>'jsr DisplayCharlda #'B'jsr DisplayCharlda #' 'jsr DisplayChartxajsr DisplayWordldy #0.001:lda #' 'jsr DisplayCharlb r1,0,xjsr DisplayByteinxinycpy #8blo .001lda #':'jsr DisplayCharldy #0sub r2,r2,#8.002lb r1,0,xcmp #26 ; convert control characters to '.'bhs .003lda #'.'.003:jsr DisplayCharinxinycpy #8blo .002jsr CRLFplyplartsmessage "Monitor";==============================================================================; System Monitor Program; The system monitor is task#0;==============================================================================;Monitor:ldx #BIOS_STACKS+0x03FF ; setup stack pointertxslda #0 ; turn off keyboard echojsr SetKeyboardEchojsr RequestIOFocus.PromptLn:jsr CRLFlda #'$'jsr DisplayChar; Get characters until a CR is keyed;.Prompt3:jsr RequestIOFocus; lw r1,#2 ; get keyboard character; syscall #417; jsr KeybdCheckForKeyDirect; cmp #0jsr KeybdGetCharcmp #-1beq .Prompt3; jsr KeybdGetCharDirectcmp #CRbeq .Prompt1jsr DisplayCharbra .Prompt3; Process the screen line that the CR was keyed on;.Prompt1:lda #80sta LEDSldx RunningTCBldx TCB_hJCB,xcpx #NR_JCBbhs .Prompt3mul r2,r2,#JCB_Sizeadd r2,r2,#JCBslda #81sta LEDSstz JCB_CursorCol,x ; go back to the start of the linejsr CalcScreenLoc ; r1 = screen memory locationtaylda #82sta LEDSjsr MonGetchcmp #'$'bne .Prompt2 ; skip over '$' prompt characterlda #83sta LEDSjsr MonGetch; Dispatch based on command character;.Prompt2:cmp #'>'beq EditMemcmp #'M'bne .testDIRjsr MonGetchcmp #'B'beq DumpMemBytesdeybra DumpMem.testDIR:cmp #'D'bne .Prompt8cmp #'I'beq DoDirbra Monitor.Prompt8:cmp #'F'bne .Prompt7jsr MonGetchcmp #'L'bne .Prompt8ajsr DumpIOFocusListjmp Monitor.Prompt8a:cmp #'I'beq DoFigcmp #'M'beq DoFmtdeybra FillMem.Prompt7:cmp #'B' ; $B - start tiny basicbne .Prompt4mStartTask #PRI_LOW,#0,#CSTART,#0,#4bra Monitor.Prompt4:cmp #'b'bne .Prompt5lda BASIC_SESSIONcmp #0bne .bsess1inc BASIC_SESSION; lda #3 ; priority level 3; ldy #$F000 ; start address $F000; ldx #$00000000 ; flags:; jmp (y); jsr ($FFFFC004>>2) ; StartTask; mStartTask #PRI_LOW,#0,#$F000,#0,#0lda #PRI_LOWldx #0ldy #$F000ld r4,#0ld r5,#3int #4db 1bra Monitor.bsess1:inc BASIC_SESSIONldx #$3000ldy #$4303000asl r1,r1,#14 ; * 16kWadd r3,r3,r1phylda #4095 ; 4096 words to copymvn ; copy BASIC ROMplyasl r3,r3,#2 ; convert to code addressadd r3,r3,#$3000 ; xxxx_F000lda #3ldx #$00000000 ; zero flags at startupjsr ($FFFFC004>>2) ; StartTaskbra Monitoremmcpu W65C02jml $0C000cpu rtf65002.Prompt5:cmp #'J' ; $J - execute codebeq ExecuteCodecmp #'L' ; $L - load dectorbeq LoadBlockcmp #'W'beq WriteBlock.Prompt9:cmp #'?' ; $? - display helpbne .Prompt10lda #HelpMsgjsr DisplayStringBjmp Monitor.Prompt10:cmp #'C' ; $C - clear screenbeq TestCLScmp #'r'bne .Prompt12lda #4 ; priority level 4ldx #0 ; zero all flags at startupldy #RandomLines ; task addressjsr (y); jsr StartTask; jsr ($FFFFC004>>2) ; StartTaskjmp Monitor; jmp RandomLinesCall.Prompt12:.Prompt13:cmp #'P'bne .Prompt14mStartTask #PRI_NORMAL,#0,#Piano,#0,#2jmp Monitor.Prompt14:cmp #'T'bne .Prompt15jsr MonGetchcmp #'O'bne .Prompt14ajsr DumpTimeoutListjmp Monitor.Prompt14a:cmp #'I'bne .Prompt14bjsr DisplayDatetimejmp Monitor.Prompt14b:cmp #'E'bne .Prompt14cjsr ReadTempjmp Monitor.Prompt14c:deyjsr DumpTaskListjmp Monitor.Prompt15:cmp #'S'bne .Prompt16jsr MonGetchcmp #'P'bne .Prompt18jsr ignBlanksjsr GetHexNumbersta SPSavejmp Monitor.Prompt18:cmp #'U'bne .Prompt18a; jsl $F500mStartTask #PRI_HIGH,#0,#$F500,#0,#6; lda #PRI_HIGH; ldx #0; ldy #$F500; ld r4,#0; ld r5,#6; int #4; db 1jmp Monitor.Prompt18a:deyjsr SDInitcmp #0bne Monitorjsr SDReadPartcmp #0bne Monitorjsr SDReadBootcmp #0bne Monitorjsr loadBootFilejmp Monitor.Prompt16:cmp #'e'bne .Prompt17; lda #1; ldx #0; ldy #eth_main; jsr StartTaskmStartTask #PRI_HIGH,#0,#eth_main,#0,#0; jsr eth_mainjmp Monitor.Prompt17:cmp #'R'bne .Prompt19jsr MonGetchcmp #'S'beq LoadBlockdeybra SetRegValuejmp Monitor.Prompt19:cmp #'K'bne .Prompt20.Prompt19a:jsr MonGetchcmp #' 'bne .Prompt19ajsr ignBlanksjsr GetDecNumberjsr KillTaskjmp Monitor.Prompt20:cmp #'8'bne .Prompt21jsr Test816jmp Monitor.Prompt21:cmp #'m'bne Monitor; lda #3; ldx #0; ldy #test_mbx_prg; jsr StartTasklda #PRI_LOWldx #0ldy #test_mbx_prgld r4,#0ld r5,#1 ; Job 1!int #4db 1bra Monitormessage "Prompt16"RandomLinesCall:; jsr RandomLinesjmp MonitorMonGetch:lda (y)inyjsr ScreenToAsciirtsDoDir:jsr do_dirjmp MonitorDoFmt:jsr do_fmtjmp MonitorDoFig:lda #3 ; priority level 3ldy #$A000 ; start address $A000ldx #$20000000 ; flags: emmulation mode setjsr StartTaskbra MonitorTestCLS:jsr MonGetchcmp #'L'bne Monitorjsr MonGetchcmp #'S'bne Monitorjsr ClearScreenjsr HomeCursor; jsr CalcScreenLocjmp Monitormessage "HelpMsg"HelpMsg:db "? = Display help",CR,LFdb "CLS = clear screen",CR,LFdb "S = Boot from SD Card",CR,LFdb "SU = supermon816",CR,LFdb "L = Load Block",CR,LFdb "W = Write Block",CR,LFdb "DIR = Disk directory",CR,LFdb "M = Dump memory words, MB = Dump memory bytes",CR,LFdb "> = Edit memory words",CR,LFdb "F = Fill memory",CR,LFdb "FL = Dump I/O Focus List",CR,LF; db "FIG = start FIG Forth",CR,LFdb "KILL n = kill task #n",CR,LFdb "B = start tiny basic",CR,LFdb "b = start EhBasic 6502",CR,LFdb "J = Jump to code",CR,LFdb "R = Dump registers, Rn = Set register value",CR,LFdb "r = random lines - test bitmap",CR,LFdb "e = ethernet test",CR,LFdb "T = Dump task list",CR,LFdb "TO = Dump timeout list",CR,LFdb "TI = display date/time",CR,LFdb "TEMP = display temperature",CR,LFdb "P = Piano",CR,LFdb "8 = 816 test",CR,LF,0;------------------------------------------------------------------------------; Ignore blanks in the input; r3 = text pointer; r1 destroyed;------------------------------------------------------------------------------;ignBlanks:ignBlanks1:jsr MonGetchcmp #' 'beq ignBlanks1deyrts;------------------------------------------------------------------------------; Edit memory byte(s).;------------------------------------------------------------------------------;EditMem:jsr ignBlanksjsr GetHexNumberld r5,r1ld r4,#3edtmem1:jsr ignBlanksjsr GetHexNumbersta (r5)add r5,r5,#1dec r4bne edtmem1jmp Monitor;------------------------------------------------------------------------------; Execute code at the specified address.;------------------------------------------------------------------------------;message "ExecuteCode"ExecuteCode:jsr ignBlanksjsr GetHexNumberst r1,JMPTMPlda #xcret ; push return address so we can do an indirect jumpphald r1,R1Saveld r2,R2Saveld r3,R3Saveld r4,R4Saveld r5,R5Saveld r6,R6Saveld r7,R7Saveld r8,R8Saveld r9,R9Saveld r10,R10Saveld r11,R11Saveld r12,R12Saveld r13,R13Saveld r14,R14Saveld r15,R15Savejmp (JMPTMP)xcret:phpst r1,R1Savest r2,R2Savest r3,R3Savest r4,R4Savest r5,R5Savest r6,R6Savest r7,R7Savest r8,R8Savest r9,R9Savest r10,R10Savest r11,R11Savest r12,R12Savest r13,R13Savest r14,R14Savest r15,R15Savetsr sp,r1st r1,SPSavetsr sp8,r1st r1,SP8Saveplasta SRSavejmp MonitorLoadBlock:jsr ignBlanksjsr GetDecNumberphajsr ignBlanksjsr GetHexNumbertaxphx; ld r2,#0x3800lda #16 ; SD Card device #ldx #1 ; Initjsr DeviceOp; jsr SDInitplxplalda #16 ; SD Card device #ldx #11 ; opcode: Read blockspop r5 ; r5 = pointer to data storage areaply ; y = block number to readld r4,#1 ; 1 block to readjsr DeviceOp; jsr SDReadSectorjmp MonitorWriteBlock:jsr ignBlanksjsr GetDecNumberphajsr ignBlanksjsr GetHexNumbertaxphxjsr SDInitplxplajsr SDWriteSectorjmp Monitor;------------------------------------------------------------------------------; Command 'R'; Dump the register set.;------------------------------------------------------------------------------message "DumpReg"DumpReg:ldy #0DumpReg1:jsr CRLFlda #'$'jsr DisplayCharlda #'R'jsr DisplayCharldx #1tyainajsr PRTNUMlda #' 'jsr DisplayCharlda R1Save,yjsr DisplayWordinycpy #15bne DumpReg1jsr CRLFlda #':'jsr DisplayCharlda #'S'jsr DisplayCharlda #'P'jsr DisplayCharlda #' 'jsr DisplayCharlda TCB_SPSavejsr DisplayWordjsr CRLFjmp Monitor;------------------------------------------------------------------------------; Command 'Rn';------------------------------------------------------------------------------SetRegValue:jsr GetDecNumbercmp #0beq DumpRegcmp #15bpl Monitorphajsr ignBlanksjsr GetHexNumberplysta R1Save,yjmp Monitor;------------------------------------------------------------------------------;------------------------------------------------------------------------------GetTwoParams:jsr ignBlanksjsr GetHexNumber ; get start address of dumptaxjsr ignBlanksjsr GetHexNumber ; get end address of dumprts;------------------------------------------------------------------------------; Get a range, the end must be greater or equal to the start.;------------------------------------------------------------------------------GetRange:jsr GetTwoParamscmp r2,r1bhi DisplayErrrts;------------------------------------------------------------------------------; Command 'M'; Do a memory dump of the requested location.;------------------------------------------------------------------------------;DumpMem:jsr GetRangejsr CRLFDumpmemW:jsr CheckKeysjsr DisplayMemWcmp r2,r1bls DumpmemWjmp MonitorDumpMemBytes:jsr GetRangejsr CRLF.001:jsr CheckKeysjsr DisplayMemBytescmp r2,r1bls .001jmp Monitor;------------------------------------------------------------------------------; CheckKeys:; Checks for a CTRLC or a scroll lock during long running dumps.;------------------------------------------------------------------------------CheckKeys:jsr CTRLCCheckjmp CheckScrollLock;------------------------------------------------------------------------------; CTRLCCheck; Checks to see if CTRL-C is pressed. If so then the current routine is; aborted and control is returned to the monitor.;------------------------------------------------------------------------------CTRLCCheck:phajsr KeybdGetCharcmp #CTRLCbeq .0001plarts.0001:plaplajmp Monitor;------------------------------------------------------------------------------; CheckScrollLock:; Check for a scroll lock by the user. If scroll lock is active then tasks; are rescheduled while the scroll lock state is tested in a loop.;------------------------------------------------------------------------------CheckScrollLock:pha.0002:jsr GetPtrCurrentJCBlda JCB_KeybdLocks,r1bit #$4000 ; is scroll lock active ?beq .0001int #2 ; reschedule tasksbra .0002.0001:plarts;------------------------------------------------------------------------------; Command 'F' or "FB"; Fill memory with specified value.;------------------------------------------------------------------------------FillMem:jsr GetRangetxy ; y = start addresssub r1,r1,r2 ; acc = countphajsr ignBlanksjsr GetHexNumber ; get the fill bytetaxplastosjmp MonitorFillMemBytes:jsr GetRangetxysub r2,r1,r2 ; x = countinxjsr ignBlanksjsr GetHexNumber.0001:sb r1,0,yinydexbne .0001jmp Monitor;------------------------------------------------------------------------------; Get a hexidecimal number. Maximum of eight digits.; R3 = text pointer (updated); R1 = hex number;------------------------------------------------------------------------------;GetHexNumber:phxpush r4ldx #0ld r4,#8gthxn2:jsr MonGetchjsr AsciiToHexNybblecmp #-1beq gthxn1asl r2,r2,#4and #$0for r2,r2,r1dec r4bne gthxn2gthxn1:txapop r4plxrtsGetDecNumber:phxpush r4push r5ldx #0ld r4,#10ld r5,#10gtdcn2:jsr MonGetchjsr AsciiToDecNybblecmp #-1beq gtdcn1mul r2,r2,r5add r2,r2,r1dec r4bne gtdcn2gtdcn1:txapop r5pop r4plxrts;------------------------------------------------------------------------------; Convert ASCII character in the range '0' to '9', 'a' to 'f' or 'A' to 'F'; to a hex nybble.;------------------------------------------------------------------------------;AsciiToHexNybble:cmp #'0'bcc gthx3cmp #'9'+1bcs gthx5sub #'0'rtsgthx5:cmp #'A'bcc gthx3cmp #'F'+1bcs gthx6sub #'A'add #10rtsgthx6:cmp #'a'bcc gthx3cmp #'z'+1bcs gthx3sub #'a'add #10rtsgthx3:lda #-1 ; not a hex numberrtsAsciiToDecNybble:cmp #'0'bcc gtdc3cmp #'9'+1bcs gtdc3sub #'0'rtsgtdc3:lda #-1rtsDisplayErr:lda #msgErrjsr DisplayStringBjmp MonitormsgErr:db "**Err",CR,LF,0;==============================================================================;==============================================================================;------------------------------------------------------------------------------;------------------------------------------------------------------------------ClearBmpScreen:phaphxphylda #(680*384) ; a = # bytes to clearldx #0x29292929 ; acc = color for four pixelsldy #BITMAPSCR;<<2 ; y = screen addresscbmp1:; tsr LFSR,r2; sb r2,0,y; iny; dea; bne cbmp1stosplyplxplarts;==============================================================================;==============================================================================;--------------------------------------------------------------------------; Setup the AC97/LM4550 audio controller. Check keyboard for a CTRL-C; interrupt which may be necessary if the audio controller isn't; responding.;--------------------------------------------------------------------------;SetupAC97:phaphxphypush r4ld r4,Millisecondssac974:stz AC97+0x26 ; trigger a read of register 26 (status reg)sac971: ; wait for status to register 0xF (all ready)ld r3,Millisecondssub r3,r3,r4cmp r3,#1000bhi sac97Abortjsr KeybdGetChar ; see if we needed to CTRL-Ccmp #CTRLCbeq sac973lda AC97+0x68 ; wait for dirty bit to clearbne sac971lda AC97+0x26 ; check status at reg h26, wait forand #0x0F ; analogue to be readycmp #$0Fbne sac974sac973:stz AC97+2 ; master volume, 0db attenuation, mute offstz AC97+4 ; headphone volume, 0db attenuation, mute offstz AC97+0x18 ; PCM gain (mixer) mute off, no attenuationstz AC97+0x0A ; mute PC beeplda #0x8000 ; bypass 3D soundsta AC97+0x20ld r4,Millisecondssac972:ld r3,Millisecondssub r3,r3,r4cmp r3,#1000bhi sac97Abortjsr KeybdGetCharcmp #CTRLCbeq sac975lda AC97+0x68 ; wait for dirty bits to clearbne sac972 ; wait a while for the settings to take effectsac975:pop r4plyplxplartssac97Abort:lda #msgAC97badjsr DisplayStringCRLFBpop r4plyplxplartsmsgAC97bad:db "The AC97 controller is not responding.",CR,LF,0;--------------------------------------------------------------------------; Sound a 800 Hz beep;--------------------------------------------------------------------------;Beep:lda #2 ; check for a PSGbmt CONFIGRECbeq .retlda #15 ; master volume to maxsta PSG+64lda #13422 ; 800Hzsta PSGFREQ0; decay (16.384 ms)2; attack (8.192 ms)1; release (1.024 s)A; sustain level Clda #0xCA12sta PSGADSR0lda #0x1104 ; gate, output enable, triangle waveformsta PSGCTRL0; lda #1000 ; delay about 1smSleep #1000lda #0x0104 ; gate off, output enable, triangle waveformsta PSGCTRL0; lda #1000 ; delay about 1smSleep #1000lda #83sta LEDSlda #0x0000 ; gate off, output enable off, no waveformsta PSGCTRL0.retrtsinclude "Piano.asm"include "SDCard.asm"; Load the root directory from disk; r2 = where to place root directory in memory;loadBootFile:lb r1,BYTE_SECTOR_BUF+BSI_SecPerFAT+1 ; sectors per FATasl r1,r1,#8orb r1,r1,BYTE_SECTOR_BUF+BSI_SecPerFATbne loadBootFile7lb r1,BYTE_SECTOR_BUF+$27 ; sectors per FAT, FAT32asl r1,r1,#8orb r1,r1,BYTE_SECTOR_BUF+$26asl r1,r1,#8orb r1,r1,BYTE_SECTOR_BUF+$25asl r1,r1,#8orb r1,r1,BYTE_SECTOR_BUF+$24loadBootFile7:lb r4,BYTE_SECTOR_BUF+$10 ; number of FATsmul r3,r1,r4 ; offsetlb r1,BYTE_SECTOR_BUF+$F ; r1 = # reserved sectors before FATasl r1,r1,#8orb r1,r1,BYTE_SECTOR_BUF+$Eadd r3,r3,r1 ; r3 = root directory sector numberld r6,startSectoradd r5,r3,r6 ; r5 = root directory sector numberlb r1,BYTE_SECTOR_BUF+$D ; sectors per clusteradd r3,r1,r5 ; r3 = first cluster after first cluster of directorybra loadBootFile6loadBootFile6:; For now we cheat and just go directly to sector 512.bra loadBootFileTmploadBootFileTmp:; We load the number of sectors per cluster, then load a single cluster of the file.; This is 16kibld r5,r3 ; r5 = start sector of data areald r2,#PROG_LOAD_AREA ; where to place file in memorylb r3,BYTE_SECTOR_BUF+$D ; sectors per clusterloadBootFile1:ld r1,r5 ; r1=sector to readjsr SDReadSectorinc r5 ; r5 = next sectoradd r2,r2,#512dec r3bne loadBootFile1lda PROG_LOAD_AREA>>2 ; make sure it's bootablecmp #$544F4F42bne loadBootFile2lda #msgJumpingToBootjsr DisplayStringBlda (PROG_LOAD_AREA>>2)+$1jsr (r1)jmp MonitorloadBootFile2:lda #msgNotBootablejsr DisplayStringBldx #PROG_LOAD_AREA>>2jsr DisplayMemWjsr DisplayMemWjsr DisplayMemWjsr DisplayMemWjmp MonitormsgJumpingToBoot:db "Jumping to boot",0msgNotBootable:db "SD card not bootable.",0spi_init_ok_msg:db "SD card initialized okay.",0spi_init_error_msg:db ": error occurred initializing the SD card.",0spi_boot_error_msg:db "SD card boot error",CR,LF,0spi_read_error_msg:db "SD card read error",CR,LF,0spi_write_error_msg:db "SD card write error",0do_fmt:jsr SDInitcmp #0bne fmt_abrt; clear out the directory bufferlda #65535ldx #0ldy #DIRBUFstosjsr store_dirfmt_abrt:rtsdo_dir:jsr CRLFjsr SDInitcmp #0bne dirabrtjsr load_dirld r4,#0 ; r4 = entry counterddir3:asl r3,r4,#6 ; y = start of entry, 64 bytes per entryldx #32 ; 32 chars in filenameddir4:lb r1,DIRBUF<<2,ybeq ddir2 ; move to next dir entry if null is foundcmp #$20 ; don't display control charsbmi ddir1jsr DisplayCharbra ddir5ddir1:lda #' 'jsr DisplayCharddir5:inydexbne ddir4lda #' 'jsr DisplayCharasl r3,r4,#4 ; y = start of entry, 16 words per entrylda DIRBUF+$D,yldx #5jsr PRTNUMjsr CRLFddir2:jsr KeybdGetCharcmp #CTRLCbeq ddir6inc r4cmp r4,#512 ; max 512 dir entriesbne ddir3ddir6:dirabrt:rtsload_dir:phaphxphylda #4000ldx #DIRBUF<<2ldy #64jsr SDReadMultipleplyplxplartsstore_dir:phaphxphylda #4000ldx #DIRBUF<<2ldy #64jsr SDWriteMultipleplyplxplarts; r1 = pointer to file name; r2 = pointer to buffer to save; r3 = length of buffer;do_save:phajsr SDInitcmp #0bne dsavErrplajsr load_dirld r4,#0dsav4:asl r5,r4,#6ld r7,#0ld r10,r1dsav2:lb r6,DIRBUF<<2,r5lb r8,0,r10cmp r6,r8bne dsav1inc r5inc r7inc r10cmp r7,#32bne dsav2; here the filename matcheddsav8:asl r7,r4,#7 ; compute file address 64k * entry #add r7,r7,#5000 ; start at sector 5,000ld r1,r7 ; r1 = sector numberlsr r3,r3,#9 ; r3/512iny ; +1jsr SDWriteMultipledsav3:rts; Here the filename didn't matchdsav1:inc r4cmp r4,#512bne dsav4; Here none of the filenames in the directory matched; Find an empty entry.ld r4,#0dsav6:asl r5,r4,#6lb r6,DIRBUF<<2,r5beq dsav5inc r4cmp r4,#512bne dsav6; Here there were no empty entrieslda #msgDiskFulljsr DisplayStringBrtsdsav5:ld r7,#32ld r10,r1dsav7:lb r6,0,r10 ; copy the filename into the directory entrysb r6,DIRBUF<<2,r5inc r5inc r10dec r7bne dsav7; copy the file size into the directory entryasl r5,r4,#4 ; 16 words per dir entrysty DIRBUF+$D,r5jsr store_dirbra dsav8dsavErr:plartsmsgDiskFulldb CR,LF,"The disk is full, unable to save file.",CR,LF,0do_load:phajsr SDInitcmp #0bne dsavErrplajsr load_dirld r4,#0dlod4:asl r5,r4,#6ld r7,#0ld r10,r1dlod2:lb r6,DIRBUF<<2,r5lb r8,0,r10cmp r6,r8bne dlod1inc r5inc r7inc r10cmp r7,#32bne dlod2; here the filename matcheddlod8:asl r5,r4,#4 ; 16 wordsld r3,DIRBUF+$d,r5 ; get file size into y registerasl r7,r4,#7 ; compute file address 64k * entry #add r7,r7,#5000 ; start at sector 5,000ld r1,r7 ; r1 = sector numberlsr r3,r3,#9 ; r3/512iny ; +1jsr SDReadMultipledlod3:rts; Here the filename didn't matchdlod1:inc r4cmp r4,#512bne dlod4; Here none of the filenames in the directory matched;lda #msgFileNotFoundjsr DisplayStringBrtsmsgFileNotFound:db CR,LF,"File not found.",CR,LF;include "ethernet.asm";--------------------------------------------------------------------------; Initialize sprite image caches with random data.;--------------------------------------------------------------------------message "RandomizeSprram"RandomizeSprram:ldx #SPRRAMld r4,#14336 ; number of chars to initializersr1:tsr LFSR,r1sta (x)inxdec r4bne rsr1rts;include "float.asm"include "RandomLines.asm";--------------------------------------------------------------------------; RTF65002 code to display the date and time from the date/time device.;--------------------------------------------------------------------------DisplayDatetimephaphxlda #' 'jsr DisplayCharstz DATETIME_SNAPSHOT ; take a snapshot of the running date/timelda DATETIME_DATEtaxlsr r1,r1,#16jsr DisplayHalf ; display the yearlda #'/'jsr DisplayChartxalsr r1,r1,#8and #$FFjsr DisplayByte ; display the monthlda #'/'jsr DisplayChartxaand #$FFjsr DisplayByte ; display the daylda #' 'jsr DisplayCharlda #' 'jsr DisplayCharlda DATETIME_TIMEtaxlsr r1,r1,#24jsr DisplayByte ; display hourslda #':'jsr DisplayChartxalsr r1,r1,#16jsr DisplayByte ; display minuteslda #':'jsr DisplayChartxalsr r1,r1,#8jsr DisplayByte ; display secondslda #'.'jsr DisplayChartxajsr DisplayByte ; display 100ths secondsjsr CRLFplxplartsinclude "ReadTemp.asm"include "memory.asm";------------------------------------------------------------------------------; Bus Error Routine; This routine display a message then restarts the BIOS.;------------------------------------------------------------------------------;message "bus_err_rout"bus_err_rout:cldldx #87stx LEDSpla ; get rid of the stacked flagsply ; get the error PCldx #$05FFFFF8 ; setup stack pointer top of memorytxsldx #88stx LEDSjsr CRLFstz RunningTCBlda #JCBssta IOFocusNdxlda #msgBusErrjsr DisplayStringBtyajsr DisplayWord ; display the originating PC addresslda #msgDataAddrjsr DisplayStringBtsr #9,r1jsr DisplayWordldx #89stx LEDSldx #128ber2:lda #' 'jsr DisplayChartsr hist,r1jsr DisplayWorddexbne ber2jsr CRLFber3:nopjmp ber3;cli ; enable interrupts so we can get a charber1:jsr KeybdGetCharDirect ; Don't use the keyboard buffercmp #-1beq ber1lda RunningTCBjsr KillTaskjmp SelectTaskToRunmsgBusErr:db "Bus error at: ",0msgDataAddr:db " data address: ",0;------------------------------------------------------------------------------; 1000 Hz interrupt; This IRQ must be fast.; Increments the millisecond counter;------------------------------------------------------------------------------message "p1000Hz"p1000Hz:phalda #2 ; reset edge sense circuitsta PIC_RSTEinc Milliseconds ; increment milliseconds countplarti;------------------------------------------------------------------------------; Sleep interrupt; This interrupt just selects another task to run. The current task is; stuck in an infinite loop.;------------------------------------------------------------------------------message "slp_rout"slp_rout:cld ; clear extended precision modepushalda RunningTCBcmp #MAX_TASKNObhi slp1jsr RemoveTaskFromReadyListtaxtsa ; save off the stack pointersta TCB_SPSave,xtsr sp8,r1 ; and the eight bit mode stack pointersta TCB_SP8Save,xtsr abs8,r1sta TCB_ABS8Save,xlda #TS_SLEEP ; set the task status to SLEEPsta TCB_Status,xslp1:jmp SelectTaskToRun;------------------------------------------------------------------------------; Check for and emulate unsupoorted instructions.;------------------------------------------------------------------------------InvalidOpIRQ:phaphxphytsxlda 4,x ; get the address of the invalid op off the stacklb r3,0,r1 ; get the opcode bytecpy #$44 ; is it MVP ?beq EmuMVPcpy #$54 ; is it MVN ?beq EmuMVN; We don't know what the op is. Treat it like a NOP; Increment the address and return.phalda #msgUnimpjsr DisplayStringBplajsr DisplayWordjsr CRLFinasta 4,x ; save incremented return address back to stackjsr DumpHistoryTableplyplxplartiDumpHistoryTable:phaphxldx #64ioi1:tsr hist,r1jsr DisplayWordlda #' 'jsr DisplayChardexbne ioi1plxplartsEmuMVP:push r4push r5tsr sp,r4lda 4,r4ldx 3,r4ldy 2,r4EmuMVP1:ld r5,(x)st r5,(y)dexdeydeacmp #$FFFFFFFFbne EmuMVP1sta 4,r4stx 3,r4sty 2,r4inc 6,r4 ; increment the return address by one.pop r5pop r4plyplxplartiEmuMVN:push r4push r5tsr sp,r4lda 4,r4ldx 3,r4ldy 2,r4EmuMVN1:ld r5,(x)st r5,(y)inxinydeacmp #$FFFFFFFFbne EmuMVN1sta 4,r4stx 3,r4sty 2,r4inc 6,r4 ; increment the return address by one.pop r5pop r4plyplxplartimsgUnimp:db "Unimplemented at: ",0brk_rout:lda #16sta LEDSjsr kernel_panicdb "Break routine",0jsr DumpHistoryTablestprtinmirout:phalda #msgPerrjsr DisplayStringBlda 3,spjsr DisplayWordjsr CRLFplartimsgPerr:db "Parity error at: ",0;==============================================================================; Finitron Multi-Tasking Kernel (FMTK); __; \\__/ o\ (C) 2013, 2014 Robert Finch, Stratford; \ __ / All rights reserved.; \/_// robfinch<remove>@opencores.org; ||;==============================================================================message "FMTK"org $FFFFC000syscall_vectors:dw MTKInitializedw StartTaskdw ExitTaskdw KillTaskdw SetTaskPrioritydw Sleepdw AllocMbxdw FreeMbxdw PostMsgdw SendMsgdw WaitMsgdw CheckMsgorg $FFFFC200message "MTKInitialize"MTKInitialize:; Initialize semaphoreslda #1sta freetcb_semasta freembx_semasta freemsg_semasta tcb_semasta readylist_semasta tolist_semasta mbx_semasta msg_semasta jcb_sematsr vbr,r2and r2,#-2lda #reschedulesta 2,xlda #syscall_intsta 4,xlda #MTKTicksta 448+3,xstz UserTicklda #-1sta TimeoutList ; no entries in timeout liststa QNdx0sta QNdx1sta QNdx2sta QNdx3sta QNdx4stz missed_ticks; Initialize IO Focus List;lda #7ldx #0ldy #IOFocusTblstos; Set owning job to zero (the monitor)lda #255ldx #0ldy #TCB_hJCBstos; zero out JCB's; This will NULL out the I/O focus list pointerslda #NR_JCB * JCB_Sizeldx #0lea r3,JCBsstos; Setup default values in the JCB'sldy #0ldx #JCBsijcb1:sty JCB_Number,xsty JCB_Map,xstz JCB_esc,xlda #31sta JCB_VideoRows,xlda #56sta JCB_VideoCols,xlda #1 ; turn on keyboard echosta JCB_KeybdEcho,xsta JCB_CursorOn,xsta JCB_CursorFlash,xstz JCB_CursorRow,xstz JCB_CursorCol,xstz JCB_CursorType,xlda #%1011_01111 ; grey on greysta JCB_NormAttr,xsta JCB_CurrAttr,xld r4,r3mul r4,r4,#8192 ; 8192 words per screenadd r4,r4,#BIOS_SCREENSst r4,JCB_pVirtVid,xst r4,JCB_pVidMem,xadd r4,r4,#$1000st r4,JCB_pVirtVidAttr,xst r4,JCB_pVidMemAttr,xcpy #0bne ijcb2lda #%0110_01110 ; CE =blue on blue FB = grey on greysta JCB_NormAttr,xsta JCB_CurrAttr,xld r4,#TEXTSCRst r4,JCB_pVidMem,xadd r4,r4,#$10000st r4,JCB_pVidMemAttr,xijcb2:lda #8sta JCB_LogSize,xinyadd r2,r2,#JCB_Sizecpy #32blo ijcb1; Initialize free message listlda #NR_MSGsta nMsgBlkstz FreeMsgldx #0lda #1st4:sta MSG_LINK,xinainxcpx #NR_MSGbne st4lda #-1sta MBX_LINK+NR_MSG-1; Initialize free mailbox list; Note the first NR_TCB mailboxes are statically allocated to the tasks.; They are effectively pre-allocated.lda #NR_MBX-NR_TCBsta nMailboxldx #NR_TCBstx FreeMbxHandlelda #NR_TCB+1st3:sta MBX_LINK,xinainxcpx #NR_MBXbne st3lda #-1sta MBX_LINK+NR_MBX-1; Initialize the FreeJCB listlda #JCBs+JCB_Size ; the next available JCBsta FreeJCBtaxadd r1,r1,#JCB_Sizeldy #NR_JCB-1st5:sta JCB_Next,xadd r1,r1,#JCB_Sizeadd r2,r2,#JCB_Sizedeybne st5stz JCB_Next,x; Initialize the FreeTCB listlda #1 ; the next available TCBsta FreeTCBldx #1lda #2st2:sta TCB_NxtTCB,xinainxcpx #256bne st2lda #-1sta TCB_NxtTCB+255lda #4sta LEDS; Manually setup the BIOS taskstz RunningTCB ; BIOS is task #0stz TCB_NxtRdy ; manually build the ready liststz TCB_PrvRdylda #-1sta TCB_NxtTosta TCB_PrvTostz QNdx2 ; insert at priority 2; manually build the IO focus listlda #JCBssta IOFocusNdx ; Job #0 (Monitor) has the focusstz JCB_iof_next,r1stz JCB_iof_prev,r1lda #1sta IOFocusTbl ; set the job #0 request bitlda #PRI_NORMALsta TCB_Prioritystz TCB_Timeoutlda #TS_RUNNING|TS_READYsta TCB_Statusstz TCB_CursorRowstz TCB_CursorColstz TCB_ABS8Saveldx #BIOS_STACKS+0x03FF ; setup stack pointer top of memorystx TCB_SPSaveldx #$1FFstx TCB_SP8Saverts;------------------------------------------------------------------------------;------------------------------------------------------------------------------message "startIdleTask"StartIdleTask:lda #4ldx #0ldy #IdleTaskjsr StartTaskrts;------------------------------------------------------------------------------; IdleTask;; IdleTask is a low priority task that is always running. It runs when there; is nothing else to run.; This task check for tasks that are stuck in infinite loops and kills them.;------------------------------------------------------------------------------IdleTask:stz TestTaskit2:inc TEXTSCR+111 ; increment IDLE active flagldx TestTaskand r2,r2,#$FFbeq it1lda TCB_Status,xcmp #TS_SLEEPbne it1txaint #4 ; KillTask functiondb 3; jsr KillTaskit1:inc TestTaskcli ; enable interruptswai ; wait for one to happenbra it2;------------------------------------------------------------------------------; Parameters:; r1 = job name; r2 = start address;------------------------------------------------------------------------------;StartJob:pha; Get a free JCBspl freejcb_sema + 1ld r6,FreeJCBbeq sjob1ld r7,JCB_Next,r6st r7,FreeJCBstz freejcb_sema + 1lea r7,JCB_Name,r6 ; r7 = address of name fieldasl r7,r7,#2 ; convert word to byte addressld r9,r7 ; save off buffer addressld r8,#0 ; r8 = count of characters (0 to 31)sjob3:lb r5,0,r1 ; get a characterbeq sjob2 ; end of string ?sb r5,1,r7inainc r7inc r8cmp r8,#31 ; max number of chars ?blo sjob3sjob2:sb r8,0,r9 ; save name lengthsjob1:stz freejcb_sema + 1plarts;------------------------------------------------------------------------------; StartTask;; Startup a task. The task is automatically allocated a 1kW stack from the BIOS; stacks area. The scheduler is invoked after the task is added to the ready; list.;; Parameters:; r1 = task priority; r2 = start flags; r3 = start address; r4 = start parameter; r5 = job handle;------------------------------------------------------------------------------message "StartTask"StartTask:pushald r6,r1 ; r6 = task priorityld r8,r2 ; r8 = flag register value on startup; get a free TCB;spl freetcb_sema+1lda FreeTCB ; get free tcb list pointerbmi stask1taxlda TCB_NxtTCB,xsta FreeTCB ; update the FreeTCB list pointerstz freetcb_sema+1lda #81sta LEDStxa ; acc = TCB index (task number)sta TCB_mbx,x; setup the stack for the task; Zap the stack memory.ld r7,r2asl r2,r2,#10 ; 1kW stack per taskadd r2,r2,#BIOS_STACKS ;+0x3ff ; add in stack basephaphxphytxy ; y = target addressldx #ExitTask ; x = fill valuelda #$3FF ; acc = # words to fill -1stosplyplxplaadd r2,r2,#$3FF ; Move pointer to top of stackstx TCB_StackTop,r7sub r2,r2,#128tsr sp,r9 ; save off current stack pointerspl tcb_sema + 1txsst r6,TCB_Priority,r7stz TCB_Status,r7stz TCB_Timeout,r7st r5,TCB_hJCB,r7 ; save job handle; setup virtual video for the task; stz TCB_CursorRow,r7; stz TCB_CursorCol,r7stz TCB_mmu_map,r7 ; use mmu map; jsr AllocateMemPagephalda #82sta LEDSlda #-1sta TCB_MbxList,r7lda BASIC_SESSIONcmp #1bls stask3asl r1,r1,#14add r1,r1,#$430_0000sta TCB_ABS8Save,r7add r1,r1,#$1FFsta TCB_SP8Save,r7bra stask4stask3:lda #$1FFsta TCB_SP8Save,r7stz TCB_ABS8Save,r7stask4:lda #83sta LEDSpla; tay; 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 stackldx #ExitTask ; save the address of the task exit routinephxphy ; save start address on stackpush 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 registerspush r4push r4push r4push r4push r4push r4push r4push r4push r4push r4push r4push r4push r4push r4push r4tsxstx TCB_SPSave,r7; now restore the current stack pointertrs r9,sp; Insert the task into the ready listld r4,#84st r4,LEDSjsr AddTaskToReadyListlda #1sta tcb_semaint #2 ; invoke the scheduler; GoReschedule ; invoke the schedulerstask2:popartsstask1:stz freetcb_sema+1jsr kernel_panicdb "No more task control blocks available.",0bra stask2;------------------------------------------------------------------------------; ExitTask;; This routine is called when the task exits with an rts instruction. OR; it may be invoked with a JMP ExitTask. In either case the task must be; running so it can't be on the timeout list. The scheduler is invoked; after the task is removed from the ready list.;------------------------------------------------------------------------------message "ExitTask"ExitTask:; release any aquired resources; - mailboxes; - messageshoffspl tcb_sema + 1lda RunningTCBcmp #MAX_TASKNObhi xtsk1jsr RemoveTaskFromReadyListjsr RemoveFromTimeoutListstz TCB_Status,r1 ; set task status to TS_NONEjsr ReleaseIOFocus; lda TCB_ABS8Save,x; jsr FreeMemPage; Free up all the mailboxes associated with the task.xtsk7:phalda TCB_MbxList,r1bmi xtsk6jsr FreeMbxplabra xtsk7xtsk6:plaldx #86stx LEDSspl freetcb_sema+1ldx FreeTCB ; add the task control block to the free liststx TCB_NxtTCB,r1sta FreeTCBstz freetcb_sema+1xtsk1:jmp SelectTaskToRun;------------------------------------------------------------------------------; r1 = task number; r2 = new priority;------------------------------------------------------------------------------;SetTaskPriority:cmp #MAX_TASKNO ; make sure task number is reasonablebhi stp1physpl tcb_sema + 1ldy TCB_Status,r1 ; if the task is on the ready listbit r3,#TS_READY|TS_RUNNING ; then remove it and re-add it.beq stp2 ; Otherwise just go set the priority fieldjsr RemoveTaskFromReadyListstx TCB_Priority,r1jsr AddTaskToReadyListbra stp3stp2:stx TCB_Priority,r1stp3:ldy #1sty tcb_semaint #2plystp1:rts;------------------------------------------------------------------------------; AddTaskToReadyList;; The ready list is a group of five ready lists, one for each priority; level. Each ready list is organized as a doubly linked list to allow fast; insertions and removals. The list is organized as a ring (or bubble) with; the last entry pointing back to the first. This allows a fast task switch; to the next task. Which task is at the head of the list is maintained; in the variable QNdx for the priority level.;; Registers Affected: none; Parameters:; r1 = task number; Returns:; none;------------------------------------------------------------------------------;message "AddTaskToReadyList"AddTaskToReadyList:phxphyldx #TS_READYstx TCB_Status,r1ldx #-1stx TCB_NxtRdy,r1stx TCB_PrvRdy,r1ldy TCB_Priority,r1cpy #5blo arl1ldy #PRI_LOWESTarl1:ldx QNdx0,ybmi arl5ldy TCB_PrvRdy,xsta TCB_NxtRdy,ysty TCB_PrvRdy,r1sta TCB_PrvRdy,xstx TCB_NxtRdy,r1plyplxrts; Here the ready list was empty, so add at headarl5:sta QNdx0,ysta TCB_NxtRdy,r1sta TCB_PrvRdy,r1plyplxrts;------------------------------------------------------------------------------; RemoveTaskFromReadyList;; This subroutine removes a task from the ready list.;; Registers Affected: none; Parameters:; r1 = task number; Returns:; r1 = task number;------------------------------------------------------------------------------message "RemoveTaskFromReadyList"RemoveTaskFromReadyList:phxphypush r4push r5ldy TCB_Status,r1 ; is the task on the ready list ?bit r3,#TS_READY|TS_RUNNINGbeq rfr2and r3,r3,#~(TS_READY|TS_RUNNING)sty TCB_Status,r1 ; task status no longer running or readyld r4,TCB_NxtRdy,r1 ; Get previous and next fields.ld r5,TCB_PrvRdy,r1st r4,TCB_NxtRdy,r5st r5,TCB_PrvRdy,r4ldy TCB_Priority,r1cmp r1,QNdx0,y ; Are we removing the QNdx task ?bne rfr2st r4,QNdx0,y; Now we test for the case where the task being removed was the only one; on the ready list of that priority level. We can tell because the; NxtRdy would point to the task itself.cmp r4,r1bne rfr2ldx #-1 ; Make QNdx negativestx QNdx0,ystx TCB_NxtRdy,r1stx TCB_PrvRdy,r1rfr2:pop r5pop r4plyplxrts;------------------------------------------------------------------------------; AddToTimeoutList; AddToTimeoutList adds a task to the timeout list. The task is placed in the; list depending on it's timeout value.;; Registers Affected: none; Parameters:; r1 = task; r2 = timeout value;------------------------------------------------------------------------------message "AddToTimeoutList"AddToTimeoutList:phxpush r4push r5ld r5,#-1st r5,TCB_NxtTo,r1 ; these fields should already be -1st r5,TCB_PrvTo,r1ld r4,TimeoutList ; are there any tasks on the timeout list ?bmi attl_add_at_head ; If not, update head of listattl_check_next:sub r2,r2,TCB_Timeout,r4 ; is this timeout > nextbmi attl_insert_beforeld r5,r4ld r4,TCB_NxtTo,r4bpl 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_NxtTo,r1 ; r4 is = -1st r1,TCB_NxtTo,r5st r5,TCB_PrvTo,r1stx TCB_Timeout,r1bra attl_exitattl_insert_before:cmp r5,#0bmi attl_insert_before_headst r4,TCB_NxtTo,r1 ; next on list goes after this taskst r5,TCB_PrvTo,r1 ; set previous linkst r1,TCB_NxtTo,r5st r1,TCB_PrvTo,r4bra attl_adjust_timeout; Here there is no previous entry in the timeout list; Add at startattl_insert_before_head:sta TCB_PrvTo,r4st r5,TCB_PrvTo,r1 ; r5 is = -1st r4,TCB_NxtTo,r1sta TimeoutList ; update the head pointerattl_adjust_timeout:add r2,r2,TCB_Timeout,r4 ; get back timeoutstx TCB_Timeout,r1ld r5,TCB_Timeout,r4 ; adjust the timeout of the next tasksub r5,r5,r2st r5,TCB_Timeout,r4bra attl_exit; Here there were no tasks on the timeout list, so we add at the; head of the list.attl_add_at_head:sta TimeoutList ; set the head of the timeout liststx TCB_Timeout,r1ldx #-1 ; flag no more entries in timeout liststx TCB_NxtTo,r1 ; no next entriesstx TCB_PrvTo,r1 ; and no prev entriesattl_exit:ldx TCB_Status,r1 ; set the task's status as timing outor r2,r2,#TS_TIMEOUTstx TCB_Status,r1pop r5pop r4plxrts;------------------------------------------------------------------------------; RemoveFromTimeoutList;; This routine is called when a task is killed. The task may need to be; removed from the middle of the timeout list.;; On entry: the timeout list semaphore must be already set.; Registers Affected: none; Parameters:; r1 = task number;------------------------------------------------------------------------------message "RemoveFromTimeoutList"RemoveFromTimeoutList:cmp #MAX_TASKNObhi rftl_not_on_list2phxpush r4push r5ld r4,TCB_Status,r1 ; Is the task even on the timeout list ?bit r4,#TS_TIMEOUTbeq rftl_not_on_listcmp TimeoutList ; Are we removing the head of the list ?beq rftl_remove_from_headld r4,TCB_PrvTo,r1 ; adjust the links of the next and previousbmi rftl_empty_list ; no previous link - list corrupt?ld r5,TCB_NxtTo,r1 ; tasks on the list to point around the taskst r5,TCB_NxtTo,r4bmi rftl_empty_listst r4,TCB_PrvTo,r5ldx TCB_Timeout,r1 ; update the timeout of the next on listadd r2,r2,TCB_Timeout,r5 ; with any remaining timeout in the taskstx TCB_Timeout,r5 ; removed from the listbra rftl_empty_list; Update the head of the list.rftl_remove_from_head:ld r5,TCB_NxtTo,r1st r5,TimeoutList ; store next field into list headbmi rftl_empty_listld r4,TCB_Timeout,r1 ; add any remaining timeout to the timeoutadd r4,r4,TCB_Timeout,r5 ; of the next task on the list.st r4,TCB_Timeout,r5ld r4,#-1 ; there is no previous item to the headsta TCB_PrvTo,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.rftl_empty_list:taxlda #0 ; clear timeout status (bit #0)bmc TCB_Status,xdea ; acc=-1; make sure the next and prev fields indicatesta TCB_NxtTo,x ; the task is not on a list.sta TCB_PrvTo,xtxarftl_not_on_list:pop r5pop r4plxrftl_not_on_list2:rts;------------------------------------------------------------------------------; PopTimeoutList;; This subroutine is called from within the timer ISR when the task's; timeout expires. It's always the head of the list that's being removed in; the timer ISR so the removal from the timeout list is optimized. We know; the timeout expired, so the amount of time to add to the next task is zero.; This routine is written as a macro since it's only called from one place.; This routine is inlined. Implementing it as a macro increases performance.;; Registers Affected: acc, x, y, flags; Parameters:; x: head of timeout list; Returns:; r1 = task id of task popped from timeout list;------------------------------------------------------------------------------;message "PopTimeoutList"macro PopTimeoutListldy #-1lda TCB_NxtTo,xsta TimeoutList ; store next field into list headbmi ptl1sty TCB_PrvTo,r1 ; previous link = -1ptl1:lda #0 ; clear timeout statusbmc TCB_Status,xsty TCB_NxtTo,x ; make sure the next and prev fields indicatesty TCB_PrvTo,x ; the task is not on a list.txaendm;------------------------------------------------------------------------------; Sleep;; Put the currently running task to sleep for a specified time.;; Registers Affected: none; Parameters:; r1 = time duration in centi-seconds (1/100 second).; Returns: none;------------------------------------------------------------------------------;Sleep:phaphxtaxspl tcb_sema + 1lda RunningTCBjsr RemoveTaskFromReadyListjsr AddToTimeoutList ; The scheduler will be returning to thislda #1sta tcb_semaint #2 ; task eventually, once the timeout expires,plxplarts;------------------------------------------------------------------------------; Short delay routine.; This routine works by reading the tick register. When a subsequent read; of the tick register exceeds the value of the original read by at least; the value passed as a parameter, then this routine returns.; The tick register increments at the clock rate (eg 25 MHz).;------------------------------------------------------------------------------;short_delay:phxphytsr tick,r2usec1:tsr tick,r3sub r3,r3,r2cmp r1,r3blo usec1plyplxrts;------------------------------------------------------------------------------; KillTask;; "Kills" a task, removing it from all system lists. If the task has the; IO focus, the IO focus is switched. Task #0 is immortal and cannot be; killed.;; Registers Affected: none; Parameters:; r1 = task number;------------------------------------------------------------------------------;KillTask:phxcmp #1 ; BIOS task and IDLE task are immortalbls kt1cmp #MAX_TASKNObhi kt1taxlda TCB_hJCB,r1jsr ForceReleaseIOFocustxaspl tcb_sema + 1jsr RemoveTaskFromReadyListjsr RemoveFromTimeoutListstz TCB_Status,r1 ; set task status to TS_NONE; Free up all the mailboxes associated with the task.kt7:phataxlda TCB_MbxList,r1bmi kt6jsr FreeMbx2plabra kt7kt6:lda #1sta tcb_semaplaspl freetcb_sema + 1ldx FreeTCB ; add the task control block to the free liststx TCB_NxtTCB,r1sta FreeTCBstz freetcb_sema + 1cmp RunningTCB ; keep running the current task as long asbne kt1 ; the task didn't kill itself.int #2 ; invoke scheduler to reschedule taskskt1:plxrts;------------------------------------------------------------------------------; Allocate a mailbox; Parameters:; r1 = pointer to place to store handle; Returns:; r1 = E_Ok means mailbox allocated properly; r1 = E_Arg means a NULL pointer was passed in r1; r1 = E_NoMoreMbx means no more mailboxes were available; zf is set if everything is ok, otherwise zf is clear;------------------------------------------------------------------------------;message "AllocMbx"AllocMbx:cmp #0beq ambx_bad_ptrphxphypush r4ld r4,r1 ; r4 = pointer to returned handlespl freembx_sema + 1lda FreeMbxHandle ; Get mailbox off of free mailbox liststa (r4) ; store off the mailbox numberbmi ambx_no_mbxsldx MBX_LINK,r1 ; and update the head of the liststx FreeMbxHandledec nMailbox ; decrement number of available mailboxesstz freembx_sema + 1spl tcb_sema + 1ldy RunningTCB ; Add the mailbox to the list of mailboxesldx TCB_MbxList,y ; managed by the task.stx MBX_LINK,r1sta TCB_MbxList,ytaxldy RunningTCB ; set the mailbox owner; bmi RunningTCBErrlda TCB_hJCB,ystz tcb_sema + 1spl mbx_sema + 1sta MBX_OWNER,xlda #-1 ; initialize the head and tail of the queuessta MBX_TQ_HEAD,xsta MBX_TQ_TAIL,xsta MBX_MQ_HEAD,xsta MBX_MQ_TAIL,xstz MBX_TQ_COUNT,x ; initialize counts to zerostz MBX_MQ_COUNT,xstz MBX_MQ_MISSED,xlda #8 ; set the max queue sizesta MBX_MQ_SIZE,x ; andlda #MQS_NEWEST ; queueing strategysta MBX_MQ_STRATEGY,xstz mbx_sema + 1pop r4plyplxlda #E_Okrtsambx_bad_ptr:lda #E_Argrtsambx_no_mbxs:stz freembx_sema + 1pop r4plyplxlda #E_NoMoreMbxrts;------------------------------------------------------------------------------; Free up a mailbox.; This function frees a mailbox from the currently running task. It may be; called by ExitTask().;; Parameters:; r1 = mailbox handle;------------------------------------------------------------------------------;FreeMbx:phxldx RunningTCBjsr FreeMbx2plxrts;------------------------------------------------------------------------------; Free up a mailbox.; This function dequeues any messages from the mailbox and adds the messages; back to the free message pool. The function also dequeues any threads from; the mailbox.; Called from KillTask() and FreeMbx().;; Parameters:; r1 = mailbox handle; r2 = task handle; Returns:; r1 = E_Ok if everything ok; r1 = E_Arg if a bad handle is passed;------------------------------------------------------------------------------;FreeMbx2:cmp #NR_MBX ; check mailbox handle parameterbhs fmbx1cpx #MAX_TASKNObhi fmbx1phxphyspl mbx_sema + 1; Dequeue messages from mailbox and add them back to the free message list.fmbx5:phajsr DequeueMsgFromMbxbmi fmbx3spl freemsg_sema + 1phxldx FreeMsgstx MSG_LINK,r1sta FreeMsgstz freemsg_sema + 1plxplabra fmbx5fmbx3:pla; Dequeue threads from mailbox.fmbx6:phajsr DequeueThreadFromMbx2bmi fmbx7plabra fmbx6fmbx7:pla; Remove mailbox from TCB listldy TCB_MbxList,xphxldx #-1fmbx10:cmp r1,r3beq fmbx9tyxldy MBX_LINK,ybpl fmbx10; ?The mailbox was not in the list managed by the task.plxbra fmbx2fmbx9:cmp r2,r0bmi fmbx11ldy MBX_LINK,ysty MBX_LINK,xplxbra fmbx12fmbx11:; No prior mailbox in list, update headldy MBX_LINK,r1plxsty TCB_MbxList,xfmbx12:; Add mailbox back to mailbox poolspl freembx_sema + 1ldx FreeMbxHandlestx MBX_LINK,r1sta FreeMbxHandlestz freembx_sema + 1fmbx2:stz mbx_sema + 1plyplxlda #E_Okrtsfmbx1:lda #E_Argrts;------------------------------------------------------------------------------; Queue a message at a mailbox.; On entry the mailbox semaphore is already activated.;; Parameters:; r1 = message; r2 = mailbox;------------------------------------------------------------------------------message "QueueMsgAtMbx"QueueMsgAtMbx:cmp #0beq qmam_bad_msgphaphxphypush r4ld r4,MBX_MQ_STRATEGY,xcmp r4,#MQS_UNLIMITEDbeq qmam_unlimitedcmp r4,#MQS_NEWESTbeq qmam_newestcmp r4,#MQS_OLDESTbeq qmam_oldestjsr kernel_panicdb "Illegal message queue strategy",0bra qmam8; Here we assumed "unlimited" message storage. Just add the new message at; the tail of the queue.qmam_unlimited:ldy MBX_MQ_TAIL,xbmi qmam_add_at_headsta MSG_LINK,ybra qmam2qmam_add_at_head:sta MBX_MQ_HEAD,xqmam2:sta MBX_MQ_TAIL,xqmam6:inc MBX_MQ_COUNT,x ; increase the queued message countldx #-1stx MSG_LINK,r1pop r4plyplxplaqmam_bad_msg:rts; Here we are queueing a limited number of messages. As new messages are; added at the tail of the queue, messages drop off the head of the queue.qmam_newest:ldy MBX_MQ_TAIL,xbmi qmam3sta MSG_LINK,ybra qmam4qmam3:sta MBX_MQ_HEAD,xqmam4:sta MBX_MQ_TAIL,xldy MBX_MQ_COUNT,xinycmp r3,MBX_MQ_SIZE,xbls qmam6ldy #-1sty MSG_LINK,r1; Remove the oldest message which is the one at the head of the mailbox queue.; Add the message back to the pool of free messages.lda MBX_MQ_HEAD,xldy MSG_LINK,r1 ; move next in queuesty MBX_MQ_HEAD,x ; to head of listqmam8:inc MBX_MQ_MISSED,xqmam1:spl freemsg_sema + 1ldy FreeMsg ; put old message back into free message liststy MSG_LINK,r1sta FreeMsginc nMsgBlkstz freemsg_sema + 1;GoReschedulepop r4plyplxplarts; Here we are buffering the oldest messages. So if there are too many messages; in the queue already, then the queue doesn't change and the new message is; lost.qmam_oldest:ldy MBX_MQ_COUNT,x ; Check if the queue is fullcmp r3,MBX_MQ_SIZE,xbhs qmam8 ; If the queue is full, then lose the current messagebra qmam_unlimited ; Otherwise add message to queue;------------------------------------------------------------------------------; Dequeue a message from a mailbox.;; Returns; r1 = message number; nf set if there is no message, otherwise clear;------------------------------------------------------------------------------message "DequeueMsgFromMbx"DequeueMsgFromMbx:phxphytax ; x = mailbox indexlda MBX_MQ_COUNT,x ; are there any messages available ?beq dmfm3deasta MBX_MQ_COUNT,x ; update the message countlda MBX_MQ_HEAD,x ; Get the head of the list, this should not be -1bmi dmfm3 ; since the message count > 0ldy MSG_LINK,r1 ; get the link to the next messagesty MBX_MQ_HEAD,x ; update the head of the listbpl dmfm2 ; if there was no more messages then update thesty 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 dequeueddmfm1:plyplxcmp #0rtsdmfm3:plyplxlda #-1rts;------------------------------------------------------------------------------; Parameters:; r1 = mailbox handle; Returns:; r1 = E_arg means pointer is invalid; r1 = E_NoThread means no thread was queued at the mailbox; r2 = thead handle;------------------------------------------------------------------------------message "DequeueThreadFromNbx"DequeueThreadFromMbx:push r4ld r4,MBX_TQ_HEAD,r1bpl dtfm2pop r4ldx #-1lda #E_NoThreadrtsdtfm2:push r5dec MBX_TQ_COUNT,r1ld r2,r4ld r4,TCB_mbq_next,r4st r4,MBX_TQ_HEAD,r1bmi dtfm3ld r5,#-1st r5,TCB_mbq_prev,r4bra dtfm4dtfm3:ld r5,#-1st r5,MBX_TQ_TAIL,r1dtfm4:; stz MBX_SEMA+1ld r5,r2lda TCB_Status,r5bit #TS_TIMEOUTbeq dtfm5ld r1,r5jsr RemoveFromTimeoutListdtfm5:ld r4,#-1st r4,TCB_mbq_next,r5st r4,TCB_mbq_prev,r5stz TCB_hWaitMbx,r5stz TCB_Status,r5 ; set task status = TS_NONEpop r5pop r4lda #E_Okrts;------------------------------------------------------------------------------; This function is called from FreeMbx(). It dequeues threads from the; mailbox without removing the thread from the timeout list. The thread will; then timeout waiting for a message that can never be delivered.;; Parameters:; r1 = mailbox handle; Returns:; r1 = E_arg means pointer is invalid; r1 = E_NoThread means no thread was queued at the mailbox; r2 = thead handle;------------------------------------------------------------------------------message "DequeueThreadFromNbx2"DequeueThreadFromMbx2:push r4ld r4,MBX_TQ_HEAD,r1bpl dtfm2apop r4ldx #-1lda #E_NoThreadrtsdtfm2a:push r5dec MBX_TQ_COUNT,r1ld r2,r4ld r4,TCB_mbq_next,r4st r4,MBX_TQ_HEAD,r1bmi dtfm3ald r5,#-1st r5,TCB_mbq_prev,r4bra dtfm4adtfm3a:ld r5,#-1st r5,MBX_TQ_TAIL,r1dtfm4a:ld r4,#-1st r4,TCB_mbq_next,xst r4,TCB_mbq_prev,xstz TCB_hWaitMbx,xseilda #TS_WAITMSG_BITbmc TCB_Status,xclipop r5pop r4lda #E_Okrts;------------------------------------------------------------------------------; PostMsg and SendMsg are the same operation except that PostMsg doesn't; invoke rescheduling while SendMsg does. So they both call the same; SendMsgPrim primitive routine. This two wrapper functions for convenience.;------------------------------------------------------------------------------;PostMsg:push r4ld r4,#0 ; Don't invoke schedulerjsr SendMsgPrimpop r4rtsSendMsg:push r4ld r4,#1 ; Do invoke schedulerjsr SendMsgPrimpop r4rts;------------------------------------------------------------------------------; SendMsgPrim; Send a message to a mailbox;; Parameters; r1 = handle to mailbox; r2 = message D1; r3 = message D2; r4 = scheduler flag 1=invoke,0=don't invoke;; Returns; r1=E_Ok everything is ok; r1=E_BadMbx for a bad mailbox number; r1=E_NotAlloc for a mailbox that isn't allocated; r1=E_NoMsg if there are no more message blocks available; zf is set if everything is okay, otherwise zf is clear;------------------------------------------------------------------------------message "SendMsgPrim"SendMsgPrim:cmp #NR_MBX ; check the mailbox number to make surebhs smsg1 ; that it's sensiblepush r5push r6push r7spl mbx_sema + 1ld r7,MBX_OWNER,r1bmi smsg2 ; error: no ownerphaphxjsr DequeueThreadFromMbx ; r1=mbxld r6,r2 ; r6 = threadplxplacmp r6,#0bpl smsg3; Here there was no thread waiting at the mailbox, so a message needs to; be allocatedsmp2:spl freemsg_sema + 1ld r7,FreeMsgbmi smsg4 ; no more messages availableld r5,MSG_LINK,r7st r5,FreeMsgdec nMsgBlk ; decrement the number of available messagesstz freemsg_sema + 1stx MSG_D1,r7sty MSG_D2,r7phaphxtax ; x = mailboxld r1,r7 ; acc = messagejsr QueueMsgAtMbxplxplacmp r6,#0 ; check if there is a thread waiting for a messagebmi smsg5smsg3:stx TCB_MSG_D1,r6sty TCB_MSG_D2,r6smsg7:spl tcb_sema + 1ld r5,TCB_Status,r6bit r5,#TS_TIMEOUTbeq smsg8ld r1,r6jsr RemoveFromTimeoutListsmsg8:lda #TS_WAITMSG_BITbmc TCB_Status,r6lda #1sta tcb_semald r1,r6spl tcb_sema + 1jsr AddTaskToReadyListstz tcb_sema + 1cmp r4,#0beq smsg5stz mbx_sema + 1int #2;GoReschedulebra smsg9smsg5:stz mbx_sema + 1smsg9:pop r7pop r6pop r5lda #E_Okrtssmsg1:lda #E_BadMbxrtssmsg2:stz mbx_sema + 1pop r7pop r6pop r5lda #E_NotAllocrtssmsg4:stz freemsg_sema + 1stz mbx_sema + 1pop r7pop r6pop r5lda #E_NoMsgrts;------------------------------------------------------------------------------; 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=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; r2=message D1; r3=message D2;------------------------------------------------------------------------------message "WaitMsg"WaitMsg:cmp #NR_MBX ; check the mailbox number to make surebhs wmsg1 ; that it's sensiblepush r4push r5push r6push r7ld r6,r1wmsg11:spl mbx_sema + 1ld r5,MBX_OWNER,r1cmp r5,#MAX_TASKNObhi wmsg2 ; error: no ownerjsr DequeueMsgFromMbx; cmp #0bpl 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.wmsg12:spl tcb_sema + 1lda RunningTCB ; remove the task from the ready listjsr RemoveTaskFromReadyListstz tcb_sema + 1wmsg13:spl tcb_sema + 1ld r7,TCB_Status,r1or r7,r7,#TS_WAITMSG ; set task status to waitingst r7,TCB_Status,r1st r6,TCB_hWaitMbx,r1 ; set which mailbox is waited forld r7,#-1st r7,TCB_mbq_next,r1 ; adding at tail, so there is no nextld r7,MBX_TQ_HEAD,r6 ; is there a task que setup at the mailbox ?bmi wmsg6ld r7,MBX_TQ_TAIL,r6st r7,TCB_mbq_prev,r1sta TCB_mbq_next,r7sta MBX_TQ_TAIL,r6inc MBX_TQ_COUNT,r6 ; increment number of tasks queuedwmsg7:stz tcb_sema + 1stz mbx_sema + 1cmp r2,#0 ; check for a timeoutbeq wmsg10wmsg14:spl tcb_sema + 1jsr AddToTimeoutListstz tcb_sema + 1int #2 ; GoReschedule ; invoke the schedulerwmsg10:; At this point either a message was sent to the task, or the task; timed out. If a message is still not available then the task must; have timed out. Return a timeout error.; Note that SendMsg will directly set the message D1, D2 data; without queing a message at the mailbox (if there is a task; waiting already). So we cannot just try dequeing a message again.ldx TCB_MSG_D1,r1ldy TCB_MSG_D2,r1ld r4,TCB_Status,r1bit r4,#TS_WAITMSG ; Is the task still waiting for a message ?beq wmsg8 ; If not, go return OK statuspop r7 ; Otherwise return timeout errorpop r6pop r5pop r4lda #E_Timeoutrts; Here there were no prior tasks queued at the mailboxwmsg6:ld r7,#-1st r7,TCB_mbq_prev,r1 ; no previous tasksst r7,TCB_mbq_next,r1sta MBX_TQ_HEAD,r6 ; set both head and tail indexessta MBX_TQ_TAIL,r6ld r7,#1st r7,MBX_TQ_COUNT,r6 ; one task queuedbra wmsg7 ; check for a timeout valuewmsg3:stz mbx_sema + 1ldx MSG_D1,r1ldy MSG_D2,r1; Add the newly dequeued message to the free messsage listwmsg5:spl freemsg_sema + 1ld r7,FreeMsgst r7,MSG_LINK,r1sta FreeMsginc nMsgBlkstz freemsg_sema + 1wmsg8:pop r7pop r6pop r5pop r4lda #E_Okrtswmsg1:lda #E_BadMbxrtswmsg2:stz mbx_sema + 1pop r7pop r6pop r5pop r4lda #E_NotAllocrts;------------------------------------------------------------------------------; Check for a message at a mailbox. Does not block. This function is a; convenience wrapper for CheckMsg().;; Parameters; r1=mailbox handle; 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; r2=message D1; r3=message D2;------------------------------------------------------------------------------;PeekMsg:ld r2,#0 ; don't remove from queuejsr CheckMsgrts;------------------------------------------------------------------------------; CheckMsg; Check for a message at a mailbox. Does not block.;; Parameters; r1=mailbox handle; r2=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; r2=message D1; r3=message D2;------------------------------------------------------------------------------CheckMsg:cmp #NR_MBX ; check the mailbox number to make surebhs cmsg1 ; that it's sensiblepush r4push r5spl mbx_sema + 1ld r5,MBX_OWNER,r1bmi cmsg2 ; error: no ownercpx #0 ; are we to dequeue the message ?phpbeq cmsg3jsr DequeueMsgFromMbxbra cmsg4cmsg3:lda MBX_MQ_HEAD,r1 ; peek the message at the head of the messages queuecmsg4:cmp #0bmi cmsg5ldx MSG_D1,r1ldy MSG_D2,r1plp ; get back dequeue flagbeq cmsg8cmsg10:spl freemsg_sema + 1ld r5,FreeMsgst r5,MSG_LINK,r1sta FreeMsginc nMsgBlkstz freemsg_sema + 1cmsg8:stz mbx_sema + 1pop r5pop r4lda #E_Okrtscmsg1:lda #E_BadMbxrtscmsg2:stz mbx_sema + 1pop r5pop r4lda #E_NotAllocrtscmsg5:stz mbx_sema + 1pop r5pop r4lda #E_NoMsgrts;------------------------------------------------------------------------------; Spinlock interrupt; Go reschedule tasks if a spinlock is taking too long.;------------------------------------------------------------------------------;spinlock_irq:clild r0,tcb_sema + 1beq spi1cldpushabra resched1spi1:rti;------------------------------------------------------------------------------; System Call Interrupt;; The system call is executed using the caller's system stack.;; Stack Frame; 4,sp: return address; 3,sp: status register; 2,sp: r6 save; 1,sp: r7 save; 0,sp: r8 save;------------------------------------------------------------------------------;syscall_int:clicldpush r6 ; save off some working registerspush r7push r8ld r6,4,sp ; get return address into r6lb r7,0,r6 ; get static call number parameter into r7inc r6 ; update return addressst r6,4,sp; tsr sp,r8 ; save off stack pointer; ld r6,RunningTCB ; load the stack pointer with the system call; ld r6,TCB_StackTop,r6 ; stack area; trs r6,spld r6,(syscall_vectors>>2),r7 ; load the vector into r6jsr (r6) ; do the system function; trs r8,sp ; restore the stack pointerpop r8pop r7pop r6rti;------------------------------------------------------------------------------; Reschedule tasks to run without affecting the timeout list timing.;------------------------------------------------------------------------------;reschedule:cli ; enable interruptscld ; clear extended precision modepusha ; save off regs on the stackspl tcb_sema + 1resched1:ldx RunningTCBtsasta TCB_SPSave,x ; save stack pointer in TCBtsr sp8,r1 ; and the eight bit mode stack pointersta TCB_SP8Save,xtsr abs8,r1sta TCB_ABS8Save,x ; 8 bit emulation base registerlda #TS_RUNNING_BIT ; clear RUNNING status (bit #3)bmc TCB_Status,x; lda TCB_StackTop,x ; switch to the system call stack; tasjmp SelectTaskToRunstrStartQue:db 0,0,0,1,0,0,0,2,0,1,0,3,0,0,0,4; db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;------------------------------------------------------------------------------; 100 Hz interrupt; - takes care of "flashing" the cursor; - decrements timeouts for tasks on timeout list; - switching tasks;------------------------------------------------------------------------------;MTKTick:phalda #3 ; reset the edge sense circuitsta PIC_RSTEplainc IRQFlag; Try and aquire the ready list and tcb. If unsuccessful it means there is; a system function in the process of updating the list. All we can do is; return to the system function and let it complete whatever it was doing.; As if we don't return to the system function we will be deadlocked.; The tick will be deferred; however if the system function was busy updating; the ready list, in all likelyhood it's about to call the reschedule; interrupt.ld r0,tcb_sema+1bne p100Hz11inc missed_ticksrtip100Hz11:clicld ; clear extended precision modepusha ; save off regs on the stacklda #96sta LEDSlda UserTickbeq p100Hz4jsr (r1)clip100Hz4:ldx RunningTCBtsa ; save off the stack pointersta TCB_SPSave,xtsr sp8,r1 ; and the eight bit mode stack pointersta TCB_SP8Save,xtsr abs8,r1sta TCB_ABS8Save,x ; 8 bit emulation base registerlda #TS_RUNNING_BITbmc TCB_Status,xlda #97sta LEDS; 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 TimeoutListbmi p100Hz12 ; are there any entries in the timeout list ?lda TCB_Timeout,xbgt p100Hz14 ; has this entry timed out ?PopTimeoutListjsr AddTaskToReadyListbra p100Hz15 ; go back and see if there's another task to be removed; there could be a string of tasks to make ready.p100Hz14:dea ; decrement the entry's timeoutsub r1,r1,missed_ticks ; account for any missed ticksstz missed_tickssta TCB_Timeout,xp100Hz12:; Falls through into selecting a task to runtck3:lda #98sta LEDS;------------------------------------------------------------------------------; 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.;------------------------------------------------------------------------------;SelectTaskToRun:ld r6,#5 ; number of queues to searchldy IRQFlag ; use the IRQFlag as a buffer index; lsr r3,r3,#1 ; the LSB is always the sameand r3,r3,#$0F ; counts from 0 to 15lb r3,strStartQue,y ; get the queue to start search atsttr2:lda QNdx0,ybmi sttr1lda TCB_NxtRdy,r1 ; Advance the queue indexsta QNdx0,y; This is the only place the RunningTCB is set (except for initialization).sta RunningTCBtaxlda #TS_RUNNING_BITbms TCB_Status,x ; flag the task as the running tasklda #99sta LEDSlda TCB_ABS8Save,x ; 8 bit emulation base registertrs r1,abs8lda TCB_SP8Save,x ; get back eight bit stack pointertrs r1,sp8ldx TCB_SPSave,x ; get back stack pointertxslda #1sta tcb_semald r0,iof_switchbeq sttr6ld r0,iof_sema + 1 ; just ignore the request to switchbeq sttr6 ; I/O focus if the semaphore can't be aquiredstz iof_switchjsr SwitchIOFocusstz iof_sema + 1sttr6:popa ; restore registersrti; Set index to check the next ready list for a task to runsttr1:inycpy #5bne sttr5ldy #0sttr5:dec r6bne sttr2; Here there were no tasks ready; This should not be able to happen, so hang the machine (in a lower; power mode).sttr3:ldx #94stx LEDSjsr kernel_panicdb "No tasks in ready queue.",0; Might as well power down the clock and wait for a reset or; NMI. In the case of an NMI the kernel is reinitialized without; doing the boot reset.stpjmp MTKInitialize;------------------------------------------------------------------------------; kernal_panic:; All this does right now is display the panic message on the screen.; Parameters:; inline: string;------------------------------------------------------------------------------;kernel_panic:pla ; pop the return address off the stackpush r4 ; save off r4ld r4,r1kpan2:lb r1,0,r4 ; get a byte from the code spaceadd r4,#1 ; increment pointerand #$FF ; we want only eight bitsbeq kpan1 ; is it end of string ?jsr DisplayCharbra kpan2kpan1: ; must update the return address !jsr CRLFld r1,r4 ; get return address into accpop r4 ; restore r4jmp (r1)include "DeviceDriver.asm";------------------------------------------------------------------;------------------------------------------------------------------include "Test816.asm"include "pi_calc816.asm";------------------------------------------------------------------; Kind of a chicken and egg problem here. If there is something; wrong with the processor, then this code likely won't execute.;; put message to screen; tests pla,sta,ldy,inc,bne,ora,jmp,jmp(abs)putmsgpla ; pop the return address off the stackwdm ; switch to 32 bitsxcecpu RTF65002push r4 ; save off r4or r4,r1,#$FFFF0000 ; set program bank bits; code is at $FFFFxxxxpm2add r4,#1 ; increment pointerlb r1,0,r4 ; get a byte from the code spaceand #$FF ; we want only eight bitsbeq pm1 ; is it end of string ?jsr DisplayCharjmp pm2pm1 ; must update the return address !ld r1,r4 ; get return address into accpop r4 ; restore r4clc ; switch back to '816 modexcecpu W65C816Srep #$30 ; mem,ndx = 16 bitsphartscpu RTF65002;------------------------------------------------------------------; This test program just loop around waiting to recieve a message.; The message is a pointer to a string to display.;------------------------------------------------------------------;test_mbx_prg:jsr RequestIOFocuslda #test_mbx ; where to put mailbox handleint #4db 6 ; AllocMbxldx #5jsr PRTNUM; mStartTask #PRI_LOWEST,#0,#test_mbx_prg2,#0,#0lda #PRI_LOWESTldx #0ldy #test_mbx_prg2ld r4,#0ld r5,#1int #4db 1 ; StartTasktmp2:lda test_mbxldx #100int #4db 10 ; WaitMsgcmp #E_Okbne tmp1txajsr DisplayStringBbra tmp2tmp1:ldx #4jsr PRTNUMbra tmp2test_mbx_prg2:tmp2a:lda test_mbxldx #msg_helloldy #0int #4db 8 ; PostMsgbra tmp2amsg_hello:db "Hello from RTF",13,10,0message "DOS.asm"include "DOS.asm"cpu RTF65002message "1298"include "TinyBasic65002.asm"message "1640"org $0FFFFFFF4 ; NMI vectordw nmiroutorg $0FFFFFFF8 ; reset vector, native modedw startend
