@CSC 230 Assignment 3
@Traffic Simulator
@By Rhett Dobson
@0626108
@All methods are void (have no side effects/don't return anything)
@Some .equ's have been renamed; these are the ones with different code spacing.

        .equ    SWI_SETSEG8,            0x200   @display on 8 Segment
        .equ    SWI_SETLED,             0x201   @LEDs on/off
        .equ    SWI_CheckBlack,         0x202   @check press Black button
        .equ    SWI_CheckBlue,          0x203   @check press Blue button
        .equ    SWI_DRAW_STRING,        0x204   @display a string on LCD; x = r0, y = r1, memory address of string = r2
        .equ SWI_CLEARLCD, 0x206                @clear LCD
        .equ    SWI_EXIT,               0x11    @terminate program
        .equ    SWI_GetTicks,           0x6d    @get current time

        @patterns for 8 segment display
        .equ    SEG_A,          0x80    @byte values for each segment
        .equ    SEG_B,          0x40    @of the 8 segment display
        .equ    SEG_C,          0x20
        .equ    SEG_D,          0x08
        .equ    SEG_E,          0x04
        .equ    SEG_F,          0x02
        .equ    SEG_G,          0x01
        .equ    SEG_P,          0x10

        @bit patters for LED lights
        .equ    LEFT_LED,                       0x02
        .equ    RIGHT_LED,                      0x01
        .equ BOTHLED, 0x03
        .equ NOLED, 0x00

        @bit patterns for buttons
        .equ    LEFT_BLACK_BUTTON,              0x02
        .equ    RIGHT_BLACK_BUTTON,             0x01

        @bit patterns for blue buttons
        .equ    BLUE_KEY_00,                    0x01            @button(0)
        .equ    BLUE_KEY_01,                    0x02            @button(1)
        .equ    BLUE_KEY_02,                    0x04            @button(2)
        .equ    BLUE_KEY_03,                    0x08            @button(3)
        .text
        .global _start
_start:
	bl Init @initialize stuff once only at the beginning.

        @infiniteLoop(1) {
        WhileLoop:
                swi SWI_CheckBlack
                cmp r0, #LEFT_BLACK_BUTTON
                beq StartSim
                swi SWI_CheckBlack
                cmp r0, #RIGHT_BLACK_BUTTON
                beq EndSim
                bal WhileLoop @}
        @no proceeding forward until either input is detected. unfortunately this makes the first
        @button press a bit "sticky" and may require a few tries to get the correct "timing".
StartSim: @bigloop() {
	@no need to "purge" the blue button buffer from before.
CarCycle: @Car cycle begins here, though it could be interrupted by pedestrians.
	  @This label is mostly symbolic; the states are branched to from elsewhere instead of
	  @branching back to CarCycle and doing tons of compares to see where to branch to again.
	  @That seems more like spaghetti code to me...
S1: 
	@display pedestrian status in top right: (37, 1)
	mov r0, #18
	mov r1, #1
	ldr r2, =W
	swi SWI_DRAW_STRING
	mov r4, #4      @loop counter for GreenMain repetitions
LightLoop1: @small loop to extend the green light until the right duration
	bl GreenMain    @lasts 2+1 seconds
	subs r4, r4, #1 @x4 = 12 seconds
	cmp r4, #0
	bne LightLoop1
	
P1: @polling black and blue buttons
	bl bluec
        swi SWI_CheckBlack
        cmp r0, #RIGHT_BLACK_BUTTON
        beq EndSim
	@proceed to S2, no branch needed
S2:
	mov r4, #2
LightLoop2:
	bl GreenMain    @lasts 3 seconds
P2: @inner polling, can end car cycle early 
	bl bluec
        swi SWI_CheckBlack
        cmp r0, #RIGHT_BLACK_BUTTON
        beq EndSim
	subs r4, r4, #1 @x2 = 6 seconds
	cmp r4, #0
	bne LightLoop2
	@proceed to S3
S3: 
	bl Yellow    @Calls to smaller light subroutines are handy,
S4:
	bl Red       @because it cuts down on repetition in code if changes need to be made.
S5:
	bl GreenSide
S6:
	bl Yellow
S7:
	bl Red

	bal CarCycle @loop back to start of cycle
@}

EndSim: @this is a function, not a goto label. Trust me.
        @clear all components on the board
        mov r0, #NOLED
        swi SWI_SETLED
        mov r1, #0  @turn point off for good
        mov r0, #10 @clear number
	bl Display8Seg
        swi SWI_CLEARLCD
        swi SWI_EXIT
        @end of program. }
        
bluec:  @This is more like a macro, or a #define. Cuts down on some repetition and makes the code look shorter.
	@Checks the first four blue buttons for a match; if none is found, the link register
	@goes back to the program from wherever it left off.
	stmfd sp!,{r0-r1,lr}
	swi SWI_CheckBlue
        cmp r0, #BLUE_KEY_00
        beq PedCycle
	swi SWI_CheckBlue
        cmp r0, #BLUE_KEY_01
        beq PedCycle
	swi SWI_CheckBlue
        cmp r0, #BLUE_KEY_02
        beq PedCycle
	swi SWI_CheckBlue
        cmp r0, #BLUE_KEY_03
        beq PedCycle
	ldmfd sp!,{r0-r1,pc}

PedCycle: @doesn't matter where it's called from, P1 or P2, PedCycle does the same thing either way.
	  @It doesn't even need the link register to find its way back; it always goes to S5.
	  @plus, I need r2 to print new strings for new crossing status.
	  @at present, there is no need to stack up register values either...
	mov r1, #0     @turn point off
	mov r0, #10    @is it too early for this? Is this for the pedestrians to see, 
	bl Display8Seg @or is it a subtle debug thing?
	bl Yellow      @lasts 2 seconds
	bl Red         @lasts 1 second
	
	@pedestrians are crossing
	mov r0, #18
	mov r1, #1
	ldr r2, =X
        swi SWI_DRAW_STRING

	mov r0, #6
	mov r1, #0 @keep the point off!
Xcd: @countdown for X from 6 to 2
	bl Display8Seg
	mov r3, #1000
	bl Wait
	sub r0, r0, #1
	cmp r0, #2
	bne Xcd
	
	@pedestrians are running
	mov r0, #18
	mov r1, #1
	ldr r2, =bang
        swi SWI_DRAW_STRING

	mov r0, #2 @don't count down from 37.
	mov r1, #0 @and still keep the point off
bangcd: @countdown for ! from 2 to 1, changes immediately on 0
	bl Display8Seg
	bl Wait @r3 is still 1000
	sub r0, r0, #1
	cmp r0, #1
	bne bangcd        
                
        bl Display8Seg @display 0 as the light turns red
        bl Red
        
        mov r1, #1  @turn point back on
	mov r0, #10 @and remove number
	bl Display8Seg
	
	mov r0, #18
	mov r1, #1
	ldr r2, =W
	swi SWI_DRAW_STRING @change pedestrian sign back to Wait	
        bal S5 		    @resume at S5

Init: @initial settings, run once only
	stmfd sp!,{r0-r2,lr}
        @target: (0, 0) (top left)
        mov r0, #0
        mov r1, #0
        ldr r2, =studnumber @name + student number
        swi SWI_DRAW_STRING
        
        @wicked ASCII art goes here
        mov r0, #0
        mov r1, #2
        ldr r2, =mainst
        swi SWI_DRAW_STRING
        
        mov r0, #0
        mov r1, #3
        ldr r2, =north
        swi SWI_DRAW_STRING
        
        mov r0, #0
	mov r1, #5
	ldr r2, =south
        swi SWI_DRAW_STRING
        
	mov r0, #4
        mov r1, #6
        ldr r2, =siderd
        swi SWI_DRAW_STRING
        
        @targets for lights are:
        @Main St: (7, 4) + (9, 4)
        @Side Rd: (8, 3) + (8, 5)
        @yellow light goes on (8, 4).
	       	   @Red on all four of those at once, normally...
	mov r0, #8 @The simulator starts with a green light on Main Street;
        mov r1, #3 @To keep it symmetrical we start with red lights on Side Road.
        ldr r2, =R
        swi SWI_DRAW_STRING
	mov r0, #8
        mov r1, #5
        ldr r2, =R
        swi SWI_DRAW_STRING

        @activate both LEDs
        mov r0, #BOTHLED
        swi SWI_SETLED

        @display the point
        mov r0, #10 @how to display no number
        mov r1, #1
        bl Display8Seg
        ldmfd sp!,{r0-r2,pc}

Wait: @(Delay:r3)   
	stmfd   sp!,{r0-r3,lr}
        swi     SWI_GetTicks    @get the current time
        mov     r1, r0          @save the current time to r1
Wait_Loop:
        swi     SWI_GetTicks    @get the new current time
        sub     r2, r0, r1      @r2 is the time interval
        cmp     r2, r3
        blt     Wait_Loop
        ldmfd   sp!,{r0-r3,pc}

Display8Seg: @(Number:r0, Point on/off: r1)
        stmfd   sp!,{r0-r2,lr}
        ldr     r2, =Digits
        ldr     r0, [r2, r0, lsl#2]
        tst     r1,#0x01                @if r1 = 1
        orrne   r0, r0, #SEG_P          @then show "P"
        swi     SWI_SETSEG8
        ldmfd   sp!,{r0-r2,pc}

GreenMain: @green light for main street. Blinks slowly (2 seconds on, 1 second off). No parameters ()
	stmfd sp!,{r0-r3,lr}
	mov r0, #7 @lights turn green on Main Street
        mov r1, #4
        ldr r2, =G
        swi SWI_DRAW_STRING
	mov r0, #9
        mov r1, #4
        ldr r2, =G
        swi SWI_DRAW_STRING
        
	mov r0, #LEFT_LED
	swi SWI_SETLED
	mov r3, #2000
	bl Wait	
	
	@blink off
	mov r0, #NOLED
	swi SWI_SETLED
	mov r3, #1000
	bl Wait
	
	mov r0, #7 @turn off lights, we're done here.
        mov r1, #4
        ldr r2, =del
        swi SWI_DRAW_STRING
	mov r0, #9
        mov r1, #4
        ldr r2, =del
        swi SWI_DRAW_STRING
	ldmfd sp!,{r0-r3,pc}
        
GreenSide: @green light for side street. Solid green for 4 whole seconds. No parameters ()
	stmfd sp!,{r0-r3,lr}
	mov r0, #8 @turn on ASCII lights
        mov r1, #3
        ldr r2, =G
        swi SWI_DRAW_STRING
	mov r0, #8
        mov r1, #5
        ldr r2, =G
        swi SWI_DRAW_STRING
	
	mov r0, #RIGHT_LED
	swi SWI_SETLED
	mov r3, #2000 @due to large integers, 4000 is not an assignable value.
	bl Wait	      @so I just call Wait for 2000 twice.
	mov r3, #2000
	bl Wait	
	
	mov r0, #8 @delete lights on exit
        mov r1, #3
        ldr r2, =del
        swi SWI_DRAW_STRING
	mov r0, #8
        mov r1, #5
        ldr r2, =del
        swi SWI_DRAW_STRING
	ldmfd sp!,{r0-r3,pc}

Yellow: @though there are two possible yellow lights, the display happens to be the same.
	@blink on and off in 1/4 second intervals 8 times, this adds up to 2 seconds.
	@No parameters ()
	stmfd sp!,{r0-r3,lr}
	mov r0, #8 @draw light on LCD
	mov r1, #4
	ldr r2, =Y
        swi SWI_DRAW_STRING
        mov r2, #4
YLoop:
	mov r0, #BOTHLED
	swi SWI_SETLED
	mov r3, #250
	bl Wait	
	
	@blink off
	mov r0, #NOLED
	swi SWI_SETLED
	mov r3, #250
	bl Wait
	sub r2, r2, #1
	cmp r2, #0
	bne YLoop
	
	mov r0, #8 @delete Y on exit
	mov r1, #4
	ldr r2, =del
        swi SWI_DRAW_STRING
	ldmfd sp!,{r0-r3,pc}
	
Red: @lights are set to red and 1 second of wait is added, though the lights are often
     @left untouched to stay red longer than that.
     @No parameters ()
	stmfd sp!,{r0-r3,lr} 
	mov r0, #7 @lights turn red in all directions at once.
        mov r1, #4
        ldr r2, =R
        swi SWI_DRAW_STRING
	mov r0, #9
        mov r1, #4
        ldr r2, =R
        swi SWI_DRAW_STRING
	mov r0, #8
        mov r1, #3
        ldr r2, =R
        swi SWI_DRAW_STRING
	mov r0, #8
        mov r1, #5
        ldr r2, =R
        swi SWI_DRAW_STRING
	
	mov r0, #NOLED
	swi SWI_SETLED
	mov r3, #1000
	bl Wait
	
	@don't deactivate lights; those can be replaced by the other lighting subroutines.
	ldmfd sp!,{r0-r3,pc}
	
.data

        Digits:
                .word   SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_G             @0
                .word   SEG_B|SEG_C                                     @1
                .word   SEG_A|SEG_B|SEG_F|SEG_E|SEG_D                   @2
                .word   SEG_A|SEG_B|SEG_F|SEG_C|SEG_D                   @3
                .word   SEG_G|SEG_F|SEG_B|SEG_C                         @4
                .word   SEG_A|SEG_G|SEG_F|SEG_C|SEG_D                   @5
                .word   SEG_A|SEG_G|SEG_F|SEG_E|SEG_D|SEG_C             @6
                .word   SEG_A|SEG_B|SEG_C                               @7
                .word   SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G       @8
                .word   SEG_A|SEG_B|SEG_F|SEG_G|SEG_C                   @9
        .word   0							@no number
        studnumber:     .asciz  "Rhett Dobson 0626108"
	X: .asciz "X" @perhaps I should have looked into SWI_DRAW_CHAR.
	bang: .asciz "!"
	W: .asciz "W"
	Y: .asciz "Y"
	R: .asciz "R"
	G: .asciz "G"
	del: .asciz " "
	mainst: .asciz "Main St   -->"
	north: .asciz "_______| |_______"
	
	south: .asciz "-------| |-------"
	    siderd: .asciz "Side^Rd" @code spacing sort of resembles ASCII art.
	