Skip to content

Instantly share code, notes, and snippets.

Created January 18, 2017 18:05
Show Gist options
  • Save anonymous/4af8e1d10e447fa1755873e8ce74f728 to your computer and use it in GitHub Desktop.
Save anonymous/4af8e1d10e447fa1755873e8ce74f728 to your computer and use it in GitHub Desktop.
SIMPL in MSP430 assembly language 582 bytes -
;-------------------------------------------------------------------------------
; MSP430 Assembler Code Template for use with TI Code Composer Studio
;
;
;-------------------------------------------------------------------------------
.cdecls C,LIST,"msp430.h" ; Include device header file
;-------------------------------------------------------------------------------
.def RESET ; Export program entry-point to
; make it known to linker.
;-------------------------------------------------------------------------------
; Variables
;-------------------------------------------------------------------------------
.sect "vars"
.bss parray, 256
.bss x, 2
.bss name, 2
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
.text ; Assemble into program memory.
.retain ; Override ELF conditional linking
; and retain current section.
.retainrefs ; And retain any sections that have
; references to current section.
;-------------------------------------------------------------------------------
; This implements the SIMPL interpreter is MSP430 assembly Language
; Register Usage
; R0 MSP430 PC Program Counter
; R1 MSP430 SP Stack Pointer
; R2 MSP430 SR Status Register
; R3 MSP430 Constant Register
; R4 SIMPL - Top of Stack TOP
; R5 SIMPL - 2nd in Stack 2ND
; R6
; R7
; R8
; R9
; R10 SIMPL - Instruction Pointer IP
; R11
; The input buffer - start is at 0x0300, which is pointed to by R14
; R12 receives the character from the uart_get_c routine and puts in the buffer, pointed to by R14
; R14 is the current character position in the input buffer
; R15 is a counter to ensure that we don't exceed 64 characters in input buffer
;-------------------------------------------------------------------------------
; textRead
; ------------------------------------------------------------------------------
; Get a character from the UART and store it in the input buffer starting at 0x0300
; Register Usage
; The input buffer - start is at 0x0300, which is pointed to by R14
; R12 receives the character from the uart_get_c routine and puts in the buffer, pointed to by R14
; R14 is the current character position in the input buffer
; R15 is a counter to ensure that we don't exceed 64 characters in input buffer
; 33 instructions
textRead: MOV.W #0x0200,R14 ; R14 = start of input buffer in RAM
CLR.B R15 ; i = 0
getChar: CALL #uart_getc ; char ch = uart_getc()
CMP.B #0x000d,R12 ; is it carriage return? 0d
JEQ textEnd
CMP.B #0x000a,R12 ; Is it newline? 0a
JEQ textEnd
CMP.B #0x0020,R12 ; if (ch >= ' ' && ch <= '~')
JLO nonValid
CMP.B #0x007f,R12
JHS nonValid
CMP.B #0x003A,R12 ; is it colon? 3A
JNE notColon
colon: ; If the input character is a colon
CALL #uart_getc ; char ch = uart_getc() - get the next character
; INC.W R14 ; increment the input buffer pointer to the next (2nd) character
MOV.B R12,R13 ; move the 1st character after the colon to "name" variable in R13
$C$L13: MOV.B R13,R12 ; Copy the character into R13 and calculate the destination address
SUB.B #0x0041,R13 ; subtract 65 to remove offset of letter A
ADD.W R13,R13 ; Double R13 ; multiply by 2
ADD.W R13,R13 ; Double R13 ; multiply by 4
ADD.W R13,R13 ; Double R13 ; multiply by 8
ADD.W R13,R13 ; Double R13 ; multiply by 16
ADD.W R13,R13 ; Double R13 ; multiply by 32
ADD.W R13,R14 ; Add (32*R13) to the index pointer R14
ADD.W #0x020,R14 ; Add to array pointer 0x0220
MOV.B R12,0xffff(R14) ; Store character at RAM buffer indexed by R14
; R14 now contains the destination address
JMP incPointer
notColon: INC.W R14 ; Increment buffer pointer
MOV.B R12,0xffff(R14) ; Store character at RAM buffer indexed by R14
incPointer: INC.B R15 ; Increment the input buffer pointer i++;
nonValid: CMP.B #0x003f,R15 ; If input pointer <64 loop back to start while (i < (63)) {
JLO getChar ; loop back and get next character
textEnd: CLR.B 0x0000(R14) ; Put a zero on the end of the buffer *p = 0;
RET
;-------------------------------------------------------------------------------------------------------------------
; We now come onto the textEval - where based on the value of the character we perform some action routine
; But first we need to determine whether the characers form part of a number - and these must be decoded separately
; and put on the stack
;-------------------------------------------------------------------------------------------------------------------
; Register Usage
; R10 - pointer to the current character in the input buffer
; R12 is the accumulator for the number - then stored in location #0x380
; R13 Temporary - use in x10 multipication
; R14
; R15
; 24 Instructions
textEval: PUSH R10
MOV.W #0x0200,R10 ; R10 = start of input buffer in RAM at address 0x0200
next: MOV.B @R10+,R12 ; Get the next character from the instruction memory
MOV.B R12,R13 ; Copy into R13
TST.B R12 ; is it end of string null? - then break
JEQ textEval_end
SUB.W #0x0030,R12 ; subtract 0x30
CMP.W #0x000a,R12 ; and if it is < 10 it is a number
JHS notNumber
number: CMP.B #0x0030,0x0000(R10) ; >= '0' Is the next digit a number
JLO ($C$L20) ; break;
CMP.B #0x003a,0x0000(R10) ; <= '9'
JHS ($C$L20) ; break;
times_10: ; This multipies R12 by 10
ADDC.W R12,R12 ; R12 = 2 * R12
MOV.W R12,R13 ; R3 = 2 * R12
ADDC.W R12,R12 ; R12 = 4 * R12
ADDC.W R12,R12 ; R12 = 8 x R12
ADDC.W R13,R12 ; R12 =10 x R12
;
MOV.B @R10+,R14 ; Increment the instruction pointer fetching the next digit
SUB.W #0x0030,R14
ADD.W R14, R12 ; Add in the next digit
JMP number
$C$L20: MOV.W R12,&0x380 ; final number x is stored in locaton 0x380
MOV.W R12, R4 ; Put in R4 -the stack
JMP next ; process the next character
notNumber: MOV.W #0x0200,R14 ; Character is either a primitive or an alpha - so form CALL address
; Restore R14 to start of RAM buffer
; Get the current character location
; If it's a primitive between 0x20 and 0x3F - point to a look-up table and fetch it's code segment address
; If its an Alpha, or character >0x40 calculate it's code address from (char - 65)x32
CMP.B #0x0040,R13 ; <= 'A' Is the next digit an Alpha or primitive
JLO primitive
; Character is in R13 so calculate the destination address
alpha: SUB.B #0x0041,R13 ; subtract 65 to remove offset of letter A
ADD.W R13,R13 ; Double R13 ; multiply by 2
ADD.W R13,R13 ; Double R13 ; multiply by 4
ADD.W R13,R13 ; Double R13 ; multiply by 8
ADD.W R13,R13 ; Double R13 ; multiply by 16
ADD.W R13,R13 ; Double R13 ; multiply by 32
ADD.W R13,R14 ; Add (32*R13) to the index pointer R14
ADD.W #0x020,R14 ; Add to array pointer 0x0220
; R14 now contains the CALL address for the code
JMP next ; process the next character
primitive: MOV.W R13,R12 ; Get the command in R12
; SUB.B #0x0020,R13 ; subtract 32 to remove offset of space
; ADD.W R13,R13 ; Double R13 ; multiply by 2
; MOV.W #0x03C0,R14 ; index into look up table
; ADD.W R13,R14 ; Add (2*R13) to the index pointer R14 - this is the table address
; -------------------------------------------------------------------------------------------------------------------
; Now we need to evaluate the primitives
space: CMP.B #0x0020,R12 ; Is it space?
JNE spaceEND
MOV.W R4,R5 ; Move a 2nd number onto the stack
JMP ($C$L18)
spaceEND:
fetch: CMP.B #0x0021,R12 ; Is it fetch?
JNE fetchEND
MOV.W (R4), R4 ; Use the address in R4 to fetch a word into R4
JMP ($C$L18)
fetchEND:
dup:
CMP.B #0x0022,R12 ; Is it is it dup?
JNE dupEND
MOV.W R4,R5
JMP ($C$L18)
dupEND:
lit:
CMP.B #0x0023,R12 ; Is it lit?
JNE litEND
JMP ($C$L18)
litEND:
swap:
CMP.B #0x0024,R12 ; Is it swap $ ?
JNE swapEND
MOV.W R4,R6
MOV.W R5,R4
MOV.W R6,R3
JMP ($C$L18)
swapEND:
over: CMP.B #0x0025,R12 ; Is it over % ?
JNE overEND
JMP ($C$L18)
overEND:
and: CMP.B #0x0026,R12 ; Is it and & ?
JNE andEND
AND.W R5,R4
JMP ($C$L18)
andEND:
drop: CMP.B #0x0027,R12 ; Is it drop ' ?
JNE dropEND
JMP ($C$L18)
dropEND:
left_par: CMP.B #0x0028,R12 ; Is it left_par ( ?
JNE left_parEND
JMP ($C$L18)
left_parEND:
right_par: CMP.B #0x0029,R12 ; Is it right_par ) ?
JNE right_parEND
JMP ($C$L18)
right_parEND:
mult: CMP.B #0x002A,R12 ; Is it mult * ?
JNE multEND
JMP ($C$L18)
multEND:
add: CMP.B #0x002B,R12 ; Is it add + ?
JNE addEND
ADD.W R5,R4
JMP ($C$L18)
addEND:
push: CMP.B #0x002C,R12 ; Is it push ' ?
JNE pushEND
JMP ($C$L18)
pushEND:
sub: CMP.B #0x002D,R12 ; Is it sub - ?
JNE subEND
SUB.W R5,R4
JMP ($C$L18)
subEND:
pop: CMP.B #0x002E,R12 ; Is it pop . ?
JNE popEND
JMP printNum ; go to decimal number print
JMP ($C$L18)
popEND:
div: CMP.B #0x002F,R12 ; Is it div / ?
JNE divEND
JMP ($C$L18)
divEND:
;-------------------------------------------------------------------------------------------------
printNum: ; Take the 16 bit value in R4 stack register and print to terminal as an integer
; do by repeated subtraction of powers of 10
;-------------------------------------------------------------------------------------------------
MOV.W #10000,R14 ; R14 used as the decimation register
CLR.W R12 ; use R12 as a counter
CLR.W R11 ; Use R11 as scratch
CLR.W R13
MOV.W R4,R12 ;copy the top of stack into R12
CLRC ; clear the carry
sub10K: SUB.W R14,R12
JLO end10K
add10K: ADD.B #1,R11 ; increments the digit count
add_zero: ADD.W R14,R13 ; R13 increases by the decimal value each time
JMP sub10K
end10K: ADD.B #0x30,R11 ; make it a number
MOV.W R11,R12
CALL #uart_putc ; output character
SUB.W R13,R4 ; Decrement the stack count by n x 10
CLR.W R11 ; Use R11 as scratch
CLR.W R13
MOV.W R4,R12
decimate: CMP.W #10000,R14
JEQ use1K
CMP.W #1000,R14
JEQ use100
CMP.W #100,R14
JEQ use10
CMP.W #10,R14
JEQ use1
JMP crlf
use1K: MOV.W #1000,R14
JMP sub10K
use100: MOV.W #100,R14
JMP sub10K
use10: MOV.W #10,R14
JMP sub10K
use1: MOV.W #1,R14
JMP sub10K
crlf: MOV.W #0x0A, R12
CALL #uart_putc ; output CR
MOV.W #0x0D, R12
CALL #uart_putc ; output LF
printNum_end:
;-------------------------------------------------------------------------------------------------
$C$L18: ; CALL uart_putc ; emit the character as confirmation its been seen
JMP next
textEval_end:
POP.W R10
RET
;-------------------------------------------------------------------------------------------------------------------
; Uses R12 to send receive chars via the UART at 115200 baud.
uart_getc: BIT.B #1,&IFG2 ; while (!(IFG2&UCA0RXIFG)) // USCI_A0 RX buffer ready?
JEQ (uart_getc)
MOV.B &UCA0RXBUF,R12 ; return UCA0RXBUF;
RET
uart_putc: BIT.B #2,&IFG2 ; while (!(IFG2&UCA0TXIFG)) // USCI_A0 TX buffer ready?
JEQ (uart_putc)
MOV.B R12,&UCA0TXBUF ; UCA0TXBUF = c; // TX
RET
;-------------------------------------------------------------------------------
; Main loop here
;-------------------------------------------------------------------------------
main:
; Implementing the initialisation, TextTead, TextChk, TextEval and UART routines in MSP430 assembly language
; Ken Boak December 23rd 2016 and more on 17th/18th Jan 2017
;-------------------------------------------------------------------------------
RESET: mov.w #03E0h,SP ; Initialize stackpointer
StopWDT: mov.w #WDTPW|WDTHOLD,&WDTCTL ; Stop watchdog timer WDTCTL = WDTPW + WDTHOLD; Stop WDT
OSC_GPIO_init:
MOV.B &CALBC1_1MHZ,&BCSCTL1 ;BCSCTL1 = CALBC1_1MHZ; Set DCO
MOV.B &CALDCO_1MHZ,&DCOCTL ;DCOCTL = CALDCO_1MHZ;
SetupP1: bis.b #041h,&P1DIR ; P1.0 P1.6 output as P1.0 and P1.6 are the red+green LEDs
MOV.B #0x0041,&P1OUT ;P1OUT = BIT0 + BIT6; // All LEDs off
uart_init: MOV.B #0x0006,&P1SEL ;Initialise the UART for 115200 baud
MOV.B #0x0006,&P1SEL2 ;P1SEL2 = RXD + TXD;
BIS.B #0x0080,&UCA0CTL1 ;UCA0CTL1 |= UCSSEL_2// SMCLK
MOV.B #0x0068,&UCA0BR0 ;UCA0BR0 = 104 // 1MHz 9600
CLR.B &UCA0BR1 ;UCA0BR1 = 0 // 1MHz 9600
MOV.B #2,&UCA0MCTL ;UCA0MCTL = UCBRS0 // Modulation UCBRSx = 1
BIC.B #1,&UCA0CTL1 ;UCA0CTL1 &= ~UCSWRST Initialize USCI state machine
MOV.W #0x4F, R12
CALL #uart_putc ; output "O"
MOV.W #0x4B, R12
CALL #uart_putc ; output "K" ; Print OK
;-------------------------------------------------------------------------------
interpreter:
CALL #textRead
; CALL #textChk
CALL #textEval
JMP interpreter
; Stack Pointer definition
;-------------------------------------------------------------------------------
.global __STACK_END
.sect .stack
;-------------------------------------------------------------------------------
; Interrupt Vectors
;-------------------------------------------------------------------------------
.sect ".reset" ; MSP430 RESET Vector
.short RESET
.end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment