/* */ /* Bootloader for XC3S200A with 25P40VP SPI flash */ /* */ /* This reads configuration data LOGICBOY.BIN from the SD/SDHC card, */ /* and writes it to the SPI configuration flash memory at address 0x50000. */ /* after power on while the switch pushed. */ /* And boot from the configuration data after power on */ /* while the switch released. */ /* */ /* This can also read data ASSEMBLY.BIN from the SD card, */ /* and write it to the flash at address 0x30000 - 4ffff. */ /* You can use it for any purpose. */ /* */ /* The external clock is assumed to be 4MHz */ /* */ /* (C) Koichi Nishida */ /* */ /* July 2, 2020 */ /* All Rights Reserved */ /* */ // SSD1306 EL display driver const uint I2C_ADDRESS = 0x78; firmfunc void init_el(fio uint io_port[], fdmem uint dmem[2048]) { uint i; io_port[2] = 0x000; // start for (i=0; i <= 0x2b; i++) { io_port[2] = 0x100 | dmem[i+0x400]; } io_port[2] = 0x200; // stop } firmfunc void cls_el(fio uint io_port[]) { uint x, y; for (y = 0; y < 8; y++) { io_port[2] = 0x000; // start io_port[2] = 0x100 | I2C_ADDRESS; io_port[2] = 0x100 | 0b00000000; io_port[2] = 0x100 | 0x22; io_port[2] = 0x100 | y; io_port[2] = 0x100 | y; io_port[2] = 0x100 | 0b00000000; io_port[2] = 0x100 | 0x21; io_port[2] = 0x100 | 0; io_port[2] = 0x100 | 127; io_port[2] = 0x200; // stop io_port[2] = 0x000; // start io_port[2] = 0x100 | I2C_ADDRESS; io_port[2] = 0x100 | 0b01000000; for (x = 0; x < 128; x++) { io_port[2] = 0x100; } io_port[2] = 0x200; // stop } } firmfunc void putbinbar_el(fio uint io_port[], uint h, uint &x, uint &y) { io_port[2] = 0x000; // start io_port[2] = 0x100 | I2C_ADDRESS; io_port[2] = 0x100 | 0b00000000; io_port[2] = 0x100 | 0x22; io_port[2] = 0x100 | y; io_port[2] = 0x100 | y; io_port[2] = 0x100 | 0b00000000; io_port[2] = 0x100 | 0x21; io_port[2] = 0x100 | x; io_port[2] = 0x100 | x; io_port[2] = 0x200; // stop io_port[2] = 0x000; // start io_port[2] = 0x100 | I2C_ADDRESS; io_port[2] = 0x100 | 0b01000000; io_port[2] = 0x100 | h; io_port[2] = 0x200; // stop x++; if (x==128) { x = 0; y += 1; if (y==8) y = 0; } } firmfunc void putchar_el(fio uint io_port[], uint ch, uint n, uint &x, uint &y, fdmem uint dmem[2048]) { uint j; for (j=0; j (0x20+96))) c = 0x20; a = (c-0x20)*4+0x450; io_port[2] = 0x000; // start io_port[2] = 0x100 | I2C_ADDRESS; io_port[2] = 0x100 | 0b00000000; io_port[2] = 0x100 | 0x22; io_port[2] = 0x100 | y; io_port[2] = 0x100 | y; io_port[2] = 0x100 | 0b00000000; io_port[2] = 0x100 | 0x21; io_port[2] = 0x100 | x; io_port[2] = 0x100 | (x+7); io_port[2] = 0x200; // stop io_port[2] = 0x000; // start io_port[2] = 0x100 | I2C_ADDRESS; io_port[2] = 0x100 | 0b01000000; for (i=0; i<4; i++) { uint d = dmem[a++]; io_port[2] = 0x100 | (d >> 8); io_port[2] = 0x100 | (d&0xff); } io_port[2] = 0x200; // stop x += 8; if (x==128) { x = 0; y += 1; if (y==8) y = 0; } ch >>= 8; } } firmfunc void puthex_el(fio uint io_port[], ulong v, uint n, uint &x, uint &y, fdmem uint dmem[2048]) { uint i; for (i=0; i>((n-i-1)*4))&0xf); if (ch>=0xa) ch += ('A'-0xa); else ch += '0'; putchar_el(io_port, ch, 1, x, y, dmem); } } // SD card firmfunc void sd_command_(fio uint io_port[], uint cmd, ulong adr, uint crc, fdmem uint dmem[2048]) { io_port[3] = (0x140ff + (cmd<<8)); io_port[3] = ((adr >> 24) & 0xff); io_port[3] = ((adr >> 16) & 0xff); io_port[3] = ((adr >> 8) & 0xff); io_port[3] = (adr & 0xff); io_port[3] = (0x1ff00 | crc); } firmfunc uint sd_get_resp(fio uint io_port[]) { uint ch; do { io_port[3] = 0x0ff; ch = (io_port[3]); } while ((ch&0x80) != 0); return ch; } firmfunc void sd_command(fio uint io_port[], uint cmd, ulong adr, uint crc, fdmem uint dmem[2948]) { uint ch; do { io_port[3] = (0x140ff + (cmd<<8)); io_port[3] = ((adr >> 24) & 0xff); io_port[3] = ((adr >> 16) & 0xff); io_port[3] = ((adr >> 8) & 0xff); io_port[3] = (adr & 0xff); io_port[3] = (0x1ff00 | crc); ch = sd_get_resp(io_port); } while ((ch != 0) && (ch != 0xff)); } firmfunc void sd_readBlock(fio uint io_port[], ulong adr, fdmem uint dmem[2048]) { uint SD_buff[512] onram; uint SD_blkAdrAccs onram; uint ch; // read block begin sd_command_(io_port, 17, SD_blkAdrAccs?adr:(adr*512), 0, dmem); // command 17 do { io_port[3] = 0xff; ch = io_port[3]; } while (ch != 0xfe); // read { uint i; for (i=0; i<256; i++) { uint ch; io_port[3] = 0x1ffff; ch = io_port[3]; SD_buff[i] = ch; } } // read block end io_port[3] = 0x1ffff; io_port[3] = 0x1ffff; } firmfunc int sd_init(fio uint io_port[], bool p, fdmem uint dmem[2048]) { // SD uint onram SD_buff[512]; uint onram SD_blkAdrAccs; uint onram SD_sectorsPerCluster; ulong onram SD_fatSz; ulong onram SD_fatAddr; ulong onram SD_fatSectors; ulong onram SD_rootAddr; ulong onram SD_rootSectors; ulong onram SD_userAddr; uint onram SD_fat32; // FILE uint onram valid; uint onram secCount; ulong onram fat; uint onram secLength; ulong onram initfat; uint onram string[6]; // local variables ulong bpbAddr; uint ver; uint fat32; uint i; uint x=0, y=0; uint ch; io_port[3] = 0x20000; // speed = low io_port[3] = 0x30001; // disable CS for (i=0; i<32; i++) { if (i==30) io_port[3] = 0x30000; // enable CS io_port[3] = 0x0ff; } sd_command_(io_port, 0, 0L, 0x95, dmem); // command 0 do { io_port[3] = 0xff; ch = (io_port[3]&0xff); } while (ch != 0x01); sd_command_(io_port, 8, 0x1AAL, 0x87, dmem); // command 8 ch = sd_get_resp(io_port); io_port[3] = 0x1ffff; io_port[3] = 0x1ffff; { uint resp7; resp7 = io_port[3]; if (ch==1) { if (resp7 != 0xaa01 /* 01aa endian changed */) return 0; ver = 2; } else { ver = 1; } } io_port[3] = 0x30001; // disable CS while (true) { io_port[3] = 0x30000; // enable CS sd_command_(io_port, 55, 0L, 0, dmem); // command 55 ch = sd_get_resp(io_port); if (ch == 0xff) return 0; if ((ch & 0xfe)!= 0) return 0; if (ch == 0x00) break; io_port[3] = 0x30001; // disable CS io_port[3] = 0x30000; // enable CS sd_command_(io_port, 41, (ver == 2)?0x40000000L:0L, 0, dmem); // command 41 ch = sd_get_resp(io_port); if (ch == 0) break; if (ch == 0xff) return 0; io_port[3] = 0x30001; // disable CS } io_port[3] = 0x20001; // speed = high // check if block access or not SD_blkAdrAccs = 0; if (ver==2) { sd_command_(io_port, 58, 0L, 0, dmem); ch = sd_get_resp(io_port); io_port[3] = 0x1ffff; { uint ocr; ocr = io_port[3]; if ((ocr & 0x0040)!=0) { SD_blkAdrAccs = 1; } io_port[3] = 0x1ffff; } } // set block size if (SD_blkAdrAccs == 0) { uint ch; do { io_port[3] = (0x140ff + (16<<8)); io_port[3] = ((512L >> 24) & 0xff); io_port[3] = ((512L >> 16) & 0xff); io_port[3] = ((512L >> 8) & 0xff); io_port[3] = (512L & 0xff); io_port[3] = (0x1ff00 | 0); ch = sd_get_resp(io_port); } while ((ch != 0) && (ch != 0xff)); // sd_command(io_port, 16, 512L, 0, dmem); } // read bpb sd_readBlock(io_port, 0L, dmem); bpbAddr = 0; if ((SD_buff[27] == 'FA') & (SD_buff[28] == 'T1') & (SD_buff[29] == '6 ')) { fat32 = 0; } else if ((SD_buff[41] == 'FA') & (SD_buff[42] == 'T3') & (SD_buff[43] == '2 ')) { fat32 = 1; } else { bpbAddr = SD_buff[0xe3] + SD_buff[0xe4]*0x10000L; sd_readBlock(io_port, bpbAddr, dmem); if ((SD_buff[41] == 'FA') & (SD_buff[42] == 'T3') & (SD_buff[43] == '2 ')) { fat32 = 1; } else return 0; } SD_fat32 = fat32; if (SD_buff[255]!=0xaa55) return 0; { uint RsvdSecCnt = SD_buff[7]; uint RootEntCnt = (((SD_buff[8]>>8) | (SD_buff[9]<<8))&0xffff); uint FATSz16 = SD_buff[11]; ulong FATSz32 = (SD_buff[18] | (SD_buff[19]*0x10000L)); ulong fatSz = FATSz16?FATSz16:FATSz32; uint bytesPerSector = (((SD_buff[5]>>8) | (SD_buff[6]<<8))&0xffff); uint numFats = SD_buff[8]&0xff; ulong fatAddr = RsvdSecCnt+bpbAddr; ulong fatSectors = fatSz * numFats; ulong rootAddr = fatAddr + fatSectors; ulong rootSectors = ((32 * RootEntCnt + 511)>>9); ulong userAddr = rootAddr + rootSectors; uint sectorsPerCluster = (SD_buff[6]>>8); if (bytesPerSector != 512) return 0; // set to the shared variables SD_sectorsPerCluster = sectorsPerCluster; SD_fatSz = fatSz; SD_fatAddr = fatAddr; SD_fatSectors = fatSectors; SD_rootAddr = rootAddr; SD_rootSectors = rootSectors; SD_userAddr = userAddr; string[0] = p?'AS':'LO'; string[1] = p?'SE':'GI'; string[2] = p?'MB':'CB'; string[3] = p?'LY':'OY'; string[4] = 'BI'; string[5] = 'N '; do { uint spc = fat32?sectorsPerCluster:64; ulong ft = 0; ulong entry_adr = rootAddr; uint s; for (s = 0; s != spc; s++) { uint entry_offset = 0; uint i; sd_readBlock(io_port, entry_adr, dmem); for (i = 0; i != 16; i++) { uint j, flg = 1; for (j=0; j<6; j++) { uint ch = SD_buff[entry_offset+j]; if (((j<5)&(ch!=string[j]))|((j==5)&((ch&0xff)!=(string[j]&0xff)))) flg = 0; } if (flg == 1) { ulong length = ((SD_buff[entry_offset+14] + SD_buff[entry_offset+15]*0x10000L+511)>>9); ulong fat_ = SD_buff[entry_offset+13] + SD_buff[entry_offset+10]*0x10000L; valid = 1; secCount = 0; fat = fat_; initfat = fat_; secLength = length; return length; } entry_offset += 16; } entry_adr++; } if (fat32 == 1) { sd_readBlock(io_port, fatAddr+((ft*4)>>9), dmem); ft = ( SD_buff[(ft*2)&0b11111111] + SD_buff[((ft*2)&0b11111111)+1] * 0x10000L) & 0xfffffffL; if (ft >= 0x0ffffff7L) return 0; } } while (fat32 == 1); } return 0; } firmfunc void sd_file_sec_read(fio uint io_port[], fdmem uint#18 dmem[2048]) { // SD uint onram SD_buff[512]; uint onram SD_blkAdrAccs; uint onram SD_sectorsPerCluster; ulong onram SD_fatSz; ulong onram SD_fatAddr; ulong onram SD_fatSectors; ulong onram SD_rootAddr; ulong onram SD_rootSectors; ulong onram SD_userAddr; uint onram SD_fat32; // FILE uint onram valid; uint onram secCount; ulong onram fat; uint onram secLength; ulong onram initfat; { ulong fat_ = fat; ulong userAddr = SD_userAddr; ulong fatAddr = SD_fatAddr; if (secCount == SD_sectorsPerCluster) { secCount = 0; sd_readBlock(io_port, fatAddr+((fat*(SD_fat32?4:2))>>9), dmem); if (SD_fat32 == 1) { fat_ = SD_buff[(fat_*2)&0xff] + SD_buff[((fat_*2)&0xff)+1]*0x10000L; } else { fat_ = SD_buff[fat_&0xff]; } fat = fat_; } sd_readBlock(io_port, userAddr+(fat_-2)*SD_sectorsPerCluster+secCount, dmem); secCount++; } } // 25p40 SPI flash for configuration firmfunc void flash_sector_erase(fio uint io_port[], uint adrx65536, fdmem uint dmem[2048]) { uint ch; io_port[4] = 0x30000; // enable CS io_port[4] = 0x00006; // write enable io_port[4] = 0x30001; // disable CS io_port[4] = 0x30000; // enable CS io_port[4] = 0x000d8; // sector erase command io_port[4] = (adrx65536&0xff); // address high io_port[4] = 0; // address mid io_port[4] = 0; // address low io_port[4] = 0x30001; // disable CS do { io_port[4] = 0x30000; // enable CS io_port[4] = 0x00005; // read status io_port[4] = 0x000ff; ch = io_port[4]; io_port[4] = 0x30001; // disable CS } while ((ch&0x01) == 1); io_port[4] = 0x30000; // enable CS io_port[4] = 0x00004; // write disable io_port[4] = 0x30001; // disable CS } firmfunc void flash_program_page(fio uint io_port[], uint adrx256, uint buff_offset, fdmem uint dmem[2048]) { uint i; uint ch; io_port[4] = 0x30000; // enable CS io_port[4] = 0x00006; // write enable io_port[4] = 0x30001; // disable CS io_port[4] = 0x30000; // enable CS io_port[4] = 0x00002; // program page command io_port[4] = ((adrx256>>8)&0xff); // address high io_port[4] = ((adrx256)&0xff); // address mid io_port[4] = 0; // address low for (i=0; i<128; i++) io_port[4] = 0x10000 + dmem[buff_offset+i]; io_port[4] = 0x30001; // disable CS do { io_port[4] = 0x30000; // enable CS io_port[4] = 0x00005; // read status io_port[4] = 0x000ff; ch = io_port[4]; io_port[4] = 0x30001; // disable CS } while ((ch&0x01) == 1); io_port[4] = 0x30000; // enable CS io_port[4] = 0x00004; // write disable io_port[4] = 0x30001; // disable CS } firmfunc void flash_read_page(fio uint io_port[], uint adrx256, uint buff_offset, fdmem uint dmem[2048]) { uint i; io_port[4] = 0x30000; // enable CS io_port[4] = 0x00003; // read data bytes command io_port[4] = ((adrx256>>8)&0xff); // address high io_port[4] = ((adrx256)&0xff); // address mid io_port[4] = 0; // address low for (i=0; i<128; i++) { uint d; io_port[4] = 0x1ffff; d = io_port[4]; dmem[buff_offset+i] = d; } io_port[4] = 0x30001; // disable CS } // firmware top firmware fdmem_last<2047> firm(fio uint io_port[], fdmem uint#18 dmem[2048]) { uint x=0, y=0; uint i, j; uint length; uint p; for (i=0; i != 0b001111111111111111; i++) ; if ((io_port[6]&1) == 1) { // initialize EL display // init_el(io_port, dmem) ; // cls_el(io_port); for (p=0; p<2; p++) { length = sd_init(io_port, (p == 1), dmem); if (((p == 0) & (length == 293)) | ((p == 1) & (length > 0) && (length <= 256))) { uint flg = 0; uint ad = ((p==0)?0x500:0x300); // flash init io_port[4] = 0x20001; // speed = high io_port[7] = 1; if (p == 0) { flash_sector_erase(io_port, 0x5, dmem); flash_sector_erase(io_port, 0x6, dmem); flash_sector_erase(io_port, 0x7, dmem); } else { flash_sector_erase(io_port, 0x3, dmem); flash_sector_erase(io_port, 0x4, dmem); } io_port[7] = 0; for (i = 0; i < length; i++) { sd_file_sec_read(io_port, dmem); io_port[7] = 1; flash_program_page(io_port, ad+i*2, 0, dmem); flash_program_page(io_port, ad+i*2+1, 128, dmem); io_port[7] = 2; flash_read_page(io_port, ad+i*2, 256, dmem); flash_read_page(io_port, ad+i*2+1, 384, dmem); for (j=0; j < 256; j++) { if (dmem[j] != dmem[j+256]) { flg = 1; } } io_port[7] = 0; } io_port[7] = flg ? 1: 0; } } } else { io_port[5] = 0xff; io_port[5] = 0xff; io_port[5] = 0xAA; io_port[5] = 0x99; io_port[5] = 0x30; io_port[5] = 0xa1; io_port[5] = 0x00; io_port[5] = 0x0E; io_port[5] = 0x20; io_port[5] = 0x00; io_port[5] = 0x20; io_port[5] = 0x00; } while (true) ; } // i2c peripheral process i2c(clkin uint#1 clk, rstin uint#1 rst, out uint#1 latch sda, out uint#1 latch scl, in uint#1 fire, in uint#12 cmd_data, out uint#1 en comp) { uint#11 ctr; uint#8 d = 0; scl = 1; sda = 1; I2C_WAIT: { uint#12 cd = cmd_data; uint#2 cmd = cd#(11..8); uint#8 data = cd#(7..0); uint#1 f = fire; ctr = 0; if (~f) goto I2C_WAIT; else if (cmd == 0) goto I2C_START; else if (cmd == 1) { d = data; goto I2C_SEND; } else goto I2C_STOP; } I2C_START: scl = 1; sda = ~ctr#(6); ctr++; if (ctr#(6..0) != 0) goto I2C_START; else { comp = 1; goto I2C_WAIT; } I2C_SEND: scl = ctr#(6)^ctr#(5); sda = ctr#(10)?1:d#(7); ctr++; if (ctr#(6..0) == 0) { if (ctr#(10..7) == 9) { comp = 1; goto I2C_WAIT; } else { d = d#(6..0)@0b0; goto I2C_SEND; } } else goto I2C_SEND; I2C_STOP: scl = 1; sda = ctr#(6); ctr++; if (ctr#(6..0) != 0) goto I2C_STOP; else { comp = 1; goto I2C_WAIT; } } combinational open_drain (in uint#1 I, out uint#1 tristate O) { if (~I) O = 0; } // spi peripheral process spi(clkin uint#1 clk, rstin uint#1 rst, in uint#18 spi_cmd_data1, in uint#1 fire1, out uint#16 data_out, out uint#1 en comp, out uint#1 latch sd_cs, out uint#1 latch sd_di, out uint#1 latch sd_clk, in uint#1 sd_do ) { uint#12 i = 0b000000000000; // 17 + 7bit uint#8 input = 0; uint#16 winput = 0; uint#1 speed = 0; uint#8 output = 0; uint#1 cs = 0, ck = 0, di = 0, doo = 0; uint#1 word = 0, high = 0; cs = 1; sd_cs = cs; SD_SPI_WAIT: { uint#1 f1 = fire1; ck = 0; di = 0; sd_clk = ck; sd_di = di; data_out = winput; if (f1) { uint#18 scd = spi_cmd_data1; uint#2 cmd = scd#(17..16); if (cmd==0b00) { word = 0; i = 0; output = scd#(7..0); winput = 0; goto SD_SPI_DO; } else if (cmd==0b01) { word = 1; high = 0; i = 0; output = scd#(7..0); winput = 0; goto SD_SPI_DO; } else if (cmd==0b10) goto SD_SPI_SET_SPEED; else goto SD_SPI_SET_CS; } else goto SD_SPI_WAIT; } SD_SPI_SET_SPEED: { uint#18 scd = spi_cmd_data1; speed = scd#(0); comp = 1; goto SD_SPI_WAIT; } SD_SPI_SET_CS: { uint#18 scd = spi_cmd_data1; cs = scd#(0); sd_cs = cs; comp = 1; goto SD_SPI_WAIT; } SD_SPI_DO: { uint#18 scd = spi_cmd_data1; uint#1 sddo = sd_do; uint#5 step = i#(11..7); uint#7 fine = i#(6..0); if ((step != 0) & (~step#(0)) & (speed | (fine==0b1111111))) { doo = sddo; input = input#(6..0)@doo; } if (~step#(4) & ~step#(0) & (speed | (fine == 0b1111111))) { di = output#(7); sd_di = di; output = output#(6..0)@0b0; } if (speed | (fine == 0b1111111)) { if (step == 17) ck = 0; else if (step#(0)) ck = 1; else ck = 0; sd_clk = ck; } if (speed) i += 0b10000000; // 16 MHz else i += 0b00000001; // 125 KHz if (step == 17) { if (word == 0b1) { if (high == 0) { i = 0; winput = input; output = scd#(15..8); high = 1; goto SD_SPI_DO; } else { winput = input@winput#(7..0); comp = 1; goto SD_SPI_WAIT; } } else { winput = input; comp = 1; goto SD_SPI_WAIT; } } else goto SD_SPI_DO; } } // 36 bit microcontroller // if you change the architecture, you have to make the compiler yourself. // You can't use Cherry Syn as the compiler. process asap processor( clkin uint#1 clk, rstin uint#1 rst, ram uint#18 imem0[1024], ram uint#18 imem1[1024], ram uint#18 imem2[1024], ram uint#18 imem3[1024], ram uint#18 imem4[1024], ram uint#18 imem5[1024], ram uint#18 imem6[1024], ram uint#18 imem7[1024], ram uint#18 imem8[1024], ram uint#18 imem9[1024], ram uint#18 imem10[1024], ram uint#18 imem11[1024], ram uint#18 imem12[1024], ram uint#18 imem13[1024], ram uint#18 dmem0[1024], ram uint#18 dmem1[1024], in uint#18 in_port, out uint#18 latch out_port, out uint#12 en i2c_cmd_data, in uint#1 i2c_comp, out uint#18 en sd_spi_cmd_data, in uint#16 sd_spi_data_out, in uint#1 sd_spi_comp, out uint#18 en flash_spi_cmd_data, in uint#16 flash_spi_data_out, in uint#1 flash_spi_comp, in uint#1 sw, out uint#2 latch led, out uint#1 latch boot_clk, out uint#1 latch boot_ce, out uint#1 latch boot_write, out uint#8 latch boot_out ) { uint#15 pc = 0; // program counter uint#12 dmadr = 0; // data memory address uint#36 rega = 0, regb = 0; // register uint#36 temp0 = 0; uint#18 temp1 = 0; uint#18 temp2 = 0; uint#3 op_kind = 0; uint#3 next = 0; // for multi state instruction uint#18 inst = 0; uint#1 high = 0, highi = 0; uint#2 mul_phase = 0; uint#1 flg = 0; uint#1 boot_phase = 0; uint#8 ctr = 0; boot_clk = 0; boot_ce = 1; boot_write = 1; boot_out = 0xff; while (1) { switch (next) { case 0: { // fetch switch (pc#(13..10)) { case 0: inst = imem0[pc#(9..0)]; break; case 1: inst = imem1[pc#(9..0)]; break; case 2: inst = imem2[pc#(9..0)]; break; case 3: inst = imem3[pc#(9..0)]; break; case 4: inst = imem4[pc#(9..0)]; break; case 5: inst = imem5[pc#(9..0)]; break; case 6: inst = imem6[pc#(9..0)]; break; case 7: inst = imem7[pc#(9..0)]; break; case 8: inst = imem8[pc#(9..0)]; break; case 9: inst = imem9[pc#(9..0)]; break; case 10: inst = imem10[pc#(9..0)]; break; case 11: inst = imem11[pc#(9..0)]; break; case 12: inst = imem12[pc#(9..0)]; break; default: inst = imem13[pc#(9..0)]; break; } pc++; next = 1; } break; case 1: { // exec if (inst#(17)) { // JP kind instructinons switch (inst#(16..15)) { case 0b00: // JP pc += inst#(14..0); next = 0; break; case 0b01: // JP_C if (rega#(0)) pc += inst#(14..0); next = 0; break; case 0b10: // JP_CN if (~(rega#(0))) pc += inst#(14..0); next = 0; break; default: next = 0; break; } } else if (inst#(17..16)==0b01) { // DMEM kind instructions high = inst#(12); switch (inst#(15..13)) { case 0b000: // LDAM dmadr = inst#(11..0); next = 3; op_kind = 0; break; case 0b001: // LDBM dmadr = inst#(11..0); next = 3; op_kind = 1; break; case 0b010: // STAM dmadr = inst#(11..0); next = 4; op_kind = 0; break; case 0b011: // STBM dmadr = inst#(11..0); op_kind = 1; next = 4; break; case 0b110: // LDAMM dmadr = inst#(11..0); next = 3; op_kind = 0b10; break; case 0b111: // STAMM dmadr = inst#(11..0); next = 3; op_kind = 0b110; break; } } else if (inst#(17..15)==0b001) { // IO kind instructions switch (inst#(14..13)) { case 0b00: { // IN uint#13 io_adr = inst#(12..0); switch (io_adr) { case 0x0: // normal input rega = in_port; next = 0; break; case 0x1: // reserved next = 0; break; case 0x2: // el i2c // not yet next = 0; break; case 0x3: // sd spi rega = sd_spi_data_out; next = 0; break; case 0x4: // flash spi rega = flash_spi_data_out; next = 0; break; case 0x6: rega = sw; next = 0; break; default: next = 0; break; } } break; case 0b01: { // OUT uint#13 io_adr = inst#(12..0); switch (io_adr) { case 0x0: // normal output out_port = rega; next = 0; break; case 0x1: // reserved next = 0; break; case 0x2: // el i2c i2c_cmd_data = rega#(11..0); if (~i2c_comp) next = 1; else next = 0; break; case 0x3: // sd spi sd_spi_cmd_data = rega; if (~sd_spi_comp) next = 1; else next = 0; break; case 0x4: // flash spi flash_spi_cmd_data = rega; if (~flash_spi_comp) next = 1; else next = 0; break; case 0x5: // boot if (~boot_phase) { boot_ce = 0; boot_phase = 1; boot_clk = 0; boot_write = 0; boot_out = rega#(0)@rega#(1)@rega#(2)@rega#(3)@rega#(4)@rega#(5)@rega#(6)@rega#(7); next = 1; } else { boot_phase = 0; boot_clk = 1; next = 0; } break; case 0x7: // led led = rega; next = 0; break; default: next = 0; break; } } break; } } else { // normal instructions switch (inst#(5..0)) { case 0x00: { // LDAI , LDBI uint#18 i; switch (pc#(13..10)) { case 0: i = imem0[pc#(9..0)]; break; case 1: i = imem1[pc#(9..0)]; break; case 2: i = imem2[pc#(9..0)]; break; case 3: i = imem3[pc#(9..0)]; break; case 4: i = imem4[pc#(9..0)]; break; case 5: i = imem5[pc#(9..0)]; break; case 6: i = imem6[pc#(9..0)]; break; case 7: i = imem7[pc#(9..0)]; break; case 8: i = imem8[pc#(9..0)]; break; case 9: i = imem9[pc#(9..0)]; break; case 10: i = imem10[pc#(9..0)]; break; case 11: i = imem11[pc#(9..0)]; break; case 12: i = imem12[pc#(9..0)]; break; default: i = imem13[pc#(9..0)]; break; } pc++; if (inst#(14)) { if (highi) { regb = i @ regb#(17..0); } else { regb = i; } } else { if (highi) { rega = i @ rega#(17..0); } else { rega = i; } } if (inst#(12) & ~highi) { highi = 1; next = 1; } else { highi = 0; next = 0; } } break; case 0x01: // NOT rega = ~rega; next = 0; break; case 0x02: // ADD rega = rega + regb; next = 0; break; case 0x03: // SUB rega = rega - regb; next = 0; break; case 0x04: { // MUL if (inst#(12)) { switch (mul_phase) { case 0: temp0 = (rega#(17..0)*regb#(17..0)); temp1 = (rega#(34..18)*regb#(17..0))#(17..0); temp2 = (rega#(17..0)*regb#(34..18))#(17..0); mul_phase = 1; next = 1; break; default: rega = temp0 + ((temp1 + temp2)@0b000000000000000000); mul_phase = 0; next = 0; break; } } else { rega = (rega#(17..0) * regb#(17..0))#(17..0); next = 0; } } break; case 0x06: // Lsh if (regb != 0) { if (regb#(3)) { rega = rega#(28..0)@0b00000000; regb -= 8; } else { rega = rega#(34..0)@0b0; regb--; } if (regb == 0) next = 0; else next = 1; } else next = 0; break; case 0x07: // ARsh if (regb != 0) { if (inst#(12)) { rega = rega#(35)@rega#(35..1); } else { rega = rega#(17)@rega#(17..1); } regb--; if (regb == 0) next = 0; else next = 1; } else next = 0; break; case 0x08: // Rsh if (regb != 0) { if (regb#(3)) { if (inst#(12)) { rega = 0b00000000@rega#(35..8); } else { rega = 0b00000000@rega#(17..8); } regb -= 8; } else { if (inst#(12)) { rega = 0b0@rega#(35..1); } else { rega = 0b0@rega#(17..1); } regb--; } if (regb == 0) next = 0; else next = 1; } else next = 0; break; case 0x09: { // LtUns uint#36 regaa = inst#(12)?rega:rega#(17..0); uint#36 regbb = inst#(12)?regb:regb#(17..0); rega = (regaa period<250> clk_in, in uint#1 pin<83> rst, inout uint#1 pin<77> pullup lcd_sda, inout uint#1 pin<78> pullup lcd_scl, // SD card out uint#1 pin<62> sd_cs, out uint#1 pin<61> sd_di, out uint#1 pin<60> sd_clk, in uint#1 pin<59> pullup sd_do, // Flash out uint#1 pin<27> flash_cs, out uint#1 pin<46> flash_di, out uint#1 pin<53> flash_clk, in uint#1 pin<51> flash_do, // sw0 in uint#1 pin<93> pulldown sw0, // led out uint#2 pin<56,52> led ) { com # clk; com # clkpo, clkp, clkplocked, clkplockedn; com # rstn; rstn = ~rst; BUFG(clk_in, clk); /* This DCM generats 32MHz */ generic ( CLKDV_DIVIDE : 2.0, CLKFX_DIVIDE : 1, CLKFX_MULTIPLY : 8, CLKIN_DIVIDE_BY_2 : FALSE, CLKIN_PERIOD : 250.0, CLKOUT_PHASE_SHIFT : "NONE", CLK_FEEDBACK : "NONE", DESKEW_ADJUST : "SYSTEM_SYNCHRONOUS", DLL_FREQUENCY_MODE : "LOW", DUTY_CYCLE_CORRECTION : FALSE, PHASE_SHIFT : 0, STARTUP_WAIT : FALSE ) DCM_SP(clkpo, clk, 0, 0, 0, rstn, clkplocked); BUFG(clkpo, clkp); { com uint#12 en i2c_cmd_data; com uint#1 en i2c_comp; com uint#18 en sd_spi_cmd_data; com uint#16 sd_spi_data_out; com uint#1 en sd_spi_comp; com uint#18 en flash_spi_cmd_data; com uint#16 flash_spi_data_out; com uint#1 en flash_spi_comp; com uint#1 boot_clk; com uint#1 boot_ce; com uint#1 boot_write; com uint#8 boot_out; ram uint#18 clock dmem0[1024]; ram uint#18 clock dmem1[1024] = { I2C_ADDRESS, // send slave address 0b10000000, 0xae, // set display off 0b00000000, 0xa8, // set multiplex ratio 0x3f, // 64MUX 0b00000000, 0xd3, // set display offset 0x00, // 0 0b10000000, 0x40, // set display start line = 0 0b10000000, 0xa0, //set segment re-map column address 0 is SEG0 0b10000000, 0xc0, //0xc8; set COM output scan direction 0b00000000, 0xda, // set COM pins hardware configuration 0b00010010, 0b00000000, 0x81, // set contrast 255, 0b10000000, // control byte continuous 0xa4, // disable entire display on 0b10000000, // control byte continuous 0xa6, // set normal display 0b00000000, 0xd5, // set display clock divide ratio 0b10000000, 0b00000000, 0x20, // set memory addressing mode 0b10, // page addressing mode 0b00000000, 0x22, // set page address 0, // start page set 7, // end page set 0b00000000, 0x21, // set column address 0, // column start address 127, // column stop address 0b00000000, 0x8d, // set enable charge pump regulator 0x14, 0b10000000, 0xaf, // display on - 0x2b 0x00, 0x00, 0x00, 0x00, // 0x30 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fonts address 0x50 - 0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x2f00,0x0000, 0x0000,0x0300,0x0300,0x0000, 0x0014,0x3e14,0x3e14,0x0000, 0x0000,0x242a,0x7f2a,0x1200, 0x0205,0x150a,0x142a,0x2810, 0x0000,0x1629,0x2911,0x1028, 0x0000,0x0000,0x0300,0x0000, 0x0000,0x0c12,0x2100,0x0000, 0x0000,0x0021,0x120c,0x0000, 0x0000,0x150e,0x1f0e,0x1500, 0x0000,0x0808,0x3e08,0x0800, 0x0000,0x0040,0x2000,0x0000, 0x0000,0x0808,0x0808,0x0000, 0x0000,0x0000,0x2000,0x0000, 0x0020,0x1008,0x0402,0x0100, 0x000c,0x1221,0x2112,0x0c00, 0x0000,0x0022,0x3f20,0x0000, 0x0022,0x3129,0x2925,0x2200, 0x0012,0x2129,0x2925,0x1200, 0x0018,0x1412,0x3f10,0x0000, 0x0017,0x2525,0x2525,0x1900, 0x001e,0x2525,0x2525,0x1800, 0x0021,0x1109,0x0503,0x0100, 0x001a,0x2525,0x2525,0x1a00, 0x0006,0x2929,0x2929,0x1e00, 0x0000,0x0000,0x2400,0x0000, 0x0000,0x0040,0x2400,0x0000, 0x0008,0x0814,0x1422,0x2200, 0x0014,0x1414,0x1414,0x1400, 0x0022,0x2214,0x1408,0x0800, 0x0002,0x0129,0x0906,0x0000, 0x1824,0x42ba,0xaabe,0x0000, 0x0030,0x0c0b,0x0b0c,0x3000, 0x003f,0x2525,0x251a,0x0000, 0x0c12,0x2121,0x2112,0x0000, 0x003f,0x2121,0x211e,0x0000, 0x003f,0x2525,0x2521,0x0000, 0x003f,0x0505,0x0501,0x0000, 0x0c12,0x2129,0x291a,0x0000, 0x003f,0x0404,0x0404,0x3f00, 0x0000,0x2121,0x3f21,0x2100, 0x0010,0x2021,0x211f,0x0000, 0x003f,0x080c,0x1221,0x0000, 0x003f,0x2020,0x2020,0x2000, 0x003f,0x0204,0x0804,0x023f, 0x003f,0x0204,0x0810,0x3f00, 0x0000,0x1e21,0x2121,0x1e00, 0x003f,0x0505,0x0502,0x0000, 0x0000,0x1e21,0x2121,0x5e00, 0x003f,0x050d,0x1522,0x0000, 0x0000,0x1225,0x2929,0x1200, 0x0001,0x0101,0x3f01,0x0101, 0x001f,0x2020,0x2020,0x1f00, 0x0106,0x1820,0x2018,0x0601, 0x003f,0x1008,0x0408,0x103f, 0x0021,0x120c,0x0c12,0x2100, 0x0001,0x0204,0x3804,0x0201, 0x0021,0x3129,0x2523,0x2100, 0x0000,0x3f21,0x2100,0x0000, 0x0001,0x0204,0x0810,0x2000, 0x0000,0x2121,0x3f00,0x0000, 0x0000,0x0201,0x0200,0x0000, 0x0020,0x2020,0x2020,0x2000, 0x0000,0x0001,0x0200,0x0000, 0x0010,0x2a2a,0x2a1a,0x3c00, 0x003f,0x1424,0x2424,0x1800, 0x0000,0x1824,0x2424,0x0000, 0x0018,0x2424,0x2414,0x3f00, 0x001c,0x2a2a,0x2a2a,0x0c00, 0x0000,0x083e,0x0a00,0x0000, 0x0018,0xa4a4,0x887c,0x0000, 0x0000,0x3f04,0x0438,0x0000, 0x0000,0x0000,0x3d00,0x0000, 0x0080,0x8084,0x7d00,0x0000, 0x0000,0x3f10,0x2824,0x0000, 0x0000,0x003f,0x2000,0x0000, 0x003c,0x0408,0x0804,0x3c00, 0x0000,0x3c08,0x0404,0x3c00, 0x0018,0x2424,0x2424,0x1800, 0x00fc,0x2824,0x2424,0x1800, 0x0018,0x2424,0x2428,0xfc00, 0x0000,0x3c08,0x0404,0x0800, 0x0000,0x242a,0x2a12,0x0000, 0x0000,0x043e,0x2404,0x0000, 0x0000,0x1c20,0x2010,0x3c00, 0x000c,0x1020,0x2010,0x0c00, 0x0c30,0x2010,0x1020,0x300c, 0x0024,0x2810,0x1028,0x2400, 0x0084,0x8850,0x2010,0x0c00, 0x0000,0x2434,0x2c24,0x0000, 0x0000,0x0c3f,0x2121,0x0000, 0x0000,0x0000,0x7f00,0x0000, 0x0000,0x2121,0x3f0c,0x0000, 0x0010,0x0808,0x1010,0x0800, 0x0000,0x0000,0x0000,0x0000 // free 0x1d0 - }; // ram uint#18 port_num<2> clock dmem2[1024]; // ram uint#18 port_num<2> clock dmem3[1024]; { com uint#18 in_port = 0; com uint#18 out_port; ram uint#18 clock imem0[1024] = { firm }; ram uint#18 clock imem1[1024] = { firm offset<0x0400> }; ram uint#18 clock imem2[1024] = { firm offset<0x0800> }; ram uint#18 clock imem3[1024] = { firm offset<0x0c00> }; ram uint#18 clock imem4[1024] = { firm offset<0x1000> }; ram uint#18 clock imem5[1024] = { firm offset<0x1400> }; ram uint#18 clock imem6[1024] = { firm offset<0x1800> }; ram uint#18 clock imem7[1024] = { firm offset<0x1c00> }; ram uint#18 clock imem8[1024] = { firm offset<0x2000> }; ram uint#18 clock imem9[1024] = { firm offset<0x2400> }; ram uint#18 clock imem10[1024] = { firm offset<0x2800> }; ram uint#18 clock imem11[1024] = { firm offset<0x2c00> }; ram uint#18 clock imem12[1024] = { firm offset<0x3000> }; ram uint#18 clock imem13[1024] = { firm offset<0x3400> }; processor(clkp, clkplocked, imem0, imem1, imem2, imem3, imem4, imem5, imem6, imem7, imem8, imem9, imem10, imem11, imem12, imem13, dmem0, dmem1, /* dmem2 port<0>, dmem3 port<0>, */ in_port, out_port, i2c_cmd_data, i2c_comp en, sd_spi_cmd_data, sd_spi_data_out, sd_spi_comp en, flash_spi_cmd_data, flash_spi_data_out, flash_spi_comp en, sw0, led, boot_clk, boot_ce, boot_write, boot_out); } { // el com uint#1 i2c_sda, i2c_scl; i2c(clkp, clkplocked, i2c_sda, i2c_scl, i2c_cmd_data en, i2c_cmd_data, i2c_comp); open_drain(i2c_sda, lcd_sda); open_drain(i2c_scl, lcd_scl); } { // sd spi(clkp, clkplocked, sd_spi_cmd_data, sd_spi_cmd_data en, sd_spi_data_out, sd_spi_comp, sd_cs, sd_di, sd_clk, sd_do /* , dmem2 port<1> */); // flash spi(clkp, clkplocked, flash_spi_cmd_data, flash_spi_cmd_data en, flash_spi_data_out, flash_spi_comp, flash_cs, flash_di, flash_clk, flash_do /* , dmem3 port<1> */); } { ICAP_SPARTAN3A(boot_clk, boot_ce, boot_write, boot_out, 0#8, 0); } } }