diff --git a/components/tme-esp32/component.mk b/components/tme-esp32/component.mk new file mode 100644 index 0000000..0a6fdc9 --- /dev/null +++ b/components/tme-esp32/component.mk @@ -0,0 +1,2 @@ +#Component makefile + diff --git a/components/tme-esp32/hd.c b/components/tme-esp32/hd.c new file mode 100644 index 0000000..225f780 --- /dev/null +++ b/components/tme-esp32/hd.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include "ncr.h" +#include "hd.h" +#include "esp_partition.h" +#include "esp_heap_alloc_caps.h" + +typedef struct { + const esp_partition_t* part; + int size; +} HdPriv; + +const uint8_t inq_resp[95]={ + 0, //HD + 0, //0x80 if removable + 0x49, //Obsolete SCSI standard 1 all the way + 0, //response version etc + 31, //extra data + 0,0, //reserved + 0, //features + 'A','P','P','L','E',' ',' ',' ', //vendor id + '2','0','S','C',' ',' ',' ',' ', //prod id + '1','.','0',' ',' ',' ',' ',' ', //prod rev lvl +}; + +static uint8_t bouncebuffer[512]; + +static int hdScsiCmd(SCSITransferData *data, unsigned int cmd, unsigned int len, unsigned int lba, void *arg) { + int ret=0; + static uint8_t *bb=NULL; + HdPriv *hd=(HdPriv*)arg; + if (cmd==0x8 || cmd==0x28) { //read + printf("HD: Read %d bytes from LBA %d.\n", len*512, lba); + for (int i=0; ipart, (lba+i)*512, bouncebuffer, 512); + memcpy(&data->data[i*512], bouncebuffer, len*512); + } + ret=len*512; + } else if (cmd==0x12) { //inquiry + printf("HD: Inquery\n"); + memcpy(data->data, inq_resp, sizeof(inq_resp)); + return 95; + } else if (cmd==0x25) { //read capacity + int lbacnt=hd->size/512; + data->data[0]=(lbacnt>>24); + data->data[1]=(lbacnt>>16); + data->data[2]=(lbacnt>>8); + data->data[3]=(lbacnt>>0); + data->data[4]=0; + data->data[5]=0; + data->data[6]=2; //512 + data->data[7]=0; + ret=8; + printf("HD: Read capacity (%d)\n", lbacnt); + } else { + printf("********** hdScsiCmd: unrecognized command %x\n", cmd); + } + data->cmd[0]=0; //status + data->msg[0]=0; + return ret; +} + +SCSIDevice *hdCreate(char *file) { + SCSIDevice *ret=malloc(sizeof(SCSIDevice)); + memset(ret, 0, sizeof(SCSIDevice)); + HdPriv *hd=malloc(sizeof(HdPriv)); + memset(hd, 0, sizeof(HdPriv)); + hd->part=esp_partition_find_first(0x40, 0x2, NULL); + if (hd->part==0) printf("Couldn't find HD part!\n"); + hd->size=hd->part->size; + ret->arg=hd; + ret->scsiCmd=hdScsiCmd; + return ret; +} diff --git a/components/tme-esp32/main.c b/components/tme-esp32/main.c new file mode 100644 index 0000000..d77cd09 --- /dev/null +++ b/components/tme-esp32/main.c @@ -0,0 +1,56 @@ +#include "esp_attr.h" + +#include "rom/cache.h" +#include "rom/ets_sys.h" +#include "rom/spi_flash.h" +#include "rom/crc.h" + +#include "soc/soc.h" +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/efuse_reg.h" +#include "soc/rtc_cntl_reg.h" +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include "esp_err.h" +#include "nvs_flash.h" +#include "esp_partition.h" + +#include "emu.h" +#include "tmeconfig.h" + +#include "mpu6050.h" + +unsigned char *romdata; + +void emuTask(void *pvParameters) +{ + void *ram=malloc(TME_RAMSIZE); + if (ram==NULL) { + printf("Couldn't allocate main ram.\n"); + abort(); + } + tmeStartEmu(ram, romdata); +} + + +void app_main() +{ + int i; + const esp_partition_t* part; + spi_flash_mmap_handle_t hrom; + esp_err_t err; + +// mpu6050_init(); +// while(1); + + part=esp_partition_find_first(0x40, 0x1, NULL); + if (part==0) printf("Couldn't find bootrom part!\n"); + err=esp_partition_mmap(part, 0, 128*1024, SPI_FLASH_MMAP_DATA, (const void**)&romdata, &hrom); + if (err!=ESP_OK) printf("Couldn't map bootrom part!\n"); + printf("Starting emu...\n"); + xTaskCreatePinnedToCore(&emuTask, "emu", 6*1024, NULL, 5, NULL, 0); +} + diff --git a/components/tme-esp32/mpu6050.c b/components/tme-esp32/mpu6050.c new file mode 100644 index 0000000..6c25761 --- /dev/null +++ b/components/tme-esp32/mpu6050.c @@ -0,0 +1,92 @@ +#include +#include "driver/i2c.h" + +#define I2C_MASTER_SCL_IO 4 /*!< gpio number for I2C master clock */ +#define I2C_MASTER_SDA_IO 26 /*!< gpio number for I2C master data */ +#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */ +#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ +#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ +#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */ + +#define WRITEW_BIT 1 +#define MPU_ADDR (0x68<<1) + +/* +esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t* data_rd, size_t size) +{ + if (size == 0) { + return ESP_OK; + } + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN); + if (size > 1) { + i2c_master_read(cmd, data_rd, size - 1, ACK_VAL); + } + i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} +*/ + +static esp_err_t setreg(int i2c_num, int reg, int val) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, ( MPU_ADDR | I2C_MASTER_WRITE), true); + i2c_master_write_byte(cmd, reg, true); + i2c_master_write_byte(cmd, val, true); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 100 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +static int getreg(int i2c_num, int reg) { + unsigned char byte; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, ( MPU_ADDR | I2C_MASTER_WRITE), true); + i2c_master_write_byte(cmd, reg, true); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, ( MPU_ADDR | I2C_MASTER_READ), true); + i2c_master_read_byte(cmd, &byte, false); + i2c_master_stop(cmd); + esp_err_t ret=i2c_master_cmd_begin(i2c_num, cmd, 100 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret!=ESP_OK) return -1; + return byte; +} + + +esp_err_t mpu6050_start(int i2c_num, int samp_div) { + int i=getreg(i2c_num, 0x75); + printf("Mpu: %x\n", i); + return ESP_OK; +} + + +void mpu6050_poll(int *x, int *y, int *z) { + +} + + +//Actually initializes the i2c port, but atm there's nothing else connected to it... should put this +//into some io init routine or something tho'. + +void mpu6050_init() { + int i2c_master_port = I2C_MASTER_NUM; + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = I2C_MASTER_SDA_IO; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_io_num = I2C_MASTER_SCL_IO; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = I2C_MASTER_FREQ_HZ; + i2c_param_config(i2c_master_port, &conf); + i2c_driver_install(i2c_master_port, conf.mode, 1024, 1024, 0); + + mpu6050_start(I2C_MASTER_NUM, 10); +} + diff --git a/components/tme-esp32/mpu6050.h b/components/tme-esp32/mpu6050.h new file mode 100644 index 0000000..c6025af --- /dev/null +++ b/components/tme-esp32/mpu6050.h @@ -0,0 +1,2 @@ +void mpu6050_poll(int *x, int *y, int *z); +void mpu6050_init(); diff --git a/components/tme-esp32/spi_lcd.c b/components/tme-esp32/spi_lcd.c new file mode 100644 index 0000000..8d16b21 --- /dev/null +++ b/components/tme-esp32/spi_lcd.c @@ -0,0 +1,307 @@ +/* SPI Master example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "driver/spi_master.h" +#include "soc/gpio_struct.h" +#include "driver/gpio.h" +#include "esp_heap_alloc_caps.h" + +#define PIN_NUM_MISO 25 +#define PIN_NUM_MOSI 27 +//#define PIN_NUM_MOSI 23 +#define PIN_NUM_CLK 19 +#define PIN_NUM_CS 22 + +#define PIN_NUM_DC 21 +#define PIN_NUM_RST 18 +#define PIN_NUM_BCKL 5 //backlight enable + + +/* + The ILI9341 needs a bunch of command/argument values to be initialized. They are stored in this struct. +*/ +typedef struct { + uint8_t cmd; + uint8_t data[16]; + uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds. +} ili_init_cmd_t; + +static const ili_init_cmd_t ili_init_cmds[]={ + {0xCF, {0x00, 0x83, 0X30}, 3}, + {0xED, {0x64, 0x03, 0X12, 0X81}, 4}, + {0xE8, {0x85, 0x01, 0x79}, 3}, + {0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5}, + {0xF7, {0x20}, 1}, + {0xEA, {0x00, 0x00}, 2}, + {0xC0, {0x26}, 1}, + {0xC1, {0x11}, 1}, + {0xC5, {0x35, 0x3E}, 2}, + {0xC7, {0xBE}, 1}, + {0x36, {0x28}, 1}, + {0x3A, {0x55}, 1}, + {0xB1, {0x00, 0x1B}, 2}, + {0xF2, {0x08}, 1}, + {0x26, {0x01}, 1}, + {0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0X87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15}, + {0XE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15}, + {0x2A, {0x00, 0x00, 0x00, 0xEF}, 4}, + {0x2B, {0x00, 0x00, 0x01, 0x3f}, 4}, + {0x2C, {0}, 0}, + {0xB7, {0x07}, 1}, + {0xB6, {0x0A, 0x82, 0x27, 0x00}, 4}, + {0x11, {0}, 0x80}, + {0x29, {0}, 0x80}, + {0, {0}, 0xff}, +}; + +static spi_device_handle_t spi; + + +//Send a command to the ILI9341. Uses spi_device_transmit, which waits until the transfer is complete. +void ili_cmd(spi_device_handle_t spi, const uint8_t cmd) +{ + esp_err_t ret; + spi_transaction_t t; + memset(&t, 0, sizeof(t)); //Zero out the transaction + t.length=8; //Command is 8 bits + t.tx_buffer=&cmd; //The data is the cmd itself + t.user=(void*)0; //D/C needs to be set to 0 + ret=spi_device_transmit(spi, &t); //Transmit! + assert(ret==ESP_OK); //Should have had no issues. +} + +//Send data to the ILI9341. Uses spi_device_transmit, which waits until the transfer is complete. +void ili_data(spi_device_handle_t spi, const uint8_t *data, int len) +{ + esp_err_t ret; + spi_transaction_t t; + if (len==0) return; //no need to send anything + memset(&t, 0, sizeof(t)); //Zero out the transaction + t.length=len*8; //Len is in bytes, transaction length is in bits. + t.tx_buffer=data; //Data + t.user=(void*)1; //D/C needs to be set to 1 + ret=spi_device_transmit(spi, &t); //Transmit! + assert(ret==ESP_OK); //Should have had no issues. +} + +//This function is called (in irq context!) just before a transmission starts. It will +//set the D/C line to the value indicated in the user field. +void ili_spi_pre_transfer_callback(spi_transaction_t *t) +{ + int dc=(int)t->user; + gpio_set_level(PIN_NUM_DC, dc); +} + +//Initialize the display +void ili_init(spi_device_handle_t spi) +{ + int cmd=0; + //Initialize non-SPI GPIOs + gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT); + + //Reset the display + gpio_set_level(PIN_NUM_RST, 0); + vTaskDelay(100 / portTICK_RATE_MS); + gpio_set_level(PIN_NUM_RST, 1); + vTaskDelay(100 / portTICK_RATE_MS); + + //Send all the commands + while (ili_init_cmds[cmd].databytes!=0xff) { + ili_cmd(spi, ili_init_cmds[cmd].cmd); + ili_data(spi, ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes&0x1F); + if (ili_init_cmds[cmd].databytes&0x80) { + vTaskDelay(100 / portTICK_RATE_MS); + } + cmd++; + } + + ///Enable backlight + gpio_set_level(PIN_NUM_BCKL, 0); +} + + +static void send_header_start(spi_device_handle_t spi, int xpos, int ypos, int w, int h) +{ + esp_err_t ret; + int x; + //Transaction descriptors. Declared static so they're not allocated on the stack; we need this memory even when this + //function is finished because the SPI driver needs access to it even while we're already calculating the next line. + static spi_transaction_t trans[5]; + + //In theory, it's better to initialize trans and data only once and hang on to the initialized + //variables. We allocate them on the stack, so we need to re-init them each call. + for (x=0; x<5; x++) { + memset(&trans[x], 0, sizeof(spi_transaction_t)); + if ((x&1)==0) { + //Even transfers are commands + trans[x].length=8; + trans[x].user=(void*)0; + } else { + //Odd transfers are data + trans[x].length=8*4; + trans[x].user=(void*)1; + } + trans[x].flags=SPI_TRANS_USE_TXDATA; + } + trans[0].tx_data[0]=0x2A; //Column Address Set + trans[1].tx_data[0]=xpos>>8; //Start Col High + trans[1].tx_data[1]=xpos; //Start Col Low + trans[1].tx_data[2]=(xpos+w-1)>>8; //End Col High + trans[1].tx_data[3]=(xpos+w-1)&0xff; //End Col Low + trans[2].tx_data[0]=0x2B; //Page address set + trans[3].tx_data[0]=ypos>>8; //Start page high + trans[3].tx_data[1]=ypos&0xff; //start page low + trans[3].tx_data[2]=(ypos+h-1)>>8; //end page high + trans[3].tx_data[3]=(ypos+h-1)&0xff; //end page low + trans[4].tx_data[0]=0x2C; //memory write + + //Queue all transactions. + for (x=0; x<5; x++) { + ret=spi_device_queue_trans(spi, &trans[x], portMAX_DELAY); + assert(ret==ESP_OK); + } + + //When we are here, the SPI driver is busy (in the background) getting the transactions sent. That happens + //mostly using DMA, so the CPU doesn't have much to do here. We're not going to wait for the transaction to + //finish because we may as well spend the time calculating the next line. When that is done, we can call + //send_line_finish, which will wait for the transfers to be done and check their status. +} + + +void send_header_cleanup(spi_device_handle_t spi) +{ + spi_transaction_t *rtrans; + esp_err_t ret; + //Wait for all 5 transactions to be done and get back the results. + for (int x=0; x<5; x++) { + ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); + assert(ret==ESP_OK); + //We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though. + } +} + + +volatile static uint8_t *currFbPtr=NULL; +SemaphoreHandle_t dispSem = NULL; + +#define NO_SIM_TRANS 5 +#define MEM_PER_TRANS 1024 + +void IRAM_ATTR displayTask(void *arg) { + int x, i; + int idx=0; + int inProgress=0; + static uint16_t *dmamem[NO_SIM_TRANS]; + spi_transaction_t trans[NO_SIM_TRANS]; + spi_transaction_t *rtrans; + + esp_err_t ret; + spi_bus_config_t buscfg={ + .miso_io_num=PIN_NUM_MISO, + .mosi_io_num=PIN_NUM_MOSI, + .sclk_io_num=PIN_NUM_CLK, + .quadwp_io_num=-1, + .quadhd_io_num=-1 + }; + spi_device_interface_config_t devcfg={ + .clock_speed_hz=40000000, //Clock out at 40 MHz. Yes, that's heavily overclocked. + .mode=0, //SPI mode 0 + .spics_io_num=PIN_NUM_CS, //CS pin + .queue_size=10, //We want to be able to queue 7 transactions at a time + .pre_cb=ili_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line + }; + + printf("*** Display task starting.\n"); + + //Initialize the SPI bus + ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1); + assert(ret==ESP_OK); + //Attach the LCD to the SPI bus + ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi); + assert(ret==ESP_OK); + //Initialize the LCD + ili_init(spi); + + for (x=0; x>=1) { + dmamem[idx][i++]=(*myData&j)?0:0xffff; + } + myData++; + xpos+=8; + if (xpos>=320) { + xpos=0; + myData+=((512-320)/8); + } + } + trans[idx].length=MEM_PER_TRANS*16; + trans[idx].user=(void*)1; + trans[idx].tx_buffer=dmamem[idx]; + ret=spi_device_queue_trans(spi, &trans[idx], portMAX_DELAY); + assert(ret==ESP_OK); + + idx++; + if (idx>=NO_SIM_TRANS) idx=0; + + if (inProgress==NO_SIM_TRANS-1) { + ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); + assert(ret==ESP_OK); + } else { + inProgress++; + } + } + while(inProgress) { + ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); + assert(ret==ESP_OK); + inProgress--; + } + } +} + + + +void dispDraw(uint8_t *mem) { + currFbPtr=mem; + xSemaphoreGive(dispSem); +} + + +void dispInit() { + printf("spi_lcd_init()\n"); + dispSem=xSemaphoreCreateBinary(); +#if CONFIG_FREERTOS_UNICORE + xTaskCreatePinnedToCore(&displayTask, "display", 3000, NULL, 6, NULL, 0); +#else + xTaskCreatePinnedToCore(&displayTask, "display", 3000, NULL, 6, NULL, 1); +#endif +} diff --git a/components/tme/mouse.c b/components/tme/mouse.c new file mode 100644 index 0000000..2d88a58 --- /dev/null +++ b/components/tme/mouse.c @@ -0,0 +1,48 @@ +#include "mouse.h" + +typedef struct { + int dx, dy; + int btn; + int rpx, rpy; +} Mouse; + +static const int quad[4]={0x0, 0x1, 0x3, 0x2}; + +Mouse mouse; + +#define MAXCDX 50 + +void mouseMove(int dx, int dy, int btn) { + mouse.dx+=dx; + mouse.dy+=dy; + if (mouse.dx>MAXCDX) mouse.dx=MAXCDX; + if (mouse.dy>MAXCDX) mouse.dy=MAXCDX; + if (mouse.dx<-MAXCDX) mouse.dx=-MAXCDX; + if (mouse.dy<-MAXCDX) mouse.dy=-MAXCDX; + if (btn) mouse.btn=1; else mouse.btn=0; +} + +int mouseTick() { + int ret=0; + if (mouse.dx>0) { + mouse.dx--; + mouse.rpx--; + } + if (mouse.dx<0) { + mouse.dx++; + mouse.rpx++; + } + if (mouse.dy>0) { + mouse.dy--; + mouse.rpy++; + } + if (mouse.dy<0) { + mouse.dy++; + mouse.rpy--; + } + ret=quad[mouse.rpx&3]; + ret|=quad[mouse.rpy&3]<<2; + ret|=mouse.btn<<4; +// printf("dx %d dy %d ret %x\n", mouse.dx, mouse.dy, ret); + return ret; +} diff --git a/components/tme/mouse.h b/components/tme/mouse.h new file mode 100644 index 0000000..1a7095a --- /dev/null +++ b/components/tme/mouse.h @@ -0,0 +1,9 @@ +#define MOUSE_QXA (1<<0) +#define MOUSE_QXB (1<<1) +#define MOUSE_QYA (1<<2) +#define MOUSE_QYB (1<<3) +#define MOUSE_BTN (1<<4) + + +void mouseMove(int dx, int dy, int btn); +int mouseTick(); diff --git a/components/tme/scc.c b/components/tme/scc.c new file mode 100644 index 0000000..f573abc --- /dev/null +++ b/components/tme/scc.c @@ -0,0 +1,133 @@ +#include +#include +#include "scc.h" +#include "m68k.h" + +/* +THis is an extremely minimal SCC implementation: it only somewhat implements the interrupt mechanism for the +DCD pins because that is what is needed for the mouse to work. +*/ + + +void sccIrq(int ena); + +typedef struct { + int regptr; + int intpending; + int intpendingOld; + int dcd[2]; + int cts[2]; + int wr1[2]; + int wr15[2]; +} Scc; + +static Scc scc; + +//WR15 is the External/Status Interrupt Control and has the interrupt enable bits. +#define SCC_WR15_BREAK (1<<7) +#define SCC_WR15_TXU (1<<6) +#define SCC_WR15_CTS (1<<5) +#define SCC_WR15_SYNC (1<<4) +#define SCC_WR15_DCD (1<<3) +#define SCC_WR15_ZCOUNT (1<<1) + +//WR3, when read, gives the Interrupt Pending status. +//This is reflected in scc.intpending. +#define SCC_WR3_CHB_EXT (1<<0) +#define SCC_WR3_CHB_TX (1<<1) +#define SCC_WR3_CHB_RX (1<<2) +#define SCC_WR3_CHA_EXT (1<<3) +#define SCC_WR3_CHA_TX (1<<4) +#define SCC_WR3_CHA_RX (1<<5) + +static void raiseInt(int chan) { + if ((scc.wr1[chan]&1) && (scc.intpending&(~scc.intpendingOld))) { + scc.intpendingOld=scc.intpending; + printf("SCC int, pending %x\n", scc.intpending); + sccIrq(1); + } +} + +void sccSetDcd(int chan, int val) { + val=val?1:0; + if (scc.dcd[chan]!=val) { + if (chan==SCC_CHANA) { + scc.intpending|=SCC_WR3_CHA_EXT; + } else { + scc.intpending|=SCC_WR3_CHB_EXT; + } + } + if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_DCD)) raiseInt(SCC_CHANA); + if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_DCD)) raiseInt(SCC_CHANB); + if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_CTS)) raiseInt(SCC_CHANA); + if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_CTS)) raiseInt(SCC_CHANB); + scc.dcd[chan]=val; +} + +void sccWrite(unsigned int addr, unsigned int val) { + int chan, reg; + if (addr & (1<<1)) chan=SCC_CHANA; else chan=SCC_CHANB; + if (addr & (1<<2)) { + //Data + reg=8; + } else { + //Control + reg=scc.regptr; + scc.regptr=0; + } + if (reg==0) { + scc.regptr=val&0x7; + if ((val&0x38)==0x8) scc.regptr|=8; + if ((val&0x38)==0x10) { + scc.intpending=0; + scc.intpendingOld=0; + } + } else if (reg==1) { + scc.wr1[chan]=val; + } else if (reg==15) { + scc.wr15[chan]=val; + } +// printf("SCC: write to addr %x chan %d reg %d val %x\n", addr, chan, reg, val); +} + + +unsigned int sccRead(unsigned int addr) { + int chan, reg, val=0xff; + if (addr & (1<<1)) chan=SCC_CHANA; else chan=SCC_CHANB; + if (addr & (1<<2)) { + //Data + reg=8; + } else { + //Control + reg=scc.regptr; + scc.regptr=0; + } + if (reg==0) { + val=(1<<2); + if (scc.dcd[chan]) val|=(1<<3); + if (scc.cts[chan]) val|=(1<<5); + } else if (reg==1) { + val=scc.wr1[chan]; + } else if (reg==2 && chan==SCC_CHANB) { + //We assume this also does an intack. + int rsn=0; + if (scc.intpending & SCC_WR3_CHB_EXT) { + rsn=1; + scc.intpending&=~SCC_WR3_CHB_EXT; + } + if (scc.intpending & SCC_WR3_CHA_EXT) { + rsn=5; + scc.intpending&=~SCC_WR3_CHA_EXT; + } + val=rsn<<1; + if (scc.intpending&0x38) raiseInt(SCC_CHANA); + if (scc.intpending&0x07) raiseInt(SCC_CHANB); + } else if (reg==3) { + if (chan==SCC_CHANA) val=scc.intpending; else val=0; + } else if (reg==15) { + val=scc.wr15[chan]; + } + printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val); + return val; +} + diff --git a/components/tme/scc.h b/components/tme/scc.h new file mode 100644 index 0000000..4836117 --- /dev/null +++ b/components/tme/scc.h @@ -0,0 +1,8 @@ + +#define SCC_CHANA 0 +#define SCC_CHANB 1 + +void sccWrite(unsigned int addr, unsigned int val); +unsigned int sccRead(unsigned int addr); +void sccSetDcd(int chan, int val); +