Also add esp32 files :/

This commit is contained in:
Jeroen Domburg 2017-03-24 18:44:04 +08:00
parent 2525c3af35
commit 3c1e4e5e61
10 changed files with 733 additions and 0 deletions

View File

@ -0,0 +1,2 @@
#Component makefile

76
components/tme-esp32/hd.c Normal file
View File

@ -0,0 +1,76 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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; i<len; i++) {
esp_partition_read(hd->part, (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;
}

View File

@ -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 <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdlib.h>
#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);
}

View File

@ -0,0 +1,92 @@
#include <stdio.h>
#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);
}

View File

@ -0,0 +1,2 @@
void mpu6050_poll(int *x, int *y, int *z);
void mpu6050_init();

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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<NO_SIM_TRANS; x++) {
dmamem[x]=pvPortMallocCaps(MEM_PER_TRANS*2, MALLOC_CAP_DMA);
assert(dmamem[x]);
memset(&trans[x], 0, sizeof(spi_transaction_t));
trans[x].length=MEM_PER_TRANS*4;
trans[x].user=(void*)1;
trans[x].tx_buffer=&dmamem[x];
}
while(1) {
xSemaphoreTake(dispSem, portMAX_DELAY);
uint8_t *myData=(uint8_t*)currFbPtr;
send_header_start(spi, 0, 0, 320, 240);
send_header_cleanup(spi);
int xpos=0;
for (x=0; x<320*240; x+=MEM_PER_TRANS) {
i=0;
while (i<MEM_PER_TRANS) {
for (int j=0x80; j!=0; j>>=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
}

48
components/tme/mouse.c Normal file
View File

@ -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;
}

9
components/tme/mouse.h Normal file
View File

@ -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();

133
components/tme/scc.c Normal file
View File

@ -0,0 +1,133 @@
#include <stdio.h>
#include <stdint.h>
#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;
}

8
components/tme/scc.h Normal file
View File

@ -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);