URL
https://opencores.org/ocsvn/rf68000/rf68000/trunk
Subversion Repositories rf68000
[/] [rf68000/] [trunk/] [software/] [examples/] [boot.asm] - Rev 4
Go to most recent revision | Compare with Previous | Blame | View Log
;-------------------------------------------------------------------------------
;
; system memory map
;
;
; 00000000 +----------------+ <+
; | startup sp,pc | 8 B |
; 00000008 +----------------+ |
; | vectors | pair shared+
; 00000400 +----------------+ |
; | bios mem | |
; 00001000 +----------------+ |
; | bios code | |
; 00008000 +----------------+ <+
; | unused |
; 00040000 +----------------+
; | local ram |
; 00042000 +----------------+
; | unused |
; 00100000 +----------------+
; | global ram |
; 00101000 +----------------+
; | serial rcvbuf |
; 00102000 +----------------+
; | unused |
; 20000000 +----------------+
; | |
; | |
; | |
; : dram memory : 512 MB
; | |
; | |
; | |
; 40000000 +----------------+
; | |
; : unused :
; | |
; FD000000 +----------------+
; | |
; : I/O area : 1.0 M
; | |
; FFE00000 +----------------+
; | |
; : unused :
; | |
; FFFFFFFF +----------------+
;
;-------------------------------------------------------------------------------
;
HAS_MMU equ 0
CTRLC EQU $03
CTRLH EQU $08
CTRLS EQU $13
CTRLX EQU $18
CTRLZ EQU $1A
LF EQU $0A
CR EQU $0D
XON EQU $11
XOFF EQU $13
SC_F12 EQU $07
SC_C EQU $21
SC_T EQU $2C
SC_Z EQU $1A
SC_KEYUP EQU $F0
SC_EXTEND EQU $E0
SC_CTRL EQU $14
SC_RSHIFT EQU $59
SC_NUMLOCK EQU $77
SC_SCROLLLOCK EQU $7E
SC_CAPSLOCK EQU $58
SC_ALT EQU $11
SC_LSHIFT EQU $12
SC_DEL EQU $71 ; extend
SC_LCTRL EQU $58
SC_TAB EQU $0D
if HAS_MMU
TEXTREG EQU $1E3FF00 ; virtual addresses
txtscreen EQU $1E00000
semamem EQU $1E50000
ACIA EQU $1E60000
ACIA_RX EQU 0
ACIA_TX EQU 0
ACIA_STAT EQU 4
ACIA_CMD EQU 8
ACIA_CTRL EQU 12
I2C2 equ $01E69000
I2C_PREL equ 0
I2C_PREH equ 1
I2C_CTRL equ 2
I2C_RXR equ 3
I2C_TXR equ 3
I2C_CMD equ 4
I2C_STAT equ 4
PLIC EQU $1E90000
MMU EQU $FDC00000 ; physical address
leds EQU $1EFFF00 ; virtual addresses
keybd EQU $1EFFE00
KEYBD EQU $1EFFE00
RAND EQU $1EFFD00
RAND_NUM EQU $1EFFD00
RAND_STRM EQU $1EFFD04
RAND_MZ EQU $1EFFD08
RAND_MW EQU $1EFFD0C
RST_REG EQU $1EFFC00
IO_BITMAP EQU $1F00000
else
TEXTREG EQU $FD03FF00 ; virtual addresses
txtscreen EQU $FD000000
semamem EQU $FD050000
ACIA EQU $FD060000
ACIA_RX EQU 0
ACIA_TX EQU 0
ACIA_STAT EQU 4
ACIA_CMD EQU 8
ACIA_CTRL EQU 12
I2C2 equ $FD069000
I2C_PREL equ 0
I2C_PREH equ 1
I2C_CTRL equ 2
I2C_RXR equ 3
I2C_TXR equ 3
I2C_CMD equ 4
I2C_STAT equ 4
PLIC EQU $FD090000
MMU EQU $FDC00000 ; physical address
leds EQU $FD0FFF00 ; virtual addresses
keybd EQU $FD0FFE00
KEYBD EQU $FD0FFE00
RAND EQU $FD0FFD00
RAND_NUM EQU $FD0FFD00
RAND_STRM EQU $FD0FFD04
RAND_MZ EQU $FD0FFD08
RAND_MW EQU $FD0FFD0C
RST_REG EQU $FD0FFC00
IO_BITMAP EQU $FD100000
endif
SERIAL_SEMA EQU 2
KEYBD_SEMA EQU 3
RAND_SEMA EQU 4
SCREEN_SEMA EQU 5
MEMORY_SEMA EQU 6
TCB_SEMA EQU 7
data
dc.l $00040FFC
dc.l start
dc.l bus_err
dc.l 0
dc.l illegal_trap * ILLEGAL instruction
dc.l 0
dc.l EXCEPTION_6 * CHK
dc.l EXCEPTION_7 * TRAPV
dc.l 0
dc.l 0
; 10
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
; 20
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l SpuriousIRQ
dc.l 0
dc.l 0
dc.l irq3_rout
dc.l 0
dc.l 0
; 30
dc.l TickIRQ ; IRQ 30 - timer / keyboard
dc.l nmi_rout
dc.l 0
dc.l 0
dc.l 0
dc.l trap3 ; breakpoint
dc.l 0
dc.l 0
dc.l 0
dc.l 0
; 40
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l TRAP15
dc.l 0
dc.l 0
; 50
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l io_irq
; 60
dc.l KeybdIRQ
dc.l SerialIRQ
dc.l 0
dc.l brdisp_trap
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
org $400
InstalledIRQ:
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0
org $500
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; BIOS variables which must be local (not shared) to each core
CursorRow equ $40000
CursorCol equ $40001
TextPos equ $40002
TextCurpos equ $40002
TextScr equ $40004
S19StartAddress equ $40008
KeybdEcho equ $4000C
KeybdWaitFlag equ $4000D
CmdBuf equ $40040
CmdBufEnd equ $40080
fgColor equ $40084
bkColor equ $40088
TextRows equ $4008C
TextCols equ $4008D
Regsave equ $40100
numBreakpoints equ 8
BreakpointFlag equ $40200
NumSetBreakpoints equ $40202 ; to $40203
Breakpoints equ $40220 ; to $40240
BreakpointWords equ $40280 ; to $402A0
;RunningTCB equ $40300
TimerStack equ $40BFC
; Keyboard buffer is in shared memory
IOFocus EQU $00100000
memend equ $00100004
KeybdLEDs equ $0010000E
_KeyState1 equ $0010000F
_KeyState2 equ $00100010
_KeybdHead equ $00100011
_KeybdTail equ $00100012
_KeybdCnt equ $00100013
KeybdID equ $00100016
_KeybdBuf equ $00100020
S19Checksum equ $00100150
SerTailRcv equ $00100160
SerHeadRcv equ $00100162
SerRcvXon equ $00100164
SerRcvXoff equ $00100165
SerRcvBuf equ $00101000
RTCBuf equ $00100200 ; to $0010023F
include "..\Femtiki\source\kernel\Femtiki_vars.x68"
code
align 2
start:
; fadd (a0)+,fp2
move.w #$2700,sr ; enable level 6 and higher interrupts
moveq #0,d0 ; set address space zero
movec d0,asid
; Setup circuit select signals
move.l #MMU,d0
movec d0,mmus
if HAS_MMU
move.l #$01F00000,d0 ; set virtual address for iop bitmap
movec d0,iops
move.l #$01E00000,d0 ; set virtual address for io block
movec d0,ios
else
move.l #$FD100000,d0 ; set virtual address for iop bitmap
movec d0,iops
move.l #$FD000000,d0 ; set virtual address for io block
movec d0,ios
endif
movec coreno,d0 ; set initial value of thread register
swap d0 ; coreno in high eight bits
lsl.l #8,d0
movec d0,tr
; Prepare local variable storage
move.w #1023,d0 ; 1024 longs to clear
lea $40000,a0 ; non shared local memory address
.0111:
clr.l (a0)+ ; clear the memory area
dbra d0,.0111
move.l #$1fffff,fgColor ; set foreground / background color
move.l #$00003f,bkColor
movec.l coreno,d0 ; get core number (2 to 9)
subi.b #2,d0 ; adjust (0 to 7)
mulu #16384,d0 ; compute screen location
if HAS_MMU
addi.l #$01E00000,d0
else
addi.l #$FD000000,d0
endif
move.l d0,TextScr
move.b #64,TextCols ; set rows and columns
move.b #32,TextRows
movec.l coreno,d0 ; get core number
cmpi.b #2,d0
bne start_other
move.b d0,IOFocus ; Set the IO focus in global memory
if HAS_MMU
bsr InitMMU ; Can't access anything till this is done
endif
bsr InitIOPBitmap ; not going to get far without this
bsr InitSemaphores
bsr InitRand
bsr Delay3s ; give devices time to reset
bsr clear_screen
bsr _KeybdInit
; bsr InitIRQ
bsr SerialInit
bsr init_i2c
; bsr rtc_read
; Write startup message to screen
lea msg_start,a1
bsr DisplayString
; bsr FemtikiInit
movec coreno,d0
swap d0
moveq #1,d1
bsr UnlockSemaphore ; allow another cpu access
moveq #0,d1
bsr UnlockSemaphore ; allow other cpus to proceed
move.w #$A4A4,leds ; diagnostics
bsr init_plic ; initialize platform level interrupt controller
bra StartMon
bsr cpu_test
; lea brdisp_trap,a0 ; set brdisp trap vector
; move.l a0,64*4
loop2:
move.l #-1,d0
loop1:
move.l d0,d1
lsr.l #8,d1
lsr.l #8,d1
move.b d1,leds
dbra d0,loop1
bra loop2
start_other:
bsr Delay3s2 ; need time for system setup (io_bitmap etc.)
bsr Delay3s2 ; need time for system setup (io_bitmap etc.)
bsr clear_screen
movec coreno,d1
bsr DisplayByte
lea msg_core_start,a1
bsr DisplayString
; bsr FemtikiInitIRQ
do_nothing:
bra StartMon
bra do_nothing
;------------------------------------------------------------------------------
; Initialize the MMU to allow thread #0 access to IO
;------------------------------------------------------------------------------
if HAS_MMU
align 2
mmu_adrtbl: ; virtual address[24:16], physical address[31:16] bytes reversed!
dc.l $0010,$10000300 ; global scratch pad
dc.l $01E0,$00FD0300
dc.l $01E1,$01FD0300
dc.l $01E2,$02FD0300
dc.l $01E3,$03FD0300
dc.l $01E5,$05FD0300
dc.l $01E6,$06FD0300
dc.l $01E9,$09FD0300
dc.l $01EF,$0FFD0300
dc.l $01F0,$10FD0300
dc.l $01FF,$FFFF0300 ; all ones output for IRQ ack needed
even
InitMMU:
lea MMU+8,a0 ; first 128kB is local RAM
move.l #$32000,d2 ; map all pages to DRAM
move.l #510,d0 ; then override for IO later
.0002
move.l d2,d1
bsr rbo
move.l d1,(a0)+
addi.w #1,d2 ; increment DRAM page number
dbra d0,.0002
lea MMU,a0 ; now program IO access
lea mmu_adrtbl,a1
moveq #10,d0
.0001
move.l (a1)+,d2
lsl.l #2,d2
move.l (a1)+,(a0,d2.w)
dbra d0,.0001
rts
endif
;------------------------------------------------------------------------------
; The IO bitmap needs to be initialized to allow access to IO.
;------------------------------------------------------------------------------
InitIOPBitmap:
moveq #0,d3 ; d3 = asid value
move.w #63,d0 ; 64 bitmaps to setup
movec iops,a0 ; a0 = IOP bitmap address
movea.l a0,a1 ; a1 = table address
.0004
tst.b d3
seq d1 ; set entire bitmap for asid 0, otherwise clear entire bitmap
ext.w d1 ; make into a long value
ext.l d1
move.w #127,d4
.0001
move.l d1,(a1)+ ; set or clear entire table
dbra d4,.0001
moveq #-1,d1
move.l d1,160(a0) ; all cores have access to semaphores
move.l d1,164(a0)
move.l d1,168(a0)
move.l d1,172(a0)
swap d0
move.w #31,d0 ; 32 long words for the screen area per bitmap
.0003
move.l d1,(a0)+ ; all cores have access to a screen
dbra d0,.0003
swap d0
addi.b #1,d3 ; do next address space
movea.l a1,a0 ; a0 points to area for next address space
dbra d0,.0004
rts
;------------------------------------------------------------------------------
; RandInit
; Initialize random number generator.
;
; Modifies:
; none
; Parameters:
; none
; Returns:
; none
;------------------------------------------------------------------------------
InitRand:
RandInit:
movem.l d0/d1,-(a7)
moveq #37,d0 ; lock semaphore
moveq #RAND_SEMA,d1
trap #15
movec coreno,d0 ; d0 = core number
lsl.l #6,d0 ; allow 64 streams per core
move.l d0,RAND_STRM ; select the stream
move.l #$12345678,RAND_MZ ; initialize to some value
move.l #$98765432,RAND_MW
move.l #777777777,RAND_NUM ; generate first number
moveq #38,d0 ; unlock semaphore
moveq #RAND_SEMA,d1
trap #15
movem.l (a7)+,d0/d1
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
RandGetNum:
movem.l d0/d2,-(a7)
moveq #37,d0 ; lock semaphore
moveq #RAND_SEMA,d1
trap #15
movec coreno,d0
lsl.l #6,d0
move.l d0,RAND_STRM ; select the stream
move.l RAND_NUM,d2 ; d2 = random number
clr.l RAND_NUM ; generate next number
moveq #38,d0 ; unlock semaphore
moveq #RAND_SEMA,d1
trap #15
move.l d2,d1
movem.l (a7)+,d0/d2
rts
;------------------------------------------------------------------------------
; RandWait
; Wait some random number of clock cycles before returning.
;------------------------------------------------------------------------------
RandWait:
movem.l d0/d1,-(a7)
bsr RandGetNum
andi.w #15,d1
.0001:
nop
dbra d1,.0001
movem.l (a7)+,d0/d1
rts
;------------------------------------------------------------------------------
; Initialize semaphores
; - all semaphores are set to unlocked except the first one, which is locked
; for core #2.
;
; Parameters:
; <none>
; Modifies:
; <none>
; Returns:
; <none>
;------------------------------------------------------------------------------
InitSemaphores:
movem.l d1/a0,-(a7)
lea semamem,a0
move.l #$20000,$2000(a0) ; lock the first semaphore for core #2, thread #0
move.w #254,d1
.0001:
lea 4(a0),a0
clr.l $2000(a0) ; write zeros to unlock
dbra d1,.0001
movem.l (a7)+,d1/a0
rts
; -----------------------------------------------------------------------------
; Parameters:
; d1 semaphore number
;
; Side Effects:
; increments semaphore, saturates at 255
;
; Returns:
; z flag set if semaphore was zero
; -----------------------------------------------------------------------------
;IncrementSemaphore:
; movem.l d1/a0,-(a7) ; save registers
; lea semamem,a0 ; point to semaphore memory
; ext.w d1 ; make d1 word value
; asl.w #4,d1 ; align to memory
; tst.b 1(a0,d1.w) ; read (test) value for zero
; movem.l (a7)+,a0/d1 ; restore regs
; rts
; -----------------------------------------------------------------------------
; Parameters:
; d1 semaphore number
;
; Side Effects:
; decrements semaphore, saturates at zero
;
; Returns:
; z flag set if semaphore was zero
; -----------------------------------------------------------------------------
;DecrementSemaphore:
; movem.l d1/a0,-(a7) ; save registers
; lea semamem,a0 ; point to semaphore memory
; andi.w #255,d1 ; make d1 word value
; asl.w #4,d1 ; align to memory
; tst.b 1(a0,d1.w) ; read (test) value for zero
; movem.l (a7)+,a0/d1 ; restore regs
; rts
; -----------------------------------------------------------------------------
; Lock a semaphore
;
; Parameters:
; d0 = key
; d1 = semaphore number
; -----------------------------------------------------------------------------
LockSemaphore:
rts
movem.l d1/a0,-(a7) ; save registers
lea semamem,a0 ; point to semaphore memory lock area
andi.w #255,d1 ; make d1 word value
lsl.w #2,d1 ; align to memory
.0001
move.l d0,(a0,d1.w) ; try and write the semaphore
cmp.l (a0,d1.w),d0 ; did it lock?
bne.s .0001 ; no, try again
movem.l (a7)+,a0/d1 ; restore regs
rts
; -----------------------------------------------------------------------------
; Unlocks a semaphore even if not the owner.
;
; Parameters:
; d1 semaphore number
; -----------------------------------------------------------------------------
ForceUnlockSemaphore:
movem.l d1/a0,-(a7) ; save registers
lea semamem+$3000,a0 ; point to semaphore memory read/write area
andi.w #255,d1 ; make d1 word value
lsl.w #2,d1 ; align to memory
clr.l (a0,d1.w) ; write zero to unlock
movem.l (a7)+,a0/d1 ; restore regs
rts
; -----------------------------------------------------------------------------
; Unlocks a semaphore. Must be the owner to have effect.
; Three cases:
; 1) the owner, the semaphore will be reset to zero
; 2) not the owner, the write will be ignored
; 3) already unlocked, the write will be ignored
;
; Parameters:
; d0 = key
; d1 = semaphore number
; -----------------------------------------------------------------------------
UnlockSemaphore:
bra ForceUnlockSemaphore
movem.l d1/a0,-(a7) ; save registers
lea semamem+$1000,a0 ; point to semaphore memory unlock area
andi.w #255,d1 ; make d1 word value
lsl.w #2,d1 ; align to memory
move.l d0,(a0,d1.w) ; write matching value to unlock
movem.l (a7)+,a0/d1 ; restore regs
rts
; -----------------------------------------------------------------------------
; Parameters:
; d1 = semaphore to lock / unlock
; -----------------------------------------------------------------------------
T15LockSemaphore:
movec tr,d0
bra LockSemaphore
T15UnlockSemaphore:
movec tr,d0
bra UnlockSemaphore
; -----------------------------------------------------------------------------
; Delay for a few seconds to allow some I/O reset operations to take place.
; -----------------------------------------------------------------------------
Delay3s:
move.l #3000000,d0 ; this should take a few seconds to loop
lea leds,a0 ; a0 = address of LED output register
bra dly3s1 ; branch to the loop
dly3s2:
swap d0 ; loop is larger than 16-bits
dly3s1:
move.l d0,d1 ; the counter cycles fast, so use upper bits for display
rol.l #8,d1 ; could use swap here, but lets test rol
rol.l #8,d1
move.b d1,(a0) ; set the LEDs
dbra d0,dly3s1 ; decrement and branch back
swap d0
dbra d0,dly3s2
rts
Delay3s2:
movec coreno,d0 ; vary delay by core to stagger startup
lsl.l #8,d0
addi.l #3000000,d0 ; this should take a few seconds to loop
bra .0001 ; branch to the loop
.0002
swap d0 ; loop is larger than 16-bits
.0001
dbra d0,.0001 ; decrement and branch back
swap d0
dbra d0,.0002
rts
include "cputest.asm"
include "TinyBasic.asm"
include "..\Femtiki\source\kernel\Femtiki.x68"
; -----------------------------------------------------------------------------
; Gets the screen color in d0 and d1.
; -----------------------------------------------------------------------------
get_screen_color:
move.l fgColor,d0 ; get foreground color
asl.l #5,d0 ; shift into position
ori.l #$40000000,d0 ; set priority
move.l bkColor,d1
lsr.l #8,d1
lsr.l #8,d1
andi.l #31,d1 ; mask off extra bits
or.l d1,d0 ; set background color bits in upper long word
move.l bkColor,d1 ; get background color
asl.l #8,d1 ; shift into position for display ram
asl.l #8,d1
rts
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
get_screen_address:
move.l TextScr,a0
rts
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
clear_screen:
movem.l d0/d1/d2/a0,-(a7)
movec coreno,d0
swap d0
moveq #SCREEN_SEMA,d1
bsr LockSemaphore
bsr get_screen_address ; a0 = pointer to screen area
move.b TextRows,d0 ; d0 = rows
move.b TextCols,d2 ; d2 = cols
ext.w d0 ; convert to word
ext.w d2 ; convert to word
mulu d0,d2 ; d2 = number of character cells to clear
bsr get_screen_color ; get the color bits
ori.w #32,d1 ; load space character
rol.w #8,d1 ; swap endian, text controller expects little endian
swap d1
rol.w #8,d1
rol.w #8,d0 ; swap endian
swap d0
rol.w #8,d0
loop3:
move.l d1,(a0)+ ; copy char plus bkcolor to cell
move.l d0,(a0)+ ; copy fgcolor to cell
dbra d2,loop3
movec coreno,d0
swap d0
moveq #SCREEN_SEMA,d1
bsr UnlockSemaphore
movem.l (a7)+,d0/d1/d2/a0
rts
CRLF:
move.l d1,-(a7)
move.b #13,d1
bsr DisplayChar
move.b #10,d1
bsr DisplayChar
move.l (a7)+,d1
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
UpdateTextPos:
move.b CursorRow,d0 ; compute screen location
andi.w #$7f,d0
move.b TextCols,d2
ext.w d2
mulu.w d2,d0
move.l d0,d3
move.b CursorCol,d2
andi.w #$ff,d2
add.w d2,d0
move.w d0,TextPos ; save cursor pos
rts
;------------------------------------------------------------------------------
; Calculate screen memory location from CursorRow,CursorCol.
; Destroys d0,d2,a0
;------------------------------------------------------------------------------
CalcScreenLoc:
bsr UpdateTextPos
ext.l d0 ; make it into a long
asl.l #3,d0 ; 8 bytes per char
bsr get_screen_address
add.l d0,a0 ; a0 = screen location
rts
;------------------------------------------------------------------------------
; Display a character on the screen
; d1.b = char to display
;------------------------------------------------------------------------------
DisplayChar:
movem.l d1/d2/d3,-(a7)
movec coreno,d2
cmpi.b #2,d2
; bne.s .0001
; bsr SerialPutChar
.0001:
andi.l #$ff,d1 ; zero out upper bytes of d1
cmpi.b #13,d1 ; carriage return ?
bne dccr
clr.b CursorCol ; just set cursor column to zero on a CR
dcx14:
bsr SyncCursor ; set position in text controller
dcx7:
movem.l (a7)+,d1/d2/d3
rts
dccr:
cmpi.b #$91,d1 ; cursor right ?
bne.s dcx6
move.b TextCols,d2
sub.b #1,d2
sub.b CursorCol,d2
beq.s dcx7
addi.b #1,CursorCol
bra.s dcx14
dcx6:
cmpi.b #$90,d1 ; cursor up ?
bne.s dcx8
cmpi.b #0,CursorRow
beq.s dcx7
subi.b #1,CursorRow
bra.s dcx14
dcx8:
cmpi.b #$93,d1 ; cursor left?
bne.s dcx9
cmpi.b #0,CursorCol
beq.s dcx7
subi.b #1,CursorCol
bra.s dcx14
dcx9:
cmpi.b #$92,d1 ; cursor down ?
bne.s dcx10
move.b TextRows,d2
sub.b #1,d2
cmp.b CursorRow,d2
beq.s dcx7
addi.b #1,CursorRow
bra.s dcx14
dcx10:
cmpi.b #$94,d1 ; cursor home ?
bne.s dcx11
cmpi.b #0,CursorCol
beq.s dcx12
clr.b CursorCol
bra dcx14
dcx12:
clr.b CursorRow
bra dcx14
dcx11:
movem.l d0/d1/d2/a0,-(a7)
cmpi.b #$99,d1 ; delete ?
beq.s doDelete
cmpi.b #CTRLH,d1 ; backspace ?
beq.s doBackspace
cmpi.b #CTRLX,d1 ; delete line ?
beq doCtrlX
cmpi.b #10,d1 ; linefeed ?
beq.s dclf
; regular char
bsr CalcScreenLoc ; a0 = screen location
move.l d1,d2 ; d2 = char
bsr get_screen_color ; d0,d1 = color
or.l d2,d1 ; d1 = char + color
rol.w #8,d1 ; text controller expects little endian data
swap d1
rol.w #8,d1
move.l d1,(a0)
rol.w #8,d0 ; swap bytes
swap d0 ; swap halfs
rol.w #8,d0 ; swap remaining bytes
move.l d0,4(a0)
bsr IncCursorPos
bsr SyncCursor
bra dcx4
dclf:
bsr IncCursorRow
dcx16:
bsr SyncCursor
dcx4:
movem.l (a7)+,d0/d1/d2/a0 ; get back a0
movem.l (a7)+,d1/d2/d3
rts
;---------------------------
; CTRL-H: backspace
;---------------------------
doBackspace:
cmpi.b #0,CursorCol ; if already at start of line
beq.s dcx4 ; nothing to do
subi.b #1,CursorCol ; decrement column
;---------------------------
; Delete key
;---------------------------
doDelete:
movem.l d0/d1/a0,-(a7) ; save off screen location
bsr CalcScreenLoc ; a0 = screen location
move.b CursorCol,d0
.0001:
move.l 8(a0),(a0) ; pull remaining characters on line over 1
move.l 12(a0),4(a0) ; pull remaining characters on line over 1
lea 8(a0),a0
addi.b #1,d0
cmp.b TextCols,d0
blo.s .0001
bsr get_screen_color
move.w #' ',d1 ; terminate line with a space
rol.w #8,d1
swap d1
rol.w #8,d1
move.l d1,-8(a0)
movem.l (a7)+,d0/d1/a0
bra.s dcx16 ; finished
;---------------------------
; CTRL-X: erase line
;---------------------------
doCtrlX:
clr.b CursorCol ; Reset cursor to start of line
move.b TextCols,d0 ; and display TextCols number of spaces
ext.w d0
ext.l d0
move.b #' ',d1 ; d1 = space char
.0001:
; DisplayChar is called recursively here
; It's safe to do because we know it won't recurse again due to the
; fact we know the character being displayed is a space char
bsr DisplayChar
subq #1,d0
bne.s .0001
clr.b CursorCol ; now really go back to start of line
bra.s dcx16 ; we're done
;------------------------------------------------------------------------------
; Increment the cursor position, scroll the screen if needed.
;------------------------------------------------------------------------------
IncCursorPos:
addi.w #1,TextCurpos
addi.b #1,CursorCol
move.b TextCols,d0
cmp.b CursorCol,d0
bhs.s icc1
clr.b CursorCol
IncCursorRow:
addi.b #1,CursorRow
move.b TextRows,d0
cmp.b CursorRow,d0
bhi.s icc1
move.b TextRows,d0
move.b d0,CursorRow ; in case CursorRow is way over
subi.b #1,CursorRow
ext.w d0
asl.w #1,d0
sub.w d0,TextCurpos
bsr ScrollUp
icc1:
rts
;------------------------------------------------------------------------------
; Scroll screen up.
;------------------------------------------------------------------------------
ScrollUp:
movem.l d0/d1/a0/a5,-(a7) ; save off some regs
movec coreno,d0
swap d0
moveq #SCREEN_SEMA,d1
bsr LockSemaphore
bsr get_screen_address
move.l a0,a5 ; a5 = pointer to text screen
.0003:
move.b TextCols,d0 ; d0 = columns
move.b TextRows,d1 ; d1 = rows
ext.w d0 ; make cols into a word value
ext.w d1 ; make rows into a word value
asl.w #3,d0 ; make into cell index
lea 0(a5,d0.w),a0 ; a0 = pointer to second row of text screen
lsr.w #3,d0 ; get back d0
subq #1,d1 ; number of rows-1
mulu d1,d0 ; d0 = count of characters to move
.0001:
move.l (a0)+,(a5)+ ; each char is 64 bits
move.l (a0)+,(a5)+
dbra d0,.0001
movec coreno,d0
swap d0
moveq #SCREEN_SEMA,d1
bsr UnlockSemaphore
movem.l (a7)+,d0/d1/a0/a5
; Fall through into blanking out last line
;------------------------------------------------------------------------------
; Blank out the last line on the screen.
;------------------------------------------------------------------------------
BlankLastLine:
movem.l d0/d1/d2/a0,-(a7)
movec coreno,d0
swap d0
moveq #SCREEN_SEMA,d1
bsr LockSemaphore
bsr get_screen_address
move.b TextRows,d0 ; d0 = rows
move.b TextCols,d1 ; d1 = columns
ext.w d0
ext.w d1
subq #1,d0 ; last row = #rows-1
mulu d1,d0 ; d0 = index of last line
lsl.w #3,d0 ; *8 bytes per char
lea (a0,d0.w),a0 ; point a0 to last row
move.b TextCols,d2 ; number of text cells to clear
ext.w d2
subi.w #1,d2 ; count must be one less than desired
bsr get_screen_color ; d0,d1 = screen color
move.w #32,d1 ; set the character for display in low 16 bits
bsr rbo ; reverse the byte order
rol.w #8,d0
swap d0
rol.w #8,d0
.0001:
move.l d0,(a0)+
move.l d1,(a0)+
dbra d2,.0001
movec coreno,d0
swap d0
moveq #SCREEN_SEMA,d1
bsr UnlockSemaphore
movem.l (a7)+,d0/d1/d2/a0
rts
;------------------------------------------------------------------------------
; Display a string on the screen.
;------------------------------------------------------------------------------
DisplayString:
movem.l d0/d1/a1,-(a7)
dspj1:
clr.l d1 ; clear upper bits of d1
move.b (a1)+,d1 ; move string char into d1
beq.s dsret ; is it end of string ?
bsr DisplayChar ; display character
bra.s dspj1 ; go back for next character
dsret:
movem.l (a7)+,d0/d1/a1
rts
;------------------------------------------------------------------------------
; Display a string on the screen followed by carriage return / linefeed.
;------------------------------------------------------------------------------
DisplayStringCRLF:
bsr DisplayString
bra CRLF
;------------------------------------------------------------------------------
; Display a string on the screen limited to 255 chars max.
;------------------------------------------------------------------------------
DisplayStringLimited:
movem.l d0/d1/d2/a1,-(a7)
move.w d1,d2 ; d2 = max count
andi.w #$00FF,d2 ; limit to 255 chars
bra.s .0003 ; enter loop at bottom
.0001:
clr.l d1 ; clear upper bits of d1
move.b (a1)+,d1 ; move string char into d1
beq.s .0002 ; is it end of string ?
bsr DisplayChar ; display character
.0003:
dbra d2,.0001 ; go back for next character
.0002:
movem.l (a7)+,d0/d1/d2/a1
rts
DisplayStringLimitedCRLF:
bsr DisplayStringLimited
bra CRLF
;------------------------------------------------------------------------------
; Set cursor position to top left of screen.
;
; Parameters:
; <none>
; Returns:
; <none>
; Registers Affected:
; <none>
;------------------------------------------------------------------------------
HomeCursor:
clr.b CursorRow
clr.b CursorCol
clr.w TextPos
; fall through
;------------------------------------------------------------------------------
; SyncCursor:
;
; Sync the hardware cursor's position to the text cursor position but only for
; the core with the IO focus.
;
; Parameters:
; <none>
; Returns:
; <none>
; Registers Affected:
; <none>
;------------------------------------------------------------------------------
SyncCursor:
movem.l d0/d2,-(a7)
bsr UpdateTextPos
movec coreno,d2
cmp.b IOFocus,d2
bne.s .0001
subi.w #2,d2 ; factor in location of screen in controller
mulu #2048,d2 ; 2048 cells per screen
add.w d2,d0
rol.w #8,d0 ; swap byte order
move.w d0,TEXTREG+$24
.0001:
movem.l (a7)+,d0/d2
rts
;==============================================================================
; TRAP #15 handler
;
; Parameters:
; d0.w = function number to perform
;==============================================================================
TRAP15:
movem.l d0/a0,-(a7)
lea T15DispatchTable,a0
asl.l #2,d0
move.l (a0,d0.w),a0
jsr (a0)
movem.l (a7)+,d0/a0
rte
align 2
T15DispatchTable:
dc.l DisplayStringLimitedCRLF
dc.l DisplayStringLimited
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l GetKey
dc.l DisplayChar
dc.l CheckForKey
dc.l StubRout
dc.l StubRout
; 10
dc.l StubRout
dc.l Cursor1
dc.l SetKeyboardEcho
dc.l DisplayStringCRLF
dc.l DisplayString
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
; 20
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
dc.l StubRout
; 30
dc.l StubRout
dc.l StubRout
dc.l rotate_iofocus
dc.l SerialPeekCharDirect
dc.l SerialPutChar
dc.l SerialPeekChar
dc.l SerialGetChar
dc.l T15LockSemaphore
dc.l T15UnlockSemaphore
dc.l StubRout
;------------------------------------------------------------------------------
; Cursor positioning / Clear screen
; - out of range settings are ignored
;
; Parameters:
; d1.w cursor position, bits 0 to 7 are row, bits 8 to 15 are column.
; Returns:
; none
;------------------------------------------------------------------------------
Cursor1:
move.l d1,-(a7)
cmpi.w #$FF00,d1
bne.s .0002
bsr clear_screen
bra HomeCursor
.0002:
cmp.b TextRows,d1 ; if cursor pos out of range, ignore setting
bhs.s .0003
move.b d1,CursorRow
.0003:
ror.w #8,d1
cmp.b TextCols,d1
bhs.s .0001
move.b d1,CursorCol
.0001:
bsr SyncCursor ; update hardware cursor
move.l (a7)+,d1
rts
;------------------------------------------------------------------------------
; Stub routine for unimplemented functionality.
;------------------------------------------------------------------------------
StubRout:
rts
;------------------------------------------------------------------------------
; Select a specific IO focus.
;------------------------------------------------------------------------------
select_iofocus:
cmpi.b #2,d1
blo.s .0001
cmpi.b #9,d1
bhi.s .0001
move.l d1,d0
bra.s select_focus1
.0001:
rts
;------------------------------------------------------------------------------
; Rotate the IO focus, done when ALT-Tab is pressed.
;
; Modifies:
; d0, IOFocus BIOS variable
;------------------------------------------------------------------------------
rotate_iofocus:
move.b IOFocus,d0 ; d0 = focus, we can trash d0
add.b #1,d0 ; increment the focus
cmp.b #9,d0 ; limit to 2 to 9
bls.s .0001
move.b #2,d0
.0001:
select_focus1:
move.b d0,IOFocus ; set IO focus
subi.b #2,d0 ; screen is 0 to 7, focus is 2 to 9
ext.w d0 ; make into long value
mulu #2048,d0 ; * 2048 cells per screen
rol.w #8,d0 ; swap byte order
move.w d0,TEXTREG+$28 ; update screen address in text controller
bra SyncCursor ; set cursor position
;==============================================================================
; PLIC - platform level interrupt controller
;
; Register layout:
; bits 0 to 7 = cause code to issue (vector number)
; bits 8 to 11 = irq level to issue
; bit 16 = irq enable
; bit 17 = edge sensitivity
; bit 18 = 0=vpa, 1=inta
; bit 24 to 29 target core
;
; Note byte order must be reversed for PLIC.
;==============================================================================
init_plic:
lea PLIC,a0 ; a0 points to PLIC
lea $80+4*29(a0),a1 ; point to timer registers (29)
move.l #$0006033F,(a1) ; initialize, core=63,edge sensitive,enabled,irq6,vpa
lea 4(a1),a1 ; point to keyboard registers (30)
move.l #$3C060502,(a1) ; core=2,level sensitive,enabled,irq6,inta
lea 4(a1),a1 ; point to nmi button register (31)
move.l #$00070302,(a1) ; initialize, core=2,edge sensitive,enabled,irq7,vpa
lea $80+4*16(a0),a1 ; a1 points to ACIA register
move.l #$3D030502,(a1) ; core=2,level sensitive,enabled,irq3,inta
lea $80+4*4(a0),a1 ; a1 points to io_bitmap irq
move.l #$3B060702,(a1) ; core=2,edge sensitive,enabled,irq6,inta
rts
;==============================================================================
; Keyboard stuff
;
; KeyState2_
; 876543210
; ||||||||+ = shift
; |||||||+- = alt
; ||||||+-- = control
; |||||+--- = numlock
; ||||+---- = capslock
; |||+----- = scrolllock
; ||+------ =
; |+------- =
; +-------- = extended
;
;==============================================================================
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Get ID - get the keyboards identifier code.
;
; Parameters: none
; Returns: d = $AB83, $00 on fail
; Modifies: d, KeybdID updated
; Stack Space: 2 words
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeybdGetID:
move.w #$F2,d1
bsr KeybdSendByte
bsr KeybdWaitTx
bsr KeybdRecvByte
btst #7,d1
bne kgnotKbd
cmpi.b #$AB,d1
bne kgnotKbd
bsr KeybdRecvByte
btst #7,d1
bne kgnotKbd
cmpi.b #$83,d1
bne kgnotKbd
move.l #$AB83,d1
kgid1:
move.w d1,KeybdID
rts
kgnotKbd:
moveq #0,d1
bra kgid1
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set the LEDs on the keyboard.
;
; Parameters:
; d1.b = LED state
; Modifies:
; none
; Returns:
; none
; Stack Space:
; 1 long word
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeybdSetLED:
move.l d1,-(a7)
move.b #$ED,d1
bsr KeybdSendByte
bsr KeybdWaitTx
bsr KeybdRecvByte
tst.b d1
bmi .0001
cmpi.b #$FA,d1
move.l (a7),d1
bsr KeybdSendByte
bsr KeybdWaitTx
bsr KeybdRecvByte
.0001:
move.l (a7)+,d1
rts
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Initialize the keyboard.
;
; Parameters:
; none
; Modifies:
; none
; Returns:
; none
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_KeybdInit:
KeybdInit:
; movem.l d0/d1/d3/a1,-(a7)
clr.b _KeyState1 ; records key up/down state
clr.b _KeyState2 ; records shift,ctrl,alt state
rts
bsr Wait300ms
bsr _KeybdGetStatus ; wait for response from keyboard
tst.b d1
bpl .0001 ; is input buffer full ? no, branch
bsr _KeybdGetScancode
cmpi.b #$AA,d1 ; keyboard Okay
beq kbdi0005
.0001:
moveq #10,d3
kbdi0002:
bsr Wait10ms
clr.b KEYBD+1 ; clear receive register (write $00 to status reg)
moveq #-1,d1 ; send reset code to keyboard
move.b d1,KEYBD+1 ; write $FF to status reg to clear TX state
bsr KeybdSendByte ; now write ($FF) to transmit register for reset
bsr KeybdWaitTx ; wait until no longer busy
tst.l d1
bmi kbdiXmitBusy
bsr KeybdRecvByte ; look for an ACK ($FA)
cmpi.b #$FA,d1
bne .0001
bsr KeybdRecvByte ; look for BAT completion code ($AA)
.0001:
cmpi.b #$FC,d1 ; reset error ?
beq kbdiTryAgain
cmpi.b #$AA,d1 ; reset complete okay ?
bne kbdiTryAgain
; After a reset, scan code set #2 should be active
.config:
move.w #$F0,d1 ; send scan code select
move.b d1,leds
bsr KeybdSendByte
bsr KeybdWaitTx
tst.l d1
bmi kbdiXmitBusy
bsr KeybdRecvByte ; wait for response from keyboard
tst.w d1
bmi kbdiTryAgain
cmpi.b #$FA,d1 ; ACK
beq kbdi0004
kbdiTryAgain:
dbra d3,kbdi0002
.keybdErr:
lea msgBadKeybd,a1
bsr DisplayStringCRLF
bra ledxit
kbdi0004:
moveq #2,d1 ; select scan code set #2
bsr KeybdSendByte
bsr KeybdWaitTx
tst.l d1
bmi kbdiXmitBusy
bsr KeybdRecvByte ; wait for response from keyboard
tst.w d1
bmi kbdiTryAgain
cmpi.b #$FA,d1
bne kbdiTryAgain
kbdi0005:
bsr KeybdGetID
ledxit:
moveq #$07,d1
bsr KeybdSetLED
bsr Wait300ms
moveq #$00,d1
bsr KeybdSetLED
movem.l (a7)+,d0/d1/d3/a1
rts
kbdiXmitBusy:
lea msgXmitBusy,a1
bsr DisplayStringCRLF
movem.l (a7)+,d0/d1/d3/a1
rts
msgBadKeybd:
dc.b "Keyboard error",0
msgXmitBusy:
dc.b "Keyboard transmitter stuck",0
even
_KeybdGetStatus:
moveq #0,d1
move.b KEYBD+1,d1
rts
; Get the scancode from the keyboard port
_KeybdGetScancode:
moveq #0,d1
move.b KEYBD,d1 ; get the scan code
move.b #0,KEYBD+1 ; clear receive register
rts
; Recieve a byte from the keyboard, used after a command is sent to the
; keyboard in order to wait for a response.
;
KeybdRecvByte:
move.l d3,-(a7)
move.w #100,d3 ; wait up to 1s
.0003:
bsr _KeybdGetStatus ; wait for response from keyboard
tst.b d1
bmi .0004 ; is input buffer full ? yes, branch
bsr Wait10ms ; wait a bit
dbra d3,.0003 ; go back and try again
move.l (a7)+,d3
moveq #-1,d1 ; return -1
rts
.0004:
bsr _KeybdGetScancode
move.l (a7)+,d3
rts
; Wait until the keyboard transmit is complete
; Returns -1 if timedout, 0 if transmit completed
;
KeybdWaitTx:
movem.l d2/d3,-(a7)
moveq #100,d3 ; wait a max of 1s
.0001:
bsr _KeybdGetStatus
btst #6,d1 ; check for transmit complete bit
bne .0002 ; branch if bit set
bsr Wait10ms ; delay a little bit
dbra d3,.0001 ; go back and try again
movem.l (a7)+,d2/d3
moveq #-1,d1 ; return -1
rts
.0002:
movem.l (a7)+,d2/d3
moveq #0,d1 ; return 0
rts
;------------------------------------------------------------------------------
; d1.b 0=echo off, non-zero = echo on
;------------------------------------------------------------------------------
SetKeyboardEcho:
move.b d1,KeybdEcho
rts
;------------------------------------------------------------------------------
; Get key pending status into d1.b
;
; Returns:
; d1.b = 1 if a key is available, otherwise zero.
;------------------------------------------------------------------------------
CheckForKey:
moveq.l #0,d1 ; clear high order bits
; move.b KEYBD+1,d1 ; get keyboard port status
; smi.b d1 ; set true/false
; andi.b #1,d1 ; return true (1) if key available, 0 otherwise
tst.b _KeybdCnt
sne.b d1
rts
;------------------------------------------------------------------------------
; GetKey
; Get a character from the keyboard.
;
; Modifies:
; d1
; Returns:
; d1 = -1 if no key available or not in focus, otherwise key
;------------------------------------------------------------------------------
GetKey:
move.l d0,-(a7) ; push d0
move.b IOFocus,d1 ; Check if the core has the IO focus
movec.l coreno,d0
cmp.b d0,d1
bne.s .0004 ; go return no key available, if not in focus
bsr KeybdGetCharNoWait ; get a character
tst.l d1 ; was a key available?
bmi.s .0004
tst.b KeybdEcho ; is keyboard echo on ?
beq.s .0003 ; no echo, just return the key
cmpi.b #CR,d1 ; convert CR keystroke into CRLF
bne.s .0005
bsr CRLF
bra.s .0003
.0005:
bsr DisplayChar
.0003:
move.l (a7)+,d0 ; pop d0
rts ; return key
; Return -1 indicating no char was available
.0004:
move.l (a7)+,d0 ; pop d0
moveq #-1,d1 ; return no key available
rts
CheckForCtrlC:
bsr KeybdGetCharNoWait
cmpi.b #CTRLC,d1
beq Monitor
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
KeybdGetCharNoWait:
clr.b KeybdWaitFlag
bra KeybdGetChar
KeybdGetCharWait:
move.b #-1,KeybdWaitFlag
KeybdGetChar:
movem.l d0/d2/d3/a0,-(a7)
.0003:
movec coreno,d0
swap d0
moveq #KEYBD_SEMA,d1
bsr LockSemaphore
move.b _KeybdCnt,d2 ; get count of buffered scan codes
beq.s .0015 ;
move.b _KeybdHead,d2 ; d2 = buffer head
ext.w d2
lea _KeybdBuf,a0 ; a0 = pointer to keyboard buffer
clr.l d1
move.b (a0,d2.w),d1 ; d1 = scan code from buffer
addi.b #1,d2 ; increment keyboard head index
andi.b #31,d2 ; and wrap around at buffer size
move.b d2,_KeybdHead
subi.b #1,_KeybdCnt ; decrement count of scan codes in buffer
exg d1,d2 ; save scancode value in d2
movec coreno,d0
swap d0
moveq #KEYBD_SEMA,d1
bsr UnlockSemaphore
exg d2,d1 ; restore scancode value
bra .0001 ; go process scan code
.0014:
bsr _KeybdGetStatus ; check keyboard status for key available
bmi .0006 ; yes, go process
.0015:
movec coreno,d0
swap d0
moveq #KEYBD_SEMA,d1
bsr UnlockSemaphore
tst.b KeybdWaitFlag ; are we willing to wait for a key ?
bmi .0003 ; yes, branch back
movem.l (a7)+,d0/d2/d3/a0
moveq #-1,d1 ; flag no char available
rts
.0006:
bsr _KeybdGetScancode
.0001:
move.w #1,leds
cmp.b #SC_KEYUP,d1
beq .doKeyup
cmp.b #SC_EXTEND,d1
beq .doExtend
cmp.b #SC_CTRL,d1
beq .doCtrl
cmp.b #SC_LSHIFT,d1
beq .doShift
cmp.b #SC_RSHIFT,d1
beq .doShift
cmp.b #SC_NUMLOCK,d1
beq .doNumLock
cmp.b #SC_CAPSLOCK,d1
beq .doCapsLock
cmp.b #SC_SCROLLLOCK,d1
beq .doScrollLock
cmp.b #SC_ALT,d1
beq .doAlt
move.b _KeyState1,d2 ; check key up/down
move.b #0,_KeyState1 ; clear keyup status
tst.b d2
bne .0003 ; ignore key up
cmp.b #SC_TAB,d1
beq .doTab
.0013:
move.b _KeyState2,d2
bpl .0010 ; is it extended code ?
and.b #$7F,d2 ; clear extended bit
move.b d2,_KeyState2
move.b #0,_KeyState1 ; clear keyup
lea _keybdExtendedCodes,a0
move.b (a0,d1.w),d1
bra .0008
.0010:
btst #2,d2 ; is it CTRL code ?
beq .0009
and.w #$7F,d1
lea _keybdControlCodes,a0
move.b (a0,d1.w),d1
bra .0008
.0009:
btst #0,d2 ; is it shift down ?
beq .0007
lea _shiftedScanCodes,a0
move.b (a0,d1.w),d1
bra .0008
.0007:
lea _unshiftedScanCodes,a0
move.b (a0,d1.w),d1
move.w #$0202,leds
.0008:
move.w #$0303,leds
movem.l (a7)+,d0/d2/d3/a0
rts
.doKeyup:
move.b #-1,_KeyState1
bra .0003
.doExtend:
or.b #$80,_KeyState2
bra .0003
.doCtrl:
move.b _KeyState1,d1
clr.b _KeyState1
tst.b d1
bpl.s .0004
bclr #2,_KeyState2
bra .0003
.0004:
bset #2,_KeyState2
bra .0003
.doAlt:
move.b _KeyState1,d1
clr.b _KeyState1
tst.b d1
bpl .0011
bclr #1,_KeyState2
bra .0003
.0011:
bset #1,_KeyState2
bra .0003
.doTab:
move.l d1,-(a7)
move.b _KeyState2,d1
btst #1,d1 ; is ALT down ?
beq .0012
; inc _iof_switch
move.l (a7)+,d1
bra .0003
.0012:
move.l (a7)+,d1
bra .0013
.doShift:
move.b _KeyState1,d1
clr.b _KeyState1
tst.b d1
bpl.s .0005
bclr #0,_KeyState2
bra .0003
.0005:
bset #0,_KeyState2
bra .0003
.doNumLock:
bchg #4,_KeyState2
bsr KeybdSetLEDStatus
bra .0003
.doCapsLock:
bchg #5,_KeyState2
bsr KeybdSetLEDStatus
bra .0003
.doScrollLock:
bchg #6,_KeyState2
bsr KeybdSetLEDStatus
bra .0003
KeybdSetLEDStatus:
movem.l d2/d3,-(a7)
clr.b KeybdLEDs
btst #4,_KeyState2
beq.s .0002
move.b #2,KeybdLEDs
.0002:
btst #5,_KeyState2
beq.s .0003
bset #2,KeybdLEDs
.0003:
btst #6,_KeyState2
beq.s .0004
bset #0,KeybdLEDs
.0004:
move.b KeybdLEDs,d1
bsr KeybdSetLED
movem.l (a7)+,d2/d3
rts
KeybdSendByte:
move.b d1,KEYBD
rts
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Wait for 10 ms
;
; Parameters: none
; Returns: none
; Modifies: none
; Stack Space: 2 long words
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Wait10ms:
movem.l d0/d1,-(a7)
movec tick,d0
addi.l #400000,d0 ; 400,000 cycles at 40MHz
.0001:
movec tick,d1
cmp.l d1,d0
bhi .0001
movem.l (a7)+,d0/d1
rts
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Wait for 300 ms
;
; Parameters: none
; Returns: none
; Modifies: none
; Stack Space: 2 long words
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Wait300ms:
movem.l d0/d1,-(a7)
movec tick,d0
addi.l #12000000,d0 ; 12,000,000 cycles at 40MHz
.0001:
movec tick,d1
cmp.l d1,d0
bhi .0001
movem.l (a7)+,d0/d1
rts
;--------------------------------------------------------------------------
; Keyboard IRQ routine.
;
; Returns:
; d1 = -1 if keyboard routine handled interrupt, otherwise positive.
;--------------------------------------------------------------------------
KeybdIRQ:
move.w #$2600,sr ; disable lower interrupts
movem.l d0/d1/a0,-(a7)
bsr _KeybdGetStatus ; check if keyboard
tst.b d1
bpl .0001 ; branch if not keyboard
movec coreno,d0
swap d0
moveq #KEYBD_SEMA,d1
bsr LockSemaphore
btst #1,_KeyState2 ; Is Alt down?
beq.s .0003
move.b KEYBD,d0 ; get scan code
cmpi.b #SC_TAB,d0 ; is Alt-Tab?
bne.s .0003
bsr _KeybdGetScancode ; grab the scan code (clears interrupt)
bsr rotate_iofocus
clr.b _KeybdHead ; clear keyboard buffer
clr.b _KeybdTail
clr.b _KeybdCnt
bra .0002 ; do not store Alt-Tab
.0003:
; Insert keyboard scan code into raw keyboard buffer
bsr _KeybdGetScancode ; grab the scan code (clears interrupt)
cmpi.b #32,_KeybdCnt ; see if keyboard buffer full
bhs.s .0002
move.b _KeybdTail,d0 ; keyboard buffer not full, add to tail
ext.w d0
lea _KeybdBuf,a0 ; a0 = pointer to buffer
move.b d1,(a0,d0.w) ; put scancode in buffer
addi.b #1,d0 ; increment tail index
andi.b #31,d0 ; wrap at buffer limit
move.b d0,_KeybdTail ; update tail index
addi.b #1,_KeybdCnt ; increment buffer count
.0002:
movec coreno,d0
swap d0
moveq #KEYBD_SEMA,d1
bsr UnlockSemaphore
.0001:
movem.l (a7)+,d0/d1/a0 ; return
rte
;--------------------------------------------------------------------------
; PS2 scan codes to ascii conversion tables.
;--------------------------------------------------------------------------
;
_unshiftedScanCodes:
dc.b $2e,$a9,$2e,$a5,$a3,$a1,$a2,$ac
dc.b $2e,$aa,$a8,$a6,$a4,$09,$60,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$71,$31,$2e
dc.b $2e,$2e,$7a,$73,$61,$77,$32,$2e
dc.b $2e,$63,$78,$64,$65,$34,$33,$2e
dc.b $2e,$20,$76,$66,$74,$72,$35,$2e
dc.b $2e,$6e,$62,$68,$67,$79,$36,$2e
dc.b $2e,$2e,$6d,$6a,$75,$37,$38,$2e
dc.b $2e,$2c,$6b,$69,$6f,$30,$39,$2e
dc.b $2e,$2e,$2f,$6c,$3b,$70,$2d,$2e
dc.b $2e,$2e,$27,$2e,$5b,$3d,$2e,$2e
dc.b $ad,$2e,$0d,$5d,$2e,$5c,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$08,$2e
dc.b $2e,$95,$2e,$93,$94,$2e,$2e,$2e
dc.b $98,$7f,$92,$2e,$91,$90,$1b,$af
dc.b $ab,$2e,$97,$2e,$2e,$96,$ae,$2e
dc.b $2e,$2e,$2e,$a7,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$fa,$2e,$2e,$2e,$2e,$2e
_shiftedScanCodes:
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$09,$7e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$51,$21,$2e
dc.b $2e,$2e,$5a,$53,$41,$57,$40,$2e
dc.b $2e,$43,$58,$44,$45,$24,$23,$2e
dc.b $2e,$20,$56,$46,$54,$52,$25,$2e
dc.b $2e,$4e,$42,$48,$47,$59,$5e,$2e
dc.b $2e,$2e,$4d,$4a,$55,$26,$2a,$2e
dc.b $2e,$3c,$4b,$49,$4f,$29,$28,$2e
dc.b $2e,$3e,$3f,$4c,$3a,$50,$5f,$2e
dc.b $2e,$2e,$22,$2e,$7b,$2b,$2e,$2e
dc.b $2e,$2e,$0d,$7d,$2e,$7c,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$08,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$7f,$2e,$2e,$2e,$2e,$1b,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
; control
_keybdControlCodes:
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$09,$7e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$11,$21,$2e
dc.b $2e,$2e,$1a,$13,$01,$17,$40,$2e
dc.b $2e,$03,$18,$04,$05,$24,$23,$2e
dc.b $2e,$20,$16,$06,$14,$12,$25,$2e
dc.b $2e,$0e,$02,$08,$07,$19,$5e,$2e
dc.b $2e,$2e,$0d,$0a,$15,$26,$2a,$2e
dc.b $2e,$3c,$0b,$09,$0f,$29,$28,$2e
dc.b $2e,$3e,$3f,$0c,$3a,$10,$5f,$2e
dc.b $2e,$2e,$22,$2e,$7b,$2b,$2e,$2e
dc.b $2e,$2e,$0d,$7d,$2e,$7c,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$08,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$7f,$2e,$2e,$2e,$2e,$1b,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
_keybdExtendedCodes:
dc.b $2e,$2e,$2e,$2e,$a3,$a1,$a2,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$2e,$2e,$2e,$2e,$2e,$2e,$2e
dc.b $2e,$95,$2e,$93,$94,$2e,$2e,$2e
dc.b $98,$99,$92,$2e,$91,$90,$2e,$2e
dc.b $2e,$2e,$97,$2e,$2e,$96,$2e,$2e
;==============================================================================
;==============================================================================
; Monitor
;==============================================================================
;==============================================================================
cmdString:
dc.b '?'+$80 ; ? display help
dc.b 'L'+$80 ; L load S19 file
dc.b 'F','B'+$80 ; FB fill with byte
dc.b 'F','W'+$80 ; FW fill with wyde
dc.b 'F','L'+$80 ; FL fill with long wyde
dc.b 'B','A'+$80 ; BA start Tiny Basic
dc.b 'B','R'+$80 ; BR breakpoint
dc.b 'D','R'+$80 ; DR dump registers
dc.b 'D'+$80 ; D dump memory
dc.b 'J'+$80 ; J jump to code
dc.b ':'+$80 ; : edit memory
dc.b "CL",'S'+$80 ; CLS clear screen
dc.b "COR",'E'+$80 ; CORE <n> switch to core
dc.b "TRA",'M'+$80 ; TRAM test RAM
dc.b 'T','R'+$80 ; TR test serial receive
dc.b 'T'+$80 ; T test CPU
dc.b 'S'+$80 ; S send serial
dc.b "RESE",'T'+$80 ; RESET <n>
dc.b "CLOC",'K'+$80 ; CLOCK <n>
dc.b 'R'+$80 ; R receive serial
align 2
cmdTable:
dc.w cmdHelp
dc.w cmdLoadS19
dc.w cmdFillB
dc.w cmdFillW
dc.w cmdFillL
dc.w cmdTinyBasic
dc.w cmdBreakpoint
dc.w cmdDumpRegs
dc.w cmdDumpMemory
dc.w cmdJump
dc.w cmdEditMemory
dc.w cmdClearScreen
dc.w cmdCore
dc.w cmdTestRAM
dc.w cmdTestSerialReceive
dc.w cmdTestCPU
dc.w cmdSendSerial
dc.w cmdReset
dc.w cmdClock
dc.w cmdReceiveSerial
dc.w cmdMonitor
; Get a word from screen memory and swap byte order
FromScreen:
move.l (a0),d1
bsr rbo
lea 8(a0),a0 ; increment screen pointer
rts
StartMon:
clr.w NumSetBreakpoints
bsr ClearBreakpointList
cmdMonitor:
Monitor:
; Reset the stack pointer on each entry into the monitor
move.l #$40FFC,sp ; reset core's stack
move.w #$2200,sr ; enable level 2 and higher interrupts
movec coreno,d0
swap d0
moveq #1,d1
bsr UnlockSemaphore
clr.b KeybdEcho ; turn off keyboard echo
PromptLn:
bsr CRLF
move.b #'$',d1
bsr DisplayChar
; Get characters until a CR is keyed
;
Prompt3:
bsr GetKey
cmpi.b #-1,d1
beq.s Prompt3
cmpi.b #CR,d1
beq.s Prompt1
bsr DisplayChar
bra.s Prompt3
; Process the screen line that the CR was keyed on
Prompt1:
clr.b CursorCol ; go back to the start of the line
bsr CalcScreenLoc ; a0 = screen memory location
.0001:
bsr FromScreen ; grab character off screen
cmpi.b #'$',d1 ; skip over '$' prompt character
beq.s .0001
; Dispatch based on command string
cmdDispatch:
lea cmdString,a2
clr.l d4 ; command counter
lea -8(a0),a0 ; backup a character
move.l a0,a3 ; a3 = start of command on screen
.checkNextCmd:
bsr FromScreen ; d1 = char from input screen
move.b (a2)+,d5
eor.b d5,d1 ; does it match with command string?
beq.s .checkNextCmd ; If it does, keep matching for longest match
cmpi.b #$80,d1 ; didn't match, was it the end of the command?
beq.s .foundCmd
tst.b -1(a2) ; was end of table hit?
beq.s .endOfTable
addi.w #2,d4 ; increment command counter
move.l a3,a0 ; reset input pointer
tst.b -1(a2) ; were we at the end of the command?
bmi.s .checkNextCmd ; if were at end continue, otherwise scan for enf of cmd
.scanToEndOfCmd
tst.b (a2)+ ; scan to end of command
beq.s .endOfTable
bpl.s .scanToEndOfCmd
bmi.s .checkNextCmd
.endOfTable
lea msgUnknownCmd,a1
bsr DisplayStringCRLF
bra Monitor
.foundCmd:
lea cmdTable,a1 ; a1 = pointer to command address table
move.w (a1,d4.w),a1 ; fetch command routine address from table
jmp (a1) ; go execute command
cmdBreakpoint:
bsr ignBlanks
bsr FromScreen
cmpi.b #'+',d1
beq ArmBreakpoint
cmpi.b #'-',d1
beq DisarmBreakpoint
cmpi.b #'L',d1
beq ListBreakpoints
bra Monitor
cmdTinyBasic:
bra CSTART
cmdTestCPU:
bsr cpu_test
lea msg_test_done,a1
bsr DisplayStringCRLF
bra Monitor
cmdClearScreen:
bsr ClearScreen
bsr HomeCursor
bra Monitor
cmdCore:
bsr ignBlanks
bsr FromScreen
cmpi.b #'2',d1 ; check range
blo Monitor
cmpi.b #'9',d1
bhi Monitor
subi.b #'0',d1 ; convert ascii to binary
bsr select_iofocus
bra Monitor
;-------------------------------------------------------------------------------
; CLOCK <n>
; Set the clock register to n which will turn off or on clocks to the CPUs.
;-------------------------------------------------------------------------------
cmdClock:
bsr ignBlanks
bsr GetHexNumber
tst.b d0 ; was there a number?
beq Monitor
ori.w #4,d0 ; primary core's clock cannot be turned off
rol.w #8,d1 ; switch byte order
move.w d1,RST_REG+2
bra Monitor
;-------------------------------------------------------------------------------
; RESET <n>
; Reset the specified core. Resetting the core automatically turns on the
; core's clock.
;-------------------------------------------------------------------------------
cmdReset:
bsr ignBlanks
bsr FromScreen
cmpi.b #'2',d1 ; check range
blo Monitor
cmpi.b #'9',d1
bhi Monitor
subi.b #'0',d1 ; convert ascii to binary
lsl.w #1,d1 ; make into index
lea tblPow2,a1
move.w (a1,d1.w),d1
rol.w #8,d1 ; reverse byte order
move.w d1,RST_REG
bra Monitor
tblPow2:
dc.w 1
dc.w 2
dc.w 4
dc.w 8
dc.w 16
dc.w 32
dc.w 64
dc.w 128
dc.w 256
dc.w 512
dc.w 1024
dc.w 2048
dc.w 4096
dc.w 8192
dc.w 16384
dc.w 32768
even
cmdHelp:
DisplayHelp:
lea HelpMsg,a1
bsr DisplayString
bra Monitor
HelpMsg:
dc.b "? = Display help",LF,CR
dc.b "CORE n = switch to core n, n = 2 to 7",LF,CR
dc.b "RESET n = reset core n",LF,CR
dc.b "CLS = clear screen",LF,CR
dc.b ": = Edit memory bytes",LF,CR
dc.b "FB = Fill memory bytes, FW, FL",LF,CR
dc.b "L = Load S19 file",LF,CR
dc.b "D = Dump memory, DR = dump registers",LF,CR
dc.b "BA = start tiny basic",LF,CR
dc.b "BR = set breakpoint",LF,CR
dc.b "J = Jump to code",LF,CR
dc.b "S = send to serial port",LF,CR
dc.b "T = cpu test program",LF,CR
dc.b "TRAM = test RAM",LF,CR,0
msgUnknownCmd:
dc.b "command unknown",0
msgHello:
dc.b LF,CR,"Hello World!",LF,CR,0
even
;------------------------------------------------------------------------------
; This routine borrowed from Gordo's Tiny Basic interpreter.
; Used to fetch a command line. (Not currently used).
;
; d0.b - command prompt
;------------------------------------------------------------------------------
GetCmdLine:
bsr DisplayChar ; display prompt
move.b #' ',d0
bsr DisplayChar
lea CmdBuf,a0
.0001:
bsr GetKey
cmp.b #CTRLH,d0
beq.s .0003
cmp.b #CTRLX,d0
beq.s .0004
cmp.b #CR,d0
beq.s .0002
cmp.b #' ',d0
bcs.s .0001
.0002:
move.b d0,(a0)
lea 8(a0),a0
bsr DisplayChar
cmp.b #CR,d0
beq .0007
cmp.l #CmdBufEnd-1,a0
bcs.s .0001
.0003:
move.b #CTRLH,d0
bsr DisplayChar
move.b #' ',d0
bsr DisplayChar
cmp.l #CmdBuf,a0
bls.s .0001
move.b #CTRLH,d0
bsr DisplayChar
subq.l #1,a0
bra.s .0001
.0004:
move.l a0,d1
sub.l #CmdBuf,d1
beq.s .0006
subq #1,d1
.0005:
move.b #CTRLH,d0
bsr DisplayChar
move.b #' ',d0
bsr DisplayChar
move.b #CTRLH,d0
bsr DisplayChar
dbra d1,.0005
.0006:
lea CmdBuf,a0
bra .0001
.0007:
move.b #LF,d0
bsr DisplayChar
rts
;------------------------------------------------------------------------------
; S <address> <length>
; Send data buffer to serial port
; S 40000 40
;------------------------------------------------------------------------------
cmdSendSerial:
bsr ignBlanks
bsr GetHexNumber
beq Monitor
move.l d1,d6 ; d6 points to buffer
bsr ignBlanks
bsr GetHexNumber
bne.s .0003
moveq #16,d1
.0003:
move.l d6,a1 ; a1 points to buffer
move.l d1,d2 ; d2 = count of bytes to send
bra.s .0002 ; enter loop at bottom
.0001:
move.b (a1)+,d1
move.w #34,d0 ; serial putchar
trap #15
.0002:
dbra d2,.0001
bra Monitor
;------------------------------------------------------------------------------
; R <address> <length>
; Send data buffer to serial port
; R 10000 40
;------------------------------------------------------------------------------
cmdReceiveSerial:
bsr ignBlanks
bsr GetHexNumber
beq Monitor
move.l d1,d6 ; d6 points to buffer
bsr ignBlanks
bsr GetHexNumber
bne.s .0003
moveq #16,d1
.0003:
move.l d6,a1 ; a1 points to buffer
move.l d1,d2 ; d2 = count of bytes to send
bra.s .0002 ; enter loop at bottom
.0001:
move.w #36,d0 ; serial peek char
trap #15
tst.l d1
bmi.s .0001
move.b d1,(a1)+
.0002:
dbra d2,.0001
bra Monitor
;------------------------------------------------------------------------------
; Fill memory
;
; FB = fill bytes FB 00000010 100 FF ; fill starting at 10 for 256 bytes
; FW = fill words
; FL = fill longs
; F = fill bytes
;------------------------------------------------------------------------------
cmdFillB:
bsr ignBlanks
bsr GetHexNumber
move.l d1,a1 ; a1 = start
bsr ignBlanks
bsr GetHexNumber
move.l d1,d3 ; d3 = count
beq Monitor
bsr ignBlanks
bsr GetHexNumber ; fill value
.fmem:
move.b d1,(a1)+
sub.l #1,d3
bne.s .fmem
bra Monitor
cmdFillW:
bsr ignBlanks
bsr GetHexNumber
move.l d1,a1 ; a1 = start
bsr ignBlanks
bsr GetHexNumber
move.l d1,d3 ; d3 = count
beq Monitor
bsr ignBlanks
bsr GetHexNumber ; fill value
.fmem:
move.w d1,(a1)+
sub.l #1,d3
bne.s .fmem
bra Monitor
cmdFillL:
bsr ignBlanks
bsr GetHexNumber
move.l d1,a1 ; a1 = start
bsr ignBlanks
bsr GetHexNumber
move.l d1,d3 ; d3 = count
beq Monitor
bsr ignBlanks
bsr GetHexNumber ; fill value
.fmem:
move.l d1,(a1)+
sub.l #1,d3
bne.s .fmem
bra Monitor
;------------------------------------------------------------------------------
; Modifies:
; a0 - text pointer
;------------------------------------------------------------------------------
ignBlanks:
move.l d1,-(a7)
.0001:
bsr FromScreen
cmpi.b #' ',d1
beq.s .0001
lea -8(a0),a0
move.l (a7)+,d1
rts
;------------------------------------------------------------------------------
; Edit memory byte.
; Bytes are built into long words in case the memory is only longword
; accessible.
;------------------------------------------------------------------------------
cmdEditMemory:
bsr ignBlanks
bsr GetHexNumber
move.l d1,a1
edtmem1:
clr.l d2
bsr ignBlanks
bsr GetHexNumber
move.b d1,d2
; move.b d1,(a1)+
bsr ignBlanks
bsr GetHexNumber
lsl.l #8,d2
move.b d1,d2
; move.b d1,(a1)+
bsr ignBlanks
bsr GetHexNumber
lsl.l #8,d2
move.b d1,d2
; move.b d1,(a1)+
bsr ignBlanks
bsr GetHexNumber
lsl.l #8,d2
move.b d1,d2
move.l d2,(a1)+
; move.b d1,(a1)+
clr.l d2
bsr ignBlanks
bsr GetHexNumber
move.b d1,d2
; move.b d1,(a1)+
bsr ignBlanks
bsr GetHexNumber
lsl.l #8,d2
move.b d1,d2
; move.b d1,(a1)+
bsr ignBlanks
bsr GetHexNumber
lsl.l #8,d2
move.b d1,d2
; move.b d1,(a1)+
bsr ignBlanks
bsr GetHexNumber
lsl.l #8,d2
move.b d1,d2
; move.b d1,(a1)+
move.l d2,(a1)+
bra Monitor
;------------------------------------------------------------------------------
; Execute code at the specified address.
;------------------------------------------------------------------------------
cmdJump:
ExecuteCode:
bsr ignBlanks
bsr GetHexNumber
move.l d1,a0
jsr (a0)
bra Monitor
;------------------------------------------------------------------------------
; Do a memory dump of the requested location.
; D 0800 0850
;------------------------------------------------------------------------------
cmdDumpMemory:
bsr ignBlanks
bsr GetHexNumber
beq Monitor ; was there a number ? no, other garbage, just ignore
move.l d1,d3 ; save off start of range
bsr ignBlanks
bsr GetHexNumber
bne.s DumpMem1
move.l d3,d1
addi.l #64,d1 ; no end specified, just dump 64 bytes
DumpMem1:
move.l d3,a0
move.l d1,a1
bsr CRLF
.0001:
cmpa.l a0,a1
bls Monitor
bsr DisplayMem
bra.s .0001
;------------------------------------------------------------------------------
; Display memory dump in a format suitable for edit.
;
; :12345678 00 11 22 33 44 55 66 77 "........"
;
; Modifies:
; d1,d2,a0
;------------------------------------------------------------------------------
DisplayMem:
move.b #':',d1
bsr DisplayChar
move.l a0,d1
bsr DisplayTetra
moveq #7,d2
dspmem1:
move.b #' ',d1
bsr DisplayChar
move.b (a0)+,d1
bsr DisplayByte
dbra d2,dspmem1
bsr DisplayTwoSpaces
move.b #34,d1
bsr DisplayChar
lea -8(a0),a0
moveq #7,d2
.0002:
move.b (a0)+,d1
cmp.b #' ',d1
blo.s .0003
cmp.b #127,d1
bls.s .0001
.0003:
move.b #'.',d1
.0001:
bsr DisplayChar
dbra d2,.0002
move.b #34,d1
bsr DisplayChar
bsr CheckForCtrlC
bra CRLF
;------------------------------------------------------------------------------
; Dump Registers
; The dump is in a format that allows the register value to be edited.
;
; RegD0 12345678
; RegD1 77777777
; ... etc
;------------------------------------------------------------------------------
cmdDumpRegs:
bsr CRLF
move.w #15,d0 ; number of registers-1
lea msg_reglist,a0 ;
lea msg_regs,a1
lea Regsave,a2 ; a2 points to register save area
.0001:
bsr DisplayString
move.b (a0)+,d1
bsr DisplayChar
move.b (a0)+,d1
bsr DisplayChar
bsr DisplaySpace
move.l (a2)+,d1
bsr DisplayTetra
bsr CRLF
dbra d0,.0001
bsr DisplayString
move.b (a0)+,d1
bsr DisplayChar
move.b (a0)+,d1
bsr DisplayChar
bsr DisplaySpace
move.l Regsave+$44,d1
bsr DisplayTetra
bsr CRLF
bsr DisplayString
move.b (a0)+,d1
bsr DisplayChar
move.b (a0)+,d1
bsr DisplayChar
bsr DisplaySpace
move.w Regsave+$40,d1
bsr DisplayWyde
bsr CRLF
bra Monitor
msg_regs:
dc.b "Reg",0
msg_reglist:
dc.b "D0D1D2D3D4D5D6D7A0A1A2A3A4A5A6A7PCSR",0
align 1
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
cmdTestSerialReceive:
.0002:
moveq #36,d0 ; serial get char from buffer
trap #15
; bsr SerialPeekCharDirect
tst.w d1
bmi.s .0001
cmpi.b #CTRLZ,d1
beq .0003
bsr DisplayChar
.0001:
bsr CheckForCtrlC
bra .0002
.0003:
bsr _KeybdInit
bra Monitor
;------------------------------------------------------------------------------
; Get a hexidecimal number. Maximum of eight digits.
;
; Returns:
; d0 = number of digits
; d1 = value of number
; zf = number of digits == 0
;------------------------------------------------------------------------------
GetHexNumber:
move.l d2,-(a7)
clr.l d2
moveq #0,d0
.0002:
bsr FromScreen
bsr AsciiToHexNybble
cmp.b #$ff,d1
beq.s .0001
lsl.l #4,d2
andi.l #$0f,d1
or.l d1,d2
addq #1,d0
cmpi.b #8,d0
blo.s .0002
.0001:
move.l d2,d1
move.l (a7)+,d2
tst.b d0
rts
;------------------------------------------------------------------------------
; Convert ASCII character in the range '0' to '9', 'a' tr 'f' or 'A' to 'F'
; to a hex nybble.
;------------------------------------------------------------------------------
AsciiToHexNybble:
cmpi.b #'0',d1
blo.s gthx3
cmpi.b #'9',d1
bhi.s gthx5
subi.b #'0',d1
rts
gthx5:
cmpi.b #'A',d1
blo.s gthx3
cmpi.b #'F',d1
bhi.s gthx6
addi.b #10-'A',d1
rts
gthx6:
cmpi.b #'a',d1
blo.s gthx3
cmpi.b #'f',d1
bhi.s gthx3
addi.b #10-'a',d1
rts
gthx3:
moveq #-1,d1 ; not a hex number
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
DisplayTwoSpaces:
move.l d1,-(a7)
move.b #' ',d1
bsr DisplayChar
dspspc1:
bsr DisplayChar
move.l (a7)+,d1
rts
DisplaySpace:
move.l d1,-(a7)
move.b #' ',d1
bra dspspc1
;------------------------------------------------------------------------------
; Display the 32 bit word in D1.L
;------------------------------------------------------------------------------
DisplayTetra:
swap d1
bsr DisplayWyde
swap d1
;------------------------------------------------------------------------------
; Display the byte in D1.W
;------------------------------------------------------------------------------
DisplayWyde:
ror.w #8,d1
bsr DisplayByte
rol.w #8,d1
;------------------------------------------------------------------------------
; Display the byte in D1.B
;------------------------------------------------------------------------------
DisplayByte:
ror.b #4,d1
bsr DisplayNybble
rol.b #4,d1
;------------------------------------------------------------------------------
; Display nybble in D1.B
;------------------------------------------------------------------------------
DisplayNybble:
move.l d1,-(a7)
andi.b #$F,d1
addi.b #'0',d1
cmpi.b #'9',d1
bls.s .0001
addi.b #7,d1
.0001:
bsr DisplayChar
move.l (a7)+,d1
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
;DisplayHexNumber:
; move.w #$A6A6,leds ; diagnostics
; move.l #VDGREG,a6
; move.w #7,d2 ; number-1 of digits to display
;disphnum1:
; move.b d1,d0 ; get digit into d0.b
; andi.w #$0f,d0
; cmpi.w #$09,d0
; bls.s disphnum2
; addi.w #7,d0
;disphnum2:
; addi.w #$30,d0 ; convert to display char
; move.w d2,d3 ; char count into d3
; asl.w #3,d3 ; scale * 8
;disphnum3:
; move.w $42C(a6),d4 ; read character queue index into d4
; cmp.w #28,d4 ; allow up 28 entries to be in progress
; bhs.s disphnum3 ; branch if too many chars queued
; ext.w d0 ; zero out high order bits
; move.w d0,$420(a6) ; set char code
; move.w #WHITE,$422(a6) ; set fg color
; move.w #DARK_BLUE,$424(a6) ; set bk color
; move.w d3,$426(a6) ; set x pos
; move.w #8,$428(a6) ; set y pos
; move.w #$0707,$42A(a6) ; set font x,y extent
; move.w #0,$42E(a6) ; pulse character queue write signal
; ror.l #4,d1 ; rot to next digit
; dbeq d2,disphnum1
; jmp (a5)
;===============================================================================
; Perform ram test. (Uses checkerboard testing).
;
; Local ram, which does not get tested, is used for the stack.
;===============================================================================
DisplayAddr:
move.l a0,d1
lsr.l #8,d1
lsr.l #8,d1
lsr.l #4,d1
subi.w #512,d1
bin2bcd d1
bsr DisplayWyde
move.b #CR,d1
bra DisplayChar
btst #$83,d0
cmdTestRAM:
ramtest:
move.w #$A5A5,leds ; diagnostics
move.l #$aaaaaaaa,d3
move.l #$55555555,d4
bsr ramtest0
; switch checkerboard pattern and repeat test.
exg d3,d4
bsr ramtest0
; Save last ram address in end of memory pointer.
rmtst5:
moveq #37,d0 ; lock semaphore
moveq #MEMORY_SEMA,d1
trap #15
move.l a0,memend
; Create very first memory block.
suba.l #12,a0
move.l a0,$20000004 ; length of block
move.l #$46524545,$20000000
moveq #38,d0 ; unlock semaphore
moveq #MEMORY_SEMA,d1
trap #15
rts
ramtest0:
move.l d3,d0
movea.l #$20000000,a0
;-----------------------------------------------------------
; Write checkerboard pattern to ram then read it back to
; find the highest usable ram address (maybe). This address
; must be lower than the start of the rom (0xe00000).
;-----------------------------------------------------------
ramtest1:
move.l d3,(a0)+
move.l d4,(a0)+
move.l a0,d1
tst.w d1
bne.s rmtst1
bsr DisplayAddr
bsr CheckForCtrlC
rmtst1:
cmpa.l #$3FFFFFF8,a0
blo.s ramtest1
bsr CRLF
;------------------------------------------------------
; Save maximum useable address for later comparison.
;------------------------------------------------------
ramtest6:
move.w #$A7A7,leds ; diagnostics
movea.l a0,a2
movea.l #$20000000,a0
;--------------------------------------------
; Read back checkerboard pattern from ram.
;--------------------------------------------
ramtest2
move.l (a0)+,d5
move.l (a0)+,d6
cmpa.l a2,a0
bhs.s ramtest3
move.l a0,d1
tst.w d1
bne.s rmtst2
bsr DisplayAddr
bsr CheckForCtrlC
rmtst2
cmp.l d3,d5
bne.s rmtst3
cmp.l d4,d6
beq.s ramtest2
;----------------------------------
; Report error in ram.
;----------------------------------
rmtst3
bsr CRLF
moveq #'E',d1
bsr DisplayChar
bsr DisplaySpace
move.l a0,d1
bsr DisplayTetra
bsr DisplaySpace
move.l d5,d1
bsr DisplayTetra
bsr CheckForCtrlC
bra ramtest2
ramtest3
rts
;==============================================================================
; Load an S19 format file
;==============================================================================
cmdLoadS19:
bsr CRLF
bra ProcessRec
NextRec:
bsr sGetChar
cmpi.b #LF,d1
bne NextRec
move.b #'.',d1
bsr DisplayChar
ProcessRec:
bsr CheckForCtrlC ; check for CTRL-C once per record
bsr sGetChar
cmpi.b #CR,d1
beq.s ProcessRec
clr.b S19Checksum
move.b d1,d4
cmpi.b #CTRLZ,d4 ; CTRL-Z ?
beq Monitor
cmpi.b #'S',d4 ; All records must begin with an 'S'
bne.s NextRec
bsr sGetChar
move.b d1,d4
cmpi.b #'0',d4 ; Record type must be between '0' and '9'
blo.s NextRec
cmpi.b #'9',d4 ; d4 = record type
bhi.s NextRec
bsr sGetChar ; get byte count for record
bsr AsciiToHexNybble
move.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.b #4,d2
or.b d2,d1 ; d1 = byte count
move.b d1,d3 ; d3 = byte count
add.b d3,S19Checksum
cmpi.b #'0',d4 ; manufacturer ID record, ignore
beq NextRec
cmpi.b #'1',d4
beq ProcessS1
cmpi.b #'2',d4
beq ProcessS2
cmpi.b #'3',d4
beq ProcessS3
cmpi.b #'5',d4 ; record count record, ignore
beq NextRec
cmpi.b #'7',d4
beq ProcessS7
cmpi.b #'8',d4
beq ProcessS8
cmpi.b #'9',d4
beq ProcessS9
bra NextRec
pcssxa:
move.l a1,d1
bsr DisplayTetra
move.b #CR,d1
bsr DisplayChar
andi.w #$ff,d3
subi.w #1,d3 ; one less for dbra
.0001:
clr.l d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
add.b d2,S19Checksum
move.b d2,(a1)+ ; move byte to memory
dbra d3,.0001
; Get the checksum byte
clr.l d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
eor.b #$FF,d2
cmp.b S19Checksum,d2
beq NextRec
move.b #'E',d1
bsr DisplayChar
bra NextRec
ProcessS1:
bsr S19Get16BitAddress
bra pcssxa
ProcessS2:
bsr S19Get24BitAddress
bra pcssxa
ProcessS3:
bsr S19Get32BitAddress
bra pcssxa
ProcessS7:
bsr S19Get32BitAddress
move.l a1,S19StartAddress
bsr _KeybdInit
bra Monitor
ProcessS8:
bsr S19Get24BitAddress
move.l a1,S19StartAddress
bsr _KeybdInit
bra Monitor
ProcessS9:
bsr S19Get16BitAddress
move.l a1,S19StartAddress
bsr _KeybdInit
bra Monitor
S19Get16BitAddress:
clr.l d2
bsr sGetChar
bsr AsciiToHexNybble
move.b d1,d2
bra S1932b
S19Get24BitAddress:
clr.l d2
bsr sGetChar
bsr AsciiToHexNybble
move.b d1,d2
bra S1932a
S19Get32BitAddress:
clr.l d2
bsr sGetChar
bsr AsciiToHexNybble
move.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
S1932a:
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
S1932b:
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
bsr sGetChar
bsr AsciiToHexNybble
lsl.l #4,d2
or.b d1,d2
clr.l d4
move.l d2,a1
; Add bytes from address value to checksum
add.b d2,S19Checksum
lsr.l #8,d2
add.b d2,S19Checksum
lsr.l #8,d2
add.b d2,S19Checksum
lsr.l #8,d2
add.b d2,S19Checksum
rts
;------------------------------------------------------------------------------
; Get a character from auxillary input. Waiting for a character is limited to
; 32000 tries. If a character is not available within the limit, then a return
; to the monitor is done.
;
; Parameters:
; none
; Returns:
; d1 = character from receive buffer or -1 if no char available
;------------------------------------------------------------------------------
sGetChar:
movem.l d0/d2,-(a7)
move.w #32000,d2
.0001:
moveq #36,d0 ; serial get char from buffer
trap #15
tst.w d1 ; was there a char available?
bpl.s .0002
dbra d2,.0001 ; no - try again
movem.l (a7)+,d0/d2
.0003:
bsr _KeybdInit
bra Monitor ; ran out of tries
.0002:
movem.l (a7)+,d0/d2
cmpi.b #CTRLZ,d1 ; receive end of file?
beq .0003
rts
AudioInputTest:
rts
BouncingBalls:
rts
GraphicsDemo:
rts
ClearScreen:
bra clear_screen
rts
;------------------------------------------------------------------------------
; Reverse the order of bytes in d1.
;------------------------------------------------------------------------------
rbo:
rol.w #8,d1
swap d1
rol.w #8,d1
rts
;==============================================================================
; Serial I/O routines
;==============================================================================
;------------------------------------------------------------------------------
; Initialize the serial port an enhanced 6551 circuit.
;
; Select internal baud rate clock divider for 9600 baud
; Reset fifos, set threshold to 3/4 full on transmit and 3/4 empty on receive
; Note that the byte order is swapped.
;------------------------------------------------------------------------------
SerialInit:
clr.w SerHeadRcv ; clear receive buffer indexes
clr.w SerTailRcv
clr.b SerRcvXon ; and Xon,Xoff flags
clr.b SerRcvXoff
move.l #$09000000,d0 ; dtr,rts active, rxint enabled, no parity
move.l d0,ACIA+ACIA_CMD
; move.l #$1E00F700,d0 ; fifos enabled
move.l #$1E000000,d0 ; fifos disabled
move.l d0,ACIA+ACIA_CTRL
rts
; move.l #$0F000000,d0 ; transmit a break for a while
; move.l d0,ACIA+ACIA_CMD
; move.l #300000,d2 ; wait 100 ms
; bra .0001
;.0003:
; swap d2
;.0001:
; nop
; dbra d2,.0001
;.0002:
; swap d2
; dbra d2,.0003
; move.l #$07000000,d0 ; clear break
; move.l d0,ACIA+ACIA_CMD
; rts
;------------------------------------------------------------------------------
; SerialGetChar
;
; Check the serial port buffer to see if there's a char available. If there's
; a char available then return it. If the buffer is almost empty then send an
; XON.
;
; Stack Space:
; 2 long words
; Parameters:
; none
; Modifies:
; d0,a0
; Returns:
; d1 = character or -1
;------------------------------------------------------------------------------
SerialGetChar:
move.l d2,-(a7)
movec coreno,d0
swap d0
moveq #SERIAL_SEMA,d1
bsr LockSemaphore
bsr SerialRcvCount ; check number of chars in receive buffer
cmpi.w #8,d0 ; less than 8?
bhi .sgc2
tst.b SerRcvXon ; skip sending XON if already sent
bne .sgc2 ; XON already sent?
move.b #XON,d1 ; if <8 send an XON
clr.b SerRcvXoff ; clear XOFF status
move.b d1,SerRcvXon ; flag so we don't send it multiple times
bsr SerialPutChar ; send it
.sgc2:
move.w SerHeadRcv,d1 ; check if anything is in buffer
cmp.w SerTailRcv,d1
beq .NoChars ; no?
lea SerRcvBuf,a0
move.b (a0,d1.w),d1 ; get byte from buffer
addi.w #1,SerHeadRcv
andi.w #$FFF,SerHeadRcv ; 4k wrap around
andi.l #$FF,d1
bra .Xit
.NoChars:
moveq #-1,d1
.Xit:
exg d1,d2
movec coreno,d0
swap d0
moveq #SERIAL_SEMA,d1
bsr UnlockSemaphore
exg d2,d1
move.l (a7)+,d2
rts
;------------------------------------------------------------------------------
; SerialPeekChar
;
; Check the serial port buffer to see if there's a char available. If there's
; a char available then return it. But don't update the buffer indexes. No need
; to send an XON here.
;
; Stack Space:
; 0 words
; Parameters:
; none
; Modifies:
; d0,d2,a0
; Returns:
; d1 = character or -1
;------------------------------------------------------------------------------
SerialPeekChar:
movec coreno,d0
swap d0
moveq #SERIAL_SEMA,d1
bsr LockSemaphore
move.w SerHeadRcv,d2 ; check if anything is in buffer
cmp.w SerTailRcv,d2
beq .NoChars ; no?
lea SerRcvBuf,a0
move.b (a0,d2.w),d2 ; get byte from buffer
bra .Xit
.NoChars:
moveq #-1,d2
.Xit:
movec coreno,d0
swap d0
moveq #SERIAL_SEMA,d1
bsr LockSemaphore
move d2,d1
rts
;------------------------------------------------------------------------------
; SerialPeekChar
; Get a character directly from the I/O port. This bypasses the input
; buffer.
;
; Stack Space:
; 0 words
; Parameters:
; none
; Modifies:
; d
; Returns:
; d1 = character or -1
;------------------------------------------------------------------------------
SerialPeekCharDirect:
move.b ACIA+ACIA_STAT,d1 ; get serial status
btst #3,d1 ; look for Rx not empty
beq.s .0001
moveq.l #0,d1 ; clear upper bits of return value
move.b ACIA+ACIA_RX,d1 ; get data from ACIA
rts ; return
.0001:
moveq #-1,d1
rts
;------------------------------------------------------------------------------
; SerialPutChar
; Put a character to the serial transmitter. This routine blocks until the
; transmitter is empty.
;
; Stack Space
; 0 words
; Parameters:
; d1.b = character to put
; Modifies:
; none
;------------------------------------------------------------------------------
SerialPutChar:
movem.l d0/d1,-(a7) ; push d0,d1
.0001:
move.b ACIA+ACIA_STAT,d0 ; wait until the uart indicates tx empty
btst #4,d0 ; bit #4 of the status reg
beq.s .0001 ; branch if transmitter is not empty
move.b d1,ACIA+ACIA_TX ; send the byte
movem.l (a7)+,d0/d1 ; pop d0,d1
rts
;------------------------------------------------------------------------------
; Reverse the order of bytes in d1.
;------------------------------------------------------------------------------
SerialRbo:
rol.w #8,d1
swap d1
rol.w #8,d1
rts
;------------------------------------------------------------------------------
; Calculate number of character in input buffer
;
; Returns:
; d0 = number of bytes in buffer.
;------------------------------------------------------------------------------
SerialRcvCount:
move.w SerTailRcv,d0
sub.w SerHeadRcv,d0
bge .0001
move.w #$1000,d0
sub.w SerHeadRcv,d0
add.w SerTailRcv,d0
.0001:
rts
;------------------------------------------------------------------------------
; Serial IRQ routine
;
; Keeps looping as long as it finds characters in the ACIA recieve buffer/fifo.
; Received characters are buffered. If the buffer becomes full, new characters
; will be lost.
;
; Parameters:
; none
; Modifies:
; none
; Returns:
; d1 = -1 if IRQ handled, otherwise zero
;------------------------------------------------------------------------------
SerialIRQ:
move.w #$2300,sr ; disable lower level IRQs
movem.l d0/d1/d2/a0,-(a7)
movec coreno,d0
swap d0
moveq #SERIAL_SEMA,d1
bsr LockSemaphore
sirqNxtByte:
move.b ACIA+ACIA_STAT,d1 ; check the status
btst #3,d1 ; bit 3 = rx full
beq notRxInt
move.b ACIA+ACIA_RX,d1
sirq0001:
move.w SerTailRcv,d0 ; check if recieve buffer full
addi.w #1,d0
andi.w #$FFF,d0
cmp.w SerHeadRcv,d0
beq sirqRxFull
move.w d0,SerTailRcv ; update tail pointer
subi.w #1,d0 ; backup
andi.w #$FFF,d0
lea SerRcvBuf,a0 ; a0 = buffer address
move.b d1,(a0,d0.w) ; store recieved byte in buffer
tst.b SerRcvXoff ; check if xoff already sent
bne sirqNxtByte
bsr SerialRcvCount ; if more than 4080 chars in buffer
cmpi.w #4080,d0
blo sirqNxtByte
move.b #XOFF,d1 ; send an XOFF
clr.b SerRcvXon ; clear XON status
move.b d1,SerRcvXoff ; set XOFF status
bsr SerialPutChar ; send XOFF
bra sirqNxtByte ; check the status for another byte
sirqRxFull:
notRxInt:
movec coreno,d0
swap d0
moveq #SERIAL_SEMA,d1
bsr UnlockSemaphore
movem.l (a7)+,d0/d1/d2/a0
rte
nmeSerial:
dc.b "Serial",0
;===============================================================================
; Generic I2C routines
;===============================================================================
even
; i2c
i2c_setup:
; lea I2C,a6
; move.w #19,I2C_PREL(a6) ; setup prescale for 400kHz clock
; move.w #0,I2C_PREH(a6)
init_i2c:
lea I2C2,a6
move.b #19,I2C_PREL(a6) ; setup prescale for 400kHz clock, 40MHz master
move.b #0,I2C_PREH(a6)
rts
; Wait for I2C transfer to complete
;
; Parameters
; a6 - I2C controller base address
i2c_wait_tip:
move.l d0,-(a7)
.0001
move.b I2C_STAT(a6),d0 ; wait for tip to clear
btst #1,d0
bne.s .0001
move.l (a7)+,d0
rts
; Parameters
; d0.b - data to transmit
; d1.b - command value
; a6 - I2C controller base address
;
i2c_wr_cmd:
move.b d0,I2C_TXR(a6)
move.b d1,I2C_CMD(a6)
bsr i2c_wait_tip
move.b I2C_STAT(a6),d0
rts
i2c_xmit1:
move.l d0,-(a7)
move.b #1,I2C_CTRL(a6) ; enable the core
moveq #$76,d0 ; set slave address = %0111011
move.w #$90,d1 ; set STA, WR
bsr i2c_wr_cmd
bsr i2c_wait_rx_nack
move.l (a7)+,d0
move.w #$50,d1 ; set STO, WR
bsr i2c_wr_cmd
bsr i2c_wait_rx_nack
i2c_wait_rx_nack:
move.l d0,-(a7)
.0001
move.b I2C_STAT(a6),d0 ; wait for RXack = 0
btst #7,d0
bne.s .0001
move.l (a7)+,d0
rts
;===============================================================================
; Realtime clock routines
;===============================================================================
rtc_read:
movea.l #I2C2,a6
lea RTCBuf,a5
move.b #$80,I2C_CTRL(a6) ; enable I2C
move.b #$DE,d0 ; read address, write op
move.b #$90,d1 ; STA + wr bit
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
move.b #$00,d0 ; address zero
move.b #$10,d1 ; wr bit
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
move.b #$DF,d0 ; read address, read op
move.b #$90,d1 ; STA + wr bit
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
move.w #$20,d2
.0001
move.b #$20,I2C_CMD(a6) ; rd bit
bsr i2c_wait_tip
bsr i2c_wait_rx_nack
move.b I2C_STAT(a6),d0
tst.b d0
bmi .rxerr
move.b I2C_RXR(a6),d0
move.b d0,(a5,d2.w)
addi.w #1,d2
cmpi.w #$5F,d2
bne .0001
move.b #$68,I2C_CMD(a6) ; STO, rd bit + nack
bsr i2c_wait_tip
bsr i2c_wait_rx_nack
move.b I2C_STAT(a6),d0
tst.b d0
bmi .rxerr
move.b I2C_RXR(a6),d0
move.b d0,(a5,d2.w)
move.b #0,I2C_CTRL(a6) ; disable I2C and return 0
moveq #0,d0
rts
.rxerr
move.b #0,I2C_CTRL(a6) ; disable I2C and return status
rts
rtc_write:
movea.l #I2C2,a6
lea RTCBuf,a5
move.b #$80,I2C_CTRL(a6) ; enable I2C
move.b #$DE,d0 ; read address, write op
move.b #$90,d1 ; STA + wr bit
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
move.b #$00,d0 ; address zero
move.b #$10,d1 ; wr bit
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
move.w #$20,d2
.0001
move.b (a5,d2.w),d0
move.b #$10,d1
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
addi.w #1,d2
cmpi.w #$5F,d2
bne.s .0001
move.b (a5,d2.w),d0
move.b #$50,d1 ; STO, wr bit
bsr i2c_wr_cmd
tst.b d0
bmi .rxerr
move.b #0,I2C_CTRL(a6) ; disable I2C and return 0
moveq #0,d0
rts
.rxerr:
move.b #0,I2C_CTRL(a6) ; disable I2C and return status
rts
msgRtcReadFail:
dc.b "RTC read/write failed.",$0A,$0D,$00
even
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
even
bus_err:
.0001:
nop
bra .0001
trap3:
; First save all registers
movem.l d0/d1/d2/d3/d4/d5/d6/d7/a0/a1/a2/a3/a4/a5/a6/a7,Regsave
move.w (a7)+,Regsave+$40
move.l (a7)+,Regsave+$44
move.l #$40FFC,a7 ; reset stack pointer
move.w #$2500,sr ; enable interrupts
move.w NumSetBreakpoints,d0
subi.w #1,d0
lea Breakpoints,a0
move.l Regsave+$44,d1
.0001:
cmp.l (a0)+,d1
beq.s ProcessBreakpoint
dbra d0,.0001
bra Monitor ; not a breakpoint
ProcessBreakpoint:
bsr DisarmAllBreakpoints
bra cmdDumpRegs
;------------------------------------------------------------------------------
; DisarmAllBreakpoints, used when entering the monitor.
;------------------------------------------------------------------------------
DisarmAllBreakpoints:
movem.l d0/a0/a1/a2,-(a7) ; stack some regs
move.w NumSetBreakpoints,d0 ; d0 = number of breakpoints that are set
cmpi.w #numBreakpoints,d0 ; check for valid number
bhs.s .0001
lea Breakpoints,a2 ; a2 = pointer to breakpoint address table
lea BreakpointWords,a0 ; a0 = pointer to breakpoint instruction word table
bra.s .0003 ; enter loop at bottom
.0002:
move.l (a2)+,a1 ; a1 = address of breakpoint
move.w (a0)+,(a1) ; copy instruction word back to code
.0003:
dbra d0,.0002
movem.l (a7)+,d0/a0/a1/a2 ; restore regs
.0001:
rts
;------------------------------------------------------------------------------
; ArmAllBreakpoints, used when entering the monitor.
;------------------------------------------------------------------------------
ArmAllBreakpoints:
movem.l d0/a0/a1/a2,-(a7) ; stack some regs
move.w NumSetBreakpoints,d0 ; d0 = number of breakpoints
cmpi.w #numBreakpoints,d0 ; is the number valid?
bhs.s .0001
lea Breakpoints,a2 ; a2 = pointer to breakpoint address table
lea BreakpointWords,a0 ; a0 = pointer to instruction word table
bra.s .0003 ; enter loop at bottom
.0002:
move.l (a2)+,a1 ; a1 = address of breakpoint
move.w (a1),(a0) ; copy instruction word to table
move.w #$4E43,(a0)+ ; set instruction = TRAP3
.0003:
dbra d0,.0002
movem.l (a7)+,d0/a0/a1/a2 ; restore regs
.0001:
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ArmBreakpoint:
movem.l d0/d1/d2/a0/a1/a2,-(a7)
move.w NumSetBreakpoints,d0 ; d0 = number of breakpoints
cmpi.w #numBreakpoints,d0 ; check if too many
bhs.s .0001
addi.w #1,NumSetBreakpoints ; increment number of breakpoints
move.l d0,d2
bsr ignBlanks
bsr GetHexNumber
beq.s .0001 ; was there an address?
btst #0,d1 ; address value must be even
bne.s .0001
; See if the breakpoint is in the table already
lea Breakpoints,a1 ; a1 points to breakpoint table
move.w #numBreakpoints-1,d2
.0002:
cmp.l (a1)+,d1
beq.s .0003 ; breakpoint is in table already
dbra d2,.0002
; Add breakpoint to table
; Search for empty entry
lea Breakpoints,a1 ; a1 = pointer to breakpoint address table
clr.w d2 ; d2 = count
.0006:
tst.l (a1) ; is the entry empty?
beq.s .0005 ; branch if found empty entry
lea 4(a1),a1 ; point to next entry
addi.w #1,d2 ; increment count
cmpi.w #numBreakpoints,d2 ; safety: check against max number
blo.s .0006
bra.s .0001 ; what? no empty entries found, table corrupt?
.0005:
asl.w #2,d2 ; d2 = long word index
move.l d1,(a1,d2.w) ; move breakpoint address to table
move.l d1,a2
lsr.w #1,d2 ; d2 = word index
.0004:
lea BreakpointWords,a1
move.w (a2),(a1,d2.w) ; copy instruction word to table
move.w #$4E43,(a2) ; replace word with TRAP3
.0001:
movem.l (a7)+,d0/d1/d2/a0/a1/a2
rts
.0003:
move.l -4(a1),a2 ; a2 = pointer to breakpoint address from table
cmpi.w #$4E43,(a2) ; see if breakpoint already armed
beq.s .0001
asl.l #1,d2 ; d2 = word index
bra.s .0004
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
DisarmBreakpoint:
movem.l d0/d1/d2/a0/a1/a2,-(a7)
move.w NumSetBreakpoints,d0 ; d0 = number of breakpoints
cmpi.w #numBreakpoints,d0 ; check if too many
bhi.s .0001
move.l d0,d2
bsr ignBlanks
bsr GetHexNumber
beq.s .0001 ; was there an address?
btst #0,d1 ; address value must be even
bne.s .0001
; See if the breakpoint is in the table already
lea Breakpoints,a1 ; a1 points to breakpoint table
subi.w #1,d2
.0002:
cmp.l (a1)+,d1
beq.s .0003 ; breakpoint is in table already
dbra d2,.0002
bra .0001 ; breakpoint was not in table
.0003:
; Remove breakpoint from table
subi.w #1,NumSetBreakpoints ; decrement number of breakpoints
move.l -4(a1),a2 ; a2 = pointer to breakpoint address from table
clr.l -4(a1) ; empty out breakpoint
lea BreakpointWords,a1
asl.l #1,d2 ; d2 = word index
move.w (a1,d2.w),(a2) ; copy instruction from table back to code
.0001:
movem.l (a7)+,d0/d1/d2/a0/a1/a2
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ListBreakpoints:
bsr CRLF
move.w #numBreakpoints,d2
lea Breakpoints,a1
.0001:
move.l (a1)+,d1
bsr DisplayTetra
bsr CRLF
dbra d2,.0001
bra Monitor
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ClearBreakpointList:
move.w #numBreakpoints,d2
lea Breakpoints,a1
.0001:
clr.l (a1)+
dbra d2,.0001
rts
;------------------------------------------------------------------------------
; SendMsg
; 00100xy0
;
; Parameters:
; d1 = target core number
; d2 = argument 1
; d3 = argument 2
; d4 = argument 3
;
;------------------------------------------------------------------------------
SendMsg:
movem.l d5/a1,-(a7)
lsl.w #8,d1
movec coreno,d5
lsl.w #4,d5
or.w d5,d1
lea $00100000,a1
tst.l 0(a1,d1.w)
bne .msgFull
movec coreno,d5
move.l d5,0(a1,d1.w)
move.l d2,4(a1,d1.w)
move.l d3,8(a1,d1.w)
move.l d4,12(a1,d1.w)
movem.l (a7)+,d5/a1
moveq #0,d1
rts
.msgFull:
movem.l (a7)+,d5/a1
moveq #-1,d1
rts
;------------------------------------------------------------------------------
; ReceiveMsg
; Scan the message table for messages and dispatch them.
; 00100xy0
;
; Parameters:
;------------------------------------------------------------------------------
ReceiveMsg:
movem.l d1/d2/d3/d4/d5/d6/d7/a1,-(a7)
lea $00100000,a1
movec coreno,d5
lsl.w #8,d5
moveq #2,d6
.nextCore:
move.w d6,d7
lsl.w #4,d7
add.w d5,d7
tst.l 0(a1,d7.w) ; Is there a message from core d6?
beq .noMsg
move.l 0(a1,d7.w),d1
move.l 4(a1,d7.w),d2
move.l 8(a1,d7.w),d3
move.l 12(a1,d7.w),d4
clr.l 0(a1,d7.w) ; indicate message was received
bsr DispatchMsg
.noMsg:
addq #1,d6
cmp.w #9,d6
bls .nextCore
movem.l (a7)+,d1/d2/d3/d4/d5/d6/d7/a1
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
DispatchMsg:
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
InitIRQ:
moveq #6,d0
lea KeybdIRQ,a0
bsr InstallIRQ
lea TickIRQ,a0
bsr InstallIRQ
moveq #3,d0
lea SerialIRQ,a0
; fall through
;------------------------------------------------------------------------------
; Install an IRQ handler.
;
; Parameters:
; d0 = IRQ level
; a0 = pointer to IRQ routine
; Returns:
; d1 = -1 if successfully added, 0 otherwise
; nf = 1, zf = 0 if successfully added, otherwise nf = 0, zf = 1
;------------------------------------------------------------------------------
InstallIRQ:
move.l d0,-(a7) ; save working register
lea InstalledIRQ,a1 ; a1 points to installed IRQ list
lsl.w #5,d0 ; multiply by 8 long words per IRQ level
.nextSpot:
cmpa.l (a1,d0.w),a0 ; Is the IRQ already installed?
beq.s .found
tst.l (a1,d0.w) ; test for an empty spot
beq.s .foundSpot
addi.w #4,d0 ; increment to next slot
move.w d0,d1
andi.w #$1F,d1 ; check to see if spots exhausted
beq.s .noEmpties
bra.s .nextSpot
.foundSpot:
move.l a0,(a1,d0.w) ; add IRQ routine to table
.found:
move.l (a7)+,d0
moveq #-1,d1 ; return success
rts
.noEmpties:
move.l (a7)+,d0
moveq #0,d1 ; return failed to add
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
TickIRQ:
move.w #$2600,sr ; disable lower level IRQs
movem.l d1/d2/a0,-(a7)
; ToDo: detect a tick interrupt
; move.l PLIC+$00,d1
; rol.l #8,d1
; cmpi.b #29,d1
; bne.s .notTick
movec coreno,d1 ; d1 = core number
cmpi.b #2,d1
bne.s .0001
move.l #$1D000000,PLIC+$14 ; reset edge sense circuit
.0001:
move.l TextScr,a0 ; a0 = screen address
move.l (a0),d2
rol.w #8,d2 ; reverse byte order of d2
swap d2
rol.w #8,d2
addi.b #'0',d1 ; binary to ascii core number
add.b d2,d1
rol.w #8,d1 ; put bytes back in order
swap d1
rol.w #8,d1
move.l d1,4(a0) ; update onscreen IRQ flag
addi.l #1,(a0) ; flashy colors
; addi.l #1,40(a0) ; nice effect
bsr ReceiveMsg
movem.l (a7)+,d1/d2/a0
rte
;.notTick:
; movem.l (a7)+,d1/a0
; rte
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
irq3_rout:
movem.l d0/d1/a0/a1,-(a7)
lea InstalledIRQ+8*4*3,a0
bra irq_rout
irq6_rout:
movem.l d0/d1/a0/a1,-(a7)
lea InstalledIRQ+8*4*6,a0
irq_rout:
moveq #7,d0
.nextHandler:
move.l (a0)+,a1
beq.s .0003
jsr (a1)
tst.l d1 ; was IRQ handled?
bmi.s .0002 ; first one to return handled quits loop
.0003:
dbra d0,.nextHandler
.0002:
movem.l (a7)+,d0/d1/a0/a1 ; return
SpuriousIRQ:
rte
; bsr KeybdIRQ
; tst.l d1 ; handled by KeybdIRQ?
; bmi.s .0002 ; if yes, go return
;.0001:
; move.l #$1D000000,PLIC+$14 ; reset edge sense circuit
; move.l TextScr,a0 ; a0 = screen address
; addi.l #1,40(a0) ; update onscreen IRQ flag
;.0002:
; movem.l (a7)+,d0/d1/a0/a1 ; return
; rte
nmi_rout:
movem.l d0/d1/a0,-(a7)
move.b #'N',d1
bsr DisplayChar
movem.l (a7)+,d0/d1/a0 ; return
rte
brdisp_trap:
movem.l d0/d1/d2/d3/d4/d5/d6/d7/a0/a1/a2/a3/a4/a5/a6/a7,Regsave
move.w (a7)+,Regsave+$40
move.l (a7)+,Regsave+$44
move.l #$40FFC,a7 ; reset stack pointer
move.w #$2500,sr ; enable interrupts
lea msg_bad_branch_disp,a1
bsr DisplayString
bsr DisplaySpace
move.l Regsave+$44,d1 ; exception address
bsr DisplayTetra ; and display it
; move.l (sp)+,d1 ; pop format word 68010 mode only
bra cmdDumpRegs
illegal_trap:
addq #2,sp ; get rid of sr
move.l (sp)+,d1 ; pop exception address
bsr DisplayTetra ; and display it
lea msg_illegal,a1 ; followed by message
bsr DisplayString
.0001:
bra .0001
bra Monitor
io_irq:
addq #2,sp
move.l (sp)+,d1
bsr DisplayTetra
lea msg_io_access,a1
bsr DisplayString
bra cmdDumpRegs
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
msg_start:
dc.b "Femtiki rf68k Multi-core OS Starting",LF,CR,0
; dc.b "rf68k System Starting",CR,LF,0
msg_core_start:
dc.b " core starting",CR,LF,0
msg_illegal:
dc.b " illegal opcode",CR,LF,0
msg_bad_branch_disp:
dc.b " branch selfref: ",0
msg_test_done:
dc.b " CPU test done.",0
msg_io_access
dc.b " unpermitted access to I/O",0
Go to most recent revision | Compare with Previous | Blame | View Log