************************************************************************** * Parameter Declearation Section * * Export Symbols xdef pgstart ; export 'pgstart' symbol absentry pgstart ; for assembly entry point * Symbols and Macros PORTA equ $0000 ; i/o port A addresses DDRA equ $0002 ; data direction register for PORTA PORTB equ $0001 ; i/o port B addresses DDRB equ $0003 ; data direction register for PORTB SCIBDH equ $00C8 ; Serial port (SCI) Baud Register H SCIBDL equ $00C9 ; Serial port (SCI) Baud Register L SCICR2 equ $00CB ; Serial port (SCI) Control Register 2 SCISR1 equ $00CC ; Serial port (SCI) Status Register 1 SCIDRL equ $00CF ; Serial port (SCI) Data Register CRGFLG EQU $0037 ; Clock and Reset Generator Flags CRGINT EQU $0038 ; Clock and Reset Generator Interrupts RTICTL EQU $003B ; Real Time Interrupt Control CR equ $0d ; carriage return, ASCII 'Return' key LF equ $0a ; line feed, ASCII 'next line' character NULL equ $00 ; NULL Terminator character ************************************************************************** * Data Section: address used [ $3000 to $30FF ] RAM Memory * org $3000 ; Reserved RAM memory starting address ; for Data for CMPEN 472 class buffer ds.b $0010 ; Array of 16 bytes to read a string dc.b NULL ; NULL terminated lenBuf dc.w $0010 ; Length of buffer array buffer2 ds.b $0010 ; Array of 16 bytes for reading and reversal dc.b NULL ; NULL terminated lenBuf2 dc.w $0010 ; length of buffer2 hours dc.w $0000 ; Buffer to hold the hours of the time minutes dc.w $0000 ; Buffer to hold the minutes of the time seconds dc.w $0000 ; Buffer to hold the seconds of the time counter dc.w $0000 ; Counter for RTI ISR for 1 second numBuf dc.b $0000 ; Used by ReadDecimal for reading numbers operator dc.b $0000 ; Used by ReadDecimal for reading numbers inputBuffer ds.b $0010 ; Input Buffer Length lenInput dc.w $0010 ; Length of the Input Buffer outputBuf dc.b 'h' ; Used to control what to output on 7 segment display n1 dc.b $03 dc.b $04 dc.b $05 n2 dc.b $06 dc.b $07 dc.b $08 * ************************************************************************** * RTI Vector Section: address used [ $FFF0 to $FFF1 ] RAM Memory * org $FFF0 ; Memory location for RTI interrupt vector section for simulator dc.w rtiisr ; Real Time Interrupt vector * ************************************************************************** * Program Section: address used [ $3100 to $3FFF ] RAM Memory * org $3100 ; Program start address, in RAM pgstart lds #$3100 ; initialize the stack pointer ldaa #%11110001 ; LED 1,2,3,4 at PORTB bit 4,5,6,7 staa DDRB ; set PORTB bit 4,5,6,7 as output ldaa #$0C ; Enable SCI port Tx and Rx units staa SCICR2 ; disable SCI interrupts ldd #$0001 ; Set SCI Baud Register = $0001 => 1.5M baud at 24MHz (for simulation) std SCIBDH ; SCI port baud rate change bset RTICTL,%00011001; set RTI: dev=10*(2**10)=2.555msec for C128 board ; 4MHz quartz oscillator clock bset CRGINT,%10000000; enable RTI interrupt bset CRGFLG,%10000000; clear RTI IF (Interrupt Flag) ldaa #$FF ; Two 7 segment displays on PORTB staa DDRB ; Set all of PORTB as output cli mainLoop ldaa #3 psha ldaa #4 psha ldaa #5 psha ldd #0 jsr SORT pula pula pula jsr add3 ldaa #200 clrb loopy incb suba #$01 ble loopy ldaa #$65 ldab #$43 ldx #256 idiv tba jsr putchar xgdx tba jsr putchar bra mainLoop ; Loop back to mainLoop always ************************************************************************** * Subroutine Section: address used [ $3100 to $3FFF ] RAM Memory * SORT pshb ldab 3,sp cmpb 4,sp bls skip movb 4,sp,3,sp stab 4,sp skip ldab 4,sp cmpb 5,sp bls done movb 5,sp,4,sp stab 5,sp ldab 3,sp cmpb 4,sp bls done movb 4,sp,3,sp stab 4,sp done pulb rts add3 pshx pshy pshd ldx #n1 ldy #n2 inx inx iny iny ldab #4 aloop dbeq b,adone ldaa 0,x adca 1,y- staa 1,x- bra aloop adone puld puly pulx rts ;************************************************************************* ; rtiisr subroutine ; ; This subroutine will increment the counter, seconds, minutes, & hours counters ; to track the time. This subroutine will be called ~400 times a second. ; ; Input: No input other than the timer to call the isr. ; Output: The counter, seconds, minutes, & hours buffers will ; be updated to track the time, the time & prompt will be ; printed every second. ; Registers in use: X for adding to the counter, seconds, minutes, & hours buffers. ; Memory locations in use: Memory Address for serial line, Memory addresses for RTIISR control, ; Buffer words for counters, seconds, minutes, & hours buffers. ; ; Comments: The counter buffer should be compared to 400, but for the simulator, ; the counter is compared to 200 to better simulate 1 second on my computer. ; rtiisr bset CRGFLG,%10000000; Clear RTI Interrupt Flag ldx counter inx stx counter cpx #100 bne rtiSkip ldx #0 stx counter ldaa PORTB eora #%00010000 staa PORTB rtiSkip RTI ; Return from RTI ISR ;************************************************************************* ; PrintTime subroutine ; ; This subroutine will print the time, command prompt, and maybe an error prompt. ; ; Input: No input. ; Output: The time prompt, time, command prompt, the current input, ; and/or an error on the serial console. ; Registers in use: A for the characters to print, X for buffer addresses, ; Y for buffer lengths, D for the seconds/minutes/hours for calling TimeOnPortB ; Memory locations in use: Memory Address for serial line, Buffer words for counters, ; seconds, minutes, & hours buffers, and buffer to print time, ; outputBuf for tracking what to output on PORTB. ; ; Comments: This subroutine requires TimeOnPortB subroutine and to be setup. The subroutine ; will print the current user input if its not finished. ; PrintTime pshd ; Save D to the stack pshy ; Save Y to the stack pshx ; Save X to the stack ldaa #CR ; Load the character CR into A jsr putchar ; Write the character to the serial ldaa #LF ; Load the character LF into A jsr putchar ; Write the character to the serial ldx #clock ; Load the address of the clock prompt into X jsr WriteString ; Write the string to serial ldd hours ; Load the hours into D cpd #10 ; Compare D to 10 bhs goodHours ; If D >= goodHours psha ; Save A to the stack ldaa #'0' ; Load '0' character into A jsr putchar ; Print '0' to the serial pula ; Restore A from the stack goodHours ldy #buffer ; Load the address of buffer into Y jsr PrintDecimalWord; Print the number to the serial ldaa #':' ; Load the character ':' into A jsr putchar ; Write the character to the serial ldd minutes ; Load the minutes into D cpd #10 ; Compare D to 10 bhs goodMins ; If D >= goodMins psha ; Save A to the stack ldaa #'0' ; Load '0' character into A jsr putchar ; Print '0' to the serial pula ; Restore A from the stack goodMins ldy #buffer ; Load the address of buffer into Y jsr PrintDecimalWord; Print the number to the serial ldaa #':' ; Load the character ':' into A jsr putchar ; Write the character to the serial ldd seconds ; Load the seconds into D cpd #10 ; Compare D to 10 bhs goodSecs ; If D >= goodSecs psha ; Save A to the stack ldaa #'0' ; Load '0' character into A jsr putchar ; Print '0' to the serial pula ; Restore A from the stack goodSecs ldy #buffer ; Load the address of buffer into Y jsr PrintDecimalWord; Print the number to the serial ldaa #' ' ; Load ' ' character into A jsr putchar ; Write the character to the serial console jsr putchar ; Write the character to the serial console jsr putchar ; Write the character to the serial console jsr putchar ; Write the character to the serial console ldx #CMD ; Load the address of CMD into X jsr WriteString ; Write the string to the serial ldx #inputBuffer ; Load the address of the inputBuffer into X jsr WriteString ; Write the string to the serial ldaa outputBuf ; Load outputBuf into A cmpa #'h' ; Compare A to 'h' bne pTimeIsM ; If A != 'h', branch to pTimeIsM ldd hours ; Load hours into B bra skipRest ; Jump to skipRest pTimeIsM cmpa #'m' ; Compare A to 'm' bne pTimeIsS ; If A != 'm', branch to pTimeIsS ldd minutes ; Load Minutes into D bra skipRest ; Jump to skipRest pTimeIsS ldd seconds ; Load seconds into D skipRest jsr TimeOnPortB ; Call TimeOnPortB to output time pulx ; Restore X from the stack puly ; Restore Y from the stack puld ; Restore D from the stack rts ; Return to caller ;************************************************************************* ; TimeOnPortB subroutine ; ; This subroutine will output the time given on on PORTB for two seven segment displays. ; ; Input: Two Digit Decimal number in register D. ; Output: The given two digit decimal number on PORTB for two 7 segment displays. ; Registers in use: D for the input, and for math to split the digits, X for math to split digits. ; Memory locations in use: PORTB memory location. ; ; Comments: This subroutine will only work with two digit decimal numbers, and one digit decimal ; numbers (leading zeros will be added). ; TimeOnPortB pshd ; Save D to the stack pshx ; Save X to the stack ldx #10 ; Load 10 into X to get digit idiv ; Divide D by X and save Digit into D pshb ; Save B to the stack (Lower Byte of D) exg x,d ; Swap X and D ldx #10 ; Load 10 into X to get digit lslb ; Shift B left by 1 lslb ; Shift B left by 1 lslb ; Shift B left by 1 lslb ; Shift B left by 1 orab 1,sp+ ; Or B with Digit on stack stab PORTB ; Save B to PORTB pulx ; Restore X from the stack puld ; Restore D from the stack rts ; Return from caller ;************************************************************************* ; ReadDecimal subroutine ; ; This subroutine will read an ASCII string of a number in decimal and convert it to ; its value. ; ; Input: A memory address in register X. ; Output: The value of the number in the Y register, and any errors printed ; to the serial line. Zero bit is set if error occurs. ; Registers in use: X for the address of the contents and for a buffer while printing, ; D for multiplication, B for the character, Y for output value. ; Memory locations in use: Memory Address for serial line, address of the string ; ; Comments: This subroutine will return the value in the Y register, and if an error occurs, ; the Zero bit in the CCR will be set. ; ReadDecimal pshd ; Save D to the stack ldy #0 ; Clear Y register dHLoop ldab 1,x+ ; Read Next character from X beq dHDone ; If B == 0, exit loop cmpb #'+' ; Compare B to '+' beq dHDone ; If B == '+', end of number cmpb #'-' ; Compare B to '-' beq dHDone ; If B == '-', end of number cmpb #'*' ; Compare B to '*' beq dHDone ; If B == '+', end of number cmpb #'/' ; Compare B to '/' beq dHDone ; If B == '-', end of number cmpb #':' ; Compare B to ':' beq dHDone ; If B == '-', end of number cmpb #' ' ; Compare B to space character beq dHDone ; If B == ' ', exit loop cmpb #'0' ; Compare B to '0' character blt dHError ; If B < '0', bad address, exit loop cmpb #'9' ; Compare B to '9' character bhi dHError ; If B > '9', check if 'A'-'F' characters subb #'0' ; Subtract '0' from B to get true value pshb ; Save B to the stack ldd #10 ; load 10 into D emul ; Multiply Y and D exg d,y ; Transfer data from D to Y pulb ; Restore b from the stack aby ; Add B to Y bra dHLoop ; Branch always to rHLoop dHDone clra ; clear A accumulator tap ; Transfer A into CCR to clear zero bit puld ; Restore D from the stack rts ; Return to caller dHError ldaa #4 ; Load 4 into A to set zero bit in CCR tap ; Transfer A into CCR to set zero bit and warn error puld ; Restore D from the stack rts ; Return to caller ;************************************************************************* ; strrev subroutine ; ; This subroutine will reverse a string from one buffer into another. ; ; Input: Address of null terminated string in X, address of a large enough ; buffer in Y. ; Output: The string in X reversed in Y. ; Registers in use: X for the address of the string, Y for the address of the buffer, ; A to read characters from the string. ; Memory locations in use: Memory Address for serial line, address of the string & buffer ; ; Comments: This subroutine will not check that the output buffer is large enough, that ; is the job of the caller. ; strrev pshx ; Save X to the stack pshy ; Save Y to the stack psha ; Save A to the stack revLoop ldaa 1,y- ; Load Character from Y into A, decrement Y beq revDone ; If Character is 0, exit loop staa 1,x+ ; Save character in address in X, increment X bra revLoop ; Loop back always clra ; Set A to Zero revDone staa 1,x+ ; Copy Null terminator into new string pula ; Restore A from the stack puly ; Restore Y from the stack pulx ; Restore X from the stack rts ; Return to caller ;************************************************************************* ; PrintDecimalWord subroutine ; ; This subroutine will print a given word of data to the serial in binary. ; ; Input: 1 word of data in register D, Buffer Address in Y ; Output: Decimal representation of the data on the serial console ; Registers in use: Y for the address of the buffer, X to count the number of bits ; written and for division, D for the input, A for characters. ; Memory locations in use: Memory addresses for serial, and operator to hold sign ; ; Comments: This subroutine requires serial to be setup and putchar subroutine. ; PrintDecimalWord pshx ; Save X to the stack pshy ; Save Y to the stack pshd ; Save D (A:B) to the stack cpd #0 ; Compare D to zero beq dIsZero ; Branch to hIsZero blt dIsNegative ; If D < 0, Jump to dIsNegative dAfterNeg psha ; Save A to the stack pshy ; Save Y to the stack pshx ; Save x to the stack ldaa #'0' ; Load the '0' character into A ldx #buffer2 ; Load the address of buffer2 into X ldy #5 ; Load 5 into Y jsr memset ; Write '0' to the first 5 bytes in buffer2 pulx ; Restore X from the stack puly ; Restore Y from the stack clra ; Set A to zero staa 0,y ; Load Zero into Y for Null Terminator pula ; Restore A from the stack dPrintLoop ldx #10 ; Load 10 in X for division idiv ; Divide D / 10 to get Hex Digit cpx #0 ; Compare X to 0 beq dCheck ; If X == 0, branch to check D is zero dDNotZero addb #'0' ; Add '0' to B to get ASCII Character stab 1,+y ; Save character from B to Y exg X,D ; Swap values in X and D bra dPrintLoop ; Loop to hPrintLoop dCheck cpd #0 ; Compare D to 0 bne dDNotZero ; If D != 0, branch back to hDNotZero dPrintDone ldaa operator ; Load operator into A to see if negative cmpa #'-' ; Compare A to '-' bne dNotNeg ; If A != '-', jump to dNotNeg staa 1,+y ; Save '-' into buffer dNotNeg ldx #buffer2 ; Load the address of buffer2 in X jsr strrev ; Reverse string in Y in buffer in X jsr WriteString ; Jump to write string to write the number ldy lenBuf2 ; Load the length of buffer2 into Y ldx #buffer2 ; Load the address of buffer2 into X jsr Zeros ; Fill buffer2 with zeros puld ; Restore D (A:B) from the stack puly ; Restore Y from the stack pulx ; Restore X from the stack rts ; Return to caller dIsZero ldaa #'0' ; Load '0' character into A jsr putchar ; Print character to the screen puld ; Restore D (A:B) from the stack puly ; Restore Y from the stack pulx ; Restore X from the stack rts ; Return to caller dIsNegative psha ; Save A to the stack ldaa #'-' ; Load '-' into A staa operator ; Save '-' to operator buffer pula ; Restore A from the stack nega ; Two's complement of A suba #1 ; Subtract 1 from A negb ; Two'complement of B subb #1 ; Subtract 1 from B addd #1 ; Add 1 to D bra dAfterNeg ; Jump back to dAfterNeg ;************************************************************************* ; Zeros subroutine ; ; This subroutine will write zeros to every byte in a given array. ; ; Input: Address of an array in X and its length in Y ; Output: Zeros in every byte of an array. ; Registers in use: X for the address of the array, Y for the length, and A for 0 ; Memory locations in use: Memory Address of the array ; ; Comments: This subroutine requires serial to be setup and putchar subroutine. ; Zeros psha ; Save A to the Stack clra ; Clear A zerosLoop staa 1,x+ ; Load A into byte at X dbne y,zerosLoop ; Decrement Y and loop if Y != 0 pula ; Restore A from the stack rts ; Return to caller ;************************************************************************* ; memset subroutine ; ; This subroutine will write a given byte to every byte in a given array. ; ; Input: Address of an array in X and its length in Y, the byte in A ; Output: The given byte in every byte of an array. ; Registers in use: X for the address of the array, Y for the length, and A for the given byte ; Memory locations in use: Memory Address of the array ; ; Comments: This subroutine requires serial to be setup and putchar subroutine. ; memset staa 1,x+ ; Load A into byte at X dbne y,memset ; Decrement Y and loop if Y != 0 rts ; Return to caller ;************************************************************************* ; WriteString subroutine ; ; This subroutine will write a given null terminated string to the serial. ; ; Input: Address of null terminated string in X ; Output: Null terminated string written to serial ; Registers in use: X for the address of the string and A for the current byte ; Memory locations in use: Memory Address for serial line, address of the string ; ; Comments: This subroutine requires serial to be setup and putchar subroutine. ; WriteString psha ; Save A to the stack writeLoop ldaa 1,x+ ; Load the byte at addr in X, then add 1 beq doneWrite ; if A == 0, branch to doneWrite jsr putchar ; Jump to putchar to write byte to serial bra writeLoop ; branch always to writeLoop doneWrite pula ; restore A from the stack rts ; return to caller ;************************************************************************* ; ReadString subroutine ; ; This subroutine will read a string from the serial line to a given address. ; ; Input: Address of an array in X ; Output: Null terminated string in the given array ; Registers in use: X for the address of the string Y for the length of the string, ; and A for the current byte ; Memory locations in use: Memory Address for serial line, address of the string ; ; Comments: This subroutine requires serial to be setup and getchar subroutine. ; ReadString psha ; Save accumulator A to the stack pshy ; Save Y to the stack pshx ; Save X to the stack readLoop jsr getchar ; Jump to putchar to write byte to serial beq readLoop ; While A == 0, loop cmpa #CR ; If A == CR, exit loop beq doneRead ; Branch to doneRead if A == CR staa 1,x+ ; Save the byte to the addr in X, then add 1 jsr putchar ; Write Character back to the terminal dey ; Decrement Y by 1 beq doneRead ; If Y == 0, no more room, stop reading bra readLoop ; branch always to readLoop doneRead pulx ; Restore X from the stack pulY ; Restore Y from the stack pula ; restore A from the stack rts ; return to caller ;************************************************************************* ; putchar subroutine ; ; This subroutine writes a single byte to a serial line ; ; Input: A single ASCII byte in accumulator A ; Output: Sends one character to SCI port ; Registers in use: Accumulator A with input byte ; Memory locations in use: SCISR1 and SCIDRL status and data registers ; putchar brclr SCISR1,#%10000000,putchar ; wait for transmit buffer empty staa SCIDRL ; send a character rts ; Return to caller ;************************************************************************* ; putchar subroutine ; ; This subroutine reads one byte from the SCI port ; ; Input: One byte from the SCI port ; Output: One byte in accumulator A ; Registers in use: Accumulator A for output byte ; Memory locations in use: SCISR1 and SCIDRL status and data registers ; getchar brclr SCISR1,#%00100000,getchar7 ; If no input on SCI port, return 0 ldaa SCIDRL ; Read one byte from SCI port into A rts ; Return to caller getchar7 clra ; Set A to 0 rts ; Return to caller * ************************************************************************** * Data Section 2: address used [ $3100 to $3FFF ] RAM Memory * clock dc.b 'Clock> ',NULL ; Prompt string for clock CMD dc.b 'CMD> ',NULL ; Prompt string for CMD error dc.b 'Error> ',NULL ; Prompt string for errors badInput dc.b 'Invalid Input',NULL ; Invalid Input Prompt ; twMsg: welcome message for typewrite twMsg dc.b CR,LF,'Clock stopped and Typewrite program started.',CR,LF dc.b 'You may type below.',CR,LF,NULL ; msg: this is the main option menu string msg dc.b 'Commands:',CR,LF dc.b 't: Set the time in format HH:MM:SS',CR,LF dc.b 'h: Display the hours on the 7 segment displays',CR,LF dc.b 'm: Display the minutes on the 7 segment displays',CR,LF dc.b 's: Display the seconds on the 7 segment displays',CR,LF dc.b 'q: Stop the clock and enter typewriter',CR,LF,NULL end ; last line of the file