;version 2.17 revised on 7-11-00 by alexandra carey ; to include LCDINT, a procedure that displays an int to LCD. ;version 2.17 revised on 5-14-00 by CWM to avoid LCD_CMD data clobbering ;version 2.17 revised on 5-12-00 by Cliff McIntire to remove CR at end of ; OutString ;version 2.17 revised on 2-29-00 by Corey Baker to avoid clobbering of data ; Startup Runtime Code for 12c 68hc11 Microcontroller Kit laboratory projects. ; This code is needed when using either the simulator only, or when ; producing files for download to the 12c trainer board. Sections are ; conditionally assembled depending on whether the target is the simulator ; or trainer board. ; HISTORY: ; //version 1.0 25 Feb 99 ; First version to get students up and running with the development system ; employing the simulator. It was not tested with the Trainer Board. ; //version 2.0 8 Feb 99/scp ; Modified to include the i/o UART procedures in the assembled user code. ; Procedure Description ; ------------- ---------------------------------------------------------- ; GETCHAR Reads a single character from the SCI port. ; OUTCRLF Write a carriage-return and line-feed out the SCI port. ; OUTCHAR Write a character out the SCI port. ; OUTSTRING Writes a null-terminated string out the SCI port ; SETUPSCI Setup HC11 UART for 9600bps. ; WAIT Software delay loop with 4.096ms resolution. ; ; //version 2.16 1 May 99/scp ; Included device drivers to manage output to the LCD: ; LCDLINE Writes a null-terminated string to the LCD ; call with A = 1 --> line1 ; A = 2 --> line2 ; x = pointer to first character of string ; LCD_CMD Writes to the LCD Command Register ; LCD_CHAR Writes to the LCD Character Array (for display) ; //version 2.17 20 May 99/scp (search for "build 17:" to see changes) ; Added support for user interrupts. Note that ver2.16 does not support ; user hooks into the sram image table. Everything else is otherwise identical. ; Several minor changes were made involving the simulator that were not flagged. ; 2.17.1 4 June 99/scp ; added cli to LCD_CMD and LCD_CHAR since interrupts are used in both. ;************************************************************************** ; The following should be the first line in your code when you want to run your ; program from within the simulator: ; $SET simulate ; ; When you are ready to download it to the 12c trainer board, the line should ; read: ; $SETNOT simulate ; ; Basic memory map: REGBASE EQU $8000 ;start of 68HC11's 64-byte register block. ROMBASE EQU $8040 ;start of ROM. RAMBASE EQU $1000 ;start of user RAM area. RAMTOP EQU $7BC0 ;top of user RAM area. ************************************************************************** * These equates define i/o devices (as hardware ports) implemented on the 12c * HC11 Trainer Board SWITCHES EQU $7C00 ;switches. LCD_CMD_REG EQU $7c80 ;lcd command. LCD_CHAR_REG EQU $7c81 ;lcd character. LEDS EQU $7d00 ;leds. DAC EQU $7d80 ;D/A. IOCS4 EQU $7e00 ;io expansion port. IOCS5 EQU $7e80 ; " IOCS6 EQU $7f00 ; " IOCS7 EQU $7f80 ; " NULL EQU $00 ;end of text/table. ;build 17: CR EQU $0D ;carriage return. LF EQU $0A ;line feed. ESC EQU $1B ;escape character user_isr EQU $7BC1 ;base of user interrupt jump table. _gocode EQU $8040 ;beginning of user monitor code. ; build 17: ; Ram isr image table jump addresses. Note the table is ordinal and that some vectors ; are not available to the user. These are used or reserved for the system and have not ; been mapped from the corresponding ROM table. See Motorola documentation for discussion ; of these vectors. ; 1 unavailable to user SCI ISR_JUMP2 EQU $7BC5 ;SPI ISR_JUMP3 EQU $7BC8 ;Pulse Accumulator Input ISR_JUMP4 EQU $7BCB ;Pulse Accumulator Overflow ; 5 unavailable to user Timer Overflow ; 6 unavailable to user Output Compare 5 ISR_JUMP7 EQU $7BD4 ;Output Compare 4 ISR_JUMP8 EQU $7BD7 ;Output Compare 3 ISR_JUMP9 EQU $7BDA ;Output Compare 2 ISR_JUMP10 EQU $7BDE ;Output Compare 1 ISR_JUMP11 EQU $7BE3 ;Input Capture 3 ISR_JUMP12 EQU $7BE6 ;Input Capture 2 ISR_JUMP13 EQU $7BE9 ;Input Capture 1 ; 14 unavailable to user Real Time Interrupt ISR_JUMP15 EQU $7BEC ;IRQ ; 16 unavailable to user XIRQ ; 17 unavailable to user SWI ; 18 unavailable to user Illegal Opcode ISR_JUMP19 EQU $7BF8 ;Cop fail ISR_JUMP20 EQU $7BFB ;Cop clock fail ; 21 unavailable to user Reset (found at 0x8040) ************************************************************************** * Some of the internal 64 registers are defined here. Their definitions * should be self-evident from the Motorola manuals. BAUD EQU REGBASE+$2B ;sci baud register SCCR1 EQU REGBASE+$2C ;sci control1 register SCCR2 EQU REGBASE+$2D ;sci control2 register SCSR EQU REGBASE+$2E ;sci status register SCDR EQU REGBASE+$2F ;sci data register ************************************************************************** * Useful system variables * These may change if the monitor software is changed. * O.k. ver2.17// * Addresses can be found in the linker map file. _GETCHR EQU $8A0A ;char getchr(void) IRQCOUNT EQU $02D5 ;16-bit integer that increments each time IRQ is called _PUTCHR EQU $89E5 ;char putchar(char c) TICSEC EQU $02E3 ;16-bit integer that increments once each second. _WAIT EQU $8A37 ;software timer 4.096 ms per tick, argument in x-reg. ;build 17: USERTICK EQU $02D7 ;unsigned int incremented every 4.096ms by system clock IRQDEBOUNCE EQU $02D3 ; $IF simulate ************************************************************************** * 68hc11 interrupt ROM interrupt vector table. This ordinal table begins * at 0xffd6 and ends at 0xffff. Each vector entry is 16 bits and points * into a user-editable area of RAM. Although all are shown mapped in the * simulator, not all are actually mapped in the Microkit. See RAM isr jump * table notations above. * ORG $FFD6 DW user_isr ; SCI DW user_isr+3T ; SPI DW user_isr+6T ; Pulse acc input DW user_isr+9T ; Pulse acc overf DW user_isr+12T ; Timer overf DW user_isr+15T ; Output compare 5 DW user_isr+18T ; Output compare 4 DW user_isr+21T ; Output compare 3 DW user_isr+24T ; Output compare 2 DW user_isr+27T ; Output compare 1 DW user_isr+30T ; Input capture 3 DW user_isr+33T ; Input capture 2 DW user_isr+36T ; Input capture 1 DW user_isr+39T ; Real time DW user_isr+42T ; IRQ DW user_isr+45T ; XIRQ DW user_isr+48T ; SWI DW user_isr+51T ; illegal DW user_isr+54T ; cop fail DW user_isr+57T ; cop clock fail DW _gocode ; RESET *********************************************************** * Procedure ISRSTUB ORG $7bff isrstub: RTI *********************************************************** * User ISR vector area. * ORG user_isr JMP isrstub ; SCI JMP isrstub ; SPI JMP isrstub ; Pulse acc input JMP isrstub ; Pulse acc overf JMP isrstub ; Timer overf JMP isrstub ; Output compare 5 JMP isrstub ; Output compare 4 JMP isrstub ; Output compare 3 JMP isrstub ; Output compare 2 JMP isrstub ; Output compare 1 JMP isrstub ; Input capture 3 JMP isrstub ; Input capture 2 JMP isrstub ; Input capture 1 JMP isrstub ; Real time JMP isrstub ; IRQ JMP isrstub ; XIRQ JMP isrstub ; SWI JMP isrstub ; illegal opcode JMP isrstub ; cop fail JMP isrstub ; cop clock fail JMP isrstub ; RESET ; reset vector starts here: ORG ROMBASE ; move the internal 64 byte register block to 8000h LDAA #$08 ; content of INIT register STAA $103d ; load INIT at $103D ; These initializations keep the simulator happy. Loading from an ; uninitialized register (cpu or memeory) will flag an error. So, ; event though Switches, for example, is really only an input port on ; the Microkit, reading it requires that we initialize it with something. ; This is true of the other input ports as well. LDD #$0000 ; default LDY #$0000 ; default LDAB #$00 ; default LDAA #$00 ; default STAA SWITCHES ; I: default switch settings STAA LEDS ; O: default all-on leds STAA LCD_CMD ; I/O: default STAA LCD_CHAR ; I/O: default STAA DAC ; O: default LDX #RAMTOP ; set default stack TXS ; JSR SETUPSCI ; intialize serial port to mimic the Microkit. JMP main *********************************************************** * Procedure to setup HC11 UART for 9600bps when used with the simulator * This is called automatically when the simulator is targeted. * xtal = 8MHz SETUPSCI: PSHA LDAA #$30 STAA BAUD LDAA #$00 STAA SCCR1 LDAA #$2C STAA SCCR2 PULA RTS $ELSEIF ;// Microkit ORG RAMBASE JMP main $ENDIF ************************************************************************** * Writes a carriage-return and line-feed out the SCI port OUTCRLF: PSHA LDAA #$0D ;cr JSR OUTCHAR ;write it out LDAA #$0A ;lf JSR OUTCHAR ;write it out PULA RTS ************************************************************************** * Writes a NULL terminated string out the SCI port * Index register x points to first byte of null-terminated string OUTSTRING: PSHA _outstring0: LDAA 0,X CMPA #NULL BEQ _outstring1 JSR OUTCHAR INX BRA _outstring0 _outstring1: PULA ;by CWM 5-12-00 ; jsr OUTCRLF RTS ************************************************************************** * Writes a null-terminated line of text to the Optrex Liquid Crystal Display * Input: A = 1 --> line1 * A = 2 --> line2 * x = pointer to first character of string (null-termineated) LCDLINE: PSHA CMPA #$01 ;which line test BEQ _lcdline1 LDAA #$A8 ;line 1 command JMP _lcdline2 _lcdline1: LDAA #$80 ;line 2 command _lcdline2: JSR LCD_CMD ;write to command register _lcdline3: LDAA 0,X CMPA #NULL BEQ _lcdline4 JSR LCD_CHAR INX BRA _lcdline3 _lcdline4: PULA RTS ************************************************************************** * Writes to the LCD Character Register * Input: a LCD_CHAR: PSHX PSHY $IFNOT simulate PSHA PSHB LDD #$0001 ;8.1 ms wait CLI JSR WAIT PULB ;lcd_char0: LDAA LCD_CMD ; ROLA ; BCS _lcd_char0 PULA $ENDIF STAA LCD_CHAR_REG PULY PULX RTS ************************************************************************** * Writes to the LCD Command Register * Input: a LCD_CMD: PSHX PSHY $IFNOT simulate PSHA PSHB ;CWM 5-14-00 LDD #$000f ;big wait CLI JSR WAIT PULB ;CWM 5-14-00 PULA $ENDIF STAA LCD_CMD_REG PULY PULX RTS ************************************************************************** * Reads a single character from the SCI port. * Returns result in accumulator A GETCHAR: $IF simulate LDAA SCSR ;status register ANDA #$20 ;rdrf bit mask BEQ GETCHAR ;loop if rdrf = 0 LDAA SCDR ;read data _getchar1: RTS $ELSEIF PSHB JSR _getchr ;calls getchr() in system TBA PULB RTS $ENDIF ************************************************************************** * Write a character out the SCI port * Character is in the A accumulator OUTCHAR: $IF simulate PSHB LDAB SCSR ;load sci status register BITB #$80 ;tdre bit BEQ OUTCHAR ;loop until tdre = 1 STAA SCDR ;write character to port PULB RTS $ELSEIF PSHB PSHX TAB ABX JSR _putchr ;calls putchr() in system TBA PULX PULB RTS $ENDIF ************************************************************************** * LCDINT * By Cliff and Alex * Displays an unsigned integer to LCD from ACCD * Clobbers no registers! * Input: D DIVISOR: DW $00 REMAINDER: DW $00 LCDINT: ;Expects: 16-bit unsigned integer in ACCD ;Returns: nothing ;Notes: prints ACCD to LCD. If input is negative, prints 0. pshx pshy psha pshb std REMAINDER ldd #0 cpd REMAINDER blt notzero ldaa #$30 jsr LCD_CHAR bra printloopend notzero: ;find the greatest divisor ldd #$2710 ;10000 ldx #$a ;10 finddiv: cpd REMAINDER ble endfinddiv idiv xgdx ;d->quo x->rem ldx #!10 bra finddiv endfinddiv: std DIVISOR ldd REMAINDER ldx DIVISOR printloop: ;decrement divisor, get next remainder & quotient ;print each quotient in turn idiv xgdx tba adda #$30 jsr lcd_char stx REMAINDER ldd DIVISOR ldx #$a idiv cpx #$0 ;exit if quo=0 beq printloopend stx DIVISOR ldd REMAINDER bra printloop printloopend: pulb pula puly pulx rts ************************************************************************** * Software time-wasting loop. _WAIT maps to the actual wait() procedure in * the monitor, which uses the master system timer to count down an argument * variable in the D-Register. Each decrement occurs at 4.096ms intervals. * Input: D -> total delay = D * (4.096E-3) seconds WAIT: $IFNOT simulate pshy JSR _WAIT puly $ENDIF RTS $IF simulate * The simulator is too dumb to know that the 64-byte embedded register block that * defaults to 0x1000 when the HC11 boots is re-mapped to 0x8000 * when the code is run, so it flags an error at load time. Oddly enough, * after running the code once, the simulator will then accept code organized * at 0x1000. * Hack: locate it just past the 64 byte boundry. ORG $1040 $ENDIF