; scif pages 553-598, toc pages viii and ix .include "regs.s" 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 rts mov.l @r15+,r0 .align 4 scif_base: .long SCIF_BASE 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 bsr read_r64cnt ldc r0,gbr 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 rts mov.l @r15+,r0 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 bf/s 1b mov #0,r0 rts nop .align 4 rtc_base: .long RTC_BASE .align 4 main: ; In the pcode machine: ; r15 = conventional stack pointer, for conventional register save/restore use ; r14 = pcode pc ; r13 = pcode dispatch table ; r12 = pcode data stack underflow limit ; r11 = pcode data stack ptr ; r10 = pcode data stack overflow limit ; r9 = pcode rstack underflow limit ; r8 = pcode rstack ptr ; r7 = pcode rstack overflow limit ; r6 = scratch ; r5 = scratch ; r4 = scratch ; r3 = scratch ; r2 = scratch ; r1 = scratch ; r0 = scratch pcode_reset: mov.l code_start,r14 ; pcode pc mov.l code_table,r13 ; fixed mov.l stack_top_ptr,r12 ; fixed mov.l stack_top_ptr,r11 ; pcode data stack ptr mov.l stack_red_ptr,r10 ; fixed mov.l rstack_top_ptr,r9 ; fixed mov.l rstack_top_ptr,r8 ; pcode data stack ptr mov.l rstack_red_ptr,r7 ; fixed mov.l loop_ptr,r0 lds r0,pr mov.l gbr_init,r0 ldc r0,gbr loop_top: cmp/hi r11,r10 bt stack_trouble cmp/hi r12,r11 bt stack_trouble cmp/hi r8,r7 bt stack_trouble cmp/hi r9,r8 bt stack_trouble mov r8,r0 or r11,r0 tst #3,r0 bf stack_trouble mov.b @r14+,r0 shll2 r0 add r13,r0 mov.l @r0,r0 jmp @r0 nop stack_trouble: bra pcode_reset nop .align 4 code_start: .long code_begin code_table: .long pcode_table loop_ptr: .long loop_top stack_top_ptr: .long stack_top stack_red_ptr: .long stack_red rstack_top_ptr: .long rstack_top rstack_red_ptr: .long rstack_red gbr_init: .long data_base pcode_table: .long pcode_00 .long pcode_01 .long pcode_02 .long pcode_03 .long pcode_04 .long pcode_05 .long pcode_06 .long pcode_07 .long pcode_08 .long pcode_09 .long pcode_0a .long pcode_0b .long pcode_0c .long pcode_0d .long pcode_0e .long pcode_0f .long pcode_10 .long pcode_11 .long pcode_12 .long pcode_13 .long pcode_14 .long pcode_15 .long pcode_16 .long pcode_17 .long pcode_18 .long pcode_19 .long pcode_1a .long pcode_1b .long pcode_1c .long pcode_1d .long pcode_1e .long pcode_1f .long pcode_20 .long pcode_21 .long pcode_22 .long pcode_23 .long pcode_24 .long pcode_25 .long pcode_26 .long pcode_27 .long pcode_28 .long pcode_29 .long pcode_2a .long pcode_2b .long pcode_2c .long pcode_2d .long pcode_2e .long pcode_2f .long pcode_30 .long pcode_31 .long pcode_32 .long pcode_33 .long pcode_34 .long pcode_35 .long pcode_36 .long pcode_37 .long pcode_38 .long pcode_39 .long pcode_3a .long pcode_3b .long pcode_3c .long pcode_3d .long pcode_3e .long pcode_3f .long pcode_40 .long pcode_41 .long pcode_42 .long pcode_43 .long pcode_44 .long pcode_45 .long pcode_46 .long pcode_47 .long pcode_48 .long pcode_49 .long pcode_4a .long pcode_4b .long pcode_4c .long pcode_4d .long pcode_4e .long pcode_4f .long pcode_50 .long pcode_51 .long pcode_52 .long pcode_53 .long pcode_54 .long pcode_55 .long pcode_56 .long pcode_57 .long pcode_58 .long pcode_59 .long pcode_5a .long pcode_5b .long pcode_5c .long pcode_5d .long pcode_5e .long pcode_5f .long pcode_60 .long pcode_61 .long pcode_62 .long pcode_63 .long pcode_64 .long pcode_65 .long pcode_66 .long pcode_67 .long pcode_68 .long pcode_69 .long pcode_6a .long pcode_6b .long pcode_6c .long pcode_6d .long pcode_6e .long pcode_6f .long pcode_70 .long pcode_71 .long pcode_72 .long pcode_73 .long pcode_74 .long pcode_75 .long pcode_76 .long pcode_77 .long pcode_78 .long pcode_79 .long pcode_7a .long pcode_7b .long pcode_7c .long pcode_7d .long pcode_7e .long pcode_7f .long pcode_80 .long pcode_81 .long pcode_82 .long pcode_83 .long pcode_84 .long pcode_85 .long pcode_86 .long pcode_87 .long pcode_88 .long pcode_89 .long pcode_8a .long pcode_8b .long pcode_8c .long pcode_8d .long pcode_8e .long pcode_8f .long pcode_90 .long pcode_91 .long pcode_92 .long pcode_93 .long pcode_94 .long pcode_95 .long pcode_96 .long pcode_97 .long pcode_98 .long pcode_99 .long pcode_9a .long pcode_9b .long pcode_9c .long pcode_9d .long pcode_9e .long pcode_9f .long pcode_a0 .long pcode_a1 .long pcode_a2 .long pcode_a3 .long pcode_a4 .long pcode_a5 .long pcode_a6 .long pcode_a7 .long pcode_a8 .long pcode_a9 .long pcode_aa .long pcode_ab .long pcode_ac .long pcode_ad .long pcode_ae .long pcode_af .long pcode_b0 .long pcode_b1 .long pcode_b2 .long pcode_b3 .long pcode_b4 .long pcode_b5 .long pcode_b6 .long pcode_b7 .long pcode_b8 .long pcode_b9 .long pcode_ba .long pcode_bb .long pcode_bc .long pcode_bd .long pcode_be .long pcode_bf .long pcode_c0 .long pcode_c1 .long pcode_c2 .long pcode_c3 .long pcode_c4 .long pcode_c5 .long pcode_c6 .long pcode_c7 .long pcode_c8 .long pcode_c9 .long pcode_ca .long pcode_cb .long pcode_cc .long pcode_cd .long pcode_ce .long pcode_cf .long pcode_d0 .long pcode_d1 .long pcode_d2 .long pcode_d3 .long pcode_d4 .long pcode_d5 .long pcode_d6 .long pcode_d7 .long pcode_d8 .long pcode_d9 .long pcode_da .long pcode_db .long pcode_dc .long pcode_dd .long pcode_de .long pcode_df .long pcode_e0 .long pcode_e1 .long pcode_e2 .long pcode_e3 .long pcode_e4 .long pcode_e5 .long pcode_e6 .long pcode_e7 .long pcode_e8 .long pcode_e9 .long pcode_ea .long pcode_eb .long pcode_ec .long pcode_ed .long pcode_ee .long pcode_ef .long pcode_f0 .long pcode_f1 .long pcode_f2 .long pcode_f3 .long pcode_f4 .long pcode_f5 .long pcode_f6 .long pcode_f7 .long pcode_f8 .long pcode_f9 .long pcode_fa .long pcode_fb .long pcode_fc .long pcode_fd .long pcode_fe .long pcode_ff pcode_26: pcode_27: pcode_28: pcode_29: pcode_2a: pcode_2b: pcode_2c: pcode_2d: pcode_2e: pcode_2f: pcode_30: pcode_31: pcode_32: pcode_33: pcode_34: pcode_35: pcode_36: pcode_37: pcode_38: pcode_39: pcode_3a: pcode_3b: pcode_3c: pcode_3d: pcode_3e: pcode_3f: pcode_40: pcode_41: pcode_42: pcode_43: pcode_44: pcode_45: pcode_46: pcode_47: pcode_48: pcode_49: pcode_4a: pcode_4b: pcode_4c: pcode_4d: pcode_4e: pcode_4f: pcode_50: pcode_51: pcode_52: pcode_53: pcode_54: pcode_55: pcode_56: pcode_57: pcode_58: pcode_59: pcode_5a: pcode_5b: pcode_5c: pcode_5d: pcode_5e: pcode_5f: pcode_60: pcode_61: pcode_62: pcode_63: pcode_64: pcode_65: pcode_66: pcode_67: pcode_68: pcode_69: pcode_6a: pcode_6b: pcode_6c: pcode_6d: pcode_6e: pcode_6f: pcode_70: pcode_71: pcode_72: pcode_73: pcode_74: pcode_75: pcode_76: pcode_77: pcode_78: pcode_79: pcode_7a: pcode_7b: pcode_7c: pcode_7d: pcode_7e: pcode_7f: pcode_80: pcode_81: pcode_82: pcode_83: pcode_84: pcode_85: pcode_86: pcode_87: pcode_88: pcode_89: pcode_8a: pcode_8b: pcode_8c: pcode_8d: pcode_8e: pcode_8f: pcode_90: pcode_91: pcode_92: pcode_93: pcode_94: pcode_95: pcode_96: pcode_97: pcode_98: pcode_99: pcode_9a: pcode_9b: pcode_9c: pcode_9d: pcode_9e: pcode_9f: pcode_a0: pcode_a1: pcode_a2: pcode_a3: pcode_a4: pcode_a5: pcode_a6: pcode_a7: pcode_a8: pcode_a9: pcode_aa: pcode_ab: pcode_ac: pcode_ad: pcode_ae: pcode_af: pcode_b0: pcode_b1: pcode_b2: pcode_b3: pcode_b4: pcode_b5: pcode_b6: pcode_b7: pcode_b8: pcode_b9: pcode_ba: pcode_bb: pcode_bc: pcode_bd: pcode_be: pcode_bf: pcode_c0: pcode_c1: pcode_c2: pcode_c3: pcode_c4: pcode_c5: pcode_c6: pcode_c7: pcode_c8: pcode_c9: pcode_ca: pcode_cb: pcode_cc: pcode_cd: pcode_ce: pcode_cf: pcode_d0: pcode_d1: pcode_d2: pcode_d3: pcode_d4: pcode_d5: pcode_d6: pcode_d7: pcode_d8: pcode_d9: pcode_da: pcode_db: pcode_dc: pcode_dd: pcode_de: pcode_df: pcode_e0: pcode_e1: pcode_e2: pcode_e3: pcode_e4: pcode_e5: pcode_e6: pcode_e7: pcode_e8: pcode_e9: pcode_ea: pcode_eb: pcode_ec: pcode_ed: pcode_ee: pcode_ef: pcode_f0: pcode_f1: pcode_f2: pcode_f3: pcode_f4: pcode_f5: pcode_f6: pcode_f7: pcode_f8: pcode_f9: pcode_fa: pcode_fb: pcode_fc: pcode_fd: pcode_fe: pcode_ff: bra pcode_reset nop ; OP_CHKINPUT - try to read input ; If char available, pushes char then 1 ; If no char available, pushes 0 OP_CHKINPUT = 0x00 .align 2 pcode_00: stc.l gbr,@-r15 mov.l 9f,r0 ldc r0,gbr mov.w @(SCFDR2-SCIF_BASE,gbr),r0 .if SCFDR2_RX_SHIFT != 0 .error Code assumes SCFDR2_RX_SHIFT is 0! .endif tst #SCFDR2_RX_MASK,r0 bt 1f mov.w @(SCFSR2-SCIF_BASE,gbr),r0 tst #SCFSR2_FER|SCFSR2_PER,r0 mov.b @(SCFRDR2-SCIF_BASE,gbr),r0 mov r0,r1 mov.w @(SCLSR2-SCIF_BASE,gbr),r0 mov #0,r0 mov.w r0,@(SCLSR2-SCIF_BASE,gbr) bf 1f mov #1,r0 bra 2f mov.l r1,@-r11 1: mov #0,r0 2: mov.l r0,@-r11 rts ldc.l @r15+,gbr .align 4 9: .long SCIF_BASE ; OP_CHKOUTPUT - try to print output if any queued ; Nothing consumed, nothing pushed. OP_CHKOUTPUT = 0x01 .align 2 pcode_01: mov.l @(outn-data_base,gbr),r0 cmp/eq #0,r0 bt 4f mov r0,r1 mov.l 9f,r2 mov.l @(outbuf-data_base,gbr),r0 mov r0,r3 mov.l @(outt-data_base,gbr),r0 mov r0,r4 mov.l 8f,r5 mov.l @(outmax-data_base,gbr),r0 mov r0,r6 3: mov.w @r2,r0 .if SCFDR2_TX_SHIFT != 8 .error Code assumes SCFDR2_RX_SHIFT is 8! .endif shlr8 r0 and #SCFDR2_TX_MASK,r0 cmp/eq #16,r0 bt 1f mov r4,r0 mov.b @(r0,r3),r0 mov.b r0,@r5 add #1,r4 cmp/hs r6,r4 bf 2f sub r6,r4 2: dt r1 bf 3b 1: mov r1,r0 mov.l r0,@(outn-data_base,gbr) mov r4,r0 mov.l r0,@(outt-data_base,gbr) 4: rts nop .align 4 9: .long SCFDR2 8: .long SCFTDR2 ; OP_IFZ_1 - conditional branch, one-byte displacement. ; Branches if value popped is zero. OP_IFZ_1 = 0x02 .align 2 pcode_02: mov.l @r11+,r0 cmp/eq #0,r0 mov.b @r14+,r1 bf 1f add r1,r14 1: rts nop ; OP_CONST_U1 - push a one-byte constant, zero-extended. OP_CONST_U1 = 0x03 .align 2 pcode_03: mov.b @r14+,r0 extu.b r0,r0 rts mov.l r0,@-r11 ; OP_CBR_DUP_EQ - conditional branch ; x y -- x, branch if x==y OP_CBR_DUP_EQ = 0x04 .align 2 pcode_04: mov.l @r11+,r0 mov.l @r11,r1 mov.b @r14+,r2 cmp/eq r0,r1 bf 1f add r2,r14 1: rts nop ; OP_PRINTCHAR - pop a value from the stack and queue it for printing. OP_PRINTCHAR = 0x05 .align 2 pcode_05: mov.l @r11+,r4 mov.l @(outn-data_base,gbr),r0 mov r0,r1 mov.l @(outmax-data_base,gbr),r0 cmp/hi r1,r0 bf/s 1f mov r0,r2 mov.l @(outbuf-data_base,gbr),r0 mov r0,r3 mov.l @(outh-data_base,gbr),r0 mov.b r4,@(r0,r3) add #1,r0 cmp/hs r2,r0 bf 2f sub r2,r0 2: mov.l r0,@(outh-data_base,gbr) add #1,r1 mov r1,r0 mov.l r0,@(outn-data_base,gbr) 1: rts nop ; OP_BRANCH_1 - unconditional branch, one-byte displacement. OP_BRANCH_1 = 0x06 .align 2 pcode_06: mov.b @r14+,r1 rts add r1,r14 ; OP_IFNZ_1 - conditional branch, one-byte displacement. ; Branches if value popped is nonzero. OP_IFNZ_1 = 0x07 .align 2 pcode_07: mov.l @r11+,r0 cmp/eq #0,r0 mov.b @r14+,r1 bt 1f add r1,r14 1: rts nop ; OP_DUP - copy top of stack OP_DUP = 0x08 pcode_08: mov.l @r11,r0 rts mov.l r0,@-r11 ; OP_POP - pop and discard top-of-stack value. OP_POP = 0x09 pcode_09: rts add #4,r11 ; OP_CBR_DUP_GES - conditional branch ; x y -- x, branch if x>=y signed OP_CBR_DUP_GES = 0x0a .align 2 pcode_0a: mov.l @r11+,r0 mov.l @r11,r1 mov.b @r14+,r2 cmp/ge r0,r1 bf 1f add r2,r14 1: rts nop ; OP_CBR_DUP_LEU - conditional branch ; x y -- x, branch if x<=y unsigned OP_CBR_DUP_LEU = 0x0b .align 2 pcode_0b: mov.l @r11+,r0 mov.l @r11,r1 mov.b @r14+,r2 cmp/hs r1,r0 bf 1f add r2,r14 1: rts nop ; OP_LD_GBR_L - load long from GBR + inline byte OP_LD_GBR_L = 0x0c .align 2 pcode_0c: mov.b @r14+,r0 stc gbr,r1 mov.l @(r0,r1),r1 rts mov.l r0,@-r11 ; OP_ST_GBR_L - store top-of-stack long to GBR + inline byte OP_ST_GBR_L = 0x0d .align 2 pcode_0d: mov.b @r14+,r0 mov.l @r11+,r2 stc gbr,r1 rts mov.l r2,@(r0,r1) ; OP_ADD - add two top of stack values; sum goes back on stack OP_ADD = 0x0e .align 2 pcode_0e: mov.l @r11+,r0 mov.l @r11+,r1 add r1,r0 rts mov.l r0,@-r11 ; OP_STORE - store TOS[1] through TOS[0] OP_STORE = 0x0f .align 2 pcode_0f: mov.l @r11+,r0 mov.l @r11+,r1 rts mov.l r1,@r0 ; OP_OVER - x y -- x y x OP_OVER = 0x10 .align 2 pcode_10: mov.l @(4,r11),r0 rts mov.l r0,@-r11 ; OP_SWAP - swap top two values on stack ; x y -- y x OP_SWAP = 0x11 .align 2 pcode_11: mov.l @r11+,r0 mov.l @r11+,r1 mov.l r0,@-r11 rts mov.l r1,@-r11 ; OP_CONST_0 - push zero OP_CONST_0 = 0x12 .align 2 pcode_12: mov #0,r0 rts mov.l r0,@-r11 ; OP_CBR_DUP_LTS - conditional branch ; x y -- x, branch if x0 ; r1 points to xN mov r0,r2 add #-1,r2 shll2 r2 add r2,r1 mov.l @(4,r1),r3 1: mov.l @r1,r2 dt r0 mov.l r2,@(4,r1) bf/s 1b add #-4,r1 rts mov.l r3,@(4,r1) ; OP_PICK -- dup deep element onto top ; xN ... x1 N -- xN ... x1 xN ; if N < 1, error (reset) OP_PICK = 0x23 .align 2 pcode_23: mov.l @r11,r0 cmp/pl r0 bt/s 1f shll2 r0 bra pcode_reset nop 1: mov.l @(r0,r11),r0 rts mov.l r0,@r11 ; OP_ROT - x y z -- y z x OP_ROT = 0x24 .align 2 pcode_24: mov.l @r11+,r0 mov.l @r11+,r1 mov.l @r11+,r2 mov.l r1,@-r11 mov.l r0,@-r11 rts mov.l r2,@-r11 ; OP_BRANCH_2 - unconditional branch, two-byte displacement. OP_BRANCH_2 = 0x25 .align 2 pcode_25: mov.b @r14+,r0 mov.b @r14+,r1 shll8 r0 extu.b r1,r1 or r1,r0 rts add r0,r14 .align 4 data_base: linelen: .space 4 inbuf: .long inspace outbuf: .long outspace inmax: .long insize outmax: .long outsize outh: .space 4 outt: .space 4 outn: .space 4 .align 2 inspace: .space 256 insize = . - inspace outspace: .space 256 outsize = . - outspace ; stack: .space 64 ; overflow redzone stack_red: .space 65536 ; data stack stack_top: .space 64 ; data stack underflow redzone; rstack overflow redzone rstack_red: .space 256 ; return stack rstack_top: .space 32 ; rstack underflow redzone code_begin: reprompt: .byte OP_ASCIZ .asciz "test> " .byte OP_CALL_1R, @SB[printstr-[.+1]] mainloop: .byte OP_CHKINPUT .byte OP_CHKOUTPUT ; char 1, or 0 .byte OP_IFZ_1, @SB[mainloop-[.+1]] .byte OP_CONST_U1, @UB[10] .byte OP_CBR_DUP_EQ, @SB[eol-[.+1]] .byte OP_CONST_U1, @UB[13] .byte OP_CBR_DUP_EQ, @SB[eol-[.+1]] .byte OP_CONST_U1, @UB[32] .byte OP_CBR_DUP_LTS, @SB[invalid_char-[.+1]] .byte OP_CONST_U1, @UB[126] .byte OP_CBR_DUP_LTS, @SB[valid_char-[.+1]] .byte OP_CONST_U1, @UB[160] .byte OP_CBR_DUP_GES, @SB[valid_char-[.+1]] invalid_char: ; junkchar .byte OP_POP .byte OP_CONST_U1, @UB[7] .byte OP_PRINTCHAR .byte OP_BRANCH_1, @SB[mainloop-[.+1]] printstr: ; ptr len -- 1: .byte OP_CONST_0 .byte OP_CBR_DUP_LEU, @SB[1f-[.+1]] .byte OP_CONST_1 .byte OP_SUB .byte OP_SWAP .byte OP_DUP .byte OP_FETCHC .byte OP_PRINTCHAR .byte OP_CONST_1 .byte OP_ADD .byte OP_SWAP .byte OP_BRANCH_1, @SB[1b-[.+1]] 1: .byte OP_POP, OP_POP .byte OP_RET valid_char: ; char .byte OP_LD_GBR_L, @UB[linelen-data_base] ; char linelen .byte OP_LD_GBR_L, @UB[inmax-data_base] ; char linelen inmax .byte OP_CBR_DUP_LTU, @SB[1f-[.+1]] ; char linelen .byte OP_POP .byte OP_BRANCH_1, @SB[invalid_char-[.+1]] 1: ; char linelen .byte OP_SWAP .byte OP_DUP .byte OP_PRINTCHAR .byte OP_OVER ; linelen char linelen .byte OP_LD_GBR_L, @UB[inbuf-data_base] .byte OP_ADD .byte OP_STORE ; linelen .byte OP_CONST_1 .byte OP_ADD .byte OP_ST_GBR_L, @UB[linelen-data_base] .byte OP_BRANCH_1, @SB[mainloop-[.+1]] isspace: .byte OP_CONST_U1, @UB[' ] ; space .byte OP_CBR_DUP_EQ, @SB[1f-[.+1]] .byte OP_CONST_U1, @UB[9] ; tab .byte OP_CBR_DUP_EQ, @SB[1f-[.+1]] .byte OP_POP .byte OP_CONST_0 .byte OP_RET 1: .byte OP_POP .byte OP_CONST_1 .byte OP_RET eol: .byte OP_CONST_U1, @UB[13] .byte OP_PRINTCHAR .byte OP_CONST_U1, @UB[10] .byte OP_PRINTCHAR .byte OP_LD_GBR_L, @UB[inbuf-data_base] .byte OP_LD_GBR_L, @UB[linelen-data_base] .byte OP_CONST_0 1: ; base len inx .byte OP_PICK_3 .byte OP_OVER .byte OP_ADD .byte OP_FETCHC .byte OP_CALL_1R, @SB[isspace-[.+1]] .byte OP_CBR_IFNZ, @SB[1f-[.+1]] .byte OP_CONST_1 .byte OP_ADD .byte OP_BRANCH_1, @SB[1b-[.+1]] 1: .byte OP_DUP .byte OP_CONST_U1, @UB[4] .byte OP_ROTATE 1: .byte OP_PICK_3 .byte OP_OVER .byte OP_ADD .byte OP_FETCHC .byte OP_CALL_1R, @SB[isspace-[.+1]] .byte OP_CBR_IFZ, @SB[1f-[.+1]] .byte OP_CONST_1 .byte OP_ADD .byte OP_BRANCH_1, @SB[1b-[.+1]] 1: ; startinx base len endinx .byte OP_CONST_U1, @UB[4] .byte OP_ROTATE_NEG ; base len endinx startinx .byte OP_DUP2 .byte OP_SUB ; base len endinx startinx wordlen .byte OP_CONST_U1, @UB[5] .byte OP_PICK .byte OP_ROT .byte OP_ADD .byte OP_SWAP ; base len endinx startptr wordlen .byte OP_DUP .byte OP_CBR_IFNZ, @SB[1f-[.+1]] .byte OP_MPOP, @UB[5] .byte OP_BRANCH_2 .word @SW[reprompt-[.+1]] 1: