diff options
Diffstat (limited to 'cmpen472hw6_McDonnell/Sources/main.asm')
| -rw-r--r-- | cmpen472hw6_McDonnell/Sources/main.asm | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/cmpen472hw6_McDonnell/Sources/main.asm b/cmpen472hw6_McDonnell/Sources/main.asm new file mode 100644 index 0000000..923c8b9 --- /dev/null +++ b/cmpen472hw6_McDonnell/Sources/main.asm @@ -0,0 +1,440 @@ +************************************************************************** +* +* Title: Hardware Controller +* +* Objective: CMPEN 472 Homework 5 +* +* Revision: V1.0 +* +* Date: Feb. 21, 2025 +* +* Programmer: Jacob McDonnell +* +* Company: The Pennsylvania State University +* Department of Computer Science and Engineering +* +* Algorithm: Simple Serial I/O, Parallel I/O use, time delay-loop, and PWM control +* +* Register Use: A & B to control LEDS initially, Light Level, current byte, etc +* X & Y to hold the counter in the loop and address of strings and length of string. +* +* Memory Use: RAM Locations from $3000 for data, +* RAM Locations from $3100 for program +* +* Input: Parameters hard-coded in the program - PORTB +* Serial Port for User Input +* +* Output: LED 1 at PORTB bit 4 +* LED 2 at PORTB bit 5 +* LED 3 at PORTB bit 6 +* LED 4 at PORTB bit 7 +* Serial Port for String Output +* +* Observation: This program will respond to user input to turn on and off LEDs 1, 2, & 3, +* Dim LED 4 from 100% to 0%, Dim LED 4 from 0% to 100%, and echo user input +* back to the terminal in Type Writer Mode. +* +* Note: ON CSM-12C128 board, +* Switch 1 is at PORTB bit 0, and +* LED 4 is at PORTB bit 7. +* +* Comments: This program is developed and simulated using CodeWarrior +* development software and targeted for Axion +* Manufacturing's CSM-12C128 board running at 24MHz. +* +************************************************************************** +* 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 + +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 +Counter dc.w $0036 ; X register count number for time Delay + ; loop for 10 useconds + ; The work to calculate this number is in + ; the comments for the delay10usec subroutine. + +LEVEL dc.b $0005 ; Light Level that the LED should be + +buffer ds.b $000F ; Array of 16 bytes to read a string + dc.b NULL +lenBuf dc.w $000F ; Length of str array +* There is a second Data Section at the end of the file. +* +************************************************************************** +* 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 + + +mainLoop + ldaa #$12 + ldab #$CD + ldy #buffer + jsr PrintHexWord + + ldx #buffer + ldy lenBuf + jsr Zeros + + ldaa #CR + jsr putchar + ldaa #LF + jsr putchar + + ldaa #$FF + ldab #$FF + ldy #buffer + jsr PrintDecimalWord + + ldx #buffer + ldy lenBuf + jsr Zeros + + ldaa #CR + jsr putchar + ldaa #LF + jsr putchar + + bra mainLoop + + ldx #msg ; Load the address of msg into X + jsr WriteString ; Jump to WriteString to output message on serial + + ldx #buffer ; Load the address of buffer into X + ldy lenBuf ; Load length of buffer into Y + jsr Zeros ; jump to Zeros to zero out buffer + + ldx #buffer ; Reload address of buffer into X + ldy lenBuf ; Load the length of the buffer into Y + jsr ReadString ; Jump to ReadString to read user input into buffer + + ldx #buffer ; Reload Address of buffer into X + jsr CheckInput ; Jump to CheckInput to handle user input + bra mainLoop ; Loop back to mainLoop always +TypeWriter ldx #twMsg ; Load Type Writer welcome message address + jsr WriteString ; Jump to WriteString to write message to serial +twReadLoop jsr getchar ; Read Character from Serial + beq twReadLoop ; While Character == 0, branch to twReadLoop + jsr putchar ; Write Character back to terminal + staa PORTB ; Write Character to PORTB + bra twReadLoop ; Branch always to twReadLoop + +************************************************************************** +* Subroutine Section: address used [ $3100 to $3FFF ] RAM Memory +* + +;************************************************************************* +; CheckInput subroutine +; +; This subroutine will check the input string and match the option. +; +; Input: Address of null terminated string in X. +; Output: No Output, Control flow changed to proper subroutine. +; Registers in use: X for the address of the string, A & B to read characters from +; from the string. +; Memory locations in use: Memory Address for serial line, address of the string +; +; Comments: This subroutine will not return a value, it will jump to the proper subroutine +; based on the input given. +; + +CheckInput + rts ; Return to caller + +;************************************************************************* +; PrintBinaryWord subroutine +; +; This subroutine will print a given word of data to the serial in binary. +; +; Input: 1 word of data in register D +; Output: Binary representation of the data on the serial console +; Registers in use: X to count the number of bits written, D for the input, A for characters, +; B for the byte being written. +; Memory locations in use: Memory addresses for serial. +; +; Comments: This subroutine requires serial to be setup and putchar subroutine. +; + +PrintBinaryWord + pshx ; Save X to the stack + pshd ; Save D (A:B) to the stack + pshb ; Save B to the stack (we want these bits again later) + tab ; Transfer A to B to get upper byte + ldaa #'%' ; Load '%' into A + jsr putchar ; Print '%' to serial to denote binary number + ldx #16 ; Load 16 into X, since we're printing 16 bits +bPrintLoop rolb ; Rotate MSB of B into C of CCR + tpa ; Copy CCR into A + anda #1 ; and A with 1 to get only LSB + adda #'0' ; Add '0' to A to get ASCII Character + jsr putchar ; Print Character A to serial + dbeq X,bPrintDone ; Decrement X and if X == 0, branch to done + cpx #8 ; Compare X to 8 to check if done with upper byte + bne bPrintLoop ; If X != 8, loop to bPrintLoop + pulb ; Restore B from stack to get lower byte + bra bPrintLoop ; Branch back into loop to print lower byte +bPrintDone puld ; Restore D (A:B) from the stack + pulx ; Restore X from the stack + rts ; Return to caller + +;************************************************************************* +; PrintHexWord 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: Hexadecimal 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. +; +; Comments: This subroutine requires serial to be setup and putchar subroutine. +; + +PrintHexWord + pshx ; Save X to the stack + pshd ; Save D (A:B) to the stack + pshy ; Save Y to the stack + iny ; Increment Y by 1 + iny ; Increment Y by 1 + iny ; Increment Y by 1 + iny ; Increment Y by 1 + ldx #5 ; Load 5 into X since we have at most 4 digits +hPrintLoop dex ; Decrement X by 1 + beq hPrintDone ; If X == 0, exit Loop + pshx ; Save X to the stack + ldx #16 ; Load 16 in X for division + idiv ; Divide D / 16 to get Hex Digit + cpd #0 ; Compare D to 0 + beq hPrintDone ; If D == 0, exit loop + cmpb #$0A ; Compare A to $0A + blt hex10 ; If B < $A, branch to hex10 + addb #'A' ; Add 'A' to B to get ASCII Character + subb #$0A ; Subtract $A to adjust characters + stab 1,-y ; Save character from B to Y + exg X,D ; Swap values in X and D + pulx ; Restore Count from stack to X + bra hPrintLoop ; loop to hPrintLoop +hex10 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 + pulx ; Restore Count from stack to X + bra hPrintLoop ; Loop to hPrintLoop +hPrintDone ldaa #'$' ; Load '$' into A + jsr putchar ; Print '$' to denote Hex Number + exg Y,X ; Move Address from Y to X + jsr WriteString ; Jump to write string to write the number + puly ; Restore Y from the stack + puld ; Restore D (A:B) from the stack + pulx ; Restore X from the stack + rts ; Return to caller + +;************************************************************************* +; PrintHexWord 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: Hexadecimal 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. +; +; Comments: This subroutine requires serial to be setup and putchar subroutine. +; + +PrintDecimalWord + pshx ; Save X to the stack + pshd ; Save D (A:B) to the stack + pshy ; Save Y to the stack + iny ; Increment Y by 1 + iny ; Increment Y by 1 + iny ; Increment Y by 1 + iny ; Increment Y by 1 + iny ; Increment Y by 1 + ldx #6 ; Load 5 into X since we have at most 5 digits +dPrintLoop dex ; Decrement X by 1 + beq dPrintDone ; If X == 0, exit Loop + pshx ; Save X to the stack + ldx #10 ; Load 10 in X for division + idiv ; Divide D / 16 to get Hex Digit + cpd #0 ; Compare D to 0 + beq dPrintDone ; If D == 0, exit loop + 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 + pulx ; Restore Count from stack to X + bra dPrintLoop ; Loop to hPrintLoop +dPrintDone exg Y,X ; Move Address from Y to X + jsr WriteString ; Jump to write string to write the number + puly ; Restore Y from the stack + puld ; Restore D (A:B) from the stack + pulx ; Restore X from the stack + rts ; Return to caller + +;************************************************************************* +; 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 + +;************************************************************************* +; 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 ldaa #LF ; Load Line Feed into A + jsr putchar ; Write LF to terminal + 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: address used [ $3100 to $3FFF ] RAM Memory +* + +; unknown: string to warn the user of unknown output +unknown dc.b 'Error: Unknown Command',CR,LF,NULL + +; twMsg: welcome message when type writer loads +twMsg dc.b 'Welcome to Type Writer, you may type below.',CR,LF + dc.b 'Restart to enter main menu again.',CR,LF,NULL + +; msg: this is the main option menu string +msg dc.b 'L1: Turn on LED1',CR,LF + dc.b 'F1: Turn off LED1',CR,LF + dc.b 'L2: Turn on LED2',CR,LF + dc.b 'F2: Turn off LED2',CR,LF + dc.b 'L3: Turn on LED3',CR,LF + dc.b 'F3: Turn off LED3',CR,LF + dc.b 'L4: LED4 goes from 0% light level to 100% light level in 0.4 seconds',CR,LF + dc.b 'F4: LED4 goes from 100% light level to 0% light level in 0.4 seconds',CR,LF + dc.b 'QUIT: Quit menu program, run Type writer program.',CR,LF,NULL + + + end ; last line of the file |
