aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile20
-rw-r--r--README.md52
-rw-r--r--main.s159
4 files changed, 234 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2135d58
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.elf
+*.hex
+*.o
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2d60cfa
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+XC32_PATH=/opt/microchip/xc32/v2.30/bin
+
+NAME:=main
+PROCESSOR:=32MZ2048ECG064
+
+ASM:=$(NAME).s
+OBJ:=$(NAME).o
+ELF:=$(NAME).elf
+HEX:=$(NAME).hex
+
+default: $(HEX)
+
+$(OBJ): %.o: %.s
+ $(XC32_PATH)/xc32-as -o $@ $<
+
+$(ELF): $(OBJ)
+ $(XC32_PATH)/xc32-gcc -mprocessor=$(PROCESSOR) -o $@ $^
+
+$(HEX): $(ELF)
+ $(XC32_PATH)/xc32-bin2hex $<
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ceba168
--- /dev/null
+++ b/README.md
@@ -0,0 +1,52 @@
+# Readme
+
+This is a test to get a PIC32MZ2048ECG064 running without the MPLAB IDE. There
+is an Assembly file and a Makefile. The generated HEX can be uploaded using the
+MPLAB IPE. Generating C code is fairly similar, but uses `gcc` instead of `as`.
+
+### Links
+
+About the chip: https://www.microchip.com/wwwproducts/en/PIC32MZ2048ECG064
+About the architecture: https://www.cs.cornell.edu/courses/cs3410/2008fa/MIPS_Vol1.pdf
+About the instruction set: https://www.cs.cornell.edu/courses/cs3410/2008fa/MIPS_Vol2.pdf
+
+## Notes to self
+
+### Instruction set
+
+This chip has a somewhat larger instruction set than MIPS32; it is a MIPS32
+microAptiv. For this extension, see ยง50 of the PIC32 reference manual (to be
+found on the chip information page linked above). It is not clear to me how
+widespread this instructions set is (i.e. whether it would make sense to rely
+on it being available for code generation or so).
+
+### Branch delay slots
+
+Watch out for the branch/jump instructions. The following instruction is always
+executed, regardless of whether the branch is taken or not. This instruction is
+said to be in the 'branch delay slot'. For example, this does not loop
+endlessly even though the body of `main_loop_delay` seems empty:
+
+```
+ lui $2,0xf
+ ori $5,0xffff
+main_loop_delay:
+ bne $2,$0,main_loop_delay
+ addiu $2,-1
+```
+
+Also note that when the file ends with a branch/jump, a `nop` *must* follow to
+avoid unpredictable behaviour (the following instruction could be anything
+otherwise).
+
+### `lw` and `lui`
+
+One needs `lui` to load an address, e.g. to clear `TRISB`:
+
+```
+ lui $2,%hi(TRISB)
+ sw $0,%lo(TRISB)($2)
+```
+
+Using `lw` instead of `lui` is an easy mistake, assembles fine, but you usually
+end up reading out of memory leading to a reset.
diff --git a/main.s b/main.s
new file mode 100644
index 0000000..eb7862c
--- /dev/null
+++ b/main.s
@@ -0,0 +1,159 @@
+ # SEQ0
+ .section .config_BFC0FFFC, code, keep, address(0xBFC0FFFC)
+ .type __config_BFC0FFFC, @object
+ .size __config_BFC0FFFC, 4
+__config_BFC0FFFC:
+ .word 0xFFFFFFFF
+ # DEVCP0
+ .section .config_BFC0FFDC, code, keep, address(0xBFC0FFDC)
+ .type __config_BFC0FFDC, @object
+ .size __config_BFC0FFDC, 4
+__config_BFC0FFDC:
+ .word 0xFFFFFFFF
+ # DEVCFG0
+ .section .config_BFC0FFCC, code, keep, address(0xBFC0FFCC)
+ .type __config_BFC0FFCC, @object
+ .size __config_BFC0FFCC, 4
+__config_BFC0FFCC:
+ .word 0xFFFFFFDB
+ # DEVCFG1
+ .section .config_BFC0FFC8, code, keep, address(0xBFC0FFC8)
+ .type __config_BFC0FFC8, @object
+ .size __config_BFC0FFC8, 4
+__config_BFC0FFC8:
+ .word 0x5F74FF39
+ # DEVCFG2
+ .section .config_BFC0FFC4, code, keep, address(0xBFC0FFC4)
+ .type __config_BFC0FFC4, @object
+ .size __config_BFC0FFC4, 4
+__config_BFC0FFC4:
+ .word 0x7FF9B198 # SPLL is 8MHz (FRC) / 1 * 50 / 2 = 200MHz
+ # DEVCFG3
+ .section .config_BFC0FFC0, code, keep, address(0xBFC0FFC0)
+ .type __config_BFC0FFC0, @object
+ .size __config_BFC0FFC0, 4
+__config_BFC0FFC0:
+ .word 0xBFFFFFFF
+
+ .section .sdata,data
+ .type string, @object
+string:
+ .ascii "Hello, world!\0"
+ .size string, .-string
+
+ .section .text,code
+ .align 2
+
+ .set nomips16
+ .set nomicromips
+ .set noreorder
+ .set nomacro
+
+ .globl main
+ .ent main
+ .type main, @function
+main:
+ # Unlock
+ di $2
+ ehb
+ lui $2,%hi(SYSKEY)
+ sw $0,%lo(SYSKEY)($2)
+ lui $3,0xaa99
+ ori $3,0x6655
+ sw $3,%lo(SYSKEY)($2)
+ lui $3,0x5566
+ ori $3,0x99aa
+ sw $3,%lo(SYSKEY)($2)
+ # PB7DIV := 0x00008800 (CPU clock: enable; SPLL / 1 = 200MHz)
+ lui $2,%hi(PB7DIV)
+ xor $3,$3
+ ori $3,0x8800
+ sw $3,%lo(PB7DIV)($2)
+ # PB2DIV := 0x00008818 (UART clock: enable; SPLL / 25 = 8MHz)
+ lui $2,%hi(PB2DIV)
+ xor $3,$3
+ ori $3,0x8818
+ sw $3,%lo(PB2DIV)($2)
+ # Lock
+ lui $2,%hi(SYSKEY)
+ sw $0,%lo(SYSKEY)($2)
+ ei $2
+ ehb
+
+ # TRISB := 0
+ lui $2,%hi(TRISB)
+ sw $0,%lo(TRISB)($2)
+
+ # Remappable pins
+ # RPG7 is U1TX
+ xor $3,$3
+ ori $3,1
+ lui $2,%hi(RPG7R)
+ sw $3,%lo(RPG7R)($2)
+ # RPG8 is U1RX
+ lui $2,%hi(U1RXR)
+ sw $3,%lo(U1RXR)($2)
+ # TRISG
+ xor $3,$3
+ ori $3,0xfff7
+ lui $2,%hi(TRISG)
+ sw $3,%lo(TRISG)($2)
+
+ # UART
+ xor $3,$3
+ ori $3,0x1400
+ lui $2,%hi(U1STA)
+ sw $3,%lo(U1STA)($2)
+ # BRG := 0; with 8MHz peripheral clock gives baud rate 500000
+ xor $3,$3
+ lui $2,%hi(U1BRG)
+ sw $3,%lo(U1BRG)($2)
+ xor $3,$3
+ ori $3,0x8000
+ lui $2,%hi(U1MODE)
+ sw $3,%lo(U1MODE)($2)
+
+ # Prepare main loop
+ lui $10,%hi(LATB)
+ lui $11,%hi(U1STA)
+ lui $12,%hi(U1TXREG)
+ lui $13,%hi(string)
+ ori $13,%lo(string)
+ # Main loop
+main_loop:
+ # Toggle LED at LATB.B15
+ lw $4,%lo(LATB)($10)
+ andi $6,$4,0x8000
+ andi $4,$4,0x7fff
+ xori $6,0x8000
+ or $4,$4,$6
+ sh $4,%lo(LATB)($10)
+
+ # Wait for UART buffer to empty
+ lw $4,%lo(U1STA)($11)
+main_loop_tx_buffer_full:
+ andi $4,$4,0x200 # UTXBF
+ bne $4,$0,main_loop_tx_buffer_full
+ lw $4,%lo(U1STA)($11)
+
+ # Write one character of the string to U1TXREG
+ lb $4,($13)
+ bne $4,$0,main_loop_no_end_of_string
+ addi $13,1
+ lui $13,%hi(string)
+ ori $13,%lo(string)
+ li $4,10 # \n
+main_loop_no_end_of_string:
+ sw $4,%lo(U1TXREG)($12)
+
+ # Busy wait delay loop
+ lui $2,0xff
+ ori $5,0xffff
+main_loop_delay:
+ bne $2,$0,main_loop_delay
+ addiu $2,-1
+ j main_loop
+ nop
+
+ .end main
+ .size main, .-main