summaryrefslogtreecommitdiff
path: root/cmpen472hw6_McDonnell/Sources/main.asm
diff options
context:
space:
mode:
Diffstat (limited to 'cmpen472hw6_McDonnell/Sources/main.asm')
-rw-r--r--cmpen472hw6_McDonnell/Sources/main.asm440
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