4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/vga.S Sat May 06 17:53:56 2017 +0200
4.3 @@ -0,0 +1,277 @@
4.4 +/*
4.5 + * Generate a VGA signal using a PIC32 microcontroller.
4.6 + *
4.7 + * Copyright (C) 2017 Paul Boddie <paul@boddie.org.uk>
4.8 + *
4.9 + * This program is free software: you can redistribute it and/or modify
4.10 + * it under the terms of the GNU General Public License as published by
4.11 + * the Free Software Foundation, either version 3 of the License, or
4.12 + * (at your option) any later version.
4.13 + *
4.14 + * This program is distributed in the hope that it will be useful,
4.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.17 + * GNU General Public License for more details.
4.18 + *
4.19 + * You should have received a copy of the GNU General Public License
4.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
4.21 + */
4.22 +
4.23 +#include "mips.h"
4.24 +#include "pic32.h"
4.25 +
4.26 +#define HFREQ_LIMIT 627 /* 20MHz cycles */
4.27 +
4.28 +/* Disable JTAG functionality on pins. */
4.29 +
4.30 +.section .devcfg0, "a"
4.31 +.word 0xfffffffb /* DEVCFG0<2> = JTAGEN = 0 */
4.32 +
4.33 +/*
4.34 +Set the oscillator to be the FRC oscillator with PLL, with peripheral clock
4.35 +divided by 1, HS oscillator mode selected (for PLL), and FRCDIV+PLL selected.
4.36 +With a system clock of 20MHz, the peripheral clock is therefore 20MHz.
4.37 +
4.38 +The watchdog timer (FWDTEN) is also disabled.
4.39 +*/
4.40 +
4.41 +.section .devcfg1, "a"
4.42 +.word 0xff7fcff9 /* DEVCFG1<23> = FWDTEN = 0; DEVCFG1<13:12> = FPBDIV<2:0> = 0; DEVCFG1<2:0> = FNOSC<2:0> = 001 */
4.43 +
4.44 +/*
4.45 +Set the FRC oscillator PLL function with an input division of 4, an output
4.46 +division of 2, a multiplication of 20, yielding a multiplication of 2.5.
4.47 +This should take the FRC at 8MHz and produce a system clock of 20MHz.
4.48 +*/
4.49 +
4.50 +.section .devcfg2, "a"
4.51 +.word 0xfff9ffdb /* DEVCFG2<18:16> = FPLLODIV<2:0> = 1; DEVCFG2<6:4> = FPLLMUL<2:0> = 101; DEVCFG2<2:0> = FPLLIDIV<2:0> = 011 */
4.52 +
4.53 +.text
4.54 +.globl _start
4.55 +
4.56 +_start:
4.57 + /*
4.58 + Configure RAM.
4.59 + See: http://microchipdeveloper.com/32bit:mx-arch-exceptions-processor-initialization
4.60 + */
4.61 +
4.62 + la $v0, BMXCON
4.63 + li $v1, (1 << 6) /* BMXCON<6> = BMXWSDRM = 0 */
4.64 + sw $v1, CLR($v0)
4.65 +
4.66 + /* Enable caching. */
4.67 +
4.68 + li $v0, CONFIG_CM_CACHABLE_NONCOHERENT
4.69 + mtc0 $v0, CP0_CONFIG
4.70 + nop
4.71 +
4.72 + /* Get the RAM size. */
4.73 +
4.74 + la $v0, BMXDRMSZ
4.75 + lw $v0, 0($v0)
4.76 +
4.77 + /* Initialise the stack pointer. */
4.78 +
4.79 + lui $v1, 0x8000 /* 0x80000000 */
4.80 + addu $sp, $v0, $v1 /* sp = 0x80000000 + RAM size */
4.81 +
4.82 + /* Initialise the globals pointer. */
4.83 +
4.84 + lui $gp, %hi(_GLOBAL_OFFSET_TABLE_)
4.85 + ori $gp, $gp, %lo(_GLOBAL_OFFSET_TABLE_)
4.86 +
4.87 + /* Set pins for output and set outputs low. */
4.88 +
4.89 + jal init_pins
4.90 + nop
4.91 +
4.92 + /* Initialise the status register. */
4.93 +
4.94 + jal init_interrupts
4.95 + nop
4.96 +
4.97 + /* Initialise timer. */
4.98 +
4.99 + jal init_timer1
4.100 + nop
4.101 +
4.102 + /* Enable interrupts and loop. */
4.103 +
4.104 + jal enable_interrupts
4.105 + nop
4.106 +
4.107 + jal handle_error_level
4.108 + nop
4.109 +
4.110 + li $a1, 20000000 /* counter = 20000000 */
4.111 + li $a2, 31872
4.112 +loop:
4.113 + addiu $a1, $a1, -1 /* counter -= 1 */
4.114 + bnez $a1, loop /* until counter == 0 */
4.115 + nop
4.116 +
4.117 + li $a1, 20000000 /* counter = 20000000 */
4.118 +
4.119 + la $v0, PORTB
4.120 + la $v1, (1 << 10) /* PORTB<10> = RB10 */
4.121 + sw $v1, INV($v0)
4.122 +
4.123 +_next:
4.124 + j loop
4.125 + nop
4.126 +
4.127 +
4.128 +
4.129 +init_pins:
4.130 + /* DEVCFG<2> needs setting to 0 before the program is run. */
4.131 +
4.132 + la $v0, CFGCON
4.133 + li $v1, (1 << 3) /* CFGCON<3> = JTAGEN = 0 */
4.134 + sw $v1, CLR($v0)
4.135 +
4.136 + la $v0, TRISB
4.137 + li $v1, (7 << 7) | 15 /* TRISB<9:7> = RB9, RB8, RB7 = 0 */
4.138 + /* sw $v1, CLR($v0) */
4.139 +
4.140 + la $v0, PORTB
4.141 + li $v1, (7 << 7) | 15 /* PORTB<9:7> = RB9, RB8, RB7 = 0 */
4.142 + /* sw $v1, CLR($v0) */
4.143 +
4.144 +init_leds:
4.145 + la $v0, TRISA
4.146 + li $v1, (1 << 2) /* TRISA<2> = RA2 = 0 */
4.147 + sw $v1, CLR($v0)
4.148 +
4.149 + la $v0, TRISB
4.150 + li $v1, (3 << 10) /* TRISB<11:10> = RB11, RB10 = 0 */
4.151 + sw $v1, CLR($v0)
4.152 +
4.153 +clear_leds:
4.154 + la $v0, PORTA
4.155 + li $v1, (1 << 2) /* PORTA<2> = RA2 = 0 */
4.156 + sw $v1, CLR($v0)
4.157 +
4.158 + la $v0, PORTB
4.159 + li $v1, (3 << 10) /* PORTB<11:10> = RB11, RB10 = 0 */
4.160 + sw $v1, CLR($v0)
4.161 +
4.162 + jr $ra
4.163 + nop
4.164 +
4.165 +
4.166 +
4.167 +/* Utilities. */
4.168 +
4.169 +handle_error_level:
4.170 + mfc0 $t3, CP0_STATUS
4.171 + li $t4, ~(STATUS_ERL | STATUS_EXL)
4.172 + and $t3, $t3, $t4
4.173 + mtc0 $t3, CP0_STATUS
4.174 + jr $ra
4.175 + nop
4.176 +
4.177 +enable_interrupts:
4.178 + mfc0 $t3, CP0_STATUS
4.179 + nop
4.180 + ori $t3, $t3, STATUS_IRQ | STATUS_IE
4.181 + mtc0 $t3, CP0_STATUS
4.182 + jr $ra
4.183 + nop
4.184 +
4.185 +init_interrupts:
4.186 + mfc0 $t3, CP0_STATUS
4.187 + li $t4, ~STATUS_BEV
4.188 + and $t3, $t3, $t4
4.189 + mtc0 $t3, CP0_STATUS /* CP0_STATUS &= ~STATUS_BEV (use non-bootloader vectors) */
4.190 +
4.191 + la $t3, _start
4.192 + mtc0 $t3, CP0_EBASE /* EBASE = _start */
4.193 +
4.194 + li $t3, CAUSE_IV /* IV = 1 (use EBASE+0x200 for interrupts) */
4.195 + mtc0 $t3, CP0_CAUSE
4.196 +
4.197 + jr $ra
4.198 + nop
4.199 +
4.200 +
4.201 +
4.202 +/* Interrupt servicing. */
4.203 +
4.204 +.org 0x200
4.205 +
4.206 +interrupt_handler:
4.207 +
4.208 + /* Check for a timer interrupt condition. */
4.209 +
4.210 + la $v0, IFS0
4.211 + lw $v1, 0($v0)
4.212 + and $v1, $v1, (1 << 4) /* T1IF */
4.213 + beqz $v1, irq_exit
4.214 + nop
4.215 +
4.216 + addiu $a2, $a2, -1
4.217 + bnez $a2, irq_clear
4.218 + nop
4.219 +
4.220 + li $a2, 31872
4.221 +
4.222 + /* Invert an LED. */
4.223 +
4.224 + la $v0, PORTB
4.225 + la $v1, (1 << 11) /* PORTB<11> = RB11 */
4.226 + sw $v1, INV($v0)
4.227 +
4.228 +irq_clear:
4.229 +
4.230 + /* Clear the timer interrupt condition. */
4.231 +
4.232 + la $v0, IFS0
4.233 + li $v1, (1 << 4) /* IFS0<4> = T1IF = 0 */
4.234 + sw $v1, CLR($v0)
4.235 +
4.236 +irq_exit:
4.237 + eret
4.238 + nop
4.239 +
4.240 +
4.241 +
4.242 +/* Initialisation routines. */
4.243 +
4.244 +init_timer1:
4.245 +
4.246 + /* Initialise Timer1 interrupt. */
4.247 +
4.248 + la $v0, T1CON
4.249 + sw $zero, 0($v0) /* T1CON = 0 */
4.250 + nop
4.251 +
4.252 + la $v0, TMR1
4.253 + sw $zero, 0($v0) /* TMR1 = 0 */
4.254 + la $v0, PR1
4.255 + li $v1, HFREQ_LIMIT
4.256 + sw $v1, 0($v0) /* PR1 = HFREQ_LIMIT */
4.257 +
4.258 + /* Initialise Timer1 interrupt. */
4.259 +
4.260 + la $v0, IFS0
4.261 + li $v1, (1 << 4)
4.262 + sw $v1, CLR($v0) /* IFS0CLR: T1IF = 0 */
4.263 + la $v0, IPC1
4.264 + li $v1, (7 << 2)
4.265 + sw $v1, SET($v0) /* IPC1SET: T1IP = 7 */
4.266 + la $v0, IPC1
4.267 + li $v1, 3
4.268 + sw $v1, SET($v0) /* IPC1SET: T1IS = 3 */
4.269 + la $v0, IEC0
4.270 + li $v1, (1 << 4)
4.271 + sw $v1, SET($v0) /* IEC0SET: T1IE = 1 */
4.272 +
4.273 + /* Start timer. */
4.274 +
4.275 + la $v0, T1CON
4.276 + li $v1, (1 << 15) /* ON = 1 */
4.277 + sw $v1, SET($v0) /* T1CONSET: ON = 1 */
4.278 +
4.279 + jr $ra
4.280 + nop
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/vga.ld Sat May 06 17:53:56 2017 +0200
5.3 @@ -0,0 +1,44 @@
5.4 +OUTPUT_ARCH(mips)
5.5 +ENTRY(_start)
5.6 +
5.7 +/* See...
5.8 + * FIGURE 4-5: MEMORY MAP ON RESET FOR PIC32MX170/270 DEVICES (64 KB RAM, 256 KB FLASH)
5.9 + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet
5.10 + */
5.11 +
5.12 +MEMORY
5.13 +{
5.14 + kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x10000
5.15 + kseg0_program_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 0xBF0
5.16 + physical_program_mem (rx) : ORIGIN = 0x1FC00000, LENGTH = 0xBF0
5.17 + sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
5.18 + configsfrs : ORIGIN = 0xBFC00BF0, LENGTH = 0x10
5.19 + config3 : ORIGIN = 0xBFC00BF0, LENGTH = 0x4
5.20 + config2 : ORIGIN = 0xBFC00BF4, LENGTH = 0x4
5.21 + config1 : ORIGIN = 0xBFC00BF8, LENGTH = 0x4
5.22 + config0 : ORIGIN = 0xBFC00BFC, LENGTH = 0x4
5.23 + physical_config3 : ORIGIN = 0x3FC00BF0, LENGTH = 0x4
5.24 + physical_config2 : ORIGIN = 0x3FC00BF4, LENGTH = 0x4
5.25 + physical_config1 : ORIGIN = 0x3FC00BF8, LENGTH = 0x4
5.26 + physical_config0 : ORIGIN = 0x3FC00BFC, LENGTH = 0x4
5.27 +}
5.28 +
5.29 +SECTIONS
5.30 +{
5.31 + .text : { *(.text*) } > kseg0_program_mem AT > physical_program_mem
5.32 + .bss : { *(.bss*) } > kseg1_data_mem
5.33 + .got : {
5.34 + _gp = ALIGN(16);
5.35 + *(.got*)
5.36 + } > kseg0_program_mem AT > physical_program_mem
5.37 + .devcfg0 : {
5.38 + *(.devcfg0)
5.39 + } > config0 AT > physical_config0
5.40 + .devcfg1 : {
5.41 + *(.devcfg1)
5.42 + } > config1 AT > physical_config1
5.43 + .devcfg2 : {
5.44 + *(.devcfg2)
5.45 + } > config2 AT > physical_config2
5.46 + /DISCARD/ : { *(.reginfo) *(.MIPS.abiflags) }
5.47 +}