; scif pages 553-598, toc pages viii and ix .include "regs.s" CR = 13 LF = 10 DC_PCLOCK = 49900000 ; Hz BAUDRATE = 57600 . = 0x8c010000 .entry . ; We want to be running in P2, to fiddle CCR. (The hardware ; PDF, page 77, says that "CCR modifications must only be made ; by a program in the non-cached P2 area".) mova 1f,r0 mov.l px_mask,r1 mov.l p2_bits,r2 and r1,r0 or r2,r0 jmp @r0 nop .align 4 1: ; Now running in P2, so we can turn on the cache. mov.l ccr_addr,r0 mov.l ccr_bits,r3 mov.l r3,@r0 ; The hardware PDF, page 77, says that "After CCR is updated, ; an instruction that performs data access to the P0, P1, P3, ; or U0 area should be located at least four instructions after ; the CCR update instruction. Also, a branch instruction to ; the P0, P1, P3, or U0 area should be located at least eight ; instructions after the CCR update instruction." It doesn't ; say why this is "should" rather than "must", nor does it ; describe the consequences if this is not done, nor does it ; say whether this "beyond" refers to address space or ; instruction execution order (eg, does a three-instruction ; loop that's executed three times count as nine instructions ; or three? does a branch seven instructions forward count?). ; We treat it pessimistically, making sure we burn eight ; instructions by any of these measures. ; ; Gotta love incomplete doc. ; mova start,r0 ; #1 mov.l p0_bits,r2 ; #2 and r1,r0 ; #3 or r2,r0 ; #4 mov.l stacktop,r15 ; #5 nop ; #6 nop ; #7 nop ; #8 jmp @r0 nop .align 4 px_mask: ; mask off Px-selecting bits .long 0x1fffffff p2_bits: ; bits for P2 .long 0xa0000000 ccr_addr: .long CCR ccr_bits: ; Not set: IIX OIX ORA WT .long CCR_ICI | CCR_ICE | CCR_OCI | CCR_CB | CCR_OCE p0_bits: ; bits for P0 .long 0x80000000 stacktop: .long 0x8c010000 .align 4 start: bsr setup_scif nop bra main nop setup_scif: mov.l r0,@-r15 mov.l r1,@-r15 mov.l r2,@-r15 mov.l r3,@-r15 stc.l gbr,@-r15 sts.l pr,@-r15 ; Initialize the SCIF. Mostly follows hardware PDF figure ; 16.6, but not entirely (eg, 16.6 shows turning on CKE1, but ; we don't want external clock, so we don't). mov.l scif_base,r1 ldc r1,gbr ; Clear SCSCR2 (in particular, clear TE and RE). mov #0,r0 mov.w r0,@(SCSCR2-SCIF_BASE,gbr) ; Clear out the FIFOs. mov.w reset_fifos,r0 mov.w r0,@(SCFCR2-SCIF_BASE,gbr) ; Configure for 8N1. mov.w config_8n1,r0 mov.w r0,@(SCMSR2-SCIF_BASE,gbr) ; Get the BRG constant. mov #[[[[DC_PCLOCK*2]/[32*BAUDRATE]]+1]/2],r0 mov.b r0,@(SCBRR2-SCIF_BASE,gbr) ; Delay at least one bit time. ; There's probably a better way to do this, but we use the 64Hz ; counter register, waiting until it's ticked twice. This ; amounts to assuming BAUDRATE is >64, so check that. .if BAUDRATE < 64 .error Code assumes BAUDRATE is at least 64 .endif bsr await_tick nop bsr await_tick nop ; Set the FIFO interrupt trigger points and clear the reset ; bits. We don't actually care about the trigger points, ; because we don't use interrupts; we might be able to skip ; this step, but it's easy and harmless. mov.w set_triggers,r0 mov.w r0,@(SCFCR2-SCIF_BASE,gbr) ; Setup complete. Enable transmitter and receiver. mov.w enable_tx_rx,r0 mov.w r0,@(SCSCR2-SCIF_BASE,gbr) ; Flush any lingering statuses. mov.w @(SCFSR2-SCIF_BASE,gbr),r0 mov #0,r0 mov.w r0,@(SCFSR2-SCIF_BASE,gbr) mov.w @(SCLSR2-SCIF_BASE,gbr),r0 mov #0,r0 mov.w r0,@(SCLSR2-SCIF_BASE,gbr) lds.l @r15+,pr ldc.l @r15+,gbr mov.l @r15+,r3 mov.l @r15+,r2 mov.l @r15+,r1 mov.l @r15+,r0 rts nop .align 4 ; scif_base is below reset_fifos: .word SCFCR2_TFRST | SCFCR2_RFRST set_triggers: .word SCFCR2_RXT_8 | SCFCR2_TXT_8 config_8n1: .word SCMSR2_CHR_8 | SCMSR2_PE_DIS | SCMSR2_STOP_1 | SCMSR2_CKS_DIV1 enable_tx_rx: .word SCSCR2_TE | SCSCR2_RE await_tick: mov.l r0,@-r15 stc.l gbr,@-r15 mov.l r2,@-r15 mov.l r3,@-r15 sts.l pr,@-r15 mov.l rtc_base,r0 ldc r0,gbr bsr read_r64cnt nop mov r2,r3 1: bsr read_r64cnt nop cmp/eq r2,r3 bt 1b lds.l @r15+,pr mov.l @r15+,r3 mov.l @r15+,r2 ldc.l @r15+,gbr mov.l @r15+,r0 rts nop 1: mov.b r0,@(RCR1-RTC_BASE,gbr) read_r64cnt: mov.b @(R64CNT-RTC_BASE,gbr),r0 mov r0,r2 mov.b @(RCR1-RTC_BASE,gbr),r0 tst #0x80,r0 mov #0,r0 bf 1b rts nop .align 4 rtc_base: .long RTC_BASE .align 4 main: ; r15 = conventional stack pointer ; r14 = SCIF base pointer ; r13 = shift register, high half ; r12 = shift register, low half ; r11 = top-of-loop pointer ; r10 = current size (1, 2, or 4) ; r9 = ; r8 = ; r7 = ; r6 = ; r5 = scratch ; r4 = scratch ; r3 = scratch ; r2 = scratch ; r1 = scratch ; r0 = scratch ; gbr = scratch mov.l scif_base,r14 mov #'>,r1 bsr putchar nop mova mainloop,r0 mov r0,r11 mov #1,r10 jmp @r11 nop .align 4 mainloop: ldc r14,gbr mov.w @(SCFDR2-SCIF_BASE,gbr),r0 SHXR #SCFDR2_RX_SHIFT,r0,r1 tst #SCFDR2_RX_MASK,r0 bt mainloop mov.w @(SCFSR2-SCIF_BASE,gbr),r0 tst #SCFSR2_FER|SCFSR2_PER,r0 mov.b @(SCFRDR2-SCIF_BASE,gbr),r0 extu.b r0,r1 mov.w @(SCLSR2-SCIF_BASE,gbr),r0 mov #0,r0 mov.w r0,@(SCLSR2-SCIF_BASE,gbr) bf mainloop mov.l chartbl,r0 mov r1,r2 shll2 r2 mov.l @(r0,r2),r2 jmp @r2 nop .align 4 scif_base: .long SCIF_BASE chartbl: .long char_default ; 0x00 .long char_default ; 0x01 .long char_default ; 0x02 .long char_default ; 0x03 .long char_default ; 0x04 .long char_default ; 0x05 .long char_default ; 0x06 .long char_default ; 0x07 .long char_default ; 0x08 .long char_default ; 0x09 .long char_default ; 0x0a .long char_default ; 0x0b .long char_default ; 0x0c .long char_default ; 0x0d .long char_default ; 0x0e .long char_default ; 0x0f .long char_default ; 0x10 .long char_default ; 0x11 .long char_default ; 0x12 .long char_default ; 0x13 .long char_default ; 0x14 .long char_default ; 0x15 .long char_default ; 0x16 .long char_default ; 0x17 .long char_default ; 0x18 .long char_default ; 0x19 .long char_default ; 0x1a .long char_default ; 0x1b .long char_default ; 0x1c .long char_default ; 0x1d .long char_default ; 0x1e .long char_default ; 0x1f .long char_default ; 0x20 = space .long char_store ; 0x21 = ! .long char_default ; 0x22 = " .long char_default ; 0x23 = # .long char_default ; 0x24 = $ .long char_default ; 0x25 = % .long char_default ; 0x26 = & .long char_default ; 0x27 = ' .long char_default ; 0x28 = ( .long char_default ; 0x29 = ) .long char_indir ; 0x2a = * .long char_default ; 0x2b = + .long char_default ; 0x2c = , .long char_default ; 0x2d = - .long char_show_d ; 0x2e = . .long char_default ; 0x2f = / .long char_digit ; 0x30 = 0 .long char_digit ; 0x31 = 1 .long char_digit ; 0x32 = 2 .long char_digit ; 0x33 = 3 .long char_digit ; 0x34 = 4 .long char_digit ; 0x35 = 5 .long char_digit ; 0x36 = 6 .long char_digit ; 0x37 = 7 .long char_digit ; 0x38 = 8 .long char_digit ; 0x39 = 9 .long char_default ; 0x3a = : .long char_default ; 0x3b = ; .long char_default ; 0x3c = < .long char_default ; 0x3d = = .long char_default ; 0x3e = > .long char_show ; 0x3f = ? .long char_fetch ; 0x40 = @ .long char_default ; 0x41 = A .long char_size_1 ; 0x42 = B .long char_default ; 0x43 = C .long char_default ; 0x44 = D .long char_default ; 0x45 = E .long char_default ; 0x46 = F .long char_default ; 0x47 = G .long char_default ; 0x48 = H .long char_default ; 0x49 = I .long char_default ; 0x4a = J .long char_default ; 0x4b = K .long char_size_4 ; 0x4c = L .long char_default ; 0x4d = M .long char_default ; 0x4e = N .long char_default ; 0x4f = O .long char_default ; 0x50 = P .long char_default ; 0x51 = Q .long char_default ; 0x52 = R .long char_default ; 0x53 = S .long char_default ; 0x54 = T .long char_default ; 0x55 = U .long char_default ; 0x56 = V .long char_size_2 ; 0x57 = W .long char_default ; 0x58 = X .long char_default ; 0x59 = Y .long char_default ; 0x5a = Z .long char_default ; 0x5b = [ .long char_default ; 0x5c = \ .long char_default ; 0x5d = ] .long char_default ; 0x5e = ^ .long char_default ; 0x5f = _ .long char_default ; 0x60 = ` .long char_xdigit ; 0x61 = a .long char_xdigit ; 0x62 = b .long char_xdigit ; 0x63 = c .long char_xdigit ; 0x64 = d .long char_xdigit ; 0x65 = e .long char_xdigit ; 0x66 = f .long char_default ; 0x67 = g .long char_default ; 0x68 = h .long char_default ; 0x69 = i .long char_default ; 0x6a = j .long char_default ; 0x6b = k .long char_default ; 0x6c = l .long char_default ; 0x6d = m .long char_default ; 0x6e = n .long char_default ; 0x6f = o .long char_default ; 0x70 = p .long char_default ; 0x71 = q .long char_default ; 0x72 = r .long char_default ; 0x73 = s .long char_default ; 0x74 = t .long char_default ; 0x75 = u .long char_default ; 0x76 = v .long char_default ; 0x77 = w .long char_default ; 0x78 = x .long char_default ; 0x79 = y .long char_default ; 0x7a = z .long char_default ; 0x7b = { .long char_default ; 0x7c = | .long char_default ; 0x7d = } .long char_default ; 0x7e = ~ .long char_default ; 0x7f = DEL .long char_default ; 0x80 .long char_default ; 0x81 .long char_default ; 0x82 .long char_default ; 0x83 .long char_default ; 0x84 .long char_default ; 0x85 .long char_default ; 0x86 .long char_default ; 0x87 .long char_default ; 0x88 .long char_default ; 0x89 .long char_default ; 0x8a .long char_default ; 0x8b .long char_default ; 0x8c .long char_default ; 0x8d .long char_default ; 0x8e .long char_default ; 0x8f .long char_default ; 0x90 .long char_default ; 0x91 .long char_default ; 0x92 .long char_default ; 0x93 .long char_default ; 0x94 .long char_default ; 0x95 .long char_default ; 0x96 .long char_default ; 0x97 .long char_default ; 0x98 .long char_default ; 0x99 .long char_default ; 0x9a .long char_default ; 0x9b .long char_default ; 0x9c .long char_default ; 0x9d .long char_default ; 0x9e .long char_default ; 0x9f .long char_default ; 0xa0 = non-break space .long char_default ; 0xa1 = ¡ .long char_default ; 0xa2 = ¢ .long char_default ; 0xa3 = £ .long char_default ; 0xa4 = ¤ .long char_default ; 0xa5 = ¥ .long char_default ; 0xa6 = ¦ .long char_default ; 0xa7 = § .long char_default ; 0xa8 = ¨ .long char_default ; 0xa9 = © .long char_default ; 0xaa = ª .long char_default ; 0xab = « .long char_default ; 0xac = ¬ .long char_default ; 0xad = ­ .long char_default ; 0xae = ® .long char_default ; 0xaf = ¯ .long char_default ; 0xb0 = ° .long char_default ; 0xb1 = ± .long char_default ; 0xb2 = ² .long char_default ; 0xb3 = ³ .long char_default ; 0xb4 = ´ .long char_default ; 0xb5 = µ .long char_default ; 0xb6 = ¶ .long char_default ; 0xb7 = · .long char_default ; 0xb8 = ¸ .long char_default ; 0xb9 = ¹ .long char_default ; 0xba = º .long char_default ; 0xbb = » .long char_default ; 0xbc = ¼ .long char_default ; 0xbd = ½ .long char_default ; 0xbe = ¾ .long char_default ; 0xbf = ¿ .long char_default ; 0xc0 = À .long char_default ; 0xc1 = Á .long char_default ; 0xc2 = Â .long char_default ; 0xc3 = Ã .long char_default ; 0xc4 = Ä .long char_default ; 0xc5 = Å .long char_default ; 0xc6 = Æ .long char_default ; 0xc7 = Ç .long char_default ; 0xc8 = È .long char_default ; 0xc9 = É .long char_default ; 0xca = Ê .long char_default ; 0xcb = Ë .long char_default ; 0xcc = Ì .long char_default ; 0xcd = Í .long char_default ; 0xce = Î .long char_default ; 0xcf = Ï .long char_default ; 0xd0 = Ð .long char_default ; 0xd1 = Ñ .long char_default ; 0xd2 = Ò .long char_default ; 0xd3 = Ó .long char_default ; 0xd4 = Ô .long char_default ; 0xd5 = Õ .long char_default ; 0xd6 = Ö .long char_default ; 0xd7 = × .long char_default ; 0xd8 = Ø .long char_default ; 0xd9 = Ù .long char_default ; 0xda = Ú .long char_default ; 0xdb = Û .long char_default ; 0xdc = Ü .long char_default ; 0xdd = Ý .long char_default ; 0xde = Þ .long char_default ; 0xdf = ß .long char_default ; 0xe0 = à .long char_default ; 0xe1 = á .long char_default ; 0xe2 = â .long char_default ; 0xe3 = ã .long char_default ; 0xe4 = ä .long char_default ; 0xe5 = å .long char_default ; 0xe6 = æ .long char_default ; 0xe7 = ç .long char_default ; 0xe8 = è .long char_default ; 0xe9 = é .long char_default ; 0xea = ê .long char_default ; 0xeb = ë .long char_default ; 0xec = ì .long char_default ; 0xed = í .long char_default ; 0xee = î .long char_default ; 0xef = ï .long char_default ; 0xf0 = ð .long char_default ; 0xf1 = ñ .long char_default ; 0xf2 = ò .long char_default ; 0xf3 = ó .long char_default ; 0xf4 = ô .long char_default ; 0xf5 = õ .long char_default ; 0xf6 = ö .long char_default ; 0xf7 = ÷ .long char_default ; 0xf8 = ø .long char_default ; 0xf9 = ù .long char_default ; 0xfa = ú .long char_default ; 0xfb = û .long char_default ; 0xfc = ü .long char_default ; 0xfd = ý .long char_default ; 0xfe = þ .long char_default ; 0xff = ÿ alignment_error: .asciz "Alignment error"(CR,LF) size_error: .asciz "Internal size error"(CR,LF) .align 2 ; Print char from r1. ; Destroys r0, gbr. putchar: ldc r14,gbr 1: mov.w @(SCFDR2-SCIF_BASE,gbr),r0 SHXR #SCFDR2_TX_SHIFT,r0 and #SCFDR2_TX_MASK,r0 cmp/eq #16,r0 bt 1b mov r1,r0 mov.b r0,@(SCFTDR2-SCIF_BASE,gbr) rts nop ; Print .asciz string pointed to by r0. ; Destroys r0-r3, gbr, pr. putstr: sts pr,r3 mov r0,r2 bsr 1f nop 1: mov.b @r2+,r0 cmp/eq #0,r0 mov r0,r1 bf putchar jmp @r3 nop ; Prints the low 1+r2 nibbles of r1 in hex, r2>0. ; Destroys r0-r5, gbr, pr. puthex: sts pr,r5 mov.l 9f,r4 mov r1,r3 1: mov r2,r1 shll2 r1 neg r1,r1 mov r3,r0 shld r1,r0 and #0xf,r0 mov.b @(r0,r4),r1 bsr putchar nop dt r2 bf 1b jmp @r5 nop .align 4 9: .long xdigits xdigits: .ascii "0123456789abcdef" .align 2 ; Fetches r0-byte data through r1. ; r0 must be 1, 2, or 4. ; Fetched value is returned in r1; if r0<4, rest of r1 is unspecified. ; If r1%r0!=0, or r0 is invalid, prints a message and jumps through r11. ; Destroys r0; on error, also destroys as for putstr. do_ifetch: add #-1,r0 tst r0,r1 bt 1f mov.l 9f,r0 lds r11,pr bra putstr nop 1: cmp/eq #0,r0 bt 1f cmp/eq #1,r0 bt 2f cmp/eq #3,r0 bt 4f mov.l 8f,r0 lds r11,pr bra putstr nop 1: mov.b @r1,r1 rts nop 2: mov.w @r1,r1 rts nop 4: mov.l @r1,r1 rts nop .align 4 9: .long alignment_error 8: .long size_error .align 2 ; Stores r0-byte data through r1; data comes from r2. ; r0 must be 1, 2, or 4. ; If r1%r0!=0, or r0 is invalid, prints a message and jumps through r11. ; Destroys r0; on error, also destroys as for putstr. do_istore: add #-1,r0 tst r0,r1 bt 1f mov.l 9f,r0 lds r11,pr bra putstr nop 1: cmp/eq #0,r0 bt 1f cmp/eq #1,r0 bt 2f cmp/eq #3,r0 bt 4f mov.l 8f,r0 lds r11,pr bra putstr nop 1: mov.b r2,@r1 rts nop 2: mov.w r2,@r1 rts nop 4: mov.l r2,@r1 rts nop .align 4 9: .long alignment_error 8: .long size_error .align 2 char_default: mov #7,r1 lds r11,pr bra putchar nop char_xdigit: add #9,r1 char_digit: mov #0xf,r2 and r2,r1 SHLL #4,r13,r2 mov r12,r0 SHLR #28,r0,r2 or r0,r13 SHLL #4,r12,r2 or r1,r12 jmp @r11 nop char_size_1: mov #1,r10 jmp @r11 nop char_size_2: mov #2,r10 jmp @r11 nop char_size_4: mov #4,r10 jmp @r11 nop char_show: mova 9f,r0 bsr putstr nop mov r12,r1 mov #8-1,r2 bsr puthex nop mova 8f,r0 bsr putstr nop char_show_d: mov r13,r1 mov r10,r2 shll r2 add #-1,r2 bsr puthex nop mova 7f,r0 lds r11,pr bra putstr nop .align 4 9: .asciz "addr = " .align 4 8: .asciz "value = " .align 4 7: .asciz (CR,LF) .align 2 char_fetch: mov r12,r1 mov r10,r0 bsr do_ifetch nop mov r10,r2 mov r1,r13 shll r2 add #-1,r2 bsr puthex nop mova 9f,r0 lds r11,pr bra putstr nop .align 4 9: .asciz (CR,LF) .align 2 char_indir: mov r12,r1 mov r10,r0 bsr do_ifetch nop mov r1,r13 jmp @r11 nop char_store: mov r10,r0 mov r12,r1 mov r13,r2 lds r11,pr bra do_istore nop