2025-06-15 21:31:45 +08:00

4983 lines
212 KiB
C

/***********************************************************************************************************************
PicoMite MMBasic
Picomite.c
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
Copyright (c) 2021, <COPYRIGHT HOLDERS> All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed
on the console at startup (additional copyright messages may be added).
4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed
by the <copyright holder>.
5. Neither the name of the <copyright holder> nor the names of its contributors may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDERS> AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDERS> BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
************************************************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdbool.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "pico/binary_info.h"
#include "configuration.h"
#include "hardware/watchdog.h"
#include "hardware/clocks.h"
#include "hardware/flash.h"
#include "hardware/adc.h"
#include "hardware/exception.h"
#include "MMBasic_Includes.h"
#include "Hardware_Includes.h"
#include "hardware/structs/systick.h"
#include "hardware/structs/timer.h"
#include "hardware/vreg.h"
#include "hardware/structs/pads_qspi.h"
#include "pico/unique_id.h"
#include "hardware/pwm.h"
extern void start_i2s(int pio, int sm);
#ifdef rp2350
#include "hardware/structs/qmi.h"
#endif
#ifdef PICOMITEVGA
extern void start_vga_i2s(void);
#ifndef HDMI
#endif
#endif
#define COPYRIGHT "Copyright " YEAR " Geoff Graham\r\n"\
"Copyright " YEAR2 " Peter Mather\r\n\r\n"
#ifdef USBKEYBOARD
#include "tusb.h"
#include "host/hcd.h"
#include "usb_host_files/tusb_config.h"
#else
#include "pico/unique_id.h"
#include "class/cdc/cdc_device.h"
#endif
#ifndef rp2350
#include "hardware/structs/ssi.h"
#include "hardware/vreg.h"
#else
#ifdef HDMI
#include "hardware/structs/hstx_ctrl.h"
#include "hardware/structs/hstx_fifo.h"
#endif
#include "hardware/dma.h"
#include "hardware/gpio.h"
#include "hardware/irq.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/xip_ctrl.h"
#include "hardware/structs/sio.h"
#include "hardware/vreg.h"
#include "pico/multicore.h"
#include "pico/sem.h"
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include <string.h>
#include "hardware/regs/sysinfo.h"
#include "hardware/regs/powman.h"
bool rp2350a=true;
uint32_t PSRAMsize=0;
#endif
#include "hardware/structs/bus_ctrl.h"
#include <pico/bootrom.h>
#include "hardware/irq.h"
#include "hardware/pio.h"
#include "hardware/pio_instructions.h"
#ifdef PICOMITEWEB
#include "lwipopts.h"
#include "pico/cyw43_arch.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/dns.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#endif
#ifdef PICOMITEVGA
uint16_t map16[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint32_t map16pairs[16];
volatile uint8_t transparent=0;
volatile uint8_t transparents=0;
volatile int RGBtransparent=0;
int MODE1SIZE, MODE2SIZE, MODE3SIZE, MODE4SIZE, MODE5SIZE;
#ifdef HDMI
uint16_t map16d[16];
uint32_t map16q[16];
uint8_t map16s[16];
#endif
// 126 MHz timings
int QVGA_TOTAL;// total clock ticks (= QVGA_HSYNC + QVGA_BP + WIDTH*QVGA_CPP[1600] + QVGA_FP)
int QVGA_HSYNC; // horizontal sync clock ticks
int QVGA_BP ; // back porch clock ticks
int QVGA_FP; // front porch clock ticks
// QVGA vertical timings
int QVGA_VACT; // V active scanlines (= 2*HEIGHT)
int QVGA_VFRONT; // V front porch
int QVGA_VSYNC; // length of V sync (number of scanlines)
int QVGA_VBACK; // V back porch
int QVGA_VTOT; // total scanlines (= QVGA_VSYNC + QVGA_VBACK + QVGA_VACT + QVGA_VFRONT)
int QVGA_HACT; // V active scanlines (= 2*HEIGHT)
#ifndef HDMI
#include "Include.h"
#endif
#ifdef USBKEYBOARD
#ifdef HDMI
#define MES_SIGNON "\rPicoMiteHDMI MMBasic USB " CHIP " Edition V"VERSION "\r\n"
#else
#define MES_SIGNON "\rPicoMiteVGA MMBasic USB " CHIP " Edition V"VERSION "\r\n"
#endif
extern void hid_app_task(void);
volatile int keytimer=0;
extern void USB_bus_reset(void);
bool USBenabled=false;
#else
#ifdef HDMI
#define MES_SIGNON "\rPicoMiteHDMI MMBasic " CHIP " Edition V"VERSION "\r\n"
#else
#define MES_SIGNON "\rPicoMiteVGA MMBasic " CHIP " Edition V"VERSION "\r\n"
#endif
#endif
#endif
#ifdef PICOMITEWEB
#define MES_SIGNON "\rWebMite MMBasic " CHIP " Edition V"VERSION "\r\n"
volatile int WIFIconnected=0;
int startupcomplete=0;
void ProcessWeb(int mode);
char LCDAttrib=0;
#endif
#ifdef PICOMITE
#ifdef USBKEYBOARD
#include "tusb.h"
#include "host/hcd.h"
#define MES_SIGNON "\rPicoMite MMBasic USB " CHIP " Edition V"VERSION "\r\n"
extern void hid_app_task(void);
volatile int keytimer=0;
extern void USB_bus_reset(void);
bool USBenabled=false;
#include "pico/multicore.h"
mutex_t frameBufferMutex; // mutex to lock frame buffer
#else
#define MES_SIGNON "\rPicoMite MMBasic " CHIP " Edition V"VERSION "\r\n"
#include "pico/multicore.h"
mutex_t frameBufferMutex; // mutex to lock frame buffer
#endif
char LCDAttrib=0;
#endif
#define KEYCHECKTIME 16
int ListCnt;
int MMCharPos;
int MMPromptPos;
int busfault=0;
int ExitMMBasicFlag = false;
volatile int MMAbort = false;
unsigned int _excep_peek;
void CheckAbort(void);
void TryLoadProgram(void);
unsigned char lastchar=0;
int adc_clk_div;
unsigned char BreakKey = BREAK_KEY; // defaults to CTRL-C. Set to zero to disable the break function
volatile char ConsoleRxBuf[CONSOLE_RX_BUF_SIZE]={0};
volatile int ConsoleRxBufHead = 0;
volatile int ConsoleRxBufTail = 0;
volatile char ConsoleTxBuf[CONSOLE_TX_BUF_SIZE]={0};
volatile int ConsoleTxBufHead = 0;
volatile int ConsoleTxBufTail = 0;
uint I2SOff;
#ifndef USBKEYBOARD
extern void initMouse0(int sensitivity);
volatile unsigned int MouseTimer = 0;
#endif
volatile unsigned int AHRSTimer = 0;
volatile unsigned int InkeyTimer = 0;
volatile long long int mSecTimer = 0; // this is used to count mSec
volatile unsigned int WDTimer = 0;
volatile unsigned int diskchecktimer = DISKCHECKRATE;
volatile unsigned int clocktimer=60*60*1000;
volatile unsigned int PauseTimer = 0;
volatile unsigned int ClassicTimer = 0;
volatile unsigned int NunchuckTimer = 0;
volatile unsigned int IntPauseTimer = 0;
volatile unsigned int Timer1=0, Timer2=0, Timer3=0, Timer4=0, Timer5=0; //1000Hz decrement timer
volatile unsigned int KeyCheck=2000;
volatile int ds18b20Timer = -1;
volatile unsigned int ScrewUpTimer = 0;
//volatile int second = 0; // date/time counters
//volatile int minute = 0;
//volatile int hour = 0;
//volatile int day = 1;
//volatile int month = 1;
//volatile int year = 2000;
volatile unsigned int GPSTimer = 0;
volatile unsigned int SecondsTimer = 0;
volatile unsigned int I2CTimer = 0;
volatile int day_of_week=1;
unsigned char PulsePin[NBR_PULSE_SLOTS];
unsigned char PulseDirection[NBR_PULSE_SLOTS];
int PulseCnt[NBR_PULSE_SLOTS];
int PulseActive;
const uint8_t *flash_option_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
const uint8_t *SavedVarsFlash = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE);
const uint8_t *flash_target_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE);
const uint8_t *flash_progmemory = (const uint8_t *) (XIP_BASE + PROGSTART);
const uint8_t *flash_libmemory = (const uint8_t *) (XIP_BASE + PROGSTART - MAX_PROG_SIZE);
int ticks_per_second;
int InterruptUsed;
int calibrate=0;
char id_out[12];
MMFLOAT VCC=3.3;
int PromptFont, PromptFC=0xFFFFFF, PromptBC=0; // the font and colours selected at the prompt
volatile int DISPLAY_TYPE;
volatile bool processtick = true;
unsigned char WatchdogSet = false;
unsigned char IgnorePIN = false;
unsigned char SPIatRisk = false;
uint32_t restart_reason=0;
uint32_t __uninitialized_ram(_excep_code);
uint64_t __uninitialized_ram(_persistent);
unsigned char lastcmd[STRINGSIZE*2]; // used to store the last command in case it is needed by the EDIT command
FATFS fs; // Work area (file system object) for logical drive
bool timer_callback(repeating_timer_t *rt);
static uint64_t __not_in_flash_func(uSecFunc)(uint64_t a){
uint64_t b=time_us_64()+a;
while(time_us_64()<b){}
return b;
}
extern void MX470Display(int fn);
//Vector to CFunction routine called every command (ie, from the BASIC interrupt checker)
extern unsigned int CFuncInt1;
//Vector to CFunction routine called by the interrupt 2 handler
extern unsigned int CFuncInt2;
extern unsigned int CFuncmSec;
extern void CallCFuncInt1(void);
extern void CallCFuncInt2(void);
extern volatile bool CSubComplete;
static uint64_t __not_in_flash_func(uSecTimer)(void){ return time_us_64();}
static int64_t PinReadFunc(int a){return gpio_get(PinDef[a].GPno);}
extern void CallCFuncmSec(void);
extern volatile uint32_t irqs;
#define CFUNCRAM_SIZE 256
int CFuncRam[CFUNCRAM_SIZE/sizeof(int)];
repeating_timer_t timer;
MMFLOAT IntToFloat(long long int a){ return a; }
MMFLOAT FMul(MMFLOAT a, MMFLOAT b){ return a * b; }
MMFLOAT FAdd(MMFLOAT a, MMFLOAT b){ return a + b; }
MMFLOAT FSub(MMFLOAT a, MMFLOAT b){ return a - b; }
MMFLOAT FDiv(MMFLOAT a, MMFLOAT b){ return a / b; }
uint32_t CFunc_delay_us;
#ifndef HDMI
int QVGA_CLKDIV; // SM divide clock ticks
#endif
void PIOExecute(int pion, int sm, uint32_t ins){
PIO pio = (pion ? pio1: pio0);
pio_sm_exec(pio, sm, ins);
}
int IDiv(int a, int b){return a/b;}
int FCmp(MMFLOAT a,MMFLOAT b){if(a>b) return 1;else if(a<b)return -1; else return 0;}
MMFLOAT LoadFloat(unsigned long long c){union ftype{ unsigned long long a; MMFLOAT b;}f;f.a=c;return f.b; }
const void * const CallTable[] __attribute__((section(".text"))) = { (void *)uSecFunc, //0x00
(void *)putConsole, //0x04
(void *)getConsole, //0x08
(void *)ExtCfg, //0x0c
(void *)ExtSet, //0x10
(void *)ExtInp, //0x14
(void *)PinSetBit, //0x18
(void *)PinReadFunc, //0x1c
(void *)MMPrintString, //0x20
(void *)IntToStr, //0x24
(void *)CheckAbort, //0x28
(void *)GetMemory, //0x2c
(void *)GetTempMemory, //0x30
(void *)FreeMemory, //0x34
(void *)&DrawRectangle, //0x38
(void *)&DrawBitmap, //0x3c
(void *)DrawLine, //0x40
(void *)FontTable, //0x44
(void *)&ExtCurrentConfig, //0x48
(void *)&HRes, //0x4C
(void *)&VRes, //0x50
(void *)SoftReset, //0x54
(void *)error, //0x58
(void *)&ProgMemory, //0x5c
(void *)&g_vartbl, //0x60
(void *)&g_varcnt, //0x64
(void *)&DrawBuffer, //0x68
(void *)&ReadBuffer, //0x6c
(void *)&FloatToStr, //0x70
(void *)CallExecuteProgram, //0x74
(void *)&CFuncmSec, //0x78
(void *)CFuncRam, //0x7c
(void *)&ScrollLCD, //0x80
(void *)IntToFloat, //0x84
(void *)FloatToInt64, //0x88
(void *)&Option, //0x8c
(void *)sin, //0x90
(void *)DrawCircle, //0x94
(void *)DrawTriangle, //0x98
(void *)uSecTimer, //0x9c
(void *)FMul,//0xa0
(void *)FAdd,//0xa4
(void *)FSub,//0xa8
(void *)FDiv,//0xac
(void *)FCmp,//0xb0
(void *)&LoadFloat,//0xb4
(void *)&CFuncInt1, //0xb8
(void *)&CFuncInt2, //0xbc
(void *)&CSubComplete, //0xc0
(void *)&AudioOutput, //0xc4
(void *)IDiv,//0x0xc8
(void *)&AUDIO_WRAP,//0x0xcc
(void *)&CFuncInt3, //0xb8
(void *)&CFuncInt4, //0xbc
(void *)PIOExecute,
};
const struct s_PinDef PinDef[]={
{ 0, 99, "NULL", UNUSED ,99, 99},
{ 1, 0, "GP0", DIGITAL_IN | DIGITAL_OUT | SPI0RX | UART0TX | I2C0SDA | PWM0A,99,0}, // pin 1
{ 2, 1, "GP1", DIGITAL_IN | DIGITAL_OUT | UART0RX | I2C0SCL | PWM0B ,99,128}, // pin 2
{ 3, 99, "GND", UNUSED ,99,99}, // pin 3
{ 4, 2, "GP2", DIGITAL_IN | DIGITAL_OUT | SPI0SCK | I2C1SDA | PWM1A ,99,1}, // pin 4
{ 5, 3, "GP3", DIGITAL_IN | DIGITAL_OUT | SPI0TX | I2C1SCL | PWM1B ,99,129}, // pin 5
{ 6, 4, "GP4", DIGITAL_IN | DIGITAL_OUT | SPI0RX| UART1TX | I2C0SDA | PWM2A ,99,2}, // pin 6
{ 7, 5, "GP5", DIGITAL_IN | DIGITAL_OUT | UART1RX | I2C0SCL | PWM2B ,99,130}, // pin 7
{ 8, 99, "GND", UNUSED ,99, 99}, // pin 8
{ 9, 6, "GP6", DIGITAL_IN | DIGITAL_OUT | SPI0SCK | I2C1SDA | PWM3A ,99, 3}, // pin 9
{ 10, 7, "GP7", DIGITAL_IN | DIGITAL_OUT | SPI0TX | I2C1SCL | PWM3B ,99, 131}, // pin 10
{ 11, 8, "GP8", DIGITAL_IN | DIGITAL_OUT | SPI1RX | UART1TX | I2C0SDA | PWM4A ,99, 4}, // pin 11
{ 12, 9, "GP9", DIGITAL_IN | DIGITAL_OUT | UART1RX | I2C0SCL | PWM4B ,99, 132}, // pin 12
{ 13, 99, "GND", UNUSED ,99, 99}, // pin 13
{ 14, 10, "GP10", DIGITAL_IN | DIGITAL_OUT | SPI1SCK | I2C1SDA | PWM5A ,99, 5}, // pin 14
{ 15, 11, "GP11", DIGITAL_IN | DIGITAL_OUT | SPI1TX | I2C1SCL | PWM5B ,99, 133}, // pin 15
#ifdef HDMI
{ 16, 12, "HDMI", UNUSED ,99, 99}, // pin 16
{ 17, 13, "HDMI", UNUSED ,99, 99}, // pin 17
{ 18, 99, "GND", UNUSED ,99, 99}, // pin 18
{ 19, 14, "HDMI", UNUSED ,99, 99}, // pin 19
{ 20, 15, "HDMI", UNUSED ,99, 99}, // pin 20
{ 21, 16, "HDMI", UNUSED ,99, 99}, // pin 21
{ 22, 17, "HDMI", UNUSED ,99, 99}, // pin 22
{ 23, 99, "GND", UNUSED ,99, 99}, // pin 23
{ 24, 18, "HDMI", UNUSED ,99, 99}, // pin 24
{ 25, 19, "HDMI", UNUSED ,99, 99}, // pin 25
#else
{ 16, 12, "GP12", DIGITAL_IN | DIGITAL_OUT | SPI1RX | UART0TX | I2C0SDA | PWM6A ,99, 6}, // pin 16
{ 17, 13, "GP13", DIGITAL_IN | DIGITAL_OUT | UART0RX | I2C0SCL | PWM6B ,99, 134}, // pin 17
{ 18, 99, "GND", UNUSED ,99, 99}, // pin 18
{ 19, 14, "GP14", DIGITAL_IN | DIGITAL_OUT | SPI1SCK | I2C1SDA | PWM7A ,99, 7}, // pin 19
{ 20, 15, "GP15", DIGITAL_IN | DIGITAL_OUT | SPI1TX | I2C1SCL | PWM7B ,99, 135}, // pin 20
{ 21, 16, "GP16", DIGITAL_IN | DIGITAL_OUT | SPI0RX | UART0TX | I2C0SDA | PWM0A ,99, 0}, // pin 21
{ 22, 17, "GP17", DIGITAL_IN | DIGITAL_OUT | UART0RX | I2C0SCL | PWM0B ,99, 128}, // pin 22
{ 23, 99, "GND", UNUSED ,99, 99}, // pin 23
{ 24, 18, "GP18", DIGITAL_IN | DIGITAL_OUT | SPI0SCK | I2C1SDA | PWM1A ,99, 1}, // pin 24
{ 25, 19, "GP19", DIGITAL_IN | DIGITAL_OUT | SPI0TX | I2C1SCL | PWM1B ,99, 129}, // pin 25
#endif
{ 26, 20, "GP20", DIGITAL_IN | DIGITAL_OUT | SPI0RX | UART1TX| I2C0SDA | PWM2A ,99, 2}, // pin 26
{ 27, 21, "GP21", DIGITAL_IN | DIGITAL_OUT | UART1RX| I2C0SCL | PWM2B ,99, 130}, // pin 27
{ 28, 99, "GND", UNUSED ,99, 99}, // pin 28
{ 29, 22, "GP22", DIGITAL_IN | DIGITAL_OUT | SPI0SCK | I2C1SDA| PWM3A ,99, 3}, // pin 29
{ 30, 99, "RUN", UNUSED ,99, 99}, // pin 30
{ 31, 26, "GP26", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | SPI1SCK| I2C1SDA | PWM5A , 0 , 5},// pin 31
{ 32, 27, "GP27", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | SPI1TX| I2C1SCL | PWM5B , 1, 133},// pin 32
{ 33, 99, "AGND", UNUSED ,99, 99}, // pin 33
{ 34, 28, "GP28", DIGITAL_IN |DIGITAL_OUT| ANALOG_IN| SPI1RX| UART0TX|I2C0SDA| PWM6A, 2, 6},// pin 34
{ 35, 99, "VREF", UNUSED ,99, 99}, // pin 35
{ 36, 99, "3V3", UNUSED ,99, 99}, // pin 36
{ 37, 99, "3V3E", UNUSED ,99, 99}, // pin 37
{ 38, 99, "GND", UNUSED ,99, 99}, // pin 38
{ 39, 99, "VSYS", UNUSED ,99, 99}, // pin 39
{ 40, 99, "VBUS", UNUSED ,99, 99}, // pin 40
#ifndef PICOMITEWEB
{ 41, 23, "GP23", DIGITAL_IN | DIGITAL_OUT | SPI0TX | I2C1SCL| PWM3B ,99 , 131}, // pseudo pin 41
{ 42, 24, "GP24", DIGITAL_IN | DIGITAL_OUT | SPI1RX | UART1TX | I2C0SDA| PWM4A ,99 , 4}, // pseudo pin 42
{ 43, 25, "GP25", DIGITAL_IN | DIGITAL_OUT | UART1RX | I2C0SCL| PWM4B ,99 , 132}, // pseudo pin 43
{ 44, 29, "GP29", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | UART0RX | I2C0SCL | PWM6B, 3, 134},// pseudo pin 44
#endif
#ifdef rp2350
#ifndef PICOMITEWEB
{ 45, 30, "GP30", DIGITAL_IN | DIGITAL_OUT | SPI1SCK | I2C1SDA | PWM7A ,99 , 7}, // pseudo pin 45
{ 46, 31, "GP31", DIGITAL_IN | DIGITAL_OUT | SPI1TX | I2C1SCL| PWM7B ,99 , 135}, // pseudo pin 46
{ 47, 32, "GP32", DIGITAL_IN | DIGITAL_OUT | UART0TX | SPI0RX | I2C0SDA| PWM8A ,99 , 8}, // pseudo pin 47
{ 48, 33, "GP33", DIGITAL_IN | DIGITAL_OUT | UART0RX | I2C0SCL| PWM8B ,99 , 136}, // pseudo pin 48
{ 49, 34, "GP34", DIGITAL_IN | DIGITAL_OUT | SPI0SCK | I2C1SDA| PWM9A ,99 , 9}, // pseudo pin 49
{ 50, 35, "GP35", DIGITAL_IN | DIGITAL_OUT | SPI0TX | I2C1SCL| PWM9B ,99 , 137}, // pseudo pin 50
{ 51, 36, "GP36", DIGITAL_IN | DIGITAL_OUT | UART1TX | SPI0RX | I2C0SDA| PWM10A ,99 , 10}, // pseudo pin 51
{ 52, 37, "GP37", DIGITAL_IN | DIGITAL_OUT | UART1RX | I2C0SCL| PWM10B ,99 , 138}, // pseudo pin 52
{ 53, 38, "GP38", DIGITAL_IN | DIGITAL_OUT | SPI0SCK | I2C1SDA| PWM11A ,99 , 11}, // pseudo pin 53
{ 54, 39, "GP39", DIGITAL_IN | DIGITAL_OUT | SPI0TX | I2C1SCL| PWM11B ,99 , 139}, // pseudo pin 54
{ 55, 40, "GP40", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN| UART1TX | SPI1RX | I2C0SDA| PWM8A ,0 , 8}, // pseudo pin 55
{ 56, 41, "GP41", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN| UART1RX | I2C0SCL| PWM8B ,1 , 136}, // pseudo pin 56
{ 57, 42, "GP42", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN| SPI1SCK | I2C1SDA| PWM9A ,2 , 9}, // pseudo pin 57
{ 58, 43, "GP43", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN| SPI1TX | I2C1SCL| PWM9B ,3 , 137}, // pseudo pin 58
{ 59, 44, "GP44", DIGITAL_IN | DIGITAL_OUT | UART0TX | ANALOG_IN | SPI1RX | I2C0SDA| PWM10A ,4 , 10}, // pseudo pin 59
{ 60, 45, "GP45", DIGITAL_IN | DIGITAL_OUT | UART0RX | ANALOG_IN | I2C0SCL| PWM10B ,5 , 138}, // pseudo pin 60
{ 61, 46, "GP46", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | SPI1SCK | I2C1SDA| PWM11A ,6 , 11}, // pseudo pin 61
{ 62, 47, "GP47", DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | SPI1TX | I2C1SCL| PWM11B ,7 , 139}, // pseudo pin 62
#endif
#endif
};
char alive[]="\033[?25h";
const char DaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static inline CommandToken commandtbl_decode(const unsigned char *p){
return ((CommandToken)(p[0] & 0x7f)) | ((CommandToken)(p[1] & 0x7f)<<7);
}
char banner[64];
void __not_in_flash_func(routinechecks)(void){
static int when=0;
if(abs((time_us_64()-mSecTimer*1000))> 5000){
cancel_repeating_timer(&timer);
add_repeating_timer_us(-1000, timer_callback, NULL, &timer);
mSecTimer=time_us_64()/1000;
}
if (CurrentlyPlaying == P_WAV || CurrentlyPlaying == P_FLAC || CurrentlyPlaying==P_MP3 || CurrentlyPlaying==P_MIDI ){
#ifdef PICOMITE
if(SPIatRisk)mutex_enter_blocking(&frameBufferMutex); // lock the frame buffer
#endif
checkWAVinput();
#ifdef PICOMITE
if(SPIatRisk)mutex_exit(&frameBufferMutex);
#endif
}
if(CurrentlyPlaying == P_MOD) checkWAVinput();
if(++when & 7 && CurrentLinePtr) return;
#ifdef USBKEYBOARD
if(USBenabled){
if(mSecTimer>2000){
tuh_task();
hid_app_task();
}
}
#else
static int c, read=0;
if(tud_cdc_connected() && (Option.SerialConsole==0 || Option.SerialConsole>4) && Option.Telnet!=-1){
while(( c=tud_cdc_read_char())!=-1){
ConsoleRxBuf[ConsoleRxBufHead] = c;
if(BreakKey && ConsoleRxBuf[ConsoleRxBufHead] == BreakKey) {// if the user wants to stop the progran
MMAbort = true; // set the flag for the interpreter to see
ConsoleRxBufHead = ConsoleRxBufTail; // empty the buffer
} else if(ConsoleRxBuf[ConsoleRxBufHead] == keyselect && KeyInterrupt!=NULL){
Keycomplete=true;
} else {
ConsoleRxBufHead = (ConsoleRxBufHead + 1) % CONSOLE_RX_BUF_SIZE; // advance the head of the queue
if(ConsoleRxBufHead == ConsoleRxBufTail) { // if the buffer has overflowed
ConsoleRxBufTail = (ConsoleRxBufTail + 1) % CONSOLE_RX_BUF_SIZE; // throw away the oldest char
}
}
}
}
#endif
if(GPSchannel)processgps();
if(diskchecktimer == 0)CheckSDCard();
#ifdef GUICONTROLS
if(Ctrl && TOUCH_GETIRQTRIS && !calibrate)ProcessTouch();
#endif
// if(tud_cdc_connected() && KeyCheck==0){
// SSPrintString(alive);
// }
if(clocktimer==0 && Option.RTC){
if(classicread==0 && nunchuckread==0){
RtcGetTime(0);
}
}
#ifndef USBKEYBOARD
if(Option.KeyboardConfig==CONFIG_I2C && KeyCheck==0){
if(read==0){
CheckI2CKeyboard(0,0);
read=1;
} else {
CheckI2CKeyboard(0,1);
read=0;
}
KeyCheck=KEYCHECKTIME;
}
#endif
if(classic1 && ClassicTimer>=10){
if(classicread==0){
WiiSend(sizeof(readcontroller),(char *)readcontroller);
if(!mmI2Cvalue)classicread=1;
} else if(classicread==1){
WiiReceive(6, (char *)nunbuff);
if(!mmI2Cvalue)classicread=2;
else classicread=0;
} else {
classicproc();
classicread=0;
classic1=2;
}
ClassicTimer=0;
}
if(nunchuck1 && NunchuckTimer>=10){
if(nunchuckread==false){
WiiSend(sizeof(readcontroller),(char *)readcontroller);
if(!mmI2Cvalue)nunchuckread=1;
} else if(nunchuckread==1){
WiiReceive(6, (char *)nunbuff);
if(!mmI2Cvalue)nunchuckread=2;
else nunchuckread=0;
} else {
nunproc();
nunchuckread=0;
nunchuck1=2;
}
NunchuckTimer=0;
}
/*frame
if(frame && CurrentLinePtr)ShowCursor(framecursor);
*/
}
int __not_in_flash_func(getConsole)(void) {
int c=-1;
#ifdef PICOMITEWEB
ProcessWeb(1);
#endif
CheckAbort();
if(ConsoleRxBufHead != ConsoleRxBufTail) { // if the queue has something in it
c = ConsoleRxBuf[ConsoleRxBufTail];
ConsoleRxBufTail = (ConsoleRxBufTail + 1) % CONSOLE_RX_BUF_SIZE; // advance the head of the queue
}
return c;
}
void __not_in_flash_func(putConsole)(int c, int flush) {
if(OptionConsole & 2)DisplayPutC(c);
if(OptionConsole & 1)SerialConsolePutC(c, flush);
}
// put a character out to the serial console
char __not_in_flash_func(SerialConsolePutC)(char c, int flush) {
if(c == '\b') {
if (MMCharPos!=1){
MMCharPos -= 1;
}
}
#ifdef PICOMITEWEB
if(Option.Telnet!=-1){
#endif
#ifndef USBKEYBOARD
if(Option.SerialConsole==0 || Option.SerialConsole>4){
if(tud_cdc_connected()){
putc(c,stdout);
if(flush){
fflush(stdout);
}
}
}
#endif
if(Option.SerialConsole){
int empty=uart_is_writable((Option.SerialConsole & 3)==1 ? uart0 : uart1);
while(ConsoleTxBufTail == ((ConsoleTxBufHead + 1) % CONSOLE_TX_BUF_SIZE)); //wait if buffer full
ConsoleTxBuf[ConsoleTxBufHead] = c; // add the char
ConsoleTxBufHead = (ConsoleTxBufHead + 1) % CONSOLE_TX_BUF_SIZE; // advance the head of the queue
if(empty){
while(irqs){}
uart_set_irq_enables((Option.SerialConsole & 3)==1 ? uart0 : uart1, true, true);
irq_set_pending((Option.SerialConsole & 3)==1 ? UART0_IRQ : UART1_IRQ);
}
}
#ifdef PICOMITEWEB
}
TelnetPutC(c,flush);
ProcessWeb(1);
#endif
return c;
}
char MMputchar(char c, int flush) {
putConsole(c, flush);
if(isprint(c)) MMCharPos++;
if(c == '\r') {
MMCharPos = 1;
}
return c;
}
// returns the number of character waiting in the console input queue
int kbhitConsole(void) {
int i;
i = ConsoleRxBufHead - ConsoleRxBufTail;
if(i < 0) i += CONSOLE_RX_BUF_SIZE;
return i;
}
// check if there is a keystroke waiting in the buffer and, if so, return with the char
// returns -1 if no char waiting
// the main work is to check for vt100 escape code sequences and map to Maximite codes
#if (defined(PICOMITEVGA) || defined(PICOMITEWEB)) && !defined(rp2350)
int MMInkey(void) {
#else
int __not_in_flash_func(MMInkey)(void) {
#endif
unsigned int c = -1; // default no character
unsigned int tc = -1; // default no character
unsigned int ttc = -1; // default no character
static unsigned int c1 = -1;
static unsigned int c2 = -1;
static unsigned int c3 = -1;
static unsigned int c4 = -1;
// static int crseen = 0;
if(c1 != -1) { // check if there are discarded chars from a previous sequence
c = c1; c1 = c2; c2 = c3; c3 = c4; c4 = -1; // shuffle the queue down
return c; // and return the head of the queue
}
c = getConsole(); // do discarded chars so get the char
#ifndef USBKEYBOARD
if(c==-1)CheckKeyboard();
#endif
if(!(c==0x1b))return c;
InkeyTimer = 0; // start the timer
while((c = getConsole()) == -1 && InkeyTimer < 30); // get the second char with a delay of 30mS to allow the next char to arrive
if(c == 'O'){ //support for many linux terminal emulators
while((c = getConsole()) == -1 && InkeyTimer < 50); // delay some more to allow the final chars to arrive, even at 1200 baud
if(c == 'P') return F1;
if(c == 'Q') return F2;
if(c == 'R') return F3;
if(c == 'S') return F4;
if(c == 'T') return F5;
if(c == '2'){
while((tc = getConsole()) == -1 && InkeyTimer < 70); // delay some more to allow the final chars to arrive, even at 1200 baud
if(tc == 'R') return F3 + 0x20;
c1 = 'O'; c2 = c; c3 = tc; return 0x1b; // not a valid 4 char code
}
c1 = 'O'; c2 = c; return 0x1b; // not a valid 4 char code
}
if(c != '[') { c1 = c; return 0x1b; } // must be a square bracket
while((c = getConsole()) == -1 && InkeyTimer < 50); // get the third char with delay
if(c == 'A') return UP; // the arrow keys are three chars
if(c == 'B') return DOWN;
if(c == 'C') return RIGHT;
if(c == 'D') return LEFT;
if(c < '1' && c > '6') { c1 = '['; c2 = c; return 0x1b; } // the 3rd char must be in this range
while((tc = getConsole()) == -1 && InkeyTimer < 70); // delay some more to allow the final chars to arrive, even at 1200 baud
if(tc == '~') { // all 4 char codes must be terminated with ~
if(c == '1') return HOME;
if(c == '2') return INSERT;
if(c == '3') return DEL;
if(c == '4') return END;
if(c == '5') return PUP;
if(c == '6') return PDOWN;
c1 = '['; c2 = c; c3 = tc; return 0x1b; // not a valid 4 char code
}
while((ttc = getConsole()) == -1 && InkeyTimer < 90); // get the 5th char with delay
if(ttc == '~') { // must be a ~
if(c == '1') {
if(tc >='1' && tc <= '5') return F1 + (tc - '1'); // F1 to F5
if(tc >='7' && tc <= '9') return F6 + (tc - '7'); // F6 to F8
}
if(c == '2') {
if(tc =='0' || tc == '1') return F9 + (tc - '0'); // F9 and F10
if(tc =='3' || tc == '4') return F11 + (tc - '3'); // F11 and F12
if(tc =='5' || tc=='6') return F3 + 0x20 + tc-'5'; // SHIFT-F3 and F4
if(tc =='8' || tc=='9') return F5 + 0x20 + tc-'8'; // SHIFT-F5 and F6
}
if(c == '3') {
if(tc >='1' && tc <= '4') return F7 + 0x20 + (tc - '1'); // SHIFT-F7 to F10
}
//NB: SHIFT F1, F2, F11, and F12 don't appear to generate anything
}
// nothing worked so bomb out
c1 = '['; c2 = c; c3 = tc; c4 = ttc;
return 0x1b;
}
// get a line from the keyboard or a serial file handle
// filenbr == 0 means the console input
void MMgetline(int filenbr, char *p) {
int c, nbrchars = 0;
char *tp;
while(1) {
CheckAbort();
if(FileTable[filenbr].com > MAXCOMPORTS && FileEOF(filenbr)) break;
c = MMfgetc(filenbr);
if(c <= 0) continue; // keep looping if there are no chars
// if this is the console, check for a programmed function key and insert the text
if(filenbr == 0) {
tp = NULL;
if(c == F2) tp = "RUN";
if(c == F3) tp = "LIST";
if(c == F4) tp = "EDIT";
if(c == F10) tp = "AUTOSAVE";
if(c == F11) tp = "XMODEM RECEIVE";
if(c == F12) tp = "XMODEM SEND";
if(c == F1) tp = (char *)Option.F1key;
if(c == F5) tp = (char *)Option.F5key;
if(c == F6) tp = (char *)Option.F6key;
if(c == F7) tp = (char *)Option.F7key;
if(c == F8) tp = (char *)Option.F8key;
if(c == F9) tp = (char *)Option.F9key;
if(tp) {
strcpy(p, tp);
if(EchoOption) { MMPrintString(tp); MMPrintString("\r\n"); }
return;
}
}
if(c == '\t') { // expand tabs to spaces
do {
if(++nbrchars > MAXSTRLEN) error("Line is too long");
*p++ = ' ';
if(filenbr == 0 && EchoOption) MMputchar(' ',1);
} while(nbrchars % 4);
continue;
}
if(c == '\b') { // handle the backspace
if(nbrchars) {
if(filenbr == 0 && EchoOption) MMPrintString("\b \b");
nbrchars--;
p--;
}
continue;
}
if(c == '\n') { // what to do with a newline
break; // a newline terminates a line (for a file)
}
if(c == '\r') {
if(filenbr == 0 && EchoOption) {
MMPrintString("\r\n");
break; // on the console this means the end of the line - stop collecting
} else
continue ; // for files loop around looking for the following newline
}
if(isprint(c)) {
if(filenbr == 0 && EchoOption) MMputchar(c,1); // The console requires that chars be echoed
}
if(++nbrchars > MAXSTRLEN) error("Line is too long"); // stop collecting if maximum length
*p++ = c; // save our char
}
*p = 0;
}
// insert a string into the start of the lastcmd buffer.
// the buffer is a sequence of strings separated by a zero byte.
// using the up arrow usere can call up the last few commands executed.
void MIPS16 InsertLastcmd(unsigned char *s) {
int i, slen;
if(strcmp((const char *)lastcmd, (const char *)s) == 0) return; // don't duplicate
slen = strlen((const char *)s);
if(slen < 1 || slen > sizeof(lastcmd) - 1) return;
slen++;
for(i = sizeof(lastcmd) - 1; i >= slen ; i--)
lastcmd[i] = lastcmd[i - slen]; // shift the contents of the buffer up
strcpy((char *)lastcmd, (char *)s); // and insert the new string in the beginning
for(i = sizeof(lastcmd) - 1; lastcmd[i]; i--) lastcmd[i] = 0; // zero the end of the buffer
}
void MIPS16 EditInputLine(void) {
char *p = NULL;
char buf[MAXKEYLEN + 3];
char goend[10];
int lastcmd_idx, lastcmd_edit;
int insert, /*startline,*/ maxchars;
int CharIndex, BufEdited;
int c, i, j;
int l4,l3,l2;
maxchars=255;
if(Option.DISPLAY_CONSOLE && Option.Width<=SCREENWIDTH){ //We will always assume the Vt100 is 80 colums if LCD is the console <=80.
l2=SCREENWIDTH+1-MMPromptPos;
l3=2*SCREENWIDTH+2-MMPromptPos;
l4=3*SCREENWIDTH+3-MMPromptPos;
}else{ // otherwise assume the VT100 matches Option.Width
l2=Option.Width +1-MMPromptPos;
l3=2*Option.Width+2-MMPromptPos;
l4=3*Option.Width+3-MMPromptPos;
}
// Build "\e[80C" equivalent string for the line length
//strcpy(goend,"\e[");IntToStr(linelen,l2+MMPromptPos, 10);strcat(goend,linelen); strcat(goend, "C");
strcpy(goend,"\e[");IntToStr(&goend[strlen(goend)],l2+MMPromptPos, 10);strcat(goend, "C");
MMPrintString((char *)inpbuf); // display the contents of the input buffer (if any)
CharIndex = strlen((const char *)inpbuf); // get the current cursor position in the line
insert = false;
// Cursor = C_STANDARD;
lastcmd_edit = lastcmd_idx = 0;
BufEdited = false; //(CharIndex != 0);
while(1) {
c = MMgetchar();
if(c == TAB) {
strcpy(buf, " ");
switch (Option.Tab) {
case 2:
buf[2 - (CharIndex % 2)] = 0; break;
case 3:
buf[3 - (CharIndex % 3)] = 0; break;
case 4:
buf[4 - (CharIndex % 4)] = 0; break;
case 8:
buf[8 - (CharIndex % 8)] = 0; break;
}
} else {
buf[0] = c;
buf[1] = 0;
}
do {
switch(buf[0]) {
case '\r':
case '\n': //if(autoOn && atoi(inpbuf) > 0) autoNext = atoi(inpbuf) + autoIncr;
//if(autoOn && !BufEdited) *inpbuf = 0;
goto saveline;
break;
case '\b':
if(CharIndex > 0) {
BufEdited = true;
i = CharIndex - 1;
j= CharIndex;
for(p = (char *)inpbuf + i; *p; p++) *p = *(p + 1); // remove the char from inpbuf
// Lets put the cursor at the beginning of where the command is displayed.
// backspace to the beginning of line
#define USEBACKSPACE
#ifdef USEBACKSPACE
while(j) {
if (j==l4 || j==l3 ||j==l2 ){DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{ MMputchar('\b',0);}
j--;
}
fflush(stdout);
MX470Display(CLEAR_TO_EOS);SSPrintString("\033[0J"); //Clear to End Of Screen
#else
CurrentX=0;CurrentY=CurrentY-((CharIndex+1)/Option.Width * gui_font_height);
if (CharIndex>l4-1)SSPrintString("\e[3A");
else if (CharIndex>l3-1)SSPrintString("\e[2A");
else if(CharIndex>l2-1)SSPrintString("\e[1A");
SSPrintString("\r");
//CurrentX=0;SerUSBPutS("\r");
MX470Display(CLEAR_TO_EOS);SSPrintString("\033[0J");
MMPrintString("> ");
fflush(stdout);
#endif
j=0;
while(j < strlen((const char *)inpbuf)) {
MMputchar(inpbuf[j],0);
if((j==l4-1 || j==l3-1 || j==l2-1 ) && j == strlen((const char *)inpbuf)-1 ){SSPrintString(" ");SSPrintString("\b");}
if((j==l4-1 || j==l3-1 || j==l2-1 ) && j < strlen((const char *)inpbuf)-1 ){SerialConsolePutC(inpbuf[j+1],0);SSPrintString("\b");}
j++;
}
fflush(stdout);
// return the cursor to the right position
for(j = strlen((const char *)inpbuf); j > i; j--){
if (j==l4 || j==l3 || j==l2) {DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{MMputchar('\b',0);}
}
CharIndex--;
fflush(stdout);
if(strlen((const char *)inpbuf)==0)BufEdited = false;
}
break;
case CTRLKEY('S'):
case LEFT:
BufEdited = true;
insert=false; //left at first char will turn OVR on
if(CharIndex > 0) {
// if(CharIndex == strlen((const char *)inpbuf)) {
//insert = true;
// }
if (CharIndex==l4 || CharIndex==l3 || CharIndex==l2 ){DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{MMputchar('\b',1);}
insert=true; //Any left turns on INS
CharIndex--;
}
break;
case CTRLKEY('D'):
case RIGHT:
if(CharIndex < strlen((const char *)inpbuf)) {
BufEdited = true;
MMputchar(inpbuf[CharIndex],1);
if((CharIndex==l4-1 || CharIndex==l3-1|| CharIndex==l2-1 ) && CharIndex == strlen((const char *)inpbuf)-1 ){SSPrintString(" ");SSPrintString("\b");}
if((CharIndex==l4-1 || CharIndex==l3-1|| CharIndex==l2-1 ) && CharIndex < strlen((const char *)inpbuf)-1 ){SerialConsolePutC(inpbuf[CharIndex+1],0);SSPrintString("\b");}
CharIndex++;
}
// insert=false; //right always switches to OVER
break;
case CTRLKEY(']'):
case DEL:
if(CharIndex < strlen((const char *)inpbuf)) {
BufEdited = true;
i = CharIndex;
for(p = (char *)inpbuf + i; *p; p++) *p = *(p + 1); // remove the char from inpbuf
j = strlen((const char *)inpbuf);
// Lets put the cursor at the beginning of where the command is displayed.
// backspace to the beginning of line
j=CharIndex;
while(j) {
if (j==l4 || j==l3 ||j==l2 ){DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{ MMputchar('\b',0);}
j--;
}
fflush(stdout);
MX470Display(CLEAR_TO_EOS);SSPrintString("\033[0J"); //Clear to End Of Screen
j=0;
while(j < strlen((const char *)inpbuf)) {
MMputchar(inpbuf[j],0);
if((j==l4-1 || j==l3-1 || j==l2-1 ) && j == strlen((const char *)inpbuf)-1 ){SSPrintString(" ");SSPrintString("\b");}
if((j==l4-1 || j==l3-1 || j==l2-1 ) && j < strlen((const char *)inpbuf)-1 ){SerialConsolePutC(inpbuf[j+1],0);SSPrintString("\b");}
j++;
}
fflush(stdout);
// return the cursor to the right position
for(j = strlen((const char *)inpbuf); j > i; j--){
if (j==l4 || j==l3 || j==l2) {DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{ MMputchar('\b',0);}
}
fflush(stdout);
}
break;
case CTRLKEY('N'):
case INSERT:insert = !insert;
// Cursor = C_STANDARD + insert;
break;
case CTRLKEY('U'):
case HOME:
BufEdited = true;
if(CharIndex > 0) {
if(CharIndex == strlen((const char *)inpbuf)) {
insert = true;
// Cursor = C_INSERT;
}
// backspace to the beginning of line
while(CharIndex) {
if (CharIndex==l4 || CharIndex==l3 || CharIndex==l2 ){DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{MMputchar('\b',0);}
CharIndex--;
}
fflush(stdout);
}else{ //HOME @ home turns off edit mode
BufEdited = false;
insert=false; //home at first char will turn OVR on
}
break;
case CTRLKEY('K'):
case END:
BufEdited = true;
while(CharIndex < strlen((const char *)inpbuf)){
MMputchar(inpbuf[CharIndex++],0);
}
fflush(stdout);
break;
/* if(c == F2) tp = "RUN";
if(c == F3) tp = "LIST";
if(c == F4) tp = "EDIT";
if(c == F10) tp = "AUTOSAVE";
if(c == F11) tp = "XMODEM RECEIVE";
if(c == F12) tp = "XMODEM SEND";
if(c == F5) tp = Option.F5key;
if(c == F6) tp = Option.F6key;
if(c == F7) tp = Option.F7key;
if(c == F8) tp = Option.F8key;
if(c == F9) tp = Option.F9key;
*/
case 0x91:
if(*Option.F1key)strcpy(&buf[1],(char *)Option.F1key);
break;
case 0x92:
strcpy(&buf[1],"RUN\r\n");
break;
case 0x93:
strcpy(&buf[1],"LIST\r\n");
break;
case 0x94:
strcpy(&buf[1],"EDIT\r\n");
break;
case 0x95:
if(*Option.F5key){
strcpy(&buf[1],(char *)Option.F5key);
}else{
/*** F5 will clear the VT100 ***/
SSPrintString("\e[2J\e[H");
fflush(stdout);
if(Option.DISPLAY_CONSOLE){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;}
if(FindSubFun((unsigned char *)"MM.PROMPT", 0) >= 0) {
ExecuteProgram((unsigned char *)"MM.PROMPT\0");
} else{
MMPrintString("> "); // print the prompt
}
//MMPrintString("> ");
fflush(stdout);
}
break;
case 0x96:
if(*Option.F6key)strcpy(&buf[1],(char *)Option.F6key);
break;
case 0x97:
if(*Option.F7key)strcpy(&buf[1],(char *)Option.F7key);
break;
case 0x98:
if(*Option.F8key)strcpy(&buf[1],(char *)Option.F8key);
break;
case 0x99:
if(*Option.F9key)strcpy(&buf[1],(char *)Option.F9key);
break;
case 0x9a:
strcpy(&buf[1],"AUTOSAVE\r\n");
break;
case 0x9b:
strcpy(&buf[1],"XMODEM RECEIVE\r\n");
break;
case 0x9c:
strcpy(&buf[1],"XMODEM SEND\r\n");
break;
case CTRLKEY('E'):
case UP: if(!(BufEdited /*|| autoOn || CurrentLineNbr */)) {
if(lastcmd_edit) {
i = lastcmd_idx + strlen((const char *)&lastcmd[lastcmd_idx]) + 1; // find the next command
if(lastcmd[i] != 0 && i < sizeof(lastcmd) - 1) lastcmd_idx = i; // and point to it for the next time around
} else
lastcmd_edit = true;
strcpy((char *)inpbuf, (const char *)&lastcmd[lastcmd_idx]); // get the command into the buffer for editing
goto insert_lastcmd;
}
break;
case CTRLKEY('X'):
case DOWN:
if(!(BufEdited /*|| autoOn || CurrentLineNbr */)) {
if(lastcmd_idx == 0)
*inpbuf = lastcmd_edit = 0;
else {
for(i = lastcmd_idx - 2; i > 0 && lastcmd[i - 1] != 0; i--);// find the start of the previous command
lastcmd_idx = i; // and point to it for the next time around
strcpy((char *)inpbuf, (const char *)&lastcmd[i]); // get the command into the buffer for editing
}
goto insert_lastcmd; // gotos are bad, I know, I know
}
break;
insert_lastcmd:
// If NoScroll and its near the bottom then clear screen and write command at top
//if(Option.NoScroll && Option.DISPLAY_CONSOLE && (CurrentY + 2*gui_font_height >= VRes)){
if(Option.NoScroll && Option.DISPLAY_CONSOLE && (CurrentY + (2 + strlen((const char *)inpbuf)/Option.Width)*gui_font_height >= VRes)){
ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;
if(FindSubFun((unsigned char *)"MM.PROMPT", 0) >= 0) {
SSPrintString("\r");
ExecuteProgram((unsigned char *)"MM.PROMPT\0");
} else{
SSPrintString("\r");
MMPrintString("> "); // print the prompt
}
}else{
// Lets put the cursor at the beginning of where the command is displayed.
// backspace to the beginning of line
j=CharIndex; //????????????????????????????????
while(j) {
if (j==l4 || j==l3 ||j==l2 ){DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{ MMputchar('\b',0);}
j--;
}
fflush(stdout);
MX470Display(CLEAR_TO_EOS);SSPrintString("\033[0J"); //Clear to End Of Screen
}
CharIndex = strlen((const char *)inpbuf);
MMPrintString((char *)inpbuf); // display the line
if(CharIndex==l4 || CharIndex==l3 || CharIndex==l2){SSPrintString(" ");SSPrintString("\b");}
fflush(stdout);
CharIndex = strlen((const char *)inpbuf); // get the current cursor position in the line
break;
default: if(buf[0] >= ' ' && buf[0] < 0x7f) {
// BufEdited = true;
i = CharIndex;
j = strlen((const char *)inpbuf);
if(insert) {
if(strlen((const char *)inpbuf) >= maxchars - 1) break; // sorry, line full
for(p = (char *)inpbuf + strlen((const char *)inpbuf); j >= CharIndex; p--, j--) *(p + 1) = *p;
inpbuf[CharIndex] = buf[0]; // insert the char
MMPrintString((char *)&inpbuf[CharIndex]); // display new part of the line
CharIndex++;
// return the cursor to the right position
for(j = strlen((const char *)inpbuf); j > CharIndex; j--){
if (j==l4 || j==l3 || j==l2){DisplayPutC('\b');SSPrintString("\e[1A");SSPrintString(goend);}else{ MMputchar('\b',0);}
}
fflush(stdout);
} else {
if(strlen((const char *)inpbuf) >= maxchars-1 ) break; // sorry, line full just ignore
inpbuf[strlen((const char *)inpbuf) + 1] = 0; // incase we are adding to the end of the string
inpbuf[CharIndex++] = buf[0]; // overwrite the char
MMputchar(buf[0],0);
if(j==l4-1 || j==l3-1 || j==l2-1){SSPrintString(" ");SSPrintString("\b");}
fflush(stdout);
}
#ifndef PICOMITEVGA
i = CharIndex;
j = strlen((const char *)inpbuf);
// If its going to scroll then clear screen
if(Option.NoScroll && Option.DISPLAY_CONSOLE){
if(CurrentY + 2*gui_font_height >= VRes) {
ClearScreen(gui_bcolour);/*CurrentX=0*/;CurrentY=0;
CurrentX = (MMPromptPos-2)*gui_font_width ;
//if(FindSubFun((unsigned char *)"MM.PROMPT", 0) >= 0) {
// ExecuteProgram((unsigned char *)"MM.PROMPT\0");
//} else{
//SSPrintString("\r");
//MMPrintString("> "); // print the prompt
DisplayPutC('>');
DisplayPutC(' ');
//}
DisplayPutS((char *)inpbuf); // display the line
}
}
#endif
}
break;
}
for(i = 0; i < MAXKEYLEN + 1; i++) buf[i] = buf[i + 1]; // shuffle down the buffer to get the next char
} while(*buf);
if(CharIndex == strlen((const char *)inpbuf)) {
insert = false;
// Cursor = C_STANDARD;
}
}
saveline:
// Cursor = C_STANDARD;
if(strlen((const char *)inpbuf) < maxchars)InsertLastcmd(inpbuf);
MMPrintString("\r\n");
}
#ifdef OLDSTUFF
void MIPS16 EditInputLine(void) {
char *p = NULL;
char buf[MAXKEYLEN + 3];
int lastcmd_idx, lastcmd_edit;
int insert, startline, maxchars;
int CharIndex, BufEdited;
int c, i, j;
maxchars = Option.Width;
if(strlen((const char *)inpbuf) >= maxchars) {
MMPrintString((char *)inpbuf);
error("Line is too long to edit");
}
startline = MMCharPos - 1; // save the current cursor position
MMPrintString((char *)inpbuf); // display the contents of the input buffer (if any)
CharIndex = strlen((const char *)inpbuf); // get the current cursor position in the line
insert = false;
// Cursor = C_STANDARD;
lastcmd_edit = lastcmd_idx = 0;
BufEdited = false; //(CharIndex != 0);
while(1) {
c = MMgetchar();
if(c == TAB) {
strcpy(buf, " ");
switch (Option.Tab) {
case 2:
buf[2 - (CharIndex % 2)] = 0; break;
case 3:
buf[3 - (CharIndex % 3)] = 0; break;
case 4:
buf[4 - (CharIndex % 4)] = 0; break;
case 8:
buf[8 - (CharIndex % 8)] = 0; break;
}
} else {
buf[0] = c;
buf[1] = 0;
}
do {
switch(buf[0]) {
case '\r':
case '\n': //if(autoOn && atoi(inpbuf) > 0) autoNext = atoi(inpbuf) + autoIncr;
//if(autoOn && !BufEdited) *inpbuf = 0;
goto saveline;
break;
case '\b': if(CharIndex > 0) {
BufEdited = true;
i = CharIndex - 1;
for(p = (char *)inpbuf + i; *p; p++) *p = *(p + 1); // remove the char from inpbuf
while(CharIndex) { MMputchar('\b',0); CharIndex--; } // go to the beginning of the line
MMPrintString((char *)inpbuf); MMputchar(' ',0); MMputchar('\b',0); // display the line and erase the last char
for(CharIndex = strlen((const char *)inpbuf); CharIndex > i; CharIndex--)
MMputchar('\b',0);
fflush(stdout); // return the cursor to the righ position
}
break;
case CTRLKEY('S'):
case LEFT: if(CharIndex > 0) {
if(CharIndex == strlen((const char *)inpbuf)) {
insert = true;
// Cursor = C_INSERT;
}
MMputchar('\b',1);
CharIndex--;
}
break;
case CTRLKEY('D'):
case RIGHT: if(CharIndex < strlen((const char *)inpbuf)) {
MMputchar(inpbuf[CharIndex],1);
CharIndex++;
}
break;
case CTRLKEY(']'):
case DEL: if(CharIndex < strlen((const char *)inpbuf)) {
BufEdited = true;
i = CharIndex;
for(p = (char *)inpbuf + i; *p; p++) *p = *(p + 1); // remove the char from inpbuf
while(CharIndex) { MMputchar('\b',0); CharIndex--; } // go to the beginning of the line
MMPrintString((char *)inpbuf); MMputchar(' ',0); MMputchar('\b',0); // display the line and erase the last char
for(CharIndex = strlen((const char *)inpbuf); CharIndex > i; CharIndex--)
MMputchar('\b',0);
fflush(stdout); // return the cursor to the right position
}
break;
case CTRLKEY('N'):
case INSERT:insert = !insert;
// Cursor = C_STANDARD + insert;
break;
case CTRLKEY('U'):
case HOME: if(CharIndex > 0) {
if(CharIndex == strlen((const char *)inpbuf)) {
insert = true;
// Cursor = C_INSERT;
}
while(CharIndex) { MMputchar('\b',0); CharIndex--; }
fflush(stdout);
}
break;
case CTRLKEY('K'):
case END: while(CharIndex < strlen((const char *)inpbuf)){
MMputchar(inpbuf[CharIndex++],0);
}
fflush(stdout);
break;
/* if(c == F2) tp = "RUN";
if(c == F3) tp = "LIST";
if(c == F4) tp = "EDIT";
if(c == F10) tp = "AUTOSAVE";
if(c == F11) tp = "XMODEM RECEIVE";
if(c == F12) tp = "XMODEM SEND";
if(c == F5) tp = Option.F5key;
if(c == F6) tp = Option.F6key;
if(c == F7) tp = Option.F7key;
if(c == F8) tp = Option.F8key;
if(c == F9) tp = Option.F9key;*/
case 0x91:
if(*Option.F1key)strcpy(&buf[1],(char *)Option.F1key);
break;
case 0x92:
strcpy(&buf[1],"RUN\r\n");
break;
case 0x93:
strcpy(&buf[1],"LIST\r\n");
break;
case 0x94:
strcpy(&buf[1],"EDIT\r\n");
break;
case 0x95:
if(*Option.F5key){
strcpy(&buf[1],(char *)Option.F5key);
}else{
/*** F5 will clear the VT100 ***/
SSPrintString("\e[2J\e[H");
fflush(stdout);
if(Option.DISPLAY_CONSOLE){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;}
MMPrintString("> ");
fflush(stdout);
}
break;
case 0x96:
if(*Option.F6key)strcpy(&buf[1],(char *)Option.F6key);
break;
case 0x97:
if(*Option.F7key)strcpy(&buf[1],(char *)Option.F7key);
break;
case 0x98:
if(*Option.F8key)strcpy(&buf[1],(char *)Option.F8key);
break;
case 0x99:
if(*Option.F9key)strcpy(&buf[1],(char *)Option.F9key);
break;
case 0x9a:
strcpy(&buf[1],"AUTOSAVE\r\n");
break;
case 0x9b:
strcpy(&buf[1],"XMODEM RECEIVE\r\n");
break;
case 0x9c:
strcpy(&buf[1],"XMODEM SEND\r\n");
break;
case CTRLKEY('E'):
case UP: if(!(BufEdited /*|| autoOn || CurrentLineNbr */)) {
while(CharIndex) { MMputchar('\b',0); CharIndex--; }
fflush(stdout); // go to the beginning of line
if(lastcmd_edit) {
i = lastcmd_idx + strlen((const char *)&lastcmd[lastcmd_idx]) + 1; // find the next command
if(lastcmd[i] != 0 && i < sizeof(lastcmd) - 1) lastcmd_idx = i; // and point to it for the next time around
} else
lastcmd_edit = true;
strcpy((char *)inpbuf, (const char *)&lastcmd[lastcmd_idx]); // get the command into the buffer for editing
goto insert_lastcmd;
}
break;
case CTRLKEY('X'):
case DOWN: if(!(BufEdited /*|| autoOn || CurrentLineNbr */)) {
while(CharIndex) { MMputchar('\b',0); CharIndex--; }
fflush(stdout); // go to the beginning of line
if(lastcmd_idx == 0)
*inpbuf = lastcmd_edit = 0;
else {
for(i = lastcmd_idx - 2; i > 0 && lastcmd[i - 1] != 0; i--);// find the start of the previous command
lastcmd_idx = i; // and point to it for the next time around
strcpy((char *)inpbuf, (const char *)&lastcmd[i]); // get the command into the buffer for editing
}
goto insert_lastcmd; // gotos are bad, I know, I know
}
break;
insert_lastcmd: // goto here if we are just editing a command
if(strlen((const char *)inpbuf) + startline >= maxchars) { // if the line is too long
while(CharIndex) { MMputchar('\b',0); CharIndex--; } // go to the start of the line
MMPrintString((char *)inpbuf); // display the offending line
error("Line is too long to edit");
}
MMPrintString((char *)inpbuf); // display the line
CharIndex = strlen((const char *)inpbuf); // get the current cursor position in the line
for(i = 1; i <= maxchars - strlen((const char *)inpbuf) - startline; i++) {
MMputchar(' ',0); // erase the rest of the line
CharIndex++;
}
while(CharIndex > strlen((const char *)inpbuf)) { MMputchar('\b',0); CharIndex--; } // return the cursor to the right position
SSPrintString("\033[0K");
break;
default: if(buf[0] >= ' ' && buf[0] < 0x7f) {
BufEdited = true; // this means that something was typed
i = CharIndex;
j = strlen((const char *)inpbuf);
if(insert) {
if(strlen((const char *)inpbuf) >= maxchars - 1) break; // sorry, line full
for(p = (char *)inpbuf + strlen((const char *)inpbuf); j >= CharIndex; p--, j--) *(p + 1) = *p;
inpbuf[CharIndex] = buf[0]; // insert the char
MMPrintString((char *)&inpbuf[CharIndex]); // display new part of the line
CharIndex++;
for(j = strlen((const char *)inpbuf); j > CharIndex; j--) MMputchar('\b',0);
fflush(stdout); // return the cursor to the right position
} else {
inpbuf[strlen((const char *)inpbuf) + 1] = 0; // incase we are adding to the end of the string
inpbuf[CharIndex++] = buf[0]; // overwrite the char
MMputchar(buf[0],1); // display it
if(CharIndex + startline >= maxchars) { // has the input gone beyond the end of the line?
MMgetline(0, (char *)inpbuf); // use the old fashioned way of getting the line
//if(autoOn && atoi(inpbuf) > 0) autoNext = atoi(inpbuf) + autoIncr;
goto saveline;
}
}
}
break;
}
for(i = 0; i < MAXKEYLEN + 1; i++) buf[i] = buf[i + 1]; // shuffle down the buffer to get the next char
} while(*buf);
if(CharIndex == strlen((const char *)inpbuf)) {
insert = false;
// Cursor = C_STANDARD;
}
}
saveline:
// Cursor = C_STANDARD;
MMPrintString("\r\n");
}
#endif
// get a keystroke. Will wait forever for input
// if the unsigned char is a cr then replace it with a newline (lf)
int MMgetchar(void) {
int c;
do {
ShowCursor(1);
c=MMInkey();
} while(c == -1);
ShowCursor(0);
return c;
}
// print a string to the console interfaces
void MMPrintString(char* s) {
while(*s) {
if(s[1])MMputchar(*s,0);
else MMputchar(*s,1);
s++;
}
fflush(stdout);
}
void SSPrintString(char* s) {
while(*s) {
SerialConsolePutC(*s,0);
s++;
}
fflush(stdout);
}
/*void myprintf(char *s){
fputs(s,stdout);
fflush(stdout);
}*/
void __not_in_flash_func(mT4IntEnable)(int status){
if(status){
processtick=true;
} else{
processtick=false;
}
}
volatile int onoff=0;
bool MIPS16 __not_in_flash_func(timer_callback)(repeating_timer_t *rt)
{
mSecTimer++; // used by the TIMER function
if(processtick){
static int IrTimeout, IrTick, NextIrTick;
int ElapsedMicroSec, IrDevTmp, IrCmdTmp;
#ifdef rp2350
if(ExtCurrentConfig[FAST_TIMER_PIN] == EXT_FAST_TIMER && --INT5Timer <= 0) {
static uint64_t now,last=0;
uint32_t hi = INT5Count;
uint32_t lo;
do {
// Read the lower 32 bits
lo = pwm_get_counter(0);
// Now read the upper 32 bits again and
// check that it hasn't incremented. If it has loop around
// and read the lower 32 bits again to get an accurate value
uint32_t next_hi = INT5Count;
if (hi == next_hi) break;
hi = next_hi;
} while (true);
now=((uint64_t) hi *50000) + lo;
INT5Value=now-last;
last=now;
INT5Timer = INT5InitTimer;
}
#endif
AHRSTimer++;
InkeyTimer++; // used to delay on an escape character
PauseTimer++; // used by the PAUSE command
IntPauseTimer++; // used by the PAUSE command inside an interrupt
ds18b20Timer++;
GPSTimer++;
I2CTimer++;
#ifdef USBKEYBOARD
keytimer++;
for(int i=0;i<4;i++){
if(HID[i].Device_type){
HID[i].report_timer++;
}
}
#else
nunstruct[2].type++;
MouseTimer++;
#endif
if(clocktimer)clocktimer--;
if(Timer5)Timer5--;
if(Timer4)Timer4--;
if(Timer3)Timer3--;
if(Timer2)Timer2--;
if(Timer1)Timer1--;
if(KeyCheck)KeyCheck--;
ClassicTimer++;
NunchuckTimer++;
if(diskchecktimer && (Option.SD_CS || Option.CombinedCS))diskchecktimer--;
if(++CursorTimer > CURSOR_OFF + CURSOR_ON) CursorTimer = 0; // used to control cursor blink rate
if(CFuncmSec) CallCFuncmSec(); // the 1mS tick for CFunctions (see CFunction.c)
if(InterruptUsed) {
int i;
for(i = 0; i < NBRSETTICKS; i++) if(TickActive[i])TickTimer[i]++; // used in the interrupt tick
}
if(WDTimer) {
if(--WDTimer == 0) {
_excep_code = WATCHDOG_TIMEOUT;
watchdog_enable(1, 1);
while(1);
}
}
if (ScrewUpTimer) {
if (--ScrewUpTimer == 0) {
_excep_code = SCREWUP_TIMEOUT;
watchdog_enable(1, 1);
while(1);
}
}
if(PulseActive) {
int i;
for(PulseActive = i = 0; i < NBR_PULSE_SLOTS; i++) {
if(PulseCnt[i] > 0) { // if the pulse timer is running
PulseCnt[i]--; // and decrement our count
if(PulseCnt[i] == 0) // if this is the last count reset the pulse
PinSetBit(PulsePin[i], LATINV);
else
PulseActive = true; // there is at least one pulse still active
}
}
}
ElapsedMicroSec = readIRclock();
if(IrState > IR_WAIT_START && ElapsedMicroSec > 15000) IrReset();
IrCmdTmp = -1;
// check for any Sony IR receive activity
if(IrState == SONY_WAIT_BIT_START && ElapsedMicroSec > 2800 && (IrCount == 12 || IrCount == 15 || IrCount == 20)) {
IrDevTmp = ((IrBits >> 7) & 0b11111);
IrCmdTmp = (IrBits & 0b1111111) | ((IrBits >> 5) & ~0b1111111);
}
// check for any NEC IR receive activity
if(IrState == NEC_WAIT_BIT_END && IrCount == 32) {
// check if it is a NON extended address and adjust if it is
if((IrBits >> 24) == ~((IrBits >> 16) & 0xff)) IrBits = (IrBits & 0x0000ffff) | ((IrBits >> 8) & 0x00ff0000);
IrDevTmp = ((IrBits >> 16) & 0xffff);
IrCmdTmp = ((IrBits >> 8) & 0xff);
}
#ifdef GUICONTROLS
// check on the touch panel, is the pen down?
TouchTimer++;
if(CheckGuiFlag) CheckGuiTimeouts(); // are blinking LEDs in use? If so count down their timers
if(TOUCH_GETIRQTRIS){ // is touch enabled and the PEN IRQ pin an input?
if(TOUCH_DOWN) { // is the pen down
if(!TouchState) { // yes, it is. If we have not reported this before
TouchState = TouchDown = true; // set the flags
// TouchUp = false;
}
} else {
if(TouchState) { // the pen is not down. If we have not reported this before
TouchState/* = TouchDown*/ = false; // set the flags
TouchUp = true;
}
}
}
if(ClickTimer) {
ClickTimer--;
if(Option.TOUCH_Click) PinSetBit(Option.TOUCH_Click, ClickTimer ? LATSET : LATCLR);
}
#endif
// now process the IR message, this includes handling auto repeat while the key is held down
// IrTick counts how many mS since the key was first pressed
// NextIrTick is used to time the auto repeat
// IrTimeout is used to detect when the key is released
// IrGotMsg is a signal to the interrupt handler that an interrupt is required
if(IrCmdTmp != -1) {
if(IrTick > IrTimeout) {
// this is a new keypress
IrTick = 0;
NextIrTick = 650;
}
if(IrTick == 0 || IrTick > NextIrTick) {
if(IrVarType & 0b01)
*(MMFLOAT *)IrDev = IrDevTmp;
else
*(long long int *)IrDev = IrDevTmp;
if(IrVarType & 0b10)
*(MMFLOAT *)IrCmd = IrCmdTmp;
else
*(long long int *)IrCmd = IrCmdTmp;
IrGotMsg = true;
NextIrTick += 250;
}
IrTimeout = IrTick + 150;
IrReset();
}
IrTick++;
if(ExtCurrentConfig[Option.INT1pin] == EXT_PER_IN) INT1Count++;
if(ExtCurrentConfig[Option.INT2pin] == EXT_PER_IN) INT2Count++;
if(ExtCurrentConfig[Option.INT3pin] == EXT_PER_IN) INT3Count++;
if(ExtCurrentConfig[Option.INT4pin] == EXT_PER_IN) INT4Count++;
if(ExtCurrentConfig[Option.INT1pin] == EXT_FREQ_IN && --INT1Timer <= 0) { INT1Value = INT1Count; INT1Count = 0; INT1Timer = INT1InitTimer; }
if(ExtCurrentConfig[Option.INT2pin] == EXT_FREQ_IN && --INT2Timer <= 0) { INT2Value = INT2Count; INT2Count = 0; INT2Timer = INT2InitTimer; }
if(ExtCurrentConfig[Option.INT3pin] == EXT_FREQ_IN && --INT3Timer <= 0) { INT3Value = INT3Count; INT3Count = 0; INT3Timer = INT3InitTimer; }
if(ExtCurrentConfig[Option.INT4pin] == EXT_FREQ_IN && --INT4Timer <= 0) { INT4Value = INT4Count; INT4Count = 0; INT4Timer = INT4InitTimer; }
////////////////////////////////// this code runs once a second /////////////////////////////////
if(++SecondsTimer >= 1000) {
SecondsTimer -= 1000;
#ifndef PICOMITEWEB
if(ExtCurrentConfig[PinDef[HEARTBEATpin].pin]==EXT_HEARTBEAT)gpio_xor_mask64(1<<PinDef[HEARTBEATpin].GPno);
#endif
// keep track of the time and date
/* if(++second >= 60) {
second = 0 ;
if(++minute >= 60) {
minute = 0;
if(++hour >= 24) {
hour = 0;
if(++day > DaysInMonth[month] + ((month == 2 && (year % 4) == 0)?1:0)) {
day = 1;
if(++month > 12) {
month = 1;
year++;
}
}
}
}
}*/
}
}
return 1;
}
void __not_in_flash_func(uSec)(int us) {
#ifdef PICOMITEWEB
if(us<500){
busy_wait_us(us);
} else {
uint64_t end=time_us_64()+us;
while(time_us_64()<end){
if(time_us_64() % 500 ==0)ProcessWeb(1);
}
}
#else
busy_wait_us(us);
#endif
}
#ifdef PICOMITEWEB
void __not_in_flash_func(ProcessWeb)(int mode){
static uint64_t flushtimer=0;
static uint64_t lastusec=0;
static int testcount=0;
static int lastonoff=0;
static uint64_t lastheartmsec=0;
uint64_t timenow=time_us_64();
if(!WIFIconnected && startupcomplete)goto flashonly;
TCP_SERVER_T *state = (TCP_SERVER_T*)TCPstate;
if(!state)return;
int t=0;
for(int i=0;i<MaxPcb;i++){
if(state->client_pcb[i]==NULL){
t++;
} else if(state->client_pcb[i]==(struct tcp_pcb *)44){
if(timenow-state->pcbopentime[i] > 1000*(uint32_t)Option.ServerResponceTime + 20000000 && !state->keepalive[i]){
state->client_pcb[i]=NULL;
// printf("PCB %d should be closed by now\r\n", i);
}
} else {
if(timenow-state->pcbopentime[i] > 1000*(uint32_t)Option.ServerResponceTime && !state->keepalive[i]){
// printf("Warning PCB %d still open\r\n", i);
if(state->buffer_recv[i]){
tcp_server_close(state,i);
error("No response to request from connection no. %",i+1);
// printf("Warning: No response to request from connection no. %d\r\n",i+1);
}
tcp_server_close(state,i);
state->client_pcb[i]=(struct tcp_pcb *)44;
}
}
}
if(testcount == 0 || timenow>lastusec){
lastusec=timenow+1000;
testcount = 0 ;
if(startupcomplete)cyw43_arch_poll();
}
testcount++;
if(testcount==100)testcount=0;
if(!mode)return;
if(state->telnet_pcb_no!=99){
if(timenow > flushtimer){
TelnetPutC(0,-1);
flushtimer=timenow+5000;
}
}
flashonly:;
if(Option.NoHeartbeat){
if(lastonoff!=2){
if(startupcomplete){
if(cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN)) cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
lastonoff=2;
}
}
} else {
if(lastonoff==2)lastonoff=0;
if(timenow-lastheartmsec>(WIFIconnected ? 500000:1000000) && startupcomplete){
lastheartmsec=timenow;
if(lastonoff)cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
else cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
lastonoff^=1;
}
}
}
#endif
void __not_in_flash_func(CheckAbort)(void) {
#ifdef PICOMITEWEB
ProcessWeb(1);
#endif
routinechecks();
if(MMAbort) {
WDTimer = 0; // turn off the watchdog timer
calibrate=0;
ShowCursor(false);
#ifdef PICOMITE
if(mergerunning){
multicore_fifo_push_blocking(0xFF);
busy_wait_ms(mergetimer+200);
if(mergerunning){
_excep_code = RESET_COMMAND;
SoftReset();
}
}
#endif
do_end(false);
longjmp(mark, 1); // jump back to the input prompt
}
}
void PRet(void){
MMPrintString("\r\n");
}
void SRet(void){
SSPrintString("\r\n");
}
void PInt(int64_t n) {
char s[20];
IntToStr(s, (int64_t)n, 10);
MMPrintString(s);
}
void SInt(int64_t n) {
char s[20];
IntToStr(s, (int64_t)n, 10);
SSPrintString(s);
}
void SIntComma(int64_t n) {
SSPrintString(", "); SInt(n);
}
void PIntComma(int64_t n) {
MMPrintString(", "); PInt(n);
}
void PIntH(unsigned long long int n) {
char s[20];
IntToStr(s, (int64_t)n, 16);
MMPrintString(s);
}
void PIntB(unsigned long long int n) {
char s[65];
IntToStr(s, (int64_t)n, 2);
MMPrintString(s);
}
void PIntHC(unsigned long long int n) {
MMPrintString(", "); PIntH(n);
}
void PIntBC(unsigned long long int n) {
MMPrintString(", "); PIntB(n);
}
void PFlt(MMFLOAT flt){
char s[20];
FloatToStr(s, flt, 4,4, ' ');
MMPrintString(s);
}
void PFltComma(MMFLOAT n) {
MMPrintString(", "); PFlt(n);
}
void sigbus(void){
MMPrintString("Error: Invalid address - resetting\r\n");
uSec(250000);
disable_interrupts_pico();
// flash_range_erase(PROGSTART, MAX_PROG_SIZE);
LoadOptions();
if(Option.NoReset==0){
Option.Autorun=0;
SaveOptions();
}
enable_interrupts_pico();
memset(inpbuf,0,STRINGSIZE);
SoftReset();
}
#ifdef PICOMITEVGA
int vgaloop1,vgaloop2, vgaloop4, vgaloop8, vgaloop16, vgaloop32;
#ifndef HDMI
// ****************************************************************************
//
// QVGA
//
// ****************************************************************************
// VGA resolution:
// - 640x480 pixels
// - vertical frequency 60 Hz
// - horizontal frequency 31.4685 kHz
// - pixel clock 25.175 MHz
//
// QVGA resolution:
// - 320x240 pixels
// - vertical double image scanlines
// - vertical frequency 60 Hz
// - horizontal frequency 31.4685 kHz
// - pixel clock 12.5875 MHz
//
// VGA vertical timings:
// - 525 scanlines total
// - line 1,2: (2) vertical sync
// - line 3..35: (33) dark
// - line 36..515: (480) image lines 0..479
// - line 516..525: (10) dark
//
// VGA horizontal timings:
// - 31.77781 total scanline in [us] (800 pixels, QVGA 400 pixels)
// - 0.63556 H front porch (after image, before HSYNC) in [us] (16 pixels, QVGA 8 pixels)
// - 3.81334 H sync pulse in [us] (96 pixels, QVGA 48 pixels)
// - 1.90667 H back porch (after HSYNC, before image) in [us] (48 pixels, QVGA 24 pixels)
// - 25.42224 H full visible in [us] (640 pixels, QVGA 320 pixels)
// - 0.0397222625 us per pixel at VGA, 0.079444525 us per pixel at QVGA
//
// We want reach 25.175 pixel clock (at 640x480). Default system clock is 125 MHz, which is
// approx. 5x pixel clock. We need 25.175*5 = 125.875 MHz. We use nearest frequency 126 MHz.
// 126000, 1512000, 126, 6, 2, // 126.00MHz, VC0=1512MHz, FBDIV=126, PD1=6, PD2=2
// 126000, 504000, 42, 4, 1, // 126.00MHz, VC0=504MHz, FBDIV=42, PD1=4, PD2=1
// sysclk=126.000000 MHz, vco=504 MHz, fbdiv=42, pd1=4, pd2=1
// sysclk=126.000000 MHz, vco=504 MHz, fbdiv=42, pd1=2, pd2=2
// sysclk=126.000000 MHz, vco=756 MHz, fbdiv=63, pd1=6, pd2=1
// sysclk=126.000000 MHz, vco=756 MHz, fbdiv=63, pd1=3, pd2=2
// sysclk=126.000000 MHz, vco=1008 MHz, fbdiv=84, pd1=4, pd2=2 !!!!!
// sysclk=126.000000 MHz, vco=1260 MHz, fbdiv=105, pd1=5, pd2=2
// sysclk=126.000000 MHz, vco=1512 MHz, fbdiv=126, pd1=6, pd2=2
// sysclk=126.000000 MHz, vco=1512 MHz, fbdiv=126, pd1=4, pd2=3
// Pixel clock is now:
// 5 system clock ticks per pixel at VGA ... pixel clock = 25.2 MHz, 0.039683 us per pixel
// 10 system clock ticks per pixel at QVGA ... pixel clock = 12.6 MHz, 0.079365 us per pixel
//
// - active image is 640*5=3200 clock ticks = 25.3968 us (QVGA: 1600 clock ticks)
// - total scanline is 126*31.77781=4004 clock ticks (QVGA: 2002 clock ticks)
// - H front porch = 82 clock ticks (QVGA: 41 clock ticks)
// - H sync pulse = 480 clock ticks (QVGA: 240 clock ticks)
// - H back porch = 242 clock ticks (QVGA: 121 clock ticks)
// in case of system clock = 125 MHz
// - PIO clock = system clock / 2
// - 5 PIO clocks per pixel = 10 system clocks per pixel
// - PIO clock = 62.5 MHz
// - pixel clock = 12.5 MHz
// - active image (320 pixels): 320*5 = 1600 PIO clocks = 3200 system ticks = 25.6 us (2.2 pixels stays invisible)
// - total scanline: 125*31.77781 = 3972 system clocks = 1986 PIO clocks
// - H front porch = 34 PIO clk
// - H sync = 238 PIO clk
// - H back = 114 PIO clk
extern volatile int VGAscrolly;
// PIO command (jmp=program address, num=loop counter)
#define QVGACMD(jmp, num) ( ((uint32_t)((jmp)+QVGAOff)<<27) | (uint32_t)(num))
// display frame buffer
// pointer to current frame buffer
uint QVGAOff; // offset of QVGA PIO program
// Scanline data buffers (commands sent to PIO)
uint32_t ScanLineImg[3]; // image: HSYNC ... back porch ... image command
uint32_t ScanLineFp; // front porch
uint32_t ScanLineDark[2]; // dark: HSYNC ... back porch + dark + front porch
uint32_t ScanLineSync[2]; // vertical sync: VHSYNC ... VSYNC(back porch + dark + front porch)
// Scanline control buffers
#define CB_MAX 8 // size of one scanline control buffer (1 link to data buffer requires 2x uint32_t)
uint32_t ScanLineCB[2*CB_MAX]; // 2 control buffers
int QVgaBufInx; // current running control buffer
uint32_t* ScanLineCBNext; // next control buffer
// handler variables
volatile int QVgaScanLine; // current processed scan line 0... (next displayed scan line)
volatile uint32_t QVgaFrame; // frame counter
#ifdef rp2350
uint16_t fbuff[2][212]={0};
#else
uint16_t fbuff[2][180]={0};
#endif
volatile int X_TILE=80, Y_TILE=40;
// saved integer divider state
// VGA DMA handler - called on end of every scanline
static int VGAnextbuf=0,VGAnowbuf=1, tile=0, tc=0;
void MIPS32 __not_in_flash_func(QVgaLine1)()
{
int i,line;
uint8_t l,d;
uint8_t transparent16=(uint8_t)transparent;
#ifdef rp2350
uint8_t s;
uint8_t transparent16s=(uint8_t)transparents;
#endif
// Clear the interrupt request for DMA control channel
dma_hw->ints0 = (1u << QVGA_DMA_PIO);
// update DMA control channel and run it
dma_channel_set_read_addr(QVGA_DMA_CB, ScanLineCBNext, true);
// save integer divider state
// hw_divider_save_state(&SaveDividerState);
// prepare control buffer to be processed
uint32_t* cb = &ScanLineCB[QVgaBufInx*CB_MAX];
// switch current buffer index (bufinx = current preparing buffer, MiniVgaBufInx = current running buffer)
QVgaBufInx ^= 1;
ScanLineCBNext = cb;
// increment scanline (1..)
line = QVgaScanLine+1; // current scanline
// line++; // new current scanline
if (line >= QVGA_VTOT) // last scanline?
{
QVgaFrame++; // increment frame counter
line = 0; // restart scanline
tile=0;
tc=0;
}
QVgaScanLine = line; // store new scanline
// check scanline
line -= QVGA_VSYNC;
if (line < 0)
{
// VSYNC
*cb++ = 2;
*cb++ = (uint32_t)&ScanLineSync[0];
}
else
{
// front porch and back porch
line -= QVGA_VBACK;
if ((line < 0) || (line >= QVGA_VACT))
{
// dark line
*cb++ = 2;
*cb++ = (uint32_t)&ScanLineDark[0];
}
// image scanlines
else
{
// prepare image line
if(DISPLAY_TYPE==SCREENMODE1){
uint16_t *q=&fbuff[VGAnextbuf][0];
volatile unsigned char *p=&DisplayBuf[line * vgaloop8];
volatile unsigned char *pp=&LayerBuf[line * vgaloop8];
if(tc==ytileheight){
tile++;
tc=0;
}
tc++;
register int pos=tile*X_TILE;
for(i=0;i<vgaloop16;i++){
register int d=*p++ | *pp++;
register int low= d & 0xF;
register int high=d >>4;
*q++=(M_Foreground[low] & tilefcols[pos]) | (M_Background[low] & tilebcols[pos]) ;
*q++=(M_Foreground[high]& tilefcols[pos]) | (M_Background[high] & tilebcols[pos]) ;
pos++;
d=*p++ | *pp++;
low= d & 0xF;
high=d++ >>4;
*q++=(M_Foreground[low] & tilefcols[pos]) | (M_Background[low] & tilebcols[pos]) ;
*q++=(M_Foreground[high]& tilefcols[pos]) | (M_Background[high] & tilebcols[pos]) ;
pos++;
}
#ifdef rp2350
} else if(DISPLAY_TYPE==SCREENMODE3){
register unsigned char *p=&DisplayBuf[line * vgaloop2];
register unsigned char *q=&LayerBuf[line * vgaloop2];
register int low, high, low2, high2;
register uint8_t *r=(uint8_t *)fbuff[VGAnextbuf];
for(int i=0;i<vgaloop2;i++){
low= map16[p[i] & 0xF];
high=map16[(p[i] & 0xF0)>>4];
low2= map16[q[i] & 0xF];
high2=map16[(q[i] & 0xF0)>>4];
if(low2!=transparent16)low=low2;
if(high2!=transparent16)high=high2;
*r++=low | (high<<4);
}
#endif
} else { //mode 2
line>>=1;
register unsigned char *dd=&DisplayBuf[line * vgaloop4];
register unsigned char *ll=&LayerBuf[line * vgaloop4];
#ifdef rp2350
register unsigned char *ss=&SecondLayer[line * vgaloop4];
if(ss==dd){
ss=ll;
transparent16s=transparent16;
}
register int low3, high3;
#endif
register int low, high, low2, high2;
register uint16_t *r=(uint16_t *)fbuff[VGAnextbuf];
for(int i=0;i<vgaloop4;i+=2){
d=*dd++;
l=*ll++;
low= map16[d & 0xF];
d>>=4;
high=map16[d];
low2= map16[l & 0xF];
l>>=4;
high2=map16[l];
#ifdef rp2350
s=*ss++;
low3= map16[s & 0xF];
s>>=4;
high3=map16[s];
#endif
if(low2!=transparent16)low=low2;
if(high2!=transparent16)high=high2;
#ifdef rp2350
if(low3!=transparent16s)low=low3;
if(high3!=transparent16s)high=high3;
#endif
*r++=(low | (low<<4) | (high<<8) | (high<<12));
d=*dd++;
l=*ll++;
low= map16[d & 0xF];
d>>=4;
high=map16[d];
low2= map16[l & 0xF];
l>>=4;
high2=map16[l];
#ifdef rp2350
s=*ss++;
low3= map16[s & 0xF];
s>>=4;
high3=map16[s];
#endif
if(low2!=transparent16)low=low2;
if(high2!=transparent16)high=high2;
#ifdef rp2350
if(low3!=transparent16s)low=low3;
if(high3!=transparent16s)high=high3;
#endif
*r++=(low | (low<<4) | (high<<8) | (high<<12));
}
}
VGAnextbuf ^=1;
VGAnowbuf ^=1;
// HSYNC ... back porch ... image command
*cb++ = 3;
*cb++ = (uint32_t)&ScanLineImg[0];
// image data
*cb++ = vgaloop8;
*cb++ = (uint32_t)fbuff[VGAnowbuf];
// front porch
*cb++ = 1;
*cb++ = (uint32_t)&ScanLineFp;
}
}
// end mark
*cb++ = 0;
*cb = 0;
// restore integer divider state
// hw_divider_restore_state(&SaveDividerState);
}
void QVgaPioInit()
{
int i;
if((Option.CPU_Speed % 126000) ==0){
QVGA_TOTAL= 4000;// total clock ticks (= QVGA_HSYNC + QVGA_BP + WIDTH*QVGA_CPP[1600] + QVGA_FP)
QVGA_HSYNC = 480; // horizontal sync clock ticks
QVGA_HACT = 640;
QVGA_BP = 240; // back porch clock ticks
QVGA_FP = 80; // front porch clock ticks
// QVGA vertical timings
QVGA_VACT = 480; // V active scanlines (= 2*HEIGHT)
QVGA_VFRONT = 10; // V front porch
QVGA_VSYNC = 2; // length of V sync (number of scanlines)
QVGA_VBACK = 33; // V back porch
QVGA_VTOT = 525; // total scanlines (= QVGA_VSYNC + QVGA_VBACK + QVGA_VACT + QVGA_VFRONT)
} else if(Option.CPU_Speed == Freq848){
QVGA_TOTAL= 1088*5;// total clock ticks (= QVGA_HSYNC + QVGA_BP + WIDTH*QVGA_CPP[1600] + QVGA_FP)
QVGA_HSYNC = 112*5; // horizontal sync clock ticks
QVGA_HACT = 848;
QVGA_BP = 112*5; // back porch clock ticks
QVGA_FP = 16*5; // front porch clock ticks
// QVGA vertical timings
QVGA_VACT = 480; // V active scanlines (= 2*HEIGHT)
QVGA_VFRONT = 8; // V front porch
QVGA_VSYNC = 6; // length of V sync (number of scanlines)
QVGA_VBACK = 23; // V back porch
QVGA_VTOT = 517; // total scanlines (= QVGA_VSYNC + QVGA_VBACK + QVGA_VACT + QVGA_VFRONT)
} else if(Option.CPU_Speed == FreqSVGA){
QVGA_TOTAL= 1024*5;// total clock ticks (= QVGA_HSYNC + QVGA_BP + WIDTH*QVGA_CPP[1600] + QVGA_FP)
QVGA_HSYNC = 72*5; // horizontal sync clock ticks
QVGA_HACT = 800;
QVGA_BP = 128*5; // back porch clock ticks
QVGA_FP = 24*5; // front porch clock ticks
// QVGA vertical timings
QVGA_VACT = 600; // V active scanlines (= 2*HEIGHT)
QVGA_VFRONT = 1; // V front porch
QVGA_VSYNC = 2; // length of V sync (number of scanlines)
QVGA_VBACK = 22; // V back porch
QVGA_VTOT = 625; // total scanlines (= QVGA_VSYNC + QVGA_VBACK + QVGA_VACT + QVGA_VFRONT)
} else if(Option.CPU_Speed == Freq400){
QVGA_TOTAL= 900*5;// total clock ticks (= QVGA_HSYNC + QVGA_BP + WIDTH*QVGA_CPP[1600] + QVGA_FP)
QVGA_HSYNC = 108*5; // horizontal sync clock ticks
QVGA_HACT = 720;
QVGA_BP = 54*5; // back porch clock ticks
QVGA_FP = 18*5; // front porch clock ticks
// QVGA vertical timings
QVGA_VACT = 400; // V active scanlines (= 2*HEIGHT)
QVGA_VFRONT = 12; // V front porch
QVGA_VSYNC = 2; // length of V sync (number of scanlines)
QVGA_VBACK = 35; // V back porch
QVGA_VTOT = 449; // total scanlines (= QVGA_VSYNC + QVGA_VBACK + QVGA_VACT + QVGA_VFRONT)
} else {
QVGA_TOTAL= 4200;// total clock ticks (= QVGA_HSYNC + QVGA_BP + WIDTH*QVGA_CPP[1600] + QVGA_FP)
QVGA_HSYNC = 320; // horizontal sync clock ticks
QVGA_HACT = 640;
QVGA_BP = 600; // back porch clock ticks
QVGA_FP = 80; // front porch clock ticks
// QVGA vertical timings
QVGA_VACT = 480; // V active scanlines (= 2*HEIGHT)
QVGA_VFRONT = 1; // V front porch
QVGA_VSYNC = 3; // length of V sync (number of scanlines)
QVGA_VBACK = 16; // V back porch
QVGA_VTOT = 500; // total scanlines (= QVGA_VSYNC + QVGA_VBACK + QVGA_VACT + QVGA_VFRONT)
}
// load PIO program
#ifdef rp2350
if(piomap[QVGA_PIO_NUM] & (uint64_t)0xFFFF00000000)pio_set_gpio_base(QVGA_PIO,16);
#endif
I2SOff = pio_add_program(QVGA_PIO, &i2s_program);
QVGAOff = pio_add_program(QVGA_PIO, &qvga_program);
// configure GPIOs for use by PIO
for (i = QVGA_GPIO_FIRST; i <= QVGA_GPIO_LAST; i++) pio_gpio_init(QVGA_PIO, i);
pio_gpio_init(QVGA_PIO, QVGA_GPIO_HSYNC);
pio_gpio_init(QVGA_PIO, QVGA_GPIO_VSYNC);
// set pin direction to output
pio_sm_set_consecutive_pindirs(QVGA_PIO, QVGA_SM, QVGA_GPIO_FIRST, QVGA_GPIO_NUM, true);
pio_sm_set_consecutive_pindirs(QVGA_PIO, QVGA_SM, QVGA_GPIO_HSYNC, 2, true);
// negate HSYNC and VSYNC output
if(!(Option.CPU_Speed==Freq848 || Option.CPU_Speed==FreqSVGA)){
gpio_set_outover(QVGA_GPIO_HSYNC, GPIO_OVERRIDE_INVERT);
gpio_set_outover(QVGA_GPIO_VSYNC, GPIO_OVERRIDE_INVERT);
}
// prepare default PIO program config
pio_sm_config cfg = qvga_program_get_default_config(QVGAOff);
// map state machine's OUT and MOV pins
sm_config_set_out_pins(&cfg, QVGA_GPIO_FIRST, QVGA_GPIO_NUM);
// set sideset pins (HSYNC and VSYNC)
sm_config_set_sideset_pins(&cfg, QVGA_GPIO_HSYNC);
// join FIFO to send only
sm_config_set_fifo_join(&cfg, PIO_FIFO_JOIN_TX);
// PIO clock divider
sm_config_set_clkdiv(&cfg, QVGA_CLKDIV);
// shift right, autopull, pull threshold
sm_config_set_out_shift(&cfg, true, true, 32);
// initialize state machine
pio_sm_init(QVGA_PIO, QVGA_SM, QVGAOff+qvga_offset_entry, &cfg);
}
// initialize scanline buffers
void QVgaBufInit()
{
// image scanline data buffer: HSYNC ... back porch ... image command
ScanLineImg[0] = QVGACMD(qvga_offset_hsync, QVGA_HSYNC-3); // HSYNC
ScanLineImg[1] = QVGACMD(qvga_offset_dark, QVGA_BP-4); // back porch
ScanLineImg[2] = QVGACMD(qvga_offset_output, QVGA_HACT-2); // image
// front porch
ScanLineFp = QVGACMD(qvga_offset_dark, QVGA_FP-4); // front porch
// dark scanline: HSYNC ... back porch + dark + front porch
ScanLineDark[0] = QVGACMD(qvga_offset_hsync, QVGA_HSYNC-3); // HSYNC
ScanLineDark[1] = QVGACMD(qvga_offset_dark, QVGA_TOTAL-QVGA_HSYNC-4); // back porch + dark + front porch
// vertical sync: VHSYNC ... VSYNC(back porch + dark + front porch)
ScanLineSync[0] = QVGACMD(qvga_offset_vhsync, QVGA_HSYNC-3); // VHSYNC
ScanLineSync[1] = QVGACMD(qvga_offset_vsync, QVGA_TOTAL-QVGA_HSYNC-3); // VSYNC(back porch + dark + front porch)
// control buffer 1 - initialize to VSYNC
ScanLineCB[0] = 2; // send 2x uint32_t (send ScanLineSync)
ScanLineCB[1] = (uint32_t)&ScanLineSync[0]; // VSYNC data buffer
ScanLineCB[2] = 0; // stop mark
ScanLineCB[3] = 0; // stop mark
// control buffer 1 - initialize to VSYNC
ScanLineCB[CB_MAX+0] = 2; // send 2x uint32_t (send ScanLineSync)
ScanLineCB[CB_MAX+1] = (uint32_t)&ScanLineSync[0]; // VSYNC data buffer
ScanLineCB[CB_MAX+2] = 0; // stop mark
ScanLineCB[CB_MAX+3] = 0; // stop mark
}
// initialize QVGA DMA
// control blocks aliases:
// +0x0 +0x4 +0x8 +0xC (Trigger)
// 0x00 (alias 0): READ_ADDR WRITE_ADDR TRANS_COUNT CTRL_TRIG
// 0x10 (alias 1): CTRL READ_ADDR WRITE_ADDR TRANS_COUNT_TRIG
// 0x20 (alias 2): CTRL TRANS_COUNT READ_ADDR WRITE_ADDR_TRIG
// 0x30 (alias 3): CTRL WRITE_ADDR TRANS_COUNT READ_ADDR_TRIG ... we use this!
void QVgaDmaInit()
{
// ==== prepare DMA control channel
// prepare DMA default config
dma_channel_config cfg = dma_channel_get_default_config(QVGA_DMA_CB);
// increment address on read from memory
channel_config_set_read_increment(&cfg, true);
// increment address on write to DMA port
channel_config_set_write_increment(&cfg, true);
// each DMA transfered entry is 32-bits
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_32);
// write ring - wrap to 8-byte boundary (TRANS_COUNT and READ_ADDR_TRIG of data DMA)
channel_config_set_ring(&cfg, true, 3);
// DMA configure
dma_channel_configure(
QVGA_DMA_CB, // channel
&cfg, // configuration
&dma_hw->ch[QVGA_DMA_PIO].al3_transfer_count, // write address
&ScanLineCB[0], // read address - as first, control buffer 1 will be sent out
2, // number of transfers in uint32_t (number of transfers per one request from data DMA)
false // do not start yet
);
// ==== prepare DMA data channel
// prepare DMA default config
cfg = dma_channel_get_default_config(QVGA_DMA_PIO);
// increment address on read from memory
channel_config_set_read_increment(&cfg, true);
// do not increment address on write to PIO
channel_config_set_write_increment(&cfg, false);
// each DMA transfered entry is 32-bits
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_32);
// DMA data request for sending data to PIO
channel_config_set_dreq(&cfg, pio_get_dreq(QVGA_PIO, QVGA_SM, true));
// chain channel to DMA control block
channel_config_set_chain_to(&cfg, QVGA_DMA_CB);
// raise the IRQ flag when 0 is written to a trigger register (end of chain)
channel_config_set_irq_quiet(&cfg, true);
// set high priority
cfg.ctrl |= DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS;
// DMA configure
dma_channel_configure(
QVGA_DMA_PIO, // channel
&cfg, // configuration
&QVGA_PIO->txf[QVGA_SM], // write address
NULL, // read address
0, // number of transfers in uint32_t
false // do not start immediately
);
// ==== initialize IRQ0, raised from DMA data channel
// enable DMA channel IRQ0
dma_channel_set_irq0_enabled(QVGA_DMA_PIO, true);
// set DMA IRQ handler
irq_set_exclusive_handler(DMA_IRQ_0, QVgaLine1);
vgaloop4=QVGA_HACT/4;
vgaloop8=QVGA_HACT/8;
vgaloop16=QVGA_HACT/16;
vgaloop2=QVGA_HACT/2;
MODE1SIZE=QVGA_HACT*QVGA_VACT/8;
MODE2SIZE=(QVGA_HACT/2)*(QVGA_VACT/2)/2;
MODE3SIZE=QVGA_HACT*QVGA_VACT/2;
HRes=QVGA_HACT;
VRes=QVGA_VACT;
// set highest IRQ priority
irq_set_priority(DMA_IRQ_0, 0);
}
// initialize QVGA (can change system clock)
void QVgaInit()
{
X_TILE=Option.X_TILE;
Y_TILE=Option.Y_TILE;
ytileheight=(X_TILE==80 || X_TILE==90 || X_TILE==106 || X_TILE==100)? 12 : 16;
// initialize PIO
QVgaPioInit();
// initialize scanline buffers
QVgaBufInit();
// initialize DMA
QVgaDmaInit();
// initialize parameters
QVgaScanLine = 0; // currently processed scanline
QVgaBufInx = 0; // at first, control buffer 1 will be sent out
QVgaFrame = 0; // current frame
ScanLineCBNext = &ScanLineCB[CB_MAX]; // send control buffer 2 next
// enable DMA IRQ
irq_set_enabled(DMA_IRQ_0, true);
// start DMA
dma_channel_start(QVGA_DMA_CB);
// run state machine
pio_sm_set_enabled(QVGA_PIO, QVGA_SM, true);
}
void (* volatile Core1Fnc)() = NULL; // core 1 remote function
// QVGA core
void __not_in_flash_func(QVgaCore)()
{
// initialize QVGA
QVgaInit();
// infinite loop
while (true)
{
// data memory barrier
__dmb();
if (multicore_fifo_rvalid()) {
int command=multicore_fifo_pop_blocking();
if(command==0x5555){
irq_set_enabled(DMA_IRQ_0, false);
};
if(command==0xAAAA){
irq_set_enabled(DMA_IRQ_0, true);
}
}
}
}
uint32_t core1stack[128];
#else
extern uint16_t HDMIlines[2][800];
// DVI constants
#define TMDS_CTRL_00 0x354u
#define TMDS_CTRL_01 0x0abu
#define TMDS_CTRL_10 0x154u
#define TMDS_CTRL_11 0x2abu
#define SYNC_V0_H0 (TMDS_CTRL_00 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
#define SYNC_V0_H1 (TMDS_CTRL_01 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
#define SYNC_V1_H0 (TMDS_CTRL_10 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
#define SYNC_V1_H1 (TMDS_CTRL_11 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
#define MODE_H_S_SYNC_POLARITY 0
#define MODE_H_S_FRONT_PORCH (Option.CPU_Speed % 126000==0 ? 16 : 16)
#define MODE_H_S_SYNC_WIDTH (Option.CPU_Speed % 126000==0 ? 96 : 64)
#define MODE_H_S_BACK_PORCH (Option.CPU_Speed % 126000==0 ? 48 : 120)
#define MODE_V_S_SYNC_POLARITY 0
#define MODE_V_S_FRONT_PORCH (Option.CPU_Speed % 126000==0 ? 10 : 1)
#define MODE_V_S_SYNC_WIDTH (Option.CPU_Speed % 126000==0 ? 2 : 3)
#define MODE_V_S_BACK_PORCH (Option.CPU_Speed % 126000==0 ? 33 : 16)
#define MODE_H_F_SYNC_POLARITY 0
#define MODE_H_F_ACTIVE_PIXELS 640
#define MODE_H_F_FRONT_PORCH 16
#define MODE_H_F_SYNC_WIDTH 96
#define MODE_H_F_BACK_PORCH 48
#define MODE_V_F_SYNC_POLARITY 0
#define MODE_V_F_ACTIVE_LINES 480
#define MODE_V_F_FRONT_PORCH 10
#define MODE_V_F_SYNC_WIDTH 2
#define MODE_V_F_BACK_PORCH 33
#define MODE_H_8_SYNC_POLARITY 1
#define MODE_H_8_FRONT_PORCH 16
#define MODE_H_8_SYNC_WIDTH 112
#define MODE_H_8_BACK_PORCH 112
#define MODE_V_8_SYNC_POLARITY 1
#define MODE_V_8_FRONT_PORCH 8
#define MODE_V_8_SYNC_WIDTH 6
#define MODE_V_8_BACK_PORCH 23
#define MODE_H_4_SYNC_POLARITY 0
#define MODE_H_4_FRONT_PORCH 18
#define MODE_H_4_SYNC_WIDTH 108
#define MODE_H_4_BACK_PORCH 54
#define MODE_V_4_SYNC_POLARITY 0
#define MODE_V_4_FRONT_PORCH 12
#define MODE_V_4_SYNC_WIDTH 2
#define MODE_V_4_BACK_PORCH 35
#define MODE_H_W_SYNC_POLARITY 1
#define MODE_H_W_FRONT_PORCH 110
#define MODE_H_W_SYNC_WIDTH 40
#define MODE_H_W_BACK_PORCH 220
#define MODE_V_W_SYNC_POLARITY 1
#define MODE_V_W_FRONT_PORCH 5
#define MODE_V_W_SYNC_WIDTH 5
#define MODE_V_W_BACK_PORCH 20
#define MODE_H_L_SYNC_POLARITY 0
#define MODE_H_L_FRONT_PORCH 24
#define MODE_H_L_SYNC_WIDTH 136
#define MODE_H_L_BACK_PORCH 144
#define MODE_V_L_SYNC_POLARITY 0
#define MODE_V_L_FRONT_PORCH 3
#define MODE_V_L_SYNC_WIDTH 6
#define MODE_V_L_BACK_PORCH 29
#define MODE_H_V_SYNC_POLARITY 1
#define MODE_H_V_FRONT_PORCH 24
#define MODE_H_V_SYNC_WIDTH 72
#define MODE_H_V_BACK_PORCH 128
#define MODE_V_V_SYNC_POLARITY 1
#define MODE_V_V_FRONT_PORCH 1
#define MODE_V_V_SYNC_WIDTH 2
#define MODE_V_V_BACK_PORCH 22
#define MODE_H_S_TOTAL_PIXELS ( \
MODE_H_S_FRONT_PORCH + MODE_H_S_SYNC_WIDTH + \
MODE_H_S_BACK_PORCH + MODE_H_S_ACTIVE_PIXELS \
)
#define MODE_V_S_TOTAL_LINES ( \
MODE_V_S_FRONT_PORCH + MODE_V_S_SYNC_WIDTH + \
MODE_V_S_BACK_PORCH + MODE_V_S_ACTIVE_LINES \
)
#define MODE_H_F_TOTAL_PIXELS ( \
MODE_H_F_FRONT_PORCH + MODE_H_F_SYNC_WIDTH + \
MODE_H_F_BACK_PORCH + MODE_H_F_ACTIVE_PIXELS \
)
#define MODE_V_F_TOTAL_LINES ( \
MODE_V_F_FRONT_PORCH + MODE_V_F_SYNC_WIDTH + \
MODE_V_F_BACK_PORCH + MODE_V_F_ACTIVE_LINES \
)
#define MODE_H_W_TOTAL_PIXELS ( \
MODE_H_W_FRONT_PORCH + MODE_H_W_SYNC_WIDTH + \
MODE_H_W_BACK_PORCH + MODE_H_W_ACTIVE_PIXELS \
)
#define MODE_V_W_TOTAL_LINES ( \
MODE_V_W_FRONT_PORCH + MODE_V_W_SYNC_WIDTH + \
MODE_V_W_BACK_PORCH + MODE_V_W_ACTIVE_LINES \
)
#define MODE_H_L_TOTAL_PIXELS ( \
MODE_H_L_FRONT_PORCH + MODE_H_L_SYNC_WIDTH + \
MODE_H_L_BACK_PORCH + MODE_H_L_ACTIVE_PIXELS \
)
#define MODE_V_L_TOTAL_LINES ( \
MODE_V_L_FRONT_PORCH + MODE_V_L_SYNC_WIDTH + \
MODE_V_L_BACK_PORCH + MODE_V_L_ACTIVE_LINES \
)
#define MODE_H_V_TOTAL_PIXELS ( \
MODE_H_V_FRONT_PORCH + MODE_H_V_SYNC_WIDTH + \
MODE_H_V_BACK_PORCH + MODE_H_V_ACTIVE_PIXELS \
)
#define MODE_V_V_TOTAL_LINES ( \
MODE_V_V_FRONT_PORCH + MODE_V_V_SYNC_WIDTH + \
MODE_V_V_BACK_PORCH + MODE_V_V_ACTIVE_LINES \
)
#define MODE_H_8_TOTAL_PIXELS ( \
MODE_H_8_FRONT_PORCH + MODE_H_8_SYNC_WIDTH + \
MODE_H_8_BACK_PORCH + MODE_H_8_ACTIVE_PIXELS \
)
#define MODE_V_8_TOTAL_LINES ( \
MODE_V_8_FRONT_PORCH + MODE_V_8_SYNC_WIDTH + \
MODE_V_8_BACK_PORCH + MODE_V_8_ACTIVE_LINES \
)
#define MODE_H_4_TOTAL_PIXELS ( \
MODE_H_4_FRONT_PORCH + MODE_H_4_SYNC_WIDTH + \
MODE_H_4_BACK_PORCH + MODE_H_4_ACTIVE_PIXELS \
)
#define MODE_V_4_TOTAL_LINES ( \
MODE_V_4_FRONT_PORCH + MODE_V_4_SYNC_WIDTH + \
MODE_V_4_BACK_PORCH + MODE_V_4_ACTIVE_LINES \
)
volatile int mode = 1;
#define HSTX_CMD_RAW (0x0u << 12)
#define HSTX_CMD_RAW_REPEAT (0x1u << 12)
#define HSTX_CMD_TMDS (0x2u << 12)
#define HSTX_CMD_TMDS_REPEAT (0x3u << 12)
#define HSTX_CMD_NOP (0xfu << 12)
#define DMACH_PING 0
#define DMACH_PONG 1
const uint32_t MAP256DEF[256] =
{
0x0,0x55,0xAA,0xFF,0x2400,0x2455,0x24AA,0x24FF,
0x4900,0x4955,0x49AA,0x49FF,0x6D00,0x6D55,0x6DAA,0x6DFF,
0x9200,0x9255,0x92AA,0x92FF,0xB600,0xB655,0xB6AA,0xB6FF,
0xDB00,0xDB55,0xDBAA,0xDBFF,0xFF00,0xFF55,0xFFAA,0xFFFF,
0x240000,0x240055,0x2400AA,0x2400FF,0x242400,0x242455,0x2424AA,0x2424FF,
0x244900,0x244955,0x2449AA,0x2449FF,0x246D00,0x246D55,0x246DAA,0x246DFF,
0x249200,0x249255,0x2492AA,0x2492FF,0x24B600,0x24B655,0x24B6AA,0x24B6FF,
0x24DB00,0x24DB55,0x24DBAA,0x24DBFF,0x24FF00,0x24FF55,0x24FFAA,0x24FFFF,
0x490000,0x490055,0x4900AA,0x4900FF,0x492400,0x492455,0x4924AA,0x4924FF,
0x494900,0x494955,0x4949AA,0x4949FF,0x496D00,0x496D55,0x496DAA,0x496DFF,
0x499200,0x499255,0x4992AA,0x4992FF,0x49B600,0x49B655,0x49B6AA,0x49B6FF,
0x49DB00,0x49DB55,0x49DBAA,0x49DBFF,0x49FF00,0x49FF55,0x49FFAA,0x49FFFF,
0x6D0000,0x6D0055,0x6D00AA,0x6D00FF,0x6D2400,0x6D2455,0x6D24AA,0x6D24FF,
0x6D4900,0x6D4955,0x6D49AA,0x6D49FF,0x6D6D00,0x6D6D55,0x6D6DAA,0x6D6DFF,
0x6D9200,0x6D9255,0x6D92AA,0x6D92FF,0x6DB600,0x6DB655,0x6DB6AA,0x6DB6FF,
0x6DDB00,0x6DDB55,0x6DDBAA,0x6DDBFF,0x6DFF00,0x6DFF55,0x6DFFAA,0x6DFFFF,
0x920000,0x920055,0x9200AA,0x9200FF,0x922400,0x922455,0x9224AA,0x9224FF,
0x924900,0x924955,0x9249AA,0x9249FF,0x926D00,0x926D55,0x926DAA,0x926DFF,
0x929200,0x929255,0x9292AA,0x9292FF,0x92B600,0x92B655,0x92B6AA,0x92B6FF,
0x92DB00,0x92DB55,0x92DBAA,0x92DBFF,0x92FF00,0x92FF55,0x92FFAA,0x92FFFF,
0xB60000,0xB60055,0xB600AA,0xB600FF,0xB62400,0xB62455,0xB624AA,0xB624FF,
0xB64900,0xB64955,0xB649AA,0xB649FF,0xB66D00,0xB66D55,0xB66DAA,0xB66DFF,
0xB69200,0xB69255,0xB692AA,0xB692FF,0xB6B600,0xB6B655,0xB6B6AA,0xB6B6FF,
0xB6DB00,0xB6DB55,0xB6DBAA,0xB6DBFF,0xB6FF00,0xB6FF55,0xB6FFAA,0xB6FFFF,
0xDB0000,0xDB0055,0xDB00AA,0xDB00FF,0xDB2400,0xDB2455,0xDB24AA,0xDB24FF,
0xDB4900,0xDB4955,0xDB49AA,0xDB49FF,0xDB6D00,0xDB6D55,0xDB6DAA,0xDB6DFF,
0xDB9200,0xDB9255,0xDB92AA,0xDB92FF,0xDBB600,0xDBB655,0xDBB6AA,0xDBB6FF,
0xDBDB00,0xDBDB55,0xDBDBAA,0xDBDBFF,0xDBFF00,0xDBFF55,0xDBFFAA,0xDBFFFF,
0xFF0000,0xFF0055,0xFF00AA,0xFF00FF,0xFF2400,0xFF2455,0xFF24AA,0xFF24FF,
0xFF4900,0xFF4955,0xFF49AA,0xFF49FF,0xFF6D00,0xFF6D55,0xFF6DAA,0xFF6DFF,
0xFF9200,0xFF9255,0xFF92AA,0xFF92FF,0xFFB600,0xFFB655,0xFFB6AA,0xFFB6FF,
0xFFDB00,0xFFDB55,0xFFDBAA,0xFFDBFF,0xFFFF00,0xFFFF55,0xFFFFAA,0xFFFFFF
};
const uint32_t MAP16DEF[16] = {0x00,0xFF,0x5500,0x55ff,0xAA00,0xAAff,0xff00,0xffff,0xff0000,0xff00FF,0xff5500,0xff55ff,0xffAA00,0xffAAff,0xffff00,0xffffff};
const uint32_t MAP4DEF[4] = {0,0xFF,0xFF00,0xFF0000};
uint16_t map256[256];
static uint32_t vblank_line_vsync_off[7] ;
static uint32_t vblank_line_vsync_on[7];
static uint32_t vactive_line[9];
static bool dma_pong = false;
int MODE_H_SYNC_POLARITY, MODE_V_TOTAL_LINES, MODE_ACTIVE_LINES, MODE_ACTIVE_PIXELS;
int MODE_H_ACTIVE_PIXELS, MODE_H_FRONT_PORCH, MODE_H_SYNC_WIDTH, MODE_H_BACK_PORCH;
int MODE_V_SYNC_POLARITY ,MODE_V_ACTIVE_LINES ,MODE_V_FRONT_PORCH, MODE_V_SYNC_WIDTH, MODE_V_BACK_PORCH;
int PIXELS_PER_WORD, TRANSFER_COUNT, BLANKING_COUNT;
// A ping and a pong are cued up initially, so the first time we enter this
// handler it is to cue up the second ping after the first ping has completed.
// This is the third scanline overall (-> =2 because zero-based).
volatile int32_t v_scanline = 2;
// During the vertical active period, we take two IRQs per scanline: one to
// post the command list, and another to post the pixels.
static bool vactive_cmdlist_posted = false;
void MIPS64 __not_in_flash_func(dma_irq_handler0)() {
// dma_pong indicates the channel that just finished, which is the one
// we're about to reload.
uint ch_num = dma_pong ? DMACH_PONG : DMACH_PING;
dma_channel_hw_t *ch = &dma_hw->ch[ch_num];
dma_hw->intr = 1u << ch_num;
dma_pong = !dma_pong;
if (v_scanline >= MODE_V_FRONT_PORCH && v_scanline < (MODE_V_FRONT_PORCH + MODE_V_SYNC_WIDTH)) {
ch->read_addr = (uintptr_t)vblank_line_vsync_on;
ch->transfer_count = count_of(vblank_line_vsync_on);
} else if (v_scanline < BLANKING_COUNT) {
ch->read_addr = (uintptr_t)vblank_line_vsync_off;
ch->transfer_count = count_of(vblank_line_vsync_off);
} else if (!vactive_cmdlist_posted) {
ch->read_addr = (uintptr_t)vactive_line;
ch->transfer_count = count_of(vactive_line);
vactive_cmdlist_posted = true;
} else {
ch->read_addr = (uintptr_t)HDMIlines[v_scanline & 1];
ch->transfer_count = TRANSFER_COUNT;
vactive_cmdlist_posted = false;
}
if (!vactive_cmdlist_posted) {
v_scanline = (v_scanline + 1) % MODE_V_TOTAL_LINES;
}
}
// ----------------------------------------------------------------------------
// Main program
/*void MIPS32 __not_in_flash_func(HDMIloop1)(void){
int last_line=2,load_line, line_to_load, Line_dup, Line_quad;
while(1){
if(v_scanline!=last_line){
last_line=v_scanline;
load_line=v_scanline - (MODE_V_TOTAL_LINES - MODE_V_ACTIVE_LINES);
Line_dup=load_line>>1;
Line_quad=load_line>>2;
line_to_load = last_line & 1;
if(load_line>=0 && load_line<MODE_V_ACTIVE_LINES){
__dmb();
switch(DISPLAY_TYPE){
case SCREENMODE1: //1280x720x2 colour with tiles
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t *fcol_w=tilefcols_w+load_line/ytileheight*X_TILE, *bcol_w=tilebcols_w+load_line/ytileheight*X_TILE; //get the relevant tile
uint32_t *pp=(uint32_t *)&DisplayBuf[load_line*vgaloop8];
uint32_t *qq=(uint32_t *)&LayerBuf[load_line*vgaloop8];
uint32_t d=*pp | *qq;
for(int i=0; i<vgaloop32 ; i++){
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
fcol_w++;
bcol_w++;
d=*(++pp) | *(++qq);
}
}
break;
case SCREENMODE2: //320 x 180 x 4bit-colour mapped to 256
{
uint32_t *p=(uint32_t *)HDMIlines[line_to_load];
uint8_t l,d,s;
int pp= (Line_quad)*vgaloop8;
for(int i=0; i<vgaloop8 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];s=SecondLayer[pp+i];
if((s&0xf)!=transparents){
*p++=map16q[s&0xf];
} else {
if((l&0xf)!=transparent){
*p++=map16q[l&0xf];
} else {
*p++=map16q[d&0xf];
}
}
d>>=4;l>>=4;s>>=4;
if((s&0xf)!=transparents){
*p++=map16q[s&0xf];
} else {
if((l&0xf)!=transparent){
*p++=map16q[l&0xf];
} else {
*p++=map16q[d&0xf];
}
}
}
}
break;
case SCREENMODE3: //640 x 360 x 4bit-colour mapped to 256
{
int pp= (Line_dup)*vgaloop4;
uint16_t *p=(uint16_t *)HDMIlines[line_to_load];
uint8_t l,d;
register uint8_t *dd=&DisplayBuf[pp];
register uint8_t *ll=&LayerBuf[pp];
for(int i=0; i<vgaloop16 ; i++){
l=*ll++;d=*dd++;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
l=*ll++;d=*dd++;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
l=*ll++;d=*dd++;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
l=*ll++;d=*dd++;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
}
}
break;
case SCREENMODE5: //320 x 180 x 8bit-colour
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t l,d,s;
int pp= (Line_quad)*vgaloop4;
for(int i=0; i<vgaloop4 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];s=SecondLayer[pp+i];
if(s!=transparents){
*p++=s;
*p++=s;
*p++=s;
*p++=s;
} else {
if(l!=transparent){
*p++=l;
*p++=l;
*p++=l;
*p++=l;
} else {
*p++=d;
*p++=d;
*p++=d;
*p++=d;
}
}
}
}
break;
default:
}
}
}
}
}*/
void MIPS32 __not_in_flash_func(HDMIloop1)(void){
int last_line=2,load_line, line_to_load, Line_dup, Line_quad;
while(1){
if(v_scanline!=last_line){
last_line=v_scanline;
load_line=v_scanline - (MODE_V_W_TOTAL_LINES - MODE_V_W_ACTIVE_LINES);
Line_dup=load_line>>1;
Line_quad=load_line>>2;
line_to_load = last_line & 1;
if(load_line>=0 && load_line<MODE_V_W_ACTIVE_LINES){
__dmb();
switch(DISPLAY_TYPE){
case SCREENMODE1: //1280x720x2 colour with tiles
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t *fcol_w=tilefcols_w+load_line/ytileheight*X_TILE, *bcol_w=tilebcols_w+load_line/ytileheight*X_TILE; //get the relevant tile
uint32_t *pp=(uint32_t *)&DisplayBuf[load_line*MODE_H_W_ACTIVE_PIXELS/8];
uint32_t *qq=(uint32_t *)&LayerBuf[load_line*MODE_H_W_ACTIVE_PIXELS/8];
uint32_t d=*pp | *qq;
for(int i=0; i<MODE_H_W_ACTIVE_PIXELS/32 ; i++){
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
fcol_w++;
bcol_w++;
d=*(++pp) | *(++qq) ;
}
}
break;
case SCREENMODE2: //320 x 180 x 4bit-colour mapped to 256
{
uint32_t *p=(uint32_t *)HDMIlines[line_to_load];
uint8_t l,d,s;
int pp= (Line_quad)*MODE_H_W_ACTIVE_PIXELS/8;
for(int i=0; i<MODE_H_W_ACTIVE_PIXELS/8 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];s=SecondLayer[pp+i];
if((s&0xf)!=transparents){
*p++=map16q[s&0xf];
} else {
if((l&0xf)!=transparent){
*p++=map16q[l&0xf];
} else {
*p++=map16q[d&0xf];
}
}
d>>=4;l>>=4;s>>=4;
if((s&0xf)!=transparents){
*p++=map16q[s&0xf];
} else {
if((l&0xf)!=transparent){
*p++=map16q[l&0xf];
} else {
*p++=map16q[d&0xf];
}
}
}
}
break;
case SCREENMODE3: //640 x 360 x 4bit-colour mapped to 256
{
int pp= (Line_dup)*MODE_H_W_ACTIVE_PIXELS/4;
uint16_t *p=(uint16_t *)HDMIlines[line_to_load];
uint8_t l,d;
for(int i=0; i<MODE_H_W_ACTIVE_PIXELS/4 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
}
}
break;
case SCREENMODE5: //320 x 180 x 8bit-colour
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t l,d,s;
int pp= (Line_quad)*MODE_H_W_ACTIVE_PIXELS/4;
for(int i=0; i<MODE_H_W_ACTIVE_PIXELS/4 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];s=SecondLayer[pp+i];
if(s!=transparents){
*p++=s;
*p++=s;
*p++=s;
*p++=s;
} else {
if(l!=transparent){
*p++=l;
*p++=l;
*p++=l;
*p++=l;
} else {
*p++=d;
*p++=d;
*p++=d;
*p++=d;
}
}
}
}
break;
default:
}
}
}
}
}
void MIPS32 __not_in_flash_func(HDMIloop2)(void){
int last_line=2,load_line, line_to_load, Line_dup, Line_quad;
while(1){
if(v_scanline!=last_line){
last_line=v_scanline;
load_line=v_scanline - (MODE_V_L_TOTAL_LINES - MODE_V_L_ACTIVE_LINES);
Line_dup=load_line>>1;
Line_quad=load_line>>2;
line_to_load = last_line & 1;
if(load_line>=0 && load_line<MODE_V_L_ACTIVE_LINES){
__dmb();
switch(DISPLAY_TYPE){
case SCREENMODE1: //1024x768x2 colour with tiles
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t *fcol_w=tilefcols_w+load_line/ytileheight*X_TILE, *bcol_w=tilebcols_w+load_line/ytileheight*X_TILE; //get the relevant tile
uint32_t *pp=(uint32_t *)&DisplayBuf[load_line*MODE_H_L_ACTIVE_PIXELS/8];
uint32_t *qq=(uint32_t *)&LayerBuf[load_line*MODE_H_L_ACTIVE_PIXELS/8];
uint32_t d=*pp | *qq;
for(int i=0; i<MODE_H_L_ACTIVE_PIXELS/32 ; i++){
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
fcol_w++;
bcol_w++;
d=*(++pp) | *(++qq) ;
}
}
break;
case SCREENMODE2: //256 x 192 x 4bit-colour mapped to 256
{
uint32_t *p=(uint32_t *)HDMIlines[line_to_load];
uint8_t l,d,s;
int pp= (Line_quad)*MODE_H_L_ACTIVE_PIXELS/8;
for(int i=0; i<MODE_H_L_ACTIVE_PIXELS/8 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];s=SecondLayer[pp+i];
if((s&0xf)!=transparents){
*p++=map16q[s&0xf];
} else {
if((l&0xf)!=transparent){
*p++=map16q[l&0xf];
} else {
*p++=map16q[d&0xf];
}
}
d>>=4;l>>=4;s>>=4;
if((s&0xf)!=transparents){
*p++=map16q[s&0xf];
} else {
if((l&0xf)!=transparent){
*p++=map16q[l&0xf];
} else {
*p++=map16q[d&0xf];
}
}
}
}
break;
case SCREENMODE3: //512 x 384 x 4bit-colour mapped to 256
{
int pp= (Line_dup)*MODE_H_L_ACTIVE_PIXELS/4;
uint16_t *p=(uint16_t *)HDMIlines[line_to_load];
uint8_t l,d;
for(int i=0; i<MODE_H_L_ACTIVE_PIXELS/4 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
}
}
break;
case SCREENMODE5: //256 x 192 x 8bit-colour
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t l,d,s;
int pp= (Line_quad)*MODE_H_L_ACTIVE_PIXELS/4;
for(int i=0; i<MODE_H_L_ACTIVE_PIXELS/4 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];s=SecondLayer[pp+i];
if(s!=transparents){
*p++=s;
*p++=s;
*p++=s;
*p++=s;
} else {
if(l!=transparent){
*p++=l;
*p++=l;
*p++=l;
*p++=l;
} else {
*p++=d;
*p++=d;
*p++=d;
*p++=d;
}
}
}
}
break;
default:
}
}
}
}
}
void MIPS32 __not_in_flash_func(HDMIloop3)(void){
int last_line=2,load_line, line_to_load, Line_dup;
while(1){
if(v_scanline!=last_line){
last_line=v_scanline;
load_line=v_scanline - (MODE_V_TOTAL_LINES - MODE_V_ACTIVE_LINES);
Line_dup=load_line>>1;
line_to_load = last_line & 1;
if(load_line>=0 && load_line<MODE_V_ACTIVE_LINES){
__dmb();
switch(DISPLAY_TYPE){
case SCREENMODE1: //800x600x2 or 848x480x2 colour with tiles
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t *fcol_w=tilefcols_w+load_line/ytileheight*X_TILE, *bcol_w=tilebcols_w+load_line/ytileheight*X_TILE; //get the relevant tile
uint16_t *pp=(uint16_t *)&DisplayBuf[load_line*vgaloop8];
uint16_t *qq=(uint16_t *)&LayerBuf[load_line*vgaloop8];
uint16_t d=*pp | *qq;
for(int i=0; i<vgaloop16 ; i++){
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
*p++ = (d&0x1) ? *fcol_w : *bcol_w;
d>>=1;
fcol_w++;
bcol_w++;
d=*(++pp) | *(++qq) ;
}
}
break;
case SCREENMODE2: //400 X 300 x 4bit-colour mapped to 256 or 424 X 240 x 4bit-colour mapped to 256
{
uint16_t *p=(uint16_t *)HDMIlines[line_to_load];
uint8_t l,d;
int pp= (Line_dup)*vgaloop4;
for(int i=0; i<vgaloop4 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16d[l&0xf];
} else {
*p++=map16d[d&0xf];
}
}
}
break;
case SCREENMODE3: //800 x 600 x 4bit-colour mapped to 256 or 848 x 480 x 4bit-colour mapped to 256
{
int pp= load_line*vgaloop2;
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t l,d;
for(int i=0; i<vgaloop2 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];
if((l&0xf)!=transparent){
*p++=map16s[l&0xf];
} else {
*p++=map16s[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent){
*p++=map16s[l&0xf];
} else {
*p++=map16s[d&0xf];
}
}
}
break;
case SCREENMODE5: //400 x 300 x 8bit-colour or 424 x 240 x 8bit-colour
{
uint8_t *p=(uint8_t *)HDMIlines[line_to_load];
uint8_t l,d;
int pp= (Line_dup)*vgaloop2;
for(int i=0; i<vgaloop2 ; i++){
l=LayerBuf[pp+i];d=DisplayBuf[pp+i];
if(l!=transparent){
*p++=l;
*p++=l;
} else {
*p++=d;
*p++=d;
}
}
}
break;
default:
}
}
}
}
}
void MIPS32 __not_in_flash_func(HDMIloop0)(void){
int last_line=2,load_line, line_to_load, line;
while (1){
if(v_scanline!=last_line){
uint8_t transparent16=(uint8_t)transparent;
uint8_t transparent16s=(uint8_t)transparents;
last_line=v_scanline;
load_line=line=v_scanline - (MODE_V_TOTAL_LINES - MODE_V_ACTIVE_LINES);
if(HRes==vgaloop2)line>>=1;
line_to_load = last_line & 1;
uint8_t l,d,s;
register unsigned char *dd;
register unsigned char *ll;
int pp;
uint16_t *p=HDMIlines[line_to_load];
if(load_line>=0 && load_line<MODE_V_ACTIVE_LINES){
__dsb();
switch(DISPLAY_TYPE){
case SCREENMODE1: //720x400x2 colour
uint16_t *fcol=tilefcols+line/ytileheight*X_TILE, *bcol=tilebcols+line/ytileheight*X_TILE; //get the relevant tile
pp= line*vgaloop8;
dd=&DisplayBuf[pp];
ll=&LayerBuf[pp];
for(int i=0; i<vgaloop8 ; i++){
d=*dd | *ll;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
d>>=1;
*p++ = (d&0x1) ? fcol[i] : bcol[i];
ll++;dd++;
}
break;
case SCREENMODE2: //360x200x16 colour with support for a top layer
{
pp= (line)*vgaloop4;
uint32_t *up=(uint32_t *)p;
dd=&DisplayBuf[pp];
ll=&LayerBuf[pp];
volatile register unsigned char *ss=&SecondLayer[pp];
if(ss==dd){
ss=ll;
transparent16s=transparent16;
}
for(int i=0; i<vgaloop4 ; i++){
l=ll[i];d=dd[i];s=ss[i];
if((s&0xf)!=transparent16s){
*up++=map16pairs[s&0xf];
} else {
if((l&0xf)!=transparent16){
*up++=map16pairs[l&0xf];
} else {
*up++=map16pairs[d&0xf];
}
}
d>>=4;l>>=4;s>>=4;
if((s&0xf)!=transparent16s){
*up++=map16pairs[s&0xf];
} else {
if((l&0xf)!=transparent16){
*up++=map16pairs[l&0xf];
} else {
*up++=map16pairs[d&0xf];
}
}
}
}
break;
case SCREENMODE3: //720x400x16 colour
pp= line*vgaloop2;
for(int i=0;i<vgaloop2;i++){
d=DisplayBuf[pp+i];
l=LayerBuf[pp+i];
if((l&0xf)!=transparent16){
*p++=map16[l&0xf];
} else {
*p++=map16[d&0xf];
}
d>>=4;l>>=4;
if((l&0xf)!=transparent16){
*p++=map16[l&0xf];
} else {
*p++=map16[d&0xf];
}
}
break;
case SCREENMODE4: //360x200xRGB555 colour
pp=line*vgaloop1;
uint16_t* d=(uint16_t *)&DisplayBuf[pp];
uint16_t* l=(uint16_t *)&LayerBuf[pp];
for(int i=0; i<vgaloop2 ; i++){
if(*l!=RGBtransparent){
*p++=*l;
*p++=*l;
} else {
*p++=*d;
*p++=*d;
}
l++;d++;
}
break;
case SCREENMODE5: //360x200x256 colour
pp=line*vgaloop2;
dd=&DisplayBuf[pp];
ll=&LayerBuf[pp];
register unsigned char *ss=&SecondLayer[pp];
if(ss==dd){
ss=ll;
transparent16s=transparent16;
}
for(int i=0; i<vgaloop2 ; i++){
int d=dd[i];
int l=ll[i];
int s=ss[i];
if(s!=transparent16s){
*p++=map256[s];
*p++=map256[s];
} else {
if(l!=transparent16){
*p++=map256[l];
*p++=map256[l];
} else {
*p++=map256[d];
*p++=map256[d];
}
}
}
break;
default:
}
}
}
}
}
void HDMICore(void){
for(int i=0;i<256;i++)map256[i]=RGB555(MAP256DEF[i]);
for(int i=0;i<16;i++){
map16[i]=RGB555(MAP16DEF[i]);
map16pairs[i]=map16[i] | (map16[i]<<16);
map16d[i]=(RGB332(MAP16DEF[i])<<8) | RGB332(MAP16DEF[i]);
map16q[i]=(RGB332(MAP16DEF[i])<<24) | (RGB332(MAP16DEF[i])<<16) | (RGB332(MAP16DEF[i])<<8) | RGB332(MAP16DEF[i]);
map16s[i]=RGB332(MAP16DEF[i]);
}
if(Option.CPU_Speed==FreqXGA){
MODE_H_SYNC_POLARITY=MODE_H_L_SYNC_POLARITY;
MODE_ACTIVE_LINES=MODE_V_L_ACTIVE_LINES;
MODE_ACTIVE_PIXELS=MODE_H_L_ACTIVE_PIXELS;
MODE_V_TOTAL_LINES=MODE_V_L_TOTAL_LINES;
MODE_H_ACTIVE_PIXELS=MODE_H_L_ACTIVE_PIXELS;
MODE_H_FRONT_PORCH=MODE_H_L_FRONT_PORCH;
MODE_H_SYNC_WIDTH=MODE_H_L_SYNC_WIDTH;
MODE_H_BACK_PORCH=MODE_H_L_BACK_PORCH;
MODE_V_SYNC_POLARITY=MODE_V_L_SYNC_POLARITY;
MODE_V_ACTIVE_LINES=MODE_V_L_ACTIVE_LINES;
MODE_V_FRONT_PORCH=MODE_V_L_FRONT_PORCH;
MODE_V_SYNC_WIDTH=MODE_V_L_SYNC_WIDTH;
MODE_V_BACK_PORCH=MODE_V_L_BACK_PORCH;
MODE1SIZE=MODE1SIZE_L;
MODE2SIZE=MODE2SIZE_L;
MODE3SIZE=MODE3SIZE_L;
MODE4SIZE=0L;
MODE5SIZE=MODE5SIZE_L;
PIXELS_PER_WORD=4;
} else if(Option.CPU_Speed==Freq720P){
MODE_H_SYNC_POLARITY=MODE_H_W_SYNC_POLARITY;
MODE_ACTIVE_LINES=MODE_V_W_ACTIVE_LINES;
MODE_ACTIVE_PIXELS=MODE_H_W_ACTIVE_PIXELS;
MODE_V_TOTAL_LINES=MODE_V_W_TOTAL_LINES;
MODE_H_ACTIVE_PIXELS=MODE_H_W_ACTIVE_PIXELS;
MODE_H_FRONT_PORCH=MODE_H_W_FRONT_PORCH;
MODE_H_SYNC_WIDTH=MODE_H_W_SYNC_WIDTH;
MODE_H_BACK_PORCH=MODE_H_W_BACK_PORCH;
MODE_V_SYNC_POLARITY=MODE_V_W_SYNC_POLARITY;
MODE_V_ACTIVE_LINES=MODE_V_W_ACTIVE_LINES;
MODE_V_FRONT_PORCH=MODE_V_W_FRONT_PORCH;
MODE_V_SYNC_WIDTH=MODE_V_W_SYNC_WIDTH;
MODE_V_BACK_PORCH=MODE_V_W_BACK_PORCH;
MODE1SIZE=MODE1SIZE_W;
MODE2SIZE=MODE2SIZE_W;
MODE3SIZE=MODE3SIZE_W;
MODE4SIZE=0L;
MODE5SIZE=MODE5SIZE_W;
PIXELS_PER_WORD=4;
} else if(Option.CPU_Speed==FreqSVGA){
MODE_H_SYNC_POLARITY=MODE_H_V_SYNC_POLARITY;
MODE_ACTIVE_LINES=MODE_V_V_ACTIVE_LINES;
MODE_ACTIVE_PIXELS=MODE_H_V_ACTIVE_PIXELS;
MODE_V_TOTAL_LINES=MODE_V_V_TOTAL_LINES;
MODE_H_ACTIVE_PIXELS=MODE_H_V_ACTIVE_PIXELS;
MODE_H_FRONT_PORCH=MODE_H_V_FRONT_PORCH;
MODE_H_SYNC_WIDTH=MODE_H_V_SYNC_WIDTH;
MODE_H_BACK_PORCH=MODE_H_V_BACK_PORCH;
MODE_V_SYNC_POLARITY=MODE_V_V_SYNC_POLARITY;
MODE_V_ACTIVE_LINES=MODE_V_V_ACTIVE_LINES;
MODE_V_FRONT_PORCH=MODE_V_V_FRONT_PORCH;
MODE_V_SYNC_WIDTH=MODE_V_V_SYNC_WIDTH;
MODE_V_BACK_PORCH=MODE_V_V_BACK_PORCH;
MODE1SIZE=MODE1SIZE_V;
MODE2SIZE=MODE2SIZE_V;
MODE3SIZE=MODE3SIZE_V;
MODE5SIZE=MODE5SIZE_V;
PIXELS_PER_WORD=4;
} else if(Option.CPU_Speed==Freq848){
MODE_H_SYNC_POLARITY=MODE_H_8_SYNC_POLARITY;
MODE_ACTIVE_LINES=MODE_V_8_ACTIVE_LINES;
MODE_ACTIVE_PIXELS=MODE_H_8_ACTIVE_PIXELS;
MODE_V_TOTAL_LINES=MODE_V_8_TOTAL_LINES;
MODE_H_ACTIVE_PIXELS=MODE_H_8_ACTIVE_PIXELS;
MODE_H_FRONT_PORCH=MODE_H_8_FRONT_PORCH;
MODE_H_SYNC_WIDTH=MODE_H_8_SYNC_WIDTH;
MODE_H_BACK_PORCH=MODE_H_8_BACK_PORCH;
MODE_V_SYNC_POLARITY=MODE_V_8_SYNC_POLARITY;
MODE_V_ACTIVE_LINES=MODE_V_8_ACTIVE_LINES;
MODE_V_FRONT_PORCH=MODE_V_8_FRONT_PORCH;
MODE_V_SYNC_WIDTH=MODE_V_8_SYNC_WIDTH;
MODE_V_BACK_PORCH=MODE_V_8_BACK_PORCH;
MODE1SIZE=MODE1SIZE_8;
MODE2SIZE=MODE2SIZE_8;
MODE3SIZE=MODE3SIZE_8;
MODE5SIZE=MODE5SIZE_8;
PIXELS_PER_WORD=4;
} else if(Option.CPU_Speed==Freq400){
MODE_H_SYNC_POLARITY=MODE_H_4_SYNC_POLARITY;
MODE_ACTIVE_LINES=MODE_V_4_ACTIVE_LINES;
MODE_ACTIVE_PIXELS=MODE_H_4_ACTIVE_PIXELS;
MODE_V_TOTAL_LINES=MODE_V_4_TOTAL_LINES;
MODE_H_ACTIVE_PIXELS=MODE_H_4_ACTIVE_PIXELS;
MODE_H_FRONT_PORCH=MODE_H_4_FRONT_PORCH;
MODE_H_SYNC_WIDTH=MODE_H_4_SYNC_WIDTH;
MODE_H_BACK_PORCH=MODE_H_4_BACK_PORCH;
MODE_V_SYNC_POLARITY=MODE_V_4_SYNC_POLARITY;
MODE_V_ACTIVE_LINES=MODE_V_4_ACTIVE_LINES;
MODE_V_FRONT_PORCH=MODE_V_4_FRONT_PORCH;
MODE_V_SYNC_WIDTH=MODE_V_4_SYNC_WIDTH;
MODE_V_BACK_PORCH=MODE_V_4_BACK_PORCH;
MODE1SIZE=MODE1SIZE_4;
MODE2SIZE=MODE2SIZE_4;
MODE3SIZE=MODE3SIZE_4;
MODE4SIZE=MODE3SIZE_4;
MODE5SIZE=MODE5SIZE_4;
PIXELS_PER_WORD=2;
} else {
MODE_H_SYNC_POLARITY=MODE_H_S_SYNC_POLARITY;
MODE_ACTIVE_LINES=MODE_V_S_ACTIVE_LINES;
MODE_ACTIVE_PIXELS=MODE_H_S_ACTIVE_PIXELS;
MODE_V_TOTAL_LINES=MODE_V_S_TOTAL_LINES;
MODE_H_ACTIVE_PIXELS=MODE_H_S_ACTIVE_PIXELS;
MODE_H_FRONT_PORCH=MODE_H_S_FRONT_PORCH;
MODE_H_SYNC_WIDTH=MODE_H_S_SYNC_WIDTH;
MODE_H_BACK_PORCH=MODE_H_S_BACK_PORCH;
MODE_V_SYNC_POLARITY=MODE_V_S_SYNC_POLARITY;
MODE_V_ACTIVE_LINES=MODE_V_S_ACTIVE_LINES;
MODE_V_FRONT_PORCH=MODE_V_S_FRONT_PORCH;
MODE_V_SYNC_WIDTH=MODE_V_S_SYNC_WIDTH;
MODE_V_BACK_PORCH=MODE_V_S_BACK_PORCH;
MODE1SIZE=MODE1SIZE_S;
MODE2SIZE=MODE2SIZE_S;
MODE3SIZE=MODE3SIZE_S;
MODE4SIZE=MODE4SIZE_S;
MODE5SIZE=MODE5SIZE_S;
PIXELS_PER_WORD=2;
}
vgaloop1=MODE_H_ACTIVE_PIXELS;
vgaloop2=MODE_H_ACTIVE_PIXELS/2;
vgaloop4=MODE_H_ACTIVE_PIXELS/4;
vgaloop8=MODE_H_ACTIVE_PIXELS/8;
vgaloop16=MODE_H_ACTIVE_PIXELS/16;
vgaloop32=MODE_H_ACTIVE_PIXELS/32;
TRANSFER_COUNT=MODE_H_ACTIVE_PIXELS/PIXELS_PER_WORD;
BLANKING_COUNT=MODE_V_FRONT_PORCH + MODE_V_SYNC_WIDTH + MODE_V_BACK_PORCH;
vblank_line_vsync_off[0] = HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH;
vblank_line_vsync_off[1] = SYNC_V1_H1;
vblank_line_vsync_off[2] = HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH;
vblank_line_vsync_off[3] = SYNC_V1_H0;
vblank_line_vsync_off[4] = HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS);
vblank_line_vsync_off[5] = SYNC_V1_H1;
vblank_line_vsync_off[6] = HSTX_CMD_NOP;
vblank_line_vsync_on[0] = HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH;
vblank_line_vsync_on[1] = SYNC_V0_H1;
vblank_line_vsync_on[2] = HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH;
vblank_line_vsync_on[3] = SYNC_V0_H0,
vblank_line_vsync_on[4] = HSTX_CMD_RAW_REPEAT | (MODE_H_BACK_PORCH + MODE_H_ACTIVE_PIXELS);
vblank_line_vsync_on[5] = SYNC_V0_H1;
vblank_line_vsync_on[6] = HSTX_CMD_NOP;
vactive_line[0] = HSTX_CMD_RAW_REPEAT | MODE_H_FRONT_PORCH;
vactive_line[1] = SYNC_V1_H1;
vactive_line[2] = HSTX_CMD_NOP;
vactive_line[3] = HSTX_CMD_RAW_REPEAT | MODE_H_SYNC_WIDTH;
vactive_line[4] = SYNC_V1_H0;
vactive_line[5] = HSTX_CMD_NOP;
vactive_line[6] = HSTX_CMD_RAW_REPEAT | MODE_H_BACK_PORCH;
vactive_line[7] = SYNC_V1_H1;
vactive_line[8] = HSTX_CMD_TMDS | MODE_H_ACTIVE_PIXELS;
// Configure HSTX's TMDS encoder for RGB332
hstx_ctrl_hw->expand_tmds =
((FullColour) ?
(29 << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB |
4 << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB |
2 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB |
4 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB |
7 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB |
4 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB)
:
(2 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
0 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB |
2 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB |
29 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB |
1 << HSTX_CTRL_EXPAND_TMDS_L0_NBITS_LSB |
26 << HSTX_CTRL_EXPAND_TMDS_L0_ROT_LSB));
// Pixels (TMDS) come in 4 8-bit chunks. Control symbols (RAW) are an
// entire 32-bit word.
hstx_ctrl_hw->expand_shift =
((FullColour) ?
(2 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
16 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB |
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB)
:
(4 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
8 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB |
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB));
// Serial output config: clock period of 5 cycles, pop from command
// expander every 5 cycles, shift the output shiftreg by 2 every cycle.
hstx_ctrl_hw->csr = 0;
hstx_ctrl_hw->csr =
HSTX_CTRL_CSR_EXPAND_EN_BITS |
5u << HSTX_CTRL_CSR_CLKDIV_LSB |
5u << HSTX_CTRL_CSR_N_SHIFTS_LSB |
2u << HSTX_CTRL_CSR_SHIFT_LSB |
HSTX_CTRL_CSR_EN_BITS;
// Note we are leaving the HSTX clock at the SDK default of 125 MHz; since
// we shift out two bits per HSTX clock cycle, this gives us an output of
// 250 Mbps, which is very close to the bit clock for 480p 60Hz (252 MHz).
// If we want the exact rate then we'll have to reconfigure PLLs.
// HSTX outputs 0 through 7 appear on GPIO 12 through 19.
// Pinout on Pico DVI sock:
//
// GP12 D0+ GP13 D0-
// GP14 CK+ GP15 CK-
// GP16 D2+ GP17 D2-
// GP18 D1+ GP19 D1-
// Assign clock pair to two neighbouring pins:
if(Option.HDMIclock & 1){
hstx_ctrl_hw->bit[Option.HDMIclock] = HSTX_CTRL_BIT0_CLK_BITS;
hstx_ctrl_hw->bit[Option.HDMIclock-1] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS;
} else {
hstx_ctrl_hw->bit[Option.HDMIclock] = HSTX_CTRL_BIT0_CLK_BITS;
hstx_ctrl_hw->bit[Option.HDMIclock+1] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS;
}
int lane_to_output_bit[3];
lane_to_output_bit[0]=Option.HDMId0;
lane_to_output_bit[1]=Option.HDMId1;
lane_to_output_bit[2]=Option.HDMId2;
for (uint lane = 0; lane < 3; ++lane) {
// For each TMDS lane, assign it to the correct GPIO pair based on the
// desired pinout:
int bit = lane_to_output_bit[lane];
// Output even bits during first half of each HSTX cycle, and odd bits
// during second half. The shifter advances by two bits each cycle.
uint32_t lane_data_sel_bits =
(lane * 10 ) << HSTX_CTRL_BIT0_SEL_P_LSB |
(lane * 10 + 1) << HSTX_CTRL_BIT0_SEL_N_LSB;
// The two halves of each pair get identical data, but one pin is inverted.
if(bit & 1){
hstx_ctrl_hw->bit[bit ] = lane_data_sel_bits;
hstx_ctrl_hw->bit[bit - 1] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
} else {
hstx_ctrl_hw->bit[bit ] = lane_data_sel_bits;
hstx_ctrl_hw->bit[bit + 1] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
}
}
for (int i = 12; i <= 19; ++i) {
gpio_set_function(i, 0); // HSTX
gpio_set_drive_strength (i, GPIO_DRIVE_STRENGTH_8MA);
gpio_set_slew_rate(i,GPIO_SLEW_RATE_FAST);
gpio_set_input_enabled(i, false);
gpio_set_pulls(i,false,false);
gpio_set_input_hysteresis_enabled(i,false);
}
// Both channels are set up identically, to transfer a whole scanline and
// then chain to the opposite channel. Each time a channel finishes, we
// reconfigure the one that just finished, meanwhile the opposite channel
// is already making progress.
dma_channel_config c;
c = dma_channel_get_default_config(DMACH_PING);
channel_config_set_chain_to(&c, DMACH_PONG);
channel_config_set_dreq(&c, DREQ_HSTX);
dma_channel_configure(
DMACH_PING,
&c,
&hstx_fifo_hw->fifo,
vblank_line_vsync_off,
count_of(vblank_line_vsync_off),
false
);
c = dma_channel_get_default_config(DMACH_PONG);
channel_config_set_chain_to(&c, DMACH_PING);
channel_config_set_dreq(&c, DREQ_HSTX);
dma_channel_configure(
DMACH_PONG,
&c,
&hstx_fifo_hw->fifo,
vblank_line_vsync_off,
count_of(vblank_line_vsync_off),
false
);
dma_hw->ints0 = (1u << DMACH_PING) | (1u << DMACH_PONG);
dma_hw->inte0 = (1u << DMACH_PING) | (1u << DMACH_PONG);
irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler0);
irq_set_enabled(DMA_IRQ_0, true);
// bus_ctrl_hw->priority = 1;
dma_channel_start(DMACH_PING);
if(Option.CPU_Speed==Freq480P || Option.CPU_Speed==Freq378P || Option.CPU_Speed==Freq252P || Option.CPU_Speed==Freq400)HDMIloop0();
else if(Option.CPU_Speed==Freq720P)HDMIloop1();
else if(Option.CPU_Speed==FreqXGA)HDMIloop2();
else HDMIloop3();
}
void settiles(void){
if(DISPLAY_TYPE!=SCREENMODE1)return;
if(FullColour){
tilefcols=(uint16_t *)((uint32_t)FRAMEBUFFER+(MODE1SIZE*3));
tilebcols=(uint16_t *)((uint32_t)FRAMEBUFFER+(MODE1SIZE*3)+(MODE1SIZE>>1));
ytileheight=gui_font_height;
Y_TILE=VRes/ytileheight;
X_TILE=HRes/8;
if(VRes % ytileheight)Y_TILE++;
for(int x=0;x<X_TILE;x++){
for(int y=0;y<Y_TILE;y++){
tilefcols[y*X_TILE+x]=RGB555(gui_fcolour);
tilebcols[y*X_TILE+x]=RGB555(gui_bcolour);
}
}
} else {
tilefcols_w=(uint8_t *)DisplayBuf+MODE1SIZE;
tilebcols_w=tilefcols_w+(MODE_H_ACTIVE_PIXELS/8)*(MODE_V_ACTIVE_LINES/8); //minimum tilesize is 8x8
memset(tilefcols_w,RGB332(gui_fcolour),(MODE_H_ACTIVE_PIXELS/8)*(MODE_V_ACTIVE_LINES/8)*sizeof(uint8_t));
memset(tilebcols_w,RGB332(gui_bcolour),(MODE_H_ACTIVE_PIXELS/8)*(MODE_V_ACTIVE_LINES/8)*sizeof(uint8_t));
ytileheight=(MediumRes? 12:24);
X_TILE=MODE_H_ACTIVE_PIXELS/8;Y_TILE=MODE_V_ACTIVE_LINES/ytileheight;
}
}
#endif
#else
#ifdef PICOMITE
#include "pico/multicore.h"
void __not_in_flash_func(UpdateCore)()
{
systick_hw->csr = 0x5;
systick_hw->rvr = 0x00FFFFFF;
while(multicore_fifo_rvalid()) {
multicore_fifo_pop_blocking();
}
while (true)
{
// data memory barrier
__dmb();
if (multicore_fifo_rvalid()) {
int command=multicore_fifo_pop_blocking();
if(command==3){
uint8_t colour=(uint8_t)multicore_fifo_pop_blocking();
uint32_t timer=(uint32_t)multicore_fifo_pop_blocking();
uint64_t delaytime=0;
if(timer)delaytime=time_us_64()+timer;
mergerunning=true;
while(1){
if (multicore_fifo_rvalid()){
int a;
if(((a=multicore_fifo_pop_blocking())==0xff)){
mergerunning=false;
break;
}
}
if(timer){
busy_wait_until(delaytime);
delaytime=time_us_64()+timer;
}
merge(colour);
}
} else if(command==2){
uint8_t colour=(uint8_t)multicore_fifo_pop_blocking();
merge(colour);
} else if(command==4){
int x1=multicore_fifo_pop_blocking();
int y1=multicore_fifo_pop_blocking();
int w=multicore_fifo_pop_blocking();
int h=multicore_fifo_pop_blocking();
uint8_t colour=(uint8_t)multicore_fifo_pop_blocking();
blitmerge(x1,y1,w,h,colour);
} else if(command==5){
int x1=multicore_fifo_pop_blocking();
int y1=multicore_fifo_pop_blocking();
int w=multicore_fifo_pop_blocking();
int h=multicore_fifo_pop_blocking();
uint8_t colour=(uint8_t)multicore_fifo_pop_blocking();
uint32_t timer=(uint32_t)multicore_fifo_pop_blocking();
uint64_t delaytime=0;
if(timer)delaytime=time_us_64()+timer;
mergerunning=true;
while(1){
if (multicore_fifo_rvalid()){
int a;
if(((a=multicore_fifo_pop_blocking())==0xff)){
mergerunning=false;
break;
}
}
if(timer){
busy_wait_until(delaytime);
delaytime=time_us_64()+timer;
}
blitmerge(x1,y1,w,h,colour);
}
} else if(command==1){
uint8_t *s=(uint8_t *)multicore_fifo_pop_blocking();
mutex_enter_blocking(&frameBufferMutex); // lock the frame buffer
copyframetoscreen(s,0,HRes-1,0,VRes-1,0);
mutex_exit(&frameBufferMutex);
}
}
}
}
uint32_t core1stack[512];
#endif
#endif
#ifndef rp2350
void __no_inline_not_in_flash_func(modclock)(uint16_t speed){
ssi_hw->ssienr=0;
ssi_hw->baudr=0;
ssi_hw->baudr=speed;
ssi_hw->ssienr=1;
}
#else
#ifndef PICOMITEWEB
uint32_t testPSRAM(void){
uint32_t *p=(uint32_t *)PSRAMbase;
uint32_t *q=(uint32_t *)PSRAMbase;
for(int i=0;i<65536;i++)*p++=i;
__dmb();
for(int i=0;i<65536;i++)if(*q++!=i) return 0;
p=(uint32_t *)PSRAMbase;
q=(uint32_t *)PSRAMbase;
p[8*1024*1024/4-1]=0x12345678;
__dmb();
if(q[8*1024*1024/4-1]==0x12345678)return 6*1024*1024;
else return 0;
}
#endif
#endif
lfs_t lfs;
lfs_dir_t lfs_dir;
struct lfs_info lfs_info;
void MIPS16 updatebootcount(void){
lfs_file_t lfs_file;
pico_lfs_cfg.block_count = (Option.FlashSize-RoundUpK4(TOP_OF_SYSTEM_FLASH)-(Option.modbuff ? 1024*Option.modbuffsize : 0))/4096;
int err,boot_count=0;
err= lfs_mount(&lfs, &pico_lfs_cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
err=lfs_format(&lfs, &pico_lfs_cfg);
err=lfs_mount(&lfs, &pico_lfs_cfg);
}
err=lfs_file_open(&lfs, &lfs_file, "bootcount", LFS_O_RDWR | LFS_O_CREAT);;
int dt=get_fattime();
err=lfs_setattr(&lfs, "bootcount", 'A', &dt, 4);
err=lfs_file_read(&lfs, &lfs_file, &boot_count, sizeof(boot_count));;
boot_count+=1;
err=lfs_file_rewind(&lfs, &lfs_file);
err=lfs_file_write(&lfs, &lfs_file, &boot_count, sizeof(boot_count));
err=lfs_file_close(&lfs, &lfs_file);
}
/**
* @brief Transforms input beginning with * into a corresponding RUN command.
*
* e.g.
* *foo => RUN "foo"
* *"foo bar" => RUN "foo bar"
* *foo --wombat => RUN "foo", "--wombat"
* *foo "wom" => RUN "foo", Chr$(34) + "wom" + Chr$(34)
* *foo "wom" "bat" => RUN "foo", Chr$(34) + "wom" + Chr$(34) + " " + Chr$(34) + "bat" + Chr$(34)
* *foo --wom="bat" => RUN "foo", "--wom=" + Chr$(34) + "bat" + Chr$(34)
*/
static void MIPS16 transform_star_command(char *input) {
char *src = input;
while (isspace((uint8_t)*src)) src++; // Skip leading whitespace.
if (*src != '*') error("Internal fault");
src++;
// Trim any trailing whitespace from the input.
char *end = input + strlen(input) - 1;
while (isspace((uint8_t)*end)) *end-- = '\0';
// Allocate extra space to avoid string overrun.
char *tmp = (char *) GetTempMemory(STRINGSIZE + 32);
strcpy(tmp, "RUN");
char *dst = tmp + 3;
if (*src == '"') {
// Everything before the second quote is the name of the file to RUN.
*dst++ = ' ';
*dst++ = *src++; // Leading quote.
while (*src && *src != '"') *dst++ = *src++;
if (*src == '"') *dst++ = *src++; // Trailing quote.
} else {
// Everything before the first space is the name of the file to RUN.
int count = 0;
while (*src && !isspace((uint8_t)*src)) {
if (++count == 1) {
*dst++ = ' ';
*dst++ = '\"';
}
*dst++ = *src++;
}
if (count) *dst++ = '\"';
}
while (isspace((uint8_t)*src)) src++; // Skip whitespace.
// Anything else is arguments.
if (*src) {
*dst++ = ',';
*dst++ = ' ';
// If 'src' starts with double-quote then replace with: Chr$(34) +
if (*src == '"') {
memcpy(dst, "Chr$(34) + ", 11);
dst += 11;
src++;
}
*dst++ = '\"';
// Copy from 'src' to 'dst'.
while (*src) {
if (*src == '"') {
// Close current set of quotes to insert a Chr$(34)
memcpy(dst, "\" + Chr$(34)", 12);
dst += 12;
// Open another set of quotes unless this was the last character.
if (*(src + 1)) {
memcpy(dst, " + \"", 4);
dst += 4;
}
src++;
} else {
*dst++ = *src++;
}
if (dst - tmp >= STRINGSIZE) error("String too long");
}
// End with a double quote unless 'src' ended with one.
if (*(src - 1) != '"') *dst++ = '\"';
*dst = '\0';
}
if (dst - tmp >= STRINGSIZE) error("String too long");
// Copy transformed string back into the input buffer.
memcpy(input, tmp, STRINGSIZE);
input[STRINGSIZE - 1] = '\0';
ClearSpecificTempMemory(tmp);
}
#ifdef PICOMITEWEB
void WebConnect(void){
if(*Option.SSID){
if(*Option.ipaddress){
cyw43_arch_enable_sta_mode();
dhcp_stop(cyw43_state.netif);
ip4_addr_t ipaddr, gateway, mask;
ip4addr_aton(Option.ipaddress, &ipaddr);
ip4addr_aton(Option.gateway, &gateway);
ip4addr_aton(Option.mask, &mask);
netif_set_addr( cyw43_state.netif,&ipaddr,&mask,&gateway);
} else cyw43_arch_enable_sta_mode();
if(*Option.hostname){
MMPrintString(Option.hostname);
netif_set_hostname(cyw43_state.netif, Option.hostname);
}
cyw43_wifi_pm(&cyw43_state, CYW43_NO_POWERSAVE_MODE);
MMPrintString(" connecting to WiFi...\r\n");
if (cyw43_arch_wifi_connect_timeout_ms((char *)Option.SSID, (char *)(*Option.PASSWORD ? Option.PASSWORD : NULL), (*Option.PASSWORD ? CYW43_AUTH_WPA2_AES_PSK : CYW43_AUTH_OPEN), 30000)) {
MMPrintString("failed to connect.\r\n");
WIFIconnected=0;
} else {
char buff[STRINGSIZE]={0};
sprintf(buff,"Connected %s\r\n",ip4addr_ntoa(netif_ip4_addr(netif_list)));
MMPrintString(buff);
WIFIconnected=1;
open_tcp_server();
if(!Option.disabletftp)cmd_tftp_server_init();
if(Option.UDP_PORT)open_udp_server();
}
} else {
cyw43_arch_enable_sta_mode();
cyw43_wifi_pm(&cyw43_state, CYW43_NO_POWERSAVE_MODE);
}
cyw43_wifi_pm(&cyw43_state, CYW43_DEFAULT_PM & ~0xf);
}
#endif
int MIPS16 main(){
static int ErrorInPrompt;
int i=0;
char savewatchdog=false;
i=watchdog_caused_reboot();
#ifdef rp2350
restart_reason=powman_hw->chip_reset | i;
rp2350a=(*((io_ro_32*)(SYSINFO_BASE + SYSINFO_PACKAGE_SEL_OFFSET)) & 1);
#else
restart_reason=vreg_and_chip_reset_hw->chip_reset | i;
#endif
if(_excep_code == SOFT_RESET || _excep_code == SCREWUP_TIMEOUT )restart_reason=0xFFFFFFFF;
if((_excep_code == WATCHDOG_TIMEOUT) & i) restart_reason=0xFFFFFFFE;
if((_excep_code == POSSIBLE_WATCHDOG) & i)restart_reason=0xFFFFFFFD;
LoadOptions();
#ifdef rp2350
if(rom_get_last_boot_type()==BOOT_TYPE_FLASH_UPDATE)restart_reason=0xFFFFFFFC;
#else
if(restart_reason==0x10001 || restart_reason==0x101)restart_reason=0xFFFFFFFC;
#endif
uint32_t excep=_excep_code;
if( Option.Baudrate == 0 ||
!(Option.Tab==2 || Option.Tab==3 || Option.Tab==4 ||Option.Tab==8) ||
!(Option.Autorun>=0 && Option.Autorun<=MAXFLASHSLOTS+1) ||
Option.CPU_Speed<MIN_CPU || Option.CPU_Speed>MAX_CPU ||
Option.PROG_FLASH_SIZE!=MAX_PROG_SIZE ||
(Option.heartbeatpin==0 && Option.NoHeartbeat==0) ||
!(Option.Magic==MagicKey)
){
ResetAllFlash(); // init the options if this is the very first startup
_excep_code=0;
watchdog_enable(1, 1);
while(1);
}
#ifndef HDMI
if(Option.VGA_HSYNC==0){
Option.VGA_HSYNC=21;
Option.VGA_BLUE=24;
SaveOptions();
}
#else
if(!(Option.CPU_Speed==Freq720P || Option.CPU_Speed==Freq378P || Option.CPU_Speed==Freq252P || Option.CPU_Speed==Freq848 || Option.CPU_Speed==Freq400 || Option.CPU_Speed==FreqSVGA || Option.CPU_Speed==Freq480P|| Option.CPU_Speed==FreqXGA )){
Option.CPU_Speed=Freq480P;
SaveOptions();
}
#endif
m_alloc(M_PROG); // init the variables for program memory
LibMemory = (uint8_t *)flash_libmemory;
uSec(100);
if(_excep_code == RESET_CLOCKSPEED) {
#ifdef PICOMITEVGA
#ifdef HDMI
Option.CPU_Speed=Freq480P; // init the options if this is the very first startup
#else
Option.CPU_Speed=Freq252P; // init the options if this is the very first startup
#endif
#else
Option.CPU_Speed=200000; // init the options if this is the very first startup
#endif
SaveOptions();
_excep_code=INVALID_CLOCKSPEED;
watchdog_enable(1, 1);
while(1);
} else {
_excep_code=RESET_CLOCKSPEED;
watchdog_enable(1000, 1);
}
#ifdef rp2350
if(!rp2350a){
if(!Option.AllPins){
Option.AllPins=true;
SaveOptions();
}
}
#endif
vreg_disable_voltage_limit ();
#ifdef rp2350
// volatile uint32_t *qmi_m0_timing=(uint32_t *)0x400d000c;
// volatile uint32_t *qmi_m1_timing=(uint32_t *)0x400d0020;
#endif
if(Option.CPU_Speed<=200000)vreg_set_voltage(VREG_VOLTAGE_1_15);
// else if(Option.CPU_Speed>200000 && Option.CPU_Speed<=300000 )vreg_set_voltage(VREG_VOLTAGE_1_25); // Std default @ boot is 1_10
else if(Option.CPU_Speed>200000 && Option.CPU_Speed<=320000 )vreg_set_voltage(VREG_VOLTAGE_1_30); // Std default @ boot is 1_10
#ifdef rp2350
else if(Option.CPU_Speed>320000 && Option.CPU_Speed<=360000 )vreg_set_voltage(VREG_VOLTAGE_1_40); // Std default @ boot is 1_10
else vreg_set_voltage(VREG_VOLTAGE_1_60); // Std default @ boot is 1_10
#else
else vreg_set_voltage(VREG_VOLTAGE_1_30);
#endif
sleep_ms(10);
#ifdef rp2350
#define QMI_COOLDOWN 30 // 0xc0000000 [31:30] COOLDOWN (0x1) Chip select cooldown period
#define QMI_PAGEBREAK 28 // 0x30000000 [29:28] PAGEBREAK (0x0) When page break is enabled, chip select will...
#define QMI_SELECT_SETUP 25 // 0x02000000 [25] SELECT_SETUP (0) Add up to one additional system clock cycle of setup...
#define QMI_SELECT_HOLD 23 // 0x01800000 [24:23] SELECT_HOLD (0x0) Add up to three additional system clock cycles of active...
#define QMI_MAX_SELECT 17 // 0x007e0000 [22:17] MAX_SELECT (0x00) Enforce a maximum assertion duration for this window's...
#define QMI_MIN_DESELECT 12 // 0x0001f000 [16:12] MIN_DESELECT (0x00) After this window's chip select is deasserted, it...
#define QMI_RXDELAY 8 // 0x00000700 [10:8] RXDELAY (0x0) Delay the read data sample timing, in units of one half...
#define QMI_CLKDIV 0 // 0x000000ff [7:0] CLKDIV (0x04) Clock divisor
pads_qspi_hw->io[0]=0x67;
pads_qspi_hw->io[1]=0x67;
pads_qspi_hw->io[2]=0x67;
pads_qspi_hw->io[3]=0x6B;
pads_qspi_hw->io[4]=0x6B;
pads_qspi_hw->io[5]=0x6B;
qmi_hw->m[1].timing = (1<<QMI_COOLDOWN) | (2<<QMI_PAGEBREAK) | (3<<QMI_SELECT_HOLD) | (18<<QMI_MAX_SELECT) | (4<<QMI_MIN_DESELECT) | (6<<QMI_RXDELAY) | (5<<QMI_CLKDIV);
if(Option.CPU_Speed<=324000)qmi_hw->m[1].timing = (1<<QMI_COOLDOWN) | (2<<QMI_PAGEBREAK) | (3<<QMI_SELECT_HOLD) | (18<<QMI_MAX_SELECT) | (4<<QMI_MIN_DESELECT) | (4<<QMI_RXDELAY) | (4<<QMI_CLKDIV);
if(Option.CPU_Speed<=288000)qmi_hw->m[0].timing = 0x40006202;
if(Option.CPU_Speed<=150000)qmi_hw->m[1].timing = 0x60006102;
sleep_ms(2);
#endif
set_sys_clock_khz(Option.CPU_Speed, false);
#ifdef rp2350
qmi_hw->m[1].timing = (1<<QMI_COOLDOWN) | (2<<QMI_PAGEBREAK) | (3<<QMI_SELECT_HOLD) | (18<<QMI_MAX_SELECT) | (4<<QMI_MIN_DESELECT) | (6<<QMI_RXDELAY) | (5<<QMI_CLKDIV);
if(Option.CPU_Speed<=324000)qmi_hw->m[1].timing = (1<<QMI_COOLDOWN) | (2<<QMI_PAGEBREAK) | (3<<QMI_SELECT_HOLD) | (18<<QMI_MAX_SELECT) | (4<<QMI_MIN_DESELECT) | (4<<QMI_RXDELAY) | (4<<QMI_CLKDIV);
if(Option.CPU_Speed<=288000)qmi_hw->m[0].timing = 0x40006202;
if(Option.CPU_Speed<=150000)qmi_hw->m[1].timing = 0x60006102;
sleep_ms(2);
#endif
PWM_FREQ=44100;
pico_get_unique_board_id_string (id_out,12);
#ifdef rp2350
#ifndef PICOMITEWEB
if(Option.PSRAM_CS_PIN){
gpio_set_function(PinDef[Option.PSRAM_CS_PIN].GPno, GPIO_FUNC_XIP_CS1); // CS for PSRAM
xip_ctrl_hw->ctrl|=XIP_CTRL_WRITABLE_M1_BITS;
if(!(PSRAMsize=testPSRAM())){
Option.PSRAM_CS_PIN=0;
SaveOptions();
}
}
#endif
#endif
if(clock_get_hz(clk_usb)!=48000000){
ResetAllFlash(); // init the options if this is the very first startup
_excep_code=INVALID_CLOCKSPEED;
watchdog_enable(1, 1);
while(1);
}
clock_configure(
clk_adc,
0, // No glitchless mux
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
Option.CPU_Speed * 1000, // Input frequency
ADC_CLK_SPEED // Output (must be same as no divider)
);
SetADCFreq(500000);
adc_clk_div=adc_hw->div;
systick_hw->csr = 0x5;
systick_hw->rvr = 0x00FFFFFF;
#ifdef PICOMITE
mutex_init( &frameBufferMutex ); // create a mutex to lock frame buffer
#endif
#ifndef rp2350
if(Option.CPU_Speed<=200000)modclock(2);
#else
#ifdef HDMI
if(FullColour || MediumRes){
clock_configure(
clk_hstx,
0, // No glitchless mux
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
Option.CPU_Speed * 1000, // Input frequency
Option.CPU_Speed * (Option.CPU_Speed==Freq378P ? 332:500) // Output (must be same as no divider)
);
}
if(Option.CPU_Speed==FreqSVGA){ //adjust the size of the heap
framebuffersize=400*300*2;
heap_memory_size=HEAP_MEMORY_SIZE-framebuffersize+320*240*2;
FRAMEBUFFER=AllMemory+heap_memory_size+256;
}
if(Option.CPU_Speed==Freq848){ //adjust the size of the heap
framebuffersize=424*240*2;
heap_memory_size=HEAP_MEMORY_SIZE-framebuffersize+320*240*2;
FRAMEBUFFER=AllMemory+heap_memory_size+256;
}
#endif
#endif
uSec(100);
hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
_excep_code=excep;
#ifdef PICOMITEVGA
#ifndef HDMI
if(Option.CPU_Speed == Freq252P || Option.CPU_Speed == Freq480P || Option.CPU_Speed == Freq848 || Option.CPU_Speed == Freq400 || Option.CPU_Speed == FreqSVGA )QVGA_CLKDIV= 2;
else if(Option.CPU_Speed == 378000)QVGA_CLKDIV= 3;
else QVGA_CLKDIV= 1;
#ifdef rp2350
if(Option.CPU_Speed==Freq848){ //adjust the size of the heap
framebuffersize=424*240*2;
heap_memory_size=HEAP_MEMORY_SIZE-framebuffersize+320*240*2;
FRAMEBUFFER=AllMemory+heap_memory_size+256;
MODE1SIZE=MODE1SIZE_8;
MODE2SIZE=MODE2SIZE_8;
MODE2SIZE=MODE2SIZE_8;
MODE2SIZE=MODE2SIZE_8;
MODE2SIZE=MODE2SIZE_8;
HRes=848;
}
if(Option.CPU_Speed==FreqSVGA){ //adjust the size of the heap
framebuffersize=400*300*2;
heap_memory_size=HEAP_MEMORY_SIZE-framebuffersize+320*240*2;
FRAMEBUFFER=AllMemory+heap_memory_size+256;
MODE1SIZE=MODE1SIZE_V;
MODE2SIZE=MODE2SIZE_V;
MODE3SIZE=MODE3SIZE_V;
MODE5SIZE=MODE5SIZE_V;
HRes=800;
VRes=600;
}
#endif
#endif
#endif
systick_hw->csr = 0x5;
systick_hw->rvr = 0x00FFFFFF;
ticks_per_second = Option.CPU_Speed*1000;
// The serial clock won't vary from this point onward, so we can configure
// the UART etc.
#ifndef USBKEYBOARD
stdio_set_translate_crlf(&stdio_usb, false);
#endif
LoadOptions();
stdio_init_all();
adc_init();
adc_set_temp_sensor_enabled(true);
mSecTimer=time_us_64()/1000;
add_repeating_timer_us(-1000, timer_callback, NULL, &timer);
InitReservedIO();
ClearExternalIO();
ConsoleRxBufHead = 0;
ConsoleRxBufTail = 0;
ConsoleTxBufHead = 0;
ConsoleTxBufTail = 0;
PromptFC=gui_fcolour=Option.DefaultFC;
PromptBC=gui_bcolour=Option.DefaultBC;
InitHeap(true); // initilise memory allocation
uSecFunc(1000);
disable_interrupts_pico();
enable_interrupts_pico();
mSecTimer=time_us_64()/1000;
DISPLAY_TYPE = Option.DISPLAY_TYPE;
// negative timeout means exact delay (rather than delay between callbacks)
OptionErrorSkip = false;
#ifndef USBKEYBOARD
if(!(Option.SerialConsole==1 || Option.SerialConsole==2) || Option.Telnet==-1) {
uint64_t t=time_us_64();
while(1){
if(tud_cdc_connected())break;
if(time_us_64()-t>5000000)break;
}
}
initKeyboard();
#endif
InitBasic();
#ifndef PICOMITEVGA
#ifndef PICOCALC
InitDisplaySSD();
#endif
InitDisplaySPI(0);
#ifndef PICOCALC
InitDisplayI2C(0);
InitDisplayVirtual();
#endif
InitTouch();
#ifndef PICOCALC
if(Option.BackLightLevel)setBacklight(Option.BackLightLevel, 0);
#else
uSec(300000);
if(Option.BackLightLevel)setBacklight(Option.BackLightLevel);
#endif
#endif
ErrorInPrompt = false;
exception_set_exclusive_handler(HARDFAULT_EXCEPTION,sigbus);
exception_set_exclusive_handler(SVCALL_EXCEPTION,sigbus);
exception_set_exclusive_handler(PENDSV_EXCEPTION,sigbus);
exception_set_exclusive_handler(NMI_EXCEPTION ,sigbus);
exception_set_exclusive_handler(SYSTICK_EXCEPTION,sigbus);
while((i=getConsole())!=-1){}
#ifdef PICOMITEVGA
// bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;
#ifdef HDMI
// bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS | BUSCTRL_BUS_PRIORITY_PROC1_BITS;
multicore_launch_core1_with_stack(HDMICore,core1stack,512);
core1stack[0]=0x12345678;
uSec(1000);
#else
#ifdef rp2350
piomap[QVGA_PIO_NUM]=(uint64_t)((uint64_t)1<<(uint64_t)PinDef[Option.VGA_BLUE].GPno);
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)(PinDef[Option.VGA_BLUE].GPno+1));
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)(PinDef[Option.VGA_BLUE].GPno+2));
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)(PinDef[Option.VGA_BLUE].GPno+3));
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)PinDef[Option.VGA_HSYNC].GPno);
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)(PinDef[Option.VGA_HSYNC].GPno+1));
if(Option.audio_i2s_bclk){
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)PinDef[Option.audio_i2s_data].GPno);
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)PinDef[Option.audio_i2s_bclk].GPno);
piomap[QVGA_PIO_NUM]|=(uint64_t)((uint64_t)1<<(uint64_t)(PinDef[Option.audio_i2s_bclk].GPno+1));
}
#endif
X_TILE=Option.X_TILE;
Y_TILE=Option.Y_TILE;
ytileheight=(X_TILE==80 || X_TILE==106)? 12 : 16;
bus_ctrl_hw->priority=0x100;
multicore_launch_core1_with_stack(QVgaCore,core1stack,512);
core1stack[0]=0x12345678;
memset((void *)WriteBuf, 0, 38400);
#endif
ResetDisplay();
ClearScreen(Option.DefaultBC);
#else
#ifdef PICOMITE
bus_ctrl_hw->priority=0x100;
multicore_launch_core1_with_stack(UpdateCore,core1stack,2048);
core1stack[0]=0x12345678;
#endif
#endif
strcpy((char *)banner,MES_SIGNON);
#ifdef rp2350
#ifdef PICOMITEVGA
#ifdef HDMI
#ifdef USBKEYBOARD
banner[32]=(rp2350a?'A':'B');
#else
banner[28]=(rp2350a?'A':'B');
#endif
#else
#ifdef USBKEYBOARD
banner[31]=(rp2350a?'A':'B');
#else
banner[27]=(rp2350a?'A':'B');
#endif
#endif
#else
#ifdef USBKEYBOARD
banner[28]=(rp2350a?'A':'B');
#else
#ifdef PICOMITEWEB
banner[23]=(rp2350a?'A':'B');
#else
banner[24]=(rp2350a?'A':'B');
#endif
#endif
#endif
#endif
if(!(_excep_code == RESTART_NOAUTORUN || _excep_code == INVALID_CLOCKSPEED || _excep_code == SCREWUP_TIMEOUT || _excep_code == WATCHDOG_TIMEOUT || (_excep_code==POSSIBLE_WATCHDOG && watchdog_caused_reboot()))){
if(Option.Autorun==0 ){
if(!(_excep_code == RESET_COMMAND || _excep_code == SOFT_RESET)){
MMPrintString((char *)banner); // print sign on message
MMPrintString((char *)COPYRIGHT); // print sign on message
}
} else {
if(Option.Autorun!=MAXFLASHSLOTS+1){
ProgMemory=(unsigned char *)(flash_target_contents+(Option.Autorun-1)*MAX_PROG_SIZE);
}
if(*ProgMemory != 0x01 ) {
MMPrintString((char *)banner);
MMPrintString((char *)COPYRIGHT); // print sign on message
}
}
}
memset(inpbuf,0,STRINGSIZE);
WatchdogSet = false;
if(_excep_code == INVALID_CLOCKSPEED) {
MMPrintString("\r\nInvalid clock speed - reset to default\r\n");
restart_reason=0xFFFFFFFF;
}
if(_excep_code == SCREWUP_TIMEOUT) {
MMPrintString("\r\nCommand timeout\r\n");
restart_reason=0xFFFFFFFF;
}
if(restart_reason==0xFFFFFFFE) {
WatchdogSet = true; // remember if it was a watchdog timeout
MMPrintString("\r\nMMBasic Watchdog timeout\r\n");
}
if(restart_reason==0xFFFFFFFD){
MMPrintString("\r\nHW Watchdog timeout\r\n");
WatchdogSet = true; // remember if it was a watchdog timeout
_excep_code=0;
}
if(restart_reason==0xFFFFFFFC) {
WatchdogSet = true; // remember if it was a watchdog timeout
MMPrintString("\rFirmware updated\r\n");
}
savewatchdog=WatchdogSet;
if(noRTC){
noRTC=0;
Option.RTC=0;
SaveOptions();
MMPrintString("RTC not found, OPTION RTC AUTO disabled\r\n");
}
if(noI2C){
noI2C=0;
Option.KeyboardConfig=NO_KEYBOARD;
SaveOptions();
MMPrintString("I2C Keyboard not found, OPTION KEYBOARD disabled\r\n");
}
updatebootcount();
*tknbuf = 0;
ContinuePoint = nextstmt; // in case the user wants to use the continue command
#ifdef USBKEYBOARD
clearrepeat();
for(int i=0;i<4;i++){
memset((void *)&HID[i],0,sizeof(struct s_HID));
HID[i].report_requested=true;
}
// USB_bus_reset();
hcd_port_reset(BOARD_TUH_RHPORT);
uSec(10000); //wait for any hub to power up
hcd_port_reset_end(BOARD_TUH_RHPORT);
tuh_init(BOARD_TUH_RHPORT);
USBenabled=true;
#else
initMouse0(0);
#endif
#ifdef rp2350
if(PSRAMsize){MMPrintString("Total of ");PInt(PSRAMsize/(1024*1024));MMPrintString(" Mbytes PSRAM available\r\n");}
#if defined(PICOMITEVGA) && !defined(HMDI)
start_i2s(QVGA_PIO_NUM,1);
#else
start_i2s(2,1);
#endif
#else
start_i2s(QVGA_PIO_NUM,1);
#endif
if(setjmp(mark) != 0) {
// we got here via a long jump which means an error or CTRL-C or the program wants to exit to the command prompt
FlashLoad = 0;
// LoadOptions();
#ifdef USBKEYBOARD
clearrepeat();
#endif
ScrewUpTimer = 0;
ProgMemory=(uint8_t *)flash_progmemory;
ContinuePoint = nextstmt; // in case the user wants to use the continue command
*tknbuf = 0; // we do not want to run whatever is in the token buffer
optionangle=1.0;
useoptionangle=false;
savewatchdog = WatchdogSet = false;
char *ptr = findvar((unsigned char *)"MM.ENDLINE$", V_NOFIND_NULL);
if(ptr && *ptr){
CurrentLinePtr=0;
memcpy(inpbuf,ptr,*ptr+1);
*ptr=0;
MtoC(inpbuf);
*ptr=0;
tokenise(true);
goto autorun;
}
} else {
if(*ProgMemory == 0x01 ) ClearVars(0,true);
else {
ClearProgram(true);
}
#ifdef PICOMITEWEB
if (cyw43_arch_init()==0) {
startupcomplete=1;
WebConnect();
}
#endif
#ifdef PICOMITE
SPIatRisk=((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel) && Option.SD_CLK_PIN==0);
#endif
PrepareProgram(true);
if(FindSubFun((unsigned char *)"MM.STARTUP", 0) >= 0) {
ExecuteProgram((unsigned char *)"MM.STARTUP\0");
memset(inpbuf,0,STRINGSIZE);
}
if(Option.Autorun && _excep_code != RESTART_DOAUTORUN) {
ClearRuntime(true);
PrepareProgram(true);
if(*ProgMemory == 0x01 ){
memset(tknbuf,0,STRINGSIZE);
unsigned short tkn=GetCommandValue((unsigned char *)"RUN");
tknbuf[0] = (tkn & 0x7f ) + C_BASETOKEN;
tknbuf[1] = (tkn >> 7) + C_BASETOKEN; //tokens can be 14-bit
goto autorun;
} else {
Option.Autorun=0;
SaveOptions();
}
}
}
while(1) {
if(Option.DISPLAY_CONSOLE) {
SetFont(PromptFont);
gui_fcolour = PromptFC;
gui_bcolour = PromptBC;
if(CurrentX != 0) MMPrintString("\r\n"); // prompt should be on a new line
}
MMAbort = false;
BreakKey = BREAK_KEY;
EchoOption = true;
g_LocalIndex = 0; // this should not be needed but it ensures that all space will be cleared
ClearTempMemory(); // clear temp string space (might have been used by the prompt)
CurrentLinePtr = NULL; // do not use the line number in error reporting
if(MMCharPos > 1) MMPrintString("\r\n"); // prompt should be on a new line
while(Option.PIN && !IgnorePIN) {
_excep_code = PIN_RESTART;
if(Option.PIN == 99999999) // 99999999 is permanent lockdown
MMPrintString("Console locked, press enter to restart: ");
else
MMPrintString("Enter PIN or 0 to restart: ");
MMgetline(0, (char *)inpbuf);
if(Option.PIN == 99999999) SoftReset();
if(*inpbuf != 0) {
uSec(3000000);
i = atoi((char *)inpbuf);
if(i == 0) SoftReset();
if(i == Option.PIN) {
IgnorePIN = true;
break;
}
}
}
if(_excep_code!=POSSIBLE_WATCHDOG)_excep_code = 0;
PrepareProgram(false);
if(!ErrorInPrompt && FindSubFun((unsigned char *)"MM.PROMPT", 0) >= 0) {
ErrorInPrompt = true;
ExecuteProgram((unsigned char *)"MM.PROMPT\0");
MMPromptPos=MMCharPos-1; //Save length of prompt
} else{
MMPrintString("> "); // print the prompt
MMPromptPos=2; //Save length of prompt
}
ErrorInPrompt = false;
EditInputLine();
//InsertLastcmd(inpbuf); // save in case we want to edit it later
if(!*inpbuf) continue; // ignore an empty line
char *p=(char *)inpbuf;
skipspace(p);
// executelocal(p);
if(strlen(p)==2 && p[1]==':'){
if(toupper(*p)=='A')strcpy(p,"drive \"a:\"");
if(toupper(*p)=='B')strcpy(p,"drive \"b:\"");
}
if(*p=='*' && p[1]!='('){ //shortform RUN command so convert to a normal version
transform_star_command((char *)inpbuf);
p = (char *)inpbuf;
}
multi=false;
tokenise(true); // turn into executable code
autorun:
i=0;
WatchdogSet=savewatchdog;
CommandToken tkn=commandtbl_decode(tknbuf);
if(tkn==GetCommandValue((unsigned char *)"RUN") || tkn==GetCommandValue((unsigned char *)"EDIT") || tkn==GetCommandValue((unsigned char *)"AUTOSAVE"))i=1;
if (setjmp(jmprun) != 0) {
PrepareProgram(false);
CurrentLinePtr = 0;
}
ExecuteProgram(tknbuf); // execute the line straight away
if(i){
cmdline=NULL;
do_end(false);
longjmp(mark, 1); // jump back to the input prompt
}
else {
memset(inpbuf,0,STRINGSIZE);
longjmp(mark, 1); // jump back to the input prompt
}
}
}
void stripcomment(char *p){
char *q=p;
int toggle=0;
while(*q){
if(*q=='\'' && toggle==0){
*q=0;
break;
}
if(*q=='"')toggle^=1;
q++;
}
}
// takes a pointer to RAM containing a program (in clear text) and writes it to memory in tokenised format
void MIPS16 SaveProgramToFlash(unsigned char *pm, int msg) {
unsigned char *p, fontnbr, prevchar = 0, buf[STRINGSIZE];
unsigned short endtoken, tkn;
int nbr, i, j, n, SaveSizeAddr;
bool continuation=false;
multi=false;
uint32_t storedupdates[MAXCFUNCTION], updatecount=0, realflashsave;
initFonts();
#ifdef rp2350
__dsb();
#endif
#ifdef USBKEYBOARD
clearrepeat();
#endif
memcpy(buf, tknbuf, STRINGSIZE); // save the token buffer because we are going to use it
FlashWriteInit(PROGRAM_FLASH);
flash_range_erase(realflashpointer, MAX_PROG_SIZE);
j=MAX_PROG_SIZE/4;
int *pp=(int *)(flash_progmemory);
while(j--)if(*pp++ != 0xFFFFFFFF){
enable_interrupts_pico();
error("Flash erase problem");
}
nbr = 0;
// this is used to count the number of bytes written to flash
while(*pm) {
contloop:
if(continuation){
p=&inpbuf[strlen((char *)inpbuf)];
continuation=false;
}
else p = inpbuf;
while(!(*pm == 0 || *pm == '\r' || (*pm == '\n' && prevchar != '\r'))) {
if(*pm == TAB) {
do {*p++ = ' ';
if((p - inpbuf) >= MAXSTRLEN) goto exiterror;
} while((p - inpbuf) % 2);
} else {
if(isprint((uint8_t)*pm)) {
*p++ = *pm;
if((p - inpbuf) >= MAXSTRLEN) goto exiterror;
}
}
prevchar = *pm++;
}
if(*pm) prevchar = *pm++; // step over the end of line char but not the terminating zero
*p = 0; // terminate the string in inpbuf
if(*inpbuf == 0 && (*pm == 0 || (!isprint((uint8_t)*pm) && pm[1] == 0))) break; // don't save a trailing newline
if(inpbuf[strlen((char *)inpbuf)-1]==Option.continuation && inpbuf[strlen((char *)inpbuf)-2]==' ' && Option.continuation){
continuation=true;
inpbuf[strlen((char *)inpbuf)-2]=0; //strip the continuation character
goto contloop;
}
tokenise(false); // turn into executable code
p = tknbuf;
while(!(p[0] == 0 && p[1] == 0)) {
FlashWriteByte(*p++); nbr++;
if((int)((char *)realflashpointer - (uint32_t)PROGSTART) >= MAX_PROG_SIZE - 5) goto exiterror;
}
FlashWriteByte(0); nbr++; // terminate that line in flash
}
FlashWriteByte(0);
FlashWriteAlign(); // this will flush the buffer and step the flash write pointer to the next word boundary
// now we must scan the program looking for CFUNCTION/CSUB/DEFINEFONT statements, extract their data and program it into the flash used by CFUNCTIONs
// programs are terminated with two zero bytes and one or more bytes of 0xff. The CFunction area starts immediately after that.
// the format of a CFunction/CSub/Font in flash is:
// Unsigned Int - Address of the CFunction/CSub in program memory (points to the token representing the "CFunction" keyword) or NULL if it is a font
// Unsigned Int - The length of the CFunction/CSub/Font in bytes including the Offset (see below)
// Unsigned Int - The Offset (in words) to the main() function (ie, the entry point to the CFunction/CSub). Omitted in a font.
// word1..wordN - The CFunction/CSub/Font code
// The next CFunction/CSub/Font starts immediately following the last word of the previous CFunction/CSub/Font
int firsthex=1;
realflashsave= realflashpointer;
p = (unsigned char *)flash_progmemory; // start scanning program memory
while(*p != 0xff) {
nbr++;
if(*p == 0) p++; // if it is at the end of an element skip the zero marker
if(*p == 0) break; // end of the program
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // step over the line number
skipspace(p);
if(*p == T_LABEL) {
p += p[1] + 2; // skip over the label
skipspace(p); // and any following spaces
}
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
if(tkn == cmdCSUB || tkn == GetCommandValue((unsigned char *)"DefineFont")) { // found a CFUNCTION, CSUB or DEFINEFONT token
if(tkn == GetCommandValue((unsigned char *)"DefineFont")) {
endtoken = GetCommandValue((unsigned char *)"End DefineFont");
p+=2; // step over the token
skipspace(p);
if(*p == '#') p++;
fontnbr = getint(p, 1, FONT_TABLE_SIZE);
// font 6 has some special characters, some of which depend on font 1
if(fontnbr == 1 || fontnbr == 6 || fontnbr == 7) {
enable_interrupts_pico();
error("Cannot redefine fonts 1, 6 or 7");
}
realflashpointer+=4;
skipelement(p); // go to the end of the command
p--;
} else {
endtoken = GetCommandValue((unsigned char *)"End CSub");
realflashpointer+=4;
fontnbr = 0;
firsthex=0;
p++;
}
SaveSizeAddr = realflashpointer; // save where we are so that we can write the CFun size in here
realflashpointer+=4;
p++;
skipspace(p);
if(!fontnbr) { //process CSub
if(!isnamestart((uint8_t)*p)){
enable_interrupts_pico();
error("Function name");
}
do { p++; } while(isnamechar((uint8_t)*p));
skipspace(p);
if(!(isxdigit((uint8_t)p[0]) && isxdigit((uint8_t)p[1]) && isxdigit((uint8_t)p[2]))) {
skipelement(p);
p++;
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over a line number
}
}
do {
while(*p && *p != '\'') {
skipspace(p);
n = 0;
for(i = 0; i < 8; i++) {
if(!isxdigit((uint8_t)*p)) {
enable_interrupts_pico();
error("Invalid hex word");
}
if((int)((char *)realflashpointer - (uint32_t)PROGSTART) >= MAX_PROG_SIZE - 5) goto exiterror;
n = n << 4;
if(*p <= '9')
n |= (*p - '0');
else
n |= (toupper(*p) - 'A' + 10);
p++;
}
realflashpointer+=4;
skipspace(p);
if(firsthex){
firsthex=0;
if(((n>>16) & 0xff) < 0x20){
enable_interrupts_pico();
error("Can't define non-printing characters");
}
}
}
// we are at the end of a embedded code line
while(*p) p++; // make sure that we move to the end of the line
p++; // step to the start of the next line
if(*p == 0) {
enable_interrupts_pico();
error("Missing END declaration");
}
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over the line number
skipspace(p);
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
} while(tkn != endtoken);
storedupdates[updatecount++]=realflashpointer - SaveSizeAddr - 4;
}
while(*p) p++; // look for the zero marking the start of the next element
}
realflashpointer = realflashsave ;
updatecount=0;
p = (unsigned char *)flash_progmemory; // start scanning program memory
while(*p != 0xff) {
nbr++;
if(*p == 0) p++; // if it is at the end of an element skip the zero marker
if(*p == 0) break; // end of the program
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // step over the line number
skipspace(p);
if(*p == T_LABEL) {
p += p[1] + 2; // skip over the label
skipspace(p); // and any following spaces
}
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
if(tkn == cmdCSUB || tkn == GetCommandValue((unsigned char *)"DefineFont")) { // found a CFUNCTION, CSUB or DEFINEFONT token
if(tkn == GetCommandValue((unsigned char *)"DefineFont")) { // found a CFUNCTION, CSUB or DEFINEFONT token
endtoken = GetCommandValue((unsigned char *)"End DefineFont");
p+=2; // step over the token
skipspace(p);
if(*p == '#') p++;
fontnbr = getint(p, 1, FONT_TABLE_SIZE);
// font 6 has some special characters, some of which depend on font 1
if(fontnbr == 1 || fontnbr == 6 || fontnbr == 7) {
enable_interrupts_pico();
error("Cannot redefine fonts 1, 6, or 7");
}
//FlashWriteWord(fontnbr - 1); // a low number (< FONT_TABLE_SIZE) marks the entry as a font
// B31 = 1 now marks entry as font.
FlashWriteByte(fontnbr - 1);
FlashWriteByte(0x00);
FlashWriteByte(0x00);
FlashWriteByte(0x80);
skipelement(p); // go to the end of the command
p--;
} else {
endtoken = GetCommandValue((unsigned char *)"End CSub");
FlashWriteWord((unsigned int)(p-flash_progmemory)); // if a CFunction/CSub save a relative pointer to the declaration
fontnbr = 0;
p++;
}
SaveSizeAddr = realflashpointer; // save where we are so that we can write the CFun size in here
FlashWriteWord(storedupdates[updatecount++]); // leave this blank so that we can later do the write
p++;
skipspace(p);
if(!fontnbr) {
if(!isnamestart((uint8_t)*p)) {
enable_interrupts_pico();
error("Function name");
}
do { p++; } while(isnamechar(*p));
skipspace(p);
if(!(isxdigit(p[0]) && isxdigit(p[1]) && isxdigit(p[2]))) {
skipelement(p);
p++;
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over a line number
}
}
do {
while(*p && *p != '\'') {
skipspace(p);
n = 0;
for(i = 0; i < 8; i++) {
if(!isxdigit(*p)) {
enable_interrupts_pico();
error("Invalid hex word");
}
if((int)((char *)realflashpointer - (uint32_t)PROGSTART) >= MAX_PROG_SIZE - 5) goto exiterror;
n = n << 4;
if(*p <= '9')
n |= (*p - '0');
else
n |= (toupper(*p) - 'A' + 10);
p++;
}
FlashWriteWord(n);
skipspace(p);
}
// we are at the end of a embedded code line
while(*p) p++; // make sure that we move to the end of the line
p++; // step to the start of the next line
if(*p == 0) {
enable_interrupts_pico();
error("Missing END declaration");
}
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over a line number
skipspace(p);
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
} while(tkn != endtoken);
}
while(*p) p++; // look for the zero marking the start of the next element
}
FlashWriteWord(0xffffffff); // make sure that the end of the CFunctions is terminated with an erased word
FlashWriteClose(); // this will flush the buffer and step the flash write pointer to the next word boundary
if(msg) { // if requested by the caller, print an informative message
if(MMCharPos > 1) MMPrintString("\r\n"); // message should be on a new line
MMPrintString("Saved ");
IntToStr((char *)tknbuf, nbr + 3, 10);
MMPrintString((char *)tknbuf);
MMPrintString(" bytes\r\n");
}
memcpy(tknbuf, buf, STRINGSIZE); // restore the token buffer in case there are other commands in it
// initConsole();
#ifdef USBKEYBOARD
clearrepeat();
#endif
enable_interrupts_pico();
return;
// we only get here in an error situation while writing the program to flash
exiterror:
FlashWriteByte(0); FlashWriteByte(0); FlashWriteByte(0); // terminate the program in flash
FlashWriteClose();
error("Not enough memory");
}
#ifdef __cplusplus
}
#endif
/// \end:uart_advanced[]