! Dreamcast Serial Slave V1.002 by Double Dutch Designs Limited ! Originally based upon Marcus's Serial.S code ! ! To compile into SREC using Win+GNU binutils: ! ! as -little -o serial.o serial.s ! ld -EL --oformat srec -Ttext 0x8c008c00 serial.o -o serial.srec ! this puts it below marcus's shell for testing... ! put it at 8c00b800 to replace bootstrap 1, or 8c00e000 to replace bootstrap 2 ! max object size is 8kbytes .globl start BaudN = 1 ! 781kbps default!!! lf = 0x0a cr = 0x0d .text start: ! First, make sure to run in the P2 area mov.l setup_cache_addr,r0 mov.l p2_mask,r1 or r1,r0 jmp @r0 nop setup_cache: ! Now that we are in P2, it's safe ! to enable the cache mov.l ccr_addr,r0 mov.w ccr_data,r1 mov.l r1,@r0 ! After changing CCR, eight instructions ! must be executed before it's safe to enter ! a cached area such as P1 mov.l main_addr,r0 ! 1 mov #0,r1 ! 2 nop ! 3 nop ! 4 nop ! 5 nop ! 6 nop ! 7 nop ! 8 jmp @r0 ! go mov r1,r0 .align 4 p2_mask: .long 0xa0000000 setup_cache_addr: .long setup_cache main_addr: .long main ccr_addr: .long 0xff00001c ccr_data: .word 0x090d ! Real program starts here. main: bsr disable_cache nop bra Reset ! reset any values nop Loop: bsr send ! prompt mov #']',r4 Wait: bsr recvw ! wait for chr nop cmp/eq #cr,r0 bt Wait ! ignore cr cmp/eq #lf,r0 bt Loop ! if just cr, then retype prompt cmp/eq #'?',r0 bt Version ! check for uppercase mov #'z',r1 cmp/hi r1,r0 ! is r0>r1? bt .NotLower ! yes! mov #'a',r1 cmp/hs r1,r0 ! is r0>=r1? bf .NotLower ! no! mov #'a'-'A',r1 sub r1,r0 ! make uppercase .NotLower: mov #' ',r1 cmp/hs r1,r0 ! is r0>=r1 bf Wait ! no! mov #'Z',r1 cmp/hi r1,r0 ! is r0>r1 bt Wait ! yes! cmp/eq #'S',r0 bt SRecord cmp/eq #'R',r0 bt Reset cmp/eq #'B',r0 bt Binary cmp/eq #'G',r0 bt Go cmp/eq #'H',r0 bt Help cmp/eq #'M',r0 bt Dump cmp/eq #'N',r0 bt NewN mova Emessage,r0 ! error message bsr send_str mov r0,r4 bra Loop nop Dump: bsr GetAddr nop bsr send mov #cr,r4 bsr send mov #lf,r4 mov #8,r12 DLoop3: bsr PutAddr nop mov #16,r14 mov.l DestAddr,r13 mov r13,r11 DLoop: bsr send mov #' ',r4 mov.b @r13+,r0 bsr PutByte nop dt r14 bf DLoop bsr send mov #' ',r4 bsr send mov #' ',r4 mov #16,r14 DLoop2: mov.b @r11+,r0 bsr SendSafe nop dt r14 bf DLoop2 mova DestAddr,r0 mov.l r13,@r0 bsr send mov #cr,r4 bsr send mov #lf,r4 dt r12 bf DLoop3 bra Loop nop Binary: bsr RecLong nop mova DestAddr,r0 mov.l r4,@r0 mov r4,r14 ! position bsr RecLong nop mov r4,r13 ! length BLoop: bsr recvw nop mov.b r0,@r14 add #1,r14 dt r13 bf BLoop bra Loop nop Go: bsr RecLong nop bra Run nop SRecord: bsr recvw ! wait for chr nop cmp/eq #cr,r0 bt SRecord ! ignore cr cmp/eq #'0',r0 bt SRecord0 cmp/eq #'3',r0 bt SRecord3 cmp/eq #'7',r0 bt SRecord7 SyntaxError: mova Smessage,r0 bsr send_str ! bad syntax! mov r0,r4 bra Loop ! next command nop Help: mova Hmessage,r0 bsr send_str mov r0,r4 bra Loop nop Version: mova Vmessage1,r0 bsr send_str mov r0,r4 mov.w PassedBaudN,r0 bsr PutByte nop mova Vmessage2,r0 bsr send_str mov r0,r4 bra Loop nop Reset: mov.w PassedBaudN,r4 ! reset stuff goes in this routine!!! bsr init_serial nop mova Omessage,r0 bsr send_str mov r0,r4 bra Loop nop NewN: bsr GetByte nop mov r4,r14 ! keep safe cmp/pz r0 bf SyntaxError bsr GetLineFeed nop cmp/pz r0 bf SyntaxError mova PassedBaudN,r0 mov.w r14,@r0 bra Reset nop .align 4 Vmessage1: .ascii "V1.003 N=" .byte 0,'*','*','*' .align 4 PassedBaudN: .word BaudN .byte '*','*,'*' .align 4 SRecord0: bsr recvw ! get character nop cmp/eq #lf,r0 bf SRecord0 ! not eol yet! bra Loop ! next command nop SRecord3: bsr GetLength nop cmp/pz r0 bf SyntaxError mov r0,r14 bsr GetAddr nop cmp/pz r0 bf SyntaxError mov.l DestAddr,r13 mov #5,r0 sub r0,r14 SR3Loop: bsr GetByte nop cmp/pz r0 bf SyntaxError mov.b r4,@r13 add #1,r13 dt r14 bf SR3Loop ! here get data bsr GetChecksum nop cmp/pz r0 bf SyntaxError bsr GetLineFeed nop cmp/pz r0 bf SyntaxError bra Loop ! next command nop SRecord7: bsr GetLength nop cmp/pz r0 bf SyntaxError bsr GetAddr nop cmp/pz r0 bf SyntaxError bsr GetChecksum nop cmp/pz r0 bf SyntaxError bsr GetLineFeed nop cmp/pz r0 bf SyntaxError mov.l DestAddr,r4 ! execute routine bra Run nop GetLength: sts.l pr,@-r15 bsr GetByte nop cmp/pz r0 bf GLExit mov r4,r0 GLExit: lds.l @r15+,pr rts nop GetAddr: sts.l pr,@-r15 bsr GetByte ! 0 nop cmp/pz r0 bf GAExit mov r4,r5 bsr GetByte ! 1 nop cmp/pz r0 bf GAExit shll8 r5 or r4,r5 bsr GetByte ! 2 nop cmp/pz r0 bf GAExit shll8 r5 or r4,r5 bsr GetByte ! 3 nop cmp/pz r0 bf GAExit shll8 r5 or r4,r5 mova DestAddr,r0 mov.l r5,@r0 mov #0,r0 GAExit: lds.l @r15+,pr rts nop GetChecksum: sts.l pr,@-r15 bsr GetByte nop GCExit: lds.l @r15+,pr rts nop RecLong: sts.l pr,@-r15 bsr recvw ! wait for character shll8 r4 or r0,r4 bsr recvw ! wait for character shll8 r4 or r0,r4 bsr recvw ! wait for character shll8 r4 or r0,r4 bsr recvw ! wait for character shll8 r4 or r0,r4 lds.l @r15+,pr rts nop GetByte: sts.l pr,@-r15 bsr GetDigit nop cmp/pz r0 bf GBExit mov #0xf,r1 and r1,r0 mov r0,r4 shll2 r4 shll2 r4 bsr GetDigit nop cmp/pz r0 bf GBExit mov #0xf,r1 and r1,r0 or r0,r4 GBExit: lds.l @r15+,pr rts nop GetDigit: sts.l pr,@-r15 bsr recvw ! wait for chr nop mov #'0',r1 cmp/hs r1,r0 ! is r0>=r1? bf GDNotDigit ! no! mov #'9',r1 cmp/hi r1,r0 ! is r0>r1? bf GDIsDigit ! no! GDNotDigit: mov #'z',r1 cmp/hi r1,r0 ! is r0>r1? bt GDNotLower ! yes! mov #'a',r1 cmp/hs r1,r0 ! is r0>=r1? bf GDNotLower ! no! mov #'a'-'A',r1 sub r1,r0 ! make uppercase GDNotLower: mov #'A',r1 cmp/hs r1,r0 ! is r0>=r1? bf GDNotDigit2 ! no! mov #'F',r1 cmp/hi r1,r0 ! is r0>r1? bf GDIsDigit2 ! no! GDNotDigit2: mov #-1,r0 lds.l @r15+,pr rts nop GDIsDigit: mov #'0',r1 sub r1,r0 ! make digit lds.l @r15+,pr rts nop GDIsDigit2: mov #'A'-10,r1 sub r1,r0 ! make 10-15 lds.l @r15+,pr rts nop ! return -1 if next chr not a lf!!! GetLineFeed: sts.l pr,@-r15 GLFLoop: bsr recvw nop cmp/eq #cr,r0 bt GLFLoop mov #-1,r1 cmp/eq #lf,r0 bf GFLExit mov #0,r1 GFLExit: lds.l @r15+,pr rts mov r1,r0 PutAddr: sts.l pr,@-r15 mov.l DestAddr,r6 mov r6,r7 shlr16 r7 mov r7,r0 bsr PutByte shlr8 r0 bsr PutByte mov r7,r0 mov r6,r0 bsr PutByte shlr8 r0 bsr PutByte mov r6,r0 lds.l @r15+,pr rts nop PutByte: sts.l pr,@-r15 mov r0,r5 shlr2 r0 shlr2 r0 mov #0xf,r1 and r1,r0 and r1,r5 mov r0,r4 mova HexTable,r0 add r0,r4 mov.b @r4,r4 bsr send add r0,r5 bsr send mov.b @r5,r4 lds.l @r15+,pr rts nop SendSafe: sts.l pr,@-r15 mov #'.',r4 mov #' ',r1 cmp/hs r1,r0 ! is r0>=r1? bf SSNow ! no! mov #'z',r1 cmp/hi r1,r0 ! is r0>r1 bt SSNow ! yes! mov r0,r4 SSNow: bsr send nop lds.l @r15+,pr rts nop .align 4 DestAddr: .long 0x8c010000 .align 4 HexTable: .ascii "0123456789abcdef" .align 4 Emessage: .ascii "? Command Unknown!" .byte cr,lf,0 .align 4 Smessage: .ascii "? Unknown Syntax!" .byte cr,lf,0 .align 4 Xmessage: .ascii "? Bad Checksum!" .byte cr,lf,0 .align 4 Rmessage: .byte cr,lf .ascii "Welcome Back!" .byte cr,lf,0 .align 4 Vmessage2: .ascii " (Press 'H' for help)." .byte cr,lf,0 .align 4 Omessage: .byte cr,lf .ascii "Okay!" .byte cr,lf,0 .align 4 Hmessage: .byte cr,lf .ascii "DCExe TEST!!! (DC Side) - (c)2000 Double Dutch Designs Limited" .byte cr,lf,lf .ascii "Help" .byte cr,lf,lf .ascii " ? Version" .byte cr,lf .ascii "*B@@ Binary load (@ is 4 byte address)!" .byte cr,lf .ascii " H You found it!" .byte cr,lf .ascii " G[#] Go!" .byte cr,lf .ascii " M[#] Memory Dump" .byte cr,lf .ascii "*N$ New 'N' rate ($ is 2 digit hex number)" .byte cr,lf .ascii " R Reset DCExe" .byte cr,lf .ascii " Sx... S-Record line (types 0, 3 & 7 are valid)" .byte cr,lf,lf .ascii "Note:# is an 8 digit hex memory address! There are no room for errors in" .byte cr,lf .ascii "a DC world... BS & DEL do nothing!!! ;) '*' commands are internal!" .byte cr,lf,lf,0 .align 4 ! Initialize SCIF registers ! ! r4 = baudrate (must be >= 6092 bps) init_serial: ! Get base address of SCIF mov #-24,r2 shll16 r2 ! disable interrupts, disable transmit/receive, use internal clock mov #0,r0 mov.w r0,@(8,r2) ! 8N1, use PŘ clock mov.w r0,@r2 ! Set baudrate, N = PŘ/(32*B)-1 mov r4,r0 ! direct! mov.b r0,@(4,r2) ! reset FIFOs, enable hardware flow control add #8,r2 ! disable manual pin control mov #0x80,r0 mov.w r0,@(24,r2) mov #12,r0 mov.w r0,@(16,r2) mov #8,r0 ! 8, bit zero is ring test mov.w r0,@(16,r2) ! clear status mov.w @(8,r2),r0 mov #0x60,r0 mov.w r0,@(8,r2) mov.w @(28,r2),r0 mov #0,r0 mov.w r0,@(28,r2) ! enable transmit/receive mov #0x30,r0 ! RE&TE bits rts mov.w r0,@r2 ! Send a NUL-terminated string to the serial port ! ! r4 = string send_str: mov #-24,r2 shll16 r2 add #12,r2 mov.l RGBAddr,r3 .ssloop1: mov.b @r4+,r1 tst r1,r1 bt .endstr extu.b r1,r1 .ssloop2: mov.w @(4,r2),r0 tst #0x20,r0 bt .ssloop2 mov.b r1,@r2 mov r1,r5 shll8 r5 or r1,r5 mov.l r5,@r3 and #0x9f,r0 bra .ssloop1 mov.w r0,@(4,r2) .endstr: rts ! Send a single character to the serial port ! ! r4 = character send: mov #-24,r2 shll16 r2 add #12,r2 .sloop: mov.w @(4,r2),r0 tst #0x20,r0 bt .sloop mov.b r4,@r2 mov.l RGBAddr,r1 and #0x9f,r0 mov r4,r3 shll8 r3 or r4,r3 mov.l r3,@r1 rts mov.w r0,@(4,r2) ! Check for serial input ! ! returns character or -1 recv: mov #-24,r2 shll16 r2 add #12,r2 mov.w @(16,r2),r0 tst #0x1f,r0 bt .norecv mov.b @(8,r2),r0 extu.b r0,r1 mov.w @(4,r2),r0 and #0x6d,r0 mov.w r0,@(4,r2) mov.l RGBAddr,r0 mov r1,r2 shll16 r2 or r1,r2 mov.l r2,@r0 rts mov r1,r0 .norecv: rts mov #-1,r0 ! Wait for serial input ! ! returns character recvw: sts pr,r3 .rcvlp: bsr recv nop cmp/pz r0 bf .rcvlp lds r3,pr rts nop .align 4 RGBAddr: .long 0xa05f8040 ! Flush output FIFO flush: mov #-24,r2 shll16 r2 add #12,r2 mov.w @(4,r2),r0 and #0xbf,r0 mov.w r0,@(4,r2) .wflush: mov.w @(4,r2),r0 tst #64,r0 bt .wflush and #0xbf,r0 rts mov.w r0,@(4,r2) ! goto address in r4 Run: mov.l stack_addr_k,r0 mov.l @r0,r15 mov.l entry_addr_k,r0 mov.l @r0,r0 lds r0,pr mov.l xsr_data_k,r0 mov.l @r0,r0 ldc r0,sr mov.l xvbr_data_k,r0 mov.l @r0,r0 ldc r0,vbr mov.l xfpscr_data_k,r0 mov.l @r0,r0 lds r0,fpscr mov #0,r0 mov r0,r1 mov r0,r2 mov r0,r3 mov r0,r5 mov r0,r6 mov r0,r7 mov r0,r8 mov r0,r9 mov r0,r10 mov r0,r11 mov r0,r12 mov r0,r13 mov r0,r14 jmp @r4 mov r0,r4 .align 4 stack_addr_k: .long stack_addr stack_addr: .long 0x8c00f400 entry_addr_k: .long entry_addr entry_addr: .long main xsr_data_k: .long sr_data sr_data: .long 0x600000f0 xvbr_data_k: .long vbr_data vbr_data: .long 0x8c00f400 xfpscr_data_k: .long fpscr_data fpscr_data: .long 0x40001 disable_cache: mov.l disable_cache_k,r0 mov.l p2_mask2,r1 or r1,r0 jmp @r0 nop xdisable_cache: mov.l ccr_addr2,r0 mov.l ccr_data_k,r1 mov.l @r1,r1 mov.l r1,@r0 nop nop nop nop nop nop nop nop rts nop .align 4 disable_cache_k: .long xdisable_cache p2_mask2: .long 0xa0000000 ccr_addr2: .long 0xff00001c ccr_data_k: .long ccr_data2 ccr_data2: .long 0x00000808 .end